1
0
Fork 0
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:
Dan Everton 2007-02-10 11:44:26 +00:00
parent 5158751263
commit 7bf62e8da6
70 changed files with 4847 additions and 3314 deletions

View file

@ -164,9 +164,7 @@ $(BUILDDIR)/libspeex.a: libspeex
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

View file

@ -14,7 +14,7 @@ ifdef APPEXTRA
INCLUDES += $(patsubst %,-I$(APPSDIR)/%,$(subst :, ,$(APPEXTRA)))
endif
SPEEXOPTS = -O
SPEEXOPTS = -O -DHAVE_CONFIG_H
CFLAGS = $(INCLUDES) $(GCCOPTS) $(TARGET_INC) $(SPEEXOPTS) $(TARGET) \
$(EXTRA_DEFINES) -DMEM=${MEMORYSIZE} ${PROFILE_OPTS} -Wno-unused-parameter

View file

@ -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
modes.c
speex.c
vq.c
high_lsp_tables.c
vbr.c
hexc_table.c
cb_search.c
exc_10_16_table.c
exc_10_32_table.c
exc_20_32_table.c
exc_5_256_table.c
exc_5_64_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
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_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
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

View file

@ -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.
*/
#ifndef MIN
#define MIN(a,b) ((a)<(b) ? (a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b) ? (a):(b))
#endif
/* kiss_fft.h
defines kiss_fft_scalar as either short or a float type
and defines
typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */
#include "kiss_fft.h"
#include "math_approx.h"
#define MAXFACTORS 32
/* 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)->i = KISS_FFT_SIN(phase);\
}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 */

View file

@ -35,16 +35,15 @@
#ifndef ARCH_H
#define ARCH_H
//#warning "----------------Arch.h-------------"
#include "speex/speex_types.h"
#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer 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 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 FIXED_POINT
#ifdef FIXED_POINT
@ -71,6 +70,7 @@ typedef spx_word32_t spx_sig_t;
#define VERY_SMALL 0
#define VERY_LARGE32 ((spx_word32_t)2147483647)
#define VERY_LARGE16 ((spx_word16_t)32767)
#define Q15_ONE ((spx_word16_t)32767)
#ifdef FIXED_DEBUG
@ -79,7 +79,7 @@ typedef spx_word32_t spx_sig_t;
#include "fixed_generic.h"
#if defined (ARM5E_ASM)
#ifdef ARM5E_ASM
#include "fixed_arm5e.h"
#elif defined (ARM4_ASM)
#include "fixed_arm4.h"
@ -116,6 +116,7 @@ typedef float spx_word32_t;
#define VERY_SMALL 1e-15f
#define VERY_LARGE32 1e15f
#define VERY_LARGE16 1e15f
#define Q15_ONE ((spx_word16_t)1.f)
#define QCONST16(x,bits) (x)
#define QCONST32(x,bits) (x)
@ -130,6 +131,7 @@ typedef float spx_word32_t;
#define SHL32(a,shift) (a)
#define PSHR16(a,shift) (a)
#define PSHR32(a,shift) (a)
#define VSHR32(a,shift) (a)
#define SATURATE16(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_Q14(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_Q15(c,a,b) ((c)+(a)*(b))

View file

@ -76,6 +76,7 @@ void speex_bits_destroy(SpeexBits *bits)
void speex_bits_reset(SpeexBits *bits)
{
/* We only need to clear the first byte now */
bits->chars[0]=0;
bits->nbBits=0;
bits->charPtr=0;
@ -229,7 +230,6 @@ void speex_bits_pack(SpeexBits *bits, int data, int nbBits)
char *tmp = (char*)speex_realloc(bits->chars, new_nchars);
if (tmp)
{
speex_memset_bytes(tmp, 0, new_nchars);
bits->buf_size=new_nchars;
bits->chars=tmp;
} else {

View file

@ -226,11 +226,13 @@ int update_target
/* Update target: only update target if necessary */
if (update_target)
{
VARDECL(spx_sig_t *r2);
ALLOC(r2, nsf, spx_sig_t);
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++)
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
VARDECL(spx_word16_t *t);
VARDECL(spx_sig_t *e);
VARDECL(spx_sig_t *r2);
VARDECL(spx_word16_t *tmp);
VARDECL(spx_word32_t *ndist);
VARDECL(spx_word32_t *odist);
@ -316,7 +317,6 @@ int update_target
#endif
ALLOC(t, nsf, spx_word16_t);
ALLOC(e, nsf, spx_sig_t);
ALLOC(r2, nsf, spx_sig_t);
ALLOC(ind, nb_subvect, int);
ALLOC(tmp, 2*N*nsf, spx_word16_t);
@ -495,9 +495,13 @@ int update_target
/* Update target: only update target if necessary */
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++)
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;
VARDECL(spx_sig_t *tmp);
ALLOC(tmp, nsf, spx_sig_t);
for (i=0;i<nsf;i++)
tmp[i]=PSHR32(EXTEND32(target[i]),SIG_SHIFT);
residue_percep_zero(tmp, ak, awk1, awk2, tmp, nsf, p, stack);
VARDECL(spx_word16_t *tmp);
ALLOC(tmp, nsf, spx_word16_t);
residue_percep_zero16(target, ak, awk1, awk2, tmp, nsf, p, stack);
for (i=0;i<nsf;i++)
exc[i]+=tmp[i];
exc[i]+=SHL32(EXTEND32(tmp[i]),8);
for (i=0;i<nsf;i++)
target[i]=0;
}

View file

@ -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)
: "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;
resp += subvect_size;

View 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

View file

@ -41,7 +41,6 @@
#include "misc.h"
#include "math_approx.h"
#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++)
{
out[i] = in[i] << shift;
out[i] = SHL16(in[i], 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;
for (i=0;i<len;i++)
{
out[i] = (in[i] + (1<<(shift-1))) >> shift;
out[i] = PSHR16(in[i], shift);
}
}
#endif
@ -104,8 +103,8 @@ void spx_fft(void *table, float *in, float *out)
if (in==out)
{
int i;
speex_warning("FFT should not be done in-place");
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++)
out[i] = scale*in[i];
} else {
@ -121,7 +120,6 @@ void spx_ifft(void *table, float *in, float *out)
{
if (in==out)
{
int i;
speex_warning("FFT should not be done in-place");
} else {
int i;

View 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

View 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

View file

@ -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_word32_t vout = ADD32(MULT16_16(num[0], x[i]),mem[0]);
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[1] = ADD32(MULT16_16(num[2],x[i]), MULT16_32_Q14(-den[2],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]), SHL32(MULT16_32_Q15(-den[2],vout),1));
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)
{
spx_word32_t sum2=0;
sum2 = MAC16_16(sum2,PSHR16(x[i],1),PSHR16(x[i],1));
sum2 = MAC16_16(sum2,PSHR16(x[i+1],1),PSHR16(x[i+1],1));
sum2 = MAC16_16(sum2,PSHR16(x[i+2],1),PSHR16(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],1),SHR16(x[i],1));
sum2 = MAC16_16(sum2,SHR16(x[i+1],1),SHR16(x[i+1],1));
sum2 = MAC16_16(sum2,SHR16(x[i+2],1),SHR16(x[i+2],1));
sum2 = MAC16_16(sum2,SHR16(x[i+3],1),SHR16(x[i+3],1));
sum = ADD32(sum,SHR32(sum2,6));
}
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
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
#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
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
#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
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,44 +356,34 @@ void fir_mem16(const spx_word16_t *x, const spx_coef_t *num, spx_word16_t *y, in
}
}
#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_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 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)
{
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);
iir_mem16(xx, ak, y, N, ord, mem, stack);
for (i=0;i<ord;i++)
mem[i]=0;
filter_mem2(y, awk1, awk2, y, N, ord, mem);
filter_mem16(y, awk1, awk2, y, N, ord, mem, 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 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_mem2(xx, ak, awk1, y, N, ord, mem);
filter_mem16(xx, ak, awk1, y, N, ord, mem, stack);
for (i=0;i<ord;i++)
mem[i]=0;
fir_mem2(y, awk2, y, N, ord, mem);
fir_mem16(y, awk2, y, N, ord, mem, stack);
}
#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)
{
@ -581,7 +419,8 @@ void compute_impulse_response(const spx_coef_t *ak, const spx_coef_t *awk1, cons
}
#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;
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;
for (i=0;i<M;i++)
a[M-i-1]= aa[i];
for (i=0;i<M-1;i++)
x[i]=mem[M-i-2];
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++)
{
y1[k]=0;
y2[k]=0;
spx_word32_t y1k=0, y2k=0;
for (j=0;j<M2;j++)
{
y1[k]=ADD32(y1[k],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])));
y1k=ADD32(y1k,MULT16_16(a[j],ADD16(x[i+j],x2[i-j])));
y2k=SUB32(y2k,MULT16_16(a[j],SUB16(x[i+j],x2[i-j])));
j++;
y1[k]=ADD32(y1[k],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])));
y1k=ADD32(y1k,MULT16_16(a[j],ADD16(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);
y2[k] = SHR32(y2[k],1);
y1[k] = EXTRACT16(SATURATE(PSHR32(y1k,15),32767));
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);
}
/* By segher */
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)
/* Re-synthesised a signal from the QMF low-band and high-band signals */
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)
/* assumptions:
all odd x[i] are zero -- well, actually they are left out of the array now
N and M are multiples of 4 */
{
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++)
xx[2*i] = PSHR32(x[N/2-1-i],SIG_SHIFT);
for (i = 0; i < M - 1; i += 2)
xx[N+i] = mem[i+1];
for (i = 0; i < N2; i++)
xx1[i] = x1[N2-1-i];
for (i = 0; i < M2; i++)
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_word16_t x0;
spx_word16_t x10, x20;
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) {
spx_word16_t x1;
for (j = 0; j < M2; j += 2) {
spx_word16_t x11, x21;
spx_word16_t a0, a1;
a0 = a[j];
a1 = a[j+1];
x1 = xx[N-2+j-i];
a0 = a[2*j];
a1 = a[2*j+1];
x11 = xx1[N2-1+j-i];
x21 = xx2[N2-1+j-i];
y0 = ADD32(y0,SHR(MULT16_16(a0, x1),2));
y1 = ADD32(y1,SHR(MULT16_16(a1, x1),2));
y2 = ADD32(y2,SHR(MULT16_16(a0, x0),2));
y3 = ADD32(y3,SHR(MULT16_16(a1, x0),2));
#ifdef FIXED_POINT
/* We multiply twice by the same coef to avoid overflows */
y0 = MAC16_16(MAC16_16(y0, a0, x11), NEG16(a0), x21);
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];
a1 = a[j+3];
x0 = xx[N+j-i];
y0 = ADD32(y0,SHR(MULT16_16(a0, x0),2));
y1 = ADD32(y1,SHR(MULT16_16(a1, x0),2));
y2 = ADD32(y2,SHR(MULT16_16(a0, x1),2));
y3 = ADD32(y3,SHR(MULT16_16(a1, x1),2));
#ifdef FIXED_POINT
/* We multiply twice by the same coef to avoid overflows */
y0 = MAC16_16(MAC16_16(y0, a0, x10), NEG16(a0), x20);
y1 = MAC16_16(MAC16_16(y1, a1, x10), a1, x20);
y2 = MAC16_16(MAC16_16(y2, a0, x11), NEG16(a0), x21);
y3 = MAC16_16(MAC16_16(y3, a1, x11), a1, x21);
#else
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;
y[i+1] = y1;
y[i+2] = y2;
y[i+3] = y3;
#ifdef FIXED_POINT
y[2*i] = EXTRACT16(SATURATE32(PSHR32(y0,15),32767));
y[2*i+1] = EXTRACT16(SATURATE32(PSHR32(y1,15),32767));
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)
mem[i+1] = xx[i];
for (i = 0; i < M2; i++)
mem1[2*i+1] = xx1[i];
for (i = 0; i < M2; i++)
mem2[2*i+1] = xx2[i];
}
#ifdef FIXED_POINT
#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},
{444, -2328, 8895, 29179, -4425, 1133, -98}};
#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},
{-209, -990, 6837, 31589, -6694, 2817, -1064}};
#endif
#else
#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.0135403, -0.0710304, 0.2714479, 0.8904793, -0.1350474, 0.0345613, -0.0029937}};
#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.0063646f, -0.0302054f, 0.2086420f, 0.9640297f, -0.2042986f, 0.0859768f, -0.0324855f}};
#endif
@ -784,7 +657,9 @@ char *stack
spx_word16_t g1, g2;
spx_word16_t ngain;
spx_word16_t gg1, gg2;
#ifdef FIXED_POINT
int scaledown=0;
#endif
#if 0 /* Set to 1 to enable full pitch search */
int nol_pitch[6];
spx_word16_t nol_pitch_coef[6];
@ -819,6 +694,23 @@ char *stack
else
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);*/
/*printf ("%d %d %f\n", pitch, corr_pitch, max_corr*ener_1);*/
@ -898,5 +790,14 @@ char *stack
for (i=0;i<nsf;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
}

