|
| 1 | +// SPDX-License-Identifier: BSD-3-Clause |
| 2 | +// |
| 3 | +// Copyright(c) 2020-2026 Intel Corporation. |
| 4 | +// |
| 5 | +// Author: Amery Song <chao.song@intel.com> |
| 6 | +// Keyon Jie <yang.jie@linux.intel.com> |
| 7 | + |
| 8 | +#include <sof/audio/format.h> |
| 9 | +#include <sof/common.h> |
| 10 | +#include <stdint.h> |
| 11 | + |
| 12 | +#ifndef __SOF_ICOMPLEX16_H__ |
| 13 | +#define __SOF_ICOMPLEX16_H__ |
| 14 | + |
| 15 | +/* Note: the add of packed attribute to icmplex16 would significantly increase |
| 16 | + * processing time of fft_execute_16() so it is not done. The optimized versions of |
| 17 | + * FFT for HiFi will need a different packed data structure vs. generic C. |
| 18 | + * |
| 19 | + * TODO: Use with care with other than 16-bit FFT internals. Access with intrinsics |
| 20 | + * will requires packed and aligned data. Currently there is no such usage in SOF. |
| 21 | + */ |
| 22 | + |
| 23 | +/** |
| 24 | + * struct icomplex16 - Storage for a normal complex number. |
| 25 | + * @param real The real part in Q1.15 fractional format. |
| 26 | + * @param imag The imaginary part in Q1.15 fractional format. |
| 27 | + */ |
| 28 | +struct icomplex16 { |
| 29 | + int16_t real; |
| 30 | + int16_t imag; |
| 31 | +}; |
| 32 | + |
| 33 | +/* |
| 34 | + * Helpers for 16 bit FFT calculation |
| 35 | + */ |
| 36 | +static inline void icomplex16_add(const struct icomplex16 *in1, const struct icomplex16 *in2, |
| 37 | + struct icomplex16 *out) |
| 38 | +{ |
| 39 | + out->real = in1->real + in2->real; |
| 40 | + out->imag = in1->imag + in2->imag; |
| 41 | +} |
| 42 | + |
| 43 | +static inline void icomplex16_sub(const struct icomplex16 *in1, const struct icomplex16 *in2, |
| 44 | + struct icomplex16 *out) |
| 45 | +{ |
| 46 | + out->real = in1->real - in2->real; |
| 47 | + out->imag = in1->imag - in2->imag; |
| 48 | +} |
| 49 | + |
| 50 | +static inline void icomplex16_mul(const struct icomplex16 *in1, const struct icomplex16 *in2, |
| 51 | + struct icomplex16 *out) |
| 52 | +{ |
| 53 | + int32_t real = (int32_t)in1->real * in2->real - (int32_t)in1->imag * in2->imag; |
| 54 | + int32_t imag = (int32_t)in1->real * in2->imag + (int32_t)in1->imag * in2->real; |
| 55 | + |
| 56 | + out->real = Q_SHIFT_RND(real, 30, 15); |
| 57 | + out->imag = Q_SHIFT_RND(imag, 30, 15); |
| 58 | +} |
| 59 | + |
| 60 | +/* complex conjugate */ |
| 61 | +static inline void icomplex16_conj(struct icomplex16 *comp) |
| 62 | +{ |
| 63 | + comp->imag = sat_int16(-((int32_t)comp->imag)); |
| 64 | +} |
| 65 | + |
| 66 | +/* shift a complex n bits, n > 0: left shift, n < 0: right shift */ |
| 67 | +static inline void icomplex16_shift(const struct icomplex16 *input, int16_t n, |
| 68 | + struct icomplex16 *output) |
| 69 | +{ |
| 70 | + int n1, n2; |
| 71 | + |
| 72 | + if (n >= 0) { |
| 73 | + /* need saturation handling */ |
| 74 | + output->real = sat_int16((int32_t)input->real << n); |
| 75 | + output->imag = sat_int16((int32_t)input->imag << n); |
| 76 | + } else { |
| 77 | + n1 = -n; |
| 78 | + n2 = 1 << (n1 - 1); |
| 79 | + output->real = sat_int16(((int32_t)input->real + n2) >> n1); |
| 80 | + output->imag = sat_int16(((int32_t)input->imag + n2) >> n1); |
| 81 | + } |
| 82 | +} |
| 83 | + |
| 84 | +#endif /* __SOF_ICOMPLEX16_H__ */ |
0 commit comments