1
0
Fork 0
forked from len0rd/rockbox

codecs: Update libspeex from 1.2beta3 to 1.2rc1

This is a relatively minor bump, but it's the first step towards
bringing this current.

Change-Id: Iab6c9b0c77f0ba705280434ea74b513364719499
This commit is contained in:
Solomon Peachy 2024-05-08 10:36:38 -04:00
parent 8ef20383b1
commit 547b6a570d
21 changed files with 1406 additions and 1001 deletions

View file

@ -1,10 +1,11 @@
Copyright 2002-2006 Copyright 2002-2008 Xiph.org Foundation
Xiph.org Foundation Copyright 2002-2008 Jean-Marc Valin
Jean-Marc Valin Copyright 2005-2007 Analog Devices Inc.
David Rowe Copyright 2005-2008 Commonwealth Scientific and Industrial Research
EpicGames Organisation (CSIRO)
Analog Devices Copyright 1993, 2002, 2006 David Rowe
Commonwealth Scientific and Industrial Research Organisation (CSIRO) Copyright 2003 EpicGames
Copyright 1992-1994 Jutta Degener, Carsten Bormann
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions modification, are permitted provided that the following conditions

View file

@ -1,6 +1,6 @@
Library: libspeex-1.2beta3 (SVN version 14054) Library: libspeex-1.2rc1
Imported: 2007-03-12 by Dan Everton Imported 1.2beta3: 2007-03-12 by Dan Everton
Updated 1.2rc1: 2024-05-08 by Solomon Peachy
This directory contains a local version of libspeex for decoding Ogg/Speex This directory contains a local version of libspeex for decoding Ogg/Speex
audio streams. audio streams.

View file

@ -235,7 +235,7 @@ typedef float spx_word32_t;
#ifdef FIXED_DEBUG #ifdef FIXED_DEBUG
long long spx_mips=0; extern long long spx_mips=0;
#endif #endif

View file