View file

@ -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 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 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 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 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 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_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);
@ -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 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_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 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 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 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);

View file

@ -33,9 +33,9 @@
*/
#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;
int sig_shift;
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;
}
#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);
}

View file

@ -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;
}
#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
@ -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
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
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)
{

View file

@ -34,7 +34,7 @@
#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];
@ -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]);
}
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];
@ -130,18 +130,18 @@ void filter_mem2_8(const float *x, const float *_num, const float *_den, float *
}
#define OVERRIDE_FILTER_MEM2
void filter_mem2(const float *x, const float *_num, const float *_den, float *y, int N, int ord, float *_mem)
#define OVERRIDE_FILTER_MEM16
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)
filter_mem2_10(x, _num, _den, y, N, ord, _mem);
filter_mem16_10(x, _num, _den, y, N, ord, _mem);
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];
@ -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];
@ -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]);
}
#define OVERRIDE_IIR_MEM2
void iir_mem2(const float *x, const float *_den, float *y, int N, int ord, float *_mem)
#define OVERRIDE_IIR_MEM16
void iir_mem16(const float *x, const float *_den, float *y, int N, int ord, float *_mem, char *stack)
{
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)
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];
@ -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]);
}
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];
@ -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]);
}
#define OVERRIDE_FIR_MEM2
void fir_mem2(const float *x, const float *_num, float *y, int N, int ord, float *_mem)
#define OVERRIDE_FIR_MEM16
void fir_mem16(const float *x, const float *_num, float *y, int N, int ord, float *_mem, char *stack)
{
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)
fir_mem2_8(x, _num, y, N, ord, _mem);
fir_mem16_8(x, _num, y, N, ord, _mem);
}

View file

@ -74,53 +74,57 @@ static inline int NEG32(long long x)
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;
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;
spx_mips++;
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;
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;
spx_mips++;
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;
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;
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++;
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;
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;
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++;
return res;
}
@ -134,7 +138,9 @@ static inline int SHR32(long long a, int shift)
}
res = a>>shift;
if (!VERIFY_INT(res))
{
fprintf (stderr, "SHR32: output is not int: %d\n", (int)res);
}
spx_mips++;
return res;
}
@ -143,62 +149,71 @@ static inline int SHL32(long long a, int shift)
long long res;
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;
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++;
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 SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
#define SHR(a,shift) ((a) >> (shift))
#define SHL(a,shift) ((a) << (shift))
//#define SHR(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;
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;
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++;
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;
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;
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++;
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 PSHR(a,shift) (SHR((a)+(1<<((shift)-1)),shift))
/* result fits in 16 bits */
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;
}
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;
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;
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++;
return res;
}
#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_Q13(c,a,b) (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_Q11(c,a,b) (EXTRACT16(ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),11)))))
#define MAC16_16_Q13(c,a,b) (EXTRACT16(ADD16((c),EXTRACT16(SHR32(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;
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;
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;
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_Q14(a,b) MULT16_32_QX(a,b,14)
#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)))
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 >>= 15;
if (!VERIFY_SHORT(res))
{
fprintf (stderr, "MULT16_16_Q15: output is not short: %d\n", (int)res);
}
spx_mips+=3;
return res;
}
@ -398,23 +434,24 @@ static inline short MULT16_16_P15(int a, int b)
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;
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;
}
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;
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)
res = 32767;
if (res<-32768)
@ -423,22 +460,24 @@ static inline int DIV32_16(long long a, long long b)
spx_mips+=20;
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;
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;
}
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;
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;
return res;
}

View file

@ -46,14 +46,15 @@
#define SHL16(a,shift) ((a) << (shift))
#define SHR32(a,shift) ((a) >> (shift))
#define SHL32(a,shift) ((a) << (shift))
#define PSHR16(a,shift) (SHR16((a)+(1<<((shift)-1)),shift))
#define PSHR32(a,shift) (SHR32((a)+(1<<((shift)-1)),shift))
#define PSHR16(a,shift) (SHR16((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 SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
#define SHR(a,shift) ((a) >> (shift))
#define SHL(a,shift) ((spx_word32_t)(a) << (shift))
#define PSHR(a,shift) (SHR((a)+(1<<((shift)-1)),shift))
#define PSHR(a,shift) (SHR((a)+((1<<((shift))>>1)),shift))
#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 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 MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)))

View file

@ -41,7 +41,10 @@
#include <speex/speex.h>
#include <speex/speex_bits.h>
#include <speex/speex_jitter.h>
#include <stdio.h>
#ifndef NULL
#define NULL 0
#endif
#define LATE_BINS 10
#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 */
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->timestamp[i]=packet->timestamp;
jitter->span[i]=packet->span;
@ -378,7 +381,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint
/* Check for potential overflow */
packet->len = jitter->len[i];
/* 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];
/* Remove packet */
speex_free(jitter->buf[i]);
@ -424,7 +427,23 @@ void jitter_buffer_tick(JitterBuffer *jitter)
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;
}

View file

