1
0
Fork 0
forked from len0rd/rockbox

codecs: Update libspeex from 1.2beta3 to 1.2rc1

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

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 */
@ -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
@ -184,3 +188,7 @@
#define RELEASE 1
/* We don't care */
#define EXPORT
#define USE_KISS_FFT

View file

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

View file

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

View file

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

View file

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

View file

@ -75,15 +75,15 @@ TODO:
#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) */
};
@ -250,7 +250,7 @@ static spx_int16_t compute_opt_delay(JitterBuffer *jitter)
if (latest >= 0 && !penalty_taken)
{
penalty_taken = 1;
late+=2;
late+=4;
}
}
@ -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++)
@ -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,7 +365,7 @@ 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;
@ -399,6 +399,13 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
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))
{
@ -428,10 +435,6 @@ 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);*/
}
@ -459,7 +462,7 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
}
/** 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;
@ -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++)
@ -732,7 +735,7 @@ static int _jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket
}
/* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */
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,
automatically disable auto-adjustment */
@ -742,12 +745,12 @@ 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)
@ -763,7 +766,7 @@ 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)
@ -776,7 +779,7 @@ void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem)
/* Used like the ioctl function to control the jitter buffer parameters */
int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
EXPORT int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
{
int count, i;
switch(request)
@ -836,4 +839,3 @@ int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
}
return 0;
}

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2003-2006 Jean-Marc Valin
/* Copyright (C) 2003-2008 Jean-Marc Valin
File: mdf.c
Echo canceller based on the MDF algorithm (see below)
@ -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,6 +137,8 @@ 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;
@ -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;
@ -194,7 +202,7 @@ static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius,
/*printf ("%d %d %d %d %d %d\n", num[0], num[1], num[2], den[0], den[1], den[2]);*/
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");
@ -413,23 +443,23 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
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,7 +510,7 @@ 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;
@ -487,7 +519,7 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
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;
@ -495,13 +527,15 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
}
/** 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,6 +617,11 @@ 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);
@ -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;
@ -661,6 +707,9 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
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,137 +719,178 @@ 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;
st->memD[chan] = st->input[chan*st->frame_size+i];
st->input[chan*st->frame_size+i] = EXTRACT16(tmp32);
}
if (tmp32 < -32767)
{
tmp32 = -32767;
if (st->saturated == 0)
st->saturated = 1;
}
#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
@ -837,11 +927,12 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
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,47 +962,57 @@ 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 */
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);
/* 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);
}
/*printf ("%f %f %f %f\n", Sff, See, Syy, Sdd, st->update_cond);*/
@ -921,7 +1025,7 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
{
/* Things have gone really bad */
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,36 +1045,17 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
/* Add a small noise floor to make sure not to have problems when dividing */
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--)
{
@ -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 {
@ -1141,7 +1226,7 @@ void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *residual_echo, in
}
int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr)
EXPORT int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr)
{
switch(request)
{
@ -1169,6 +1254,29 @@ int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr)
case SPEEX_ECHO_GET_SAMPLING_RATE:
(*(int*)ptr) = st->sampling_rate;
break;
case SPEEX_ECHO_GET_IMPULSE_RESPONSE_SIZE:
/*FIXME: Implement this for multiple channels */
*((spx_int32_t *)ptr) = st->M * st->frame_size;
break;
case SPEEX_ECHO_GET_IMPULSE_RESPONSE:
{
int M = st->M, N = st->window_size, n = st->frame_size, i, j;
spx_int32_t *filt = (spx_int32_t *) ptr;
for(j=0;j<M;j++)
{
/*FIXME: Implement this for multiple channels */
#ifdef FIXED_POINT
for (i=0;i<N;i++)
st->wtmp2[i] = EXTRACT16(PSHR32(st->W[j*N+i],16+NORMALIZE_SCALEDOWN));
spx_ifft(st->fft_table, st->wtmp2, st->wtmp);
#else
spx_ifft(st->fft_table, &st->W[j*N], st->wtmp);
#endif
for(i=0;i<n;i++)
filt[j*n+i] = PSHR32(MULT16_16(32767,st->wtmp[i]), WEIGHT_SHIFT-NORMALIZE_SCALEDOWN);
}
}
break;
default:
speex_warning_int("Unknown speex_echo_ctl request: ", request);
return -1;

View file

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

View file

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

View file

@ -199,6 +199,8 @@ struct SpeexPreprocessState_ {
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 */
@ -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;
@ -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);
@ -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);
@ -705,7 +704,7 @@ static void update_noise_prob(SpeexPreprocessState *st)
}
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;
@ -994,9 +993,10 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x)
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;
@ -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;
@ -1169,17 +1169,51 @@ int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr)
st->echo_state = (SpeexEchoState*)ptr;
break;
case SPEEX_PREPROCESS_GET_ECHO_STATE:
ptr = (void*)st->echo_state;
(*(SpeexEchoState**)ptr) = (SpeexEchoState*)st->echo_state;
break;
#ifndef FIXED_POINT
case SPEEX_PREPROCESS_GET_AGC_LOUDNESS:
(*(spx_int32_t*)ptr) = pow(st->loudness, 1.0/LOUDNESS_EXP);
break;
case SPEEX_PREPROCESS_GET_AGC_GAIN:
(*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->agc_gain));
break;
#endif
case SPEEX_PREPROCESS_GET_PSD_SIZE:
case SPEEX_PREPROCESS_GET_NOISE_PSD_SIZE:
(*(spx_int32_t*)ptr) = st->ps_size;
break;
case SPEEX_PREPROCESS_GET_PSD:
for(i=0;i<st->ps_size;i++)
((spx_int32_t *)ptr)[i] = (spx_int32_t) st->ps[i];
break;
case SPEEX_PREPROCESS_GET_NOISE_PSD:
for(i=0;i<st->ps_size;i++)
((spx_int32_t *)ptr)[i] = (spx_int32_t) PSHR32(st->noise[i], NOISE_SHIFT);
break;
case SPEEX_PREPROCESS_GET_PROB:
(*(spx_int32_t*)ptr) = MULT16_16_Q15(st->speech_prob, 100);
break;
#ifndef FIXED_POINT
case SPEEX_PREPROCESS_SET_AGC_TARGET:
st->agc_level = (*(spx_int32_t*)ptr);
if (st->agc_level<1)
st->agc_level=1;
if (st->agc_level>32768)
st->agc_level=32768;
break;
case SPEEX_PREPROCESS_GET_AGC_TARGET:
(*(spx_int32_t*)ptr) = st->agc_level;
break;
#endif
default:
speex_warning_int("Unknown speex_preprocess_ctl request: ", request);
return -1;
}
return 0;
}
#ifdef FIXED_DEBUG
long long spx_mips=0;
#endif

