map01bf@620
|
1 // pyadbmodule.c
|
map01bf@620
|
2 //
|
map01bf@620
|
3 // the internal portion of the wrapper for audio
|
map01bf@620
|
4 // see pyadb.py for the public classes
|
map01bf@620
|
5 //
|
map01bf@620
|
6 // Created by Benjamin Fields on 2009-09-04.
|
map01bf@716
|
7 // Big update for direct data insertion 2010-June (Benjamin Fields)
|
map01bf@716
|
8 // Copyleft 2009, 2010 Goldsmith University of London.
|
map01bf@621
|
9 // Distributed and licensed under GPL2. See ../../license.txt for details.
|
map01bf@620
|
10 //
|
map01bf@620
|
11 #include <fcntl.h>
|
map01bf@621
|
12 #include <string.h>
|
map01bf@620
|
13 #include "Python.h"
|
map01bf@622
|
14 #include "structmember.h"
|
map01bf@620
|
15 #include "audioDB_API.h"
|
map01bf@620
|
16 #include "numpy/arrayobject.h"
|
map01bf@620
|
17
|
mas01mc@746
|
18 #define ADB_HEADER_FLAG_L2NORM (0x1U)
|
mas01mc@746
|
19 #define ADB_HEADER_FLAG_POWER (0x4U)
|
mas01mc@746
|
20 #define ADB_HEADER_FLAG_TIMES (0x20U)
|
mas01mc@746
|
21 #define ADB_HEADER_FLAG_REFERENCES (0x40U)
|
mas01mc@746
|
22
|
map01bf@620
|
23 static void _pyadb_close(void *ptr);
|
map01bf@620
|
24
|
map01bf@620
|
25 /* create a new database */
|
map01bf@620
|
26 /* returns a struct or NULL on failure */
|
map01bf@620
|
27 /* api call: */
|
mas01cr@671
|
28 /* adb_t *audiodb_create(const char *path, unsigned datasize, unsigned ntracks, unsigned datadim);*/
|
map01bf@620
|
29 PyObject * _pyadb_create(PyObject *self, PyObject *args)
|
map01bf@620
|
30 {
|
map01bf@620
|
31 unsigned datasize, ntracks, datadim;
|
map01bf@620
|
32 const char *path;
|
map01bf@620
|
33 int ok;
|
mas01cr@671
|
34 adb_t *new_database;
|
map01bf@620
|
35 ok = PyArg_ParseTuple(args, "sIII", &path, &datasize, &ntracks, &datadim);
|
map01bf@620
|
36 if (!ok) return 0;
|
map01bf@620
|
37 new_database = audiodb_create(path, datasize, ntracks, datadim);
|
map01bf@620
|
38 if (!new_database) return 0;
|
map01bf@620
|
39
|
mas01mc@746
|
40 return PyCObject_FromVoidPtr( new_database, _pyadb_close);
|
map01bf@620
|
41 }
|
map01bf@620
|
42
|
map01bf@620
|
43 /* open an existing database */
|
map01bf@620
|
44 /* returns a struct or NULL on failure */
|
map01bf@620
|
45 /* flags expects fcntl flags concerning the opening mode */
|
map01bf@620
|
46 /* api call: */
|
mas01cr@671
|
47 // adb_t *audiodb_open(const char *path, int flags);
|
map01bf@620
|
48 PyObject * _pyadb_open(PyObject *self, PyObject *args)
|
map01bf@620
|
49 {
|
map01bf@620
|
50 const char *path;
|
map01bf@620
|
51 char mode;
|
map01bf@620
|
52 int ok;//in python layer need to translate boolean flags to byte mask
|
mas01cr@671
|
53 adb_t *fresh_database;
|
map01bf@620
|
54 ok = PyArg_ParseTuple(args, "sc", &path, &mode);
|
map01bf@620
|
55 if (!ok) return 0;
|
map01bf@620
|
56 if (mode == 'r'){
|
map01bf@620
|
57 fresh_database = audiodb_open(path, O_RDONLY);
|
map01bf@620
|
58 }else if (mode == 'w'){
|
map01bf@620
|
59 fresh_database = audiodb_open(path, O_RDWR);
|
map01bf@620
|
60 }else{
|
map01bf@620
|
61 PyErr_SetString(PyExc_ValueError,
|
map01bf@620
|
62 "mode must be either \'r\' or \'w\'. It appears to be something else.");
|
map01bf@620
|
63 return 0;
|
map01bf@620
|
64 }
|
map01bf@620
|
65 if (!fresh_database) return 0;
|
map01bf@620
|
66
|
map01bf@620
|
67 return PyCObject_FromVoidPtr( fresh_database, _pyadb_close);
|
map01bf@620
|
68 }
|
map01bf@620
|
69
|
map01bf@620
|
70 /* database status */
|
map01bf@620
|
71 /* api call: */
|
mas01cr@671
|
72 // int audiodb_status(adb_t *mydb, adb_status_ptr status);
|
map01bf@620
|
73 PyObject * _pyadb_status(PyObject *self, PyObject *args)
|
map01bf@620
|
74 {
|
mas01cr@671
|
75 adb_t *check_db;
|
mas01cr@671
|
76 adb_status_t *status;
|
map01bf@620
|
77 int flags, ok;
|
map01bf@620
|
78 PyObject * incoming = 0;
|
mas01cr@671
|
79 status = (adb_status_t *)malloc(sizeof(adb_status_t));
|
map01bf@620
|
80
|
map01bf@620
|
81 ok = PyArg_ParseTuple(args, "O", &incoming);
|
map01bf@620
|
82 if (!ok) return 0;
|
mas01cr@671
|
83 check_db = (adb_t *)PyCObject_AsVoidPtr(incoming);
|
map01bf@620
|
84
|
map01bf@620
|
85
|
map01bf@620
|
86 flags = audiodb_status(check_db, status);
|
map01bf@620
|
87 return Py_BuildValue("IIIIILL", status->numFiles,
|
map01bf@620
|
88 status->dim,
|
map01bf@620
|
89 status->dudCount,
|
map01bf@620
|
90 status->nullCount,
|
map01bf@620
|
91 status->flags,
|
map01bf@620
|
92 status->length,
|
map01bf@620
|
93 status->data_region_size);
|
map01bf@620
|
94
|
map01bf@620
|
95 }
|
map01bf@620
|
96
|
map01bf@620
|
97 /*engage l2norm in the referenced db*/
|
map01bf@620
|
98 /*api call:*/
|
mas01cr@671
|
99 //int audiodb_l2norm(adb_t *mydb);
|
map01bf@620
|
100 PyObject * _pyadb_l2norm(PyObject *self, PyObject *args)
|
map01bf@620
|
101 {
|
mas01cr@671
|
102 adb_t *current_db;
|
map01bf@620
|
103 int ok;
|
map01bf@620
|
104 PyObject * incoming = 0;
|
map01bf@620
|
105
|
map01bf@620
|
106 ok = PyArg_ParseTuple(args, "O", &incoming);
|
map01bf@620
|
107 if (!ok) return 0;
|
mas01cr@671
|
108 current_db = (adb_t *)PyCObject_AsVoidPtr(incoming);
|
map01bf@620
|
109
|
map01bf@620
|
110 ok = audiodb_l2norm(current_db);
|
map01bf@622
|
111 return PyBool_FromLong(ok-1);
|
map01bf@620
|
112
|
map01bf@620
|
113 }
|
map01bf@620
|
114
|
map01bf@620
|
115 /*engage power thresholding in the referenced db*/
|
map01bf@620
|
116 /*api call:*/
|
mas01cr@671
|
117 // int audiodb_power(adb_t *mydb);
|
map01bf@620
|
118 PyObject * _pyadb_power(PyObject *self, PyObject *args)
|
map01bf@620
|
119 {
|
mas01cr@671
|
120 adb_t *current_db;
|
map01bf@620
|
121 int ok;
|
map01bf@620
|
122 PyObject * incoming = 0;
|
map01bf@620
|
123
|
map01bf@620
|
124 ok = PyArg_ParseTuple(args, "O", &incoming);
|
map01bf@620
|
125 if (!ok) return 0;
|
mas01cr@671
|
126 current_db = (adb_t *)PyCObject_AsVoidPtr(incoming);
|
map01bf@620
|
127
|
map01bf@620
|
128 ok = audiodb_power(current_db);
|
map01bf@622
|
129 return PyBool_FromLong(ok-1);
|
map01bf@620
|
130
|
map01bf@620
|
131 }
|
map01bf@716
|
132
|
map01bf@716
|
133 /* insert feature data from a numpy array */
|
map01bf@720
|
134 /* array given should have ndarray.shape = (numVectors, numDims)*/
|
map01bf@716
|
135 /* array datatype needs to be doubles (float may work...)*/
|
map01bf@716
|
136 /* if power is given, must be 1d array of length numVectors*/
|
map01bf@716
|
137 /* if times is given, must be 1d array of length 2*numVectors like this:*/
|
map01bf@716
|
138
|
map01bf@716
|
139 /* api call: */
|
map01bf@716
|
140 // typedef struct adb_datum {
|
map01bf@716
|
141 // uint32_t nvectors;
|
map01bf@716
|
142 // uint32_t dim;
|
map01bf@716
|
143 // const char *key;
|
map01bf@716
|
144 // double *data;
|
map01bf@716
|
145 // double *power;
|
map01bf@716
|
146 // double *times;
|
map01bf@716
|
147 // } adb_datum_t;
|
map01bf@716
|
148 // int audiodb_insert_datum(adb_t *, const adb_datum_t *);
|
map01bf@716
|
149 PyObject * _pyadb_insertFromArray(PyObject *self, PyObject *args, PyObject *keywds)
|
map01bf@716
|
150 {
|
map01bf@716
|
151 adb_t *current_db;
|
map01bf@716
|
152 adb_status_t *status;
|
map01bf@716
|
153 adb_datum_t *ins;
|
map01bf@716
|
154 int ok;
|
map01bf@716
|
155 npy_intp dims[1];
|
map01bf@716
|
156 unsigned int nDims = 0;
|
map01bf@716
|
157 unsigned int nVect = 0;
|
map01bf@716
|
158 PyObject *incoming = 0;
|
map01bf@718
|
159 PyArrayObject *features = 0;
|
map01bf@718
|
160 PyArrayObject *power = 0;
|
map01bf@718
|
161 PyArrayObject *times = 0;
|
map01bf@716
|
162 const char *key = NULL;
|
map01bf@716
|
163 PyArray_Descr *descr;
|
map01bf@716
|
164 static char *kwlist[] = { "db", "features", "nDim", "nVect", "power", "key", "times" , NULL};
|
map01bf@716
|
165
|
map01bf@718
|
166 ok = PyArg_ParseTupleAndKeywords(args, keywds, "OO!II|O!sO!", kwlist, &incoming, &PyArray_Type, &features, &nDims, &nVect, &PyArray_Type, &power, &key, &PyArray_Type, ×);
|
mas01mc@743
|
167 if (!ok){
|
mas01mc@743
|
168 PyErr_SetString(PyExc_TypeError, "Failed at PyArg_ParseTupleAndKeywords");
|
mas01mc@743
|
169 return NULL;
|
mas01mc@743
|
170 }
|
map01bf@716
|
171 //check our arrays
|
map01bf@718
|
172 // if (!PyArray_Check(features)){
|
map01bf@718
|
173 // PyErr_SetString(PyExc_TypeError, "features must be a numpy array (of floats or doubles)");
|
map01bf@718
|
174 // return NULL;
|
map01bf@718
|
175 // }
|
map01bf@716
|
176 if (!PyArray_ISFLOAT(features)){
|
map01bf@716
|
177 PyErr_SetString(PyExc_TypeError, "features numpy array must contain floats or doubles");
|
map01bf@716
|
178 return NULL;
|
map01bf@716
|
179 }
|
map01bf@716
|
180 if ((PyArray_NDIM(features) != 1) || (PyArray_DIMS(features)[0] != (nDims * nVect))){
|
map01bf@716
|
181 PyErr_SetString(PyExc_TypeError, "features numpy array must be flattened before call.");
|
map01bf@716
|
182 return NULL;
|
map01bf@716
|
183 }
|
map01bf@716
|
184 descr = PyArray_DescrFromType(NPY_DOUBLE);
|
map01bf@716
|
185
|
map01bf@716
|
186 if (power){
|
map01bf@716
|
187 if (!PyArray_Check(power)){
|
map01bf@716
|
188 PyErr_SetString(PyExc_TypeError, "power, if given, must be a numpy array (of floats or doubles)");
|
map01bf@716
|
189 return NULL;
|
map01bf@716
|
190 }
|
map01bf@716
|
191 if (!PyArray_ISFLOAT(power)){
|
map01bf@716
|
192 PyErr_SetString(PyExc_TypeError, "power numpy array, if given, must contain floats or doubles");
|
map01bf@716
|
193 return NULL;
|
map01bf@716
|
194 }
|
map01bf@716
|
195 // power = (PyArrayObject *)PyCObject_AsVoidPtr(incomingPow);
|
mas01mc@743
|
196 if (PyArray_NDIM(features) != 1 || PyArray_DIMS(power)[0] != nVect){
|
map01bf@716
|
197 PyErr_SetString(PyExc_ValueError, "power, if given must be a 1d numpy array with shape = (numVectors,)");
|
map01bf@716
|
198 return NULL;
|
map01bf@716
|
199 }
|
map01bf@716
|
200 }
|
map01bf@716
|
201 if (times){
|
map01bf@716
|
202 if (!PyArray_Check(times)){
|
map01bf@716
|
203 PyErr_SetString(PyExc_TypeError, "times, if given, must be a numpy array (of floats or doubles)");
|
map01bf@716
|
204 return NULL;
|
map01bf@716
|
205 }
|
map01bf@716
|
206 if (!PyArray_ISFLOAT(times)){
|
map01bf@716
|
207 PyErr_SetString(PyExc_TypeError, "times numpy array, if given, must contain floats or doubles");
|
map01bf@716
|
208 return NULL;
|
map01bf@716
|
209 }
|
map01bf@716
|
210 // times = (PyArrayObject *)PyCObject_AsVoidPtr(incomingTime);
|
mas01mc@749
|
211 if (PyArray_NDIM(times) != 1 || PyArray_DIMS(times)[0] != (nVect*2)){
|
mas01mc@749
|
212 PyErr_SetString(PyExc_ValueError, "times, if given must be a 1d numpy array with shape = (numVectors*2,)");
|
map01bf@716
|
213 return NULL;
|
map01bf@716
|
214 }
|
map01bf@716
|
215 }
|
map01bf@716
|
216 current_db = (adb_t *)PyCObject_AsVoidPtr(incoming);
|
map01bf@716
|
217 status = (adb_status_t *)malloc(sizeof(adb_status_t));
|
map01bf@716
|
218 //verify that the data to be inserted is the correct size for the database.
|
map01bf@716
|
219
|
map01bf@716
|
220 ins = (adb_datum_t *)malloc(sizeof(adb_datum_t));
|
mas01mc@758
|
221 if (PyArray_AsCArray((PyObject**)&features, &(ins->data), dims, 1, descr)){
|
map01bf@716
|
222 PyErr_SetString(PyExc_RuntimeError, "Trouble expressing the feature np array as a C array.");
|
map01bf@716
|
223 return NULL;
|
map01bf@716
|
224 }
|
map01bf@716
|
225
|
map01bf@718
|
226 if (power){
|
mas01mc@758
|
227 if (PyArray_AsCArray((PyObject**)&power, &(ins->power), dims, 1, descr)){
|
map01bf@716
|
228 PyErr_SetString(PyExc_RuntimeError, "Trouble expressing the power np array as a C array.");
|
map01bf@716
|
229 return NULL;
|
map01bf@716
|
230 }
|
map01bf@719
|
231 }else{
|
map01bf@719
|
232 ins->power=NULL;
|
map01bf@716
|
233 }
|
map01bf@716
|
234
|
map01bf@718
|
235 if (times){
|
mas01mc@758
|
236 if (PyArray_AsCArray((PyObject**)×, &(ins->times), dims, 1, descr)){
|
map01bf@716
|
237 PyErr_SetString(PyExc_RuntimeError, "Trouble expressing the times np array as a C array.");
|
map01bf@716
|
238 return NULL;
|
map01bf@716
|
239 }
|
map01bf@719
|
240 }else{
|
map01bf@719
|
241 ins->times=NULL;
|
map01bf@716
|
242 }
|
map01bf@716
|
243 ins->key = key;
|
map01bf@716
|
244 ins->nvectors = (uint32_t)nVect;
|
map01bf@716
|
245 ins->dim = (uint32_t)nDims;
|
map01bf@716
|
246 //printf("features::%s\npower::%s\nkey::%s\ntimes::%s\n", ins->features, ins->power, ins->key, ins->times);
|
map01bf@716
|
247 ok = audiodb_insert_datum(current_db, ins);//(current_db, ins);
|
map01bf@719
|
248 return PyInt_FromLong(ok);
|
map01bf@716
|
249
|
map01bf@716
|
250 }
|
map01bf@716
|
251
|
map01bf@621
|
252 /* insert feature data stored in a file */
|
map01bf@621
|
253 /* this is a bit gross, */
|
map01bf@621
|
254 /* should be replaced eventually by a numpy based feature.*/
|
map01bf@621
|
255 /* api call: */
|
mas01cr@673
|
256 // struct adb_insert {
|
map01bf@621
|
257 // const char *features;
|
map01bf@621
|
258 // const char *power;
|
map01bf@621
|
259 // const char *key;
|
map01bf@621
|
260 // const char *times;
|
map01bf@621
|
261 // };
|
mas01cr@671
|
262 // int audiodb_insert(adb_t *mydb, adb_insert_t *ins);
|
map01bf@621
|
263 PyObject * _pyadb_insertFromFile(PyObject *self, PyObject *args, PyObject *keywds)
|
map01bf@621
|
264 {
|
mas01cr@671
|
265 adb_t *current_db;
|
mas01cr@671
|
266 adb_insert_t *ins;
|
map01bf@621
|
267 int ok;
|
map01bf@621
|
268 const char *features;
|
map01bf@621
|
269 const char *power = NULL;
|
map01bf@621
|
270 const char *key = NULL;
|
map01bf@621
|
271 const char *times = NULL;
|
map01bf@621
|
272 PyObject * incoming = 0;
|
map01bf@621
|
273 static char *kwlist[] = { "db", "features", "power", "key", "times" , NULL};
|
map01bf@621
|
274
|
map01bf@621
|
275 ok = PyArg_ParseTupleAndKeywords(args, keywds, "Os|sss", kwlist, &incoming, &features, &power, &key, ×);
|
map01bf@621
|
276 if (!ok){return NULL;}
|
map01bf@621
|
277
|
mas01cr@671
|
278 current_db = (adb_t *)PyCObject_AsVoidPtr(incoming);
|
mas01cr@671
|
279 ins = (adb_insert_t *)malloc(sizeof(adb_insert_t));
|
map01bf@621
|
280 ins->features = features;
|
map01bf@621
|
281 ins->power = power;
|
map01bf@621
|
282 ins->key = key;
|
map01bf@621
|
283 ins->times = times;
|
map01bf@622
|
284 //printf("features::%s\npower::%s\nkey::%s\ntimes::%s\n", ins->features, ins->power, ins->key, ins->times);
|
map01bf@621
|
285 ok = audiodb_insert(current_db, ins);
|
map01bf@622
|
286 return PyBool_FromLong(ok-1);
|
map01bf@621
|
287
|
map01bf@621
|
288 }
|
map01bf@621
|
289
|
mas01mc@744
|
290 /* liszt - list strings, sizes, and time-points of all database entries
|
mas01mc@744
|
291 *
|
mas01mc@744
|
292 */
|
mas01mc@744
|
293 PyObject* _pyadb_liszt(PyObject *self, PyObject *args)
|
mas01mc@744
|
294 {
|
mas01mc@744
|
295 adb_t *current_db;
|
mas01mc@744
|
296 int ok,i;
|
mas01mc@744
|
297 PyObject * incoming = NULL;
|
mas01mc@744
|
298 PyObject * outgoing = NULL;
|
mas01mc@744
|
299 PyObject * newBits = NULL;
|
mas01mc@744
|
300
|
mas01mc@744
|
301 ok = PyArg_ParseTuple(args, "O", &incoming);
|
mas01mc@744
|
302
|
mas01mc@744
|
303 if (!ok) return 0;
|
mas01mc@744
|
304 current_db = (adb_t *)PyCObject_AsVoidPtr(incoming);
|
mas01mc@744
|
305
|
mas01mc@744
|
306 adb_liszt_results_t *liszt = audiodb_liszt(current_db);
|
mas01mc@744
|
307
|
mas01mc@744
|
308 outgoing = PyList_New((Py_ssize_t)0);
|
mas01mc@744
|
309 for (i=0 ; i<liszt->nresults ; i++){
|
mas01mc@744
|
310 newBits = Py_BuildValue("sI",liszt->entries[i].key,liszt->entries[i].nvectors);
|
mas01mc@744
|
311 if (PyList_Append(outgoing, newBits)){
|
mas01mc@744
|
312 //error msg here
|
mas01mc@744
|
313 Py_XDECREF(newBits);
|
mas01mc@744
|
314 return NULL;
|
mas01mc@744
|
315 }
|
mas01mc@744
|
316 Py_DECREF(newBits);
|
mas01mc@744
|
317 }
|
mas01mc@744
|
318 audiodb_liszt_free_results(current_db, liszt);
|
mas01mc@744
|
319 return outgoing;
|
mas01mc@744
|
320 }
|
mas01mc@744
|
321
|
map01bf@622
|
322 /* base query. The nomenclature here is about a far away as pythonic as is possible.
|
map01bf@622
|
323 * This should be taken care of via the higher level python structure
|
map01bf@622
|
324 * returns a dict that should be result ordered and key = result key
|
map01bf@622
|
325 * and value is a list of tuples one per result associated with that key, of the form:
|
map01bf@622
|
326 * (dist, qpos, ipos)
|
map01bf@622
|
327 * Note as well that this is by no means the most efficient way to cast from C, simply the most direct
|
map01bf@622
|
328 * and what it lacks in effeciency it gains in python side access. It remains to be seen if this is
|
map01bf@622
|
329 * a sensible trade.
|
map01bf@622
|
330 * api call:
|
map01bf@622
|
331 * adb_query_results_t *audiodb_query_spec(adb_t *, const adb_query_spec_t *);
|
map01bf@622
|
332 ***/
|
map01bf@622
|
333 PyObject * _pyadb_queryFromKey(PyObject *self, PyObject *args, PyObject *keywds)
|
map01bf@622
|
334 {
|
mas01cr@671
|
335 adb_t *current_db;
|
map01bf@622
|
336 adb_query_spec_t *spec;
|
map01bf@622
|
337 adb_query_results_t *result;
|
map01bf@622
|
338 int ok, exhaustive, falsePositives;
|
map01bf@622
|
339 uint32_t i;
|
map01bf@622
|
340 const char *key;
|
map01bf@622
|
341 const char *accuMode = "db";
|
map01bf@622
|
342 const char *distMode = "dot";
|
map01bf@624
|
343 const char *resFmt = "dict";
|
map01bf@622
|
344 uint32_t hop = 0;
|
map01bf@622
|
345 double radius = 0;
|
map01bf@622
|
346 double absThres = 0;
|
map01bf@622
|
347 double relThres = 0;
|
map01bf@622
|
348 double durRatio = 0;
|
map01bf@622
|
349 PyObject *includeKeys = NULL;
|
map01bf@622
|
350 PyObject *excludeKeys = NULL;
|
map01bf@622
|
351 PyObject *incoming = 0;
|
map01bf@622
|
352 PyObject *outgoing = NULL;
|
map01bf@622
|
353 PyObject *thisKey = NULL;
|
map01bf@622
|
354 PyObject *currentValue = 0;
|
map01bf@622
|
355 PyObject *newBits = 0;
|
map01bf@622
|
356 static char *kwlist[] = { "db", "key",
|
map01bf@622
|
357 "seqLength",
|
map01bf@622
|
358 "seqStart",
|
map01bf@622
|
359 "exhaustive",
|
map01bf@622
|
360 "falsePositives",
|
map01bf@622
|
361 "accumulation",
|
map01bf@622
|
362 "distance",
|
map01bf@622
|
363 "npoints",//nearest neighbor points per track
|
map01bf@624
|
364 "ntracks",
|
map01bf@622
|
365 "includeKeys",
|
map01bf@622
|
366 "excludeKeys",
|
map01bf@622
|
367 "radius",
|
map01bf@622
|
368 "absThres",
|
map01bf@622
|
369 "relThres",
|
map01bf@622
|
370 "durRatio",
|
map01bf@624
|
371 "hopSize",
|
map01bf@718
|
372 "resFmt",
|
map01bf@718
|
373 NULL
|
map01bf@622
|
374 };
|
map01bf@622
|
375 spec = (adb_query_spec_t *)malloc(sizeof(adb_query_spec_t));
|
map01bf@622
|
376 spec->qid.datum = (adb_datum_t *)malloc(sizeof(adb_datum_t));
|
map01bf@622
|
377 result = (adb_query_results_t *)malloc(sizeof(adb_query_results_t));
|
map01bf@622
|
378
|
map01bf@622
|
379 spec->qid.sequence_length = 16;
|
map01bf@622
|
380 spec->qid.sequence_start = 0;
|
map01bf@622
|
381 spec->qid.flags = 0;
|
map01bf@622
|
382 spec->params.npoints = 1;
|
map01bf@622
|
383 spec->params.ntracks = 100;//number of results returned in db mode
|
map01bf@622
|
384 spec->refine.flags = 0;
|
map01bf@622
|
385
|
map01bf@624
|
386 ok = PyArg_ParseTupleAndKeywords(args, keywds, "Os|iiiissIIOOddddIs", kwlist,
|
map01bf@622
|
387 &incoming, &key,
|
map01bf@622
|
388 &spec->qid.sequence_length,
|
map01bf@622
|
389 &spec->qid.sequence_start,
|
map01bf@622
|
390 &exhaustive, &falsePositives,
|
map01bf@622
|
391 &accuMode,&distMode,
|
map01bf@622
|
392 &spec->params.npoints,
|
map01bf@622
|
393 &spec->params.ntracks,
|
map01bf@622
|
394 &includeKeys, &excludeKeys,
|
map01bf@624
|
395 &radius, &absThres, &relThres, &durRatio, &hop,
|
map01bf@624
|
396 &resFmt
|
map01bf@622
|
397 );
|
map01bf@622
|
398
|
map01bf@622
|
399 if (!ok) {return NULL;}
|
mas01cr@671
|
400 current_db = (adb_t *)PyCObject_AsVoidPtr(incoming);
|
map01bf@622
|
401
|
map01bf@622
|
402 if (exhaustive){
|
map01bf@622
|
403 spec->qid.flags = spec->qid.flags | ADB_QID_FLAG_EXHAUSTIVE;
|
map01bf@622
|
404 }
|
map01bf@622
|
405 if (falsePositives){
|
map01bf@622
|
406 spec->qid.flags = spec->qid.flags | ADB_QID_FLAG_ALLOW_FALSE_POSITIVES;
|
map01bf@622
|
407 }
|
map01bf@622
|
408
|
map01bf@622
|
409 //set up spec->params
|
mas01mc@750
|
410 if (strcmp(accuMode,"db")==0){
|
map01bf@622
|
411 spec->params.accumulation = ADB_ACCUMULATION_DB;
|
mas01mc@750
|
412 } else if (strcmp(accuMode,"track")==0){
|
map01bf@622
|
413 spec->params.accumulation = ADB_ACCUMULATION_PER_TRACK;
|
mas01mc@750
|
414 } else if (strcmp(accuMode,"one2one")==0){
|
map01bf@622
|
415 spec->params.accumulation = ADB_ACCUMULATION_ONE_TO_ONE;
|
map01bf@622
|
416 } else{
|
map01bf@624
|
417 PyErr_SetString(PyExc_ValueError,
|
map01bf@624
|
418 "Poorly specified distance mode. distance must either be \'db\', \'track\' or \'one2one\'.\n");
|
map01bf@622
|
419 return NULL;
|
map01bf@622
|
420 }
|
mas01mc@750
|
421 if (strcmp(distMode, "dot")==0){
|
mas01mc@768
|
422 spec->params.distance = ADB_DISTANCE_DOT_PRODUCT;
|
mas01mc@750
|
423 }else if (strcmp(distMode, "eucNorm")==0){
|
mas01mc@768
|
424 spec->params.distance = ADB_DISTANCE_EUCLIDEAN_NORMED;
|
mas01mc@750
|
425 }else if (strcmp(distMode, "euclidean")==0){
|
mas01mc@768
|
426 spec->params.distance = ADB_DISTANCE_EUCLIDEAN;
|
mas01mc@768
|
427 }else if (strcmp(distMode, "kullback")==0){
|
mas01mc@768
|
428 spec->params.distance = ADB_DISTANCE_KULLBACK_LEIBLER_DIVERGENCE;
|
map01bf@622
|
429 }else{
|
mas01mc@768
|
430 PyErr_SetString(PyExc_ValueError,
|
mas01mc@768
|
431 "Poorly specified distance mode. distance must either be \'dot\', \'eucNorm\' ,\'euclidean\' or \'kullback\'.\n");
|
mas01mc@768
|
432 return NULL;
|
map01bf@622
|
433 }
|
map01bf@622
|
434
|
map01bf@622
|
435 //set up spec->refine
|
map01bf@622
|
436 //include/exclude keys
|
map01bf@622
|
437 if (includeKeys){
|
map01bf@622
|
438 if (!PyList_Check(includeKeys)){
|
map01bf@624
|
439 PyErr_SetString(PyExc_TypeError, "Include keys must be specified as a list of strings.\n");
|
map01bf@622
|
440 return NULL;
|
map01bf@622
|
441 }
|
map01bf@622
|
442 spec->refine.flags = spec->refine.flags | ADB_REFINE_INCLUDE_KEYLIST;
|
map01bf@622
|
443 spec->refine.include.nkeys = (uint32_t)PyList_Size(includeKeys);
|
map01bf@622
|
444 spec->refine.include.keys = (const char **)calloc(sizeof(const char *), spec->refine.include.nkeys);
|
map01bf@622
|
445 for (i=0;i<spec->refine.include.nkeys;i++){
|
map01bf@622
|
446 if (PyString_Check(PyList_GetItem(includeKeys, (Py_ssize_t)i))){
|
map01bf@622
|
447 spec->refine.include.keys[i] = PyString_AsString(PyList_GetItem(includeKeys, (Py_ssize_t)i));
|
map01bf@622
|
448 }else{
|
map01bf@624
|
449 PyErr_SetString(PyExc_TypeError, "Include keys must each be specified as a string.\nFound one that was not.\n");
|
map01bf@622
|
450 return NULL;
|
map01bf@622
|
451 }
|
map01bf@622
|
452 }
|
map01bf@622
|
453 }
|
map01bf@622
|
454 if (excludeKeys){
|
map01bf@622
|
455 if (!PyList_Check(excludeKeys)){
|
map01bf@624
|
456 PyErr_SetString(PyExc_TypeError, "Exclude keys must be specified as a list of strings.\n");
|
map01bf@622
|
457 return NULL;
|
map01bf@622
|
458 }
|
map01bf@622
|
459 spec->refine.flags = spec->refine.flags | ADB_REFINE_EXCLUDE_KEYLIST;
|
map01bf@622
|
460 spec->refine.exclude.nkeys = (uint32_t)PyList_Size(excludeKeys);
|
map01bf@622
|
461 spec->refine.exclude.keys = (const char **)calloc(sizeof(const char *), spec->refine.exclude.nkeys);
|
map01bf@622
|
462 for (i=0;i<spec->refine.exclude.nkeys;i++){
|
map01bf@622
|
463 if (PyString_Check(PyList_GetItem(excludeKeys, (Py_ssize_t)i))){
|
map01bf@622
|
464 spec->refine.exclude.keys[i] = PyString_AsString(PyList_GetItem(excludeKeys, (Py_ssize_t)i));
|
map01bf@622
|
465 }else{
|
map01bf@624
|
466 PyErr_SetString(PyExc_TypeError, "Exclude keys must each be specified as a string.\nFound one that was not.\n");
|
map01bf@622
|
467 return NULL;
|
map01bf@622
|
468 }
|
map01bf@622
|
469 }
|
map01bf@622
|
470 }
|
map01bf@622
|
471 //the rest of spec->refine
|
map01bf@622
|
472 if (radius){
|
map01bf@622
|
473 spec->refine.flags = spec->refine.flags | ADB_REFINE_RADIUS;
|
map01bf@622
|
474 spec->refine.radius = radius;
|
map01bf@622
|
475 }
|
map01bf@622
|
476 if (absThres){
|
map01bf@622
|
477 spec->refine.flags = spec->refine.flags | ADB_REFINE_ABSOLUTE_THRESHOLD;
|
map01bf@622
|
478 spec->refine.absolute_threshold = absThres;
|
map01bf@622
|
479 }
|
map01bf@622
|
480 if (relThres){
|
map01bf@622
|
481 spec->refine.flags = spec->refine.flags | ADB_REFINE_RELATIVE_THRESHOLD;
|
map01bf@622
|
482 spec->refine.relative_threshold = relThres;
|
map01bf@622
|
483 }
|
map01bf@622
|
484 if (durRatio){
|
map01bf@622
|
485 spec->refine.flags = spec->refine.flags | ADB_REFINE_DURATION_RATIO;
|
map01bf@622
|
486 spec->refine.duration_ratio = durRatio;
|
map01bf@622
|
487 }
|
map01bf@622
|
488 if (hop){
|
map01bf@622
|
489 spec->refine.flags = spec->refine.flags | ADB_REFINE_HOP_SIZE;
|
mas01cr@679
|
490 /* not ideal but a temporary bandage fix */
|
mas01cr@679
|
491 spec->refine.qhopsize = hop;
|
mas01cr@679
|
492 spec->refine.ihopsize = hop;
|
map01bf@622
|
493 }
|
map01bf@622
|
494 //setup the datum
|
map01bf@622
|
495 spec->qid.datum->data = NULL;
|
map01bf@622
|
496 spec->qid.datum->power = NULL;
|
map01bf@622
|
497 spec->qid.datum->times = NULL;
|
map01bf@622
|
498 //grab the datum from the key
|
map01bf@622
|
499 ok = audiodb_retrieve_datum(current_db, key, spec->qid.datum);
|
map01bf@622
|
500 if (ok != 0){
|
map01bf@622
|
501 PyErr_SetString(PyExc_RuntimeError, "Encountered an error while trying to retrieve the data associated with the passed key.\n");
|
map01bf@622
|
502 return NULL;
|
map01bf@622
|
503 }
|
map01bf@622
|
504 result = audiodb_query_spec(current_db, spec);
|
map01bf@622
|
505 if (result == NULL){
|
map01bf@718
|
506 PyErr_SetString(PyExc_RuntimeError, "Encountered an error while running the actual query, or there was nothing returned.\n");
|
map01bf@622
|
507 return NULL;
|
map01bf@622
|
508 }
|
map01bf@624
|
509 if(strcmp(resFmt, "dict")==0){
|
map01bf@624
|
510 outgoing = PyDict_New();
|
map01bf@624
|
511 for (i=0;i<result->nresults;i++){
|
mas01cr@672
|
512 thisKey = PyString_FromString(result->results[i].ikey);
|
map01bf@624
|
513 if (!PyDict_Contains(outgoing, thisKey)){
|
map01bf@624
|
514 newBits = Py_BuildValue("[(dII)]",
|
map01bf@624
|
515 result->results[i].dist,
|
map01bf@624
|
516 result->results[i].qpos,
|
map01bf@624
|
517 result->results[i].ipos);
|
map01bf@624
|
518 if (PyDict_SetItem(outgoing, thisKey,newBits)){
|
mas01cr@672
|
519 printf("key : %s\ndist : %f\nqpos : %i\nipos : %i\n", result->results[i].ikey, result->results[i].dist, result->results[i].qpos, result->results[i].ipos);
|
map01bf@624
|
520 PyErr_SetString(PyExc_AttributeError, "Error adding a tuple to the result dict\n");
|
map01bf@624
|
521 Py_XDECREF(newBits);
|
map01bf@624
|
522 return NULL;
|
map01bf@624
|
523 }
|
map01bf@624
|
524 Py_DECREF(newBits);
|
map01bf@624
|
525 }else {
|
map01bf@624
|
526 //the key already has a value, so we need to fetch the value, confirm it's a list and append another tuple to it.
|
map01bf@624
|
527 currentValue = PyDict_GetItem(outgoing, thisKey);
|
map01bf@624
|
528 if (!PyList_Check(currentValue)){
|
map01bf@624
|
529 PyErr_SetString(PyExc_TypeError, "The result dictionary appears to be malformed.\n");
|
map01bf@624
|
530 return NULL;
|
map01bf@624
|
531 }
|
map01bf@624
|
532 newBits = Py_BuildValue("dII",result->results[i].dist,
|
map01bf@624
|
533 result->results[i].qpos,
|
map01bf@624
|
534 result->results[i].ipos);
|
map01bf@624
|
535 if (PyList_Append(currentValue, newBits)){
|
map01bf@624
|
536 //error msg here
|
map01bf@624
|
537 Py_XDECREF(newBits);
|
map01bf@624
|
538 return NULL;
|
map01bf@624
|
539 }
|
map01bf@624
|
540 if (PyDict_SetItem(outgoing, thisKey, newBits)){
|
map01bf@624
|
541 PyErr_SetString(PyExc_AttributeError, "Error adding a tuple to the result dict\n");
|
map01bf@624
|
542 Py_XDECREF(newBits);
|
map01bf@624
|
543 return NULL;
|
map01bf@624
|
544 }
|
map01bf@624
|
545 Py_DECREF(newBits);
|
map01bf@624
|
546
|
map01bf@624
|
547 }
|
map01bf@624
|
548 }
|
map01bf@624
|
549 }else if(strcmp(resFmt, "list")==0){
|
map01bf@624
|
550 outgoing = PyList_New((Py_ssize_t)0);
|
map01bf@624
|
551 for (i=0;i<result->nresults;i++){
|
mas01cr@672
|
552 newBits = Py_BuildValue("sdII",result->results[i].ikey,
|
map01bf@622
|
553 result->results[i].dist,
|
map01bf@622
|
554 result->results[i].qpos,
|
map01bf@622
|
555 result->results[i].ipos);
|
map01bf@624
|
556 if (PyList_Append(outgoing, newBits)){
|
map01bf@624
|
557 //error msg here
|
map01bf@622
|
558 Py_XDECREF(newBits);
|
map01bf@622
|
559 return NULL;
|
map01bf@622
|
560 }
|
map01bf@622
|
561 Py_DECREF(newBits);
|
map01bf@624
|
562 }
|
map01bf@624
|
563 if(PyList_Reverse(outgoing)){//need to do this as things come off the accumulator backward.
|
map01bf@720
|
564 PyErr_SetString(PyExc_RuntimeError,
|
map01bf@720
|
565 "the reverse failed, hopefully a sensable error will follow.\nIf not, fix it.\n");
|
map01bf@624
|
566 return NULL;
|
map01bf@622
|
567 }
|
map01bf@624
|
568 }else{
|
map01bf@624
|
569 PyErr_SetString(PyExc_ValueError,
|
map01bf@624
|
570 "Poorly specified result mode. Result must be either \'dist\' or \'list\'.\n");
|
map01bf@624
|
571 return NULL;
|
map01bf@622
|
572 }
|
map01bf@628
|
573 if (audiodb_query_free_results(current_db, spec, result)){
|
map01bf@622
|
574 printf("bit of trouble freeing the result and spec...\ncheck for leaks.");
|
map01bf@622
|
575 }
|
map01bf@622
|
576
|
map01bf@622
|
577 return outgoing;
|
map01bf@622
|
578
|
map01bf@622
|
579
|
map01bf@622
|
580
|
map01bf@622
|
581 }
|
map01bf@622
|
582
|
mas01mc@750
|
583 /* Data query.
|
mas01mc@750
|
584 * Returns a dict that is result ordered and key = result key
|
mas01mc@750
|
585 * value is a list of tuples one per result associated with that key, of the form:
|
mas01mc@750
|
586 * (dist, qpos, ipos)
|
mas01mc@750
|
587 * api call:
|
mas01mc@750
|
588 * adb_query_results_t *audiodb_query_spec(adb_t *, const adb_query_spec_t *);
|
mas01mc@750
|
589 ***/
|
mas01mc@750
|
590 PyObject * _pyadb_queryFromData(PyObject *self, PyObject *args, PyObject *keywds)
|
mas01mc@750
|
591 {
|
mas01mc@750
|
592 adb_t *current_db;
|
mas01mc@750
|
593 adb_query_spec_t *spec;
|
mas01mc@750
|
594 adb_query_results_t *result;
|
mas01mc@750
|
595 int ok, exhaustive, falsePositives;
|
mas01mc@750
|
596 uint32_t i;
|
mas01mc@750
|
597 const char *accuMode = "db";
|
mas01mc@750
|
598 const char *distMode = "dot";
|
mas01mc@750
|
599 const char *resFmt = "dict";
|
mas01mc@750
|
600 uint32_t hop = 0;
|
mas01mc@750
|
601 double radius = 0;
|
mas01mc@750
|
602 double absThres = 0;
|
mas01mc@750
|
603 double relThres = 0;
|
mas01mc@750
|
604 double durRatio = 0;
|
mas01mc@750
|
605 PyObject *includeKeys = NULL;
|
mas01mc@750
|
606 PyObject *excludeKeys = NULL;
|
mas01mc@750
|
607 PyObject *incoming = NULL;
|
mas01mc@750
|
608 PyObject *outgoing = NULL;
|
mas01mc@750
|
609 PyObject *thisKey = NULL;
|
mas01mc@750
|
610 PyObject *currentValue = NULL;
|
mas01mc@750
|
611 PyObject *newBits = NULL;
|
mas01mc@750
|
612 unsigned int nDims = 0;
|
mas01mc@750
|
613 unsigned int nVect = 0;
|
mas01mc@750
|
614 PyArrayObject *features = NULL;
|
mas01mc@750
|
615 PyArrayObject *power = NULL;
|
mas01mc@750
|
616 PyArrayObject *times = NULL;
|
mas01mc@750
|
617 adb_status_t *status;
|
mas01mc@750
|
618
|
mas01mc@750
|
619 static char *kwlist[] = { "db", "features",
|
mas01mc@750
|
620 "seqLength",
|
mas01mc@750
|
621 "seqStart",
|
mas01mc@750
|
622 "exhaustive",
|
mas01mc@750
|
623 "falsePositives",
|
mas01mc@750
|
624 "accumulation",
|
mas01mc@750
|
625 "distance",
|
mas01mc@750
|
626 "npoints",//nearest neighbor points per track
|
mas01mc@750
|
627 "ntracks",
|
mas01mc@750
|
628 "includeKeys",
|
mas01mc@750
|
629 "excludeKeys",
|
mas01mc@750
|
630 "radius",
|
mas01mc@750
|
631 "absThres",
|
mas01mc@750
|
632 "relThres",
|
mas01mc@750
|
633 "durRatio",
|
mas01mc@750
|
634 "hopSize",
|
mas01mc@750
|
635 "resFmt",
|
mas01mc@750
|
636 "power",
|
mas01mc@750
|
637 "times",
|
mas01mc@750
|
638 NULL
|
mas01mc@750
|
639 };
|
mas01mc@750
|
640
|
mas01mc@750
|
641 spec = (adb_query_spec_t *)malloc(sizeof(adb_query_spec_t));
|
mas01mc@750
|
642 spec->qid.datum = (adb_datum_t *)malloc(sizeof(adb_datum_t));
|
mas01mc@750
|
643 result = (adb_query_results_t *)malloc(sizeof(adb_query_results_t));
|
mas01mc@750
|
644
|
mas01mc@750
|
645 spec->qid.sequence_length = 16;
|
mas01mc@750
|
646 spec->qid.sequence_start = 0;
|
mas01mc@750
|
647 spec->qid.flags = 0;
|
mas01mc@750
|
648 spec->params.npoints = 1;
|
mas01mc@750
|
649 spec->params.ntracks = 100;//number of results returned in db mode
|
mas01mc@750
|
650 spec->refine.flags = 0;
|
mas01mc@750
|
651
|
mas01mc@750
|
652 ok = PyArg_ParseTupleAndKeywords(args, keywds, "OO!|iiiissIIOOddddIsO!O!", kwlist,
|
mas01mc@750
|
653 &incoming, &PyArray_Type, &features,
|
mas01mc@750
|
654 &spec->qid.sequence_length,
|
mas01mc@750
|
655 &spec->qid.sequence_start,
|
mas01mc@750
|
656 &exhaustive, &falsePositives,
|
mas01mc@750
|
657 &accuMode,&distMode,
|
mas01mc@750
|
658 &spec->params.npoints,
|
mas01mc@750
|
659 &spec->params.ntracks,
|
mas01mc@750
|
660 &includeKeys, &excludeKeys,
|
mas01mc@750
|
661 &radius, &absThres, &relThres, &durRatio, &hop,
|
mas01mc@750
|
662 &resFmt,
|
mas01mc@750
|
663 &PyArray_Type, &power, &PyArray_Type, ×
|
mas01mc@750
|
664 );
|
mas01mc@750
|
665
|
mas01mc@750
|
666 if (!ok) {return NULL;}
|
mas01mc@750
|
667 current_db = (adb_t *)PyCObject_AsVoidPtr(incoming);
|
mas01mc@750
|
668
|
mas01mc@750
|
669 if (!features){ /* Sanity Check */
|
mas01mc@750
|
670 PyErr_SetString(PyExc_ValueError,
|
mas01mc@750
|
671 "queryFromData: function requires feature data as numpy ndarray. PythonC required keyword check failed.\n");
|
mas01mc@750
|
672 return NULL;
|
mas01mc@750
|
673 }
|
mas01mc@750
|
674
|
mas01mc@750
|
675 /* Check the dimensionality of passed data agrees with the passed database */
|
mas01mc@750
|
676 if(PyArray_NDIM(features)!=2){
|
mas01mc@750
|
677 PyErr_SetString(PyExc_ValueError,
|
mas01mc@750
|
678 "queryFromData: passed features have incorrect shape, should be (nVecs, nDims).\n");
|
mas01mc@750
|
679 return NULL;
|
mas01mc@750
|
680 }
|
mas01mc@750
|
681
|
mas01mc@750
|
682
|
mas01mc@750
|
683 if(power && PyArray_NDIM(power)!=1){
|
mas01mc@750
|
684 PyErr_SetString(PyExc_ValueError,
|
mas01mc@750
|
685 "queryFromData: passed power have incorrect shape, should be (nVecs,).\n");
|
mas01mc@750
|
686 return NULL;
|
mas01mc@750
|
687 }
|
mas01mc@750
|
688
|
mas01mc@750
|
689 if(times && PyArray_NDIM(times)!=1){
|
mas01mc@750
|
690 PyErr_SetString(PyExc_ValueError,
|
mas01mc@750
|
691 "queryFromData: passed times have incorrect shape, should be (nVecs,).\n");
|
mas01mc@750
|
692 return NULL;
|
mas01mc@750
|
693 }
|
mas01mc@750
|
694
|
mas01mc@750
|
695 status = (adb_status_t*) malloc(sizeof(adb_status_t));
|
mas01mc@750
|
696 int errtest = audiodb_status(current_db, status);
|
mas01mc@750
|
697 if(errtest){
|
mas01mc@750
|
698 PyErr_SetString(PyExc_TypeError, "queryFromData failed: could not get status of passed ADB database");
|
mas01mc@750
|
699 free(status);
|
mas01mc@750
|
700 return NULL;
|
mas01mc@750
|
701 }
|
mas01mc@750
|
702
|
mas01mc@750
|
703 if(!PyArray_DIMS(features)[1]==status->dim){
|
mas01mc@750
|
704 PyErr_SetString(PyExc_ValueError,
|
mas01mc@750
|
705 "queryFromData: passed features have incorrect dimensionality.\n");
|
mas01mc@750
|
706 free(status);
|
mas01mc@750
|
707 return NULL;
|
mas01mc@750
|
708 }
|
mas01mc@750
|
709
|
mas01mc@750
|
710 if(power && PyArray_DIMS(power)[0] != PyArray_DIMS(features)[0]){
|
mas01mc@750
|
711 PyErr_SetString(PyExc_ValueError,
|
mas01mc@750
|
712 "queryFromData: passed power and features have incompatible nVecs dimension.\n");
|
mas01mc@750
|
713 free(status);
|
mas01mc@750
|
714 return NULL;
|
mas01mc@750
|
715 }
|
mas01mc@750
|
716
|
mas01mc@750
|
717 if(times && PyArray_DIMS(times)[0] != PyArray_DIMS(features)[0]){
|
mas01mc@750
|
718 PyErr_SetString(PyExc_ValueError,
|
mas01mc@750
|
719 "queryFromData: passed times and features have incompatible nVecs dimension.\n");
|
mas01mc@750
|
720 free(status);
|
mas01mc@750
|
721 return NULL;
|
mas01mc@750
|
722 }
|
mas01mc@750
|
723
|
mas01mc@750
|
724 free(status);
|
mas01mc@750
|
725
|
mas01mc@750
|
726 if (exhaustive){
|
mas01mc@750
|
727 spec->qid.flags = spec->qid.flags | ADB_QID_FLAG_EXHAUSTIVE;
|
mas01mc@750
|
728 }
|
mas01mc@750
|
729 if (falsePositives){
|
mas01mc@750
|
730 spec->qid.flags = spec->qid.flags | ADB_QID_FLAG_ALLOW_FALSE_POSITIVES;
|
mas01mc@750
|
731 }
|
mas01mc@750
|
732
|
mas01mc@750
|
733 //set up spec->params
|
mas01mc@750
|
734 if (strcmp(accuMode,"db")==0){
|
mas01mc@750
|
735 spec->params.accumulation = ADB_ACCUMULATION_DB;
|
mas01mc@750
|
736 } else if (strcmp(accuMode,"track")==0){
|
mas01mc@750
|
737 spec->params.accumulation = ADB_ACCUMULATION_PER_TRACK;
|
mas01mc@750
|
738 } else if (strcmp(accuMode,"one2one")==0){
|
mas01mc@750
|
739 spec->params.accumulation = ADB_ACCUMULATION_ONE_TO_ONE;
|
mas01mc@750
|
740 } else{
|
mas01mc@750
|
741 PyErr_SetString(PyExc_ValueError,
|
mas01mc@750
|
742 "Poorly specified distance mode. distance must either be \'db\', \'track\' or \'one2one\'.\n");
|
mas01mc@750
|
743 return NULL;
|
mas01mc@750
|
744 }
|
mas01mc@750
|
745 if (strcmp(distMode, "dot")==0){
|
mas01mc@750
|
746 spec->params.distance = ADB_DISTANCE_DOT_PRODUCT;
|
mas01mc@750
|
747 }else if (strcmp(distMode, "eucNorm")==0){
|
mas01mc@750
|
748 spec->params.distance = ADB_DISTANCE_EUCLIDEAN_NORMED;
|
mas01mc@750
|
749 }else if (strcmp(distMode, "euclidean")==0){
|
mas01mc@750
|
750 spec->params.distance = ADB_DISTANCE_EUCLIDEAN;
|
mas01mc@768
|
751 }else if (strcmp(distMode, "kullback")==0){
|
mas01mc@768
|
752 spec->params.distance = ADB_DISTANCE_KULLBACK_LEIBLER_DIVERGENCE;
|
mas01mc@750
|
753 }else{
|
mas01mc@750
|
754 PyErr_SetString(PyExc_ValueError,
|
mas01mc@768
|
755 "Poorly specified distance mode. distance must either be \'dot\', \'eucNorm\' ,\'euclidean\' or \'kullback\'.\n");
|
mas01mc@750
|
756 return NULL;
|
mas01mc@750
|
757 }
|
mas01mc@750
|
758
|
mas01mc@750
|
759 //set up spec->refine
|
mas01mc@750
|
760 //include/exclude keys
|
mas01mc@750
|
761 if (includeKeys){
|
mas01mc@750
|
762 if (!PyList_Check(includeKeys)){
|
mas01mc@750
|
763 PyErr_SetString(PyExc_TypeError, "Include keys must be specified as a list of strings.\n");
|
mas01mc@750
|
764 return NULL;
|
mas01mc@750
|
765 }
|
mas01mc@750
|
766 spec->refine.flags = spec->refine.flags | ADB_REFINE_INCLUDE_KEYLIST;
|
mas01mc@750
|
767 spec->refine.include.nkeys = (uint32_t)PyList_Size(includeKeys);
|
mas01mc@750
|
768 spec->refine.include.keys = (const char **)calloc(sizeof(const char *), spec->refine.include.nkeys);
|
mas01mc@750
|
769 for (i=0;i<spec->refine.include.nkeys;i++){
|
mas01mc@750
|
770 if (PyString_Check(PyList_GetItem(includeKeys, (Py_ssize_t)i))){
|
mas01mc@750
|
771 spec->refine.include.keys[i] = PyString_AsString(PyList_GetItem(includeKeys, (Py_ssize_t)i));
|
mas01mc@750
|
772 }else{
|
mas01mc@750
|
773 PyErr_SetString(PyExc_TypeError, "Include keys must each be specified as a string.\nFound one that was not.\n");
|
mas01mc@750
|
774 return NULL;
|
mas01mc@750
|
775 }
|
mas01mc@750
|
776 }
|
mas01mc@750
|
777 }
|
mas01mc@750
|
778 if (excludeKeys){
|
mas01mc@750
|
779 if (!PyList_Check(excludeKeys)){
|
mas01mc@750
|
780 PyErr_SetString(PyExc_TypeError, "Exclude keys must be specified as a list of strings.\n");
|
mas01mc@750
|
781 return NULL;
|
mas01mc@750
|
782 }
|
mas01mc@750
|
783 spec->refine.flags = spec->refine.flags | ADB_REFINE_EXCLUDE_KEYLIST;
|
mas01mc@750
|
784 spec->refine.exclude.nkeys = (uint32_t)PyList_Size(excludeKeys);
|
mas01mc@750
|
785 spec->refine.exclude.keys = (const char **)calloc(sizeof(const char *), spec->refine.exclude.nkeys);
|
mas01mc@750
|
786 for (i=0;i<spec->refine.exclude.nkeys;i++){
|
mas01mc@750
|
787 if (PyString_Check(PyList_GetItem(excludeKeys, (Py_ssize_t)i))){
|
mas01mc@750
|
788 spec->refine.exclude.keys[i] = PyString_AsString(PyList_GetItem(excludeKeys, (Py_ssize_t)i));
|
mas01mc@750
|
789 }else{
|
mas01mc@750
|
790 PyErr_SetString(PyExc_TypeError, "Exclude keys must each be specified as a string.\nFound one that was not.\n");
|
mas01mc@750
|
791 return NULL;
|
mas01mc@750
|
792 }
|
mas01mc@750
|
793 }
|
mas01mc@750
|
794 }
|
mas01mc@750
|
795 //the rest of spec->refine
|
mas01mc@750
|
796 if (radius){
|
mas01mc@750
|
797 spec->refine.flags = spec->refine.flags | ADB_REFINE_RADIUS;
|
mas01mc@750
|
798 spec->refine.radius = radius;
|
mas01mc@750
|
799 }
|
mas01mc@750
|
800 if (absThres){
|
mas01mc@750
|
801 spec->refine.flags = spec->refine.flags | ADB_REFINE_ABSOLUTE_THRESHOLD;
|
mas01mc@750
|
802 spec->refine.absolute_threshold = absThres;
|
mas01mc@750
|
803 }
|
mas01mc@750
|
804 if (relThres){
|
mas01mc@750
|
805 spec->refine.flags = spec->refine.flags | ADB_REFINE_RELATIVE_THRESHOLD;
|
mas01mc@750
|
806 spec->refine.relative_threshold = relThres;
|
mas01mc@750
|
807 }
|
mas01mc@750
|
808 if (durRatio){
|
mas01mc@750
|
809 spec->refine.flags = spec->refine.flags | ADB_REFINE_DURATION_RATIO;
|
mas01mc@750
|
810 spec->refine.duration_ratio = durRatio;
|
mas01mc@750
|
811 }
|
mas01mc@750
|
812 if (hop){
|
mas01mc@750
|
813 spec->refine.flags = spec->refine.flags | ADB_REFINE_HOP_SIZE;
|
mas01mc@750
|
814 /* not ideal but a temporary bandage fix */
|
mas01mc@750
|
815 spec->refine.qhopsize = hop;
|
mas01mc@750
|
816 spec->refine.ihopsize = hop;
|
mas01mc@750
|
817 }
|
mas01mc@750
|
818
|
mas01mc@758
|
819 spec->qid.datum->data = (double*) features->data;
|
mas01mc@750
|
820
|
mas01mc@750
|
821 if (power){
|
mas01mc@758
|
822 spec->qid.datum->power = (double*) power->data;
|
mas01mc@750
|
823 }else{
|
mas01mc@750
|
824 spec->qid.datum->power=NULL;
|
mas01mc@750
|
825 }
|
mas01mc@750
|
826
|
mas01mc@750
|
827 if (times){
|
mas01mc@758
|
828 spec->qid.datum->times = (double*) times->data;
|
mas01mc@750
|
829 }else{
|
mas01mc@750
|
830 spec->qid.datum->times=NULL;
|
mas01mc@750
|
831 }
|
mas01mc@750
|
832
|
mas01mc@750
|
833 nVect = PyArray_DIMS(features)[0];
|
mas01mc@750
|
834 nDims = PyArray_DIMS(features)[1];
|
mas01mc@750
|
835 spec->qid.datum->nvectors = (uint32_t)nVect;
|
mas01mc@750
|
836 spec->qid.datum->dim = (uint32_t)nDims;
|
mas01mc@750
|
837
|
mas01mc@750
|
838 result = audiodb_query_spec(current_db, spec);
|
mas01mc@750
|
839
|
mas01mc@750
|
840 if (result == NULL){
|
mas01mc@750
|
841 PyErr_SetString(PyExc_RuntimeError, "Encountered an error while running the actual query, or there was nothing returned.\n");
|
mas01mc@750
|
842 return NULL;
|
mas01mc@750
|
843 }
|
mas01mc@750
|
844 if(strcmp(resFmt, "dict")==0){
|
mas01mc@750
|
845 outgoing = PyDict_New();
|
mas01mc@750
|
846 for (i=0;i<result->nresults;i++){
|
mas01mc@750
|
847 thisKey = PyString_FromString(result->results[i].ikey);
|
mas01mc@750
|
848 if (!PyDict_Contains(outgoing, thisKey)){
|
mas01mc@750
|
849 newBits = Py_BuildValue("[(dII)]",
|
mas01mc@750
|
850 result->results[i].dist,
|
mas01mc@750
|
851 result->results[i].qpos,
|
mas01mc@750
|
852 result->results[i].ipos);
|
mas01mc@750
|
853 if (PyDict_SetItem(outgoing, thisKey,newBits)){
|
mas01mc@750
|
854 printf("key : %s\ndist : %f\nqpos : %i\nipos : %i\n", result->results[i].ikey, result->results[i].dist, result->results[i].qpos, result->results[i].ipos);
|
mas01mc@750
|
855 PyErr_SetString(PyExc_AttributeError, "Error adding a tuple to the result dict\n");
|
mas01mc@750
|
856 Py_XDECREF(newBits);
|
mas01mc@750
|
857 return NULL;
|
mas01mc@750
|
858 }
|
mas01mc@750
|
859 Py_DECREF(newBits);
|
mas01mc@750
|
860 }else {
|
mas01mc@750
|
861 //the key already has a value, so we need to fetch the value, confirm it's a list and append another tuple to it.
|
mas01mc@750
|
862 currentValue = PyDict_GetItem(outgoing, thisKey);
|
mas01mc@750
|
863 if (!PyList_Check(currentValue)){
|
mas01mc@750
|
864 PyErr_SetString(PyExc_TypeError, "The result dictionary appears to be malformed.\n");
|
mas01mc@750
|
865 return NULL;
|
mas01mc@750
|
866 }
|
mas01mc@750
|
867 newBits = Py_BuildValue("dII",result->results[i].dist,
|
mas01mc@750
|
868 result->results[i].qpos,
|
mas01mc@750
|
869 result->results[i].ipos);
|
mas01mc@750
|
870 if (PyList_Append(currentValue, newBits)){
|
mas01mc@750
|
871 //error msg here
|
mas01mc@750
|
872 Py_XDECREF(newBits);
|
mas01mc@750
|
873 return NULL;
|
mas01mc@750
|
874 }
|
mas01mc@750
|
875 if (PyDict_SetItem(outgoing, thisKey, newBits)){
|
mas01mc@750
|
876 PyErr_SetString(PyExc_AttributeError, "Error adding a tuple to the result dict\n");
|
mas01mc@750
|
877 Py_XDECREF(newBits);
|
mas01mc@750
|
878 return NULL;
|
mas01mc@750
|
879 }
|
mas01mc@750
|
880 Py_DECREF(newBits);
|
mas01mc@750
|
881
|
mas01mc@750
|
882 }
|
mas01mc@750
|
883 }
|
mas01mc@750
|
884 }else if(strcmp(resFmt, "list")==0){
|
mas01mc@750
|
885 outgoing = PyList_New((Py_ssize_t)0);
|
mas01mc@750
|
886 for (i=0;i<result->nresults;i++){
|
mas01mc@750
|
887 newBits = Py_BuildValue("sdII",result->results[i].ikey,
|
mas01mc@750
|
888 result->results[i].dist,
|
mas01mc@750
|
889 result->results[i].qpos,
|
mas01mc@750
|
890 result->results[i].ipos);
|
mas01mc@750
|
891 if (PyList_Append(outgoing, newBits)){
|
mas01mc@750
|
892 //error msg here
|
mas01mc@750
|
893 Py_XDECREF(newBits);
|
mas01mc@750
|
894 return NULL;
|
mas01mc@750
|
895 }
|
mas01mc@750
|
896 Py_DECREF(newBits);
|
mas01mc@750
|
897 }
|
mas01mc@750
|
898 if(PyList_Reverse(outgoing)){//need to do this as things come off the accumulator backward.
|
mas01mc@750
|
899 PyErr_SetString(PyExc_RuntimeError,
|
mas01mc@750
|
900 "the reverse failed, hopefully a sensable error will follow.\nIf not, fix it.\n");
|
mas01mc@750
|
901 return NULL;
|
mas01mc@750
|
902 }
|
mas01mc@750
|
903 }else{
|
mas01mc@750
|
904 PyErr_SetString(PyExc_ValueError,
|
mas01mc@750
|
905 "Poorly specified result mode. Result must be either \'dist\' or \'list\'.\n");
|
mas01mc@750
|
906 return NULL;
|
mas01mc@750
|
907 }
|
mas01mc@750
|
908 if (audiodb_query_free_results(current_db, spec, result)){
|
mas01mc@750
|
909 printf("bit of trouble freeing the result and spec...\ncheck for leaks.");
|
mas01mc@750
|
910 }
|
mas01mc@750
|
911
|
mas01mc@750
|
912 return outgoing;
|
mas01mc@750
|
913
|
mas01mc@750
|
914
|
mas01mc@750
|
915
|
mas01mc@750
|
916 }
|
mas01mc@750
|
917
|
map01bf@622
|
918
|
mas01mc@746
|
919 /* retrieval of inserted data
|
mas01mc@746
|
920 * returned numpy array has ndarray.shape = (numVectors, numDims)
|
mas01mc@746
|
921 * array datatype needs to be doubles (float may work...)
|
mas01mc@746
|
922 * if power reqeusted, it will be a 1d array of length numVectors
|
mas01mc@746
|
923 * if times are requested, they will be a 1d array of length 2*nvectors
|
mas01mc@746
|
924 */
|
mas01mc@746
|
925
|
mas01mc@746
|
926 // api call:
|
mas01mc@746
|
927 // typedef struct adb_datum {
|
mas01mc@746
|
928 // uint32_t nvectors;
|
mas01mc@746
|
929 // uint32_t dim;
|
mas01mc@746
|
930 // const char *key;
|
mas01mc@746
|
931 // double *data;
|
mas01mc@746
|
932 // double *power;
|
mas01mc@746
|
933 // double *times;
|
mas01mc@746
|
934 // } adb_datum_t;
|
mas01mc@746
|
935
|
mas01mc@746
|
936 //int audiodb_retrieve_datum(adb_t *, const char *, adb_datum_t *);
|
mas01mc@746
|
937 //int audiodb_free_datum(adb_t *, adb_datum_t *);
|
mas01mc@746
|
938 PyObject * _pyadb_retrieveDatum(PyObject *self, PyObject *args, PyObject *keywds)
|
mas01mc@746
|
939 {
|
mas01mc@746
|
940 adb_t *current_db = NULL;
|
mas01mc@746
|
941 adb_status_t *status = NULL;
|
mas01mc@746
|
942 adb_datum_t *ins = NULL;
|
mas01mc@746
|
943 int ok=0, errtest=0;
|
mas01mc@746
|
944 unsigned features=0, powers=0, times=0;
|
mas01mc@746
|
945 PyObject *incoming = 0; // The ADB database
|
mas01mc@746
|
946 PyObject *outgoing = 0; // The PyArrayObject
|
mas01mc@746
|
947 const char *key = NULL;
|
mas01mc@746
|
948 static char *kwlist[] = { "db", "key", "features", "powers", "times", NULL};
|
mas01mc@758
|
949 double * data = NULL;
|
mas01mc@746
|
950 int dims = 0;
|
mas01mc@746
|
951 npy_intp shape[2] = { 0, 0 };
|
mas01mc@746
|
952
|
mas01mc@746
|
953 ok = PyArg_ParseTupleAndKeywords(args, keywds, "Os|III", kwlist, &incoming, &key, &features, &powers, ×);
|
mas01mc@746
|
954 if (!ok){
|
mas01mc@746
|
955 PyErr_SetString(PyExc_TypeError, "Failed at PyArg_ParseTupleAndKeywords");
|
mas01mc@746
|
956 return NULL;
|
mas01mc@746
|
957 }
|
mas01mc@746
|
958
|
mas01mc@746
|
959 if(features+powers+times>1){
|
mas01mc@746
|
960 PyErr_SetString(PyExc_TypeError, "Failed: you must specify only one of features, powers, or times");
|
mas01mc@746
|
961 return NULL;
|
mas01mc@746
|
962 }
|
mas01mc@746
|
963
|
mas01mc@746
|
964 if(!(features||powers||times)){
|
mas01mc@746
|
965 features=1; // default is to return features
|
mas01mc@746
|
966 }
|
mas01mc@746
|
967
|
mas01mc@746
|
968 current_db = (adb_t *)PyCObject_AsVoidPtr(incoming);
|
mas01mc@746
|
969 if (!current_db){
|
mas01mc@746
|
970 PyErr_SetString(PyExc_TypeError, "Failed to convert open database to C-pointer");
|
mas01mc@746
|
971 return NULL;
|
mas01mc@746
|
972 }
|
mas01mc@746
|
973 status = (adb_status_t*) malloc(sizeof(adb_status_t));
|
mas01mc@746
|
974 errtest = audiodb_status(current_db, status);
|
mas01mc@746
|
975 if(errtest){
|
mas01mc@746
|
976 PyErr_SetString(PyExc_TypeError, "Failed: could not get status of passed ADB database");
|
mas01mc@746
|
977 free(status);
|
mas01mc@746
|
978 return NULL;
|
mas01mc@746
|
979 }
|
mas01mc@746
|
980
|
mas01mc@746
|
981 if(powers && !(status->flags&ADB_HEADER_FLAG_POWER)){
|
mas01mc@746
|
982 PyErr_SetString(PyExc_TypeError, "Failed: powers requested but passed ADB database has no powers");
|
mas01mc@746
|
983 free(status);
|
mas01mc@746
|
984 return NULL;
|
mas01mc@746
|
985 }
|
mas01mc@746
|
986
|
mas01mc@746
|
987 if(times && !(status->flags&ADB_HEADER_FLAG_TIMES)){
|
mas01mc@746
|
988 PyErr_SetString(PyExc_TypeError, "Failed: times requested but passed ADB database has no times");
|
mas01mc@746
|
989 free(status);
|
mas01mc@746
|
990 return NULL;
|
mas01mc@746
|
991 }
|
mas01mc@746
|
992
|
mas01mc@746
|
993 ins = (adb_datum_t *)malloc(sizeof(adb_datum_t));
|
mas01mc@746
|
994 errtest = audiodb_retrieve_datum(current_db, key, ins); // retrieve data from adb via key
|
mas01mc@746
|
995 if (errtest){
|
mas01mc@746
|
996 PyErr_SetString(PyExc_TypeError, "Failed to retrieve datum");
|
mas01mc@746
|
997 free(ins);
|
mas01mc@746
|
998 return NULL;
|
mas01mc@746
|
999 }
|
mas01mc@746
|
1000
|
mas01mc@746
|
1001 if(features){
|
mas01mc@746
|
1002 if(ins->dim>1){
|
mas01mc@746
|
1003 dims=2;
|
mas01mc@751
|
1004 shape[1]= ins->dim;
|
mas01mc@746
|
1005 }
|
mas01mc@746
|
1006 else{
|
mas01mc@746
|
1007 dims=1;
|
mas01mc@746
|
1008 }
|
mas01mc@746
|
1009 shape[0]= ins->nvectors;
|
mas01mc@746
|
1010 data = ins->data;
|
mas01mc@746
|
1011 }
|
mas01mc@746
|
1012 else if(powers){
|
mas01mc@746
|
1013 dims=1;
|
mas01mc@746
|
1014 shape[0]= ins->nvectors;
|
mas01mc@746
|
1015 data = ins->power;
|
mas01mc@746
|
1016 }
|
mas01mc@746
|
1017 else if(times){
|
mas01mc@746
|
1018 dims=1;
|
mas01mc@746
|
1019 shape[0]= 2 * ins->nvectors;
|
mas01mc@746
|
1020 data = ins->times;
|
mas01mc@746
|
1021 }
|
mas01mc@746
|
1022
|
mas01mc@748
|
1023 outgoing = PyArray_SimpleNew(dims, shape, NPY_DOUBLE);
|
mas01mc@746
|
1024 if (!outgoing){
|
mas01mc@748
|
1025 free(status);
|
mas01mc@748
|
1026 free(ins); // free the malloced adb_datum_t structure though
|
mas01mc@748
|
1027 Py_XDECREF(outgoing);
|
mas01mc@746
|
1028 PyErr_SetString(PyExc_TypeError, "Failed to convert retrieved datum to C-Array");
|
mas01mc@746
|
1029 return NULL;
|
mas01mc@748
|
1030 }
|
mas01mc@747
|
1031
|
mas01mc@748
|
1032 /* Copy the data, this allows us to free the allocated memory and let
|
mas01mc@748
|
1033 * python do the subsequent garbage collection itself.
|
mas01mc@748
|
1034 */
|
mas01mc@751
|
1035 int num_items = ins->nvectors;
|
mas01mc@751
|
1036 if(dims>1){
|
mas01mc@751
|
1037 num_items *= shape[1];
|
mas01mc@751
|
1038 }
|
mas01mc@748
|
1039 double* p = (double*) PyArray_DATA(outgoing);
|
mas01mc@748
|
1040 double* d = data;
|
mas01mc@748
|
1041 while(num_items--)
|
mas01mc@748
|
1042 *p++ = *d++;
|
mas01mc@748
|
1043 audiodb_free_datum(current_db, ins); // free the source audiodb_datum
|
mas01mc@748
|
1044 free(status); // free the malloced status object
|
mas01mc@748
|
1045 free(ins); // free the malloced adb_datum_t structure though
|
mas01mc@746
|
1046 return outgoing;
|
mas01mc@746
|
1047 }
|
map01bf@622
|
1048
|
map01bf@622
|
1049
|
map01bf@620
|
1050 /* close a database */
|
map01bf@620
|
1051 /* api call: */
|
mas01cr@671
|
1052 // void audiodb_close(adb_t *db);
|
map01bf@620
|
1053 static void _pyadb_close(void *ptr)
|
map01bf@620
|
1054 {
|
mas01cr@671
|
1055 adb_t *stale_database;
|
mas01cr@671
|
1056 stale_database = (adb_t *)ptr;
|
map01bf@620
|
1057
|
map01bf@620
|
1058 audiodb_close(stale_database);
|
map01bf@620
|
1059 }
|
map01bf@620
|
1060
|
map01bf@620
|
1061 static PyMethodDef _pyadbMethods[] =
|
map01bf@620
|
1062 {
|
map01bf@620
|
1063 { "_pyadb_create", _pyadb_create, METH_VARARGS,
|
map01bf@620
|
1064 "_pyadb_create(string path, unsigned datasize, unsigned ntracks, unsigned datadim)->adb object"},
|
map01bf@620
|
1065 { "_pyadb_open", _pyadb_open, METH_VARARGS,
|
map01bf@620
|
1066 "_pyadb_open(string path, [\'r\'|\'w\'])->adb object\nNote that specifing \'w\' opens the file in read and write mode. \
|
map01bf@620
|
1067 There is currently no way to open in write only."},
|
map01bf@620
|
1068 { "_pyadb_status", _pyadb_status, METH_VARARGS,
|
mas01cr@671
|
1069 "_status(adb_t *)->(numFiles, dims, dudCount, nullCount, flags, length, data_region_size)"},
|
map01bf@620
|
1070 { "_pyadb_l2norm", _pyadb_l2norm, METH_VARARGS,
|
mas01cr@671
|
1071 "_pyadb_l2norm(adb_t *)->int return code (0 for sucess)"},
|
map01bf@620
|
1072 { "_pyadb_power", _pyadb_power, METH_VARARGS,
|
mas01cr@671
|
1073 "_pyadb_power(adb_t *)->int return code (0 for sucess)"},
|
map01bf@716
|
1074 {"_pyadb_insertFromArray", (PyCFunction)_pyadb_insertFromArray, METH_VARARGS | METH_KEYWORDS,
|
map01bf@718
|
1075 "_pyadb_insertFromArray(adb_t *, features=ndarray, [power=ndarray | key=keystring | times=ndarray])->\
|
map01bf@718
|
1076 int return code (0 for sucess)\n\
|
map01bf@718
|
1077 insert feature data from a numpy array\n\
|
map01bf@716
|
1078 array given should have ndarray.shape = (numDims*numVectors,)\n\
|
map01bf@716
|
1079 array datatype needs to be doubles (float may work...)\n\
|
map01bf@716
|
1080 if power is given, must be 1d array of length numVectors\n\
|
map01bf@716
|
1081 if times is given, must be 1d array of length 2*numVectors like this:\n\
|
map01bf@716
|
1082 int audiodb_insert_datum(adb_t *, const adb_datum_t *);"},
|
mas01mc@746
|
1083 {"_pyadb_retrieveDatum", (PyCFunction)_pyadb_retrieveDatum, METH_VARARGS | METH_KEYWORDS, "_pyadb_retrieveDatum(adb_t *, key=keystring"},
|
map01bf@622
|
1084 { "_pyadb_insertFromFile", (PyCFunction)_pyadb_insertFromFile, METH_VARARGS | METH_KEYWORDS,
|
mas01cr@671
|
1085 "_pyadb_insertFromFile(adb_t *, features=featureFile, [power=powerfile | key=keystring | times=timingFile])->\
|
map01bf@621
|
1086 int return code (0 for sucess)"},
|
mas01mc@744
|
1087 { "_pyadb_liszt", (PyCFunction)_pyadb_liszt, METH_VARARGS,
|
mas01mc@744
|
1088 "_pyadb_liszt(adb_t*)->[[key1,numvecs1],[key2,numvecs2]...]"},
|
map01bf@622
|
1089 { "_pyadb_queryFromKey", (PyCFunction)_pyadb_queryFromKey, METH_VARARGS | METH_KEYWORDS,
|
map01bf@622
|
1090 "base query. The nomenclature here is about a far away as pythonic as is possible.\n\
|
map01bf@622
|
1091 This should be taken care of via the higher level python structure\n\
|
map01bf@622
|
1092 returns a dict that should be result ordered and key = result key\n\
|
map01bf@622
|
1093 and value is a list of tuples one per result associated with that key, of the form:\n\
|
map01bf@622
|
1094 \t(dist, qpos, ipos)\n\
|
map01bf@622
|
1095 Note as well that this is by no means the most efficient way to cast from C, simply the most direct\n\
|
map01bf@622
|
1096 and what it lacks in effeciency it gains in python side access. It remains to be seen if this is\n\
|
map01bf@622
|
1097 a sensible trade.\n\
|
mas01cr@671
|
1098 _pyadb_queryFromKey(adb_t *, query key,\n\
|
map01bf@622
|
1099 [seqLength = Int Sequence Length, \n\
|
map01bf@622
|
1100 seqStart = Int offset from start for key, \n\
|
map01bf@622
|
1101 exhaustive = boolean - True for exhaustive (false by default),\n\
|
map01bf@622
|
1102 falsePositives= boolean - True to keep fps (false by defaults),\n\
|
map01bf@622
|
1103 accumulation = [\"db\"|\"track\"|\"one2one\"] (\"db\" by default),\n\
|
map01bf@622
|
1104 distance = [\"dot\"|\"eucNorm\"|\"euclidean\"] (\"dot\" by default),\n\
|
map01bf@622
|
1105 npoints = int number of points per track,\n\
|
map01bf@622
|
1106 ntracks = max number of results returned in db accu mode,\n\
|
map01bf@622
|
1107 includeKeys = list of strings to include (use all by default),\n\
|
map01bf@622
|
1108 excludeKeys = list of strings to exclude (none by default),\n\
|
map01bf@622
|
1109 radius = double of nnRadius (1.0 default, overrides npoints if specified),\n\
|
map01bf@622
|
1110 absThres = double absolute power threshold (db must have power),\n\
|
map01bf@622
|
1111 relThres = double relative power threshold (db must have power),\n\
|
map01bf@622
|
1112 durRatio = double time expansion/compresion ratio,\n\
|
map01bf@628
|
1113 hopSize = int hopsize (1 by default)])->resultDict\n\
|
map01bf@628
|
1114 resFmt = [\"list\"|\"dict\"](\"dict\" by default)"},
|
mas01mc@750
|
1115 {"_pyadb_queryFromData", (PyCFunction)_pyadb_queryFromData, METH_VARARGS | METH_KEYWORDS,
|
mas01mc@750
|
1116 "data query. Required features=F (numpy ndarray). Optional: power=P (numpy 1d array), times=T (numpy 1d array)"},
|
map01bf@620
|
1117 {NULL,NULL, 0, NULL}
|
map01bf@620
|
1118 };
|
map01bf@620
|
1119
|
mas01mc@758
|
1120 void init_pyadb(void)
|
map01bf@620
|
1121 {
|
map01bf@718
|
1122 Py_InitModule3("_pyadb", _pyadbMethods, "internal c bindings for audioDB. Use pyadb for pythonic access to adb.");
|
map01bf@718
|
1123 import_array();
|
map01bf@620
|
1124 return;
|
map01bf@620
|
1125 }
|
map01bf@620
|
1126
|
map01bf@620
|
1127
|