Mercurial > hg > audiodb
view audioDB.cpp @ 408:f0a69693eaef api-inversion
The lesser of two evils, part 1.
Most of the body of audiodb_insert_datum() will apply to
"LARGE_ADB"-type insertions: checking for the right flags, checking for
enough space free, synchronizing the header. Wouldn't it be nice if we
could reuse all that code (or at least the bits that apply) without one
horrible almost-identical cut-and-paste job (see
batchinsert_large_adb(), or if that's not compelling enough, the four
almost-identical query loops from before the Great Refactoring).
Well, yes, it would. Sadly C makes it mildly difficult, because its
functions are explicitly typed (so we can't pass arbitrary arguments of
other types, even if they're ABI-compatible), while its macros are
textual (which makes writing and maintaining them horrible). The
thought of a union argument was briefly entertained and then discarded
as being just Too Weird.
So, instead, (ab)use the oldest trick in the book: void *. Define an
adb_datum_internal_t which has void * instead of double *; the intention
is that this internal data type can be constructed both from an
adb_datum_t and some notional adb_reference_t (which looks very much
like an adb_insert_t at the time of writing, with char * structure
entries representing filenames). This adb_datum_internal_t structure is
very much an internals-only thing, so put its definition in the
internals header.
Call what was previously audiodb_insert_datum() a new function
audiodb_insert_datum_internal(), made static so that really no-one is
tempted to call it other than ourselves. audiodb_insert_datum() is then
trivial in terms of this new function, if stupidly tedious. (If we were
playing dangerously, we could just perform a cast, but relying on the
fact that sizeof(double *) = sizeof(void *) would almost certainly end
up biting when we least expect.
Incidental inclusion in this patch, since I noticed it at the time:
actually check for the O2_FLAG_L2NORM before scribbling all over the
l2norm table. Somewhat unsurprisingly, there are as yet no tests to
defend against this (harmless, as it turns out) erroneous behaviour.
author | mas01cr |
---|---|
date | Tue, 09 Dec 2008 20:53:39 +0000 |
parents | ef4792df8f93 |
children | 99e6cbad7f76 |
line wrap: on
line source
#include "audioDB.h" extern "C" { #include "audioDB_API.h" #include "audioDB-internals.h" } LSH* SERVER_LSH_INDEX_SINGLETON; char* SERVER_ADB_ROOT; char* SERVER_ADB_FEATURE_ROOT; PointPair::PointPair(Uns32T a, Uns32T b, Uns32T c):trackID(a),qpos(b),spos(c){}; bool operator<(const PointPair& a, const PointPair& b){ return ( (a.trackID<b.trackID) || ( (a.trackID==b.trackID) && ( (a.spos<b.spos) || ( (a.spos==b.spos) && (a.qpos < b.qpos) )) ) ); } bool operator>(const PointPair& a, const PointPair& b){ return ( (a.trackID>b.trackID) || ( (a.trackID==b.trackID) && ( (a.spos>b.spos) || ( (a.spos==b.spos) && (a.qpos > b.qpos) )) ) ); } bool operator==(const PointPair& a, const PointPair& b){ return ( (a.trackID==b.trackID) && (a.qpos==b.qpos) && (a.spos==b.spos) ); } audioDB::audioDB(const unsigned argc, const char *argv[]): O2_AUDIODB_INITIALIZERS { if(processArgs(argc, argv)<0){ printf("No command found.\n"); cmdline_parser_print_version (); if (strlen(gengetopt_args_info_purpose) > 0) printf("%s\n", gengetopt_args_info_purpose); printf("%s\n", gengetopt_args_info_usage); printf("%s\n", gengetopt_args_info_help[1]); printf("%s\n", gengetopt_args_info_help[2]); printf("%s\n", gengetopt_args_info_help[0]); error("No command found"); } // Perform database prefix substitution if(dbName && adb_root) prefix_name((char** const)&dbName, adb_root); if(O2_ACTION(COM_SERVER)) #ifdef LIBRARY ; #else startServer(); #endif else if(O2_ACTION(COM_CREATE)) create(dbName); else if(O2_ACTION(COM_INSERT)) insert(dbName, inFile); else if(O2_ACTION(COM_BATCHINSERT)) batchinsert(dbName, inFile); else if(O2_ACTION(COM_QUERY)) if(isClient){ #ifdef LIBRARY ; #else if(query_from_key){ VERB_LOG(1, "Calling web services query %s on database %s, query=%s\n", radius>0?"(Radius)":"(NN)", dbName, (key&&strlen(key))?key:inFile); ws_query_by_key(dbName, key, inFile, (char*)hostport); } else{ VERB_LOG(1, "Calling web services query on database %s, query=%s\n", dbName, (key&&strlen(key))?key:inFile); ws_query(dbName, inFile, (char*)hostport); } #endif } else query(dbName, inFile); else if(O2_ACTION(COM_STATUS)) if(isClient) #ifdef LIBRARY ; #else ws_status(dbName,(char*)hostport); #endif else status(dbName); else if(O2_ACTION(COM_SAMPLE)) sample(dbName); 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); else if(O2_ACTION(COM_LISZT)) if(isClient) #ifdef LIBRARY ; #else ws_liszt(dbName, (char*) hostport); #endif else liszt(dbName, lisztOffset, lisztLength); else if(O2_ACTION(COM_INDEX)) index_index_db(dbName); else error("Unrecognized command",command); } audioDB::audioDB(const unsigned argc, const char *argv[], adb__queryResponse *adbQueryResponse): O2_AUDIODB_INITIALIZERS { try { isServer = 1; // Set to make errors report over SOAP processArgs(argc, argv); // Perform database prefix substitution if(dbName && adb_root) prefix_name((char** const)&dbName, adb_root); assert(O2_ACTION(COM_QUERY)); query(dbName, inFile, adbQueryResponse); } catch(char *err) { cleanup(); throw(err); } } audioDB::audioDB(const unsigned argc, const char *argv[], adb__statusResponse *adbStatusResponse): O2_AUDIODB_INITIALIZERS { try { isServer = 1; // Set to make errors report over SOAP processArgs(argc, argv); // Perform database prefix substitution if(dbName && adb_root) prefix_name((char** const)&dbName, adb_root); assert(O2_ACTION(COM_STATUS)); status(dbName, adbStatusResponse); } catch(char *err) { cleanup(); throw(err); } } audioDB::audioDB(const unsigned argc, const char *argv[], adb__lisztResponse *adbLisztResponse): O2_AUDIODB_INITIALIZERS { try { isServer = 1; // Set to make errors report over SOAP processArgs(argc, argv); // Perform database prefix substitution if(dbName && adb_root) prefix_name((char** const)&dbName, adb_root); assert(O2_ACTION(COM_LISZT)); liszt(dbName, lisztOffset, lisztLength, adbLisztResponse); } catch(char *err) { cleanup(); throw(err); } } //for API query audioDB::audioDB(const unsigned argc, const char *argv[],adb__queryResponse *adbQueryResponse, int * apierror, adb_t *a): O2_AUDIODB_INITIALIZERS { try { UseApiError=1; adb = a; if(processArgs(argc, argv)<0){ printf("No command found.\n"); cmdline_parser_print_version (); if (strlen(gengetopt_args_info_purpose) > 0) printf("%s\n", gengetopt_args_info_purpose); printf("%s\n", gengetopt_args_info_usage); printf("%s\n", gengetopt_args_info_help[1]); printf("%s\n", gengetopt_args_info_help[2]); printf("%s\n", gengetopt_args_info_help[0]); error("No command found"); } query(dbName, inFile, adbQueryResponse); } catch(int a) { *apierror=a; return; } *apierror=apierrortemp; return; } void audioDB::cleanup() { cmdline_parser_free(&args_info); if(indata) munmap(indata,statbuf.st_size); if(db) munmap(db,getpagesize()); if(fileTable) munmap(fileTable, fileTableLength); if(trackTable) munmap(trackTable, trackTableLength); if(dataBuf) munmap(dataBuf, dataBufLength); if(timesTable) munmap(timesTable, timesTableLength); if(powerTable) munmap(powerTable, powerTableLength); if(l2normTable) munmap(l2normTable, l2normTableLength); if(featureFileNameTable) munmap(featureFileNameTable, fileTableLength); if(timesFileNameTable) munmap(timesFileNameTable, fileTableLength); if(powerFileNameTable) munmap(powerFileNameTable, fileTableLength); if(trackOffsetTable) delete [] trackOffsetTable; if(reporter) delete reporter; if(exact_evaluation_queue) delete exact_evaluation_queue; if(rng) gsl_rng_free(rng); if(vv) delete vv; if(infid>0) close(infid); if(adb && !UseApiError) { audiodb_close(adb); adb = NULL; } if(lsh!=SERVER_LSH_INDEX_SINGLETON) delete lsh; } audioDB::~audioDB(){ cleanup(); } int audioDB::processArgs(const unsigned argc, const char *argv[]){ if(argc<2){ cmdline_parser_print_version (); if (strlen(gengetopt_args_info_purpose) > 0) printf("%s\n", gengetopt_args_info_purpose); printf("%s\n", gengetopt_args_info_usage); printf("%s\n", gengetopt_args_info_help[1]); printf("%s\n", gengetopt_args_info_help[2]); printf("%s\n", gengetopt_args_info_help[0]); exit(0); } /* KLUDGE: gengetopt generates a function which is not completely const-clean in its declaration. We cast argv here to keep the compiler happy. -- CSR, 2008-10-08 */ if (cmdline_parser (argc, (char *const *) argv, &args_info) != 0) error("Error parsing command line"); if(args_info.help_given){ cmdline_parser_print_help(); exit(0); } if(args_info.verbosity_given){ verbosity = args_info.verbosity_arg; if(verbosity < 0 || verbosity > 10){ std::cerr << "Warning: verbosity out of range, setting to 1" << std::endl; verbosity = 1; } } if(args_info.size_given) { if(args_info.datasize_given) { error("both --size and --datasize given", ""); } if(args_info.ntracks_given) { error("both --size and --ntracks given", ""); } if(args_info.datadim_given) { error("both --size and --datadim given", ""); } if (args_info.size_arg < 50 || args_info.size_arg > 32000) { error("Size out of range", ""); } double ratio = (double) args_info.size_arg * 1000000 / ((double) O2_DEFAULTDBSIZE); /* FIXME: what's the safe way of doing this? */ datasize = (unsigned int) ceil(datasize * ratio); ntracks = (unsigned int) ceil(ntracks * ratio); } else { if(args_info.datasize_given) { datasize = args_info.datasize_arg; } if(args_info.ntracks_given) { ntracks = args_info.ntracks_arg; } if(args_info.datadim_given) { datadim = args_info.datadim_arg; } } if(args_info.radius_given) { radius = args_info.radius_arg; if(radius < 0 || radius > 1000000000) { error("radius out of range"); } else { VERB_LOG(3, "Setting radius to %f\n", radius); } } sequenceLength = args_info.sequencelength_arg; if(sequenceLength < 1 || sequenceLength > 1000) { error("seqlen out of range: 1 <= seqlen <= 1000"); } sequenceHop = args_info.sequencehop_arg; 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; } if (args_info.adb_root_given){ adb_root = args_info.adb_root_arg; } if (args_info.adb_feature_root_given){ adb_feature_root = args_info.adb_feature_root_arg; } // perform dbName path prefix SERVER-side subsitution if(SERVER_ADB_ROOT && !adb_root) adb_root = SERVER_ADB_ROOT; if(SERVER_ADB_FEATURE_ROOT && !adb_feature_root) adb_feature_root = SERVER_ADB_FEATURE_ROOT; if(args_info.SERVER_given){ command=COM_SERVER; port=args_info.SERVER_arg; if(port<100 || port > 100000) error("port out of range"); #if defined(O2_DEBUG) struct sigaction sa; sa.sa_sigaction = sigterm_action; sa.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER; sigaction(SIGTERM, &sa, NULL); sa.sa_sigaction = sighup_action; sa.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER; sigaction(SIGHUP, &sa, NULL); #endif if(args_info.load_index_given){ if(!args_info.database_given) error("load_index requires a --database argument"); else dbName=args_info.database_arg; if(!args_info.radius_given) error("load_index requires a --radius argument"); if(!args_info.sequencelength_given) error("load_index requires a --sequenceLength argument"); WS_load_index = true; } return 0; } // No return on client command, find database command if(args_info.client_given){ command=COM_CLIENT; hostport=args_info.client_arg; isClient=1; } if(args_info.NEW_given){ command=COM_CREATE; dbName=args_info.database_arg; return 0; } if(args_info.STATUS_given){ command=COM_STATUS; dbName=args_info.database_arg; return 0; } if(args_info.SAMPLE_given) { command = COM_SAMPLE; dbName = args_info.database_arg; sequenceLength = args_info.sequencelength_arg; if(sequenceLength < 1 || sequenceLength > 1000) { error("seqlen out of range: 1 <= seqlen <= 1000"); } nsamples = args_info.nsamples_arg; return 0; } if(args_info.DUMP_given){ command=COM_DUMP; dbName=args_info.database_arg; output = args_info.output_arg; return 0; } if(args_info.L2NORM_given){ command=COM_L2NORM; dbName=args_info.database_arg; 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; inFile=args_info.features_arg; if(args_info.key_given) { if(!args_info.features_given) { error("INSERT: '-k key' argument depends on '-f features'"); } else { key=args_info.key_arg; } } if(args_info.times_given) { timesFileName=args_info.times_arg; if(strlen(timesFileName)>0) { if(!(timesFile = new std::ifstream(timesFileName,std::ios::in))) { error("Could not open times file for reading", timesFileName); } 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; } if(args_info.BATCHINSERT_given) { command=COM_BATCHINSERT; dbName=args_info.database_arg; inFile=args_info.featureList_arg; if(args_info.keyList_given) { if(!args_info.featureList_given) { error("BATCHINSERT: '-K keyList' argument depends on '-F featureList'"); } else { key=args_info.keyList_arg; // INCONSISTENT NO CHECK } } /* TO DO: REPLACE WITH if(args_info.keyList_given){ trackFileName=args_info.keyList_arg; if(strlen(trackFileName)>0 && !(trackFile = new std::ifstream(trackFileName,std::ios::in))) error("Could not open keyList file for reading",trackFileName); } AND UPDATE BATCHINSERT() */ if(args_info.timesList_given) { timesFileName=args_info.timesList_arg; if(strlen(timesFileName)>0) { if(!(timesFile = new std::ifstream(timesFileName,std::ios::in))) error("Could not open timesList file for reading", timesFileName); usingTimes=1; } } if(args_info.powerList_given) { powerFileName=args_info.powerList_arg; if(strlen(powerFileName)>0) { if(!(powerFile = new std::ifstream(powerFileName,std::ios::in))) error("Could not open powerList file for reading", powerFileName); usingPower=1; } } return 0; } // Set no_unit_norm flag no_unit_norming = args_info.no_unit_norming_flag; lsh_use_u_functions = args_info.lsh_use_u_functions_flag; // LSH Index Command if(args_info.INDEX_given){ if(radius <= 0 ) error("INDEXing requires a Radius argument"); if(!(sequenceLength>0 && sequenceLength <= O2_MAXSEQLEN)) error("INDEXing requires 1 <= sequenceLength <= 1000"); command=COM_INDEX; if(!args_info.database_given) error("INDEXing requires a database"); dbName=args_info.database_arg; // Whether to store LSH hash tables for query in core (FORMAT2) lsh_in_core = !args_info.lsh_on_disk_flag; // This flag is set to 0 if on_disk requested lsh_param_w = args_info.lsh_w_arg; if(!(lsh_param_w>0 && lsh_param_w<=O2_SERIAL_MAX_BINWIDTH)) error("Indexing parameter w out of range (0.0 < w <= 100.0)"); lsh_param_k = args_info.lsh_k_arg; if(!(lsh_param_k>0 && lsh_param_k<=O2_SERIAL_MAX_FUNS)) error("Indexing parameter k out of range (1 <= k <= 100)"); lsh_param_m = args_info.lsh_m_arg; if(!(lsh_param_m>0 && lsh_param_m<= (1 + (sqrt(1 + O2_SERIAL_MAX_TABLES*8.0)))/2.0)) error("Indexing parameter m out of range (1 <= m <= 20)"); lsh_param_N = args_info.lsh_N_arg; if(!(lsh_param_N>0 && lsh_param_N<=O2_SERIAL_MAX_ROWS)) error("Indexing parameter N out of range (1 <= N <= 1000000)"); lsh_param_b = args_info.lsh_b_arg; if(!(lsh_param_b>0 && lsh_param_b<=O2_SERIAL_MAX_TRACKBATCH)) error("Indexing parameter b out of range (1 <= b <= 10000)"); lsh_param_ncols = args_info.lsh_ncols_arg; if(lsh_in_core) // We don't want to block rows with FORMAT2 indexing lsh_param_ncols = O2_SERIAL_MAX_COLS; if( !(lsh_param_ncols>0 && lsh_param_ncols<=O2_SERIAL_MAX_COLS)) error("Indexing parameter ncols out of range (1 <= ncols <= 1000"); return 0; } // Query command and arguments if(args_info.QUERY_given){ command=COM_QUERY; dbName=args_info.database_arg; // XOR features and key search if((!args_info.features_given && !args_info.key_given) || (args_info.features_given && args_info.key_given)) error("QUERY requires exactly one of either -f features or -k key"); if(args_info.features_given) inFile=args_info.features_arg; // query from file else{ query_from_key = true; key=args_info.key_arg; // query from key } if(args_info.keyList_given){ trackFileName=args_info.keyList_arg; if(strlen(trackFileName)>0 && !(trackFile = new std::ifstream(trackFileName,std::ios::in))) error("Could not open keyList file for reading",trackFileName); } if(args_info.times_given){ timesFileName=args_info.times_arg; if(strlen(timesFileName)>0){ if(!(timesFile = new std::ifstream(timesFileName,std::ios::in))) error("Could not open times file for reading", timesFileName); 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) queryType=O2_TRACK_QUERY; else if(strncmp(args_info.QUERY_arg, "point", MAXSTR)==0) queryType=O2_POINT_QUERY; else if(strncmp(args_info.QUERY_arg, "sequence", MAXSTR)==0) queryType=O2_SEQUENCE_QUERY; else if(strncmp(args_info.QUERY_arg, "nsequence", MAXSTR)==0) queryType=O2_N_SEQUENCE_QUERY; else if(strncmp(args_info.QUERY_arg, "onetoonensequence", MAXSTR)==0) queryType=O2_ONE_TO_ONE_N_SEQUENCE_QUERY; else error("unsupported query type",args_info.QUERY_arg); if(!args_info.exhaustive_flag){ queryPoint = args_info.qpoint_arg; usingQueryPoint=1; if(queryPoint<0 || queryPoint >10000) error("queryPoint out of range: 0 <= queryPoint <= 10000"); } // Whether to pre-load LSH hash tables for query (default on, if flag set then off) lsh_in_core = !args_info.lsh_on_disk_flag; // Whether to perform exact evaluation of points returned by LSH lsh_exact = args_info.lsh_exact_flag; pointNN = args_info.pointnn_arg; if(pointNN < 1 || pointNN > O2_MAXNN) { error("pointNN out of range: 1 <= pointNN <= 1000000"); } trackNN = args_info.resultlength_arg; if(trackNN < 1 || trackNN > O2_MAXNN) { error("resultlength out of range: 1 <= resultlength <= 1000000"); } return 0; } if(args_info.LISZT_given){ command = COM_LISZT; dbName=args_info.database_arg; lisztOffset = args_info.lisztOffset_arg; lisztLength = args_info.lisztLength_arg; if(args_info.lisztOffset_arg<0) // check upper bound later when database is opened error("lisztOffset cannot be negative"); if(args_info.lisztLength_arg<0) error("lisztLength cannot be negative"); if(lisztLength >1000000) error("lisztLength too large (>1000000)"); return 0; } return -1; // no command found } void audioDB::status(const char* dbName, adb__statusResponse *adbStatusResponse){ adb_status_t status; if(!adb) { if(!(adb = audiodb_open(dbName, O_RDONLY))) { error("Failed to open database file", dbName); } } if(audiodb_status(adb, &status)) { error("Failed to retrieve database status", dbName); } if(adbStatusResponse == 0) { std::cout << "num files:" << status.numFiles << std::endl; std::cout << "data dim:" << status.dim <<std::endl; if(status.dim > 0) { size_t bytes_per_vector = sizeof(double) * status.dim; off_t nvectors = status.length / bytes_per_vector; off_t data_region_vectors = status.data_region_size / bytes_per_vector; std::cout << "total vectors:" << nvectors << std::endl; std::cout << "vectors available:"; if(status.flags & O2_FLAG_LARGE_ADB) { std::cout << O2_MAX_VECTORS - nvectors << std::endl; } else { std::cout << data_region_vectors - nvectors << std::endl; } } if(!(status.flags & O2_FLAG_LARGE_ADB)) { double used_frac = ((double) status.length) / status.data_region_size; std::cout << "total bytes:" << status.length << " (" << (100.0*used_frac) << "%)" << std::endl; std::cout << "bytes available:" << status.data_region_size - status.length << " (" << (100.0*(1-used_frac)) << "%)" << std::endl; } std::cout << "flags:" << " l2norm[" << DISPLAY_FLAG(status.flags&O2_FLAG_L2NORM) << "] minmax[" << DISPLAY_FLAG(status.flags&O2_FLAG_MINMAX) << "] power[" << DISPLAY_FLAG(status.flags&O2_FLAG_POWER) << "] times[" << DISPLAY_FLAG(status.flags&O2_FLAG_TIMES) << "] largeADB[" << DISPLAY_FLAG(status.flags&O2_FLAG_LARGE_ADB) << "]" << endl; std::cout << "null count: " << status.nullCount << " small sequence count " << status.dudCount-status.nullCount << std::endl; } else { adbStatusResponse->result.numFiles = status.numFiles; adbStatusResponse->result.dim = status.dim; adbStatusResponse->result.length = status.length; adbStatusResponse->result.dudCount = status.dudCount; adbStatusResponse->result.nullCount = status.nullCount; adbStatusResponse->result.flags = status.flags; } } void audioDB::l2norm(const char* dbName) { if(!adb) { if(!(adb = audiodb_open(dbName, O_RDWR))) { error("Failed to open database file", dbName); } } if(audiodb_l2norm(adb)) { error("failed to turn on l2norm flag for database", dbName); } } void audioDB::power_flag(const char *dbName) { if(!adb) { if(!(adb = audiodb_open(dbName, O_RDWR))) { error("Failed to open database file", dbName); } } if(audiodb_power(adb)) { error("can't turn on power flag for database", dbName); } } void audioDB::create(const char *dbName) { if(adb) { error("Already have an adb in this object", ""); } if(!(adb = audiodb_create(dbName, datasize, ntracks, datadim))) { error("Failed to create database file", dbName); } } void audioDB::dump(const char *dbName) { if(!adb) { if(!(adb = audiodb_open(dbName, O_RDONLY))) { error("Failed to open database file", dbName); } } if(audiodb_dump(adb, output)) { error("Failed to dump database to ", output); } status(dbName); } // This entry point is visited once per instance // so it is a good place to set any global state variables int main(const int argc, const char* argv[]){ SERVER_LSH_INDEX_SINGLETON = 0; // Initialize global variables SERVER_ADB_ROOT = 0; // Server-side database root prefix SERVER_ADB_FEATURE_ROOT = 0; // Server-side features root prefix audioDB(argc, argv); } extern "C" { /* for API questions contact * Christophe Rhodes c.rhodes@gold.ac.uk * Ian Knopke mas01ik@gold.ac.uk, ian.knopke@gmail.com */ int audiodb_query(adb_ptr mydb, adb_query_ptr adbq, adb_queryresult_ptr adbqr){ const char *argv[32]; int argvctr=0; char tempstr1[200]; char tempstr2[200]; char tempstr3[200]; int apierror=0; adb__queryResponse adbQueryResponse; /* TODO: may need error checking here */ /* currently counting on audioDB binary to fail for me */ argv[argvctr++]="audioDB"; if(adbq->querytype){ argv[argvctr++]="-Q"; argv[argvctr++]=adbq->querytype; } if(mydb->path){ argv[argvctr++]="-d"; argv[argvctr++]=mydb->path; } if (adbq->feature){ argv[argvctr++]="-f"; argv[argvctr++]=adbq->feature; } if (adbq->power){ argv[argvctr++]="-w"; argv[argvctr++]=adbq->power; } if (adbq->qpoint){ argv[argvctr++]="-p"; argv[argvctr++]=adbq->qpoint; } if (adbq->numpoints){ argv[argvctr++]="-n"; argv[argvctr++]=adbq->numpoints; } if (adbq->radius){ argv[argvctr++]="-R"; argv[argvctr++]=adbq->radius; } if(adbq->resultlength){ argv[argvctr++]="-r"; argv[argvctr++]=adbq->resultlength; } if(adbq->sequencelength){ argv[argvctr++]="-l"; argv[argvctr++]=adbq->sequencelength; } if(adbq->sequencehop){ argv[argvctr++]="-h"; argv[argvctr++]=adbq->sequencehop; } if (adbq->absolute_threshold){ argv[argvctr++]="--absolute-threshold"; snprintf(tempstr1,sizeof(tempstr1),"%f",adbq->absolute_threshold); argv[argvctr++]=tempstr1; } if (adbq->relative_threshold){ argv[argvctr++]="--relative-threshold"; snprintf(tempstr2,sizeof(tempstr2),"%f",adbq->relative_threshold); argv[argvctr++]=tempstr2; } if (adbq->exhaustive){ argv[argvctr++]="--exhaustive"; } if (adbq->expandfactor){ argv[argvctr++]="--expandfactor"; snprintf(tempstr3,sizeof(tempstr3),"%f",adbq->expandfactor); argv[argvctr++]=tempstr3; } if (adbq->rotate){ argv[argvctr++]="--rotate"; } if (adbq->keylist){ argv[argvctr++]="-K"; argv[argvctr++]=adbq->keylist; } argv[argvctr]='\0'; /* debugging */ audioDB::audioDB(argvctr,argv, &adbQueryResponse, &apierror,mydb); //copy data over here from adbQueryResponse to adbqr adbqr->sizeRlist=adbQueryResponse.result.__sizeRlist; adbqr->sizeDist=adbQueryResponse.result.__sizeDist; adbqr->sizeQpos=adbQueryResponse.result.__sizeQpos; adbqr->sizeSpos=adbQueryResponse.result.__sizeSpos; adbqr->Rlist=adbQueryResponse.result.Rlist; adbqr->Dist=adbQueryResponse.result.Dist; adbqr->Qpos=adbQueryResponse.result.Qpos; adbqr->Spos=adbQueryResponse.result.Spos; return apierror; } }