View file

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

View file

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

View file

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

View file

@ -49,25 +49,25 @@
#define MAX_IN_SAMPLES 640
#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);
}
@ -219,7 +219,7 @@ int nb_mode_query(const void *mode, int request, void *ptr)
int speex_lib_ctl(int request, void *ptr)
EXPORT int speex_lib_ctl(int request, void *ptr)
{
switch (request)
{

View file

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

View file

@ -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 ";
@ -121,7 +121,7 @@ void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const Spe
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));
@ -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;
@ -183,6 +183,25 @@ SpeexHeader *speex_packet_to_header(char *packet, int size)
ENDIAN_SWITCH(le_header->frames_per_packet);
ENDIAN_SWITCH(le_header->extra_headers);
if (le_header->mode >= SPEEX_NB_MODES || le_header->mode < 0)
{
speex_notify("Invalid mode specified in Speex header");
speex_free (le_header);
return NULL;
}
if (le_header->nb_channels>2)
le_header->nb_channels = 2;
if (le_header->nb_channels<1)
le_header->nb_channels = 1;
return le_header;
}
#if 0 /* Unused by rockbox */
EXPORT void speex_header_free(void *ptr)
{
speex_free(ptr);
}
#endif

View file

@ -75,7 +75,7 @@ static const spx_word16_t balance_bounds[31] = {18, 23, 30, 38, 49, 63, 81, 104
#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
@ -103,7 +103,7 @@ void speex_stereo_state_reset(SpeexStereoState *_stereo)
#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;
@ -149,7 +149,7 @@ void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits)
}
#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;
@ -225,7 +225,7 @@ 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;
@ -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;
@ -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;