@ -19,7 +19,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
#include "_kiss_fft_guts.h"
#include "misc.h"
#include "math_approx.h"
/* 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.
@ -55,8 +54,8 @@ static void kf_bfly2(
kiss_fft_cpx *x=Fout;
for (i=0;i<2*m;i++)
{
x[i].r = SHR(x[i].r,1);
x[i].i = SHR(x[i].i,1);
x[i].r = SHR16(x[i].r,1);
x[i].i = SHR16(x[i].i,1);
}
}
@ -86,9 +85,9 @@ static void kf_bfly4(
tw3 = tw2 = tw1 = st->twiddles;
if (!st->inverse) {
int i;
unsigned int i;
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].i = PSHR16(x[i].i,2);
@ -339,8 +338,6 @@ static
void kf_factor(int n,int * facbuf)
{
int p=4;
double floor_sqrt;
floor_sqrt = floor( sqrt((double)n) );
/*factor out powers of 4, powers of 2, then any remaining primes */
do {
@ -350,7 +347,7 @@ void kf_factor(int n,int * facbuf)
case 2: p = 3; 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 */
}
n /= p;
@ -358,7 +355,6 @@ void kf_factor(int n,int * facbuf)
*facbuf++ = n;
} while (n > 1);
}
/*
*
* User-callable function to allocate all necessary storage space for the fft.
@ -383,7 +379,14 @@ kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem
int i;
st->nfft=nfft;
st->inverse = inverse_fft;
#ifdef FIXED_POINT
for (i=0;i<nfft;++i) {
spx_word32_t phase = i;
if (!st->inverse)
phase = -phase;
kf_cexp2(st->twiddles+i, DIV32(SHL32(phase,17),nfft));
}
#else
for (i=0;i<nfft;++i) {
const double pi=3.14159265358979323846264338327;
double phase = ( -2*pi /nfft ) * i;
@ -391,7 +394,7 @@ kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem
phase *= -1;
kf_cexp(st->twiddles+i, phase );
}
#endif
kf_factor(nfft,st->factors);
}
return st;

View file

@ -17,7 +17,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
#endif
#include "kiss_fftr.h"
#include "math_approx.h"
#include "_kiss_fft_guts.h"
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;
kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize);
#ifdef FIXED_POINT
for (i=0;i<nfft;++i) {
double phase =
-3.14159265358979323846264338327 * ((double) i / nfft + .5);
if (inverse_fft)
phase *= -1;
spx_word32_t phase = i+(nfft>>1);
if (!inverse_fft)
phase = -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;
}
@ -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;
if ( st->substate->inverse) {
speex_warning("kiss fft usage error: improper alloc\n");
//exit(1);
speex_error("kiss fft usage error: improper alloc\n");
}
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;
if (st->substate->inverse == 0) {
speex_warning ("kiss fft usage error: improper alloc\n");
//exit (1);
speex_error ("kiss fft usage error: improper alloc\n");
}
ncfft = st->substate->nfft;

View file

@ -34,74 +34,74 @@
#endif
int dummy_epic_48k_variable=0;
const int dummy_epic_48k_variable=0;
#ifdef EPIC_48K
const signed char gain_cdbk_ulbr[192] = {
-31, -48, -30,
-19, -10, -18,
-33, -22, -45,
-5, -56, -43,
-30, -56, -3,
-59, -17, -52,
-41, -60, -58,
-64, -47, -22,
-30, -31, -31,
-29, -14, -31,
-22, -37, -58,
-31, -44, 13,
-37, 0, 1,
-46, -55, -35,
-56, -14, -53,
-8, 1, -36,
-29, -15, -27,
-29, -39, -28,
-43, -5, 3,
-51, -27, -54,
10, -46, -36,
3, -3, -42,
-27, 16, -22,
-34, -52, 13,
-31, -21, -28,
-34, -45, -40,
-20, -48, 4,
-40, -27, 16,
-6, 11, -44,
-35, 12, -5,
19, -33, -37,
-29, 18, -32,
-29, -23, -19,
16, -47, -28,
-34, -30, 17,
-20, 2, -26,
-38, -40, -36,
15, -14, -40,
-39, 14, -9,
-15, 25, -39,
-26, 19, -32,
-39, 17, -14,
10, -36, -26,
14, -13, -40,
-29, -21, -12,
-8, 19, -39,
-36, -18, 15,
-32, -38, -38,
-19, 4, -23,
-38, -7, 11,
9, -10, -39,
-37, 24, -19,
-34, -5, -8,
-20, 23, -41,
-4, 17, -31,
-17, -26, -26,
-24, 28, -36,
-7, 15, -39,
-42, 16, -11,
-29, 14, -6,
-36, 28, -27,
-21, 5, -26,
11, -9, -39,
-38, -7, 13,
const signed char gain_cdbk_ulbr[256] = {
-31, -48, -30, 10,
-19, -10, -18, 25,
-33, -22, -45, 12,
-5, -56, -43, 31,
-30, -56, -3, 28,
-59, -17, -52, 31,
-41, -60, -58, 32,
-64, -47, -22, 29,
-30, -31, -31, 2,
-29, -14, -31, 11,
-22, -37, -58, 21,
-31, -44, 13, 29,
-37, 0, 1, 35,
-46, -55, -35, 20,
-56, -14, -53, 32,
-8, 1, -36, 31,
-29, -15, -27, 13,
-29, -39, -28, 7,
-43, -5, 3, 37,
-51, -27, -54, 23,
10, -46, -36, 30,
3, -3, -42, 37,
-27, 16, -22, 32,
-34, -52, 13, 34,
-31, -21, -28, 8,
-34, -45, -40, 12,
-20, -48, 4, 32,
-40, -27, 16, 31,
-6, 11, -44, 41,
-35, 12, -5, 37,
19, -33, -37, 29,
-29, 18, -32, 27,
-29, -23, -19, 13,
16, -47, -28, 34,
-34, -30, 17, 27,
-20, 2, -26, 26,
-38, -40, -36, 9,
15, -14, -40, 37,
-39, 14, -9, 38,
-15, 25, -39, 41,
-26, 19, -32, 29,
-39, 17, -14, 37,
10, -36, -26, 26,
14, -13, -40, 37,
-29, -21, -12, 17,
-8, 19, -39, 41,
-36, -18, 15, 33,
-32, -38, -38, 6,
-19, 4, -23, 29,
-38, -7, 11, 37,
9, -10, -39, 35,
-37, 24, -19, 37,
-34, -5, -8, 27,
-20, 23, -41, 38,
-4, 17, -31, 39,
-17, -26, -26, 14,
-24, 28, -36, 36,
-7, 15, -39, 40,
-42, 16, -11, 40,
-29, 14, -6, 38,
-36, 28, -27, 35,
-21, 5, -26, 27,
11, -9, -39, 37,
-38, -7, 13, 38
};

View file

@ -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 */
if (a < -32767) a = 32767;
if (a < -32767) a = -32767;
if (a > 32767) a = 32767;
ak[j-1] = (short)a;

View file

@ -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

View file

@ -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);
spx_word32_t e0;
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);
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_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++)
{
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;
}
#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);
e0=inner_prod(sw, sw, len);
for (i=start;i<end;i++)
@ -200,19 +236,27 @@ void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *p
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);
/* FIXME: Fixed-point and floating-point code should be merged */
#ifdef FIXED_POINT
{
VARDECL(spx_word16_t *corr16);
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);
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)
{
for (i=-end;i<len;i++)
{
sw[i]=SHL16(sw[i],1);
}
}
#endif
/* Search for the best pitch prediction gain */
for (i=start;i<=end;i++)
{
spx_word16_t tmp = MULT16_16_16(corr16[i-start],corr16[i-start]);
@ -242,47 +286,23 @@ void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *p
}
}
}
}
#else
for (i=start;i<=end;i++)
{
float tmp = corr[i-start]*corr[i-start];
if (tmp*best_ener[N-1]>best_score[N-1]*(1+energy[i-start]))
{
for (j=0;j<N;j++)
{
if (tmp*best_ener[j]>best_score[j]*(1+energy[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]=energy[i-start]+1;
pitch[j]=i;
break;
}
}
}
}
#endif
/* Compute open-loop gain */
/* Compute open-loop gain if necessary */
if (gain)
{
for (j=0;j<N;j++)
{
spx_word16_t g;
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) */
if (g<0)
g = 0;
gain[j]=g;
}
}
}
#endif
@ -342,7 +362,8 @@ const spx_word16_t *r,
spx_word16_t *new_target,
int *cdbk_index,
int plc_tuning,
spx_word32_t cumul_gain
spx_word32_t cumul_gain,
int scaledown
)
{
int i,j;
@ -366,6 +387,9 @@ spx_word32_t cumul_gain
x[1]=tmp1+nsf;
x[2]=tmp1+2*nsf;
for (j=0;j<nsf;j++)
new_target[j] = target[j];
{
VARDECL(spx_mem_t *mm);
int pp=pitch-1;
@ -379,6 +403,16 @@ spx_word32_t cumul_gain
else
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++)
mm[j] = 0;
iir_mem16(e, ak, e, nsf, p, mm, stack);
@ -391,13 +425,18 @@ spx_word32_t cumul_gain
for (i=1;i>=0;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);
for (j=0;j<nsf-1;j++)
x[i][j+1]=ADD32(x[i+1][j],MULT16_16_P14(r[j+1], e0));
}
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 (j=0;j<=i;j++)
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])),
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);
@ -520,6 +559,7 @@ spx_word32_t *cumul_gain
const ltp_params *params;
const signed char *gain_cdbk;
int gain_cdbk_size;
int scaledown=0;
VARDECL(int *nbest);
@ -545,6 +585,25 @@ spx_word32_t *cumul_gain
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)
N=end-start+1;
if (end != start)
@ -562,7 +621,7 @@ spx_word32_t *cumul_gain
for (j=0;j<nsf;j++)
exc[j]=0;
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)
{
for (j=0;j<nsf;j++)
@ -588,7 +647,14 @@ spx_word32_t *cumul_gain
exc[i]=best_exc[i];
for (i=0;i<nsf;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;
}
@ -717,8 +783,8 @@ spx_word32_t *cumul_gain
)
{
int i;
VARDECL(spx_sig_t *res);
ALLOC(res, nsf, spx_sig_t);
VARDECL(spx_word16_t *res);
ALLOC(res, nsf, spx_word16_t);
#ifdef FIXED_POINT
if (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]);
}
syn_percep_zero(exc, ak, awk1, awk2, res, nsf, p, stack);
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;
}
@ -770,7 +838,7 @@ int cdbk_offset
for (i=0;i<nsf;i++)
{
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;
gain_val[0]=gain_val[2]=0;

View file

@ -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" (x), "=r" (y), "=r" (x0),
"=m" (sum1), "=m" (sum2), "=m" (sum3), "=m" (sum4), "=r" (dead1)
: "m" (y0), "m" (y1), "m" (y2), "m" (y3),
"m" (x), "m" (y),
"m" (sum1), "m" (sum2), "m" (sum3), "m" (sum4)
: "0" (y0), "1" (y1), "2" (y2), "3" (y3),
"8" (x), "9" (y),
"11" (sum1), "12" (sum2), "13" (sum3), "14" (sum4)
: "cc", "memory"
);
}

View 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

View file

@ -34,181 +34,89 @@
#include "config.h"
#endif
#include "math_approx.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
/* 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 C1 21173
#define C2 -12627
#define C3 4215
#define C3 4204
spx_word16_t spx_sqrt(spx_word32_t x)
{
int k=0;
int k;
spx_word32_t rt;
if (x<=0)
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--;
}
k = spx_ilog4(x)-6;
x = VSHR32(x, (k<<1));
rt = ADD16(C0, MULT16_16_Q14(x, ADD16(C1, MULT16_16_Q14(x, ADD16(C2, MULT16_16_Q14(x, (C3)))))));
if (rt > 16383)
rt = 16383;
if (k>0)
rt <<= k;
else
rt >>= -k;
rt >>=7;
rt = VSHR32(rt,7-k);
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) */
@ -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
#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)));
}
}
#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;
}

View file

@ -35,37 +35,28 @@
#ifndef MATH_APPROX_H
#define MATH_APPROX_H
#include "misc.h"
#ifdef FIXED_POINT
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);
float spx_sqrtf(float arg);
spx_word16_t spx_acos(spx_word16_t x);
float spx_floor(float x);
float spx_exp(float 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);
spx_word32_t spx_exp(spx_word16_t x);
spx_word16_t spx_cos_norm(spx_word32_t x);
#define floor spx_floor
#define exp spx_exp
#define sqrt spx_sqrt
#define acos spx_acos
#define cos spx_cos
/* Input in Q15, output in Q14 */
spx_word16_t spx_atan(spx_word32_t x);
#else
#define spx_sqrt sqrt
#define spx_acos acos
#define spx_exp exp
#define spx_cos_norm(x) (cos((.5f*M_PI)*(x)))
#define spx_atan atan
#endif
#endif

