Line data Source code
1 : /******************************************************************************
2 : * ETSI TS 103 634 V1.5.1 *
3 : * Low Complexity Communication Codec Plus (LC3plus) *
4 : * *
5 : * Copyright licence is solely granted through ETSI Intellectual Property *
6 : * Rights Policy, 3rd April 2019. No patent licence is granted by implication, *
7 : * estoppel or otherwise. *
8 : ******************************************************************************/
9 :
10 : #ifndef UTIL_H
11 : #define UTIL_H
12 :
13 : #include "options.h"
14 : #include "wmc_auto.h"
15 : #include "clib.h"
16 : #include "math.h"
17 :
18 : #ifdef _MSC_VER
19 : /* strcasecmp is not available on visual studio */
20 : static LC3_INT strcasecmp(const char* a, const char* b) {
21 : return _stricmp(a,b);
22 : }
23 : #endif
24 :
25 : /* restrict is not available on visual studio */
26 : #ifdef _MSC_VER
27 : #define restrict __restrict
28 : /* inline is not recognized in visual studio 13 required by matlab r2015a in win10 */
29 : #define inline __inline
30 : #endif
31 :
32 : /* number of elements in array */
33 : #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
34 :
35 : /* min max with no side effects */
36 0 : static inline LC3_INT imin(LC3_INT a, LC3_INT b) { return a < b ? a : b; }
37 : static inline LC3_INT imax(LC3_INT a, LC3_INT b) { return a > b ? a : b; }
38 :
39 : /* restrict x to range [min, max] */
40 : static inline LC3_INT iclamp(LC3_INT min, LC3_INT x, LC3_INT max) {
41 : return x < min ? min : x > max ? max : x;
42 : }
43 : static inline double fcmamp(double min, double x, double max) {
44 : return x < min ? min : x > max ? max : x;
45 : }
46 0 : static inline LC3_FLOAT fclampf(LC3_FLOAT min, LC3_FLOAT x, LC3_FLOAT max) {
47 0 : return x < min ? min : x > max ? max : x;
48 : }
49 :
50 : /* x² */
51 0 : static inline LC3_FLOAT sqrf(LC3_FLOAT x) { return x * x; }
52 :
53 : /* convenience wrappers around memmove */
54 0 : static inline void move_float(LC3_FLOAT *dst, const LC3_FLOAT *src, LC3_INT len) {
55 : #ifdef WMOPS
56 : LC3_INT i;
57 : for (i = 0; i < len; i++)
58 : {
59 : dst[i] = src[i];
60 : }
61 : #else
62 0 : memmove(dst, src, len * sizeof(LC3_FLOAT));
63 : #endif
64 0 : }
65 0 : static inline void move_int(LC3_INT *dst, const LC3_INT *src, LC3_INT len) {
66 : #ifdef WMOPS
67 : LC3_INT i;
68 : for (i = 0; i < len; i++)
69 : {
70 : dst[i] = src[i];
71 : }
72 : #else
73 0 : memmove(dst, src, len * sizeof(LC3_INT));
74 : #endif
75 0 : }
76 :
77 : /* convenience wrappers around memset */
78 0 : static inline void zero_float(LC3_FLOAT *x, LC3_INT len) {
79 : #ifdef WMOPS
80 : LC3_INT i;
81 : for (i = 0; i < len; i++)
82 : {
83 : x[i] = 0;
84 : }
85 : #else
86 0 : memset(x, 0, len * sizeof(LC3_FLOAT));
87 : #endif
88 0 : }
89 0 : static inline void zero_int(LC3_INT *x, LC3_INT len) {
90 : #ifdef WMOPS
91 : LC3_INT i;
92 : for (i = 0; i < len; i++)
93 : {
94 : x[i] = 0;
95 : }
96 : #else
97 0 : memset(x, 0, len * sizeof(LC3_INT));
98 : #endif
99 0 : }
100 :
101 : /* multiply float vectors element by element, in-place */
102 0 : static inline void mult_vec(LC3_FLOAT *a, const LC3_FLOAT *b,
103 : LC3_INT len) {
104 0 : LC3_INT i = 0;
105 0 : for (i = 0; i < len; i++) {
106 0 : a[i] *= b[i];
107 : }
108 0 : }
109 :
110 : /* multiply float vector with constant, in-place */
111 0 : static inline void mult_const(LC3_FLOAT *a, LC3_FLOAT b, LC3_INT len) {
112 0 : LC3_INT i = 0;
113 0 : for (i = 0; i < len; i++) {
114 0 : a[i] *= b;
115 : }
116 0 : }
117 :
118 : /* sum of vector */
119 0 : static inline LC3_FLOAT sum_vec(const LC3_FLOAT *x, LC3_INT len) {
120 0 : LC3_FLOAT sum = 0;
121 0 : LC3_INT i = 0;
122 0 : for (i = 0; i < len; i++) {
123 0 : sum += x[i];
124 : }
125 0 : return sum;
126 : }
127 :
128 : /* complex constructor */
129 0 : static inline Complex cmplx(LC3_FLOAT r, LC3_FLOAT i) { return (Complex){r, i}; }
130 :
131 : /* complex a + b */
132 0 : static inline Complex cadd(Complex a, Complex b) {
133 0 : return cmplx(a.r + b.r, a.i + b.i);
134 : }
135 :
136 : /* complex a * b */
137 0 : static inline Complex cmul(Complex a, Complex b) {
138 0 : return cmplx(a.r * b.r - a.i * b.i, a.i * b.r + a.r * b.i);
139 : }
140 :
141 : /* mac operator */
142 0 : static inline LC3_FLOAT mac_loop(const LC3_FLOAT *array1, const LC3_FLOAT *array2, LC3_INT len)
143 : {
144 : LC3_INT i;
145 0 : LC3_FLOAT sum = 0.0;
146 :
147 0 : for (i = 0; i < len; i++)
148 : {
149 0 : sum += (*array1++) * (*array2++);
150 : }
151 :
152 0 : return sum;
153 : }
154 :
155 : /* complex eᶦˣ */
156 0 : static inline Complex cexpi(LC3_FLOAT x) { return cmplx(LC3_COS(x), LC3_SIN(x)); }
157 :
158 : /* complex -x */
159 : static inline Complex cneg(Complex x) { return cmplx(-x.r, -x.i); }
160 :
161 : /* convert string to number. return true on success */
162 : static inline bool str_to_int(const char *str, LC3_INT *value) {
163 : char *end = NULL;
164 : long v = str ? strtol(str, &end, 0) : 0;
165 : *value = (LC3_INT)v;
166 : return str && *end == 0 && v >= INT_MIN && v <= INT_MAX;
167 : }
168 :
169 : /* returns true if str ends with str ends with suffix. ignoring case. str may be
170 : * NULL */
171 : static inline bool str_ends_with(const char *str, const char *suffix) {
172 : char *tmp = str ? strrchr(str, suffix[0]) : NULL;
173 : return tmp && !strcasecmp(tmp, suffix);
174 : }
175 :
176 : /* complex a - b */
177 0 : static inline Complex csub(Complex a, Complex b) {
178 0 : return cmplx(a.r - b.r, a.i - b.i);
179 : }
180 :
181 0 : static inline void move_cmplx(Complex *dst, const Complex *src, LC3_INT32 len) {
182 0 : if (len > 0) {
183 0 : memmove(dst, src, len * sizeof(Complex));
184 0 : assert(src[len - 1].r == dst[len - 1].r && src[len - 1].i == dst[len - 1].i); /*check that Cmplx is stored contiguously*/
185 0 : assert(src[0].r == dst[0].r && src[0].i == dst[0].i); /*check that Cmplx is stored contiguously*/
186 : }
187 0 : }
188 :
189 0 : static inline void zero_cmplx(Complex *x, LC3_INT32 len) {
190 0 : if(len > 0) {
191 0 : memset(x, 0, len * sizeof(Complex));
192 0 : assert(x[0].r == 0 && x[0].i == 0 && x[len-1].r == 0 && x[len-1].i == 0);
193 : }
194 0 : }
195 :
196 0 : static inline Complex realtoc(LC3_FLOAT r) { return cmplx(r, 0); }
197 :
198 : /* set float vector to constant */
199 0 : static inline void set_vec(const LC3_FLOAT c, LC3_FLOAT *x, LC3_INT32 len) {
200 0 : LC3_INT32 i = 0;
201 0 : for (i = 0; i < len; i++) {
202 0 : x[i] = c;
203 : }
204 0 : }
205 :
206 : /* set float vector to constant */
207 0 : static inline void set_vec_int(const LC3_INT32 c, LC3_INT32 *x, LC3_INT32 len) {
208 0 : LC3_INT32 i = 0;
209 0 : for (i = 0; i < len; i++) {
210 0 : x[i] = c;
211 : }
212 0 : }
213 :
214 0 : static inline LC3_INT32 clz_func(LC3_INT32 inp)
215 : {
216 : #if defined(__clang__) || defined(__GNUC__)
217 0 : if (inp == 0)
218 : {
219 0 : return 0;
220 : }
221 0 : return __builtin_clz(inp);
222 :
223 : #elif defined(_WIN32) || defined(_WIN64)
224 : LC3_INT32 leading_zero = 0;
225 :
226 : if (_BitScanReverse(&leading_zero, inp))
227 : {
228 : return 31 - leading_zero;
229 : }
230 : else
231 : return 0;
232 :
233 : #else
234 : LC3_INT32 i = 0;
235 : int64_t x = inp;
236 :
237 : if (inp == 0)
238 : {
239 : return 0;
240 : }
241 :
242 : inp = (inp < 0) ? ~inp : inp;
243 :
244 : while (x < (int64_t)0x80000000L)
245 : {
246 : inp <<= 1;
247 : i += 1;
248 : }
249 :
250 : return i;
251 : #endif
252 : }
253 :
254 :
255 : #endif
|