mirror of
https://github.com/google/liblc3.git
synced 2026-04-18 05:35:31 +00:00
wip: MDCT, SNS in fixed point
This commit is contained in:
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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
81
src/fixmath.h
Normal 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 */
|
||||
49
src/lc3.c
49
src/lc3.c
@@ -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,
|
||||
|
||||
255
src/mdct.c
255
src/mdct.c
@@ -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
|
||||
}
|
||||
|
||||
10
src/mdct.h
10
src/mdct.h
@@ -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
257
src/sns.c
@@ -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,
|
||||
|
||||
@@ -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 */
|
||||
|
||||
3889
src/tables.c
3889
src/tables.c
File diff suppressed because it is too large
Load Diff
@@ -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];
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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():
|
||||
|
||||
12
test/mdct.py
12
test/mdct.py
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user