diff options
| author | Dan Everton <dan@iocaine.org> | 2007-03-12 11:54:07 +0000 |
|---|---|---|
| committer | Dan Everton <dan@iocaine.org> | 2007-03-12 11:54:07 +0000 |
| commit | 879070f89e004be03cef53ad7f61610e02e7aa00 (patch) | |
| tree | eccbcce2722da50eb473c78cf9ce16fad6602c00 /apps/codecs | |
| parent | 19bba742e789e669d4cfc15ed3a5cef4aa64199d (diff) | |
| download | rockbox-879070f89e004be03cef53ad7f61610e02e7aa00.zip rockbox-879070f89e004be03cef53ad7f61610e02e7aa00.tar.gz rockbox-879070f89e004be03cef53ad7f61610e02e7aa00.tar.bz2 rockbox-879070f89e004be03cef53ad7f61610e02e7aa00.tar.xz | |
* 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
Diffstat (limited to 'apps/codecs')
| -rw-r--r-- | apps/codecs/libspeex/README.rockbox | 8 | ||||
| -rw-r--r-- | apps/codecs/libspeex/SOURCES | 1 | ||||
| -rw-r--r-- | apps/codecs/libspeex/_kiss_fft_guts.h | 7 | ||||
| -rw-r--r-- | apps/codecs/libspeex/fftwrap.c | 37 | ||||
| -rw-r--r-- | apps/codecs/libspeex/jitter.c | 209 | ||||
| -rw-r--r-- | apps/codecs/libspeex/kiss_fft.c | 329 | ||||
| -rw-r--r-- | apps/codecs/libspeex/kiss_fftr.c | 128 | ||||
| -rw-r--r-- | apps/codecs/libspeex/kiss_fftr.h | 5 | ||||
| -rw-r--r-- | apps/codecs/libspeex/mdf.c | 39 | ||||
| -rw-r--r-- | apps/codecs/libspeex/modes.h | 14 | ||||
| -rw-r--r-- | apps/codecs/libspeex/preprocess.c | 4 | ||||
| -rw-r--r-- | apps/codecs/libspeex/pseudofloat.h | 9 | ||||
| -rw-r--r-- | apps/codecs/libspeex/resample.c | 432 | ||||
| -rw-r--r-- | apps/codecs/libspeex/sb_celp.c | 122 | ||||
| -rw-r--r-- | apps/codecs/libspeex/sb_celp.h | 11 | ||||
| -rw-r--r-- | apps/codecs/libspeex/speex/speex.h | 18 | ||||
| -rw-r--r-- | apps/codecs/libspeex/speex/speex_jitter.h | 8 | ||||
| -rw-r--r-- | apps/codecs/libspeex/speex/speex_noglobals.h | 60 | ||||
| -rw-r--r-- | apps/codecs/libspeex/speex/speex_resampler.h | 221 | ||||
| -rw-r--r-- | apps/codecs/libspeex/testresample.c | 7 | ||||
| -rw-r--r-- | apps/codecs/speex.c | 188 |
21 files changed, 1299 insertions, 558 deletions
diff --git a/apps/codecs/libspeex/README.rockbox b/apps/codecs/libspeex/README.rockbox index 4280df4..7f7f975 100644 --- a/apps/codecs/libspeex/README.rockbox +++ b/apps/codecs/libspeex/README.rockbox @@ -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. + diff --git a/apps/codecs/libspeex/SOURCES b/apps/codecs/libspeex/SOURCES index 16168b0..df73565 100644 --- a/apps/codecs/libspeex/SOURCES +++ b/apps/codecs/libspeex/SOURCES @@ -31,7 +31,6 @@ nb_celp.c oggframing.c preprocess.c quant_lsp.c -resample.c rockbox.c sb_celp.c smallft.c diff --git a/apps/codecs/libspeex/_kiss_fft_guts.h b/apps/codecs/libspeex/_kiss_fft_guts.h index 43a3ba5..526a73b 100644 --- a/apps/codecs/libspeex/_kiss_fft_guts.h +++ b/apps/codecs/libspeex/_kiss_fft_guts.h @@ -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);\ diff --git a/apps/codecs/libspeex/fftwrap.c b/apps/codecs/libspeex/fftwrap.c index a108640..35e2d05 100644 --- a/apps/codecs/libspeex/fftwrap.c +++ b/apps/codecs/libspeex/fftwrap.c @@ -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); } diff --git a/apps/codecs/libspeex/jitter.c b/apps/codecs/libspeex/jitter.c index dc31c06..ae60f73 100644 --- a/apps/codecs/libspeex/jitter.c +++ b/apps/codecs/libspeex/jitter.c @@ -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,7 +71,9 @@ 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 */ float longterm_margin[MAX_MARGIN]; /**< Long 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) - { - jitter->shortterm_margin[int_margin] += .02; - jitter->longterm_margin[int_margin] += .005; - } + 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); } diff --git a/apps/codecs/libspeex/kiss_fft.c b/apps/codecs/libspeex/kiss_fft.c index 4ab31f2..449e7b8 100644 --- a/apps/codecs/libspeex/kiss_fft.c +++ b/apps/codecs/libspeex/kiss_fft.c @@ -1,5 +1,6 @@ /* Copyright (c) 2003-2004, Mark Borgerding +Copyright (c) 2005-2007, Jean-Marc Valin All rights reserved. @@ -24,121 +25,143 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND fixed or floating point complex numbers. It also delares the kf_ internal functions. */ -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++) + { + 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; + } + } + } else { + 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++) + { + C_MUL (t, *Fout2 , *tw1); + tw1 += fstride; + C_SUB( *Fout2 , *Fout , t ); + C_ADDTO( *Fout , t ); + ++Fout2; + ++Fout; + } } } - - do{ - C_MUL (t, *Fout2 , *tw1); - tw1 += fstride; - C_SUB( *Fout2 , *Fout , t ); - C_ADDTO( *Fout , t ); - ++Fout2; - ++Fout; - }while (--m); } static void kf_bfly4( 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 { - C_MUL(scratch[0],Fout[m] , *tw1 ); - C_MUL(scratch[1],Fout[m2] , *tw2 ); - C_MUL(scratch[2],Fout[m3] , *tw3 ); - - 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] ); - C_SUB( Fout[m2], *Fout, scratch[3] ); - tw1 += fstride; - tw2 += fstride*2; - tw3 += fstride*3; - C_ADDTO( *Fout , scratch[3] ); - - Fout[m].r = scratch[5].r - scratch[4].i; - Fout[m].i = scratch[5].i + scratch[4].r; - Fout[m3].r = scratch[5].r + scratch[4].i; - Fout[m3].i = scratch[5].i - scratch[4].r; - ++Fout; - } while(--k); + 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 ); + + 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] ); + C_SUB( Fout[m2], *Fout, scratch[3] ); + tw1 += fstride; + tw2 += fstride*2; + tw3 += fstride*3; + C_ADDTO( *Fout , scratch[3] ); + + Fout[m].r = scratch[5].r - scratch[4].i; + Fout[m].i = scratch[5].i + scratch[4].r; + Fout[m3].r = scratch[5].r + scratch[4].i; + Fout[m3].i = scratch[5].i - scratch[4].r; + ++Fout; + } + } } else { - do { - C_MUL(scratch[0],Fout[m] , *tw1 ); - C_MUL(scratch[1],Fout[m2] , *tw2 ); - C_MUL(scratch[2],Fout[m3] , *tw3 ); - - 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] ); - C_SUB( Fout[m2], *Fout, scratch[3] ); - tw1 += fstride; - tw2 += fstride*2; - tw3 += fstride*3; - C_ADDTO( *Fout , scratch[3] ); - - Fout[m].r = scratch[5].r + scratch[4].i; - Fout[m].i = scratch[5].i - scratch[4].r; - Fout[m3].r = scratch[5].r - scratch[4].i; - Fout[m3].i = scratch[5].i + scratch[4].r; - ++Fout; - }while(--k); + 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; + tw3 += fstride*3; + C_ADDTO( *Fout , scratch[3] ); + + Fout[m].r = scratch[5].r + scratch[4].i; + Fout[m].i = scratch[5].i - scratch[4].r; + Fout[m3].r = scratch[5].r - scratch[4].i; + Fout[m3].i = scratch[5].i + scratch[4].r; + ++Fout; + } + } } } @@ -263,10 +286,13 @@ static void kf_bfly_generic( int u,k,q1,q; 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; for ( q1=0 ; q1<p ; ++q1 ) { @@ -291,6 +317,39 @@ static void kf_bfly_generic( } } } + +static +void kf_shuffle( + kiss_fft_cpx * Fout, + const kiss_fft_cpx * f, + const size_t fstride, + int in_stride, + int * factors, + const kiss_fft_cfg st + ) +{ + const int p=*factors++; /* the radix */ + const int m=*factors++; /* stage's fft length/p */ + + /*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/ + if (m==1) + { + int j; + for (j=0;j<p;j++) + { + Fout[j] = *f; + f += fstride*in_stride; + } + } else { + int j; + for (j=0;j<p;j++) + { + kf_shuffle( Fout , f, fstride*p, in_stride, factors,st); + f += fstride*in_stride; + Fout += m; + } + } +} static void kf_work( @@ -299,24 +358,34 @@ void kf_work( const size_t fstride, int in_stride, int * factors, - const kiss_fft_cfg st + const kiss_fft_cfg st, + int N, + int s2, + int m2 ) { + int i; kiss_fft_cpx * Fout_beg=Fout; 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; - f += fstride*in_stride; - }while(++Fout != Fout_end ); - }else{ - do{ - kf_work( Fout , f, fstride*p, in_stride, factors,st); - f += fstride*in_stride; - }while( (Fout += m) != Fout_end ); +#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; + }*/ + } 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; + 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); - 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 ); + 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_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; -} diff --git a/apps/codecs/libspeex/kiss_fftr.c b/apps/codecs/libspeex/kiss_fftr.c index 95c4573..392945c 100644 --- a/apps/codecs/libspeex/kiss_fftr.c +++ b/apps/codecs/libspeex/kiss_fftr.c @@ -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); +} diff --git a/apps/codecs/libspeex/kiss_fftr.h b/apps/codecs/libspeex/kiss_fftr.h index 2e8351a..7bfb423 100644 --- a/apps/codecs/libspeex/kiss_fftr.h +++ b/apps/codecs/libspeex/kiss_fftr.h @@ -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 diff --git a/apps/codecs/libspeex/mdf.c b/apps/codecs/libspeex/mdf.c index eac9f83..498dd39 100644 --- a/apps/codecs/libspeex/mdf.c +++ b/apps/codecs/libspeex/mdf.c @@ -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]; diff --git a/apps/codecs/libspeex/modes.h b/apps/codecs/libspeex/modes.h index 819be70..385cec0 100644 --- a/apps/codecs/libspeex/modes.h +++ b/apps/codecs/libspeex/modes.h @@ -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 *); diff --git a/apps/codecs/libspeex/preprocess.c b/apps/codecs/libspeex/preprocess.c index bd4f776..c4217f4 100644 --- a/apps/codecs/libspeex/preprocess.c +++ b/apps/codecs/libspeex/preprocess.c @@ -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)) { diff --git a/apps/codecs/libspeex/pseudofloat.h b/apps/codecs/libspeex/pseudofloat.h index 67f01b3..a6c4762 100644 --- a/apps/codecs/libspeex/pseudofloat.h +++ b/apps/codecs/libspeex/pseudofloat.h @@ -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 diff --git a/apps/codecs/libspeex/resample.c b/apps/codecs/libspeex/resample.c index d6bfa3e..74d5f40 100644 --- a/apps/codecs/libspeex/resample.c +++ b/apps/codecs/libspeex/resample.c @@ -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,6 +411,75 @@ 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}; + spx_word16_t interp[4]; + const spx_word16_t *ptr; + int offset; + spx_word16_t frac; + offset = samp_frac_num*st->oversample/st->den_rate; +#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 */ + for (j=0;last_sample-N+1+j < 0;j++) + { + spx_word16_t curr_mem = mem[last_sample+j]; + accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]); + accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]); + accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]); + accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]); + } + ptr = in+st->in_stride*(last_sample-N+1+j); + /* Do the new part */ + for (;j<N;j++) + { + spx_word16_t curr_in = *ptr; + ptr += st->in_stride; + accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]); + accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); + accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); + accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); + } + cubic_coef(frac, interp); + sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]); + + *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; +} + +#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; @@ -246,7 +490,7 @@ static int resampler_basic_interpolate_single(SpeexResamplerState *st, int chann have only two accumulators */ for (j=0;last_sample-N+1+j < 0;j++) { - spx_word16_t curr_mem = mem[last_sample+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]); @@ -256,22 +500,14 @@ static int resampler_basic_interpolate_single(SpeexResamplerState *st, int chann /* Do the new part */ for (;j<N;j++) { - spx_word16_t curr_in = *ptr; + 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]); } - /* 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];*/ + 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); @@ -289,7 +525,7 @@ static int resampler_basic_interpolate_single(SpeexResamplerState *st, int chann 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 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(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) { 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; diff --git a/apps/codecs/libspeex/sb_celp.c b/apps/codecs/libspeex/sb_celp.c index 61ca34e..b1159cd 100644 --- a/apps/codecs/libspeex/sb_celp.c +++ b/apps/codecs/libspeex/sb_celp.c @@ -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,7 +318,15 @@ 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; mode = (const SpeexSBMode*)(st->mode->mode); @@ -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]); + /* Lag windowing: equivalent to filtering in the power-spectrum domain */ + for (i=0;i<st->lpcSize+1;i++) + autocorr[i] = MULT16_16_Q14(autocorr[i],st->lagWindow[i]); - /* Levinson-Durbin */ - _spx_lpc(st->lpc, st->autocorr, st->lpcSize); + /* Levinson-Durbin */ + _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++) diff --git a/apps/codecs/libspeex/sb_celp.h b/apps/codecs/libspeex/sb_celp.h index 35997cb..a0dc3af 100644 --- a/apps/codecs/libspeex/sb_celp.h +++ b/apps/codecs/libspeex/sb_celp.h @@ -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; diff --git a/apps/codecs/libspeex/speex/speex.h b/apps/codecs/libspeex/speex/speex.h index 95facf4..0ae1aba 100644 --- a/apps/codecs/libspeex/speex/speex.h +++ b/apps/codecs/libspeex/speex/speex.h @@ -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 */ diff --git a/apps/codecs/libspeex/speex/speex_jitter.h b/apps/codecs/libspeex/speex/speex_jitter.h index b998a02..a5314d6 100644 --- a/apps/codecs/libspeex/speex/speex_jitter.h +++ b/apps/codecs/libspeex/speex/speex_jitter.h @@ -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 diff --git a/apps/codecs/libspeex/speex/speex_noglobals.h b/apps/codecs/libspeex/speex/speex_noglobals.h deleted file mode 100644 index 1d46993..0000000 --- a/apps/codecs/libspeex/speex/speex_noglobals.h +++ /dev/null @@ -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 diff --git a/apps/codecs/libspeex/speex/speex_resampler.h b/apps/codecs/libspeex/speex/speex_resampler.h index 501fab8..93642ce 100644 --- a/apps/codecs/libspeex/speex/speex_resampler.h +++ b/apps/codecs/libspeex/speex/speex_resampler.h @@ -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 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_float(SpeexResamplerState *st, + const float *in, + int *in_len, + float *out, + int *out_len); -/** Resample an interleaved float array. The input and output may *not* alias. +/** 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 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_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_process_interleaved_float(SpeexResamplerState *st, const float *in, int *in_len, float *out, int *out_len); +void speex_resampler_get_rate(SpeexResamplerState *st, + int *in_rate, + int *out_rate); -/** Set (change) the input/output sampling rates and resampling ratio. +/** 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_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_set_rate(SpeexResamplerState *st, int ratio_num, int ratio_den, int in_rate, int out_rate); +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); + +/** 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. +/** 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); diff --git a/apps/codecs/libspeex/testresample.c b/apps/codecs/libspeex/testresample.c index c54b113..5e02479 100644 --- a/apps/codecs/libspeex/testresample.c +++ b/apps/codecs/libspeex/testresample.c @@ -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++; } diff --git a/apps/codecs/speex.c b/apps/codecs/speex.c index a9b333b..8dd9f01 100644 --- a/apps/codecs/speex.c +++ b/apps/codecs/speex.c @@ -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,24 +558,24 @@ 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); cur_granule = stream_init = rate = samplerate = headerssize - = packet_count = eos = 0; + = packet_count = eos = 0; - stereo.balance =stereo.smooth_left = stereo.smooth_right = 1; + stereo.balance = stereo.smooth_left = stereo.smooth_right = 1; stereo.e_ratio = .5; - stereo.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); |