View file

@ -79,9 +79,6 @@
#define M_PI 3.14159265358979323846
#endif
#define min(a,b) ((a)<(b) ? (a) : (b))
#define max(a,b) ((a)>(b) ? (a) : (b))
#ifdef FIXED_POINT
#define WEIGHT_SHIFT 11
#define NORMALIZE_SCALEDOWN 5
@ -90,19 +87,40 @@
#define WEIGHT_SHIFT 0
#endif
/* If enabled, the transition between blocks is smooth, so there isn't any blocking
aftifact when adapting. The cost is an extra FFT and a matrix-vector multiply */
#define SMOOTH_BLOCKS
/* If enabled, the AEC will use a foreground filter and a background filter to be more robust to double-talk
and difficult signals in general. The cost is an extra FFT and a matrix-vector multiply */
#define TWO_PATH
#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)
#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)
#endif
#define PLAYBACK_DELAY 2
void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len);
/** Speex echo cancellation state. */
struct SpeexEchoState_ {
int frame_size; /**< Number of samples processed each time */
@ -111,31 +129,40 @@ struct SpeexEchoState_ {
int cancel_count;
int adapted;
int saturated;
int screwed_up;
spx_int32_t sampling_rate;
spx_word16_t spec_average;
spx_word16_t beta0;
spx_word16_t beta_max;
spx_word32_t sum_adapt;
spx_word16_t *e;
spx_word16_t *x;
spx_word16_t *X;
spx_word16_t *d;
spx_word16_t *y;
spx_word16_t leak_estimate;
spx_word16_t *e; /* scratch */
spx_word16_t *x; /* Far-end input buffer (2N) */
spx_word16_t *X; /* Far-end buffer (M+1 frames) in frequency domain */
spx_word16_t *input; /* scratch */
spx_word16_t *y; /* scratch */
spx_word16_t *last_y;
spx_word32_t *Yps;
spx_word16_t *Y;
spx_word16_t *Y; /* scratch */
spx_word16_t *E;
spx_word32_t *PHI;
spx_word32_t *W;
spx_word32_t *power;
spx_float_t *power_1;
spx_word16_t *wtmp;
#ifdef FIXED_POINT
spx_word16_t *wtmp2;
spx_word32_t *PHI; /* scratch */
spx_word32_t *W; /* (Background) filter weights */
#ifdef TWO_PATH
spx_word32_t *foreground; /* Foreground filter weights */
spx_word32_t Davg1; /* 1st recursive average of the residual power difference */
spx_word32_t Davg2; /* 2nd recursive average of the residual power difference */
spx_float_t Dvar1; /* Estimated variance of 1st estimator */
spx_float_t Dvar2; /* Estimated variance of 2nd estimator */
#endif
spx_word32_t *Rf;
spx_word32_t *Yf;
spx_word32_t *Xf;
spx_word32_t *power; /* Power of the far-end signal */
spx_float_t *power_1;/* Inverse power of far-end */
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 *Yh;
spx_float_t Pey;
@ -151,6 +178,7 @@ struct SpeexEchoState_ {
/* NOTE: If you only use speex_echo_cancel() and want to save some memory, remove this */
spx_int16_t *play_buf;
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)
@ -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)
{
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
/** 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;
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++)
{
prod[i] = FLOAT_MUL32(w[j],MAC16_16(MULT16_16(X[i],Y[i]), X[i+1],Y[i+1]));
prod[i+1] = FLOAT_MUL32(w[j],MAC16_16(MULT16_16(-X[i+1],Y[i]), X[i],Y[i+1]));
W = FLOAT_AMULT(p, w[j]);
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 */
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->sum_adapt = 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->spec_average = DIV32_16(SHL32(EXTEND32(st->frame_size), 15), st->sampling_rate);
#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->beta_max = (.5f*st->frame_size)/st->sampling_rate;
#endif
st->leak_estimate = 0;
st->fft_table = spx_fft_init(N);
st->e = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
st->x = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
st->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->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->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));
@ -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->E = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_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->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));
@ -331,12 +398,10 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
st->power_1[i] = FLOAT_ONE;
for (i=0;i<N*M;i++)
st->W[i] = 0;
for (i=0;i<N;i++)
st->PHI[i] = 0;
{
spx_word32_t sum = 0;
/* 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);
sum = EXTEND32(st->prop[0]);
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--)
{
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->Pey = st->Pyy = FLOAT_ONE;
st->play_buf = (spx_int16_t*)speex_alloc(2*st->frame_size*sizeof(spx_int16_t));
st->play_buf_pos = 0;
#ifdef TWO_PATH
st->Davg1 = st->Davg2 = 0;
st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
#endif
st->play_buf = (spx_int16_t*)speex_alloc((PLAYBACK_DELAY+1)*st->frame_size*sizeof(spx_int16_t));
st->play_buf_pos = PLAYBACK_DELAY*st->frame_size;
st->play_buf_started = 0;
return st;
}
@ -374,23 +445,48 @@ void speex_echo_state_reset(SpeexEchoState *st)
{
int i, M, N;
st->cancel_count=0;
st->screwed_up = 0;
N = st->window_size;
M = st->M;
for (i=0;i<N*M;i++)
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++)
st->X[i] = 0;
for (i=0;i<=st->frame_size;i++)
{
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++)
{
st->E[i] = 0;
st->x[i] = 0;
}
st->notch_mem[0] = st->notch_mem[1] = 0;
st->memX=st->memD=st->memE=0;
st->saturated = 0;
st->adapted = 0;
st->sum_adapt = 0;
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->x);
speex_free(st->d);
speex_free(st->input);
speex_free(st->y);
speex_free(st->last_y);
speex_free(st->Yps);
speex_free(st->Yf);
speex_free(st->Rf);
speex_free(st->Xf);
@ -415,6 +510,9 @@ void speex_echo_state_destroy(SpeexEchoState *st)
speex_free(st->Y);
speex_free(st->E);
speex_free(st->W);
#ifdef TWO_PATH
speex_free(st->foreground);
#endif
speex_free(st->PHI);
speex_free(st->power);
speex_free(st->power_1);
@ -428,17 +526,19 @@ void speex_echo_state_destroy(SpeexEchoState *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;
/*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)
{
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;
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];
} 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)
{
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)
{
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;
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;
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 {
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 */
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 N,M;
spx_word32_t Syy,See,Sxx;
spx_word16_t leak_estimate;
spx_word32_t Syy,See,Sxx,Sdd, Sff;
#ifdef TWO_PATH
spx_word32_t Dbf;
int update_foreground;
#endif
spx_word32_t Sey;
spx_word16_t ss, ss_1;
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;
#endif
filter_dc_notch16(ref, st->notch_radius, st->d, st->frame_size, st->notch_mem);
/* Copy input data to buffer */
/* Apply a notch filter to make sure DC doesn't end up causing problems */
filter_dc_notch16(in, st->notch_radius, st->input, st->frame_size, st->notch_mem);
/* Copy input data to buffer and apply pre-emphasis */
for (i=0;i<st->frame_size;i++)
{
spx_word16_t tmp;
spx_word32_t tmp32;
st->x[i] = st->x[i+st->frame_size];
tmp32 = SUB32(EXTEND32(echo[i]), EXTEND32(MULT16_16_P15(st->preemph, st->memX)));
tmp32 = SUB32(EXTEND32(far_end[i]), EXTEND32(MULT16_16_P15(st->preemph, st->memX)));
#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)
{
tmp32 = 32767;
st->saturated = 1;
st->saturated = M+1;
}
if (tmp32 < -32767)
{
tmp32 = -32767;
st->saturated = 1;
st->saturated = M+1;
}
#endif
st->x[i+st->frame_size] = EXTRACT16(tmp32);
st->memX = echo[i];
st->memX = far_end[i];
tmp = st->d[i];
st->d[i] = st->d[i+st->frame_size];
tmp32 = SUB32(EXTEND32(tmp), EXTEND32(MULT16_16_P15(st->preemph, st->memD)));
tmp32 = SUB32(EXTEND32(st->input[i]), EXTEND32(MULT16_16_P15(st->preemph, st->memD)));
#ifdef FIXED_POINT
if (tmp32 > 32767)
{
tmp32 = 32767;
if (st->saturated == 0)
st->saturated = 1;
}
if (tmp32 < -32767)
{
tmp32 = -32767;
if (st->saturated == 0)
st->saturated = 1;
}
#endif
st->d[i+st->frame_size] = tmp32;
st->memD = tmp;
st->memD = st->input[i];
st->input[i] = tmp32;
}
/* 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];
}
/* Convert x (echo input) to frequency domain */
/* Convert x (far end) to frequency domain */
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
spectral_mul_accum(st->X, st->W, st->Y, N, M);
#ifdef TWO_PATH
/* Compute foreground filter */
spectral_mul_accum(st->X, st->foreground, st->Y, N, M);
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
/* Adjust proportional adaption rate */
mdf_adjust_prop (st->W, N, M, st->prop);
/* Compute weight gradient */
if (!st->saturated)
if (st->saturated == 0)
{
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++)
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) */
for (j=0;j<M;j++)
{
@ -597,28 +730,103 @@ 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);
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) */
for (i=0;i<st->frame_size;i++)
{
spx_word32_t tmp_out;
#ifdef SMOOTH_BLOCKS
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->d[i+st->frame_size]), EXTEND32(y));
#ifdef TWO_PATH
tmp_out = SUB32(EXTEND32(st->input[i]), EXTEND32(st->e[i+st->frame_size]));
#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
/* Saturation */
if (tmp_out>32767)
tmp_out = 32767;
else if (tmp_out<-32768)
tmp_out = -32768;
tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(st->preemph, st->memE)));
/* This is an arbitrary test for saturation */
if (ref[i] <= -32000 || ref[i] >= 32000)
/* This is an arbitrary test for saturation in the microphone signal */
if (in[i] <= -32000 || in[i] >= 32000)
{
tmp_out = 0;
if (st->saturated == 0)
st->saturated = 1;
}
out[i] = (spx_int16_t)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++)
{
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 */
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);
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 */
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;
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->Y, st->Yf, 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++)
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;
for (j=0;j<=st->frame_size;j++)
st->power[j] = 0;
st->power[j] = 100;
for (i=0;i<M;i++)
{
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))
st->Pey = st->Pyy;
/* 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) */
if (leak_estimate > 16383)
leak_estimate = 32767;
if (st->leak_estimate > 16383)
st->leak_estimate = 32767;
else
leak_estimate = SHL16(leak_estimate,1);
/*printf ("%f\n", leak_estimate);*/
st->leak_estimate = SHL16(st->leak_estimate,1);
/*printf ("%f\n", st->leak_estimate);*/
/* Compute Residual to Error Ratio */
#ifdef FIXED_POINT
tmp32 = MULT16_32_Q15(leak_estimate,Syy);
tmp32 = MULT16_32_Q15(st->leak_estimate,Syy);
tmp32 = ADD32(SHR32(Sxx,13), ADD32(tmp32, SHL32(tmp32,1)));
/* 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);
RER = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32,See),15));
#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) */
if (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
/* 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;
}
if (st->adapted)
{
/* Normal learning rate calculation once we're past the minimal adaptation phase */
for (i=0;i<=st->frame_size;i++)
{
spx_word32_t r, e;
/* 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;
#ifdef FIXED_POINT
if (r>SHR32(e,1))
@ -764,10 +1002,12 @@ 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] = 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 */
spx_word16_t adapt_rate=0;
if (Sxx > SHR32(MULT16_16(N, 1000),6))
{
tmp32 = MULT16_32_Q15(QCONST16(.25f, 15), Sxx);
#ifdef FIXED_POINT
if (tmp32 > SHR32(See,2))
@ -777,7 +1017,7 @@ void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int
tmp32 = .25*See;
#endif
adapt_rate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32, See),15));
}
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);
@ -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);
}
/* Compute spectrum of estimated echo for use in an echo post-filter (if necessary)*/
if (Yout)
{
spx_word16_t leak2;
/* Save residual echo so it can be used by the nonlinear processor */
if (st->adapted)
{
/* If the filter is adapted, take the filtered echo */
for (i=0;i<st->frame_size;i++)
st->last_y[i] = st->last_y[st->frame_size+i];
for (i=0;i<st->frame_size;i++)
st->last_y[st->frame_size+i] = ref[i]-out[i];
st->last_y[st->frame_size+i] = in[i]-out[i];
} else {
/* 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];
/* If filter isn't adapted yet, all we can do is take the far end signal directly */
/* moved earlier: for (i=0;i<N;i++)
st->last_y[i] = st->x[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, st->Yps, N);
power_spectrum(st->Y, residual_echo, N);
#ifdef FIXED_POINT
if (leak_estimate > 16383)
if (st->leak_estimate > 16383)
leak2 = 32767;
else
leak2 = SHL16(leak_estimate, 1);
leak2 = SHL16(st->leak_estimate, 1);
#else
if (leak_estimate>.5)
if (st->leak_estimate>.5)
leak2 = 1;
else
leak2 = 2*leak_estimate;
leak2 = 2*st->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]);
}
}
residual_echo[i] = (spx_int32_t)MULT16_32_Q15(leak2,residual_echo[i]);
}
int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr)
{

View file

@ -34,15 +34,11 @@
#include "config.h"
#endif
#include "../codecs.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "misc.h"
#ifdef USER_MISC
#include "user_misc.h"
#endif
@ -51,16 +47,14 @@
#include "misc_bfin.h"
#endif
//static struct codec_api *rb;//defined in decoder api speex.c
#ifndef RELEASE
void print_vec(float *vec, int len, char *name)
{
/* int i;
int i;
printf ("%s ", name);
for (i=0;i<len;i++)
printf (" %f", vec[i]);
printf ("\n");*/
printf ("\n");
}
#endif
@ -72,7 +66,7 @@ long long spx_mips=0;
spx_uint32_t be_int(spx_uint32_t i)
{
spx_uint32_t ret=i;
#ifndef ROCKBOX_BIG_ENDIAN
#ifndef WORDS_BIGENDIAN
ret = i>>24;
ret += (i>>8)&0x0000ff00;
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 ret=i;
#ifdef ROCKBOX_BIG_ENDIAN
#ifdef WORDS_BIGENDIAN
ret = i>>24;
ret += (i>>8)&0x0000ff00;
ret += (i<<8)&0x00ff0000;
@ -93,86 +87,38 @@ spx_uint32_t le_int(spx_uint32_t i)
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
void *speex_alloc (int size)
{
//printf("CLC:%d\n",size);
return codec_calloc(size,1);
return calloc(size,1);
}
#endif
#ifndef OVERRIDE_SPEEX_ALLOC_SCRATCH
void *speex_alloc_scratch (int size)
{
//printf("CLCS:%d\n",size);
return codec_calloc(size,1);
return calloc(size,1);
}
#endif
#ifndef OVERRIDE_SPEEX_REALLOC
void *speex_realloc (void *ptr, int size)
{
//printf("CLCR:%d\n",size);
return codec_realloc(ptr, size);
return realloc(ptr, size);
}
#endif
#ifndef OVERRIDE_SPEEX_FREE
void speex_free (void *ptr)
{
//printf("CLF:%d\n",ptr);
codec_free(ptr);
free(ptr);
}
#endif
#ifndef OVERRIDE_SPEEX_FREE_SCRATCH
void speex_free_scratch (void *ptr)
{
codec_free(ptr);
free(ptr);
}
#endif
@ -186,60 +132,50 @@ void *speex_move (void *dest, void *src, int n)
#ifndef OVERRIDE_SPEEX_ERROR
void speex_error(const char *str)
{
//fprintf ("Fatal error: %s\n", str);
//exit(1);
fprintf (stderr, "Fatal error: %s\n", str);
exit(1);
}
#endif
#ifndef OVERRIDE_SPEEX_WARNING
void speex_warning(const char *str)
{
//fprintf ("warning: %s\n", str);
fprintf (stderr, "warning: %s\n", str);
}
#endif
#ifndef OVERRIDE_SPEEX_WARNING_INT
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
#define FIXED_POINT
#ifdef FIXED_POINT
spx_word16_t speex_rand(spx_word16_t std, spx_int32_t *seed)
{
// spx_word32_t res;
// *seed = 1664525 * *seed + 1013904223;
// res = MULT16_16(EXTRACT16(SHR32(*seed,16)),std);
// return PSHR32(SUB32(res, SHR(res, 3)),14);
return 0;
spx_word32_t res;
*seed = 1664525 * *seed + 1013904223;
res = MULT16_16(EXTRACT16(SHR32(*seed,16)),std);
return EXTRACT16(PSHR32(SUB32(res, SHR32(res, 3)),14));
}
#else
spx_word16_t speex_rand(spx_word16_t std, spx_int32_t *seed)
{
// const unsigned int jflone = 0x3f800000;
// const unsigned int jflmsk = 0x007fffff;
// union {int i; float f;} ran;
// *seed = 1664525 * *seed + 1013904223;
// ran.i = jflone | (jflmsk & *seed);
// ran.f -= 1.5;
// return 3.4642*std*ran.f;
return 0;
const unsigned int jflone = 0x3f800000;
const unsigned int jflmsk = 0x007fffff;
union {int i; float f;} ran;
*seed = 1664525 * *seed + 1013904223;
ran.i = jflone | (jflmsk & *seed);
ran.f -= 1.5;
return 3.4642*std*ran.f;
}
#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
void _speex_putc(int ch, void *file)
{
//FILE *f = (FILE *)file;
//printf("%c", ch);
FILE *f = (FILE *)file;
fprintf(f, "%c", ch);
}
#endif

View file

@ -40,10 +40,7 @@
#define SPEEX_MINOR_VERSION 1 /**< Minor Speex version. */
#define SPEEX_MICRO_VERSION 13 /**< Micro Speex version. */
#define SPEEX_EXTRA_VERSION "" /**< Extra Speex version. */
#define SPEEX_VERSION "speex-1.2-beta1" /**< Speex version string. */
#define FIXED_POINT
//#define EPIC_48K
#define SPEEX_VERSION "speex-1.2beta1" /**< Speex version string. */
#endif
/* 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?
#endif
#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
#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"
#ifndef RELEASE
@ -125,12 +98,6 @@ void speex_free_scratch (void *ptr);
/** Speex wrapper for mem_move */
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 */
void speex_error(const char *str);

View file

@ -495,7 +495,7 @@ static const SpeexSBMode sb_wb_mode = {
#endif
.012, /*lag_factor*/
QCONST16(.0002,15), /*lpc_floor*/
0.9,
QCONST16(0.9f,15),
{NULL, &wb_submode1, &wb_submode2, &wb_submode3, &wb_submode4, NULL, NULL, NULL},
3,
{1, 8, 2, 3, 4, 5, 5, 6, 6, 7, 7},
@ -541,7 +541,7 @@ static const SpeexSBMode sb_uwb_mode = {
#endif
.012, /*lag_factor*/
QCONST16(.0002,15), /*lpc_floor*/
0.7,
QCONST16(0.7f,15),
{NULL, &wb_submode1, NULL, NULL, NULL, NULL, NULL, NULL},
1,
{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_shape_sign_unquant,
&split_cb_nb_48k,
#ifdef FIXED_POINT
22938, 16384, 11796, 18022,
#else
0.7, 0.5, .36, .55,
#endif
QCONST16(.7,15),
144
};
@ -622,7 +618,6 @@ static const SpeexNBMode nb_48k_mode = {
240, /*frameSize*/
48, /*subframeSize*/
10, /*lpcSize*/
640, /*bufSize*/
17, /*pitchStart*/
144, /*pitchEnd*/
0.9, /*gamma1*/

View file

@ -130,7 +130,7 @@ typedef struct SpeexSBMode {
spx_word16_t gamma2; /**< Perceptual filter parameter #1 */
float lag_factor; /**< Lag-windowing parameter */
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 */
int defaultSubmode; /**< Default sub-mode to use when encoding */

View file

@ -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->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));
@ -280,6 +280,8 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
int pitch_half[2];
int ol_pitch_id=0;
#endif
spx_word32_t ener=0;
spx_word16_t fine_gain;
spx_word16_t *in = (spx_word16_t*)vin;
st=(EncState *)state;
@ -432,7 +434,7 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
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_gain=SHR(sqrt(1+ol_gain2/st->frameSize),SIG_SHIFT);
ol_gain=SHR32(sqrt(1+ol_gain2/st->frameSize),SIG_SHIFT);
} else
#endif
@ -490,7 +492,7 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
/* delta_qual*=.1*(3+st->vbr_quality);*/
if (st->vbr_enabled)
{
int mode;
spx_int32_t mode;
int choice=0;
float min_diff=100;
mode = 8;
@ -540,7 +542,7 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
if (st->abr_enabled)
{
int bitrate;
spx_int32_t bitrate;
speex_encoder_ctl(state, SPEEX_GET_BITRATE, &bitrate);
st->abr_drift+=(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;
spx_word16_t *sw;
spx_word16_t *exc;
spx_sig_t *innov_save = NULL;
int pitch;
int response_bound = st->subframeSize;
#ifdef EPIC_48K
@ -739,9 +740,6 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
exc=st->exc+offset;
/* Weighted signal */
sw=st->sw+offset;
/* Pointer for saving innovation */
if (st->innov_save)
innov_save = st->innov_save+offset;
/* LSP interpolation (quantized and unquantized) */
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++)
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++)
target[i]=SUB16(sw[i],PSHR32(ringing[i],1));
target[i]=EXTRACT16(SATURATE(SUB32(sw[i],PSHR32(ringing[i],1)),32767));
/* Reset excitation */
for (i=0;i<st->subframeSize;i++)
@ -901,15 +899,12 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
}
/* Quantization of innovation */
{
spx_word32_t ener=0;
spx_word16_t fine_gain;
for (i=0;i<st->subframeSize;i++)
innov[i]=0;
/* FIXME: Make sure this is save from overflows (so far so good) */
for (i=0;i<st->subframeSize;i++)
real_exc[i] = SUB16(real_exc[i], PSHR32(exc32[i],SIG_SHIFT-1));
real_exc[i] = EXTRACT16(SUB32(EXTEND32(real_exc[i]), PSHR32(exc32[i],SIG_SHIFT-1)));
ener = SHL32(EXTEND32(compute_rms16(real_exc, st->subframeSize)),SIG_SHIFT);
@ -960,16 +955,8 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
signal_mul(innov, innov, ener, st->subframeSize);
for (i=0;i<st->subframeSize;i++)
exc[i] = EXTRACT16(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT));
} else {
speex_error("No fixed codebook");
}
exc[i] = EXTRACT16(SATURATE32(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT),32767));
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 */
if (SUBMODE(double_codebook)) {
char *tmp_stack=stack;
@ -978,22 +965,25 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
for (i=0;i<st->subframeSize;i++)
innov2[i]=0;
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_params), st->lpcSize, st->subframeSize,
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++)
exc[i] = ADD32(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]);
}
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));
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++)
sw[i] = exc[i];
@ -1166,7 +1156,7 @@ static void nb_decode_lost(DecState *st, spx_word16_t *out, char *stack)
pitch_gain = st->last_pitch_gain;
if (pitch_gain>54)
pitch_gain = 54;
pitch_gain = SHL(pitch_gain, 9);
pitch_gain = SHL16(pitch_gain, 9);
#else
pitch_gain = GAIN_SCALING_1*st->last_pitch_gain;
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->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 */
st->pitch_gain_buf_idx = 0;
}
@ -1226,7 +1216,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
VARDECL(spx_lsp_t *qlsp);
spx_word16_t pitch_average=0;
#ifdef EPIC_48K
int pitch_half[2];
int pitch_half[2] = {0, 0};
int ol_pitch_id=0;
#endif
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);
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 pgain=GAIN_SCALING_1*st->last_pitch_gain;
@ -1426,6 +1416,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
int qe;
qe = speex_bits_unpack_unsigned(bits, 5);
#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]);
#else
ol_gain = SIG_SCALING*exp(qe/3.5);
@ -1458,7 +1449,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
int offset;
spx_word16_t *exc;
spx_word16_t *sp;
spx_sig_t *innov_save = NULL;
spx_word16_t *innov_save = NULL;
spx_word16_t tmp;
#ifdef EPIC_48K
@ -1576,16 +1567,38 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
{
/*Fixed codebook contribution*/
SUBMODE(innovation_unquant)(innov, SUBMODE(innovation_params), st->subframeSize, bits, stack, &st->seed);
} else {
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
/* 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 {
speex_error("No fixed codebook");
}
/*Vocoder mode*/
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];
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)
{
case SPEEX_GET_FRAME_SIZE:
(*(int*)ptr) = st->frameSize;
(*(spx_int32_t*)ptr) = st->frameSize;
break;
case SPEEX_SET_LOW_MODE:
case SPEEX_SET_MODE:
st->submodeSelect = st->submodeID = (*(int*)ptr);
st->submodeSelect = st->submodeID = (*(spx_int32_t*)ptr);
break;
case SPEEX_GET_LOW_MODE:
case SPEEX_GET_MODE:
(*(int*)ptr) = st->submodeID;
(*(spx_int32_t*)ptr) = st->submodeID;
break;
case SPEEX_SET_VBR:
st->vbr_enabled = (*(int*)ptr);
st->vbr_enabled = (*(spx_int32_t*)ptr);
break;
case SPEEX_GET_VBR:
(*(int*)ptr) = st->vbr_enabled;
(*(spx_int32_t*)ptr) = st->vbr_enabled;
break;
case SPEEX_SET_VAD:
st->vad_enabled = (*(int*)ptr);
st->vad_enabled = (*(spx_int32_t*)ptr);
break;
case SPEEX_GET_VAD:
(*(int*)ptr) = st->vad_enabled;
(*(spx_int32_t*)ptr) = st->vad_enabled;
break;
case SPEEX_SET_DTX:
st->dtx_enabled = (*(int*)ptr);
st->dtx_enabled = (*(spx_int32_t*)ptr);
break;
case SPEEX_GET_DTX:
(*(int*)ptr) = st->dtx_enabled;
(*(spx_int32_t*)ptr) = st->dtx_enabled;
break;
case SPEEX_SET_ABR:
st->abr_enabled = (*(spx_int32_t*)ptr);
st->vbr_enabled = st->abr_enabled!=0;
if (st->vbr_enabled)
{
int i=10;
spx_int32_t i=10;
spx_int32_t rate, target;
float vbr_qual;
target = (*(spx_int32_t*)ptr);
@ -1825,7 +1811,7 @@ int nb_encoder_ctl(void *state, int request, void *ptr)
break;
case SPEEX_SET_QUALITY:
{
int quality = (*(int*)ptr);
int quality = (*(spx_int32_t*)ptr);
if (quality < 0)
quality = 0;
if (quality > 10)
@ -1834,7 +1820,7 @@ int nb_encoder_ctl(void *state, int request, void *ptr)
}
break;
case SPEEX_SET_COMPLEXITY:
st->complexity = (*(int*)ptr);
st->complexity = (*(spx_int32_t*)ptr);
if (st->complexity<0)
st->complexity=0;
break;
@ -1843,7 +1829,7 @@ int nb_encoder_ctl(void *state, int request, void *ptr)
break;
case SPEEX_SET_BITRATE:
{
int i=10;
spx_int32_t i=10;
spx_int32_t rate, target;
target = (*(spx_int32_t*)ptr);
while (i>=0)
@ -1884,21 +1870,21 @@ int nb_encoder_ctl(void *state, int request, void *ptr)
}
break;
case SPEEX_SET_SUBMODE_ENCODING:
st->encode_submode = (*(int*)ptr);
st->encode_submode = (*(spx_int32_t*)ptr);
break;
case SPEEX_GET_SUBMODE_ENCODING:
(*(int*)ptr) = st->encode_submode;
(*(spx_int32_t*)ptr) = st->encode_submode;
break;
case SPEEX_GET_LOOKAHEAD:
(*(int*)ptr)=(st->windowSize-st->frameSize);
(*(spx_int32_t*)ptr)=(st->windowSize-st->frameSize);
break;
case SPEEX_SET_PLC_TUNING:
st->plc_tuning = (*(int*)ptr);
st->plc_tuning = (*(spx_int32_t*)ptr);
if (st->plc_tuning>100)
st->plc_tuning=100;
break;
case SPEEX_GET_PLC_TUNING:
(*(int*)ptr)=(st->plc_tuning);
(*(spx_int32_t*)ptr)=(st->plc_tuning);
break;
case SPEEX_SET_VBR_MAX_BITRATE:
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:
{
int i;
spx_word16_t *e = (spx_word16_t*)ptr;
for (i=0;i<st->frameSize;i++)
e[i]=st->exc[i];
for (i=0;i<st->nbSubframes;i++)
((spx_word16_t*)ptr)[i] = compute_rms16(st->exc+i*st->subframeSize, st->subframeSize);
}
break;
case SPEEX_GET_RELATIVE_QUALITY:
(*(float*)ptr)=st->relative_quality;
break;
case SPEEX_SET_INNOVATION_SAVE:
st->innov_save = (spx_sig_t*)ptr;
st->innov_rms_save = (spx_word16_t*)ptr;
break;
case SPEEX_SET_WIDEBAND:
st->isWideband = *((int*)ptr);
st->isWideband = *((spx_int32_t*)ptr);
break;
default:
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_MODE:
st->submodeID = (*(int*)ptr);
st->submodeID = (*(spx_int32_t*)ptr);
break;
case SPEEX_GET_LOW_MODE:
case SPEEX_GET_MODE:
(*(int*)ptr) = st->submodeID;
(*(spx_int32_t*)ptr) = st->submodeID;
break;
case SPEEX_SET_ENH:
st->lpc_enh_enabled = *((int*)ptr);
st->lpc_enh_enabled = *((spx_int32_t*)ptr);
break;
case SPEEX_GET_ENH:
*((int*)ptr) = st->lpc_enh_enabled;
*((spx_int32_t*)ptr) = st->lpc_enh_enabled;
break;
case SPEEX_GET_FRAME_SIZE:
(*(int*)ptr) = st->frameSize;
(*(spx_int32_t*)ptr) = st->frameSize;
break;
case SPEEX_GET_BITRATE:
if (st->submodes[st->submodeID])
@ -2007,13 +1992,13 @@ int nb_decoder_ctl(void *state, int request, void *ptr)
}
break;
case SPEEX_SET_SUBMODE_ENCODING:
st->encode_submode = (*(int*)ptr);
st->encode_submode = (*(spx_int32_t*)ptr);
break;
case SPEEX_GET_SUBMODE_ENCODING:
(*(int*)ptr) = st->encode_submode;
(*(spx_int32_t*)ptr) = st->encode_submode;
break;
case SPEEX_GET_LOOKAHEAD:
(*(int*)ptr)=st->subframeSize;
(*(spx_int32_t*)ptr)=st->subframeSize;
break;
case SPEEX_SET_HIGHPASS:
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:
{
int i;
spx_word16_t *e = (spx_word16_t*)ptr;
for (i=0;i<st->frameSize;i++)
e[i]=st->exc[i];
for (i=0;i<st->nbSubframes;i++)
((spx_word16_t*)ptr)[i] = compute_rms16(st->exc+i*st->subframeSize, st->subframeSize);
}
break;
case SPEEX_GET_DTX_STATUS:
*((int*)ptr) = st->dtx_enabled;
*((spx_int32_t*)ptr) = st->dtx_enabled;
break;
case SPEEX_SET_INNOVATION_SAVE:
st->innov_save = (spx_sig_t*)ptr;
st->innov_save = (spx_word16_t*)ptr;
break;
case SPEEX_SET_WIDEBAND:
st->isWideband = *((int*)ptr);
st->isWideband = *((spx_int32_t*)ptr);
break;
default:
speex_warning_int("Unknown nb_ctl request: ", request);

View file

@ -96,12 +96,12 @@ typedef struct EncState {
spx_mem_t *mem_exc2; /**< Filter memory for excitation (whole frame) */
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_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 */
float vbr_quality; /**< Quality setting for VBR encoding */
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 */
int vad_enabled; /**< 1 for enabling VAD, 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_hp[2]; /**< High-pass filter memory */
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 */
int last_pitch; /**< Pitch of last correctly decoded frame */

File diff suppressed because it is too large Load diff

View file

@ -37,7 +37,7 @@
#include "misc.h"
#include "math_approx.h"
//#include <math.h>
#include <math.h>
#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_HALF = {16384,-15};
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
static inline spx_float_t PSEUDOFLOAT(spx_int32_t x)
{
int e=0;
@ -67,18 +65,8 @@ static inline spx_float_t PSEUDOFLOAT(spx_int32_t x)
spx_float_t r = {0,0};
return r;
}
while (x>32767)
{
x >>= 1;
/*x *= .5;*/
e++;
}
while (x<16383)
{
x <<= 1;
/*x *= 2;*/
e--;
}
e = spx_ilog2(ABS32(x))-14;
x = VSHR32(x, e);
if (sign)
{
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;
}
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)
{
@ -232,64 +228,40 @@ static inline spx_int32_t FLOAT_EXTRACT32(spx_float_t a)
return EXTEND32(a.m)<<a.e;
}
static inline spx_int32_t FLOAT_MUL32(spx_float_t a, spx_word32_t b)
{
if (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);
return VSHR32(MULT16_32_Q15(a.m, b),-a.e-15);
}
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;
/* FIXME: Handle the sign */
if (a==0)
if (a==0 || b==0)
{
return FLOAT_ZERO;
}
while (a>32767)
{
a >>= 1;
e++;
}
while (a<16384)
{
a <<= 1;
e--;
}
while (b>32767)
{
b >>= 1;
e++;
}
while (b<16384)
{
b <<= 1;
e--;
}
e1 = spx_ilog2(ABS32(a));
a = VSHR32(a, e1-14);
e2 = spx_ilog2(ABS32(b));
b = VSHR32(b, e2-14);
r.m = MULT16_16_Q15(a,b);
r.e = e+15;
r.e = e1+e2-13;
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)
{
int e=0;
spx_float_t r;
/* FIXME: Handle the sign */
if (a==0)
{
return FLOAT_ZERO;
}
while (a<SHL32(EXTEND32(b.m),14))
{
a <<= 1;
e--;
}
while (a>=SHL32(EXTEND32(b.m-1),15))
e = spx_ilog2(ABS32(a))-spx_ilog2(b.m-1)-15;
a = VSHR32(a, e);
if (ABS32(a)>=SHL32(EXTEND32(b.m-1),15))
{
a >>= 1;
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)
{
int e=0;
int e0=0,e=0;
spx_float_t r;
/* FIXME: Handle the sign */
if (a==0)
{
return FLOAT_ZERO;
}
while (b>32767)
if (b>32767)
{
b >>= 1;
e--;
e0 = spx_ilog2(b)-14;
b = VSHR32(b, e0);
e0 = -e0;
}
while (a<SHL32(b,14))
{
a <<= 1;
e--;
}
while (a>=SHL32(b-1,15))
e = spx_ilog2(ABS32(a))-spx_ilog2(b-1)-15;
a = VSHR32(a, e);
if (ABS32(a)>=SHL32(EXTEND32(b-1),15))
{
a >>= 1;
e++;
}
e += e0;
r.m = DIV32_16(a,b);
r.e = e;
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)
{
int e=0;
spx_int32_t num;
spx_float_t r;
if (b.m<=0)
{
speex_warning_int("Attempted to divide by", b.m);
return FLOAT_ONE;
}
num = a.m;
a.m = ABS16(a.m);
while (a.m >= b.m)
{
e++;
@ -350,7 +328,7 @@ static inline spx_float_t FLOAT_SQRT(spx_float_t a)
{
spx_float_t r;
spx_int32_t m;
m = a.m << 14;
m = SHL32(EXTEND32(a.m), 14);
r.e = a.e - 14;
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 PSEUDOFLOAT(x) (x)
#define FLOAT_MULT(a,b) ((a)*(b))
#define FLOAT_AMULT(a,b) ((a)*(b))
#define FLOAT_MUL32(a,b) ((a)*(b))
#define FLOAT_DIV32(a,b) ((a)/(b))
#define FLOAT_EXTRACT16(a) (a)

View file

@ -417,7 +417,7 @@ void lsp_quant_48k(spx_lsp_t *lsp, spx_lsp_t *qlsp, int order, SpeexBits *bits)
#ifdef FIXED_POINT
for (i=0;i<order;i++)
qlsp[i]=PSHR(qlsp[i],2);
qlsp[i]=PSHR16(qlsp[i],2);
#else
for (i=0;i<order;i++)
qlsp[i]=qlsp[i]*0.00097655;

View 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;
}

View 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

View file

@ -58,16 +58,9 @@ typedef struct SBEncState {
spx_word16_t gamma2; /**< Perceptual weighting coef 2 */
char *stack; /**< Temporary allocation stack */
spx_sig_t *x0d, *x1d; /**< QMF filter signals*/
spx_sig_t *high; /**< High-band signal (buffer) */
spx_sig_t *y0, *y1; /**< QMF synthesis signals */
spx_word16_t *high; /**< High-band signal (buffer) */
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 */
spx_word16_t *lagWindow; /**< Auto-correlation window */
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_sw; /**< Perceptual signal memory */
spx_word32_t *pi_gain;
spx_sig_t *innov_save; /**< If non-NULL, innovation is copied here */
spx_sig_t *low_innov; /**< Lower-band innovation is copied here magically */
spx_word16_t *exc_rms;
spx_word16_t *innov_rms_save; /**< If non-NULL, innovation is copied here */
float vbr_quality; /**< Quality setting for VBR encoding */
int vbr_enabled; /**< 1 for enabling VBR, 0 otherwise */
@ -125,13 +118,9 @@ typedef struct SBDecState {
int lpc_enh_enabled;
char *stack;
spx_sig_t *x0d, *x1d;
spx_sig_t *high;
spx_sig_t *y0, *y1;
spx_word32_t *g0_mem, *g1_mem;
spx_sig_t *exc;
spx_sig_t *excBuf;
spx_word16_t *excBuf;
spx_lsp_t *qlsp;
spx_lsp_t *old_qlsp;
spx_lsp_t *interp_qlsp;
@ -139,9 +128,10 @@ typedef struct SBDecState {
spx_mem_t *mem_sp;
spx_word32_t *pi_gain;
spx_sig_t *innov_save; /** If non-NULL, innovation is copied here */
spx_sig_t *low_innov; /** Lower-band innovation is copied here magically */
spx_word16_t *exc_rms;
spx_word16_t *innov_save; /** If non-NULL, innovation is copied here */
spx_word16_t last_ener;
spx_int32_t seed;
int encode_submode;

View file

@ -37,7 +37,7 @@
#endif
#include "modes.h"
#include "math_approx.h"
#include <math.h>
#ifndef NULL
#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 i;
int N;
spx_int32_t N;
spx_int16_t short_in[MAX_IN_SAMPLES];
speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N);
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 i, ret;
int N;
spx_int32_t N;
spx_int16_t short_out[MAX_IN_SAMPLES];
speex_decoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N);
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 i;
int N;
spx_int32_t N;
float float_in[MAX_IN_SAMPLES];
speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N);
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 i;
int N;
spx_int32_t N;
float float_out[MAX_IN_SAMPLES];
int ret;
speex_decoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N);

View file

@ -21,6 +21,8 @@
extern "C" {
#endif
#include "../../codec.h"
typedef short spx_ogg_int16_t;
typedef unsigned short spx_ogg_uint16_t;
typedef int spx_ogg_int32_t;

View file

@ -35,6 +35,10 @@
#ifndef SPEEX_H
#define SPEEX_H
/** @defgroup Codec Speex encoder and decoder
* This is the Speex codec itself.
* @{
*/
#include "speex_bits.h"
#include "speex_types.h"
@ -427,5 +431,5 @@ const SpeexMode * speex_lib_get_mode (int mode);
}
#endif
/** @}*/
#endif

View file

@ -35,6 +35,11 @@
#ifndef 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
extern "C" {
@ -72,13 +77,20 @@ void speex_bits_rewind(SpeexBits *bits);
void speex_bits_read_from(SpeexBits *bits, char *bytes, int len);
/** Append bytes to the bit-stream
*
* @param bits Bit-stream to operate on
* @param bytes pointer to the bytes what will be appended
* @param len Number of bytes of append
*/
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);
/** 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);
/** 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);
/** Get the value of the next bit in the stream, without modifying the
* "cursor" position
*
* @param bits Bit-stream to operate on
* @return Value of the bit peeked (one bit only)
*/
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
*
* @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);
@ -148,4 +167,5 @@ void speex_bits_insert_terminator(SpeexBits *bits);
}
#endif
/* @} */
#endif

