1
0
Fork 0
forked from len0rd/rockbox

* Clean up speex.c a little.

* Sync to Speex SVN 12735 which includes some of our warnings fixes.
* Move decoder output to IRAM. Not much perfomance gain though.



git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12735 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Dan Everton 2007-03-12 11:54:07 +00:00
parent 19bba742e7
commit 879070f89e
21 changed files with 1302 additions and 561 deletions

View file

@ -1,5 +1,5 @@
Library: libspeex-1.2beta1 (SVN version 12449) Library: libspeex-1.2beta1 (SVN version 12735)
Imported: 2007-02-10 by Dan Everton Imported: 2007-03-12 by Dan Everton
This directory contains a local version of libspeex for decoding Ogg/Speex This directory contains a local version of libspeex for decoding Ogg/Speex
@ -16,7 +16,8 @@ license is described in the COPYING file in this directory.
IMPORT DETAILS IMPORT DETAILS
The .[ch] files from speex/libspeex/ and speex/include/ were imported The .[ch] files from speex/libspeex/ and speex/include/ were imported
into Rockbox. This includes the test files. into Rockbox. This includes the test files. Some hackery was done to
the include files so that they #include properly when built in Rockbox.
A simple config.h file was added to enable libspeex's fixed-point A simple config.h file was added to enable libspeex's fixed-point
integer-only mode and to specify the endianness of the target CPU. Also, integer-only mode and to specify the endianness of the target CPU. Also,
@ -26,3 +27,4 @@ Since some parts of Speex still rely on <math.h> functions, a simple
include was created to get these parts to compile. Stub functions can be include was created to get these parts to compile. Stub functions can be
found in rockbox.c in this directory. found in rockbox.c in this directory.

View file

@ -31,7 +31,6 @@ nb_celp.c
oggframing.c oggframing.c
preprocess.c preprocess.c
quant_lsp.c quant_lsp.c
resample.c
rockbox.c rockbox.c
sb_celp.c sb_celp.c
smallft.c smallft.c

View file

