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