wip: MDCT, SNS in fixed point

This commit is contained in:
Antoine Soulier
2023-04-14 14:47:31 -07:00
parent 2ce884d8ef
commit 82db8e05ae
16 changed files with 2526 additions and 2187 deletions

View File

@@ -24,7 +24,6 @@
#define __LC3_COMMON_H
#include <lc3.h>
#include "fastmath.h"
#include <stdalign.h>
#include <limits.h>
@@ -139,9 +138,12 @@ enum lc3_bandwidth {
* Complex floating point number
*/
// TODO
#include "fastmath.h"
struct lc3_complex
{
float re, im;
lc3_intfloat_t re, im;
};

View File

@@ -26,34 +26,40 @@
#include <stdint.h>
#include <math.h>
#include "fixmath.h"
/**
* Fast 2^n approximation
* x Operand, range -8 to 8
* return 2^x approximation (max relative error ~ 7e-6)
* return 2^x approximation (9.23)
*/
static inline float fast_exp2f(float x)
static inline lc3_intfloat_t fast_exp2f(lc3_intfloat_t x)
{
float y;
lc3_intfloat_t y;
/* --- Polynomial approx in range -0.5 to 0.5 --- */
static const float c[] = { 1.27191277e-09, 1.47415221e-07,
1.35510312e-05, 9.38375815e-04, 4.33216946e-02 };
static const lc3_intfloat_t c[] = {
LC3_INTFLOAT_C(1.27191277e-09, 59),
LC3_INTFLOAT_C(1.47415221e-07, 52),
LC3_INTFLOAT_C(1.35510312e-05, 45),
LC3_INTFLOAT_C(9.38375815e-04, 38),
LC3_INTFLOAT_C(4.33216946e-02, 31) };
y = ( c[0]) * x;
y = (y + c[1]) * x;
y = (y + c[2]) * x;
y = (y + c[3]) * x;
y = (y + c[4]) * x;
y = (y + 1.f);
y = lc3_shr( lc3_mul(x, c[0]), 31 );
y = lc3_shr( lc3_mul(x, y + c[1]), 31 );
y = lc3_shr( lc3_mul(x, y + c[2]), 31 );
y = lc3_shr( lc3_mul(x, y + c[3]), 31 );
y = lc3_shr( lc3_mul(x, y + c[4]), 31 );
y = LC3_INTFLOAT_C(1.f, 24) + y;
/* --- Raise to the power of 16 --- */
y = y*y;
y = y*y;
y = y*y;
y = y*y;
y = lc3_shr( lc3_mul(y, y), 24 );
y = lc3_shr( lc3_mul(y, y), 24 );
y = lc3_shr( lc3_mul(y, y), 24 );
y = lc3_shr( lc3_mul(y, y), 25 );
return y;
}

81
src/fixmath.h Normal file
View File

@@ -0,0 +1,81 @@
/******************************************************************************
*
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/**
* LC3 - Mathematics in fixed point
*/
#ifndef __LC3_FIXMATH_H
#define __LC3_FIXMATH_H
#include <stdint.h>
#undef CONFIG_FIXED_POINT // TODO
/**
* Type definition, integer or floating point
* TODO
*/
#ifdef CONFIG_FIXED_POINT
typedef int32_t lc3_intfloat_t;
#define LC3_INTFLOAT_C(x, q) \
(int32_t)LC3_CLIP( (x) * (INT64_C(1) << (q)), -0x1p31, 0x1p31-1 )
#else /* CONFIG_FIXED_POINT */
typedef float lc3_intfloat_t;
#define LC3_INTFLOAT_C(x, q) (x)
#endif /* CONFIG_FIXED_POINT */
/**
* Arithmetic operations
* mul Multiplicaton of 2 x 32 bits values, results on 64 bits
* shr Arithmetic rounded right shift
*/
#ifdef CONFIG_FIXED_POINT
static inline int64_t lc3_mul(int32_t a, int32_t b) {
return (int64_t)a * b;
}
static inline int32_t lc3_shr(int64_t x, int q) {
return (x + (INT64_C(1) << (q-1))) >> q;
}
static inline int32_t lc3_rsqrt(int32_t x, int q) {
return (int32_t)(ldexpf(1.f / sqrtf(x), q) + 0.5f);
}
#else /* CONFIG_FIXED_POINT */
#define lc3_mul(a, b) ( (a) * (b) )
#define lc3_shr(x, q) ( (x) )
#define lc3_rsqrt(x, q) ( 1.f / sqrtf(x) )
#endif /* CONFIG_FIXED_POINT */
#endif /* __LC3_FIXMATH_H */

View File

@@ -271,7 +271,21 @@ static void analyze(struct lc3_encoder *encoder,
float e[LC3_NUM_BANDS];
#ifdef CONFIG_FIXED_POINT
{
int nd = LC3_ND(dt, sr);
int32_t __xs[ns], __xf[ns], __xd[nd];
for (int i = 0; i < ns; i++) __xs[i] = ldexpf(xs[i], 8);
for (int i = 0; i < nd; i++) __xd[i] = ldexpf(xd[i], 8);
lc3_mdct_forward(dt, sr_pcm, sr, __xs, __xd, __xf);
for (int i = 0; i < nd; i++) xd[i] = ldexpf(__xd[i], -8);
for (int i = 0; i < ns; i++) xf[i] = ldexpf(__xf[i], -8);
}
#else
lc3_mdct_forward(dt, sr_pcm, sr, xs, xd, xf);
#endif
bool nn_flag = lc3_energy_compute(dt, sr, xf, e);
if (nn_flag)
@@ -583,16 +597,49 @@ static void synthesize(struct lc3_decoder *decoder,
lc3_tns_synthesize(dt, bw, &side->tns, xf);
#ifdef CONFIG_FIXED_POINT
{
int nd = LC3_ND(dt, sr);
int32_t __xf[ns], __xg[ns], __xs[ns], __xd[nd];
for (int i = 0; i < ns; i++) __xf[i] = ldexpf(xf[i], 8);
for (int i = 0; i < ns; i++) __xg[i] = ldexpf(xg[i], 8);
for (int i = 0; i < nd; i++) __xd[i] = ldexpf(xd[i], 8);
lc3_sns_synthesize(dt, sr, &side->sns, __xf, __xg);
lc3_mdct_inverse(dt, sr_pcm, sr, __xg, __xd, __xs);
for (int i = 0; i < nd; i++) xd[i] = ldexpf(__xd[i], -8);
for (int i = 0; i < ns; i++) xs[i] = ldexpf(__xs[i], -8);
for (int i = 0; i < ns; i++) xg[i] = ldexpf(__xg[i], -8);
}
#else
lc3_sns_synthesize(dt, sr, &side->sns, xf, xg);
lc3_mdct_inverse(dt, sr_pcm, sr, xg, xd, xs);
#endif
} else {
lc3_plc_synthesize(dt, sr, &decoder->plc, xg, xf);
memset(xf + ne, 0, (ns - ne) * sizeof(float));
memset(xf + ne, 0, (ns - ne) * sizeof(lc3_intfloat_t));
#ifdef CONFIG_FIXED_POINT
{
int nd = LC3_ND(dt, sr);
lc3_intfloat_t __xf[ns], __xs[ns], __xd[nd];
for (int i = 0; i < ns; i++) __xf[i] = ldexpf(xf[i], 8);
for (int i = 0; i < nd; i++) __xd[i] = ldexpf(xd[i], 8);
lc3_mdct_inverse(dt, sr_pcm, sr, __xf, __xd, __xs);
for (int i = 0; i < nd; i++) xd[i] = ldexpf(__xd[i], -8);
for (int i = 0; i < ns; i++) xs[i] = ldexpf(__xs[i], -8);
}
#else
lc3_mdct_inverse(dt, sr_pcm, sr, xf, xd, xs);
#endif
}
lc3_ltpf_synthesize(dt, sr_pcm, nbytes, &decoder->ltpf,

View File

@@ -35,11 +35,13 @@
LC3_HOT static inline void fft_5(
const struct lc3_complex *x, struct lc3_complex *y, int n)
{
static const float cos1 = 0.3090169944; /* cos(-2Pi 1/5) */
static const float cos2 = -0.8090169944; /* cos(-2Pi 2/5) */
/* cos( -2Pi n/5 ), sin( -2Pi n/5 ) for n = {1, 2} */
static const float sin1 = -0.9510565163; /* sin(-2Pi 1/5) */
static const float sin2 = -0.5877852523; /* sin(-2Pi 2/5) */
static const lc3_intfloat_t cos1 = LC3_INTFLOAT_C( 0.3090169944, 31);
static const lc3_intfloat_t cos2 = LC3_INTFLOAT_C(-0.8090169944, 31);
static const lc3_intfloat_t sin1 = LC3_INTFLOAT_C(-0.9510565163, 31);
static const lc3_intfloat_t sin2 = LC3_INTFLOAT_C(-0.5877852523, 31);
for (int i = 0; i < n; i++, x++, y+= 5) {
@@ -57,29 +59,37 @@ LC3_HOT static inline void fft_5(
y[0].im = x[0].im + s14.im + s23.im;
y[1].re = x[0].re + s14.re * cos1 - d14.im * sin1
+ s23.re * cos2 - d23.im * sin2;
y[1].re = x[0].re + lc3_shr(
lc3_mul(s14.re, cos1) - lc3_mul(d14.im, sin1) +
lc3_mul(s23.re, cos2) - lc3_mul(d23.im, sin2), 31);
y[1].im = x[0].im + s14.im * cos1 + d14.re * sin1
+ s23.im * cos2 + d23.re * sin2;
y[1].im = x[0].im + lc3_shr(
lc3_mul(s14.im, cos1) + lc3_mul(d14.re, sin1) +
lc3_mul(s23.im, cos2) + lc3_mul(d23.re, sin2), 31);
y[2].re = x[0].re + s14.re * cos2 - d14.im * sin2
+ s23.re * cos1 + d23.im * sin1;
y[2].re = x[0].re + lc3_shr(
lc3_mul(s14.re, cos2) - lc3_mul(d14.im, sin2) +
lc3_mul(s23.re, cos1) + lc3_mul(d23.im, sin1), 31);
y[2].im = x[0].im + s14.im * cos2 + d14.re * sin2
+ s23.im * cos1 - d23.re * sin1;
y[2].im = x[0].im + lc3_shr(
lc3_mul(s14.im, cos2) + lc3_mul(d14.re, sin2) +
lc3_mul(s23.im, cos1) - lc3_mul(d23.re, sin1), 31);
y[3].re = x[0].re + s14.re * cos2 + d14.im * sin2
+ s23.re * cos1 - d23.im * sin1;
y[3].re = x[0].re + lc3_shr(
lc3_mul(s14.re, cos2) + lc3_mul(d14.im, sin2) +
lc3_mul(s23.re, cos1) - lc3_mul(d23.im, sin1), 31);
y[3].im = x[0].im + s14.im * cos2 - d14.re * sin2
+ s23.im * cos1 + d23.re * sin1;
y[3].im = x[0].im + lc3_shr(
lc3_mul(s14.im, cos2) - lc3_mul(d14.re, sin2) +
lc3_mul(s23.im, cos1) + lc3_mul(d23.re, sin1), 31);
y[4].re = x[0].re + s14.re * cos1 + d14.im * sin1
+ s23.re * cos2 + d23.im * sin2;
y[4].re = x[0].re + lc3_shr(
lc3_mul(s14.re, cos1) + lc3_mul(d14.im, sin1) +
lc3_mul(s23.re, cos2) + lc3_mul(d23.im, sin2), 31);
y[4].im = x[0].im + s14.im * cos1 - d14.re * sin1
+ s23.im * cos2 - d23.re * sin2;
y[4].im = x[0].im + lc3_shr(
lc3_mul(s14.im, cos1) - lc3_mul(d14.re, sin1) +
lc3_mul(s23.im, cos2) - lc3_mul(d23.re, sin2), 31);
}
}
#endif /* fft_5 */
@@ -105,23 +115,29 @@ LC3_HOT static inline void fft_bf3(
for (int i = 0; i < n; i++, y0 += 3*n3, y1 += 3*n3, y2 += 3*n3)
for (int j = 0; j < n3; j++, x0++, x1++, x2++) {
y0[j].re = x0->re + x1->re * w0[j][0].re - x1->im * w0[j][0].im
+ x2->re * w0[j][1].re - x2->im * w0[j][1].im;
y0[j].re = x0->re + lc3_shr(
lc3_mul(x1->re, w0[j][0].re) - lc3_mul(x1->im, w0[j][0].im) +
lc3_mul(x2->re, w0[j][1].re) - lc3_mul(x2->im, w0[j][1].im), 31);
y0[j].im = x0->im + x1->im * w0[j][0].re + x1->re * w0[j][0].im
+ x2->im * w0[j][1].re + x2->re * w0[j][1].im;
y0[j].im = x0->im + lc3_shr(
lc3_mul(x1->im, w0[j][0].re) + lc3_mul(x1->re, w0[j][0].im) +
lc3_mul(x2->im, w0[j][1].re) + lc3_mul(x2->re, w0[j][1].im), 31);
y1[j].re = x0->re + x1->re * w1[j][0].re - x1->im * w1[j][0].im
+ x2->re * w1[j][1].re - x2->im * w1[j][1].im;
y1[j].re = x0->re + lc3_shr(
lc3_mul(x1->re, w1[j][0].re) - lc3_mul(x1->im, w1[j][0].im) +
lc3_mul(x2->re, w1[j][1].re) - lc3_mul(x2->im, w1[j][1].im), 31);
y1[j].im = x0->im + x1->im * w1[j][0].re + x1->re * w1[j][0].im
+ x2->im * w1[j][1].re + x2->re * w1[j][1].im;
y1[j].im = x0->im + lc3_shr(
lc3_mul(x1->im, w1[j][0].re) + lc3_mul(x1->re, w1[j][0].im) +
lc3_mul(x2->im, w1[j][1].re) + lc3_mul(x2->re, w1[j][1].im), 31);
y2[j].re = x0->re + x1->re * w2[j][0].re - x1->im * w2[j][0].im
+ x2->re * w2[j][1].re - x2->im * w2[j][1].im;
y2[j].re = x0->re + lc3_shr(
lc3_mul(x1->re, w2[j][0].re) - lc3_mul(x1->im, w2[j][0].im) +
lc3_mul(x2->re, w2[j][1].re) - lc3_mul(x2->im, w2[j][1].im), 31);
y2[j].im = x0->im + x1->im * w2[j][0].re + x1->re * w2[j][0].im
+ x2->im * w2[j][1].re + x2->re * w2[j][1].im;
y2[j].im = x0->im + lc3_shr(
lc3_mul(x1->im, w2[j][0].re) + lc3_mul(x1->re, w2[j][0].im) +
lc3_mul(x2->im, w2[j][1].re) + lc3_mul(x2->re, w2[j][1].im), 31);
}
}
#endif /* fft_bf3 */
@@ -147,11 +163,15 @@ LC3_HOT static inline void fft_bf2(
for (int j = 0; j < n2; j++, x0++, x1++) {
y0[j].re = x0->re + x1->re * w[j].re - x1->im * w[j].im;
y0[j].im = x0->im + x1->im * w[j].re + x1->re * w[j].im;
y0[j].re = x0->re + lc3_shr(
lc3_mul(x1->re, w[j].re) - lc3_mul(x1->im, w[j].im), 31);
y0[j].im = x0->im + lc3_shr(
lc3_mul(x1->im, w[j].re) + lc3_mul(x1->re, w[j].im), 31);
y1[j].re = x0->re - x1->re * w[j].re + x1->im * w[j].im;
y1[j].im = x0->im - x1->im * w[j].re - x1->re * w[j].im;
y1[j].re = x0->re - lc3_shr(
lc3_mul(x1->re, w[j].re) - lc3_mul(x1->im, w[j].im), 31);
y1[j].im = x0->im - lc3_shr(
lc3_mul(x1->im, w[j].re) + lc3_mul(x1->re, w[j].im), 31);
}
}
}
@@ -205,58 +225,68 @@ static struct lc3_complex *fft(const struct lc3_complex *x, int n,
* y, d Output windowed samples, and delayed ones
*/
LC3_HOT static void mdct_window(enum lc3_dt dt, enum lc3_srate sr,
const float *x, float *d, float *y)
const lc3_intfloat_t *x, lc3_intfloat_t *d, lc3_intfloat_t *y)
{
int ns = LC3_NS(dt, sr), nd = LC3_ND(dt, sr);
const float *w0 = lc3_mdct_win[dt][sr], *w1 = w0 + ns;
const float *w2 = w1, *w3 = w2 + nd;
const lc3_intfloat_t *w0 = lc3_mdct_win[dt][sr], *w1 = w0 + ns;
const lc3_intfloat_t *w2 = w1, *w3 = w2 + nd;
const float *x0 = x + ns-nd, *x1 = x0;
float *y0 = y + ns/2, *y1 = y0;
float *d0 = d, *d1 = d + nd;
const lc3_intfloat_t *x0 = x + ns-nd, *x1 = x0;
lc3_intfloat_t *y0 = y + ns/2, *y1 = y0;
lc3_intfloat_t *d0 = d, *d1 = d + nd;
while (x1 > x) {
*(--y0) = *d0 * *(w0++) - *(--x1) * *(--w1);
*(y1++) = (*(d0++) = *(x0++)) * *(w2++);
*(--y0) = lc3_shr( lc3_mul(*(d0 ), *(w0++)) -
lc3_mul(*(--x1), *(--w1)), 30 );
*(--y0) = *d0 * *(w0++) - *(--x1) * *(--w1);
*(y1++) = (*(d0++) = *(x0++)) * *(w2++);
*(y1++) = lc3_shr( lc3_mul(*(d0++) = *(x0++), *(w2++)), 30 );
*(--y0) = lc3_shr( lc3_mul(*(d0 ), *(w0++)) -
lc3_mul(*(--x1), *(--w1)), 30 );
*(y1++) = lc3_shr( lc3_mul(*(d0++) = *(x0++), *(w2++)), 30 );
}
for (x1 += ns; x0 < x1; ) {
*(--y0) = *d0 * *(w0++) - *(--d1) * *(--w1);
*(y1++) = (*(d0++) = *(x0++)) * *(w2++) + (*d1 = *(--x1)) * *(--w3);
*(--y0) = lc3_shr( lc3_mul(*(d0 ), *(w0++)) -
lc3_mul(*(--d1), *(--w1)), 30 );
*(--y0) = *d0 * *(w0++) - *(--d1) * *(--w1);
*(y1++) = (*(d0++) = *(x0++)) * *(w2++) + (*d1 = *(--x1)) * *(--w3);
*(y1++) = lc3_shr( lc3_mul(*(d0++) = *(x0++), *(w2++)) +
lc3_mul(*(d1 ) = *(--x1), *(--w3)), 30 );
*(--y0) = lc3_shr( lc3_mul(*(d0 ), *(w0++)) -
lc3_mul(*(--d1), *(--w1)), 30 );
*(y1++) = lc3_shr( lc3_mul(*(d0++) = *(x0++), *(w2++)) +
lc3_mul(*(d1 ) = *(--x1), *(--w3)), 30 );
}
}
/**
* Pre-rotate MDCT coefficients of N/2 points, before FFT N/4 points FFT
* Pre-rotate and scale MDCT of N/2 points, before N/4 points FFT
* def Size and twiddles factors
* x, y Input and output coefficients
*
* `x` and y` can be the same buffer
*/
LC3_HOT static void mdct_pre_fft(const struct lc3_mdct_rot_def *def,
const float *x, struct lc3_complex *y)
const lc3_intfloat_t *x, struct lc3_complex *y)
{
int n4 = def->n4;
const float *x0 = x, *x1 = x0 + 2*n4;
const lc3_intfloat_t *x0 = x, *x1 = x0 + 2*n4;
const struct lc3_complex *w0 = def->w, *w1 = w0 + n4;
struct lc3_complex *y0 = y, *y1 = y0 + n4;
while (x0 < x1) {
struct lc3_complex u, uw = *(w0++);
u.re = - *(--x1) * uw.re + *x0 * uw.im;
u.im = *(x0++) * uw.re + *x1 * uw.im;
u.re = lc3_shr( - lc3_mul(*(--x1), uw.re) + lc3_mul(*x0, uw.im), 31 );
u.im = lc3_shr( lc3_mul(*(x0++), uw.re) + lc3_mul(*x1, uw.im), 31 );
struct lc3_complex v, vw = *(--w1);
v.re = - *(--x1) * vw.im + *x0 * vw.re;
v.im = - *(x0++) * vw.im - *x1 * vw.re;
v.re = lc3_shr( - lc3_mul(*(--x1), vw.im) + lc3_mul(*x0, vw.re), 31 );
v.im = lc3_shr( - lc3_mul(*(x0++), vw.im) - lc3_mul(*x1, vw.re), 31 );
*(y0++) = u;
*(--y1) = v;
@@ -264,30 +294,30 @@ LC3_HOT static void mdct_pre_fft(const struct lc3_mdct_rot_def *def,
}
/**
* Post-rotate FFT N/4 points coefficients, resulting MDCT N points
* Post-rotate and scale FFT N/4 points, resulting MDCT N points
* def Size and twiddles factors
* x, y Input and output coefficients
* scale Scale on output coefficients
*
* `x` and y` can be the same buffer
*/
LC3_HOT static void mdct_post_fft(const struct lc3_mdct_rot_def *def,
const struct lc3_complex *x, float *y, float scale)
const struct lc3_complex *x, lc3_intfloat_t *y)
{
int n4 = def->n4, n8 = n4 >> 1;
const struct lc3_complex *w0 = def->w + n8, *w1 = w0 - 1;
const struct lc3_complex *x0 = x + n8, *x1 = x0 - 1;
float *y0 = y + n4, *y1 = y0;
lc3_intfloat_t *y0 = y + n4, *y1 = y0;
for ( ; y1 > y; x0++, x1--, w0++, w1--) {
lc3_intfloat_t u0, u1, v0, v1;
float u0 = (x0->im * w0->im + x0->re * w0->re) * scale;
float u1 = (x1->re * w1->im - x1->im * w1->re) * scale;
u0 = lc3_shr( lc3_mul(x0->im, w0->im) + lc3_mul(x0->re, w0->re), 31 );
u1 = lc3_shr( lc3_mul(x1->re, w1->im) - lc3_mul(x1->im, w1->re), 31 );
float v0 = (x0->re * w0->im - x0->im * w0->re) * scale;
float v1 = (x1->im * w1->im + x1->re * w1->re) * scale;
v0 = lc3_shr( lc3_mul(x0->re, w0->im) - lc3_mul(x0->im, w0->re), 31 );
v1 = lc3_shr( lc3_mul(x1->im, w1->im) + lc3_mul(x1->re, w1->re), 31 );
*(y0++) = u0; *(y0++) = u1;
*(--y1) = v0; *(--y1) = v1;
@@ -295,7 +325,7 @@ LC3_HOT static void mdct_post_fft(const struct lc3_mdct_rot_def *def,
}
/**
* Pre-rotate IMDCT coefficients of N points, before FFT N/4 points FFT
* Pre-rotate and scale IMDCT of N points, before FFT N/4 points FFT
* def Size and twiddles factors
* x, y Input and output coefficients
*
@@ -304,57 +334,56 @@ LC3_HOT static void mdct_post_fft(const struct lc3_mdct_rot_def *def,
* to operate on FFT instead of IFFT
*/
LC3_HOT static void imdct_pre_fft(const struct lc3_mdct_rot_def *def,
const float *x, struct lc3_complex *y)
const lc3_intfloat_t *x, struct lc3_complex *y)
{
int n4 = def->n4;
const float *x0 = x, *x1 = x0 + 2*n4;
const lc3_intfloat_t *x0 = x, *x1 = x0 + 2*n4;
const struct lc3_complex *w0 = def->w, *w1 = w0 + n4;
struct lc3_complex *y0 = y, *y1 = y0 + n4;
while (x0 < x1) {
float u0 = *(x0++), u1 = *(--x1);
float v0 = *(x0++), v1 = *(--x1);
lc3_intfloat_t u0 = *(x0++), u1 = *(--x1);
lc3_intfloat_t v0 = *(x0++), v1 = *(--x1);
struct lc3_complex uw = *(w0++), vw = *(--w1);
(y0 )->re = - u0 * uw.re - u1 * uw.im;
(y0++)->im = - u1 * uw.re + u0 * uw.im;
(y0 )->re = lc3_shr( - lc3_mul(u0, uw.re) - lc3_mul(u1, uw.im), 31 );
(y0++)->im = lc3_shr( - lc3_mul(u1, uw.re) + lc3_mul(u0, uw.im), 31 );
(--y1)->re = - v1 * vw.re - v0 * vw.im;
( y1)->im = - v0 * vw.re + v1 * vw.im;
(--y1)->re = lc3_shr( - lc3_mul(v1, vw.re) - lc3_mul(v0, vw.im), 31 );
( y1)->im = lc3_shr( - lc3_mul(v0, vw.re) + lc3_mul(v1, vw.im), 31 );
}
}
/**
* Post-rotate FFT N/4 points coefficients, resulting IMDCT N points
* Post-rotate and scale FFT N/4 points, resulting IMDCT N points
* def Size and twiddles factors
* x, y Input and output coefficients
* scale Scale on output coefficients
*
* `x` and y` can be the same buffer
* The real and imaginary parts of `x` are swapped,
* to operate on FFT instead of IFFT
*/
LC3_HOT static void imdct_post_fft(const struct lc3_mdct_rot_def *def,
const struct lc3_complex *x, float *y, float scale)
const struct lc3_complex *x, lc3_intfloat_t *y)
{
int n4 = def->n4;
const struct lc3_complex *w0 = def->w, *w1 = w0 + n4;
const struct lc3_complex *x0 = x, *x1 = x0 + n4;
float *y0 = y, *y1 = y0 + 2*n4;
lc3_intfloat_t *y0 = y, *y1 = y0 + 2*n4;
while (x0 < x1) {
struct lc3_complex uz = *(x0++), vz = *(--x1);
struct lc3_complex uw = *(w0++), vw = *(--w1);
*(y0++) = (uz.re * uw.im - uz.im * uw.re) * scale;
*(--y1) = (uz.re * uw.re + uz.im * uw.im) * scale;
*(y0++) = lc3_shr( lc3_mul(uz.re, uw.im) - lc3_mul(uz.im, uw.re), 31 );
*(--y1) = lc3_shr( lc3_mul(uz.re, uw.re) + lc3_mul(uz.im, uw.im), 31 );
*(--y1) = (vz.re * vw.im - vz.im * vw.re) * scale;
*(y0++) = (vz.re * vw.re + vz.im * vw.im) * scale;
*(--y1) = lc3_shr( lc3_mul(vz.re, vw.im) - lc3_mul(vz.im, vw.re), 31 );
*(y0++) = lc3_shr( lc3_mul(vz.re, vw.re) + lc3_mul(vz.im, vw.im), 31 );
}
}
@@ -365,7 +394,7 @@ LC3_HOT static void imdct_post_fft(const struct lc3_mdct_rot_def *def,
* y, d Output samples and delayed ones
*/
LC3_HOT static void imdct_window(enum lc3_dt dt, enum lc3_srate sr,
const float *x, float *d, float *y)
const lc3_intfloat_t *x, lc3_intfloat_t *d, lc3_intfloat_t *y)
{
/* The full MDCT coefficients is given by symmetry :
* T[ 0 .. n/4-1] = -half[n/4-1 .. 0 ]
@@ -374,46 +403,47 @@ LC3_HOT static void imdct_window(enum lc3_dt dt, enum lc3_srate sr,
* T[3n/4 .. n-1] = half[n/2-1 .. n/4 ] */
int n4 = LC3_NS(dt, sr) >> 1, nd = LC3_ND(dt, sr);
const float *w2 = lc3_mdct_win[dt][sr], *w0 = w2 + 3*n4, *w1 = w0;
const lc3_intfloat_t *w2 = lc3_mdct_win[dt][sr], *w0 = w2 + 3*n4, *w1 = w0;
const float *x0 = d + nd-n4, *x1 = x0;
float *y0 = y + nd-n4, *y1 = y0, *y2 = d + nd, *y3 = d;
const lc3_intfloat_t *x0 = d + nd-n4, *x1 = x0;
lc3_intfloat_t *y0 = y + nd-n4, *y1 = y0, *y2 = d + nd, *y3 = d;
while (y0 > y) {
*(--y0) = *(--x0) - *(x ) * *(w1++);
*(y1++) = *(x1++) + *(x++) * *(--w0);
*(--y0) = *(--x0) - lc3_shr( lc3_mul(*(x ), *(w1++)), 30 );
*(y1++) = *(x1++) + lc3_shr( lc3_mul(*(x++), *(--w0)), 30 );
*(--y0) = *(--x0) - *(x ) * *(w1++);
*(y1++) = *(x1++) + *(x++) * *(--w0);
*(--y0) = *(--x0) - lc3_shr( lc3_mul(*(x ), *(w1++)), 30 );
*(y1++) = *(x1++) + lc3_shr( lc3_mul(*(x++), *(--w0)), 30 );
}
while (y1 < y + nd) {
*(y1++) = *(x1++) + *(x++) * *(--w0);
*(y1++) = *(x1++) + *(x++) * *(--w0);
*(y1++) = *(x1++) + lc3_shr( lc3_mul(*(x++), *(--w0)), 30 );
*(y1++) = *(x1++) + lc3_shr( lc3_mul(*(x++), *(--w0)), 30 );
}
while (y1 < y + 2*n4) {
*(y1++) = *(x ) * *(--w0);
*(--y2) = *(x++) * *(w2++);
*(y1++) = lc3_shr( lc3_mul(*(x ), *(--w0)), 30 );
*(--y2) = lc3_shr( lc3_mul(*(x++), *(w2++)), 30 );
*(y1++) = *(x ) * *(--w0);
*(--y2) = *(x++) * *(w2++);
*(y1++) = lc3_shr( lc3_mul(*(x ), *(--w0)), 30 );
*(--y2) = lc3_shr( lc3_mul(*(x++), *(w2++)), 30 );
}
while (y2 > y3) {
*(y3++) = *(x ) * *(--w0);
*(--y2) = *(x++) * *(w2++);
*(y3++) = lc3_shr( lc3_mul(*(x ), *(--w0)), 30 );
*(--y2) = lc3_shr( lc3_mul(*(x++), *(w2++)), 30 );
*(y3++) = *(x ) * *(--w0);
*(--y2) = *(x++) * *(w2++);
*(y3++) = lc3_shr( lc3_mul(*(x ), *(--w0)), 30 );
*(--y2) = lc3_shr( lc3_mul(*(x++), *(w2++)), 30 );
}
}
/**
* Forward MDCT transformation
*/
void lc3_mdct_forward(enum lc3_dt dt, enum lc3_srate sr,
enum lc3_srate sr_dst, const float *x, float *d, float *y)
void lc3_mdct_forward(
enum lc3_dt dt, enum lc3_srate sr, enum lc3_srate sr_dst,
const lc3_intfloat_t *x, lc3_intfloat_t *d, lc3_intfloat_t *y)
{
const struct lc3_mdct_rot_def *rot = lc3_mdct_rot[dt][sr];
int nf = LC3_NS(dt, sr_dst);
@@ -421,20 +451,23 @@ void lc3_mdct_forward(enum lc3_dt dt, enum lc3_srate sr,
struct lc3_complex buffer[ns/2];
struct lc3_complex *z = (struct lc3_complex *)y;
union { float *f; struct lc3_complex *z; } u = { .z = buffer };
union { lc3_intfloat_t *s; struct lc3_complex *z; } u = { .z = buffer };
mdct_window(dt, sr, x, d, u.f);
mdct_window(dt, sr, x, d, u.s);
mdct_pre_fft(rot, u.f, u.z);
mdct_pre_fft(rot, u.s, u.z);
u.z = fft(u.z, ns/2, u.z, z);
mdct_post_fft(rot, u.z, y, sqrtf( (2.f*nf) / (ns*ns) ));
mdct_post_fft(rot, u.z, y);
if (ns != nf) abort(); // TODO: Rescale
}
/**
* Inverse MDCT transformation
*/
void lc3_mdct_inverse(enum lc3_dt dt, enum lc3_srate sr,
enum lc3_srate sr_src, const float *x, float *d, float *y)
enum lc3_srate sr_src, const lc3_intfloat_t *x,
lc3_intfloat_t *d, lc3_intfloat_t *y)
{
const struct lc3_mdct_rot_def *rot = lc3_mdct_rot[dt][sr];
int nf = LC3_NS(dt, sr_src);
@@ -442,11 +475,13 @@ void lc3_mdct_inverse(enum lc3_dt dt, enum lc3_srate sr,
struct lc3_complex buffer[ns/2];
struct lc3_complex *z = (struct lc3_complex *)y;
union { float *f; struct lc3_complex *z; } u = { .z = buffer };
union { lc3_intfloat_t *s; struct lc3_complex *z; } u = { .z = buffer };
imdct_pre_fft(rot, x, z);
z = fft(z, ns/2, z, u.z);
imdct_post_fft(rot, z, u.f, sqrtf(2.f / nf));
imdct_post_fft(rot, z, u.s);
imdct_window(dt, sr, u.f, d, y);
imdct_window(dt, sr, u.s, d, y);
if (ns != nf) abort(); // TODO: Rescale
}

View File

@@ -38,8 +38,9 @@
*
* `x` and `y` can be the same buffer
*/
void lc3_mdct_forward(enum lc3_dt dt, enum lc3_srate sr,
enum lc3_srate sr_dst, const float *x, float *d, float *y);
void lc3_mdct_forward(
enum lc3_dt dt, enum lc3_srate sr, enum lc3_srate sr_dst,
const lc3_intfloat_t *x, lc3_intfloat_t *d, lc3_intfloat_t *y);
/**
* Inverse MDCT transformation
@@ -50,8 +51,9 @@ void lc3_mdct_forward(enum lc3_dt dt, enum lc3_srate sr,
*
* `x` and `y` can be the same buffer
*/
void lc3_mdct_inverse(enum lc3_dt dt, enum lc3_srate sr,
enum lc3_srate sr_src, const float *x, float *d, float *y);
void lc3_mdct_inverse(
enum lc3_dt dt, enum lc3_srate sr, enum lc3_srate sr_src,
const lc3_intfloat_t *x, lc3_intfloat_t *d, lc3_intfloat_t *y);
#endif /* __LC3_MDCT_H */

257
src/sns.c
View File

@@ -34,85 +34,91 @@
*/
static const float dct16_m[16][16] = {
{ 2.50000000e-01, 3.51850934e-01, 3.46759961e-01, 3.38329500e-01,
3.26640741e-01, 3.11806253e-01, 2.93968901e-01, 2.73300467e-01,
2.50000000e-01, 2.24291897e-01, 1.96423740e-01, 1.66663915e-01,
1.35299025e-01, 1.02631132e-01, 6.89748448e-02, 3.46542923e-02 },
#define __C4(a, b, c, d) \
LC3_INTFLOAT_C(a, 31), LC3_INTFLOAT_C(b, 31), \
LC3_INTFLOAT_C(c, 31), LC3_INTFLOAT_C(d, 31)
{ 2.50000000e-01, 3.38329500e-01, 2.93968901e-01, 2.24291897e-01,
1.35299025e-01, 3.46542923e-02, -6.89748448e-02, -1.66663915e-01,
-2.50000000e-01, -3.11806253e-01, -3.46759961e-01, -3.51850934e-01,
-3.26640741e-01, -2.73300467e-01, -1.96423740e-01, -1.02631132e-01 },
{ __C4( 2.50000000e-01, 3.51850934e-01, 3.46759961e-01, 3.38329500e-01),
__C4( 3.26640741e-01, 3.11806253e-01, 2.93968901e-01, 2.73300467e-01),
__C4( 2.50000000e-01, 2.24291897e-01, 1.96423740e-01, 1.66663915e-01),
__C4( 1.35299025e-01, 1.02631132e-01, 6.89748448e-02, 3.46542923e-02) },
{ 2.50000000e-01, 3.11806253e-01, 1.96423740e-01, 3.46542923e-02,
-1.35299025e-01, -2.73300467e-01, -3.46759961e-01, -3.38329500e-01,
-2.50000000e-01, -1.02631132e-01, 6.89748448e-02, 2.24291897e-01,
3.26640741e-01, 3.51850934e-01, 2.93968901e-01, 1.66663915e-01 },
{ __C4( 2.50000000e-01, 3.38329500e-01, 2.93968901e-01, 2.24291897e-01),
__C4( 1.35299025e-01, 3.46542923e-02, -6.89748448e-02, -1.66663915e-01),
__C4(-2.50000000e-01, -3.11806253e-01, -3.46759961e-01, -3.51850934e-01),
__C4(-3.26640741e-01, -2.73300467e-01, -1.96423740e-01, -1.02631132e-01) },
{ 2.50000000e-01, 2.73300467e-01, 6.89748448e-02, -1.66663915e-01,
-3.26640741e-01, -3.38329500e-01, -1.96423740e-01, 3.46542923e-02,
2.50000000e-01, 3.51850934e-01, 2.93968901e-01, 1.02631132e-01,
-1.35299025e-01, -3.11806253e-01, -3.46759961e-01, -2.24291897e-01 },
{ __C4( 2.50000000e-01, 3.11806253e-01, 1.96423740e-01, 3.46542923e-02),
__C4(-1.35299025e-01, -2.73300467e-01, -3.46759961e-01, -3.38329500e-01),
__C4(-2.50000000e-01, -1.02631132e-01, 6.89748448e-02, 2.24291897e-01),
__C4( 3.26640741e-01, 3.51850934e-01, 2.93968901e-01, 1.66663915e-01) },
{ 2.50000000e-01, 2.24291897e-01, -6.89748448e-02, -3.11806253e-01,
-3.26640741e-01, -1.02631132e-01, 1.96423740e-01, 3.51850934e-01,
2.50000000e-01, -3.46542923e-02, -2.93968901e-01, -3.38329500e-01,
-1.35299025e-01, 1.66663915e-01, 3.46759961e-01, 2.73300467e-01 },
{ __C4( 2.50000000e-01, 2.73300467e-01, 6.89748448e-02, -1.66663915e-01),
__C4(-3.26640741e-01, -3.38329500e-01, -1.96423740e-01, 3.46542923e-02),
__C4( 2.50000000e-01, 3.51850934e-01, 2.93968901e-01, 1.02631132e-01),
__C4(-1.35299025e-01, -3.11806253e-01, -3.46759961e-01, -2.24291897e-01) },
{ 2.50000000e-01, 1.66663915e-01, -1.96423740e-01, -3.51850934e-01,
-1.35299025e-01, 2.24291897e-01, 3.46759961e-01, 1.02631132e-01,
-2.50000000e-01, -3.38329500e-01, -6.89748448e-02, 2.73300467e-01,
3.26640741e-01, 3.46542923e-02, -2.93968901e-01, -3.11806253e-01 },
{ __C4( 2.50000000e-01, 2.24291897e-01, -6.89748448e-02, -3.11806253e-01),
__C4(-3.26640741e-01, -1.02631132e-01, 1.96423740e-01, 3.51850934e-01),
__C4( 2.50000000e-01, -3.46542923e-02, -2.93968901e-01, -3.38329500e-01),
__C4(-1.35299025e-01, 1.66663915e-01, 3.46759961e-01, 2.73300467e-01) },
{ 2.50000000e-01, 1.02631132e-01, -2.93968901e-01, -2.73300467e-01,
1.35299025e-01, 3.51850934e-01, 6.89748448e-02, -3.11806253e-01,
-2.50000000e-01, 1.66663915e-01, 3.46759961e-01, 3.46542923e-02,
-3.26640741e-01, -2.24291897e-01, 1.96423740e-01, 3.38329500e-01 },
{ __C4( 2.50000000e-01, 1.66663915e-01, -1.96423740e-01, -3.51850934e-01),
__C4(-1.35299025e-01, 2.24291897e-01, 3.46759961e-01, 1.02631132e-01),
__C4(-2.50000000e-01, -3.38329500e-01, -6.89748448e-02, 2.73300467e-01),
__C4( 3.26640741e-01, 3.46542923e-02, -2.93968901e-01, -3.11806253e-01) },
{ 2.50000000e-01, 3.46542923e-02, -3.46759961e-01, -1.02631132e-01,
3.26640741e-01, 1.66663915e-01, -2.93968901e-01, -2.24291897e-01,
2.50000000e-01, 2.73300467e-01, -1.96423740e-01, -3.11806253e-01,
1.35299025e-01, 3.38329500e-01, -6.89748448e-02, -3.51850934e-01 },
{ __C4( 2.50000000e-01, 1.02631132e-01, -2.93968901e-01, -2.73300467e-01),
__C4( 1.35299025e-01, 3.51850934e-01, 6.89748448e-02, -3.11806253e-01),
__C4(-2.50000000e-01, 1.66663915e-01, 3.46759961e-01, 3.46542923e-02),
__C4(-3.26640741e-01, -2.24291897e-01, 1.96423740e-01, 3.38329500e-01) },
{ 2.50000000e-01, -3.46542923e-02, -3.46759961e-01, 1.02631132e-01,
3.26640741e-01, -1.66663915e-01, -2.93968901e-01, 2.24291897e-01,
2.50000000e-01, -2.73300467e-01, -1.96423740e-01, 3.11806253e-01,
1.35299025e-01, -3.38329500e-01, -6.89748448e-02, 3.51850934e-01 },
{ __C4( 2.50000000e-01, 3.46542923e-02, -3.46759961e-01, -1.02631132e-01),
__C4( 3.26640741e-01, 1.66663915e-01, -2.93968901e-01, -2.24291897e-01),
__C4( 2.50000000e-01, 2.73300467e-01, -1.96423740e-01, -3.11806253e-01),
__C4( 1.35299025e-01, 3.38329500e-01, -6.89748448e-02, -3.51850934e-01) },
{ 2.50000000e-01, -1.02631132e-01, -2.93968901e-01, 2.73300467e-01,
1.35299025e-01, -3.51850934e-01, 6.89748448e-02, 3.11806253e-01,
-2.50000000e-01, -1.66663915e-01, 3.46759961e-01, -3.46542923e-02,
-3.26640741e-01, 2.24291897e-01, 1.96423740e-01, -3.38329500e-01 },
{ __C4( 2.50000000e-01, -3.46542923e-02, -3.46759961e-01, 1.02631132e-01),
__C4( 3.26640741e-01, -1.66663915e-01, -2.93968901e-01, 2.24291897e-01),
__C4( 2.50000000e-01, -2.73300467e-01, -1.96423740e-01, 3.11806253e-01),
__C4( 1.35299025e-01, -3.38329500e-01, -6.89748448e-02, 3.51850934e-01) },
{ 2.50000000e-01, -1.66663915e-01, -1.96423740e-01, 3.51850934e-01,
-1.35299025e-01, -2.24291897e-01, 3.46759961e-01, -1.02631132e-01,
-2.50000000e-01, 3.38329500e-01, -6.89748448e-02, -2.73300467e-01,
3.26640741e-01, -3.46542923e-02, -2.93968901e-01, 3.11806253e-01 },
{ __C4( 2.50000000e-01, -1.02631132e-01, -2.93968901e-01, 2.73300467e-01),
__C4( 1.35299025e-01, -3.51850934e-01, 6.89748448e-02, 3.11806253e-01),
__C4(-2.50000000e-01, -1.66663915e-01, 3.46759961e-01, -3.46542923e-02),
__C4(-3.26640741e-01, 2.24291897e-01, 1.96423740e-01, -3.38329500e-01) },
{ 2.50000000e-01, -2.24291897e-01, -6.89748448e-02, 3.11806253e-01,
-3.26640741e-01, 1.02631132e-01, 1.96423740e-01, -3.51850934e-01,
2.50000000e-01, 3.46542923e-02, -2.93968901e-01, 3.38329500e-01,
-1.35299025e-01, -1.66663915e-01, 3.46759961e-01, -2.73300467e-01 },
{ __C4( 2.50000000e-01, -1.66663915e-01, -1.96423740e-01, 3.51850934e-01),
__C4(-1.35299025e-01, -2.24291897e-01, 3.46759961e-01, -1.02631132e-01),
__C4(-2.50000000e-01, 3.38329500e-01, -6.89748448e-02, -2.73300467e-01),
__C4( 3.26640741e-01, -3.46542923e-02, -2.93968901e-01, 3.11806253e-01) },
{ 2.50000000e-01, -2.73300467e-01, 6.89748448e-02, 1.66663915e-01,
-3.26640741e-01, 3.38329500e-01, -1.96423740e-01, -3.46542923e-02,
2.50000000e-01, -3.51850934e-01, 2.93968901e-01, -1.02631132e-01,
-1.35299025e-01, 3.11806253e-01, -3.46759961e-01, 2.24291897e-01 },
{ __C4( 2.50000000e-01, -2.24291897e-01, -6.89748448e-02, 3.11806253e-01),
__C4(-3.26640741e-01, 1.02631132e-01, 1.96423740e-01, -3.51850934e-01),
__C4( 2.50000000e-01, 3.46542923e-02, -2.93968901e-01, 3.38329500e-01),
__C4(-1.35299025e-01, -1.66663915e-01, 3.46759961e-01, -2.73300467e-01) },
{ 2.50000000e-01, -3.11806253e-01, 1.96423740e-01, -3.46542923e-02,
-1.35299025e-01, 2.73300467e-01, -3.46759961e-01, 3.38329500e-01,
-2.50000000e-01, 1.02631132e-01, 6.89748448e-02, -2.24291897e-01,
3.26640741e-01, -3.51850934e-01, 2.93968901e-01, -1.66663915e-01 },
{ __C4( 2.50000000e-01, -2.73300467e-01, 6.89748448e-02, 1.66663915e-01),
__C4(-3.26640741e-01, 3.38329500e-01, -1.96423740e-01, -3.46542923e-02),
__C4( 2.50000000e-01, -3.51850934e-01, 2.93968901e-01, -1.02631132e-01),
__C4(-1.35299025e-01, 3.11806253e-01, -3.46759961e-01, 2.24291897e-01) },
{ 2.50000000e-01, -3.38329500e-01, 2.93968901e-01, -2.24291897e-01,
1.35299025e-01, -3.46542923e-02, -6.89748448e-02, 1.66663915e-01,
-2.50000000e-01, 3.11806253e-01, -3.46759961e-01, 3.51850934e-01,
-3.26640741e-01, 2.73300467e-01, -1.96423740e-01, 1.02631132e-01 },
{ __C4( 2.50000000e-01, -3.11806253e-01, 1.96423740e-01, -3.46542923e-02),
__C4(-1.35299025e-01, 2.73300467e-01, -3.46759961e-01, 3.38329500e-01),
__C4(-2.50000000e-01, 1.02631132e-01, 6.89748448e-02, -2.24291897e-01),
__C4( 3.26640741e-01, -3.51850934e-01, 2.93968901e-01, -1.66663915e-01) },
{ 2.50000000e-01, -3.51850934e-01, 3.46759961e-01, -3.38329500e-01,
3.26640741e-01, -3.11806253e-01, 2.93968901e-01, -2.73300467e-01,
2.50000000e-01, -2.24291897e-01, 1.96423740e-01, -1.66663915e-01,
1.35299025e-01, -1.02631132e-01, 6.89748448e-02, -3.46542923e-02 },
{ __C4( 2.50000000e-01, -3.38329500e-01, 2.93968901e-01, -2.24291897e-01),
__C4( 1.35299025e-01, -3.46542923e-02, -6.89748448e-02, 1.66663915e-01),
__C4(-2.50000000e-01, 3.11806253e-01, -3.46759961e-01, 3.51850934e-01),
__C4(-3.26640741e-01, 2.73300467e-01, -1.96423740e-01, 1.02631132e-01) },
{ __C4( 2.50000000e-01, -3.51850934e-01, 3.46759961e-01, -3.38329500e-01),
__C4( 3.26640741e-01, -3.11806253e-01, 2.93968901e-01, -2.73300467e-01),
__C4( 2.50000000e-01, -2.24291897e-01, 1.96423740e-01, -1.66663915e-01),
__C4( 1.35299025e-01, -1.02631132e-01, 6.89748448e-02, -3.46542923e-02) },
#undef __C4
};
@@ -124,18 +130,31 @@ LC3_HOT static void dct16_forward(const float *x, float *y)
{
for (int i = 0, j; i < 16; i++)
for (y[i] = 0, j = 0; j < 16; j++)
#ifdef CONFIG_FIXED_POINT
y[i] += x[j] * ldexpf(dct16_m[j][i], -31);
#else
y[i] += x[j] * dct16_m[j][i];
#endif
}
/**
* Inverse DCT-16 transformation
* x, y Input and output 16 values
*/
LC3_HOT static void dct16_inverse(const float *x, float *y)
LC3_HOT static void dct16_inverse(const lc3_intfloat_t *x, lc3_intfloat_t *y)
{
#ifdef CONFIG_FIXED_POINT
for (int i = 0, j; i < 16; i++) {
int64_t yi = 0;
for (j = 0; j < 16; j++)
yi += x[j] * dct16_m[i][j];
y[i] = lc3_shr(yi, 31);
}
#else
for (int i = 0, j; i < 16; i++)
for (y[i] = 0, j = 0; j < 16; j++)
y[i] += x[j] * dct16_m[i][j];
#endif
}
@@ -351,13 +370,18 @@ LC3_HOT static void resolve_codebooks(
*lfcb_idx = *hfcb_idx = 0;
for (int icb = 0; icb < 32; icb++) {
const float *lfcb = lc3_sns_lfcb[icb];
const float *hfcb = lc3_sns_hfcb[icb];
const lc3_intfloat_t *lfcb = lc3_sns_lfcb[icb];
const lc3_intfloat_t *hfcb = lc3_sns_hfcb[icb];
float dlfcb = 0, dhfcb = 0;
for (int i = 0; i < 8; i++) {
#ifdef CONFIG_FIXED_POINT
dlfcb += (scf[ i] - ldexpf(lfcb[i], -24)) * (scf[ i] - ldexpf(lfcb[i], -24));
dhfcb += (scf[8+i] - ldexpf(hfcb[i], -24)) * (scf[8+i] - ldexpf(hfcb[i], -24));
#else
dlfcb += (scf[ i] - lfcb[i]) * (scf[ i] - lfcb[i]);
dhfcb += (scf[8+i] - hfcb[i]) * (scf[8+i] - hfcb[i]);
#endif
}
if (icb == 0 || dlfcb < dlfcb_max)
@@ -371,15 +395,15 @@ LC3_HOT static void resolve_codebooks(
/**
* Unit energy normalize pulse configuration
* c Pulse configuration
* cn Normalized pulse configuration
* cn Normalized pulse configuration (8.24)
*/
LC3_HOT static void normalize(const int *c, float *cn)
LC3_HOT static void normalize(const int *c, lc3_intfloat_t *cn)
{
int c2_sum = 0;
for (int i = 0; i < 16; i++)
c2_sum += c[i] * c[i];
float c_norm = 1.f / sqrtf(c2_sum);
lc3_intfloat_t c_norm = lc3_rsqrt(c2_sum, 24);
for (int i = 0; i < 16; i++)
cn[i] = c[i] * c_norm;
@@ -425,13 +449,18 @@ LC3_HOT static void quantize(const float *scf, int lfcb_idx, int hfcb_idx,
{
/* --- Residual --- */
const float *lfcb = lc3_sns_lfcb[lfcb_idx];
const float *hfcb = lc3_sns_hfcb[hfcb_idx];
const lc3_intfloat_t *lfcb = lc3_sns_lfcb[lfcb_idx];
const lc3_intfloat_t *hfcb = lc3_sns_hfcb[hfcb_idx];
float r[16], x[16];
for (int i = 0; i < 8; i++) {
#ifdef CONFIG_FIXED_POINT
r[ i] = scf[ i] - ldexpf(lfcb[i], -24);
r[8+i] = scf[8+i] - ldexpf(hfcb[i], -24);
#else
r[ i] = scf[ i] - lfcb[i];
r[8+i] = scf[8+i] - hfcb[i];
#endif
}
dct16_forward(r, x);
@@ -500,8 +529,21 @@ LC3_HOT static void quantize(const float *scf, int lfcb_idx, int hfcb_idx,
for (int i = 0; i < 4; i++)
c[i][j] = x[j] < 0 ? -c[i][j] : c[i][j];
#ifdef CONFIG_FIXED_POINT
lc3_intfloat_t __cn[4][16];
for (int i = 0; i < 4; i++)
normalize(c[i], __cn[i]);
for (int j = 0; j < 16; j++)
for (int i = 0; i < 4; i++)
cn[i][j] = ldexpf(__cn[i][j], -24);
#else
for (int i = 0; i < 4; i++)
normalize(c[i], cn[i]);
#endif
/* --- Determe shape & gain index ---
* Search the Mean Square Error, within (shape, gain) combinations */
@@ -515,7 +557,11 @@ LC3_HOT static void quantize(const float *scf, int lfcb_idx, int hfcb_idx,
int cgain_idx = 0;
for (int ig = 0; ig < cgains->count; ig++) {
#ifdef CONFIG_FIXED_POINT
float g = ldexpf(cgains->v[ig], -12);
#else
float g = cgains->v[ig];
#endif
float mse = 0;
for (int i = 0; i < 16; i++)
@@ -542,19 +588,19 @@ LC3_HOT static void quantize(const float *scf, int lfcb_idx, int hfcb_idx,
* scf Return unquantized scale factors
*/
LC3_HOT static void unquantize(int lfcb_idx, int hfcb_idx,
const float *c, int shape, int gain, float *scf)
const lc3_intfloat_t *c, int shape, int gain, lc3_intfloat_t *scf)
{
const float *lfcb = lc3_sns_lfcb[lfcb_idx];
const float *hfcb = lc3_sns_hfcb[hfcb_idx];
float g = lc3_sns_vq_gains[shape].v[gain];
const lc3_intfloat_t *lfcb = lc3_sns_lfcb[lfcb_idx];
const lc3_intfloat_t *hfcb = lc3_sns_hfcb[hfcb_idx];
lc3_intfloat_t g = lc3_sns_vq_gains[shape].v[gain];
dct16_inverse(c, scf);
for (int i = 0; i < 8; i++)
scf[i] = lfcb[i] + g * scf[i];
scf[i] = lfcb[i] + lc3_shr(lc3_mul(g, scf[i]), 12);
for (int i = 8; i < 16; i++)
scf[i] = hfcb[i-8] + g * scf[i];
scf[i] = hfcb[i-8] + lc3_shr(lc3_mul(g, scf[i]), 12);
}
/**
@@ -675,17 +721,27 @@ static void deenumerate(int shape,
*
* `x` and `y` can be the same buffer
*/
LC3_HOT static void spectral_shaping(enum lc3_dt dt, enum lc3_srate sr,
const float *scf_q, bool inv, const float *x, float *y)
LC3_HOT static void spectral_shaping(
enum lc3_dt dt, enum lc3_srate sr, const lc3_intfloat_t *scf_q, bool inv,
const lc3_intfloat_t *x, lc3_intfloat_t *y)
{
/* --- Interpolate scale factors --- */
float scf[LC3_NUM_BANDS];
float s0, s1 = inv ? -scf_q[0] : scf_q[0];
lc3_intfloat_t scf[LC3_NUM_BANDS];
lc3_intfloat_t s0, s1 = inv ? -scf_q[0] : scf_q[0];
scf[0] = scf[1] = s1;
for (int i = 0; i < 15; i++) {
s0 = s1, s1 = inv ? -scf_q[i+1] : scf_q[i+1];
#ifdef CONFIG_FIXED_POINT
scf[4*i+2] = s0 + lc3_shr(1 * (s1 - s0), 3);
scf[4*i+3] = s0 + lc3_shr(3 * (s1 - s0), 3);
scf[4*i+4] = s0 + lc3_shr(5 * (s1 - s0), 3);
scf[4*i+5] = s0 + lc3_shr(7 * (s1 - s0), 3);
}
scf[62] = s1 + lc3_shr(1 * (s1 - s0), 3);
scf[63] = s1 + lc3_shr(3 * (s1 - s0), 3);
#else
scf[4*i+2] = s0 + 0.125f * (s1 - s0);
scf[4*i+3] = s0 + 0.375f * (s1 - s0);
scf[4*i+4] = s0 + 0.625f * (s1 - s0);
@@ -693,25 +749,30 @@ LC3_HOT static void spectral_shaping(enum lc3_dt dt, enum lc3_srate sr,
}
scf[62] = s1 + 0.125f * (s1 - s0);
scf[63] = s1 + 0.375f * (s1 - s0);
#endif
int nb = LC3_MIN(lc3_band_lim[dt][sr][LC3_NUM_BANDS], LC3_NUM_BANDS);
int n2 = LC3_NUM_BANDS - nb;
for (int i2 = 0; i2 < n2; i2++)
#ifdef CONFIG_FIXED_POINT
scf[i2] = lc3_shr(scf[2*i2] + scf[2*i2+1], 1);
#else
scf[i2] = 0.5f * (scf[2*i2] + scf[2*i2+1]);
#endif
if (n2 > 0)
memmove(scf + n2, scf + 2*n2, (nb - n2) * sizeof(float));
memmove(scf + n2, scf + 2*n2, (nb - n2) * sizeof(lc3_intfloat_t));
/* --- Spectral shaping --- */
const int *lim = lc3_band_lim[dt][sr];
for (int i = 0, ib = 0; ib < nb; ib++) {
float g_sns = fast_exp2f(-scf[ib]);
lc3_intfloat_t g_sns = fast_exp2f(-scf[ib]);
for ( ; i < lim[ib+1]; i++)
y[i] = x[i] * g_sns;
y[i] = lc3_shr(lc3_mul(x[i], g_sns), 23);
}
}
@@ -744,22 +805,44 @@ void lc3_sns_analyze(enum lc3_dt dt, enum lc3_srate sr,
quantize(scf, data->lfcb, data->hfcb,
c, cn, &data->shape, &data->gain);
#ifdef CONFIG_FIXED_POINT
int32_t __scf[16], __cn[16];
for (int i = 0; i < 16; i++) __cn[i] = ldexpf(cn[data->shape][i], 24);
unquantize(data->lfcb, data->hfcb,
__cn, data->shape, data->gain, __scf);
for (int i = 0; i < 16; i++) scf[i] = ldexpf(__scf[i], -24);
#else
unquantize(data->lfcb, data->hfcb,
cn[data->shape], data->shape, data->gain, scf);
#endif
enumerate(data->shape, c[data->shape],
&data->idx_a, &data->ls_a, &data->idx_b, &data->ls_b);
#ifdef CONFIG_FIXED_POINT
int ne = LC3_NE(dt, sr);
int32_t __x[ne], __y[ne];
for (int i = 0; i < 16; i++) __scf[i] = ldexpf(scf[i], 24);
for (int i = 0; i < ne; i++) __x[i] = ldexpf(x[i], 8);
spectral_shaping(dt, sr, __scf, false, __x, __y);
for (int i = 0; i < ne; i++) y[i] = ldexpf(__y[i], -8);
#else
spectral_shaping(dt, sr, scf, false, x, y);
#endif
}
/**
* SNS synthesis
*/
void lc3_sns_synthesize(enum lc3_dt dt, enum lc3_srate sr,
const lc3_sns_data_t *data, const float *x, float *y)
const lc3_sns_data_t *data, const lc3_intfloat_t *x, lc3_intfloat_t *y)
{
float scf[16], cn[16];
lc3_intfloat_t scf[16], cn[16];
int c[16];
deenumerate(data->shape,

View File

@@ -97,7 +97,7 @@ int lc3_sns_get_data(lc3_bits_t *bits, lc3_sns_data_t *data);
* `x` and `y` can be the same buffer
*/
void lc3_sns_synthesize(enum lc3_dt dt, enum lc3_srate sr,
const lc3_sns_data_t *data, const float *x, float *y);
const lc3_sns_data_t *data, const lc3_intfloat_t *x, lc3_intfloat_t *y);
#endif /* __LC3_SNS_H */

File diff suppressed because it is too large Load Diff

View File

@@ -35,7 +35,7 @@ extern const struct lc3_fft_bf3_twiddles *lc3_fft_twiddles_bf3[];
extern const struct lc3_fft_bf2_twiddles *lc3_fft_twiddles_bf2[][3];
extern const struct lc3_mdct_rot_def *lc3_mdct_rot[LC3_NUM_DT][LC3_NUM_SRATE];
extern const float *lc3_mdct_win[LC3_NUM_DT][LC3_NUM_SRATE];
extern const lc3_intfloat_t *lc3_mdct_win[LC3_NUM_DT][LC3_NUM_SRATE];
/**
@@ -51,11 +51,11 @@ extern const int lc3_band_lim[LC3_NUM_DT][LC3_NUM_SRATE][LC3_NUM_BANDS+1];
* SNS Quantization
*/
extern const float lc3_sns_lfcb[32][8];
extern const float lc3_sns_hfcb[32][8];
extern const lc3_intfloat_t lc3_sns_lfcb[32][8];
extern const lc3_intfloat_t lc3_sns_hfcb[32][8];
struct lc3_sns_vq_gains {
int count; const float *v;
int count; const lc3_intfloat_t *v;
};
extern const struct lc3_sns_vq_gains lc3_sns_vq_gains[4];

View File

@@ -28,27 +28,52 @@ def fast_exp2(x, p):
return np.power(y.astype(np.float32), 16)
def fast_exp2_fxp(x, p):
c = np.array([ p[0] * 2**59, p[1] * 2**52, p[2] * 2**45,
p[3] * 2**38, p[4] * 2**31 ], dtype=np.int32)
x = (x * 2**24).astype(np.int32)
y = ((x.astype(np.int64) * ( c[0]) + (1 << 30)) >> 31).astype(np.int32)
y = ((x.astype(np.int64) * (y + c[1]) + (1 << 30)) >> 31).astype(np.int32)
y = ((x.astype(np.int64) * (y + c[2]) + (1 << 30)) >> 31).astype(np.int32)
y = ((x.astype(np.int64) * (y + c[3]) + (1 << 30)) >> 31).astype(np.int32)
y = ((x.astype(np.int64) * (y + c[4]) + (1 << 30)) >> 31).astype(np.int32)
y = y + (1 << 24)
y = (((y.astype(np.int64) * y) + (1 << 23)) >> 24).astype(np.int32)
y = (((y.astype(np.int64) * y) + (1 << 23)) >> 24).astype(np.int32)
y = (((y.astype(np.int64) * y) + (1 << 23)) >> 24).astype(np.int32)
y = (((y.astype(np.int64) * y) + (1 << 24)) >> 25).astype(np.int32)
return y.astype(np.float32) * 2**-23
def approx_exp2():
x = np.arange(-8, 8, step=1e-3)
p = np.polyfit(x, ((2 ** (x/16)) - 1) / x, 4)
y = [ fast_exp2(x[i], p) for i in range(len(x)) ]
e = np.abs(y - 2**x) / (2 ** x)
p = np.polyfit(x, ((2 ** (x/16)) - 1) / x, 4)
y0 = [ fast_exp2(x[i], p) for i in range(len(x)) ]
y1 = [ fast_exp2_fxp(x[i], p) for i in range(len(x)) ]
e0 = np.abs(y0 - 2**x) / (2 ** x)
e1 = np.abs(y1 - 2**x) / (2 ** x)
print('{{ {:14.8e}, {:14.8e}, {:14.8e}, {:14.8e}, {:14.8e} }}'
.format(p[0], p[1], p[2], p[3], p[4]))
print('Max relative error: ', np.max(e))
print('Max RMS error: ', np.sqrt(np.mean(e ** 2)))
print('Max relative error: ', np.max(e0))
print('Max RMS error: ', np.sqrt(np.mean(e0 ** 2)))
if False:
fig, (ax1, ax2) = plt.subplots(2)
ax1.plot(x, 2**x, label='Reference')
ax1.plot(x, y, label='Approximation')
ax1.plot(x, y0, label='Floating point Approximation')
ax1.plot(x, y1, label='Fixed point Approximation')
ax1.legend()
ax2.plot(x, e, label='Relative Error')
ax2.plot(x, e0, label='Floating point Relative Error')
ax2.plot(x, e1, label='Fixed point Relative Error')
ax2.legend()
plt.show()

View File

@@ -104,8 +104,8 @@ def mdct_fft_twiddles():
kv = -2 * np.pi * np.arange(n // 2) / n
for (i, k) in enumerate(kv):
print('{{ {:14.7e}, {:14.7e} }},'.format(np.cos(k), np.sin(k)),
end = '\n' if i%2 == 1 else ' ')
print('{{ {:14.7e}, {:14.7e} }},'.format(
np.cos(k) / np.sqrt(2), np.sin(k) / np.sqrt(2)))
for n in (15, 45):
@@ -115,7 +115,8 @@ def mdct_fft_twiddles():
for k in kv:
print(('{{ {{ {:14.7e}, {:14.7e} }},' +
' {{ {:14.7e}, {:14.7e} }} }},').format(
np.cos(k), np.sin(k), np.cos(2*k), np.sin(2*k)))
np.cos( k) / np.sqrt(3), np.sin( k) / np.sqrt(3),
np.cos(2*k) / np.sqrt(3), np.sin(2*k) / np.sqrt(3)))
def mdct_rot_twiddles():
@@ -126,8 +127,7 @@ def mdct_rot_twiddles():
kv = 2 * np.pi * (np.arange(n // 4) + 1/8) / n
for (i, k) in enumerate(kv):
print('{{ {:14.7e}, {:14.7e} }},'.format(np.cos(k), np.sin(k)),
end = '\n' if i%2 == 1 else ' ')
print('{{ {:14.7e}, {:14.7e} }},'.format(np.cos(k), np.sin(k)))
def mdct_scaling():

View File

@@ -97,7 +97,7 @@ def check_forward_unit(rng, dt, sr):
nd = T.ND[dt][sr]
ok = True
x = (2 * rng.random(ns)) - 1
x = ( (2 * rng.random(ns)) - 1 ) * 2**15
y = [ None ] * 2
y_c = [ None ] * 2
@@ -109,8 +109,8 @@ def check_forward_unit(rng, dt, sr):
(y_c[0], d_c) = lc3.mdct_forward(dt, sr, x, np.zeros(nd))
y_c[1] = lc3.mdct_forward(dt, sr, x, d_c)[0]
ok = ok and np.amax(np.abs(y[0] - y_c[0])) < 1e-5
ok = ok and np.amax(np.abs(y[1] - y_c[1])) < 1e-5
ok = ok and np.amax(np.abs(y[0] - y_c[0])) < 1e-1
ok = ok and np.amax(np.abs(y[1] - y_c[1])) < 1e-1
return ok
@@ -137,7 +137,7 @@ def check_inverse_unit(rng, dt, sr):
nd = [ (23 * ns) // 30, (5 * ns) // 8 ][dt]
ok = True
x = (2 * rng.random(ns)) - 1
x = ( (2 * rng.random(ns)) - 1 ) * 2**15
y = [ None ] * 2
y_c = [ None ] * 2
@@ -149,8 +149,8 @@ def check_inverse_unit(rng, dt, sr):
(y_c[0], d_c) = lc3.mdct_inverse(dt, sr, x, np.zeros(nd))
y_c[1] = lc3.mdct_inverse(dt, sr, x, d_c)[0]
ok = ok and np.amax(np.abs(y[0] - y_c[0])) < 1e-5
ok = ok and np.amax(np.abs(y[1] - y_c[1])) < 1e-5
ok = ok and np.amax(np.abs(y[0] - y_c[0])) < 1e-1
ok = ok and np.amax(np.abs(y[1] - y_c[1])) < 1e-1
return ok

View File

@@ -28,7 +28,7 @@ static PyObject *mdct_forward_py(PyObject *m, PyObject *args)
PyObject *x_obj, *xd_obj, *y_obj, *d_obj;
enum lc3_dt dt;
enum lc3_srate sr;
float *x, *xd, *y, *d;
lc3_intfloat_t *x, *xd, *y, *d;
if (!PyArg_ParseTuple(args, "iiOO", &dt, &sr, &x_obj, &xd_obj))
return NULL;
@@ -45,8 +45,18 @@ static PyObject *mdct_forward_py(PyObject *m, PyObject *args)
memcpy(d, xd, nd * sizeof(float));
#ifdef CONFIG_FIXED_POINT
for (int i = 0; i < ns; i++) x[i] = ldexpf(((float *)x)[i], 8);
for (int i = 0; i < nd; i++) d[i] = ldexpf(((float *)d)[i], 8);
#endif
lc3_mdct_forward(dt, sr, sr, x, d, y);
#ifdef CONFIG_FIXED_POINT
for (int i = 0; i < nd; i++) ((float *)d)[i] = ldexpf(d[i], -8);
for (int i = 0; i < ns; i++) ((float *)y)[i] = ldexpf(y[i], -8);
#endif
return Py_BuildValue("NN", y_obj, d_obj);
}
@@ -55,7 +65,7 @@ static PyObject *mdct_inverse_py(PyObject *m, PyObject *args)
PyObject *x_obj, *xd_obj, *d_obj, *y_obj;
enum lc3_dt dt;
enum lc3_srate sr;
float *x, *xd, *d, *y;
lc3_intfloat_t *x, *xd, *d, *y;
if (!PyArg_ParseTuple(args, "iiOO", &dt, &sr, &x_obj, &xd_obj))
return NULL;
@@ -72,8 +82,18 @@ static PyObject *mdct_inverse_py(PyObject *m, PyObject *args)
memcpy(d, xd, nd * sizeof(float));
#ifdef CONFIG_FIXED_POINT
for (int i = 0; i < ns; i++) x[i] = ldexpf(((float *)x)[i], 8);
for (int i = 0; i < nd; i++) d[i] = ldexpf(((float *)d)[i], 8);
#endif
lc3_mdct_inverse(dt, sr, sr, x, d, y);
#ifdef CONFIG_FIXED_POINT
for (int i = 0; i < nd; i++) ((float *)d)[i] = ldexpf(d[i], -8);
for (int i = 0; i < ns; i++) ((float *)y)[i] = ldexpf(y[i], -8);
#endif
return Py_BuildValue("NN", y_obj, d_obj);
}

View File

@@ -535,7 +535,7 @@ def check_analysis_appendix_c(dt):
ok = ok and np.amax(np.abs(scf_q - C.SCF_Q[dt][i])) < 1e-5
x = lc3.sns_spectral_shaping(dt, sr, C.SCF_Q[dt][i], False, C.X[dt][i])
ok = ok and np.amax(np.abs(1 - x/C.X_S[dt][i])) < 1e-5
ok = ok and np.amax(np.abs(x - C.X_S[dt][i])) < 1e-1
(x, data) = lc3.sns_analyze(dt, sr, C.E_B[dt][i], False, C.X[dt][i])
ok = ok and data['lfcb'] == C.IND_LF[dt][i]
@@ -549,7 +549,7 @@ def check_analysis_appendix_c(dt):
data['idx_b'] == C.IDX_B[dt][i])
ok = ok and (C.LS_IND_B[dt][i] is None or
data['ls_b'] == C.LS_IND_B[dt][i])
ok = ok and np.amax(np.abs(1 - x/C.X_S[dt][i])) < 1e-5
ok = ok and np.amax(np.abs(x - C.X_S[dt][i])) < 1e-1
return ok

View File

@@ -92,7 +92,7 @@ static PyObject *unquantize_py(PyObject *m, PyObject *args)
PyObject *y_obj, *scf_obj;
int lfcb_idx, hfcb_idx;
int shape, gain;
float *y, *scf;
lc3_intfloat_t *y, *scf;
if (!PyArg_ParseTuple(args, "iiOii",
&lfcb_idx, &hfcb_idx, &y_obj, &shape, &gain))
@@ -107,8 +107,16 @@ static PyObject *unquantize_py(PyObject *m, PyObject *args)
scf_obj = new_1d_ptr(NPY_FLOAT, 16, &scf);
#ifdef CONFIG_FIXED_POINT
for (int i = 0; i < 16; i++) y[i] = ldexpf(((float *)y)[i], 24);
#endif
unquantize(lfcb_idx, hfcb_idx, y, shape, gain, scf);
#ifdef CONFIG_FIXED_POINT
for (int i = 0; i < 16; i++) ((float *)scf)[i] = ldexpf(scf[i], -24);
#endif
return Py_BuildValue("N", scf_obj);
}
@@ -116,7 +124,7 @@ static PyObject *spectral_shaping_py(PyObject *m, PyObject *args)
{
PyObject *scf_q_obj, *x_obj;
unsigned dt, sr;
float *scf_q, *x;
lc3_intfloat_t *scf_q, *x;
int inv;
if (!PyArg_ParseTuple(args, "IIOpO", &dt, &sr, &scf_q_obj, &inv, &x_obj))
@@ -130,8 +138,17 @@ static PyObject *spectral_shaping_py(PyObject *m, PyObject *args)
CTYPES_CHECK("scf_q", to_1d_ptr(scf_q_obj, NPY_FLOAT, 16, &scf_q));
CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x));
#ifdef CONFIG_FIXED_POINT
for (int i = 0; i < 16; i++) scf_q[i] = ldexpf(((float *)scf_q)[i], 24);
for (int i = 0; i < ne; i++) x[i] = ldexpf(((float *)x)[i], 8);
#endif
spectral_shaping(dt, sr, scf_q, inv, x, x);
#ifdef CONFIG_FIXED_POINT
for (int i = 0; i < ne; i++) ((float *)x)[i] = ldexpf(x[i], -8);
#endif
return Py_BuildValue("O", x_obj);
}
@@ -165,7 +182,7 @@ static PyObject *synthesize_py(PyObject *m, PyObject *args)
PyObject *data_obj, *x_obj;
struct lc3_sns_data data;
unsigned dt, sr;
float *x;
lc3_intfloat_t *x;
if (!PyArg_ParseTuple(args, "IIOO", &dt, &sr, &data_obj, &x_obj))
return NULL;
@@ -178,8 +195,16 @@ static PyObject *synthesize_py(PyObject *m, PyObject *args)
CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x));
#ifdef CONFIG_FIXED_POINT
for (int i = 0; i < ne; i++) x[i] = ldexpf(((float *)x)[i], 8);
#endif
lc3_sns_synthesize(dt, sr, &data, x, x);
#ifdef CONFIG_FIXED_POINT
for (int i = 0; i < ne; i++) ((float *)x)[i] = ldexpf(x[i], -8);
#endif
return Py_BuildValue("O", x_obj);
}