FreeCalypso > hg > gsm-codec-lib
comparison libgsmfr2/comfort_noise.c @ 256:a33edf624061
libgsmfr2: start with API definition and port of libgsmfrp code
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 12 Apr 2024 20:49:53 +0000 |
parents | libgsmfrp/comfort_noise.c@f081a6850fb5 |
children | 573afa985df6 |
comparison
equal
deleted
inserted
replaced
255:07f936338de1 | 256:a33edf624061 |
---|---|
1 /* | |
2 * In this module we implement comfort noise generation per GSM 06.12 | |
3 * or 3GPP TS 46.012. | |
4 */ | |
5 | |
6 #include <stdint.h> | |
7 #include <string.h> | |
8 #include "tw_gsmfr.h" | |
9 #include "pp_internal.h" | |
10 | |
11 static const uint8_t fold_table_8to6[24] = { | |
12 1, 2, 3, 4, 5, 6, 1, 2, | |
13 1, 2, 3, 4, 5, 6, 3, 4, | |
14 1, 2, 3, 4, 5, 6, 5, 6, | |
15 }; | |
16 | |
17 static const uint8_t bc[4] = {0, 0, 0, 0}; | |
18 static const uint8_t Nc[4] = {40, 120, 40, 120}; | |
19 | |
20 static uint8_t random_1to6(struct gsmfr_preproc_state *st) | |
21 { | |
22 uint8_t range8, range6; | |
23 | |
24 range8 = gsmfr_preproc_prng(st, 3); | |
25 range6 = fold_table_8to6[(st->cn_random_6fold << 3) | range8]; | |
26 st->cn_random_6fold++; | |
27 if (st->cn_random_6fold >= 3) | |
28 st->cn_random_6fold = 0; | |
29 return range6; | |
30 } | |
31 | |
32 void gsmfr_preproc_gen_cn(struct gsmfr_preproc_state *st, uint8_t *frame) | |
33 { | |
34 unsigned sub, pulse; | |
35 uint8_t Mc, xmc[13]; | |
36 uint8_t *c; | |
37 | |
38 /* global bytes (magic and LARc) are fixed */ | |
39 memcpy(frame, st->sid_prefix, 5); | |
40 c = frame + 5; | |
41 /* now do the 4 subframes, mostly PRNG output */ | |
42 for (sub = 0; sub < 4; sub++) { | |
43 Mc = gsmfr_preproc_prng(st, 2); | |
44 for (pulse = 0; pulse < 13; pulse++) | |
45 xmc[pulse] = random_1to6(st); | |
46 /* packing code from libgsm */ | |
47 *c++ = ((Nc[sub] & 0x7F) << 1) | |
48 | ((bc[sub] >> 1) & 0x1); | |
49 *c++ = ((bc[sub] & 0x1) << 7) | |
50 | ((Mc & 0x3) << 5) | |
51 | ((st->sid_xmaxc >> 1) & 0x1F); | |
52 *c++ = ((st->sid_xmaxc & 0x1) << 7) | |
53 | ((xmc[0] & 0x7) << 4) | |
54 | ((xmc[1] & 0x7) << 1) | |
55 | ((xmc[2] >> 2) & 0x1); | |
56 *c++ = ((xmc[2] & 0x3) << 6) | |
57 | ((xmc[3] & 0x7) << 3) | |
58 | (xmc[4] & 0x7); | |
59 *c++ = ((xmc[5] & 0x7) << 5) | |
60 | ((xmc[6] & 0x7) << 2) | |
61 | ((xmc[7] >> 1) & 0x3); | |
62 *c++ = ((xmc[7] & 0x1) << 7) | |
63 | ((xmc[8] & 0x7) << 4) | |
64 | ((xmc[9] & 0x7) << 1) | |
65 | ((xmc[10] >> 2) & 0x1); | |
66 *c++ = ((xmc[10] & 0x3) << 6) | |
67 | ((xmc[11] & 0x7) << 3) | |
68 | (xmc[12] & 0x7); | |
69 } | |
70 } | |
71 | |
72 void gsmfr_preproc_sid2cn(struct gsmfr_preproc_state *st, uint8_t *frame) | |
73 { | |
74 unsigned sub, pulse; | |
75 uint8_t Mc, xmc[13]; | |
76 uint8_t *c; | |
77 | |
78 /* save LARc and Xmaxc from the last subframe for subsequent CN gen */ | |
79 memcpy(st->sid_prefix, frame, 5); | |
80 st->sid_xmaxc = ((frame[27] & 0x1F) << 1) | (frame[28] >> 7); | |
81 /* ... and turn *this* frame into very first CN output */ | |
82 c = frame + 5; | |
83 for (sub = 0; sub < 4; sub++) { | |
84 Mc = gsmfr_preproc_prng(st, 2); | |
85 for (pulse = 0; pulse < 13; pulse++) | |
86 xmc[pulse] = random_1to6(st); | |
87 /* keep each of Xmaxc and replace the rest with CN */ | |
88 *c++ = ((Nc[sub] & 0x7F) << 1) | |
89 | ((bc[sub] >> 1) & 0x1); | |
90 *c &= 0x1F; | |
91 *c++ |= ((bc[sub] & 0x1) << 7) | |
92 | ((Mc & 0x3) << 5); | |
93 *c &= 0x80; | |
94 *c++ |= ((xmc[0] & 0x7) << 4) | |
95 | ((xmc[1] & 0x7) << 1) | |
96 | ((xmc[2] >> 2) & 0x1); | |
97 *c++ = ((xmc[2] & 0x3) << 6) | |
98 | ((xmc[3] & 0x7) << 3) | |
99 | (xmc[4] & 0x7); | |
100 *c++ = ((xmc[5] & 0x7) << 5) | |
101 | ((xmc[6] & 0x7) << 2) | |
102 | ((xmc[7] >> 1) & 0x3); | |
103 *c++ = ((xmc[7] & 0x1) << 7) | |
104 | ((xmc[8] & 0x7) << 4) | |
105 | ((xmc[9] & 0x7) << 1) | |
106 | ((xmc[10] >> 2) & 0x1); | |
107 *c++ = ((xmc[10] & 0x3) << 6) | |
108 | ((xmc[11] & 0x7) << 3) | |
109 | (xmc[12] & 0x7); | |
110 } | |
111 } |