mirror of
https://github.moeyy.xyz/https://github.com/TheAlgorithms/C.git
synced 2023-10-11 15:56:24 +08:00
feat: add G.711 a-law algorithm (#858)
* feat: add G.711 a-law algorithm * chore: add CMakeLists.txt for audio/ * updating DIRECTORY.md * docs: add explanation to G.711 a-law algorithm * docs: adjust comments to G.711 a-law algorithm Co-authored-by: David Leal <halfpacho@gmail.com> * docs: adjust comments to G.711 a-law algorithm Co-authored-by: David Leal <halfpacho@gmail.com> * test: add self-test for G.711 a-law algorithm * fix: initialize variables to zero * docs: adjust comments to G.711 a-law algorithm Co-authored-by: David Leal <halfpacho@gmail.com> Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal <halfpacho@gmail.com>
This commit is contained in:
parent
690d49099d
commit
97d021424e
@ -52,6 +52,7 @@ add_subdirectory(developer_tools)
|
|||||||
add_subdirectory(hash)
|
add_subdirectory(hash)
|
||||||
add_subdirectory(misc)
|
add_subdirectory(misc)
|
||||||
add_subdirectory(games)
|
add_subdirectory(games)
|
||||||
|
add_subdirectory(audio)
|
||||||
add_subdirectory(sorting)
|
add_subdirectory(sorting)
|
||||||
add_subdirectory(geometry)
|
add_subdirectory(geometry)
|
||||||
add_subdirectory(graphics)
|
add_subdirectory(graphics)
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
# List of all files
|
# List of all files
|
||||||
|
|
||||||
|
## Audio
|
||||||
|
* [Alaw](https://github.com/TheAlgorithms/C/blob/master/audio/alaw.c)
|
||||||
|
|
||||||
## Client Server
|
## Client Server
|
||||||
* [Client](https://github.com/TheAlgorithms/C/blob/master/client_server/client.c)
|
* [Client](https://github.com/TheAlgorithms/C/blob/master/client_server/client.c)
|
||||||
* [Server](https://github.com/TheAlgorithms/C/blob/master/client_server/server.c)
|
* [Server](https://github.com/TheAlgorithms/C/blob/master/client_server/server.c)
|
||||||
|
14
audio/CMakeLists.txt
Normal file
14
audio/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# If necessary, use the RELATIVE flag, otherwise each source file may be listed
|
||||||
|
# with full pathname. RELATIVE may makes it easier to extract an executable name
|
||||||
|
# automatically.
|
||||||
|
file( GLOB APP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.c )
|
||||||
|
# file( GLOB APP_SOURCES ${CMAKE_SOURCE_DIR}/*.c )
|
||||||
|
# AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} APP_SOURCES)
|
||||||
|
foreach( testsourcefile ${APP_SOURCES} )
|
||||||
|
# I used a simple string replace, to cut off .cpp.
|
||||||
|
string( REPLACE ".c" "" testname ${testsourcefile} )
|
||||||
|
add_executable( ${testname} ${testsourcefile} )
|
||||||
|
|
||||||
|
install(TARGETS ${testname} DESTINATION "bin/audio")
|
||||||
|
|
||||||
|
endforeach( testsourcefile ${APP_SOURCES} )
|
216
audio/alaw.c
Normal file
216
audio/alaw.c
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @author [sunzhenliang](https://github.com/HiSunzhenliang)
|
||||||
|
* @brief A-law algorithm for encoding and decoding (16bit pcm <=> a-law).
|
||||||
|
* This is the implementation of [G.711](https://en.wikipedia.org/wiki/G.711)
|
||||||
|
* in C.
|
||||||
|
**/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Linear input code | Compressed code | Linear output code
|
||||||
|
* ------------------+-----------------+-------------------
|
||||||
|
* s0000000abcdx | s000abcd | s0000000abcd1
|
||||||
|
* s0000001abcdx | s001abcd | s0000001abcd1
|
||||||
|
* s000001abcdxx | s010abcd | s000001abcd10
|
||||||
|
* s00001abcdxxx | s011abcd | s00001abcd100
|
||||||
|
* s0001abcdxxxx | s100abcd | s0001abcd1000
|
||||||
|
* s001abcdxxxxx | s101abcd | s001abcd10000
|
||||||
|
* s01abcdxxxxxx | s110abcd | s01abcd100000
|
||||||
|
* s1abcdxxxxxxx | s111abcd | s1abcd1000000
|
||||||
|
*
|
||||||
|
* Compressed code: (s | eee | abcd)
|
||||||
|
**/
|
||||||
|
#include <assert.h> /// for assert
|
||||||
|
#include <inttypes.h> /// for appropriate size int types
|
||||||
|
#include <stdio.h> /// for IO operations
|
||||||
|
|
||||||
|
/* length of test inputs */
|
||||||
|
#define LEN ((size_t)8)
|
||||||
|
|
||||||
|
/* input pcm for test */
|
||||||
|
int16_t pcm[LEN] = {1000, -1000, 1234, 3200, -1314, 0, 32767, -32768};
|
||||||
|
|
||||||
|
/* result coded alaw for test */
|
||||||
|
uint8_t r_coded[LEN] = {250, 122, 230, 156, 97, 213, 170, 42};
|
||||||
|
|
||||||
|
/* result decoded for test */
|
||||||
|
int16_t r_decoded[LEN] = {1008, -1008, 1248, 3264, -1312, 8, 32256, -32256};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 16bit pcm to 8bit alaw
|
||||||
|
* @param out unsigned 8bit alaw array
|
||||||
|
* @param in signed 16bit pcm array
|
||||||
|
* @param len length of pcm array
|
||||||
|
* @returns void
|
||||||
|
*/
|
||||||
|
void encode(uint8_t *out, int16_t *in, size_t len)
|
||||||
|
{
|
||||||
|
uint8_t alaw = 0;
|
||||||
|
int16_t pcm = 0;
|
||||||
|
int32_t sign = 0;
|
||||||
|
int32_t abcd = 0;
|
||||||
|
int32_t eee = 0;
|
||||||
|
int32_t mask = 0;
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
pcm = *in++;
|
||||||
|
/* 0-7 kinds of quantization level from the table above */
|
||||||
|
eee = 7;
|
||||||
|
mask = 0x4000; /* 0x4000: '0b0100 0000 0000 0000' */
|
||||||
|
|
||||||
|
/* Get sign bit */
|
||||||
|
sign = (pcm & 0x8000) >> 8;
|
||||||
|
|
||||||
|
/* Turn negative pcm to positive */
|
||||||
|
/* The absolute value of a negative number may be larger than the size
|
||||||
|
* of the corresponding positive number, so here needs `-pcm -1` after
|
||||||
|
* taking the opposite number. */
|
||||||
|
pcm = sign ? (-pcm - 1) : pcm;
|
||||||
|
|
||||||
|
/* Get eee and abcd bit */
|
||||||
|
/* Use mask to locate the first `1` bit and quantization level at the
|
||||||
|
* same time */
|
||||||
|
while ((pcm & mask) == 0 && eee > 0)
|
||||||
|
{
|
||||||
|
eee--;
|
||||||
|
mask >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The location of abcd bits is related with quantization level. Check
|
||||||
|
* the table above to determine how many bits to `>>` to get abcd */
|
||||||
|
abcd = (pcm >> (eee ? (eee + 3) : 4)) & 0x0f;
|
||||||
|
|
||||||
|
/* Put the quantization level number at right bit location to get eee
|
||||||
|
* bits */
|
||||||
|
eee <<= 4;
|
||||||
|
|
||||||
|
/* Splice results */
|
||||||
|
alaw = (sign | eee | abcd);
|
||||||
|
|
||||||
|
/* The standard specifies that all resulting even bits (LSB
|
||||||
|
* is even) are inverted before the octet is transmitted. This is to
|
||||||
|
* provide plenty of 0/1 transitions to facilitate the clock recovery
|
||||||
|
* process in the PCM receivers. Thus, a silent A-law encoded PCM
|
||||||
|
* channel has the 8 bit samples coded 0xD5 instead of 0x80 in the
|
||||||
|
* octets. (Reference from wiki above) */
|
||||||
|
*out++ = alaw ^ 0xD5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 8bit alaw to 16bit pcm
|
||||||
|
* @param out signed 16bit pcm array
|
||||||
|
* @param in unsigned 8bit alaw array
|
||||||
|
* @param len length of alaw array
|
||||||
|
* @returns void
|
||||||
|
*/
|
||||||
|
void decode(int16_t *out, uint8_t *in, size_t len)
|
||||||
|
{
|
||||||
|
uint8_t alaw = 0;
|
||||||
|
int32_t pcm = 0;
|
||||||
|
int32_t sign = 0;
|
||||||
|
int32_t eee = 0;
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
alaw = *in++;
|
||||||
|
|
||||||
|
/* Re-toggle toggled bits */
|
||||||
|
alaw ^= 0xD5;
|
||||||
|
|
||||||
|
/* Get sign bit */
|
||||||
|
sign = alaw & 0x80;
|
||||||
|
|
||||||
|
/* Get eee bits */
|
||||||
|
eee = (alaw & 0x70) >> 4;
|
||||||
|
|
||||||
|
/* Get abcd bits and add 1/2 quantization step */
|
||||||
|
pcm = (alaw & 0x0f) << 4 | 8;
|
||||||
|
|
||||||
|
/* If quantization level > 0, there need `1` bit before abcd bits */
|
||||||
|
pcm += eee ? 0x100 : 0x0;
|
||||||
|
|
||||||
|
/* Left shift according quantization level */
|
||||||
|
pcm <<= eee > 1 ? (eee - 1) : 0;
|
||||||
|
|
||||||
|
/* Use the right sign */
|
||||||
|
*out++ = sign ? -pcm : pcm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Self-test implementations
|
||||||
|
* @param pcm signed 16bit pcm array
|
||||||
|
* @param coded unsigned 8bit alaw array
|
||||||
|
* @param decoded signed 16bit pcm array
|
||||||
|
* @param len length of test array
|
||||||
|
* @returns void
|
||||||
|
*/
|
||||||
|
static void test(int16_t *pcm, uint8_t *coded, int16_t *decoded, size_t len)
|
||||||
|
{
|
||||||
|
/* run encode */
|
||||||
|
encode(coded, pcm, len);
|
||||||
|
|
||||||
|
/* check encode result */
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
assert(coded[i] == r_coded[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* run decode */
|
||||||
|
decode(decoded, coded, len);
|
||||||
|
|
||||||
|
/* check decode result */
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
assert(decoded[i] == r_decoded[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Main function
|
||||||
|
* @param argc commandline argument count (ignored)
|
||||||
|
* @param argv commandline array of arguments (ignored)
|
||||||
|
* @returns 0 on exit
|
||||||
|
*/
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
/* output alaw encoded by encode() */
|
||||||
|
uint8_t coded[LEN];
|
||||||
|
|
||||||
|
/* output pcm decoded by decode() from coded[LEN] */
|
||||||
|
int16_t decoded[LEN];
|
||||||
|
|
||||||
|
test(pcm, coded, decoded, LEN); // run self-test implementations
|
||||||
|
|
||||||
|
/* print test pcm inputs */
|
||||||
|
printf("inputs: ");
|
||||||
|
for (size_t i = 0; i < LEN; i++)
|
||||||
|
{
|
||||||
|
printf("%d ", pcm[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
/* print encoded alaw */
|
||||||
|
printf("encode: ");
|
||||||
|
for (size_t i = 0; i < LEN; i++)
|
||||||
|
{
|
||||||
|
printf("%u ", coded[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
/* print decoded pcm */
|
||||||
|
printf("decode: ");
|
||||||
|
for (size_t i = 0; i < LEN; i++)
|
||||||
|
{
|
||||||
|
printf("%d ", decoded[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
/* It can be seen that the encoded alaw is smaller than the input PCM, so
|
||||||
|
* the purpose of compression is achieved. And the decoded PCM is almost the
|
||||||
|
* same as the original input PCM, which verifies the correctness of the
|
||||||
|
* decoding. The reason why it is not exactly the same is that there is
|
||||||
|
* precision loss during encode / decode. */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user