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