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
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
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