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->block_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 # add block_size, synonim of hop_size
119 'block_size': 'Py_default_vector_length / 2',
120 # these should be alright
121 'samplerate': 'Py_aubio_default_samplerate',
122 # now for the non obvious ones
132 'method': '"default"',
147 aubiovecfrompyobj = {
148 'fvec_t*': 'PyAubio_ArrayToCFvec',
149 'cvec_t*': 'PyAubio_ArrayToCCvec',
150 'uint_t': '(uint_t)PyInt_AsLong',
155 'fvec_t*': 'PyAubio_CFvecToArray',
156 'cvec_t*': 'PyAubio_CCvecToPyCvec',
157 'smpl_t': 'PyFloat_FromDouble',
158 'uint_t*': 'PyInt_FromLong',
159 'uint_t': 'PyInt_FromLong',
162 def gen_new_init(newfunc, name):
163 newparams = get_params_types_names(newfunc)
164 # self->param1, self->param2, self->param3
166 selfparams = ', self->'+', self->'.join([p['name'] for p in newparams])
169 # "param1", "param2", "param3"
170 paramnames = ", ".join(["\""+p['name']+"\"" for p in newparams])
171 pyparams = "".join(map(lambda p: aubio2pytypes[p['type']], newparams))
172 paramrefs = ", ".join(["&" + p['name'] for p in newparams])
174 // WARNING: this file is generated, DO NOT EDIT
176 // WARNING: if you haven't read the first line yet, please do so
177 #include "aubiowraphell.h"
182 aubio_%(name)s_t * o;
193 static char Py_%(name)s_doc[] = "%(name)s object";
196 Py_%(name)s_new (PyTypeObject * pytype, PyObject * args, PyObject * kwds)
203 initval = aubioinitvalue[ptype]
205 %(ptype)s %(pname)s = %(initval)s;
207 # now the actual PyArg_Parse
210 static char *kwlist[] = { %(paramnames)s, NULL };
212 if (!PyArg_ParseTupleAndKeywords (args, kwds, "|%(pyparams)s", kwlist,
219 self = (Py_%(name)s *) pytype->tp_alloc (pytype, 0);
228 defval = aubiodefvalue[pname]
229 if ptype == 'char_t*':
232 self->%(pname)s = %(defval)s;
233 if (%(pname)s != NULL) {
234 self->%(pname)s = %(pname)s;
237 elif ptype == 'uint_t':
240 self->%(pname)s = %(defval)s;
242 self->%(pname)s = %(pname)s;
243 } else if (%(pname)s < 0) {
244 PyErr_SetString (PyExc_ValueError,
245 "can not use negative value for %(pname)s");
249 elif ptype == 'smpl_t':
252 self->%(pname)s = %(defval)s;
253 if (%(pname)s != %(defval)s) {
254 self->%(pname)s = %(pname)s;
258 write_msg ("ERROR, unknown type of parameter %s %s" % (ptype, pname) )
261 return (PyObject *) self;
264 AUBIO_INIT(%(name)s %(selfparams)s)
271 def gen_do_input_params(inputparams):
279 # build the parsing string for PyArg_ParseTuple
280 pytypes = "".join([aubio2pytypes[p['type']] for p in inputparams])
282 inputdefs = " /* input vectors python prototypes */\n"
283 for p in inputparams:
284 if p['type'] != 'uint_t':
285 inputdefs += " PyObject * " + p['name'] + "_obj;\n"
287 inputvecs = " /* input vectors prototypes */\n "
288 inputvecs += "\n ".join(map(lambda p: p['type'] + ' ' + p['name'] + ";", inputparams))
290 parseinput = " /* input vectors parsing */\n "
291 for p in inputparams:
293 if p['type'] != 'uint_t':
294 inputdef = p['name'] + "_obj"
297 converter = aubiovecfrompyobj[p['type']]
298 if p['type'] != 'uint_t':
299 parseinput += """%(inputvec)s = %(converter)s (%(inputdef)s);
301 if (%(inputvec)s == NULL) {
307 # build the string for the input objects references
309 for p in inputparams:
310 if p['type'] != 'uint_t':
311 inputreflist += [ "&" + p['name'] + "_obj" ]
313 inputreflist += [ "&" + p['name'] ]
314 inputrefs = ", ".join(inputreflist)
315 # end of inputs strings
316 return inputdefs, parseinput, inputrefs, inputvecs, pytypes
318 def gen_do_output_params(outputparams, name):
321 if len(outputparams):
322 outputvecs = " /* output vectors prototypes */\n"
323 for p in outputparams:
325 'name': p['name'], 'pytype': p['type'], 'autype': p['type'][:-3],
326 'length': defaultsizes[name].pop(0) }
327 if (p['type'] == 'uint_t*'):
328 outputvecs += ' uint_t' + ' ' + p['name'] + ";\n"
329 outputcreate += " %(name)s = 0;\n" % params
331 outputvecs += " " + p['type'] + ' ' + p['name'] + ";\n"
332 outputcreate += " /* creating output %(name)s as a new_%(autype)s of length %(length)s */\n" % params
333 outputcreate += " %(name)s = new_%(autype)s (%(length)s);\n" % params
336 if len(outputparams) > 1:
337 returnval += " PyObject *outputs = PyList_New(0);\n"
338 for p in outputparams:
339 returnval += " PyList_Append( outputs, (PyObject *)" + aubiovectopyobj[p['type']] + " (" + p['name'] + ")" +");\n"
340 returnval += " return outputs;"
341 elif len(outputparams) == 1:
342 if defaultsizes[name] == '1':
343 returnval += " return (PyObject *)PyFloat_FromDouble(" + p['name'] + "->data[0])"
345 returnval += " return (PyObject *)" + aubiovectopyobj[p['type']] + " (" + p['name'] + ")"
347 returnval += " Py_RETURN_NONE"
348 # end of output strings
349 return outputvecs, outputcreate, returnval
351 def gen_do(dofunc, name):
352 funcname = dofunc.split()[1].split('(')[0]
353 doparams = get_params_types_names(dofunc)
354 # make sure the first parameter is the object
355 assert doparams[0]['type'] == "aubio_"+name+"_t*", \
356 "method is not in 'aubio_<name>_t"
358 doparams = doparams[1:]
360 n_param = len(doparams)
362 if name in param_numbers.keys():
363 n_input_param, n_output_param = param_numbers[name]
365 n_input_param, n_output_param = 1, n_param - 1
367 assert n_output_param + n_input_param == n_param, "n_output_param + n_input_param != n_param for %s" % name
369 inputparams = doparams[:n_input_param]
370 outputparams = doparams[n_input_param:n_input_param + n_output_param]
372 inputdefs, parseinput, inputrefs, inputvecs, pytypes = gen_do_input_params(inputparams);
373 outputvecs, outputcreate, returnval = gen_do_output_params(outputparams, name)
375 # build strings for outputs
376 # build the parameters for the _do() call
377 doparams_string = "self->o"
379 if p['type'] == 'uint_t*':
380 doparams_string += ", &" + p['name']
382 doparams_string += ", " + p['name']
385 arg_parse_tuple = """\
386 if (!PyArg_ParseTuple (args, "%(pytypes)s", %(inputrefs)s)) {
392 # put it all together
394 /* function Py_%(name)s_do */
396 Py_%(name)s_do(Py_%(name)s * self, PyObject * args)
408 /* compute _do function */
409 %(funcname)s (%(doparams_string)s);
416 def gen_members(new_method, name):
417 newparams = get_params_types_names(new_method)
419 AUBIO_MEMBERS_START(%(name)s)""" % locals()
420 for param in newparams:
421 if param['type'] == 'char_t*':
423 {"%(pname)s", T_STRING, offsetof (Py_%(name)s, %(pname)s), READONLY, ""},""" \
424 % { 'pname': param['name'], 'ptype': param['type'], 'name': name}
425 elif param['type'] == 'uint_t':
427 {"%(pname)s", T_INT, offsetof (Py_%(name)s, %(pname)s), READONLY, ""},""" \
428 % { 'pname': param['name'], 'ptype': param['type'], 'name': name}
429 elif param['type'] == 'smpl_t':
431 {"%(pname)s", T_FLOAT, offsetof (Py_%(name)s, %(pname)s), READONLY, ""},""" \
432 % { 'pname': param['name'], 'ptype': param['type'], 'name': name}
434 write_msg ("-- ERROR, unknown member type ", param )
436 AUBIO_MEMBERS_STOP(%(name)s)
442 def gen_methods(get_methods, set_methods, name):
445 for method in set_methods:
446 method_name = get_name(method)
447 params = get_params_types_names(method)
448 out_type = get_return_type(method)
449 assert params[0]['type'] == "aubio_"+name+"_t*", \
450 "get method is not in 'aubio_<name>_t"
452 write_msg (params[1:])
453 setter_args = "self->o, " +",".join([p['name'] for p in params[1:]])
456 parse_args += p['type'] + " " + p['name'] + ";\n"
457 argmap = "".join([aubio2pytypes[p['type']] for p in params[1:]])
458 arglist = ", ".join(["&"+p['name'] for p in params[1:]])
460 if (!PyArg_ParseTuple (args, "%(argmap)s", %(arglist)s)) {
465 Py%(funcname)s (Py_%(objname)s *self, PyObject *args)
471 err = %(funcname)s (%(setter_args)s);
474 PyErr_SetString (PyExc_ValueError,
475 "error running %(funcname)s");
480 """ % {'funcname': method_name, 'objname': name,
481 'out_type': out_type, 'setter_args': setter_args, 'parse_args': parse_args }
482 shortname = method_name.split('aubio_'+name+'_')[-1]
484 {"%(shortname)s", (PyCFunction) Py%(method_name)s,
488 for method in get_methods:
489 method_name = get_name(method)
490 params = get_params_types_names(method)
491 out_type = get_return_type(method)
492 assert params[0]['type'] == "aubio_"+name+"_t*", \
493 "get method is not in 'aubio_<name>_t %s" % params[0]['type']
494 assert len(params) == 1, \
495 "get method has more than one parameter %s" % params
496 getter_args = "self->o"
497 returnval = "(PyObject *)" + aubiovectopyobj[out_type] + " (tmp)"
498 shortname = method_name.split('aubio_'+name+'_')[-1]
500 {"%(shortname)s", (PyCFunction) Py%(method_name)s,
505 Py%(funcname)s (Py_%(objname)s *self, PyObject *unused)
507 %(out_type)s tmp = %(funcname)s (%(getter_args)s);
508 return %(returnval)s;
510 """ % {'funcname': method_name, 'objname': name,
511 'out_type': out_type, 'getter_args': getter_args, 'returnval': returnval }
514 static PyMethodDef Py_%(name)s_methods[] = {
518 {NULL} /* sentinel */
523 def gen_finish(name):
526 AUBIO_TYPEOBJECT(%(name)s, "aubio.%(name)s")