View file

@ -35,6 +35,9 @@
#ifndef SPEEX_CALLBACKS_H
#define SPEEX_CALLBACKS_H
/** @defgroup SpeexCallbacks Various definitions for Speex callbacks supported by the decoder.
* @{
*/
#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);
/** Standard handler for VBR request (Set VBR, no questions asked) */
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);
/** 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);
@ -124,5 +130,5 @@ int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *da
}
#endif
/** @} */
#endif

View file

@ -1,11 +1,13 @@
#ifndef __SPEEX_TYPES_H__
#define __SPEEX_TYPES_H__
/* these are filled in by configure */
typedef short spx_int16_t;
typedef unsigned short spx_uint16_t;
typedef int spx_int32_t;
typedef unsigned int spx_uint32_t;
#include "inttypes.h"
#define spx_int16_t int16_t
#define spx_uint16_t uint16_t
#define spx_int32_t int32_t
#define spx_uint32_t uint32_t
#define spx_int64_t int64_t
#define spx_uint64_t uint64_t
#endif

View file

@ -33,8 +33,11 @@
#ifndef SPEEX_ECHO_H
#define SPEEX_ECHO_H
#include "speex/speex_types.h"
/** @defgroup SpeexEchoState SpeexEchoState: Acoustic echo canceller
* This is the acoustic echo canceller module.
* @{
*/
#include "speex_types.h"
#ifdef __cplusplus
extern "C" {
@ -48,33 +51,63 @@ extern "C" {
/** Get sampling rate */
#define SPEEX_ECHO_GET_SAMPLING_RATE 25
/*struct drft_lookup;*/
/** Internal echo canceller state. Should never be accessed directly. */
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;
/** 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);
/** Destroys an echo canceller state */
/** Destroys an echo canceller state
* @param st Echo canceller state
*/
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);
/** Perform echo cancellation using internal playback buffer */
void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out, spx_int32_t *Yout);
/** Perform echo cancellation using internal playback buffer, which is delayed by two frames
* 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);
/** 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);
/** 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 ptr Data exchanged to-from function
* @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

View file

@ -36,6 +36,10 @@
#ifndef 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"
@ -45,6 +49,7 @@ extern "C" {
struct SpeexMode;
/** Length of the Speex header identifier */
#define SPEEX_HEADER_STRING_LENGTH 8
/** 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

View file

@ -35,6 +35,11 @@
#ifndef 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_bits.h"
@ -43,58 +48,120 @@
extern "C" {
#endif
/** Generic adaptive jitter buffer state */
struct JitterBuffer_;
/** Generic adaptive jitter buffer state */
typedef struct JitterBuffer_ JitterBuffer;
/** Definition of an incoming packet */
typedef struct _JitterBufferPacket JitterBufferPacket;
/** Definition of an incoming packet */
struct _JitterBufferPacket {
char *data;
spx_uint32_t len;
spx_uint32_t timestamp;
spx_uint32_t span;
char *data; /**< Data bytes contained in the packet */
spx_uint32_t len; /**< Length of the packet in bytes */
spx_uint32_t timestamp; /**< Timestamp for the packet */
spx_uint32_t span; /**< Time covered by the packet (same units as timestamp) */
};
/** Packet has been retrieved */
#define JITTER_BUFFER_OK 0
/** Packet is missing */
#define JITTER_BUFFER_MISSING 1
/** Packet is incomplete (does not cover the entive tick */
#define JITTER_BUFFER_INCOMPLETE 2
/** There was an error in the jitter buffer */
#define JITTER_BUFFER_INTERNAL_ERROR -1
/** Invalid argument */
#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);
/** Reset jitter buffer */
/** Restores jitter buffer to its original state
*
* @param jitter Jitter buffer state
*/
void jitter_buffer_reset(JitterBuffer *jitter);
/** Destroy jitter buffer */
/** Destroys jitter buffer
*
* @param jitter Jitter buffer state
*/
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);
/** 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);
/** 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);
/** Advance by one tick */
/** Advance by one tick
*
* @param jitter Jitter buffer state
*/
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 {
SpeexBits current_packet; /**< Current Speex packet */
int valid_bits; /**< True if Speex bits are valid */
JitterBuffer *packets;
JitterBuffer *packets; /**< Generic jitter buffer state */
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;
/** 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);
/** Destroy jitter buffer */
@ -113,5 +180,5 @@ int speex_jitter_get_pointer_timestamp(SpeexJitter *jitter);
}
#endif
/* @} */
#endif

