Skip to content

Commit fbf8849

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

4 files changed

Lines changed: 188 additions & 0 deletions

File tree

src/include/sof/math/mu_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_MU_LAW_H__
7+
#define __SOF_MATH_MU_LAW_H__
8+
9+
#include <stdint.h>
10+
11+
/**
12+
* sofm_mu_law_encode() - Encode sample with mu-law coding
13+
* @param sample: A s16 sample value
14+
*
15+
* The mu-law codec is defined in ITU-T G.711 standard and has been used
16+
* in telecommunications in USA and Japan. The mu-law coding compresses
17+
* 14 bit samples to 8 bit data stream. In SOF the high 14 bits of s16
18+
* format are used for compatibility with normal audios.
19+
*
20+
* @return: Compressed 8 bit code value
21+
*/
22+
uint8_t sofm_mu_law_encode(int16_t sample);
23+
24+
/**
25+
* sofm_mu_law_decode() - Decode mu-law encoded code word
26+
* @param byte: Encoded code word
27+
*
28+
* The mu-law decoder expands a 8 bit code word into a 14 bit sample value.
29+
* In the SOF the high 14 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_mu_law_decode(int8_t byte);
35+
36+
#endif /* __SOF_MATH_MU_LAW_H__ */

src/math/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ if(CONFIG_MATH_A_LAW_CODEC)
8787
list(APPEND base_files a_law.c)
8888
endif()
8989

90+
if(CONFIG_MATH_MU_LAW_CODEC)
91+
list(APPEND base_files mu_law.c)
92+
endif()
93+
9094
is_zephyr(it_is)
9195
if(it_is) ### Zephyr ###
9296

src/math/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,4 +279,14 @@ config MATH_A_LAW_CODEC
279279
to 8 bit coded data. A-law codec can be used in VoIP and
280280
8-bit wav formats.
281281

282+
config MATH_MU_LAW_CODEC
283+
bool "mu-law encoder and decoder"
284+
help
285+
This option enables functions sofm_mu_law_encode() and
286+
sofm_mu_law_decode(). The mu-law codec is defined in
287+
ITU-T G.711 standard and has been used in telecommunications
288+
in USA and Japan. The mu-law coding compresses 14 bit samples
289+
to 8 bit coded data. Mu-law codec can be used in VoIP and
290+
8-bit wav formats.
291+
282292
endmenu

