changeset 567:43caea931de0

Adding pd binding
author mas01mj
date Wed, 01 Jul 2009 11:02:10 +0000
parents 702c7778c1ba
children 7a257a2364a4
files bindings/pd/Makefile bindings/pd/adbpd.c bindings/pd/pdtest.pd
diffstat 3 files changed, 478 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/pd/Makefile	Wed Jul 01 11:02:10 2009 +0000
@@ -0,0 +1,14 @@
+LIBS = -L/usr/local/lib/ -lflext-pd -laudioDB
+CXX = gcc
+
+adbpd.pd_linux: adbpd.o 
+	$(CXX) -o $@ -shared -Wl,-export-dynamic $(LDFLAGS) $^ $(LIBS)
+
+adbpd.o: adbpd.c
+	$(CXX) -c -fPIC -I/usr/local/include/ $< -o $@
+
+clean:
+	rm -f adbpd.o
+	rm -f adbpd.pd_linux
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/pd/adbpd.c	Wed Jul 01 11:02:10 2009 +0000
@@ -0,0 +1,443 @@
+#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);
+
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bindings/pd/pdtest.pd	Wed Jul 01 11:02:10 2009 +0000
@@ -0,0 +1,21 @@
+#N canvas 671 210 536 428 10;
+#X obj 109 270 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144
+-1 -1;
+#X msg 71 305 parameters;
+#X msg 45 119 set pdtest.adb \, querytype sequence \, features pdtest.chr12
+;
+#X floatatom 260 251 5 0 0 0 - - -;
+#X floatatom 314 253 5 0 0 0 - - -;
+#X floatatom 366 253 5 0 0 0 - - -;
+#X floatatom 420 259 5 0 0 0 - - -;
+#X floatatom 477 264 5 0 0 0 - - -;
+#X obj 303 336 adbpd 100 1 1 5 20;
+#X connect 0 0 8 0;
+#X connect 1 0 8 0;
+#X connect 2 0 8 0;
+#X connect 3 0 8 1;
+#X connect 4 0 8 2;
+#X connect 5 0 8 3;
+#X connect 6 0 8 4;
+#X connect 7 0 8 5;
+#X coords 0 0 1 1 85 60 0;