mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-14 02:27:39 -04:00
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:
parent
8ef20383b1
commit
547b6a570d
21 changed files with 1406 additions and 1001 deletions
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -235,7 +235,7 @@ typedef float spx_word32_t;
|
|||
|
||||
|
||||
#ifdef FIXED_DEBUG
|
||||
long long spx_mips=0;
|
||||
extern long long spx_mips=0;
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)))
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
128
lib/rbcodec/codecs/libspeex/resample_sse.h
Normal file
128
lib/rbcodec/codecs/libspeex/resample_sse.h
Normal 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
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue