annotate native/PyRealTime.cpp @ 113:1c7c4bd74363

Fix RealTime compare (& thus the tests, for Py2 anyway)
author Chris Cannam
date Wed, 17 Jun 2015 12:43:01 +0100
parents 9343eee50605
children 3489986a044c 2370b942cd32
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@113 237 RealTime *ap = PyRealTime_AS_REALTIME(self);
Chris@113 238 RealTime *bp = PyRealTime_AS_REALTIME(other);
Chris@113 239
Chris@113 240 if (!ap || !bp) return Py_False;
Chris@113 241 const RealTime &a = *ap;
Chris@113 242 const RealTime &b = *bp;
Chris@73 243
Chris@112 244 if (op == Py_LT) {
Chris@112 245 return (a < b) ? Py_True : Py_False;
Chris@112 246 } else if (op == Py_LE) {
Chris@112 247 return (a <= b) ? Py_True : Py_False;
Chris@112 248 } else if (op == Py_EQ) {
Chris@112 249 return (a == b) ? Py_True : Py_False;
Chris@112 250 } else if (op == Py_NE) {
Chris@112 251 return (a != b) ? Py_True : Py_False;
Chris@112 252 } else if (op == Py_GT) {
Chris@112 253 return (a > b) ? Py_True : Py_False;
Chris@112 254 } else if (op == Py_GE) {
Chris@112 255 return (a >= b) ? Py_True : Py_False;
Chris@112 256 } else {
Chris@112 257 return Py_False;
Chris@112 258 }
Chris@73 259 }
Chris@73 260
Chris@26 261 /* String representation called by e.g. str(realtime), print realtime*/
Chris@26 262 static PyObject *
Chris@26 263 RealTime_repr(PyObject *self)
Chris@26 264 {
Chris@26 265 return Py_BuildValue("s",
Chris@39 266 ((RealTimeObject*)self)->rt->toString().c_str());
Chris@26 267 }
Chris@26 268
Chris@26 269
Chris@26 270 /* Number Protocol */
Chris@26 271 /// TODO: implement all methods available in Vamp::RealTime() objects
Chris@26 272
Chris@26 273 static PyObject *
Chris@26 274 RealTime_add(PyObject *s, PyObject *w)
Chris@26 275 {
Chris@26 276 RealTimeObject *result =
Chris@39 277 PyObject_New(RealTimeObject, &RealTime_Type);
Chris@26 278 if (result == NULL) return NULL;
Chris@26 279
Chris@26 280 result->rt = new RealTime(
Chris@39 281 *((RealTimeObject*)s)->rt + *((RealTimeObject*)w)->rt);
Chris@26 282 return (PyObject*)result;
Chris@26 283 }
Chris@26 284
Chris@26 285 static PyObject *
Chris@26 286 RealTime_subtract(PyObject *s, PyObject *w)
Chris@26 287 {
Chris@26 288 RealTimeObject *result =
Chris@39 289 PyObject_New(RealTimeObject, &RealTime_Type);
Chris@26 290 if (result == NULL) return NULL;
Chris@26 291
Chris@26 292 result->rt = new RealTime(
Chris@39 293 *((RealTimeObject*)s)->rt - *((RealTimeObject*)w)->rt);
Chris@26 294 return (PyObject*)result;
Chris@26 295 }
Chris@26 296
Chris@26 297 static PyNumberMethods realtime_as_number =
Chris@26 298 {
Chris@112 299 (binaryfunc)RealTime_add, /*nb_add*/
Chris@112 300 (binaryfunc)RealTime_subtract, /*nb_subtract*/
Chris@39 301 0, /*nb_multiply*/
Chris@112 302 #if (PY_MAJOR_VERSION < 3)
Chris@39 303 0, /*nb_divide*/
Chris@112 304 #endif
Chris@39 305 0, /*nb_remainder*/
Chris@39 306 0, /*nb_divmod*/
Chris@39 307 0, /*nb_power*/
Chris@39 308 0, /*nb_neg*/
Chris@39 309 0, /*nb_pos*/
Chris@39 310 0, /*(unaryfunc)array_abs,*/
Chris@39 311 0, /*nb_nonzero*/
Chris@39 312 0, /*nb_invert*/
Chris@39 313 0, /*nb_lshift*/
Chris@39 314 0, /*nb_rshift*/
Chris@39 315 0, /*nb_and*/
Chris@39 316 0, /*nb_xor*/
Chris@39 317 0, /*nb_or*/
Chris@112 318 #if (PY_MAJOR_VERSION < 3)
Chris@26 319 0, /*nb_coerce*/
Chris@112 320 #endif
Chris@39 321 0, /*nb_int*/
Chris@39 322 0, /*nb_long*/
Chris@26 323 (unaryfunc)RealTime_float,/*nb_float*/
Chris@26 324 };
Chris@26 325
Chris@26 326 /* REAL-TIME TYPE OBJECT */
Chris@26 327
Chris@26 328 #define RealTime_alloc PyType_GenericAlloc
Chris@26 329 #define RealTime_free PyObject_Del
Chris@26 330
Chris@26 331 /* Doc:: 10.3 Type Objects */ /* static */
Chris@26 332 PyTypeObject RealTime_Type =
Chris@26 333 {
Chris@112 334 PyVarObject_HEAD_INIT(NULL, 0)
Chris@39 335 "vampy.RealTime", /*tp_name*/
Chris@39 336 sizeof(RealTimeObject), /*tp_basicsize*/
Chris@39 337 0, /*tp_itemsize*/
Chris@39 338 /* methods */
Chris@26 339 (destructor)RealTimeObject_dealloc, /*tp_dealloc*/
Chris@39 340 0, /*tp_print*/
Chris@112 341 0, /*tp_getattr*/
Chris@26 342 (setattrfunc)RealTime_setattr, /*tp_setattr*/
Chris@112 343 0, /*tp_compare*/
Chris@39 344 RealTime_repr, /*tp_repr*/
Chris@39 345 &realtime_as_number, /*tp_as_number*/
Chris@39 346 0, /*tp_as_sequence*/
Chris@39 347 0, /*tp_as_mapping*/
Chris@39 348 0, /*tp_hash*/
Chris@39 349 0, /*tp_call*/
Chris@26 350 0, /*tp_str*/
Chris@112 351 (getattrofunc)RealTime_getattro, /*tp_getattro*/
Chris@26 352 0, /*tp_setattro*/
Chris@26 353 0, /*tp_as_buffer*/
Chris@26 354 Py_TPFLAGS_DEFAULT, /*tp_flags*/
Chris@39 355 "RealTime object, used for Vamp plugin timestamps.", /*tp_doc*/
Chris@26 356 0, /*tp_traverse*/
Chris@26 357 0, /*tp_clear*/
Chris@112 358 (richcmpfunc)RealTime_richcompare, /*tp_richcompare*/
Chris@26 359 0, /*tp_weaklistoffset*/
Chris@26 360 0, /*tp_iter*/
Chris@26 361 0, /*tp_iternext*/
Chris@26 362 RealTime_methods, /*tp_methods*/ //TypeObject Methods
Chris@26 363 0, /*tp_members*/
Chris@26 364 0, /*tp_getset*/
Chris@26 365 0, /*tp_base*/
Chris@26 366 0, /*tp_dict*/
Chris@26 367 0, /*tp_descr_get*/
Chris@26 368 0, /*tp_descr_set*/
Chris@26 369 0, /*tp_dictoffset*/
Chris@26 370 0, /*tp_init*/
Chris@26 371 RealTime_alloc, /*tp_alloc*/
Chris@26 372 RealTime_new, /*tp_new*/
Chris@39 373 RealTime_free, /*tp_free*/
Chris@26 374 0, /*tp_is_gc*/
Chris@26 375 };
Chris@26 376
Chris@26 377
Chris@26 378
Chris@26 379 /* PyRealTime C++ API */
Chris@26 380
Chris@26 381 /*PyRealTime from RealTime*/
Chris@26 382 PyObject*
Chris@26 383 PyRealTime_FromRealTime(const Vamp::RealTime& rt) {
Chris@26 384
Chris@26 385 RealTimeObject *self =
Chris@39 386 PyObject_New(RealTimeObject, &RealTime_Type);
Chris@26 387 if (self == NULL) return NULL;
Chris@26 388
Chris@26 389 self->rt = new RealTime(rt);
Chris@26 390 return (PyObject*) self;
Chris@26 391 }
Chris@26 392
Chris@26 393 /*RealTime* from PyRealTime*/
Chris@26 394 const Vamp::RealTime*
Chris@26 395 PyRealTime_AsRealTime (PyObject *self) {
Chris@26 396
Chris@26 397 RealTimeObject *s = (RealTimeObject*) self;
Chris@26 398
Chris@26 399 if (!PyRealTime_Check(s)) {
Chris@39 400 PyErr_SetString(PyExc_TypeError, "RealTime Object Expected.");
Chris@39 401 cerr << "in call PyRealTime_AsPointer(): RealTime Object Expected. " << endl;
Chris@113 402 return NULL;
Chris@113 403 }
Chris@26 404 return s->rt;
Chris@26 405 };
Chris@26 406