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

View file

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

View file

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

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2002 Jean-Marc Valin
/* Copyright (C) 2002 Jean-Marc Valin
File: speex_bits.c
Handles bit packing/unpacking
@ -6,18 +6,18 @@
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@ -46,7 +46,7 @@
#endif
#ifdef ROCKBOX_VOICE_ENCODER
void speex_bits_init(SpeexBits *bits)
EXPORT void speex_bits_init(SpeexBits *bits)
{
bits->chars = (char*)speex_alloc(MAX_CHARS_PER_FRAME);
if (!bits->chars)
@ -62,7 +62,7 @@ void speex_bits_init(SpeexBits *bits)
#if 0
/* Rockbox: unused */
void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size)
EXPORT void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size)
{
bits->chars = (char*)buff;
bits->buf_size = buf_size;
@ -73,7 +73,7 @@ void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size)
}
#endif
void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size)
EXPORT void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size)
{
bits->chars = (char*)buff;
bits->buf_size = buf_size;
@ -84,11 +84,11 @@ void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size)
bits->charPtr=0;
bits->bitPtr=0;
bits->overflow=0;
}
#ifndef ROCKBOX_VOICE_CODEC
void speex_bits_destroy(SpeexBits *bits)
EXPORT void speex_bits_destroy(SpeexBits *bits)
{
if (bits->owner)
speex_free(bits->chars);
@ -97,7 +97,7 @@ void speex_bits_destroy(SpeexBits *bits)
#endif
#ifdef ROCKBOX_VOICE_ENCODER
void speex_bits_reset(SpeexBits *bits)
EXPORT void speex_bits_reset(SpeexBits *bits)
{
/* We only need to clear the first byte now */
bits->chars[0]=0;
@ -110,7 +110,7 @@ void speex_bits_reset(SpeexBits *bits)
#if 0
/* Rockbox: unused */
void speex_bits_rewind(SpeexBits *bits)
EXPORT void speex_bits_rewind(SpeexBits *bits)
{
bits->charPtr=0;
bits->bitPtr=0;
@ -119,7 +119,7 @@ void speex_bits_rewind(SpeexBits *bits)
#endif
#if !defined(SPEEX_VOICE_ENCODER) && !defined(ROCKBOX_VOICE_CODEC)
void speex_bits_read_from(SpeexBits *bits, char *chars, int len)
EXPORT void speex_bits_read_from(SpeexBits *bits, char *chars, int len)
{
int i;
int nchars = len / BYTES_PER_CHAR;
@ -166,9 +166,10 @@ static void speex_bits_flush(SpeexBits *bits)
bits->charPtr=0;
}
void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes)
EXPORT void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes)
{
int i,pos;
int nchars = nbytes/BYTES_PER_CHAR;
if (((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR)+nchars > bits->buf_size)
@ -200,7 +201,7 @@ void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes)
#endif
#ifndef SPEEX_DISABLE_ENCODER
int speex_bits_write(SpeexBits *bits, char *chars, int max_nbytes)
EXPORT int speex_bits_write(SpeexBits *bits, char *chars, int max_nbytes)
{
int i;
int max_nchars = max_nbytes/BYTES_PER_CHAR;
@ -223,7 +224,7 @@ int speex_bits_write(SpeexBits *bits, char *chars, int max_nbytes)
return max_nchars*BYTES_PER_CHAR;
}
int speex_bits_write_whole_bytes(SpeexBits *bits, char *chars, int max_nbytes)
EXPORT int speex_bits_write_whole_bytes(SpeexBits *bits, char *chars, int max_nbytes)
{
int max_nchars = max_nbytes/BYTES_PER_CHAR;
int i;
@ -241,7 +242,7 @@ int speex_bits_write_whole_bytes(SpeexBits *bits, char *chars, int max_nbytes)
return max_nchars*BYTES_PER_CHAR;
}
void speex_bits_pack(SpeexBits *bits, int data, int nbBits)
EXPORT void speex_bits_pack(SpeexBits *bits, int data, int nbBits)
{
unsigned int d=data;
@ -287,7 +288,7 @@ void speex_bits_pack(SpeexBits *bits, int data, int nbBits)
#if 0
/* Rockbox: unused */
int speex_bits_unpack_signed(SpeexBits *bits, int nbBits)
EXPORT int speex_bits_unpack_signed(SpeexBits *bits, int nbBits)
{
unsigned int d=speex_bits_unpack_unsigned(bits,nbBits);
/* If number is negative */
@ -299,7 +300,7 @@ int speex_bits_unpack_signed(SpeexBits *bits, int nbBits)
}
#endif
unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits)
EXPORT unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits)
{
unsigned int d=0;
if ((bits->charPtr<<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
/* Rockbox: unused */
unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits)
EXPORT unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits)
{
unsigned int d=0;
int bitPtr, charPtr;
@ -353,7 +354,7 @@ unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits)
}
#endif
int speex_bits_peek(SpeexBits *bits)
EXPORT int speex_bits_peek(SpeexBits *bits)
{
if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+1>bits->nbBits)
bits->overflow=1;
@ -362,7 +363,7 @@ int speex_bits_peek(SpeexBits *bits)
return (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1;
}
void speex_bits_advance(SpeexBits *bits, int n)
EXPORT void speex_bits_advance(SpeexBits *bits, int n)
{
if (((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+n>bits->nbBits) || bits->overflow){
bits->overflow=1;
@ -372,7 +373,7 @@ void speex_bits_advance(SpeexBits *bits, int n)
bits->bitPtr = (bits->bitPtr+n) & (BITS_PER_CHAR-1); /* modulo by BITS_PER_CHAR */
}
int speex_bits_remaining(SpeexBits *bits)
EXPORT int speex_bits_remaining(SpeexBits *bits)
{
if (bits->overflow)
return -1;
@ -382,14 +383,14 @@ int speex_bits_remaining(SpeexBits *bits)
#if 0
/* Rockbox: unused */
int speex_bits_nbytes(SpeexBits *bits)
EXPORT int speex_bits_nbytes(SpeexBits *bits)
{
return ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR);
}
#endif
#ifndef SPEEX_DISABLE_ENCODER
void speex_bits_insert_terminator(SpeexBits *bits)
EXPORT void speex_bits_insert_terminator(SpeexBits *bits)
{
if (bits->bitPtr)
speex_bits_pack(bits, 0, 1);

View file

@ -1,5 +1,5 @@
#ifndef ROCKBOX_VOICE_ENCODER
#include "codeclib.h"
#include "codeclib.h"
#include "autoconf.h"
#else
#define ICODE_ATTR
@ -17,7 +17,11 @@
/* Make use of ARM4E assembly optimizations */
#if defined(CPU_ARM)
#if (ARM_ARCH < 5)
#define ARM4_ASM
#else
#define ARM5E_ASM
#endif
#endif
/* Make use of Coldfire assembly optimizations */
@ -40,10 +44,10 @@
#ifndef ROCKBOX_VOICE_ENCODER
/* Compile target codec as fixed point */
#define FIXED_POINT
#define FIXED_POINT
#else
/* Compile voice clip encoder as floating point */
#define FLOATING_POINT
#define FLOATING_POINT
#endif
#ifndef ROCKBOX_VOICE_CODEC
@ -137,13 +141,13 @@
#define SPEEX_MAJOR_VERSION 1
/* Version micro */
#define SPEEX_MICRO_VERSION 15
#define SPEEX_MICRO_VERSION 16
/* Version minor */
#define SPEEX_MINOR_VERSION 1
/* Complete version string */
#define SPEEX_VERSION "1.2beta3"
#define SPEEX_VERSION "1.2rc1"
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
@ -155,7 +159,7 @@
/* #undef USE_ALLOCA */
/* Use C99 variable-size arrays */
#define VAR_ARRAYS
#define VAR_ARRAYS
/* Enable Vorbis-style psychoacoustics (EXPERIMENTAL) */
/* #undef VORBIS_PSYCHO */
@ -184,3 +188,7 @@
#define RELEASE 1
/* We don't care */
#define EXPORT
#define USE_KISS_FFT

View file

@ -1,23 +1,23 @@
/* Copyright (C) 2005-2006 Jean-Marc Valin
/* Copyright (C) 2005-2006 Jean-Marc Valin
File: fftwrap.c
Wrapper for various FFTs
Wrapper for various FFTs
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@ -36,10 +36,6 @@
#include "config-speex.h"
#endif
/*#define USE_SMALLFT*/
#define USE_KISS_FFT
#include "arch.h"
#include "os_support.h"
@ -66,7 +62,7 @@ static int maximize_range(spx_word16_t *in, spx_word16_t *out, spx_word16_t boun
for (i=0;i<len;i++)
{
out[i] = SHL16(in[i], shift);
}
}
return shift;
}
@ -130,6 +126,119 @@ void spx_ifft(void *table, float *in, float *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)
#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"
"\tstrh %5, [%1], #2 \n"
"\tbge .normalize16loop%=\n"
"\tbgt .normalize16loop%=\n"
: "=r" (dead1), "=r" (dead2), "=r" (dead3), "=r" (dead4),
"=r" (dead5), "=r" (dead6)
: "0" (x), "1" (y), "2" (len>>2), "3" (sig_shift)

View file

@ -7,18 +7,18 @@
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@ -101,7 +101,7 @@ static inline int _EXTEND32(int x, char *file, int line)
}
#define SHR16(a, shift) _SHR16(a, shift, __FILE__, __LINE__)
static inline short _SHR16(int a, int shift, char *file, int line)
static inline short _SHR16(int a, int shift, char *file, int line)
{
int res;
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift))
@ -115,7 +115,7 @@ static inline short _SHR16(int a, int shift, char *file, int line)
return res;
}
#define SHL16(a, shift) _SHL16(a, shift, __FILE__, __LINE__)
static inline short _SHL16(int a, int shift, char *file, int line)
static inline short _SHL16(int a, int shift, char *file, int line)
{
int res;
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift))
@ -129,7 +129,7 @@ static inline short _SHL16(int a, int shift, char *file, int line)
return res;
}
static inline int SHR32(long long a, int shift)
static inline int SHR32(long long a, int shift)
{
long long res;
if (!VERIFY_INT(a) || !VERIFY_SHORT(shift))
@ -144,7 +144,7 @@ static inline int SHR32(long long a, int shift)
spx_mips++;
return res;
}
static inline int SHL32(long long a, int shift)
static inline int SHL32(long long a, int shift)
{
long long res;
if (!VERIFY_INT(a) || !VERIFY_SHORT(shift))
@ -161,7 +161,7 @@ static inline int SHL32(long long a, int shift)
}
#define PSHR16(a,shift) (SHR16(ADD16((a),((1<<((shift))>>1))),shift))
#define PSHR32(a,shift) (SHR32(ADD32((a),((1<<((shift))>>1))),shift))
#define PSHR32(a,shift) (SHR32(ADD32((a),((EXTEND32(1)<<((shift))>>1))),shift))
#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
@ -171,7 +171,7 @@ static inline int SHL32(long long a, int shift)
//#define SHL(a,shift) ((a) << (shift))
#define ADD16(a, b) _ADD16(a, b, __FILE__, __LINE__)
static inline short _ADD16(int a, int b, char *file, int line)
static inline short _ADD16(int a, int b, char *file, int line)
{
int res;
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
@ -188,7 +188,7 @@ static inline short _ADD16(int a, int b, char *file, int line)
}
#define SUB16(a, b) _SUB16(a, b, __FILE__, __LINE__)
static inline short _SUB16(int a, int b, char *file, int line)
static inline short _SUB16(int a, int b, char *file, int line)
{
int res;
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
@ -203,7 +203,7 @@ static inline short _SUB16(int a, int b, char *file, int line)
}
#define ADD32(a, b) _ADD32(a, b, __FILE__, __LINE__)
static inline int _ADD32(long long a, long long b, char *file, int line)
static inline int _ADD32(long long a, long long b, char *file, int line)
{
long long res;
if (!VERIFY_INT(a) || !VERIFY_INT(b))
@ -219,7 +219,7 @@ static inline int _ADD32(long long a, long long b, char *file, int line)
return res;
}
static inline int SUB32(long long a, long long b)
static inline int SUB32(long long a, long long b)
{
long long res;
if (!VERIFY_INT(a) || !VERIFY_INT(b))
@ -236,7 +236,7 @@ static inline int SUB32(long long a, long long b)
#define ADD64(a,b) (MIPS_INC(a)+(b))
/* result fits in 16 bits */
static inline short MULT16_16_16(int a, int b)
static inline short MULT16_16_16(int a, int b)
{
int res;
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
@ -251,7 +251,7 @@ static inline short MULT16_16_16(int a, int b)
}
#define MULT16_16(a, b) _MULT16_16(a, b, __FILE__, __LINE__)
static inline int _MULT16_16(int a, int b, char *file, int line)
static inline int _MULT16_16(int a, int b, char *file, int line)
{
long long res;
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
@ -279,8 +279,8 @@ static inline int _MULT16_32_QX(int a, long long b, int Q, char *file, int line)
{
fprintf (stderr, "MULT16_32_Q%d: inputs are not short+int: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
}
if (ABS32(b)>=(1<<(15+Q)))
fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
if (ABS32(b)>=(EXTEND32(1)<<(15+Q)))
fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
res = (((long long)a)*(long long)b) >> Q;
if (!VERIFY_INT(res))
fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line);
@ -295,9 +295,9 @@ static inline int MULT16_32_PX(int a, long long b, int Q)
{
fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d\n", Q, (int)a, (int)b);
}
if (ABS32(b)>=(1<<(15+Q)))
fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b);
res = ((((long long)a)*(long long)b) + ((1<<Q)>>1))>> Q;
if (ABS32(b)>=(EXTEND32(1)<<(15+Q)))
fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b);
res = ((((long long)a)*(long long)b) + ((EXTEND32(1)<<Q)>>1))>> Q;
if (!VERIFY_INT(res))
fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d\n", Q, (int)a, (int)b,(int)res);
spx_mips+=5;
@ -323,7 +323,7 @@ static inline int SATURATE(int a, int b)
return a;
}
static inline int MULT16_16_Q11_32(int a, int b)
static inline int MULT16_16_Q11_32(int a, int b)
{
long long res;
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
@ -337,7 +337,7 @@ static inline int MULT16_16_Q11_32(int a, int b)
spx_mips+=3;
return res;
}
static inline short MULT16_16_Q13(int a, int b)
static inline short MULT16_16_Q13(int a, int b)
{
long long res;
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
@ -351,7 +351,7 @@ static inline short MULT16_16_Q13(int a, int b)
spx_mips+=3;
return res;
}
static inline short MULT16_16_Q14(int a, int b)
static inline short MULT16_16_Q14(int a, int b)
{
long long res;
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
@ -365,7 +365,7 @@ static inline short MULT16_16_Q14(int a, int b)
spx_mips+=3;
return res;
}
static inline short MULT16_16_Q15(int a, int b)
static inline short MULT16_16_Q15(int a, int b)
{
long long res;
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
@ -382,7 +382,7 @@ static inline short MULT16_16_Q15(int a, int b)
return res;
}
static inline short MULT16_16_P13(int a, int b)
static inline short MULT16_16_P13(int a, int b)
{
long long res;
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
@ -399,7 +399,7 @@ static inline short MULT16_16_P13(int a, int b)
spx_mips+=4;
return res;
}
static inline short MULT16_16_P14(int a, int b)
static inline short MULT16_16_P14(int a, int b)
{
long long res;
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
@ -416,7 +416,7 @@ static inline short MULT16_16_P14(int a, int b)
spx_mips+=4;
return res;
}
static inline short MULT16_16_P15(int a, int b)
static inline short MULT16_16_P15(int a, int b)
{
long long res;
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
@ -436,7 +436,7 @@ static inline short MULT16_16_P15(int a, int b)
#define DIV32_16(a, b) _DIV32_16(a, b, __FILE__, __LINE__)
static inline int _DIV32_16(long long a, long long b, char *file, int line)
static inline int _DIV32_16(long long a, long long b, char *file, int line)
{
long long res;
if (b==0)
@ -462,7 +462,7 @@ static inline int _DIV32_16(long long a, long long b, char *file, int line)
}
#define DIV32(a, b) _DIV32(a, b, __FILE__, __LINE__)
static inline int _DIV32(long long a, long long b, char *file, int line)
static inline int _DIV32(long long a, long long b, char *file, int line)
{
long long res;
if (b==0)

View file

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

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2002 Jean-Marc Valin
/* Copyright (C) 2002 Jean-Marc Valin
File: speex_jitter.h
Adaptive jitter buffer for Speex
@ -6,18 +6,18 @@
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@ -73,17 +73,17 @@ TODO:
#define LT32(a,b) (((spx_int32_t)((a)-(b)))<0)
#define LE32(a,b) (((spx_int32_t)((a)-(b)))<=0)
#define ROUND_DOWN(x, step) ((x)<0 ? ((x)-(step)+1)/(step)*(step) : (x)/(step)*(step))
#define ROUND_DOWN(x, step) ((x)<0 ? ((x)-(step)+1)/(step)*(step) : (x)/(step)*(step))
#define MAX_TIMINGS 20
#define MAX_TIMINGS 40
#define MAX_BUFFERS 3
#define TOP_DELAY 20
#define TOP_DELAY 40
/** Buffer that keeps the time of arrival of the latest packets */
struct TimingBuffer {
int filled; /**< Number of entries occupied in "timing" and "counts"*/
int curr_count; /**< Number of packet timings we got (including those we discarded) */
spx_int16_t timing[MAX_TIMINGS]; /**< Sorted list of all timings ("latest" packets first) */
spx_int32_t timing[MAX_TIMINGS]; /**< Sorted list of all timings ("latest" packets first) */
spx_int16_t counts[MAX_TIMINGS]; /**< Order the packets were put in (will be used for short-term estimate) */
};
@ -103,7 +103,7 @@ static void tb_add(struct TimingBuffer *tb, spx_int16_t timing)
tb->curr_count++;
return;
}
/* Find where the timing info goes in the sorted list */
pos = 0;
/* FIXME: Do bisection instead of linear search */
@ -111,9 +111,9 @@ static void tb_add(struct TimingBuffer *tb, spx_int16_t timing)
{
pos++;
}
speex_assert(pos <= tb->filled && pos < MAX_TIMINGS);
/* Shift everything so we can perform the insertion */
if (pos < tb->filled)
{
@ -126,7 +126,7 @@ static void tb_add(struct TimingBuffer *tb, spx_int16_t timing)
/* Insert */
tb->timing[pos] = timing;
tb->counts[pos] = tb->curr_count;
tb->curr_count++;
if (tb->filled<MAX_TIMINGS)
tb->filled++;
@ -139,12 +139,12 @@ struct JitterBuffer_ {
spx_uint32_t pointer_timestamp; /**< Timestamp of what we will *get* next */
spx_uint32_t last_returned_timestamp; /**< Useful for getting the next packet with the same timestamp (for fragmented media) */
spx_uint32_t next_stop; /**< Estimated time the next get() will be called */
spx_int32_t buffered; /**< Amount of data we think is still buffered by the application (timestamp units)*/
JitterBufferPacket packets[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packets stored in the buffer */
spx_uint32_t arrival[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packet arrival time (0 means it was late, even though it's a valid timestamp) */
void (*destroy) (void *); /**< Callback for destroying a packet */
spx_int32_t delay_step; /**< Size of the steps when adjusting buffering (timestamp units) */
@ -154,7 +154,7 @@ struct JitterBuffer_ {
int late_cutoff; /**< How late must a packet be for it not to be considered at all */
int interp_requested; /**< An interpolation is requested by speex_jitter_update_delay() */
int auto_adjust; /**< Whether to automatically adjust the delay at any time */
struct TimingBuffer _tb[MAX_BUFFERS]; /**< Don't use those directly */
struct TimingBuffer *timeBuffers[MAX_BUFFERS]; /**< Storing arrival time of latest frames so we can compute some stats */
int window_size; /**< Total window over which the late frames are counted */
@ -162,15 +162,15 @@ struct JitterBuffer_ {
int max_late_rate; /**< Absolute maximum amount of late packets tolerable (in percent) */
int latency_tradeoff; /**< Latency equivalent of losing one percent of packets */
int auto_tradeoff; /**< Latency equivalent of losing one percent of packets (automatic default) */
int lost_count; /**< Number of consecutive lost packets */
};
/** Based on available data, this computes the optimal delay for the jitter buffer.
/** Based on available data, this computes the optimal delay for the jitter buffer.
The optimised function is in timestamp units and is:
cost = delay + late_factor*[number of frames that would be late if we used that delay]
@param tb Array of buffers
@param late_factor Equivalent cost of a late frame (in timestamp units)
@param late_factor Equivalent cost of a late frame (in timestamp units)
*/
static spx_int16_t compute_opt_delay(JitterBuffer *jitter)
{
@ -186,27 +186,27 @@ static spx_int16_t compute_opt_delay(JitterBuffer *jitter)
int worst = 0;
spx_int32_t deltaT;
struct TimingBuffer *tb;
tb = jitter->_tb;
/* Number of packet timings we have received (including those we didn't keep) */
tot_count = 0;
for (i=0;i<MAX_BUFFERS;i++)
tot_count += tb[i].curr_count;
if (tot_count==0)
return 0;
/* Compute cost for one lost packet */
if (jitter->latency_tradeoff != 0)
late_factor = jitter->latency_tradeoff * 100.0f / tot_count;
else
late_factor = jitter->auto_tradeoff * jitter->window_size/tot_count;
/*fprintf(stderr, "late_factor = %f\n", late_factor);*/
for (i=0;i<MAX_BUFFERS;i++)
pos[i] = 0;
/* Pick the TOP_DELAY "latest" packets (doesn't need to actually be late
/* Pick the TOP_DELAY "latest" packets (doesn't need to actually be late
for the current settings) */
for (i=0;i<TOP_DELAY;i++)
{
@ -225,13 +225,13 @@ static spx_int16_t compute_opt_delay(JitterBuffer *jitter)
if (next != -1)
{
spx_int32_t cost;
if (i==0)
worst = latest;
best = latest;
latest = ROUND_DOWN(latest, jitter->delay_step);
pos[next]++;
/* Actual cost function that tells us how bad using this delay would be */
cost = -latest + late_factor*late;
/*fprintf(stderr, "cost %d = %d + %f * %d\n", cost, -latest, late_factor, late);*/
@ -243,24 +243,24 @@ static spx_int16_t compute_opt_delay(JitterBuffer *jitter)
} else {
break;
}
/* For the next timing we will consider, there will be one more late packet to count */
late++;
/* Two-frame penalty if we're going to increase the amount of late frames (hysteresis) */
if (latest >= 0 && !penalty_taken)
{
penalty_taken = 1;
late+=2;
late+=4;
}
}
deltaT = best-worst;
/* This is a default "automatic latency tradeoff" when none is provided */
jitter->auto_tradeoff = 1 + deltaT/TOP_DELAY;
/*fprintf(stderr, "auto_tradeoff = %d (%d %d %d)\n", jitter->auto_tradeoff, best, worst, i);*/
/* FIXME: Compute a short-term estimate too and combine with the long-term one */
/* Prevents reducing the buffer size when we haven't really had much data */
if (tot_count < TOP_DELAY && opt > 0)
return 0;
@ -269,7 +269,7 @@ static spx_int16_t compute_opt_delay(JitterBuffer *jitter)
/** Initialise jitter buffer */
JitterBuffer *jitter_buffer_init(int step_size)
EXPORT JitterBuffer *jitter_buffer_init(int step_size)
{
JitterBuffer *jitter = (JitterBuffer*)speex_alloc(sizeof(JitterBuffer));
if (jitter)
@ -294,7 +294,7 @@ JitterBuffer *jitter_buffer_init(int step_size)
}
/** Reset jitter buffer */
void jitter_buffer_reset(JitterBuffer *jitter)
EXPORT void jitter_buffer_reset(JitterBuffer *jitter)
{
int i;
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
@ -315,7 +315,7 @@ void jitter_buffer_reset(JitterBuffer *jitter)
jitter->lost_count = 0;
jitter->buffered = 0;
jitter->auto_tradeoff = 32000;
for (i=0;i<MAX_BUFFERS;i++)
{
tb_init(&jitter->_tb[i]);
@ -325,7 +325,7 @@ void jitter_buffer_reset(JitterBuffer *jitter)
}
/** Destroy jitter buffer */
void jitter_buffer_destroy(JitterBuffer *jitter)
EXPORT void jitter_buffer_destroy(JitterBuffer *jitter)
{
jitter_buffer_reset(jitter);
speex_free(jitter);
@ -365,12 +365,12 @@ static void shift_timings(JitterBuffer *jitter, spx_int16_t amount)
/** Put one packet into the jitter buffer */
void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
EXPORT void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
{
int i,j;
int late;
/*fprintf (stderr, "put packet %d %d\n", timestamp, span);*/
/* Cleanup buffer (remove old packets that weren't played) */
if (!jitter->reset_state)
{
@ -388,7 +388,7 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
}
}
}
/*fprintf(stderr, "arrival: %d %d %d\n", packet->timestamp, jitter->next_stop, jitter->pointer_timestamp);*/
/* Check if packet is late (could still be useful though) */
if (!jitter->reset_state && LT32(packet->timestamp, jitter->next_stop))
@ -398,7 +398,14 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
} else {
late = 0;
}
/* For some reason, the consumer has failed the last 20 fetches. Make sure this packet is
* used to resync. */
if (jitter->lost_count>20)
{
jitter_buffer_reset(jitter);
}
/* Only insert the packet if it's not hopelessly late (i.e. totally useless) */
if (jitter->reset_state || GE32(packet->timestamp+packet->span+jitter->delay_step, jitter->pointer_timestamp))
{
@ -409,7 +416,7 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
if (jitter->packets[i].data==NULL)
break;
}
/*No place left in the buffer, need to make room for it by discarding the oldest packet */
if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
{
@ -428,13 +435,9 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
else
speex_free(jitter->packets[i].data);
jitter->packets[i].data=NULL;
if (jitter->lost_count>20)
{
jitter_buffer_reset(jitter);
}
/*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/
/*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/
}
/* Copy packet in buffer */
if (jitter->destroy)
{
@ -454,18 +457,18 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
else
jitter->arrival[i] = jitter->next_stop;
}
}
/** Get one packet from the jitter buffer */
int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset)
EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset)
{
int i;
unsigned int j;
int incomplete = 0;
spx_int16_t opt;
if (start_offset != NULL)
*start_offset = 0;
@ -485,7 +488,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
}
if (found)
{
jitter->reset_state=0;
jitter->reset_state=0;
jitter->pointer_timestamp = oldest;
jitter->next_stop = oldest;
} else {
@ -494,36 +497,36 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
return JITTER_BUFFER_MISSING;
}
}
jitter->last_returned_timestamp = jitter->pointer_timestamp;
if (jitter->interp_requested != 0)
{
packet->timestamp = jitter->pointer_timestamp;
packet->span = jitter->interp_requested;
/* Increment the pointer because it got decremented in the delay update */
jitter->pointer_timestamp += jitter->interp_requested;
packet->len = 0;
/*fprintf (stderr, "Deferred interpolate\n");*/
jitter->interp_requested = 0;
jitter->buffered = packet->span - desired_span;
return JITTER_BUFFER_INSERTION;
}
/* Searching for the packet that fits best */
/* Search the buffer for a packet with the right timestamp and spanning the whole current chunk */
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
{
if (jitter->packets[i].data && jitter->packets[i].timestamp==jitter->pointer_timestamp && GE32(jitter->packets[i].timestamp+jitter->packets[i].span,jitter->pointer_timestamp+desired_span))
break;
}
/* If no match, try for an "older" packet that still spans (fully) the current chunk */
if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
{
@ -533,7 +536,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
break;
}
}
/* If still no match, try for an "older" packet that spans part of the current chunk */
if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
{
@ -543,7 +546,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
break;
}
}
/* If still no match, try for earliest packet possible */
if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
{
@ -577,17 +580,17 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE)
{
spx_int32_t offset;
/* We (obviously) haven't lost this packet */
jitter->lost_count = 0;
/* In this case, 0 isn't as a valid timestamp */
if (jitter->arrival[i] != 0)
{
update_timings(jitter, ((spx_int32_t)jitter->packets[i].timestamp) - ((spx_int32_t)jitter->arrival[i]) - jitter->buffer_margin);
}
if (jitter->packets[i].len > packet->len)
{
speex_warning_int("jitter_buffer_get(): packet too large to fit. Size is", jitter->packets[i].len);
@ -611,10 +614,10 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
*start_offset = offset;
else if (offset != 0)
speex_warning_int("jitter_buffer_get() discarding non-zero start_offset", offset);
packet->timestamp = jitter->packets[i].timestamp;
jitter->last_returned_timestamp = packet->timestamp;
packet->span = jitter->packets[i].span;
packet->sequence = jitter->packets[i].sequence;
packet->user_data = jitter->packets[i].user_data;
@ -622,36 +625,36 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
jitter->pointer_timestamp = jitter->packets[i].timestamp+jitter->packets[i].span;
jitter->buffered = packet->span - desired_span;
if (start_offset != NULL)
jitter->buffered += *start_offset;
return JITTER_BUFFER_OK;
}
/* If we haven't found anything worth returning */
/*fprintf (stderr, "not found\n");*/
jitter->lost_count++;
/*fprintf (stderr, "m");*/
/*fprintf (stderr, "lost_count = %d\n", jitter->lost_count);*/
opt = compute_opt_delay(jitter);
/* Should we force an increase in the buffer or just do normal interpolation? */
/* Should we force an increase in the buffer or just do normal interpolation? */
if (opt < 0)
{
/* Need to increase buffering */
/* Shift histogram to compensate */
shift_timings(jitter, -opt);
packet->timestamp = jitter->pointer_timestamp;
packet->span = -opt;
/* Don't move the pointer_timestamp forward */
packet->len = 0;
jitter->buffered = packet->span - desired_span;
return JITTER_BUFFER_INSERTION;
/*jitter->pointer_timestamp -= jitter->delay_step;*/
@ -659,12 +662,12 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
} else {
/* Normal packet loss */
packet->timestamp = jitter->pointer_timestamp;
desired_span = ROUND_DOWN(desired_span, jitter->concealment_size);
packet->span = desired_span;
jitter->pointer_timestamp += desired_span;
packet->len = 0;
jitter->buffered = packet->span - desired_span;
return JITTER_BUFFER_MISSING;
/*fprintf (stderr, "Normal loss\n");*/
@ -673,7 +676,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3
}
int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet)
EXPORT int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet)
{
int i, j;
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
@ -713,11 +716,11 @@ static int _jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket
{
spx_int16_t opt = compute_opt_delay(jitter);
/*fprintf(stderr, "opt adjustment is %d ", opt);*/
if (opt < 0)
{
shift_timings(jitter, -opt);
jitter->pointer_timestamp += opt;
jitter->interp_requested = -opt;
/*fprintf (stderr, "Decision to interpolate %d samples\n", -opt);*/
@ -727,14 +730,14 @@ static int _jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket
jitter->pointer_timestamp += opt;
/*fprintf (stderr, "Decision to drop %d samples\n", opt);*/
}
return opt;
}
/* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */
int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset)
EXPORT int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset)
{
/* If the programmer calls jitter_buffer_update_delay() directly,
/* If the programmer calls jitter_buffer_update_delay() directly,
automatically disable auto-adjustment */
jitter->auto_adjust = 0;
@ -742,17 +745,17 @@ int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet,
}
/** Get pointer timestamp of jitter buffer */
int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter)
EXPORT int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter)
{
return jitter->pointer_timestamp;
}
void jitter_buffer_tick(JitterBuffer *jitter)
EXPORT void jitter_buffer_tick(JitterBuffer *jitter)
{
/* Automatically-adjust the buffering delay if requested */
if (jitter->auto_adjust)
_jitter_buffer_update_delay(jitter, NULL, NULL);
if (jitter->buffered >= 0)
{
jitter->next_stop = jitter->pointer_timestamp - jitter->buffered;
@ -763,12 +766,12 @@ void jitter_buffer_tick(JitterBuffer *jitter)
jitter->buffered = 0;
}
void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem)
EXPORT void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem)
{
/* Automatically-adjust the buffering delay if requested */
if (jitter->auto_adjust)
_jitter_buffer_update_delay(jitter, NULL, NULL);
if (jitter->buffered < 0)
speex_warning_int("jitter buffer sees negative buffering, your code might be broken. Value is ", jitter->buffered);
jitter->next_stop = jitter->pointer_timestamp - rem;
@ -776,7 +779,7 @@ void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem)
/* Used like the ioctl function to control the jitter buffer parameters */
int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
EXPORT int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
{
int count, i;
switch(request)
@ -836,4 +839,3 @@ int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
}
return 0;
}

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2003-2006 Jean-Marc Valin
/* Copyright (C) 2003-2008 Jean-Marc Valin
File: mdf.c
Echo canceller based on the MDF algorithm (see below)
@ -33,36 +33,36 @@
/*
The echo canceller is based on the MDF algorithm described in:
J. S. Soo, K. K. Pang Multidelay block frequency adaptive filter,
IEEE Trans. Acoust. Speech Signal Process., Vol. ASSP-38, No. 2,
J. S. Soo, K. K. Pang Multidelay block frequency adaptive filter,
IEEE Trans. Acoust. Speech Signal Process., Vol. ASSP-38, No. 2,
February 1990.
We use the Alternatively Updated MDF (AUMDF) variant. Robustness to
We use the Alternatively Updated MDF (AUMDF) variant. Robustness to
double-talk is achieved using a variable learning rate as described in:
Valin, J.-M., On Adjusting the Learning Rate in Frequency Domain Echo
Valin, J.-M., On Adjusting the Learning Rate in Frequency Domain Echo
Cancellation With Double-Talk. IEEE Transactions on Audio,
Speech and Language Processing, Vol. 15, No. 3, pp. 1030-1034, 2007.
http://people.xiph.org/~jm/papers/valin_taslp2006.pdf
There is no explicit double-talk detection, but a continuous variation
in the learning rate based on residual echo, double-talk and background
noise.
About the fixed-point version:
All the signals are represented with 16-bit words. The filter weights
All the signals are represented with 16-bit words. The filter weights
are represented with 32-bit words, but only the top 16 bits are used
in most cases. The lower 16 bits are completely unreliable (due to the
fact that the update is done only on the top bits), but help in the
adaptation -- probably by removing a "threshold effect" due to
quantization (rounding going to zero) when the gradient is small.
Another kludge that seems to work good: when performing the weight
update, we only move half the way toward the "goal" this seems to
reduce the effect of quantization noise in the update phase. This
can be seen as applying a gradient descent on a "soft constraint"
instead of having a hard constraint.
*/
#ifdef HAVE_CONFIG_H
@ -88,6 +88,12 @@
#define WEIGHT_SHIFT 0
#endif
#ifdef FIXED_POINT
#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x)))
#else
#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x))))
#endif
/* If enabled, the AEC will use a foreground filter and a background filter to be more robust to double-talk
and difficult signals in general. The cost is an extra FFT and a matrix-vector multiply */
#define TWO_PATH
@ -131,13 +137,15 @@ struct SpeexEchoState_ {
int adapted;
int saturated;
int screwed_up;
int C; /** Number of input channels (microphones) */
int K; /** Number of output channels (loudspeakers) */
spx_int32_t sampling_rate;
spx_word16_t spec_average;
spx_word16_t beta0;
spx_word16_t beta_max;
spx_word32_t sum_adapt;
spx_word16_t leak_estimate;
spx_word16_t *e; /* scratch */
spx_word16_t *x; /* Far-end input buffer (2N) */
spx_word16_t *X; /* Far-end buffer (M+1 frames) in frequency domain */
@ -171,10 +179,10 @@ struct SpeexEchoState_ {
spx_word16_t *window;
spx_word16_t *prop;
void *fft_table;
spx_word16_t memX, memD, memE;
spx_word16_t *memX, *memD, *memE;
spx_word16_t preemph;
spx_word16_t notch_radius;
spx_mem_t notch_mem[2];
spx_mem_t *notch_mem;
/* NOTE: If you only use speex_echo_cancel() and want to save some memory, remove this */
spx_int16_t *play_buf;
@ -182,7 +190,7 @@ struct SpeexEchoState_ {
int play_buf_started;
};
static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius, spx_word16_t *out, int len, spx_mem_t *mem)
static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius, spx_word16_t *out, int len, spx_mem_t *mem, int stride)
{
int i;
spx_word16_t den2;
@ -190,11 +198,11 @@ static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius,
den2 = MULT16_16_Q15(radius,radius) + MULT16_16_Q15(QCONST16(.7,15),MULT16_16_Q15(32767-radius,32767-radius));
#else
den2 = radius*radius + .7*(1-radius)*(1-radius);
#endif
#endif
/*printf ("%d %d %d %d %d %d\n", num[0], num[1], num[2], den[0], den[1], den[2]);*/
for (i=0;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);
#ifdef FIXED_POINT
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]);
}
/** 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 */
#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)
@ -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]));
}
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_word32_t prop_sum = 1;
for (i=0;i<M;i++)
{
spx_word32_t tmp = 1;
for (j=0;j<N;j++)
tmp += MULT16_16(EXTRACT16(SHR32(W[i*N+j],18)), EXTRACT16(SHR32(W[i*N+j],18)));
for (p=0;p<P;p++)
for (j=0;j<N;j++)
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
/* Just a security in case an overflow were to occur */
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
/** 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));
st->K = nb_speakers;
st->C = nb_mic;
C=st->C;
K=st->K;
#ifdef DUMP_ECHO_CANCEL_DATA
if (rFile || pFile || oFile)
speex_fatal("Opening dump files twice");
@ -390,7 +420,7 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
pFile = fopen("aec_play.sw", "wb");
oFile = fopen("aec_out.sw", "wb");
#endif
st->frame_size = frame_size;
st->window_size = 2*frame_size;
N = st->window_size;
@ -412,24 +442,24 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
st->leak_estimate = 0;
st->fft_table = spx_fft_init(N);
st->e = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
st->x = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
st->input = (spx_word16_t*)speex_alloc(st->frame_size*sizeof(spx_word16_t));
st->y = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
st->last_y = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
st->e = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t));
st->x = (spx_word16_t*)speex_alloc(K*N*sizeof(spx_word16_t));
st->input = (spx_word16_t*)speex_alloc(C*st->frame_size*sizeof(spx_word16_t));
st->y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t));
st->last_y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t));
st->Yf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
st->Rf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
st->Xf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
st->Yh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
st->Eh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
st->X = (spx_word16_t*)speex_alloc((M+1)*N*sizeof(spx_word16_t));
st->Y = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
st->E = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
st->W = (spx_word32_t*)speex_alloc(M*N*sizeof(spx_word32_t));
st->X = (spx_word16_t*)speex_alloc(K*(M+1)*N*sizeof(spx_word16_t));
st->Y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t));
st->E = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t));
st->W = (spx_word32_t*)speex_alloc(C*K*M*N*sizeof(spx_word32_t));
#ifdef TWO_PATH
st->foreground = (spx_word16_t*)speex_alloc(M*N*sizeof(spx_word16_t));
st->foreground = (spx_word16_t*)speex_alloc(M*N*C*K*sizeof(spx_word16_t));
#endif
st->PHI = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t));
st->power = (spx_word32_t*)speex_alloc((frame_size+1)*sizeof(spx_word32_t));
@ -450,7 +480,7 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
#endif
for (i=0;i<=st->frame_size;i++)
st->power_1[i] = FLOAT_ONE;
for (i=0;i<N*M;i++)
for (i=0;i<N*M*K*C;i++)
st->W[i] = 0;
{
spx_word32_t sum = 0;
@ -465,11 +495,13 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
}
for (i=M-1;i>=0;i--)
{
st->prop[i] = DIV32(MULT16_16(QCONST16(.8,15), st->prop[i]),sum);
st->prop[i] = DIV32(MULT16_16(QCONST16(.8f,15), st->prop[i]),sum);
}
}
st->memX=st->memD=st->memE=0;
st->memX = (spx_word16_t*)speex_alloc(K*sizeof(spx_word16_t));
st->memD = (spx_word16_t*)speex_alloc(C*sizeof(spx_word16_t));
st->memE = (spx_word16_t*)speex_alloc(C*sizeof(spx_word16_t));
st->preemph = QCONST16(.9,15);
if (st->sampling_rate<12000)
st->notch_radius = QCONST16(.9, 15);
@ -478,30 +510,32 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
else
st->notch_radius = QCONST16(.992, 15);
st->notch_mem[0] = st->notch_mem[1] = 0;
st->notch_mem = (spx_mem_t*)speex_alloc(2*C*sizeof(spx_mem_t));
st->adapted = 0;
st->Pey = st->Pyy = FLOAT_ONE;
#ifdef TWO_PATH
st->Davg1 = st->Davg2 = 0;
st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
#endif
st->play_buf = (spx_int16_t*)speex_alloc((PLAYBACK_DELAY+1)*st->frame_size*sizeof(spx_int16_t));
st->play_buf = (spx_int16_t*)speex_alloc(K*(PLAYBACK_DELAY+1)*st->frame_size*sizeof(spx_int16_t));
st->play_buf_pos = PLAYBACK_DELAY*st->frame_size;
st->play_buf_started = 0;
return st;
}
/** Resets echo canceller state */
void speex_echo_state_reset(SpeexEchoState *st)
EXPORT void speex_echo_state_reset(SpeexEchoState *st)
{
int i, M, N;
int i, M, N, C, K;
st->cancel_count=0;
st->screwed_up = 0;
N = st->window_size;
M = st->M;
C=st->C;
K=st->K;
for (i=0;i<N*M;i++)
st->W[i] = 0;
#ifdef TWO_PATH
@ -521,13 +555,20 @@ void speex_echo_state_reset(SpeexEchoState *st)
{
st->last_y[i] = 0;
}
for (i=0;i<N;i++)
for (i=0;i<N*C;i++)
{
st->E[i] = 0;
}
for (i=0;i<N*K;i++)
{
st->x[i] = 0;
}
st->notch_mem[0] = st->notch_mem[1] = 0;
st->memX=st->memD=st->memE=0;
for (i=0;i<2*C;i++)
st->notch_mem[i] = 0;
for (i=0;i<C;i++)
st->memD[i]=st->memE[i]=0;
for (i=0;i<K;i++)
st->memX[i]=0;
st->saturated = 0;
st->adapted = 0;
@ -545,7 +586,7 @@ void speex_echo_state_reset(SpeexEchoState *st)
}
/** Destroys an echo canceller state */
void speex_echo_state_destroy(SpeexEchoState *st)
EXPORT void speex_echo_state_destroy(SpeexEchoState *st)
{
spx_fft_destroy(st->fft_table);
@ -576,9 +617,14 @@ void speex_echo_state_destroy(SpeexEchoState *st)
#ifdef FIXED_POINT
speex_free(st->wtmp2);
#endif
speex_free(st->memX);
speex_free(st->memD);
speex_free(st->memE);
speex_free(st->notch_mem);
speex_free(st->play_buf);
speex_free(st);
#ifdef DUMP_ECHO_CANCEL_DATA
fclose(rFile);
fclose(pFile);
@ -587,7 +633,7 @@ void speex_echo_state_destroy(SpeexEchoState *st)
#endif
}
void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out)
EXPORT void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out)
{
int i;
/*speex_warning_int("capture with fill level ", st->play_buf_pos/st->frame_size);*/
@ -610,7 +656,7 @@ void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t
}
}
void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play)
EXPORT void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play)
{
/*speex_warning_int("playback with fill level ", st->play_buf_pos/st->frame_size);*/
if (!st->play_buf_started)
@ -637,16 +683,16 @@ void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play)
}
/** Performs echo cancellation on a frame (deprecated, last arg now ignored) */
void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out, spx_int32_t *Yout)
EXPORT void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out, spx_int32_t *Yout)
{
speex_echo_cancellation(st, in, far_end, out);
}
/** Performs echo cancellation on a frame */
void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out)
EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out)
{
int i,j;
int N,M;
int i,j, chan, speak;
int N,M, C, K;
spx_word32_t Syy,See,Sxx,Sdd, Sff;
#ifdef TWO_PATH
spx_word32_t Dbf;
@ -658,9 +704,12 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
spx_float_t alpha, alpha_1;
spx_word16_t RER;
spx_word32_t tmp32;
N = st->window_size;
M = st->M;
C = st->C;
K = st->K;
st->cancel_count++;
#ifdef FIXED_POINT
ss=DIV32_16(11469,M);
@ -670,157 +719,198 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
ss_1 = 1-ss;
#endif
/* Apply a notch filter to make sure DC doesn't end up causing problems */
filter_dc_notch16(in, st->notch_radius, st->input, st->frame_size, st->notch_mem);
/* Copy input data to buffer and apply pre-emphasis */
for (i=0;i<st->frame_size;i++)
for (chan = 0; chan < C; chan++)
{
spx_word32_t tmp32;
tmp32 = SUB32(EXTEND32(far_end[i]), EXTEND32(MULT16_16_P15(st->preemph, st->memX)));
/* Apply a notch filter to make sure DC doesn't end up causing problems */
filter_dc_notch16(in+chan, st->notch_radius, st->input+chan*st->frame_size, st->frame_size, st->notch_mem+2*chan, C);
/* Copy input data to buffer and apply pre-emphasis */
/* Copy input data to buffer */
for (i=0;i<st->frame_size;i++)
{
spx_word32_t tmp32;
/* FIXME: This core has changed a bit, need to merge properly */
tmp32 = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(MULT16_16_P15(st->preemph, st->memD[chan])));
#ifdef FIXED_POINT
/* If 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;
}
if (tmp32 > 32767)
{
tmp32 = 32767;
if (st->saturated == 0)
st->saturated = 1;
}
if (tmp32 < -32767)
{
tmp32 = -32767;
if (st->saturated == 0)
st->saturated = 1;
}
#endif
st->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
if (tmp32 > 32767)
{
tmp32 = 32767;
if (st->saturated == 0)
st->saturated = 1;
}
if (tmp32 < -32767)
{
tmp32 = -32767;
if (st->saturated == 0)
st->saturated = 1;
st->memD[chan] = st->input[chan*st->frame_size+i];
st->input[chan*st->frame_size+i] = EXTRACT16(tmp32);
}
#endif
st->memD = st->input[i];
st->input[i] = tmp32;
}
/* Shift memory: this could be optimized eventually*/
for (j=M-1;j>=0;j--)
for (speak = 0; speak < K; speak++)
{
for (i=0;i<N;i++)
st->X[(j+1)*N+i] = st->X[j*N+i];
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];
}
}
/* Convert x (far end) to frequency domain */
spx_fft(st->fft_table, st->x, &st->X[0]);
for (i=0;i<N;i++)
st->last_y[i] = st->x[i];
Sxx = mdf_inner_prod(st->x+st->frame_size, st->x+st->frame_size, st->frame_size);
for (i=0;i<st->frame_size;i++)
st->x[i] = st->x[i+st->frame_size];
/* From here on, the top part of x is used as scratch space */
for (speak = 0; speak < K; speak++)
{
/* Shift memory: this could be optimized eventually*/
for (j=M-1;j>=0;j--)
{
for (i=0;i<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]);
}
Sxx = 0;
for (speak = 0; speak < K; speak++)
{
Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size);
power_spectrum_accum(st->X+speak*N, st->Xf, N);
}
Sff = 0;
for (chan = 0; chan < C; chan++)
{
#ifdef TWO_PATH
/* Compute foreground filter */
spectral_mul_accum16(st->X, st->foreground, st->Y, N, M);
spx_ifft(st->fft_table, st->Y, st->e);
for (i=0;i<st->frame_size;i++)
st->e[i] = SUB16(st->input[i], st->e[i+st->frame_size]);
Sff = mdf_inner_prod(st->e, st->e, st->frame_size);
/* Compute foreground filter */
spectral_mul_accum16(st->X, st->foreground+chan*N*K*M, st->Y+chan*N, N, M*K);
spx_ifft(st->fft_table, st->Y+chan*N, st->e+chan*N);
for (i=0;i<st->frame_size;i++)
st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->e[chan*N+i+st->frame_size]);
Sff += mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size);
#endif
}
/* Adjust proportional adaption rate */
mdf_adjust_prop (st->W, N, M, st->prop);
/* FIXME: Adjust that for C, K*/
if (st->adapted)
mdf_adjust_prop (st->W, N, M, C*K, st->prop);
/* Compute weight gradient */
if (st->saturated == 0)
{
for (j=M-1;j>=0;j--)
for (chan = 0; chan < C; chan++)
{
weighted_spectral_mul_conj(st->power_1, FLOAT_SHL(PSEUDOFLOAT(st->prop[j]),-15), &st->X[(j+1)*N], st->E, st->PHI, N);
for (i=0;i<N;i++)
st->W[j*N+i] = ADD32(st->W[j*N+i], st->PHI[i]);
for (speak = 0; speak < K; speak++)
{
for (j=M-1;j>=0;j--)
{
weighted_spectral_mul_conj(st->power_1, FLOAT_SHL(PSEUDOFLOAT(st->prop[j]),-15), &st->X[(j+1)*N*K+speak*N], st->E+chan*N, st->PHI, N);
for (i=0;i<N;i++)
st->W[chan*N*K*M + j*N*K + speak*N + i] += st->PHI[i];
}
}
}
} else {
st->saturated--;
}
/* FIXME: MC conversion required */
/* Update weight to prevent circular convolution (MDF / AUMDF) */
for (j=0;j<M;j++)
for (chan = 0; chan < C; chan++)
{
/* This is a variant of the Alternatively Updated MDF (AUMDF) */
/* Remove the "if" to make this an MDF filter */
if (j==0 || st->cancel_count%(M-1) == j-1)
for (speak = 0; speak < K; speak++)
{
for (j=0;j<M;j++)
{
/* This is a variant of the Alternatively Updated MDF (AUMDF) */
/* Remove the "if" to make this an MDF filter */
if (j==0 || st->cancel_count%(M-1) == j-1)
{
#ifdef FIXED_POINT
for (i=0;i<N;i++)
st->wtmp2[i] = EXTRACT16(PSHR32(st->W[j*N+i],NORMALIZE_SCALEDOWN+16));
spx_ifft(st->fft_table, st->wtmp2, st->wtmp);
for (i=0;i<st->frame_size;i++)
{
st->wtmp[i]=0;
}
for (i=st->frame_size;i<N;i++)
{
st->wtmp[i]=SHL16(st->wtmp[i],NORMALIZE_SCALEUP);
}
spx_fft(st->fft_table, st->wtmp, st->wtmp2);
/* The "-1" in the shift is a sort of kludge that trades less efficient update speed for decrease noise */
for (i=0;i<N;i++)
st->W[j*N+i] -= SHL32(EXTEND32(st->wtmp2[i]),16+NORMALIZE_SCALEDOWN-NORMALIZE_SCALEUP-1);
for (i=0;i<N;i++)
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);
for (i=0;i<st->frame_size;i++)
{
st->wtmp[i]=0;
}
for (i=st->frame_size;i<N;i++)
{
st->wtmp[i]=SHL16(st->wtmp[i],NORMALIZE_SCALEUP);
}
spx_fft(st->fft_table, st->wtmp, st->wtmp2);
/* The "-1" in the shift is a sort of kludge that trades less efficient update speed for decrease noise */
for (i=0;i<N;i++)
st->W[chan*N*K*M + j*N*K + speak*N + i] -= SHL32(EXTEND32(st->wtmp2[i]),16+NORMALIZE_SCALEDOWN-NORMALIZE_SCALEUP-1);
#else
spx_ifft(st->fft_table, &st->W[j*N], st->wtmp);
for (i=st->frame_size;i<N;i++)
{
st->wtmp[i]=0;
}
spx_fft(st->fft_table, st->wtmp, &st->W[j*N]);
spx_ifft(st->fft_table, &st->W[chan*N*K*M + j*N*K + speak*N], st->wtmp);
for (i=st->frame_size;i<N;i++)
{
st->wtmp[i]=0;
}
spx_fft(st->fft_table, st->wtmp, &st->W[chan*N*K*M + j*N*K + speak*N]);
#endif
}
}
}
}
/* Compute filter response Y */
spectral_mul_accum(st->X, st->W, st->Y, N, M);
spx_ifft(st->fft_table, st->Y, st->y);
/* So we can use power_spectrum_accum */
for (i=0;i<=st->frame_size;i++)
st->Rf[i] = st->Yf[i] = st->Xf[i] = 0;
Dbf = 0;
See = 0;
#ifdef TWO_PATH
/* Difference in response, this is used to estimate the variance of our residual power estimate */
for (i=0;i<st->frame_size;i++)
st->e[i] = SUB16(st->e[i+st->frame_size], st->y[i+st->frame_size]);
Dbf = 10+mdf_inner_prod(st->e, st->e, st->frame_size);
for (chan = 0; chan < C; chan++)
{
spectral_mul_accum(st->X, st->W+chan*N*K*M, st->Y+chan*N, N, M*K);
spx_ifft(st->fft_table, st->Y+chan*N, st->y+chan*N);
for (i=0;i<st->frame_size;i++)
st->e[chan*N+i] = SUB16(st->e[chan*N+i+st->frame_size], st->y[chan*N+i+st->frame_size]);
Dbf += 10+mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size);
for (i=0;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
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
Sff = See;
#endif
#ifdef TWO_PATH
/* Logic for updating the foreground filter */
/* For two time windows, compute the mean of the energy difference, as well as the variance */
st->Davg1 = ADD32(MULT16_32_Q15(QCONST16(.6f,15),st->Davg1), MULT16_32_Q15(QCONST16(.4f,15),SUB32(Sff,See)));
st->Davg2 = ADD32(MULT16_32_Q15(QCONST16(.85f,15),st->Davg2), MULT16_32_Q15(QCONST16(.15f,15),SUB32(Sff,See)));
st->Dvar1 = FLOAT_ADD(FLOAT_MULT(VAR1_SMOOTH, st->Dvar1), FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.4f,15),Sff), MULT16_32_Q15(QCONST16(.4f,15),Dbf)));
st->Dvar2 = FLOAT_ADD(FLOAT_MULT(VAR2_SMOOTH, st->Dvar2), FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.15f,15),Sff), MULT16_32_Q15(QCONST16(.15f,15),Dbf)));
/* Equivalent float code:
st->Davg1 = .6*st->Davg1 + .4*(Sff-See);
st->Davg2 = .85*st->Davg2 + .15*(Sff-See);
st->Dvar1 = .36*st->Dvar1 + .16*Sff*Dbf;
st->Dvar2 = .7225*st->Dvar2 + .0225*Sff*Dbf;
*/
update_foreground = 0;
/* Check if we have a statistically significant reduction in the residual echo */
/* Note that this is *not* Gaussian, so we need to be careful about the longer tail */
@ -830,18 +920,19 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
update_foreground = 1;
else if (FLOAT_GT(FLOAT_MUL32U(st->Davg2, ABS32(st->Davg2)), FLOAT_MULT(VAR2_UPDATE,(st->Dvar2))))
update_foreground = 1;
/* Do we update? */
if (update_foreground)
{
st->Davg1 = st->Davg2 = 0;
st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
/* Copy background filter to foreground filter */
for (i=0;i<N*M;i++)
for (i=0;i<N*M*C*K;i++)
st->foreground[i] = EXTRACT16(PSHR32(st->W[i],16));
/* Apply a smooth transition so as to not introduce blocking artifacts */
for (i=0;i<st->frame_size;i++)
st->e[i+st->frame_size] = MULT16_16_Q15(st->window[i+st->frame_size],st->e[i+st->frame_size]) + MULT16_16_Q15(st->window[i],st->y[i+st->frame_size]);
for (chan = 0; chan < C; chan++)
for (i=0;i<st->frame_size;i++)
st->e[chan*N+i+st->frame_size] = MULT16_16_Q15(st->window[i+st->frame_size],st->e[chan*N+i+st->frame_size]) + MULT16_16_Q15(st->window[i],st->y[chan*N+i+st->frame_size]);
} else {
int reset_background=0;
/* Otherwise, check if the background filter is significantly worse */
@ -854,13 +945,16 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
if (reset_background)
{
/* Copy foreground filter to background filter */
for (i=0;i<N*M;i++)
for (i=0;i<N*M*C*K;i++)
st->W[i] = SHL32(EXTEND32(st->foreground[i]),16);
/* We also need to copy the output so as to get correct adaptation */
for (i=0;i<st->frame_size;i++)
st->y[i+st->frame_size] = st->e[i+st->frame_size];
for (i=0;i<st->frame_size;i++)
st->e[i] = SUB16(st->input[i], st->y[i+st->frame_size]);
for (chan = 0; chan < C; chan++)
{
for (i=0;i<st->frame_size;i++)
st->y[chan*N+i+st->frame_size] = st->e[chan*N+i+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 = Sff;
st->Davg1 = st->Davg2 = 0;
st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
@ -868,50 +962,60 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
}
#endif
/* Compute error signal (for the output with de-emphasis) */
for (i=0;i<st->frame_size;i++)
Sey = Syy = Sdd = 0;
for (chan = 0; chan < C; chan++)
{
spx_word32_t tmp_out;
#ifdef TWO_PATH
tmp_out = SUB32(EXTEND32(st->input[i]), EXTEND32(st->e[i+st->frame_size]));
#else
tmp_out = SUB32(EXTEND32(st->input[i]), EXTEND32(st->y[i+st->frame_size]));
#endif
/* Saturation */
if (tmp_out>32767)
tmp_out = 32767;
else if (tmp_out<-32768)
tmp_out = -32768;
tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(st->preemph, st->memE)));
/* This is an arbitrary test for saturation in the microphone signal */
if (in[i] <= -32000 || in[i] >= 32000)
/* Compute error signal (for the output with de-emphasis) */
for (i=0;i<st->frame_size;i++)
{
tmp_out = 0;
spx_word32_t tmp_out;
#ifdef TWO_PATH
tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->e[chan*N+i+st->frame_size]));
#else
tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->y[chan*N+i+st->frame_size]));
#endif
tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(st->preemph, st->memE[chan])));
/* This is an arbitrary test for saturation in the microphone signal */
if (in[i*C+chan] <= -32000 || in[i*C+chan] >= 32000)
{
if (st->saturated == 0)
st->saturated = 1;
}
out[i*C+chan] = WORD2INT(tmp_out);
st->memE[chan] = tmp_out;
}
out[i] = (spx_int16_t)tmp_out;
st->memE = tmp_out;
}
#ifdef DUMP_ECHO_CANCEL_DATA
dump_audio(in, far_end, out, st->frame_size);
dump_audio(in, far_end, out, st->frame_size);
#endif
/* Compute error signal (filter update version) */
for (i=0;i<st->frame_size;i++)
{
st->e[i+st->frame_size] = st->e[i];
st->e[i] = 0;
/* Compute error signal (filter update version) */
for (i=0;i<st->frame_size;i++)
{
st->e[chan*N+i+st->frame_size] = st->e[chan*N+i];
st->e[chan*N+i] = 0;
}
/* Compute a bunch of correlations */
/* FIXME: bad merge */
Sey += mdf_inner_prod(st->e+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size);
Syy += mdf_inner_prod(st->y+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size);
Sdd += mdf_inner_prod(st->input+chan*st->frame_size, st->input+chan*st->frame_size, st->frame_size);
/* Convert error to frequency domain */
spx_fft(st->fft_table, st->e+chan*N, st->E+chan*N);
for (i=0;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);
}
/* Compute a bunch of correlations */
Sey = mdf_inner_prod(st->e+st->frame_size, st->y+st->frame_size, st->frame_size);
Syy = mdf_inner_prod(st->y+st->frame_size, st->y+st->frame_size, st->frame_size);
Sdd = mdf_inner_prod(st->input, st->input, st->frame_size);
/*printf ("%f %f %f %f\n", Sff, See, Syy, Sdd, st->update_cond);*/
/* Do some sanity check */
if (!(Syy>=0 && Sxx>=0 && See >= 0)
#ifndef FIXED_POINT
@ -921,7 +1025,7 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
{
/* Things have gone really bad */
st->screwed_up += 50;
for (i=0;i<st->frame_size;i++)
for (i=0;i<st->frame_size*C;i++)
out[i] = 0;
} else if (SHR32(Sff, 2) > ADD32(Sdd, SHR32(MULT16_16(N, 10000),6)))
{
@ -941,35 +1045,16 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
/* Add a small noise floor to make sure not to have problems when dividing */
See = MAX32(See, SHR32(MULT16_16(N, 100),6));
/* Convert error to frequency domain */
spx_fft(st->fft_table, st->e, st->E);
for (i=0;i<st->frame_size;i++)
st->y[i] = 0;
spx_fft(st->fft_table, st->y, st->Y);
for (speak = 0; speak < K; speak++)
{
Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size);
power_spectrum_accum(st->X+speak*N, st->Xf, N);
}
/* Compute power spectrum of far end (X), error (E) and filter response (Y) */
power_spectrum(st->E, st->Rf, N);
power_spectrum(st->Y, st->Yf, N);
power_spectrum(st->X, st->Xf, N);
/* Smooth far end energy estimate over time */
for (j=0;j<=st->frame_size;j++)
st->power[j] = MULT16_32_Q15(ss_1,st->power[j]) + 1 + MULT16_32_Q15(ss,st->Xf[j]);
/* Enable this to compute the power based only on the tail (would need to compute more
efficiently to make this really useful */
if (0)
{
float scale2 = .5f/M;
for (j=0;j<=st->frame_size;j++)
st->power[j] = 100;
for (i=0;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 */
for (j=st->frame_size;j>=0;j--)
@ -987,7 +1072,7 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
st->Yh[j] = (1-st->spec_average)*st->Yh[j] + st->spec_average*st->Yf[j];
#endif
}
Pyy = FLOAT_SQRT(Pyy);
Pey = FLOAT_DIVU(Pey,Pyy);
@ -1015,7 +1100,7 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
else
st->leak_estimate = SHL16(st->leak_estimate,1);
/*printf ("%f\n", st->leak_estimate);*/
/* Compute Residual to Error Ratio */
#ifdef FIXED_POINT
tmp32 = MULT16_32_Q15(st->leak_estimate,Syy);
@ -1071,7 +1156,7 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
/* Temporary adaption rate if filter is not yet adapted enough */
spx_word16_t adapt_rate=0;
if (Sxx > SHR32(MULT16_16(N, 1000),6))
if (Sxx > SHR32(MULT16_16(N, 1000),6))
{
tmp32 = MULT16_32_Q15(QCONST16(.25f, 15), Sxx);
#ifdef FIXED_POINT
@ -1091,12 +1176,12 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
st->sum_adapt = ADD32(st->sum_adapt,adapt_rate);
}
/* Save residual echo so it can be used by the nonlinear processor */
/* FIXME: MC conversion required */
for (i=0;i<st->frame_size;i++)
st->last_y[i] = st->last_y[st->frame_size+i];
if (st->adapted)
{
/* If the filter is adapted, take the filtered echo */
for (i=0;i<st->frame_size;i++)
st->last_y[i] = st->last_y[st->frame_size+i];
for (i=0;i<st->frame_size;i++)
st->last_y[st->frame_size+i] = in[i]-out[i];
} else {
@ -1113,17 +1198,17 @@ void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *residual_echo, in
int i;
spx_word16_t leak2;
int N;
N = st->window_size;
/* Apply hanning window (should pre-compute it)*/
for (i=0;i<N;i++)
st->y[i] = MULT16_16_Q15(st->window[i],st->last_y[i]);
/* Compute power spectrum of the echo */
spx_fft(st->fft_table, st->y, st->Y);
power_spectrum(st->Y, residual_echo, N);
#ifdef FIXED_POINT
if (st->leak_estimate > 16383)
leak2 = 32767;
@ -1138,14 +1223,14 @@ void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *residual_echo, in
/* Estimate residual echo */
for (i=0;i<=st->frame_size;i++)
residual_echo[i] = (spx_int32_t)MULT16_32_Q15(leak2,residual_echo[i]);
}
int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr)
EXPORT int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr)
{
switch(request)
{
case SPEEX_ECHO_GET_FRAME_SIZE:
(*(int*)ptr) = st->frame_size;
break;
@ -1169,6 +1254,29 @@ int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr)
case SPEEX_ECHO_GET_SAMPLING_RATE:
(*(int*)ptr) = st->sampling_rate;
break;
case SPEEX_ECHO_GET_IMPULSE_RESPONSE_SIZE:
/*FIXME: Implement this for multiple channels */
*((spx_int32_t *)ptr) = st->M * st->frame_size;
break;
case SPEEX_ECHO_GET_IMPULSE_RESPONSE:
{
int M = st->M, N = st->window_size, n = st->frame_size, i, j;
spx_int32_t *filt = (spx_int32_t *) ptr;
for(j=0;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:
speex_warning_int("Unknown speex_echo_ctl request: ", request);
return -1;

View file

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

View file

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

View file

@ -1,6 +1,6 @@
/* Copyright (C) 2003 Epic Games (written by Jean-Marc Valin)
Copyright (C) 2004-2006 Epic Games
Copyright (C) 2004-2006 Epic Games
File: preprocess.c
Preprocessor with denoising based on the algorithm by Ephraim and Malah
@ -34,24 +34,24 @@
/*
Recommended papers:
Y. Ephraim and D. Malah, "Speech enhancement using minimum mean-square error
short-time spectral amplitude estimator". IEEE Transactions on Acoustics,
short-time spectral amplitude estimator". IEEE Transactions on Acoustics,
Speech and Signal Processing, vol. ASSP-32, no. 6, pp. 1109-1121, 1984.
Y. Ephraim and D. Malah, "Speech enhancement using minimum mean-square error
log-spectral amplitude estimator". IEEE Transactions on Acoustics, Speech and
log-spectral amplitude estimator". IEEE Transactions on Acoustics, Speech and
Signal Processing, vol. ASSP-33, no. 2, pp. 443-445, 1985.
I. Cohen and B. Berdugo, "Speech enhancement for non-stationary noise environments".
Signal Processing, vol. 81, no. 2, pp. 2403-2418, 2001.
Stefan Gustafsson, Rainer Martin, Peter Jax, and Peter Vary. "A psychoacoustic
approach to combined acoustic echo cancellation and noise reduction". IEEE
Stefan Gustafsson, Rainer Martin, Peter Jax, and Peter Vary. "A psychoacoustic
approach to combined acoustic echo cancellation and noise reduction". IEEE
Transactions on Speech and Audio Processing, 2002.
J.-M. Valin, J. Rouat, and F. Michaud, "Microphone array post-filter for separation
of simultaneous non-stationary sources". In Proceedings IEEE International
of simultaneous non-stationary sources". In Proceedings IEEE International
Conference on Acoustics, Speech, and Signal Processing, 2004.
*/
@ -75,7 +75,7 @@
#define LOUDNESS_EXP 5.f
#define AMP_SCALE .001f
#define AMP_SCALE_1 1000.f
#define NB_BANDS 24
#define SPEECH_PROB_START_DEFAULT QCONST16(0.35f,15)
@ -117,7 +117,7 @@ static inline spx_word16_t DIV32_16_Q8(spx_word32_t a, spx_word32_t b)
a = SHL32(a,8);
return PDIV32_16(a,b);
}
}
static inline spx_word16_t DIV32_16_Q15(spx_word32_t a, spx_word32_t b)
{
@ -185,7 +185,7 @@ struct SpeexPreprocessState_ {
int sampling_rate; /**< Sampling rate of the input/output */
int nbands;
FilterBank *bank;
/* Parameters */
int denoise_enabled;
int vad_enabled;
@ -198,7 +198,9 @@ struct SpeexPreprocessState_ {
int echo_suppress;
int echo_suppress_active;
SpeexEchoState *echo_state;
spx_word16_t speech_prob; /**< Probability last frame was speech */
/* DSP-related arrays */
spx_word16_t *frame; /**< Processing frame (2*ps_size) */
spx_word16_t *ft; /**< Processing frame in freq domain (2*ps_size) */
@ -234,7 +236,6 @@ struct SpeexPreprocessState_ {
float *loudness_weight; /**< Perceptual loudness curve */
float loudness; /**< Loudness estimate */
float agc_gain; /**< Current AGC gain */
int nb_loudness_adapt; /**< Number of frames used for loudness adaptation so far */
float max_gain; /**< Maximum gain allowed */
float max_increase_step; /**< Maximum increase in gain from one frame to another */
float max_decrease_step; /**< Maximum decrease in gain from one frame to another */
@ -259,7 +260,7 @@ static void conj_window(spx_word16_t *w, int len)
spx_word16_t tmp;
#ifdef FIXED_POINT
spx_word16_t x = DIV32_16(MULT16_16(32767,i),len);
#else
#else
spx_word16_t x = DIV32_16(MULT16_16(QCONST16(4.f,13),i),len);
#endif
int inv=0;
@ -284,10 +285,10 @@ static void conj_window(spx_word16_t *w, int len)
}
}
#ifdef FIXED_POINT
/* This function approximates the gain function
y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x)
/* This function approximates the gain function
y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x)
which multiplied by xi/(1+xi) is the optimal gain
in the loudness domain ( sqrt[amplitude] )
Input in Q11 format, output in Q15
@ -320,7 +321,7 @@ static inline spx_word16_t qcurve(spx_word16_t x)
static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, spx_word32_t *noise, spx_word32_t *echo, spx_word16_t *gain_floor, int len)
{
int i;
if (noise_suppress > effective_echo_suppress)
{
spx_word16_t noise_gain, gain_ratio;
@ -346,8 +347,8 @@ static void compute_gain_floor(int noise_suppress, int effective_echo_suppress,
}
#else
/* This function approximates the gain function
y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x)
/* This function approximates the gain function
y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x)
which multiplied by xi/(1+xi) is the optimal gain
in the loudness domain ( sqrt[amplitude] )
*/
@ -391,7 +392,7 @@ static void compute_gain_floor(int noise_suppress, int effective_echo_suppress,
}
#endif
SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_rate)
EXPORT SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_rate)
{
int i;
int N, N3, N4, M;
@ -413,8 +414,8 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r
break;
}
}
if (st->ps_size < 3*st->frame_size/4)
st->ps_size = st->ps_size * 3 / 2;
#else
@ -424,7 +425,7 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r
N = st->ps_size;
N3 = 2*N - st->frame_size;
N4 = st->frame_size - N3;
st->sampling_rate = sampling_rate;
st->denoise_enabled = 1;
st->vad_enabled = 0;
@ -439,15 +440,15 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r
st->speech_prob_continue = SPEECH_PROB_CONTINUE_DEFAULT;
st->echo_state = NULL;
st->nbands = NB_BANDS;
M = st->nbands;
st->bank = filterbank_new(M, sampling_rate, N, 1);
st->frame = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t));
st->window = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t));
st->ft = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t));
st->ps = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t));
st->noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t));
st->echo_noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t));
@ -460,19 +461,19 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r
st->gain2 = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t));
st->gain_floor = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t));
st->zeta = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t));
st->S = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t));
st->Smin = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t));
st->Stmp = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t));
st->update_prob = (int*)speex_alloc(N*sizeof(int));
st->inbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t));
st->outbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t));
conj_window(st->window, 2*N3);
for (i=2*N3;i<2*st->ps_size;i++)
st->window[i]=Q15_ONE;
if (N4>0)
{
for (i=N3-1;i>=0;i--)
@ -514,7 +515,6 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r
/*st->loudness = pow(AMP_SCALE*st->agc_level,LOUDNESS_EXP);*/
st->loudness = 1e-15;
st->agc_gain = 1;
st->nb_loudness_adapt = 0;
st->max_gain = 30;
st->max_increase_step = exp(0.11513f * 12.*st->frame_size / st->sampling_rate);
st->max_decrease_step = exp(-0.11513f * 40.*st->frame_size / st->sampling_rate);
@ -530,7 +530,7 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r
return st;
}
void speex_preprocess_state_destroy(SpeexPreprocessState *st)
EXPORT void speex_preprocess_state_destroy(SpeexPreprocessState *st)
{
speex_free(st->frame);
speex_free(st->ft);
@ -573,7 +573,7 @@ static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx
float target_gain;
float loudness=1.f;
float rate;
for (i=2;i<N;i++)
{
loudness += 2.f*N*st->ps[i]* st->loudness_weight[i];
@ -583,7 +583,6 @@ static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx
loudness*2 > pow(st->loudness, 1.0/LOUDNESS_EXP))*/
if (Pframe>.3f)
{
st->nb_loudness_adapt++;
/*rate=2.0f*Pframe*Pframe/(1+st->nb_loudness_adapt);*/
rate = .03*Pframe*Pframe;
st->loudness = (1-rate)*st->loudness + (rate)*pow(AMP_SCALE*loudness, LOUDNESS_EXP);
@ -592,7 +591,7 @@ static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx
st->init_max *= 1.f + .1f*Pframe*Pframe;
}
/*printf ("%f %f %f %f\n", Pframe, loudness, pow(st->loudness, 1.0f/LOUDNESS_EXP), st->loudness2);*/
target_gain = AMP_SCALE*st->agc_level*pow(st->loudness/(1e-4+st->loudness_accum), -1.0f/LOUDNESS_EXP);
if ((Pframe>.5 && st->nb_adapt > 20) || target_gain < st->agc_gain)
@ -605,11 +604,11 @@ static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx
target_gain = st->max_gain;
if (target_gain > st->init_max)
target_gain = st->init_max;
st->agc_gain = target_gain;
}
/*fprintf (stderr, "%f %f %f\n", loudness, (float)AMP_SCALE_1*pow(st->loudness, 1.0f/LOUDNESS_EXP), st->agc_gain);*/
for (i=0;i<2*N;i++)
ft[i] *= st->agc_gain;
st->prev_loudness = loudness;
@ -629,7 +628,7 @@ static void preprocess_analysis(SpeexPreprocessState *st, spx_int16_t *x)
st->frame[i]=st->inbuf[i];
for (i=0;i<st->frame_size;i++)
st->frame[N3+i]=x[i];
/* Update inbuf */
for (i=0;i<N3;i++)
st->inbuf[i]=x[N4+i];
@ -648,10 +647,10 @@ static void preprocess_analysis(SpeexPreprocessState *st, spx_int16_t *x)
st->frame[i] = SHL16(st->frame[i], st->frame_shift);
}
#endif
/* Perform FFT */
spx_fft(st->fft_lookup, st->frame, st->ft);
/* Power spectrum */
ps[0]=MULT16_16(st->ft[0],st->ft[0]);
for (i=1;i<N;i++)
@ -669,11 +668,11 @@ static void update_noise_prob(SpeexPreprocessState *st)
int N = st->ps_size;
for (i=1;i<N-1;i++)
st->S[i] = MULT16_32_Q15(QCONST16(.8f,15),st->S[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i-1])
st->S[i] = MULT16_32_Q15(QCONST16(.8f,15),st->S[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i-1])
+ MULT16_32_Q15(QCONST16(.1f,15),st->ps[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i+1]);
st->S[0] = MULT16_32_Q15(QCONST16(.8f,15),st->S[0]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[0]);
st->S[N-1] = MULT16_32_Q15(QCONST16(.8f,15),st->S[N-1]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[N-1]);
if (st->nb_adapt==1)
{
for (i=0;i<N;i++)
@ -700,12 +699,12 @@ static void update_noise_prob(SpeexPreprocessState *st)
for (i=0;i<N;i++)
{
st->Smin[i] = MIN32(st->Smin[i], st->S[i]);
st->Stmp[i] = MIN32(st->Stmp[i], st->S[i]);
st->Stmp[i] = MIN32(st->Stmp[i], st->S[i]);
}
}
for (i=0;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;
else
st->update_prob[i] = 0;
@ -719,12 +718,12 @@ static void update_noise_prob(SpeexPreprocessState *st)
void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len);
int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo)
EXPORT int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo)
{
return speex_preprocess_run(st, x);
}
int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
EXPORT int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
{
int i;
int M;
@ -736,12 +735,12 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
spx_word16_t Pframe;
spx_word16_t beta, beta_1;
spx_word16_t effective_echo_suppress;
st->nb_adapt++;
if (st->nb_adapt>20000)
st->nb_adapt = 20000;
st->min_count++;
beta = MAX16(QCONST16(.03,15),DIV32_16(Q15_ONE,st->nb_adapt));
beta_1 = Q15_ONE-beta;
M = st->nbands;
@ -775,7 +774,7 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
st->update_prob[i] = 0;
}
*/
/* Update the noise estimate for the frequencies where it can be */
for (i=0;i<N;i++)
{
@ -793,17 +792,17 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
for (i=0;i<N+M;i++)
{
spx_word16_t gamma;
/* Total noise estimate including residual echo and reverberation */
spx_word32_t tot_noise = ADD32(ADD32(ADD32(EXTEND32(1), PSHR32(st->noise[i],NOISE_SHIFT)) , st->echo_noise[i]) , st->reverb_estimate[i]);
/* A posteriori SNR = ps/noise - 1*/
st->post[i] = SUB16(DIV32_16_Q8(ps[i],tot_noise), QCONST16(1.f,SNR_SHIFT));
st->post[i]=MIN16(st->post[i], QCONST16(100.f,SNR_SHIFT));
/* Computing update gamma = .1 + .9*(old/(old+noise))^2 */
gamma = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.89f,15),SQR16_Q15(DIV32_16_Q15(st->old_ps[i],ADD32(st->old_ps[i],tot_noise))));
/* A priori SNR update = gamma*max(0,post) + (1-gamma)*old/noise */
st->prior[i] = EXTRACT16(PSHR32(ADD32(MULT16_16(gamma,MAX16(0,st->post[i])), MULT16_16(Q15_ONE-gamma,DIV32_16_Q8(st->old_ps[i],tot_noise))), 15));
st->prior[i]=MIN16(st->prior[i], QCONST16(100.f,SNR_SHIFT));
@ -824,13 +823,13 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
for (i=N;i<N+M;i++)
Zframe = ADD32(Zframe, EXTEND32(st->zeta[i]));
Pframe = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.899f,15),qcurve(DIV32_16(Zframe,st->nbands)));
effective_echo_suppress = EXTRACT16(PSHR32(ADD32(MULT16_16(SUB16(Q15_ONE,Pframe), st->echo_suppress), MULT16_16(Pframe, st->echo_suppress_active)),15));
compute_gain_floor(st->noise_suppress, effective_echo_suppress, st->noise+N, st->echo_noise+N, st->gain_floor+N, M);
/* Compute Ephraim & Malah gain speech probability of presence for each critical band (Bark scale)
Technically this is actually wrong because the EM gaim assumes a slightly different probability
/* Compute Ephraim & Malah gain speech probability of presence for each critical band (Bark scale)
Technically this is actually wrong because the EM gaim assumes a slightly different probability
distribution */
for (i=N;i<N+M;i++)
{
@ -847,7 +846,7 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
#ifdef FIXED_POINT
spx_word16_t tmp;
#endif
prior_ratio = PDIV32_16(SHL32(EXTEND32(st->prior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT)));
theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT));
@ -872,12 +871,12 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
/* Convert the EM gains and speech prob to linear frequency */
filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2);
filterbank_compute_psd16(st->bank,st->gain+N, st->gain);
/* Use 1 for linear gain resolution (best) or 0 for Bark gain resolution (faster) */
if (1)
{
filterbank_compute_psd16(st->bank,st->gain_floor+N, st->gain_floor);
/* Compute gain according to the Ephraim-Malah algorithm -- linear frequency */
for (i=0;i<N;i++)
{
@ -887,7 +886,7 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
spx_word16_t tmp;
spx_word16_t p;
spx_word16_t g;
/* Wiener filter gain */
prior_ratio = PDIV32_16(SHL32(EXTEND32(st->prior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT)));
theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT));
@ -898,22 +897,22 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
g = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM)));
/* Interpolated speech probability of presence */
p = st->gain2[i];
/* Constrain the gain to be close to the Bark scale gain */
if (MULT16_16_Q15(QCONST16(.333f,15),g) > st->gain[i])
g = MULT16_16(3,st->gain[i]);
st->gain[i] = g;
/* Save old power spectrum */
st->old_ps[i] = MULT16_32_P15(QCONST16(.2f,15),st->old_ps[i]) + MULT16_32_P15(MULT16_16_P15(QCONST16(.8f,15),SQR16_Q15(st->gain[i])),ps[i]);
/* Apply gain floor */
if (st->gain[i] < st->gain_floor[i])
st->gain[i] = st->gain_floor[i];
/* Exponential decay model for reverberation (unused) */
/*st->reverb_estimate[i] = st->reverb_decay*st->reverb_estimate[i] + st->reverb_decay*st->reverb_level*st->gain[i]*st->gain[i]*st->ps[i];*/
/* Take into account speech probability of presence (loudness domain MMSE estimator) */
/* gain2 = [p*sqrt(gain)+(1-p)*sqrt(gain _floor) ]^2 */
tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(st->gain[i]),15))) + MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(st->gain_floor[i]),15)));
@ -927,20 +926,20 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
{
spx_word16_t tmp;
spx_word16_t p = st->gain2[i];
st->gain[i] = MAX16(st->gain[i], st->gain_floor[i]);
st->gain[i] = MAX16(st->gain[i], st->gain_floor[i]);
tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(st->gain[i]),15))) + MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(st->gain_floor[i]),15)));
st->gain2[i]=SQR16_Q15(tmp);
}
filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2);
}
/* If noise suppression is off, don't apply the gain (but then why call this in the first place!) */
if (!st->denoise_enabled)
{
for (i=0;i<N+M;i++)
st->gain2[i]=Q15_ONE;
}
/* Apply computed gain */
for (i=1;i<N;i++)
{
@ -949,7 +948,7 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
}
st->ft[0] = MULT16_16_P15(st->gain2[0],st->ft[0]);
st->ft[2*N-1] = MULT16_16_P15(st->gain2[N-1],st->ft[2*N-1]);
/*FIXME: This *will* not work for fixed-point */
#ifndef FIXED_POINT
if (st->agc_enabled)
@ -978,7 +977,7 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
}
}
#endif
/* Synthesis window (for WOLA) */
for (i=0;i<2*N;i++)
st->frame[i] = MULT16_16_Q15(st->frame[i], st->window[i]);
@ -988,15 +987,16 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
x[i] = st->outbuf[i] + st->frame[i];
for (i=0;i<N4;i++)
x[N3+i] = st->frame[N3+i];
/* Update outbuf */
for (i=0;i<N3;i++)
st->outbuf[i] = st->frame[st->frame_size+i];
/* FIXME: This VAD is a kludge */
st->speech_prob = Pframe;
if (st->vad_enabled)
{
if (Pframe > st->speech_prob_start || (st->was_speech && Pframe > st->speech_prob_continue))
if (st->speech_prob > st->speech_prob_start || (st->was_speech && st->speech_prob > st->speech_prob_continue))
{
st->was_speech=1;
return 1;
@ -1010,7 +1010,7 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
}
}
void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x)
EXPORT void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x)
{
int i;
int N = st->ps_size;
@ -1020,11 +1020,11 @@ void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x)
M = st->nbands;
st->min_count++;
preprocess_analysis(st, x);
update_noise_prob(st);
for (i=1;i<N-1;i++)
{
if (!st->update_prob[i] || st->ps[i] < PSHR32(st->noise[i],NOISE_SHIFT))
@ -1045,7 +1045,7 @@ void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x)
}
int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr)
EXPORT int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr)
{
int i;
SpeexPreprocessState *st;
@ -1103,7 +1103,7 @@ int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr)
case SPEEX_PREPROCESS_GET_VAD:
(*(spx_int32_t*)ptr) = st->vad_enabled;
break;
case SPEEX_PREPROCESS_SET_DEREVERB:
st->dereverb_enabled = (*(spx_int32_t*)ptr);
for (i=0;i<st->ps_size;i++)
@ -1121,7 +1121,7 @@ int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr)
/* FIXME: Re-enable when de-reverberation is actually enabled again */
/*(*(float*)ptr) = st->reverb_level;*/
break;
case SPEEX_PREPROCESS_SET_DEREVERB_DECAY:
/* FIXME: Re-enable when de-reverberation is actually enabled again */
/*st->reverb_decay = (*(float*)ptr);*/
@ -1169,17 +1169,51 @@ int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr)
st->echo_state = (SpeexEchoState*)ptr;
break;
case SPEEX_PREPROCESS_GET_ECHO_STATE:
ptr = (void*)st->echo_state;
(*(SpeexEchoState**)ptr) = (SpeexEchoState*)st->echo_state;
break;
#ifndef FIXED_POINT
case SPEEX_PREPROCESS_GET_AGC_LOUDNESS:
(*(spx_int32_t*)ptr) = pow(st->loudness, 1.0/LOUDNESS_EXP);
break;
case SPEEX_PREPROCESS_GET_AGC_GAIN:
(*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->agc_gain));
break;
#endif
case SPEEX_PREPROCESS_GET_PSD_SIZE:
case SPEEX_PREPROCESS_GET_NOISE_PSD_SIZE:
(*(spx_int32_t*)ptr) = st->ps_size;
break;
case SPEEX_PREPROCESS_GET_PSD:
for(i=0;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
default:
speex_warning_int("Unknown speex_preprocess_ctl request: ", request);
return -1;
}
return 0;
}
#ifdef FIXED_DEBUG
long long spx_mips=0;
#endif