@ -68,6 +68,10 @@ struct kiss_fft_state{
do{ (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \ do{ (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \
(m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0) (m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0)
# define C_MUL4(m,a,b) \
do{ (m).r = PSHR32( smul((a).r,(b).r) - smul((a).i,(b).i),17 ); \
(m).i = PSHR32( smul((a).r,(b).i) + smul((a).i,(b).r),17 ); }while(0)
# define DIVSCALAR(x,k) \ # define DIVSCALAR(x,k) \
(x) = sround( smul( x, SAMP_MAX/k ) ) (x) = sround( smul( x, SAMP_MAX/k ) )
@ -85,6 +89,9 @@ struct kiss_fft_state{
#define C_MUL(m,a,b) \ #define C_MUL(m,a,b) \
do{ (m).r = (a).r*(b).r - (a).i*(b).i;\ do{ (m).r = (a).r*(b).r - (a).i*(b).i;\
(m).i = (a).r*(b).i + (a).i*(b).r; }while(0) (m).i = (a).r*(b).i + (a).i*(b).r; }while(0)
#define C_MUL4(m,a,b) C_MUL(m,a,b)
# define C_FIXDIV(c,div) /* NOOP */ # define C_FIXDIV(c,div) /* NOOP */
# define C_MULBYSCALAR( c, s ) \ # define C_MULBYSCALAR( c, s ) \
do{ (c).r *= (s);\ do{ (c).r *= (s);\

View file

@ -137,7 +137,6 @@ void spx_ifft(void *table, float *in, float *out)
struct kiss_config { struct kiss_config {
kiss_fftr_cfg forward; kiss_fftr_cfg forward;
kiss_fftr_cfg backward; kiss_fftr_cfg backward;
kiss_fft_cpx *freq_data;
int N; int N;
}; };
@ -145,7 +144,6 @@ void *spx_fft_init(int size)
{ {
struct kiss_config *table; struct kiss_config *table;
table = (struct kiss_config*)speex_alloc(sizeof(struct kiss_config)); table = (struct kiss_config*)speex_alloc(sizeof(struct kiss_config));
table->freq_data = (kiss_fft_cpx*)speex_alloc(sizeof(kiss_fft_cpx)*((size>>1)+1));
table->forward = kiss_fftr_alloc(size,0,NULL,NULL); table->forward = kiss_fftr_alloc(size,0,NULL,NULL);
table->backward = kiss_fftr_alloc(size,1,NULL,NULL); table->backward = kiss_fftr_alloc(size,1,NULL,NULL);
table->N = size; table->N = size;
@ -157,7 +155,6 @@ void spx_fft_destroy(void *table)
struct kiss_config *t = (struct kiss_config *)table; struct kiss_config *t = (struct kiss_config *)table;
kiss_fftr_free(t->forward); kiss_fftr_free(t->forward);
kiss_fftr_free(t->backward); kiss_fftr_free(t->backward);
speex_free(t->freq_data);
speex_free(table); speex_free(table);
} }
@ -165,18 +162,10 @@ void spx_fft_destroy(void *table)
void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out)
{ {
int i;
int shift; int shift;
struct kiss_config *t = (struct kiss_config *)table; struct kiss_config *t = (struct kiss_config *)table;
shift = maximize_range(in, in, 32000, t->N); shift = maximize_range(in, in, 32000, t->N);
kiss_fftr(t->forward, in, t->freq_data); kiss_fftr2(t->forward, in, out);
out[0] = t->freq_data[0].r;
for (i=1;i<t->N>>1;i++)
{
out[(i<<1)-1] = t->freq_data[i].r;
out[(i<<1)] = t->freq_data[i].i;
}
out[(i<<1)-1] = t->freq_data[i].r;
renorm_range(in, in, shift, t->N); renorm_range(in, in, shift, t->N);
renorm_range(out, out, shift, t->N); renorm_range(out, out, shift, t->N);
} }
@ -189,32 +178,16 @@ void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out)
float scale; float scale;
struct kiss_config *t = (struct kiss_config *)table; struct kiss_config *t = (struct kiss_config *)table;
scale = 1./t->N; scale = 1./t->N;
kiss_fftr(t->forward, in, t->freq_data); kiss_fftr2(t->forward, in, out);
out[0] = scale*t->freq_data[0].r; for (i=0;i<t->N;i++)
for (i=1;i<t->N>>1;i++) out[i] *= scale;
{
out[(i<<1)-1] = scale*t->freq_data[i].r;
out[(i<<1)] = scale*t->freq_data[i].i;
}
out[(i<<1)-1] = scale*t->freq_data[i].r;
} }
#endif #endif
void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out) void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out)
{ {
int i;
struct kiss_config *t = (struct kiss_config *)table; struct kiss_config *t = (struct kiss_config *)table;
t->freq_data[0].r = in[0]; kiss_fftri2(t->backward, in, out);
t->freq_data[0].i = 0;
for (i=1;i<t->N>>1;i++)
{
t->freq_data[i].r = in[(i<<1)-1];
t->freq_data[i].i = in[(i<<1)];
}
t->freq_data[i].r = in[(i<<1)-1];
t->freq_data[i].i = 0;
kiss_fftri(t->backward, t->freq_data, out);
} }

View file

@ -46,7 +46,7 @@
#define NULL 0 #define NULL 0
#endif #endif
#define LATE_BINS 10 #define LATE_BINS 15
#define MAX_MARGIN 30 /**< Number of bins in margin histogram */ #define MAX_MARGIN 30 /**< Number of bins in margin histogram */
#define SPEEX_JITTER_MAX_BUFFER_SIZE 200 /**< Maximum number of packets in jitter buffer */ #define SPEEX_JITTER_MAX_BUFFER_SIZE 200 /**< Maximum number of packets in jitter buffer */
@ -71,7 +71,9 @@ struct JitterBuffer_ {
int tick_size; /**< Output granularity */ int tick_size; /**< Output granularity */
int reset_state; /**< True if state was just reset */ int reset_state; /**< True if state was just reset */
int buffer_margin; /**< How many frames we want to keep in the buffer (lower bound) */ int buffer_margin; /**< How many frames we want to keep in the buffer (lower bound) */
int late_cutoff; /**< How late must a packet be for it not to be considered at all */
int interp_requested; /**< An interpolation is requested by speex_jitter_update_delay() */
int lost_count; /**< Number of consecutive lost packets */ int lost_count; /**< Number of consecutive lost packets */
float shortterm_margin[MAX_MARGIN]; /**< Short term margin histogram */ float shortterm_margin[MAX_MARGIN]; /**< Short term margin histogram */
float longterm_margin[MAX_MARGIN]; /**< Long term margin histogram */ float longterm_margin[MAX_MARGIN]; /**< Long term margin histogram */
@ -89,6 +91,7 @@ JitterBuffer *jitter_buffer_init(int tick)
jitter->buf[i]=NULL; jitter->buf[i]=NULL;
jitter->tick_size = tick; jitter->tick_size = tick;
jitter->buffer_margin = 1; jitter->buffer_margin = 1;
jitter->late_cutoff = 50;
jitter_buffer_reset(jitter); jitter_buffer_reset(jitter);
} }
return jitter; return jitter;
@ -130,7 +133,8 @@ void jitter_buffer_destroy(JitterBuffer *jitter)
/** Put one packet into the jitter buffer */ /** Put one packet into the jitter buffer */
void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
{ {
int i,j; int i;
unsigned int j;
spx_int32_t arrival_margin; spx_int32_t arrival_margin;
/*fprintf (stderr, "put packet %d %d\n", timestamp, span);*/ /*fprintf (stderr, "put packet %d %d\n", timestamp, span);*/
if (jitter->reset_state) if (jitter->reset_state)
@ -144,6 +148,7 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
/* Cleanup buffer (remove old packets that weren't played) */ /* Cleanup buffer (remove old packets that weren't played) */
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
{ {
/* Make sure we don't discard a "just-late" packet in case we want to play it next (if we interpolate). */
if (jitter->buf[i] && LE32(jitter->timestamp[i] + jitter->span[i], jitter->pointer_timestamp)) if (jitter->buf[i] && LE32(jitter->timestamp[i] + jitter->span[i], jitter->pointer_timestamp))
{ {
/*fprintf (stderr, "cleaned (not played)\n");*/ /*fprintf (stderr, "cleaned (not played)\n");*/
@ -184,33 +189,39 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
/* Copy packet in buffer */ /* Copy packet in buffer */
jitter->buf[i]=(char*)speex_alloc(packet->len); jitter->buf[i]=(char*)speex_alloc(packet->len);
for (j=0;((unsigned)j)<packet->len;j++) for (j=0;j<packet->len;j++)
jitter->buf[i][j]=packet->data[j]; jitter->buf[i][j]=packet->data[j];
jitter->timestamp[i]=packet->timestamp; jitter->timestamp[i]=packet->timestamp;
jitter->span[i]=packet->span; jitter->span[i]=packet->span;
jitter->len[i]=packet->len; jitter->len[i]=packet->len;
/* Adjust the buffer size depending on network conditions */ /* Adjust the buffer size depending on network conditions.
arrival_margin = (packet->timestamp - jitter->current_timestamp) - jitter->buffer_margin*jitter->tick_size; The arrival margin is how much in advance (or late) the packet it */
arrival_margin = (packet->timestamp - jitter->current_timestamp)/jitter->tick_size - jitter->buffer_margin;
if (arrival_margin >= -LATE_BINS*jitter->tick_size) if (arrival_margin >= -jitter->late_cutoff)
{ {
/* Here we compute the histogram based on the time of arrival of the packet.
This is based on a (first-order) recursive average. We keep both a short-term
histogram and a long-term histogram */
spx_int32_t int_margin; spx_int32_t int_margin;
/* First, apply the "damping" of the recursive average to all bins */
for (i=0;i<MAX_MARGIN;i++) for (i=0;i<MAX_MARGIN;i++)
{ {
jitter->shortterm_margin[i] *= .98; jitter->shortterm_margin[i] *= .98;
jitter->longterm_margin[i] *= .995; jitter->longterm_margin[i] *= .995;
} }
int_margin = LATE_BINS + arrival_margin/jitter->tick_size; /* What histogram bin the packet should be counted in */
int_margin = LATE_BINS + arrival_margin;
if (int_margin>MAX_MARGIN-1) if (int_margin>MAX_MARGIN-1)
int_margin = MAX_MARGIN-1; int_margin = MAX_MARGIN-1;
if (int_margin>=0) if (int_margin<0)
{ int_margin = 0;
jitter->shortterm_margin[int_margin] += .02; /* Add the packet to the right bin */
jitter->longterm_margin[int_margin] += .005; jitter->shortterm_margin[int_margin] += .02;
} jitter->longterm_margin[int_margin] += .005;
} else { } else {
/* Packet has arrived *way* too late, we pretty much consider it lost and not take it into account in the histogram */
/*fprintf (stderr, "way too late = %d\n", arrival_margin);*/ /*fprintf (stderr, "way too late = %d\n", arrival_margin);*/
if (jitter->lost_count>20) if (jitter->lost_count>20)
{ {
@ -234,7 +245,8 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
/** Get one packet from the jitter buffer */ /** Get one packet from the jitter buffer */
int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint32_t *start_offset) int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint32_t *start_offset)
{ {
int i, j; int i;
unsigned int j;
float late_ratio_short; float late_ratio_short;
float late_ratio_long; float late_ratio_long;
float ontime_ratio_short; float ontime_ratio_short;
@ -244,6 +256,17 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint
int chunk_size; int chunk_size;
int incomplete = 0; int incomplete = 0;
if (jitter->interp_requested)
{
jitter->interp_requested = 0;
if (start_offset)
*start_offset = 0;
packet->timestamp = jitter->pointer_timestamp;
packet->span = jitter->tick_size;
jitter->pointer_timestamp += jitter->tick_size;
packet->len = 0;
return JITTER_BUFFER_MISSING;
}
if (LT32(jitter->current_timestamp+jitter->tick_size, jitter->pointer_timestamp)) if (LT32(jitter->current_timestamp+jitter->tick_size, jitter->pointer_timestamp))
{ {
jitter->current_timestamp = jitter->pointer_timestamp; jitter->current_timestamp = jitter->pointer_timestamp;
@ -258,14 +281,17 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint
late_ratio_short = 0; late_ratio_short = 0;
late_ratio_long = 0; late_ratio_long = 0;
/* Count the proportion of packets that are late */
for (i=0;i<LATE_BINS;i++) for (i=0;i<LATE_BINS;i++)
{ {
late_ratio_short += jitter->shortterm_margin[i]; late_ratio_short += jitter->shortterm_margin[i];
late_ratio_long += jitter->longterm_margin[i]; late_ratio_long += jitter->longterm_margin[i];
} }
/* Count the proportion of packets that are just on time */
ontime_ratio_short = jitter->shortterm_margin[LATE_BINS]; ontime_ratio_short = jitter->shortterm_margin[LATE_BINS];
ontime_ratio_long = jitter->longterm_margin[LATE_BINS]; ontime_ratio_long = jitter->longterm_margin[LATE_BINS];
early_ratio_short = early_ratio_long = 0; early_ratio_short = early_ratio_long = 0;
/* Count the proportion of packets that are early */
for (i=LATE_BINS+1;i<MAX_MARGIN;i++) for (i=LATE_BINS+1;i<MAX_MARGIN;i++)
{ {
early_ratio_short += jitter->shortterm_margin[i]; early_ratio_short += jitter->shortterm_margin[i];
@ -277,42 +303,6 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint
/*fprintf (stderr, "%f %f\n", early_ratio_short + ontime_ratio_short + late_ratio_short, early_ratio_long + ontime_ratio_long + late_ratio_long);*/ /*fprintf (stderr, "%f %f\n", early_ratio_short + ontime_ratio_short + late_ratio_short, early_ratio_long + ontime_ratio_long + late_ratio_long);*/
} }
/* Adjusting the buffering */
if (late_ratio_short > .1 || late_ratio_long > .03)
{
/* If too many packets are arriving late */
jitter->shortterm_margin[MAX_MARGIN-1] += jitter->shortterm_margin[MAX_MARGIN-2];
jitter->longterm_margin[MAX_MARGIN-1] += jitter->longterm_margin[MAX_MARGIN-2];
for (i=MAX_MARGIN-3;i>=0;i--)
{
jitter->shortterm_margin[i+1] = jitter->shortterm_margin[i];
jitter->longterm_margin[i+1] = jitter->longterm_margin[i];
}
jitter->shortterm_margin[0] = 0;
jitter->longterm_margin[0] = 0;
jitter->pointer_timestamp -= jitter->tick_size;
jitter->current_timestamp -= jitter->tick_size;
/*fprintf (stderr, "i");*/
/*fprintf (stderr, "interpolate (getting some slack)\n");*/
} else if (late_ratio_short + ontime_ratio_short < .005 && late_ratio_long + ontime_ratio_long < .01 && early_ratio_short > .8)
{
/* Many frames arriving early */
jitter->shortterm_margin[0] += jitter->shortterm_margin[1];
jitter->longterm_margin[0] += jitter->longterm_margin[1];
for (i=1;i<MAX_MARGIN-1;i++)
{
jitter->shortterm_margin[i] = jitter->shortterm_margin[i+1];
jitter->longterm_margin[i] = jitter->longterm_margin[i+1];
}
jitter->shortterm_margin[MAX_MARGIN-1] = 0;
jitter->longterm_margin[MAX_MARGIN-1] = 0;
/*fprintf (stderr, "drop frame\n");*/
/*fprintf (stderr, "d");*/
jitter->pointer_timestamp += jitter->tick_size;
jitter->current_timestamp += jitter->tick_size;
/*fprintf (stderr, "dropping packet (getting more aggressive)\n");*/
}
/* Searching for the packet that fits best */ /* Searching for the packet that fits best */
@ -328,7 +318,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint
{ {
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
{ {
if (jitter->buf[i] && jitter->timestamp[i]<=jitter->pointer_timestamp && GE32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp+chunk_size)) if (jitter->buf[i] && LE32(jitter->timestamp[i], jitter->pointer_timestamp) && GE32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp+chunk_size))
break; break;
} }
} }
@ -338,7 +328,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint
{ {
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
{ {
if (jitter->buf[i] && jitter->timestamp[i]<=jitter->pointer_timestamp && GT32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp)) if (jitter->buf[i] && LE32(jitter->timestamp[i], jitter->pointer_timestamp) && GT32(jitter->timestamp[i]+jitter->span[i],jitter->pointer_timestamp))
break; break;
} }
} }
@ -381,7 +371,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint
/* Check for potential overflow */ /* Check for potential overflow */
packet->len = jitter->len[i]; packet->len = jitter->len[i];
/* Copy packet */ /* Copy packet */
for (j=0;((unsigned)j)<packet->len;j++) for (j=0;j<packet->len;j++)
packet->data[j] = jitter->buf[i][j]; packet->data[j] = jitter->buf[i][j];
/* Remove packet */ /* Remove packet */
speex_free(jitter->buf[i]); speex_free(jitter->buf[i]);
@ -412,6 +402,26 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint
packet->span = jitter->tick_size; packet->span = jitter->tick_size;
jitter->pointer_timestamp += chunk_size; jitter->pointer_timestamp += chunk_size;
packet->len = 0; packet->len = 0;
/* Adjusting the buffering bssed on the amount of packets that are early/on time/late */
if (late_ratio_short > .1 || late_ratio_long > .03)
{
/* If too many packets are arriving late */
jitter->shortterm_margin[MAX_MARGIN-1] += jitter->shortterm_margin[MAX_MARGIN-2];
jitter->longterm_margin[MAX_MARGIN-1] += jitter->longterm_margin[MAX_MARGIN-2];
for (i=MAX_MARGIN-3;i>=0;i--)
{
jitter->shortterm_margin[i+1] = jitter->shortterm_margin[i];
jitter->longterm_margin[i+1] = jitter->longterm_margin[i];
}
jitter->shortterm_margin[0] = 0;
jitter->longterm_margin[0] = 0;
jitter->pointer_timestamp -= jitter->tick_size;
jitter->current_timestamp -= jitter->tick_size;
/*fprintf (stderr, "i");*/
/*fprintf (stderr, "interpolate (getting some slack)\n");*/
}
return JITTER_BUFFER_MISSING; return JITTER_BUFFER_MISSING;
} }
@ -427,9 +437,88 @@ void jitter_buffer_tick(JitterBuffer *jitter)
jitter->current_timestamp += jitter->tick_size; jitter->current_timestamp += jitter->tick_size;
} }
/* 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_uint32_t *start_offset)
{
int i;
float late_ratio_short;
float late_ratio_long;
float ontime_ratio_short;
float ontime_ratio_long;
float early_ratio_short;
float early_ratio_long;
if (LT32(jitter->current_timestamp+jitter->tick_size, jitter->pointer_timestamp))
{
jitter->current_timestamp = jitter->pointer_timestamp;
speex_warning("did you forget to call jitter_buffer_tick() by any chance?");
}
/*fprintf (stderr, "get packet %d %d\n", jitter->pointer_timestamp, jitter->current_timestamp);*/
/* FIXME: This should be only what remaining of the current tick */
late_ratio_short = 0;
late_ratio_long = 0;
/* Count the proportion of packets that are late */
for (i=0;i<LATE_BINS;i++)
{
late_ratio_short += jitter->shortterm_margin[i];
late_ratio_long += jitter->longterm_margin[i];
}
/* Count the proportion of packets that are just on time */
ontime_ratio_short = jitter->shortterm_margin[LATE_BINS];
ontime_ratio_long = jitter->longterm_margin[LATE_BINS];
early_ratio_short = early_ratio_long = 0;
/* Count the proportion of packets that are early */
for (i=LATE_BINS+1;i<MAX_MARGIN;i++)
{
early_ratio_short += jitter->shortterm_margin[i];
early_ratio_long += jitter->longterm_margin[i];
}
/* Adjusting the buffering bssed on the amount of packets that are early/on time/late */
if (late_ratio_short > .1 || late_ratio_long > .03)
{
/* If too many packets are arriving late */
jitter->shortterm_margin[MAX_MARGIN-1] += jitter->shortterm_margin[MAX_MARGIN-2];
jitter->longterm_margin[MAX_MARGIN-1] += jitter->longterm_margin[MAX_MARGIN-2];
for (i=MAX_MARGIN-3;i>=0;i--)
{
jitter->shortterm_margin[i+1] = jitter->shortterm_margin[i];
jitter->longterm_margin[i+1] = jitter->longterm_margin[i];
}
jitter->shortterm_margin[0] = 0;
jitter->longterm_margin[0] = 0;
jitter->pointer_timestamp -= jitter->tick_size;
jitter->current_timestamp -= jitter->tick_size;
jitter->interp_requested = 1;
return JITTER_BUFFER_ADJUST_INTERPOLATE;
} else if (late_ratio_short + ontime_ratio_short < .005 && late_ratio_long + ontime_ratio_long < .01 && early_ratio_short > .8)
{
/* Many frames arriving early */
jitter->shortterm_margin[0] += jitter->shortterm_margin[1];
jitter->longterm_margin[0] += jitter->longterm_margin[1];
for (i=1;i<MAX_MARGIN-1;i++)
{
jitter->shortterm_margin[i] = jitter->shortterm_margin[i+1];
jitter->longterm_margin[i] = jitter->longterm_margin[i+1];
}
jitter->shortterm_margin[MAX_MARGIN-1] = 0;
jitter->longterm_margin[MAX_MARGIN-1] = 0;
/*fprintf (stderr, "drop frame\n");*/
/*fprintf (stderr, "d");*/
jitter->pointer_timestamp += jitter->tick_size;
jitter->current_timestamp += jitter->tick_size;
return JITTER_BUFFER_ADJUST_DROP;
}
return JITTER_BUFFER_ADJUST_OK;
}
/* Used like the ioctl function to control the jitter buffer parameters */ /* Used like the ioctl function to control the jitter buffer parameters */
int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr) int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
{ {
int count, i;
switch(request) switch(request)
{ {
case JITTER_BUFFER_SET_MARGIN: case JITTER_BUFFER_SET_MARGIN:
@ -438,6 +527,17 @@ int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
case JITTER_BUFFER_GET_MARGIN: case JITTER_BUFFER_GET_MARGIN:
*(spx_int32_t*)ptr = jitter->buffer_margin; *(spx_int32_t*)ptr = jitter->buffer_margin;
break; break;
case JITTER_BUFFER_GET_AVALIABLE_COUNT:
count = 0;
for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
{
if (jitter->buf[i] && LE32(jitter->pointer_timestamp, jitter->timestamp[i]))
{
count++;
}
}
*(spx_int32_t*)ptr = count;
break;
default: default:
speex_warning_int("Unknown jitter_buffer_ctl request: ", request); speex_warning_int("Unknown jitter_buffer_ctl request: ", request);
return -1; return -1;
@ -518,6 +618,7 @@ void speex_jitter_get(SpeexJitter *jitter, short *out, int *current_timestamp)
out[i]=0; out[i]=0;
} }
} }
jitter_buffer_update_delay(jitter->packets, &packet, NULL);
jitter_buffer_tick(jitter->packets); jitter_buffer_tick(jitter->packets);
} }

View file

@ -1,5 +1,6 @@
/* /*
Copyright (c) 2003-2004, Mark Borgerding Copyright (c) 2003-2004, Mark Borgerding
Copyright (c) 2005-2007, Jean-Marc Valin
All rights reserved. All rights reserved.
@ -24,121 +25,143 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
fixed or floating point complex numbers. It also delares the kf_ internal functions. fixed or floating point complex numbers. It also delares the kf_ internal functions.
*/ */
static kiss_fft_cpx *scratchbuf=NULL;
static size_t nscratchbuf=0;
static kiss_fft_cpx *tmpbuf=NULL;
static size_t ntmpbuf=0;
#define CHECKBUF(buf,nbuf,n) \
do { \
if ( nbuf < (size_t)(n) ) {\
speex_free(buf); \
buf = (kiss_fft_cpx*)KISS_FFT_MALLOC(sizeof(kiss_fft_cpx)*(n)); \
nbuf = (size_t)(n); \
} \
}while(0)
static void kf_bfly2( static void kf_bfly2(
kiss_fft_cpx * Fout, kiss_fft_cpx * Fout,
const size_t fstride, const size_t fstride,
const kiss_fft_cfg st, const kiss_fft_cfg st,
int m int m,
int N,
int mm
) )
{ {
kiss_fft_cpx * Fout2; kiss_fft_cpx * Fout2;
kiss_fft_cpx * tw1 = st->twiddles; kiss_fft_cpx * tw1;
kiss_fft_cpx t; kiss_fft_cpx t;
Fout2 = Fout + m;
if (!st->inverse) { if (!st->inverse) {
int i; int i,j;
kiss_fft_cpx *x=Fout; kiss_fft_cpx * Fout_beg = Fout;
for (i=0;i<2*m;i++) for (i=0;i<N;i++)
{ {
x[i].r = SHR16(x[i].r,1); Fout = Fout_beg + i*mm;
x[i].i = SHR16(x[i].i,1); Fout2 = Fout + m;
tw1 = st->twiddles;
for(j=0;j<m;j++)
{
/* Almost the same as the code path below, except that we divide the input by two
(while keeping the best accuracy possible) */
spx_word32_t tr, ti;
tr = SHR32(SUB32(MULT16_16(Fout2->r , tw1->r),MULT16_16(Fout2->i , tw1->i)), 1);
ti = SHR32(ADD32(MULT16_16(Fout2->i , tw1->r),MULT16_16(Fout2->r , tw1->i)), 1);
tw1 += fstride;
Fout2->r = PSHR32(SUB32(SHL32(EXTEND32(Fout->r), 14), tr), 15);
Fout2->i = PSHR32(SUB32(SHL32(EXTEND32(Fout->i), 14), ti), 15);
Fout->r = PSHR32(ADD32(SHL32(EXTEND32(Fout->r), 14), tr), 15);
Fout->i = PSHR32(ADD32(SHL32(EXTEND32(Fout->i), 14), ti), 15);
++Fout2;
++Fout;
}
}
} else {
int i,j;
kiss_fft_cpx * Fout_beg = Fout;
for (i=0;i<N;i++)
{
Fout = Fout_beg + i*mm;
Fout2 = Fout + m;
tw1 = st->twiddles;
for(j=0;j<m;j++)
{
C_MUL (t, *Fout2 , *tw1);
tw1 += fstride;
C_SUB( *Fout2 , *Fout , t );
C_ADDTO( *Fout , t );
++Fout2;
++Fout;
}
} }
} }
do{
C_MUL (t, *Fout2 , *tw1);
tw1 += fstride;
C_SUB( *Fout2 , *Fout , t );
C_ADDTO( *Fout , t );
++Fout2;
++Fout;
}while (--m);
} }
static void kf_bfly4( static void kf_bfly4(
kiss_fft_cpx * Fout, kiss_fft_cpx * Fout,
const size_t fstride, const size_t fstride,
const kiss_fft_cfg st, const kiss_fft_cfg st,
const size_t m const size_t m,
int N,
int mm
) )
{ {
kiss_fft_cpx *tw1,*tw2,*tw3; kiss_fft_cpx *tw1,*tw2,*tw3;
kiss_fft_cpx scratch[6]; kiss_fft_cpx scratch[6];
size_t k=m;
const size_t m2=2*m; const size_t m2=2*m;
const size_t m3=3*m; const size_t m3=3*m;
int i;
unsigned int j;
tw3 = tw2 = tw1 = st->twiddles;
if (!st->inverse) {
unsigned int i;
kiss_fft_cpx *x=Fout;
for (i=0;i<4*m;i++)
{
x[i].r = PSHR16(x[i].r,2);
x[i].i = PSHR16(x[i].i,2);
}
}
if (st->inverse) if (st->inverse)
{ {
do { kiss_fft_cpx * Fout_beg = Fout;
C_MUL(scratch[0],Fout[m] , *tw1 ); for (i=0;i<N;i++)
C_MUL(scratch[1],Fout[m2] , *tw2 ); {
C_MUL(scratch[2],Fout[m3] , *tw3 ); Fout = Fout_beg + i*mm;
tw3 = tw2 = tw1 = st->twiddles;
C_SUB( scratch[5] , *Fout, scratch[1] ); for (j=0;j<m;j++)
C_ADDTO(*Fout, scratch[1]); {
C_ADD( scratch[3] , scratch[0] , scratch[2] ); C_MUL(scratch[0],Fout[m] , *tw1 );
C_SUB( scratch[4] , scratch[0] , scratch[2] ); C_MUL(scratch[1],Fout[m2] , *tw2 );
C_SUB( Fout[m2], *Fout, scratch[3] ); C_MUL(scratch[2],Fout[m3] , *tw3 );
tw1 += fstride;
tw2 += fstride*2; C_SUB( scratch[5] , *Fout, scratch[1] );
tw3 += fstride*3; C_ADDTO(*Fout, scratch[1]);
C_ADDTO( *Fout , scratch[3] ); C_ADD( scratch[3] , scratch[0] , scratch[2] );
C_SUB( scratch[4] , scratch[0] , scratch[2] );
Fout[m].r = scratch[5].r - scratch[4].i; C_SUB( Fout[m2], *Fout, scratch[3] );
Fout[m].i = scratch[5].i + scratch[4].r; tw1 += fstride;
Fout[m3].r = scratch[5].r + scratch[4].i; tw2 += fstride*2;
Fout[m3].i = scratch[5].i - scratch[4].r; tw3 += fstride*3;
++Fout; C_ADDTO( *Fout , scratch[3] );
} while(--k);
Fout[m].r = scratch[5].r - scratch[4].i;
Fout[m].i = scratch[5].i + scratch[4].r;
Fout[m3].r = scratch[5].r + scratch[4].i;
Fout[m3].i = scratch[5].i - scratch[4].r;
++Fout;
}
}
} else } else
{ {
do { kiss_fft_cpx * Fout_beg = Fout;
C_MUL(scratch[0],Fout[m] , *tw1 ); for (i=0;i<N;i++)
C_MUL(scratch[1],Fout[m2] , *tw2 ); {
C_MUL(scratch[2],Fout[m3] , *tw3 ); Fout = Fout_beg + i*mm;
tw3 = tw2 = tw1 = st->twiddles;
C_SUB( scratch[5] , *Fout, scratch[1] ); for (j=0;j<m;j++)
C_ADDTO(*Fout, scratch[1]); {
C_ADD( scratch[3] , scratch[0] , scratch[2] ); C_MUL4(scratch[0],Fout[m] , *tw1 );
C_SUB( scratch[4] , scratch[0] , scratch[2] ); C_MUL4(scratch[1],Fout[m2] , *tw2 );
C_SUB( Fout[m2], *Fout, scratch[3] ); C_MUL4(scratch[2],Fout[m3] , *tw3 );
tw1 += fstride;
tw2 += fstride*2; Fout->r = PSHR16(Fout->r, 2);
tw3 += fstride*3; Fout->i = PSHR16(Fout->i, 2);
C_ADDTO( *Fout , scratch[3] ); C_SUB( scratch[5] , *Fout, scratch[1] );
C_ADDTO(*Fout, scratch[1]);
Fout[m].r = scratch[5].r + scratch[4].i; C_ADD( scratch[3] , scratch[0] , scratch[2] );
Fout[m].i = scratch[5].i - scratch[4].r; C_SUB( scratch[4] , scratch[0] , scratch[2] );
Fout[m3].r = scratch[5].r - scratch[4].i; Fout[m2].r = PSHR16(Fout[m2].r, 2);
Fout[m3].i = scratch[5].i + scratch[4].r; Fout[m2].i = PSHR16(Fout[m2].i, 2);
++Fout; C_SUB( Fout[m2], *Fout, scratch[3] );
}while(--k); tw1 += fstride;
tw2 += fstride*2;
tw3 += fstride*3;
C_ADDTO( *Fout , scratch[3] );
Fout[m].r = scratch[5].r + scratch[4].i;
Fout[m].i = scratch[5].i - scratch[4].r;
Fout[m3].r = scratch[5].r - scratch[4].i;
Fout[m3].i = scratch[5].i + scratch[4].r;
++Fout;
}
}
} }
} }
@ -263,10 +286,13 @@ static void kf_bfly_generic(
int u,k,q1,q; int u,k,q1,q;
kiss_fft_cpx * twiddles = st->twiddles; kiss_fft_cpx * twiddles = st->twiddles;
kiss_fft_cpx t; kiss_fft_cpx t;
kiss_fft_cpx scratchbuf[17];
int Norig = st->nfft; int Norig = st->nfft;
CHECKBUF(scratchbuf,nscratchbuf,p); /*CHECKBUF(scratchbuf,nscratchbuf,p);*/
if (p>17)
speex_error("KissFFT: max radix supported is 17");
for ( u=0; u<m; ++u ) { for ( u=0; u<m; ++u ) {
k=u; k=u;
for ( q1=0 ; q1<p ; ++q1 ) { for ( q1=0 ; q1<p ; ++q1 ) {
@ -291,6 +317,39 @@ static void kf_bfly_generic(
} }
} }
} }
static
void kf_shuffle(
kiss_fft_cpx * Fout,
const kiss_fft_cpx * f,
const size_t fstride,
int in_stride,
int * factors,
const kiss_fft_cfg st
)
{
const int p=*factors++; /* the radix */
const int m=*factors++; /* stage's fft length/p */
/*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/
if (m==1)
{
int j;
for (j=0;j<p;j++)
{
Fout[j] = *f;
f += fstride*in_stride;
}
} else {
int j;
for (j=0;j<p;j++)
{
kf_shuffle( Fout , f, fstride*p, in_stride, factors,st);
f += fstride*in_stride;
Fout += m;
}
}
}
static static
void kf_work( void kf_work(
@ -299,24 +358,34 @@ void kf_work(
const size_t fstride, const size_t fstride,
int in_stride, int in_stride,
int * factors, int * factors,
const kiss_fft_cfg st const kiss_fft_cfg st,
int N,
int s2,
int m2
) )
{ {
int i;
kiss_fft_cpx * Fout_beg=Fout; kiss_fft_cpx * Fout_beg=Fout;
const int p=*factors++; /* the radix */ const int p=*factors++; /* the radix */
const int m=*factors++; /* stage's fft length/p */ const int m=*factors++; /* stage's fft length/p */
const kiss_fft_cpx * Fout_end = Fout + p*m; #if 0
/*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/
if (m==1) { if (m==1)
do{ {
*Fout = *f; /* int j;
f += fstride*in_stride; for (j=0;j<p;j++)
}while(++Fout != Fout_end ); {
}else{ Fout[j] = *f;
do{ f += fstride*in_stride;
kf_work( Fout , f, fstride*p, in_stride, factors,st); }*/
f += fstride*in_stride; } else {
}while( (Fout += m) != Fout_end ); int j;
for (j=0;j<p;j++)
{
kf_work( Fout , f, fstride*p, in_stride, factors,st, N*p, fstride*in_stride, m);
f += fstride*in_stride;
Fout += m;
}
} }
Fout=Fout_beg; Fout=Fout_beg;
@ -328,6 +397,36 @@ void kf_work(
case 5: kf_bfly5(Fout,fstride,st,m); break; case 5: kf_bfly5(Fout,fstride,st,m); break;
default: kf_bfly_generic(Fout,fstride,st,m,p); break; default: kf_bfly_generic(Fout,fstride,st,m,p); break;
} }
#else
/*printf ("fft %d %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N, m2);*/
if (m==1)
{
/*for (i=0;i<N;i++)
{
int j;
Fout = Fout_beg+i*m2;
const kiss_fft_cpx * f2 = f+i*s2;
for (j=0;j<p;j++)
{
*Fout++ = *f2;
f2 += fstride*in_stride;
}
}*/
}else{
kf_work( Fout , f, fstride*p, in_stride, factors,st, N*p, fstride*in_stride, m);
}
switch (p) {
case 2: kf_bfly2(Fout,fstride,st,m, N, m2); break;
case 3: for (i=0;i<N;i++){Fout=Fout_beg+i*m2; kf_bfly3(Fout,fstride,st,m);} break;
case 4: kf_bfly4(Fout,fstride,st,m, N, m2); break;
case 5: for (i=0;i<N;i++){Fout=Fout_beg+i*m2; kf_bfly5(Fout,fstride,st,m);} break;
default: for (i=0;i<N;i++){Fout=Fout_beg+i*m2; kf_bfly_generic(Fout,fstride,st,m,p);} break;
}
#endif
} }
/* facbuf is populated by p1,m1,p2,m2, ... /* facbuf is populated by p1,m1,p2,m2, ...
@ -405,12 +504,15 @@ kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem
void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride) void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride)
{ {
if (fin == fout) { if (fin == fout)
CHECKBUF(tmpbuf,ntmpbuf,st->nfft); {
kf_work(tmpbuf,fin,1,in_stride, st->factors,st); speex_error("In-place FFT not supported");
speex_move(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft); /*CHECKBUF(tmpbuf,ntmpbuf,st->nfft);
}else{ kf_work(tmpbuf,fin,1,in_stride, st->factors,st);
kf_work( fout, fin, 1,in_stride, st->factors,st ); speex_move(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft);*/
} else {
kf_shuffle( fout, fin, 1,in_stride, st->factors,st);
kf_work( fout, fin, 1,in_stride, st->factors,st, 1, in_stride, 1);
} }
} }
@ -419,16 +521,3 @@ void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
kiss_fft_stride(cfg,fin,fout,1); kiss_fft_stride(cfg,fin,fout,1);
} }
/* not really necessary to call, but if someone is doing in-place ffts, they may want to free the
buffers from CHECKBUF
*/
void kiss_fft_cleanup(void)
{
speex_free(scratchbuf);
scratchbuf = NULL;
nscratchbuf=0;
speex_free(tmpbuf);
tmpbuf=NULL;
ntmpbuf=0;
}

