diff options
author | Solomon Peachy <pizza@shaftnet.org> | 2024-05-08 10:36:38 -0400 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2024-06-20 07:08:35 -0400 |
commit | 547b6a570dbad844e79b4ba5eb934f043bab6318 (patch) | |
tree | 0cbdb670d73a2544d33985166c5abfa69e20a590 /lib | |
parent | 8ef20383b1e5025f7724e750832de6e28e50680d (diff) | |
download | rockbox-547b6a570dbad844e79b4ba5eb934f043bab6318.tar.gz rockbox-547b6a570dbad844e79b4ba5eb934f043bab6318.zip |
codecs: Update libspeex from 1.2beta3 to 1.2rc1
This is a relatively minor bump, but it's the first step towards
bringing this current.
Change-Id: Iab6c9b0c77f0ba705280434ea74b513364719499
Diffstat (limited to 'lib')
21 files changed, 1399 insertions, 994 deletions
diff --git a/lib/rbcodec/codecs/libspeex/COPYING b/lib/rbcodec/codecs/libspeex/COPYING index 3b6b579cf3..de6fbe2c91 100644 --- a/lib/rbcodec/codecs/libspeex/COPYING +++ b/lib/rbcodec/codecs/libspeex/COPYING | |||
@@ -1,10 +1,11 @@ | |||
1 | Copyright 2002-2006 | 1 | Copyright 2002-2008 Xiph.org Foundation |
2 | Xiph.org Foundation | 2 | Copyright 2002-2008 Jean-Marc Valin |
3 | Jean-Marc Valin | 3 | Copyright 2005-2007 Analog Devices Inc. |
4 | David Rowe | 4 | Copyright 2005-2008 Commonwealth Scientific and Industrial Research |
5 | EpicGames | 5 | Organisation (CSIRO) |
6 | Analog Devices | 6 | Copyright 1993, 2002, 2006 David Rowe |
7 | Commonwealth Scientific and Industrial Research Organisation (CSIRO) | 7 | Copyright 2003 EpicGames |
8 | Copyright 1992-1994 Jutta Degener, Carsten Bormann | ||
8 | 9 | ||
9 | Redistribution and use in source and binary forms, with or without | 10 | Redistribution and use in source and binary forms, with or without |
10 | modification, are permitted provided that the following conditions | 11 | modification, are permitted provided that the following conditions |
diff --git a/lib/rbcodec/codecs/libspeex/README.rockbox b/lib/rbcodec/codecs/libspeex/README.rockbox index 84fff59b60..be809dc40d 100644 --- a/lib/rbcodec/codecs/libspeex/README.rockbox +++ b/lib/rbcodec/codecs/libspeex/README.rockbox | |||
@@ -1,6 +1,6 @@ | |||
1 | Library: libspeex-1.2beta3 (SVN version 14054) | 1 | Library: libspeex-1.2rc1 |
2 | Imported: 2007-03-12 by Dan Everton | 2 | Imported 1.2beta3: 2007-03-12 by Dan Everton |
3 | 3 | Updated 1.2rc1: 2024-05-08 by Solomon Peachy | |
4 | 4 | ||
5 | This directory contains a local version of libspeex for decoding Ogg/Speex | 5 | This directory contains a local version of libspeex for decoding Ogg/Speex |
6 | audio streams. | 6 | audio streams. |
diff --git a/lib/rbcodec/codecs/libspeex/arch.h b/lib/rbcodec/codecs/libspeex/arch.h index 35b5363837..b0a9097f99 100644 --- a/lib/rbcodec/codecs/libspeex/arch.h +++ b/lib/rbcodec/codecs/libspeex/arch.h | |||
@@ -235,7 +235,7 @@ typedef float spx_word32_t; | |||
235 | 235 | ||
236 | 236 | ||
237 | #ifdef FIXED_DEBUG | 237 | #ifdef FIXED_DEBUG |
238 | long long spx_mips=0; | 238 | extern long long spx_mips=0; |
239 | #endif | 239 | #endif |
240 | 240 | ||
241 | 241 | ||
diff --git a/lib/rbcodec/codecs/libspeex/bits.c b/lib/rbcodec/codecs/libspeex/bits.c index c7a5c14ede..2580e700fe 100644 --- a/lib/rbcodec/codecs/libspeex/bits.c +++ b/lib/rbcodec/codecs/libspeex/bits.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* Copyright (C) 2002 Jean-Marc Valin | 1 | /* Copyright (C) 2002 Jean-Marc Valin |
2 | File: speex_bits.c | 2 | File: speex_bits.c |
3 | 3 | ||
4 | Handles bit packing/unpacking | 4 | Handles bit packing/unpacking |
@@ -6,18 +6,18 @@ | |||
6 | Redistribution and use in source and binary forms, with or without | 6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions | 7 | modification, are permitted provided that the following conditions |
8 | are met: | 8 | are met: |
9 | 9 | ||
10 | - Redistributions of source code must retain the above copyright | 10 | - Redistributions of source code must retain the above copyright |
11 | notice, this list of conditions and the following disclaimer. | 11 | notice, this list of conditions and the following disclaimer. |
12 | 12 | ||
13 | - Redistributions in binary form must reproduce the above copyright | 13 | - Redistributions in binary form must reproduce the above copyright |
14 | notice, this list of conditions and the following disclaimer in the | 14 | notice, this list of conditions and the following disclaimer in the |
15 | documentation and/or other materials provided with the distribution. | 15 | documentation and/or other materials provided with the distribution. |
16 | 16 | ||
17 | - Neither the name of the Xiph.org Foundation nor the names of its | 17 | - Neither the name of the Xiph.org Foundation nor the names of its |
18 | contributors may be used to endorse or promote products derived from | 18 | contributors may be used to endorse or promote products derived from |
19 | this software without specific prior written permission. | 19 | this software without specific prior written permission. |
20 | 20 | ||
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
22 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 22 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
@@ -46,7 +46,7 @@ | |||
46 | #endif | 46 | #endif |
47 | 47 | ||
48 | #ifdef ROCKBOX_VOICE_ENCODER | 48 | #ifdef ROCKBOX_VOICE_ENCODER |
49 | void speex_bits_init(SpeexBits *bits) | 49 | EXPORT void speex_bits_init(SpeexBits *bits) |
50 | { | 50 | { |
51 | bits->chars = (char*)speex_alloc(MAX_CHARS_PER_FRAME); | 51 | bits->chars = (char*)speex_alloc(MAX_CHARS_PER_FRAME); |
52 | if (!bits->chars) | 52 | if (!bits->chars) |
@@ -62,7 +62,7 @@ void speex_bits_init(SpeexBits *bits) | |||
62 | 62 | ||
63 | #if 0 | 63 | #if 0 |
64 | /* Rockbox: unused */ | 64 | /* Rockbox: unused */ |
65 | void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size) | 65 | EXPORT void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size) |
66 | { | 66 | { |
67 | bits->chars = (char*)buff; | 67 | bits->chars = (char*)buff; |
68 | bits->buf_size = buf_size; | 68 | bits->buf_size = buf_size; |
@@ -73,7 +73,7 @@ void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size) | |||
73 | } | 73 | } |
74 | #endif | 74 | #endif |
75 | 75 | ||
76 | void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size) | 76 | EXPORT void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size) |
77 | { | 77 | { |
78 | bits->chars = (char*)buff; | 78 | bits->chars = (char*)buff; |
79 | bits->buf_size = buf_size; | 79 | bits->buf_size = buf_size; |
@@ -84,11 +84,11 @@ void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size) | |||
84 | bits->charPtr=0; | 84 | bits->charPtr=0; |
85 | bits->bitPtr=0; | 85 | bits->bitPtr=0; |
86 | bits->overflow=0; | 86 | bits->overflow=0; |
87 | 87 | ||
88 | } | 88 | } |
89 | 89 | ||
90 | #ifndef ROCKBOX_VOICE_CODEC | 90 | #ifndef ROCKBOX_VOICE_CODEC |
91 | void speex_bits_destroy(SpeexBits *bits) | 91 | EXPORT void speex_bits_destroy(SpeexBits *bits) |
92 | { | 92 | { |
93 | if (bits->owner) | 93 | if (bits->owner) |
94 | speex_free(bits->chars); | 94 | speex_free(bits->chars); |
@@ -97,7 +97,7 @@ void speex_bits_destroy(SpeexBits *bits) | |||
97 | #endif | 97 | #endif |
98 | 98 | ||
99 | #ifdef ROCKBOX_VOICE_ENCODER | 99 | #ifdef ROCKBOX_VOICE_ENCODER |
100 | void speex_bits_reset(SpeexBits *bits) | 100 | EXPORT void speex_bits_reset(SpeexBits *bits) |
101 | { | 101 | { |
102 | /* We only need to clear the first byte now */ | 102 | /* We only need to clear the first byte now */ |
103 | bits->chars[0]=0; | 103 | bits->chars[0]=0; |
@@ -110,7 +110,7 @@ void speex_bits_reset(SpeexBits *bits) | |||
110 | 110 | ||
111 | #if 0 | 111 | #if 0 |
112 | /* Rockbox: unused */ | 112 | /* Rockbox: unused */ |
113 | void speex_bits_rewind(SpeexBits *bits) | 113 | EXPORT void speex_bits_rewind(SpeexBits *bits) |
114 | { | 114 | { |
115 | bits->charPtr=0; | 115 | bits->charPtr=0; |
116 | bits->bitPtr=0; | 116 | bits->bitPtr=0; |
@@ -119,7 +119,7 @@ void speex_bits_rewind(SpeexBits *bits) | |||
119 | #endif | 119 | #endif |
120 | 120 | ||
121 | #if !defined(SPEEX_VOICE_ENCODER) && !defined(ROCKBOX_VOICE_CODEC) | 121 | #if !defined(SPEEX_VOICE_ENCODER) && !defined(ROCKBOX_VOICE_CODEC) |
122 | void speex_bits_read_from(SpeexBits *bits, char *chars, int len) | 122 | EXPORT void speex_bits_read_from(SpeexBits *bits, char *chars, int len) |
123 | { | 123 | { |
124 | int i; | 124 | int i; |
125 | int nchars = len / BYTES_PER_CHAR; | 125 | int nchars = len / BYTES_PER_CHAR; |
@@ -166,9 +166,10 @@ static void speex_bits_flush(SpeexBits *bits) | |||
166 | bits->charPtr=0; | 166 | bits->charPtr=0; |
167 | } | 167 | } |
168 | 168 | ||
169 | void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes) | 169 | EXPORT void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes) |
170 | { | 170 | { |
171 | int i,pos; | 171 | int i,pos; |
172 | |||
172 | int nchars = nbytes/BYTES_PER_CHAR; | 173 | int nchars = nbytes/BYTES_PER_CHAR; |
173 | 174 | ||
174 | if (((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR)+nchars > bits->buf_size) | 175 | if (((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR)+nchars > bits->buf_size) |
@@ -200,7 +201,7 @@ void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes) | |||
200 | #endif | 201 | #endif |
201 | 202 | ||
202 | #ifndef SPEEX_DISABLE_ENCODER | 203 | #ifndef SPEEX_DISABLE_ENCODER |
203 | int speex_bits_write(SpeexBits *bits, char *chars, int max_nbytes) | 204 | EXPORT int speex_bits_write(SpeexBits *bits, char *chars, int max_nbytes) |
204 | { | 205 | { |
205 | int i; | 206 | int i; |
206 | int max_nchars = max_nbytes/BYTES_PER_CHAR; | 207 | int max_nchars = max_nbytes/BYTES_PER_CHAR; |
@@ -223,7 +224,7 @@ int speex_bits_write(SpeexBits *bits, char *chars, int max_nbytes) | |||
223 | return max_nchars*BYTES_PER_CHAR; | 224 | return max_nchars*BYTES_PER_CHAR; |
224 | } | 225 | } |
225 | 226 | ||
226 | int speex_bits_write_whole_bytes(SpeexBits *bits, char *chars, int max_nbytes) | 227 | EXPORT int speex_bits_write_whole_bytes(SpeexBits *bits, char *chars, int max_nbytes) |
227 | { | 228 | { |
228 | int max_nchars = max_nbytes/BYTES_PER_CHAR; | 229 | int max_nchars = max_nbytes/BYTES_PER_CHAR; |
229 | int i; | 230 | int i; |
@@ -241,7 +242,7 @@ int speex_bits_write_whole_bytes(SpeexBits *bits, char *chars, int max_nbytes) | |||
241 | return max_nchars*BYTES_PER_CHAR; | 242 | return max_nchars*BYTES_PER_CHAR; |
242 | } | 243 | } |
243 | 244 | ||
244 | void speex_bits_pack(SpeexBits *bits, int data, int nbBits) | 245 | EXPORT void speex_bits_pack(SpeexBits *bits, int data, int nbBits) |
245 | { | 246 | { |
246 | unsigned int d=data; | 247 | unsigned int d=data; |
247 | 248 | ||
@@ -287,7 +288,7 @@ void speex_bits_pack(SpeexBits *bits, int data, int nbBits) | |||
287 | 288 | ||
288 | #if 0 | 289 | #if 0 |
289 | /* Rockbox: unused */ | 290 | /* Rockbox: unused */ |
290 | int speex_bits_unpack_signed(SpeexBits *bits, int nbBits) | 291 | EXPORT int speex_bits_unpack_signed(SpeexBits *bits, int nbBits) |
291 | { | 292 | { |
292 | unsigned int d=speex_bits_unpack_unsigned(bits,nbBits); | 293 | unsigned int d=speex_bits_unpack_unsigned(bits,nbBits); |
293 | /* If number is negative */ | 294 | /* If number is negative */ |
@@ -299,7 +300,7 @@ int speex_bits_unpack_signed(SpeexBits *bits, int nbBits) | |||
299 | } | 300 | } |
300 | #endif | 301 | #endif |
301 | 302 | ||
302 | unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits) | 303 | EXPORT unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits) |
303 | { | 304 | { |
304 | unsigned int d=0; | 305 | unsigned int d=0; |
305 | if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+nbBits>bits->nbBits) | 306 | if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+nbBits>bits->nbBits) |
@@ -323,7 +324,7 @@ unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits) | |||
323 | 324 | ||
324 | #if 0 | 325 | #if 0 |
325 | /* Rockbox: unused */ | 326 | /* Rockbox: unused */ |
326 | unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits) | 327 | EXPORT unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits) |
327 | { | 328 | { |
328 | unsigned int d=0; | 329 | unsigned int d=0; |
329 | int bitPtr, charPtr; | 330 | int bitPtr, charPtr; |
@@ -353,7 +354,7 @@ unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits) | |||
353 | } | 354 | } |
354 | #endif | 355 | #endif |
355 | 356 | ||
356 | int speex_bits_peek(SpeexBits *bits) | 357 | EXPORT int speex_bits_peek(SpeexBits *bits) |
357 | { | 358 | { |
358 | if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+1>bits->nbBits) | 359 | if ((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+1>bits->nbBits) |
359 | bits->overflow=1; | 360 | bits->overflow=1; |
@@ -362,7 +363,7 @@ int speex_bits_peek(SpeexBits *bits) | |||
362 | return (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1; | 363 | return (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1; |
363 | } | 364 | } |
364 | 365 | ||
365 | void speex_bits_advance(SpeexBits *bits, int n) | 366 | EXPORT void speex_bits_advance(SpeexBits *bits, int n) |
366 | { | 367 | { |
367 | if (((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+n>bits->nbBits) || bits->overflow){ | 368 | if (((bits->charPtr<<LOG2_BITS_PER_CHAR)+bits->bitPtr+n>bits->nbBits) || bits->overflow){ |
368 | bits->overflow=1; | 369 | bits->overflow=1; |
@@ -372,7 +373,7 @@ void speex_bits_advance(SpeexBits *bits, int n) | |||
372 | bits->bitPtr = (bits->bitPtr+n) & (BITS_PER_CHAR-1); /* modulo by BITS_PER_CHAR */ | 373 | bits->bitPtr = (bits->bitPtr+n) & (BITS_PER_CHAR-1); /* modulo by BITS_PER_CHAR */ |
373 | } | 374 | } |
374 | 375 | ||
375 | int speex_bits_remaining(SpeexBits *bits) | 376 | EXPORT int speex_bits_remaining(SpeexBits *bits) |
376 | { | 377 | { |
377 | if (bits->overflow) | 378 | if (bits->overflow) |
378 | return -1; | 379 | return -1; |
@@ -382,14 +383,14 @@ int speex_bits_remaining(SpeexBits *bits) | |||
382 | 383 | ||
383 | #if 0 | 384 | #if 0 |
384 | /* Rockbox: unused */ | 385 | /* Rockbox: unused */ |
385 | int speex_bits_nbytes(SpeexBits *bits) | 386 | EXPORT int speex_bits_nbytes(SpeexBits *bits) |
386 | { | 387 | { |
387 | return ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR); | 388 | return ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR); |
388 | } | 389 | } |
389 | #endif | 390 | #endif |
390 | 391 | ||
391 | #ifndef SPEEX_DISABLE_ENCODER | 392 | #ifndef SPEEX_DISABLE_ENCODER |
392 | void speex_bits_insert_terminator(SpeexBits *bits) | 393 | EXPORT void speex_bits_insert_terminator(SpeexBits *bits) |
393 | { | 394 | { |
394 | if (bits->bitPtr) | 395 | if (bits->bitPtr) |
395 | speex_bits_pack(bits, 0, 1); | 396 | speex_bits_pack(bits, 0, 1); |
diff --git a/lib/rbcodec/codecs/libspeex/config-speex.h b/lib/rbcodec/codecs/libspeex/config-speex.h index 7e0672c150..d6d3b23a0a 100644 --- a/lib/rbcodec/codecs/libspeex/config-speex.h +++ b/lib/rbcodec/codecs/libspeex/config-speex.h | |||
@@ -1,5 +1,5 @@ | |||
1 | #ifndef ROCKBOX_VOICE_ENCODER | 1 | #ifndef ROCKBOX_VOICE_ENCODER |
2 | #include "codeclib.h" | 2 | #include "codeclib.h" |
3 | #include "autoconf.h" | 3 | #include "autoconf.h" |
4 | #else | 4 | #else |
5 | #define ICODE_ATTR | 5 | #define ICODE_ATTR |
@@ -17,7 +17,11 @@ | |||
17 | 17 | ||
18 | /* Make use of ARM4E assembly optimizations */ | 18 | /* Make use of ARM4E assembly optimizations */ |
19 | #if defined(CPU_ARM) | 19 | #if defined(CPU_ARM) |
20 | #if (ARM_ARCH < 5) | ||
20 | #define ARM4_ASM | 21 | #define ARM4_ASM |
22 | #else | ||
23 | #define ARM5E_ASM | ||
24 | #endif | ||
21 | #endif | 25 | #endif |
22 | 26 | ||
23 | /* Make use of Coldfire assembly optimizations */ | 27 | /* Make use of Coldfire assembly optimizations */ |
@@ -40,10 +44,10 @@ | |||
40 | 44 | ||
41 | #ifndef ROCKBOX_VOICE_ENCODER | 45 | #ifndef ROCKBOX_VOICE_ENCODER |
42 | /* Compile target codec as fixed point */ | 46 | /* Compile target codec as fixed point */ |
43 | #define FIXED_POINT | 47 | #define FIXED_POINT |
44 | #else | 48 | #else |
45 | /* Compile voice clip encoder as floating point */ | 49 | /* Compile voice clip encoder as floating point */ |
46 | #define FLOATING_POINT | 50 | #define FLOATING_POINT |
47 | #endif | 51 | #endif |
48 | 52 | ||
49 | #ifndef ROCKBOX_VOICE_CODEC | 53 | #ifndef ROCKBOX_VOICE_CODEC |
@@ -137,13 +141,13 @@ | |||
137 | #define SPEEX_MAJOR_VERSION 1 | 141 | #define SPEEX_MAJOR_VERSION 1 |
138 | 142 | ||
139 | /* Version micro */ | 143 | /* Version micro */ |
140 | #define SPEEX_MICRO_VERSION 15 | 144 | #define SPEEX_MICRO_VERSION 16 |
141 | 145 | ||
142 | /* Version minor */ | 146 | /* Version minor */ |
143 | #define SPEEX_MINOR_VERSION 1 | 147 | #define SPEEX_MINOR_VERSION 1 |
144 | 148 | ||
145 | /* Complete version string */ | 149 | /* Complete version string */ |
146 | #define SPEEX_VERSION "1.2beta3" | 150 | #define SPEEX_VERSION "1.2rc1" |
147 | 151 | ||
148 | /* Define to 1 if you have the ANSI C header files. */ | 152 | /* Define to 1 if you have the ANSI C header files. */ |
149 | #define STDC_HEADERS 1 | 153 | #define STDC_HEADERS 1 |
@@ -155,7 +159,7 @@ | |||
155 | /* #undef USE_ALLOCA */ | 159 | /* #undef USE_ALLOCA */ |
156 | 160 | ||
157 | /* Use C99 variable-size arrays */ | 161 | /* Use C99 variable-size arrays */ |
158 | #define VAR_ARRAYS | 162 | #define VAR_ARRAYS |
159 | 163 | ||
160 | /* Enable Vorbis-style psychoacoustics (EXPERIMENTAL) */ | 164 | /* Enable Vorbis-style psychoacoustics (EXPERIMENTAL) */ |
161 | /* #undef VORBIS_PSYCHO */ | 165 | /* #undef VORBIS_PSYCHO */ |
@@ -184,3 +188,7 @@ | |||
184 | 188 | ||
185 | #define RELEASE 1 | 189 | #define RELEASE 1 |
186 | 190 | ||
191 | /* We don't care */ | ||
192 | #define EXPORT | ||
193 | |||
194 | #define USE_KISS_FFT | ||
diff --git a/lib/rbcodec/codecs/libspeex/fftwrap.c b/lib/rbcodec/codecs/libspeex/fftwrap.c index 2312f755d6..b849e74f7c 100644 --- a/lib/rbcodec/codecs/libspeex/fftwrap.c +++ b/lib/rbcodec/codecs/libspeex/fftwrap.c | |||
@@ -1,23 +1,23 @@ | |||
1 | /* Copyright (C) 2005-2006 Jean-Marc Valin | 1 | /* Copyright (C) 2005-2006 Jean-Marc Valin |
2 | File: fftwrap.c | 2 | File: fftwrap.c |
3 | 3 | ||
4 | Wrapper for various FFTs | 4 | Wrapper for various FFTs |
5 | 5 | ||
6 | Redistribution and use in source and binary forms, with or without | 6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions | 7 | modification, are permitted provided that the following conditions |
8 | are met: | 8 | are met: |
9 | 9 | ||
10 | - Redistributions of source code must retain the above copyright | 10 | - Redistributions of source code must retain the above copyright |
11 | notice, this list of conditions and the following disclaimer. | 11 | notice, this list of conditions and the following disclaimer. |
12 | 12 | ||
13 | - Redistributions in binary form must reproduce the above copyright | 13 | - Redistributions in binary form must reproduce the above copyright |
14 | notice, this list of conditions and the following disclaimer in the | 14 | notice, this list of conditions and the following disclaimer in the |
15 | documentation and/or other materials provided with the distribution. | 15 | documentation and/or other materials provided with the distribution. |
16 | 16 | ||
17 | - Neither the name of the Xiph.org Foundation nor the names of its | 17 | - Neither the name of the Xiph.org Foundation nor the names of its |
18 | contributors may be used to endorse or promote products derived from | 18 | contributors may be used to endorse or promote products derived from |
19 | this software without specific prior written permission. | 19 | this software without specific prior written permission. |
20 | 20 | ||
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
22 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 22 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
@@ -36,10 +36,6 @@ | |||
36 | #include "config-speex.h" | 36 | #include "config-speex.h" |
37 | #endif | 37 | #endif |
38 | 38 | ||
39 | /*#define USE_SMALLFT*/ | ||
40 | #define USE_KISS_FFT | ||
41 | |||
42 | |||
43 | #include "arch.h" | 39 | #include "arch.h" |
44 | #include "os_support.h" | 40 | #include "os_support.h" |
45 | 41 | ||
@@ -66,7 +62,7 @@ static int maximize_range(spx_word16_t *in, spx_word16_t *out, spx_word16_t boun | |||
66 | for (i=0;i<len;i++) | 62 | for (i=0;i<len;i++) |
67 | { | 63 | { |
68 | out[i] = SHL16(in[i], shift); | 64 | out[i] = SHL16(in[i], shift); |
69 | } | 65 | } |
70 | return shift; | 66 | return shift; |
71 | } | 67 | } |
72 | 68 | ||
@@ -130,6 +126,119 @@ void spx_ifft(void *table, float *in, float *out) | |||
130 | spx_drft_backward((struct drft_lookup *)table, out); | 126 | spx_drft_backward((struct drft_lookup *)table, out); |
131 | } | 127 | } |
132 | 128 | ||
129 | #elif defined(USE_INTEL_MKL) | ||
130 | #include <mkl.h> | ||
131 | |||
132 | struct mkl_config { | ||
133 | DFTI_DESCRIPTOR_HANDLE desc; | ||
134 | int N; | ||
135 | }; | ||
136 | |||
137 | void *spx_fft_init(int size) | ||
138 | { | ||
139 | struct mkl_config *table = (struct mkl_config *) speex_alloc(sizeof(struct mkl_config)); | ||
140 | table->N = size; | ||
141 | DftiCreateDescriptor(&table->desc, DFTI_SINGLE, DFTI_REAL, 1, size); | ||
142 | DftiSetValue(table->desc, DFTI_PACKED_FORMAT, DFTI_PACK_FORMAT); | ||
143 | DftiSetValue(table->desc, DFTI_PLACEMENT, DFTI_NOT_INPLACE); | ||
144 | DftiSetValue(table->desc, DFTI_FORWARD_SCALE, 1.0f / size); | ||
145 | DftiCommitDescriptor(table->desc); | ||
146 | return table; | ||
147 | } | ||
148 | |||
149 | void spx_fft_destroy(void *table) | ||
150 | { | ||
151 | struct mkl_config *t = (struct mkl_config *) table; | ||
152 | DftiFreeDescriptor(t->desc); | ||
153 | speex_free(table); | ||
154 | } | ||
155 | |||
156 | void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) | ||
157 | { | ||
158 | struct mkl_config *t = (struct mkl_config *) table; | ||
159 | DftiComputeForward(t->desc, in, out); | ||
160 | } | ||
161 | |||
162 | void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out) | ||
163 | { | ||
164 | struct mkl_config *t = (struct mkl_config *) table; | ||
165 | DftiComputeBackward(t->desc, in, out); | ||
166 | } | ||
167 | |||
168 | #elif defined(USE_GPL_FFTW3) | ||
169 | |||
170 | #include <fftw3.h> | ||
171 | |||
172 | struct fftw_config { | ||
173 | float *in; | ||
174 | float *out; | ||
175 | fftwf_plan fft; | ||
176 | fftwf_plan ifft; | ||
177 | int N; | ||
178 | }; | ||
179 | |||
180 | void *spx_fft_init(int size) | ||
181 | { | ||
182 | struct fftw_config *table = (struct fftw_config *) speex_alloc(sizeof(struct fftw_config)); | ||
183 | table->in = fftwf_malloc(sizeof(float) * (size+2)); | ||
184 | table->out = fftwf_malloc(sizeof(float) * (size+2)); | ||
185 | |||
186 | table->fft = fftwf_plan_dft_r2c_1d(size, table->in, (fftwf_complex *) table->out, FFTW_PATIENT); | ||
187 | table->ifft = fftwf_plan_dft_c2r_1d(size, (fftwf_complex *) table->in, table->out, FFTW_PATIENT); | ||
188 | |||
189 | table->N = size; | ||
190 | return table; | ||
191 | } | ||
192 | |||
193 | void spx_fft_destroy(void *table) | ||
194 | { | ||
195 | struct fftw_config *t = (struct fftw_config *) table; | ||
196 | fftwf_destroy_plan(t->fft); | ||
197 | fftwf_destroy_plan(t->ifft); | ||
198 | fftwf_free(t->in); | ||
199 | fftwf_free(t->out); | ||
200 | speex_free(table); | ||
201 | } | ||
202 | |||
203 | |||
204 | void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) | ||
205 | { | ||
206 | int i; | ||
207 | struct fftw_config *t = (struct fftw_config *) table; | ||
208 | const int N = t->N; | ||
209 | float *iptr = t->in; | ||
210 | float *optr = t->out; | ||
211 | const float m = 1.0 / N; | ||
212 | for(i=0;i<N;++i) | ||
213 | iptr[i]=in[i] * m; | ||
214 | |||
215 | fftwf_execute(t->fft); | ||
216 | |||
217 | out[0] = optr[0]; | ||
218 | for(i=1;i<N;++i) | ||
219 | out[i] = optr[i+1]; | ||
220 | } | ||
221 | |||
222 | void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out) | ||
223 | { | ||
224 | int i; | ||
225 | struct fftw_config *t = (struct fftw_config *) table; | ||
226 | const int N = t->N; | ||
227 | float *iptr = t->in; | ||
228 | float *optr = t->out; | ||
229 | |||
230 | iptr[0] = in[0]; | ||
231 | iptr[1] = 0.0f; | ||
232 | for(i=1;i<N;++i) | ||
233 | iptr[i+1] = in[i]; | ||
234 | iptr[N+1] = 0.0f; | ||
235 | |||
236 | fftwf_execute(t->ifft); | ||
237 | |||
238 | for(i=0;i<N;++i) | ||
239 | out[i] = optr[i]; | ||
240 | } | ||
241 | |||
133 | #elif defined(USE_KISS_FFT) | 242 | #elif defined(USE_KISS_FFT) |
134 | 243 | ||
135 | #include "kiss_fftr.h" | 244 | #include "kiss_fftr.h" |
diff --git a/lib/rbcodec/codecs/libspeex/filters_arm4.h b/lib/rbcodec/codecs/libspeex/filters_arm4.h index 18c2a7d448..eb93715b9b 100644 --- a/lib/rbcodec/codecs/libspeex/filters_arm4.h +++ b/lib/rbcodec/codecs/libspeex/filters_arm4.h | |||
@@ -86,7 +86,7 @@ int normalize16(const spx_sig_t *x, spx_word16_t *y, spx_sig_t max_scale, int le | |||
86 | "\tmov %5, %5, asr %3 \n" | 86 | "\tmov %5, %5, asr %3 \n" |
87 | "\tstrh %5, [%1], #2 \n" | 87 | "\tstrh %5, [%1], #2 \n" |
88 | 88 | ||
89 | "\tbge .normalize16loop%=\n" | 89 | "\tbgt .normalize16loop%=\n" |
90 | : "=r" (dead1), "=r" (dead2), "=r" (dead3), "=r" (dead4), | 90 | : "=r" (dead1), "=r" (dead2), "=r" (dead3), "=r" (dead4), |
91 | "=r" (dead5), "=r" (dead6) | 91 | "=r" (dead5), "=r" (dead6) |
92 | : "0" (x), "1" (y), "2" (len>>2), "3" (sig_shift) | 92 | : "0" (x), "1" (y), "2" (len>>2), "3" (sig_shift) |
diff --git a/lib/rbcodec/codecs/libspeex/fixed_debug.h b/lib/rbcodec/codecs/libspeex/fixed_debug.h index d5c449f4d9..4d5fe11113 100644 --- a/lib/rbcodec/codecs/libspeex/fixed_debug.h +++ b/lib/rbcodec/codecs/libspeex/fixed_debug.h | |||
@@ -7,18 +7,18 @@ | |||
7 | Redistribution and use in source and binary forms, with or without | 7 | Redistribution and use in source and binary forms, with or without |
8 | modification, are permitted provided that the following conditions | 8 | modification, are permitted provided that the following conditions |
9 | are met: | 9 | are met: |
10 | 10 | ||
11 | - Redistributions of source code must retain the above copyright | 11 | - Redistributions of source code must retain the above copyright |
12 | notice, this list of conditions and the following disclaimer. | 12 | notice, this list of conditions and the following disclaimer. |
13 | 13 | ||
14 | - Redistributions in binary form must reproduce the above copyright | 14 | - Redistributions in binary form must reproduce the above copyright |
15 | notice, this list of conditions and the following disclaimer in the | 15 | notice, this list of conditions and the following disclaimer in the |
16 | documentation and/or other materials provided with the distribution. | 16 | documentation and/or other materials provided with the distribution. |
17 | 17 | ||
18 | - Neither the name of the Xiph.org Foundation nor the names of its | 18 | - Neither the name of the Xiph.org Foundation nor the names of its |
19 | contributors may be used to endorse or promote products derived from | 19 | contributors may be used to endorse or promote products derived from |
20 | this software without specific prior written permission. | 20 | this software without specific prior written permission. |
21 | 21 | ||
22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
23 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 23 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
24 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 24 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
@@ -101,7 +101,7 @@ static inline int _EXTEND32(int x, char *file, int line) | |||
101 | } | 101 | } |
102 | 102 | ||
103 | #define SHR16(a, shift) _SHR16(a, shift, __FILE__, __LINE__) | 103 | #define SHR16(a, shift) _SHR16(a, shift, __FILE__, __LINE__) |
104 | static inline short _SHR16(int a, int shift, char *file, int line) | 104 | static inline short _SHR16(int a, int shift, char *file, int line) |
105 | { | 105 | { |
106 | int res; | 106 | int res; |
107 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) | 107 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) |
@@ -115,7 +115,7 @@ static inline short _SHR16(int a, int shift, char *file, int line) | |||
115 | return res; | 115 | return res; |
116 | } | 116 | } |
117 | #define SHL16(a, shift) _SHL16(a, shift, __FILE__, __LINE__) | 117 | #define SHL16(a, shift) _SHL16(a, shift, __FILE__, __LINE__) |
118 | static inline short _SHL16(int a, int shift, char *file, int line) | 118 | static inline short _SHL16(int a, int shift, char *file, int line) |
119 | { | 119 | { |
120 | int res; | 120 | int res; |
121 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) | 121 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) |
@@ -129,7 +129,7 @@ static inline short _SHL16(int a, int shift, char *file, int line) | |||
129 | return res; | 129 | return res; |
130 | } | 130 | } |
131 | 131 | ||
132 | static inline int SHR32(long long a, int shift) | 132 | static inline int SHR32(long long a, int shift) |
133 | { | 133 | { |
134 | long long res; | 134 | long long res; |
135 | if (!VERIFY_INT(a) || !VERIFY_SHORT(shift)) | 135 | if (!VERIFY_INT(a) || !VERIFY_SHORT(shift)) |
@@ -144,7 +144,7 @@ static inline int SHR32(long long a, int shift) | |||
144 | spx_mips++; | 144 | spx_mips++; |
145 | return res; | 145 | return res; |
146 | } | 146 | } |
147 | static inline int SHL32(long long a, int shift) | 147 | static inline int SHL32(long long a, int shift) |
148 | { | 148 | { |
149 | long long res; | 149 | long long res; |
150 | if (!VERIFY_INT(a) || !VERIFY_SHORT(shift)) | 150 | if (!VERIFY_INT(a) || !VERIFY_SHORT(shift)) |
@@ -161,7 +161,7 @@ static inline int SHL32(long long a, int shift) | |||
161 | } | 161 | } |
162 | 162 | ||
163 | #define PSHR16(a,shift) (SHR16(ADD16((a),((1<<((shift))>>1))),shift)) | 163 | #define PSHR16(a,shift) (SHR16(ADD16((a),((1<<((shift))>>1))),shift)) |
164 | #define PSHR32(a,shift) (SHR32(ADD32((a),((1<<((shift))>>1))),shift)) | 164 | #define PSHR32(a,shift) (SHR32(ADD32((a),((EXTEND32(1)<<((shift))>>1))),shift)) |
165 | #define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) | 165 | #define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) |
166 | 166 | ||
167 | #define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) | 167 | #define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) |
@@ -171,7 +171,7 @@ static inline int SHL32(long long a, int shift) | |||
171 | //#define SHL(a,shift) ((a) << (shift)) | 171 | //#define SHL(a,shift) ((a) << (shift)) |
172 | 172 | ||
173 | #define ADD16(a, b) _ADD16(a, b, __FILE__, __LINE__) | 173 | #define ADD16(a, b) _ADD16(a, b, __FILE__, __LINE__) |
174 | static inline short _ADD16(int a, int b, char *file, int line) | 174 | static inline short _ADD16(int a, int b, char *file, int line) |
175 | { | 175 | { |
176 | int res; | 176 | int res; |
177 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) | 177 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) |
@@ -188,7 +188,7 @@ static inline short _ADD16(int a, int b, char *file, int line) | |||
188 | } | 188 | } |
189 | 189 | ||
190 | #define SUB16(a, b) _SUB16(a, b, __FILE__, __LINE__) | 190 | #define SUB16(a, b) _SUB16(a, b, __FILE__, __LINE__) |
191 | static inline short _SUB16(int a, int b, char *file, int line) | 191 | static inline short _SUB16(int a, int b, char *file, int line) |
192 | { | 192 | { |
193 | int res; | 193 | int res; |
194 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) | 194 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) |
@@ -203,7 +203,7 @@ static inline short _SUB16(int a, int b, char *file, int line) | |||
203 | } | 203 | } |
204 | 204 | ||
205 | #define ADD32(a, b) _ADD32(a, b, __FILE__, __LINE__) | 205 | #define ADD32(a, b) _ADD32(a, b, __FILE__, __LINE__) |
206 | static inline int _ADD32(long long a, long long b, char *file, int line) | 206 | static inline int _ADD32(long long a, long long b, char *file, int line) |
207 | { | 207 | { |
208 | long long res; | 208 | long long res; |
209 | if (!VERIFY_INT(a) || !VERIFY_INT(b)) | 209 | if (!VERIFY_INT(a) || !VERIFY_INT(b)) |
@@ -219,7 +219,7 @@ static inline int _ADD32(long long a, long long b, char *file, int line) | |||
219 | return res; | 219 | return res; |
220 | } | 220 | } |
221 | 221 | ||
222 | static inline int SUB32(long long a, long long b) | 222 | static inline int SUB32(long long a, long long b) |
223 | { | 223 | { |
224 | long long res; | 224 | long long res; |
225 | if (!VERIFY_INT(a) || !VERIFY_INT(b)) | 225 | if (!VERIFY_INT(a) || !VERIFY_INT(b)) |
@@ -236,7 +236,7 @@ static inline int SUB32(long long a, long long b) | |||
236 | #define ADD64(a,b) (MIPS_INC(a)+(b)) | 236 | #define ADD64(a,b) (MIPS_INC(a)+(b)) |
237 | 237 | ||
238 | /* result fits in 16 bits */ | 238 | /* result fits in 16 bits */ |
239 | static inline short MULT16_16_16(int a, int b) | 239 | static inline short MULT16_16_16(int a, int b) |
240 | { | 240 | { |
241 | int res; | 241 | int res; |
242 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) | 242 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) |
@@ -251,7 +251,7 @@ static inline short MULT16_16_16(int a, int b) | |||
251 | } | 251 | } |
252 | 252 | ||
253 | #define MULT16_16(a, b) _MULT16_16(a, b, __FILE__, __LINE__) | 253 | #define MULT16_16(a, b) _MULT16_16(a, b, __FILE__, __LINE__) |
254 | static inline int _MULT16_16(int a, int b, char *file, int line) | 254 | static inline int _MULT16_16(int a, int b, char *file, int line) |
255 | { | 255 | { |
256 | long long res; | 256 | long long res; |
257 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) | 257 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) |
@@ -279,8 +279,8 @@ static inline int _MULT16_32_QX(int a, long long b, int Q, char *file, int line) | |||
279 | { | 279 | { |
280 | 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); | 280 | 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); |
281 | } | 281 | } |
282 | if (ABS32(b)>=(1<<(15+Q))) | 282 | if (ABS32(b)>=(EXTEND32(1)<<(15+Q))) |
283 | fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); | 283 | fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); |
284 | res = (((long long)a)*(long long)b) >> Q; | 284 | res = (((long long)a)*(long long)b) >> Q; |
285 | if (!VERIFY_INT(res)) | 285 | if (!VERIFY_INT(res)) |
286 | 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); | 286 | 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); |
@@ -295,9 +295,9 @@ static inline int MULT16_32_PX(int a, long long b, int Q) | |||
295 | { | 295 | { |
296 | fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d\n", Q, (int)a, (int)b); | 296 | fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d\n", Q, (int)a, (int)b); |
297 | } | 297 | } |
298 | if (ABS32(b)>=(1<<(15+Q))) | 298 | if (ABS32(b)>=(EXTEND32(1)<<(15+Q))) |
299 | fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b); | 299 | fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b); |
300 | res = ((((long long)a)*(long long)b) + ((1<<Q)>>1))>> Q; | 300 | res = ((((long long)a)*(long long)b) + ((EXTEND32(1)<<Q)>>1))>> Q; |
301 | if (!VERIFY_INT(res)) | 301 | if (!VERIFY_INT(res)) |
302 | fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d\n", Q, (int)a, (int)b,(int)res); | 302 | fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d\n", Q, (int)a, (int)b,(int)res); |
303 | spx_mips+=5; | 303 | spx_mips+=5; |
@@ -323,7 +323,7 @@ static inline int SATURATE(int a, int b) | |||
323 | return a; | 323 | return a; |
324 | } | 324 | } |
325 | 325 | ||
326 | static inline int MULT16_16_Q11_32(int a, int b) | 326 | static inline int MULT16_16_Q11_32(int a, int b) |
327 | { | 327 | { |
328 | long long res; | 328 | long long res; |
329 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) | 329 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) |
@@ -337,7 +337,7 @@ static inline int MULT16_16_Q11_32(int a, int b) | |||
337 | spx_mips+=3; | 337 | spx_mips+=3; |
338 | return res; | 338 | return res; |
339 | } | 339 | } |
340 | static inline short MULT16_16_Q13(int a, int b) | 340 | static inline short MULT16_16_Q13(int a, int b) |
341 | { | 341 | { |
342 | long long res; | 342 | long long res; |
343 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) | 343 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) |
@@ -351,7 +351,7 @@ static inline short MULT16_16_Q13(int a, int b) | |||
351 | spx_mips+=3; | 351 | spx_mips+=3; |
352 | return res; | 352 | return res; |
353 | } | 353 | } |
354 | static inline short MULT16_16_Q14(int a, int b) | 354 | static inline short MULT16_16_Q14(int a, int b) |
355 | { | 355 | { |
356 | long long res; | 356 | long long res; |
357 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) | 357 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) |
@@ -365,7 +365,7 @@ static inline short MULT16_16_Q14(int a, int b) | |||
365 | spx_mips+=3; | 365 | spx_mips+=3; |
366 | return res; | 366 | return res; |
367 | } | 367 | } |
368 | static inline short MULT16_16_Q15(int a, int b) | 368 | static inline short MULT16_16_Q15(int a, int b) |
369 | { | 369 | { |
370 | long long res; | 370 | long long res; |
371 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) | 371 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) |
@@ -382,7 +382,7 @@ static inline short MULT16_16_Q15(int a, int b) | |||
382 | return res; | 382 | return res; |
383 | } | 383 | } |
384 | 384 | ||
385 | static inline short MULT16_16_P13(int a, int b) | 385 | static inline short MULT16_16_P13(int a, int b) |
386 | { | 386 | { |
387 | long long res; | 387 | long long res; |
388 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) | 388 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) |
@@ -399,7 +399,7 @@ static inline short MULT16_16_P13(int a, int b) | |||
399 | spx_mips+=4; | 399 | spx_mips+=4; |
400 | return res; | 400 | return res; |
401 | } | 401 | } |
402 | static inline short MULT16_16_P14(int a, int b) | 402 | static inline short MULT16_16_P14(int a, int b) |
403 | { | 403 | { |
404 | long long res; | 404 | long long res; |
405 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) | 405 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) |
@@ -416,7 +416,7 @@ static inline short MULT16_16_P14(int a, int b) | |||
416 | spx_mips+=4; | 416 | spx_mips+=4; |
417 | return res; | 417 | return res; |
418 | } | 418 | } |
419 | static inline short MULT16_16_P15(int a, int b) | 419 | static inline short MULT16_16_P15(int a, int b) |
420 | { | 420 | { |
421 | long long res; | 421 | long long res; |
422 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) | 422 | if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) |
@@ -436,7 +436,7 @@ static inline short MULT16_16_P15(int a, int b) | |||
436 | 436 | ||
437 | #define DIV32_16(a, b) _DIV32_16(a, b, __FILE__, __LINE__) | 437 | #define DIV32_16(a, b) _DIV32_16(a, b, __FILE__, __LINE__) |
438 | 438 | ||
439 | static inline int _DIV32_16(long long a, long long b, char *file, int line) | 439 | static inline int _DIV32_16(long long a, long long b, char *file, int line) |
440 | { | 440 | { |
441 | long long res; | 441 | long long res; |
442 | if (b==0) | 442 | if (b==0) |
@@ -462,7 +462,7 @@ static inline int _DIV32_16(long long a, long long b, char *file, int line) | |||
462 | } | 462 | } |
463 | 463 | ||
464 | #define DIV32(a, b) _DIV32(a, b, __FILE__, __LINE__) | 464 | #define DIV32(a, b) _DIV32(a, b, __FILE__, __LINE__) |
465 | static inline int _DIV32(long long a, long long b, char *file, int line) | 465 | static inline int _DIV32(long long a, long long b, char *file, int line) |
466 | { | 466 | { |
467 | long long res; | 467 | long long res; |
468 | if (b==0) | 468 | if (b==0) |
diff --git a/lib/rbcodec/codecs/libspeex/fixed_generic.h b/lib/rbcodec/codecs/libspeex/fixed_generic.h index 2948177c0b..3fb096ed90 100644 --- a/lib/rbcodec/codecs/libspeex/fixed_generic.h +++ b/lib/rbcodec/codecs/libspeex/fixed_generic.h | |||
@@ -47,14 +47,14 @@ | |||
47 | #define SHR32(a,shift) ((a) >> (shift)) | 47 | #define SHR32(a,shift) ((a) >> (shift)) |
48 | #define SHL32(a,shift) ((a) << (shift)) | 48 | #define SHL32(a,shift) ((a) << (shift)) |
49 | #define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift)) | 49 | #define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift)) |
50 | #define PSHR32(a,shift) (SHR32((a)+((1<<((shift))>>1)),shift)) | 50 | #define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift)) |
51 | #define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) | 51 | #define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) |
52 | #define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) | 52 | #define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) |
53 | #define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) | 53 | #define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) |
54 | 54 | ||
55 | #define SHR(a,shift) ((a) >> (shift)) | 55 | #define SHR(a,shift) ((a) >> (shift)) |
56 | #define SHL(a,shift) ((spx_word32_t)(a) << (shift)) | 56 | #define SHL(a,shift) ((spx_word32_t)(a) << (shift)) |
57 | #define PSHR(a,shift) (SHR((a)+((1<<((shift))>>1)),shift)) | 57 | #define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift)) |
58 | #define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) | 58 | #define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) |
59 | 59 | ||
60 | 60 | ||
diff --git a/lib/rbcodec/codecs/libspeex/jitter.c b/lib/rbcodec/codecs/libspeex/jitter.c index d9f6c67b86..f4e3bc2be1 100644 --- a/lib/rbcodec/codecs/libspeex/jitter.c +++ b/lib/rbcodec/codecs/libspeex/jitter.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* Copyright (C) 2002 Jean-Marc Valin | 1 | /* Copyright (C) 2002 Jean-Marc Valin |
2 | File: speex_jitter.h | 2 | File: speex_jitter.h |
3 | 3 | ||
4 | Adaptive jitter buffer for Speex | 4 | Adaptive jitter buffer for Speex |
@@ -6,18 +6,18 @@ | |||
6 | Redistribution and use in source and binary forms, with or without | 6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions | 7 | modification, are permitted provided that the following conditions |
8 | are met: | 8 | are met: |
9 | 9 | ||
10 | - Redistributions of source code must retain the above copyright | 10 | - Redistributions of source code must retain the above copyright |
11 | notice, this list of conditions and the following disclaimer. | 11 | notice, this list of conditions and the following disclaimer. |
12 | 12 | ||
13 | - Redistributions in binary form must reproduce the above copyright | 13 | - Redistributions in binary form must reproduce the above copyright |
14 | notice, this list of conditions and the following disclaimer in the | 14 | notice, this list of conditions and the following disclaimer in the |
15 | documentation and/or other materials provided with the distribution. | 15 | documentation and/or other materials provided with the distribution. |
16 | 16 | ||
17 | - Neither the name of the Xiph.org Foundation nor the names of its | 17 | - Neither the name of the Xiph.org Foundation nor the names of its |
18 | contributors may be used to endorse or promote products derived from | 18 | contributors may be used to endorse or promote products derived from |
19 | this software without specific prior written permission. | 19 | this software without specific prior written permission. |
20 | 20 | ||
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
22 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 22 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
@@ -73,17 +73,17 @@ TODO: | |||
73 | #define LT32(a,b) (((spx_int32_t)((a)-(b)))<0) | 73 | #define LT32(a,b) (((spx_int32_t)((a)-(b)))<0) |
74 | #define LE32(a,b) (((spx_int32_t)((a)-(b)))<=0) | 74 | #define LE32(a,b) (((spx_int32_t)((a)-(b)))<=0) |
75 | 75 | ||
76 | #define ROUND_DOWN(x, step) ((x)<0 ? ((x)-(step)+1)/(step)*(step) : (x)/(step)*(step)) | 76 | #define ROUND_DOWN(x, step) ((x)<0 ? ((x)-(step)+1)/(step)*(step) : (x)/(step)*(step)) |
77 | 77 | ||
78 | #define MAX_TIMINGS 20 | 78 | #define MAX_TIMINGS 40 |
79 | #define MAX_BUFFERS 3 | 79 | #define MAX_BUFFERS 3 |
80 | #define TOP_DELAY 20 | 80 | #define TOP_DELAY 40 |
81 | 81 | ||
82 | /** Buffer that keeps the time of arrival of the latest packets */ | 82 | /** Buffer that keeps the time of arrival of the latest packets */ |
83 | struct TimingBuffer { | 83 | struct TimingBuffer { |
84 | int filled; /**< Number of entries occupied in "timing" and "counts"*/ | 84 | int filled; /**< Number of entries occupied in "timing" and "counts"*/ |
85 | int curr_count; /**< Number of packet timings we got (including those we discarded) */ | 85 | int curr_count; /**< Number of packet timings we got (including those we discarded) */ |
86 | spx_int16_t timing[MAX_TIMINGS]; /**< Sorted list of all timings ("latest" packets first) */ | 86 | spx_int32_t timing[MAX_TIMINGS]; /**< Sorted list of all timings ("latest" packets first) */ |
87 | spx_int16_t counts[MAX_TIMINGS]; /**< Order the packets were put in (will be used for short-term estimate) */ | 87 | spx_int16_t counts[MAX_TIMINGS]; /**< Order the packets were put in (will be used for short-term estimate) */ |
88 | }; | 88 | }; |
89 | 89 | ||
@@ -103,7 +103,7 @@ static void tb_add(struct TimingBuffer *tb, spx_int16_t timing) | |||
103 | tb->curr_count++; | 103 | tb->curr_count++; |
104 | return; | 104 | return; |
105 | } | 105 | } |
106 | 106 | ||
107 | /* Find where the timing info goes in the sorted list */ | 107 | /* Find where the timing info goes in the sorted list */ |
108 | pos = 0; | 108 | pos = 0; |
109 | /* FIXME: Do bisection instead of linear search */ | 109 | /* FIXME: Do bisection instead of linear search */ |
@@ -111,9 +111,9 @@ static void tb_add(struct TimingBuffer *tb, spx_int16_t timing) | |||
111 | { | 111 | { |
112 | pos++; | 112 | pos++; |
113 | } | 113 | } |
114 | 114 | ||
115 | speex_assert(pos <= tb->filled && pos < MAX_TIMINGS); | 115 | speex_assert(pos <= tb->filled && pos < MAX_TIMINGS); |
116 | 116 | ||
117 | /* Shift everything so we can perform the insertion */ | 117 | /* Shift everything so we can perform the insertion */ |
118 | if (pos < tb->filled) | 118 | if (pos < tb->filled) |
119 | { | 119 | { |
@@ -126,7 +126,7 @@ static void tb_add(struct TimingBuffer *tb, spx_int16_t timing) | |||
126 | /* Insert */ | 126 | /* Insert */ |
127 | tb->timing[pos] = timing; | 127 | tb->timing[pos] = timing; |
128 | tb->counts[pos] = tb->curr_count; | 128 | tb->counts[pos] = tb->curr_count; |
129 | 129 | ||
130 | tb->curr_count++; | 130 | tb->curr_count++; |
131 | if (tb->filled<MAX_TIMINGS) | 131 | if (tb->filled<MAX_TIMINGS) |
132 | tb->filled++; | 132 | tb->filled++; |
@@ -139,12 +139,12 @@ struct JitterBuffer_ { | |||
139 | spx_uint32_t pointer_timestamp; /**< Timestamp of what we will *get* next */ | 139 | spx_uint32_t pointer_timestamp; /**< Timestamp of what we will *get* next */ |
140 | spx_uint32_t last_returned_timestamp; /**< Useful for getting the next packet with the same timestamp (for fragmented media) */ | 140 | spx_uint32_t last_returned_timestamp; /**< Useful for getting the next packet with the same timestamp (for fragmented media) */ |
141 | spx_uint32_t next_stop; /**< Estimated time the next get() will be called */ | 141 | spx_uint32_t next_stop; /**< Estimated time the next get() will be called */ |
142 | 142 | ||
143 | spx_int32_t buffered; /**< Amount of data we think is still buffered by the application (timestamp units)*/ | 143 | spx_int32_t buffered; /**< Amount of data we think is still buffered by the application (timestamp units)*/ |
144 | 144 | ||
145 | JitterBufferPacket packets[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packets stored in the buffer */ | 145 | JitterBufferPacket packets[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packets stored in the buffer */ |
146 | spx_uint32_t arrival[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packet arrival time (0 means it was late, even though it's a valid timestamp) */ | 146 | spx_uint32_t arrival[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packet arrival time (0 means it was late, even though it's a valid timestamp) */ |
147 | 147 | ||
148 | void (*destroy) (void *); /**< Callback for destroying a packet */ | 148 | void (*destroy) (void *); /**< Callback for destroying a packet */ |
149 | 149 | ||
150 | spx_int32_t delay_step; /**< Size of the steps when adjusting buffering (timestamp units) */ | 150 | spx_int32_t delay_step; /**< Size of the steps when adjusting buffering (timestamp units) */ |
@@ -154,7 +154,7 @@ struct JitterBuffer_ { | |||
154 | int late_cutoff; /**< How late must a packet be for it not to be considered at all */ | 154 | int late_cutoff; /**< How late must a packet be for it not to be considered at all */ |
155 | int interp_requested; /**< An interpolation is requested by speex_jitter_update_delay() */ | 155 | int interp_requested; /**< An interpolation is requested by speex_jitter_update_delay() */ |
156 | int auto_adjust; /**< Whether to automatically adjust the delay at any time */ | 156 | int auto_adjust; /**< Whether to automatically adjust the delay at any time */ |
157 | 157 | ||
158 | struct TimingBuffer _tb[MAX_BUFFERS]; /**< Don't use those directly */ | 158 | struct TimingBuffer _tb[MAX_BUFFERS]; /**< Don't use those directly */ |
159 | struct TimingBuffer *timeBuffers[MAX_BUFFERS]; /**< Storing arrival time of latest frames so we can compute some stats */ | 159 | struct TimingBuffer *timeBuffers[MAX_BUFFERS]; /**< Storing arrival time of latest frames so we can compute some stats */ |
160 | int window_size; /**< Total window over which the late frames are counted */ | 160 | int window_size; /**< Total window over which the late frames are counted */ |
@@ -162,15 +162,15 @@ struct JitterBuffer_ { | |||
162 | int max_late_rate; /**< Absolute maximum amount of late packets tolerable (in percent) */ | 162 | int max_late_rate; /**< Absolute maximum amount of late packets tolerable (in percent) */ |
163 | int latency_tradeoff; /**< Latency equivalent of losing one percent of packets */ | 163 | int latency_tradeoff; /**< Latency equivalent of losing one percent of packets */ |
164 | int auto_tradeoff; /**< Latency equivalent of losing one percent of packets (automatic default) */ | 164 | int auto_tradeoff; /**< Latency equivalent of losing one percent of packets (automatic default) */ |
165 | 165 | ||
166 | int lost_count; /**< Number of consecutive lost packets */ | 166 | int lost_count; /**< Number of consecutive lost packets */ |
167 | }; | 167 | }; |
168 | 168 | ||
169 | /** Based on available data, this computes the optimal delay for the jitter buffer. | 169 | /** Based on available data, this computes the optimal delay for the jitter buffer. |
170 | The optimised function is in timestamp units and is: | 170 | The optimised function is in timestamp units and is: |
171 | cost = delay + late_factor*[number of frames that would be late if we used that delay] | 171 | cost = delay + late_factor*[number of frames that would be late if we used that delay] |
172 | @param tb Array of buffers | 172 | @param tb Array of buffers |
173 | @param late_factor Equivalent cost of a late frame (in timestamp units) | 173 | @param late_factor Equivalent cost of a late frame (in timestamp units) |
174 | */ | 174 | */ |
175 | static spx_int16_t compute_opt_delay(JitterBuffer *jitter) | 175 | static spx_int16_t compute_opt_delay(JitterBuffer *jitter) |
176 | { | 176 | { |
@@ -186,27 +186,27 @@ static spx_int16_t compute_opt_delay(JitterBuffer *jitter) | |||
186 | int worst = 0; | 186 | int worst = 0; |
187 | spx_int32_t deltaT; | 187 | spx_int32_t deltaT; |
188 | struct TimingBuffer *tb; | 188 | struct TimingBuffer *tb; |
189 | 189 | ||
190 | tb = jitter->_tb; | 190 | tb = jitter->_tb; |
191 | 191 | ||
192 | /* Number of packet timings we have received (including those we didn't keep) */ | 192 | /* Number of packet timings we have received (including those we didn't keep) */ |
193 | tot_count = 0; | 193 | tot_count = 0; |
194 | for (i=0;i<MAX_BUFFERS;i++) | 194 | for (i=0;i<MAX_BUFFERS;i++) |
195 | tot_count += tb[i].curr_count; | 195 | tot_count += tb[i].curr_count; |
196 | if (tot_count==0) | 196 | if (tot_count==0) |
197 | return 0; | 197 | return 0; |
198 | 198 | ||
199 | /* Compute cost for one lost packet */ | 199 | /* Compute cost for one lost packet */ |
200 | if (jitter->latency_tradeoff != 0) | 200 | if (jitter->latency_tradeoff != 0) |
201 | late_factor = jitter->latency_tradeoff * 100.0f / tot_count; | 201 | late_factor = jitter->latency_tradeoff * 100.0f / tot_count; |
202 | else | 202 | else |
203 | late_factor = jitter->auto_tradeoff * jitter->window_size/tot_count; | 203 | late_factor = jitter->auto_tradeoff * jitter->window_size/tot_count; |
204 | 204 | ||
205 | /*fprintf(stderr, "late_factor = %f\n", late_factor);*/ | 205 | /*fprintf(stderr, "late_factor = %f\n", late_factor);*/ |
206 | for (i=0;i<MAX_BUFFERS;i++) | 206 | for (i=0;i<MAX_BUFFERS;i++) |
207 | pos[i] = 0; | 207 | pos[i] = 0; |
208 | 208 | ||
209 | /* Pick the TOP_DELAY "latest" packets (doesn't need to actually be late | 209 | /* Pick the TOP_DELAY "latest" packets (doesn't need to actually be late |
210 | for the current settings) */ | 210 | for the current settings) */ |
211 | for (i=0;i<TOP_DELAY;i++) | 211 | for (i=0;i<TOP_DELAY;i++) |
212 | { | 212 | { |
@@ -225,13 +225,13 @@ static spx_int16_t compute_opt_delay(JitterBuffer *jitter) | |||
225 | if (next != -1) | 225 | if (next != -1) |
226 | { | 226 | { |
227 | spx_int32_t cost; | 227 | spx_int32_t cost; |
228 | 228 | ||
229 | if (i==0) | 229 | if (i==0) |
230 | worst = latest; | 230 | worst = latest; |
231 | best = latest; | 231 | best = latest; |
232 | latest = ROUND_DOWN(latest, jitter->delay_step); | 232 | latest = ROUND_DOWN(latest, jitter->delay_step); |
233 | pos[next]++; | 233 | pos[next]++; |
234 | 234 | ||
235 | /* Actual cost function that tells us how bad using this delay would be */ | 235 | /* Actual cost function that tells us how bad using this delay would be */ |
236 | cost = -latest + late_factor*late; | 236 | cost = -latest + late_factor*late; |
237 | /*fprintf(stderr, "cost %d = %d + %f * %d\n", cost, -latest, late_factor, late);*/ | 237 | /*fprintf(stderr, "cost %d = %d + %f * %d\n", cost, -latest, late_factor, late);*/ |
@@ -243,24 +243,24 @@ static spx_int16_t compute_opt_delay(JitterBuffer *jitter) | |||
243 | } else { | 243 | } else { |
244 | break; | 244 | break; |
245 | } | 245 | } |
246 | 246 | ||
247 | /* For the next timing we will consider, there will be one more late packet to count */ | 247 | /* For the next timing we will consider, there will be one more late packet to count */ |
248 | late++; | 248 | late++; |
249 | /* Two-frame penalty if we're going to increase the amount of late frames (hysteresis) */ | 249 | /* Two-frame penalty if we're going to increase the amount of late frames (hysteresis) */ |
250 | if (latest >= 0 && !penalty_taken) | 250 | if (latest >= 0 && !penalty_taken) |
251 | { | 251 | { |
252 | penalty_taken = 1; | 252 | penalty_taken = 1; |
253 | late+=2; | 253 | late+=4; |
254 | } | 254 | } |
255 | } | 255 | } |
256 | 256 | ||
257 | deltaT = best-worst; | 257 | deltaT = best-worst; |
258 | /* This is a default "automatic latency tradeoff" when none is provided */ | 258 | /* This is a default "automatic latency tradeoff" when none is provided */ |
259 | jitter->auto_tradeoff = 1 + deltaT/TOP_DELAY; | 259 | jitter->auto_tradeoff = 1 + deltaT/TOP_DELAY; |
260 | /*fprintf(stderr, "auto_tradeoff = %d (%d %d %d)\n", jitter->auto_tradeoff, best, worst, i);*/ | 260 | /*fprintf(stderr, "auto_tradeoff = %d (%d %d %d)\n", jitter->auto_tradeoff, best, worst, i);*/ |
261 | 261 | ||
262 | /* FIXME: Compute a short-term estimate too and combine with the long-term one */ | 262 | /* FIXME: Compute a short-term estimate too and combine with the long-term one */ |
263 | 263 | ||
264 | /* Prevents reducing the buffer size when we haven't really had much data */ | 264 | /* Prevents reducing the buffer size when we haven't really had much data */ |
265 | if (tot_count < TOP_DELAY && opt > 0) | 265 | if (tot_count < TOP_DELAY && opt > 0) |
266 | return 0; | 266 | return 0; |
@@ -269,7 +269,7 @@ static spx_int16_t compute_opt_delay(JitterBuffer *jitter) | |||
269 | 269 | ||
270 | 270 | ||
271 | /** Initialise jitter buffer */ | 271 | /** Initialise jitter buffer */ |
272 | JitterBuffer *jitter_buffer_init(int step_size) | 272 | EXPORT JitterBuffer *jitter_buffer_init(int step_size) |
273 | { | 273 | { |
274 | JitterBuffer *jitter = (JitterBuffer*)speex_alloc(sizeof(JitterBuffer)); | 274 | JitterBuffer *jitter = (JitterBuffer*)speex_alloc(sizeof(JitterBuffer)); |
275 | if (jitter) | 275 | if (jitter) |
@@ -294,7 +294,7 @@ JitterBuffer *jitter_buffer_init(int step_size) | |||
294 | } | 294 | } |
295 | 295 | ||
296 | /** Reset jitter buffer */ | 296 | /** Reset jitter buffer */ |
297 | void jitter_buffer_reset(JitterBuffer *jitter) | 297 | EXPORT void jitter_buffer_reset(JitterBuffer *jitter) |
298 | { | 298 | { |
299 | int i; | 299 | int i; |
300 | for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) | 300 | for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) |
@@ -315,7 +315,7 @@ void jitter_buffer_reset(JitterBuffer *jitter) | |||
315 | jitter->lost_count = 0; | 315 | jitter->lost_count = 0; |
316 | jitter->buffered = 0; | 316 | jitter->buffered = 0; |
317 | jitter->auto_tradeoff = 32000; | 317 | jitter->auto_tradeoff = 32000; |
318 | 318 | ||
319 | for (i=0;i<MAX_BUFFERS;i++) | 319 | for (i=0;i<MAX_BUFFERS;i++) |
320 | { | 320 | { |
321 | tb_init(&jitter->_tb[i]); | 321 | tb_init(&jitter->_tb[i]); |
@@ -325,7 +325,7 @@ void jitter_buffer_reset(JitterBuffer *jitter) | |||
325 | } | 325 | } |
326 | 326 | ||
327 | /** Destroy jitter buffer */ | 327 | /** Destroy jitter buffer */ |
328 | void jitter_buffer_destroy(JitterBuffer *jitter) | 328 | EXPORT void jitter_buffer_destroy(JitterBuffer *jitter) |
329 | { | 329 | { |
330 | jitter_buffer_reset(jitter); | 330 | jitter_buffer_reset(jitter); |
331 | speex_free(jitter); | 331 | speex_free(jitter); |
@@ -365,12 +365,12 @@ static void shift_timings(JitterBuffer *jitter, spx_int16_t amount) | |||
365 | 365 | ||
366 | 366 | ||
367 | /** Put one packet into the jitter buffer */ | 367 | /** Put one packet into the jitter buffer */ |
368 | void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) | 368 | EXPORT void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) |
369 | { | 369 | { |
370 | int i,j; | 370 | int i,j; |
371 | int late; | 371 | int late; |
372 | /*fprintf (stderr, "put packet %d %d\n", timestamp, span);*/ | 372 | /*fprintf (stderr, "put packet %d %d\n", timestamp, span);*/ |
373 | 373 | ||
374 | /* Cleanup buffer (remove old packets that weren't played) */ | 374 | /* Cleanup buffer (remove old packets that weren't played) */ |
375 | if (!jitter->reset_state) | 375 | if (!jitter->reset_state) |
376 | { | 376 | { |
@@ -388,7 +388,7 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) | |||
388 | } | 388 | } |
389 | } | 389 | } |
390 | } | 390 | } |
391 | 391 | ||
392 | /*fprintf(stderr, "arrival: %d %d %d\n", packet->timestamp, jitter->next_stop, jitter->pointer_timestamp);*/ | 392 | /*fprintf(stderr, "arrival: %d %d %d\n", packet->timestamp, jitter->next_stop, jitter->pointer_timestamp);*/ |
393 | /* Check if packet is late (could still be useful though) */ | 393 | /* Check if packet is late (could still be useful though) */ |
394 | if (!jitter->reset_state && LT32(packet->timestamp, jitter->next_stop)) | 394 | if (!jitter->reset_state && LT32(packet->timestamp, jitter->next_stop)) |
@@ -398,7 +398,14 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) | |||
398 | } else { | 398 | } else { |
399 | late = 0; | 399 | late = 0; |
400 | } | 400 | } |
401 | 401 | ||
402 | /* For some reason, the consumer has failed the last 20 fetches. Make sure this packet is | ||
403 | * used to resync. */ | ||
404 | if (jitter->lost_count>20) | ||
405 | { | ||
406 | jitter_buffer_reset(jitter); | ||
407 | } | ||
408 | |||
402 | /* Only insert the packet if it's not hopelessly late (i.e. totally useless) */ | 409 | /* Only insert the packet if it's not hopelessly late (i.e. totally useless) */ |
403 | if (jitter->reset_state || GE32(packet->timestamp+packet->span+jitter->delay_step, jitter->pointer_timestamp)) | 410 | if (jitter->reset_state || GE32(packet->timestamp+packet->span+jitter->delay_step, jitter->pointer_timestamp)) |
404 | { | 411 | { |
@@ -409,7 +416,7 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) | |||
409 | if (jitter->packets[i].data==NULL) | 416 | if (jitter->packets[i].data==NULL) |
410 | break; | 417 | break; |
411 | } | 418 | } |
412 | 419 | ||
413 | /*No place left in the buffer, need to make room for it by discarding the oldest packet */ | 420 | /*No place left in the buffer, need to make room for it by discarding the oldest packet */ |
414 | if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) | 421 | if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) |
415 | { | 422 | { |
@@ -428,13 +435,9 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) | |||
428 | else | 435 | else |
429 | speex_free(jitter->packets[i].data); | 436 | speex_free(jitter->packets[i].data); |
430 | jitter->packets[i].data=NULL; | 437 | jitter->packets[i].data=NULL; |
431 | if (jitter->lost_count>20) | 438 | /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/ |
432 | { | ||
433 | jitter_buffer_reset(jitter); | ||
434 | } | ||
435 | /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/ | ||
436 | } | 439 | } |
437 | 440 | ||
438 | /* Copy packet in buffer */ | 441 | /* Copy packet in buffer */ |
439 | if (jitter->destroy) | 442 | if (jitter->destroy) |
440 | { | 443 | { |
@@ -454,18 +457,18 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) | |||
454 | else | 457 | else |
455 | jitter->arrival[i] = jitter->next_stop; | 458 | jitter->arrival[i] = jitter->next_stop; |
456 | } | 459 | } |
457 | 460 | ||
458 | 461 | ||
459 | } | 462 | } |
460 | 463 | ||
461 | /** Get one packet from the jitter buffer */ | 464 | /** Get one packet from the jitter buffer */ |
462 | int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset) | 465 | EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset) |
463 | { | 466 | { |
464 | int i; | 467 | int i; |
465 | unsigned int j; | 468 | unsigned int j; |
466 | int incomplete = 0; | 469 | int incomplete = 0; |
467 | spx_int16_t opt; | 470 | spx_int16_t opt; |
468 | 471 | ||
469 | if (start_offset != NULL) | 472 | if (start_offset != NULL) |
470 | *start_offset = 0; | 473 | *start_offset = 0; |
471 | 474 | ||
@@ -485,7 +488,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3 | |||
485 | } | 488 | } |
486 | if (found) | 489 | if (found) |
487 | { | 490 | { |
488 | jitter->reset_state=0; | 491 | jitter->reset_state=0; |
489 | jitter->pointer_timestamp = oldest; | 492 | jitter->pointer_timestamp = oldest; |
490 | jitter->next_stop = oldest; | 493 | jitter->next_stop = oldest; |
491 | } else { | 494 | } else { |
@@ -494,36 +497,36 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3 | |||
494 | return JITTER_BUFFER_MISSING; | 497 | return JITTER_BUFFER_MISSING; |
495 | } | 498 | } |
496 | } | 499 | } |
497 | 500 | ||
498 | 501 | ||
499 | jitter->last_returned_timestamp = jitter->pointer_timestamp; | 502 | jitter->last_returned_timestamp = jitter->pointer_timestamp; |
500 | 503 | ||
501 | if (jitter->interp_requested != 0) | 504 | if (jitter->interp_requested != 0) |
502 | { | 505 | { |
503 | packet->timestamp = jitter->pointer_timestamp; | 506 | packet->timestamp = jitter->pointer_timestamp; |
504 | packet->span = jitter->interp_requested; | 507 | packet->span = jitter->interp_requested; |
505 | 508 | ||
506 | /* Increment the pointer because it got decremented in the delay update */ | 509 | /* Increment the pointer because it got decremented in the delay update */ |
507 | jitter->pointer_timestamp += jitter->interp_requested; | 510 | jitter->pointer_timestamp += jitter->interp_requested; |
508 | packet->len = 0; | 511 | packet->len = 0; |
509 | /*fprintf (stderr, "Deferred interpolate\n");*/ | 512 | /*fprintf (stderr, "Deferred interpolate\n");*/ |
510 | 513 | ||
511 | jitter->interp_requested = 0; | 514 | jitter->interp_requested = 0; |
512 | 515 | ||
513 | jitter->buffered = packet->span - desired_span; | 516 | jitter->buffered = packet->span - desired_span; |
514 | 517 | ||
515 | return JITTER_BUFFER_INSERTION; | 518 | return JITTER_BUFFER_INSERTION; |
516 | } | 519 | } |
517 | 520 | ||
518 | /* Searching for the packet that fits best */ | 521 | /* Searching for the packet that fits best */ |
519 | 522 | ||
520 | /* Search the buffer for a packet with the right timestamp and spanning the whole current chunk */ | 523 | /* Search the buffer for a packet with the right timestamp and spanning the whole current chunk */ |
521 | for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) | 524 | for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) |
522 | { | 525 | { |
523 | 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)) | 526 | 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)) |
524 | break; | 527 | break; |
525 | } | 528 | } |
526 | 529 | ||
527 | /* If no match, try for an "older" packet that still spans (fully) the current chunk */ | 530 | /* If no match, try for an "older" packet that still spans (fully) the current chunk */ |
528 | if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) | 531 | if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) |
529 | { | 532 | { |
@@ -533,7 +536,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3 | |||
533 | break; | 536 | break; |
534 | } | 537 | } |
535 | } | 538 | } |
536 | 539 | ||
537 | /* If still no match, try for an "older" packet that spans part of the current chunk */ | 540 | /* If still no match, try for an "older" packet that spans part of the current chunk */ |
538 | if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) | 541 | if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) |
539 | { | 542 | { |
@@ -543,7 +546,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3 | |||
543 | break; | 546 | break; |
544 | } | 547 | } |
545 | } | 548 | } |
546 | 549 | ||
547 | /* If still no match, try for earliest packet possible */ | 550 | /* If still no match, try for earliest packet possible */ |
548 | if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) | 551 | if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) |
549 | { | 552 | { |
@@ -577,17 +580,17 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3 | |||
577 | if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE) | 580 | if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE) |
578 | { | 581 | { |
579 | spx_int32_t offset; | 582 | spx_int32_t offset; |
580 | 583 | ||
581 | /* We (obviously) haven't lost this packet */ | 584 | /* We (obviously) haven't lost this packet */ |
582 | jitter->lost_count = 0; | 585 | jitter->lost_count = 0; |
583 | 586 | ||
584 | /* In this case, 0 isn't as a valid timestamp */ | 587 | /* In this case, 0 isn't as a valid timestamp */ |
585 | if (jitter->arrival[i] != 0) | 588 | if (jitter->arrival[i] != 0) |
586 | { | 589 | { |
587 | update_timings(jitter, ((spx_int32_t)jitter->packets[i].timestamp) - ((spx_int32_t)jitter->arrival[i]) - jitter->buffer_margin); | 590 | update_timings(jitter, ((spx_int32_t)jitter->packets[i].timestamp) - ((spx_int32_t)jitter->arrival[i]) - jitter->buffer_margin); |
588 | } | 591 | } |
589 | 592 | ||
590 | 593 | ||
591 | if (jitter->packets[i].len > packet->len) | 594 | if (jitter->packets[i].len > packet->len) |
592 | { | 595 | { |
593 | speex_warning_int("jitter_buffer_get(): packet too large to fit. Size is", jitter->packets[i].len); | 596 | speex_warning_int("jitter_buffer_get(): packet too large to fit. Size is", jitter->packets[i].len); |
@@ -611,10 +614,10 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3 | |||
611 | *start_offset = offset; | 614 | *start_offset = offset; |
612 | else if (offset != 0) | 615 | else if (offset != 0) |
613 | speex_warning_int("jitter_buffer_get() discarding non-zero start_offset", offset); | 616 | speex_warning_int("jitter_buffer_get() discarding non-zero start_offset", offset); |
614 | 617 | ||
615 | packet->timestamp = jitter->packets[i].timestamp; | 618 | packet->timestamp = jitter->packets[i].timestamp; |
616 | jitter->last_returned_timestamp = packet->timestamp; | 619 | jitter->last_returned_timestamp = packet->timestamp; |
617 | 620 | ||
618 | packet->span = jitter->packets[i].span; | 621 | packet->span = jitter->packets[i].span; |
619 | packet->sequence = jitter->packets[i].sequence; | 622 | packet->sequence = jitter->packets[i].sequence; |
620 | packet->user_data = jitter->packets[i].user_data; | 623 | packet->user_data = jitter->packets[i].user_data; |
@@ -622,36 +625,36 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3 | |||
622 | jitter->pointer_timestamp = jitter->packets[i].timestamp+jitter->packets[i].span; | 625 | jitter->pointer_timestamp = jitter->packets[i].timestamp+jitter->packets[i].span; |
623 | 626 | ||
624 | jitter->buffered = packet->span - desired_span; | 627 | jitter->buffered = packet->span - desired_span; |
625 | 628 | ||
626 | if (start_offset != NULL) | 629 | if (start_offset != NULL) |
627 | jitter->buffered += *start_offset; | 630 | jitter->buffered += *start_offset; |
628 | 631 | ||
629 | return JITTER_BUFFER_OK; | 632 | return JITTER_BUFFER_OK; |
630 | } | 633 | } |
631 | 634 | ||
632 | 635 | ||
633 | /* If we haven't found anything worth returning */ | 636 | /* If we haven't found anything worth returning */ |
634 | 637 | ||
635 | /*fprintf (stderr, "not found\n");*/ | 638 | /*fprintf (stderr, "not found\n");*/ |
636 | jitter->lost_count++; | 639 | jitter->lost_count++; |
637 | /*fprintf (stderr, "m");*/ | 640 | /*fprintf (stderr, "m");*/ |
638 | /*fprintf (stderr, "lost_count = %d\n", jitter->lost_count);*/ | 641 | /*fprintf (stderr, "lost_count = %d\n", jitter->lost_count);*/ |
639 | 642 | ||
640 | opt = compute_opt_delay(jitter); | 643 | opt = compute_opt_delay(jitter); |
641 | 644 | ||
642 | /* Should we force an increase in the buffer or just do normal interpolation? */ | 645 | /* Should we force an increase in the buffer or just do normal interpolation? */ |
643 | if (opt < 0) | 646 | if (opt < 0) |
644 | { | 647 | { |
645 | /* Need to increase buffering */ | 648 | /* Need to increase buffering */ |
646 | 649 | ||
647 | /* Shift histogram to compensate */ | 650 | /* Shift histogram to compensate */ |
648 | shift_timings(jitter, -opt); | 651 | shift_timings(jitter, -opt); |
649 | 652 | ||
650 | packet->timestamp = jitter->pointer_timestamp; | 653 | packet->timestamp = jitter->pointer_timestamp; |
651 | packet->span = -opt; | 654 | packet->span = -opt; |
652 | /* Don't move the pointer_timestamp forward */ | 655 | /* Don't move the pointer_timestamp forward */ |
653 | packet->len = 0; | 656 | packet->len = 0; |
654 | 657 | ||
655 | jitter->buffered = packet->span - desired_span; | 658 | jitter->buffered = packet->span - desired_span; |
656 | return JITTER_BUFFER_INSERTION; | 659 | return JITTER_BUFFER_INSERTION; |
657 | /*jitter->pointer_timestamp -= jitter->delay_step;*/ | 660 | /*jitter->pointer_timestamp -= jitter->delay_step;*/ |
@@ -659,12 +662,12 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3 | |||
659 | } else { | 662 | } else { |
660 | /* Normal packet loss */ | 663 | /* Normal packet loss */ |
661 | packet->timestamp = jitter->pointer_timestamp; | 664 | packet->timestamp = jitter->pointer_timestamp; |
662 | 665 | ||
663 | desired_span = ROUND_DOWN(desired_span, jitter->concealment_size); | 666 | desired_span = ROUND_DOWN(desired_span, jitter->concealment_size); |
664 | packet->span = desired_span; | 667 | packet->span = desired_span; |
665 | jitter->pointer_timestamp += desired_span; | 668 | jitter->pointer_timestamp += desired_span; |
666 | packet->len = 0; | 669 | packet->len = 0; |
667 | 670 | ||
668 | jitter->buffered = packet->span - desired_span; | 671 | jitter->buffered = packet->span - desired_span; |
669 | return JITTER_BUFFER_MISSING; | 672 | return JITTER_BUFFER_MISSING; |
670 | /*fprintf (stderr, "Normal loss\n");*/ | 673 | /*fprintf (stderr, "Normal loss\n");*/ |
@@ -673,7 +676,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3 | |||
673 | 676 | ||
674 | } | 677 | } |
675 | 678 | ||
676 | int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet) | 679 | EXPORT int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet) |
677 | { | 680 | { |
678 | int i, j; | 681 | int i, j; |
679 | for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) | 682 | for (i=0;i<SPEEX_JITTER_MAX_BUFFER_SIZE;i++) |
@@ -713,11 +716,11 @@ static int _jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket | |||
713 | { | 716 | { |
714 | spx_int16_t opt = compute_opt_delay(jitter); | 717 | spx_int16_t opt = compute_opt_delay(jitter); |
715 | /*fprintf(stderr, "opt adjustment is %d ", opt);*/ | 718 | /*fprintf(stderr, "opt adjustment is %d ", opt);*/ |
716 | 719 | ||
717 | if (opt < 0) | 720 | if (opt < 0) |
718 | { | 721 | { |
719 | shift_timings(jitter, -opt); | 722 | shift_timings(jitter, -opt); |
720 | 723 | ||
721 | jitter->pointer_timestamp += opt; | 724 | jitter->pointer_timestamp += opt; |
722 | jitter->interp_requested = -opt; | 725 | jitter->interp_requested = -opt; |
723 | /*fprintf (stderr, "Decision to interpolate %d samples\n", -opt);*/ | 726 | /*fprintf (stderr, "Decision to interpolate %d samples\n", -opt);*/ |
@@ -727,14 +730,14 @@ static int _jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket | |||
727 | jitter->pointer_timestamp += opt; | 730 | jitter->pointer_timestamp += opt; |
728 | /*fprintf (stderr, "Decision to drop %d samples\n", opt);*/ | 731 | /*fprintf (stderr, "Decision to drop %d samples\n", opt);*/ |
729 | } | 732 | } |
730 | 733 | ||
731 | return opt; | 734 | return opt; |
732 | } | 735 | } |
733 | 736 | ||
734 | /* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */ | 737 | /* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */ |
735 | int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset) | 738 | EXPORT int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset) |
736 | { | 739 | { |
737 | /* If the programmer calls jitter_buffer_update_delay() directly, | 740 | /* If the programmer calls jitter_buffer_update_delay() directly, |
738 | automatically disable auto-adjustment */ | 741 | automatically disable auto-adjustment */ |
739 | jitter->auto_adjust = 0; | 742 | jitter->auto_adjust = 0; |
740 | 743 | ||
@@ -742,17 +745,17 @@ int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, | |||
742 | } | 745 | } |
743 | 746 | ||
744 | /** Get pointer timestamp of jitter buffer */ | 747 | /** Get pointer timestamp of jitter buffer */ |
745 | int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter) | 748 | EXPORT int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter) |
746 | { | 749 | { |
747 | return jitter->pointer_timestamp; | 750 | return jitter->pointer_timestamp; |
748 | } | 751 | } |
749 | 752 | ||
750 | void jitter_buffer_tick(JitterBuffer *jitter) | 753 | EXPORT void jitter_buffer_tick(JitterBuffer *jitter) |
751 | { | 754 | { |
752 | /* Automatically-adjust the buffering delay if requested */ | 755 | /* Automatically-adjust the buffering delay if requested */ |
753 | if (jitter->auto_adjust) | 756 | if (jitter->auto_adjust) |
754 | _jitter_buffer_update_delay(jitter, NULL, NULL); | 757 | _jitter_buffer_update_delay(jitter, NULL, NULL); |
755 | 758 | ||
756 | if (jitter->buffered >= 0) | 759 | if (jitter->buffered >= 0) |
757 | { | 760 | { |
758 | jitter->next_stop = jitter->pointer_timestamp - jitter->buffered; | 761 | jitter->next_stop = jitter->pointer_timestamp - jitter->buffered; |
@@ -763,12 +766,12 @@ void jitter_buffer_tick(JitterBuffer *jitter) | |||
763 | jitter->buffered = 0; | 766 | jitter->buffered = 0; |
764 | } | 767 | } |
765 | 768 | ||
766 | void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem) | 769 | EXPORT void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem) |
767 | { | 770 | { |
768 | /* Automatically-adjust the buffering delay if requested */ | 771 | /* Automatically-adjust the buffering delay if requested */ |
769 | if (jitter->auto_adjust) | 772 | if (jitter->auto_adjust) |
770 | _jitter_buffer_update_delay(jitter, NULL, NULL); | 773 | _jitter_buffer_update_delay(jitter, NULL, NULL); |
771 | 774 | ||
772 | if (jitter->buffered < 0) | 775 | if (jitter->buffered < 0) |
773 | speex_warning_int("jitter buffer sees negative buffering, your code might be broken. Value is ", jitter->buffered); | 776 | speex_warning_int("jitter buffer sees negative buffering, your code might be broken. Value is ", jitter->buffered); |
774 | jitter->next_stop = jitter->pointer_timestamp - rem; | 777 | jitter->next_stop = jitter->pointer_timestamp - rem; |
@@ -776,7 +779,7 @@ void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem) | |||
776 | 779 | ||
777 | 780 | ||
778 | /* Used like the ioctl function to control the jitter buffer parameters */ | 781 | /* Used like the ioctl function to control the jitter buffer parameters */ |
779 | int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr) | 782 | EXPORT int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr) |
780 | { | 783 | { |
781 | int count, i; | 784 | int count, i; |
782 | switch(request) | 785 | switch(request) |
@@ -836,4 +839,3 @@ int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr) | |||
836 | } | 839 | } |
837 | return 0; | 840 | return 0; |
838 | } | 841 | } |
839 | |||
diff --git a/lib/rbcodec/codecs/libspeex/mdf.c b/lib/rbcodec/codecs/libspeex/mdf.c index 1994f2a886..cfbe4d1284 100644 --- a/lib/rbcodec/codecs/libspeex/mdf.c +++ b/lib/rbcodec/codecs/libspeex/mdf.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* Copyright (C) 2003-2006 Jean-Marc Valin | 1 | /* Copyright (C) 2003-2008 Jean-Marc Valin |
2 | 2 | ||
3 | File: mdf.c | 3 | File: mdf.c |
4 | Echo canceller based on the MDF algorithm (see below) | 4 | Echo canceller based on the MDF algorithm (see below) |
@@ -33,36 +33,36 @@ | |||
33 | /* | 33 | /* |
34 | The echo canceller is based on the MDF algorithm described in: | 34 | The echo canceller is based on the MDF algorithm described in: |
35 | 35 | ||
36 | J. S. Soo, K. K. Pang Multidelay block frequency adaptive filter, | 36 | J. S. Soo, K. K. Pang Multidelay block frequency adaptive filter, |
37 | IEEE Trans. Acoust. Speech Signal Process., Vol. ASSP-38, No. 2, | 37 | IEEE Trans. Acoust. Speech Signal Process., Vol. ASSP-38, No. 2, |
38 | February 1990. | 38 | February 1990. |
39 | 39 | ||
40 | We use the Alternatively Updated MDF (AUMDF) variant. Robustness to | 40 | We use the Alternatively Updated MDF (AUMDF) variant. Robustness to |
41 | double-talk is achieved using a variable learning rate as described in: | 41 | double-talk is achieved using a variable learning rate as described in: |
42 | 42 | ||
43 | Valin, J.-M., On Adjusting the Learning Rate in Frequency Domain Echo | 43 | Valin, J.-M., On Adjusting the Learning Rate in Frequency Domain Echo |
44 | Cancellation With Double-Talk. IEEE Transactions on Audio, | 44 | Cancellation With Double-Talk. IEEE Transactions on Audio, |
45 | Speech and Language Processing, Vol. 15, No. 3, pp. 1030-1034, 2007. | 45 | Speech and Language Processing, Vol. 15, No. 3, pp. 1030-1034, 2007. |
46 | http://people.xiph.org/~jm/papers/valin_taslp2006.pdf | 46 | http://people.xiph.org/~jm/papers/valin_taslp2006.pdf |
47 | 47 | ||
48 | There is no explicit double-talk detection, but a continuous variation | 48 | There is no explicit double-talk detection, but a continuous variation |
49 | in the learning rate based on residual echo, double-talk and background | 49 | in the learning rate based on residual echo, double-talk and background |
50 | noise. | 50 | noise. |
51 | 51 | ||
52 | About the fixed-point version: | 52 | About the fixed-point version: |
53 | All the signals are represented with 16-bit words. The filter weights | 53 | All the signals are represented with 16-bit words. The filter weights |
54 | are represented with 32-bit words, but only the top 16 bits are used | 54 | are represented with 32-bit words, but only the top 16 bits are used |
55 | in most cases. The lower 16 bits are completely unreliable (due to the | 55 | in most cases. The lower 16 bits are completely unreliable (due to the |
56 | fact that the update is done only on the top bits), but help in the | 56 | fact that the update is done only on the top bits), but help in the |
57 | adaptation -- probably by removing a "threshold effect" due to | 57 | adaptation -- probably by removing a "threshold effect" due to |
58 | quantization (rounding going to zero) when the gradient is small. | 58 | quantization (rounding going to zero) when the gradient is small. |
59 | 59 | ||
60 | Another kludge that seems to work good: when performing the weight | 60 | Another kludge that seems to work good: when performing the weight |
61 | update, we only move half the way toward the "goal" this seems to | 61 | update, we only move half the way toward the "goal" this seems to |
62 | reduce the effect of quantization noise in the update phase. This | 62 | reduce the effect of quantization noise in the update phase. This |
63 | can be seen as applying a gradient descent on a "soft constraint" | 63 | can be seen as applying a gradient descent on a "soft constraint" |
64 | instead of having a hard constraint. | 64 | instead of having a hard constraint. |
65 | 65 | ||
66 | */ | 66 | */ |
67 | 67 | ||
68 | #ifdef HAVE_CONFIG_H | 68 | #ifdef HAVE_CONFIG_H |
@@ -88,6 +88,12 @@ | |||
88 | #define WEIGHT_SHIFT 0 | 88 | #define WEIGHT_SHIFT 0 |
89 | #endif | 89 | #endif |
90 | 90 | ||
91 | #ifdef FIXED_POINT | ||
92 | #define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x))) | ||
93 | #else | ||
94 | #define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) | ||
95 | #endif | ||
96 | |||
91 | /* If enabled, the AEC will use a foreground filter and a background filter to be more robust to double-talk | 97 | /* If enabled, the AEC will use a foreground filter and a background filter to be more robust to double-talk |
92 | and difficult signals in general. The cost is an extra FFT and a matrix-vector multiply */ | 98 | and difficult signals in general. The cost is an extra FFT and a matrix-vector multiply */ |
93 | #define TWO_PATH | 99 | #define TWO_PATH |
@@ -131,13 +137,15 @@ struct SpeexEchoState_ { | |||
131 | int adapted; | 137 | int adapted; |
132 | int saturated; | 138 | int saturated; |
133 | int screwed_up; | 139 | int screwed_up; |
140 | int C; /** Number of input channels (microphones) */ | ||
141 | int K; /** Number of output channels (loudspeakers) */ | ||
134 | spx_int32_t sampling_rate; | 142 | spx_int32_t sampling_rate; |
135 | spx_word16_t spec_average; | 143 | spx_word16_t spec_average; |
136 | spx_word16_t beta0; | 144 | spx_word16_t beta0; |
137 | spx_word16_t beta_max; | 145 | spx_word16_t beta_max; |
138 | spx_word32_t sum_adapt; | 146 | spx_word32_t sum_adapt; |
139 | spx_word16_t leak_estimate; | 147 | spx_word16_t leak_estimate; |
140 | 148 | ||
141 | spx_word16_t *e; /* scratch */ | 149 | spx_word16_t *e; /* scratch */ |
142 | spx_word16_t *x; /* Far-end input buffer (2N) */ | 150 | spx_word16_t *x; /* Far-end input buffer (2N) */ |
143 | spx_word16_t *X; /* Far-end buffer (M+1 frames) in frequency domain */ | 151 | spx_word16_t *X; /* Far-end buffer (M+1 frames) in frequency domain */ |
@@ -171,10 +179,10 @@ struct SpeexEchoState_ { | |||
171 | spx_word16_t *window; | 179 | spx_word16_t *window; |
172 | spx_word16_t *prop; | 180 | spx_word16_t *prop; |
173 | void *fft_table; | 181 | void *fft_table; |
174 | spx_word16_t memX, memD, memE; | 182 | spx_word16_t *memX, *memD, *memE; |
175 | spx_word16_t preemph; | 183 | spx_word16_t preemph; |
176 | spx_word16_t notch_radius; | 184 | spx_word16_t notch_radius; |
177 | spx_mem_t notch_mem[2]; | 185 | spx_mem_t *notch_mem; |
178 | 186 | ||
179 | /* NOTE: If you only use speex_echo_cancel() and want to save some memory, remove this */ | 187 | /* NOTE: If you only use speex_echo_cancel() and want to save some memory, remove this */ |
180 | spx_int16_t *play_buf; | 188 | spx_int16_t *play_buf; |
@@ -182,7 +190,7 @@ struct SpeexEchoState_ { | |||
182 | int play_buf_started; | 190 | int play_buf_started; |
183 | }; | 191 | }; |
184 | 192 | ||
185 | 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) | 193 | 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) |
186 | { | 194 | { |
187 | int i; | 195 | int i; |
188 | spx_word16_t den2; | 196 | spx_word16_t den2; |
@@ -190,11 +198,11 @@ static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius, | |||
190 | den2 = MULT16_16_Q15(radius,radius) + MULT16_16_Q15(QCONST16(.7,15),MULT16_16_Q15(32767-radius,32767-radius)); | 198 | den2 = MULT16_16_Q15(radius,radius) + MULT16_16_Q15(QCONST16(.7,15),MULT16_16_Q15(32767-radius,32767-radius)); |
191 | #else | 199 | #else |
192 | den2 = radius*radius + .7*(1-radius)*(1-radius); | 200 | den2 = radius*radius + .7*(1-radius)*(1-radius); |
193 | #endif | 201 | #endif |
194 | /*printf ("%d %d %d %d %d %d\n", num[0], num[1], num[2], den[0], den[1], den[2]);*/ | 202 | /*printf ("%d %d %d %d %d %d\n", num[0], num[1], num[2], den[0], den[1], den[2]);*/ |
195 | for (i=0;i<len;i++) | 203 | for (i=0;i<len;i++) |
196 | { | 204 | { |
197 | spx_word16_t vin = in[i]; | 205 | spx_word16_t vin = in[i*stride]; |
198 | spx_word32_t vout = mem[0] + SHL32(EXTEND32(vin),15); | 206 | spx_word32_t vout = mem[0] + SHL32(EXTEND32(vin),15); |
199 | #ifdef FIXED_POINT | 207 | #ifdef FIXED_POINT |
200 | mem[0] = mem[1] + SHL32(SHL32(-EXTEND32(vin),15) + MULT16_32_Q15(radius,vout),1); | 208 | mem[0] = mem[1] + SHL32(SHL32(-EXTEND32(vin),15) + MULT16_32_Q15(radius,vout),1); |
@@ -234,6 +242,18 @@ static inline void power_spectrum(const spx_word16_t *X, spx_word32_t *ps, int N | |||
234 | ps[j]=MULT16_16(X[i],X[i]); | 242 | ps[j]=MULT16_16(X[i],X[i]); |
235 | } | 243 | } |
236 | 244 | ||
245 | /** Compute power spectrum of a half-complex (packed) vector and accumulate */ | ||
246 | static inline void power_spectrum_accum(const spx_word16_t *X, spx_word32_t *ps, int N) | ||
247 | { | ||
248 | int i, j; | ||
249 | ps[0]+=MULT16_16(X[0],X[0]); | ||
250 | for (i=1,j=1;i<N-1;i+=2,j++) | ||
251 | { | ||
252 | ps[j] += MULT16_16(X[i],X[i]) + MULT16_16(X[i+1],X[i+1]); | ||
253 | } | ||
254 | ps[j]+=MULT16_16(X[i],X[i]); | ||
255 | } | ||
256 | |||
237 | /** Compute cross-power spectrum of a half-complex (packed) vectors and add to acc */ | 257 | /** Compute cross-power spectrum of a half-complex (packed) vectors and add to acc */ |
238 | #ifdef FIXED_POINT | 258 | #ifdef FIXED_POINT |
239 | static inline void spectral_mul_accum(const spx_word16_t *X, const spx_word32_t *Y, spx_word16_t *acc, int N, int M) | 259 | static inline void spectral_mul_accum(const spx_word16_t *X, const spx_word32_t *Y, spx_word16_t *acc, int N, int M) |
@@ -330,16 +350,17 @@ static inline void weighted_spectral_mul_conj(const spx_float_t *w, const spx_fl | |||
330 | prod[i] = FLOAT_MUL32(W,MULT16_16(X[i],Y[i])); | 350 | prod[i] = FLOAT_MUL32(W,MULT16_16(X[i],Y[i])); |
331 | } | 351 | } |
332 | 352 | ||
333 | static inline void mdf_adjust_prop(const spx_word32_t *W, int N, int M, spx_word16_t *prop) | 353 | static inline void mdf_adjust_prop(const spx_word32_t *W, int N, int M, int P, spx_word16_t *prop) |
334 | { | 354 | { |
335 | int i, j; | 355 | int i, j, p; |
336 | spx_word16_t max_sum = 1; | 356 | spx_word16_t max_sum = 1; |
337 | spx_word32_t prop_sum = 1; | 357 | spx_word32_t prop_sum = 1; |
338 | for (i=0;i<M;i++) | 358 | for (i=0;i<M;i++) |
339 | { | 359 | { |
340 | spx_word32_t tmp = 1; | 360 | spx_word32_t tmp = 1; |
341 | for (j=0;j<N;j++) | 361 | for (p=0;p<P;p++) |
342 | tmp += MULT16_16(EXTRACT16(SHR32(W[i*N+j],18)), EXTRACT16(SHR32(W[i*N+j],18))); | 362 | for (j=0;j<N;j++) |
363 | tmp += MULT16_16(EXTRACT16(SHR32(W[p*N*M + i*N+j],18)), EXTRACT16(SHR32(W[p*N*M + i*N+j],18))); | ||
343 | #ifdef FIXED_POINT | 364 | #ifdef FIXED_POINT |
344 | /* Just a security in case an overflow were to occur */ | 365 | /* Just a security in case an overflow were to occur */ |
345 | tmp = MIN32(ABS32(tmp), 536870912); | 366 | tmp = MIN32(ABS32(tmp), 536870912); |
@@ -378,11 +399,20 @@ static void dump_audio(const spx_int16_t *rec, const spx_int16_t *play, const sp | |||
378 | #endif | 399 | #endif |
379 | 400 | ||
380 | /** Creates a new echo canceller state */ | 401 | /** Creates a new echo canceller state */ |
381 | SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length) | 402 | EXPORT SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length) |
382 | { | 403 | { |
383 | int i,N,M; | 404 | return speex_echo_state_init_mc(frame_size, filter_length, 1, 1); |
405 | } | ||
406 | |||
407 | EXPORT SpeexEchoState *speex_echo_state_init_mc(int frame_size, int filter_length, int nb_mic, int nb_speakers) | ||
408 | { | ||
409 | int i,N,M, C, K; | ||
384 | SpeexEchoState *st = (SpeexEchoState *)speex_alloc(sizeof(SpeexEchoState)); | 410 | SpeexEchoState *st = (SpeexEchoState *)speex_alloc(sizeof(SpeexEchoState)); |
385 | 411 | ||
412 | st->K = nb_speakers; | ||
413 | st->C = nb_mic; | ||
414 | C=st->C; | ||
415 | K=st->K; | ||
386 | #ifdef DUMP_ECHO_CANCEL_DATA | 416 | #ifdef DUMP_ECHO_CANCEL_DATA |
387 | if (rFile || pFile || oFile) | 417 | if (rFile || pFile || oFile) |
388 | speex_fatal("Opening dump files twice"); | 418 | speex_fatal("Opening dump files twice"); |
@@ -390,7 +420,7 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length) | |||
390 | pFile = fopen("aec_play.sw", "wb"); | 420 | pFile = fopen("aec_play.sw", "wb"); |
391 | oFile = fopen("aec_out.sw", "wb"); | 421 | oFile = fopen("aec_out.sw", "wb"); |
392 | #endif | 422 | #endif |
393 | 423 | ||
394 | st->frame_size = frame_size; | 424 | st->frame_size = frame_size; |
395 | st->window_size = 2*frame_size; | 425 | st->window_size = 2*frame_size; |
396 | N = st->window_size; | 426 | N = st->window_size; |
@@ -412,24 +442,24 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length) | |||
412 | st->leak_estimate = 0; | 442 | st->leak_estimate = 0; |
413 | 443 | ||
414 | st->fft_table = spx_fft_init(N); | 444 | st->fft_table = spx_fft_init(N); |
415 | 445 | ||
416 | st->e = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); | 446 | st->e = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); |
417 | st->x = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); | 447 | st->x = (spx_word16_t*)speex_alloc(K*N*sizeof(spx_word16_t)); |
418 | st->input = (spx_word16_t*)speex_alloc(st->frame_size*sizeof(spx_word16_t)); | 448 | st->input = (spx_word16_t*)speex_alloc(C*st->frame_size*sizeof(spx_word16_t)); |
419 | st->y = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); | 449 | st->y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); |
420 | st->last_y = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); | 450 | st->last_y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); |
421 | st->Yf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); | 451 | st->Yf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); |
422 | st->Rf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); | 452 | st->Rf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); |
423 | st->Xf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); | 453 | st->Xf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); |
424 | st->Yh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); | 454 | st->Yh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); |
425 | st->Eh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); | 455 | st->Eh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); |
426 | 456 | ||
427 | st->X = (spx_word16_t*)speex_alloc((M+1)*N*sizeof(spx_word16_t)); | 457 | st->X = (spx_word16_t*)speex_alloc(K*(M+1)*N*sizeof(spx_word16_t)); |
428 | st->Y = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); | 458 | st->Y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); |
429 | st->E = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); | 459 | st->E = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); |
430 | st->W = (spx_word32_t*)speex_alloc(M*N*sizeof(spx_word32_t)); | 460 | st->W = (spx_word32_t*)speex_alloc(C*K*M*N*sizeof(spx_word32_t)); |
431 | #ifdef TWO_PATH | 461 | #ifdef TWO_PATH |
432 | st->foreground = (spx_word16_t*)speex_alloc(M*N*sizeof(spx_word16_t)); | 462 | st->foreground = (spx_word16_t*)speex_alloc(M*N*C*K*sizeof(spx_word16_t)); |
433 | #endif | 463 | #endif |
434 | st->PHI = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); | 464 | st->PHI = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); |
435 | st->power = (spx_word32_t*)speex_alloc((frame_size+1)*sizeof(spx_word32_t)); | 465 | st->power = (spx_word32_t*)speex_alloc((frame_size+1)*sizeof(spx_word32_t)); |
@@ -450,7 +480,7 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length) | |||
450 | #endif | 480 | #endif |
451 | for (i=0;i<=st->frame_size;i++) | 481 | for (i=0;i<=st->frame_size;i++) |
452 | st->power_1[i] = FLOAT_ONE; | 482 | st->power_1[i] = FLOAT_ONE; |
453 | for (i=0;i<N*M;i++) | 483 | for (i=0;i<N*M*K*C;i++) |
454 | st->W[i] = 0; | 484 | st->W[i] = 0; |
455 | { | 485 | { |
456 | spx_word32_t sum = 0; | 486 | spx_word32_t sum = 0; |
@@ -465,11 +495,13 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length) | |||
465 | } | 495 | } |
466 | for (i=M-1;i>=0;i--) | 496 | for (i=M-1;i>=0;i--) |
467 | { | 497 | { |
468 | st->prop[i] = DIV32(MULT16_16(QCONST16(.8,15), st->prop[i]),sum); | 498 | st->prop[i] = DIV32(MULT16_16(QCONST16(.8f,15), st->prop[i]),sum); |
469 | } | 499 | } |
470 | } | 500 | } |
471 | 501 | ||
472 | st->memX=st->memD=st->memE=0; | 502 | st->memX = (spx_word16_t*)speex_alloc(K*sizeof(spx_word16_t)); |
503 | st->memD = (spx_word16_t*)speex_alloc(C*sizeof(spx_word16_t)); | ||
504 | st->memE = (spx_word16_t*)speex_alloc(C*sizeof(spx_word16_t)); | ||
473 | st->preemph = QCONST16(.9,15); | 505 | st->preemph = QCONST16(.9,15); |
474 | if (st->sampling_rate<12000) | 506 | if (st->sampling_rate<12000) |
475 | st->notch_radius = QCONST16(.9, 15); | 507 | st->notch_radius = QCONST16(.9, 15); |
@@ -478,30 +510,32 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length) | |||
478 | else | 510 | else |
479 | st->notch_radius = QCONST16(.992, 15); | 511 | st->notch_radius = QCONST16(.992, 15); |
480 | 512 | ||
481 | st->notch_mem[0] = st->notch_mem[1] = 0; | 513 | st->notch_mem = (spx_mem_t*)speex_alloc(2*C*sizeof(spx_mem_t)); |
482 | st->adapted = 0; | 514 | st->adapted = 0; |
483 | st->Pey = st->Pyy = FLOAT_ONE; | 515 | st->Pey = st->Pyy = FLOAT_ONE; |
484 | 516 | ||
485 | #ifdef TWO_PATH | 517 | #ifdef TWO_PATH |
486 | st->Davg1 = st->Davg2 = 0; | 518 | st->Davg1 = st->Davg2 = 0; |
487 | st->Dvar1 = st->Dvar2 = FLOAT_ZERO; | 519 | st->Dvar1 = st->Dvar2 = FLOAT_ZERO; |
488 | #endif | 520 | #endif |
489 | 521 | ||
490 | st->play_buf = (spx_int16_t*)speex_alloc((PLAYBACK_DELAY+1)*st->frame_size*sizeof(spx_int16_t)); | 522 | st->play_buf = (spx_int16_t*)speex_alloc(K*(PLAYBACK_DELAY+1)*st->frame_size*sizeof(spx_int16_t)); |
491 | st->play_buf_pos = PLAYBACK_DELAY*st->frame_size; | 523 | st->play_buf_pos = PLAYBACK_DELAY*st->frame_size; |
492 | st->play_buf_started = 0; | 524 | st->play_buf_started = 0; |
493 | 525 | ||
494 | return st; | 526 | return st; |
495 | } | 527 | } |
496 | 528 | ||
497 | /** Resets echo canceller state */ | 529 | /** Resets echo canceller state */ |
498 | void speex_echo_state_reset(SpeexEchoState *st) | 530 | EXPORT void speex_echo_state_reset(SpeexEchoState *st) |
499 | { | 531 | { |
500 | int i, M, N; | 532 | int i, M, N, C, K; |
501 | st->cancel_count=0; | 533 | st->cancel_count=0; |
502 | st->screwed_up = 0; | 534 | st->screwed_up = 0; |
503 | N = st->window_size; | 535 | N = st->window_size; |
504 | M = st->M; | 536 | M = st->M; |
537 | C=st->C; | ||
538 | K=st->K; | ||
505 | for (i=0;i<N*M;i++) | 539 | for (i=0;i<N*M;i++) |
506 | st->W[i] = 0; | 540 | st->W[i] = 0; |
507 | #ifdef TWO_PATH | 541 | #ifdef TWO_PATH |
@@ -521,13 +555,20 @@ void speex_echo_state_reset(SpeexEchoState *st) | |||
521 | { | 555 | { |
522 | st->last_y[i] = 0; | 556 | st->last_y[i] = 0; |
523 | } | 557 | } |
524 | for (i=0;i<N;i++) | 558 | for (i=0;i<N*C;i++) |
525 | { | 559 | { |
526 | st->E[i] = 0; | 560 | st->E[i] = 0; |
561 | } | ||
562 | for (i=0;i<N*K;i++) | ||
563 | { | ||
527 | st->x[i] = 0; | 564 | st->x[i] = 0; |
528 | } | 565 | } |
529 | st->notch_mem[0] = st->notch_mem[1] = 0; | 566 | for (i=0;i<2*C;i++) |
530 | st->memX=st->memD=st->memE=0; | 567 | st->notch_mem[i] = 0; |
568 | for (i=0;i<C;i++) | ||
569 | st->memD[i]=st->memE[i]=0; | ||
570 | for (i=0;i<K;i++) | ||
571 | st->memX[i]=0; | ||
531 | 572 | ||
532 | st->saturated = 0; | 573 | st->saturated = 0; |
533 | st->adapted = 0; | 574 | st->adapted = 0; |
@@ -545,7 +586,7 @@ void speex_echo_state_reset(SpeexEchoState *st) | |||
545 | } | 586 | } |
546 | 587 | ||
547 | /** Destroys an echo canceller state */ | 588 | /** Destroys an echo canceller state */ |
548 | void speex_echo_state_destroy(SpeexEchoState *st) | 589 | EXPORT void speex_echo_state_destroy(SpeexEchoState *st) |
549 | { | 590 | { |
550 | spx_fft_destroy(st->fft_table); | 591 | spx_fft_destroy(st->fft_table); |
551 | 592 | ||
@@ -576,9 +617,14 @@ void speex_echo_state_destroy(SpeexEchoState *st) | |||
576 | #ifdef FIXED_POINT | 617 | #ifdef FIXED_POINT |
577 | speex_free(st->wtmp2); | 618 | speex_free(st->wtmp2); |
578 | #endif | 619 | #endif |
620 | speex_free(st->memX); | ||
621 | speex_free(st->memD); | ||
622 | speex_free(st->memE); | ||
623 | speex_free(st->notch_mem); | ||
624 | |||
579 | speex_free(st->play_buf); | 625 | speex_free(st->play_buf); |
580 | speex_free(st); | 626 | speex_free(st); |
581 | 627 | ||
582 | #ifdef DUMP_ECHO_CANCEL_DATA | 628 | #ifdef DUMP_ECHO_CANCEL_DATA |
583 | fclose(rFile); | 629 | fclose(rFile); |
584 | fclose(pFile); | 630 | fclose(pFile); |
@@ -587,7 +633,7 @@ void speex_echo_state_destroy(SpeexEchoState *st) | |||
587 | #endif | 633 | #endif |
588 | } | 634 | } |
589 | 635 | ||
590 | void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out) | 636 | EXPORT void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out) |
591 | { | 637 | { |
592 | int i; | 638 | int i; |
593 | /*speex_warning_int("capture with fill level ", st->play_buf_pos/st->frame_size);*/ | 639 | /*speex_warning_int("capture with fill level ", st->play_buf_pos/st->frame_size);*/ |
@@ -610,7 +656,7 @@ void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t | |||
610 | } | 656 | } |
611 | } | 657 | } |
612 | 658 | ||
613 | void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play) | 659 | EXPORT void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play) |
614 | { | 660 | { |
615 | /*speex_warning_int("playback with fill level ", st->play_buf_pos/st->frame_size);*/ | 661 | /*speex_warning_int("playback with fill level ", st->play_buf_pos/st->frame_size);*/ |
616 | if (!st->play_buf_started) | 662 | if (!st->play_buf_started) |
@@ -637,16 +683,16 @@ void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play) | |||
637 | } | 683 | } |
638 | 684 | ||
639 | /** Performs echo cancellation on a frame (deprecated, last arg now ignored) */ | 685 | /** Performs echo cancellation on a frame (deprecated, last arg now ignored) */ |
640 | 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) | 686 | 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) |
641 | { | 687 | { |
642 | speex_echo_cancellation(st, in, far_end, out); | 688 | speex_echo_cancellation(st, in, far_end, out); |
643 | } | 689 | } |
644 | 690 | ||
645 | /** Performs echo cancellation on a frame */ | 691 | /** Performs echo cancellation on a frame */ |
646 | void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out) | 692 | EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out) |
647 | { | 693 | { |
648 | int i,j; | 694 | int i,j, chan, speak; |
649 | int N,M; | 695 | int N,M, C, K; |
650 | spx_word32_t Syy,See,Sxx,Sdd, Sff; | 696 | spx_word32_t Syy,See,Sxx,Sdd, Sff; |
651 | #ifdef TWO_PATH | 697 | #ifdef TWO_PATH |
652 | spx_word32_t Dbf; | 698 | spx_word32_t Dbf; |
@@ -658,9 +704,12 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp | |||
658 | spx_float_t alpha, alpha_1; | 704 | spx_float_t alpha, alpha_1; |
659 | spx_word16_t RER; | 705 | spx_word16_t RER; |
660 | spx_word32_t tmp32; | 706 | spx_word32_t tmp32; |
661 | 707 | ||
662 | N = st->window_size; | 708 | N = st->window_size; |
663 | M = st->M; | 709 | M = st->M; |
710 | C = st->C; | ||
711 | K = st->K; | ||
712 | |||
664 | st->cancel_count++; | 713 | st->cancel_count++; |
665 | #ifdef FIXED_POINT | 714 | #ifdef FIXED_POINT |
666 | ss=DIV32_16(11469,M); | 715 | ss=DIV32_16(11469,M); |
@@ -670,157 +719,198 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp | |||
670 | ss_1 = 1-ss; | 719 | ss_1 = 1-ss; |
671 | #endif | 720 | #endif |
672 | 721 | ||
673 | /* Apply a notch filter to make sure DC doesn't end up causing problems */ | 722 | for (chan = 0; chan < C; chan++) |
674 | filter_dc_notch16(in, st->notch_radius, st->input, st->frame_size, st->notch_mem); | ||
675 | /* Copy input data to buffer and apply pre-emphasis */ | ||
676 | for (i=0;i<st->frame_size;i++) | ||
677 | { | 723 | { |
678 | spx_word32_t tmp32; | 724 | /* Apply a notch filter to make sure DC doesn't end up causing problems */ |
679 | tmp32 = SUB32(EXTEND32(far_end[i]), EXTEND32(MULT16_16_P15(st->preemph, st->memX))); | 725 | filter_dc_notch16(in+chan, st->notch_radius, st->input+chan*st->frame_size, st->frame_size, st->notch_mem+2*chan, C); |
680 | #ifdef FIXED_POINT | 726 | /* Copy input data to buffer and apply pre-emphasis */ |
681 | /* If saturation occurs here, we need to freeze adaptation for M+1 frames (not just one) */ | 727 | /* Copy input data to buffer */ |
682 | if (tmp32 > 32767) | 728 | for (i=0;i<st->frame_size;i++) |
683 | { | 729 | { |
684 | tmp32 = 32767; | 730 | spx_word32_t tmp32; |
685 | st->saturated = M+1; | 731 | /* FIXME: This core has changed a bit, need to merge properly */ |
732 | tmp32 = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(MULT16_16_P15(st->preemph, st->memD[chan]))); | ||
733 | #ifdef FIXED_POINT | ||
734 | if (tmp32 > 32767) | ||
735 | { | ||
736 | tmp32 = 32767; | ||
737 | if (st->saturated == 0) | ||
738 | st->saturated = 1; | ||
739 | } | ||
740 | if (tmp32 < -32767) | ||
741 | { | ||
742 | tmp32 = -32767; | ||
743 | if (st->saturated == 0) | ||
744 | st->saturated = 1; | ||
745 | } | ||
746 | #endif | ||
747 | st->memD[chan] = st->input[chan*st->frame_size+i]; | ||
748 | st->input[chan*st->frame_size+i] = EXTRACT16(tmp32); | ||
686 | } | 749 | } |
687 | if (tmp32 < -32767) | 750 | } |
751 | |||
752 | for (speak = 0; speak < K; speak++) | ||
753 | { | ||
754 | for (i=0;i<st->frame_size;i++) | ||
688 | { | 755 | { |
689 | tmp32 = -32767; | 756 | spx_word32_t tmp32; |
690 | st->saturated = M+1; | 757 | st->x[speak*N+i] = st->x[speak*N+i+st->frame_size]; |
691 | } | 758 | tmp32 = SUB32(EXTEND32(far_end[i*K+speak]), EXTEND32(MULT16_16_P15(st->preemph, st->memX[speak]))); |
692 | #endif | ||
693 | st->x[i+st->frame_size] = EXTRACT16(tmp32); | ||
694 | st->memX = far_end[i]; | ||
695 | |||
696 | tmp32 = SUB32(EXTEND32(st->input[i]), EXTEND32(MULT16_16_P15(st->preemph, st->memD))); | ||
697 | #ifdef FIXED_POINT | 759 | #ifdef FIXED_POINT |
698 | if (tmp32 > 32767) | 760 | /*FIXME: If saturation occurs here, we need to freeze adaptation for M frames (not just one) */ |
699 | { | 761 | if (tmp32 > 32767) |
700 | tmp32 = 32767; | 762 | { |
701 | if (st->saturated == 0) | 763 | tmp32 = 32767; |
702 | st->saturated = 1; | 764 | st->saturated = M+1; |
703 | } | 765 | } |
704 | if (tmp32 < -32767) | 766 | if (tmp32 < -32767) |
767 | { | ||
768 | tmp32 = -32767; | ||
769 | st->saturated = M+1; | ||
770 | } | ||
771 | #endif | ||
772 | st->x[speak*N+i+st->frame_size] = EXTRACT16(tmp32); | ||
773 | st->memX[speak] = far_end[i*K+speak]; | ||
774 | } | ||
775 | } | ||
776 | |||
777 | for (speak = 0; speak < K; speak++) | ||
778 | { | ||
779 | /* Shift memory: this could be optimized eventually*/ | ||
780 | for (j=M-1;j>=0;j--) | ||
705 | { | 781 | { |
706 | tmp32 = -32767; | 782 | for (i=0;i<N;i++) |
707 | if (st->saturated == 0) | 783 | st->X[(j+1)*N*K+speak*N+i] = st->X[j*N*K+speak*N+i]; |
708 | st->saturated = 1; | ||
709 | } | 784 | } |
710 | #endif | 785 | /* Convert x (echo input) to frequency domain */ |
711 | st->memD = st->input[i]; | 786 | spx_fft(st->fft_table, st->x+speak*N, &st->X[speak*N]); |
712 | st->input[i] = tmp32; | ||
713 | } | 787 | } |
714 | 788 | ||
715 | /* Shift memory: this could be optimized eventually*/ | 789 | Sxx = 0; |
716 | for (j=M-1;j>=0;j--) | 790 | for (speak = 0; speak < K; speak++) |
717 | { | 791 | { |
718 | for (i=0;i<N;i++) | 792 | Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size); |
719 | st->X[(j+1)*N+i] = st->X[j*N+i]; | 793 | power_spectrum_accum(st->X+speak*N, st->Xf, N); |
720 | } | 794 | } |
721 | 795 | ||
722 | /* Convert x (far end) to frequency domain */ | 796 | Sff = 0; |
723 | spx_fft(st->fft_table, st->x, &st->X[0]); | 797 | for (chan = 0; chan < C; chan++) |
724 | for (i=0;i<N;i++) | 798 | { |
725 | st->last_y[i] = st->x[i]; | ||
726 | Sxx = mdf_inner_prod(st->x+st->frame_size, st->x+st->frame_size, st->frame_size); | ||
727 | for (i=0;i<st->frame_size;i++) | ||
728 | st->x[i] = st->x[i+st->frame_size]; | ||
729 | /* From here on, the top part of x is used as scratch space */ | ||
730 | |||
731 | #ifdef TWO_PATH | 799 | #ifdef TWO_PATH |
732 | /* Compute foreground filter */ | 800 | /* Compute foreground filter */ |
733 | spectral_mul_accum16(st->X, st->foreground, st->Y, N, M); | 801 | spectral_mul_accum16(st->X, st->foreground+chan*N*K*M, st->Y+chan*N, N, M*K); |
734 | spx_ifft(st->fft_table, st->Y, st->e); | 802 | spx_ifft(st->fft_table, st->Y+chan*N, st->e+chan*N); |
735 | for (i=0;i<st->frame_size;i++) | 803 | for (i=0;i<st->frame_size;i++) |
736 | st->e[i] = SUB16(st->input[i], st->e[i+st->frame_size]); | 804 | st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->e[chan*N+i+st->frame_size]); |
737 | Sff = mdf_inner_prod(st->e, st->e, st->frame_size); | 805 | Sff += mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size); |
738 | #endif | 806 | #endif |
739 | 807 | } | |
808 | |||
740 | /* Adjust proportional adaption rate */ | 809 | /* Adjust proportional adaption rate */ |
741 | mdf_adjust_prop (st->W, N, M, st->prop); | 810 | /* FIXME: Adjust that for C, K*/ |
811 | if (st->adapted) | ||
812 | mdf_adjust_prop (st->W, N, M, C*K, st->prop); | ||
742 | /* Compute weight gradient */ | 813 | /* Compute weight gradient */ |
743 | if (st->saturated == 0) | 814 | if (st->saturated == 0) |
744 | { | 815 | { |
745 | for (j=M-1;j>=0;j--) | 816 | for (chan = 0; chan < C; chan++) |
746 | { | 817 | { |
747 | weighted_spectral_mul_conj(st->power_1, FLOAT_SHL(PSEUDOFLOAT(st->prop[j]),-15), &st->X[(j+1)*N], st->E, st->PHI, N); | 818 | for (speak = 0; speak < K; speak++) |
748 | for (i=0;i<N;i++) | 819 | { |
749 | st->W[j*N+i] = ADD32(st->W[j*N+i], st->PHI[i]); | 820 | for (j=M-1;j>=0;j--) |
750 | 821 | { | |
822 | 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); | ||
823 | for (i=0;i<N;i++) | ||
824 | st->W[chan*N*K*M + j*N*K + speak*N + i] += st->PHI[i]; | ||
825 | } | ||
826 | } | ||
751 | } | 827 | } |
752 | } else { | 828 | } else { |
753 | st->saturated--; | 829 | st->saturated--; |
754 | } | 830 | } |
755 | 831 | ||
832 | /* FIXME: MC conversion required */ | ||
756 | /* Update weight to prevent circular convolution (MDF / AUMDF) */ | 833 | /* Update weight to prevent circular convolution (MDF / AUMDF) */ |
757 | for (j=0;j<M;j++) | 834 | for (chan = 0; chan < C; chan++) |
758 | { | 835 | { |
759 | /* This is a variant of the Alternatively Updated MDF (AUMDF) */ | 836 | for (speak = 0; speak < K; speak++) |
760 | /* Remove the "if" to make this an MDF filter */ | ||
761 | if (j==0 || st->cancel_count%(M-1) == j-1) | ||
762 | { | 837 | { |
763 | #ifdef FIXED_POINT | 838 | for (j=0;j<M;j++) |
764 | for (i=0;i<N;i++) | ||
765 | st->wtmp2[i] = EXTRACT16(PSHR32(st->W[j*N+i],NORMALIZE_SCALEDOWN+16)); | ||
766 | spx_ifft(st->fft_table, st->wtmp2, st->wtmp); | ||
767 | for (i=0;i<st->frame_size;i++) | ||
768 | { | 839 | { |
769 | st->wtmp[i]=0; | 840 | /* This is a variant of the Alternatively Updated MDF (AUMDF) */ |
770 | } | 841 | /* Remove the "if" to make this an MDF filter */ |
771 | for (i=st->frame_size;i<N;i++) | 842 | if (j==0 || st->cancel_count%(M-1) == j-1) |
772 | { | 843 | { |
773 | st->wtmp[i]=SHL16(st->wtmp[i],NORMALIZE_SCALEUP); | 844 | #ifdef FIXED_POINT |
774 | } | 845 | for (i=0;i<N;i++) |
775 | spx_fft(st->fft_table, st->wtmp, st->wtmp2); | 846 | st->wtmp2[i] = EXTRACT16(PSHR32(st->W[chan*N*K*M + j*N*K + speak*N + i],NORMALIZE_SCALEDOWN+16)); |
776 | /* The "-1" in the shift is a sort of kludge that trades less efficient update speed for decrease noise */ | 847 | spx_ifft(st->fft_table, st->wtmp2, st->wtmp); |
777 | for (i=0;i<N;i++) | 848 | for (i=0;i<st->frame_size;i++) |
778 | st->W[j*N+i] -= SHL32(EXTEND32(st->wtmp2[i]),16+NORMALIZE_SCALEDOWN-NORMALIZE_SCALEUP-1); | 849 | { |
850 | st->wtmp[i]=0; | ||
851 | } | ||
852 | for (i=st->frame_size;i<N;i++) | ||
853 | { | ||
854 | st->wtmp[i]=SHL16(st->wtmp[i],NORMALIZE_SCALEUP); | ||
855 | } | ||
856 | spx_fft(st->fft_table, st->wtmp, st->wtmp2); | ||
857 | /* The "-1" in the shift is a sort of kludge that trades less efficient update speed for decrease noise */ | ||
858 | for (i=0;i<N;i++) | ||
859 | st->W[chan*N*K*M + j*N*K + speak*N + i] -= SHL32(EXTEND32(st->wtmp2[i]),16+NORMALIZE_SCALEDOWN-NORMALIZE_SCALEUP-1); | ||
779 | #else | 860 | #else |
780 | spx_ifft(st->fft_table, &st->W[j*N], st->wtmp); | 861 | spx_ifft(st->fft_table, &st->W[chan*N*K*M + j*N*K + speak*N], st->wtmp); |
781 | for (i=st->frame_size;i<N;i++) | 862 | for (i=st->frame_size;i<N;i++) |
782 | { | 863 | { |
783 | st->wtmp[i]=0; | 864 | st->wtmp[i]=0; |
784 | } | 865 | } |
785 | spx_fft(st->fft_table, st->wtmp, &st->W[j*N]); | 866 | spx_fft(st->fft_table, st->wtmp, &st->W[chan*N*K*M + j*N*K + speak*N]); |
786 | #endif | 867 | #endif |
868 | } | ||
869 | } | ||
787 | } | 870 | } |
788 | } | 871 | } |
789 | 872 | ||
790 | /* Compute filter response Y */ | 873 | /* So we can use power_spectrum_accum */ |
791 | spectral_mul_accum(st->X, st->W, st->Y, N, M); | 874 | for (i=0;i<=st->frame_size;i++) |
792 | spx_ifft(st->fft_table, st->Y, st->y); | 875 | st->Rf[i] = st->Yf[i] = st->Xf[i] = 0; |
793 | 876 | ||
877 | Dbf = 0; | ||
878 | See = 0; | ||
794 | #ifdef TWO_PATH | 879 | #ifdef TWO_PATH |
795 | /* Difference in response, this is used to estimate the variance of our residual power estimate */ | 880 | /* Difference in response, this is used to estimate the variance of our residual power estimate */ |
796 | for (i=0;i<st->frame_size;i++) | 881 | for (chan = 0; chan < C; chan++) |
797 | st->e[i] = SUB16(st->e[i+st->frame_size], st->y[i+st->frame_size]); | 882 | { |
798 | Dbf = 10+mdf_inner_prod(st->e, st->e, st->frame_size); | 883 | spectral_mul_accum(st->X, st->W+chan*N*K*M, st->Y+chan*N, N, M*K); |
884 | spx_ifft(st->fft_table, st->Y+chan*N, st->y+chan*N); | ||
885 | for (i=0;i<st->frame_size;i++) | ||
886 | st->e[chan*N+i] = SUB16(st->e[chan*N+i+st->frame_size], st->y[chan*N+i+st->frame_size]); | ||
887 | Dbf += 10+mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size); | ||
888 | for (i=0;i<st->frame_size;i++) | ||
889 | st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->y[chan*N+i+st->frame_size]); | ||
890 | See += mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size); | ||
891 | } | ||
799 | #endif | 892 | #endif |
800 | 893 | ||
801 | for (i=0;i<st->frame_size;i++) | ||
802 | st->e[i] = SUB16(st->input[i], st->y[i+st->frame_size]); | ||
803 | See = mdf_inner_prod(st->e, st->e, st->frame_size); | ||
804 | #ifndef TWO_PATH | 894 | #ifndef TWO_PATH |
805 | Sff = See; | 895 | Sff = See; |
806 | #endif | 896 | #endif |
807 | 897 | ||
808 | #ifdef TWO_PATH | 898 | #ifdef TWO_PATH |
809 | /* Logic for updating the foreground filter */ | 899 | /* Logic for updating the foreground filter */ |
810 | 900 | ||
811 | /* For two time windows, compute the mean of the energy difference, as well as the variance */ | 901 | /* For two time windows, compute the mean of the energy difference, as well as the variance */ |
812 | st->Davg1 = ADD32(MULT16_32_Q15(QCONST16(.6f,15),st->Davg1), MULT16_32_Q15(QCONST16(.4f,15),SUB32(Sff,See))); | 902 | st->Davg1 = ADD32(MULT16_32_Q15(QCONST16(.6f,15),st->Davg1), MULT16_32_Q15(QCONST16(.4f,15),SUB32(Sff,See))); |
813 | st->Davg2 = ADD32(MULT16_32_Q15(QCONST16(.85f,15),st->Davg2), MULT16_32_Q15(QCONST16(.15f,15),SUB32(Sff,See))); | 903 | st->Davg2 = ADD32(MULT16_32_Q15(QCONST16(.85f,15),st->Davg2), MULT16_32_Q15(QCONST16(.15f,15),SUB32(Sff,See))); |
814 | 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))); | 904 | 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))); |
815 | 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))); | 905 | 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))); |
816 | 906 | ||
817 | /* Equivalent float code: | 907 | /* Equivalent float code: |
818 | st->Davg1 = .6*st->Davg1 + .4*(Sff-See); | 908 | st->Davg1 = .6*st->Davg1 + .4*(Sff-See); |
819 | st->Davg2 = .85*st->Davg2 + .15*(Sff-See); | 909 | st->Davg2 = .85*st->Davg2 + .15*(Sff-See); |
820 | st->Dvar1 = .36*st->Dvar1 + .16*Sff*Dbf; | 910 | st->Dvar1 = .36*st->Dvar1 + .16*Sff*Dbf; |
821 | st->Dvar2 = .7225*st->Dvar2 + .0225*Sff*Dbf; | 911 | st->Dvar2 = .7225*st->Dvar2 + .0225*Sff*Dbf; |
822 | */ | 912 | */ |
823 | 913 | ||
824 | update_foreground = 0; | 914 | update_foreground = 0; |
825 | /* Check if we have a statistically significant reduction in the residual echo */ | 915 | /* Check if we have a statistically significant reduction in the residual echo */ |
826 | /* Note that this is *not* Gaussian, so we need to be careful about the longer tail */ | 916 | /* Note that this is *not* Gaussian, so we need to be careful about the longer tail */ |
@@ -830,18 +920,19 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp | |||
830 | update_foreground = 1; | 920 | update_foreground = 1; |
831 | else if (FLOAT_GT(FLOAT_MUL32U(st->Davg2, ABS32(st->Davg2)), FLOAT_MULT(VAR2_UPDATE,(st->Dvar2)))) | 921 | else if (FLOAT_GT(FLOAT_MUL32U(st->Davg2, ABS32(st->Davg2)), FLOAT_MULT(VAR2_UPDATE,(st->Dvar2)))) |
832 | update_foreground = 1; | 922 | update_foreground = 1; |
833 | 923 | ||
834 | /* Do we update? */ | 924 | /* Do we update? */ |
835 | if (update_foreground) | 925 | if (update_foreground) |
836 | { | 926 | { |
837 | st->Davg1 = st->Davg2 = 0; | 927 | st->Davg1 = st->Davg2 = 0; |
838 | st->Dvar1 = st->Dvar2 = FLOAT_ZERO; | 928 | st->Dvar1 = st->Dvar2 = FLOAT_ZERO; |
839 | /* Copy background filter to foreground filter */ | 929 | /* Copy background filter to foreground filter */ |
840 | for (i=0;i<N*M;i++) | 930 | for (i=0;i<N*M*C*K;i++) |
841 | st->foreground[i] = EXTRACT16(PSHR32(st->W[i],16)); | 931 | st->foreground[i] = EXTRACT16(PSHR32(st->W[i],16)); |
842 | /* Apply a smooth transition so as to not introduce blocking artifacts */ | 932 | /* Apply a smooth transition so as to not introduce blocking artifacts */ |
843 | for (i=0;i<st->frame_size;i++) | 933 | for (chan = 0; chan < C; chan++) |
844 | 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]); | 934 | for (i=0;i<st->frame_size;i++) |
935 | 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]); | ||
845 | } else { | 936 | } else { |
846 | int reset_background=0; | 937 | int reset_background=0; |
847 | /* Otherwise, check if the background filter is significantly worse */ | 938 | /* Otherwise, check if the background filter is significantly worse */ |
@@ -854,13 +945,16 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp | |||
854 | if (reset_background) | 945 | if (reset_background) |
855 | { | 946 | { |
856 | /* Copy foreground filter to background filter */ | 947 | /* Copy foreground filter to background filter */ |
857 | for (i=0;i<N*M;i++) | 948 | for (i=0;i<N*M*C*K;i++) |
858 | st->W[i] = SHL32(EXTEND32(st->foreground[i]),16); | 949 | st->W[i] = SHL32(EXTEND32(st->foreground[i]),16); |
859 | /* We also need to copy the output so as to get correct adaptation */ | 950 | /* We also need to copy the output so as to get correct adaptation */ |
860 | for (i=0;i<st->frame_size;i++) | 951 | for (chan = 0; chan < C; chan++) |
861 | st->y[i+st->frame_size] = st->e[i+st->frame_size]; | 952 | { |
862 | for (i=0;i<st->frame_size;i++) | 953 | for (i=0;i<st->frame_size;i++) |
863 | st->e[i] = SUB16(st->input[i], st->y[i+st->frame_size]); | 954 | st->y[chan*N+i+st->frame_size] = st->e[chan*N+i+st->frame_size]; |
955 | for (i=0;i<st->frame_size;i++) | ||
956 | st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->y[chan*N+i+st->frame_size]); | ||
957 | } | ||
864 | See = Sff; | 958 | See = Sff; |
865 | st->Davg1 = st->Davg2 = 0; | 959 | st->Davg1 = st->Davg2 = 0; |
866 | st->Dvar1 = st->Dvar2 = FLOAT_ZERO; | 960 | st->Dvar1 = st->Dvar2 = FLOAT_ZERO; |
@@ -868,50 +962,60 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp | |||
868 | } | 962 | } |
869 | #endif | 963 | #endif |
870 | 964 | ||
871 | /* Compute error signal (for the output with de-emphasis) */ | 965 | Sey = Syy = Sdd = 0; |
872 | for (i=0;i<st->frame_size;i++) | 966 | for (chan = 0; chan < C; chan++) |
873 | { | 967 | { |
874 | spx_word32_t tmp_out; | 968 | /* Compute error signal (for the output with de-emphasis) */ |
969 | for (i=0;i<st->frame_size;i++) | ||
970 | { | ||
971 | spx_word32_t tmp_out; | ||
875 | #ifdef TWO_PATH | 972 | #ifdef TWO_PATH |
876 | tmp_out = SUB32(EXTEND32(st->input[i]), EXTEND32(st->e[i+st->frame_size])); | 973 | tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->e[chan*N+i+st->frame_size])); |
877 | #else | 974 | #else |
878 | tmp_out = SUB32(EXTEND32(st->input[i]), EXTEND32(st->y[i+st->frame_size])); | 975 | tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->y[chan*N+i+st->frame_size])); |
879 | #endif | 976 | #endif |
880 | /* Saturation */ | 977 | tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(st->preemph, st->memE[chan]))); |
881 | if (tmp_out>32767) | ||
882 | tmp_out = 32767; | ||
883 | else if (tmp_out<-32768) | ||
884 | tmp_out = -32768; | ||
885 | tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(st->preemph, st->memE))); | ||
886 | /* This is an arbitrary test for saturation in the microphone signal */ | 978 | /* This is an arbitrary test for saturation in the microphone signal */ |
887 | if (in[i] <= -32000 || in[i] >= 32000) | 979 | if (in[i*C+chan] <= -32000 || in[i*C+chan] >= 32000) |
888 | { | 980 | { |
889 | tmp_out = 0; | ||
890 | if (st->saturated == 0) | 981 | if (st->saturated == 0) |
891 | st->saturated = 1; | 982 | st->saturated = 1; |
983 | } | ||
984 | out[i*C+chan] = WORD2INT(tmp_out); | ||
985 | st->memE[chan] = tmp_out; | ||
892 | } | 986 | } |
893 | out[i] = (spx_int16_t)tmp_out; | 987 | |
894 | st->memE = tmp_out; | ||
895 | } | ||
896 | |||
897 | #ifdef DUMP_ECHO_CANCEL_DATA | 988 | #ifdef DUMP_ECHO_CANCEL_DATA |
898 | dump_audio(in, far_end, out, st->frame_size); | 989 | dump_audio(in, far_end, out, st->frame_size); |
899 | #endif | 990 | #endif |
900 | 991 | ||
901 | /* Compute error signal (filter update version) */ | 992 | /* Compute error signal (filter update version) */ |
902 | for (i=0;i<st->frame_size;i++) | 993 | for (i=0;i<st->frame_size;i++) |
903 | { | 994 | { |
904 | st->e[i+st->frame_size] = st->e[i]; | 995 | st->e[chan*N+i+st->frame_size] = st->e[chan*N+i]; |
905 | st->e[i] = 0; | 996 | st->e[chan*N+i] = 0; |
997 | } | ||
998 | |||
999 | /* Compute a bunch of correlations */ | ||
1000 | /* FIXME: bad merge */ | ||
1001 | Sey += mdf_inner_prod(st->e+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size); | ||
1002 | Syy += mdf_inner_prod(st->y+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size); | ||
1003 | Sdd += mdf_inner_prod(st->input+chan*st->frame_size, st->input+chan*st->frame_size, st->frame_size); | ||
1004 | |||
1005 | /* Convert error to frequency domain */ | ||
1006 | spx_fft(st->fft_table, st->e+chan*N, st->E+chan*N); | ||
1007 | for (i=0;i<st->frame_size;i++) | ||
1008 | st->y[i+chan*N] = 0; | ||
1009 | spx_fft(st->fft_table, st->y+chan*N, st->Y+chan*N); | ||
1010 | |||
1011 | /* Compute power spectrum of echo (X), error (E) and filter response (Y) */ | ||
1012 | power_spectrum_accum(st->E+chan*N, st->Rf, N); | ||
1013 | power_spectrum_accum(st->Y+chan*N, st->Yf, N); | ||
1014 | |||
906 | } | 1015 | } |
907 | 1016 | ||
908 | /* Compute a bunch of correlations */ | ||
909 | Sey = mdf_inner_prod(st->e+st->frame_size, st->y+st->frame_size, st->frame_size); | ||
910 | Syy = mdf_inner_prod(st->y+st->frame_size, st->y+st->frame_size, st->frame_size); | ||
911 | Sdd = mdf_inner_prod(st->input, st->input, st->frame_size); | ||
912 | |||
913 | /*printf ("%f %f %f %f\n", Sff, See, Syy, Sdd, st->update_cond);*/ | 1017 | /*printf ("%f %f %f %f\n", Sff, See, Syy, Sdd, st->update_cond);*/ |
914 | 1018 | ||
915 | /* Do some sanity check */ | 1019 | /* Do some sanity check */ |
916 | if (!(Syy>=0 && Sxx>=0 && See >= 0) | 1020 | if (!(Syy>=0 && Sxx>=0 && See >= 0) |
917 | #ifndef FIXED_POINT | 1021 | #ifndef FIXED_POINT |
@@ -921,7 +1025,7 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp | |||
921 | { | 1025 | { |
922 | /* Things have gone really bad */ | 1026 | /* Things have gone really bad */ |
923 | st->screwed_up += 50; | 1027 | st->screwed_up += 50; |
924 | for (i=0;i<st->frame_size;i++) | 1028 | for (i=0;i<st->frame_size*C;i++) |
925 | out[i] = 0; | 1029 | out[i] = 0; |
926 | } else if (SHR32(Sff, 2) > ADD32(Sdd, SHR32(MULT16_16(N, 10000),6))) | 1030 | } else if (SHR32(Sff, 2) > ADD32(Sdd, SHR32(MULT16_16(N, 10000),6))) |
927 | { | 1031 | { |
@@ -941,35 +1045,16 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp | |||
941 | /* Add a small noise floor to make sure not to have problems when dividing */ | 1045 | /* Add a small noise floor to make sure not to have problems when dividing */ |
942 | See = MAX32(See, SHR32(MULT16_16(N, 100),6)); | 1046 | See = MAX32(See, SHR32(MULT16_16(N, 100),6)); |
943 | 1047 | ||
944 | /* Convert error to frequency domain */ | 1048 | for (speak = 0; speak < K; speak++) |
945 | spx_fft(st->fft_table, st->e, st->E); | 1049 | { |
946 | for (i=0;i<st->frame_size;i++) | 1050 | Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size); |
947 | st->y[i] = 0; | 1051 | power_spectrum_accum(st->X+speak*N, st->Xf, N); |
948 | spx_fft(st->fft_table, st->y, st->Y); | 1052 | } |
1053 | |||
949 | 1054 | ||
950 | /* Compute power spectrum of far end (X), error (E) and filter response (Y) */ | ||
951 | power_spectrum(st->E, st->Rf, N); | ||
952 | power_spectrum(st->Y, st->Yf, N); | ||
953 | power_spectrum(st->X, st->Xf, N); | ||
954 | |||
955 | /* Smooth far end energy estimate over time */ | 1055 | /* Smooth far end energy estimate over time */ |
956 | for (j=0;j<=st->frame_size;j++) | 1056 | for (j=0;j<=st->frame_size;j++) |
957 | st->power[j] = MULT16_32_Q15(ss_1,st->power[j]) + 1 + MULT16_32_Q15(ss,st->Xf[j]); | 1057 | st->power[j] = MULT16_32_Q15(ss_1,st->power[j]) + 1 + MULT16_32_Q15(ss,st->Xf[j]); |
958 | |||
959 | /* Enable this to compute the power based only on the tail (would need to compute more | ||
960 | efficiently to make this really useful */ | ||
961 | if (0) | ||
962 | { | ||
963 | float scale2 = .5f/M; | ||
964 | for (j=0;j<=st->frame_size;j++) | ||
965 | st->power[j] = 100; | ||
966 | for (i=0;i<M;i++) | ||
967 | { | ||
968 | power_spectrum(&st->X[i*N], st->Xf, N); | ||
969 | for (j=0;j<=st->frame_size;j++) | ||
970 | st->power[j] += scale2*st->Xf[j]; | ||
971 | } | ||
972 | } | ||
973 | 1058 | ||
974 | /* Compute filtered spectra and (cross-)correlations */ | 1059 | /* Compute filtered spectra and (cross-)correlations */ |
975 | for (j=st->frame_size;j>=0;j--) | 1060 | for (j=st->frame_size;j>=0;j--) |
@@ -987,7 +1072,7 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp | |||
987 | st->Yh[j] = (1-st->spec_average)*st->Yh[j] + st->spec_average*st->Yf[j]; | 1072 | st->Yh[j] = (1-st->spec_average)*st->Yh[j] + st->spec_average*st->Yf[j]; |
988 | #endif | 1073 | #endif |
989 | } | 1074 | } |
990 | 1075 | ||
991 | Pyy = FLOAT_SQRT(Pyy); | 1076 | Pyy = FLOAT_SQRT(Pyy); |
992 | Pey = FLOAT_DIVU(Pey,Pyy); | 1077 | Pey = FLOAT_DIVU(Pey,Pyy); |
993 | 1078 | ||
@@ -1015,7 +1100,7 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp | |||
1015 | else | 1100 | else |
1016 | st->leak_estimate = SHL16(st->leak_estimate,1); | 1101 | st->leak_estimate = SHL16(st->leak_estimate,1); |
1017 | /*printf ("%f\n", st->leak_estimate);*/ | 1102 | /*printf ("%f\n", st->leak_estimate);*/ |
1018 | 1103 | ||
1019 | /* Compute Residual to Error Ratio */ | 1104 | /* Compute Residual to Error Ratio */ |
1020 | #ifdef FIXED_POINT | 1105 | #ifdef FIXED_POINT |
1021 | tmp32 = MULT16_32_Q15(st->leak_estimate,Syy); | 1106 | tmp32 = MULT16_32_Q15(st->leak_estimate,Syy); |
@@ -1071,7 +1156,7 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp | |||
1071 | /* Temporary adaption rate if filter is not yet adapted enough */ | 1156 | /* Temporary adaption rate if filter is not yet adapted enough */ |
1072 | spx_word16_t adapt_rate=0; | 1157 | spx_word16_t adapt_rate=0; |
1073 | 1158 | ||
1074 | if (Sxx > SHR32(MULT16_16(N, 1000),6)) | 1159 | if (Sxx > SHR32(MULT16_16(N, 1000),6)) |
1075 | { | 1160 | { |
1076 | tmp32 = MULT16_32_Q15(QCONST16(.25f, 15), Sxx); | 1161 | tmp32 = MULT16_32_Q15(QCONST16(.25f, 15), Sxx); |
1077 | #ifdef FIXED_POINT | 1162 | #ifdef FIXED_POINT |
@@ -1091,13 +1176,13 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp | |||
1091 | st->sum_adapt = ADD32(st->sum_adapt,adapt_rate); | 1176 | st->sum_adapt = ADD32(st->sum_adapt,adapt_rate); |
1092 | } | 1177 | } |
1093 | 1178 | ||
1094 | /* Save residual echo so it can be used by the nonlinear processor */ | 1179 | /* FIXME: MC conversion required */ |
1180 | for (i=0;i<st->frame_size;i++) | ||
1181 | st->last_y[i] = st->last_y[st->frame_size+i]; | ||
1095 | if (st->adapted) | 1182 | if (st->adapted) |
1096 | { | 1183 | { |
1097 | /* If the filter is adapted, take the filtered echo */ | 1184 | /* If the filter is adapted, take the filtered echo */ |
1098 | for (i=0;i<st->frame_size;i++) | 1185 | for (i=0;i<st->frame_size;i++) |
1099 | st->last_y[i] = st->last_y[st->frame_size+i]; | ||
1100 | for (i=0;i<st->frame_size;i++) | ||
1101 | st->last_y[st->frame_size+i] = in[i]-out[i]; | 1186 | st->last_y[st->frame_size+i] = in[i]-out[i]; |
1102 | } else { | 1187 | } else { |
1103 | /* If filter isn't adapted yet, all we can do is take the far end signal directly */ | 1188 | /* If filter isn't adapted yet, all we can do is take the far end signal directly */ |
@@ -1113,17 +1198,17 @@ void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *residual_echo, in | |||
1113 | int i; | 1198 | int i; |
1114 | spx_word16_t leak2; | 1199 | spx_word16_t leak2; |
1115 | int N; | 1200 | int N; |
1116 | 1201 | ||
1117 | N = st->window_size; | 1202 | N = st->window_size; |
1118 | 1203 | ||
1119 | /* Apply hanning window (should pre-compute it)*/ | 1204 | /* Apply hanning window (should pre-compute it)*/ |
1120 | for (i=0;i<N;i++) | 1205 | for (i=0;i<N;i++) |
1121 | st->y[i] = MULT16_16_Q15(st->window[i],st->last_y[i]); | 1206 | st->y[i] = MULT16_16_Q15(st->window[i],st->last_y[i]); |
1122 | 1207 | ||
1123 | /* Compute power spectrum of the echo */ | 1208 | /* Compute power spectrum of the echo */ |
1124 | spx_fft(st->fft_table, st->y, st->Y); | 1209 | spx_fft(st->fft_table, st->y, st->Y); |
1125 | power_spectrum(st->Y, residual_echo, N); | 1210 | power_spectrum(st->Y, residual_echo, N); |
1126 | 1211 | ||
1127 | #ifdef FIXED_POINT | 1212 | #ifdef FIXED_POINT |
1128 | if (st->leak_estimate > 16383) | 1213 | if (st->leak_estimate > 16383) |
1129 | leak2 = 32767; | 1214 | leak2 = 32767; |
@@ -1138,14 +1223,14 @@ void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *residual_echo, in | |||
1138 | /* Estimate residual echo */ | 1223 | /* Estimate residual echo */ |
1139 | for (i=0;i<=st->frame_size;i++) | 1224 | for (i=0;i<=st->frame_size;i++) |
1140 | residual_echo[i] = (spx_int32_t)MULT16_32_Q15(leak2,residual_echo[i]); | 1225 | residual_echo[i] = (spx_int32_t)MULT16_32_Q15(leak2,residual_echo[i]); |
1141 | 1226 | ||
1142 | } | 1227 | } |
1143 | 1228 | ||
1144 | int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr) | 1229 | EXPORT int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr) |
1145 | { | 1230 | { |
1146 | switch(request) | 1231 | switch(request) |
1147 | { | 1232 | { |
1148 | 1233 | ||
1149 | case SPEEX_ECHO_GET_FRAME_SIZE: | 1234 | case SPEEX_ECHO_GET_FRAME_SIZE: |
1150 | (*(int*)ptr) = st->frame_size; | 1235 | (*(int*)ptr) = st->frame_size; |
1151 | break; | 1236 | break; |
@@ -1169,6 +1254,29 @@ int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr) | |||
1169 | case SPEEX_ECHO_GET_SAMPLING_RATE: | 1254 | case SPEEX_ECHO_GET_SAMPLING_RATE: |
1170 | (*(int*)ptr) = st->sampling_rate; | 1255 | (*(int*)ptr) = st->sampling_rate; |
1171 | break; | 1256 | break; |
1257 | case SPEEX_ECHO_GET_IMPULSE_RESPONSE_SIZE: | ||
1258 | /*FIXME: Implement this for multiple channels */ | ||
1259 | *((spx_int32_t *)ptr) = st->M * st->frame_size; | ||
1260 | break; | ||
1261 | case SPEEX_ECHO_GET_IMPULSE_RESPONSE: | ||
1262 | { | ||
1263 | int M = st->M, N = st->window_size, n = st->frame_size, i, j; | ||
1264 | spx_int32_t *filt = (spx_int32_t *) ptr; | ||
1265 | for(j=0;j<M;j++) | ||
1266 | { | ||
1267 | /*FIXME: Implement this for multiple channels */ | ||
1268 | #ifdef FIXED_POINT | ||
1269 | for (i=0;i<N;i++) | ||
1270 | st->wtmp2[i] = EXTRACT16(PSHR32(st->W[j*N+i],16+NORMALIZE_SCALEDOWN)); | ||
1271 | spx_ifft(st->fft_table, st->wtmp2, st->wtmp); | ||
1272 | #else | ||
1273 | spx_ifft(st->fft_table, &st->W[j*N], st->wtmp); | ||
1274 | #endif | ||
1275 | for(i=0;i<n;i++) | ||
1276 | filt[j*n+i] = PSHR32(MULT16_16(32767,st->wtmp[i]), WEIGHT_SHIFT-NORMALIZE_SCALEDOWN); | ||
1277 | } | ||
1278 | } | ||
1279 | break; | ||
1172 | default: | 1280 | default: |
1173 | speex_warning_int("Unknown speex_echo_ctl request: ", request); | 1281 | speex_warning_int("Unknown speex_echo_ctl request: ", request); |
1174 | return -1; | 1282 | return -1; |
diff --git a/lib/rbcodec/codecs/libspeex/modes.c b/lib/rbcodec/codecs/libspeex/modes.c index a58c0786dd..881ff91368 100644 --- a/lib/rbcodec/codecs/libspeex/modes.c +++ b/lib/rbcodec/codecs/libspeex/modes.c | |||
@@ -450,7 +450,7 @@ static const SpeexNBMode nb_mode = { | |||
450 | 450 | ||
451 | 451 | ||
452 | /* Default mode for narrowband */ | 452 | /* Default mode for narrowband */ |
453 | const SpeexMode speex_nb_mode = { | 453 | EXPORT const SpeexMode speex_nb_mode = { |
454 | &nb_mode, | 454 | &nb_mode, |
455 | nb_mode_query, | 455 | nb_mode_query, |
456 | "narrowband", | 456 | "narrowband", |
@@ -479,8 +479,12 @@ const SpeexMode speex_nb_mode = { | |||
479 | 479 | ||
480 | 480 | ||
481 | 481 | ||
482 | int speex_mode_query(const SpeexMode *mode, int request, void *ptr) | 482 | EXPORT int speex_mode_query(const SpeexMode *mode, int request, void *ptr) |
483 | { | 483 | { |
484 | return mode->query(mode->mode, request, ptr); | 484 | return mode->query(mode->mode, request, ptr); |
485 | } | 485 | } |
486 | 486 | ||
487 | #ifdef FIXED_DEBUG | ||
488 | long long spx_mips=0; | ||
489 | #endif | ||
490 | |||
diff --git a/lib/rbcodec/codecs/libspeex/modes_wb.c b/lib/rbcodec/codecs/libspeex/modes_wb.c index 5438551c1b..4fe1ef08fc 100644 --- a/lib/rbcodec/codecs/libspeex/modes_wb.c +++ b/lib/rbcodec/codecs/libspeex/modes_wb.c | |||
@@ -55,9 +55,9 @@ | |||
55 | #endif | 55 | #endif |
56 | 56 | ||
57 | #ifndef ROCKBOX_VOICE_CODEC | 57 | #ifndef ROCKBOX_VOICE_CODEC |
58 | const SpeexMode * const speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, &speex_uwb_mode}; | 58 | EXPORT const SpeexMode * const speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, &speex_uwb_mode}; |
59 | #else | 59 | #else |
60 | const SpeexMode * const speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, NULL}; | 60 | EXPORT const SpeexMode * const speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, NULL}; |
61 | #endif | 61 | #endif |
62 | 62 | ||
63 | extern const signed char hexc_table[]; | 63 | extern const signed char hexc_table[]; |
@@ -250,7 +250,7 @@ static const SpeexSBMode sb_wb_mode = { | |||
250 | }; | 250 | }; |
251 | 251 | ||
252 | 252 | ||
253 | const SpeexMode speex_wb_mode = { | 253 | EXPORT const SpeexMode speex_wb_mode = { |
254 | &sb_wb_mode, | 254 | &sb_wb_mode, |
255 | wb_mode_query, | 255 | wb_mode_query, |
256 | "wideband (sub-band CELP)", | 256 | "wideband (sub-band CELP)", |
@@ -285,7 +285,7 @@ const SpeexMode speex_wb_mode = { | |||
285 | 285 | ||
286 | #ifndef ROCKBOX_VOICE_CODEC | 286 | #ifndef ROCKBOX_VOICE_CODEC |
287 | /* Split-band "ultra-wideband" (32 kbps) CELP mode*/ | 287 | /* Split-band "ultra-wideband" (32 kbps) CELP mode*/ |
288 | static const SpeexSBMode sb_uwb_mode = { | 288 | EXPORT static const SpeexSBMode sb_uwb_mode = { |
289 | &speex_wb_mode, | 289 | &speex_wb_mode, |
290 | 320, /*frameSize*/ | 290 | 320, /*frameSize*/ |
291 | 80, /*subframeSize*/ | 291 | 80, /*subframeSize*/ |
@@ -365,7 +365,7 @@ const SpeexMode speex_uwb_mode = { | |||
365 | /* We have defined speex_lib_get_mode() as a macro in speex.h */ | 365 | /* We have defined speex_lib_get_mode() as a macro in speex.h */ |
366 | #undef speex_lib_get_mode | 366 | #undef speex_lib_get_mode |
367 | 367 | ||
368 | const SpeexMode * speex_lib_get_mode (int mode) | 368 | EXPORT const SpeexMode * speex_lib_get_mode (int mode) |
369 | { | 369 | { |
370 | if (mode < 0 || mode >= SPEEX_NB_MODES) return NULL; | 370 | if (mode < 0 || mode >= SPEEX_NB_MODES) return NULL; |
371 | 371 | ||
diff --git a/lib/rbcodec/codecs/libspeex/preprocess.c b/lib/rbcodec/codecs/libspeex/preprocess.c index 07a2ad3479..58d213a0a9 100644 --- a/lib/rbcodec/codecs/libspeex/preprocess.c +++ b/lib/rbcodec/codecs/libspeex/preprocess.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* Copyright (C) 2003 Epic Games (written by Jean-Marc Valin) | 1 | /* Copyright (C) 2003 Epic Games (written by Jean-Marc Valin) |
2 | Copyright (C) 2004-2006 Epic Games | 2 | Copyright (C) 2004-2006 Epic Games |
3 | 3 | ||
4 | File: preprocess.c | 4 | File: preprocess.c |
5 | Preprocessor with denoising based on the algorithm by Ephraim and Malah | 5 | Preprocessor with denoising based on the algorithm by Ephraim and Malah |
6 | 6 | ||
@@ -34,24 +34,24 @@ | |||
34 | 34 | ||
35 | /* | 35 | /* |
36 | Recommended papers: | 36 | Recommended papers: |
37 | 37 | ||
38 | Y. Ephraim and D. Malah, "Speech enhancement using minimum mean-square error | 38 | Y. Ephraim and D. Malah, "Speech enhancement using minimum mean-square error |
39 | short-time spectral amplitude estimator". IEEE Transactions on Acoustics, | 39 | short-time spectral amplitude estimator". IEEE Transactions on Acoustics, |
40 | Speech and Signal Processing, vol. ASSP-32, no. 6, pp. 1109-1121, 1984. | 40 | Speech and Signal Processing, vol. ASSP-32, no. 6, pp. 1109-1121, 1984. |
41 | 41 | ||
42 | Y. Ephraim and D. Malah, "Speech enhancement using minimum mean-square error | 42 | Y. Ephraim and D. Malah, "Speech enhancement using minimum mean-square error |
43 | log-spectral amplitude estimator". IEEE Transactions on Acoustics, Speech and | 43 | log-spectral amplitude estimator". IEEE Transactions on Acoustics, Speech and |
44 | Signal Processing, vol. ASSP-33, no. 2, pp. 443-445, 1985. | 44 | Signal Processing, vol. ASSP-33, no. 2, pp. 443-445, 1985. |
45 | 45 | ||
46 | I. Cohen and B. Berdugo, "Speech enhancement for non-stationary noise environments". | 46 | I. Cohen and B. Berdugo, "Speech enhancement for non-stationary noise environments". |
47 | Signal Processing, vol. 81, no. 2, pp. 2403-2418, 2001. | 47 | Signal Processing, vol. 81, no. 2, pp. 2403-2418, 2001. |
48 | 48 | ||
49 | Stefan Gustafsson, Rainer Martin, Peter Jax, and Peter Vary. "A psychoacoustic | 49 | Stefan Gustafsson, Rainer Martin, Peter Jax, and Peter Vary. "A psychoacoustic |
50 | approach to combined acoustic echo cancellation and noise reduction". IEEE | 50 | approach to combined acoustic echo cancellation and noise reduction". IEEE |
51 | Transactions on Speech and Audio Processing, 2002. | 51 | Transactions on Speech and Audio Processing, 2002. |
52 | 52 | ||
53 | J.-M. Valin, J. Rouat, and F. Michaud, "Microphone array post-filter for separation | 53 | J.-M. Valin, J. Rouat, and F. Michaud, "Microphone array post-filter for separation |
54 | of simultaneous non-stationary sources". In Proceedings IEEE International | 54 | of simultaneous non-stationary sources". In Proceedings IEEE International |
55 | Conference on Acoustics, Speech, and Signal Processing, 2004. | 55 | Conference on Acoustics, Speech, and Signal Processing, 2004. |
56 | */ | 56 | */ |
57 | 57 | ||
@@ -75,7 +75,7 @@ | |||
75 | #define LOUDNESS_EXP 5.f | 75 | #define LOUDNESS_EXP 5.f |
76 | #define AMP_SCALE .001f | 76 | #define AMP_SCALE .001f |
77 | #define AMP_SCALE_1 1000.f | 77 | #define AMP_SCALE_1 1000.f |
78 | 78 | ||
79 | #define NB_BANDS 24 | 79 | #define NB_BANDS 24 |
80 | 80 | ||
81 | #define SPEECH_PROB_START_DEFAULT QCONST16(0.35f,15) | 81 | #define SPEECH_PROB_START_DEFAULT QCONST16(0.35f,15) |
@@ -117,7 +117,7 @@ static inline spx_word16_t DIV32_16_Q8(spx_word32_t a, spx_word32_t b) | |||
117 | a = SHL32(a,8); | 117 | a = SHL32(a,8); |
118 | return PDIV32_16(a,b); | 118 | return PDIV32_16(a,b); |
119 | } | 119 | } |
120 | 120 | ||
121 | } | 121 | } |
122 | static inline spx_word16_t DIV32_16_Q15(spx_word32_t a, spx_word32_t b) | 122 | static inline spx_word16_t DIV32_16_Q15(spx_word32_t a, spx_word32_t b) |
123 | { | 123 | { |
@@ -185,7 +185,7 @@ struct SpeexPreprocessState_ { | |||
185 | int sampling_rate; /**< Sampling rate of the input/output */ | 185 | int sampling_rate; /**< Sampling rate of the input/output */ |
186 | int nbands; | 186 | int nbands; |
187 | FilterBank *bank; | 187 | FilterBank *bank; |
188 | 188 | ||
189 | /* Parameters */ | 189 | /* Parameters */ |
190 | int denoise_enabled; | 190 | int denoise_enabled; |
191 | int vad_enabled; | 191 | int vad_enabled; |
@@ -198,7 +198,9 @@ struct SpeexPreprocessState_ { | |||
198 | int echo_suppress; | 198 | int echo_suppress; |
199 | int echo_suppress_active; | 199 | int echo_suppress_active; |
200 | SpeexEchoState *echo_state; | 200 | SpeexEchoState *echo_state; |
201 | 201 | ||
202 | spx_word16_t speech_prob; /**< Probability last frame was speech */ | ||
203 | |||
202 | /* DSP-related arrays */ | 204 | /* DSP-related arrays */ |
203 | spx_word16_t *frame; /**< Processing frame (2*ps_size) */ | 205 | spx_word16_t *frame; /**< Processing frame (2*ps_size) */ |
204 | spx_word16_t *ft; /**< Processing frame in freq domain (2*ps_size) */ | 206 | spx_word16_t *ft; /**< Processing frame in freq domain (2*ps_size) */ |
@@ -234,7 +236,6 @@ struct SpeexPreprocessState_ { | |||
234 | float *loudness_weight; /**< Perceptual loudness curve */ | 236 | float *loudness_weight; /**< Perceptual loudness curve */ |
235 | float loudness; /**< Loudness estimate */ | 237 | float loudness; /**< Loudness estimate */ |
236 | float agc_gain; /**< Current AGC gain */ | 238 | float agc_gain; /**< Current AGC gain */ |
237 | int nb_loudness_adapt; /**< Number of frames used for loudness adaptation so far */ | ||
238 | float max_gain; /**< Maximum gain allowed */ | 239 | float max_gain; /**< Maximum gain allowed */ |
239 | float max_increase_step; /**< Maximum increase in gain from one frame to another */ | 240 | float max_increase_step; /**< Maximum increase in gain from one frame to another */ |
240 | float max_decrease_step; /**< Maximum decrease in gain from one frame to another */ | 241 | float max_decrease_step; /**< Maximum decrease in gain from one frame to another */ |
@@ -259,7 +260,7 @@ static void conj_window(spx_word16_t *w, int len) | |||
259 | spx_word16_t tmp; | 260 | spx_word16_t tmp; |
260 | #ifdef FIXED_POINT | 261 | #ifdef FIXED_POINT |
261 | spx_word16_t x = DIV32_16(MULT16_16(32767,i),len); | 262 | spx_word16_t x = DIV32_16(MULT16_16(32767,i),len); |
262 | #else | 263 | #else |
263 | spx_word16_t x = DIV32_16(MULT16_16(QCONST16(4.f,13),i),len); | 264 | spx_word16_t x = DIV32_16(MULT16_16(QCONST16(4.f,13),i),len); |
264 | #endif | 265 | #endif |
265 | int inv=0; | 266 | int inv=0; |
@@ -284,10 +285,10 @@ static void conj_window(spx_word16_t *w, int len) | |||
284 | } | 285 | } |
285 | } | 286 | } |
286 | 287 | ||
287 | 288 | ||
288 | #ifdef FIXED_POINT | 289 | #ifdef FIXED_POINT |
289 | /* This function approximates the gain function | 290 | /* This function approximates the gain function |
290 | y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x) | 291 | y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x) |
291 | which multiplied by xi/(1+xi) is the optimal gain | 292 | which multiplied by xi/(1+xi) is the optimal gain |
292 | in the loudness domain ( sqrt[amplitude] ) | 293 | in the loudness domain ( sqrt[amplitude] ) |
293 | Input in Q11 format, output in Q15 | 294 | Input in Q11 format, output in Q15 |
@@ -320,7 +321,7 @@ static inline spx_word16_t qcurve(spx_word16_t x) | |||
320 | static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, spx_word32_t *noise, spx_word32_t *echo, spx_word16_t *gain_floor, int len) | 321 | static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, spx_word32_t *noise, spx_word32_t *echo, spx_word16_t *gain_floor, int len) |
321 | { | 322 | { |
322 | int i; | 323 | int i; |
323 | 324 | ||
324 | if (noise_suppress > effective_echo_suppress) | 325 | if (noise_suppress > effective_echo_suppress) |
325 | { | 326 | { |
326 | spx_word16_t noise_gain, gain_ratio; | 327 | spx_word16_t noise_gain, gain_ratio; |
@@ -346,8 +347,8 @@ static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, | |||
346 | } | 347 | } |
347 | 348 | ||
348 | #else | 349 | #else |
349 | /* This function approximates the gain function | 350 | /* This function approximates the gain function |
350 | y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x) | 351 | y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x) |
351 | which multiplied by xi/(1+xi) is the optimal gain | 352 | which multiplied by xi/(1+xi) is the optimal gain |
352 | in the loudness domain ( sqrt[amplitude] ) | 353 | in the loudness domain ( sqrt[amplitude] ) |
353 | */ | 354 | */ |
@@ -391,7 +392,7 @@ static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, | |||
391 | } | 392 | } |
392 | 393 | ||
393 | #endif | 394 | #endif |
394 | SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_rate) | 395 | EXPORT SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_rate) |
395 | { | 396 | { |
396 | int i; | 397 | int i; |
397 | int N, N3, N4, M; | 398 | int N, N3, N4, M; |
@@ -413,8 +414,8 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r | |||
413 | break; | 414 | break; |
414 | } | 415 | } |
415 | } | 416 | } |
416 | 417 | ||
417 | 418 | ||
418 | if (st->ps_size < 3*st->frame_size/4) | 419 | if (st->ps_size < 3*st->frame_size/4) |
419 | st->ps_size = st->ps_size * 3 / 2; | 420 | st->ps_size = st->ps_size * 3 / 2; |
420 | #else | 421 | #else |
@@ -424,7 +425,7 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r | |||
424 | N = st->ps_size; | 425 | N = st->ps_size; |
425 | N3 = 2*N - st->frame_size; | 426 | N3 = 2*N - st->frame_size; |
426 | N4 = st->frame_size - N3; | 427 | N4 = st->frame_size - N3; |
427 | 428 | ||
428 | st->sampling_rate = sampling_rate; | 429 | st->sampling_rate = sampling_rate; |
429 | st->denoise_enabled = 1; | 430 | st->denoise_enabled = 1; |
430 | st->vad_enabled = 0; | 431 | st->vad_enabled = 0; |
@@ -439,15 +440,15 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r | |||
439 | st->speech_prob_continue = SPEECH_PROB_CONTINUE_DEFAULT; | 440 | st->speech_prob_continue = SPEECH_PROB_CONTINUE_DEFAULT; |
440 | 441 | ||
441 | st->echo_state = NULL; | 442 | st->echo_state = NULL; |
442 | 443 | ||
443 | st->nbands = NB_BANDS; | 444 | st->nbands = NB_BANDS; |
444 | M = st->nbands; | 445 | M = st->nbands; |
445 | st->bank = filterbank_new(M, sampling_rate, N, 1); | 446 | st->bank = filterbank_new(M, sampling_rate, N, 1); |
446 | 447 | ||
447 | st->frame = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); | 448 | st->frame = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); |
448 | st->window = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); | 449 | st->window = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); |
449 | st->ft = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); | 450 | st->ft = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); |
450 | 451 | ||
451 | st->ps = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); | 452 | st->ps = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); |
452 | st->noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); | 453 | st->noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); |
453 | st->echo_noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); | 454 | st->echo_noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); |
@@ -460,19 +461,19 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r | |||
460 | st->gain2 = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); | 461 | st->gain2 = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); |
461 | st->gain_floor = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); | 462 | st->gain_floor = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); |
462 | st->zeta = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); | 463 | st->zeta = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); |
463 | 464 | ||
464 | st->S = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); | 465 | st->S = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); |
465 | st->Smin = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); | 466 | st->Smin = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); |
466 | st->Stmp = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); | 467 | st->Stmp = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); |
467 | st->update_prob = (int*)speex_alloc(N*sizeof(int)); | 468 | st->update_prob = (int*)speex_alloc(N*sizeof(int)); |
468 | 469 | ||
469 | st->inbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t)); | 470 | st->inbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t)); |
470 | st->outbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t)); | 471 | st->outbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t)); |
471 | 472 | ||
472 | conj_window(st->window, 2*N3); | 473 | conj_window(st->window, 2*N3); |
473 | for (i=2*N3;i<2*st->ps_size;i++) | 474 | for (i=2*N3;i<2*st->ps_size;i++) |
474 | st->window[i]=Q15_ONE; | 475 | st->window[i]=Q15_ONE; |
475 | 476 | ||
476 | if (N4>0) | 477 | if (N4>0) |
477 | { | 478 | { |
478 | for (i=N3-1;i>=0;i--) | 479 | for (i=N3-1;i>=0;i--) |
@@ -514,7 +515,6 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r | |||
514 | /*st->loudness = pow(AMP_SCALE*st->agc_level,LOUDNESS_EXP);*/ | 515 | /*st->loudness = pow(AMP_SCALE*st->agc_level,LOUDNESS_EXP);*/ |
515 | st->loudness = 1e-15; | 516 | st->loudness = 1e-15; |
516 | st->agc_gain = 1; | 517 | st->agc_gain = 1; |
517 | st->nb_loudness_adapt = 0; | ||
518 | st->max_gain = 30; | 518 | st->max_gain = 30; |
519 | st->max_increase_step = exp(0.11513f * 12.*st->frame_size / st->sampling_rate); | 519 | st->max_increase_step = exp(0.11513f * 12.*st->frame_size / st->sampling_rate); |
520 | st->max_decrease_step = exp(-0.11513f * 40.*st->frame_size / st->sampling_rate); | 520 | st->max_decrease_step = exp(-0.11513f * 40.*st->frame_size / st->sampling_rate); |
@@ -530,7 +530,7 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r | |||
530 | return st; | 530 | return st; |
531 | } | 531 | } |
532 | 532 | ||
533 | void speex_preprocess_state_destroy(SpeexPreprocessState *st) | 533 | EXPORT void speex_preprocess_state_destroy(SpeexPreprocessState *st) |
534 | { | 534 | { |
535 | speex_free(st->frame); | 535 | speex_free(st->frame); |
536 | speex_free(st->ft); | 536 | speex_free(st->ft); |
@@ -573,7 +573,7 @@ static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx | |||
573 | float target_gain; | 573 | float target_gain; |
574 | float loudness=1.f; | 574 | float loudness=1.f; |
575 | float rate; | 575 | float rate; |
576 | 576 | ||
577 | for (i=2;i<N;i++) | 577 | for (i=2;i<N;i++) |
578 | { | 578 | { |
579 | loudness += 2.f*N*st->ps[i]* st->loudness_weight[i]; | 579 | loudness += 2.f*N*st->ps[i]* st->loudness_weight[i]; |
@@ -583,7 +583,6 @@ static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx | |||
583 | loudness*2 > pow(st->loudness, 1.0/LOUDNESS_EXP))*/ | 583 | loudness*2 > pow(st->loudness, 1.0/LOUDNESS_EXP))*/ |
584 | if (Pframe>.3f) | 584 | if (Pframe>.3f) |
585 | { | 585 | { |
586 | st->nb_loudness_adapt++; | ||
587 | /*rate=2.0f*Pframe*Pframe/(1+st->nb_loudness_adapt);*/ | 586 | /*rate=2.0f*Pframe*Pframe/(1+st->nb_loudness_adapt);*/ |
588 | rate = .03*Pframe*Pframe; | 587 | rate = .03*Pframe*Pframe; |
589 | st->loudness = (1-rate)*st->loudness + (rate)*pow(AMP_SCALE*loudness, LOUDNESS_EXP); | 588 | st->loudness = (1-rate)*st->loudness + (rate)*pow(AMP_SCALE*loudness, LOUDNESS_EXP); |
@@ -592,7 +591,7 @@ static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx | |||
592 | st->init_max *= 1.f + .1f*Pframe*Pframe; | 591 | st->init_max *= 1.f + .1f*Pframe*Pframe; |
593 | } | 592 | } |
594 | /*printf ("%f %f %f %f\n", Pframe, loudness, pow(st->loudness, 1.0f/LOUDNESS_EXP), st->loudness2);*/ | 593 | /*printf ("%f %f %f %f\n", Pframe, loudness, pow(st->loudness, 1.0f/LOUDNESS_EXP), st->loudness2);*/ |
595 | 594 | ||
596 | target_gain = AMP_SCALE*st->agc_level*pow(st->loudness/(1e-4+st->loudness_accum), -1.0f/LOUDNESS_EXP); | 595 | target_gain = AMP_SCALE*st->agc_level*pow(st->loudness/(1e-4+st->loudness_accum), -1.0f/LOUDNESS_EXP); |
597 | 596 | ||
598 | if ((Pframe>.5 && st->nb_adapt > 20) || target_gain < st->agc_gain) | 597 | if ((Pframe>.5 && st->nb_adapt > 20) || target_gain < st->agc_gain) |
@@ -605,11 +604,11 @@ static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx | |||
605 | target_gain = st->max_gain; | 604 | target_gain = st->max_gain; |
606 | if (target_gain > st->init_max) | 605 | if (target_gain > st->init_max) |
607 | target_gain = st->init_max; | 606 | target_gain = st->init_max; |
608 | 607 | ||
609 | st->agc_gain = target_gain; | 608 | st->agc_gain = target_gain; |
610 | } | 609 | } |
611 | /*fprintf (stderr, "%f %f %f\n", loudness, (float)AMP_SCALE_1*pow(st->loudness, 1.0f/LOUDNESS_EXP), st->agc_gain);*/ | 610 | /*fprintf (stderr, "%f %f %f\n", loudness, (float)AMP_SCALE_1*pow(st->loudness, 1.0f/LOUDNESS_EXP), st->agc_gain);*/ |
612 | 611 | ||
613 | for (i=0;i<2*N;i++) | 612 | for (i=0;i<2*N;i++) |
614 | ft[i] *= st->agc_gain; | 613 | ft[i] *= st->agc_gain; |
615 | st->prev_loudness = loudness; | 614 | st->prev_loudness = loudness; |
@@ -629,7 +628,7 @@ static void preprocess_analysis(SpeexPreprocessState *st, spx_int16_t *x) | |||
629 | st->frame[i]=st->inbuf[i]; | 628 | st->frame[i]=st->inbuf[i]; |
630 | for (i=0;i<st->frame_size;i++) | 629 | for (i=0;i<st->frame_size;i++) |
631 | st->frame[N3+i]=x[i]; | 630 | st->frame[N3+i]=x[i]; |
632 | 631 | ||
633 | /* Update inbuf */ | 632 | /* Update inbuf */ |
634 | for (i=0;i<N3;i++) | 633 | for (i=0;i<N3;i++) |
635 | st->inbuf[i]=x[N4+i]; | 634 | st->inbuf[i]=x[N4+i]; |
@@ -648,10 +647,10 @@ static void preprocess_analysis(SpeexPreprocessState *st, spx_int16_t *x) | |||
648 | st->frame[i] = SHL16(st->frame[i], st->frame_shift); | 647 | st->frame[i] = SHL16(st->frame[i], st->frame_shift); |
649 | } | 648 | } |
650 | #endif | 649 | #endif |
651 | 650 | ||
652 | /* Perform FFT */ | 651 | /* Perform FFT */ |
653 | spx_fft(st->fft_lookup, st->frame, st->ft); | 652 | spx_fft(st->fft_lookup, st->frame, st->ft); |
654 | 653 | ||
655 | /* Power spectrum */ | 654 | /* Power spectrum */ |
656 | ps[0]=MULT16_16(st->ft[0],st->ft[0]); | 655 | ps[0]=MULT16_16(st->ft[0],st->ft[0]); |
657 | for (i=1;i<N;i++) | 656 | for (i=1;i<N;i++) |
@@ -669,11 +668,11 @@ static void update_noise_prob(SpeexPreprocessState *st) | |||
669 | int N = st->ps_size; | 668 | int N = st->ps_size; |
670 | 669 | ||
671 | for (i=1;i<N-1;i++) | 670 | for (i=1;i<N-1;i++) |
672 | st->S[i] = MULT16_32_Q15(QCONST16(.8f,15),st->S[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i-1]) | 671 | st->S[i] = MULT16_32_Q15(QCONST16(.8f,15),st->S[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i-1]) |
673 | + MULT16_32_Q15(QCONST16(.1f,15),st->ps[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i+1]); | 672 | + MULT16_32_Q15(QCONST16(.1f,15),st->ps[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i+1]); |
674 | st->S[0] = MULT16_32_Q15(QCONST16(.8f,15),st->S[0]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[0]); | 673 | st->S[0] = MULT16_32_Q15(QCONST16(.8f,15),st->S[0]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[0]); |
675 | st->S[N-1] = MULT16_32_Q15(QCONST16(.8f,15),st->S[N-1]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[N-1]); | 674 | st->S[N-1] = MULT16_32_Q15(QCONST16(.8f,15),st->S[N-1]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[N-1]); |
676 | 675 | ||
677 | if (st->nb_adapt==1) | 676 | if (st->nb_adapt==1) |
678 | { | 677 | { |
679 | for (i=0;i<N;i++) | 678 | for (i=0;i<N;i++) |
@@ -700,12 +699,12 @@ static void update_noise_prob(SpeexPreprocessState *st) | |||
700 | for (i=0;i<N;i++) | 699 | for (i=0;i<N;i++) |
701 | { | 700 | { |
702 | st->Smin[i] = MIN32(st->Smin[i], st->S[i]); | 701 | st->Smin[i] = MIN32(st->Smin[i], st->S[i]); |
703 | st->Stmp[i] = MIN32(st->Stmp[i], st->S[i]); | 702 | st->Stmp[i] = MIN32(st->Stmp[i], st->S[i]); |
704 | } | 703 | } |
705 | } | 704 | } |
706 | for (i=0;i<N;i++) | 705 | for (i=0;i<N;i++) |
707 | { | 706 | { |
708 | if (MULT16_32_Q15(QCONST16(.4f,15),st->S[i]) > ADD32(st->Smin[i],EXTEND32(20))) | 707 | if (MULT16_32_Q15(QCONST16(.4f,15),st->S[i]) > st->Smin[i]) |
709 | st->update_prob[i] = 1; | 708 | st->update_prob[i] = 1; |
710 | else | 709 | else |
711 | st->update_prob[i] = 0; | 710 | st->update_prob[i] = 0; |
@@ -719,12 +718,12 @@ static void update_noise_prob(SpeexPreprocessState *st) | |||
719 | 718 | ||
720 | void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len); | 719 | void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len); |
721 | 720 | ||
722 | int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo) | 721 | EXPORT int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo) |
723 | { | 722 | { |
724 | return speex_preprocess_run(st, x); | 723 | return speex_preprocess_run(st, x); |
725 | } | 724 | } |
726 | 725 | ||
727 | int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) | 726 | EXPORT int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) |
728 | { | 727 | { |
729 | int i; | 728 | int i; |
730 | int M; | 729 | int M; |
@@ -736,12 +735,12 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) | |||
736 | spx_word16_t Pframe; | 735 | spx_word16_t Pframe; |
737 | spx_word16_t beta, beta_1; | 736 | spx_word16_t beta, beta_1; |
738 | spx_word16_t effective_echo_suppress; | 737 | spx_word16_t effective_echo_suppress; |
739 | 738 | ||
740 | st->nb_adapt++; | 739 | st->nb_adapt++; |
741 | if (st->nb_adapt>20000) | 740 | if (st->nb_adapt>20000) |
742 | st->nb_adapt = 20000; | 741 | st->nb_adapt = 20000; |
743 | st->min_count++; | 742 | st->min_count++; |
744 | 743 | ||
745 | beta = MAX16(QCONST16(.03,15),DIV32_16(Q15_ONE,st->nb_adapt)); | 744 | beta = MAX16(QCONST16(.03,15),DIV32_16(Q15_ONE,st->nb_adapt)); |
746 | beta_1 = Q15_ONE-beta; | 745 | beta_1 = Q15_ONE-beta; |
747 | M = st->nbands; | 746 | M = st->nbands; |
@@ -775,7 +774,7 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) | |||
775 | st->update_prob[i] = 0; | 774 | st->update_prob[i] = 0; |
776 | } | 775 | } |
777 | */ | 776 | */ |
778 | 777 | ||
779 | /* Update the noise estimate for the frequencies where it can be */ | 778 | /* Update the noise estimate for the frequencies where it can be */ |
780 | for (i=0;i<N;i++) | 779 | for (i=0;i<N;i++) |
781 | { | 780 | { |
@@ -793,17 +792,17 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) | |||
793 | for (i=0;i<N+M;i++) | 792 | for (i=0;i<N+M;i++) |
794 | { | 793 | { |
795 | spx_word16_t gamma; | 794 | spx_word16_t gamma; |
796 | 795 | ||
797 | /* Total noise estimate including residual echo and reverberation */ | 796 | /* Total noise estimate including residual echo and reverberation */ |
798 | spx_word32_t tot_noise = ADD32(ADD32(ADD32(EXTEND32(1), PSHR32(st->noise[i],NOISE_SHIFT)) , st->echo_noise[i]) , st->reverb_estimate[i]); | 797 | spx_word32_t tot_noise = ADD32(ADD32(ADD32(EXTEND32(1), PSHR32(st->noise[i],NOISE_SHIFT)) , st->echo_noise[i]) , st->reverb_estimate[i]); |
799 | 798 | ||
800 | /* A posteriori SNR = ps/noise - 1*/ | 799 | /* A posteriori SNR = ps/noise - 1*/ |
801 | st->post[i] = SUB16(DIV32_16_Q8(ps[i],tot_noise), QCONST16(1.f,SNR_SHIFT)); | 800 | st->post[i] = SUB16(DIV32_16_Q8(ps[i],tot_noise), QCONST16(1.f,SNR_SHIFT)); |
802 | st->post[i]=MIN16(st->post[i], QCONST16(100.f,SNR_SHIFT)); | 801 | st->post[i]=MIN16(st->post[i], QCONST16(100.f,SNR_SHIFT)); |
803 | 802 | ||
804 | /* Computing update gamma = .1 + .9*(old/(old+noise))^2 */ | 803 | /* Computing update gamma = .1 + .9*(old/(old+noise))^2 */ |
805 | gamma = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.89f,15),SQR16_Q15(DIV32_16_Q15(st->old_ps[i],ADD32(st->old_ps[i],tot_noise)))); | 804 | gamma = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.89f,15),SQR16_Q15(DIV32_16_Q15(st->old_ps[i],ADD32(st->old_ps[i],tot_noise)))); |
806 | 805 | ||
807 | /* A priori SNR update = gamma*max(0,post) + (1-gamma)*old/noise */ | 806 | /* A priori SNR update = gamma*max(0,post) + (1-gamma)*old/noise */ |
808 | st->prior[i] = EXTRACT16(PSHR32(ADD32(MULT16_16(gamma,MAX16(0,st->post[i])), MULT16_16(Q15_ONE-gamma,DIV32_16_Q8(st->old_ps[i],tot_noise))), 15)); | 807 | st->prior[i] = EXTRACT16(PSHR32(ADD32(MULT16_16(gamma,MAX16(0,st->post[i])), MULT16_16(Q15_ONE-gamma,DIV32_16_Q8(st->old_ps[i],tot_noise))), 15)); |
809 | st->prior[i]=MIN16(st->prior[i], QCONST16(100.f,SNR_SHIFT)); | 808 | st->prior[i]=MIN16(st->prior[i], QCONST16(100.f,SNR_SHIFT)); |
@@ -824,13 +823,13 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) | |||
824 | for (i=N;i<N+M;i++) | 823 | for (i=N;i<N+M;i++) |
825 | Zframe = ADD32(Zframe, EXTEND32(st->zeta[i])); | 824 | Zframe = ADD32(Zframe, EXTEND32(st->zeta[i])); |
826 | Pframe = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.899f,15),qcurve(DIV32_16(Zframe,st->nbands))); | 825 | Pframe = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.899f,15),qcurve(DIV32_16(Zframe,st->nbands))); |
827 | 826 | ||
828 | effective_echo_suppress = EXTRACT16(PSHR32(ADD32(MULT16_16(SUB16(Q15_ONE,Pframe), st->echo_suppress), MULT16_16(Pframe, st->echo_suppress_active)),15)); | 827 | effective_echo_suppress = EXTRACT16(PSHR32(ADD32(MULT16_16(SUB16(Q15_ONE,Pframe), st->echo_suppress), MULT16_16(Pframe, st->echo_suppress_active)),15)); |
829 | 828 | ||
830 | compute_gain_floor(st->noise_suppress, effective_echo_suppress, st->noise+N, st->echo_noise+N, st->gain_floor+N, M); | 829 | compute_gain_floor(st->noise_suppress, effective_echo_suppress, st->noise+N, st->echo_noise+N, st->gain_floor+N, M); |
831 | 830 | ||
832 | /* Compute Ephraim & Malah gain speech probability of presence for each critical band (Bark scale) | 831 | /* Compute Ephraim & Malah gain speech probability of presence for each critical band (Bark scale) |
833 | Technically this is actually wrong because the EM gaim assumes a slightly different probability | 832 | Technically this is actually wrong because the EM gaim assumes a slightly different probability |
834 | distribution */ | 833 | distribution */ |
835 | for (i=N;i<N+M;i++) | 834 | for (i=N;i<N+M;i++) |
836 | { | 835 | { |
@@ -847,7 +846,7 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) | |||
847 | #ifdef FIXED_POINT | 846 | #ifdef FIXED_POINT |
848 | spx_word16_t tmp; | 847 | spx_word16_t tmp; |
849 | #endif | 848 | #endif |
850 | 849 | ||
851 | prior_ratio = PDIV32_16(SHL32(EXTEND32(st->prior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT))); | 850 | prior_ratio = PDIV32_16(SHL32(EXTEND32(st->prior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT))); |
852 | theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT)); | 851 | theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT)); |
853 | 852 | ||
@@ -872,12 +871,12 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) | |||
872 | /* Convert the EM gains and speech prob to linear frequency */ | 871 | /* Convert the EM gains and speech prob to linear frequency */ |
873 | filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2); | 872 | filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2); |
874 | filterbank_compute_psd16(st->bank,st->gain+N, st->gain); | 873 | filterbank_compute_psd16(st->bank,st->gain+N, st->gain); |
875 | 874 | ||
876 | /* Use 1 for linear gain resolution (best) or 0 for Bark gain resolution (faster) */ | 875 | /* Use 1 for linear gain resolution (best) or 0 for Bark gain resolution (faster) */ |
877 | if (1) | 876 | if (1) |
878 | { | 877 | { |
879 | filterbank_compute_psd16(st->bank,st->gain_floor+N, st->gain_floor); | 878 | filterbank_compute_psd16(st->bank,st->gain_floor+N, st->gain_floor); |
880 | 879 | ||
881 | /* Compute gain according to the Ephraim-Malah algorithm -- linear frequency */ | 880 | /* Compute gain according to the Ephraim-Malah algorithm -- linear frequency */ |
882 | for (i=0;i<N;i++) | 881 | for (i=0;i<N;i++) |
883 | { | 882 | { |
@@ -887,7 +886,7 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) | |||
887 | spx_word16_t tmp; | 886 | spx_word16_t tmp; |
888 | spx_word16_t p; | 887 | spx_word16_t p; |
889 | spx_word16_t g; | 888 | spx_word16_t g; |
890 | 889 | ||
891 | /* Wiener filter gain */ | 890 | /* Wiener filter gain */ |
892 | prior_ratio = PDIV32_16(SHL32(EXTEND32(st->prior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT))); | 891 | prior_ratio = PDIV32_16(SHL32(EXTEND32(st->prior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT))); |
893 | theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT)); | 892 | theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT)); |
@@ -898,22 +897,22 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) | |||
898 | g = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM))); | 897 | g = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM))); |
899 | /* Interpolated speech probability of presence */ | 898 | /* Interpolated speech probability of presence */ |
900 | p = st->gain2[i]; | 899 | p = st->gain2[i]; |
901 | 900 | ||
902 | /* Constrain the gain to be close to the Bark scale gain */ | 901 | /* Constrain the gain to be close to the Bark scale gain */ |
903 | if (MULT16_16_Q15(QCONST16(.333f,15),g) > st->gain[i]) | 902 | if (MULT16_16_Q15(QCONST16(.333f,15),g) > st->gain[i]) |
904 | g = MULT16_16(3,st->gain[i]); | 903 | g = MULT16_16(3,st->gain[i]); |
905 | st->gain[i] = g; | 904 | st->gain[i] = g; |
906 | 905 | ||
907 | /* Save old power spectrum */ | 906 | /* Save old power spectrum */ |
908 | st->old_ps[i] = MULT16_32_P15(QCONST16(.2f,15),st->old_ps[i]) + MULT16_32_P15(MULT16_16_P15(QCONST16(.8f,15),SQR16_Q15(st->gain[i])),ps[i]); | 907 | st->old_ps[i] = MULT16_32_P15(QCONST16(.2f,15),st->old_ps[i]) + MULT16_32_P15(MULT16_16_P15(QCONST16(.8f,15),SQR16_Q15(st->gain[i])),ps[i]); |
909 | 908 | ||
910 | /* Apply gain floor */ | 909 | /* Apply gain floor */ |
911 | if (st->gain[i] < st->gain_floor[i]) | 910 | if (st->gain[i] < st->gain_floor[i]) |
912 | st->gain[i] = st->gain_floor[i]; | 911 | st->gain[i] = st->gain_floor[i]; |
913 | 912 | ||
914 | /* Exponential decay model for reverberation (unused) */ | 913 | /* Exponential decay model for reverberation (unused) */ |
915 | /*st->reverb_estimate[i] = st->reverb_decay*st->reverb_estimate[i] + st->reverb_decay*st->reverb_level*st->gain[i]*st->gain[i]*st->ps[i];*/ | 914 | /*st->reverb_estimate[i] = st->reverb_decay*st->reverb_estimate[i] + st->reverb_decay*st->reverb_level*st->gain[i]*st->gain[i]*st->ps[i];*/ |
916 | 915 | ||
917 | /* Take into account speech probability of presence (loudness domain MMSE estimator) */ | 916 | /* Take into account speech probability of presence (loudness domain MMSE estimator) */ |
918 | /* gain2 = [p*sqrt(gain)+(1-p)*sqrt(gain _floor) ]^2 */ | 917 | /* gain2 = [p*sqrt(gain)+(1-p)*sqrt(gain _floor) ]^2 */ |
919 | tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(st->gain[i]),15))) + MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(st->gain_floor[i]),15))); | 918 | tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(st->gain[i]),15))) + MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(st->gain_floor[i]),15))); |
@@ -927,20 +926,20 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) | |||
927 | { | 926 | { |
928 | spx_word16_t tmp; | 927 | spx_word16_t tmp; |
929 | spx_word16_t p = st->gain2[i]; | 928 | spx_word16_t p = st->gain2[i]; |
930 | st->gain[i] = MAX16(st->gain[i], st->gain_floor[i]); | 929 | st->gain[i] = MAX16(st->gain[i], st->gain_floor[i]); |
931 | tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(st->gain[i]),15))) + MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(st->gain_floor[i]),15))); | 930 | tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(st->gain[i]),15))) + MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(st->gain_floor[i]),15))); |
932 | st->gain2[i]=SQR16_Q15(tmp); | 931 | st->gain2[i]=SQR16_Q15(tmp); |
933 | } | 932 | } |
934 | filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2); | 933 | filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2); |
935 | } | 934 | } |
936 | 935 | ||
937 | /* If noise suppression is off, don't apply the gain (but then why call this in the first place!) */ | 936 | /* If noise suppression is off, don't apply the gain (but then why call this in the first place!) */ |
938 | if (!st->denoise_enabled) | 937 | if (!st->denoise_enabled) |
939 | { | 938 | { |
940 | for (i=0;i<N+M;i++) | 939 | for (i=0;i<N+M;i++) |
941 | st->gain2[i]=Q15_ONE; | 940 | st->gain2[i]=Q15_ONE; |
942 | } | 941 | } |
943 | 942 | ||
944 | /* Apply computed gain */ | 943 | /* Apply computed gain */ |
945 | for (i=1;i<N;i++) | 944 | for (i=1;i<N;i++) |
946 | { | 945 | { |
@@ -949,7 +948,7 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) | |||
949 | } | 948 | } |
950 | st->ft[0] = MULT16_16_P15(st->gain2[0],st->ft[0]); | 949 | st->ft[0] = MULT16_16_P15(st->gain2[0],st->ft[0]); |
951 | st->ft[2*N-1] = MULT16_16_P15(st->gain2[N-1],st->ft[2*N-1]); | 950 | st->ft[2*N-1] = MULT16_16_P15(st->gain2[N-1],st->ft[2*N-1]); |
952 | 951 | ||
953 | /*FIXME: This *will* not work for fixed-point */ | 952 | /*FIXME: This *will* not work for fixed-point */ |
954 | #ifndef FIXED_POINT | 953 | #ifndef FIXED_POINT |
955 | if (st->agc_enabled) | 954 | if (st->agc_enabled) |
@@ -978,7 +977,7 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) | |||
978 | } | 977 | } |
979 | } | 978 | } |
980 | #endif | 979 | #endif |
981 | 980 | ||
982 | /* Synthesis window (for WOLA) */ | 981 | /* Synthesis window (for WOLA) */ |
983 | for (i=0;i<2*N;i++) | 982 | for (i=0;i<2*N;i++) |
984 | st->frame[i] = MULT16_16_Q15(st->frame[i], st->window[i]); | 983 | st->frame[i] = MULT16_16_Q15(st->frame[i], st->window[i]); |
@@ -988,15 +987,16 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) | |||
988 | x[i] = st->outbuf[i] + st->frame[i]; | 987 | x[i] = st->outbuf[i] + st->frame[i]; |
989 | for (i=0;i<N4;i++) | 988 | for (i=0;i<N4;i++) |
990 | x[N3+i] = st->frame[N3+i]; | 989 | x[N3+i] = st->frame[N3+i]; |
991 | 990 | ||
992 | /* Update outbuf */ | 991 | /* Update outbuf */ |
993 | for (i=0;i<N3;i++) | 992 | for (i=0;i<N3;i++) |
994 | st->outbuf[i] = st->frame[st->frame_size+i]; | 993 | st->outbuf[i] = st->frame[st->frame_size+i]; |
995 | 994 | ||
996 | /* FIXME: This VAD is a kludge */ | 995 | /* FIXME: This VAD is a kludge */ |
996 | st->speech_prob = Pframe; | ||
997 | if (st->vad_enabled) | 997 | if (st->vad_enabled) |
998 | { | 998 | { |
999 | if (Pframe > st->speech_prob_start || (st->was_speech && Pframe > st->speech_prob_continue)) | 999 | if (st->speech_prob > st->speech_prob_start || (st->was_speech && st->speech_prob > st->speech_prob_continue)) |
1000 | { | 1000 | { |
1001 | st->was_speech=1; | 1001 | st->was_speech=1; |
1002 | return 1; | 1002 | return 1; |
@@ -1010,7 +1010,7 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) | |||
1010 | } | 1010 | } |
1011 | } | 1011 | } |
1012 | 1012 | ||
1013 | void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x) | 1013 | EXPORT void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x) |
1014 | { | 1014 | { |
1015 | int i; | 1015 | int i; |
1016 | int N = st->ps_size; | 1016 | int N = st->ps_size; |
@@ -1020,11 +1020,11 @@ void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x) | |||
1020 | 1020 | ||
1021 | M = st->nbands; | 1021 | M = st->nbands; |
1022 | st->min_count++; | 1022 | st->min_count++; |
1023 | 1023 | ||
1024 | preprocess_analysis(st, x); | 1024 | preprocess_analysis(st, x); |
1025 | 1025 | ||
1026 | update_noise_prob(st); | 1026 | update_noise_prob(st); |
1027 | 1027 | ||
1028 | for (i=1;i<N-1;i++) | 1028 | for (i=1;i<N-1;i++) |
1029 | { | 1029 | { |
1030 | if (!st->update_prob[i] || st->ps[i] < PSHR32(st->noise[i],NOISE_SHIFT)) | 1030 | if (!st->update_prob[i] || st->ps[i] < PSHR32(st->noise[i],NOISE_SHIFT)) |
@@ -1045,7 +1045,7 @@ void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x) | |||
1045 | } | 1045 | } |
1046 | 1046 | ||
1047 | 1047 | ||
1048 | int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr) | 1048 | EXPORT int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr) |
1049 | { | 1049 | { |
1050 | int i; | 1050 | int i; |
1051 | SpeexPreprocessState *st; | 1051 | SpeexPreprocessState *st; |
@@ -1103,7 +1103,7 @@ int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr) | |||
1103 | case SPEEX_PREPROCESS_GET_VAD: | 1103 | case SPEEX_PREPROCESS_GET_VAD: |
1104 | (*(spx_int32_t*)ptr) = st->vad_enabled; | 1104 | (*(spx_int32_t*)ptr) = st->vad_enabled; |
1105 | break; | 1105 | break; |
1106 | 1106 | ||
1107 | case SPEEX_PREPROCESS_SET_DEREVERB: | 1107 | case SPEEX_PREPROCESS_SET_DEREVERB: |
1108 | st->dereverb_enabled = (*(spx_int32_t*)ptr); | 1108 | st->dereverb_enabled = (*(spx_int32_t*)ptr); |
1109 | for (i=0;i<st->ps_size;i++) | 1109 | for (i=0;i<st->ps_size;i++) |
@@ -1121,7 +1121,7 @@ int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr) | |||
1121 | /* FIXME: Re-enable when de-reverberation is actually enabled again */ | 1121 | /* FIXME: Re-enable when de-reverberation is actually enabled again */ |
1122 | /*(*(float*)ptr) = st->reverb_level;*/ | 1122 | /*(*(float*)ptr) = st->reverb_level;*/ |
1123 | break; | 1123 | break; |
1124 | 1124 | ||
1125 | case SPEEX_PREPROCESS_SET_DEREVERB_DECAY: | 1125 | case SPEEX_PREPROCESS_SET_DEREVERB_DECAY: |
1126 | /* FIXME: Re-enable when de-reverberation is actually enabled again */ | 1126 | /* FIXME: Re-enable when de-reverberation is actually enabled again */ |
1127 | /*st->reverb_decay = (*(float*)ptr);*/ | 1127 | /*st->reverb_decay = (*(float*)ptr);*/ |
@@ -1169,17 +1169,51 @@ int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr) | |||
1169 | st->echo_state = (SpeexEchoState*)ptr; | 1169 | st->echo_state = (SpeexEchoState*)ptr; |
1170 | break; | 1170 | break; |
1171 | case SPEEX_PREPROCESS_GET_ECHO_STATE: | 1171 | case SPEEX_PREPROCESS_GET_ECHO_STATE: |
1172 | ptr = (void*)st->echo_state; | 1172 | (*(SpeexEchoState**)ptr) = (SpeexEchoState*)st->echo_state; |
1173 | break; | 1173 | break; |
1174 | #ifndef FIXED_POINT | 1174 | #ifndef FIXED_POINT |
1175 | case SPEEX_PREPROCESS_GET_AGC_LOUDNESS: | 1175 | case SPEEX_PREPROCESS_GET_AGC_LOUDNESS: |
1176 | (*(spx_int32_t*)ptr) = pow(st->loudness, 1.0/LOUDNESS_EXP); | 1176 | (*(spx_int32_t*)ptr) = pow(st->loudness, 1.0/LOUDNESS_EXP); |
1177 | break; | 1177 | break; |
1178 | case SPEEX_PREPROCESS_GET_AGC_GAIN: | ||
1179 | (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->agc_gain)); | ||
1180 | break; | ||
1181 | #endif | ||
1182 | case SPEEX_PREPROCESS_GET_PSD_SIZE: | ||
1183 | case SPEEX_PREPROCESS_GET_NOISE_PSD_SIZE: | ||
1184 | (*(spx_int32_t*)ptr) = st->ps_size; | ||
1185 | break; | ||
1186 | case SPEEX_PREPROCESS_GET_PSD: | ||
1187 | for(i=0;i<st->ps_size;i++) | ||
1188 | ((spx_int32_t *)ptr)[i] = (spx_int32_t) st->ps[i]; | ||
1189 | break; | ||
1190 | case SPEEX_PREPROCESS_GET_NOISE_PSD: | ||
1191 | for(i=0;i<st->ps_size;i++) | ||
1192 | ((spx_int32_t *)ptr)[i] = (spx_int32_t) PSHR32(st->noise[i], NOISE_SHIFT); | ||
1193 | break; | ||
1194 | case SPEEX_PREPROCESS_GET_PROB: | ||
1195 | (*(spx_int32_t*)ptr) = MULT16_16_Q15(st->speech_prob, 100); | ||
1196 | break; | ||
1197 | #ifndef FIXED_POINT | ||
1198 | case SPEEX_PREPROCESS_SET_AGC_TARGET: | ||
1199 | st->agc_level = (*(spx_int32_t*)ptr); | ||
1200 | if (st->agc_level<1) | ||
1201 | st->agc_level=1; | ||
1202 | if (st->agc_level>32768) | ||
1203 | st->agc_level=32768; | ||
1204 | break; | ||
1205 | case SPEEX_PREPROCESS_GET_AGC_TARGET: | ||
1206 | (*(spx_int32_t*)ptr) = st->agc_level; | ||
1207 | break; | ||
1178 | #endif | 1208 | #endif |
1179 | |||
1180 | default: | 1209 | default: |
1181 | speex_warning_int("Unknown speex_preprocess_ctl request: ", request); | 1210 | speex_warning_int("Unknown speex_preprocess_ctl request: ", request); |
1182 | return -1; | 1211 | return -1; |
1183 | } | 1212 | } |
1184 | return 0; | 1213 | return 0; |
1185 | } | 1214 | } |
1215 | |||
1216 | #ifdef FIXED_DEBUG | ||
1217 | long long spx_mips=0; | ||
1218 | #endif | ||
1219 | |||
diff --git a/lib/rbcodec/codecs/libspeex/quant_lsp_bfin.h b/lib/rbcodec/codecs/libspeex/quant_lsp_bfin.h index 917047bb56..087b466b75 100644 --- a/lib/rbcodec/codecs/libspeex/quant_lsp_bfin.h +++ b/lib/rbcodec/codecs/libspeex/quant_lsp_bfin.h | |||
@@ -55,9 +55,9 @@ static int lsp_quant( | |||
55 | 55 | ||
56 | __asm__ __volatile__ | 56 | __asm__ __volatile__ |
57 | ( | 57 | ( |
58 | " %0 = 1 (X);\n\t" /* %0: best_dist */ | 58 | " %0 = 1 (X);\n\t" /* %0: best_dist */ |
59 | " %0 <<= 30;\n\t" | 59 | " %0 <<= 30;\n\t" |
60 | " %1 = 0 (X);\n\t" /* %1: best_i */ | 60 | " %1 = 0 (X);\n\t" /* %1: best_i */ |
61 | " P2 = %3\n\t" /* P2: ptr to cdbk */ | 61 | " P2 = %3\n\t" /* P2: ptr to cdbk */ |
62 | " R5 = 0;\n\t" /* R5: best cb entry */ | 62 | " R5 = 0;\n\t" /* R5: best cb entry */ |
63 | 63 | ||
@@ -68,19 +68,19 @@ static int lsp_quant( | |||
68 | " B0 = %2;\n\t" | 68 | " B0 = %2;\n\t" |
69 | 69 | ||
70 | " R2.L = W [I0++];\n\t" | 70 | " R2.L = W [I0++];\n\t" |
71 | " LSETUP (lq1, lq2) LC0 = %4;\n\t" | 71 | " LSETUP (1f, 2f) LC0 = %4;\n\t" |
72 | "lq1: R3 = 0;\n\t" /* R3: dist */ | 72 | "1: R3 = 0;\n\t" /* R3: dist */ |
73 | " LSETUP (lq3, lq4) LC1 = %5;\n\t" | 73 | " LSETUP (3f, 4f) LC1 = %5;\n\t" |
74 | "lq3: R1 = B [P2++] (X);\n\t" | 74 | "3: R1 = B [P2++] (X);\n\t" |
75 | " R1 <<= 5;\n\t" | 75 | " R1 <<= 5;\n\t" |
76 | " R0.L = R2.L - R1.L || R2.L = W [I0++];\n\t" | 76 | " R0.L = R2.L - R1.L || R2.L = W [I0++];\n\t" |
77 | " R0 = R0.L*R0.L;\n\t" | 77 | " R0 = R0.L*R0.L;\n\t" |
78 | "lq4: R3 = R3 + R0;\n\t" | 78 | "4: R3 = R3 + R0;\n\t" |
79 | 79 | ||
80 | " cc =R3<%0;\n\t" | 80 | " cc =R3<%0;\n\t" |
81 | " if cc %0=R3;\n\t" | 81 | " if cc %0=R3;\n\t" |
82 | " if cc %1=R5;\n\t" | 82 | " if cc %1=R5;\n\t" |
83 | "lq2: R5 += 1;\n\t" | 83 | "2: R5 += 1;\n\t" |
84 | " L0 = 0;\n\t" | 84 | " L0 = 0;\n\t" |
85 | : "=&d" (best_dist), "=&d" (best_id) | 85 | : "=&d" (best_dist), "=&d" (best_id) |
86 | : "a" (x), "b" (cdbk), "a" (nbVec), "a" (nbDim) | 86 | : "a" (x), "b" (cdbk), "a" (nbVec), "a" (nbDim) |
@@ -117,9 +117,9 @@ static int lsp_weight_quant( | |||
117 | 117 | ||
118 | __asm__ __volatile__ | 118 | __asm__ __volatile__ |
119 | ( | 119 | ( |
120 | " %0 = 1 (X);\n\t" /* %0: best_dist */ | 120 | " %0 = 1 (X);\n\t" /* %0: best_dist */ |
121 | " %0 <<= 30;\n\t" | 121 | " %0 <<= 30;\n\t" |
122 | " %1 = 0 (X);\n\t" /* %1: best_i */ | 122 | " %1 = 0 (X);\n\t" /* %1: best_i */ |
123 | " P2 = %4\n\t" /* P2: ptr to cdbk */ | 123 | " P2 = %4\n\t" /* P2: ptr to cdbk */ |
124 | " R5 = 0;\n\t" /* R5: best cb entry */ | 124 | " R5 = 0;\n\t" /* R5: best cb entry */ |
125 | 125 | ||
@@ -128,27 +128,27 @@ static int lsp_weight_quant( | |||
128 | " L0 = R0;\n\t" | 128 | " L0 = R0;\n\t" |
129 | " L1 = R0;\n\t" | 129 | " L1 = R0;\n\t" |
130 | " I0 = %2;\n\t" /* %2: &x[0] */ | 130 | " I0 = %2;\n\t" /* %2: &x[0] */ |
131 | " I1 = %3;\n\t" /* %3: &weight[0] */ | 131 | " I1 = %3;\n\t" /* %3: &weight[0] */ |
132 | " B0 = %2;\n\t" | 132 | " B0 = %2;\n\t" |
133 | " B1 = %3;\n\t" | 133 | " B1 = %3;\n\t" |
134 | 134 | ||
135 | " LSETUP (lwq1, lwq2) LC0 = %5;\n\t" | 135 | " LSETUP (1f, 2f) LC0 = %5;\n\t" |
136 | "lwq1: R3 = 0 (X);\n\t" /* R3: dist */ | 136 | "1: R3 = 0 (X);\n\t" /* R3: dist */ |
137 | " LSETUP (lwq3, lwq4) LC1 = %6;\n\t" | 137 | " LSETUP (3f, 4f) LC1 = %6;\n\t" |
138 | "lwq3: R0.L = W [I0++] || R2.L = W [I1++];\n\t" | 138 | "3: R0.L = W [I0++] || R2.L = W [I1++];\n\t" |
139 | " R1 = B [P2++] (X);\n\t" | 139 | " R1 = B [P2++] (X);\n\t" |
140 | " R1 <<= 5;\n\t" | 140 | " R1 <<= 5;\n\t" |
141 | " R0.L = R0.L - R1.L;\n\t" | 141 | " R0.L = R0.L - R1.L;\n\t" |
142 | " R0 = R0.L*R0.L;\n\t" | 142 | " R0 = R0.L*R0.L;\n\t" |
143 | " A1 = R2.L*R0.L (M,IS);\n\t" | 143 | " A1 = R2.L*R0.L (M,IS);\n\t" |
144 | " A1 = A1 >>> 16;\n\t" | 144 | " A1 = A1 >>> 16;\n\t" |
145 | " R1 = (A1 += R2.L*R0.H) (IS);\n\t" | 145 | " R1 = (A1 += R2.L*R0.H) (IS);\n\t" |
146 | "lwq4: R3 = R3 + R1;\n\t" | 146 | "4: R3 = R3 + R1;\n\t" |
147 | 147 | ||
148 | " cc =R3<%0;\n\t" | 148 | " cc =R3<%0;\n\t" |
149 | " if cc %0=R3;\n\t" | 149 | " if cc %0=R3;\n\t" |
150 | " if cc %1=R5;\n\t" | 150 | " if cc %1=R5;\n\t" |
151 | "lwq2: R5 += 1;\n\t" | 151 | "2: R5 += 1;\n\t" |
152 | " L0 = 0;\n\t" | 152 | " L0 = 0;\n\t" |
153 | " L1 = 0;\n\t" | 153 | " L1 = 0;\n\t" |
154 | : "=&d" (best_dist), "=&d" (best_id) | 154 | : "=&d" (best_dist), "=&d" (best_id) |
diff --git a/lib/rbcodec/codecs/libspeex/resample.c b/lib/rbcodec/codecs/libspeex/resample.c index 65dfef28a3..5f5b9c6b4d 100644 --- a/lib/rbcodec/codecs/libspeex/resample.c +++ b/lib/rbcodec/codecs/libspeex/resample.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* Copyright (C) 2007 Jean-Marc Valin | 1 | /* Copyright (C) 2007-2008 Jean-Marc Valin |
2 | 2 | Copyright (C) 2008 Thorvald Natvig | |
3 | |||
3 | File: resample.c | 4 | File: resample.c |
4 | Arbitrary resampling code | 5 | Arbitrary resampling code |
5 | 6 | ||
@@ -37,27 +38,27 @@ | |||
37 | - Low memory requirement | 38 | - Low memory requirement |
38 | - Good *perceptual* quality (and not best SNR) | 39 | - Good *perceptual* quality (and not best SNR) |
39 | 40 | ||
40 | Warning: This resampler is relatively new. Although I think I got rid of | 41 | Warning: This resampler is relatively new. Although I think I got rid of |
41 | all the major bugs and I don't expect the API to change anymore, there | 42 | all the major bugs and I don't expect the API to change anymore, there |
42 | may be something I've missed. So use with caution. | 43 | may be something I've missed. So use with caution. |
43 | 44 | ||
44 | This algorithm is based on this original resampling algorithm: | 45 | This algorithm is based on this original resampling algorithm: |
45 | Smith, Julius O. Digital Audio Resampling Home Page | 46 | Smith, Julius O. Digital Audio Resampling Home Page |
46 | Center for Computer Research in Music and Acoustics (CCRMA), | 47 | Center for Computer Research in Music and Acoustics (CCRMA), |
47 | Stanford University, 2007. | 48 | Stanford University, 2007. |
48 | Web published at http://www-ccrma.stanford.edu/~jos/resample/. | 49 | Web published at http://www-ccrma.stanford.edu/~jos/resample/. |
49 | 50 | ||
50 | There is one main difference, though. This resampler uses cubic | 51 | There is one main difference, though. This resampler uses cubic |
51 | interpolation instead of linear interpolation in the above paper. This | 52 | interpolation instead of linear interpolation in the above paper. This |
52 | makes the table much smaller and makes it possible to compute that table | 53 | makes the table much smaller and makes it possible to compute that table |
53 | on a per-stream basis. In turn, being able to tweak the table for each | 54 | on a per-stream basis. In turn, being able to tweak the table for each |
54 | stream makes it possible to both reduce complexity on simple ratios | 55 | stream makes it possible to both reduce complexity on simple ratios |
55 | (e.g. 2/3), and get rid of the rounding operations in the inner loop. | 56 | (e.g. 2/3), and get rid of the rounding operations in the inner loop. |
56 | The latter both reduces CPU time and makes the algorithm more SIMD-friendly. | 57 | The latter both reduces CPU time and makes the algorithm more SIMD-friendly. |
57 | */ | 58 | */ |
58 | 59 | ||
59 | #ifdef HAVE_CONFIG_H | 60 | #ifdef HAVE_CONFIG_H |
60 | #include "config-speex.h" | 61 | #include "config.h" |
61 | #endif | 62 | #endif |
62 | 63 | ||
63 | #ifdef OUTSIDE_SPEEX | 64 | #ifdef OUTSIDE_SPEEX |
@@ -68,12 +69,13 @@ static void speex_free (void *ptr) {free(ptr);} | |||
68 | #include "speex_resampler.h" | 69 | #include "speex_resampler.h" |
69 | #include "arch.h" | 70 | #include "arch.h" |
70 | #else /* OUTSIDE_SPEEX */ | 71 | #else /* OUTSIDE_SPEEX */ |
71 | 72 | ||
72 | #include "speex/speex_resampler.h" | 73 | #include "speex/speex_resampler.h" |
73 | #include "arch.h" | 74 | #include "arch.h" |
74 | #include "os_support.h" | 75 | #include "os_support.h" |
75 | #endif /* OUTSIDE_SPEEX */ | 76 | #endif /* OUTSIDE_SPEEX */ |
76 | 77 | ||
78 | #include "stack_alloc.h" | ||
77 | #include <math.h> | 79 | #include <math.h> |
78 | 80 | ||
79 | #ifndef M_PI | 81 | #ifndef M_PI |
@@ -81,14 +83,10 @@ static void speex_free (void *ptr) {free(ptr);} | |||
81 | #endif | 83 | #endif |
82 | 84 | ||
83 | #ifdef FIXED_POINT | 85 | #ifdef FIXED_POINT |
84 | #define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x))) | 86 | #define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x))) |
85 | #else | 87 | #else |
86 | #define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) | 88 | #define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) |
87 | #endif | 89 | #endif |
88 | |||
89 | /*#define float double*/ | ||
90 | #define FILTER_SIZE 64 | ||
91 | #define OVERSAMPLE 8 | ||
92 | 90 | ||
93 | #define IMAX(a,b) ((a) > (b) ? (a) : (b)) | 91 | #define IMAX(a,b) ((a) > (b) ? (a) : (b)) |
94 | #define IMIN(a,b) ((a) < (b) ? (a) : (b)) | 92 | #define IMIN(a,b) ((a) < (b) ? (a) : (b)) |
@@ -97,6 +95,17 @@ static void speex_free (void *ptr) {free(ptr);} | |||
97 | #define NULL 0 | 95 | #define NULL 0 |
98 | #endif | 96 | #endif |
99 | 97 | ||
98 | #ifdef _USE_SSE | ||
99 | #include "resample_sse.h" | ||
100 | #endif | ||
101 | |||
102 | /* Numer of elements to allocate on the stack */ | ||
103 | #ifdef VAR_ARRAYS | ||
104 | #define FIXED_STACK_ALLOC 8192 | ||
105 | #else | ||
106 | #define FIXED_STACK_ALLOC 1024 | ||
107 | #endif | ||
108 | |||
100 | typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *); | 109 | typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *); |
101 | 110 | ||
102 | struct SpeexResamplerState_ { | 111 | struct SpeexResamplerState_ { |
@@ -104,28 +113,29 @@ struct SpeexResamplerState_ { | |||
104 | spx_uint32_t out_rate; | 113 | spx_uint32_t out_rate; |
105 | spx_uint32_t num_rate; | 114 | spx_uint32_t num_rate; |
106 | spx_uint32_t den_rate; | 115 | spx_uint32_t den_rate; |
107 | 116 | ||
108 | int quality; | 117 | int quality; |
109 | spx_uint32_t nb_channels; | 118 | spx_uint32_t nb_channels; |
110 | spx_uint32_t filt_len; | 119 | spx_uint32_t filt_len; |
111 | spx_uint32_t mem_alloc_size; | 120 | spx_uint32_t mem_alloc_size; |
121 | spx_uint32_t buffer_size; | ||
112 | int int_advance; | 122 | int int_advance; |
113 | int frac_advance; | 123 | int frac_advance; |
114 | float cutoff; | 124 | float cutoff; |
115 | spx_uint32_t oversample; | 125 | spx_uint32_t oversample; |
116 | int initialised; | 126 | int initialised; |
117 | int started; | 127 | int started; |
118 | 128 | ||
119 | /* These are per-channel */ | 129 | /* These are per-channel */ |
120 | spx_int32_t *last_sample; | 130 | spx_int32_t *last_sample; |
121 | spx_uint32_t *samp_frac_num; | 131 | spx_uint32_t *samp_frac_num; |
122 | spx_uint32_t *magic_samples; | 132 | spx_uint32_t *magic_samples; |
123 | 133 | ||
124 | spx_word16_t *mem; | 134 | spx_word16_t *mem; |
125 | spx_word16_t *sinc_table; | 135 | spx_word16_t *sinc_table; |
126 | spx_uint32_t sinc_table_length; | 136 | spx_uint32_t sinc_table_length; |
127 | resampler_basic_func resampler_ptr; | 137 | resampler_basic_func resampler_ptr; |
128 | 138 | ||
129 | int in_stride; | 139 | int in_stride; |
130 | int out_stride; | 140 | int out_stride; |
131 | } ; | 141 | } ; |
@@ -167,7 +177,7 @@ static double kaiser8_table[36] = { | |||
167 | 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758, | 177 | 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758, |
168 | 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490, | 178 | 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490, |
169 | 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000}; | 179 | 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000}; |
170 | 180 | ||
171 | static double kaiser6_table[36] = { | 181 | static double kaiser6_table[36] = { |
172 | 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003, | 182 | 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003, |
173 | 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565, | 183 | 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565, |
@@ -180,7 +190,7 @@ struct FuncDef { | |||
180 | double *table; | 190 | double *table; |
181 | int oversample; | 191 | int oversample; |
182 | }; | 192 | }; |
183 | 193 | ||
184 | static struct FuncDef _KAISER12 = {kaiser12_table, 64}; | 194 | static struct FuncDef _KAISER12 = {kaiser12_table, 64}; |
185 | #define KAISER12 (&_KAISER12) | 195 | #define KAISER12 (&_KAISER12) |
186 | /*static struct FuncDef _KAISER12 = {kaiser12_table, 32}; | 196 | /*static struct FuncDef _KAISER12 = {kaiser12_table, 32}; |
@@ -202,7 +212,7 @@ struct QualityMapping { | |||
202 | 212 | ||
203 | 213 | ||
204 | /* This table maps conversion quality to internal parameters. There are two | 214 | /* This table maps conversion quality to internal parameters. There are two |
205 | reasons that explain why the up-sampling bandwidth is larger than the | 215 | reasons that explain why the up-sampling bandwidth is larger than the |
206 | down-sampling bandwidth: | 216 | down-sampling bandwidth: |
207 | 1) When up-sampling, we can assume that the spectrum is already attenuated | 217 | 1) When up-sampling, we can assume that the spectrum is already attenuated |
208 | close to the Nyquist rate (from an A/D or a previous resampling filter) | 218 | close to the Nyquist rate (from an A/D or a previous resampling filter) |
@@ -228,7 +238,7 @@ static double compute_func(float x, struct FuncDef *func) | |||
228 | { | 238 | { |
229 | float y, frac; | 239 | float y, frac; |
230 | double interp[4]; | 240 | double interp[4]; |
231 | int ind; | 241 | int ind; |
232 | y = x*func->oversample; | 242 | y = x*func->oversample; |
233 | ind = (int)floor(y); | 243 | ind = (int)floor(y); |
234 | frac = (y-ind); | 244 | frac = (y-ind); |
@@ -239,7 +249,7 @@ static double compute_func(float x, struct FuncDef *func) | |||
239 | interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac); | 249 | interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac); |
240 | /* Just to make sure we don't have rounding problems */ | 250 | /* Just to make sure we don't have rounding problems */ |
241 | interp[1] = 1.f-interp[3]-interp[2]-interp[0]; | 251 | interp[1] = 1.f-interp[3]-interp[2]-interp[0]; |
242 | 252 | ||
243 | /*sum = frac*accum[1] + (1-frac)*accum[2];*/ | 253 | /*sum = frac*accum[1] + (1-frac)*accum[2];*/ |
244 | return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3]; | 254 | return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3]; |
245 | } | 255 | } |
@@ -317,47 +327,47 @@ static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4]) | |||
317 | 327 | ||
318 | static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) | 328 | static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) |
319 | { | 329 | { |
320 | int N = st->filt_len; | 330 | const int N = st->filt_len; |
321 | int out_sample = 0; | 331 | int out_sample = 0; |
322 | spx_word16_t *mem; | ||
323 | int last_sample = st->last_sample[channel_index]; | 332 | int last_sample = st->last_sample[channel_index]; |
324 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; | 333 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; |
325 | mem = st->mem + channel_index * st->mem_alloc_size; | 334 | const spx_word16_t *sinc_table = st->sinc_table; |
335 | const int out_stride = st->out_stride; | ||
336 | const int int_advance = st->int_advance; | ||
337 | const int frac_advance = st->frac_advance; | ||
338 | const spx_uint32_t den_rate = st->den_rate; | ||
339 | spx_word32_t sum; | ||
340 | int j; | ||
341 | |||
326 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) | 342 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) |
327 | { | 343 | { |
328 | int j; | 344 | const spx_word16_t *sinc = & sinc_table[samp_frac_num*N]; |
329 | spx_word32_t sum=0; | 345 | const spx_word16_t *iptr = & in[last_sample]; |
330 | 346 | ||
331 | /* We already have all the filter coefficients pre-computed in the table */ | 347 | #ifndef OVERRIDE_INNER_PRODUCT_SINGLE |
332 | const spx_word16_t *ptr; | 348 | float accum[4] = {0,0,0,0}; |
333 | /* Do the memory part */ | 349 | |
334 | for (j=0;last_sample-N+1+j < 0;j++) | 350 | for(j=0;j<N;j+=4) { |
335 | { | 351 | accum[0] += sinc[j]*iptr[j]; |
336 | sum += MULT16_16(mem[last_sample+j],st->sinc_table[samp_frac_num*st->filt_len+j]); | 352 | accum[1] += sinc[j+1]*iptr[j+1]; |
337 | } | 353 | accum[2] += sinc[j+2]*iptr[j+2]; |
338 | 354 | accum[3] += sinc[j+3]*iptr[j+3]; | |
339 | /* Do the new part */ | ||
340 | if (in != NULL) | ||
341 | { | ||
342 | ptr = in+st->in_stride*(last_sample-N+1+j); | ||
343 | for (;j<N;j++) | ||
344 | { | ||
345 | sum += MULT16_16(*ptr,st->sinc_table[samp_frac_num*st->filt_len+j]); | ||
346 | ptr += st->in_stride; | ||
347 | } | ||
348 | } | 355 | } |
349 | 356 | sum = accum[0] + accum[1] + accum[2] + accum[3]; | |
350 | *out = PSHR32(sum,15); | 357 | #else |
351 | out += st->out_stride; | 358 | sum = inner_product_single(sinc, iptr, N); |
352 | out_sample++; | 359 | #endif |
353 | last_sample += st->int_advance; | 360 | |
354 | samp_frac_num += st->frac_advance; | 361 | out[out_stride * out_sample++] = PSHR32(sum, 15); |
355 | if (samp_frac_num >= st->den_rate) | 362 | last_sample += int_advance; |
363 | samp_frac_num += frac_advance; | ||
364 | if (samp_frac_num >= den_rate) | ||
356 | { | 365 | { |
357 | samp_frac_num -= st->den_rate; | 366 | samp_frac_num -= den_rate; |
358 | last_sample++; | 367 | last_sample++; |
359 | } | 368 | } |
360 | } | 369 | } |
370 | |||
361 | st->last_sample[channel_index] = last_sample; | 371 | st->last_sample[channel_index] = last_sample; |
362 | st->samp_frac_num[channel_index] = samp_frac_num; | 372 | st->samp_frac_num[channel_index] = samp_frac_num; |
363 | return out_sample; | 373 | return out_sample; |
@@ -368,47 +378,47 @@ static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t c | |||
368 | /* This is the same as the previous function, except with a double-precision accumulator */ | 378 | /* This is the same as the previous function, except with a double-precision accumulator */ |
369 | static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) | 379 | static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) |
370 | { | 380 | { |
371 | int N = st->filt_len; | 381 | const int N = st->filt_len; |
372 | int out_sample = 0; | 382 | int out_sample = 0; |
373 | spx_word16_t *mem; | ||
374 | int last_sample = st->last_sample[channel_index]; | 383 | int last_sample = st->last_sample[channel_index]; |
375 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; | 384 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; |
376 | mem = st->mem + channel_index * st->mem_alloc_size; | 385 | const spx_word16_t *sinc_table = st->sinc_table; |
386 | const int out_stride = st->out_stride; | ||
387 | const int int_advance = st->int_advance; | ||
388 | const int frac_advance = st->frac_advance; | ||
389 | const spx_uint32_t den_rate = st->den_rate; | ||
390 | double sum; | ||
391 | int j; | ||
392 | |||
377 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) | 393 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) |
378 | { | 394 | { |
379 | int j; | 395 | const spx_word16_t *sinc = & sinc_table[samp_frac_num*N]; |
380 | double sum=0; | 396 | const spx_word16_t *iptr = & in[last_sample]; |
381 | 397 | ||
382 | /* We already have all the filter coefficients pre-computed in the table */ | 398 | #ifndef OVERRIDE_INNER_PRODUCT_DOUBLE |
383 | const spx_word16_t *ptr; | 399 | double accum[4] = {0,0,0,0}; |
384 | /* Do the memory part */ | 400 | |
385 | for (j=0;last_sample-N+1+j < 0;j++) | 401 | for(j=0;j<N;j+=4) { |
386 | { | 402 | accum[0] += sinc[j]*iptr[j]; |
387 | sum += MULT16_16(mem[last_sample+j],(double)st->sinc_table[samp_frac_num*st->filt_len+j]); | 403 | accum[1] += sinc[j+1]*iptr[j+1]; |
388 | } | 404 | accum[2] += sinc[j+2]*iptr[j+2]; |
389 | 405 | accum[3] += sinc[j+3]*iptr[j+3]; | |
390 | /* Do the new part */ | ||
391 | if (in != NULL) | ||
392 | { | ||
393 | ptr = in+st->in_stride*(last_sample-N+1+j); | ||
394 | for (;j<N;j++) | ||
395 | { | ||
396 | sum += MULT16_16(*ptr,(double)st->sinc_table[samp_frac_num*st->filt_len+j]); | ||
397 | ptr += st->in_stride; | ||
398 | } | ||
399 | } | 406 | } |
400 | 407 | sum = accum[0] + accum[1] + accum[2] + accum[3]; | |
401 | *out = sum; | 408 | #else |
402 | out += st->out_stride; | 409 | sum = inner_product_double(sinc, iptr, N); |
403 | out_sample++; | 410 | #endif |
404 | last_sample += st->int_advance; | 411 | |
405 | samp_frac_num += st->frac_advance; | 412 | out[out_stride * out_sample++] = PSHR32(sum, 15); |
406 | if (samp_frac_num >= st->den_rate) | 413 | last_sample += int_advance; |
414 | samp_frac_num += frac_advance; | ||
415 | if (samp_frac_num >= den_rate) | ||
407 | { | 416 | { |
408 | samp_frac_num -= st->den_rate; | 417 | samp_frac_num -= den_rate; |
409 | last_sample++; | 418 | last_sample++; |
410 | } | 419 | } |
411 | } | 420 | } |
421 | |||
412 | st->last_sample[channel_index] = last_sample; | 422 | st->last_sample[channel_index] = last_sample; |
413 | st->samp_frac_num[channel_index] = samp_frac_num; | 423 | st->samp_frac_num[channel_index] = samp_frac_num; |
414 | return out_sample; | 424 | return out_sample; |
@@ -417,69 +427,58 @@ static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t c | |||
417 | 427 | ||
418 | static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) | 428 | static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) |
419 | { | 429 | { |
420 | int N = st->filt_len; | 430 | const int N = st->filt_len; |
421 | int out_sample = 0; | 431 | int out_sample = 0; |
422 | spx_word16_t *mem; | ||
423 | int last_sample = st->last_sample[channel_index]; | 432 | int last_sample = st->last_sample[channel_index]; |
424 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; | 433 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; |
425 | mem = st->mem + channel_index * st->mem_alloc_size; | 434 | const int out_stride = st->out_stride; |
435 | const int int_advance = st->int_advance; | ||
436 | const int frac_advance = st->frac_advance; | ||
437 | const spx_uint32_t den_rate = st->den_rate; | ||
438 | int j; | ||
439 | spx_word32_t sum; | ||
440 | |||
426 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) | 441 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) |
427 | { | 442 | { |
428 | int j; | 443 | const spx_word16_t *iptr = & in[last_sample]; |
429 | spx_word32_t sum=0; | 444 | |
430 | 445 | const int offset = samp_frac_num*st->oversample/st->den_rate; | |
431 | /* We need to interpolate the sinc filter */ | ||
432 | spx_word32_t accum[4] = {0.f,0.f, 0.f, 0.f}; | ||
433 | spx_word16_t interp[4]; | ||
434 | const spx_word16_t *ptr; | ||
435 | int offset; | ||
436 | spx_word16_t frac; | ||
437 | offset = samp_frac_num*st->oversample/st->den_rate; | ||
438 | #ifdef FIXED_POINT | 446 | #ifdef FIXED_POINT |
439 | frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); | 447 | const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); |
440 | #else | 448 | #else |
441 | frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; | 449 | const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; |
442 | #endif | 450 | #endif |
443 | /* This code is written like this to make it easy to optimise with SIMD. | 451 | spx_word16_t interp[4]; |
444 | For most DSPs, it would be best to split the loops in two because most DSPs | 452 | |
445 | have only two accumulators */ | 453 | |
446 | for (j=0;last_sample-N+1+j < 0;j++) | 454 | #ifndef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE |
447 | { | 455 | spx_word32_t accum[4] = {0,0,0,0}; |
448 | spx_word16_t curr_mem = mem[last_sample+j]; | 456 | |
449 | accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]); | 457 | for(j=0;j<N;j++) { |
450 | accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]); | 458 | const spx_word16_t curr_in=iptr[j]; |
451 | accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]); | 459 | accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]); |
452 | accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]); | 460 | accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); |
453 | } | 461 | accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); |
454 | 462 | accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); | |
455 | if (in != NULL) | ||
456 | { | ||
457 | ptr = in+st->in_stride*(last_sample-N+1+j); | ||
458 | /* Do the new part */ | ||
459 | for (;j<N;j++) | ||
460 | { | ||
461 | spx_word16_t curr_in = *ptr; | ||
462 | ptr += st->in_stride; | ||
463 | accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]); | ||
464 | accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); | ||
465 | accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); | ||
466 | accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); | ||
467 | } | ||
468 | } | 463 | } |
464 | |||
469 | cubic_coef(frac, interp); | 465 | cubic_coef(frac, interp); |
470 | 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]); | 466 | 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]); |
471 | 467 | #else | |
472 | *out = PSHR32(sum,15); | 468 | cubic_coef(frac, interp); |
473 | out += st->out_stride; | 469 | sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp); |
474 | out_sample++; | 470 | #endif |
475 | last_sample += st->int_advance; | 471 | |
476 | samp_frac_num += st->frac_advance; | 472 | out[out_stride * out_sample++] = PSHR32(sum,15); |
477 | if (samp_frac_num >= st->den_rate) | 473 | last_sample += int_advance; |
474 | samp_frac_num += frac_advance; | ||
475 | if (samp_frac_num >= den_rate) | ||
478 | { | 476 | { |
479 | samp_frac_num -= st->den_rate; | 477 | samp_frac_num -= den_rate; |
480 | last_sample++; | 478 | last_sample++; |
481 | } | 479 | } |
482 | } | 480 | } |
481 | |||
483 | st->last_sample[channel_index] = last_sample; | 482 | st->last_sample[channel_index] = last_sample; |
484 | st->samp_frac_num[channel_index] = samp_frac_num; | 483 | st->samp_frac_num[channel_index] = samp_frac_num; |
485 | return out_sample; | 484 | return out_sample; |
@@ -490,63 +489,58 @@ static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint3 | |||
490 | /* This is the same as the previous function, except with a double-precision accumulator */ | 489 | /* This is the same as the previous function, except with a double-precision accumulator */ |
491 | static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) | 490 | static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) |
492 | { | 491 | { |
493 | int N = st->filt_len; | 492 | const int N = st->filt_len; |
494 | int out_sample = 0; | 493 | int out_sample = 0; |
495 | spx_word16_t *mem; | ||
496 | int last_sample = st->last_sample[channel_index]; | 494 | int last_sample = st->last_sample[channel_index]; |
497 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; | 495 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; |
498 | mem = st->mem + channel_index * st->mem_alloc_size; | 496 | const int out_stride = st->out_stride; |
497 | const int int_advance = st->int_advance; | ||
498 | const int frac_advance = st->frac_advance; | ||
499 | const spx_uint32_t den_rate = st->den_rate; | ||
500 | int j; | ||
501 | spx_word32_t sum; | ||
502 | |||
499 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) | 503 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) |
500 | { | 504 | { |
501 | int j; | 505 | const spx_word16_t *iptr = & in[last_sample]; |
502 | spx_word32_t sum=0; | 506 | |
503 | 507 | const int offset = samp_frac_num*st->oversample/st->den_rate; | |
504 | /* We need to interpolate the sinc filter */ | 508 | #ifdef FIXED_POINT |
505 | double accum[4] = {0.f,0.f, 0.f, 0.f}; | 509 | const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); |
506 | float interp[4]; | 510 | #else |
507 | const spx_word16_t *ptr; | 511 | const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; |
508 | float alpha = ((float)samp_frac_num)/st->den_rate; | 512 | #endif |
509 | int offset = samp_frac_num*st->oversample/st->den_rate; | 513 | spx_word16_t interp[4]; |
510 | float frac = alpha*st->oversample - offset; | 514 | |
511 | /* This code is written like this to make it easy to optimise with SIMD. | 515 | |
512 | For most DSPs, it would be best to split the loops in two because most DSPs | 516 | #ifndef OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE |
513 | have only two accumulators */ | 517 | double accum[4] = {0,0,0,0}; |
514 | for (j=0;last_sample-N+1+j < 0;j++) | 518 | |
515 | { | 519 | for(j=0;j<N;j++) { |
516 | double curr_mem = mem[last_sample+j]; | 520 | const double curr_in=iptr[j]; |
517 | accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]); | 521 | accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]); |
518 | accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]); | 522 | accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); |
519 | accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]); | 523 | accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); |
520 | accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]); | 524 | accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); |
521 | } | ||
522 | if (in != NULL) | ||
523 | { | ||
524 | ptr = in+st->in_stride*(last_sample-N+1+j); | ||
525 | /* Do the new part */ | ||
526 | for (;j<N;j++) | ||
527 | { | ||
528 | double curr_in = *ptr; | ||
529 | ptr += st->in_stride; | ||
530 | accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]); | ||
531 | accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); | ||
532 | accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); | ||
533 | accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); | ||
534 | } | ||
535 | } | 525 | } |
526 | |||
536 | cubic_coef(frac, interp); | 527 | cubic_coef(frac, interp); |
537 | sum = interp[0]*accum[0] + interp[1]*accum[1] + interp[2]*accum[2] + interp[3]*accum[3]; | 528 | 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]); |
538 | 529 | #else | |
539 | *out = PSHR32(sum,15); | 530 | cubic_coef(frac, interp); |
540 | out += st->out_stride; | 531 | sum = interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp); |
541 | out_sample++; | 532 | #endif |
542 | last_sample += st->int_advance; | 533 | |
543 | samp_frac_num += st->frac_advance; | 534 | out[out_stride * out_sample++] = PSHR32(sum,15); |
544 | if (samp_frac_num >= st->den_rate) | 535 | last_sample += int_advance; |
536 | samp_frac_num += frac_advance; | ||
537 | if (samp_frac_num >= den_rate) | ||
545 | { | 538 | { |
546 | samp_frac_num -= st->den_rate; | 539 | samp_frac_num -= den_rate; |
547 | last_sample++; | 540 | last_sample++; |
548 | } | 541 | } |
549 | } | 542 | } |
543 | |||
550 | st->last_sample[channel_index] = last_sample; | 544 | st->last_sample[channel_index] = last_sample; |
551 | st->samp_frac_num[channel_index] = samp_frac_num; | 545 | st->samp_frac_num[channel_index] = samp_frac_num; |
552 | return out_sample; | 546 | return out_sample; |
@@ -556,11 +550,11 @@ static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint3 | |||
556 | static void update_filter(SpeexResamplerState *st) | 550 | static void update_filter(SpeexResamplerState *st) |
557 | { | 551 | { |
558 | spx_uint32_t old_length; | 552 | spx_uint32_t old_length; |
559 | 553 | ||
560 | old_length = st->filt_len; | 554 | old_length = st->filt_len; |
561 | st->oversample = quality_map[st->quality].oversample; | 555 | st->oversample = quality_map[st->quality].oversample; |
562 | st->filt_len = quality_map[st->quality].base_length; | 556 | st->filt_len = quality_map[st->quality].base_length; |
563 | 557 | ||
564 | if (st->num_rate > st->den_rate) | 558 | if (st->num_rate > st->den_rate) |
565 | { | 559 | { |
566 | /* down-sampling */ | 560 | /* down-sampling */ |
@@ -636,25 +630,25 @@ static void update_filter(SpeexResamplerState *st) | |||
636 | st->int_advance = st->num_rate/st->den_rate; | 630 | st->int_advance = st->num_rate/st->den_rate; |
637 | st->frac_advance = st->num_rate%st->den_rate; | 631 | st->frac_advance = st->num_rate%st->den_rate; |
638 | 632 | ||
639 | 633 | ||
640 | /* Here's the place where we update the filter memory to take into account | 634 | /* Here's the place where we update the filter memory to take into account |
641 | the change in filter length. It's probably the messiest part of the code | 635 | the change in filter length. It's probably the messiest part of the code |
642 | due to handling of lots of corner cases. */ | 636 | due to handling of lots of corner cases. */ |
643 | if (!st->mem) | 637 | if (!st->mem) |
644 | { | 638 | { |
645 | spx_uint32_t i; | 639 | spx_uint32_t i; |
646 | st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); | 640 | st->mem_alloc_size = st->filt_len-1 + st->buffer_size; |
647 | for (i=0;i<st->nb_channels*(st->filt_len-1);i++) | 641 | st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); |
642 | for (i=0;i<st->nb_channels*st->mem_alloc_size;i++) | ||
648 | st->mem[i] = 0; | 643 | st->mem[i] = 0; |
649 | st->mem_alloc_size = st->filt_len-1; | ||
650 | /*speex_warning("init filter");*/ | 644 | /*speex_warning("init filter");*/ |
651 | } else if (!st->started) | 645 | } else if (!st->started) |
652 | { | 646 | { |
653 | spx_uint32_t i; | 647 | spx_uint32_t i; |
654 | st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); | 648 | st->mem_alloc_size = st->filt_len-1 + st->buffer_size; |
655 | for (i=0;i<st->nb_channels*(st->filt_len-1);i++) | 649 | st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); |
650 | for (i=0;i<st->nb_channels*st->mem_alloc_size;i++) | ||
656 | st->mem[i] = 0; | 651 | st->mem[i] = 0; |
657 | st->mem_alloc_size = st->filt_len-1; | ||
658 | /*speex_warning("reinit filter");*/ | 652 | /*speex_warning("reinit filter");*/ |
659 | } else if (st->filt_len > old_length) | 653 | } else if (st->filt_len > old_length) |
660 | { | 654 | { |
@@ -662,10 +656,10 @@ static void update_filter(SpeexResamplerState *st) | |||
662 | /* Increase the filter length */ | 656 | /* Increase the filter length */ |
663 | /*speex_warning("increase filter size");*/ | 657 | /*speex_warning("increase filter size");*/ |
664 | int old_alloc_size = st->mem_alloc_size; | 658 | int old_alloc_size = st->mem_alloc_size; |
665 | if (st->filt_len-1 > st->mem_alloc_size) | 659 | if ((st->filt_len-1 + st->buffer_size) > st->mem_alloc_size) |
666 | { | 660 | { |
667 | st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); | 661 | st->mem_alloc_size = st->filt_len-1 + st->buffer_size; |
668 | st->mem_alloc_size = st->filt_len-1; | 662 | st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); |
669 | } | 663 | } |
670 | for (i=st->nb_channels-1;i>=0;i--) | 664 | for (i=st->nb_channels-1;i>=0;i--) |
671 | { | 665 | { |
@@ -674,7 +668,7 @@ static void update_filter(SpeexResamplerState *st) | |||
674 | /*if (st->magic_samples[i])*/ | 668 | /*if (st->magic_samples[i])*/ |
675 | { | 669 | { |
676 | /* Try and remove the magic samples as if nothing had happened */ | 670 | /* Try and remove the magic samples as if nothing had happened */ |
677 | 671 | ||
678 | /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */ | 672 | /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */ |
679 | olen = old_length + 2*st->magic_samples[i]; | 673 | olen = old_length + 2*st->magic_samples[i]; |
680 | for (j=old_length-2+st->magic_samples[i];j>=0;j--) | 674 | for (j=old_length-2+st->magic_samples[i];j>=0;j--) |
@@ -721,12 +715,12 @@ static void update_filter(SpeexResamplerState *st) | |||
721 | 715 | ||
722 | } | 716 | } |
723 | 717 | ||
724 | SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) | 718 | EXPORT SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) |
725 | { | 719 | { |
726 | return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err); | 720 | return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err); |
727 | } | 721 | } |
728 | 722 | ||
729 | 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) | 723 | 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) |
730 | { | 724 | { |
731 | spx_uint32_t i; | 725 | spx_uint32_t i; |
732 | SpeexResamplerState *st; | 726 | SpeexResamplerState *st; |
@@ -749,12 +743,18 @@ SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uin | |||
749 | st->filt_len = 0; | 743 | st->filt_len = 0; |
750 | st->mem = 0; | 744 | st->mem = 0; |
751 | st->resampler_ptr = 0; | 745 | st->resampler_ptr = 0; |
752 | 746 | ||
753 | st->cutoff = 1.f; | 747 | st->cutoff = 1.f; |
754 | st->nb_channels = nb_channels; | 748 | st->nb_channels = nb_channels; |
755 | st->in_stride = 1; | 749 | st->in_stride = 1; |
756 | st->out_stride = 1; | 750 | st->out_stride = 1; |
757 | 751 | ||
752 | #ifdef FIXED_POINT | ||
753 | st->buffer_size = 160; | ||
754 | #else | ||
755 | st->buffer_size = 160; | ||
756 | #endif | ||
757 | |||
758 | /* Per channel data */ | 758 | /* Per channel data */ |
759 | st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int)); | 759 | st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int)); |
760 | st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int)); | 760 | st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int)); |
@@ -769,9 +769,9 @@ SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uin | |||
769 | speex_resampler_set_quality(st, quality); | 769 | speex_resampler_set_quality(st, quality); |
770 | speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate); | 770 | speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate); |
771 | 771 | ||
772 | 772 | ||
773 | update_filter(st); | 773 | update_filter(st); |
774 | 774 | ||
775 | st->initialised = 1; | 775 | st->initialised = 1; |
776 | if (err) | 776 | if (err) |
777 | *err = RESAMPLER_ERR_SUCCESS; | 777 | *err = RESAMPLER_ERR_SUCCESS; |
@@ -779,7 +779,7 @@ SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uin | |||
779 | return st; | 779 | return st; |
780 | } | 780 | } |
781 | 781 | ||
782 | void speex_resampler_destroy(SpeexResamplerState *st) | 782 | EXPORT void speex_resampler_destroy(SpeexResamplerState *st) |
783 | { | 783 | { |
784 | speex_free(st->mem); | 784 | speex_free(st->mem); |
785 | speex_free(st->sinc_table); | 785 | speex_free(st->sinc_table); |
@@ -789,186 +789,168 @@ void speex_resampler_destroy(SpeexResamplerState *st) | |||
789 | speex_free(st); | 789 | speex_free(st); |
790 | } | 790 | } |
791 | 791 | ||
792 | 792 | 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) | |
793 | |||
794 | 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) | ||
795 | { | 793 | { |
796 | int j=0; | 794 | int j=0; |
797 | int N = st->filt_len; | 795 | const int N = st->filt_len; |
798 | int out_sample = 0; | 796 | int out_sample = 0; |
799 | spx_word16_t *mem; | 797 | spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size; |
800 | spx_uint32_t tmp_out_len = 0; | 798 | spx_uint32_t ilen; |
801 | mem = st->mem + channel_index * st->mem_alloc_size; | 799 | |
802 | st->started = 1; | 800 | st->started = 1; |
803 | 801 | ||
804 | /* Handle the case where we have samples left from a reduction in filter length */ | ||
805 | if (st->magic_samples[channel_index]) | ||
806 | { | ||
807 | int istride_save; | ||
808 | spx_uint32_t tmp_in_len; | ||
809 | spx_uint32_t tmp_magic; | ||
810 | |||
811 | istride_save = st->in_stride; | ||
812 | tmp_in_len = st->magic_samples[channel_index]; | ||
813 | tmp_out_len = *out_len; | ||
814 | /* magic_samples needs to be set to zero to avoid infinite recursion */ | ||
815 | tmp_magic = st->magic_samples[channel_index]; | ||
816 | st->magic_samples[channel_index] = 0; | ||
817 | st->in_stride = 1; | ||
818 | speex_resampler_process_native(st, channel_index, mem+N-1, &tmp_in_len, out, &tmp_out_len); | ||
819 | st->in_stride = istride_save; | ||
820 | /*speex_warning_int("extra samples:", tmp_out_len);*/ | ||
821 | /* If we couldn't process all "magic" input samples, save the rest for next time */ | ||
822 | if (tmp_in_len < tmp_magic) | ||
823 | { | ||
824 | spx_uint32_t i; | ||
825 | st->magic_samples[channel_index] = tmp_magic-tmp_in_len; | ||
826 | for (i=0;i<st->magic_samples[channel_index];i++) | ||
827 | mem[N-1+i]=mem[N-1+i+tmp_in_len]; | ||
828 | } | ||
829 | out += tmp_out_len*st->out_stride; | ||
830 | *out_len -= tmp_out_len; | ||
831 | } | ||
832 | |||
833 | /* Call the right resampler through the function ptr */ | 802 | /* Call the right resampler through the function ptr */ |
834 | out_sample = st->resampler_ptr(st, channel_index, in, in_len, out, out_len); | 803 | out_sample = st->resampler_ptr(st, channel_index, mem, in_len, out, out_len); |
835 | 804 | ||
836 | if (st->last_sample[channel_index] < (spx_int32_t)*in_len) | 805 | if (st->last_sample[channel_index] < (spx_int32_t)*in_len) |
837 | *in_len = st->last_sample[channel_index]; | 806 | *in_len = st->last_sample[channel_index]; |
838 | *out_len = out_sample+tmp_out_len; | 807 | *out_len = out_sample; |
839 | st->last_sample[channel_index] -= *in_len; | 808 | st->last_sample[channel_index] -= *in_len; |
840 | 809 | ||
841 | for (j=0;j<N-1-(spx_int32_t)*in_len;j++) | 810 | ilen = *in_len; |
842 | mem[j] = mem[j+*in_len]; | 811 | |
843 | for (;j<N-1;j++) | 812 | for(j=0;j<N-1;++j) |
844 | mem[j] = in[st->in_stride*(j+*in_len-N+1)]; | 813 | mem[j] = mem[j+ilen]; |
845 | 814 | ||
846 | return RESAMPLER_ERR_SUCCESS; | 815 | return RESAMPLER_ERR_SUCCESS; |
847 | } | 816 | } |
848 | 817 | ||
849 | #define FIXED_STACK_ALLOC 1024 | 818 | static int speex_resampler_magic(SpeexResamplerState *st, spx_uint32_t channel_index, spx_word16_t **out, spx_uint32_t out_len) { |
819 | spx_uint32_t tmp_in_len = st->magic_samples[channel_index]; | ||
820 | spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size; | ||
821 | const int N = st->filt_len; | ||
822 | |||
823 | speex_resampler_process_native(st, channel_index, &tmp_in_len, *out, &out_len); | ||
824 | |||
825 | st->magic_samples[channel_index] -= tmp_in_len; | ||
826 | |||
827 | /* If we couldn't process all "magic" input samples, save the rest for next time */ | ||
828 | if (st->magic_samples[channel_index]) | ||
829 | { | ||
830 | spx_uint32_t i; | ||
831 | for (i=0;i<st->magic_samples[channel_index];i++) | ||
832 | mem[N-1+i]=mem[N-1+i+tmp_in_len]; | ||
833 | } | ||
834 | *out += out_len*st->out_stride; | ||
835 | return out_len; | ||
836 | } | ||
850 | 837 | ||
851 | #ifdef FIXED_POINT | 838 | #ifdef FIXED_POINT |
852 | 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) | 839 | 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) |
853 | { | ||
854 | spx_uint32_t i; | ||
855 | int istride_save, ostride_save; | ||
856 | #ifdef VAR_ARRAYS | ||
857 | spx_word16_t x[*in_len]; | ||
858 | spx_word16_t y[*out_len]; | ||
859 | /*VARDECL(spx_word16_t *x); | ||
860 | VARDECL(spx_word16_t *y); | ||
861 | ALLOC(x, *in_len, spx_word16_t); | ||
862 | ALLOC(y, *out_len, spx_word16_t);*/ | ||
863 | istride_save = st->in_stride; | ||
864 | ostride_save = st->out_stride; | ||
865 | for (i=0;i<*in_len;i++) | ||
866 | x[i] = WORD2INT(in[i*st->in_stride]); | ||
867 | st->in_stride = st->out_stride = 1; | ||
868 | speex_resampler_process_native(st, channel_index, x, in_len, y, out_len); | ||
869 | st->in_stride = istride_save; | ||
870 | st->out_stride = ostride_save; | ||
871 | for (i=0;i<*out_len;i++) | ||
872 | out[i*st->out_stride] = y[i]; | ||
873 | #else | 840 | #else |
874 | spx_word16_t x[FIXED_STACK_ALLOC]; | 841 | 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) |
875 | spx_word16_t y[FIXED_STACK_ALLOC]; | 842 | #endif |
876 | spx_uint32_t ilen=*in_len, olen=*out_len; | 843 | { |
877 | istride_save = st->in_stride; | 844 | int j; |
878 | ostride_save = st->out_stride; | 845 | spx_uint32_t ilen = *in_len; |
879 | while (ilen && olen) | 846 | spx_uint32_t olen = *out_len; |
880 | { | 847 | spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size; |
881 | spx_uint32_t ichunk, ochunk; | 848 | const int filt_offs = st->filt_len - 1; |
882 | ichunk = ilen; | 849 | const spx_uint32_t xlen = st->mem_alloc_size - filt_offs; |
883 | ochunk = olen; | 850 | const int istride = st->in_stride; |
884 | if (ichunk>FIXED_STACK_ALLOC) | 851 | |
885 | ichunk=FIXED_STACK_ALLOC; | 852 | if (st->magic_samples[channel_index]) |
886 | if (ochunk>FIXED_STACK_ALLOC) | 853 | olen -= speex_resampler_magic(st, channel_index, &out, olen); |
887 | ochunk=FIXED_STACK_ALLOC; | 854 | if (! st->magic_samples[channel_index]) { |
888 | for (i=0;i<ichunk;i++) | 855 | while (ilen && olen) { |
889 | x[i] = WORD2INT(in[i*st->in_stride]); | 856 | spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen; |
890 | st->in_stride = st->out_stride = 1; | 857 | spx_uint32_t ochunk = olen; |
891 | speex_resampler_process_native(st, channel_index, x, &ichunk, y, &ochunk); | 858 | |
892 | st->in_stride = istride_save; | 859 | if (in) { |
893 | st->out_stride = ostride_save; | 860 | for(j=0;j<ichunk;++j) |
894 | for (i=0;i<ochunk;i++) | 861 | x[j+filt_offs]=in[j*istride]; |
895 | out[i*st->out_stride] = y[i]; | 862 | } else { |
896 | out += ochunk; | 863 | for(j=0;j<ichunk;++j) |
897 | in += ichunk; | 864 | x[j+filt_offs]=0; |
898 | ilen -= ichunk; | 865 | } |
899 | olen -= ochunk; | 866 | speex_resampler_process_native(st, channel_index, &ichunk, out, &ochunk); |
867 | ilen -= ichunk; | ||
868 | olen -= ochunk; | ||
869 | out += ochunk * st->out_stride; | ||
870 | if (in) | ||
871 | in += ichunk * istride; | ||
872 | } | ||
900 | } | 873 | } |
901 | *in_len -= ilen; | 874 | *in_len -= ilen; |
902 | *out_len -= olen; | 875 | *out_len -= olen; |
903 | #endif | ||
904 | return RESAMPLER_ERR_SUCCESS; | 876 | return RESAMPLER_ERR_SUCCESS; |
905 | } | 877 | } |
906 | 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) | 878 | |
907 | { | 879 | #ifdef FIXED_POINT |
908 | return speex_resampler_process_native(st, channel_index, in, in_len, out, out_len); | 880 | 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) |
909 | } | ||
910 | #else | 881 | #else |
911 | 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) | 882 | 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) |
912 | { | 883 | #endif |
913 | return speex_resampler_process_native(st, channel_index, in, in_len, out, out_len); | ||
914 | } | ||
915 | 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) | ||
916 | { | 884 | { |
917 | spx_uint32_t i; | 885 | int j; |
918 | int istride_save, ostride_save; | 886 | const int istride_save = st->in_stride; |
887 | const int ostride_save = st->out_stride; | ||
888 | spx_uint32_t ilen = *in_len; | ||
889 | spx_uint32_t olen = *out_len; | ||
890 | spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size; | ||
891 | const spx_uint32_t xlen = st->mem_alloc_size - (st->filt_len - 1); | ||
919 | #ifdef VAR_ARRAYS | 892 | #ifdef VAR_ARRAYS |
920 | spx_word16_t x[*in_len]; | 893 | const unsigned int ylen = (olen < FIXED_STACK_ALLOC) ? olen : FIXED_STACK_ALLOC; |
921 | spx_word16_t y[*out_len]; | 894 | VARDECL(spx_word16_t *ystack); |
922 | /*VARDECL(spx_word16_t *x); | 895 | ALLOC(ystack, ylen, spx_word16_t); |
923 | VARDECL(spx_word16_t *y); | ||
924 | ALLOC(x, *in_len, spx_word16_t); | ||
925 | ALLOC(y, *out_len, spx_word16_t);*/ | ||
926 | istride_save = st->in_stride; | ||
927 | ostride_save = st->out_stride; | ||
928 | for (i=0;i<*in_len;i++) | ||
929 | x[i] = in[i*st->in_stride]; | ||
930 | st->in_stride = st->out_stride = 1; | ||
931 | speex_resampler_process_native(st, channel_index, x, in_len, y, out_len); | ||
932 | st->in_stride = istride_save; | ||
933 | st->out_stride = ostride_save; | ||
934 | for (i=0;i<*out_len;i++) | ||
935 | out[i*st->out_stride] = WORD2INT(y[i]); | ||
936 | #else | 896 | #else |
937 | spx_word16_t x[FIXED_STACK_ALLOC]; | 897 | const unsigned int ylen = FIXED_STACK_ALLOC; |
938 | spx_word16_t y[FIXED_STACK_ALLOC]; | 898 | spx_word16_t ystack[FIXED_STACK_ALLOC]; |
939 | spx_uint32_t ilen=*in_len, olen=*out_len; | 899 | #endif |
940 | istride_save = st->in_stride; | 900 | |
941 | ostride_save = st->out_stride; | 901 | st->out_stride = 1; |
942 | while (ilen && olen) | 902 | |
943 | { | 903 | while (ilen && olen) { |
944 | spx_uint32_t ichunk, ochunk; | 904 | spx_word16_t *y = ystack; |
945 | ichunk = ilen; | 905 | spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen; |
946 | ochunk = olen; | 906 | spx_uint32_t ochunk = (olen > ylen) ? ylen : olen; |
947 | if (ichunk>FIXED_STACK_ALLOC) | 907 | spx_uint32_t omagic = 0; |
948 | ichunk=FIXED_STACK_ALLOC; | 908 | |
949 | if (ochunk>FIXED_STACK_ALLOC) | 909 | if (st->magic_samples[channel_index]) { |
950 | ochunk=FIXED_STACK_ALLOC; | 910 | omagic = speex_resampler_magic(st, channel_index, &y, ochunk); |
951 | for (i=0;i<ichunk;i++) | 911 | ochunk -= omagic; |
952 | x[i] = in[i*st->in_stride]; | 912 | olen -= omagic; |
953 | st->in_stride = st->out_stride = 1; | 913 | } |
954 | speex_resampler_process_native(st, channel_index, x, &ichunk, y, &ochunk); | 914 | if (! st->magic_samples[channel_index]) { |
955 | st->in_stride = istride_save; | 915 | if (in) { |
956 | st->out_stride = ostride_save; | 916 | for(j=0;j<ichunk;++j) |
957 | for (i=0;i<ochunk;i++) | 917 | #ifdef FIXED_POINT |
958 | out[i*st->out_stride] = WORD2INT(y[i]); | 918 | x[j+st->filt_len-1]=WORD2INT(in[j*istride_save]); |
959 | out += ochunk; | 919 | #else |
960 | in += ichunk; | 920 | x[j+st->filt_len-1]=in[j*istride_save]; |
961 | ilen -= ichunk; | 921 | #endif |
962 | olen -= ochunk; | 922 | } else { |
923 | for(j=0;j<ichunk;++j) | ||
924 | x[j+st->filt_len-1]=0; | ||
925 | } | ||
926 | |||
927 | speex_resampler_process_native(st, channel_index, &ichunk, y, &ochunk); | ||
928 | } else { | ||
929 | ichunk = 0; | ||
930 | ochunk = 0; | ||
931 | } | ||
932 | |||
933 | for (j=0;j<ochunk+omagic;++j) | ||
934 | #ifdef FIXED_POINT | ||
935 | out[j*ostride_save] = ystack[j]; | ||
936 | #else | ||
937 | out[j*ostride_save] = WORD2INT(ystack[j]); | ||
938 | #endif | ||
939 | |||
940 | ilen -= ichunk; | ||
941 | olen -= ochunk; | ||
942 | out += (ochunk+omagic) * ostride_save; | ||
943 | if (in) | ||
944 | in += ichunk * istride_save; | ||
963 | } | 945 | } |
946 | st->out_stride = ostride_save; | ||
964 | *in_len -= ilen; | 947 | *in_len -= ilen; |
965 | *out_len -= olen; | 948 | *out_len -= olen; |
966 | #endif | 949 | |
967 | return RESAMPLER_ERR_SUCCESS; | 950 | return RESAMPLER_ERR_SUCCESS; |
968 | } | 951 | } |
969 | #endif | ||
970 | 952 | ||
971 | int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) | 953 | EXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) |
972 | { | 954 | { |
973 | spx_uint32_t i; | 955 | spx_uint32_t i; |
974 | int istride_save, ostride_save; | 956 | int istride_save, ostride_save; |
@@ -989,8 +971,7 @@ int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const flo | |||
989 | return RESAMPLER_ERR_SUCCESS; | 971 | return RESAMPLER_ERR_SUCCESS; |
990 | } | 972 | } |
991 | 973 | ||
992 | 974 | 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) | |
993 | 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) | ||
994 | { | 975 | { |
995 | spx_uint32_t i; | 976 | spx_uint32_t i; |
996 | int istride_save, ostride_save; | 977 | int istride_save, ostride_save; |
@@ -1011,25 +992,25 @@ int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_i | |||
1011 | return RESAMPLER_ERR_SUCCESS; | 992 | return RESAMPLER_ERR_SUCCESS; |
1012 | } | 993 | } |
1013 | 994 | ||
1014 | int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate) | 995 | EXPORT int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate) |
1015 | { | 996 | { |
1016 | return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate); | 997 | return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate); |
1017 | } | 998 | } |
1018 | 999 | ||
1019 | void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate) | 1000 | EXPORT void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate) |
1020 | { | 1001 | { |
1021 | *in_rate = st->in_rate; | 1002 | *in_rate = st->in_rate; |
1022 | *out_rate = st->out_rate; | 1003 | *out_rate = st->out_rate; |
1023 | } | 1004 | } |
1024 | 1005 | ||
1025 | 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) | 1006 | 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) |
1026 | { | 1007 | { |
1027 | spx_uint32_t fact; | 1008 | spx_uint32_t fact; |
1028 | spx_uint32_t old_den; | 1009 | spx_uint32_t old_den; |
1029 | spx_uint32_t i; | 1010 | spx_uint32_t i; |
1030 | if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den) | 1011 | if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den) |
1031 | return RESAMPLER_ERR_SUCCESS; | 1012 | return RESAMPLER_ERR_SUCCESS; |
1032 | 1013 | ||
1033 | old_den = st->den_rate; | 1014 | old_den = st->den_rate; |
1034 | st->in_rate = in_rate; | 1015 | st->in_rate = in_rate; |
1035 | st->out_rate = out_rate; | 1016 | st->out_rate = out_rate; |
@@ -1044,7 +1025,7 @@ int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_nu | |||
1044 | st->den_rate /= fact; | 1025 | st->den_rate /= fact; |
1045 | } | 1026 | } |
1046 | } | 1027 | } |
1047 | 1028 | ||
1048 | if (old_den > 0) | 1029 | if (old_den > 0) |
1049 | { | 1030 | { |
1050 | for (i=0;i<st->nb_channels;i++) | 1031 | for (i=0;i<st->nb_channels;i++) |
@@ -1055,19 +1036,19 @@ int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_nu | |||
1055 | st->samp_frac_num[i] = st->den_rate-1; | 1036 | st->samp_frac_num[i] = st->den_rate-1; |
1056 | } | 1037 | } |
1057 | } | 1038 | } |
1058 | 1039 | ||
1059 | if (st->initialised) | 1040 | if (st->initialised) |
1060 | update_filter(st); | 1041 | update_filter(st); |
1061 | return RESAMPLER_ERR_SUCCESS; | 1042 | return RESAMPLER_ERR_SUCCESS; |
1062 | } | 1043 | } |
1063 | 1044 | ||
1064 | void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den) | 1045 | EXPORT void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den) |
1065 | { | 1046 | { |
1066 | *ratio_num = st->num_rate; | 1047 | *ratio_num = st->num_rate; |
1067 | *ratio_den = st->den_rate; | 1048 | *ratio_den = st->den_rate; |
1068 | } | 1049 | } |
1069 | 1050 | ||
1070 | int speex_resampler_set_quality(SpeexResamplerState *st, int quality) | 1051 | EXPORT int speex_resampler_set_quality(SpeexResamplerState *st, int quality) |
1071 | { | 1052 | { |
1072 | if (quality > 10 || quality < 0) | 1053 | if (quality > 10 || quality < 0) |
1073 | return RESAMPLER_ERR_INVALID_ARG; | 1054 | return RESAMPLER_ERR_INVALID_ARG; |
@@ -1079,32 +1060,42 @@ int speex_resampler_set_quality(SpeexResamplerState *st, int quality) | |||
1079 | return RESAMPLER_ERR_SUCCESS; | 1060 | return RESAMPLER_ERR_SUCCESS; |
1080 | } | 1061 | } |
1081 | 1062 | ||
1082 | void speex_resampler_get_quality(SpeexResamplerState *st, int *quality) | 1063 | EXPORT void speex_resampler_get_quality(SpeexResamplerState *st, int *quality) |
1083 | { | 1064 | { |
1084 | *quality = st->quality; | 1065 | *quality = st->quality; |
1085 | } | 1066 | } |
1086 | 1067 | ||
1087 | void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride) | 1068 | EXPORT void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride) |
1088 | { | 1069 | { |
1089 | st->in_stride = stride; | 1070 | st->in_stride = stride; |
1090 | } | 1071 | } |
1091 | 1072 | ||
1092 | void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride) | 1073 | EXPORT void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride) |
1093 | { | 1074 | { |
1094 | *stride = st->in_stride; | 1075 | *stride = st->in_stride; |
1095 | } | 1076 | } |
1096 | 1077 | ||
1097 | void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride) | 1078 | EXPORT void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride) |
1098 | { | 1079 | { |
1099 | st->out_stride = stride; | 1080 | st->out_stride = stride; |
1100 | } | 1081 | } |
1101 | 1082 | ||
1102 | void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride) | 1083 | EXPORT void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride) |
1103 | { | 1084 | { |
1104 | *stride = st->out_stride; | 1085 | *stride = st->out_stride; |
1105 | } | 1086 | } |
1106 | 1087 | ||
1107 | int speex_resampler_skip_zeros(SpeexResamplerState *st) | 1088 | EXPORT int speex_resampler_get_input_latency(SpeexResamplerState *st) |
1089 | { | ||
1090 | return st->filt_len / 2; | ||
1091 | } | ||
1092 | |||
1093 | EXPORT int speex_resampler_get_output_latency(SpeexResamplerState *st) | ||
1094 | { | ||
1095 | return ((st->filt_len / 2) * st->den_rate + (st->num_rate >> 1)) / st->num_rate; | ||
1096 | } | ||
1097 | |||
1098 | EXPORT int speex_resampler_skip_zeros(SpeexResamplerState *st) | ||
1108 | { | 1099 | { |
1109 | spx_uint32_t i; | 1100 | spx_uint32_t i; |
1110 | for (i=0;i<st->nb_channels;i++) | 1101 | for (i=0;i<st->nb_channels;i++) |
@@ -1112,7 +1103,7 @@ int speex_resampler_skip_zeros(SpeexResamplerState *st) | |||
1112 | return RESAMPLER_ERR_SUCCESS; | 1103 | return RESAMPLER_ERR_SUCCESS; |
1113 | } | 1104 | } |
1114 | 1105 | ||
1115 | int speex_resampler_reset_mem(SpeexResamplerState *st) | 1106 | EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st) |
1116 | { | 1107 | { |
1117 | spx_uint32_t i; | 1108 | spx_uint32_t i; |
1118 | for (i=0;i<st->nb_channels*(st->filt_len-1);i++) | 1109 | for (i=0;i<st->nb_channels*(st->filt_len-1);i++) |
@@ -1120,7 +1111,7 @@ int speex_resampler_reset_mem(SpeexResamplerState *st) | |||
1120 | return RESAMPLER_ERR_SUCCESS; | 1111 | return RESAMPLER_ERR_SUCCESS; |
1121 | } | 1112 | } |
1122 | 1113 | ||
1123 | const char *speex_resampler_strerror(int err) | 1114 | EXPORT const char *speex_resampler_strerror(int err) |
1124 | { | 1115 | { |
1125 | switch (err) | 1116 | switch (err) |
1126 | { | 1117 | { |
diff --git a/lib/rbcodec/codecs/libspeex/resample_sse.h b/lib/rbcodec/codecs/libspeex/resample_sse.h new file mode 100644 index 0000000000..d85898067e --- /dev/null +++ b/lib/rbcodec/codecs/libspeex/resample_sse.h | |||
@@ -0,0 +1,128 @@ | |||
1 | /* Copyright (C) 2007-2008 Jean-Marc Valin | ||
2 | * Copyright (C) 2008 Thorvald Natvig | ||
3 | */ | ||
4 | /** | ||
5 | @file resample_sse.h | ||
6 | @brief Resampler functions (SSE version) | ||
7 | */ | ||
8 | /* | ||
9 | Redistribution and use in source and binary forms, with or without | ||
10 | modification, are permitted provided that the following conditions | ||
11 | are met: | ||
12 | |||
13 | - Redistributions of source code must retain the above copyright | ||
14 | notice, this list of conditions and the following disclaimer. | ||
15 | |||
16 | - Redistributions in binary form must reproduce the above copyright | ||
17 | notice, this list of conditions and the following disclaimer in the | ||
18 | documentation and/or other materials provided with the distribution. | ||
19 | |||
20 | - Neither the name of the Xiph.org Foundation nor the names of its | ||
21 | contributors may be used to endorse or promote products derived from | ||
22 | this software without specific prior written permission. | ||
23 | |||
24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
25 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
26 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
27 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR | ||
28 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
30 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
31 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
32 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
33 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
34 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
35 | */ | ||
36 | |||
37 | #include <xmmintrin.h> | ||
38 | |||
39 | #define OVERRIDE_INNER_PRODUCT_SINGLE | ||
40 | static inline float inner_product_single(const float *a, const float *b, unsigned int len) | ||
41 | { | ||
42 | int i; | ||
43 | float ret; | ||
44 | __m128 sum = _mm_setzero_ps(); | ||
45 | for (i=0;i<len;i+=8) | ||
46 | { | ||
47 | sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(a+i), _mm_loadu_ps(b+i))); | ||
48 | sum = _mm_add_ps(sum, _mm_mul_ps(_mm_loadu_ps(a+i+4), _mm_loadu_ps(b+i+4))); | ||
49 | } | ||
50 | sum = _mm_add_ps(sum, _mm_movehl_ps(sum, sum)); | ||
51 | sum = _mm_add_ss(sum, _mm_shuffle_ps(sum, sum, 0x55)); | ||
52 | _mm_store_ss(&ret, sum); | ||
53 | return ret; | ||
54 | } | ||
55 | |||
56 | #define OVERRIDE_INTERPOLATE_PRODUCT_SINGLE | ||
57 | static inline float interpolate_product_single(const float *a, const float *b, unsigned int len, const spx_uint32_t oversample, float *frac) { | ||
58 | int i; | ||
59 | float ret; | ||
60 | __m128 sum = _mm_setzero_ps(); | ||
61 | __m128 f = _mm_loadu_ps(frac); | ||
62 | for(i=0;i<len;i+=2) | ||
63 | { | ||
64 | sum = _mm_add_ps(sum, _mm_mul_ps(_mm_load1_ps(a+i), _mm_loadu_ps(b+i*oversample))); | ||
65 | sum = _mm_add_ps(sum, _mm_mul_ps(_mm_load1_ps(a+i+1), _mm_loadu_ps(b+(i+1)*oversample))); | ||
66 | } | ||
67 | sum = _mm_mul_ps(f, sum); | ||
68 | sum = _mm_add_ps(sum, _mm_movehl_ps(sum, sum)); | ||
69 | sum = _mm_add_ss(sum, _mm_shuffle_ps(sum, sum, 0x55)); | ||
70 | _mm_store_ss(&ret, sum); | ||
71 | return ret; | ||
72 | } | ||
73 | |||
74 | #ifdef _USE_SSE2 | ||
75 | #include <emmintrin.h> | ||
76 | #define OVERRIDE_INNER_PRODUCT_DOUBLE | ||
77 | |||
78 | static inline double inner_product_double(const float *a, const float *b, unsigned int len) | ||
79 | { | ||
80 | int i; | ||
81 | double ret; | ||
82 | __m128d sum = _mm_setzero_pd(); | ||
83 | __m128 t; | ||
84 | for (i=0;i<len;i+=8) | ||
85 | { | ||
86 | t = _mm_mul_ps(_mm_loadu_ps(a+i), _mm_loadu_ps(b+i)); | ||
87 | sum = _mm_add_pd(sum, _mm_cvtps_pd(t)); | ||
88 | sum = _mm_add_pd(sum, _mm_cvtps_pd(_mm_movehl_ps(t, t))); | ||
89 | |||
90 | t = _mm_mul_ps(_mm_loadu_ps(a+i+4), _mm_loadu_ps(b+i+4)); | ||
91 | sum = _mm_add_pd(sum, _mm_cvtps_pd(t)); | ||
92 | sum = _mm_add_pd(sum, _mm_cvtps_pd(_mm_movehl_ps(t, t))); | ||
93 | } | ||
94 | sum = _mm_add_sd(sum, (__m128d) _mm_movehl_ps((__m128) sum, (__m128) sum)); | ||
95 | _mm_store_sd(&ret, sum); | ||
96 | return ret; | ||
97 | } | ||
98 | |||
99 | #define OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE | ||
100 | static inline double interpolate_product_double(const float *a, const float *b, unsigned int len, const spx_uint32_t oversample, float *frac) { | ||
101 | int i; | ||
102 | double ret; | ||
103 | __m128d sum; | ||
104 | __m128d sum1 = _mm_setzero_pd(); | ||
105 | __m128d sum2 = _mm_setzero_pd(); | ||
106 | __m128 f = _mm_loadu_ps(frac); | ||
107 | __m128d f1 = _mm_cvtps_pd(f); | ||
108 | __m128d f2 = _mm_cvtps_pd(_mm_movehl_ps(f,f)); | ||
109 | __m128 t; | ||
110 | for(i=0;i<len;i+=2) | ||
111 | { | ||
112 | t = _mm_mul_ps(_mm_load1_ps(a+i), _mm_loadu_ps(b+i*oversample)); | ||
113 | sum1 = _mm_add_pd(sum1, _mm_cvtps_pd(t)); | ||
114 | sum2 = _mm_add_pd(sum2, _mm_cvtps_pd(_mm_movehl_ps(t, t))); | ||
115 | |||
116 | t = _mm_mul_ps(_mm_load1_ps(a+i+1), _mm_loadu_ps(b+(i+1)*oversample)); | ||
117 | sum1 = _mm_add_pd(sum1, _mm_cvtps_pd(t)); | ||
118 | sum2 = _mm_add_pd(sum2, _mm_cvtps_pd(_mm_movehl_ps(t, t))); | ||
119 | } | ||
120 | sum1 = _mm_mul_pd(f1, sum1); | ||
121 | sum2 = _mm_mul_pd(f2, sum2); | ||
122 | sum = _mm_add_pd(sum1, sum2); | ||
123 | sum = _mm_add_sd(sum, (__m128d) _mm_movehl_ps((__m128) sum, (__m128) sum)); | ||
124 | _mm_store_sd(&ret, sum); | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | #endif | ||
diff --git a/lib/rbcodec/codecs/libspeex/speex.c b/lib/rbcodec/codecs/libspeex/speex.c index 92e41f52ae..9836de36b8 100644 --- a/lib/rbcodec/codecs/libspeex/speex.c +++ b/lib/rbcodec/codecs/libspeex/speex.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* Copyright (C) 2002 Jean-Marc Valin | 1 | /* Copyright (C) 2002 Jean-Marc Valin |
2 | File: speex.c | 2 | File: speex.c |
3 | 3 | ||
4 | Basic Speex functions | 4 | Basic Speex functions |
@@ -6,18 +6,18 @@ | |||
6 | Redistribution and use in source and binary forms, with or without | 6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions | 7 | modification, are permitted provided that the following conditions |
8 | are met: | 8 | are met: |
9 | 9 | ||
10 | - Redistributions of source code must retain the above copyright | 10 | - Redistributions of source code must retain the above copyright |
11 | notice, this list of conditions and the following disclaimer. | 11 | notice, this list of conditions and the following disclaimer. |
12 | 12 | ||
13 | - Redistributions in binary form must reproduce the above copyright | 13 | - Redistributions in binary form must reproduce the above copyright |
14 | notice, this list of conditions and the following disclaimer in the | 14 | notice, this list of conditions and the following disclaimer in the |
15 | documentation and/or other materials provided with the distribution. | 15 | documentation and/or other materials provided with the distribution. |
16 | 16 | ||
17 | - Neither the name of the Xiph.org Foundation nor the names of its | 17 | - Neither the name of the Xiph.org Foundation nor the names of its |
18 | contributors may be used to endorse or promote products derived from | 18 | contributors may be used to endorse or promote products derived from |
19 | this software without specific prior written permission. | 19 | this software without specific prior written permission. |
20 | 20 | ||
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
22 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 22 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
@@ -49,25 +49,25 @@ | |||
49 | #define MAX_IN_SAMPLES 640 | 49 | #define MAX_IN_SAMPLES 640 |
50 | 50 | ||
51 | #ifndef SPEEX_DISABLE_ENCODER | 51 | #ifndef SPEEX_DISABLE_ENCODER |
52 | void *speex_encoder_init(const SpeexMode *mode) | 52 | EXPORT void *speex_encoder_init(const SpeexMode *mode) |
53 | { | 53 | { |
54 | return mode->enc_init(mode); | 54 | return mode->enc_init(mode); |
55 | } | 55 | } |
56 | #endif | 56 | #endif |
57 | 57 | ||
58 | void *speex_decoder_init(const SpeexMode *mode) | 58 | EXPORT void *speex_decoder_init(const SpeexMode *mode) |
59 | { | 59 | { |
60 | return mode->dec_init(mode); | 60 | return mode->dec_init(mode); |
61 | } | 61 | } |
62 | 62 | ||
63 | #ifndef SPEEX_DISABLE_ENCODER | 63 | #ifndef SPEEX_DISABLE_ENCODER |
64 | void speex_encoder_destroy(void *state) | 64 | EXPORT void speex_encoder_destroy(void *state) |
65 | { | 65 | { |
66 | (*((SpeexMode**)state))->enc_destroy(state); | 66 | (*((SpeexMode**)state))->enc_destroy(state); |
67 | } | 67 | } |
68 | #endif | 68 | #endif |
69 | 69 | ||
70 | void speex_decoder_destroy(void *state) | 70 | EXPORT void speex_decoder_destroy(void *state) |
71 | { | 71 | { |
72 | (*((SpeexMode**)state))->dec_destroy(state); | 72 | (*((SpeexMode**)state))->dec_destroy(state); |
73 | } | 73 | } |
@@ -90,7 +90,7 @@ int speex_decode_native(void *state, SpeexBits *bits, spx_word16_t *out) | |||
90 | 90 | ||
91 | #ifndef SPEEX_DISABLE_ENCODER | 91 | #ifndef SPEEX_DISABLE_ENCODER |
92 | #ifndef DISABLE_FLOAT_API | 92 | #ifndef DISABLE_FLOAT_API |
93 | int speex_encode(void *state, float *in, SpeexBits *bits) | 93 | EXPORT int speex_encode(void *state, float *in, SpeexBits *bits) |
94 | { | 94 | { |
95 | int i; | 95 | int i; |
96 | spx_int32_t N; | 96 | spx_int32_t N; |
@@ -109,7 +109,7 @@ int speex_encode(void *state, float *in, SpeexBits *bits) | |||
109 | } | 109 | } |
110 | #endif /* #ifndef DISABLE_FLOAT_API */ | 110 | #endif /* #ifndef DISABLE_FLOAT_API */ |
111 | 111 | ||
112 | int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) | 112 | EXPORT int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) |
113 | { | 113 | { |
114 | SpeexMode *mode; | 114 | SpeexMode *mode; |
115 | mode = *(SpeexMode**)state; | 115 | mode = *(SpeexMode**)state; |
@@ -118,7 +118,7 @@ int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) | |||
118 | #endif /* SPEEX_DISABLE_ENCODER */ | 118 | #endif /* SPEEX_DISABLE_ENCODER */ |
119 | 119 | ||
120 | #ifndef DISABLE_FLOAT_API | 120 | #ifndef DISABLE_FLOAT_API |
121 | int speex_decode(void *state, SpeexBits *bits, float *out) | 121 | EXPORT int speex_decode(void *state, SpeexBits *bits, float *out) |
122 | { | 122 | { |
123 | int i, ret; | 123 | int i, ret; |
124 | spx_int32_t N; | 124 | spx_int32_t N; |
@@ -131,7 +131,7 @@ int speex_decode(void *state, SpeexBits *bits, float *out) | |||
131 | } | 131 | } |
132 | #endif /* #ifndef DISABLE_FLOAT_API */ | 132 | #endif /* #ifndef DISABLE_FLOAT_API */ |
133 | 133 | ||
134 | int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out) | 134 | EXPORT int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out) |
135 | { | 135 | { |
136 | SpeexMode *mode = *(SpeexMode**)state; | 136 | SpeexMode *mode = *(SpeexMode**)state; |
137 | return (mode)->dec(state, bits, out); | 137 | return (mode)->dec(state, bits, out); |
@@ -139,12 +139,12 @@ int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out) | |||
139 | 139 | ||
140 | #else | 140 | #else |
141 | 141 | ||
142 | int speex_encode(void *state, float *in, SpeexBits *bits) | 142 | EXPORT int speex_encode(void *state, float *in, SpeexBits *bits) |
143 | { | 143 | { |
144 | return (*((SpeexMode**)state))->enc(state, in, bits); | 144 | return (*((SpeexMode**)state))->enc(state, in, bits); |
145 | } | 145 | } |
146 | 146 | ||
147 | int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) | 147 | EXPORT int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) |
148 | { | 148 | { |
149 | int i; | 149 | int i; |
150 | spx_int32_t N; | 150 | spx_int32_t N; |
@@ -155,12 +155,12 @@ int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) | |||
155 | return (*((SpeexMode**)state))->enc(state, float_in, bits); | 155 | return (*((SpeexMode**)state))->enc(state, float_in, bits); |
156 | } | 156 | } |
157 | 157 | ||
158 | int speex_decode(void *state, SpeexBits *bits, float *out) | 158 | EXPORT int speex_decode(void *state, SpeexBits *bits, float *out) |
159 | { | 159 | { |
160 | return (*((SpeexMode**)state))->dec(state, bits, out); | 160 | return (*((SpeexMode**)state))->dec(state, bits, out); |
161 | } | 161 | } |
162 | 162 | ||
163 | int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out) | 163 | EXPORT int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out) |
164 | { | 164 | { |
165 | int i; | 165 | int i; |
166 | spx_int32_t N; | 166 | spx_int32_t N; |
@@ -182,13 +182,13 @@ int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out) | |||
182 | #endif | 182 | #endif |
183 | 183 | ||
184 | #ifndef SPEEX_DISABLE_ENCODER | 184 | #ifndef SPEEX_DISABLE_ENCODER |
185 | int speex_encoder_ctl(void *state, int request, void *ptr) | 185 | EXPORT int speex_encoder_ctl(void *state, int request, void *ptr) |
186 | { | 186 | { |
187 | return (*((SpeexMode**)state))->enc_ctl(state, request, ptr); | 187 | return (*((SpeexMode**)state))->enc_ctl(state, request, ptr); |
188 | } | 188 | } |
189 | #endif | 189 | #endif |
190 | 190 | ||
191 | int speex_decoder_ctl(void *state, int request, void *ptr) | 191 | EXPORT int speex_decoder_ctl(void *state, int request, void *ptr) |
192 | { | 192 | { |
193 | return (*((SpeexMode**)state))->dec_ctl(state, request, ptr); | 193 | return (*((SpeexMode**)state))->dec_ctl(state, request, ptr); |
194 | } | 194 | } |
@@ -196,7 +196,7 @@ int speex_decoder_ctl(void *state, int request, void *ptr) | |||
196 | int nb_mode_query(const void *mode, int request, void *ptr) | 196 | int nb_mode_query(const void *mode, int request, void *ptr) |
197 | { | 197 | { |
198 | const SpeexNBMode *m = (const SpeexNBMode*)mode; | 198 | const SpeexNBMode *m = (const SpeexNBMode*)mode; |
199 | 199 | ||
200 | switch (request) | 200 | switch (request) |
201 | { | 201 | { |
202 | case SPEEX_MODE_FRAME_SIZE: | 202 | case SPEEX_MODE_FRAME_SIZE: |
@@ -219,7 +219,7 @@ int nb_mode_query(const void *mode, int request, void *ptr) | |||
219 | 219 | ||
220 | 220 | ||
221 | 221 | ||
222 | int speex_lib_ctl(int request, void *ptr) | 222 | EXPORT int speex_lib_ctl(int request, void *ptr) |
223 | { | 223 | { |
224 | switch (request) | 224 | switch (request) |
225 | { | 225 | { |
diff --git a/lib/rbcodec/codecs/libspeex/speex_callbacks.c b/lib/rbcodec/codecs/libspeex/speex_callbacks.c index f1de038488..ca236ed399 100644 --- a/lib/rbcodec/codecs/libspeex/speex_callbacks.c +++ b/lib/rbcodec/codecs/libspeex/speex_callbacks.c | |||
@@ -6,18 +6,18 @@ | |||
6 | Redistribution and use in source and binary forms, with or without | 6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions | 7 | modification, are permitted provided that the following conditions |
8 | are met: | 8 | are met: |
9 | 9 | ||
10 | - Redistributions of source code must retain the above copyright | 10 | - Redistributions of source code must retain the above copyright |
11 | notice, this list of conditions and the following disclaimer. | 11 | notice, this list of conditions and the following disclaimer. |
12 | 12 | ||
13 | - Redistributions in binary form must reproduce the above copyright | 13 | - Redistributions in binary form must reproduce the above copyright |
14 | notice, this list of conditions and the following disclaimer in the | 14 | notice, this list of conditions and the following disclaimer in the |
15 | documentation and/or other materials provided with the distribution. | 15 | documentation and/or other materials provided with the distribution. |
16 | 16 | ||
17 | - Neither the name of the Xiph.org Foundation nor the names of its | 17 | - Neither the name of the Xiph.org Foundation nor the names of its |
18 | contributors may be used to endorse or promote products derived from | 18 | contributors may be used to endorse or promote products derived from |
19 | this software without specific prior written permission. | 19 | this software without specific prior written permission. |
20 | 20 | ||
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
22 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 22 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
@@ -40,7 +40,7 @@ | |||
40 | #include "arch.h" | 40 | #include "arch.h" |
41 | #include "os_support.h" | 41 | #include "os_support.h" |
42 | 42 | ||
43 | int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *state) | 43 | EXPORT int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *state) |
44 | { | 44 | { |
45 | int id; | 45 | int id; |
46 | SpeexCallback *callback; | 46 | SpeexCallback *callback; |
@@ -65,7 +65,7 @@ int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *st | |||
65 | adv = 16; | 65 | adv = 16; |
66 | else if (id<14) | 66 | else if (id<14) |
67 | adv = 32; | 67 | adv = 32; |
68 | else | 68 | else |
69 | adv = 64; | 69 | adv = 64; |
70 | speex_bits_advance(bits, adv); | 70 | speex_bits_advance(bits, adv); |
71 | } | 71 | } |
@@ -74,7 +74,7 @@ int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *st | |||
74 | 74 | ||
75 | #if 0 | 75 | #if 0 |
76 | /* Rockbox: unused */ | 76 | /* Rockbox: unused */ |
77 | int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data) | 77 | EXPORT int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data) |
78 | { | 78 | { |
79 | (void)state; | 79 | (void)state; |
80 | spx_int32_t m; | 80 | spx_int32_t m; |
@@ -83,7 +83,7 @@ int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data) | |||
83 | return 0; | 83 | return 0; |
84 | } | 84 | } |
85 | 85 | ||
86 | int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data) | 86 | EXPORT int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data) |
87 | { | 87 | { |
88 | (void)state; | 88 | (void)state; |
89 | spx_int32_t m; | 89 | spx_int32_t m; |
@@ -92,7 +92,7 @@ int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data) | |||
92 | return 0; | 92 | return 0; |
93 | } | 93 | } |
94 | 94 | ||
95 | int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data) | 95 | EXPORT int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data) |
96 | { | 96 | { |
97 | (void)state; | 97 | (void)state; |
98 | spx_int32_t m; | 98 | spx_int32_t m; |
@@ -103,7 +103,7 @@ int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data | |||
103 | #endif | 103 | #endif |
104 | 104 | ||
105 | #ifndef DISABLE_VBR | 105 | #ifndef DISABLE_VBR |
106 | int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data) | 106 | EXPORT int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data) |
107 | { | 107 | { |
108 | (void)state; | 108 | (void)state; |
109 | spx_int32_t vbr; | 109 | spx_int32_t vbr; |
@@ -115,7 +115,7 @@ int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data) | |||
115 | 115 | ||
116 | #if 0 | 116 | #if 0 |
117 | /* Rockbox: unused */ | 117 | /* Rockbox: unused */ |
118 | int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data) | 118 | EXPORT int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data) |
119 | { | 119 | { |
120 | (void)state; | 120 | (void)state; |
121 | spx_int32_t enh; | 121 | spx_int32_t enh; |
@@ -126,7 +126,7 @@ int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data) | |||
126 | #endif | 126 | #endif |
127 | 127 | ||
128 | #ifndef DISABLE_VBR | 128 | #ifndef DISABLE_VBR |
129 | int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data) | 129 | EXPORT int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data) |
130 | { | 130 | { |
131 | (void)state; | 131 | (void)state; |
132 | float qual; | 132 | float qual; |
@@ -138,7 +138,7 @@ int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *da | |||
138 | 138 | ||
139 | #if 0 | 139 | #if 0 |
140 | /* Rockbox: unused */ | 140 | /* Rockbox: unused */ |
141 | int speex_std_char_handler(SpeexBits *bits, void *state, void *data) | 141 | EXPORT int speex_std_char_handler(SpeexBits *bits, void *state, void *data) |
142 | { | 142 | { |
143 | (void)state; | 143 | (void)state; |
144 | unsigned char ch; | 144 | unsigned char ch; |
@@ -150,7 +150,7 @@ int speex_std_char_handler(SpeexBits *bits, void *state, void *data) | |||
150 | #endif | 150 | #endif |
151 | 151 | ||
152 | /* Default handler for user callbacks: skip it */ | 152 | /* Default handler for user callbacks: skip it */ |
153 | int speex_default_user_handler(SpeexBits *bits, void *state, void *data) | 153 | EXPORT int speex_default_user_handler(SpeexBits *bits, void *state, void *data) |
154 | { | 154 | { |
155 | (void)state; | 155 | (void)state; |
156 | (void)data; | 156 | (void)data; |
diff --git a/lib/rbcodec/codecs/libspeex/speex_header.c b/lib/rbcodec/codecs/libspeex/speex_header.c index b0e98b7c9c..f83e0f2152 100644 --- a/lib/rbcodec/codecs/libspeex/speex_header.c +++ b/lib/rbcodec/codecs/libspeex/speex_header.c | |||
@@ -1,22 +1,22 @@ | |||
1 | /* Copyright (C) 2002 Jean-Marc Valin | 1 | /* Copyright (C) 2002 Jean-Marc Valin |
2 | File: speex_header.c | 2 | File: speex_header.c |
3 | Describes the Speex header | 3 | Describes the Speex header |
4 | 4 | ||
5 | Redistribution and use in source and binary forms, with or without | 5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the following conditions | 6 | modification, are permitted provided that the following conditions |
7 | are met: | 7 | are met: |
8 | 8 | ||
9 | - Redistributions of source code must retain the above copyright | 9 | - Redistributions of source code must retain the above copyright |
10 | notice, this list of conditions and the following disclaimer. | 10 | notice, this list of conditions and the following disclaimer. |
11 | 11 | ||
12 | - Redistributions in binary form must reproduce the above copyright | 12 | - Redistributions in binary form must reproduce the above copyright |
13 | notice, this list of conditions and the following disclaimer in the | 13 | notice, this list of conditions and the following disclaimer in the |
14 | documentation and/or other materials provided with the distribution. | 14 | documentation and/or other materials provided with the distribution. |
15 | 15 | ||
16 | - Neither the name of the Xiph.org Foundation nor the names of its | 16 | - Neither the name of the Xiph.org Foundation nor the names of its |
17 | contributors may be used to endorse or promote products derived from | 17 | contributors may be used to endorse or promote products derived from |
18 | this software without specific prior written permission. | 18 | this software without specific prior written permission. |
19 | 19 | ||
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
21 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 21 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
@@ -47,7 +47,7 @@ | |||
47 | /** Convert little endian */ | 47 | /** Convert little endian */ |
48 | static inline spx_int32_t le_int(spx_int32_t i) | 48 | static inline spx_int32_t le_int(spx_int32_t i) |
49 | { | 49 | { |
50 | #ifdef ROCKBOX | 50 | #ifdef ROCKBOX |
51 | return letoh32(i); | 51 | return letoh32(i); |
52 | #elif !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) ) | 52 | #elif !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) ) |
53 | spx_uint32_t ui, ret; | 53 | spx_uint32_t ui, ret; |
@@ -86,7 +86,7 @@ typedef struct SpeexHeader { | |||
86 | */ | 86 | */ |
87 | 87 | ||
88 | #ifndef SPEEX_DISABLE_ENCODER | 88 | #ifndef SPEEX_DISABLE_ENCODER |
89 | void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const SpeexMode *m) | 89 | EXPORT void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const SpeexMode *m) |
90 | { | 90 | { |
91 | int i; | 91 | int i; |
92 | const char *h="Speex "; | 92 | const char *h="Speex "; |
@@ -101,10 +101,10 @@ void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const Spe | |||
101 | header->speex_version[i]=SPEEX_VERSION[i]; | 101 | header->speex_version[i]=SPEEX_VERSION[i]; |
102 | for (;i<SPEEX_HEADER_VERSION_LENGTH;i++) | 102 | for (;i<SPEEX_HEADER_VERSION_LENGTH;i++) |
103 | header->speex_version[i]=0; | 103 | header->speex_version[i]=0; |
104 | 104 | ||
105 | header->speex_version_id = 1; | 105 | header->speex_version_id = 1; |
106 | header->header_size = sizeof(SpeexHeader); | 106 | header->header_size = sizeof(SpeexHeader); |
107 | 107 | ||
108 | header->rate = rate; | 108 | header->rate = rate; |
109 | header->mode = m->modeID; | 109 | header->mode = m->modeID; |
110 | header->mode_bitstream_version = m->bitstream_version; | 110 | header->mode_bitstream_version = m->bitstream_version; |
@@ -114,20 +114,20 @@ void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const Spe | |||
114 | header->bitrate = -1; | 114 | header->bitrate = -1; |
115 | speex_mode_query(m, SPEEX_MODE_FRAME_SIZE, &header->frame_size); | 115 | speex_mode_query(m, SPEEX_MODE_FRAME_SIZE, &header->frame_size); |
116 | header->vbr = 0; | 116 | header->vbr = 0; |
117 | 117 | ||
118 | header->frames_per_packet = 0; | 118 | header->frames_per_packet = 0; |
119 | header->extra_headers = 0; | 119 | header->extra_headers = 0; |
120 | header->reserved1 = 0; | 120 | header->reserved1 = 0; |
121 | header->reserved2 = 0; | 121 | header->reserved2 = 0; |
122 | } | 122 | } |
123 | 123 | ||
124 | char *speex_header_to_packet(SpeexHeader *header, int *size) | 124 | EXPORT char *speex_header_to_packet(SpeexHeader *header, int *size) |
125 | { | 125 | { |
126 | SpeexHeader *le_header; | 126 | SpeexHeader *le_header; |
127 | le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader)); | 127 | le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader)); |
128 | 128 | ||
129 | SPEEX_COPY(le_header, header, 1); | 129 | SPEEX_COPY(le_header, header, 1); |
130 | 130 | ||
131 | /*Make sure everything is now little-endian*/ | 131 | /*Make sure everything is now little-endian*/ |
132 | ENDIAN_SWITCH(le_header->speex_version_id); | 132 | ENDIAN_SWITCH(le_header->speex_version_id); |
133 | ENDIAN_SWITCH(le_header->header_size); | 133 | ENDIAN_SWITCH(le_header->header_size); |
@@ -147,7 +147,7 @@ char *speex_header_to_packet(SpeexHeader *header, int *size) | |||
147 | #endif /* SPEEX_DISABLE_ENCODER */ | 147 | #endif /* SPEEX_DISABLE_ENCODER */ |
148 | 148 | ||
149 | static SpeexHeader global_le_header; /* Avoid malloc */ | 149 | static SpeexHeader global_le_header; /* Avoid malloc */ |
150 | SpeexHeader *speex_packet_to_header(char *packet, int size) | 150 | EXPORT SpeexHeader *speex_packet_to_header(char *packet, int size) |
151 | { | 151 | { |
152 | int i; | 152 | int i; |
153 | SpeexHeader *le_header = &global_le_header; | 153 | SpeexHeader *le_header = &global_le_header; |
@@ -158,18 +158,18 @@ SpeexHeader *speex_packet_to_header(char *packet, int size) | |||
158 | speex_notify("This doesn't look like a Speex file"); | 158 | speex_notify("This doesn't look like a Speex file"); |
159 | return NULL; | 159 | return NULL; |
160 | } | 160 | } |
161 | 161 | ||
162 | /*FIXME: Do we allow larger headers?*/ | 162 | /*FIXME: Do we allow larger headers?*/ |
163 | if (size < (int)sizeof(SpeexHeader)) | 163 | if (size < (int)sizeof(SpeexHeader)) |
164 | { | 164 | { |
165 | speex_notify("Speex header too small"); | 165 | speex_notify("Speex header too small"); |
166 | return NULL; | 166 | return NULL; |
167 | } | 167 | } |
168 | 168 | ||
169 | /* le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader)); */ | 169 | /* le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader)); */ |
170 | 170 | ||
171 | SPEEX_COPY(le_header, (SpeexHeader*)packet, 1); | 171 | SPEEX_COPY(le_header, (SpeexHeader*)packet, 1); |
172 | 172 | ||
173 | /*Make sure everything is converted correctly from little-endian*/ | 173 | /*Make sure everything is converted correctly from little-endian*/ |
174 | ENDIAN_SWITCH(le_header->speex_version_id); | 174 | ENDIAN_SWITCH(le_header->speex_version_id); |
175 | ENDIAN_SWITCH(le_header->header_size); | 175 | ENDIAN_SWITCH(le_header->header_size); |
@@ -183,6 +183,25 @@ SpeexHeader *speex_packet_to_header(char *packet, int size) | |||
183 | ENDIAN_SWITCH(le_header->frames_per_packet); | 183 | ENDIAN_SWITCH(le_header->frames_per_packet); |
184 | ENDIAN_SWITCH(le_header->extra_headers); | 184 | ENDIAN_SWITCH(le_header->extra_headers); |
185 | 185 | ||
186 | if (le_header->mode >= SPEEX_NB_MODES || le_header->mode < 0) | ||
187 | { | ||
188 | speex_notify("Invalid mode specified in Speex header"); | ||
189 | speex_free (le_header); | ||
190 | return NULL; | ||
191 | } | ||
192 | |||
193 | if (le_header->nb_channels>2) | ||
194 | le_header->nb_channels = 2; | ||
195 | if (le_header->nb_channels<1) | ||
196 | le_header->nb_channels = 1; | ||
197 | |||
186 | return le_header; | 198 | return le_header; |
187 | 199 | ||
188 | } | 200 | } |
201 | |||
202 | #if 0 /* Unused by rockbox */ | ||
203 | EXPORT void speex_header_free(void *ptr) | ||
204 | { | ||
205 | speex_free(ptr); | ||
206 | } | ||
207 | #endif | ||
diff --git a/lib/rbcodec/codecs/libspeex/stereo.c b/lib/rbcodec/codecs/libspeex/stereo.c index 0aca1050fa..e995cde093 100644 --- a/lib/rbcodec/codecs/libspeex/stereo.c +++ b/lib/rbcodec/codecs/libspeex/stereo.c | |||
@@ -1,21 +1,21 @@ | |||
1 | /* Copyright (C) 2002 Jean-Marc Valin | 1 | /* Copyright (C) 2002 Jean-Marc Valin |
2 | File: stereo.c | 2 | File: stereo.c |
3 | 3 | ||
4 | Redistribution and use in source and binary forms, with or without | 4 | Redistribution and use in source and binary forms, with or without |
5 | modification, are permitted provided that the following conditions | 5 | modification, are permitted provided that the following conditions |
6 | are met: | 6 | are met: |
7 | 7 | ||
8 | - Redistributions of source code must retain the above copyright | 8 | - Redistributions of source code must retain the above copyright |
9 | notice, this list of conditions and the following disclaimer. | 9 | notice, this list of conditions and the following disclaimer. |
10 | 10 | ||
11 | - Redistributions in binary form must reproduce the above copyright | 11 | - Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the | 12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. | 13 | documentation and/or other materials provided with the distribution. |
14 | 14 | ||
15 | - Neither the name of the Xiph.org Foundation nor the names of its | 15 | - Neither the name of the Xiph.org Foundation nor the names of its |
16 | contributors may be used to endorse or promote products derived from | 16 | contributors may be used to endorse or promote products derived from |
17 | this software without specific prior written permission. | 17 | this software without specific prior written permission. |
18 | 18 | ||
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
20 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 20 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
@@ -71,11 +71,11 @@ static const spx_word16_t balance_bounds[31] = {18, 23, 30, 38, 49, 63, 81, 104 | |||
71 | #ifdef FIXED_POINT | 71 | #ifdef FIXED_POINT |
72 | #define COMPATIBILITY_HACK(s) do {if ((s)->reserved1 != 0xdeadbeef) speex_stereo_state_reset((SpeexStereoState*)s); } while (0); | 72 | #define COMPATIBILITY_HACK(s) do {if ((s)->reserved1 != 0xdeadbeef) speex_stereo_state_reset((SpeexStereoState*)s); } while (0); |
73 | #else | 73 | #else |
74 | #define COMPATIBILITY_HACK(s) | 74 | #define COMPATIBILITY_HACK(s) |
75 | #endif | 75 | #endif |
76 | 76 | ||
77 | static SpeexStereoState global_stereo_state; | 77 | static SpeexStereoState global_stereo_state; |
78 | SpeexStereoState *speex_stereo_state_init() | 78 | EXPORT SpeexStereoState *speex_stereo_state_init() |
79 | { | 79 | { |
80 | /* SpeexStereoState *stereo = speex_alloc(sizeof(SpeexStereoState)); */ | 80 | /* SpeexStereoState *stereo = speex_alloc(sizeof(SpeexStereoState)); */ |
81 | SpeexStereoState *stereo = &global_stereo_state; | 81 | SpeexStereoState *stereo = &global_stereo_state; |
@@ -83,7 +83,7 @@ SpeexStereoState *speex_stereo_state_init() | |||
83 | return stereo; | 83 | return stereo; |
84 | } | 84 | } |
85 | 85 | ||
86 | void speex_stereo_state_reset(SpeexStereoState *_stereo) | 86 | EXPORT void speex_stereo_state_reset(SpeexStereoState *_stereo) |
87 | { | 87 | { |
88 | RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; | 88 | RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; |
89 | #ifdef FIXED_POINT | 89 | #ifdef FIXED_POINT |
@@ -100,10 +100,10 @@ void speex_stereo_state_reset(SpeexStereoState *_stereo) | |||
100 | stereo->smooth_right = 1.f; | 100 | stereo->smooth_right = 1.f; |
101 | stereo->reserved1 = 0; | 101 | stereo->reserved1 = 0; |
102 | stereo->reserved2 = 0; | 102 | stereo->reserved2 = 0; |
103 | #endif | 103 | #endif |
104 | } | 104 | } |
105 | 105 | ||
106 | void speex_stereo_state_destroy(SpeexStereoState *stereo) | 106 | EXPORT void speex_stereo_state_destroy(SpeexStereoState *stereo) |
107 | { | 107 | { |
108 | (void)stereo; | 108 | (void)stereo; |
109 | /* speex_free(stereo); */ | 109 | /* speex_free(stereo); */ |
@@ -111,7 +111,7 @@ void speex_stereo_state_destroy(SpeexStereoState *stereo) | |||
111 | 111 | ||
112 | #ifndef SPEEX_DISABLE_ENCODER | 112 | #ifndef SPEEX_DISABLE_ENCODER |
113 | #ifndef DISABLE_FLOAT_API | 113 | #ifndef DISABLE_FLOAT_API |
114 | void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits) | 114 | EXPORT void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits) |
115 | { | 115 | { |
116 | int i, tmp; | 116 | int i, tmp; |
117 | float e_left=0, e_right=0, e_tot=0; | 117 | float e_left=0, e_right=0, e_tot=0; |
@@ -129,7 +129,7 @@ void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits) | |||
129 | /*Quantization*/ | 129 | /*Quantization*/ |
130 | speex_bits_pack(bits, 14, 5); | 130 | speex_bits_pack(bits, 14, 5); |
131 | speex_bits_pack(bits, SPEEX_INBAND_STEREO, 4); | 131 | speex_bits_pack(bits, SPEEX_INBAND_STEREO, 4); |
132 | 132 | ||
133 | balance=4*log(balance); | 133 | balance=4*log(balance); |
134 | 134 | ||
135 | /*Pack sign*/ | 135 | /*Pack sign*/ |
@@ -140,16 +140,16 @@ void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits) | |||
140 | balance=floor(.5+fabs(balance)); | 140 | balance=floor(.5+fabs(balance)); |
141 | if (balance>30) | 141 | if (balance>30) |
142 | balance=31; | 142 | balance=31; |
143 | 143 | ||
144 | speex_bits_pack(bits, (int)balance, 5); | 144 | speex_bits_pack(bits, (int)balance, 5); |
145 | 145 | ||
146 | /* FIXME: this is a hack */ | 146 | /* FIXME: this is a hack */ |
147 | tmp=scal_quant(e_ratio*Q15_ONE, e_ratio_quant_bounds, 4); | 147 | tmp=scal_quant(e_ratio*Q15_ONE, e_ratio_quant_bounds, 4); |
148 | speex_bits_pack(bits, tmp, 2); | 148 | speex_bits_pack(bits, tmp, 2); |
149 | } | 149 | } |
150 | #endif /* #ifndef DISABLE_FLOAT_API */ | 150 | #endif /* #ifndef DISABLE_FLOAT_API */ |
151 | 151 | ||
152 | void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits) | 152 | EXPORT void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits) |
153 | { | 153 | { |
154 | int i, tmp; | 154 | int i, tmp; |
155 | spx_word32_t e_left=0, e_right=0, e_tot=0; | 155 | spx_word32_t e_left=0, e_right=0, e_tot=0; |
@@ -159,7 +159,7 @@ void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits) | |||
159 | #ifdef FIXED_POINT | 159 | #ifdef FIXED_POINT |
160 | int shift; | 160 | int shift; |
161 | #endif | 161 | #endif |
162 | 162 | ||
163 | /* In band marker */ | 163 | /* In band marker */ |
164 | speex_bits_pack(bits, 14, 5); | 164 | speex_bits_pack(bits, 14, 5); |
165 | /* Stereo marker */ | 165 | /* Stereo marker */ |
@@ -204,9 +204,9 @@ void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits) | |||
204 | if (balance_id>30) | 204 | if (balance_id>30) |
205 | balance_id=31; | 205 | balance_id=31; |
206 | #endif | 206 | #endif |
207 | 207 | ||
208 | speex_bits_pack(bits, balance_id, 5); | 208 | speex_bits_pack(bits, balance_id, 5); |
209 | 209 | ||
210 | /* "coherence" quantisation */ | 210 | /* "coherence" quantisation */ |
211 | #ifdef FIXED_POINT | 211 | #ifdef FIXED_POINT |
212 | shift = spx_ilog2(e_tot); | 212 | shift = spx_ilog2(e_tot); |
@@ -217,7 +217,7 @@ void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits) | |||
217 | #else | 217 | #else |
218 | e_ratio = e_tot/(1.+e_left+e_right); | 218 | e_ratio = e_tot/(1.+e_left+e_right); |
219 | #endif | 219 | #endif |
220 | 220 | ||
221 | tmp=scal_quant(EXTRACT16(e_ratio), e_ratio_quant_bounds, 4); | 221 | tmp=scal_quant(EXTRACT16(e_ratio), e_ratio_quant_bounds, 4); |
222 | /*fprintf (stderr, "%d %d %d %d\n", largest, smallest, balance_id, e_ratio);*/ | 222 | /*fprintf (stderr, "%d %d %d %d\n", largest, smallest, balance_id, e_ratio);*/ |
223 | speex_bits_pack(bits, tmp, 2); | 223 | speex_bits_pack(bits, tmp, 2); |
@@ -225,18 +225,18 @@ void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits) | |||
225 | #endif /* SPEEX_DISABLE_ENCODER */ | 225 | #endif /* SPEEX_DISABLE_ENCODER */ |
226 | 226 | ||
227 | #ifndef DISABLE_FLOAT_API | 227 | #ifndef DISABLE_FLOAT_API |
228 | void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *_stereo) | 228 | EXPORT void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *_stereo) |
229 | { | 229 | { |
230 | int i; | 230 | int i; |
231 | spx_word32_t balance; | 231 | spx_word32_t balance; |
232 | spx_word16_t e_left, e_right, e_ratio; | 232 | spx_word16_t e_left, e_right, e_ratio; |
233 | RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; | 233 | RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; |
234 | 234 | ||
235 | COMPATIBILITY_HACK(stereo); | 235 | COMPATIBILITY_HACK(stereo); |
236 | 236 | ||
237 | balance=stereo->balance; | 237 | balance=stereo->balance; |
238 | e_ratio=stereo->e_ratio; | 238 | e_ratio=stereo->e_ratio; |
239 | 239 | ||
240 | /* These two are Q14, with max value just below 2. */ | 240 | /* These two are Q14, with max value just below 2. */ |
241 | e_right = DIV32(QCONST32(1., 22), spx_sqrt(MULT16_32_Q15(e_ratio, ADD32(QCONST32(1., 16), balance)))); | 241 | e_right = DIV32(QCONST32(1., 22), spx_sqrt(MULT16_32_Q15(e_ratio, ADD32(QCONST32(1., 16), balance)))); |
242 | e_left = SHR32(MULT16_16(spx_sqrt(balance), e_right), 8); | 242 | e_left = SHR32(MULT16_16(spx_sqrt(balance), e_right), 8); |
@@ -252,7 +252,7 @@ void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *_stereo) | |||
252 | } | 252 | } |
253 | #endif /* #ifndef DISABLE_FLOAT_API */ | 253 | #endif /* #ifndef DISABLE_FLOAT_API */ |
254 | 254 | ||
255 | void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState *_stereo) | 255 | EXPORT void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState *_stereo) |
256 | { | 256 | { |
257 | int i; | 257 | int i; |
258 | spx_word32_t balance; | 258 | spx_word32_t balance; |
@@ -260,10 +260,10 @@ void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState | |||
260 | RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; | 260 | RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; |
261 | 261 | ||
262 | /* COMPATIBILITY_HACK(stereo); */ | 262 | /* COMPATIBILITY_HACK(stereo); */ |
263 | 263 | ||
264 | balance=stereo->balance; | 264 | balance=stereo->balance; |
265 | e_ratio=stereo->e_ratio; | 265 | e_ratio=stereo->e_ratio; |
266 | 266 | ||
267 | /* These two are Q14, with max value just below 2. */ | 267 | /* These two are Q14, with max value just below 2. */ |
268 | e_right = DIV32(QCONST32(1., 22), spx_sqrt(MULT16_32_Q15(e_ratio, ADD32(QCONST32(1., 16), balance)))); | 268 | e_right = DIV32(QCONST32(1., 22), spx_sqrt(MULT16_32_Q15(e_ratio, ADD32(QCONST32(1., 16), balance)))); |
269 | e_left = SHR32(MULT16_16(spx_sqrt(balance), e_right), 8); | 269 | e_left = SHR32(MULT16_16(spx_sqrt(balance), e_right), 8); |
@@ -278,7 +278,7 @@ void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState | |||
278 | } | 278 | } |
279 | } | 279 | } |
280 | 280 | ||
281 | int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data) | 281 | EXPORT int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data) |
282 | { | 282 | { |
283 | (void)state; | 283 | (void)state; |
284 | RealSpeexStereoState *stereo; | 284 | RealSpeexStereoState *stereo; |
@@ -286,7 +286,7 @@ int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data) | |||
286 | int tmp; | 286 | int tmp; |
287 | 287 | ||
288 | stereo = (RealSpeexStereoState*)data; | 288 | stereo = (RealSpeexStereoState*)data; |
289 | 289 | ||
290 | /* COMPATIBILITY_HACK(stereo); */ | 290 | /* COMPATIBILITY_HACK(stereo); */ |
291 | 291 | ||
292 | if (speex_bits_unpack_unsigned(bits, 1)) | 292 | if (speex_bits_unpack_unsigned(bits, 1)) |