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.
28 # do function: for now, only the following pattern is supported:
29 # void aubio_<foo>_do (aubio_foo_t * o,
30 # [input1_t * input, [output1_t * output, ..., output3_t * output]]);
31 # There is no way of knowing that output1 is actually input2. In the future,
32 # const could be used for the inputs in the C prototypes.
36 # uncomment out for debugging
41 return ['foo*', 'name'] """
43 type_arg = {'type': l[0], 'name': l[1]}
44 # ['foo', '*name'] -> ['foo*', 'name']
45 if l[-1].startswith('*'):
46 #return [l[0]+'*', l[1][1:]]
47 type_arg['type'] = l[0] + '*'
48 type_arg['name'] = l[1][1:]
49 # ['foo', '*', 'name'] -> ['foo*', 'name']
51 #return [l[0]+l[1], l[2]]
52 type_arg['type'] = l[0]+l[1]
53 type_arg['name'] = l[2]
59 def get_params(proto):
60 """ get the list of parameters from a function prototype
61 example: proto = "int main (int argc, char ** argv)"
62 returns: ['int argc', 'char ** argv']
65 paramregex = re.compile('[\(, ](\w+ \*?\*? ?\w+)[, \)]')
66 return paramregex.findall(proto)
68 def get_params_types_names(proto):
69 """ get the list of parameters from a function prototype
70 example: proto = "int main (int argc, char ** argv)"
71 returns: [['int', 'argc'], ['char **','argv']]
73 return list(map(split_type, get_params(proto)))
75 def get_return_type(proto):
77 paramregex = re.compile('(\w+ ?\*?).*')
78 outputs = paramregex.findall(proto)
79 assert len(outputs) == 1
80 return outputs[0].replace(' ', '')
83 name = proto.split()[1].split('(')[0]
84 return name.replace('*','')
86 # the important bits: the size of the output for each objects. this data should
87 # move into the C library at some point.
89 'resampler': ['input->length * self->ratio'],
94 'pitchschmitt': ['1'],
98 'tss': ['self->buf_size', 'self->buf_size'],
99 'mfcc': ['self->n_coeffs'],
100 'beattracking': ['self->hop_size'],
103 'source': ['self->hop_size', '1'],
104 'sampler': ['self->hop_size'],
105 'wavetable': ['self->hop_size'],
108 # default value for variables
118 # we have some clean up to do
119 'buf_size': 'Py_default_vector_length',
121 'hop_size': 'Py_default_vector_length / 2',
122 # these should be alright
123 'samplerate': 'Py_aubio_default_samplerate',
124 # now for the non obvious ones
134 'method': '"default"',
150 aubiovecfrompyobj = {
151 'fvec_t*': 'PyAubio_ArrayToCFvec',
152 'cvec_t*': 'PyAubio_ArrayToCCvec',
153 'uint_t': '(uint_t)PyInt_AsLong',
158 'fvec_t*': 'PyAubio_CFvecToArray',
159 'cvec_t*': 'PyAubio_CCvecToPyCvec',
160 'smpl_t': 'PyFloat_FromDouble',
161 'uint_t*': 'PyInt_FromLong',
162 'uint_t': 'PyInt_FromLong',
165 def gen_new_init(newfunc, name):
166 newparams = get_params_types_names(newfunc)
167 # self->param1, self->param2, self->param3
169 selfparams = ', self->'+', self->'.join([p['name'] for p in newparams])
172 # "param1", "param2", "param3"
173 paramnames = ", ".join(["\""+p['name']+"\"" for p in newparams])
174 pyparams = "".join(map(lambda p: aubio2pytypes[p['type']], newparams))
175 paramrefs = ", ".join(["&" + p['name'] for p in newparams])
177 // WARNING: this file is generated, DO NOT EDIT
179 // WARNING: if you haven't read the first line yet, please do so
180 #include "aubiowraphell.h"
185 aubio_%(name)s_t * o;
196 static char Py_%(name)s_doc[] = "%(name)s object";
199 Py_%(name)s_new (PyTypeObject * pytype, PyObject * args, PyObject * kwds)
206 initval = aubioinitvalue[ptype]
208 %(ptype)s %(pname)s = %(initval)s;
210 # now the actual PyArg_Parse
213 static char *kwlist[] = { %(paramnames)s, NULL };
215 if (!PyArg_ParseTupleAndKeywords (args, kwds, "|%(pyparams)s", kwlist,
222 self = (Py_%(name)s *) pytype->tp_alloc (pytype, 0);
231 defval = aubiodefvalue[pname]
232 if ptype == 'char_t*':
235 self->%(pname)s = %(defval)s;
236 if (%(pname)s != NULL) {
237 self->%(pname)s = %(pname)s;
240 elif ptype == 'uint_t':
243 self->%(pname)s = %(defval)s;
244 if ((sint_t)%(pname)s > 0) {
245 self->%(pname)s = %(pname)s;
246 } else if ((sint_t)%(pname)s < 0) {
247 PyErr_SetString (PyExc_ValueError,
248 "can not use negative value for %(pname)s");
252 elif ptype == 'smpl_t':
255 self->%(pname)s = %(defval)s;
256 if (%(pname)s != %(defval)s) {
257 self->%(pname)s = %(pname)s;
261 write_msg ("ERROR, unknown type of parameter %s %s" % (ptype, pname) )
264 return (PyObject *) self;
267 AUBIO_INIT(%(name)s %(selfparams)s)
274 def gen_do_input_params(inputparams):
282 # build the parsing string for PyArg_ParseTuple
283 pytypes = "".join([aubio2pytypes[p['type']] for p in inputparams])
285 inputdefs = " /* input vectors python prototypes */\n"
286 for p in inputparams:
287 if p['type'] != 'uint_t':
288 inputdefs += " PyObject * " + p['name'] + "_obj;\n"
290 inputvecs = " /* input vectors prototypes */\n "
291 inputvecs += "\n ".join(map(lambda p: p['type'] + ' ' + p['name'] + ";", inputparams))
293 parseinput = " /* input vectors parsing */\n "
294 for p in inputparams:
296 if p['type'] != 'uint_t':
297 inputdef = p['name'] + "_obj"
300 converter = aubiovecfrompyobj[p['type']]
301 if p['type'] != 'uint_t':
302 parseinput += """%(inputvec)s = %(converter)s (%(inputdef)s);
304 if (%(inputvec)s == NULL) {
310 # build the string for the input objects references
312 for p in inputparams:
313 if p['type'] != 'uint_t':
314 inputreflist += [ "&" + p['name'] + "_obj" ]
316 inputreflist += [ "&" + p['name'] ]
317 inputrefs = ", ".join(inputreflist)
318 # end of inputs strings
319 return inputdefs, parseinput, inputrefs, inputvecs, pytypes
321 def gen_do_output_params(outputparams, name):
324 if len(outputparams):
325 outputvecs = " /* output vectors prototypes */\n"
326 for p in outputparams:
328 'name': p['name'], 'pytype': p['type'], 'autype': p['type'][:-3],
329 'length': defaultsizes[name].pop(0) }
330 if (p['type'] == 'uint_t*'):
331 outputvecs += ' uint_t' + ' ' + p['name'] + ";\n"
332 outputcreate += " %(name)s = 0;\n" % params
334 outputvecs += " " + p['type'] + ' ' + p['name'] + ";\n"
335 outputcreate += " /* creating output %(name)s as a new_%(autype)s of length %(length)s */\n" % params
336 outputcreate += " %(name)s = new_%(autype)s (%(length)s);\n" % params
339 if len(outputparams) > 1:
340 returnval += " PyObject *outputs = PyList_New(0);\n"
341 for p in outputparams:
342 returnval += " PyList_Append( outputs, (PyObject *)" + aubiovectopyobj[p['type']] + " (" + p['name'] + ")" +");\n"
343 returnval += " return outputs;"
344 elif len(outputparams) == 1:
345 if defaultsizes[name] == '1':
346 returnval += " return (PyObject *)PyFloat_FromDouble(" + p['name'] + "->data[0])"
348 returnval += " return (PyObject *)" + aubiovectopyobj[p['type']] + " (" + p['name'] + ")"
350 returnval += " Py_RETURN_NONE"
351 # end of output strings
352 return outputvecs, outputcreate, returnval
354 def gen_do(dofunc, name):
355 funcname = dofunc.split()[1].split('(')[0]
356 doparams = get_params_types_names(dofunc)
357 # make sure the first parameter is the object
358 assert doparams[0]['type'] == "aubio_"+name+"_t*", \
359 "method is not in 'aubio_<name>_t"
361 doparams = doparams[1:]
363 n_param = len(doparams)
365 if name in param_numbers.keys():
366 n_input_param, n_output_param = param_numbers[name]
368 n_input_param, n_output_param = 1, n_param - 1
370 assert n_output_param + n_input_param == n_param, "n_output_param + n_input_param != n_param for %s" % name
372 inputparams = doparams[:n_input_param]
373 outputparams = doparams[n_input_param:n_input_param + n_output_param]
375 inputdefs, parseinput, inputrefs, inputvecs, pytypes = gen_do_input_params(inputparams);
376 outputvecs, outputcreate, returnval = gen_do_output_params(outputparams, name)
378 # build strings for outputs
379 # build the parameters for the _do() call
380 doparams_string = "self->o"
382 if p['type'] == 'uint_t*':
383 doparams_string += ", &" + p['name']
385 doparams_string += ", " + p['name']
388 arg_parse_tuple = """\
389 if (!PyArg_ParseTuple (args, "%(pytypes)s", %(inputrefs)s)) {
395 # put it all together
397 /* function Py_%(name)s_do */
399 Py_%(name)s_do(Py_%(name)s * self, PyObject * args)
411 /* compute _do function */
412 %(funcname)s (%(doparams_string)s);
419 def gen_members(new_method, name):
420 newparams = get_params_types_names(new_method)
422 AUBIO_MEMBERS_START(%(name)s)""" % locals()
423 for param in newparams:
424 if param['type'] == 'char_t*':
426 {"%(pname)s", T_STRING, offsetof (Py_%(name)s, %(pname)s), READONLY, ""},""" \
427 % { 'pname': param['name'], 'ptype': param['type'], 'name': name}
428 elif param['type'] == 'uint_t':
430 {"%(pname)s", T_INT, offsetof (Py_%(name)s, %(pname)s), READONLY, ""},""" \
431 % { 'pname': param['name'], 'ptype': param['type'], 'name': name}
432 elif param['type'] == 'smpl_t':
434 {"%(pname)s", T_FLOAT, offsetof (Py_%(name)s, %(pname)s), READONLY, ""},""" \
435 % { 'pname': param['name'], 'ptype': param['type'], 'name': name}
437 write_msg ("-- ERROR, unknown member type ", param )
439 AUBIO_MEMBERS_STOP(%(name)s)
445 def gen_methods(get_methods, set_methods, name):
448 for method in set_methods:
449 method_name = get_name(method)
450 params = get_params_types_names(method)
451 out_type = get_return_type(method)
452 assert params[0]['type'] == "aubio_"+name+"_t*", \
453 "get method is not in 'aubio_<name>_t"
455 write_msg (params[1:])
456 setter_args = "self->o, " +",".join([p['name'] for p in params[1:]])
459 parse_args += p['type'] + " " + p['name'] + ";\n"
460 argmap = "".join([aubio2pytypes[p['type']] for p in params[1:]])
461 arglist = ", ".join(["&"+p['name'] for p in params[1:]])
463 if (!PyArg_ParseTuple (args, "%(argmap)s", %(arglist)s)) {
468 Py%(funcname)s (Py_%(objname)s *self, PyObject *args)
474 err = %(funcname)s (%(setter_args)s);
477 PyErr_SetString (PyExc_ValueError,
478 "error running %(funcname)s");
483 """ % {'funcname': method_name, 'objname': name,
484 'out_type': out_type, 'setter_args': setter_args, 'parse_args': parse_args }
485 shortname = method_name.split('aubio_'+name+'_')[-1]
487 {"%(shortname)s", (PyCFunction) Py%(method_name)s,
491 for method in get_methods:
492 method_name = get_name(method)
493 params = get_params_types_names(method)
494 out_type = get_return_type(method)
495 assert params[0]['type'] == "aubio_"+name+"_t*", \
496 "get method is not in 'aubio_<name>_t %s" % params[0]['type']
497 assert len(params) == 1, \
498 "get method has more than one parameter %s" % params
499 getter_args = "self->o"
500 returnval = "(PyObject *)" + aubiovectopyobj[out_type] + " (tmp)"
501 shortname = method_name.split('aubio_'+name+'_')[-1]
503 {"%(shortname)s", (PyCFunction) Py%(method_name)s,
508 Py%(funcname)s (Py_%(objname)s *self, PyObject *unused)
510 %(out_type)s tmp = %(funcname)s (%(getter_args)s);
511 return %(returnval)s;
513 """ % {'funcname': method_name, 'objname': name,
514 'out_type': out_type, 'getter_args': getter_args, 'returnval': returnval }
517 static PyMethodDef Py_%(name)s_methods[] = {
521 {NULL} /* sentinel */
526 def gen_finish(name):
529 AUBIO_TYPEOBJECT(%(name)s, "aubio.%(name)s")