View file

@ -132,7 +132,7 @@ void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *fr
} }
} }
void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata) void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata, kiss_fft_scalar *timedata)
{ {
/* input buffer timedata is stored row-wise */ /* input buffer timedata is stored row-wise */
int k, ncfft; int k, ncfft;
@ -168,3 +168,129 @@ void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *t
} }
kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata); kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata);
} }
void kiss_fftr2(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_scalar *freqdata)
{
/* input buffer timedata is stored row-wise */
int k,ncfft;
kiss_fft_cpx f2k,tdc;
spx_word32_t f1kr, f1ki, twr, twi;
if ( st->substate->inverse) {
speex_error("kiss fft usage error: improper alloc\n");
}
ncfft = st->substate->nfft;
/*perform the parallel fft of two real signals packed in real,imag*/
kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf );
/* The real part of the DC element of the frequency spectrum in st->tmpbuf
* contains the sum of the even-numbered elements of the input time sequence
* The imag part is the sum of the odd-numbered elements
*
* The sum of tdc.r and tdc.i is the sum of the input time sequence.
* yielding DC of input time sequence
* The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1...
* yielding Nyquist bin of input time sequence
*/
tdc.r = st->tmpbuf[0].r;
tdc.i = st->tmpbuf[0].i;
C_FIXDIV(tdc,2);
CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i);
CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i);
freqdata[0] = tdc.r + tdc.i;
freqdata[2*ncfft-1] = tdc.r - tdc.i;
for ( k=1;k <= ncfft/2 ; ++k )
{
/*fpk = st->tmpbuf[k];
fpnk.r = st->tmpbuf[ncfft-k].r;
fpnk.i = - st->tmpbuf[ncfft-k].i;
C_FIXDIV(fpk,2);
C_FIXDIV(fpnk,2);
C_ADD( f1k, fpk , fpnk );
C_SUB( f2k, fpk , fpnk );
C_MUL( tw , f2k , st->super_twiddles[k]);
freqdata[2*k-1] = HALF_OF(f1k.r + tw.r);
freqdata[2*k] = HALF_OF(f1k.i + tw.i);
freqdata[2*(ncfft-k)-1] = HALF_OF(f1k.r - tw.r);
freqdata[2*(ncfft-k)] = HALF_OF(tw.i - f1k.i);
*/
/*f1k.r = PSHR32(ADD32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1);
f1k.i = PSHR32(SUB32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1);
f2k.r = PSHR32(SUB32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1);
f2k.i = SHR32(ADD32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1);
C_MUL( tw , f2k , st->super_twiddles[k]);
freqdata[2*k-1] = HALF_OF(f1k.r + tw.r);
freqdata[2*k] = HALF_OF(f1k.i + tw.i);
freqdata[2*(ncfft-k)-1] = HALF_OF(f1k.r - tw.r);
freqdata[2*(ncfft-k)] = HALF_OF(tw.i - f1k.i);
*/
f2k.r = SHR32(SUB32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),1);
f2k.i = PSHR32(ADD32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),1);
f1kr = SHL32(ADD32(EXTEND32(st->tmpbuf[k].r), EXTEND32(st->tmpbuf[ncfft-k].r)),13);
f1ki = SHL32(SUB32(EXTEND32(st->tmpbuf[k].i), EXTEND32(st->tmpbuf[ncfft-k].i)),13);
twr = SHR32(SUB32(MULT16_16(f2k.r,st->super_twiddles[k].r),MULT16_16(f2k.i,st->super_twiddles[k].i)), 1);
twi = SHR32(ADD32(MULT16_16(f2k.i,st->super_twiddles[k].r),MULT16_16(f2k.r,st->super_twiddles[k].i)), 1);
#ifdef FIXED_POINT
freqdata[2*k-1] = PSHR32(f1kr + twr, 15);
freqdata[2*k] = PSHR32(f1ki + twi, 15);
freqdata[2*(ncfft-k)-1] = PSHR32(f1kr - twr, 15);
freqdata[2*(ncfft-k)] = PSHR32(twi - f1ki, 15);
#else
freqdata[2*k-1] = .5f*(f1kr + twr);
freqdata[2*k] = .5f*(f1ki + twi);
freqdata[2*(ncfft-k)-1] = .5f*(f1kr - twr);
freqdata[2*(ncfft-k)] = .5f*(twi - f1ki);
#endif
}
}
void kiss_fftri2(kiss_fftr_cfg st,const kiss_fft_scalar *freqdata,kiss_fft_scalar *timedata)
{
/* input buffer timedata is stored row-wise */
int k, ncfft;
if (st->substate->inverse == 0) {
speex_error ("kiss fft usage error: improper alloc\n");
}
ncfft = st->substate->nfft;
st->tmpbuf[0].r = freqdata[0] + freqdata[2*ncfft-1];
st->tmpbuf[0].i = freqdata[0] - freqdata[2*ncfft-1];
/*C_FIXDIV(st->tmpbuf[0],2);*/
for (k = 1; k <= ncfft / 2; ++k) {
kiss_fft_cpx fk, fnkc, fek, fok, tmp;
fk.r = freqdata[2*k-1];
fk.i = freqdata[2*k];
fnkc.r = freqdata[2*(ncfft - k)-1];
fnkc.i = -freqdata[2*(ncfft - k)];
/*C_FIXDIV( fk , 2 );
C_FIXDIV( fnkc , 2 );*/
C_ADD (fek, fk, fnkc);
C_SUB (tmp, fk, fnkc);
C_MUL (fok, tmp, st->super_twiddles[k]);
C_ADD (st->tmpbuf[k], fek, fok);
C_SUB (st->tmpbuf[ncfft - k], fek, fok);
#ifdef USE_SIMD
st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0);
#else
st->tmpbuf[ncfft - k].i *= -1;
#endif
}
kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata);
}

View file

