diff options
Diffstat (limited to 'shared')
-rw-r--r-- | shared/common/bifi.c | 217 | ||||
-rw-r--r-- | shared/common/bifi.h | 40 | ||||
-rw-r--r-- | shared/common/clc.c | 84 | ||||
-rw-r--r-- | shared/common/clc.h | 10 | ||||
-rw-r--r-- | shared/common/fi.c | 54 | ||||
-rw-r--r-- | shared/common/fi.h | 11 | ||||
-rw-r--r-- | shared/common/lex.c | 272 | ||||
-rw-r--r-- | shared/common/lex.h | 25 | ||||
-rw-r--r-- | shared/common/qtree.c | 780 | ||||
-rw-r--r-- | shared/common/qtree.h | 83 | ||||
-rw-r--r-- | shared/common/sq.c | 371 | ||||
-rw-r--r-- | shared/common/sq.h | 169 | ||||
-rw-r--r-- | shared/unstable/standalone.c | 80 | ||||
-rw-r--r-- | shared/unstable/standalone.h | 57 |
14 files changed, 1456 insertions, 797 deletions
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 |