changeset 193:f9d16137e704

Merge powertable branch -r168:227 to trunk.
author mas01cr
date Wed, 21 Nov 2007 11:35:44 +0000
parents 10bcea4e5c40
children 0e75deb7d4d1
files audioDB.cpp audioDB.h audioDBws.h gengetopt.in tests/0026/run-test.sh tests/0026/short-description tests/0027/run-test.sh tests/0027/short-description tests/0028/run-test.sh tests/0028/short-description tests/0029/run-test.sh tests/0029/short-description tests/0030/run-test.sh tests/0030/short-description tests/test-utils.sh
diffstat 15 files changed, 844 insertions(+), 206 deletions(-) [+]
line wrap: on
line diff
--- a/audioDB.cpp	Tue Nov 13 17:14:21 2007 +0000
+++ b/audioDB.cpp	Wed Nov 21 11:35:44 2007 +0000
@@ -72,6 +72,9 @@
   else if(O2_ACTION(COM_L2NORM))
     l2norm(dbName);
   
+  else if(O2_ACTION(COM_POWER))
+    power_flag(dbName);
+
   else if(O2_ACTION(COM_DUMP))
     dump(dbName);
   
@@ -220,6 +223,12 @@
     return 0;
   }
        
+  if(args_info.POWER_given){
+    command=COM_POWER;
+    dbName=args_info.database_arg;
+    return 0;
+  }
+       
   if(args_info.INSERT_given){
     command=COM_INSERT;
     dbName=args_info.database_arg;
@@ -234,6 +243,15 @@
         usingTimes=1;
       }
     }
+    if (args_info.power_given) {
+      powerFileName = args_info.power_arg;
+      if (strlen(powerFileName) > 0) {
+        if (!(powerfd = open(powerFileName, O_RDONLY))) {
+          error("Could not open power file for reading", powerFileName, "open");
+        }
+        usingPower = 1;
+      }
+    }    
     return 0;
   }
   
@@ -261,6 +279,14 @@
         usingTimes=1;
       }
     }
+    if(args_info.powerList_given){
+      powerFileName=args_info.powerList_arg;
+      if(strlen(powerFileName)>0){
+        if(!(powerFile = new ifstream(powerFileName,ios::in)))
+          error("Could not open powerList file for reading", powerFileName);
+        usingPower=1;
+      }
+    }
     return 0;
   }
   
@@ -284,6 +310,16 @@
         usingTimes=1;
       }
     }
+
+    if(args_info.power_given){
+      powerFileName=args_info.power_arg;
+      if(strlen(powerFileName)>0){
+        if (!(powerfd = open(powerFileName, O_RDONLY))) {
+          error("Could not open power file for reading", powerFileName, "open");
+        }
+        usingPower = 1;
+      }
+    }
     
     // query type
     if(strncmp(args_info.QUERY_arg, "track", MAXSTR)==0)
@@ -318,6 +354,18 @@
     if(sequenceHop < 1 || sequenceHop > 1000) {
       error("seqhop out of range: 1 <= seqhop <= 1000");
     }
+
+    if (args_info.absolute_threshold_given) {
+      if (args_info.absolute_threshold_arg >= 0) {
+	error("absolute threshold out of range: should be negative");
+      }
+      use_absolute_threshold = true;
+      absolute_threshold = args_info.absolute_threshold_arg;
+    }
+    if (args_info.relative_threshold_given) {
+      use_relative_threshold = true;
+      relative_threshold = args_info.relative_threshold_arg;
+    }
     return 0;
   }
   return -1; // no command found
@@ -412,6 +460,7 @@
   dbH->dataOffset = ALIGN_UP(dbH->trackTableOffset + O2_TRACKTABLESIZE*maxfiles, 8);
   dbH->l2normTableOffset = ALIGN_DOWN(size - maxfiles*O2_MEANNUMVECTORS*sizeof(double), 8);
   dbH->timesTableOffset = ALIGN_DOWN(dbH->l2normTableOffset - maxfiles*O2_MEANNUMVECTORS*sizeof(double), 8);
+  dbH->powerTableOffset = ALIGN_DOWN(dbH->timesTableOffset - maxfiles*O2_MEANNUMVECTORS*sizeof(double), 8);
   dbH->dbSize = size;
 
   memcpy (db, dbH, O2_HEADERSIZE);
@@ -470,6 +519,7 @@
   dataBuf = (double *) (db + dbH->dataOffset);
   l2normTable = (double *) (db + dbH->l2normTableOffset);
   timesTable = (double *) (db + dbH->timesTableOffset);
+  powerTable = (double *) (db + dbH->powerTableOffset);
 }
 
 void audioDB::initInputFile (const char *inFile) {
@@ -523,6 +573,9 @@
   if(!usingTimes && (dbH->flags & O2_FLAG_TIMES))
     error("Must use timestamps with timestamped database","use --times");
 
+  if(!usingPower && (dbH->flags & O2_FLAG_POWER))
+    error("Must use power with power-enabled database", dbName);
+
   // Check that there is room for at least 1 more file
   if((char*)timesTable<((char*)dataBuf+dbH->length+statbuf.st_size-sizeof(int)))
     error("Insert failed: no more room in database", inFile);
@@ -567,6 +620,9 @@
   assert(timesdata+numVectors<l2normTable);
   insertTimeStamps(numVectors, timesFile, timesdata);
 
+  double *powerdata = powerTable + timesoffset;
+  insertPowerData(numVectors, powerfd, powerdata);
+
   // Increment file count
   dbH->numFiles++;
 
@@ -652,6 +708,32 @@
  }
 }
 
+void audioDB::insertPowerData(unsigned numVectors, int powerfd, double *powerdata) {
+  if (usingPower) {
+    if (!(dbH->flags & O2_FLAG_POWER)) {
+      error("Cannot insert power data on non-power DB", dbName);
+    }
+
+    int one;
+    unsigned int count;
+
+    count = read(powerfd, &one, sizeof(unsigned int));
+    if (count != sizeof(unsigned int)) {
+      error("powerfd read failed", "int", "read");
+    }
+    if (one != 1) {
+      error("dimensionality of power file not 1", powerFileName);
+    }
+
+    // FIXME: should check that the powerfile is the right size for
+    // this.  -- CSR, 2007-10-30
+    count = read(powerfd, powerdata, numVectors * sizeof(double));
+    if (count != numVectors * sizeof(double)) {
+      error("powerfd read failed", "double", "read");
+    }
+  }
+}
+
 void audioDB::batchinsert(const char* dbName, const char* inFile) {
 
   initDBHeader(dbName, true);
@@ -661,6 +743,7 @@
   ifstream *filesIn = 0;
   ifstream *keysIn = 0;
   ifstream* thisTimesFile = 0;
+  int thispowerfd = 0;
 
   if(!(filesIn = new ifstream(inFile)))
     error("Could not open batch in file", inFile);
@@ -671,10 +754,14 @@
   if(!usingTimes && (dbH->flags & O2_FLAG_TIMES))
     error("Must use timestamps with timestamped database","use --times");
 
+  if(!usingPower && (dbH->flags & O2_FLAG_POWER))
+    error("Must use power with power-enabled database", dbName);
+
   unsigned totalVectors=0;
   char *thisKey = new char[MAXSTR];
   char *thisFile = new char[MAXSTR];
   char *thisTimesFileName = new char[MAXSTR];
+  char *thisPowerFileName = new char[MAXSTR];
   
   do{
     filesIn->getline(thisFile,MAXSTR);
@@ -684,6 +771,8 @@
       thisKey = thisFile;
     if(usingTimes)
       timesFile->getline(thisTimesFileName,MAXSTR);	  
+    if(usingPower)
+      powerFile->getline(thisPowerFileName, MAXSTR);
     
     if(filesIn->eof())
       break;
@@ -717,7 +806,7 @@
 	  cerr << "Warning: ignoring zero-length feature vector file:" << thisKey << endl;
         }
       }
