comparison spandsp-0.0.3/spandsp-0.0.3/src/gsm0610_rpe.c @ 5:f762bf195c4b

import spandsp-0.0.3
author Peter Meerwald <pmeerw@cosy.sbg.ac.at>
date Fri, 25 Jun 2010 16:00:21 +0200
parents
children
comparison
equal deleted inserted replaced
4:26cd8f1ef0b1 5:f762bf195c4b
1 /*
2 * SpanDSP - a series of DSP components for telephony
3 *
4 * gsm0610_rpe.c - GSM 06.10 full rate speech codec.
5 *
6 * Written by Steve Underwood <steveu@coppice.org>
7 *
8 * Copyright (C) 2006 Steve Underwood
9 *
10 * All rights reserved.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2, as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 * This code is based on the widely used GSM 06.10 code available from
26 * http://kbs.cs.tu-berlin.de/~jutta/toast.html
27 *
28 * $Id: gsm0610_rpe.c,v 1.13 2006/11/19 14:07:24 steveu Exp $
29 */
30
31 /*! \file */
32
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
36
37 #include <assert.h>
38 #include <inttypes.h>
39 #if defined(HAVE_TGMATH_H)
40 #include <tgmath.h>
41 #endif
42 #if defined(HAVE_MATH_H)
43 #include <math.h>
44 #endif
45 #include <stdlib.h>
46
47 #include "spandsp/telephony.h"
48 #include "spandsp/dc_restore.h"
49 #include "spandsp/gsm0610.h"
50
51 #include "gsm0610_local.h"
52
53 /* 4.2.13 .. 4.2.17 RPE ENCODING SECTION */
54
55 /* 4.2.13 */
56 static void weighting_filter(const int16_t *e, // signal [-5..0.39.44] IN
57 int16_t x[40])
58 {
59 #if defined(__GNUC__) && defined(__i386__)
60 /* Table 4.4 Coefficients of the weighting filter */
61 /* This must be padded to a multiple of 4 for MMX to work */
62 static const int16_t gsm_H[12] =
63 {
64 -134, -374, 0, 2054, 5741, 8192, 5741, 2054, 0, -374, -134, 0
65 };
66
67 __asm__ __volatile__(
68 " emms;\n"
69 " addl $-10,%%ecx;\n"
70 " movl $0x1000,%%eax;\n"
71 " movd %%eax,%%mm5;\n" /* for rounding */
72 " movq %[gsm_H],%%mm1;\n"
73 " movq %[gsm_H8],%%mm2;\n"
74 " movq %[gsm_H16],%%mm3;\n"
75 " xorl %%esi,%%esi;\n"
76 " .p2align 2;\n"
77 "1:;\n"
78 " movq (%%ecx,%%esi,2),%%mm0;\n"
79 " pmaddwd %%mm1,%%mm0;\n"
80
81 " movq 8(%%ecx,%%esi,2),%%mm4;\n"
82 " pmaddwd %%mm2,%%mm4;\n"
83 " paddd %%mm4,%%mm0;\n"
84
85 " movq 16(%%ecx,%%esi,2),%%mm4;\n"
86 " pmaddwd %%mm3,%%mm4;\n"
87 " paddd %%mm4,%%mm0;\n"
88
89 " movq %%mm0,%%mm4;\n"
90 " punpckhdq %%mm0,%%mm4;\n" /* mm4 has high int32 of mm0 dup'd */
91 " paddd %%mm4,%%mm0;\n"
92
93 " paddd %%mm5,%%mm0;\n" /* Add for roundoff */
94 " psrad $13,%%mm0;\n"
95 " packssdw %%mm0,%%mm0;\n"
96 " movd %%mm0,%%eax;\n" /* eax has result */
97 " movw %%ax,(%%edi,%%esi,2);\n"
98 " incl %%esi;\n"
99 " cmpl $39,%%esi;\n"
100 " jle 1b;\n"
101 " emms;\n"
102 :
103 : "c" (e), "D" (x), [gsm_H] "X" (*((int64_t *) gsm_H)), [gsm_H8] "X" (*((int64_t *) (gsm_H + 4))), [gsm_H16] "X" (*((int64_t *) (gsm_H + 8)))
104 : "eax", "edx", "esi"
105 );
106 #else
107 int32_t L_result;
108 int k;
109
110 /* The coefficients of the weighting filter are stored in a table
111 (see table 4.4). The following scaling is used:
112
113 H[0..10] = integer(real_H[0..10] * 8192);
114 */
115 /* Initialization of a temporary working array wt[0...49] */
116
117 /* for (k = 0; k <= 4; k++) wt[k] = 0;
118 * for (k = 5; k <= 44; k++) wt[k] = *e++;
119 * for (k = 45; k <= 49; k++) wt[k] = 0;
120 *
121 * (e[-5..-1] and e[40..44] are allocated by the caller,
122 * are initially zero and are not written anywhere.)
123 */
124 e -= 5;
125
126 /* Compute the signal x[0..39] */
127 for (k = 0; k < 40; k++)
128 {
129 L_result = 8192 >> 1;
130
131 /* for (i = 0; i <= 10; i++)
132 * {
133 * L_temp = gsm_l_mult(wt[k + i], gsm_H[i]);
134 * L_result = gsm_l_add(L_result, L_temp);
135 * }
136 */
137
138 #undef STEP
139 #define STEP(i,H) (e[k + i] * (int32_t) H)
140
141 /* Every one of these multiplications is done twice,
142 but I don't see an elegant way to optimize this.
143 Do you?
144 */
145 L_result += STEP( 0, -134);
146 L_result += STEP( 1, -374);
147 // += STEP( 2, 0 );
148 L_result += STEP( 3, 2054);
149 L_result += STEP( 4, 5741);
150 L_result += STEP( 5, 8192);
151 L_result += STEP( 6, 5741);
152 L_result += STEP( 7, 2054);
153 // += STEP( 8, 0 );
154 L_result += STEP( 9, -374);
155 L_result += STEP(10, -134);
156
157 /* 2 adds vs. >> 16 => 14, minus one shift to compensate for
158 those we lost when replacing L_MULT by '*'. */
159 L_result >>= 13;
160 x[k] = saturate(L_result);
161 }
162 /*endfor*/
163 #endif
164 }
165 /*- End of function --------------------------------------------------------*/
166
167 /* 4.2.14 */
168 static void rpe_grid_selection(int16_t x[40], int16_t xM[13], int16_t *Mc_out)
169 {
170 int i;
171 int32_t L_result;
172 int32_t L_temp;
173 int32_t EM; /* xxx should be L_EM? */
174 int16_t Mc;
175 int32_t L_common_0_3;
176
177 /* The signal x[0..39] is used to select the RPE grid which is
178 represented by Mc. */
179
180 EM = 0;
181 Mc = 0;
182
183 #undef STEP
184 #define STEP(m,i) \
185 L_temp = x[m + 3*i] >> 2; \
186 L_result += L_temp*L_temp;
187
188 /* Common part of 0 and 3 */
189 L_result = 0;
190 STEP(0, 1);
191 STEP(0, 2);
192 STEP(0, 3);
193 STEP(0, 4);
194 STEP(0, 5);
195 STEP(0, 6);
196 STEP(0, 7);
197 STEP(0, 8);
198 STEP(0, 9);
199 STEP(0, 10);
200 STEP(0, 11);
201 STEP(0, 12);
202 L_common_0_3 = L_result;
203
204 /* i = 0 */
205
206 STEP(0, 0);
207 L_result <<= 1; /* implicit in L_MULT */
208 EM = L_result;
209
210 /* i = 1 */
211
212 L_result = 0;
213 STEP(1, 0);
214 STEP(1, 1);
215 STEP(1, 2);
216 STEP(1, 3);
217 STEP(1, 4);
218 STEP(1, 5);
219 STEP(1, 6);
220 STEP(1, 7);
221 STEP(1, 8);
222 STEP(1, 9);
223 STEP(1, 10);
224 STEP(1, 11);
225 STEP(1, 12);
226 L_result <<= 1;
227 if (L_result > EM)
228 {
229 Mc = 1;
230 EM = L_result;
231 }
232 /*endif*/
233
234 /* i = 2 */
235
236 L_result = 0;
237 STEP(2, 0);
238 STEP(2, 1);
239 STEP(2, 2);
240 STEP(2, 3);
241 STEP(2, 4);
242 STEP(2, 5);
243 STEP(2, 6);
244 STEP(2, 7);
245 STEP(2, 8);
246 STEP(2, 9);
247 STEP(2, 10);
248 STEP(2, 11);
249 STEP(2, 12);
250 L_result <<= 1;
251 if (L_result > EM)
252 {
253 Mc = 2;
254 EM = L_result;
255 }
256 /*endif*/
257
258 /* i = 3 */
259
260 L_result = L_common_0_3;
261 STEP(3, 12);
262 L_result <<= 1;
263 if (L_result > EM)
264 {
265 Mc = 3;
266 EM = L_result;
267 }
268 /*endif*/
269
270 /* Down-sampling by a factor 3 to get the selected xM[0..12]
271 RPE sequence. */
272 for (i = 0; i < 13; i++)
273 xM[i] = x[Mc + 3*i];
274 /*endfor*/
275 *Mc_out = Mc;
276 }
277 /*- End of function --------------------------------------------------------*/
278
279 /* 4.12.15 */
280 static void apcm_quantization_xmaxc_to_exp_mant(int16_t xmaxc,
281 int16_t *exp_out,
282 int16_t *mant_out)
283 {
284 int16_t exp;
285 int16_t mant;
286
287 /* Compute exponent and mantissa of the decoded version of xmaxc */
288 exp = 0;
289 if (xmaxc > 15)
290 exp = (int16_t) ((xmaxc >> 3) - 1);
291 /*endif*/
292 mant = xmaxc - (exp << 3);
293
294 if (mant == 0)
295 {
296 exp = -4;
297 mant = 7;
298 }
299 else
300 {
301 while (mant <= 7)
302 {
303 mant = (int16_t) (mant << 1 | 1);
304 exp--;
305 }
306 /*endwhile*/
307 mant -= 8;
308 }
309 /*endif*/
310
311 assert(exp >= -4 && exp <= 6);
312 assert(mant >= 0 && mant <= 7);
313
314 *exp_out = exp;
315 *mant_out = mant;
316 }
317 /*- End of function --------------------------------------------------------*/
318
319 static void apcm_quantization(int16_t xM[13],
320 int16_t xMc[13],
321 int16_t *mant_out,
322 int16_t *exp_out,
323 int16_t *xmaxc_out)
324 {
325 /* Table 4.5 Normalized inverse mantissa used to compute xM/xmax */
326 static const int16_t gsm_NRFAC[8] =
327 {
328 29128, 26215, 23832, 21846, 20165, 18725, 17476, 16384
329 };
330 int i;
331 int itest;
332 int16_t xmax;
333 int16_t xmaxc;
334 int16_t temp;
335 int16_t temp1;
336 int16_t temp2;
337 int16_t exp;
338 int16_t mant;
339
340 /* Find the maximum absolute value xmax of xM[0..12]. */
341 xmax = 0;
342 for (i = 0; i < 13; i++)
343 {
344 temp = xM[i];
345 temp = gsm_abs(temp);
346 if (temp > xmax)
347 xmax = temp;
348 /*endif*/
349 }
350 /*endfor*/
351
352 /* Quantizing and coding of xmax to get xmaxc. */
353 exp = 0;
354 temp = xmax >> 9;
355 itest = 0;
356
357 for (i = 0; i <= 5; i++)
358 {
359 itest |= (temp <= 0);
360 temp >>= 1;
361
362 assert(exp <= 5);
363 if (itest == 0)
364 exp++;
365 /*endif*/
366 }
367 /*endfor*/
368
369 assert(exp <= 6 && exp >= 0);
370 temp = (int16_t) (exp + 5);
371
372 assert(temp <= 11 && temp >= 0);
373 xmaxc = gsm_add((xmax >> temp), exp << 3);
374
375 /* Quantizing and coding of the xM[0..12] RPE sequence
376 to get the xMc[0..12] */
377 apcm_quantization_xmaxc_to_exp_mant(xmaxc, &exp, &mant);
378
379 /* This computation uses the fact that the decoded version of xmaxc
380 can be calculated by using the exponent and the mantissa part of
381 xmaxc (logarithmic table).
382 So, this method avoids any division and uses only a scaling
383 of the RPE samples by a function of the exponent. A direct
384 multiplication by the inverse of the mantissa (NRFAC[0..7]
385 found in table 4.5) gives the 3 bit coded version xMc[0..12]
386 of the RPE samples.
387 */
388 /* Direct computation of xMc[0..12] using table 4.5 */
389 assert(exp <= 4096 && exp >= -4096);
390 assert(mant >= 0 && mant <= 7);
391
392 temp1 = (int16_t) (6 - exp); /* Normalization by the exponent */
393 temp2 = gsm_NRFAC[mant]; /* Inverse mantissa */
394
395 for (i = 0; i < 13; i++)
396 {
397 assert(temp1 >= 0 && temp1 < 16);
398
399 temp = xM[i] << temp1;
400 temp = gsm_mult(temp, temp2);
401 temp >>= 12;
402 xMc[i] = (int16_t) (temp + 4); /* See note below */
403 }
404 /*endfor*/
405
406 /* NOTE: This equation is used to make all the xMc[i] positive. */
407 *mant_out = mant;
408 *exp_out = exp;
409 *xmaxc_out = xmaxc;
410 }
411 /*- End of function --------------------------------------------------------*/
412
413 /* 4.2.16 */
414 static void apcm_inverse_quantization(int16_t xMc[13],
415 int16_t mant,
416 int16_t exp,
417 int16_t xMp[13])
418 {
419 /* Table 4.6 Normalized direct mantissa used to compute xM/xmax */
420 static const int16_t gsm_FAC[8] =
421 {
422 18431, 20479, 22527, 24575, 26623, 28671, 30719, 32767
423 };
424 int i;
425 int16_t temp;
426 int16_t temp1;
427 int16_t temp2;
428 int16_t temp3;
429
430 /* This part is for decoding the RPE sequence of coded xMc[0..12]
431 samples to obtain the xMp[0..12] array. Table 4.6 is used to get
432 the mantissa of xmaxc (FAC[0..7]).
433 */
434 assert(mant >= 0 && mant <= 7);
435
436 temp1 = gsm_FAC[mant]; /* See 4.2-15 for mant */
437 temp2 = gsm_sub(6, exp); /* See 4.2-15 for exp */
438 temp3 = gsm_asl(1, gsm_sub (temp2, 1));
439
440 for (i = 0; i < 13; i++)
441 {
442 assert(xMc[i] >= 0 && xMc[i] <= 7); /* 3 bit unsigned */
443
444 temp = (int16_t) ((xMc[i] << 1) - 7); /* Restore sign */
445 assert(temp <= 7 && temp >= -7); /* 4 bit signed */
446
447 temp <<= 12; /* 16 bit signed */
448 temp = gsm_mult_r(temp1, temp);
449 temp = gsm_add(temp, temp3);
450 xMp[i] = gsm_asr(temp, temp2);
451 }
452 /*endfor*/
453 }
454 /*- End of function --------------------------------------------------------*/
455
456 /* 4.2.17 */
457 static void rpe_grid_positioning(int16_t Mc,
458 int16_t xMp[13],
459 int16_t ep[40])
460 {
461 int i = 13;
462
463 /* This procedure computes the reconstructed long term residual signal
464 ep[0..39] for the LTP analysis filter. The inputs are the Mc
465 which is the grid position selection and the xMp[0..12] decoded
466 RPE samples which are upsampled by a factor of 3 by inserting zero
467 values.
468 */
469 assert(0 <= Mc && Mc <= 3);
470
471 switch (Mc)
472 {
473 case 3:
474 *ep++ = 0;
475 case 2:
476 do
477 {
478 *ep++ = 0;
479 case 1:
480 *ep++ = 0;
481 case 0:
482 *ep++ = *xMp++;
483 }
484 while (--i);
485 }
486 /*endswitch*/
487 while (++Mc < 4)
488 *ep++ = 0;
489 /*endwhile*/
490 }
491 /*- End of function --------------------------------------------------------*/
492
493 void gsm0610_rpe_encoding(gsm0610_state_t *s,
494 int16_t *e, // [-5..-1][0..39][40..44]
495 int16_t *xmaxc,
496 int16_t *Mc,
497 int16_t xMc[13])
498 {
499 int16_t x[40];
500 int16_t xM[13];
501 int16_t xMp[13];
502 int16_t mant;
503 int16_t exp;
504
505 weighting_filter(e, x);
506 rpe_grid_selection(x, xM, Mc);
507
508 apcm_quantization(xM, xMc, &mant, &exp, xmaxc);
509 apcm_inverse_quantization(xMc, mant, exp, xMp);
510
511 rpe_grid_positioning(*Mc, xMp, e);
512 }
513 /*- End of function --------------------------------------------------------*/
514
515 void gsm0610_rpe_decoding(gsm0610_state_t *s,
516 int16_t xmaxc,
517 int16_t Mcr,
518 int16_t xMcr[13],
519 int16_t erp[40])
520 {
521 int16_t exp;
522 int16_t mant;
523 int16_t xMp[13];
524
525 apcm_quantization_xmaxc_to_exp_mant(xmaxc, &exp, &mant);
526 apcm_inverse_quantization(xMcr, mant, exp, xMp);
527 rpe_grid_positioning(Mcr, xMp, erp);
528 }
529 /*- End of function --------------------------------------------------------*/
530 /*- End of file ------------------------------------------------------------*/

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.