@ -46,7 +46,7 @@
#endif #endif
#ifdef ROCKBOX_VOICE_ENCODER #ifdef ROCKBOX_VOICE_ENCODER
void speex_bits_init(SpeexBits *bits) EXPORT void speex_bits_init(SpeexBits *bits)
{ {
bits->chars = (char*)speex_alloc(MAX_CHARS_PER_FRAME); bits->chars = (char*)speex_alloc(MAX_CHARS_PER_FRAME);
if (!bits->chars) if (!bits->chars)
@ -62,7 +62,7 @@ void speex_bits_init(SpeexBits *bits)
#if 0 #if 0
/* Rockbox: unused */ /* Rockbox: unused */
void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size) EXPORT void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size)
{ {
bits->chars = (char*)buff; bits->chars = (char*)buff;
bits->buf_size = buf_size; bits->buf_size = buf_size;
@ -73,7 +73,7 @@ void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size)
} }
#endif #endif
void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size) EXPORT void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size)
{ {
bits->chars = (char*)buff; bits->chars = (char*)buff;
bits->buf_size = buf_size; bits->buf_size = buf_size;
@ -88,7 +88,7 @@ void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size)
} }
#ifndef ROCKBOX_VOICE_CODEC #ifndef ROCKBOX_VOICE_CODEC
void speex_bits_destroy(SpeexBits *bits) EXPORT void speex_bits_destroy(SpeexBits *bits)
{ {
if (bits->owner) if (bits->owner)
speex_free(bits->chars); speex_free(bits->chars);
@ -97,7 +97,7 @@ void speex_bits_destroy(SpeexBits *bits)
#endif #endif
#ifdef ROCKBOX_VOICE_ENCODER #ifdef ROCKBOX_VOICE_ENCODER
void speex_bits_reset(SpeexBits *bits) EXPORT void speex_bits_reset(SpeexBits *bits)
{ {
/* We only need to clear the first byte now */ /* We only need to clear the first byte now */
bits->chars[0]=0; bits->chars[0]=0;
@ -110,7 +110,7 @@ void speex_bits_reset(SpeexBits *bits)
#if 0 #if 0
/* Rockbox: unused */ /* Rockbox: unused */
void speex_bits_rewind(SpeexBits *bits) EXPORT void speex_bits_rewind(SpeexBits *bits)
{ {
bits->charPtr=0; bits->charPtr=0;
bits->bitPtr=0; bits->bitPtr=0;
@ -119,7 +119,7 @@ void speex_bits_rewind(SpeexBits *bits)
#endif #endif
#if !defined(SPEEX_VOICE_ENCODER) && !defined(ROCKBOX_VOICE_CODEC) #if !defined(SPEEX_VOICE_ENCODER) && !defined(ROCKBOX_VOICE_CODEC)
void speex_bits_read_from(SpeexBits *bits, char *chars, int len) EXPORT void speex_bits_read_from(SpeexBits *bits, char *chars, int len)
{ {
int i; int i;
int nchars = len / BYTES_PER_CHAR; int nchars = len / BYTES_PER_CHAR;
@ -166,9 +166,10 @@ static void speex_bits_flush(SpeexBits *bits)
bits->charPtr=0; bits->charPtr=0;
} }
void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes) EXPORT void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes)
{ {
int i,pos; int i,pos;
int nchars = nbytes/BYTES_PER_CHAR; int nchars = nbytes/BYTES_PER_CHAR;
if (((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR)+nchars > bits->buf_size) if (((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR)+nchars > bits->buf_size)
@ -200,7 +201,7 @@ void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes)
#endif #endif
#ifndef SPEEX_DISABLE_ENCODER #ifndef SPEEX_DISABLE_ENCODER
int speex_bits_write(SpeexBits *bits, char *chars, int max_nbytes) EXPORT int speex_bits_write(SpeexBits *bits, char *chars, int max_nbytes)
{ {
int i; int i;
int max_nchars = max_nbytes/BYTES_PER_CHAR; int max_nchars = max_nbytes/BYTES_PER_CHAR;
@ -223,7 +224,7 @@ int speex_bits_write(SpeexBits *bits, char *chars, int max_nbytes)
return max_nchars*BYTES_PER_CHAR; return max_nchars*BYTES_PER_CHAR;
} }
int speex_bits_write_whole_bytes(SpeexBits *bits, char *chars, int max_nbytes) EXPORT int speex_bits_write_whole_bytes(SpeexBits *bits, char *chars, int max_nbytes)
{ {
int max_nchars = max_nbytes/BYTES_PER_CHAR; int max_nchars = max_nbytes/BYTES_PER_CHAR;
int i; int i;
@ -241,7 +242,7 @@ int speex_bits_write_whole_bytes(SpeexBits *bits, char *chars, int max_nbytes)
return max_nchars*BYTES_PER_CHAR; return max_nchars*BYTES_PER_CHAR;
} }
void speex_bits_pack(SpeexBits *bits, int data, int nbBits) EXPORT void speex_bits_pack(SpeexBits *bits, int data, int nbBits)
{ {
unsigned int d=data; unsigned int d=data;
@ -287,7 +288,7 @@ void speex_bits_pack(SpeexBits *bits, int data, int nbBits)
#if 0 #if 0
/* Rockbox: unused */ /* Rockbox: unused */
int speex_bits_unpack_signed(SpeexBits *bits, int nbBits) EXPORT int speex_bits_unpack_signed(SpeexBits *bits, int nbBits)
{ {
unsigned int d=speex_bits_unpack_unsigned(bits,nbBits); unsigned int d=speex_bits_unpack_unsigned(bits,nbBits);
/* If number is negative */ /* If number is negative */
@ -299,7 +300,7 @@ int speex_bits_unpack_signed(SpeexBits *bits, int nbBits)
} }
#endif #endif
unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits) EXPORT unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits)
{ {
unsigned int d=0; unsigned int d=0;
if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+nbBits>bits->nbBits) if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+nbBits>bits->nbBits)
@ -323,7 +324,7 @@ unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits)
#if 0 #if 0
/* Rockbox: unused */ /* Rockbox: unused */
unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits) EXPORT unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits)
{ {
unsigned int d=0; unsigned int d=0;
int bitPtr, charPtr; int bitPtr, charPtr;
@ -353,7 +354,7 @@ unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits)
} }
#endif #endif
int speex_bits_peek(SpeexBits *bits) EXPORT int speex_bits_peek(SpeexBits *bits)
{ {
if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+1>bits->nbBits) if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+1>bits->nbBits)
bits->overflow=1; bits->overflow=1;
@ -362,7 +363,7 @@ int speex_bits_peek(SpeexBits *bits)
return (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1; return (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1;
} }
void speex_bits_advance(SpeexBits *bits, int n) EXPORT void speex_bits_advance(SpeexBits *bits, int n)
{ {
if (((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+n>bits->nbBits) || bits->overflow){ if (((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+n>bits->nbBits) || bits->overflow){
bits->overflow=1; bits->overflow=1;
@ -372,7 +373,7 @@ void speex_bits_advance(SpeexBits *bits, int n)
bits->bitPtr = (bits->bitPtr+n) & (BITS_PER_CHAR-1); /* modulo by BITS_PER_CHAR */ bits->bitPtr = (bits->bitPtr+n) & (BITS_PER_CHAR-1); /* modulo by BITS_PER_CHAR */
} }
int speex_bits_remaining(SpeexBits *bits) EXPORT int speex_bits_remaining(SpeexBits *bits)
{ {
if (bits->overflow) if (bits->overflow)
return -1; return -1;
@ -382,14 +383,14 @@ int speex_bits_remaining(SpeexBits *bits)
#if 0 #if 0
/* Rockbox: unused */ /* Rockbox: unused */
int speex_bits_nbytes(SpeexBits *bits) EXPORT int speex_bits_nbytes(SpeexBits *bits)
{ {
return ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR); return ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR);
} }
#endif #endif
#ifndef SPEEX_DISABLE_ENCODER #ifndef SPEEX_DISABLE_ENCODER
void speex_bits_insert_terminator(SpeexBits *bits) EXPORT void speex_bits_insert_terminator(SpeexBits *bits)
{ {
if (bits->bitPtr) if (bits->bitPtr)
speex_bits_pack(bits, 0, 1); speex_bits_pack(bits, 0, 1);

View file

@ -17,7 +17,11 @@
/* Make use of ARM4E assembly optimizations */ /* Make use of ARM4E assembly optimizations */
#if defined(CPU_ARM) #if defined(CPU_ARM)
#if (ARM_ARCH < 5)
#define ARM4_ASM #define ARM4_ASM
#else
#define ARM5E_ASM
#endif
#endif #endif
/* Make use of Coldfire assembly optimizations */ /* Make use of Coldfire assembly optimizations */
@ -137,13 +141,13 @@
#define SPEEX_MAJOR_VERSION 1 #define SPEEX_MAJOR_VERSION 1
/* Version micro */ /* Version micro */
#define SPEEX_MICRO_VERSION 15 #define SPEEX_MICRO_VERSION 16
/* Version minor */ /* Version minor */
#define SPEEX_MINOR_VERSION 1 #define SPEEX_MINOR_VERSION 1
/* Complete version string */ /* Complete version string */
#define SPEEX_VERSION "1.2beta3" #define SPEEX_VERSION "1.2rc1"
/* Define to 1 if you have the ANSI C header files. */ /* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1 #define STDC_HEADERS 1
@ -184,3 +188,7 @@
#define RELEASE 1 #define RELEASE 1
/* We don't care */
#define EXPORT
#define USE_KISS_FFT

View file

@ -36,10 +36,6 @@
#include "config-speex.h" #include "config-speex.h"
#endif #endif
/*#define USE_SMALLFT*/
#define USE_KISS_FFT
#include "arch.h" #include "arch.h"
#include "os_support.h" #include "os_support.h"
@ -130,6 +126,119 @@ void spx_ifft(void *table, float *in, float *out)
spx_drft_backward((struct drft_lookup *)table, out); spx_drft_backward((struct drft_lookup *)table, out);
} }
#elif defined(USE_INTEL_MKL)
#include <mkl.h>
struct mkl_config {
DFTI_DESCRIPTOR_HANDLE desc;
int N;
};
void *spx_fft_init(int size)
{
struct mkl_config *table = (struct mkl_config *) speex_alloc(sizeof(struct mkl_config));
table->N = size;
DftiCreateDescriptor(&table->desc, DFTI_SINGLE, DFTI_REAL, 1, size);
DftiSetValue(table->desc, DFTI_PACKED_FORMAT, DFTI_PACK_FORMAT);
DftiSetValue(table->desc, DFTI_PLACEMENT, DFTI_NOT_INPLACE);
DftiSetValue(table->desc, DFTI_FORWARD_SCALE, 1.0f / size);
DftiCommitDescriptor(table->desc);
return table;
}
void spx_fft_destroy(void *table)
{
struct mkl_config *t = (struct mkl_config *) table;
DftiFreeDescriptor(t->desc);
speex_free(table);
}
void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out)
{
struct mkl_config *t = (struct mkl_config *) table;
DftiComputeForward(t->desc, in, out);
}
void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out)
{
struct mkl_config *t = (struct mkl_config *) table;
DftiComputeBackward(t->desc, in, out);
}
#elif defined(USE_GPL_FFTW3)
#include <fftw3.h>
struct fftw_config {
float *in;
float *out;
fftwf_plan fft;
fftwf_plan ifft;
int N;
};
void *spx_fft_init(int size)
{
struct fftw_config *table = (struct fftw_config *) speex_alloc(sizeof(struct fftw_config));
table->in = fftwf_malloc(sizeof(float) * (size+2));
table->out = fftwf_malloc(sizeof(float) * (size+2));
table->fft = fftwf_plan_dft_r2c_1d(size, table->in, (fftwf_complex *) table->out, FFTW_PATIENT);
table->ifft = fftwf_plan_dft_c2r_1d(size, (fftwf_complex *) table->in, table->out, FFTW_PATIENT);
table->N = size;
return table;
}
void spx_fft_destroy(void *table)
{
struct fftw_config *t = (struct fftw_config *) table;
fftwf_destroy_plan(t->fft);
fftwf_destroy_plan(t->ifft);
fftwf_free(t->in);
fftwf_free(t->out);
speex_free(table);
}
void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out)
{
int i;
struct fftw_config *t = (struct fftw_config *) table;
const int N = t->N;
float *iptr = t->in;
float *optr = t->out;
const float m = 1.0 / N;
for(i=0;i<N;++i)
iptr[i]=in[i] * m;
fftwf_execute(t->fft);
out[0] = optr[0];
for(i=1;i<N;++i)
out[i] = optr[i+1];
}
void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out)
{
int i;
struct fftw_config *t = (struct fftw_config *) table;
const int N = t->N;
float *iptr = t->in;
float *optr = t->out;
iptr[0] = in[0];
iptr[1] = 0.0f;
for(i=1;i<N;++i)
iptr[i+1] = in[i];
iptr[N+1] = 0.0f;
fftwf_execute(t->ifft);
for(i=0;i<N;++i)
out[i] = optr[i];
}
#elif defined(USE_KISS_FFT) #elif defined(USE_KISS_FFT)
#include "kiss_fftr.h" #include "kiss_fftr.h"

View file

@ -86,7 +86,7 @@ int normalize16(const spx_sig_t *x, spx_word16_t *y, spx_sig_t max_scale, int le
"\tmov %5, %5, asr %3 \n" "\tmov %5, %5, asr %3 \n"
"\tstrh %5, [%1], #2 \n" "\tstrh %5, [%1], #2 \n"
"\tbge .normalize16loop%=\n" "\tbgt .normalize16loop%=\n"
: "=r" (dead1), "=r" (dead2), "=r" (dead3), "=r" (dead4), : "=r" (dead1), "=r" (dead2), "=r" (dead3), "=r" (dead4),
"=r" (dead5), "=r" (dead6) "=r" (dead5), "=r" (dead6)
: "0" (x), "1" (y), "2" (len>>2), "3" (sig_shift) : "0" (x), "1" (y), "2" (len>>2), "3" (sig_shift)

View file

@ -161,7 +161,7 @@ static inline int SHL32(long long a, int shift)
} }
#define PSHR16(a,shift) (SHR16(ADD16((a),((1<<((shift))>>1))),shift)) #define PSHR16(a,shift) (SHR16(ADD16((a),((1<<((shift))>>1))),shift))
#define PSHR32(a,shift) (SHR32(ADD32((a),((1<<((shift))>>1))),shift)) #define PSHR32(a,shift) (SHR32(ADD32((a),((EXTEND32(1)<<((shift))>>1))),shift))
#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) #define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) #define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
@ -279,7 +279,7 @@ static inline int _MULT16_32_QX(int a, long long b, int Q, char *file, int line)
{ {
fprintf (stderr, "MULT16_32_Q%d: inputs are not short+int: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); 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))) if (ABS32(b)>=(EXTEND32(1)<<(15+Q)))
fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
res = (((long long)a)*(long long)b) >> Q; res = (((long long)a)*(long long)b) >> Q;
if (!VERIFY_INT(res)) if (!VERIFY_INT(res))
@ -295,9 +295,9 @@ static inline int MULT16_32_PX(int a, long long b, int Q)
{ {
fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d\n", Q, (int)a, (int)b); 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))) if (ABS32(b)>=(EXTEND32(1)<<(15+Q)))
fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b); 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; res = ((((long long)a)*(long long)b) + ((EXTEND32(1)<<Q)>>1))>> Q;
if (!VERIFY_INT(res)) 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); fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d\n", Q, (int)a, (int)b,(int)res);
spx_mips+=5; spx_mips+=5;

View file

@ -47,14 +47,14 @@
#define SHR32(a,shift) ((a) >> (shift)) #define SHR32(a,shift) ((a) >> (shift))
#define SHL32(a,shift) ((a) << (shift)) #define SHL32(a,shift) ((a) << (shift))
#define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift)) #define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift))
#define PSHR32(a,shift) (SHR32((a)+((1<<((shift))>>1)),shift)) #define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift))
#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) #define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) #define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
#define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) #define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
#define SHR(a,shift) ((a) >> (shift)) #define SHR(a,shift) ((a) >> (shift))
#define SHL(a,shift) ((spx_word32_t)(a) << (shift)) #define SHL(a,shift) ((spx_word32_t)(a) << (shift))
#define PSHR(a,shift) (SHR((a)+((1<<((shift))>>1)),shift)) #define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift))
#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) #define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))

View file

@ -75,15 +75,15 @@ TODO:
#define ROUND_DOWN(x, step) ((x)<0 ? ((x)-(step)+1)/(step)*(step) : (x)/(step)*(step)) #define ROUND_DOWN(x, step) ((x)<0 ? ((x)-(step)+1)/(step)*(step) : (x)/(step)*(step))
#define MAX_TIMINGS 20 #define MAX_TIMINGS 40
#define MAX_BUFFERS 3 #define MAX_BUFFERS 3
#define TOP_DELAY 20 #define TOP_DELAY 40
/** Buffer that keeps the time of arrival of the latest packets */ /** Buffer that keeps the time of arrival of the latest packets */
struct TimingBuffer { struct TimingBuffer {
int filled; /**< Number of entries occupied in "timing" and "counts"*/ int filled; /**< Number of entries occupied in "timing" and "counts"*/
int curr_count; /**< Number of packet timings we got (including those we discarded) */ int curr_count; /**< Number of packet timings we got (including those we discarded) */
spx_int16_t timing[MAX_TIMINGS]; /**< Sorted list of all timings ("latest" packets first) */ spx_int32_t timing[MAX_TIMINGS]; /**< Sorted list of all timings ("latest" packets first) */
spx_int16_t counts[MAX_TIMINGS]; /**< Order the packets were put in (will be used for short-term estimate) */ spx_int16_t counts[MAX_TIMINGS]; /**< Order the packets were put in (will be used for short-term estimate) */
}; };
@ -250,7 +250,7 @@ static spx_int16_t compute_opt_delay(JitterBuffer *jitter)
if (latest >= 0 && !penalty_taken) if (latest >= 0 && !penalty_taken)
{ {
penalty_taken = 1; penalty_taken = 1;
late+=2; late+=4;
} }
} }
@ -269,7 +269,7 @@ static spx_int16_t compute_opt_delay(JitterBuffer *jitter)
/** Initialise jitter buffer */ /** Initialise jitter buffer */
JitterBuffer *jitter_buffer_init(int step_size) EXPORT JitterBuffer *jitter_buffer_init(int step_size)
{ {
JitterBuffer *jitter = (JitterBuffer*)speex_alloc(sizeof(JitterBuffer)); JitterBuffer *jitter = (JitterBuffer*)speex_alloc(sizeof(JitterBuffer));
if (jitter) if (jitter)
@ -294,7 +294,7 @@ JitterBuffer *jitter_buffer_init(int step_size)
} }
/** Reset jitter buffer */ /** Reset jitter buffer */
void jitter_buffer_reset(JitterBuffer *jitter) EXPORT void jitter_buffer_reset(JitterBuffer *jitter)
{ {
int i; int i;
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
@ -325,7 +325,7 @@ void jitter_buffer_reset(JitterBuffer *jitter)
} }
/** Destroy jitter buffer */ /** Destroy jitter buffer */
void jitter_buffer_destroy(JitterBuffer *jitter) EXPORT void jitter_buffer_destroy(JitterBuffer *jitter)
{ {
jitter_buffer_reset(jitter); jitter_buffer_reset(jitter);
speex_free(jitter); speex_free(jitter);
@ -365,7 +365,7 @@ static void shift_timings(JitterBuffer *jitter, spx_int16_t amount)
/** Put one packet into the jitter buffer */ /** Put one packet into the jitter buffer */
void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) EXPORT void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
{ {
int i,j; int i,j;
int late; int late;
@ -399,6 +399,13 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
late = 0; late = 0;
} }
/* For some reason, the consumer has failed the last 20 fetches. Make sure this packet is
* used to resync. */
if (jitter->lost_count>20)
{
jitter_buffer_reset(jitter);
}
/* Only insert the packet if it's not hopelessly late (i.e. totally useless) */ /* Only insert the packet if it's not hopelessly late (i.e. totally useless) */
if (jitter->reset_state || GE32(packet->timestamp+packet->span+jitter->delay_step, jitter->pointer_timestamp)) if (jitter->reset_state || GE32(packet->timestamp+packet->span+jitter->delay_step, jitter->pointer_timestamp))
{ {
@ -428,10 +435,6 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
else else
speex_free(jitter->packets[i].data); speex_free(jitter->packets[i].data);
jitter->packets[i].data=NULL; jitter->packets[i].data=NULL;
if (jitter->lost_count>20)
{
jitter_buffer_reset(jitter);
}
/*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/ /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/
} }
@ -459,7 +462,7 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
} }
/** Get one packet from the jitter buffer */ /** Get one packet from the jitter buffer */
int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset) EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset)
{ {
int i; int i;
unsigned int j; unsigned int j;
@ -673,7 +676,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
} }
int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet) EXPORT int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet)
{ {
int i, j; int i, j;
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
@ -732,7 +735,7 @@ static int _jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket
} }
/* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */ /* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */
int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset) EXPORT int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset)
{ {
/* If the programmer calls jitter_buffer_update_delay() directly, /* If the programmer calls jitter_buffer_update_delay() directly,
automatically disable auto-adjustment */ automatically disable auto-adjustment */
@ -742,12 +745,12 @@ int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet,
} }
/** Get pointer timestamp of jitter buffer */ /** Get pointer timestamp of jitter buffer */
int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter) EXPORT int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter)
{ {
return jitter->pointer_timestamp; return jitter->pointer_timestamp;
} }
void jitter_buffer_tick(JitterBuffer *jitter) EXPORT void jitter_buffer_tick(JitterBuffer *jitter)
{ {
/* Automatically-adjust the buffering delay if requested */ /* Automatically-adjust the buffering delay if requested */
if (jitter->auto_adjust) if (jitter->auto_adjust)
@ -763,7 +766,7 @@ void jitter_buffer_tick(JitterBuffer *jitter)
jitter->buffered = 0; jitter->buffered = 0;
} }
void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem) EXPORT void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem)
{ {
/* Automatically-adjust the buffering delay if requested */ /* Automatically-adjust the buffering delay if requested */
if (jitter->auto_adjust) if (jitter->auto_adjust)
@ -776,7 +779,7 @@ void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem)
/* Used like the ioctl function to control the jitter buffer parameters */ /* Used like the ioctl function to control the jitter buffer parameters */
int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr) EXPORT int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
{ {
int count, i; int count, i;
switch(request) switch(request)
@ -836,4 +839,3 @@ int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
} }
return 0; return 0;
} }

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2003-2006 Jean-Marc Valin /* Copyright (C) 2003-2008 Jean-Marc Valin
File: mdf.c File: mdf.c
Echo canceller based on the MDF algorithm (see below) Echo canceller based on the MDF algorithm (see below)
@ -88,6 +88,12 @@
#define WEIGHT_SHIFT 0 #define WEIGHT_SHIFT 0
#endif #endif
#ifdef FIXED_POINT
#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x)))
#else
#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x))))
#endif
/* If enabled, the AEC will use a foreground filter and a background filter to be more robust to double-talk /* 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 */ and difficult signals in general. The cost is an extra FFT and a matrix-vector multiply */
#define TWO_PATH #define TWO_PATH
@ -131,6 +137,8 @@ struct SpeexEchoState_ {
int adapted; int adapted;
int saturated; int saturated;
int screwed_up; int screwed_up;
int C; /** Number of input channels (microphones) */
int K; /** Number of output channels (loudspeakers) */
spx_int32_t sampling_rate; spx_int32_t sampling_rate;
spx_word16_t spec_average; spx_word16_t spec_average;
spx_word16_t beta0; spx_word16_t beta0;
@ -171,10 +179,10 @@ struct SpeexEchoState_ {
spx_word16_t *window; spx_word16_t *window;
spx_word16_t *prop; spx_word16_t *prop;
void *fft_table; void *fft_table;
spx_word16_t memX, memD, memE; spx_word16_t *memX, *memD, *memE;
spx_word16_t preemph; spx_word16_t preemph;
spx_word16_t notch_radius; spx_word16_t notch_radius;
spx_mem_t notch_mem[2]; spx_mem_t *notch_mem;
/* NOTE: If you only use speex_echo_cancel() and want to save some memory, remove this */ /* NOTE: If you only use speex_echo_cancel() and want to save some memory, remove this */
spx_int16_t *play_buf; spx_int16_t *play_buf;
@ -182,7 +190,7 @@ struct SpeexEchoState_ {
int play_buf_started; int play_buf_started;
}; };
static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius, spx_word16_t *out, int len, spx_mem_t *mem) static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius, spx_word16_t *out, int len, spx_mem_t *mem, int stride)
{ {
int i; int i;
spx_word16_t den2; spx_word16_t den2;
@ -194,7 +202,7 @@ static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius,
/*printf ("%d %d %d %d %d %d\n", num[0], num[1], num[2], den[0], den[1], den[2]);*/ /*printf ("%d %d %d %d %d %d\n", num[0], num[1], num[2], den[0], den[1], den[2]);*/
for (i=0;i<len;i++) for (i=0;i<len;i++)
{ {
spx_word16_t vin = in[i]; spx_word16_t vin = in[i*stride];
spx_word32_t vout = mem[0] + SHL32(EXTEND32(vin),15); spx_word32_t vout = mem[0] + SHL32(EXTEND32(vin),15);
#ifdef FIXED_POINT #ifdef FIXED_POINT
mem[0] = mem[1] + SHL32(SHL32(-EXTEND32(vin),15) + MULT16_32_Q15(radius,vout),1); mem[0] = mem[1] + SHL32(SHL32(-EXTEND32(vin),15) + MULT16_32_Q15(radius,vout),1);
@ -234,6 +242,18 @@ static inline void power_spectrum(const spx_word16_t *X, spx_word32_t *ps, int N
ps[j]=MULT16_16(X[i],X[i]); ps[j]=MULT16_16(X[i],X[i]);
} }
/** Compute power spectrum of a half-complex (packed) vector and accumulate */
static inline void power_spectrum_accum(const spx_word16_t *X, spx_word32_t *ps, int N)
{
int i, j;
ps[0]+=MULT16_16(X[0],X[0]);
for (i=1,j=1;i<N-1;i+=2,j++)
{
ps[j] += MULT16_16(X[i],X[i]) + MULT16_16(X[i+1],X[i+1]);
}
ps[j]+=MULT16_16(X[i],X[i]);
}
/** Compute cross-power spectrum of a half-complex (packed) vectors and add to acc */ /** Compute cross-power spectrum of a half-complex (packed) vectors and add to acc */
#ifdef FIXED_POINT #ifdef FIXED_POINT
static inline void spectral_mul_accum(const spx_word16_t *X, const spx_word32_t *Y, spx_word16_t *acc, int N, int M) static inline void spectral_mul_accum(const spx_word16_t *X, const spx_word32_t *Y, spx_word16_t *acc, int N, int M)
@ -330,16 +350,17 @@ static inline void weighted_spectral_mul_conj(const spx_float_t *w, const spx_fl
prod[i] = FLOAT_MUL32(W,MULT16_16(X[i],Y[i])); 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) static inline void mdf_adjust_prop(const spx_word32_t *W, int N, int M, int P, spx_word16_t *prop)
{ {
int i, j; int i, j, p;
spx_word16_t max_sum = 1; spx_word16_t max_sum = 1;
spx_word32_t prop_sum = 1; spx_word32_t prop_sum = 1;
for (i=0;i<M;i++) for (i=0;i<M;i++)
{ {
spx_word32_t tmp = 1; spx_word32_t tmp = 1;
for (p=0;p<P;p++)
for (j=0;j<N;j++) for (j=0;j<N;j++)
tmp += MULT16_16(EXTRACT16(SHR32(W[i*N+j],18)), EXTRACT16(SHR32(W[i*N+j],18))); tmp += MULT16_16(EXTRACT16(SHR32(W[p*N*M + i*N+j],18)), EXTRACT16(SHR32(W[p*N*M + i*N+j],18)));
#ifdef FIXED_POINT #ifdef FIXED_POINT
/* Just a security in case an overflow were to occur */ /* Just a security in case an overflow were to occur */
tmp = MIN32(ABS32(tmp), 536870912); tmp = MIN32(ABS32(tmp), 536870912);
@ -378,11 +399,20 @@ static void dump_audio(const spx_int16_t *rec, const spx_int16_t *play, const sp
#endif #endif
/** Creates a new echo canceller state */ /** Creates a new echo canceller state */
SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length) EXPORT SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
{ {
int i,N,M; return speex_echo_state_init_mc(frame_size, filter_length, 1, 1);
}
EXPORT SpeexEchoState *speex_echo_state_init_mc(int frame_size, int filter_length, int nb_mic, int nb_speakers)
{
int i,N,M, C, K;
SpeexEchoState *st = (SpeexEchoState *)speex_alloc(sizeof(SpeexEchoState)); SpeexEchoState *st = (SpeexEchoState *)speex_alloc(sizeof(SpeexEchoState));
st->K = nb_speakers;
st->C = nb_mic;
C=st->C;
K=st->K;
#ifdef DUMP_ECHO_CANCEL_DATA #ifdef DUMP_ECHO_CANCEL_DATA
if (rFile || pFile || oFile) if (rFile || pFile || oFile)
speex_fatal("Opening dump files twice"); speex_fatal("Opening dump files twice");
@ -413,23 +443,23 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
st->fft_table = spx_fft_init(N); st->fft_table = spx_fft_init(N);
st->e = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); st->e = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t));
st->x = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); st->x = (spx_word16_t*)speex_alloc(K*N*sizeof(spx_word16_t));
st->input = (spx_word16_t*)speex_alloc(st->frame_size*sizeof(spx_word16_t)); st->input = (spx_word16_t*)speex_alloc(C*st->frame_size*sizeof(spx_word16_t));
st->y = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); st->y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t));
st->last_y = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); st->last_y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t));
st->Yf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); st->Yf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
st->Rf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); st->Rf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
st->Xf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); st->Xf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
st->Yh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); st->Yh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
st->Eh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); st->Eh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
st->X = (spx_word16_t*)speex_alloc((M+1)*N*sizeof(spx_word16_t)); st->X = (spx_word16_t*)speex_alloc(K*(M+1)*N*sizeof(spx_word16_t));
st->Y = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); st->Y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t));
st->E = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); st->E = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t));
st->W = (spx_word32_t*)speex_alloc(M*N*sizeof(spx_word32_t)); st->W = (spx_word32_t*)speex_alloc(C*K*M*N*sizeof(spx_word32_t));
#ifdef TWO_PATH #ifdef TWO_PATH
st->foreground = (spx_word16_t*)speex_alloc(M*N*sizeof(spx_word16_t)); st->foreground = (spx_word16_t*)speex_alloc(M*N*C*K*sizeof(spx_word16_t));
#endif #endif
st->PHI = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); st->PHI = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t));
st->power = (spx_word32_t*)speex_alloc((frame_size+1)*sizeof(spx_word32_t)); st->power = (spx_word32_t*)speex_alloc((frame_size+1)*sizeof(spx_word32_t));
@ -450,7 +480,7 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
#endif #endif
for (i=0;i<=st->frame_size;i++) for (i=0;i<=st->frame_size;i++)
st->power_1[i] = FLOAT_ONE; st->power_1[i] = FLOAT_ONE;
for (i=0;i<N*M;i++) for (i=0;i<N*M*K*C;i++)
st->W[i] = 0; st->W[i] = 0;
{ {
spx_word32_t sum = 0; spx_word32_t sum = 0;
@ -465,11 +495,13 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
} }
for (i=M-1;i>=0;i--) for (i=M-1;i>=0;i--)
{ {
st->prop[i] = DIV32(MULT16_16(QCONST16(.8,15), st->prop[i]),sum); st->prop[i] = DIV32(MULT16_16(QCONST16(.8f,15), st->prop[i]),sum);
} }
} }
st->memX=st->memD=st->memE=0; st->memX = (spx_word16_t*)speex_alloc(K*sizeof(spx_word16_t));
st->memD = (spx_word16_t*)speex_alloc(C*sizeof(spx_word16_t));
st->memE = (spx_word16_t*)speex_alloc(C*sizeof(spx_word16_t));
st->preemph = QCONST16(.9,15); st->preemph = QCONST16(.9,15);
if (st->sampling_rate<12000) if (st->sampling_rate<12000)
st->notch_radius = QCONST16(.9, 15); st->notch_radius = QCONST16(.9, 15);
@ -478,7 +510,7 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
else else
st->notch_radius = QCONST16(.992, 15); st->notch_radius = QCONST16(.992, 15);
st->notch_mem[0] = st->notch_mem[1] = 0; st->notch_mem = (spx_mem_t*)speex_alloc(2*C*sizeof(spx_mem_t));
st->adapted = 0; st->adapted = 0;
st->Pey = st->Pyy = FLOAT_ONE; st->Pey = st->Pyy = FLOAT_ONE;
@ -487,7 +519,7 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
st->Dvar1 = st->Dvar2 = FLOAT_ZERO; st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
#endif #endif
st->play_buf = (spx_int16_t*)speex_alloc((PLAYBACK_DELAY+1)*st->frame_size*sizeof(spx_int16_t)); st->play_buf = (spx_int16_t*)speex_alloc(K*(PLAYBACK_DELAY+1)*st->frame_size*sizeof(spx_int16_t));
st->play_buf_pos = PLAYBACK_DELAY*st->frame_size; st->play_buf_pos = PLAYBACK_DELAY*st->frame_size;
st->play_buf_started = 0; st->play_buf_started = 0;
@ -495,13 +527,15 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
} }
/** Resets echo canceller state */ /** Resets echo canceller state */
void speex_echo_state_reset(SpeexEchoState *st) EXPORT void speex_echo_state_reset(SpeexEchoState *st)
{ {
int i, M, N; int i, M, N, C, K;
st->cancel_count=0; st->cancel_count=0;
st->screwed_up = 0; st->screwed_up = 0;
N = st->window_size; N = st->window_size;
M = st->M; M = st->M;
C=st->C;
K=st->K;
for (i=0;i<N*M;i++) for (i=0;i<N*M;i++)
st->W[i] = 0; st->W[i] = 0;
#ifdef TWO_PATH #ifdef TWO_PATH
@ -521,13 +555,20 @@ void speex_echo_state_reset(SpeexEchoState *st)
{ {
st->last_y[i] = 0; st->last_y[i] = 0;
} }
for (i=0;i<N;i++) for (i=0;i<N*C;i++)
{ {
st->E[i] = 0; st->E[i] = 0;
}
for (i=0;i<N*K;i++)
{
st->x[i] = 0; st->x[i] = 0;
} }
st->notch_mem[0] = st->notch_mem[1] = 0; for (i=0;i<2*C;i++)
st->memX=st->memD=st->memE=0; st->notch_mem[i] = 0;
for (i=0;i<C;i++)
st->memD[i]=st->memE[i]=0;
for (i=0;i<K;i++)
st->memX[i]=0;
st->saturated = 0; st->saturated = 0;
st->adapted = 0; st->adapted = 0;
@ -545,7 +586,7 @@ void speex_echo_state_reset(SpeexEchoState *st)
} }
/** Destroys an echo canceller state */ /** Destroys an echo canceller state */
void speex_echo_state_destroy(SpeexEchoState *st) EXPORT void speex_echo_state_destroy(SpeexEchoState *st)
{ {
spx_fft_destroy(st->fft_table); spx_fft_destroy(st->fft_table);
@ -576,6 +617,11 @@ void speex_echo_state_destroy(SpeexEchoState *st)
#ifdef FIXED_POINT #ifdef FIXED_POINT
speex_free(st->wtmp2); speex_free(st->wtmp2);
#endif #endif
speex_free(st->memX);
speex_free(st->memD);
speex_free(st->memE);
speex_free(st->notch_mem);
speex_free(st->play_buf); speex_free(st->play_buf);
speex_free(st); speex_free(st);
@ -587,7 +633,7 @@ void speex_echo_state_destroy(SpeexEchoState *st)
#endif #endif
} }
void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out) EXPORT void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out)
{ {
int i; int i;
/*speex_warning_int("capture with fill level ", st->play_buf_pos/st->frame_size);*/ /*speex_warning_int("capture with fill level ", st->play_buf_pos/st->frame_size);*/
@ -610,7 +656,7 @@ void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t
} }
} }
void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play) EXPORT void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play)
{ {
/*speex_warning_int("playback with fill level ", st->play_buf_pos/st->frame_size);*/ /*speex_warning_int("playback with fill level ", st->play_buf_pos/st->frame_size);*/
if (!st->play_buf_started) if (!st->play_buf_started)
@ -637,16 +683,16 @@ void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play)
} }
/** Performs echo cancellation on a frame (deprecated, last arg now ignored) */ /** Performs echo cancellation on a frame (deprecated, last arg now ignored) */
void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out, spx_int32_t *Yout) EXPORT void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out, spx_int32_t *Yout)
{ {
speex_echo_cancellation(st, in, far_end, out); speex_echo_cancellation(st, in, far_end, out);
} }
/** Performs echo cancellation on a frame */ /** Performs echo cancellation on a frame */
void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out) EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out)
{ {
int i,j; int i,j, chan, speak;
int N,M; int N,M, C, K;
spx_word32_t Syy,See,Sxx,Sdd, Sff; spx_word32_t Syy,See,Sxx,Sdd, Sff;
#ifdef TWO_PATH #ifdef TWO_PATH
spx_word32_t Dbf; spx_word32_t Dbf;
@ -661,6 +707,9 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
N = st->window_size; N = st->window_size;
M = st->M; M = st->M;
C = st->C;
K = st->K;
st->cancel_count++; st->cancel_count++;
#ifdef FIXED_POINT #ifdef FIXED_POINT
ss=DIV32_16(11469,M); ss=DIV32_16(11469,M);
@ -670,30 +719,17 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
ss_1 = 1-ss; ss_1 = 1-ss;
#endif #endif
for (chan = 0; chan < C; chan++)
{
/* Apply a notch filter to make sure DC doesn't end up causing problems */ /* 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); filter_dc_notch16(in+chan, st->notch_radius, st->input+chan*st->frame_size, st->frame_size, st->notch_mem+2*chan, C);
/* Copy input data to buffer and apply pre-emphasis */ /* Copy input data to buffer and apply pre-emphasis */
/* Copy input data to buffer */
for (i=0;i<st->frame_size;i++) for (i=0;i<st->frame_size;i++)
{ {
spx_word32_t tmp32; spx_word32_t tmp32;
tmp32 = SUB32(EXTEND32(far_end[i]), EXTEND32(MULT16_16_P15(st->preemph, st->memX))); /* FIXME: This core has changed a bit, need to merge properly */
#ifdef FIXED_POINT tmp32 = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(MULT16_16_P15(st->preemph, st->memD[chan])));
/* If saturation occurs here, we need to freeze adaptation for M+1 frames (not just one) */
if (tmp32 > 32767)
{
tmp32 = 32767;
st->saturated = M+1;
}
if (tmp32 < -32767)
{
tmp32 = -32767;
st->saturated = M+1;
}
#endif
st->x[i+st->frame_size] = EXTRACT16(tmp32);
st->memX = far_end[i];
tmp32 = SUB32(EXTEND32(st->input[i]), EXTEND32(MULT16_16_P15(st->preemph, st->memD)));
#ifdef FIXED_POINT #ifdef FIXED_POINT
if (tmp32 > 32767) if (tmp32 > 32767)
{ {
@ -708,52 +744,97 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
st->saturated = 1; st->saturated = 1;
} }
#endif #endif
st->memD = st->input[i]; st->memD[chan] = st->input[chan*st->frame_size+i];
st->input[i] = tmp32; st->input[chan*st->frame_size+i] = EXTRACT16(tmp32);
}
} }
for (speak = 0; speak < K; speak++)
{
for (i=0;i<st->frame_size;i++)
{
spx_word32_t tmp32;
st->x[speak*N+i] = st->x[speak*N+i+st->frame_size];
tmp32 = SUB32(EXTEND32(far_end[i*K+speak]), EXTEND32(MULT16_16_P15(st->preemph, st->memX[speak])));
#ifdef FIXED_POINT
/*FIXME: If saturation occurs here, we need to freeze adaptation for M frames (not just one) */
if (tmp32 > 32767)
{
tmp32 = 32767;
st->saturated = M+1;
}
if (tmp32 < -32767)
{
tmp32 = -32767;
st->saturated = M+1;
}
#endif
st->x[speak*N+i+st->frame_size] = EXTRACT16(tmp32);
st->memX[speak] = far_end[i*K+speak];
}
}
for (speak = 0; speak < K; speak++)
{
/* Shift memory: this could be optimized eventually*/ /* Shift memory: this could be optimized eventually*/
for (j=M-1;j>=0;j--) for (j=M-1;j>=0;j--)
{ {
for (i=0;i<N;i++) for (i=0;i<N;i++)
st->X[(j+1)*N+i] = st->X[j*N+i]; st->X[(j+1)*N*K+speak*N+i] = st->X[j*N*K+speak*N+i];
}
/* Convert x (echo input) to frequency domain */
spx_fft(st->fft_table, st->x+speak*N, &st->X[speak*N]);
} }
/* Convert x (far end) to frequency domain */ Sxx = 0;
spx_fft(st->fft_table, st->x, &st->X[0]); for (speak = 0; speak < K; speak++)
for (i=0;i<N;i++) {
st->last_y[i] = st->x[i]; Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size);
Sxx = mdf_inner_prod(st->x+st->frame_size, st->x+st->frame_size, st->frame_size); power_spectrum_accum(st->X+speak*N, st->Xf, N);
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 */
Sff = 0;
for (chan = 0; chan < C; chan++)
{
#ifdef TWO_PATH #ifdef TWO_PATH
/* Compute foreground filter */ /* Compute foreground filter */
spectral_mul_accum16(st->X, st->foreground, st->Y, N, M); spectral_mul_accum16(st->X, st->foreground+chan*N*K*M, st->Y+chan*N, N, M*K);
spx_ifft(st->fft_table, st->Y, st->e); spx_ifft(st->fft_table, st->Y+chan*N, st->e+chan*N);
for (i=0;i<st->frame_size;i++) for (i=0;i<st->frame_size;i++)
st->e[i] = SUB16(st->input[i], st->e[i+st->frame_size]); st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->e[chan*N+i+st->frame_size]);
Sff = mdf_inner_prod(st->e, st->e, st->frame_size); Sff += mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size);
#endif #endif
}
/* Adjust proportional adaption rate */ /* Adjust proportional adaption rate */
mdf_adjust_prop (st->W, N, M, st->prop); /* FIXME: Adjust that for C, K*/
if (st->adapted)
mdf_adjust_prop (st->W, N, M, C*K, st->prop);
/* Compute weight gradient */ /* Compute weight gradient */
if (st->saturated == 0) if (st->saturated == 0)
{
for (chan = 0; chan < C; chan++)
{
for (speak = 0; speak < K; speak++)
{ {
for (j=M-1;j>=0;j--) for (j=M-1;j>=0;j--)
{ {
weighted_spectral_mul_conj(st->power_1, FLOAT_SHL(PSEUDOFLOAT(st->prop[j]),-15), &st->X[(j+1)*N], st->E, st->PHI, N); weighted_spectral_mul_conj(st->power_1, FLOAT_SHL(PSEUDOFLOAT(st->prop[j]),-15), &st->X[(j+1)*N*K+speak*N], st->E+chan*N, st->PHI, N);
for (i=0;i<N;i++) for (i=0;i<N;i++)
st->W[j*N+i] = ADD32(st->W[j*N+i], st->PHI[i]); st->W[chan*N*K*M + j*N*K + speak*N + i] += st->PHI[i];
}
}
} }
} else { } else {
st->saturated--; st->saturated--;
} }
/* FIXME: MC conversion required */
/* Update weight to prevent circular convolution (MDF / AUMDF) */ /* Update weight to prevent circular convolution (MDF / AUMDF) */
for (chan = 0; chan < C; chan++)
{
for (speak = 0; speak < K; speak++)
{
for (j=0;j<M;j++) for (j=0;j<M;j++)
{ {
/* This is a variant of the Alternatively Updated MDF (AUMDF) */ /* This is a variant of the Alternatively Updated MDF (AUMDF) */
@ -762,7 +843,7 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
{ {
#ifdef FIXED_POINT #ifdef FIXED_POINT
for (i=0;i<N;i++) for (i=0;i<N;i++)
st->wtmp2[i] = EXTRACT16(PSHR32(st->W[j*N+i],NORMALIZE_SCALEDOWN+16)); st->wtmp2[i] = EXTRACT16(PSHR32(st->W[chan*N*K*M + j*N*K + speak*N + i],NORMALIZE_SCALEDOWN+16));
spx_ifft(st->fft_table, st->wtmp2, st->wtmp); spx_ifft(st->fft_table, st->wtmp2, st->wtmp);
for (i=0;i<st->frame_size;i++) for (i=0;i<st->frame_size;i++)
{ {
@ -775,32 +856,41 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
spx_fft(st->fft_table, st->wtmp, st->wtmp2); spx_fft(st->fft_table, st->wtmp, st->wtmp2);
/* The "-1" in the shift is a sort of kludge that trades less efficient update speed for decrease noise */ /* The "-1" in the shift is a sort of kludge that trades less efficient update speed for decrease noise */
for (i=0;i<N;i++) for (i=0;i<N;i++)
st->W[j*N+i] -= SHL32(EXTEND32(st->wtmp2[i]),16+NORMALIZE_SCALEDOWN-NORMALIZE_SCALEUP-1); st->W[chan*N*K*M + j*N*K + speak*N + i] -= SHL32(EXTEND32(st->wtmp2[i]),16+NORMALIZE_SCALEDOWN-NORMALIZE_SCALEUP-1);
#else #else
spx_ifft(st->fft_table, &st->W[j*N], st->wtmp); spx_ifft(st->fft_table, &st->W[chan*N*K*M + j*N*K + speak*N], st->wtmp);
for (i=st->frame_size;i<N;i++) for (i=st->frame_size;i<N;i++)
{ {
st->wtmp[i]=0; st->wtmp[i]=0;
} }
spx_fft(st->fft_table, st->wtmp, &st->W[j*N]); spx_fft(st->fft_table, st->wtmp, &st->W[chan*N*K*M + j*N*K + speak*N]);
#endif #endif
} }
} }
}
}
/* Compute filter response Y */ /* So we can use power_spectrum_accum */
spectral_mul_accum(st->X, st->W, st->Y, N, M); for (i=0;i<=st->frame_size;i++)
spx_ifft(st->fft_table, st->Y, st->y); st->Rf[i] = st->Yf[i] = st->Xf[i] = 0;
Dbf = 0;
See = 0;
#ifdef TWO_PATH #ifdef TWO_PATH
/* Difference in response, this is used to estimate the variance of our residual power estimate */ /* Difference in response, this is used to estimate the variance of our residual power estimate */
for (chan = 0; chan < C; chan++)
{
spectral_mul_accum(st->X, st->W+chan*N*K*M, st->Y+chan*N, N, M*K);
spx_ifft(st->fft_table, st->Y+chan*N, st->y+chan*N);
for (i=0;i<st->frame_size;i++) for (i=0;i<st->frame_size;i++)
st->e[i] = SUB16(st->e[i+st->frame_size], st->y[i+st->frame_size]); st->e[chan*N+i] = SUB16(st->e[chan*N+i+st->frame_size], st->y[chan*N+i+st->frame_size]);
Dbf = 10+mdf_inner_prod(st->e, st->e, st->frame_size); Dbf += 10+mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size);
for (i=0;i<st->frame_size;i++)
st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->y[chan*N+i+st->frame_size]);
See += mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size);
}
#endif #endif
for (i=0;i<st->frame_size;i++)
st->e[i] = SUB16(st->input[i], st->y[i+st->frame_size]);
See = mdf_inner_prod(st->e, st->e, st->frame_size);
#ifndef TWO_PATH #ifndef TWO_PATH
Sff = See; Sff = See;
#endif #endif
@ -837,11 +927,12 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
st->Davg1 = st->Davg2 = 0; st->Davg1 = st->Davg2 = 0;
st->Dvar1 = st->Dvar2 = FLOAT_ZERO; st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
/* Copy background filter to foreground filter */ /* Copy background filter to foreground filter */
for (i=0;i<N*M;i++) for (i=0;i<N*M*C*K;i++)
st->foreground[i] = EXTRACT16(PSHR32(st->W[i],16)); st->foreground[i] = EXTRACT16(PSHR32(st->W[i],16));
/* Apply a smooth transition so as to not introduce blocking artifacts */ /* Apply a smooth transition so as to not introduce blocking artifacts */
for (chan = 0; chan < C; chan++)
for (i=0;i<st->frame_size;i++) 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]); st->e[chan*N+i+st->frame_size] = MULT16_16_Q15(st->window[i+st->frame_size],st->e[chan*N+i+st->frame_size]) + MULT16_16_Q15(st->window[i],st->y[chan*N+i+st->frame_size]);
} else { } else {
int reset_background=0; int reset_background=0;
/* Otherwise, check if the background filter is significantly worse */ /* Otherwise, check if the background filter is significantly worse */
@ -854,13 +945,16 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
if (reset_background) if (reset_background)
{ {
/* Copy foreground filter to background filter */ /* Copy foreground filter to background filter */
for (i=0;i<N*M;i++) for (i=0;i<N*M*C*K;i++)
st->W[i] = SHL32(EXTEND32(st->foreground[i]),16); st->W[i] = SHL32(EXTEND32(st->foreground[i]),16);
/* We also need to copy the output so as to get correct adaptation */ /* We also need to copy the output so as to get correct adaptation */
for (chan = 0; chan < C; chan++)
{
for (i=0;i<st->frame_size;i++) for (i=0;i<st->frame_size;i++)
st->y[i+st->frame_size] = st->e[i+st->frame_size]; st->y[chan*N+i+st->frame_size] = st->e[chan*N+i+st->frame_size];
for (i=0;i<st->frame_size;i++) for (i=0;i<st->frame_size;i++)
st->e[i] = SUB16(st->input[i], st->y[i+st->frame_size]); st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->y[chan*N+i+st->frame_size]);
}
See = Sff; See = Sff;
st->Davg1 = st->Davg2 = 0; st->Davg1 = st->Davg2 = 0;
st->Dvar1 = st->Dvar2 = FLOAT_ZERO; st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
@ -868,30 +962,27 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
} }
#endif #endif
Sey = Syy = Sdd = 0;
for (chan = 0; chan < C; chan++)
{
/* Compute error signal (for the output with de-emphasis) */ /* Compute error signal (for the output with de-emphasis) */
for (i=0;i<st->frame_size;i++) for (i=0;i<st->frame_size;i++)
{ {
spx_word32_t tmp_out; spx_word32_t tmp_out;
#ifdef TWO_PATH #ifdef TWO_PATH
tmp_out = SUB32(EXTEND32(st->input[i]), EXTEND32(st->e[i+st->frame_size])); tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->e[chan*N+i+st->frame_size]));
#else #else
tmp_out = SUB32(EXTEND32(st->input[i]), EXTEND32(st->y[i+st->frame_size])); tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->y[chan*N+i+st->frame_size]));
#endif #endif
/* Saturation */ tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(st->preemph, st->memE[chan])));
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 in the microphone signal */ /* This is an arbitrary test for saturation in the microphone signal */
if (in[i] <= -32000 || in[i] >= 32000) if (in[i*C+chan] <= -32000 || in[i*C+chan] >= 32000)
{ {
tmp_out = 0;
if (st->saturated == 0) if (st->saturated == 0)
st->saturated = 1; st->saturated = 1;
} }
out[i] = (spx_int16_t)tmp_out; out[i*C+chan] = WORD2INT(tmp_out);
st->memE = tmp_out; st->memE[chan] = tmp_out;
} }
#ifdef DUMP_ECHO_CANCEL_DATA #ifdef DUMP_ECHO_CANCEL_DATA
@ -901,14 +992,27 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
/* Compute error signal (filter update version) */ /* Compute error signal (filter update version) */
for (i=0;i<st->frame_size;i++) for (i=0;i<st->frame_size;i++)
{ {
st->e[i+st->frame_size] = st->e[i]; st->e[chan*N+i+st->frame_size] = st->e[chan*N+i];
st->e[i] = 0; st->e[chan*N+i] = 0;
} }
/* Compute a bunch of correlations */ /* Compute a bunch of correlations */
Sey = mdf_inner_prod(st->e+st->frame_size, st->y+st->frame_size, st->frame_size); /* FIXME: bad merge */
Syy = mdf_inner_prod(st->y+st->frame_size, st->y+st->frame_size, st->frame_size); Sey += mdf_inner_prod(st->e+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size);
Sdd = mdf_inner_prod(st->input, st->input, st->frame_size); Syy += mdf_inner_prod(st->y+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size);
Sdd += mdf_inner_prod(st->input+chan*st->frame_size, st->input+chan*st->frame_size, st->frame_size);
/* Convert error to frequency domain */
spx_fft(st->fft_table, st->e+chan*N, st->E+chan*N);
for (i=0;i<st->frame_size;i++)
st->y[i+chan*N] = 0;
spx_fft(st->fft_table, st->y+chan*N, st->Y+chan*N);
/* Compute power spectrum of echo (X), error (E) and filter response (Y) */
power_spectrum_accum(st->E+chan*N, st->Rf, N);
power_spectrum_accum(st->Y+chan*N, st->Yf, N);
}
/*printf ("%f %f %f %f\n", Sff, See, Syy, Sdd, st->update_cond);*/ /*printf ("%f %f %f %f\n", Sff, See, Syy, Sdd, st->update_cond);*/
@ -921,7 +1025,7 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
{ {
/* Things have gone really bad */ /* Things have gone really bad */
st->screwed_up += 50; st->screwed_up += 50;
for (i=0;i<st->frame_size;i++) for (i=0;i<st->frame_size*C;i++)
out[i] = 0; out[i] = 0;
} else if (SHR32(Sff, 2) > ADD32(Sdd, SHR32(MULT16_16(N, 10000),6))) } else if (SHR32(Sff, 2) > ADD32(Sdd, SHR32(MULT16_16(N, 10000),6)))
{ {
@ -941,36 +1045,17 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
/* Add a small noise floor to make sure not to have problems when dividing */ /* Add a small noise floor to make sure not to have problems when dividing */
See = MAX32(See, SHR32(MULT16_16(N, 100),6)); See = MAX32(See, SHR32(MULT16_16(N, 100),6));
/* Convert error to frequency domain */ for (speak = 0; speak < K; speak++)
spx_fft(st->fft_table, st->e, st->E); {
for (i=0;i<st->frame_size;i++) Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size);
st->y[i] = 0; power_spectrum_accum(st->X+speak*N, st->Xf, N);
spx_fft(st->fft_table, st->y, st->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 far end energy estimate over time */ /* Smooth far end energy estimate over time */
for (j=0;j<=st->frame_size;j++) for (j=0;j<=st->frame_size;j++)
st->power[j] = MULT16_32_Q15(ss_1,st->power[j]) + 1 + MULT16_32_Q15(ss,st->Xf[j]); st->power[j] = MULT16_32_Q15(ss_1,st->power[j]) + 1 + MULT16_32_Q15(ss,st->Xf[j]);
/* Enable this to compute the power based only on the tail (would need to compute more
efficiently to make this really useful */
if (0)
{
float scale2 = .5f/M;
for (j=0;j<=st->frame_size;j++)
st->power[j] = 100;
for (i=0;i<M;i++)
{
power_spectrum(&st->X[i*N], st->Xf, N);
for (j=0;j<=st->frame_size;j++)
st->power[j] += scale2*st->Xf[j];
}
}
/* Compute filtered spectra and (cross-)correlations */ /* Compute filtered spectra and (cross-)correlations */
for (j=st->frame_size;j>=0;j--) for (j=st->frame_size;j>=0;j--)
{ {
@ -1091,12 +1176,12 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
st->sum_adapt = ADD32(st->sum_adapt,adapt_rate); st->sum_adapt = ADD32(st->sum_adapt,adapt_rate);
} }
/* Save residual echo so it can be used by the nonlinear processor */ /* FIXME: MC conversion required */
for (i=0;i<st->frame_size;i++)
st->last_y[i] = st->last_y[st->frame_size+i];
if (st->adapted) if (st->adapted)
{ {
/* If the filter is adapted, take the filtered echo */ /* 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++) for (i=0;i<st->frame_size;i++)
st->last_y[st->frame_size+i] = in[i]-out[i]; st->last_y[st->frame_size+i] = in[i]-out[i];
} else { } else {
@ -1141,7 +1226,7 @@ void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *residual_echo, in
} }
int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr) EXPORT int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr)
{ {
switch(request) switch(request)
{ {
@ -1169,6 +1254,29 @@ int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr)
case SPEEX_ECHO_GET_SAMPLING_RATE: case SPEEX_ECHO_GET_SAMPLING_RATE:
(*(int*)ptr) = st->sampling_rate; (*(int*)ptr) = st->sampling_rate;
break; break;
case SPEEX_ECHO_GET_IMPULSE_RESPONSE_SIZE:
/*FIXME: Implement this for multiple channels */
*((spx_int32_t *)ptr) = st->M * st->frame_size;
break;
case SPEEX_ECHO_GET_IMPULSE_RESPONSE:
{
int M = st->M, N = st->window_size, n = st->frame_size, i, j;
spx_int32_t *filt = (spx_int32_t *) ptr;
for(j=0;j<M;j++)
{
/*FIXME: Implement this for multiple channels */
#ifdef FIXED_POINT
for (i=0;i<N;i++)
st->wtmp2[i] = EXTRACT16(PSHR32(st->W[j*N+i],16+NORMALIZE_SCALEDOWN));
spx_ifft(st->fft_table, st->wtmp2, st->wtmp);
#else
spx_ifft(st->fft_table, &st->W[j*N], st->wtmp);
#endif
for(i=0;i<n;i++)
filt[j*n+i] = PSHR32(MULT16_16(32767,st->wtmp[i]), WEIGHT_SHIFT-NORMALIZE_SCALEDOWN);
}
}
break;
default: default:
speex_warning_int("Unknown speex_echo_ctl request: ", request); speex_warning_int("Unknown speex_echo_ctl request: ", request);
return -1; return -1;

View file

@ -450,7 +450,7 @@ static const SpeexNBMode nb_mode = {
/* Default mode for narrowband */ /* Default mode for narrowband */
const SpeexMode speex_nb_mode = { EXPORT const SpeexMode speex_nb_mode = {
&nb_mode, &nb_mode,
nb_mode_query, nb_mode_query,
"narrowband", "narrowband",
@ -479,8 +479,12 @@ const SpeexMode speex_nb_mode = {
int speex_mode_query(const SpeexMode *mode, int request, void *ptr) EXPORT int speex_mode_query(const SpeexMode *mode, int request, void *ptr)
{ {
return mode->query(mode->mode, request, ptr); return mode->query(mode->mode, request, ptr);
} }
#ifdef FIXED_DEBUG
long long spx_mips=0;
#endif

View file

@ -55,9 +55,9 @@
#endif #endif
#ifndef ROCKBOX_VOICE_CODEC #ifndef ROCKBOX_VOICE_CODEC
const SpeexMode * const speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, &speex_uwb_mode}; EXPORT const SpeexMode * const speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, &speex_uwb_mode};
#else #else
const SpeexMode * const speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, NULL}; EXPORT const SpeexMode * const speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, NULL};
#endif #endif
extern const signed char hexc_table[]; extern const signed char hexc_table[];
@ -250,7 +250,7 @@ static const SpeexSBMode sb_wb_mode = {
}; };
const SpeexMode speex_wb_mode = { EXPORT const SpeexMode speex_wb_mode = {
&sb_wb_mode, &sb_wb_mode,
wb_mode_query, wb_mode_query,
"wideband (sub-band CELP)", "wideband (sub-band CELP)",
@ -285,7 +285,7 @@ const SpeexMode speex_wb_mode = {
#ifndef ROCKBOX_VOICE_CODEC #ifndef ROCKBOX_VOICE_CODEC
/* Split-band "ultra-wideband" (32 kbps) CELP mode*/ /* Split-band "ultra-wideband" (32 kbps) CELP mode*/
static const SpeexSBMode sb_uwb_mode = { EXPORT static const SpeexSBMode sb_uwb_mode = {
&speex_wb_mode, &speex_wb_mode,
320, /*frameSize*/ 320, /*frameSize*/
80, /*subframeSize*/ 80, /*subframeSize*/
@ -365,7 +365,7 @@ const SpeexMode speex_uwb_mode = {
/* We have defined speex_lib_get_mode() as a macro in speex.h */ /* We have defined speex_lib_get_mode() as a macro in speex.h */
#undef speex_lib_get_mode #undef speex_lib_get_mode
const SpeexMode * speex_lib_get_mode (int mode) EXPORT const SpeexMode * speex_lib_get_mode (int mode)
{ {
if (mode < 0 || mode >= SPEEX_NB_MODES) return NULL; if (mode < 0 || mode >= SPEEX_NB_MODES) return NULL;

View file

@ -199,6 +199,8 @@ struct SpeexPreprocessState_ {
int echo_suppress_active; int echo_suppress_active;
SpeexEchoState *echo_state; SpeexEchoState *echo_state;
spx_word16_t speech_prob; /**< Probability last frame was speech */
/* DSP-related arrays */ /* DSP-related arrays */
spx_word16_t *frame; /**< Processing frame (2*ps_size) */ spx_word16_t *frame; /**< Processing frame (2*ps_size) */
spx_word16_t *ft; /**< Processing frame in freq domain (2*ps_size) */ spx_word16_t *ft; /**< Processing frame in freq domain (2*ps_size) */
@ -234,7 +236,6 @@ struct SpeexPreprocessState_ {
float *loudness_weight; /**< Perceptual loudness curve */ float *loudness_weight; /**< Perceptual loudness curve */
float loudness; /**< Loudness estimate */ float loudness; /**< Loudness estimate */
float agc_gain; /**< Current AGC gain */ float agc_gain; /**< Current AGC gain */
int nb_loudness_adapt; /**< Number of frames used for loudness adaptation so far */
float max_gain; /**< Maximum gain allowed */ float max_gain; /**< Maximum gain allowed */
float max_increase_step; /**< Maximum increase in gain from one frame to another */ float max_increase_step; /**< Maximum increase in gain from one frame to another */
float max_decrease_step; /**< Maximum decrease in gain from one frame to another */ float max_decrease_step; /**< Maximum decrease in gain from one frame to another */
@ -391,7 +392,7 @@ static void compute_gain_floor(int noise_suppress, int effective_echo_suppress,
} }
#endif #endif
SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_rate) EXPORT SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_rate)
{ {
int i; int i;
int N, N3, N4, M; int N, N3, N4, M;
@ -514,7 +515,6 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r
/*st->loudness = pow(AMP_SCALE*st->agc_level,LOUDNESS_EXP);*/ /*st->loudness = pow(AMP_SCALE*st->agc_level,LOUDNESS_EXP);*/
st->loudness = 1e-15; st->loudness = 1e-15;
st->agc_gain = 1; st->agc_gain = 1;
st->nb_loudness_adapt = 0;
st->max_gain = 30; st->max_gain = 30;
st->max_increase_step = exp(0.11513f * 12.*st->frame_size / st->sampling_rate); st->max_increase_step = exp(0.11513f * 12.*st->frame_size / st->sampling_rate);
st->max_decrease_step = exp(-0.11513f * 40.*st->frame_size / st->sampling_rate); st->max_decrease_step = exp(-0.11513f * 40.*st->frame_size / st->sampling_rate);
@ -530,7 +530,7 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r
return st; return st;
} }
void speex_preprocess_state_destroy(SpeexPreprocessState *st) EXPORT void speex_preprocess_state_destroy(SpeexPreprocessState *st)
{ {
speex_free(st->frame); speex_free(st->frame);
speex_free(st->ft); speex_free(st->ft);
@ -583,7 +583,6 @@ static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx
loudness*2 > pow(st->loudness, 1.0/LOUDNESS_EXP))*/ loudness*2 > pow(st->loudness, 1.0/LOUDNESS_EXP))*/
if (Pframe>.3f) if (Pframe>.3f)
{ {
st->nb_loudness_adapt++;
/*rate=2.0f*Pframe*Pframe/(1+st->nb_loudness_adapt);*/ /*rate=2.0f*Pframe*Pframe/(1+st->nb_loudness_adapt);*/
rate = .03*Pframe*Pframe; rate = .03*Pframe*Pframe;
st->loudness = (1-rate)*st->loudness + (rate)*pow(AMP_SCALE*loudness, LOUDNESS_EXP); st->loudness = (1-rate)*st->loudness + (rate)*pow(AMP_SCALE*loudness, LOUDNESS_EXP);
@ -705,7 +704,7 @@ static void update_noise_prob(SpeexPreprocessState *st)
} }
for (i=0;i<N;i++) for (i=0;i<N;i++)
{ {
if (MULT16_32_Q15(QCONST16(.4f,15),st->S[i]) > ADD32(st->Smin[i],EXTEND32(20))) if (MULT16_32_Q15(QCONST16(.4f,15),st->S[i]) > st->Smin[i])
st->update_prob[i] = 1; st->update_prob[i] = 1;
else else
st->update_prob[i] = 0; st->update_prob[i] = 0;
@ -719,12 +718,12 @@ static void update_noise_prob(SpeexPreprocessState *st)
void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len); void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len);
int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo) EXPORT int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo)
{ {
return speex_preprocess_run(st, x); return speex_preprocess_run(st, x);
} }
int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) EXPORT int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
{ {
int i; int i;
int M; int M;
@ -994,9 +993,10 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
st->outbuf[i] = st->frame[st->frame_size+i]; st->outbuf[i] = st->frame[st->frame_size+i];
/* FIXME: This VAD is a kludge */ /* FIXME: This VAD is a kludge */
st->speech_prob = Pframe;
if (st->vad_enabled) if (st->vad_enabled)
{ {
if (Pframe > st->speech_prob_start || (st->was_speech && Pframe > st->speech_prob_continue)) if (st->speech_prob > st->speech_prob_start || (st->was_speech && st->speech_prob > st->speech_prob_continue))
{ {
st->was_speech=1; st->was_speech=1;
return 1; return 1;
@ -1010,7 +1010,7 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
} }
} }
void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x) EXPORT void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x)
{ {
int i; int i;
int N = st->ps_size; int N = st->ps_size;
@ -1045,7 +1045,7 @@ void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x)
} }
int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr) EXPORT int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr)
{ {
int i; int i;
SpeexPreprocessState *st; SpeexPreprocessState *st;
@ -1169,17 +1169,51 @@ int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr)
st->echo_state = (SpeexEchoState*)ptr; st->echo_state = (SpeexEchoState*)ptr;
break; break;
case SPEEX_PREPROCESS_GET_ECHO_STATE: case SPEEX_PREPROCESS_GET_ECHO_STATE:
ptr = (void*)st->echo_state; (*(SpeexEchoState**)ptr) = (SpeexEchoState*)st->echo_state;
break; break;
#ifndef FIXED_POINT #ifndef FIXED_POINT
case SPEEX_PREPROCESS_GET_AGC_LOUDNESS: case SPEEX_PREPROCESS_GET_AGC_LOUDNESS:
(*(spx_int32_t*)ptr) = pow(st->loudness, 1.0/LOUDNESS_EXP); (*(spx_int32_t*)ptr) = pow(st->loudness, 1.0/LOUDNESS_EXP);
break; break;
case SPEEX_PREPROCESS_GET_AGC_GAIN:
(*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->agc_gain));
break;
#endif
case SPEEX_PREPROCESS_GET_PSD_SIZE:
case SPEEX_PREPROCESS_GET_NOISE_PSD_SIZE:
(*(spx_int32_t*)ptr) = st->ps_size;
break;
case SPEEX_PREPROCESS_GET_PSD:
for(i=0;i<st->ps_size;i++)
((spx_int32_t *)ptr)[i] = (spx_int32_t) st->ps[i];
break;
case SPEEX_PREPROCESS_GET_NOISE_PSD:
for(i=0;i<st->ps_size;i++)
((spx_int32_t *)ptr)[i] = (spx_int32_t) PSHR32(st->noise[i], NOISE_SHIFT);
break;
case SPEEX_PREPROCESS_GET_PROB:
(*(spx_int32_t*)ptr) = MULT16_16_Q15(st->speech_prob, 100);
break;
#ifndef FIXED_POINT
case SPEEX_PREPROCESS_SET_AGC_TARGET:
st->agc_level = (*(spx_int32_t*)ptr);
if (st->agc_level<1)
st->agc_level=1;
if (st->agc_level>32768)
st->agc_level=32768;
break;
case SPEEX_PREPROCESS_GET_AGC_TARGET:
(*(spx_int32_t*)ptr) = st->agc_level;
break;
#endif #endif
default: default:
speex_warning_int("Unknown speex_preprocess_ctl request: ", request); speex_warning_int("Unknown speex_preprocess_ctl request: ", request);
return -1; return -1;
} }
return 0; return 0;
} }
#ifdef FIXED_DEBUG
long long spx_mips=0;
#endif

View file

@ -68,19 +68,19 @@ static int lsp_quant(
" B0 = %2;\n\t" " B0 = %2;\n\t"
" R2.L = W [I0++];\n\t" " R2.L = W [I0++];\n\t"
" LSETUP (lq1, lq2) LC0 = %4;\n\t" " LSETUP (1f, 2f) LC0 = %4;\n\t"
"lq1: R3 = 0;\n\t" /* R3: dist */ "1: R3 = 0;\n\t" /* R3: dist */
" LSETUP (lq3, lq4) LC1 = %5;\n\t" " LSETUP (3f, 4f) LC1 = %5;\n\t"
"lq3: R1 = B [P2++] (X);\n\t" "3: R1 = B [P2++] (X);\n\t"
" R1 <<= 5;\n\t" " R1 <<= 5;\n\t"
" R0.L = R2.L - R1.L || R2.L = W [I0++];\n\t" " R0.L = R2.L - R1.L || R2.L = W [I0++];\n\t"
" R0 = R0.L*R0.L;\n\t" " R0 = R0.L*R0.L;\n\t"
"lq4: R3 = R3 + R0;\n\t" "4: R3 = R3 + R0;\n\t"
" cc =R3<%0;\n\t" " cc =R3<%0;\n\t"
" if cc %0=R3;\n\t" " if cc %0=R3;\n\t"
" if cc %1=R5;\n\t" " if cc %1=R5;\n\t"
"lq2: R5 += 1;\n\t" "2: R5 += 1;\n\t"
" L0 = 0;\n\t" " L0 = 0;\n\t"
: "=&d" (best_dist), "=&d" (best_id) : "=&d" (best_dist), "=&d" (best_id)
: "a" (x), "b" (cdbk), "a" (nbVec), "a" (nbDim) : "a" (x), "b" (cdbk), "a" (nbVec), "a" (nbDim)
@ -132,10 +132,10 @@ static int lsp_weight_quant(
" B0 = %2;\n\t" " B0 = %2;\n\t"
" B1 = %3;\n\t" " B1 = %3;\n\t"
" LSETUP (lwq1, lwq2) LC0 = %5;\n\t" " LSETUP (1f, 2f) LC0 = %5;\n\t"
"lwq1: R3 = 0 (X);\n\t" /* R3: dist */ "1: R3 = 0 (X);\n\t" /* R3: dist */
" LSETUP (lwq3, lwq4) LC1 = %6;\n\t" " LSETUP (3f, 4f) LC1 = %6;\n\t"
"lwq3: R0.L = W [I0++] || R2.L = W [I1++];\n\t" "3: R0.L = W [I0++] || R2.L = W [I1++];\n\t"
" R1 = B [P2++] (X);\n\t" " R1 = B [P2++] (X);\n\t"
" R1 <<= 5;\n\t" " R1 <<= 5;\n\t"
" R0.L = R0.L - R1.L;\n\t" " R0.L = R0.L - R1.L;\n\t"
@ -143,12 +143,12 @@ static int lsp_weight_quant(
" A1 = R2.L*R0.L (M,IS);\n\t" " A1 = R2.L*R0.L (M,IS);\n\t"
" A1 = A1 >>> 16;\n\t" " A1 = A1 >>> 16;\n\t"
" R1 = (A1 += R2.L*R0.H) (IS);\n\t" " R1 = (A1 += R2.L*R0.H) (IS);\n\t"
"lwq4: R3 = R3 + R1;\n\t" "4: R3 = R3 + R1;\n\t"
" cc =R3<%0;\n\t" " cc =R3<%0;\n\t"
" if cc %0=R3;\n\t" " if cc %0=R3;\n\t"
" if cc %1=R5;\n\t" " if cc %1=R5;\n\t"
"lwq2: R5 += 1;\n\t" "2: R5 += 1;\n\t"
" L0 = 0;\n\t" " L0 = 0;\n\t"
" L1 = 0;\n\t" " L1 = 0;\n\t"
: "=&d" (best_dist), "=&d" (best_id) : "=&d" (best_dist), "=&d" (best_id)

View file

@ -1,4 +1,5 @@
/* Copyright (C) 2007 Jean-Marc Valin /* Copyright (C) 2007-2008 Jean-Marc Valin
Copyright (C) 2008 Thorvald Natvig
File: resample.c File: resample.c
Arbitrary resampling code Arbitrary resampling code
@ -57,7 +58,7 @@
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config-speex.h" #include "config.h"
#endif #endif
#ifdef OUTSIDE_SPEEX #ifdef OUTSIDE_SPEEX
@ -74,6 +75,7 @@ static void speex_free (void *ptr) {free(ptr);}
#include "os_support.h" #include "os_support.h"
#endif /* OUTSIDE_SPEEX */ #endif /* OUTSIDE_SPEEX */
#include "stack_alloc.h"
#include <math.h> #include <math.h>
#ifndef M_PI #ifndef M_PI
@ -86,10 +88,6 @@ static void speex_free (void *ptr) {free(ptr);}
#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) #define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x))))
#endif #endif
/*#define float double*/
#define FILTER_SIZE 64
#define OVERSAMPLE 8
#define IMAX(a,b) ((a) > (b) ? (a) : (b)) #define IMAX(a,b) ((a) > (b) ? (a) : (b))
#define IMIN(a,b) ((a) < (b) ? (a) : (b)) #define IMIN(a,b) ((a) < (b) ? (a) : (b))
@ -97,6 +95,17 @@ static void speex_free (void *ptr) {free(ptr);}
#define NULL 0 #define NULL 0
#endif #endif
#ifdef _USE_SSE
#include "resample_sse.h"
#endif
/* Numer of elements to allocate on the stack */
#ifdef VAR_ARRAYS
#define FIXED_STACK_ALLOC 8192
#else
#define FIXED_STACK_ALLOC 1024
#endif
typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *); typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *);
struct SpeexResamplerState_ { struct SpeexResamplerState_ {
@ -109,6 +118,7 @@ struct SpeexResamplerState_ {
spx_uint32_t nb_channels; spx_uint32_t nb_channels;
spx_uint32_t filt_len; spx_uint32_t filt_len;
spx_uint32_t mem_alloc_size; spx_uint32_t mem_alloc_size;
spx_uint32_t buffer_size;
int int_advance; int int_advance;
int frac_advance; int frac_advance;
float cutoff; float cutoff;
@ -317,47 +327,47 @@ static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4])
static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
{ {
int N = st->filt_len; const int N = st->filt_len;
int out_sample = 0; int out_sample = 0;
spx_word16_t *mem;
int last_sample = st->last_sample[channel_index]; int last_sample = st->last_sample[channel_index];
spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
mem = st->mem + channel_index * st->mem_alloc_size; const spx_word16_t *sinc_table = st->sinc_table;
const int out_stride = st->out_stride;
const int int_advance = st->int_advance;
const int frac_advance = st->frac_advance;
const spx_uint32_t den_rate = st->den_rate;
spx_word32_t sum;
int j;
while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
{ {
int j; const spx_word16_t *sinc = & sinc_table[samp_frac_num*N];
spx_word32_t sum=0; const spx_word16_t *iptr = & in[last_sample];
/* We already have all the filter coefficients pre-computed in the table */ #ifndef OVERRIDE_INNER_PRODUCT_SINGLE
const spx_word16_t *ptr; float accum[4] = {0,0,0,0};
/* 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 */ for(j=0;j<N;j+=4) {
if (in != NULL) accum[0] += sinc[j]*iptr[j];
{ accum[1] += sinc[j+1]*iptr[j+1];
ptr = in+st->in_stride*(last_sample-N+1+j); accum[2] += sinc[j+2]*iptr[j+2];
for (;j<N;j++) accum[3] += sinc[j+3]*iptr[j+3];
{
sum += MULT16_16(*ptr,st->sinc_table[samp_frac_num*st->filt_len+j]);
ptr += st->in_stride;
}
} }
sum = accum[0] + accum[1] + accum[2] + accum[3];
#else
sum = inner_product_single(sinc, iptr, N);
#endif
*out = PSHR32(sum,15); out[out_stride * out_sample++] = PSHR32(sum, 15);
out += st->out_stride; last_sample += int_advance;
out_sample++; samp_frac_num += frac_advance;
last_sample += st->int_advance; if (samp_frac_num >= den_rate)
samp_frac_num += st->frac_advance;
if (samp_frac_num >= st->den_rate)
{ {
samp_frac_num -= st->den_rate; samp_frac_num -= den_rate;
last_sample++; last_sample++;
} }
} }
st->last_sample[channel_index] = last_sample; st->last_sample[channel_index] = last_sample;
st->samp_frac_num[channel_index] = samp_frac_num; st->samp_frac_num[channel_index] = samp_frac_num;
return out_sample; return out_sample;
@ -368,47 +378,47 @@ static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t c
/* This is the same as the previous function, except with a double-precision accumulator */ /* This is the same as the previous function, except with a double-precision accumulator */
static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
{ {
int N = st->filt_len; const int N = st->filt_len;
int out_sample = 0; int out_sample = 0;
spx_word16_t *mem;
int last_sample = st->last_sample[channel_index]; int last_sample = st->last_sample[channel_index];
spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
mem = st->mem + channel_index * st->mem_alloc_size; const spx_word16_t *sinc_table = st->sinc_table;
const int out_stride = st->out_stride;
const int int_advance = st->int_advance;
const int frac_advance = st->frac_advance;
const spx_uint32_t den_rate = st->den_rate;
double sum;
int j;
while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
{ {
int j; const spx_word16_t *sinc = & sinc_table[samp_frac_num*N];
double sum=0; const spx_word16_t *iptr = & in[last_sample];
/* We already have all the filter coefficients pre-computed in the table */ #ifndef OVERRIDE_INNER_PRODUCT_DOUBLE
const spx_word16_t *ptr; double accum[4] = {0,0,0,0};
/* Do the memory part */
for (j=0;last_sample-N+1+j < 0;j++)
{
sum += MULT16_16(mem[last_sample+j],(double)st->sinc_table[samp_frac_num*st->filt_len+j]);
}
/* Do the new part */ for(j=0;j<N;j+=4) {
if (in != NULL) accum[0] += sinc[j]*iptr[j];
{ accum[1] += sinc[j+1]*iptr[j+1];
ptr = in+st->in_stride*(last_sample-N+1+j); accum[2] += sinc[j+2]*iptr[j+2];
for (;j<N;j++) accum[3] += sinc[j+3]*iptr[j+3];
{
sum += MULT16_16(*ptr,(double)st->sinc_table[samp_frac_num*st->filt_len+j]);
ptr += st->in_stride;
}
} }
sum = accum[0] + accum[1] + accum[2] + accum[3];
#else
sum = inner_product_double(sinc, iptr, N);
#endif
*out = sum; out[out_stride * out_sample++] = PSHR32(sum, 15);
out += st->out_stride; last_sample += int_advance;
out_sample++; samp_frac_num += frac_advance;
last_sample += st->int_advance; if (samp_frac_num >= den_rate)
samp_frac_num += st->frac_advance;
if (samp_frac_num >= st->den_rate)
{ {
samp_frac_num -= st->den_rate; samp_frac_num -= den_rate;
last_sample++; last_sample++;
} }
} }
st->last_sample[channel_index] = last_sample; st->last_sample[channel_index] = last_sample;
st->samp_frac_num[channel_index] = samp_frac_num; st->samp_frac_num[channel_index] = samp_frac_num;
return out_sample; return out_sample;
@ -417,69 +427,58 @@ static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t c
static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
{ {
int N = st->filt_len; const int N = st->filt_len;
int out_sample = 0; int out_sample = 0;
spx_word16_t *mem;
int last_sample = st->last_sample[channel_index]; int last_sample = st->last_sample[channel_index];
spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
mem = st->mem + channel_index * st->mem_alloc_size; const int out_stride = st->out_stride;
const int int_advance = st->int_advance;
const int frac_advance = st->frac_advance;
const spx_uint32_t den_rate = st->den_rate;
int j;
spx_word32_t sum;
while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
{ {
int j; const spx_word16_t *iptr = & in[last_sample];
spx_word32_t sum=0;
/* We need to interpolate the sinc filter */ const int offset = samp_frac_num*st->oversample/st->den_rate;
spx_word32_t accum[4] = {0.f,0.f, 0.f, 0.f};
spx_word16_t interp[4];
const spx_word16_t *ptr;
int offset;
spx_word16_t frac;
offset = samp_frac_num*st->oversample/st->den_rate;
#ifdef FIXED_POINT #ifdef FIXED_POINT
frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate);
#else #else
frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate;
#endif #endif
/* This code is written like this to make it easy to optimise with SIMD. spx_word16_t interp[4];
For most DSPs, it would be best to split the loops in two because most DSPs
have only two accumulators */
for (j=0;last_sample-N+1+j < 0;j++)
{
spx_word16_t curr_mem = mem[last_sample+j];
accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]);
accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
}
if (in != NULL)
{ #ifndef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE
ptr = in+st->in_stride*(last_sample-N+1+j); spx_word32_t accum[4] = {0,0,0,0};
/* Do the new part */
for (;j<N;j++) for(j=0;j<N;j++) {
{ const spx_word16_t curr_in=iptr[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[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[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[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]); accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
} }
}
cubic_coef(frac, interp); cubic_coef(frac, interp);
sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]); sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]);
#else
cubic_coef(frac, interp);
sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);
#endif
*out = PSHR32(sum,15); out[out_stride * out_sample++] = PSHR32(sum,15);
out += st->out_stride; last_sample += int_advance;
out_sample++; samp_frac_num += frac_advance;
last_sample += st->int_advance; if (samp_frac_num >= den_rate)
samp_frac_num += st->frac_advance;
if (samp_frac_num >= st->den_rate)
{ {
samp_frac_num -= st->den_rate; samp_frac_num -= den_rate;
last_sample++; last_sample++;
} }
} }
st->last_sample[channel_index] = last_sample; st->last_sample[channel_index] = last_sample;
st->samp_frac_num[channel_index] = samp_frac_num; st->samp_frac_num[channel_index] = samp_frac_num;
return out_sample; return out_sample;
@ -490,63 +489,58 @@ static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint3
/* This is the same as the previous function, except with a double-precision accumulator */ /* This is the same as the previous function, except with a double-precision accumulator */
static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
{ {
int N = st->filt_len; const int N = st->filt_len;
int out_sample = 0; int out_sample = 0;
spx_word16_t *mem;
int last_sample = st->last_sample[channel_index]; int last_sample = st->last_sample[channel_index];
spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
mem = st->mem + channel_index * st->mem_alloc_size; const int out_stride = st->out_stride;
const int int_advance = st->int_advance;
const int frac_advance = st->frac_advance;
const spx_uint32_t den_rate = st->den_rate;
int j;
spx_word32_t sum;
while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
{ {
int j; const spx_word16_t *iptr = & in[last_sample];
spx_word32_t sum=0;
/* We need to interpolate the sinc filter */ const int offset = samp_frac_num*st->oversample/st->den_rate;
double accum[4] = {0.f,0.f, 0.f, 0.f}; #ifdef FIXED_POINT
float interp[4]; const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate);
const spx_word16_t *ptr; #else
float alpha = ((float)samp_frac_num)/st->den_rate; const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate;
int offset = samp_frac_num*st->oversample/st->den_rate; #endif
float frac = alpha*st->oversample - offset; spx_word16_t interp[4];
/* 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 */ #ifndef OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE
for (j=0;last_sample-N+1+j < 0;j++) double accum[4] = {0,0,0,0};
{
double curr_mem = mem[last_sample+j]; for(j=0;j<N;j++) {
accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]); const double curr_in=iptr[j];
accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]);
accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
}
if (in != NULL)
{
ptr = in+st->in_stride*(last_sample-N+1+j);
/* Do the new part */
for (;j<N;j++)
{
double curr_in = *ptr;
ptr += st->in_stride;
accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]); 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[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[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]); accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
} }
}
cubic_coef(frac, interp);
sum = interp[0]*accum[0] + interp[1]*accum[1] + interp[2]*accum[2] + interp[3]*accum[3];
*out = PSHR32(sum,15); cubic_coef(frac, interp);
out += st->out_stride; sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]);
out_sample++; #else
last_sample += st->int_advance; cubic_coef(frac, interp);
samp_frac_num += st->frac_advance; sum = interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);
if (samp_frac_num >= st->den_rate) #endif
out[out_stride * out_sample++] = PSHR32(sum,15);
last_sample += int_advance;
samp_frac_num += frac_advance;
if (samp_frac_num >= den_rate)
{ {
samp_frac_num -= st->den_rate; samp_frac_num -= den_rate;
last_sample++; last_sample++;
} }
} }
st->last_sample[channel_index] = last_sample; st->last_sample[channel_index] = last_sample;
st->samp_frac_num[channel_index] = samp_frac_num; st->samp_frac_num[channel_index] = samp_frac_num;
return out_sample; return out_sample;
@ -643,18 +637,18 @@ static void update_filter(SpeexResamplerState *st)
if (!st->mem) if (!st->mem)
{ {
spx_uint32_t i; spx_uint32_t i;
st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
for (i=0;i<st->nb_channels*(st->filt_len-1);i++) st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
for (i=0;i<st->nb_channels*st->mem_alloc_size;i++)
st->mem[i] = 0; st->mem[i] = 0;
st->mem_alloc_size = st->filt_len-1;
/*speex_warning("init filter");*/ /*speex_warning("init filter");*/
} else if (!st->started) } else if (!st->started)
{ {
spx_uint32_t i; spx_uint32_t i;
st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
for (i=0;i<st->nb_channels*(st->filt_len-1);i++) st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
for (i=0;i<st->nb_channels*st->mem_alloc_size;i++)
st->mem[i] = 0; st->mem[i] = 0;
st->mem_alloc_size = st->filt_len-1;
/*speex_warning("reinit filter");*/ /*speex_warning("reinit filter");*/
} else if (st->filt_len > old_length) } else if (st->filt_len > old_length)
{ {
@ -662,10 +656,10 @@ static void update_filter(SpeexResamplerState *st)
/* Increase the filter length */ /* Increase the filter length */
/*speex_warning("increase filter size");*/ /*speex_warning("increase filter size");*/
int old_alloc_size = st->mem_alloc_size; int old_alloc_size = st->mem_alloc_size;
if (st->filt_len-1 > st->mem_alloc_size) if ((st->filt_len-1 + st->buffer_size) > st->mem_alloc_size)
{ {
st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
st->mem_alloc_size = st->filt_len-1; st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
} }
for (i=st->nb_channels-1;i>=0;i--) for (i=st->nb_channels-1;i>=0;i--)
{ {
@ -721,12 +715,12 @@ static void update_filter(SpeexResamplerState *st)
} }
SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) EXPORT SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)
{ {
return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err); return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err);
} }
SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)
{ {
spx_uint32_t i; spx_uint32_t i;
SpeexResamplerState *st; SpeexResamplerState *st;
@ -755,6 +749,12 @@ SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uin
st->in_stride = 1; st->in_stride = 1;
st->out_stride = 1; st->out_stride = 1;
#ifdef FIXED_POINT
st->buffer_size = 160;
#else
st->buffer_size = 160;
#endif
/* Per channel data */ /* Per channel data */
st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int)); st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int));
st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int)); st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int));
@ -779,7 +779,7 @@ SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uin
return st; return st;
} }
void speex_resampler_destroy(SpeexResamplerState *st) EXPORT void speex_resampler_destroy(SpeexResamplerState *st)
{ {
speex_free(st->mem); speex_free(st->mem);
speex_free(st->sinc_table); speex_free(st->sinc_table);
@ -789,186 +789,168 @@ void speex_resampler_destroy(SpeexResamplerState *st)
speex_free(st); speex_free(st);
} }
static int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
static int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
{ {
int j=0; int j=0;
int N = st->filt_len; const int N = st->filt_len;
int out_sample = 0; int out_sample = 0;
spx_word16_t *mem; spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size;
spx_uint32_t tmp_out_len = 0; spx_uint32_t ilen;
mem = st->mem + channel_index * st->mem_alloc_size;
st->started = 1; st->started = 1;
/* Handle the case where we have samples left from a reduction in filter length */
if (st->magic_samples[channel_index])
{
int istride_save;
spx_uint32_t tmp_in_len;
spx_uint32_t tmp_magic;
istride_save = st->in_stride;
tmp_in_len = st->magic_samples[channel_index];
tmp_out_len = *out_len;
/* magic_samples needs to be set to zero to avoid infinite recursion */
tmp_magic = st->magic_samples[channel_index];
st->magic_samples[channel_index] = 0;
st->in_stride = 1;
speex_resampler_process_native(st, channel_index, mem+N-1, &tmp_in_len, out, &tmp_out_len);
st->in_stride = istride_save;
/*speex_warning_int("extra samples:", tmp_out_len);*/
/* If we couldn't process all "magic" input samples, save the rest for next time */
if (tmp_in_len < tmp_magic)
{
spx_uint32_t i;
st->magic_samples[channel_index] = tmp_magic-tmp_in_len;
for (i=0;i<st->magic_samples[channel_index];i++)
mem[N-1+i]=mem[N-1+i+tmp_in_len];
}
out += tmp_out_len*st->out_stride;
*out_len -= tmp_out_len;
}
/* Call the right resampler through the function ptr */ /* Call the right resampler through the function ptr */
out_sample = st->resampler_ptr(st, channel_index, in, in_len, out, out_len); out_sample = st->resampler_ptr(st, channel_index, mem, in_len, out, out_len);
if (st->last_sample[channel_index] < (spx_int32_t)*in_len) if (st->last_sample[channel_index] < (spx_int32_t)*in_len)
*in_len = st->last_sample[channel_index]; *in_len = st->last_sample[channel_index];
*out_len = out_sample+tmp_out_len; *out_len = out_sample;
st->last_sample[channel_index] -= *in_len; st->last_sample[channel_index] -= *in_len;
for (j=0;j<N-1-(spx_int32_t)*in_len;j++) ilen = *in_len;
mem[j] = mem[j+*in_len];
for (;j<N-1;j++) for(j=0;j<N-1;++j)
mem[j] = in[st->in_stride*(j+*in_len-N+1)]; mem[j] = mem[j+ilen];
return RESAMPLER_ERR_SUCCESS; return RESAMPLER_ERR_SUCCESS;
} }
#define FIXED_STACK_ALLOC 1024 static int speex_resampler_magic(SpeexResamplerState *st, spx_uint32_t channel_index, spx_word16_t **out, spx_uint32_t out_len) {
spx_uint32_t tmp_in_len = st->magic_samples[channel_index];
spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size;
const int N = st->filt_len;
speex_resampler_process_native(st, channel_index, &tmp_in_len, *out, &out_len);
st->magic_samples[channel_index] -= tmp_in_len;
/* If we couldn't process all "magic" input samples, save the rest for next time */
if (st->magic_samples[channel_index])
{
spx_uint32_t i;
for (i=0;i<st->magic_samples[channel_index];i++)
mem[N-1+i]=mem[N-1+i+tmp_in_len];
}
*out += out_len*st->out_stride;
return out_len;
}
#ifdef FIXED_POINT #ifdef FIXED_POINT
int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
{
spx_uint32_t i;
int istride_save, ostride_save;
#ifdef VAR_ARRAYS
spx_word16_t x[*in_len];
spx_word16_t y[*out_len];
/*VARDECL(spx_word16_t *x);
VARDECL(spx_word16_t *y);
ALLOC(x, *in_len, spx_word16_t);
ALLOC(y, *out_len, spx_word16_t);*/
istride_save = st->in_stride;
ostride_save = st->out_stride;
for (i=0;i<*in_len;i++)
x[i] = WORD2INT(in[i*st->in_stride]);
st->in_stride = st->out_stride = 1;
speex_resampler_process_native(st, channel_index, x, in_len, y, out_len);
st->in_stride = istride_save;
st->out_stride = ostride_save;
for (i=0;i<*out_len;i++)
out[i*st->out_stride] = y[i];
#else #else
spx_word16_t x[FIXED_STACK_ALLOC]; EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
spx_word16_t y[FIXED_STACK_ALLOC]; #endif
spx_uint32_t ilen=*in_len, olen=*out_len;
istride_save = st->in_stride;
ostride_save = st->out_stride;
while (ilen && olen)
{ {
spx_uint32_t ichunk, ochunk; int j;
ichunk = ilen; spx_uint32_t ilen = *in_len;
ochunk = olen; spx_uint32_t olen = *out_len;
if (ichunk>FIXED_STACK_ALLOC) spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size;
ichunk=FIXED_STACK_ALLOC; const int filt_offs = st->filt_len - 1;
if (ochunk>FIXED_STACK_ALLOC) const spx_uint32_t xlen = st->mem_alloc_size - filt_offs;
ochunk=FIXED_STACK_ALLOC; const int istride = st->in_stride;
for (i=0;i<ichunk;i++)
x[i] = WORD2INT(in[i*st->in_stride]); if (st->magic_samples[channel_index])
st->in_stride = st->out_stride = 1; olen -= speex_resampler_magic(st, channel_index, &out, olen);
speex_resampler_process_native(st, channel_index, x, &ichunk, y, &ochunk); if (! st->magic_samples[channel_index]) {
st->in_stride = istride_save; while (ilen && olen) {
st->out_stride = ostride_save; spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen;
for (i=0;i<ochunk;i++) spx_uint32_t ochunk = olen;
out[i*st->out_stride] = y[i];
out += ochunk; if (in) {
in += ichunk; for(j=0;j<ichunk;++j)
x[j+filt_offs]=in[j*istride];
} else {
for(j=0;j<ichunk;++j)
x[j+filt_offs]=0;
}
speex_resampler_process_native(st, channel_index, &ichunk, out, &ochunk);
ilen -= ichunk; ilen -= ichunk;
olen -= ochunk; olen -= ochunk;
out += ochunk * st->out_stride;
if (in)
in += ichunk * istride;
}
} }
*in_len -= ilen; *in_len -= ilen;
*out_len -= olen; *out_len -= olen;
#endif
return RESAMPLER_ERR_SUCCESS; return RESAMPLER_ERR_SUCCESS;
} }
int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
{ #ifdef FIXED_POINT
return speex_resampler_process_native(st, channel_index, in, in_len, out, out_len); EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
}
#else #else
int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
#endif
{ {
return speex_resampler_process_native(st, channel_index, in, in_len, out, out_len); int j;
} const int istride_save = st->in_stride;
int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) const int ostride_save = st->out_stride;
{ spx_uint32_t ilen = *in_len;
spx_uint32_t i; spx_uint32_t olen = *out_len;
int istride_save, ostride_save; spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size;
const spx_uint32_t xlen = st->mem_alloc_size - (st->filt_len - 1);
#ifdef VAR_ARRAYS #ifdef VAR_ARRAYS
spx_word16_t x[*in_len]; const unsigned int ylen = (olen < FIXED_STACK_ALLOC) ? olen : FIXED_STACK_ALLOC;
spx_word16_t y[*out_len]; VARDECL(spx_word16_t *ystack);
/*VARDECL(spx_word16_t *x); ALLOC(ystack, ylen, spx_word16_t);
VARDECL(spx_word16_t *y);
ALLOC(x, *in_len, spx_word16_t);
ALLOC(y, *out_len, spx_word16_t);*/
istride_save = st->in_stride;
ostride_save = st->out_stride;
for (i=0;i<*in_len;i++)
x[i] = in[i*st->in_stride];
st->in_stride = st->out_stride = 1;
speex_resampler_process_native(st, channel_index, x, in_len, y, out_len);
st->in_stride = istride_save;
st->out_stride = ostride_save;
for (i=0;i<*out_len;i++)
out[i*st->out_stride] = WORD2INT(y[i]);
#else #else
spx_word16_t x[FIXED_STACK_ALLOC]; const unsigned int ylen = FIXED_STACK_ALLOC;
spx_word16_t y[FIXED_STACK_ALLOC]; spx_word16_t ystack[FIXED_STACK_ALLOC];
spx_uint32_t ilen=*in_len, olen=*out_len;
istride_save = st->in_stride;
ostride_save = st->out_stride;
while (ilen && olen)
{
spx_uint32_t ichunk, ochunk;
ichunk = ilen;
ochunk = olen;
if (ichunk>FIXED_STACK_ALLOC)
ichunk=FIXED_STACK_ALLOC;
if (ochunk>FIXED_STACK_ALLOC)
ochunk=FIXED_STACK_ALLOC;
for (i=0;i<ichunk;i++)
x[i] = in[i*st->in_stride];
st->in_stride = st->out_stride = 1;
speex_resampler_process_native(st, channel_index, x, &ichunk, y, &ochunk);
st->in_stride = istride_save;
st->out_stride = ostride_save;
for (i=0;i<ochunk;i++)
out[i*st->out_stride] = WORD2INT(y[i]);
out += ochunk;
in += ichunk;
ilen -= ichunk;
olen -= ochunk;
}
*in_len -= ilen;
*out_len -= olen;
#endif
return RESAMPLER_ERR_SUCCESS;
}
#endif #endif
int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) st->out_stride = 1;
while (ilen && olen) {
spx_word16_t *y = ystack;
spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen;
spx_uint32_t ochunk = (olen > ylen) ? ylen : olen;
spx_uint32_t omagic = 0;
if (st->magic_samples[channel_index]) {
omagic = speex_resampler_magic(st, channel_index, &y, ochunk);
ochunk -= omagic;
olen -= omagic;
}
if (! st->magic_samples[channel_index]) {
if (in) {
for(j=0;j<ichunk;++j)
#ifdef FIXED_POINT
x[j+st->filt_len-1]=WORD2INT(in[j*istride_save]);
#else
x[j+st->filt_len-1]=in[j*istride_save];
#endif
} else {
for(j=0;j<ichunk;++j)
x[j+st->filt_len-1]=0;
}
speex_resampler_process_native(st, channel_index, &ichunk, y, &ochunk);
} else {
ichunk = 0;
ochunk = 0;
}
for (j=0;j<ochunk+omagic;++j)
#ifdef FIXED_POINT
out[j*ostride_save] = ystack[j];
#else
out[j*ostride_save] = WORD2INT(ystack[j]);
#endif
ilen -= ichunk;
olen -= ochunk;
out += (ochunk+omagic) * ostride_save;
if (in)
in += ichunk * istride_save;
}
st->out_stride = ostride_save;
*in_len -= ilen;
*out_len -= olen;
return RESAMPLER_ERR_SUCCESS;
}
EXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
{ {
spx_uint32_t i; spx_uint32_t i;
int istride_save, ostride_save; int istride_save, ostride_save;
@ -989,8 +971,7 @@ int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const flo
return RESAMPLER_ERR_SUCCESS; return RESAMPLER_ERR_SUCCESS;
} }
EXPORT int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
{ {
spx_uint32_t i; spx_uint32_t i;
int istride_save, ostride_save; int istride_save, ostride_save;
@ -1011,18 +992,18 @@ int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_i
return RESAMPLER_ERR_SUCCESS; return RESAMPLER_ERR_SUCCESS;
} }
int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate) EXPORT int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate)
{ {
return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate); return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate);
} }
void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate) EXPORT void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate)
{ {
*in_rate = st->in_rate; *in_rate = st->in_rate;
*out_rate = st->out_rate; *out_rate = st->out_rate;
} }
int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate) EXPORT int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate)
{ {
spx_uint32_t fact; spx_uint32_t fact;
spx_uint32_t old_den; spx_uint32_t old_den;
@ -1061,13 +1042,13 @@ int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_nu
return RESAMPLER_ERR_SUCCESS; return RESAMPLER_ERR_SUCCESS;
} }
void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den) EXPORT void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den)
{ {
*ratio_num = st->num_rate; *ratio_num = st->num_rate;
*ratio_den = st->den_rate; *ratio_den = st->den_rate;
} }
int speex_resampler_set_quality(SpeexResamplerState *st, int quality) EXPORT int speex_resampler_set_quality(SpeexResamplerState *st, int quality)
{ {
if (quality > 10 || quality < 0) if (quality > 10 || quality < 0)
return RESAMPLER_ERR_INVALID_ARG; return RESAMPLER_ERR_INVALID_ARG;
@ -1079,32 +1060,42 @@ int speex_resampler_set_quality(SpeexResamplerState *st, int quality)
return RESAMPLER_ERR_SUCCESS; return RESAMPLER_ERR_SUCCESS;
} }
void speex_resampler_get_quality(SpeexResamplerState *st, int *quality) EXPORT void speex_resampler_get_quality(SpeexResamplerState *st, int *quality)
{ {
*quality = st->quality; *quality = st->quality;
} }
void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride) EXPORT void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride)
{ {
st->in_stride = stride; st->in_stride = stride;
} }
void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride) EXPORT void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride)
{ {
*stride = st->in_stride; *stride = st->in_stride;
} }
void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride) EXPORT void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride)
{ {
st->out_stride = stride; st->out_stride = stride;
} }
void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride) EXPORT void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride)
{ {
*stride = st->out_stride; *stride = st->out_stride;
} }
int speex_resampler_skip_zeros(SpeexResamplerState *st) EXPORT int speex_resampler_get_input_latency(SpeexResamplerState *st)
{
return st->filt_len / 2;
}
EXPORT int speex_resampler_get_output_latency(SpeexResamplerState *st)
{
return ((st->filt_len / 2) * st->den_rate + (st->num_rate >> 1)) / st->num_rate;
}
EXPORT int speex_resampler_skip_zeros(SpeexResamplerState *st)
{ {
spx_uint32_t i; spx_uint32_t i;
for (i=0;i<st->nb_channels;i++) for (i=0;i<st->nb_channels;i++)
@ -1112,7 +1103,7 @@ int speex_resampler_skip_zeros(SpeexResamplerState *st)
return RESAMPLER_ERR_SUCCESS; return RESAMPLER_ERR_SUCCESS;
} }
int speex_resampler_reset_mem(SpeexResamplerState *st) EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st)
{ {
spx_uint32_t i; spx_uint32_t i;
for (i=0;i<st->nb_channels*(st->filt_len-1);i++) for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
@ -1120,7 +1111,7 @@ int speex_resampler_reset_mem(SpeexResamplerState *st)
return RESAMPLER_ERR_SUCCESS; return RESAMPLER_ERR_SUCCESS;
} }
const char *speex_resampler_strerror(int err) EXPORT const char *speex_resampler_strerror(int err)
{ {
switch (err) switch (err)
{ {

View file

@ -0,0 +1,128 @@
/* Copyright (C) 2007-2008 Jean-Marc Valin
* Copyright (C) 2008 Thorvald Natvig
*/
/**
@file resample_sse.h
@brief Resampler functions (SSE version)
*/
/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <xmmintrin.h>
#define OVERRIDE_INNER_PRODUCT_SINGLE
static inline float inner_product_single(const float *a, const float *b, unsigned int len)
{
int i;
float ret;
__m128 sum = _mm_setzero_ps();
for (i=0;i<len;i+=8)
{
sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(a+i), _mm_loadu_ps(b+i)));
sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(a+i+4), _mm_loadu_ps(b+i+4)));
}
sum = _mm_add_ps(sum, _mm_movehl_ps(sum, sum));
sum = _mm_add_ss(sum, _mm_shuffle_ps(sum, sum, 0x55));
_mm_store_ss(&ret, sum);
return ret;
}
#define OVERRIDE_INTERPOLATE_PRODUCT_SINGLE
static inline float interpolate_product_single(const float *a, const float *b, unsigned int len, const spx_uint32_t oversample, float *frac) {
int i;
float ret;
__m128 sum = _mm_setzero_ps();
__m128 f = _mm_loadu_ps(frac);
for(i=0;i<len;i+=2)
{
sum = _mm_add_ps(sum, _mm_mul_ps(_mm_load1_ps(a+i), _mm_loadu_ps(b+i*oversample)));
sum = _mm_add_ps(sum, _mm_mul_ps(_mm_load1_ps(a+i+1), _mm_loadu_ps(b+(i+1)*oversample)));
}
sum = _mm_mul_ps(f, sum);
sum = _mm_add_ps(sum, _mm_movehl_ps(sum, sum));
sum = _mm_add_ss(sum, _mm_shuffle_ps(sum, sum, 0x55));
_mm_store_ss(&ret, sum);
return ret;
}
#ifdef _USE_SSE2
#include <emmintrin.h>
#define OVERRIDE_INNER_PRODUCT_DOUBLE
static inline double inner_product_double(const float *a, const float *b, unsigned int len)
{
int i;
double ret;
__m128d sum = _mm_setzero_pd();
__m128 t;
for (i=0;i<len;i+=8)
{
t = _mm_mul_ps(_mm_loadu_ps(a+i), _mm_loadu_ps(b+i));
sum = _mm_add_pd(sum, _mm_cvtps_pd(t));
sum = _mm_add_pd(sum, _mm_cvtps_pd(_mm_movehl_ps(t, t)));
t = _mm_mul_ps(_mm_loadu_ps(a+i+4), _mm_loadu_ps(b+i+4));
sum = _mm_add_pd(sum, _mm_cvtps_pd(t));
sum = _mm_add_pd(sum, _mm_cvtps_pd(_mm_movehl_ps(t, t)));
}
sum = _mm_add_sd(sum, (__m128d) _mm_movehl_ps((__m128) sum, (__m128) sum));
_mm_store_sd(&ret, sum);
return ret;
}
#define OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE
static inline double interpolate_product_double(const float *a, const float *b, unsigned int len, const spx_uint32_t oversample, float *frac) {
int i;
double ret;
__m128d sum;
__m128d sum1 = _mm_setzero_pd();
__m128d sum2 = _mm_setzero_pd();
__m128 f = _mm_loadu_ps(frac);
__m128d f1 = _mm_cvtps_pd(f);
__m128d f2 = _mm_cvtps_pd(_mm_movehl_ps(f,f));
__m128 t;
for(i=0;i<len;i+=2)
{
t = _mm_mul_ps(_mm_load1_ps(a+i), _mm_loadu_ps(b+i*oversample));
sum1 = _mm_add_pd(sum1, _mm_cvtps_pd(t));
sum2 = _mm_add_pd(sum2, _mm_cvtps_pd(_mm_movehl_ps(t, t)));
t = _mm_mul_ps(_mm_load1_ps(a+i+1), _mm_loadu_ps(b+(i+1)*oversample));
sum1 = _mm_add_pd(sum1, _mm_cvtps_pd(t));
sum2 = _mm_add_pd(sum2, _mm_cvtps_pd(_mm_movehl_ps(t, t)));
}
sum1 = _mm_mul_pd(f1, sum1);
sum2 = _mm_mul_pd(f2, sum2);
sum = _mm_add_pd(sum1, sum2);
sum = _mm_add_sd(sum, (__m128d) _mm_movehl_ps((__m128) sum, (__m128) sum));
_mm_store_sd(&ret, sum);
return ret;
}
#endif

