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__) | ||
| @@ -0,0 +1,182 @@ | |||
| 1 | import os | ||
| 2 | |||
| 3 | header = """// this file is generated! do not modify | ||
| 4 | #include "aubio-types.h" | ||
| 5 | """ | ||
| 6 | |||
| 7 | skip_objects = [ | ||
| 8 | # already in ext/ | ||
| 9 | 'fft', | ||
| 10 | 'pvoc', | ||
| 11 | 'filter', | ||
| 12 | 'filterbank', | ||
| 13 | #'resampler', | ||
| 14 | # AUBIO_UNSTABLE | ||
| 15 | 'hist', | ||
| 16 | 'parameter', | ||
| 17 | 'scale', | ||
| 18 | 'beattracking', | ||
| 19 | 'resampler', | ||
| 20 | 'peakpicker', | ||
| 21 | 'pitchfcomb', | ||
| 22 | 'pitchmcomb', | ||
| 23 | 'pitchschmitt', | ||
| 24 | 'pitchspecacf', | ||
| 25 | 'pitchyin', | ||
| 26 | 'pitchyinfft', | ||
| 27 | 'sink', | ||
| 28 | 'sink_apple_audio', | ||
| 29 | 'sink_sndfile', | ||
| 30 | 'sink_wavwrite', | ||
| 31 | #'mfcc', | ||
| 32 | 'source', | ||
| 33 | 'source_apple_audio', | ||
| 34 | 'source_sndfile', | ||
| 35 | 'source_avcodec', | ||
| 36 | 'source_wavread', | ||
| 37 | #'sampler', | ||
| 38 | 'audio_unit', | ||
| 39 | |||
| 40 | 'tss', | ||
| 41 | ] | ||
| 42 | |||
| 43 | |||
| 44 | def get_cpp_objects(): | ||
| 45 | |||
| 46 | cpp_output = [l.strip() for l in os.popen('cpp -DAUBIO_UNSTABLE=1 -I../build/src ../src/aubio.h').readlines()] | ||
| 47 | #cpp_output = [l.strip() for l in os.popen('cpp -DAUBIO_UNSTABLE=0 -I../build/src ../src/onset/onset.h').readlines()] | ||
| 48 | #cpp_output = [l.strip() for l in os.popen('cpp -DAUBIO_UNSTABLE=0 -I../build/src ../src/pitch/pitch.h').readlines()] | ||
| 49 | |||
| 50 | cpp_output = filter(lambda y: len(y) > 1, cpp_output) | ||
| 51 | cpp_output = filter(lambda y: not y.startswith('#'), cpp_output) | ||
| 52 | cpp_output = list(cpp_output) | ||
| 53 | |||
| 54 | i = 1 | ||
| 55 | while 1: | ||
| 56 | if i >= len(cpp_output): break | ||
| 57 | if cpp_output[i-1].endswith(',') or cpp_output[i-1].endswith('{') or cpp_output[i].startswith('}'): | ||
| 58 | cpp_output[i] = cpp_output[i-1] + ' ' + cpp_output[i] | ||
| 59 | cpp_output.pop(i-1) | ||
| 60 | else: | ||
| 61 | i += 1 | ||
| 62 | |||
| 63 | typedefs = filter(lambda y: y.startswith ('typedef struct _aubio'), cpp_output) | ||
| 64 | |||
| 65 | cpp_objects = [a.split()[3][:-1] for a in typedefs] | ||
| 66 | |||
| 67 | return cpp_output, cpp_objects | ||
| 68 | |||
| 69 | def generate_external(output_path): | ||
| 70 | os.mkdir(output_path) | ||
| 71 | sources_list = [] | ||
| 72 | cpp_output, cpp_objects = get_cpp_objects() | ||
| 73 | lib = {} | ||
| 74 | |||
| 75 | for o in cpp_objects: | ||
| 76 | if o[:6] != 'aubio_': | ||
| 77 | continue | ||
| 78 | shortname = o[6:-2] | ||
| 79 | if shortname in skip_objects: | ||
| 80 | continue | ||
| 81 | lib[shortname] = {'struct': [], 'new': [], 'del': [], 'do': [], 'get': [], 'set': [], 'other': []} | ||
| 82 | lib[shortname]['longname'] = o | ||
| 83 | lib[shortname]['shortname'] = shortname | ||
| 84 | for fn in cpp_output: | ||
| 85 | if o[:-1] in fn: | ||
| 86 | #print "found", o[:-1], "in", fn | ||
| 87 | if 'typedef struct ' in fn: | ||
| 88 | lib[shortname]['struct'].append(fn) | ||
| 89 | elif '_do' in fn: | ||
| 90 | lib[shortname]['do'].append(fn) | ||
| 91 | elif 'new_' in fn: | ||
| 92 | lib[shortname]['new'].append(fn) | ||
| 93 | elif 'del_' in fn: | ||
| 94 | lib[shortname]['del'].append(fn) | ||
| 95 | elif '_get_' in fn: | ||
| 96 | lib[shortname]['get'].append(fn) | ||
| 97 | elif '_set_' in fn: | ||
| 98 | lib[shortname]['set'].append(fn) | ||
| 99 | else: | ||
| 100 | #print "no idea what to do about", fn | ||
| 101 | lib[shortname]['other'].append(fn) | ||
| 102 | |||
| 103 | """ | ||
| 104 | for fn in cpp_output: | ||
| 105 | found = 0 | ||
| 106 | for o in lib: | ||
| 107 | for family in lib[o]: | ||
| 108 | if fn in lib[o][family]: | ||
| 109 | found = 1 | ||
| 110 | if found == 0: | ||
| 111 | print "missing", fn | ||
| 112 | |||
| 113 | for o in lib: | ||
| 114 | for family in lib[o]: | ||
| 115 | if type(lib[o][family]) == str: | ||
| 116 | print ( "{:15s} {:10s} {:s}".format(o, family, lib[o][family] ) ) | ||
| 117 | elif len(lib[o][family]) == 1: | ||
| 118 | print ( "{:15s} {:10s} {:s}".format(o, family, lib[o][family][0] ) ) | ||
| 119 | else: | ||
| 120 | print ( "{:15s} {:10s} {:d}".format(o, family, len(lib[o][family]) ) ) | ||
| 121 | """ | ||
| 122 | |||
| 123 | from .gen_code import MappedObject | ||
| 124 | for o in lib: | ||
| 125 | out = header | ||
| 126 | mapped = MappedObject(lib[o]) | ||
| 127 | out += mapped.gen_code() | ||
| 128 | output_file = os.path.join(output_path, 'gen-%s.c' % o) | ||
| 129 | with open(output_file, 'w') as f: | ||
| 130 | f.write(out) | ||
| 131 | print ("wrote %s" % output_file ) | ||
| 132 | sources_list.append(output_file) | ||
| 133 | |||
| 134 | out = header | ||
| 135 | out += "#include \"aubio-generated.h\"" | ||
| 136 | check_types = "\n || ".join(["PyType_Ready(&Py_%sType) < 0" % o for o in lib]) | ||
| 137 | out += """ | ||
| 138 | |||
| 139 | int generated_types_ready (void) | ||
| 140 | {{ | ||
| 141 | return ({pycheck_types}); | ||
| 142 | }} | ||
| 143 | """.format(pycheck_types = check_types) | ||
| 144 | |||
| 145 | add_types = "".join([""" | ||
| 146 | Py_INCREF (&Py_{name}Type); | ||
| 147 | PyModule_AddObject(m, "{name}", (PyObject *) & Py_{name}Type);""".format(name = o) for o in lib]) | ||
| 148 | out += """ | ||
| 149 | |||
| 150 | void add_generated_objects ( PyObject *m ) | ||
| 151 | {{ | ||
| 152 | {add_types} | ||
| 153 | }} | ||
| 154 | """.format(add_types = add_types) | ||
| 155 | |||
| 156 | output_file = os.path.join(output_path, 'aubio-generated.c') | ||
| 157 | with open(output_file, 'w') as f: | ||
| 158 | f.write(out) | ||
| 159 | print ("wrote %s" % output_file ) | ||
| 160 | sources_list.append(output_file) | ||
| 161 | |||
| 162 | objlist = "".join(["extern PyTypeObject Py_%sType;\n" % p for p in lib]) | ||
| 163 | out = """ | ||
| 164 | // generated list of objects created with gen_external.py | ||
| 165 | #include <Python.h> | ||
| 166 | |||
| 167 | {objlist} | ||
| 168 | int generated_objects ( void ); | ||
| 169 | void add_generated_objects( PyObject *m ); | ||
| 170 | """.format(objlist = objlist) | ||
| 171 | |||
| 172 | output_file = os.path.join(output_path, 'aubio-generated.h') | ||
| 173 | with open(output_file, 'w') as f: | ||
| 174 | f.write(out) | ||
| 175 | print ("wrote %s" % output_file ) | ||
| 176 | # no need to add header to list of sources | ||
| 177 | |||
| 178 | return sources_list | ||
| 179 | |||
| 180 | if __name__ == '__main__': | ||
| 181 | output_path = 'gen' | ||
| 182 | generate_external(output_path) | ||
| @@ -1,531 +0,0 @@ | |||
| 1 | #! /usr/bin/python | ||
| 2 | |||
| 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. | ||
| 5 | |||
| 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. | ||
| 8 | |||
| 9 | I hear the ones asking "why not use swig, or cython, or something like that?" | ||
| 10 | |||
| 11 | The 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 | |||
| 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. | ||
| 19 | """ | ||
| 20 | |||
| 21 | param_numbers = { | ||
| 22 | 'source': [0, 2], | ||
| 23 | 'sink': [2, 0], | ||
| 24 | 'sampler': [1, 1], | ||
| 25 | } | ||
| 26 | |||
| 27 | # TODO | ||
| 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. | ||
| 33 | |||
| 34 | def write_msg(*args): | ||
| 35 | pass | ||
| 36 | # uncomment out for debugging | ||
| 37 | #print args | ||
| 38 | |||
| 39 | def split_type(arg): | ||
| 40 | """ arg = 'foo *name' | ||
| 41 | return ['foo*', 'name'] """ | ||
| 42 | l = arg.split() | ||
| 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'] | ||
| 50 | if len(l) == 3: | ||
| 51 | #return [l[0]+l[1], l[2]] | ||
| 52 | type_arg['type'] = l[0]+l[1] | ||
| 53 | type_arg['name'] = l[2] | ||
| 54 | else: | ||
| 55 | #return l | ||
| 56 | pass | ||
| 57 | return type_arg | ||
| 58 | |||
| 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'] | ||
| 63 | """ | ||
| 64 | import re | ||
| 65 | paramregex = re.compile('[\(, ](\w+ \*?\*? ?\w+)[, \)]') | ||
| 66 | return paramregex.findall(proto) | ||
| 67 | |||
| 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']] | ||
| 72 | """ | ||
| 73 | return list(map(split_type, get_params(proto))) | ||
| 74 | |||
| 75 | def get_return_type(proto): | ||
| 76 | import re | ||
| 77 | paramregex = re.compile('(\w+ ?\*?).*') | ||
| 78 | outputs = paramregex.findall(proto) | ||
| 79 | assert len(outputs) == 1 | ||
| 80 | return outputs[0].replace(' ', '') | ||
| 81 | |||
| 82 | def get_name(proto): | ||
| 83 | name = proto.split()[1].split('(')[0] | ||
| 84 | return name.replace('*','') | ||
| 85 | |||
| 86 | # the important bits: the size of the output for each objects. this data should | ||
| 87 | # move into the C library at some point. | ||
| 88 | defaultsizes = { | ||
| 89 | 'resampler': ['input->length * self->ratio'], | ||
| 90 | 'specdesc': ['1'], | ||
| 91 | 'onset': ['1'], | ||
| 92 | 'pitchyin': ['1'], | ||
| 93 | 'pitchyinfft': ['1'], | ||
| 94 | 'pitchschmitt': ['1'], | ||
| 95 | 'pitchmcomb': ['1'], | ||
| 96 | 'pitchfcomb': ['1'], | ||
| 97 | 'pitch': ['1'], | ||
| 98 | 'tss': ['self->buf_size', 'self->buf_size'], | ||
| 99 | 'mfcc': ['self->n_coeffs'], | ||
| 100 | 'beattracking': ['self->hop_size'], | ||
| 101 | 'tempo': ['1'], | ||
| 102 | 'peakpicker': ['1'], | ||
| 103 | 'source': ['self->hop_size', '1'], | ||
| 104 | 'sampler': ['self->hop_size'], | ||
| 105 | 'wavetable': ['self->hop_size'], | ||
| 106 | } | ||
| 107 | |||
| 108 | # default value for variables | ||
| 109 | aubioinitvalue = { | ||
| 110 | 'uint_t': 0, | ||
| 111 | 'sint_t': 0, | ||
| 112 | 'smpl_t': 0, | ||
| 113 | 'lsmp_t': 0., | ||
| 114 | 'char_t*': 'NULL', | ||
| 115 | } | ||
| 116 | |||
| 117 | aubiodefvalue = { | ||
| 118 | # we have some clean up to do | ||
| 119 | 'buf_size': 'Py_default_vector_length', | ||
| 120 | # and here too | ||
| 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 | ||
| 125 | 'n_filters': '40', | ||
| 126 | 'n_coeffs': '13', | ||
| 127 | 'nelems': '10', | ||
| 128 | 'flow': '0.', | ||
| 129 | 'fhig': '1.', | ||
| 130 | 'ilow': '0.', | ||
| 131 | 'ihig': '1.', | ||
| 132 | 'thrs': '0.5', | ||
| 133 | 'ratio': '0.5', | ||
| 134 | 'method': '"default"', | ||
| 135 | 'uri': '"none"', | ||
| 136 | } | ||
| 137 | |||
| 138 | # aubio to python | ||
| 139 | aubio2pytypes = { | ||
| 140 | 'uint_t': 'I', | ||
| 141 | 'sint_t': 'I', | ||
| 142 | 'smpl_t': 'f', | ||
| 143 | 'lsmp_t': 'd', | ||
| 144 | 'fvec_t*': 'O', | ||
| 145 | 'cvec_t*': 'O', | ||
| 146 | 'char_t*': 's', | ||
| 147 | } | ||
| 148 | |||
| 149 | # python to aubio | ||
| 150 | aubiovecfrompyobj = { | ||
| 151 | 'fvec_t*': 'PyAubio_ArrayToCFvec', | ||
| 152 | 'cvec_t*': 'PyAubio_ArrayToCCvec', | ||
| 153 | 'uint_t': '(uint_t)PyLong_AsLong', | ||
| 154 | } | ||
| 155 | |||
| 156 | # aubio to python | ||
| 157 | aubiovectopyobj = { | ||
| 158 | 'fvec_t*': 'PyAubio_CFvecToArray', | ||
| 159 | 'cvec_t*': 'PyAubio_CCvecToPyCvec', | ||
| 160 | 'smpl_t': 'PyFloat_FromDouble', | ||
| 161 | 'uint_t*': 'PyLong_FromLong', | ||
| 162 | 'uint_t': 'PyLong_FromLong', | ||
| 163 | } | ||
| 164 | |||
| 165 | def gen_new_init(newfunc, name): | ||
| 166 | newparams = get_params_types_names(newfunc) | ||
| 167 | # self->param1, self->param2, self->param3 | ||
| 168 | if len(newparams): | ||
| 169 | selfparams = ', self->'+', self->'.join([p['name'] for p in newparams]) | ||
| 170 | else: | ||
| 171 | selfparams = '' | ||
| 172 | # "param1", "param2", "param3" | ||
| 173 | paramnames = ", ".join(["\""+p['name']+"\"" for p in newparams]) | ||
| 174 | pyparams = "".join([aubio2pytypes[p['type']] for p in newparams]) | ||
| 175 | paramrefs = ", ".join(["&" + p['name'] for p in newparams]) | ||
| 176 | s = """\ | ||
| 177 | // WARNING: this file is generated, DO NOT EDIT | ||
| 178 | |||
| 179 | // WARNING: if you haven't read the first line yet, please do so | ||
| 180 | #include "aubiowraphell.h" | ||
| 181 | |||
| 182 | typedef struct | ||
| 183 | { | ||
| 184 | PyObject_HEAD | ||
| 185 | aubio_%(name)s_t * o; | ||
| 186 | """ % locals() | ||
| 187 | for p in newparams: | ||
| 188 | ptype = p['type'] | ||
| 189 | pname = p['name'] | ||
| 190 | s += """\ | ||
| 191 | %(ptype)s %(pname)s; | ||
| 192 | """ % locals() | ||
| 193 | s += """\ | ||
| 194 | } Py_%(name)s; | ||
| 195 | |||
| 196 | static char Py_%(name)s_doc[] = "%(name)s object"; | ||
| 197 | |||
| 198 | static PyObject * | ||
| 199 | Py_%(name)s_new (PyTypeObject * pytype, PyObject * args, PyObject * kwds) | ||
| 200 | { | ||
| 201 | Py_%(name)s *self; | ||
| 202 | """ % locals() | ||
| 203 | for p in newparams: | ||
| 204 | ptype = p['type'] | ||
| 205 | pname = p['name'] | ||
| 206 | initval = aubioinitvalue[ptype] | ||
| 207 | s += """\ | ||
| 208 | %(ptype)s %(pname)s = %(initval)s; | ||
| 209 | """ % locals() | ||
| 210 | # now the actual PyArg_Parse | ||
| 211 | if len(paramnames): | ||
| 212 | s += """\ | ||
| 213 | static char *kwlist[] = { %(paramnames)s, NULL }; | ||
| 214 | |||
| 215 | if (!PyArg_ParseTupleAndKeywords (args, kwds, "|%(pyparams)s", kwlist, | ||
| 216 | %(paramrefs)s)) { | ||
| 217 | return NULL; | ||
| 218 | } | ||
| 219 | """ % locals() | ||
| 220 | s += """\ | ||
| 221 | |||
| 222 | self = (Py_%(name)s *) pytype->tp_alloc (pytype, 0); | ||
| 223 | |||
| 224 | if (self == NULL) { | ||
| 225 | return NULL; | ||
| 226 | } | ||
| 227 | """ % locals() | ||
| 228 | for p in newparams: | ||
| 229 | ptype = p['type'] | ||
| 230 | pname = p['name'] | ||
| 231 | defval = aubiodefvalue[pname] | ||
| 232 | if ptype == 'char_t*': | ||
| 233 | s += """\ | ||
| 234 | |||
| 235 | self->%(pname)s = %(defval)s; | ||
| 236 | if (%(pname)s != NULL) { | ||
| 237 | self->%(pname)s = %(pname)s; | ||
| 238 | } | ||
| 239 | """ % locals() | ||
| 240 | elif ptype == 'uint_t': | ||
| 241 | s += """\ | ||
| 242 | |||
| 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"); | ||
| 249 | return NULL; | ||
| 250 | } | ||
| 251 | """ % locals() | ||
| 252 | elif ptype == 'smpl_t': | ||
| 253 | s += """\ | ||
| 254 | |||
| 255 | self->%(pname)s = %(defval)s; | ||
| 256 | if (%(pname)s != %(defval)s) { | ||
| 257 | self->%(pname)s = %(pname)s; | ||
| 258 | } | ||
| 259 | """ % locals() | ||
| 260 | else: | ||
| 261 | write_msg ("ERROR, unknown type of parameter %s %s" % (ptype, pname) ) | ||
| 262 | s += """\ | ||
| 263 | |||
| 264 | return (PyObject *) self; | ||
| 265 | } | ||
| 266 | |||
| 267 | AUBIO_INIT(%(name)s %(selfparams)s) | ||
| 268 | |||
| 269 | AUBIO_DEL(%(name)s) | ||
| 270 | |||
| 271 | """ % locals() | ||
| 272 | return s | ||
| 273 | |||
| 274 | def gen_do_input_params(inputparams): | ||
| 275 | inputdefs = '' | ||
| 276 | parseinput = '' | ||
| 277 | inputrefs = '' | ||
| 278 | inputvecs = '' | ||
| 279 | pytypes = '' | ||
| 280 | |||
| 281 | if len(inputparams): | ||
| 282 | # build the parsing string for PyArg_ParseTuple | ||
| 283 | pytypes = "".join([aubio2pytypes[p['type']] for p in inputparams]) | ||
| 284 | |||
| 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" | ||
| 289 | |||
| 290 | inputvecs = " /* input vectors prototypes */\n " | ||
| 291 | inputvecs += "\n ".join([ p['type'] + ' ' + p['name'] + ";" for p in inputparams]) | ||
| 292 | |||
| 293 | parseinput = " /* input vectors parsing */\n " | ||
| 294 | for p in inputparams: | ||
| 295 | inputvec = p['name'] | ||
| 296 | if p['type'] != 'uint_t': | ||
| 297 | inputdef = p['name'] + "_obj" | ||
| 298 | else: | ||
| 299 | inputdef = p['name'] | ||
| 300 | converter = aubiovecfrompyobj[p['type']] | ||
| 301 | if p['type'] != 'uint_t': | ||
| 302 | parseinput += """%(inputvec)s = %(converter)s (%(inputdef)s); | ||
| 303 | |||
| 304 | if (%(inputvec)s == NULL) { | ||
| 305 | return NULL; | ||
| 306 | } | ||
| 307 | |||
| 308 | """ % locals() | ||
| 309 | |||
| 310 | # build the string for the input objects references | ||
| 311 | inputreflist = [] | ||
| 312 | for p in inputparams: | ||
| 313 | if p['type'] != 'uint_t': | ||
| 314 | inputreflist += [ "&" + p['name'] + "_obj" ] | ||
| 315 | else: | ||
| 316 | inputreflist += [ "&" + p['name'] ] | ||
| 317 | inputrefs = ", ".join(inputreflist) | ||
| 318 | # end of inputs strings | ||
| 319 | return inputdefs, parseinput, inputrefs, inputvecs, pytypes | ||
| 320 | |||
| 321 | def gen_do_output_params(outputparams, name): | ||
| 322 | outputvecs = "" | ||
| 323 | outputcreate = "" | ||
| 324 | if len(outputparams): | ||
| 325 | outputvecs = " /* output vectors prototypes */\n" | ||
| 326 | for p in outputparams: | ||
| 327 | params = { | ||
| 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 | ||
| 333 | else: | ||
| 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 | ||
| 337 | |||
| 338 | returnval = ""; | ||
| 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])" | ||
| 347 | else: | ||
| 348 | returnval += " return (PyObject *)" + aubiovectopyobj[p['type']] + " (" + p['name'] + ")" | ||
| 349 | else: | ||
| 350 | returnval += " Py_RETURN_NONE" | ||
| 351 | # end of output strings | ||
| 352 | return outputvecs, outputcreate, returnval | ||
| 353 | |||
| 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" | ||
| 360 | # and remove it | ||
| 361 | doparams = doparams[1:] | ||
| 362 | |||
| 363 | n_param = len(doparams) | ||
| 364 | |||
| 365 | if name in list(param_numbers.keys()): | ||
| 366 | n_input_param, n_output_param = param_numbers[name] | ||
| 367 | else: | ||
| 368 | n_input_param, n_output_param = 1, n_param - 1 | ||
| 369 | |||
| 370 | assert n_output_param + n_input_param == n_param, "n_output_param + n_input_param != n_param for %s" % name | ||
| 371 | |||
| 372 | inputparams = doparams[:n_input_param] | ||
| 373 | outputparams = doparams[n_input_param:n_input_param + n_output_param] | ||
| 374 | |||
| 375 | inputdefs, parseinput, inputrefs, inputvecs, pytypes = gen_do_input_params(inputparams); | ||
| 376 | outputvecs, outputcreate, returnval = gen_do_output_params(outputparams, name) | ||
| 377 | |||
| 378 | # build strings for outputs | ||
| 379 | # build the parameters for the _do() call | ||
| 380 | doparams_string = "self->o" | ||
| 381 | for p in doparams: | ||
| 382 | if p['type'] == 'uint_t*': | ||
| 383 | doparams_string += ", &" + p['name'] | ||
| 384 | else: | ||
| 385 | doparams_string += ", " + p['name'] | ||
| 386 | |||
| 387 | if n_input_param: | ||
| 388 | arg_parse_tuple = """\ | ||
| 389 | if (!PyArg_ParseTuple (args, "%(pytypes)s", %(inputrefs)s)) { | ||
| 390 | return NULL; | ||
| 391 | } | ||
| 392 | """ % locals() | ||
| 393 | else: | ||
| 394 | arg_parse_tuple = "" | ||
| 395 | # put it all together | ||
| 396 | s = """\ | ||
| 397 | /* function Py_%(name)s_do */ | ||
| 398 | static PyObject * | ||
| 399 | Py_%(name)s_do(Py_%(name)s * self, PyObject * args) | ||
| 400 | { | ||
| 401 | %(inputdefs)s | ||
| 402 | %(inputvecs)s | ||
| 403 | %(outputvecs)s | ||
| 404 | |||
| 405 | %(arg_parse_tuple)s | ||
| 406 | |||
| 407 | %(parseinput)s | ||
| 408 | |||
| 409 | %(outputcreate)s | ||
| 410 | |||
| 411 | /* compute _do function */ | ||
| 412 | %(funcname)s (%(doparams_string)s); | ||
| 413 | |||
| 414 | %(returnval)s; | ||
| 415 | } | ||
| 416 | """ % locals() | ||
| 417 | return s | ||
| 418 | |||
| 419 | def gen_members(new_method, name): | ||
| 420 | newparams = get_params_types_names(new_method) | ||
| 421 | s = """ | ||
| 422 | AUBIO_MEMBERS_START(%(name)s)""" % locals() | ||
| 423 | for param in newparams: | ||
| 424 | if param['type'] == 'char_t*': | ||
| 425 | s += """ | ||
| 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': | ||
| 429 | s += """ | ||
| 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': | ||
| 433 | s += """ | ||
| 434 | {"%(pname)s", T_FLOAT, offsetof (Py_%(name)s, %(pname)s), READONLY, ""},""" \ | ||
| 435 | % { 'pname': param['name'], 'ptype': param['type'], 'name': name} | ||
| 436 | else: | ||
| 437 | write_msg ("-- ERROR, unknown member type ", param ) | ||
| 438 | s += """ | ||
| 439 | AUBIO_MEMBERS_STOP(%(name)s) | ||
| 440 | |||
| 441 | """ % locals() | ||
| 442 | return s | ||
| 443 | |||
| 444 | |||
| 445 | def gen_methods(get_methods, set_methods, name): | ||
| 446 | s = "" | ||
| 447 | method_defs = "" | ||
| 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" | ||
| 454 | write_msg (method ) | ||
| 455 | write_msg (params[1:]) | ||
| 456 | setter_args = "self->o, " +",".join([p['name'] for p in params[1:]]) | ||
| 457 | parse_args = "" | ||
| 458 | 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:]]) | ||
| 462 | parse_args += """ | ||
| 463 | if (!PyArg_ParseTuple (args, "%(argmap)s", %(arglist)s)) { | ||
| 464 | return NULL; | ||
| 465 | } """ % locals() | ||
| 466 | s += """ | ||
| 467 | static PyObject * | ||
| 468 | Py%(funcname)s (Py_%(objname)s *self, PyObject *args) | ||
| 469 | { | ||
| 470 | uint_t err = 0; | ||
| 471 | |||
| 472 | %(parse_args)s | ||
| 473 | |||
| 474 | err = %(funcname)s (%(setter_args)s); | ||
| 475 | |||
| 476 | if (err > 0) { | ||
| 477 | PyErr_SetString (PyExc_ValueError, | ||
| 478 | "error running %(funcname)s"); | ||
| 479 | return NULL; | ||
| 480 | } | ||
| 481 | Py_RETURN_NONE; | ||
| 482 | } | ||
| 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] | ||
| 486 | method_defs += """\ | ||
| 487 | {"%(shortname)s", (PyCFunction) Py%(method_name)s, | ||
| 488 | METH_VARARGS, ""}, | ||
| 489 | """ % locals() | ||
| 490 | |||
| 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] | ||
| 502 | method_defs += """\ | ||
| 503 | {"%(shortname)s", (PyCFunction) Py%(method_name)s, | ||
| 504 | METH_NOARGS, ""}, | ||
| 505 | """ % locals() | ||
| 506 | s += """ | ||
| 507 | static PyObject * | ||
| 508 | Py%(funcname)s (Py_%(objname)s *self, PyObject *unused) | ||
| 509 | { | ||
| 510 | %(out_type)s tmp = %(funcname)s (%(getter_args)s); | ||
| 511 | return %(returnval)s; | ||
| 512 | } | ||
| 513 | """ % {'funcname': method_name, 'objname': name, | ||
| 514 | 'out_type': out_type, 'getter_args': getter_args, 'returnval': returnval } | ||
| 515 | |||
| 516 | s += """ | ||
| 517 | static PyMethodDef Py_%(name)s_methods[] = { | ||
| 518 | """ % locals() | ||
| 519 | s += method_defs | ||
| 520 | s += """\ | ||
| 521 | {NULL} /* sentinel */ | ||
| 522 | }; | ||
| 523 | """ % locals() | ||
| 524 | return s | ||
| 525 | |||
| 526 | def gen_finish(name): | ||
| 527 | s = """\ | ||
| 528 | |||
| 529 | AUBIO_TYPEOBJECT(%(name)s, "aubio.%(name)s") | ||
| 530 | """ % locals() | ||
| 531 | return s | ||
| @@ -1,233 +0,0 @@ | |||
| 1 | #! /usr/bin/python | ||
| 2 | |||
| 3 | """ This file generates a c file from a list of cpp prototypes. """ | ||
| 4 | |||
| 5 | import os, sys, shutil | ||
| 6 | from .gen_pyobject import write_msg, gen_new_init, gen_do, gen_members, gen_methods, gen_finish | ||
| 7 | |||
| 8 | def get_cpp_objects(): | ||
| 9 | |||
| 10 | cpp_output = [l.strip() for l in os.popen('cpp -DAUBIO_UNSTABLE=1 -I../build/src ../src/aubio.h').readlines()] | ||
| 11 | |||
| 12 | cpp_output = filter(lambda y: len(y) > 1, cpp_output) | ||
| 13 | cpp_output = filter(lambda y: not y.startswith('#'), cpp_output) | ||
| 14 | cpp_output = list(cpp_output) | ||
| 15 | |||
| 16 | i = 1 | ||
| 17 | while 1: | ||
| 18 | if i >= len(cpp_output): break | ||
| 19 | if cpp_output[i-1].endswith(',') or cpp_output[i-1].endswith('{') or cpp_output[i].startswith('}'): | ||
| 20 | cpp_output[i] = cpp_output[i-1] + ' ' + cpp_output[i] | ||
| 21 | cpp_output.pop(i-1) | ||
| 22 | else: | ||
| 23 | i += 1 | ||
| 24 | |||
| 25 | typedefs = filter(lambda y: y.startswith ('typedef struct _aubio'), cpp_output) | ||
| 26 | typedefs = list(typedefs) | ||
| 27 | |||
| 28 | cpp_objects = [a.split()[3][:-1] for a in typedefs] | ||
| 29 | |||
| 30 | return cpp_output, cpp_objects | ||
| 31 | |||
| 32 | def generate_object_files(output_path): | ||
| 33 | if os.path.isdir(output_path): shutil.rmtree(output_path) | ||
| 34 | os.mkdir(output_path) | ||
| 35 | |||
| 36 | generated_objects = [] | ||
| 37 | cpp_output, cpp_objects = get_cpp_objects() | ||
| 38 | skip_objects = [ | ||
| 39 | # already in ext/ | ||
| 40 | 'fft', | ||
| 41 | 'pvoc', | ||
| 42 | 'filter', | ||
| 43 | 'filterbank', | ||
| 44 | #'resampler', | ||
| 45 | # AUBIO_UNSTABLE | ||
| 46 | 'hist', | ||
| 47 | 'parameter', | ||
| 48 | 'scale', | ||
| 49 | 'beattracking', | ||
| 50 | 'resampler', | ||
| 51 | 'sndfile', | ||
| 52 | 'peakpicker', | ||
| 53 | 'pitchfcomb', | ||
| 54 | 'pitchmcomb', | ||
| 55 | 'pitchschmitt', | ||
| 56 | 'pitchspecacf', | ||
| 57 | 'pitchyin', | ||
| 58 | 'pitchyinfft', | ||
| 59 | 'sink', | ||
| 60 | 'sink_apple_audio', | ||
| 61 | 'sink_sndfile', | ||
| 62 | 'sink_wavwrite', | ||
| 63 | 'source', | ||
| 64 | 'source_apple_audio', | ||
| 65 | 'source_sndfile', | ||
| 66 | 'source_avcodec', | ||
| 67 | 'source_wavread', | ||
| 68 | #'sampler', | ||
| 69 | 'audio_unit', | ||
| 70 | ] | ||
| 71 | |||
| 72 | write_msg("-- INFO: %d objects in total" % len(cpp_objects)) | ||
| 73 | |||
| 74 | for this_object in cpp_objects: | ||
| 75 | lint = 0 | ||
| 76 | |||
| 77 | if this_object[-2:] == '_t': | ||
| 78 | object_name = this_object[:-2] | ||
| 79 | else: | ||
| 80 | object_name = this_object | ||
| 81 | write_msg("-- WARNING: %s does not end in _t" % this_object) | ||
| 82 | |||
| 83 | if object_name[:len('aubio_')] != 'aubio_': | ||
| 84 | write_msg("-- WARNING: %s does not start n aubio_" % this_object) | ||
| 85 | |||
| 86 | write_msg("-- INFO: looking at", object_name) | ||
| 87 | object_methods = filter(lambda x: this_object in x, cpp_output) | ||
| 88 | object_methods = [a.strip() for a in object_methods] | ||
| 89 | object_methods = filter(lambda x: not x.startswith('typedef'), object_methods) | ||
| 90 | object_methods = list(object_methods) | ||
| 91 | #for method in object_methods: | ||
| 92 | # write_msg(method) | ||
| 93 | new_methods = list(filter( | ||
| 94 | lambda x: 'new_'+object_name in x, object_methods)) | ||
| 95 | if len(new_methods) > 1: | ||
| 96 | write_msg("-- WARNING: more than one new method for", object_name) | ||
| 97 | for method in new_methods: | ||
| 98 | write_msg(method) | ||
| 99 | elif len(new_methods) < 1: | ||
| 100 | write_msg("-- WARNING: no new method for", object_name) | ||
| 101 | elif 0: | ||
| 102 | for method in new_methods: | ||
| 103 | write_msg(method) | ||
| 104 | |||
| 105 | del_methods = list(filter( | ||
| 106 | lambda x: 'del_'+object_name in x, object_methods)) | ||
| 107 | if len(del_methods) > 1: | ||
| 108 | write_msg("-- WARNING: more than one del method for", object_name) | ||
| 109 | for method in del_methods: | ||
| 110 | write_msg(method) | ||
| 111 | elif len(del_methods) < 1: | ||
| 112 | write_msg("-- WARNING: no del method for", object_name) | ||
| 113 | |||
| 114 | do_methods = list(filter( | ||
| 115 | lambda x: object_name+'_do' in x, object_methods)) | ||
| 116 | if len(do_methods) > 1: | ||
| 117 | pass | ||
| 118 | #write_msg("-- WARNING: more than one do method for", object_name) | ||
| 119 | #for method in do_methods: | ||
| 120 | # write_msg(method) | ||
| 121 | elif len(do_methods) < 1: | ||
| 122 | write_msg("-- WARNING: no do method for", object_name) | ||
| 123 | elif 0: | ||
| 124 | for method in do_methods: | ||
| 125 | write_msg(method) | ||
| 126 | |||
| 127 | # check do methods return void | ||
| 128 | for method in do_methods: | ||
| 129 | if (method.split()[0] != 'void'): | ||
| 130 | write_msg("-- ERROR: _do method does not return void:", method ) | ||
| 131 | |||
| 132 | get_methods = filter(lambda x: object_name+'_get_' in x, object_methods) | ||
| 133 | |||
| 134 | set_methods = filter(lambda x: object_name+'_set_' in x, object_methods) | ||
| 135 | for method in set_methods: | ||
| 136 | if (method.split()[0] != 'uint_t'): | ||
| 137 | write_msg("-- ERROR: _set method does not return uint_t:", method ) | ||
| 138 | |||
| 139 | other_methods = filter(lambda x: x not in new_methods, object_methods) | ||
| 140 | other_methods = filter(lambda x: x not in del_methods, other_methods) | ||
| 141 | other_methods = filter(lambda x: x not in do_methods, other_methods) | ||
| 142 | other_methods = filter(lambda x: x not in get_methods, other_methods) | ||
| 143 | other_methods = filter(lambda x: x not in set_methods, other_methods) | ||
| 144 | other_methods = list(other_methods) | ||
| 145 | |||
| 146 | if len(other_methods) > 0: | ||
| 147 | write_msg("-- WARNING: some methods for", object_name, "were unidentified") | ||
| 148 | for method in other_methods: | ||
| 149 | write_msg(method) | ||
| 150 | |||
| 151 | |||
| 152 | # generate this_object | ||
| 153 | short_name = object_name[len('aubio_'):] | ||
| 154 | if short_name in skip_objects: | ||
| 155 | write_msg("-- INFO: skipping object", short_name ) | ||
| 156 | continue | ||
| 157 | if 1: #try: | ||
| 158 | s = gen_new_init(new_methods[0], short_name) | ||
| 159 | s += gen_do(do_methods[0], short_name) | ||
| 160 | s += gen_members(new_methods[0], short_name) | ||
| 161 | s += gen_methods(get_methods, set_methods, short_name) | ||
| 162 | s += gen_finish(short_name) | ||
| 163 | generated_filepath = os.path.join(output_path,'gen-'+short_name+'.c') | ||
| 164 | fd = open(generated_filepath, 'w') | ||
| 165 | fd.write(s) | ||
| 166 | #except Exception, e: | ||
| 167 | # write_msg("-- ERROR:", type(e), str(e), "in", short_name) | ||
| 168 | # continue | ||
| 169 | generated_objects += [this_object] | ||
| 170 | |||
| 171 | s = """// generated list of objects created with generator.py | ||
| 172 | |||
| 173 | """ | ||
| 174 | |||
| 175 | types_ready = [] | ||
| 176 | for each in generated_objects: | ||
| 177 | types_ready.append(" PyType_Ready (&Py_%sType) < 0" % \ | ||
| 178 | each.replace('aubio_','').replace('_t','') ) | ||
| 179 | |||
| 180 | s = """// generated list of objects created with generator.py | ||
| 181 | |||
| 182 | #include "aubio-generated.h" | ||
| 183 | """ | ||
| 184 | |||
| 185 | s += """ | ||
| 186 | int generated_types_ready (void) | ||
| 187 | { | ||
| 188 | return ( | ||
| 189 | """ | ||
| 190 | s += ('\n ||').join(types_ready) | ||
| 191 | s += """); | ||
| 192 | } | ||
| 193 | """ | ||
| 194 | |||
| 195 | s += """ | ||
| 196 | void add_generated_objects ( PyObject *m ) | ||
| 197 | {""" | ||
| 198 | for each in generated_objects: | ||
| 199 | s += """ | ||
| 200 | Py_INCREF (&Py_%(name)sType); | ||
| 201 | PyModule_AddObject (m, "%(name)s", (PyObject *) & Py_%(name)sType);""" % \ | ||
| 202 | { 'name': ( each.replace('aubio_','').replace('_t','') ) } | ||
| 203 | |||
| 204 | s += """ | ||
| 205 | }""" | ||
| 206 | |||
| 207 | fd = open(os.path.join(output_path,'aubio-generated.c'), 'w') | ||
| 208 | fd.write(s) | ||
| 209 | |||
| 210 | s = """// generated list of objects created with generator.py | ||
| 211 | |||
| 212 | #include <Python.h> | ||
| 213 | |||
| 214 | """ | ||
| 215 | |||
| 216 | for each in generated_objects: | ||
| 217 | s += "extern PyTypeObject Py_%sType;\n" % \ | ||
| 218 | each.replace('aubio_','').replace('_t','') | ||
| 219 | |||
| 220 | s+= "int generated_objects ( void );\n" | ||
| 221 | s+= "void add_generated_objects( PyObject *m );\n" | ||
| 222 | |||
| 223 | fd = open(os.path.join(output_path,'aubio-generated.h'), 'w') | ||
| 224 | fd.write(s) | ||
| 225 | |||
| 226 | from os import listdir | ||
| 227 | generated_files = listdir(output_path) | ||
| 228 | generated_files = filter(lambda x: x.endswith('.c'), generated_files) | ||
| 229 | generated_files = [output_path+'/'+f for f in generated_files] | ||
| 230 | return generated_files | ||
| 231 | |||
| 232 | if __name__ == '__main__': | ||
| 233 | generate_object_files('gen') | ||