[PD] Coll object Was: cartopol~ and poltocar~

Ivica Ico Bukvic ico at vt.edu
Mon Oct 19 00:48:11 CEST 2015


Fred Jan,

Attached are diffs between l2ork coll.c (threaded option and another 
feature that is currently missing in Pd implementation but is present in 
Max) and another small bug-fix inside curve.c. There are more changes to 
Scope.c and comment.c but given these are gui based they are not going 
to be universally compatible (e.g. vanilla does not have accelerated 
displace with tag so that part is pointless unless there is interest in 
ifdef-ing the code.

If you can merge two patches, this will make it easier for pd-l2ork to 
keep your code as a submodule (assuming you have a git for your code).

Best,

Ico
-------------- next part --------------
diff -u /home/ico/Desktop/cyclone/cyclone-0.1-alpha57/hammer/coll.c miXed/cyclone/hammer/coll.c
--- /home/ico/Desktop/cyclone/cyclone-0.1-alpha57/hammer/coll.c	2015-06-18 04:37:52.000000000 -0400
+++ miXed/cyclone/hammer/coll.c	2015-10-18 18:31:57.550291910 -0400
@@ -9,6 +9,9 @@
 #include "common/loud.h"
 #include "hammer/file.h"
 
+#include <pthread.h>
+#include <unistd.h>
+
 /* LATER profile for the bottlenecks of insertion and sorting */
 /* LATER make sure that ``reentrancy protection hack'' is really working... */
 
@@ -49,6 +52,12 @@
     int            c_headstate;
 } t_collcommon;
 
+typedef struct _coll_q    		/* element in a linked list of stored messages waiting to be sent out */
+{
+    struct _coll_q *q_next; 	/* next in list */
+    char *q_s;            		/* the string */
+} t_coll_q;
+
 typedef struct _coll
 {
     t_object       x_ob;
@@ -60,11 +69,131 @@
     t_outlet      *x_filebangout;
     t_outlet      *x_dumpbangout;
     struct _coll  *x_next;
+
+	//for thread-unsafe file i/o operations
+	//added by Ivica Ico Bukvic <ico at vt.edu> 9-24-2010
+	//http://disis.music.vt.edu http://l2ork.music.vt.edu
+	t_clock *x_clock;
+
+	pthread_t unsafe_t;
+	pthread_mutex_t unsafe_mutex;
+	pthread_cond_t unsafe_cond;
+
+	t_symbol *x_s;
+	t_int unsafe;
+	t_int init; //used to make sure that the secondary thread is ready to go
+
+	t_int threaded; //used to decide whether this should be a threaded instance
+
+	t_coll_q *x_q; //a list of error messages to be processed
 } t_coll;
 
+typedef struct _msg
+{
+	int m_flag;
+	int m_line;
+} t_msg;
+
+typedef struct _threadedFunctionParams
+{
+	t_coll *x;
+} t_threadedFunctionParams;
+
 static t_class *coll_class;
 static t_class *collcommon_class;
 
+static void coll_q_free(t_coll *x)
+{
+	//fprintf(stderr,"coll_q_free\n");
+    t_coll_q *q2;
+    while (x->x_q)
+    {
+		q2 = x->x_q->q_next;
+		t_freebytes(x->x_q->q_s, strlen(x->x_q->q_s) + 1);
+		t_freebytes(x->x_q, sizeof(*x->x_q));
+		x->x_q = q2;
+    }
+	x->x_q = NULL;
+}
+
+static void coll_q_post(t_coll_q *q)
+{
+    t_coll_q *qtmp;
+    for (qtmp = q; qtmp; qtmp = qtmp->q_next)
+    {
+		//fprintf(stderr,"posting...%s\n", qtmp->q_s);
+		post("%s", qtmp->q_s);
+    }
+}
+
+static void coll_q_enqueue(t_coll *x, const char *s)
+{
+	//fprintf(stderr,"enqueuing %s\n", s);
+	t_coll_q *q, *q2 = NULL;
+	q = (t_coll_q *)(getbytes(sizeof(*q)));
+	q->q_next = NULL;
+	q->q_s = (char *)getbytes(strlen(s) + 1);
+	strcpy(q->q_s, s);
+	if (!x->x_q) {
+		//fprintf(stderr,"first\n");
+		x->x_q = q;
+	}
+	else {
+		//fprintf(stderr,"not first\n");
+		q2 = x->x_q;
+		while (q2->q_next)
+			q2 = q2->q_next;
+		q2->q_next = q;
+	}
+}
+
+static void coll_enqueue_threaded_msgs(t_coll *x, t_msg *m)
+{
+	//fprintf(stderr,"msgs = %d\n", m->m_flag);
+	char s[MAXPDSTRING];
+	if (m->m_flag & 1) {
+		//fprintf(stderr,"0x01\n");
+		sprintf(s, "coll: no coll file '%s'", x->x_s->s_name);
+		coll_q_enqueue(x, s);
+	}
+	if (m->m_flag & 2) {
+		//fprintf(stderr,"0x02\n");
+		sprintf(s, "coll: error reading text file '%s'", x->x_s->s_name);
+		coll_q_enqueue(x, s);
+	}
+	if (m->m_flag & 4) {
+		//fprintf(stderr,"0x04\n");
+		sprintf(s, "coll: finished reading %d lines from text file '%s'", m->m_line, x->x_s->s_name);
+		coll_q_enqueue(x, s);
+	}
+	if (m->m_flag & 8) {
+		//fprintf(stderr,"0x08\n");
+		sprintf(s, "coll: error in line %d of text file '%s'", m->m_line, x->x_s->s_name);
+		coll_q_enqueue(x, s);
+	}
+	if (m->m_flag & 16) {
+		//fprintf(stderr,"0x16\n");
+		sprintf(s, "coll: error reading text file '%s'", x->x_s->s_name);
+		coll_q_enqueue(x, s);
+	}
+	if (m->m_flag & 32) {
+		//fprintf(stderr,"0x32\n");
+		sprintf(s, "coll: error writing text file '%s'", x->x_s->s_name);
+		coll_q_enqueue(x, s);
+	}
+}
+
+static void coll_tick(t_coll *x)
+{
+	//x->busy = 0;
+	if (x->x_q)
+	{
+		coll_q_post(x->x_q);
+		coll_q_free(x);
+	}
+    outlet_bang(x->x_filebangout);
+}
+
 static t_collelem *collelem_new(int ac, t_atom *av, int *np, t_symbol *s)
 {
     t_collelem *ep = (t_collelem *)getbytes(sizeof(*ep));
@@ -201,6 +330,8 @@
     }
 }
 
+
+
 /* atomic collcommon modifiers:  clearall, remove, replace,
    putbefore, putafter, swaplinks, swapkeys, changesymkey, renumber, sort */
 
@@ -582,63 +713,89 @@
     return (collcommon_fromatoms(cc, binbuf_getnatom(bb), binbuf_getvec(bb)));
 }
 
