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 
21 #define PY_SSIZE_T_CLEAN
22 #include <Python.h>
23 #include <numpy/ndarrayobject.h>
24 
25 #include <lc3.c>
26 
27 #define __CTYPES_LC3_C
28 #include "ctypes.h"
29 
setup_encoder_py(PyObject * m,PyObject * args)30 static PyObject *setup_encoder_py(PyObject *m, PyObject *args)
31 {
32     int dt_us, sr_hz;
33 
34     if (!PyArg_ParseTuple(args, "ii", &dt_us, &sr_hz))
35         return NULL;
36 
37     CTYPES_CHECK("dt_us", LC3_CHECK_DT_US(dt_us));
38     CTYPES_CHECK("sr_hz", LC3_CHECK_SR_HZ(sr_hz));
39 
40     lc3_encoder_t encoder = lc3_setup_encoder(dt_us, sr_hz, 0,
41             malloc(lc3_encoder_size(dt_us, sr_hz)));
42 
43     PyObject *encoder_obj = from_encoder(NULL, encoder);
44 
45     free(encoder);
46 
47     return Py_BuildValue("N", encoder_obj);
48 }
49 
encode_py(PyObject * m,PyObject * args)50 static PyObject *encode_py(PyObject *m, PyObject *args)
51 {
52     PyObject *encoder_obj, *pcm_obj;
53     int nbytes;
54     int16_t *pcm;
55 
56     if (!PyArg_ParseTuple(args, "OOi", &encoder_obj, &pcm_obj, &nbytes))
57         return NULL;
58 
59     lc3_encoder_t encoder =
60         lc3_setup_encoder(10000, 48000, 0, &(lc3_encoder_mem_48k_t){ });
61 
62     CTYPES_CHECK(NULL, encoder_obj = to_encoder(encoder_obj, encoder));
63 
64     int ns = LC3_NS(encoder->dt, encoder->sr);
65 
66     CTYPES_CHECK("x", pcm_obj = to_1d_ptr(pcm_obj, NPY_INT16, ns, &pcm));
67     CTYPES_CHECK("nbytes", nbytes >= 20 && nbytes <= 400);
68 
69     uint8_t out[nbytes];
70 
71     lc3_encode(encoder, LC3_PCM_FORMAT_S16, pcm, 1, nbytes, out);
72 
73     from_encoder(encoder_obj, encoder);
74 
75     return Py_BuildValue("N",
76         PyBytes_FromStringAndSize((const char *)out, nbytes));
77 }
78 
setup_decoder_py(PyObject * m,PyObject * args)79 static PyObject *setup_decoder_py(PyObject *m, PyObject *args)
80 {
81     int dt_us, sr_hz;
82 
83     if (!PyArg_ParseTuple(args, "ii", &dt_us, &sr_hz))
84         return NULL;
85 
86     CTYPES_CHECK("dt_us", LC3_CHECK_DT_US(dt_us));
87     CTYPES_CHECK("sr_hz", LC3_CHECK_SR_HZ(sr_hz));
88 
89     lc3_decoder_t decoder = lc3_setup_decoder(dt_us, sr_hz, 0,
90             malloc(lc3_decoder_size(dt_us, sr_hz)));
91 
92     PyObject *decoder_obj = from_decoder(NULL, decoder);
93 
94     free(decoder);
95 
96     return Py_BuildValue("N", decoder_obj);
97 }
98 
decode_py(PyObject * m,PyObject * args)99 static PyObject *decode_py(PyObject *m, PyObject *args)
100 {
101     PyObject *decoder_obj, *pcm_obj, *in_obj;
102     int16_t *pcm;
103 
104     if (!PyArg_ParseTuple(args, "OO", &decoder_obj, &in_obj))
105         return NULL;
106 
107     CTYPES_CHECK("in", in_obj == Py_None || PyBytes_Check(in_obj));
108 
109     char *in = in_obj == Py_None ? NULL : PyBytes_AsString(in_obj);
110     int nbytes = in_obj == Py_None ? 0 : PyBytes_Size(in_obj);
111 
112     lc3_decoder_t decoder =
113         lc3_setup_decoder(10000, 48000, 0, &(lc3_decoder_mem_48k_t){ });
114 
115     CTYPES_CHECK(NULL, decoder_obj = to_decoder(decoder_obj, decoder));
116 
117     int ns = LC3_NS(decoder->dt, decoder->sr);
118     pcm_obj = new_1d_ptr(NPY_INT16, ns, &pcm);
119 
120     lc3_decode(decoder, in, nbytes, LC3_PCM_FORMAT_S16, pcm, 1);
121 
122     from_decoder(decoder_obj, decoder);
123 
124     return Py_BuildValue("N", pcm_obj);
125 }
126 
127 static PyMethodDef methods[] = {
128     { "setup_encoder"      , setup_encoder_py      , METH_VARARGS },
129     { "encode"             , encode_py             , METH_VARARGS },
130     { "setup_decoder"      , setup_decoder_py      , METH_VARARGS },
131     { "decode"             , decode_py             , METH_VARARGS },
132     { NULL },
133 };
134 
lc3_interface_py_init(PyObject * m)135 PyMODINIT_FUNC lc3_interface_py_init(PyObject *m)
136 {
137     import_array();
138 
139     PyModule_AddFunctions(m, methods);
140 
141     return m;
142 }
143