annotate native/PyRealTime.cpp @ 112:9343eee50605

Update to Python 3. Currently crashes during tests (and also, two tests are now failing, even with Py2).
author Chris Cannam
date Wed, 17 Jun 2015 12:35:41 +0100
parents 917e3e2ef2ee
children 1c7c4bd74363
rev   line source
Chris@26 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@26 2
Chris@26 3 /*
Chris@26 4 VampyHost
Chris@26 5
Chris@26 6 Use Vamp audio analysis plugins in Python
Chris@26 7
Chris@26 8 Gyorgy Fazekas and Chris Cannam
Chris@26 9 Centre for Digital Music, Queen Mary, University of London
Chris@26 10 Copyright 2008-2014 Queen Mary, University of London
Chris@26 11
Chris@26 12 Permission is hereby granted, free of charge, to any person
Chris@26 13 obtaining a copy of this software and associated documentation
Chris@26 14 files (the "Software"), to deal in the Software without
Chris@26 15 restriction, including without limitation the rights to use, copy,
Chris@26 16 modify, merge, publish, distribute, sublicense, and/or sell copies
Chris@26 17 of the Software, and to permit persons to whom the Software is
Chris@26 18 furnished to do so, subject to the following conditions:
Chris@26 19
Chris@26 20 The above copyright notice and this permission notice shall be
Chris@26 21 included in all copies or substantial portions of the Software.
Chris@26 22
Chris@26 23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Chris@26 24 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Chris@26 25 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Chris@26 26 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
Chris@26 27 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
Chris@26 28 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
Chris@26 29 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Chris@26 30
Chris@26 31 Except as contained in this notice, the names of the Centre for
Chris@26 32 Digital Music; Queen Mary, University of London; and the authors
Chris@26 33 shall not be used in advertising or otherwise to promote the sale,
Chris@26 34 use or other dealings in this Software without prior written
Chris@26 35 authorization.
Chris@26 36 */
Chris@26 37
Chris@26 38 #include "PyRealTime.h"
Chris@30 39
Chris@26 40 #include <string>
Chris@26 41
Chris@26 42 using namespace std;
Chris@26 43 using namespace Vamp;
Chris@26 44
Chris@26 45 /* CONSTRUCTOR: New RealTime object from sec and nsec */
Chris@26 46 static PyObject*
Chris@26 47 RealTime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
Chris@26 48 {
Chris@26 49 unsigned int sec = 0;
Chris@26 50 unsigned int nsec = 0;
Chris@26 51 double unary = 0;
Chris@26 52 const char *fmt = NULL;
Chris@26 53
Chris@26 54 if (
Chris@39 55 /// new RealTime from ('format',float) e.g. ('seconds',2.34123)
Chris@39 56 !PyArg_ParseTuple(args, "|sd:RealTime.new ",
Chris@39 57 (const char *) &fmt,
Chris@39 58 (double *) &unary) &&
Chris@26 59
Chris@39 60 /// new RealTime from (sec{int},nsec{int}) e.g. (2,34)
Chris@39 61 !PyArg_ParseTuple(args, "|II:RealTime.new ",
Chris@39 62 (unsigned int*) &sec,
Chris@39 63 (unsigned int*) &nsec)
Chris@39 64
Chris@39 65 ) {
Chris@39 66 PyErr_SetString(PyExc_TypeError,
Chris@91 67 "RealTime constructor requires either (sec,nsec) integer tuple, or ('format',float) where 'format' is 'seconds' or 'milliseconds'");
Chris@39 68 return NULL;
Chris@26 69 }
Chris@26 70
Chris@87 71 PyErr_Clear();
Chris@26 72
Chris@26 73 // RealTimeObject *self = PyObject_New(RealTimeObject, &RealTime_Type);
Chris@26 74 RealTimeObject *self = (RealTimeObject*)type->tp_alloc(type, 0);
Chris@39 75
Chris@26 76 if (self == NULL) return NULL;
Chris@26 77
Chris@26 78 self->rt = NULL;
Chris@26 79
Chris@26 80 if (sec == 0 && nsec == 0 && fmt == 0)
Chris@39 81 self->rt = new RealTime();
Chris@26 82 else if (fmt == 0)
Chris@39 83 self->rt = new RealTime(sec,nsec);
Chris@26 84 else {
Chris@26 85 /// new RealTime from seconds or milliseconds: i.e. >>>RealTime('seconds',12.3)
Chris@39 86 if (!string(fmt).compare("float") ||
Chris@39 87 !string(fmt).compare("seconds"))
Chris@39 88 self->rt = new RealTime(
Chris@39 89 RealTime::fromSeconds((double) unary));
Chris@26 90
Chris@39 91 if (!string(fmt).compare("milliseconds")) {
Chris@39 92 self->rt = new RealTime(
Chris@39 93 RealTime::fromSeconds((double) unary / 1000.0)); }
Chris@26 94 }
Chris@26 95
Chris@26 96 if (!self->rt) {
Chris@39 97 PyErr_SetString(PyExc_TypeError,
Chris@39 98 "RealTime initialised with wrong arguments.");
Chris@39 99 return NULL;
Chris@26 100 }
Chris@26 101
Chris@26 102 return (PyObject *) self;
Chris@26 103 }
Chris@26 104
Chris@26 105 /* DESTRUCTOR: delete type object */
Chris@26 106 static void
Chris@26 107 RealTimeObject_dealloc(RealTimeObject *self)
Chris@26 108 {
Chris@39 109 if (self->rt) delete self->rt; //delete the C object
Chris@26 110 PyObject_Del(self); //delete the Python object (original)
Chris@26 111 /// this requires PyType_Ready() which fills ob_type
Chris@26 112 // self->ob_type->tp_free((PyObject*)self);
Chris@26 113 }
Chris@26 114
Chris@26 115 /* RealTime Object's Methods */
Chris@26 116 //these are internals not exposed by the module but the object
Chris@26 117
Chris@26 118 /* Returns a Tuple containing sec and nsec values */
Chris@26 119 static PyObject *
Chris@26 120 RealTime_values(RealTimeObject *self)
Chris@26 121 {
Chris@26 122 return Py_BuildValue("(ii)",self->rt->sec,self->rt->nsec);
Chris@26 123 }
Chris@26 124
Chris@26 125 /* Returns a Text representation */
Chris@26 126 static PyObject *
Chris@26 127 RealTime_toString(RealTimeObject *self, PyObject *args)
Chris@26 128 {
Chris@26 129 return Py_BuildValue("s",self->rt->toText().c_str());
Chris@26 130 }
Chris@26 131
Chris@26 132 /* Frame representation */
Chris@26 133 static PyObject *
Chris@26 134 RealTime_toFrame(PyObject *self, PyObject *args)
Chris@26 135 {
Chris@26 136 unsigned int samplerate;
Chris@39 137
Chris@26 138 if ( !PyArg_ParseTuple(args, "I:realtime.toFrame object ",
Chris@39 139 (unsigned int *) &samplerate )) {
Chris@39 140 PyErr_SetString(PyExc_ValueError,"Integer Sample Rate Required.");
Chris@39 141 return NULL;
Chris@26 142 }
Chris@39 143
Chris@26 144 return Py_BuildValue("k",
Chris@39 145 RealTime::realTime2Frame(
Chris@39 146 *(const RealTime*) ((RealTimeObject*)self)->rt,
Chris@39 147 (unsigned int) samplerate));
Chris@26 148 }
Chris@26 149
Chris@26 150 /* Conversion of realtime to a double precision floating point value */
Chris@26 151 /* ...in Python called by e.g. float(realtime) */
Chris@26 152 static PyObject *
Chris@26 153 RealTime_float(PyObject *s)
Chris@26 154 {
Chris@26 155 double drt = ((double) ((RealTimeObject*)s)->rt->sec +
Chris@39 156 (double)((double) ((RealTimeObject*)s)->rt->nsec)/1000000000);
Chris@39 157 return PyFloat_FromDouble(drt);
Chris@26 158 }
Chris@26 159
Chris@26 160
Chris@26 161 /* Type object's (RealTime) methods table */
Chris@26 162 static PyMethodDef RealTime_methods[] =
Chris@26 163 {
Chris@39 164 {"values", (PyCFunction)RealTime_values, METH_NOARGS,
Chris@26 165 PyDoc_STR("values() -> Tuple of sec,nsec representation.")},
Chris@26 166
Chris@82 167 {"to_string", (PyCFunction)RealTime_toString, METH_NOARGS,
Chris@82 168 PyDoc_STR("to_string() -> Return a user-readable string to the nearest millisecond in a form like HH:MM:SS.mmm")},
Chris@26 169
Chris@82 170 {"to_frame", (PyCFunction)RealTime_toFrame, METH_VARARGS,
Chris@82 171 PyDoc_STR("to_frame(samplerate) -> Sample count for given sample rate.")},
Chris@26 172
Chris@82 173 {"to_float", (PyCFunction)RealTime_float, METH_NOARGS,
Chris@82 174 PyDoc_STR("to_float() -> Floating point representation.")},
Chris@39 175
Chris@39 176 {NULL, NULL} /* sentinel */
Chris@26 177 };
Chris@26 178
Chris@26 179
Chris@26 180 /* Methods implementing protocols */
Chris@26 181 // these functions are called by the interpreter
Chris@26 182
Chris@26 183 /* Object Protocol */
Chris@26 184
Chris@112 185 #if (PY_MAJOR_VERSION >= 3)
Chris@112 186 #define PyInt_AS_LONG PyLong_AS_LONG
Chris@112 187 #define PyInt_FromSsize_t PyLong_FromSsize_t
Chris@112 188 #endif
Chris@112 189
Chris@26 190 static int
Chris@26 191 RealTime_setattr(RealTimeObject *self, char *name, PyObject *value)
Chris@26 192 {
Chris@112 193 if ( !string(name).compare("sec")) {
Chris@39 194 self->rt->sec= (int) PyInt_AS_LONG(value);
Chris@39 195 return 0;
Chris@26 196 }
Chris@26 197
Chris@26 198 if ( !string(name).compare("nsec")) {
Chris@39 199 self->rt->nsec= (int) PyInt_AS_LONG(value);
Chris@39 200 return 0;
Chris@26 201 }
Chris@26 202
Chris@26 203 return -1;
Chris@26 204 }
Chris@26 205
Chris@26 206 static PyObject *
Chris@112 207 RealTime_getattro(RealTimeObject *self, PyObject *nameobj)
Chris@26 208 {
Chris@112 209 string name;
Chris@112 210 #if PY_MAJOR_VERSION < 3
Chris@112 211 name = PyString_AsString(nameobj);
Chris@112 212 #else
Chris@112 213 name = PyBytes_AsString(PyUnicode_AsUTF8String(nameobj));
Chris@112 214 #endif
Chris@112 215
Chris@26 216 if ( !string(name).compare("sec") ) {
Chris@39 217 return PyInt_FromSsize_t(
Chris@39 218 (Py_ssize_t) self->rt->sec);
Chris@26 219 }
Chris@26 220
Chris@26 221 if ( !string(name).compare("nsec") ) {
Chris@39 222 return PyInt_FromSsize_t(
Chris@39 223 (Py_ssize_t) self->rt->nsec);
Chris@26 224 }
Chris@26 225
Chris@112 226 return PyObject_GenericGetAttr((PyObject *)self, nameobj);
Chris@26 227 }
Chris@26 228
Chris@112 229 static PyObject *
Chris@112 230 RealTime_richcompare(PyObject *self, PyObject *other, int op)
Chris@73 231 {
Chris@73 232 if (!PyRealTime_Check(self) || !PyRealTime_Check(other)) {
Chris@73 233 PyErr_SetString(PyExc_TypeError, "RealTime Object Expected.");
Chris@112 234 return Py_False;
Chris@73 235 }
Chris@73 236
Chris@112 237 RealTime *a = PyRealTime_AS_REALTIME(self);
Chris@112 238 RealTime *b = PyRealTime_AS_REALTIME(other);
Chris@73 239
Chris@112 240 if (op == Py_LT) {
Chris@112 241 return (a < b) ? Py_True : Py_False;
Chris@112 242 } else if (op == Py_LE) {
Chris@112 243 return (a <= b) ? Py_True : Py_False;
Chris@112 244 } else if (op == Py_EQ) {
Chris@112 245 return (a == b) ? Py_True : Py_False;
Chris@112 246 } else if (op == Py_NE) {
Chris@112 247 return (a != b) ? Py_True : Py_False;
Chris@112 248 } else if (op == Py_GT) {
Chris@112 249 return (a > b) ? Py_True : Py_False;
Chris@112 250 } else if (op == Py_GE) {
Chris@112 251 return (a >= b) ? Py_True : Py_False;
Chris@112 252 } else {
Chris@112 253 return Py_False;
Chris@112 254 }
Chris@73 255 }
Chris@73 256
Chris@26 257 /* String representation called by e.g. str(realtime), print realtime*/
Chris@26 258 static PyObject *
Chris@26 259 RealTime_repr(PyObject *self)
Chris@26 260 {
Chris@26 261 return Py_BuildValue("s",
Chris@39 262 ((RealTimeObject*)self)->rt->toString().c_str());
Chris@26 263 }
Chris@26 264
Chris@26 265
Chris@26 266 /* Number Protocol */
Chris@26 267 /// TODO: implement all methods available in Vamp::RealTime() objects
Chris@26 268
Chris@26 269 static PyObject *
Chris@26 270 RealTime_add(PyObject *s, PyObject *w)
Chris@26 271 {
Chris@26 272 RealTimeObject *result =
Chris@39 273 PyObject_New(RealTimeObject, &RealTime_Type);
Chris@26 274 if (result == NULL) return NULL;
Chris@26 275
Chris@26 276 result->rt = new RealTime(
Chris@39 277 *((RealTimeObject*)s)->rt + *((RealTimeObject*)w)->rt);
Chris@26 278 return (PyObject*)result;
Chris@26 279 }
Chris@26 280
Chris@26 281 static PyObject *
Chris@26 282 RealTime_subtract(PyObject *s, PyObject *w)
Chris@26 283 {
Chris@26 284 RealTimeObject *result =
Chris@39 285 PyObject_New(RealTimeObject, &RealTime_Type);
Chris@26 286 if (result == NULL) return NULL;
Chris@26 287
Chris@26 288 result->rt = new RealTime(
Chris@39 289 *((RealTimeObject*)s)->rt - *((RealTimeObject*)w)->rt);
Chris@26 290 return (PyObject*)result;
Chris@26 291 }
Chris@26 292
Chris@26 293 static PyNumberMethods realtime_as_number =
Chris@26 294 {
Chris@112 295 (binaryfunc)RealTime_add, /*nb_add*/
Chris@112 296 (binaryfunc)RealTime_subtract, /*nb_subtract*/
Chris@39 297 0, /*nb_multiply*/
Chris@112 298 #if (PY_MAJOR_VERSION < 3)
Chris@39 299 0, /*nb_divide*/
Chris@112 300 #endif
Chris@39 301 0, /*nb_remainder*/
Chris@39 302 0, /*nb_divmod*/
Chris@39 303 0, /*nb_power*/
Chris@39 304 0, /*nb_neg*/
Chris@39 305 0, /*nb_pos*/
Chris@39 306 0, /*(unaryfunc)array_abs,*/
Chris@39 307 0, /*nb_nonzero*/
Chris@39 308 0, /*nb_invert*/
Chris@39 309 0, /*nb_lshift*/
Chris@39 310 0, /*nb_rshift*/
Chris@39 311 0, /*nb_and*/
Chris@39 312 0, /*nb_xor*/
Chris@39 313 0, /*nb_or*/
Chris@112 314 #if (PY_MAJOR_VERSION < 3)
Chris@26 315 0, /*nb_coerce*/
Chris@112 316 #endif
Chris@39 317 0, /*nb_int*/
Chris@39 318 0, /*nb_long*/
Chris@26 319 (unaryfunc)RealTime_float,/*nb_float*/
Chris@26 320 };
Chris@26 321
Chris@26 322 /* REAL-TIME TYPE OBJECT */
Chris@26 323
Chris@26 324 #define RealTime_alloc PyType_GenericAlloc
Chris@26 325 #define RealTime_free PyObject_Del
Chris@26 326
Chris@26 327 /* Doc:: 10.3 Type Objects */ /* static */
Chris@26 328 PyTypeObject RealTime_Type =
Chris@26 329 {
Chris@112 330 PyVarObject_HEAD_INIT(NULL, 0)
Chris@39 331 "vampy.RealTime", /*tp_name*/
Chris@39 332 sizeof(RealTimeObject), /*tp_basicsize*/
Chris@39 333 0, /*tp_itemsize*/
Chris@39 334 /* methods */
Chris@26 335 (destructor)RealTimeObject_dealloc, /*tp_dealloc*/
Chris@39 336 0, /*tp_print*/
Chris@112 337 0, /*tp_getattr*/
Chris@26 338 (setattrfunc)RealTime_setattr, /*tp_setattr*/
Chris@112 339 0, /*tp_compare*/
Chris@39 340 RealTime_repr, /*tp_repr*/
Chris@39 341 &realtime_as_number, /*tp_as_number*/
Chris@39 342 0, /*tp_as_sequence*/
Chris@39 343 0, /*tp_as_mapping*/
Chris@39 344 0, /*tp_hash*/
Chris@39 345 0, /*tp_call*/
Chris@26 346 0, /*tp_str*/
Chris@112 347 (getattrofunc)RealTime_getattro, /*tp_getattro*/
Chris@26 348 0, /*tp_setattro*/
Chris@26 349 0, /*tp_as_buffer*/
Chris@26 350 Py_TPFLAGS_DEFAULT, /*tp_flags*/
Chris@39 351 "RealTime object, used for Vamp plugin timestamps.", /*tp_doc*/
Chris@26 352 0, /*tp_traverse*/
Chris@26 353 0, /*tp_clear*/
Chris@112 354 (richcmpfunc)RealTime_richcompare, /*tp_richcompare*/
Chris@26 355 0, /*tp_weaklistoffset*/
Chris@26 356 0, /*tp_iter*/
Chris@26 357 0, /*tp_iternext*/
Chris@26 358 RealTime_methods, /*tp_methods*/ //TypeObject Methods
Chris@26 359 0, /*tp_members*/
Chris@26 360 0, /*tp_getset*/
Chris@26 361 0, /*tp_base*/
Chris@26 362 0, /*tp_dict*/
Chris@26 363 0, /*tp_descr_get*/
Chris@26 364 0, /*tp_descr_set*/
Chris@26 365 0, /*tp_dictoffset*/
Chris@26 366 0, /*tp_init*/
Chris@26 367 RealTime_alloc, /*tp_alloc*/
Chris@26 368 RealTime_new, /*tp_new*/
Chris@39 369 RealTime_free, /*tp_free*/
Chris@26 370 0, /*tp_is_gc*/
Chris@26 371 };
Chris@26 372
Chris@26 373
Chris@26 374
Chris@26 375 /* PyRealTime C++ API */
Chris@26 376
Chris@26 377 /*PyRealTime from RealTime*/
Chris@26 378 PyObject*
Chris@26 379 PyRealTime_FromRealTime(const Vamp::RealTime& rt) {
Chris@26 380
Chris@26 381 RealTimeObject *self =
Chris@39 382 PyObject_New(RealTimeObject, &RealTime_Type);
Chris@26 383 if (self == NULL) return NULL;
Chris@26 384
Chris@26 385 self->rt = new RealTime(rt);
Chris@26 386 return (PyObject*) self;
Chris@26 387 }
Chris@26 388
Chris@26 389 /*RealTime* from PyRealTime*/
Chris@26 390 const Vamp::RealTime*
Chris@26 391 PyRealTime_AsRealTime (PyObject *self) {
Chris@26 392
Chris@26 393 RealTimeObject *s = (RealTimeObject*) self;
Chris@26 394
Chris@26 395 if (!PyRealTime_Check(s)) {
Chris@39 396 PyErr_SetString(PyExc_TypeError, "RealTime Object Expected.");
Chris@39 397 cerr << "in call PyRealTime_AsPointer(): RealTime Object Expected. " << endl;
Chris@39 398 return NULL; }
Chris@26 399 return s->rt;
Chris@26 400 };
Chris@26 401