-static void collcommon_doread(t_collcommon *cc, t_symbol *fn, t_canvas *cv)
+static t_msg *collcommon_doread(t_collcommon *cc, t_symbol *fn, t_canvas *cv, int threaded)
 {
     t_binbuf *bb;
+	t_msg *m = (t_msg *)(getbytes(sizeof(*m)));
+	m->m_flag = 0;
+	m->m_line = 0;
     char buf[MAXPDSTRING];
+
     if (!fn && !(fn = cc->c_filename))  /* !fn: 'readagain' */
-	return;
+		return(m);
+
     /* FIXME use open_via_path() */
     if (cv || (cv = cc->c_lastcanvas))  /* !cv: 'read' w/o arg, 'readagain' */
-	canvas_makefilename(cv, fn->s_name, buf, MAXPDSTRING);
+		canvas_makefilename(cv, fn->s_name, buf, MAXPDSTRING);
     else
     {
     	strncpy(buf, fn->s_name, MAXPDSTRING);
     	buf[MAXPDSTRING-1] = 0;
     }
+
     if (!cc->c_refs)
     {
-	/* loading during object creation --
-	   avoid binbuf_read()'s complaints, LATER rethink */
-	FILE *fp;
-	if (!(fp = sys_fopen(buf, "r")))
-	{
-	    loud_warning(&coll_class, 0, "no coll file '%s'", buf);
-	    return;
-	}
-	fclose(fp);
+		/* loading during object creation --
+		   avoid binbuf_read()'s complaints, LATER rethink */
+		FILE *fp;
+		char fname[MAXPDSTRING];
+		sys_bashfilename(buf, fname);
+		if (!(fp = fopen(fname, "r")))
+		{
+			m->m_flag |= 0x01;
+			if (!threaded)
+				loud_warning(&coll_class, 0, "no coll file '%s'", fname);
+			return(m);
+		}
+		fclose(fp);
     }
+
     bb = binbuf_new();
     if (binbuf_read(bb, buf, "", 0))
-	loud_error(0, "coll: error reading text file '%s'", fn->s_name);
-    else
-    {
-	int nlines = collcommon_frombinbuf(cc, bb);
-	if (nlines > 0)
 	{
-	    t_coll *x;
-	    /* LATER consider making this more robust */
-	    for (x = cc->c_refs; x; x = x->x_next)
-		outlet_bang(x->x_filebangout);
-	    cc->c_lastcanvas = cv;
-	    cc->c_filename = fn;
-	    post("coll: finished reading %d lines from text file '%s'",
-		 nlines, fn->s_name);
-	}
-	else if (nlines < 0)
-	    loud_error(0, "coll: error in line %d of text file '%s'",
-		       1 - nlines, fn->s_name);
-	else
-	    loud_error(0, "coll: error reading text file '%s'", fn->s_name);
-	if (cc->c_refs)
-	    collcommon_modified(cc, 1);
-    }
+		m->m_flag |= 0x02;
+		if (!threaded)
+			loud_error(0, "coll: error reading text file '%s'", fn->s_name);
+	}
+    else if (!binbuf_read(bb, buf, "", 0))
+    {
+		int nlines = collcommon_frombinbuf(cc, bb);
+		if (nlines > 0)
+		{
+			t_coll *x;
+			/* LATER consider making this more robust */
+			for (x = cc->c_refs; x; x = x->x_next)
+			//outlet_bang(x->x_filebangout);
+			cc->c_lastcanvas = cv;
+			cc->c_filename = fn;
+			m->m_flag |= 0x04;
+			m->m_line = nlines;
+			if (!threaded)
+				post("coll: finished reading %d lines from text file '%s'",
+					nlines, fn->s_name);
+		}
+		else if (nlines < 0) {
+			m->m_flag |= 0x08;
+			m->m_line = 1 - nlines;
+			if (!threaded)
+				loud_error(0, "coll: error in line %d of text file '%s'",
+					1 - nlines, fn->s_name);
+		}
+		else {
+			m->m_flag |= 0x16;
+			if (!threaded)
+				loud_error(0, "coll: error reading text file '%s'", fn->s_name);
+		}
+		if (cc->c_refs)
+			collcommon_modified(cc, 1);
+	}
     binbuf_free(bb);
+	return(m);
 }
 
 static void collcommon_readhook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
 {
-    collcommon_doread((t_collcommon *)z, fn, 0);
+    collcommon_doread((t_collcommon *)z, fn, 0, 0);
 }
 
 static void collcommon_tobinbuf(t_collcommon *cc, t_binbuf *bb)
@@ -666,14 +823,17 @@
     }
 }
 
-static void collcommon_dowrite(t_collcommon *cc, t_symbol *fn, t_canvas *cv)
+static t_msg *collcommon_dowrite(t_collcommon *cc, t_symbol *fn, t_canvas *cv, int threaded)
 {
     t_binbuf *bb;
     int ac;
     t_atom *av;
+	t_msg *m = (t_msg *)(getbytes(sizeof(*m)));
+	m->m_flag = 0;
+	m->m_line = 0;
     char buf[MAXPDSTRING];
     if (!fn && !(fn = cc->c_filename))  /* !fn: 'writeagain' */
-	return;
+		return(0);
     if (cv || (cv = cc->c_lastcanvas))  /* !cv: 'write' w/o arg, 'writeagain' */
 	canvas_makefilename(cv, fn->s_name, buf, MAXPDSTRING);
     else
@@ -683,19 +843,24 @@
     }
     bb = binbuf_new();
     collcommon_tobinbuf(cc, bb);
-    if (binbuf_write(bb, buf, "", 0))
-	loud_error(0, "coll: error writing text file '%s'", fn->s_name);
+    if (binbuf_write(bb, buf, "", 0)) {
+		m->m_flag |= 0x32;
+		if (!threaded)
+			loud_error(0, "coll: error writing text file '%s'", fn->s_name);
+	}
     else
-    {
-	cc->c_lastcanvas = cv;
-	cc->c_filename = fn;
-    }
+		if (!binbuf_write(bb, buf, "", 0))
+		{
+			cc->c_lastcanvas = cv;
+			cc->c_filename = fn;
+		}
     binbuf_free(bb);
+	return(m);
 }
 
 static void collcommon_writehook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
 {
-    collcommon_dowrite((t_collcommon *)z, fn, 0);
+    collcommon_dowrite((t_collcommon *)z, fn, 0, 0);
 }
 
 static void coll_embedhook(t_pd *z, t_binbuf *bb, t_symbol *bindsym)
@@ -823,11 +988,17 @@
 	cc = (t_collcommon *)collcommon_new();
 	cc->c_refs = 0;
 	cc->c_increation = 0;
