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:
parent
19bba742e7
commit
879070f89e
21 changed files with 1302 additions and 561 deletions
|
|
@ -1,5 +1,5 @@
|
|||
Library: libspeex-1.2beta1 (SVN version 12449)
|
||||
Imported: 2007-02-10 by Dan Everton
|
||||
Library: libspeex-1.2beta1 (SVN version 12735)
|
||||
Imported: 2007-03-12 by Dan Everton
|
||||
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
found in rockbox.c in this directory.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ nb_celp.c
|
|||
oggframing.c
|
||||
preprocess.c
|
||||
quant_lsp.c
|
||||
resample.c
|
||||
rockbox.c
|
||||
sb_celp.c
|
||||
smallft.c
|
||||
|
|
|
|||
|
|
@ -68,6 +68,10 @@ struct kiss_fft_state{
|
|||
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)
|
||||
|
||||
# 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) \
|
||||
(x) = sround( smul( x, SAMP_MAX/k ) )
|
||||
|
||||
|
|
@ -85,6 +89,9 @@ struct kiss_fft_state{
|
|||
#define C_MUL(m,a,b) \
|
||||
do{ (m).r = (a).r*(b).r - (a).i*(b).i;\
|
||||
(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_MULBYSCALAR( c, s ) \
|
||||
do{ (c).r *= (s);\
|
||||
|
|
|
|||
|
|
@ -137,7 +137,6 @@ void spx_ifft(void *table, float *in, float *out)
|
|||
struct kiss_config {
|
||||
kiss_fftr_cfg forward;
|
||||
kiss_fftr_cfg backward;
|
||||
kiss_fft_cpx *freq_data;
|
||||
int N;
|
||||
};
|
||||
|
||||
|
|
@ -145,7 +144,6 @@ void *spx_fft_init(int size)
|
|||
{
|
||||
struct kiss_config *table;
|
||||
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->backward = kiss_fftr_alloc(size,1,NULL,NULL);
|
||||
table->N = size;
|
||||
|
|
@ -157,7 +155,6 @@ void spx_fft_destroy(void *table)
|
|||
struct kiss_config *t = (struct kiss_config *)table;
|
||||
kiss_fftr_free(t->forward);
|
||||
kiss_fftr_free(t->backward);
|
||||
speex_free(t->freq_data);
|
||||
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)
|
||||
{
|
||||
int i;
|
||||
int shift;
|
||||
struct kiss_config *t = (struct kiss_config *)table;
|
||||
shift = maximize_range(in, in, 32000, t->N);
|
||||
kiss_fftr(t->forward, in, t->freq_data);
|
||||
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;
|
||||
kiss_fftr2(t->forward, in, out);
|
||||
renorm_range(in, in, 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;
|
||||
struct kiss_config *t = (struct kiss_config *)table;
|
||||
scale = 1./t->N;
|
||||
kiss_fftr(t->forward, in, t->freq_data);
|
||||
out[0] = scale*t->freq_data[0].r;
|
||||
for (i=1;i<t->N>>1;i++)
|
||||
{
|
||||
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;
|
||||
kiss_fftr2(t->forward, in, out);
|
||||
for (i=0;i<t->N;i++)
|
||||
out[i] *= scale;
|
||||
}
|
||||
#endif
|
||||
|
||||
void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out)
|
||||
{
|
||||
int i;
|
||||
struct kiss_config *t = (struct kiss_config *)table;
|
||||
t->freq_data[0].r = in[0];
|
||||
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);
|
||||
kiss_fftri2(t->backward, in, out);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#define LATE_BINS 10
|
||||
#define LATE_BINS 15
|
||||
#define MAX_MARGIN 30 /**< Number of bins in margin histogram */
|
||||
|
||||
#define SPEEX_JITTER_MAX_BUFFER_SIZE 200 /**< Maximum number of packets in jitter buffer */
|
||||
|
|
@ -71,6 +71,8 @@ struct JitterBuffer_ {
|
|||
int tick_size; /**< Output granularity */
|
||||
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 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 */
|
||||
float shortterm_margin[MAX_MARGIN]; /**< Short term margin histogram */
|
||||
|
|
@ -89,6 +91,7 @@ JitterBuffer *jitter_buffer_init(int tick)
|
|||
jitter->buf[i]=NULL;
|
||||
jitter->tick_size = tick;
|
||||
jitter->buffer_margin = 1;
|
||||
jitter->late_cutoff = 50;
|
||||
jitter_buffer_reset(jitter);
|
||||
}
|
||||
return jitter;
|
||||
|
|
@ -130,7 +133,8 @@ void jitter_buffer_destroy(JitterBuffer *jitter)
|
|||
/** Put one packet into the jitter buffer */
|
||||
void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
|
||||
{
|
||||
int i,j;
|
||||
int i;
|
||||
unsigned int j;
|
||||
spx_int32_t arrival_margin;
|
||||
/*fprintf (stderr, "put packet %d %d\n", timestamp, span);*/
|
||||
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) */
|
||||
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))
|
||||
{
|
||||
/*fprintf (stderr, "cleaned (not played)\n");*/
|
||||
|
|
@ -184,33 +189,39 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
|
|||
|
||||
/* Copy packet in buffer */
|
||||
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->timestamp[i]=packet->timestamp;
|
||||
jitter->span[i]=packet->span;
|
||||
jitter->len[i]=packet->len;
|
||||
|
||||
/* Adjust the buffer size depending on network conditions */
|
||||
arrival_margin = (packet->timestamp - jitter->current_timestamp) - jitter->buffer_margin*jitter->tick_size;
|
||||
/* Adjust the buffer size depending on network conditions.
|
||||
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;
|
||||
/* First, apply the "damping" of the recursive average to all bins */
|
||||
for (i=0;i<MAX_MARGIN;i++)
|
||||
{
|
||||
jitter->shortterm_margin[i] *= .98;
|
||||
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)
|
||||
int_margin = MAX_MARGIN-1;
|
||||
if (int_margin>=0)
|
||||
{
|
||||
if (int_margin<0)
|
||||
int_margin = 0;
|
||||
/* Add the packet to the right bin */
|
||||
jitter->shortterm_margin[int_margin] += .02;
|
||||
jitter->longterm_margin[int_margin] += .005;
|
||||
}
|
||||
} 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);*/
|
||||
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 */
|
||||
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_long;
|
||||
float ontime_ratio_short;
|
||||
|
|
@ -244,6 +256,17 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint
|
|||
int chunk_size;
|
||||
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))
|
||||
{
|
||||
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_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];
|
||||
|
|
@ -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);*/
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
|
||||
|
|
@ -328,7 +318,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint
|
|||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -338,7 +328,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint
|
|||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -381,7 +371,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint
|
|||
/* Check for potential overflow */
|
||||
packet->len = jitter->len[i];
|
||||
/* Copy packet */
|
||||
for (j=0;((unsigned)j)<packet->len;j++)
|
||||
for (j=0;j<packet->len;j++)
|
||||
packet->data[j] = jitter->buf[i][j];
|
||||
/* Remove packet */
|
||||
speex_free(jitter->buf[i]);
|
||||
|
|
@ -412,6 +402,26 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint
|
|||
packet->span = jitter->tick_size;
|
||||
jitter->pointer_timestamp += chunk_size;
|
||||
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;
|
||||
|
||||
}
|
||||
|
|
@ -427,9 +437,88 @@ void jitter_buffer_tick(JitterBuffer *jitter)
|
|||
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 */
|
||||
int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
|
||||
{
|
||||
int count, i;
|
||||
switch(request)
|
||||
{
|
||||
case JITTER_BUFFER_SET_MARGIN:
|
||||
|
|
@ -438,6 +527,17 @@ int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
|
|||
case JITTER_BUFFER_GET_MARGIN:
|
||||
*(spx_int32_t*)ptr = jitter->buffer_margin;
|
||||
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:
|
||||
speex_warning_int("Unknown jitter_buffer_ctl request: ", request);
|
||||
return -1;
|
||||
|
|
@ -518,6 +618,7 @@ void speex_jitter_get(SpeexJitter *jitter, short *out, int *current_timestamp)
|
|||
out[i]=0;
|
||||
}
|
||||
}
|
||||
jitter_buffer_update_delay(jitter->packets, &packet, NULL);
|
||||
jitter_buffer_tick(jitter->packets);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
Copyright (c) 2003-2004, Mark Borgerding
|
||||
Copyright (c) 2005-2007, Jean-Marc Valin
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
|
@ -24,78 +25,88 @@ 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.
|
||||
*/
|
||||
|
||||
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(
|
||||
kiss_fft_cpx * Fout,
|
||||
const size_t fstride,
|
||||
const kiss_fft_cfg st,
|
||||
int m
|
||||
int m,
|
||||
int N,
|
||||
int mm
|
||||
)
|
||||
{
|
||||
kiss_fft_cpx * Fout2;
|
||||
kiss_fft_cpx * tw1 = st->twiddles;
|
||||
kiss_fft_cpx * tw1;
|
||||
kiss_fft_cpx t;
|
||||
Fout2 = Fout + m;
|
||||
if (!st->inverse) {
|
||||
int i;
|
||||
kiss_fft_cpx *x=Fout;
|
||||
for (i=0;i<2*m;i++)
|
||||
int i,j;
|
||||
kiss_fft_cpx * Fout_beg = Fout;
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
x[i].r = SHR16(x[i].r,1);
|
||||
x[i].i = SHR16(x[i].i,1);
|
||||
Fout = Fout_beg + i*mm;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
do{
|
||||
} 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;
|
||||
}while (--m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void kf_bfly4(
|
||||
kiss_fft_cpx * Fout,
|
||||
const size_t fstride,
|
||||
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 scratch[6];
|
||||
size_t k=m;
|
||||
const size_t m2=2*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)
|
||||
{
|
||||
do {
|
||||
kiss_fft_cpx * Fout_beg = Fout;
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
Fout = Fout_beg + i*mm;
|
||||
tw3 = tw2 = tw1 = st->twiddles;
|
||||
for (j=0;j<m;j++)
|
||||
{
|
||||
C_MUL(scratch[0],Fout[m] , *tw1 );
|
||||
C_MUL(scratch[1],Fout[m2] , *tw2 );
|
||||
C_MUL(scratch[2],Fout[m3] , *tw3 );
|
||||
|
|
@ -115,18 +126,29 @@ static void kf_bfly4(
|
|||
Fout[m3].r = scratch[5].r + scratch[4].i;
|
||||
Fout[m3].i = scratch[5].i - scratch[4].r;
|
||||
++Fout;
|
||||
} while(--k);
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
do {
|
||||
C_MUL(scratch[0],Fout[m] , *tw1 );
|
||||
C_MUL(scratch[1],Fout[m2] , *tw2 );
|
||||
C_MUL(scratch[2],Fout[m3] , *tw3 );
|
||||
kiss_fft_cpx * Fout_beg = Fout;
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
Fout = Fout_beg + i*mm;
|
||||
tw3 = tw2 = tw1 = st->twiddles;
|
||||
for (j=0;j<m;j++)
|
||||
{
|
||||
C_MUL4(scratch[0],Fout[m] , *tw1 );
|
||||
C_MUL4(scratch[1],Fout[m2] , *tw2 );
|
||||
C_MUL4(scratch[2],Fout[m3] , *tw3 );
|
||||
|
||||
Fout->r = PSHR16(Fout->r, 2);
|
||||
Fout->i = PSHR16(Fout->i, 2);
|
||||
C_SUB( scratch[5] , *Fout, scratch[1] );
|
||||
C_ADDTO(*Fout, scratch[1]);
|
||||
C_ADD( scratch[3] , scratch[0] , scratch[2] );
|
||||
C_SUB( scratch[4] , scratch[0] , scratch[2] );
|
||||
Fout[m2].r = PSHR16(Fout[m2].r, 2);
|
||||
Fout[m2].i = PSHR16(Fout[m2].i, 2);
|
||||
C_SUB( Fout[m2], *Fout, scratch[3] );
|
||||
tw1 += fstride;
|
||||
tw2 += fstride*2;
|
||||
|
|
@ -138,7 +160,8 @@ static void kf_bfly4(
|
|||
Fout[m3].r = scratch[5].r - scratch[4].i;
|
||||
Fout[m3].i = scratch[5].i + scratch[4].r;
|
||||
++Fout;
|
||||
}while(--k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -263,9 +286,12 @@ static void kf_bfly_generic(
|
|||
int u,k,q1,q;
|
||||
kiss_fft_cpx * twiddles = st->twiddles;
|
||||
kiss_fft_cpx t;
|
||||
kiss_fft_cpx scratchbuf[17];
|
||||
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 ) {
|
||||
k=u;
|
||||
|
|
@ -293,7 +319,7 @@ static void kf_bfly_generic(
|
|||
}
|
||||
|
||||
static
|
||||
void kf_work(
|
||||
void kf_shuffle(
|
||||
kiss_fft_cpx * Fout,
|
||||
const kiss_fft_cpx * f,
|
||||
const size_t fstride,
|
||||
|
|
@ -302,21 +328,64 @@ void kf_work(
|
|||
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
|
||||
void kf_work(
|
||||
kiss_fft_cpx * Fout,
|
||||
const kiss_fft_cpx * f,
|
||||
const size_t fstride,
|
||||
int in_stride,
|
||||
int * factors,
|
||||
const kiss_fft_cfg st,
|
||||
int N,
|
||||
int s2,
|
||||
int m2
|
||||
)
|
||||
{
|
||||
int i;
|
||||
kiss_fft_cpx * Fout_beg=Fout;
|
||||
const int p=*factors++; /* the radix */
|
||||
const int m=*factors++; /* stage's fft length/p */
|
||||
const kiss_fft_cpx * Fout_end = Fout + p*m;
|
||||
|
||||
if (m==1) {
|
||||
do{
|
||||
*Fout = *f;
|
||||
#if 0
|
||||
/*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;
|
||||
}while(++Fout != Fout_end );
|
||||
}else{
|
||||
do{
|
||||
kf_work( Fout , f, fstride*p, in_stride, factors,st);
|
||||
}*/
|
||||
} else {
|
||||
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;
|
||||
}while( (Fout += m) != Fout_end );
|
||||
Fout += m;
|
||||
}
|
||||
}
|
||||
|
||||
Fout=Fout_beg;
|
||||
|
|
@ -328,6 +397,36 @@ void kf_work(
|
|||
case 5: kf_bfly5(Fout,fstride,st,m); 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, ...
|
||||
|
|
@ -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)
|
||||
{
|
||||
if (fin == fout) {
|
||||
CHECKBUF(tmpbuf,ntmpbuf,st->nfft);
|
||||
if (fin == fout)
|
||||
{
|
||||
speex_error("In-place FFT not supported");
|
||||
/*CHECKBUF(tmpbuf,ntmpbuf,st->nfft);
|
||||
kf_work(tmpbuf,fin,1,in_stride, st->factors,st);
|
||||
speex_move(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft);
|
||||
}else{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
||||
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_fftri2(kiss_fftr_cfg st,const kiss_fft_scalar *freqdata, kiss_fft_scalar *timedata);
|
||||
|
||||
/*
|
||||
input freqdata has nfft/2+1 complex points
|
||||
output timedata has nfft scalar points
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ struct SpeexEchoState_ {
|
|||
spx_word32_t *PHI; /* scratch */
|
||||
spx_word32_t *W; /* (Background) filter weights */
|
||||
#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 Davg2; /* 2nd recursive average of the residual power difference */
|
||||
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);
|
||||
}
|
||||
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
|
||||
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;
|
||||
}
|
||||
}
|
||||
#define spectral_mul_accum16 spectral_mul_accum
|
||||
#endif
|
||||
|
||||
/** 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->W = (spx_word32_t*)speex_alloc(M*N*sizeof(spx_word32_t));
|
||||
#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
|
||||
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));
|
||||
|
|
@ -669,7 +698,7 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
|
|||
|
||||
#ifdef TWO_PATH
|
||||
/* 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);
|
||||
for (i=0;i<st->frame_size;i++)
|
||||
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;
|
||||
/* Copy background filter to foreground filter */
|
||||
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 */
|
||||
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]);
|
||||
|
|
@ -794,7 +823,7 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
|
|||
{
|
||||
/* Copy foreground filter to background filter */
|
||||
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 */
|
||||
for (i=0;i<st->frame_size;i++)
|
||||
st->y[i+st->frame_size] = st->e[i+st->frame_size];
|
||||
|
|
|
|||
|
|
@ -46,6 +46,20 @@
|
|||
#define SB_SUBMODES 8
|
||||
#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 */
|
||||
typedef void (*lsp_quant_func)(spx_lsp_t *, spx_lsp_t *, int, SpeexBits *);
|
||||
|
|
|
|||
|
|
@ -255,7 +255,11 @@ static void conj_window(spx_word16_t *w, int len)
|
|||
for (i=0;i<len;i++)
|
||||
{
|
||||
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);
|
||||
#endif
|
||||
int inv=0;
|
||||
if (x<QCONST16(1.f,13))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,15 @@
|
|||
/**
|
||||
@file pseudofloat.h
|
||||
@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
|
||||
|
|
|
|||
|
|
@ -59,12 +59,13 @@ TODO list:
|
|||
void *speex_alloc (int size) {return calloc(size,1);}
|
||||
void *speex_realloc (void *ptr, int size) {return realloc(ptr, size);}
|
||||
void speex_free (void *ptr) {free(ptr);}
|
||||
#include "speex_resampler.h"
|
||||
#else
|
||||
#include "speex/speex_resampler.h"
|
||||
#include "misc.h"
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include "speex/speex_resampler.h"
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159263
|
||||
|
|
@ -82,37 +83,6 @@ void speex_free (void *ptr) {free(ptr);}
|
|||
|
||||
#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 *);
|
||||
|
||||
|
|
@ -145,34 +115,190 @@ struct SpeexResamplerState_ {
|
|||
|
||||
int in_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
|
||||
/* 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);*/
|
||||
x *= cutoff;
|
||||
float xx = x * cutoff;
|
||||
if (fabs(x)<1e-6f)
|
||||
return WORD2INT(32768.*cutoff);
|
||||
else if (fabs(x) > .5f*N)
|
||||
return 0;
|
||||
/*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
|
||||
/* 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);*/
|
||||
x *= cutoff;
|
||||
float xx = x * cutoff;
|
||||
if (fabs(x)<1e-6)
|
||||
return cutoff;
|
||||
else if (fabs(x) > .5*N)
|
||||
return 0;
|
||||
/*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
|
||||
|
||||
|
|
@ -221,6 +347,55 @@ static int resampler_basic_direct_single(SpeexResamplerState *st, int channel_in
|
|||
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)
|
||||
{
|
||||
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 */
|
||||
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;
|
||||
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;
|
||||
int offset;
|
||||
spx_word16_t frac;
|
||||
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.
|
||||
For most DSPs, it would be best to split the loops in two because most DSPs
|
||||
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[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
|
||||
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.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];
|
||||
cubic_coef(frac, interp);
|
||||
sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]);
|
||||
|
||||
*out = PSHR32(sum,15);
|
||||
out += st->out_stride;
|
||||
|
|
@ -290,6 +462,70 @@ static int resampler_basic_interpolate_single(SpeexResamplerState *st, int chann
|
|||
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)
|
||||
{
|
||||
|
|
@ -328,11 +564,17 @@ static void update_filter(SpeexResamplerState *st)
|
|||
int 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;
|
||||
#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);*/
|
||||
} else {
|
||||
if (!st->sinc_table)
|
||||
|
|
@ -343,9 +585,15 @@ static void update_filter(SpeexResamplerState *st)
|
|||
st->sinc_table_length = st->filt_len*st->oversample+8;
|
||||
}
|
||||
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->type = SPEEX_RESAMPLER_INTERPOLATE_SINGLE;
|
||||
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);
|
||||
#ifdef FIXED_POINT
|
||||
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);*/
|
||||
}
|
||||
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;
|
||||
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_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);
|
||||
|
|
@ -472,16 +724,26 @@ static void speex_resampler_process_native(SpeexResamplerState *st, int channel_
|
|||
st->started = 1;
|
||||
|
||||
/* 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_magic;
|
||||
tmp_in_len = st->magic_samples[channel_index];
|
||||
tmp_out_len = *out_len;
|
||||
/* 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 */
|
||||
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_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;
|
||||
}
|
||||
|
||||
|
|
@ -536,13 +798,13 @@ void speex_resampler_process_int(SpeexResamplerState *st, int channel_index, con
|
|||
istride_save = st->in_stride;
|
||||
ostride_save = st->out_stride;
|
||||
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;
|
||||
speex_resampler_process_native(st, channel_index, x, in_len, y, out_len);
|
||||
st->in_stride = istride_save;
|
||||
st->out_stride = ostride_save;
|
||||
for (i=0;i<*out_len;i++)
|
||||
out[i+st->out_stride] = WORD2INT(y[i]);
|
||||
out[i*st->out_stride] = WORD2INT(y[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -561,8 +823,33 @@ void speex_resampler_process_interleaved_float(SpeexResamplerState *st, const fl
|
|||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (quality < 0)
|
||||
|
|
@ -599,16 +892,31 @@ void speex_resampler_set_quality(SpeexResamplerState *st, int quality)
|
|||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
int i;
|
||||
|
|
|
|||
|
|
@ -236,17 +236,8 @@ void *sb_encoder_init(const SpeexMode *m)
|
|||
for (i=0;i<st->lpcSize+1;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_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->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));
|
||||
|
|
@ -294,17 +285,8 @@ void sb_encoder_destroy(void *state)
|
|||
|
||||
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_qlsp);
|
||||
speex_free(st->interp_lsp);
|
||||
speex_free(st->interp_qlsp);
|
||||
speex_free(st->interp_lpc);
|
||||
speex_free(st->interp_qlpc);
|
||||
speex_free(st->pi_gain);
|
||||
speex_free(st->exc_rms);
|
||||
|
|
@ -336,6 +318,14 @@ int sb_encode(void *state, void *vin, SpeexBits *bits)
|
|||
spx_int32_t dtx;
|
||||
spx_word16_t *in = (spx_word16_t*)vin;
|
||||
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;
|
||||
stack=st->stack;
|
||||
|
|
@ -378,8 +368,20 @@ int sb_encode(void *state, void *vin, SpeexBits *bits)
|
|||
else
|
||||
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);
|
||||
ALLOC(autocorr, st->lpcSize+1, spx_word16_t);
|
||||
ALLOC(w_sig, st->windowSize, spx_word16_t);
|
||||
/* Window for analysis */
|
||||
/* 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));
|
||||
}
|
||||
/* Compute auto-correlation */
|
||||
_spx_autocorr(w_sig, st->autocorr, st->lpcSize+1, st->windowSize);
|
||||
}
|
||||
st->autocorr[0] = ADD16(st->autocorr[0],MULT16_16_Q15(st->autocorr[0],st->lpc_floor)); /* Noise floor in auto-correlation domain */
|
||||
_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++)
|
||||
st->autocorr[i] = MULT16_16_Q14(st->autocorr[i],st->lagWindow[i]);
|
||||
autocorr[i] = MULT16_16_Q14(autocorr[i],st->lagWindow[i]);
|
||||
|
||||
/* Levinson-Durbin */
|
||||
_spx_lpc(st->lpc, st->autocorr, st->lpcSize);
|
||||
_spx_lpc(lpc, autocorr, st->lpcSize);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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 we can't find all LSP's, do some damage control and use a flat filter*/
|
||||
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 */
|
||||
SUBMODE(lsp_quant)(st->lsp, st->qlsp, st->lpcSize, bits);
|
||||
SUBMODE(lsp_quant)(lsp, qlsp, st->lpcSize, bits);
|
||||
|
||||
if (st->first)
|
||||
{
|
||||
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++)
|
||||
st->old_qlsp[i] = st->qlsp[i];
|
||||
st->old_qlsp[i] = qlsp[i];
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* LSP interpolation (quantized and unquantized) */
|
||||
lsp_interpolate(st->old_lsp, st->lsp, st->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_lsp, lsp, interp_lsp, 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(st->interp_qlsp, st->lpcSize, LSP_MARGIN);
|
||||
lsp_enforce_margin(interp_lsp, 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(st->interp_qlsp, st->interp_qlpc, st->lpcSize, stack);
|
||||
lsp_to_lpc(interp_lsp, interp_lpc, 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->gamma2, st->interp_lpc, st->bw_lpc2, st->lpcSize);
|
||||
bw_lpc(st->gamma1, interp_lpc, bw_lpc1, 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
|
||||
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);
|
||||
|
||||
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 */
|
||||
|
|
@ -664,12 +666,12 @@ int sb_encode(void *state, void *vin, SpeexBits *bits)
|
|||
|
||||
for (i=0;i<st->lpcSize;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 */
|
||||
for (i=0;i<st->lpcSize;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 */
|
||||
for (i=0;i<st->subframeSize;i++)
|
||||
|
|
@ -682,7 +684,7 @@ int sb_encode(void *state, void *vin, SpeexBits *bits)
|
|||
innov[i]=0;
|
||||
|
||||
/*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,
|
||||
innov, syn_resp, bits, stack, st->complexity, SUBMODE(double_codebook));
|
||||
/*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++)
|
||||
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,
|
||||
innov2, syn_resp, bits, stack, st->complexity, 0);
|
||||
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);
|
||||
|
||||
/* 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++)
|
||||
st->old_lsp[i] = st->lsp[i];
|
||||
st->old_lsp[i] = lsp[i];
|
||||
for (i=0;i<st->lpcSize;i++)
|
||||
st->old_qlsp[i] = st->qlsp[i];
|
||||
st->old_qlsp[i] = qlsp[i];
|
||||
|
||||
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->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->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->g1_mem);
|
||||
speex_free(st->excBuf);
|
||||
speex_free(st->qlsp);
|
||||
speex_free(st->old_qlsp);
|
||||
speex_free(st->interp_qlsp);
|
||||
speex_free(st->interp_qlpc);
|
||||
speex_free(st->pi_gain);
|
||||
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_word16_t *low_exc_rms);
|
||||
VARDECL(spx_coef_t *ak);
|
||||
VARDECL(spx_lsp_t *qlsp);
|
||||
VARDECL(spx_lsp_t *interp_qlsp);
|
||||
spx_int32_t dtx;
|
||||
const SpeexSBMode *mode;
|
||||
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_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)
|
||||
{
|
||||
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);
|
||||
|
|
@ -990,12 +992,12 @@ int sb_decode(void *state, SpeexBits *bits, void *vout)
|
|||
}
|
||||
|
||||
/* 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(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
|
||||
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);
|
||||
for (i=0;i<st->lpcSize;i++)
|
||||
st->old_qlsp[i] = st->qlsp[i];
|
||||
st->old_qlsp[i] = qlsp[i];
|
||||
|
||||
st->first=0;
|
||||
|
||||
|
|
@ -1245,7 +1247,7 @@ int sb_encoder_ctl(void *state, int request, void *ptr)
|
|||
int i;
|
||||
st->first = 1;
|
||||
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++)
|
||||
st->mem_sw[i]=st->mem_sp[i]=st->mem_sp2[i]=0;
|
||||
for (i=0;i<QMF_ORDER;i++)
|
||||
|
|
|
|||
|
|
@ -63,18 +63,9 @@ typedef struct SBEncState {
|
|||
|
||||
const spx_word16_t *window; /**< LPC analysis 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_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 *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_sp2;
|
||||
|
|
@ -121,9 +112,7 @@ typedef struct SBDecState {
|
|||
spx_word32_t *g0_mem, *g1_mem;
|
||||
|
||||
spx_word16_t *excBuf;
|
||||
spx_lsp_t *qlsp;
|
||||
spx_lsp_t *old_qlsp;
|
||||
spx_lsp_t *interp_qlsp;
|
||||
spx_coef_t *interp_qlpc;
|
||||
|
||||
spx_mem_t *mem_sp;
|
||||
|
|
|
|||
|
|
@ -155,20 +155,6 @@ extern "C" {
|
|||
/** Get status of input/output high-pass filtering */
|
||||
#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:*/
|
||||
/** 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
|
||||
"in". The encoded bit-stream is saved in "bits".
|
||||
@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
|
||||
@return 0 if frame needs not be transmitted (DTX only), 1 otherwise
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -81,7 +81,13 @@ struct _JitterBufferPacket {
|
|||
#define JITTER_BUFFER_SET_MARGIN 0
|
||||
/** Get minimum amount of extra buffering required (margin) */
|
||||
#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
|
||||
*
|
||||
|
|
@ -138,6 +144,8 @@ void jitter_buffer_tick(JitterBuffer *jitter);
|
|||
*/
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -41,22 +41,59 @@
|
|||
|
||||
#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
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
#define spx_word16_t short
|
||||
#define spx_word32_t int
|
||||
#else
|
||||
|
||||
#else /* FIXED_POINT */
|
||||
|
||||
#define spx_word16_t float
|
||||
#define spx_word32_t float
|
||||
#define MULT16_16(a,b) ((a)*(b))
|
||||
#define MULT16_32_Q15(a,b) ((a)*(b))
|
||||
#define PSHR32(a,b) (a)
|
||||
#endif
|
||||
#endif /* FIXED_POINT */
|
||||
|
||||
#else
|
||||
#else /* OUTSIDE_SPEEX */
|
||||
|
||||
#include "speex_types.h"
|
||||
|
||||
#endif
|
||||
#endif /* OUTSIDE_SPEEX */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -71,81 +108,201 @@ extern "C" {
|
|||
struct SpeexResamplerState_;
|
||||
typedef struct SpeexResamplerState_ SpeexResamplerState;
|
||||
|
||||
/** Create a new resampler. The sampling rate ratio is an arbitrary rational number
|
||||
* with both the numerator and denominator being 32-bit integers.
|
||||
/** Create a new resampler with integer input and output rates.
|
||||
* @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 ratio_num Numerator 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 out_rate Nominal output sampling rate rounded to the nearest integer (in Hz). This does not need to be accurate.
|
||||
* @param quality Resampling quality between 0 and 10, where 0 has poor quality and 10 has very high quality.
|
||||
* @param in_rate Input sampling rate rounded to the nearest integer (in Hz).
|
||||
* @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.
|
||||
* @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.
|
||||
* @param st Resampler state
|
||||
*/
|
||||
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 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_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_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 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_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_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 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_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 ratio_num Numerator 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 out_rate Nominal output 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 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.
|
||||
* @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.
|
||||
* @param st Resampler state
|
||||
* @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.
|
||||
* @param st Resampler state
|
||||
* @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.
|
||||
* This is only useful before starting to use a newly created resampler.
|
||||
/** Get the output stride.
|
||||
* @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
|
||||
*/
|
||||
void speex_resampler_skip_zeros(SpeexResamplerState *st);
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ int main(int argc, char **argv)
|
|||
short *out;
|
||||
float *fin, *fout;
|
||||
int count = 0;
|
||||
SpeexResamplerState *st = speex_resampler_init(1, 8000, 12000, 8000, 12000, 5);
|
||||
speex_resampler_set_rate(st, 16000, 8001, 8000, 15999);
|
||||
SpeexResamplerState *st = speex_resampler_init(1, 8000, 12000, 10);
|
||||
speex_resampler_set_rate(st, 8000, 15999);
|
||||
speex_resampler_skip_zeros(st);
|
||||
|
||||
in = malloc(NN*sizeof(short));
|
||||
|
|
@ -67,9 +67,12 @@ int main(int argc, char **argv)
|
|||
fin[i]=in[i];
|
||||
in_len = 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);
|
||||
for (i=0;i<out_len;i++)
|
||||
out[i]=floor(.5+fout[i]);
|
||||
/*speex_warning_int("writing", out_len);*/
|
||||
fwrite(out, sizeof(short), out_len, stdout);
|
||||
count++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,20 +30,18 @@
|
|||
#define CHUNKSIZE 10000 /*2kb*/
|
||||
#define SEEK_CHUNKSIZE 7*CHUNKSIZE
|
||||
|
||||
//#define LOGF(...)
|
||||
|
||||
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;
|
||||
char *buffer;
|
||||
|
||||
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);
|
||||
|
||||
|
|
@ -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 */
|
||||
|
||||
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 ret;
|
||||
|
||||
if (boundary > 0)
|
||||
boundary += rb->curpos;
|
||||
boundary += ci->curpos;
|
||||
|
||||
while (1) {
|
||||
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 */
|
||||
if(!boundary)return(-1);
|
||||
{
|
||||
ret = get_more_data(oy,rb);
|
||||
ret = get_more_data(oy);
|
||||
if (ret == 0)
|
||||
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,
|
||||
spx_int64_t wantedpos,
|
||||
struct codec_api *rb)
|
||||
spx_int64_t wantedpos)
|
||||
{
|
||||
spx_int64_t crofs;
|
||||
spx_int64_t *curoffset=&crofs;
|
||||
*curoffset=rb->curpos;
|
||||
*curoffset=ci->curpos;
|
||||
spx_int64_t begin=*curoffset;
|
||||
spx_int64_t end=begin;
|
||||
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;
|
||||
|
||||
rb->seek_buffer(*curoffset);
|
||||
ci->seek_buffer(*curoffset);
|
||||
|
||||
spx_ogg_sync_reset(oy);
|
||||
|
||||
lastgranule = -1;
|
||||
|
||||
while (*curoffset < end) {
|
||||
ret = get_next_page(oy,og,end-*curoffset,rb);
|
||||
ret = get_next_page(oy,og,end-*curoffset);
|
||||
|
||||
if (ret > 0) {
|
||||
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,
|
||||
spx_ogg_sync_state *oy,
|
||||
spx_int64_t headerssize,
|
||||
struct codec_api *rb)
|
||||
spx_int64_t headerssize)
|
||||
{
|
||||
/* TODO: Someone may want to try to implement seek to packet,
|
||||
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 *curbyteoffset = &crofs;
|
||||
*curbyteoffset = rb->curpos;
|
||||
*curbyteoffset = ci->curpos;
|
||||
spx_int64_t curoffset;
|
||||
curoffset = *curbyteoffset;
|
||||
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;
|
||||
|
||||
rb->seek_buffer(curoffset);
|
||||
ci->seek_buffer(curoffset);
|
||||
|
||||
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 */
|
||||
LOGF("Seek/guess/fault:%d->-<-%d,%d:%d,%d,%d\n",
|
||||
curpos,0,pos,offset,0,
|
||||
rb->curpos,/*stream_length*/0);
|
||||
ci->curpos,/*stream_length*/0);
|
||||
|
||||
curoffset = *curbyteoffset;
|
||||
|
||||
rb->seek_buffer(curoffset);
|
||||
ci->seek_buffer(curoffset);
|
||||
|
||||
spx_ogg_sync_reset(oy);
|
||||
} else {
|
||||
if (spx_ogg_page_granulepos(&og) == 0 && pos > 5000) {
|
||||
LOGF("SEEK/guess/fault:%d->-<-%d,%d:%d,%d,%d\n",
|
||||
curpos,spx_ogg_page_granulepos(&og),pos,
|
||||
offset,0,rb->curpos,/*stream_length*/0);
|
||||
offset,0,ci->curpos,/*stream_length*/0);
|
||||
|
||||
curoffset = *curbyteoffset;
|
||||
|
||||
rb->seek_buffer(curoffset);
|
||||
ci->seek_buffer(curoffset);
|
||||
|
||||
spx_ogg_sync_reset(oy);
|
||||
} 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? */
|
||||
|
||||
if (curpos > pos) { /* backwards */
|
||||
offset = seek_backwards(oy,&og,pos,rb);
|
||||
offset = seek_backwards(oy,&og,pos);
|
||||
|
||||
if (offset > 0) {
|
||||
*curbyteoffset = curoffset;
|
||||
|
|
@ -262,7 +258,7 @@ int speex_seek_page_granule(spx_int64_t pos, spx_int64_t curpos,
|
|||
}
|
||||
} 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 (avgpagelen < 0)
|
||||
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);
|
||||
|
||||
LOGF("Seek failed:%d\n", offset);
|
||||
|
||||
rb->splash(HZ*2, true, "Seek failed");
|
||||
ci->splash(HZ*2, true, "Seek failed");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -327,7 +323,7 @@ static void *process_header(spx_ogg_packet *op,
|
|||
|
||||
modeID = header->mode;
|
||||
|
||||
mode = speex_lib_get_mode (modeID);
|
||||
mode = speex_lib_get_mode(modeID);
|
||||
|
||||
if (header->speex_version_id > 1) {
|
||||
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_GET_FRAME_SIZE, frame_size);
|
||||
|
||||
if (*channels==-1)
|
||||
*channels = header->nb_channels;
|
||||
|
||||
if (!(*channels==1)){
|
||||
callback.callback_id = SPEEX_INBAND_STEREO;
|
||||
callback.func = speex_std_stereo_request_handler;
|
||||
|
|
@ -368,11 +361,8 @@ static void *process_header(spx_ogg_packet *op,
|
|||
|
||||
*nframes = header->frames_per_packet;
|
||||
|
||||
if (*channels == 2) {
|
||||
rb->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
|
||||
} else if (*channels == 1) {
|
||||
rb->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
|
||||
}
|
||||
if (*channels == -1)
|
||||
*channels = header->nb_channels;
|
||||
|
||||
*extra_headers = header->extra_headers;
|
||||
|
||||
|
|
@ -383,35 +373,28 @@ static void *process_header(spx_ogg_packet *op,
|
|||
/* this is the codec entry point */
|
||||
enum codec_status codec_main(void)
|
||||
{
|
||||
SpeexBits vf;
|
||||
int error;
|
||||
int eof;
|
||||
SpeexBits bits;
|
||||
int error = 0;
|
||||
int eof = 0;
|
||||
spx_ogg_sync_state oy;
|
||||
spx_ogg_page og;
|
||||
spx_ogg_packet op;
|
||||
spx_ogg_stream_state os;
|
||||
spx_int64_t page_granule=0, cur_granule=0;
|
||||
int enh_enabled;
|
||||
int nframes=2;
|
||||
int eos=0;
|
||||
spx_int64_t page_granule = 0, cur_granule = 0;
|
||||
int enh_enabled = 1;
|
||||
int nframes = 2;
|
||||
int eos = 0;
|
||||
SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT;
|
||||
int channels=-1;
|
||||
int rate=0,samplerate=0;
|
||||
int extra_headers;
|
||||
int stream_init=0;
|
||||
int page_nb_packets,frame_size,packet_count=0;
|
||||
int lookahead;
|
||||
int headerssize=-1;
|
||||
unsigned long strtoffset;
|
||||
short output[MAX_FRAME_SIZE];
|
||||
enh_enabled = 1;
|
||||
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);
|
||||
int channels = -1;
|
||||
int rate = 0, samplerate = 0;
|
||||
int extra_headers = 0;
|
||||
int stream_init = 0;
|
||||
int page_nb_packets, frame_size, packet_count = 0;
|
||||
int lookahead = 0;
|
||||
int headerssize = -1;
|
||||
unsigned long strtoffset = 0;
|
||||
void *st = NULL;
|
||||
int j = 0;
|
||||
|
||||
/* We need to flush reserver memory every track load. */
|
||||
next_track:
|
||||
|
|
@ -421,44 +404,44 @@ next_track:
|
|||
goto exit;
|
||||
}
|
||||
|
||||
strtoffset=rb->id3->offset;
|
||||
strtoffset = ci->id3->offset;
|
||||
|
||||
while (!*rb->taginfo_ready && !rb->stop_codec)
|
||||
rb->sleep(1);
|
||||
while (!*ci->taginfo_ready && !ci->stop_codec)
|
||||
ci->sleep(1);
|
||||
|
||||
spx_ogg_sync_init(&oy);
|
||||
spx_ogg_alloc_buffer(&oy,2*CHUNKSIZE);
|
||||
|
||||
samplerate = rb->id3->frequency;
|
||||
codec_set_replaygain(rb->id3);
|
||||
samplerate = ci->id3->frequency;
|
||||
codec_set_replaygain(ci->id3);
|
||||
|
||||
speex_bits_init(&vf);
|
||||
speex_bits_init(&bits);
|
||||
|
||||
eof = 0;
|
||||
while (!eof) {
|
||||
rb->yield();
|
||||
if (rb->stop_codec || rb->new_track)
|
||||
ci->yield();
|
||||
if (ci->stop_codec || ci->new_track)
|
||||
break;
|
||||
|
||||
/*seek (seeks to the page before the position) */
|
||||
if (rb->seek_time) {
|
||||
if (ci->seek_time) {
|
||||
if(samplerate!=0&&packet_count>1){
|
||||
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,
|
||||
page_granule, rb->seek_time,
|
||||
page_granule, ci->seek_time,
|
||||
(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,
|
||||
page_granule, &oy, headerssize, rb);
|
||||
rb->seek_complete();
|
||||
page_granule, &oy, headerssize);
|
||||
ci->seek_complete();
|
||||
}
|
||||
}
|
||||
|
||||
next_page:
|
||||
/*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;
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -467,7 +450,7 @@ next_page:
|
|||
while (spx_ogg_sync_pageout(&oy, &og) == 1) {
|
||||
int packet_no;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -486,7 +469,7 @@ next_page:
|
|||
/* If first packet, process as Speex header */
|
||||
if (packet_count==0){
|
||||
st = process_header(&op, enh_enabled, &frame_size,
|
||||
&samplerate,&nframes, &channels,
|
||||
&samplerate, &nframes, &channels,
|
||||
&stereo, &extra_headers);
|
||||
|
||||
speex_decoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead);
|
||||
|
|
@ -499,13 +482,19 @@ next_page:
|
|||
goto exit;
|
||||
}
|
||||
|
||||
rb->id3->vbr = true;
|
||||
rb->id3->frequency = samplerate;
|
||||
rb->configure(DSP_SET_FREQUENCY, rb->id3->frequency);
|
||||
ci->id3->vbr = true;
|
||||
ci->id3->frequency = samplerate;
|
||||
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
|
||||
headersize */
|
||||
headerssize+=og.header_len+og.body_len;
|
||||
headerssize += og.header_len+og.body_len;
|
||||
|
||||
} else if (packet_count<=1+extra_headers){
|
||||
/* add packet to headersize */
|
||||
|
|
@ -515,7 +504,7 @@ next_page:
|
|||
} else {
|
||||
if (packet_count <= 2+extra_headers) {
|
||||
if (strtoffset) {
|
||||
rb->seek_buffer(strtoffset);
|
||||
ci->seek_buffer(strtoffset);
|
||||
spx_ogg_sync_reset(&oy);
|
||||
packet_count++;
|
||||
goto next_page;
|
||||
|
|
@ -528,21 +517,21 @@ next_page:
|
|||
|
||||
/* 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++){
|
||||
int ret;
|
||||
|
||||
/* Decode frame */
|
||||
ret = speex_decode_int(st, &vf, output);
|
||||
ret = speex_decode_int(st, &bits, output);
|
||||
|
||||
if (ret==-1)
|
||||
if (ret == -1)
|
||||
break;
|
||||
|
||||
if (ret==-2)
|
||||
if (ret == -2)
|
||||
break;
|
||||
|
||||
if (speex_bits_remaining(&vf) < 0)
|
||||
if (speex_bits_remaining(&bits) < 0)
|
||||
break;
|
||||
|
||||
if (channels == 2)
|
||||
|
|
@ -550,17 +539,16 @@ next_page:
|
|||
|
||||
int new_frame_size = frame_size;
|
||||
|
||||
if (new_frame_size>0){
|
||||
rb->pcmbuf_insert((const char*)output, NULL,
|
||||
new_frame_size);
|
||||
if (new_frame_size > 0) {
|
||||
ci->pcmbuf_insert(output, NULL, new_frame_size);
|
||||
|
||||
/* 2 bytes/sample */
|
||||
cur_granule += new_frame_size / 2;
|
||||
|
||||
rb->set_offset((long)rb->curpos);
|
||||
ci->set_offset((long) ci->curpos);
|
||||
|
||||
rb->set_elapsed( (samplerate==0) ? 0 :
|
||||
cur_granule*1000/samplerate);
|
||||
ci->set_elapsed((samplerate == 0) ? 0 :
|
||||
cur_granule * 1000 / samplerate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -570,14 +558,14 @@ next_page:
|
|||
}
|
||||
|
||||
done:
|
||||
if (rb->request_next_track()) {
|
||||
if (ci->request_next_track()) {
|
||||
|
||||
/* Clean things up for the next track */
|
||||
|
||||
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_sync_reset(&oy);
|
||||
|
|
@ -585,9 +573,9 @@ done:
|
|||
cur_granule = stream_init = rate = samplerate = headerssize
|
||||
= 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.reserved1=stereo.reserved2= 0;
|
||||
stereo.reserved1 = stereo.reserved2 = 0;
|
||||
|
||||
goto next_track;
|
||||
}
|
||||
|
|
@ -595,7 +583,7 @@ done:
|
|||
error = CODEC_OK;
|
||||
|
||||
exit:
|
||||
speex_bits_destroy(&vf);
|
||||
speex_bits_destroy(&bits);
|
||||
|
||||
if (stream_init)
|
||||
spx_ogg_stream_destroy(&os);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue