comparison spandsp-0.0.6pre17/src/gsm0610_rpe.c @ 4:26cd8f1ef0b1

import spandsp-0.0.6pre17
author Peter Meerwald <pmeerw@cosy.sbg.ac.at>
date Fri, 25 Jun 2010 15:50:58 +0200
parents
children
comparison
equal deleted inserted replaced
3:c6c5a16ce2f2 4:26cd8f1ef0b1
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 Lesser General Public License version 2.1,
14 * as 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 Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License 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.25.4.2 2009/12/28 11:54:58 steveu Exp $
29 */
30
31 /*! \file */
32
33 #if defined(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 "floating_fudge.h"
46 #include <stdlib.h>
47
48 #include "mmx_sse_decs.h"
49
50 #include "spandsp/telephony.h"
51 #include "spandsp/fast_convert.h"
52 #include "spandsp/bitstream.h"
53 #include "spandsp/saturated.h"
54 #include "spandsp/gsm0610.h"
55
56 #include "gsm0610_local.h"
57
58 /* 4.2.13 .. 4.2.17 RPE ENCODING SECTION */
59
60 /* 4.2.13 */
61 static void weighting_filter(int16_t x[40],
62 const int16_t *e) // signal [-5..0.39.44] IN)
63 {
64 #if defined(__GNUC__) && defined(SPANDSP_USE_MMX) && defined(__x86_64__)
65 /* Table 4.4 Coefficients of the weighting filter */
66 /* This must be padded to a multiple of 4 for MMX to work */
67 static const union
68 {
69 int16_t gsm_H[12];
70 __m64 x[3];
71 } gsm_H =
72 {
73 {
74 -134, -374, 0, 2054, 5741, 8192, 5741, 2054, 0, -374, -134, 0
75 }
76
77 };
78
79 __asm__ __volatile__(
80 " emms;\n"
81 " addq $-10,%%rcx;\n"
82 " leaq %[gsm_H],%%rax;\n"
83 " movq (%%rax),%%mm1;\n"
84 " movq 8(%%rax),%%mm2;\n"
85 " movq 16(%%rax),%%mm3;\n"
86 " movq $0x1000,%%rax;\n"
87 " movq %%rax,%%mm5;\n" /* For rounding */
88 " xorq %%rsi,%%rsi;\n"
89 " .p2align 2;\n"
90 "1:\n"
91 " movq (%%rcx,%%rsi,2),%%mm0;\n"
92 " pmaddwd %%mm1,%%mm0;\n"
93
94 " movq 8(%%rcx,%%rsi,2),%%mm4;\n"
95 " pmaddwd %%mm2,%%mm4;\n"
96 " paddd %%mm4,%%mm0;\n"
97
98 " movq 16(%%rcx,%%rsi,2),%%mm4;\n"
99 " pmaddwd %%mm3,%%mm4;\n"
100 " paddd %%mm4,%%mm0;\n"
101
102 " movq %%mm0,%%mm4;\n"
103 " punpckhdq %%mm0,%%mm4;\n" /* mm4 has high int32 of mm0 dup'd */
104 " paddd %%mm4,%%mm0;\n"
105
106 " paddd %%mm5,%%mm0;\n" /* Add for roundoff */
107 " psrad $13,%%mm0;\n"
108 " packssdw %%mm0,%%mm0;\n"
109 " movd %%mm0,%%eax;\n" /* eax has result */
110 " movw %%ax,(%%rdi,%%rsi,2);\n"
111 " incq %%rsi;\n"
112 " cmpq $39,%%rsi;\n"
113 " jle 1b;\n"
114 " emms;\n"
115 :
116 : "c" (e), "D" (x), [gsm_H] "X" (gsm_H)
117 : "rax", "rdx", "rsi", "memory"
118 );
119 #elif defined(__GNUC__) && defined(SPANDSP_USE_MMX) && defined(__i386__)
120 /* Table 4.4 Coefficients of the weighting filter */
121 /* This must be padded to a multiple of 4 for MMX to work */
122 static const union
123 {
124 int16_t gsm_H[12];
125 __m64 x[3];
126 } gsm_H =
127 {
128 {
129 -134, -374, 0, 2054, 5741, 8192, 5741, 2054, 0, -374, -134, 0
130 }
131
132 };
133
134 __asm__ __volatile__(
135 " emms;\n"
136 " addl $-10,%%ecx;\n"
137 " leal %[gsm_H],%%eax;\n"
138 " movq (%%eax),%%mm1;\n"
139 " movq 8(%%eax),%%mm2;\n"
140 " movq 16(%%eax),%%mm3;\n"
141 " movl $0x1000,%%eax;\n"
142 " movd %%eax,%%mm5;\n" /* For rounding */
143 " xorl %%esi,%%esi;\n"
144 " .p2align 2;\n"
145 "1:\n"
146 " movq (%%ecx,%%esi,2),%%mm0;\n"
147 " pmaddwd %%mm1,%%mm0;\n"
148
149 " movq 8(%%ecx,%%esi,2),%%mm4;\n"
150 " pmaddwd %%mm2,%%mm4;\n"
151 " paddd %%mm4,%%mm0;\n"
152
153 " movq 16(%%ecx,%%esi,2),%%mm4;\n"
154 " pmaddwd %%mm3,%%mm4;\n"
155 " paddd %%mm4,%%mm0;\n"
156
157 " movq %%mm0,%%mm4;\n"
158 " punpckhdq %%mm0,%%mm4;\n" /* mm4 has high int32 of mm0 dup'd */
159 " paddd %%mm4,%%mm0;\n"
160
161 " paddd %%mm5,%%mm0;\n" /* Add for roundoff */
162 " psrad $13,%%mm0;\n"
163 " packssdw %%mm0,%%mm0;\n"
164 " movd %%mm0,%%eax;\n" /* eax has result */
165 " movw %%ax,(%%edi,%%esi,2);\n"
166 " incl %%esi;\n"
167 " cmpl $39,%%esi;\n"
168 " jle 1b;\n"
169 " emms;\n"
170 :
171 : "c" (e), "D" (x), [gsm_H] "X" (gsm_H)
172 : "eax", "edx", "esi", "memory"
173 );
174 #else
175 int32_t L_result;
176 int k;
177
178 /* The coefficients of the weighting filter are stored in a table
179 (see table 4.4). The following scaling is used:
180
181 H[0..10] = integer(real_H[0..10] * 8192);
182 */
183 /* Initialization of a temporary working array wt[0...49] */
184
185 /* for (k = 0; k <= 4; k++) wt[k] = 0;
186 * for (k = 5; k <= 44; k++) wt[k] = *e++;
187 * for (k = 45; k <= 49; k++) wt[k] = 0;
188 *
189 * (e[-5..-1] and e[40..44] are allocated by the caller,
190 * are initially zero and are not written anywhere.)
191 */
192 e -= 5;
193
194 /* Compute the signal x[0..39] */
195 for (k = 0; k < 40; k++)
196 {
197 L_result = 8192 >> 1;
198
199 /* for (i = 0; i <= 10; i++)
200 * {
201 * L_temp = saturated_mul_16_32(wt[k + i], gsm_H[i]);
202 * L_result = saturated_add32(L_result, L_temp);
203 * }
204 */
205
206 #undef STEP
207 #define STEP(i,H) (e[k + i] * (int32_t) H)
208
209 /* Every one of these multiplications is done twice,
210 but I don't see an elegant way to optimize this.
211 Do you?
212 */
213 L_result += STEP( 0, -134);
214 L_result += STEP( 1, -374);
215 /* += STEP( 2, 0 ); */
216 L_result += STEP( 3, 2054);
217 L_result += STEP( 4, 5741);
218 L_result += STEP( 5, 8192);
219 L_result += STEP( 6, 5741);
220 L_result += STEP( 7, 2054);
221 /* += STEP( 8, 0 ); */
222 L_result += STEP( 9, -374);
223 L_result += STEP(10, -134);
224
225 /* 2 adds vs. >> 16 => 14, minus one shift to compensate for
226 those we lost when replacing L_MULT by '*'. */
227 L_result >>= 13;
228 x[k] = saturate(L_result);
229 }
230 /*endfor*/
231 #endif
232 }
233 /*- End of function --------------------------------------------------------*/
234
235 /* 4.2.14 */
236 static void rpe_grid_selection(int16_t x[40], int16_t xM[13], int16_t *Mc_out)
237 {
238 int i;
239 int32_t L_result;
240 int32_t L_temp;
241 int32_t EM; /* xxx should be L_EM? */
242 int16_t Mc;
243 int32_t L_common_0_3;
244
245 /* The signal x[0..39] is used to select the RPE grid which is
246 represented by Mc. */
247
248 EM = 0;
249 Mc = 0;
250
251 #undef STEP
252 #define STEP(m,i) \
253 L_temp = x[m + 3*i] >> 2; \
254 L_result += L_temp*L_temp;
255
256 /* Common part of 0 and 3 */
257 L_result = 0;
258 STEP(0, 1);
259 STEP(0, 2);
260 STEP(0, 3);
261 STEP(0, 4);
262 STEP(0, 5);
263 STEP(0, 6);
264 STEP(0, 7);
265 STEP(0, 8);
266 STEP(0, 9);
267 STEP(0, 10);
268 STEP(0, 11);
269 STEP(0, 12);
270 L_common_0_3 = L_result;
271
272 /* i = 0 */
273
274 STEP(0, 0);
275 L_result <<= 1; /* implicit in L_MULT */
276 EM = L_result;
277
278 /* i = 1 */
279
280 L_result = 0;
281 STEP(1, 0);
282 STEP(1, 1);
283 STEP(1, 2);
284 STEP(1, 3);
285 STEP(1, 4);
286 STEP(1, 5);
287 STEP(1, 6);
288 STEP(1, 7);
289 STEP(1, 8);
290 STEP(1, 9);
291 STEP(1, 10);
292 STEP(1, 11);
293 STEP(1, 12);
294 L_result <<= 1;
295 if (L_result > EM)
296 {
297 Mc = 1;
298 EM = L_result;
299 }
300 /*endif*/
301
302 /* i = 2 */
303
304 L_result = 0;
305 STEP(2, 0);
306 STEP(2, 1);
307 STEP(2, 2);
308 STEP(2, 3);
309 STEP(2, 4);
310 STEP(2, 5);
311 STEP(2, 6);
312 STEP(2, 7);
313 STEP(2, 8);
314 STEP(2, 9);
315 STEP(2, 10);
316 STEP(2, 11);
317 STEP(2, 12);
318 L_result <<= 1;
319 if (L_result > EM)
320 {
321 Mc = 2;
322 EM = L_result;
323 }
324 /*endif*/
325
326 /* i = 3 */
327
328 L_result = L_common_0_3;
329 STEP(3, 12);
330 L_result <<= 1;
331 if (L_result > EM)
332 {
333 Mc = 3;
334 EM = L_result;
335 }
336 /*endif*/
337
338 /* Down-sampling by a factor 3 to get the selected xM[0..12]
339 RPE sequence. */
340 for (i = 0; i < 13; i++)
341 xM[i] = x[Mc + 3*i];
342 /*endfor*/
343 *Mc_out = Mc;
344 }
345 /*- End of function --------------------------------------------------------*/
346
347 /* 4.12.15 */
348 static void apcm_quantization_xmaxc_to_exp_mant(int16_t xmaxc,
349 int16_t *exp_out,
350 int16_t *mant_out)
351 {
352 int16_t exp;
353 int16_t mant;
354
355 /* Compute exponent and mantissa of the decoded version of xmaxc */
356 exp = 0;
357 if (xmaxc > 15)
358 exp = (int16_t) ((xmaxc >> 3) - 1);
359 /*endif*/
360 mant = xmaxc - (exp << 3);
361
362 if (mant == 0)
363 {
364 exp = -4;
365 mant = 7;
366 }
367 else
368 {
369 while (mant <= 7)
370 {
371 mant = (int16_t) (mant << 1 | 1);
372 exp--;
373 }
374 /*endwhile*/
375 mant -= 8;
376 }
377 /*endif*/
378
379 assert(exp >= -4 && exp <= 6);
380 assert(mant >= 0 && mant <= 7);
381
382 *exp_out = exp;
383 *mant_out = mant;
384 }
385 /*- End of function --------------------------------------------------------*/
386
387 static void apcm_quantization(int16_t xM[13],
388 int16_t xMc[13],
389 int16_t *mant_out,
390 int16_t *exp_out,
391 int16_t *xmaxc_out)
392 {
393 /* Table 4.5 Normalized inverse mantissa used to compute xM/xmax */
394 static const int16_t gsm_NRFAC[8] =
395 {
396 29128, 26215, 23832, 21846, 20165, 18725, 17476, 16384
397 };
398 int i;
399 int itest;
400 int16_t xmax;
401 int16_t xmaxc;
402 int16_t temp;
403 int16_t temp1;
404 int16_t temp2;
405 int16_t exp;
406 int16_t mant;
407
408 /* Find the maximum absolute value xmax of xM[0..12]. */
409 xmax = 0;
410 for (i = 0; i < 13; i++)
411 {
412 temp = xM[i];
413 temp = saturated_abs16(temp);
414 if (temp > xmax)
415 xmax = temp;
416 /*endif*/
417 }
418 /*endfor*/
419
420 /* Quantizing and coding of xmax to get xmaxc. */
421 exp = 0;
422 temp = xmax >> 9;
423 itest = 0;
424
425 for (i = 0; i <= 5; i++)
426 {
427 itest |= (temp <= 0);
428 temp >>= 1;
429
430 assert(exp <= 5);
431 if (itest == 0)
432 exp++;
433 /*endif*/
434 }
435 /*endfor*/
436
437 assert(exp <= 6 && exp >= 0);
438 temp = (int16_t) (exp + 5);
439
440 assert(temp <= 11 && temp >= 0);
441 xmaxc = saturated_add16((xmax >> temp), exp << 3);
442
443 /* Quantizing and coding of the xM[0..12] RPE sequence
444 to get the xMc[0..12] */
445 apcm_quantization_xmaxc_to_exp_mant(xmaxc, &exp, &mant);
446
447 /* This computation uses the fact that the decoded version of xmaxc
448 can be calculated by using the exponent and the mantissa part of
449 xmaxc (logarithmic table).
450 So, this method avoids any division and uses only a scaling
451 of the RPE samples by a function of the exponent. A direct
452 multiplication by the inverse of the mantissa (NRFAC[0..7]
453 found in table 4.5) gives the 3 bit coded version xMc[0..12]
454 of the RPE samples.
455 */
456 /* Direct computation of xMc[0..12] using table 4.5 */
457 assert(exp <= 4096 && exp >= -4096);
458 assert(mant >= 0 && mant <= 7);
459
460 temp1 = (int16_t) (6 - exp); /* Normalization by the exponent */
461 temp2 = gsm_NRFAC[mant]; /* Inverse mantissa */
462
463 for (i = 0; i < 13; i++)
464 {
465 assert(temp1 >= 0 && temp1 < 16);
466
467 temp = xM[i] << temp1;
468 temp = saturated_mul16(temp, temp2);
469 temp >>= 12;
470 xMc[i] = (int16_t) (temp + 4); /* See note below */
471 }
472 /*endfor*/
473
474 /* NOTE: This equation is used to make all the xMc[i] positive. */
475 *mant_out = mant;
476 *exp_out = exp;
477 *xmaxc_out = xmaxc;
478 }
479 /*- End of function --------------------------------------------------------*/
480
481 /* 4.2.16 */
482 static void apcm_inverse_quantization(int16_t xMc[13],
483 int16_t mant,
484 int16_t exp,
485 int16_t xMp[13])
486 {
487 /* Table 4.6 Normalized direct mantissa used to compute xM/xmax */
488 static const int16_t gsm_FAC[8] =
489 {
490 18431, 20479, 22527, 24575, 26623, 28671, 30719, 32767
491 };
492 int i;
493 int16_t temp;
494 int16_t temp1;
495 int16_t temp2;
496 int16_t temp3;
497
498 /* This part is for decoding the RPE sequence of coded xMc[0..12]
499 samples to obtain the xMp[0..12] array. Table 4.6 is used to get
500 the mantissa of xmaxc (FAC[0..7]).
501 */
502 #if 0
503 assert(mant >= 0 && mant <= 7);
504 #endif
505
506 temp1 = gsm_FAC[mant]; /* See 4.2-15 for mant */
507 temp2 = saturated_sub16(6, exp); /* See 4.2-15 for exp */
508 temp3 = gsm_asl(1, saturated_sub16(temp2, 1));
509
510 for (i = 0; i < 13; i++)
511 {
512 assert(xMc[i] >= 0 && xMc[i] <= 7); /* 3 bit unsigned */
513
514 temp = (int16_t) ((xMc[i] << 1) - 7); /* Restore sign */
515 assert(temp <= 7 && temp >= -7); /* 4 bit signed */
516
517 temp <<= 12; /* 16 bit signed */
518 temp = gsm_mult_r(temp1, temp);
519 temp = saturated_add16(temp, temp3);
520 xMp[i] = gsm_asr(temp, temp2);
521 }
522 /*endfor*/
523 }
524 /*- End of function --------------------------------------------------------*/
525
526 /* 4.2.17 */
527 static void rpe_grid_positioning(int16_t Mc,
528 int16_t xMp[13],
529 int16_t ep[40])
530 {
531 int i = 13;
532
533 /* This procedure computes the reconstructed long term residual signal
534 ep[0..39] for the LTP analysis filter. The inputs are the Mc
535 which is the grid position selection and the xMp[0..12] decoded
536 RPE samples which are upsampled by a factor of 3 by inserting zero
537 values.
538 */
539 assert(0 <= Mc && Mc <= 3);
540
541 switch (Mc)
542 {
543 case 3:
544 *ep++ = 0;
545 case 2:
546 do
547 {
548 *ep++ = 0;
549 case 1:
550 *ep++ = 0;
551 case 0:
552 *ep++ = *xMp++;
553 }
554 while (--i);
555 }
556 /*endswitch*/
557 while (++Mc < 4)
558 *ep++ = 0;
559 /*endwhile*/
560 }
561 /*- End of function --------------------------------------------------------*/
562
563 void gsm0610_rpe_encoding(gsm0610_state_t *s,
564 int16_t *e, // [-5..-1][0..39][40..44]
565 int16_t *xmaxc,
566 int16_t *Mc,
567 int16_t xMc[13])
568 {
569 int16_t x[40];
570 int16_t xM[13];
571 int16_t xMp[13];
572 int16_t mant;
573 int16_t exp;
574
575 weighting_filter(x, e);
576 rpe_grid_selection(x, xM, Mc);
577
578 apcm_quantization(xM, xMc, &mant, &exp, xmaxc);
579 apcm_inverse_quantization(xMc, mant, exp, xMp);
580
581 rpe_grid_positioning(*Mc, xMp, e);
582 }
583 /*- End of function --------------------------------------------------------*/
584
585 void gsm0610_rpe_decoding(gsm0610_state_t *s,
586 int16_t xmaxc,
587 int16_t Mcr,
588 int16_t xMcr[13],
589 int16_t erp[40])
590 {
591 int16_t exp;
592 int16_t mant;
593 int16_t xMp[13];
594
595 apcm_quantization_xmaxc_to_exp_mant(xmaxc, &exp, &mant);
596 apcm_inverse_quantization(xMcr, mant, exp, xMp);
597 rpe_grid_positioning(Mcr, xMp, erp);
598 }
599 /*- End of function --------------------------------------------------------*/
600 /*- End of file ------------------------------------------------------------*/

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