annotate query.cpp @ 431:8632cd387e24 api-inversion

Punishment gluttony. Continue teasing out vague orthogonalities by beginning the task of using an adb_query_parameters_t. This does have the benefit of making the distance calculation clearer, and we begin to see the shape of a putative audiodb_query() emerging from the shrapnel of audioDB::query. (Only the general shape; the detail is still a long, long way away).
author mas01cr
date Wed, 24 Dec 2008 10:55:40 +0000
parents 2d14d21f826b
children 681837f7c903
rev   line source
mas01cr@239 1 #include "audioDB.h"
mas01cr@239 2 #include "reporter.h"
mas01cr@239 3
mas01cr@422 4 #include "audioDB-internals.h"
mas01cr@422 5 #include "accumulators.h"
mas01cr@422 6
mas01cr@425 7 static bool audiodb_powers_acceptable(adb_query_refine_t *r, double p1, double p2) {
mas01cr@425 8 if (r->flags & ADB_REFINE_ABSOLUTE_THRESHOLD) {
mas01cr@425 9 if ((p1 < r->absolute_threshold) || (p2 < r->absolute_threshold)) {
mas01cr@239 10 return false;
mas01cr@239 11 }
mas01cr@239 12 }
mas01cr@425 13 if (r->flags & ADB_REFINE_RELATIVE_THRESHOLD) {
mas01cr@425 14 if (fabs(p1-p2) > fabs(r->relative_threshold)) {
mas01cr@239 15 return false;
mas01cr@239 16 }
mas01cr@239 17 }
mas01cr@239 18 return true;
mas01cr@239 19 }
mas01cr@239 20
mas01cr@239 21 void audioDB::query(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse) {
mas01cr@425 22
mas01cr@431 23 // init database tables and dbH first
mas01cr@431 24 if(query_from_key)
mas01cr@431 25 initTables(dbName);
mas01cr@431 26 else
mas01cr@431 27 initTables(dbName, inFile);
mas01cr@431 28
mas01cr@425 29 adb_query_refine_t refine;
mas01cr@431 30 adb_query_parameters_t params;
mas01cr@425 31 refine.flags = 0;
mas01cr@425 32 /* FIXME: trackFile / ADB_REFINE_KEYLIST */
mas01cr@425 33 if(radius) {
mas01cr@425 34 refine.flags |= ADB_REFINE_RADIUS;
mas01cr@425 35 refine.radius = radius;
mas01cr@425 36 }
mas01cr@425 37 if(use_absolute_threshold) {
mas01cr@425 38 refine.flags |= ADB_REFINE_ABSOLUTE_THRESHOLD;
mas01cr@425 39 refine.absolute_threshold = absolute_threshold;
mas01cr@425 40 }
mas01cr@425 41 if(use_relative_threshold) {
mas01cr@425 42 refine.flags |= ADB_REFINE_RELATIVE_THRESHOLD;
mas01cr@425 43 refine.relative_threshold = relative_threshold;
mas01cr@425 44 }
mas01cr@425 45 if(usingTimes) {
mas01cr@425 46 refine.flags |= ADB_REFINE_DURATION_RATIO;
mas01cr@425 47 refine.duration_ratio = timesTol;
mas01cr@425 48 }
mas01cr@425 49 /* FIXME: not sure about this any more; maybe it belongs in query_id */
mas01cr@425 50 if(sequenceHop != 1) {
mas01cr@425 51 refine.flags |= ADB_REFINE_HOP_SIZE;
mas01cr@425 52 refine.hopsize = sequenceHop;
mas01cr@425 53 }
mas01cr@425 54
mas01cr@431 55 switch(queryType) {
mas01cr@431 56 case O2_POINT_QUERY:
mas01cr@431 57 sequenceLength = 1;
mas01cr@431 58 params.accumulation = ADB_ACCUMULATION_DB;
mas01cr@431 59 params.distance = ADB_DISTANCE_DOT_PRODUCT;
mas01cr@431 60 params.npoints = pointNN;
mas01cr@431 61 params.ntracks = 0;
mas01cr@431 62 reporter = new pointQueryReporter< std::greater < NNresult > >(pointNN);
mas01cr@431 63 break;
mas01cr@431 64 case O2_TRACK_QUERY:
mas01cr@431 65 sequenceLength = 1;
mas01cr@431 66 params.accumulation = ADB_ACCUMULATION_PER_TRACK;
mas01cr@431 67 params.distance = ADB_DISTANCE_DOT_PRODUCT;
mas01cr@431 68 params.npoints = pointNN;
mas01cr@431 69 params.ntracks = trackNN;
mas01cr@431 70 reporter = new trackAveragingReporter< std::greater< NNresult > >(pointNN, trackNN, dbH->numFiles);
mas01cr@431 71 break;
mas01cr@431 72 case O2_SEQUENCE_QUERY:
mas01cr@431 73 case O2_N_SEQUENCE_QUERY:
mas01cr@431 74 params.accumulation = ADB_ACCUMULATION_PER_TRACK;
mas01cr@431 75 params.distance = no_unit_norming ? ADB_DISTANCE_EUCLIDEAN : ADB_DISTANCE_EUCLIDEAN_NORMED;
mas01cr@431 76 params.npoints = pointNN;
mas01cr@431 77 params.ntracks = trackNN;
mas01cr@431 78 switch(queryType) {
mas01cr@431 79 case O2_SEQUENCE_QUERY:
mas01cr@431 80 if(!(refine.flags & ADB_REFINE_RADIUS)) {
mas01cr@431 81 reporter = new trackAveragingReporter< std::less< NNresult > >(pointNN, trackNN, dbH->numFiles);
mas01cr@431 82 } else if (index_exists(dbName, radius, sequenceLength)) {
mas01cr@431 83 char* indexName = index_get_name(dbName, radius, sequenceLength);
mas01cr@431 84 lsh = index_allocate(indexName, false);
mas01cr@431 85 reporter = new trackSequenceQueryRadReporter(trackNN, index_to_trackID(lsh->get_maxp(), lsh_n_point_bits)+1);
mas01cr@431 86 delete[] indexName;
mas01cr@431 87 } else {
mas01cr@431 88 reporter = new trackSequenceQueryRadReporter(trackNN, dbH->numFiles);
mas01cr@431 89 }
mas01cr@431 90 break;
mas01cr@431 91 case O2_N_SEQUENCE_QUERY:
mas01cr@431 92 if(!(refine.flags & ADB_REFINE_RADIUS)) {
mas01cr@431 93 reporter = new trackSequenceQueryNNReporter< std::less < NNresult > >(pointNN, trackNN, dbH->numFiles);
mas01cr@431 94 } else if (index_exists(dbName, radius, sequenceLength)){
mas01cr@431 95 char* indexName = index_get_name(dbName, radius, sequenceLength);
mas01cr@431 96 lsh = index_allocate(indexName, false);
mas01cr@431 97 reporter = new trackSequenceQueryRadNNReporter(pointNN,trackNN, index_to_trackID(lsh->get_maxp(), lsh_n_point_bits)+1);
mas01cr@431 98 delete[] indexName;
mas01cr@431 99 } else {
mas01cr@431 100 reporter = new trackSequenceQueryRadNNReporter(pointNN,trackNN, dbH->numFiles);
mas01cr@431 101 }
mas01cr@431 102 break;
mas01cr@431 103 }
mas01cr@431 104 break;
mas01cr@431 105 case O2_ONE_TO_ONE_N_SEQUENCE_QUERY:
mas01cr@431 106 params.accumulation = ADB_ACCUMULATION_ONE_TO_ONE;
mas01cr@431 107 params.distance = ADB_DISTANCE_EUCLIDEAN_NORMED;
mas01cr@431 108 params.npoints = 0;
mas01cr@431 109 params.ntracks = 0;
mas01cr@431 110 break;
mas01cr@431 111 default:
mas01cr@431 112 error("unrecognized queryType");
mas01cr@431 113 }
mas01mc@292 114
mas01mc@292 115 // keyKeyPos requires dbH to be initialized
mas01cr@430 116 if(query_from_key && (!key || (query_from_key_index = audiodb_key_index(adb, key)) == (uint32_t) -1))
mas01cr@430 117 error("Query key not found", key);
mas01cr@431 118
mas01cr@431 119 switch(params.distance) {
mas01cr@431 120 case ADB_DISTANCE_DOT_PRODUCT:
mas01cr@431 121 switch(params.accumulation) {
mas01cr@431 122 case ADB_ACCUMULATION_DB:
mas01cr@431 123 accumulator = new DBAccumulator<adb_result_dist_gt>(params.npoints);
mas01cr@431 124 break;
mas01cr@431 125 case ADB_ACCUMULATION_PER_TRACK:
mas01cr@431 126 accumulator = new PerTrackAccumulator<adb_result_dist_gt>(params.npoints, params.ntracks);
mas01cr@431 127 break;
mas01cr@431 128 case ADB_ACCUMULATION_ONE_TO_ONE:
mas01cr@431 129 accumulator = new NearestAccumulator<adb_result_dist_gt>();
mas01cr@431 130 break;
mas01cr@431 131 default:
mas01cr@431 132 error("unknown accumulation");
mas01cr@239 133 }
mas01cr@239 134 break;
mas01cr@431 135 case ADB_DISTANCE_EUCLIDEAN_NORMED:
mas01cr@431 136 case ADB_DISTANCE_EUCLIDEAN:
mas01cr@431 137 switch(params.accumulation) {
mas01cr@431 138 case ADB_ACCUMULATION_DB:
mas01cr@431 139 accumulator = new DBAccumulator<adb_result_dist_lt>(params.npoints);
mas01cr@431 140 break;
mas01cr@431 141 case ADB_ACCUMULATION_PER_TRACK:
mas01cr@431 142 accumulator = new PerTrackAccumulator<adb_result_dist_lt>(params.npoints, params.ntracks);
mas01cr@431 143 break;
mas01cr@431 144 case ADB_ACCUMULATION_ONE_TO_ONE:
mas01cr@431 145 accumulator = new NearestAccumulator<adb_result_dist_lt>();
mas01cr@431 146 break;
mas01cr@431 147 default:
mas01cr@431 148 error("unknown accumulation");
mas01mc@263 149 }
mas01mc@263 150 break;
mas01cr@239 151 default:
mas01cr@431 152 error("unknown distance function");
mas01cr@431 153 }
mas01cr@431 154
mas01mc@292 155 // Test for index (again) here
mas01cr@425 156 if((refine.flags & ADB_REFINE_RADIUS) && index_exists(dbName, radius, sequenceLength)){
mas01mc@329 157 VERB_LOG(1, "Calling indexed query on database %s, radius=%f, sequenceLength=%d\n", dbName, radius, sequenceLength);
mas01cr@431 158 index_query_loop(&params, &refine, dbName, query_from_key_index);
mas01mc@329 159 }
mas01mc@329 160 else{
mas01mc@329 161 VERB_LOG(1, "Calling brute-force query on database %s\n", dbName);
mas01cr@431 162 query_loop(&params, &refine, query_from_key_index);
mas01mc@329 163 }
mas01mc@292 164
mas01cr@423 165 adb_query_results_t *rs = accumulator->get_points();
mas01cr@423 166 for(unsigned int k = 0; k < rs->nresults; k++) {
mas01cr@423 167 adb_result_t r = rs->results[k];
mas01cr@430 168 reporter->add_point(audiodb_key_index(adb, r.key), r.qpos, r.ipos, r.dist);
mas01cr@423 169 }
mas01cr@423 170
mas01mc@292 171 reporter->report(fileTable, adbQueryResponse);
mas01cr@239 172 }
mas01cr@239 173
mas01cr@239 174 void audioDB::initialize_arrays(int track, unsigned int numVectors, double *query, double *data_buffer, double **D, double **DD) {
mas01cr@239 175 unsigned int j, k, l, w;
mas01cr@239 176 double *dp, *qp, *sp;
mas01cr@239 177
mas01cr@239 178 const unsigned HOP_SIZE = sequenceHop;
mas01cr@239 179 const unsigned wL = sequenceLength;
mas01cr@239 180
mas01cr@239 181 for(j = 0; j < numVectors; j++) {
mas01cr@239 182 // Sum products matrix
mas01cr@239 183 D[j] = new double[trackTable[track]];
mas01cr@239 184 assert(D[j]);
mas01cr@239 185 // Matched filter matrix
mas01cr@239 186 DD[j]=new double[trackTable[track]];
mas01cr@239 187 assert(DD[j]);
mas01cr@239 188 }
mas01cr@239 189
mas01cr@239 190 // Dot product
mas01cr@239 191 for(j = 0; j < numVectors; j++)
mas01cr@239 192 for(k = 0; k < trackTable[track]; k++){
mas01cr@239 193 qp = query + j * dbH->dim;
mas01cr@239 194 sp = data_buffer + k * dbH->dim;
mas01cr@239 195 DD[j][k] = 0.0; // Initialize matched filter array
mas01cr@239 196 dp = &D[j][k]; // point to correlation cell j,k
mas01cr@239 197 *dp = 0.0; // initialize correlation cell
mas01cr@239 198 l = dbH->dim; // size of vectors
mas01cr@239 199 while(l--)
mas01cr@239 200 *dp += *qp++ * *sp++;
mas01cr@239 201 }
mas01cr@239 202
mas01cr@239 203 // Matched Filter
mas01cr@239 204 // HOP SIZE == 1
mas01cr@239 205 double* spd;
mas01cr@239 206 if(HOP_SIZE == 1) { // HOP_SIZE = shingleHop
mas01cr@239 207 for(w = 0; w < wL; w++) {
mas01cr@239 208 for(j = 0; j < numVectors - w; j++) {
mas01cr@239 209 sp = DD[j];
mas01cr@239 210 spd = D[j+w] + w;
mas01cr@239 211 k = trackTable[track] - w;
mas01mc@292 212 while(k--)
mas01mc@292 213 *sp++ += *spd++;
mas01cr@239 214 }
mas01cr@239 215 }
mas01cr@239 216 } else { // HOP_SIZE != 1
mas01cr@239 217 for(w = 0; w < wL; w++) {
mas01cr@239 218 for(j = 0; j < numVectors - w; j += HOP_SIZE) {
mas01cr@239 219 sp = DD[j];
mas01cr@239 220 spd = D[j+w]+w;
mas01cr@239 221 for(k = 0; k < trackTable[track] - w; k += HOP_SIZE) {
mas01cr@239 222 *sp += *spd;
mas01cr@239 223 sp += HOP_SIZE;
mas01cr@239 224 spd += HOP_SIZE;
mas01cr@239 225 }
mas01cr@239 226 }
mas01cr@239 227 }
mas01cr@239 228 }
mas01cr@239 229 }
mas01cr@239 230
mas01cr@239 231 void audioDB::delete_arrays(int track, unsigned int numVectors, double **D, double **DD) {
mas01cr@239 232 if(D != NULL) {
mas01cr@239 233 for(unsigned int j = 0; j < numVectors; j++) {
mas01cr@239 234 delete[] D[j];
mas01cr@239 235 }
mas01cr@239 236 }
mas01cr@239 237 if(DD != NULL) {
mas01cr@239 238 for(unsigned int j = 0; j < numVectors; j++) {
mas01cr@239 239 delete[] DD[j];
mas01cr@239 240 }
mas01cr@239 241 }
mas01cr@239 242 }
mas01cr@239 243
mas01mc@324 244 void audioDB::read_data(int trkfid, int track, double **data_buffer_p, size_t *data_buffer_size_p) {
mas01cr@239 245 if (trackTable[track] * sizeof(double) * dbH->dim > *data_buffer_size_p) {
mas01cr@239 246 if(*data_buffer_p) {
mas01cr@239 247 free(*data_buffer_p);
mas01cr@239 248 }
mas01cr@239 249 {
mas01cr@239 250 *data_buffer_size_p = trackTable[track] * sizeof(double) * dbH->dim;
mas01cr@239 251 void *tmp = malloc(*data_buffer_size_p);
mas01cr@239 252 if (tmp == NULL) {
mas01cr@239 253 error("error allocating data buffer");
mas01cr@239 254 }
mas01cr@239 255 *data_buffer_p = (double *) tmp;
mas01cr@239 256 }
mas01cr@239 257 }
mas01cr@239 258
mas01cr@370 259 CHECKED_READ(trkfid, *data_buffer_p, trackTable[track] * sizeof(double) * dbH->dim);
mas01cr@239 260 }
mas01cr@239 261
mas01cr@405 262 void audioDB::insertTimeStamps(unsigned numVectors, std::ifstream *timesFile, double *timesdata) {
mas01cr@405 263 assert(usingTimes);
mas01cr@405 264
mas01cr@405 265 unsigned numtimes = 0;
mas01cr@405 266
mas01cr@405 267 if(!timesFile->is_open()) {
mas01cr@405 268 error("problem opening times file on timestamped database", timesFileName);
mas01cr@405 269 }
mas01cr@405 270
mas01cr@405 271 double timepoint, next;
mas01cr@405 272 *timesFile >> timepoint;
mas01cr@405 273 if (timesFile->eof()) {
mas01cr@405 274 error("no entries in times file", timesFileName);
mas01cr@405 275 }
mas01cr@405 276 numtimes++;
mas01cr@405 277 do {
mas01cr@405 278 *timesFile >> next;
mas01cr@405 279 if (timesFile->eof()) {
mas01cr@405 280 break;
mas01cr@405 281 }
mas01cr@405 282 numtimes++;
mas01cr@405 283 timesdata[0] = timepoint;
mas01cr@405 284 timepoint = (timesdata[1] = next);
mas01cr@405 285 timesdata += 2;
mas01cr@405 286 } while (numtimes < numVectors + 1);
mas01cr@405 287
mas01cr@405 288 if (numtimes < numVectors + 1) {
mas01cr@405 289 error("too few timepoints in times file", timesFileName);
mas01cr@405 290 }
mas01cr@405 291
mas01cr@405 292 *timesFile >> next;
mas01cr@405 293 if (!timesFile->eof()) {
mas01cr@405 294 error("too many timepoints in times file", timesFileName);
mas01cr@405 295 }
mas01cr@405 296 }
mas01cr@405 297
mas01cr@239 298 // These names deserve some unpicking. The names starting with a "q"
mas01cr@239 299 // are pointers to the query, norm and power vectors; the names
mas01cr@239 300 // starting with "v" are things that will end up pointing to the
mas01cr@239 301 // actual query point's information. -- CSR, 2007-12-05
mas01cr@239 302 void audioDB::set_up_query(double **qp, double **vqp, double **qnp, double **vqnp, double **qpp, double **vqpp, double *mqdp, unsigned *nvp) {
mas01cr@239 303 *nvp = (statbuf.st_size - sizeof(int)) / (dbH->dim * sizeof(double));
mas01mc@292 304
mas01cr@239 305 if(!(dbH->flags & O2_FLAG_L2NORM)) {
mas01cr@239 306 error("Database must be L2 normed for sequence query","use -L2NORM");
mas01cr@239 307 }
mas01cr@239 308
mas01cr@239 309 if(*nvp < sequenceLength) {
mas01cr@239 310 error("Query shorter than requested sequence length", "maybe use -l");
mas01cr@239 311 }
mas01cr@239 312
mas01cr@239 313 VERB_LOG(1, "performing norms... ");
mas01cr@239 314
mas01cr@239 315 *qp = new double[*nvp * dbH->dim];
mas01cr@239 316 memcpy(*qp, indata+sizeof(int), *nvp * dbH->dim * sizeof(double));
mas01cr@239 317 *qnp = new double[*nvp];
mas01cr@426 318 audiodb_l2norm_buffer(*qp, dbH->dim, *nvp, *qnp);
mas01cr@239 319
mas01cr@427 320 audiodb_sequence_sum(*qnp, *nvp, sequenceLength);
mas01cr@427 321 audiodb_sequence_sqrt(*qnp, *nvp, sequenceLength);
mas01cr@239 322
mas01cr@239 323 if (usingPower) {
mas01cr@239 324 *qpp = new double[*nvp];
mas01cr@239 325 if (lseek(powerfd, sizeof(int), SEEK_SET) == (off_t) -1) {
mas01cr@239 326 error("error seeking to data", powerFileName, "lseek");
mas01cr@239 327 }
mas01cr@239 328 int count = read(powerfd, *qpp, *nvp * sizeof(double));
mas01cr@239 329 if (count == -1) {
mas01cr@239 330 error("error reading data", powerFileName, "read");
mas01cr@239 331 }
mas01cr@239 332 if ((unsigned) count != *nvp * sizeof(double)) {
mas01cr@239 333 error("short read", powerFileName);
mas01cr@239 334 }
mas01cr@239 335
mas01cr@427 336 audiodb_sequence_sum(*qpp, *nvp, sequenceLength);
mas01cr@427 337 audiodb_sequence_average(*qpp, *nvp, sequenceLength);
mas01cr@239 338 }
mas01cr@239 339
mas01cr@239 340 if (usingTimes) {
mas01cr@239 341 unsigned int k;
mas01cr@239 342 *mqdp = 0.0;
mas01cr@239 343 double *querydurs = new double[*nvp];
mas01cr@239 344 double *timesdata = new double[*nvp*2];
mas01cr@239 345 insertTimeStamps(*nvp, timesFile, timesdata);
mas01cr@239 346 for(k = 0; k < *nvp; k++) {
mas01cr@239 347 querydurs[k] = timesdata[2*k+1] - timesdata[2*k];
mas01cr@239 348 *mqdp += querydurs[k];
mas01cr@239 349 }
mas01cr@239 350 *mqdp /= k;
mas01cr@239 351
mas01cr@239 352 VERB_LOG(1, "mean query file duration: %f\n", *mqdp);
mas01cr@239 353
mas01cr@239 354 delete [] querydurs;
mas01cr@239 355 delete [] timesdata;
mas01cr@239 356 }
mas01cr@239 357
mas01cr@239 358 // Defaults, for exhaustive search (!usingQueryPoint)
mas01cr@239 359 *vqp = *qp;
mas01cr@239 360 *vqnp = *qnp;
mas01cr@239 361 *vqpp = *qpp;
mas01cr@239 362
mas01cr@239 363 if(usingQueryPoint) {
mas01mc@341 364 if( !(queryPoint < *nvp && queryPoint < *nvp - sequenceLength + 1) ) {
mas01mc@342 365 error("queryPoint >= numVectors-sequenceLength+1 in query");
mas01cr@239 366 } else {
mas01cr@239 367 VERB_LOG(1, "query point: %u\n", queryPoint);
mas01cr@239 368 *vqp = *qp + queryPoint * dbH->dim;
mas01cr@239 369 *vqnp = *qnp + queryPoint;
mas01cr@239 370 if (usingPower) {
mas01cr@239 371 *vqpp = *qpp + queryPoint;
mas01cr@239 372 }
mas01cr@239 373 *nvp = sequenceLength;
mas01cr@239 374 }
mas01cr@239 375 }
mas01cr@239 376 }
mas01cr@239 377
mas01mc@292 378 // Does the same as set_up_query(...) but from database features instead of from a file
mas01mc@292 379 // Constructs the same outputs as set_up_query
mas01mc@292 380 void audioDB::set_up_query_from_key(double **qp, double **vqp, double **qnp, double **vqnp, double **qpp, double **vqpp, double *mqdp, unsigned *nvp, Uns32T queryIndex) {
mas01mc@292 381 if(!trackTable)
mas01mc@292 382 error("trackTable not initialized","set_up_query_from_key");
mas01mc@292 383
mas01mc@292 384 if(!(dbH->flags & O2_FLAG_L2NORM)) {
mas01mc@292 385 error("Database must be L2 normed for sequence query","use -L2NORM");
mas01mc@292 386 }
mas01mc@292 387
mas01mc@292 388 if(dbH->flags & O2_FLAG_POWER)
mas01mc@292 389 usingPower = true;
mas01mc@292 390
mas01mc@292 391 if(dbH->flags & O2_FLAG_TIMES)
mas01mc@292 392 usingTimes = true;
mas01mc@292 393
mas01mc@292 394 *nvp = trackTable[queryIndex];
mas01mc@292 395 if(*nvp < sequenceLength) {
mas01mc@292 396 error("Query shorter than requested sequence length", "maybe use -l");
mas01mc@292 397 }
mas01mc@292 398
mas01mc@292 399 VERB_LOG(1, "performing norms... ");
mas01mc@292 400
mas01mc@324 401 // For LARGE_ADB load query features from file
mas01mc@324 402 if( dbH->flags & O2_FLAG_LARGE_ADB ){
mas01mc@324 403 if(infid>0)
mas01mc@324 404 close(infid);
mas01mc@324 405 char* prefixedString = new char[O2_MAXFILESTR];
mas01mc@324 406 char* tmpStr = prefixedString;
mas01mc@324 407 strncpy(prefixedString, featureFileNameTable+queryIndex*O2_FILETABLE_ENTRY_SIZE, O2_MAXFILESTR);
mas01mc@324 408 prefix_name(&prefixedString, adb_feature_root);
mas01mc@324 409 if(tmpStr!=prefixedString)
mas01mc@324 410 delete[] tmpStr;
mas01mc@324 411 initInputFile(prefixedString, false); // nommap, file pointer at correct position
mas01mc@324 412 size_t allocatedSize = 0;
mas01mc@324 413 read_data(infid, queryIndex, qp, &allocatedSize); // over-writes qp and allocatedSize
mas01mc@324 414 // Consistency check on allocated memory and query feature size
mas01mc@324 415 if(*nvp*sizeof(double)*dbH->dim != allocatedSize)
mas01mc@324 416 error("Query memory allocation failed consitency check","set_up_query_from_key");
mas01mc@324 417 // Allocated and calculate auxillary sequences: l2norm and power
mas01mc@324 418 init_track_aux_data(queryIndex, *qp, qnp, vqnp, qpp, vqpp);
mas01mc@324 419 }
mas01mc@324 420 else{ // Load from self-contained ADB database
mas01mc@324 421 // Read query feature vectors from database
mas01mc@324 422 *qp = NULL;
mas01mc@324 423 lseek(dbfid, dbH->dataOffset + trackOffsetTable[queryIndex] * sizeof(double), SEEK_SET);
mas01mc@324 424 size_t allocatedSize = 0;
mas01mc@324 425 read_data(dbfid, queryIndex, qp, &allocatedSize);
mas01mc@324 426 // Consistency check on allocated memory and query feature size
mas01mc@324 427 if(*nvp*sizeof(double)*dbH->dim != allocatedSize)
mas01mc@324 428 error("Query memory allocation failed consitency check","set_up_query_from_key");
mas01mc@324 429
mas01mc@324 430 Uns32T trackIndexOffset = trackOffsetTable[queryIndex]/dbH->dim; // Convert num data elements to num vectors
mas01mc@324 431 // Copy L2 norm partial-sum coefficients
mas01mc@324 432 assert(*qnp = new double[*nvp]);
mas01mc@324 433 memcpy(*qnp, l2normTable+trackIndexOffset, *nvp*sizeof(double));
mas01cr@427 434 audiodb_sequence_sum(*qnp, *nvp, sequenceLength);
mas01cr@427 435 audiodb_sequence_sqrt(*qnp, *nvp, sequenceLength);
mas01mc@324 436
mas01mc@324 437 if( usingPower ){
mas01mc@324 438 // Copy Power partial-sum coefficients
mas01mc@324 439 assert(*qpp = new double[*nvp]);
mas01mc@324 440 memcpy(*qpp, powerTable+trackIndexOffset, *nvp*sizeof(double));
mas01cr@427 441 audiodb_sequence_sum(*qpp, *nvp, sequenceLength);
mas01cr@427 442 audiodb_sequence_average(*qpp, *nvp, sequenceLength);
mas01mc@324 443 }
mas01mc@324 444
mas01mc@324 445 if (usingTimes) {
mas01mc@324 446 unsigned int k;
mas01mc@324 447 *mqdp = 0.0;
mas01mc@324 448 double *querydurs = new double[*nvp];
mas01mc@324 449 double *timesdata = new double[*nvp*2];
mas01mc@324 450 assert(querydurs && timesdata);
mas01mc@324 451 memcpy(timesdata, timesTable+trackIndexOffset, *nvp*sizeof(double));
mas01mc@324 452 for(k = 0; k < *nvp; k++) {
mas01mc@324 453 querydurs[k] = timesdata[2*k+1] - timesdata[2*k];
mas01mc@324 454 *mqdp += querydurs[k];
mas01mc@324 455 }
mas01mc@324 456 *mqdp /= k;
mas01mc@324 457
mas01mc@324 458 VERB_LOG(1, "mean query file duration: %f\n", *mqdp);
mas01mc@324 459
mas01mc@324 460 delete [] querydurs;
mas01mc@324 461 delete [] timesdata;
mas01mc@324 462 }
mas01mc@292 463 }
mas01mc@292 464
mas01mc@292 465 // Defaults, for exhaustive search (!usingQueryPoint)
mas01mc@292 466 *vqp = *qp;
mas01mc@292 467 *vqnp = *qnp;
mas01mc@292 468 *vqpp = *qpp;
mas01mc@292 469
mas01mc@292 470 if(usingQueryPoint) {
mas01mc@341 471 if( !(queryPoint < *nvp && queryPoint < *nvp - sequenceLength + 1) ) {
mas01mc@342 472 error("queryPoint >= numVectors-sequenceLength+1 in query");
mas01mc@292 473 } else {
mas01mc@292 474 VERB_LOG(1, "query point: %u\n", queryPoint);
mas01mc@292 475 *vqp = *qp + queryPoint * dbH->dim;
mas01mc@292 476 *vqnp = *qnp + queryPoint;
mas01mc@292 477 if (usingPower) {
mas01mc@292 478 *vqpp = *qpp + queryPoint;
mas01mc@292 479 }
mas01mc@292 480 *nvp = sequenceLength;
mas01mc@292 481 }
mas01mc@292 482 }
mas01mc@292 483 }
mas01mc@292 484
mas01mc@292 485
mas01cr@239 486 // FIXME: this is not the right name; we're not actually setting up
mas01cr@239 487 // the database, but copying various bits of it out of mmap()ed tables
mas01cr@239 488 // in order to reduce seeks.
mas01cr@239 489 void audioDB::set_up_db(double **snp, double **vsnp, double **spp, double **vspp, double **mddp, unsigned int *dvp) {
mas01cr@239 490 *dvp = dbH->length / (dbH->dim * sizeof(double));
mas01cr@239 491 *snp = new double[*dvp];
mas01cr@239 492
mas01cr@239 493 double *snpp = *snp, *sppp = 0;
mas01cr@239 494 memcpy(*snp, l2normTable, *dvp * sizeof(double));
mas01cr@239 495
mas01cr@239 496 if (usingPower) {
mas01cr@239 497 if (!(dbH->flags & O2_FLAG_POWER)) {
mas01cr@239 498 error("database not power-enabled", dbName);
mas01cr@239 499 }
mas01cr@239 500 *spp = new double[*dvp];
mas01cr@239 501 sppp = *spp;
mas01cr@239 502 memcpy(*spp, powerTable, *dvp * sizeof(double));
mas01cr@239 503 }
mas01cr@239 504
mas01cr@239 505 for(unsigned int i = 0; i < dbH->numFiles; i++){
mas01cr@239 506 if(trackTable[i] >= sequenceLength) {
mas01cr@427 507 audiodb_sequence_sum(snpp, trackTable[i], sequenceLength);
mas01cr@427 508 audiodb_sequence_sqrt(snpp, trackTable[i], sequenceLength);
mas01cr@239 509
mas01cr@239 510 if (usingPower) {
mas01cr@427 511 audiodb_sequence_sum(sppp, trackTable[i], sequenceLength);
mas01cr@427 512 audiodb_sequence_average(sppp, trackTable[i], sequenceLength);
mas01cr@239 513 }
mas01cr@239 514 }
mas01cr@239 515 snpp += trackTable[i];
mas01cr@239 516 if (usingPower) {
mas01cr@239 517 sppp += trackTable[i];
mas01cr@239 518 }
mas01cr@239 519 }
mas01cr@239 520
mas01cr@239 521 if (usingTimes) {
mas01cr@239 522 if(!(dbH->flags & O2_FLAG_TIMES)) {
mas01cr@239 523 error("query timestamps provided for non-timed database", dbName);
mas01cr@239 524 }
mas01cr@239 525
mas01cr@239 526 *mddp = new double[dbH->numFiles];
mas01cr@239 527
mas01cr@239 528 for(unsigned int k = 0; k < dbH->numFiles; k++) {
mas01cr@239 529 unsigned int j;
mas01cr@239 530 (*mddp)[k] = 0.0;
mas01cr@239 531 for(j = 0; j < trackTable[k]; j++) {
mas01cr@239 532 (*mddp)[k] += timesTable[2*j+1] - timesTable[2*j];
mas01cr@239 533 }
mas01cr@239 534 (*mddp)[k] /= j;
mas01cr@239 535 }
mas01cr@239 536 }
mas01cr@239 537
mas01cr@239 538 *vsnp = *snp;
mas01cr@239 539 *vspp = *spp;
mas01cr@239 540 }
mas01cr@239 541
mas01mc@292 542 // query_points()
mas01mc@292 543 //
mas01mc@292 544 // using PointPairs held in the exact_evaluation_queue compute squared distance for each PointPair
mas01mc@292 545 // and insert result into the current reporter.
mas01mc@292 546 //
mas01mc@292 547 // Preconditions:
mas01mc@292 548 // A query inFile has been opened with setup_query(...) and query pointers initialized
mas01mc@292 549 // The database contains some points
mas01mc@292 550 // An exact_evaluation_queue has been allocated and populated
mas01mc@292 551 // A reporter has been allocated
mas01mc@292 552 //
mas01mc@292 553 // Postconditions:
mas01mc@292 554 // reporter contains the points and distances that meet the reporter constraints
mas01mc@292 555
mas01cr@431 556 void audioDB::query_loop_points(double* query, double* qnPtr, double* qpPtr, double meanQdur, Uns32T numVectors, adb_query_parameters_t *params, adb_query_refine_t *refine){
mas01mc@292 557 unsigned int dbVectors;
mas01mc@315 558 double *sNorm = 0, *snPtr, *sPower = 0, *spPtr = 0;
mas01mc@292 559 double *meanDBdur = 0;
mas01mc@292 560
mas01mc@292 561 // check pre-conditions
mas01mc@292 562 assert(exact_evaluation_queue&&reporter);
mas01mc@292 563 if(!exact_evaluation_queue->size()) // Exit if no points to evaluate
mas01mc@292 564 return;
mas01mc@292 565
mas01mc@292 566 // Compute database info
mas01mc@292 567 // FIXME: we more than likely don't need very much of the database
mas01mc@292 568 // so make a new method to build these values per-track or, even better, per-point
mas01mc@324 569 if( !( dbH->flags & O2_FLAG_LARGE_ADB) )
mas01mc@324 570 set_up_db(&sNorm, &snPtr, &sPower, &spPtr, &meanDBdur, &dbVectors);
mas01mc@292 571
mas01mc@292 572 VERB_LOG(1, "matching points...");
mas01mc@292 573
mas01mc@292 574 // We are guaranteed that the order of points is sorted by:
mas01mc@324 575 // trackID, spos, qpos
mas01mc@292 576 // so we can be relatively efficient in initialization of track data.
mas01mc@292 577 // Here we assume that points don't overlap, so we will use exhaustive dot
mas01mc@324 578 // product evaluation instead of memoization of partial sums which is used
mas01mc@324 579 // for exhaustive brute-force evaluation from smaller databases: e.g. query_loop()
mas01mc@292 580 double dist;
mas01mc@292 581 size_t data_buffer_size = 0;
mas01mc@292 582 double *data_buffer = 0;
mas01mc@324 583 Uns32T trackOffset = 0;
mas01mc@324 584 Uns32T trackIndexOffset = 0;
mas01mc@292 585 Uns32T currentTrack = 0x80000000; // Initialize with a value outside of track index range
mas01mc@292 586 Uns32T npairs = exact_evaluation_queue->size();
mas01mc@292 587 while(npairs--){
mas01mc@292 588 PointPair pp = exact_evaluation_queue->top();
mas01mc@324 589 // Large ADB track data must be loaded here for sPower
mas01mc@324 590 if(dbH->flags & O2_FLAG_LARGE_ADB){
mas01mc@324 591 trackOffset=0;
mas01mc@324 592 trackIndexOffset=0;
mas01mc@292 593 if(currentTrack!=pp.trackID){
mas01mc@324 594 char* prefixedString = new char[O2_MAXFILESTR];
mas01mc@324 595 char* tmpStr = prefixedString;
mas01mc@324 596 // On currentTrack change, allocate and load track data
mas01mc@292 597 currentTrack=pp.trackID;
mas01mc@324 598 SAFE_DELETE_ARRAY(sNorm);
mas01mc@324 599 SAFE_DELETE_ARRAY(sPower);
mas01mc@324 600 if(infid>0)
mas01mc@324 601 close(infid);
mas01mc@324 602 // Open and check dimensions of feature file
mas01mc@324 603 strncpy(prefixedString, featureFileNameTable+pp.trackID*O2_FILETABLE_ENTRY_SIZE, O2_MAXFILESTR);
mas01mc@324 604 prefix_name((char ** const) &prefixedString, adb_feature_root);
mas01mc@324 605 if (prefixedString!=tmpStr)
mas01mc@324 606 delete[] tmpStr;
mas01mc@324 607 initInputFile(prefixedString, false); // nommap, file pointer at correct position
mas01mc@324 608 // Load the feature vector data for current track into data_buffer
mas01mc@324 609 read_data(infid, pp.trackID, &data_buffer, &data_buffer_size);
mas01mc@324 610 // Load power and calculate power and l2norm sequence sums
mas01mc@324 611 init_track_aux_data(pp.trackID, data_buffer, &sNorm, &snPtr, &sPower, &spPtr);
mas01mc@292 612 }
mas01mc@324 613 }
mas01mc@324 614 else{
mas01mc@324 615 // These offsets are w.r.t. the entire database of feature vectors and auxillary variables
mas01mc@324 616 trackOffset=trackOffsetTable[pp.trackID]; // num data elements offset
mas01mc@324 617 trackIndexOffset=trackOffset/dbH->dim; // num vectors offset
mas01mc@324 618 }
mas01mc@324 619 Uns32T qPos = usingQueryPoint?0:pp.qpos;// index for query point
mas01mc@324 620 Uns32T sPos = trackIndexOffset+pp.spos; // index into l2norm table
mas01mc@324 621 // Test power thresholds before computing distance
mas01cr@425 622 if( ( !usingPower || audiodb_powers_acceptable(refine, qpPtr[qPos], sPower[sPos])) &&
mas01mc@324 623 ( qPos<numVectors-sequenceLength+1 && pp.spos<trackTable[pp.trackID]-sequenceLength+1 ) ){
mas01mc@324 624 // Non-large ADB track data is loaded inside power test for efficiency
mas01mc@324 625 if( !(dbH->flags & O2_FLAG_LARGE_ADB) && (currentTrack!=pp.trackID) ){
mas01mc@324 626 // On currentTrack change, allocate and load track data
mas01mc@324 627 currentTrack=pp.trackID;
mas01mc@324 628 lseek(dbfid, dbH->dataOffset + trackOffset * sizeof(double), SEEK_SET);
mas01mc@324 629 read_data(dbfid, currentTrack, &data_buffer, &data_buffer_size);
mas01mc@324 630 }
mas01mc@324 631 // Compute distance
mas01cr@425 632 dist = audiodb_dot_product(query+qPos*dbH->dim, data_buffer+pp.spos*dbH->dim, dbH->dim*sequenceLength);
mas01mc@324 633 double qn = qnPtr[qPos];
mas01mc@324 634 double sn = sNorm[sPos];
mas01cr@431 635 switch(params->distance) {
mas01cr@431 636 case ADB_DISTANCE_EUCLIDEAN_NORMED:
mas01mc@324 637 dist = 2 - (2/(qn*sn))*dist;
mas01cr@431 638 break;
mas01cr@431 639 case ADB_DISTANCE_EUCLIDEAN:
mas01cr@431 640 dist = qn*qn + sn*sn - 2*dist;
mas01cr@431 641 break;
mas01cr@431 642 }
mas01cr@424 643 if((!radius) || dist <= (O2_LSH_EXACT_MULT*radius+O2_DISTANCE_TOLERANCE)) {
mas01cr@424 644 adb_result_t r;
mas01cr@424 645 r.key = fileTable + pp.trackID * O2_FILETABLE_ENTRY_SIZE;
mas01cr@424 646 r.dist = dist;
mas01cr@424 647 r.qpos = pp.qpos;
mas01cr@424 648 r.ipos = pp.spos;
mas01cr@424 649 accumulator->add_point(&r);
mas01cr@424 650 }
mas01mc@292 651 }
mas01mc@292 652 exact_evaluation_queue->pop();
mas01mc@292 653 }
mas01mc@315 654 // Cleanup
mas01mc@324 655 SAFE_DELETE_ARRAY(sNorm);
mas01mc@324 656 SAFE_DELETE_ARRAY(sPower);
mas01mc@324 657 SAFE_DELETE_ARRAY(meanDBdur);
mas01mc@292 658 }
mas01mc@292 659
mas01cr@431 660 void audioDB::query_loop(adb_query_parameters_t *params, adb_query_refine_t *refine, Uns32T queryIndex) {
mas01cr@239 661
mas01cr@239 662 unsigned int numVectors;
mas01cr@239 663 double *query, *query_data;
mas01cr@239 664 double *qNorm, *qnPtr, *qPower = 0, *qpPtr = 0;
mas01cr@239 665 double meanQdur;
mas01cr@239 666
mas01mc@324 667 if( dbH->flags & O2_FLAG_LARGE_ADB )
mas01mc@324 668 error("error: LARGE_ADB requires indexed query");
mas01mc@324 669
mas01mc@292 670 if(query_from_key)
mas01mc@292 671 set_up_query_from_key(&query_data, &query, &qNorm, &qnPtr, &qPower, &qpPtr, &meanQdur, &numVectors, queryIndex);
mas01mc@292 672 else
mas01mc@292 673 set_up_query(&query_data, &query, &qNorm, &qnPtr, &qPower, &qpPtr, &meanQdur, &numVectors);
mas01cr@239 674
mas01cr@239 675 unsigned int dbVectors;
mas01cr@239 676 double *sNorm, *snPtr, *sPower = 0, *spPtr = 0;
mas01cr@239 677 double *meanDBdur = 0;
mas01cr@239 678
mas01cr@239 679 set_up_db(&sNorm, &snPtr, &sPower, &spPtr, &meanDBdur, &dbVectors);
mas01cr@239 680
mas01cr@239 681 VERB_LOG(1, "matching tracks...");
mas01cr@239 682
mas01cr@239 683 unsigned j,k,track,trackOffset=0, HOP_SIZE=sequenceHop, wL=sequenceLength;
mas01cr@239 684 double **D = 0; // Differences query and target
mas01cr@239 685 double **DD = 0; // Matched filter distance
mas01cr@239 686
mas01mc@292 687 D = new double*[numVectors]; // pre-allocate
mas01cr@239 688 DD = new double*[numVectors];
mas01cr@239 689
mas01cr@239 690 gettimeofday(&tv1, NULL);
mas01cr@239 691 unsigned processedTracks = 0;
mas01cr@239 692 off_t trackIndexOffset;
mas01cr@239 693 char nextKey[MAXSTR];
mas01cr@239 694
mas01cr@239 695 // Track loop
mas01cr@239 696 size_t data_buffer_size = 0;
mas01cr@239 697 double *data_buffer = 0;
mas01cr@239 698 lseek(dbfid, dbH->dataOffset, SEEK_SET);
mas01cr@239 699
mas01cr@239 700 for(processedTracks=0, track=0 ; processedTracks < dbH->numFiles ; track++, processedTracks++) {
mas01cr@239 701
mas01cr@239 702 trackOffset = trackOffsetTable[track]; // numDoubles offset
mas01cr@239 703
mas01cr@239 704 // get trackID from file if using a control file
mas01cr@239 705 if(trackFile) {
mas01cr@239 706 trackFile->getline(nextKey,MAXSTR);
mas01cr@239 707 if(!trackFile->eof()) {
mas01cr@430 708 track = audiodb_key_index(adb, nextKey);
mas01cr@430 709 if(track == (uint32_t) -1) {
mas01cr@430 710 error("key not found", nextKey);
mas01cr@430 711 }
mas01cr@239 712 trackOffset = trackOffsetTable[track];
mas01cr@239 713 lseek(dbfid, dbH->dataOffset + trackOffset * sizeof(double), SEEK_SET);
mas01cr@239 714 } else {
mas01cr@239 715 break;
mas01cr@239 716 }
mas01cr@239 717 }
mas01cr@239 718
mas01mc@292 719 // skip identity on query_from_key
mas01mc@292 720 if( query_from_key && (track == queryIndex) ) {
mas01mc@292 721 if(queryIndex!=dbH->numFiles-1){
mas01mc@292 722 track++;
mas01mc@292 723 trackOffset = trackOffsetTable[track];
mas01mc@292 724 lseek(dbfid, dbH->dataOffset + trackOffset * sizeof(double), SEEK_SET);
mas01mc@292 725 }
mas01mc@292 726 else{
mas01mc@292 727 break;
mas01mc@292 728 }
mas01mc@292 729 }
mas01mc@292 730
mas01cr@239 731 trackIndexOffset=trackOffset/dbH->dim; // numVectors offset
mas01cr@239 732
mas01mc@324 733 read_data(dbfid, track, &data_buffer, &data_buffer_size);
mas01cr@239 734 if(sequenceLength <= trackTable[track]) { // test for short sequences
mas01cr@239 735
mas01cr@239 736 VERB_LOG(7,"%u.%jd.%u | ", track, (intmax_t) trackIndexOffset, trackTable[track]);
mas01cr@239 737
mas01cr@239 738 initialize_arrays(track, numVectors, query, data_buffer, D, DD);
mas01cr@239 739
mas01cr@425 740 if(refine->flags & ADB_REFINE_DURATION_RATIO) {
mas01cr@239 741 VERB_LOG(3,"meanQdur=%f meanDBdur=%f\n", meanQdur, meanDBdur[track]);
mas01cr@239 742 }
mas01cr@239 743
mas01cr@425 744 if((!(refine->flags & ADB_REFINE_DURATION_RATIO)) || fabs(meanDBdur[track]-meanQdur) < meanQdur*refine->duration_ratio) {
mas01cr@425 745 if(refine->flags & ADB_REFINE_DURATION_RATIO) {
mas01cr@239 746 VERB_LOG(3,"within duration tolerance.\n");
mas01cr@239 747 }
mas01cr@239 748
mas01cr@239 749 // Search for minimum distance by shingles (concatenated vectors)
mas01cr@239 750 for(j = 0; j <= numVectors - wL; j += HOP_SIZE) {
mas01cr@239 751 for(k = 0; k <= trackTable[track] - wL; k += HOP_SIZE) {
mas01cr@431 752 double thisDist = 0;
mas01cr@431 753 switch(params->distance) {
mas01cr@431 754 case ADB_DISTANCE_EUCLIDEAN_NORMED:
mas01cr@239 755 thisDist = 2-(2/(qnPtr[j]*sNorm[trackIndexOffset+k]))*DD[j][k];
mas01cr@431 756 break;
mas01cr@431 757 case ADB_DISTANCE_EUCLIDEAN:
mas01cr@431 758 thisDist = qnPtr[j]*qnPtr[j]+sNorm[trackIndexOffset+k]*sNorm[trackIndexOffset+k] - 2*DD[j][k];
mas01cr@431 759 break;
mas01cr@431 760 case ADB_DISTANCE_DOT_PRODUCT:
mas01cr@431 761 thisDist = DD[j][k];
mas01cr@431 762 break;
mas01cr@431 763 }
mas01cr@239 764 // Power test
mas01cr@425 765 if ((!usingPower) || audiodb_powers_acceptable(refine, qpPtr[j], sPower[trackIndexOffset + k])) {
mas01cr@239 766 // radius test
mas01cr@425 767 if((!(refine->flags & ADB_REFINE_RADIUS)) ||
mas01cr@425 768 thisDist <= (refine->radius+O2_DISTANCE_TOLERANCE)) {
mas01cr@423 769 adb_result_t r;
mas01cr@423 770 r.key = fileTable + track * O2_FILETABLE_ENTRY_SIZE;
mas01cr@423 771 r.dist = thisDist;
mas01cr@423 772 r.qpos = usingQueryPoint ? queryPoint : j;
mas01cr@423 773 r.ipos = k;
mas01cr@423 774 accumulator->add_point(&r);
mas01cr@239 775 }
mas01cr@239 776 }
mas01cr@239 777 }
mas01cr@239 778 }
mas01cr@239 779 } // Duration match
mas01cr@239 780 delete_arrays(track, numVectors, D, DD);
mas01cr@239 781 }
mas01cr@239 782 }
mas01cr@239 783
mas01cr@239 784 free(data_buffer);
mas01cr@239 785
mas01cr@239 786 gettimeofday(&tv2,NULL);
mas01cr@239 787 VERB_LOG(1,"elapsed time: %ld msec\n",
mas01cr@239 788 (tv2.tv_sec*1000 + tv2.tv_usec/1000) -
mas01cr@239 789 (tv1.tv_sec*1000 + tv1.tv_usec/1000))
mas01cr@239 790
mas01cr@239 791 // Clean up
mas01cr@239 792 if(query_data)
mas01cr@239 793 delete[] query_data;
mas01cr@239 794 if(qNorm)
mas01cr@239 795 delete[] qNorm;
mas01cr@239 796 if(sNorm)
mas01cr@239 797 delete[] sNorm;
mas01cr@239 798 if(qPower)
mas01cr@239 799 delete[] qPower;
mas01cr@239 800 if(sPower)
mas01cr@239 801 delete[] sPower;
mas01cr@239 802 if(D)
mas01cr@239 803 delete[] D;
mas01cr@239 804 if(DD)
mas01cr@239 805 delete[] DD;
mas01cr@239 806 if(meanDBdur)
mas01cr@239 807 delete[] meanDBdur;
mas01cr@239 808 }