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__) | ||