Showing the changes to python/lib/gen_code.py (1 of 4 files). Show all
Unified · Split
| @@ -0,0 +1,487 @@ | ||
| 1 | +aubiodefvalue = { | |
| 2 | + # we have some clean up to do | |
| 3 | + 'buf_size': 'Py_default_vector_length', | |
| 4 | + 'win_s': 'Py_default_vector_length', | |
| 5 | + # and here too | |
| 6 | + 'hop_size': 'Py_default_vector_length / 2', | |
| 7 | + 'hop_s': 'Py_default_vector_length / 2', | |
| 8 | + # these should be alright | |
| 9 | + 'samplerate': 'Py_aubio_default_samplerate', | |
| 10 | + # now for the non obvious ones | |
| 11 | + 'n_filters': '40', | |
| 12 | + 'n_coeffs': '13', | |
| 13 | + 'nelems': '10', | |
| 14 | + 'flow': '0.', | |
| 15 | + 'fhig': '1.', | |
| 16 | + 'ilow': '0.', | |
| 17 | + 'ihig': '1.', | |
| 18 | + 'thrs': '0.5', | |
| 19 | + 'ratio': '0.5', | |
| 20 | + 'method': '"default"', | |
| 21 | + 'uri': '"none"', | |
| 22 | + } | |
| 23 | + | |
| 24 | +member_types = { | |
| 25 | + 'name': 'type', | |
| 26 | + 'char_t*': 'T_STRING', | |
| 27 | + 'uint_t': 'T_INT', | |
| 28 | + 'smpl_t': 'T_FLOAT', | |
| 29 | + } | |
| 30 | + | |
| 31 | +pyfromtype_fn = { | |
| 32 | + 'smpl_t': 'PyFloat_FromDouble', | |
| 33 | + 'uint_t': 'PyLong_FromLong', # was: 'PyInt_FromLong', | |
| 34 | + 'fvec_t*': 'PyAubio_CFvecToArray', | |
| 35 | + 'fmat_t*': 'PyAubio_CFmatToArray', | |
| 36 | + } | |
| 37 | + | |
| 38 | +pytoaubio_fn = { | |
| 39 | + 'fvec_t*': 'PyAubio_ArrayToCFvec', | |
| 40 | + 'cvec_t*': 'PyAubio_ArrayToCCvec', | |
| 41 | + 'fmat_t*': 'PyAubio_ArrayToCFmat', | |
| 42 | + } | |
| 43 | + | |
| 44 | +pyfromaubio_fn = { | |
| 45 | + 'fvec_t*': 'PyAubio_CFvecToArray', | |
| 46 | + 'cvec_t*': 'PyAubio_CCvecToArray', | |
| 47 | + 'fmat_t*': 'PyAubio_CFmatToArray', | |
| 48 | + } | |
| 49 | + | |
| 50 | +newfromtype_fn = { | |
| 51 | + 'fvec_t*': 'new_fvec', | |
| 52 | + 'fmat_t*': 'new_fmat', | |
| 53 | + 'cvec_t*': 'new_cvec', | |
| 54 | + } | |
| 55 | + | |
| 56 | +delfromtype_fn = { | |
| 57 | + 'fvec_t*': 'del_fvec', | |
| 58 | + 'fmat_t*': 'del_fmat', | |
| 59 | + 'cvec_t*': 'del_cvec', | |
| 60 | + } | |
| 61 | + | |
| 62 | +param_init = { | |
| 63 | + 'char_t*': 'NULL', | |
| 64 | + 'uint_t': '0', | |
| 65 | + 'sint_t': 0, | |
| 66 | + 'smpl_t': 0., | |
| 67 | + 'lsmp_t': 0., | |
| 68 | + } | |
| 69 | + | |
| 70 | +pyargparse_chars = { | |
| 71 | + 'smpl_t': 'f', | |
| 72 | + 'uint_t': 'I', | |
| 73 | + 'sint_t': 'I', | |
| 74 | + 'char_t*': 's', | |
| 75 | + 'fmat_t*': 'O', | |
| 76 | + 'fvec_t*': 'O', | |
| 77 | + } | |
| 78 | + | |
| 79 | +objoutsize = { | |
| 80 | + 'onset': '1', | |
| 81 | + 'pitch': '1', | |
| 82 | + 'wavetable': 'self->hop_size', | |
| 83 | + 'sampler': 'self->hop_size', | |
| 84 | + 'mfcc': 'self->n_coeffs', | |
| 85 | + 'specdesc': '1', | |
| 86 | + 'tempo': '1', | |
| 87 | + 'filterbank': 'self->n_filters', | |
| 88 | + } | |
| 89 | + | |
| 90 | +def get_name(proto): | |
| 91 | + name = proto.replace(' *', '* ').split()[1].split('(')[0] | |
| 92 | + name = name.replace('*','') | |
| 93 | + if name == '': raise ValueError(proto + "gave empty name") | |
| 94 | + return name | |
| 95 | + | |
| 96 | +def get_return_type(proto): | |
| 97 | + import re | |
| 98 | + paramregex = re.compile('(\w+ ?\*?).*') | |
| 99 | + outputs = paramregex.findall(proto) | |
| 100 | + assert len(outputs) == 1 | |
| 101 | + return outputs[0].replace(' ', '') | |
| 102 | + | |
| 103 | +def split_type(arg): | |
| 104 | + """ arg = 'foo *name' | |
| 105 | + return ['foo*', 'name'] """ | |
| 106 | + l = arg.split() | |
| 107 | + type_arg = {'type': l[0], 'name': l[1]} | |
| 108 | + # ['foo', '*name'] -> ['foo*', 'name'] | |
| 109 | + if l[-1].startswith('*'): | |
| 110 | + #return [l[0]+'*', l[1][1:]] | |
| 111 | + type_arg['type'] = l[0] + '*' | |
| 112 | + type_arg['name'] = l[1][1:] | |
| 113 | + # ['foo', '*', 'name'] -> ['foo*', 'name'] | |
| 114 | + if len(l) == 3: | |
| 115 | + #return [l[0]+l[1], l[2]] | |
| 116 | + type_arg['type'] = l[0]+l[1] | |
| 117 | + type_arg['name'] = l[2] | |
| 118 | + else: | |
| 119 | + #return l | |
| 120 | + pass | |
| 121 | + return type_arg | |
| 122 | + | |
| 123 | +def get_params(proto): | |
| 124 | + """ get the list of parameters from a function prototype | |
| 125 | + example: proto = "int main (int argc, char ** argv)" | |
| 126 | + returns: ['int argc', 'char ** argv'] | |
| 127 | + """ | |
| 128 | + import re | |
| 129 | + paramregex = re.compile('[\(, ](\w+ \*?\*? ?\w+)[, \)]') | |
| 130 | + return paramregex.findall(proto) | |
| 131 | + | |
| 132 | +def get_params_types_names(proto): | |
| 133 | + """ get the list of parameters from a function prototype | |
| 134 | + example: proto = "int main (int argc, char ** argv)" | |
| 135 | + returns: [['int', 'argc'], ['char **','argv']] | |
| 136 | + """ | |
| 137 | + return list(map(split_type, get_params(proto))) | |
| 138 | + | |
| 139 | + | |
| 140 | +class MappedObject(object): | |
| 141 | + | |
| 142 | + def __init__(self, prototypes): | |
| 143 | + self.prototypes = prototypes | |
| 144 | + | |
| 145 | + self.shortname = prototypes['shortname'] | |
| 146 | + self.longname = prototypes['longname'] | |
| 147 | + self.new_proto = prototypes['new'][0] | |
| 148 | + self.del_proto = prototypes['del'][0] | |
| 149 | + self.do_proto = prototypes['do'][0] | |
| 150 | + self.input_params = get_params_types_names(self.new_proto) | |
| 151 | + self.input_params_list = "; ".join(get_params(self.new_proto)) | |
| 152 | + self.outputs = get_params_types_names(self.do_proto)[2:] | |
| 153 | + self.outputs_flat = get_params(self.do_proto)[2:] | |
| 154 | + self.output_results = ", ".join(self.outputs_flat) | |
| 155 | + | |
| 156 | + def gen_code(self): | |
| 157 | + out = "" | |
| 158 | + out += self.gen_struct() | |
| 159 | + out += self.gen_doc() | |
| 160 | + out += self.gen_new() | |
| 161 | + out += self.gen_init() | |
| 162 | + out += self.gen_del() | |
| 163 | + out += self.gen_do() | |
| 164 | + out += self.gen_memberdef() | |
| 165 | + out += self.gen_set() | |
| 166 | + out += self.gen_get() | |
| 167 | + out += self.gen_methodef() | |
| 168 | + out += self.gen_typeobject() | |
| 169 | + return out | |
| 170 | + | |
| 171 | + def gen_struct(self): | |
| 172 | + out = """ | |
| 173 | +// {shortname} structure | |
| 174 | +typedef struct{{ | |
| 175 | + PyObject_HEAD | |
| 176 | + // pointer to aubio object | |
| 177 | + {longname} *o; | |
| 178 | + // input parameters | |
| 179 | + {input_params_list}; | |
| 180 | + // output results | |
| 181 | + {output_results}; | |
| 182 | +}} Py_{shortname}; | |
| 183 | +""" | |
| 184 | + return out.format(**self.__dict__) | |
| 185 | + | |
| 186 | + def gen_doc(self): | |
| 187 | + out = """ | |
| 188 | +// TODO: add documentation | |
| 189 | +static char Py_{shortname}_doc[] = \"undefined\"; | |
| 190 | + """ | |
| 191 | + return out.format(**self.__dict__) | |
| 192 | + | |
| 193 | + def gen_new(self): | |
| 194 | + out = """ | |
| 195 | +// new {shortname} | |
| 196 | +static PyObject * | |
| 197 | +Py_{shortname}_new (PyTypeObject * pytype, PyObject * args, PyObject * kwds) | |
| 198 | +{{ | |
| 199 | + Py_{shortname} *self; | |
| 200 | +""".format(**self.__dict__) | |
| 201 | + params = self.input_params | |
| 202 | + for p in params: | |
| 203 | + out += """ | |
| 204 | + {type} {name} = {defval};""".format(defval = param_init[p['type']], **p) | |
| 205 | + plist = ", ".join(["\"%s\"" % p['name'] for p in params]) | |
| 206 | + out += """ | |
| 207 | + static char *kwlist[] = {{ {plist}, NULL }};""".format(plist = plist) | |
| 208 | + argchars = "".join([pyargparse_chars[p['type']] for p in params]) | |
| 209 | + arglist = ", ".join(["&%s" % p['name'] for p in params]) | |
| 210 | + out += """ | |
| 211 | + if (!PyArg_ParseTupleAndKeywords (args, kwds, "|{argchars}", kwlist, | |
| 212 | + {arglist})) {{ | |
| 213 | + return NULL; | |
| 214 | + }} | |
| 215 | +""".format(argchars = argchars, arglist = arglist) | |
| 216 | + out += """ | |
| 217 | + self = (Py_{shortname} *) pytype->tp_alloc (pytype, 0); | |
| 218 | + if (self == NULL) {{ | |
| 219 | + return NULL; | |
| 220 | + }} | |
| 221 | +""".format(**self.__dict__) | |
| 222 | + params = self.input_params | |
| 223 | + for p in params: | |
| 224 | + out += self.check_valid(p) | |
| 225 | + out += """ | |
| 226 | + return (PyObject *)self; | |
| 227 | +} | |
| 228 | +""" | |
| 229 | + return out | |
| 230 | + | |
| 231 | + def check_valid(self, p): | |
| 232 | + if p['type'] == 'uint_t': | |
| 233 | + return self.check_valid_uint(p) | |
| 234 | + if p['type'] == 'char_t*': | |
| 235 | + return self.check_valid_char(p) | |
| 236 | + else: | |
| 237 | + print ("ERROR, no idea how to check %s for validity" % p['type']) | |
| 238 | + | |
| 239 | + def check_valid_uint(self, p): | |
| 240 | + name = p['name'] | |
| 241 | + return """ | |
| 242 | + self->{name} = {defval}; | |
| 243 | + if ((sint_t){name} > 0) {{ | |
| 244 | + self->{name} = {name}; | |
| 245 | + }} else if ((sint_t){name} < 0) {{ | |
| 246 | + PyErr_SetString (PyExc_ValueError, "can not use negative value for {name}"); | |
| 247 | + return NULL; | |
| 248 | + }} | |
| 249 | +""".format(defval = aubiodefvalue[name], name = name) | |
| 250 | + | |
| 251 | + def check_valid_char(self, p): | |
| 252 | + name = p['name'] | |
| 253 | + return """ | |
| 254 | + self->{name} = {defval}; | |
| 255 | + if ({name} != NULL) {{ | |
| 256 | + self->{name} = {name}; | |
| 257 | + }} | |
| 258 | +""".format(defval = aubiodefvalue[name], name = name) | |
| 259 | + | |
| 260 | + def gen_init(self): | |
| 261 | + out = """ | |
| 262 | +// init {shortname} | |
| 263 | +static int | |
| 264 | +Py_{shortname}_init (Py_{shortname} * self, PyObject * args, PyObject * kwds) | |
| 265 | +{{ | |
| 266 | +""".format(**self.__dict__) | |
| 267 | + new_name = get_name(self.new_proto) | |
| 268 | + new_params = ", ".join(["self->%s" % s['name'] for s in self.input_params]) | |
| 269 | + out += """ | |
| 270 | + self->o = {new_name}({new_params}); | |
| 271 | +""".format(new_name = new_name, new_params = new_params) | |
| 272 | + paramchars = "%s" | |
| 273 | + paramvals = "self->method" | |
| 274 | + out += """ | |
| 275 | + // return -1 and set error string on failure | |
| 276 | + if (self->o == NULL) {{ | |
| 277 | + //char_t errstr[30 + strlen(self->uri)]; | |
| 278 | + //sprintf(errstr, "error creating {shortname} with params {paramchars}", {paramvals}); | |
| 279 | + char_t errstr[60]; | |
| 280 | + sprintf(errstr, "error creating {shortname} with given params"); | |
| 281 | + PyErr_SetString (PyExc_Exception, errstr); | |
| 282 | + return -1; | |
| 283 | + }} | |
| 284 | +""".format(paramchars = paramchars, paramvals = paramvals, **self.__dict__) | |
| 285 | + output_create = "" | |
| 286 | + for o in self.outputs: | |
| 287 | + output_create += """ | |
| 288 | + self->{name} = {create_fn}({output_size});""".format(name = o['name'], create_fn = newfromtype_fn[o['type']], output_size = objoutsize[self.shortname]) | |
| 289 | + out += """ | |
| 290 | + // TODO get internal params after actual object creation? | |
| 291 | +""" | |
| 292 | + out += """ | |
| 293 | + // create outputs{output_create} | |
| 294 | +""".format(output_create = output_create) | |
| 295 | + out += """ | |
| 296 | + return 0; | |
| 297 | +} | |
| 298 | +""" | |
| 299 | + return out | |
| 300 | + | |
| 301 | + def gen_memberdef(self): | |
| 302 | + out = """ | |
| 303 | +static PyMemberDef Py_{shortname}_members[] = {{ | |
| 304 | +""".format(**self.__dict__) | |
| 305 | + for p in get_params_types_names(self.new_proto): | |
| 306 | + tmp = " {{\"{name}\", {ttype}, offsetof (Py_{shortname}, {name}), READONLY, \"TODO documentation\"}},\n" | |
| 307 | + pytype = member_types[p['type']] | |
| 308 | + out += tmp.format(name = p['name'], ttype = pytype, shortname = self.shortname) | |
| 309 | + out += """ {NULL}, // sentinel | |
| 310 | +}; | |
| 311 | +""" | |
| 312 | + return out | |
| 313 | + | |
| 314 | + def gen_del(self): | |
| 315 | + out = """ | |
| 316 | +// del {shortname} | |
| 317 | +static void | |
| 318 | +Py_{shortname}_del (Py_{shortname} * self, PyObject * unused) | |
| 319 | +{{""".format(**self.__dict__) | |
| 320 | + for o in self.outputs: | |
| 321 | + name = o['name'] | |
| 322 | + del_out = delfromtype_fn[o['type']] | |
| 323 | + out += """ | |
| 324 | + {del_out}(self->{name});""".format(del_out = del_out, name = name) | |
| 325 | + del_fn = get_name(self.del_proto) | |
| 326 | + out += """ | |
| 327 | + {del_fn}(self->o); | |
| 328 | + Py_TYPE(self)->tp_free((PyObject *) self); | |
| 329 | +}} | |
| 330 | +""".format(del_fn = del_fn) | |
| 331 | + return out | |
| 332 | + | |
| 333 | + def gen_do(self): | |
| 334 | + do_fn = get_name(self.do_proto) | |
| 335 | + input_param = get_params_types_names(self.do_proto)[1]; | |
| 336 | + pytoaubio = pytoaubio_fn[input_param['type']] | |
| 337 | + output = self.outputs[0] | |
| 338 | + out = """ | |
| 339 | +// do {shortname} | |
| 340 | +static PyObject* | |
| 341 | +Py_{shortname}_do (Py_{shortname} * self, PyObject * args) | |
| 342 | +{{ | |
| 343 | + PyObject * in_obj; | |
| 344 | + {input_type} {input_name}; | |
| 345 | + | |
| 346 | + if (!PyArg_ParseTuple (args, "O", &in_obj)) {{ | |
| 347 | + return NULL; | |
| 348 | + }} | |
| 349 | + {input_name} = {pytoaubio} (in_obj); | |
| 350 | + if ({input_name} == NULL) {{ | |
| 351 | + return NULL; | |
| 352 | + }} | |
| 353 | + | |
| 354 | + {do_fn}(self->o, {input_name}, {outputs}); | |
| 355 | + | |
| 356 | + return (PyObject *) {aubiotonumpy} ({outputs}); | |
| 357 | +}} | |
| 358 | +""" | |
| 359 | + return out.format(do_fn = do_fn, | |
| 360 | + shortname = self.prototypes['shortname'], | |
| 361 | + input_name = input_param['name'], | |
| 362 | + input_type= input_param['type'], | |
| 363 | + pytoaubio = pytoaubio, | |
| 364 | + outputs = ", ".join(["self->%s" % p['name'] for p in self.outputs]), | |
| 365 | + aubiotonumpy = pyfromaubio_fn[output['type']], | |
| 366 | + ) | |
| 367 | + | |
| 368 | + def gen_set(self): | |
| 369 | + out = """ | |
| 370 | +// {shortname} setters | |
| 371 | +""".format(**self.__dict__) | |
| 372 | + for set_param in self.prototypes['set']: | |
| 373 | + params = get_params_types_names(set_param)[1] | |
| 374 | + paramtype = params['type'] | |
| 375 | + method_name = get_name(set_param) | |
| 376 | + param = method_name.split('aubio_'+self.shortname+'_set_')[-1] | |
| 377 | + pyparamtype = pyargparse_chars[paramtype] | |
| 378 | + out += """ | |
| 379 | +static PyObject * | |
| 380 | +Pyaubio_{shortname}_set_{param} (Py_{shortname} *self, PyObject *args) | |
| 381 | +{{ | |
| 382 | + uint_t err = 0; | |
| 383 | + {paramtype} {param}; | |
| 384 | + | |
| 385 | + if (!PyArg_ParseTuple (args, "{pyparamtype}", &{param})) {{ | |
| 386 | + return NULL; | |
| 387 | + }} | |
| 388 | + err = aubio_{shortname}_set_{param} (self->o, {param}); | |
| 389 | + | |
| 390 | + if (err > 0) {{ | |
| 391 | + PyErr_SetString (PyExc_ValueError, "error running aubio_{shortname}_set_{param}"); | |
| 392 | + return NULL; | |
| 393 | + }} | |
| 394 | + Py_RETURN_NONE; | |
| 395 | +}} | |
| 396 | +""".format(param = param, paramtype = paramtype, pyparamtype = pyparamtype, **self.__dict__) | |
| 397 | + return out | |
| 398 | + | |
| 399 | + def gen_get(self): | |
| 400 | + out = """ | |
| 401 | +// {shortname} getters | |
| 402 | +""".format(**self.__dict__) | |
| 403 | + for method in self.prototypes['get']: | |
| 404 | + params = get_params_types_names(method) | |
| 405 | + method_name = get_name(method) | |
| 406 | + assert len(params) == 1, \ | |
| 407 | + "get method has more than one parameter %s" % params | |
| 408 | + param = method_name.split('aubio_'+self.shortname+'_get_')[-1] | |
| 409 | + paramtype = get_return_type(method) | |
| 410 | + ptypeconv = pyfromtype_fn[paramtype] | |
| 411 | + out += """ | |
| 412 | +static PyObject * | |
| 413 | +Pyaubio_{shortname}_get_{param} (Py_{shortname} *self, PyObject *unused) | |
| 414 | +{{ | |
| 415 | + {ptype} {param} = aubio_{shortname}_get_{param} (self->o); | |
| 416 | + return (PyObject *){ptypeconv} ({param}); | |
| 417 | +}} | |
| 418 | +""".format(param = param, ptype = paramtype, ptypeconv = ptypeconv, | |
| 419 | + **self.__dict__) | |
| 420 | + return out | |
| 421 | + | |
| 422 | + def gen_methodef(self): | |
| 423 | + out = """ | |
| 424 | +static PyMethodDef Py_{shortname}_methods[] = {{""".format(**self.__dict__) | |
| 425 | + for m in self.prototypes['set']: | |
| 426 | + name = get_name(m) | |
| 427 | + shortname = name.replace('aubio_%s_' % self.shortname, '') | |
| 428 | + out += """ | |
| 429 | + {{"{shortname}", (PyCFunction) Py{name}, | |
| 430 | + METH_VARARGS, ""}},""".format(name = name, shortname = shortname) | |
| 431 | + for m in self.prototypes['get']: | |
| 432 | + name = get_name(m) | |
| 433 | + shortname = name.replace('aubio_%s_' % self.shortname, '') | |
| 434 | + out += """ | |
| 435 | + {{"{shortname}", (PyCFunction) Py{name}, | |
| 436 | + METH_NOARGS, ""}},""".format(name = name, shortname = shortname) | |
| 437 | + out += """ | |
| 438 | + {NULL} /* sentinel */ | |
| 439 | +}; | |
| 440 | +""" | |
| 441 | + return out | |
| 442 | + | |
| 443 | + def gen_typeobject(self): | |
| 444 | + return """ | |
| 445 | +PyTypeObject Py_{shortname}Type = {{ | |
| 446 | + //PyObject_HEAD_INIT (NULL) | |
| 447 | + //0, | |
| 448 | + PyVarObject_HEAD_INIT (NULL, 0) | |
| 449 | + "aubio.{shortname}", | |
| 450 | + sizeof (Py_{shortname}), | |
| 451 | + 0, | |
| 452 | + (destructor) Py_{shortname}_del, | |
| 453 | + 0, | |
| 454 | + 0, | |
| 455 | + 0, | |
| 456 | + 0, | |
| 457 | + 0, | |
| 458 | + 0, | |
| 459 | + 0, | |
| 460 | + 0, | |
| 461 | + 0, | |
| 462 | + (ternaryfunc)Py_{shortname}_do, | |
| 463 | + 0, | |
| 464 | + 0, | |
| 465 | + 0, | |
| 466 | + 0, | |
| 467 | + Py_TPFLAGS_DEFAULT, | |
| 468 | + Py_{shortname}_doc, | |
| 469 | + 0, | |
| 470 | + 0, | |
| 471 | + 0, | |
| 472 | + 0, | |
| 473 | + 0, | |
| 474 | + 0, | |
| 475 | + Py_{shortname}_methods, | |
| 476 | + Py_{shortname}_members, | |
| 477 | + 0, | |
| 478 | + 0, | |
| 479 | + 0, | |
| 480 | + 0, | |
| 481 | + 0, | |
| 482 | + 0, | |
| 483 | + (initproc) Py_{shortname}_init, | |
| 484 | + 0, | |
| 485 | + Py_{shortname}_new, | |
| 486 | +}}; | |
| 487 | +""".format(**self.__dict__) | |