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