+	//x->x_common = cc;
+	//x->x_s = name;
 	if (name)
 	{
 	    pd_bind(&cc->c_pd, name);
 	    /* LATER rethink canvas unpredictability */
-	    collcommon_doread(cc, name, x->x_canvas);
+		//x->unsafe = 1;
+		//pthread_mutex_lock(&x->unsafe_mutex);
+		//pthread_cond_signal(&x->unsafe_cond);
+		//pthread_mutex_unlock(&x->unsafe_mutex);
+	    collcommon_doread(cc, name, x->x_canvas, 0);
 	}
 	else
 	{
@@ -950,234 +1121,264 @@
 
 static void coll_float(t_coll *x, t_float f)
 {
-    t_collcommon *cc = x->x_common;
-    t_collelem *ep;
-    int numkey;
-    if (loud_checkint((t_pd *)x, f, &numkey, &s_float) &&
-	(ep = collcommon_numkey(cc, numkey)))
-    {
-	coll_keyoutput(x, ep);
-	if (!cc->c_selfmodified || (ep = collcommon_numkey(cc, numkey)))
-	    coll_dooutput(x, ep->e_size, ep->e_data);
-    }
+	//if (!x->busy) {
+		t_collcommon *cc = x->x_common;
+		t_collelem *ep;
+		int numkey;
+		if (loud_checkint((t_pd *)x, f, &numkey, &s_float) &&
+		(ep = collcommon_numkey(cc, numkey)))
+		{
+		coll_keyoutput(x, ep);
+		if (!cc->c_selfmodified || (ep = collcommon_numkey(cc, numkey)))
+			coll_dooutput(x, ep->e_size, ep->e_data);
+		}
+	//}
 }
 
 static void coll_symbol(t_coll *x, t_symbol *s)
 {
-    t_collcommon *cc = x->x_common;
-    t_collelem *ep;
-    if (ep = collcommon_symkey(cc, s))
-    {
-	coll_keyoutput(x, ep);
-	if (!cc->c_selfmodified || (ep = collcommon_symkey(cc, s)))
-	    coll_dooutput(x, ep->e_size, ep->e_data);
-    }
+	//if (!x->busy) {
+		t_collcommon *cc = x->x_common;
+		t_collelem *ep;
+		if (ep = collcommon_symkey(cc, s))
+		{
+		coll_keyoutput(x, ep);
+		if (!cc->c_selfmodified || (ep = collcommon_symkey(cc, s)))
+			coll_dooutput(x, ep->e_size, ep->e_data);
+		}
+	//}
 }
 
 static void coll_list(t_coll *x, t_symbol *s, int ac, t_atom *av)
 {
-    if (ac >= 2 && av->a_type == A_FLOAT)
-	coll_tokey(x, av, ac-1, av+1, 1, &s_list);
-    else
-	loud_messarg((t_pd *)x, &s_list);
+	//if (!x->busy) {
+		if (ac >= 2 && av->a_type == A_FLOAT)
+		coll_tokey(x, av, ac-1, av+1, 1, &s_list);
+		else
+		loud_messarg((t_pd *)x, &s_list);
+	//}
 }
 
 static void coll_anything(t_coll *x, t_symbol *s, int ac, t_atom *av)
 {
-    coll_symbol(x, s);
+	//if (!x->busy)
+    	coll_symbol(x, s);
 }
 
 static void coll_store(t_coll *x, t_symbol *s, int ac, t_atom *av)
 {
-    if (ac >= 2)
-	coll_tokey(x, av, ac-1, av+1, 1, s);
-    else
-	loud_messarg((t_pd *)x, s);
+	//if (!x->busy) {
+		if (ac >= 2)
+		coll_tokey(x, av, ac-1, av+1, 1, s);
+		else
+		loud_messarg((t_pd *)x, s);
+	//}
 }
 
 static void coll_nstore(t_coll *x, t_symbol *s, int ac, t_atom *av)
 {
-    if (ac >= 3)
-    {
-	t_collcommon *cc = x->x_common;
-	t_collelem *ep;
-	int numkey;
-	if (av->a_type == A_FLOAT && av[1].a_type == A_SYMBOL)
-	{
-	    if (loud_checkint((t_pd *)x, av->a_w.w_float, &numkey, s))
-	    {
-		if (ep = collcommon_symkey(cc, av[1].a_w.w_symbol))
-		    collcommon_remove(cc, ep);
-		ep = collcommon_tonumkey(cc, numkey, ac-2, av+2, 1);
-		ep->e_symkey = av[1].a_w.w_symbol;
-	    }
-	}
-	else if (av->a_type == A_SYMBOL && av[1].a_type == A_FLOAT)
-	{
-	    if (loud_checkint((t_pd *)x, av[1].a_w.w_float, &numkey, s))
-	    {
-		if (ep = collcommon_numkey(cc, numkey))
-		    collcommon_remove(cc, ep);
-		ep = collcommon_tosymkey(cc, av->a_w.w_symbol, ac-2, av+2, 1);
-		ep->e_hasnumkey = 1;
-		ep->e_numkey = numkey;
-	    }
-	}
-	else loud_messarg((t_pd *)x, s);
-    }
-    else loud_messarg((t_pd *)x, s);
+	//if (!x->busy) {
+		if (ac >= 3)
+		{
+		t_collcommon *cc = x->x_common;
+		t_collelem *ep;
+		int numkey;
+		if (av->a_type == A_FLOAT && av[1].a_type == A_SYMBOL)
+		{
+			if (loud_checkint((t_pd *)x, av->a_w.w_float, &numkey, s))
+			{
+			if (ep = collcommon_symkey(cc, av[1].a_w.w_symbol))
+				collcommon_remove(cc, ep);
+			ep = collcommon_tonumkey(cc, numkey, ac-2, av+2, 1);
+			ep->e_symkey = av[1].a_w.w_symbol;
+			}
+		}
+		else if (av->a_type == A_SYMBOL && av[1].a_type == A_FLOAT)
+		{
+			if (loud_checkint((t_pd *)x, av[1].a_w.w_float, &numkey, s))
+			{
+			if (ep = collcommon_numkey(cc, numkey))
+				collcommon_remove(cc, ep);
+			ep = collcommon_tosymkey(cc, av->a_w.w_symbol, ac-2, av+2, 1);
+			ep->e_hasnumkey = 1;
+			ep->e_numkey = numkey;
+			}
+		}
+		else loud_messarg((t_pd *)x, s);
+		}
+		else loud_messarg((t_pd *)x, s);
+	//}
 }
 
 static void coll_insert(t_coll *x, t_symbol *s, int ac, t_atom *av)
 {
-    if (ac >= 2 && av->a_type == A_FLOAT)
-	coll_tokey(x, av, ac-1, av+1, 0, s);
-    else
-	loud_messarg((t_pd *)x, s);
+	//if (!x->busy) {
+		if (ac >= 2 && av->a_type == A_FLOAT)
+		coll_tokey(x, av, ac-1, av+1, 0, s);
+		else
+		loud_messarg((t_pd *)x, s);
+	//}
 }
 
 static void coll_remove(t_coll *x, t_symbol *s, int ac, t_atom *av)
 {
-    if (ac)
-    {
-	t_collelem *ep;
-	if (ep = coll_findkey(x, av, s))
-	    collcommon_remove(x->x_common, ep);
-    }
-    else loud_messarg((t_pd *)x, s);
+	//if (!x->busy) {
+		if (ac)
+		{
+		t_collelem *ep;
+		if (ep = coll_findkey(x, av, s))
+			collcommon_remove(x->x_common, ep);
+		}
+		else loud_messarg((t_pd *)x, s);
+	//}
 }
 
 static void coll_delete(t_coll *x, t_symbol *s, int ac, t_atom *av)
 {
-    if (ac)
-    {
-	t_collelem *ep;
-	if (ep = coll_findkey(x, av, s))
-	{
-	    if (av->a_type == A_FLOAT)
-	    {
-		int numkey = ep->e_numkey;
-		t_collelem *next;
-		for (next = ep->e_next; next; next = next->e_next)
-		    if (next->e_hasnumkey && next->e_numkey > numkey)
-			next->e_numkey--;
-	    }
-	    collcommon_remove(x->x_common, ep);
-	}
-    }
-    else loud_messarg((t_pd *)x, s);
+	//if (!x->busy) {
+		if (ac)
+		{
+			t_collelem *ep;
+			if (ep = coll_findkey(x, av, s))
+			{
+				if (av->a_type == A_FLOAT)
+				{
+				int numkey = ep->e_numkey;
+				t_collelem *next;
+				for (next = ep->e_next; next; next = next->e_next)
+					if (next->e_hasnumkey && next->e_numkey > numkey)
+					next->e_numkey--;
+				}
+				collcommon_remove(x->x_common, ep);
+			}
+		}
+		else loud_messarg((t_pd *)x, s);
+	//}
 }
 
 static void coll_assoc(t_coll *x, t_symbol *s, t_floatarg f)
 {
-    int numkey;
-    if (loud_checkint((t_pd *)x, f, &numkey, gensym("assoc")))
-    {
-	t_collcommon *cc = x->x_common;
-	t_collelem *ep1, *ep2;
-	if ((ep1 = collcommon_numkey(cc, numkey)) &&
-	    ep1->e_symkey != s)  /* LATER rethink */
-	{
-	    if (ep2 = collcommon_symkey(cc, s))
-		collcommon_remove(cc, ep2);
-	    collcommon_changesymkey(cc, ep1, s);
-	}
-    }
+	//if (!x->busy) {
+		int numkey;
+		if (loud_checkint((t_pd *)x, f, &numkey, gensym("assoc")))
+		{
+			t_collcommon *cc = x->x_common;
+			t_collelem *ep1, *ep2;
+			if ((ep1 = collcommon_numkey(cc, numkey)) &&
+				ep1->e_symkey != s)  /* LATER rethink */
+			{
+				if (ep2 = collcommon_symkey(cc, s))
+				collcommon_remove(cc, ep2);
+				collcommon_changesymkey(cc, ep1, s);
+			}
+		}
+	//}
 }
 		
 static void coll_deassoc(t_coll *x, t_symbol *s, t_floatarg f)
 {
-    int numkey;
-    if (loud_checkint((t_pd *)x, f, &numkey, gensym("deassoc")))
-    {
-	t_collcommon *cc = x->x_common;
-	t_collelem *ep;
-	if (ep = collcommon_numkey(cc, numkey))
-	    collcommon_changesymkey(cc, ep, 0);
-    }
+	//if (!x->busy) {
+		int numkey;
+		if (loud_checkint((t_pd *)x, f, &numkey, gensym("deassoc")))
+		{
+			t_collcommon *cc = x->x_common;
+			t_collelem *ep;
+			if (ep = collcommon_numkey(cc, numkey))
+				collcommon_changesymkey(cc, ep, 0);
+		}
+	//}
 }
 
 static void coll_subsym(t_coll *x, t_symbol *s1, t_symbol *s2)
 {
-    t_collelem *ep;
-    if (s1 != s2 && (ep = collcommon_symkey(x->x_common, s2)))
-	collcommon_changesymkey(x->x_common, ep, s1);
+	//if (!x->busy) {
+		t_collelem *ep;
+		if (s1 != s2 && (ep = collcommon_symkey(x->x_common, s2)))
+		collcommon_changesymkey(x->x_common, ep, s1);
+	//}
 }
 
 static void coll_renumber(t_coll *x, t_floatarg f)
 {
-    int startkey;
-    if (loud_checkint((t_pd *)x, f, &startkey, gensym("renumber")))
-	collcommon_renumber(x->x_common, startkey);
+	//if (!x->busy) {
+		int startkey;
+		if (loud_checkint((t_pd *)x, f, &startkey, gensym("renumber")))
+		collcommon_renumber(x->x_common, startkey);
+	//}
 }
 
 static void coll_merge(t_coll *x, t_symbol *s, int ac, t_atom *av)
 {
-    if (ac >= 2)
-    {
-	t_collcommon *cc = x->x_common;
-	t_collelem *ep;
-	if (av->a_type == A_FLOAT)
-	{
-	    int numkey;
-	    if (loud_checkint((t_pd *)x, av->a_w.w_float, &numkey, s))
-	    {
-		if (ep = collcommon_numkey(cc, numkey))
-		    collcommon_adddata(cc, ep, ac-1, av+1);
-		else  /* LATER consider defining collcommon_toclosest() */
-		    collcommon_tonumkey(cc, numkey, ac-1, av+1, 1);
-	    }
-	}
-	else if (av->a_type == A_SYMBOL)
-	{
-	    if (ep = collcommon_symkey(cc, av->a_w.w_symbol))
-		collcommon_adddata(cc, ep, ac-1, av+1);
-	    else
-	    {
-		ep = collelem_new(ac-1, av+1, 0, av->a_w.w_symbol);
-		collcommon_putafter(cc, ep, cc->c_last);
-	    }
-	}
-	else loud_messarg((t_pd *)x, s);
-    }
-    else loud_messarg((t_pd *)x, s);
+	//if (!x->busy) {
+		if (ac >= 2)
+		{
+			t_collcommon *cc = x->x_common;
+			t_collelem *ep;
+			if (av->a_type == A_FLOAT)
+			{
+				int numkey;
+				if (loud_checkint((t_pd *)x, av->a_w.w_float, &numkey, s))
+				{
+				if (ep = collcommon_numkey(cc, numkey))
+					collcommon_adddata(cc, ep, ac-1, av+1);
+				else  /* LATER consider defining collcommon_toclosest() */
+					collcommon_tonumkey(cc, numkey, ac-1, av+1, 1);
+				}
+			}
+			else if (av->a_type == A_SYMBOL)
+			{
+				if (ep = collcommon_symkey(cc, av->a_w.w_symbol))
+				collcommon_adddata(cc, ep, ac-1, av+1);
+				else
+				{
+					ep = collelem_new(ac-1, av+1, 0, av->a_w.w_symbol);
+					collcommon_putafter(cc, ep, cc->c_last);
+				}
+			}
+			else loud_messarg((t_pd *)x, s);
+		}
+		else loud_messarg((t_pd *)x, s);
+	//}
 }
 
 static void coll_sub(t_coll *x, t_symbol *s, int ac, t_atom *av)
 {
-    if (ac)
-    {
-	t_collelem *ep;
-	if (ep = coll_findkey(x, av, s))
-	{
-	    t_collcommon *cc = x->x_common;
-	    t_atom *key = av++;
-	    ac--;
-	    while (ac >= 2)
-	    {
-		if (av->a_type == A_FLOAT)
+	//if (!x->busy) {
+		if (ac)
 		{
-		    int ndx;
-		    if (loud_checkint((t_pd *)x, av->a_w.w_float, &ndx, 0)
-			&& ndx >= 1 && ndx <= ep->e_size)
-			ep->e_data[ndx-1] = av[1];
+			t_collelem *ep;
+			if (ep = coll_findkey(x, av, s))
+			{
+				t_collcommon *cc = x->x_common;
+				t_atom *key = av++;
+				ac--;
+				while (ac >= 2)
+				{
+					if (av->a_type == A_FLOAT)
+					{
+						int ndx;
+						if (loud_checkint((t_pd *)x, av->a_w.w_float, &ndx, 0)
+						&& ndx >= 1 && ndx <= ep->e_size)
+						ep->e_data[ndx-1] = av[1];
+					}
+					ac -= 2;
+					av += 2;
+				}
+				if (s == gensym("sub"))
+				{
+				coll_keyoutput(x, ep);
+				if (!cc->c_selfmodified || (ep = coll_findkey(x, key, 0)))
+					coll_dooutput(x, ep->e_size, ep->e_data);
+				}
+			}
 		}
-		ac -= 2;
-		av += 2;
-	    }
-	    if (s == gensym("sub"))
-	    {
-		coll_keyoutput(x, ep);
-		if (!cc->c_selfmodified || (ep = coll_findkey(x, key, 0)))
-		    coll_dooutput(x, ep->e_size, ep->e_data);
-	    }
-	}
-    }
-    else loud_messarg((t_pd *)x, s);
+		else loud_messarg((t_pd *)x, s);
+	//}
 }
 
 static void coll_sort(t_coll *x, t_floatarg f1, t_floatarg f2)
 {
+
     int dir, ndx;
     if (loud_checkint((t_pd *)x, f1, &dir, gensym("sort")) &&
 	loud_checkint((t_pd *)x, f2, &ndx, gensym("sort")))
@@ -1195,14 +1396,16 @@
    needed in case of their implementation... */
 static void coll_swap(t_coll *x, t_symbol *s, int ac, t_atom *av)
 {
-    if (ac == 2)
-    {
-	t_collelem *ep1, *ep2;
-	if ((ep1 = coll_findkey(x, av, s)) &&
-	    (ep2 = coll_findkey(x, av + 1, s)))
-	    collcommon_swapkeys(x->x_common, ep1, ep2);
-    }
-    else loud_messarg((t_pd *)x, s);
+	//if (!x->busy) {
+		if (ac == 2)
+		{
+		t_collelem *ep1, *ep2;
+		if ((ep1 = coll_findkey(x, av, s)) &&
+			(ep2 = coll_findkey(x, av + 1, s)))
+			collcommon_swapkeys(x->x_common, ep1, ep2);
+		}
+		else loud_messarg((t_pd *)x, s);
+	//}
 }
 
 /* CHECKED traversal direction change is consistent with the general rule:
@@ -1214,212 +1417,296 @@
 
 static void coll_next(t_coll *x)
 {
-    t_collcommon *cc = x->x_common;
-    if (cc->c_headstate != COLL_HEADRESET &&
-	cc->c_headstate != COLL_HEADDELETED)  /* asymmetric, LATER rethink */
-    {
-	if (cc->c_head)
-	    cc->c_head = cc->c_head->e_next;
-	if (!cc->c_head && !(cc->c_head = cc->c_first))  /* CHECKED wrapping */
-	    return;
-    }
-    else if (!cc->c_head && !(cc->c_head = cc->c_first))
-	return;
-    cc->c_headstate = COLL_HEADNEXT;
-    coll_keyoutput(x, cc->c_head);
-    if (cc->c_head)
-	coll_dooutput(x, cc->c_head->e_size, cc->c_head->e_data);
-    else if (!cc->c_selfmodified)
-	loudbug_bug("coll_next");  /* LATER rethink */
+	//if (!x->busy) {
+		t_collcommon *cc = x->x_common;
+		if (cc->c_headstate != COLL_HEADRESET &&
+		cc->c_headstate != COLL_HEADDELETED)  /* asymmetric, LATER rethink */
+		{
+		if (cc->c_head)
+			cc->c_head = cc->c_head->e_next;
+		if (!cc->c_head && !(cc->c_head = cc->c_first))  /* CHECKED wrapping */
+			return;
+		}
+		else if (!cc->c_head && !(cc->c_head = cc->c_first))
+		return;
+		cc->c_headstate = COLL_HEADNEXT;
+		coll_keyoutput(x, cc->c_head);
+		if (cc->c_head)
+		coll_dooutput(x, cc->c_head->e_size, cc->c_head->e_data);
+		else if (!cc->c_selfmodified)
+		loudbug_bug("coll_next");  /* LATER rethink */
+	//}
 }
 
 static void coll_prev(t_coll *x)
 {
-    t_collcommon *cc = x->x_common;
-    if (cc->c_headstate != COLL_HEADRESET)
-    {
-	if (cc->c_head)
-	    cc->c_head = cc->c_head->e_prev;
-	if (!cc->c_head && !(cc->c_head = cc->c_last))  /* CHECKED wrapping */
-	    return;
-    }
-    else if (!cc->c_head && !(cc->c_head = cc->c_first))
-	return;
-    cc->c_headstate = COLL_HEADPREV;
-    coll_keyoutput(x, cc->c_head);
-    if (cc->c_head)
-	coll_dooutput(x, cc->c_head->e_size, cc->c_head->e_data);
-    else if (!cc->c_selfmodified)
-	loudbug_bug("coll_prev");  /* LATER rethink */
+	//if (!x->busy) {
+		t_collcommon *cc = x->x_common;
+		if (cc->c_headstate != COLL_HEADRESET)
+		{
+			if (cc->c_head)
+				cc->c_head = cc->c_head->e_prev;
+			if (!cc->c_head && !(cc->c_head = cc->c_last))  /* CHECKED wrapping */
+				return;
+		}
+		else if (!cc->c_head && !(cc->c_head = cc->c_first))
+		return;
+		cc->c_headstate = COLL_HEADPREV;
+		coll_keyoutput(x, cc->c_head);
+		if (cc->c_head)
+		coll_dooutput(x, cc->c_head->e_size, cc->c_head->e_data);
+		else if (!cc->c_selfmodified)
+		loudbug_bug("coll_prev");  /* LATER rethink */
+	//}
+}
+
+static void coll_start(t_coll *x)
+{
+	//if (!x->busy) {
+		t_collcommon *cc = x->x_common;
+		cc->c_head = cc->c_first;
+		cc->c_headstate = COLL_HEADRESET;
+	//}
 }
 
 static void coll_end(t_coll *x)
 {
-    t_collcommon *cc = x->x_common;
-    cc->c_head = cc->c_last;
-    cc->c_headstate = COLL_HEADRESET;
+	//if (!x->busy) {
+		t_collcommon *cc = x->x_common;
+		cc->c_head = cc->c_last;
+		cc->c_headstate = COLL_HEADRESET;
+	//}
 }
 
 static void coll_goto(t_coll *x, t_symbol *s, int ac, t_atom *av)
 {
-    if (ac)
-    {
-	t_collelem *ep = coll_findkey(x, av, s);
-	if (ep)
-	{
-	    t_collcommon *cc = x->x_common;
-	    cc->c_head = ep;
-	    cc->c_headstate = COLL_HEADRESET;
-	}
-    }
-    else loud_messarg((t_pd *)x, s);
+	//if (!x->busy) {
+		if (ac)
+		{
+			t_collelem *ep = coll_findkey(x, av, s);
+			if (ep)
+			{
+				t_collcommon *cc = x->x_common;
+				cc->c_head = ep;
+				cc->c_headstate = COLL_HEADRESET;
+			}
+		}
+		//else loud_messarg((t_pd *)x, s);
+		else coll_start(x);
+	//}
 }
 
 static void coll_nth(t_coll *x, t_symbol *s, int ac, t_atom *av)
 {
-    if (ac >= 2 && av[1].a_type == A_FLOAT)
-    {
-	int ndx;
-	t_collelem *ep;
-	if (loud_checkint((t_pd *)x, av[1].a_w.w_float, &ndx, s) &&
-	    (ep = coll_findkey(x, av, s)) &&
-	    ep->e_size >= ndx)
-	{
-	    t_atom *ap = ep->e_data + --ndx;
-	    if (ap->a_type == A_FLOAT)
-		outlet_float(((t_object *)x)->ob_outlet, ap->a_w.w_float);
-	    else if (ap->a_type == A_SYMBOL)
-		outlet_symbol(((t_object *)x)->ob_outlet, ap->a_w.w_symbol);
-	}
-    }
-    else loud_messarg((t_pd *)x, s);
+	//if (!x->busy) {
+		if (ac >= 2 && av[1].a_type == A_FLOAT)
+		{
+			int ndx;
+			t_collelem *ep;
+			if (loud_checkint((t_pd *)x, av[1].a_w.w_float, &ndx, s) &&
+				(ep = coll_findkey(x, av, s)) &&
+				ep->e_size >= ndx)
+			{
+				t_atom *ap = ep->e_data + --ndx;
+				if (ap->a_type == A_FLOAT)
+				outlet_float(((t_object *)x)->ob_outlet, ap->a_w.w_float);
+				else if (ap->a_type == A_SYMBOL)
+				outlet_symbol(((t_object *)x)->ob_outlet, ap->a_w.w_symbol);
+			}
+		}
+		else loud_messarg((t_pd *)x, s);
+	//}
 }
 
 static void coll_length(t_coll *x)
 {
-    t_collcommon *cc = x->x_common;
-    t_collelem *ep = cc->c_first;
-    int result = 0;
-    while (ep) result++, ep = ep->e_next;
-    outlet_float(((t_object *)x)->ob_outlet, result);
+	//if (!x->busy) {
+		t_collcommon *cc = x->x_common;
+		t_collelem *ep = cc->c_first;
+		int result = 0;
+		while (ep) result++, ep = ep->e_next;
+		outlet_float(((t_object *)x)->ob_outlet, result);
+	//}
 }
 
 static void coll_min(t_coll *x, t_floatarg f)
 {
-    int ndx;
-    if (loud_checkint((t_pd *)x, f, &ndx, gensym("min")))
-    {
-	t_collelem *found;
-	if (ndx > 0)
-	    ndx--;
-	/* LATER consider complaining: */
-	else if (ndx < 0)
-	    return;  /* CHECKED silently rejected */
-	/* else CHECKED silently defaults to 1 */
-	if (found = coll_firsttyped(x, ndx, A_FLOAT))
-	{
-	    t_float result = found->e_data[ndx].a_w.w_float;
-	    t_collelem *ep;
-	    for (ep = found->e_next; ep; ep = ep->e_next)
-	    {
-		if (ep->e_size > ndx &&
-		    ep->e_data[ndx].a_type == A_FLOAT &&
-		    ep->e_data[ndx].a_w.w_float < result)
+	//if (!x->busy) {
+		int ndx;
+		if (loud_checkint((t_pd *)x, f, &ndx, gensym("min")))
 		{
-		    found = ep;
-		    result = ep->e_data[ndx].a_w.w_float;
+			t_collelem *found;
+			if (ndx > 0)
+				ndx--;
+			/* LATER consider complaining: */
+			else if (ndx < 0)
+				return;  /* CHECKED silently rejected */
+			/* else CHECKED silently defaults to 1 */
+			if (found = coll_firsttyped(x, ndx, A_FLOAT))
+			{
+				t_float result = found->e_data[ndx].a_w.w_float;
+				t_collelem *ep;
+				for (ep = found->e_next; ep; ep = ep->e_next)
+				{
+				if (ep->e_size > ndx &&
+					ep->e_data[ndx].a_type == A_FLOAT &&
+					ep->e_data[ndx].a_w.w_float < result)
+				{
+					found = ep;
+					result = ep->e_data[ndx].a_w.w_float;
+				}
+				}
+				coll_keyoutput(x, found);
+				outlet_float(((t_object *)x)->ob_outlet, result);
+			}
 		}
-	    }
-	    coll_keyoutput(x, found);
-	    outlet_float(((t_object *)x)->ob_outlet, result);
-	}
-    }
+	//}
 }
 
 static void coll_max(t_coll *x, t_floatarg f)
 {
-    int ndx;
-    if (loud_checkint((t_pd *)x, f, &ndx, gensym("max")))
-    {
-	t_collelem *found;
-	if (ndx > 0)
-	    ndx--;
-	/* LATER consider complaining: */
-	else if (ndx < 0)
-	    return;  /* CHECKED silently rejected */
-	/* else CHECKED silently defaults to 1 */
-	if (found = coll_firsttyped(x, ndx, A_FLOAT))
-	{
-	    t_float result = found->e_data[ndx].a_w.w_float;
-	    t_collelem *ep;
-	    for (ep = found->e_next; ep; ep = ep->e_next)
-	    {
-		if (ep->e_size > ndx &&
-		    ep->e_data[ndx].a_type == A_FLOAT &&
-		    ep->e_data[ndx].a_w.w_float > result)
+	//if (!x->busy) {
+		int ndx;
+		if (loud_checkint((t_pd *)x, f, &ndx, gensym("max")))
 		{
-		    found = ep;
-		    result = ep->e_data[ndx].a_w.w_float;
+			t_collelem *found;
+			if (ndx > 0)
+				ndx--;
+			/* LATER consider complaining: */
+			else if (ndx < 0)
+				return;  /* CHECKED silently rejected */
+			/* else CHECKED silently defaults to 1 */
+			if (found = coll_firsttyped(x, ndx, A_FLOAT))
+			{
+				t_float result = found->e_data[ndx].a_w.w_float;
+				t_collelem *ep;
+				for (ep = found->e_next; ep; ep = ep->e_next)
+				{
+				if (ep->e_size > ndx &&
+					ep->e_data[ndx].a_type == A_FLOAT &&
+					ep->e_data[ndx].a_w.w_float > result)
+				{
+					found = ep;
+					result = ep->e_data[ndx].a_w.w_float;
+				}
+				}
+				coll_keyoutput(x, found);
+				outlet_float(((t_object *)x)->ob_outlet, result);
+			}
 		}
-	    }
-	    coll_keyoutput(x, found);
-	    outlet_float(((t_object *)x)->ob_outlet, result);
-	}
-    }
+	//}
 }
 
 static void coll_refer(t_coll *x, t_symbol *s)
 {
-    if (!coll_rebind(x, s))
-    {
-	/* LATER consider complaining */
-    }
+	//if (!x->busy) {
+		if (!coll_rebind(x, s))
+		{
+		/* LATER consider complaining */
+		}
+	//}
 }
 
 static void coll_flags(t_coll *x, t_float f1, t_float f2)
 {
-    int i1;
-    if (loud_checkint((t_pd *)x, f1, &i1, gensym("flags")))
-    {
-	t_collcommon *cc = x->x_common;
-	cc->c_embedflag = (i1 != 0);
-    }
+	//if (!x->busy) {
+		int i1;
+		if (loud_checkint((t_pd *)x, f1, &i1, gensym("flags")))
+		{
+			t_collcommon *cc = x->x_common;
+			cc->c_embedflag = (i1 != 0);
+		}
+	//}
 }
 
 static void coll_read(t_coll *x, t_symbol *s)
 {
-    t_collcommon *cc = x->x_common;
-    if (s && s != &s_)
-	collcommon_doread(cc, s, x->x_canvas);
-    else
-	hammerpanel_open(cc->c_filehandle, 0);
+	if (!x->unsafe) {
+		t_collcommon *cc = x->x_common;
+		if (s && s != &s_) {
+			x->x_s = s;
+			if (x->threaded == 1) {
+				x->unsafe = 1;
+
+				pthread_mutex_lock(&x->unsafe_mutex);
+				pthread_cond_signal(&x->unsafe_cond);
+				pthread_mutex_unlock(&x->unsafe_mutex);
+				//collcommon_doread(cc, s, x->x_canvas, 0);
+			}
+			else {
+				collcommon_doread(cc, s, x->x_canvas, 0);
+			}
+		}
+		else
+			hammerpanel_open(cc->c_filehandle, 0);
+	}
 }
 
 static void coll_write(t_coll *x, t_symbol *s)
 {
-    t_collcommon *cc = x->x_common;
-    if (s && s != &s_)
-	collcommon_dowrite(cc, s, x->x_canvas);
-    else
-	hammerpanel_save(cc->c_filehandle, 0, 0);  /* CHECKED no default name */
+	if (!x->unsafe) {
+		t_collcommon *cc = x->x_common;
+		if (s && s != &s_) {
+			x->x_s = s;
+			if (x->threaded == 1) {
+				x->unsafe = 10;
+
+				pthread_mutex_lock(&x->unsafe_mutex);
+				pthread_cond_signal(&x->unsafe_cond);
+				pthread_mutex_unlock(&x->unsafe_mutex);
+				//collcommon_dowrite(cc, s, x->x_canvas, 0);
+			}
+			else {
+				collcommon_dowrite(cc, s, x->x_canvas, 0);
+			}
+		}
+		else
+			hammerpanel_save(cc->c_filehandle, 0, 0);  /* CHECKED no default name */
+	}
 }
 
 static void coll_readagain(t_coll *x)
 {
-    t_collcommon *cc = x->x_common;
-    if (cc->c_filename)
-	collcommon_doread(cc, 0, 0);
-    else
-	hammerpanel_open(cc->c_filehandle, 0);
+	//if (!x->busy) {
+		t_collcommon *cc = x->x_common;
+		if (cc->c_filename) {
+			if (x->threaded == 1) {
+				x->unsafe = 2;
+
+				pthread_mutex_lock(&x->unsafe_mutex);
+				pthread_cond_signal(&x->unsafe_cond);
+				pthread_mutex_unlock(&x->unsafe_mutex);
+				//collcommon_doread(cc, 0, 0, 0);
+			}
+			else {
+				collcommon_doread(cc, 0, 0, 0);
+			}
+		}
+		else
+		hammerpanel_open(cc->c_filehandle, 0);
+	//}
 }
 
 static void coll_writeagain(t_coll *x)
 {
-    t_collcommon *cc = x->x_common;
-    if (cc->c_filename)
-	collcommon_dowrite(cc, 0, 0);
-    else
-	hammerpanel_save(cc->c_filehandle, 0, 0);  /* CHECKED no default name */
+	//if (!x->busy) {
+		t_collcommon *cc = x->x_common;
+		if (cc->c_filename) {
+			if (x->threaded == 1) {
+				x->unsafe = 11;
+
+				pthread_mutex_lock(&x->unsafe_mutex);
+				pthread_cond_signal(&x->unsafe_cond);
+				pthread_mutex_unlock(&x->unsafe_mutex);
+				//collcommon_dowrite(cc, 0, 0, 0);
+			}
+			else {
+				collcommon_dowrite(cc, 0, 0, 0);
+			}
+		}
+		else
+		hammerpanel_save(cc->c_filehandle, 0, 0);  /* CHECKED no default name */
+	//}
 }
 
 static void coll_filetype(t_coll *x, t_symbol *s)
@@ -1429,17 +1716,19 @@
 
 static void coll_dump(t_coll *x)
 {
-    t_collcommon *cc = x->x_common;
-    t_collelem *ep;
-    for (ep = cc->c_first; ep; ep = ep->e_next)
-    {
-	coll_keyoutput(x, ep);
-	if (cc->c_selfmodified)
-	    break;
-	coll_dooutput(x, ep->e_size, ep->e_data);
-	/* FIXME dooutput() may invalidate ep as well as keyoutput()... */
-    }
-    outlet_bang(x->x_dumpbangout);
+	//if (!x->busy) {
+		t_collcommon *cc = x->x_common;
+		t_collelem *ep;
+		for (ep = cc->c_first; ep; ep = ep->e_next)
+		{
+		coll_keyoutput(x, ep);
+		if (cc->c_selfmodified)
+			break;
+		coll_dooutput(x, ep->e_size, ep->e_data);
+		/* FIXME dooutput() may invalidate ep as well as keyoutput()... */
+		}
+		outlet_bang(x->x_dumpbangout);
+	//}
 }
 
 static void coll_open(t_coll *x)
@@ -1490,15 +1779,17 @@
 #ifdef COLL_DEBUG
 static void collelem_post(t_collelem *ep)
 {
-    if (ep->e_hasnumkey && ep->e_symkey)
-	loudbug_startpost("%d %s:", ep->e_numkey, ep->e_symkey->s_name);
-    else if (ep->e_hasnumkey)
-	loudbug_startpost("%d:", ep->e_numkey);
-    else if (ep->e_symkey)
-	loudbug_startpost("%s:", ep->e_symkey->s_name);
-    else loudbug_bug("collcommon_post");
-    loudbug_postatom(ep->e_size, ep->e_data);
-    loudbug_endpost();
+	//if (!x->busy) {
+		if (ep->e_hasnumkey && ep->e_symkey)
+		loudbug_startpost("%d %s:", ep->e_numkey, ep->e_symkey->s_name);
+		else if (ep->e_hasnumkey)
+		loudbug_startpost("%d:", ep->e_numkey);
+		else if (ep->e_symkey)
+		loudbug_startpost("%s:", ep->e_symkey->s_name);
+		else loudbug_bug("collcommon_post");
+		loudbug_postatom(ep->e_size, ep->e_data);
+		loudbug_endpost();
+	//}
 }
 
 static void collcommon_post(t_collcommon *cc)
@@ -1509,43 +1800,111 @@
 
 static void coll_debug(t_coll *x, t_floatarg f)
 {
-    t_collcommon *cc = coll_checkcommon(x);
-    if (cc)
-    {
-	t_coll *x1 = cc->c_refs;
-	t_collelem *ep, *last;
-	int i = 0;
-	while (x1) i++, x1 = x1->x_next;
-	loudbug_post("refcount %d", i);
-	for (ep = cc->c_first, last = 0; ep; ep = ep->e_next) last = ep;
-	if (last != cc->c_last) loudbug_bug("coll_debug: last element");
-	collcommon_post(cc);
-    }
+	//if (!x->busy) {
+		t_collcommon *cc = coll_checkcommon(x);
+		if (cc)
+		{
+			t_coll *x1 = cc->c_refs;
+			t_collelem *ep, *last;
+			int i = 0;
+			while (x1) i++, x1 = x1->x_next;
+			loudbug_post("refcount %d", i);
+			for (ep = cc->c_first, last = 0; ep; ep = ep->e_next) last = ep;
+			if (last != cc->c_last) loudbug_bug("coll_debug: last element");
+			collcommon_post(cc);
+		}
+	//}
 }
 #endif
 
+static void *coll_threaded_fileio(void *ptr)
+{
+	t_threadedFunctionParams *rPars = (t_threadedFunctionParams*)ptr;
+	t_coll *x = rPars->x;
+	t_msg *m = NULL;
+
+	while(x->unsafe > -1) {
+		pthread_mutex_lock(&x->unsafe_mutex);
+		if (x->unsafe == 0)
+			if (!x->init) x->init = 1;
+			pthread_cond_wait(&x->unsafe_cond, &x->unsafe_mutex);		
+
+		if (x->unsafe == 1) { //read
+			m = collcommon_doread(x->x_common, x->x_s, x->x_canvas, 1);
+			if (m->m_flag)
+				coll_enqueue_threaded_msgs(x, m);
+			clock_delay(x->x_clock, 0);
+		}
+		else if (x->unsafe == 2) { //read
+			m = collcommon_doread(x->x_common, 0, 0, 1);
+			if (m->m_flag)
+				coll_enqueue_threaded_msgs(x, m);
+			clock_delay(x->x_clock, 0);
+		}
+		else if (x->unsafe == 10) { //write
+			m = collcommon_dowrite(x->x_common, x->x_s, x->x_canvas, 1);
+			if (m->m_flag)
+				coll_enqueue_threaded_msgs(x, m);
+		}
+		else if (x->unsafe == 11) { //write
+			m = collcommon_dowrite(x->x_common, 0, 0, 1);
+			if (m->m_flag)
+				coll_enqueue_threaded_msgs(x, m);
+		}
+
+		if (m != NULL)
+		{
+			t_freebytes(m, sizeof(*m));
+			m = NULL;
+		}
+
+		if (x->unsafe != -1) x->unsafe = 0;
+		pthread_mutex_unlock(&x->unsafe_mutex);
+	}
+	pthread_exit(0);
+}
+
 static void coll_separate(t_coll *x, t_floatarg f)
 {
-    int indx;
-    t_collcommon *cc = x->x_common;
-    if (loud_checkint((t_pd *)x, f, &indx, gensym("separate")))
-    {
-	t_collelem *ep;
-	for (ep = cc->c_first; ep; ep = ep->e_next)
-	    if (ep->e_hasnumkey && ep->e_numkey >= indx)
-		ep->e_numkey += 1;
-	collcommon_modified(cc, 0);
-    }
+	int indx;
+	t_collcommon *cc = x->x_common;
+	if (loud_checkint((t_pd *)x, f, &indx, gensym("separate")))
+	{
+		t_collelem *ep;
+		for (ep = cc->c_first; ep; ep = ep->e_next)
+			if (ep->e_hasnumkey && ep->e_numkey >= indx)
+				ep->e_numkey += 1;
+		collcommon_modified(cc, 0);
+	}
 }
 
 static void coll_free(t_coll *x)
 {
+	if (x->threaded == 1)
+	{
+		x->unsafe = -1;
+
+		pthread_mutex_lock(&x->unsafe_mutex);
+		pthread_cond_signal(&x->unsafe_cond);
+		pthread_mutex_unlock(&x->unsafe_mutex);
+
+		pthread_join(x->unsafe_t, NULL);
+		pthread_mutex_destroy(&x->unsafe_mutex);
+
+		clock_free(x->x_clock);
+		if (x->x_q)
+			coll_q_free(x);
+	}
+
     hammerfile_free(x->x_filehandle);
     coll_unbind(x);
 }
 
-static void *coll_new(t_symbol *s)
+static void *coll_new(t_symbol *s, int argc, t_atom *argv)
 {
+	int ret;
+	int count = 0;
+	t_symbol *file = NULL;
     t_coll *x = (t_coll *)pd_new(coll_class);
     x->x_canvas = canvas_getcurrent();
     outlet_new((t_object *)x, &s_);
@@ -1553,7 +1912,50 @@
     x->x_filebangout = outlet_new((t_object *)x, &s_bang);
     x->x_dumpbangout = outlet_new((t_object *)x, &s_bang);
     x->x_filehandle = hammerfile_new((t_pd *)x, coll_embedhook, 0, 0, 0);
-    coll_bind(x, s);
+
+    // check arguments for filename and threaded version
+    if (argc > 0)
+	{
+		while(count < argc)
+		{
+			if (argv[count].a_type == A_SYMBOL)
+			{
+				// we got a file name
+				file = gensym(atom_getsymbol(&argv[count])->s_name);
+			}
+			else if (argv[count].a_type == A_FLOAT)
+			{
+				// we got a flag for threaded (1) vs non-threaded (0)
+				x->threaded = (int)atom_getfloat(&argv[count]);
+				if (x->threaded < 0) x->threaded = 0;
+				if (x->threaded > 1) x->threaded = 1;
+			}
+			count++;
+		}
+	}
+	// if no file name provided, associate with empty symbol
+	if (file == NULL)
+		file = &s_;
+	
+	// prep threading stuff
+	x->unsafe = 0;
+	x->init = 0;
+	if (x->threaded == 1)
+	{
+		x->x_clock = clock_new(x, (t_method)coll_tick);
+		t_threadedFunctionParams rPars;
+		rPars.x = x;
+		pthread_mutex_init(&x->unsafe_mutex, NULL);
+		pthread_cond_init(&x->unsafe_cond, NULL);
+		ret = pthread_create( &x->unsafe_t, NULL, (void *) &coll_threaded_fileio, (void *) &rPars);
+
+		while (!x->init) {
+			sched_yield();
+		}
+	}
+
+    coll_bind(x, file);
+
     return (x);
 }
 
@@ -1562,7 +1964,7 @@
     coll_class = class_new(gensym("coll"),
 			   (t_newmethod)coll_new,
 			   (t_method)coll_free,
-			   sizeof(t_coll), 0, A_DEFSYM, 0);
+			   sizeof(t_coll), 0, A_GIMME, 0);
     class_addbang(coll_class, coll_next);
     class_addfloat(coll_class, coll_float);
     class_addsymbol(coll_class, coll_symbol);
