Mercurial > hg > audiodb
view bindings/pd/adbpd.c @ 567:43caea931de0
Adding pd binding
author | mas01mj |
---|---|
date | Wed, 01 Jul 2009 11:02:10 +0000 |
parents | |
children | 327fd3aa17e6 |
line wrap: on
line source
#include "m_pd.h" #include <math.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <audioDB_API.h> #define ADB_MAXSTR (512U) #define MAXSTR ADB_MAXSTR // Query types #define O2_POINT_QUERY (0x4U) #define O2_SEQUENCE_QUERY (0x8U) #define O2_TRACK_QUERY (0x10U) #define O2_N_SEQUENCE_QUERY (0x20U) #define O2_ONE_TO_ONE_N_SEQUENCE_QUERY (0x40U) static t_class *adbpd_class; /* so this bit is different */ adb_ptr dbpointer={0};/*This is the audioDB pointer*/ typedef struct _adbpd { t_object x_obj; t_outlet *x_key; t_outlet *x_dist; t_outlet *x_qpos; t_outlet *x_spos; t_symbol *x_dbname; //database name t_symbol *x_dbquerytype; //sequence, track, etc. t_symbol *x_dbfeature; // t_symbol *x_dbpower; t_symbol *x_dbkey; t_float x_dbqpoint; t_float x_dbnumpoints; t_float x_dbradius; t_float x_dbresultlength; t_float x_dbsequencelength; adb_ptr db; } t_adbpd; static void adbpd_create(t_adbpd *x); static void adbpd_open(t_adbpd *x); static void adbpd_setname(t_adbpd *x, t_symbol *s, int argc, t_atom *argv); static void adbpd_status(t_adbpd *x); static void adbpd_l2norm(t_adbpd *x); static void adbpd_power(t_adbpd *x); static void adbpd_setfeatures(t_adbpd *x,t_symbol *s,int argc, t_atom *argv); static void adbpd_setquerytype(t_adbpd *x,t_symbol *s,int argc, t_atom *argv); static void adbpd_setqpoint(t_adbpd *x,t_floatarg f); static void adbpd_setresultlength(t_adbpd *x,t_floatarg f); static void adbpd_setradius(t_adbpd *x,t_floatarg f); static void adbpd_setnumpoints(t_adbpd *x,t_floatarg f); static void adbpd_setsequencelength(t_adbpd *x,t_floatarg f); static void adbpd_doquery(t_adbpd *x); static void adbpd_parameters(t_adbpd *x); static void adbpd_getname(t_adbpd *x); /* input arguments are only used for startup vals */ static void *adbpd_new(t_symbol *s) { /* some sort of standard declaration line */ t_adbpd *x = (t_adbpd *)pd_new(adbpd_class); /* setup some inlets */ floatinlet_new(&x->x_obj,&x->x_dbqpoint); /* second inlet */ floatinlet_new(&x->x_obj,&x->x_dbnumpoints); /* third inlet */ floatinlet_new(&x->x_obj,&x->x_dbradius); /* fourth inlet */ floatinlet_new(&x->x_obj,&x->x_dbresultlength); /* fifth inlet */ floatinlet_new(&x->x_obj,&x->x_dbsequencelength); /* sixth inlet */ /* outlets */ outlet_new(&x->x_obj, &s_float); x->x_key = outlet_new(&x->x_obj, &s_symbol); x->x_dist = outlet_new(&x->x_obj, &s_float); x->x_qpos = outlet_new(&x->x_obj, &s_float); x->x_spos = outlet_new(&x->x_obj, &s_float); /* adb defaults. These are the same but we need to init them */ x->x_dbname=gensym("no db has been specified yet"); x->x_dbquerytype=gensym("point"); x->x_dbfeature=gensym("No feature file yet specified"); x->x_dbqpoint=1; x->x_dbnumpoints=10; x->x_dbradius=1; x->x_dbresultlength=10; x->x_dbsequencelength=12; return(x); } /* bang just gets the status of the db */ static void adbpd_bang(t_adbpd *x) { adbpd_doquery(x); } /* create a database */ static void adbpd_create(t_adbpd *x){ post("creating db '%s'",x->x_dbname->s_name); dbpointer=audiodb_create(x->x_dbname->s_name,0,0,0); if (dbpointer){ post("Created"); x->db=dbpointer; } else { error("Could not create db. May already exist"); x->db=NULL; } } /* open a database. Need to work out the path stuff here. At present databases need to be in the root directory. Not good. */ static void adbpd_open(t_adbpd *x){ post("Opening db '%s'",x->x_dbname->s_name); dbpointer=audiodb_open(x->x_dbname->s_name,O_RDWR); if (dbpointer){ post("Opened db"); x->db=dbpointer; } else { error("failed ! Check '%s' exists, or create a new db",x->x_dbname->s_name); x->db=NULL; } } /* This is accessed via the 'set' message. It sets the name and opens the database. */ static void adbpd_setname(t_adbpd *x, t_symbol *s, int argc, t_atom *argv){ /* if we have a properly formed instruction */ if (argc == 1 && argv->a_type == A_SYMBOL){ x->x_dbname=gensym(argv->a_w.w_symbol->s_name); /* make the internal database reference name the same as the name of the database we want. This is stupid. There must be a better way of doing this. */ post("Name has been set to '%s', and can now be opened.",x->x_dbname->s_name); } /* now we can open the database as we did with the audiodb_open call above*/ post("Opening db '%s'",x->x_dbname->s_name); dbpointer=audiodb_open(x->x_dbname->s_name,O_RDWR); /* opened in read and write mode for when I get round to doing the insert code */ if (dbpointer){ /* yes we have a database*/ post("Opened db"); x->db=dbpointer; } else { error("failed ! Check '%s' exists, or create a new db",x->x_dbname->s_name); x->db=NULL; } } /* this is a status call to the audioDB API */ static void adbpd_status(t_adbpd *x){ adb_status_t mystatus; post("Getting Status"); if (x->db && !(audiodb_status(x->db,&mystatus))){ post("numFiles %d",mystatus.numFiles); post("dim %d",mystatus.dim); post("length %d",mystatus.length); post("dudCount %d",mystatus.dudCount); post("numCount %d",mystatus.nullCount); post("flags %d",mystatus.flags); post("Bytes Available %d",mystatus.data_region_size); } else { error("Can't get Status. Have you selected a db?"); } } static void adbpd_doquery(t_adbpd *x){ adb_datum_t datum = {0}; adb_query_id_t qid = {0}; adb_query_parameters_t params = {0}; adb_query_refine_t refine = {0}; adb_query_spec_t spec = {0}; qid.datum = &datum; qid.sequence_length = x->x_dbsequencelength; qid.sequence_start = x->x_dbqpoint; qid.flags = 0; refine.hopsize = 1; refine.flags |= ADB_REFINE_RADIUS; refine.radius = x->x_dbradius; spec.qid = qid; spec.params = params; spec.refine = refine; int fd; struct stat st; /* FIXME: around here there are all sorts of hideous leaks. */ fd = open(x->x_dbfeature->s_name, O_RDONLY); if(fd < 0) { error("failed to open feature file", x->x_dbfeature->s_name); return; } fstat(fd, &st); read(fd, &datum.dim, sizeof(uint32_t)); datum.nvectors = (st.st_size - sizeof(uint32_t)) / (datum.dim * sizeof(double)); datum.data = (double *) malloc(st.st_size - sizeof(uint32_t)); read(fd, datum.data, st.st_size - sizeof(uint32_t)); close(fd); int queryType; // query type if(strncmp(x->x_dbquerytype->s_name, "track", MAXSTR)==0) queryType=O2_TRACK_QUERY; else if(strncmp(x->x_dbquerytype->s_name, "point", MAXSTR)==0) queryType=O2_POINT_QUERY; else if(strncmp(x->x_dbquerytype->s_name, "sequence", MAXSTR)==0) queryType=O2_SEQUENCE_QUERY; else if(strncmp(x->x_dbquerytype->s_name, "nsequence", MAXSTR)==0) queryType=O2_N_SEQUENCE_QUERY; else if(strncmp(x->x_dbquerytype->s_name, "onetoonensequence", MAXSTR)==0) queryType=O2_ONE_TO_ONE_N_SEQUENCE_QUERY; else error("unsupported query type"); switch(queryType) { case O2_POINT_QUERY: spec.qid.sequence_length = 1; spec.params.accumulation = ADB_ACCUMULATION_DB; spec.params.distance = ADB_DISTANCE_DOT_PRODUCT; spec.params.npoints = x->x_dbnumpoints; spec.params.ntracks = x->x_dbresultlength; break; case O2_TRACK_QUERY: spec.qid.sequence_length = 1; spec.params.accumulation = ADB_ACCUMULATION_PER_TRACK; spec.params.distance = ADB_DISTANCE_DOT_PRODUCT; spec.params.npoints = x->x_dbnumpoints; spec.params.ntracks = x->x_dbresultlength; case O2_SEQUENCE_QUERY: case O2_N_SEQUENCE_QUERY: spec.params.accumulation = ADB_ACCUMULATION_PER_TRACK; // TODO : Add unit norming param. Defaults to false. // spec.params.distance = no_unit_norming ? ADB_DISTANCE_EUCLIDEAN : ADB_DISTANCE_EUCLIDEAN_NORMED; spec.params.distance = ADB_DISTANCE_EUCLIDEAN_NORMED; spec.params.npoints = x->x_dbnumpoints; spec.params.ntracks = x->x_dbresultlength; break; case O2_ONE_TO_ONE_N_SEQUENCE_QUERY: spec.params.accumulation = ADB_ACCUMULATION_ONE_TO_ONE; // TODO : Add unit norming param. Defaults to false. // spec.params.distance = no_unit_norming ? ADB_DISTANCE_EUCLIDEAN : ADB_DISTANCE_EUCLIDEAN_NORMED; spec.params.distance =ADB_DISTANCE_EUCLIDEAN_NORMED; spec.params.npoints = 0; spec.params.ntracks = 0; break; default: post("Unsupported query type"); } adb_query_results_t *rs = audiodb_query_spec(x->db, &spec); if(datum.data) { free(datum.data); datum.data = NULL; } if(datum.power) { free(datum.data); datum.data = NULL; } if(datum.times) { free(datum.data); datum.data = NULL; } if(rs == NULL) { error("Query failed"); return; } int size = rs->nresults; post("result size:[%d]",(int)size); int i = 0; for(i=0; i<size; i++){ adb_result_t r = rs->results[i]; outlet_float(x->x_dist,r.dist); outlet_float(x->x_qpos,r.qpos); outlet_float(x->x_spos,r.ipos); post("in obj key:%s",r.key); post("in obj Dist:%f", r.dist); post("in obj qpos:%d", r.qpos); post("in obj ipos:%d", r.ipos); } } /* Do I need to set a the power file for this flag to work ? Hmmm. Dunno. Also, should be on/off*/ static void adbpd_power(t_adbpd *x){ post("power"); if (x->db && !(audiodb_power(x->db))){ post("power successfully set on db"); } else { error("power flag not working"); } } /* works fine but would be better if it took an argument to switch it on and off */ static void adbpd_l2norm(t_adbpd *x){ post("l2norm"); if (x->db && !(audiodb_l2norm(x->db))){ post("l2norm successfully set on db"); } else { error("l2norm flag not working"); } } /* reports the name of the current db */ static void adbpd_getname(t_adbpd *x){ post("db name is '%s'", x->x_dbname->s_name); } /* this sets the qpoint for the current query*/ static void adbpd_setqpoint(t_adbpd *x,t_floatarg f){ post("qpoint %.3f",f); x->x_dbqpoint=f; } /* This sets the number of points for current query */ static void adbpd_setnumpoints(t_adbpd *x,t_floatarg f){ post("numpoints %.3f",f); x->x_dbnumpoints=(int)f; } /* This sets the radius */ static void adbpd_setradius(t_adbpd *x,t_floatarg f){ post("radius %.3f",f); x->x_dbradius=f; } /* This sets the result length */ static void adbpd_setresultlength(t_adbpd *x,t_floatarg f){ post("resultlength %.3f",f); x->x_dbresultlength=(int)f; } /* This sets the sequence length */ static void adbpd_setsequencelength(t_adbpd *x,t_floatarg f){ post("sequencelength %.3f",f); x->x_dbsequencelength=(int)f; } /* This sets the feature file to use for the query */ static void adbpd_setfeatures(t_adbpd *x,t_symbol *s,int argc, t_atom *argv){ if (argc == 1 && argv->a_type == A_SYMBOL){ x->x_dbfeature=gensym(argv->a_w.w_symbol->s_name); post("Features file has been set to '%s'",x->x_dbfeature->s_name); } } /* This sets the query type */ static void adbpd_setquerytype(t_adbpd *x,t_symbol *s,int argc, t_atom *argv){ if (argc == 1 && argv->a_type == A_SYMBOL){ x->x_dbquerytype=gensym(argv->a_w.w_symbol->s_name); post("Query type has been set to '%s'",x->x_dbquerytype->s_name); } } /* This lists all the parameters */ static void adbpd_parameters(t_adbpd *x){ post("dbname %s",x->x_dbname->s_name); post("querytype %s",x->x_dbquerytype->s_name); post("features %s",x->x_dbfeature->s_name); post("qpoint %.3f",x->x_dbqpoint); post("numpoints %.3f",x->x_dbnumpoints); post("radius %.3f",x->x_dbradius); post("resultlength %.3f",x->x_dbresultlength); post("sequencelength %.3f",x->x_dbsequencelength); } /* THAR SHE BLOWS. This sets up the object, takes the messages with args and maps them to methods. */ void adbpd_setup(void) { /* the arguments in this line refer to INPUT ARGUMENTS and not OUTPUTS */ adbpd_class = class_new(gensym("adbpd"),(t_newmethod)adbpd_new,0,sizeof(t_adbpd),0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); /* all methods that respond to input must be defined here */ class_addbang(adbpd_class, adbpd_bang); class_addfloat(adbpd_class, adbpd_setqpoint); class_addfloat(adbpd_class, adbpd_setnumpoints); class_addfloat(adbpd_class, adbpd_setradius); class_addfloat(adbpd_class, adbpd_setresultlength); class_addfloat(adbpd_class, adbpd_setsequencelength); class_addmethod(adbpd_class, (t_method)adbpd_setname, gensym("set"), A_GIMME, 0); class_addmethod(adbpd_class, (t_method)adbpd_getname, gensym("get"), A_NULL); class_addmethod(adbpd_class, (t_method)adbpd_open, gensym("open"), A_NULL); class_addmethod(adbpd_class, (t_method)adbpd_status, gensym("status"), A_NULL); class_addmethod(adbpd_class, (t_method)adbpd_l2norm, gensym("l2norm"), A_NULL); class_addmethod(adbpd_class, (t_method)adbpd_power, gensym("power"), A_NULL); class_addmethod(adbpd_class, (t_method)adbpd_doquery, gensym("doquery"), A_NULL); class_addmethod(adbpd_class, (t_method)adbpd_setquerytype, gensym("querytype"), A_GIMME, 0); class_addmethod(adbpd_class, (t_method)adbpd_setfeatures, gensym("features"), A_GIMME, 0); class_addmethod(adbpd_class, (t_method)adbpd_parameters, gensym("parameters"), A_NULL); }