src/math/mu_law.c

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
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/mu_law.h>
9+
#include <stdint.h>
10+
11+
#define SOFM_MULAW_BIAS 33
12+
#define SOFM_MULAW_MAX 8191
13+
#define SOFM_MULAW_TOGGLE_BITS 0x7f
14+
#define SOFM_MULAW_SIGN_BIT 0x80
15+
#define SOFM_MULAW_MANTISSA_MASK 0x0f
16+
#define SOFM_MULAW_MANTISSA_BITS 4
17+
#define SOFM_MULAW_SHIFT_MASK 0x07
18+
#define SOFM_MULAW_DEC_ONES_MASK 0x21 /* 0b100001 for "1abcd1", see below */
19+
20+
/*
21+
* mu-law encode table (sign bit is b12)
22+
*
23+
* Input values 12:0 Output values 6:0
24+
*
25+
* 0 0 0 0 0 0 0 1 a b c d x 0 0 0 a b c d
26+
* 0 0 0 0 0 0 1 a b c d x x 0 0 1 a b c d
27+
* 0 0 0 0 0 1 a b c d x x x 0 1 0 a b c d
28+
* 0 0 0 0 1 a b c d x x x x 0 1 1 a b c d
29+
* 0 0 0 1 a b c d x x x x x 1 0 0 a b c d
30+
* 0 0 1 a b c d x x x x x x 1 0 1 a b c d
31+
* 0 1 a b c d x x x x x x x 1 1 0 a b c d
32+
* 1 a b c d x x x x x x x x 1 1 1 a b c d
33+
*
34+
* mu-law decode table (sign bit is b7)
35+
*
36+
* Input values 6:0 Output values 12:0
37+
*
38+
* 0 0 0 a b c d 0 0 0 0 0 0 0 1 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 0
40+
* 0 1 0 a b c d 0 0 0 0 0 1 a b c d 1 0 0
41+
* 0 1 1 a b c d 0 0 0 0 1 a b c d 1 0 0 0
42+
* 1 0 0 a b c d 0 0 0 1 a b c d 1 0 0 0 0
43+
* 1 0 1 a b c d 0 0 1 a b c d 1 0 0 0 0 0
44+
* 1 1 0 a b c d 0 1 a b c d 1 0 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 0
46+
*/
47+
48+
/* Shift values lookup table for above table for 7
49+
* highest sample value bits.
50+
*/
51+
static uint8_t mulaw_encode_shifts[128] = {
52+
0, 1, 2, 2, 3, 3, 3, 3,
53+
4, 4, 4, 4, 4, 4, 4, 4,
54+
5, 5, 5, 5, 5, 5, 5, 5,
55+
5, 5, 5, 5, 5, 5, 5, 5,
56+
6, 6, 6, 6, 6, 6, 6, 6,
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+
7, 7, 7, 7, 7, 7, 7, 7,
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+
};
69+
70+
/**
71+
* sofm_mu_law_encode() - Encode sample with mu-law coding
72+
* @param sample: A s16 sample value
73+
*
74+
* The mu-law codec is defined in ITU-T G.711 standard and has been used
75+
* in telecommunications in USA and Japan. The mu-law coding compresses
76+
* 14 bit samples to 8 bit data stream. In SOF the high 14 bits of s16
77+
* format are used for compatibility with normal audios.
78+
*
79+
* @return: Compressed 8 bit code value
80+
*/
81+
82+
uint8_t sofm_mu_law_encode(int16_t sample)
83+
{
84+
int sign = SOFM_MULAW_SIGN_BIT;
85+
int shift = 0;
86+
int low_bits;
87+
uint8_t byte;
88+
89+
/* Convert to 14 bits with shift */
90+
sample >>= 2;
91+
92+
/* Negative samples are 1's complement with zero sign bit */
93+
if (sample < 0) {
94+
sign = 0;
95+
sample = -sample - 1;
96+
}
97+
98+
sample += SOFM_MULAW_BIAS;
99+
if (sample > SOFM_MULAW_MAX)
100+
sample = SOFM_MULAW_MAX;
101+
102+
shift = mulaw_encode_shifts[sample >> 6];
103+
low_bits = (sample >> (shift + 1)) & SOFM_MULAW_MANTISSA_MASK;
104+
105+
byte = (shift << SOFM_MULAW_MANTISSA_BITS) | low_bits | sign;
106+
byte ^= SOFM_MULAW_TOGGLE_BITS;
107+
return byte;
108+
}
109+
110+
/**
111+
* sofm_mu_law_decode() - Decode mu-law encoded code word
112+
* @param byte: Encoded code word
113+
*
114+
* The mu-law decoder expands a 8 bit code word into a 14 bit sample value.
115+
* In the SOF the high 14 bits are aligned to the most significant bits
116+
* to be compatible with normal s16 Q1.15 samples.
117+
*
118+
* @return: Sampple value in s16 format
119+
*/
120+
int16_t sofm_mu_law_decode(int8_t byte)
121+
{
122+
int low_bits;
123+
int shift;
124+
int sign;
125+
int16_t value;
126+
127+
sign = byte & SOFM_MULAW_SIGN_BIT;
128+
byte ^= SOFM_MULAW_TOGGLE_BITS;
129+
low_bits = byte & SOFM_MULAW_MANTISSA_MASK;
130+
shift = (byte >> SOFM_MULAW_MANTISSA_BITS) & SOFM_MULAW_SHIFT_MASK;
131+
value = (low_bits << (shift + 1)) | (SOFM_MULAW_DEC_ONES_MASK << shift);
132+
value -= SOFM_MULAW_BIAS;
133+
if (!sign)
134+
value = -value;
135+
136+
/* Shift 14 bit Q1.13 to 16 bit Q1.15 */
137+
return value << 2;
138+
}

0 commit comments

Comments
 (0)