annotate audioDB.cpp @ 53:944f05e65a58

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