annotate native/PyRealTime.cpp @ 151:5a6b8f4be9b9 tracks tip

Docs
author Chris Cannam
date Fri, 21 Apr 2017 14:33:57 +0100
parents 1f23d18883a1
children
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@117 10 Copyright 2008-2015 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@124 45 #if (PY_MAJOR_VERSION >= 3)
Chris@124 46 #define PyInt_AS_LONG PyLong_AS_LONG
Chris@124 47 #define PyInt_FromSsize_t PyLong_FromSsize_t
Chris@124 48 #endif
Chris@124 49
Chris@26 50 /* CONSTRUCTOR: New RealTime object from sec and nsec */
Chris@26 51 static PyObject*
Chris@26 52 RealTime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
Chris@26 53 {
Chris@124 54 int sec = 0;
Chris@124 55 int nsec = 0;
Chris@124 56 int unaryInt = 0;
Chris@26 57 double unary = 0;
Chris@26 58 const char *fmt = NULL;
Chris@26 59
Chris@124 60 if (!PyArg_ParseTuple(args, ":RealTime.new ")) { // zero time
Chris@26 61
Chris@124 62 PyErr_Clear();
Chris@124 63
Chris@124 64 /// new RealTime from exact ('format',int) e.g. ('milliseconds',200)
Chris@124 65 if (!PyArg_ParseTuple(args, "si:RealTime.new ",
Chris@124 66 (const char *) &fmt,
Chris@124 67 (int *) &unaryInt)) {
Chris@124 68
Chris@124 69 PyErr_Clear();
Chris@124 70
Chris@124 71 /// new RealTime from ('format',float) e.g. ('seconds',2.34123)
Chris@124 72 if (!PyArg_ParseTuple(args, "sd:RealTime.new ",
Chris@124 73 (const char *) &fmt,
Chris@124 74 (double *) &unary)) {
Chris@124 75
Chris@124 76 PyErr_Clear();
Chris@124 77
Chris@124 78 /// new RealTime from (sec{int},nsec{int}) e.g. (2,34)
Chris@124 79 if (!PyArg_ParseTuple(args, "ii:RealTime.new ",
Chris@124 80 (int*) &sec,
Chris@124 81 (int*) &nsec)) {
Chris@124 82
Chris@124 83 PyErr_SetString(PyExc_TypeError,
Chris@124 84 "RealTime constructor requires either (sec,nsec) integer tuple, or ('format',float) where 'format' is 'seconds' or 'milliseconds'");
Chris@124 85 return NULL;
Chris@124 86 }
Chris@124 87 }
Chris@124 88 }
Chris@26 89 }
Chris@26 90
Chris@87 91 PyErr_Clear();
Chris@26 92
Chris@124 93 // Using PyObject_New because we use PyObject_Del to delete in the
Chris@124 94 // destructor
Chris@124 95 RealTimeObject *self = PyObject_New(RealTimeObject, &RealTime_Type);
Chris@124 96 PyObject_Init((PyObject *)self, &RealTime_Type);
Chris@39 97
Chris@26 98 if (self == NULL) return NULL;
Chris@26 99
Chris@26 100 self->rt = NULL;
Chris@26 101
Chris@26 102 if (sec == 0 && nsec == 0 && fmt == 0)
Chris@39 103 self->rt = new RealTime();
Chris@26 104 else if (fmt == 0)
Chris@39 105 self->rt = new RealTime(sec,nsec);
Chris@26 106 else {
Chris@26 107 /// new RealTime from seconds or milliseconds: i.e. >>>RealTime('seconds',12.3)
Chris@39 108 if (!string(fmt).compare("float") ||
Chris@124 109 !string(fmt).compare("seconds")) {
Chris@26 110
Chris@124 111 if (unaryInt != 0) {
Chris@124 112 self->rt = new RealTime(RealTime::fromMilliseconds(unaryInt * 1000));
Chris@124 113 } else {
Chris@124 114 self->rt = new RealTime(RealTime::fromSeconds(unary));
Chris@124 115 }
Chris@124 116
Chris@124 117 } else if (!string(fmt).compare("milliseconds")) {
Chris@124 118
Chris@124 119 if (unaryInt != 0) {
Chris@124 120 self->rt = new RealTime(RealTime::fromMilliseconds(unaryInt));
Chris@124 121 } else {
Chris@124 122 self->rt = new RealTime(RealTime::fromSeconds(unary / 1000.0));
Chris@124 123 }
Chris@124 124 }
Chris@26 125 }
Chris@26 126
Chris@26 127 if (!self->rt) {
Chris@39 128 PyErr_SetString(PyExc_TypeError,
Chris@39 129 "RealTime initialised with wrong arguments.");
Chris@39 130 return NULL;
Chris@26 131 }
Chris@26 132
Chris@26 133 return (PyObject *) self;
Chris@26 134 }
Chris@26 135
Chris@26 136 /* DESTRUCTOR: delete type object */
Chris@26 137 static void
Chris@26 138 RealTimeObject_dealloc(RealTimeObject *self)
Chris@26 139 {
Chris@124 140 delete self->rt; // delete the C object
Chris@124 141
Chris@124 142 // "If the type is not subtypable (doesn’t have the
Chris@124 143 // Py_TPFLAGS_BASETYPE flag bit set), it is permissible to call
Chris@124 144 // the object deallocator directly instead of via tp_free"
Chris@124 145 PyObject_Del(self); // delete the Python object (original)
Chris@26 146 }
Chris@26 147
Chris@26 148 /* RealTime Object's Methods */
Chris@26 149 //these are internals not exposed by the module but the object
Chris@26 150
Chris@26 151 /* Returns a Tuple containing sec and nsec values */
Chris@26 152 static PyObject *
Chris@26 153 RealTime_values(RealTimeObject *self)
Chris@26 154 {
Chris@134 155 return Py_BuildValue("(ii)", self->rt->sec, self->rt->nsec);
Chris@26 156 }
Chris@26 157
Chris@26 158 /* Returns a Text representation */
Chris@26 159 static PyObject *
Chris@26 160 RealTime_toString(RealTimeObject *self, PyObject *args)
Chris@26 161 {
Chris@134 162 return Py_BuildValue("s", self->rt->toText().c_str());
Chris@26 163 }
Chris@26 164
Chris@26 165 /* Frame representation */
Chris@26 166 static PyObject *
Chris@26 167 RealTime_toFrame(PyObject *self, PyObject *args)
Chris@26 168 {
Chris@26 169 unsigned int samplerate;
Chris@39 170
Chris@134 171 if (!PyArg_ParseTuple(args, "I:realtime.toFrame object ",
Chris@134 172 (unsigned int *) &samplerate)) {
Chris@39 173 PyErr_SetString(PyExc_ValueError,"Integer Sample Rate Required.");
Chris@39 174 return NULL;
Chris@26 175 }
Chris@39 176
Chris@26 177 return Py_BuildValue("k",
Chris@39 178 RealTime::realTime2Frame(
Chris@39 179 *(const RealTime*) ((RealTimeObject*)self)->rt,
Chris@39 180 (unsigned int) samplerate));
Chris@26 181 }
Chris@26 182
Chris@26 183 /* Conversion of realtime to a double precision floating point value */
Chris@26 184 /* ...in Python called by e.g. float(realtime) */
Chris@26 185 static PyObject *
Chris@26 186 RealTime_float(PyObject *s)
Chris@26 187 {
Chris@26 188 double drt = ((double) ((RealTimeObject*)s)->rt->sec +
Chris@39 189 (double)((double) ((RealTimeObject*)s)->rt->nsec)/1000000000);
Chris@39 190 return PyFloat_FromDouble(drt);
Chris@26 191 }
Chris@26 192
Chris@26 193
Chris@26 194 /* Type object's (RealTime) methods table */
Chris@26 195 static PyMethodDef RealTime_methods[] =
Chris@26 196 {
Chris@124 197 {"values", (PyCFunction)RealTime_values, METH_NOARGS,
Chris@26 198 PyDoc_STR("values() -> Tuple of sec,nsec representation.")},
Chris@26 199
Chris@124 200 {"to_string", (PyCFunction)RealTime_toString, METH_NOARGS,
Chris@82 201 PyDoc_STR("to_string() -> Return a user-readable string to the nearest millisecond in a form like HH:MM:SS.mmm")},
Chris@26 202
Chris@82 203 {"to_frame", (PyCFunction)RealTime_toFrame, METH_VARARGS,
Chris@82 204 PyDoc_STR("to_frame(samplerate) -> Sample count for given sample rate.")},
Chris@26 205
Chris@82 206 {"to_float", (PyCFunction)RealTime_float, METH_NOARGS,
Chris@82 207 PyDoc_STR("to_float() -> Floating point representation.")},
Chris@39 208
Chris@39 209 {NULL, NULL} /* sentinel */
Chris@26 210 };
Chris@26 211
Chris@26 212
Chris@26 213 /* Methods implementing protocols */
Chris@26 214 // these functions are called by the interpreter
Chris@26 215
Chris@26 216 /* Object Protocol */
Chris@26 217
Chris@26 218 static int
Chris@26 219 RealTime_setattr(RealTimeObject *self, char *name, PyObject *value)
Chris@26 220 {
Chris@124 221 if (!string(name).compare("sec")) {
Chris@124 222 self->rt->sec = (int) PyInt_AS_LONG(value);
Chris@39 223 return 0;
Chris@26 224 }
Chris@26 225
Chris@124 226 if (!string(name).compare("nsec")) {
Chris@124 227 self->rt->nsec = (int) PyInt_AS_LONG(value);
Chris@39 228 return 0;
Chris@26 229 }
Chris@26 230
Chris@26 231 return -1;
Chris@26 232 }
Chris@26 233
Chris@26 234 static PyObject *
Chris@112 235 RealTime_getattro(RealTimeObject *self, PyObject *nameobj)
Chris@26 236 {
Chris@112 237 string name;
Chris@112 238 #if PY_MAJOR_VERSION < 3
Chris@112 239 name = PyString_AsString(nameobj);
Chris@112 240 #else
Chris@112 241 name = PyBytes_AsString(PyUnicode_AsUTF8String(nameobj));
Chris@112 242 #endif
Chris@112 243
Chris@26 244 if ( !string(name).compare("sec") ) {
Chris@39 245 return PyInt_FromSsize_t(
Chris@39 246 (Py_ssize_t) self->rt->sec);
Chris@26 247 }
Chris@26 248
Chris@26 249 if ( !string(name).compare("nsec") ) {
Chris@39 250 return PyInt_FromSsize_t(
Chris@39 251 (Py_ssize_t) self->rt->nsec);
Chris@26 252 }
Chris@26 253
Chris@112 254 return PyObject_GenericGetAttr((PyObject *)self, nameobj);
Chris@26 255 }
Chris@26 256
Chris@112 257 static PyObject *
Chris@112 258 RealTime_richcompare(PyObject *self, PyObject *other, int op)
Chris@73 259 {
Chris@73 260 if (!PyRealTime_Check(self) || !PyRealTime_Check(other)) {
Chris@73 261 PyErr_SetString(PyExc_TypeError, "RealTime Object Expected.");
Chris@112 262 return Py_False;
Chris@73 263 }
Chris@73 264
Chris@113 265 RealTime *ap = PyRealTime_AS_REALTIME(self);
Chris@113 266 RealTime *bp = PyRealTime_AS_REALTIME(other);
Chris@113 267
Chris@113 268 if (!ap || !bp) return Py_False;
Chris@113 269 const RealTime &a = *ap;
Chris@113 270 const RealTime &b = *bp;
Chris@73 271
Chris@116 272 // cerr << "a = " << a << ", b = " << b << ", op = " << op << endl;
Chris@116 273
Chris@116 274 PyObject *result = Py_False;
Chris@116 275
Chris@112 276 if (op == Py_LT) {
Chris@116 277 result = (a < b) ? Py_True : Py_False;
Chris@112 278 } else if (op == Py_LE) {
Chris@116 279 result = (a <= b) ? Py_True : Py_False;
Chris@112 280 } else if (op == Py_EQ) {
Chris@116 281 result = (a == b) ? Py_True : Py_False;
Chris@112 282 } else if (op == Py_NE) {
Chris@116 283 result = (a != b) ? Py_True : Py_False;
Chris@112 284 } else if (op == Py_GT) {
Chris@116 285 result = (a > b) ? Py_True : Py_False;
Chris@112 286 } else if (op == Py_GE) {
Chris@116 287 result = (a >= b) ? Py_True : Py_False;
Chris@112 288 }
Chris@116 289
Chris@116 290 // cerr << "returning: " << (result == Py_True ? "true" : "false") << endl;
Chris@116 291
Chris@134 292 Py_INCREF(result);
Chris@116 293 return result;
Chris@73 294 }
Chris@73 295
Chris@26 296 /* String representation called by e.g. str(realtime), print realtime*/
Chris@26 297 static PyObject *
Chris@26 298 RealTime_repr(PyObject *self)
Chris@26 299 {
Chris@26 300 return Py_BuildValue("s",
Chris@39 301 ((RealTimeObject*)self)->rt->toString().c_str());
Chris@26 302 }
Chris@26 303
Chris@26 304
Chris@26 305 /* Number Protocol */
Chris@26 306 /// TODO: implement all methods available in Vamp::RealTime() objects
Chris@26 307
Chris@26 308 static PyObject *
Chris@26 309 RealTime_add(PyObject *s, PyObject *w)
Chris@26 310 {
Chris@124 311 RealTimeObject *result = PyObject_New(RealTimeObject, &RealTime_Type);
Chris@26 312 if (result == NULL) return NULL;
Chris@124 313 PyObject_Init((PyObject *)result, &RealTime_Type);
Chris@26 314
Chris@26 315 result->rt = new RealTime(
Chris@39 316 *((RealTimeObject*)s)->rt + *((RealTimeObject*)w)->rt);
Chris@26 317 return (PyObject*)result;
Chris@26 318 }
Chris@26 319
Chris@26 320 static PyObject *
Chris@26 321 RealTime_subtract(PyObject *s, PyObject *w)
Chris@26 322 {
Chris@124 323 RealTimeObject *result = PyObject_New(RealTimeObject, &RealTime_Type);
Chris@26 324 if (result == NULL) return NULL;
Chris@124 325 PyObject_Init((PyObject *)result, &RealTime_Type);
Chris@26 326
Chris@26 327 result->rt = new RealTime(
Chris@39 328 *((RealTimeObject*)s)->rt - *((RealTimeObject*)w)->rt);
Chris@26 329 return (PyObject*)result;
Chris@26 330 }
Chris@26 331
Chris@26 332 static PyNumberMethods realtime_as_number =
Chris@26 333 {
Chris@112 334 (binaryfunc)RealTime_add, /*nb_add*/
Chris@112 335 (binaryfunc)RealTime_subtract, /*nb_subtract*/
Chris@39 336 0, /*nb_multiply*/
Chris@112 337 #if (PY_MAJOR_VERSION < 3)
Chris@39 338 0, /*nb_divide*/
Chris@112 339 #endif
Chris@39 340 0, /*nb_remainder*/
Chris@39 341 0, /*nb_divmod*/
Chris@39 342 0, /*nb_power*/
Chris@39 343 0, /*nb_neg*/
Chris@39 344 0, /*nb_pos*/
Chris@39 345 0, /*(unaryfunc)array_abs,*/
Chris@39 346 0, /*nb_nonzero*/
Chris@39 347 0, /*nb_invert*/
Chris@39 348 0, /*nb_lshift*/
Chris@39 349 0, /*nb_rshift*/
Chris@39 350 0, /*nb_and*/
Chris@39 351 0, /*nb_xor*/
Chris@39 352 0, /*nb_or*/
Chris@112 353 #if (PY_MAJOR_VERSION < 3)
Chris@26 354 0, /*nb_coerce*/
Chris@112 355 #endif
Chris@39 356 0, /*nb_int*/
Chris@39 357 0, /*nb_long*/
Chris@26 358 (unaryfunc)RealTime_float,/*nb_float*/
Chris@26 359 };
Chris@26 360
Chris@26 361 /* REAL-TIME TYPE OBJECT */
Chris@26 362
Chris@26 363 /* Doc:: 10.3 Type Objects */ /* static */
Chris@26 364 PyTypeObject RealTime_Type =
Chris@26 365 {
Chris@112 366 PyVarObject_HEAD_INIT(NULL, 0)
Chris@124 367 "vampyhost.RealTime", /*tp_name*/
Chris@39 368 sizeof(RealTimeObject), /*tp_basicsize*/
Chris@39 369 0, /*tp_itemsize*/
Chris@39 370 /* methods */
Chris@26 371 (destructor)RealTimeObject_dealloc, /*tp_dealloc*/
Chris@39 372 0, /*tp_print*/
Chris@112 373 0, /*tp_getattr*/
Chris@26 374 (setattrfunc)RealTime_setattr, /*tp_setattr*/
Chris@112 375 0, /*tp_compare*/
Chris@39 376 RealTime_repr, /*tp_repr*/
Chris@39 377 &realtime_as_number, /*tp_as_number*/
Chris@39 378 0, /*tp_as_sequence*/
Chris@39 379 0, /*tp_as_mapping*/
Chris@39 380 0, /*tp_hash*/
Chris@39 381 0, /*tp_call*/
Chris@26 382 0, /*tp_str*/
Chris@112 383 (getattrofunc)RealTime_getattro, /*tp_getattro*/
Chris@26 384 0, /*tp_setattro*/
Chris@26 385 0, /*tp_as_buffer*/
Chris@26 386 Py_TPFLAGS_DEFAULT, /*tp_flags*/
Chris@39 387 "RealTime object, used for Vamp plugin timestamps.", /*tp_doc*/
Chris@26 388 0, /*tp_traverse*/
Chris@26 389 0, /*tp_clear*/
Chris@112 390 (richcmpfunc)RealTime_richcompare, /*tp_richcompare*/
Chris@26 391 0, /*tp_weaklistoffset*/
Chris@26 392 0, /*tp_iter*/
Chris@26 393 0, /*tp_iternext*/
Chris@26 394 RealTime_methods, /*tp_methods*/ //TypeObject Methods
Chris@26 395 0, /*tp_members*/
Chris@26 396 0, /*tp_getset*/
Chris@26 397 0, /*tp_base*/
Chris@26 398 0, /*tp_dict*/
Chris@26 399 0, /*tp_descr_get*/
Chris@26 400 0, /*tp_descr_set*/
Chris@26 401 0, /*tp_dictoffset*/
Chris@26 402 0, /*tp_init*/
Chris@124 403 0, /*tp_alloc*/
Chris@26 404 RealTime_new, /*tp_new*/
Chris@124 405 0, /*tp_free*/
Chris@26 406 0, /*tp_is_gc*/
Chris@26 407 };
Chris@26 408
Chris@26 409
Chris@26 410
Chris@26 411 /* PyRealTime C++ API */
Chris@26 412
Chris@26 413 /*PyRealTime from RealTime*/
Chris@26 414 PyObject*
Chris@26 415 PyRealTime_FromRealTime(const Vamp::RealTime& rt) {
Chris@26 416
Chris@26 417 RealTimeObject *self =
Chris@39 418 PyObject_New(RealTimeObject, &RealTime_Type);
Chris@26 419 if (self == NULL) return NULL;
Chris@26 420
Chris@26 421 self->rt = new RealTime(rt);
Chris@26 422 return (PyObject*) self;
Chris@26 423 }
Chris@26 424
Chris@26 425 /*RealTime* from PyRealTime*/
Chris@26 426 const Vamp::RealTime*
Chris@26 427 PyRealTime_AsRealTime (PyObject *self) {
Chris@26 428
Chris@26 429 RealTimeObject *s = (RealTimeObject*) self;
Chris@26 430
Chris@26 431 if (!PyRealTime_Check(s)) {
Chris@39 432 PyErr_SetString(PyExc_TypeError, "RealTime Object Expected.");
Chris@39 433 cerr << "in call PyRealTime_AsPointer(): RealTime Object Expected. " << endl;
Chris@113 434 return NULL;
Chris@113 435 }
Chris@26 436 return s->rt;
Chris@26 437 };
Chris@26 438