/src/speex/libspeex/stereo.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2002 Jean-Marc Valin |
2 | | File: stereo.c |
3 | | |
4 | | Redistribution and use in source and binary forms, with or without |
5 | | modification, are permitted provided that the following conditions |
6 | | are met: |
7 | | |
8 | | - Redistributions of source code must retain the above copyright |
9 | | notice, this list of conditions and the following disclaimer. |
10 | | |
11 | | - Redistributions in binary form must reproduce the above copyright |
12 | | notice, this list of conditions and the following disclaimer in the |
13 | | documentation and/or other materials provided with the distribution. |
14 | | |
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 |
17 | | this software without specific prior written permission. |
18 | | |
19 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
20 | | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
21 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
22 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR |
23 | | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
24 | | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
25 | | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
26 | | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
27 | | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
28 | | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
29 | | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | | */ |
31 | | |
32 | | #ifdef HAVE_CONFIG_H |
33 | | #include "config.h" |
34 | | #endif |
35 | | |
36 | | #include "speex/speex_stereo.h" |
37 | | #include "speex/speex_callbacks.h" |
38 | | #include "math_approx.h" |
39 | | #include "vq.h" |
40 | | #include <math.h> |
41 | | #include "os_support.h" |
42 | | |
43 | | typedef struct RealSpeexStereoState { |
44 | | spx_word32_t balance; /**< Left/right balance info */ |
45 | | spx_word32_t e_ratio; /**< Ratio of energies: E(left+right)/[E(left)+E(right)] */ |
46 | | spx_word32_t smooth_left; /**< Smoothed left channel gain */ |
47 | | spx_word32_t smooth_right; /**< Smoothed right channel gain */ |
48 | | spx_uint32_t reserved1; /**< Reserved for future use */ |
49 | | spx_int32_t reserved2; /**< Reserved for future use */ |
50 | | } RealSpeexStereoState; |
51 | | |
52 | | |
53 | | /*float e_ratio_quant[4] = {1, 1.26, 1.587, 2};*/ |
54 | | #ifndef FIXED_POINT |
55 | | static const float e_ratio_quant[4] = {.25f, .315f, .397f, .5f}; |
56 | | static const float e_ratio_quant_bounds[3] = {0.2825f, 0.356f, 0.4485f}; |
57 | | #else |
58 | | static const spx_word16_t e_ratio_quant[4] = {8192, 10332, 13009, 16384}; |
59 | | static const spx_word16_t e_ratio_quant_bounds[3] = {9257, 11665, 14696}; |
60 | | static const spx_word16_t balance_bounds[31] = {18, 23, 30, 38, 49, 63, 81, 104, |
61 | | 134, 172, 221, 284, 364, 468, 600, 771, |
62 | | 990, 1271, 1632, 2096, 2691, 3455, 4436, 5696, |
63 | | 7314, 9392, 12059, 15484, 19882, 25529, 32766}; |
64 | | #endif |
65 | | |
66 | | /* This is an ugly compatibility hack that properly resets the stereo state |
67 | | In case it it compiled in fixed-point, but initialised with the deprecated |
68 | | floating point static initialiser */ |
69 | | #ifdef FIXED_POINT |
70 | | #define COMPATIBILITY_HACK(s) do {if ((s)->reserved1 != 0xdeadbeef) speex_stereo_state_reset((SpeexStereoState*)s); } while (0); |
71 | | #else |
72 | | #define COMPATIBILITY_HACK(s) |
73 | | #endif |
74 | | |
75 | | EXPORT SpeexStereoState *speex_stereo_state_init() |
76 | 0 | { |
77 | 0 | SpeexStereoState *stereo = speex_alloc(sizeof(SpeexStereoState)); |
78 | 0 | speex_stereo_state_reset(stereo); |
79 | 0 | return stereo; |
80 | 0 | } |
81 | | |
82 | | EXPORT void speex_stereo_state_reset(SpeexStereoState *_stereo) |
83 | 0 | { |
84 | 0 | RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; |
85 | | #ifdef FIXED_POINT |
86 | | stereo->balance = 65536; |
87 | | stereo->e_ratio = 16384; |
88 | | stereo->smooth_left = 16384; |
89 | | stereo->smooth_right = 16384; |
90 | | stereo->reserved1 = 0xdeadbeef; |
91 | | stereo->reserved2 = 0; |
92 | | #else |
93 | 0 | stereo->balance = 1.0f; |
94 | 0 | stereo->e_ratio = .5f; |
95 | 0 | stereo->smooth_left = 1.f; |
96 | 0 | stereo->smooth_right = 1.f; |
97 | 0 | stereo->reserved1 = 0; |
98 | 0 | stereo->reserved2 = 0; |
99 | 0 | #endif |
100 | 0 | } |
101 | | |
102 | | EXPORT void speex_stereo_state_destroy(SpeexStereoState *stereo) |
103 | 0 | { |
104 | 0 | speex_free(stereo); |
105 | 0 | } |
106 | | |
107 | | #ifndef DISABLE_ENCODER |
108 | | #ifndef DISABLE_FLOAT_API |
109 | | EXPORT void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits) |
110 | 0 | { |
111 | 0 | int i, tmp; |
112 | 0 | float e_left=0, e_right=0, e_tot=0; |
113 | 0 | float balance, e_ratio; |
114 | 0 | for (i=0;i<frame_size;i++) |
115 | 0 | { |
116 | 0 | e_left += ((float)data[2*i])*data[2*i]; |
117 | 0 | e_right += ((float)data[2*i+1])*data[2*i+1]; |
118 | 0 | data[i] = .5*(((float)data[2*i])+data[2*i+1]); |
119 | 0 | e_tot += ((float)data[i])*data[i]; |
120 | 0 | } |
121 | 0 | balance=(e_left+1)/(e_right+1); |
122 | 0 | e_ratio = e_tot/(1+e_left+e_right); |
123 | | |
124 | | /*Quantization*/ |
125 | 0 | speex_bits_pack(bits, 14, 5); |
126 | 0 | speex_bits_pack(bits, SPEEX_INBAND_STEREO, 4); |
127 | |
|
128 | 0 | balance=4*log(balance); |
129 | | |
130 | | /*Pack sign*/ |
131 | 0 | if (balance>0) |
132 | 0 | speex_bits_pack(bits, 0, 1); |
133 | 0 | else |
134 | 0 | speex_bits_pack(bits, 1, 1); |
135 | 0 | balance=floor(.5+fabs(balance)); |
136 | 0 | if (balance>30) |
137 | 0 | balance=31; |
138 | |
|
139 | 0 | speex_bits_pack(bits, (int)balance, 5); |
140 | | |
141 | | /* FIXME: this is a hack */ |
142 | 0 | tmp=scal_quant(e_ratio*Q15_ONE, e_ratio_quant_bounds, 4); |
143 | 0 | speex_bits_pack(bits, tmp, 2); |
144 | 0 | } |
145 | | #endif /* #ifndef DISABLE_FLOAT_API */ |
146 | | |
147 | | EXPORT void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits) |
148 | 1.47k | { |
149 | 1.47k | int i, tmp; |
150 | 1.47k | spx_word32_t e_left=0, e_right=0, e_tot=0; |
151 | 1.47k | spx_word32_t balance, e_ratio; |
152 | 1.47k | spx_word32_t largest, smallest; |
153 | 1.47k | int balance_id; |
154 | | #ifdef FIXED_POINT |
155 | | int shift; |
156 | | int sqr_shift; |
157 | | |
158 | | /* Avoid overflows when summing squares */ |
159 | | sqr_shift = frame_size >= 512 ? 9 : 8; |
160 | | #endif |
161 | | |
162 | | /* In band marker */ |
163 | 1.47k | speex_bits_pack(bits, 14, 5); |
164 | | /* Stereo marker */ |
165 | 1.47k | speex_bits_pack(bits, SPEEX_INBAND_STEREO, 4); |
166 | | |
167 | 421k | for (i=0;i<frame_size;i++) |
168 | 420k | { |
169 | 420k | e_left += SHR32(MULT16_16(data[2*i],data[2*i]),sqr_shift); |
170 | 420k | e_right += SHR32(MULT16_16(data[2*i+1],data[2*i+1]),sqr_shift); |
171 | | #ifdef FIXED_POINT |
172 | | /* I think this is actually unbiased */ |
173 | | data[i] = SHR16(data[2*i],1)+PSHR16(data[2*i+1],1); |
174 | | #else |
175 | 420k | data[i] = .5*(((float)data[2*i])+data[2*i+1]); |
176 | 420k | #endif |
177 | 420k | e_tot += SHR32(MULT16_16(data[i],data[i]),sqr_shift); |
178 | 420k | } |
179 | 1.47k | if (e_left > e_right) |
180 | 262 | { |
181 | 262 | speex_bits_pack(bits, 0, 1); |
182 | 262 | largest = e_left; |
183 | 262 | smallest = e_right; |
184 | 1.21k | } else { |
185 | 1.21k | speex_bits_pack(bits, 1, 1); |
186 | 1.21k | largest = e_right; |
187 | 1.21k | smallest = e_left; |
188 | 1.21k | } |
189 | | |
190 | | /* Balance quantization */ |
191 | | #ifdef FIXED_POINT |
192 | | shift = spx_ilog2(largest)-15; |
193 | | largest = VSHR32(largest, shift-4); |
194 | | smallest = VSHR32(smallest, shift); |
195 | | balance = DIV32(largest, ADD32(smallest, 1)); |
196 | | if (balance > 32767) |
197 | | balance = 32767; |
198 | | balance_id = scal_quant(EXTRACT16(balance), balance_bounds, 32); |
199 | | #else |
200 | 1.47k | balance=(largest+1.)/(smallest+1.); |
201 | 1.47k | balance=4*log(balance); |
202 | 1.47k | balance_id=floor(.5+fabs(balance)); |
203 | 1.47k | if (balance_id>30) |
204 | 84 | balance_id=31; |
205 | 1.47k | #endif |
206 | | |
207 | 1.47k | speex_bits_pack(bits, balance_id, 5); |
208 | | |
209 | | /* "coherence" quantisation */ |
210 | | #ifdef FIXED_POINT |
211 | | shift = spx_ilog2(e_tot); |
212 | | e_tot = VSHR32(e_tot, shift-25); |
213 | | e_left = VSHR32(e_left, shift-10); |
214 | | e_right = VSHR32(e_right, shift-10); |
215 | | e_ratio = DIV32(e_tot, e_left+e_right+1); |
216 | | #else |
217 | 1.47k | e_ratio = e_tot/(1.+e_left+e_right); |
218 | 1.47k | #endif |
219 | | |
220 | 1.47k | tmp=scal_quant(EXTRACT16(e_ratio), e_ratio_quant_bounds, 4); |
221 | | /*fprintf (stderr, "%d %d %d %d\n", largest, smallest, balance_id, e_ratio);*/ |
222 | 1.47k | speex_bits_pack(bits, tmp, 2); |
223 | 1.47k | } |
224 | | #else /* DISABLE_ENCODER */ |
225 | | EXPORT void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits) |
226 | | { |
227 | | } |
228 | | #endif /* DISABLE_ENCODER */ |
229 | | |
230 | | |
231 | | #ifndef DISABLE_FLOAT_API |
232 | | EXPORT void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *_stereo) |
233 | 0 | { |
234 | 0 | int i; |
235 | 0 | spx_word32_t balance; |
236 | 0 | spx_word16_t e_left, e_right, e_ratio; |
237 | 0 | RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; |
238 | |
|
239 | 0 | COMPATIBILITY_HACK(stereo); |
240 | |
|
241 | 0 | balance=stereo->balance; |
242 | 0 | e_ratio=stereo->e_ratio; |
243 | | |
244 | | /* These two are Q14, with max value just below 2. */ |
245 | 0 | e_right = DIV32(QCONST32(1., 22), spx_sqrt(MULT16_32_Q15(e_ratio, ADD32(QCONST32(1., 16), balance)))); |
246 | 0 | e_left = SHR32(MULT16_16(spx_sqrt(balance), e_right), 8); |
247 | |
|
248 | 0 | for (i=frame_size-1;i>=0;i--) |
249 | 0 | { |
250 | 0 | spx_word16_t tmp=data[i]; |
251 | 0 | stereo->smooth_left = EXTRACT16(PSHR32(MAC16_16(MULT16_16(stereo->smooth_left, QCONST16(0.98, 15)), e_left, QCONST16(0.02, 15)), 15)); |
252 | 0 | stereo->smooth_right = EXTRACT16(PSHR32(MAC16_16(MULT16_16(stereo->smooth_right, QCONST16(0.98, 15)), e_right, QCONST16(0.02, 15)), 15)); |
253 | 0 | data[2*i] = (float)MULT16_16_P14(stereo->smooth_left, tmp); |
254 | 0 | data[2*i+1] = (float)MULT16_16_P14(stereo->smooth_right, tmp); |
255 | 0 | } |
256 | 0 | } |
257 | | #endif /* #ifndef DISABLE_FLOAT_API */ |
258 | | |
259 | | EXPORT void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState *_stereo) |
260 | 0 | { |
261 | 0 | int i; |
262 | 0 | spx_word32_t balance; |
263 | 0 | spx_word16_t e_left, e_right, e_ratio; |
264 | 0 | RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; |
265 | |
|
266 | 0 | COMPATIBILITY_HACK(stereo); |
267 | |
|
268 | 0 | balance=stereo->balance; |
269 | 0 | e_ratio=stereo->e_ratio; |
270 | | |
271 | | /* These two are Q14, with max value just below 2. */ |
272 | 0 | e_right = DIV32(QCONST32(1., 22), spx_sqrt(MULT16_32_Q15(e_ratio, ADD32(QCONST32(1., 16), balance)))); |
273 | 0 | e_left = SHR32(MULT16_16(spx_sqrt(balance), e_right), 8); |
274 | |
|
275 | 0 | for (i=frame_size-1;i>=0;i--) |
276 | 0 | { |
277 | 0 | spx_int16_t tmp=data[i]; |
278 | 0 | stereo->smooth_left = EXTRACT16(PSHR32(MAC16_16(MULT16_16(stereo->smooth_left, QCONST16(0.98, 15)), e_left, QCONST16(0.02, 15)), 15)); |
279 | 0 | stereo->smooth_right = EXTRACT16(PSHR32(MAC16_16(MULT16_16(stereo->smooth_right, QCONST16(0.98, 15)), e_right, QCONST16(0.02, 15)), 15)); |
280 | 0 | data[2*i] = (spx_int16_t)MULT16_16_P14(stereo->smooth_left, tmp); |
281 | 0 | data[2*i+1] = (spx_int16_t)MULT16_16_P14(stereo->smooth_right, tmp); |
282 | 0 | } |
283 | 0 | } |
284 | | |
285 | | EXPORT int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data) |
286 | 0 | { |
287 | 0 | RealSpeexStereoState *stereo; |
288 | 0 | spx_word16_t sign=1, dexp; |
289 | 0 | int tmp; |
290 | |
|
291 | 0 | stereo = (RealSpeexStereoState*)data; |
292 | |
|
293 | 0 | COMPATIBILITY_HACK(stereo); |
294 | |
|
295 | 0 | if (speex_bits_unpack_unsigned(bits, 1)) |
296 | 0 | sign=-1; |
297 | 0 | dexp = speex_bits_unpack_unsigned(bits, 5); |
298 | 0 | #ifndef FIXED_POINT |
299 | 0 | stereo->balance = exp(sign*.25*dexp); |
300 | | #else |
301 | | stereo->balance = spx_exp(MULT16_16(sign, SHL16(dexp, 9))); |
302 | | #endif |
303 | 0 | tmp = speex_bits_unpack_unsigned(bits, 2); |
304 | 0 | stereo->e_ratio = e_ratio_quant[tmp]; |
305 | |
|
306 | 0 | return 0; |
307 | 0 | } |