Changeset 90077e4


Ignore:
Timestamp:
Nov 15, 2009, 3:19:45 PM (10 years ago)
Author:
Paul Brossier <piem@piem.org>
Branches:
feature/autosink, feature/constantq, feature/pitchshift, feature/pydocstrings, feature/timestretch, master, pitchshift, sampler, timestretch, yinfft+
Children:
449bff6
Parents:
4bc098c
Message:

gen_pyobject.py: simplify using regex, add PyMethodDefs?

File:
1 edited

Legend:

Unmodified
Added
Removed
  • interfaces/python/gen_pyobject.py

    r4bc098c r90077e4  
    2626# const could be used for the inputs in the C prototypes.
    2727
     28def split_type(arg):
     29    """ arg = 'foo *name'
     30        return ['foo*', 'name'] """
     31    l = arg.split()
     32    # ['foo', '*name'] -> ['foo*', 'name']
     33    if l[-1].startswith('*'):
     34        return [l[0]+'*', l[1][1:]]
     35    # ['foo', '*', 'name'] -> ['foo*', 'name']
     36    if len(l) == 3:
     37        return [l[0]+l[1], l[2]]
     38    else:
     39        return l
     40
     41def get_params(proto):
     42    """ get the list of parameters from a function prototype
     43    example: proto = "int main (int argc, char ** argv)"
     44    returns: ['int argc', 'char ** argv']
     45    """
     46    import re
     47    paramregex = re.compile('[\(, ](\w+ \*?\*? ?\w+)[, \)]')
     48    return paramregex.findall(proto)
     49
     50def get_params_types_names(proto):
     51    """ get the list of parameters from a function prototype
     52    example: proto = "int main (int argc, char ** argv)"
     53    returns: [['int', 'argc'], ['char **','argv']]
     54    """
     55    return map(split_type, get_params(proto))
     56
     57def get_return_type(proto):
     58    import re
     59    paramregex = re.compile('(\w+ ?\*?).*')
     60    outputs = paramregex.findall(proto)
     61    assert len(outputs) == 1
     62    return outputs[0].replace(' ', '')
     63
     64def get_name(proto):
     65    name = proto.split()[1].split('(')[0]
     66    return name.replace('*','')
     67
    2868# the important bits: the size of the output for each objects. this data should
    2969# move into the C library at some point.
    3070defaultsizes = {
    3171    'resampler':    ('input->length * self->ratio', 'input->channels'),
    32     'specdesc':     ('1', 'self->channels'),
     72    'specdesc':     ('1', 'fftgrain->channels'),
    3373    'onset':        ('1', 'self->channels'),
    3474    'pitchyin':     ('1', 'in->channels'),
     
    79119    'smpl_t': 'I',
    80120    'lsmp_t': 'I',
    81     'fvec_t': 'O',
    82     'cvec_t': 'O',
     121    'fvec_t*': 'O',
     122    'cvec_t*': 'O',
    83123    'char_t*': 's',
    84124}
     
    86126# aubio to pyaubio
    87127aubio2pyaubio = {
    88     'fvec_t': 'Py_fvec',
    89     'cvec_t': 'Py_cvec',
     128    'fvec_t*': 'Py_fvec',
     129    'cvec_t*': 'Py_cvec',
    90130}
    91131
    92132# array to aubio
    93133aubiovecfrompyobj = {
    94     'fvec_t': 'PyAubio_ArrayToFvec',
    95     'cvec_t': 'PyAubio_ArrayToCvec',
     134    'fvec_t*': 'PyAubio_ArrayToFvec',
     135    'cvec_t*': 'PyAubio_ArrayToCvec',
    96136}
    97137
    98138# aubio to array
    99139aubiovectopyobj = {
    100     'fvec_t': 'PyAubio_FvecToArray',
    101     'cvec_t': 'PyAubio_CvecToArray',
    102 }
    103 
    104 def get_newparams(newfunc):
    105     newparams = [[p.split()[0], p.split()[-1]]
    106             for p in newfunc.split('(')[1].split(')')[0].split(',')]
    107     # make char_t a pointer
    108     return map(lambda x: [x[0].replace('char_t', 'char_t*'), x[1]], newparams)
     140    'fvec_t*': 'PyAubio_FvecToArray',
     141    'cvec_t*': 'PyAubio_CvecToArray',
     142}
     143
     144aubiovectopyobj_new = {
     145    'fvec_t*': 'PyAubio_CFvecToArray',
     146    'cvec_t*': 'PyAubio_CCvecToArray',
     147    'smpl_t': 'PyFloat_FromDouble',
     148}
    109149
    110150def gen_new_init(newfunc, name):
    111     newparams = get_newparams(newfunc)
     151    newparams = get_params_types_names(newfunc)
    112152    # self->param1, self->param2, self->param3
    113153    selfparams = ', self->'.join([p[1] for p in newparams])
     
    118158    s = """\
    119159// WARNING: this file is generated, DO NOT EDIT
     160
     161// WARNING: if you haven't read the first line yet, please do so
    120162#include "aubiowraphell.h"
    121163
     
    159201  }
    160202""" % locals()
    161     # TODO add parameters default values
    162203    for ptype, pname in newparams:
    163204        defval = aubiodefvalue[pname]
     
    206247def gen_do(dofunc, name):
    207248    funcname = dofunc.split()[1].split('(')[0]
    208     doparams = [p.split() for p in dofunc.split('(')[1].split(')')[0].split(',')]
     249    doparams = get_params_types_names(dofunc)
    209250    # make sure the first parameter is the object
    210     assert doparams[0][0] == "aubio_"+name+"_t", \
     251    assert doparams[0][0] == "aubio_"+name+"_t*", \
    211252        "method is not in 'aubio_<name>_t"
    212253    # and remove it
     
    241282    # build strings for outputs
    242283    outputparams = doparams[1:]
    243     if len(doparams) > 1:
     284    if len(outputparams) >= 1:
    244285        #assert len(outputparams) == 1, \
    245286        #    "too many output parameters"
    246287        outputvecs = "\n  ".join([aubio2pyaubio[p[0]]+" * " + p[-1] + ";" for p in outputparams])
    247         outputcreate = """\
     288        outputcreate = "\n  ".join(["""\
    248289AUBIO_NEW_VEC(%(name)s, %(pytype)s, %(length)s, %(channels)s)
    249290  %(name)s->o = new_%(autype)s (%(length)s, %(channels)s);""" % \
    250     {'name': p[-1], 'pytype': aubio2pyaubio[p[0]], 'autype': p[0][:-2],
    251         'length': defaultsizes[name][0], 'channels': defaultsizes[name][1]}
    252         returnval = "(PyObject *)" + aubiovectopyobj[p[0]] + " (" + p[-1] + ")"
     291    {'name': p[-1], 'pytype': aubio2pyaubio[p[0]], 'autype': p[0][:-3],
     292        'length': defaultsizes[name][0], 'channels': defaultsizes[name][1]} \
     293        for p in outputparams])
     294        if len(outputparams) > 1:
     295            returnval = "PyObject *outputs = PyList_New(0);\n"
     296            for p in outputparams:
     297                returnval += "  PyList_Append( outputs, (PyObject *)" + aubiovectopyobj[p[0]] + " (" + p[-1] + ")" +");\n"
     298            returnval += "  return outputs;"
     299        else:
     300            returnval = "return (PyObject *)" + aubiovectopyobj[p[0]] + " (" + p[-1] + ")"
    253301    else:
    254302        # no output
     
    256304        outputcreate = ""
    257305        #returnval = "Py_None";
    258         returnval = "(PyObject *)" + aubiovectopyobj[p[0]] + " (" + p[-1] + ")"
     306        returnval = "return (PyObject *)" + aubiovectopyobj[p[0]] + " (" + p[-1] + ")"
    259307    # end of output strings
    260308
     
    282330  %(funcname)s (%(doparams_string)s);
    283331
    284   return %(returnval)s;
     332  %(returnval)s;
    285333}
    286334""" % locals()
     
    288336
    289337def gen_members(new_method, name):
    290     newparams = get_newparams(new_method)
     338    newparams = get_params_types_names(new_method)
    291339    s = """
    292340AUBIO_MEMBERS_START(%(name)s)""" % locals()
     
    312360    return s
    313361
     362
    314363def gen_methods(get_methods, set_methods, name):
    315     # TODO add methods
    316     s = """\
     364    s = ""
     365    method_defs = ""
     366    for method in set_methods:
     367        method_name = get_name(method)
     368        params = get_params_types_names(method)
     369        out_type = get_return_type(method)
     370        assert params[0][0] == "aubio_"+name+"_t*", \
     371            "get method is not in 'aubio_<name>_t"
     372        print method
     373        print params[1:]
     374        setter_args = "self->o, " +",".join([p[1] for p in params[1:]])
     375        parse_args = ""
     376        for p in params[1:]:
     377            parse_args += p[0] + " " + p[1] + ";\n"
     378        argmap = "".join([aubio2pytypes[p[0]] for p in params[1:]])
     379        arglist = ", ".join(["&"+p[1] for p in params[1:]])
     380        parse_args += """
     381  if (!PyArg_ParseTuple (args, "%(argmap)s", %(arglist)s)) {
     382    return NULL;
     383  } """ % locals()
     384        s += """
     385static PyObject *
     386Py%(funcname)s (Py_%(objname)s *self, PyObject *args)
     387{
     388  uint_t err = 0;
     389
     390  %(parse_args)s
     391
     392  err = %(funcname)s (%(setter_args)s);
     393
     394  if (err > 0) {
     395    PyErr_SetString (PyExc_ValueError,
     396        "error running %(funcname)s");
     397    return NULL;
     398  }
     399  return Py_None;
     400}
     401""" % {'funcname': method_name, 'objname': name,
     402        'out_type': out_type, 'setter_args': setter_args, 'parse_args': parse_args }
     403        shortname = method_name.split(name+'_')[-1]
     404        method_defs += """\
     405  {"%(shortname)s", (PyCFunction) Py%(method_name)s,
     406    METH_VARARGS, ""},
     407""" % locals()
     408
     409    for method in get_methods:
     410        method_name = get_name(method)
     411        params = get_params_types_names(method)
     412        out_type = get_return_type(method)
     413        assert params[0][0] == "aubio_"+name+"_t*", \
     414            "get method is not in 'aubio_<name>_t %s" % params[0][0]
     415        assert len(params) == 1, \
     416            "get method has more than one parameter %s" % params
     417        getter_args = "self->o"
     418        returnval = "(PyObject *)" + aubiovectopyobj_new[out_type] + " (tmp)"
     419        shortname = method_name.split(name+'_')[-1]
     420        method_defs += """\
     421  {"%(shortname)s", (PyCFunction) Py%(method_name)s,
     422    METH_NOARGS, ""},
     423""" % locals()
     424        s += """
     425static PyObject *
     426Py%(funcname)s (Py_%(objname)s *self, PyObject *unused)
     427{
     428  %(out_type)s tmp = %(funcname)s (%(getter_args)s);
     429  return %(returnval)s;
     430}
     431""" % {'funcname': method_name, 'objname': name,
     432        'out_type': out_type, 'getter_args': getter_args, 'returnval': returnval }
     433
     434    s += """
    317435static PyMethodDef Py_%(name)s_methods[] = {
    318436""" % locals()
    319     # TODO add PyMethodDefs
     437    s += method_defs
    320438    s += """\
    321439  {NULL} /* sentinel */
Note: See TracChangeset for help on using the changeset viewer.