Skip to content

Commit e9777b7

Browse files
singalsulgirdwood
authored andcommitted
Math: Add functions for A-law encode and decode
This patch adds to math library functions sofm_a_law_encode() and sofm_a_law_decode(). The main usage is support for VoIP and 8-bit A-law encoded wav files support. Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
1 parent b694161 commit e9777b7

4 files changed

Lines changed: 196 additions & 0 deletions

File tree

src/include/sof/math/a_law.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/* SPDX-License-Identifier: BSD-3-Clause
2+
*
3+
* Copyright(c) 2025 Intel Corporation.
4+
*/
5+
6+
#ifndef __SOF_MATH_A_LAW_H__
7+
#define __SOF_MATH_A_LAW_H__
8+
9+
#include <stdint.h>
10+
11+
/**
12+
* sofm_a_law_encode() - Encode sample with A-law coding
13+
* @param sample: A s16 sample value
14+
*
15+
* The A-law codec is defined in ITU-T G.711 standard and has been used
16+
* in telecommunications in e.g. Europe. The A-law coding compresses 13 bit
17+
* samples to 8 bit data stream. In SOF the high 13 bits of s16 format are
18+
* used for compatibility with normal audios.
19+
*
20+
* @return: Compressed 8 bit code value
21+
*/
22+
uint8_t sofm_a_law_encode(int16_t sample);
23+
24+
/**
25+
* sofm_a_law_decode() - Decode A-law encoded code word
26+
* @param byte: Encoded code word
27+
*
28+
* The A-law decoder expands a 8 bit code word into a 13 bit sample value.
29+
* In the SOF the high 13 bits are aligned to the most significant bits
30+
* to be compatible with normal s16 Q1.15 samples.
31+
*
32+
* @return: Sample value in s16 format
33+
*/
34+
int16_t sofm_a_law_decode(int8_t byte);
35+
36+
#endif /* __SOF_MATH_A_LAW_H__ */

src/math/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ if(CONFIG_MATH_DCT)
8383
list(APPEND base_files dct.c)
8484
endif()
8585

86+
if(CONFIG_MATH_A_LAW_CODEC)
87+
list(APPEND base_files a_law.c)
88+
endif()
89+
8690
is_zephyr(it_is)
8791
if(it_is) ### Zephyr ###
8892

src/math/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,4 +269,14 @@ config MATH_DCT
269269
transform for data is done as matrix multiply with the
270270
returned DCT matrix.
271271

272+
config MATH_A_LAW_CODEC
273+
bool "A-law encoder and decoder"
274+
help
275+
This option enables functions sofm_a_law_encode() and
276+
sofm_a_law_decode(). The A-law codec is defined in
277+
ITU-T G.711 standard and has been used in telecommunications
278+
in e.g. Europe. The A-law coding compresses 13 bit samples
279+
to 8 bit coded data. A-law codec can be used in VoIP and
280+
8-bit wav formats.
281+
272282
endmenu