@@ -1620,6 +2022,8 @@
 		    gensym("flags"), A_FLOAT, A_FLOAT, 0);
     class_addmethod(coll_class, (t_method)coll_read,
 		    gensym("read"), A_DEFSYM, 0);
+    class_addmethod(coll_class, (t_method)coll_start,
+		    gensym("start"), 0);
     class_addmethod(coll_class, (t_method)coll_write,
 		    gensym("write"), A_DEFSYM, 0);
     class_addmethod(coll_class, (t_method)coll_readagain,
@@ -1650,6 +2054,6 @@
        class itself has been already set up above), but it is better to
        have it around, just in case... */
     hammerfile_setup(collcommon_class, 0);
-//    logpost(NULL, 4, "this is cyclone/coll %s, %dth %s build",
-//	CYCLONE_VERSION, CYCLONE_BUILD, CYCLONE_RELEASE);
+    //logpost(NULL, 4, "this is cyclone/coll %s, %dth %s build",
+	//CYCLONE_VERSION, CYCLONE_BUILD, CYCLONE_RELEASE);
 }
diff -u /home/ico/Desktop/cyclone/cyclone-0.1-alpha57/hammer/decide.c miXed/cyclone/hammer/decide.c
--- /home/ico/Desktop/cyclone/cyclone-0.1-alpha57/hammer/decide.c	2015-06-18 04:37:52.000000000 -0400
+++ miXed/cyclone/hammer/decide.c	2015-10-18 18:35:48.277301861 -0400
@@ -5,6 +5,7 @@
 #include "m_pd.h"
 #include "common/loud.h"
 #include "shared.h"
+#include <stdlib.h>
 
 typedef struct _decide
 {
-------------- next part --------------
diff -u /home/ico/Desktop/cyclone/cyclone-0.1-alpha57/sickle/curve.c miXed/cyclone/sickle/curve.c
--- /home/ico/Desktop/cyclone/cyclone-0.1-alpha57/sickle/curve.c	2005-11-21 17:16:37.000000000 -0500
+++ miXed/cyclone/sickle/curve.c	2015-10-18 18:31:47.684291484 -0400
@@ -296,7 +296,7 @@
 	    segp->s_delta = av[1].a_w.w_float;
 	else
 	    segp->s_delta = 0;
-	curve_cc(x, segp, 0.);
+	curve_cc(x, segp, x->x_ccinput);
     }
     x->x_deltaset = 0;
     x->x_target = x->x_segs->s_target;


More information about the Pd-list mailing list