@ -32,7 +32,12 @@ void kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx *f
output freqdata has nfft/2+1 complex points output freqdata has nfft/2+1 complex points
*/ */
void kiss_fftr2(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_scalar *freqdata);
void kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata); void kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata);
void kiss_fftri2(kiss_fftr_cfg st,const kiss_fft_scalar *freqdata, kiss_fft_scalar *timedata);
/* /*
input freqdata has nfft/2+1 complex points input freqdata has nfft/2+1 complex points
output timedata has nfft scalar points output timedata has nfft scalar points

View file

@ -148,7 +148,7 @@ struct SpeexEchoState_ {
spx_word32_t *PHI; /* scratch */ spx_word32_t *PHI; /* scratch */
spx_word32_t *W; /* (Background) filter weights */ spx_word32_t *W; /* (Background) filter weights */
#ifdef TWO_PATH #ifdef TWO_PATH
spx_word32_t *foreground; /* Foreground filter weights */ spx_word16_t *foreground; /* Foreground filter weights */
spx_word32_t Davg1; /* 1st recursive average of the residual power difference */ spx_word32_t Davg1; /* 1st recursive average of the residual power difference */
spx_word32_t Davg2; /* 2nd recursive average of the residual power difference */ spx_word32_t Davg2; /* 2nd recursive average of the residual power difference */
spx_float_t Dvar1; /* Estimated variance of 1st estimator */ spx_float_t Dvar1; /* Estimated variance of 1st estimator */
@ -262,6 +262,34 @@ static inline void spectral_mul_accum(const spx_word16_t *X, const spx_word32_t
} }
acc[N-1] = PSHR32(tmp1,WEIGHT_SHIFT); acc[N-1] = PSHR32(tmp1,WEIGHT_SHIFT);
} }
static inline void spectral_mul_accum16(const spx_word16_t *X, const spx_word16_t *Y, spx_word16_t *acc, int N, int M)
{
int i,j;
spx_word32_t tmp1=0,tmp2=0;
for (j=0;j<M;j++)
{
tmp1 = MAC16_16(tmp1, X[j*N],Y[j*N]);
}
acc[0] = PSHR32(tmp1,WEIGHT_SHIFT);
for (i=1;i<N-1;i+=2)
{
tmp1 = tmp2 = 0;
for (j=0;j<M;j++)
{
tmp1 = SUB32(MAC16_16(tmp1, X[j*N+i],Y[j*N+i]), MULT16_16(X[j*N+i+1],Y[j*N+i+1]));
tmp2 = MAC16_16(MAC16_16(tmp2, X[j*N+i+1],Y[j*N+i]), X[j*N+i], Y[j*N+i+1]);
}
acc[i] = PSHR32(tmp1,WEIGHT_SHIFT);
acc[i+1] = PSHR32(tmp2,WEIGHT_SHIFT);
}
tmp1 = tmp2 = 0;
for (j=0;j<M;j++)
{
tmp1 = MAC16_16(tmp1, X[(j+1)*N-1],Y[(j+1)*N-1]);
}
acc[N-1] = PSHR32(tmp1,WEIGHT_SHIFT);
}
#else #else
static inline void spectral_mul_accum(const spx_word16_t *X, const spx_word32_t *Y, spx_word16_t *acc, int N, int M) static inline void spectral_mul_accum(const spx_word16_t *X, const spx_word32_t *Y, spx_word16_t *acc, int N, int M)
{ {
@ -281,6 +309,7 @@ static inline void spectral_mul_accum(const spx_word16_t *X, const spx_word32_t
Y += N; Y += N;
} }
} }
#define spectral_mul_accum16 spectral_mul_accum
#endif #endif
/** Compute weighted cross-power spectrum of a half-complex (packed) vector with conjugate */ /** Compute weighted cross-power spectrum of a half-complex (packed) vector with conjugate */
@ -375,7 +404,7 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
st->E = (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->W = (spx_word32_t*)speex_alloc(M*N*sizeof(spx_word32_t));
#ifdef TWO_PATH #ifdef TWO_PATH
st->foreground = (spx_word32_t*)speex_alloc(M*N*sizeof(spx_word32_t)); st->foreground = (spx_word16_t*)speex_alloc(M*N*sizeof(spx_word16_t));
#endif #endif
st->PHI = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); st->PHI = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t));
st->power = (spx_word32_t*)speex_alloc((frame_size+1)*sizeof(spx_word32_t)); st->power = (spx_word32_t*)speex_alloc((frame_size+1)*sizeof(spx_word32_t));
@ -669,7 +698,7 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
#ifdef TWO_PATH #ifdef TWO_PATH
/* Compute foreground filter */ /* Compute foreground filter */
spectral_mul_accum(st->X, st->foreground, st->Y, N, M); spectral_mul_accum16(st->X, st->foreground, st->Y, N, M);
spx_ifft(st->fft_table, st->Y, st->e); spx_ifft(st->fft_table, st->Y, st->e);
for (i=0;i<st->frame_size;i++) for (i=0;i<st->frame_size;i++)
st->x[i+st->frame_size] = SUB16(st->input[i], st->e[i+st->frame_size]); st->x[i+st->frame_size] = SUB16(st->input[i], st->e[i+st->frame_size]);
@ -777,7 +806,7 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
st->Dvar1 = st->Dvar2 = FLOAT_ZERO; st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
/* Copy background filter to foreground filter */ /* Copy background filter to foreground filter */
for (i=0;i<N*M;i++) for (i=0;i<N*M;i++)
st->foreground[i] = st->W[i]; st->foreground[i] = EXTRACT16(PSHR32(st->W[i],16));
/* Apply a smooth transition so as to not introduce blocking artifacts */ /* Apply a smooth transition so as to not introduce blocking artifacts */
for (i=0;i<st->frame_size;i++) for (i=0;i<st->frame_size;i++)
st->e[i+st->frame_size] = MULT16_16_Q15(st->window[i+st->frame_size],st->e[i+st->frame_size]) + MULT16_16_Q15(st->window[i],st->y[i+st->frame_size]); st->e[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]);
@ -794,7 +823,7 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
{ {
/* Copy foreground filter to background filter */ /* Copy foreground filter to background filter */
for (i=0;i<N*M;i++) for (i=0;i<N*M;i++)
st->W[i] = st->foreground[i]; st->W[i] = SHL32(EXTEND32(st->foreground[i]),16);
/* We also need to copy the output so as to get correct adaptation */ /* We also need to copy the output so as to get correct adaptation */
for (i=0;i<st->frame_size;i++) for (i=0;i<st->frame_size;i++)
st->y[i+st->frame_size] = st->e[i+st->frame_size]; st->y[i+st->frame_size] = st->e[i+st->frame_size];

View file

@ -46,6 +46,20 @@
#define SB_SUBMODES 8 #define SB_SUBMODES 8
#define SB_SUBMODE_BITS 3 #define SB_SUBMODE_BITS 3
/* Used internally, NOT TO BE USED in applications */
/** Used internally*/
#define SPEEX_GET_PI_GAIN 100
/** Used internally*/
#define SPEEX_GET_EXC 101
/** Used internally*/
#define SPEEX_GET_INNOV 102
/** Used internally*/
#define SPEEX_GET_DTX_STATUS 103
/** Used internally*/
#define SPEEX_SET_INNOVATION_SAVE 104
/** Used internally*/
#define SPEEX_SET_WIDEBAND 105
/** Quantizes LSPs */ /** Quantizes LSPs */
typedef void (*lsp_quant_func)(spx_lsp_t *, spx_lsp_t *, int, SpeexBits *); typedef void (*lsp_quant_func)(spx_lsp_t *, spx_lsp_t *, int, SpeexBits *);

View file

@ -255,7 +255,11 @@ static void conj_window(spx_word16_t *w, int len)
for (i=0;i<len;i++) for (i=0;i<len;i++)
{ {
spx_word16_t tmp; spx_word16_t tmp;
#ifdef FIXED_POINT
spx_word16_t x = DIV32_16(MULT16_16(32767,i),len);
#else
spx_word16_t x = DIV32_16(MULT16_16(QCONST16(4.f,13),i),len); spx_word16_t x = DIV32_16(MULT16_16(QCONST16(4.f,13),i),len);
#endif
int inv=0; int inv=0;
if (x<QCONST16(1.f,13)) if (x<QCONST16(1.f,13))
{ {

View file

@ -2,6 +2,15 @@
/** /**
@file pseudofloat.h @file pseudofloat.h
@brief Pseudo-floating point @brief Pseudo-floating point
* This header file provides a lightweight floating point type for
* use on fixed-point platforms when a large dynamic range is
* required. The new type is not compatible with the 32-bit IEEE format,
* it is not even remotely as accurate as 32-bit floats, and is not
* even guaranteed to produce even remotely correct results for code
* other than Speex. It makes all kinds of shortcuts that are acceptable
* for Speex, but may not be acceptable for your application. You're
* quite welcome to reuse this code and improve it, but don't assume
* it works out of the box. Most likely, it doesn't.
*/ */
/* /*
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View file

@ -59,12 +59,13 @@ TODO list:
void *speex_alloc (int size) {return calloc(size,1);} void *speex_alloc (int size) {return calloc(size,1);}
void *speex_realloc (void *ptr, int size) {return realloc(ptr, size);} void *speex_realloc (void *ptr, int size) {return realloc(ptr, size);}
void speex_free (void *ptr) {free(ptr);} void speex_free (void *ptr) {free(ptr);}
#include "speex_resampler.h"
#else #else
#include "speex/speex_resampler.h"
#include "misc.h" #include "misc.h"
#endif #endif
#include <math.h> #include <math.h>
#include "speex/speex_resampler.h"
#ifndef M_PI #ifndef M_PI
#define M_PI 3.14159263 #define M_PI 3.14159263
@ -82,37 +83,6 @@ void speex_free (void *ptr) {free(ptr);}
#define IMAX(a,b) ((a) > (b) ? (a) : (b)) #define IMAX(a,b) ((a) > (b) ? (a) : (b))
struct QualityMapping {
int base_length;
int oversample;
float downsample_bandwidth;
float upsample_bandwidth;
};
/* This table maps conversion quality to internal parameters. There are two
reasons that explain why the up-sampling bandwidth is larger than the
down-sampling bandwidth:
1) When up-sampling, we can assume that the spectrum is already attenuated
close to the Nyquist rate (from an A/D or a previous resampling filter)
2) Any aliasing that occurs very close to the Nyquist rate will be masked
by the sinusoids/noise just below the Nyquist rate (guaranteed only for
up-sampling).
*/
const struct QualityMapping quality_map[11] = {
{ 8, 4, 0.70f, 0.80f}, /* 0 */
{ 16, 4, 0.74f, 0.83f}, /* 1 */
{ 32, 4, 0.77f, 0.87f}, /* 2 */
{ 48, 8, 0.84f, 0.90f}, /* 3 */
{ 64, 8, 0.88f, 0.92f}, /* 4 */
{ 80, 8, 0.90f, 0.94f}, /* 5 */
{ 96, 8, 0.91f, 0.94f}, /* 6 */
{128, 16, 0.93f, 0.95f}, /* 7 */
{160, 16, 0.94f, 0.96f}, /* 8 */
{192, 16, 0.95f, 0.96f}, /* 9 */
{256, 16, 0.96f, 0.97f}, /* 10 */
};
typedef enum {SPEEX_RESAMPLER_DIRECT_SINGLE=0, SPEEX_RESAMPLER_INTERPOLATE_SINGLE=1} SpeexSincType;
typedef int (*resampler_basic_func)(SpeexResamplerState *, int , const spx_word16_t *, int *, spx_word16_t *, int *); typedef int (*resampler_basic_func)(SpeexResamplerState *, int , const spx_word16_t *, int *, spx_word16_t *, int *);
@ -145,34 +115,190 @@ struct SpeexResamplerState_ {
int in_stride; int in_stride;
int out_stride; int out_stride;
SpeexSincType type;
} ; } ;
static double kaiser12_table[68] = {
0.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076,
0.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014,
0.84290116, 0.81573067, 0.78710866, 0.75723148, 0.72629970, 0.69451601,
0.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014,
0.46473455, 0.43304576, 0.40211431, 0.37206735, 0.34301800, 0.31506490,
0.28829195, 0.26276832, 0.23854851, 0.21567274, 0.19416736, 0.17404546,
0.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178,
0.07063950, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947,
0.02584161, 0.02127838, 0.01736250, 0.01402878, 0.01121463, 0.00886058,
0.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438,
0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734,
0.00001000, 0.00000000};
/*
static double kaiser12_table[36] = {
0.99440475, 1.00000000, 0.99440475, 0.97779076, 0.95066529, 0.91384741,
0.86843014, 0.81573067, 0.75723148, 0.69451601, 0.62920216, 0.56287762,
0.49704014, 0.43304576, 0.37206735, 0.31506490, 0.26276832, 0.21567274,
0.17404546, 0.13794294, 0.10723616, 0.08164178, 0.06075685, 0.04409466,
0.03111947, 0.02127838, 0.01402878, 0.00886058, 0.00531256, 0.00298291,
0.00153438, 0.00069463, 0.00025272, 0.0000527734, 0.00000500, 0.00000000};
*/
static double kaiser10_table[36] = {
0.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446,
0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347,
0.56155915, 0.50119680, 0.44221549, 0.38553619, 0.33194107, 0.28205962,
0.23636152, 0.19515633, 0.15859932, 0.12670280, 0.09935205, 0.07632451,
0.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739,
0.00488951, 0.00257636, 0.00115101, 0.00035515, 0.00000000, 0.00000000};
static double kaiser8_table[36] = {
0.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200,
0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126,
0.63451750, 0.58014482, 0.52566725, 0.47185369, 0.41941150, 0.36897272,
0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758,
0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490,
0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000};
static double kaiser6_table[36] = {
0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003,
0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565,
0.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561,
0.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058,
0.19505503, 0.16360756, 0.13508755, 0.10953262, 0.08693120, 0.06722600,
0.05031820, 0.03607231, 0.02432151, 0.01487334, 0.00752000, 0.00000000};
struct FuncDef {
double *table;
int oversample;
};
static struct FuncDef _KAISER12 = {kaiser12_table, 64};
#define KAISER12 (&_KAISER12)
/*static struct FuncDef _KAISER12 = {kaiser12_table, 32};
#define KAISER12 (&_KAISER12)*/
static struct FuncDef _KAISER10 = {kaiser10_table, 32};
#define KAISER10 (&_KAISER10)
static struct FuncDef _KAISER8 = {kaiser8_table, 32};
#define KAISER8 (&_KAISER8)
static struct FuncDef _KAISER6 = {kaiser6_table, 32};
#define KAISER6 (&_KAISER6)
struct QualityMapping {
int base_length;
int oversample;
float downsample_bandwidth;
float upsample_bandwidth;
struct FuncDef *window_func;
};
/* This table maps conversion quality to internal parameters. There are two
reasons that explain why the up-sampling bandwidth is larger than the
down-sampling bandwidth:
1) When up-sampling, we can assume that the spectrum is already attenuated
close to the Nyquist rate (from an A/D or a previous resampling filter)
2) Any aliasing that occurs very close to the Nyquist rate will be masked
by the sinusoids/noise just below the Nyquist rate (guaranteed only for
up-sampling).
*/
static const struct QualityMapping quality_map[11] = {
{ 8, 4, 0.830f, 0.860f, KAISER6 }, /* Q0 */
{ 16, 4, 0.850f, 0.880f, KAISER6 }, /* Q1 */
{ 32, 4, 0.882f, 0.910f, KAISER6 }, /* Q2 */ /* 82.3% cutoff ( ~60 dB stop) 6 */
{ 48, 8, 0.895f, 0.917f, KAISER8 }, /* Q3 */ /* 84.9% cutoff ( ~80 dB stop) 8 */
{ 64, 8, 0.921f, 0.940f, KAISER8 }, /* Q4 */ /* 88.7% cutoff ( ~80 dB stop) 8 */
{ 80, 8, 0.922f, 0.940f, KAISER10}, /* Q5 */ /* 89.1% cutoff (~100 dB stop) 10 */
{ 96, 8, 0.940f, 0.945f, KAISER10}, /* Q6 */ /* 91.5% cutoff (~100 dB stop) 10 */
{128, 16, 0.950f, 0.950f, KAISER10}, /* Q7 */ /* 93.1% cutoff (~100 dB stop) 10 */
{160, 16, 0.960f, 0.960f, KAISER10}, /* Q8 */ /* 94.5% cutoff (~100 dB stop) 10 */
{192, 16, 0.968f, 0.968f, KAISER12}, /* Q9 */ /* 95.5% cutoff (~100 dB stop) 10 */
{256, 16, 0.975f, 0.975f, KAISER12}, /* Q10 */ /* 96.6% cutoff (~100 dB stop) 10 */
};
/*8,24,40,56,80,104,128,160,200,256,320*/
static double compute_func(float x, struct FuncDef *func)
{
float y, frac;
double interp[4];
int ind;
y = x*func->oversample;
ind = (int)floor(y);
frac = (y-ind);
/* CSE with handle the repeated powers */
interp[3] = -0.1666666667*frac + 0.1666666667*(frac*frac*frac);
interp[2] = frac + 0.5*(frac*frac) - 0.5*(frac*frac*frac);
/*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/
interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac);
/* Just to make sure we don't have rounding problems */
interp[1] = 1.f-interp[3]-interp[2]-interp[0];
/*sum = frac*accum[1] + (1-frac)*accum[2];*/
return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3];
}
#if 0
#include <stdio.h>
int main(int argc, char **argv)
{
int i;
for (i=0;i<256;i++)
{
printf ("%f\n", compute_func(i/256., KAISER12));
}
return 0;
}
#endif
#ifdef FIXED_POINT #ifdef FIXED_POINT
/* The slow way of computing a sinc for the table. Should improve that some day */ /* The slow way of computing a sinc for the table. Should improve that some day */
static spx_word16_t sinc(float cutoff, float x, int N) static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func)
{ {
/*fprintf (stderr, "%f ", x);*/ /*fprintf (stderr, "%f ", x);*/
x *= cutoff; float xx = x * cutoff;
if (fabs(x)<1e-6f) if (fabs(x)<1e-6f)
return WORD2INT(32768.*cutoff); return WORD2INT(32768.*cutoff);
else if (fabs(x) > .5f*N) else if (fabs(x) > .5f*N)
return 0; return 0;
/*FIXME: Can it really be any slower than this? */ /*FIXME: Can it really be any slower than this? */
return WORD2INT(32768.*cutoff*sin(M_PI*x)/(M_PI*x) * (.42+.5*cos(2*x*M_PI/N)+.08*cos(4*x*M_PI/N))); return WORD2INT(32768.*cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func));
} }
#else #else
/* The slow way of computing a sinc for the table. Should improve that some day */ /* The slow way of computing a sinc for the table. Should improve that some day */
static spx_word16_t sinc(float cutoff, float x, int N) static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func)
{ {
/*fprintf (stderr, "%f ", x);*/ /*fprintf (stderr, "%f ", x);*/
x *= cutoff; float xx = x * cutoff;
if (fabs(x)<1e-6) if (fabs(x)<1e-6)
return cutoff; return cutoff;
else if (fabs(x) > .5*N) else if (fabs(x) > .5*N)
return 0; return 0;
/*FIXME: Can it really be any slower than this? */ /*FIXME: Can it really be any slower than this? */
return cutoff*sin(M_PI*x)/(M_PI*x) * (.42+.5*cos(2*x*M_PI/N)+.08*cos(4*x*M_PI/N)); return cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func);
}
#endif
#ifdef FIXED_POINT
static void cubic_coef(spx_word16_t x, spx_word16_t interp[4])
{
/* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation
but I know it's MMSE-optimal on a sinc */
spx_word16_t x2, x3;
x2 = MULT16_16_P15(x, x);
x3 = MULT16_16_P15(x, x2);
interp[0] = PSHR32(MULT16_16(QCONST16(-0.16667f, 15),x) + MULT16_16(QCONST16(0.16667f, 15),x3),15);
interp[1] = EXTRACT16(EXTEND32(x) + SHR32(SUB32(EXTEND32(x2),EXTEND32(x3)),1));
interp[3] = PSHR32(MULT16_16(QCONST16(-0.33333f, 15),x) + MULT16_16(QCONST16(.5f,15),x2) - MULT16_16(QCONST16(0.16667f, 15),x3),15);
/* Just to make sure we don't have rounding problems */
interp[2] = Q15_ONE-interp[0]-interp[1]-interp[3];
if (interp[2]<32767)
interp[2]+=1;
}
#else
static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4])
{
/* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation
but I know it's MMSE-optimal on a sinc */
interp[0] = -0.16667f*frac + 0.16667f*frac*frac*frac;
interp[1] = frac + 0.5f*frac*frac - 0.5f*frac*frac*frac;
/*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/
interp[3] = -0.33333f*frac + 0.5f*frac*frac - 0.16667f*frac*frac*frac;
/* Just to make sure we don't have rounding problems */
interp[2] = 1.-interp[0]-interp[1]-interp[3];
} }
#endif #endif
@ -221,6 +347,55 @@ static int resampler_basic_direct_single(SpeexResamplerState *st, int channel_in
return out_sample; return out_sample;
} }
#ifdef FIXED_POINT
#else
/* This is the same as the previous function, except with a double-precision accumulator */
static int resampler_basic_direct_double(SpeexResamplerState *st, int channel_index, const spx_word16_t *in, int *in_len, spx_word16_t *out, int *out_len)
{
int N = st->filt_len;
int out_sample = 0;
spx_word16_t *mem;
int last_sample = st->last_sample[channel_index];
int samp_frac_num = st->samp_frac_num[channel_index];
mem = st->mem + channel_index * st->mem_alloc_size;
while (!(last_sample >= *in_len || out_sample >= *out_len))
{
int j;
double sum=0;
/* We already have all the filter coefficients pre-computed in the table */
const spx_word16_t *ptr;
/* Do the memory part */
for (j=0;last_sample-N+1+j < 0;j++)
{
sum += MULT16_16(mem[last_sample+j],(double)st->sinc_table[samp_frac_num*st->filt_len+j]);
}
/* Do the new part */
ptr = in+st->in_stride*(last_sample-N+1+j);
for (;j<N;j++)
{
sum += MULT16_16(*ptr,(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;
last_sample++;
}
}
st->last_sample[channel_index] = last_sample;
st->samp_frac_num[channel_index] = samp_frac_num;
return out_sample;
}
#endif
static int resampler_basic_interpolate_single(SpeexResamplerState *st, int channel_index, const spx_word16_t *in, int *in_len, spx_word16_t *out, int *out_len) static int resampler_basic_interpolate_single(SpeexResamplerState *st, int channel_index, const spx_word16_t *in, int *in_len, spx_word16_t *out, int *out_len)
{ {
int N = st->filt_len; int N = st->filt_len;
@ -236,11 +411,16 @@ static int resampler_basic_interpolate_single(SpeexResamplerState *st, int chann
/* We need to interpolate the sinc filter */ /* We need to interpolate the sinc filter */
spx_word32_t accum[4] = {0.f,0.f, 0.f, 0.f}; spx_word32_t accum[4] = {0.f,0.f, 0.f, 0.f};
float interp[4]; spx_word16_t interp[4];
const spx_word16_t *ptr; const spx_word16_t *ptr;
float alpha = ((float)samp_frac_num)/st->den_rate; int offset;
int offset = samp_frac_num*st->oversample/st->den_rate; spx_word16_t frac;
float frac = alpha*st->oversample - offset; 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);
#else
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. /* 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 For most DSPs, it would be best to split the loops in two because most DSPs
have only two accumulators */ have only two accumulators */
@ -263,16 +443,8 @@ static int resampler_basic_interpolate_single(SpeexResamplerState *st, int chann
accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
} }
/* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation cubic_coef(frac, interp);
but I know it's MMSE-optimal on a sinc */ 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]);
interp[0] = -0.16667f*frac + 0.16667f*frac*frac*frac;
interp[1] = frac + 0.5f*frac*frac - 0.5f*frac*frac*frac;
/*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/
interp[3] = -0.33333f*frac + 0.5f*frac*frac - 0.16667f*frac*frac*frac;
/* Just to make sure we don't have rounding problems */
interp[2] = 1.f-interp[0]-interp[1]-interp[3];
/*sum = frac*accum[1] + (1-frac)*accum[2];*/
sum = interp[0]*accum[0] + interp[1]*accum[1] + interp[2]*accum[2] + interp[3]*accum[3];
*out = PSHR32(sum,15); *out = PSHR32(sum,15);
out += st->out_stride; out += st->out_stride;
@ -290,6 +462,70 @@ static int resampler_basic_interpolate_single(SpeexResamplerState *st, int chann
return out_sample; return out_sample;
} }
#ifdef FIXED_POINT
#else
/* This is the same as the previous function, except with a double-precision accumulator */
static int resampler_basic_interpolate_double(SpeexResamplerState *st, int channel_index, const spx_word16_t *in, int *in_len, spx_word16_t *out, int *out_len)
{
int N = st->filt_len;
int out_sample = 0;
spx_word16_t *mem;
int last_sample = st->last_sample[channel_index];
int samp_frac_num = st->samp_frac_num[channel_index];
mem = st->mem + channel_index * st->mem_alloc_size;
while (!(last_sample >= *in_len || out_sample >= *out_len))
{
int j;
spx_word32_t sum=0;
/* We need to interpolate the sinc filter */
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]);
}
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]);
}
cubic_coef(frac, interp);
sum = interp[0]*accum[0] + interp[1]*accum[1] + interp[2]*accum[2] + interp[3]*accum[3];
*out = PSHR32(sum,15);
out += st->out_stride;
out_sample++;
last_sample += st->int_advance;
samp_frac_num += st->frac_advance;
if (samp_frac_num >= st->den_rate)
{
samp_frac_num -= st->den_rate;
last_sample++;
}
}
st->last_sample[channel_index] = last_sample;
st->samp_frac_num[channel_index] = samp_frac_num;
return out_sample;
}
#endif
static void update_filter(SpeexResamplerState *st) static void update_filter(SpeexResamplerState *st)
{ {
@ -328,11 +564,17 @@ static void update_filter(SpeexResamplerState *st)
int j; int j;
for (j=0;j<st->filt_len;j++) for (j=0;j<st->filt_len;j++)
{ {
st->sinc_table[i*st->filt_len+j] = sinc(st->cutoff,((j-st->filt_len/2+1)-((float)i)/st->den_rate), st->filt_len); st->sinc_table[i*st->filt_len+j] = sinc(st->cutoff,((j-st->filt_len/2+1)-((float)i)/st->den_rate), st->filt_len, quality_map[st->quality].window_func);
} }
} }
st->type = SPEEX_RESAMPLER_DIRECT_SINGLE; #ifdef FIXED_POINT
st->resampler_ptr = resampler_basic_direct_single; st->resampler_ptr = resampler_basic_direct_single;
#else
if (st->quality>8)
st->resampler_ptr = resampler_basic_direct_double;
else
st->resampler_ptr = resampler_basic_direct_single;
#endif
/*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/ /*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/
} else { } else {
if (!st->sinc_table) if (!st->sinc_table)
@ -343,9 +585,15 @@ static void update_filter(SpeexResamplerState *st)
st->sinc_table_length = st->filt_len*st->oversample+8; st->sinc_table_length = st->filt_len*st->oversample+8;
} }
for (i=-4;i<st->oversample*st->filt_len+4;i++) for (i=-4;i<st->oversample*st->filt_len+4;i++)
st->sinc_table[i+4] = sinc(st->cutoff,(i/(float)st->oversample - st->filt_len/2), st->filt_len); st->sinc_table[i+4] = sinc(st->cutoff,(i/(float)st->oversample - st->filt_len/2), st->filt_len, quality_map[st->quality].window_func);
st->type = SPEEX_RESAMPLER_INTERPOLATE_SINGLE; #ifdef FIXED_POINT
st->resampler_ptr = resampler_basic_interpolate_single; st->resampler_ptr = resampler_basic_interpolate_single;
#else
if (st->quality>8)
st->resampler_ptr = resampler_basic_interpolate_double;
else
st->resampler_ptr = resampler_basic_interpolate_single;
#endif
/*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/ /*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/
} }
st->int_advance = st->num_rate/st->den_rate; st->int_advance = st->num_rate/st->den_rate;
@ -405,8 +653,12 @@ static void update_filter(SpeexResamplerState *st)
} }
SpeexResamplerState *speex_resampler_init(int nb_channels, int in_rate, int out_rate, int quality)
{
return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality);
}
SpeexResamplerState *speex_resampler_init(int nb_channels, int ratio_num, int ratio_den, int in_rate, int out_rate, int quality) SpeexResamplerState *speex_resampler_init_frac(int nb_channels, int ratio_num, int ratio_den, int in_rate, int out_rate, int quality)
{ {
int i; int i;
SpeexResamplerState *st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState)); SpeexResamplerState *st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState));
@ -440,7 +692,7 @@ SpeexResamplerState *speex_resampler_init(int nb_channels, int ratio_num, int ra
} }
speex_resampler_set_quality(st, quality); speex_resampler_set_quality(st, quality);
speex_resampler_set_rate(st, ratio_num, ratio_den, in_rate, out_rate); speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate);
update_filter(st); update_filter(st);
@ -472,16 +724,26 @@ static void speex_resampler_process_native(SpeexResamplerState *st, int channel_
st->started = 1; st->started = 1;
/* Handle the case where we have samples left from a reduction in filter length */ /* Handle the case where we have samples left from a reduction in filter length */
if (st->magic_samples) if (st->magic_samples[channel_index])
{ {
int tmp_in_len; int tmp_in_len;
int tmp_magic;
tmp_in_len = st->magic_samples[channel_index]; tmp_in_len = st->magic_samples[channel_index];
tmp_out_len = *out_len; tmp_out_len = *out_len;
/* FIXME: Need to handle the case where the out array is too small */ /* FIXME: Need to handle the case where the out array is too small */
/* magic_samples needs to be set to zero to avoid infinite recursion */ /* magic_samples needs to be set to zero to avoid infinite recursion */
st->magic_samples = 0; tmp_magic = st->magic_samples[channel_index];
st->magic_samples[channel_index] = 0;
speex_resampler_process_native(st, channel_index, mem+N-1, &tmp_in_len, out, &tmp_out_len); speex_resampler_process_native(st, channel_index, mem+N-1, &tmp_in_len, out, &tmp_out_len);
/*speex_warning_int("extra samples:", tmp_out_len);*/ /*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)
{
int 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; out += tmp_out_len;
} }
@ -536,13 +798,13 @@ void speex_resampler_process_int(SpeexResamplerState *st, int channel_index, con
istride_save = st->in_stride; istride_save = st->in_stride;
ostride_save = st->out_stride; ostride_save = st->out_stride;
for (i=0;i<*in_len;i++) for (i=0;i<*in_len;i++)
x[i] = in[i+st->in_stride]; x[i] = in[i*st->in_stride];
st->in_stride = st->out_stride = 1; st->in_stride = st->out_stride = 1;
speex_resampler_process_native(st, channel_index, x, in_len, y, out_len); speex_resampler_process_native(st, channel_index, x, in_len, y, out_len);
st->in_stride = istride_save; st->in_stride = istride_save;
st->out_stride = ostride_save; st->out_stride = ostride_save;
for (i=0;i<*out_len;i++) for (i=0;i<*out_len;i++)
out[i+st->out_stride] = WORD2INT(y[i]); out[i*st->out_stride] = WORD2INT(y[i]);
} }
#endif #endif
@ -561,8 +823,33 @@ void speex_resampler_process_interleaved_float(SpeexResamplerState *st, const fl
st->out_stride = ostride_save; st->out_stride = ostride_save;
} }
void speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, int *in_len, spx_int16_t *out, int *out_len)
{
int i;
int istride_save, ostride_save;
istride_save = st->in_stride;
ostride_save = st->out_stride;
st->in_stride = st->out_stride = st->nb_channels;
for (i=0;i<st->nb_channels;i++)
{
speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len);
}
st->in_stride = istride_save;
st->out_stride = ostride_save;
}
void speex_resampler_set_rate(SpeexResamplerState *st, int ratio_num, int ratio_den, int in_rate, int out_rate) void speex_resampler_set_rate(SpeexResamplerState *st, int in_rate, int out_rate)
{
speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate);
}
void speex_resampler_get_rate(SpeexResamplerState *st, int *in_rate, int *out_rate)
{
*in_rate = st->in_rate;
*out_rate = st->out_rate;
}
void speex_resampler_set_rate_frac(SpeexResamplerState *st, int ratio_num, int ratio_den, int in_rate, int out_rate)
{ {
int fact; int fact;
if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den) if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den)
@ -586,6 +873,12 @@ void speex_resampler_set_rate(SpeexResamplerState *st, int ratio_num, int ratio_
update_filter(st); update_filter(st);
} }
void speex_resampler_get_ratio(SpeexResamplerState *st, int *ratio_num, int *ratio_den)
{
*ratio_num = st->num_rate;
*ratio_den = st->den_rate;
}
void speex_resampler_set_quality(SpeexResamplerState *st, int quality) void speex_resampler_set_quality(SpeexResamplerState *st, int quality)
{ {
if (quality < 0) if (quality < 0)
@ -599,16 +892,31 @@ void speex_resampler_set_quality(SpeexResamplerState *st, int quality)
update_filter(st); update_filter(st);
} }
void speex_resampler_get_quality(SpeexResamplerState *st, int *quality)
{
*quality = st->quality;
}
void speex_resampler_set_input_stride(SpeexResamplerState *st, int stride) void speex_resampler_set_input_stride(SpeexResamplerState *st, int stride)
{ {
st->in_stride = stride; st->in_stride = stride;
} }
void speex_resampler_get_input_stride(SpeexResamplerState *st, int *stride)
{
*stride = st->in_stride;
}
void speex_resampler_set_output_stride(SpeexResamplerState *st, int stride) void speex_resampler_set_output_stride(SpeexResamplerState *st, int stride)
{ {
st->out_stride = stride; st->out_stride = stride;
} }
void speex_resampler_get_output_stride(SpeexResamplerState *st, int *stride)
{
*stride = st->out_stride;
}
void speex_resampler_skip_zeros(SpeexResamplerState *st) void speex_resampler_skip_zeros(SpeexResamplerState *st)
{ {
int i; int i;

View file

@ -236,17 +236,8 @@ void *sb_encoder_init(const SpeexMode *m)
for (i=0;i<st->lpcSize+1;i++) for (i=0;i<st->lpcSize+1;i++)
st->lagWindow[i]=16384*exp(-.5*sqr(2*M_PI*st->lag_factor*i)); st->lagWindow[i]=16384*exp(-.5*sqr(2*M_PI*st->lag_factor*i));
st->autocorr = (spx_word16_t*)speex_alloc((st->lpcSize+1)*sizeof(spx_word16_t));
st->lpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t));
st->bw_lpc1 = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t));
st->bw_lpc2 = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t));
st->lsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t));
st->qlsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t));
st->old_lsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t)); st->old_lsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t));
st->old_qlsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t)); st->old_qlsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t));
st->interp_lsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t));
st->interp_qlsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t));
st->interp_lpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t));
st->interp_qlpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t)); st->interp_qlpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t));
st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t)); st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t));
st->exc_rms = (spx_word16_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word16_t)); st->exc_rms = (spx_word16_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word16_t));
@ -294,17 +285,8 @@ void sb_encoder_destroy(void *state)
speex_free(st->lagWindow); speex_free(st->lagWindow);
speex_free(st->autocorr);
speex_free(st->lpc);
speex_free(st->bw_lpc1);
speex_free(st->bw_lpc2);
speex_free(st->lsp);
speex_free(st->qlsp);
speex_free(st->old_lsp); speex_free(st->old_lsp);
speex_free(st->old_qlsp); speex_free(st->old_qlsp);
speex_free(st->interp_lsp);
speex_free(st->interp_qlsp);
speex_free(st->interp_lpc);
speex_free(st->interp_qlpc); speex_free(st->interp_qlpc);
speex_free(st->pi_gain); speex_free(st->pi_gain);
speex_free(st->exc_rms); speex_free(st->exc_rms);
@ -336,7 +318,15 @@ int sb_encode(void *state, void *vin, SpeexBits *bits)
spx_int32_t dtx; spx_int32_t dtx;
spx_word16_t *in = (spx_word16_t*)vin; spx_word16_t *in = (spx_word16_t*)vin;
spx_word16_t e_low=0, e_high=0; spx_word16_t e_low=0, e_high=0;
VARDECL(spx_coef_t *lpc);
VARDECL(spx_coef_t *interp_lpc);
VARDECL(spx_coef_t *bw_lpc1);
VARDECL(spx_coef_t *bw_lpc2);
VARDECL(spx_lsp_t *lsp);
VARDECL(spx_lsp_t *qlsp);
VARDECL(spx_lsp_t *interp_lsp);
VARDECL(spx_lsp_t *interp_qlsp);
st = (SBEncState*)state; st = (SBEncState*)state;
stack=st->stack; stack=st->stack;
mode = (const SpeexSBMode*)(st->mode->mode); mode = (const SpeexSBMode*)(st->mode->mode);
@ -378,8 +368,20 @@ int sb_encode(void *state, void *vin, SpeexBits *bits)
else else
dtx=0; dtx=0;
ALLOC(lpc, st->lpcSize, spx_coef_t);
ALLOC(interp_lpc, st->lpcSize, spx_coef_t);
ALLOC(bw_lpc1, st->lpcSize, spx_coef_t);
ALLOC(bw_lpc2, st->lpcSize, spx_coef_t);
ALLOC(lsp, st->lpcSize, spx_lsp_t);
ALLOC(qlsp, st->lpcSize, spx_lsp_t);
ALLOC(interp_lsp, st->lpcSize, spx_lsp_t);
ALLOC(interp_qlsp, st->lpcSize, spx_lsp_t);
{ {
VARDECL(spx_word16_t *autocorr);
VARDECL(spx_word16_t *w_sig); VARDECL(spx_word16_t *w_sig);
ALLOC(autocorr, st->lpcSize+1, spx_word16_t);
ALLOC(w_sig, st->windowSize, spx_word16_t); ALLOC(w_sig, st->windowSize, spx_word16_t);
/* Window for analysis */ /* Window for analysis */
/* FIXME: This is a kludge */ /* FIXME: This is a kludge */
@ -392,27 +394,27 @@ int sb_encode(void *state, void *vin, SpeexBits *bits)
w_sig[i] = EXTRACT16(SHR32(MULT16_16(high[i],st->window[i]),SIG_SHIFT)); w_sig[i] = EXTRACT16(SHR32(MULT16_16(high[i],st->window[i]),SIG_SHIFT));
} }
/* Compute auto-correlation */ /* Compute auto-correlation */
_spx_autocorr(w_sig, st->autocorr, st->lpcSize+1, st->windowSize); _spx_autocorr(w_sig, autocorr, st->lpcSize+1, st->windowSize);
autocorr[0] = ADD16(autocorr[0],MULT16_16_Q15(autocorr[0],st->lpc_floor)); /* Noise floor in auto-correlation domain */
/* Lag windowing: equivalent to filtering in the power-spectrum domain */
for (i=0;i<st->lpcSize+1;i++)
autocorr[i] = MULT16_16_Q14(autocorr[i],st->lagWindow[i]);
/* Levinson-Durbin */
_spx_lpc(lpc, autocorr, st->lpcSize);
} }
st->autocorr[0] = ADD16(st->autocorr[0],MULT16_16_Q15(st->autocorr[0],st->lpc_floor)); /* Noise floor in auto-correlation domain */
/* Lag windowing: equivalent to filtering in the power-spectrum domain */
for (i=0;i<st->lpcSize+1;i++)
st->autocorr[i] = MULT16_16_Q14(st->autocorr[i],st->lagWindow[i]);
/* Levinson-Durbin */
_spx_lpc(st->lpc, st->autocorr, st->lpcSize);
/* LPC to LSPs (x-domain) transform */ /* LPC to LSPs (x-domain) transform */
roots=lpc_to_lsp (st->lpc, st->lpcSize, st->lsp, 10, LSP_DELTA1, stack); roots=lpc_to_lsp (lpc, st->lpcSize, lsp, 10, LSP_DELTA1, stack);
if (roots!=st->lpcSize) if (roots!=st->lpcSize)
{ {
roots = lpc_to_lsp (st->lpc, st->lpcSize, st->lsp, 10, LSP_DELTA2, stack); roots = lpc_to_lsp (lpc, st->lpcSize, lsp, 10, LSP_DELTA2, stack);
if (roots!=st->lpcSize) { if (roots!=st->lpcSize) {
/*If we can't find all LSP's, do some damage control and use a flat filter*/ /*If we can't find all LSP's, do some damage control and use a flat filter*/
for (i=0;i<st->lpcSize;i++) for (i=0;i<st->lpcSize;i++)
{ {
st->lsp[i]=st->old_lsp[i]; lsp[i]=st->old_lsp[i];
} }
} }
} }
@ -524,14 +526,14 @@ int sb_encode(void *state, void *vin, SpeexBits *bits)
/* LSP quantization */ /* LSP quantization */
SUBMODE(lsp_quant)(st->lsp, st->qlsp, st->lpcSize, bits); SUBMODE(lsp_quant)(lsp, qlsp, st->lpcSize, bits);
if (st->first) if (st->first)
{ {
for (i=0;i<st->lpcSize;i++) for (i=0;i<st->lpcSize;i++)
st->old_lsp[i] = st->lsp[i]; st->old_lsp[i] = lsp[i];
for (i=0;i<st->lpcSize;i++) for (i=0;i<st->lpcSize;i++)
st->old_qlsp[i] = st->qlsp[i]; st->old_qlsp[i] = qlsp[i];
} }
ALLOC(mem, st->lpcSize, spx_mem_t); ALLOC(mem, st->lpcSize, spx_mem_t);
@ -557,17 +559,17 @@ int sb_encode(void *state, void *vin, SpeexBits *bits)
ALLOC(sw, st->subframeSize, spx_word16_t); ALLOC(sw, st->subframeSize, spx_word16_t);
/* LSP interpolation (quantized and unquantized) */ /* LSP interpolation (quantized and unquantized) */
lsp_interpolate(st->old_lsp, st->lsp, st->interp_lsp, st->lpcSize, sub, st->nbSubframes); lsp_interpolate(st->old_lsp, lsp, interp_lsp, st->lpcSize, sub, st->nbSubframes);
lsp_interpolate(st->old_qlsp, st->qlsp, st->interp_qlsp, st->lpcSize, sub, st->nbSubframes); lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpcSize, sub, st->nbSubframes);
lsp_enforce_margin(st->interp_lsp, st->lpcSize, LSP_MARGIN); lsp_enforce_margin(interp_lsp, st->lpcSize, LSP_MARGIN);
lsp_enforce_margin(st->interp_qlsp, st->lpcSize, LSP_MARGIN); lsp_enforce_margin(interp_qlsp, st->lpcSize, LSP_MARGIN);
lsp_to_lpc(st->interp_lsp, st->interp_lpc, st->lpcSize,stack); lsp_to_lpc(interp_lsp, interp_lpc, st->lpcSize,stack);
lsp_to_lpc(st->interp_qlsp, st->interp_qlpc, st->lpcSize, stack); lsp_to_lpc(interp_qlsp, st->interp_qlpc, st->lpcSize, stack);
bw_lpc(st->gamma1, st->interp_lpc, st->bw_lpc1, st->lpcSize); bw_lpc(st->gamma1, interp_lpc, bw_lpc1, st->lpcSize);
bw_lpc(st->gamma2, st->interp_lpc, st->bw_lpc2, st->lpcSize); bw_lpc(st->gamma2, interp_lpc, bw_lpc2, st->lpcSize);
/* Compute mid-band (4000 Hz for wideband) response of low-band and high-band /* Compute mid-band (4000 Hz for wideband) response of low-band and high-band
filters */ filters */
@ -650,7 +652,7 @@ int sb_encode(void *state, void *vin, SpeexBits *bits)
scale = SHL32(MULT16_16(PDIV32_16(SHL32(EXTEND32(gc),SIG_SHIFT-6),filter_ratio),(1+el)),6); scale = SHL32(MULT16_16(PDIV32_16(SHL32(EXTEND32(gc),SIG_SHIFT-6),filter_ratio),(1+el)),6);
compute_impulse_response(st->interp_qlpc, st->bw_lpc1, st->bw_lpc2, syn_resp, st->subframeSize, st->lpcSize, stack); compute_impulse_response(st->interp_qlpc, bw_lpc1, bw_lpc2, syn_resp, st->subframeSize, st->lpcSize, stack);
/* Reset excitation */ /* Reset excitation */
@ -664,12 +666,12 @@ int sb_encode(void *state, void *vin, SpeexBits *bits)
for (i=0;i<st->lpcSize;i++) for (i=0;i<st->lpcSize;i++)
mem[i]=st->mem_sw[i]; mem[i]=st->mem_sw[i];
filter_mem16(res, st->bw_lpc1, st->bw_lpc2, res, st->subframeSize, st->lpcSize, mem, stack); filter_mem16(res, bw_lpc1, bw_lpc2, res, st->subframeSize, st->lpcSize, mem, stack);
/* Compute weighted signal */ /* Compute weighted signal */
for (i=0;i<st->lpcSize;i++) for (i=0;i<st->lpcSize;i++)
mem[i]=st->mem_sw[i]; mem[i]=st->mem_sw[i];
filter_mem16(sp, st->bw_lpc1, st->bw_lpc2, sw, st->subframeSize, st->lpcSize, mem, stack); filter_mem16(sp, bw_lpc1, bw_lpc2, sw, st->subframeSize, st->lpcSize, mem, stack);
/* Compute target signal */ /* Compute target signal */
for (i=0;i<st->subframeSize;i++) for (i=0;i<st->subframeSize;i++)
@ -682,7 +684,7 @@ int sb_encode(void *state, void *vin, SpeexBits *bits)
innov[i]=0; innov[i]=0;
/*print_vec(target, st->subframeSize, "\ntarget");*/ /*print_vec(target, st->subframeSize, "\ntarget");*/
SUBMODE(innovation_quant)(target, st->interp_qlpc, st->bw_lpc1, st->bw_lpc2, SUBMODE(innovation_quant)(target, st->interp_qlpc, bw_lpc1, bw_lpc2,
SUBMODE(innovation_params), st->lpcSize, st->subframeSize, SUBMODE(innovation_params), st->lpcSize, st->subframeSize,
innov, syn_resp, bits, stack, st->complexity, SUBMODE(double_codebook)); innov, syn_resp, bits, stack, st->complexity, SUBMODE(double_codebook));
/*print_vec(target, st->subframeSize, "after");*/ /*print_vec(target, st->subframeSize, "after");*/
@ -698,7 +700,7 @@ int sb_encode(void *state, void *vin, SpeexBits *bits)
for (i=0;i<st->subframeSize;i++) for (i=0;i<st->subframeSize;i++)
target[i]=MULT16_16_P13(QCONST16(2.5f,13), target[i]); target[i]=MULT16_16_P13(QCONST16(2.5f,13), target[i]);
SUBMODE(innovation_quant)(target, st->interp_qlpc, st->bw_lpc1, st->bw_lpc2, SUBMODE(innovation_quant)(target, st->interp_qlpc, bw_lpc1, bw_lpc2,
SUBMODE(innovation_params), st->lpcSize, st->subframeSize, SUBMODE(innovation_params), st->lpcSize, st->subframeSize,
innov2, syn_resp, bits, stack, st->complexity, 0); innov2, syn_resp, bits, stack, st->complexity, 0);
signal_mul(innov2, innov2, MULT16_32_P15(QCONST16(0.4f,15),scale), st->subframeSize); signal_mul(innov2, innov2, MULT16_32_P15(QCONST16(0.4f,15),scale), st->subframeSize);
@ -727,13 +729,13 @@ int sb_encode(void *state, void *vin, SpeexBits *bits)
iir_mem16(exc, st->interp_qlpc, sp, st->subframeSize, st->lpcSize, st->mem_sp, stack); iir_mem16(exc, st->interp_qlpc, sp, st->subframeSize, st->lpcSize, st->mem_sp, stack);
/* Compute weighted signal again, from synthesized speech (not sure it's the right thing) */ /* Compute weighted signal again, from synthesized speech (not sure it's the right thing) */
filter_mem16(sp, st->bw_lpc1, st->bw_lpc2, sw, st->subframeSize, st->lpcSize, st->mem_sw, stack); filter_mem16(sp, bw_lpc1, bw_lpc2, sw, st->subframeSize, st->lpcSize, st->mem_sw, stack);
} }
for (i=0;i<st->lpcSize;i++) for (i=0;i<st->lpcSize;i++)
st->old_lsp[i] = st->lsp[i]; st->old_lsp[i] = lsp[i];
for (i=0;i<st->lpcSize;i++) for (i=0;i<st->lpcSize;i++)
st->old_qlsp[i] = st->qlsp[i]; st->old_qlsp[i] = qlsp[i];
st->first=0; st->first=0;
@ -786,9 +788,7 @@ void *sb_decoder_init(const SpeexMode *m)
st->excBuf = (spx_word16_t*)speex_alloc((st->subframeSize)*sizeof(spx_word16_t)); st->excBuf = (spx_word16_t*)speex_alloc((st->subframeSize)*sizeof(spx_word16_t));
st->qlsp = (spx_lsp_t*)speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
st->old_qlsp = (spx_lsp_t*)speex_alloc((st->lpcSize)*sizeof(spx_lsp_t)); st->old_qlsp = (spx_lsp_t*)speex_alloc((st->lpcSize)*sizeof(spx_lsp_t));
st->interp_qlsp = (spx_lsp_t*)speex_alloc(st->lpcSize*sizeof(spx_lsp_t));
st->interp_qlpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t)); st->interp_qlpc = (spx_coef_t*)speex_alloc(st->lpcSize*sizeof(spx_coef_t));
st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t)); st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t));
@ -819,9 +819,7 @@ void sb_decoder_destroy(void *state)
speex_free(st->g0_mem); speex_free(st->g0_mem);
speex_free(st->g1_mem); speex_free(st->g1_mem);
speex_free(st->excBuf); speex_free(st->excBuf);
speex_free(st->qlsp);
speex_free(st->old_qlsp); speex_free(st->old_qlsp);
speex_free(st->interp_qlsp);
speex_free(st->interp_qlpc); speex_free(st->interp_qlpc);
speex_free(st->pi_gain); speex_free(st->pi_gain);
speex_free(st->exc_rms); speex_free(st->exc_rms);
@ -878,6 +876,8 @@ int sb_decode(void *state, SpeexBits *bits, void *vout)
VARDECL(spx_word32_t *low_pi_gain); VARDECL(spx_word32_t *low_pi_gain);
VARDECL(spx_word16_t *low_exc_rms); VARDECL(spx_word16_t *low_exc_rms);
VARDECL(spx_coef_t *ak); VARDECL(spx_coef_t *ak);
VARDECL(spx_lsp_t *qlsp);
VARDECL(spx_lsp_t *interp_qlsp);
spx_int32_t dtx; spx_int32_t dtx;
const SpeexSBMode *mode; const SpeexSBMode *mode;
spx_word16_t *out = (spx_word16_t*)vout; spx_word16_t *out = (spx_word16_t*)vout;
@ -958,12 +958,14 @@ int sb_decode(void *state, SpeexBits *bits, void *vout)
speex_decoder_ctl(st->st_low, SPEEX_GET_PI_GAIN, low_pi_gain); speex_decoder_ctl(st->st_low, SPEEX_GET_PI_GAIN, low_pi_gain);
speex_decoder_ctl(st->st_low, SPEEX_GET_EXC, low_exc_rms); speex_decoder_ctl(st->st_low, SPEEX_GET_EXC, low_exc_rms);
SUBMODE(lsp_unquant)(st->qlsp, st->lpcSize, bits); ALLOC(qlsp, st->lpcSize, spx_lsp_t);
ALLOC(interp_qlsp, st->lpcSize, spx_lsp_t);
SUBMODE(lsp_unquant)(qlsp, st->lpcSize, bits);
if (st->first) if (st->first)
{ {
for (i=0;i<st->lpcSize;i++) for (i=0;i<st->lpcSize;i++)
st->old_qlsp[i] = st->qlsp[i]; st->old_qlsp[i] = qlsp[i];
} }
ALLOC(ak, st->lpcSize, spx_coef_t); ALLOC(ak, st->lpcSize, spx_coef_t);
@ -990,12 +992,12 @@ int sb_decode(void *state, SpeexBits *bits, void *vout)
} }
/* LSP interpolation */ /* LSP interpolation */
lsp_interpolate(st->old_qlsp, st->qlsp, st->interp_qlsp, st->lpcSize, sub, st->nbSubframes); lsp_interpolate(st->old_qlsp, qlsp, interp_qlsp, st->lpcSize, sub, st->nbSubframes);
lsp_enforce_margin(st->interp_qlsp, st->lpcSize, LSP_MARGIN); lsp_enforce_margin(interp_qlsp, st->lpcSize, LSP_MARGIN);
/* LSP to LPC */ /* LSP to LPC */
lsp_to_lpc(st->interp_qlsp, ak, st->lpcSize, stack); lsp_to_lpc(interp_qlsp, ak, st->lpcSize, stack);
/* Calculate reponse ratio between the low and high filter in the middle /* Calculate reponse ratio between the low and high filter in the middle
of the band (4000 Hz) */ of the band (4000 Hz) */
@ -1087,7 +1089,7 @@ int sb_decode(void *state, SpeexBits *bits, void *vout)
qmf_synth(out, out+st->frame_size, h0, out, st->full_frame_size, QMF_ORDER, st->g0_mem, st->g1_mem, stack); qmf_synth(out, out+st->frame_size, h0, out, st->full_frame_size, QMF_ORDER, st->g0_mem, st->g1_mem, stack);
for (i=0;i<st->lpcSize;i++) for (i=0;i<st->lpcSize;i++)
st->old_qlsp[i] = st->qlsp[i]; st->old_qlsp[i] = qlsp[i];
st->first=0; st->first=0;
@ -1245,7 +1247,7 @@ int sb_encoder_ctl(void *state, int request, void *ptr)
int i; int i;
st->first = 1; st->first = 1;
for (i=0;i<st->lpcSize;i++) for (i=0;i<st->lpcSize;i++)
st->lsp[i]=(M_PI*((float)(i+1)))/(st->lpcSize+1); st->old_lsp[i]=(M_PI*((float)(i+1)))/(st->lpcSize+1);
for (i=0;i<st->lpcSize;i++) for (i=0;i<st->lpcSize;i++)
st->mem_sw[i]=st->mem_sp[i]=st->mem_sp2[i]=0; st->mem_sw[i]=st->mem_sp[i]=st->mem_sp2[i]=0;
for (i=0;i<QMF_ORDER;i++) for (i=0;i<QMF_ORDER;i++)

