···11-Copyright 2002-2006
22- Xiph.org Foundation
33- Jean-Marc Valin
44- David Rowe
55- EpicGames
66- Analog Devices
77- Commonwealth Scientific and Industrial Research Organisation (CSIRO)
11+Copyright 2002-2008 Xiph.org Foundation
22+Copyright 2002-2008 Jean-Marc Valin
33+Copyright 2005-2007 Analog Devices Inc.
44+Copyright 2005-2008 Commonwealth Scientific and Industrial Research
55+ Organisation (CSIRO)
66+Copyright 1993, 2002, 2006 David Rowe
77+Copyright 2003 EpicGames
88+Copyright 1992-1994 Jutta Degener, Carsten Bormann
89910Redistribution and use in source and binary forms, with or without
1011modification, are permitted provided that the following conditions
+3-3
lib/rbcodec/codecs/libspeex/README.rockbox
···11-Library: libspeex-1.2beta3 (SVN version 14054)
22-Imported: 2007-03-12 by Dan Everton
33-11+Library: libspeex-1.2rc1
22+Imported 1.2beta3: 2007-03-12 by Dan Everton
33+Updated 1.2rc1: 2024-05-08 by Solomon Peachy
4455This directory contains a local version of libspeex for decoding Ogg/Speex
66audio streams.
···11-/* Copyright (C) 2002 Jean-Marc Valin
11+/* Copyright (C) 2002 Jean-Marc Valin
22 File: speex_bits.c
3344 Handles bit packing/unpacking
···66 Redistribution and use in source and binary forms, with or without
77 modification, are permitted provided that the following conditions
88 are met:
99-99+1010 - Redistributions of source code must retain the above copyright
1111 notice, this list of conditions and the following disclaimer.
1212-1212+1313 - Redistributions in binary form must reproduce the above copyright
1414 notice, this list of conditions and the following disclaimer in the
1515 documentation and/or other materials provided with the distribution.
1616-1616+1717 - Neither the name of the Xiph.org Foundation nor the names of its
1818 contributors may be used to endorse or promote products derived from
1919 this software without specific prior written permission.
2020-2020+2121 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2222 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2323 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
···4646#endif
47474848#ifdef ROCKBOX_VOICE_ENCODER
4949-void speex_bits_init(SpeexBits *bits)
4949+EXPORT void speex_bits_init(SpeexBits *bits)
5050{
5151 bits->chars = (char*)speex_alloc(MAX_CHARS_PER_FRAME);
5252 if (!bits->chars)
···62626363#if 0
6464/* Rockbox: unused */
6565-void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size)
6565+EXPORT void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size)
6666{
6767 bits->chars = (char*)buff;
6868 bits->buf_size = buf_size;
···7373}
7474#endif
75757676-void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size)
7676+EXPORT void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size)
7777{
7878 bits->chars = (char*)buff;
7979 bits->buf_size = buf_size;
···8484 bits->charPtr=0;
8585 bits->bitPtr=0;
8686 bits->overflow=0;
8787-8787+8888}
89899090#ifndef ROCKBOX_VOICE_CODEC
9191-void speex_bits_destroy(SpeexBits *bits)
9191+EXPORT void speex_bits_destroy(SpeexBits *bits)
9292{
9393 if (bits->owner)
9494 speex_free(bits->chars);
···9797#endif
98989999#ifdef ROCKBOX_VOICE_ENCODER
100100-void speex_bits_reset(SpeexBits *bits)
100100+EXPORT void speex_bits_reset(SpeexBits *bits)
101101{
102102 /* We only need to clear the first byte now */
103103 bits->chars[0]=0;
···110110111111#if 0
112112/* Rockbox: unused */
113113-void speex_bits_rewind(SpeexBits *bits)
113113+EXPORT void speex_bits_rewind(SpeexBits *bits)
114114{
115115 bits->charPtr=0;
116116 bits->bitPtr=0;
···119119#endif
120120121121#if !defined(SPEEX_VOICE_ENCODER) && !defined(ROCKBOX_VOICE_CODEC)
122122-void speex_bits_read_from(SpeexBits *bits, char *chars, int len)
122122+EXPORT void speex_bits_read_from(SpeexBits *bits, char *chars, int len)
123123{
124124 int i;
125125 int nchars = len / BYTES_PER_CHAR;
···166166 bits->charPtr=0;
167167}
168168169169-void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes)
169169+EXPORT void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes)
170170{
171171 int i,pos;
172172+172173 int nchars = nbytes/BYTES_PER_CHAR;
173174174175 if (((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR)+nchars > bits->buf_size)
···200201#endif
201202202203#ifndef SPEEX_DISABLE_ENCODER
203203-int speex_bits_write(SpeexBits *bits, char *chars, int max_nbytes)
204204+EXPORT int speex_bits_write(SpeexBits *bits, char *chars, int max_nbytes)
204205{
205206 int i;
206207 int max_nchars = max_nbytes/BYTES_PER_CHAR;
···223224 return max_nchars*BYTES_PER_CHAR;
224225}
225226226226-int speex_bits_write_whole_bytes(SpeexBits *bits, char *chars, int max_nbytes)
227227+EXPORT int speex_bits_write_whole_bytes(SpeexBits *bits, char *chars, int max_nbytes)
227228{
228229 int max_nchars = max_nbytes/BYTES_PER_CHAR;
229230 int i;
···241242 return max_nchars*BYTES_PER_CHAR;
242243}
243244244244-void speex_bits_pack(SpeexBits *bits, int data, int nbBits)
245245+EXPORT void speex_bits_pack(SpeexBits *bits, int data, int nbBits)
245246{
246247 unsigned int d=data;
247248···287288288289#if 0
289290/* Rockbox: unused */
290290-int speex_bits_unpack_signed(SpeexBits *bits, int nbBits)
291291+EXPORT int speex_bits_unpack_signed(SpeexBits *bits, int nbBits)
291292{
292293 unsigned int d=speex_bits_unpack_unsigned(bits,nbBits);
293294 /* If number is negative */
···299300}
300301#endif
301302302302-unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits)
303303+EXPORT unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits)
303304{
304305 unsigned int d=0;
305306 if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+nbBits>bits->nbBits)
···323324324325#if 0
325326/* Rockbox: unused */
326326-unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits)
327327+EXPORT unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits)
327328{
328329 unsigned int d=0;
329330 int bitPtr, charPtr;
···353354}
354355#endif
355356356356-int speex_bits_peek(SpeexBits *bits)
357357+EXPORT int speex_bits_peek(SpeexBits *bits)
357358{
358359 if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+1>bits->nbBits)
359360 bits->overflow=1;
···362363 return (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1;
363364}
364365365365-void speex_bits_advance(SpeexBits *bits, int n)
366366+EXPORT void speex_bits_advance(SpeexBits *bits, int n)
366367{
367368 if (((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+n>bits->nbBits) || bits->overflow){
368369 bits->overflow=1;
···372373 bits->bitPtr = (bits->bitPtr+n) & (BITS_PER_CHAR-1); /* modulo by BITS_PER_CHAR */
373374}
374375375375-int speex_bits_remaining(SpeexBits *bits)
376376+EXPORT int speex_bits_remaining(SpeexBits *bits)
376377{
377378 if (bits->overflow)
378379 return -1;
···382383383384#if 0
384385/* Rockbox: unused */
385385-int speex_bits_nbytes(SpeexBits *bits)
386386+EXPORT int speex_bits_nbytes(SpeexBits *bits)
386387{
387388 return ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR);
388389}
389390#endif
390391391392#ifndef SPEEX_DISABLE_ENCODER
392392-void speex_bits_insert_terminator(SpeexBits *bits)
393393+EXPORT void speex_bits_insert_terminator(SpeexBits *bits)
393394{
394395 if (bits->bitPtr)
395396 speex_bits_pack(bits, 0, 1);
+14-6
lib/rbcodec/codecs/libspeex/config-speex.h
···11#ifndef ROCKBOX_VOICE_ENCODER
22-#include "codeclib.h"
22+#include "codeclib.h"
33#include "autoconf.h"
44#else
55#define ICODE_ATTR
···17171818/* Make use of ARM4E assembly optimizations */
1919#if defined(CPU_ARM)
2020+#if (ARM_ARCH < 5)
2021#define ARM4_ASM
2222+#else
2323+#define ARM5E_ASM
2424+#endif
2125#endif
22262327/* Make use of Coldfire assembly optimizations */
···40444145#ifndef ROCKBOX_VOICE_ENCODER
4246/* Compile target codec as fixed point */
4343-#define FIXED_POINT
4747+#define FIXED_POINT
4448#else
4549/* Compile voice clip encoder as floating point */
4646-#define FLOATING_POINT
5050+#define FLOATING_POINT
4751#endif
48524953#ifndef ROCKBOX_VOICE_CODEC
···137141#define SPEEX_MAJOR_VERSION 1
138142139143/* Version micro */
140140-#define SPEEX_MICRO_VERSION 15
144144+#define SPEEX_MICRO_VERSION 16
141145142146/* Version minor */
143147#define SPEEX_MINOR_VERSION 1
144148145149/* Complete version string */
146146-#define SPEEX_VERSION "1.2beta3"
150150+#define SPEEX_VERSION "1.2rc1"
147151148152/* Define to 1 if you have the ANSI C header files. */
149153#define STDC_HEADERS 1
···155159/* #undef USE_ALLOCA */
156160157161/* Use C99 variable-size arrays */
158158-#define VAR_ARRAYS
162162+#define VAR_ARRAYS
159163160164/* Enable Vorbis-style psychoacoustics (EXPERIMENTAL) */
161165/* #undef VORBIS_PSYCHO */
···184188185189#define RELEASE 1
186190191191+/* We don't care */
192192+#define EXPORT
193193+194194+#define USE_KISS_FFT
+120-11
lib/rbcodec/codecs/libspeex/fftwrap.c
···11-/* Copyright (C) 2005-2006 Jean-Marc Valin
11+/* Copyright (C) 2005-2006 Jean-Marc Valin
22 File: fftwrap.c
3344- Wrapper for various FFTs
44+ Wrapper for various FFTs
5566 Redistribution and use in source and binary forms, with or without
77 modification, are permitted provided that the following conditions
88 are met:
99-99+1010 - Redistributions of source code must retain the above copyright
1111 notice, this list of conditions and the following disclaimer.
1212-1212+1313 - Redistributions in binary form must reproduce the above copyright
1414 notice, this list of conditions and the following disclaimer in the
1515 documentation and/or other materials provided with the distribution.
1616-1616+1717 - Neither the name of the Xiph.org Foundation nor the names of its
1818 contributors may be used to endorse or promote products derived from
1919 this software without specific prior written permission.
2020-2020+2121 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2222 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2323 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
···3535#ifdef HAVE_CONFIG_H
3636#include "config-speex.h"
3737#endif
3838-3939-/*#define USE_SMALLFT*/
4040-#define USE_KISS_FFT
4141-42384339#include "arch.h"
4440#include "os_support.h"
···6662 for (i=0;i<len;i++)
6763 {
6864 out[i] = SHL16(in[i], shift);
6969- }
6565+ }
7066 return shift;
7167}
7268···128124 out[i] = in[i];
129125 }
130126 spx_drft_backward((struct drft_lookup *)table, out);
127127+}
128128+129129+#elif defined(USE_INTEL_MKL)
130130+#include <mkl.h>
131131+132132+struct mkl_config {
133133+ DFTI_DESCRIPTOR_HANDLE desc;
134134+ int N;
135135+};
136136+137137+void *spx_fft_init(int size)
138138+{
139139+ struct mkl_config *table = (struct mkl_config *) speex_alloc(sizeof(struct mkl_config));
140140+ table->N = size;
141141+ DftiCreateDescriptor(&table->desc, DFTI_SINGLE, DFTI_REAL, 1, size);
142142+ DftiSetValue(table->desc, DFTI_PACKED_FORMAT, DFTI_PACK_FORMAT);
143143+ DftiSetValue(table->desc, DFTI_PLACEMENT, DFTI_NOT_INPLACE);
144144+ DftiSetValue(table->desc, DFTI_FORWARD_SCALE, 1.0f / size);
145145+ DftiCommitDescriptor(table->desc);
146146+ return table;
147147+}
148148+149149+void spx_fft_destroy(void *table)
150150+{
151151+ struct mkl_config *t = (struct mkl_config *) table;
152152+ DftiFreeDescriptor(t->desc);
153153+ speex_free(table);
154154+}
155155+156156+void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out)
157157+{
158158+ struct mkl_config *t = (struct mkl_config *) table;
159159+ DftiComputeForward(t->desc, in, out);
160160+}
161161+162162+void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out)
163163+{
164164+ struct mkl_config *t = (struct mkl_config *) table;
165165+ DftiComputeBackward(t->desc, in, out);
166166+}
167167+168168+#elif defined(USE_GPL_FFTW3)
169169+170170+#include <fftw3.h>
171171+172172+struct fftw_config {
173173+ float *in;
174174+ float *out;
175175+ fftwf_plan fft;
176176+ fftwf_plan ifft;
177177+ int N;
178178+};
179179+180180+void *spx_fft_init(int size)
181181+{
182182+ struct fftw_config *table = (struct fftw_config *) speex_alloc(sizeof(struct fftw_config));
183183+ table->in = fftwf_malloc(sizeof(float) * (size+2));
184184+ table->out = fftwf_malloc(sizeof(float) * (size+2));
185185+186186+ table->fft = fftwf_plan_dft_r2c_1d(size, table->in, (fftwf_complex *) table->out, FFTW_PATIENT);
187187+ table->ifft = fftwf_plan_dft_c2r_1d(size, (fftwf_complex *) table->in, table->out, FFTW_PATIENT);
188188+189189+ table->N = size;
190190+ return table;
191191+}
192192+193193+void spx_fft_destroy(void *table)
194194+{
195195+ struct fftw_config *t = (struct fftw_config *) table;
196196+ fftwf_destroy_plan(t->fft);
197197+ fftwf_destroy_plan(t->ifft);
198198+ fftwf_free(t->in);
199199+ fftwf_free(t->out);
200200+ speex_free(table);
201201+}
202202+203203+204204+void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out)
205205+{
206206+ int i;
207207+ struct fftw_config *t = (struct fftw_config *) table;
208208+ const int N = t->N;
209209+ float *iptr = t->in;
210210+ float *optr = t->out;
211211+ const float m = 1.0 / N;
212212+ for(i=0;i<N;++i)
213213+ iptr[i]=in[i] * m;
214214+215215+ fftwf_execute(t->fft);
216216+217217+ out[0] = optr[0];
218218+ for(i=1;i<N;++i)
219219+ out[i] = optr[i+1];
220220+}
221221+222222+void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out)
223223+{
224224+ int i;
225225+ struct fftw_config *t = (struct fftw_config *) table;
226226+ const int N = t->N;
227227+ float *iptr = t->in;
228228+ float *optr = t->out;
229229+230230+ iptr[0] = in[0];
231231+ iptr[1] = 0.0f;
232232+ for(i=1;i<N;++i)
233233+ iptr[i+1] = in[i];
234234+ iptr[N+1] = 0.0f;
235235+236236+ fftwf_execute(t->ifft);
237237+238238+ for(i=0;i<N;++i)
239239+ out[i] = optr[i];
131240}
132241133242#elif defined(USE_KISS_FFT)
···77 Redistribution and use in source and binary forms, with or without
88 modification, are permitted provided that the following conditions
99 are met:
1010-1010+1111 - Redistributions of source code must retain the above copyright
1212 notice, this list of conditions and the following disclaimer.
1313-1313+1414 - Redistributions in binary form must reproduce the above copyright
1515 notice, this list of conditions and the following disclaimer in the
1616 documentation and/or other materials provided with the distribution.
1717-1717+1818 - Neither the name of the Xiph.org Foundation nor the names of its
1919 contributors may be used to endorse or promote products derived from
2020 this software without specific prior written permission.
2121-2121+2222 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2323 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2424 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
···101101}
102102103103#define SHR16(a, shift) _SHR16(a, shift, __FILE__, __LINE__)
104104-static inline short _SHR16(int a, int shift, char *file, int line)
104104+static inline short _SHR16(int a, int shift, char *file, int line)
105105{
106106 int res;
107107 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift))
···115115 return res;
116116}
117117#define SHL16(a, shift) _SHL16(a, shift, __FILE__, __LINE__)
118118-static inline short _SHL16(int a, int shift, char *file, int line)
118118+static inline short _SHL16(int a, int shift, char *file, int line)
119119{
120120 int res;
121121 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift))
···129129 return res;
130130}
131131132132-static inline int SHR32(long long a, int shift)
132132+static inline int SHR32(long long a, int shift)
133133{
134134 long long res;
135135 if (!VERIFY_INT(a) || !VERIFY_SHORT(shift))
···144144 spx_mips++;
145145 return res;
146146}
147147-static inline int SHL32(long long a, int shift)
147147+static inline int SHL32(long long a, int shift)
148148{
149149 long long res;
150150 if (!VERIFY_INT(a) || !VERIFY_SHORT(shift))
···161161}
162162163163#define PSHR16(a,shift) (SHR16(ADD16((a),((1<<((shift))>>1))),shift))
164164-#define PSHR32(a,shift) (SHR32(ADD32((a),((1<<((shift))>>1))),shift))
164164+#define PSHR32(a,shift) (SHR32(ADD32((a),((EXTEND32(1)<<((shift))>>1))),shift))
165165#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
166166167167#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
···171171//#define SHL(a,shift) ((a) << (shift))
172172173173#define ADD16(a, b) _ADD16(a, b, __FILE__, __LINE__)
174174-static inline short _ADD16(int a, int b, char *file, int line)
174174+static inline short _ADD16(int a, int b, char *file, int line)
175175{
176176 int res;
177177 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
···188188}
189189190190#define SUB16(a, b) _SUB16(a, b, __FILE__, __LINE__)
191191-static inline short _SUB16(int a, int b, char *file, int line)
191191+static inline short _SUB16(int a, int b, char *file, int line)
192192{
193193 int res;
194194 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
···203203}
204204205205#define ADD32(a, b) _ADD32(a, b, __FILE__, __LINE__)
206206-static inline int _ADD32(long long a, long long b, char *file, int line)
206206+static inline int _ADD32(long long a, long long b, char *file, int line)
207207{
208208 long long res;
209209 if (!VERIFY_INT(a) || !VERIFY_INT(b))
···219219 return res;
220220}
221221222222-static inline int SUB32(long long a, long long b)
222222+static inline int SUB32(long long a, long long b)
223223{
224224 long long res;
225225 if (!VERIFY_INT(a) || !VERIFY_INT(b))
···236236#define ADD64(a,b) (MIPS_INC(a)+(b))
237237238238/* result fits in 16 bits */
239239-static inline short MULT16_16_16(int a, int b)
239239+static inline short MULT16_16_16(int a, int b)
240240{
241241 int res;
242242 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
···251251}
252252253253#define MULT16_16(a, b) _MULT16_16(a, b, __FILE__, __LINE__)
254254-static inline int _MULT16_16(int a, int b, char *file, int line)
254254+static inline int _MULT16_16(int a, int b, char *file, int line)
255255{
256256 long long res;
257257 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
···279279 {
280280 fprintf (stderr, "MULT16_32_Q%d: inputs are not short+int: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
281281 }
282282- if (ABS32(b)>=(1<<(15+Q)))
283283- fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
282282+ if (ABS32(b)>=(EXTEND32(1)<<(15+Q)))
283283+ fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
284284 res = (((long long)a)*(long long)b) >> Q;
285285 if (!VERIFY_INT(res))
286286 fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line);
···295295 {
296296 fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d\n", Q, (int)a, (int)b);
297297 }
298298- if (ABS32(b)>=(1<<(15+Q)))
299299- fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b);
300300- res = ((((long long)a)*(long long)b) + ((1<<Q)>>1))>> Q;
298298+ if (ABS32(b)>=(EXTEND32(1)<<(15+Q)))
299299+ fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b);
300300+ res = ((((long long)a)*(long long)b) + ((EXTEND32(1)<<Q)>>1))>> Q;
301301 if (!VERIFY_INT(res))
302302 fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d\n", Q, (int)a, (int)b,(int)res);
303303 spx_mips+=5;
···323323 return a;
324324}
325325326326-static inline int MULT16_16_Q11_32(int a, int b)
326326+static inline int MULT16_16_Q11_32(int a, int b)
327327{
328328 long long res;
329329 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
···337337 spx_mips+=3;
338338 return res;
339339}
340340-static inline short MULT16_16_Q13(int a, int b)
340340+static inline short MULT16_16_Q13(int a, int b)
341341{
342342 long long res;
343343 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
···351351 spx_mips+=3;
352352 return res;
353353}
354354-static inline short MULT16_16_Q14(int a, int b)
354354+static inline short MULT16_16_Q14(int a, int b)
355355{
356356 long long res;
357357 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
···365365 spx_mips+=3;
366366 return res;
367367}
368368-static inline short MULT16_16_Q15(int a, int b)
368368+static inline short MULT16_16_Q15(int a, int b)
369369{
370370 long long res;
371371 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
···382382 return res;
383383}
384384385385-static inline short MULT16_16_P13(int a, int b)
385385+static inline short MULT16_16_P13(int a, int b)
386386{
387387 long long res;
388388 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
···399399 spx_mips+=4;
400400 return res;
401401}
402402-static inline short MULT16_16_P14(int a, int b)
402402+static inline short MULT16_16_P14(int a, int b)
403403{
404404 long long res;
405405 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
···416416 spx_mips+=4;
417417 return res;
418418}
419419-static inline short MULT16_16_P15(int a, int b)
419419+static inline short MULT16_16_P15(int a, int b)
420420{
421421 long long res;
422422 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
···436436437437#define DIV32_16(a, b) _DIV32_16(a, b, __FILE__, __LINE__)
438438439439-static inline int _DIV32_16(long long a, long long b, char *file, int line)
439439+static inline int _DIV32_16(long long a, long long b, char *file, int line)
440440{
441441 long long res;
442442 if (b==0)
···462462}
463463464464#define DIV32(a, b) _DIV32(a, b, __FILE__, __LINE__)
465465-static inline int _DIV32(long long a, long long b, char *file, int line)
465465+static inline int _DIV32(long long a, long long b, char *file, int line)
466466{
467467 long long res;
468468 if (b==0)
···11-/* Copyright (C) 2002 Jean-Marc Valin
11+/* Copyright (C) 2002 Jean-Marc Valin
22 File: speex_jitter.h
3344 Adaptive jitter buffer for Speex
···66 Redistribution and use in source and binary forms, with or without
77 modification, are permitted provided that the following conditions
88 are met:
99-99+1010 - Redistributions of source code must retain the above copyright
1111 notice, this list of conditions and the following disclaimer.
1212-1212+1313 - Redistributions in binary form must reproduce the above copyright
1414 notice, this list of conditions and the following disclaimer in the
1515 documentation and/or other materials provided with the distribution.
1616-1616+1717 - Neither the name of the Xiph.org Foundation nor the names of its
1818 contributors may be used to endorse or promote products derived from
1919 this software without specific prior written permission.
2020-2020+2121 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2222 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2323 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
···7373#define LT32(a,b) (((spx_int32_t)((a)-(b)))<0)
7474#define LE32(a,b) (((spx_int32_t)((a)-(b)))<=0)
75757676-#define ROUND_DOWN(x, step) ((x)<0 ? ((x)-(step)+1)/(step)*(step) : (x)/(step)*(step))
7676+#define ROUND_DOWN(x, step) ((x)<0 ? ((x)-(step)+1)/(step)*(step) : (x)/(step)*(step))
77777878-#define MAX_TIMINGS 20
7878+#define MAX_TIMINGS 40
7979#define MAX_BUFFERS 3
8080-#define TOP_DELAY 20
8080+#define TOP_DELAY 40
81818282/** Buffer that keeps the time of arrival of the latest packets */
8383struct TimingBuffer {
8484 int filled; /**< Number of entries occupied in "timing" and "counts"*/
8585 int curr_count; /**< Number of packet timings we got (including those we discarded) */
8686- spx_int16_t timing[MAX_TIMINGS]; /**< Sorted list of all timings ("latest" packets first) */
8686+ spx_int32_t timing[MAX_TIMINGS]; /**< Sorted list of all timings ("latest" packets first) */
8787 spx_int16_t counts[MAX_TIMINGS]; /**< Order the packets were put in (will be used for short-term estimate) */
8888};
8989···103103 tb->curr_count++;
104104 return;
105105 }
106106-106106+107107 /* Find where the timing info goes in the sorted list */
108108 pos = 0;
109109 /* FIXME: Do bisection instead of linear search */
···111111 {
112112 pos++;
113113 }
114114-114114+115115 speex_assert(pos <= tb->filled && pos < MAX_TIMINGS);
116116-116116+117117 /* Shift everything so we can perform the insertion */
118118 if (pos < tb->filled)
119119 {
···126126 /* Insert */
127127 tb->timing[pos] = timing;
128128 tb->counts[pos] = tb->curr_count;
129129-129129+130130 tb->curr_count++;
131131 if (tb->filled<MAX_TIMINGS)
132132 tb->filled++;
···139139 spx_uint32_t pointer_timestamp; /**< Timestamp of what we will *get* next */
140140 spx_uint32_t last_returned_timestamp; /**< Useful for getting the next packet with the same timestamp (for fragmented media) */
141141 spx_uint32_t next_stop; /**< Estimated time the next get() will be called */
142142-142142+143143 spx_int32_t buffered; /**< Amount of data we think is still buffered by the application (timestamp units)*/
144144-144144+145145 JitterBufferPacket packets[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packets stored in the buffer */
146146 spx_uint32_t arrival[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packet arrival time (0 means it was late, even though it's a valid timestamp) */
147147-147147+148148 void (*destroy) (void *); /**< Callback for destroying a packet */
149149150150 spx_int32_t delay_step; /**< Size of the steps when adjusting buffering (timestamp units) */
···154154 int late_cutoff; /**< How late must a packet be for it not to be considered at all */
155155 int interp_requested; /**< An interpolation is requested by speex_jitter_update_delay() */
156156 int auto_adjust; /**< Whether to automatically adjust the delay at any time */
157157-157157+158158 struct TimingBuffer _tb[MAX_BUFFERS]; /**< Don't use those directly */
159159 struct TimingBuffer *timeBuffers[MAX_BUFFERS]; /**< Storing arrival time of latest frames so we can compute some stats */
160160 int window_size; /**< Total window over which the late frames are counted */
···162162 int max_late_rate; /**< Absolute maximum amount of late packets tolerable (in percent) */
163163 int latency_tradeoff; /**< Latency equivalent of losing one percent of packets */
164164 int auto_tradeoff; /**< Latency equivalent of losing one percent of packets (automatic default) */
165165-165165+166166 int lost_count; /**< Number of consecutive lost packets */
167167};
168168169169-/** Based on available data, this computes the optimal delay for the jitter buffer.
169169+/** Based on available data, this computes the optimal delay for the jitter buffer.
170170 The optimised function is in timestamp units and is:
171171 cost = delay + late_factor*[number of frames that would be late if we used that delay]
172172 @param tb Array of buffers
173173- @param late_factor Equivalent cost of a late frame (in timestamp units)
173173+ @param late_factor Equivalent cost of a late frame (in timestamp units)
174174 */
175175static spx_int16_t compute_opt_delay(JitterBuffer *jitter)
176176{
···186186 int worst = 0;
187187 spx_int32_t deltaT;
188188 struct TimingBuffer *tb;
189189-189189+190190 tb = jitter->_tb;
191191-191191+192192 /* Number of packet timings we have received (including those we didn't keep) */
193193 tot_count = 0;
194194 for (i=0;i<MAX_BUFFERS;i++)
195195 tot_count += tb[i].curr_count;
196196 if (tot_count==0)
197197 return 0;
198198-198198+199199 /* Compute cost for one lost packet */
200200 if (jitter->latency_tradeoff != 0)
201201 late_factor = jitter->latency_tradeoff * 100.0f / tot_count;
202202 else
203203 late_factor = jitter->auto_tradeoff * jitter->window_size/tot_count;
204204-204204+205205 /*fprintf(stderr, "late_factor = %f\n", late_factor);*/
206206 for (i=0;i<MAX_BUFFERS;i++)
207207 pos[i] = 0;
208208-209209- /* Pick the TOP_DELAY "latest" packets (doesn't need to actually be late
208208+209209+ /* Pick the TOP_DELAY "latest" packets (doesn't need to actually be late
210210 for the current settings) */
211211 for (i=0;i<TOP_DELAY;i++)
212212 {
···225225 if (next != -1)
226226 {
227227 spx_int32_t cost;
228228-228228+229229 if (i==0)
230230 worst = latest;
231231 best = latest;
232232 latest = ROUND_DOWN(latest, jitter->delay_step);
233233 pos[next]++;
234234-234234+235235 /* Actual cost function that tells us how bad using this delay would be */
236236 cost = -latest + late_factor*late;
237237 /*fprintf(stderr, "cost %d = %d + %f * %d\n", cost, -latest, late_factor, late);*/
···243243 } else {
244244 break;
245245 }
246246-246246+247247 /* For the next timing we will consider, there will be one more late packet to count */
248248 late++;
249249 /* Two-frame penalty if we're going to increase the amount of late frames (hysteresis) */
250250 if (latest >= 0 && !penalty_taken)
251251 {
252252 penalty_taken = 1;
253253- late+=2;
253253+ late+=4;
254254 }
255255 }
256256-256256+257257 deltaT = best-worst;
258258 /* This is a default "automatic latency tradeoff" when none is provided */
259259 jitter->auto_tradeoff = 1 + deltaT/TOP_DELAY;
260260 /*fprintf(stderr, "auto_tradeoff = %d (%d %d %d)\n", jitter->auto_tradeoff, best, worst, i);*/
261261-261261+262262 /* FIXME: Compute a short-term estimate too and combine with the long-term one */
263263-263263+264264 /* Prevents reducing the buffer size when we haven't really had much data */
265265 if (tot_count < TOP_DELAY && opt > 0)
266266 return 0;
···269269270270271271/** Initialise jitter buffer */
272272-JitterBuffer *jitter_buffer_init(int step_size)
272272+EXPORT JitterBuffer *jitter_buffer_init(int step_size)
273273{
274274 JitterBuffer *jitter = (JitterBuffer*)speex_alloc(sizeof(JitterBuffer));
275275 if (jitter)
···294294}
295295296296/** Reset jitter buffer */
297297-void jitter_buffer_reset(JitterBuffer *jitter)
297297+EXPORT void jitter_buffer_reset(JitterBuffer *jitter)
298298{
299299 int i;
300300 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
···315315 jitter->lost_count = 0;
316316 jitter->buffered = 0;
317317 jitter->auto_tradeoff = 32000;
318318-318318+319319 for (i=0;i<MAX_BUFFERS;i++)
320320 {
321321 tb_init(&jitter->_tb[i]);
···325325}
326326327327/** Destroy jitter buffer */
328328-void jitter_buffer_destroy(JitterBuffer *jitter)
328328+EXPORT void jitter_buffer_destroy(JitterBuffer *jitter)
329329{
330330 jitter_buffer_reset(jitter);
331331 speex_free(jitter);
···365365366366367367/** Put one packet into the jitter buffer */
368368-void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
368368+EXPORT void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
369369{
370370 int i,j;
371371 int late;
372372 /*fprintf (stderr, "put packet %d %d\n", timestamp, span);*/
373373-373373+374374 /* Cleanup buffer (remove old packets that weren't played) */
375375 if (!jitter->reset_state)
376376 {
···388388 }
389389 }
390390 }
391391-391391+392392 /*fprintf(stderr, "arrival: %d %d %d\n", packet->timestamp, jitter->next_stop, jitter->pointer_timestamp);*/
393393 /* Check if packet is late (could still be useful though) */
394394 if (!jitter->reset_state && LT32(packet->timestamp, jitter->next_stop))
···398398 } else {
399399 late = 0;
400400 }
401401-401401+402402+ /* For some reason, the consumer has failed the last 20 fetches. Make sure this packet is
403403+ * used to resync. */
404404+ if (jitter->lost_count>20)
405405+ {
406406+ jitter_buffer_reset(jitter);
407407+ }
408408+402409 /* Only insert the packet if it's not hopelessly late (i.e. totally useless) */
403410 if (jitter->reset_state || GE32(packet->timestamp+packet->span+jitter->delay_step, jitter->pointer_timestamp))
404411 {
···409416 if (jitter->packets[i].data==NULL)
410417 break;
411418 }
412412-419419+413420 /*No place left in the buffer, need to make room for it by discarding the oldest packet */
414421 if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
415422 {
···428435 else
429436 speex_free(jitter->packets[i].data);
430437 jitter->packets[i].data=NULL;
431431- if (jitter->lost_count>20)
432432- {
433433- jitter_buffer_reset(jitter);
434434- }
435435- /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/
438438+ /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/
436439 }
437437-440440+438441 /* Copy packet in buffer */
439442 if (jitter->destroy)
440443 {
···454457 else
455458 jitter->arrival[i] = jitter->next_stop;
456459 }
457457-458458-460460+461461+459462}
460463461464/** Get one packet from the jitter buffer */
462462-int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset)
465465+EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset)
463466{
464467 int i;
465468 unsigned int j;
466469 int incomplete = 0;
467470 spx_int16_t opt;
468468-471471+469472 if (start_offset != NULL)
470473 *start_offset = 0;
471474···485488 }
486489 if (found)
487490 {
488488- jitter->reset_state=0;
491491+ jitter->reset_state=0;
489492 jitter->pointer_timestamp = oldest;
490493 jitter->next_stop = oldest;
491494 } else {
···494497 return JITTER_BUFFER_MISSING;
495498 }
496499 }
497497-500500+498501499502 jitter->last_returned_timestamp = jitter->pointer_timestamp;
500500-503503+501504 if (jitter->interp_requested != 0)
502505 {
503506 packet->timestamp = jitter->pointer_timestamp;
504507 packet->span = jitter->interp_requested;
505505-508508+506509 /* Increment the pointer because it got decremented in the delay update */
507510 jitter->pointer_timestamp += jitter->interp_requested;
508511 packet->len = 0;
509512 /*fprintf (stderr, "Deferred interpolate\n");*/
510510-513513+511514 jitter->interp_requested = 0;
512512-515515+513516 jitter->buffered = packet->span - desired_span;
514517515518 return JITTER_BUFFER_INSERTION;
516519 }
517517-520520+518521 /* Searching for the packet that fits best */
519519-522522+520523 /* Search the buffer for a packet with the right timestamp and spanning the whole current chunk */
521524 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
522525 {
523526 if (jitter->packets[i].data && jitter->packets[i].timestamp==jitter->pointer_timestamp && GE32(jitter->packets[i].timestamp+jitter->packets[i].span,jitter->pointer_timestamp+desired_span))
524527 break;
525528 }
526526-529529+527530 /* If no match, try for an "older" packet that still spans (fully) the current chunk */
528531 if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
529532 {
···533536 break;
534537 }
535538 }
536536-539539+537540 /* If still no match, try for an "older" packet that spans part of the current chunk */
538541 if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
539542 {
···543546 break;
544547 }
545548 }
546546-549549+547550 /* If still no match, try for earliest packet possible */
548551 if (i==SPEEX_JITTER_MAX_BUFFER_SIZE)
549552 {
···577580 if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE)
578581 {
579582 spx_int32_t offset;
580580-583583+581584 /* We (obviously) haven't lost this packet */
582585 jitter->lost_count = 0;
583583-586586+584587 /* In this case, 0 isn't as a valid timestamp */
585588 if (jitter->arrival[i] != 0)
586589 {
587590 update_timings(jitter, ((spx_int32_t)jitter->packets[i].timestamp) - ((spx_int32_t)jitter->arrival[i]) - jitter->buffer_margin);
588591 }
589589-590590-592592+593593+591594 if (jitter->packets[i].len > packet->len)
592595 {
593596 speex_warning_int("jitter_buffer_get(): packet too large to fit. Size is", jitter->packets[i].len);
···611614 *start_offset = offset;
612615 else if (offset != 0)
613616 speex_warning_int("jitter_buffer_get() discarding non-zero start_offset", offset);
614614-617617+615618 packet->timestamp = jitter->packets[i].timestamp;
616619 jitter->last_returned_timestamp = packet->timestamp;
617617-620620+618621 packet->span = jitter->packets[i].span;
619622 packet->sequence = jitter->packets[i].sequence;
620623 packet->user_data = jitter->packets[i].user_data;
···622625 jitter->pointer_timestamp = jitter->packets[i].timestamp+jitter->packets[i].span;
623626624627 jitter->buffered = packet->span - desired_span;
625625-628628+626629 if (start_offset != NULL)
627630 jitter->buffered += *start_offset;
628628-631631+629632 return JITTER_BUFFER_OK;
630633 }
631631-632632-634634+635635+633636 /* If we haven't found anything worth returning */
634634-637637+635638 /*fprintf (stderr, "not found\n");*/
636639 jitter->lost_count++;
637640 /*fprintf (stderr, "m");*/
638641 /*fprintf (stderr, "lost_count = %d\n", jitter->lost_count);*/
639639-642642+640643 opt = compute_opt_delay(jitter);
641641-642642- /* Should we force an increase in the buffer or just do normal interpolation? */
644644+645645+ /* Should we force an increase in the buffer or just do normal interpolation? */
643646 if (opt < 0)
644647 {
645648 /* Need to increase buffering */
646646-649649+647650 /* Shift histogram to compensate */
648651 shift_timings(jitter, -opt);
649649-652652+650653 packet->timestamp = jitter->pointer_timestamp;
651654 packet->span = -opt;
652655 /* Don't move the pointer_timestamp forward */
653656 packet->len = 0;
654654-657657+655658 jitter->buffered = packet->span - desired_span;
656659 return JITTER_BUFFER_INSERTION;
657660 /*jitter->pointer_timestamp -= jitter->delay_step;*/
···659662 } else {
660663 /* Normal packet loss */
661664 packet->timestamp = jitter->pointer_timestamp;
662662-665665+663666 desired_span = ROUND_DOWN(desired_span, jitter->concealment_size);
664667 packet->span = desired_span;
665668 jitter->pointer_timestamp += desired_span;
666669 packet->len = 0;
667667-670670+668671 jitter->buffered = packet->span - desired_span;
669672 return JITTER_BUFFER_MISSING;
670673 /*fprintf (stderr, "Normal loss\n");*/
···673676674677}
675678676676-int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet)
679679+EXPORT int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet)
677680{
678681 int i, j;
679682 for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++)
···713716{
714717 spx_int16_t opt = compute_opt_delay(jitter);
715718 /*fprintf(stderr, "opt adjustment is %d ", opt);*/
716716-719719+717720 if (opt < 0)
718721 {
719722 shift_timings(jitter, -opt);
720720-723723+721724 jitter->pointer_timestamp += opt;
722725 jitter->interp_requested = -opt;
723726 /*fprintf (stderr, "Decision to interpolate %d samples\n", -opt);*/
···727730 jitter->pointer_timestamp += opt;
728731 /*fprintf (stderr, "Decision to drop %d samples\n", opt);*/
729732 }
730730-733733+731734 return opt;
732735}
733736734737/* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */
735735-int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset)
738738+EXPORT int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset)
736739{
737737- /* If the programmer calls jitter_buffer_update_delay() directly,
740740+ /* If the programmer calls jitter_buffer_update_delay() directly,
738741 automatically disable auto-adjustment */
739742 jitter->auto_adjust = 0;
740743···742745}
743746744747/** Get pointer timestamp of jitter buffer */
745745-int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter)
748748+EXPORT int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter)
746749{
747750 return jitter->pointer_timestamp;
748751}
749752750750-void jitter_buffer_tick(JitterBuffer *jitter)
753753+EXPORT void jitter_buffer_tick(JitterBuffer *jitter)
751754{
752755 /* Automatically-adjust the buffering delay if requested */
753756 if (jitter->auto_adjust)
754757 _jitter_buffer_update_delay(jitter, NULL, NULL);
755755-758758+756759 if (jitter->buffered >= 0)
757760 {
758761 jitter->next_stop = jitter->pointer_timestamp - jitter->buffered;
···763766 jitter->buffered = 0;
764767}
765768766766-void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem)
769769+EXPORT void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem)
767770{
768771 /* Automatically-adjust the buffering delay if requested */
769772 if (jitter->auto_adjust)
770773 _jitter_buffer_update_delay(jitter, NULL, NULL);
771771-774774+772775 if (jitter->buffered < 0)
773776 speex_warning_int("jitter buffer sees negative buffering, your code might be broken. Value is ", jitter->buffered);
774777 jitter->next_stop = jitter->pointer_timestamp - rem;
···776779777780778781/* Used like the ioctl function to control the jitter buffer parameters */
779779-int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
782782+EXPORT int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
780783{
781784 int count, i;
782785 switch(request)
···836839 }
837840 return 0;
838841}
839839-
+342-234
lib/rbcodec/codecs/libspeex/mdf.c
···11-/* Copyright (C) 2003-2006 Jean-Marc Valin
11+/* Copyright (C) 2003-2008 Jean-Marc Valin
2233 File: mdf.c
44 Echo canceller based on the MDF algorithm (see below)
···3333/*
3434 The echo canceller is based on the MDF algorithm described in:
35353636- J. S. Soo, K. K. Pang Multidelay block frequency adaptive filter,
3737- IEEE Trans. Acoust. Speech Signal Process., Vol. ASSP-38, No. 2,
3636+ J. S. Soo, K. K. Pang Multidelay block frequency adaptive filter,
3737+ IEEE Trans. Acoust. Speech Signal Process., Vol. ASSP-38, No. 2,
3838 February 1990.
3939-4040- We use the Alternatively Updated MDF (AUMDF) variant. Robustness to
3939+4040+ We use the Alternatively Updated MDF (AUMDF) variant. Robustness to
4141 double-talk is achieved using a variable learning rate as described in:
4242-4343- Valin, J.-M., On Adjusting the Learning Rate in Frequency Domain Echo
4242+4343+ Valin, J.-M., On Adjusting the Learning Rate in Frequency Domain Echo
4444 Cancellation With Double-Talk. IEEE Transactions on Audio,
4545 Speech and Language Processing, Vol. 15, No. 3, pp. 1030-1034, 2007.
4646 http://people.xiph.org/~jm/papers/valin_taslp2006.pdf
4747-4747+4848 There is no explicit double-talk detection, but a continuous variation
4949 in the learning rate based on residual echo, double-talk and background
5050 noise.
5151-5151+5252 About the fixed-point version:
5353- All the signals are represented with 16-bit words. The filter weights
5353+ All the signals are represented with 16-bit words. The filter weights
5454 are represented with 32-bit words, but only the top 16 bits are used
5555 in most cases. The lower 16 bits are completely unreliable (due to the
5656 fact that the update is done only on the top bits), but help in the
5757 adaptation -- probably by removing a "threshold effect" due to
5858 quantization (rounding going to zero) when the gradient is small.
5959-5959+6060 Another kludge that seems to work good: when performing the weight
6161 update, we only move half the way toward the "goal" this seems to
6262 reduce the effect of quantization noise in the update phase. This
6363 can be seen as applying a gradient descent on a "soft constraint"
6464 instead of having a hard constraint.
6565-6565+6666*/
67676868#ifdef HAVE_CONFIG_H
···8888#define WEIGHT_SHIFT 0
8989#endif
90909191+#ifdef FIXED_POINT
9292+#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x)))
9393+#else
9494+#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x))))
9595+#endif
9696+9197/* If enabled, the AEC will use a foreground filter and a background filter to be more robust to double-talk
9298 and difficult signals in general. The cost is an extra FFT and a matrix-vector multiply */
9399#define TWO_PATH
···131137 int adapted;
132138 int saturated;
133139 int screwed_up;
140140+ int C; /** Number of input channels (microphones) */
141141+ int K; /** Number of output channels (loudspeakers) */
134142 spx_int32_t sampling_rate;
135143 spx_word16_t spec_average;
136144 spx_word16_t beta0;
137145 spx_word16_t beta_max;
138146 spx_word32_t sum_adapt;
139147 spx_word16_t leak_estimate;
140140-148148+141149 spx_word16_t *e; /* scratch */
142150 spx_word16_t *x; /* Far-end input buffer (2N) */
143151 spx_word16_t *X; /* Far-end buffer (M+1 frames) in frequency domain */
···171179 spx_word16_t *window;
172180 spx_word16_t *prop;
173181 void *fft_table;
174174- spx_word16_t memX, memD, memE;
182182+ spx_word16_t *memX, *memD, *memE;
175183 spx_word16_t preemph;
176184 spx_word16_t notch_radius;
177177- spx_mem_t notch_mem[2];
185185+ spx_mem_t *notch_mem;
178186179187 /* NOTE: If you only use speex_echo_cancel() and want to save some memory, remove this */
180188 spx_int16_t *play_buf;
···182190 int play_buf_started;
183191};
184192185185-static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius, spx_word16_t *out, int len, spx_mem_t *mem)
193193+static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius, spx_word16_t *out, int len, spx_mem_t *mem, int stride)
186194{
187195 int i;
188196 spx_word16_t den2;
···190198 den2 = MULT16_16_Q15(radius,radius) + MULT16_16_Q15(QCONST16(.7,15),MULT16_16_Q15(32767-radius,32767-radius));
191199#else
192200 den2 = radius*radius + .7*(1-radius)*(1-radius);
193193-#endif
201201+#endif
194202 /*printf ("%d %d %d %d %d %d\n", num[0], num[1], num[2], den[0], den[1], den[2]);*/
195203 for (i=0;i<len;i++)
196204 {
197197- spx_word16_t vin = in[i];
205205+ spx_word16_t vin = in[i*stride];
198206 spx_word32_t vout = mem[0] + SHL32(EXTEND32(vin),15);
199207#ifdef FIXED_POINT
200208 mem[0] = mem[1] + SHL32(SHL32(-EXTEND32(vin),15) + MULT16_32_Q15(radius,vout),1);
···234242 ps[j]=MULT16_16(X[i],X[i]);
235243}
236244245245+/** Compute power spectrum of a half-complex (packed) vector and accumulate */
246246+static inline void power_spectrum_accum(const spx_word16_t *X, spx_word32_t *ps, int N)
247247+{
248248+ int i, j;
249249+ ps[0]+=MULT16_16(X[0],X[0]);
250250+ for (i=1,j=1;i<N-1;i+=2,j++)
251251+ {
252252+ ps[j] += MULT16_16(X[i],X[i]) + MULT16_16(X[i+1],X[i+1]);
253253+ }
254254+ ps[j]+=MULT16_16(X[i],X[i]);
255255+}
256256+237257/** Compute cross-power spectrum of a half-complex (packed) vectors and add to acc */
238258#ifdef FIXED_POINT
239259static inline void spectral_mul_accum(const spx_word16_t *X, const spx_word32_t *Y, spx_word16_t *acc, int N, int M)
···330350 prod[i] = FLOAT_MUL32(W,MULT16_16(X[i],Y[i]));
331351}
332352333333-static inline void mdf_adjust_prop(const spx_word32_t *W, int N, int M, spx_word16_t *prop)
353353+static inline void mdf_adjust_prop(const spx_word32_t *W, int N, int M, int P, spx_word16_t *prop)
334354{
335335- int i, j;
355355+ int i, j, p;
336356 spx_word16_t max_sum = 1;
337357 spx_word32_t prop_sum = 1;
338358 for (i=0;i<M;i++)
339359 {
340360 spx_word32_t tmp = 1;
341341- for (j=0;j<N;j++)
342342- tmp += MULT16_16(EXTRACT16(SHR32(W[i*N+j],18)), EXTRACT16(SHR32(W[i*N+j],18)));
361361+ for (p=0;p<P;p++)
362362+ for (j=0;j<N;j++)
363363+ tmp += MULT16_16(EXTRACT16(SHR32(W[p*N*M + i*N+j],18)), EXTRACT16(SHR32(W[p*N*M + i*N+j],18)));
343364#ifdef FIXED_POINT
344365 /* Just a security in case an overflow were to occur */
345366 tmp = MIN32(ABS32(tmp), 536870912);
···378399#endif
379400380401/** Creates a new echo canceller state */
381381-SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
402402+EXPORT SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
382403{
383383- int i,N,M;
404404+ return speex_echo_state_init_mc(frame_size, filter_length, 1, 1);
405405+}
406406+407407+EXPORT SpeexEchoState *speex_echo_state_init_mc(int frame_size, int filter_length, int nb_mic, int nb_speakers)
408408+{
409409+ int i,N,M, C, K;
384410 SpeexEchoState *st = (SpeexEchoState *)speex_alloc(sizeof(SpeexEchoState));
385411412412+ st->K = nb_speakers;
413413+ st->C = nb_mic;
414414+ C=st->C;
415415+ K=st->K;
386416#ifdef DUMP_ECHO_CANCEL_DATA
387417 if (rFile || pFile || oFile)
388418 speex_fatal("Opening dump files twice");
···390420 pFile = fopen("aec_play.sw", "wb");
391421 oFile = fopen("aec_out.sw", "wb");
392422#endif
393393-423423+394424 st->frame_size = frame_size;
395425 st->window_size = 2*frame_size;
396426 N = st->window_size;
···412442 st->leak_estimate = 0;
413443414444 st->fft_table = spx_fft_init(N);
415415-416416- st->e = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
417417- st->x = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
418418- st->input = (spx_word16_t*)speex_alloc(st->frame_size*sizeof(spx_word16_t));
419419- st->y = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
420420- st->last_y = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
445445+446446+ st->e = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t));
447447+ st->x = (spx_word16_t*)speex_alloc(K*N*sizeof(spx_word16_t));
448448+ st->input = (spx_word16_t*)speex_alloc(C*st->frame_size*sizeof(spx_word16_t));
449449+ st->y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t));
450450+ st->last_y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t));
421451 st->Yf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
422452 st->Rf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
423453 st->Xf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
424454 st->Yh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
425455 st->Eh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
426456427427- st->X = (spx_word16_t*)speex_alloc((M+1)*N*sizeof(spx_word16_t));
428428- st->Y = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
429429- st->E = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
430430- st->W = (spx_word32_t*)speex_alloc(M*N*sizeof(spx_word32_t));
457457+ st->X = (spx_word16_t*)speex_alloc(K*(M+1)*N*sizeof(spx_word16_t));
458458+ st->Y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t));
459459+ st->E = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t));
460460+ st->W = (spx_word32_t*)speex_alloc(C*K*M*N*sizeof(spx_word32_t));
431461#ifdef TWO_PATH
432432- st->foreground = (spx_word16_t*)speex_alloc(M*N*sizeof(spx_word16_t));
462462+ st->foreground = (spx_word16_t*)speex_alloc(M*N*C*K*sizeof(spx_word16_t));
433463#endif
434464 st->PHI = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t));
435465 st->power = (spx_word32_t*)speex_alloc((frame_size+1)*sizeof(spx_word32_t));
···450480#endif
451481 for (i=0;i<=st->frame_size;i++)
452482 st->power_1[i] = FLOAT_ONE;
453453- for (i=0;i<N*M;i++)
483483+ for (i=0;i<N*M*K*C;i++)
454484 st->W[i] = 0;
455485 {
456486 spx_word32_t sum = 0;
···465495 }
466496 for (i=M-1;i>=0;i--)
467497 {
468468- st->prop[i] = DIV32(MULT16_16(QCONST16(.8,15), st->prop[i]),sum);
498498+ st->prop[i] = DIV32(MULT16_16(QCONST16(.8f,15), st->prop[i]),sum);
469499 }
470500 }
471471-472472- st->memX=st->memD=st->memE=0;
501501+502502+ st->memX = (spx_word16_t*)speex_alloc(K*sizeof(spx_word16_t));
503503+ st->memD = (spx_word16_t*)speex_alloc(C*sizeof(spx_word16_t));
504504+ st->memE = (spx_word16_t*)speex_alloc(C*sizeof(spx_word16_t));
473505 st->preemph = QCONST16(.9,15);
474506 if (st->sampling_rate<12000)
475507 st->notch_radius = QCONST16(.9, 15);
···478510 else
479511 st->notch_radius = QCONST16(.992, 15);
480512481481- st->notch_mem[0] = st->notch_mem[1] = 0;
513513+ st->notch_mem = (spx_mem_t*)speex_alloc(2*C*sizeof(spx_mem_t));
482514 st->adapted = 0;
483515 st->Pey = st->Pyy = FLOAT_ONE;
484484-516516+485517#ifdef TWO_PATH
486518 st->Davg1 = st->Davg2 = 0;
487519 st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
488520#endif
489489-490490- st->play_buf = (spx_int16_t*)speex_alloc((PLAYBACK_DELAY+1)*st->frame_size*sizeof(spx_int16_t));
521521+522522+ st->play_buf = (spx_int16_t*)speex_alloc(K*(PLAYBACK_DELAY+1)*st->frame_size*sizeof(spx_int16_t));
491523 st->play_buf_pos = PLAYBACK_DELAY*st->frame_size;
492524 st->play_buf_started = 0;
493493-525525+494526 return st;
495527}
496528497529/** Resets echo canceller state */
498498-void speex_echo_state_reset(SpeexEchoState *st)
530530+EXPORT void speex_echo_state_reset(SpeexEchoState *st)
499531{
500500- int i, M, N;
532532+ int i, M, N, C, K;
501533 st->cancel_count=0;
502534 st->screwed_up = 0;
503535 N = st->window_size;
504536 M = st->M;
537537+ C=st->C;
538538+ K=st->K;
505539 for (i=0;i<N*M;i++)
506540 st->W[i] = 0;
507541#ifdef TWO_PATH
···521555 {
522556 st->last_y[i] = 0;
523557 }
524524- for (i=0;i<N;i++)
558558+ for (i=0;i<N*C;i++)
525559 {
526560 st->E[i] = 0;
561561+ }
562562+ for (i=0;i<N*K;i++)
563563+ {
527564 st->x[i] = 0;
528565 }
529529- st->notch_mem[0] = st->notch_mem[1] = 0;
530530- st->memX=st->memD=st->memE=0;
566566+ for (i=0;i<2*C;i++)
567567+ st->notch_mem[i] = 0;
568568+ for (i=0;i<C;i++)
569569+ st->memD[i]=st->memE[i]=0;
570570+ for (i=0;i<K;i++)
571571+ st->memX[i]=0;
531572532573 st->saturated = 0;
533574 st->adapted = 0;
···545586}
546587547588/** Destroys an echo canceller state */
548548-void speex_echo_state_destroy(SpeexEchoState *st)
589589+EXPORT void speex_echo_state_destroy(SpeexEchoState *st)
549590{
550591 spx_fft_destroy(st->fft_table);
551592···576617#ifdef FIXED_POINT
577618 speex_free(st->wtmp2);
578619#endif
620620+ speex_free(st->memX);
621621+ speex_free(st->memD);
622622+ speex_free(st->memE);
623623+ speex_free(st->notch_mem);
624624+579625 speex_free(st->play_buf);
580626 speex_free(st);
581581-627627+582628#ifdef DUMP_ECHO_CANCEL_DATA
583629 fclose(rFile);
584630 fclose(pFile);
···587633#endif
588634}
589635590590-void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out)
636636+EXPORT void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out)
591637{
592638 int i;
593639 /*speex_warning_int("capture with fill level ", st->play_buf_pos/st->frame_size);*/
···610656 }
611657}
612658613613-void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play)
659659+EXPORT void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play)
614660{
615661 /*speex_warning_int("playback with fill level ", st->play_buf_pos/st->frame_size);*/
616662 if (!st->play_buf_started)
···637683}
638684639685/** Performs echo cancellation on a frame (deprecated, last arg now ignored) */
640640-void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out, spx_int32_t *Yout)
686686+EXPORT void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out, spx_int32_t *Yout)
641687{
642688 speex_echo_cancellation(st, in, far_end, out);
643689}
644690645691/** Performs echo cancellation on a frame */
646646-void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out)
692692+EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out)
647693{
648648- int i,j;
649649- int N,M;
694694+ int i,j, chan, speak;
695695+ int N,M, C, K;
650696 spx_word32_t Syy,See,Sxx,Sdd, Sff;
651697#ifdef TWO_PATH
652698 spx_word32_t Dbf;
···658704 spx_float_t alpha, alpha_1;
659705 spx_word16_t RER;
660706 spx_word32_t tmp32;
661661-707707+662708 N = st->window_size;
663709 M = st->M;
710710+ C = st->C;
711711+ K = st->K;
712712+664713 st->cancel_count++;
665714#ifdef FIXED_POINT
666715 ss=DIV32_16(11469,M);
···670719 ss_1 = 1-ss;
671720#endif
672721673673- /* Apply a notch filter to make sure DC doesn't end up causing problems */
674674- filter_dc_notch16(in, st->notch_radius, st->input, st->frame_size, st->notch_mem);
675675- /* Copy input data to buffer and apply pre-emphasis */
676676- for (i=0;i<st->frame_size;i++)
722722+ for (chan = 0; chan < C; chan++)
677723 {
678678- spx_word32_t tmp32;
679679- tmp32 = SUB32(EXTEND32(far_end[i]), EXTEND32(MULT16_16_P15(st->preemph, st->memX)));
680680-#ifdef FIXED_POINT
681681- /* If saturation occurs here, we need to freeze adaptation for M+1 frames (not just one) */
682682- if (tmp32 > 32767)
724724+ /* Apply a notch filter to make sure DC doesn't end up causing problems */
725725+ filter_dc_notch16(in+chan, st->notch_radius, st->input+chan*st->frame_size, st->frame_size, st->notch_mem+2*chan, C);
726726+ /* Copy input data to buffer and apply pre-emphasis */
727727+ /* Copy input data to buffer */
728728+ for (i=0;i<st->frame_size;i++)
683729 {
684684- tmp32 = 32767;
685685- st->saturated = M+1;
730730+ spx_word32_t tmp32;
731731+ /* FIXME: This core has changed a bit, need to merge properly */
732732+ tmp32 = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(MULT16_16_P15(st->preemph, st->memD[chan])));
733733+#ifdef FIXED_POINT
734734+ if (tmp32 > 32767)
735735+ {
736736+ tmp32 = 32767;
737737+ if (st->saturated == 0)
738738+ st->saturated = 1;
739739+ }
740740+ if (tmp32 < -32767)
741741+ {
742742+ tmp32 = -32767;
743743+ if (st->saturated == 0)
744744+ st->saturated = 1;
745745+ }
746746+#endif
747747+ st->memD[chan] = st->input[chan*st->frame_size+i];
748748+ st->input[chan*st->frame_size+i] = EXTRACT16(tmp32);
686749 }
687687- if (tmp32 < -32767)
750750+ }
751751+752752+ for (speak = 0; speak < K; speak++)
753753+ {
754754+ for (i=0;i<st->frame_size;i++)
688755 {
689689- tmp32 = -32767;
690690- st->saturated = M+1;
691691- }
692692-#endif
693693- st->x[i+st->frame_size] = EXTRACT16(tmp32);
694694- st->memX = far_end[i];
695695-696696- tmp32 = SUB32(EXTEND32(st->input[i]), EXTEND32(MULT16_16_P15(st->preemph, st->memD)));
756756+ spx_word32_t tmp32;
757757+ st->x[speak*N+i] = st->x[speak*N+i+st->frame_size];
758758+ tmp32 = SUB32(EXTEND32(far_end[i*K+speak]), EXTEND32(MULT16_16_P15(st->preemph, st->memX[speak])));
697759#ifdef FIXED_POINT
698698- if (tmp32 > 32767)
699699- {
700700- tmp32 = 32767;
701701- if (st->saturated == 0)
702702- st->saturated = 1;
703703- }
704704- if (tmp32 < -32767)
760760+ /*FIXME: If saturation occurs here, we need to freeze adaptation for M frames (not just one) */
761761+ if (tmp32 > 32767)
762762+ {
763763+ tmp32 = 32767;
764764+ st->saturated = M+1;
765765+ }
766766+ if (tmp32 < -32767)
767767+ {
768768+ tmp32 = -32767;
769769+ st->saturated = M+1;
770770+ }
771771+#endif
772772+ st->x[speak*N+i+st->frame_size] = EXTRACT16(tmp32);
773773+ st->memX[speak] = far_end[i*K+speak];
774774+ }
775775+ }
776776+777777+ for (speak = 0; speak < K; speak++)
778778+ {
779779+ /* Shift memory: this could be optimized eventually*/
780780+ for (j=M-1;j>=0;j--)
705781 {
706706- tmp32 = -32767;
707707- if (st->saturated == 0)
708708- st->saturated = 1;
782782+ for (i=0;i<N;i++)
783783+ st->X[(j+1)*N*K+speak*N+i] = st->X[j*N*K+speak*N+i];
709784 }
710710-#endif
711711- st->memD = st->input[i];
712712- st->input[i] = tmp32;
785785+ /* Convert x (echo input) to frequency domain */
786786+ spx_fft(st->fft_table, st->x+speak*N, &st->X[speak*N]);
713787 }
714788715715- /* Shift memory: this could be optimized eventually*/
716716- for (j=M-1;j>=0;j--)
789789+ Sxx = 0;
790790+ for (speak = 0; speak < K; speak++)
717791 {
718718- for (i=0;i<N;i++)
719719- st->X[(j+1)*N+i] = st->X[j*N+i];
792792+ Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size);
793793+ power_spectrum_accum(st->X+speak*N, st->Xf, N);
720794 }
721795722722- /* Convert x (far end) to frequency domain */
723723- spx_fft(st->fft_table, st->x, &st->X[0]);
724724- for (i=0;i<N;i++)
725725- st->last_y[i] = st->x[i];
726726- Sxx = mdf_inner_prod(st->x+st->frame_size, st->x+st->frame_size, st->frame_size);
727727- for (i=0;i<st->frame_size;i++)
728728- st->x[i] = st->x[i+st->frame_size];
729729- /* From here on, the top part of x is used as scratch space */
730730-796796+ Sff = 0;
797797+ for (chan = 0; chan < C; chan++)
798798+ {
731799#ifdef TWO_PATH
732732- /* Compute foreground filter */
733733- spectral_mul_accum16(st->X, st->foreground, st->Y, N, M);
734734- spx_ifft(st->fft_table, st->Y, st->e);
735735- for (i=0;i<st->frame_size;i++)
736736- st->e[i] = SUB16(st->input[i], st->e[i+st->frame_size]);
737737- Sff = mdf_inner_prod(st->e, st->e, st->frame_size);
800800+ /* Compute foreground filter */
801801+ spectral_mul_accum16(st->X, st->foreground+chan*N*K*M, st->Y+chan*N, N, M*K);
802802+ spx_ifft(st->fft_table, st->Y+chan*N, st->e+chan*N);
803803+ for (i=0;i<st->frame_size;i++)
804804+ st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->e[chan*N+i+st->frame_size]);
805805+ Sff += mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size);
738806#endif
739739-807807+ }
808808+740809 /* Adjust proportional adaption rate */
741741- mdf_adjust_prop (st->W, N, M, st->prop);
810810+ /* FIXME: Adjust that for C, K*/
811811+ if (st->adapted)
812812+ mdf_adjust_prop (st->W, N, M, C*K, st->prop);
742813 /* Compute weight gradient */
743814 if (st->saturated == 0)
744815 {
745745- for (j=M-1;j>=0;j--)
816816+ for (chan = 0; chan < C; chan++)
746817 {
747747- weighted_spectral_mul_conj(st->power_1, FLOAT_SHL(PSEUDOFLOAT(st->prop[j]),-15), &st->X[(j+1)*N], st->E, st->PHI, N);
748748- for (i=0;i<N;i++)
749749- st->W[j*N+i] = ADD32(st->W[j*N+i], st->PHI[i]);
750750-818818+ for (speak = 0; speak < K; speak++)
819819+ {
820820+ for (j=M-1;j>=0;j--)
821821+ {
822822+ weighted_spectral_mul_conj(st->power_1, FLOAT_SHL(PSEUDOFLOAT(st->prop[j]),-15), &st->X[(j+1)*N*K+speak*N], st->E+chan*N, st->PHI, N);
823823+ for (i=0;i<N;i++)
824824+ st->W[chan*N*K*M + j*N*K + speak*N + i] += st->PHI[i];
825825+ }
826826+ }
751827 }
752828 } else {
753829 st->saturated--;
754830 }
755755-831831+832832+ /* FIXME: MC conversion required */
756833 /* Update weight to prevent circular convolution (MDF / AUMDF) */
757757- for (j=0;j<M;j++)
834834+ for (chan = 0; chan < C; chan++)
758835 {
759759- /* This is a variant of the Alternatively Updated MDF (AUMDF) */
760760- /* Remove the "if" to make this an MDF filter */
761761- if (j==0 || st->cancel_count%(M-1) == j-1)
836836+ for (speak = 0; speak < K; speak++)
762837 {
763763-#ifdef FIXED_POINT
764764- for (i=0;i<N;i++)
765765- st->wtmp2[i] = EXTRACT16(PSHR32(st->W[j*N+i],NORMALIZE_SCALEDOWN+16));
766766- spx_ifft(st->fft_table, st->wtmp2, st->wtmp);
767767- for (i=0;i<st->frame_size;i++)
838838+ for (j=0;j<M;j++)
768839 {
769769- st->wtmp[i]=0;
770770- }
771771- for (i=st->frame_size;i<N;i++)
772772- {
773773- st->wtmp[i]=SHL16(st->wtmp[i],NORMALIZE_SCALEUP);
774774- }
775775- spx_fft(st->fft_table, st->wtmp, st->wtmp2);
776776- /* The "-1" in the shift is a sort of kludge that trades less efficient update speed for decrease noise */
777777- for (i=0;i<N;i++)
778778- st->W[j*N+i] -= SHL32(EXTEND32(st->wtmp2[i]),16+NORMALIZE_SCALEDOWN-NORMALIZE_SCALEUP-1);
840840+ /* This is a variant of the Alternatively Updated MDF (AUMDF) */
841841+ /* Remove the "if" to make this an MDF filter */
842842+ if (j==0 || st->cancel_count%(M-1) == j-1)
843843+ {
844844+#ifdef FIXED_POINT
845845+ for (i=0;i<N;i++)
846846+ st->wtmp2[i] = EXTRACT16(PSHR32(st->W[chan*N*K*M + j*N*K + speak*N + i],NORMALIZE_SCALEDOWN+16));
847847+ spx_ifft(st->fft_table, st->wtmp2, st->wtmp);
848848+ for (i=0;i<st->frame_size;i++)
849849+ {
850850+ st->wtmp[i]=0;
851851+ }
852852+ for (i=st->frame_size;i<N;i++)
853853+ {
854854+ st->wtmp[i]=SHL16(st->wtmp[i],NORMALIZE_SCALEUP);
855855+ }
856856+ spx_fft(st->fft_table, st->wtmp, st->wtmp2);
857857+ /* The "-1" in the shift is a sort of kludge that trades less efficient update speed for decrease noise */
858858+ for (i=0;i<N;i++)
859859+ st->W[chan*N*K*M + j*N*K + speak*N + i] -= SHL32(EXTEND32(st->wtmp2[i]),16+NORMALIZE_SCALEDOWN-NORMALIZE_SCALEUP-1);
779860#else
780780- spx_ifft(st->fft_table, &st->W[j*N], st->wtmp);
781781- for (i=st->frame_size;i<N;i++)
782782- {
783783- st->wtmp[i]=0;
784784- }
785785- spx_fft(st->fft_table, st->wtmp, &st->W[j*N]);
861861+ spx_ifft(st->fft_table, &st->W[chan*N*K*M + j*N*K + speak*N], st->wtmp);
862862+ for (i=st->frame_size;i<N;i++)
863863+ {
864864+ st->wtmp[i]=0;
865865+ }
866866+ spx_fft(st->fft_table, st->wtmp, &st->W[chan*N*K*M + j*N*K + speak*N]);
786867#endif
868868+ }
869869+ }
787870 }
788871 }
789872790790- /* Compute filter response Y */
791791- spectral_mul_accum(st->X, st->W, st->Y, N, M);
792792- spx_ifft(st->fft_table, st->Y, st->y);
873873+ /* So we can use power_spectrum_accum */
874874+ for (i=0;i<=st->frame_size;i++)
875875+ st->Rf[i] = st->Yf[i] = st->Xf[i] = 0;
793876877877+ Dbf = 0;
878878+ See = 0;
794879#ifdef TWO_PATH
795880 /* Difference in response, this is used to estimate the variance of our residual power estimate */
796796- for (i=0;i<st->frame_size;i++)
797797- st->e[i] = SUB16(st->e[i+st->frame_size], st->y[i+st->frame_size]);
798798- Dbf = 10+mdf_inner_prod(st->e, st->e, st->frame_size);
881881+ for (chan = 0; chan < C; chan++)
882882+ {
883883+ spectral_mul_accum(st->X, st->W+chan*N*K*M, st->Y+chan*N, N, M*K);
884884+ spx_ifft(st->fft_table, st->Y+chan*N, st->y+chan*N);
885885+ for (i=0;i<st->frame_size;i++)
886886+ st->e[chan*N+i] = SUB16(st->e[chan*N+i+st->frame_size], st->y[chan*N+i+st->frame_size]);
887887+ Dbf += 10+mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size);
888888+ for (i=0;i<st->frame_size;i++)
889889+ st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->y[chan*N+i+st->frame_size]);
890890+ See += mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size);
891891+ }
799892#endif
800893801801- for (i=0;i<st->frame_size;i++)
802802- st->e[i] = SUB16(st->input[i], st->y[i+st->frame_size]);
803803- See = mdf_inner_prod(st->e, st->e, st->frame_size);
804894#ifndef TWO_PATH
805895 Sff = See;
806896#endif
807897808898#ifdef TWO_PATH
809899 /* Logic for updating the foreground filter */
810810-900900+811901 /* For two time windows, compute the mean of the energy difference, as well as the variance */
812902 st->Davg1 = ADD32(MULT16_32_Q15(QCONST16(.6f,15),st->Davg1), MULT16_32_Q15(QCONST16(.4f,15),SUB32(Sff,See)));
813903 st->Davg2 = ADD32(MULT16_32_Q15(QCONST16(.85f,15),st->Davg2), MULT16_32_Q15(QCONST16(.15f,15),SUB32(Sff,See)));
814904 st->Dvar1 = FLOAT_ADD(FLOAT_MULT(VAR1_SMOOTH, st->Dvar1), FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.4f,15),Sff), MULT16_32_Q15(QCONST16(.4f,15),Dbf)));
815905 st->Dvar2 = FLOAT_ADD(FLOAT_MULT(VAR2_SMOOTH, st->Dvar2), FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.15f,15),Sff), MULT16_32_Q15(QCONST16(.15f,15),Dbf)));
816816-906906+817907 /* Equivalent float code:
818908 st->Davg1 = .6*st->Davg1 + .4*(Sff-See);
819909 st->Davg2 = .85*st->Davg2 + .15*(Sff-See);
820910 st->Dvar1 = .36*st->Dvar1 + .16*Sff*Dbf;
821911 st->Dvar2 = .7225*st->Dvar2 + .0225*Sff*Dbf;
822912 */
823823-913913+824914 update_foreground = 0;
825915 /* Check if we have a statistically significant reduction in the residual echo */
826916 /* Note that this is *not* Gaussian, so we need to be careful about the longer tail */
···830920 update_foreground = 1;
831921 else if (FLOAT_GT(FLOAT_MUL32U(st->Davg2, ABS32(st->Davg2)), FLOAT_MULT(VAR2_UPDATE,(st->Dvar2))))
832922 update_foreground = 1;
833833-923923+834924 /* Do we update? */
835925 if (update_foreground)
836926 {
837927 st->Davg1 = st->Davg2 = 0;
838928 st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
839929 /* Copy background filter to foreground filter */
840840- for (i=0;i<N*M;i++)
930930+ for (i=0;i<N*M*C*K;i++)
841931 st->foreground[i] = EXTRACT16(PSHR32(st->W[i],16));
842932 /* Apply a smooth transition so as to not introduce blocking artifacts */
843843- for (i=0;i<st->frame_size;i++)
844844- 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]);
933933+ for (chan = 0; chan < C; chan++)
934934+ for (i=0;i<st->frame_size;i++)
935935+ st->e[chan*N+i+st->frame_size] = MULT16_16_Q15(st->window[i+st->frame_size],st->e[chan*N+i+st->frame_size]) + MULT16_16_Q15(st->window[i],st->y[chan*N+i+st->frame_size]);
845936 } else {
846937 int reset_background=0;
847938 /* Otherwise, check if the background filter is significantly worse */
···854945 if (reset_background)
855946 {
856947 /* Copy foreground filter to background filter */
857857- for (i=0;i<N*M;i++)
948948+ for (i=0;i<N*M*C*K;i++)
858949 st->W[i] = SHL32(EXTEND32(st->foreground[i]),16);
859950 /* We also need to copy the output so as to get correct adaptation */
860860- for (i=0;i<st->frame_size;i++)
861861- st->y[i+st->frame_size] = st->e[i+st->frame_size];
862862- for (i=0;i<st->frame_size;i++)
863863- st->e[i] = SUB16(st->input[i], st->y[i+st->frame_size]);
951951+ for (chan = 0; chan < C; chan++)
952952+ {
953953+ for (i=0;i<st->frame_size;i++)
954954+ st->y[chan*N+i+st->frame_size] = st->e[chan*N+i+st->frame_size];
955955+ for (i=0;i<st->frame_size;i++)
956956+ st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->y[chan*N+i+st->frame_size]);
957957+ }
864958 See = Sff;
865959 st->Davg1 = st->Davg2 = 0;
866960 st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
···868962 }
869963#endif
870964871871- /* Compute error signal (for the output with de-emphasis) */
872872- for (i=0;i<st->frame_size;i++)
965965+ Sey = Syy = Sdd = 0;
966966+ for (chan = 0; chan < C; chan++)
873967 {
874874- spx_word32_t tmp_out;
968968+ /* Compute error signal (for the output with de-emphasis) */
969969+ for (i=0;i<st->frame_size;i++)
970970+ {
971971+ spx_word32_t tmp_out;
875972#ifdef TWO_PATH
876876- tmp_out = SUB32(EXTEND32(st->input[i]), EXTEND32(st->e[i+st->frame_size]));
973973+ tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->e[chan*N+i+st->frame_size]));
877974#else
878878- tmp_out = SUB32(EXTEND32(st->input[i]), EXTEND32(st->y[i+st->frame_size]));
975975+ tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->y[chan*N+i+st->frame_size]));
879976#endif
880880- /* Saturation */
881881- if (tmp_out>32767)
882882- tmp_out = 32767;
883883- else if (tmp_out<-32768)
884884- tmp_out = -32768;
885885- tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(st->preemph, st->memE)));
977977+ tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(st->preemph, st->memE[chan])));
886978 /* This is an arbitrary test for saturation in the microphone signal */
887887- if (in[i] <= -32000 || in[i] >= 32000)
888888- {
889889- tmp_out = 0;
979979+ if (in[i*C+chan] <= -32000 || in[i*C+chan] >= 32000)
980980+ {
890981 if (st->saturated == 0)
891982 st->saturated = 1;
983983+ }
984984+ out[i*C+chan] = WORD2INT(tmp_out);
985985+ st->memE[chan] = tmp_out;
892986 }
893893- out[i] = (spx_int16_t)tmp_out;
894894- st->memE = tmp_out;
895895- }
896896-987987+897988#ifdef DUMP_ECHO_CANCEL_DATA
898898- dump_audio(in, far_end, out, st->frame_size);
989989+ dump_audio(in, far_end, out, st->frame_size);
899990#endif
900900-901901- /* Compute error signal (filter update version) */
902902- for (i=0;i<st->frame_size;i++)
903903- {
904904- st->e[i+st->frame_size] = st->e[i];
905905- st->e[i] = 0;
991991+992992+ /* Compute error signal (filter update version) */
993993+ for (i=0;i<st->frame_size;i++)
994994+ {
995995+ st->e[chan*N+i+st->frame_size] = st->e[chan*N+i];
996996+ st->e[chan*N+i] = 0;
997997+ }
998998+999999+ /* Compute a bunch of correlations */
10001000+ /* FIXME: bad merge */
10011001+ Sey += mdf_inner_prod(st->e+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size);
10021002+ Syy += mdf_inner_prod(st->y+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size);
10031003+ Sdd += mdf_inner_prod(st->input+chan*st->frame_size, st->input+chan*st->frame_size, st->frame_size);
10041004+10051005+ /* Convert error to frequency domain */
10061006+ spx_fft(st->fft_table, st->e+chan*N, st->E+chan*N);
10071007+ for (i=0;i<st->frame_size;i++)
10081008+ st->y[i+chan*N] = 0;
10091009+ spx_fft(st->fft_table, st->y+chan*N, st->Y+chan*N);
10101010+10111011+ /* Compute power spectrum of echo (X), error (E) and filter response (Y) */
10121012+ power_spectrum_accum(st->E+chan*N, st->Rf, N);
10131013+ power_spectrum_accum(st->Y+chan*N, st->Yf, N);
10141014+9061015 }
9071016908908- /* Compute a bunch of correlations */
909909- Sey = mdf_inner_prod(st->e+st->frame_size, st->y+st->frame_size, st->frame_size);
910910- Syy = mdf_inner_prod(st->y+st->frame_size, st->y+st->frame_size, st->frame_size);
911911- Sdd = mdf_inner_prod(st->input, st->input, st->frame_size);
912912-9131017 /*printf ("%f %f %f %f\n", Sff, See, Syy, Sdd, st->update_cond);*/
914914-10181018+9151019 /* Do some sanity check */
9161020 if (!(Syy>=0 && Sxx>=0 && See >= 0)
9171021#ifndef FIXED_POINT
···9211025 {
9221026 /* Things have gone really bad */
9231027 st->screwed_up += 50;
924924- for (i=0;i<st->frame_size;i++)
10281028+ for (i=0;i<st->frame_size*C;i++)
9251029 out[i] = 0;
9261030 } else if (SHR32(Sff, 2) > ADD32(Sdd, SHR32(MULT16_16(N, 10000),6)))
9271031 {
···9411045 /* Add a small noise floor to make sure not to have problems when dividing */
9421046 See = MAX32(See, SHR32(MULT16_16(N, 100),6));
9431047944944- /* Convert error to frequency domain */
945945- spx_fft(st->fft_table, st->e, st->E);
946946- for (i=0;i<st->frame_size;i++)
947947- st->y[i] = 0;
948948- spx_fft(st->fft_table, st->y, st->Y);
10481048+ for (speak = 0; speak < K; speak++)
10491049+ {
10501050+ Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size);
10511051+ power_spectrum_accum(st->X+speak*N, st->Xf, N);
10521052+ }
9491053950950- /* Compute power spectrum of far end (X), error (E) and filter response (Y) */
951951- power_spectrum(st->E, st->Rf, N);
952952- power_spectrum(st->Y, st->Yf, N);
953953- power_spectrum(st->X, st->Xf, N);
954954-10541054+9551055 /* Smooth far end energy estimate over time */
9561056 for (j=0;j<=st->frame_size;j++)
9571057 st->power[j] = MULT16_32_Q15(ss_1,st->power[j]) + 1 + MULT16_32_Q15(ss,st->Xf[j]);
958958-959959- /* Enable this to compute the power based only on the tail (would need to compute more
960960- efficiently to make this really useful */
961961- if (0)
962962- {
963963- float scale2 = .5f/M;
964964- for (j=0;j<=st->frame_size;j++)
965965- st->power[j] = 100;
966966- for (i=0;i<M;i++)
967967- {
968968- power_spectrum(&st->X[i*N], st->Xf, N);
969969- for (j=0;j<=st->frame_size;j++)
970970- st->power[j] += scale2*st->Xf[j];
971971- }
972972- }
97310589741059 /* Compute filtered spectra and (cross-)correlations */
9751060 for (j=st->frame_size;j>=0;j--)
···9871072 st->Yh[j] = (1-st->spec_average)*st->Yh[j] + st->spec_average*st->Yf[j];
9881073#endif
9891074 }
990990-10751075+9911076 Pyy = FLOAT_SQRT(Pyy);
9921077 Pey = FLOAT_DIVU(Pey,Pyy);
9931078···10151100 else
10161101 st->leak_estimate = SHL16(st->leak_estimate,1);
10171102 /*printf ("%f\n", st->leak_estimate);*/
10181018-11031103+10191104 /* Compute Residual to Error Ratio */
10201105#ifdef FIXED_POINT
10211106 tmp32 = MULT16_32_Q15(st->leak_estimate,Syy);
···10711156 /* Temporary adaption rate if filter is not yet adapted enough */
10721157 spx_word16_t adapt_rate=0;
1073115810741074- if (Sxx > SHR32(MULT16_16(N, 1000),6))
11591159+ if (Sxx > SHR32(MULT16_16(N, 1000),6))
10751160 {
10761161 tmp32 = MULT16_32_Q15(QCONST16(.25f, 15), Sxx);
10771162#ifdef FIXED_POINT
···10911176 st->sum_adapt = ADD32(st->sum_adapt,adapt_rate);
10921177 }
1093117810941094- /* Save residual echo so it can be used by the nonlinear processor */
11791179+ /* FIXME: MC conversion required */
11801180+ for (i=0;i<st->frame_size;i++)
11811181+ st->last_y[i] = st->last_y[st->frame_size+i];
10951182 if (st->adapted)
10961183 {
10971184 /* If the filter is adapted, take the filtered echo */
10981185 for (i=0;i<st->frame_size;i++)
10991099- st->last_y[i] = st->last_y[st->frame_size+i];
11001100- for (i=0;i<st->frame_size;i++)
11011186 st->last_y[st->frame_size+i] = in[i]-out[i];
11021187 } else {
11031188 /* If filter isn't adapted yet, all we can do is take the far end signal directly */
···11131198 int i;
11141199 spx_word16_t leak2;
11151200 int N;
11161116-12011201+11171202 N = st->window_size;
1118120311191204 /* Apply hanning window (should pre-compute it)*/
11201205 for (i=0;i<N;i++)
11211206 st->y[i] = MULT16_16_Q15(st->window[i],st->last_y[i]);
11221122-12071207+11231208 /* Compute power spectrum of the echo */
11241209 spx_fft(st->fft_table, st->y, st->Y);
11251210 power_spectrum(st->Y, residual_echo, N);
11261126-12111211+11271212#ifdef FIXED_POINT
11281213 if (st->leak_estimate > 16383)
11291214 leak2 = 32767;
···11381223 /* Estimate residual echo */
11391224 for (i=0;i<=st->frame_size;i++)
11401225 residual_echo[i] = (spx_int32_t)MULT16_32_Q15(leak2,residual_echo[i]);
11411141-12261226+11421227}
1143122811441144-int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr)
12291229+EXPORT int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr)
11451230{
11461231 switch(request)
11471232 {
11481148-12331233+11491234 case SPEEX_ECHO_GET_FRAME_SIZE:
11501235 (*(int*)ptr) = st->frame_size;
11511236 break;
···11681253 break;
11691254 case SPEEX_ECHO_GET_SAMPLING_RATE:
11701255 (*(int*)ptr) = st->sampling_rate;
12561256+ break;
12571257+ case SPEEX_ECHO_GET_IMPULSE_RESPONSE_SIZE:
12581258+ /*FIXME: Implement this for multiple channels */
12591259+ *((spx_int32_t *)ptr) = st->M * st->frame_size;
12601260+ break;
12611261+ case SPEEX_ECHO_GET_IMPULSE_RESPONSE:
12621262+ {
12631263+ int M = st->M, N = st->window_size, n = st->frame_size, i, j;
12641264+ spx_int32_t *filt = (spx_int32_t *) ptr;
12651265+ for(j=0;j<M;j++)
12661266+ {
12671267+ /*FIXME: Implement this for multiple channels */
12681268+#ifdef FIXED_POINT
12691269+ for (i=0;i<N;i++)
12701270+ st->wtmp2[i] = EXTRACT16(PSHR32(st->W[j*N+i],16+NORMALIZE_SCALEDOWN));
12711271+ spx_ifft(st->fft_table, st->wtmp2, st->wtmp);
12721272+#else
12731273+ spx_ifft(st->fft_table, &st->W[j*N], st->wtmp);
12741274+#endif
12751275+ for(i=0;i<n;i++)
12761276+ filt[j*n+i] = PSHR32(MULT16_16(32767,st->wtmp[i]), WEIGHT_SHIFT-NORMALIZE_SCALEDOWN);
12771277+ }
12781278+ }
11711279 break;
11721280 default:
11731281 speex_warning_int("Unknown speex_echo_ctl request: ", request);
···11-/* Copyright (C) 2007 Jean-Marc Valin
22-11+/* Copyright (C) 2007-2008 Jean-Marc Valin
22+ Copyright (C) 2008 Thorvald Natvig
33+34 File: resample.c
45 Arbitrary resampling code
56···3738 - Low memory requirement
3839 - Good *perceptual* quality (and not best SNR)
39404040- Warning: This resampler is relatively new. Although I think I got rid of
4141+ Warning: This resampler is relatively new. Although I think I got rid of
4142 all the major bugs and I don't expect the API to change anymore, there
4243 may be something I've missed. So use with caution.
43444445 This algorithm is based on this original resampling algorithm:
4546 Smith, Julius O. Digital Audio Resampling Home Page
4646- Center for Computer Research in Music and Acoustics (CCRMA),
4747+ Center for Computer Research in Music and Acoustics (CCRMA),
4748 Stanford University, 2007.
4849 Web published at http://www-ccrma.stanford.edu/~jos/resample/.
49505050- There is one main difference, though. This resampler uses cubic
5151+ There is one main difference, though. This resampler uses cubic
5152 interpolation instead of linear interpolation in the above paper. This
5253 makes the table much smaller and makes it possible to compute that table
5353- on a per-stream basis. In turn, being able to tweak the table for each
5454- stream makes it possible to both reduce complexity on simple ratios
5555- (e.g. 2/3), and get rid of the rounding operations in the inner loop.
5454+ on a per-stream basis. In turn, being able to tweak the table for each
5555+ stream makes it possible to both reduce complexity on simple ratios
5656+ (e.g. 2/3), and get rid of the rounding operations in the inner loop.
5657 The latter both reduces CPU time and makes the algorithm more SIMD-friendly.
5758*/
58595960#ifdef HAVE_CONFIG_H
6060-#include "config-speex.h"
6161+#include "config.h"
6162#endif
62636364#ifdef OUTSIDE_SPEEX
···6869#include "speex_resampler.h"
6970#include "arch.h"
7071#else /* OUTSIDE_SPEEX */
7171-7272+7273#include "speex/speex_resampler.h"
7374#include "arch.h"
7475#include "os_support.h"
7576#endif /* OUTSIDE_SPEEX */
76777878+#include "stack_alloc.h"
7779#include <math.h>
78807981#ifndef M_PI
···8183#endif
82848385#ifdef FIXED_POINT
8484-#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x)))
8686+#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x)))
8587#else
8686-#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x))))
8888+#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x))))
8789#endif
8888-8989-/*#define float double*/
9090-#define FILTER_SIZE 64
9191-#define OVERSAMPLE 8
92909391#define IMAX(a,b) ((a) > (b) ? (a) : (b))
9492#define IMIN(a,b) ((a) < (b) ? (a) : (b))
···9795#define NULL 0
9896#endif
99979898+#ifdef _USE_SSE
9999+#include "resample_sse.h"
100100+#endif
101101+102102+/* Numer of elements to allocate on the stack */
103103+#ifdef VAR_ARRAYS
104104+#define FIXED_STACK_ALLOC 8192
105105+#else
106106+#define FIXED_STACK_ALLOC 1024
107107+#endif
108108+100109typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *);
101110102111struct SpeexResamplerState_ {
···104113 spx_uint32_t out_rate;
105114 spx_uint32_t num_rate;
106115 spx_uint32_t den_rate;
107107-116116+108117 int quality;
109118 spx_uint32_t nb_channels;
110119 spx_uint32_t filt_len;
111120 spx_uint32_t mem_alloc_size;
121121+ spx_uint32_t buffer_size;
112122 int int_advance;
113123 int frac_advance;
114124 float cutoff;
115125 spx_uint32_t oversample;
116126 int initialised;
117127 int started;
118118-128128+119129 /* These are per-channel */
120130 spx_int32_t *last_sample;
121131 spx_uint32_t *samp_frac_num;
122132 spx_uint32_t *magic_samples;
123123-133133+124134 spx_word16_t *mem;
125135 spx_word16_t *sinc_table;
126136 spx_uint32_t sinc_table_length;
127137 resampler_basic_func resampler_ptr;
128128-138138+129139 int in_stride;
130140 int out_stride;
131141} ;
···167177 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758,
168178 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490,
169179 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000};
170170-180180+171181static double kaiser6_table[36] = {
172182 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003,
173183 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565,
···180190 double *table;
181191 int oversample;
182192};
183183-193193+184194static struct FuncDef _KAISER12 = {kaiser12_table, 64};
185195#define KAISER12 (&_KAISER12)
186196/*static struct FuncDef _KAISER12 = {kaiser12_table, 32};
···202212203213204214/* This table maps conversion quality to internal parameters. There are two
205205- reasons that explain why the up-sampling bandwidth is larger than the
215215+ reasons that explain why the up-sampling bandwidth is larger than the
206216 down-sampling bandwidth:
207217 1) When up-sampling, we can assume that the spectrum is already attenuated
208218 close to the Nyquist rate (from an A/D or a previous resampling filter)
···228238{
229239 float y, frac;
230240 double interp[4];
231231- int ind;
241241+ int ind;
232242 y = x*func->oversample;
233243 ind = (int)floor(y);
234244 frac = (y-ind);
···239249 interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac);
240250 /* Just to make sure we don't have rounding problems */
241251 interp[1] = 1.f-interp[3]-interp[2]-interp[0];
242242-252252+243253 /*sum = frac*accum[1] + (1-frac)*accum[2];*/
244254 return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3];
245255}
···317327318328static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
319329{
320320- int N = st->filt_len;
330330+ const int N = st->filt_len;
321331 int out_sample = 0;
322322- spx_word16_t *mem;
323332 int last_sample = st->last_sample[channel_index];
324333 spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
325325- mem = st->mem + channel_index * st->mem_alloc_size;
334334+ const spx_word16_t *sinc_table = st->sinc_table;
335335+ const int out_stride = st->out_stride;
336336+ const int int_advance = st->int_advance;
337337+ const int frac_advance = st->frac_advance;
338338+ const spx_uint32_t den_rate = st->den_rate;
339339+ spx_word32_t sum;
340340+ int j;
341341+326342 while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
327343 {
328328- int j;
329329- spx_word32_t sum=0;
330330-331331- /* We already have all the filter coefficients pre-computed in the table */
332332- const spx_word16_t *ptr;
333333- /* Do the memory part */
334334- for (j=0;last_sample-N+1+j < 0;j++)
335335- {
336336- sum += MULT16_16(mem[last_sample+j],st->sinc_table[samp_frac_num*st->filt_len+j]);
337337- }
338338-339339- /* Do the new part */
340340- if (in != NULL)
341341- {
342342- ptr = in+st->in_stride*(last_sample-N+1+j);
343343- for (;j<N;j++)
344344- {
345345- sum += MULT16_16(*ptr,st->sinc_table[samp_frac_num*st->filt_len+j]);
346346- ptr += st->in_stride;
347347- }
344344+ const spx_word16_t *sinc = & sinc_table[samp_frac_num*N];
345345+ const spx_word16_t *iptr = & in[last_sample];
346346+347347+#ifndef OVERRIDE_INNER_PRODUCT_SINGLE
348348+ float accum[4] = {0,0,0,0};
349349+350350+ for(j=0;j<N;j+=4) {
351351+ accum[0] += sinc[j]*iptr[j];
352352+ accum[1] += sinc[j+1]*iptr[j+1];
353353+ accum[2] += sinc[j+2]*iptr[j+2];
354354+ accum[3] += sinc[j+3]*iptr[j+3];
348355 }
349349-350350- *out = PSHR32(sum,15);
351351- out += st->out_stride;
352352- out_sample++;
353353- last_sample += st->int_advance;
354354- samp_frac_num += st->frac_advance;
355355- if (samp_frac_num >= st->den_rate)
356356+ sum = accum[0] + accum[1] + accum[2] + accum[3];
357357+#else
358358+ sum = inner_product_single(sinc, iptr, N);
359359+#endif
360360+361361+ out[out_stride * out_sample++] = PSHR32(sum, 15);
362362+ last_sample += int_advance;
363363+ samp_frac_num += frac_advance;
364364+ if (samp_frac_num >= den_rate)
356365 {
357357- samp_frac_num -= st->den_rate;
366366+ samp_frac_num -= den_rate;
358367 last_sample++;
359368 }
360369 }
370370+361371 st->last_sample[channel_index] = last_sample;
362372 st->samp_frac_num[channel_index] = samp_frac_num;
363373 return out_sample;
···368378/* This is the same as the previous function, except with a double-precision accumulator */
369379static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
370380{
371371- int N = st->filt_len;
381381+ const int N = st->filt_len;
372382 int out_sample = 0;
373373- spx_word16_t *mem;
374383 int last_sample = st->last_sample[channel_index];
375384 spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
376376- mem = st->mem + channel_index * st->mem_alloc_size;
385385+ const spx_word16_t *sinc_table = st->sinc_table;
386386+ const int out_stride = st->out_stride;
387387+ const int int_advance = st->int_advance;
388388+ const int frac_advance = st->frac_advance;
389389+ const spx_uint32_t den_rate = st->den_rate;
390390+ double sum;
391391+ int j;
392392+377393 while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
378394 {
379379- int j;
380380- double sum=0;
381381-382382- /* We already have all the filter coefficients pre-computed in the table */
383383- const spx_word16_t *ptr;
384384- /* Do the memory part */
385385- for (j=0;last_sample-N+1+j < 0;j++)
386386- {
387387- sum += MULT16_16(mem[last_sample+j],(double)st->sinc_table[samp_frac_num*st->filt_len+j]);
388388- }
389389-390390- /* Do the new part */
391391- if (in != NULL)
392392- {
393393- ptr = in+st->in_stride*(last_sample-N+1+j);
394394- for (;j<N;j++)
395395- {
396396- sum += MULT16_16(*ptr,(double)st->sinc_table[samp_frac_num*st->filt_len+j]);
397397- ptr += st->in_stride;
398398- }
395395+ const spx_word16_t *sinc = & sinc_table[samp_frac_num*N];
396396+ const spx_word16_t *iptr = & in[last_sample];
397397+398398+#ifndef OVERRIDE_INNER_PRODUCT_DOUBLE
399399+ double accum[4] = {0,0,0,0};
400400+401401+ for(j=0;j<N;j+=4) {
402402+ accum[0] += sinc[j]*iptr[j];
403403+ accum[1] += sinc[j+1]*iptr[j+1];
404404+ accum[2] += sinc[j+2]*iptr[j+2];
405405+ accum[3] += sinc[j+3]*iptr[j+3];
399406 }
400400-401401- *out = sum;
402402- out += st->out_stride;
403403- out_sample++;
404404- last_sample += st->int_advance;
405405- samp_frac_num += st->frac_advance;
406406- if (samp_frac_num >= st->den_rate)
407407+ sum = accum[0] + accum[1] + accum[2] + accum[3];
408408+#else
409409+ sum = inner_product_double(sinc, iptr, N);
410410+#endif
411411+412412+ out[out_stride * out_sample++] = PSHR32(sum, 15);
413413+ last_sample += int_advance;
414414+ samp_frac_num += frac_advance;
415415+ if (samp_frac_num >= den_rate)
407416 {
408408- samp_frac_num -= st->den_rate;
417417+ samp_frac_num -= den_rate;
409418 last_sample++;
410419 }
411420 }
421421+412422 st->last_sample[channel_index] = last_sample;
413423 st->samp_frac_num[channel_index] = samp_frac_num;
414424 return out_sample;
···417427418428static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
419429{
420420- int N = st->filt_len;
430430+ const int N = st->filt_len;
421431 int out_sample = 0;
422422- spx_word16_t *mem;
423432 int last_sample = st->last_sample[channel_index];
424433 spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
425425- mem = st->mem + channel_index * st->mem_alloc_size;
434434+ const int out_stride = st->out_stride;
435435+ const int int_advance = st->int_advance;
436436+ const int frac_advance = st->frac_advance;
437437+ const spx_uint32_t den_rate = st->den_rate;
438438+ int j;
439439+ spx_word32_t sum;
440440+426441 while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
427442 {
428428- int j;
429429- spx_word32_t sum=0;
430430-431431- /* We need to interpolate the sinc filter */
432432- spx_word32_t accum[4] = {0.f,0.f, 0.f, 0.f};
433433- spx_word16_t interp[4];
434434- const spx_word16_t *ptr;
435435- int offset;
436436- spx_word16_t frac;
437437- offset = samp_frac_num*st->oversample/st->den_rate;
443443+ const spx_word16_t *iptr = & in[last_sample];
444444+445445+ const int offset = samp_frac_num*st->oversample/st->den_rate;
438446#ifdef FIXED_POINT
439439- frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate);
447447+ const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate);
440448#else
441441- frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate;
449449+ const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate;
442450#endif
443443- /* This code is written like this to make it easy to optimise with SIMD.
444444- For most DSPs, it would be best to split the loops in two because most DSPs
445445- have only two accumulators */
446446- for (j=0;last_sample-N+1+j < 0;j++)
447447- {
448448- spx_word16_t curr_mem = mem[last_sample+j];
449449- accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
450450- accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
451451- accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]);
452452- accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
453453- }
454454-455455- if (in != NULL)
456456- {
457457- ptr = in+st->in_stride*(last_sample-N+1+j);
458458- /* Do the new part */
459459- for (;j<N;j++)
460460- {
461461- spx_word16_t curr_in = *ptr;
462462- ptr += st->in_stride;
463463- accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
464464- accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
465465- accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
466466- accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
467467- }
451451+ spx_word16_t interp[4];
452452+453453+454454+#ifndef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE
455455+ spx_word32_t accum[4] = {0,0,0,0};
456456+457457+ for(j=0;j<N;j++) {
458458+ const spx_word16_t curr_in=iptr[j];
459459+ accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
460460+ accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
461461+ accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
462462+ accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
468463 }
464464+469465 cubic_coef(frac, interp);
470466 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]);
471471-472472- *out = PSHR32(sum,15);
473473- out += st->out_stride;
474474- out_sample++;
475475- last_sample += st->int_advance;
476476- samp_frac_num += st->frac_advance;
477477- if (samp_frac_num >= st->den_rate)
467467+#else
468468+ cubic_coef(frac, interp);
469469+ sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);
470470+#endif
471471+472472+ out[out_stride * out_sample++] = PSHR32(sum,15);
473473+ last_sample += int_advance;
474474+ samp_frac_num += frac_advance;
475475+ if (samp_frac_num >= den_rate)
478476 {
479479- samp_frac_num -= st->den_rate;
477477+ samp_frac_num -= den_rate;
480478 last_sample++;
481479 }
482480 }
481481+483482 st->last_sample[channel_index] = last_sample;
484483 st->samp_frac_num[channel_index] = samp_frac_num;
485484 return out_sample;
···490489/* This is the same as the previous function, except with a double-precision accumulator */
491490static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
492491{
493493- int N = st->filt_len;
492492+ const int N = st->filt_len;
494493 int out_sample = 0;
495495- spx_word16_t *mem;
496494 int last_sample = st->last_sample[channel_index];
497495 spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
498498- mem = st->mem + channel_index * st->mem_alloc_size;
496496+ const int out_stride = st->out_stride;
497497+ const int int_advance = st->int_advance;
498498+ const int frac_advance = st->frac_advance;
499499+ const spx_uint32_t den_rate = st->den_rate;
500500+ int j;
501501+ spx_word32_t sum;
502502+499503 while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
500504 {
501501- int j;
502502- spx_word32_t sum=0;
503503-504504- /* We need to interpolate the sinc filter */
505505- double accum[4] = {0.f,0.f, 0.f, 0.f};
506506- float interp[4];
507507- const spx_word16_t *ptr;
508508- float alpha = ((float)samp_frac_num)/st->den_rate;
509509- int offset = samp_frac_num*st->oversample/st->den_rate;
510510- float frac = alpha*st->oversample - offset;
511511- /* This code is written like this to make it easy to optimise with SIMD.
512512- For most DSPs, it would be best to split the loops in two because most DSPs
513513- have only two accumulators */
514514- for (j=0;last_sample-N+1+j < 0;j++)
515515- {
516516- double curr_mem = mem[last_sample+j];
517517- accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
518518- accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
519519- accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]);
520520- accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
521521- }
522522- if (in != NULL)
523523- {
524524- ptr = in+st->in_stride*(last_sample-N+1+j);
525525- /* Do the new part */
526526- for (;j<N;j++)
527527- {
528528- double curr_in = *ptr;
529529- ptr += st->in_stride;
530530- accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
531531- accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
532532- accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
533533- accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
534534- }
505505+ const spx_word16_t *iptr = & in[last_sample];
506506+507507+ const int offset = samp_frac_num*st->oversample/st->den_rate;
508508+#ifdef FIXED_POINT
509509+ const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate);
510510+#else
511511+ const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate;
512512+#endif
513513+ spx_word16_t interp[4];
514514+515515+516516+#ifndef OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE
517517+ double accum[4] = {0,0,0,0};
518518+519519+ for(j=0;j<N;j++) {
520520+ const double curr_in=iptr[j];
521521+ accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
522522+ accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
523523+ accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
524524+ accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
535525 }
526526+536527 cubic_coef(frac, interp);
537537- sum = interp[0]*accum[0] + interp[1]*accum[1] + interp[2]*accum[2] + interp[3]*accum[3];
538538-539539- *out = PSHR32(sum,15);
540540- out += st->out_stride;
541541- out_sample++;
542542- last_sample += st->int_advance;
543543- samp_frac_num += st->frac_advance;
544544- if (samp_frac_num >= st->den_rate)
528528+ 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]);
529529+#else
530530+ cubic_coef(frac, interp);
531531+ sum = interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);
532532+#endif
533533+534534+ out[out_stride * out_sample++] = PSHR32(sum,15);
535535+ last_sample += int_advance;
536536+ samp_frac_num += frac_advance;
537537+ if (samp_frac_num >= den_rate)
545538 {
546546- samp_frac_num -= st->den_rate;
539539+ samp_frac_num -= den_rate;
547540 last_sample++;
548541 }
549542 }
543543+550544 st->last_sample[channel_index] = last_sample;
551545 st->samp_frac_num[channel_index] = samp_frac_num;
552546 return out_sample;
···556550static void update_filter(SpeexResamplerState *st)
557551{
558552 spx_uint32_t old_length;
559559-553553+560554 old_length = st->filt_len;
561555 st->oversample = quality_map[st->quality].oversample;
562556 st->filt_len = quality_map[st->quality].base_length;
563563-557557+564558 if (st->num_rate > st->den_rate)
565559 {
566560 /* down-sampling */
···636630 st->int_advance = st->num_rate/st->den_rate;
637631 st->frac_advance = st->num_rate%st->den_rate;
638632639639-633633+640634 /* Here's the place where we update the filter memory to take into account
641635 the change in filter length. It's probably the messiest part of the code
642636 due to handling of lots of corner cases. */
643637 if (!st->mem)
644638 {
645639 spx_uint32_t i;
646646- st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t));
647647- for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
640640+ st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
641641+ st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
642642+ for (i=0;i<st->nb_channels*st->mem_alloc_size;i++)
648643 st->mem[i] = 0;
649649- st->mem_alloc_size = st->filt_len-1;
650644 /*speex_warning("init filter");*/
651645 } else if (!st->started)
652646 {
653647 spx_uint32_t i;
654654- st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t));
655655- for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
648648+ st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
649649+ st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
650650+ for (i=0;i<st->nb_channels*st->mem_alloc_size;i++)
656651 st->mem[i] = 0;
657657- st->mem_alloc_size = st->filt_len-1;
658652 /*speex_warning("reinit filter");*/
659653 } else if (st->filt_len > old_length)
660654 {
···662656 /* Increase the filter length */
663657 /*speex_warning("increase filter size");*/
664658 int old_alloc_size = st->mem_alloc_size;
665665- if (st->filt_len-1 > st->mem_alloc_size)
659659+ if ((st->filt_len-1 + st->buffer_size) > st->mem_alloc_size)
666660 {
667667- st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t));
668668- st->mem_alloc_size = st->filt_len-1;
661661+ st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
662662+ st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
669663 }
670664 for (i=st->nb_channels-1;i>=0;i--)
671665 {
···674668 /*if (st->magic_samples[i])*/
675669 {
676670 /* Try and remove the magic samples as if nothing had happened */
677677-671671+678672 /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */
679673 olen = old_length + 2*st->magic_samples[i];
680674 for (j=old_length-2+st->magic_samples[i];j>=0;j--)
···721715722716}
723717724724-SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)
718718+EXPORT SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)
725719{
726720 return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err);
727721}
728722729729-SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)
723723+EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)
730724{
731725 spx_uint32_t i;
732726 SpeexResamplerState *st;
···749743 st->filt_len = 0;
750744 st->mem = 0;
751745 st->resampler_ptr = 0;
752752-746746+753747 st->cutoff = 1.f;
754748 st->nb_channels = nb_channels;
755749 st->in_stride = 1;
756750 st->out_stride = 1;
757757-751751+752752+#ifdef FIXED_POINT
753753+ st->buffer_size = 160;
754754+#else
755755+ st->buffer_size = 160;
756756+#endif
757757+758758 /* Per channel data */
759759 st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int));
760760 st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int));
···769769 speex_resampler_set_quality(st, quality);
770770 speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate);
771771772772-772772+773773 update_filter(st);
774774-774774+775775 st->initialised = 1;
776776 if (err)
777777 *err = RESAMPLER_ERR_SUCCESS;
···779779 return st;
780780}
781781782782-void speex_resampler_destroy(SpeexResamplerState *st)
782782+EXPORT void speex_resampler_destroy(SpeexResamplerState *st)
783783{
784784 speex_free(st->mem);
785785 speex_free(st->sinc_table);
···789789 speex_free(st);
790790}
791791792792-793793-794794-static int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
792792+static int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
795793{
796794 int j=0;
797797- int N = st->filt_len;
795795+ const int N = st->filt_len;
798796 int out_sample = 0;
799799- spx_word16_t *mem;
800800- spx_uint32_t tmp_out_len = 0;
801801- mem = st->mem + channel_index * st->mem_alloc_size;
797797+ spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size;
798798+ spx_uint32_t ilen;
799799+802800 st->started = 1;
803803-804804- /* Handle the case where we have samples left from a reduction in filter length */
805805- if (st->magic_samples[channel_index])
806806- {
807807- int istride_save;
808808- spx_uint32_t tmp_in_len;
809809- spx_uint32_t tmp_magic;
810810-811811- istride_save = st->in_stride;
812812- tmp_in_len = st->magic_samples[channel_index];
813813- tmp_out_len = *out_len;
814814- /* magic_samples needs to be set to zero to avoid infinite recursion */
815815- tmp_magic = st->magic_samples[channel_index];
816816- st->magic_samples[channel_index] = 0;
817817- st->in_stride = 1;
818818- speex_resampler_process_native(st, channel_index, mem+N-1, &tmp_in_len, out, &tmp_out_len);
819819- st->in_stride = istride_save;
820820- /*speex_warning_int("extra samples:", tmp_out_len);*/
821821- /* If we couldn't process all "magic" input samples, save the rest for next time */
822822- if (tmp_in_len < tmp_magic)
823823- {
824824- spx_uint32_t i;
825825- st->magic_samples[channel_index] = tmp_magic-tmp_in_len;
826826- for (i=0;i<st->magic_samples[channel_index];i++)
827827- mem[N-1+i]=mem[N-1+i+tmp_in_len];
828828- }
829829- out += tmp_out_len*st->out_stride;
830830- *out_len -= tmp_out_len;
831831- }
832832-801801+833802 /* Call the right resampler through the function ptr */
834834- out_sample = st->resampler_ptr(st, channel_index, in, in_len, out, out_len);
835835-803803+ out_sample = st->resampler_ptr(st, channel_index, mem, in_len, out, out_len);
804804+836805 if (st->last_sample[channel_index] < (spx_int32_t)*in_len)
837806 *in_len = st->last_sample[channel_index];
838838- *out_len = out_sample+tmp_out_len;
807807+ *out_len = out_sample;
839808 st->last_sample[channel_index] -= *in_len;
840840-841841- for (j=0;j<N-1-(spx_int32_t)*in_len;j++)
842842- mem[j] = mem[j+*in_len];
843843- for (;j<N-1;j++)
844844- mem[j] = in[st->in_stride*(j+*in_len-N+1)];
845845-809809+810810+ ilen = *in_len;
811811+812812+ for(j=0;j<N-1;++j)
813813+ mem[j] = mem[j+ilen];
814814+846815 return RESAMPLER_ERR_SUCCESS;
847816}
848817849849-#define FIXED_STACK_ALLOC 1024
818818+static int speex_resampler_magic(SpeexResamplerState *st, spx_uint32_t channel_index, spx_word16_t **out, spx_uint32_t out_len) {
819819+ spx_uint32_t tmp_in_len = st->magic_samples[channel_index];
820820+ spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size;
821821+ const int N = st->filt_len;
822822+823823+ speex_resampler_process_native(st, channel_index, &tmp_in_len, *out, &out_len);
824824+825825+ st->magic_samples[channel_index] -= tmp_in_len;
826826+827827+ /* If we couldn't process all "magic" input samples, save the rest for next time */
828828+ if (st->magic_samples[channel_index])
829829+ {
830830+ spx_uint32_t i;
831831+ for (i=0;i<st->magic_samples[channel_index];i++)
832832+ mem[N-1+i]=mem[N-1+i+tmp_in_len];
833833+ }
834834+ *out += out_len*st->out_stride;
835835+ return out_len;
836836+}
850837851838#ifdef FIXED_POINT
852852-int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
853853-{
854854- spx_uint32_t i;
855855- int istride_save, ostride_save;
856856-#ifdef VAR_ARRAYS
857857- spx_word16_t x[*in_len];
858858- spx_word16_t y[*out_len];
859859- /*VARDECL(spx_word16_t *x);
860860- VARDECL(spx_word16_t *y);
861861- ALLOC(x, *in_len, spx_word16_t);
862862- ALLOC(y, *out_len, spx_word16_t);*/
863863- istride_save = st->in_stride;
864864- ostride_save = st->out_stride;
865865- for (i=0;i<*in_len;i++)
866866- x[i] = WORD2INT(in[i*st->in_stride]);
867867- st->in_stride = st->out_stride = 1;
868868- speex_resampler_process_native(st, channel_index, x, in_len, y, out_len);
869869- st->in_stride = istride_save;
870870- st->out_stride = ostride_save;
871871- for (i=0;i<*out_len;i++)
872872- out[i*st->out_stride] = y[i];
839839+EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
873840#else
874874- spx_word16_t x[FIXED_STACK_ALLOC];
875875- spx_word16_t y[FIXED_STACK_ALLOC];
876876- spx_uint32_t ilen=*in_len, olen=*out_len;
877877- istride_save = st->in_stride;
878878- ostride_save = st->out_stride;
879879- while (ilen && olen)
880880- {
881881- spx_uint32_t ichunk, ochunk;
882882- ichunk = ilen;
883883- ochunk = olen;
884884- if (ichunk>FIXED_STACK_ALLOC)
885885- ichunk=FIXED_STACK_ALLOC;
886886- if (ochunk>FIXED_STACK_ALLOC)
887887- ochunk=FIXED_STACK_ALLOC;
888888- for (i=0;i<ichunk;i++)
889889- x[i] = WORD2INT(in[i*st->in_stride]);
890890- st->in_stride = st->out_stride = 1;
891891- speex_resampler_process_native(st, channel_index, x, &ichunk, y, &ochunk);
892892- st->in_stride = istride_save;
893893- st->out_stride = ostride_save;
894894- for (i=0;i<ochunk;i++)
895895- out[i*st->out_stride] = y[i];
896896- out += ochunk;
897897- in += ichunk;
898898- ilen -= ichunk;
899899- olen -= ochunk;
841841+EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
842842+#endif
843843+{
844844+ int j;
845845+ spx_uint32_t ilen = *in_len;
846846+ spx_uint32_t olen = *out_len;
847847+ spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size;
848848+ const int filt_offs = st->filt_len - 1;
849849+ const spx_uint32_t xlen = st->mem_alloc_size - filt_offs;
850850+ const int istride = st->in_stride;
851851+852852+ if (st->magic_samples[channel_index])
853853+ olen -= speex_resampler_magic(st, channel_index, &out, olen);
854854+ if (! st->magic_samples[channel_index]) {
855855+ while (ilen && olen) {
856856+ spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen;
857857+ spx_uint32_t ochunk = olen;
858858+859859+ if (in) {
860860+ for(j=0;j<ichunk;++j)
861861+ x[j+filt_offs]=in[j*istride];
862862+ } else {
863863+ for(j=0;j<ichunk;++j)
864864+ x[j+filt_offs]=0;
865865+ }
866866+ speex_resampler_process_native(st, channel_index, &ichunk, out, &ochunk);
867867+ ilen -= ichunk;
868868+ olen -= ochunk;
869869+ out += ochunk * st->out_stride;
870870+ if (in)
871871+ in += ichunk * istride;
872872+ }
900873 }
901874 *in_len -= ilen;
902902- *out_len -= olen;
903903-#endif
875875+ *out_len -= olen;
904876 return RESAMPLER_ERR_SUCCESS;
905877}
906906-int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
907907-{
908908- return speex_resampler_process_native(st, channel_index, in, in_len, out, out_len);
909909-}
878878+879879+#ifdef FIXED_POINT
880880+EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
910881#else
911911-int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
912912-{
913913- return speex_resampler_process_native(st, channel_index, in, in_len, out, out_len);
914914-}
915915-int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
882882+EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
883883+#endif
916884{
917917- spx_uint32_t i;
918918- int istride_save, ostride_save;
885885+ int j;
886886+ const int istride_save = st->in_stride;
887887+ const int ostride_save = st->out_stride;
888888+ spx_uint32_t ilen = *in_len;
889889+ spx_uint32_t olen = *out_len;
890890+ spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size;
891891+ const spx_uint32_t xlen = st->mem_alloc_size - (st->filt_len - 1);
919892#ifdef VAR_ARRAYS
920920- spx_word16_t x[*in_len];
921921- spx_word16_t y[*out_len];
922922- /*VARDECL(spx_word16_t *x);
923923- VARDECL(spx_word16_t *y);
924924- ALLOC(x, *in_len, spx_word16_t);
925925- ALLOC(y, *out_len, spx_word16_t);*/
926926- istride_save = st->in_stride;
927927- ostride_save = st->out_stride;
928928- for (i=0;i<*in_len;i++)
929929- x[i] = in[i*st->in_stride];
930930- st->in_stride = st->out_stride = 1;
931931- speex_resampler_process_native(st, channel_index, x, in_len, y, out_len);
932932- st->in_stride = istride_save;
933933- st->out_stride = ostride_save;
934934- for (i=0;i<*out_len;i++)
935935- out[i*st->out_stride] = WORD2INT(y[i]);
893893+ const unsigned int ylen = (olen < FIXED_STACK_ALLOC) ? olen : FIXED_STACK_ALLOC;
894894+ VARDECL(spx_word16_t *ystack);
895895+ ALLOC(ystack, ylen, spx_word16_t);
896896+#else
897897+ const unsigned int ylen = FIXED_STACK_ALLOC;
898898+ spx_word16_t ystack[FIXED_STACK_ALLOC];
899899+#endif
900900+901901+ st->out_stride = 1;
902902+903903+ while (ilen && olen) {
904904+ spx_word16_t *y = ystack;
905905+ spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen;
906906+ spx_uint32_t ochunk = (olen > ylen) ? ylen : olen;
907907+ spx_uint32_t omagic = 0;
908908+909909+ if (st->magic_samples[channel_index]) {
910910+ omagic = speex_resampler_magic(st, channel_index, &y, ochunk);
911911+ ochunk -= omagic;
912912+ olen -= omagic;
913913+ }
914914+ if (! st->magic_samples[channel_index]) {
915915+ if (in) {
916916+ for(j=0;j<ichunk;++j)
917917+#ifdef FIXED_POINT
918918+ x[j+st->filt_len-1]=WORD2INT(in[j*istride_save]);
919919+#else
920920+ x[j+st->filt_len-1]=in[j*istride_save];
921921+#endif
922922+ } else {
923923+ for(j=0;j<ichunk;++j)
924924+ x[j+st->filt_len-1]=0;
925925+ }
926926+927927+ speex_resampler_process_native(st, channel_index, &ichunk, y, &ochunk);
928928+ } else {
929929+ ichunk = 0;
930930+ ochunk = 0;
931931+ }
932932+933933+ for (j=0;j<ochunk+omagic;++j)
934934+#ifdef FIXED_POINT
935935+ out[j*ostride_save] = ystack[j];
936936#else
937937- spx_word16_t x[FIXED_STACK_ALLOC];
938938- spx_word16_t y[FIXED_STACK_ALLOC];
939939- spx_uint32_t ilen=*in_len, olen=*out_len;
940940- istride_save = st->in_stride;
941941- ostride_save = st->out_stride;
942942- while (ilen && olen)
943943- {
944944- spx_uint32_t ichunk, ochunk;
945945- ichunk = ilen;
946946- ochunk = olen;
947947- if (ichunk>FIXED_STACK_ALLOC)
948948- ichunk=FIXED_STACK_ALLOC;
949949- if (ochunk>FIXED_STACK_ALLOC)
950950- ochunk=FIXED_STACK_ALLOC;
951951- for (i=0;i<ichunk;i++)
952952- x[i] = in[i*st->in_stride];
953953- st->in_stride = st->out_stride = 1;
954954- speex_resampler_process_native(st, channel_index, x, &ichunk, y, &ochunk);
955955- st->in_stride = istride_save;
956956- st->out_stride = ostride_save;
957957- for (i=0;i<ochunk;i++)
958958- out[i*st->out_stride] = WORD2INT(y[i]);
959959- out += ochunk;
960960- in += ichunk;
961961- ilen -= ichunk;
962962- olen -= ochunk;
937937+ out[j*ostride_save] = WORD2INT(ystack[j]);
938938+#endif
939939+940940+ ilen -= ichunk;
941941+ olen -= ochunk;
942942+ out += (ochunk+omagic) * ostride_save;
943943+ if (in)
944944+ in += ichunk * istride_save;
963945 }
946946+ st->out_stride = ostride_save;
964947 *in_len -= ilen;
965965- *out_len -= olen;
966966-#endif
948948+ *out_len -= olen;
949949+967950 return RESAMPLER_ERR_SUCCESS;
968951}
969969-#endif
970952971971-int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
953953+EXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
972954{
973955 spx_uint32_t i;
974956 int istride_save, ostride_save;
···989971 return RESAMPLER_ERR_SUCCESS;
990972}
991973992992-993993-int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
974974+EXPORT int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
994975{
995976 spx_uint32_t i;
996977 int istride_save, ostride_save;
···1011992 return RESAMPLER_ERR_SUCCESS;
1012993}
101399410141014-int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate)
995995+EXPORT int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate)
1015996{
1016997 return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate);
1017998}
101899910191019-void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate)
10001000+EXPORT void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate)
10201001{
10211002 *in_rate = st->in_rate;
10221003 *out_rate = st->out_rate;
10231004}
1024100510251025-int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate)
10061006+EXPORT int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate)
10261007{
10271008 spx_uint32_t fact;
10281009 spx_uint32_t old_den;
10291010 spx_uint32_t i;
10301011 if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den)
10311012 return RESAMPLER_ERR_SUCCESS;
10321032-10131013+10331014 old_den = st->den_rate;
10341015 st->in_rate = in_rate;
10351016 st->out_rate = out_rate;
···10441025 st->den_rate /= fact;
10451026 }
10461027 }
10471047-10281028+10481029 if (old_den > 0)
10491030 {
10501031 for (i=0;i<st->nb_channels;i++)
···10551036 st->samp_frac_num[i] = st->den_rate-1;
10561037 }
10571038 }
10581058-10391039+10591040 if (st->initialised)
10601041 update_filter(st);
10611042 return RESAMPLER_ERR_SUCCESS;
10621043}
1063104410641064-void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den)
10451045+EXPORT void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den)
10651046{
10661047 *ratio_num = st->num_rate;
10671048 *ratio_den = st->den_rate;
10681049}
1069105010701070-int speex_resampler_set_quality(SpeexResamplerState *st, int quality)
10511051+EXPORT int speex_resampler_set_quality(SpeexResamplerState *st, int quality)
10711052{
10721053 if (quality > 10 || quality < 0)
10731054 return RESAMPLER_ERR_INVALID_ARG;
···10791060 return RESAMPLER_ERR_SUCCESS;
10801061}
1081106210821082-void speex_resampler_get_quality(SpeexResamplerState *st, int *quality)
10631063+EXPORT void speex_resampler_get_quality(SpeexResamplerState *st, int *quality)
10831064{
10841065 *quality = st->quality;
10851066}
1086106710871087-void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride)
10681068+EXPORT void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride)
10881069{
10891070 st->in_stride = stride;
10901071}
1091107210921092-void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride)
10731073+EXPORT void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride)
10931074{
10941075 *stride = st->in_stride;
10951076}
1096107710971097-void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride)
10781078+EXPORT void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride)
10981079{
10991080 st->out_stride = stride;
11001081}
1101108211021102-void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride)
10831083+EXPORT void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride)
11031084{
11041085 *stride = st->out_stride;
11051086}
1106108711071107-int speex_resampler_skip_zeros(SpeexResamplerState *st)
10881088+EXPORT int speex_resampler_get_input_latency(SpeexResamplerState *st)
10891089+{
10901090+ return st->filt_len / 2;
10911091+}
10921092+10931093+EXPORT int speex_resampler_get_output_latency(SpeexResamplerState *st)
10941094+{
10951095+ return ((st->filt_len / 2) * st->den_rate + (st->num_rate >> 1)) / st->num_rate;
10961096+}
10971097+10981098+EXPORT int speex_resampler_skip_zeros(SpeexResamplerState *st)
11081099{
11091100 spx_uint32_t i;
11101101 for (i=0;i<st->nb_channels;i++)
···11121103 return RESAMPLER_ERR_SUCCESS;
11131104}
1114110511151115-int speex_resampler_reset_mem(SpeexResamplerState *st)
11061106+EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st)
11161107{
11171108 spx_uint32_t i;
11181109 for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
···11201111 return RESAMPLER_ERR_SUCCESS;
11211112}
1122111311231123-const char *speex_resampler_strerror(int err)
11141114+EXPORT const char *speex_resampler_strerror(int err)
11241115{
11251116 switch (err)
11261117 {
+128
lib/rbcodec/codecs/libspeex/resample_sse.h
···11+/* Copyright (C) 2007-2008 Jean-Marc Valin
22+ * Copyright (C) 2008 Thorvald Natvig
33+ */
44+/**
55+ @file resample_sse.h
66+ @brief Resampler functions (SSE version)
77+*/
88+/*
99+ Redistribution and use in source and binary forms, with or without
1010+ modification, are permitted provided that the following conditions
1111+ are met:
1212+1313+ - Redistributions of source code must retain the above copyright
1414+ notice, this list of conditions and the following disclaimer.
1515+1616+ - Redistributions in binary form must reproduce the above copyright
1717+ notice, this list of conditions and the following disclaimer in the
1818+ documentation and/or other materials provided with the distribution.
1919+2020+ - Neither the name of the Xiph.org Foundation nor the names of its
2121+ contributors may be used to endorse or promote products derived from
2222+ this software without specific prior written permission.
2323+2424+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2525+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2626+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2727+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
2828+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
2929+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
3030+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
3131+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
3232+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3333+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3434+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3535+*/
3636+3737+#include <xmmintrin.h>
3838+3939+#define OVERRIDE_INNER_PRODUCT_SINGLE
4040+static inline float inner_product_single(const float *a, const float *b, unsigned int len)
4141+{
4242+ int i;
4343+ float ret;
4444+ __m128 sum = _mm_setzero_ps();
4545+ for (i=0;i<len;i+=8)
4646+ {
4747+ sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(a+i), _mm_loadu_ps(b+i)));
4848+ sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(a+i+4), _mm_loadu_ps(b+i+4)));
4949+ }
5050+ sum = _mm_add_ps(sum, _mm_movehl_ps(sum, sum));
5151+ sum = _mm_add_ss(sum, _mm_shuffle_ps(sum, sum, 0x55));
5252+ _mm_store_ss(&ret, sum);
5353+ return ret;
5454+}
5555+5656+#define OVERRIDE_INTERPOLATE_PRODUCT_SINGLE
5757+static inline float interpolate_product_single(const float *a, const float *b, unsigned int len, const spx_uint32_t oversample, float *frac) {
5858+ int i;
5959+ float ret;
6060+ __m128 sum = _mm_setzero_ps();
6161+ __m128 f = _mm_loadu_ps(frac);
6262+ for(i=0;i<len;i+=2)
6363+ {
6464+ sum = _mm_add_ps(sum, _mm_mul_ps(_mm_load1_ps(a+i), _mm_loadu_ps(b+i*oversample)));
6565+ sum = _mm_add_ps(sum, _mm_mul_ps(_mm_load1_ps(a+i+1), _mm_loadu_ps(b+(i+1)*oversample)));
6666+ }
6767+ sum = _mm_mul_ps(f, sum);
6868+ sum = _mm_add_ps(sum, _mm_movehl_ps(sum, sum));
6969+ sum = _mm_add_ss(sum, _mm_shuffle_ps(sum, sum, 0x55));
7070+ _mm_store_ss(&ret, sum);
7171+ return ret;
7272+}
7373+7474+#ifdef _USE_SSE2
7575+#include <emmintrin.h>
7676+#define OVERRIDE_INNER_PRODUCT_DOUBLE
7777+7878+static inline double inner_product_double(const float *a, const float *b, unsigned int len)
7979+{
8080+ int i;
8181+ double ret;
8282+ __m128d sum = _mm_setzero_pd();
8383+ __m128 t;
8484+ for (i=0;i<len;i+=8)
8585+ {
8686+ t = _mm_mul_ps(_mm_loadu_ps(a+i), _mm_loadu_ps(b+i));
8787+ sum = _mm_add_pd(sum, _mm_cvtps_pd(t));
8888+ sum = _mm_add_pd(sum, _mm_cvtps_pd(_mm_movehl_ps(t, t)));
8989+9090+ t = _mm_mul_ps(_mm_loadu_ps(a+i+4), _mm_loadu_ps(b+i+4));
9191+ sum = _mm_add_pd(sum, _mm_cvtps_pd(t));
9292+ sum = _mm_add_pd(sum, _mm_cvtps_pd(_mm_movehl_ps(t, t)));
9393+ }
9494+ sum = _mm_add_sd(sum, (__m128d) _mm_movehl_ps((__m128) sum, (__m128) sum));
9595+ _mm_store_sd(&ret, sum);
9696+ return ret;
9797+}
9898+9999+#define OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE
100100+static inline double interpolate_product_double(const float *a, const float *b, unsigned int len, const spx_uint32_t oversample, float *frac) {
101101+ int i;
102102+ double ret;
103103+ __m128d sum;
104104+ __m128d sum1 = _mm_setzero_pd();
105105+ __m128d sum2 = _mm_setzero_pd();
106106+ __m128 f = _mm_loadu_ps(frac);
107107+ __m128d f1 = _mm_cvtps_pd(f);
108108+ __m128d f2 = _mm_cvtps_pd(_mm_movehl_ps(f,f));
109109+ __m128 t;
110110+ for(i=0;i<len;i+=2)
111111+ {
112112+ t = _mm_mul_ps(_mm_load1_ps(a+i), _mm_loadu_ps(b+i*oversample));
113113+ sum1 = _mm_add_pd(sum1, _mm_cvtps_pd(t));
114114+ sum2 = _mm_add_pd(sum2, _mm_cvtps_pd(_mm_movehl_ps(t, t)));
115115+116116+ t = _mm_mul_ps(_mm_load1_ps(a+i+1), _mm_loadu_ps(b+(i+1)*oversample));
117117+ sum1 = _mm_add_pd(sum1, _mm_cvtps_pd(t));
118118+ sum2 = _mm_add_pd(sum2, _mm_cvtps_pd(_mm_movehl_ps(t, t)));
119119+ }
120120+ sum1 = _mm_mul_pd(f1, sum1);
121121+ sum2 = _mm_mul_pd(f2, sum2);
122122+ sum = _mm_add_pd(sum1, sum2);
123123+ sum = _mm_add_sd(sum, (__m128d) _mm_movehl_ps((__m128) sum, (__m128) sum));
124124+ _mm_store_sd(&ret, sum);
125125+ return ret;
126126+}
127127+128128+#endif
+21-21
lib/rbcodec/codecs/libspeex/speex.c
···11-/* Copyright (C) 2002 Jean-Marc Valin
11+/* Copyright (C) 2002 Jean-Marc Valin
22 File: speex.c
3344 Basic Speex functions
···66 Redistribution and use in source and binary forms, with or without
77 modification, are permitted provided that the following conditions
88 are met:
99-99+1010 - Redistributions of source code must retain the above copyright
1111 notice, this list of conditions and the following disclaimer.
1212-1212+1313 - Redistributions in binary form must reproduce the above copyright
1414 notice, this list of conditions and the following disclaimer in the
1515 documentation and/or other materials provided with the distribution.
1616-1616+1717 - Neither the name of the Xiph.org Foundation nor the names of its
1818 contributors may be used to endorse or promote products derived from
1919 this software without specific prior written permission.
2020-2020+2121 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2222 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2323 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
···4949#define MAX_IN_SAMPLES 640
50505151#ifndef SPEEX_DISABLE_ENCODER
5252-void *speex_encoder_init(const SpeexMode *mode)
5252+EXPORT void *speex_encoder_init(const SpeexMode *mode)
5353{
5454 return mode->enc_init(mode);
5555}
5656#endif
57575858-void *speex_decoder_init(const SpeexMode *mode)
5858+EXPORT void *speex_decoder_init(const SpeexMode *mode)
5959{
6060 return mode->dec_init(mode);
6161}
62626363#ifndef SPEEX_DISABLE_ENCODER
6464-void speex_encoder_destroy(void *state)
6464+EXPORT void speex_encoder_destroy(void *state)
6565{
6666 (*((SpeexMode**)state))->enc_destroy(state);
6767}
6868#endif
69697070-void speex_decoder_destroy(void *state)
7070+EXPORT void speex_decoder_destroy(void *state)
7171{
7272 (*((SpeexMode**)state))->dec_destroy(state);
7373}
···90909191#ifndef SPEEX_DISABLE_ENCODER
9292#ifndef DISABLE_FLOAT_API
9393-int speex_encode(void *state, float *in, SpeexBits *bits)
9393+EXPORT int speex_encode(void *state, float *in, SpeexBits *bits)
9494{
9595 int i;
9696 spx_int32_t N;
···109109}
110110#endif /* #ifndef DISABLE_FLOAT_API */
111111112112-int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits)
112112+EXPORT int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits)
113113{
114114 SpeexMode *mode;
115115 mode = *(SpeexMode**)state;
···118118#endif /* SPEEX_DISABLE_ENCODER */
119119120120#ifndef DISABLE_FLOAT_API
121121-int speex_decode(void *state, SpeexBits *bits, float *out)
121121+EXPORT int speex_decode(void *state, SpeexBits *bits, float *out)
122122{
123123 int i, ret;
124124 spx_int32_t N;
···131131}
132132#endif /* #ifndef DISABLE_FLOAT_API */
133133134134-int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out)
134134+EXPORT int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out)
135135{
136136 SpeexMode *mode = *(SpeexMode**)state;
137137 return (mode)->dec(state, bits, out);
···139139140140#else
141141142142-int speex_encode(void *state, float *in, SpeexBits *bits)
142142+EXPORT int speex_encode(void *state, float *in, SpeexBits *bits)
143143{
144144 return (*((SpeexMode**)state))->enc(state, in, bits);
145145}
146146147147-int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits)
147147+EXPORT int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits)
148148{
149149 int i;
150150 spx_int32_t N;
···155155 return (*((SpeexMode**)state))->enc(state, float_in, bits);
156156}
157157158158-int speex_decode(void *state, SpeexBits *bits, float *out)
158158+EXPORT int speex_decode(void *state, SpeexBits *bits, float *out)
159159{
160160 return (*((SpeexMode**)state))->dec(state, bits, out);
161161}
162162163163-int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out)
163163+EXPORT int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out)
164164{
165165 int i;
166166 spx_int32_t N;
···182182#endif
183183184184#ifndef SPEEX_DISABLE_ENCODER
185185-int speex_encoder_ctl(void *state, int request, void *ptr)
185185+EXPORT int speex_encoder_ctl(void *state, int request, void *ptr)
186186{
187187 return (*((SpeexMode**)state))->enc_ctl(state, request, ptr);
188188}
189189#endif
190190191191-int speex_decoder_ctl(void *state, int request, void *ptr)
191191+EXPORT int speex_decoder_ctl(void *state, int request, void *ptr)
192192{
193193 return (*((SpeexMode**)state))->dec_ctl(state, request, ptr);
194194}
···196196int nb_mode_query(const void *mode, int request, void *ptr)
197197{
198198 const SpeexNBMode *m = (const SpeexNBMode*)mode;
199199-199199+200200 switch (request)
201201 {
202202 case SPEEX_MODE_FRAME_SIZE:
···219219220220221221222222-int speex_lib_ctl(int request, void *ptr)
222222+EXPORT int speex_lib_ctl(int request, void *ptr)
223223{
224224 switch (request)
225225 {
+14-14
lib/rbcodec/codecs/libspeex/speex_callbacks.c
···66 Redistribution and use in source and binary forms, with or without
77 modification, are permitted provided that the following conditions
88 are met:
99-99+1010 - Redistributions of source code must retain the above copyright
1111 notice, this list of conditions and the following disclaimer.
1212-1212+1313 - Redistributions in binary form must reproduce the above copyright
1414 notice, this list of conditions and the following disclaimer in the
1515 documentation and/or other materials provided with the distribution.
1616-1616+1717 - Neither the name of the Xiph.org Foundation nor the names of its
1818 contributors may be used to endorse or promote products derived from
1919 this software without specific prior written permission.
2020-2020+2121 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2222 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2323 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
···4040#include "arch.h"
4141#include "os_support.h"
42424343-int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *state)
4343+EXPORT int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *state)
4444{
4545 int id;
4646 SpeexCallback *callback;
···6565 adv = 16;
6666 else if (id<14)
6767 adv = 32;
6868- else
6868+ else
6969 adv = 64;
7070 speex_bits_advance(bits, adv);
7171 }
···74747575#if 0
7676/* Rockbox: unused */
7777-int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data)
7777+EXPORT int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data)
7878{
7979 (void)state;
8080 spx_int32_t m;
···8383 return 0;
8484}
85858686-int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data)
8686+EXPORT int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data)
8787{
8888 (void)state;
8989 spx_int32_t m;
···9292 return 0;
9393}
94949595-int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data)
9595+EXPORT int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data)
9696{
9797 (void)state;
9898 spx_int32_t m;
···103103#endif
104104105105#ifndef DISABLE_VBR
106106-int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data)
106106+EXPORT int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data)
107107{
108108 (void)state;
109109 spx_int32_t vbr;
···115115116116#if 0
117117/* Rockbox: unused */
118118-int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data)
118118+EXPORT int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data)
119119{
120120 (void)state;
121121 spx_int32_t enh;
···126126#endif
127127128128#ifndef DISABLE_VBR
129129-int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data)
129129+EXPORT int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data)
130130{
131131 (void)state;
132132 float qual;
···138138139139#if 0
140140/* Rockbox: unused */
141141-int speex_std_char_handler(SpeexBits *bits, void *state, void *data)
141141+EXPORT int speex_std_char_handler(SpeexBits *bits, void *state, void *data)
142142{
143143 (void)state;
144144 unsigned char ch;
···150150#endif
151151152152/* Default handler for user callbacks: skip it */
153153-int speex_default_user_handler(SpeexBits *bits, void *state, void *data)
153153+EXPORT int speex_default_user_handler(SpeexBits *bits, void *state, void *data)
154154{
155155 (void)state;
156156 (void)data;
+37-18
lib/rbcodec/codecs/libspeex/speex_header.c
···11-/* Copyright (C) 2002 Jean-Marc Valin
11+/* Copyright (C) 2002 Jean-Marc Valin
22 File: speex_header.c
33 Describes the Speex header
4455 Redistribution and use in source and binary forms, with or without
66 modification, are permitted provided that the following conditions
77 are met:
88-88+99 - Redistributions of source code must retain the above copyright
1010 notice, this list of conditions and the following disclaimer.
1111-1111+1212 - Redistributions in binary form must reproduce the above copyright
1313 notice, this list of conditions and the following disclaimer in the
1414 documentation and/or other materials provided with the distribution.
1515-1515+1616 - Neither the name of the Xiph.org Foundation nor the names of its
1717 contributors may be used to endorse or promote products derived from
1818 this software without specific prior written permission.
1919-1919+2020 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2121 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2222 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
···4747/** Convert little endian */
4848static inline spx_int32_t le_int(spx_int32_t i)
4949{
5050-#ifdef ROCKBOX
5050+#ifdef ROCKBOX
5151 return letoh32(i);
5252#elif !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) )
5353 spx_uint32_t ui, ret;
···8686*/
87878888#ifndef SPEEX_DISABLE_ENCODER
8989-void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const SpeexMode *m)
8989+EXPORT void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const SpeexMode *m)
9090{
9191 int i;
9292 const char *h="Speex ";
···101101 header->speex_version[i]=SPEEX_VERSION[i];
102102 for (;i<SPEEX_HEADER_VERSION_LENGTH;i++)
103103 header->speex_version[i]=0;
104104-104104+105105 header->speex_version_id = 1;
106106 header->header_size = sizeof(SpeexHeader);
107107-107107+108108 header->rate = rate;
109109 header->mode = m->modeID;
110110 header->mode_bitstream_version = m->bitstream_version;
···114114 header->bitrate = -1;
115115 speex_mode_query(m, SPEEX_MODE_FRAME_SIZE, &header->frame_size);
116116 header->vbr = 0;
117117-117117+118118 header->frames_per_packet = 0;
119119 header->extra_headers = 0;
120120 header->reserved1 = 0;
121121 header->reserved2 = 0;
122122}
123123124124-char *speex_header_to_packet(SpeexHeader *header, int *size)
124124+EXPORT char *speex_header_to_packet(SpeexHeader *header, int *size)
125125{
126126 SpeexHeader *le_header;
127127 le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader));
128128-128128+129129 SPEEX_COPY(le_header, header, 1);
130130-130130+131131 /*Make sure everything is now little-endian*/
132132 ENDIAN_SWITCH(le_header->speex_version_id);
133133 ENDIAN_SWITCH(le_header->header_size);
···147147#endif /* SPEEX_DISABLE_ENCODER */
148148149149static SpeexHeader global_le_header; /* Avoid malloc */
150150-SpeexHeader *speex_packet_to_header(char *packet, int size)
150150+EXPORT SpeexHeader *speex_packet_to_header(char *packet, int size)
151151{
152152 int i;
153153 SpeexHeader *le_header = &global_le_header;
···158158 speex_notify("This doesn't look like a Speex file");
159159 return NULL;
160160 }
161161-161161+162162 /*FIXME: Do we allow larger headers?*/
163163 if (size < (int)sizeof(SpeexHeader))
164164 {
165165 speex_notify("Speex header too small");
166166 return NULL;
167167 }
168168-168168+169169 /* le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader)); */
170170-170170+171171 SPEEX_COPY(le_header, (SpeexHeader*)packet, 1);
172172-172172+173173 /*Make sure everything is converted correctly from little-endian*/
174174 ENDIAN_SWITCH(le_header->speex_version_id);
175175 ENDIAN_SWITCH(le_header->header_size);
···183183 ENDIAN_SWITCH(le_header->frames_per_packet);
184184 ENDIAN_SWITCH(le_header->extra_headers);
185185186186+ if (le_header->mode >= SPEEX_NB_MODES || le_header->mode < 0)
187187+ {
188188+ speex_notify("Invalid mode specified in Speex header");
189189+ speex_free (le_header);
190190+ return NULL;
191191+ }
192192+193193+ if (le_header->nb_channels>2)
194194+ le_header->nb_channels = 2;
195195+ if (le_header->nb_channels<1)
196196+ le_header->nb_channels = 1;
197197+186198 return le_header;
187199188200}
201201+202202+#if 0 /* Unused by rockbox */
203203+EXPORT void speex_header_free(void *ptr)
204204+{
205205+ speex_free(ptr);
206206+}
207207+#endif
+28-28
lib/rbcodec/codecs/libspeex/stereo.c
···11-/* Copyright (C) 2002 Jean-Marc Valin
11+/* Copyright (C) 2002 Jean-Marc Valin
22 File: stereo.c
3344 Redistribution and use in source and binary forms, with or without
55 modification, are permitted provided that the following conditions
66 are met:
77-77+88 - Redistributions of source code must retain the above copyright
99 notice, this list of conditions and the following disclaimer.
1010-1010+1111 - Redistributions in binary form must reproduce the above copyright
1212 notice, this list of conditions and the following disclaimer in the
1313 documentation and/or other materials provided with the distribution.
1414-1414+1515 - Neither the name of the Xiph.org Foundation nor the names of its
1616 contributors may be used to endorse or promote products derived from
1717 this software without specific prior written permission.
1818-1818+1919 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2020 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2121 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
···7171#ifdef FIXED_POINT
7272#define COMPATIBILITY_HACK(s) do {if ((s)->reserved1 != 0xdeadbeef) speex_stereo_state_reset((SpeexStereoState*)s); } while (0);
7373#else
7474-#define COMPATIBILITY_HACK(s)
7474+#define COMPATIBILITY_HACK(s)
7575#endif
76767777static SpeexStereoState global_stereo_state;
7878-SpeexStereoState *speex_stereo_state_init()
7878+EXPORT SpeexStereoState *speex_stereo_state_init()
7979{
8080 /* SpeexStereoState *stereo = speex_alloc(sizeof(SpeexStereoState)); */
8181 SpeexStereoState *stereo = &global_stereo_state;
···8383 return stereo;
8484}
85858686-void speex_stereo_state_reset(SpeexStereoState *_stereo)
8686+EXPORT void speex_stereo_state_reset(SpeexStereoState *_stereo)
8787{
8888 RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo;
8989#ifdef FIXED_POINT
···100100 stereo->smooth_right = 1.f;
101101 stereo->reserved1 = 0;
102102 stereo->reserved2 = 0;
103103-#endif
103103+#endif
104104}
105105106106-void speex_stereo_state_destroy(SpeexStereoState *stereo)
106106+EXPORT void speex_stereo_state_destroy(SpeexStereoState *stereo)
107107{
108108 (void)stereo;
109109 /* speex_free(stereo); */
···111111112112#ifndef SPEEX_DISABLE_ENCODER
113113#ifndef DISABLE_FLOAT_API
114114-void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits)
114114+EXPORT void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits)
115115{
116116 int i, tmp;
117117 float e_left=0, e_right=0, e_tot=0;
···129129 /*Quantization*/
130130 speex_bits_pack(bits, 14, 5);
131131 speex_bits_pack(bits, SPEEX_INBAND_STEREO, 4);
132132-132132+133133 balance=4*log(balance);
134134135135 /*Pack sign*/
···140140 balance=floor(.5+fabs(balance));
141141 if (balance>30)
142142 balance=31;
143143-143143+144144 speex_bits_pack(bits, (int)balance, 5);
145145-145145+146146 /* FIXME: this is a hack */
147147 tmp=scal_quant(e_ratio*Q15_ONE, e_ratio_quant_bounds, 4);
148148 speex_bits_pack(bits, tmp, 2);
149149}
150150#endif /* #ifndef DISABLE_FLOAT_API */
151151152152-void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits)
152152+EXPORT void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits)
153153{
154154 int i, tmp;
155155 spx_word32_t e_left=0, e_right=0, e_tot=0;
···159159#ifdef FIXED_POINT
160160 int shift;
161161#endif
162162-162162+163163 /* In band marker */
164164 speex_bits_pack(bits, 14, 5);
165165 /* Stereo marker */
···204204 if (balance_id>30)
205205 balance_id=31;
206206#endif
207207-207207+208208 speex_bits_pack(bits, balance_id, 5);
209209-209209+210210 /* "coherence" quantisation */
211211#ifdef FIXED_POINT
212212 shift = spx_ilog2(e_tot);
···217217#else
218218 e_ratio = e_tot/(1.+e_left+e_right);
219219#endif
220220-220220+221221 tmp=scal_quant(EXTRACT16(e_ratio), e_ratio_quant_bounds, 4);
222222 /*fprintf (stderr, "%d %d %d %d\n", largest, smallest, balance_id, e_ratio);*/
223223 speex_bits_pack(bits, tmp, 2);
···225225#endif /* SPEEX_DISABLE_ENCODER */
226226227227#ifndef DISABLE_FLOAT_API
228228-void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *_stereo)
228228+EXPORT void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *_stereo)
229229{
230230 int i;
231231 spx_word32_t balance;
232232 spx_word16_t e_left, e_right, e_ratio;
233233 RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo;
234234-234234+235235 COMPATIBILITY_HACK(stereo);
236236-236236+237237 balance=stereo->balance;
238238 e_ratio=stereo->e_ratio;
239239-239239+240240 /* These two are Q14, with max value just below 2. */
241241 e_right = DIV32(QCONST32(1., 22), spx_sqrt(MULT16_32_Q15(e_ratio, ADD32(QCONST32(1., 16), balance))));
242242 e_left = SHR32(MULT16_16(spx_sqrt(balance), e_right), 8);
···252252}
253253#endif /* #ifndef DISABLE_FLOAT_API */
254254255255-void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState *_stereo)
255255+EXPORT void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState *_stereo)
256256{
257257 int i;
258258 spx_word32_t balance;
···260260 RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo;
261261262262 /* COMPATIBILITY_HACK(stereo); */
263263-263263+264264 balance=stereo->balance;
265265 e_ratio=stereo->e_ratio;
266266-266266+267267 /* These two are Q14, with max value just below 2. */
268268 e_right = DIV32(QCONST32(1., 22), spx_sqrt(MULT16_32_Q15(e_ratio, ADD32(QCONST32(1., 16), balance))));
269269 e_left = SHR32(MULT16_16(spx_sqrt(balance), e_right), 8);
···278278 }
279279}
280280281281-int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data)
281281+EXPORT int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data)
282282{
283283 (void)state;
284284 RealSpeexStereoState *stereo;
···286286 int tmp;
287287288288 stereo = (RealSpeexStereoState*)data;
289289-289289+290290 /* COMPATIBILITY_HACK(stereo); */
291291292292 if (speex_bits_unpack_unsigned(bits, 1))