source: interfaces/python/gen_pyobject.py @ ec1ce52

feature/autosinkfeature/cnnfeature/cnn_orgfeature/constantqfeature/crepefeature/crepe_orgfeature/pitchshiftfeature/pydocstringsfeature/timestretchfix/ffmpeg5pitchshiftsamplertimestretchyinfft+
Last change on this file since ec1ce52 was ec1ce52, checked in by Paul Brossier <piem@piem.org>, 15 years ago

added crazy generator

  • Property mode set to 100644
File size: 8.8 KB
Line 
1#! /usr/bin/python
2
3""" This madness of code is used to generate the C code of the python interface
4to aubio. Don't try this at home.
5
6The list of typedefs and functions is obtained from the command line 'cpp
7aubio.h'. This list is then used to parse all the functions about this object.
8
9I hear the ones asking "why not use swig, or cython, or something like that?"
10
11The requirements for this extension are the following:
12
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
15
16I haven't met any python interface generator that can meet both these
17requirements. If you know of one, please let me know, it will spare me
18maintaining this bizarre file.
19"""
20
21# TODO
22# do function: for now, only the following pattern is supported:
23# void aubio_<foo>_do (aubio_foo_t * o,
24#       [input1_t * input, [output1_t * output, ..., output3_t * output]]);
25# There is no way of knowing that output1 is actually input2. In the future,
26# const could be used for the inputs in the C prototypes.
27
28# the important bits: the size of the output for each objects. this data should
29# move into the C library at some point.
30defaultsizes = {
31    'resampler':    ('input->length * self->ratio', 'input->channels'),
32    'onsetdetection': ('1', 'self->channels'),
33    'onset':        ('1', 'self->channels'),
34    'pitchyin':     ('1', 'in->channels'),
35    'pitchyinfft':  ('1', 'in->channels'),
36    'pitchschmitt': ('1', 'in->channels'),
37    'pitchmcomb':   ('1', 'self->channels'),
38    'pitchfcomb':   ('1', 'self->channels'),
39    'pitch':        ('1', 'self->channels'),
40    'tss':          ('self->hop_s', 'self->channels'),
41    'mfcc':         ('self->n_coeffs', 'in->channels'),
42    'beattracking': ('self->winlen', 'self->channels'),
43    'tempo':        ('self->buf_size', 'self->channels'),
44    'peakpicker':   ('1', 'self->channels'),
45}
46
47# default value for variables
48aubioinitvalue = {
49    'uint_t': 0,
50    'smpl_t': 0,
51    'lsmp_t': 0.,
52    'char_t*': 'NULL',
53    }
54
55aubiodefvalue = {
56    # we have some clean up to do
57    'win_s': 'Py_default_vector_length', 
58    'bufsize': 'Py_default_vector_length', 
59    'buf_size': 'Py_default_vector_length', 
60    'winlen': 'Py_default_vector_length', 
61    # and here too
62    'hop_s': 'Py_default_vector_length / 2', 
63    'hopsize': 'Py_default_vector_length / 2', 
64    'hop_size': 'Py_default_vector_length / 2', 
65    # these should be alright
66    'channels': 'Py_default_vector_channels', 
67    'samplerate': 'Py_aubio_default_samplerate', 
68    # now for the non obvious ones
69    'n_filters': '40', 
70    'n_coeffs': '13', 
71    'nelems': '10',
72    'flow': '0.', 
73    'fhig': '1.', 
74    'ilow': '0.', 
75    'ihig': '1.', 
76    'thrs': '0.5',
77    'ratio': '0.5',
78    'threshold': '0.5',
79    'mode': '"default"',
80    'onset_mode': '"default"',
81    'type': '0',
82    }
83
84# aubio to python
85aubio2pytypes = {
86    'uint_t': 'I',
87    'smpl_t': 'I',
88    'lsmp_t': 'I',
89    'fvec_t': 'O',
90    'cvec_t': 'O',
91    'char_t*': 's',
92}
93
94# aubio to pyaubio
95aubio2pyaubio = {
96    'fvec_t': 'Py_fvec',
97    'cvec_t': 'Py_cvec',
98}
99
100# array to aubio
101aubiovecfrompyobj = {
102    'fvec_t': 'PyAubio_ArrayToFvec',
103    'cvec_t': 'PyAubio_ArrayToCvec',
104}
105
106# aubio to array
107aubiovectopyobj = {
108    'fvec_t': 'PyAubio_FvecToArray',
109    'cvec_t': 'PyAubio_CvecToArray',
110}
111
112def get_newparams(newfunc):
113    newparams = [[p.split()[0], p.split()[-1]]
114            for p in newfunc.split('(')[1].split(')')[0].split(',')]
115    # make char_t a pointer
116    return map(lambda x: [x[0].replace('char_t', 'char_t*'), x[1]], newparams)
117
118def gen_new_init(newfunc, name):
119    newparams = get_newparams(newfunc)
120    # self->param1, self->param2, self->param3
121    selfparams = ', self->'.join([p[1] for p in newparams])
122    # "param1", "param2", "param3"
123    paramnames = ", ".join(["\""+p[1]+"\"" for p in newparams])
124    pyparams = "".join(map(lambda p: aubio2pytypes[p[0]], newparams))
125    paramrefs = ", ".join(["&" + p[1] for p in newparams])
126    s = """\
127// WARNING: this file is generated, DO NOT EDIT
128#include "aubiowraphell.h"
129
130typedef struct
131{
132  PyObject_HEAD
133  aubio_%(name)s_t * o;
134""" % locals()
135    for ptype, pname in newparams:
136        s += """\
137  %(ptype)s %(pname)s;
138""" % locals()
139    s += """\
140} Py_%(name)s;
141
142static char Py_%(name)s_doc[] = "%(name)s object";
143
144static PyObject *
145Py_%(name)s_new (PyTypeObject * pytype, PyObject * args, PyObject * kwds)
146{
147""" % locals()
148    for ptype, pname in newparams:
149        defval = aubioinitvalue[ptype]
150        s += """\
151  %(ptype)s %(pname)s = %(defval)s;
152""" % locals()
153    s += """\
154  Py_%(name)s *self;
155  static char *kwlist[] = { %(paramnames)s, NULL };
156
157  if (!PyArg_ParseTupleAndKeywords (args, kwds, "|%(pyparams)s", kwlist,
158          %(paramrefs)s)) {
159    return NULL;
160  }
161
162  self = (Py_%(name)s *) pytype->tp_alloc (pytype, 0);
163
164  if (self == NULL) {
165    return NULL;
166  }
167""" % locals()
168    # TODO add parameters default values
169    for ptype, pname in newparams:
170        defval = aubiodefvalue[pname]
171        s += """\
172
173  self->%(pname)s = %(defval)s;
174  if (%(pname)s > 0) {
175    self->%(pname)s = %(pname)s;
176  } else if (%(pname)s < 0) {
177    PyErr_SetString (PyExc_ValueError,
178        "can not use negative window size");
179    return NULL;
180  }
181""" % locals()
182    s += """\
183
184  return (PyObject *) self;
185}
186
187AUBIO_INIT(%(name)s, self->%(selfparams)s)
188
189AUBIO_DEL(%(name)s)
190
191""" % locals()
192    return s
193
194def gen_do(dofunc, name):
195    funcname = dofunc.split()[1].split('(')[0]
196    doparams = [p.split() for p in dofunc.split('(')[1].split(')')[0].split(',')]
197    # make sure the first parameter is the object
198    assert doparams[0][0] == "aubio_"+name+"_t", \
199        "method is not in 'aubio_<name>_t"
200    # and remove it
201    doparams = doparams[1:]
202    # guess the input/output params, assuming we have less than 3
203    assert len(doparams) > 0, \
204        "no parameters for function do in object %s" % name
205    #assert (len(doparams) <= 2), \
206    #    "more than 3 parameters for do in object %s" % name
207
208    # build strings for inputs, assuming there is only one input
209    inputparams = [doparams[0]]
210    # build the parsing string for PyArg_ParseTuple
211    pytypes = "".join([aubio2pytypes[p[0]] for p in doparams[0:1]])
212    inputdefs = "\n  ".join(["PyObject * " + p[-1] + "_obj;" for p in inputparams])
213    inputvecs = "\n  ".join(map(lambda p: \
214                aubio2pyaubio[p[0]]+" * " + p[-1] + ";", inputparams))
215    parseinput = ""
216    for p in inputparams:
217        inputvec = p[-1]
218        inputdef = p[-1] + "_obj"
219        converter = aubiovecfrompyobj[p[0]]
220        parseinput += """%(inputvec)s = %(converter)s (%(inputdef)s);
221
222  if (%(inputvec)s == NULL) {
223    return NULL;
224  }""" % locals()
225    # build the string for the input objects references
226    inputrefs = ", ".join(["&" + p[-1] + "_obj" for p in inputparams])
227    # end of inputs strings
228
229    # build strings for outputs
230    outputparams = doparams[1:]
231    if len(doparams) > 1:
232        #assert len(outputparams) == 1, \
233        #    "too many output parameters"
234        outputvecs = "\n  ".join([aubio2pyaubio[p[0]]+" * " + p[-1] + ";" for p in outputparams])
235        outputcreate = """\
236AUBIO_NEW_VEC(%(name)s, %(pytype)s, %(length)s, %(channels)s)
237  %(name)s->o = new_%(autype)s (%(length)s, %(channels)s);""" % \
238    {'name': p[-1], 'pytype': aubio2pyaubio[p[0]], 'autype': p[0][:-2],
239        'length': defaultsizes[name][0], 'channels': defaultsizes[name][1]}
240        returnval = "(PyObject *)" + aubiovectopyobj[p[0]] + " (" + p[-1] + ")"
241    else:
242        # no output
243        outputvecs = ""
244        outputcreate = ""
245        #returnval = "Py_None";
246        returnval = "(PyObject *)" + aubiovectopyobj[p[0]] + " (" + p[-1] + ")"
247    # end of output strings
248
249    # build the parameters for the  _do() call
250    doparams_string = "self->o, " + ", ".join([p[-1]+"->o" for p in doparams])
251
252    # put it all together
253    s = """\
254static PyObject *
255Py_%(name)s_do(Py_%(name)s * self, PyObject * args)
256{
257  %(inputdefs)s
258  %(inputvecs)s
259  %(outputvecs)s
260
261  if (!PyArg_ParseTuple (args, "%(pytypes)s", %(inputrefs)s)) {
262    return NULL;
263  }
264
265  %(parseinput)s
266 
267  %(outputcreate)s
268
269  /* compute _do function */
270  %(funcname)s (%(doparams_string)s);
271
272  return %(returnval)s;
273}
274""" % locals()
275    return s
276
277def gen_members(new_method, name):
278    newparams = get_newparams(new_method)
279    s = """
280AUBIO_MEMBERS_START(%(name)s)""" % locals()
281    for param in newparams:
282        s += """
283  {"%(pname)s", T_INT, offsetof (Py_%(name)s, %(pname)s), READONLY, ""},""" \
284        % { 'pname': param[1], 'ptype': param[0], 'name': name}
285    s += """
286AUBIO_MEMBERS_STOP(%(name)s)
287
288""" % locals()
289    return s
290
291def gen_methods(get_methods, set_methods, name):
292    # TODO add methods
293    s = """\
294static PyMethodDef Py_%(name)s_methods[] = {
295""" % locals() 
296    # TODO add PyMethodDefs
297    s += """\
298  {NULL} /* sentinel */
299};
300""" % locals() 
301    return s
302
303def gen_finish(name):
304    s = """\
305
306AUBIO_TYPEOBJECT(%(name)s, "aubio.%(name)s")
307""" % locals()
308    return s
Note: See TracBrowser for help on using the repository browser.