View file

@ -63,18 +63,9 @@ typedef struct SBEncState {
const spx_word16_t *window; /**< LPC analysis window */ const spx_word16_t *window; /**< LPC analysis window */
spx_word16_t *lagWindow; /**< Auto-correlation window */ spx_word16_t *lagWindow; /**< Auto-correlation window */
spx_word16_t *autocorr; /**< Auto-correlation (for LPC analysis) */
spx_coef_t *lpc; /**< LPC coefficients */
spx_lsp_t *lsp; /**< LSP coefficients */
spx_lsp_t *qlsp; /**< Quantized LSPs */
spx_lsp_t *old_lsp; /**< LSPs of previous frame */ spx_lsp_t *old_lsp; /**< LSPs of previous frame */
spx_lsp_t *old_qlsp; /**< Quantized LSPs of previous frame */ spx_lsp_t *old_qlsp; /**< Quantized LSPs of previous frame */
spx_lsp_t *interp_lsp; /**< Interpolated LSPs for current sub-frame */
spx_lsp_t *interp_qlsp; /**< Interpolated quantized LSPs for current sub-frame */
spx_coef_t *interp_lpc; /**< Interpolated LPCs for current sub-frame */
spx_coef_t *interp_qlpc; /**< Interpolated quantized LPCs for current sub-frame */ spx_coef_t *interp_qlpc; /**< Interpolated quantized LPCs for current sub-frame */
spx_coef_t *bw_lpc1; /**< Bandwidth-expanded version of LPCs (#1) */
spx_coef_t *bw_lpc2; /**< Bandwidth-expanded version of LPCs (#2) */
spx_mem_t *mem_sp; /**< Synthesis signal memory */ spx_mem_t *mem_sp; /**< Synthesis signal memory */
spx_mem_t *mem_sp2; spx_mem_t *mem_sp2;
@ -121,9 +112,7 @@ typedef struct SBDecState {
spx_word32_t *g0_mem, *g1_mem; spx_word32_t *g0_mem, *g1_mem;
spx_word16_t *excBuf; spx_word16_t *excBuf;
spx_lsp_t *qlsp;
spx_lsp_t *old_qlsp; spx_lsp_t *old_qlsp;
spx_lsp_t *interp_qlsp;
spx_coef_t *interp_qlpc; spx_coef_t *interp_qlpc;
spx_mem_t *mem_sp; spx_mem_t *mem_sp;

View file

@ -155,20 +155,6 @@ extern "C" {
/** Get status of input/output high-pass filtering */ /** Get status of input/output high-pass filtering */
#define SPEEX_GET_HIGHPASS 45 #define SPEEX_GET_HIGHPASS 45
/* Used internally, NOT TO BE USED in applications */
/** Used internally*/
#define SPEEX_GET_PI_GAIN 100
/** Used internally*/
#define SPEEX_GET_EXC 101
/** Used internally*/
#define SPEEX_GET_INNOV 102
/** Used internally*/
#define SPEEX_GET_DTX_STATUS 103
/** Used internally*/
#define SPEEX_SET_INNOVATION_SAVE 104
/** Used internally*/
#define SPEEX_SET_WIDEBAND 105
/* Preserving compatibility:*/ /* Preserving compatibility:*/
/** Equivalent to SPEEX_SET_ENH */ /** Equivalent to SPEEX_SET_ENH */
@ -322,7 +308,9 @@ void speex_encoder_destroy(void *state);
/** Uses an existing encoder state to encode one frame of speech pointed to by /** Uses an existing encoder state to encode one frame of speech pointed to by
"in". The encoded bit-stream is saved in "bits". "in". The encoded bit-stream is saved in "bits".
@param state Encoder state @param state Encoder state
@param in Frame that will be encoded with a +-2^15 range @param in Frame that will be encoded with a +-2^15 range. This data MAY be
overwritten by the encoder and should be considered uninitialised
after the call.
@param bits Bit-stream where the data will be written @param bits Bit-stream where the data will be written
@return 0 if frame needs not be transmitted (DTX only), 1 otherwise @return 0 if frame needs not be transmitted (DTX only), 1 otherwise
*/ */

View file

@ -81,7 +81,13 @@ struct _JitterBufferPacket {
#define JITTER_BUFFER_SET_MARGIN 0 #define JITTER_BUFFER_SET_MARGIN 0
/** Get minimum amount of extra buffering required (margin) */ /** Get minimum amount of extra buffering required (margin) */
#define JITTER_BUFFER_GET_MARGIN 1 #define JITTER_BUFFER_GET_MARGIN 1
/* JITTER_BUFFER_SET_AVALIABLE_COUNT wouldn't make sense */
/** Get the amount of avaliable packets currently buffered */
#define JITTER_BUFFER_GET_AVALIABLE_COUNT 3
#define JITTER_BUFFER_ADJUST_INTERPOLATE -1
#define JITTER_BUFFER_ADJUST_OK 0
#define JITTER_BUFFER_ADJUST_DROP 1
/** Initialises jitter buffer /** Initialises jitter buffer
* *
@ -138,6 +144,8 @@ void jitter_buffer_tick(JitterBuffer *jitter);
*/ */
int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr); int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr);
int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint32_t *start_offset);
/* @} */ /* @} */
/** @defgroup SpeexJitter SpeexJitter: Adaptive jitter buffer specifically for Speex /** @defgroup SpeexJitter SpeexJitter: Adaptive jitter buffer specifically for Speex

View file

@ -1,60 +0,0 @@
/* Copyright (C) 2004 CSIRO Australia */
/* Copyright (C) 2002 Jean-Marc Valin*/
/**
@file speex_noglobals.h
@brief Dynamically allocates the different modes of the codec
*/
/*
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.
*/
#ifndef SPEEX_NOGLOBALS_H
#define SPEEX_NOGLOBALS_H
/* See README.symbian in the Speex source distribution for information
* on using this API */
typedef struct SpeexMode SpeexMode;
#ifdef __cplusplus
extern "C" {
#endif
/** Instantiate a mode */
const SpeexMode * speex_mode_new (int modeID);
/** Destroy a mode */
void speex_mode_destroy (const SpeexMode * mode);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -41,22 +41,59 @@
#ifdef OUTSIDE_SPEEX #ifdef OUTSIDE_SPEEX
/********* WARNING: MENTAL SANITY ENDS HERE *************/
/* If the resampler is defined outside of Speex, we change the symbol names so that
there won't be any clash if linking with Speex later on. */
/* #define RANDOM_PREFIX your software name here */
#ifndef RANDOM_PREFIX
#error "Please define RANDOM_PREFIX (above) to something specific to your project to prevent symbol name clashes"
#endif
#define CAT_PREFIX2(a,b) a ## b
#define CAT_PREFIX(a,b) CAT_PREFIX2(a, b)
#define speex_resampler_init CAT_PREFIX(RANDOM_PREFIX,_resampler_init)
#define speex_resampler_init_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_init_frac)
#define speex_resampler_destroy CAT_PREFIX(RANDOM_PREFIX,_resampler_destroy)
#define speex_resampler_process_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_float)
#define speex_resampler_process_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_int)
#define speex_resampler_process_interleaved_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_float)
#define speex_resampler_process_interleaved_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_int)
#define speex_resampler_set_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate)
#define speex_resampler_get_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_get_rate)
#define speex_resampler_set_rate_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate_frac)
#define speex_resampler_get_ratio CAT_PREFIX(RANDOM_PREFIX,_resampler_get_ratio)
#define speex_resampler_set_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_set_quality)
#define speex_resampler_get_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_get_quality)
#define speex_resampler_set_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_input_stride)
#define speex_resampler_get_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_stride)
#define speex_resample_set_output_stride CAT_PREFIX(RANDOM_PREFIX,_resample_set_output_stride)
#define speex_resample_get_output_stride CAT_PREFIX(RANDOM_PREFIX,_resample_get_output_stride)
#define speex_resampler_skip_zeros CAT_PREFIX(RANDOM_PREFIX,_resampler_skip_zeros)
#define speex_resampler_reset_mem CAT_PREFIX(RANDOM_PREFIX,_resampler_reset_mem)
#define spx_int16_t short #define spx_int16_t short
#ifdef FIXED_POINT #ifdef FIXED_POINT
#define spx_word16_t short #define spx_word16_t short
#define spx_word32_t int #define spx_word32_t int
#else
#else /* FIXED_POINT */
#define spx_word16_t float #define spx_word16_t float
#define spx_word32_t float #define spx_word32_t float
#define MULT16_16(a,b) ((a)*(b)) #define MULT16_16(a,b) ((a)*(b))
#define MULT16_32_Q15(a,b) ((a)*(b))
#define PSHR32(a,b) (a) #define PSHR32(a,b) (a)
#endif #endif /* FIXED_POINT */
#else #else /* OUTSIDE_SPEEX */
#include "speex_types.h" #include "speex_types.h"
#endif #endif /* OUTSIDE_SPEEX */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -71,81 +108,201 @@ extern "C" {
struct SpeexResamplerState_; struct SpeexResamplerState_;
typedef struct SpeexResamplerState_ SpeexResamplerState; typedef struct SpeexResamplerState_ SpeexResamplerState;
/** Create a new resampler. The sampling rate ratio is an arbitrary rational number /** Create a new resampler with integer input and output rates.
* with both the numerator and denominator being 32-bit integers. * @param nb_channels Number of channels to be processed
* @param in_rate Input sampling rate (integer number of Hz).
* @param out_rate Output sampling rate (integer number of Hz).
* @param quality Resampling quality between 0 and 10, where 0 has poor quality
* and 10 has very high quality.
* @return Newly created resampler state
* @retval NULL Error: not enough memory
*/
SpeexResamplerState *speex_resampler_init(int nb_channels,
int in_rate,
int out_rate,
int quality);
/** Create a new resampler with fractional input/output rates. The sampling
* rate ratio is an arbitrary rational number with both the numerator and
* denominator being 32-bit integers.
* @param nb_channels Number of channels to be processed * @param nb_channels Number of channels to be processed
* @param ratio_num Numerator of the sampling rate ratio * @param ratio_num Numerator of the sampling rate ratio
* @param ratio_den Denominator of the sampling rate ratio * @param ratio_den Denominator of the sampling rate ratio
* @param in_rate Nominal input sampling rate rounded to the nearest integer (in Hz). This does not need to be accurate. * @param in_rate Input sampling rate rounded to the nearest integer (in Hz).
* @param out_rate Nominal output sampling rate rounded to the nearest integer (in Hz). This does not need to be accurate. * @param out_rate Output sampling rate rounded to the nearest integer (in Hz).
* @param quality Resampling quality between 0 and 10, where 0 has poor quality and 10 has very high quality. * @param quality Resampling quality between 0 and 10, where 0 has poor quality
* and 10 has very high quality.
* @return Newly created resampler state * @return Newly created resampler state
* @retval NULL Error: not enough memory
*/ */
SpeexResamplerState *speex_resampler_init(int nb_channels, int ratio_num, int ratio_den, int in_rate, int out_rate, int quality); SpeexResamplerState *speex_resampler_init_frac(int nb_channels,
int ratio_num,
int ratio_den,
int in_rate,
int out_rate,
int quality);
/** Destroy a resampler state. /** Destroy a resampler state.
* @param st Resampler state * @param st Resampler state
*/ */
void speex_resampler_destroy(SpeexResamplerState *st); void speex_resampler_destroy(SpeexResamplerState *st);
/** Resample a float array. The input and output may *not* alias. /** Resample a float array. The input and output buffers must *not* overlap.
* @param st Resampler state * @param st Resampler state
* @param channel_index Index of the channel to process for the multi-channel base (0 otherwise) * @param channel_index Index of the channel to process for the multi-channel
* base (0 otherwise)
* @param in Input buffer * @param in Input buffer
* @param in_len Number of input samples in the input buffer. Returns the number of samples processed * @param in_len Number of input samples in the input buffer. Returns the
* number of samples processed
* @param out Output buffer * @param out Output buffer
* @param out_len Size of the output buffer. Returns the number of samples written * @param out_len Size of the output buffer. Returns the number of samples written
*/ */
void speex_resampler_process_float(SpeexResamplerState *st, int channel_index, const float *in, int *in_len, float *out, int *out_len); void speex_resampler_process_float(SpeexResamplerState *st,
int channel_index,
const float *in,
int *in_len,
float *out,
int *out_len);
/** Resample an int array. The input and output may *not* alias. /** Resample an int array. The input and output buffers must *not* overlap.
* @param st Resampler state * @param st Resampler state
* @param channel_index Index of the channel to process for the multi-channel base (0 otherwise) * @param channel_index Index of the channel to process for the multi-channel
* base (0 otherwise)
* @param in Input buffer * @param in Input buffer
* @param in_len Number of input samples in the input buffer. Returns the number of samples processed * @param in_len Number of input samples in the input buffer. Returns the number
* of samples processed
* @param out Output buffer * @param out Output buffer
* @param out_len Size of the output buffer. Returns the number of samples written * @param out_len Size of the output buffer. Returns the number of samples written
*/ */
void speex_resampler_process_int(SpeexResamplerState *st, int channel_index, const spx_int16_t *in, int *in_len, spx_int16_t *out, int *out_len); void speex_resampler_process_int(SpeexResamplerState *st,
int channel_index,
const spx_int16_t *in,
int *in_len,
spx_int16_t *out,
int *out_len);
/** Resample an interleaved float array. The input and output may *not* alias. /** Resample an interleaved float array. The input and output buffers must *not* overlap.
* @param st Resampler state * @param st Resampler state
* @param in Input buffer * @param in Input buffer
* @param in_len Number of input samples in the input buffer. Returns the number of samples processed. This is all per-channel. * @param in_len Number of input samples in the input buffer. Returns the number
* of samples processed. This is all per-channel.
* @param out Output buffer * @param out Output buffer
* @param out_len Size of the output buffer. Returns the number of samples written. This is all per-channel. * @param out_len Size of the output buffer. Returns the number of samples written.
* This is all per-channel.
*/ */
void speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, int *in_len, float *out, int *out_len); void speex_resampler_process_interleaved_float(SpeexResamplerState *st,
const float *in,
int *in_len,
float *out,
int *out_len);
/** Set (change) the input/output sampling rates and resampling ratio. /** Resample an interleaved int array. The input and output buffers must *not* overlap.
* @param st Resampler state
* @param in Input buffer
* @param in_len Number of input samples in the input buffer. Returns the number
* of samples processed. This is all per-channel.
* @param out Output buffer
* @param out_len Size of the output buffer. Returns the number of samples written.
* This is all per-channel.
*/
void speex_resampler_process_interleaved_int(SpeexResamplerState *st,
const spx_int16_t *in,
int *in_len,
spx_int16_t *out,
int *out_len);
/** Set (change) the input/output sampling rates (integer value).
* @param st Resampler state
* @param in_rate Input sampling rate (integer number of Hz).
* @param out_rate Output sampling rate (integer number of Hz).
*/
void speex_resampler_set_rate(SpeexResamplerState *st,
int in_rate,
int out_rate);
/** Get the current input/output sampling rates (integer value).
* @param st Resampler state
* @param in_rate Input sampling rate (integer number of Hz) copied.
* @param out_rate Output sampling rate (integer number of Hz) copied.
*/
void speex_resampler_get_rate(SpeexResamplerState *st,
int *in_rate,
int *out_rate);
/** Set (change) the input/output sampling rates and resampling ratio
* (fractional values in Hz supported).
* @param st Resampler state * @param st Resampler state
* @param ratio_num Numerator of the sampling rate ratio * @param ratio_num Numerator of the sampling rate ratio
* @param ratio_den Denominator of the sampling rate ratio * @param ratio_den Denominator of the sampling rate ratio
* @param in_rate Nominal input sampling rate rounded to the nearest integer (in Hz). This does not need to be accurate. * @param in_rate Input sampling rate rounded to the nearest integer (in Hz).
* @param out_rate Nominal output sampling rate rounded to the nearest integer (in Hz). This does not need to be accurate. * @param out_rate Output sampling rate rounded to the nearest integer (in Hz).
*/ */
void speex_resampler_set_rate(SpeexResamplerState *st, int ratio_num, int ratio_den, int in_rate, int out_rate); void speex_resampler_set_rate_frac(SpeexResamplerState *st,
int ratio_num,
int ratio_den,
int in_rate,
int out_rate);
/** Get the current resampling ratio. This will be reduced to the least
* common denominator.
* @param st Resampler state
* @param ratio_num Numerator of the sampling rate ratio copied
* @param ratio_den Denominator of the sampling rate ratio copied
*/
void speex_resampler_get_ratio(SpeexResamplerState *st,
int *ratio_num,
int *ratio_den);
/** Set (change) the conversion quality. /** Set (change) the conversion quality.
* @param st Resampler state * @param st Resampler state
* @param quality Resampling quality between 0 and 10, where 0 has poor quality and 10 has very high quality. * @param quality Resampling quality between 0 and 10, where 0 has poor
* quality and 10 has very high quality.
*/ */
void speex_resampler_set_quality(SpeexResamplerState *st, int quality); void speex_resampler_set_quality(SpeexResamplerState *st,
int quality);
/** Get the conversion quality.
* @param st Resampler state
* @param quality Resampling quality between 0 and 10, where 0 has poor
* quality and 10 has very high quality.
*/
void speex_resampler_get_quality(SpeexResamplerState *st,
int *quality);
/** Set (change) the input stride. /** Set (change) the input stride.
* @param st Resampler state * @param st Resampler state
* @param stride Input stride * @param stride Input stride
*/ */
void speex_resampler_set_input_stride(SpeexResamplerState *st, int stride); void speex_resampler_set_input_stride(SpeexResamplerState *st,
int stride);
/** Get the input stride.
* @param st Resampler state
* @param stride Input stride copied
*/
void speex_resampler_get_input_stride(SpeexResamplerState *st,
int *stride);
/** Set (change) the output stride. /** Set (change) the output stride.
* @param st Resampler state * @param st Resampler state
* @param stride Output stride * @param stride Output stride
*/ */
void speex_resample_set_output_stride(SpeexResamplerState *st, int stride); void speex_resample_set_output_stride(SpeexResamplerState *st,
int stride);
/** Make sure that the first samples to go out of the resamplers don't have leading zeros. /** Get the output stride.
* This is only useful before starting to use a newly created resampler. * @param st Resampler state copied
* @param stride Output stride
*/
void speex_resample_get_output_stride(SpeexResamplerState *st,
int *stride);
/** Make sure that the first samples to go out of the resamplers don't have
* leading zeros. This is only useful before starting to use a newly created
* resampler. It is recommended to use that when resampling an audio file, as
* it will generate a file with the same length. For real-time processing,
* it is probably easier not to use this call (so that the output duration
* is the same for the first frame).
* @param st Resampler state * @param st Resampler state
*/ */
void speex_resampler_skip_zeros(SpeexResamplerState *st); void speex_resampler_skip_zeros(SpeexResamplerState *st);

View file

@ -48,8 +48,8 @@ int main(int argc, char **argv)
short *out; short *out;
float *fin, *fout; float *fin, *fout;
int count = 0; int count = 0;
SpeexResamplerState *st = speex_resampler_init(1, 8000, 12000, 8000, 12000, 5); SpeexResamplerState *st = speex_resampler_init(1, 8000, 12000, 10);
speex_resampler_set_rate(st, 16000, 8001, 8000, 15999); speex_resampler_set_rate(st, 8000, 15999);
speex_resampler_skip_zeros(st); speex_resampler_skip_zeros(st);
in = malloc(NN*sizeof(short)); in = malloc(NN*sizeof(short));
@ -67,9 +67,12 @@ int main(int argc, char **argv)
fin[i]=in[i]; fin[i]=in[i];
in_len = NN; in_len = NN;
out_len = 2*NN; out_len = 2*NN;
/*if (count==2)
speex_resampler_set_quality(st, 10);*/
speex_resampler_process_float(st, 0, fin, &in_len, fout, &out_len); speex_resampler_process_float(st, 0, fin, &in_len, fout, &out_len);
for (i=0;i<out_len;i++) for (i=0;i<out_len;i++)
out[i]=floor(.5+fout[i]); out[i]=floor(.5+fout[i]);
/*speex_warning_int("writing", out_len);*/
fwrite(out, sizeof(short), out_len, stdout); fwrite(out, sizeof(short), out_len, stdout);
count++; count++;
} }

