FreeCalypso > hg > gsm-codec-lib
annotate doc/PCM8-conversions @ 235:0ee1a66c1846
doc/PCM8-conversions: beginning of document
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 08 May 2023 00:45:26 +0000 |
parents | |
children | 4c7d0dc1eecb |
rev | line source |
---|---|
235
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
1 What is the authoritatively correct, officially endorsed bidirectional mapping |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
2 between G.711 A-law and mu-law encodings on one side and 16-bit 2's complement |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
3 linear PCM on the other side? Surprisingly, there is no official answer to this |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
4 problem anywhere in the specs! Instead the specs provide the following partial |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
5 answers: |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
6 |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
7 * The G.711 spec itself provides one mapping from A-law code octets to linear |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
8 numeric values in range [-4032,4032] and another mapping from mu-law code |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
9 octets to linear numeric values in range [-8031,8031]. The output from each |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
10 of these mapping is given in "pure mathematical" form, without specifying any |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
11 bit-level encoding, and furthermore, mu-law decoder output in its pure |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
12 "conceptual" form has both +0 and -0 values. (The same signed zero problem |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
13 does not occur in A-law because it's a mid-riser code rather than mid-tread, |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
14 and thus has no quantized values equal to 0.) |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
15 |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
16 * If one takes the "pure mathematical" output from the spec-prescribed G.711 |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
17 decoder and represents it in 2's complement form, squashing +0 and -0 outputs |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
18 from the canonical mu-law decoder into "plain 0" at this step, the result is |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
19 a 13 bits wide 2's complement value for A-law decoding and a 14 bits wide 2's |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
20 complement value for mu-law. |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
21 |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
22 * All GSM speech encoders take 13-bit 2's complement linear PCM samples as their |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
23 input. How should this 13-bit GSM codec input be derived from A-law or mu-law |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
24 code octets? GSM specs refer to ITU's G.726 spec for ADPCM - it just so |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
25 happens that inside the ADPCM algorithm of G.726 (a totally unrelated codec of |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
26 no relevance to GSM codec work outside of this reference) there is a pair of |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
27 functions for expanding A-law and mu-law to linear PCM and compressing linear |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
28 PCM back to A-law or mu-law. |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
29 |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
30 * Following this obscure G.726 reference, we eventually conclude that in the |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
31 case of A-law, GSM specs call for the obvious treatment: take the "natural" |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
32 output from the canonical A-law decoder, represent it in 2's complement form, |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
33 the result is 13 bits wide, and just feed that 13-bit 2's complement form to |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
34 the input of GSM speech encoders. However, in the case of mu-law the |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
35 "natural" G.711 decoder output is one sign bit plus 13 bits of magnitude, |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
36 requiring 14 bits in 2's complement representation - and none of the specs I |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
37 could find says anything about exactly how this 14-bit input should be reduced |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
38 to 13 bits for feeding to GSM speech encoders. Canonical C implementations |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
39 of all GSM speech encoders take their input in 16-bit words and clear the 3 |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
40 least significant bits as their first step; if the 14-bit mu-law decoder |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
41 output is represented in 16-bit words by padding 2 zero bits on the right and |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
42 this output is then fed to GSM speech encoder functions, the end effect is |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
43 that the least-significant bit of the 14-bit decoder output is simply cut off. |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
44 This form of mu-law-to-GSM transcoder implementation is consistent with |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
45 TESTx-U.INP and TESTx-U.COD sequences provided in the GSM 06.54 package for |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
46 EFR. |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
47 |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
48 Based on the above considerations, we have our answer for how we should convert |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
49 from G.711 to 16-bit 2's complement linear PCM: |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
50 |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
51 * For A-law, we emit the "natural" output in 13-bit 2's complement form and |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
52 append 3 zero bits on the right; this transformation is fully lossless. |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
53 |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
54 * For mu-law, we emit the "natural" output in 14-bit 2's complement form and |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
55 append 2 zero bits on the right. This transformation is almost lossless, |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
56 with just one exception: the "pure" decoder's -0 output (resulting from PCMU |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
57 octet 0x7F) is squashed to "plain 0", and will be re-emitted as PCMU octet |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
58 0xFF rather than 0x7F on subsequent re-encoding to G.711 PCMU. |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
59 |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
60 For anyone needing a G.711 to 16-bit linear PCM decoder, the present package |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
61 provides ready-made decoding tables (following the above rules) in |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
62 dev/a2s-regen.out and dev/u2s-regen.out, generated by dev/a2s-regen.c and |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
63 dev/u2s-regen.c programs. |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
64 |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
65 Now for the opposite problem: what is the most correct way to compress 16-bit |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
66 2's complement linear PCM to A-law or mu-law? In this direction the official |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
67 specs leave even more ambiguity than in the G.711 decoding direction: |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
68 |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
69 * The G.711 spec itself says: "The conversion to A-law or mu-law values from |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
70 uniform PCM values corresponding to the decision values, is left to the |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
71 individual equipment specification." The specific implementation used in the |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
72 guts of G.726 ADPCM codec is referred to only as a non-normative example. |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
73 |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
74 * GSM specs likewise refer to this G.726 section 4.2.8 (for compression of |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
75 13-bit speech decoder output to G.711) with language that suggests a |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
76 non-normative example. |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
77 |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
78 After painstakingly comparing the C implementation of G.726 in the ITU-T G.191 |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
79 STL against the language of G.726 spec itself and convincing myself that they |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
80 really do match, and then painstakingly comparing this approach against the one |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
81 implemented in the same G.191 STL for G.711 in alaw_compress() and |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
82 ulaw_compress() and against the table lookup method implemented in libgsm/toast |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
83 (my first reference, before I went down the rabbit hole of tracking down |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
84 official specs), I reached the following conclusions: |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
85 |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
86 * For A-law encoding all 3 parties (G.191 STL alaw_compress() function, G.726 |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
87 "compress" block and toast_alaw.c) agree on the same mapping. In this |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
88 mapping only the most significant 12 bits of the 2's complement input word |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
89 (equivalent to one sign bit and 11 bits of magnitude) are relevant, leading |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
90 to the following two interesting properties: |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
91 |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
92 - the least-significant bit of GSM speech decoder output is always discarded |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
93 when converting to A-law; |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
94 |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
95 - conversion can be easily implemented with a 4096-byte look-up table based |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
96 on the upper 12 bits of input, exactly as was done in toast_alaw.c in the |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
97 venerable libgsm source. |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
98 |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
99 * Mu-law encoding is the real hair-raiser: if the input to the to-be-implemented |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
100 encoder has 14 or more bits (including the most practical problem of 16-bit |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
101 2's complement input), there are no less than 3 different ways to implement |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
102 this encoder! |
0ee1a66c1846
doc/PCM8-conversions: beginning of document
Mychaela Falconia <falcon@freecalypso.org>
parents:
diff
changeset
|
103 |