aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cyclone/shadow/maxmode.c21
-rw-r--r--shared/common/bifi.c217
-rw-r--r--shared/common/bifi.h40
-rw-r--r--shared/common/clc.c84
-rw-r--r--shared/common/clc.h10
-rw-r--r--shared/common/fi.c54
-rw-r--r--shared/common/fi.h11
-rw-r--r--shared/common/lex.c272
-rw-r--r--shared/common/lex.h25
-rw-r--r--shared/common/qtree.c780
-rw-r--r--shared/common/qtree.h83
-rw-r--r--shared/common/sq.c371
-rw-r--r--shared/common/sq.h169
-rw-r--r--shared/unstable/standalone.c80
-rw-r--r--shared/unstable/standalone.h57
-rw-r--r--test/cyclone/maxmode-test.pd20
-rw-r--r--test/toxy/lbpict-test.pd3
-rw-r--r--test/toxy/lbpict.wid7
-rw-r--r--test/toxy/testmess-test.pd35
-rw-r--r--test/toxy/testmess.wid34
-rw-r--r--test/toxy/tot-color.pd27
21 files changed, 1603 insertions, 797 deletions
diff --git a/cyclone/shadow/maxmode.c b/cyclone/shadow/maxmode.c
new file mode 100644
index 0000000..f90d990
--- /dev/null
+++ b/cyclone/shadow/maxmode.c
@@ -0,0 +1,21 @@
+/* Copyright (c) 2004 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+#include "unstable/loader.h"
+
+void maxmode_setup(void)
+{
+ shared_setmaxcompatibility();
+ if (zgetfn(&pd_objectmaker, gensym("cyclone")))
+ loud_warning(0, "maxmode", "cyclone is already loaded");
+ else
+ {
+ if (unstable_load_lib("", "cyclone") == LOADER_NOFILE)
+ loud_error(0, "cyclone library is missing");
+ else if (!zgetfn(&pd_objectmaker, gensym("cyclone")))
+ loud_error(0, "miXed/Pd version mismatch");
+ }
+}
diff --git a/shared/common/bifi.c b/shared/common/bifi.c
deleted file mode 100644
index 22f3df3..0000000
--- a/shared/common/bifi.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/* Copyright (c) 2002-2003 krzYszcz and others.
- * For information on usage and redistribution, and for a DISCLAIMER OF ALL
- * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
-
-/* generic helpers for binary file reading and writing */
-
-#ifdef NT
-#include <io.h>
-#else
-#include <unistd.h>
-#endif
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include "m_pd.h"
-#include "shared.h"
-#include "common/bifi.h"
-
-#if 1
-#define BIFI_VERBOSE
-#if 0
-#define BIFI_DEBUG
-#endif
-#endif
-
-static int bifi_swapping = 1; /* set in bifi_clear() */
-
-/* one helper from g_array.c (the original is global, but since
- garray_ambigendian() lacks EXTERN specifier, .dll externs cannot see it;
- btw. it has a comment: ``this should be renamed and moved...'')
-*/
-static int ambigendian(void)
-{
- unsigned short s = 1;
- unsigned char c = *(char *)(&s);
- return (c==0);
-}
-
-/* two helpers from d_soundfile.c */
-uint32 bifi_swap4(uint32 n)
-{
- if (bifi_swapping)
- return (((n & 0xff) << 24) | ((n & 0xff00) << 8) |
- ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24));
- else return (n);
-}
-
-uint16 bifi_swap2(uint16 n)
-{
- if (bifi_swapping)
- return (((n & 0xff) << 8) | ((n & 0xff00) >> 8));
- else return (n);
-}
-
-static void bifi_error_clear(t_bifi *x)
-{
- x->b_err = BIFI_ERR_OK;
- x->b_syserrno = 0;
- errno = 0;
-}
-
-static void bifi_error_set(t_bifi *x, int errcode)
-{
- x->b_err = errcode;
- x->b_syserrno = errno;
- if (errcode != BIFI_ERR_OK && x->b_fp)
- {
- fclose(x->b_fp);
- x->b_fp = 0;
- }
-#if 0 /* LATER use Pd's own error logging mechanism, maybe by calling this: */
- sys_unixerror((char *)x); /* sys_logerror((char *)x, "...")? */
-#endif
-}
-
-void bifi_clear(t_bifi *x)
-{
- bifi_swapping = !ambigendian();
- x->b_fp = 0;
- x->b_filename[0] = '\0';
- bifi_error_clear(x);
-}
-
-t_bifi *bifi_new(t_bifi *x, char *hdr, size_t hdrsz)
-{
- t_bifi *result = x;
- if (result) result->b_selfalloc = 0;
- else {
- if (!(result = getbytes(sizeof(*result)))) return (0);
- result->b_selfalloc = 1;
- }
- if (hdr || !hdrsz) result->b_hdralloc = 0;
- else {
- if (!(hdr = getbytes(hdrsz)))
- {
- if (result->b_selfalloc) freebytes(result, sizeof(*result));
- return (0);
- }
- result->b_hdralloc = 1;
- }
- result->b_header = hdr;
- result->b_headersize = hdrsz;
- bifi_clear(result);
- return (result);
-}
-
-void bifi_free(t_bifi *x)
-{
- if (x->b_fp) fclose(x->b_fp);
- if (x->b_hdralloc) freebytes(x->b_header, x->b_headersize);
- if (x->b_selfalloc) freebytes(x, sizeof(*x));
-}
-
-void bifi_error_report(t_bifi *x)
-{
- char *errmess = 0;
- switch (x->b_err)
- {
- case BIFI_ERR_OK:
- break;
- case BIFI_ERR_OPEN:
- errmess = "cannot open";
- break;
- case BIFI_ERR_READ:
- errmess = "error reading";
- break;
- case BIFI_ERR_WRITE:
- errmess = "error writing";
- break;
- case BIFI_ERR_BADHEADER:
- errmess = "missing header of";
- break;
- default:
- post("binary file i/o unknown error");
- }
- if (errmess)
- post("%s binary file `%s\' (errno %d: %s)", errmess,
- x->b_filename, x->b_syserrno, strerror(x->b_syserrno));
- bifi_error_clear(x);
-}
-
-/* Open file and read in its header (x must be a valid t_bifi pointer,
- no checks are being made...)
-*/
-int bifi_read_start(t_bifi *x, const char *filename, const char *dirname)
-{
- int fd;
- char dirbuf[MAXPDSTRING], *nameptr;
-
- bifi_clear(x);
- strcpy(x->b_filename, filename);
- if ((fd = open_via_path(dirname, filename,
- "", dirbuf, &nameptr, MAXPDSTRING, 1)) < 0)
- {
- bifi_error_set(x, BIFI_ERR_OPEN);
- return (0);
- }
-
- /* Closing/reopening dance. This is unnecessary under linux, and we
- could have tried to convert fd to fp (since we prefer using streams),
- but under windows open_via_path() returns what seems to be an invalid
- fd. LATER try to understand what is going on here... */
- close(fd);
- if (dirbuf != nameptr)
- {
- char *slashpos = dirbuf + strlen(dirbuf);
- *slashpos++ = '/';
- /* try not to be dependent on current open_via_path() implementation */
- if (nameptr != slashpos)
- strcpy(slashpos, nameptr);
- }
- sys_unbashfilename(dirbuf, dirbuf);
- if (!(x->b_fp = fopen(dirbuf, "rb")))
- {
- bifi_error_set(x, BIFI_ERR_OPEN);
- return (0);
- }
-
- if (x->b_headersize &&
- fread(x->b_header, 1, x->b_headersize, x->b_fp) < x->b_headersize)
- {
- bifi_error_set(x, BIFI_ERR_BADHEADER);
- return (0);
- }
- return (1);
-}
-
-/* Open file and write the supplied header (x must be a valid t_bifi pointer
- with header data properly filled, no checks are being made...)
-*/
-int bifi_write_start(t_bifi *x, const char *filename, const char *dirname)
-{
- char fnamebuf[MAXPDSTRING];
-
- bifi_clear(x);
- strcpy(x->b_filename, filename);
-
- fnamebuf[0] = 0;
- if (*dirname)
- strcat(fnamebuf, dirname), strcat(fnamebuf, "/");
- strcat(fnamebuf, filename);
- sys_bashfilename(fnamebuf, fnamebuf);
- if (!(x->b_fp = fopen(fnamebuf, "wb")))
- {
- bifi_error_set(x, BIFI_ERR_OPEN);
- return (0);
- }
-
- if (x->b_headersize &&
- fwrite(x->b_header, 1, x->b_headersize, x->b_fp) < x->b_headersize)
- {
- bifi_error_set(x, BIFI_ERR_WRITE);
- return (0);
- }
- return (1);
-}
diff --git a/shared/common/bifi.h b/shared/common/bifi.h
deleted file mode 100644
index 29fe5ae..0000000
--- a/shared/common/bifi.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Copyright (c) 2002-2003 krzYszcz and others.
- * For information on usage and redistribution, and for a DISCLAIMER OF ALL
- * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
-
-/* generic helpers for binary file reading and writing */
-
-#ifndef __BIFI_H__
-#define __BIFI_H__
-
-#define BIFI_ERR_OK 0
-#define BIFI_ERR_OPEN -1
-#define BIFI_ERR_READ -2 /* generic read failure */
-#define BIFI_ERR_WRITE -3 /* generic write failure */
-#define BIFI_ERR_BADHEADER -4 /* header missing or short */
-
-typedef struct _bifi
-{
- int b_selfalloc:1;
- int b_hdralloc:1;
- char *b_header;
- size_t b_headersize;
- FILE *b_fp;
- char b_filename[MAXPDSTRING];
- int b_err; /* BIFI_ERR code */
- int b_syserrno; /* system error code */
-} t_bifi;
-
-uint32 bifi_swap4(uint32 n);
-uint16 bifi_swap2(uint16 n);
-
-t_bifi *bifi_new(t_bifi *x, char *hdr, size_t hdrsz);
-void bifi_free(t_bifi *x);
-void bifi_clear(t_bifi *x);
-
-int bifi_read_start(t_bifi *x, const char *filename, const char *dirname);
-int bifi_write_start(t_bifi *x, const char *filename, const char *dirname);
-
-void bifi_error_report(t_bifi *x);
-
-#endif
diff --git a/shared/common/clc.c b/shared/common/clc.c
new file mode 100644
index 0000000..b4d1208
--- /dev/null
+++ b/shared/common/clc.c
@@ -0,0 +1,84 @@
+/* Copyright (c) 2004 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+
+/* Problem: find a function f : p -> q (where p is user's curve control
+ parameter, q is log factor) such that the curves will bend in
+ a semi-linear way over the p's range of 0..1. The curve function is
+ then g(x, p) = (exp(f(p) * x) - 1) / (exp(f(p)) - 1), where x is
+ curve's domain. If, for example, the points g(0.5, p) are to make
+ a semi-linear pattern, then the solution is a function f that minimizes
+ the integral of the error function e(p) = sqr(((1-p)/2)-g(.5, p))
+ over 0..1. Until someone does this analytically, we are left with
+ a lame formula, which has been tweaked and tested in gnuplot:
+ f(p) = h(p) / (1 - h(p)), where h(p) = (((p + 1e-20) * 1.2) ** .41) * .91.
+ The file curve.gp, in the sickle's source directory, may come handy,
+ in case there is anyone, who fancy tweaking it even further.
+
+ To implement this, start from these equations:
+ nhops = npoints - 1
+ bb * mm ^ nhops = bb + 1
+ (bb ^ 2) * (mm ^ nhops) = ((exp(ff/2) - 1) / (exp(ff) - 1)) ^ 2
+
+ and calculate:
+ hh = pow(((p + c1) * c2), c3) * c4
+ ff = hh / (1 - hh)
+ eff = exp(ff) - 1
+ gh = (exp(ff * .5) - 1) / eff
+ bb = gh * (gh / (1 - (gh + gh)))
+ mm = ((exp(ff * (1/nhops)) - 1) / (eff * bb)) + 1
+
+ The loop is:
+ for (vv = bb, i = 0; i <= nhops; vv *= mm, i++)
+ result = (vv - bb) * (y1 - y0) + y0
+ where y0, y1 are start and destination values
+
+ This formula generates curves with < .000004% deviation from the straight
+ line for p = 0 at half-domain, range 1. There are no nans for -1 <= p <= 1.
+*/
+
+#define CLCCURVE_C1 1e-20
+#define CLCCURVE_C2 1.2
+#define CLCCURVE_C3 0.41
+#define CLCCURVE_C4 0.91
+
+void clccurve_coefs(int nhops, double crv, double *bbp, double *mmp)
+{
+ if (nhops > 0)
+ {
+ double hh, ff, eff, gh;
+ if (crv < 0)
+ {
+ if (crv < -1.)
+ crv = -1.;
+ hh = pow(((CLCCURVE_C1 - crv) * CLCCURVE_C2), CLCCURVE_C3)
+ * CLCCURVE_C4;
+ ff = hh / (1. - hh);
+ eff = exp(ff) - 1.;
+ gh = (exp(ff * .5) - 1.) / eff;
+ *bbp = gh * (gh / (1. - (gh + gh)));
+ *mmp = 1. / (((exp(ff * (1. / (double)nhops)) - 1.) /
+ (eff * *bbp)) + 1.);
+ *bbp += 1.;
+ }
+ else
+ {
+ if (crv > 1.)
+ crv = 1.;
+ hh = pow(((crv + CLCCURVE_C1) * CLCCURVE_C2), CLCCURVE_C3)
+ * CLCCURVE_C4;
+ ff = hh / (1. - hh);
+ eff = exp(ff) - 1.;
+ gh = (exp(ff * .5) - 1.) / eff;
+ *bbp = gh * (gh / (1. - (gh + gh)));
+ *mmp = ((exp(ff * (1. / (double)nhops)) - 1.) /
+ (eff * *bbp)) + 1.;
+ }
+ }
+ else if (crv < 0)
+ *bbp = 2., *mmp = 1.;
+ else
+ *bbp = *mmp = 1.;
+}
diff --git a/shared/common/clc.h b/shared/common/clc.h
new file mode 100644
index 0000000..7618704
--- /dev/null
+++ b/shared/common/clc.h
@@ -0,0 +1,10 @@
+/* Copyright (c) 2004 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __CLC_H__
+#define __CLC_H__
+
+void clccurve_coefs(int nhops, double crv, double *bbp, double *mmp);
+
+#endif
diff --git a/shared/common/fi.c b/shared/common/fi.c
new file mode 100644
index 0000000..e46d001
--- /dev/null
+++ b/shared/common/fi.c
@@ -0,0 +1,54 @@
+/* Copyright (c) 2004 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifdef NT
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include "m_pd.h"
+#include "fi.h"
+
+FILE *firead_open(char *filename, t_canvas *cv, int textmode)
+{
+ int fd;
+ char path[MAXPDSTRING+2], *nameptr;
+ t_symbol *dirsym = (cv ? canvas_getdir(cv) : 0);
+ /* path arg is returned unbashed (system-independent) */
+ if ((fd = open_via_path((dirsym ? dirsym->s_name : ""), filename,
+ "", path, &nameptr, MAXPDSTRING, 1)) < 0)
+ return (0);
+ /* Closing/reopening dance. This is unnecessary under linux, and we
+ could have tried to convert fd to fp, but under windows open_via_path()
+ returns what seems to be an invalid fd.
+ LATER try to understand what is going on here... */
+ close(fd);
+ if (path != nameptr)
+ {
+ char *slashpos = path + strlen(path);
+ *slashpos++ = '/';
+ /* try not to be dependent on current open_via_path() implementation */
+ if (nameptr != slashpos)
+ strcpy(slashpos, nameptr);
+ }
+ sys_bashfilename(path, path);
+ return (fopen(path, (textmode ? "r" : "rb")));
+}
+
+FILE *fiwrite_open(char *filename, t_canvas *cv, int textmode)
+{
+ char path[MAXPDSTRING+2];
+ if (cv)
+ /* path arg is returned unbashed (system-independent) */
+ canvas_makefilename(cv, filename, path, MAXPDSTRING);
+ else
+ {
+ strncpy(path, filename, MAXPDSTRING);
+ path[MAXPDSTRING-1] = 0;
+ }
+ sys_bashfilename(path, path);
+ return (fopen(path, (textmode ? "w" : "wb")));
+}
diff --git a/shared/common/fi.h b/shared/common/fi.h
new file mode 100644
index 0000000..c6e8401
--- /dev/null
+++ b/shared/common/fi.h
@@ -0,0 +1,11 @@
+/* Copyright (c) 2004 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __FI_H__
+#define __FI_H__
+
+FILE *firead_open(char *filename, t_canvas *cv, int textmode);
+FILE *fiwrite_open(char *filename, t_canvas *cv, int textmode);
+
+#endif
diff --git a/shared/common/lex.c b/shared/common/lex.c
new file mode 100644
index 0000000..e9fd574
--- /dev/null
+++ b/shared/common/lex.c
@@ -0,0 +1,272 @@
+/* Copyright (c) 1997-2004 Miller Puckette, krzYszcz, and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef MIXED_STANDALONE
+#include "unstable/standalone.h"
+#else
+#include "m_pd.h"
+#endif
+#include "common/lex.h"
+
+static int lex_nextbyte(t_lex *lx, unsigned char *buf)
+{
+ int ich;
+ if (lx->l_fp)
+ {
+ if ((ich = fgetc(lx->l_fp)) == EOF)
+ return (0);
+ }
+ else if (lx->l_buf)
+ {
+ if (lx->l_bufndx < lx->l_bufsize)
+ ich = lx->l_buf[lx->l_bufndx++];
+ else
+ return (0);
+ }
+ else return (0);
+ if (ich)
+ {
+ *buf = (unsigned char)ich;
+ return (1);
+ }
+ else
+ {
+ lx->l_errbinary = 1;
+ return (0);
+ }
+}
+
+static void lex_ungetbyte(t_lex *lx, unsigned char ch)
+{
+ if (lx->l_fp)
+ {
+ ungetc(ch, lx->l_fp);
+ }
+ else if (lx->l_buf)
+ {
+ if (lx->l_bufndx > 0)
+ lx->l_buf[--lx->l_bufndx] = ch;
+ }
+}
+
+/* single pass of binbuf_text(), optionally int-preserving version */
+int lex_nextatom(t_lex *lx, t_atom *ap)
+{
+ char buf[1001], *bufp, *ebuf = buf + 1000;
+ int ready;
+ unsigned char ch;
+ ap->a_type = A_NULL;
+ while ((ready = lex_nextbyte(lx, &ch)) &&
+ (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'));
+ if (!ready)
+ {
+ /* ??? */
+ if (lx->l_lasttype == A_SEMI)
+ return (0);
+ else
+ ap->a_type = A_SEMI;
+ }
+ else if (ch == ';')
+ ap->a_type = A_SEMI;
+ else if (ch == ',')
+ ap->a_type = A_COMMA;
+ else
+ {
+ int floatstate = 0, slash = 0, lastslash = 0, firstslash = (ch == '\\');
+ bufp = buf;
+ do
+ {
+ *bufp = ch;
+ lastslash = slash;
+ slash = (ch == '\\');
+
+ if (floatstate >= 0)
+ {
+ int digit = (ch >= '0' && ch <= '9'),
+ dot = (ch == '.'), minus = (ch == '-'),
+ plusminus = (minus || (ch == '+')),
+ expon = (ch == 'e' || ch == 'E');
+ if (floatstate == 0) /* beginning */
+ {
+ if (minus) floatstate = 1;
+ else if (digit) floatstate = 2;
+ else if (dot) floatstate = 3;
+ else floatstate = -1;
+ }
+ else if (floatstate == 1) /* got minus */
+ {
+ if (digit) floatstate = 2;
+ else if (dot) floatstate = 3;
+ else floatstate = -1;
+ }
+ else if (floatstate == 2) /* got digits */
+ {
+ if (dot) floatstate = 4;
+ else if (expon) floatstate = 6;
+ else if (!digit) floatstate = -1;
+ }
+ else if (floatstate == 3) /* got '.' without digits */
+ {
+ if (digit) floatstate = 5;
+ else floatstate = -1;
+ }
+ else if (floatstate == 4) /* got '.' after digits */
+ {
+ if (digit) floatstate = 5;
+ else if (expon) floatstate = 6;
+ else floatstate = -1;
+ }
+ else if (floatstate == 5) /* got digits after . */
+ {
+ if (expon) floatstate = 6;
+ else if (!digit) floatstate = -1;
+ }
+ else if (floatstate == 6) /* got 'e' */
+ {
+ if (plusminus) floatstate = 7;
+ else if (digit) floatstate = 8;
+ else floatstate = -1;
+ }
+ else if (floatstate == 7) /* got plus or minus */
+ {
+ if (digit) floatstate = 8;
+ else floatstate = -1;
+ }
+ else if (floatstate == 8) /* got digits */
+ {
+ if (!digit) floatstate = -1;
+ }
+ }
+ if (!slash) bufp++;
+ }
+ while ((ready = lex_nextbyte(lx, &ch)) && bufp != ebuf
+ && (slash || (ch != ' ' && ch != '\n' && ch != '\r'
+ && ch != '\t' && ch != ',' && ch != ';')));
+ if (ready && (ch == ',' || ch == ';'))
+ lex_ungetbyte(lx, ch);
+ *bufp = 0;
+#if 0
+ fprintf(stderr, "buf %s\n", buf);
+#endif
+ if (*buf == '$' && buf[1] >= '0' && buf[1] <= '9' && !firstslash)
+ {
+ for (bufp = buf+2; *bufp; bufp++)
+ {
+ if (*bufp < '0' || *bufp > '9')
+ {
+ ap->a_type = A_DOLLSYM;
+ ap->a_w.w_symbol = gensym(buf+1);
+ break;
+ }
+ }
+ if (ap->a_type == A_NULL)
+ {
+ ap->a_type = A_DOLLAR;
+ ap->a_w.w_index = atoi(buf+1);
+ }
+ }
+ else if (floatstate == 2)
+ {
+ if (lx->l_inttype == A_FLOAT)
+ {
+ ap->a_type = A_FLOAT;
+ ap->a_w.w_float = (float)atof(buf);
+ }
+ else
+ {
+ ap->a_type = lx->l_inttype;
+ ap->a_w.w_index = atoi(buf);
+ }
+ }
+ else if (floatstate == 4 || floatstate == 5 || floatstate == 8)
+ {
+ ap->a_type = A_FLOAT;
+ ap->a_w.w_float = (float)atof(buf);
+ }
+ else
+ {
+ ap->a_type = A_SYMBOL;
+ ap->a_w.w_symbol = gensym(buf);
+ }
+ }
+ lx->l_lasttype = ap->a_type;
+ return (1);
+}
+
+void lex_atomstring(t_atom *ap, char *buf, int bufsize, t_atomtype inttype)
+{
+ char *sp, *bp, *ep;
+ switch(ap->a_type)
+ {
+ case A_SEMI:
+ strcpy(buf, ";"); break;
+ case A_COMMA:
+ strcpy(buf, ","); break;
+ case A_FLOAT:
+ sprintf(buf, "%#f", ap->a_w.w_float);
+ ep = buf + strlen(buf) - 1;
+ while (ep > buf && *ep == '0') *ep-- = 0;
+ break;
+ case A_SYMBOL:
+ sp = ap->a_w.w_symbol->s_name;
+ bp = buf;
+ ep = buf + (bufsize-5);
+ while (bp < ep && *sp)
+ {
+ if (*sp == ';' || *sp == ',' || *sp == '\\' ||
+ (*sp == '$' && bp == buf && sp[1] >= '0' && sp[1] <= '9'))
+ *bp++ = '\\';
+ if ((unsigned char)*sp < 127)
+ *bp++ = *sp++;
+ else
+ /* FIXME this is temporary -- codepage horror */
+ sprintf(bp, "\\%.3o", (unsigned char)*sp++), bp += 4;
+ }
+ if (*sp) *bp++ = '*';
+ *bp = 0;
+ break;
+ case A_DOLLAR:
+ sprintf(buf, "$%d", ap->a_w.w_index);
+ break;
+ case A_DOLLSYM:
+ sprintf(buf, "$%s", ap->a_w.w_symbol->s_name);
+ break;
+ default:
+ if (ap->a_type == inttype)
+ sprintf(buf, "%d", ap->a_w.w_index);
+ else
+ {
+#ifdef MIXED_STANDALONE
+ fprintf(stderr, "BUG (lex): bad atom type\n");
+#else
+ bug("lex_atomstring (bad atom type)");
+#endif
+ strcpy(buf, "???");
+ }
+ }
+}
+
+int lex_isbinary(t_lex *lx)
+{
+ return (lx->l_errbinary);
+}
+
+void lex_free(t_lex *lx)
+{
+ freebytes(lx, sizeof(*lx));
+}
+
+t_lex *lex_new(FILE *fp, t_atomtype inttype)
+{
+ t_lex *lx = (t_lex *)getbytes(sizeof(*lx));
+ lx->l_fp = fp;
+ lx->l_buf = 0; /* FIXME */
+ lx->l_inttype = inttype;
+ lx->l_lasttype = A_SEMI;
+ lx->l_errbinary = 0;
+ return (lx);
+}
diff --git a/shared/common/lex.h b/shared/common/lex.h
new file mode 100644
index 0000000..041aa23
--- /dev/null
+++ b/shared/common/lex.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2003-2004 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __LEX_H__
+#define __LEX_H__
+
+typedef struct _lex
+{
+ FILE *l_fp;
+ unsigned char *l_buf;
+ int l_bufsize;
+ int l_bufndx;
+ t_atomtype l_inttype;
+ t_atomtype l_lasttype;
+ int l_errbinary;
+} t_lex;
+
+int lex_nextatom(t_lex *lx, t_atom *ap);
+void lex_atomstring(t_atom *ap, char *buf, int bufsize, t_atomtype inttype);
+int lex_isbinary(t_lex *lx);
+void lex_free(t_lex *lx);
+t_lex *lex_new(FILE *fp, t_atomtype inttype);
+
+#endif
diff --git a/shared/common/qtree.c b/shared/common/qtree.c
new file mode 100644
index 0000000..368e38c
--- /dev/null
+++ b/shared/common/qtree.c
@@ -0,0 +1,780 @@
+/* Copyright (c) 2004 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "qtree.h"
+
+/* Since there is no sentinel node, the deletion routine has to have
+ a few extra checks. LATER rethink. */
+
+/* LATER freelist */
+
+typedef t_qnode *(*t_qtree_inserthook)(t_qnode *);
+
+#ifdef QTREE_DEBUG
+/* returns black-height or 0 if failed */
+static int qnode_verify(t_qnode *np)
+{
+ if (np)
+ {
+ int bhl, bhr;
+ if (((bhl = qnode_verify(np->n_left)) == 0) ||
+ ((bhr = qnode_verify(np->n_right)) == 0))
+ return (0);
+ if (bhl != bhr)
+ {
+ /* failure: two paths rooted in the same node
+ contain different number of black nodes */
+ bug("qnode_verify: not balanced");
+ return (0);
+ }
+ if (np->n_black)
+ return (bhl + 1);
+ else
+ {
+ if ((np->n_left && !np->n_left->n_black) ||
+ (np->n_right && !np->n_right->n_black))
+ {
+ bug("qnode_verify: adjacent red nodes");
+ return (0);
+ }
+ return (bhl);
+ }
+ }
+ else return (1);
+}
+
+/* returns black-height or 0 if failed */
+static int qtree_verify(t_qtree *tree)
+{
+ return (qnode_verify(tree->t_root));
+}
+
+static int qnode_checkmulti(t_qnode *np1, t_qnode *np2)
+{
+ if (np1 && np2 && np1->n_key == np2->n_key)
+ {
+ if (np1 == np2)
+ bug("qnode_checkmulti");
+ else
+ return (1);
+ }
+ return (0);
+}
+
+static void qnode_post(t_qtree *tree, t_qnode *np,
+ t_qnode_vshowhook hook, char *message)
+{
+ startpost("%g ", np->n_key);
+ if (tree->t_valuetype == QTREETYPE_FLOAT)
+ startpost("%g ", QNODE_GETFLOAT(np));
+ else if (tree->t_valuetype == QTREETYPE_SYMBOL)
+ startpost("%s ", QNODE_GETSYMBOL(np)->s_name);
+ else if (tree->t_valuetype == QTREETYPE_ATOM)
+ {
+ t_atom *ap = QNODE_GETATOMPTR(np);
+ if (ap->a_type == A_FLOAT)
+ startpost("%g ", ap->a_w.w_float);
+ else if (ap->a_type == A_SYMBOL)
+ startpost("%s ", ap->a_w.w_symbol->s_name);
+ }
+ else if (hook)
+ {
+ char buf[MAXPDSTRING];
+ (*hook)(np, buf, MAXPDSTRING);
+ startpost("%s ", buf);
+ }
+ else startpost("0x%08x ", (int)QNODE_GETSYMBOL(np));
+ startpost("%s ", (np->n_black ? "black" : "red"));
+
+ if (qnode_checkmulti(np, np->n_parent) ||
+ qnode_checkmulti(np, np->n_left) ||
+ qnode_checkmulti(np, np->n_right) ||
+ qnode_checkmulti(np->n_parent, np->n_left) ||
+ qnode_checkmulti(np->n_parent, np->n_right) ||
+ qnode_checkmulti(np->n_left, np->n_right))
+ startpost("multi ");
+
+ if (np->n_parent)
+ startpost("(%g -> ", np->n_parent->n_key);
+ else
+ startpost("(nul -> ");
+ if (np->n_left)
+ startpost("%g, ", np->n_left->n_key);
+ else
+ startpost("nul, ");
+ if (np->n_right)
+ startpost("%g)", np->n_right->n_key);
+ else
+ startpost("nul)");
+ if (message)
+ post(": %s", message);
+ else
+ endpost();
+}
+
+/* Assert a standard stackless traversal producing the same sequence,
+ as the auxiliary list. */
+static int qtree_checktraversal(t_qtree *tree)
+{
+ t_qnode *treewalk = tree->t_root;
+ t_qnode *listwalk = tree->t_first;
+ int count = 0;
+ while (treewalk)
+ {
+ t_qnode *prev = treewalk->n_left;
+ if (prev)
+ {
+ while (prev->n_right && prev->n_right != treewalk)
+ prev = prev->n_right;
+ if (prev->n_right)
+ {
+ prev->n_right = 0;
+ count++;
+ if (treewalk == listwalk)
+ listwalk = listwalk->n_next;
+ else
+ {
+ bug("qtree_checktraversal 1");
+ qnode_post(tree, treewalk, 0, "treewalk");
+ if (listwalk)
+ qnode_post(tree, listwalk, 0, "listwalk");
+ else
+ post("empty listwalk pointer");
+ listwalk = treewalk;
+ }
+ treewalk = treewalk->n_right;
+ }
+ else
+ {
+ prev->n_right = treewalk;
+ treewalk = treewalk->n_left;
+ }
+ }
+ else
+ {
+ count++;
+ if (treewalk == listwalk)
+ listwalk = listwalk->n_next;
+ else
+ {
+ bug("qtree_checktraversal 2");
+ qnode_post(tree, treewalk, 0, "treewalk");
+ if (listwalk)
+ qnode_post(tree, listwalk, 0, "listwalk");
+ else
+ post("empty listwalk pointer");
+ listwalk = treewalk;
+ }
+ treewalk = treewalk->n_right;
+ }
+ }
+ return (count);
+}
+
+static int qnode_height(t_qnode *np)
+{
+ if (np)
+ {
+ int lh = qnode_height(np->n_left);
+ int rh = qnode_height(np->n_right);
+ return (lh > rh ? lh + 1 : rh + 1);
+ }
+ else return (0);
+}
+
+void qtree_debug(t_qtree *tree, int level, t_qnode_vshowhook hook)
+{
+ t_qnode *np;
+ int count;
+ post("------------------------");
+ count = qtree_checktraversal(tree);
+ if (level)
+ {
+ for (np = tree->t_first; np; np = np->n_next)
+ qnode_post(tree, np, hook, 0);
+ if (level > 1)
+ {
+ post("************");
+ for (np = tree->t_last; np; np = np->n_prev)
+ startpost("%g ", np->n_key);
+ endpost();
+ }
+ }
+ if (tree->t_root)
+ {
+ t_qnode *first = tree->t_root, *last = tree->t_root;
+ while (first->n_left && first->n_left != tree->t_root)
+ first = first->n_left;
+ while (last->n_right && last->n_right != tree->t_root)
+ last = last->n_right;
+ post("count %d, height %d, root %g",
+ count, qnode_height(tree->t_root), tree->t_root->n_key);
+ post("first %g, root->left* %g, last %g, root->right* %g",
+ (tree->t_first ? tree->t_first->n_key : 0), first->n_key,
+ (tree->t_last ? tree->t_last->n_key : 0), last->n_key);
+ }
+ else post("empty");
+ post("...verified (black-height is %d)", qtree_verify(tree));
+ post("------------------------");
+}
+#endif
+
+/* assuming that target node (np->n_right) exists */
+static void qtree_lrotate(t_qtree *tree, t_qnode *np)
+{
+ t_qnode *target = np->n_right;
+ if (np->n_right = target->n_left)
+ np->n_right->n_parent = np;
+ if (!(target->n_parent = np->n_parent))
+ tree->t_root = target;
+ else if (np == np->n_parent->n_left)
+ np->n_parent->n_left = target;
+ else
+ np->n_parent->n_right = target;
+ target->n_left = np;
+ np->n_parent = target;
+}
+
+/* assuming that target node (np->n_left) exists */
+static void qtree_rrotate(t_qtree *tree, t_qnode *np)
+{
+ t_qnode *target = np->n_left;
+ if (np->n_left = target->n_right)
+ np->n_left->n_parent = np;
+ if (!(target->n_parent = np->n_parent))
+ tree->t_root = target;
+ else if (np == np->n_parent->n_left)
+ np->n_parent->n_left = target;
+ else
+ np->n_parent->n_right = target;
+ target->n_right = np;
+ np->n_parent = target;
+}
+
+static t_qnode *qtree_preinserthook(t_qnode *np)
+{
+ while (np->n_prev && np->n_prev->n_key == np->n_key)
+ np = np->n_prev;
+ if (np->n_left)
+ {
+ np = np->n_prev;
+ if (np->n_right)
+ {
+ /* LATER revisit */
+ bug("qtree_preinserthook");
+ return (0); /* do nothing */
+ }
+ }
+ return (np);
+}
+
+static t_qnode *qtree_postinserthook(t_qnode *np)
+{
+ while (np->n_next && np->n_next->n_key == np->n_key)
+ np = np->n_next;
+ if (np->n_right)
+ {
+ np = np->n_next;
+ if (np->n_left)
+ {
+ /* LATER revisit */
+ bug("qtree_postinserthook");
+ return (0); /* do nothing */
+ }
+ }
+ return (np);
+}
+
+/* Returns a newly inserted or already existing node (or 0 if allocation
+ failed). A caller is responsible for assigning a value. If hook is
+ supplied, it is called iff key is found. In case of key being found
+ (which means foundp returns 1), a new node is inserted, unless hook is
+ either empty, or returns null. Hook's nonempty return is the parent
+ for the new node. It is expected to have no more than one child. */
+static t_qnode *qtree_doinsert(t_qtree *tree, double key,
+ t_qtree_inserthook hook, int *foundp)
+{
+ t_qnode *np, *parent, *result;
+ int leftchild;
+ *foundp = 0;
+ if (!(np = tree->t_root))
+ {
+ if (!(np = getbytes(tree->t_nodesize)))
+ return (0);
+ np->n_key = key;
+ np->n_black = 1;
+ tree->t_root = tree->t_first = tree->t_last = np;
+ return (np);
+ }
+
+ do
+ {
+ if (np->n_key == key)
+ {
+ *foundp = 1;
+ if (hook && (parent = (*hook)(np)))
+ {
+ if (parent->n_left && parent->n_right)
+ {
+ bug("qtree_insert, callback return 1");
+ parent = parent->n_next;
+ }
+ if (leftchild = (key < parent->n_key))
+ {
+ if (parent->n_left)
+ {
+ bug("qtree_insert, callback return 2");
+ leftchild = 0;
+ }
+ }
+ else if (parent->n_right)
+ leftchild = 1;
+ goto addit;
+ }
+ else return (np); /* a caller may then keep or replace the value */
+ }
+ else parent = np;
+ }
+ while (np = (key < np->n_key ? np->n_left : np->n_right));
+ leftchild = (key < parent->n_key);
+addit:
+ /* parent has no more than one child, new node becomes
+ parent's immediate successor or predecessor */
+ if (!(np = getbytes(tree->t_nodesize)))
+ return (0);
+ np->n_key = key;
+ np->n_parent = parent;
+ if (leftchild)
+ {
+ parent->n_left = np;
+ /* update the auxiliary linked list structure */
+ np->n_next = parent;
+ if (np->n_prev = parent->n_prev)
+ np->n_prev->n_next = np;
+ else
+ tree->t_first = np;
+ parent->n_prev = np;
+ }
+ else
+ {
+ parent->n_right = np;
+ /* update the auxiliary linked list structure */
+ np->n_prev = parent;
+ if (np->n_next = parent->n_next)
+ np->n_next->n_prev = np;
+ else
+ tree->t_last = np;
+ parent->n_next = np;
+ }
+ result = np;
+
+ /* balance the tree -- LATER clean this if possible... */
+ np->n_black = 0;
+ while (np != tree->t_root && !np->n_parent->n_black)
+ {
+ t_qnode *uncle;
+ /* np->n_parent->n_parent exists (we always paint root node in black) */
+ if (np->n_parent == np->n_parent->n_parent->n_left)
+ {
+ uncle = np->n_parent->n_parent->n_right;
+ if (!uncle /* (sentinel not used) */
+ || uncle->n_black)
+ {
+ if (np == np->n_parent->n_right)
+ {
+ np = np->n_parent;
+ qtree_lrotate(tree, np);
+ }
+ np->n_parent->n_black = 1;
+ np->n_parent->n_parent->n_black = 0;
+ qtree_rrotate(tree, np->n_parent->n_parent);
+ }
+ else
+ {
+ np->n_parent->n_black = 1;
+ uncle->n_black = 1;
+ np = np->n_parent->n_parent;
+ np->n_black = 0;
+ }
+ }
+ else
+ {
+ uncle = np->n_parent->n_parent->n_left;
+ if (!uncle /* (sentinel not used) */
+ || uncle->n_black)
+ {
+ if (np == np->n_parent->n_left)
+ {
+ np = np->n_parent;
+ qtree_rrotate(tree, np);
+ }
+ np->n_parent->n_black = 1;
+ np->n_parent->n_parent->n_black = 0;
+ qtree_lrotate(tree, np->n_parent->n_parent);
+ }
+ else
+ {
+ np->n_parent->n_black = 1;
+ uncle->n_black = 1;
+ np = np->n_parent->n_parent;
+ np->n_black = 0;
+ }
+ }
+ }
+ tree->t_root->n_black = 1;
+ return (result);
+}
+
+/* assuming that requested node exists */
+void qtree_delete(t_qtree *tree, t_qnode *gone)
+{
+ t_qnode *parent; /* parent of gone, after relinking */
+ t_qnode *child; /* gone's only child (or null), after relinking */
+ /* gone has to be the parent of no more than one child */
+ if (gone->n_left && gone->n_right)
+ {
+ /* Successor is the new parent of gone's children, and a new child
+ of gone's parent (if any). Successor always exists in this context,
+ and it has no left child. The simplistic scheme is to replace
+ gone's fields with successor's fields, and delete the successor.
+ We cannot do so, however, because successor may be pointed at... */
+ t_qnode *successor = gone->n_next;
+ child = successor->n_right;
+ successor->n_left = gone->n_left;
+ successor->n_left->n_parent = successor;
+ if (successor == gone->n_right)
+ parent = successor;
+ else
+ {
+ /* successor's parent always exists in this context,
+ successor is the left child of its parent */
+ parent = successor->n_parent;
+ parent->n_left = child;
+ if (child) /* (sentinel not used) */
+ child->n_parent = parent;
+ successor->n_right = gone->n_right;
+ successor->n_right->n_parent = successor;
+ }
+ if (gone->n_parent)
+ {
+ int swp;
+ if (gone == gone->n_parent->n_left)
+ gone->n_parent->n_left = successor;
+ else
+ gone->n_parent->n_right = successor;
+ successor->n_parent = gone->n_parent;
+ swp = gone->n_black;
+ gone->n_black = successor->n_black;
+ successor->n_black = swp;
+ }
+ else
+ {
+ tree->t_root = successor;
+ successor->n_parent = 0;
+ gone->n_black = successor->n_black;
+ successor->n_black = 1; /* LATER rethink */
+ }
+
+ /* update the auxiliary linked list structure */
+ if (successor->n_prev = gone->n_prev)
+ gone->n_prev->n_next = successor;
+ else
+ tree->t_first = successor;
+ }
+ else
+ {
+ /* update the auxiliary linked list structure */
+ if (gone->n_prev)
+ gone->n_prev->n_next = gone->n_next;
+ else
+ tree->t_first = gone->n_next;
+ if (gone->n_next)
+ gone->n_next->n_prev = gone->n_prev;
+ else
+ tree->t_last = gone->n_prev;
+
+ /* connect gone's child with gone's parent */
+ if (gone->n_left)
+ child = gone->n_left;
+ else
+ child = gone->n_right;
+ if (parent = gone->n_parent)
+ {
+ if (child) /* (sentinel not used) */
+ child->n_parent = parent;
+ if (gone == parent->n_left)
+ parent->n_left = child;
+ else
+ parent->n_right = child;
+ }
+ else
+ {
+ if (tree->t_root = child)
+ {
+ child->n_parent = 0;
+ child->n_black = 1; /* LATER rethink */
+ }
+ goto done;
+ }
+ }
+
+ if (gone->n_black)
+ {
+ /* balance the tree -- LATER clean this if possible... */
+ /* on entry: tree is not empty, parent always exists, child
+ not necessarily... */
+ while (child != tree->t_root &&
+ (!child || /* (sentinel not used) */
+ child->n_black))
+ {
+ t_qnode *other; /* another child of the same parent */
+ if (child == parent->n_left)
+ {
+ other = parent->n_right;
+ if (other && /* (sentinel not used) */
+ !other->n_black)
+ {
+ other->n_black = 1;
+ parent->n_black = 0;
+ qtree_lrotate(tree, parent);
+ other = parent->n_right;
+ }
+ if (!other || /* (sentinel not used) */
+ (!other->n_left || other->n_left->n_black) &&
+ (!other->n_right || other->n_right->n_black))
+ {
+ if (other) /* (sentinel not used) */
+ other->n_black = 0;
+ child = parent;
+ parent = parent->n_parent;
+ }
+ else
+ {
+ if (!other || /* (sentinel not used) */
+ !other->n_right || other->n_right->n_black)
+ {
+ if (other) /* (sentinel not used) */
+ {
+ if (other->n_left) other->n_left->n_black = 1;
+ other->n_black = 0;
+ qtree_rrotate(tree, other);
+ other = parent->n_right;
+ }
+ }
+ if (other) /* (sentinel not used) */
+ {
+ if (other->n_right) other->n_right->n_black = 1;
+ other->n_black = parent->n_black;
+ }
+ parent->n_black = 1;
+ qtree_lrotate(tree, parent);
+ tree->t_root->n_black = 1; /* LATER rethink */
+ goto done;
+ }
+ }
+ else /* right child */
+ {
+ other = parent->n_left;
+ if (other && /* (sentinel not used) */
+ !other->n_black)
+ {
+ other->n_black = 1;
+ parent->n_black = 0;
+ qtree_rrotate(tree, parent);
+ other = parent->n_left;
+ }
+ if (!other || /* (sentinel not used) */
+ (!other->n_left || other->n_left->n_black) &&
+ (!other->n_right || other->n_right->n_black))
+ {
+ if (other) /* (sentinel not used) */
+ other->n_black = 0;
+ child = parent;
+ parent = parent->n_parent;
+ }
+ else
+ {
+ if (!other || /* (sentinel not used) */
+ !other->n_left || other->n_left->n_black)
+ {
+ if (other) /* (sentinel not used) */
+ {
+ if (other->n_right) other->n_right->n_black = 1;
+ other->n_black = 0;
+ qtree_lrotate(tree, other);
+ other = parent->n_left;
+ }
+ }
+ if (other) /* (sentinel not used) */
+ {
+ if (other->n_left) other->n_left->n_black = 1;
+ other->n_black = parent->n_black;
+ }
+ parent->n_black = 1;
+ qtree_rrotate(tree, parent);
+ tree->t_root->n_black = 1; /* LATER rethink */
+ goto done;
+ }
+ }
+ }
+ if (child) /* (sentinel not used) */
+ child->n_black = 1;
+ }
+done:
+ freebytes(gone, tree->t_nodesize);
+#ifdef QTREE_DEBUG
+ qtree_verify(tree);
+#endif
+}
+
+t_qnode *qtree_search(t_qtree *tree, double key)
+{
+ t_qnode *np = tree->t_root;
+ while (np && np->n_key != key)
+ np = (key < np->n_key ? np->n_left : np->n_right);
+ return (np);
+}
+
+t_qnode *qtree_closest(t_qtree *tree, double key, int geqflag)
+{
+ t_qnode *np, *parent;
+ if (!(np = tree->t_root))
+ return (0);
+ do
+ if (np->n_key == key)
+ return (np);
+ else
+ parent = np;
+ while (np = (key < np->n_key ? np->n_left : np->n_right));
+ if (geqflag)
+ return (key > parent->n_key ? parent->n_next : parent);
+ else
+ return (key < parent->n_key ? parent->n_prev : parent);
+}
+
+t_qnode *qtree_insert(t_qtree *tree, double key, int *foundp)
+{
+ return (qtree_doinsert(tree, key, 0, foundp));
+}
+
+t_qnode *qtree_multiinsert(t_qtree *tree, double key, int fifoflag)
+{
+ int found;
+ return (qtree_doinsert(tree, key, (fifoflag ?
+ qtree_postinserthook :
+ qtree_preinserthook), &found));
+}
+
+t_qnode *qtree_insertfloat(t_qtree *tree, double key, t_float f,
+ int replaceflag)
+{
+ int found;
+ t_qnode *np = qtree_doinsert(tree, key, 0, &found);
+ if (np && (!found || replaceflag))
+ {
+ if (tree->t_valuetype == QTREETYPE_FLOAT)
+ {
+ t_qnode_float *npf = (t_qnode_float *)np;
+ npf->nf_value = f;
+ }
+ else if (tree->t_valuetype == QTREETYPE_ATOM)
+ {
+ t_qnode_atom *npa = (t_qnode_atom *)np;
+ t_atom *ap = &npa->na_value;
+ SETFLOAT(ap, f);
+ }
+ else bug("qtree_insertfloat");
+ }
+ return (np);
+}
+
+t_qnode *qtree_insertsymbol(t_qtree *tree, double key, t_symbol *s,
+ int replaceflag)
+{
+ int found;
+ t_qnode *np = qtree_doinsert(tree, key, 0, &found);
+ if (np && (!found || replaceflag))
+ {
+ if (tree->t_valuetype == QTREETYPE_SYMBOL)
+ {
+ t_qnode_symbol *nps = (t_qnode_symbol *)np;
+ nps->ns_value = s;
+ }
+ else if (tree->t_valuetype == QTREETYPE_ATOM)
+ {
+ t_qnode_atom *npa = (t_qnode_atom *)np;
+ t_atom *ap = &npa->na_value;
+ SETSYMBOL(ap, s);
+ }
+ else bug("qtree_insertsymbol");
+ }
+ return (np);
+}
+
+t_qnode *qtree_insertatom(t_qtree *tree, double key, t_atom *ap,
+ int replaceflag)
+{
+ int found;
+ t_qnode *np = qtree_doinsert(tree, key, 0, &found);
+ if (np && (!found || replaceflag))
+ {
+ if (tree->t_valuetype == QTREETYPE_ATOM)
+ {
+ t_qnode_atom *npa = (t_qnode_atom *)np;
+ npa->na_value = *ap;
+ }
+ else bug("qtree_insertatom");
+ }
+ return (np);
+}
+
+/* LATER preallocate 'freecount' nodes */
+static void qtree_doinit(t_qtree *tree, t_qtreetype vtype,
+ size_t nodesize, int freecount)
+{
+ tree->t_root = tree->t_first = tree->t_last = 0;
+ tree->t_valuetype = vtype;
+ tree->t_nodesize = nodesize;
+}
+
+void qtree_inittyped(t_qtree *tree, t_qtreetype vtype, int freecount)
+{
+ size_t nsize;
+ switch (vtype)
+ {
+ case QTREETYPE_FLOAT:
+ nsize = sizeof(t_qnode_float);
+ break;
+ case QTREETYPE_SYMBOL:
+ nsize = sizeof(t_qnode_symbol);
+ break;
+ case QTREETYPE_ATOM:
+ nsize = sizeof(t_qnode_atom);
+ break;
+ default:
+ bug("qtree_inittyped");
+ vtype = QTREETYPE_ILLEGAL;
+ nsize = sizeof(t_qnode);
+ }
+ qtree_doinit(tree, vtype, nsize, freecount);
+}
+
+void qtree_initcustom(t_qtree *tree, size_t nodesize, int freecount)
+{
+ qtree_doinit(tree, QTREETYPE_CUSTOM, nodesize, freecount);
+}
+
+/* LATER keep and/or preallocate 'freecount' nodes (if negative, keep all) */
+void qtree_clear(t_qtree *tree, int freecount)
+{
+ t_qnode *np, *next = tree->t_first;
+ while (next)
+ {
+ np = next;
+ next = next->n_next;
+ freebytes(np, tree->t_nodesize);
+ }
+ qtree_doinit(tree, tree->t_valuetype, tree->t_nodesize, 0);
+}
diff --git a/shared/common/qtree.h b/shared/common/qtree.h
new file mode 100644
index 0000000..97c2906
--- /dev/null
+++ b/shared/common/qtree.h
@@ -0,0 +1,83 @@
+/* Copyright (c) 2004 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __QTREE_H__
+#define __QTREE_H__
+
+#ifdef KRZYSZCZ
+#define QTREE_DEBUG
+#endif
+
+typedef enum
+{
+ QTREETYPE_FLOAT, QTREETYPE_SYMBOL, QTREETYPE_ATOM,
+ QTREETYPE_CUSTOM, QTREETYPE_ILLEGAL
+} t_qtreetype;
+
+typedef struct _qnode
+{
+ double n_key;
+ int n_black;
+ struct _qnode *n_left;
+ struct _qnode *n_right;
+ struct _qnode *n_parent;
+ struct _qnode *n_prev;
+ struct _qnode *n_next;
+} t_qnode;
+
+typedef struct _qnode_float
+{
+ t_qnode nf_node;
+ t_float nf_value;
+} t_qnode_float;
+
+typedef struct _qnode_symbol
+{
+ t_qnode ns_node;
+ t_symbol *ns_value;
+} t_qnode_symbol;
+
+typedef struct _qnode_atom
+{
+ t_qnode na_node;
+ t_atom na_value;
+} t_qnode_atom;
+
+typedef struct _qtree
+{
+ t_qnode *t_root;
+ t_qnode *t_first;
+ t_qnode *t_last;
+ t_qtreetype t_valuetype;
+ size_t t_nodesize;
+} t_qtree;
+
+#define QNODE_GETFLOAT(np) (((t_qnode_float *)(np))->nf_value)
+#define QNODE_GETSYMBOL(np) (((t_qnode_symbol *)(np))->ns_value)
+#define QNODE_GETATOMPTR(np) (&((t_qnode_atom *)(np))->na_value)
+
+typedef void (*t_qnode_vshowhook)(t_qnode *, char *, unsigned);
+
+t_qnode *qtree_search(t_qtree *tree, double key);
+t_qnode *qtree_closest(t_qtree *tree, double key, int geqflag);
+
+t_qnode *qtree_insert(t_qtree *tree, double key, int *foundp);
+t_qnode *qtree_multiinsert(t_qtree *tree, double key, int fifoflag);
+t_qnode *qtree_insertfloat(t_qtree *tree, double key, t_float f,
+ int replaceflag);
+t_qnode *qtree_insertsymbol(t_qtree *tree, double key, t_symbol *s,
+ int replaceflag);
+t_qnode *qtree_insertatom(t_qtree *tree, double key, t_atom *ap,
+ int replaceflag);
+void qtree_delete(t_qtree *tree, t_qnode *np);
+
+void qtree_inittyped(t_qtree *tree, t_qtreetype vtype, int freecount);
+void qtree_initcustom(t_qtree *tree, size_t nodesize, int freecount);
+void qtree_clear(t_qtree *tree, int freecount);
+
+#ifdef QTREE_DEBUG
+void qtree_debug(t_qtree *tree, int level, t_qnode_vshowhook hook);
+#endif
+
+#endif
diff --git a/shared/common/sq.c b/shared/common/sq.c
deleted file mode 100644
index d7b1ea5..0000000
--- a/shared/common/sq.c
+++ /dev/null
@@ -1,371 +0,0 @@
-/* Copyright (c) 2001-2003 krzYszcz and others.
- * For information on usage and redistribution, and for a DISCLAIMER OF ALL
- * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
-
-/* squeak and squeal: sequencing utilities, a prototype version
- (the main, 'sq' part of the library) */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include "m_pd.h"
-#include "shared.h"
-#include "common/sq.h"
-
-#if 1
-#define SQ_VERBOSE
-#if 0
-#define SQ_DEBUG
-#endif
-#endif
-
-/* #define SQUMPI_IGNORE */
-
-#define SQUB_NALLOC 32
-#define SQUMPI_NALLOC (32 * sizeof(t_squmpo))
-#define SQUAX_NALLOC (32 * sizeof(t_squack))
-
-#define SQUMPI_DEFAULT 500000 /* 120 bpm in microseconds per beat */
-
-/* Arguments reqcount and elsize as in calloc, returns count */
-size_t squb_checksize(void *buf, size_t reqcount, size_t elsize)
-{
- t_squb *x = buf;
- size_t reqsize = reqcount * elsize;
- size_t newsize = x->b_bufsize;
- while (newsize < reqsize) newsize *= 2;
- if (newsize == x->b_bufsize)
- return (newsize);
-#ifdef SQ_DEBUG
- post("need to resize buffer %x from %d to %d (requested size %d)",
- (int)x, x->b_bufsize, newsize, reqsize);
-#endif
- if (!(x->b_data = resizebytes(x->b_data, x->b_bufsize, newsize)) &&
- /* rather hopeless... */
- !(x->b_data = getbytes(newsize = SQUB_NALLOC * elsize)))
- newsize = 0;
- return ((x->b_bufsize = newsize) / elsize); /* LATER do it right */
-}
-
-/* generic event */
-
-/* tempo map */
-
-/* comparison function used by qsort */
-static int squmpi_compare(const void *tp1, const void *tp2)
-{
- return (((t_squmpo *)tp1)->te_onset > ((t_squmpo *)tp2)->te_onset ? 1 : -1);
-}
-
-void squmpi_sort(t_sq *x)
-{
- int i;
- t_squmpo *tp;
- qsort(x->s_tempomap, x->s_ntempi, sizeof(t_squmpo), squmpi_compare);
-#if defined SQ_VERBOSE && ! defined SQ_DEBUG
- for (i = x->s_ntempi, tp = x->s_tempomap; i > 0 ; i--, tp++)
- post("tempo %d at %d", tp->te_value, (int)tp->te_onset);
-#endif
-}
-
-t_squmpo *squmpi_add(t_sq *x)
-{
- size_t count = x->s_ntempi + 1;
- t_squmpo *tep;
- if (squb_checksize(x->s_mytempi, count, sizeof(t_squmpo)) < count)
- return (0);
- tep = x->s_tempomap + x->s_ntempi++;
- squmpo_reset(tep);
- return (tep);
-}
-
-void squmpo_reset(t_squmpo *x)
-{
- x->te_onset = 0;
- x->te_value = SQUMPI_DEFAULT;
-}
-
-/* track map */
-
-t_squack *squax_add(t_sq *x)
-{
- size_t count = x->s_ntracks + 2; /* guard point */
- t_squack *trp;
- if (squb_checksize(x->s_mytracks, count, sizeof(t_squack)) < count)
- return (0);
- trp = x->s_trackmap + x->s_ntracks++;
- squack_reset(trp);
- return (trp);
-}
-
-void squack_reset(t_squack *x)
-{
- x->tr_id = 0; /* this is no-id */
- x->tr_nevents = 0;
- x->tr_name = 0;
- x->tr_head = 0;
-}
-
-/* generic iterator */
-
-void *squiter_new(t_sq *x)
-{
- if (x->s_myiter = getbytes(sizeof(*x->s_myiter)))
- {
- }
- return (x->s_myiter);
-}
-
-/* routines to access iterator hooks (setting hooks is explicit only) */
-t_squiter_seekhook squiter_seekhook(t_squiter *x)
-{
- return (x ? (t_squiter_seekhook)x->i_hooks[SQUITER_SEEKHOOK] : 0);
-}
-
-t_squiter_incrhook squiter_incrhook(t_squiter *x)
-{
- return (x ? (t_squiter_incrhook)x->i_hooks[SQUITER_INCRHOOK] : 0);
-}
-
-t_squiter_getevehook squiter_getevehook(t_squiter *x)
-{
- return (x ? (t_squiter_getevehook)x->i_hooks[SQUITER_GETEVEHOOK] : 0);
-}
-
-t_squiter_setevehook squiter_setevehook(t_squiter *x)
-{
- return (x ? (t_squiter_setevehook)x->i_hooks[SQUITER_SETEVEHOOK] : 0);
-}
-
-t_squiter_gettimhook squiter_gettimhook(t_squiter *x)
-{
- return (x ? (t_squiter_gettimhook)x->i_hooks[SQUITER_GETTIMHOOK] : 0);
-}
-
-t_squiter_settimhook squiter_settimhook(t_squiter *x)
-{
- return (x ? (t_squiter_settimhook)x->i_hooks[SQUITER_SETTIMHOOK] : 0);
-}
-
-t_squiter_gettarhook squiter_gettarhook(t_squiter *x)
-{
- return (x ? (t_squiter_gettarhook)x->i_hooks[SQUITER_GETTARHOOK] : 0);
-}
-
-t_squiter_settarhook squiter_settarhook(t_squiter *x)
-{
- return (x ? (t_squiter_settarhook)x->i_hooks[SQUITER_SETTARHOOK] : 0);
-}
-
-/* time conversion */
-
-/* Compute reusable coefficient, rather then repeatedly apply the formula.
- For smpte time:
- d msecs == (d / 1000.) secs == ((d * nframes * nticks) / 1000.) ticks
- or for metrical time:
- d msecs == (d * 1000.) usecs == ((d * 1000.) / tempo) beats
- == ((d * nticks * 1000.) / tempo) ticks
-*/
-/* LATER ntsc */
-float sq_ticks2msecs(t_sq *x, uint32 tempo)
-{
- if (x->s_nframes)
- return (1000. / (x->s_nframes * x->s_nticks));
- if (tempo <= 0)
- tempo = x->s_tempo;
- if (tempo <= 0)
- tempo = SQUMPI_DEFAULT;
- return (tempo / (x->s_nticks * 1000.));
-}
-
-float sq_msecs2ticks(t_sq *x, uint32 tempo)
-{
- if (x->s_nframes)
- return (((x->s_nframes * x->s_nticks) / 1000.));
- if (!tempo)
- tempo = x->s_tempo;
- if (!tempo)
- tempo = SQUMPI_DEFAULT;
- return ((x->s_nticks * 1000.) / tempo);
-}
-
-/* transform onset ticks into delta msecs */
-void sq_fold_time(t_sq *x)
-{
- t_squiter *it = x->s_myiter;
- t_squiter_seekhook seekhook = squiter_seekhook(it);
- t_squiter_incrhook incrhook = squiter_incrhook(it);
- t_squiter_gettimhook gethook = squiter_gettimhook(it);
- t_squiter_settimhook sethook = squiter_settimhook(it);
- int i, ret, nevents = x->s_nevents;
-
- if (!it || !seekhook(it, 0))
- return;
- if (x->s_nframes)
- {
- float coef = sq_ticks2msecs(x, 0);
- t_float lasttime = 0;
- for (i = 0; i < nevents; i++)
- {
- if (ret = squiter_inrange(it))
- {
- t_float thistime = gethook(it, &ret) * coef;
- /* back to delta time */
- if (ret) sethook(it, thistime - lasttime, &ret);
- lasttime = thistime;
- }
- if (ret) incrhook(it);
- else
- {
- post("sequence folding error: bad iterator");
- break;
- }
- }
- }
- else /* apply tempomap */
- {
- float coef = sq_ticks2msecs(x, SQUMPI_DEFAULT);
- int ntempi = x->s_ntempi;
- t_float lasttime = 0, thistime = 0;
- t_float temposince = 0;
- t_float tempoonset = 0;
- int tempondx = 0;
- for (i = 0; i < nevents; i++)
- {
- if (ret = squiter_inrange(it))
- {
- t_float thisonset = gethook(it, &ret);
- t_float nexttempoonset;
-#ifdef SQUMPI_IGNORE
- thistime = thisonset * coef;
-#else
- while (tempondx < ntempi /* LATER consider using guard point */
- && (nexttempoonset = x->s_tempo_onset(tempondx))
- < thisonset)
- {
- temposince += (nexttempoonset - tempoonset) * coef;
- tempoonset = nexttempoonset;
- coef = sq_ticks2msecs(x, x->s_tempo_value(tempondx));
- tempondx++;
- }
- thistime = temposince + (thisonset - tempoonset) * coef;
-#endif
- if (thistime < lasttime)
- {
-#ifdef SQ_DEBUG
- /* FIXME under msvc -- horror! */
- if (thistime != lasttime)
- post("ndx %d, this-last (%x-%x) %.15f, \
-tix %.9f, tsince %.9f, ttix %.9f, coef %.9f",
- tempondx, (int)thistime, (int)lasttime,
- thistime - lasttime,
- thisonset, temposince, tempoonset, coef);
-#endif
- thistime = lasttime;
- }
- /* back to delta time */
- if (ret) sethook(it, thistime - lasttime, &ret);
- lasttime = thistime;
- }
- if (ret) incrhook(it);
- else
- {
- post("sequence folding error: bad iterator");
- break;
- }
- }
- }
-}
-
-/* transform delta msecs into onset msecs */
-/* LATER add an option (or a separate function) for obtaining ticks
- (according to tempomap) */
-void sq_unfold_time(t_sq *x)
-{
- t_squiter *it = x->s_myiter;
- t_squiter_seekhook seekhook = squiter_seekhook(it);
- t_squiter_incrhook incrhook = squiter_incrhook(it);
- t_squiter_gettimhook gethook = squiter_gettimhook(it);
- t_squiter_settimhook sethook = squiter_settimhook(it);
- int i, ret, nevents = x->s_nevents;
- t_float thisonset = 0;
-
- if (!it || !seekhook(it, 0))
- return;
- for (i = 0; i < nevents; i++)
- {
- if (ret = squiter_inrange(it))
- {
- thisonset += gethook(it, &ret);
- if (ret) sethook(it, thisonset, &ret);
- }
- if (ret) incrhook(it);
- else
- {
- post("sequence unfolding error: bad iterator");
- break;
- }
- }
-}
-
-void sq_reset(t_sq *x)
-{
- x->s_eof = 0;
- x->s_newtrack = 0;
- x->s_anapass = 1;
- x->s_fp = 0;
- x->s_time = 0;
- x->s_tempo = SQUMPI_DEFAULT;
- x->s_track = 0;
-}
-
-t_sq *sq_new(void)
-{
- t_sq *x = (t_sq *)getbytes(sizeof(*x));
- if (!x)
- goto constructorfailure;
-
- /* these two are allocated in derived structure constructor */
- x->s_myiter = 0;
- x->s_auxeve = 0;
-
- if (!(x->s_mytempi = getbytes(sizeof(t_squmpi))))
- goto constructorfailure;
- if (!(x->s_tempomap = getbytes(x->s_mytempi->m_bufsize = SQUMPI_NALLOC)))
- goto constructorfailure;
- x->s_ntempi = 0;
- if (!(x->s_mytracks = getbytes(sizeof(t_squax))))
- goto constructorfailure;
- if (!(x->s_trackmap = getbytes(x->s_mytracks->m_bufsize = SQUAX_NALLOC)))
- goto constructorfailure;
- x->s_ntracks = 0;
-
- x->s_autoalloc = 0;
- x->s_format = 0;
- x->s_nticks = 192; /* LATER parametrize this somehow */
- x->s_nframes = 0;
-
- sq_reset(x);
- return (x);
-constructorfailure:
- if (x) sq_free(x);
- return (0);
-}
-
-void sq_free(t_sq *x)
-{
- if (x->s_mytempi)
- {
- if (x->s_tempomap)
- freebytes(x->s_tempomap, x->s_mytempi->m_bufsize);
- freebytes(x->s_mytempi, sizeof(t_squmpi));
- }
- if (x->s_mytracks)
- {
- if (x->s_trackmap)
- freebytes(x->s_trackmap, x->s_mytracks->m_bufsize);
- freebytes(x->s_mytracks, sizeof(t_squax));
- }
- if (x->s_myiter)
- freebytes(x->s_myiter, sizeof(*x->s_myiter));
- freebytes(x, sizeof(*x));
-}
diff --git a/shared/common/sq.h b/shared/common/sq.h
deleted file mode 100644
index 6b7586e..0000000
--- a/shared/common/sq.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/* Copyright (c) 2001-2003 krzYszcz and others.
- * For information on usage and redistribution, and for a DISCLAIMER OF ALL
- * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
-
-/* squeak and squeal: sequencing utilities, a prototype version
- (the main, 'sq' part of the library) */
-/* LATER move everything not needed in mifi to squeal */
-
-#ifndef __SQ_H__
-#define __SQ_H__
-
-/* Generic buffer structure, the `base' for t_squeve, t_squmpi and t_squax */
-typedef struct _squb
-{
- uint32 b_length; /* length of data currently used (in items) */
- uchar *b_data; /* data buffer */
- size_t b_bufsize; /* allocated size of data buffer (in bytes) */
-} t_squb;
-
-/* Generic event structure. Designed as an interface to squeak routines,
- and not to be kept in arrays or lists (use sequence containers instead).
- Data buffer is automatically allocated and resized by those routines. */
-typedef struct _squeve
-{
- uint32 e_length; /* set for any event type! */
- uchar *e_data;
- size_t e_bufsize;
- uint32 e_delay;
-} t_squeve;
-
-/* tempo map element */
-typedef struct _squmpo
-{
- t_float te_onset; /* ticks or microseconds from start of sequence */
- uint32 te_value; /* microseconds per beat */
-} t_squmpo;
-
-typedef struct _squmpi
-{
- uint32 m_ntempi;
- t_squmpo *m_map;
- size_t m_bufsize; /* allocated size of m_map array in bytes */
-} t_squmpi;
-
-/* track/subtrack map element */
-typedef struct _squack
-{
- int tr_id; /* according to target template */
- uint32 tr_nevents; /* number of events (in this track or pre-total) */
- t_symbol *tr_name; /* track name */
- void *tr_head; /* pointer to first event */
-} t_squack;
-
-typedef struct _squax
-{
- uint32 m_ntracks;
- t_squack *m_map;
- size_t m_bufsize; /* allocated size of m_map array in bytes */
-} t_squax;
-
-/* generic type of callback routines used to read/write
- sequence containers through t_squiter */
-typedef int (*t_squiterhook)(void *it);
-
-#define SQUITER_SEEKHOOK 0
-#define SQUITER_INCRHOOK 1
-#define SQUITER_GETEVEHOOK 2
-#define SQUITER_SETEVEHOOK 3
-#define SQUITER_GETTIMHOOK 4
-#define SQUITER_SETTIMHOOK 5
-#define SQUITER_GETTARHOOK 6
-#define SQUITER_SETTARHOOK 7
-#define SQUITER_NHOOKS 8
-/* LATER move these typedefs to sq.c, if still not used globally */
-typedef int (*t_squiter_seekhook)(void *it, int offset);
-typedef void (*t_squiter_incrhook)(void *it);
-typedef void (*t_squiter_getevehook)(void *it, t_squeve *evp, int *ret);
-typedef void (*t_squiter_setevehook)(void *it, t_squeve *evp, int *ret);
-typedef t_float (*t_squiter_gettimhook)(void *it, int *ret);
-typedef void (*t_squiter_settimhook)(void *it, t_float v, int *ret);
-typedef t_symbol (*t_squiter_gettarhook)(void *it, int *ret);
-typedef void (*t_squiter_settarhook)(void *it, t_symbol *s, int *ret);
-
-/* elements might be 'atoms' or whole events, whatever suits better */
-typedef struct _squiter
-{
- void *i_owner;
- int i_nelems;
- void *i_sequence; /* first element pointer */
- void *i_element; /* current element pointer */
- int i_index; /* current element index */
- t_squiterhook i_hooks[SQUITER_NHOOKS];
-} t_squiter;
-
-/* This is a good candidate for a derivation hierarchy. */
-typedef struct _sq
-{
- t_squiter *s_myiter;
- t_squax *s_mytracks;
- t_squmpi *s_mytempi; /* use shortcuts #defined below */
- void *s_auxeve; /* auxiliary event */
- uint32 s_nevents; /* total number of events */
- FILE *s_fp; /* hmm... */
- int s_autoalloc:1; /* set if auto-allocated */
- int s_eof:1; /* reading: set in case of early eof (error) */
- int s_newtrack:1; /* reading: set if first event in a track */
- int s_anapass:1; /* read/write: set during analysis (pass #1) */
- uchar s_nframes; /* fps if nonzero, else use metrical time */
- uint16 s_nticks; /* number of ticks per beat or per frame */
- uint16 s_format; /* `ismultitrack' flag, LATER add other formats */
- uint32 s_time; /* current time in ticks */
- uint32 s_tempo; /* current tempo, or last one encountered in a file */
- int s_trackid; /* LATER remove? */
- uint16 s_track; /* current track number */
-
- /* fields below are specific to midifile streams */
- uchar s_status; /* current running status, | channel in writing */
- uchar s_channel; /* current channel, not used in writing */
- uint16 s_hdtracks; /* number of tracks declared in a midifile header */
- uint32 s_alltracks; /* total number of nonempty tracks */
- /* (s_ntracks counts `in range' nonempty tracks) */
- float s_timecoef; /* msecs->ticks, used in writing only */
- uint32 s_bytesleft; /* nbytes remaining to be read from current track,
- or number of bytes written to a track so far */
-} t_sq;
-
-#define s_ntempi s_mytempi->m_ntempi
-#define s_tempomap s_mytempi->m_map
-#define s_tempo_onset(ndx) s_mytempi->m_map[ndx].te_onset
-#define s_tempo_value(ndx) s_mytempi->m_map[ndx].te_value
-#define s_ntracks s_mytracks->m_ntracks
-#define s_trackmap s_mytracks->m_map
-#define s_track_id(ndx) s_mytracks->m_map[ndx].tr_id
-#define s_track_nevents(ndx) s_mytracks->m_map[ndx].tr_nevents
-#define s_track_name(ndx) s_mytracks->m_map[ndx].tr_name
-#define s_track_head(ndx) s_mytracks->m_map[ndx].tr_head
-
-/* prototypes of public interface routines */
-
-size_t squb_checksize(void *buf, size_t reqcount, size_t elsize);
-
-#define squiter_inrange(it) ((it)->i_index < (it)->i_nelems)
-void *squiter_new(t_sq *x);
-t_squiter_seekhook squiter_seekhook(t_squiter *x);
-t_squiter_incrhook squiter_incrhook(t_squiter *x);
-t_squiter_getevehook squiter_getevehook(t_squiter *x);
-t_squiter_setevehook squiter_setevehook(t_squiter *x);
-t_squiter_gettimhook squiter_gettimhook(t_squiter *x);
-t_squiter_settimhook squiter_settimhook(t_squiter *x);
-t_squiter_gettarhook squiter_gettarhook(t_squiter *x);
-t_squiter_settarhook squiter_settarhook(t_squiter *x);
-
-void squmpi_sort(t_sq *x);
-t_squmpo *squmpi_add(t_sq *x);
-void squmpo_reset(t_squmpo *x);
-t_squack *squax_add(t_sq *x);
-void squack_reset(t_squack *x);
-
-float sq_ticks2msecs(t_sq *x, uint32 tempo);
-float sq_msecs2ticks(t_sq *x, uint32 tempo);
-
-void sq_fold_time(t_sq *x);
-void sq_unfold_time(t_sq *x);
-
-t_sq *sq_new(void);
-void sq_reset(t_sq *x);
-void sq_free(t_sq *x);
-
-#endif
diff --git a/shared/unstable/standalone.c b/shared/unstable/standalone.c
new file mode 100644
index 0000000..5b780e9
--- /dev/null
+++ b/shared/unstable/standalone.c
@@ -0,0 +1,80 @@
+/* Copyright (c) 1997-2004 Miller Puckette, krzYszcz, and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* Parts of Pd API are duplicated here, as needed by standalone versions of
+ Pd modules. LATER standalones should be linked to the Pd API library. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "standalone.h"
+
+void *getbytes(size_t nbytes)
+{
+ void *ret;
+ if (nbytes < 1) nbytes = 1;
+ ret = (void *)calloc(nbytes, 1);
+ if (!ret)
+ fprintf(stderr, "ERROR: getbytes() failed -- out of memory");
+ return (ret);
+}
+
+void *resizebytes(void *old, size_t oldsize, size_t newsize)
+{
+ void *ret;
+ if (newsize < 1) newsize = 1;
+ if (oldsize < 1) oldsize = 1;
+ ret = (void *)realloc((char *)old, newsize);
+ if (newsize > oldsize && ret)
+ memset(((char *)ret) + oldsize, 0, newsize - oldsize);
+ if (!ret)
+ fprintf(stderr, "ERROR: resizebytes() failed -- out of memory");
+ return (ret);
+}
+
+void freebytes(void *fatso, size_t nbytes)
+{
+ free(fatso);
+}
+
+#define HASHSIZE 1024
+
+static t_symbol *symhash[HASHSIZE];
+
+static t_symbol *dogensym(char *s, t_symbol *oldsym)
+{
+ t_symbol **sym1, *sym2;
+ unsigned int hash1 = 0, hash2 = 0;
+ int length = 0;
+ char *s2 = s;
+ while (*s2)
+ {
+ hash1 += *s2;
+ hash2 += hash1;
+ length++;
+ s2++;
+ }
+ sym1 = symhash + (hash2 & (HASHSIZE-1));
+ while (sym2 = *sym1)
+ {
+ if (!strcmp(sym2->s_name, s)) return(sym2);
+ sym1 = &sym2->s_next;
+ }
+ if (oldsym) sym2 = oldsym;
+ else
+ {
+ sym2 = (t_symbol *)getbytes(sizeof(*sym2));
+ sym2->s_name = getbytes(length+1);
+ sym2->s_next = 0;
+ sym2->s_thing = 0;
+ strcpy(sym2->s_name, s);
+ }
+ *sym1 = sym2;
+ return (sym2);
+}
+
+t_symbol *gensym(char *s)
+{
+ return(dogensym(s, 0));
+}
diff --git a/shared/unstable/standalone.h b/shared/unstable/standalone.h
new file mode 100644
index 0000000..6ca62d1
--- /dev/null
+++ b/shared/unstable/standalone.h
@@ -0,0 +1,57 @@
+/* Copyright (c) 2004 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef MIXED_STANDALONE
+#error MIXED_STANDALONE not defined
+#else
+#ifndef __STANDALONE_H__
+#define __STANDALONE_H__
+
+typedef int t_int;
+typedef float t_float;
+
+typedef struct _symbol
+{
+ char *s_name;
+ void *s_thing;
+ struct _symbol *s_next;
+} t_symbol;
+
+typedef union word
+{
+ t_float w_float;
+ t_symbol *w_symbol;
+ int w_index;
+} t_word;
+
+typedef enum
+{
+ A_NULL,
+ A_FLOAT,
+ A_SYMBOL,
+ A_POINTER,
+ A_SEMI,
+ A_COMMA,
+ A_DEFFLOAT,
+ A_DEFSYM,
+ A_DOLLAR,
+ A_DOLLSYM,
+ A_GIMME,
+ A_CANT
+} t_atomtype;
+
+typedef struct _atom
+{
+ t_atomtype a_type;
+ union word a_w;
+} t_atom;
+
+
+void *getbytes(size_t nbytes);
+void *resizebytes(void *old, size_t oldsize, size_t newsize);
+void freebytes(void *fatso, size_t nbytes);
+t_symbol *gensym(char *s);
+
+#endif
+#endif
diff --git a/test/cyclone/maxmode-test.pd b/test/cyclone/maxmode-test.pd
new file mode 100644
index 0000000..1a4512a
--- /dev/null
+++ b/test/cyclone/maxmode-test.pd
@@ -0,0 +1,20 @@
+#N canvas 356 180 524 263 12;
+#X obj 310 29 r #compatibility;
+#X obj 23 66 s #compatibility;
+#X msg 23 29 bang;
+#X msg 78 29 symbol max;
+#X obj 24 173 prepend test;
+#X msg 79 130 set this;
+#X msg 184 130 set that;
+#X msg 24 130 x;
+#X obj 310 66 print mode;
+#X obj 24 208 print output;
+#X msg 178 29 symbol barry;
+#X connect 0 0 8 0;
+#X connect 2 0 1 0;
+#X connect 3 0 1 0;
+#X connect 4 0 9 0;
+#X connect 5 0 4 0;
+#X connect 6 0 4 0;
+#X connect 7 0 4 0;
+#X connect 10 0 1 0;
diff --git a/test/toxy/lbpict-test.pd b/test/toxy/lbpict-test.pd
new file mode 100644
index 0000000..b2214b6
--- /dev/null
+++ b/test/toxy/lbpict-test.pd
@@ -0,0 +1,3 @@
+#N canvas 0 0 756 516 12;
+#X obj 47 50 widget lbpict p1 #fname /usr/lib/tk8.4/demos/images/earth.gif
+;
diff --git a/test/toxy/lbpict.wid b/test/toxy/lbpict.wid
new file mode 100644
index 0000000..d7d5771
--- /dev/null
+++ b/test/toxy/lbpict.wid
@@ -0,0 +1,7 @@
+proc ::toxy::lbpict {path fname} {
+ $path config -image [image create photo -file $fname]
+}
+
+#> lbpict label
+
+::toxy::lbpict .- .#fname
diff --git a/test/toxy/testmess-test.pd b/test/toxy/testmess-test.pd
new file mode 100644
index 0000000..712cbfc
--- /dev/null
+++ b/test/toxy/testmess-test.pd
@@ -0,0 +1,35 @@
+#N canvas 235 56 752 558 12;
+#X obj 326 23 widget testmess t;
+#X obj 122 241 tow . testmess t;
+#X msg 141 113 1;
+#X msg 122 75 1 2 3 4 5 6 7 8 9 10;
+#X msg 245 113 1 2 test;
+#X floatatom 243 194 0 0 0 0 - - -;
+#X obj 14 152 testmess 20;
+#X msg 76 28 50;
+#X msg 137 28 100;
+#X msg 190 113 list;
+#X msg 14 113 set \$1 \, bang;
+#X msg 14 28 20;
+#X floatatom 14 75 5 0 0 0 - - -;
+#X obj 16 241 r lb;
+#X obj 122 194 t b a;
+#X obj 243 152 tow . testmess t;
+#X msg 16 282;
+#X msg 212 28 debug;
+#X connect 2 0 14 0;
+#X connect 3 0 14 0;
+#X connect 4 0 14 0;
+#X connect 6 0 14 0;
+#X connect 7 0 12 0;
+#X connect 8 0 12 0;
+#X connect 9 0 14 0;
+#X connect 10 0 6 0;
+#X connect 11 0 12 0;
+#X connect 12 0 10 0;
+#X connect 13 0 16 0;
+#X connect 14 0 1 0;
+#X connect 14 1 1 0;
+#X connect 15 0 5 0;
+#X connect 17 0 15 0;
+#X connect 17 0 0 0;
diff --git a/test/toxy/testmess.wid b/test/toxy/testmess.wid
new file mode 100644
index 0000000..3263fa4
--- /dev/null
+++ b/test/toxy/testmess.wid
@@ -0,0 +1,34 @@
+puts setup
+
+proc testmess_list {path target args} {
+ set sum 0
+ foreach a $args {
+ incr sum $a
+ }
+ set lb [concat [lindex $args 0]]
+ foreach a [lrange $args 1 end] {
+ lappend lb + $a
+ }
+ lappend lb = $sum
+ set [$path cget -textvariable] $lb
+ pd [concat $target _cb $sum \;]
+}
+
+proc testmess_command {path} {
+ pd [concat lb set [set [$path cget -textvariable]] \;]
+}
+
+#> testmess button
+#. -bg green -wraplength 350 -text test
+#. -command [concat testmess_command .-]
+#. @bang .- invoke
+#. @float testmess_list .- .| .#args
+#. @list testmess_list .- .| .#args
+
+puts initializer
+
+#@ new
+puts constructor
+
+#@ free
+puts destructor
diff --git a/test/toxy/tot-color.pd b/test/toxy/tot-color.pd
new file mode 100644
index 0000000..c799195
--- /dev/null
+++ b/test/toxy/tot-color.pd
@@ -0,0 +1,27 @@
+#N canvas 307 84 527 317 12;
+#X obj 20 92 tot .;
+#X msg 82 73 query winfo rgb . green;
+#X obj 20 129 unpack 0 0 0;
+#X obj 20 168 / 256;
+#X obj 95 168 / 256;
+#X obj 170 168 / 256;
+#X obj 20 276 print;
+#X obj 20 241 pack 0 0 0;
+#X obj 20 205 int;
+#X obj 95 205 int;
+#X obj 170 205 int;
+#X msg 20 22 query set cl [tk_chooseColor] .: if .($cl != "".) .(winfo
+rgb . $cl.);
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 2 0 3 0;
+#X connect 2 1 4 0;
+#X connect 2 2 5 0;
+#X connect 3 0 8 0;
+#X connect 4 0 9 0;
+#X connect 5 0 10 0;
+#X connect 7 0 6 0;
+#X connect 8 0 7 0;
+#X connect 9 0 7 1;
+#X connect 10 0 7 2;
+#X connect 11 0 0 0;