annotate audioDB.cpp @ 174:2826339b4e92 no-big-mmap

mmap() the various tables separately on init. Continue mmap()ing the whole database as well, as there is still use of it elsewhere in one or two naughty places. mmap()ing individual tables means aligning to page boundaries; make it so.
author mas01cr
date Wed, 14 Nov 2007 16:32:18 +0000
parents 42585bd03636
children 38bdbab60972
rev   line source
mas01cr@0 1 #include "audioDB.h"
mas01cr@0 2
mas01cr@105 3 #if defined(O2_DEBUG)
mas01cr@104 4 void sigterm_action(int signal, siginfo_t *info, void *context) {
mas01cr@104 5 exit(128+signal);
mas01cr@104 6 }
mas01cr@104 7
mas01cr@104 8 void sighup_action(int signal, siginfo_t *info, void *context) {
mas01cr@104 9 // FIXME: reread any configuration files
mas01cr@104 10 }
mas01cr@105 11 #endif
mas01cr@0 12
mas01cr@32 13 void audioDB::error(const char* a, const char* b, const char *sysFunc) {
mas01cr@77 14 if(isServer) {
mas01cr@81 15 /* FIXME: I think this is leaky -- we never delete err. actually
mas01cr@81 16 deleting it is tricky, though; it gets placed into some
mas01cr@81 17 soap-internal struct with uncertain extent... -- CSR,
mas01cr@81 18 2007-10-01 */
mas01cr@77 19 char *err = new char[256]; /* FIXME: overflows */
mas01cr@77 20 snprintf(err, 255, "%s: %s\n%s", a, b, sysFunc ? strerror(errno) : "");
mas01cr@77 21 /* FIXME: actually we could usefully do with a properly structured
mas01cr@77 22 type, so that we can throw separate faultstring and details.
mas01cr@77 23 -- CSR, 2007-10-01 */
mas01cr@77 24 throw(err);
mas01cr@77 25 } else {
mas01cr@77 26 cerr << a << ": " << b << endl;
mas01cr@77 27 if (sysFunc) {
mas01cr@77 28 perror(sysFunc);
mas01cr@77 29 }
mas01cr@77 30 exit(1);
mas01cr@32 31 }
mas01cr@0 32 }
mas01cr@0 33
mas01cr@76 34 audioDB::audioDB(const unsigned argc, char* const argv[]): O2_AUDIODB_INITIALIZERS
mas01cr@76 35 {
mas01cr@0 36 if(processArgs(argc, argv)<0){
mas01cr@0 37 printf("No command found.\n");
mas01cr@0 38 cmdline_parser_print_version ();
mas01cr@0 39 if (strlen(gengetopt_args_info_purpose) > 0)
mas01cr@0 40 printf("%s\n", gengetopt_args_info_purpose);
mas01cr@0 41 printf("%s\n", gengetopt_args_info_usage);
mas01cr@0 42 printf("%s\n", gengetopt_args_info_help[1]);
mas01cr@0 43 printf("%s\n", gengetopt_args_info_help[2]);
mas01cr@0 44 printf("%s\n", gengetopt_args_info_help[0]);
mas01cr@151 45 error("No command found");
mas01cr@0 46 }
mas01cr@77 47
mas01cr@0 48 if(O2_ACTION(COM_SERVER))
mas01cr@0 49 startServer();
mas01cr@0 50
mas01cr@0 51 else if(O2_ACTION(COM_CREATE))
mas01cr@0 52 create(dbName);
mas01cr@0 53
mas01cr@0 54 else if(O2_ACTION(COM_INSERT))
mas01cr@0 55 insert(dbName, inFile);
mas01cr@0 56
mas01cr@0 57 else if(O2_ACTION(COM_BATCHINSERT))
mas01cr@0 58 batchinsert(dbName, inFile);
mas01cr@0 59
mas01cr@0 60 else if(O2_ACTION(COM_QUERY))
mas01cr@0 61 if(isClient)
mas01cr@0 62 ws_query(dbName, inFile, (char*)hostport);
mas01cr@0 63 else
mas01cr@76 64 query(dbName, inFile);
mas01cr@0 65
mas01cr@0 66 else if(O2_ACTION(COM_STATUS))
mas01cr@0 67 if(isClient)
mas01cr@0 68 ws_status(dbName,(char*)hostport);
mas01cr@0 69 else
mas01cr@0 70 status(dbName);
mas01cr@0 71
mas01cr@0 72 else if(O2_ACTION(COM_L2NORM))
mas01cr@0 73 l2norm(dbName);
mas01cr@0 74
mas01cr@0 75 else if(O2_ACTION(COM_DUMP))
mas01cr@0 76 dump(dbName);
mas01cr@0 77
mas01cr@0 78 else
mas01cr@0 79 error("Unrecognized command",command);
mas01cr@0 80 }
mas01cr@0 81
mas01cr@133 82 audioDB::audioDB(const unsigned argc, char* const argv[], adb__queryResponse *adbQueryResponse): O2_AUDIODB_INITIALIZERS
mas01cr@76 83 {
mas01cr@97 84 try {
mas01cr@151 85 isServer = 1; // FIXME: Hack
mas01cr@97 86 processArgs(argc, argv);
mas01cr@97 87 assert(O2_ACTION(COM_QUERY));
mas01cr@133 88 query(dbName, inFile, adbQueryResponse);
mas01cr@97 89 } catch(char *err) {
mas01cr@97 90 cleanup();
mas01cr@97 91 throw(err);
mas01cr@97 92 }
mas01cr@76 93 }
mas01cr@76 94
mas01cr@133 95 audioDB::audioDB(const unsigned argc, char* const argv[], adb__statusResponse *adbStatusResponse): O2_AUDIODB_INITIALIZERS
mas01cr@76 96 {
mas01cr@97 97 try {
mas01cr@151 98 isServer = 1; // FIXME: Hack
mas01cr@97 99 processArgs(argc, argv);
mas01cr@97 100 assert(O2_ACTION(COM_STATUS));
mas01cr@133 101 status(dbName, adbStatusResponse);
mas01cr@97 102 } catch(char *err) {
mas01cr@97 103 cleanup();
mas01cr@97 104 throw(err);
mas01cr@97 105 }
mas01cr@76 106 }
mas01cr@76 107
mas01cr@97 108 void audioDB::cleanup() {
mas01cr@122 109 cmdline_parser_free(&args_info);
mas01cr@0 110 if(indata)
mas01cr@0 111 munmap(indata,statbuf.st_size);
mas01cr@0 112 if(db)
mas01cr@128 113 munmap(db,dbH->dbSize);
mas01cr@0 114 if(dbfid>0)
mas01cr@0 115 close(dbfid);
mas01cr@0 116 if(infid>0)
mas01cr@0 117 close(infid);
mas01cr@0 118 if(dbH)
mas01cr@0 119 delete dbH;
mas01cr@0 120 }
mas01cr@0 121
mas01cr@97 122 audioDB::~audioDB(){
mas01cr@97 123 cleanup();
mas01cr@97 124 }
mas01cr@97 125
mas01cr@0 126 int audioDB::processArgs(const unsigned argc, char* const argv[]){
mas01cr@0 127
mas01cr@0 128 if(argc<2){
mas01cr@0 129 cmdline_parser_print_version ();
mas01cr@0 130 if (strlen(gengetopt_args_info_purpose) > 0)
mas01cr@0 131 printf("%s\n", gengetopt_args_info_purpose);
mas01cr@0 132 printf("%s\n", gengetopt_args_info_usage);
mas01cr@0 133 printf("%s\n", gengetopt_args_info_help[1]);
mas01cr@0 134 printf("%s\n", gengetopt_args_info_help[2]);
mas01cr@0 135 printf("%s\n", gengetopt_args_info_help[0]);
mas01cr@0 136 exit(0);
mas01cr@0 137 }
mas01cr@0 138
mas01cr@0 139 if (cmdline_parser (argc, argv, &args_info) != 0)
mas01cr@151 140 error("Error parsing command line");
mas01cr@0 141
mas01cr@0 142 if(args_info.help_given){
mas01cr@0 143 cmdline_parser_print_help();
mas01cr@0 144 exit(0);
mas01cr@0 145 }
mas01cr@0 146
mas01cr@0 147 if(args_info.verbosity_given){
mas01cr@0 148 verbosity=args_info.verbosity_arg;
mas01cr@0 149 if(verbosity<0 || verbosity>10){
mas01cr@0 150 cerr << "Warning: verbosity out of range, setting to 1" << endl;
mas01cr@0 151 verbosity=1;
mas01cr@0 152 }
mas01cr@0 153 }
mas01cr@0 154
mas01cr@129 155 if(args_info.size_given) {
mas01cr@140 156 if (args_info.size_arg < 50 || args_info.size_arg > 4000) {
mas01cr@129 157 error("Size out of range", "");
mas01cr@129 158 }
mas01cr@129 159 size = args_info.size_arg * 1000000;
mas01cr@129 160 }
mas01cr@129 161
mas01mc@17 162 if(args_info.radius_given){
mas01mc@17 163 radius=args_info.radius_arg;
mas01mc@17 164 if(radius<=0 || radius>1000000000){
mas01cr@77 165 error("radius out of range");
mas01mc@17 166 }
mas01mc@17 167 else
mas01cr@60 168 if(verbosity>3) {
mas01mc@17 169 cerr << "Setting radius to " << radius << endl;
mas01cr@60 170 }
mas01mc@17 171 }
mas01mc@17 172
mas01cr@0 173 if(args_info.SERVER_given){
mas01cr@0 174 command=COM_SERVER;
mas01cr@0 175 port=args_info.SERVER_arg;
mas01cr@0 176 if(port<100 || port > 100000)
mas01cr@0 177 error("port out of range");
mas01cr@151 178 isServer = 1;
mas01cr@105 179 #if defined(O2_DEBUG)
mas01cr@104 180 struct sigaction sa;
mas01cr@104 181 sa.sa_sigaction = sigterm_action;
mas01cr@104 182 sa.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;
mas01cr@104 183 sigaction(SIGTERM, &sa, NULL);
mas01cr@104 184 sa.sa_sigaction = sighup_action;
mas01cr@104 185 sa.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;
mas01cr@104 186 sigaction(SIGHUP, &sa, NULL);
mas01cr@105 187 #endif
mas01cr@0 188 return 0;
mas01cr@0 189 }
mas01cr@0 190
mas01cr@0 191 // No return on client command, find database command
mas01cr@105 192 if(args_info.client_given){
mas01cr@105 193 command=COM_CLIENT;
mas01cr@105 194 hostport=args_info.client_arg;
mas01cr@105 195 isClient=1;
mas01cr@105 196 }
mas01cr@0 197
mas01cr@105 198 if(args_info.NEW_given){
mas01cr@105 199 command=COM_CREATE;
mas01cr@105 200 dbName=args_info.database_arg;
mas01cr@105 201 return 0;
mas01cr@105 202 }
mas01cr@0 203
mas01cr@105 204 if(args_info.STATUS_given){
mas01cr@105 205 command=COM_STATUS;
mas01cr@105 206 dbName=args_info.database_arg;
mas01cr@105 207 return 0;
mas01cr@105 208 }
mas01cr@0 209
mas01cr@105 210 if(args_info.DUMP_given){
mas01cr@105 211 command=COM_DUMP;
mas01cr@105 212 dbName=args_info.database_arg;
mas01cr@131 213 output = args_info.output_arg;
mas01cr@105 214 return 0;
mas01cr@105 215 }
mas01cr@0 216
mas01cr@105 217 if(args_info.L2NORM_given){
mas01cr@105 218 command=COM_L2NORM;
mas01cr@105 219 dbName=args_info.database_arg;
mas01cr@105 220 return 0;
mas01cr@105 221 }
mas01cr@0 222
mas01cr@105 223 if(args_info.INSERT_given){
mas01cr@105 224 command=COM_INSERT;
mas01cr@105 225 dbName=args_info.database_arg;
mas01cr@105 226 inFile=args_info.features_arg;
mas01cr@105 227 if(args_info.key_given)
mas01cr@105 228 key=args_info.key_arg;
mas01cr@105 229 if(args_info.times_given){
mas01cr@105 230 timesFileName=args_info.times_arg;
mas01cr@105 231 if(strlen(timesFileName)>0){
mas01cr@105 232 if(!(timesFile = new ifstream(timesFileName,ios::in)))
mas01cr@105 233 error("Could not open times file for reading", timesFileName);
mas01cr@105 234 usingTimes=1;
mas01cr@105 235 }
mas01cr@105 236 }
mas01cr@105 237 return 0;
mas01cr@105 238 }
mas01cr@105 239
mas01cr@105 240 if(args_info.BATCHINSERT_given){
mas01cr@105 241 command=COM_BATCHINSERT;
mas01cr@105 242 dbName=args_info.database_arg;
mas01cr@105 243 inFile=args_info.featureList_arg;
mas01cr@105 244 if(args_info.keyList_given)
mas01cr@105 245 key=args_info.keyList_arg; // INCONSISTENT NO CHECK
mas01cr@0 246
mas01cr@105 247 /* TO DO: REPLACE WITH
mas01cr@0 248 if(args_info.keyList_given){
mas01mc@18 249 trackFileName=args_info.keyList_arg;
mas01mc@18 250 if(strlen(trackFileName)>0 && !(trackFile = new ifstream(trackFileName,ios::in)))
mas01mc@18 251 error("Could not open keyList file for reading",trackFileName);
mas01cr@0 252 }
mas01cr@0 253 AND UPDATE BATCHINSERT()
mas01cr@105 254 */
mas01cr@105 255
mas01cr@105 256 if(args_info.timesList_given){
mas01cr@105 257 timesFileName=args_info.timesList_arg;
mas01cr@105 258 if(strlen(timesFileName)>0){
mas01cr@105 259 if(!(timesFile = new ifstream(timesFileName,ios::in)))
mas01cr@105 260 error("Could not open timesList file for reading", timesFileName);
mas01cr@105 261 usingTimes=1;
mas01cr@105 262 }
mas01cr@105 263 }
mas01cr@105 264 return 0;
mas01cr@105 265 }
mas01cr@105 266
mas01cr@105 267 // Query command and arguments
mas01cr@105 268 if(args_info.QUERY_given){
mas01cr@105 269 command=COM_QUERY;
mas01cr@105 270 dbName=args_info.database_arg;
mas01cr@105 271 inFile=args_info.features_arg;
mas01cr@105 272
mas01cr@105 273 if(args_info.keyList_given){
mas01cr@105 274 trackFileName=args_info.keyList_arg;
mas01cr@105 275 if(strlen(trackFileName)>0 && !(trackFile = new ifstream(trackFileName,ios::in)))
mas01cr@105 276 error("Could not open keyList file for reading",trackFileName);
mas01cr@105 277 }
mas01cr@105 278
mas01cr@105 279 if(args_info.times_given){
mas01cr@105 280 timesFileName=args_info.times_arg;
mas01cr@105 281 if(strlen(timesFileName)>0){
mas01cr@105 282 if(!(timesFile = new ifstream(timesFileName,ios::in)))
mas01cr@105 283 error("Could not open times file for reading", timesFileName);
mas01cr@105 284 usingTimes=1;
mas01cr@105 285 }
mas01cr@105 286 }
mas01cr@105 287
mas01cr@105 288 // query type
mas01cr@105 289 if(strncmp(args_info.QUERY_arg, "track", MAXSTR)==0)
mas01cr@105 290 queryType=O2_TRACK_QUERY;
mas01cr@105 291 else if(strncmp(args_info.QUERY_arg, "point", MAXSTR)==0)
mas01cr@105 292 queryType=O2_POINT_QUERY;
mas01cr@105 293 else if(strncmp(args_info.QUERY_arg, "sequence", MAXSTR)==0)
mas01cr@105 294 queryType=O2_SEQUENCE_QUERY;
mas01cr@105 295 else
mas01cr@105 296 error("unsupported query type",args_info.QUERY_arg);
mas01cr@105 297
mas01cr@105 298 if(!args_info.exhaustive_flag){
mas01cr@105 299 queryPoint = args_info.qpoint_arg;
mas01cr@105 300 usingQueryPoint=1;
mas01cr@105 301 if(queryPoint<0 || queryPoint >10000)
mas01cr@105 302 error("queryPoint out of range: 0 <= queryPoint <= 10000");
mas01cr@105 303 }
mas01cr@105 304
mas01cr@105 305 pointNN = args_info.pointnn_arg;
mas01cr@105 306 if(pointNN < 1 || pointNN > 1000) {
mas01cr@105 307 error("pointNN out of range: 1 <= pointNN <= 1000");
mas01cr@105 308 }
mas01cr@105 309 trackNN = args_info.resultlength_arg;
mas01cr@105 310 if(trackNN < 1 || trackNN > 1000) {
mas01cr@105 311 error("resultlength out of range: 1 <= resultlength <= 1000");
mas01cr@105 312 }
mas01cr@105 313 sequenceLength = args_info.sequencelength_arg;
mas01cr@105 314 if(sequenceLength < 1 || sequenceLength > 1000) {
mas01cr@105 315 error("seqlen out of range: 1 <= seqlen <= 1000");
mas01cr@105 316 }
mas01cr@105 317 sequenceHop = args_info.sequencehop_arg;
mas01cr@105 318 if(sequenceHop < 1 || sequenceHop > 1000) {
mas01cr@105 319 error("seqhop out of range: 1 <= seqhop <= 1000");
mas01cr@105 320 }
mas01cr@105 321 return 0;
mas01cr@105 322 }
mas01cr@105 323 return -1; // no command found
mas01cr@0 324 }
mas01cr@0 325
mas01cr@30 326 void audioDB::get_lock(int fd, bool exclusive) {
mas01cr@30 327 struct flock lock;
mas01cr@30 328 int status;
mas01cr@30 329
mas01cr@30 330 lock.l_type = exclusive ? F_WRLCK : F_RDLCK;
mas01cr@30 331 lock.l_whence = SEEK_SET;
mas01cr@30 332 lock.l_start = 0;
mas01cr@30 333 lock.l_len = 0; /* "the whole file" */
mas01cr@30 334
mas01cr@30 335 retry:
mas01cr@30 336 do {
mas01cr@30 337 status = fcntl(fd, F_SETLKW, &lock);
mas01cr@30 338 } while (status != 0 && errno == EINTR);
mas01cr@30 339
mas01cr@30 340 if (status) {
mas01cr@30 341 if (errno == EAGAIN) {
mas01cr@30 342 sleep(1);
mas01cr@30 343 goto retry;
mas01cr@30 344 } else {
mas01cr@32 345 error("fcntl lock error", "", "fcntl");
mas01cr@30 346 }
mas01cr@30 347 }
mas01cr@30 348 }
mas01cr@30 349
mas01cr@30 350 void audioDB::release_lock(int fd) {
mas01cr@30 351 struct flock lock;
mas01cr@30 352 int status;
mas01cr@30 353
mas01cr@30 354 lock.l_type = F_UNLCK;
mas01cr@30 355 lock.l_whence = SEEK_SET;
mas01cr@30 356 lock.l_start = 0;
mas01cr@30 357 lock.l_len = 0;
mas01cr@30 358
mas01cr@30 359 status = fcntl(fd, F_SETLKW, &lock);
mas01cr@30 360
mas01cr@30 361 if (status)
mas01cr@32 362 error("fcntl unlock error", "", "fcntl");
mas01cr@30 363 }
mas01cr@30 364
mas01cr@120 365 /* Make a new database.
mas01cr@120 366
mas01cr@120 367 The database consists of:
mas01cr@120 368
mas01cr@120 369 * a header (see dbTableHeader struct definition);
mas01cr@120 370 * keyTable: list of keys of tracks;
mas01cr@120 371 * trackTable: Maps implicit feature index to a feature vector
mas01cr@120 372 matrix (sizes of tracks)
mas01cr@120 373 * featureTable: Lots of doubles;
mas01cr@120 374 * timesTable: time points for each feature vector;
mas01cr@120 375 * l2normTable: squared l2norms for each feature vector.
mas01cr@120 376 */
mas01cr@0 377 void audioDB::create(const char* dbName){
mas01cr@31 378 if ((dbfid = open (dbName, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0)
mas01cr@32 379 error("Can't create database file", dbName, "open");
mas01cr@30 380 get_lock(dbfid, 1);
mas01cr@0 381
mas01cr@60 382 if(verbosity) {
mas01cr@0 383 cerr << "header size:" << O2_HEADERSIZE << endl;
mas01cr@60 384 }
mas01cr@0 385
mas01cr@0 386 dbH = new dbTableHeaderT();
mas01cr@0 387 assert(dbH);
mas01cr@0 388
mas01cr@140 389 unsigned int maxfiles = (unsigned int) rint((double) O2_MAXFILES * (double) size / (double) O2_DEFAULTDBSIZE);
mas01cr@140 390
mas01cr@0 391 // Initialize header
mas01cr@108 392 dbH->magic = O2_MAGIC;
mas01cr@108 393 dbH->version = O2_FORMAT_VERSION;
mas01cr@108 394 dbH->numFiles = 0;
mas01cr@108 395 dbH->dim = 0;
mas01cr@108 396 dbH->flags = 0;
mas01cr@108 397 dbH->length = 0;
mas01cr@174 398 dbH->fileTableOffset = ALIGN_PAGE_UP(O2_HEADERSIZE, 8);
mas01cr@174 399 dbH->trackTableOffset = ALIGN_PAGE_UP(dbH->fileTableOffset + O2_FILETABLESIZE*maxfiles, 8);
mas01cr@174 400 dbH->dataOffset = ALIGN_PAGE_UP(dbH->trackTableOffset + O2_TRACKTABLESIZE*maxfiles, 8);
mas01cr@174 401 dbH->l2normTableOffset = ALIGN_PAGE_DOWN(size - maxfiles*O2_MEANNUMVECTORS*sizeof(double), 8);
mas01cr@174 402 dbH->timesTableOffset = ALIGN_PAGE_DOWN(dbH->l2normTableOffset - maxfiles*O2_MEANNUMVECTORS*sizeof(double), 8);
mas01cr@129 403 dbH->dbSize = size;
mas01cr@0 404
mas01cr@173 405 write(dbfid, dbH, O2_HEADERSIZE);
mas01cr@173 406
mas01cr@173 407 // go to the location corresponding to the last byte
mas01cr@173 408 if (lseek (dbfid, size - 1, SEEK_SET) == -1)
mas01cr@173 409 error("lseek error in db file", "", "lseek");
mas01cr@173 410
mas01cr@173 411 // write a dummy byte at the last location
mas01cr@173 412 if (write (dbfid, "", 1) != 1)
mas01cr@173 413 error("write error", "", "write");
mas01cr@173 414
mas01cr@60 415 if(verbosity) {
mas01cr@0 416 cerr << COM_CREATE << " " << dbName << endl;
mas01cr@60 417 }
mas01cr@0 418 }
mas01cr@0 419
mas01cr@0 420 void audioDB::drop(){
mas01cr@108 421 // FIXME: drop something? Should we even allow this?
mas01cr@0 422 }
mas01cr@0 423
mas01cr@120 424 void audioDB::initDBHeader(const char* dbName, bool forWrite) {
mas01cr@106 425 if ((dbfid = open(dbName, forWrite ? O_RDWR : O_RDONLY)) < 0) {
mas01cr@32 426 error("Can't open database file", dbName, "open");
mas01cr@106 427 }
mas01cr@120 428
mas01cr@30 429 get_lock(dbfid, forWrite);
mas01cr@0 430 // Get the database header info
mas01cr@0 431 dbH = new dbTableHeaderT();
mas01cr@0 432 assert(dbH);
mas01cr@0 433
mas01cr@106 434 if(read(dbfid, (char *) dbH, O2_HEADERSIZE) != O2_HEADERSIZE) {
mas01cr@106 435 error("error reading db header", dbName, "read");
mas01cr@106 436 }
mas01cr@0 437
mas01cr@108 438 if(dbH->magic == O2_OLD_MAGIC) {
mas01cr@108 439 // FIXME: if anyone ever complains, write the program to convert
mas01cr@108 440 // from the old audioDB format to the new...
mas01cr@108 441 error("database file has old O2 header", dbName);
mas01cr@108 442 }
mas01cr@0 443
mas01cr@106 444 if(dbH->magic != O2_MAGIC) {
mas01cr@106 445 cerr << "expected: " << O2_MAGIC << ", got: " << dbH->magic << endl;
mas01cr@108 446 error("database file has incorrect header", dbName);
mas01cr@108 447 }
mas01cr@108 448
mas01cr@108 449 if(dbH->version != O2_FORMAT_VERSION) {
mas01cr@108 450 error("database file has incorect version", dbName);
mas01cr@0 451 }
mas01cr@0 452
mas01cr@128 453 // FIXME: when changing file format version, remove this workaround.
mas01cr@128 454 if(dbH->dbSize == 0) {
mas01cr@128 455 dbH->dbSize = O2_DEFAULTDBSIZE;
mas01cr@128 456 }
mas01cr@128 457
mas01cr@120 458 // mmap the database file
mas01cr@128 459 if ((db = (char*) mmap(0, dbH->dbSize, PROT_READ | (forWrite ? PROT_WRITE : 0),
mas01cr@120 460 MAP_SHARED, dbfid, 0)) == (caddr_t) -1)
mas01cr@120 461 error("mmap error for initting tables of database", "", "mmap");
mas01cr@120 462
mas01cr@120 463 // Make some handy tables with correct types
mas01cr@174 464 #define CHECKED_MMAP(type, var, start, end) \
mas01cr@174 465 { void *tmp = mmap(0, ((end) - (start)), (PROT_READ | (forWrite ? PROT_WRITE : 0)), MAP_SHARED, dbfid, (start)); \
mas01cr@174 466 if(tmp == (void *) -1) { \
mas01cr@174 467 error("mmap error for db table", #var, "mmap"); \
mas01cr@174 468 } \
mas01cr@174 469 var = (type) tmp; \
mas01cr@174 470 }
mas01cr@174 471
mas01cr@174 472 CHECKED_MMAP(char *, fileTable, dbH->fileTableOffset, dbH->trackTableOffset);
mas01cr@174 473 CHECKED_MMAP(unsigned *, trackTable, dbH->trackTableOffset, dbH->dataOffset);
mas01cr@174 474 CHECKED_MMAP(double *, dataBuf, dbH->dataOffset, dbH->timesTableOffset);
mas01cr@174 475 CHECKED_MMAP(double *, timesTable, dbH->timesTableOffset, dbH->l2normTableOffset);
mas01cr@174 476 CHECKED_MMAP(double *, l2normTable, dbH->l2normTableOffset, dbH->dbSize);
mas01cr@120 477 }
mas01cr@120 478
mas01cr@169 479 void audioDB::initInputFile (const char *inFile) {
mas01cr@169 480 if (inFile) {
mas01cr@169 481 if ((infid = open(inFile, O_RDONLY)) < 0) {
mas01cr@169 482 error("can't open input file for reading", inFile, "open");
mas01cr@169 483 }
mas01cr@169 484
mas01cr@169 485 if (fstat(infid, &statbuf) < 0) {
mas01cr@169 486 error("fstat error finding size of input", inFile, "fstat");
mas01cr@169 487 }
mas01cr@169 488
mas01cr@169 489 if(dbH->dim == 0 && dbH->length == 0) { // empty database
mas01cr@169 490 // initialize with input dimensionality
mas01cr@169 491 if(read(infid, &dbH->dim, sizeof(unsigned)) != sizeof(unsigned)) {
mas01cr@169 492 error("short read of input file", inFile);
mas01cr@169 493 }
mas01cr@169 494 if(dbH->dim == 0) {
mas01cr@169 495 error("dimensionality of zero in input file", inFile);
mas01cr@169 496 }
mas01cr@169 497 } else {
mas01cr@169 498 unsigned test;
mas01cr@169 499 if(read(infid, &test, sizeof(unsigned)) != sizeof(unsigned)) {
mas01cr@169 500 error("short read of input file", inFile);
mas01cr@169 501 }
mas01cr@169 502 if(dbH->dim == 0) {
mas01cr@169 503 error("dimensionality of zero in input file", inFile);
mas01cr@169 504 }
mas01cr@169 505 if(dbH->dim != test) {
mas01cr@169 506 cerr << "error: expected dimension: " << dbH->dim << ", got : " << test <<endl;
mas01cr@169 507 error("feature dimensions do not match database table dimensions", inFile);
mas01cr@169 508 }
mas01cr@169 509 }
mas01cr@169 510
mas01cr@169 511 if ((indata = (char *) mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, infid, 0)) == (caddr_t) -1) {
mas01cr@169 512 error("mmap error for input", inFile, "mmap");
mas01cr@169 513 }
mas01cr@169 514 }
mas01cr@169 515 }
mas01cr@169 516
mas01cr@120 517 void audioDB::initTables(const char* dbName, bool forWrite, const char* inFile = 0) {
mas01cr@120 518
mas01cr@120 519 initDBHeader(dbName, forWrite);
mas01cr@169 520 initInputFile(inFile);
mas01cr@0 521 }
mas01cr@0 522
mas01cr@0 523 void audioDB::insert(const char* dbName, const char* inFile){
mas01cr@0 524
mas01cr@27 525 initTables(dbName, 1, inFile);
mas01cr@0 526
mas01cr@0 527 if(!usingTimes && (dbH->flags & O2_FLAG_TIMES))
mas01cr@0 528 error("Must use timestamps with timestamped database","use --times");
mas01cr@0 529
mas01cr@0 530 // Check that there is room for at least 1 more file
mas01cr@0 531 if((char*)timesTable<((char*)dataBuf+dbH->length+statbuf.st_size-sizeof(int)))
mas01cr@169 532 error("Insert failed: no more room in database", inFile);
mas01cr@0 533
mas01cr@0 534 if(!key)
mas01cr@0 535 key=inFile;
mas01cr@0 536 // Linear scan of filenames check for pre-existing feature
mas01cr@0 537 unsigned alreadyInserted=0;
mas01cr@0 538 for(unsigned k=0; k<dbH->numFiles; k++)
mas01cr@0 539 if(strncmp(fileTable + k*O2_FILETABLESIZE, key, strlen(key))==0){
mas01cr@0 540 alreadyInserted=1;
mas01cr@0 541 break;
mas01cr@0 542 }
mas01cr@0 543
mas01cr@0 544 if(alreadyInserted){
mas01cr@60 545 if(verbosity) {
mas01cr@0 546 cerr << "Warning: key already exists in database, ignoring: " <<inFile << endl;
mas01cr@60 547 }
mas01cr@0 548 return;
mas01cr@0 549 }
mas01cr@0 550
mas01mc@18 551 // Make a track index table of features to file indexes
mas01cr@0 552 unsigned numVectors = (statbuf.st_size-sizeof(int))/(sizeof(double)*dbH->dim);
mas01cr@0 553 if(!numVectors){
mas01cr@60 554 if(verbosity) {
mas01cr@0 555 cerr << "Warning: ignoring zero-length feature vector file:" << key << endl;
mas01cr@60 556 }
mas01cr@0 557 // CLEAN UP
mas01cr@0 558 munmap(indata,statbuf.st_size);
mas01cr@128 559 munmap(db,dbH->dbSize);
mas01cr@0 560 close(infid);
mas01cr@0 561 return;
mas01cr@0 562 }
mas01cr@0 563
mas01cr@0 564 strncpy(fileTable + dbH->numFiles*O2_FILETABLESIZE, key, strlen(key));
mas01cr@0 565
mas01cr@0 566 unsigned insertoffset = dbH->length;// Store current state
mas01cr@0 567
mas01cr@0 568 // Check times status and insert times from file
mas01cr@0 569 unsigned timesoffset=insertoffset/(dbH->dim*sizeof(double));
mas01cr@0 570 double* timesdata=timesTable+timesoffset;
mas01cr@0 571 assert(timesdata+numVectors<l2normTable);
mas01cr@0 572 insertTimeStamps(numVectors, timesFile, timesdata);
mas01cr@0 573
mas01cr@0 574 // Increment file count
mas01cr@0 575 dbH->numFiles++;
mas01cr@0 576
mas01cr@0 577 // Update Header information
mas01cr@0 578 dbH->length+=(statbuf.st_size-sizeof(int));
mas01cr@0 579
mas01cr@0 580 // Copy the header back to the database
mas01cr@0 581 memcpy (db, dbH, sizeof(dbTableHeaderT));
mas01cr@0 582
mas01mc@18 583 // Update track to file index map
mas01mc@18 584 //memcpy (db+trackTableOffset+(dbH->numFiles-1)*sizeof(unsigned), &numVectors, sizeof(unsigned));
mas01mc@18 585 memcpy (trackTable+dbH->numFiles-1, &numVectors, sizeof(unsigned));
mas01cr@0 586
mas01cr@0 587 // Update the feature database
mas01cr@108 588 memcpy (db+dbH->dataOffset+insertoffset, indata+sizeof(int), statbuf.st_size-sizeof(int));
mas01cr@0 589
mas01cr@0 590 // Norm the vectors on input if the database is already L2 normed
mas01cr@0 591 if(dbH->flags & O2_FLAG_L2NORM)
mas01cr@108 592 unitNormAndInsertL2((double*)(db+dbH->dataOffset+insertoffset), dbH->dim, numVectors, 1); // append
mas01cr@0 593
mas01cr@0 594 // Report status
mas01cr@0 595 status(dbName);
mas01cr@60 596 if(verbosity) {
mas01cr@0 597 cerr << COM_INSERT << " " << dbName << " " << numVectors << " vectors "
mas01cr@0 598 << (statbuf.st_size-sizeof(int)) << " bytes." << endl;
mas01cr@60 599 }
mas01cr@0 600
mas01cr@0 601 // CLEAN UP
mas01cr@0 602 munmap(indata,statbuf.st_size);
mas01cr@0 603 close(infid);
mas01cr@0 604 }
mas01cr@0 605
mas01cr@0 606 void audioDB::insertTimeStamps(unsigned numVectors, ifstream* timesFile, double* timesdata){
mas01cr@0 607 unsigned numtimes=0;
mas01cr@0 608 if(usingTimes){
mas01cr@0 609 if(!(dbH->flags & O2_FLAG_TIMES) && !dbH->numFiles)
mas01cr@0 610 dbH->flags=dbH->flags|O2_FLAG_TIMES;
mas01cr@0 611 else if(!(dbH->flags&O2_FLAG_TIMES)){
mas01cr@0 612 cerr << "Warning: timestamp file used with non time-stamped database: ignoring timestamps" << endl;
mas01cr@0 613 usingTimes=0;
mas01cr@0 614 }
mas01cr@0 615
mas01cr@0 616 if(!timesFile->is_open()){
mas01cr@0 617 if(dbH->flags & O2_FLAG_TIMES){
mas01cr@0 618 munmap(indata,statbuf.st_size);
mas01cr@128 619 munmap(db,dbH->dbSize);
mas01cr@0 620 error("problem opening times file on timestamped database",timesFileName);
mas01cr@0 621 }
mas01cr@0 622 else{
mas01cr@0 623 cerr << "Warning: problem opening times file. But non-timestamped database, so ignoring times file." << endl;
mas01cr@0 624 usingTimes=0;
mas01cr@0 625 }
mas01cr@0 626 }
mas01cr@0 627
mas01cr@0 628 // Process time file
mas01cr@0 629 if(usingTimes){
mas01cr@0 630 do{
mas01cr@0 631 *timesFile>>*timesdata++;
mas01cr@0 632 if(timesFile->eof())
mas01cr@0 633 break;
mas01cr@0 634 numtimes++;
mas01cr@0 635 }while(!timesFile->eof() && numtimes<numVectors);
mas01cr@0 636 if(!timesFile->eof()){
mas01cr@0 637 double dummy;
mas01cr@0 638 do{
mas01cr@0 639 *timesFile>>dummy;
mas01cr@0 640 if(timesFile->eof())
mas01cr@0 641 break;
mas01cr@0 642 numtimes++;
mas01cr@0 643 }while(!timesFile->eof());
mas01cr@0 644 }
mas01cr@0 645 if(numtimes<numVectors || numtimes>numVectors+2){
mas01cr@0 646 munmap(indata,statbuf.st_size);
mas01cr@128 647 munmap(db,dbH->dbSize);
mas01cr@0 648 close(infid);
mas01cr@0 649 cerr << "expected " << numVectors << " found " << numtimes << endl;
mas01cr@0 650 error("Times file is incorrect length for features file",inFile);
mas01cr@0 651 }
mas01cr@60 652 if(verbosity>2) {
mas01cr@0 653 cerr << "numtimes: " << numtimes << endl;
mas01cr@60 654 }
mas01cr@0 655 }
mas01cr@0 656 }
mas01cr@0 657 }
mas01cr@0 658
mas01cr@120 659 void audioDB::batchinsert(const char* dbName, const char* inFile) {
mas01cr@0 660
mas01cr@120 661 initDBHeader(dbName, true);
mas01cr@0 662
mas01cr@0 663 if(!key)
mas01cr@0 664 key=inFile;
mas01cr@0 665 ifstream *filesIn = 0;
mas01cr@0 666 ifstream *keysIn = 0;
mas01cr@0 667 ifstream* thisTimesFile = 0;
mas01cr@0 668
mas01cr@0 669 if(!(filesIn = new ifstream(inFile)))
mas01cr@0 670 error("Could not open batch in file", inFile);
mas01cr@0 671 if(key && key!=inFile)
mas01cr@0 672 if(!(keysIn = new ifstream(key)))
mas01cr@0 673 error("Could not open batch key file",key);
mas01cr@0 674
mas01cr@0 675 if(!usingTimes && (dbH->flags & O2_FLAG_TIMES))
mas01cr@0 676 error("Must use timestamps with timestamped database","use --times");
mas01cr@0 677
mas01cr@0 678 unsigned totalVectors=0;
mas01cr@0 679 char *thisKey = new char[MAXSTR];
mas01cr@0 680 char *thisFile = new char[MAXSTR];
mas01cr@0 681 char *thisTimesFileName = new char[MAXSTR];
mas01cr@120 682
mas01cr@0 683 do{
mas01cr@0 684 filesIn->getline(thisFile,MAXSTR);
mas01cr@0 685 if(key && key!=inFile)
mas01cr@0 686 keysIn->getline(thisKey,MAXSTR);
mas01cr@0 687 else
mas01cr@0 688 thisKey = thisFile;
mas01cr@0 689 if(usingTimes)
mas01cr@0 690 timesFile->getline(thisTimesFileName,MAXSTR);
mas01cr@0 691
mas01cr@0 692 if(filesIn->eof())
mas01cr@0 693 break;
mas01cr@0 694
mas01cr@169 695 initInputFile(thisFile);
mas01cr@0 696
mas01cr@0 697 // Check that there is room for at least 1 more file
mas01cr@0 698 if((char*)timesTable<((char*)dataBuf+(dbH->length+statbuf.st_size-sizeof(int))))
mas01cr@169 699 error("batchinsert failed: no more room in database", thisFile);
mas01cr@0 700
mas01cr@0 701 // Linear scan of filenames check for pre-existing feature
mas01cr@0 702 unsigned alreadyInserted=0;
mas01cr@0 703
mas01cr@0 704 for(unsigned k=0; k<dbH->numFiles; k++)
mas01cr@0 705 if(strncmp(fileTable + k*O2_FILETABLESIZE, thisKey, strlen(thisKey))==0){
mas01cr@0 706 alreadyInserted=1;
mas01cr@0 707 break;
mas01cr@0 708 }
mas01cr@0 709
mas01cr@0 710 if(alreadyInserted){
mas01cr@60 711 if(verbosity) {
mas01cr@0 712 cerr << "Warning: key already exists in database:" << thisKey << endl;
mas01cr@60 713 }
mas01cr@0 714 }
mas01cr@0 715 else{
mas01cr@0 716
mas01mc@18 717 // Make a track index table of features to file indexes
mas01cr@0 718 unsigned numVectors = (statbuf.st_size-sizeof(int))/(sizeof(double)*dbH->dim);
mas01cr@0 719 if(!numVectors){
mas01cr@60 720 if(verbosity) {
mas01cr@0 721 cerr << "Warning: ignoring zero-length feature vector file:" << thisKey << endl;
mas01cr@60 722 }
mas01cr@0 723 }
mas01cr@0 724 else{
mas01cr@0 725 if(usingTimes){
mas01cr@0 726 if(timesFile->eof())
mas01cr@0 727 error("not enough timestamp files in timesList");
mas01cr@0 728 thisTimesFile=new ifstream(thisTimesFileName,ios::in);
mas01cr@0 729 if(!thisTimesFile->is_open())
mas01cr@0 730 error("Cannot open timestamp file",thisTimesFileName);
mas01cr@0 731 unsigned insertoffset=dbH->length;
mas01cr@0 732 unsigned timesoffset=insertoffset/(dbH->dim*sizeof(double));
mas01cr@0 733 double* timesdata=timesTable+timesoffset;
mas01cr@0 734 assert(timesdata+numVectors<l2normTable);
mas01cr@0 735 insertTimeStamps(numVectors,thisTimesFile,timesdata);
mas01cr@0 736 if(thisTimesFile)
mas01cr@0 737 delete thisTimesFile;
mas01cr@0 738 }
mas01cr@0 739
mas01cr@0 740 strncpy(fileTable + dbH->numFiles*O2_FILETABLESIZE, thisKey, strlen(thisKey));
mas01cr@0 741
mas01cr@0 742 unsigned insertoffset = dbH->length;// Store current state
mas01cr@0 743
mas01cr@0 744 // Increment file count
mas01cr@0 745 dbH->numFiles++;
mas01cr@0 746
mas01cr@0 747 // Update Header information
mas01cr@0 748 dbH->length+=(statbuf.st_size-sizeof(int));
mas01cr@0 749 // Copy the header back to the database
mas01cr@0 750 memcpy (db, dbH, sizeof(dbTableHeaderT));
mas01cr@0 751
mas01mc@18 752 // Update track to file index map
mas01mc@18 753 //memcpy (db+trackTableOffset+(dbH->numFiles-1)*sizeof(unsigned), &numVectors, sizeof(unsigned));
mas01mc@18 754 memcpy (trackTable+dbH->numFiles-1, &numVectors, sizeof(unsigned));
mas01cr@0 755
mas01cr@0 756 // Update the feature database
mas01cr@108 757 memcpy (db+dbH->dataOffset+insertoffset, indata+sizeof(int), statbuf.st_size-sizeof(int));
mas01cr@0 758
mas01cr@0 759 // Norm the vectors on input if the database is already L2 normed
mas01cr@0 760 if(dbH->flags & O2_FLAG_L2NORM)
mas01cr@108 761 unitNormAndInsertL2((double*)(db+dbH->dataOffset+insertoffset), dbH->dim, numVectors, 1); // append
mas01cr@0 762
mas01cr@0 763 totalVectors+=numVectors;
mas01cr@0 764 }
mas01cr@0 765 }
mas01cr@0 766 // CLEAN UP
mas01cr@0 767 munmap(indata,statbuf.st_size);
mas01cr@0 768 close(infid);
mas01cr@0 769 }while(!filesIn->eof());
mas01mc@12 770
mas01cr@60 771 if(verbosity) {
mas01cr@0 772 cerr << COM_BATCHINSERT << " " << dbName << " " << totalVectors << " vectors "
mas01cr@0 773 << totalVectors*dbH->dim*sizeof(double) << " bytes." << endl;
mas01cr@60 774 }
mas01cr@0 775
mas01cr@0 776 // Report status
mas01cr@0 777 status(dbName);
mas01cr@0 778 }
mas01cr@0 779
mas01cr@76 780 // FIXME: this can't propagate the sequence length argument (used for
mas01cr@76 781 // dudCount). See adb__status() definition for the other half of
mas01cr@76 782 // this. -- CSR, 2007-10-01
mas01cr@0 783 void audioDB::ws_status(const char*dbName, char* hostport){
mas01cr@0 784 struct soap soap;
mas01cr@133 785 adb__statusResponse adbStatusResponse;
mas01cr@0 786
mas01cr@0 787 // Query an existing adb database
mas01cr@0 788 soap_init(&soap);
mas01cr@133 789 if(soap_call_adb__status(&soap,hostport,NULL,(char*)dbName,adbStatusResponse)==SOAP_OK) {
mas01cr@133 790 cout << "numFiles = " << adbStatusResponse.result.numFiles << endl;
mas01cr@133 791 cout << "dim = " << adbStatusResponse.result.dim << endl;
mas01cr@133 792 cout << "length = " << adbStatusResponse.result.length << endl;
mas01cr@133 793 cout << "dudCount = " << adbStatusResponse.result.dudCount << endl;
mas01cr@133 794 cout << "nullCount = " << adbStatusResponse.result.nullCount << endl;
mas01cr@133 795 cout << "flags = " << adbStatusResponse.result.flags << endl;
mas01cr@76 796 } else {
mas01cr@0 797 soap_print_fault(&soap,stderr);
mas01cr@76 798 }
mas01cr@0 799
mas01cr@0 800 soap_destroy(&soap);
mas01cr@0 801 soap_end(&soap);
mas01cr@0 802 soap_done(&soap);
mas01cr@0 803 }
mas01cr@0 804
mas01mc@18 805 void audioDB::ws_query(const char*dbName, const char *trackKey, const char* hostport){
mas01cr@0 806 struct soap soap;
mas01cr@133 807 adb__queryResponse adbQueryResponse;
mas01cr@0 808
mas01cr@0 809 soap_init(&soap);
mas01cr@0 810 if(soap_call_adb__query(&soap,hostport,NULL,
mas01mc@18 811 (char*)dbName,(char*)trackKey,(char*)trackFileName,(char*)timesFileName,
mas01cr@133 812 queryType, queryPoint, pointNN, trackNN, sequenceLength, adbQueryResponse)==SOAP_OK){
mas01cr@133 813 //std::cerr << "result list length:" << adbQueryResponse.result.__sizeRlist << std::endl;
mas01cr@133 814 for(int i=0; i<adbQueryResponse.result.__sizeRlist; i++)
mas01cr@133 815 std::cout << adbQueryResponse.result.Rlist[i] << " " << adbQueryResponse.result.Dist[i]
mas01cr@133 816 << " " << adbQueryResponse.result.Qpos[i] << " " << adbQueryResponse.result.Spos[i] << std::endl;
mas01cr@0 817 }
mas01cr@0 818 else
mas01cr@0 819 soap_print_fault(&soap,stderr);
mas01cr@0 820
mas01cr@0 821 soap_destroy(&soap);
mas01cr@0 822 soap_end(&soap);
mas01cr@0 823 soap_done(&soap);
mas01cr@0 824
mas01cr@0 825 }
mas01cr@0 826
mas01cr@0 827
mas01cr@133 828 void audioDB::status(const char* dbName, adb__statusResponse *adbStatusResponse){
mas01cr@0 829 if(!dbH)
mas01cr@27 830 initTables(dbName, 0, 0);
mas01cr@0 831
mas01cr@0 832 unsigned dudCount=0;
mas01cr@0 833 unsigned nullCount=0;
mas01cr@0 834 for(unsigned k=0; k<dbH->numFiles; k++){
mas01mc@18 835 if(trackTable[k]<sequenceLength){
mas01cr@0 836 dudCount++;
mas01mc@18 837 if(!trackTable[k])
mas01cr@76 838 nullCount++;
mas01cr@0 839 }
mas01cr@0 840 }
mas01cr@76 841
mas01cr@133 842 if(adbStatusResponse == 0) {
mas01cr@76 843
mas01cr@76 844 // Update Header information
mas01cr@76 845 cout << "num files:" << dbH->numFiles << endl;
mas01cr@76 846 cout << "data dim:" << dbH->dim <<endl;
mas01cr@76 847 if(dbH->dim>0){
mas01cr@76 848 cout << "total vectors:" << dbH->length/(sizeof(double)*dbH->dim)<<endl;
mas01cr@108 849 cout << "vectors available:" << (dbH->timesTableOffset-(dbH->dataOffset+dbH->length))/(sizeof(double)*dbH->dim) << endl;
mas01cr@76 850 }
mas01cr@108 851 cout << "total bytes:" << dbH->length << " (" << (100.0*dbH->length)/(dbH->timesTableOffset-dbH->dataOffset) << "%)" << endl;
mas01cr@108 852 cout << "bytes available:" << dbH->timesTableOffset-(dbH->dataOffset+dbH->length) << " (" <<
mas01cr@108 853 (100.0*(dbH->timesTableOffset-(dbH->dataOffset+dbH->length)))/(dbH->timesTableOffset-dbH->dataOffset) << "%)" << endl;
mas01cr@76 854 cout << "flags:" << dbH->flags << endl;
mas01cr@76 855
mas01cr@76 856 cout << "null count: " << nullCount << " small sequence count " << dudCount-nullCount << endl;
mas01cr@76 857 } else {
mas01cr@133 858 adbStatusResponse->result.numFiles = dbH->numFiles;
mas01cr@133 859 adbStatusResponse->result.dim = dbH->dim;
mas01cr@133 860 adbStatusResponse->result.length = dbH->length;
mas01cr@133 861 adbStatusResponse->result.dudCount = dudCount;
mas01cr@133 862 adbStatusResponse->result.nullCount = nullCount;
mas01cr@133 863 adbStatusResponse->result.flags = dbH->flags;
mas01cr@76 864 }
mas01cr@0 865 }
mas01cr@0 866
mas01cr@0 867 void audioDB::dump(const char* dbName){
mas01cr@131 868 if(!dbH) {
mas01cr@27 869 initTables(dbName, 0, 0);
mas01mc@17 870 }
mas01cr@0 871
mas01cr@131 872 if((mkdir(output, S_IRWXU|S_IRWXG|S_IRWXO)) < 0) {
mas01cr@131 873 error("error making output directory", output, "mkdir");
mas01cr@131 874 }
mas01cr@131 875
mas01cr@131 876 char *cwd = new char[PATH_MAX];
mas01cr@131 877
mas01cr@131 878 if ((getcwd(cwd, PATH_MAX)) == 0) {
mas01cr@131 879 error("error getting working directory", "", "getcwd");
mas01cr@131 880 }
mas01cr@131 881
mas01cr@131 882 if((chdir(output)) < 0) {
mas01cr@131 883 error("error changing working directory", output, "chdir");
mas01cr@131 884 }
mas01cr@131 885
mas01cr@131 886 int fLfd, tLfd = 0, kLfd;
mas01cr@131 887 FILE *fLFile, *tLFile = 0, *kLFile;
mas01cr@131 888
mas01cr@131 889 if ((fLfd = open("featureList.txt", O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) {
mas01cr@131 890 error("error creating featureList file", "featureList.txt", "open");
mas01cr@131 891 }
mas01cr@131 892 int times = dbH->flags & O2_FLAG_TIMES;
mas01cr@131 893 if (times) {
mas01cr@131 894 if ((tLfd = open("timesList.txt", O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) {
mas01cr@131 895 error("error creating timesList file", "timesList.txt", "open");
mas01cr@131 896 }
mas01cr@131 897 }
mas01cr@131 898 if ((kLfd = open("keyList.txt", O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) {
mas01cr@131 899 error("error creating keyList file", "keyList.txt", "open");
mas01cr@131 900 }
mas01cr@131 901
mas01cr@131 902 /* can these fail? I sincerely hope not. */
mas01cr@131 903 fLFile = fdopen(fLfd, "w");
mas01cr@131 904 if (times) {
mas01cr@131 905 tLFile = fdopen(tLfd, "w");
mas01cr@131 906 }
mas01cr@131 907 kLFile = fdopen(kLfd, "w");
mas01cr@131 908
mas01cr@131 909 char *fName = new char[256];
mas01cr@131 910 int ffd;
mas01cr@131 911 FILE *tFile;
mas01cr@131 912 unsigned pos = 0;
mas01cr@131 913 for(unsigned k = 0; k < dbH->numFiles; k++) {
mas01cr@131 914 fprintf(kLFile, "%s\n", fileTable + k*O2_FILETABLESIZE);
mas01cr@131 915 snprintf(fName, 256, "%05d.features", k);
mas01cr@131 916 if ((ffd = open(fName, O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) {
mas01cr@131 917 error("error creating feature file", fName, "open");
mas01cr@131 918 }
mas01cr@131 919 if ((write(ffd, &dbH->dim, sizeof(uint32_t))) < 0) {
mas01cr@131 920 error("error writing dimensions", fName, "write");
mas01cr@131 921 }
mas01cr@131 922
mas01cr@131 923 if ((write(ffd, dataBuf + pos * dbH->dim, trackTable[k] * dbH->dim * sizeof(double))) < 0) {
mas01cr@131 924 error("error writing data", fName, "write");
mas01cr@131 925 }
mas01cr@131 926 fprintf(fLFile, "%s\n", fName);
mas01cr@131 927 close(ffd);
mas01cr@131 928
mas01cr@131 929 if(times) {
mas01cr@131 930 snprintf(fName, 256, "%05d.times", k);
mas01cr@131 931 tFile = fopen(fName, "w");
mas01cr@131 932 for(unsigned i = 0; i < trackTable[k]; i++) {
mas01cr@131 933 // KLUDGE: specifying 16 digits of precision after the decimal
mas01cr@131 934 // point is (but check this!) sufficient to uniquely identify
mas01cr@131 935 // doubles; however, that will cause ugliness, as that's
mas01cr@131 936 // vastly too many for most values of interest. Moving to %a
mas01cr@131 937 // here and scanf() in the timesFile reading might fix this.
mas01cr@131 938 // -- CSR, 2007-10-19
mas01cr@131 939 fprintf(tFile, "%.16e\n", *(timesTable + pos + i));
mas01cr@131 940 }
mas01cr@131 941 fprintf(tLFile, "%s\n", fName);
mas01cr@131 942 }
mas01cr@131 943
mas01cr@131 944 pos += trackTable[k];
mas01cr@131 945 cout << fileTable+k*O2_FILETABLESIZE << " " << trackTable[k] << endl;
mas01cr@131 946 }
mas01cr@131 947
mas01cr@131 948 FILE *scriptFile;
mas01cr@131 949 scriptFile = fopen("restore.sh", "w");
mas01cr@131 950 fprintf(scriptFile, "\
mas01cr@131 951 #! /bin/sh\n\
mas01cr@131 952 #\n\
mas01cr@131 953 # usage: AUDIODB=/path/to/audioDB sh ./restore.sh <newdb>\n\
mas01cr@131 954 \n\
mas01cr@131 955 if [ -z \"${AUDIODB}\" ]; then echo set AUDIODB variable; exit 1; fi\n\
mas01cr@131 956 if [ -z \"$1\" ]; then echo usage: $0 newdb; exit 1; fi\n\n\
mas01cr@131 957 \"${AUDIODB}\" -d \"$1\" -N --size=%d\n", dbH->dbSize / 1000000);
mas01cr@131 958 if(dbH->flags & O2_FLAG_L2NORM) {
mas01cr@131 959 fprintf(scriptFile, "\"${AUDIODB}\" -d \"$1\" -L\n");
mas01cr@131 960 }
mas01cr@131 961 fprintf(scriptFile, "\"${AUDIODB}\" -d \"$1\" -B -F featureList.txt -K keyList.txt");
mas01cr@131 962 if(times) {
mas01cr@131 963 fprintf(scriptFile, " -T timesList.txt");
mas01cr@131 964 }
mas01cr@131 965 fprintf(scriptFile, "\n");
mas01cr@131 966 fclose(scriptFile);
mas01cr@131 967
mas01cr@131 968 if((chdir(cwd)) < 0) {
mas01cr@131 969 error("error changing working directory", cwd, "chdir");
mas01cr@131 970 }
mas01cr@131 971
mas01cr@131 972 fclose(fLFile);
mas01cr@131 973 if(times) {
mas01cr@131 974 fclose(tLFile);
mas01cr@131 975 }
mas01cr@131 976 fclose(kLFile);
mas01cr@131 977 delete[] fName;
mas01cr@131 978
mas01cr@0 979 status(dbName);
mas01cr@0 980 }
mas01cr@0 981
mas01cr@0 982 void audioDB::l2norm(const char* dbName){
mas01cr@50 983 initTables(dbName, true, 0);
mas01cr@0 984 if(dbH->length>0){
mas01cr@0 985 unsigned numVectors = dbH->length/(sizeof(double)*dbH->dim);
mas01cr@0 986 unitNormAndInsertL2(dataBuf, dbH->dim, numVectors, 0); // No append
mas01cr@0 987 }
mas01cr@0 988 // Update database flags
mas01cr@0 989 dbH->flags = dbH->flags|O2_FLAG_L2NORM;
mas01cr@0 990 memcpy (db, dbH, O2_HEADERSIZE);
mas01cr@0 991 }
mas01cr@0 992
mas01cr@0 993
mas01cr@0 994
mas01cr@133 995 void audioDB::query(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse){
mas01cr@0 996 switch(queryType){
mas01cr@105 997 case O2_POINT_QUERY:
mas01cr@133 998 pointQuery(dbName, inFile, adbQueryResponse);
mas01cr@0 999 break;
mas01cr@105 1000 case O2_SEQUENCE_QUERY:
mas01mc@17 1001 if(radius==0)
mas01cr@133 1002 trackSequenceQueryNN(dbName, inFile, adbQueryResponse);
mas01mc@17 1003 else
mas01cr@133 1004 trackSequenceQueryRad(dbName, inFile, adbQueryResponse);
mas01cr@0 1005 break;
mas01cr@105 1006 case O2_TRACK_QUERY:
mas01cr@133 1007 trackPointQuery(dbName, inFile, adbQueryResponse);
mas01cr@0 1008 break;
mas01cr@0 1009 default:
mas01cr@0 1010 error("unrecognized queryType in query()");
mas01cr@0 1011
mas01cr@0 1012 }
mas01cr@0 1013 }
mas01cr@0 1014
mas01cr@0 1015 //return ordinal position of key in keyTable
mas01cr@0 1016 unsigned audioDB::getKeyPos(char* key){
mas01cr@0 1017 for(unsigned k=0; k<dbH->numFiles; k++)
mas01cr@0 1018 if(strncmp(fileTable + k*O2_FILETABLESIZE, key, strlen(key))==0)
mas01cr@0 1019 return k;
mas01cr@0 1020 error("Key not found",key);
mas01cr@0 1021 return O2_ERR_KEYNOTFOUND;
mas01cr@0 1022 }
mas01cr@0 1023
mas01cr@0 1024 // Basic point query engine
mas01cr@133 1025 void audioDB::pointQuery(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse){
mas01cr@0 1026
mas01cr@27 1027 initTables(dbName, 0, inFile);
mas01cr@0 1028
mas01cr@0 1029 // For each input vector, find the closest pointNN matching output vectors and report
mas01cr@0 1030 // we use stdout in this stub version
mas01cr@0 1031 unsigned numVectors = (statbuf.st_size-sizeof(int))/(sizeof(double)*dbH->dim);
mas01cr@0 1032
mas01cr@0 1033 double* query = (double*)(indata+sizeof(int));
mas01cr@0 1034 double* data = dataBuf;
mas01cr@0 1035 double* queryCopy = 0;
mas01cr@0 1036
mas01cr@0 1037 if( dbH->flags & O2_FLAG_L2NORM ){
mas01cr@0 1038 // Make a copy of the query
mas01cr@0 1039 queryCopy = new double[numVectors*dbH->dim];
mas01cr@0 1040 qNorm = new double[numVectors];
mas01cr@0 1041 assert(queryCopy&&qNorm);
mas01cr@0 1042 memcpy(queryCopy, query, numVectors*dbH->dim*sizeof(double));
mas01cr@0 1043 unitNorm(queryCopy, dbH->dim, numVectors, qNorm);
mas01cr@0 1044 query = queryCopy;
mas01cr@0 1045 }
mas01cr@0 1046
mas01cr@0 1047 // Make temporary dynamic memory for results
mas01cr@0 1048 assert(pointNN>0 && pointNN<=O2_MAXNN);
mas01cr@0 1049 double distances[pointNN];
mas01cr@0 1050 unsigned qIndexes[pointNN];
mas01cr@0 1051 unsigned sIndexes[pointNN];
mas01cr@0 1052 for(unsigned k=0; k<pointNN; k++){
mas01cr@62 1053 distances[k]=-DBL_MAX;
mas01cr@0 1054 qIndexes[k]=~0;
mas01cr@0 1055 sIndexes[k]=~0;
mas01cr@0 1056 }
mas01cr@0 1057
mas01cr@0 1058 unsigned j=numVectors;
mas01cr@0 1059 unsigned k,l,n;
mas01cr@0 1060 double thisDist;
mas01cr@0 1061
mas01cr@0 1062 unsigned totalVecs=dbH->length/(dbH->dim*sizeof(double));
mas01cr@0 1063 double meanQdur = 0;
mas01cr@0 1064 double* timesdata = 0;
mas01cr@0 1065 double* dbdurs = 0;
mas01cr@0 1066
mas01cr@0 1067 if(usingTimes && !(dbH->flags & O2_FLAG_TIMES)){
mas01cr@0 1068 cerr << "warning: ignoring query timestamps for non-timestamped database" << endl;
mas01cr@0 1069 usingTimes=0;
mas01cr@0 1070 }
mas01cr@0 1071
mas01cr@0 1072 else if(!usingTimes && (dbH->flags & O2_FLAG_TIMES))
mas01cr@0 1073 cerr << "warning: no timestamps given for query. Ignoring database timestamps." << endl;
mas01cr@0 1074
mas01cr@0 1075 else if(usingTimes && (dbH->flags & O2_FLAG_TIMES)){
mas01cr@0 1076 timesdata = new double[numVectors];
mas01cr@0 1077 insertTimeStamps(numVectors, timesFile, timesdata);
mas01cr@0 1078 // Calculate durations of points
mas01cr@0 1079 for(k=0; k<numVectors-1; k++){
mas01cr@0 1080 timesdata[k]=timesdata[k+1]-timesdata[k];
mas01cr@0 1081 meanQdur+=timesdata[k];
mas01cr@0 1082 }
mas01cr@0 1083 meanQdur/=k;
mas01cr@0 1084 // Individual exhaustive timepoint durations
mas01cr@0 1085 dbdurs = new double[totalVecs];
mas01cr@0 1086 for(k=0; k<totalVecs-1; k++)
mas01cr@0 1087 dbdurs[k]=timesTable[k+1]-timesTable[k];
mas01cr@0 1088 j--; // decrement vector counter by one
mas01cr@0 1089 }
mas01cr@0 1090
mas01cr@0 1091 if(usingQueryPoint)
mas01cr@0 1092 if(queryPoint>numVectors-1)
mas01cr@0 1093 error("queryPoint > numVectors in query");
mas01cr@0 1094 else{
mas01cr@60 1095 if(verbosity>1) {
mas01cr@0 1096 cerr << "query point: " << queryPoint << endl; cerr.flush();
mas01cr@60 1097 }
mas01cr@0 1098 query=query+queryPoint*dbH->dim;
mas01cr@0 1099 numVectors=queryPoint+1;
mas01cr@0 1100 j=1;
mas01cr@0 1101 }
mas01cr@0 1102
mas01cr@0 1103 gettimeofday(&tv1, NULL);
mas01cr@0 1104 while(j--){ // query
mas01cr@0 1105 data=dataBuf;
mas01cr@0 1106 k=totalVecs; // number of database vectors
mas01cr@0 1107 while(k--){ // database
mas01cr@0 1108 thisDist=0;
mas01cr@0 1109 l=dbH->dim;
mas01cr@0 1110 double* q=query;
mas01cr@0 1111 while(l--)
mas01cr@0 1112 thisDist+=*q++**data++;
mas01cr@0 1113 if(!usingTimes ||
mas01cr@0 1114 (usingTimes
mas01cr@0 1115 && fabs(dbdurs[totalVecs-k-1]-timesdata[numVectors-j-1])<timesdata[numVectors-j-1]*timesTol)){
mas01cr@0 1116 n=pointNN;
mas01cr@0 1117 while(n--){
mas01cr@0 1118 if(thisDist>=distances[n]){
mas01cr@0 1119 if((n==0 || thisDist<=distances[n-1])){
mas01cr@0 1120 // Copy all values above up the queue
mas01cr@0 1121 for( l=pointNN-1 ; l >= n+1 ; l--){
mas01cr@0 1122 distances[l]=distances[l-1];
mas01cr@0 1123 qIndexes[l]=qIndexes[l-1];
mas01cr@0 1124 sIndexes[l]=sIndexes[l-1];
mas01cr@0 1125 }
mas01cr@0 1126 distances[n]=thisDist;
mas01cr@0 1127 qIndexes[n]=numVectors-j-1;
mas01cr@0 1128 sIndexes[n]=dbH->length/(sizeof(double)*dbH->dim)-k-1;
mas01cr@0 1129 break;
mas01cr@0 1130 }
mas01cr@0 1131 }
mas01cr@0 1132 else
mas01cr@0 1133 break;
mas01cr@0 1134 }
mas01cr@0 1135 }
mas01cr@0 1136 }
mas01cr@0 1137 // Move query pointer to next query point
mas01cr@0 1138 query+=dbH->dim;
mas01cr@0 1139 }
mas01cr@0 1140
mas01cr@0 1141 gettimeofday(&tv2, NULL);
mas01cr@60 1142 if(verbosity>1) {
mas01cr@0 1143 cerr << endl << " elapsed time:" << ( tv2.tv_sec*1000 + tv2.tv_usec/1000 ) - ( tv1.tv_sec*1000+tv1.tv_usec/1000 ) << " msec" << endl;
mas01cr@60 1144 }
mas01cr@0 1145
mas01cr@133 1146 if(adbQueryResponse==0){
mas01cr@0 1147 // Output answer
mas01cr@0 1148 // Loop over nearest neighbours
mas01cr@0 1149 for(k=0; k < pointNN; k++){
mas01cr@0 1150 // Scan for key
mas01mc@18 1151 unsigned cumTrack=0;
mas01cr@0 1152 for(l=0 ; l<dbH->numFiles; l++){
mas01mc@18 1153 cumTrack+=trackTable[l];
mas01mc@18 1154 if(sIndexes[k]<cumTrack){
mas01cr@0 1155 cout << fileTable+l*O2_FILETABLESIZE << " " << distances[k] << " " << qIndexes[k] << " "
mas01mc@18 1156 << sIndexes[k]+trackTable[l]-cumTrack << endl;
mas01cr@0 1157 break;
mas01cr@0 1158 }
mas01cr@0 1159 }
mas01cr@0 1160 }
mas01cr@0 1161 }
mas01cr@0 1162 else{ // Process Web Services Query
mas01cr@89 1163 int listLen;
mas01cr@89 1164 for(k = 0; k < pointNN; k++) {
mas01cr@89 1165 if(distances[k] == -DBL_MAX)
mas01cr@89 1166 break;
mas01cr@89 1167 }
mas01cr@89 1168 listLen = k;
mas01cr@89 1169
mas01cr@133 1170 adbQueryResponse->result.__sizeRlist=listLen;
mas01cr@133 1171 adbQueryResponse->result.__sizeDist=listLen;
mas01cr@133 1172 adbQueryResponse->result.__sizeQpos=listLen;
mas01cr@133 1173 adbQueryResponse->result.__sizeSpos=listLen;
mas01cr@133 1174 adbQueryResponse->result.Rlist= new char*[listLen];
mas01cr@133 1175 adbQueryResponse->result.Dist = new double[listLen];
mas01cr@133 1176 adbQueryResponse->result.Qpos = new unsigned int[listLen];
mas01cr@133 1177 adbQueryResponse->result.Spos = new unsigned int[listLen];
mas01cr@133 1178 for(k=0; k<(unsigned)adbQueryResponse->result.__sizeRlist; k++){
mas01cr@133 1179 adbQueryResponse->result.Rlist[k]=new char[O2_MAXFILESTR];
mas01cr@133 1180 adbQueryResponse->result.Dist[k]=distances[k];
mas01cr@133 1181 adbQueryResponse->result.Qpos[k]=qIndexes[k];
mas01mc@18 1182 unsigned cumTrack=0;
mas01cr@0 1183 for(l=0 ; l<dbH->numFiles; l++){
mas01mc@18 1184 cumTrack+=trackTable[l];
mas01mc@18 1185 if(sIndexes[k]<cumTrack){
mas01cr@133 1186 sprintf(adbQueryResponse->result.Rlist[k], "%s", fileTable+l*O2_FILETABLESIZE);
mas01cr@0 1187 break;
mas01cr@0 1188 }
mas01cr@0 1189 }
mas01cr@133 1190 adbQueryResponse->result.Spos[k]=sIndexes[k]+trackTable[l]-cumTrack;
mas01cr@0 1191 }
mas01cr@0 1192 }
mas01cr@0 1193
mas01cr@0 1194 // Clean up
mas01cr@0 1195 if(queryCopy)
mas01cr@0 1196 delete queryCopy;
mas01cr@0 1197 if(qNorm)
mas01cr@0 1198 delete qNorm;
mas01cr@0 1199 if(timesdata)
mas01cr@0 1200 delete timesdata;
mas01cr@0 1201 if(dbdurs)
mas01cr@0 1202 delete dbdurs;
mas01cr@0 1203 }
mas01cr@0 1204
mas01mc@18 1205 // trackPointQuery
mas01mc@18 1206 // return the trackNN closest tracks to the query track
mas01mc@18 1207 // uses average of pointNN points per track
mas01cr@133 1208 void audioDB::trackPointQuery(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse){
mas01cr@27 1209 initTables(dbName, 0, inFile);
mas01cr@0 1210
mas01cr@0 1211 // For each input vector, find the closest pointNN matching output vectors and report
mas01cr@0 1212 unsigned numVectors = (statbuf.st_size-sizeof(int))/(sizeof(double)*dbH->dim);
mas01cr@0 1213 double* query = (double*)(indata+sizeof(int));
mas01cr@0 1214 double* data = dataBuf;
mas01cr@0 1215 double* queryCopy = 0;
mas01cr@0 1216
mas01cr@0 1217 if( dbH->flags & O2_FLAG_L2NORM ){
mas01cr@0 1218 // Make a copy of the query
mas01cr@0 1219 queryCopy = new double[numVectors*dbH->dim];
mas01cr@0 1220 qNorm = new double[numVectors];
mas01cr@0 1221 assert(queryCopy&&qNorm);
mas01cr@0 1222 memcpy(queryCopy, query, numVectors*dbH->dim*sizeof(double));
mas01cr@0 1223 unitNorm(queryCopy, dbH->dim, numVectors, qNorm);
mas01cr@0 1224 query = queryCopy;
mas01cr@0 1225 }
mas01cr@0 1226
mas01cr@0 1227 assert(pointNN>0 && pointNN<=O2_MAXNN);
mas01mc@18 1228 assert(trackNN>0 && trackNN<=O2_MAXNN);
mas01cr@0 1229
mas01cr@0 1230 // Make temporary dynamic memory for results
mas01mc@18 1231 double trackDistances[trackNN];
mas01mc@18 1232 unsigned trackIDs[trackNN];
mas01mc@18 1233 unsigned trackQIndexes[trackNN];
mas01mc@18 1234 unsigned trackSIndexes[trackNN];
mas01cr@0 1235
mas01cr@0 1236 double distances[pointNN];
mas01cr@0 1237 unsigned qIndexes[pointNN];
mas01cr@0 1238 unsigned sIndexes[pointNN];
mas01cr@0 1239
mas01cr@0 1240 unsigned j=numVectors; // number of query points
mas01mc@18 1241 unsigned k,l,n, track, trackOffset=0, processedTracks=0;
mas01cr@0 1242 double thisDist;
mas01cr@0 1243
mas01cr@0 1244 for(k=0; k<pointNN; k++){
mas01cr@66 1245 distances[k]=-DBL_MAX;
mas01cr@0 1246 qIndexes[k]=~0;
mas01cr@0 1247 sIndexes[k]=~0;
mas01cr@0 1248 }
mas01cr@0 1249
mas01mc@18 1250 for(k=0; k<trackNN; k++){
mas01cr@66 1251 trackDistances[k]=-DBL_MAX;
mas01mc@18 1252 trackQIndexes[k]=~0;
mas01mc@18 1253 trackSIndexes[k]=~0;
mas01mc@18 1254 trackIDs[k]=~0;
mas01cr@0 1255 }
mas01cr@0 1256
mas01cr@0 1257 double meanQdur = 0;
mas01cr@0 1258 double* timesdata = 0;
mas01cr@0 1259 double* meanDBdur = 0;
mas01cr@0 1260
mas01cr@0 1261 if(usingTimes && !(dbH->flags & O2_FLAG_TIMES)){
mas01cr@0 1262 cerr << "warning: ignoring query timestamps for non-timestamped database" << endl;
mas01cr@0 1263 usingTimes=0;
mas01cr@0 1264 }
mas01cr@0 1265
mas01cr@0 1266 else if(!usingTimes && (dbH->flags & O2_FLAG_TIMES))
mas01cr@0 1267 cerr << "warning: no timestamps given for query. Ignoring database timestamps." << endl;
mas01cr@0 1268
mas01cr@0 1269 else if(usingTimes && (dbH->flags & O2_FLAG_TIMES)){
mas01cr@0 1270 timesdata = new double[numVectors];
mas01cr@0 1271 insertTimeStamps(numVectors, timesFile, timesdata);
mas01cr@0 1272 // Calculate durations of points
mas01cr@0 1273 for(k=0; k<numVectors-1; k++){
mas01cr@0 1274 timesdata[k]=timesdata[k+1]-timesdata[k];
mas01cr@0 1275 meanQdur+=timesdata[k];
mas01cr@0 1276 }
mas01cr@0 1277 meanQdur/=k;
mas01cr@0 1278 meanDBdur = new double[dbH->numFiles];
mas01cr@0 1279 for(k=0; k<dbH->numFiles; k++){
mas01cr@0 1280 meanDBdur[k]=0.0;
mas01mc@18 1281 for(j=0; j<trackTable[k]-1 ; j++)
mas01cr@0 1282 meanDBdur[k]+=timesTable[j+1]-timesTable[j];
mas01cr@0 1283 meanDBdur[k]/=j;
mas01cr@0 1284 }
mas01cr@0 1285 }
mas01cr@0 1286
mas01cr@0 1287 if(usingQueryPoint)
mas01cr@0 1288 if(queryPoint>numVectors-1)
mas01cr@0 1289 error("queryPoint > numVectors in query");
mas01cr@0 1290 else{
mas01cr@60 1291 if(verbosity>1) {
mas01cr@0 1292 cerr << "query point: " << queryPoint << endl; cerr.flush();
mas01cr@60 1293 }
mas01cr@0 1294 query=query+queryPoint*dbH->dim;
mas01cr@0 1295 numVectors=queryPoint+1;
mas01cr@0 1296 }
mas01cr@0 1297
mas01mc@18 1298 // build track offset table
mas01mc@18 1299 unsigned *trackOffsetTable = new unsigned[dbH->numFiles];
mas01mc@18 1300 unsigned cumTrack=0;
mas01mc@18 1301 unsigned trackIndexOffset;
mas01cr@0 1302 for(k=0; k<dbH->numFiles;k++){
mas01mc@18 1303 trackOffsetTable[k]=cumTrack;
mas01mc@18 1304 cumTrack+=trackTable[k]*dbH->dim;
mas01cr@0 1305 }
mas01cr@0 1306
mas01cr@0 1307 char nextKey[MAXSTR];
mas01cr@0 1308
mas01cr@0 1309 gettimeofday(&tv1, NULL);
mas01cr@0 1310
mas01mc@18 1311 for(processedTracks=0, track=0 ; processedTracks < dbH->numFiles ; track++, processedTracks++){
mas01mc@18 1312 if(trackFile){
mas01mc@18 1313 if(!trackFile->eof()){
mas01mc@18 1314 trackFile->getline(nextKey,MAXSTR);
mas01mc@18 1315 track=getKeyPos(nextKey);
mas01cr@0 1316 }
mas01cr@0 1317 else
mas01cr@0 1318 break;
mas01cr@0 1319 }
mas01mc@18 1320 trackOffset=trackOffsetTable[track]; // numDoubles offset
mas01mc@18 1321 trackIndexOffset=trackOffset/dbH->dim; // numVectors offset
mas01cr@60 1322 if(verbosity>7) {
mas01mc@18 1323 cerr << track << "." << trackOffset/(dbH->dim) << "." << trackTable[track] << " | ";cerr.flush();
mas01cr@60 1324 }
mas01cr@0 1325
mas01cr@0 1326 if(dbH->flags & O2_FLAG_L2NORM)
mas01cr@0 1327 usingQueryPoint?query=queryCopy+queryPoint*dbH->dim:query=queryCopy;
mas01cr@0 1328 else
mas01cr@0 1329 usingQueryPoint?query=(double*)(indata+sizeof(int))+queryPoint*dbH->dim:query=(double*)(indata+sizeof(int));
mas01cr@0 1330 if(usingQueryPoint)
mas01cr@0 1331 j=1;
mas01cr@0 1332 else
mas01cr@0 1333 j=numVectors;
mas01cr@0 1334 while(j--){
mas01mc@18 1335 k=trackTable[track]; // number of vectors in track
mas01mc@18 1336 data=dataBuf+trackOffset; // data for track
mas01cr@0 1337 while(k--){
mas01cr@0 1338 thisDist=0;
mas01cr@0 1339 l=dbH->dim;
mas01cr@0 1340 double* q=query;
mas01cr@0 1341 while(l--)
mas01cr@0 1342 thisDist+=*q++**data++;
mas01cr@0 1343 if(!usingTimes ||
mas01cr@0 1344 (usingTimes
mas01mc@18 1345 && fabs(meanDBdur[track]-meanQdur)<meanQdur*timesTol)){
mas01cr@0 1346 n=pointNN;
mas01cr@0 1347 while(n--){
mas01cr@0 1348 if(thisDist>=distances[n]){
mas01cr@0 1349 if((n==0 || thisDist<=distances[n-1])){
mas01cr@0 1350 // Copy all values above up the queue
mas01cr@0 1351 for( l=pointNN-1 ; l > n ; l--){
mas01cr@0 1352 distances[l]=distances[l-1];
mas01cr@0 1353 qIndexes[l]=qIndexes[l-1];
mas01cr@0 1354 sIndexes[l]=sIndexes[l-1];
mas01cr@0 1355 }
mas01cr@0 1356 distances[n]=thisDist;
mas01cr@0 1357 qIndexes[n]=numVectors-j-1;
mas01mc@18 1358 sIndexes[n]=trackTable[track]-k-1;
mas01cr@0 1359 break;
mas01cr@0 1360 }
mas01cr@0 1361 }
mas01cr@0 1362 else
mas01cr@0 1363 break;
mas01cr@0 1364 }
mas01cr@0 1365 }
mas01mc@18 1366 } // track
mas01cr@0 1367 // Move query pointer to next query point
mas01cr@0 1368 query+=dbH->dim;
mas01cr@0 1369 } // query
mas01mc@18 1370 // Take the average of this track's distance
mas01mc@18 1371 // Test the track distances
mas01cr@0 1372 thisDist=0;
mas01cr@66 1373 for (n = 0; n < pointNN; n++) {
mas01cr@66 1374 if (distances[n] == -DBL_MAX) break;
mas01cr@66 1375 thisDist += distances[n];
mas01cr@66 1376 }
mas01cr@66 1377 thisDist /= n;
mas01cr@66 1378
mas01mc@18 1379 n=trackNN;
mas01cr@0 1380 while(n--){
mas01mc@18 1381 if(thisDist>=trackDistances[n]){
mas01mc@18 1382 if((n==0 || thisDist<=trackDistances[n-1])){
mas01cr@0 1383 // Copy all values above up the queue
mas01cr@74 1384 for( l=trackNN-1 ; l > n ; l--){
mas01mc@18 1385 trackDistances[l]=trackDistances[l-1];
mas01mc@18 1386 trackQIndexes[l]=trackQIndexes[l-1];
mas01mc@18 1387 trackSIndexes[l]=trackSIndexes[l-1];
mas01mc@18 1388 trackIDs[l]=trackIDs[l-1];
mas01cr@0 1389 }
mas01mc@18 1390 trackDistances[n]=thisDist;
mas01mc@18 1391 trackQIndexes[n]=qIndexes[0];
mas01mc@18 1392 trackSIndexes[n]=sIndexes[0];
mas01mc@18 1393 trackIDs[n]=track;
mas01cr@0 1394 break;
mas01cr@0 1395 }
mas01cr@0 1396 }
mas01cr@0 1397 else
mas01cr@0 1398 break;
mas01cr@0 1399 }
mas01cr@0 1400 for(unsigned k=0; k<pointNN; k++){
mas01cr@66 1401 distances[k]=-DBL_MAX;
mas01cr@0 1402 qIndexes[k]=~0;
mas01cr@0 1403 sIndexes[k]=~0;
mas01cr@0 1404 }
mas01mc@18 1405 } // tracks
mas01cr@0 1406 gettimeofday(&tv2, NULL);
mas01cr@0 1407
mas01cr@60 1408 if(verbosity>1) {
mas01mc@18 1409 cerr << endl << "processed tracks :" << processedTracks
mas01cr@0 1410 << " elapsed time:" << ( tv2.tv_sec*1000 + tv2.tv_usec/1000 ) - ( tv1.tv_sec*1000+tv1.tv_usec/1000 ) << " msec" << endl;
mas01cr@60 1411 }
mas01cr@0 1412
mas01cr@133 1413 if(adbQueryResponse==0){
mas01cr@60 1414 if(verbosity>1) {
mas01cr@0 1415 cerr<<endl;
mas01cr@60 1416 }
mas01cr@0 1417 // Output answer
mas01cr@0 1418 // Loop over nearest neighbours
mas01mc@18 1419 for(k=0; k < min(trackNN,processedTracks); k++)
mas01mc@18 1420 cout << fileTable+trackIDs[k]*O2_FILETABLESIZE
mas01mc@18 1421 << " " << trackDistances[k] << " " << trackQIndexes[k] << " " << trackSIndexes[k] << endl;
mas01cr@0 1422 }
mas01cr@0 1423 else{ // Process Web Services Query
mas01mc@18 1424 int listLen = min(trackNN, processedTracks);
mas01cr@133 1425 adbQueryResponse->result.__sizeRlist=listLen;
mas01cr@133 1426 adbQueryResponse->result.__sizeDist=listLen;
mas01cr@133 1427 adbQueryResponse->result.__sizeQpos=listLen;
mas01cr@133 1428 adbQueryResponse->result.__sizeSpos=listLen;
mas01cr@133 1429 adbQueryResponse->result.Rlist= new char*[listLen];
mas01cr@133 1430 adbQueryResponse->result.Dist = new double[listLen];
mas01cr@133 1431 adbQueryResponse->result.Qpos = new unsigned int[listLen];
mas01cr@133 1432 adbQueryResponse->result.Spos = new unsigned int[listLen];
mas01cr@133 1433 for(k=0; k<(unsigned)adbQueryResponse->result.__sizeRlist; k++){
mas01cr@133 1434 adbQueryResponse->result.Rlist[k]=new char[O2_MAXFILESTR];
mas01cr@133 1435 adbQueryResponse->result.Dist[k]=trackDistances[k];
mas01cr@133 1436 adbQueryResponse->result.Qpos[k]=trackQIndexes[k];
mas01cr@133 1437 adbQueryResponse->result.Spos[k]=trackSIndexes[k];
mas01cr@133 1438 sprintf(adbQueryResponse->result.Rlist[k], "%s", fileTable+trackIDs[k]*O2_FILETABLESIZE);
mas01cr@0 1439 }
mas01cr@0 1440 }
mas01cr@0 1441
mas01cr@0 1442
mas01cr@0 1443 // Clean up
mas01mc@18 1444 if(trackOffsetTable)
mas01mc@18 1445 delete trackOffsetTable;
mas01cr@0 1446 if(queryCopy)
mas01cr@0 1447 delete queryCopy;
mas01cr@0 1448 if(qNorm)
mas01cr@0 1449 delete qNorm;
mas01cr@0 1450 if(timesdata)
mas01cr@0 1451 delete timesdata;
mas01cr@0 1452 if(meanDBdur)
mas01cr@0 1453 delete meanDBdur;
mas01cr@0 1454
mas01cr@0 1455 }
mas01cr@0 1456
mas01cr@0 1457
mas01mc@20 1458 // k nearest-neighbor (k-NN) search between query and target tracks
mas01mc@20 1459 // efficient implementation based on matched filter
mas01mc@20 1460 // assumes normed shingles
mas01mc@20 1461 // outputs distances of retrieved shingles, max retreived = pointNN shingles per per track
mas01cr@133 1462 void audioDB::trackSequenceQueryNN(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse){
mas01cr@0 1463
mas01cr@27 1464 initTables(dbName, 0, inFile);
mas01cr@0 1465
mas01cr@0 1466 // For each input vector, find the closest pointNN matching output vectors and report
mas01cr@0 1467 // we use stdout in this stub version
mas01cr@0 1468 unsigned numVectors = (statbuf.st_size-sizeof(int))/(sizeof(double)*dbH->dim);
mas01cr@0 1469 double* query = (double*)(indata+sizeof(int));
mas01cr@0 1470 double* queryCopy = 0;
mas01cr@0 1471
mas01cr@0 1472 double qMeanL2;
mas01cr@0 1473 double* sMeanL2;
mas01cr@0 1474
mas01cr@0 1475 unsigned USE_THRESH=0;
mas01cr@0 1476 double SILENCE_THRESH=0;
mas01cr@0 1477 double DIFF_THRESH=0;
mas01cr@0 1478
mas01cr@0 1479 if(!(dbH->flags & O2_FLAG_L2NORM) )
mas01cr@55 1480 error("Database must be L2 normed for sequence query","use -L2NORM");
mas01cr@55 1481
mas01cr@55 1482 if(numVectors<sequenceLength)
mas01cr@55 1483 error("Query shorter than requested sequence length", "maybe use -l");
mas01cr@0 1484
mas01cr@60 1485 if(verbosity>1) {
mas01cr@0 1486 cerr << "performing norms ... "; cerr.flush();
mas01cr@60 1487 }
mas01cr@0 1488 unsigned dbVectors = dbH->length/(sizeof(double)*dbH->dim);
mas01mc@20 1489
mas01cr@0 1490 // Make a copy of the query
mas01cr@0 1491 queryCopy = new double[numVectors*dbH->dim];
mas01cr@0 1492 memcpy(queryCopy, query, numVectors*dbH->dim*sizeof(double));
mas01cr@0 1493 qNorm = new double[numVectors];
mas01cr@0 1494 sNorm = new double[dbVectors];
mas01cr@0 1495 sMeanL2=new double[dbH->numFiles];
mas01cr@0 1496 assert(qNorm&&sNorm&&queryCopy&&sMeanL2&&sequenceLength);
mas01cr@0 1497 unitNorm(queryCopy, dbH->dim, numVectors, qNorm);
mas01cr@0 1498 query = queryCopy;
mas01mc@20 1499
mas01cr@0 1500 // Make norm measurements relative to sequenceLength
mas01cr@0 1501 unsigned w = sequenceLength-1;
mas01cr@0 1502 unsigned i,j;
mas01cr@0 1503 double* ps;
mas01cr@0 1504 double tmp1,tmp2;
mas01mc@20 1505
mas01cr@0 1506 // Copy the L2 norm values to core to avoid disk random access later on
mas01cr@0 1507 memcpy(sNorm, l2normTable, dbVectors*sizeof(double));
mas01cr@125 1508 double* qnPtr = qNorm;
mas01cr@0 1509 double* snPtr = sNorm;
mas01cr@0 1510 for(i=0; i<dbH->numFiles; i++){
mas01mc@20 1511 if(trackTable[i]>=sequenceLength){
mas01cr@0 1512 tmp1=*snPtr;
mas01cr@0 1513 j=1;
mas01cr@0 1514 w=sequenceLength-1;
mas01cr@0 1515 while(w--)
mas01cr@0 1516 *snPtr+=snPtr[j++];
mas01cr@0 1517 ps = snPtr+1;
mas01mc@18 1518 w=trackTable[i]-sequenceLength; // +1 - 1
mas01cr@0 1519 while(w--){
mas01cr@0 1520 tmp2=*ps;
mas01mc@20 1521 *ps=*(ps-1)-tmp1+*(ps+sequenceLength-1);
mas01cr@0 1522 tmp1=tmp2;
mas01cr@0 1523 ps++;
mas01cr@0 1524 }
mas01mc@20 1525 ps = snPtr;
mas01mc@20 1526 w=trackTable[i]-sequenceLength+1;
mas01mc@20 1527 while(w--){
mas01mc@20 1528 *ps=sqrt(*ps);
mas01mc@20 1529 ps++;
mas01mc@20 1530 }
mas01cr@0 1531 }
mas01mc@18 1532 snPtr+=trackTable[i];
mas01cr@0 1533 }
mas01cr@0 1534
mas01cr@0 1535 double* pn = sMeanL2;
mas01cr@0 1536 w=dbH->numFiles;
mas01cr@0 1537 while(w--)
mas01cr@0 1538 *pn++=0.0;
mas01cr@0 1539 ps=sNorm;
mas01mc@18 1540 unsigned processedTracks=0;
mas01cr@0 1541 for(i=0; i<dbH->numFiles; i++){
mas01mc@18 1542 if(trackTable[i]>sequenceLength-1){
mas01cr@57 1543 w = trackTable[i]-sequenceLength+1;
mas01cr@0 1544 pn = sMeanL2+i;
mas01mc@20 1545 *pn=0;
mas01cr@0 1546 while(w--)
mas01mc@20 1547 if(*ps>0)
mas01mc@20 1548 *pn+=*ps++;
mas01cr@57 1549 *pn/=trackTable[i]-sequenceLength+1;
mas01cr@0 1550 SILENCE_THRESH+=*pn;
mas01mc@18 1551 processedTracks++;
mas01cr@0 1552 }
mas01mc@18 1553 ps = sNorm + trackTable[i];
mas01cr@0 1554 }
mas01cr@60 1555 if(verbosity>1) {
mas01mc@18 1556 cerr << "processedTracks: " << processedTracks << endl;
mas01cr@60 1557 }
mas01mc@20 1558
mas01mc@18 1559 SILENCE_THRESH/=processedTracks;
mas01cr@0 1560 USE_THRESH=1; // Turn thresholding on
mas01mc@20 1561 DIFF_THRESH=SILENCE_THRESH; // mean shingle power
mas01mc@20 1562 SILENCE_THRESH/=5; // 20% of the mean shingle power is SILENCE
mas01cr@60 1563 if(verbosity>4) {
mas01mc@20 1564 cerr << "silence thresh: " << SILENCE_THRESH;
mas01cr@60 1565 }
mas01cr@0 1566 w=sequenceLength-1;
mas01cr@0 1567 i=1;
mas01cr@125 1568 tmp1=*qnPtr;
mas01cr@0 1569 while(w--)
mas01cr@125 1570 *qnPtr+=qnPtr[i++];
mas01cr@125 1571 ps = qnPtr+1;
mas01mc@20 1572 w=numVectors-sequenceLength; // +1 -1
mas01cr@0 1573 while(w--){
mas01cr@0 1574 tmp2=*ps;
mas01mc@20 1575 *ps=*(ps-1)-tmp1+*(ps+sequenceLength-1);
mas01cr@0 1576 tmp1=tmp2;
mas01mc@20 1577 ps++;
mas01mc@20 1578 }
mas01cr@125 1579 ps = qnPtr;
mas01mc@20 1580 qMeanL2 = 0;
mas01mc@20 1581 w=numVectors-sequenceLength+1;
mas01mc@20 1582 while(w--){
mas01mc@20 1583 *ps=sqrt(*ps);
mas01mc@20 1584 qMeanL2+=*ps++;
mas01cr@0 1585 }
mas01cr@0 1586 qMeanL2 /= numVectors-sequenceLength+1;
mas01mc@20 1587
mas01cr@60 1588 if(verbosity>1) {
mas01cr@60 1589 cerr << "done." << endl;
mas01cr@60 1590 }
mas01cr@0 1591
mas01cr@60 1592 if(verbosity>1) {
mas01mc@18 1593 cerr << "matching tracks..." << endl;
mas01cr@60 1594 }
mas01cr@0 1595
mas01cr@0 1596 assert(pointNN>0 && pointNN<=O2_MAXNN);
mas01mc@18 1597 assert(trackNN>0 && trackNN<=O2_MAXNN);
mas01cr@0 1598
mas01cr@0 1599 // Make temporary dynamic memory for results
mas01mc@18 1600 double trackDistances[trackNN];
mas01mc@18 1601 unsigned trackIDs[trackNN];
mas01mc@18 1602 unsigned trackQIndexes[trackNN];
mas01mc@18 1603 unsigned trackSIndexes[trackNN];
mas01cr@0 1604
mas01cr@0 1605 double distances[pointNN];
mas01cr@0 1606 unsigned qIndexes[pointNN];
mas01cr@0 1607 unsigned sIndexes[pointNN];
mas01cr@0 1608
mas01cr@0 1609
mas01mc@18 1610 unsigned k,l,m,n,track,trackOffset=0, HOP_SIZE=sequenceHop, wL=sequenceLength;
mas01cr@0 1611 double thisDist;
mas01cr@0 1612
mas01cr@0 1613 for(k=0; k<pointNN; k++){
mas01mc@20 1614 distances[k]=1.0e6;
mas01cr@0 1615 qIndexes[k]=~0;
mas01cr@0 1616 sIndexes[k]=~0;
mas01cr@0 1617 }
mas01cr@0 1618
mas01mc@18 1619 for(k=0; k<trackNN; k++){
mas01mc@20 1620 trackDistances[k]=1.0e6;
mas01mc@18 1621 trackQIndexes[k]=~0;
mas01mc@18 1622 trackSIndexes[k]=~0;
mas01mc@18 1623 trackIDs[k]=~0;
mas01cr@0 1624 }
mas01cr@0 1625
mas01cr@0 1626 // Timestamp and durations processing
mas01cr@0 1627 double meanQdur = 0;
mas01cr@0 1628 double* timesdata = 0;
mas01cr@0 1629 double* meanDBdur = 0;
mas01cr@0 1630
mas01cr@0 1631 if(usingTimes && !(dbH->flags & O2_FLAG_TIMES)){
mas01cr@0 1632 cerr << "warning: ignoring query timestamps for non-timestamped database" << endl;
mas01cr@0 1633 usingTimes=0;
mas01cr@0 1634 }
mas01cr@0 1635
mas01cr@0 1636 else if(!usingTimes && (dbH->flags & O2_FLAG_TIMES))
mas01cr@0 1637 cerr << "warning: no timestamps given for query. Ignoring database timestamps." << endl;
mas01cr@0 1638
mas01cr@0 1639 else if(usingTimes && (dbH->flags & O2_FLAG_TIMES)){
mas01cr@0 1640 timesdata = new double[numVectors];
mas01cr@0 1641 assert(timesdata);
mas01cr@0 1642 insertTimeStamps(numVectors, timesFile, timesdata);
mas01cr@0 1643 // Calculate durations of points
mas01cr@0 1644 for(k=0; k<numVectors-1; k++){
mas01cr@0 1645 timesdata[k]=timesdata[k+1]-timesdata[k];
mas01cr@0 1646 meanQdur+=timesdata[k];
mas01cr@0 1647 }
mas01cr@0 1648 meanQdur/=k;
mas01cr@60 1649 if(verbosity>1) {
mas01cr@0 1650 cerr << "mean query file duration: " << meanQdur << endl;
mas01cr@60 1651 }
mas01cr@0 1652 meanDBdur = new double[dbH->numFiles];
mas01cr@0 1653 assert(meanDBdur);
mas01cr@0 1654 for(k=0; k<dbH->numFiles; k++){
mas01cr@0 1655 meanDBdur[k]=0.0;
mas01mc@18 1656 for(j=0; j<trackTable[k]-1 ; j++)
mas01cr@0 1657 meanDBdur[k]+=timesTable[j+1]-timesTable[j];
mas01cr@0 1658 meanDBdur[k]/=j;
mas01cr@0 1659 }
mas01cr@0 1660 }
mas01cr@0 1661
mas01cr@0 1662 if(usingQueryPoint)
mas01cr@0 1663 if(queryPoint>numVectors || queryPoint>numVectors-wL+1)
mas01cr@0 1664 error("queryPoint > numVectors-wL+1 in query");
mas01cr@0 1665 else{
mas01cr@60 1666 if(verbosity>1) {
mas01cr@0 1667 cerr << "query point: " << queryPoint << endl; cerr.flush();
mas01cr@60 1668 }
mas01cr@0 1669 query=query+queryPoint*dbH->dim;
mas01cr@125 1670 qnPtr=qnPtr+queryPoint;
mas01cr@0 1671 numVectors=wL;
mas01cr@0 1672 }
mas01cr@0 1673
mas01mc@20 1674 double ** D = 0; // Differences query and target
mas01cr@0 1675 double ** DD = 0; // Matched filter distance
mas01cr@0 1676
mas01cr@0 1677 D = new double*[numVectors];
mas01cr@0 1678 assert(D);
mas01cr@0 1679 DD = new double*[numVectors];
mas01cr@0 1680 assert(DD);
mas01cr@0 1681
mas01cr@0 1682 gettimeofday(&tv1, NULL);
mas01mc@18 1683 processedTracks=0;
mas01mc@18 1684 unsigned successfulTracks=0;
mas01cr@0 1685
mas01cr@0 1686 double* qp;
mas01cr@0 1687 double* sp;
mas01cr@0 1688 double* dp;
mas01cr@0 1689
mas01mc@18 1690 // build track offset table
mas01mc@18 1691 unsigned *trackOffsetTable = new unsigned[dbH->numFiles];
mas01mc@18 1692 unsigned cumTrack=0;
mas01mc@18 1693 unsigned trackIndexOffset;
mas01cr@0 1694 for(k=0; k<dbH->numFiles;k++){
mas01mc@18 1695 trackOffsetTable[k]=cumTrack;
mas01mc@18 1696 cumTrack+=trackTable[k]*dbH->dim;
mas01cr@0 1697 }
mas01cr@0 1698
mas01cr@0 1699 char nextKey [MAXSTR];
mas01mc@20 1700
mas01mc@20 1701 // chi^2 statistics
mas01mc@20 1702 double sampleCount = 0;
mas01mc@20 1703 double sampleSum = 0;
mas01mc@20 1704 double logSampleSum = 0;
mas01mc@20 1705 double minSample = 1e9;
mas01mc@20 1706 double maxSample = 0;
mas01mc@20 1707
mas01mc@20 1708 // Track loop
mas01mc@18 1709 for(processedTracks=0, track=0 ; processedTracks < dbH->numFiles ; track++, processedTracks++){
mas01cr@0 1710
mas01mc@18 1711 // get trackID from file if using a control file
mas01mc@18 1712 if(trackFile){
mas01mc@18 1713 if(!trackFile->eof()){
mas01mc@18 1714 trackFile->getline(nextKey,MAXSTR);
mas01mc@18 1715 track=getKeyPos(nextKey);
mas01cr@0 1716 }
mas01cr@0 1717 else
mas01cr@0 1718 break;
mas01cr@0 1719 }
mas01mc@12 1720
mas01mc@18 1721 trackOffset=trackOffsetTable[track]; // numDoubles offset
mas01mc@18 1722 trackIndexOffset=trackOffset/dbH->dim; // numVectors offset
mas01cr@0 1723
mas01cr@57 1724 if(sequenceLength<=trackTable[track]){ // test for short sequences
mas01cr@0 1725
mas01cr@60 1726 if(verbosity>7) {
mas01mc@18 1727 cerr << track << "." << trackIndexOffset << "." << trackTable[track] << " | ";cerr.flush();
mas01cr@60 1728 }
mas01cr@0 1729
mas01mc@20 1730 // Sum products matrix
mas01cr@0 1731 for(j=0; j<numVectors;j++){
mas01mc@18 1732 D[j]=new double[trackTable[track]];
mas01cr@0 1733 assert(D[j]);
mas01cr@0 1734
mas01cr@0 1735 }
mas01cr@0 1736
mas01cr@0 1737 // Matched filter matrix
mas01cr@0 1738 for(j=0; j<numVectors;j++){
mas01mc@18 1739 DD[j]=new double[trackTable[track]];
mas01cr@0 1740 assert(DD[j]);
mas01cr@0 1741 }
mas01cr@0 1742
mas01mc@20 1743 // Dot product
mas01cr@0 1744 for(j=0; j<numVectors; j++)
mas01mc@18 1745 for(k=0; k<trackTable[track]; k++){
mas01cr@0 1746 qp=query+j*dbH->dim;
mas01mc@18 1747 sp=dataBuf+trackOffset+k*dbH->dim;
mas01cr@0 1748 DD[j][k]=0.0; // Initialize matched filter array
mas01cr@0 1749 dp=&D[j][k]; // point to correlation cell j,k
mas01cr@0 1750 *dp=0.0; // initialize correlation cell
mas01cr@0 1751 l=dbH->dim; // size of vectors
mas01cr@0 1752 while(l--)
mas01cr@0 1753 *dp+=*qp++**sp++;
mas01cr@0 1754 }
mas01cr@0 1755
mas01cr@0 1756 // Matched Filter
mas01cr@0 1757 // HOP SIZE == 1
mas01cr@0 1758 double* spd;
mas01cr@0 1759 if(HOP_SIZE==1){ // HOP_SIZE = shingleHop
mas01cr@0 1760 for(w=0; w<wL; w++)
mas01cr@0 1761 for(j=0; j<numVectors-w; j++){
mas01cr@0 1762 sp=DD[j];
mas01cr@0 1763 spd=D[j+w]+w;
mas01mc@18 1764 k=trackTable[track]-w;
mas01cr@0 1765 while(k--)
mas01cr@0 1766 *sp+++=*spd++;
mas01cr@0 1767 }
mas01cr@0 1768 }
mas01mc@20 1769
mas01cr@0 1770 else{ // HOP_SIZE != 1
mas01cr@0 1771 for(w=0; w<wL; w++)
mas01cr@0 1772 for(j=0; j<numVectors-w; j+=HOP_SIZE){
mas01cr@0 1773 sp=DD[j];
mas01cr@0 1774 spd=D[j+w]+w;
mas01mc@18 1775 for(k=0; k<trackTable[track]-w; k+=HOP_SIZE){
mas01cr@0 1776 *sp+=*spd;
mas01cr@0 1777 sp+=HOP_SIZE;
mas01cr@0 1778 spd+=HOP_SIZE;
mas01cr@0 1779 }
mas01cr@0 1780 }
mas01cr@0 1781 }
mas01cr@0 1782
mas01cr@60 1783 if(verbosity>3 && usingTimes) {
mas01mc@18 1784 cerr << "meanQdur=" << meanQdur << " meanDBdur=" << meanDBdur[track] << endl;
mas01cr@0 1785 cerr.flush();
mas01cr@0 1786 }
mas01cr@0 1787
mas01cr@0 1788 if(!usingTimes ||
mas01cr@0 1789 (usingTimes
mas01mc@18 1790 && fabs(meanDBdur[track]-meanQdur)<meanQdur*timesTol)){
mas01cr@0 1791
mas01cr@60 1792 if(verbosity>3 && usingTimes) {
mas01cr@0 1793 cerr << "within duration tolerance." << endl;
mas01cr@0 1794 cerr.flush();
mas01cr@0 1795 }
mas01cr@0 1796
mas01cr@0 1797 // Search for minimum distance by shingles (concatenated vectors)
mas01cr@53 1798 for(j=0;j<=numVectors-wL;j+=HOP_SIZE)
mas01cr@53 1799 for(k=0;k<=trackTable[track]-wL;k+=HOP_SIZE){
mas01cr@125 1800 thisDist=2-(2/(qnPtr[j]*sNorm[trackIndexOffset+k]))*DD[j][k];
mas01cr@60 1801 if(verbosity>10) {
mas01cr@125 1802 cerr << thisDist << " " << qnPtr[j] << " " << sNorm[trackIndexOffset+k] << endl;
mas01cr@60 1803 }
mas01mc@20 1804 // Gather chi^2 statistics
mas01mc@20 1805 if(thisDist<minSample)
mas01mc@20 1806 minSample=thisDist;
mas01mc@20 1807 else if(thisDist>maxSample)
mas01mc@20 1808 maxSample=thisDist;
mas01mc@20 1809 if(thisDist>1e-9){
mas01mc@20 1810 sampleCount++;
mas01mc@20 1811 sampleSum+=thisDist;
mas01mc@20 1812 logSampleSum+=log(thisDist);
mas01mc@20 1813 }
mas01mc@20 1814
mas01cr@125 1815 // diffL2 = fabs(qnPtr[j] - sNorm[trackIndexOffset+k]);
mas01cr@0 1816 // Power test
mas01cr@0 1817 if(!USE_THRESH ||
mas01cr@0 1818 // Threshold on mean L2 of Q and S sequences
mas01cr@125 1819 (USE_THRESH && qnPtr[j]>SILENCE_THRESH && sNorm[trackIndexOffset+k]>SILENCE_THRESH &&
mas01cr@0 1820 // Are both query and target windows above mean energy?
mas01cr@125 1821 (qnPtr[j]>qMeanL2*.25 && sNorm[trackIndexOffset+k]>sMeanL2[track]*.25))) // && diffL2 < DIFF_THRESH )))
mas01mc@20 1822 thisDist=thisDist; // Computed above
mas01cr@0 1823 else
mas01mc@20 1824 thisDist=1000000.0;
mas01mc@20 1825
mas01mc@20 1826 // k-NN match algorithm
mas01cr@58 1827 m=pointNN;
mas01mc@20 1828 while(m--){
mas01mc@20 1829 if(thisDist<=distances[m])
mas01mc@20 1830 if(m==0 || thisDist>=distances[m-1]){
mas01cr@0 1831 // Shuffle distances up the list
mas01cr@0 1832 for(l=pointNN-1; l>m; l--){
mas01cr@0 1833 distances[l]=distances[l-1];
mas01cr@0 1834 qIndexes[l]=qIndexes[l-1];
mas01cr@0 1835 sIndexes[l]=sIndexes[l-1];
mas01cr@0 1836 }
mas01cr@0 1837 distances[m]=thisDist;
mas01cr@0 1838 if(usingQueryPoint)
mas01cr@0 1839 qIndexes[m]=queryPoint;
mas01cr@0 1840 else
mas01cr@0 1841 qIndexes[m]=j;
mas01cr@0 1842 sIndexes[m]=k;
mas01cr@0 1843 break;
mas01mc@20 1844 }
mas01cr@0 1845 }
mas01cr@0 1846 }
mas01cr@0 1847 // Calculate the mean of the N-Best matches
mas01cr@0 1848 thisDist=0.0;
mas01cr@53 1849 for(m=0; m<pointNN; m++) {
mas01cr@53 1850 if (distances[m] == 1000000.0) break;
mas01mc@20 1851 thisDist+=distances[m];
mas01cr@53 1852 }
mas01cr@53 1853 thisDist/=m;
mas01cr@0 1854
mas01mc@12 1855 // Let's see the distances then...
mas01cr@60 1856 if(verbosity>3) {
mas01mc@18 1857 cerr << fileTable+track*O2_FILETABLESIZE << " " << thisDist << endl;
mas01cr@60 1858 }
mas01mc@12 1859
mas01mc@20 1860
mas01mc@18 1861 // All the track stuff goes here
mas01cr@58 1862 n=trackNN;
mas01cr@0 1863 while(n--){
mas01mc@20 1864 if(thisDist<=trackDistances[n]){
mas01mc@20 1865 if((n==0 || thisDist>=trackDistances[n-1])){
mas01cr@0 1866 // Copy all values above up the queue
mas01mc@18 1867 for( l=trackNN-1 ; l > n ; l--){
mas01mc@18 1868 trackDistances[l]=trackDistances[l-1];
mas01mc@18 1869 trackQIndexes[l]=trackQIndexes[l-1];
mas01mc@18 1870 trackSIndexes[l]=trackSIndexes[l-1];
mas01mc@18 1871 trackIDs[l]=trackIDs[l-1];
mas01cr@0 1872 }
mas01mc@18 1873 trackDistances[n]=thisDist;
mas01mc@18 1874 trackQIndexes[n]=qIndexes[0];
mas01mc@18 1875 trackSIndexes[n]=sIndexes[0];
mas01mc@18 1876 successfulTracks++;
mas01mc@18 1877 trackIDs[n]=track;
mas01cr@0 1878 break;
mas01cr@0 1879 }
mas01cr@0 1880 }
mas01cr@0 1881 else
mas01cr@0 1882 break;
mas01cr@0 1883 }
mas01cr@0 1884 } // Duration match
mas01mc@20 1885
mas01mc@18 1886 // Clean up current track
mas01cr@0 1887 if(D!=NULL){
mas01cr@0 1888 for(j=0; j<numVectors; j++)
mas01cr@0 1889 delete[] D[j];
mas01cr@0 1890 }
mas01cr@0 1891
mas01cr@0 1892 if(DD!=NULL){
mas01cr@0 1893 for(j=0; j<numVectors; j++)
mas01cr@0 1894 delete[] DD[j];
mas01cr@0 1895 }
mas01cr@0 1896 }
mas01mc@20 1897 // per-track reset array values
mas01mc@20 1898 for(unsigned k=0; k<pointNN; k++){
mas01mc@20 1899 distances[k]=1.0e6;
mas01mc@20 1900 qIndexes[k]=~0;
mas01mc@20 1901 sIndexes[k]=~0;
mas01mc@20 1902 }
mas01cr@0 1903 }
mas01cr@0 1904
mas01cr@0 1905 gettimeofday(&tv2,NULL);
mas01cr@60 1906 if(verbosity>1) {
mas01mc@18 1907 cerr << endl << "processed tracks :" << processedTracks << " matched tracks: " << successfulTracks << " elapsed time:"
mas01cr@0 1908 << ( tv2.tv_sec*1000 + tv2.tv_usec/1000 ) - ( tv1.tv_sec*1000+tv1.tv_usec/1000 ) << " msec" << endl;
mas01mc@20 1909 cerr << "sampleCount: " << sampleCount << " sampleSum: " << sampleSum << " logSampleSum: " << logSampleSum
mas01mc@20 1910 << " minSample: " << minSample << " maxSample: " << maxSample << endl;
mas01mc@20 1911 }
mas01cr@133 1912 if(adbQueryResponse==0){
mas01cr@60 1913 if(verbosity>1) {
mas01cr@0 1914 cerr<<endl;
mas01cr@60 1915 }
mas01cr@0 1916 // Output answer
mas01cr@0 1917 // Loop over nearest neighbours
mas01mc@18 1918 for(k=0; k < min(trackNN,successfulTracks); k++)
mas01mc@20 1919 cout << fileTable+trackIDs[k]*O2_FILETABLESIZE << " " << trackDistances[k] << " "
mas01mc@20 1920 << trackQIndexes[k] << " " << trackSIndexes[k] << endl;
mas01cr@0 1921 }
mas01cr@0 1922 else{ // Process Web Services Query
mas01mc@18 1923 int listLen = min(trackNN, processedTracks);
mas01cr@133 1924 adbQueryResponse->result.__sizeRlist=listLen;
mas01cr@133 1925 adbQueryResponse->result.__sizeDist=listLen;
mas01cr@133 1926 adbQueryResponse->result.__sizeQpos=listLen;
mas01cr@133 1927 adbQueryResponse->result.__sizeSpos=listLen;
mas01cr@133 1928 adbQueryResponse->result.Rlist= new char*[listLen];
mas01cr@133 1929 adbQueryResponse->result.Dist = new double[listLen];
mas01cr@133 1930 adbQueryResponse->result.Qpos = new unsigned int[listLen];
mas01cr@133 1931 adbQueryResponse->result.Spos = new unsigned int[listLen];
mas01cr@133 1932 for(k=0; k<(unsigned)adbQueryResponse->result.__sizeRlist; k++){
mas01cr@133 1933 adbQueryResponse->result.Rlist[k]=new char[O2_MAXFILESTR];
mas01cr@133 1934 adbQueryResponse->result.Dist[k]=trackDistances[k];
mas01cr@133 1935 adbQueryResponse->result.Qpos[k]=trackQIndexes[k];
mas01cr@133 1936 adbQueryResponse->result.Spos[k]=trackSIndexes[k];
mas01cr@133 1937 sprintf(adbQueryResponse->result.Rlist[k], "%s", fileTable+trackIDs[k]*O2_FILETABLESIZE);
mas01cr@0 1938 }
mas01cr@0 1939 }
mas01cr@0 1940
mas01cr@0 1941
mas01cr@0 1942 // Clean up
mas01mc@18 1943 if(trackOffsetTable)
mas01mc@20 1944 delete[] trackOffsetTable;
mas01cr@0 1945 if(queryCopy)
mas01mc@20 1946 delete[] queryCopy;
mas01cr@121 1947 if(qNorm)
mas01cr@121 1948 delete[] qNorm;
mas01cr@121 1949 if(sNorm)
mas01cr@121 1950 delete[] sNorm;
mas01cr@121 1951 if(sMeanL2)
mas01cr@121 1952 delete[] sMeanL2;
mas01cr@0 1953 if(D)
mas01cr@0 1954 delete[] D;
mas01cr@0 1955 if(DD)
mas01cr@0 1956 delete[] DD;
mas01cr@0 1957 if(timesdata)
mas01mc@20 1958 delete[] timesdata;
mas01cr@0 1959 if(meanDBdur)
mas01mc@20 1960 delete[] meanDBdur;
mas01cr@0 1961
mas01cr@0 1962
mas01cr@0 1963 }
mas01cr@0 1964
mas01mc@20 1965 // Radius search between query and target tracks
mas01mc@20 1966 // efficient implementation based on matched filter
mas01mc@20 1967 // assumes normed shingles
mas01mc@20 1968 // outputs count of retrieved shingles, max retreived = one shingle per query shingle per track
mas01cr@133 1969 void audioDB::trackSequenceQueryRad(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse){
mas01mc@17 1970
mas01cr@27 1971 initTables(dbName, 0, inFile);
mas01mc@17 1972
mas01mc@17 1973 // For each input vector, find the closest pointNN matching output vectors and report
mas01mc@17 1974 // we use stdout in this stub version
mas01mc@17 1975 unsigned numVectors = (statbuf.st_size-sizeof(int))/(sizeof(double)*dbH->dim);
mas01mc@17 1976 double* query = (double*)(indata+sizeof(int));
mas01mc@17 1977 double* queryCopy = 0;
mas01mc@17 1978
mas01mc@17 1979 double qMeanL2;
mas01mc@17 1980 double* sMeanL2;
mas01mc@17 1981
mas01mc@17 1982 unsigned USE_THRESH=0;
mas01mc@17 1983 double SILENCE_THRESH=0;
mas01mc@17 1984 double DIFF_THRESH=0;
mas01mc@17 1985
mas01mc@17 1986 if(!(dbH->flags & O2_FLAG_L2NORM) )
mas01mc@17 1987 error("Database must be L2 normed for sequence query","use -l2norm");
mas01mc@17 1988
mas01cr@60 1989 if(verbosity>1) {
mas01mc@17 1990 cerr << "performing norms ... "; cerr.flush();
mas01cr@60 1991 }
mas01mc@17 1992 unsigned dbVectors = dbH->length/(sizeof(double)*dbH->dim);
mas01mc@18 1993
mas01mc@17 1994 // Make a copy of the query
mas01mc@17 1995 queryCopy = new double[numVectors*dbH->dim];
mas01mc@17 1996 memcpy(queryCopy, query, numVectors*dbH->dim*sizeof(double));
mas01mc@17 1997 qNorm = new double[numVectors];
mas01mc@17 1998 sNorm = new double[dbVectors];
mas01mc@17 1999 sMeanL2=new double[dbH->numFiles];
mas01mc@17 2000 assert(qNorm&&sNorm&&queryCopy&&sMeanL2&&sequenceLength);
mas01mc@17 2001 unitNorm(queryCopy, dbH->dim, numVectors, qNorm);
mas01mc@17 2002 query = queryCopy;
mas01mc@18 2003
mas01mc@17 2004 // Make norm measurements relative to sequenceLength
mas01mc@17 2005 unsigned w = sequenceLength-1;
mas01mc@17 2006 unsigned i,j;
mas01mc@17 2007 double* ps;
mas01mc@17 2008 double tmp1,tmp2;
mas01mc@18 2009
mas01mc@17 2010 // Copy the L2 norm values to core to avoid disk random access later on
mas01mc@17 2011 memcpy(sNorm, l2normTable, dbVectors*sizeof(double));
mas01mc@17 2012 double* snPtr = sNorm;
mas01cr@125 2013 double* qnPtr = qNorm;
mas01mc@17 2014 for(i=0; i<dbH->numFiles; i++){
mas01mc@18 2015 if(trackTable[i]>=sequenceLength){
mas01mc@17 2016 tmp1=*snPtr;
mas01mc@17 2017 j=1;
mas01mc@17 2018 w=sequenceLength-1;
mas01mc@17 2019 while(w--)
mas01mc@17 2020 *snPtr+=snPtr[j++];
mas01mc@17 2021 ps = snPtr+1;
mas01mc@18 2022 w=trackTable[i]-sequenceLength; // +1 - 1
mas01mc@17 2023 while(w--){
mas01mc@17 2024 tmp2=*ps;
mas01mc@17 2025 *ps=*(ps-1)-tmp1+*(ps+sequenceLength-1);
mas01mc@17 2026 tmp1=tmp2;
mas01mc@17 2027 ps++;
mas01mc@17 2028 }
mas01mc@17 2029 ps = snPtr;
mas01mc@18 2030 w=trackTable[i]-sequenceLength+1;
mas01mc@17 2031 while(w--){
mas01mc@17 2032 *ps=sqrt(*ps);
mas01mc@17 2033 ps++;
mas01mc@17 2034 }
mas01mc@17 2035 }
mas01mc@18 2036 snPtr+=trackTable[i];
mas01mc@17 2037 }
mas01mc@17 2038
mas01mc@17 2039 double* pn = sMeanL2;
mas01mc@17 2040 w=dbH->numFiles;
mas01mc@17 2041 while(w--)
mas01mc@17 2042 *pn++=0.0;
mas01mc@17 2043 ps=sNorm;
mas01mc@18 2044 unsigned processedTracks=0;
mas01mc@17 2045 for(i=0; i<dbH->numFiles; i++){
mas01mc@18 2046 if(trackTable[i]>sequenceLength-1){
mas01cr@70 2047 w = trackTable[i]-sequenceLength+1;
mas01mc@17 2048 pn = sMeanL2+i;
mas01mc@17 2049 *pn=0;
mas01mc@17 2050 while(w--)
mas01mc@17 2051 if(*ps>0)
mas01mc@17 2052 *pn+=*ps++;
mas01cr@70 2053 *pn/=trackTable[i]-sequenceLength+1;
mas01mc@17 2054 SILENCE_THRESH+=*pn;
mas01mc@18 2055 processedTracks++;
mas01mc@17 2056 }
mas01mc@18 2057 ps = sNorm + trackTable[i];
mas01mc@17 2058 }
mas01cr@60 2059 if(verbosity>1) {
mas01mc@18 2060 cerr << "processedTracks: " << processedTracks << endl;
mas01cr@60 2061 }
mas01mc@17 2062
mas01mc@18 2063 SILENCE_THRESH/=processedTracks;
mas01mc@17 2064 USE_THRESH=1; // Turn thresholding on
mas01mc@18 2065 DIFF_THRESH=SILENCE_THRESH; // mean shingle power
mas01mc@17 2066 SILENCE_THRESH/=5; // 20% of the mean shingle power is SILENCE
mas01cr@60 2067 if(verbosity>4) {
mas01mc@17 2068 cerr << "silence thresh: " << SILENCE_THRESH;
mas01cr@60 2069 }
mas01mc@17 2070 w=sequenceLength-1;
mas01mc@17 2071 i=1;
mas01cr@125 2072 tmp1=*qnPtr;
mas01mc@17 2073 while(w--)
mas01cr@125 2074 *qnPtr+=qnPtr[i++];
mas01cr@125 2075 ps = qnPtr+1;
mas01mc@17 2076 w=numVectors-sequenceLength; // +1 -1
mas01mc@17 2077 while(w--){
mas01mc@17 2078 tmp2=*ps;
mas01mc@17 2079 *ps=*(ps-1)-tmp1+*(ps+sequenceLength-1);
mas01mc@17 2080 tmp1=tmp2;
mas01mc@17 2081 ps++;
mas01mc@17 2082 }
mas01cr@125 2083 ps = qnPtr;
mas01mc@17 2084 qMeanL2 = 0;
mas01mc@17 2085 w=numVectors-sequenceLength+1;
mas01mc@17 2086 while(w--){
mas01mc@17 2087 *ps=sqrt(*ps);
mas01mc@17 2088 qMeanL2+=*ps++;
mas01mc@17 2089 }
mas01mc@17 2090 qMeanL2 /= numVectors-sequenceLength+1;
mas01mc@17 2091
mas01cr@60 2092 if(verbosity>1) {
mas01mc@17 2093 cerr << "done." << endl;
mas01cr@60 2094 }
mas01mc@17 2095
mas01cr@60 2096 if(verbosity>1) {
mas01mc@18 2097 cerr << "matching tracks..." << endl;
mas01cr@60 2098 }
mas01mc@17 2099
mas01mc@17 2100 assert(pointNN>0 && pointNN<=O2_MAXNN);
mas01mc@18 2101 assert(trackNN>0 && trackNN<=O2_MAXNN);
mas01mc@17 2102
mas01mc@17 2103 // Make temporary dynamic memory for results
mas01mc@18 2104 double trackDistances[trackNN];
mas01mc@18 2105 unsigned trackIDs[trackNN];
mas01mc@18 2106 unsigned trackQIndexes[trackNN];
mas01mc@18 2107 unsigned trackSIndexes[trackNN];
mas01mc@17 2108
mas01mc@17 2109 double distances[pointNN];
mas01mc@17 2110 unsigned qIndexes[pointNN];
mas01mc@17 2111 unsigned sIndexes[pointNN];
mas01mc@17 2112
mas01mc@17 2113
mas01cr@59 2114 unsigned k,l,n,track,trackOffset=0, HOP_SIZE=sequenceHop, wL=sequenceLength;
mas01mc@17 2115 double thisDist;
mas01mc@17 2116
mas01mc@17 2117 for(k=0; k<pointNN; k++){
mas01mc@17 2118 distances[k]=0.0;
mas01mc@17 2119 qIndexes[k]=~0;
mas01mc@17 2120 sIndexes[k]=~0;
mas01mc@17 2121 }
mas01mc@17 2122
mas01mc@18 2123 for(k=0; k<trackNN; k++){
mas01mc@18 2124 trackDistances[k]=0.0;
mas01mc@18 2125 trackQIndexes[k]=~0;
mas01mc@18 2126 trackSIndexes[k]=~0;
mas01mc@18 2127 trackIDs[k]=~0;
mas01mc@17 2128 }
mas01mc@17 2129
mas01mc@17 2130 // Timestamp and durations processing
mas01mc@17 2131 double meanQdur = 0;
mas01mc@17 2132 double* timesdata = 0;
mas01mc@17 2133 double* meanDBdur = 0;
mas01mc@17 2134
mas01mc@17 2135 if(usingTimes && !(dbH->flags & O2_FLAG_TIMES)){
mas01mc@17 2136 cerr << "warning: ignoring query timestamps for non-timestamped database" << endl;
mas01mc@17 2137 usingTimes=0;
mas01mc@17 2138 }
mas01mc@17 2139
mas01mc@17 2140 else if(!usingTimes && (dbH->flags & O2_FLAG_TIMES))
mas01mc@17 2141 cerr << "warning: no timestamps given for query. Ignoring database timestamps." << endl;
mas01mc@17 2142
mas01mc@17 2143 else if(usingTimes && (dbH->flags & O2_FLAG_TIMES)){
mas01mc@17 2144 timesdata = new double[numVectors];
mas01mc@17 2145 assert(timesdata);
mas01mc@17 2146 insertTimeStamps(numVectors, timesFile, timesdata);
mas01mc@17 2147 // Calculate durations of points
mas01mc@17 2148 for(k=0; k<numVectors-1; k++){
mas01mc@17 2149 timesdata[k]=timesdata[k+1]-timesdata[k];
mas01mc@17 2150 meanQdur+=timesdata[k];
mas01mc@17 2151 }
mas01mc@17 2152 meanQdur/=k;
mas01cr@60 2153 if(verbosity>1) {
mas01mc@17 2154 cerr << "mean query file duration: " << meanQdur << endl;
mas01cr@60 2155 }
mas01mc@17 2156 meanDBdur = new double[dbH->numFiles];
mas01mc@17 2157 assert(meanDBdur);
mas01mc@17 2158 for(k=0; k<dbH->numFiles; k++){
mas01mc@17 2159 meanDBdur[k]=0.0;
mas01mc@18 2160 for(j=0; j<trackTable[k]-1 ; j++)
mas01mc@17 2161 meanDBdur[k]+=timesTable[j+1]-timesTable[j];
mas01mc@17 2162 meanDBdur[k]/=j;
mas01mc@17 2163 }
mas01mc@17 2164 }
mas01mc@17 2165
mas01mc@17 2166 if(usingQueryPoint)
mas01mc@17 2167 if(queryPoint>numVectors || queryPoint>numVectors-wL+1)
mas01mc@17 2168 error("queryPoint > numVectors-wL+1 in query");
mas01mc@17 2169 else{
mas01cr@60 2170 if(verbosity>1) {
mas01mc@17 2171 cerr << "query point: " << queryPoint << endl; cerr.flush();
mas01cr@60 2172 }
mas01mc@17 2173 query=query+queryPoint*dbH->dim;
mas01cr@125 2174 qnPtr=qnPtr+queryPoint;
mas01mc@17 2175 numVectors=wL;
mas01mc@17 2176 }
mas01mc@17 2177
mas01mc@17 2178 double ** D = 0; // Differences query and target
mas01mc@17 2179 double ** DD = 0; // Matched filter distance
mas01mc@17 2180
mas01mc@17 2181 D = new double*[numVectors];
mas01mc@17 2182 assert(D);
mas01mc@17 2183 DD = new double*[numVectors];
mas01mc@17 2184 assert(DD);
mas01mc@17 2185
mas01mc@17 2186 gettimeofday(&tv1, NULL);
mas01mc@18 2187 processedTracks=0;
mas01mc@18 2188 unsigned successfulTracks=0;
mas01mc@17 2189
mas01mc@17 2190 double* qp;
mas01mc@17 2191 double* sp;
mas01mc@17 2192 double* dp;
mas01mc@17 2193
mas01mc@18 2194 // build track offset table
mas01mc@18 2195 unsigned *trackOffsetTable = new unsigned[dbH->numFiles];
mas01mc@18 2196 unsigned cumTrack=0;
mas01mc@18 2197 unsigned trackIndexOffset;
mas01mc@17 2198 for(k=0; k<dbH->numFiles;k++){
mas01mc@18 2199 trackOffsetTable[k]=cumTrack;
mas01mc@18 2200 cumTrack+=trackTable[k]*dbH->dim;
mas01mc@17 2201 }
mas01mc@17 2202
mas01mc@17 2203 char nextKey [MAXSTR];
mas01mc@17 2204
mas01mc@17 2205 // chi^2 statistics
mas01mc@17 2206 double sampleCount = 0;
mas01mc@17 2207 double sampleSum = 0;
mas01mc@17 2208 double logSampleSum = 0;
mas01mc@17 2209 double minSample = 1e9;
mas01mc@17 2210 double maxSample = 0;
mas01mc@17 2211
mas01mc@17 2212 // Track loop
mas01mc@18 2213 for(processedTracks=0, track=0 ; processedTracks < dbH->numFiles ; track++, processedTracks++){
mas01mc@17 2214
mas01mc@18 2215 // get trackID from file if using a control file
mas01mc@18 2216 if(trackFile){
mas01mc@18 2217 if(!trackFile->eof()){
mas01mc@18 2218 trackFile->getline(nextKey,MAXSTR);
mas01mc@18 2219 track=getKeyPos(nextKey);
mas01mc@17 2220 }
mas01mc@17 2221 else
mas01mc@17 2222 break;
mas01mc@17 2223 }
mas01mc@17 2224
mas01mc@18 2225 trackOffset=trackOffsetTable[track]; // numDoubles offset
mas01mc@18 2226 trackIndexOffset=trackOffset/dbH->dim; // numVectors offset
mas01mc@17 2227
mas01cr@70 2228 if(sequenceLength<=trackTable[track]){ // test for short sequences
mas01mc@17 2229
mas01cr@60 2230 if(verbosity>7) {
mas01mc@18 2231 cerr << track << "." << trackIndexOffset << "." << trackTable[track] << " | ";cerr.flush();
mas01cr@60 2232 }
mas01cr@60 2233
mas01mc@17 2234 // Sum products matrix
mas01mc@17 2235 for(j=0; j<numVectors;j++){
mas01mc@18 2236 D[j]=new double[trackTable[track]];
mas01mc@17 2237 assert(D[j]);
mas01mc@17 2238
mas01mc@17 2239 }
mas01mc@17 2240
mas01mc@17 2241 // Matched filter matrix
mas01mc@17 2242 for(j=0; j<numVectors;j++){
mas01mc@18 2243 DD[j]=new double[trackTable[track]];
mas01mc@17 2244 assert(DD[j]);
mas01mc@17 2245 }
mas01mc@17 2246
mas01mc@17 2247 // Dot product
mas01mc@17 2248 for(j=0; j<numVectors; j++)
mas01mc@18 2249 for(k=0; k<trackTable[track]; k++){
mas01mc@17 2250 qp=query+j*dbH->dim;
mas01mc@18 2251 sp=dataBuf+trackOffset+k*dbH->dim;
mas01mc@17 2252 DD[j][k]=0.0; // Initialize matched filter array
mas01mc@17 2253 dp=&D[j][k]; // point to correlation cell j,k
mas01mc@17 2254 *dp=0.0; // initialize correlation cell
mas01mc@17 2255 l=dbH->dim; // size of vectors
mas01mc@17 2256 while(l--)
mas01mc@17 2257 *dp+=*qp++**sp++;
mas01mc@17 2258 }
mas01mc@17 2259
mas01mc@17 2260 // Matched Filter
mas01mc@17 2261 // HOP SIZE == 1
mas01mc@17 2262 double* spd;
mas01mc@17 2263 if(HOP_SIZE==1){ // HOP_SIZE = shingleHop
mas01mc@17 2264 for(w=0; w<wL; w++)
mas01mc@17 2265 for(j=0; j<numVectors-w; j++){
mas01mc@17 2266 sp=DD[j];
mas01mc@17 2267 spd=D[j+w]+w;
mas01mc@18 2268 k=trackTable[track]-w;
mas01mc@17 2269 while(k--)
mas01mc@17 2270 *sp+++=*spd++;
mas01mc@17 2271 }
mas01mc@17 2272 }
mas01mc@17 2273
mas01mc@17 2274 else{ // HOP_SIZE != 1
mas01mc@17 2275 for(w=0; w<wL; w++)
mas01mc@17 2276 for(j=0; j<numVectors-w; j+=HOP_SIZE){
mas01mc@17 2277 sp=DD[j];
mas01mc@17 2278 spd=D[j+w]+w;
mas01mc@18 2279 for(k=0; k<trackTable[track]-w; k+=HOP_SIZE){
mas01mc@17 2280 *sp+=*spd;
mas01mc@17 2281 sp+=HOP_SIZE;
mas01mc@17 2282 spd+=HOP_SIZE;
mas01mc@17 2283 }
mas01mc@17 2284 }
mas01mc@17 2285 }
mas01mc@17 2286
mas01cr@60 2287 if(verbosity>3 && usingTimes) {
mas01mc@18 2288 cerr << "meanQdur=" << meanQdur << " meanDBdur=" << meanDBdur[track] << endl;
mas01mc@17 2289 cerr.flush();
mas01mc@17 2290 }
mas01mc@17 2291
mas01mc@17 2292 if(!usingTimes ||
mas01mc@17 2293 (usingTimes
mas01mc@18 2294 && fabs(meanDBdur[track]-meanQdur)<meanQdur*timesTol)){
mas01mc@17 2295
mas01cr@60 2296 if(verbosity>3 && usingTimes) {
mas01mc@17 2297 cerr << "within duration tolerance." << endl;
mas01mc@17 2298 cerr.flush();
mas01mc@17 2299 }
mas01mc@17 2300
mas01mc@17 2301 // Search for minimum distance by shingles (concatenated vectors)
mas01cr@70 2302 for(j=0;j<=numVectors-wL;j+=HOP_SIZE)
mas01cr@70 2303 for(k=0;k<=trackTable[track]-wL;k+=HOP_SIZE){
mas01cr@125 2304 thisDist=2-(2/(qnPtr[j]*sNorm[trackIndexOffset+k]))*DD[j][k];
mas01cr@60 2305 if(verbosity>10) {
mas01cr@125 2306 cerr << thisDist << " " << qnPtr[j] << " " << sNorm[trackIndexOffset+k] << endl;
mas01cr@60 2307 }
mas01mc@17 2308 // Gather chi^2 statistics
mas01mc@17 2309 if(thisDist<minSample)
mas01mc@17 2310 minSample=thisDist;
mas01mc@17 2311 else if(thisDist>maxSample)
mas01mc@17 2312 maxSample=thisDist;
mas01mc@17 2313 if(thisDist>1e-9){
mas01mc@17 2314 sampleCount++;
mas01mc@17 2315 sampleSum+=thisDist;
mas01mc@17 2316 logSampleSum+=log(thisDist);
mas01mc@17 2317 }
mas01mc@17 2318
mas01cr@125 2319 // diffL2 = fabs(qnPtr[j] - sNorm[trackIndexOffset+k]);
mas01mc@17 2320 // Power test
mas01mc@17 2321 if(!USE_THRESH ||
mas01mc@17 2322 // Threshold on mean L2 of Q and S sequences
mas01cr@125 2323 (USE_THRESH && qnPtr[j]>SILENCE_THRESH && sNorm[trackIndexOffset+k]>SILENCE_THRESH &&
mas01mc@17 2324 // Are both query and target windows above mean energy?
mas01cr@125 2325 (qnPtr[j]>qMeanL2*.25 && sNorm[trackIndexOffset+k]>sMeanL2[track]*.25))) // && diffL2 < DIFF_THRESH )))
mas01mc@17 2326 thisDist=thisDist; // Computed above
mas01mc@17 2327 else
mas01mc@17 2328 thisDist=1000000.0;
mas01mc@17 2329 if(thisDist>=0 && thisDist<=radius){
mas01mc@17 2330 distances[0]++; // increment count
mas01mc@18 2331 break; // only need one track point per query point
mas01mc@17 2332 }
mas01mc@17 2333 }
mas01mc@17 2334 // How many points were below threshold ?
mas01mc@17 2335 thisDist=distances[0];
mas01mc@17 2336
mas01mc@17 2337 // Let's see the distances then...
mas01cr@60 2338 if(verbosity>3) {
mas01mc@18 2339 cerr << fileTable+track*O2_FILETABLESIZE << " " << thisDist << endl;
mas01cr@60 2340 }
mas01mc@17 2341
mas01mc@18 2342 // All the track stuff goes here
mas01mc@18 2343 n=trackNN;
mas01mc@17 2344 while(n--){
mas01mc@18 2345 if(thisDist>trackDistances[n]){
mas01mc@18 2346 if((n==0 || thisDist<=trackDistances[n-1])){
mas01mc@17 2347 // Copy all values above up the queue
mas01mc@18 2348 for( l=trackNN-1 ; l > n ; l--){
mas01mc@18 2349 trackDistances[l]=trackDistances[l-1];
mas01mc@18 2350 trackQIndexes[l]=trackQIndexes[l-1];
mas01mc@18 2351 trackSIndexes[l]=trackSIndexes[l-1];
mas01mc@18 2352 trackIDs[l]=trackIDs[l-1];
mas01mc@17 2353 }
mas01mc@18 2354 trackDistances[n]=thisDist;
mas01mc@18 2355 trackQIndexes[n]=qIndexes[0];
mas01mc@18 2356 trackSIndexes[n]=sIndexes[0];
mas01mc@18 2357 successfulTracks++;
mas01mc@18 2358 trackIDs[n]=track;
mas01mc@17 2359 break;
mas01mc@17 2360 }
mas01mc@17 2361 }
mas01mc@17 2362 else
mas01mc@17 2363 break;
mas01mc@17 2364 }
mas01mc@17 2365 } // Duration match
mas01mc@17 2366
mas01mc@18 2367 // Clean up current track
mas01mc@17 2368 if(D!=NULL){
mas01mc@17 2369 for(j=0; j<numVectors; j++)
mas01mc@17 2370 delete[] D[j];
mas01mc@17 2371 }
mas01mc@17 2372
mas01mc@17 2373 if(DD!=NULL){
mas01mc@17 2374 for(j=0; j<numVectors; j++)
mas01mc@17 2375 delete[] DD[j];
mas01mc@17 2376 }
mas01mc@17 2377 }
mas01mc@18 2378 // per-track reset array values
mas01mc@17 2379 for(unsigned k=0; k<pointNN; k++){
mas01mc@17 2380 distances[k]=0.0;
mas01mc@17 2381 qIndexes[k]=~0;
mas01mc@17 2382 sIndexes[k]=~0;
mas01mc@17 2383 }
mas01mc@17 2384 }
mas01mc@17 2385
mas01mc@17 2386 gettimeofday(&tv2,NULL);
mas01cr@60 2387 if(verbosity>1) {
mas01mc@18 2388 cerr << endl << "processed tracks :" << processedTracks << " matched tracks: " << successfulTracks << " elapsed time:"
mas01mc@17 2389 << ( tv2.tv_sec*1000 + tv2.tv_usec/1000 ) - ( tv1.tv_sec*1000+tv1.tv_usec/1000 ) << " msec" << endl;
mas01mc@17 2390 cerr << "sampleCount: " << sampleCount << " sampleSum: " << sampleSum << " logSampleSum: " << logSampleSum
mas01mc@17 2391 << " minSample: " << minSample << " maxSample: " << maxSample << endl;
mas01mc@17 2392 }
mas01mc@17 2393
mas01cr@133 2394 if(adbQueryResponse==0){
mas01cr@60 2395 if(verbosity>1) {
mas01mc@17 2396 cerr<<endl;
mas01cr@60 2397 }
mas01mc@17 2398 // Output answer
mas01mc@17 2399 // Loop over nearest neighbours
mas01mc@18 2400 for(k=0; k < min(trackNN,successfulTracks); k++)
mas01mc@18 2401 cout << fileTable+trackIDs[k]*O2_FILETABLESIZE << " " << trackDistances[k] << endl;
mas01mc@17 2402 }
mas01mc@17 2403 else{ // Process Web Services Query
mas01mc@18 2404 int listLen = min(trackNN, processedTracks);
mas01cr@133 2405 adbQueryResponse->result.__sizeRlist=listLen;
mas01cr@133 2406 adbQueryResponse->result.__sizeDist=listLen;
mas01cr@133 2407 adbQueryResponse->result.__sizeQpos=listLen;
mas01cr@133 2408 adbQueryResponse->result.__sizeSpos=listLen;
mas01cr@133 2409 adbQueryResponse->result.Rlist= new char*[listLen];
mas01cr@133 2410 adbQueryResponse->result.Dist = new double[listLen];
mas01cr@133 2411 adbQueryResponse->result.Qpos = new unsigned int[listLen];
mas01cr@133 2412 adbQueryResponse->result.Spos = new unsigned int[listLen];
mas01cr@133 2413 for(k=0; k<(unsigned)adbQueryResponse->result.__sizeRlist; k++){
mas01cr@133 2414 adbQueryResponse->result.Rlist[k]=new char[O2_MAXFILESTR];
mas01cr@133 2415 adbQueryResponse->result.Dist[k]=trackDistances[k];
mas01cr@133 2416 adbQueryResponse->result.Qpos[k]=trackQIndexes[k];
mas01cr@133 2417 adbQueryResponse->result.Spos[k]=trackSIndexes[k];
mas01cr@133 2418 sprintf(adbQueryResponse->result.Rlist[k], "%s", fileTable+trackIDs[k]*O2_FILETABLESIZE);
mas01mc@17 2419 }
mas01mc@17 2420 }
mas01mc@17 2421
mas01mc@17 2422 // Clean up
mas01mc@18 2423 if(trackOffsetTable)
mas01mc@18 2424 delete[] trackOffsetTable;
mas01mc@17 2425 if(queryCopy)
mas01mc@17 2426 delete[] queryCopy;
mas01cr@121 2427 if(qNorm)
mas01cr@121 2428 delete[] qNorm;
mas01cr@121 2429 if(sNorm)
mas01cr@121 2430 delete[] sNorm;
mas01cr@121 2431 if(sMeanL2)
mas01cr@121 2432 delete[] sMeanL2;
mas01mc@17 2433 if(D)
mas01mc@17 2434 delete[] D;
mas01mc@17 2435 if(DD)
mas01mc@17 2436 delete[] DD;
mas01mc@17 2437 if(timesdata)
mas01mc@17 2438 delete[] timesdata;
mas01mc@17 2439 if(meanDBdur)
mas01mc@17 2440 delete[] meanDBdur;
mas01mc@17 2441
mas01mc@17 2442
mas01mc@17 2443 }
mas01mc@17 2444
mas01cr@0 2445 // Unit norm block of features
mas01cr@0 2446 void audioDB::unitNorm(double* X, unsigned dim, unsigned n, double* qNorm){
mas01cr@0 2447 unsigned d;
mas01cr@59 2448 double L2, *p;
mas01cr@60 2449 if(verbosity>2) {
mas01cr@0 2450 cerr << "norming " << n << " vectors...";cerr.flush();
mas01cr@60 2451 }
mas01cr@0 2452 while(n--){
mas01cr@0 2453 p=X;
mas01cr@0 2454 L2=0.0;
mas01cr@0 2455 d=dim;
mas01cr@0 2456 while(d--){
mas01cr@0 2457 L2+=*p**p;
mas01cr@0 2458 p++;
mas01cr@0 2459 }
mas01mc@17 2460 /* L2=sqrt(L2);*/
mas01cr@0 2461 if(qNorm)
mas01cr@0 2462 *qNorm++=L2;
mas01mc@17 2463 /*
mas01cr@0 2464 oneOverL2 = 1.0/L2;
mas01cr@0 2465 d=dim;
mas01cr@0 2466 while(d--){
mas01cr@0 2467 *X*=oneOverL2;
mas01cr@0 2468 X++;
mas01mc@17 2469 */
mas01mc@17 2470 X+=dim;
mas01cr@0 2471 }
mas01cr@60 2472 if(verbosity>2) {
mas01cr@0 2473 cerr << "done..." << endl;
mas01cr@60 2474 }
mas01cr@0 2475 }
mas01cr@0 2476
mas01cr@0 2477 // Unit norm block of features
mas01cr@0 2478 void audioDB::unitNormAndInsertL2(double* X, unsigned dim, unsigned n, unsigned append=0){
mas01cr@0 2479 unsigned d;
mas01cr@59 2480 double *p;
mas01cr@0 2481 unsigned nn = n;
mas01cr@0 2482
mas01cr@0 2483 assert(l2normTable);
mas01cr@0 2484
mas01cr@0 2485 if( !append && (dbH->flags & O2_FLAG_L2NORM) )
mas01cr@0 2486 error("Database is already L2 normed", "automatic norm on insert is enabled");
mas01cr@0 2487
mas01cr@60 2488 if(verbosity>2) {
mas01cr@0 2489 cerr << "norming " << n << " vectors...";cerr.flush();
mas01cr@60 2490 }
mas01cr@0 2491
mas01cr@0 2492 double* l2buf = new double[n];
mas01cr@0 2493 double* l2ptr = l2buf;
mas01cr@0 2494 assert(l2buf);
mas01cr@0 2495 assert(X);
mas01cr@0 2496
mas01cr@0 2497 while(nn--){
mas01cr@0 2498 p=X;
mas01cr@0 2499 *l2ptr=0.0;
mas01cr@0 2500 d=dim;
mas01cr@0 2501 while(d--){
mas01cr@0 2502 *l2ptr+=*p**p;
mas01cr@0 2503 p++;
mas01cr@0 2504 }
mas01mc@17 2505 l2ptr++;
mas01mc@17 2506 /*
mas01mc@17 2507 oneOverL2 = 1.0/(*l2ptr++);
mas01mc@17 2508 d=dim;
mas01mc@17 2509 while(d--){
mas01cr@0 2510 *X*=oneOverL2;
mas01cr@0 2511 X++;
mas01mc@17 2512 }
mas01mc@17 2513 */
mas01mc@17 2514 X+=dim;
mas01cr@0 2515 }
mas01cr@0 2516 unsigned offset;
mas01cr@84 2517 if(append) {
mas01cr@84 2518 // FIXME: a hack, a very palpable hack: the vectors have already
mas01cr@84 2519 // been inserted, and dbH->length has already been updated. We
mas01cr@84 2520 // need to subtract off again the number of vectors that we've
mas01cr@84 2521 // inserted this time...
mas01cr@84 2522 offset=(dbH->length/(dbH->dim*sizeof(double)))-n; // number of vectors
mas01cr@84 2523 } else {
mas01cr@0 2524 offset=0;
mas01cr@84 2525 }
mas01cr@0 2526 memcpy(l2normTable+offset, l2buf, n*sizeof(double));
mas01cr@0 2527 if(l2buf)
mas01mc@17 2528 delete[] l2buf;
mas01cr@60 2529 if(verbosity>2) {
mas01cr@0 2530 cerr << "done..." << endl;
mas01cr@60 2531 }
mas01cr@0 2532 }
mas01cr@0 2533
mas01cr@0 2534
mas01cr@0 2535 // Start an audioDB server on the host
mas01cr@0 2536 void audioDB::startServer(){
mas01cr@0 2537 struct soap soap;
mas01cr@0 2538 int m, s; // master and slave sockets
mas01cr@0 2539 soap_init(&soap);
mas01cr@92 2540 // FIXME: largely this use of SO_REUSEADDR is to make writing (and
mas01cr@92 2541 // running) test cases more convenient, so that multiple test runs
mas01cr@92 2542 // in close succession don't fail because of a bin() error.
mas01cr@92 2543 // Investigate whether there are any potential drawbacks in this,
mas01cr@92 2544 // and also whether there's a better way to write the tests. --
mas01cr@92 2545 // CSR, 2007-10-03
mas01cr@92 2546 soap.bind_flags |= SO_REUSEADDR;
mas01cr@0 2547 m = soap_bind(&soap, NULL, port, 100);
mas01cr@0 2548 if (m < 0)
mas01cr@0 2549 soap_print_fault(&soap, stderr);
mas01cr@0 2550 else
mas01cr@0 2551 {
mas01cr@0 2552 fprintf(stderr, "Socket connection successful: master socket = %d\n", m);
mas01cr@0 2553 for (int i = 1; ; i++)
mas01cr@0 2554 {
mas01cr@0 2555 s = soap_accept(&soap);
mas01cr@0 2556 if (s < 0)
mas01cr@0 2557 {
mas01cr@0 2558 soap_print_fault(&soap, stderr);
mas01cr@0 2559 break;
mas01cr@0 2560 }
mas01cr@75 2561 fprintf(stderr, "%d: accepted connection from IP=%lu.%lu.%lu.%lu socket=%d\n", i,
mas01cr@0 2562 (soap.ip >> 24)&0xFF, (soap.ip >> 16)&0xFF, (soap.ip >> 8)&0xFF, soap.ip&0xFF, s);
mas01cr@0 2563 if (soap_serve(&soap) != SOAP_OK) // process RPC request
mas01cr@0 2564 soap_print_fault(&soap, stderr); // print error
mas01cr@0 2565 fprintf(stderr, "request served\n");
mas01cr@0 2566 soap_destroy(&soap); // clean up class instances
mas01cr@0 2567 soap_end(&soap); // clean up everything and close socket
mas01cr@0 2568 }
mas01cr@0 2569 }
mas01cr@0 2570 soap_done(&soap); // close master socket and detach environment
mas01cr@0 2571 }
mas01cr@0 2572
mas01cr@0 2573
mas01cr@0 2574 // web services
mas01cr@0 2575
mas01cr@0 2576 // SERVER SIDE
mas01cr@133 2577 int adb__status(struct soap* soap, xsd__string dbName, adb__statusResponse &adbStatusResponse){
mas01cr@21 2578 char* const argv[]={"audioDB",COM_STATUS,"-d",dbName};
mas01cr@21 2579 const unsigned argc = 4;
mas01cr@77 2580 try {
mas01cr@133 2581 audioDB(argc, argv, &adbStatusResponse);
mas01cr@77 2582 return SOAP_OK;
mas01cr@77 2583 } catch(char *err) {
mas01cr@77 2584 soap_receiver_fault(soap, err, "");
mas01cr@77 2585 return SOAP_FAULT;
mas01cr@77 2586 }
mas01cr@0 2587 }
mas01cr@0 2588
mas01cr@0 2589 // Literal translation of command line to web service
mas01cr@0 2590
mas01cr@133 2591 int adb__query(struct soap* soap, xsd__string dbName, xsd__string qKey, xsd__string keyList, xsd__string timesFileName, xsd__int qType, xsd__int qPos, xsd__int pointNN, xsd__int trackNN, xsd__int seqLen, adb__queryResponse &adbQueryResponse){
mas01cr@0 2592 char queryType[256];
mas01cr@0 2593 for(int k=0; k<256; k++)
mas01cr@0 2594 queryType[k]='\0';
mas01cr@105 2595 if(qType == O2_POINT_QUERY)
mas01cr@0 2596 strncpy(queryType, "point", strlen("point"));
mas01cr@105 2597 else if (qType == O2_SEQUENCE_QUERY)
mas01cr@0 2598 strncpy(queryType, "sequence", strlen("sequence"));
mas01cr@105 2599 else if(qType == O2_TRACK_QUERY)
mas01mc@18 2600 strncpy(queryType,"track", strlen("track"));
mas01cr@0 2601 else
mas01cr@0 2602 strncpy(queryType, "", strlen(""));
mas01cr@0 2603
mas01cr@0 2604 if(pointNN==0)
mas01cr@0 2605 pointNN=10;
mas01mc@18 2606 if(trackNN==0)
mas01mc@18 2607 trackNN=10;
mas01cr@0 2608 if(seqLen==0)
mas01cr@0 2609 seqLen=16;
mas01cr@0 2610
mas01cr@0 2611 char qPosStr[256];
mas01cr@0 2612 sprintf(qPosStr, "%d", qPos);
mas01cr@0 2613 char pointNNStr[256];
mas01cr@0 2614 sprintf(pointNNStr,"%d",pointNN);
mas01mc@18 2615 char trackNNStr[256];
mas01mc@18 2616 sprintf(trackNNStr,"%d",trackNN);
mas01cr@0 2617 char seqLenStr[256];
mas01cr@0 2618 sprintf(seqLenStr,"%d",seqLen);
mas01cr@0 2619
mas01cr@0 2620 const char* argv[] ={
mas01cr@0 2621 "./audioDB",
mas01cr@0 2622 COM_QUERY,
mas01cr@0 2623 queryType, // Need to pass a parameter
mas01cr@0 2624 COM_DATABASE,
mas01cr@166 2625 ENSURE_STRING(dbName),
mas01cr@0 2626 COM_FEATURES,
mas01cr@166 2627 ENSURE_STRING(qKey),
mas01cr@0 2628 COM_KEYLIST,
mas01cr@166 2629 ENSURE_STRING(keyList),
mas01cr@0 2630 COM_TIMES,
mas01cr@166 2631 ENSURE_STRING(timesFileName),
mas01cr@0 2632 COM_QPOINT,
mas01cr@0 2633 qPosStr,
mas01cr@0 2634 COM_POINTNN,
mas01cr@0 2635 pointNNStr,
mas01mc@18 2636 COM_TRACKNN,
mas01mc@18 2637 trackNNStr, // Need to pass a parameter
mas01cr@0 2638 COM_SEQLEN,
mas01cr@0 2639 seqLenStr
mas01cr@0 2640 };
mas01cr@0 2641
mas01cr@0 2642 const unsigned argc = 19;
mas01cr@79 2643 try {
mas01cr@133 2644 audioDB(argc, (char* const*)argv, &adbQueryResponse);
mas01cr@79 2645 return SOAP_OK;
mas01cr@79 2646 } catch (char *err) {
mas01cr@79 2647 soap_receiver_fault(soap, err, "");
mas01cr@79 2648 return SOAP_FAULT;
mas01cr@79 2649 }
mas01cr@0 2650 }
mas01cr@0 2651
mas01cr@0 2652 int main(const unsigned argc, char* const argv[]){
mas01cr@0 2653 audioDB(argc, argv);
mas01cr@0 2654 }
mas01cr@104 2655