View file

@ -49,25 +49,25 @@
#define MAX_IN_SAMPLES 640 #define MAX_IN_SAMPLES 640
#ifndef SPEEX_DISABLE_ENCODER #ifndef SPEEX_DISABLE_ENCODER
void *speex_encoder_init(const SpeexMode *mode) EXPORT void *speex_encoder_init(const SpeexMode *mode)
{ {
return mode->enc_init(mode); return mode->enc_init(mode);
} }
#endif #endif
void *speex_decoder_init(const SpeexMode *mode) EXPORT void *speex_decoder_init(const SpeexMode *mode)
{ {
return mode->dec_init(mode); return mode->dec_init(mode);
} }
#ifndef SPEEX_DISABLE_ENCODER #ifndef SPEEX_DISABLE_ENCODER
void speex_encoder_destroy(void *state) EXPORT void speex_encoder_destroy(void *state)
{ {
(*((SpeexMode**)state))->enc_destroy(state); (*((SpeexMode**)state))->enc_destroy(state);
} }
#endif #endif
void speex_decoder_destroy(void *state) EXPORT void speex_decoder_destroy(void *state)
{ {
(*((SpeexMode**)state))->dec_destroy(state); (*((SpeexMode**)state))->dec_destroy(state);
} }
@ -90,7 +90,7 @@ int speex_decode_native(void *state, SpeexBits *bits, spx_word16_t *out)
#ifndef SPEEX_DISABLE_ENCODER #ifndef SPEEX_DISABLE_ENCODER
#ifndef DISABLE_FLOAT_API #ifndef DISABLE_FLOAT_API
int speex_encode(void *state, float *in, SpeexBits *bits) EXPORT int speex_encode(void *state, float *in, SpeexBits *bits)
{ {
int i; int i;
spx_int32_t N; spx_int32_t N;
@ -109,7 +109,7 @@ int speex_encode(void *state, float *in, SpeexBits *bits)
} }
#endif /* #ifndef DISABLE_FLOAT_API */ #endif /* #ifndef DISABLE_FLOAT_API */
int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) EXPORT int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits)
{ {
SpeexMode *mode; SpeexMode *mode;
mode = *(SpeexMode**)state; mode = *(SpeexMode**)state;
@ -118,7 +118,7 @@ int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits)
#endif /* SPEEX_DISABLE_ENCODER */ #endif /* SPEEX_DISABLE_ENCODER */
#ifndef DISABLE_FLOAT_API #ifndef DISABLE_FLOAT_API
int speex_decode(void *state, SpeexBits *bits, float *out) EXPORT int speex_decode(void *state, SpeexBits *bits, float *out)
{ {
int i, ret; int i, ret;
spx_int32_t N; spx_int32_t N;
@ -131,7 +131,7 @@ int speex_decode(void *state, SpeexBits *bits, float *out)
} }
#endif /* #ifndef DISABLE_FLOAT_API */ #endif /* #ifndef DISABLE_FLOAT_API */
int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out) EXPORT int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out)
{ {
SpeexMode *mode = *(SpeexMode**)state; SpeexMode *mode = *(SpeexMode**)state;
return (mode)->dec(state, bits, out); return (mode)->dec(state, bits, out);
@ -139,12 +139,12 @@ int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out)
#else #else
int speex_encode(void *state, float *in, SpeexBits *bits) EXPORT int speex_encode(void *state, float *in, SpeexBits *bits)
{ {
return (*((SpeexMode**)state))->enc(state, in, bits); return (*((SpeexMode**)state))->enc(state, in, bits);
} }
int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) EXPORT int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits)
{ {
int i; int i;
spx_int32_t N; spx_int32_t N;
@ -155,12 +155,12 @@ int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits)
return (*((SpeexMode**)state))->enc(state, float_in, bits); return (*((SpeexMode**)state))->enc(state, float_in, bits);
} }
int speex_decode(void *state, SpeexBits *bits, float *out) EXPORT int speex_decode(void *state, SpeexBits *bits, float *out)
{ {
return (*((SpeexMode**)state))->dec(state, bits, out); return (*((SpeexMode**)state))->dec(state, bits, out);
} }
int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out) EXPORT int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out)
{ {
int i; int i;
spx_int32_t N; spx_int32_t N;
@ -182,13 +182,13 @@ int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out)
#endif #endif
#ifndef SPEEX_DISABLE_ENCODER #ifndef SPEEX_DISABLE_ENCODER
int speex_encoder_ctl(void *state, int request, void *ptr) EXPORT int speex_encoder_ctl(void *state, int request, void *ptr)
{ {
return (*((SpeexMode**)state))->enc_ctl(state, request, ptr); return (*((SpeexMode**)state))->enc_ctl(state, request, ptr);
} }
#endif #endif
int speex_decoder_ctl(void *state, int request, void *ptr) EXPORT int speex_decoder_ctl(void *state, int request, void *ptr)
{ {
return (*((SpeexMode**)state))->dec_ctl(state, request, ptr); return (*((SpeexMode**)state))->dec_ctl(state, request, ptr);
} }
@ -219,7 +219,7 @@ int nb_mode_query(const void *mode, int request, void *ptr)
int speex_lib_ctl(int request, void *ptr) EXPORT int speex_lib_ctl(int request, void *ptr)
{ {
switch (request) switch (request)
{ {

View file

@ -40,7 +40,7 @@
#include "arch.h" #include "arch.h"
#include "os_support.h" #include "os_support.h"
int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *state) EXPORT int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *state)
{ {
int id; int id;
SpeexCallback *callback; SpeexCallback *callback;
@ -74,7 +74,7 @@ int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *st
#if 0 #if 0
/* Rockbox: unused */ /* Rockbox: unused */
int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data) EXPORT int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data)
{ {
(void)state; (void)state;
spx_int32_t m; spx_int32_t m;
@ -83,7 +83,7 @@ int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data)
return 0; return 0;
} }
int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data) EXPORT int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data)
{ {
(void)state; (void)state;
spx_int32_t m; spx_int32_t m;
@ -92,7 +92,7 @@ int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data)
return 0; return 0;
} }
int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data) EXPORT int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data)
{ {
(void)state; (void)state;
spx_int32_t m; spx_int32_t m;
@ -103,7 +103,7 @@ int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data
#endif #endif
#ifndef DISABLE_VBR #ifndef DISABLE_VBR
int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data) EXPORT int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data)
{ {
(void)state; (void)state;
spx_int32_t vbr; spx_int32_t vbr;
@ -115,7 +115,7 @@ int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data)
#if 0 #if 0
/* Rockbox: unused */ /* Rockbox: unused */
int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data) EXPORT int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data)
{ {
(void)state; (void)state;
spx_int32_t enh; spx_int32_t enh;
@ -126,7 +126,7 @@ int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data)
#endif #endif
#ifndef DISABLE_VBR #ifndef DISABLE_VBR
int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data) EXPORT int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data)
{ {
(void)state; (void)state;
float qual; float qual;
@ -138,7 +138,7 @@ int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *da
#if 0 #if 0
/* Rockbox: unused */ /* Rockbox: unused */
int speex_std_char_handler(SpeexBits *bits, void *state, void *data) EXPORT int speex_std_char_handler(SpeexBits *bits, void *state, void *data)
{ {
(void)state; (void)state;
unsigned char ch; unsigned char ch;
@ -150,7 +150,7 @@ int speex_std_char_handler(SpeexBits *bits, void *state, void *data)
#endif #endif
/* Default handler for user callbacks: skip it */ /* Default handler for user callbacks: skip it */
int speex_default_user_handler(SpeexBits *bits, void *state, void *data) EXPORT int speex_default_user_handler(SpeexBits *bits, void *state, void *data)
{ {
(void)state; (void)state;
(void)data; (void)data;

View file

@ -86,7 +86,7 @@ typedef struct SpeexHeader {
*/ */
#ifndef SPEEX_DISABLE_ENCODER #ifndef SPEEX_DISABLE_ENCODER
void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const SpeexMode *m) EXPORT void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const SpeexMode *m)
{ {
int i; int i;
const char *h="Speex "; const char *h="Speex ";
@ -121,7 +121,7 @@ void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const Spe
header->reserved2 = 0; header->reserved2 = 0;
} }
char *speex_header_to_packet(SpeexHeader *header, int *size) EXPORT char *speex_header_to_packet(SpeexHeader *header, int *size)
{ {
SpeexHeader *le_header; SpeexHeader *le_header;
le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader)); le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader));
@ -147,7 +147,7 @@ char *speex_header_to_packet(SpeexHeader *header, int *size)
#endif /* SPEEX_DISABLE_ENCODER */ #endif /* SPEEX_DISABLE_ENCODER */
static SpeexHeader global_le_header; /* Avoid malloc */ static SpeexHeader global_le_header; /* Avoid malloc */
SpeexHeader *speex_packet_to_header(char *packet, int size) EXPORT SpeexHeader *speex_packet_to_header(char *packet, int size)
{ {
int i; int i;
SpeexHeader *le_header = &global_le_header; SpeexHeader *le_header = &global_le_header;
@ -183,6 +183,25 @@ SpeexHeader *speex_packet_to_header(char *packet, int size)
ENDIAN_SWITCH(le_header->frames_per_packet); ENDIAN_SWITCH(le_header->frames_per_packet);
ENDIAN_SWITCH(le_header->extra_headers); ENDIAN_SWITCH(le_header->extra_headers);
if (le_header->mode >= SPEEX_NB_MODES || le_header->mode < 0)
{
speex_notify("Invalid mode specified in Speex header");
speex_free (le_header);
return NULL;
}
if (le_header->nb_channels>2)
le_header->nb_channels = 2;
if (le_header->nb_channels<1)
le_header->nb_channels = 1;
return le_header; return le_header;
} }
#if 0 /* Unused by rockbox */
EXPORT void speex_header_free(void *ptr)
{
speex_free(ptr);
}
#endif

View file

@ -75,7 +75,7 @@ static const spx_word16_t balance_bounds[31] = {18, 23, 30, 38, 49, 63, 81, 104
#endif #endif
static SpeexStereoState global_stereo_state; static SpeexStereoState global_stereo_state;
SpeexStereoState *speex_stereo_state_init() EXPORT SpeexStereoState *speex_stereo_state_init()
{ {
/* SpeexStereoState *stereo = speex_alloc(sizeof(SpeexStereoState)); */ /* SpeexStereoState *stereo = speex_alloc(sizeof(SpeexStereoState)); */
SpeexStereoState *stereo = &global_stereo_state; SpeexStereoState *stereo = &global_stereo_state;
@ -83,7 +83,7 @@ SpeexStereoState *speex_stereo_state_init()
return stereo; return stereo;
} }
void speex_stereo_state_reset(SpeexStereoState *_stereo) EXPORT void speex_stereo_state_reset(SpeexStereoState *_stereo)
{ {
RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo;
#ifdef FIXED_POINT #ifdef FIXED_POINT
@ -103,7 +103,7 @@ void speex_stereo_state_reset(SpeexStereoState *_stereo)
#endif #endif
} }
void speex_stereo_state_destroy(SpeexStereoState *stereo) EXPORT void speex_stereo_state_destroy(SpeexStereoState *stereo)
{ {
(void)stereo; (void)stereo;
/* speex_free(stereo); */ /* speex_free(stereo); */
@ -111,7 +111,7 @@ void speex_stereo_state_destroy(SpeexStereoState *stereo)
#ifndef SPEEX_DISABLE_ENCODER #ifndef SPEEX_DISABLE_ENCODER
#ifndef DISABLE_FLOAT_API #ifndef DISABLE_FLOAT_API
void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits) EXPORT void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits)
{ {
int i, tmp; int i, tmp;
float e_left=0, e_right=0, e_tot=0; float e_left=0, e_right=0, e_tot=0;
@ -149,7 +149,7 @@ void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits)
} }
#endif /* #ifndef DISABLE_FLOAT_API */ #endif /* #ifndef DISABLE_FLOAT_API */
void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits) EXPORT void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits)
{ {
int i, tmp; int i, tmp;
spx_word32_t e_left=0, e_right=0, e_tot=0; spx_word32_t e_left=0, e_right=0, e_tot=0;
@ -225,7 +225,7 @@ void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits)
#endif /* SPEEX_DISABLE_ENCODER */ #endif /* SPEEX_DISABLE_ENCODER */
#ifndef DISABLE_FLOAT_API #ifndef DISABLE_FLOAT_API
void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *_stereo) EXPORT void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *_stereo)
{ {
int i; int i;
spx_word32_t balance; spx_word32_t balance;
@ -252,7 +252,7 @@ void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *_stereo)
} }
#endif /* #ifndef DISABLE_FLOAT_API */ #endif /* #ifndef DISABLE_FLOAT_API */
void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState *_stereo) EXPORT void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState *_stereo)
{ {
int i; int i;
spx_word32_t balance; spx_word32_t balance;
@ -278,7 +278,7 @@ void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState
} }
} }
int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data) EXPORT int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data)
{ {
(void)state; (void)state;
RealSpeexStereoState *stereo; RealSpeexStereoState *stereo;