Mercurial > hg > audiodb
comparison bindings/python/pyadbmodule.c @ 622:695651b8c1a3
added a query hook. Should compile a run, but I haven't exhaustively tested the various input parameters yet.
As such, there may well be some ways to get to the api calls that bring the module down.
Let me know if you find any.
The actual query call is a bit of a mess, but will be more intuitive from the native python layer (to be written)...
so the python bindings now have a complete path:
>>import _pyadb
>>aDB = _pyadb._pyadb_create("test.adb", 0,0,0)
>>_pyadb._pyadb_status(aDB)
>>_pyadb._pyadb_insertFromFile(aDB, "someFeats.mfcc12")
...(add some more data)
>>result = _pyadb._pyadb_queryFromKey(aDB, "a Key in aDB", [options])
and then result has a nice dict of your results.
author | map01bf |
---|---|
date | Mon, 21 Sep 2009 17:42:52 +0000 |
parents | 2e9a6e4500d3 |
children | afa05407ce41 |
comparison
equal
deleted
inserted
replaced
621:2e9a6e4500d3 | 622:695651b8c1a3 |
---|---|
8 // Distributed and licensed under GPL2. See ../../license.txt for details. | 8 // Distributed and licensed under GPL2. See ../../license.txt for details. |
9 // | 9 // |
10 #include <fcntl.h> | 10 #include <fcntl.h> |
11 #include <string.h> | 11 #include <string.h> |
12 #include "Python.h" | 12 #include "Python.h" |
13 #include "structmember.h" | |
13 #include "audioDB_API.h" | 14 #include "audioDB_API.h" |
14 #include "numpy/arrayobject.h" | 15 #include "numpy/arrayobject.h" |
15 | 16 |
16 static void _pyadb_close(void *ptr); | 17 static void _pyadb_close(void *ptr); |
17 | 18 |
100 ok = PyArg_ParseTuple(args, "O", &incoming); | 101 ok = PyArg_ParseTuple(args, "O", &incoming); |
101 if (!ok) return 0; | 102 if (!ok) return 0; |
102 current_db = (adb_ptr)PyCObject_AsVoidPtr(incoming); | 103 current_db = (adb_ptr)PyCObject_AsVoidPtr(incoming); |
103 | 104 |
104 ok = audiodb_l2norm(current_db); | 105 ok = audiodb_l2norm(current_db); |
105 return Py_BuildValue("i", ok); | 106 return PyBool_FromLong(ok-1); |
106 | 107 |
107 } | 108 } |
108 | 109 |
109 /*engage power thresholding in the referenced db*/ | 110 /*engage power thresholding in the referenced db*/ |
110 /*api call:*/ | 111 /*api call:*/ |
118 ok = PyArg_ParseTuple(args, "O", &incoming); | 119 ok = PyArg_ParseTuple(args, "O", &incoming); |
119 if (!ok) return 0; | 120 if (!ok) return 0; |
120 current_db = (adb_ptr)PyCObject_AsVoidPtr(incoming); | 121 current_db = (adb_ptr)PyCObject_AsVoidPtr(incoming); |
121 | 122 |
122 ok = audiodb_power(current_db); | 123 ok = audiodb_power(current_db); |
123 return Py_BuildValue("i", ok); | 124 return PyBool_FromLong(ok-1); |
124 | 125 |
125 } | 126 } |
126 /* insert feature data stored in a file */ | 127 /* insert feature data stored in a file */ |
127 /* this is a bit gross, */ | 128 /* this is a bit gross, */ |
128 /* should be replaced eventually by a numpy based feature.*/ | 129 /* should be replaced eventually by a numpy based feature.*/ |
153 ins = (adb_insert_ptr)malloc(sizeof(adb_insert_t)); | 154 ins = (adb_insert_ptr)malloc(sizeof(adb_insert_t)); |
154 ins->features = features; | 155 ins->features = features; |
155 ins->power = power; | 156 ins->power = power; |
156 ins->key = key; | 157 ins->key = key; |
157 ins->times = times; | 158 ins->times = times; |
158 printf("features::%s\npower::%s\nkey::%s\ntimes::%s\n", ins->features, ins->power, ins->key, ins->times); | 159 //printf("features::%s\npower::%s\nkey::%s\ntimes::%s\n", ins->features, ins->power, ins->key, ins->times); |
159 ok = audiodb_insert(current_db, ins); | 160 ok = audiodb_insert(current_db, ins); |
160 return Py_BuildValue("i", ok); | 161 return PyBool_FromLong(ok-1); |
161 | 162 |
162 } | 163 } |
164 | |
165 | |
166 /* base query. The nomenclature here is about a far away as pythonic as is possible. | |
167 * This should be taken care of via the higher level python structure | |
168 * returns a dict that should be result ordered and key = result key | |
169 * and value is a list of tuples one per result associated with that key, of the form: | |
170 * (dist, qpos, ipos) | |
171 * Note as well that this is by no means the most efficient way to cast from C, simply the most direct | |
172 * and what it lacks in effeciency it gains in python side access. It remains to be seen if this is | |
173 * a sensible trade. | |
174 * api call: | |
175 * adb_query_results_t *audiodb_query_spec(adb_t *, const adb_query_spec_t *); | |
176 ***/ | |
177 PyObject * _pyadb_queryFromKey(PyObject *self, PyObject *args, PyObject *keywds) | |
178 { | |
179 adb_ptr current_db; | |
180 adb_query_spec_t *spec; | |
181 adb_query_results_t *result; | |
182 int ok, exhaustive, falsePositives; | |
183 uint32_t i; | |
184 const char *key; | |
185 const char *accuMode = "db"; | |
186 const char *distMode = "dot"; | |
187 const char *errMsg = NULL; | |
188 uint32_t hop = 0; | |
189 double radius = 0; | |
190 double absThres = 0; | |
191 double relThres = 0; | |
192 double durRatio = 0; | |
193 PyObject *includeKeys = NULL; | |
194 PyObject *excludeKeys = NULL; | |
195 PyObject *incoming = 0; | |
196 PyObject *outgoing = NULL; | |
197 PyObject *thisKey = NULL; | |
198 PyObject *currentValue = 0; | |
199 PyObject *newBits = 0; | |
200 static char *kwlist[] = { "db", "key", | |
201 "seqLength", | |
202 "seqStart", | |
203 "exhaustive", | |
204 "falsePositives", | |
205 "accumulation", | |
206 "distance", | |
207 "npoints",//nearest neighbor points per track | |
208 "ntracks",//I don't know what this one is... Maybe number of results... | |
209 "includeKeys", | |
210 "excludeKeys", | |
211 "radius", | |
212 "absThres", | |
213 "relThres", | |
214 "durRatio", | |
215 "hopSize" | |
216 }; | |
217 spec = (adb_query_spec_t *)malloc(sizeof(adb_query_spec_t)); | |
218 spec->qid.datum = (adb_datum_t *)malloc(sizeof(adb_datum_t)); | |
219 result = (adb_query_results_t *)malloc(sizeof(adb_query_results_t)); | |
220 | |
221 spec->qid.sequence_length = 16; | |
222 spec->qid.sequence_start = 0; | |
223 spec->qid.flags = 0; | |
224 spec->params.npoints = 1; | |
225 spec->params.ntracks = 100;//number of results returned in db mode | |
226 spec->refine.flags = 0; | |
227 | |
228 ok = PyArg_ParseTupleAndKeywords(args, keywds, "Os|iiiissIIOOddddI", kwlist, | |
229 &incoming, &key, | |
230 &spec->qid.sequence_length, | |
231 &spec->qid.sequence_start, | |
232 &exhaustive, &falsePositives, | |
233 &accuMode,&distMode, | |
234 &spec->params.npoints, | |
235 &spec->params.ntracks, | |
236 &includeKeys, &excludeKeys, | |
237 &radius, &absThres, &relThres, &durRatio, &hop | |
238 ); | |
239 | |
240 if (!ok) {return NULL;} | |
241 current_db = (adb_ptr)PyCObject_AsVoidPtr(incoming); | |
242 | |
243 if (exhaustive){ | |
244 spec->qid.flags = spec->qid.flags | ADB_QID_FLAG_EXHAUSTIVE; | |
245 } | |
246 if (falsePositives){ | |
247 spec->qid.flags = spec->qid.flags | ADB_QID_FLAG_ALLOW_FALSE_POSITIVES; | |
248 } | |
249 | |
250 //set up spec->params | |
251 if (strcmp(accuMode,"db")){ | |
252 spec->params.accumulation = ADB_ACCUMULATION_DB; | |
253 } else if (strcmp(accuMode,"track")){ | |
254 spec->params.accumulation = ADB_ACCUMULATION_PER_TRACK; | |
255 } else if (strcmp(accuMode,"one2one")){ | |
256 spec->params.accumulation = ADB_ACCUMULATION_ONE_TO_ONE; | |
257 } else{ | |
258 //error dump | |
259 return NULL; | |
260 } | |
261 if (strcmp(distMode, "dot")){ | |
262 spec->params.distance = ADB_DISTANCE_DOT_PRODUCT; | |
263 }else if (strcmp(distMode, "eucNorm")){ | |
264 spec->params.distance = ADB_DISTANCE_EUCLIDEAN_NORMED; | |
265 }else if (strcmp(distMode, "euclidean")){ | |
266 spec->params.distance = ADB_DISTANCE_EUCLIDEAN; | |
267 }else{ | |
268 //error dump | |
269 return NULL; | |
270 } | |
271 | |
272 //set up spec->refine | |
273 //include/exclude keys | |
274 if (includeKeys){ | |
275 if (!PyList_Check(includeKeys)){ | |
276 //error! | |
277 return NULL; | |
278 } | |
279 spec->refine.flags = spec->refine.flags | ADB_REFINE_INCLUDE_KEYLIST; | |
280 spec->refine.include.nkeys = (uint32_t)PyList_Size(includeKeys); | |
281 spec->refine.include.keys = (const char **)calloc(sizeof(const char *), spec->refine.include.nkeys); | |
282 for (i=0;i<spec->refine.include.nkeys;i++){ | |
283 if (PyString_Check(PyList_GetItem(includeKeys, (Py_ssize_t)i))){ | |
284 spec->refine.include.keys[i] = PyString_AsString(PyList_GetItem(includeKeys, (Py_ssize_t)i)); | |
285 }else{ | |
286 //bad string no cookie! | |
287 return NULL; | |
288 } | |
289 } | |
290 } | |
291 if (excludeKeys){ | |
292 if (!PyList_Check(excludeKeys)){ | |
293 //error! | |
294 return NULL; | |
295 } | |
296 spec->refine.flags = spec->refine.flags | ADB_REFINE_EXCLUDE_KEYLIST; | |
297 spec->refine.exclude.nkeys = (uint32_t)PyList_Size(excludeKeys); | |
298 spec->refine.exclude.keys = (const char **)calloc(sizeof(const char *), spec->refine.exclude.nkeys); | |
299 for (i=0;i<spec->refine.exclude.nkeys;i++){ | |
300 if (PyString_Check(PyList_GetItem(excludeKeys, (Py_ssize_t)i))){ | |
301 spec->refine.exclude.keys[i] = PyString_AsString(PyList_GetItem(excludeKeys, (Py_ssize_t)i)); | |
302 }else{ | |
303 //bad string no cookie! | |
304 return NULL; | |
305 } | |
306 } | |
307 } | |
308 //the rest of spec->refine | |
309 if (radius){ | |
310 spec->refine.flags = spec->refine.flags | ADB_REFINE_RADIUS; | |
311 spec->refine.radius = radius; | |
312 } | |
313 if (absThres){ | |
314 spec->refine.flags = spec->refine.flags | ADB_REFINE_ABSOLUTE_THRESHOLD; | |
315 spec->refine.absolute_threshold = absThres; | |
316 } | |
317 if (relThres){ | |
318 spec->refine.flags = spec->refine.flags | ADB_REFINE_RELATIVE_THRESHOLD; | |
319 spec->refine.relative_threshold = relThres; | |
320 } | |
321 if (durRatio){ | |
322 spec->refine.flags = spec->refine.flags | ADB_REFINE_DURATION_RATIO; | |
323 spec->refine.duration_ratio = durRatio; | |
324 } | |
325 if (hop){ | |
326 spec->refine.flags = spec->refine.flags | ADB_REFINE_HOP_SIZE; | |
327 spec->refine.hopsize = hop; | |
328 } | |
329 //setup the datum | |
330 spec->qid.datum->data = NULL; | |
331 spec->qid.datum->power = NULL; | |
332 spec->qid.datum->times = NULL; | |
333 //grab the datum from the key | |
334 ok = audiodb_retrieve_datum(current_db, key, spec->qid.datum); | |
335 if (ok != 0){ | |
336 PyErr_SetString(PyExc_RuntimeError, "Encountered an error while trying to retrieve the data associated with the passed key.\n"); | |
337 return NULL; | |
338 } | |
339 result = audiodb_query_spec(current_db, spec); | |
340 if (result == NULL){ | |
341 PyErr_SetString(PyExc_RuntimeError, "Encountered an error while running the actual query.\n"); | |
342 return NULL; | |
343 } | |
344 outgoing = PyDict_New(); | |
345 for (i=0;i<result->nresults;i++){ | |
346 thisKey = PyString_FromString(result->results[i].key); | |
347 if (!PyDict_Contains(outgoing, thisKey)){ | |
348 newBits = Py_BuildValue("[(dII)]", | |
349 result->results[i].dist, | |
350 result->results[i].qpos, | |
351 result->results[i].ipos); | |
352 if (PyDict_SetItem(outgoing, thisKey,newBits)){ | |
353 printf("key : %s\ndist : %f\nqpos : %i\nipos : %i\n", result->results[i].key, result->results[i].dist, result->results[i].qpos, result->results[i].ipos); | |
354 PyErr_SetString(PyExc_AttributeError, "Error adding a tuple to the result dict\n"); | |
355 // PyObject_Print(newBits, STDOUT, Py_PRINT_RAW); | |
356 Py_XDECREF(newBits); | |
357 return NULL; | |
358 } | |
359 Py_DECREF(newBits); | |
360 }else { | |
361 //the key already has a value, so we need to fetch the value, confirm it's a list and append another tuple to it. | |
362 currentValue = PyDict_GetItem(outgoing, thisKey); | |
363 if (!PyList_Check(currentValue)){ | |
364 //add some error msg... | |
365 return NULL; | |
366 } | |
367 newBits = Py_BuildValue("dII",result->results[i].dist, | |
368 result->results[i].qpos, | |
369 result->results[i].ipos); | |
370 if (PyList_Append(currentValue, newBits)){ | |
371 //error msg here | |
372 Py_XDECREF(newBits); | |
373 return NULL; | |
374 } | |
375 if (PyDict_SetItem(outgoing, thisKey, newBits)){ | |
376 PyErr_SetString(PyExc_AttributeError, "Error adding a tuple to the result dict\n"); | |
377 // PyObject_Print(newBits, STDOUT, Py_PRINT_RAW); | |
378 Py_XDECREF(newBits); | |
379 return NULL; | |
380 } | |
381 Py_DECREF(newBits); | |
382 | |
383 } | |
384 } | |
385 if (!audiodb_query_free_results(current_db, spec, result)){ | |
386 printf("bit of trouble freeing the result and spec...\ncheck for leaks."); | |
387 } | |
388 | |
389 return outgoing; | |
390 | |
391 | |
392 | |
393 } | |
394 | |
395 | |
396 | |
397 | |
398 | |
163 | 399 |
164 | 400 |
165 | 401 |
166 | 402 |
167 /* close a database */ | 403 /* close a database */ |
186 "_status(adb_ptr)->(numFiles, dims, dudCount, nullCount, flags, length, data_region_size)"}, | 422 "_status(adb_ptr)->(numFiles, dims, dudCount, nullCount, flags, length, data_region_size)"}, |
187 { "_pyadb_l2norm", _pyadb_l2norm, METH_VARARGS, | 423 { "_pyadb_l2norm", _pyadb_l2norm, METH_VARARGS, |
188 "_pyadb_l2norm(adb_ptr)->int return code (0 for sucess)"}, | 424 "_pyadb_l2norm(adb_ptr)->int return code (0 for sucess)"}, |
189 { "_pyadb_power", _pyadb_power, METH_VARARGS, | 425 { "_pyadb_power", _pyadb_power, METH_VARARGS, |
190 "_pyadb_power(adb_ptr)->int return code (0 for sucess)"}, | 426 "_pyadb_power(adb_ptr)->int return code (0 for sucess)"}, |
191 { "_pyadb_insertFromFile", _pyadb_insertFromFile, METH_VARARGS | METH_KEYWORDS, | 427 { "_pyadb_insertFromFile", (PyCFunction)_pyadb_insertFromFile, METH_VARARGS | METH_KEYWORDS, |
192 "_pyadb_insertFromFile(adb_ptr, features=featureFile, [power=powerfile | key=keystring | times=timingFile])->\ | 428 "_pyadb_insertFromFile(adb_ptr, features=featureFile, [power=powerfile | key=keystring | times=timingFile])->\ |
193 int return code (0 for sucess)"}, | 429 int return code (0 for sucess)"}, |
430 { "_pyadb_queryFromKey", (PyCFunction)_pyadb_queryFromKey, METH_VARARGS | METH_KEYWORDS, | |
431 "base query. The nomenclature here is about a far away as pythonic as is possible.\n\ | |
432 This should be taken care of via the higher level python structure\n\ | |
433 returns a dict that should be result ordered and key = result key\n\ | |
434 and value is a list of tuples one per result associated with that key, of the form:\n\ | |
435 \t(dist, qpos, ipos)\n\ | |
436 Note as well that this is by no means the most efficient way to cast from C, simply the most direct\n\ | |
437 and what it lacks in effeciency it gains in python side access. It remains to be seen if this is\n\ | |
438 a sensible trade.\n\ | |
439 _pyadb_queryFromKey(adb_ptr, query key,\n\ | |
440 [seqLength = Int Sequence Length, \n\ | |
441 seqStart = Int offset from start for key, \n\ | |
442 exhaustive = boolean - True for exhaustive (false by default),\n\ | |
443 falsePositives= boolean - True to keep fps (false by defaults),\n\ | |
444 accumulation = [\"db\"|\"track\"|\"one2one\"] (\"db\" by default),\n\ | |
445 distance = [\"dot\"|\"eucNorm\"|\"euclidean\"] (\"dot\" by default),\n\ | |
446 npoints = int number of points per track,\n\ | |
447 ntracks = max number of results returned in db accu mode,\n\ | |
448 includeKeys = list of strings to include (use all by default),\n\ | |
449 excludeKeys = list of strings to exclude (none by default),\n\ | |
450 radius = double of nnRadius (1.0 default, overrides npoints if specified),\n\ | |
451 absThres = double absolute power threshold (db must have power),\n\ | |
452 relThres = double relative power threshold (db must have power),\n\ | |
453 durRatio = double time expansion/compresion ratio,\n\ | |
454 hopSize = int hopsize (1 by default)])->resultDict\n"}, | |
194 {NULL,NULL, 0, NULL} | 455 {NULL,NULL, 0, NULL} |
195 }; | 456 }; |
196 | 457 |
197 void init_pyadb() | 458 void init_pyadb() |
198 { | 459 { |