Skip to content

Commit 894a7f1

Browse files
committed
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 8-bit A-law encoded wav files support. Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
1 parent 8386366 commit 894a7f1

4 files changed

Lines changed: 200 additions & 0 deletions

File tree

src/include/sof/math/a_law.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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.701 standard and has been used
16+
* in telecommunications in e.g. Europe. In SOF the main purpose is
17+
* support for wav format. The A-law coding compresses 13 bit samples
18+
* to 8 bit data stream. In SOF the high 13 bits of s16 format are used
19+
* for compatibility with normal audios.
20+
*
21+
* @return: Compressed 8 bit code value
22+
*/
23+
uint8_t sofm_a_law_encode(int16_t sample);
24+
25+
/**
26+
* sofm_a_law_decode() - Decode A-law encoded code word
27+
* @param byte: Encoded code word
28+
*
29+
* The A-law decoder expands a 8 bit code word into a 13 bit sample value.
30+
* In the SOF the high 13 bits are aligned to the most significant bits
31+
* to be compatible with normal s16 Q1.15 samples.
32+
*
33+
* @return: Sampple value in s16 format
34+
*/
35+
int16_t sofm_a_law_decode(int8_t byte);
36+
37+
#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: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,4 +269,16 @@ 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+
default n
275+
help
276+
This option enables functions sofm_a_law_encode() and
277+
sofm_a_law_decode(). The A-law codec is defined in
278+
ITU-T G.701 standard and has been used in telecommunications
279+
in e.g. Europe. In SOF the main purpose is support for wav
280+
format. The A-law coding compresses 13 bit samples to 8 bit
281+
coded data.
282+
283+
272284
endmenu

src/math/a_law.c

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
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.701 standard and has been used
76+
* in telecommunications in e.g. Europe. In SOF the main purpose is
77+
* support for wav format. The A-law coding compresses 13 bit samples
78+
* to 8 bit data stream. In SOF the high 13 bits of s16 format are used
79+
* for compatibility with normal audios.
80+
*
81+
* @return: Compressed 8 bit code value
82+
*/
83+
84+
uint8_t sofm_a_law_encode(int16_t sample)
85+
{
86+
int sign = SOFM_ALAW_SIGN_BIT;
87+
int shift = 0;
88+
int low_bits;
89+
uint8_t byte;
90+
91+
/* Convert to 13 bits with shift */
92+
sample = sample >> 3;
93+
94+
/* Negative samples are 1's complement with zero sign bit */
95+
if (sample < 0) {
96+
sign = 0;
97+
sample = -sample - 1;
98+
}
99+
100+
if (sample > SOFM_ALAW_MAX)
101+
sample = SOFM_ALAW_MAX;
102+
103+
if (sample > 31) {
104+
shift = alaw_encode_shifts[sample >> 5];
105+
low_bits = (sample >> shift) & SOFM_ALAW_MANTISSA_MASK;
106+
} else {
107+
low_bits = (sample >> 1) & SOFM_ALAW_MANTISSA_MASK;
108+
}
109+
110+
byte = (shift << SOFM_ALAW_MANTISSA_BITS) | low_bits;
111+
byte = (byte | sign) ^ SOFM_ALAW_TOGGLE_EVEN_BITS;
112+
return byte;
113+
}
114+
115+
/**
116+
* sofm_a_law_decode() - Decode A-law encoded code word
117+
* @param byte: Encoded code word
118+
*
119+
* The A-law decoder expands a 8 bit code word into a 13 bit sample value.
120+
* In the SOF the high 13 bits are aligned to the most significant bits
121+
* to be compatible with normal s16 Q1.15 samples.
122+
*
123+
* @return: Sampple value in s16 format
124+
*/
125+
int16_t sofm_a_law_decode(int8_t byte)
126+
{
127+
int low_bits;
128+
int shift;
129+
int sign;
130+
int16_t value;
131+
132+
byte ^= SOFM_ALAW_TOGGLE_EVEN_BITS;
133+
low_bits = byte & SOFM_ALAW_MANTISSA_MASK;
134+
shift = (byte >> SOFM_ALAW_MANTISSA_BITS) & SOFM_ALAW_SHIFT_MASK;
135+
sign = byte & SOFM_ALAW_SIGN_BIT;
136+
137+
if (shift > 0)
138+
value = (low_bits << shift) | (SOFM_ALAW_DEC_ONES_MASK << (shift - 1));
139+
else
140+
value = (low_bits << 1) | 1;
141+
142+
if (!sign)
143+
value = -value;
144+
145+
/* Shift 13 bit Q1.12 to 16 bit Q1.15 */
146+
return value << 3;
147+
}

0 commit comments

Comments
 (0)