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 <spec.c>
24 #include "ctypes.h"
25
estimate_gain_py(PyObject * m,PyObject * args)26 static PyObject *estimate_gain_py(PyObject *m, PyObject *args)
27 {
28 PyObject *x_obj;
29 unsigned dt, sr;
30 float *x;
31 int nbits_budget;
32 float nbits_off;
33 int g_off;
34 bool reset_off;
35
36 if (!PyArg_ParseTuple(args, "IIOifi", &dt, &sr,
37 &x_obj, &nbits_budget, &nbits_off, &g_off))
38 return NULL;
39
40 CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT);
41 CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE);
42
43 int ne = LC3_NE(dt, sr);
44
45 CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x));
46
47 int g_int = estimate_gain(dt, sr,
48 x, nbits_budget, nbits_off, g_off, &reset_off);
49
50 return Py_BuildValue("ii", g_int, reset_off);
51 }
52
adjust_gain_py(PyObject * m,PyObject * args)53 static PyObject *adjust_gain_py(PyObject *m, PyObject *args)
54 {
55 unsigned sr;
56 int g_idx, nbits, nbits_budget;
57
58 if (!PyArg_ParseTuple(args, "Iiii", &sr, &g_idx, &nbits, &nbits_budget))
59 return NULL;
60
61 CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE);
62 CTYPES_CHECK("g_idx", g_idx >= 0 && g_idx <= 255);
63
64 g_idx = adjust_gain(sr, g_idx, nbits, nbits_budget);
65
66 return Py_BuildValue("i", g_idx);
67 }
68
quantize_py(PyObject * m,PyObject * args)69 static PyObject *quantize_py(PyObject *m, PyObject *args)
70 {
71 PyObject *x_obj, *xq_obj;
72 unsigned dt, sr;
73 float *x;
74 int16_t *xq;
75 int g_int, nq;
76
77 if (!PyArg_ParseTuple(args, "IIiO", &dt, &sr, &g_int, &x_obj))
78 return NULL;
79
80 CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT);
81 CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE);
82 CTYPES_CHECK("g_int", g_int >= -255 && g_int <= 255);
83
84 int ne = LC3_NE(dt, sr);
85
86 CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x));
87
88 xq_obj = new_1d_ptr(NPY_INT16, ne, &xq);
89 uint16_t __xq[ne];
90
91 quantize(dt, sr, g_int, x, __xq, &nq);
92
93 for (int i = 0; i < nq; i++)
94 xq[i] = __xq[i] & 1 ? -(__xq[i] >> 1) : (__xq[i] >> 1);
95
96 return Py_BuildValue("ONi", x_obj, xq_obj, nq);
97 }
98
compute_nbits_py(PyObject * m,PyObject * args)99 static PyObject *compute_nbits_py(PyObject *m, PyObject *args)
100 {
101 PyObject *xq_obj;
102 unsigned dt, sr, nbytes;
103 int16_t *xq;
104 int nq, nbits_budget;
105 bool lsb_mode;
106
107 if (!PyArg_ParseTuple(args, "IIIOii", &dt, &sr,
108 &nbytes, &xq_obj, &nq, &nbits_budget))
109 return NULL;
110
111 CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT);
112 CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE);
113
114 int ne = LC3_NE(dt, sr);
115
116 CTYPES_CHECK("xq", xq_obj = to_1d_ptr(xq_obj, NPY_INT16, ne, &xq));
117
118 uint16_t __xq[ne];
119 for (int i = 0; i < ne; i++)
120 __xq[i] = xq[i] < 0 ? (-xq[i] << 1) + 1 : (xq[i] << 1);
121
122 int nbits = compute_nbits(
123 dt, sr, nbytes, __xq, &nq, nbits_budget, &lsb_mode);
124
125 return Py_BuildValue("iii", nbits, nq, lsb_mode);
126 }
127
analyze_py(PyObject * m,PyObject * args)128 static PyObject *analyze_py(PyObject *m, PyObject *args)
129 {
130 PyObject *tns_obj, *spec_obj, *x_obj, *xq_obj;
131 struct lc3_tns_data tns = { 0 };
132 struct lc3_spec_analysis spec = { 0 };
133 struct lc3_spec_side side = { 0 };
134 unsigned dt, sr, nbytes;
135 int pitch;
136 float *x;
137 int16_t *xq;
138
139 if (!PyArg_ParseTuple(args, "IIIpOOO", &dt, &sr, &nbytes,
140 &pitch, &tns_obj, &spec_obj, &x_obj))
141 return NULL;
142
143 CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT);
144 CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE);
145
146 int ne = LC3_NE(dt, sr);
147
148 CTYPES_CHECK(NULL, tns_obj = to_tns_data(tns_obj, &tns));
149 CTYPES_CHECK(NULL, spec_obj = to_spec_analysis(spec_obj, &spec));
150 CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x));
151
152 xq_obj = new_1d_ptr(NPY_INT16, ne, &xq);
153 uint16_t __xq[ne];
154
155 lc3_spec_analyze(dt, sr, nbytes, pitch, &tns, &spec, x, __xq, &side);
156
157 for (int i = 0; i < ne; i++)
158 xq[i] = __xq[i] & 1 ? -(__xq[i] >> 1) : (__xq[i] >> 1);
159
160 from_spec_analysis(spec_obj, &spec);
161 return Py_BuildValue("ONN", x_obj, xq_obj, new_spec_side(&side));
162 }
163
estimate_noise_py(PyObject * m,PyObject * args)164 static PyObject *estimate_noise_py(PyObject *m, PyObject *args)
165 {
166 PyObject *x_obj, *xq_obj;
167 unsigned dt, bw;
168 int16_t *xq;
169 float *x;
170 int nq;
171
172 if (!PyArg_ParseTuple(args, "IIOIO", &dt, &bw, &xq_obj, &nq, &x_obj))
173 return NULL;
174
175 CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT);
176 CTYPES_CHECK("bw", (unsigned)bw < LC3_NUM_BANDWIDTH);
177
178 int ne = LC3_NE(dt, bw);
179
180 CTYPES_CHECK("xq", xq_obj = to_1d_ptr(xq_obj, NPY_INT16, ne, &xq));
181 CTYPES_CHECK("x" , x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x ));
182
183 uint16_t __xq[nq];
184 for (int i = 0; i < nq; i++)
185 __xq[i] = xq[i] < 0 ? (-xq[i] << 1) + 1 : (xq[i] << 1);
186
187 int noise_factor = estimate_noise(dt, bw, __xq, nq, x);
188
189 return Py_BuildValue("i", noise_factor);
190 }
191
192 static PyMethodDef methods[] = {
193 { "spec_estimate_gain" , estimate_gain_py , METH_VARARGS },
194 { "spec_adjust_gain" , adjust_gain_py , METH_VARARGS },
195 { "spec_quantize" , quantize_py , METH_VARARGS },
196 { "spec_compute_nbits" , compute_nbits_py , METH_VARARGS },
197 { "spec_analyze" , analyze_py , METH_VARARGS },
198 { "spec_estimate_noise", estimate_noise_py, METH_VARARGS },
199 { NULL },
200 };
201
lc3_spec_py_init(PyObject * m)202 PyMODINIT_FUNC lc3_spec_py_init(PyObject *m)
203 {
204 import_array();
205
206 PyModule_AddFunctions(m, methods);
207
208 return m;
209 }
210