blob: cb35fc6517c085d6f9b92cd1d74dc7beec42f974 [file] [log] [blame]
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001/*
2 * PCM - A-Law conversion
3 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
4 *
5 * Wrapper for linphone Codec class by Simon Morlat <simon.morlat@linphone.org>
6 *
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23static inline int val_seg(int val)
24{
25 int r = 0;
26 val >>= 7; /*7 = 4 + 3*/
27 if (val & 0xf0) {
28 val >>= 4;
29 r += 4;
30 }
31 if (val & 0x0c) {
32 val >>= 2;
33 r += 2;
34 }
35 if (val & 0x02)
36 r += 1;
37 return r;
38}
39
40/*
41 * s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
42 *
43 * s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data.
44 *
45 * Linear Input Code Compressed Code
46 * ------------------------ ---------------
47 * 0000000wxyza 000wxyz
48 * 0000001wxyza 001wxyz
49 * 000001wxyzab 010wxyz
50 * 00001wxyzabc 011wxyz
51 * 0001wxyzabcd 100wxyz
52 * 001wxyzabcde 101wxyz
53 * 01wxyzabcdef 110wxyz
54 * 1wxyzabcdefg 111wxyz
55 *
56 * For further information see John C. Bellamy's Digital Telephony, 1982,
57 * John Wiley & Sons, pps 98-111 and 472-476.
58 * G711 is designed for 13 bits input signal, this function add extra shifting to take this into account.
59 */
60
61static inline unsigned char s16_to_alaw(int pcm_val)
62{
63 int mask;
64 int seg;
65 unsigned char aval;
66
67 if (pcm_val >= 0) {
68 mask = 0xD5;
69 } else {
70 mask = 0x55;
71 pcm_val = -pcm_val;
72 if (pcm_val > 0x7fff)
73 pcm_val = 0x7fff;
74 }
75
76 if (pcm_val < 256) /*256 = 32 << 3*/
77 aval = pcm_val >> 4; /*4 = 1 + 3*/
78 else {
79 /* Convert the scaled magnitude to segment number. */
80 seg = val_seg(pcm_val);
81 aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
82 }
83 return aval ^ mask;
84}
85
86/*
87 * alaw_to_s16() - Convert an A-law value to 16-bit linear PCM
88 *
89 */
90static inline int alaw_to_s16(unsigned char a_val)
91{
92 int t;
93 int seg;
94
95 a_val ^= 0x55;
96 t = a_val & 0x7f;
97 if (t < 16)
98 t = (t << 4) + 8;
99 else {
100 seg = (t >> 4) & 0x07;
101 t = ((t & 0x0f) << 4) + 0x108;
102 t <<= seg -1;
103 }
104 return ((a_val & 0x80) ? t : -t);
105}
106/*
107 * s16_to_ulaw() - Convert a linear PCM value to u-law
108 *
109 * In order to simplify the encoding process, the original linear magnitude
110 * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
111 * (33 - 8191). The result can be seen in the following encoding table:
112 *
113 * Biased Linear Input Code Compressed Code
114 * ------------------------ ---------------
115 * 00000001wxyza 000wxyz
116 * 0000001wxyzab 001wxyz
117 * 000001wxyzabc 010wxyz
118 * 00001wxyzabcd 011wxyz
119 * 0001wxyzabcde 100wxyz
120 * 001wxyzabcdef 101wxyz
121 * 01wxyzabcdefg 110wxyz
122 * 1wxyzabcdefgh 111wxyz
123 *
124 * Each biased linear code has a leading 1 which identifies the segment
125 * number. The value of the segment number is equal to 7 minus the number
126 * of leading 0's. The quantization interval is directly available as the
127 * four bits wxyz. * The trailing bits (a - h) are ignored.
128 *
129 * Ordinarily the complement of the resulting code word is used for
130 * transmission, and so the code word is complemented before it is returned.
131 *
132 * For further information see John C. Bellamy's Digital Telephony, 1982,
133 * John Wiley & Sons, pps 98-111 and 472-476.
134 */
135
136static inline unsigned char s16_to_ulaw(int pcm_val) /* 2's complement (16-bit range) */
137{
138 int mask;
139 int seg;
140 unsigned char uval;
141
142 if (pcm_val < 0) {
143 pcm_val = 0x84 - pcm_val;
144 mask = 0x7f;
145 } else {
146 pcm_val += 0x84;
147 mask = 0xff;
148 }
149 if (pcm_val > 0x7fff)
150 pcm_val = 0x7fff;
151
152 /* Convert the scaled magnitude to segment number. */
153 seg = val_seg(pcm_val);
154
155 /*
156 * Combine the sign, segment, quantization bits;
157 * and complement the code word.
158 */
159 uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
160 return uval ^ mask;
161}
162
163/*
164 * ulaw_to_s16() - Convert a u-law value to 16-bit linear PCM
165 *
166 * First, a biased linear code is derived from the code word. An unbiased
167 * output can then be obtained by subtracting 33 from the biased code.
168 *
169 * Note that this function expects to be passed the complement of the
170 * original code word. This is in keeping with ISDN conventions.
171 */
172static inline int ulaw_to_s16(unsigned char u_val)
173{
174 int t;
175
176 /* Complement to obtain normal u-law value. */
177 u_val = ~u_val;
178
179 /*
180 * Extract and bias the quantization bits. Then
181 * shift up by the segment number and subtract out the bias.
182 */
183 t = ((u_val & 0x0f) << 3) + 0x84;
184 t <<= (u_val & 0x70) >> 4;
185
186 return ((u_val & 0x80) ? (0x84 - t) : (t - 0x84));
187}