View file

@ -30,20 +30,18 @@
#define CHUNKSIZE 10000 /*2kb*/ #define CHUNKSIZE 10000 /*2kb*/
#define SEEK_CHUNKSIZE 7*CHUNKSIZE #define SEEK_CHUNKSIZE 7*CHUNKSIZE
//#define LOGF(...)
CODEC_HEADER CODEC_HEADER
struct codec_api *rb; spx_int16_t output[MAX_FRAME_SIZE] IBSS_ATTR;
int get_more_data(spx_ogg_sync_state *oy,struct codec_api *rb) int get_more_data(spx_ogg_sync_state *oy)
{ {
int bytes; int bytes;
char *buffer; char *buffer;
buffer = (char *)spx_ogg_sync_buffer(oy,CHUNKSIZE); buffer = (char *)spx_ogg_sync_buffer(oy,CHUNKSIZE);
bytes = rb->read_filebuf(buffer, sizeof(char)*CHUNKSIZE); bytes = ci->read_filebuf(buffer, sizeof(char)*CHUNKSIZE);
spx_ogg_sync_wrote(oy,bytes); spx_ogg_sync_wrote(oy,bytes);
@ -53,14 +51,14 @@ int get_more_data(spx_ogg_sync_state *oy,struct codec_api *rb)
/* The read/seek functions track absolute position within the stream */ /* The read/seek functions track absolute position within the stream */
static spx_int64_t get_next_page(spx_ogg_sync_state *oy,spx_ogg_page *og, static spx_int64_t get_next_page(spx_ogg_sync_state *oy,spx_ogg_page *og,
spx_int64_t boundary,struct codec_api *rb) spx_int64_t boundary)
{ {
spx_int64_t localoffset = rb->curpos; spx_int64_t localoffset = ci->curpos;
long more; long more;
long ret; long ret;
if (boundary > 0) if (boundary > 0)
boundary += rb->curpos; boundary += ci->curpos;
while (1) { while (1) {
more = spx_ogg_sync_pageseek(oy,og); more = spx_ogg_sync_pageseek(oy,og);
@ -73,7 +71,7 @@ static spx_int64_t get_next_page(spx_ogg_sync_state *oy,spx_ogg_page *og,
/* send more paramedics */ /* send more paramedics */
if(!boundary)return(-1); if(!boundary)return(-1);
{ {
ret = get_more_data(oy,rb); ret = get_more_data(oy);
if (ret == 0) if (ret == 0)
return(-2); return(-2);
@ -93,12 +91,11 @@ static spx_int64_t get_next_page(spx_ogg_sync_state *oy,spx_ogg_page *og,
} }
static spx_int64_t seek_backwards(spx_ogg_sync_state *oy, spx_ogg_page *og, static spx_int64_t seek_backwards(spx_ogg_sync_state *oy, spx_ogg_page *og,
spx_int64_t wantedpos, spx_int64_t wantedpos)
struct codec_api *rb)
{ {
spx_int64_t crofs; spx_int64_t crofs;
spx_int64_t *curoffset=&crofs; spx_int64_t *curoffset=&crofs;
*curoffset=rb->curpos; *curoffset=ci->curpos;
spx_int64_t begin=*curoffset; spx_int64_t begin=*curoffset;
spx_int64_t end=begin; spx_int64_t end=begin;
spx_int64_t ret; spx_int64_t ret;
@ -124,14 +121,14 @@ static spx_int64_t seek_backwards(spx_ogg_sync_state *oy, spx_ogg_page *og,
*curoffset = begin; *curoffset = begin;
rb->seek_buffer(*curoffset); ci->seek_buffer(*curoffset);
spx_ogg_sync_reset(oy); spx_ogg_sync_reset(oy);
lastgranule = -1; lastgranule = -1;
while (*curoffset < end) { while (*curoffset < end) {
ret = get_next_page(oy,og,end-*curoffset,rb); ret = get_next_page(oy,og,end-*curoffset);
if (ret > 0) { if (ret > 0) {
if (lastgranule != -1) { if (lastgranule != -1) {
@ -184,8 +181,7 @@ static spx_int64_t seek_backwards(spx_ogg_sync_state *oy, spx_ogg_page *og,
int speex_seek_page_granule(spx_int64_t pos, spx_int64_t curpos, int speex_seek_page_granule(spx_int64_t pos, spx_int64_t curpos,
spx_ogg_sync_state *oy, spx_ogg_sync_state *oy,
spx_int64_t headerssize, spx_int64_t headerssize)
struct codec_api *rb)
{ {
/* TODO: Someone may want to try to implement seek to packet, /* TODO: Someone may want to try to implement seek to packet,
instead of just to page (should be more accurate, not be any instead of just to page (should be more accurate, not be any
@ -193,7 +189,7 @@ int speex_seek_page_granule(spx_int64_t pos, spx_int64_t curpos,
spx_int64_t crofs; spx_int64_t crofs;
spx_int64_t *curbyteoffset = &crofs; spx_int64_t *curbyteoffset = &crofs;
*curbyteoffset = rb->curpos; *curbyteoffset = ci->curpos;
spx_int64_t curoffset; spx_int64_t curoffset;
curoffset = *curbyteoffset; curoffset = *curbyteoffset;
spx_int64_t offset = 0; spx_int64_t offset = 0;
@ -217,31 +213,31 @@ int speex_seek_page_granule(spx_int64_t pos, spx_int64_t curpos,
//spx_int64_t toffset=curoffset; //spx_int64_t toffset=curoffset;
rb->seek_buffer(curoffset); ci->seek_buffer(curoffset);
spx_ogg_sync_reset(oy); spx_ogg_sync_reset(oy);
offset = get_next_page(oy,&og,-1,rb); offset = get_next_page(oy,&og,-1);
if (offset < 0) { /* could not find new page,use old offset */ if (offset < 0) { /* could not find new page,use old offset */
LOGF("Seek/guess/fault:%d->-<-%d,%d:%d,%d,%d\n", LOGF("Seek/guess/fault:%d->-<-%d,%d:%d,%d,%d\n",
curpos,0,pos,offset,0, curpos,0,pos,offset,0,
rb->curpos,/*stream_length*/0); ci->curpos,/*stream_length*/0);
curoffset = *curbyteoffset; curoffset = *curbyteoffset;
rb->seek_buffer(curoffset); ci->seek_buffer(curoffset);
spx_ogg_sync_reset(oy); spx_ogg_sync_reset(oy);
} else { } else {
if (spx_ogg_page_granulepos(&og) == 0 && pos > 5000) { if (spx_ogg_page_granulepos(&og) == 0 && pos > 5000) {
LOGF("SEEK/guess/fault:%d->-<-%d,%d:%d,%d,%d\n", LOGF("SEEK/guess/fault:%d->-<-%d,%d:%d,%d,%d\n",
curpos,spx_ogg_page_granulepos(&og),pos, curpos,spx_ogg_page_granulepos(&og),pos,
offset,0,rb->curpos,/*stream_length*/0); offset,0,ci->curpos,/*stream_length*/0);
curoffset = *curbyteoffset; curoffset = *curbyteoffset;
rb->seek_buffer(curoffset); ci->seek_buffer(curoffset);
spx_ogg_sync_reset(oy); spx_ogg_sync_reset(oy);
} else { } else {
@ -254,7 +250,7 @@ int speex_seek_page_granule(spx_int64_t pos, spx_int64_t curpos,
/* which way do we want to seek? */ /* which way do we want to seek? */
if (curpos > pos) { /* backwards */ if (curpos > pos) { /* backwards */
offset = seek_backwards(oy,&og,pos,rb); offset = seek_backwards(oy,&og,pos);
if (offset > 0) { if (offset > 0) {
*curbyteoffset = curoffset; *curbyteoffset = curoffset;
@ -262,7 +258,7 @@ int speex_seek_page_granule(spx_int64_t pos, spx_int64_t curpos,
} }
} else { /* forwards */ } else { /* forwards */
while ( (offset = get_next_page(oy,&og,-1,rb)) > 0) { while ( (offset = get_next_page(oy,&og,-1)) > 0) {
if (lastgranule != -1) { if (lastgranule != -1) {
if (avgpagelen < 0) if (avgpagelen < 0)
avgpagelen = (spx_ogg_page_granulepos(&og) - lastgranule); avgpagelen = (spx_ogg_page_granulepos(&og) - lastgranule);
@ -286,13 +282,13 @@ int speex_seek_page_granule(spx_int64_t pos, spx_int64_t curpos,
} }
} }
rb->seek_buffer(*curbyteoffset); ci->seek_buffer(*curbyteoffset);
spx_ogg_sync_reset(oy); spx_ogg_sync_reset(oy);
LOGF("Seek failed:%d\n", offset); LOGF("Seek failed:%d\n", offset);
rb->splash(HZ*2, true, "Seek failed"); ci->splash(HZ*2, true, "Seek failed");
return -1; return -1;
} }
@ -327,7 +323,7 @@ static void *process_header(spx_ogg_packet *op,
modeID = header->mode; modeID = header->mode;
mode = speex_lib_get_mode (modeID); mode = speex_lib_get_mode(modeID);
if (header->speex_version_id > 1) { if (header->speex_version_id > 1) {
DEBUGF("Undecodeable bitstream"); DEBUGF("Undecodeable bitstream");
@ -352,9 +348,6 @@ static void *process_header(spx_ogg_packet *op,
speex_decoder_ctl(st, SPEEX_SET_ENH, &enh_enabled); speex_decoder_ctl(st, SPEEX_SET_ENH, &enh_enabled);
speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size); speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size);
if (*channels==-1)
*channels = header->nb_channels;
if (!(*channels==1)){ if (!(*channels==1)){
callback.callback_id = SPEEX_INBAND_STEREO; callback.callback_id = SPEEX_INBAND_STEREO;
callback.func = speex_std_stereo_request_handler; callback.func = speex_std_stereo_request_handler;
@ -368,11 +361,8 @@ static void *process_header(spx_ogg_packet *op,
*nframes = header->frames_per_packet; *nframes = header->frames_per_packet;
if (*channels == 2) { if (*channels == -1)
rb->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); *channels = header->nb_channels;
} else if (*channels == 1) {
rb->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
}
*extra_headers = header->extra_headers; *extra_headers = header->extra_headers;
@ -383,35 +373,28 @@ static void *process_header(spx_ogg_packet *op,
/* this is the codec entry point */ /* this is the codec entry point */
enum codec_status codec_main(void) enum codec_status codec_main(void)
{ {
SpeexBits vf; SpeexBits bits;
int error; int error = 0;
int eof; int eof = 0;
spx_ogg_sync_state oy; spx_ogg_sync_state oy;
spx_ogg_page og; spx_ogg_page og;
spx_ogg_packet op; spx_ogg_packet op;
spx_ogg_stream_state os; spx_ogg_stream_state os;
spx_int64_t page_granule=0, cur_granule=0; spx_int64_t page_granule = 0, cur_granule = 0;
int enh_enabled; int enh_enabled = 1;
int nframes=2; int nframes = 2;
int eos=0; int eos = 0;
SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT; SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT;
int channels=-1; int channels = -1;
int rate=0,samplerate=0; int rate = 0, samplerate = 0;
int extra_headers; int extra_headers = 0;
int stream_init=0; int stream_init = 0;
int page_nb_packets,frame_size,packet_count=0; int page_nb_packets, frame_size, packet_count = 0;
int lookahead; int lookahead = 0;
int headerssize=-1; int headerssize = -1;
unsigned long strtoffset; unsigned long strtoffset = 0;
short output[MAX_FRAME_SIZE]; void *st = NULL;
enh_enabled = 1; int j = 0;
void *st=0;
int j;
rb = ci;
//rb->configure(CODEC_SET_FILEBUF_CHUNKSIZE, CHUNKSIZE*128);
//rb->configure(DSP_DITHER, false);
rb->configure(DSP_SET_SAMPLE_DEPTH, 16);
/* We need to flush reserver memory every track load. */ /* We need to flush reserver memory every track load. */
next_track: next_track:
@ -421,44 +404,44 @@ next_track:
goto exit; goto exit;
} }
strtoffset=rb->id3->offset; strtoffset = ci->id3->offset;
while (!*rb->taginfo_ready && !rb->stop_codec) while (!*ci->taginfo_ready && !ci->stop_codec)
rb->sleep(1); ci->sleep(1);
spx_ogg_sync_init(&oy); spx_ogg_sync_init(&oy);
spx_ogg_alloc_buffer(&oy,2*CHUNKSIZE); spx_ogg_alloc_buffer(&oy,2*CHUNKSIZE);
samplerate = rb->id3->frequency; samplerate = ci->id3->frequency;
codec_set_replaygain(rb->id3); codec_set_replaygain(ci->id3);
speex_bits_init(&vf); speex_bits_init(&bits);
eof = 0; eof = 0;
while (!eof) { while (!eof) {
rb->yield(); ci->yield();
if (rb->stop_codec || rb->new_track) if (ci->stop_codec || ci->new_track)
break; break;
/*seek (seeks to the page before the position) */ /*seek (seeks to the page before the position) */
if (rb->seek_time) { if (ci->seek_time) {
if(samplerate!=0&&packet_count>1){ if(samplerate!=0&&packet_count>1){
LOGF("Speex seek page:%d,%d,%d,%d\n", LOGF("Speex seek page:%d,%d,%d,%d\n",
((spx_int64_t)rb->seek_time/1000) * ((spx_int64_t)ci->seek_time/1000) *
(spx_int64_t)samplerate, (spx_int64_t)samplerate,
page_granule, rb->seek_time, page_granule, ci->seek_time,
(page_granule/samplerate)*1000, samplerate); (page_granule/samplerate)*1000, samplerate);
speex_seek_page_granule(((spx_int64_t)rb->seek_time/1000) * speex_seek_page_granule(((spx_int64_t)ci->seek_time/1000) *
(spx_int64_t)samplerate, (spx_int64_t)samplerate,
page_granule, &oy, headerssize, rb); page_granule, &oy, headerssize);
rb->seek_complete(); ci->seek_complete();
} }
} }
next_page: next_page:
/*Get the ogg buffer for writing*/ /*Get the ogg buffer for writing*/
if(get_more_data(&oy,rb)<1){/*read error*/ if(get_more_data(&oy)<1){/*read error*/
error=CODEC_ERROR; error=CODEC_ERROR;
goto done; goto done;
} }
@ -467,7 +450,7 @@ next_page:
while (spx_ogg_sync_pageout(&oy, &og) == 1) { while (spx_ogg_sync_pageout(&oy, &og) == 1) {
int packet_no; int packet_no;
if (stream_init == 0) { if (stream_init == 0) {
spx_ogg_stream_init(&os,spx_ogg_page_serialno(&og)); spx_ogg_stream_init(&os, spx_ogg_page_serialno(&og));
stream_init = 1; stream_init = 1;
} }
@ -486,7 +469,7 @@ next_page:
/* If first packet, process as Speex header */ /* If first packet, process as Speex header */
if (packet_count==0){ if (packet_count==0){
st = process_header(&op, enh_enabled, &frame_size, st = process_header(&op, enh_enabled, &frame_size,
&samplerate,&nframes, &channels, &samplerate, &nframes, &channels,
&stereo, &extra_headers); &stereo, &extra_headers);
speex_decoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead); speex_decoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead);
@ -499,13 +482,19 @@ next_page:
goto exit; goto exit;
} }
rb->id3->vbr = true; ci->id3->vbr = true;
rb->id3->frequency = samplerate; ci->id3->frequency = samplerate;
rb->configure(DSP_SET_FREQUENCY, rb->id3->frequency); ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency);
ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
if (channels == 2) {
ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
} else if (channels == 1) {
ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
}
/* Speex header in its own page, add the whole page /* Speex header in its own page, add the whole page
headersize */ headersize */
headerssize+=og.header_len+og.body_len; headerssize += og.header_len+og.body_len;
} else if (packet_count<=1+extra_headers){ } else if (packet_count<=1+extra_headers){
/* add packet to headersize */ /* add packet to headersize */
@ -515,7 +504,7 @@ next_page:
} else { } else {
if (packet_count <= 2+extra_headers) { if (packet_count <= 2+extra_headers) {
if (strtoffset) { if (strtoffset) {
rb->seek_buffer(strtoffset); ci->seek_buffer(strtoffset);
spx_ogg_sync_reset(&oy); spx_ogg_sync_reset(&oy);
packet_count++; packet_count++;
goto next_page; goto next_page;
@ -528,21 +517,21 @@ next_page:
/* Copy Ogg packet to Speex bitstream */ /* Copy Ogg packet to Speex bitstream */
speex_bits_read_from(&vf, (char*)op.packet, op.bytes); speex_bits_read_from(&bits, (char*)op.packet, op.bytes);
for (j = 0; j != nframes; j++){ for (j = 0; j != nframes; j++){
int ret; int ret;
/* Decode frame */ /* Decode frame */
ret = speex_decode_int(st, &vf, output); ret = speex_decode_int(st, &bits, output);
if (ret==-1) if (ret == -1)
break; break;
if (ret==-2) if (ret == -2)
break; break;
if (speex_bits_remaining(&vf) < 0) if (speex_bits_remaining(&bits) < 0)
break; break;
if (channels == 2) if (channels == 2)
@ -550,17 +539,16 @@ next_page:
int new_frame_size = frame_size; int new_frame_size = frame_size;
if (new_frame_size>0){ if (new_frame_size > 0) {
rb->pcmbuf_insert((const char*)output, NULL, ci->pcmbuf_insert(output, NULL, new_frame_size);
new_frame_size);
/* 2 bytes/sample */ /* 2 bytes/sample */
cur_granule += new_frame_size / 2; cur_granule += new_frame_size / 2;
rb->set_offset((long)rb->curpos); ci->set_offset((long) ci->curpos);
rb->set_elapsed( (samplerate==0) ? 0 : ci->set_elapsed((samplerate == 0) ? 0 :
cur_granule*1000/samplerate); cur_granule * 1000 / samplerate);
} }
} }
} }
@ -570,24 +558,24 @@ next_page:
} }
done: done:
if (rb->request_next_track()) { if (ci->request_next_track()) {
/* Clean things up for the next track */ /* Clean things up for the next track */
speex_decoder_destroy(st); speex_decoder_destroy(st);
speex_bits_reset(&vf); speex_bits_reset(&bits);
if (stream_init==1) if (stream_init == 1)
spx_ogg_stream_reset(&os); spx_ogg_stream_reset(&os);
spx_ogg_sync_reset(&oy); spx_ogg_sync_reset(&oy);
cur_granule = stream_init = rate = samplerate = headerssize cur_granule = stream_init = rate = samplerate = headerssize
= packet_count = eos = 0; = packet_count = eos = 0;
stereo.balance =stereo.smooth_left = stereo.smooth_right = 1; stereo.balance = stereo.smooth_left = stereo.smooth_right = 1;
stereo.e_ratio = .5; stereo.e_ratio = .5;
stereo.reserved1=stereo.reserved2= 0; stereo.reserved1 = stereo.reserved2 = 0;
goto next_track; goto next_track;
} }
@ -595,7 +583,7 @@ done:
error = CODEC_OK; error = CODEC_OK;
exit: exit:
speex_bits_destroy(&vf); speex_bits_destroy(&bits);
if (stream_init) if (stream_init)
spx_ogg_stream_destroy(&os); spx_ogg_stream_destroy(&os);