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 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 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 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 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 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 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 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