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 <sns.c>
24 #include "ctypes.h"
25 
compute_scale_factors_py(PyObject * m,PyObject * args)26 static PyObject *compute_scale_factors_py(PyObject *m, PyObject *args)
27 {
28     unsigned dt, sr;
29     PyObject *eb_obj, *scf_obj;
30     float *eb, *scf;
31     int att;
32 
33     if (!PyArg_ParseTuple(args, "IIOp", &dt, &sr, &eb_obj, &att))
34         return NULL;
35 
36     CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT);
37     CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE);
38 
39     int nb = LC3_MIN(lc3_band_lim[dt][sr][LC3_NUM_BANDS], LC3_NUM_BANDS);
40 
41     CTYPES_CHECK("eb", to_1d_ptr(eb_obj, NPY_FLOAT, nb, &eb));
42     scf_obj = new_1d_ptr(NPY_FLOAT, 16, &scf);
43 
44     compute_scale_factors(dt, sr, eb, att, scf);
45 
46     return Py_BuildValue("N", scf_obj);
47 }
48 
resolve_codebooks_py(PyObject * m,PyObject * args)49 static PyObject *resolve_codebooks_py(PyObject *m, PyObject *args)
50 {
51     PyObject *scf_obj;
52     float *scf;
53     int lfcb_idx, hfcb_idx;
54 
55     if (!PyArg_ParseTuple(args, "O", &scf_obj))
56         return NULL;
57 
58     CTYPES_CHECK("eb", to_1d_ptr(scf_obj, NPY_FLOAT, 16, &scf));
59 
60     resolve_codebooks(scf, &lfcb_idx, &hfcb_idx);
61 
62     return Py_BuildValue("ii", lfcb_idx, hfcb_idx);
63 }
64 
quantize_py(PyObject * m,PyObject * args)65 static PyObject *quantize_py(PyObject *m, PyObject *args)
66 {
67     PyObject *scf_obj, *y_obj, *yn_obj;
68     float *scf;
69     int lfcb_idx, hfcb_idx;
70     int shape_idx, gain_idx;
71     float (*yn)[16];
72     int (*y)[16];
73 
74     if (!PyArg_ParseTuple(args, "Oii", &scf_obj, &lfcb_idx, &hfcb_idx))
75         return NULL;
76 
77     CTYPES_CHECK("scf", to_1d_ptr(scf_obj, NPY_FLOAT, 16, &scf));
78     CTYPES_CHECK("lfcb_idx", (unsigned)lfcb_idx < 32);
79     CTYPES_CHECK("hfcb_idx", (unsigned)hfcb_idx < 32);
80 
81     y_obj = new_2d_ptr(NPY_INT, 4, 16, &y);
82     yn_obj = new_2d_ptr(NPY_FLOAT, 4, 16, &yn);
83 
84     quantize(scf, lfcb_idx, hfcb_idx,
85         y, yn, &shape_idx, &gain_idx);
86 
87     return Py_BuildValue("NNii", y_obj, yn_obj, shape_idx, gain_idx);
88 }
89 
unquantize_py(PyObject * m,PyObject * args)90 static PyObject *unquantize_py(PyObject *m, PyObject *args)
91 {
92     PyObject *y_obj, *scf_obj;
93     int lfcb_idx, hfcb_idx;
94     int shape, gain;
95     float *y, *scf;
96 
97     if (!PyArg_ParseTuple(args, "iiOii",
98                 &lfcb_idx, &hfcb_idx, &y_obj, &shape, &gain))
99         return NULL;
100 
101     CTYPES_CHECK("lfcb_idx", (unsigned)lfcb_idx < 32);
102     CTYPES_CHECK("hfcb_idx", (unsigned)hfcb_idx < 32);
103     CTYPES_CHECK("y", to_1d_ptr(y_obj, NPY_FLOAT, 16, &y));
104     CTYPES_CHECK("shape", (unsigned)shape < 4);
105     CTYPES_CHECK("gain",
106         (unsigned)gain < (unsigned)lc3_sns_vq_gains[shape].count);
107 
108     scf_obj = new_1d_ptr(NPY_FLOAT, 16, &scf);
109 
110     unquantize(lfcb_idx, hfcb_idx, y, shape, gain, scf);
111 
112     return Py_BuildValue("N", scf_obj);
113 }
114 
spectral_shaping_py(PyObject * m,PyObject * args)115 static PyObject *spectral_shaping_py(PyObject *m, PyObject *args)
116 {
117     PyObject *scf_q_obj, *x_obj;
118     unsigned dt, sr;
119     float *scf_q, *x;
120     int inv;
121 
122     if (!PyArg_ParseTuple(args, "IIOpO", &dt, &sr, &scf_q_obj, &inv, &x_obj))
123         return NULL;
124 
125     CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT);
126     CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE);
127 
128     int ne = LC3_NE(dt, sr);
129 
130     CTYPES_CHECK("scf_q", to_1d_ptr(scf_q_obj, NPY_FLOAT, 16, &scf_q));
131     CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x));
132 
133     spectral_shaping(dt, sr, scf_q, inv, x, x);
134 
135     return Py_BuildValue("O", x_obj);
136 }
137 
analyze_py(PyObject * m,PyObject * args)138 static PyObject *analyze_py(PyObject *m, PyObject *args)
139 {
140     PyObject *eb_obj, *x_obj;
141     struct lc3_sns_data data = { 0 };
142     unsigned dt, sr;
143     float *eb, *x;
144     int att;
145 
146     if (!PyArg_ParseTuple(args, "IIOpO", &dt, &sr, &eb_obj, &att, &x_obj))
147         return NULL;
148 
149     CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT);
150     CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE);
151 
152     int ne = LC3_NE(dt, sr);
153     int nb = LC3_MIN(ne, LC3_NUM_BANDS);
154 
155     CTYPES_CHECK("eb", to_1d_ptr(eb_obj, NPY_FLOAT, nb, &eb));
156     CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x));
157 
158     lc3_sns_analyze(dt, sr, eb, att, &data, x, x);
159 
160     return Py_BuildValue("ON", x_obj, new_sns_data(&data));
161 }
162 
synthesize_py(PyObject * m,PyObject * args)163 static PyObject *synthesize_py(PyObject *m, PyObject *args)
164 {
165     PyObject *data_obj, *x_obj;
166     struct lc3_sns_data data;
167     unsigned dt, sr;
168     float *x;
169 
170     if (!PyArg_ParseTuple(args, "IIOO", &dt, &sr, &data_obj, &x_obj))
171         return NULL;
172 
173     CTYPES_CHECK("dt", (unsigned)dt < LC3_NUM_DT);
174     CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE);
175     CTYPES_CHECK(NULL, data_obj = to_sns_data(data_obj, &data));
176 
177     int ne = LC3_NE(dt, sr);
178 
179     CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x));
180 
181     lc3_sns_synthesize(dt, sr, &data, x, x);
182 
183     return Py_BuildValue("O", x_obj);
184 }
185 
get_nbits_py(PyObject * m,PyObject * args)186 static PyObject *get_nbits_py(PyObject *m, PyObject *args)
187 {
188     if (!PyArg_ParseTuple(args, ""))
189         return NULL;
190 
191     int nbits = lc3_sns_get_nbits();
192 
193     return Py_BuildValue("i", nbits);
194 }
195 
196 static PyMethodDef methods[] = {
197     { "sns_compute_scale_factors", compute_scale_factors_py, METH_VARARGS },
198     { "sns_resolve_codebooks"    , resolve_codebooks_py    , METH_VARARGS },
199     { "sns_quantize"             , quantize_py             , METH_VARARGS },
200     { "sns_unquantize"           , unquantize_py           , METH_VARARGS },
201     { "sns_spectral_shaping"     , spectral_shaping_py     , METH_VARARGS },
202     { "sns_analyze"              , analyze_py              , METH_VARARGS },
203     { "sns_synthesize"           , synthesize_py           , METH_VARARGS },
204     { "sns_get_nbits"            , get_nbits_py            , METH_VARARGS },
205     { NULL },
206 };
207 
lc3_sns_py_init(PyObject * m)208 PyMODINIT_FUNC lc3_sns_py_init(PyObject *m)
209 {
210     import_array();
211 
212     PyModule_AddFunctions(m, methods);
213 
214     return m;
215 }
216