View file

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

File diff suppressed because it is too large Load diff

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

@ -1,4 +1,4 @@
/* Copyright (C) 2002 Jean-Marc Valin
/* Copyright (C) 2002 Jean-Marc Valin
File: speex.c
Basic Speex functions
@ -6,18 +6,18 @@
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@ -49,25 +49,25 @@
#define MAX_IN_SAMPLES 640
#ifndef SPEEX_DISABLE_ENCODER
void *speex_encoder_init(const SpeexMode *mode)
EXPORT void *speex_encoder_init(const SpeexMode *mode)
{
return mode->enc_init(mode);
}
#endif
void *speex_decoder_init(const SpeexMode *mode)
EXPORT void *speex_decoder_init(const SpeexMode *mode)
{
return mode->dec_init(mode);
}
#ifndef SPEEX_DISABLE_ENCODER
void speex_encoder_destroy(void *state)
EXPORT void speex_encoder_destroy(void *state)
{
(*((SpeexMode**)state))->enc_destroy(state);
}
#endif
void speex_decoder_destroy(void *state)
EXPORT void speex_decoder_destroy(void *state)
{
(*((SpeexMode**)state))->dec_destroy(state);
}
@ -90,7 +90,7 @@ int speex_decode_native(void *state, SpeexBits *bits, spx_word16_t *out)
#ifndef SPEEX_DISABLE_ENCODER
#ifndef DISABLE_FLOAT_API
int speex_encode(void *state, float *in, SpeexBits *bits)
EXPORT int speex_encode(void *state, float *in, SpeexBits *bits)
{
int i;
spx_int32_t N;
@ -109,7 +109,7 @@ int speex_encode(void *state, float *in, SpeexBits *bits)
}
#endif /* #ifndef DISABLE_FLOAT_API */
int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits)
EXPORT int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits)
{
SpeexMode *mode;
mode = *(SpeexMode**)state;
@ -118,7 +118,7 @@ int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits)
#endif /* SPEEX_DISABLE_ENCODER */
#ifndef DISABLE_FLOAT_API
int speex_decode(void *state, SpeexBits *bits, float *out)
EXPORT int speex_decode(void *state, SpeexBits *bits, float *out)
{
int i, ret;
spx_int32_t N;
@ -131,7 +131,7 @@ int speex_decode(void *state, SpeexBits *bits, float *out)
}
#endif /* #ifndef DISABLE_FLOAT_API */
int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out)
EXPORT int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out)
{
SpeexMode *mode = *(SpeexMode**)state;
return (mode)->dec(state, bits, out);
@ -139,12 +139,12 @@ int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out)
#else
int speex_encode(void *state, float *in, SpeexBits *bits)
EXPORT int speex_encode(void *state, float *in, SpeexBits *bits)
{
return (*((SpeexMode**)state))->enc(state, in, bits);
}
int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits)
EXPORT int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits)
{
int i;
spx_int32_t N;
@ -155,12 +155,12 @@ int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits)
return (*((SpeexMode**)state))->enc(state, float_in, bits);
}
int speex_decode(void *state, SpeexBits *bits, float *out)
EXPORT int speex_decode(void *state, SpeexBits *bits, float *out)
{
return (*((SpeexMode**)state))->dec(state, bits, out);
}
int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out)
EXPORT int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out)
{
int i;
spx_int32_t N;
@ -182,13 +182,13 @@ int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out)
#endif
#ifndef SPEEX_DISABLE_ENCODER
int speex_encoder_ctl(void *state, int request, void *ptr)
EXPORT int speex_encoder_ctl(void *state, int request, void *ptr)
{
return (*((SpeexMode**)state))->enc_ctl(state, request, ptr);
}
#endif
int speex_decoder_ctl(void *state, int request, void *ptr)
EXPORT int speex_decoder_ctl(void *state, int request, void *ptr)
{
return (*((SpeexMode**)state))->dec_ctl(state, request, ptr);
}
@ -196,7 +196,7 @@ int speex_decoder_ctl(void *state, int request, void *ptr)
int nb_mode_query(const void *mode, int request, void *ptr)
{
const SpeexNBMode *m = (const SpeexNBMode*)mode;
switch (request)
{
case SPEEX_MODE_FRAME_SIZE:
@ -219,7 +219,7 @@ int nb_mode_query(const void *mode, int request, void *ptr)
int speex_lib_ctl(int request, void *ptr)
EXPORT int speex_lib_ctl(int request, void *ptr)
{
switch (request)
{

View file

@ -6,18 +6,18 @@
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@ -40,7 +40,7 @@
#include "arch.h"
#include "os_support.h"
int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *state)
EXPORT int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *state)
{
int id;
SpeexCallback *callback;
@ -65,7 +65,7 @@ int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *st
adv = 16;
else if (id<14)
adv = 32;
else
else
adv = 64;
speex_bits_advance(bits, adv);
}
@ -74,7 +74,7 @@ int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *st
#if 0
/* Rockbox: unused */
int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data)
EXPORT int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data)
{
(void)state;
spx_int32_t m;
@ -83,7 +83,7 @@ int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data)
return 0;
}
int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data)
EXPORT int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data)
{
(void)state;
spx_int32_t m;
@ -92,7 +92,7 @@ int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data)
return 0;
}
int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data)
EXPORT int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data)
{
(void)state;
spx_int32_t m;
@ -103,7 +103,7 @@ int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data
#endif
#ifndef DISABLE_VBR
int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data)
EXPORT int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data)
{
(void)state;
spx_int32_t vbr;
@ -115,7 +115,7 @@ int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data)
#if 0
/* Rockbox: unused */
int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data)
EXPORT int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data)
{
(void)state;
spx_int32_t enh;
@ -126,7 +126,7 @@ int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data)
#endif
#ifndef DISABLE_VBR
int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data)
EXPORT int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data)
{
(void)state;
float qual;
@ -138,7 +138,7 @@ int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *da
#if 0
/* Rockbox: unused */
int speex_std_char_handler(SpeexBits *bits, void *state, void *data)
EXPORT int speex_std_char_handler(SpeexBits *bits, void *state, void *data)
{
(void)state;
unsigned char ch;
@ -150,7 +150,7 @@ int speex_std_char_handler(SpeexBits *bits, void *state, void *data)
#endif
/* Default handler for user callbacks: skip it */
int speex_default_user_handler(SpeexBits *bits, void *state, void *data)
EXPORT int speex_default_user_handler(SpeexBits *bits, void *state, void *data)
{
(void)state;
(void)data;

View file

@ -1,22 +1,22 @@
/* Copyright (C) 2002 Jean-Marc Valin
/* Copyright (C) 2002 Jean-Marc Valin
File: speex_header.c
Describes the Speex header
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@ -47,7 +47,7 @@
/** Convert little endian */
static inline spx_int32_t le_int(spx_int32_t i)
{
#ifdef ROCKBOX
#ifdef ROCKBOX
return letoh32(i);
#elif !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) )
spx_uint32_t ui, ret;
@ -86,7 +86,7 @@ typedef struct SpeexHeader {
*/
#ifndef SPEEX_DISABLE_ENCODER
void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const SpeexMode *m)
EXPORT void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const SpeexMode *m)
{
int i;
const char *h="Speex ";
@ -101,10 +101,10 @@ void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const Spe
header->speex_version[i]=SPEEX_VERSION[i];
for (;i<SPEEX_HEADER_VERSION_LENGTH;i++)
header->speex_version[i]=0;
header->speex_version_id = 1;
header->header_size = sizeof(SpeexHeader);
header->rate = rate;
header->mode = m->modeID;
header->mode_bitstream_version = m->bitstream_version;
@ -114,20 +114,20 @@ void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const Spe
header->bitrate = -1;
speex_mode_query(m, SPEEX_MODE_FRAME_SIZE, &header->frame_size);
header->vbr = 0;
header->frames_per_packet = 0;
header->extra_headers = 0;
header->reserved1 = 0;
header->reserved2 = 0;
}
char *speex_header_to_packet(SpeexHeader *header, int *size)
EXPORT char *speex_header_to_packet(SpeexHeader *header, int *size)
{
SpeexHeader *le_header;
le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader));
SPEEX_COPY(le_header, header, 1);
/*Make sure everything is now little-endian*/
ENDIAN_SWITCH(le_header->speex_version_id);
ENDIAN_SWITCH(le_header->header_size);
@ -147,7 +147,7 @@ char *speex_header_to_packet(SpeexHeader *header, int *size)
#endif /* SPEEX_DISABLE_ENCODER */
static SpeexHeader global_le_header; /* Avoid malloc */
SpeexHeader *speex_packet_to_header(char *packet, int size)
EXPORT SpeexHeader *speex_packet_to_header(char *packet, int size)
{
int i;
SpeexHeader *le_header = &global_le_header;
@ -158,18 +158,18 @@ SpeexHeader *speex_packet_to_header(char *packet, int size)
speex_notify("This doesn't look like a Speex file");
return NULL;
}
/*FIXME: Do we allow larger headers?*/
if (size < (int)sizeof(SpeexHeader))
{
speex_notify("Speex header too small");
return NULL;
}
/* le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader)); */
SPEEX_COPY(le_header, (SpeexHeader*)packet, 1);
/*Make sure everything is converted correctly from little-endian*/
ENDIAN_SWITCH(le_header->speex_version_id);
ENDIAN_SWITCH(le_header->header_size);
@ -183,6 +183,25 @@ SpeexHeader *speex_packet_to_header(char *packet, int size)
ENDIAN_SWITCH(le_header->frames_per_packet);
ENDIAN_SWITCH(le_header->extra_headers);
if (le_header->mode >= SPEEX_NB_MODES || le_header->mode < 0)
{
speex_notify("Invalid mode specified in Speex header");
speex_free (le_header);
return NULL;
}
if (le_header->nb_channels>2)
le_header->nb_channels = 2;
if (le_header->nb_channels<1)
le_header->nb_channels = 1;
return le_header;
}
#if 0 /* Unused by rockbox */
EXPORT void speex_header_free(void *ptr)
{
speex_free(ptr);
}
#endif

View file

@ -1,21 +1,21 @@
/* Copyright (C) 2002 Jean-Marc Valin
/* Copyright (C) 2002 Jean-Marc Valin
File: stereo.c
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@ -71,11 +71,11 @@ static const spx_word16_t balance_bounds[31] = {18, 23, 30, 38, 49, 63, 81, 104
#ifdef FIXED_POINT
#define COMPATIBILITY_HACK(s) do {if ((s)->reserved1 != 0xdeadbeef) speex_stereo_state_reset((SpeexStereoState*)s); } while (0);
#else
#define COMPATIBILITY_HACK(s)
#define COMPATIBILITY_HACK(s)
#endif
static SpeexStereoState global_stereo_state;
SpeexStereoState *speex_stereo_state_init()
EXPORT SpeexStereoState *speex_stereo_state_init()
{
/* SpeexStereoState *stereo = speex_alloc(sizeof(SpeexStereoState)); */
SpeexStereoState *stereo = &global_stereo_state;
@ -83,7 +83,7 @@ SpeexStereoState *speex_stereo_state_init()
return stereo;
}
void speex_stereo_state_reset(SpeexStereoState *_stereo)
EXPORT void speex_stereo_state_reset(SpeexStereoState *_stereo)
{
RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo;
#ifdef FIXED_POINT
@ -100,10 +100,10 @@ void speex_stereo_state_reset(SpeexStereoState *_stereo)
stereo->smooth_right = 1.f;
stereo->reserved1 = 0;
stereo->reserved2 = 0;
#endif
#endif
}
void speex_stereo_state_destroy(SpeexStereoState *stereo)
EXPORT void speex_stereo_state_destroy(SpeexStereoState *stereo)
{
(void)stereo;
/* speex_free(stereo); */
@ -111,7 +111,7 @@ void speex_stereo_state_destroy(SpeexStereoState *stereo)
#ifndef SPEEX_DISABLE_ENCODER
#ifndef DISABLE_FLOAT_API
void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits)
EXPORT void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits)
{
int i, tmp;
float e_left=0, e_right=0, e_tot=0;
@ -129,7 +129,7 @@ void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits)
/*Quantization*/
speex_bits_pack(bits, 14, 5);
speex_bits_pack(bits, SPEEX_INBAND_STEREO, 4);
balance=4*log(balance);
/*Pack sign*/
@ -140,16 +140,16 @@ void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits)
balance=floor(.5+fabs(balance));
if (balance>30)
balance=31;
speex_bits_pack(bits, (int)balance, 5);
/* FIXME: this is a hack */
tmp=scal_quant(e_ratio*Q15_ONE, e_ratio_quant_bounds, 4);
speex_bits_pack(bits, tmp, 2);
}
#endif /* #ifndef DISABLE_FLOAT_API */
void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits)
EXPORT void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits)
{
int i, tmp;
spx_word32_t e_left=0, e_right=0, e_tot=0;
@ -159,7 +159,7 @@ void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits)
#ifdef FIXED_POINT
int shift;
#endif
/* In band marker */
speex_bits_pack(bits, 14, 5);
/* Stereo marker */
@ -204,9 +204,9 @@ void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits)
if (balance_id>30)
balance_id=31;
#endif
speex_bits_pack(bits, balance_id, 5);
/* "coherence" quantisation */
#ifdef FIXED_POINT
shift = spx_ilog2(e_tot);
@ -217,7 +217,7 @@ void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits)
#else
e_ratio = e_tot/(1.+e_left+e_right);
#endif
tmp=scal_quant(EXTRACT16(e_ratio), e_ratio_quant_bounds, 4);
/*fprintf (stderr, "%d %d %d %d\n", largest, smallest, balance_id, e_ratio);*/
speex_bits_pack(bits, tmp, 2);
@ -225,18 +225,18 @@ void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits)
#endif /* SPEEX_DISABLE_ENCODER */
#ifndef DISABLE_FLOAT_API
void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *_stereo)
EXPORT void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *_stereo)
{
int i;
spx_word32_t balance;
spx_word16_t e_left, e_right, e_ratio;
RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo;
COMPATIBILITY_HACK(stereo);
balance=stereo->balance;
e_ratio=stereo->e_ratio;
/* These two are Q14, with max value just below 2. */
e_right = DIV32(QCONST32(1., 22), spx_sqrt(MULT16_32_Q15(e_ratio, ADD32(QCONST32(1., 16), balance))));
e_left = SHR32(MULT16_16(spx_sqrt(balance), e_right), 8);
@ -252,7 +252,7 @@ void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *_stereo)
}
#endif /* #ifndef DISABLE_FLOAT_API */
void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState *_stereo)
EXPORT void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState *_stereo)
{
int i;
spx_word32_t balance;
@ -260,10 +260,10 @@ void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState
RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo;
/* COMPATIBILITY_HACK(stereo); */
balance=stereo->balance;
e_ratio=stereo->e_ratio;
/* These two are Q14, with max value just below 2. */
e_right = DIV32(QCONST32(1., 22), spx_sqrt(MULT16_32_Q15(e_ratio, ADD32(QCONST32(1., 16), balance))));
e_left = SHR32(MULT16_16(spx_sqrt(balance), e_right), 8);
@ -278,7 +278,7 @@ void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState
}
}
int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data)
EXPORT int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data)
{
(void)state;
RealSpeexStereoState *stereo;
@ -286,7 +286,7 @@ int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data)
int tmp;
stereo = (RealSpeexStereoState*)data;
/* COMPATIBILITY_HACK(stereo); */
if (speex_bits_unpack_unsigned(bits, 1))