-      else{	
+      else{
 	if(usingTimes){
 	  if(timesFile->eof())
 	    error("not enough timestamp files in timesList");
@@ -732,7 +821,23 @@
 	  if(thisTimesFile)
 	    delete thisTimesFile;
 	}
-	  
+        
+        if (usingPower) {
+          if(powerFile->eof()) {
+            error("not enough power files in powerList", powerFileName);
+          }
+          thispowerfd = open(thisPowerFileName, O_RDONLY);
+          if (thispowerfd < 0) {
+            error("failed to open power file", thisPowerFileName);
+          }
+          unsigned insertoffset = dbH->length;
+          unsigned poweroffset = insertoffset / (dbH->dim * sizeof(double));
+          double *powerdata = powerTable + poweroffset;
+          insertPowerData(numVectors, thispowerfd, powerdata);
+          if (0 < thispowerfd) {
+            close(thispowerfd);
+          }
+        }
 	strncpy(fileTable + dbH->numFiles*O2_FILETABLESIZE, thisKey, strlen(thisKey));
   
 	unsigned insertoffset = dbH->length;// Store current state
@@ -879,18 +984,27 @@
     error("error changing working directory", output, "chdir");
   }
 
-  int fLfd, tLfd = 0, kLfd;
-  FILE *fLFile, *tLFile = 0, *kLFile;
+  int fLfd, tLfd = 0, pLfd = 0, kLfd;
+  FILE *fLFile, *tLFile = 0, *pLFile = 0, *kLFile;
 
   if ((fLfd = open("featureList.txt", O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) {
     error("error creating featureList file", "featureList.txt", "open");
   }
+
   int times = dbH->flags & O2_FLAG_TIMES;
   if (times) {
     if ((tLfd = open("timesList.txt", O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) {
       error("error creating timesList file", "timesList.txt", "open");
     }
   }
+
+  int power = dbH->flags & O2_FLAG_POWER;
+  if (power) {
+    if ((pLfd = open("powerList.txt", O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) {
+      error("error creating powerList file", "powerList.txt", "open");
+    }
+  }
+
   if ((kLfd = open("keyList.txt", O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) {
     error("error creating keyList file", "keyList.txt", "open");
   }
@@ -900,10 +1014,13 @@
   if (times) {
     tLFile = fdopen(tLfd, "w");
   }
+  if (power) {
+    pLFile = fdopen(pLfd, "w");
+  }
   kLFile = fdopen(kLfd, "w");
 
   char *fName = new char[256];
-  int ffd;
+  int ffd, pfd;
   FILE *tFile;
   unsigned pos = 0;
   for(unsigned k = 0; k < dbH->numFiles; k++) {
@@ -937,6 +1054,22 @@
       fprintf(tLFile, "%s\n", fName);
     }
 
+    if (power) {
+      uint32_t one = 1;
+      snprintf(fName, 256, "%05d.power", k);
+      if ((pfd = open(fName, O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) {
+	error("error creating power file", fName, "open");
+      }
+      if ((write(pfd, &one, sizeof(uint32_t))) < 0) {
+	error("error writing one", fName, "write");
+      }
+      if ((write(pfd, powerTable + pos, trackTable[k] * sizeof(double))) < 0) {
+	error("error writing data", fName, "write");
+      }
+      fprintf(pLFile, "%s\n", fName);
+      close(pfd);
+    } 
+
     pos += trackTable[k];
     cout << fileTable+k*O2_FILETABLESIZE << " " << trackTable[k] << endl;
   }
@@ -954,10 +1087,16 @@
   if(dbH->flags & O2_FLAG_L2NORM) {
     fprintf(scriptFile, "\"${AUDIODB}\" -d \"$1\" -L\n");
   }
+  if(power) {
+    fprintf(scriptFile, "\"${AUDIODB}\" -d \"$1\" -P\n");
+  }
   fprintf(scriptFile, "\"${AUDIODB}\" -d \"$1\" -B -F featureList.txt -K keyList.txt");
   if(times) {
     fprintf(scriptFile, " -T timesList.txt");
   }
+  if(power) {
+    fprintf(scriptFile, " -W powerList.txt");
+  }
   fprintf(scriptFile, "\n");
   fclose(scriptFile);
 
@@ -969,6 +1108,9 @@
   if(times) {
     fclose(tLFile);
   }
+  if(power) {
+    fclose(pLFile);
+  }
   fclose(kLFile);
   delete[] fName;
     
@@ -985,7 +1127,29 @@
   dbH->flags = dbH->flags|O2_FLAG_L2NORM;
   memcpy (db, dbH, O2_HEADERSIZE);
 }
-  
+
+void audioDB::power_flag(const char *dbName) {
+  initTables(dbName, true, 0);
+  if (dbH->length > 0) {
+    error("cannot turn on power storage for non-empty database", dbName);
+  }
+  dbH->flags |= O2_FLAG_POWER;
+  memcpy(db, dbH, O2_HEADERSIZE);
+}
+
+bool audioDB::powers_acceptable(double p1, double p2) {
+  if (use_absolute_threshold) {
+    if ((p1 < absolute_threshold) || (p2 < absolute_threshold)) {
+      return false;
+    }
+  }
+  if (use_relative_threshold) {
+    if (fabs(p1-p2) > fabs(relative_threshold)) {
+      return false;
+    }
+  }
+  return true;
+}
 
   
 void audioDB::query(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse){  
@@ -1450,6 +1614,46 @@
 
 }
 
+// This is a common pattern in sequence queries: what we are doing is
+// taking a window of length seqlen over a buffer of length length,
+// and placing the sum of the elements in that window in the first
+// element of the window: thus replacing all but the last seqlen
+// elements in the buffer the corresponding windowed sum.
+void audioDB::sequence_sum(double *buffer, int length, int seqlen) {
+  double tmp1, tmp2, *ps;
+  int j, w;
+
+  tmp1 = *buffer;
+  j = 1;
+  w = seqlen - 1;
+  while(w--) {
+    *buffer += buffer[j++];
+  }
+  ps = buffer + 1;
+  w = length - seqlen; // +1 - 1
+  while(w--) {
+    tmp2 = *ps;
+    *ps = *(ps - 1) - tmp1 + *(ps + seqlen - 1);
+    tmp1 = tmp2;
+    ps++;
+  }
+}
+
+void audioDB::sequence_sqrt(double *buffer, int length, int seqlen) {
+  int w = length - seqlen + 1;
+  while(w--) {
+    *buffer = sqrt(*buffer);
+    buffer++;
+  }
+}
+
+void audioDB::sequence_average(double *buffer, int length, int seqlen) {
+  int w = length - seqlen + 1;
+  while(w--) {
+    *buffer /= seqlen;
+    buffer++;
+  }
+}
 
 // k nearest-neighbor (k-NN) search between query and target tracks
 // efficient implementation based on matched filter
@@ -1465,13 +1669,6 @@
   double* query = (double*)(indata+sizeof(int));
   double* queryCopy = 0;
 
-  double qMeanL2;
-  double* sMeanL2;
-
-  unsigned USE_THRESH=0;
-  double SILENCE_THRESH=0;
-  double DIFF_THRESH=0;
-
   if(!(dbH->flags & O2_FLAG_L2NORM) )
     error("Database must be L2 normed for sequence query","use -L2NORM");
 
@@ -1488,98 +1685,67 @@
   memcpy(queryCopy, query, numVectors*dbH->dim*sizeof(double));
   qNorm = new double[numVectors];
   sNorm = new double[dbVectors];
-  sMeanL2=new double[dbH->numFiles];
-  assert(qNorm&&sNorm&&queryCopy&&sMeanL2&&sequenceLength);    
+  assert(qNorm&&sNorm&&queryCopy&&sequenceLength);    
   unitNorm(queryCopy, dbH->dim, numVectors, qNorm);
   query = queryCopy;
 
   // Make norm measurements relative to sequenceLength
   unsigned w = sequenceLength-1;
   unsigned i,j;
-  double* ps;
-  double tmp1,tmp2;
 
   // Copy the L2 norm values to core to avoid disk random access later on
   memcpy(sNorm, l2normTable, dbVectors*sizeof(double));
   double* qnPtr = qNorm;
   double* snPtr = sNorm;
+
+  double *sPower = 0, *qPower = 0;
+  double *spPtr = 0, *qpPtr = 0;
+
+  if (usingPower) {
+    if (!(dbH->flags & O2_FLAG_POWER)) {
+      error("database not power-enabled", dbName);
+    }
+    sPower = new double[dbVectors];
+    spPtr = sPower;
+    memcpy(sPower, powerTable, dbVectors * sizeof(double));
+  }
+
   for(i=0; i<dbH->numFiles; i++){
-    if(trackTable[i]>=sequenceLength){
-      tmp1=*snPtr;
-      j=1;
-      w=sequenceLength-1;
-      while(w--)
-	*snPtr+=snPtr[j++];
-      ps = snPtr+1;
-      w=trackTable[i]-sequenceLength; // +1 - 1
-      while(w--){
-	tmp2=*ps;
-	*ps=*(ps-1)-tmp1+*(ps+sequenceLength-1);
-	tmp1=tmp2;
-	ps++;
-      }
-      ps = snPtr;
-      w=trackTable[i]-sequenceLength+1;
-      while(w--){
-	*ps=sqrt(*ps);
-	ps++;
+    if(trackTable[i]>=sequenceLength) {
+      sequence_sum(snPtr, trackTable[i], sequenceLength);
+      sequence_sqrt(snPtr, trackTable[i], sequenceLength);
+
+      if (usingPower) {
+	sequence_sum(spPtr, trackTable[i], sequenceLength);
+        sequence_average(spPtr, trackTable[i], sequenceLength);
       }
     }
-    snPtr+=trackTable[i];
+    snPtr += trackTable[i];
+    if (usingPower) {
+      spPtr += trackTable[i];
+    }
   }
   
-  double* pn = sMeanL2;
-  w=dbH->numFiles;
-  while(w--)
-    *pn++=0.0;
-  ps=sNorm;
-  unsigned processedTracks=0;
-  for(i=0; i<dbH->numFiles; i++){
-    if(trackTable[i]>sequenceLength-1){
-      w = trackTable[i]-sequenceLength+1;
-      pn = sMeanL2+i;
-      *pn=0;
-      while(w--)
-	if(*ps>0)
-	  *pn+=*ps++;
-      *pn/=trackTable[i]-sequenceLength+1;
-      SILENCE_THRESH+=*pn;
-      processedTracks++;
+  sequence_sum(qnPtr, numVectors, sequenceLength);
+  sequence_sqrt(qnPtr, numVectors, sequenceLength);
+
+  if (usingPower) {
+    qPower = new double[numVectors];
+    qpPtr = qPower;
+    if (lseek(powerfd, sizeof(int), SEEK_SET) == (off_t) -1) {
+      error("error seeking to data", powerFileName, "lseek");
     }
-    ps = sNorm + trackTable[i];
+    int count = read(powerfd, qPower, numVectors * sizeof(double));
+    if (count == -1) {
+      error("error reading data", powerFileName, "read");
+    }
+    if ((unsigned) count != numVectors * sizeof(double)) {
+      error("short read", powerFileName);
+    }
+
+    sequence_sum(qpPtr, numVectors, sequenceLength);
+    sequence_average(qpPtr, numVectors, sequenceLength);
   }
-  if(verbosity>1) {
-    cerr << "processedTracks: " << processedTracks << endl;
-  }
-    
-  SILENCE_THRESH/=processedTracks;
-  USE_THRESH=1; // Turn thresholding on
-  DIFF_THRESH=SILENCE_THRESH; //  mean shingle power
-  SILENCE_THRESH/=5; // 20% of the mean shingle power is SILENCE
-  if(verbosity>4) {
-    cerr << "silence thresh: " << SILENCE_THRESH;
-  }
-  w=sequenceLength-1;
-  i=1;
-  tmp1=*qnPtr;
-  while(w--)
-    *qnPtr+=qnPtr[i++];
-  ps = qnPtr+1;
-  w=numVectors-sequenceLength; // +1 -1
-  while(w--){
-    tmp2=*ps;
-    *ps=*(ps-1)-tmp1+*(ps+sequenceLength-1);
-    tmp1=tmp2;
-    ps++;
-  }
-  ps = qnPtr;
-  qMeanL2 = 0;
-  w=numVectors-sequenceLength+1;
-  while(w--){
-    *ps=sqrt(*ps);
-    qMeanL2+=*ps++;
-  }
-  qMeanL2 /= numVectors-sequenceLength+1;
 
   if(verbosity>1) {
     cerr << "done." << endl;
@@ -1662,8 +1828,11 @@
       if(verbosity>1) {
 	cerr << "query point: " << queryPoint << endl; cerr.flush();
       }
-      query=query+queryPoint*dbH->dim;
-      qnPtr=qnPtr+queryPoint;
+      query = query + queryPoint * dbH->dim;
+      qnPtr = qnPtr + queryPoint;
+      if (usingPower) {
+        qpPtr = qpPtr + queryPoint;
+      }
       numVectors=wL;
     }
   
@@ -1676,7 +1845,7 @@
   assert(DD);
 
   gettimeofday(&tv1, NULL); 
-  processedTracks=0;
+  unsigned processedTracks = 0;
   unsigned successfulTracks=0;
 
   double* qp;
@@ -1794,7 +1963,7 @@
 	for(j=0;j<=numVectors-wL;j+=HOP_SIZE)
 	  for(k=0;k<=trackTable[track]-wL;k+=HOP_SIZE){
 	    thisDist=2-(2/(qnPtr[j]*sNorm[trackIndexOffset+k]))*DD[j][k];
-	    if(verbosity>10) {
+	    if(verbosity>9) {
 	      cerr << thisDist << " " << qnPtr[j] << " " << sNorm[trackIndexOffset+k] << endl;
             }
 	    // Gather chi^2 statistics
@@ -1810,14 +1979,11 @@
 
 	    // diffL2 = fabs(qnPtr[j] - sNorm[trackIndexOffset+k]);
 	    // Power test
-	    if(!USE_THRESH || 
-	       // Threshold on mean L2 of Q and S sequences
-	       (USE_THRESH && qnPtr[j]>SILENCE_THRESH && sNorm[trackIndexOffset+k]>SILENCE_THRESH && 
-		// Are both query and target windows above mean energy?
-		(qnPtr[j]>qMeanL2*.25 && sNorm[trackIndexOffset+k]>sMeanL2[track]*.25))) // &&  diffL2 < DIFF_THRESH )))
-	      thisDist=thisDist; // Computed above
-	    else
-	      thisDist=1000000.0;
+	    if (usingPower) {
+	      if (!(powers_acceptable(qpPtr[j], sPower[trackIndexOffset + k]))) {
+		thisDist = 1000000.0;
+	      }
+	    }
 
 	    // k-NN match algorithm
 	    m=pointNN;
@@ -1934,7 +2100,6 @@
     }
   }
 
-
   // Clean up
   if(trackOffsetTable)
     delete[] trackOffsetTable;
@@ -1944,8 +2109,10 @@
     delete[] qNorm;
   if(sNorm)
     delete[] sNorm;
-  if(sMeanL2)
-    delete[] sMeanL2;
+  if(qPower)
+    delete[] qPower;
+  if(sPower) 
+    delete[] sPower;
   if(D)
     delete[] D;
   if(DD)
@@ -1954,8 +2121,6 @@
     delete[] timesdata;
   if(meanDBdur)
     delete[] meanDBdur;
-
-
 }
 
 // Radius search between query and target tracks
@@ -1972,13 +2137,6 @@
   double* query = (double*)(indata+sizeof(int));
   double* queryCopy = 0;
 
-  double qMeanL2;
-  double* sMeanL2;
-
-  unsigned USE_THRESH=0;
-  double SILENCE_THRESH=0;
-  double DIFF_THRESH=0;
-
   if(!(dbH->flags & O2_FLAG_L2NORM) )
     error("Database must be L2 normed for sequence query","use -l2norm");
   
@@ -1992,98 +2150,66 @@
   memcpy(queryCopy, query, numVectors*dbH->dim*sizeof(double));
   qNorm = new double[numVectors];
   sNorm = new double[dbVectors];
-  sMeanL2=new double[dbH->numFiles];
-  assert(qNorm&&sNorm&&queryCopy&&sMeanL2&&sequenceLength);    
+  assert(qNorm&&sNorm&&queryCopy&&sequenceLength);    
   unitNorm(queryCopy, dbH->dim, numVectors, qNorm);
   query = queryCopy;
 
   // Make norm measurements relative to sequenceLength
   unsigned w = sequenceLength-1;
   unsigned i,j;
-  double* ps;
-  double tmp1,tmp2;
 
   // Copy the L2 norm values to core to avoid disk random access later on
   memcpy(sNorm, l2normTable, dbVectors*sizeof(double));
   double* snPtr = sNorm;
   double* qnPtr = qNorm;
+
+  double *sPower = 0, *qPower = 0;
+  double *spPtr = 0, *qpPtr = 0;
+
+  if (usingPower) {
+    if(!(dbH->flags & O2_FLAG_POWER)) {
+      error("database not power-enabled", dbName);
+    }
+    sPower = new double[dbVectors];
+    spPtr = sPower;
+    memcpy(sPower, powerTable, dbVectors * sizeof(double));
+  }
+
   for(i=0; i<dbH->numFiles; i++){
-    if(trackTable[i]>=sequenceLength){
-      tmp1=*snPtr;
-      j=1;
-      w=sequenceLength-1;
-      while(w--)
-	*snPtr+=snPtr[j++];
-      ps = snPtr+1;
-      w=trackTable[i]-sequenceLength; // +1 - 1
-      while(w--){
-	tmp2=*ps;
-	*ps=*(ps-1)-tmp1+*(ps+sequenceLength-1);
-	tmp1=tmp2;
-	ps++;
-      }
-      ps = snPtr;
-      w=trackTable[i]-sequenceLength+1;
-      while(w--){
-	*ps=sqrt(*ps);
-	ps++;
+    if(trackTable[i]>=sequenceLength) {
+      sequence_sum(snPtr, trackTable[i], sequenceLength);
+      sequence_sqrt(snPtr, trackTable[i], sequenceLength);
+      if (usingPower) {
+        sequence_sum(spPtr, trackTable[i], sequenceLength);
+        sequence_average(spPtr, trackTable[i], sequenceLength);
       }
     }
-    snPtr+=trackTable[i];
+    snPtr += trackTable[i];
+    if (usingPower) {
+      spPtr += trackTable[i];
+    }
   }
   
-  double* pn = sMeanL2;
-  w=dbH->numFiles;
-  while(w--)
-    *pn++=0.0;
-  ps=sNorm;
-  unsigned processedTracks=0;
-  for(i=0; i<dbH->numFiles; i++){
-    if(trackTable[i]>sequenceLength-1){
-      w = trackTable[i]-sequenceLength+1;
-      pn = sMeanL2+i;
-      *pn=0;
-      while(w--)
-	if(*ps>0)
-	  *pn+=*ps++;
-      *pn/=trackTable[i]-sequenceLength+1;
-      SILENCE_THRESH+=*pn;
-      processedTracks++;
+  sequence_sum(qnPtr, numVectors, sequenceLength);
+  sequence_sqrt(qnPtr, numVectors, sequenceLength);
+
+  if (usingPower) {
+    qPower = new double[numVectors];
+    qpPtr = qPower;
+    if (lseek(powerfd, sizeof(int), SEEK_SET) == (off_t) -1) {
+      error("error seeking to data", powerFileName, "lseek");
     }
-    ps = sNorm + trackTable[i];
+    int count = read(powerfd, qPower, numVectors * sizeof(double));
+    if (count == -1) {
+      error("error reading data", powerFileName, "read");
+    }
+    if ((unsigned) count != numVectors * sizeof(double)) {
+      error("short read", powerFileName);
+    }
+
+    sequence_sum(qpPtr, numVectors, sequenceLength);
+    sequence_average(qpPtr, numVectors, sequenceLength);
   }
-  if(verbosity>1) {
-    cerr << "processedTracks: " << processedTracks << endl;
-  }
-    
-  SILENCE_THRESH/=processedTracks;
-  USE_THRESH=1; // Turn thresholding on
-  DIFF_THRESH=SILENCE_THRESH; //  mean shingle power
-  SILENCE_THRESH/=5; // 20% of the mean shingle power is SILENCE
-  if(verbosity>4) {
-    cerr << "silence thresh: " << SILENCE_THRESH;
-  }
-  w=sequenceLength-1;
-  i=1;
-  tmp1=*qnPtr;
-  while(w--)
-    *qnPtr+=qnPtr[i++];
-  ps = qnPtr+1;
-  w=numVectors-sequenceLength; // +1 -1
-  while(w--){
-    tmp2=*ps;
-    *ps=*(ps-1)-tmp1+*(ps+sequenceLength-1);
-    tmp1=tmp2;
-    ps++;
-  }
-  ps = qnPtr;
-  qMeanL2 = 0;
-  w=numVectors-sequenceLength+1;
-  while(w--){
-    *ps=sqrt(*ps);
-    qMeanL2+=*ps++;
-  }
-  qMeanL2 /= numVectors-sequenceLength+1;
 
   if(verbosity>1) {
     cerr << "done." << endl;    
@@ -2166,8 +2292,11 @@
       if(verbosity>1) {
 	cerr << "query point: " << queryPoint << endl; cerr.flush();
       }
-      query=query+queryPoint*dbH->dim;
-      qnPtr=qnPtr+queryPoint;
+      query = query + queryPoint*dbH->dim;
+      qnPtr = qnPtr + queryPoint;
+      if (usingPower) {
+        qpPtr = qpPtr + queryPoint;
+      }
       numVectors=wL;
     }
   
@@ -2180,7 +2309,7 @@
   assert(DD);
 
   gettimeofday(&tv1, NULL); 
-  processedTracks=0;
+  unsigned processedTracks = 0;
   unsigned successfulTracks=0;
 
   double* qp;
@@ -2298,7 +2427,7 @@
 	for(j=0;j<=numVectors-wL;j+=HOP_SIZE)
 	  for(k=0;k<=trackTable[track]-wL;k+=HOP_SIZE){
 	    thisDist=2-(2/(qnPtr[j]*sNorm[trackIndexOffset+k]))*DD[j][k];
-	    if(verbosity>10) {
+	    if(verbosity>9) {
 	      cerr << thisDist << " " << qnPtr[j] << " " << sNorm[trackIndexOffset+k] << endl;
             }
 	    // Gather chi^2 statistics
@@ -2314,14 +2443,12 @@
 
 	    // diffL2 = fabs(qnPtr[j] - sNorm[trackIndexOffset+k]);
 	    // Power test
-	    if(!USE_THRESH || 
-	       // Threshold on mean L2 of Q and S sequences
-	       (USE_THRESH && qnPtr[j]>SILENCE_THRESH && sNorm[trackIndexOffset+k]>SILENCE_THRESH && 
-		// Are both query and target windows above mean energy?
-		(qnPtr[j]>qMeanL2*.25 && sNorm[trackIndexOffset+k]>sMeanL2[track]*.25))) // &&  diffL2 < DIFF_THRESH )))
-	      thisDist=thisDist; // Computed above
-	    else
-	      thisDist=1000000.0;
+            if (usingPower) {
+              if (!(powers_acceptable(qpPtr[j], sPower[trackIndexOffset + k]))) {
+                thisDist = 1000000.0;
+              }
+            }
+
 	    if(thisDist>=0 && thisDist<=radius){
 	      distances[0]++; // increment count
 	      break; // only need one track point per query point
@@ -2424,8 +2551,10 @@
     delete[] qNorm;
   if(sNorm)
     delete[] sNorm;
-  if(sMeanL2)
-    delete[] sMeanL2;
+  if(qPower)
+    delete[] qPower;
+  if(sPower) 
+    delete[] sPower;
   if(D)
     delete[] D;
   if(DD)
@@ -2434,8 +2563,6 @@
     delete[] timesdata;
   if(meanDBdur)
     delete[] meanDBdur;
-
-
 }
 
 // Unit norm block of features
@@ -2645,7 +2772,73 @@
   }
 }
 
+int adb__sequenceQuery(struct soap* soap, xsd__string dbName, xsd__string qKey,
+		       adb__sequenceQueryParms *parms,
+		       adb__queryResponse &adbQueryResponse) {
+
+  char qPosStr[256];
+  char pointNNStr[256];
+  char trackNNStr[256];
+  char seqLenStr[256];
+  char relative_thresholdStr[256];
+  char absolute_thresholdStr[256];
+
+  /* When the branch is merged, move this to a header and use it
+     elsewhere */
+#define INTSTRINGIFY(val, str) \
+  snprintf(str, 256, "%d", val);
+#define DOUBLESTRINGIFY(val, str) \
+  snprintf(str, 256, "%f", val);
+
+  INTSTRINGIFY(parms->qPos, qPosStr);
+  INTSTRINGIFY(parms->pointNN, pointNNStr);
+  INTSTRINGIFY(parms->segNN, trackNNStr);
+  /* FIXME: decide which of segLen and seqLen should live */
+  INTSTRINGIFY(parms->segLen, seqLenStr);
+
+  DOUBLESTRINGIFY(parms->relative_threshold, relative_thresholdStr);
+  DOUBLESTRINGIFY(parms->absolute_threshold, absolute_thresholdStr);
+  
+  const char *argv[] = {
+    "./audioDB",
+    COM_QUERY,
+    "sequence",
+    COM_DATABASE,
+    dbName, 
+    COM_FEATURES,
+    qKey,
+    COM_KEYLIST,
+    /* FIXME: when this branch is merged, use ENSURE_STRING */
+    parms->keyList==0?"":parms->keyList,
+    COM_TIMES,
+    parms->timesFileName==0?"":parms->timesFileName,
+    COM_QUERYPOWER,
+    parms->powerFileName==0?"":parms->powerFileName,
+    COM_QPOINT, 
+    qPosStr,
+    COM_POINTNN,
+    pointNNStr,
+    COM_TRACKNN,
+    trackNNStr,
+    COM_SEQLEN,
+    seqLenStr,
+    COM_RELATIVE_THRESH,
+    relative_thresholdStr,
+    COM_ABSOLUTE_THRESH,
+    absolute_thresholdStr
+  };
+
+  const unsigned argc = 25;
+
+  try {
+    audioDB(argc, (char* const*)argv, &adbQueryResponse);
+    return SOAP_OK;
+  } catch (char *err) {
+    soap_receiver_fault(soap, err, "");
+    return SOAP_FAULT;
+  }
+}
+
 int main(const unsigned argc, char* const argv[]){
   audioDB(argc, argv);
 }
-
--- a/audioDB.h	Tue Nov 13 17:14:21 2007 +0000
+++ b/audioDB.h	Wed Nov 21 11:35:44 2007 +0000
@@ -27,6 +27,7 @@
 #define COM_QUERY "--QUERY"
 #define COM_STATUS "--STATUS"
 #define COM_L2NORM "--L2NORM"
+#define COM_POWER "--POWER"
 #define COM_DUMP "--DUMP"
 #define COM_SERVER "--SERVER"
 
@@ -43,10 +44,13 @@
 #define COM_QUERYKEY "--key"
 #define COM_KEYLIST "--keyList"
 #define COM_TIMES "--times"
+#define COM_QUERYPOWER "--power"
+#define COM_RELATIVE_THRESH "--relative-threshold"
+#define COM_ABSOLUTE_THRESH "--absolute-threshold"
 
 #define O2_OLD_MAGIC ('O'|'2'<<8|'D'<<16|'B'<<24)
 #define O2_MAGIC ('o'|'2'<<8|'d'<<16|'b'<<24)
-#define O2_FORMAT_VERSION (0U)
+#define O2_FORMAT_VERSION (1U)
 
 #define O2_DEFAULT_POINTNN (10U)
 #define O2_DEFAULT_TRACKNN  (10U)
@@ -67,6 +71,7 @@
 // Flags
 #define O2_FLAG_L2NORM (0x1U)
 #define O2_FLAG_MINMAX (0x2U)
+#define O2_FLAG_POWER (0x4U)
 #define O2_FLAG_TIMES (0x20U)
 
 // Query types
@@ -106,6 +111,7 @@
   uint32_t dataOffset;
   uint32_t l2normTableOffset;
   uint32_t timesTableOffset;
+  uint32_t powerTableOffset;
   uint32_t dbSize;
 } dbTableHeaderT, *dbTableHeaderPtr;
 
@@ -125,6 +131,9 @@
   const char *output;
   const char *timesFileName;
   ifstream *timesFile;
+  const char *powerFileName;
+  ifstream *powerFile;
+  int powerfd;
 
   int dbfid;
   int infid;
@@ -141,6 +150,7 @@
   double* qNorm;
   double* sNorm;
   double* timesTable;  
+  double* powerTable;
 
   // Flags and parameters
   unsigned verbosity;   // how much do we want to know?
@@ -153,11 +163,18 @@
   unsigned queryPoint;
   unsigned usingQueryPoint;
   unsigned usingTimes;
+  unsigned usingPower;
   unsigned isClient;
   unsigned isServer;
   unsigned port;
   double timesTol;
   double radius;
+
+  bool use_absolute_threshold;
+  double absolute_threshold;
+  bool use_relative_threshold;
+  double relative_threshold;
+
   
   // Timers
   struct timeval tv1;
@@ -167,6 +184,10 @@
   void error(const char* a, const char* b = "", const char *sysFunc = 0);
   void pointQuery(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse=0);
   void trackPointQuery(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse=0);
+  void sequence_sum(double *buffer, int length, int seqlen);
+  void sequence_sqrt(double *buffer, int length, int seqlen);
+  void sequence_average(double *buffer, int length, int seqlen);
+
   void trackSequenceQueryNN(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse=0);
   void trackSequenceQueryRad(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse=0);
 
@@ -176,6 +197,7 @@
   void unitNorm(double* X, unsigned d, unsigned n, double* qNorm);
   void unitNormAndInsertL2(double* X, unsigned dim, unsigned n, unsigned append);
   void insertTimeStamps(unsigned n, ifstream* timesFile, double* timesdata);
+  void insertPowerData(unsigned n, int powerfd, double *powerdata);
   unsigned getKeyPos(char* key);
  public:
 
@@ -196,6 +218,8 @@
   void ws_status(const char*dbName, char* hostport);
   void ws_query(const char*dbName, const char *trackKey, const char* hostport);
   void l2norm(const char* dbName);
+  void power_flag(const char *dbName);
+  bool powers_acceptable(double p1, double p2);
   void dump(const char* dbName);
 
   // web services
@@ -214,6 +238,9 @@
   output(0), \
   timesFileName(0), \
   timesFile(0), \
+  powerFileName(0), \
+  powerFile(0), \
+  powerfd(0), \
   dbfid(0), \
   infid(0), \
   db(0), \
@@ -235,8 +262,13 @@
   queryPoint(0), \
   usingQueryPoint(0), \
   usingTimes(0), \
+  usingPower(0), \
   isClient(0), \
   isServer(0), \
   port(0), \
   timesTol(0.1), \
-  radius(0)
+  radius(0), \
+  use_absolute_threshold(false), \
+  absolute_threshold(0.0), \
+  use_relative_threshold(false), \
+  relative_threshold(0.0)
--- a/audioDBws.h	Tue Nov 13 17:14:21 2007 +0000
+++ b/audioDBws.h	Wed Nov 21 11:35:44 2007 +0000
@@ -45,3 +45,20 @@
 
 // Query an existing adb database
 int adb__query(xsd__string dbName, xsd__string qKey, xsd__string keyList, xsd__string timesFileName, xsd__int qType, xsd__int qPos, xsd__int pointNN, xsd__int segNN, xsd__int segLen, struct adb__queryResponse &adbQueryResponse);
+
+struct adb__sequenceQueryParms {
+  xsd__string keyList;
+  xsd__string timesFileName;
+  xsd__string powerFileName;
+  xsd__int qPos;
+  xsd__int pointNN;
+  xsd__int segNN;
+  xsd__int segLen;
+  xsd__double relative_threshold;
+  xsd__double absolute_threshold;
+};
+
+// Perform a sequence query
+int adb__sequenceQuery(xsd__string dbName, xsd__string qKey, 
+		       struct adb__sequenceQueryParms *parms, 
+		       struct adb__queryResponse &adbQueryResponse);
--- a/gengetopt.in	Tue Nov 13 17:14:21 2007 +0000
+++ b/gengetopt.in	Wed Nov 21 11:35:44 2007 +0000
@@ -14,17 +14,20 @@
 option "DUMP"   D "output all entries: index key size." dependon="database" optional
 option "output" - "output directory" string dependon="DUMP" default="audioDB.dump" optional
 option "L2NORM" L "unit norm vectors and norm all future inserts." dependon="database" optional
+option "POWER"  P "turn on power flag for database." dependon="database" optional
 
 section "Database Insertion" sectiondesc="The following commands insert feature files, with optional keys and timestamps.\n"
 option "INSERT"      I "add feature vectors to an existing database." dependon="features" optional
 option "UPDATE"      U "replace inserted vectors associated with key with new input vectors." dependon="features" dependon="key" dependon="database" optional hidden
 option "features" f "binary series of vectors file {int sz:ieee double[][sz]:eof}." string typestr="filename" dependon="database" optional
 option "times"    t "list of time points (ascii) for feature vectors." string typestr="filename" dependon="features" optional
+option "power"    w "binary power feature file." string typestr="filename" dependon="database" optional
 option "key"      k "unique identifier associated with features." string typestr="identifier" dependon="features" optional
 text ""
 option "BATCHINSERT" B "add feature vectors named in a --featureList file (with optional keys in a --keyList file) to the named database." dependon="featureList" optional
 option "featureList" F "text file containing list of binary feature vector files to process, one per track" string typestr="filename" dependon="database" optional
 option "timesList"   T "text file containing list of ascii --times for each --features file in --featureList." string typestr="filename" dependon="featureList" optional
+option "powerList"   W "text file containing list of binary power feature file." string typestr="filename" dependon="database" optional
 option "keyList"     K "text file containing list of unique identifiers associated with --features." string typestr="filename" optional
 
 
@@ -40,6 +43,8 @@
 option "resultlength" r "maximum length of the result list." int typestr="length" default="10" optional
 option "sequencelength" l "length of sequences for sequence search." int typestr="length" default="16" dependon="QUERY" optional
 option "sequencehop"  h "hop size of sequence window for sequence search." int typestr="hop" default="1" dependon="QUERY" optional
+option "absolute-threshold" - "absolute power threshold for consideration of query or target sequence (in Bels)" double dependon="QUERY" optional
+option "relative-threshold" - "relative power threshold between query and target sequence (in Bels)" double dependon="QUERY" optional
 
 section "Web Services" sectiondesc="These commands enable the database process to establish a connection via the internet and operate as separate client and server processes.\n"
 option "SERVER" s "run as standalone web service on named port." int typestr="port" default="14475" optional
@@ -47,5 +52,3 @@
 
 
 text "\nCopyright (C) 2007 Michael Casey, Goldsmiths, University of London\n"
-
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/0026/run-test.sh	Wed Nov 21 11:35:44 2007 +0000
@@ -0,0 +1,15 @@
+#! /bin/sh
+
+. ../test-utils.sh
+
+if [ -f testdb ]; then rm -f testdb; fi
+
+${AUDIODB} -N -d testdb
+
+${AUDIODB} -P -d testdb
+${AUDIODB} -d testdb -P
+
+# should fail (no db given)
+expect_clean_error_exit ${AUDIODB} -P
+
+exit 104
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/0026/short-description	Wed Nov 21 11:35:44 2007 +0000
@@ -0,0 +1,1 @@
+command-line -P handling
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/0027/run-test.sh	Wed Nov 21 11:35:44 2007 +0000
@@ -0,0 +1,103 @@
+#! /bin/sh
+
+. ../test-utils.sh
+
+if [ -f testdb ]; then rm -f testdb; fi
+
+${AUDIODB} -d testdb -N
+
+intstring 2 > testfeature
+floatstring 0 1 >> testfeature
+floatstring 1 0 >> testfeature
+
+intstring 1 > testpower
+floatstring -0.5 >> testpower
+floatstring -1 >> testpower
+
+expect_clean_error_exit ${AUDIODB} -d testdb -I -f testfeature -w testpower
+
+${AUDIODB} -d testdb -P
+
+expect_clean_error_exit ${AUDIODB} -d testdb -I -f testfeature
+
+${AUDIODB} -d testdb -I -f testfeature -w testpower
+
+# sequence queries require L2NORM
+${AUDIODB} -d testdb -L
+
+# queries without power files should run as before
+echo "query point (0.0,0.5)"
+intstring 2 > testquery
+floatstring 0 0.5 >> testquery
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery > testoutput
+echo testfeature 1 0 0 > test-expected-output
+cmp testoutput test-expected-output
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -n 1 > testoutput
+echo testfeature 0 0 0 > test-expected-output
+cmp testoutput test-expected-output
+
+echo "query point (0.5,0.0)"
+intstring 2 > testquery
+floatstring 0.5 0 >> testquery
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery > testoutput
+echo testfeature 1 0 1 > test-expected-output
+cmp testoutput test-expected-output
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -n 1 > testoutput
+echo testfeature 0 0 1 > test-expected-output
+cmp testoutput test-expected-output
+
+# queries with power files might do something different
+echo "query point (0.0,0.5), p=-0.5"
+intstring 2 > testquery
+floatstring 0 0.5 >> testquery
+
+intstring 1 > testquerypower
+floatstring -0.5 >> testquerypower
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -w testquerypower --absolute-threshold=-1.4 > testoutput
+echo testfeature 1 0 0 > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -w testquerypower --absolute-threshold=-0.6 > testoutput
+echo testfeature 0 0 0 > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -w testquerypower --absolute-threshold=-0.2 > testoutput
+cat /dev/null > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -w testquerypower --relative-threshold=1 > testoutput
+echo testfeature 1 0 0 > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -w testquerypower --relative-threshold=0.2 > testoutput
+echo testfeature 0 0 0 > test-expected-output
+cmp testoutput test-expected-output
+
+echo "query point (0.5,0.0), p=-0.5"
+intstring 2 > testquery
+floatstring 0.5 0 >> testquery
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -w testquerypower --absolute-threshold=-1.4 > testoutput
+echo testfeature 1 0 1 > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -w testquerypower --absolute-threshold=-0.6 > testoutput
+echo testfeature 2 0 0 > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -w testquerypower --absolute-threshold=-0.2 > testoutput
+cat /dev/null > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -w testquerypower --relative-threshold=1 > testoutput
+echo testfeature 1 0 1 > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -w testquerypower --relative-threshold=0.2 > testoutput
+echo testfeature 2 0 0 > test-expected-output
+cmp testoutput test-expected-output
+
+exit 104
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/0027/short-description	Wed Nov 21 11:35:44 2007 +0000
@@ -0,0 +1,1 @@
+0006 with power
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/0028/run-test.sh	Wed Nov 21 11:35:44 2007 +0000
@@ -0,0 +1,106 @@
+#! /bin/sh
+
+. ../test-utils.sh
+
+if [ -f testdb ]; then rm -f testdb; fi
+
+${AUDIODB} -d testdb -N
+
+intstring 2 > testfeature
+floatstring 0 1 >> testfeature
+floatstring 1 0 >> testfeature
+
+intstring 1 > testpower
+floatstring -0.5 >> testpower
+floatstring -1 >> testpower
+
+echo testfeature > testFeatureList.txt
+echo testpower > testPowerList.txt
+
+expect_clean_error_exit ${AUDIODB} -d testdb -B -F testFeatureList.txt -W testPowerList.txt
+
+${AUDIODB} -d testdb -P
+
+expect_clean_error_exit ${AUDIODB} -d testdb -B -F testFeatureList.txt
+
+${AUDIODB} -d testdb -B -F testFeatureList.txt -W testPowerList.txt
+
+# sequence queries require L2NORM
+${AUDIODB} -d testdb -L
+
+# queries without power files should run as before
+echo "query point (0.0,0.5)"
+intstring 2 > testquery
+floatstring 0 0.5 >> testquery
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery > testoutput
+echo testfeature 1 0 0 > test-expected-output
+cmp testoutput test-expected-output
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -n 1 > testoutput
+echo testfeature 0 0 0 > test-expected-output
+cmp testoutput test-expected-output
+
+echo "query point (0.5,0.0)"
+intstring 2 > testquery
+floatstring 0.5 0 >> testquery
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery > testoutput
+echo testfeature 1 0 1 > test-expected-output
+cmp testoutput test-expected-output
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -n 1 > testoutput
+echo testfeature 0 0 1 > test-expected-output
+cmp testoutput test-expected-output
+
+# queries with power files might do something different
+echo "query point (0.0,0.5), p=-0.5"
+intstring 2 > testquery
+floatstring 0 0.5 >> testquery
+
+intstring 1 > testquerypower
+floatstring -0.5 >> testquerypower
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -w testquerypower --absolute-threshold=-1.4 > testoutput
+echo testfeature 1 0 0 > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -w testquerypower --absolute-threshold=-0.6 > testoutput
+echo testfeature 0 0 0 > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -w testquerypower --absolute-threshold=-0.2 > testoutput
+cat /dev/null > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -w testquerypower --relative-threshold=1 > testoutput
+echo testfeature 1 0 0 > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -w testquerypower --relative-threshold=0.2 > testoutput
+echo testfeature 0 0 0 > test-expected-output
+cmp testoutput test-expected-output
+
+echo "query point (0.5,0.0), p=-0.5"
+intstring 2 > testquery
+floatstring 0.5 0 >> testquery
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -w testquerypower --absolute-threshold=-1.4 > testoutput
+echo testfeature 1 0 1 > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -w testquerypower --absolute-threshold=-0.6 > testoutput
+echo testfeature 2 0 0 > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -w testquerypower --absolute-threshold=-0.2 > testoutput
+cat /dev/null > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -w testquerypower --relative-threshold=1 > testoutput
+echo testfeature 1 0 1 > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -w testquerypower --relative-threshold=0.2 > testoutput
+echo testfeature 2 0 0 > test-expected-output
+cmp testoutput test-expected-output
+
+exit 104
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/0028/short-description	Wed Nov 21 11:35:44 2007 +0000
@@ -0,0 +1,1 @@
+batchinsert version of 0027
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/0029/run-test.sh	Wed Nov 21 11:35:44 2007 +0000
@@ -0,0 +1,75 @@
+#! /bin/sh
+
+. ../test-utils.sh
+
+if [ -f testdb ]; then rm -f testdb; fi
+
+${AUDIODB} -d testdb -N
+
+intstring 2 > testfeature
+floatstring 0 1 >> testfeature
+floatstring 1 0 >> testfeature
+floatstring 1 0 >> testfeature
+floatstring 0 1 >> testfeature
+
+intstring 1 > testpower
+floatstring -0.5 >> testpower
+floatstring -1 >> testpower
+floatstring -1 >> testpower
+floatstring -0.5 >> testpower
+
+expect_clean_error_exit ${AUDIODB} -d testdb -I -f testfeature -w testpower
+${AUDIODB} -d testdb -P
+expect_clean_error_exit ${AUDIODB} -d testdb -I -f testfeature
+${AUDIODB} -d testdb -I -f testfeature -w testpower
+
+# sequence queries require L2NORM
+${AUDIODB} -d testdb -L
+
+echo "query points (0.0,0.5),(0.0,0.5),(0.5,0.0)"
+intstring 2 > testquery
+floatstring 0 0.5 >> testquery
+floatstring 0 0.5 >> testquery
+floatstring 0.5 0 >> testquery
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery > testoutput
+echo testfeature 1 0 0 > test-expected-output
+cmp testoutput test-expected-output
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -p 0 > testoutput
+echo testfeature 1 0 0 > test-expected-output
+cmp testoutput test-expected-output
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -p 1 > testoutput
+echo testfeature 1 1 0 > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 2 -f testquery -p 0 > testoutput
+echo testfeature 1.33333 0 0 > test-expected-output
+cmp testoutput test-expected-output
+${AUDIODB} -d testdb -Q sequence -l 2 -f testquery -p 1 > testoutput
+echo testfeature 1 1 0 > test-expected-output
+cmp testoutput test-expected-output
+
+echo "query points (0.0,0.5)p=-0.5,(0.0,0.5)p=-1,(0.5,0.0)p=-1"
+
+intstring 1 > testquerypower
+floatstring -0.5 -1 -1 >> testquerypower
+
+${AUDIODB} -d testdb -Q sequence -l 2 -f testquery -w testquerypower --absolute-threshold=-1.4 -p 0 > testoutput
+echo testfeature 1.33333 0 0 > test-expected-output
+cmp testoutput test-expected-output
+${AUDIODB} -d testdb -Q sequence -l 2 -f testquery -w testquerypower --absolute-threshold=-1.4 -p 1 > testoutput
+echo testfeature 1 1 0 > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 2 -f testquery -w testquerypower --absolute-threshold=-0.8 -p 0 > testoutput
+echo testfeature 1 0 0 > test-expected-output
+cmp testoutput test-expected-output
+${AUDIODB} -d testdb -Q sequence -l 2 -f testquery -w testquerypower --absolute-threshold=-0.8 -p 1 > testoutput
+cat /dev/null > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 2 -f testquery -w testquerypower --relative-threshold=0.1 -p 0 > testoutput
+echo testfeature 1 0 0 > test-expected-output
+cmp testoutput test-expected-output
+
+exit 104
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/0029/short-description	Wed Nov 21 11:35:44 2007 +0000
@@ -0,0 +1,1 @@
+-l 2 searches with power
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/0030/run-test.sh	Wed Nov 21 11:35:44 2007 +0000
@@ -0,0 +1,85 @@
+#! /bin/sh
+
+. ../test-utils.sh
+
+if [ -f testdb ]; then rm -f testdb; fi
+
+${AUDIODB} -d testdb -N
+
+intstring 2 > testfeature
+floatstring 0 1 >> testfeature
+floatstring 1 0 >> testfeature
+floatstring 1 0 >> testfeature
+floatstring 0 1 >> testfeature
+
+intstring 1 > testpower
+floatstring -0.5 >> testpower
+floatstring -1 >> testpower
+floatstring -1 >> testpower
+floatstring -0.5 >> testpower
+
+expect_clean_error_exit ${AUDIODB} -d testdb -I -f testfeature -w testpower
+${AUDIODB} -d testdb -P
+expect_clean_error_exit ${AUDIODB} -d testdb -I -f testfeature
+${AUDIODB} -d testdb -I -f testfeature -w testpower
+
+# sequence queries require L2NORM
+${AUDIODB} -d testdb -L
+
+echo "query points (0.0,0.5),(0.0,0.5),(0.5,0.0)"
+intstring 2 > testquery
+floatstring 0 0.5 >> testquery
+floatstring 0 0.5 >> testquery
+floatstring 0.5 0 >> testquery
+
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -R 0.1 > testoutput
+echo testfeature 1 > test-expected-output
+cmp testoutput test-expected-output
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -p 0 -R 0.1 > testoutput
+echo testfeature 1 > test-expected-output
+cmp testoutput test-expected-output
+${AUDIODB} -d testdb -Q sequence -l 1 -f testquery -p 1 -R 0.1 > testoutput
+echo testfeature 1 > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 2 -f testquery -p 0 -R 1.1 > testoutput
+echo testfeature 1 > test-expected-output
+cmp testoutput test-expected-output
+${AUDIODB} -d testdb -Q sequence -l 2 -f testquery -p 0 -R 0.9 > testoutput
+cat /dev/null > test-expected-output
+cmp testoutput test-expected-output
+${AUDIODB} -d testdb -Q sequence -l 2 -f testquery -p 1 -R 0.9 > testoutput
+echo testfeature 1 > test-expected-output
+cmp testoutput test-expected-output
+
+echo "query points (0.0,0.5)p=-0.5,(0.0,0.5)p=-1,(0.5,0.0)p=-1"
+
+intstring 1 > testquerypower
+floatstring -0.5 -1 -1 >> testquerypower
+
+${AUDIODB} -d testdb -Q sequence -l 2 -f testquery -w testquerypower --absolute-threshold=-1.4 -p 0 -R 1.1 > testoutput
+echo testfeature 1 > test-expected-output
+cmp testoutput test-expected-output
+${AUDIODB} -d testdb -Q sequence -l 2 -f testquery -w testquerypower --absolute-threshold=-0.8 -p 0 -R 1.1 > testoutput
+echo testfeature 1 > test-expected-output
+cmp testoutput test-expected-output
+${AUDIODB} -d testdb -Q sequence -l 2 -f testquery -w testquerypower --absolute-threshold=-0.7 -p 0 -R 1.1 > testoutput
+cat /dev/null > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 2 -f testquery -w testquerypower --absolute-threshold=-1.4 -p 1 -R 0.9 > testoutput
+echo testfeature 1 > test-expected-output
+cmp testoutput test-expected-output
+${AUDIODB} -d testdb -Q sequence -l 2 -f testquery -w testquerypower --absolute-threshold=-0.9 -p 1 -R 0.9 > testoutput
+cat /dev/null > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 2 -f testquery -w testquerypower --relative-threshold=0.1 -p 0 -R 1.1 > testoutput
+echo testfeature 1 > test-expected-output
+cmp testoutput test-expected-output
+
+${AUDIODB} -d testdb -Q sequence -l 2 -f testquery -w testquerypower --relative-threshold=0.1 -p 0 -R 0.9 > testoutput
+cat /dev/null > test-expected-output
+cmp testoutput test-expected-output
+
+exit 104
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/0030/short-description	Wed Nov 21 11:35:44 2007 +0000
@@ -0,0 +1,1 @@
+single-track sequence radius search with power
\ No newline at end of file
--- a/tests/test-utils.sh	Tue Nov 13 17:14:21 2007 +0000
+++ b/tests/test-utils.sh	Wed Nov 21 11:35:44 2007 +0000
@@ -30,8 +30,12 @@
     case ${arg} in
       0)
         printf "\x00\x00\x00\x00\x00\x00\x00\x00";;
+      -0.5)
+        printf "\x00\x00\x00\x00\x00\x00\xe0\xbf";;
       0.5)
         printf "\x00\x00\x00\x00\x00\x00\xe0\x3f";;
+      -1)
+        printf "\x00\x00\x00\x00\x00\x00\xf0\xbf";;
       1)
         printf "\x00\x00\x00\x00\x00\x00\xf0\x3f";;
       *)