src/math/a_law.c

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
//
3+
// Copyright(c) 2025 Intel Corporation.
4+
//
5+
// Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
6+
7+
#include <sof/audio/format.h>
8+
#include <sof/math/a_law.h>
9+
#include <stdint.h>
10+
11+
#define SOFM_ALAW_SIGN_BIT 0x80
12+
#define SOFM_ALAW_MAX 4095
13+
#define SOFM_ALAW_TOGGLE_EVEN_BITS 0x55
14+
#define SOFM_ALAW_MANTISSA_MASK 0x0f
15+
#define SOFM_ALAW_MANTISSA_BITS 4
16+
#define SOFM_ALAW_SHIFT_MASK 0x07
17+
#define SOFM_ALAW_DEC_ONES_MASK 0x21 /* 0b100001 for "1abcd1", see below */
18+
19+
/*
20+
* A-law encode table (sign bit is b12)
21+
*
22+
* Input values 11:0 Output values 6:0
23+
*
24+
* 0 0 0 0 0 0 0 a b c d x 0 0 0 a b c d
25+
* 0 0 0 0 0 0 1 a b c d x 0 0 1 a b c d
26+
* 0 0 0 0 0 1 a b c d x x 0 1 0 a b c d
27+
* 0 0 0 0 1 a b c d x x x 0 1 1 a b c d
28+
* 0 0 0 1 a b c d x x x x 1 0 0 a b c d
29+
* 0 0 1 a b c d x x x x x 1 0 1 a b c d
30+
* 0 1 a b c d x x x x x x 1 1 0 a b c d
31+
* 1 a b c d x x x x x x x 1 1 1 a b c d
32+
*
33+
*
34+
* A-law decode table (sign bit is b7)
35+
*
36+
* Input values 6:0 Output values 11:0
37+
*
38+
* 0 0 0 a b c d 0 0 0 0 0 0 0 a b c d 1
39+
* 0 0 1 a b c d 0 0 0 0 0 0 1 a b c d 1
40+
* 0 1 0 a b c d 0 0 0 0 0 1 a b c d 1 0
41+
* 0 1 1 a b c d 0 0 0 0 1 a b c d 1 0 0
42+
* 1 0 0 a b c d 0 0 0 1 a b c d 1 0 0 0
43+
* 1 0 1 a b c d 0 0 1 a b c d 1 0 0 0 0
44+
* 1 1 0 a b c d 0 1 a b c d 1 0 0 0 0 0
45+
* 1 1 1 a b c d 1 a b c d 1 0 0 0 0 0 0
46+
*
47+
*/
48+
49+
/* Shift values lookup table for above table for 7
50+
* highest sample value bits.
51+
*/
52+
static uint8_t alaw_encode_shifts[128] = {
53+
1, 1, 2, 2, 3, 3, 3, 3,
54+
4, 4, 4, 4, 4, 4, 4, 4,
55+
5, 5, 5, 5, 5, 5, 5, 5,
56+
5, 5, 5, 5, 5, 5, 5, 5,
57+
6, 6, 6, 6, 6, 6, 6, 6,
58+
6, 6, 6, 6, 6, 6, 6, 6,
59+
6, 6, 6, 6, 6, 6, 6, 6,
60+
6, 6, 6, 6, 6, 6, 6, 6,
61+
7, 7, 7, 7, 7, 7, 7, 7,
62+
7, 7, 7, 7, 7, 7, 7, 7,
63+
7, 7, 7, 7, 7, 7, 7, 7,
64+
7, 7, 7, 7, 7, 7, 7, 7,
65+
7, 7, 7, 7, 7, 7, 7, 7,
66+
7, 7, 7, 7, 7, 7, 7, 7,
67+
7, 7, 7, 7, 7, 7, 7, 7,
68+
7, 7, 7, 7, 7, 7, 7, 7,
69+
};
70+
71+
/**
72+
* sofm_a_law_encode() - Encode sample with A-law coding
73+
* @param sample: A s16 sample value
74+
*
75+
* The A-law codec is defined in ITU-T G.711 standard and has been used
76+
* in telecommunications in e.g. Europe. The A-law coding compresses 13 bit
77+
* samples to 8 bit data stream. In SOF the high 13 bits of s16 format are
78+
* used for compatibility with normal audios.
79+
*
80+
* @return: Compressed 8 bit code value
81+
*/
82+
83+
uint8_t sofm_a_law_encode(int16_t sample)
84+
{
85+
int sign = SOFM_ALAW_SIGN_BIT;
86+
int shift = 0;
87+
int low_bits;
88+
uint8_t byte;
89+
90+
/* Convert to 13 bits with shift */
91+
sample >>= 3;
92+
93+
/* Negative samples are 1's complement with zero sign bit */
94+
if (sample < 0) {
95+
sign = 0;
96+
sample = -sample - 1;
97+
}
98+
99+
if (sample > SOFM_ALAW_MAX)
100+
sample = SOFM_ALAW_MAX;
101+
102+
if (sample > 31) {
103+
shift = alaw_encode_shifts[sample >> 5];
104+
low_bits = (sample >> shift) & SOFM_ALAW_MANTISSA_MASK;
105+
} else {
106+
low_bits = (sample >> 1) & SOFM_ALAW_MANTISSA_MASK;
107+
}
108+
109+
byte = (shift << SOFM_ALAW_MANTISSA_BITS) | low_bits;
110+
byte = (byte | sign) ^ SOFM_ALAW_TOGGLE_EVEN_BITS;
111+
return byte;
112+
}
113+
114+
/**
115+
* sofm_a_law_decode() - Decode A-law encoded code word
116+
* @param byte: Encoded code word
117+
*
118+
* The A-law decoder expands a 8 bit code word into a 13 bit sample value.
119+
* In the SOF the high 13 bits are aligned to the most significant bits
120+
* to be compatible with normal s16 Q1.15 samples.
121+
*
122+
* @return: Sample value in s16 format
123+
*/
124+
int16_t sofm_a_law_decode(int8_t byte)
125+
{
126+
int low_bits;
127+
int shift;
128+
int sign;
129+
int16_t value;
130+
131+
byte ^= SOFM_ALAW_TOGGLE_EVEN_BITS;
132+
low_bits = byte & SOFM_ALAW_MANTISSA_MASK;
133+
shift = (byte >> SOFM_ALAW_MANTISSA_BITS) & SOFM_ALAW_SHIFT_MASK;
134+
sign = byte & SOFM_ALAW_SIGN_BIT;
135+
136+
if (shift > 0)
137+
value = (low_bits << shift) | (SOFM_ALAW_DEC_ONES_MASK << (shift - 1));
138+
else
139+
value = (low_bits << 1) | 1;
140+
141+
if (!sign)
142+
value = -value;
143+
144+
/* Shift 13 bit Q1.12 to 16 bit Q1.15 */
145+
return value << 3;
146+
}

0 commit comments

Comments
 (0)