View file

@ -1,8 +1,10 @@
/* Copyright (C) 2003 Epic Games
Written by Jean-Marc Valin */
/**
@file speex_preprocess.h
@brief Speex preprocessor
* @file speex_preprocess.h
* @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
@ -34,91 +36,61 @@
#ifndef 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
extern "C" {
#endif
struct drft_lookup;
/** State of the preprocessor (one per channel). Should never be accessed directly. */
struct SpeexPreprocessState_;
/** Speex pre-processor state. */
typedef struct 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 */
/** State of the preprocessor (one per channel). Should never be accessed directly. */
typedef struct SpeexPreprocessState_ SpeexPreprocessState;
/* 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) */
float *ps; /**< Current power spectrum */
float *gain2; /**< Adjusted gains */
float *window; /**< Analysis/Synthesis window */
float *noise; /**< Noise estimate */
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 */
/** Creates a new preprocessing state. You MUST create one state per channel processed.
* @param frame_size Number of samples to process at one time (should correspond to 10-20 ms). Must be
* the same value as that used for the echo canceller for residual echo cancellation to work.
* @param sampling_rate Sampling rate used for the input.
* @return Newly created preprocessor state
*/
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);
/** 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);
/** Preprocess a frame */
void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo);
/** Update preprocessor state, but do not compute the output
* @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);
@ -158,14 +130,57 @@ int speex_preprocess_ctl(SpeexPreprocessState *st, int request, void *ptr);
/** Get preprocessor dereverb decay */
#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
/** Get probability required for the VAD to go from silence to voice */
#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
/** Get probability required for the VAD to stay in the voice state (integer percent) */
#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
}
#endif
/** @}*/
#endif

