Mercurial > hg > audiodb
comparison audioDB.cpp @ 498:342822c2d49a
Merge api-inversion branch (-r656:771, but I don't expect to return to
that branch) into the trunk.
I expect there to be minor performance regressions (e.g. in the SOAP
server index cacheing, which I have forcibly removed) and minor
unplugged memory leaks (e.g. in audioDB::query(), where I don't free up
the datum). I hope that these leaks and performance regressions can be
plugged in short order. I also expect that some (but maybe not all) of
the issues currently addressed in the memory-leaks branch are superseded
or fixed by this merge.
There remains much work to be done; go forth and do it.
author | mas01cr |
---|---|
date | Sat, 10 Jan 2009 16:47:57 +0000 |
parents | f9d86b1db21c |
children | da4b76190d43 |
comparison
equal
deleted
inserted
replaced
476:a7193678280b | 498:342822c2d49a |
---|---|
1 #include "audioDB.h" | 1 #include "audioDB.h" |
2 | 2 extern "C" { |
3 LSH* SERVER_LSH_INDEX_SINGLETON; | 3 #include "audioDB_API.h" |
4 #include "audioDB-internals.h" | |
5 } | |
6 #include "reporter.h" | |
7 | |
4 char* SERVER_ADB_ROOT; | 8 char* SERVER_ADB_ROOT; |
5 char* SERVER_ADB_FEATURE_ROOT; | 9 char* SERVER_ADB_FEATURE_ROOT; |
6 | |
7 PointPair::PointPair(Uns32T a, Uns32T b, Uns32T c):trackID(a),qpos(b),spos(c){}; | |
8 | |
9 bool operator<(const PointPair& a, const PointPair& b){ | |
10 return ( (a.trackID<b.trackID) || | |
11 ( (a.trackID==b.trackID) && | |
12 ( (a.spos<b.spos) || ( (a.spos==b.spos) && (a.qpos < b.qpos) )) ) ); | |
13 } | |
14 | |
15 bool operator>(const PointPair& a, const PointPair& b){ | |
16 return ( (a.trackID>b.trackID) || | |
17 ( (a.trackID==b.trackID) && | |
18 ( (a.spos>b.spos) || ( (a.spos==b.spos) && (a.qpos > b.qpos) )) ) ); | |
19 } | |
20 | |
21 bool operator==(const PointPair& a, const PointPair& b){ | |
22 return ( (a.trackID==b.trackID) && (a.qpos==b.qpos) && (a.spos==b.spos) ); | |
23 } | |
24 | 10 |
25 audioDB::audioDB(const unsigned argc, const char *argv[]): O2_AUDIODB_INITIALIZERS | 11 audioDB::audioDB(const unsigned argc, const char *argv[]): O2_AUDIODB_INITIALIZERS |
26 { | 12 { |
27 if(processArgs(argc, argv)<0){ | 13 if(processArgs(argc, argv)<0){ |
28 printf("No command found.\n"); | 14 printf("No command found.\n"); |
39 // Perform database prefix substitution | 25 // Perform database prefix substitution |
40 if(dbName && adb_root) | 26 if(dbName && adb_root) |
41 prefix_name((char** const)&dbName, adb_root); | 27 prefix_name((char** const)&dbName, adb_root); |
42 | 28 |
43 if(O2_ACTION(COM_SERVER)){ | 29 if(O2_ACTION(COM_SERVER)){ |
44 #ifdef LIBRARY | |
45 ; | |
46 #else | |
47 startServer(); | 30 startServer(); |
48 if(SERVER_LSH_INDEX_SINGLETON) | |
49 delete lsh; | |
50 #endif | |
51 } | 31 } |
52 else if(O2_ACTION(COM_CREATE)) | 32 else if(O2_ACTION(COM_CREATE)) |
53 create(dbName); | 33 create(dbName); |
54 | 34 |
55 else if(O2_ACTION(COM_INSERT)) | 35 else if(O2_ACTION(COM_INSERT)) |
58 else if(O2_ACTION(COM_BATCHINSERT)) | 38 else if(O2_ACTION(COM_BATCHINSERT)) |
59 batchinsert(dbName, inFile); | 39 batchinsert(dbName, inFile); |
60 | 40 |
61 else if(O2_ACTION(COM_QUERY)) | 41 else if(O2_ACTION(COM_QUERY)) |
62 if(isClient){ | 42 if(isClient){ |
63 #ifdef LIBRARY | |
64 ; | |
65 #else | |
66 if(query_from_key){ | 43 if(query_from_key){ |
67 VERB_LOG(1, "Calling web services query %s on database %s, query=%s\n", radius>0?"(Radius)":"(NN)", dbName, (key&&strlen(key))?key:inFile); | 44 VERB_LOG(1, "Calling web services query %s on database %s, query=%s\n", radius>0?"(Radius)":"(NN)", dbName, (key&&strlen(key))?key:inFile); |
68 ws_query_by_key(dbName, key, inFile, (char*)hostport); | 45 ws_query_by_key(dbName, key, inFile, (char*)hostport); |
69 } | 46 } |
70 else{ | 47 else{ |
71 VERB_LOG(1, "Calling web services query on database %s, query=%s\n", dbName, (key&&strlen(key))?key:inFile); | 48 VERB_LOG(1, "Calling web services query on database %s, query=%s\n", dbName, (key&&strlen(key))?key:inFile); |
72 ws_query(dbName, inFile, (char*)hostport); | 49 ws_query(dbName, inFile, (char*)hostport); |
73 } | 50 } |
74 #endif | |
75 } | 51 } |
76 else | 52 else |
77 query(dbName, inFile); | 53 query(dbName, inFile); |
78 | 54 |
79 else if(O2_ACTION(COM_STATUS)) | 55 else if(O2_ACTION(COM_STATUS)) |
80 if(isClient) | 56 if(isClient) |
81 #ifdef LIBRARY | |
82 ; | |
83 #else | |
84 ws_status(dbName,(char*)hostport); | 57 ws_status(dbName,(char*)hostport); |
85 #endif | |
86 else | 58 else |
87 status(dbName); | 59 status(dbName); |
88 | 60 |
89 else if(O2_ACTION(COM_SAMPLE)) | 61 else if(O2_ACTION(COM_SAMPLE)) |
90 sample(dbName); | 62 sample(dbName); |
98 else if(O2_ACTION(COM_DUMP)) | 70 else if(O2_ACTION(COM_DUMP)) |
99 dump(dbName); | 71 dump(dbName); |
100 | 72 |
101 else if(O2_ACTION(COM_LISZT)) | 73 else if(O2_ACTION(COM_LISZT)) |
102 if(isClient) | 74 if(isClient) |
103 #ifdef LIBRARY | |
104 ; | |
105 #else | |
106 ws_liszt(dbName, (char*) hostport); | 75 ws_liszt(dbName, (char*) hostport); |
107 #endif | |
108 else | 76 else |
109 liszt(dbName, lisztOffset, lisztLength); | 77 liszt(dbName, lisztOffset, lisztLength); |
110 | 78 |
111 else if(O2_ACTION(COM_INDEX)) | 79 else if(O2_ACTION(COM_INDEX)) |
112 index_index_db(dbName); | 80 index_index_db(dbName); |
161 cleanup(); | 129 cleanup(); |
162 throw(err); | 130 throw(err); |
163 } | 131 } |
164 } | 132 } |
165 | 133 |
166 | |
167 //for the lib / API | |
168 audioDB::audioDB(const unsigned argc, const char *argv[], int * apierror): O2_AUDIODB_INITIALIZERS | |
169 { | |
170 | |
171 try { | |
172 UseApiError=1; | |
173 | |
174 if(processArgs(argc, argv)<0){ | |
175 printf("No command found.\n"); | |
176 cmdline_parser_print_version (); | |
177 if (strlen(gengetopt_args_info_purpose) > 0) | |
178 printf("%s\n", gengetopt_args_info_purpose); | |
179 printf("%s\n", gengetopt_args_info_usage); | |
180 printf("%s\n", gengetopt_args_info_help[1]); | |
181 printf("%s\n", gengetopt_args_info_help[2]); | |
182 printf("%s\n", gengetopt_args_info_help[0]); | |
183 error("No command found"); | |
184 } | |
185 | |
186 adb__queryResponse adbq; | |
187 | |
188 if(O2_ACTION(COM_CREATE)) | |
189 create(dbName); | |
190 | |
191 else if(O2_ACTION(COM_INSERT)) | |
192 insert(dbName, inFile); | |
193 | |
194 else if(O2_ACTION(COM_BATCHINSERT)) | |
195 batchinsert(dbName, inFile); | |
196 | |
197 else if(O2_ACTION(COM_QUERY)) | |
198 if(isClient) | |
199 ;//ws_query(dbName, inFile, (char*)hostport); | |
200 else | |
201 query(dbName, inFile, &adbq); | |
202 //query(dbName, inFile); | |
203 | |
204 else if(O2_ACTION(COM_STATUS)) | |
205 if(isClient) | |
206 ;//ws_status(dbName,(char*)hostport); | |
207 else | |
208 status(dbName); | |
209 | |
210 else if(O2_ACTION(COM_L2NORM)) | |
211 l2norm(dbName); | |
212 | |
213 else if(O2_ACTION(COM_POWER)) | |
214 power_flag(dbName); | |
215 | |
216 else if(O2_ACTION(COM_DUMP)) | |
217 dump(dbName); | |
218 | |
219 else | |
220 error("Unrecognized command",command); | |
221 | |
222 } catch(int a) { | |
223 *apierror=a; | |
224 return; | |
225 | |
226 } | |
227 *apierror=apierrortemp; | |
228 return; | |
229 | |
230 } | |
231 | |
232 //for API status | |
233 audioDB::audioDB(const unsigned argc, const char *argv[], cppstatusptr stat, int * apierror): O2_AUDIODB_INITIALIZERS | |
234 { | |
235 | |
236 try { | |
237 UseApiError=1; | |
238 | |
239 | |
240 if(processArgs(argc, argv)<0){ | |
241 printf("No command found.\n"); | |
242 cmdline_parser_print_version (); | |
243 if (strlen(gengetopt_args_info_purpose) > 0) | |
244 printf("%s\n", gengetopt_args_info_purpose); | |
245 printf("%s\n", gengetopt_args_info_usage); | |
246 printf("%s\n", gengetopt_args_info_help[1]); | |
247 printf("%s\n", gengetopt_args_info_help[2]); | |
248 printf("%s\n", gengetopt_args_info_help[0]); | |
249 error("No command found"); | |
250 } | |
251 | |
252 status(dbName, stat); | |
253 | |
254 | |
255 } catch(int a) { | |
256 *apierror=a; | |
257 return; | |
258 | |
259 } | |
260 *apierror=apierrortemp; | |
261 return; | |
262 | |
263 } | |
264 | |
265 | |
266 //for API query | |
267 audioDB::audioDB(const unsigned argc, const char *argv[],adb__queryResponse *adbQueryResponse, int * apierror): O2_AUDIODB_INITIALIZERS | |
268 { | |
269 | |
270 try { | |
271 UseApiError=1; | |
272 | |
273 if(processArgs(argc, argv)<0){ | |
274 printf("No command found.\n"); | |
275 cmdline_parser_print_version (); | |
276 if (strlen(gengetopt_args_info_purpose) > 0) | |
277 printf("%s\n", gengetopt_args_info_purpose); | |
278 printf("%s\n", gengetopt_args_info_usage); | |
279 printf("%s\n", gengetopt_args_info_help[1]); | |
280 printf("%s\n", gengetopt_args_info_help[2]); | |
281 printf("%s\n", gengetopt_args_info_help[0]); | |
282 error("No command found"); | |
283 } | |
284 | |
285 query(dbName, inFile, adbQueryResponse); | |
286 | |
287 } catch(int a) { | |
288 *apierror=a; | |
289 return; | |
290 | |
291 } | |
292 *apierror=apierrortemp; | |
293 return; | |
294 | |
295 } | |
296 | |
297 | |
298 | |
299 | |
300 | |
301 void audioDB::cleanup() { | 134 void audioDB::cleanup() { |
302 cmdline_parser_free(&args_info); | 135 cmdline_parser_free(&args_info); |
303 if(indata) | |
304 munmap(indata,statbuf.st_size); | |
305 if(db) | |
306 munmap(db,getpagesize()); | |
307 if(fileTable) | 136 if(fileTable) |
308 munmap(fileTable, fileTableLength); | 137 munmap(fileTable, fileTableLength); |
309 if(trackTable) | 138 if(trackTable) |
310 munmap(trackTable, trackTableLength); | 139 munmap(trackTable, trackTableLength); |
311 if(dataBuf) | |
312 munmap(dataBuf, dataBufLength); | |
313 if(timesTable) | 140 if(timesTable) |
314 munmap(timesTable, timesTableLength); | 141 munmap(timesTable, timesTableLength); |
315 if(powerTable) | 142 if(powerTable) |
316 munmap(powerTable, powerTableLength); | 143 munmap(powerTable, powerTableLength); |
317 if(l2normTable) | 144 if(l2normTable) |
320 munmap(featureFileNameTable, fileTableLength); | 147 munmap(featureFileNameTable, fileTableLength); |
321 if(timesFileNameTable) | 148 if(timesFileNameTable) |
322 munmap(timesFileNameTable, fileTableLength); | 149 munmap(timesFileNameTable, fileTableLength); |
323 if(powerFileNameTable) | 150 if(powerFileNameTable) |
324 munmap(powerFileNameTable, fileTableLength); | 151 munmap(powerFileNameTable, fileTableLength); |
325 if(trackOffsetTable) | |
326 delete [] trackOffsetTable; | |
327 if(reporter) | 152 if(reporter) |
328 delete reporter; | 153 delete reporter; |
329 if(exact_evaluation_queue) | |
330 delete exact_evaluation_queue; | |
331 if(allowed_keys) | 154 if(allowed_keys) |
332 delete allowed_keys; | 155 delete allowed_keys; |
333 if(rng) | 156 if(rng) |
334 gsl_rng_free(rng); | 157 gsl_rng_free(rng); |
335 if(vv) | |
336 delete vv; | |
337 if(dbfid>0) | |
338 close(dbfid); | |
339 if(infid>0) | 158 if(infid>0) |
340 close(infid); | 159 close(infid); |
341 if(dbH) | 160 if(adb) { |
342 delete dbH; | 161 audiodb_close(adb); |
343 if(lsh!=SERVER_LSH_INDEX_SINGLETON) | 162 adb = NULL; |
163 } | |
164 if(lsh) | |
344 delete lsh; | 165 delete lsh; |
345 } | 166 } |
346 | 167 |
347 audioDB::~audioDB(){ | 168 audioDB::~audioDB(){ |
348 cleanup(); | 169 cleanup(); |
741 | 562 |
742 return -1; // no command found | 563 return -1; // no command found |
743 } | 564 } |
744 | 565 |
745 void audioDB::status(const char* dbName, adb__statusResponse *adbStatusResponse){ | 566 void audioDB::status(const char* dbName, adb__statusResponse *adbStatusResponse){ |
746 if(!dbH) | 567 adb_status_t status; |
747 initTables(dbName, 0); | 568 if(!adb) { |
748 | 569 if(!(adb = audiodb_open(dbName, O_RDONLY))) { |
749 unsigned dudCount=0; | 570 error("Failed to open database file", dbName); |
750 unsigned nullCount=0; | 571 } |
751 for(unsigned k=0; k<dbH->numFiles; k++){ | 572 } |
752 if(trackTable[k]<sequenceLength){ | 573 if(audiodb_status(adb, &status)) { |
753 dudCount++; | 574 error("Failed to retrieve database status", dbName); |
754 if(!trackTable[k]) | |
755 nullCount++; | |
756 } | |
757 } | 575 } |
758 | 576 |
759 if(adbStatusResponse == 0) { | 577 if(adbStatusResponse == 0) { |
760 | 578 std::cout << "num files:" << status.numFiles << std::endl; |
761 // Update Header information | 579 std::cout << "data dim:" << status.dim <<std::endl; |
762 std::cout << "num files:" << dbH->numFiles << std::endl; | 580 if(status.dim > 0) { |
763 std::cout << "data dim:" << dbH->dim <<std::endl; | 581 size_t bytes_per_vector = sizeof(double) * status.dim; |
764 if(dbH->dim>0){ | 582 off_t nvectors = status.length / bytes_per_vector; |
765 std::cout << "total vectors:" << dbH->length/(sizeof(double)*dbH->dim)<<std::endl; | 583 off_t data_region_vectors = status.data_region_size / bytes_per_vector; |
766 if(dbH->flags & O2_FLAG_LARGE_ADB) | 584 std::cout << "total vectors:" << nvectors << std::endl; |
767 std::cout << "vectors available:" << O2_MAX_VECTORS - (dbH->length / (sizeof(double)*dbH->dim)) << std::endl; | 585 std::cout << "vectors available:"; |
768 else | 586 if(status.flags & O2_FLAG_LARGE_ADB) { |
769 std::cout << "vectors available:" << (dbH->timesTableOffset-(dbH->dataOffset+dbH->length))/(sizeof(double)*dbH->dim) << std::endl; | 587 std::cout << O2_MAX_VECTORS - nvectors << std::endl; |
770 } | 588 } else { |
771 if( ! (dbH->flags & O2_FLAG_LARGE_ADB) ){ | 589 std::cout << data_region_vectors - nvectors << std::endl; |
772 std::cout << "total bytes:" << dbH->length << " (" << (100.0*dbH->length)/(dbH->timesTableOffset-dbH->dataOffset) << "%)" << std::endl; | 590 } |
773 std::cout << "bytes available:" << dbH->timesTableOffset-(dbH->dataOffset+dbH->length) << " (" << | 591 } |
774 (100.0*(dbH->timesTableOffset-(dbH->dataOffset+dbH->length)))/(dbH->timesTableOffset-dbH->dataOffset) << "%)" << std::endl; | 592 if(!(status.flags & O2_FLAG_LARGE_ADB)) { |
775 } | 593 double used_frac = ((double) status.length) / status.data_region_size; |
776 std::cout << "flags:" << " l2norm[" << DISPLAY_FLAG(dbH->flags&O2_FLAG_L2NORM) | 594 std::cout << "total bytes:" << status.length << |
777 << "] minmax[" << DISPLAY_FLAG(dbH->flags&O2_FLAG_MINMAX) | 595 " (" << (100.0*used_frac) << "%)" << std::endl; |
778 << "] power[" << DISPLAY_FLAG(dbH->flags&O2_FLAG_POWER) | 596 std::cout << "bytes available:" << status.data_region_size - status.length << |
779 << "] times[" << DISPLAY_FLAG(dbH->flags&O2_FLAG_TIMES) | 597 " (" << (100.0*(1-used_frac)) << "%)" << std::endl; |
780 << "] largeADB[" << DISPLAY_FLAG(dbH->flags&O2_FLAG_LARGE_ADB) | 598 } |
599 std::cout << "flags:" << " l2norm[" << DISPLAY_FLAG(status.flags&O2_FLAG_L2NORM) | |
600 << "] minmax[" << DISPLAY_FLAG(status.flags&O2_FLAG_MINMAX) | |
601 << "] power[" << DISPLAY_FLAG(status.flags&O2_FLAG_POWER) | |
602 << "] times[" << DISPLAY_FLAG(status.flags&O2_FLAG_TIMES) | |
603 << "] largeADB[" << DISPLAY_FLAG(status.flags&O2_FLAG_LARGE_ADB) | |
781 << "]" << endl; | 604 << "]" << endl; |
782 | 605 |
783 std::cout << "null count: " << nullCount << " small sequence count " << dudCount-nullCount << std::endl; | 606 std::cout << "null count: " << status.nullCount << " small sequence count " << status.dudCount-status.nullCount << std::endl; |
784 } else { | 607 } else { |
785 adbStatusResponse->result.numFiles = dbH->numFiles; | 608 adbStatusResponse->result.numFiles = status.numFiles; |
786 adbStatusResponse->result.dim = dbH->dim; | 609 adbStatusResponse->result.dim = status.dim; |
787 adbStatusResponse->result.length = dbH->length; | 610 adbStatusResponse->result.length = status.length; |
788 adbStatusResponse->result.dudCount = dudCount; | 611 adbStatusResponse->result.dudCount = status.dudCount; |
789 adbStatusResponse->result.nullCount = nullCount; | 612 adbStatusResponse->result.nullCount = status.nullCount; |
790 adbStatusResponse->result.flags = dbH->flags; | 613 adbStatusResponse->result.flags = status.flags; |
791 } | 614 } |
792 } | 615 } |
793 | 616 |
794 ///used by lib/API | 617 void audioDB::l2norm(const char* dbName) { |
795 void audioDB::status(const char* dbName, cppstatusptr status){ | 618 if(!adb) { |
796 if(!dbH) { | 619 if(!(adb = audiodb_open(dbName, O_RDWR))) { |
797 initTables(dbName, 0); | 620 error("Failed to open database file", dbName); |
798 } | 621 } |
799 | 622 } |
800 unsigned dudCount=0; | 623 if(audiodb_l2norm(adb)) { |
801 unsigned nullCount=0; | 624 error("failed to turn on l2norm flag for database", dbName); |
802 for(unsigned k=0; k<dbH->numFiles; k++){ | 625 } |
803 if(trackTable[k]<sequenceLength){ | 626 } |
804 dudCount++; | 627 |
805 if(!trackTable[k]) | 628 void audioDB::power_flag(const char *dbName) { |
806 nullCount++; | 629 if(!adb) { |
807 } | 630 if(!(adb = audiodb_open(dbName, O_RDWR))) { |
808 } | 631 error("Failed to open database file", dbName); |
632 } | |
633 } | |
634 if(audiodb_power(adb)) { | |
635 error("can't turn on power flag for database", dbName); | |
636 } | |
637 } | |
638 | |
639 void audioDB::create(const char *dbName) { | |
640 if(adb) { | |
641 error("Already have an adb in this object", ""); | |
642 } | |
643 if(!(adb = audiodb_create(dbName, datasize, ntracks, datadim))) { | |
644 error("Failed to create database file", dbName); | |
645 } | |
646 } | |
647 | |
648 void audioDB::dump(const char *dbName) { | |
649 if(!adb) { | |
650 if(!(adb = audiodb_open(dbName, O_RDONLY))) { | |
651 error("Failed to open database file", dbName); | |
652 } | |
653 } | |
654 if(audiodb_dump(adb, output)) { | |
655 error("Failed to dump database to ", output); | |
656 } | |
657 status(dbName); | |
658 } | |
659 | |
660 void audioDB::insert(const char* dbName, const char* inFile) { | |
661 if(!adb) { | |
662 if(!(adb = audiodb_open(dbName, O_RDWR))) { | |
663 error("failed to open database", dbName); | |
664 } | |
665 } | |
666 | |
667 /* at this point, we have powerfd (an fd), timesFile (a | |
668 * std::ifstream *) and inFile (a char *). Wacky, huh? Ignore | |
669 * the wackiness and just use the names. */ | |
670 adb_insert_t insert; | |
671 insert.features = inFile; | |
672 insert.times = timesFileName; | |
673 insert.power = powerFileName; | |
674 insert.key = key; | |
675 | |
676 if(audiodb_insert(adb, &insert)) { | |
677 error("insertion failure", inFile); | |
678 } | |
679 status(dbName); | |
680 } | |
681 | |
682 void audioDB::batchinsert(const char* dbName, const char* inFile) { | |
683 if(!adb) { | |
684 if(!(adb = audiodb_open(dbName, O_RDWR))) { | |
685 error("failed to open database", dbName); | |
686 } | |
687 } | |
688 | |
689 if(!key) | |
690 key=inFile; | |
691 std::ifstream *filesIn = 0; | |
692 std::ifstream *keysIn = 0; | |
693 | |
694 if(!(filesIn = new std::ifstream(inFile))) | |
695 error("Could not open batch in file", inFile); | |
696 if(key && key!=inFile) | |
697 if(!(keysIn = new std::ifstream(key))) | |
698 error("Could not open batch key file",key); | |
699 | |
700 unsigned totalVectors=0; | |
701 char *thisFile = new char[MAXSTR]; | |
702 char *thisKey = 0; | |
703 if (key && (key != inFile)) { | |
704 thisKey = new char[MAXSTR]; | |
705 } | |
706 char *thisTimesFileName = new char[MAXSTR]; | |
707 char *thisPowerFileName = new char[MAXSTR]; | |
708 | |
709 do { | |
710 filesIn->getline(thisFile,MAXSTR); | |
711 if(key && key!=inFile) { | |
712 keysIn->getline(thisKey,MAXSTR); | |
713 } else { | |
714 thisKey = thisFile; | |
715 } | |
716 if(usingTimes) { | |
717 timesFile->getline(thisTimesFileName,MAXSTR); | |
718 } | |
719 if(usingPower) { | |
720 powerFile->getline(thisPowerFileName, MAXSTR); | |
721 } | |
722 | |
723 if(filesIn->eof()) { | |
724 break; | |
725 } | |
726 if(usingTimes){ | |
727 if(timesFile->eof()) { | |
728 error("not enough timestamp files in timesList", timesFileName); | |
729 } | |
730 } | |
731 if (usingPower) { | |
732 if(powerFile->eof()) { | |
733 error("not enough power files in powerList", powerFileName); | |
734 } | |
735 } | |
736 adb_insert_t insert; | |
737 insert.features = thisFile; | |
738 insert.times = usingTimes ? thisTimesFileName : NULL; | |
739 insert.power = usingPower ? thisPowerFileName : NULL; | |
740 insert.key = thisKey; | |
741 if(audiodb_insert(adb, &insert)) { | |
742 error("insertion failure", thisFile); | |
743 } | |
744 } while(!filesIn->eof()); | |
745 | |
746 VERB_LOG(0, "%s %s %u vectors %ju bytes.\n", COM_BATCHINSERT, dbName, totalVectors, (intmax_t) (totalVectors * dbH->dim * sizeof(double))); | |
747 | |
748 delete [] thisPowerFileName; | |
749 if(key && (key != inFile)) { | |
750 delete [] thisKey; | |
751 } | |
752 delete [] thisFile; | |
753 delete [] thisTimesFileName; | |
809 | 754 |
810 status->numFiles = dbH->numFiles; | 755 delete filesIn; |
811 status->dim = dbH->dim; | 756 delete keysIn; |
812 status->length = dbH->length; | 757 |
813 status->dudCount = dudCount; | 758 // Report status |
814 status->nullCount = nullCount; | 759 status(dbName); |
815 status->flags = dbH->flags; | 760 } |
816 | 761 |
817 return; | 762 void audioDB::query(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse) { |
818 } | 763 |
819 | 764 if(!adb) { |
820 | 765 if(!(adb = audiodb_open(dbName, O_RDWR))) { |
821 | 766 error("failed to open database", dbName); |
822 | 767 } |
823 void audioDB::l2norm(const char* dbName) { | 768 } |
824 forWrite = true; | 769 |
825 initTables(dbName, 0); | 770 /* FIXME: we only need this for getting nfiles, which we only need |
826 if( !(dbH->flags & O2_FLAG_LARGE_ADB ) && (dbH->length>0) ){ | 771 * because the reporters aren't desperately well implemented, |
827 /* FIXME: should probably be uint64_t */ | 772 * relying on statically-sized vectors rather than adjustable data |
828 unsigned numVectors = dbH->length/(sizeof(double)*dbH->dim); | 773 * structures. Rework reporter.h to be less lame. */ |
829 CHECKED_MMAP(double *, dataBuf, dbH->dataOffset, dataBufLength); | 774 adb_status_t status; |
830 unitNormAndInsertL2(dataBuf, dbH->dim, numVectors, 0); // No append | 775 audiodb_status(adb, &status); |
831 } | 776 uint32_t nfiles = status.numFiles; |
832 // Update database flags | 777 |
833 dbH->flags = dbH->flags|O2_FLAG_L2NORM; | 778 adb_query_spec_t qspec; |
834 memcpy (db, dbH, O2_HEADERSIZE); | 779 adb_datum_t datum = {0}; |
835 } | 780 |
836 | 781 qspec.refine.flags = 0; |
837 void audioDB::power_flag(const char *dbName) { | 782 if(trackFile) { |
838 forWrite = true; | 783 qspec.refine.flags |= ADB_REFINE_INCLUDE_KEYLIST; |
839 initTables(dbName, 0); | 784 std::vector<const char *> v; |
840 if( !(dbH->flags & O2_FLAG_LARGE_ADB ) && (dbH->length>0) ){ | 785 char *k = new char[MAXSTR]; |
841 error("cannot turn on power storage for non-empty database", dbName); | 786 trackFile->getline(k, MAXSTR); |
842 } | 787 while(!trackFile->eof()) { |
843 dbH->flags |= O2_FLAG_POWER; | 788 v.push_back(k); |
844 memcpy(db, dbH, O2_HEADERSIZE); | 789 k = new char[MAXSTR]; |
845 } | 790 trackFile->getline(k, MAXSTR); |
846 | 791 } |
847 // Unit norm block of features | 792 delete [] k; |
848 | 793 qspec.refine.include.nkeys = v.size(); |
849 /* FIXME: in fact this does not unit norm a block of features, it just | 794 qspec.refine.include.keys = new const char *[qspec.refine.include.nkeys]; |
850 records the L2 norms somewhere. unitNorm() does in fact unit norm | 795 for(unsigned int k = 0; k < qspec.refine.include.nkeys; k++) { |
851 a block of features. */ | 796 qspec.refine.include.keys[k] = v[k]; |
852 void audioDB::unitNormAndInsertL2(double* X, unsigned dim, unsigned n, unsigned append=0){ | 797 } |
853 unsigned d; | 798 } |
854 double *p; | 799 if(query_from_key) { |
855 unsigned nn = n; | 800 qspec.refine.flags |= ADB_REFINE_EXCLUDE_KEYLIST; |
856 | 801 qspec.refine.exclude.nkeys = 1; |
857 assert(l2normTable); | 802 qspec.refine.exclude.keys = &key; |
858 | 803 } |
859 if( !(dbH->flags & O2_FLAG_LARGE_ADB) && !append && (dbH->flags & O2_FLAG_L2NORM) ) | 804 if(radius) { |
860 error("Database is already L2 normed", "automatic norm on insert is enabled"); | 805 qspec.refine.flags |= ADB_REFINE_RADIUS; |
861 | 806 qspec.refine.radius = radius; |
862 VERB_LOG(2, "norming %u vectors...", n); | 807 } |
863 | 808 if(use_absolute_threshold) { |
864 double* l2buf = new double[n]; | 809 qspec.refine.flags |= ADB_REFINE_ABSOLUTE_THRESHOLD; |
865 double* l2ptr = l2buf; | 810 qspec.refine.absolute_threshold = absolute_threshold; |
866 assert(l2buf); | 811 } |
867 assert(X); | 812 if(use_relative_threshold) { |
868 | 813 qspec.refine.flags |= ADB_REFINE_RELATIVE_THRESHOLD; |
869 while(nn--){ | 814 qspec.refine.relative_threshold = relative_threshold; |
870 p=X; | 815 } |
871 *l2ptr=0.0; | 816 if(usingTimes) { |
872 d=dim; | 817 qspec.refine.flags |= ADB_REFINE_DURATION_RATIO; |
873 while(d--){ | 818 qspec.refine.duration_ratio = timesTol; |
874 *l2ptr+=*p**p; | 819 } |
875 p++; | 820 /* FIXME: not sure about this any more; maybe it belongs in |
876 } | 821 query_id? Or maybe we just don't need a flag for it? */ |
877 l2ptr++; | 822 qspec.refine.hopsize = sequenceHop; |
878 X+=dim; | 823 if(sequenceHop != 1) { |
879 } | 824 qspec.refine.flags |= ADB_REFINE_HOP_SIZE; |
880 unsigned offset; | 825 } |
881 if(append) { | 826 |
882 // FIXME: a hack, a very palpable hack: the vectors have already | 827 if(query_from_key) { |
883 // been inserted, and dbH->length has already been updated. We | 828 datum.key = key; |
884 // need to subtract off again the number of vectors that we've | |
885 // inserted this time... | |
886 offset=(dbH->length/(dbH->dim*sizeof(double)))-n; // number of vectors | |
887 } else { | 829 } else { |
888 offset=0; | 830 int fd; |
889 } | 831 struct stat st; |
890 memcpy(l2normTable+offset, l2buf, n*sizeof(double)); | 832 |
891 if(l2buf) | 833 /* FIXME: around here there are all sorts of hideous leaks. */ |
892 delete[] l2buf; | 834 fd = open(inFile, O_RDONLY); |
893 VERB_LOG(2, " done."); | 835 if(fd < 0) { |
836 error("failed to open feature file", inFile); | |
837 } | |
838 fstat(fd, &st); | |
839 read(fd, &datum.dim, sizeof(uint32_t)); | |
840 datum.nvectors = (st.st_size - sizeof(uint32_t)) / (datum.dim * sizeof(double)); | |
841 datum.data = (double *) malloc(st.st_size - sizeof(uint32_t)); | |
842 read(fd, datum.data, st.st_size - sizeof(uint32_t)); | |
843 close(fd); | |
844 if(usingPower) { | |
845 uint32_t one; | |
846 fd = open(powerFileName, O_RDONLY); | |
847 if(fd < 0) { | |
848 error("failed to open power file", powerFileName); | |
849 } | |
850 read(fd, &one, sizeof(uint32_t)); | |
851 if(one != 1) { | |
852 error("malformed power file dimensionality", powerFileName); | |
853 } | |
854 datum.power = (double *) malloc(datum.nvectors * sizeof(double)); | |
855 if(read(fd, datum.power, datum.nvectors * sizeof(double)) != (ssize_t) (datum.nvectors * sizeof(double))) { | |
856 error("malformed power file", powerFileName); | |
857 } | |
858 close(fd); | |
859 } | |
860 if(usingTimes) { | |
861 datum.times = (double *) malloc(2 * datum.nvectors * sizeof(double)); | |
862 insertTimeStamps(datum.nvectors, timesFile, datum.times); | |
863 } | |
864 } | |
865 | |
866 qspec.qid.datum = &datum; | |
867 qspec.qid.sequence_length = sequenceLength; | |
868 qspec.qid.flags = 0; | |
869 qspec.qid.flags |= usingQueryPoint ? 0 : ADB_QID_FLAG_EXHAUSTIVE; | |
870 qspec.qid.flags |= lsh_exact ? 0 : ADB_QID_FLAG_ALLOW_FALSE_POSITIVES; | |
871 qspec.qid.sequence_start = queryPoint; | |
872 | |
873 switch(queryType) { | |
874 case O2_POINT_QUERY: | |
875 qspec.qid.sequence_length = 1; | |
876 qspec.params.accumulation = ADB_ACCUMULATION_DB; | |
877 qspec.params.distance = ADB_DISTANCE_DOT_PRODUCT; | |
878 qspec.params.npoints = pointNN; | |
879 qspec.params.ntracks = 0; | |
880 reporter = new pointQueryReporter< std::greater < NNresult > >(pointNN); | |
881 break; | |
882 case O2_TRACK_QUERY: | |
883 qspec.qid.sequence_length = 1; | |
884 qspec.params.accumulation = ADB_ACCUMULATION_PER_TRACK; | |
885 qspec.params.distance = ADB_DISTANCE_DOT_PRODUCT; | |
886 qspec.params.npoints = pointNN; | |
887 qspec.params.ntracks = trackNN; | |
888 reporter = new trackAveragingReporter< std::greater< NNresult > >(pointNN, trackNN, nfiles); | |
889 break; | |
890 case O2_SEQUENCE_QUERY: | |
891 case O2_N_SEQUENCE_QUERY: | |
892 qspec.params.accumulation = ADB_ACCUMULATION_PER_TRACK; | |
893 qspec.params.distance = no_unit_norming ? ADB_DISTANCE_EUCLIDEAN : ADB_DISTANCE_EUCLIDEAN_NORMED; | |
894 qspec.params.npoints = pointNN; | |
895 qspec.params.ntracks = trackNN; | |
896 switch(queryType) { | |
897 case O2_SEQUENCE_QUERY: | |
898 if(!(qspec.refine.flags & ADB_REFINE_RADIUS)) { | |
899 reporter = new trackAveragingReporter< std::less< NNresult > >(pointNN, trackNN, nfiles); | |
900 } else { | |
901 reporter = new trackSequenceQueryRadReporter(trackNN, nfiles); | |
902 } | |
903 break; | |
904 case O2_N_SEQUENCE_QUERY: | |
905 if(!(qspec.refine.flags & ADB_REFINE_RADIUS)) { | |
906 reporter = new trackSequenceQueryNNReporter< std::less < NNresult > >(pointNN, trackNN, nfiles); | |
907 } else { | |
908 reporter = new trackSequenceQueryRadNNReporter(pointNN, trackNN, nfiles); | |
909 } | |
910 break; | |
911 } | |
912 break; | |
913 case O2_ONE_TO_ONE_N_SEQUENCE_QUERY: | |
914 qspec.params.accumulation = ADB_ACCUMULATION_ONE_TO_ONE; | |
915 qspec.params.distance = no_unit_norming ? ADB_DISTANCE_EUCLIDEAN : ADB_DISTANCE_EUCLIDEAN_NORMED; | |
916 qspec.params.npoints = 0; | |
917 qspec.params.ntracks = 0; | |
918 if(!(qspec.refine.flags & ADB_REFINE_RADIUS)) { | |
919 error("query-type not yet supported"); | |
920 } else { | |
921 reporter = new trackSequenceQueryRadNNReporterOneToOne(pointNN,trackNN, dbH->numFiles); | |
922 } | |
923 break; | |
924 default: | |
925 error("unrecognized queryType"); | |
926 } | |
927 | |
928 adb_query_results_t *rs = audiodb_query_spec(adb, &qspec); | |
929 | |
930 // FIXME: free bits of datum if !query_from_key | |
931 | |
932 if(rs == NULL) { | |
933 error("audiodb_query_spec failed"); | |
934 } | |
935 | |
936 for(unsigned int k = 0; k < rs->nresults; k++) { | |
937 adb_result_t r = rs->results[k]; | |
938 reporter->add_point(audiodb_key_index(adb, r.key), r.qpos, r.ipos, r.dist); | |
939 } | |
940 audiodb_query_free_results(adb, &qspec, rs); | |
941 | |
942 reporter->report(adb, adbQueryResponse); | |
894 } | 943 } |
895 | 944 |
896 // This entry point is visited once per instance | 945 // This entry point is visited once per instance |
897 // so it is a good place to set any global state variables | 946 // so it is a good place to set any global state variables |
898 int main(const int argc, const char* argv[]){ | 947 int main(const int argc, const char* argv[]){ |
899 SERVER_LSH_INDEX_SINGLETON = 0; // Initialize global variables | |
900 SERVER_ADB_ROOT = 0; // Server-side database root prefix | 948 SERVER_ADB_ROOT = 0; // Server-side database root prefix |
901 SERVER_ADB_FEATURE_ROOT = 0; // Server-side features root prefix | 949 SERVER_ADB_FEATURE_ROOT = 0; // Server-side features root prefix |
902 audioDB(argc, argv); | 950 audioDB(argc, argv); |
903 } | 951 } |
904 | |
905 | |
906 extern "C" { | |
907 | |
908 /* for API questions contact | |
909 * Christophe Rhodes c.rhodes@gold.ac.uk | |
910 * Ian Knopke mas01ik@gold.ac.uk, ian.knopke@gmail.com */ | |
911 | |
912 #include "audioDB_API.h" | |
913 | |
914 adb_ptr audiodb_create(const char *path, unsigned datasize, unsigned ntracks, unsigned datadim) { | |
915 const char *argv[12]; | |
916 int argvctr=0; | |
917 char tempstr1[200]; | |
918 char tempstr2[200]; | |
919 char tempstr3[200]; | |
920 int apierror=0; | |
921 | |
922 | |
923 argv[argvctr++] = "audioDB"; | |
924 argv[argvctr++] = "--NEW"; | |
925 argv[argvctr++] = "-d"; | |
926 argv[argvctr++] = path; | |
927 | |
928 if (datasize >0){ | |
929 argv[argvctr++]="--datasize"; | |
930 snprintf(tempstr1,sizeof(tempstr1),"%u",datasize); | |
931 argv[argvctr++]=tempstr1; | |
932 } | |
933 | |
934 if (ntracks >0){ | |
935 argv[argvctr++]="--ntracks"; | |
936 snprintf(tempstr2,sizeof(tempstr2),"%u",ntracks); | |
937 argv[argvctr++]=tempstr2; | |
938 } | |
939 | |
940 if (datadim > 0){ | |
941 argv[argvctr++]="--datadim"; | |
942 snprintf(tempstr3,sizeof(tempstr3),"%u",datadim); | |
943 argv[argvctr++]=tempstr3; | |
944 } | |
945 | |
946 argv[argvctr]='\0'; | |
947 | |
948 audioDB::audioDB(argvctr, argv, &apierror); | |
949 | |
950 if (!apierror){ | |
951 return audiodb_open(path); | |
952 } | |
953 | |
954 /* database exists, so fail and pass NULL */ | |
955 return NULL; | |
956 } | |
957 | |
958 | |
959 | |
960 int audiodb_insert(adb_ptr mydb, adb_insert_ptr ins) { | |
961 const char *argv[15]; | |
962 int argvctr=0; | |
963 int apierror=0; | |
964 | |
965 argv[argvctr++]="audioDB"; | |
966 argv[argvctr++]="-I"; | |
967 argv[argvctr++]="-d"; | |
968 argv[argvctr++]=mydb->dbname; | |
969 argv[argvctr++]="-f"; | |
970 argv[argvctr++]=ins->features; | |
971 | |
972 if (ins->times){ | |
973 argv[argvctr++]="--times"; | |
974 argv[argvctr++]=ins->times; | |
975 } | |
976 | |
977 if (ins->power){ | |
978 argv[argvctr++]="-w"; | |
979 argv[argvctr++]=ins->power; | |
980 } | |
981 | |
982 if (ins->key){ | |
983 argv[argvctr++]="--key"; | |
984 argv[argvctr++]=ins->key; | |
985 } | |
986 argv[argvctr]='\0'; | |
987 | |
988 audioDB::audioDB(argvctr,argv,&apierror); | |
989 return apierror; | |
990 } | |
991 | |
992 | |
993 int audiodb_batchinsert(adb_ptr mydb, adb_insert_ptr ins, unsigned int size) { | |
994 | |
995 const char *argv[22]; | |
996 int argvctr=0; | |
997 unsigned int i=0; | |
998 char tempfeaturename[]="tempfeatureXXXXXX"; | |
999 char temppowername[]="temppowerXXXXXX"; | |
1000 char tempkeyname[]="tempkeyXXXXXX"; | |
1001 char temptimesname[]="temptimesXXXXXX"; | |
1002 int tempfeaturefd = -1; | |
1003 int temppowerfd = -1; | |
1004 int tempkeyfd = -1; | |
1005 int temptimesfd = -1; | |
1006 | |
1007 int flags[4]={0}; | |
1008 int apierror=0; | |
1009 | |
1010 /* So the final API should take an array of structs. However, the current | |
1011 * version requires four separate text files. So temporarily, we need to | |
1012 * unpack the struct array, make four separate text files, and then reinsert | |
1013 * them into the command-line call. This should change as soon as possible */ | |
1014 | |
1015 | |
1016 argv[argvctr++]="audioDB"; | |
1017 argv[argvctr++]="-B"; | |
1018 argv[argvctr++]="-d"; | |
1019 argv[argvctr++]=mydb->dbname; | |
1020 | |
1021 | |
1022 /* assume struct is well formed for all entries */ | |
1023 if (ins[0].features){ flags[0]++;} else { | |
1024 /* short circuit the case where there are no features in the structs */ | |
1025 return -1; | |
1026 } ; | |
1027 if (ins[0].power){ flags[1]++;}; | |
1028 if (ins[0].key){ flags[2]++;}; | |
1029 if (ins[0].times){ flags[3]++;}; | |
1030 | |
1031 | |
1032 /* make four temp files */ | |
1033 if ((tempfeaturefd = mkstemp(tempfeaturename)) == -1) | |
1034 goto error; | |
1035 if ((temppowerfd = mkstemp(temppowername)) == -1) | |
1036 goto error; | |
1037 if ((tempkeyfd=mkstemp(tempkeyname)) == -1) | |
1038 goto error; | |
1039 if ((temptimesfd=mkstemp(temptimesname)) == -1) | |
1040 goto error; | |
1041 | |
1042 /* Ok, so we should have a working set of files to write to */ | |
1043 /* I'm going to assume that the same format is kept for all structs in the array */ | |
1044 /* That is, each struct should be correctly formed, and contain at least a features file, because I'm just going to pass the terms along to the text files */ | |
1045 for (i = 0; i < size; i++) { | |
1046 if (write(tempfeaturefd,ins[i].features,strlen(ins[i].features)) != (ssize_t) strlen(ins[i].features)) | |
1047 goto error; | |
1048 if (write(tempfeaturefd,"\n",1) != 1) | |
1049 goto error; | |
1050 | |
1051 if (flags[1]) { | |
1052 if (write(temppowerfd,ins[i].power,strlen(ins[i].power)) != (ssize_t) strlen(ins[i].power)) | |
1053 goto error; | |
1054 if (write(temppowerfd,"\n",1) != 1) | |
1055 goto error; | |
1056 } | |
1057 if (flags[2]) { | |
1058 if (write(tempkeyfd,ins[i].key,strlen(ins[i].key)) != (ssize_t) strlen(ins[i].key)) | |
1059 goto error; | |
1060 if (write(tempkeyfd,"\n",1) != 1) | |
1061 goto error; | |
1062 } | |
1063 if (flags[3]) { | |
1064 if (write(temptimesfd,ins[i].times,strlen(ins[i].times)) != (ssize_t) strlen(ins[i].times)) | |
1065 goto error; | |
1066 if (write(temptimesfd,"\n",1) != 1) | |
1067 goto error; | |
1068 } | |
1069 } | |
1070 | |
1071 argv[argvctr++]="-F"; | |
1072 argv[argvctr++]=tempfeaturename; | |
1073 close(tempfeaturefd); | |
1074 close(temppowerfd); | |
1075 close(tempkeyfd); | |
1076 close(temptimesfd); | |
1077 | |
1078 if (flags[1]){ | |
1079 argv[argvctr++]="--powerList"; | |
1080 argv[argvctr++]=temppowername; | |
1081 } | |
1082 | |
1083 if (flags[2]){ | |
1084 argv[argvctr++]="--keyList"; | |
1085 argv[argvctr++]=tempkeyname; | |
1086 } | |
1087 | |
1088 if (flags[3]){ | |
1089 argv[argvctr++]="--timesList"; | |
1090 argv[argvctr++]=temptimesname; | |
1091 } | |
1092 | |
1093 argv[argvctr]='\0'; | |
1094 | |
1095 audioDB::audioDB(argvctr,argv,&apierror); | |
1096 | |
1097 remove(tempfeaturename); | |
1098 remove(temppowername); | |
1099 remove(tempkeyname); | |
1100 remove(temptimesname); | |
1101 | |
1102 | |
1103 return apierror; | |
1104 | |
1105 error: | |
1106 if(tempfeaturefd != -1) { | |
1107 close(tempfeaturefd); | |
1108 remove(tempfeaturename); | |
1109 } | |
1110 if(temppowerfd != -1) { | |
1111 close(temppowerfd); | |
1112 remove(temppowername); | |
1113 } | |
1114 if(tempkeyfd != -1) { | |
1115 close(tempkeyfd); | |
1116 remove(tempkeyname); | |
1117 } | |
1118 if(temptimesfd != -1) { | |
1119 close(temptimesfd); | |
1120 remove(temptimesname); | |
1121 } | |
1122 return -1; | |
1123 } | |
1124 | |
1125 | |
1126 int audiodb_query(adb_ptr mydb, adb_query_ptr adbq, adb_queryresult_ptr adbqr){ | |
1127 | |
1128 const char *argv[32]; | |
1129 int argvctr=0; | |
1130 char tempstr1[200]; | |
1131 char tempstr2[200]; | |
1132 char tempstr3[200]; | |
1133 int apierror=0; | |
1134 | |
1135 adb__queryResponse adbQueryResponse; | |
1136 | |
1137 /* TODO: may need error checking here */ | |
1138 /* currently counting on audioDB binary to fail for me */ | |
1139 argv[argvctr++]="audioDB"; | |
1140 | |
1141 if(adbq->querytype){ | |
1142 argv[argvctr++]="-Q"; | |
1143 argv[argvctr++]=adbq->querytype; | |
1144 } | |
1145 | |
1146 if(mydb->dbname){ | |
1147 argv[argvctr++]="-d"; | |
1148 argv[argvctr++]=mydb->dbname; | |
1149 } | |
1150 | |
1151 if (adbq->feature){ | |
1152 argv[argvctr++]="-f"; | |
1153 argv[argvctr++]=adbq->feature; | |
1154 } | |
1155 | |
1156 if (adbq->key){ | |
1157 argv[argvctr++]="-k"; | |
1158 argv[argvctr++]=adbq->key; | |
1159 } | |
1160 | |
1161 if (adbq->power){ | |
1162 argv[argvctr++]="-w"; | |
1163 argv[argvctr++]=adbq->power; | |
1164 } | |
1165 | |
1166 if (adbq->qpoint){ | |
1167 argv[argvctr++]="-p"; | |
1168 argv[argvctr++]=adbq->qpoint; | |
1169 } | |
1170 if (adbq->numpoints){ | |
1171 argv[argvctr++]="-n"; | |
1172 argv[argvctr++]=adbq->numpoints; | |
1173 } | |
1174 if (adbq->radius){ | |
1175 argv[argvctr++]="-R"; | |
1176 argv[argvctr++]=adbq->radius; | |
1177 } | |
1178 if(adbq->resultlength){ | |
1179 argv[argvctr++]="-r"; | |
1180 argv[argvctr++]=adbq->resultlength; | |
1181 } | |
1182 if(adbq->sequencelength){ | |
1183 argv[argvctr++]="-l"; | |
1184 argv[argvctr++]=adbq->sequencelength; | |
1185 } | |
1186 if(adbq->sequencehop){ | |
1187 argv[argvctr++]="-h"; | |
1188 argv[argvctr++]=adbq->sequencehop; | |
1189 } | |
1190 | |
1191 if (adbq->absolute_threshold){ | |
1192 argv[argvctr++]="--absolute-threshold"; | |
1193 snprintf(tempstr1,sizeof(tempstr1),"%f",adbq->absolute_threshold); | |
1194 argv[argvctr++]=tempstr1; | |
1195 } | |
1196 | |
1197 if (adbq->relative_threshold){ | |
1198 argv[argvctr++]="--relative-threshold"; | |
1199 snprintf(tempstr2,sizeof(tempstr2),"%f",adbq->relative_threshold); | |
1200 argv[argvctr++]=tempstr2; | |
1201 } | |
1202 | |
1203 if (adbq->exhaustive){ | |
1204 argv[argvctr++]="--exhaustive"; | |
1205 } | |
1206 | |
1207 if (adbq->expandfactor){ | |
1208 argv[argvctr++]="--expandfactor"; | |
1209 snprintf(tempstr3,sizeof(tempstr3),"%f",adbq->expandfactor); | |
1210 argv[argvctr++]=tempstr3; | |
1211 } | |
1212 | |
1213 if (adbq->rotate){ | |
1214 argv[argvctr++]="--rotate"; | |
1215 } | |
1216 | |
1217 if (adbq->keylist){ | |
1218 argv[argvctr++]="-K"; | |
1219 argv[argvctr++]=adbq->keylist; | |
1220 } | |
1221 argv[argvctr]='\0'; | |
1222 | |
1223 /* debugging */ | |
1224 | |
1225 audioDB::audioDB(argvctr,argv, &adbQueryResponse, &apierror); | |
1226 | |
1227 //copy data over here from adbQueryResponse to adbqr | |
1228 adbqr->sizeRlist=adbQueryResponse.result.__sizeRlist; | |
1229 adbqr->sizeDist=adbQueryResponse.result.__sizeDist; | |
1230 adbqr->sizeQpos=adbQueryResponse.result.__sizeQpos; | |
1231 adbqr->sizeSpos=adbQueryResponse.result.__sizeSpos; | |
1232 adbqr->Rlist=adbQueryResponse.result.Rlist; | |
1233 adbqr->Dist=adbQueryResponse.result.Dist; | |
1234 adbqr->Qpos=adbQueryResponse.result.Qpos; | |
1235 adbqr->Spos=adbQueryResponse.result.Spos; | |
1236 | |
1237 return apierror; | |
1238 } | |
1239 | |
1240 ///* status command */ | |
1241 int audiodb_status(adb_ptr mydb, adb_status_ptr status){ | |
1242 | |
1243 cppstatus sss; | |
1244 int apierror=0; | |
1245 | |
1246 const char *argv[5]; | |
1247 | |
1248 apierror=0; | |
1249 argv[0]="audioDB"; | |
1250 argv[1]="--STATUS"; | |
1251 argv[2]="-d"; | |
1252 argv[3]=mydb->dbname; | |
1253 argv[4]='\0'; | |
1254 | |
1255 audioDB::audioDB(4,argv,&sss ,&apierror); | |
1256 | |
1257 status->numFiles=sss.numFiles; | |
1258 status->dim=sss.dim; | |
1259 status->length=sss.length; | |
1260 status->dudCount=sss.dudCount; | |
1261 status->nullCount=sss.nullCount; | |
1262 status->flags=sss.flags; | |
1263 | |
1264 return apierror; | |
1265 } | |
1266 | |
1267 int audiodb_dump(adb_ptr mydb){ | |
1268 return audiodb_dump_withdir(mydb,"audioDB.dump"); | |
1269 } | |
1270 | |
1271 int audiodb_dump_withdir(adb_ptr mydb, const char *outputdir){ | |
1272 | |
1273 const char *argv[7]; | |
1274 int argvctr=0; | |
1275 int apierror=0; | |
1276 | |
1277 argv[argvctr++]="audioDB"; | |
1278 argv[argvctr++]="--DUMP"; | |
1279 argv[argvctr++]="-d"; | |
1280 argv[argvctr++]=mydb->dbname; | |
1281 argv[argvctr++]="--output"; | |
1282 argv[argvctr++]=(char *)outputdir; | |
1283 argv[argvctr]='\0'; | |
1284 | |
1285 audioDB::audioDB(6,argv,&apierror); | |
1286 | |
1287 return apierror; | |
1288 } | |
1289 | |
1290 int audiodb_l2norm(adb_ptr mydb){ | |
1291 | |
1292 const char *argv[5]; | |
1293 int apierror=0; | |
1294 | |
1295 argv[0]="audioDB"; | |
1296 argv[1]="--L2NORM"; | |
1297 argv[2]="-d"; | |
1298 argv[3]=mydb->dbname; | |
1299 argv[4]='\0'; | |
1300 | |
1301 audioDB::audioDB(4,argv,&apierror); | |
1302 return apierror; | |
1303 } | |
1304 | |
1305 int audiodb_power(adb_ptr mydb){ | |
1306 | |
1307 const char *argv[5]; | |
1308 int apierror=0; | |
1309 | |
1310 argv[0]="audioDB"; | |
1311 argv[1]="--POWER"; | |
1312 argv[2]="-d"; | |
1313 argv[3]=mydb->dbname; | |
1314 argv[4]='\0'; | |
1315 | |
1316 audioDB::audioDB(4,argv,&apierror); | |
1317 return apierror; | |
1318 } | |
1319 | |
1320 adb_ptr audiodb_open(const char *path){ | |
1321 | |
1322 adb_ptr mydbp; | |
1323 adbstatus mystatus; | |
1324 | |
1325 /* if db exists */ | |
1326 | |
1327 if (open(path, O_EXCL) != -1){ | |
1328 | |
1329 mydbp=(adb_ptr)malloc(sizeof(adb)); | |
1330 mydbp->dbname=(char *)malloc(1+strlen(path)); | |
1331 | |
1332 strcpy(mydbp->dbname,path); | |
1333 | |
1334 audiodb_status(mydbp, &mystatus); | |
1335 mydbp->ntracks=mystatus.numFiles; | |
1336 mydbp->datadim=mystatus.dim; | |
1337 | |
1338 return mydbp; | |
1339 } | |
1340 | |
1341 return NULL; | |
1342 }; | |
1343 | |
1344 | |
1345 | |
1346 void audiodb_close(adb_ptr db){ | |
1347 | |
1348 free(db->dbname); | |
1349 free(db); | |
1350 | |
1351 } | |
1352 | |
1353 | |
1354 } | |
1355 |