|
| 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