View 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

View file

@ -34,6 +34,10 @@
#ifndef 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_bits.h"
@ -74,5 +78,5 @@ int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data);
}
#endif
/** @} */
#endif

View file

@ -21,11 +21,106 @@
*/
#ifndef _SPEEX_TYPES_H
#define _SPEEX_TYPES_H
#include "inttypes.h"
#define spx_int16_t int16_t
#define spx_uint16_t uint16_t
#define spx_int32_t int32_t
#define spx_uint32_t uint32_t
#define spx_int64_t int64_t
#define spx_uint64_t uint64_t
#if defined(_WIN32)
# if defined(__CYGWIN__)
# include <_G_config.h>
typedef _G_int32_t spx_int32_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 */

View file

@ -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 m;
spx_int32_t m;
m = speex_bits_unpack_unsigned(bits, 4);
speex_encoder_ctl(data, SPEEX_SET_MODE, &m);
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 m;
spx_int32_t m;
m = speex_bits_unpack_unsigned(bits, 4);
speex_encoder_ctl(data, SPEEX_SET_LOW_MODE, &m);
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 m;
spx_int32_t m;
m = speex_bits_unpack_unsigned(bits, 4);
speex_encoder_ctl(data, SPEEX_SET_HIGH_MODE, &m);
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 vbr;
spx_int32_t vbr;
vbr = speex_bits_unpack_unsigned(bits, 1);
speex_encoder_ctl(data, SPEEX_SET_VBR, &vbr);
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 enh;
spx_int32_t enh;
enh = speex_bits_unpack_unsigned(bits, 1);
speex_decoder_ctl(data, SPEEX_SET_ENH, &enh);
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 qual;
float qual;
qual = speex_bits_unpack_unsigned(bits, 4);
speex_encoder_ctl(data, SPEEX_SET_VBR_QUALITY, &qual);
return 0;

