diff options
Diffstat (limited to 'src')
49 files changed, 14059 insertions, 0 deletions
diff --git a/src/makefile.irix b/src/makefile.irix new file mode 100644 index 0000000..b644cf1 --- /dev/null +++ b/src/makefile.irix @@ -0,0 +1,29 @@ +current: irix5 + +TARGETS = zexy \ + z_sfplay z_sfrecord \ + z_noise z_testfun \ + z_limiter \ + z_dfreq z_sigbin \ + z_sigzero z_pdf z_average \ + z_nop z_zdelay z_swap z_quantize \ + z_makesymbol z_tabread4 \ + z_datetime z_index \ + z_connective z_sigpack z_sort \ + z_multiplex z_drip z_pack \ + +SGI5OBJECTS = $(TARGETS:%=%.pd_irix5) + +# ----------------------- IRIX ---------------------------- +.SUFFIXES: .pd_irix5 +SGIINCLUDE = -I../../src + +irix5: $(SGIOBJECTS) + +.c.pd_irix5: + cc -g -w2 -fullwarn -mips2 -DFTS $(SGIINCLUDE) -c $*.c + ld -elf -shared -rdata_shared -o $*.pd_irix5 $*.o + rm $*.o + +clean:: + rm *.o obj/* *.pd_irix5 so_locations rm *.pd_linux *~ diff --git a/src/makefile.linux b/src/makefile.linux new file mode 100644 index 0000000..caa9297 --- /dev/null +++ b/src/makefile.linux @@ -0,0 +1,90 @@ +current: all + + +# the ZEXY-EXTERNAL-makefile +# everything is GnuGPL that should come with the zexy.tgz +# NO WARRANTIES FOR ANYTHING +# et cetera +# 1999:forum::für::umläute:2001 + +# make sure that the "m_pd.h" is somehow available either by putting it into this +# directory, by adding it's path to the INCLUDE-path or by putting it into an +# already included path, e.g. "/usr/local/include/" + +#these are the user adjustables : adjust them to fit into your system +# PD will install to $(DESTDIR)$(INSTALLL_PREFIX)$(PDLIBDIR), which is /usr/local/lib/pd +# by default +DESTDIR = +INSTALL_PREFIX = /usr/local +PDLIBDIR = /lib/pd +#these were the user adjustables + + +TARGETS = zexy \ + z_connective z_pack z_multiplex z_drip \ + z_makesymbol z_strings \ + z_index z_msgfile \ + z_stat z_average z_sort \ + z_tabread4 z_coordinates \ + z_datetime z_lp \ + z_matrix \ + z_noise z_testfun \ + z_multiline z_sigmatrix \ + z_nop z_zdelay \ + z_limiter z_quantize z_swap \ + z_sigbin z_sigaverage \ + z_dfreq z_sigzero z_pdf \ + z_sfplay z_sfrecord \ + z_sigpack \ + z_down z_prime z_random + +# ----------------------- LINUX ---------------------------- +.SUFFIXES: .pd_linux + + +LINUXOBJECTS = $(TARGETS:%=%.o) +ARCH = $(shell uname --machine) + +PD_DIR = $(DESTDIR)$(INSTALL_PREFIX)$(PDLIBDIR) + +ifeq (${ARCH},alpha) +AFLAGS = -mieee -mcpu=ev56 +endif + +LINCLUDE = + +$(LINUXOBJECTS): *.h + +CFLAGS = -O2 -g -Wall $(LINCLUDE) $(UCFLAGS) $(AFLAGS) + +everything: clean all install distclean + +distclean: + touch dummy.o + touch dummy.pd_linux + touch dummy~ + touch _dummy + rm *.o *.pd_linux *~ _* + +clean: + touch dummy.o + touch dummy.pd_linux + rm *.o *.pd_linux + +all: $(LINUXOBJECTS) + + @echo :: $(LINUXOBJECTS) + + ld -export_dynamic -shared -o zexy.pd_linux *.o -lc -lm + strip --strip-unneeded zexy.pd_linux + +.c.pd_linux: + cc $(CFLAGS) -O2 -DPD -fPIC $(INCLUDE) -c -o $*.o $*.c + + +install: installdocs + install -m 644 zexy.pd_linux $(PD_DIR)/externs + +installdocs: + install -d $(PD_DIR)/doc/5.reference/zexy + install -m644 ../examples/* $(PD_DIR)/doc/5.reference/zexy diff --git a/src/strip_objects b/src/strip_objects new file mode 100755 index 0000000..3e99132 --- /dev/null +++ b/src/strip_objects @@ -0,0 +1,8 @@ +#!/bin/sh +TMPFILE=/tmp/pdobjects +touch $TMPFILE +rm $TMPFILE +grep --no-filename class_new *.c | awk '{print $3}' >> $TMPFILE +for i in `cat $TMPFILE`; do i=${i##class_new(gensym(\"}; i=${i%%\"),}; echo $i ; done +touch $TMPFILE +rm $TMPFILE diff --git a/src/z_average.c b/src/z_average.c new file mode 100644 index 0000000..f0c2fd9 --- /dev/null +++ b/src/z_average.c @@ -0,0 +1,113 @@ +#include "zexy.h" + +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +/* ------------------------ average ----------------------------- */ + +/* mavg :: moving average filter */ + +static t_class *mavg_class; + +typedef struct _mavg +{ + t_object x_obj; + + t_float n_inv; + t_float avg; + int size; + t_float *buf, *wp; +} t_mavg; + +static void mavg_resize(t_mavg *x, t_float f) +{ + int i; + t_float *dumbuf; + + f = (int)f; + if ((f<1) || (f == x->size)) return; + + freebytes(x->buf, sizeof(t_float)*x->size); + x->n_inv = 1.0/f; + x->size = f; + x->buf = getbytes(sizeof(t_float)*x->size); + + dumbuf = x->wp = x->buf; + i = x->size; + while(i--) *dumbuf++ = x->avg; +} + +static void mavg_set(t_mavg *x, t_symbol *s, int argc, t_atom *argv) +{ + int i = x->size; + t_float *dummy = x->buf; + t_float f=(argc)?atom_getfloat(argv):x->avg; + + while (i--) *dummy++=f; + + x->wp = x->buf; +} + +static void mavg_float(t_mavg *x, t_float f) +{ + int i = x->size; + t_float dummy = 0; + t_float *dumb = x->buf; + + *x->wp++ = f; + if (x->wp == x->buf + x->size) x->wp = x->buf; + + while (i--) dummy += *dumb++; + + x->avg = dummy*x->n_inv; + + outlet_float(x->x_obj.ob_outlet,x->avg); +} + +static void *mavg_new(t_floatarg f) +{ + t_mavg *x = (t_mavg *)pd_new(mavg_class); + int i = (f<1)?2:f; + t_float *dumbuf; + + outlet_new(&x->x_obj, gensym("float")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("")); + + x->buf = x->wp = (t_float *)getbytes(sizeof(t_float) * i); + x->size = i; + x->n_inv = 1.0f/(t_float)i; + + dumbuf = x->buf; + while (i--) *dumbuf++=0; + + return (x); +} + +static void mavg_help(void) +{ + post("mavg\t:: moving average filter"); +} + +static void mavg_setup(void) +{ + mavg_class = class_new(gensym("mavg"), (t_newmethod)mavg_new, 0, + sizeof(t_mavg), 0, A_DEFFLOAT, 0); + + class_addfloat(mavg_class, (t_method)mavg_float); + + class_addmethod(mavg_class, (t_method)mavg_help, gensym("help"), 0); + class_addmethod(mavg_class, (t_method)mavg_set, gensym("set"), A_GIMME, 0); + class_addmethod(mavg_class, (t_method)mavg_resize, gensym(""), A_DEFFLOAT, 0); + + class_sethelpsymbol(mavg_class, gensym("zexy/mavg")); +} + + +/* global setup routine */ + +void z_average_setup(void) +{ + mavg_setup(); +} diff --git a/src/z_connective.c b/src/z_connective.c new file mode 100644 index 0000000..79acbdd --- /dev/null +++ b/src/z_connective.c @@ -0,0 +1,585 @@ +/* 2305:forum::für::umläute:2001 */ + +/* connective objects */ + +/* + segregate : segregate atoms by their types + nop : a do-nothing, pass-everything + lister : the same as "float" for floats but for packages + a2l : convert "anything" to "list" + list2int : cast all floats of a list to integers + glue : glue to lists together (append,...) + . : scalar mult + TODO : any +*/ + +#include "zexy.h" + + +#ifdef NT +#include <string.h> +#endif + +/* -------------------- segregate ------------------------------ */ + +/* + sorts the input by type :: + known types are (in order of their outlets :: + BANG, FLOAT, SYMBOL, LIST, POINTER, ANYTHING +*/ + +static t_class *segregate_class; + +typedef struct _segregate +{ + t_object x_obj; + + t_outlet *bang_out, *float_out, *symbol_out, *list_out, *pointer_out, *any_out; +} t_segregate; + +static void segregate_bang(t_segregate *x) +{ outlet_bang(x->bang_out); } + +static void segregate_float(t_segregate *x, t_float f) +{ outlet_float(x->float_out, f); } + +static void segregate_symbol(t_segregate *x, t_symbol *s) +{ outlet_symbol(x->symbol_out, s); } + +static void segregate_pointer(t_segregate *x, t_gpointer *gp) +{ outlet_pointer(x->pointer_out, gp); } + +static void segregate_list(t_segregate *x, t_symbol *s, int argc, t_atom *argv) +{ outlet_list(x->list_out, s, argc, argv); } + +static void segregate_anything(t_segregate *x, t_symbol *s, int argc, t_atom *argv) +{ outlet_anything(x->any_out, s, argc, argv); } + +static void *segregate_new(t_symbol *s) +{ + t_segregate *x = (t_segregate *)pd_new(segregate_class); + + x->bang_out = outlet_new(&x->x_obj, &s_bang); + x->float_out = outlet_new(&x->x_obj, &s_float); + x->symbol_out = outlet_new(&x->x_obj, &s_symbol); + x->list_out = outlet_new(&x->x_obj, &s_list); + x->pointer_out = outlet_new(&x->x_obj, &s_pointer); + x->any_out = outlet_new(&x->x_obj, 0); + + return (x); +} + +static void segregate_setup(void) +{ + segregate_class = class_new(gensym("segregate"), (t_newmethod)segregate_new, + 0, sizeof(t_segregate), 0, 0); + + class_addbang(segregate_class, segregate_bang); + class_addfloat(segregate_class, (t_method)segregate_float); + class_addsymbol(segregate_class, segregate_symbol); + class_addpointer(segregate_class, segregate_pointer); + class_addlist(segregate_class, segregate_list); + class_addanything(segregate_class, segregate_anything); + + class_sethelpsymbol(segregate_class, gensym("zexy/segregate")); +} + +/* ------------------------- nop ------------------------------- */ + +/* a no-operation - just pass through what you get in */ + +static t_class *nop_class; + +typedef struct _nop +{ + t_object x_obj; +} t_nop; + +static void nop_anything(t_nop *x, t_symbol *s, int argc, t_atom *argv) +{ outlet_anything(x->x_obj.ob_outlet, s, argc, argv);} + +static void nop_list(t_nop *x, t_symbol *s, int argc, t_atom *argv) +{ outlet_list(x->x_obj.ob_outlet, s, argc, argv);} + +static void nop_float(t_nop *x, t_floatarg f) +{ outlet_float(x->x_obj.ob_outlet, f);} + +static void nop_symbol(t_nop *x, t_symbol *s) +{ outlet_symbol(x->x_obj.ob_outlet, s);} + +static void nop_pointer(t_nop *x, t_gpointer *gp) +{ outlet_pointer(x->x_obj.ob_outlet, gp);} + +static void nop_bang(t_nop *x) +{ outlet_bang(x->x_obj.ob_outlet);} + +static void *nop_new(void) +{ + t_nop *x = (t_nop *)pd_new(nop_class); + outlet_new(&x->x_obj, 0); + return (x); +} + +static void nop_setup(void) +{ + nop_class = class_new(gensym("nop"), (t_newmethod)nop_new, + 0, sizeof(t_nop), 0, 0); + + class_addbang (nop_class, nop_bang); + class_addfloat (nop_class, nop_float); + class_addsymbol (nop_class, nop_symbol); + class_addpointer (nop_class, nop_pointer); + class_addlist (nop_class, nop_list); + class_addanything(nop_class, nop_anything); + + class_sethelpsymbol(nop_class, gensym("zexy/nop")); +} + + + + +/* ------------------------- a2l ------------------------------- */ + +/* convert anythings to lists, pass through the rest */ + +static t_class *a2l_class; + +typedef struct _a2l +{ + t_object x_obj; +} t_a2l; + +static void a2l_anything(t_a2l *x, t_symbol *s, int argc, t_atom *argv) +{ + int n = argc+1; + t_atom *cur, *alist = (t_atom *)getbytes(n * sizeof(t_atom)); + + cur = alist; + SETSYMBOL(cur, s); + cur++; + + memcpy(cur, argv, argc * sizeof(t_atom)); + + outlet_list(x->x_obj.ob_outlet, gensym("list"), n, alist); + + freebytes(alist, n * sizeof(t_atom)); + +} + +static void a2l_list(t_a2l *x, t_symbol *s, int argc, t_atom *argv) +{ outlet_list(x->x_obj.ob_outlet, s, argc, argv);} + +static void a2l_float(t_a2l *x, t_floatarg f) +{ outlet_float(x->x_obj.ob_outlet, f);} + +static void a2l_symbol(t_a2l *x, t_symbol *s) +{ outlet_symbol(x->x_obj.ob_outlet, s);} + +static void a2l_pointer(t_a2l *x, t_gpointer *gp) +{ outlet_pointer(x->x_obj.ob_outlet, gp);} + +static void a2l_bang(t_a2l *x) +{ outlet_bang(x->x_obj.ob_outlet);} + +static void *a2l_new(void) +{ + t_a2l *x = (t_a2l *)pd_new(a2l_class); + outlet_new(&x->x_obj, 0); + return (x); +} + +static void a2l_setup(void) +{ + + a2l_class = class_new(gensym("any2list"), (t_newmethod)a2l_new, + 0, sizeof(t_a2l), 0, 0); + class_addcreator((t_newmethod)a2l_new, gensym("a2l"), 0); + + + class_addbang (a2l_class, a2l_bang); + class_addfloat (a2l_class, a2l_float); + class_addsymbol (a2l_class, a2l_symbol); + class_addpointer (a2l_class, a2l_pointer); + class_addlist (a2l_class, a2l_list); + class_addanything(a2l_class, a2l_anything); + + class_sethelpsymbol(a2l_class, gensym("zexy/any2list")); +} + +/* ------------------------- list ------------------------------- */ + +/* this is for packages, what "float" is for floats */ + +static t_class *mypdlist_class; + +typedef struct _mypdlist +{ + t_object x_obj; + + int x_n; + t_atom *x_list; +} t_mypdlist; + +static void mypdlist_secondlist(t_mypdlist *x, t_symbol *s, int argc, t_atom *argv) +{ + if (argc) { + if (x->x_n != argc) { + freebytes(x->x_list, x->x_n * sizeof(t_atom)); + x->x_n = argc; + x->x_list = copybytes(argv, argc * sizeof(t_atom)); + } else memcpy(x->x_list, argv, argc * sizeof(t_atom)); + } +} + +static void mypdlist_list(t_mypdlist *x, t_symbol *s, int argc, t_atom *argv) +{ + if (x->x_n != argc) { + freebytes(x->x_list, x->x_n * sizeof(t_atom)); + x->x_n = argc; + x->x_list = copybytes(argv, argc * sizeof(t_atom)); + } else memcpy(x->x_list, argv, argc * sizeof(t_atom)); + + outlet_list(x->x_obj.ob_outlet, gensym("list"), x->x_n, x->x_list); +} +static void mypdlist_bang(t_mypdlist *x) +{ outlet_list(x->x_obj.ob_outlet, gensym("list"), x->x_n, x->x_list);} + +static void mypdlist_free(t_mypdlist *x) +{ freebytes(x->x_list, x->x_n * sizeof(t_atom)); } + +static void *mypdlist_new(t_symbol *s, int argc, t_atom *argv) +{ + t_mypdlist *x = (t_mypdlist *)pd_new(mypdlist_class); + + outlet_new(&x->x_obj, 0); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("list"), gensym("lst2")); + + x->x_n = 0; + x->x_list = 0; + + mypdlist_secondlist(x, gensym("list"), argc, argv); + + return (x); +} + +static void mypdlist_setup(void) +{ + mypdlist_class = class_new(gensym("lister"), (t_newmethod)mypdlist_new, + (t_method)mypdlist_free, sizeof(t_mypdlist), 0, A_GIMME, 0); + /* i don't know how to get this work with name=="list" !!! */ + + class_addcreator((t_newmethod)mypdlist_new, gensym("l"), A_GIMME, 0); + + class_addbang (mypdlist_class, mypdlist_bang); + class_addlist (mypdlist_class, mypdlist_list); + class_addmethod (mypdlist_class, (t_method)mypdlist_secondlist, gensym("lst2"), A_GIMME, 0); + + class_sethelpsymbol(mypdlist_class, gensym("zexy/lister")); +} + +/* ------------------------- list2int ------------------------------- */ + +/* cast each float of a list (or anything) to integer */ + +static t_class *list2int_class; + +static void list2int_any(t_mypdlist *x, t_symbol *s, int argc, t_atom *argv) +{ + t_atom *ap; + if (x->x_n != argc) { + freebytes(x->x_list, x->x_n * sizeof(t_atom)); + x->x_n = argc; + x->x_list = copybytes(argv, argc * sizeof(t_atom)); + } else memcpy(x->x_list, argv, argc * sizeof(t_atom)); + ap = x->x_list; + while(argc--){ + if(ap->a_type == A_FLOAT)ap->a_w.w_float=(int)ap->a_w.w_float; + ap++; + } + outlet_anything(x->x_obj.ob_outlet, s, x->x_n, x->x_list); +} +static void list2int_bang(t_mypdlist *x) +{ outlet_bang(x->x_obj.ob_outlet);} +static void list2int_float(t_mypdlist *x, t_float f) +{ outlet_float(x->x_obj.ob_outlet, (int)f);} +static void list2int_symbol(t_mypdlist *x, t_symbol *s) +{ outlet_symbol(x->x_obj.ob_outlet, s);} +static void list2int_pointer(t_mypdlist *x, t_gpointer *p) +{ outlet_pointer(x->x_obj.ob_outlet, p);} + +static void *list2int_new(t_symbol *s, int argc, t_atom *argv) +{ + t_mypdlist *x = (t_mypdlist *)pd_new(list2int_class); + outlet_new(&x->x_obj, 0); + x->x_n = 0; + x->x_list = 0; + return (x); +} + +static void list2int_setup(void) +{ + list2int_class = class_new(gensym("list2int"), (t_newmethod)list2int_new, + (t_method)mypdlist_free, sizeof(t_mypdlist), 0, A_GIMME, 0); + class_addcreator((t_newmethod)list2int_new, gensym("l2i"), A_GIMME, 0); + class_addanything(list2int_class, list2int_any); + class_addlist(list2int_class, list2int_any); + class_addbang(list2int_class, list2int_bang); + class_addfloat(list2int_class, list2int_float); + class_addsymbol(list2int_class, list2int_symbol); + class_addpointer(list2int_class, list2int_pointer); + class_sethelpsymbol(list2int_class, gensym("zexy/list2int")); +} + +/* ------------------------- glue ------------------------------- */ + +/* glue 2 lists together (append) */ + +static t_class *glue_class; + +typedef struct _glue +{ + t_object x_obj; + + t_atom *ap2, *ap; + t_int n1, n2, n; + + t_int changed; +} t_glue; + +static void glue_lst2(t_glue *x, t_symbol *s, int argc, t_atom *argv) +{ + x->changed = 1; + if (x->n2 != argc) { + freebytes(x->ap2, x->n2 * sizeof(t_atom)); + x->n2 = argc; + x->ap2 = copybytes(argv, argc * sizeof(t_atom)); + } else memcpy(x->ap2, argv, argc * sizeof(t_atom)); +} + +static void glue_lst(t_glue *x, t_symbol *s, int argc, t_atom *argv) +{ + if (x->n != x->n2+argc) { + freebytes(x->ap, x->n * sizeof(t_atom)); + x->n1 = argc; + x->n = x->n1+x->n2; + x->ap = (t_atom *)getbytes(sizeof(t_atom)*x->n); + memcpy(x->ap+argc, x->ap2, x->n2*sizeof(t_atom)); + } else if ((x->n1 != argc)||x->changed)memcpy(x->ap+argc, x->ap2, x->n2*sizeof(t_atom)); + + x->n1 = argc; + memcpy(x->ap, argv, x->n1*sizeof(t_atom)); + + x->changed=0; + + outlet_list(x->x_obj.ob_outlet, gensym("list"), x->n, x->ap); +} + +static void glue_bang(t_glue *x) +{ + if (x->changed) { + if (x->n1+x->n2 != x->n){ + t_atom *ap = (t_atom*)getbytes(sizeof(t_atom)*(x->n1+x->n2)); + memcpy(ap, x->ap, x->n1*sizeof(t_atom)); + freebytes(x->ap, sizeof(t_atom)*x->n); + x->ap=ap; + x->n=x->n1+x->n2; + } + memcpy(x->ap+x->n1, x->ap2, x->n2*sizeof(t_atom)); + x->changed=0; + } + + outlet_list(x->x_obj.ob_outlet, gensym("list"), x->n, x->ap); +} + +static void glue_free(t_glue *x) +{ + freebytes(x->ap, sizeof(t_atom)*x->n); + freebytes(x->ap2, sizeof(t_atom)*x->n2); +} + +static void *glue_new(t_symbol *s, int argc, t_atom *argv) +{ + t_glue *x = (t_glue *)pd_new(glue_class); + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("list"), gensym("")); + outlet_new(&x->x_obj, 0); + x->n =x->n2 = 0; + x->ap=x->ap2 = 0; + x->changed = 0; + + if (argc)glue_lst2(x, gensym("list"), argc, argv); + + return (x); +} + +static void glue_setup(void) +{ + glue_class = class_new(gensym("glue"), (t_newmethod)glue_new, + (t_method)glue_free, sizeof(t_glue), 0, A_GIMME, 0); + class_addlist(glue_class, glue_lst); + class_addmethod (glue_class, (t_method)glue_lst2, gensym(""), A_GIMME, 0); + class_addbang(glue_class, glue_bang); + + class_sethelpsymbol(glue_class, gensym("zexy/glue")); +} + +/*skalar multiplikation */ + +static t_class *scalmul_class; +static t_class *scalmul_scal_class; + +typedef struct _scalmul +{ + t_object x_obj; + + t_int n1, n2; + + t_float *buf1, *buf2; + + t_float f; +} t_scalmul; + + +static void scalmul_lst2(t_scalmul *x, t_symbol *s, int argc, t_atom *argv) +{ + t_float *fp; + if (x->n2 != argc) { + freebytes(x->buf2, x->n2 * sizeof(t_float)); + x->n2 = argc; + x->buf2=(t_float *)getbytes(sizeof(t_float)*x->n2); + }; + fp = x->buf2; + while(argc--)*fp++=atom_getfloat(argv++); +} + +static void scalmul_lst(t_scalmul *x, t_symbol *s, int argc, t_atom *argv) +{ + t_float *fp; + t_atom *ap; + int n; + + if (argc){ + if (x->n1 != argc) { + freebytes(x->buf1, x->n1 * sizeof(t_float)); + x->n1 = argc; + x->buf1=(t_float *)getbytes(sizeof(t_float)*x->n1); + }; + fp = x->buf1; + while(argc--)*fp++=atom_getfloat(argv++); + } + + if (x->n1*x->n2==1){ + outlet_float(x->x_obj.ob_outlet, *x->buf1**x->buf2); + return; + } + if (x->n1==1){ + t_atom *a; + int i = x->n2; + t_float f = *x->buf1; + fp = x->buf2; + n = x->n2; + ap = (t_atom *)getbytes(sizeof(t_atom)*n); + a = ap; + while(i--){ + SETFLOAT(a, *fp++*f); + a++; + } + } else if (x->n2==1){ + t_float f = *x->buf2; + t_atom *a; + int i = x->n1; + n = x->n1; + ap = (t_atom *)getbytes(sizeof(t_atom)*n); + a = ap; + fp = x->buf1; + while(i--){ + SETFLOAT(a, *fp++*f); + a++; + } + } else { + t_atom *a; + int i; + t_float *fp2=x->buf2; + fp = x->buf1; + n = x->n1; + if (x->n1!=x->n2){ + post("scalar multiplication: truncating vectors to the same length"); + if (x->n2<x->n1)n=x->n2; + } + ap = (t_atom *)getbytes(sizeof(t_atom)*n); + a = ap; + i=n; + while(i--){ + SETFLOAT(a, *fp++**fp2++); + a++; + } + } + outlet_list(x->x_obj.ob_outlet, gensym("list"), n, ap); + freebytes(ap, sizeof(t_atom)*n); +} +static void scalmul_free(t_scalmul *x) +{ + freebytes(x->buf1, sizeof(t_float)*x->n1); + freebytes(x->buf2, sizeof(t_float)*x->n2); +} + +static void *scalmul_new(t_symbol *s, int argc, t_atom *argv) +{ + t_scalmul *x; + + if (argc-1){ + x = (t_scalmul *)pd_new(scalmul_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("list"), gensym("")); + } else x = (t_scalmul *)pd_new(scalmul_scal_class); + + outlet_new(&x->x_obj, 0); + + x->n1 =1; + x->buf1 =(t_float*)getbytes(sizeof(t_float)); + *x->buf1=0; + + if (argc)scalmul_lst2(x, gensym("list"), argc, argv); + else { + x->n2 =1; + x->buf2 =(t_float*)getbytes(sizeof(t_float)); + *x->buf2=0; + } + + if (argc==1)floatinlet_new(&x->x_obj, x->buf2); + + return (x); +} + +static void scalmul_setup(void) +{ + scalmul_class = class_new(gensym("."), (t_newmethod)scalmul_new, + (t_method)scalmul_free, sizeof(t_scalmul), 0, A_GIMME, 0); + class_addlist(scalmul_class, scalmul_lst); + class_addmethod (scalmul_class, (t_method)scalmul_lst2, gensym(""), A_GIMME, 0); + scalmul_scal_class = class_new(gensym("."), 0, (t_method)scalmul_free, + sizeof(t_scalmul), 0, 0); + class_addlist(scalmul_scal_class, scalmul_lst); + + class_sethelpsymbol(scalmul_class, gensym("zexy/scalarmult")); + class_sethelpsymbol(scalmul_scal_class, gensym("zexy/scalarmult")); +} + + + + +/* -------------- overall setup routine for this file ----------------- */ + +void z_connective_setup(void) +{ + segregate_setup(); + nop_setup(); + mypdlist_setup(); + glue_setup(); + + list2int_setup(); + scalmul_setup(); + + a2l_setup(); + + /* I don't supply HELP - functionality, since this might harm overall-performance here */ +} diff --git a/src/z_coordinates.c b/src/z_coordinates.c new file mode 100644 index 0000000..3efcf8f --- /dev/null +++ b/src/z_coordinates.c @@ -0,0 +1,433 @@ +#include "zexy.h" +#include <math.h> + +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#define atan2f atan2 +#define sqrtf sqrt +#define sinf sin +#define cosf cos +#endif + +/* ----------------------- deg/rad utils ----------------- */ +t_class *deg2rad_class, *rad2deg_class; +typedef struct _deg2rad +{ + t_object x_obj; + t_float factor; +} t_deg2rad; + +/* deg2rad :: degree 2 radian */ + +static void deg2rad_float(t_deg2rad *x, t_float f) +{ + outlet_float(x->x_obj.ob_outlet, x->factor*f); +} + +static void *deg2rad_new(t_floatarg f) +{ + t_deg2rad *x = (t_deg2rad *)pd_new(deg2rad_class); + outlet_new(&x->x_obj, gensym("float")); + x->factor=atan2f(1,1)/45.0; + + return (x); +} + +static void deg2rad_help(void) +{ + post("deg2rad\t:: convert degree 2 radians"); +} + +static void deg2rad_setup(void) +{ + deg2rad_class = class_new(gensym("deg2rad"), (t_newmethod)deg2rad_new, 0, + sizeof(t_deg2rad), 0, A_DEFFLOAT, 0); + + class_addmethod(deg2rad_class, (t_method)deg2rad_help, gensym("help"), 0); + class_addfloat(deg2rad_class, deg2rad_float); + class_sethelpsymbol(deg2rad_class, gensym("zexy/deg2rad")); +} + +/* rad2deg :: radian 2 degree */ +t_class *rad2deg_class; + +static void rad2deg_float(t_deg2rad *x, t_float f) +{ + outlet_float(x->x_obj.ob_outlet, x->factor*f); +} + +static void *rad2deg_new(t_floatarg f) +{ + t_deg2rad *x = (t_deg2rad *)pd_new(rad2deg_class); + outlet_new(&x->x_obj, gensym("float")); + x->factor=45.0/atan2f(1,1); + + return (x); +} + +static void rad2deg_help(void) +{ + post("rad2deg\t:: convert radian 2 degree"); +} + +static void rad2deg_setup(void) +{ + rad2deg_class = class_new(gensym("rad2deg"), (t_newmethod)rad2deg_new, 0, + sizeof(t_deg2rad), 0, A_DEFFLOAT, 0); + + class_addmethod(rad2deg_class, (t_method)rad2deg_help, gensym("help"), 0); + class_addfloat(rad2deg_class, rad2deg_float); + class_sethelpsymbol(rad2deg_class, gensym("zexy/deg2rad")); +} + +/* ------------------------ coordinate transformations ----------------------------- */ + +typedef struct _coordinates +{ + t_object x_obj; + + t_outlet *out[3]; + t_float old_coord[3], new_coord[3]; +} t_coordinates; + +void coordinates_free(t_coordinates *x) +{ +} + +void coord_bang(t_coordinates *x) +{ + int i=3; + while(i--)outlet_float(x->out[i], x->new_coord[i]); +} + + +/* cart2pol :: cartesian to polar coordinates */ +t_class *cart2pol_class; + +static void cart2pol_bang(t_coordinates *x) +{ + t_float X=x->old_coord[0], Y=x->old_coord[1]; + x->new_coord[0]=sqrtf(X*X+Y*Y); /* R */ + x->new_coord[1]=atan2f(Y, X); /* PHI */ + x->new_coord[2]=x->old_coord[2]; /* Z */ + coord_bang(x); +} + +static void cart2pol_float(t_coordinates *x, t_float f) +{ + x->old_coord[0]=f; + cart2pol_bang(x); +} + +static void *cart2pol_new(t_floatarg X, t_floatarg Y, t_floatarg Z) +{ + t_coordinates *x = (t_coordinates *)pd_new(cart2pol_class); + int i=3; + floatinlet_new(&x->x_obj, &x->old_coord[1]); + floatinlet_new(&x->x_obj, &x->old_coord[2]); + while(i--){ + x->out[2-i]=outlet_new(&x->x_obj, gensym("float")); + x->new_coord[i]=0; + } + x->old_coord[0]=X; + x->old_coord[1]=Y; + x->old_coord[2]=Z; + + return (x); +} + +static void cart2pol_help(void) +{ + post("cart2pol\t:: convert cartesian to polar coordinates"); + post("\t\"<x> <y> <z>\": returns <r> <phi> <z>"); +} + +static void cart2pol_setup(void) +{ + cart2pol_class = class_new(gensym("cart2pol"), (t_newmethod)cart2pol_new, (t_method)coordinates_free, + sizeof(t_coordinates), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + + class_addmethod(cart2pol_class, (t_method)cart2pol_help, gensym("help"), 0); + class_addfloat(cart2pol_class, cart2pol_float); + class_addbang(cart2pol_class, cart2pol_bang); + + class_sethelpsymbol(cart2pol_class, gensym("zexy/cart2pol")); +} + + +/* pol2cart :: polar to cartesian coordinates */ +t_class *pol2cart_class; + +static void pol2cart_bang(t_coordinates *x) +{ + x->new_coord[0]=x->old_coord[0]*cosf(x->old_coord[1]); /* X */ + x->new_coord[1]=x->old_coord[0]*sinf(x->old_coord[1]); /* Y */ + x->new_coord[2]=x->old_coord[2]; /* Z */ + coord_bang(x); +} + +static void pol2cart_float(t_coordinates *x, t_float f) +{ + x->old_coord[0]=f; + pol2cart_bang(x); +} + +static void *pol2cart_new(t_floatarg X, t_floatarg Y, t_floatarg Z) +{ + t_coordinates *x = (t_coordinates *)pd_new(pol2cart_class); + int i=3; + floatinlet_new(&x->x_obj, &x->old_coord[1]); + floatinlet_new(&x->x_obj, &x->old_coord[2]); + while(i--){ + x->out[2-i]=outlet_new(&x->x_obj, gensym("float")); + x->new_coord[i]=0; + } + x->old_coord[0]=X; + x->old_coord[1]=Y; + x->old_coord[2]=Z; + return (x); +} + +static void pol2cart_help(void) +{ + post("pol2cart\t:: convert polar to cartesian coordinates"); + post("\t\"<r> <phi> <z>\": returns <x> <x> <z>"); +} + +static void pol2cart_setup(void) +{ + pol2cart_class = class_new(gensym("pol2cart"), (t_newmethod)pol2cart_new, (t_method)coordinates_free, + sizeof(t_coordinates), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + + class_addmethod(pol2cart_class, (t_method)pol2cart_help, gensym("help"), 0); + class_addfloat(pol2cart_class, pol2cart_float); + class_addbang(pol2cart_class, pol2cart_bang); + + class_sethelpsymbol(pol2cart_class, gensym("zexy/pol2cart")); +} + +/* cart2sph :: cartesian to sphar coordinates */ +t_class *cart2sph_class; + +static void cart2sph_bang(t_coordinates *x) +{ + t_float X=x->old_coord[0], Y=x->old_coord[1], Z=x->old_coord[2]; + x->new_coord[0]=sqrtf(X*X+Y*Y+Z*Z); /* R */ + x->new_coord[1]=atan2f(Y, X); /* PHI */ + x->new_coord[2]=atan2f(Z, sqrt(X*X+Y*Y)); /* THETA */ + coord_bang(x); +} + +static void cart2sph_float(t_coordinates *x, t_float f) +{ + x->old_coord[0]=f; + cart2sph_bang(x); +} + +static void *cart2sph_new(t_floatarg X, t_floatarg Y, t_floatarg Z) +{ + t_coordinates *x = (t_coordinates *)pd_new(cart2sph_class); + int i=3; + floatinlet_new(&x->x_obj, &x->old_coord[1]); + floatinlet_new(&x->x_obj, &x->old_coord[2]); + while(i--){ + x->out[2-i]=outlet_new(&x->x_obj, gensym("float")); + x->new_coord[i]=0; + } + x->old_coord[0]=X; + x->old_coord[1]=Y; + x->old_coord[2]=Z; + return (x); +} + +static void cart2sph_help(void) +{ + post("cart2sph\t:: convert cartesian to sphar coordinates"); + post("\t\"<x> <y> <z>\": returns <r> <phi> <theta>"); +} + +static void cart2sph_setup(void) +{ + cart2sph_class = class_new(gensym("cart2sph"), (t_newmethod)cart2sph_new, (t_method)coordinates_free, + sizeof(t_coordinates), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + + class_addmethod(cart2sph_class, (t_method)cart2sph_help, gensym("help"), 0); + class_addfloat(cart2sph_class, cart2sph_float); + class_addbang(cart2sph_class, cart2sph_bang); + + class_sethelpsymbol(cart2sph_class, gensym("zexy/cart2sph")); +} + + +/* sph2cart :: sphar to cartesian coordinates */ +t_class *sph2cart_class; + +static void sph2cart_bang(t_coordinates *x) +{ + x->new_coord[0]=x->old_coord[0]*cosf(x->old_coord[1])*cosf(x->old_coord[2]); /* X */ + x->new_coord[1]=x->old_coord[0]*sinf(x->old_coord[1])*cosf(x->old_coord[2]); /* Y */ + x->new_coord[2]=x->old_coord[0]*sinf(x->old_coord[2]); /* Z */ + coord_bang(x); +} + +static void sph2cart_float(t_coordinates *x, t_float f) +{ + x->old_coord[0]=f; + sph2cart_bang(x); +} + +static void *sph2cart_new(t_floatarg X, t_floatarg Y, t_floatarg Z) +{ + t_coordinates *x = (t_coordinates *)pd_new(sph2cart_class); + int i=3; + floatinlet_new(&x->x_obj, &x->old_coord[1]); + floatinlet_new(&x->x_obj, &x->old_coord[2]); + while(i--){ + x->out[2-i]=outlet_new(&x->x_obj, gensym("float")); + x->new_coord[i]=0; + } + x->old_coord[0]=X; + x->old_coord[1]=Y; + x->old_coord[2]=Z; + return (x); +} + +static void sph2cart_help(void) +{ + post("sph2cart\t:: convert sphar to cartesian coordinates"); + post("\t\"<r> <phi> <theta>\": returns <x> <y> <z>"); +} + +static void sph2cart_setup(void) +{ + sph2cart_class = class_new(gensym("sph2cart"), (t_newmethod)sph2cart_new, (t_method)coordinates_free, + sizeof(t_coordinates), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + + class_addmethod(sph2cart_class, (t_method)sph2cart_help, gensym("help"), 0); + class_addfloat(sph2cart_class, sph2cart_float); + class_addbang(sph2cart_class, sph2cart_bang); + + class_sethelpsymbol(sph2cart_class, gensym("zexy/sph2cart")); +} + + +/* pol2sph :: polesian to sphar coordinates */ +t_class *pol2sph_class; + +static void pol2sph_bang(t_coordinates *x) +{ + t_float r=x->old_coord[0], z=x->old_coord[2]; + x->new_coord[0]=sqrtf(r*r+z*z); /* R */ + x->new_coord[1]=x->old_coord[1]; /* PHI */ + x->new_coord[2]=atan2f(z,r); /* THETA */ + coord_bang(x); +} + +static void pol2sph_float(t_coordinates *x, t_float f) +{ + x->old_coord[0]=f; + pol2sph_bang(x); +} + +static void *pol2sph_new(t_floatarg X, t_floatarg Y, t_floatarg Z) +{ + t_coordinates *x = (t_coordinates *)pd_new(pol2sph_class); + int i=3; + floatinlet_new(&x->x_obj, &x->old_coord[1]); + floatinlet_new(&x->x_obj, &x->old_coord[2]); + while(i--){ + x->out[2-i]=outlet_new(&x->x_obj, gensym("float")); + x->new_coord[i]=0; + } + x->old_coord[0]=X; + x->old_coord[1]=Y; + x->old_coord[2]=Z; + return (x); +} + +static void pol2sph_help(void) +{ + post("pol2sph\t:: convert polar to spheric coordinates"); + post("\t\"<r> <phi> <z>\": returns <r> <phi> <theta>"); +} + +static void pol2sph_setup(void) +{ + pol2sph_class = class_new(gensym("pol2sph"), (t_newmethod)pol2sph_new, (t_method)coordinates_free, + sizeof(t_coordinates), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + + class_addmethod(pol2sph_class, (t_method)pol2sph_help, gensym("help"), 0); + class_addfloat(pol2sph_class, pol2sph_float); + class_addbang(pol2sph_class, pol2sph_bang); + + class_sethelpsymbol(pol2sph_class, gensym("zexy/pol2sph")); +} + + +/* sph2pol :: sphar to polesian coordinates */ +t_class *sph2pol_class; + +static void sph2pol_bang(t_coordinates *x) +{ + x->new_coord[0]=x->old_coord[0]*cosf(x->old_coord[2]); /* R */ + x->new_coord[1]=x->old_coord[1]; /* PHI */ + x->new_coord[2]=x->old_coord[0]*sinf(x->old_coord[2]); /* Z */ + + coord_bang(x); +} + +static void sph2pol_float(t_coordinates *x, t_float f) +{ + x->old_coord[0]=f; + sph2pol_bang(x); +} + +static void *sph2pol_new(t_floatarg X, t_floatarg Y, t_floatarg Z) +{ + t_coordinates *x = (t_coordinates *)pd_new(sph2pol_class); + int i=3; + floatinlet_new(&x->x_obj, &x->old_coord[1]); + floatinlet_new(&x->x_obj, &x->old_coord[2]); + while(i--){ + x->out[2-i]=outlet_new(&x->x_obj, gensym("float")); + x->new_coord[i]=0; + } + x->old_coord[0]=X; + x->old_coord[1]=Y; + x->old_coord[2]=Z; + return (x); +} + +static void sph2pol_help(void) +{ + post("sph2pol\t:: convert spherical to polar coordinates"); + post("\t\"<r> <phi> <theta>\": returns <r> <phi> <z>"); +} + +static void sph2pol_setup(void) +{ + sph2pol_class = class_new(gensym("sph2pol"), (t_newmethod)sph2pol_new, (t_method)coordinates_free, + sizeof(t_coordinates), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + + class_addmethod(sph2pol_class, (t_method)sph2pol_help, gensym("help"), 0); + class_addfloat(sph2pol_class, sph2pol_float); + class_addbang(sph2pol_class, sph2pol_bang); + + class_sethelpsymbol(sph2pol_class, gensym("zexy/sph2pol")); +} + +/* global setup routine */ + +void z_coordinates_setup(void) +{ + cart2pol_setup(); + pol2cart_setup(); + cart2sph_setup(); + sph2cart_setup(); + pol2sph_setup(); + sph2pol_setup(); + + deg2rad_setup(); + rad2deg_setup(); +} diff --git a/src/z_count.c b/src/z_count.c new file mode 100644 index 0000000..103be4f --- /dev/null +++ b/src/z_count.c @@ -0,0 +1,35 @@ +#include "m_pd.h" + +static t_class *prime_class; + +typedef struct _prime { + t_object x_obj; + t_int i_count; +} t_prime; + + +void prime_bug(t_prime *x) +{ + bug("bug!"); +} + +void *prime_new(t_floatarg f) +{ + t_prime *x = (t_prime *)pd_new(prime_class); + + x->i_count=f; + outlet_new(&x->x_obj, &s_float); + + return (void *)x; +} + +void z_prime_setup(void) { + prime_class = class_new(gensym("prime"), + (t_newmethod)prime_new, + 0, sizeof(t_prime), + CLASS_DEFAULT, 0); + + class_addbang(prime_class, prime_bang); + class_addmethod(prime_class, (t_method)prime_bug, gensym("bug"), 0); + class_addmethod(prime_class, (t_method)prime_error, gensym("error"), 0); +} diff --git a/src/z_datetime.c b/src/z_datetime.c new file mode 100644 index 0000000..af93209 --- /dev/null +++ b/src/z_datetime.c @@ -0,0 +1,161 @@ +/* + (c) 1202:forum::für::umläute:2000 + + "time" gets the current time from the system + "date" gets the current date from the system + +*/ + +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +#include "zexy.h" +#include <sys/timeb.h> +#include <time.h> + +/* ----------------------- time --------------------- */ + +static t_class *time_class; + +typedef struct _time +{ + t_object x_obj; + + int GMT; + + t_outlet *x_outlet1; + t_outlet *x_outlet2; + t_outlet *x_outlet3; + t_outlet *x_outlet4; +} t_time; + +static void *time_new(t_symbol *s, int argc, t_atom *argv) +{ + t_time *x = (t_time *)pd_new(time_class); + char buf[5]; + + x->GMT=0; + if (argc) { + atom_string(argv, buf, 5); + if (buf[0]=='G' && buf[1]=='M' && buf[2]=='T') + x->GMT = 1; + } + + x->x_outlet1 = outlet_new(&x->x_obj, &s_float); + x->x_outlet2 = outlet_new(&x->x_obj, &s_float); + x->x_outlet3 = outlet_new(&x->x_obj, &s_float); + x->x_outlet4 = outlet_new(&x->x_obj, &s_float); + + return (x); +} + +static void time_bang(t_time *x) +{ + struct timeb mytime; + struct tm *resolvetime; + + ftime(&mytime); + resolvetime = (x->GMT)?gmtime(&mytime.time):localtime(&mytime.time); + + outlet_float(x->x_outlet4, (t_float)(mytime.millitm)); + outlet_float(x->x_outlet3, (t_float)resolvetime->tm_sec); + outlet_float(x->x_outlet2, (t_float)resolvetime->tm_min); + outlet_float(x->x_outlet1, (t_float)resolvetime->tm_hour); +} + +static void help_time(t_time *x) +{ + post("\n%c time\t\t:: get the current system time", HEARTSYMBOL); + post("\noutputs are\t: hour / minute / sec / msec"); + post("\ncreation\t:: 'time [GMT]': show local time or GMT"); +} + +void time_setup(void) +{ + time_class = class_new(gensym("time"), + (t_newmethod)time_new, 0, + sizeof(t_time), 0, A_GIMME, 0); + + class_addbang(time_class, time_bang); + + class_addmethod(time_class, (t_method)help_time, gensym("help"), 0); + class_sethelpsymbol(time_class, gensym("zexy/time")); +} + +/* ----------------------- date --------------------- */ + +static t_class *date_class; + +typedef struct _date +{ + t_object x_obj; + + int GMT; + + t_outlet *x_outlet1; + t_outlet *x_outlet2; + t_outlet *x_outlet3; +} t_date; + +static void *date_new(t_symbol *s, int argc, t_atom *argv) +{ + t_date *x = (t_date *)pd_new(date_class); + char buf[5]; + + x->GMT=0; + if (argc) { + atom_string(argv, buf, 5); + if (buf[0]=='G' && buf[1]=='M' && buf[2]=='T') + x->GMT = 1; + } + + x->x_outlet1 = outlet_new(&x->x_obj, &s_float); + x->x_outlet2 = outlet_new(&x->x_obj, &s_float); + x->x_outlet3 = outlet_new(&x->x_obj, &s_float); + + return (x); +} + +static void date_bang(t_date *x) +{ + struct timeb mytime; + struct tm *resolvetime; + + ftime(&mytime); + resolvetime=(x->GMT)?gmtime(&mytime.time):localtime(&mytime.time); + + outlet_float(x->x_outlet3, (t_float)resolvetime->tm_mday); + outlet_float(x->x_outlet2, (t_float)resolvetime->tm_mon + 1); + outlet_float(x->x_outlet1, (t_float)resolvetime->tm_year + 1900); +} + +static void help_date(t_date *x) +{ + post("\n%c date\t\t:: get the current system date", HEARTSYMBOL); + post("\noutputs are\t: year / month / day"); + post("\ncreation\t::'date [GMT]': show local date or GMT"); +} + +void date_setup(void) +{ + date_class = class_new(gensym("date"), + (t_newmethod)date_new, 0, + sizeof(t_date), 0, A_GIMME, 0); + + class_addbang(date_class, date_bang); + + class_addmethod(date_class, (t_method)help_date, gensym("help"), 0); + class_sethelpsymbol(date_class, gensym("zexy/date")); +} + + +/* general setup */ + + +void z_datetime_setup(void) +{ + time_setup(); + date_setup(); +} diff --git a/src/z_dfreq.c b/src/z_dfreq.c new file mode 100644 index 0000000..e5074a5 --- /dev/null +++ b/src/z_dfreq.c @@ -0,0 +1,101 @@ +#include <stdio.h> + +#include "zexy.h" + +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +/* ------------------------ dspobj~ ----------------------------- */ + +/* datendefinition */ + +static t_class *dfreq_class; + +typedef struct _dfreq +{ + t_object x_obj; + + t_float freq; /*freqenz variable */ + t_float alt; + float sampcount; + t_float sr; +} t_dfreq; + + +static t_int *dfreq_perform(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_float *out = (t_float *)(w[2]); + int n = (int)(w[3]); + t_dfreq *x = (t_dfreq *) w[4]; + + t_float a = x->alt, c = x->sampcount; + t_float freq = x->freq, sr=x->sr; + + t_float delta_inv; + + while (n--) { + + if( (a * *in) < 0 && (a < *in)){ + + /* interpolate for real zerocross */ + delta_inv = 1./(*in-a); + if(c > 0.0) + freq = sr / ((t_float) c + a*delta_inv); + else + freq = sr; + + c = *in*delta_inv; /*rest of time */ + }; + + a = *in; + in++; + c += 1.0; + *out++ = freq; + } + + x->alt = a; + x->sampcount = c; + x->freq=freq; + + return (w+5); +} + +static void dfreq_dsp(t_dfreq *x, t_signal **sp) +{ + dsp_add(dfreq_perform, 4, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n,x); +} + + + +static void *dfreq_new() +{ + t_dfreq *x = (t_dfreq *)pd_new(dfreq_class); + outlet_new(&x->x_obj, gensym("signal")); + + x->sr = sys_getsr(); + + return (x); +} + +static void helper(void) +{ + post("\n%c dfreq~\t :: pitch-detector that counts zero-crossings", HEARTSYMBOL); + post("\noutputs a frequency estimate as a stream~ that will be updated every zero-X"); + post("\ncreation::\t'dfreq~': that's all"); +} + + +void z_dfreq_setup(void) +{ + dfreq_class = class_new(gensym("dfreq~"), (t_newmethod)dfreq_new, 0, + sizeof(t_dfreq), 0, A_DEFFLOAT, 0); + class_addmethod(dfreq_class, nullfn, gensym("signal"), 0); + class_addmethod(dfreq_class, (t_method)dfreq_dsp, gensym("dsp"), 0); + + class_addmethod(dfreq_class, (t_method)helper, gensym("help"), 0); + class_sethelpsymbol(dfreq_class, gensym("zexy/dfreq~")); +} + diff --git a/src/z_down.c b/src/z_down.c new file mode 100644 index 0000000..9673385 --- /dev/null +++ b/src/z_down.c @@ -0,0 +1,121 @@ +#include <stdio.h> + +#include "zexy.h" + +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +/* down~ : down-code for a signal-object */ + +/* ------------------------ down~ ----------------------------- */ + +static t_class *down_class; + +typedef struct _down +{ + t_object x_obj; + + t_int old_n; + t_int new_n; + + t_int factor; + t_int wantedfactor; + + t_float *buffer; +} t_down; + +static t_int *down_perform_inplace(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_float *out = (t_float *)(w[2]); + t_down *x = (t_down *) w[3]; + + + t_int factor = x->factor; + int n = x->new_n; + t_float *buf = x->buffer; + + while(n--) { + *buf++=*in; + in+=factor; + } + + buf = x->buffer; + n=x->new_n; + + while(n--){ + *out++=*buf++; + } + + return (w+4); +} +static t_int *down_perform(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_float *out = (t_float *)(w[2]); + t_down *x = (t_down *) w[3]; + + t_int factor = x->factor; + int n = x->new_n; + + while(n--) { + *out++=*in; + in+=factor; + } + + return (w+4); +} + +static void down_dsp(t_down *x, t_signal **sp) +{ + t_float f = sp[0]->s_n/(t_float)x->wantedfactor; + + if (f != (int)f) { + int faktor = x->wantedfactor; + while ((f = sp[0]->s_n/(t_float)faktor) != (int)f) faktor--; + + error("bad downsampling factor %d, setting to %d", x->wantedfactor, faktor); + x->factor = faktor; + } else x->factor=x->wantedfactor; + + + freebytes(x->buffer, sizeof(t_float)*x->new_n); + + x->old_n=sp[0]->s_n; + x->new_n=sp[0]->s_n/x->factor; + + sp[0]->s_n=x->new_n; + + x->buffer = getbytes (sizeof(t_float)*x->new_n); + + if (sp[0]->s_vec!=sp[1]->s_vec)dsp_add(down_perform, 3, sp[0]->s_vec, sp[1]->s_vec, x); + else dsp_add(down_perform_inplace, 3, sp[0]->s_vec, sp[1]->s_vec, x); +} + +static void *down_new(t_floatarg f) +{ + t_down *x = (t_down *)pd_new(down_class); + outlet_new(&x->x_obj, gensym("signal")); + + x->wantedfactor=f; + if (x->wantedfactor<1)x->wantedfactor=1; + + return (x); +} +static void down_setup(void) +{ + down_class = class_new(gensym("down~"), (t_newmethod)down_new, 0, + sizeof(t_down), 0, A_DEFFLOAT, 0); + class_addmethod(down_class, nullfn, gensym("signal"), 0); + class_addmethod(down_class, (t_method)down_dsp, gensym("dsp"), 0); + + class_sethelpsymbol(down_class, gensym("zexy/down~")); +} + +void z_down_setup(void) +{ + down_setup(); +} + diff --git a/src/z_drip.c b/src/z_drip.c new file mode 100644 index 0000000..939d547 --- /dev/null +++ b/src/z_drip.c @@ -0,0 +1,185 @@ +/* 3009:forum::für::umläute:2000 */ + +/* -------------------- drip ------------------------------ */ + +/* +unfold a parallel data-structure (*pack*age) into a sequence +like a medical drip +you can adjust the drop-speed in [ms] +*/ + + +#include "zexy.h" + +static t_class *drip_class; + +typedef struct _drip +{ + t_object x_obj; + + t_atom *buffer, *current; + int bufsize; + + t_clock *x_clock; + float deltime; + + int flush; +} t_drip; + + +static void drip_makebuffer(t_drip *x, int n, t_atom *list) +{ + if (x->buffer) { + freebytes(x->buffer, x->bufsize * sizeof(t_atom)); + x->buffer = 0; + x->bufsize = 0; + } + + x->buffer = copybytes(list, n * sizeof(t_atom)); + x->bufsize = n; + x->current = x->buffer; +} + +static void drip_bang(t_drip *x) +{ outlet_bang(x->x_obj.ob_outlet);} + + +static void drip_all(t_drip *x, int argc, t_atom *argv) +{ + while (argc--) { + switch (argv->a_type) { + case A_FLOAT: + outlet_float(x->x_obj.ob_outlet, atom_getfloat(argv)); + break; + case A_SYMBOL: + outlet_symbol(x->x_obj.ob_outlet, atom_getsymbol(argv)); + break; + case A_POINTER: + outlet_pointer(x->x_obj.ob_outlet, argv->a_w.w_gpointer); + break; + default: + outlet_bang(x->x_obj.ob_outlet); + } + argv++; + } +} + +static void drip_tick(t_drip *x) +{ + switch (x->current->a_type) { + case A_FLOAT: + outlet_float(x->x_obj.ob_outlet, atom_getfloat(x->current)); + break; + case A_SYMBOL: + outlet_symbol(x->x_obj.ob_outlet, atom_getsymbol(x->current)); + break; + case A_POINTER: + outlet_pointer(x->x_obj.ob_outlet, x->current->a_w.w_gpointer); + break; + case A_NULL: + outlet_bang(x->x_obj.ob_outlet); + default: + break; + } + + if (x->current + 1 >= x->buffer + x->bufsize) { /* ok, we're done */ + clock_unset(x->x_clock); + x->current = 0; + } else { /* do it again */ + x->current++; + clock_delay(x->x_clock, x->deltime); + } +} + +static void drip_list(t_drip *x, t_symbol *s, int argc, t_atom *argv) +{ + if (x->flush && x->current) { /* do we want to flush */ + drip_all(x, x->bufsize - (x->current - x->buffer), x->current); + } + + if (x->deltime >= 0.f) { /* do we want to SCHEDULE ? */ + /* outlet the first element */ + switch (argv->a_type) { + case (A_FLOAT): + outlet_float(x->x_obj.ob_outlet, atom_getfloat(argv)); + break; + case (A_SYMBOL): + outlet_symbol(x->x_obj.ob_outlet, atom_getsymbol(argv)); + break; + case (A_POINTER): + outlet_pointer(x->x_obj.ob_outlet, argv->a_w.w_gpointer); + break; + default: + outlet_bang(x->x_obj.ob_outlet); + } + /* create a buffer and copy the remaining list into it */ + drip_makebuffer(x, argc-1, argv+1); + /* set the clock and start */ + clock_delay(x->x_clock, x->deltime); + } else { /* UNSCHEDULED */ + drip_all(x, argc, argv); + } +} + +static void drip_anything(t_drip *x, t_symbol *s, int argc, t_atom *argv) +{ + if (x->flush && x->current) { /* do we want to flush */ + drip_all(x, x->bufsize - (x->current - x->buffer), x->current); + } + + /* outlet the first element */ + outlet_symbol(x->x_obj.ob_outlet, s); + + if (x->deltime >= 0.f) { /* do we want to SCHEDULE ? */ + /* create a buffer and copy the remaining list into it */ + drip_makebuffer(x, argc, argv); + /* set the clock and start */ + clock_delay(x->x_clock, x->deltime); + } else { /* UNSCHEDULED */ + drip_all(x, argc, argv); + } +} + +static void drip_free(t_drip *x) +{ + clock_free(x->x_clock); + + if (x->buffer) { + freebytes(x->buffer, x->bufsize * sizeof(t_atom)); + x->buffer = 0; + x->bufsize = 0; + } +} + + +static void *drip_new(t_symbol *s, int argc, t_atom *argv) +{ + t_drip *x = (t_drip *)pd_new(drip_class); + + if (argc>1) x->flush = 1; + else x->flush = 0; + + if (argc) x->deltime = atom_getfloat(argv); + else x->deltime = -1.f; + if (x->deltime < 0.f) x->deltime = -1.0; + + x->x_clock = clock_new(x, (t_method)drip_tick); + floatinlet_new(&x->x_obj, &x->deltime); + + outlet_new(&x->x_obj, 0); + return (x); +} + +void z_drip_setup(void) +{ + drip_class = class_new(gensym("drip"), (t_newmethod)drip_new, + (t_method)drip_free, sizeof(t_drip), 0 ,A_GIMME, 0); + + class_addcreator((t_newmethod)drip_new, gensym("unfold"), A_GIMME, 0); + /* for historical reasons */ + + class_addbang (drip_class, drip_bang); + class_addlist (drip_class, drip_list); + class_addanything(drip_class, drip_anything); + class_sethelpsymbol(drip_class, gensym("zexy/drip")); +} diff --git a/src/z_index.c b/src/z_index.c new file mode 100644 index 0000000..a2a96eb --- /dev/null +++ b/src/z_index.c @@ -0,0 +1,203 @@ +/* + (c) 2005:forum::für::umläute:2000 + + "index" simulates an associative index :: that is : convert a symbol to an index + +*/ + +#include "zexy.h" + +#include <string.h> +#include <stdio.h> + +#define MAXKEYLEN 16 + +/* ----------------------- index --------------------- */ + +static t_class *index_class; + +typedef struct _index +{ + t_object x_obj; + + int entries, maxentries; + int auto_mode; /* 1--add if key doesn't already exist; 0--do not add; */ + + char **names; +} t_index; + +static int find_last(char **names, int maxentries) +{ /* returns the index of the last entry (0..(maxentries-1)) */ + while (maxentries--) if (names[maxentries]) return maxentries; + return 0; +} + +static int find_item(const char *key, char **names, int maxentries) +{ /* returns index (0..[maxentries-1?]) on success; -1 if the item could not be found */ + int i=-1; + int max = find_last(names, maxentries); + + while (++i<=max) + if (names[i]) + if (!strcmp(key, names[i])) return i; + + return -1; +} + +static int find_free(char **names, int maxentries) +{ + int i=0; + + while (i<maxentries) { + if (!names[i]) return i; + i++; + } + return -1; +} + +static void index_float(t_index *x, t_float findex) +{ + int index = (int)findex; + if ((index > 0) && (index <= x->maxentries) && (x->names[index-1])) post("index[%d] = %s", index, x->names[index-1]); +} + +static void index_auto(t_index *x, t_float automod) +{ + x->auto_mode = !(!automod); +} + + +static void index_add(t_index *x, t_symbol *s) +{ + int newentry; + int ok = 0; + + if (! (find_item(s->s_name, x->names, x->maxentries)+1) ) { + if ( x->entries < x->maxentries ) { + newentry=find_free(x->names, x->maxentries); + if (newentry + 1) { + char *buf = (char *)getbytes(sizeof(char) * MAXKEYLEN); + x->entries++; + strcpy(buf, s->s_name); + x->names[newentry]=buf; + + ok=1; + + outlet_float(x->x_obj.ob_outlet, (t_float)newentry+1); + + } else post("index :: couldn't find any place for new entry"); + } else post("index :: max number of elements (%d) reached !", x->maxentries); + } else post("index :: element already exists"); + + if (!ok) outlet_float(x->x_obj.ob_outlet, -1.f); +} + +static void index_delete(t_index *x, t_symbol *s) +{ + int element; + t_float r = -1.f; + + if ( (element = find_item(s->s_name,x->names, x->maxentries))+1 ) { + freebytes(x->names[element], sizeof(char) * MAXKEYLEN); + x->names[element]=0; + r = 0.f; + x->entries--; + } else post("index :: couldn't find element"); + + outlet_float(x->x_obj.ob_outlet, r); +} + +static void index_reset(t_index *x) +{ + int i=x->maxentries; + + while (i--) + if (x->names[i]) { + freebytes(x->names[i], sizeof(char) * MAXKEYLEN); + x->names[i]=0; + } + + x->entries=0; + + outlet_float(x->x_obj.ob_outlet, 0.f); +} + +static void index_symbol(t_index *x, t_symbol *s) +{ + int element; + if ( (element = find_item(s->s_name, x->names, x->maxentries)+1) ) + outlet_float(x->x_obj.ob_outlet, (t_float)element); + else if (x->auto_mode) + index_add(x, s); + else outlet_float(x->x_obj.ob_outlet, 0.f); +} + +static void *index_new(t_symbol *s, int argc, t_atom *argv) +{ + t_index *x = (t_index *)pd_new(index_class); + char** buf; + + int maxentries = 0, automod=0; + int i; + + if (argc--) { + maxentries = (int)atom_getfloat(argv++); + if (argc) automod = (int)atom_getfloat(argv++); + } + + if (!maxentries) maxentries=128; + + buf = (char **)getbytes(sizeof(char *) * maxentries); + + i = maxentries; + while (i--) buf[i]=0; + + x->entries = 0; + x->maxentries = maxentries; + x->names = buf; + x->auto_mode = !(!automod); + + outlet_new(&x->x_obj, &s_float); + + return (x); +} + +static void index_free(t_index *x) +{ + index_reset(x); + freebytes(x->names, sizeof(char *) * x->maxentries); +} + + +static void helper(t_index *x) +{ + post("\n%c index :: index symbols to indices", HEARTSYMBOL); + post("<symbol>\t : look up the <symbol> in the index and return it's index\n" + "'add <symbol>'\t: add a new symbol to the index\n" + "'delete <symbol>' : delete a symbol from the index\n" + "'reset'\t\t : delete the whole index\n" + "'auto <1/0>\t : if auto is 1 and a yet unknown symbol is looked up it is\n\t\t\t automatically added to the index\n" + "'help'\t\t : view this" + "\noutlet : <n>\t : index of the <symbol>"); + post("\ncreation:\"index [<maxelements> [<auto>]]\": creates a <maxelements> sized index"); +} + +void z_index_setup(void) +{ + index_class = class_new(gensym("index"), + (t_newmethod)index_new, (t_method)index_free, + sizeof(t_index), 0, A_GIMME, 0); + + class_addsymbol(index_class, index_symbol); + + class_addmethod(index_class, (t_method)index_reset, gensym("reset"), 0); + class_addmethod(index_class, (t_method)index_delete, gensym("delete"), A_SYMBOL, 0); + class_addmethod(index_class, (t_method)index_add, gensym("add"), A_SYMBOL, 0); + + class_addmethod(index_class, (t_method)index_auto, gensym("auto"), A_FLOAT, 0); + + class_addfloat(index_class, (t_method)index_float); + + class_addmethod(index_class, (t_method)helper, gensym("help"), 0); + class_sethelpsymbol(index_class, gensym("zexy/index")); +} diff --git a/src/z_limiter.c b/src/z_limiter.c new file mode 100644 index 0000000..9f18efe --- /dev/null +++ b/src/z_limiter.c @@ -0,0 +1,707 @@ +/* + --------------------------------- limiter/compressor --------------------------------- + + for details on how it works watch out for "http://iem.kug.ac.at/~zmoelnig/pd" + ...and search for "limiter" + + mail2me4more!n4m8ion : zmoelnig@iem.kug.ac.at +*/ + +/* + this is a limiter/compressor-object + the limiter is based on Falkner's thesis + "Entwicklung eines digitalen Stereo-limiters mit Hilfe des Signalprozessors DSP56001" pp.14 + + 2108:forum::für::umläute:1999 all rights reserved and no warranties... + + see GNU-license for details (shipped with pd) +*/ + +#define LIMIT0 0 +#define LIMIT1 1 +#define COMPRESS 2 + +#include "zexy.h" +#include <math.h> + +#ifdef NT +#define fabsf fabs +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +#define LN2 .69314718056 +#define SINC1 .822462987 +#define SINC2 .404460777 +#define SINC3 -.188874003 +#define SINC4 -.143239449 +#define SINC5 .087796546 +#define SINC6 .06917082 +#define SINC7 -.041349667 +#define SINC8 -.030578954 +#define SINC9 .013226276 + +#define BUFSIZE 128 +#define XTRASAMPS 9 +#define TABLESIZE 512 /* compressor table */ + +/* ------------------------------------------------------------------------------------ */ +// first define the structs... + +static t_class *limiter_class; + +typedef struct _limctl +{ // variables changed by user + float limit, hold_samples, change_of_amplification; +} t_limctl; + +typedef struct _cmpctl +{ + float treshold, ratio; // uclimit is the very same is the limiter1-limit (decalculated relative to our treshold) + float uclimit, climit_inverse; // climit == compressed limit (uclimit == uncompressed limit) + + float limiter_limit; // start limiting (stop compressing); == tresh/limit; + + float treshdB, oneminusratio; +} t_cmpctl; + +typedef struct _inbuf +{ + float* ringbuf; + int buf_position; +} t_inbuf; + +typedef struct _limiter +{ + t_object x_obj; + + int number_of_inlets, s_n; + + // variables changed by process + + float amplification; + float samples_left, still_left; + + int mode; + + t_limctl *val1, *val2; + t_cmpctl *cmp; + + // note : limit is not the same for val1 & val2 : + // at val1 it is the limit of the INPUT_VALUE + // at val2 it is the limit for the AMPLIFICATION (in fact it is abs_limit1/abs_limit2) + + t_inbuf* in; + int buf_size; + +} t_limiter; + +/* ------------------------------------------------------------------------------------ */ +// then do the message - thing + +// do the user settings + +// calcs +static t_float calc_holdsamples(t_float htime, int buf) +{ // hold_time must be greater than buffer_time to make sure that any peak_sample is amplified with its own factor + float min_hold = buf / sys_getsr(); + return (0.001 * sys_getsr() * ((htime > min_hold)?htime:((min_hold > 50)?min_hold:50))); +} + +static t_float calc_coa(t_float hlife) +{ + return (exp(LN2 * 1000 / (((hlife > 0)?hlife:15) * sys_getsr()))); +} + +static void set_uclimit(t_limiter *x) +{ + t_cmpctl *c = x->cmp; + t_float limit = x->val1->limit, limitdB = rmstodb(limit), ratio = c->ratio, tresh = c->treshold, treshdB = rmstodb(tresh); + + c->climit_inverse = limit / tresh; + c->uclimit = tresh / dbtorms(treshdB+(limitdB - treshdB)/ratio); + + c->treshdB = treshdB; + c->oneminusratio = 1. - ratio; +} + +// settings + +static void set_treshold(t_limiter *x, float treshold) +{ + t_cmpctl *c = x->cmp; + float tresh = dbtorms (treshold); + if (tresh > x->val1->limit) tresh = x->val1->limit; + + c->treshold = tresh; + + set_uclimit(x); +} + +static void set_ratio(t_limiter *x, float ratio) +{ + if (ratio < 0) ratio = 1; + x->cmp->ratio = ratio; + + set_uclimit(x); +} + +static void set_mode(t_limiter *x, float mode) +{ + int modus = mode; + + switch (modus) { + case LIMIT0: + x->mode = LIMIT0; + break; + case LIMIT1: + x->mode = LIMIT1; + break; + case COMPRESS: + x->mode = COMPRESS; + break; + default: + x->mode = LIMIT0; + break; + } + post("mode set to %d", x->mode); +} + +static void set_LIMIT(t_limiter *x) +{ + set_mode(x, LIMIT0); +} + +static void set_CRACK(t_limiter *x) +{ + set_mode(x, LIMIT1); +} + +static void set_COMPRESS(t_limiter *x) +{ + set_mode(x, COMPRESS); +} + +static void set_bufsize(t_limiter *x, float size) +{ // this is really unneeded...and for historical reasons only + if (size < BUFSIZE) size = BUFSIZE; + x->buf_size = size + XTRASAMPS; +} + +static void set_limit(t_limiter *x, t_floatarg limit) +{ + if (limit < 0.00001) limit = 100; + x->val1->limit = dbtorms(limit); + + if (x->val1->limit < x->cmp->treshold) x->cmp->treshold = x->val1->limit; + set_uclimit(x); +} + +static void set_limits(t_limiter *x, t_floatarg limit1, t_floatarg limit2) +{ + t_float lim1, lim2; + + if (limit1 < 0.00001) limit1 = 100; + + lim1 = dbtorms(limit1); + lim2 = dbtorms(limit2); + + if (lim2 < lim1) + { + lim2 = 2*lim1; // this is to prevent lim2 (which should trigger the FAST regulation) + x->mode = 0; // to underrun the SLOW regulation; this would cause distortion + } + + x->val1->limit = lim1; + x->val2->limit = lim1/lim2; + + if (lim1 < x->cmp->treshold) x->cmp->treshold = lim1; + set_uclimit(x); +} + +static void set1(t_limiter *x, t_floatarg limit, t_floatarg hold, t_floatarg release) +{ + t_float lim = dbtorms(limit); + + x->val1->limit = (lim > 0)?lim:1; + x->val1->hold_samples = calc_holdsamples(hold, x->buf_size); + x->val1->change_of_amplification = calc_coa(release); + + if (lim < x->cmp->treshold) x->cmp->treshold = lim; + set_uclimit(x); +} + + +static void set2(t_limiter *x, t_floatarg limit, t_floatarg hold, t_floatarg release) +{ + t_float lim = dbtorms(limit); + x->val2->limit = (lim > x->val1->limit)?(x->val1->limit/lim):.5; + x->val2->hold_samples = calc_holdsamples(hold, x->buf_size); + x->val2->change_of_amplification = calc_coa(release); +} + + + +static void set_compressor(t_limiter *x, t_floatarg limit, t_floatarg treshold, t_floatarg ratio) +{ + t_cmpctl *c = x->cmp; + t_float lim = dbtorms(limit); + t_float tresh = dbtorms(treshold); + + if ((limit == 0) && (treshold = 0) && (ratio = 0)) {set_mode(x, COMPRESS); return;} + + if (tresh > lim) tresh = lim; + if (ratio < 0.) ratio = 1.; + + c->ratio = ratio; + x->val1->limit = lim; + c->treshold = tresh; + set_uclimit(x); + + set_mode(x, COMPRESS); +} + +static void reset(t_limiter *x) +{ + x->amplification = 1.; +} + +// verbose +static void status(t_limiter *x) +{ + t_limctl *v1 = x->val1; + t_limctl *v2 = x->val2; + t_cmpctl *c = x->cmp; + + t_float sr = sys_getsr() / 1000.; + + switch (x->mode) { + case LIMIT1: + post("%d-channel crack-limiter @ %fkHz\n" + "\noutput-limit\t= %fdB\nhold1\t\t= %fms\nrelease1\t= %fms\ncrack-limit\t= %fdB\nhold2\t\t= %fms\nrelease2\t= %fms\n" + "\namplify\t\t= %fdB\n", + x->number_of_inlets, sr, + rmstodb(v1->limit), (v1->hold_samples) / sr, LN2 / (log(v1->change_of_amplification) * sr), + rmstodb(v1->limit / v2->limit), (v2->hold_samples) / sr, LN2 / (log(v2->change_of_amplification) * sr), + x->amplification); + break; + case LIMIT0: + post("%d-channel limiter @ %fkHz\n" + "\noutput-limit\t= %fdB\nhold\t\t= %fms\nrelease\t\t= %fms\n" + "\namplify\t\t= %fdB\n", + x->number_of_inlets, sr, + rmstodb(v1->limit), (v1->hold_samples) / sr, LN2 / (log(v1->change_of_amplification) * sr), + rmstodb(x->amplification)); + break; + case COMPRESS: + post("%d-channel compressor @ %fkHz\n" + "\noutput-limit\t= %fdB\ntreshold\t= %fdB\ninput-limit\t= %f\nratio\t\t= 1:%f\n" + "\nhold\t\t= %fms\nrelease\t\t= %fms\n" + "\namplify\t\t= %fdB\n", + x->number_of_inlets, sr, + rmstodb(c->treshold * c->climit_inverse), rmstodb(c->treshold), rmstodb(c->treshold / c->uclimit), 1./c->ratio, + (v1->hold_samples) / sr, LN2 / (log(v1->change_of_amplification) * sr), + rmstodb(x->amplification)); + } +} + +static void helper(t_limiter *x) +{ + post("\n\n%c %d-channel limiter-object: mode %d", HEARTSYMBOL, x->number_of_inlets, x->mode); + poststring("\n'mode <mode>'\t\t\t: (0_limiter, 1_crack-limiter, 2_compressor)"); + poststring("\n'LIMIT'\t\t\t\t: set to LIMITer"); + poststring("\n'CRACK'\t\t\t\t: set to CRACK-limiter"); + poststring("\n'COMPRESS'\t\t\t\t: set to COMPRESSor"); + + switch (x->mode) { + case LIMIT0: + poststring("\n'limit <limit>'\t\t\t: set limit (in dB)" + "\n'set <limit><htime><rtime>'\t: set limiter"); + break; + case LIMIT1: + poststring("\n'limits <limit1><limit2>'\t: set limits (in dB)" + "\n'set <limit1><htime1><rtime1>'\t: set limiter 1" + "\n'set2 <limit2><htime2><rtime2>'\t: set crack-limiter"); + break; + case COMPRESS: + poststring("\n'ratio <compressratio>'\t\t: set compressratio (´0.5´ instead of ´1:2´)" + "\n'treshold <treshold>'\t\t: set treshold of the compressor" + "\n'compress <limit><treshold><ratio>'\t: set compressor" + "\n..........note that <limit> is the same for COMPRESSOR and LIMITER.........."); + break; + default: + break; + } + poststring("\n'print'\t\t\t\t: view actual settings" + "\n'help'\t\t\t\t: view this\n"); + poststring("\ncreating arguments are :\n" + "\"limiter~ [<in1> [<in2> [<in3> [...]]]]\": <in*> may be anything\n"); + endpost(); +} + + +/* ------------------------------------------------------------------------------------ */ +// now do the dsp - thing // +/* ------------------------------------------------------------------------------------ */ + +static t_int *oversampling_maxima(t_int *w) +{ + t_limiter *x = (t_limiter *)w[1]; + t_inbuf *buf = (t_inbuf *)w[2]; + t_float *in = (t_float *)w[3]; + t_float *out = (t_float *)w[4]; + + int n = x->s_n; + int bufsize = x->buf_size; + + int i = buf->buf_position; + + t_float *vp = buf->ringbuf, *ep = vp + bufsize, *bp = vp + XTRASAMPS + i; + + i += n; + + while (n--) + { + t_float os1, os2, max; + t_float last4, last3, last2, last1, sinccurrent, current, next1, next2, next3, next4; + + if (bp == ep) + { + vp[0] = bp[-9]; + vp[1] = bp[-8]; + vp[2] = bp[-7]; + vp[3] = bp[-6]; + vp[4] = bp[-5]; + vp[5] = bp[-4]; + vp[6] = bp[-3]; + vp[7] = bp[-2]; + vp[8] = bp[-1]; + + bp = vp + XTRASAMPS; + i -= bufsize - XTRASAMPS; + } + + os1= fabsf(SINC8 * (last4 = bp[-8]) + + SINC6 * (last3 = bp[-7]) + + SINC4 * (last2 = bp[-6]) + + SINC2 * (last1 = bp[-5]) + + (sinccurrent = SINC1 * (current = bp[-4])) + + SINC3 * (next1 = bp[-3]) + + SINC5 * (next2 = bp[-2]) + + SINC7 * (next3 = bp[-1]) + + SINC9 * (next4 = bp[0])); + + os2= fabsf(SINC8 * next4 + + SINC4 * next3 + + SINC6 * next2 + + SINC2 * next1 + + sinccurrent + + SINC3 * last1 + + SINC5 * last2 + + SINC7 * last3 + + SINC9 * last4); + + max = fabsf(current); + + if (max < os1) + { + max = os1; + } + if (max < os2) + { + max = os2; + } + + *bp++ = *in++; + if (*out++ < max) *(out-1) = max; + } + buf->buf_position = i; + + return (w+5); +} + + +static t_int *limiter_perform(t_int *w) +{ + t_limiter *x=(t_limiter *)w[1]; + int n = x->s_n; + + t_float *in = (t_float *)w[2]; + t_float *out= (t_float *)w[3]; + + t_limctl *v1 = (t_limctl *)(x->val1); + t_limctl *v2 = (t_limctl *)(x->val2); + t_cmpctl *c = (t_cmpctl *)(x->cmp); + + // now let's make things a little bit faster + + // these must not be changed by process + const t_float limit = v1->limit; + const t_float holdlong = v1->hold_samples; + const t_float coa_long = v1->change_of_amplification; + + const t_float alimit = v2->limit; + const t_float holdshort = v2->hold_samples; + const t_float coa_short = v2->change_of_amplification; + + t_float tresh = c->treshold; + t_float uclimit = c->uclimit; + t_float climit_inv = c->climit_inverse; + + t_float oneminusratio = c->oneminusratio; + + // these will be changed by process + t_float amp = x->amplification; + t_float samplesleft = x->samples_left; + t_float stillleft = x->still_left; + + // an intern variable... + t_float max_val; + + switch (x->mode) { + case LIMIT0: + while (n--) + { + max_val = *in; + + // the MAIN routine for the 1-treshold-limiter + + if ((max_val * amp) > limit) + { + amp = limit / max_val; + samplesleft = holdlong; + } else + { + if (samplesleft > 0) + { + samplesleft--; + } else + { + if ((amp *= coa_long) > 1) amp = 1; + } + } + + *out++ = amp; + *in++ = 0; + } + break; + case LIMIT1: + while (n--) + { + max_val = *in; + // the main routine 2 + + if ((max_val * amp) > limit) + { + samplesleft = ((amp = (limit / max_val)) < alimit)?holdshort:holdlong; + stillleft = holdlong; + } else + { + if (samplesleft > 0) + { + samplesleft--; + stillleft--; + } else + { + if (amp < alimit) + { + if ((amp *= coa_short) > 1) amp = 1; + } else + { + if (stillleft > 0) + { + samplesleft = stillleft; + } else + { + if ((amp *= coa_long) > 1) amp = 1; + } + } + } + } + *out++ = amp; + *in++ = 0; + } + x->still_left = stillleft; + break; + case COMPRESS: + while (n--) + { + max_val = *in; + + // the MAIN routine for the compressor (very similar to the 1-treshold-limiter) + + if (max_val * amp > tresh) { + amp = tresh / max_val; + samplesleft = holdlong; + } else + if (samplesleft > 0) samplesleft--; + else if ((amp *= coa_long) > 1) amp = 1; + + if (amp < 1.) + if (amp > uclimit) // amp is still UnCompressed uclimit==limitIN/tresh; + *out++ = pow(amp, oneminusratio); + else *out++ = amp * climit_inv; // amp must fit for limiting : amp(new) = limit/maxval; = amp(old)*limitOUT/tresh; + else *out++ = 1.; + + *in++ = 0.; + } + break; + default: + while (n--) *out++ = *in++ = 0.; + break; + } + + // now return the goodies + x->amplification = amp; + x->samples_left = samplesleft; + + return (w+4); +} + + +#if 0 +static t_int *route_through(t_int *w) +{ + t_float *in = (t_float *)w[1]; + t_float *out = (t_float *)w[2]; + int n = (int)w[3]; + + while(n--) + { + *out++ = *in; + *in++ = 0; + } + + return (w+4); +} +#endif + +void limiter_dsp(t_limiter *x, t_signal **sp) +{ + int i = 0; + t_float* sig_buf = (t_float *)getbytes(sizeof(t_float) * sp[0]->s_n); + + x->s_n = sp[0]->s_n; + + if (x->amplification == 0) x->amplification = 0.0000001; + + if (x->val2->limit >= 1) x->mode = 0; + + while (i < x->number_of_inlets) + { + dsp_add(oversampling_maxima, 4, x, &(x->in[i]), sp[i]->s_vec, sig_buf); + i++; + } + + dsp_add(limiter_perform, 3, x, sig_buf, sp[i]->s_vec); +} + + + +/* ------------------------------------------------------------------------------------ */ +// finally do the creation - things + +void *limiter_new(t_symbol *s, int argc, t_atom *argv) +{ + t_limiter *x = (t_limiter *)pd_new(limiter_class); + + int i = 0; + + if (argc) set_bufsize(x, atom_getfloat(argv)); + else + { + argc = 1; + set_bufsize(x, 0); + } + + if (argc > 64) argc=64; + if (argc == 0) argc=1; + + x->number_of_inlets = argc--; + + while (argc--) + { + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + } + + outlet_new(&x->x_obj, &s_signal); + + x->in = (t_inbuf*)getbytes(sizeof(t_inbuf) * x->number_of_inlets); + while (i < x->number_of_inlets) + { + int n; + t_float* buf = (float *)getbytes(sizeof(float) * x->buf_size); + x->in[i].ringbuf = buf; + x->in[i].buf_position = 0; + for (n = 0; n < x->buf_size; n++) x->in[i].ringbuf[n] = 0.; + i++; + } + + x->val1 = (t_limctl *)getbytes(sizeof(t_limctl)); + x->val2 = (t_limctl *)getbytes(sizeof(t_limctl)); + x->cmp = (t_cmpctl *)getbytes(sizeof(t_cmpctl)); + + x->cmp->ratio = 1.; + x->cmp->treshold = 1; + + set1(x, 100, 30, 139); + set2(x, 110, 5, 14.2); + + x->amplification= 1; + x->samples_left = x->still_left = x->mode = 0; + + return (x); +} + +void limiter_free(t_limiter *x) +{ + int i=0; + + freebytes(x->val1, sizeof(t_limctl)); + freebytes(x->val2, sizeof(t_limctl)); + freebytes(x->cmp , sizeof(t_cmpctl)); + + while (i < x->number_of_inlets) freebytes(x->in[i++].ringbuf, x->buf_size * sizeof(t_float)); + + freebytes(x->in, x->number_of_inlets * sizeof(t_inbuf)); +} + + + +/* ------------------------------------------------------------------------------------ */ +/* ------------------------------------------------------------------------------------ */ + + + +void z_limiter_setup(void) +{ + limiter_class = class_new(gensym("limiter~"), (t_newmethod)limiter_new, (t_method)limiter_free, + sizeof(t_limiter), 0, A_GIMME, 0); + + class_addmethod(limiter_class, nullfn, gensym("signal"), 0); + class_addmethod(limiter_class, (t_method)limiter_dsp, gensym("dsp"), 0); + + class_addmethod(limiter_class, (t_method)helper, gensym("help"), 0); + class_addmethod(limiter_class, (t_method)status, gensym("print"), 0); + class_sethelpsymbol(limiter_class, gensym("zexy/limiter~")); + + class_addmethod(limiter_class, (t_method)set_mode, gensym("mode"), A_FLOAT, 0); + class_addmethod(limiter_class, (t_method)set_LIMIT, gensym("LIMIT"), 0); + class_addmethod(limiter_class, (t_method)set_CRACK, gensym("CRACK"), 0); + class_addmethod(limiter_class, (t_method)set_COMPRESS, gensym("COMPRESS"), 0); + + + class_addmethod(limiter_class, (t_method)set_treshold, gensym("tresh"), A_FLOAT, 0); + class_addmethod(limiter_class, (t_method)set_treshold, gensym("treshold"), A_FLOAT, 0); + class_addmethod(limiter_class, (t_method)set_ratio, gensym("ratio"), A_FLOAT, 0); + class_addmethod(limiter_class, (t_method)set1, gensym("set"), A_FLOAT, A_FLOAT, A_FLOAT, 0); + class_addmethod(limiter_class, (t_method)set2, gensym("set2"), A_FLOAT, A_FLOAT, A_FLOAT, 0); + class_addmethod(limiter_class, (t_method)set_compressor,gensym("compress"), A_FLOAT, A_FLOAT, A_FLOAT, 0); + + class_addmethod(limiter_class, (t_method)set_limits, gensym("limits"), A_FLOAT, A_FLOAT, 0); + class_addmethod(limiter_class, (t_method)set_limit, gensym("limit"), A_FLOAT, 0); + class_addfloat (limiter_class, set_limit); + + class_addmethod(limiter_class, (t_method)reset, gensym("reset"), 0); + +} diff --git a/src/z_lp.c b/src/z_lp.c new file mode 100644 index 0000000..c9dba09 --- /dev/null +++ b/src/z_lp.c @@ -0,0 +1,132 @@ + /* + (c) 2005:forum::für::umläute:2000 + + write to the parallel port + extended to write to any port (if we do have permissions) + +*/ +#define BASE0 0x3bc +#define BASE1 0x378 +#define BASE2 0x278 + +#define MODE_IOPERM 1 +#define MODE_IOPL 0 + +#include "zexy.h" + +#include <sys/io.h> +#include <stdlib.h> + +/* ----------------------- lp --------------------- */ + +static int count_iopl = 0; + +static t_class *lp_class; + +typedef struct _lp +{ + t_object x_obj; + + unsigned long port; + + int mode; // MODE_IOPERM, MODE_IOPL +} t_lp; + +static void lp_float(t_lp *x, t_floatarg f) +{ + if (x->port) { + unsigned char b = f; + outb(b, x->port); + } +} + +static void *lp_new(t_symbol *s, int argc, t_atom *argv) +{ + t_lp *x = (t_lp *)pd_new(lp_class); + + x->port = 0; + + if ((argc==0)||(argv->a_type==A_FLOAT)) { + /* FLOAT specifies a parallel port */ + switch ((int)((argc)?atom_getfloat(argv):0)) { + case 0: + x->port = BASE0; + break; + case 1: + x->port = BASE1; + break; + case 2: + x->port = BASE2; + break; + default: + error("lp : only lp0, lp1 and lp2 are accessible"); + x->port = 0; + return (x); + } + } else { + /* SYMBOL might be a file or a hex port-number; + we ignore the file (device) case by now; + LATER think about this + */ + x->port=strtol(atom_getsymbol(argv)->s_name, 0, 16); + } + + if (!x->port || x->port>65535){ + post("lp : bad port %x", x->port); + x->port = 0; + return (x); + } + + if (x->port && x->port < 0x400){ + if (ioperm(x->port, 8, 1)) { + error("lp : couldn't get write permissions"); + x->port = 0; + return (x); + } + x->mode = MODE_IOPERM; + } else { + if (iopl(3)){ + error("lp : couldn't get write permissions"); + x->port = 0; + return (x); + } + x->mode=MODE_IOPL; + count_iopl++; + post("iopl.............................%d", count_iopl); + } + + post("connected to port %x in mode '%s'", x->port, (x->mode==MODE_IOPL)?"iopl":"ioperm"); + if (x->mode==MODE_IOPL)post("warning: this might seriously damage your pc..."); + + return (x); +} + +static void lp_free(t_lp *x) +{ + if (x->port) { + if (x->mode==MODE_IOPERM && ioperm(x->port, 8, 0)) error("lp: couldn't clean up device"); + else if (x->mode==MODE_IOPL && (!--count_iopl) && iopl(0)) + error("lp: couldn't clean up device"); + } +} + + +static void helper(t_lp *x) +{ + post("\n%c lp :: direct access to the parallel port", HEARTSYMBOL); + post("<byte>\t: write byte to the parallel-port"); + post("\ncreation:\t\"lp [<port>]\": connect to parallel port <port> (0..2)"); + post("\t\t\"lp <portaddr>\": connect to port @ <portaddr> (hex)"); +} + +void z_lp_setup(void) +{ + lp_class = class_new(gensym("lp"), + (t_newmethod)lp_new, (t_method)lp_free, + sizeof(t_lp), 0, A_GIMME, 0); + + class_addfloat(lp_class, (t_method)lp_float); + + class_addmethod(lp_class, (t_method)helper, gensym("help"), 0); + class_sethelpsymbol(lp_class, gensym("zexy/lp")); +} diff --git a/src/z_makesymbol.c b/src/z_makesymbol.c new file mode 100644 index 0000000..89ba95f --- /dev/null +++ b/src/z_makesymbol.c @@ -0,0 +1,126 @@ +/* +(l) 1210:forum::für::umläute:1999 + + "makesymbol" is something between "symbol" and "makefilename", thus storing and creating (formatted) + symbols... + +*/ + +#include "zexy.h" + +#include <string.h> +#include <stdio.h> + +#define MAXSTRINGARGS 10 +#define MAXSTRINGLENG 80 + +/* ----------------------- makesymbol --------------------- */ + +static t_class *makesymbol_class; + +typedef struct _makesymbol +{ + t_object x_obj; + t_symbol *x_sym; + + char* mask; + char* buf; +} t_makesymbol; + +static void reset_mask(t_makesymbol *x, t_symbol *s) +{ + if (*s->s_name) { + x->mask = s->s_name; + x->x_sym = s; + } else { + x->mask = "%s%s%s%s%s%s%s%s%s%s"; + x->x_sym = gensym(""); + } +} + +t_symbol* list2symbol(char *masque, int argc, t_atom *argv) +{ + typedef char cstring[MAXSTRINGLENG]; + + cstring buf[MAXSTRINGARGS]; + cstring buffer; + int i; + + for (i=0; i<argc; i++) { + atom_string(argv+i, buf[i], MAXSTRINGLENG); + } + + sprintf(buffer, + masque, + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9]); + + return (gensym(buffer)); +} + +static void makesymbol_list(t_makesymbol *x, t_symbol *s, int argc, t_atom *argv) +{ + x->x_sym = list2symbol(x->mask, argc, argv); + outlet_symbol(x->x_obj.ob_outlet, x->x_sym); +} + +static void makesymbol_bang(t_makesymbol *x) +{ + outlet_symbol(x->x_obj.ob_outlet, x->x_sym); +} + + +static void *makesymbol_new(t_symbol *s, int argc, t_atom *argv) +{ + t_makesymbol *x = (t_makesymbol *)pd_new(makesymbol_class); + + x->buf = (char *)getbytes(MAXSTRINGLENG * sizeof(char)); + + x->mask = x->buf; + + if (argc) { + atom_string(argv, x->buf, MAXSTRINGLENG); + x->x_sym = gensym(x->buf); + } else { + x->mask = "%s%s%s%s%s%s%s%s%s%s"; + x->x_sym = gensym(""); + } + + outlet_new(&x->x_obj, &s_symbol); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("symbol"), gensym("sym1")); + + return (x); +} + +static void makesymbol_free(t_makesymbol *x) +{ + freebytes(x->buf, MAXSTRINGLENG*sizeof(char)); +} + + +static void helper(t_makesymbol *x) +{ + post("\n%c makesymbol :: create a formatted symbol", HEARTSYMBOL); + post("<list of anything>\t: glue up to 10 list-elements to 1 formatted symbol\n" + "'bang'\t\t\t: re-output\n" + "'help'\t\t\t: view this" + "\ninlet2 : <format-string>: new format-string (symbol !)" + "\noutlet : <symbol>\t: formatted concatenation"); + post("\ncreation:\"makesymbol [<format-string>]\": C-style format-string (%s only)", "%s"); + +post("\n\nmasq = %s", x->mask); +} + +void z_makesymbol_setup(void) +{ + makesymbol_class = class_new(gensym("makesymbol"), + (t_newmethod)makesymbol_new, (t_method)makesymbol_free, + sizeof(t_makesymbol), 0, A_GIMME, 0); + + class_addlist(makesymbol_class, makesymbol_list); + class_addbang(makesymbol_class, makesymbol_bang); + + class_addmethod(makesymbol_class, (t_method)reset_mask, gensym("sym1"), A_SYMBOL, 0); + + class_addmethod(makesymbol_class, (t_method)helper, gensym("help"), 0); + class_sethelpsymbol(makesymbol_class, gensym("zexy/makesymbol")); +} diff --git a/src/z_matrix.c b/src/z_matrix.c new file mode 100644 index 0000000..a0cd4d9 --- /dev/null +++ b/src/z_matrix.c @@ -0,0 +1,2705 @@ +/* 2504:forum::für::umläute:2001 */ + +/* objects for manipulating matrices */ +/* mostly i refer to matlab/octave matrix functions */ + +/* + matrix : basic object : create and store matrices + mtx : alias for matrix + + mtx_resize + mtx_row + mtx_col + mtx_element + + mtx_ones + mtx_zeros + mtx_eye + mtx_egg + + mtx_diag + mtx_diegg + mtx_trace + + mtx_mean + mtx_rand + + mtx_transpose + mtx_scroll + mtx_roll + + mtx_add + mtx_+ + mtx_mul + mtx_* + mtx_.* + mtx_./ + + mtx_inverse + mtx_pivot + + mtx_size + + mtx_check + mtx_print +*/ + +#define MY_WRITE + +#define T_FLOAT long double + +#include "zexy.h" +#include <math.h> + +#ifdef MY_WRITE +#include <stdio.h> +#endif + +#ifdef NT +#include <memory.h> +#define fabsf fabs +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + + +/* -------------------- matrix ------------------------------ */ + +static t_class *matrix_class; + +typedef struct _matrix +{ + t_object x_obj; + + int row; + int col; + + t_atom *atombuffer; + + int current_row, current_col; /* this makes things easy for the mtx_row & mtx_col...*/ + t_float f; + + t_canvas *x_canvas; +} t_matrix; + +/* intern utility functions */ + +static void setdimen(t_matrix *x, int row, int col) +{ + x->col = col; + x->row = row; + SETFLOAT(x->atombuffer, row); + SETFLOAT(x->atombuffer+1, col); +} + +static void adjustsize(t_matrix *x, int desiredRow, int desiredCol) +{ + int col=x->col, row=x->row; + + if (desiredRow<1){ + post("cannot make less than 1 rows"); + desiredRow=1; + } + if (desiredCol<1){ + post("cannot make less than 1 columns"); + desiredCol=1; + } + + if (col*row!=desiredRow*desiredCol){ + if(x->atombuffer)freebytes(x->atombuffer, (col*row+2)*sizeof(t_atom)); + x->atombuffer=(t_atom *)getbytes((desiredCol*desiredRow+2)*sizeof(t_atom)); + } + + setdimen(x, desiredRow, desiredCol); + return; +} + +static void debugmtx(int argc, t_float *buf, int id) +{ + int i=argc; + while(i--){ + int j=argc; + startpost("debug%d: ", id); + while(j--) + startpost("%f ", *buf++); + endpost(); + } +} +static T_FLOAT *matrix2float(t_atom *ap) +{ + int row = atom_getfloat(ap++); + int col=atom_getfloat(ap++); + int length = row * col; + T_FLOAT *buffer = (T_FLOAT *)getbytes(sizeof(T_FLOAT)*length); + T_FLOAT *buf = buffer; + while(length--)*buf++=atom_getfloat(ap++); + return buffer; +} +static void float2matrix(t_atom *ap, T_FLOAT *buffer) +{ + int row=atom_getfloat(ap++); + int col=atom_getfloat(ap++); + int length = row * col; + T_FLOAT*buf= buffer; + while(length--){ + SETFLOAT(ap, *buf++); + ap++; + } + freebytes(buffer, row*col*sizeof(T_FLOAT)); +} + + +/* core functions */ + +static void matrix_bang(t_matrix *x) +{ + /* output the matrix */ + if (x->atombuffer)outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), x->col*x->row+2, x->atombuffer); +} + +static void matrix_matrix2(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int row, col; + + if (argc<2){ + post("matrix : corrupt matrix passed"); + return; + } + row = atom_getfloat(argv); + col = atom_getfloat(argv+1); + if ((row<1)||(col<1)){ + post("matrix : corrupt matrix passed"); + return; + } + if (row*col > argc-2){ + post("matrix: sparse matrices not yet supported : use \"mtx_check\""); + return; + } + + /* this is fast and dirty, MAYBE make it slow and clean */ + /* or, to clean matrices, use the mtx_check object */ + if (row*col != x->row*x->col) { + freebytes(x->atombuffer, x->row*x->col*sizeof(t_atom)); + x->atombuffer = copybytes(argv, (row*col+2)*sizeof(t_atom)); + } else memcpy(x->atombuffer, argv, (row*col+2)*sizeof(t_atom)); + + setdimen(x, row, col); +} + +static void matrix_matrix(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int row, col; + + if (argc<2){ + post("matrix : corrupt matrix passed"); + return; + } + row = atom_getfloat(argv); + col = atom_getfloat(argv+1); + if ((row<1)||(col<1)){ + post("matrix : corrupt matrix passed"); + return; + } + if (row*col > argc-2){ + post("matrix: sparse matrices not yet supported : use \"mtx_check\""); + return; + } + + matrix_matrix2(x, s, argc, argv); + matrix_bang(x); +} + + +/* basic functions */ + +static void matrix_set(t_matrix *x, t_float f) +{ + int size = x->col * x->row; + t_atom *buf=x->atombuffer+2; + if(x->atombuffer)while(size--)SETFLOAT(&buf[size], f); +} + +static void matrix_zeros(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int col, row; + + switch(argc) { + case 0: /* zero out the actual matrix */ + matrix_set(x, 0); + break; + case 1: + row=atom_getfloat(argv); + adjustsize(x, row, row); + matrix_set(x, 0); + break; + default: + row=atom_getfloat(argv++); + col=atom_getfloat(argv); + adjustsize(x, row, col); + + matrix_set(x, 0); + } + + matrix_bang(x); +} + +static void matrix_ones(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int col, row; + + switch(argc) { + case 0: /* zero out the actual matrix */ + matrix_set(x, 1); + break; + case 1: + row=atom_getfloat(argv); + adjustsize(x, row, row); + matrix_set(x, 1); + break; + default: + row=atom_getfloat(argv++); + col=atom_getfloat(argv); + adjustsize(x, row, col); + + matrix_set(x, 1); + } + + matrix_bang(x); +} + +static void matrix_eye(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int col, row; + int n; + + switch(argc) { + case 0: /* zero out the actual matrix */ + matrix_set(x, 0); + break; + case 1: + row=atom_getfloat(argv); + adjustsize(x, row, row); + matrix_set(x, 0); + break; + default: + row=atom_getfloat(argv++); + col=atom_getfloat(argv); + adjustsize(x, row, col); + matrix_set(x, 0); + } + + col=x->col; + row=x->row; + n = (col<row)?col:row; + while(n--)SETFLOAT(x->atombuffer+2+n*(1+col), 1); + + matrix_bang(x); +} +static void matrix_egg(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int col, row; + int n; + + switch(argc) { + case 0: /* zero out the actual matrix */ + matrix_set(x, 0); + break; + case 1: + row=atom_getfloat(argv); + adjustsize(x, row, row); + matrix_set(x, 0); + break; + default: + row=atom_getfloat(argv++); + col=atom_getfloat(argv); + adjustsize(x, row, col); + matrix_set(x, 0); + } + + col=x->col; + row=x->row; + n = (col<row)?col:row; + while(n--)SETFLOAT(x->atombuffer+2+(n+1)*(col-1), 1); + + matrix_bang(x); +} + +static void matrix_diag(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int col=argc; + argv+=argc-1; + if (argc<1) { + post("matrix: no diagonale present"); + return; + } + adjustsize(x, argc, argc); + matrix_set(x, 0); + + while(argc--)SETFLOAT(x->atombuffer+2+argc*(1+col), atom_getfloat(argv--)); + + matrix_bang(x); +} +static void matrix_diegg(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int col=argc; + argv+=argc-1; + if (argc<1) { + post("matrix: no dieggonale present"); + return; + } + adjustsize(x, argc, argc); + matrix_set(x, 0); + + while(argc--){ + t_atom *ap=x->atombuffer+2+(argc+1)*(col-1); + SETFLOAT(ap, atom_getfloat(argv--)); + } + + matrix_bang(x); +} +/* the rest */ + +static void matrix_row(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + t_atom *ap; + int row=x->row, col=x->col; + int r; + t_float f; + + switch (argc){ + case 0: + for (r=0;r<row;r++)outlet_list(x->x_obj.ob_outlet, gensym("row"), col, x->atombuffer+r*col+2); + break; + case 1: + r=atom_getfloat(argv)-1; + if ((r<0)||(r>=row)){ + post("matrix: row index %d is out of range", r+1); + return; + } + outlet_list(x->x_obj.ob_outlet, gensym("row"), col, x->atombuffer+r*col+2); + break; + case 2: + r=atom_getfloat(argv)-1; + f=atom_getfloat(argv+1); + if ((r<0)||(r>=row)){ + post("matrix: row index %d is out of range", r+1); + return; + } + + + default: + r=atom_getfloat(argv++)-1; + if (argc--<col){ + post("matrix: sparse rows not yet supported : use \"mtx_check\""); + return; + } + if ((r<0)||(r>=row)){ + post("matrix: row index %d is out of range", r+1); + return; + } + if (r==row) { + } else { + ap=x->atombuffer+2+col*r; + memcpy(ap, argv, col*sizeof(t_atom)); + } + } +} + +static void matrix_col(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + t_atom *ap; + int row=x->row, col=x->col; + int c, r; + + switch (argc){ + case 0: + ap=(t_atom *)getbytes(row*sizeof(t_atom)); + for (c=0;c<col;c++) { + for (r=0;r<row;r++)SETFLOAT(&ap[r], atom_getfloat(x->atombuffer+2+c+col*r)); + outlet_list(x->x_obj.ob_outlet, gensym("col"), row, ap); + } + freebytes(ap, row*sizeof(t_atom)); + break; + case 1: + ap=(t_atom *)getbytes(row*sizeof(t_atom)); + c=atom_getfloat(argv)-1; + if ((c<0)||(c>=col)){ + post("matrix: col index %d is out of range", c+1); + return; + } + for (r=0;r<row;r++)SETFLOAT(&ap[r], atom_getfloat(x->atombuffer+2+c+col*r)); + outlet_list(x->x_obj.ob_outlet, gensym("col"), row, ap); + freebytes(ap, row*sizeof(t_atom)); + break; + default: + c=atom_getfloat(argv++)-1; + if (argc--<row){ + post("matrix: sparse cols not yet supported : use \"mtx_check\""); + return; + } + if ((c<0)||(c>=col)){ + post("matrix: col index %d is out of range", c+1); + return; + } + argv+=argc-1; + if (argc>row)argc=row; + while(argc--){ + ap=x->atombuffer+2+c+col*argc; + SETFLOAT(ap, atom_getfloat(argv--)); + } + } +} + +static void matrix_element(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + t_atom *ap=x->atombuffer+2; + int row=x->row, col=x->col; + int r, c, i=row*col; + + switch (argc){ + case 0: + while(i--)outlet_float(x->x_obj.ob_outlet, atom_getfloat(ap++)); + break; + case 1: + r=c=atom_getfloat(argv)-1; + if ((r<0)||(r>=row)){ + post("matrix: row index %d is out of range", r+1); + return; + } + if ((c<0)||(c>=col)){ + post("matrix: col index %d is out of range", c+1); + return; + } + outlet_float(x->x_obj.ob_outlet, atom_getfloat(x->atombuffer+2+c+r*col)); + break; + case 2: + r=atom_getfloat(argv++)-1; + c=atom_getfloat(argv++)-1; + if ((r<0)||(r>=row)){ post("matrix: row index %d is out of range", r+1); return; } + if ((c<0)||(c>=col)){ post("matrix: col index %d is out of range", c+1); return; } + outlet_float(x->x_obj.ob_outlet, atom_getfloat(x->atombuffer+2+c+r*col)); + break; + default: + r=atom_getfloat(argv++)-1; + c=atom_getfloat(argv++)-1; + if ((r<0)||(r>=row)){ post("matrix: row index %d is out of range", r+1); return; } + if ((c<0)||(c>=col)){ post("matrix: col index %d is out of range", c+1); return; } + SETFLOAT(x->atombuffer+2+c+r*col, atom_getfloat(argv)); + } +} + +static void matrix_float(t_matrix *x, t_float f) +{ + matrix_set(x, f); + matrix_bang(x); +} + +/* ------------- file I/O ------------------ */ + +static void matrix_read(t_matrix *x, t_symbol *filename) +{ + t_binbuf *bbuf = binbuf_new(); + t_atom *ap; + int n; + + if (binbuf_read_via_path(bbuf, filename->s_name, canvas_getdir(x->x_canvas)->s_name, 0)) + error("matrix: failed to read %s", filename->s_name); + + ap=binbuf_getvec(bbuf); + n =binbuf_getnatom(bbuf)-1; + + if ((ap->a_type == A_SYMBOL) && + (!strcmp(ap->a_w.w_symbol->s_name,"matrix") || !strcmp(ap->a_w.w_symbol->s_name,"#matrix")) ){ + matrix_matrix2(x, gensym("matrix"), n, ap+1); + } + + binbuf_free(bbuf); +} +#ifndef MY_WRITE +static void matrix_write(t_matrix *x, t_symbol *filename) +{ + t_binbuf *bbuf = binbuf_new(); + t_atom atom, *ap=x->atombuffer; + char buf[MAXPDSTRING]; + int n = x->row; + + canvas_makefilename(x->x_canvas, filename->s_name, buf, MAXPDSTRING); + + /* we now write "#matrix" instead of "matrix", + * so that these files can easily read by other + * applications such as octave + */ + SETSYMBOL(&atom, gensym("#matrix")); + binbuf_add(bbuf, 1, &atom); + binbuf_add(bbuf, 2, ap); + binbuf_addsemi(bbuf); + ap+=2; + while(n--){ + binbuf_add(bbuf, x->col, ap); + binbuf_addsemi(bbuf); + ap+=x->col; + } + + if (binbuf_write(bbuf, buf, "", 1)){ + error("matrix: failed to write %s", filename->s_name); + } + + binbuf_free(bbuf); +} +#else +static void matrix_write(t_matrix *x, t_symbol *filename) +{ + t_atom *ap=x->atombuffer+2; + char filnam[MAXPDSTRING]; + int rows = x->row, cols = x->col; + FILE *f=0; + + sys_bashfilename(filename->s_name, filnam); + + /* open file */ + if (!(f = fopen(filnam, "w"))) { + error("matrix : failed to open %s", filnam); + } else { + char *text=(char *)getbytes(sizeof(char)*MAXPDSTRING); + int textlen; + + /* header: + * we now write "#matrix" instead of "matrix", + * so that these files can easily read by other + * applications such as octave + */ + sprintf(text, "#matrix %d %d\n", rows, cols); + textlen = strlen(text); + if (fwrite(text, textlen*sizeof(char), 1, f) < 1) { + error("matrix : failed to write %s", filnam); goto end; + } + + while(rows--) { + int c = cols; + while (c--) { + t_float val = atom_getfloat(ap++); + sprintf(text, "%.15f ", val); + textlen=strlen(text); + if (fwrite(text, textlen*sizeof(char), 1, f) < 1) { + error("matrix : failed to write %s", filnam); goto end; + } + } + if (fwrite("\n", sizeof(char), 1, f) < 1) { + error("matrix : failed to write %s", filnam); goto end; + } + } + freebytes(text, sizeof(char)*MAXPDSTRING); + } + + end: + /* close file */ + if (f) fclose(f); +} +#endif + +static void matrix_free(t_matrix *x) +{ + freebytes(x->atombuffer, (x->col*x->row+2)*sizeof(t_atom)); + x->atombuffer=0; + x->col=x->row=0; +} +static void matrix_list(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + /* like matrix, but without col/row information, so the previous size is kept */ + int row=x->row, col=x->col; + + if(!row*col){ + post("matrix : unknown matrix dimensions"); + return; + } + if (argc<row*col){ + post("matrix: sparse matrices not yet supported : use \"mtx_check\" !"); + return; + } + + memcpy(x->atombuffer+2, argv, row*col*sizeof(t_atom)); + matrix_bang(x); +} + +static void *matrix_new(t_symbol *s, int argc, t_atom *argv) +{ + t_matrix *x = (t_matrix *)pd_new(matrix_class); + int row, col; + + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("matrix"), gensym("")); + outlet_new(&x->x_obj, 0); + + x->atombuffer = 0; + x->x_canvas = canvas_getcurrent(); + + switch (argc) { + case 0: + row = col = 0; + break; + case 1: + if (argv->a_type == A_SYMBOL) { + matrix_read(x, argv->a_w.w_symbol); + return(x); + } + row = col = atom_getfloat(argv); + break; + default: + row = atom_getfloat(argv++); + col = atom_getfloat(argv++); + } + + if(row*col){ + adjustsize(x, row, col); + matrix_set(x, 0); + } + + return (x); +} + +static void matrix_setup(void) +{ + matrix_class = class_new(gensym("matrix"), (t_newmethod)matrix_new, + (t_method)matrix_free, sizeof(t_matrix), 0, A_GIMME, 0); + class_addcreator((t_newmethod)matrix_new, gensym("mtx"), A_GIMME, 0); + + /* the core : functions for matrices */ + class_addmethod (matrix_class, (t_method)matrix_matrix, gensym("matrix"), A_GIMME, 0); + class_addmethod (matrix_class, (t_method)matrix_matrix2, gensym(""), A_GIMME, 0); + + /* the basics : functions for creation */ + class_addmethod (matrix_class, (t_method)matrix_eye, gensym("eye"), A_GIMME, 0); + class_addmethod (matrix_class, (t_method)matrix_diag, gensym("diag"), A_GIMME, 0); + class_addmethod (matrix_class, (t_method)matrix_ones, gensym("ones"), A_GIMME, 0); + class_addmethod (matrix_class, (t_method)matrix_zeros, gensym("zeros"), A_GIMME, 0); + class_addmethod (matrix_class, (t_method)matrix_egg, gensym("egg"), A_GIMME, 0); + class_addmethod (matrix_class, (t_method)matrix_diegg, gensym("diegg"), A_GIMME, 0); + + /* the rest : functions for anything */ + class_addbang (matrix_class, matrix_bang); + class_addfloat (matrix_class, matrix_float); + class_addlist (matrix_class, matrix_list); + class_addmethod (matrix_class, (t_method)matrix_row, gensym("row"), A_GIMME, 0); + class_addmethod (matrix_class, (t_method)matrix_col, gensym("column"), A_GIMME, 0); + class_addmethod (matrix_class, (t_method)matrix_col, gensym("col"), A_GIMME, 0); + class_addmethod (matrix_class, (t_method)matrix_element, gensym("element"), A_GIMME, 0); + + /* the file functions */ + class_addmethod (matrix_class, (t_method)matrix_write, gensym("write"), A_SYMBOL, 0); + class_addmethod (matrix_class, (t_method)matrix_read , gensym("read") , A_SYMBOL, 0); + + + class_sethelpsymbol(matrix_class, gensym("zexy/matrix")); +} + + +/* ------------------------------------------------------------------------------------- */ + +/* mtx_resize */ + +static t_class *mtx_resize_class; +static void mtx_resize_list2(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int r, c; + if (argc<1)return; + if (argc>2)error("mtx_resize : only rows & cols are needed, skipping the rest"); + if (argc==1)r=c=atom_getfloat(argv++); + else{ + r=atom_getfloat(argv++); + c=atom_getfloat(argv++); + } + + if (r<0)r=0; + if (c<0)c=0; + + x->current_row = r; + x->current_col = c; +} + +static void mtx_resize_matrix(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int row=atom_getfloat(argv); + int col=atom_getfloat(argv+1); + int r = x->current_row, c = x->current_col; + int R=0, ROW, COL; + + if (argc<2){ post("mtx_add: crippled matrix"); return; } + if ((col<1)||(row<1)) { post("mtx_add: invalid dimensions"); return; } + if (col*row>argc-2){ post("sparse matrix not yet supported : use \"mtx_check\""); return; } + + if (!r)r=row; + if (!c)c=col; + + if (r==row && c==col) { // no need to change + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), argc, argv); + return; + } + + x->atombuffer=(t_atom *)getbytes((c*r+2)*sizeof(t_atom)); + setdimen(x, r, c); + matrix_set(x, 0); + + ROW=(r<row)?r:row; + COL=(c<col)?c:col; + R=ROW; + while(R--)memcpy(x->atombuffer+2+(ROW-R-1)*c, argv+2+(ROW-R-1)*col, COL*sizeof(t_atom)); + + matrix_bang(x); + + freebytes(x->atombuffer, (c*r+2)*sizeof(t_atom)); +} + +static void *mtx_resize_new(t_symbol *s, int argc, t_atom *argv) +{ + t_matrix *x = (t_matrix *)pd_new(mtx_resize_class); + int c=0, r=0; + + if(argc){ + if(argc-1){ + r=atom_getfloat(argv); + c=atom_getfloat(argv+1); + } else r=c=atom_getfloat(argv); + if(c<0)c=0; + if(r<0)r=0; + } + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("")); + outlet_new(&x->x_obj, 0); + x->current_row = r; + x->current_col = c; + x->row = x->col= 0; + x->atombuffer = 0; + + return (x); +} +static void mtx_resize_setup(void) +{ + mtx_resize_class = class_new(gensym("mtx_resize"), (t_newmethod)mtx_resize_new, + 0, sizeof(t_matrix), 0, A_GIMME, 0); + class_addmethod (mtx_resize_class, (t_method)mtx_resize_matrix, gensym("matrix"), A_GIMME, 0); + class_addmethod (mtx_resize_class, (t_method)mtx_resize_list2, gensym(""), A_GIMME, 0); + class_sethelpsymbol(mtx_resize_class, gensym("zexy/mtx_size")); +} + +/* mtx_row */ +static t_class *mtx_row_class; + +static void mtx_row_float(t_matrix *x, t_floatarg f) +{ + int i = f; + if(i<0)i=0; + x->current_row = i; +} +static void mtx_row_matrix(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int row, col; + if (argc<2){ post("matrix : corrupt matrix passed"); return; } + row = atom_getfloat(argv); + col = atom_getfloat(argv+1); + if ((row<1)||(col<1)){ post("matrix : corrupt matrix passed"); return; } + if (row*col > argc-2){ post("matrix: sparse matrices not yet supported : use \"mtx_check\""); return; } + matrix_matrix2(x, s, argc, argv); + matrix_bang(x); +} +static void mtx_row_list(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + if (argc==1){ + t_float f=atom_getfloat(argv); + t_atom *ap=x->atombuffer+2+(x->current_row-1)*x->col; + if (x->current_row>x->row){ + post("mtx_row : too high a row is to be set"); + return; + } + if (x->current_row){ + int n=x->col; + while(n--){ + SETFLOAT(ap, f); + ap++; + } + } + matrix_bang(x); + return; + } + + if (argc<x->col){ + post("mtx_row : row length is too small for %dx%d-matrix", x->row, x->col); + return; + } + if (x->current_row>x->row){ + post("mtx_row : too high a row is to be set"); + return; + } + if(x->current_row) {memcpy(x->atombuffer+2+(x->current_row-1)*x->col, argv, x->col*sizeof(t_atom)); + } else { + int r=x->row; + while(r--)memcpy(x->atombuffer+2+r*x->col, argv, x->col*sizeof(t_atom)); + } + matrix_bang(x); +} +static void *mtx_row_new(t_symbol *s, int argc, t_atom *argv) +{ + t_matrix *x = (t_matrix *)pd_new(mtx_row_class); + int i, j, q; + + outlet_new(&x->x_obj, 0); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("")); + x->current_row=0; + x->col=x->row=0; + x->atombuffer=0; + switch (argc) { + case 0:break; + case 1: + i = atom_getfloat(argv); + if (i<0)i=0; + if(i)adjustsize(x, i, i); + matrix_set(x, 0); + break; + case 2: + i = atom_getfloat(argv++);if(i<0)i=0; + j = atom_getfloat(argv++);if(j<0)j=0; + if(i*j)adjustsize(x, i, j); + matrix_set(x, 0); + break; + default: + i = atom_getfloat(argv++);if(i<0)i=0; + j = atom_getfloat(argv++);if(j<0)j=0; + q = atom_getfloat(argv++);if(q<0)q=0; + if(i*j)adjustsize(x, i, j); + matrix_set(x, 0); + x->current_row=q; + } + return (x); +} +static void mtx_row_setup(void) +{ + mtx_row_class = class_new(gensym("mtx_row"), (t_newmethod)mtx_row_new, + (t_method)matrix_free, sizeof(t_matrix), 0, A_GIMME, 0); + class_addbang (mtx_row_class, matrix_bang); + class_addlist (mtx_row_class, mtx_row_list); + class_addmethod(mtx_row_class, (t_method)mtx_row_matrix, gensym("matrix"), A_GIMME, 0); + class_addmethod(mtx_row_class, (t_method)mtx_row_float, gensym(""), A_FLOAT, 0); + class_sethelpsymbol(mtx_row_class, gensym("zexy/mtx_element")); +} + + +/* mtx_col */ +static t_class *mtx_col_class; + +static void mtx_col_float(t_matrix *x, t_floatarg f) +{ + int i = f; + if(i<0)i=0; + x->current_col = i; +} +static void mtx_col_matrix(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int row, col; + if (argc<2){ post("matrix : corrupt matrix passed"); return; } + row = atom_getfloat(argv); + col = atom_getfloat(argv+1); + if ((row<1)||(col<1)){ post("matrix : corrupt matrix passed"); return; } + if (row*col > argc-2){ post("matrix: sparse matrices not yet supported : use \"mtx_check\""); return; } + matrix_matrix2(x, s, argc, argv); + matrix_bang(x); +} +static void mtx_col_list(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + if (argc==1){ + t_float f=atom_getfloat(argv); + t_atom *ap=x->atombuffer+1+x->current_col; + if (x->current_col>x->col){ + post("mtx_col : too high a column is to be set"); + return; + } + if (x->current_col){ + int n=x->row; + while(n--){ + SETFLOAT(ap, f); + ap+=x->row+1; + } + } + matrix_bang(x); + return; + } + + if (argc<x->row){ + post("mtx_col : column length is too small for %dx%d-matrix", x->row, x->col); + return; + } + if (x->current_col>x->col){ + post("mtx_col : too high a column is to be set"); + return; + } + if(x->current_col) { + int r=x->row; + t_atom *ap=x->atombuffer+1+x->current_col; + while(r--)SETFLOAT(&ap[(x->row-r-1)*x->col], atom_getfloat(argv++)); + } else { + int r=x->row; + t_atom *ap=x->atombuffer+2; + while (r--) { + t_float f=atom_getfloat(argv++); + int c=x->col; + while(c--){ + SETFLOAT(ap, f); + ap++; + } + } + } + matrix_bang(x); +} +static void *mtx_col_new(t_symbol *s, int argc, t_atom *argv) +{ + t_matrix *x = (t_matrix *)pd_new(mtx_col_class); + int i, j, q; + outlet_new(&x->x_obj, 0); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("")); + x->current_col=0; + x->col=x->row=0; + x->atombuffer=0; + switch (argc) { + case 0:break; + case 1: + i = atom_getfloat(argv); + if (i<0)i=0; + if(i)adjustsize(x, i, i); + matrix_set(x, 0); + break; + case 2: + i = atom_getfloat(argv++);if(i<0)i=0; + j = atom_getfloat(argv++);if(j<0)j=0; + if(i*j)adjustsize(x, i, j); + matrix_set(x, 0); + break; + default: + i = atom_getfloat(argv++);if(i<0)i=0; + j = atom_getfloat(argv++);if(j<0)j=0; + q = atom_getfloat(argv++);if(q<0)q=0; + if(i*j)adjustsize(x, i, j); + matrix_set(x, 0); + x->current_col=q; + } + return (x); +} +static void mtx_col_setup(void) +{ + mtx_col_class = class_new(gensym("mtx_col"), (t_newmethod)mtx_col_new, + (t_method)matrix_free, sizeof(t_matrix), 0, A_GIMME, 0); + class_addbang (mtx_col_class, matrix_bang); + class_addlist (mtx_col_class, mtx_col_list); + class_addmethod(mtx_col_class, (t_method)mtx_col_matrix, gensym("matrix"), A_GIMME, 0); + class_addmethod(mtx_col_class, (t_method)mtx_col_float, gensym(""), A_FLOAT, 0); + class_sethelpsymbol(mtx_col_class, gensym("zexy/mtx_element")); +} + +/* mtx_element */ +static t_class *mtx_element_class; + +static void mtx_element_list2(t_matrix *x, t_floatarg f1, t_floatarg f2) +{ + int r = f1, c= f2; + if(r<0)r=0; + if(c<0)c=0; + x->current_row = r; + x->current_col = c; +} +static void mtx_element_matrix(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int row, col; + if (argc<2){ post("matrix : corrupt matrix passed"); return; } + row = atom_getfloat(argv); + col = atom_getfloat(argv+1); + if ((row<1)||(col<1)){ post("matrix : corrupt matrix passed"); return; } + if (row*col > argc-2){ post("matrix: sparse matrices not yet supported : use \"mtx_check\""); return; } + matrix_matrix2(x, s, argc, argv); + matrix_bang(x); +} +static void mtx_element_float(t_matrix *x, t_floatarg f) +{ + if(x->current_col>x->col || x->current_row>x->row){ + error("mtx_element: element position exceeds matrix dimensions"); + return; + } + if(x->current_row == 0 && x->current_col == 0){ + matrix_set(x, f); + matrix_bang(x); + return; + } + if(x->current_row*x->current_col)SETFLOAT(x->atombuffer+1+(x->current_row-1)*x->col+x->current_col, f); + else { + t_atom *ap=x->atombuffer+2; + int count; + if (!x->current_col){ + ap+=x->col*(x->current_row-1); + count=x->col; + while(count--)SETFLOAT(&ap[count], f); + } else { // x->current_row==0 + ap+=x->current_col-1; + count=x->row; + while(count--)SETFLOAT(&ap[count*x->col], f); + } + } + matrix_bang(x); +} + +static void *mtx_element_new(t_symbol *s, int argc, t_atom *argv) +{ + t_matrix *x = (t_matrix *)pd_new(mtx_element_class); + int i, j, q; + outlet_new(&x->x_obj, 0); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("")); + x->current_row=x->current_col=0; + x->col=x->row=0; + x->atombuffer=0; + switch (argc) { + case 1: + i = atom_getfloat(argv); + if (i<0)i=0; + if(i)adjustsize(x, i, i); + matrix_set(x, 0); + break; + case 2: + i = atom_getfloat(argv++);if(i<0)i=0; + j = atom_getfloat(argv++);if(j<0)j=0; + if(i*j)adjustsize(x, i, j); + matrix_set(x, 0); + break; + case 4: + i = atom_getfloat(argv++);if(i<0)i=0; + j = atom_getfloat(argv++);if(j<0)j=0; + if(i*j)adjustsize(x, i, j); + matrix_set(x, 0); + q = atom_getfloat(argv++);if(q<0)q=0; + x->current_row=q; + q = atom_getfloat(argv++);if(q<0)q=0; + x->current_col=q; + break; + default:; + } + return (x); +} +static void mtx_element_setup(void) +{ + mtx_element_class = class_new(gensym("mtx_element"), (t_newmethod)mtx_element_new, + (t_method)matrix_free, sizeof(t_matrix), 0, A_GIMME, 0); + class_addbang (mtx_element_class, matrix_bang); + class_addfloat (mtx_element_class, mtx_element_float); + class_addmethod(mtx_element_class, (t_method)mtx_element_matrix, gensym("matrix"), A_GIMME, 0); + class_addmethod(mtx_element_class, (t_method)mtx_element_list2, gensym(""), A_FLOAT, A_FLOAT, 0); + class_sethelpsymbol(mtx_element_class, gensym("zexy/mtx_element")); +} + +/* mtx_eye */ +static t_class *mtx_eye_class; +static void *mtx_eye_new(t_symbol *s, int argc, t_atom *argv) +{ + t_matrix *x = (t_matrix *)pd_new(mtx_eye_class); + int col=0, row=0; + outlet_new(&x->x_obj, 0); + x->row = x->col = 0; + x->atombuffer = 0; + switch(argc) { + case 0: + break; + case 1: + col=row=atom_getfloat(argv); + break; + default: + row=atom_getfloat(argv++); + col=atom_getfloat(argv); + } + if(col<0)col=0; + if(row<0)row=0; + if (col*row){ + int n = (col<row)?col:row; + x->atombuffer = (t_atom *)getbytes((col*row+2)*sizeof(t_atom)); + setdimen(x, row, col); + matrix_set(x, 0); + while(n--)SETFLOAT(x->atombuffer+2+n*(1+col), 1); + } + return (x); +} +static void mtx_eye_setup(void) +{ + mtx_eye_class = class_new(gensym("mtx_eye"), (t_newmethod)mtx_eye_new, + (t_method)matrix_free, sizeof(t_matrix), 0, A_GIMME, 0); + class_addlist(mtx_eye_class, matrix_eye); + class_addbang(mtx_eye_class, matrix_bang); + class_addmethod(mtx_eye_class, (t_method)matrix_eye, gensym("matrix"), A_GIMME, 0); + + class_sethelpsymbol(mtx_eye_class, gensym("zexy/mtx_special")); +} +/* mtx_egg */ +static t_class *mtx_egg_class; +static void *mtx_egg_new(t_symbol *s, int argc, t_atom *argv) +{ + t_matrix *x = (t_matrix *)pd_new(mtx_egg_class); + int col=0, row=0; + outlet_new(&x->x_obj, 0); + x->row = x->col = 0; + x->atombuffer = 0; + switch(argc) { + case 0: + break; + case 1: + col=row=atom_getfloat(argv); + break; + default: + row=atom_getfloat(argv++); + col=atom_getfloat(argv); + } + if(col<0)col=0; + if(row<0)row=0; + if (col*row){ + int n = (col<row)?col:row; + x->atombuffer = (t_atom *)getbytes((col*row+2)*sizeof(t_atom)); + setdimen(x, row, col); + matrix_set(x, 0); + while(n--)SETFLOAT(x->atombuffer+2+(n+1)*(col-1), 1); + } + return (x); +} +static void mtx_egg_setup(void) +{ + mtx_egg_class = class_new(gensym("mtx_egg"), (t_newmethod)mtx_egg_new, + (t_method)matrix_free, sizeof(t_matrix), 0, A_GIMME, 0); + class_addlist(mtx_egg_class, matrix_egg); + class_addbang(mtx_egg_class, matrix_bang); + class_addmethod(mtx_egg_class, (t_method)matrix_egg, gensym("matrix"), A_GIMME, 0); + + class_sethelpsymbol(mtx_egg_class, gensym("zexy/mtx_special")); +} +/* mtx_ones */ +static t_class *mtx_ones_class; +static void *mtx_ones_new(t_symbol *s, int argc, t_atom *argv) +{ + t_matrix *x = (t_matrix *)pd_new(mtx_ones_class); + int col=0, row=0; + outlet_new(&x->x_obj, 0); + x->row = x->col = 0; + x->atombuffer = 0; + switch(argc) { + case 0: + break; + case 1: + col=row=atom_getfloat(argv); + break; + default: + row=atom_getfloat(argv++); + col=atom_getfloat(argv); + } + if(col<0)col=0; + if(row<0)row=0; + if (col*row){ + x->atombuffer = (t_atom *)getbytes((col*row+2)*sizeof(t_atom)); + setdimen(x, row, col); + matrix_set(x, 1); + } + return (x); +} +static void mtx_ones_setup(void) +{ + mtx_ones_class = class_new(gensym("mtx_ones"), (t_newmethod)mtx_ones_new, + (t_method)matrix_free, sizeof(t_matrix), 0, A_GIMME, 0); + class_addlist(mtx_ones_class, matrix_ones); + class_addbang(mtx_ones_class, matrix_bang); + class_addmethod(mtx_ones_class, (t_method)matrix_ones, gensym("matrix"), A_GIMME, 0); + + class_sethelpsymbol(mtx_ones_class, gensym("zexy/mtx_special")); +} + +/* mtx_zeros */ +static t_class *mtx_zeros_class; +static void *mtx_zeros_new(t_symbol *s, int argc, t_atom *argv) +{ + t_matrix *x = (t_matrix *)pd_new(mtx_zeros_class); + int col=0, row=0; + outlet_new(&x->x_obj, 0); + x->row = x->col = 0; + x->atombuffer = 0; + switch(argc) { + case 0: + break; + case 1: + col=row=atom_getfloat(argv); + break; + default: + row=atom_getfloat(argv++); + col=atom_getfloat(argv); + } + if(col<0)col=0; + if(row<0)row=0; + if (col*row){ + x->atombuffer = (t_atom *)getbytes((col*row+2)*sizeof(t_atom)); + setdimen(x, row, col); + matrix_set(x, 0); + } + return (x); +} +static void mtx_zeros_setup(void) +{ + mtx_zeros_class = class_new(gensym("mtx_zeros"), (t_newmethod)mtx_zeros_new, + (t_method)matrix_free, sizeof(t_matrix), 0, A_GIMME, 0); + class_addlist(mtx_zeros_class, matrix_zeros); + class_addbang(mtx_zeros_class, matrix_bang); + class_addmethod(mtx_zeros_class, (t_method)matrix_zeros, gensym("matrix"), A_GIMME, 0); + + class_sethelpsymbol(mtx_zeros_class, gensym("zexy/mtx_special")); +} + +/* mtx_diag */ +static t_class *mtx_diag_class; +static void mtx_diag_matrix(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int row=atom_getfloat(argv++); + int col=atom_getfloat(argv++); + int length=(col<row)?col:row, n=length; + t_atom *ap = (t_atom *)getbytes(length * sizeof(t_atom)), *dummy=ap; + if(row*col>argc-2)post("mtx_diag: sparse matrices not yet supported : use \"mtx_check\""); + else { + for(n=0;n<length;n++, dummy++)SETFLOAT(dummy, atom_getfloat(argv+n*(col+1))); + outlet_list(x->x_obj.ob_outlet, gensym("diag"), length, ap); + } + freebytes(ap, (length * sizeof(t_atom))); +} + +static void *mtx_diag_new(t_symbol *s, int argc, t_atom *argv) +{ + t_matrix *x = (t_matrix *)pd_new(mtx_diag_class); + outlet_new(&x->x_obj, 0); + x->row = x->col = 0; + x->atombuffer = 0; + + if(!argc)return(x); + x->atombuffer = (t_atom *)getbytes((argc*argc+2)*sizeof(t_atom)); + setdimen(x, argc, argc); + matrix_set(x, 0); + argv+=argc-1; + while(argc--)SETFLOAT(x->atombuffer+2+argc*(1+x->col), atom_getfloat(argv--)); + + return (x); +} +static void mtx_diag_setup(void) +{ + mtx_diag_class = class_new(gensym("mtx_diag"), (t_newmethod)mtx_diag_new, + (t_method)matrix_free, sizeof(t_matrix), 0, A_GIMME, 0); + class_addlist (mtx_diag_class, matrix_diag); + class_addbang (mtx_diag_class, matrix_bang); + class_addmethod(mtx_diag_class, (t_method)mtx_diag_matrix, gensym("matrix"), A_GIMME, 0); + class_sethelpsymbol(mtx_diag_class, gensym("zexy/mtx_trace")); +} + +/* mtx_diegg */ +static t_class *mtx_diegg_class; +static void mtx_diegg_matrix(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int row=atom_getfloat(argv++); + int col=atom_getfloat(argv++); + int length=(col<row)?col:row, n=length; + t_atom *ap = (t_atom *)getbytes(length * sizeof(t_atom)), *dummy=ap; + if(row*col>argc-2)post("mtx_diegg: sparse matrices not yet supported : use \"mtx_check\""); + else { + for(n=0;n<length;n++, dummy++)SETFLOAT(dummy, atom_getfloat(argv+(n-1)*(col-1))); + outlet_list(x->x_obj.ob_outlet, gensym("diegg"), length, ap); + } + freebytes(ap, (length * sizeof(t_atom))); +} + +static void *mtx_diegg_new(t_symbol *s, int argc, t_atom *argv) +{ + t_matrix *x = (t_matrix *)pd_new(mtx_diegg_class); + outlet_new(&x->x_obj, 0); + x->row = x->col = 0; + x->atombuffer = 0; + + if(!argc)return(x); + x->atombuffer = (t_atom *)getbytes((argc*argc+2)*sizeof(t_atom)); + setdimen(x, argc, argc); + matrix_set(x, 0); + argv+=argc-1; + while(argc--)SETFLOAT(x->atombuffer+2+argc*(1+x->col), atom_getfloat(argv--)); + + return (x); +} +static void mtx_diegg_setup(void) +{ + mtx_diegg_class = class_new(gensym("mtx_diegg"), (t_newmethod)mtx_diegg_new, + (t_method)matrix_free, sizeof(t_matrix), 0, A_GIMME, 0); + class_addlist (mtx_diegg_class, matrix_diegg); + class_addbang (mtx_diegg_class, matrix_bang); + class_addmethod(mtx_diegg_class, (t_method)mtx_diegg_matrix, gensym("matrix"), A_GIMME, 0); + class_sethelpsymbol(mtx_diegg_class, gensym("zexy/mtx_special")); +} +/* mtx_trace */ +static t_class *mtx_trace_class; +typedef struct _mtx_trace +{ + t_object x_obj; + t_float trace; +} t_mtx_trace; +static void mtx_trace_bang(t_mtx_trace *x) +{ + outlet_float(x->x_obj.ob_outlet, x->trace); +} +static void mtx_trace_matrix(t_mtx_trace *x, t_symbol *s, int argc, t_atom *argv) +{ + int row=atom_getfloat(argv++); + int col=atom_getfloat(argv++); + int length=(col<row)?col:row; + t_float trace = 0; + if(row*col>argc-2)post("mtx_trace: sparse matrices not yet supported : use \"mtx_check\""); + else while(length--)trace+=atom_getfloat(argv+length*(col+1)); + x->trace=trace; + mtx_trace_bang(x); +} +static void *mtx_trace_new(t_symbol *s, int argc, t_atom *argv) +{ + t_mtx_trace *x = (t_mtx_trace *)pd_new(mtx_trace_class); + outlet_new(&x->x_obj, 0); + x->trace=0; + return (x); +} +static void mtx_trace_setup(void) +{ + mtx_trace_class = class_new(gensym("mtx_trace"), (t_newmethod)mtx_trace_new, + 0, sizeof(t_mtx_trace), 0, A_GIMME, 0); + class_addbang (mtx_trace_class, mtx_trace_bang); + class_addmethod(mtx_trace_class, (t_method)mtx_trace_matrix, gensym("matrix"), A_GIMME, 0); + class_sethelpsymbol(mtx_trace_class, gensym("zexy/mtx_trace")); +} + +/* mtx_mean */ +static t_class *mtx_mean_class; + +static void mtx_mean_matrix(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int row=atom_getfloat(argv++); + int col=atom_getfloat(argv++); + t_atom *ip, *op; + int c=col, r; + t_float sum; + t_float factor=1./row; + adjustsize(x, 1, col); + op=x->atombuffer; + + while(c--){ + sum=0; + ip=argv+col-c-1; + r=row; + while(r--)sum+=atom_getfloat(ip+col*r); + SETFLOAT(op, sum*factor); + op++; + } + outlet_list(x->x_obj.ob_outlet, gensym("row"), col, x->atombuffer); +} + +static void *mtx_mean_new(void) +{ + t_matrix *x = (t_matrix *)pd_new(mtx_mean_class); + outlet_new(&x->x_obj, 0); + x->col=x->row=0; + x->atombuffer=0; + return (x); +} +static void mtx_mean_setup(void) +{ + mtx_mean_class = class_new(gensym("mtx_mean"), (t_newmethod)mtx_mean_new, + (t_method)matrix_free, sizeof(t_matrix), 0, 0, 0); + class_addmethod(mtx_mean_class, (t_method)mtx_mean_matrix, gensym("matrix"), A_GIMME, 0); + class_sethelpsymbol(mtx_mean_class, gensym("zexy/mtx_mean")); +} + +/* mtx_rand */ +static t_class *mtx_rand_class; + +static void mtx_rand_seed(t_matrix *x, t_float f) +{ + x->current_row=f; +} +static int makeseed(void) +{ + static unsigned int random_nextseed = 1489853723; + random_nextseed = random_nextseed * 435898247 + 938284287; + return (random_nextseed & 0x7fffffff); +} +static void mtx_rand_random(t_matrix *x) +{ + long size = x->row * x->col; + t_atom *ap=x->atombuffer+2; + int val = x->current_row; + while(size--)SETFLOAT(ap+size, ((float)(((val=val*435898247+382842987)&0x7fffffff)-0x40000000))*(float)(0.5/0x40000000)+0.5); + x->current_row=val; +} + +static void mtx_rand_list(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int row = atom_getfloat(argv++); + int col = atom_getfloat(argv++); + + if(!argv)return; + if(argc==1)col=row; + + adjustsize(x, row, col); + mtx_rand_random(x); + matrix_bang(x); +} +static void mtx_rand_matrix(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + matrix_matrix2(x, s, argc, argv); + mtx_rand_random(x); + matrix_bang(x); +} +static void mtx_rand_bang(t_matrix *x) +{ + mtx_rand_random(x); + matrix_bang(x); +} +static void *mtx_rand_new(t_symbol *s, int argc, t_atom *argv) +{ + t_matrix *x = (t_matrix *)pd_new(mtx_rand_class); + int row, col; + outlet_new(&x->x_obj, 0); + x->col=x->row=0; + x->atombuffer=0; + x->current_row=makeseed(); + + if (argc) { + row=atom_getfloat(argv); + col=(argc>1)?atom_getfloat(argv+1):row; + adjustsize(x, row, col); + mtx_rand_random(x); + } + return (x); +} +static void mtx_rand_setup(void) +{ + mtx_rand_class = class_new(gensym("mtx_rand"), (t_newmethod)mtx_rand_new, + (t_method)matrix_free, sizeof(t_matrix), 0, A_GIMME, 0); + class_addmethod(mtx_rand_class, (t_method)mtx_rand_matrix, gensym("matrix"), A_GIMME, 0); + class_addlist (mtx_rand_class, mtx_rand_list); + class_addbang (mtx_rand_class, mtx_rand_bang); + + class_addmethod(mtx_rand_class, (t_method)mtx_rand_seed, gensym("seed"), A_FLOAT, 0); + class_sethelpsymbol(mtx_rand_class, gensym("zexy/mtx_rand")); +} + + +/* mtx_scroll */ +/* scroll the rows */ +static t_class *mtx_scroll_class; + +static void mtx_scroll_matrix(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int row=atom_getfloat(argv++); + int col=atom_getfloat(argv++); + int rowscroll = ((int)x->f%row+row)%row; + + if(row*col>argc-2) { + post("mtx_scroll: sparse matrices not yet supported : use \"mtx_check\""); + return; + } + adjustsize(x, row, col); + + memcpy(x->atombuffer+2, argv+(row-rowscroll)*col, rowscroll*col*sizeof(t_atom)); + memcpy(x->atombuffer+2+rowscroll*col, argv, (row-rowscroll)*col*sizeof(t_atom)); + + matrix_bang(x); +} + +static void *mtx_scroll_new(t_symbol *s, int argc, t_atom *argv) +{ + t_matrix *x = (t_matrix *)pd_new(mtx_scroll_class); + floatinlet_new(&x->x_obj, &(x->f)); + outlet_new(&x->x_obj, 0); + + x->f=argc?atom_getfloat(argv):0; + x->col=x->row=0; + x->atombuffer=0; + return (x); +} +static void mtx_scroll_setup(void) +{ + mtx_scroll_class = class_new(gensym("mtx_scroll"), (t_newmethod)mtx_scroll_new, + (t_method)matrix_free, sizeof(t_matrix), 0, A_GIMME, 0); + class_addbang (mtx_scroll_class, matrix_bang); + class_addmethod(mtx_scroll_class, (t_method)mtx_scroll_matrix, gensym("matrix"), A_GIMME, 0); + class_sethelpsymbol(mtx_scroll_class, gensym("zexy/mtx_transpose")); +} + +/* mtx_roll */ +/* roll the rows */ +static t_class *mtx_roll_class; + +static void mtx_roll_matrix(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int row=atom_getfloat(argv++); + int col=atom_getfloat(argv++); + t_atom *ap; + int colroll = ((int)x->f%col+col)%col; + int c; + + if(row*col>argc-2) { + post("mtx_roll: sparse matrices not yet supported : use \"mtx_check\""); + return; + } + + adjustsize(x, row, col); + ap = x->atombuffer+2; + + c=col; + while(c--){ + t_atom *in = argv+col-c-1; + t_atom *out = ap +(col-c-1+colroll)%col; + int r = row; + while (r--){ + SETFLOAT(out, atom_getfloat(in)); + out+=col; + in+=col; + } + + } + + matrix_bang(x); +} + +static void *mtx_roll_new(t_symbol *s, int argc, t_atom *argv) +{ + t_matrix *x = (t_matrix *)pd_new(mtx_roll_class); + floatinlet_new(&x->x_obj, &(x->f)); + outlet_new(&x->x_obj, 0); + + x->f=argc?atom_getfloat(argv):0; + x->col=x->row=0; + x->atombuffer=0; + return (x); +} +static void mtx_roll_setup(void) +{ + mtx_roll_class = class_new(gensym("mtx_roll"), (t_newmethod)mtx_roll_new, + (t_method)matrix_free, sizeof(t_matrix), 0, A_GIMME, 0); + class_addbang (mtx_roll_class, matrix_bang); + class_addmethod(mtx_roll_class, (t_method)mtx_roll_matrix, gensym("matrix"), A_GIMME, 0); + class_sethelpsymbol(mtx_roll_class, gensym("zexy/mtx_transpose")); +} + +/* mtx_transpose */ +static t_class *mtx_transpose_class; + +static void mtx_transpose_matrix(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int row=atom_getfloat(argv++); + int col=atom_getfloat(argv++); + t_atom *ap; + int r, c; + + if(row*col>argc-2) { + post("mtx_transpose: sparse matrices not yet supported : use \"mtx_check\""); + return; + } + if (col*row!=x->col*x->row) { + freebytes(x->atombuffer, (x->col*x->row+2)*sizeof(t_atom)); + x->atombuffer = (t_atom *)getbytes((row*col+2)*sizeof(t_atom)); + } + ap = x->atombuffer+2; + setdimen(x, col, row); + r = row; + while(r--){ + c=col; + while(c--) { + t_float f = atom_getfloat(argv+r*col+c); + SETFLOAT(ap+c*row+r, f); + } + } + + matrix_bang(x); +} + +static void *mtx_transpose_new(t_symbol *s, int argc, t_atom *argv) +{ + t_matrix *x = (t_matrix *)pd_new(mtx_transpose_class); + outlet_new(&x->x_obj, 0); + x->col=x->row=0; + x->atombuffer=0; + return (x); +} +static void mtx_transpose_setup(void) +{ + mtx_transpose_class = class_new(gensym("mtx_transpose"), (t_newmethod)mtx_transpose_new, + (t_method)matrix_free, sizeof(t_matrix), 0, A_GIMME, 0); + class_addbang (mtx_transpose_class, matrix_bang); + class_addmethod(mtx_transpose_class, (t_method)mtx_transpose_matrix, gensym("matrix"), A_GIMME, 0); + class_sethelpsymbol(mtx_transpose_class, gensym("zexy/mtx_transpose")); +} + +/* -------------------------------------------------------------- */ +/* matrix math */ + +typedef struct _mtx_binscalar +{ + t_object x_obj; + + t_matrix m; // the output matrix + t_float f; // the second input +} t_mtx_binscalar; + +typedef struct _mtx_binmtx +{ + t_object x_obj; + + t_matrix m; // the output matrix + t_matrix m2; // the second input +} t_mtx_binmtx; + +static void mtx_bin_matrix2(t_mtx_binmtx *x, t_symbol *s, int argc, t_atom *argv) +{ + int row = atom_getfloat(argv); + int col = atom_getfloat(argv+1); + if (argc<2){post("mtx_bin2: crippled matrix"); return;} + if ((col<1)||(row<1)) {post("mtx_bin2: invalid dimensions %dx%d", row,col); return;} + if (col*row+2>argc){ post("mtx_bin2: sparse matrix not yet supported : use \"mtx_check\""); return;} + + if (row*col!=x->m2.row*x->m2.col) { + freebytes(x->m2.atombuffer, (x->m2.row*x->m2.col+2)*sizeof(t_atom)); + x->m2.atombuffer=copybytes(argv,(row*col+2)*sizeof(t_atom)); + }else memcpy(x->m2.atombuffer, argv, (row*col+2)*sizeof(t_atom)); + setdimen(&x->m2, row, col); +} + +static void mtx_binmtx_bang(t_mtx_binmtx *x) +{ + if((&x->m)&&(x->m.atombuffer)) + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), x->m.col*x->m.row+2, x->m.atombuffer); +} + + +static void mtx_binmtx_free(t_mtx_binmtx *x) +{ + matrix_free(&x->m); + matrix_free(&x->m2); +} +static void mtx_binscalar_bang(t_mtx_binscalar *x) +{ + if((&x->m)&&(x->m.atombuffer)) + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), x->m.col*x->m.row+2, x->m.atombuffer); +} +static void mtx_binscalar_free(t_mtx_binscalar *x) +{ + matrix_free(&x->m); +} + + + +/* mtx_add */ +static t_class *mtx_add_class, *mtx_addscalar_class; + +static void mtx_addscalar_matrix(t_mtx_binscalar *x, t_symbol *s, int argc, t_atom *argv) +{ + int n=argc-2; + int row=atom_getfloat(argv), col=atom_getfloat(argv+1); + + t_float offset=x->f; + t_atom *buf; + t_atom *ap=argv+2; + + if(argc<2){post("mtx_add: crippled matrix");return; } + adjustsize(&x->m, row, col); + + buf=x->m.atombuffer+2; + + while(n--){ + buf->a_type = A_FLOAT; + buf++->a_w.w_float = atom_getfloat(ap++) + offset; + } + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), argc, x->m.atombuffer); +} +static void mtx_addscalar_list(t_mtx_binscalar *x, t_symbol *s, int argc, t_atom *argv) +{ + int n=argc; + t_atom *m; + t_float offset = x->f; + adjustsize(&x->m, 1, argc); + m = x->m.atombuffer; + + while(n--){ + m->a_type = A_FLOAT; + (m++)->a_w.w_float = atom_getfloat(argv++) + offset; + } + outlet_list(x->x_obj.ob_outlet, gensym("list"), argc, x->m.atombuffer); +} + +static void mtx_add_matrix(t_mtx_binmtx *x, t_symbol *s, int argc, t_atom *argv) +{ + int row=atom_getfloat(argv); + int col=atom_getfloat(argv+1); + t_atom *m; + t_atom *m1 = argv+2; + t_atom *m2 = x->m2.atombuffer+2; + int n = argc-2; + + if (argc<2){ post("mtx_add: crippled matrix"); return; } + if ((col<1)||(row<1)) { post("mtx_add: invalid dimensions"); return; } + if (col*row>argc-2){ post("sparse matrix not yet supported : use \"mtx_check\""); return; } + + if (!(x->m2.col*x->m2.row)) { + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), argc, argv); + return; + } + + if ((col!=x->m2.col)||(row!=x->m2.row)){ + post("mtx_add: matrix dimensions do not match"); + /* LATER SOLVE THIS */ + return; + } + adjustsize(&x->m, row, col); + m = x->m.atombuffer+2; + + while(n--){ + t_float f = atom_getfloat(m1++)+atom_getfloat(m2++); + SETFLOAT(m, f); + m++; + } + + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), argc, x->m.atombuffer); +} +static void mtx_add_float(t_mtx_binmtx *x, t_float f) +{ + t_matrix *m=&x->m, *m2=&x->m2; + t_atom *ap, *ap2=m2->atombuffer+2; + int row2, col2, n; + + if (!m2->atombuffer){ post("mulitply with what ?"); return; } + + row2=atom_getfloat(m2->atombuffer); + col2=atom_getfloat(m2->atombuffer+1); + adjustsize(m, row2, col2); + ap=m->atombuffer+2; + + n=row2*col2; + + while(n--){ + SETFLOAT(ap, f+atom_getfloat(ap2++)); + ap++; + } + + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), m->row*m->col+2, m->atombuffer); +} +static void *mtx_add_new(t_symbol *s, int argc, t_atom *argv) +{ + if (argc>1) post("mtx_add : extra arguments ignored"); + if (argc) { + t_mtx_binscalar *x = (t_mtx_binscalar *)pd_new(mtx_addscalar_class); + floatinlet_new(&x->x_obj, &x->f); + x->f = atom_getfloatarg(0, argc, argv); + outlet_new(&x->x_obj, 0); + return(x); + } else { + t_mtx_binmtx *x = (t_mtx_binmtx *)pd_new(mtx_add_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("matrix"), gensym("")); + outlet_new(&x->x_obj, 0); + x->m.col = x->m.row = x->m2.col = x->m2.row = 0; + x->m.atombuffer = x->m2.atombuffer = 0; + return(x); + } +} + +static void mtx_add_setup(void) +{ + mtx_add_class = class_new(gensym("mtx_add"), (t_newmethod)mtx_add_new, (t_method)mtx_binmtx_free, + sizeof(t_mtx_binmtx), 0, A_GIMME, 0); + class_addcreator((t_newmethod)mtx_add_new, gensym("mtx_+"), A_GIMME,0); + class_addmethod(mtx_add_class, (t_method)mtx_add_matrix, gensym("matrix"), A_GIMME, 0); + class_addmethod(mtx_add_class, (t_method)mtx_bin_matrix2, gensym(""), A_GIMME, 0); + class_addfloat (mtx_add_class, mtx_add_float); + class_addbang (mtx_add_class, mtx_binmtx_bang); + + mtx_addscalar_class = class_new(gensym("mtx_add"), 0, (t_method)mtx_binscalar_free, + sizeof(t_mtx_binscalar), 0, 0); + class_addcreator(0, gensym("mtx_+"), 0, 0); + class_addmethod(mtx_addscalar_class, (t_method)mtx_addscalar_matrix, gensym("matrix"), A_GIMME, 0); + class_addlist (mtx_addscalar_class, mtx_addscalar_list); + class_addbang (mtx_addscalar_class, mtx_binscalar_bang); + + class_sethelpsymbol(mtx_add_class, gensym("zexy/mtx_binops")); + class_sethelpsymbol(mtx_addscalar_class, gensym("zexy/mtx_binops")); +} + +/* mtx_sub */ +static t_class *mtx_sub_class, *mtx_subscalar_class; + +static void mtx_subscalar_matrix(t_mtx_binscalar *x, t_symbol *s, int argc, t_atom *argv) +{ + int n=argc-2; + int row=atom_getfloat(argv), col=atom_getfloat(argv+1); + + t_float offset=x->f; + t_atom *buf; + t_atom *ap=argv+2; + + if(argc<2){post("mtx_sub: crippled matrix");return; } + adjustsize(&x->m, row, col); + + buf=x->m.atombuffer+2; + + while(n--){ + buf->a_type = A_FLOAT; + buf++->a_w.w_float = atom_getfloat(ap++) - offset; + } + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), argc, x->m.atombuffer); +} +static void mtx_subscalar_list(t_mtx_binscalar *x, t_symbol *s, int argc, t_atom *argv) +{ + int n=argc; + t_atom *m; + t_float offset = x->f; + adjustsize(&x->m, 1, argc); + m = x->m.atombuffer; + + while(n--){ + m->a_type = A_FLOAT; + (m++)->a_w.w_float = atom_getfloat(argv++) - offset; + } + outlet_list(x->x_obj.ob_outlet, gensym("list"), argc, x->m.atombuffer); +} + +static void mtx_sub_matrix(t_mtx_binmtx *x, t_symbol *s, int argc, t_atom *argv) +{ + int row=atom_getfloat(argv); + int col=atom_getfloat(argv+1); + t_atom *m; + t_atom *m1 = argv+2; + t_atom *m2 = x->m2.atombuffer+2; + int n = argc-2; + + if (argc<2){ post("mtx_sub: crippled matrix"); return; } + if ((col<1)||(row<1)) { post("mtx_sub: invalid dimensions"); return; } + if (col*row>argc-2){ post("sparse matrix not yet supported : use \"mtx_check\""); return; } + + if (!(x->m2.col*x->m2.row)) { + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), argc, argv); + return; + } + + if ((col!=x->m2.col)||(row!=x->m2.row)){ + post("mtx_sub: matrix dimensions do not match"); + /* LATER SOLVE THIS */ + return; + } + adjustsize(&x->m, row, col); + m = x->m.atombuffer+2; + + while(n--){ + t_float f = atom_getfloat(m1++)-atom_getfloat(m2++); + SETFLOAT(m, f); + m++; + } + + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), argc, x->m.atombuffer); +} +static void mtx_sub_float(t_mtx_binmtx *x, t_float f) +{ + t_matrix *m=&x->m, *m2=&x->m2; + t_atom *ap, *ap2=m2->atombuffer+2; + int row2, col2, n; + + if (!m2->atombuffer){ post("mulitply with what ?"); return; } + + row2=atom_getfloat(m2->atombuffer); + col2=atom_getfloat(m2->atombuffer+1); + adjustsize(m, row2, col2); + ap=m->atombuffer+2; + + n=row2*col2; + + while(n--){ + SETFLOAT(ap, f-atom_getfloat(ap2++)); + ap++; + } + + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), m->row*m->col+2, m->atombuffer); +} +static void *mtx_sub_new(t_symbol *s, int argc, t_atom *argv) +{ + if (argc>1) post("mtx_sub : extra arguments ignored"); + if (argc) { + t_mtx_binscalar *x = (t_mtx_binscalar *)pd_new(mtx_subscalar_class); + floatinlet_new(&x->x_obj, &x->f); + x->f = atom_getfloatarg(0, argc, argv); + outlet_new(&x->x_obj, 0); + return(x); + } else { + t_mtx_binmtx *x = (t_mtx_binmtx *)pd_new(mtx_sub_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("matrix"), gensym("")); + outlet_new(&x->x_obj, 0); + x->m.col = x->m.row = x->m2.col = x->m2.row = 0; + x->m.atombuffer = x->m2.atombuffer = 0; + return(x); + } +} + +static void mtx_sub_setup(void) +{ + mtx_sub_class = class_new(gensym("mtx_sub"), (t_newmethod)mtx_sub_new, (t_method)mtx_binmtx_free, + sizeof(t_mtx_binmtx), 0, A_GIMME, 0); + class_addcreator((t_newmethod)mtx_sub_new, gensym("mtx_-"), A_GIMME,0); + class_addmethod(mtx_sub_class, (t_method)mtx_sub_matrix, gensym("matrix"), A_GIMME, 0); + class_addmethod(mtx_sub_class, (t_method)mtx_bin_matrix2, gensym(""), A_GIMME, 0); + class_addfloat (mtx_sub_class, mtx_sub_float); + class_addbang (mtx_sub_class, mtx_binmtx_bang); + + mtx_subscalar_class = class_new(gensym("mtx_sub"), 0, (t_method)mtx_binscalar_free, + sizeof(t_mtx_binscalar), 0, 0); + class_addcreator(0, gensym("mtx_-"), 0, 0); + class_addmethod(mtx_subscalar_class, (t_method)mtx_subscalar_matrix, gensym("matrix"), A_GIMME, 0); + class_addlist (mtx_subscalar_class, mtx_subscalar_list); + class_addbang (mtx_subscalar_class, mtx_binscalar_bang); + + class_sethelpsymbol(mtx_sub_class, gensym("zexy/mtx_binops")); + class_sethelpsymbol(mtx_subscalar_class, gensym("zexy/mtx_binops")); +} + + +/* mtx_mul */ +static t_class *mtx_mul_class, *mtx_mulelement_class, *mtx_mulscalar_class; + +static void mtx_mul_matrix(t_mtx_binmtx *x, t_symbol *s, int argc, t_atom *argv) +{ + t_matrix *m=&x->m, *m2=&x->m2; + t_atom *ap, *ap1=argv+2, *ap2=m2->atombuffer+2; + int row=atom_getfloat(argv), col=atom_getfloat(argv+1); + int row2, col2, n, r, c; + + if (!m2->atombuffer){ post("mulitply with what ?"); return; } + if (argc<2){ post("mtx_mul: crippled matrix"); return; } + if ((col<1)||(row<1)){post("mtx_mul: invalid dimensions"); return; } + if (col*row>argc-2){ post("sparse matrix not yet supported : use \"mtx_check\""); return; } + + row2=atom_getfloat(m2->atombuffer); + col2=atom_getfloat(m2->atombuffer+1); + + if (col!=row2) { post("mtx_mul: matrix dimensions do not match !"); return; } + + adjustsize(m, row, col2); + ap=m->atombuffer+2; + + for(r=0;r<row;r++) + for(c=0;c<col2;c++) { + T_FLOAT sum = 0.f; + for(n=0;n<col;n++)sum+=(T_FLOAT)atom_getfloat(ap1+col*r+n)*atom_getfloat(ap2+col2*n+c); + SETFLOAT(ap+col2*r+c,sum); + } + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), m->row*m->col+2, m->atombuffer); +} + +static void mtx_mul_float(t_mtx_binmtx *x, t_float f) +{ + t_matrix *m=&x->m, *m2=&x->m2; + t_atom *ap, *ap2=m2->atombuffer+2; + int row2, col2, n; + + if (!m2->atombuffer){ post("mulitply with what ?"); return; } + + row2=atom_getfloat(m2->atombuffer); + col2=atom_getfloat(m2->atombuffer+1); + adjustsize(m, row2, col2); + ap=m->atombuffer+2; + + n=row2*col2; + + while(n--){ + SETFLOAT(ap, f*atom_getfloat(ap2++)); + ap++; + } + + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), m->row*m->col+2, m->atombuffer); +} + +static void mtx_mulelement_matrix(t_mtx_binmtx *x, t_symbol *s, int argc, t_atom *argv) +{ + int row=atom_getfloat(argv++); + int col=atom_getfloat(argv++); + t_atom *m; + t_atom *m2 = x->m2.atombuffer+2; + int n = argc-2; + + if (argc<2){ post("mtx_mul: crippled matrix"); return; } + if ((col<1)||(row<1)) { post("mtx_mul: invalid dimensions"); return; } + if (col*row>argc-2){ post("sparse matrix not yet supported : use \"mtx_check\""); return; } + if (!(x->m2.col*x->m2.row)) { + adjustsize(&x->m, row, col); + matrix_set(&x->m, 0); + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), argc, x->m.atombuffer); + return; + } + if ((col!=x->m2.col)||(row!=x->m2.row)){ post("matrix dimension do not match"); /* LATER SOLVE THIS */ return; } + + adjustsize(&x->m, row, col); + m = x->m.atombuffer+2; + + while(n--){ + t_float f = atom_getfloat(argv++)*atom_getfloat(m2++); + SETFLOAT(m, f); + m++; + } + + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), argc, x->m.atombuffer); +} + +static void mtx_mulscalar_matrix(t_mtx_binscalar *x, t_symbol *s, int argc, t_atom *argv) +{ + int n=argc-2; + t_atom *m; + t_float factor = x->f; + int row=atom_getfloat(argv++); + int col=atom_getfloat(argv++); + + if (argc<2){ + post("mtx_mul: crippled matrix"); + return; + } + adjustsize(&x->m, row, col); + m = x->m.atombuffer+2; + + while(n--){ + m->a_type = A_FLOAT; + (m++)->a_w.w_float = atom_getfloat(argv++)*factor; + } + + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), argc, x->m.atombuffer); +} +static void mtx_mulscalar_list(t_mtx_binscalar *x, t_symbol *s, int argc, t_atom *argv) +{ + int n=argc; + t_atom *m; + t_float factor = x->f; + adjustsize(&x->m, 1, argc); + m = x->m.atombuffer; + + while(n--){ + m->a_type = A_FLOAT; + (m++)->a_w.w_float = atom_getfloat(argv++)*factor; + } + outlet_list(x->x_obj.ob_outlet, gensym("list"), argc, x->m.atombuffer); +} + +static void *mtx_mul_new(t_symbol *s, int argc, t_atom *argv) +{ + if (argc>1) post("mtx_mul : extra arguments ignored"); + if (argc) { + t_mtx_binscalar *x = (t_mtx_binscalar *)pd_new(mtx_mulscalar_class); + floatinlet_new(&x->x_obj, &x->f); + x->f = atom_getfloatarg(0, argc, argv); + outlet_new(&x->x_obj, 0); + return(x); + } else { + if (s->s_name[4]=='.') { + /* element mul */ + + t_matrix *x = (t_matrix *)pd_new(mtx_mulelement_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("matrix"), gensym("")); + outlet_new(&x->x_obj, 0); + x->col = x->row = 0; + x->atombuffer = 0; + return(x); + } else { + t_mtx_binmtx *x = (t_mtx_binmtx *)pd_new(mtx_mul_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("matrix"), gensym("")); + outlet_new(&x->x_obj, 0); + x->m.col = x->m.row = x->m2.col = x->m2.row = 0; + x->m.atombuffer = x->m2.atombuffer = 0; + return (x); + } + } +} + +static void mtx_mul_setup(void) +{ + mtx_mul_class = class_new(gensym("mtx_mul"), (t_newmethod)mtx_mul_new, (t_method)mtx_binmtx_free, + sizeof(t_mtx_binmtx), 0, A_GIMME, 0); + class_addcreator((t_newmethod)mtx_mul_new, gensym("mtx_*"), A_GIMME,0); + class_addmethod(mtx_mul_class, (t_method)mtx_mul_matrix, gensym("matrix"), A_GIMME, 0); + class_addmethod(mtx_mul_class, (t_method)mtx_bin_matrix2, gensym(""), A_GIMME, 0); + class_addfloat (mtx_mul_class, mtx_mul_float); + class_addbang (mtx_mul_class, mtx_binmtx_bang); + + mtx_mulelement_class = class_new(gensym("mtx_.*"), (t_newmethod)mtx_mul_new, (t_method)mtx_binmtx_free, + sizeof(t_mtx_binmtx), 0, A_GIMME, 0); + class_addmethod(mtx_mulelement_class, (t_method)mtx_mulelement_matrix, gensym("matrix"), A_GIMME, 0); + class_addmethod(mtx_mulelement_class, (t_method)mtx_bin_matrix2, gensym(""), A_GIMME, 0); + class_addfloat (mtx_mulelement_class, mtx_mul_float); + class_addbang (mtx_mulelement_class, mtx_binmtx_bang); + + mtx_mulscalar_class = class_new(gensym("mtx_mul"), 0, (t_method)mtx_binscalar_free, + sizeof(t_mtx_binscalar), 0, 0); + class_addcreator(0, gensym("mtx_*"), 0, 0); + class_addcreator(0, gensym("mtx_.*"), 0, 0); + class_addmethod(mtx_mulscalar_class, (t_method)mtx_mulscalar_matrix, gensym("matrix"), A_GIMME, 0); + class_addlist (mtx_mulscalar_class, mtx_mulscalar_list); + class_addbang (mtx_mulscalar_class, mtx_binscalar_bang); + + class_sethelpsymbol(mtx_mul_class, gensym("zexy/mtx_binops")); + class_sethelpsymbol(mtx_mulelement_class, gensym("zexy/mtx_binops")); + class_sethelpsymbol(mtx_mulscalar_class, gensym("zexy/mtx_binops")); +} + + +/* mtx_div */ +static t_class *mtx_divelement_class, *mtx_divscalar_class; + +static void mtx_divelement_matrix(t_mtx_binmtx *x, t_symbol *s, int argc, t_atom *argv) +{ + int row=atom_getfloat(argv++); + int col=atom_getfloat(argv++); + t_atom *m; + t_atom *m2 = x->m2.atombuffer+2; + int n = argc-2; + + if (argc<2){ post("mtx_div: crippled matrix"); return; } + if ((col<1)||(row<1)) { post("mtx_div: invalid dimensions"); return; } + if (col*row>argc-2){ post("sparse matrix not yet supported : use \"mtx_check\""); return; } + if (!(x->m2.col*x->m2.row)) { + adjustsize(&x->m, row, col); + matrix_set(&x->m, 0); + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), argc, x->m.atombuffer); + return; + } + if ((col!=x->m2.col)||(row!=x->m2.row)){ post("matrix dimension do not match"); /* LATER SOLVE THIS */ return; } + + adjustsize(&x->m, row, col); + m = x->m.atombuffer+2; + + while(n--){ + t_float f = atom_getfloat(argv++)/atom_getfloat(m2++); + SETFLOAT(m, f); + m++; + } + + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), argc, x->m.atombuffer); +} +static void mtx_divelement_float(t_mtx_binmtx *x, t_float f) +{ + t_matrix *m=&x->m, *m2=&x->m2; + t_atom *ap, *ap2=m2->atombuffer+2; + int row2, col2, n; + + if (!m2->atombuffer){ post("divide by what ?"); return; } + + row2=atom_getfloat(m2->atombuffer); + col2=atom_getfloat(m2->atombuffer+1); + adjustsize(m, row2, col2); + ap=m->atombuffer+2; + + n=row2*col2; + + while(n--){ + SETFLOAT(ap, f/atom_getfloat(ap2++)); + ap++; + } + + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), m->row*m->col+2, m->atombuffer); +} +static void mtx_divscalar_matrix(t_mtx_binscalar *x, t_symbol *s, int argc, t_atom *argv) +{ + int n=argc-2; + t_atom *m; + t_float factor = 1.0/x->f; + int row=atom_getfloat(argv++); + int col=atom_getfloat(argv++); + + if (argc<2){ + post("mtx_div: crippled matrix"); + return; + } + adjustsize(&x->m, row, col); + m = x->m.atombuffer+2; + + while(n--){ + m->a_type = A_FLOAT; + (m++)->a_w.w_float = atom_getfloat(argv++)*factor; + } + + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), argc, x->m.atombuffer); +} +static void mtx_divscalar_list(t_mtx_binscalar *x, t_symbol *s, int argc, t_atom *argv) +{ + int n=argc; + t_atom *m; + t_float factor = 1.0/x->f; + + adjustsize(&x->m, 1, argc); + m = x->m.atombuffer; + + while(n--){ + m->a_type = A_FLOAT; + (m++)->a_w.w_float = atom_getfloat(argv++)*factor; + } + + outlet_list(x->x_obj.ob_outlet, gensym("list"), argc, x->m.atombuffer); +} + +static void *mtx_div_new(t_symbol *s, int argc, t_atom *argv) +{ + if (argc>1) post("mtx_div : extra arguments ignored"); + if (argc) { + /* scalar division */ + t_mtx_binscalar *x = (t_mtx_binscalar *)pd_new(mtx_divscalar_class); + floatinlet_new(&x->x_obj, &x->f); + x->f = atom_getfloatarg(0, argc, argv); + outlet_new(&x->x_obj, 0); + return(x); + } else { + /* element division */ + t_matrix *x = (t_matrix *)pd_new(mtx_divelement_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("matrix"), gensym("")); + outlet_new(&x->x_obj, 0); + x->col = x->row = 0; + x->atombuffer = 0; + return(x); + } +} + +static void mtx_div_setup(void) +{ + mtx_divelement_class = class_new(gensym("mtx_./"), (t_newmethod)mtx_div_new, (t_method)mtx_binmtx_free, + sizeof(t_mtx_binmtx), 0, A_GIMME, 0); + class_addmethod(mtx_divelement_class, (t_method)mtx_divelement_matrix, gensym("matrix"), A_GIMME, 0); + class_addmethod(mtx_divelement_class, (t_method)mtx_bin_matrix2, gensym(""), A_GIMME, 0); + class_addfloat (mtx_divelement_class, mtx_divelement_float); + class_addbang (mtx_divelement_class, mtx_binmtx_bang); + + mtx_divscalar_class = class_new(gensym("mtx_./"), 0, (t_method)mtx_binscalar_free, + sizeof(t_mtx_binscalar), 0, 0); + class_addmethod(mtx_divscalar_class, (t_method)mtx_divscalar_matrix, gensym("matrix"), A_GIMME, 0); + class_addlist (mtx_divscalar_class, mtx_divscalar_list); + class_addbang (mtx_divscalar_class, mtx_binscalar_bang); + + class_sethelpsymbol(mtx_divelement_class, gensym("zexy/mtx_binops")); + class_sethelpsymbol(mtx_divscalar_class, gensym("zexy/mtx_binops")); +} + +/* mtx_inverse */ +static t_class *mtx_inverse_class; + +static void mtx_inverse_matrix(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + /* maybe we should do this in double or long double ? */ + int row=atom_getfloat(argv); + int col=atom_getfloat(argv+1); + int i, k, row2=row*row; + + T_FLOAT *original, *inverted; + T_FLOAT *a1, *a2, *b1, *b2; // dummy pointers + + int ok = 0; + + if(row*col+2>argc){ + post("mtx_print : sparse matrices not yet supported : use \"mtx_check\""); + return; + } + if (row!=col){ + post("mtx_inverse: only square matrices can be inverted"); + return; + } + + // reserve memory for outputting afterwards + adjustsize(x, row, row); + // 1. get the 2 matrices : orig; invert (create as eye, but will be orig^(-1)) + inverted = (T_FLOAT *)getbytes(sizeof(T_FLOAT)*row2); + // 1a extract values of A to float-buf + original=matrix2float(argv); + // 1b make an eye-shaped float-buf for B + i=row2; + b1=inverted; + while(i--)*b1++=0; + i=row; + b1=inverted; + while(i--)b1[i*(row+1)]=1; + + // 2. do the Gauss-Jordan + for (k=0;k<row;k++) { + // 2. adjust current row + T_FLOAT diagel = original[k*(col+1)]; +#if 1 + T_FLOAT i_diagel = diagel?1./diagel:0; + if (!diagel)ok++; +#else + T_FLOAT i_diagel = 1./diagel; +#endif + + /* normalize current row (set the diagonal-element to 1 */ + a2=original+k*col; + b2=inverted+k*col; + i=row; + while(i--){ + *a2++*=i_diagel; + *b2++*=i_diagel; + } + /* eliminate the k-th element in each row by adding the weighted normalized row */ + + a2=original+k*row; + b2=inverted+k*row; + for(i=0;i<row;i++) + if (i-k) { + T_FLOAT f=-*(original+i*row+k); + int j = row; + a1=original+i*row; + b1=inverted+i*row; + while (j--) { + *(a1+j)+=f**(a2+j); + *(b1+j)+=f**(b2+j); + } + } + } + // 3. output the matrix + // 3a convert the floatbuf to an atombuf; + float2matrix(x->atombuffer, inverted); + // 3b destroy the buffers + freebytes(original, sizeof(T_FLOAT)*row2); + + if (ok)post("mtx_inverse: couldn't really invert the matrix !!! %d error%c", ok, (ok-1)?'s':0); + + // 3c output the atombuf; + matrix_bang(x); +} + +static void *mtx_inverse_new(t_symbol *s, int argc, t_atom *argv) +{ + t_matrix *x = (t_matrix *)pd_new(mtx_inverse_class); + outlet_new(&x->x_obj, 0); + x->col=x->row=0; + x->atombuffer=0; + + return (x); +} +static void mtx_inverse_setup(void) +{ + mtx_inverse_class = class_new(gensym("mtx_inverse"), (t_newmethod)mtx_inverse_new, + (t_method)matrix_free, sizeof(t_matrix), 0, A_GIMME, 0); + class_addbang (mtx_inverse_class, matrix_bang); + class_addmethod(mtx_inverse_class, (t_method)mtx_inverse_matrix, gensym("matrix"), A_GIMME, 0); + class_sethelpsymbol(mtx_inverse_class, gensym("zexy/mtx_inverse")); +} + + +/* mtx_pivot */ +static t_class *mtx_pivot_class; + +typedef struct _mtx_pivot +{ + t_object x_obj; + + t_matrix m; // the output matrix + t_matrix m_pre; // the pre -multiply matrix + t_matrix m_post; // the post-multiply matrix + + t_outlet *pivo, *pre, *post; + +} t_mtx_pivot; + +static void mtx_pivot_matrix(t_mtx_pivot *x, t_symbol *s, int argc, t_atom *argv) +{ + int row=atom_getfloat(argv); + int col=atom_getfloat(argv+1); + t_atom *m_pre, *m_post; + int i, j, k; + int min_rowcol = (row<col)?row:col; + T_FLOAT *buffer, *buf; + int *i_pre, *i_post, *i_buf; + + int pivot_row, pivot_col; + + if (argc<2){ post("mtx_pivot: crippled matrix"); return; } + if ((col<1)||(row<1)) { post("mtx_pivot: invalid dimensions"); return; } + if (col*row>argc-2){ post("sparse matrix not yet supported : use \"mtx_check\""); return; } + + adjustsize(&x->m, row, col); + adjustsize(&x->m_pre, row, row); + adjustsize(&x->m_post,col, col); + matrix_set(&x->m_pre, 0); + matrix_set(&x->m_post, 0); + + buffer = matrix2float(argv); + i_pre = (int *)getbytes(sizeof(int)*row); + i_post = (int *)getbytes(sizeof(int)*col); + + /* clear pre&post matrices */ + i=row; + i_buf=i_pre; + while(i--)*i_buf++=row-i-1; + i=col; + i_buf=i_post; + while(i--)*i_buf++=col-i-1; + + /* do the pivot thing */ + + for (k=0; k<min_rowcol-1; k++){ + // 1. find max_element + T_FLOAT max = 0; + pivot_row = pivot_col = k; + + for(i=k; i<row; i++){ + buf=buffer+col*i+k; + + j=col-k; + while(j--){ + T_FLOAT f = fabsf(*buf++); + if (f>max) { + max=f; + pivot_row = i; + pivot_col = col-j-1; + } + } + } + // 2. move max el to [k,k] + // 2a swap rows + if (k-pivot_row) { + T_FLOAT *oldrow=buffer+col*k; + T_FLOAT *newrow=buffer+col*pivot_row; + + i=col; + while(i--){ + T_FLOAT f=*oldrow; + *oldrow++=*newrow; + *newrow++=f; + } + i=i_pre[k]; + i_pre[k]=i_pre[pivot_row]; + i_pre[pivot_row]=i; + } + // 2b swap columns + if (k-pivot_col) { + T_FLOAT *oldcol=buffer+k; + T_FLOAT *newcol=buffer+pivot_col; + + i=row; + while(i--){ + T_FLOAT f=*oldcol; + *oldcol=*newcol; + *newcol=f; + oldcol+=col; + newcol+=col; + } + i=i_post[k]; + i_post[k]=i_post[pivot_col]; + i_post[pivot_col]=i; + } + } + + float2matrix(x->m.atombuffer, buffer); + + i=col; + m_post = x->m_post.atombuffer+2; + while(i--){ + SETFLOAT(m_post+i_post[i]*col+i, 1); + } + i=row; + m_pre = x->m_pre.atombuffer+2; + while(i--)SETFLOAT(m_pre+i_pre[i]+i*col, 1); + + + outlet_anything(x->post, gensym("matrix"), 2+col*col, x->m_post.atombuffer); + outlet_anything(x->pre, gensym("matrix"), 2+row*row, x->m_pre.atombuffer); + outlet_anything(x->pivo , gensym("matrix"), 2+row*col, x->m.atombuffer ); +} + +static void mtx_pivot_free(t_mtx_pivot *x) +{ + matrix_free(&x->m); + matrix_free(&x->m_pre); + matrix_free(&x->m_post); +} + +static void *mtx_pivot_new(void) +{ + t_mtx_pivot *x = (t_mtx_pivot *)pd_new(mtx_pivot_class); + + x->pivo = outlet_new(&x->x_obj, 0); + x->pre = outlet_new(&x->x_obj, 0); + x->post = outlet_new(&x->x_obj, 0); + + x->m.atombuffer = x->m_pre.atombuffer = x->m_post.atombuffer = 0; + x->m.row = x->m.col = x->m_pre.row = x->m_pre.col = x->m_post.row = x->m_post.col = 0; + + return(x); +} + +static void mtx_pivot_setup(void) +{ + mtx_pivot_class = class_new(gensym("mtx_pivot"), (t_newmethod)mtx_pivot_new, (t_method)mtx_pivot_free, + sizeof(t_mtx_pivot), 0, 0, 0); + class_addmethod(mtx_pivot_class, (t_method)mtx_pivot_matrix, gensym("matrix"), A_GIMME, 0); + + class_sethelpsymbol(mtx_pivot_class, gensym("zexy/mtx_transpose")); +} + + +/* -------------------------------------------------------------- */ +/* utilities */ +/* mtx_check */ +static t_class *mtx_check_class; + +static void mtx_check_matrix(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int row=atom_getfloat(argv); + int col=atom_getfloat(argv+1); + t_atom *ap; + int length=row*col, n; + argc-=2; + + if(length>argc) { + /* sparse matrix */ + adjustsize(x, row, col); + matrix_set(x, 0); + argv+=2; + ap=x->atombuffer+2; + n=argc; + while(n--){ + t_float f = atom_getfloat(argv++); + SETFLOAT(ap, f); + ap++; + } + matrix_bang(x); + } else { + SETFLOAT(argv, row); + SETFLOAT(argv+1, col); + ap=argv+2; + n=length; + while(n--){ + t_float f = atom_getfloat(ap); + SETFLOAT(ap, f); + ap++; + } + outlet_anything(x->x_obj.ob_outlet, gensym("matrix"), length+2, argv); + } +} + +static void *mtx_check_new(t_symbol *s, int argc, t_atom *argv) +{ + t_matrix *x = (t_matrix *)pd_new(mtx_check_class); + outlet_new(&x->x_obj, 0); + x->col=x->row=0; + x->atombuffer=0; + return (x); +} +static void mtx_check_setup(void) +{ + mtx_check_class = class_new(gensym("mtx_check"), (t_newmethod)mtx_check_new, + (t_method)matrix_free, sizeof(t_matrix), 0, A_GIMME, 0); + class_addbang (mtx_check_class, matrix_bang); + class_addmethod(mtx_check_class, (t_method)mtx_check_matrix, gensym("matrix"), A_GIMME, 0); + class_sethelpsymbol(mtx_check_class, gensym("zexy/matrix")); +} + +/* mtx_size */ +static t_class *mtx_size_class; +typedef struct _mtx_size +{ + t_object x_obj; + + int row; + int col; + + t_outlet *left, *right; +} t_mtx_size; + +static void mtx_size_matrix(t_mtx_size *x, t_symbol *s, int argc, t_atom *argv) +{ + if(argc<2)return; + outlet_float(x->right, atom_getfloat(argv+1)); + outlet_float(x->left, atom_getfloat(argv)); + +} + +static void *mtx_size_new(t_symbol *s, int argc, t_atom *argv) +{ + t_mtx_size *x = (t_mtx_size *)pd_new(mtx_size_class); + x->left = outlet_new(&x->x_obj, 0); + x->right = outlet_new(&x->x_obj, 0); + + return (x); +} +static void mtx_size_setup(void) +{ + mtx_size_class = class_new(gensym("mtx_size"), (t_newmethod)mtx_size_new, + 0, sizeof(t_mtx_size), 0, A_GIMME, 0); + class_addmethod(mtx_size_class, (t_method)mtx_size_matrix, gensym("matrix"), A_GIMME, 0); + class_sethelpsymbol(mtx_size_class, gensym("zexy/mtx_size")); +} + +/* mtx_print */ +static t_class *mtx_print_class; +static void mtx_print(t_matrix *x, t_symbol *s, int argc, t_atom *argv) +{ + int col, row; + if (argc<2){ + post("mtx_print : crippled matrix"); + return; + } + row = atom_getfloat(argv++); + col = atom_getfloat(argv++); + if(row*col>argc-2){ + post("mtx_print : sparse matrices not yet supported : use \"mtx_check\""); + return; + } + post("matrix:"); + while(row--){ + postatom(col, argv); + argv+=col; + endpost(); + } + endpost(); +} +static void *mtx_print_new(void) +{ + t_matrix *x = (t_matrix *)pd_new(mtx_print_class); + x->row = x->col = 0; + x->atombuffer = 0; + return (x); +} +static void mtx_print_setup(void) +{ + mtx_print_class = class_new(gensym("mtx_print"), (t_newmethod)mtx_print_new, + 0, sizeof(t_matrix), 0, 0, 0); + class_addmethod (mtx_print_class, (t_method)mtx_print, gensym("matrix"), A_GIMME, 0); + class_sethelpsymbol(mtx_print_class, gensym("zexy/matrix")); +} + + +/* -------------- overall setup routine for this file ----------------- */ + +void z_matrix_setup(void) +{ + matrix_setup(); + + mtx_resize_setup(); + mtx_row_setup(); + mtx_col_setup(); + mtx_element_setup(); + + mtx_eye_setup(); + mtx_egg_setup(); + mtx_zeros_setup(); + mtx_ones_setup(); + mtx_diag_setup(); + mtx_diegg_setup(); + mtx_trace_setup(); + + mtx_transpose_setup(); + mtx_scroll_setup(); + mtx_roll_setup(); + + mtx_mean_setup(); + mtx_rand_setup(); + + mtx_add_setup(); + mtx_sub_setup(); + mtx_mul_setup(); + mtx_div_setup(); + mtx_inverse_setup(); + mtx_pivot_setup(); + + mtx_size_setup(); + + mtx_check_setup(); + mtx_print_setup(); + + if (0) debugmtx(0,0,0); /* this is to avoid this compiler warning... */ +} diff --git a/src/z_msgfile.c b/src/z_msgfile.c new file mode 100644 index 0000000..706ed60 --- /dev/null +++ b/src/z_msgfile.c @@ -0,0 +1,791 @@ +/* Copyright 1997-1998 Regents of the University of California. +Permission is granted to use this software for any noncommercial purpose. +For commercial licensing contact the UCSD Technology Transfer Office. + +UC MAKES NO WARRANTY, EXPRESS OR IMPLIED, IN CONNECTION WITH THIS SOFTWARE! + +Written by Miller Puckette (msp@ucsd.edu) +*/ + +#include "zexy.h" +#include <stdio.h> +#include <fcntl.h> +#include <string.h> +#ifdef linux +#include <unistd.h> +#endif +#ifdef NT +#include <io.h> +#endif + +/* ****************************************************************************** */ +/* msgfile : save and load messages... */ + +#define PD_MODE 0 +#define CR_MODE 1 +#define CSV_MODE 2 +/* modi + PD : separate items by ' '; seperate lines by ";\n" + looks like a PD-file + CR : separate items by ' '; seperate lines by " \n" + how you would expect a file to look like + CSV: separate items by ','; seperate lines by " \n" + spreadsheet: each argument gets its own column +*/ + + +typedef struct _msglist { + int n; + t_atom *thislist; + + void *next; + void *previous; +} t_msglist; + +typedef struct _msgfile +{ + t_object x_obj; /* everything */ + t_outlet *x_secondout; /* "done" */ + + int mode; + + + t_msglist *current; /* pointer to our list */ + + t_symbol *x_dir; + t_canvas *x_canvas; + + char eol, separator; + +} t_msgfile; + +static t_class *msgfile_class; + +static int node_wherearewe(t_msgfile *x) +{ + int counter = 0; + t_msglist *cur = x->current; + + while (cur && cur->previous) cur=cur->previous; + + while (cur && cur->next && cur!=x->current) { + counter++; + cur = cur->next; + } + + return (cur->thislist)?counter:-1; +} + +static void write_currentnode(t_msgfile *x, int ac, t_atom *av) +{ + /* append list to the current node list */ + + t_msglist *cur=x->current; + + if (cur) { + t_atom *ap; + int newsize = cur->n + ac; + + ap = (t_atom *)getbytes(newsize * sizeof(t_atom)); + memcpy(ap, cur->thislist, cur->n * sizeof(t_atom)); + cur->thislist = ap; + memcpy(cur->thislist + cur->n, av, ac * sizeof(t_atom)); + + cur->n = newsize; + } +} + +static void clear_currentnode(t_msgfile *x) +{ + t_msglist *dummy = x->current; + t_msglist *nxt; + t_msglist *prv; + + if (!dummy) return; + + freebytes(dummy->thislist, sizeof(dummy->thislist)); + dummy->thislist = 0; + dummy->n = 0; + + prv = dummy->previous; + nxt = dummy->next; + + if (nxt) nxt->previous = prv; + if (prv) prv->next = nxt; + + if (!prv && !nxt) return; + + x->current = (nxt)?nxt:prv; + freebytes(dummy, sizeof(t_msglist)); +} +static void clear_emptynodes(t_msgfile *x) +{ + t_msglist *dummy = x->current; + + if (!x->current) return; + + while (!dummy->thislist && !dummy->next && dummy->previous) dummy=dummy->previous; + + while (x->current && x->current->previous) x->current = x->current->previous; + while (x->current && x->current->next) { + if (!x->current->thislist) clear_currentnode(x); + else x->current = x->current->next; + } + dummy = x->current; +} + +static void add_currentnode(t_msgfile *x) +{ + /* add (after the current node) a node at the current position (do not write the listbuf !!!) */ + t_msglist *newnode = (t_msglist *)getbytes(sizeof(t_msglist)); + t_msglist *prv, *nxt, *cur=x->current; + + newnode->n = 0; + newnode->thislist = 0; + + prv = cur; + nxt = (cur)?cur->next:0; + + newnode->next = nxt; + newnode->previous = prv; + + if (prv) prv->next = newnode; + if (nxt) nxt->previous = newnode; + + + if (x->current->thislist) x->current = newnode; +} +static void insert_currentnode(t_msgfile *x) +{ /* insert (add before the current node) a node (do not write a the listbuf !!!) */ + t_msglist *newnode; + t_msglist *prv, *nxt, *cur = x->current; + + if (!(cur && cur->thislist)) add_currentnode(x); + else { + newnode = (t_msglist *)getbytes(sizeof(t_msglist)); + + newnode->n = 0; + newnode->thislist = 0; + + nxt = cur; + prv = (cur)?cur->previous:0; + + newnode->next = nxt; + newnode->previous = prv; + + if (prv) prv->next = newnode; + if (nxt) nxt->previous = newnode; + + x->current = newnode; + } +} + +static void msgfile_rewind(t_msgfile *x) +{ + while (x->current && x->current->previous) x->current = x->current->previous; +} +static void msgfile_end(t_msgfile *x) +{ + if (!x->current) return; + while (x->current->next) x->current = x->current->next; + +} +static void msgfile_goto(t_msgfile *x, t_float f) +{ + int i = f; + + if (i<0) return; + if (!x->current) return; + while (x->current && x->current->previous) x->current = x->current->previous; + + while (i-- && x->current->next) { + x->current = x->current->next; + } +} +static void msgfile_skip(t_msgfile *x, t_float f) +{ + int i; + int counter = 0; + + t_msglist *dummy = x->current; + while (dummy && dummy->previous) dummy = dummy->previous; + + if (!f) return; + if (!x->current) return; + + while (dummy->next && dummy!=x->current) { + counter++; + dummy=dummy->next; + } + + i = counter + f; + if (i<0) i=0; + + msgfile_goto(x, i); + +} + +static void msgfile_clear(t_msgfile *x) +{ + while (x->current && x->current->previous) x->current = x->current->previous; + + while (x->current && (x->current->previous || x->current->next)) { + clear_currentnode(x); + } + if (x->current->thislist) { + freebytes(x->current->thislist, sizeof(x->current->thislist)); + x->current->n = 0; + } +} + +static void delete_region(t_msgfile *x, int start, int stop) +{ + int n; + int newwhere, oldwhere = node_wherearewe(x); + + /* get the number of lists in the buffer */ + t_msglist *dummy = x->current; + int counter = 0; + + while (dummy && dummy->previous) dummy=dummy->previous; + while (dummy && dummy->next) { + counter++; + dummy = dummy->next; + } + + if ((stop > counter) || (stop == -1)) stop = counter; + if ((stop+1) && (start > stop)) return; + if (stop == 0) return; + + newwhere = (oldwhere < start)?oldwhere:( (oldwhere < stop)?start:start+(oldwhere-stop)); + n = stop - start; + + msgfile_goto(x, start); + + while (n--) clear_currentnode(x); + + if (newwhere+1) msgfile_goto(x, newwhere); + else msgfile_end(x); +} + +static void msgfile_delete(t_msgfile *x, t_symbol *s, int ac, t_atom *av) +{ + if (ac==1) { + int pos = atom_getfloat(av); + int oldwhere = node_wherearewe(x); + + if (pos<0) return; + if (oldwhere > pos) oldwhere--; + + msgfile_goto(x, pos); + clear_currentnode(x); + msgfile_goto(x, oldwhere); + } else if (ac==2) { + int pos1 = atom_getfloat(av++); + int pos2 = atom_getfloat(av); + + if ((pos1 < pos2) || (pos2 == -1)) { + if (pos2+1) delete_region(x, pos1, pos2+1); + else delete_region(x, pos1, -1); + } else { + delete_region(x, pos1+1, -1); + delete_region(x, 0, pos2); + } + } else clear_currentnode(x); +} + +static void msgfile_add(t_msgfile *x, t_symbol *s, int ac, t_atom *av) +{ + msgfile_end(x); + add_currentnode(x); + write_currentnode(x, ac, av); +} +static void msgfile_add2(t_msgfile *x, t_symbol *s, int ac, t_atom *av) +{ + msgfile_end(x); + if (x->current->previous) x->current = x->current->previous; + write_currentnode(x, ac, av); + if (x->current->next) x->current = x->current->next; +} +static void msgfile_append(t_msgfile *x, t_symbol *s, int ac, t_atom *av) +{ + add_currentnode(x); + write_currentnode(x, ac, av); +} +static void msgfile_append2(t_msgfile *x, t_symbol *s, int ac, t_atom *av) +{ + if (x->current->thislist) write_currentnode(x, ac, av); + else msgfile_append(x, s, ac, av); +} +static void msgfile_insert(t_msgfile *x, t_symbol *s, int ac, t_atom *av) +{ + t_msglist *cur = x->current; + insert_currentnode(x); + write_currentnode(x, ac, av); + x->current = cur; +} +static void msgfile_insert2(t_msgfile *x, t_symbol *s, int ac, t_atom *av) +{ + t_msglist *cur = x->current; + if ((x->current) && (x->current->previous)) x->current = x->current->previous; + write_currentnode(x, ac, av); + x->current = cur; +} + +static void msgfile_set(t_msgfile *x, t_symbol *s, int ac, t_atom *av) +{ + msgfile_clear(x); + msgfile_add(x, s, ac, av); +} + +static void msgfile_replace(t_msgfile *x, t_symbol *s, int ac, t_atom *av) +{ + freebytes(x->current->thislist, sizeof(x->current->thislist)); + x->current->thislist = 0; + x->current->n = 0; + write_currentnode(x, ac, av); +} + +static void msgfile_flush(t_msgfile *x) +{ + t_msglist *cur = x->current; + + while (x->current && x->current->previous) x->current=x->current->previous; + while (x->current && x->current->thislist) { + outlet_list(x->x_obj.ob_outlet, gensym("list"), x->current->n, x->current->thislist); + x->current = x->current->next; + } + x->current = cur; +} +static void msgfile_this(t_msgfile *x) +{ + if ((x->current) && (x->current->thislist)) { + outlet_list(x->x_obj.ob_outlet, gensym("list"), x->current->n, x->current->thislist); + } else { + outlet_bang(x->x_secondout); + } +} +static void msgfile_next(t_msgfile *x) +{ + if ((x->current) && (x->current->next)) { + t_msglist *next = x->current->next; + if (next->thislist) + outlet_list(x->x_obj.ob_outlet, gensym("list"), next->n, next->thislist); + else outlet_bang(x->x_secondout); + } else outlet_bang(x->x_secondout); +} +static void msgfile_prev(t_msgfile *x) +{ + if ((x->current) && (x->current->previous)) { + t_msglist *prev = x->current->previous; + if (prev->thislist) + outlet_list(x->x_obj.ob_outlet, gensym("list"), prev->n, prev->thislist); + else outlet_bang(x->x_secondout); + } else outlet_bang(x->x_secondout); +} + +static void msgfile_bang(t_msgfile *x) +{ + msgfile_this(x); + msgfile_skip(x, 1); +} + +static int atomcmp(t_atom *this, t_atom *that) +{ + if (this->a_type != that->a_type) return 1; + + switch (this->a_type) { + case A_FLOAT: + return !(atom_getfloat(this) == atom_getfloat(that)); + break; + case A_SYMBOL: + return strcmp(atom_getsymbol(this)->s_name, atom_getsymbol(that)->s_name); + break; + case A_POINTER: + return !(this->a_w.w_gpointer == that->a_w.w_gpointer); + break; + default: + return 0; + } + + return 1; +} + +static void msgfile_find(t_msgfile *x, t_symbol *s, int ac, t_atom *av) +{ + int searching = 1; + t_msglist *found = x->current; + int actu = 0; + + while ((searching) && (x->current) && (x->current->thislist)) { + int n = x->current->n; + int equal = 1; + t_atom *that = av; + t_atom *this = x->current->thislist; + + if (ac < n) n = ac; + + while (n--) { + if ( (strcmp("*", atom_getsymbol(that)->s_name) && atomcmp(that, this)) ) { + equal = 0; + } + + that++; + this++; + } + + if (equal) { + found = x->current; + outlet_float(x->x_secondout, node_wherearewe(x)); + outlet_list(x->x_obj.ob_outlet, gensym("list"), x->current->n, x->current->thislist); + } + + searching = !(equal); + + if (x->current && x->current->thislist) { + if (x->current->next) x->current = x->current->next; + actu++; + } + } + + if (searching) outlet_bang(x->x_secondout); + x->current = found; +} + +static void msgfile_where(t_msgfile *x) +{ + if (x->current && x->current->thislist) outlet_float(x->x_secondout, node_wherearewe(x)); + else outlet_bang(x->x_secondout); +} +static void msgfile_print(t_msgfile *x) +{ + t_msglist *cur = x->current; + + post("--------- msgfile contents: -----------"); + + while (x->current && x->current->previous) x->current=x->current->previous; + while (x->current) { + t_msglist *dum=x->current; + int i; + startpost(""); + for (i = 0; i < dum->n; i++) { + t_atom *a = dum->thislist + i; + postatom(1, a); + } + endpost(); + x->current = x->current->next; + } + x->current = cur; +} + +static void msgfile_binbuf2listbuf(t_msgfile *x, t_binbuf *bbuf) +{ + int ac = binbuf_getnatom(bbuf); + t_atom *ap = binbuf_getvec(bbuf); + + while (ac--) { + if (ap->a_type == A_SEMI) { + add_currentnode(x); + } else { + write_currentnode(x, 1, ap); + } + ap++; + } + + clear_emptynodes(x); +} + +static void msgfile_read(t_msgfile *x, t_symbol *filename, t_symbol *format) +{ + int rmode = 0; + + int fd; + long readlength, length; + char filnam[MAXPDSTRING]; + char buf[MAXPDSTRING], *bufptr, *readbuf; + + int mode = x->mode; + char separator, eol; + + t_binbuf *bbuf = binbuf_new(); + + if ((fd = open_via_path(canvas_getdir(x->x_canvas)->s_name, + filename->s_name, "", buf, &bufptr, MAXPDSTRING, 0)) < 0) { + error("%s: can't open", filename->s_name); + return; + } + else + close (fd); + + if (!strcmp(format->s_name, "cr")) { + mode = CR_MODE; + } else if (!strcmp(format->s_name, "csv")) { + mode = CSV_MODE; + } else if (!strcmp(format->s_name, "pd")) { + mode = PD_MODE; + } else if (*format->s_name) + error("msgfile_read: unknown flag: %s", format->s_name); + + switch (mode) { + case CR_MODE: + separator = ' '; + eol = ' '; + break; + case CSV_MODE: + separator = ','; + eol = ' '; + break; + default: + separator = ' '; + eol = ';'; + break; + } + + /* open and get length */ + sys_bashfilename(filename->s_name, filnam); + +#ifdef NT + rmode |= O_BINARY; +#endif + + if ((fd = open(filnam, rmode)) < 0) { + error("msgfile_read: unable to open %s", filnam); + return; + } + if ((length = lseek(fd, 0, SEEK_END)) < 0 || lseek(fd, 0,SEEK_SET) < 0 + || !(readbuf = t_getbytes(length))) { + error("msgfile_read: unable to lseek %s", filnam); + close(fd); + return; + } + + /* read */ + if ((readlength = read(fd, readbuf, length)) < length) { + error("msgfile_read: unable to read %s", filnam); + close(fd); + t_freebytes(readbuf, length); + return; + } + + /* close */ + close(fd); + + /* undo separators and eols */ + bufptr=readbuf; + + while (readlength--) { + if (*bufptr == separator) { + *bufptr = ' '; + } + else if ((*bufptr == eol) && (bufptr[1] == '\n')) *bufptr = ';'; + bufptr++; + } + + /* convert to binbuf */ + binbuf_text(bbuf, readbuf, length); + msgfile_binbuf2listbuf(x, bbuf); + + + binbuf_free(bbuf); + t_freebytes(readbuf, length); +} + +static void msgfile_write(t_msgfile *x, t_symbol *filename, t_symbol *format) +{ + char buf[MAXPDSTRING]; + t_binbuf *bbuf = binbuf_new(); + t_msglist *cur = x->current; + + char *mytext = 0, *dumtext; + char filnam[MAXPDSTRING]; + int textlen = 0, i; + + char separator, eol; + int mode = x->mode; + + FILE *f=0; + + while (x->current && x->current->previous) x->current=x->current->previous; + + while(x->current) { + binbuf_add(bbuf, x->current->n, x->current->thislist); + binbuf_addsemi(bbuf); + x->current = x->current->next; + } + x->current = cur; + + canvas_makefilename(x->x_canvas, filename->s_name, + buf, MAXPDSTRING); + + if (!strcmp(format->s_name, "cr")) { + mode = CR_MODE; + } else if (!strcmp(format->s_name, "csv")) { + mode = CSV_MODE; + } else if (!strcmp(format->s_name, "pd")) { + mode = PD_MODE; + } else if (*format->s_name) + error("msgfile_write: unknown flag: %s", format->s_name); + + switch (mode) { + case CR_MODE: + separator = ' '; + eol = ' '; + break; + case CSV_MODE: + separator = ','; + eol = ' '; + break; + default: + separator = ' '; + eol = ';'; + break; + } + + binbuf_gettext(bbuf, &mytext, &textlen); + dumtext = mytext; + i = textlen; + + while(i--) { + if (*dumtext==' ') *dumtext=separator; + if ((*dumtext==';') && (dumtext[1]=='\n')) *dumtext = eol; + dumtext++; + } + + /* open */ + sys_bashfilename(filename->s_name, filnam); + if (!(f = fopen(filnam, "w"))) { + error("msgfile : failed to open %s", filnam); + } else { + /* write */ + if (fwrite(mytext, textlen*sizeof(char), 1, f) < 1) { + error("msgfile : failed to write %s", filnam); + } + } + /* close */ + if (f) fclose(f); + +#if 0 + if (binbuf_write(bbuf, buf, "", cr)) + error("%s: write failed", filename->s_name); +#endif + + binbuf_free(bbuf); +} + +static void msgfile_help(t_msgfile *x) +{ + post("\n%c msgfile\t:: handle and store files of lists", HEARTSYMBOL); + post("goto <n>\t: goto line <n>" + "\nrewind\t\t: goto the beginning of the file" + "\nend\t\t: goto the end of the file" + "\nskip <n>\t: move relatively to current position" + "\nbang\t\t: output current line and move forward" + "\nprev\t\t: output previous line" + "\nthis\t\t: output this line" + "\nnext\t\t: output next line" + "\nflush\t\t: output all lines" + "\nset <list>\t: clear the buffer and add <list>" + "\nadd <list>\t: add <list> at the end of the file" + "\nadd2 <list>\t: append <list> to the last line of the file" + "\nappend <list>\t: append <list> at the current position" + "\nappend2 <list>\t: append <list> to the current line" + "\ninsert <list>\t: insert <list> at the current position" + "\ninsert2 <list>\t: append <list> to position [current-1]" + "\nreplace <list>\t: replace current line by <list>" + "\ndelete [<pos> [<pos2>]]\t: delete lines or regions" + "\nclear\t\t: delete the whole buffer" + "\nwhere\t\t: output current position" + "\nfind <list>\t: search for <list>" + "\nread <file> [<format>]\t: read <file> as <format>" + "\nwrite <file> [<format>]\t: write <file> as <format>" + "\n\t\t: valid <formats> are\t: PD, CR, CSV" + "\n\nprint\t\t: show buffer (for debugging)" + "\nhelp\t\t: show this help"); + post("creation: \"msgfile [<format>]\": <format> defines fileaccess-mode(default is PD)"); +} +static void msgfile_free(t_msgfile *x) +{ + while (x->current && x->current->previous) x->current=x->current->previous; + + msgfile_clear(x); + freebytes(x->current, sizeof(t_msglist)); +} + +static void *msgfile_new(t_symbol *s, int argc, t_atom *argv) +{ + t_msgfile *x = (t_msgfile *)pd_new(msgfile_class); + + /* an empty node indicates the end of our listbuffer */ + x->current = (t_msglist *)getbytes(sizeof(t_msglist)); + x->current->n = 0; + x->current->thislist = 0; + x->current->previous = x->current->next = 0; + + if ((argc==1) && (argv->a_type == A_SYMBOL)) { + if (!strcmp(argv->a_w.w_symbol->s_name, "cr")) x->mode = CR_MODE; + else if (!strcmp(argv->a_w.w_symbol->s_name, "csv")) x->mode = CSV_MODE; + else if (!strcmp(argv->a_w.w_symbol->s_name, "pd")) x->mode = PD_MODE; + else { + error("msgfile: unknown argument %s", argv->a_w.w_symbol->s_name); + x->mode = PD_MODE; + } + } else x->mode = PD_MODE; + + outlet_new(&x->x_obj, &s_list); + x->x_secondout = outlet_new(&x->x_obj, &s_float); + x->x_canvas = canvas_getcurrent(); + + x->eol=' '; + x->separator=','; + return (x); +} + +static void msgfile_setup(void) +{ + msgfile_class = class_new(gensym("msgfile"), (t_newmethod)msgfile_new, + (t_method)msgfile_free, sizeof(t_msgfile), 0, A_GIMME, 0); + class_addmethod(msgfile_class, (t_method)msgfile_goto, gensym("goto"), A_DEFFLOAT, 0); + class_addmethod(msgfile_class, (t_method)msgfile_rewind, gensym("rewind"), 0); + class_addmethod(msgfile_class, (t_method)msgfile_rewind, gensym("begin"), 0); + class_addmethod(msgfile_class, (t_method)msgfile_end, gensym("end"), 0); + + class_addmethod(msgfile_class, (t_method)msgfile_next, gensym("next"), A_DEFFLOAT, 0); + class_addmethod(msgfile_class, (t_method)msgfile_prev, gensym("prev"), A_DEFFLOAT, 0); + + class_addmethod(msgfile_class, (t_method)msgfile_skip, gensym("skip"), A_DEFFLOAT, 0); + + class_addmethod(msgfile_class, (t_method)msgfile_set, gensym("set"), A_GIMME, 0); + + class_addmethod(msgfile_class, (t_method)msgfile_clear, gensym("clear"), 0); + class_addmethod(msgfile_class, (t_method)msgfile_delete, gensym("delete"), A_GIMME, 0); + + class_addmethod(msgfile_class, (t_method)msgfile_add, gensym("add"), A_GIMME, 0); + class_addmethod(msgfile_class, (t_method)msgfile_add2, gensym("add2"), A_GIMME, 0); + class_addmethod(msgfile_class, (t_method)msgfile_append, gensym("append"), A_GIMME, 0); + class_addmethod(msgfile_class, (t_method)msgfile_append2, gensym("append2"), A_GIMME, 0); + class_addmethod(msgfile_class, (t_method)msgfile_insert, gensym("insert"), A_GIMME, 0); + class_addmethod(msgfile_class, (t_method)msgfile_insert2, gensym("insert2"), A_GIMME, 0); + + class_addmethod(msgfile_class, (t_method)msgfile_replace, gensym("replace"), A_GIMME, 0); + + class_addmethod(msgfile_class, (t_method)msgfile_find, gensym("find"), A_GIMME, 0); + + class_addmethod(msgfile_class, (t_method)msgfile_read, gensym("read"), A_SYMBOL, A_DEFSYM, 0); + class_addmethod(msgfile_class, (t_method)msgfile_write, gensym("write"), A_SYMBOL, A_DEFSYM, 0); + class_addmethod(msgfile_class, (t_method)msgfile_print, gensym("print"), 0); + class_addmethod(msgfile_class, (t_method)msgfile_flush, gensym("flush"), 0); + + class_addbang(msgfile_class, msgfile_bang); + class_addmethod(msgfile_class, (t_method)msgfile_this, gensym("this"), 0); + class_addmethod(msgfile_class, (t_method)msgfile_where, gensym("where"), 0); + + class_addmethod(msgfile_class, (t_method)msgfile_help, gensym("help"), 0); + class_sethelpsymbol(msgfile_class, gensym("zexy/msgfile")); + +} + +void z_msgfile_setup(void) +{ + msgfile_setup(); +} + diff --git a/src/z_mtx.c b/src/z_mtx.c new file mode 100644 index 0000000..785c7e9 --- /dev/null +++ b/src/z_mtx.c @@ -0,0 +1,669 @@ +/* 1605:forum::für::umläute:2001 */ + +/* objects for manipulating matrices */ +/* mostly i refer to matlab/octave matrix functions */ + +/* + matrix : basic object : create and store matrices + mtx : alias for matrix + + mtx_resize + mtx_row + mtx_col + mtx_element + + mtx_ones + mtx_zeros + mtx_eye + mtx_egg + + mtx_diag + mtx_diegg + mtx_trace + + mtx_mean + mtx_rand + + mtx_transpose + mtx_scroll + mtx_roll + + mtx_add + mtx_+ + mtx_mul + mtx_* + mtx_.* + mtx_./ + + mtx_inverse + mtx_pivot + + mtx_size + + mtx_check + mtx_print +*/ + +#include "zexy.h" +#include <math.h> + +#ifdef NT +#include <memory.h> +#define fabsf fabs +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +#define VALID_MTX 12450 + +typedef struct _matrix +{ + int row; + int col; + + int valid; + + t_float *buffer; + +} t_matrix; + +/* intern utility functions */ +static void MTX_setdimen(t_matrix *x, int row, int col) +{ + x->col = col; + x->row = row; +} + +static void MTX_adjustsize(t_matrix *m, int desiredRow, int desiredCol) +{ + int col=m->col, row=m->row; + + if (desiredRow<1){ + post("cannot make less than 1 rows"); + desiredRow=1; + } + if (desiredCol<1){ + post("cannot make less than 1 columns"); + desiredCol=1; + } + + if (col*row!=desiredRow*desiredCol){ + if(m->buffer)freebytes(m->buffer, (col*row)*sizeof(t_float)); + m->buffer=(t_float *)getbytes((desiredCol*desiredRow)*sizeof(t_float)); + } + + MTX_setdimen(m, desiredRow, desiredCol); + return; +} + +static void MTX_debugmtx(t_matrix *m, int id) +{ + int i=m->col; + t_float *buf = m->buffer; + while(i--){ + int j=m->row; + startpost("debug%d: ", id); + while(j--) + startpost("%f ", *buf++); + endpost(); + } +} + +static void MTX_freematrix(t_matrix *x) +{ + freebytes(x->buffer, x->row*x->col*sizeof(t_float)); + x->row = x->col = x->valid = 0; +} + +static void outlet_matrix(t_outlet *x, t_matrix *m) +{ + t_gpointer *gp=(t_gpointer *)m; + outlet_pointer(x, gp); +} +static t_matrix *get_inmatrix(t_gpointer *gp) +{ + t_matrix *m = (t_matrix *)gp; + if (m->valid != VALID_MTX){ + error("matrix: no valid matrix passed !"); + return 0; + } + if ((m->col <= 0) || (m->row <= 0)){ + error("matrix: strange dimensions"); + return 0; + } + return m; +} +static void MTX_set(t_matrix *m, t_float f) +{ + t_float *buf=m->buffer; + int size = m->col*m->row; + if(buf)while(size--)*buf++=f; +} + +/* -------------------- matrix ------------------------------ */ + +static t_class *matrix_class; + +typedef struct _mtx +{ + t_object x_obj; + + t_matrix *m; + + int current_row, current_col; /* this makes things easy for the mtx_row & mtx_col...*/ + + t_canvas *x_canvas; /* and for reading / writing */ +} t_mtx; + +/* core functions */ + +static void matrix_bang(t_mtx *x) +{ /* output the matrix */ + post("matrix %dx%d @ %x", x->m->row, x->m->col, x->m->buffer); + outlet_matrix(x->x_obj.ob_outlet, x->m); +} +static void matrix_matrix2(t_mtx *x, t_gpointer *gp) +{ + t_matrix *m = get_inmatrix(gp); + if(!m)return; + + if (x->m->row*x->m->col != m->row*m->col) { + freebytes(x->m->buffer, x->m->row*x->m->col*sizeof(t_float)); + x->m->buffer = copybytes(m->buffer, m->row*m->col*sizeof(t_float)); + } else memcpy(x->m->buffer, m->buffer, m->row*m->col*sizeof(t_float)); + + MTX_setdimen(x->m, m->row, m->col); +} +static void matrix_matrix(t_mtx *x, t_gpointer *gp) +{ + t_matrix *m = get_inmatrix(gp); + if(!m)return; + + matrix_matrix2(x, gp); + outlet_matrix(x->x_obj.ob_outlet, x->m); +} + + +/* basic functions */ + +static void matrix_zeros(t_mtx *x, t_symbol *s, int argc, t_atom *argv) +{ + int col, row; + switch(argc) { + case 0: /* zero out the actual matrix */ + break; + case 1: + row=atom_getfloat(argv); + MTX_adjustsize(x->m, row, row); + break; + default: + row=atom_getfloat(argv++); + col=atom_getfloat(argv); + MTX_adjustsize(x->m, row, col); + } + MTX_set(x->m, 0); + outlet_matrix(x->x_obj.ob_outlet, x->m); +} +static void matrix_ones(t_mtx *x, t_symbol *s, int argc, t_atom *argv) +{ + int col, row; + switch(argc) { + case 0: /* zero out the actual matrix */ + break; + case 1: + row=atom_getfloat(argv); + MTX_adjustsize(x->m, row, row); + break; + default: + row=atom_getfloat(argv++); + col=atom_getfloat(argv); + MTX_adjustsize(x->m, row, col); + } + MTX_set(x->m, 1); + outlet_matrix(x->x_obj.ob_outlet, x->m); +} +static void matrix_eye(t_mtx *x, t_symbol *s, int argc, t_atom *argv) +{ + int col, row, n; + switch(argc) { + case 0: /* zero out the actual matrix */ + break; + case 1: + row=atom_getfloat(argv); + MTX_adjustsize(x->m, row, row); + break; + default: + row=atom_getfloat(argv++); + col=atom_getfloat(argv); + MTX_adjustsize(x->m, row, col); + } + MTX_set(x->m, 0); + + col=x->m->col; + row=x->m->row; + n = (col<row)?col:row; + while(n--)x->m->buffer[n*(1+col)]=1; + outlet_matrix(x->x_obj.ob_outlet, x->m); +} +static void matrix_egg(t_mtx *x, t_symbol *s, int argc, t_atom *argv) +{ + int col, row, n; + switch(argc) { + case 0: /* zero out the actual matrix */ + break; + case 1: + row=atom_getfloat(argv); + MTX_adjustsize(x->m, row, row); + break; + default: + row=atom_getfloat(argv++); + col=atom_getfloat(argv); + MTX_adjustsize(x->m, row, col); + } + MTX_set(x->m, 0); + + col=x->m->col; + row=x->m->row; + n = (col<row)?col:row; + while(n--)x->m->buffer[(n+1)*(col-1)]=1; + outlet_matrix(x->x_obj.ob_outlet, x->m); +} +static void matrix_diag(t_mtx *x, t_symbol *s, int argc, t_atom *argv) +{ + int col=argc; + argv+=argc-1; + if (argc<1) { + post("matrix: no diagonale present"); + return; + } + MTX_adjustsize(x->m, argc, argc); + MTX_set(x->m, 0); + + while(argc--)x->m->buffer[argc*(1+col)]=atom_getfloat(argv--); + outlet_matrix(x->x_obj.ob_outlet, x->m); +} +static void matrix_diegg(t_mtx *x, t_symbol *s, int argc, t_atom *argv) +{ + int col=argc; + argv+=argc-1; + if (argc<1) { + post("matrix: no dieggonale present"); + return; + } + MTX_adjustsize(x->m, argc, argc); + MTX_set(x->m, 0); + while(argc--)x->m->buffer[(argc+1)*(col-1)]=atom_getfloat(argv--); + outlet_matrix(x->x_obj.ob_outlet, x->m); +} +static void matrix_float(t_mtx *x, t_float f) +{ + MTX_set(x->m, f); + outlet_matrix(x->x_obj.ob_outlet, x->m); +} +static void matrix_row(t_mtx *x, t_symbol *s, int argc, t_atom *argv) +{ + t_atom *ap=(t_atom *)getbytes(sizeof(t_atom)*x->m->col); + t_float *mtx_flt; + int row=x->m->row, col=x->m->col; + int r, c; + t_float f; + + switch (argc){ + case 0: /* show all rows as a list of floats */ + for (r=0;r<row;r++){ + mtx_flt = x->m->buffer+r*col; + argv = ap; + c=col; + while(c--){ + SETFLOAT(argv, *mtx_flt); + argv++; + } + outlet_list(x->x_obj.ob_outlet, gensym("row"), col, ap); + } + break; + case 1: /* show this row as a list of floats */ + r=atom_getfloat(argv)-1; + if ((r<0)||(r>=row)){ + post("matrix: row index %d is out of range", r+1); + return; + } + argv=ap; + mtx_flt=x->m->buffer+r*col; + c=col; + while(c--){ + SETFLOAT(argv, *mtx_flt); + argv++; + } + outlet_list(x->x_obj.ob_outlet, gensym("row"), col, ap); + break; + case 2: /* set this row to a constant value */ + r=atom_getfloat(argv)-1; + f=atom_getfloat(argv+1); + if ((r<0)||(r>=row)){ + post("matrix: row index %d is out of range", r+1); + return; + } + mtx_flt = x->m->buffer+r*col; + c=col; + while(c--)*mtx_flt++=f; + outlet_matrix(x->x_obj.ob_outlet, x->m); + default: /* set this row to new values */ + r=atom_getfloat(argv++)-1; + if (argc--<col){ + post("matrix: sparse rows not yet supported : use \"mtx_check\""); + return; + } + if ((r<0)||(r>=row)){ + post("matrix: row index %d is out of range", r+1); + return; + } + mtx_flt=x->m->buffer+col*r; + c=col; + while(c--)*mtx_flt++=atom_getfloat(argv++); + outlet_matrix(x->x_obj.ob_outlet, x->m); + } + freebytes(ap, x->m->col*sizeof(t_atom)); +} +static void matrix_col(t_mtx *x, t_symbol *s, int argc, t_atom *argv) +{ + t_float *mtx_flt; + int row=x->m->row, col=x->m->col; + int c=0, r=0; + t_float f; + t_atom *ap=(t_atom *)getbytes(row*sizeof(t_atom)); + + switch (argc){ + case 0: /* show all columns as a list of floats */ + for (c=0;c<col;c++) { + mtx_flt = x->m->buffer+c; + + for (r=0;r<row;r++)SETFLOAT(&ap[r], mtx_flt[col*r]); + outlet_list(x->x_obj.ob_outlet, gensym("col"), row, ap); + } + break; + case 1:/* show this column as a list of floats */ + c=atom_getfloat(argv)-1; + if ((c<0)||(c>=col)){ + post("matrix: col index %d is out of range", c+1); + return; + } + mtx_flt = x->m->buffer+c; + + for (r=0;r<row;r++)SETFLOAT(&ap[r],x->m->buffer[col*r]); + outlet_list(x->x_obj.ob_outlet, gensym("col"), row, ap); + break; + case 2: /* set this column to a constant value */ + c=atom_getfloat(argv)-1; + f=atom_getfloat(argv+1); + if ((c<0)||(c>=row)){ + post("matrix: col index %d is out of range", c+1); + return; + } + mtx_flt = x->m->buffer+r*col; + c=col; + while(c--){ + *mtx_flt=f; + mtx_flt+=col; + } + outlet_matrix(x->x_obj.ob_outlet, x->m); + default:/* set this column to new values */ + c=atom_getfloat(argv++)-1; + if (argc--<row){ + post("matrix: sparse cols not yet supported : use \"mtx_check\""); + return; + } + if ((c<0)||(c>=col)){ + post("matrix: col index %d is out of range", c+1); + return; + } + mtx_flt=x->m->buffer+c; + r=row; + while(r--){ + *mtx_flt=atom_getfloat(argv++); + mtx_flt+=col; + } + outlet_matrix(x->x_obj.ob_outlet, x->m); + } + freebytes(ap, row*sizeof(t_atom)); +} +static void matrix_element(t_mtx *x, t_symbol *s, int argc, t_atom *argv) +{ + t_float *mtx_flt=x->m->buffer; + int row=x->m->row, col=x->m->col; + int r, c, i=row*col; + + switch (argc){ + case 0: + while(i--)outlet_float(x->x_obj.ob_outlet, *mtx_flt++); + break; + case 1: + r=c=atom_getfloat(argv)-1; + if ((r<0)||(r>=row)){ + post("matrix: row index %d is out of range", r+1); + return; + } + if ((c<0)||(c>=col)){ + post("matrix: col index %d is out of range", c+1); + return; + } + outlet_float(x->x_obj.ob_outlet, mtx_flt[c+r*col]); + break; + case 2: + r=atom_getfloat(argv++)-1; + c=atom_getfloat(argv++)-1; + if ((r<0)||(r>=row)){ post("matrix: row index %d is out of range", r+1); return; } + if ((c<0)||(c>=col)){ post("matrix: col index %d is out of range", c+1); return; } + outlet_float(x->x_obj.ob_outlet, mtx_flt[c+r*col]); + break; + default: + r=atom_getfloat(argv++)-1; + c=atom_getfloat(argv++)-1; + if ((r<0)||(r>=row)){ post("matrix: row index %d is out of range", r+1); return; } + if ((c<0)||(c>=col)){ post("matrix: col index %d is out of range", c+1); return; } + mtx_flt[c+r*col]=atom_getfloat(argv); + outlet_matrix(x->x_obj.ob_outlet, x->m); + } +} + +/* ------------- file I/O ------------------ */ +static void matrix_read(t_mtx *x, t_symbol *filename) +{ + t_binbuf *bbuf = binbuf_new(); + t_atom *ap; + int n; + + if (binbuf_read_via_path(bbuf, filename->s_name, canvas_getdir(x->x_canvas)->s_name, 0)) + error("matrix: failed to read %s", filename->s_name); + + ap=binbuf_getvec(bbuf); + n =binbuf_getnatom(bbuf)-1; + + if ((ap->a_type == A_SYMBOL) && !strcmp(ap->a_w.w_symbol->s_name,"matrix") ){ + /* ok, this looks like a matrix */ + int row = atom_getfloat(ap+1); + int col = atom_getfloat(ap+2); + t_float *mtx_flt; + if (n-2<row*col){ + error("matrix: sparse matrices not supported"); + binbuf_free(bbuf); + return; + } + if (row<1 || col<1){ + error("matrix: illegal matrix dimensions"); + binbuf_free(bbuf); + return; + } + + MTX_adjustsize(x->m, row, col); + ap+=2; + mtx_flt=x->m->buffer; + n=row*col; + while(n--)*mtx_flt++=atom_getfloat(ap++); + } + + binbuf_free(bbuf); +} +static void matrix_write(t_mtx *x, t_symbol *filename) +{ + t_binbuf *bbuf = binbuf_new(); + t_atom atom; + t_float *mtx_flt=x->m->buffer; + char buf[MAXPDSTRING]; + int n; + int r = x->m->row; + int c = x->m->col; + canvas_makefilename(x->x_canvas, filename->s_name, buf, MAXPDSTRING); + + SETSYMBOL(&atom, gensym("matrix")); + binbuf_add(bbuf, 1, &atom); + SETFLOAT (&atom, x->m->row); + binbuf_add(bbuf, 1, &atom); + SETFLOAT (&atom, x->m->col); + binbuf_add(bbuf, 1, &atom); + binbuf_addsemi(bbuf); + n=x->m->row*x->m->col; + while(r--){ + c=x->m->col; + while(c--){ + SETFLOAT(&atom, *mtx_flt++); + binbuf_add(bbuf, 1, &atom); + } + binbuf_addsemi(bbuf); + } + + if (binbuf_write(bbuf, buf, "", 1)){ + error("matrix: failed to write %s", filename->s_name); + } + + binbuf_free(bbuf); +} + +/* ----------------- setup ------------------- */ + +static void matrix_free(t_mtx *x) +{ + MTX_freematrix(x->m); + freebytes(x->m, sizeof(t_matrix)); +} +static void *matrix_new(t_symbol *s, int argc, t_atom *argv) +{ + t_mtx *x = (t_mtx *)pd_new(matrix_class); + int row, col; + + x->m = (t_matrix *)getbytes(sizeof(t_matrix)); + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("pointer"), gensym("")); + outlet_new(&x->x_obj, 0); + + x->m->buffer= 0; + x->m->row = x->m->col = 0; + x->m->valid = VALID_MTX; + x->x_canvas = canvas_getcurrent(); + + switch (argc) { + case 0: + row = col = 0; + break; + case 1: + if (argv->a_type == A_SYMBOL) { + matrix_read(x, argv->a_w.w_symbol); + return(x); + } + row = col = atom_getfloat(argv); + break; + default: + row = atom_getfloat(argv++); + col = atom_getfloat(argv++); + } + + if(row*col){ + MTX_adjustsize(x->m, row, col); + MTX_set(x->m, 0); + } + + return (x); +} + +static void matrix_setup(void) +{ + matrix_class = class_new(gensym("mtx"), (t_newmethod)matrix_new, + (t_method)matrix_free, sizeof(t_mtx), 0, A_GIMME, 0); + + /* the core : functions for matrices */ + class_addmethod (matrix_class, (t_method)matrix_matrix, gensym("matrix"), A_GIMME, 0); + class_addmethod (matrix_class, (t_method)matrix_matrix2, gensym(""), A_GIMME, 0); + + /* the basics : functions for creation */ + class_addmethod (matrix_class, (t_method)matrix_eye, gensym("eye"), A_GIMME, 0); + class_addmethod (matrix_class, (t_method)matrix_diag, gensym("diag"), A_GIMME, 0); + class_addmethod (matrix_class, (t_method)matrix_ones, gensym("ones"), A_GIMME, 0); + class_addmethod (matrix_class, (t_method)matrix_zeros, gensym("zeros"), A_GIMME, 0); + class_addmethod (matrix_class, (t_method)matrix_egg, gensym("egg"), A_GIMME, 0); + class_addmethod (matrix_class, (t_method)matrix_diegg, gensym("diegg"), A_GIMME, 0); + + /* the rest : functions for anything */ + class_addbang (matrix_class, matrix_bang); + class_addfloat (matrix_class, matrix_float); + // class_addlist (matrix_class, matrix_list); + class_addmethod (matrix_class, (t_method)matrix_row, gensym("row"), A_GIMME, 0); + class_addmethod (matrix_class, (t_method)matrix_col, gensym("column"), A_GIMME, 0); + class_addmethod (matrix_class, (t_method)matrix_col, gensym("col"), A_GIMME, 0); + class_addmethod (matrix_class, (t_method)matrix_element, gensym("element"), A_GIMME, 0); + + /* the file functions */ + class_addmethod (matrix_class, (t_method)matrix_write, gensym("write"), A_SYMBOL, 0); + class_addmethod (matrix_class, (t_method)matrix_read , gensym("read") , A_SYMBOL, 0); + + + class_sethelpsymbol(matrix_class, gensym("zexy/mtx")); +} + + +/* mtx_print */ + +static t_class *mtx_print_class; + +typedef struct _m_print +{ + t_object x_obj; + +} t_m_print; +static void mtx_print(t_m_print *x, t_gpointer *gp) +{ + t_matrix *m = get_inmatrix(gp); + int c, r; + t_float *f; + if (!m) return; + + c=m->col; + r=m->row; + f=m->buffer; + + post("matrix %dx%d @ %x", r,c, f); + + while(r--){ + c=m->col; + while(c--)startpost("%f\t", *f++); + endpost(); + } + +} +static void *mtx_print_new(void) +{ + t_m_print *x = (t_m_print *)pd_new(mtx_print_class); + + return (x); +} +static void mtx_print_setup(void) +{ + mtx_print_class = class_new(gensym("m_print"), (t_newmethod)mtx_print_new, + 0, sizeof(t_m_print), 0, 0, 0); + class_addpointer(mtx_print_class, mtx_print); +} + + +void z_mtx_setup(void) +{ + matrix_setup(); + mtx_print_setup(); +} diff --git a/src/z_multiline.c b/src/z_multiline.c new file mode 100644 index 0000000..9226ba1 --- /dev/null +++ b/src/z_multiline.c @@ -0,0 +1,252 @@ +/* + a multiline that MULTIplicates MULTIple signals with "ramped floats" (--> like "line~") + + this is kind of multiplying some streams with the square diagonal matrix : diag*~ + for smooth-results we do this line~ thing + + 1403:forum::für::umläute:2001 +*/ + + +/* i am not sure, whether there is a difference between loop-unrolling by hand or by compiler + * i somehow have the feeling, that doing it by hand increases(!) performance for about 2% + * anyhow, if you think that the compiler can do this job better, just disable the UNROLLED define below + */ +#define UNROLLED + +#include "zexy.h" + +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + + +/* --------------------------- multiline~ ---------------------------------- */ + +static t_class *mline_class; + +typedef struct _mline { + t_object x_obj; + + t_float time; + + int ticksleft; + int retarget; + + t_float msec2tick; + + t_float *value; + t_float *target; + t_float *increment; /* single precision is really a bad */ + + t_float **sigIN; + t_float **sigOUT; + t_float *sigBUF; + int sigNUM; + +} t_mline; + +/* the message thing */ + +static void mline_list(t_mline *x, t_symbol *s, int argc, t_atom *argv) +{ + if (argc>x->sigNUM)x->time=atom_getfloat(argv+argc-1); + + if (x->time <= 0) { + if (argc==1) { + t_float f = atom_getfloat(argv); + int i=x->sigNUM; + while(i--)x->target[i]=x->value[i]=f; + } else { + int offset = (argc<x->sigNUM)?x->sigNUM-argc:0; + int i=offset?argc:x->sigNUM; + while(i--)x->target[i+offset]=x->value[i+offset]=atom_getfloat(argv++); + } + x->ticksleft=x->retarget=x->time=0; + } else { + if (argc==1) { + int i = x->sigNUM; + t_float f = atom_getfloat(argv); + for(i=0;i<x->sigNUM;i++)x->target[i]=f; + } else { + int offset = (argc<x->sigNUM)?x->sigNUM-argc:0; + int i=offset?argc:x->sigNUM; + while(i--)x->target[i+offset]=atom_getfloat(argv++); + } + x->retarget = 1; + } +} + +static void mline_stop(t_mline *x) +{ + int i = x->sigNUM; + while (i--) x->target[i] = x->value[i]; + x->ticksleft = x->retarget = 0; +} + +/* the dsp thing */ + +static t_int *mline_perform(t_int *w) +{ + t_mline *x = (t_mline *)(w[1]); + int n = (int)(w[2]); + + t_float **out = x->sigOUT; + t_float **in = x->sigIN; + t_float *buf = x->sigBUF, *sigBUF = buf; + t_float *inc = x->increment, *increment = inc; + t_float *val = x->value, *value = val; + t_float *tgt = x->target, *target = tgt; + + int sigNUM = x->sigNUM; + + if (x->retarget) { + int nticks = x->time * x->msec2tick; + + if (!nticks) nticks = 1; + x->ticksleft = nticks; + + x->retarget = 0; + } + + if (x->ticksleft) { + int N=n-1; + t_float oneovernos = 1./(x->ticksleft*n); + + int i=sigNUM; + while(i--)*inc++=(*tgt++-*val++)*oneovernos; + + n=-1; + while (n++<N) { + buf = sigBUF; + val = value; + inc = increment; + + i = sigNUM; + while (i--)*buf++=in[i][n]*(*val++ += *inc++); + i=sigNUM; + buf=sigBUF; + while (i--)out[i][n]=*buf++; + } + + if (!--x->ticksleft) { + val = value; + tgt = target; + i = sigNUM; + while(i--)*val++=*tgt++; + } + + } else { /* no ticks left */ + int i = sigNUM; + while (n--) { + i = sigNUM; + val = value; + buf = sigBUF; + while (i--)*buf++=in[i][n]**val++; + i = sigNUM; + buf = sigBUF; + while (i--)out[i][n]=*buf++; + } + } + + return (w+3); +} + + + +static void mline_dsp(t_mline *x, t_signal **sp) +{ + int i = x->sigNUM, n = 0; + t_float **dummy = x->sigIN; + while(i--)*dummy++=sp[n++]->s_vec; + + i = x->sigNUM; + dummy =x->sigOUT; + while(i--)*dummy++=sp[n++]->s_vec; + + x->msec2tick = sp[0]->s_sr / (1000.f * sp[0]->s_n); + dsp_add(mline_perform, 2, x, sp[0]->s_n); +} + + +/* setup/setdown things */ + +static void mline_free(t_mline *x) +{ + freebytes(x->value, sizeof(x->value)); + freebytes(x->target, sizeof(x->target)); + freebytes(x->increment, sizeof(x->increment)); + + freebytes(x->sigIN, sizeof(x->sigIN)); + freebytes(x->sigOUT, sizeof(x->sigOUT)); + freebytes(x->sigBUF, sizeof(x->sigBUF)); +} + + +static void *mline_new(t_symbol *s, int argc, t_atom *argv) +{ + t_mline *x = (t_mline *)pd_new(mline_class); + int i; + + if (!argc) { + argc = 1; + x->time = 0; + } else { + x->time = atom_getfloat(argv+argc-1); + if (x->time < 0) x->time = 0; + + argc--; + if (!argc) argc = 1; + } + + x->sigNUM = argc; + + i = argc-1; + + outlet_new(&x->x_obj, &s_signal); + + while (i--) { + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + outlet_new(&x->x_obj, &s_signal); + } + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("")); + floatinlet_new(&x->x_obj, &x->time); + + x->sigIN = (t_float **)getbytes(x->sigNUM * sizeof(t_float **)); + x->sigOUT = (t_float **)getbytes(x->sigNUM * sizeof(t_float **)); + x->sigBUF = (t_float *)getbytes(x->sigNUM * sizeof(t_float *)); + + x->value = (t_float *)getbytes(x->sigNUM * sizeof(t_float *)); + x->target = (t_float *)getbytes(x->sigNUM * sizeof(t_float *)); + x->increment = (t_float *)getbytes(x->sigNUM * sizeof(t_float *)); + + i = x->sigNUM; + + while (i--) { + x->sigIN[i] = x->sigOUT[i] = 0; + x->increment[i] = 0; + x->value[x->sigNUM-i-1] = x->target[x->sigNUM-i-1] = atom_getfloat(argv+i); + } + + x->msec2tick = x->ticksleft = x->retarget = 0; + + return (x); +} + + + +void z_multiline_setup(void) +{ + mline_class = class_new(gensym("multiline~"), (t_newmethod)mline_new, (t_method)mline_free, + sizeof(t_mline), 0, A_GIMME, 0); + + class_addmethod(mline_class, (t_method)mline_dsp, gensym("dsp"), 0); + class_addmethod(mline_class, nullfn, gensym("signal"), 0); + + class_addmethod(mline_class, (t_method)mline_list, gensym(""), A_GIMME, 0); + class_addmethod(mline_class, (t_method)mline_stop, gensym("stop"), 0); + + class_sethelpsymbol(mline_class, gensym("zexy/multiline~")); +} diff --git a/src/z_multiplex.c b/src/z_multiplex.c new file mode 100644 index 0000000..2c1ec19 --- /dev/null +++ b/src/z_multiplex.c @@ -0,0 +1,171 @@ + +/* 1509:forum::für::umläute:2000 */ + +/* + demux : multiplex the input to a specified output +to do:: mux : demultiplex a specified input to the output +*/ + +#include "zexy.h" +#include <stdio.h> + +/* ------------------------- demux ------------------------------- */ + +/* + a demultiplexer +*/ + +static t_class *demux_class; + +typedef struct _demux +{ + t_object x_obj; + + int n_out; + t_outlet **out, *selected; + + +} t_demux; + +static void demux_select(t_demux *x, t_float f) +{ + int n = ( (f<0) || (f>x->n_out) ) ? 0 : f; + x->selected = x->out[n]; +} + +static void demux_list(t_demux *x, t_symbol *s, int argc, t_atom *argv) +{ + switch (argc) { + case 0: + outlet_bang(x->selected); + break; + case 1: + switch (argv->a_type) { + case A_FLOAT: + outlet_float(x->selected, atom_getfloat(argv)); + break; + case A_SYMBOL: + outlet_symbol(x->selected, atom_getsymbol(argv)); + break; + case A_POINTER: + outlet_pointer(x->selected, argv->a_w.w_gpointer); + break; + default: + outlet_list(x->selected, s, argc, argv); + } + break; + default: + outlet_list(x->selected, s, argc, argv); + } +} +static void demux_any(t_demux *x, t_symbol *s, int argc, t_atom *argv) +{ + outlet_anything(x->selected, s, argc, argv); +} + +static void *demux_new(t_symbol *s, int argc, t_atom *argv) +{ + t_demux *x = (t_demux *)pd_new(demux_class); + int n = (argc < 2)?2:argc; + + x->n_out = n - 1; + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("select")); + x->out = (t_outlet **)getbytes(n * sizeof(t_outlet *)); + + for (n=0; n<=x->n_out; n++) { + x->out[n] = outlet_new(&x->x_obj, 0); + } + + x->selected = x->out[0]; + + return (x); +} + +static void demux_setup(void) +{ + demux_class = class_new(gensym("demultiplex"), (t_newmethod)demux_new, + 0, sizeof(t_demux), 0, A_GIMME, 0); + class_addcreator((t_newmethod)demux_new, gensym("demux"), A_GIMME, 0); + + class_addanything (demux_class, demux_any); + class_addlist (demux_class, demux_list); + + class_addmethod (demux_class, (t_method)demux_select, gensym("select"), A_DEFFLOAT, 0); + + class_sethelpsymbol(demux_class, gensym("zexy/demultiplex")); +} + + +#ifdef MUX +/* ------------------------- mux ------------------------------- */ + +/* + a multiplexer +*/ + +static t_class *mux_class; + +typedef struct _mux +{ + t_object x_obj; + + int n_in; + t_inlet **in, *selected; +} t_mux; + +static void mux_select(t_mux *x, t_float f) +{ + int n = ( (f<0) || (f>x->n_in) ) ? 0 : f; +} + +static void mux_incoming(t_mux *x, t_symbol *s, int argc, t_atom *argv) +{ + error("symbol @ %x", s); +} + +static void *mux_new(t_symbol *s, int argc, t_atom *argv) +{ + t_mux *x = (t_mux *)pd_new(mux_class); + + int n = (argc < 2)?2:argc; + + x->n_in = n; + x->in = (t_inlet **)getbytes(x->n_in * sizeof(t_inlet *)); + + for (n = 0; n<x->n_in; n++) { + char name[8]; + int i = 8; + + while (i--) name[i]=0; + + sprintf(name, "inlet%d", n); + + x->in[n] = inlet_new (&x->x_obj, &x->x_obj.ob_pd, &s_list, gensym(name)); + class_addmethod (mux_class, (t_method)mux_incoming, gensym(name), A_GIMME, 0); + } + + + outlet_new(&x->x_obj, 0); + return (x); +} + +static void mux_setup(void) +{ + mux_class = class_new(gensym("multiplex"), (t_newmethod)mux_new, + 0, sizeof(t_mux), 0, A_GIMME, 0); + class_addcreator((t_newmethod)mux_new, gensym("mux"), A_GIMME, 0); + + class_addfloat (mux_class, (t_method)mux_select); + + class_sethelpsymbol(mux_class, gensym("zexy/multiplex")); +} +#endif + +void z_multiplex_setup(void) +{ + demux_setup(); +#ifdef MUX + mux_setup(); +#endif +} diff --git a/src/z_noise.c b/src/z_noise.c new file mode 100644 index 0000000..8e73d44 --- /dev/null +++ b/src/z_noise.c @@ -0,0 +1,312 @@ +/* + 30041999 + + two bandlimited noise gnerators based on DODGE/JERSE "computer music" c3.9 : RANDI & RANDH + + I do not care for copyrights + (all in all, the used noise~-code (in fact, the pseude-random-code) is from Miller Puckette + and I made only very few modifications so look out for the LICENSE.TXT delivered with + puredata for further (c)-information + + forum für umläute 1999 + + this is in fact the very same as the late "NOISE.C", except that I tried to optimize the code a little + bit(by partially removing those very expensive if..then's in about 15 minutes, so there are thousands of + new bugs very likely + + 14071999 + finally added changing seeds, this is to prevent to noise~-units to output the very same, something quite + unnatural even for pseudo-random-noise +*/ + +#include "zexy.h" +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +/* general */ + +typedef struct _nois +{ + t_object x_obj; + int val; + t_float current; + t_float decrement; + t_float updater; + t_float to_go; +} t_nois; + + +static void set_freq(t_nois *x, t_floatarg freq) +{ + x->updater = (freq > 0) ? sys_getsr() / freq : 1; + if (x->updater < 1) + { + x->updater = 1; + } + x->to_go = 0; +} + + +/* ------------------------ noish~ ----------------------------- */ + +static t_class *noish_class; + +static t_int *noish_perform(t_int *w) +{ + t_nois *x = (t_nois *)(w[1]); + t_float *out = (t_float *)(w[2]); + int n = (int)(w[3]); + + int *vp = (int *)(&x->val); + int i_value = *vp; + t_float f_value = ((float)((i_value & 0x7fffffff) - 0x40000000)) * + (float)(1.0 / 0x40000000); + t_float all_to_go = x->updater; + t_float still_to_go = x->to_go; + + if (all_to_go == 1) + { /* this is "pure white" noise, so we have to calculate each sample */ + while (n--) + { + i_value *= 435898247; + i_value += 382842987; + *out++ = ((float)((i_value & 0x7fffffff) - 0x40000000)) * (float)(1.0 / 0x40000000); + } + } + else + if (n < still_to_go) + { /* signal won't change for the next 64 samples */ + still_to_go -= n; + while (n--) + { + *out++ = f_value; + } + } + else + if (all_to_go + still_to_go > n) + { /* only one update calculation necessary for 64 samples !!! */ + while (still_to_go-- > 0) + { + n--; + *out++ = f_value; + } + + still_to_go += all_to_go + 1; + + i_value *= 435898247; + i_value += 382842987; + f_value = ( (float)((i_value & 0x7fffffff) - 0x40000000) ) * (float)(1.0 / 0x40000000); + + while (n--) + { + still_to_go--; + *out++ = f_value; + } + } + else + { /* anything else */ + while (n--) + { + if (still_to_go-- <= 0) /* update only if all time has elapsed */ + { + still_to_go += all_to_go; + + i_value *= 435898247; + i_value += 382842987; + + f_value = ( (float)((i_value & 0x7fffffff) - 0x40000000) ) * (float)(1.0 / 0x40000000); + } + *out++ = f_value; + } + } + + + *vp = i_value; + x->updater = all_to_go; + x->to_go = still_to_go; + + return (w+4); +} + +static void noish_dsp(t_nois *x, t_signal **sp) +{ + post("sr=%f\nsn=%f", sp[0]->s_sr, sp[0]->s_n); + dsp_add(noish_perform, 3, x, sp[0]->s_vec, sp[0]->s_n); +} + +static void noish_helper(void) +{ + post("\n%c noish~\t:: a bandlimited pseudo-noise generator", HEARTSYMBOL); + post("<freq>\t : sampling-frequency (in Hz)\n" + "'help'\t : view this"); + post("creation : \"noish~ [<freq>]\"\t: ('0'(default) will produce 'white' noise)\n"); + post("note\t : the seed of the pseudo-noise generator changes from\n" + "\t instance to instance, so two noish~-objects created at the\n" + "\t same time will produce dífferent signals, something the original\n" + "\t noise~-object misses\n"); + post("for further details see DODGE/JERSE \"computer music\" c3.9\n"); +} + +static void *noish_new(t_floatarg f) +{ + t_nois *x = (t_nois *)pd_new(noish_class); + + static int init = 307; + x->val = (init *= 13); + + set_freq(x, f); + + outlet_new(&x->x_obj, gensym("signal")); + return (x); +} + +void noish_setup(void) +{ + noish_class = class_new(gensym("noish~"), (t_newmethod)noish_new, 0, sizeof(t_nois), 0, A_DEFFLOAT, 0); + + class_addfloat(noish_class, set_freq); + class_addmethod(noish_class, (t_method)noish_dsp, gensym("dsp"), 0); + + class_addmethod(noish_class, (t_method)noish_helper, gensym("help"), 0); + class_sethelpsymbol(noish_class, gensym("zexy/noish~")); +} + + + +/* ------------------------ noisi~ ----------------------------- */ + +static t_class *noisi_class; + +static t_int *noisi_perform(t_int *w) +{ + t_nois *x = (t_nois *)(w[1]); + t_float *out = (t_float *)(w[2]); + int n = (int)(w[3]); + + int *vp = (int *)(&x->val); /* what the ... */ + int i_value = *vp; + t_float f_value = x->current; + t_float decrement = x->decrement; + t_float all_to_go = x->updater; + t_float still_to_go = x->to_go; + + if (all_to_go == 1) + { /* this is "pure white" noise, so we have to calculate each sample */ + while (n--) + { + i_value *= 435898247; + i_value += 382842987; + *out++ = ((float)((i_value & 0x7fffffff) - 0x40000000)) * (float)(1.0 / 0x40000000); + } + } + else + if (n < still_to_go) + { /* signal won't change for the next 64 samples */ + still_to_go -= n; + while (n--) + { + *out++ = (f_value -= decrement); + } + } + else + if (all_to_go + still_to_go > n) + { /* only one update calculation necessary for 64 samples !!! */ + while (still_to_go-- > 0) + { + n--; + *out++ = (f_value -= decrement); + } + + + still_to_go += all_to_go + 1; + + decrement = ( + (f_value = ((float)((i_value & 0x7fffffff) - 0x40000000)) * (float)(1.0 / 0x40000000)) - + ((float)(((i_value = i_value * 435898247 + 382842987) & 0x7fffffff) - 0x40000000)) * (float)(1.0 / 0x40000000) + ) / all_to_go; + + + while (n--) + { + still_to_go--; + *out++ = (f_value -= decrement); + } + } + else + { /* anything else */ + while (n--) + { + if (still_to_go-- <= 0) /* update only if all time has elapsed */ + { + still_to_go += all_to_go; + + decrement = ( + (f_value = ((float)((i_value & 0x7fffffff) - 0x40000000)) * (float)(1.0 / 0x40000000)) - + ((float)(((i_value = i_value * 435898247 + 382842987) & 0x7fffffff) - 0x40000000)) * (float)(1.0 / 0x40000000) + ) / all_to_go; + } + *out++ = (f_value -= decrement); + } + } + + *vp = i_value; + x->current = f_value; + x->decrement = decrement; + x->to_go = still_to_go; + + return (w+4); +} + +static void noisi_dsp(t_nois *x, t_signal **sp) +{ + dsp_add(noisi_perform, 3, x, sp[0]->s_vec, sp[0]->s_n); +} + + +static void noisi_helper(void) +{ + post("\n%c noisi~\t:: a bandlimited interpolating pseudo-noise generator", HEARTSYMBOL); + post("<freq>\t : sampling-frequency (in Hz)\n" + "'help'\t : view this"); + post("creation : \"noisi~ [<freq>]\"\t: ('0'(default) will produce 'white' noise)\n"); + post("note\t : the seed of the pseudo-noise generator changes from\n" + "\t instance to instance, so two noisi~-objects created at the\n" + "\t same time will produce different signals, something the original\n" + "\t noise~-object misses\n"); + post("for further details see DODGE/JERSE \"computer music\" c3.9\n"); +} + +static void *noisi_new(t_floatarg f) +{ + t_nois *x = (t_nois *)pd_new(noisi_class); + + static int init = 4259; + x->val = (init *= 17); + + set_freq (x, f); + + outlet_new(&x->x_obj, gensym("signal")); + return (x); + +} + +void noisi_setup(void) +{ + noisi_class = class_new(gensym("noisi~"), (t_newmethod)noisi_new, 0, sizeof(t_nois), 0, A_DEFFLOAT, 0); + + class_addfloat(noisi_class, set_freq); + class_addmethod(noisi_class, (t_method)noisi_dsp, gensym("dsp"), 0); + + class_addmethod(noisi_class, (t_method)noisi_helper, gensym("help"), 0); + class_sethelpsymbol(noisi_class, gensym("zexy/noisi~")); +} + +/* global setup routine */ + +void z_noise_setup(void) +{ + noish_setup(); + noisi_setup(); +} diff --git a/src/z_nop.c b/src/z_nop.c new file mode 100644 index 0000000..6fa6ac0 --- /dev/null +++ b/src/z_nop.c @@ -0,0 +1,78 @@ +#include "zexy.h" +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +/* ------------------------ nop~ ----------------------------- */ +/* this will pass trough the signal unchanged except for a delay of 1 block */ + +static t_class *nop_class; + +typedef struct _nop +{ + t_object x_obj; + t_float *buf; + int n; + int toggle; +} t_nop; + +static t_int *nop_perform(t_int *w) +{ + t_float *in = (t_float *)w[1]; + t_float *out = (t_float *)w[2]; + t_nop *x = (t_nop *)w[3]; + int n = x->n; + t_float *rp = x->buf + n * x->toggle, *wp = x->buf + n * (x->toggle ^= 1); + + while (n--) { + *wp++ = *in++; + *out++ = *rp++; + } + + return (w+4); +} + +static void nop_dsp(t_nop *x, t_signal **sp) +{ + if (x->n != sp[0]->s_n) + { + freebytes(x->buf, x->n * 2 * sizeof(t_float)); + + x->buf = (t_float *)getbytes(sizeof(t_float) * 2 * (x->n = sp[0]->s_n)); + } + dsp_add(nop_perform, 3, sp[0]->s_vec, sp[1]->s_vec, x); +} + +static void helper(t_nop *x) +{ + post("%c nop~-object ::\tdo_nothing but delay a signal for 1 block\n" + "\t\t this might be helpful for synchronising signals", HEARTSYMBOL); +} + +static void nop_free(t_nop *x) +{ + freebytes(x->buf, x->n * sizeof(t_float)); +} + + +static void *nop_new() +{ + t_nop *x = (t_nop *)pd_new(nop_class); + outlet_new(&x->x_obj, gensym("signal")); + x->toggle = 0; + x->n = 0; + + return (x); +} + +void z_nop_setup(void) +{ + nop_class = class_new(gensym("nop~"), (t_newmethod)nop_new, (t_method)nop_free, + sizeof(t_nop), 0, A_DEFFLOAT, 0); + class_addmethod(nop_class, nullfn, gensym("signal"), 0); + class_addmethod(nop_class, (t_method)nop_dsp, gensym("dsp"), 0); + + class_addmethod(nop_class, (t_method)helper, gensym("help"), 0); + class_sethelpsymbol(nop_class, gensym("zexy/nop~")); +} diff --git a/src/z_pack.c b/src/z_pack.c new file mode 100644 index 0000000..22a74eb --- /dev/null +++ b/src/z_pack.c @@ -0,0 +1,344 @@ +/* 3108:forum::für::umläute:2000 */ + +/* objects for manipulating packages*/ + +/* + repack : (re)pack floats/symbols/pointers to fixed-length packages + niagara : divides a package into 2 sub-packages + packel : get a specifique element of a package by its index +*/ + +#include "zexy.h" +#ifdef NT +#include <memory.h> +#endif + + +/* -------------------- repack ------------------------------ */ + +/* +(re)pack a sequence of (packages of) atoms into a package of given length + +"bang" gives out the current package immediately +the second inlet lets you change the default package size +*/ + +static t_class *repack_class; + +typedef struct _repack +{ + t_object x_obj; + t_atom *buffer; + int bufsize; + + int outputsize; + int current; +} t_repack; + + +static void repack_set(t_repack *x, t_float f) +{ + /* set the new default size */ + int n = f; + + if (n > 0) { + + /* flush all the newsized packages that are in the buffer */ + t_atom *dumbuf = x->buffer; + int dumcur = x->current; + + while (n <= dumcur) { + outlet_list(x->x_obj.ob_outlet, gensym("list"), n, dumbuf); + dumcur -= n; + dumbuf += n; + } + + if (dumcur < 0) error("this should never happen :: dumcur = %d < 0", dumcur); + else { + memcpy(x->buffer, dumbuf, dumcur * sizeof(t_atom)); + x->current = dumcur; + } + + if (n > x->bufsize) { + dumbuf = (t_atom *)getbytes(n * sizeof(t_atom)); + memcpy(dumbuf, x->buffer, x->current * sizeof(t_atom)); + freebytes(x->buffer, x->bufsize * sizeof(t_atom)); + x->buffer = dumbuf; + x->bufsize = n; + } + + x->outputsize = n; + } +} + +static void repack_bang(t_repack *x) +{ + /* output the list as far as we are now */ + outlet_list(x->x_obj.ob_outlet, gensym("list"), x->current, x->buffer); + x->current = 0; +} + +static void repack_float(t_repack *x, t_float f) +{ + /* add a float-atom to the list */ + SETFLOAT(&x->buffer[x->current], f); + x->current++; + if (x->current >= x->outputsize) repack_bang(x); +} + +static void repack_symbol(t_repack *x, t_symbol *s) +{ + /* add a sym-atom to the list */ + SETSYMBOL(&x->buffer[x->current], s); + x->current++; + if (x->current >= x->outputsize) repack_bang(x); +} +static void repack_pointer(t_repack *x, t_gpointer *p) +{ + /* add a pointer-atom to the list */ + SETPOINTER(&x->buffer[x->current], p); + x->current++; + if (x->current >= x->outputsize) repack_bang(x); +} +static void repack_list(t_repack *x, t_symbol *s, int argc, t_atom *argv) +{ + int remain = x->outputsize - x->current; + t_atom *ap = argv; + + if (argc >= remain) { + memcpy(x->buffer+x->current, ap, remain * sizeof(t_atom)); + ap += remain; + argc -= remain; + outlet_list(x->x_obj.ob_outlet, gensym("list"), x->outputsize, x->buffer); + x->current = 0; + } + + while (argc >= x->outputsize) { + outlet_list(x->x_obj.ob_outlet, gensym("list"), x->outputsize, ap); + ap += x->outputsize; + argc -= x->outputsize; + } + + memcpy(x->buffer + x->current, ap, argc * sizeof(t_atom)); + x->current += argc; +} +static void repack_anything(t_repack *x, t_symbol *s, int argc, t_atom *argv) +{ + SETSYMBOL(&x->buffer[x->current], s); + x->current++; + + if (x->current >= x->outputsize) { + repack_bang(x); + } + repack_list(x, gensym("list"), argc, argv); +} + +static void *repack_new(t_floatarg f) +{ + t_repack *x = (t_repack *)pd_new(repack_class); + + + + x->outputsize = x->bufsize = (f>0.f)?f:2 ; + x->current = 0; + + + x->buffer = (t_atom *)getbytes(x->bufsize * sizeof(t_atom)); + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("")); + outlet_new(&x->x_obj, 0); + + return (x); +} + +static void repack_setup(void) +{ + repack_class = class_new(gensym("repack"), (t_newmethod)repack_new, + 0, sizeof(t_repack), 0, A_DEFFLOAT, 0); + + class_addbang (repack_class, repack_bang); + class_addfloat (repack_class, repack_float); + class_addsymbol (repack_class, repack_symbol); + class_addpointer (repack_class, repack_pointer); + class_addlist (repack_class, repack_list); + class_addanything(repack_class, repack_anything); + class_addmethod (repack_class, (t_method)repack_set, gensym(""), A_DEFFLOAT, 0); + + class_sethelpsymbol(repack_class, gensym("zexy/repack")); +} + +/* ------------------------- niagara ------------------------------- */ + +/* +divides a package into 2 sub-packages at a specified point +like the niagara-falls, some water goes down to the left side, the rest to the right side, devided by the rock +*/ + +static t_class *niagara_class; + +typedef struct _niagara +{ + t_object x_obj; + t_float rock; + t_outlet *left, *right; +} t_niagara; + +static void niagara_list(t_niagara *x, t_symbol *s, int argc, t_atom *argv) +{ + int n_l, n_r; + t_atom *ap_l, *ap_r; + int dumrock = x->rock; + int rock = ((dumrock < 0.f)?(argc+dumrock):dumrock); + + n_l = (rock < argc)?rock:argc; + ap_l = argv; + + n_r = argc - n_l; + ap_r = &argv[n_l]; + + if (n_r) outlet_list(x->right, s, n_r, ap_r); + if (n_l) outlet_list(x->left, s, n_l, ap_l); +} + +static void niagara_any(t_niagara *x, t_symbol *s, int argc, t_atom *argv) +{ + int n_l, n_r; + t_atom *ap_l, *ap_r; + t_symbol *s_r, *s_l; + int dumrock = x->rock; + int rock = ((dumrock < 0.f)?(argc+dumrock):dumrock-1); + + n_l = (rock < argc)?rock:argc; + ap_l = argv; + s_l = s; + + n_r = argc - n_l; + ap_r = &argv[n_l]; + + if (n_r) { + s_r = 0; + if (ap_r->a_type == A_FLOAT) s_r = gensym("list"); + else { + s_r = atom_getsymbol(ap_r); + ap_r++; + n_r--; + } + outlet_anything(x->right, s_r, n_r, ap_r); + } + + if (n_l+1 ) outlet_anything(x->left, s_l, n_l, ap_l); +} + +static void *niagara_new(t_floatarg f) +{ + t_niagara *x = (t_niagara *)pd_new(niagara_class); + + x->rock = f; + + x->left = outlet_new(&x->x_obj, &s_list); + x->right = outlet_new(&x->x_obj, &s_list); + + floatinlet_new(&x->x_obj, &x->rock); + + return (x); +} + +static void niagara_setup(void) +{ + niagara_class = class_new(gensym("niagara"), (t_newmethod)niagara_new, + 0, sizeof(t_niagara), 0, A_DEFFLOAT, 0); + + class_addlist (niagara_class, niagara_list); + class_addanything(niagara_class, niagara_any); + + class_sethelpsymbol(niagara_class, gensym("zexy/niagara")); +} + +/* ------------------------- packel ------------------------------- */ + +/* +get the nth element of a package +*/ + +static t_class *packel_class; + +typedef struct _packel +{ + t_object x_obj; + t_float position; +} t_packel; + +static void packel_list(t_packel *x, t_symbol *s, int argc, t_atom *argv) +{ + int mypos = x->position; + + if (mypos) { + t_atom *current; + int pos = (mypos < 0)?(argc+mypos):(mypos-1); + + if (pos < 0) pos = 0; + else if (pos >= argc) pos = argc - 1; + + current = &(argv[pos]); + + switch (current->a_type) { + case A_FLOAT: + outlet_float(x->x_obj.ob_outlet, atom_getfloat(current)); + break; + case A_SYMBOL: + outlet_symbol(x->x_obj.ob_outlet, atom_getsymbol(current)); + break; + case A_POINTER: + outlet_pointer(x->x_obj.ob_outlet, current->a_w.w_gpointer); + break; + case A_NULL: + outlet_bang(x->x_obj.ob_outlet); + default: + ; + } + } else outlet_list(x->x_obj.ob_outlet, s, argc, argv); +} + +static void packel_anything(t_packel *x, t_symbol *s, int argc, t_atom *argv) +{ + t_atom *av2 = (t_atom *)getbytes((argc + 1) * sizeof(t_atom)); + int i; + + for (i = 0; i < argc; i++) + av2[i + 1] = argv[i]; + SETSYMBOL(av2, s); + packel_list(x, gensym("list"), argc+1, av2); + freebytes(av2, (argc + 1) * sizeof(t_atom)); +} + +static void *packel_new(t_floatarg f) +{ + t_packel *x = (t_packel *)pd_new(packel_class); + outlet_new(&x->x_obj, 0); + floatinlet_new(&x->x_obj, &x->position); + x->position = (int) f; + + return (x); +} + +static void packel_setup(void) +{ + packel_class = class_new(gensym("packel"), (t_newmethod)packel_new, + 0, sizeof(t_packel), 0, A_DEFFLOAT, 0); + + class_addlist (packel_class, packel_list); + class_addanything(packel_class, packel_anything); + + class_sethelpsymbol(packel_class, gensym("zexy/packel")); +} + +/* -------------- overall setup routine for this file ----------------- */ + +void z_pack_setup(void) +{ + repack_setup(); + niagara_setup(); + packel_setup(); + + /* I don't supply HELP - functionality, since this might harm overall-performance ere */ +} diff --git a/src/z_pdf.c b/src/z_pdf.c new file mode 100644 index 0000000..dc6fbfe --- /dev/null +++ b/src/z_pdf.c @@ -0,0 +1,128 @@ +/* get the ProbabilityDensityFunction of a signal */ + +#include "zexy.h" + +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +/* ------------------------ pdf~ ----------------------------- */ + +static t_class *pdf_class; + +typedef struct _pdf +{ + t_object x_obj; + + t_float *buf; + int size; + t_float halfsize; +} t_pdf; + +static void clear_pdfbuf(t_pdf *x) +{ + int n = x->size; + t_float *buf = x->buf; + + while (n--) *buf++=0.; +} + +static void pdf_bang(t_pdf *x) +{ + int n = x->size; + t_float *buf = x->buf, max = 0; + t_atom a[2]; + + while (n--) if (max < *buf++) max = buf[-1]; + + n=x->size; + buf = x->buf; + + if (max==0.) max=1.; + max = 1./max; + + while (n--) + { + SETFLOAT(a, *buf++*max); + SETFLOAT(a+1,x->size-n-1); + outlet_list(x->x_obj.ob_outlet, &s_list, 2, (t_atom*)&a); + } +} + +static void pdf_float(t_pdf *x, t_floatarg f) +{ + if (f) pdf_bang(x); else clear_pdfbuf(x); +} + +static t_int *pdf_perform(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_pdf *x = (t_pdf *)(w[2]); + int n = (int)(w[3]); + + t_float *buf = x->buf; + t_float halfsize = x->halfsize; + + while (n--) + { + t_float f = *in++; + int index = ((f + 1.0) * halfsize)+0.5; + buf[(index<0)?0:((index>=x->size)?x->size-1:index)]+=1.; + } + return (w+4); +} + +static void pdf_dsp(t_pdf *x, t_signal **sp) +{ + x->halfsize = (x->size - 1) / 2.0; + + dsp_add(pdf_perform, 3, sp[0]->s_vec, x, sp[0]->s_n); +} + +static void *pdf_new(t_floatarg f) +{ + int i = f; + t_pdf *x = (t_pdf *)pd_new(pdf_class); + t_float *buf; + + x->size = (i)?i:64; + x->buf = (t_float *)getbytes(x->size * sizeof(t_float)); + buf = x->buf; + clear_pdfbuf(x); + + outlet_new(&x->x_obj, &s_list); + + return (x); +} + +static void pdf_free(t_pdf *x) +{ + freebytes(x->buf, x->size*sizeof(t_float)); +} + +static void helper(void) +{ + post("\n%c pdf~\t:: get the probability density function of a signal (-1.0 to +1.0)", HEARTSYMBOL); + post("'bang'\t : output a list of the probabilities of 'n' function values" + "\n'clear'\t : clear the buffer (set all probabilities to zero)" + "\n<1/0>\t : short for 'bang' and 'clear'" + "\n'help'\t : view this"); + post("creation :: 'pdf~ [<n>]':: get the pdf for <n> (default: 64) values"); +} + +void z_pdf_setup(void) +{ + pdf_class = class_new(gensym("pdf~"), (t_newmethod)pdf_new, (t_method)pdf_free, + sizeof(t_pdf), 0, A_DEFFLOAT, 0); + + class_addmethod(pdf_class, nullfn, gensym("signal"), 0); + class_addmethod(pdf_class, (t_method)pdf_dsp, gensym("dsp"), 0); + + class_addmethod(pdf_class, (t_method)pdf_bang, gensym("bang"), 0); + class_addmethod(pdf_class, (t_method)clear_pdfbuf, gensym("clear"), 0); + class_addfloat(pdf_class, pdf_float); + + class_addmethod(pdf_class, (t_method)helper, gensym("help"), 0); + class_sethelpsymbol(pdf_class, gensym("zexy/pdf~")); +} diff --git a/src/z_point.c b/src/z_point.c new file mode 100644 index 0000000..f313805 --- /dev/null +++ b/src/z_point.c @@ -0,0 +1,110 @@ +/* + (c) 1202:forum::für::umläute:2000 + + "time" gets the current time from the system + "date" gets the current date from the system + +*/ + +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +#include "zexy.h" + +typedef struct _inner +{ + int n; + t_float f; +} t_inner; + +/* ----------------------- test --------------------- */ + +static t_class *test_class; + +typedef struct _test +{ + t_object x_obj; + + t_inner *val; + +} t_test; + +static void *test_new(t_symbol *s, int argc, t_atom *argv) +{ + t_test *x = (t_test *)pd_new(test_class); + + x->val = (t_inner *)getbytes(sizeof(t_inner)); + + outlet_new(&x->x_obj, 0); + + return (x); +} + +static void test_point(t_test *x, t_gpointer *gp ) +{ + t_inner *a=(t_inner *)gp; + // post("got pointer to %x or %x", gp, a); + + post("reading @ %x & %x............... f=%f n=%d", &(a->f), &(a->n), a->f, a->n); + + outlet_float(x->x_obj.ob_outlet, a->f); + outlet_float(x->x_obj.ob_outlet, (t_float)a->n); + +} + +static void test_float(t_test *x,t_floatarg f ) +{ + t_gpointer *gp; + t_inner *a; + + x->val->f = f; + x->val->n = f; + + gp=(t_gpointer *)(x->val); + + // post("set pointer to %x or %x", x->val, gp); + + outlet_pointer(x->x_obj.ob_outlet, gp); + + // post("setted at %x", gp); + + a = (t_inner *)gp; + // post("yes %f at %x", a->f, a); + +} +static void test_bang(t_test *x) +{ + post("bang"); + + outlet_pointer(x->x_obj.ob_outlet, (t_gpointer *)x->val); +} + +static void help_test(t_test *x) +{ +} + +void test_setup(void) +{ + test_class = class_new(gensym("test"), + (t_newmethod)test_new, 0, + sizeof(t_test), 0, A_GIMME, 0); + + class_addbang(test_class, test_bang); + class_addpointer(test_class, test_point); + class_addfloat(test_class, test_float); + + class_addmethod(test_class, (t_method)help_test, gensym("help"), 0); + class_sethelpsymbol(test_class, gensym("zexy/test")); + +} + + +/* general setup */ + + +void z_point_setup(void) +{ + test_setup(); +} diff --git a/src/z_prime.c b/src/z_prime.c new file mode 100644 index 0000000..2af18b2 --- /dev/null +++ b/src/z_prime.c @@ -0,0 +1,50 @@ +#include "zexy.h" +#include <math.h> + + +static t_class *prime_class; + +typedef struct _prime { + t_object x_obj; +} t_prime; + + +void prime_float(t_prime *x, t_float f) +{ + + unsigned int i=f; + unsigned int max_divisor; + int divisor=1; + + if (f<2)return; + + if (!(i%2)){ + if (i==2)outlet_bang(x->x_obj.ob_outlet); + return; + } + + max_divisor = sqrt(f)+1; + + while ((divisor+=2)<max_divisor) + if (!(i%divisor)) return; + + outlet_bang(x->x_obj.ob_outlet); +} + +void *prime_new(void) +{ + t_prime *x = (t_prime *)pd_new(prime_class); + + outlet_new(&x->x_obj, &s_float); + + return (void *)x; +} + +void z_prime_setup(void) { + prime_class = class_new(gensym("prime"), + (t_newmethod)prime_new, + 0, sizeof(t_prime), + CLASS_DEFAULT, 0); + + class_addfloat(prime_class, prime_float); +} diff --git a/src/z_quantize.c b/src/z_quantize.c new file mode 100644 index 0000000..a66c1eb --- /dev/null +++ b/src/z_quantize.c @@ -0,0 +1,99 @@ +/* + the long waited for quantize~-object that quantizes in many possible (but equal) steps + of course, we´ll make a comfortable quantize of the float-signal for 16bit and 8bit + + 1110:forum::für::umläute:1999 + */ + +#include "zexy.h" +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +/* ------------------------ quantize~ ----------------------------- */ + +static t_class *quantize_class; + +typedef struct _quantize +{ + t_object x_obj; + t_float quantiz, dequantiz; +} t_quantize; + +static void quantize_float(t_quantize *x, t_floatarg f) +{ + x->quantiz = f; + x->dequantiz = 1./f; +} + +static void quantize_16bit(t_quantize *x) +{ + x->quantiz = 32768.; + x->dequantiz = 1./32768.; +} + +static void quantize_8bit(t_quantize *x) +{ + x->quantiz = 128.; + x->dequantiz = 1./128.; +} + +static t_int *quantize_perform(t_int *w) +{ + t_quantize *x = (t_quantize *)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + + t_float quantiz = x->quantiz, dequantiz = x->dequantiz; + + if (quantiz) + while (n--) *out++ = dequantiz*(int)(quantiz**in++); + else while (n--) *out++ = *in++; + + return (w+5); +} + +static void quantize_dsp(t_quantize *x, t_signal **sp) +{ + dsp_add(quantize_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); +} + +static void helper(t_quantize *x) +{ + post("%c quantize~-object\t:: used for quantizing signals by various degrees", HEARTSYMBOL); + post("<quants> : quantize a signal into <quants> steps ('0' turns quantizing off)\n" + "'8bit' : quantize to 8 bit\n" + "'16bit' : quantize to 16 bit (default)\n" + "'float' : pass-through the signal unchanged\n" + "'help' : view this\n" + "signal~\n"); + post("creation:: \"quantize~ [<quants>]\""); + +} + +static void *quantize_new(t_floatarg f) +{ + t_quantize *x = (t_quantize *)pd_new(quantize_class); + outlet_new(&x->x_obj, gensym("signal")); + if (f) quantize_float(x, f); + else quantize_16bit(x); + + return (x); +} + +void z_quantize_setup(void) +{ + quantize_class = class_new(gensym("quantize~"), (t_newmethod)quantize_new, 0, + sizeof(t_quantize), 0, A_DEFFLOAT, 0); + class_addmethod(quantize_class, nullfn, gensym("signal"), 0); + class_addmethod(quantize_class, (t_method)quantize_dsp, gensym("dsp"), 0); + + class_addfloat(quantize_class, quantize_float); + class_addmethod(quantize_class, (t_method)quantize_8bit, gensym("8bit"), 0); + class_addmethod(quantize_class, (t_method)quantize_16bit, gensym("16bit"), 0); + + class_addmethod(quantize_class, (t_method)helper, gensym("help"), 0); + class_sethelpsymbol(quantize_class, gensym("zexy/quantize~")); +} diff --git a/src/z_random.c b/src/z_random.c new file mode 100644 index 0000000..9a4bb9e --- /dev/null +++ b/src/z_random.c @@ -0,0 +1,143 @@ + +/* 1008:forum::für::umläute:2001 */ + +/* + urn : "generate random numbers without duplicates" + very max-like +*/ + +#include "zexy.h" + +/* ------------------------- urn ------------------------------- */ + +static t_class *urn_class; + +typedef struct _urn +{ + t_object x_obj; + unsigned int x_seed; /* the seed of the generator */ + + unsigned int x_range; /* max. random-number + 1 */ + unsigned int x_count; /* how many random numbers have we generated ? */ + char *x_state; /* has this number been generated already ? */ + + t_outlet *x_floatout, *x_bangout; + char x_noauto; +} t_urn; + +static int makeseed(void) +{ + static unsigned int random_nextseed = 1489853723; + random_nextseed = random_nextseed * 435898247 + 938284287; + return (random_nextseed & 0x7fffffff); +} + +static void makestate(t_urn *x, unsigned int newrange) +{ + if (x->x_range == newrange)return; + + if (x->x_range && x->x_state) { + freebytes(x->x_state, sizeof(char)*x->x_range); + x->x_state=0; + } + + x->x_range=newrange; + x->x_state=getbytes(sizeof(char)*x->x_range); +} + +static void urn_clear(t_urn *x) +{ + unsigned int i=x->x_range; + char *dummy=x->x_state; + if (!dummy || !i)return; + while(i--)*dummy++=0; + x->x_count=0; +} +static void urn_bang(t_urn *x) +{ + int range = (x->x_range<1?1:x->x_range); + unsigned int randval = x->x_seed; + + int nval, used=1; + + if (x->x_count>=range){ + outlet_bang(x->x_bangout); + if (x->x_noauto)return; + urn_clear(x); + } + + while (used) { + randval = randval * 472940017 + 832416023; + nval = ((double)range) * ((double)randval) + * (1./4294967296.); + if (nval >= range) nval = range-1; + used=x->x_state[nval]; + } + + x->x_count++; + x->x_state[nval]=1; + x->x_seed = randval; + outlet_float(x->x_floatout, nval); +} + +static void urn_flt2(t_urn *x, t_float f) +{ + unsigned int range = (f<1)?1:f; + makestate(x, range); + urn_clear(x); +} + + +static void urn_seed(t_urn *x, t_float f) +{ + x->x_seed = f; +} + +static void *urn_new(t_symbol *s, int argc, t_atom *argv) +{ + t_urn *x = (t_urn *)pd_new(urn_class); + + t_float f=0.; + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("")); + x->x_floatout=outlet_new(&x->x_obj, &s_float); + x->x_bangout =outlet_new(&x->x_obj, &s_bang); + + x->x_seed = makeseed(); + x->x_noauto = 0; + + while(argc--){ + if (argv->a_type==A_SYMBOL) { + if (atom_getsymbol(argv)==gensym("no_auto")) { + x->x_noauto=1; + } + } else f = atom_getfloat(argv); + argv++; + } + + if (f<1.0)f=1.0; + makestate(x, f); + x->x_range = f; + urn_clear(x); + + return (x); +} + +static void urn_setup(void) +{ + urn_class = class_new(gensym("urn"), (t_newmethod)urn_new, + 0, sizeof(t_urn), 0, A_GIMME, 0); + + class_addbang (urn_class, urn_bang); + class_addmethod(urn_class, (t_method)urn_clear, gensym("clear"), 0); + class_addmethod(urn_class, (t_method)urn_flt2, gensym(""), A_DEFFLOAT, 0); + class_addmethod(urn_class, (t_method)urn_seed, gensym("seed"), A_DEFFLOAT, 0); + + + class_sethelpsymbol(urn_class, gensym("zexy/urn")); +} + +void z_random_setup(void) +{ + urn_setup(); +} diff --git a/src/z_sfplay.c b/src/z_sfplay.c new file mode 100644 index 0000000..5ba4320 --- /dev/null +++ b/src/z_sfplay.c @@ -0,0 +1,660 @@ +/* +sfplay.c - Author: Winfried Ritsch - IEM Graz 10.Mai 99 - +Modified: + + Description: + + Soundfile player for playing many soundfiles in single speed. + (Made for "3 Farben Schwarz" - exhibition in Graz 99 ) + + Filename must have the path or actual directory, since pathname + search ist not supported to garantuee a fast open call. + + They idea is a state machine which handles open, skip, play, close, error + so that a minimum intervall between OS-calls are made, to avoid peak load. + + It has shown, that the open call is slow if there are a lot of files + to search for, then with the first skip the first part of a + soundfile is also loaded by the OS. + + I experimented with asynchronous buffering with paralell + process,which has shown no much performance hit, since more + processes has to be handled and the modern OS's do caching anyway + also caching is done in modern hard disk, so an additional cache + woud be an overhead, if not special behaviour is needed (big jumps + etc). + + This sfplayers should be used with an appropriate audio buffer for + good performance, so also buffering on the object is an overhead. + + The sfread for linux using mmap has also not much improvement over this, if plain playing in one + direction is done for random access the sfread should be used, even not knowing how to mmap in + NT. + +Todo: + Add the SPEED feature, but therefore there should be an own external using e.g. a 4-point interpolation. + so overhead is reduced in this one. + + Split open to an own object called sfopen to hold more soundfiles + then players and to enable glueless switching between soundfiles. + +please mail problems and ideas for improvements to +ritsch@iem.kug.ac.at */ + +/*#define DEBUG_ME // for debugging messages */ + +#include "zexy.h" + +/*#include "m_imp.h"*/ + +#define DACBLKSIZE 64 /* in m_imp.h, but error if it is included it here*/ + +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#pragma warning( disable : 4018 ) +#endif + +#include <stdio.h> +#include <string.h> +#include <fcntl.h> + +/* ------------------------ sfplay ----------------------------- */ +#define MAX_CHANS 8 /* channels for soundfiles 1,2,4,8 */ + +#ifdef NT +#define BINREADMODE "rb" +#endif +#ifdef unix +#include <unistd.h> +#include <sys/mman.h> +#define BINREADMODE "r" +#endif + +static t_class *sfplay_class; + +typedef struct _sfplay +{ + t_object x_obj; + + t_outlet *bangout; /* end of file */ + + void* filep; /* pointer to file data read in mem */ + t_symbol* filename; /* filename */ + /* + because there is no command queue, + flags are used instead + */ + t_int play; /* play: 1, stop: 0 */ + t_int please_stop; /* can be reset only by stop-state itself */ + t_int please_close; /* can be reset only by close-state */ + t_int x_channels; /* channels to play */ + t_float x_offset; /* offsetto start reading */ + t_float offset; /* inlet value offset in secs */ + t_float x_skip; /* skip bytes because header */ + t_int skip; /* pending skip if 1 */ + t_float x_speed; /* play speed, not supported in this version */ + t_int size; /* size of file (if memory mapped) */ + t_int swap; /* swap bytes from l->b or b->m */ + FILE *fp; /* file oper non-NULL of open */ + t_int state; /* which state is player in */ + t_int count; /* count for ticks before next step */ + +} t_sfplay; + +/* states of statemachine */ +#define SFPLAY_WAIT 0 /* wait for open */ +#define SFPLAY_OPEN 1 +#define SFPLAY_CLOSE 2 +#define SFPLAY_SKIP 3 +#define SFPLAY_PLAY 4 +#define SFPLAY_STOP 5 +#define SFPLAY_ERROR -1 + +#define SFPLAY_WAITTICKS 10 /* 1 tick of 64 Samples is ca. 1.5ms on 441000 */ + +/* split the os-calls in as many steps as possible +to split them on different ticks in steps of SFPLAY_WAITTICKS +to avoid peak performance */ + +/* like the one from garray */ +static int sfplay_am_i_big_endian() +{ + unsigned short s = 1; + unsigned char c = *(char *) (&s); + return(c==0); +} + + +void helper(t_sfplay *x) +{ + post("\nsfplay :: a soundfile-player (c) winfried ritsch 1999"); + post("\ncreation :: sfplay <channels> <bytes> : channels set the number of channels, bytes skip fileheader"); + post("\nopen [<path>]<filename> [<endianity>]\t::open b(ig) or l(ittle) endian file" + "\nclose\t\t\t::close file (aka eject)" + "\nstart\t\t\t::start playing" + "\nstop\t\t\t::stop playing" + "\nrewind\t\t\t::rewind tape" + "\ngoto <n>\t\t::play from byte n"); + post("\n\nyou can also start playing with a ´bang´ or a ´1´, and stop with a ´0´" + "\nthe last outlet will do a bang after the last sample has been played"); + +} + + +/* METHOD: "open" file */ + +/* this dont use memory map, because I dont know about this on NT ? +Use of the buffered functions fopen, fseek fread fclose instead the +non buffered ones open read close */ + +void sfplay_open(t_sfplay *x,t_symbol *filename,t_symbol *endian) +{ + + if(x->state != SFPLAY_WAIT) + { + post("sfplay: first close %s before open %s",x->filename->s_name,filename->s_name); + return; + } + +/* test if big endian else asume little endian + should be 'l' but could be anything*/ + + if(sfplay_am_i_big_endian()) + x->swap = !(endian->s_name[0] == 'b'); + else + x->swap = (endian->s_name[0] == 'b'); + + x->skip = 1; /* skip header after open */ + + x->filename = filename; + +#ifdef DEBUG_ME + post("sfplay: filename = %s",x->filename->s_name); +#endif + + if (x->fp != NULL)fclose(x->fp); /* should not happen */ + + if (!(x->fp = fopen(x->filename->s_name,BINREADMODE))) + { + error("sfplay: can't open %s", x->filename->s_name); + } +} + + + +/* METHOD: close */ +static void sfplay_close(t_sfplay *x) +{ + x->play = 0; + x->please_close = 1; + + /* now in state machine + if(x->fp != NULL) + { + fclose(x->fp); + x->fp = NULL; + } + */ + +#ifdef DEBUG_ME + post("sfplay: close "); +#endif + return; +} + +/* for skipping header of soundfile Dont use this for memory map */ + +static int sfplay_skip(t_sfplay *x) +{ + if(!x->skip) return 0; + + x->skip = 0; + + if(fseek(x->fp, (long) x->x_offset, SEEK_SET) < 0) + { + error(" sfplay can't seek to byte %ld",(long) x->x_offset); + x->x_offset = x->x_skip; + x->skip = 1; + return 0; + } + +#ifdef DEBUG_ME + post("sfplay:skip to %f",x->x_offset); +#endif + return 1; +} + +/* Input, method for Start stop */ + +static void sfplay_start(t_sfplay *x) +{ + long of = x->offset * sys_getsr() * x->x_channels; + + if(of < 0) of = x->x_skip; + else of += x->x_skip; /* offset in sec */ + + of &= ~0x111l; /* no odds please (8 channels boundary) */ + +#ifdef DEBUG_ME + post("sfplay: start"); +#endif + + /* new offset postion ? (fom inlet offset) */ + if( ((float) of) != x->x_offset) + { + x->skip=1; + x->x_offset = of; + } + x->play=1; +} + +static void sfplay_stop(t_sfplay *x) +{ +#ifdef DEBUG_ME + post("sfplay: stop"); +#endif + + x->play=0; + x->please_stop = 1; +} + +static void sfplay_float(t_sfplay *x, t_floatarg f) +{ + int t = f; + if (t) sfplay_start(x); + else sfplay_stop(x); +} + +/* start playing at position offset*/ +static void sfplay_offset(t_sfplay *x, t_floatarg f) +{ + x->offset = f; + x->skip = 1; + /* correction in sfplay_play() */ + +#ifdef DEBUG_ME + post("sfplay: offset %f",f); +#endif + return; +} + +static void sfplay_rewind(t_sfplay *x) +{ +#ifdef DEBUG_ME + post("sfplay: rewind to %f",x->x_skip); +#endif + + if(!x->fp)return; + + x->play=0; + fseek(x->fp,(long) x->x_skip,SEEK_SET); +} + +/* restart with bang */ + +void sfplay_bang(t_sfplay* x) +{ + x->skip = 1; + sfplay_start(x); +} + +static t_int *sfplay_perform(t_int *w) +{ + t_sfplay* x = (t_sfplay*)(w[1]); + short* buf = x->filep; + int c = x->x_channels; + + int i,j,n; + t_float* out[MAX_CHANS]; + + short s; + int swap = x->swap; + + for (i=0;i<c;i++) + out[i] = (t_float *)(w[3+i]); + + n = (int)(w[3+c]); + + /* loop */ + + + switch(x->state){ + + /* just wait */ + case SFPLAY_WAIT: + + if(x->fp != NULL){ +#ifdef DEBUG_ME + post("wait -> open"); +#endif + x->state = SFPLAY_OPEN; + x->count = SFPLAY_WAITTICKS; + }; + break; + + /* if in open state, already opened but wait for skip */ + case SFPLAY_OPEN: /* file hase opened wait some time */ + + if(!(x->count--)){ +#ifdef DEBUG_ME + post("open -> skip"); +#endif + x->state = SFPLAY_SKIP; + x->count = SFPLAY_WAITTICKS; + }; + + break; + + + /* in skipmode wait until ready for stop */ + case SFPLAY_SKIP: + + + if(x->count == SFPLAY_WAITTICKS) + { + if(!x->fp) + { + x->state = SFPLAY_CLOSE; + x->count=1; +#ifdef DEBUG_ME + post("skip -> close"); +#endif + break; + } + sfplay_skip(x); + } + if(!(x->count--)) + { +#ifdef DEBUG_ME + post("skip -> stop"); +#endif + x->state = SFPLAY_STOP; + x->count = SFPLAY_WAITTICKS; + }; + break; + + + + case SFPLAY_STOP: /* in stop state mainly waits for play */ + + x->please_stop = 0; + + if(x->please_close) + { + x->state = SFPLAY_CLOSE; + x->count = SFPLAY_WAITTICKS; +#ifdef DEBUG_ME + post("stop -> close"); +#endif + } + else if(x->skip) + { + x->state = SFPLAY_SKIP; + x->count = SFPLAY_WAITTICKS; + +#ifdef DEBUG_ME + post("stop -> skip"); +#endif + + } + else if(x->play) + { + +#ifdef DEBUG_ME + post("stop -> play"); +#endif + x->state = SFPLAY_PLAY; + } + break; + + + case SFPLAY_PLAY: /* yes play now */ + + + if(!x->play || x->please_stop) + { + + /* if closing dont need o go to stop */ + if(x->please_close) + { + x->state = SFPLAY_CLOSE; + x->count = SFPLAY_WAITTICKS; +#ifdef DEBUG_ME + post("play -> close"); +#endif + } + else + { + x->state = SFPLAY_STOP; +#ifdef DEBUG_ME + post("play -> stop"); +#endif + }; + break; + } + + /* should never happen */ + if(!x->filep){ + x->state = SFPLAY_ERROR; + error("sfplay: playing but no buffer ???? play"); + return (w+4+c); + } + + /* first read soundfile 16 bit*/ + if((j=fread(buf,sizeof(short),c*n,x->fp)) < (unsigned int) n) + { + + outlet_bang(x->bangout); + + if(feof(x->fp)){ + + while (n--) { + for (i=0;i<c;i++) { + if(--j > 0){ + s = *buf++; + if(swap) s = ((s & 0xFF)<< 8) | ((s& 0xFF00) >> 8); + *out[i]++ = s*(1./32768.); + } + else *out[i]++ = 0; + } + } + + x->state = SFPLAY_STOP; + x->play = 0; + return(w+c+4); + } + + /* or error if(ferror()) */ + x->state = SFPLAY_ERROR; + x->count = SFPLAY_WAITTICKS; + +#ifdef DEBUG_ME + post("play -> read error"); +#endif + break; + }; + + /* copy 16 Bit to floats and swap if neccesairy */ + while (n--) { + for (i=0;i<c;i++) { + s = *buf++; + if(swap) s = ((s & 0xFF)<< 8) | ((s& 0xFF00) >> 8); + *out[i]++ = s*(1./32768.); + } + } + return (w+c+4); /* dont zero out outs */ + + /* ok read error please close */ + case SFPLAY_ERROR: + + if(!(x->count--)){ + x->state = SFPLAY_CLOSE; + sfplay_close(x); +#ifdef DEBUG_ME + post("sfplay error reading sf: error -> close"); +#endif + x->count = SFPLAY_WAITTICKS; + } + break; + + /* in close state go to wait afterwards */ + case SFPLAY_CLOSE: + + x->please_close = 0; + + /* wait until ready for close operation */ + if(!(x->count--)){ + + x->state = SFPLAY_WAIT; + x->count = SFPLAY_WAITTICKS; + + /* avoid openfiles */ + if(x->fp){fclose(x->fp);x->fp = NULL;}; + +#ifdef DEBUG_ME + post("sfplay: close -> wait"); +#endif + } + break; + + }; /*case */ + + /* zero out outs */ + while (n--) { + for (i=0;i<c;i++) + *out[i]++ = 0.; + }; + + return(w+c+4); +} + + +/* ---------------------- Setup junk -------------------------- */ + +static void sfplay_dsp(t_sfplay *x, t_signal **sp) +{ + +#ifdef DEBUG_ME + post("sfplay: dsp"); +#endif + + switch (x->x_channels) { + case 1: + dsp_add(sfplay_perform, 4, x, + sp[0]->s_vec, + sp[1]->s_vec, /* out 1 */ + sp[0]->s_n); + break; + case 2: + dsp_add(sfplay_perform, 5, x, + sp[0]->s_vec, /* out 1*/ + sp[1]->s_vec, /* out 2*/ + sp[2]->s_vec, + sp[0]->s_n); + break; + case 4: + dsp_add(sfplay_perform, 6, x, + sp[0]->s_vec, + sp[1]->s_vec, + sp[2]->s_vec, + sp[3]->s_vec, + sp[4]->s_vec, + sp[0]->s_n); + break; + + case 8: + dsp_add(sfplay_perform, 8, x, + sp[0]->s_vec, + sp[1]->s_vec, + sp[2]->s_vec, + sp[3]->s_vec, + sp[4]->s_vec, + sp[5]->s_vec, + sp[6]->s_vec, + sp[7]->s_vec, + sp[8]->s_vec, + sp[0]->s_n); + break; + + } +} + + +/* create sfplay with args <channels> <skip> */ +static void *sfplay_new(t_floatarg chan,t_floatarg skip) +{ + t_sfplay *x = (t_sfplay *)pd_new(sfplay_class); + t_int c = chan; + + switch(c){ + /* ok */ + case 1: case 2: case 8: break; + /* try it, good luck ... */ + case 3: c = 2; break; + case 5: case 6: case 7: c=7; break; + default: c=1; break; + } + + floatinlet_new(&x->x_obj, &x->offset); /* inlet 2 */ + /* floatinlet_new(&x->x_obj, &x->speed); *//* inlet 3 */ + + x->x_channels = c; + x->x_skip = x->x_offset = skip; + x->offset = 0.; + x->skip = 1; + x->x_speed = 1.0; + x->play = 0; + x->please_stop = 0; + x->please_close = 0; + x->state = SFPLAY_WAIT; + x->count = 0; + x->filename = NULL; + x->fp = NULL; + x->swap = 1; + + while (c--) { + outlet_new(&x->x_obj, gensym("signal")); /* channels outlet */ + } + x->bangout = outlet_new(&x->x_obj, &s_bang); + + x->filep = t_getbytes(DACBLKSIZE*sizeof(short)*x->x_channels); + +#ifdef DEBUG_ME + post("get_bytes DACBLKSIZE*%d*%d->%ld",sizeof(short),x->x_channels,x->filep); + post("sfplay: x_channels = %d, x_speed = %f, x_skip = %f",x->x_channels,x->x_speed,x->x_skip); +#endif + + return (x); +} + + +static void sfplay_free(t_sfplay *x) +{ + freebytes(x->filep, DACBLKSIZE*sizeof(short)*x->x_channels); +} + +void z_sfplay_setup(void) +{ + sfplay_class = class_new(gensym("sfplay"), (t_newmethod)sfplay_new, (t_method)sfplay_free, + sizeof(t_sfplay), 0, A_DEFFLOAT, A_DEFFLOAT,0); + class_addmethod(sfplay_class, nullfn, gensym("signal"), 0); + class_addmethod(sfplay_class, (t_method)sfplay_dsp, gensym("dsp"), 0); + + class_addmethod(sfplay_class, (t_method)helper, gensym("help"), A_NULL); + class_sethelpsymbol(sfplay_class, gensym("zexy/sf-play_record")); + + /* method open with filename */ + class_addmethod(sfplay_class, (t_method)sfplay_open, gensym("open"), A_SYMBOL,A_SYMBOL,A_NULL); + class_addmethod(sfplay_class, (t_method)sfplay_close, gensym("close"), A_NULL); + + class_addmethod(sfplay_class, (t_method)sfplay_start, gensym("start"), A_NULL); + class_addmethod(sfplay_class, (t_method)sfplay_stop, gensym("stop"), A_NULL); + class_addmethod(sfplay_class, (t_method)sfplay_rewind, gensym("rewind"), A_NULL); + class_addmethod(sfplay_class, (t_method)sfplay_offset, gensym("goto"), A_DEFFLOAT, A_NULL); + + /* start stop with 0 and 1 */ + class_addfloat(sfplay_class, sfplay_float); + /* start with bang */ + class_addbang(sfplay_class,sfplay_bang); +} diff --git a/src/z_sfrecord.c b/src/z_sfrecord.c new file mode 100644 index 0000000..027a246 --- /dev/null +++ b/src/z_sfrecord.c @@ -0,0 +1,592 @@ +/* +sfplay.c - Author: Winfried Ritsch - IEM Graz 10.Mai 99 - +Modified: +sfrecord.c - hacked from sfplay ::: 2308:forum::für::umläute:1999 @ iem + +please mail problems and ideas for improvements to +ritsch@iem.kug.ac.at +zmoelnig@iem.kug.ac.at +*/ + +/* to do :: add headers for wav, aiff etc files */ + + +/* #define DEBUG_ME // for debugging messages */ + +#include "zexy.h" + + +/* #include "m_imp.h" */ + +#define DACBLKSIZE 64 /* in m_imp.h, but error if it is included it here*/ + +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +#include <stdio.h> +#include <string.h> +#include <fcntl.h> + +/* ------------------------ sfrecord ----------------------------- */ +#define MAX_CHANS 8 /* channels for soundfiles 1,2,4,8 */ + +#ifdef NT +#define BINWRITEMODE "wb" +#endif +#ifdef linux +#include <unistd.h> +#include <sys/mman.h> +#define BINWRITEMODE "w" +#endif + +static t_class *sfrecord_class; + +typedef struct _sfrecord +{ + t_object x_obj; + + void* filep; /* pointer to file data read in mem */ + t_symbol* filename; /* filename */ + + /* + because there is no command queue, + flags are used instead + */ + t_int write; /* write: 1, stop: 0 */ + t_int please_stop; /* can be reset only by stop-state itself */ + t_int please_close; /* can be reset only by close-state */ + t_int x_channels; /* channels to write */ + t_float x_offset; /* offset to start writing */ + t_float offset; /* inlet value offset in secs */ + t_float x_skip; /* skip bytes because header */ + t_int skip; /* pending skip if 1 */ + t_float x_speed; /* write speed, not supported in this version */ + t_int size; /* size of file (if memory mapped) */ + t_int swap; /* swap bytes from l->b or b->m */ + FILE *fp; /* file oper non-NULL of open */ + t_int state; /* which state is writer in */ + t_int count; /* count for ticks before next step */ + +} t_sfrecord; + +/* states of statemachine */ +#define SFRECORD_WAIT 0 /* wait for open */ +#define SFRECORD_OPEN 1 +#define SFRECORD_CLOSE 2 +#define SFRECORD_SKIP 3 +#define SFRECORD_WRITE 4 +#define SFRECORD_STOP 5 +#define SFRECORD_ERROR -1 + +#define SFRECORD_WAITTICKS 10 /* 1 tick of 64 Samples is ca.1.5ms on 441000 */ + +/* split the os-calls in as many steps as possible +to split them on different ticks in steps of SFRECORD_WAITTICKS +to avoid peak performance */ + +/* like the one from garray */ +static int sfrecord_am_i_big_endian() +{ + unsigned short s = 1; + unsigned char c = *(char *) (&s); +#ifdef DEBUG_ME + post("i am %s-endian", c?"little":"big"); +#endif + return(c==0); +} + +static void state_out(t_sfrecord *x, int state) +{ /* outlet the actual state */ + outlet_float(x->x_obj.ob_outlet, state); +} + + +/* METHOD: "open" file */ + +/* this dont use memory map, because I dont know about this on NT ? +Use of the buffered functions fopen, fseek fread fclose instead the +non buffered ones open read close */ + +void sfrecord_open(t_sfrecord *x,t_symbol *filename,t_symbol *endian) +{ + + if(x->state != SFRECORD_WAIT) + { + post("sfrecord: first close %s before open %s",x->filename->s_name,filename->s_name); + return; + } + +/* test if big endian else asume little endian + should be 'l' but could be anything*/ + + if(sfrecord_am_i_big_endian()) + x->swap = !(endian->s_name[0] == 'b'); + else + x->swap = (endian->s_name[0] == 'b'); + +// x->skip = 1; /* skip header after open;; sometimes we´ll have to write a header using the x->skip; so don´t delete it completely*/ + + x->filename = filename; + +#ifdef DEBUG_ME + post("sfrecord: opening %s",x->filename->s_name); +#endif + + if (x->fp != NULL)fclose(x->fp); /* should not happen */ + + if (!(x->fp = fopen(x->filename->s_name,BINWRITEMODE))) + { + error("sfrecord: can't open %s", x->filename->s_name); + } +} + + + +/* METHOD: close */ +static void sfrecord_close(t_sfrecord *x) +{ + x->write = 0; + x->please_close = 1; + + /* now in state machine + if(x->fp != NULL) + { + fclose(x->fp); + x->fp = NULL; + } + */ + +#ifdef DEBUG_ME + post("sfrecord: closing "); +#endif + return; +} + +/* for skipping header of soundfile Don´t use this for memory map */ + +static int sfrecord_skip(t_sfrecord *x) +{ + if(!x->skip) return 0; + +#ifdef DEBUG_ME + post("sfrecord:skip to %f",x->x_skip); +#endif + + x->skip = 0; + return 1; +} + +/* Input, method for Start stop */ + +static void sfrecord_start(t_sfrecord *x) +{ +#ifdef DEBUG_ME + post("sfrecord: start at %d", x->x_offset); +#endif + + state_out(x, 1); + x->write=1; +} + +static void sfrecord_stop(t_sfrecord *x) +{ +#ifdef DEBUG_ME + post("sfrecord: stop"); +#endif + state_out(x, 0); + + x->write=0; + x->please_stop = 1; +} + +static void sfrecord_float(t_sfrecord *x, t_floatarg f) +{ + int t = f; + if (t) sfrecord_start(x); + else sfrecord_stop(x); +} + +/* say what state we´re in */ +void sfrecord_bang(t_sfrecord* x) +{ + if (x->state == SFRECORD_WRITE) state_out(x, 1); else state_out(x, 0); +} + +/* ******************************************************************************** */ +/* the work krow eht */ +/* ******************************************************************************** */ + + +static t_int *sfrecord_perform(t_int *w) +{ + t_sfrecord* x = (t_sfrecord*)(w[1]); + short* buf = x->filep; + short* bufstart = buf; + int c = x->x_channels; + + int i,j,n, s_n; + t_float* in[MAX_CHANS]; + + short s; + int swap = x->swap; + + for (i=0;i<c;i++) + in[i] = (t_float *)(w[2+i]); + + n = s_n = (int)(w[2+c]); + + /* loop */ + + switch(x->state){ + + /* just wait */ + case SFRECORD_WAIT: + + if(x->fp != NULL){ +#ifdef DEBUG_ME + post("wait -> open"); +#endif + x->state = SFRECORD_OPEN; + x->count = SFRECORD_WAITTICKS; + }; + break; + + /* if in open state, already opened but wait for skip */ + case SFRECORD_OPEN: /* file has opened wait some time */ + + if(!(x->count--)){ +#ifdef DEBUG_ME + post("open -> skip"); +#endif + x->state = SFRECORD_SKIP; + x->count = SFRECORD_WAITTICKS; + }; + + break; + + /* in skipmode wait until ready for stop */ + case SFRECORD_SKIP: + + if(x->count == SFRECORD_WAITTICKS) + { + if(!x->fp) + { + x->state = SFRECORD_CLOSE; + x->count=1; +#ifdef DEBUG_ME + post("skip -> close"); +#endif + break; + } + sfrecord_skip(x); + } + if(!(x->count--)) + { +#ifdef DEBUG_ME + post("skip -> stop"); +#endif + x->state = SFRECORD_STOP; + x->count = SFRECORD_WAITTICKS; + }; + break; + + case SFRECORD_STOP: /* in stop state mainly waits for write */ + + x->please_stop = 0; + + if(x->please_close) + { + x->state = SFRECORD_CLOSE; + x->count = SFRECORD_WAITTICKS; +#ifdef DEBUG_ME + post("stop -> close"); +#endif + } + else if(x->skip) + { + x->state = SFRECORD_SKIP; + x->count = SFRECORD_WAITTICKS; + +#ifdef DEBUG_ME + post("stop -> skip"); +#endif + + } + else if(x->write) + { + +#ifdef DEBUG_ME + post("stop -> write"); +#endif + x->state = SFRECORD_WRITE; + state_out(x, 1); + } + break; + + case SFRECORD_WRITE: /* yes write now */ + + if(!x->write || x->please_stop) + { + /* if closing dont need to go to stop */ + if(x->please_close) { + x->state = SFRECORD_CLOSE; + x->count = SFRECORD_WAITTICKS; +#ifdef DEBUG_ME + post("write -> close"); +#endif + state_out(x, 0); + + } + else { + x->state = SFRECORD_STOP; +#ifdef DEBUG_ME + post("write -> stop"); +#endif + }; + break; + } + + /* should never happen */ + if(!x->filep){ + x->state = SFRECORD_ERROR; + error("sfrecord: writing but no buffer ???? write"); + return (w+4+c); + } + + /* copy float to 16 Bit and swap if neccesairy */ /* LATER treat overflows */ + while (n--) { + for (i=0;i<c;i++) { + s = *in[i]++ * 32768.; + if (swap) s = ((s & 0xFF)<< 8) | ((s& 0xFF00) >> 8); + *buf++ = s; + } + } + + /* then write soundfile 16 bit*/ + if ( (j = fwrite(bufstart, sizeof(short), c*s_n, x->fp)) < 1) { + x->state = SFRECORD_ERROR; + x->count = SFRECORD_WAITTICKS; +#ifdef DEBUG_ME + post("write -> write error\t %xd\t%xd\t%d\t%d", x->filep, buf, c*s_n*sizeof(short), j); +#endif + break; + } + +#if 0 + if((j=fwrite(buf,sizeof(short),c*n,x->fp)) < (unsigned int) n) + { + if(feof(x->fp)){ + + while (n--) { + for (i=0;i<c;i++) { + if(--j > 0){ + s = *buf++; + if(swap) s = ((s & 0xFF)<< 8) | ((s& 0xFF00) >> 8); + *out[i]++ = s*(1./32768.); + } + else + *out[i]++ = 0; + } + } + } + + x->state = SFRECORD_STOP; + x->write = 0; + return(w+c+3); + } + /* or error if(ferror()) */ + x->state = SFRECORD_ERROR; + x->count = SFRECORD_WAITTICKS; +#ifdef DEBUG_ME + post("write -> write error"); +#endif + break; + }; +#endif //0 + return (w+c+3); /* writing was fine */ + + + /* ok :?: write error, please close */ + case SFRECORD_ERROR: + + if(!(x->count--)) { + x->state = SFRECORD_CLOSE; + sfrecord_close(x); +#ifdef DEBUG_ME + post("sfrecord error writing sf: error -> close"); +#endif + x->count = SFRECORD_WAITTICKS; + } + break; + + /* in close state go to wait afterwards */ + case SFRECORD_CLOSE: + + x->please_close = 0; + + /* wait until ready for close operation */ + if(!(x->count--)){ + + x->state = SFRECORD_WAIT; + x->count = SFRECORD_WAITTICKS; + + /* avoid openfiles */ + if(x->fp){fclose(x->fp);x->fp = NULL;}; + +#ifdef DEBUG_ME + post("sfrecord: close -> wait"); +#endif + } + break; + + }; /*case */ + + return(w+c+3); +} + + + + +/* ---------------------- Setup junk -------------------------- */ + +static void sfrecord_dsp(t_sfrecord *x, t_signal **sp) +{ + +#ifdef DEBUG_ME + post("sfrecord: dsp"); + post("offset = %f\tspeed = %f\t", x->offset, x->x_speed); +#endif + + + switch (x->x_channels) { + case 1: + dsp_add(sfrecord_perform, 3, x, + sp[0]->s_vec, /* in 1 */ + sp[0]->s_n); + break; + case 2: + dsp_add(sfrecord_perform, 4, x, + sp[0]->s_vec, + sp[1]->s_vec, + sp[0]->s_n); + break; + case 4: + dsp_add(sfrecord_perform, 5, x, + sp[0]->s_vec, + sp[1]->s_vec, + sp[2]->s_vec, + sp[3]->s_vec, + sp[0]->s_n); + break; + case 8: + dsp_add(sfrecord_perform, 7, x, + sp[0]->s_vec, + sp[1]->s_vec, + sp[2]->s_vec, + sp[3]->s_vec, + sp[4]->s_vec, + sp[5]->s_vec, + sp[6]->s_vec, + sp[7]->s_vec, + sp[0]->s_n); + break; + } +} + + +/* create sfrecord with args <channels> <skip> */ +static void *sfrecord_new(t_floatarg chan) +{ + t_sfrecord *x = (t_sfrecord *)pd_new(sfrecord_class); + t_int c = chan; + + switch(c){ + /* ok */ + case 1: case 2: case 8: break; + /* try it, good luck ... */ + case 3: c = 2; break; + case 5: case 6: case 7: c=7; break; + default: c=1; break; + } + + outlet_new(&x->x_obj, &s_float); + + x->x_channels = c; + x->x_skip = x->x_offset = 0; + x->skip = 1; + x->offset = 0.; + x->x_speed = 1.0; + x->write = 0; + x->please_stop = 0; + x->please_close = 0; + x->state = SFRECORD_WAIT; + x->count = 0; + x->filename = NULL; + x->fp = NULL; + x->swap = 1; + + c--; + + while (c--) { +#ifdef DEBUG_ME + post("create extra channel #%d", c); +#endif + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); /* channels inlet */ + } + + x->filep = t_getbytes(DACBLKSIZE*sizeof(short)*x->x_channels); + +#ifdef DEBUG_ME + post("get_bytes DACBLKSIZE*%d*%d->%ld",sizeof(short),x->x_channels,x->filep); + post("sfrecord: x_channels = %d, x_speed = %f, x_skip = %f",x->x_channels,x->x_speed,x->x_skip); +#endif + + return (x); +} + + +static void helper(void) +{ + post("\nsfplay :: a raw-data soundfile-recorder"); + post("\ncreation :: sfrecord <channels>\t: channels set the number of channels"); + post("\nopen [<path>]<filename> [<endianity>]\t:: open b(ig) or l(ittle) endian file" + "\nclose\t\t\t:: close file (aka eject)" + "\nstart\t\t\t:: start playing" + "\nstop\t\t\t:: stop playing" + "\nbang\t\t\t:: outputs the current state (1_recording, 0_not-recording)"); + + post("\n\nyou can also start recording with a ´1´, and stop with a ´0´"); +} + + +static void sfrecord_free(t_sfrecord *x) +{ + freebytes(x->filep, DACBLKSIZE*sizeof(short)*x->x_channels); +} + +void z_sfrecord_setup(void) +{ + sfrecord_class = class_new(gensym("sfrecord"), (t_newmethod)sfrecord_new, (t_method)sfrecord_free, + sizeof(t_sfrecord), 0, A_DEFFLOAT, A_DEFFLOAT,0); + class_addmethod(sfrecord_class, nullfn, gensym("signal"), 0); + class_addmethod(sfrecord_class, (t_method)sfrecord_dsp, gensym("dsp"), 0); + + /* method open with filename */ + class_addmethod(sfrecord_class, (t_method)sfrecord_open, gensym("open"), A_SYMBOL,A_SYMBOL,A_NULL); + class_addmethod(sfrecord_class, (t_method)sfrecord_close, gensym("close"), A_NULL); + + class_addmethod(sfrecord_class, (t_method)sfrecord_start, gensym("start"), A_NULL); + class_addmethod(sfrecord_class, (t_method)sfrecord_stop, gensym("stop"), A_NULL); + + /* start/stop with 0/1 */ + class_addfloat(sfrecord_class, sfrecord_float); + + /* bang out the current-state to the outlet*/ + class_addbang(sfrecord_class,sfrecord_bang); + + /* some help */ + class_addmethod(sfrecord_class, (t_method)helper, gensym("help"), A_NULL); + class_sethelpsymbol(sfrecord_class, gensym("zexy/sf-play_record")); +} diff --git a/src/z_sigaverage.c b/src/z_sigaverage.c new file mode 100644 index 0000000..3ceb29c --- /dev/null +++ b/src/z_sigaverage.c @@ -0,0 +1,287 @@ +#include "zexy.h" +#include <math.h> + +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#define sqrtf sqrt +#endif + +/* ---------------- envrms~ - simple envelope follower. ----------------- */ +/* this is exactly the same as msp's env~-object, but does not output dB but RMS !! */ +/* i found env~+dbtorms most inconvenient (and expensive...) */ + +#define MAXOVERLAP 10 +#define MAXVSTAKEN 64 + +t_class *sigenvrms_class; + +typedef struct sigenvrms +{ + t_object x_obj; /* header */ + void *x_outlet; /* a "float" outlet */ + void *x_clock; /* a "clock" object */ + float *x_buf; /* a Hanning window */ + int x_phase; /* number of points since last output */ + int x_period; /* requested period of output */ + int x_realperiod; /* period rounded up to vecsize multiple */ + int x_npoints; /* analysis window size in samples */ + float x_result; /* result to output */ + float x_sumbuf[MAXOVERLAP]; /* summing buffer */ +} t_sigenvrms; + +static void sigenvrms_tick(t_sigenvrms *x); + +static void *sigenvrms_new(t_floatarg fnpoints, t_floatarg fperiod) +{ + int npoints = fnpoints; + int period = fperiod; + t_sigenvrms *x; + float *buf; + int i; + + if (npoints < 1) npoints = 1024; + if (period < 1) period = npoints/2; + if (period < npoints / MAXOVERLAP + 1) + period = npoints / MAXOVERLAP + 1; + if (!(buf = getbytes(sizeof(float) * (npoints + MAXVSTAKEN)))) + { + error("env: couldn't allocate buffer"); + return (0); + } + x = (t_sigenvrms *)pd_new(sigenvrms_class); + x->x_buf = buf; + x->x_npoints = npoints; + x->x_phase = 0; + x->x_period = period; + for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0; + for (i = 0; i < npoints; i++) + buf[i] = (1. - cos((2 * 3.141592654 * i) / npoints))/npoints; + for (; i < npoints+MAXVSTAKEN; i++) buf[i] = 0; + x->x_clock = clock_new(x, (t_method)sigenvrms_tick); + x->x_outlet = outlet_new(&x->x_obj, gensym("float")); + return (x); +} + +static t_int *sigenvrms_perform(t_int *w) +{ + t_sigenvrms *x = (t_sigenvrms *)(w[1]); + t_float *in = (t_float *)(w[2]); + int n = (int)(w[3]); + int count; + float *sump; + in += n; + for (count = x->x_phase, sump = x->x_sumbuf; + count < x->x_npoints; count += x->x_realperiod, sump++) + { + float *hp = x->x_buf + count; + float *fp = in; + float sum = *sump; + int i; + + for (i = 0; i < n; i++) + { + fp--; + sum += *hp++ * (*fp * *fp); + } + *sump = sum; + } + sump[0] = 0; + x->x_phase -= n; + if (x->x_phase < 0) + { + x->x_result = x->x_sumbuf[0]; + for (count = x->x_realperiod, sump = x->x_sumbuf; + count < x->x_npoints; count += x->x_realperiod, sump++) + sump[0] = sump[1]; + sump[0] = 0; + x->x_phase = x->x_realperiod - n; + clock_delay(x->x_clock, 0L); + } + return (w+4); +} + +static void sigenvrms_dsp(t_sigenvrms *x, t_signal **sp) +{ + if (x->x_period % sp[0]->s_n) x->x_realperiod = + x->x_period + sp[0]->s_n - (x->x_period % sp[0]->s_n); + else x->x_realperiod = x->x_period; + dsp_add(sigenvrms_perform, 3, x, sp[0]->s_vec, sp[0]->s_n); + if (sp[0]->s_n > MAXVSTAKEN) bug("sigenvrms_dsp"); +} + +static void sigenvrms_tick(t_sigenvrms *x) /* callback function for the clock */ +{ + outlet_float(x->x_outlet, sqrtf(x->x_result)); +} + +static void sigenvrms_ff(t_sigenvrms *x) /* cleanup on free */ +{ + clock_free(x->x_clock); + freebytes(x->x_buf, (x->x_npoints + MAXVSTAKEN) * sizeof(float)); +} + +static void sigenvrms_help(void) +{ + post("envrms~\t:: envelope follower that does output rms instead of dB"); +} + + +void sigenvrms_setup(void ) +{ + sigenvrms_class = class_new(gensym("envrms~"), (t_newmethod)sigenvrms_new, + (t_method)sigenvrms_ff, sizeof(t_sigenvrms), 0, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addmethod(sigenvrms_class, nullfn, gensym("signal"), 0); + class_addmethod(sigenvrms_class, (t_method)sigenvrms_dsp, gensym("dsp"), 0); + + class_addmethod(sigenvrms_class, (t_method)sigenvrms_help, gensym("help"), 0); + class_sethelpsymbol(sigenvrms_class, gensym("zexy/envrms~")); +} + +/* ------------------------ average~ ----------------------------- */ + +/* tilde object to take absolute value. */ + +static t_class *avg_class; + +typedef struct _avg +{ + t_object x_obj; + + t_float n_inv; + t_float buf; + int blocks; +} t_avg; + + +/* average :: arithmetic mean of one signal-vector */ + +static t_int *avg_perform(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + + t_avg *x = (t_avg *)w[2]; + int n = (int)(w[3]); + + t_float buf = 0.; + + while (n--) + { + buf += *in++; + } + outlet_float(x->x_obj.ob_outlet, buf*x->n_inv); + + return (w+4); +} + +static void avg_dsp(t_avg *x, t_signal **sp) +{ + x->n_inv=1./sp[0]->s_n; + dsp_add(avg_perform, 3, sp[0]->s_vec, x, sp[0]->s_n); +} + +static void *avg_new(void) +{ + t_avg *x = (t_avg *)pd_new(avg_class); + outlet_new(&x->x_obj, gensym("float")); + return (x); +} + +static void avg_help(void) +{ + post("avg~\t:: outputs the arithmetic mean of each signal-vector"); +} + + +void avg_setup(void) +{ + avg_class = class_new(gensym("avg~"), (t_newmethod)avg_new, 0, + sizeof(t_avg), 0, A_DEFFLOAT, 0); + class_addmethod(avg_class, nullfn, gensym("signal"), 0); + class_addmethod(avg_class, (t_method)avg_dsp, gensym("dsp"), 0); + + class_addmethod(avg_class, (t_method)avg_help, gensym("help"), 0); + class_sethelpsymbol(avg_class, gensym("zexy/avg~")); +} + + +/* triggered average :: arithmetic mean between last and current BANG */ + +static t_class *tavg_class; + +typedef struct _tavg +{ + t_object x_obj; + + t_float n_inv; + t_float buf; + int blocks; +} t_tavg; + + + +static void tavg_bang(t_avg *x) +{ + if (x->blocks) { + outlet_float(x->x_obj.ob_outlet, x->buf*x->n_inv/x->blocks); + x->blocks = 0; + x->buf = 0.; + } +} + +static t_int *tavg_perform(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_tavg *x = (t_tavg *)w[2]; + int n = (int)(w[3]); + + t_float buf = x->buf; + + while (n--) buf += *in++; + + x->buf = buf; + x->blocks++; + + return (w+4); +} + +static void tavg_dsp(t_tavg *x, t_signal **sp) +{ + x->n_inv=1./sp[0]->s_n; + dsp_add(tavg_perform, 3, sp[0]->s_vec, x, sp[0]->s_n); +} + +static void *tavg_new(void) +{ + t_tavg *x = (t_tavg *)pd_new(tavg_class); + outlet_new(&x->x_obj, gensym("float")); + return (x); +} + +static void tavg_help(void) +{ + post("tavg~\t\t:: outputs the arithmetic mean of a signal when triggered"); + post("<bang>\t\t: triggers the output"); +} + +void tavg_setup(void) +{ + tavg_class = class_new(gensym("tavg~"), (t_newmethod)tavg_new, 0, + sizeof(t_tavg), 0, A_DEFFLOAT, 0); + class_addmethod(tavg_class, nullfn, gensym("signal"), 0); + class_addmethod(tavg_class, (t_method)tavg_dsp, gensym("dsp"), 0); + + class_addbang(tavg_class, tavg_bang); + + class_addmethod(tavg_class, (t_method)tavg_help, gensym("help"), 0); + class_sethelpsymbol(tavg_class, gensym("zexy/tavg~")); +} + +/* global setup routine */ + +void z_sigaverage_setup(void) +{ + avg_setup(); + tavg_setup(); + sigenvrms_setup(); +} diff --git a/src/z_sigbin.c b/src/z_sigbin.c new file mode 100644 index 0000000..b1023e7 --- /dev/null +++ b/src/z_sigbin.c @@ -0,0 +1,801 @@ +/* + finally :: some of the missing binops for signals :: abs~, sgn~, >~, <~, ==~, &&~, ||~ + + 1302:forum::für::umläute:2000 +*/ + +#include "zexy.h" +#include <math.h> + +#ifdef NT +#define fabsf fabs +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +typedef struct _misc +{ + t_object x_obj; +} t_misc; + + +/* ------------------------ sigABS~ ----------------------------- */ + +static t_class *sigABS_class; + +static t_int *sigABS_perform(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_float *out = (t_float *)(w[2]); + int n = (int)(w[3]); + + while (n--) *out++ = fabsf(*in++); + + return (w+4); +} + +static void sigABS_dsp(t_misc *x, t_signal **sp) +{ + dsp_add(sigABS_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); +} + +static void sigABS_helper(void) +{ + post("\n%c abs~ \t\t:: absolute value of a signal", HEARTSYMBOL); +} + +static void *sigABS_new(void) +{ + t_misc *x = (t_misc *)pd_new(sigABS_class); + outlet_new(&x->x_obj, gensym("signal")); + + return (x); +} + +static void sigABS_setup(void) +{ + sigABS_class = class_new(gensym("abs~"), (t_newmethod)sigABS_new, 0, + sizeof(t_misc), 0, A_DEFFLOAT, 0); + class_addmethod(sigABS_class, nullfn, gensym("signal"), 0); + class_addmethod(sigABS_class, (t_method)sigABS_dsp, gensym("dsp"), 0); + + class_addmethod(sigABS_class, (t_method)sigABS_helper, gensym("help"), 0); + + class_sethelpsymbol(sigABS_class, gensym("zexy/sigbinops+")); +} + +/* ------------------------ sgn~ ----------------------------- */ + +static t_class *sigSGN_class; + +static t_int *sigSGN_perform(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_float *out = (t_float *)(w[2]); + int n = (int)(w[3]); + t_float x; + + while (n--) { + if ((x=*in++)>0.) *out++=1.; + else if (x<0.) *out++=-1.; + else *out++=0.; + } + + return (w+4); +} + +static void sigSGN_dsp(t_misc *x, t_signal **sp) +{ + dsp_add(sigSGN_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); +} + +static void sigSGN_helper(void) +{ + post("\n%c sgn~ \t\t:: sign of a signal", HEARTSYMBOL); +} + +static void *sigSGN_new() +{ + t_misc *x = (t_misc *)pd_new(sigSGN_class); + outlet_new(&x->x_obj, gensym("signal")); + + return (x); +} + +static void sigSGN_setup(void) +{ + sigSGN_class = class_new(gensym("sgn~"), (t_newmethod)sigSGN_new, 0, + sizeof(t_misc), 0, A_DEFFLOAT, 0); + class_addmethod(sigSGN_class, nullfn, gensym("signal"), 0); + class_addmethod(sigSGN_class, (t_method)sigSGN_dsp, gensym("dsp"), 0); + + class_addmethod(sigSGN_class, (t_method)sigSGN_helper, gensym("help"), 0); + class_sethelpsymbol(sigSGN_class, gensym("zexy/sigbinops+")); +} + +/* ------------------------ relational~ ----------------------------- */ + +/* ----------------------------- sigGRT ----------------------------- */ +static t_class *sigGRT_class, *scalarsigGRT_class; + +typedef struct _sigGRT +{ + t_object x_obj; + float x_f; +} t_sigGRT; + +typedef struct _scalarsigGRT +{ + t_object x_obj; + float x_f; + t_float x_g; /* inlet value */ +} t_scalarsigGRT; + +static void *sigGRT_new(t_symbol *s, int argc, t_atom *argv) +{ + if (argc > 1) post(">~: extra arguments ignored"); + if (argc) + { + t_scalarsigGRT *x = (t_scalarsigGRT *)pd_new(scalarsigGRT_class); + floatinlet_new(&x->x_obj, &x->x_g); + x->x_g = atom_getfloatarg(0, argc, argv); + outlet_new(&x->x_obj, &s_signal); + x->x_f = 0; + return (x); + } + else + { + t_sigGRT *x = (t_sigGRT *)pd_new(sigGRT_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + outlet_new(&x->x_obj, &s_signal); + x->x_f = 0; + return (x); + } +} + +t_int *sigGRT_perform(t_int *w) +{ + t_float *in1 = (t_float *)(w[1]); + t_float *in2 = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + while (n--) *out++ = *in1++ > *in2++; + return (w+5); +} + +t_int *sigGRT_perf8(t_int *w) +{ + t_float *in1 = (t_float *)(w[1]); + t_float *in2 = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + for (; n; n -= 8, in1 += 8, in2 += 8, out += 8) + { + float f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3]; + float f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7]; + + float g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3]; + float g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7]; + + out[0] = f0 > g0; out[1] = f1 > g1; out[2] = f2 > g2; out[3] = f3 > g3; + out[4] = f4 > g4; out[5] = f5 > g5; out[6] = f6 > g6; out[7] = f7 > g7; + } + return (w+5); +} + +t_int *scalarsigGRT_perform(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_float f = *(t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + while (n--) *out++ = *in++ > f; + return (w+5); +} + +t_int *scalarsigGRT_perf8(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_float g = *(t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + for (; n; n -= 8, in += 8, out += 8) + { + float f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3]; + float f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7]; + + out[0] = f0 > g; out[1] = f1 > g; out[2] = f2 > g; out[3] = f3 > g; + out[4] = f4 > g; out[5] = f5 > g; out[6] = f6 > g; out[7] = f7 > g; + } + return (w+5); +} + +void dsp_add_sigGRT(t_sample *in1, t_sample *in2, t_sample *out, int n) +{ + if (n&7) + dsp_add(sigGRT_perform, 4, in1, in2, out, n); + else + dsp_add(sigGRT_perf8, 4, in1, in2, out, n); +} + +static void sigGRT_dsp(t_sigGRT *x, t_signal **sp) +{ + dsp_add_sigGRT(sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); +} + +static void scalarsigGRT_dsp(t_scalarsigGRT *x, t_signal **sp) +{ + if (sp[0]->s_n&7) + dsp_add(scalarsigGRT_perform, 4, sp[0]->s_vec, &x->x_g, + sp[1]->s_vec, sp[0]->s_n); + else + dsp_add(scalarsigGRT_perf8, 4, sp[0]->s_vec, &x->x_g, + sp[1]->s_vec, sp[0]->s_n); +} + +static void sigGRT_setup(void) +{ + sigGRT_class = class_new(gensym(">~"), (t_newmethod)sigGRT_new, 0, + sizeof(t_sigGRT), 0, A_GIMME, 0); + class_addmethod(sigGRT_class, (t_method)sigGRT_dsp, gensym("dsp"), 0); + CLASS_MAINSIGNALIN(sigGRT_class, t_sigGRT, x_f); + class_sethelpsymbol(sigGRT_class, gensym("zexy/sigbinops+")); + scalarsigGRT_class = class_new(gensym(">~"), 0, 0, + sizeof(t_scalarsigGRT), 0, 0); + CLASS_MAINSIGNALIN(scalarsigGRT_class, t_scalarsigGRT, x_f); + class_addmethod(scalarsigGRT_class, (t_method)scalarsigGRT_dsp, gensym("dsp"), + 0); + class_sethelpsymbol(scalarsigGRT_class, gensym("zexy/sigbinops+")); +} + + +/* ----------------------------- sigLESS ----------------------------- */ +static t_class *sigLESS_class, *scalarsigLESS_class; + +typedef struct _sigLESS +{ + t_object x_obj; + float x_f; +} t_sigLESS; + +typedef struct _scalarsigLESS +{ + t_object x_obj; + float x_f; + t_float x_g; /* inlet value */ +} t_scalarsigLESS; + +static void *sigLESS_new(t_symbol *s, int argc, t_atom *argv) +{ + if (argc > 1) post("<~: extra arguments ignored"); + if (argc) + { + t_scalarsigLESS *x = (t_scalarsigLESS *)pd_new(scalarsigLESS_class); + floatinlet_new(&x->x_obj, &x->x_g); + x->x_g = atom_getfloatarg(0, argc, argv); + outlet_new(&x->x_obj, &s_signal); + x->x_f = 0; + return (x); + } + else + { + t_sigLESS *x = (t_sigLESS *)pd_new(sigLESS_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + outlet_new(&x->x_obj, &s_signal); + x->x_f = 0; + return (x); + } +} + +t_int *sigLESS_perform(t_int *w) +{ + t_float *in1 = (t_float *)(w[1]); + t_float *in2 = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + while (n--) *out++ = *in1++ < *in2++; + return (w+5); +} + +t_int *sigLESS_perf8(t_int *w) +{ + t_float *in1 = (t_float *)(w[1]); + t_float *in2 = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + for (; n; n -= 8, in1 += 8, in2 += 8, out += 8) + { + float f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3]; + float f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7]; + + float g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3]; + float g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7]; + + out[0] = f0 < g0; out[1] = f1 < g1; out[2] = f2 < g2; out[3] = f3 < g3; + out[4] = f4 < g4; out[5] = f5 < g5; out[6] = f6 < g6; out[7] = f7 < g7; + } + return (w+5); +} + +t_int *scalarsigLESS_perform(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_float f = *(t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + while (n--) *out++ = *in++ < f; + return (w+5); +} + +t_int *scalarsigLESS_perf8(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_float g = *(t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + for (; n; n -= 8, in += 8, out += 8) + { + float f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3]; + float f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7]; + + out[0] = f0 < g; out[1] = f1 < g; out[2] = f2 < g; out[3] = f3 < g; + out[4] = f4 < g; out[5] = f5 < g; out[6] = f6 < g; out[7] = f7 < g; + } + return (w+5); +} + +void dsp_add_sigLESS(t_sample *in1, t_sample *in2, t_sample *out, int n) +{ + if (n&7) + dsp_add(sigLESS_perform, 4, in1, in2, out, n); + else + dsp_add(sigLESS_perf8, 4, in1, in2, out, n); +} + +static void sigLESS_dsp(t_sigLESS *x, t_signal **sp) +{ + dsp_add_sigLESS(sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); +} + +static void scalarsigLESS_dsp(t_scalarsigLESS *x, t_signal **sp) +{ + if (sp[0]->s_n&7) + dsp_add(scalarsigLESS_perform, 4, sp[0]->s_vec, &x->x_g, + sp[1]->s_vec, sp[0]->s_n); + else + dsp_add(scalarsigLESS_perf8, 4, sp[0]->s_vec, &x->x_g, + sp[1]->s_vec, sp[0]->s_n); +} + +static void sigLESS_setup(void) +{ + sigLESS_class = class_new(gensym("<~"), (t_newmethod)sigLESS_new, 0, + sizeof(t_sigLESS), 0, A_GIMME, 0); + class_addmethod(sigLESS_class, (t_method)sigLESS_dsp, gensym("dsp"), 0); + CLASS_MAINSIGNALIN(sigLESS_class, t_sigLESS, x_f); + class_sethelpsymbol(sigLESS_class, gensym("zexy/sigbinops+")); + scalarsigLESS_class = class_new(gensym("<~"), 0, 0, + sizeof(t_scalarsigLESS), 0, 0); + CLASS_MAINSIGNALIN(scalarsigLESS_class, t_scalarsigLESS, x_f); + class_addmethod(scalarsigLESS_class, (t_method)scalarsigLESS_dsp, gensym("dsp"), + 0); + class_sethelpsymbol(scalarsigLESS_class, gensym("zexy/sigbinops+")); +} + +/* ----------------------------- sigEQUAL ----------------------------- */ +static t_class *sigEQUAL_class, *scalarsigEQUAL_class; + +typedef struct _sigEQUAL +{ + t_object x_obj; + float x_f; +} t_sigEQUAL; + +typedef struct _scalarsigEQUAL +{ + t_object x_obj; + float x_f; + t_float x_g; /* inlet value */ +} t_scalarsigEQUAL; + +static void *sigEQUAL_new(t_symbol *s, int argc, t_atom *argv) +{ + if (argc > 1) post("==~: extra arguments ignored"); + if (argc) + { + t_scalarsigEQUAL *x = (t_scalarsigEQUAL *)pd_new(scalarsigEQUAL_class); + floatinlet_new(&x->x_obj, &x->x_g); + x->x_g = atom_getfloatarg(0, argc, argv); + outlet_new(&x->x_obj, &s_signal); + x->x_f = 0; + return (x); + } + else + { + t_sigEQUAL *x = (t_sigEQUAL *)pd_new(sigEQUAL_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + outlet_new(&x->x_obj, &s_signal); + x->x_f = 0; + return (x); + } +} + +t_int *sigEQUAL_perform(t_int *w) +{ + t_float *in1 = (t_float *)(w[1]); + t_float *in2 = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + while (n--) *out++ = (*in1++ == *in2++); + return (w+5); +} + +t_int *sigEQUAL_perf8(t_int *w) +{ + t_float *in1 = (t_float *)(w[1]); + t_float *in2 = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + for (; n; n -= 8, in1 += 8, in2 += 8, out += 8) + { + float f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3]; + float f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7]; + + float g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3]; + float g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7]; + + out[0] = f0 == g0; out[1] = f1 == g1; out[2] = f2 == g2; out[3] = f3 == g3; + out[4] = f4 == g4; out[5] = f5 == g5; out[6] = f6 == g6; out[7] = f7 == g7; + } + return (w+5); +} + +t_int *scalarsigEQUAL_perform(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_float f = *(t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + while (n--) *out++ = (*in++ == f); + return (w+5); +} + +t_int *scalarsigEQUAL_perf8(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_float g = *(t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + for (; n; n -= 8, in += 8, out += 8) + { + float f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3]; + float f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7]; + + out[0] = (f0 == g); out[1] = (f1 == g); out[2] = (f2 == g); out[3] = (f3 == g); + out[4] = (f4 == g); out[5] = (f5 == g); out[6] = (f6 == g); out[7] = (f7 == g); + } + return (w+5); +} + +void dsp_add_sigEQUAL(t_sample *in1, t_sample *in2, t_sample *out, int n) +{ + if (n&7) + dsp_add(sigEQUAL_perform, 4, in1, in2, out, n); + else + dsp_add(sigEQUAL_perf8, 4, in1, in2, out, n); +} + +static void sigEQUAL_dsp(t_sigEQUAL *x, t_signal **sp) +{ + dsp_add_sigEQUAL(sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); +} + +static void scalarsigEQUAL_dsp(t_scalarsigEQUAL *x, t_signal **sp) +{ + if (sp[0]->s_n&7) + dsp_add(scalarsigEQUAL_perform, 4, sp[0]->s_vec, &x->x_g, + sp[1]->s_vec, sp[0]->s_n); + else + dsp_add(scalarsigEQUAL_perf8, 4, sp[0]->s_vec, &x->x_g, + sp[1]->s_vec, sp[0]->s_n); +} + +static void sigEQUAL_setup(void) +{ + sigEQUAL_class = class_new(gensym("==~"), (t_newmethod)sigEQUAL_new, 0, + sizeof(t_sigEQUAL), 0, A_GIMME, 0); + class_addmethod(sigEQUAL_class, (t_method)sigEQUAL_dsp, gensym("dsp"), 0); + CLASS_MAINSIGNALIN(sigEQUAL_class, t_sigEQUAL, x_f); + class_sethelpsymbol(sigEQUAL_class, gensym("zexy/sigbinops+")); + scalarsigEQUAL_class = class_new(gensym("==~"), 0, 0, + sizeof(t_scalarsigEQUAL), 0, 0); + CLASS_MAINSIGNALIN(scalarsigEQUAL_class, t_scalarsigEQUAL, x_f); + class_addmethod(scalarsigEQUAL_class, (t_method)scalarsigEQUAL_dsp, gensym("dsp"), + 0); + class_sethelpsymbol(scalarsigEQUAL_class, gensym("zexy/sigbinops+")); +} + +/* ------------------------ logical~ ----------------------------- */ + +/* ----------------------------- sigAND ----------------------------- */ +static t_class *sigAND_class, *scalarsigAND_class; + +typedef struct _sigAND +{ + t_object x_obj; + float x_f; +} t_sigAND; + +typedef struct _scalarsigAND +{ + t_object x_obj; + float x_f; + t_float x_g; /* inlet value */ +} t_scalarsigAND; + +static void *sigAND_new(t_symbol *s, int argc, t_atom *argv) +{ + if (argc > 1) post("&&~: extra arguments ignored"); + if (argc) + { + t_scalarsigAND *x = (t_scalarsigAND *)pd_new(scalarsigAND_class); + floatinlet_new(&x->x_obj, &x->x_g); + x->x_g = atom_getfloatarg(0, argc, argv); + outlet_new(&x->x_obj, &s_signal); + x->x_f = 0; + return (x); + } + else + { + t_sigAND *x = (t_sigAND *)pd_new(sigAND_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + outlet_new(&x->x_obj, &s_signal); + x->x_f = 0; + return (x); + } +} + +t_int *sigAND_perform(t_int *w) +{ + t_float *in1 = (t_float *)(w[1]); + t_float *in2 = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + while (n--) *out++ = (int)*in1++ && (int)*in2++; + return (w+5); +} + +t_int *sigAND_perf8(t_int *w) +{ + t_float *in1 = (t_float *)(w[1]); + t_float *in2 = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + for (; n; n -= 8, in1 += 8, in2 += 8, out += 8) + { + int f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3]; + int f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7]; + + int g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3]; + int g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7]; + + out[0] = f0 && g0; out[1] = f1 && g1; out[2] = f2 && g2; out[3] = f3 && g3; + out[4] = f4 && g4; out[5] = f5 && g5; out[6] = f6 && g6; out[7] = f7 && g7; + } + return (w+5); +} + +t_int *scalarsigAND_perform(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_float f = *(t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + while (n--) *out++ = (int)*in++ && (int)f; + return (w+5); +} + +t_int *scalarsigAND_perf8(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + int g = *(t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + for (; n; n -= 8, in += 8, out += 8) + { + int f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3]; + int f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7]; + + out[0] = f0 && g; out[1] = f1 && g; out[2] = f2 && g; out[3] = f3 && g; + out[4] = f4 && g; out[5] = f5 && g; out[6] = f6 && g; out[7] = f7 && g; + } + return (w+5); +} + +void dsp_add_sigAND(t_sample *in1, t_sample *in2, t_sample *out, int n) +{ + if (n&7) + dsp_add(sigAND_perform, 4, in1, in2, out, n); + else + dsp_add(sigAND_perf8, 4, in1, in2, out, n); +} + +static void sigAND_dsp(t_sigAND *x, t_signal **sp) +{ + dsp_add_sigAND(sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); +} + +static void scalarsigAND_dsp(t_scalarsigAND *x, t_signal **sp) +{ + if (sp[0]->s_n&7) + dsp_add(scalarsigAND_perform, 4, sp[0]->s_vec, &x->x_g, + sp[1]->s_vec, sp[0]->s_n); + else + dsp_add(scalarsigAND_perf8, 4, sp[0]->s_vec, &x->x_g, + sp[1]->s_vec, sp[0]->s_n); +} + +static void sigAND_setup(void) +{ + sigAND_class = class_new(gensym("&&~"), (t_newmethod)sigAND_new, 0, + sizeof(t_sigAND), 0, A_GIMME, 0); + class_addmethod(sigAND_class, (t_method)sigAND_dsp, gensym("dsp"), 0); + CLASS_MAINSIGNALIN(sigAND_class, t_sigAND, x_f); + class_sethelpsymbol(sigAND_class, gensym("zexy/sigbinops+")); + scalarsigAND_class = class_new(gensym("&&~"), 0, 0, + sizeof(t_scalarsigAND), 0, 0); + CLASS_MAINSIGNALIN(scalarsigAND_class, t_scalarsigAND, x_f); + class_addmethod(scalarsigAND_class, (t_method)scalarsigAND_dsp, gensym("dsp"), + 0); + class_sethelpsymbol(scalarsigAND_class, gensym("zexy/sigbinops+")); +} + + +/* ----------------------------- sigOR ----------------------------- */ +static t_class *sigOR_class, *scalarsigOR_class; + +typedef struct _sigOR +{ + t_object x_obj; + float x_f; +} t_sigOR; + +typedef struct _scalarsigOR +{ + t_object x_obj; + float x_f; + t_float x_g; /* inlet value */ +} t_scalarsigOR; + +static void *sigOR_new(t_symbol *s, int argc, t_atom *argv) +{ + if (argc > 1) post("||~: extra arguments ignored"); + if (argc) + { + t_scalarsigOR *x = (t_scalarsigOR *)pd_new(scalarsigOR_class); + floatinlet_new(&x->x_obj, &x->x_g); + x->x_g = atom_getfloatarg(0, argc, argv); + outlet_new(&x->x_obj, &s_signal); + x->x_f = 0; + return (x); + } + else + { + t_sigOR *x = (t_sigOR *)pd_new(sigOR_class); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); + outlet_new(&x->x_obj, &s_signal); + x->x_f = 0; + return (x); + } +} + +t_int *sigOR_perform(t_int *w) +{ + t_float *in1 = (t_float *)(w[1]); + t_float *in2 = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + while (n--) *out++ = (int)*in1++ || (int)*in2++; + return (w+5); +} + +t_int *sigOR_perf8(t_int *w) +{ + t_float *in1 = (t_float *)(w[1]); + t_float *in2 = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + for (; n; n -= 8, in1 += 8, in2 += 8, out += 8) + { + int f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3]; + int f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7]; + + int g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3]; + int g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7]; + + out[0] = f0 || g0; out[1] = f1 || g1; out[2] = f2 || g2; out[3] = f3 || g3; + out[4] = f4 || g4; out[5] = f5 || g5; out[6] = f6 || g6; out[7] = f7 || g7; + } + return (w+5); +} + +t_int *scalarsigOR_perform(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + int f = *(t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + while (n--) *out++ = (int)*in++ || f; + return (w+5); +} + +t_int *scalarsigOR_perf8(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + int g = *(t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + for (; n; n -= 8, in += 8, out += 8) + { + int f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3]; + int f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7]; + + out[0] = f0 || g; out[1] = f1 || g; out[2] = f2 || g; out[3] = f3 || g; + out[4] = f4 || g; out[5] = f5 || g; out[6] = f6 || g; out[7] = f7 || g; + } + return (w+5); +} + +void dsp_add_sigOR(t_sample *in1, t_sample *in2, t_sample *out, int n) +{ + if (n&7) + dsp_add(sigOR_perform, 4, in1, in2, out, n); + else + dsp_add(sigOR_perf8, 4, in1, in2, out, n); +} + +static void sigOR_dsp(t_sigOR *x, t_signal **sp) +{ + dsp_add_sigOR(sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n); +} + +static void scalarsigOR_dsp(t_scalarsigOR *x, t_signal **sp) +{ + if (sp[0]->s_n&7) + dsp_add(scalarsigOR_perform, 4, sp[0]->s_vec, &x->x_g, + sp[1]->s_vec, sp[0]->s_n); + else + dsp_add(scalarsigOR_perf8, 4, sp[0]->s_vec, &x->x_g, + sp[1]->s_vec, sp[0]->s_n); +} + +static void sigOR_setup(void) +{ + sigOR_class = class_new(gensym("||~"), (t_newmethod)sigOR_new, 0, + sizeof(t_sigOR), 0, A_GIMME, 0); + class_addmethod(sigOR_class, (t_method)sigOR_dsp, gensym("dsp"), 0); + CLASS_MAINSIGNALIN(sigOR_class, t_sigOR, x_f); + class_sethelpsymbol(sigOR_class, gensym("zexy/sigbinops+")); + scalarsigOR_class = class_new(gensym("||~"), 0, 0, + sizeof(t_scalarsigOR), 0, 0); + CLASS_MAINSIGNALIN(scalarsigOR_class, t_scalarsigOR, x_f); + class_addmethod(scalarsigOR_class, (t_method)scalarsigOR_dsp, gensym("dsp"), + 0); + class_sethelpsymbol(scalarsigOR_class, gensym("zexy/sigbinops+")); +} + + + +/* ---------------------- global setup ------------------------- */ + + +void z_sigbin_setup(void) +{ + sigABS_setup(); + sigSGN_setup(); + sigGRT_setup(); + sigLESS_setup(); + sigEQUAL_setup(); + sigOR_setup(); + sigAND_setup(); +} diff --git a/src/z_sigmatrix.c b/src/z_sigmatrix.c new file mode 100644 index 0000000..850f303 --- /dev/null +++ b/src/z_sigmatrix.c @@ -0,0 +1,538 @@ +#include "zexy.h" + +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +/* the sigmatrix objects :: + matrix~ : multiply a n-vector of in~ with a matrix to get a m-vector of out~ + line~ between the 2 matrices, to make it useable as a mixer + multiplex~ : multiplex 1-of-n in~ to 1 out~ + demultiplex~ : demultiplex 1 in~ to 1-of-n out~ + + to do : + patchbay~ : array of mux~ and demux~ + +*/ + + +/* --------------------------- matrix~ ---------------------------------- + * + * multiply a n-vector of signals with a (n*m) matrix, to get m output-streams. + * make the (n*m)-matrix of scalars to be liny~ + * + * 1703:forum::für::umläute:2001 + */ + +static t_class *sigmtx_class; + +typedef struct _sigmtx { + t_object x_obj; + + t_float time; + int ticksleft; + int retarget; + t_float msec2tick; + + t_float **value; + t_float **target; + t_float **increment; /* single precision is really a bad, especially when doing long line~s. + * but the biginc (like in msp's line~ (d_ctl.c) is far too expensive... */ + t_float **sigIN; + t_float **sigOUT; + t_float *sigBUF; + + int n_sigIN; /* columns */ + int n_sigOUT; /* rows */ +} t_sigmtx; + +/* the message thing */ + +static void sigmtx_matrix(t_sigmtx *x, t_symbol *s, int argc, t_atom *argv) +{ + int col, row, c=0, r=0; + + if (argc<2){ + post("matrix~ : bad matrix !"); + return; + } + + row = atom_getfloat(argv++); + col = atom_getfloat(argv++); + argc-=2; + + if((col!=x->n_sigOUT)||(row!=x->n_sigIN)){ + post("matrix~ : matrix dimensions do not match !!"); + return; + } + if(argc<row*col){ + post("matrix~ : reduced matrices not yet supported"); + return; + } + + if (x->time<=0) { + for(r=0; r<row; r++) + for(c=0; c<col; c++) + x->target[c][r]=x->value[c][r]=atom_getfloat(argv++); + x->time=x->ticksleft=x->retarget=0; + } else { + for(r=0; r<row; r++) + for(c=0; c<col; c++) + x->target[c][r]=atom_getfloat(argv++); + x->retarget=1; + } +} + +static void sigmtx_stop(t_sigmtx *x) +{ + int c = x->n_sigOUT, r; + t_float *tgt, *val; + while(c--){ + tgt=x->target[c]; + val=x->value [c]; + r=x->n_sigIN; + while(r--)*tgt++=*val++; + } + x->ticksleft = x->retarget = 0; +} + + +/* the dsp thing */ + +static t_int *sigmtx_perform(t_int *w) +{ + t_sigmtx *x = (t_sigmtx *)(w[1]); + int n = (int)(w[2]); + + int r, c; + + t_float **out = x->sigOUT; + t_float **in = x->sigIN; + + t_float *buf = x->sigBUF, *sigBUF = buf; + + t_float **value = x->value; + t_float **target = x->target; + t_float **increment = x->increment; + + t_float *inc, *val, *tgt; + + int n_IN=x->n_sigIN, n_OUT=x->n_sigOUT; + + if (x->retarget) { + int nticks = x->time * x->msec2tick; + t_float oneovernos; + + if (!nticks) nticks = 1; + oneovernos = 1./(nticks*n); + x->ticksleft = nticks; + + c = n_OUT; + while(c--) { + inc=increment[c]; + val=value[c]; + tgt=target[c]; + r=n_IN; + while(r--)*inc++=(*tgt++-*val++)*oneovernos; + } + + x->retarget = 0; + } + + if (x->ticksleft) { + int N=n-1; + n=-1; + // while (n--) { + while(n++<N){ + c = n_OUT; + while(c--) { + t_float sum = 0; + val = value[c]+n_IN-1; + inc = increment[c]+n_IN-1; + r=n_IN; + + while(r--)sum+=in[r][n]*(*val--+=*inc--); + + sigBUF[c]=sum; + } + buf = sigBUF; + c = n_OUT; + while(c--)out[c][n]=*buf++; + } + if (!--x->ticksleft) { + c = n_OUT; + while(c--){ + val=value[c]; + tgt=target[c]; + r=n_IN; + while(r--)*val++=*tgt++; + } + } + } else { /* no ticks left */ + while (n--) { + c = n_OUT; + while(c--) { + t_float sum = 0; + val = value[c]+n_IN-1; + r = n_IN; + while(r--)sum+=in[r][n]**val--; + sigBUF[c]=sum; + } + buf = sigBUF; + c = n_OUT; + while(c--)out[c][n]=*buf++; + } + } + return (w+3); +} + +static void sigmtx_dsp(t_sigmtx *x, t_signal **sp) +{ + int o = x->n_sigOUT, i=x->n_sigIN, n=0; + t_float **dummy = x->sigIN; + + while(i--)*dummy++=sp[n++]->s_vec; + + dummy =x->sigOUT; + while(o--)dummy[o]=sp[n++]->s_vec; + + x->msec2tick = sp[0]->s_sr / (1000.f * sp[0]->s_n); + dsp_add(sigmtx_perform, 2, x, sp[0]->s_n); +} + + +/* setup/setdown things */ + +static void sigmtx_free(t_sigmtx *x) +{ + int i = x->n_sigOUT; + while(i--) { + freebytes(x->value [i], x->n_sigOUT * sizeof(t_float *)); + freebytes(x->target [i], x->n_sigOUT * sizeof(t_float *)); + freebytes(x->increment[i], x->n_sigOUT * sizeof(t_float *)); + } + + freebytes(x->value, sizeof(x->value)); + freebytes(x->target, sizeof(x->target)); + freebytes(x->increment, sizeof(x->increment)); + + freebytes(x->sigIN, x->n_sigIN * sizeof(t_float *)); + freebytes(x->sigOUT, x->n_sigOUT * sizeof(t_float *)); + freebytes(x->sigBUF, x->n_sigOUT * sizeof(t_float )); +} + +static void *sigmtx_new(t_symbol *s, int argc, t_atom *argv) +{ + t_sigmtx *x = (t_sigmtx *)pd_new(sigmtx_class); + int i; + + x->time = 0; + + switch (argc) { + case 0: + x->n_sigIN = x->n_sigOUT = 1; + break; + case 1: + x->n_sigIN = x->n_sigOUT = atom_getfloat(argv); + break; + default: + x->time= atom_getfloat(argv+2); + case 2: + x->n_sigIN = atom_getfloat(argv); + x->n_sigOUT = atom_getfloat(argv+1); + break; + } + + if (x->time<0) x->time=0; + if (x->n_sigIN <1) x->n_sigIN =1; + if (x->n_sigOUT<1) x->n_sigOUT=1; + + /* the inlets */ + i=x->n_sigIN-1; + while(i--)inlet_new(&x->x_obj,&x->x_obj.ob_pd,&s_signal,&s_signal); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("matrix"), gensym("")); + floatinlet_new(&x->x_obj, &x->time); + + /* the outlets */ + i=x->n_sigOUT; + while(i--)outlet_new(&x->x_obj,&s_signal); + + /* make all the buffers */ + x->sigIN = (t_float **)getbytes(x->n_sigIN * sizeof(t_float *)); + x->sigOUT = (t_float **)getbytes(x->n_sigOUT * sizeof(t_float *)); + x->sigBUF = (t_float *)getbytes(x->n_sigOUT * sizeof(t_float )); + + x->value = (t_float **)getbytes(x->n_sigOUT * sizeof(t_float)); + x->target = (t_float **)getbytes(x->n_sigOUT * sizeof(t_float)); + x->increment = (t_float **)getbytes(x->n_sigOUT * sizeof(t_float)); + + i = x->n_sigOUT; + while(i--){ + int j = x->n_sigIN; + x->sigOUT [i] = 0; + x->value [i] = (t_float *)getbytes(x->n_sigIN * sizeof(t_float)); + x->target [i] = (t_float *)getbytes(x->n_sigIN * sizeof(t_float)); + x->increment[i] = (t_float *)getbytes(x->n_sigIN * sizeof(t_float)); + + while(j--)x->value[i][j]=x->target[i][j]=x->increment[i][j]=0; + } + + i = x->n_sigIN; + while(i--)x->sigIN[i] = 0; + + x->msec2tick = x->ticksleft = x->retarget = 0; + return (x); +} + +static void sigmtx_setup(void) +{ + sigmtx_class = class_new(gensym("matrix~"), (t_newmethod)sigmtx_new, (t_method)sigmtx_free, + sizeof(t_sigmtx), 0, A_GIMME, 0); + + class_addmethod(sigmtx_class, (t_method)sigmtx_dsp, gensym("dsp"), 0); + class_addmethod(sigmtx_class, nullfn, gensym("signal"), 0); + + class_addmethod(sigmtx_class, (t_method)sigmtx_matrix, gensym(""), A_GIMME, 0); + class_addmethod(sigmtx_class, (t_method)sigmtx_stop, gensym("stop"), 0); + + class_sethelpsymbol(sigmtx_class, gensym("zexy/matrix~")); +} + +/* ------------------------------------------------------------------------------ */ + +/* demux~ : demultiplex a signal to a specified output */ + +static t_class *demux_class; + +typedef struct _demux { + t_object x_obj; + + int output; + + int n_out; + t_float **out; + + int changed; + int oldout; +} t_demux; + +static void demux_output(t_demux *x, t_floatarg f) +{ + if ((f>=0)&&(f<x->n_out)&&((int)f!=x->output)){ + x->oldout=x->output; + x->output=f; + x->changed=1; + } +} + + +static t_int *demux_perform(t_int *w) +{ + t_demux *x = (t_demux *)(w[1]); + t_float *in = (t_float *)(w[2]); + int N = (int)(w[3]); + int n = N, i; + + t_float *out = x->out[x->output]; + + if(x->changed){ + t_float *oldout=x->out[x->oldout]; + x->changed=0; + + if (out!=in) + while(n--){ + *out++=*in; + *in++=*oldout++=0; + } + else + while(n--)*oldout++=0; + + } else { /* !changed */ + if (out!=in) + while(n--){ + *out++=*in; + *in++=0; + } + } + + return (w+4); +} + +static void demux_dsp(t_demux *x, t_signal **sp) +{ + int n = x->n_out; + t_float **dummy=x->out; + while(n--)*dummy++=sp[x->n_out-n]->s_vec; + dsp_add(demux_perform, 3, x, sp[0]->s_vec, sp[0]->s_n); +} + + +static void demux_helper(void) +{ + post("\n%c demux~\t:: demultiplex a signal to one of various outlets", HEARTSYMBOL); + post("<#out>\t : the outlet-number (counting from 0) to witch the inlet is routed" + "'help'\t : view this"); + post("creation : \"demux~ [arg1 [arg2...]]\"\t: the number of arguments equals the number of outlets\n"); +} + +static void demux_free(t_demux *x) +{ + freebytes(x->out, x->n_out * sizeof(t_float *)); +} + +static void *demux_new(t_symbol *s, int argc, t_atom *argv) +{ + t_demux *x = (t_demux *)pd_new(demux_class); + int i; + + if (!argc)argc=2; + x->n_out=argc; + x->output=0; + + while(argc--)outlet_new(&x->x_obj, gensym("signal")); + + x->out = (t_float **)getbytes(x->n_out * sizeof(t_float *)); + i=x->n_out; + while(i--)x->out[i]=0; + + return (x); +} + +void demux_setup(void) +{ + demux_class = class_new(gensym("demultiplex~"), (t_newmethod)demux_new, (t_method)demux_free, sizeof(t_demux), 0, A_GIMME, 0); + class_addcreator((t_newmethod)demux_new, gensym("demux~"), A_GIMME, 0); + + class_addfloat(demux_class, demux_output); + class_addmethod(demux_class, (t_method)demux_dsp, gensym("dsp"), 0); + class_addmethod(demux_class, nullfn, gensym("signal"), 0); + + class_addmethod(demux_class, (t_method)demux_helper, gensym("help"), 0); + class_sethelpsymbol(demux_class, gensym("zexy/demultiplex~")); +} + + +/* ------------------------------------------------------------------------------ */ + +/* mux~ : multiplex a specified signal to the output */ + +static t_class *mux_class; + +typedef struct _mux { + t_object x_obj; + + int input; + + int n_in; + t_float **in; + + int changed; + int oldin; +} t_mux; + +static void mux_input(t_mux *x, t_floatarg f) +{ + if ((f>=0)&&(f<x->n_in)&&((int)f!=x->input)){ + x->oldin=x->input; + x->input=f; + x->changed=1; + } +} + +static t_int *mux_perform(t_int *w) +{ + t_mux *x = (t_mux *)(w[1]); + t_float *out = (t_float *)(w[2]); + int n = (int)(w[3]); + + t_float *in; + + in = x->in[x->input]; + + if(x->changed){ + t_float *oldin=x->in[x->oldin]; + x->changed=0; + if (in!=out) + while(n--){ + *out++=*in; + *in++=*oldin++=0; + } + else while(n--)*oldin++=0; + } else { + if (in!=out) + while(n--){ + *out++=*in; + *in++=0; + } + } + return (w+4); +} + +static void mux_dsp(t_mux *x, t_signal **sp) +{ + int n = 0; + t_float **dummy=x->in; + + for(n=0;n<x->n_in;n++)*dummy++=sp[n]->s_vec; + + dsp_add(mux_perform, 3, x, sp[n]->s_vec, sp[0]->s_n); +} + +static void mux_helper(void) +{ + post("\n%c mux~\t:: multiplex a one of various signals to one outlet", HEARTSYMBOL); + post("<#out>\t : the inlet-number (counting from 0) witch is routed to the outlet" + "'help'\t : view this"); + post("creation : \"mux~ [arg1 [arg2...]]\"\t: the number of arguments equals the number of inlets\n"); +} + +static void mux_free(t_mux *x) +{ + freebytes(x->in, x->n_in * sizeof(t_float *)); +} + +static void *mux_new(t_symbol *s, int argc, t_atom *argv) +{ + t_mux *x = (t_mux *)pd_new(mux_class); + int i; + + if (!argc)argc=2; + x->n_in=argc; + x->input=0; + + argc--; + while(argc--)inlet_new(&x->x_obj,&x->x_obj.ob_pd,&s_signal,&s_signal); + + x->in = (t_float **)getbytes(x->n_in * sizeof(t_float *)); + i=x->n_in; + while(i--)x->in[i]=0; + + outlet_new(&x->x_obj, gensym("signal")); + + return (x); +} + +void mux_setup(void) +{ + mux_class = class_new(gensym("multiplex~"), (t_newmethod)mux_new, (t_method)mux_free, sizeof(t_mux), 0, A_GIMME, 0); + class_addcreator((t_newmethod)mux_new, gensym("mux~"), A_GIMME, 0); + + class_addfloat(mux_class, mux_input); + class_addmethod(mux_class, (t_method)mux_dsp, gensym("dsp"), 0); + class_addmethod(mux_class, nullfn, gensym("signal"), 0); + + class_addmethod(mux_class, (t_method)mux_helper, gensym("help"), 0); + class_sethelpsymbol(mux_class, gensym("zexy/multiplex~")); +} + +/* ---------------------------------------------------------------------- + * main setup + * ---------------------------------------------------------------------- */ + +void z_sigmatrix_setup(void) +{ + sigmtx_setup(); + demux_setup(); + mux_setup(); +} diff --git a/src/z_sigpack.c b/src/z_sigpack.c new file mode 100644 index 0000000..d614543 --- /dev/null +++ b/src/z_sigpack.c @@ -0,0 +1,198 @@ +/* 0109:forum::für::umläute:2000 + pack~ :: convert signals to float-packages + unpack~ :: convert float-(package)-inputs to signals +*/ + +#include "zexy.h" +#include <math.h> + +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +/* ------------------------ pack~ ----------------------------- */ +/* pack the signal-vector to a float-package :: ~2message */ + +static t_class *sigpack_class; + +typedef struct _sigpack +{ + t_object x_obj; + + int vector_length; + t_atom *buffer; + +} t_sigpack; + +static t_int *sigpack_perform(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_sigpack *x = (t_sigpack *)w[2]; + int n = (int)(w[3]), i = 0; + t_atom *buf = x->buffer; + + while (n--) { + SETFLOAT(&buf[i], *in++); + i++; + } + outlet_list(x->x_obj.ob_outlet, &s_list, x->vector_length, x->buffer); + + return (w+4); +} + +static void sigpack_dsp(t_sigpack *x, t_signal **sp) +{ + if (x->vector_length != sp[0]->s_n) { + freebytes(x->buffer, x->vector_length * sizeof(t_atom)); + x->vector_length = sp[0]->s_n; + x->buffer = (t_atom *)getbytes(x->vector_length * sizeof(t_atom)); + } + dsp_add(sigpack_perform, 3, sp[0]->s_vec, x, sp[0]->s_n); +} + +static void *sigpack_new(void) +{ + t_sigpack *x = (t_sigpack *)pd_new(sigpack_class); + x->vector_length = 0; + x->buffer = 0; + outlet_new(&x->x_obj, gensym("list")); + + return (x); +} + +static void sigpack_help(void) +{ + post("pack~\t:: outputs the signal-vectors as float-packages"); +} + +void sigpack_setup(void) +{ + sigpack_class = class_new(gensym("pack~"), (t_newmethod)sigpack_new, 0, + sizeof(t_sigpack), 0, A_DEFFLOAT, 0); + class_addmethod(sigpack_class, nullfn, gensym("signal"), 0); + class_addmethod(sigpack_class, (t_method)sigpack_dsp, gensym("dsp"), 0); + + class_addmethod(sigpack_class, (t_method)sigpack_help, gensym("help"), 0); + class_sethelpsymbol(sigpack_class, gensym("zexy/pack~")); +} + +/* ---------------------------- unpack~ ----------------------------- */ +/* unpack a sequence of float-package to a signal-vector :: message2~ */ + +static t_class *sigunpack_class; + +typedef struct _sigunpack +{ + t_object x_obj; + t_float *buffer; + t_float *rp, *wp; + int bufsize; + +} t_sigunpack; + +static void sigunpack_float(t_sigunpack *x, t_float f) +{ + if (x->wp + 1 != x->rp) { + *(x->wp)++ = f; + if (x->wp == x->buffer + x->bufsize) x->wp = x->buffer; + } +} + +static void sigunpack_list(t_sigunpack *x, t_symbol *s, int argc, t_atom *argv) +{ + t_atom *ap = argv; + int i; + + for (i = 0, ap = argv; i < argc; ap++, i++) { + // if (ap->a_type == A_FLOAT) { + if (x->wp + 1 != x->rp) { + *(x->wp)++ = atom_getfloat(ap); + if (x->wp == x->buffer + x->bufsize) x->wp = x->buffer; + } + // } + } +} + + +static t_int *sigunpack_perform(t_int *w) +{ + t_float *out = (t_float *)(w[1]); + t_sigunpack *x = (t_sigunpack *)w[2]; + int n = (int)(w[3]); + + t_float *buf = x->rp; + int hitchhike = 0; + + if ((x->wp >= x->rp) && (x->wp < x->rp+n)) hitchhike=1; + x->rp += n; + if (x->rp == x->buffer + x->bufsize) x->rp = x->buffer; + if (hitchhike) x->wp = x->rp; + + while (n--) { + *out++ = *buf; + *buf++ = 0; + } + + return (w+4); +} + +static void sigunpack_dsp(t_sigunpack *x, t_signal **sp) +{ + if (x->bufsize % sp[0]->s_n) { + int newsize = sp[0]->s_n*(1+(int)(x->bufsize/sp[0]->s_n)); + freebytes(x->buffer, x->bufsize * sizeof(t_float)); + x->buffer = (t_float *)getbytes(newsize * sizeof(t_float)); + + x->rp = x->wp = x->buffer; + x->bufsize = newsize; + } + + dsp_add(sigunpack_perform, 3, sp[0]->s_vec, x, sp[0]->s_n); +} + +static void *sigunpack_new(t_floatarg f) +{ + t_sigunpack *x = (t_sigunpack *)pd_new(sigunpack_class); + + int suggestedsize = (int)f; + int bufsize; + if (!suggestedsize) bufsize = 64; + else bufsize = (suggestedsize % 64)?(64*(1+(int)(suggestedsize/64))):suggestedsize; + + x->buffer = (t_float *)getbytes(bufsize * sizeof(t_float)); + x->bufsize = bufsize; + x->rp = x->wp = x->buffer; + + outlet_new(&x->x_obj, gensym("signal")); + + return (x); +} + +static void sigunpack_help(void) +{ + post("unpack~\t:: outputs a sequence of floats as a signal"); +} + +void sigunpack_setup(void) +{ + sigunpack_class = class_new(gensym("unpack~"), (t_newmethod)sigunpack_new, 0, + sizeof(t_sigunpack), 0, A_DEFFLOAT, 0); + class_addmethod(sigunpack_class, (t_method)sigunpack_dsp, gensym("dsp"), 0); + class_addfloat(sigunpack_class, (t_method)sigunpack_float); + class_addlist (sigunpack_class, (t_method)sigunpack_list); + + + class_addmethod(sigunpack_class, (t_method)sigunpack_help, gensym("help"), 0); + class_sethelpsymbol(sigunpack_class, gensym("zexy/unpack~")); +} + + + +/* global setup routine */ + +void z_sigpack_setup(void) +{ + sigunpack_setup(); + sigpack_setup(); +} diff --git a/src/z_sigzero.c b/src/z_sigzero.c new file mode 100644 index 0000000..a3f0790 --- /dev/null +++ b/src/z_sigzero.c @@ -0,0 +1,100 @@ +#include "zexy.h" +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +/* ------------------------ sigzero~ ----------------------------- */ +/* + a very useful function, which detects, whether a signal is zeroes-only this block or not + this is really great together with the "switch~"-object +*/ + + + +static t_class *sigzero_class; + +typedef struct _sigzero +{ + t_object x_obj; + int activate; + int current; /* 0 == (signalblock == 0); 1==(signalblock != 0) */ +} t_sigzero; + +static void sigzero_activate(t_sigzero *x, t_floatarg activate) +{ + x->activate = (activate)?1:0; +} + +static void sigzero_banged(t_sigzero *x, t_floatarg activate) +{ + x->activate = 1; +} + +static void sigzero_off(t_sigzero *x, t_floatarg activate) +{ + x->activate = 0; +} + +static t_int *sigzero_perform(t_int *w) +{ + t_float *in = (t_float *)w[1]; + t_sigzero *x = (t_sigzero *)w[2]; + int n = (int)w[3]; + + int non_zero = 0; + + if (x->activate) { + while (n--) + { + if (*in++ != 0.) { + non_zero = 1; + break; + } + } + if (non_zero != x->current) { + outlet_float(x->x_obj.ob_outlet, x->current = non_zero); + } +// else post("non_zero=%d\tcurrent=%d", non_zero, x->current); + } + + return (w+4); +} + +static void sigzero_dsp(t_sigzero *x, t_signal **sp) +{ + dsp_add(sigzero_perform, 3, sp[0]->s_vec, x, sp[0]->s_n); +} + +static void helper(void) +{ + post("\n%c sigzero~-object :: for detecting whether a signal is currently zero or not", HEARTSYMBOL); + post("'bang'\t: turn the detector on\n" + "'off'\t: turn it off\n" + "<1/0>\t: turn it on/off\n" + "'help'\t: view this\n" + "signal~"); + post("outlet :: 1/0\t: signal turned to non-zero/zero\n"); +} + +static void *sigzero_new(t_symbol s) +{ + t_sigzero *x = (t_sigzero *)pd_new(sigzero_class); + outlet_new(&x->x_obj, &s_float); + return (x); +} + +void z_sigzero_setup(void) +{ + sigzero_class = class_new(gensym("sigzero~"), (t_newmethod)sigzero_new, 0, + sizeof(t_sigzero), 0, 0); + class_addfloat(sigzero_class, sigzero_activate); + class_addbang(sigzero_class, sigzero_banged); + class_addmethod(sigzero_class, (t_method)sigzero_off, gensym("off"), 0); + + class_addmethod(sigzero_class, nullfn, gensym("signal"), 0); + class_addmethod(sigzero_class, (t_method)sigzero_dsp, gensym("dsp"), 0); + + class_addmethod(sigzero_class, (t_method)helper, gensym("help"), 0); + class_sethelpsymbol(sigzero_class, gensym("zexy/sigzero~")); +} diff --git a/src/z_skeleton.c b/src/z_skeleton.c new file mode 100644 index 0000000..e13c385 --- /dev/null +++ b/src/z_skeleton.c @@ -0,0 +1,57 @@ + +/* 1008:forum::für::umläute:2001 */ + +/* + skeleton : skeleton-code for message-objects +*/ + +#include "zexy.h" + +/* ------------------------- skeleton ------------------------------- */ + +/* +MESSAGE SKELETON: simple and easy +*/ + +static t_class *skeleton_class; + +typedef struct _skeleton +{ + t_object x_obj; + +} t_skeleton; + + +static void skeleton_float(t_skeleton *x, t_float f) +{ + +} + +static void skeleton_list(t_skeleton *x, t_symbol *s, int argc, t_atom *argv) +{ + +} + +static void skeleton_foo(t_skeleton *x, t_float f) +{ + +} + +static void *skeleton_new(t_floatarg f) +{ + t_skeleton *x = (t_skeleton *)pd_new(skeleton_class); + + return (x); +} + +void z_skeleton_setup(void) +{ + skeleton_class = class_new(gensym("skeleton"), (t_newmethod)skeleton_new, + 0, sizeof(t_skeleton), 0, A_DEFFLOAT, 0); + + class_addlist (skeleton_class, skeleton_list); + class_addfloat (skeleton_class, skeleton_float); + class_addmethod(skeleton_class, (t_method)skeleton_foo, gensym("foo"), A_DEFFLOAT, 0); + + class_sethelpsymbol(skeleton_class, gensym("zexy/skeleton")); +} diff --git a/src/z_skeleton_tilde.c b/src/z_skeleton_tilde.c new file mode 100644 index 0000000..2e638f7 --- /dev/null +++ b/src/z_skeleton_tilde.c @@ -0,0 +1,61 @@ +#include <stdio.h> + +#include "zexy.h" + +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +/* skeleton~ : skeleton-code for a signal-object */ + +/* ------------------------ skeleton~ ----------------------------- */ + +static t_class *skeleton_class; + +typedef struct _skeleton +{ + t_object x_obj; + +} t_skeleton; + + +static t_int *skeleton_perform(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_float *out = (t_float *)(w[2]); + int n = (int)(w[3]); + t_skeleton *x = (t_skeleton *) w[4]; + + while (n--) { + *in++=*out++; + } + + return (w+5); +} + +static void skeleton_dsp(t_skeleton *x, t_signal **sp) +{ + dsp_add(skeleton_perform, 4, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n,x); +} + + + +static void *skeleton_new() +{ + t_skeleton *x = (t_skeleton *)pd_new(skeleton_class); + outlet_new(&x->x_obj, gensym("signal")); + + return (x); +} + +void z_skeleton_setup(void) +{ + skeleton_class = class_new(gensym("skeleton~"), (t_newmethod)skeleton_new, 0, + sizeof(t_skeleton), 0, A_DEFFLOAT, 0); + class_addmethod(skeleton_class, nullfn, gensym("signal"), 0); + class_addmethod(skeleton_class, (t_method)skeleton_dsp, gensym("dsp"), 0); + + class_sethelpsymbol(skeleton_class, gensym("zexy/skeleton~")); +} + diff --git a/src/z_sort.c b/src/z_sort.c new file mode 100644 index 0000000..e0c656a --- /dev/null +++ b/src/z_sort.c @@ -0,0 +1,114 @@ + +/* 1309:forum::für::umläute:2000 */ + +/* + sort : sort a package of floats +*/ + +#include "zexy.h" + +/* ------------------------- sort ------------------------------- */ + +/* +SHELL SORT: simple and easy +*/ + +static t_class *sort_class; + +typedef struct _sort +{ + t_object x_obj; + + int bufsize; + t_float *buffer; + + int ascending; +} t_sort; + + +static void sort_dir(t_sort *x, t_float f) +{ + x->ascending = (f < 0.f)?0:1; +} + +static void sort_buffer(t_sort *x, int argc, t_atom *argv) +{ + int n = argc; + t_float *buf; + t_atom *atombuf = argv; + + if (argc != x->bufsize) { + if (x->buffer) freebytes(x->buffer, x->bufsize * sizeof(t_float)); + x->bufsize = argc; + x->buffer = getbytes(x->bufsize * sizeof(t_float)); + } + + buf = x->buffer; + while (n--) + *buf++ = atom_getfloat(atombuf++); +} + +static void sort_list(t_sort *x, t_symbol *s, int argc, t_atom *argv) +{ + int step = argc, n; + t_atom *atombuf = (t_atom *)getbytes(sizeof(t_atom) * argc); + t_float *buf; + + int i, loops = 1; + + sort_buffer(x, argc, argv); + buf = x->buffer; + + while (step > 1) { + step = (step % 2)?(step+1)/2:step/2; + + // i = loops++; + i = loops; + loops += 2; + + while(i--) { /* there might be some optimization in here */ + for (n=0; n<(argc-step); n++) { + if (buf[n] > buf[n+step]) { + t_float dummy = buf[n]; + buf[n] = buf[n+step]; + buf[n+step] = dummy; + } + } + } + } + + if (x->ascending) + for (n = 0; n < argc; n++) SETFLOAT(&atombuf[n], buf[n]); + else + for (n = 0, i=argc-1; n < argc; n++, i--) SETFLOAT(&atombuf[n], buf[i]); + + outlet_list(x->x_obj.ob_outlet, &s_list, n, atombuf); + + freebytes(atombuf, sizeof(atombuf)); +} + +static void *sort_new(t_floatarg f) +{ + t_sort *x = (t_sort *)pd_new(sort_class); + x->ascending = (f < 0.f)?0:1; + + outlet_new(&x->x_obj, &s_list); + + x->bufsize = 0; + x->buffer = NULL; + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("direction")); + + return (x); +} + +void z_sort_setup(void) +{ + sort_class = class_new(gensym("sort"), (t_newmethod)sort_new, + 0, sizeof(t_sort), 0, A_DEFFLOAT, 0); + + class_addlist (sort_class, sort_list); + class_addmethod (sort_class, (t_method)sort_dir, gensym("direction"), A_DEFFLOAT, 0); + + class_sethelpsymbol(sort_class, gensym("zexy/sort")); +} diff --git a/src/z_stat.c b/src/z_stat.c new file mode 100644 index 0000000..5b3a5e6 --- /dev/null +++ b/src/z_stat.c @@ -0,0 +1,164 @@ +#include "zexy.h" +#include <math.h> + +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#define sqrtf sqrt +#endif + +/* mean :: the mean of a list of floats */ + +static t_class *mean_class; + +typedef struct _mean +{ + t_object x_obj; +} t_mean; + +static void mean_list(t_mean *x, t_symbol *s, int argc, t_atom *argv) +{ + t_float factor = 1./argc; + t_float sum = 0; + + while(argc--)sum+=atom_getfloat(argv++); + + outlet_float(x->x_obj.ob_outlet,sum*factor); +} + +static void *mean_new(void) +{ + t_mean *x = (t_mean *)pd_new(mean_class); + + outlet_new(&x->x_obj, gensym("float")); + + return (x); +} + +static void mean_help(void) +{ + post("mean\t:: calculate the mean of a list of floats"); +} + +static void mean_setup(void) +{ + mean_class = class_new(gensym("mean"), (t_newmethod)mean_new, 0, + sizeof(t_mean), 0, A_DEFFLOAT, 0); + + class_addlist(mean_class, (t_method)mean_list); + class_addmethod(mean_class, (t_method)mean_help, gensym("help"), 0); + + class_sethelpsymbol(mean_class, gensym("zexy/mean")); +} + +/* minmax :: get minimum and maximum of a list */ + +static t_class *minmax_class; + +typedef struct _minmax +{ + t_object x_obj; + t_float min; + t_float max; + + t_outlet *mino, *maxo; +} t_minmax; + +static void minmax_bang(t_minmax *x) +{ + outlet_float(x->maxo,x->max); + outlet_float(x->mino,x->min); +} + +static void minmax_list(t_minmax *x, t_symbol *s, int argc, t_atom *argv) +{ + t_float min = atom_getfloat(argv++); + t_float max=min; + argc--; + + while(argc--){ + t_float f = atom_getfloat(argv++); + if (f<min)min=f; + else if (f>max)max=f; + } + + x->min=min; + x->max=max; + + minmax_bang(x); +} + +static void *minmax_new(void) +{ + t_minmax *x = (t_minmax *)pd_new(minmax_class); + + x->mino=outlet_new(&x->x_obj, gensym("float")); + x->maxo=outlet_new(&x->x_obj, gensym("float")); + + x->min = x->max = 0; + + return (x); +} + +static void minmax_help(void) +{ + post("minmax\t:: get minimum and maximum of a list of floats"); +} + +static void minmax_setup(void) +{ + minmax_class = class_new(gensym("minmax"), (t_newmethod)minmax_new, 0, + sizeof(t_minmax), 0, A_DEFFLOAT, 0); + + class_addlist(minmax_class, (t_method)minmax_list); + class_addbang(minmax_class, (t_method)minmax_bang); + class_addmethod(minmax_class, (t_method)minmax_help, gensym("help"), 0); + + class_sethelpsymbol(minmax_class, gensym("zexy/minmax")); +} + +/* length :: get minimum and maximum of a list */ + +static t_class *length_class; + +typedef struct _length +{ + t_object x_obj; +} t_length; + +static void length_list(t_length *x, t_symbol *s, int argc, t_atom *argv) +{ + outlet_float(x->x_obj.ob_outlet, (t_float)argc); +} +static void length_any(t_length *x, t_symbol *s, int argc, t_atom *argv) +{ + outlet_float(x->x_obj.ob_outlet, (t_float)argc+1); +} + +static void *length_new(void) +{ + t_length *x = (t_length *)pd_new(length_class); + outlet_new(&x->x_obj, gensym("float")); + return (x); +} + +static void length_setup(void) +{ + length_class = class_new(gensym("length"), (t_newmethod)length_new, 0, + sizeof(t_length), 0, A_DEFFLOAT, 0); + + class_addlist(length_class, (t_method)length_list); + class_addanything(length_class, (t_method)length_any); + // class_addbang(length_class, (t_method)length_bang); + + class_sethelpsymbol(length_class, gensym("zexy/length")); +} + +/* global setup routine */ + +void z_stat_setup(void) +{ + mean_setup(); + minmax_setup(); + length_setup(); +} diff --git a/src/z_strings.c b/src/z_strings.c new file mode 100644 index 0000000..4992d18 --- /dev/null +++ b/src/z_strings.c @@ -0,0 +1,251 @@ +#include "zexy.h" +#include <stdlib.h> + +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#define sqrtf sqrt +#endif + +/* + * atoi : ascii to integer + * strcmp : compare 2 lists as if they were strings +*/ + +/* atoi :: ascii to integer */ + +static t_class *atoi_class; + +typedef struct _atoi +{ + t_object x_obj; + int i; +} t_atoi; +static void atoi_bang(t_atoi *x) +{ + outlet_float(x->x_obj.ob_outlet, (t_float)x->i); +} +static void atoi_float(t_atoi *x, t_floatarg f) +{ + x->i = f; + outlet_float(x->x_obj.ob_outlet, (t_float)x->i); +} +static void atoi_symbol(t_atoi *x, t_symbol *s) +{ + int base=10; + const char* c = s->s_name; + if(c[0]=='0'){ + base=8; + if (c[1]=='x')base=16; + } + x->i=strtol(c, 0, base); + outlet_float(x->x_obj.ob_outlet, (t_float)x->i); +} +static void atoi_list(t_atoi *x, t_symbol *s, int argc, t_atom *argv) +{ + int base=10; + const char* c; + + if (argv->a_type==A_FLOAT){ + x->i=atom_getfloat(argv); + outlet_float(x->x_obj.ob_outlet, (t_float)x->i); + return; + } + + if (argc>1){ + base=atom_getfloat(argv+1); + if (base<2) { + error("atoi: setting base to 10"); + base=10; + } + } + c=atom_getsymbol(argv)->s_name; + x->i=strtol(c, 0, base); + outlet_float(x->x_obj.ob_outlet, (t_float)x->i); +} + +static void *atoi_new(void) +{ + t_atoi *x = (t_atoi *)pd_new(atoi_class); + outlet_new(&x->x_obj, gensym("float")); + return (x); +} + +static void atoi_setup(void) +{ + atoi_class = class_new(gensym("atoi"), (t_newmethod)atoi_new, 0, + sizeof(t_atoi), 0, A_DEFFLOAT, 0); + + class_addbang(atoi_class, (t_method)atoi_bang); + class_addfloat(atoi_class, (t_method)atoi_float); + class_addlist(atoi_class, (t_method)atoi_list); + class_addsymbol(atoi_class, (t_method)atoi_symbol); + class_addanything(atoi_class, (t_method)atoi_symbol); + + class_sethelpsymbol(atoi_class, gensym("zexy/atoi")); +} + +/* ------------------------- strcmp ------------------------------- */ + +/* compare 2 lists ( == for lists) */ + +static t_class *strcmp_class; + +typedef struct _strcmp +{ + t_object x_obj; + + t_binbuf *bbuf1, *bbuf2; +} t_strcmp; + +static void strcmp_bang(t_strcmp *x) +{ + char *str1=0, *str2=0; + int n1=0, n2=0; + int result = 0; + + binbuf_gettext(x->bbuf1, &str1, &n1); + binbuf_gettext(x->bbuf2, &str2, &n2); + + result = strcmp(str1, str2); + + freebytes(str1, n1); + freebytes(str2, n2); + + outlet_float(x->x_obj.ob_outlet, result); +} + +static void strcmp_secondlist(t_strcmp *x, t_symbol *s, int argc, t_atom *argv) +{ + binbuf_clear(x->bbuf2); + binbuf_add(x->bbuf2, argc, argv); +} + +static void strcmp_list(t_strcmp *x, t_symbol *s, int argc, t_atom *argv) +{ + binbuf_clear(x->bbuf1); + binbuf_add(x->bbuf1, argc, argv); + + strcmp_bang(x); +} + +static void *strcmp_new(t_symbol *s, int argc, t_atom *argv) +{ + t_strcmp *x = (t_strcmp *)pd_new(strcmp_class); + + outlet_new(&x->x_obj, 0); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("list"), gensym("lst2")); + + x->bbuf1 = binbuf_new(); + x->bbuf2 = binbuf_new(); + + + strcmp_secondlist(x, gensym("list"), argc, argv); + + return (x); +} + +static void strcmp_free(t_strcmp *x) +{ + binbuf_free(x->bbuf1); + binbuf_free(x->bbuf2); +} + + +static void strcmp_setup(void) +{ + strcmp_class = class_new(gensym("strcmp"), (t_newmethod)strcmp_new, + (t_method)strcmp_free, sizeof(t_strcmp), 0, A_GIMME, 0); + + class_addbang (strcmp_class, strcmp_bang); + class_addlist (strcmp_class, strcmp_list); + class_addmethod (strcmp_class, (t_method)strcmp_secondlist, gensym("lst2"), A_GIMME, 0); + + class_sethelpsymbol(strcmp_class, gensym("zexy/strcmp")); +} + +/* ------------------------- list2symbol ------------------------------- */ + +/* compare 2 lists ( == for lists) */ + +static t_class *list2symbol_class; + +typedef struct _list2symbol +{ + t_object x_obj; + + t_binbuf *bbuf; +} t_list2symbol; + +static void list2symbol_bang(t_list2symbol *x) +{ + char *str=0, *s2; + int n=0; + + binbuf_gettext(x->bbuf, &str, &n); + /* memory bug ! detected and fixed by Juvu */ + s2 = copybytes(str, n+1); + s2[n]=0; + + outlet_symbol(x->x_obj.ob_outlet, gensym(s2)); + freebytes(str, n); + freebytes(s2,n+1); +} + +static void list2symbol_list(t_list2symbol *x, t_symbol *s, int argc, t_atom *argv) +{ + binbuf_clear(x->bbuf); + binbuf_add(x->bbuf, argc, argv); + + list2symbol_bang(x); +} +static void list2symbol_anything(t_list2symbol *x, t_symbol *s, int argc, t_atom *argv) +{ + t_atom ap; + binbuf_clear(x->bbuf); + SETSYMBOL(&ap, s); + binbuf_add(x->bbuf, 1, &ap); + binbuf_add(x->bbuf, argc, argv); + + list2symbol_bang(x); +} + +static void *list2symbol_new(t_symbol *s, int argc, t_atom *argv) +{ + t_list2symbol *x = (t_list2symbol *)pd_new(list2symbol_class); + + outlet_new(&x->x_obj, 0); + x->bbuf = binbuf_new(); + binbuf_add(x->bbuf, argc, argv); + + return (x); +} + +static void list2symbol_free(t_list2symbol *x) +{ + binbuf_free(x->bbuf); +} + + +static void list2symbol_setup(void) +{ + list2symbol_class = class_new(gensym("list2symbol"), (t_newmethod)list2symbol_new, + (t_method)list2symbol_free, sizeof(t_list2symbol), 0, A_GIMME, 0); + + class_addcreator((t_newmethod)list2symbol_new, gensym("l2s"), A_GIMME, 0); + class_addbang (list2symbol_class, list2symbol_bang); + class_addlist (list2symbol_class, list2symbol_list); + class_addanything(list2symbol_class, list2symbol_anything); + + class_sethelpsymbol(list2symbol_class, gensym("zexy/list2symbol")); +} + + +/* global setup routine */ + +void z_strings_setup(void) +{ + atoi_setup(); + strcmp_setup(); + list2symbol_setup(); +} diff --git a/src/z_swap.c b/src/z_swap.c new file mode 100644 index 0000000..60b72c2 --- /dev/null +++ b/src/z_swap.c @@ -0,0 +1,89 @@ +/* + the long waited for swap~-object that does a byte swap + of course, we unfortunately have to quantize the float-signal to 16bit (to get bytes) + + 1110:forum::für::umläute:1999 + */ + +#include "zexy.h" +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +/* ------------------------ swap~ ----------------------------- */ +#define FLOAT2SHORT 32768. +#define SHORT2FLOAT 1./32768. + +static t_class *swap_class; + +typedef struct _swap +{ + t_object x_obj; + int swapper; +} t_swap; + +static void swap_float(t_swap *x, t_floatarg f) +{ + x->swapper = (f != 0); +} + +static void swap_bang(t_swap *x) +{ + x->swapper ^= 1; +} + +static t_int *swap_perform(t_int *w) +{ + t_swap *x = (t_swap *)(w[1]); + t_float *in = (t_float *)(w[2]); + t_float *out = (t_float *)(w[3]); + int n = (int)(w[4]); + + + if (x->swapper) + while (n--) { + short dummy = FLOAT2SHORT * *in++; + *out++ = SHORT2FLOAT * (short)( ((dummy & 0xFF) << 8) | ((dummy & 0xFF00) >> 8) ); + } + else while (n--) *out++ = *in++; + + return (w+5); +} + +static void swap_dsp(t_swap *x, t_signal **sp) +{ + dsp_add(swap_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); +} + +static void helper(void) +{ + post("\n%c swap~-object for byteswapping a signal", HEARTSYMBOL); + post("<1/0> : turn the swapper on/off\n" + "'bang' : toggle the swapper on/off\n" + "'help' : view this\n" + "signal~"); + post("outlet : signal~"); +} + +static void *swap_new() +{ + t_swap *x = (t_swap *)pd_new(swap_class); + outlet_new(&x->x_obj, gensym("signal")); + x->swapper = 1; + return (x); +} + +void z_swap_setup(void) +{ + swap_class = class_new(gensym("swap~"), (t_newmethod)swap_new, 0, + sizeof(t_swap), 0, A_DEFFLOAT, 0); + class_addmethod(swap_class, nullfn, gensym("signal"), 0); + class_addmethod(swap_class, (t_method)swap_dsp, gensym("dsp"), 0); + + class_addfloat(swap_class, swap_float); + class_addbang(swap_class, swap_bang); + + class_addmethod(swap_class, (t_method)helper, gensym("help"), 0); + class_sethelpsymbol(swap_class, gensym("zexy/swap~")); +} diff --git a/src/z_tabread4.c b/src/z_tabread4.c new file mode 100644 index 0000000..ec61bfa --- /dev/null +++ b/src/z_tabread4.c @@ -0,0 +1,249 @@ + +/* ---------- tabread4: control, interpolating ------------------------ */ +/* hack : 2108:forum::für::umläute:1999 @ iem */ + +#include "zexy.h" + + +/* =================== tabdump ====================== */ + +static t_class *tabdump_class; + +typedef struct _tabdump +{ + t_object x_obj; + t_symbol *x_arrayname; +} t_tabdump; + +static void tabdump_bang(t_tabdump *x, t_float findex) +{ + t_garray *A; + int npoints; + t_float *vec; + + if (!(A = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) + error("%s: no such array", x->x_arrayname->s_name); + else if (!garray_getfloatarray(A, &npoints, &vec)) + error("%s: bad template for tabdump", x->x_arrayname->s_name); + else + { + int n; + t_atom *atombuf = (t_atom *)getbytes(sizeof(t_atom)*npoints); + + for (n = 0; n < npoints; n++) SETFLOAT(&atombuf[n], vec[n]); + outlet_list(x->x_obj.ob_outlet, &s_list, npoints, atombuf); + } +} + + +static void tabdump_set(t_tabdump *x, t_symbol *s) +{ + x->x_arrayname = s; +} + +static void *tabdump_new(t_symbol *s) +{ + t_tabdump *x = (t_tabdump *)pd_new(tabdump_class); + x->x_arrayname = s; + outlet_new(&x->x_obj, &s_list); + + return (x); +} + +static void tabdump_helper(void) +{ + post("\n%c tabdump - object : dumps a table as a package of floats", HEARTSYMBOL); + post("'set <table>'\t: read out another table\n" + "'bang'\t\t: dump the table\n" + "outlet\t\t: table-data as package of floats"); + post("creation\t: \"tabdump <table>\""); + +} + +static void tabdump_setup(void) +{ + tabdump_class = class_new(gensym("tabdump"), (t_newmethod)tabdump_new, + 0, sizeof(t_tabdump), 0, A_DEFSYM, 0); + class_addbang(tabdump_class, (t_method)tabdump_bang); + class_addmethod(tabdump_class, (t_method)tabdump_set, gensym("set"), + A_SYMBOL, 0); + + class_addmethod(tabdump_class, (t_method)tabdump_helper, gensym("help"), 0); + class_sethelpsymbol(tabdump_class, gensym("zexy/tabdump")); +} + + +/* =================== tabset ====================== */ + +static t_class *tabset_class; + +typedef struct _tabset +{ + t_object x_obj; + t_symbol *x_arrayname; +} t_tabset; + +static void tabset_float(t_tabset *x, t_floatarg f) +{ + t_garray *A; + int npoints; + t_float *vec; + + if (!(A = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) + error("%s: no such array", x->x_arrayname->s_name); + else if (!garray_getfloatarray(A, &npoints, &vec)) + error("%s: bad template for tabset", x->x_arrayname->s_name); + else { + while(npoints--)*vec++=f; + garray_redraw(A); + } +} + +static void tabset_list(t_tabset *x, t_symbol *s, int argc, t_atom* argv) +{ + t_garray *A; + int npoints; + t_float *vec; + + if (!(A = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) + error("%s: no such array", x->x_arrayname->s_name); + else if (!garray_getfloatarray(A, &npoints, &vec)) + error("%s: bad template for tabset", x->x_arrayname->s_name); + else { + if (argc>=npoints) + while(npoints--)*vec++=atom_getfloat(argv++); + else { + npoints-=argc; + while (argc--)*vec++=atom_getfloat(argv++); + while (npoints--)*vec++=0; + } + garray_redraw(A); + } +} +static void tabset_set(t_tabset *x, t_symbol *s) +{ + x->x_arrayname = s; +} + +static void *tabset_new(t_symbol *s) +{ + t_tabset *x = (t_tabset *)pd_new(tabset_class); + x->x_arrayname = s; + + return (x); +} + +static void tabset_helper(void) +{ + post("\n%c tabset - object : set a table with a package of floats", HEARTSYMBOL); + post("'set <table>'\t: set another table\n" + "<list>\t\t: set the table" + "<float>\t\t: set the table to constant float\n"); + post("creation\t: \"tabset <table>\""); +} + +static void tabset_setup(void) +{ + tabset_class = class_new(gensym("tabset"), (t_newmethod)tabset_new, + 0, sizeof(t_tabset), 0, A_DEFSYM, 0); + class_addfloat(tabset_class, (t_method)tabset_float); + class_addlist (tabset_class, (t_method)tabset_list); + class_addmethod(tabset_class, (t_method)tabset_set, gensym("set"), + A_SYMBOL, 0); + + class_addmethod(tabset_class, (t_method)tabset_helper, gensym("help"), 0); + class_sethelpsymbol(tabset_class, gensym("zexy/tabset")); +} + + +/* =================== tabread4 ====================== */ + +static t_class *tabread4_class; + +typedef struct _tabread +{ + t_object x_obj; + t_symbol *x_arrayname; +} t_tabread; + +static void tabread4_float(t_tabread *x, t_float findex) +{ + t_garray *A; + int npoints; + t_float *vec; + + if (!(A = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) + error("%s: no such array", x->x_arrayname->s_name); + else if (!garray_getfloatarray(A, &npoints, &vec)) + + error("%s: bad template for tabread", x->x_arrayname->s_name); + else + { + float a, b, c, d, cminusb, frac, out; + int index = (int)findex, max_index = npoints - 1; + + if (index < 0) index = 0, frac = 0.; + else if (index > max_index) index = max_index, frac = 0.; + else frac = findex - index; + + a = vec[index-1]; + b = vec[index]; + c = vec[index+1]; + d = vec[index+2]; + cminusb = c - b; + + out = (t_float)(b + frac * (cminusb - 0.5 * (frac-1.) * ( + (a - d + 3.0 * cminusb) * frac + + (b - a - cminusb) + ) + )); + + outlet_float(x->x_obj.ob_outlet, (npoints ? out : 0)); + } +} + + +static void tabread4_set(t_tabread *x, t_symbol *s) +{ + x->x_arrayname = s; +} + +static void *tabread4_new(t_symbol *s) +{ + t_tabread *x = (t_tabread *)pd_new(tabread4_class); + x->x_arrayname = s; + outlet_new(&x->x_obj, &s_float); + + post("zexy/tabread4: this is obsolete, since tabread4 is now included into pd"); + post("maybe you should go for an upgrade..."); + return (x); +} + +static void tabread4_helper(void) +{ + post("\n%c tabread4 - object : reads out a table (4point-interpolation-support)", HEARTSYMBOL); + post("'set <table>': read out another table\n" + "<position> : read from table at specified position\n" + "outlet\t: table-data at specified position (evt. interpolated)"); + post("creation: \"tabread4 <table>\""); + +} + +static void tabread4_setup(void) +{ + tabread4_class = class_new(gensym("tabread4"), (t_newmethod)tabread4_new, + 0, sizeof(t_tabread), 0, A_DEFSYM, 0); + class_addfloat(tabread4_class, (t_method)tabread4_float); + class_addmethod(tabread4_class, (t_method)tabread4_set, gensym("set"), + A_SYMBOL, 0); + + class_addmethod(tabread4_class, (t_method)tabread4_helper, gensym("help"), 0); + class_sethelpsymbol(tabread4_class, gensym("zexy/tabread4")); +} + +void z_tabread4_setup(void) +{ + tabread4_setup(); + tabdump_setup(); + tabset_setup(); +} diff --git a/src/z_testfun.c b/src/z_testfun.c new file mode 100644 index 0000000..57d8f20 --- /dev/null +++ b/src/z_testfun.c @@ -0,0 +1,222 @@ +/* +This external makes the two main test-functions available : +dirac~ : will make a single peak (eg: a 1 in all the 0s) at a desired position in the signal-vector + the position can be passed as an argument when creating the object +step~ : will make a unity step at a desired point in the signal-vector; the second input specifies a + length: after the so-specified time has elapsed, the step will toggle back to the previous + value; + the length can be passed as an argument when creating the object + with length==1 you might do the dirac~ thing a little bit more complicated + with length==0 the output just toggles between 0 and 1 every time you bang the object + +NOTE : the inlets do NOT specify any times but sample-NUMBERS; there are 64 samples in a signal-vector, + each "lasting" for 1/44100 secs. +*/ + +#include "zexy.h" +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +/* ------------------------ dirac~ ----------------------------- */ + + +static t_class *dirac_class; + +typedef struct _dirac +{ + t_object x_obj; + t_float position; + t_float do_it; +} t_dirac; + +static void dirac_bang(t_dirac *x) +{ + x->do_it = x->position; +} + +static void dirac_float(t_dirac *x, t_float where) +{ + x->do_it = x->position = where; +} + +static t_int *dirac_perform(t_int *w) +{ + t_dirac *x = (t_dirac *)(w[1]); + t_float *out = (t_float *)(w[2]); + int n = (int)(w[3]); + + int do_it = x->do_it; + + while (n--) + { + *out++ = (!do_it--); + } + x->do_it = do_it; + + return (w+4); +} + +static void dirac_dsp(t_dirac *x, t_signal **sp) +{ + dsp_add(dirac_perform, 3, x, sp[0]->s_vec, sp[0]->s_n); +} + +static void dirac_helper(void) +{ + post("%c dirac~-object :: generates a dirac (unity-pulse)", HEARTSYMBOL); + post("creation : \"dirac~ [<position>]\" : create a dirac at specified position (in samples)\n" + "inlet\t: <position>\t: create a dirac at new position\n" + "\t 'bang'\t: create a dirac at specified position\n" + "\t 'help'\t: view this\n" + "outlet\t: signal~"); +} + + + +static void *dirac_new(t_floatarg where) +{ + t_dirac *x = (t_dirac *)pd_new(dirac_class); + + outlet_new(&x->x_obj, gensym("signal")); + + x->do_it = 0; + x->position = where; + return (x); +} + +void dirac_setup(void) +{ + dirac_class = class_new(gensym("dirac~"), (t_newmethod)dirac_new, 0, + sizeof(t_dirac), 0, A_DEFFLOAT, 0); + class_addfloat(dirac_class, dirac_float); + class_addbang(dirac_class, dirac_bang); + class_addmethod(dirac_class, (t_method)dirac_dsp, gensym("dsp"), 0); + + class_addmethod(dirac_class, (t_method)dirac_helper, gensym("help"), 0); + class_sethelpsymbol(dirac_class, gensym("zexy/dirac~")); +} + + + +/* ------------------------ step~ ----------------------------- */ + + +static t_class *step_class; + +typedef struct _step +{ + t_object x_obj; + int position; + int length; + + int toggle; + + int wait4start; + int wait4stop; +} t_step; + +static void step_bang(t_step *x) +{ + x->wait4stop = x->length + (x->wait4start = x->position); +} + +static void step_float(t_step *x, t_float where) +{ + x->wait4stop = x->length + + (x->wait4start = + (x->position = (where>0)*where) + ); +} + +static void step_setlength(t_step *x, t_float arg) +{ + x->length = 1 + (arg>0)*arg; +} + + + +static t_int *step_perform(t_int *w) +{ + t_step *x = (t_step *)(w[1]); + t_float *out = (t_float *)(w[2]); + int n = (int)(w[3]); + + int toggle = x->toggle; + + int wait4start = x->wait4start, wait4stop = x->wait4stop; + + while (n--) + { + wait4stop--; + if (!wait4start--) toggle ^= 1; + else if (!wait4stop) toggle ^= 1; + + *out++ = toggle; + } + + x->wait4start = wait4start; + x->wait4stop = wait4stop; + + x->toggle = toggle; + return (w+4); +} + +static void step_dsp(t_step *x, t_signal **sp) +{ + dsp_add(step_perform, 3, x, sp[0]->s_vec, sp[0]->s_n); +} + + +static void step_helper(void) +{ + post("%c step~-object :: generates a unity-step", HEARTSYMBOL); + post("creation : \"dirac~ [<position> [<length>]]\" : create a rectangular window\n" + "\t\t\tat specified position and with specified length (in samples)\n" + "inlet1\t: <position>\t: create a rectangular window at new position\n" + "\t 'bang'\t: create a rectangular window at specified position\n" + "\t 'help'\t: view this\n" + "inlet2\t: <length>\t: define new window length ('0' will make a unity-step)\n" + "outlet\t: signal~"); +} + + +static void *step_new(t_floatarg farg) +{ + t_step *x = (t_step *)pd_new(step_class); + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1")); + outlet_new(&x->x_obj, gensym("signal")); + + x->position = 0; + x->wait4start = x->wait4stop = 0; + x->toggle = 1; + + step_setlength(x, farg); + + return (x); +} + +void step_setup(void) +{ + step_class = class_new(gensym("step~"), (t_newmethod)step_new, 0, + sizeof(t_step), 0, A_DEFFLOAT, 0); + + class_addfloat(step_class, step_float); + class_addbang(step_class, step_bang); + class_addmethod(step_class, (t_method)step_setlength, gensym("ft1"), A_FLOAT, 0); + class_addmethod(step_class, (t_method)step_dsp, gensym("dsp"), 0); + + class_addmethod(step_class, (t_method)step_helper, gensym("help"), 0); + class_sethelpsymbol(step_class, gensym("zexy/step~")); + +} + +/* global setup routine */ + +void z_testfun_setup(void) +{ + step_setup(); + dirac_setup(); +} diff --git a/src/z_urn.c b/src/z_urn.c new file mode 100644 index 0000000..961baab --- /dev/null +++ b/src/z_urn.c @@ -0,0 +1,120 @@ + +/* 1008:forum::für::umläute:2001 */ + +/* + urn : "generate random numbers without duplicates" + very max-like +*/ + +#include "zexy.h" + +/* ------------------------- urn ------------------------------- */ + +static t_class *urn_class; + +typedef struct _urn +{ + t_object x_obj; + unsigned int x_seed; /* the seed of the generator */ + + unsigned int x_range; /* max. random-number + 1 */ + unsigned int x_count; /* how many random numbers have we generated ? */ + char *x_state; /* has this number been generated already ? */ +} t_urn; + +static int makeseed(void) +{ + static unsigned int random_nextseed = 1489853723; + random_nextseed = random_nextseed * 435898247 + 938284287; + return (random_nextseed & 0x7fffffff); +} + +static void urn_clear(t_urn *x) +{ + unsigned int i=x->x_range; + t_int *dummy=x->x_state; + while(i--)*dummy++=0; + x->x_count=0; +} + +static void makestate(t_urn *x, unsigned int newrange) +{ + if (x->x_range == newrange)return; + + if (x->x_range && x->x_state) { + freebytes(x->x_state, sizeof(char)*x->x_range); + x->x_state=0; + } + + x->x_range=newrange; + x->x_state=getbytes(sizeof(char)*x->x_range); + + urn_clear(x); +} + +static void urn_bang(t_urn *x) +{ + int range = (x->x_range<1?:1:x->x_range); + unsigned int randval = x->x_state; + + int nval, used=1; + + if (x->x_count>=range)urn_clear(x); + + while (used) { + randval = randval * 472940017 + 832416023; + nval = ((double)range) * ((double)randval) + * (1./4294967296.); + if (nval >= range) nval = range-1; + used=x->x_state[nval]; + } + + x->x_count++; + x->x_state[nval]=1; + outlet_float(x->x_obj.ob_outlet, nval); +} + +static void urn_flt2(t_urn *x, t_float f) +{ + unsigned int range = (f<1)?1:f; + makestate(x, range); +} + + +static void urn_seed(t_urn *x, t_float f) +{ + x->x_seed = f; +} + +static void *urn_new(t_floatarg f) +{ + t_urn *x = (t_urn *)pd_new(urn_class); + + if (f<1.0)f=1.0; + x->x_range = f; + x->x_seed = makeseed(); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("")); + outlet_new(&x->x_obj, &s_float); + return (x); + + return (x); +} + +static void urn_setup(void) +{ + urn_class = class_new(gensym("urn"), (t_newmethod)urn_new, + 0, sizeof(t_urn), 0, A_DEFFLOAT, 0); + + class_addbang (urn_class, urn_bang); + class_addmethod(urn_class, (t_method)urn_clear, gensym("clear"), 0); + class_addmehtod(urn_class, (t_method)urn_flt2, gensym(""), A_DEFFLOAT, 0); + class_addmethod(urn_class, (t_method)urn_seed, gensym("seed"), A_DEFFLOAT, 0); + + + class_sethelpsymbol(urn_class, gensym("zexy/urn")); +} + +void z_random_setup(void) +{ + urn_setup(); +} diff --git a/src/z_zdelay.c b/src/z_zdelay.c new file mode 100644 index 0000000..1c4f1ed --- /dev/null +++ b/src/z_zdelay.c @@ -0,0 +1,120 @@ +/* + here we do some sample-wise delay, so you can do your own FIR-filter-designs + here are :: "z^(-1)", "z^(-N)" + to do :: a "lattice~" section ... + + 1302:forum::für::umläute:2000 +*/ + +#include "zexy.h" + +#ifdef NT +#pragma warning( disable : 4244 ) +#pragma warning( disable : 4305 ) +#endif + +/* ----------------------------------------------------- */ + +static t_class *zNdelay_class; + +typedef struct _zNdelay +{ + t_object x_obj; + + t_float *buf; + int bufsize, phase; + +} t_zNdelay; + +static void zdel_float(t_zNdelay *x, t_floatarg f) +{ + int i = f+1; + if (i<1)i=1; + if (i==x->bufsize)return; + freebytes(x->buf, x->bufsize*sizeof(t_float)); + x->bufsize=i; + x->buf=(t_float *)getbytes(x->bufsize*sizeof(t_float)); + x->phase=0; +} + +static t_int *zN_perform(t_int *w) +{ + t_float *in = (t_float *)(w[1]); + t_float *out = (t_float *)(w[2]); + t_zNdelay *x = (t_zNdelay *)(w[3]); + int n = (int)(w[4]); + + t_float *buf = x->buf; + int bufsize=x->bufsize, ph=x->phase; + + if (bufsize==1) { + if (in!=out)while(n--)*out++=*in++; + } else if (bufsize==2) { + register t_float f, last=*buf; + while(n--){ + f=*in++; + *out++=last; + last=f; + } + *buf=last; + } else { + while (n--) { + *(buf+ph++) = *in++; + *out++ = buf[ph%=bufsize]; + } + x->phase=ph; + } + return (w+5); +} + + +static void zNdelay_dsp(t_zNdelay *x, t_signal **sp) +{ + dsp_add(zN_perform, 4, sp[0]->s_vec, sp[1]->s_vec, x, sp[0]->s_n); +} + +static void *zNdelay_new(t_floatarg f) +{ + t_zNdelay *x = (t_zNdelay *)pd_new(zNdelay_class); + int i = f; + t_float *b; + + if (i<=0) i=1; + i++; + + x->bufsize = i; + x->buf = (t_float *)getbytes(sizeof(t_float) * x->bufsize); + b=x->buf; + while (i--) { + *b++=0; + } + x->phase = 0; + + outlet_new(&x->x_obj, gensym("signal")); + return (x); +} + +static void zNdelay_free(t_zNdelay *x) +{ + freebytes(x->buf, sizeof(t_float) * x->bufsize); +} + + +static void zdel_helper(void) +{ + post("\n%c z~\t:: samplewise delay", HEARTSYMBOL); + post("creation :: 'z~ [<n>]' : creates a <n>-sample delay; default is 1"); +} + + +void z_zdelay_setup(void) +{ + zNdelay_class = class_new(gensym("z~"), (t_newmethod)zNdelay_new, (t_method)zNdelay_free, + sizeof(t_zNdelay), 0, A_DEFFLOAT, 0); + class_addmethod(zNdelay_class, nullfn, gensym("signal"), 0); + class_addmethod(zNdelay_class, (t_method)zNdelay_dsp, gensym("dsp"), 0); + + class_addfloat(zNdelay_class, zdel_float); + class_addmethod(zNdelay_class, (t_method)zdel_helper, gensym("help"), 0); + class_sethelpsymbol(zNdelay_class, gensym("zexy/z~")); +} diff --git a/src/zexy.c b/src/zexy.c new file mode 100644 index 0000000..dd818f6 --- /dev/null +++ b/src/zexy.c @@ -0,0 +1,286 @@ +/* ...this is a very ZEXY external ... + so have fun + + 1999:forum::für::umläute:2001 +*/ + +#include "zexy.h" + +/* do a little help thing */ + +typedef struct zexy +{ + t_object t_ob; +} t_zexy; + +t_class *zexy_class; + +static void zexy_help(void) +{ + post("\n\n...this is the zexy %c external "VERSION"...\n", HEARTSYMBOL); + post("\n%c handling signals" +#if 0 + "\nstreamout~\t:: stream signals via a LAN : (%c) gige 1999" + "\nstreamin~\t:: catch signals from a LAN : based on gige" +#endif + "\nsfplay\t\t:: play back a (multichannel) soundfile : (%c) ritsch 1999" + "\nsfrecord\t:: record a (multichannel) soundfile : based on ritsch" + "\n%c generating signals" + "\nnoish~\t\t:: generate bandlimited noise" + "\nnoisi~\t\t:: generate bandlimited noise" + "\ndirac~\t\t:: generate a dirac-pulse" + "\nstep~\t\t:: generate a unity-step" + "\ndfreq~\t\t:: detect frequency by counting zero-crossings : (%c) ritsch 1998" + "\n%c manipulating signals" + "\nlimiter~\t:: limit/compress one or more signals" + "\nnop~\t\t:: pass through a signal (delay 1 block)" + "\nz~\t\t:: samplewise delay" + "\nswap~\t\t:: byte-swap a signal" + "\nquantize~\t:: quantize a signal" + + "\n%c binary operations on signals" + "\nabs~, sgn~, >~, <~, ==~, &&~, ||~" + + "\n%c multary operations on signals" + + "\nmatrix~\t\t:: handle matrices" + "\nmultiline~\t:: multiple line~ multiplication" + "\nmultiplex~\t:: multiplex 1 inlet~ to 1-of-various outlet~s" + "\ndemultiplex~\t:: demultiplex 1-of-various inlet~s to 1 outlet~" + + "\n%c investigating signals in message-domain" + "\npack~\t\t:: convert a signal into a list of floats" + "\nunpack~\t\t:: convert packages of floats into a signal" + + "\nsigzero~\t:: indicates whether a signal is zero throughout the block" + "\navg~\t\t:: outputs average of a signal as float" + "\ntavg~\t\t:: outputs average of a signal between two bangs" + "\nenvrms~\t\t:: an env~-object that ouputs rms instead of db" + "\npdf~\t\t:: power density function" + + "\n%c basic message objects" + "\nnop\t\t:: a no-operation" + "\nlister\t\t:: stores lists" + "\nany2list\t\t:: converts \"anything\" to lists" + "\nlist2int\t:: cast each float of a list to integer" + "\natoi\t\t:: convert ascii to integer" + "\nlist2symbol\t:: convert a list into a single symbol" + "\nstrcmp\t\t:: compare 2 lists as if they where strings" + "\nrepack\t\t:: (re)packs atoms to packages of a given size" + "\npackel\t\t:: element of a package" + "\nlength\t\t:: length of a package" + "\nniagara\t\t:: divide a package into 2 sub-packages" + "\nglue\t\t:: append a list to another" + "\nsegregate\t:: sort inputs by type" + "\nmatrix\t\t:: handle matrices" + "\n.\t\t:: scalar multiplication of vectors (lists of floats)" + "\nmean\t\t:: get the arithmetic mean of a vector" + "\nminmax\t\t:: get the minimum and the maximum of a vector" + + "\n%c advanced message objects" + + "\ntabread4\t:: 4-point interpolating table-read object" + "\ntabdump\t\t:: dump the table as a list" + "\ntabset\t\t:: set a table with a list" + "\nmavg\t\t:: a variable moving average filter" + "\nmakesymbol\t:: creates (formatted) symbols" + "\ndate\t\t:: get the current system date" + "\ntime\t\t:: get the current system time" + "\nindex\t\t:: convert symbols to indices" + "\ndrip\t\t:: converts a package to a sequence of atoms" + "\nsort\t\t:: shell-sort a package of floats" + "\ndemux\t\t:: demultiplex the input to a specified output" + "\nmsgfile\t\t:: store and handles lists of lists" +#ifdef linux + "\nlp\t\t:: write to the (parallel) port" +#endif +#if 0 + "\nexecute\t\t:: execute an application" +#endif + + "\n%c matrix message objects" + + "\nmatrix\t\t:: create/store/edit matrices" + + "\nmtx_element\t:: change elements of a matrix" + "\nmtx_row\t\t:: change rows of a matrix" + "\nmtx_col\t\t:: change columns of a matrix" + "\nmtx_eye\t\t:: create an identity matrix" + "\nmtx_egg\t\t:: create an identity matrix that is rotated by 90deg" + "\nmtx_zeros\t:: create a matrix whose elements are all 1" + "\nmtx_ones\t:: create a matrix whose elements are all 0" + "\nmtx_diag\t:: returns the diagonal of a matrix or create a diagonal matrix" + "\nmtx_dieggt:: like mtx_diag but rotated by 90deg" + "\nmtx_trace\t:: calculate the trace of a matrix" + "\nmtx_size\t:: returns the size of a matrix" + "\nmtx_resize\t:: resize a matrix (evt. with zero-padding)" + "\nmtx_transpose\t:: transpose a matrix" + "\nmtx_scroll\t:: shift the rows of a matrix" + "\nmtx_roll\t:: shift the columns of a matrix" + "\nmtx_pivot\t:: pivot-transform a matrix" + "\nmtx_add\t\t:: add matrices" + "\nmtx_mul\t\t:: multiply matrices" + "\nmtx_.*\t\t:: multiply matrices element by element" + "\nmtx_./\t\t:: divide matrices element by element" + "\nmtx_inverse\t:: calculate the inverse of a matrix" + "\nmtx_mean\t:: return the mean value of each column" + "\nmtx_rand\t:: fill a matrix with random values" + "\nmtx_check\t:: check the consistency of a matrix and correct if necessary" + "\nmtx_print\t:: print formatted matrix to the stdout (for debug)" + + "\n\n(l) forum::für::umläute except where indicated (%c)\n" + "this software is under the GnuGPL that is provided with these files", HEARTSYMBOL, HEARTSYMBOL, HEARTSYMBOL, HEARTSYMBOL, HEARTSYMBOL, HEARTSYMBOL, HEARTSYMBOL, HEARTSYMBOL, HEARTSYMBOL, HEARTSYMBOL, HEARTSYMBOL, HEARTSYMBOL); +} + +void *zexy_new(void) +{ + t_zexy *x = (t_zexy *)pd_new(zexy_class); + return (void *)x; +} + +/* include some externals */ +#if 0 +void z_streamin_setup(); /* urps, i THINK this will be linux only */ +void z_streamout_setup(); +void z_stdinout_setup(); // not yet... +#endif // 0 +void z_sfplay_setup(); +void z_sfrecord_setup(); +void z_noise_setup(); +void z_testfun_setup(); +void z_nop_setup(); +void z_zdelay_setup(); +void z_limiter_setup(); +void z_swap_setup(); +void z_quantize_setup(); +void z_sigzero_setup(); +void z_tabread4_setup(); +void z_makefilenamen_setup(); +void z_makesymbol_setup(); + +void z_pdf_setup(); +void z_dfreq_setup(); +void z_sigaverage_setup(); +void z_sigpack_setup(); + +void z_datetime_setup(); + +void z_sigbin_setup(); + +#if 0 // used to be Win32 only, but i somehow lost the fine code +void z_execute_setup(); +#endif + +void z_lp_setup(); + +void z_index_setup(); +void z_connective_setup(); +void z_sort_setup(); +void z_multiplex_setup(); +void z_average_setup(); +void z_coordinates_setup(); +void z_stat_setup(); + +void z_pack_setup(); +void z_drip_setup(); + +void z_stdinout_setup(); +void z_msgfile_setup(); +void z_multiline_setup(); +void z_matrix_setup(); +void z_sigmatrix_setup(); + +void z_strings_setup(); + +void z_down_setup(); + +void z_prime_setup(); +void z_random_setup(); +/* + waiting to be released in near future: + make stdin~ and stdout~ work + MAKE streamin~ work !!! + sql + ... +*/ + + + +void zexy_setup(void) +{ + int i; +#if 0 +#ifdef linux + z_streamin_setup(); +#endif + z_streamout_setup(); + z_stdinout_setup(); +#endif + z_sfplay_setup(); + z_sfrecord_setup(); + z_noise_setup(); + z_testfun_setup(); + z_limiter_setup(); + z_nop_setup(); + z_zdelay_setup(); + z_swap_setup(); + z_quantize_setup(); + + z_sigzero_setup(); + z_pdf_setup(); + z_dfreq_setup(); + z_sigaverage_setup(); + z_sigbin_setup(); + + z_sigpack_setup(); + + z_tabread4_setup(); + z_average_setup(); + z_coordinates_setup(); + z_stat_setup(); + z_makesymbol_setup(); + + z_datetime_setup(); + + z_index_setup(); + z_connective_setup(); + z_sort_setup(); + z_multiplex_setup(); + z_pack_setup(); + z_drip_setup(); + + z_prime_setup(); + z_random_setup(); +#if 0 + z_stdinout_setup(); + + // we'll do this the next days + z_execute_setup(); +#endif + z_msgfile_setup(); + + z_multiline_setup(); + z_matrix_setup(); + z_sigmatrix_setup(); + + z_strings_setup(); +#ifdef linux + z_lp_setup(); +#endif + z_down_setup(); + + /* ************************************** */ + + startpost("\n\t"); + for (i=0; i<28; i++) startpost("%c", HEARTSYMBOL); + endpost(); + post("\t%c...the zexy external"VERSION"...%c", HEARTSYMBOL, HEARTSYMBOL); + post("\t%c forum::für::umläute 2000 %c", HEARTSYMBOL, HEARTSYMBOL); + post("\t%c send me a 'help' message %c", HEARTSYMBOL, HEARTSYMBOL); + startpost("\t"); + for (i=0; i<28; i++) startpost("%c", HEARTSYMBOL); + endpost(); endpost(); + + zexy_class = class_new(gensym("zexy"), zexy_new, 0, sizeof(t_zexy), 0, 0); + class_addmethod(zexy_class, zexy_help, gensym("help"), 0); +} diff --git a/src/zexy.dsp b/src/zexy.dsp new file mode 100644 index 0000000..a8970a1 --- /dev/null +++ b/src/zexy.dsp @@ -0,0 +1,195 @@ +# Microsoft Developer Studio Project File - Name="zexy" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** NICHT BEARBEITEN ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=ZEXY - WIN32 RELEASE +!MESSAGE Dies ist kein gültiges Makefile. Zum Erstellen dieses Projekts mit NMAKE +!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und führen Sie den Befehl +!MESSAGE +!MESSAGE NMAKE /f "zexy.mak". +!MESSAGE +!MESSAGE Sie können beim Ausführen von NMAKE eine Konfiguration angeben +!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel: +!MESSAGE +!MESSAGE NMAKE /f "zexy.mak" CFG="ZEXY - WIN32 RELEASE" +!MESSAGE +!MESSAGE Für die Konfiguration stehen zur Auswahl: +!MESSAGE +!MESSAGE "zexy - Win32 Release" (basierend auf "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 1 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "" +# PROP Intermediate_Dir "obj\" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ZEXY_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /I "..\..\src" /D "WIN32" /D "NT" /D "_WINDOWS" /D "ZEXY" /FR /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /win32 +# SUBTRACT MTL /mktyplib203 +# ADD BASE RSC /l 0xc07 /d "NDEBUG" +# ADD RSC /l 0xc07 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib wsock32.lib uuid.lib libc.lib oldnames.lib pd.lib /nologo /dll /machine:I386 /nodefaultlib /out:"..\zexy.dll" /libpath:"../../bin" /export:zexy_setup +# SUBTRACT LINK32 /pdb:none +# Begin Target + +# Name "zexy - Win32 Release" +# Begin Group "Quellcodedateien" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\z_average.c +# End Source File +# Begin Source File + +SOURCE=.\z_connective.c +# End Source File +# Begin Source File + +SOURCE=.\z_datetime.c +# End Source File +# Begin Source File + +SOURCE=.\z_dfreq.c +# End Source File +# Begin Source File + +SOURCE=.\z_drip.c +# End Source File +# Begin Source File + +SOURCE=.\z_index.c +# End Source File +# Begin Source File + +SOURCE=.\z_limiter.c +# End Source File +# Begin Source File + +SOURCE=.\z_makesymbol.c +# End Source File +# Begin Source File + +SOURCE=.\z_matrix.c +# End Source File +# Begin Source File + +SOURCE=.\z_msgfile.c +# End Source File +# Begin Source File + +SOURCE=.\z_multiline.c +# End Source File +# Begin Source File + +SOURCE=.\z_multiplex.c +# End Source File +# Begin Source File + +SOURCE=.\z_noise.c +# End Source File +# Begin Source File + +SOURCE=.\z_nop.c +# End Source File +# Begin Source File + +SOURCE=.\z_pack.c +# End Source File +# Begin Source File + +SOURCE=.\z_pdf.c +# End Source File +# Begin Source File + +SOURCE=.\z_quantize.c +# End Source File +# Begin Source File + +SOURCE=.\z_sfplay.c +# End Source File +# Begin Source File + +SOURCE=.\z_sfrecord.c +# End Source File +# Begin Source File + +SOURCE=.\z_sigaverage.c +# End Source File +# Begin Source File + +SOURCE=.\z_sigbin.c +# End Source File +# Begin Source File + +SOURCE=.\z_sigmatrix.c +# End Source File +# Begin Source File + +SOURCE=.\z_sigpack.c +# End Source File +# Begin Source File + +SOURCE=.\z_sigzero.c +# End Source File +# Begin Source File + +SOURCE=.\z_sort.c +# End Source File +# Begin Source File + +SOURCE=.\z_swap.c +# End Source File +# Begin Source File + +SOURCE=.\z_tabread4.c +# End Source File +# Begin Source File + +SOURCE=.\z_testfun.c +# End Source File +# Begin Source File + +SOURCE=.\z_zdelay.c +# End Source File +# Begin Source File + +SOURCE=.\zexy.c +# End Source File +# End Group +# Begin Group "Header-Dateien" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\src\m_pd.h +# End Source File +# Begin Source File + +SOURCE=.\Zexy.h +# End Source File +# End Group +# End Target +# End Project diff --git a/src/zexy.dsw b/src/zexy.dsw new file mode 100644 index 0000000..bb788fc --- /dev/null +++ b/src/zexy.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNUNG: DIESE ARBEITSBEREICHSDATEI DARF NICHT BEARBEITET ODER GELÖSCHT WERDEN! + +############################################################################### + +Project: "zexy"=.\zexy.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/src/zexy.h b/src/zexy.h new file mode 100644 index 0000000..95d760d --- /dev/null +++ b/src/zexy.h @@ -0,0 +1,45 @@ +/* ********************************************** */ +/* the ZEXY external */ +/* ********************************************** */ +/* forum::für::umläute */ +/* ********************************************** */ + +/* the ZEXY external is a runtime-library for miller s. puckette's realtime-computermusic-software "pure data" + * therefore you NEED "pure data" to make any use of the ZEXY external + * (except if you want to use the code for other things) + * download "pure data" at + + http://iem.kug.ac.at/pd + ftp://iem.kug.ac.at/pd + + * + * if you are looking for the latest release of the ZEXY-external you should have another look at + + ftp://iem.kug.ac.at/pd/Externals/ZEXY + + * + * ZEXY is published under the GNU GeneralPublicLicense, that must be shipped with ZEXY. + * if you are using Debian GNU/linux, the GNU-GPL can be found under /usr/share/common-licenses/GPL + * if you still haven't found a copy of the GNU-GPL, have a look at http://www.gnu.org + * + * "pure data" has it's own license, that comes shipped with "pure data". + * + * there are ABSOLUTELY NO WARRANTIES for anything + */ + +#ifndef INCLUDE_ZEXY_H__ +#define INCLUDE_ZEXY_H__ + +#include "m_pd.h" + +#define VERSION "1P2" + +#ifdef NT +/* yes, we have beautiful hearts under NT */ +#define HEARTSYMBOL 3 +#else +/* but none for linux; indeed the only drawback */ +#define HEARTSYMBOL 64 +#endif + +#endif |