1 /******************************************************************************
2  *
3  *  Copyright 2022 Google LLC
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 
19 #include "lc3.h"
20 #include <Python.h>
21 #include <numpy/ndarrayobject.h>
22 
23 #include <tns.c>
24 #include "ctypes.h"
25 
compute_lpc_coeffs_py(PyObject * m,PyObject * args)26 static PyObject *compute_lpc_coeffs_py(PyObject *m, PyObject *args)
27 {
28     PyObject *x_obj, *a_obj, *g_obj;
29     unsigned dt, bw;
30     float *x, *g, (*a)[9];
31 
32     if (!PyArg_ParseTuple(args, "IIO", &dt, &bw, &x_obj))
33         return NULL;
34 
35     CTYPES_CHECK("dt", dt < LC3_NUM_DT);
36     CTYPES_CHECK("sr", bw < LC3_NUM_BANDWIDTH);
37 
38     int ne = lc3_ne(dt, bw);
39     int maxorder = dt <= LC3_DT_5M ? 4 : 8;
40 
41     CTYPES_CHECK("x", to_1d_ptr(x_obj, NPY_FLOAT, ne, &x));
42 
43     g_obj = new_1d_ptr(NPY_FLOAT, 2, &g);
44     a_obj = new_2d_ptr(NPY_FLOAT, 2, 9, &a);
45 
46     compute_lpc_coeffs(dt, bw, maxorder, x, g, a);
47 
48     return Py_BuildValue("NN", g_obj, a_obj);
49 }
50 
lpc_reflection_py(PyObject * m,PyObject * args)51 static PyObject *lpc_reflection_py(PyObject *m, PyObject *args)
52 {
53     PyObject *a_obj, *rc_obj;
54     unsigned dt;
55     float *a, *rc;
56 
57     if (!PyArg_ParseTuple(args, "IO", &dt, &a_obj))
58         return NULL;
59 
60     CTYPES_CHECK("dt", dt < LC3_NUM_DT);
61 
62     int maxorder = dt <= LC3_DT_5M ? 4 : 8;
63 
64     CTYPES_CHECK("a", to_1d_ptr(a_obj, NPY_FLOAT, 9, &a));
65     rc_obj = new_1d_ptr(NPY_FLOAT, maxorder, &rc);
66 
67     lpc_reflection(a, maxorder, rc);
68 
69     return Py_BuildValue("N", rc_obj);
70 }
71 
quantize_rc_py(PyObject * m,PyObject * args)72 static PyObject *quantize_rc_py(PyObject *m, PyObject *args)
73 {
74     PyObject *rc_obj, *rc_q_obj;
75     unsigned dt;
76     float *rc;
77     int rc_order, *rc_q;
78 
79     if (!PyArg_ParseTuple(args, "iO", &dt, &rc_obj))
80         return NULL;
81 
82     CTYPES_CHECK("dt", dt < LC3_NUM_DT);
83 
84     int maxorder = dt <= LC3_DT_5M ? 4 : 8;
85 
86     CTYPES_CHECK("rc", to_1d_ptr(rc_obj, NPY_FLOAT, 8, &rc));
87     rc_q_obj = new_1d_ptr(NPY_INT, 8, &rc_q);
88 
89     quantize_rc(rc, maxorder, &rc_order, rc_q);
90 
91     return Py_BuildValue("iN", rc_order, rc_q_obj);
92 }
93 
unquantize_rc_py(PyObject * m,PyObject * args)94 static PyObject *unquantize_rc_py(PyObject *m, PyObject *args)
95 {
96     PyObject *rc_q_obj, *rc_obj;
97     int rc_order, *rc_q;
98     float *rc;
99 
100     if (!PyArg_ParseTuple(args, "OI", &rc_q_obj, &rc_order))
101         return NULL;
102 
103     CTYPES_CHECK("rc_q", to_1d_ptr(rc_q_obj, NPY_INT, 8, &rc_q));
104     CTYPES_CHECK("rc_order", (unsigned)rc_order <= 8);
105 
106     rc_obj = new_1d_ptr(NPY_FLOAT, 8, &rc);
107 
108     unquantize_rc(rc_q, rc_order, rc);
109 
110     return Py_BuildValue("N", rc_obj);
111 }
112 
analyze_py(PyObject * m,PyObject * args)113 static PyObject *analyze_py(PyObject *m, PyObject *args)
114 {
115     PyObject *x_obj;
116     struct lc3_tns_data data = { 0 };
117     unsigned dt, bw;
118     int nn_flag, nbytes;
119     float *x;
120 
121     if (!PyArg_ParseTuple(args, "IIpiO",
122             &dt, &bw, &nn_flag, &nbytes, &x_obj))
123         return NULL;
124 
125     CTYPES_CHECK("dt", dt < LC3_NUM_DT);
126     CTYPES_CHECK("bw", bw < LC3_NUM_BANDWIDTH);
127 
128     int ne = lc3_ne(dt, bw);
129 
130     CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x));
131 
132     lc3_tns_analyze(dt, bw, nn_flag, nbytes, &data, x);
133 
134     return Py_BuildValue("ON", x_obj, new_tns_data(&data));
135 }
136 
synthesize_py(PyObject * m,PyObject * args)137 static PyObject *synthesize_py(PyObject *m, PyObject *args)
138 {
139     PyObject *data_obj, *x_obj;
140     unsigned dt, bw;
141     struct lc3_tns_data data;
142     float *x;
143 
144     if (!PyArg_ParseTuple(args, "IIOO", &dt, &bw, &data_obj, &x_obj))
145         return NULL;
146 
147     CTYPES_CHECK("dt", dt < LC3_NUM_DT);
148     CTYPES_CHECK("bw", bw < LC3_NUM_BANDWIDTH);
149     CTYPES_CHECK(NULL, data_obj = to_tns_data(data_obj, &data));
150 
151     int ne = lc3_ne(dt, bw);
152 
153     CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x));
154 
155     lc3_tns_synthesize(dt, bw, &data, x);
156 
157     return Py_BuildValue("O", x_obj);
158 }
159 
get_nbits_py(PyObject * m,PyObject * args)160 static PyObject *get_nbits_py(PyObject *m, PyObject *args)
161 {
162     PyObject *data_obj;
163     struct lc3_tns_data data = { 0 };
164 
165     if (!PyArg_ParseTuple(args, "O", &data_obj))
166         return NULL;
167 
168     CTYPES_CHECK("data", to_tns_data(data_obj, &data));
169 
170     int nbits = lc3_tns_get_nbits(&data);
171 
172     return Py_BuildValue("i", nbits);
173 }
174 
175 static PyMethodDef methods[] = {
176     { "tns_compute_lpc_coeffs", compute_lpc_coeffs_py, METH_VARARGS },
177     { "tns_lpc_reflection"    , lpc_reflection_py    , METH_VARARGS },
178     { "tns_quantize_rc"       , quantize_rc_py       , METH_VARARGS },
179     { "tns_unquantize_rc"     , unquantize_rc_py     , METH_VARARGS },
180     { "tns_analyze"           , analyze_py           , METH_VARARGS },
181     { "tns_synthesize"        , synthesize_py        , METH_VARARGS },
182     { "tns_get_nbits"         , get_nbits_py         , METH_VARARGS },
183     { NULL },
184 };
185 
lc3_tns_py_init(PyObject * m)186 PyMODINIT_FUNC lc3_tns_py_init(PyObject *m)
187 {
188     import_array();
189 
190     PyModule_AddFunctions(m, methods);
191 
192     return m;
193 }
194