3 """ This madness of code is used to generate the C code of the python interface
4 to aubio. Don't try this at home.
6 The list of typedefs and functions is obtained from the command line 'cpp
7 aubio.h'. This list is then used to parse all the functions about this object.
9 I hear the ones asking "why not use swig, or cython, or something like that?"
11 The requirements for this extension are the following:
13 - aubio vectors can be viewed as numpy arrays, and vice versa
14 - aubio 'object' should be python classes, not just a bunch of functions
16 I haven't met any python interface generator that can meet both these
17 requirements. If you know of one, please let me know, it will spare me
18 maintaining this bizarre file.
27 # do function: for now, only the following pattern is supported:
28 # void aubio_<foo>_do (aubio_foo_t * o,
29 # [input1_t * input, [output1_t * output, ..., output3_t * output]]);
30 # There is no way of knowing that output1 is actually input2. In the future,
31 # const could be used for the inputs in the C prototypes.
35 # uncomment out for debugging
40 return ['foo*', 'name'] """
42 type_arg = {'type': l[0], 'name': l[1]}
43 # ['foo', '*name'] -> ['foo*', 'name']
44 if l[-1].startswith('*'):
45 #return [l[0]+'*', l[1][1:]]
46 type_arg['type'] = l[0] + '*'
47 type_arg['name'] = l[1][1:]
48 # ['foo', '*', 'name'] -> ['foo*', 'name']
50 #return [l[0]+l[1], l[2]]
51 type_arg['type'] = l[0]+l[1]
52 type_arg['name'] = l[2]
58 def get_params(proto):
59 """ get the list of parameters from a function prototype
60 example: proto = "int main (int argc, char ** argv)"
61 returns: ['int argc', 'char ** argv']
64 paramregex = re.compile('[\(, ](\w+ \*?\*? ?\w+)[, \)]')
65 return paramregex.findall(proto)
67 def get_params_types_names(proto):
68 """ get the list of parameters from a function prototype
69 example: proto = "int main (int argc, char ** argv)"
70 returns: [['int', 'argc'], ['char **','argv']]
72 return map(split_type, get_params(proto))
74 def get_return_type(proto):
76 paramregex = re.compile('(\w+ ?\*?).*')
77 outputs = paramregex.findall(proto)
78 assert len(outputs) == 1
79 return outputs[0].replace(' ', '')
82 name = proto.split()[1].split('(')[0]
83 return name.replace('*','')
85 # the important bits: the size of the output for each objects. this data should
86 # move into the C library at some point.
88 'resampler': ['input->length * self->ratio'],
93 'pitchschmitt': ['1'],
97 'tss': ['self->buf_size', 'self->buf_size'],
98 'mfcc': ['self->n_coeffs'],
99 'beattracking': ['self->hop_size'],
102 'source': ['self->hop_size', '1'],
105 # default value for variables
114 # we have some clean up to do
115 'buf_size': 'Py_default_vector_length',
117 'hop_size': 'Py_default_vector_length / 2',
118 # these should be alright
119 'samplerate': 'Py_aubio_default_samplerate',
120 # now for the non obvious ones
130 'method': '"default"',
145 aubiovecfrompyobj = {
146 'fvec_t*': 'PyAubio_ArrayToCFvec',
147 'cvec_t*': 'PyAubio_ArrayToCCvec',
148 'uint_t': '(uint_t)PyInt_AsLong',
153 'fvec_t*': 'PyAubio_CFvecToArray',
154 'cvec_t*': 'PyAubio_CCvecToPyCvec',
155 'smpl_t': 'PyFloat_FromDouble',
156 'uint_t*': 'PyInt_FromLong',
157 'uint_t': 'PyInt_FromLong',
160 def gen_new_init(newfunc, name):
161 newparams = get_params_types_names(newfunc)
162 # self->param1, self->param2, self->param3
164 selfparams = ', self->'+', self->'.join([p['name'] for p in newparams])
167 # "param1", "param2", "param3"
168 paramnames = ", ".join(["\""+p['name']+"\"" for p in newparams])
169 pyparams = "".join(map(lambda p: aubio2pytypes[p['type']], newparams))
170 paramrefs = ", ".join(["&" + p['name'] for p in newparams])
172 // WARNING: this file is generated, DO NOT EDIT
174 // WARNING: if you haven't read the first line yet, please do so
175 #include "aubiowraphell.h"
180 aubio_%(name)s_t * o;
191 static char Py_%(name)s_doc[] = "%(name)s object";
194 Py_%(name)s_new (PyTypeObject * pytype, PyObject * args, PyObject * kwds)
201 initval = aubioinitvalue[ptype]
203 %(ptype)s %(pname)s = %(initval)s;
205 # now the actual PyArg_Parse
208 static char *kwlist[] = { %(paramnames)s, NULL };
210 if (!PyArg_ParseTupleAndKeywords (args, kwds, "|%(pyparams)s", kwlist,
217 self = (Py_%(name)s *) pytype->tp_alloc (pytype, 0);
226 defval = aubiodefvalue[pname]
227 if ptype == 'char_t*':
230 self->%(pname)s = %(defval)s;
231 if (%(pname)s != NULL) {
232 self->%(pname)s = %(pname)s;
235 elif ptype == 'uint_t':
238 self->%(pname)s = %(defval)s;
240 self->%(pname)s = %(pname)s;
241 } else if (%(pname)s < 0) {
242 PyErr_SetString (PyExc_ValueError,
243 "can not use negative value for %(pname)s");
247 elif ptype == 'smpl_t':
250 self->%(pname)s = %(defval)s;
251 if (%(pname)s != %(defval)s) {
252 self->%(pname)s = %(pname)s;
256 write_msg ("ERROR, unknown type of parameter %s %s" % (ptype, pname) )
259 return (PyObject *) self;
262 AUBIO_INIT(%(name)s %(selfparams)s)
269 def gen_do_input_params(inputparams):
277 # build the parsing string for PyArg_ParseTuple
278 pytypes = "".join([aubio2pytypes[p['type']] for p in inputparams])
280 inputdefs = " /* input vectors python prototypes */\n"
281 for p in inputparams:
282 if p['type'] != 'uint_t':
283 inputdefs += " PyObject * " + p['name'] + "_obj;\n"
285 inputvecs = " /* input vectors prototypes */\n "
286 inputvecs += "\n ".join(map(lambda p: p['type'] + ' ' + p['name'] + ";", inputparams))
288 parseinput = " /* input vectors parsing */\n "
289 for p in inputparams:
291 if p['type'] != 'uint_t':
292 inputdef = p['name'] + "_obj"
295 converter = aubiovecfrompyobj[p['type']]
296 if p['type'] != 'uint_t':
297 parseinput += """%(inputvec)s = %(converter)s (%(inputdef)s);
299 if (%(inputvec)s == NULL) {
305 # build the string for the input objects references
307 for p in inputparams:
308 if p['type'] != 'uint_t':
309 inputreflist += [ "&" + p['name'] + "_obj" ]
311 inputreflist += [ "&" + p['name'] ]
312 inputrefs = ", ".join(inputreflist)
313 # end of inputs strings
314 return inputdefs, parseinput, inputrefs, inputvecs, pytypes
316 def gen_do_output_params(outputparams, name):
319 if len(outputparams):
320 outputvecs = " /* output vectors prototypes */\n"
321 for p in outputparams:
323 'name': p['name'], 'pytype': p['type'], 'autype': p['type'][:-3],
324 'length': defaultsizes[name].pop(0) }
325 if (p['type'] == 'uint_t*'):
326 outputvecs += ' uint_t' + ' ' + p['name'] + ";\n"
327 outputcreate += " %(name)s = 0;\n" % params
329 outputvecs += " " + p['type'] + ' ' + p['name'] + ";\n"
330 outputcreate += " /* creating output %(name)s as a new_%(autype)s of length %(length)s */\n" % params
331 outputcreate += " %(name)s = new_%(autype)s (%(length)s);\n" % params
334 if len(outputparams) > 1:
335 returnval += " PyObject *outputs = PyList_New(0);\n"
336 for p in outputparams:
337 returnval += " PyList_Append( outputs, (PyObject *)" + aubiovectopyobj[p['type']] + " (" + p['name'] + ")" +");\n"
338 returnval += " return outputs;"
339 elif len(outputparams) == 1:
340 if defaultsizes[name] == '1':
341 returnval += " return (PyObject *)PyFloat_FromDouble(" + p['name'] + "->data[0])"
343 returnval += " return (PyObject *)" + aubiovectopyobj[p['type']] + " (" + p['name'] + ")"
345 returnval += " Py_RETURN_NONE"
346 # end of output strings
347 return outputvecs, outputcreate, returnval
349 def gen_do(dofunc, name):
350 funcname = dofunc.split()[1].split('(')[0]
351 doparams = get_params_types_names(dofunc)
352 # make sure the first parameter is the object
353 assert doparams[0]['type'] == "aubio_"+name+"_t*", \
354 "method is not in 'aubio_<name>_t"
356 doparams = doparams[1:]
358 n_param = len(doparams)
360 if name in param_numbers.keys():
361 n_input_param, n_output_param = param_numbers[name]
363 n_input_param, n_output_param = 1, n_param - 1
365 assert n_output_param + n_input_param == n_param, "n_output_param + n_input_param != n_param for %s" % name
367 inputparams = doparams[:n_input_param]
368 outputparams = doparams[n_input_param:n_input_param + n_output_param]
370 inputdefs, parseinput, inputrefs, inputvecs, pytypes = gen_do_input_params(inputparams);
371 outputvecs, outputcreate, returnval = gen_do_output_params(outputparams, name)
373 # build strings for outputs
374 # build the parameters for the _do() call
375 doparams_string = "self->o"
377 if p['type'] == 'uint_t*':
378 doparams_string += ", &" + p['name']
380 doparams_string += ", " + p['name']
383 arg_parse_tuple = """\
384 if (!PyArg_ParseTuple (args, "%(pytypes)s", %(inputrefs)s)) {
390 # put it all together
392 /* function Py_%(name)s_do */
394 Py_%(name)s_do(Py_%(name)s * self, PyObject * args)
406 /* compute _do function */
407 %(funcname)s (%(doparams_string)s);
414 def gen_members(new_method, name):
415 newparams = get_params_types_names(new_method)
417 AUBIO_MEMBERS_START(%(name)s)""" % locals()
418 for param in newparams:
419 if param['type'] == 'char_t*':
421 {"%(pname)s", T_STRING, offsetof (Py_%(name)s, %(pname)s), READONLY, ""},""" \
422 % { 'pname': param['name'], 'ptype': param['type'], 'name': name}
423 elif param['type'] == 'uint_t':
425 {"%(pname)s", T_INT, offsetof (Py_%(name)s, %(pname)s), READONLY, ""},""" \
426 % { 'pname': param['name'], 'ptype': param['type'], 'name': name}
427 elif param['type'] == 'smpl_t':
429 {"%(pname)s", T_FLOAT, offsetof (Py_%(name)s, %(pname)s), READONLY, ""},""" \
430 % { 'pname': param['name'], 'ptype': param['type'], 'name': name}
432 write_msg ("-- ERROR, unknown member type ", param )
434 AUBIO_MEMBERS_STOP(%(name)s)
440 def gen_methods(get_methods, set_methods, name):
443 for method in set_methods:
444 method_name = get_name(method)
445 params = get_params_types_names(method)
446 out_type = get_return_type(method)
447 assert params[0]['type'] == "aubio_"+name+"_t*", \
448 "get method is not in 'aubio_<name>_t"
450 write_msg (params[1:])
451 setter_args = "self->o, " +",".join([p['name'] for p in params[1:]])
454 parse_args += p['type'] + " " + p['name'] + ";\n"
455 argmap = "".join([aubio2pytypes[p['type']] for p in params[1:]])
456 arglist = ", ".join(["&"+p['name'] for p in params[1:]])
458 if (!PyArg_ParseTuple (args, "%(argmap)s", %(arglist)s)) {
463 Py%(funcname)s (Py_%(objname)s *self, PyObject *args)
469 err = %(funcname)s (%(setter_args)s);
472 PyErr_SetString (PyExc_ValueError,
473 "error running %(funcname)s");
478 """ % {'funcname': method_name, 'objname': name,
479 'out_type': out_type, 'setter_args': setter_args, 'parse_args': parse_args }
480 shortname = method_name.split('aubio_'+name+'_')[-1]
482 {"%(shortname)s", (PyCFunction) Py%(method_name)s,
486 for method in get_methods:
487 method_name = get_name(method)
488 params = get_params_types_names(method)
489 out_type = get_return_type(method)
490 assert params[0]['type'] == "aubio_"+name+"_t*", \
491 "get method is not in 'aubio_<name>_t %s" % params[0]['type']
492 assert len(params) == 1, \
493 "get method has more than one parameter %s" % params
494 getter_args = "self->o"
495 returnval = "(PyObject *)" + aubiovectopyobj[out_type] + " (tmp)"
496 shortname = method_name.split('aubio_'+name+'_')[-1]
498 {"%(shortname)s", (PyCFunction) Py%(method_name)s,
503 Py%(funcname)s (Py_%(objname)s *self, PyObject *unused)
505 %(out_type)s tmp = %(funcname)s (%(getter_args)s);
506 return %(returnval)s;
508 """ % {'funcname': method_name, 'objname': name,
509 'out_type': out_type, 'getter_args': getter_args, 'returnval': returnval }
512 static PyMethodDef Py_%(name)s_methods[] = {
516 {NULL} /* sentinel */
521 def gen_finish(name):
524 AUBIO_TYPEOBJECT(%(name)s, "aubio.%(name)s")