mirror of
https://github.com/google/liblc3.git
synced 2026-06-01 17:37:01 +00:00
mdct: work on 2 input buffers, and remove 1 encoding buffer
This commit is contained in:
@@ -108,12 +108,12 @@ struct lc3_encoder {
|
||||
lc3_spec_analysis_t spec;
|
||||
|
||||
int16_t *xt;
|
||||
float *xs, *xf, s[0];
|
||||
float *xs, *xd, s[0];
|
||||
};
|
||||
|
||||
#define LC3_ENCODER_BUFFER_COUNT(dt_us, sr_hz) \
|
||||
( ( __LC3_NS(dt_us, sr_hz) + __LC3_NT(sr_hz) ) / 2 + \
|
||||
2*__LC3_NS(dt_us, sr_hz) + __LC3_ND(dt_us, sr_hz) )
|
||||
__LC3_NS(dt_us, sr_hz) + __LC3_ND(dt_us, sr_hz) )
|
||||
|
||||
#define LC3_ENCODER_MEM_T(dt_us, sr_hz) \
|
||||
struct { \
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
#define LC3_ND(dt, sr) \
|
||||
( (dt) == LC3_DT_7M5 ? 23 * LC3_NS(dt, sr) / 30 \
|
||||
: 5 * LC3_NS(dt, sr) / 8 )
|
||||
|
||||
#define LC3_NE(dt, sr) \
|
||||
( 20 * (3 + (dt)) * (1 + (sr)) )
|
||||
|
||||
|
||||
@@ -205,12 +205,12 @@ static void analyze(struct lc3_encoder *encoder,
|
||||
enum lc3_srate sr = encoder->sr;
|
||||
enum lc3_srate sr_pcm = encoder->sr_pcm;
|
||||
int ns = LC3_NS(dt, sr_pcm);
|
||||
int nd = LC3_ND(dt, sr_pcm);
|
||||
int nt = LC3_NT(sr_pcm);
|
||||
|
||||
int16_t *xt = encoder->xt;
|
||||
float *xs = encoder->xs;
|
||||
float *xf = encoder->xf;
|
||||
float *xd = encoder->xd;
|
||||
float *xf = xs;
|
||||
|
||||
/* --- Temporal --- */
|
||||
|
||||
@@ -225,8 +225,7 @@ static void analyze(struct lc3_encoder *encoder,
|
||||
|
||||
float e[LC3_NUM_BANDS];
|
||||
|
||||
lc3_mdct_forward(dt, sr_pcm, sr, xs, xf);
|
||||
memmove(xs - nd, xs + (ns-nd), nd * sizeof(*xs));
|
||||
lc3_mdct_forward(dt, sr_pcm, sr, xs, xd, xf);
|
||||
|
||||
bool nn_flag = lc3_energy_compute(dt, sr, xf, e);
|
||||
if (nn_flag)
|
||||
@@ -256,7 +255,7 @@ static void encode(struct lc3_encoder *encoder,
|
||||
enum lc3_dt dt = encoder->dt;
|
||||
enum lc3_srate sr = encoder->sr;
|
||||
enum lc3_bandwidth bw = side->bw;
|
||||
float *xf = encoder->xf;
|
||||
float *xf = encoder->xs;
|
||||
|
||||
lc3_bits_t bits;
|
||||
|
||||
@@ -312,7 +311,6 @@ struct lc3_encoder *lc3_setup_encoder(
|
||||
|
||||
struct lc3_encoder *encoder = mem;
|
||||
int ns = LC3_NS(dt, sr_pcm);
|
||||
int nd = LC3_ND(dt, sr_pcm);
|
||||
int nt = LC3_NT(sr_pcm);
|
||||
|
||||
*encoder = (struct lc3_encoder){
|
||||
@@ -320,8 +318,8 @@ struct lc3_encoder *lc3_setup_encoder(
|
||||
.sr_pcm = sr_pcm,
|
||||
|
||||
.xt = (int16_t *)encoder->s + nt,
|
||||
.xs = encoder->s + (nt+ns)/2 + nd,
|
||||
.xf = encoder->s + (nt+ns)/2 + nd+ns,
|
||||
.xs = encoder->s + (nt+ns)/2,
|
||||
.xd = encoder->s + (nt+ns)/2 + ns,
|
||||
};
|
||||
|
||||
memset(encoder->s, 0,
|
||||
|
||||
+22
-25
@@ -193,39 +193,35 @@ static struct lc3_complex *fft(const struct lc3_complex *x, int n,
|
||||
/**
|
||||
* Windowing of samples before MDCT
|
||||
* dt, sr Duration and samplerate (size of the transform)
|
||||
* x [-nd..-1] Previous, [0..ns-1] Current samples
|
||||
* y Output `ns` windowed samples
|
||||
*
|
||||
* The number of previous samples `nd` accessed on `x` is :
|
||||
* nd: `ns` * 23/30 for 7.5ms frame duration
|
||||
* nd: `ns` * 5/ 8 for 10ms frame duration
|
||||
* x, y Input current and delayed samples
|
||||
* y, d Output windowed samples, and delayed ones
|
||||
*/
|
||||
static void mdct_window(
|
||||
enum lc3_dt dt, enum lc3_srate sr, const float *x, float *y)
|
||||
static void mdct_window(enum lc3_dt dt, enum lc3_srate sr,
|
||||
const float *x, float *d, float *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 float *x0 = x - nd, *x1 = x0 + ns;
|
||||
const float *x2 = x1, *x3 = x2 + nd;
|
||||
|
||||
const float *x0 = x + ns-nd, *x1 = x0;
|
||||
float *y0 = y + ns/2, *y1 = y0;
|
||||
float *d0 = d, *d1 = d + nd;
|
||||
|
||||
while (x0 < x1) {
|
||||
*(--y0) = *(x0++) * *(w0++) - *(--x1) * *(--w1);
|
||||
*(--y0) = *(x0++) * *(w0++) - *(--x1) * *(--w1);
|
||||
while (x1 > x) {
|
||||
*(--y0) = *d0 * *(w0++) - *(--x1) * *(--w1);
|
||||
*(y1++) = (*(d0++) = *(x0++)) * *(w2++);
|
||||
|
||||
*(--y0) = *d0 * *(w0++) - *(--x1) * *(--w1);
|
||||
*(y1++) = (*(d0++) = *(x0++)) * *(w2++);
|
||||
}
|
||||
|
||||
for (const float *xe = x2 + ns-nd; x2 < xe; ) {
|
||||
*(y1++) = *(x2++) * *(w2++);
|
||||
*(y1++) = *(x2++) * *(w2++);
|
||||
}
|
||||
for (x1 += ns; x0 < x1; ) {
|
||||
*(--y0) = *d0 * *(w0++) - *(--d1) * *(--w1);
|
||||
*(y1++) = (*(d0++) = *(x0++)) * *(w2++) + (*d1 = *(--x1)) * *(--w3);
|
||||
|
||||
while (x2 < x3) {
|
||||
*(y1++) = *(x2++) * *(w2++) + *(--x3) * *(--w3);
|
||||
*(y1++) = *(x2++) * *(w2++) + *(--x3) * *(--w3);
|
||||
*(--y0) = *d0 * *(w0++) - *(--d1) * *(--w1);
|
||||
*(y1++) = (*(d0++) = *(x0++)) * *(w2++) + (*d1 = *(--x1)) * *(--w3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,16 +405,17 @@ static void imdct_window(enum lc3_dt dt, enum lc3_srate sr,
|
||||
* Forward MDCT transformation
|
||||
*/
|
||||
void lc3_mdct_forward(enum lc3_dt dt, enum lc3_srate sr,
|
||||
enum lc3_srate sr_dst, const float *x, float *y)
|
||||
enum lc3_srate sr_dst, const float *x, float *d, float *y)
|
||||
{
|
||||
const struct lc3_mdct_rot_def *rot = lc3_mdct_rot[dt][sr];
|
||||
int nf = LC3_NS(dt, sr_dst);
|
||||
int ns = LC3_NS(dt, sr);
|
||||
|
||||
union { float *f; struct lc3_complex *z; } u = { .f = y };
|
||||
struct lc3_complex z[ns/2];
|
||||
struct lc3_complex buffer[ns/2];
|
||||
struct lc3_complex *z = (struct lc3_complex *)y;
|
||||
union { float *f; struct lc3_complex *z; } u = { .z = buffer };
|
||||
|
||||
mdct_window(dt, sr, x, u.f);
|
||||
mdct_window(dt, sr, x, d, u.f);
|
||||
|
||||
mdct_pre_fft(rot, u.f, u.z);
|
||||
u.z = fft(u.z, ns/2, u.z, z);
|
||||
|
||||
+4
-6
@@ -33,15 +33,13 @@
|
||||
* Forward MDCT transformation
|
||||
* dt, sr Duration and samplerate (size of the transform)
|
||||
* sr_dst Samplerate destination, scale transforam accordingly
|
||||
* x [-nd..-1] Previous, [0..ns-1] Current samples
|
||||
* y Output `ns` frequency coefficients
|
||||
* x, d Temporal samples and delayed buffer
|
||||
* y, d Output `ns` coefficients and `nd` delayed samples
|
||||
*
|
||||
* The number of previous samples `nd` accessed on `x` is :
|
||||
* nd: `ns` * 23/30 for 7.5ms frame duration
|
||||
* nd: `ns` * 5/ 8 for 10ms frame duration
|
||||
* `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 *y);
|
||||
enum lc3_srate sr_dst, const float *x, float *d, float *y);
|
||||
|
||||
/**
|
||||
* Inverse MDCT transformation
|
||||
|
||||
+8
-8
@@ -729,10 +729,10 @@ static PyObject *from_encoder(PyObject *obj, const struct lc3_encoder *enc)
|
||||
new_1d_copy(NPY_INT16, nt+ns, enc->xt-nt));
|
||||
|
||||
PyDict_SetItemString(obj, "xs",
|
||||
new_1d_copy(NPY_FLOAT, ns+nd, enc->xs-nd));
|
||||
new_1d_copy(NPY_FLOAT, ns, enc->xs));
|
||||
|
||||
PyDict_SetItemString(obj, "xf",
|
||||
new_1d_copy(NPY_FLOAT, ns, enc->xf));
|
||||
PyDict_SetItemString(obj, "xd",
|
||||
new_1d_copy(NPY_FLOAT, nd, enc->xd));
|
||||
|
||||
return obj;
|
||||
}
|
||||
@@ -741,7 +741,7 @@ __attribute__((unused))
|
||||
static PyObject *to_encoder(PyObject *obj, struct lc3_encoder *enc)
|
||||
{
|
||||
unsigned dt, sr, sr_pcm;
|
||||
PyObject *xt_obj, *xs_obj, *xf_obj;
|
||||
PyObject *xt_obj, *xs_obj, *xd_obj;
|
||||
|
||||
CTYPES_CHECK("encoder", obj && PyDict_Check(obj));
|
||||
|
||||
@@ -776,12 +776,12 @@ static PyObject *to_encoder(PyObject *obj, struct lc3_encoder *enc)
|
||||
PyDict_SetItemString(obj, "xt", xt_obj);
|
||||
|
||||
CTYPES_CHECK("encoder.xs", xs_obj = to_1d_copy(
|
||||
PyDict_GetItemString(obj, "xs"), NPY_FLOAT, enc->xs-nd, ns+nd));
|
||||
PyDict_GetItemString(obj, "xs"), NPY_FLOAT, enc->xs, ns));
|
||||
PyDict_SetItemString(obj, "xs", xs_obj);
|
||||
|
||||
CTYPES_CHECK("encoder.xf", xf_obj = to_1d_copy(
|
||||
PyDict_GetItemString(obj, "xf"), NPY_FLOAT, enc->xf, ns));
|
||||
PyDict_SetItemString(obj, "xf", xf_obj);
|
||||
CTYPES_CHECK("encoder.xd", xd_obj = to_1d_copy(
|
||||
PyDict_GetItemString(obj, "xd"), NPY_FLOAT, enc->xd, nd));
|
||||
PyDict_SetItemString(obj, "xd", xd_obj);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
+10
-8
@@ -99,11 +99,15 @@ def check_forward_unit(rng, dt, sr):
|
||||
|
||||
x = (2 * rng.random(ns)) - 1
|
||||
|
||||
mdct = MdctForward(dt, sr)
|
||||
y = [ mdct.run(x), mdct.run(x) ]
|
||||
y = [ None ] * 2
|
||||
y_c = [ None ] * 2
|
||||
|
||||
y_c = [ lc3.mdct_forward(dt, sr, np.append(np.zeros(nd), x)),
|
||||
lc3.mdct_forward(dt, sr, np.append(x[-nd:], x)) ]
|
||||
mdct = MdctForward(dt, sr)
|
||||
y[0] = mdct.run(x)
|
||||
y[1] = mdct.run(x)
|
||||
|
||||
(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
|
||||
@@ -118,12 +122,10 @@ def check_forward_appendix_c(dt):
|
||||
nd = T.ND[dt][sr]
|
||||
ok = True
|
||||
|
||||
y = lc3.mdct_forward(dt, sr,
|
||||
np.append(np.zeros(nd), C.X_PCM[dt][0]))
|
||||
(y, d) = lc3.mdct_forward(dt, sr, C.X_PCM[dt][0], np.zeros(nd))
|
||||
ok = ok and np.amax(np.abs(y - C.X[dt][0])) < 1e-1
|
||||
|
||||
y = lc3.mdct_forward(dt, sr,
|
||||
np.append(C.X_PCM[dt][0][-nd:], C.X_PCM[dt][1]))
|
||||
(y, d) = lc3.mdct_forward(dt, sr, C.X_PCM[dt][1], d)
|
||||
ok = ok and np.amax(np.abs(y - C.X[dt][1])) < 1e-1
|
||||
|
||||
return ok
|
||||
|
||||
+10
-6
@@ -25,12 +25,12 @@
|
||||
|
||||
static PyObject *mdct_forward_py(PyObject *m, PyObject *args)
|
||||
{
|
||||
PyObject *x_obj, *y_obj;
|
||||
PyObject *x_obj, *xd_obj, *y_obj, *d_obj;
|
||||
enum lc3_dt dt;
|
||||
enum lc3_srate sr;
|
||||
float *x, *y;
|
||||
float *x, *xd, *y, *d;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iiO", &dt, &sr, &x_obj))
|
||||
if (!PyArg_ParseTuple(args, "iiOO", &dt, &sr, &x_obj, &xd_obj))
|
||||
return NULL;
|
||||
|
||||
CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT);
|
||||
@@ -38,12 +38,16 @@ static PyObject *mdct_forward_py(PyObject *m, PyObject *args)
|
||||
|
||||
int ns = LC3_NS(dt, sr), nd = LC3_ND(dt, sr);
|
||||
|
||||
CTYPES_CHECK("x", to_1d_ptr(x_obj, NPY_FLOAT, nd+ns, &x));
|
||||
CTYPES_CHECK("x", to_1d_ptr(x_obj, NPY_FLOAT, ns, &x));
|
||||
CTYPES_CHECK("xd", to_1d_ptr(xd_obj, NPY_FLOAT, nd, &xd));
|
||||
d_obj = new_1d_ptr(NPY_FLOAT, nd, &d);
|
||||
y_obj = new_1d_ptr(NPY_FLOAT, ns, &y);
|
||||
|
||||
lc3_mdct_forward(dt, sr, sr, x+nd, y);
|
||||
memcpy(d, xd, nd * sizeof(float));
|
||||
|
||||
return Py_BuildValue("N", y_obj);
|
||||
lc3_mdct_forward(dt, sr, sr, x, d, y);
|
||||
|
||||
return Py_BuildValue("NN", y_obj, d_obj);
|
||||
}
|
||||
|
||||
static PyObject *mdct_inverse_py(PyObject *m, PyObject *args)
|
||||
|
||||
Reference in New Issue
Block a user