View file

@ -36,7 +36,7 @@
#include <speex/speex_stereo.h>
#include <speex/speex_callbacks.h>
#include "vq.h"
#include <math_approx.h>
#include <math.h>
/*float e_ratio_quant[4] = {1, 1.26, 1.587, 2};*/
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;
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;
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_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_left = spx_sqrtf(e_left/(e_tot+.01));
e_right = spx_sqrtf(e_right/(e_tot+.01));
e_left = sqrt(e_left/(e_tot+.01));
e_right = sqrt(e_right/(e_tot+.01));
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))
sign=-1;
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);
stereo->e_ratio = e_ratio_quant[tmp];

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View file

@ -37,7 +37,7 @@
#endif
#include "vbr.h"
#include "math_approx.h"
#include <math.h>
#define sqr(x) ((x)*(x))

View file

@ -41,7 +41,7 @@
#ifdef _USE_SSE
#include <xmmintrin.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"
#elif defined(BFIN_ASM)
#include "vq_bfin.h"

View file

@ -35,12 +35,12 @@
#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)
{
int i/*,j*/;
int i,j;
for (i=0;i<entries;i+=4)
{
#if 1
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__ (
"mov %0, #0 \n\t"
"mov %1, #0 \n\t"

View file

@ -20,9 +20,10 @@
#include "libspeex/speex/ogg.h"
#include "libspeex/speex/speex.h"
#include "libspeex/speex/speex_callbacks.h"
#include "libspeex/speex/speex_header.h"
#include "libspeex/speex/speex_stereo.h"
#include "libspeex/speex/speex_callbacks.h"
#include "libspeex/speex/speex_types.h"
#include "codeclib.h"
#define MAX_FRAME_SIZE 2000