aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/makefile.irix29
-rw-r--r--src/makefile.linux90
-rwxr-xr-xsrc/strip_objects8
-rw-r--r--src/z_average.c113
-rw-r--r--src/z_connective.c585
-rw-r--r--src/z_coordinates.c433
-rw-r--r--src/z_count.c35
-rw-r--r--src/z_datetime.c161
-rw-r--r--src/z_dfreq.c101
-rw-r--r--src/z_down.c121
-rw-r--r--src/z_drip.c185
-rw-r--r--src/z_index.c203
-rw-r--r--src/z_limiter.c707
-rw-r--r--src/z_lp.c132
-rw-r--r--src/z_makesymbol.c126
-rw-r--r--src/z_matrix.c2705
-rw-r--r--src/z_msgfile.c791
-rw-r--r--src/z_mtx.c669
-rw-r--r--src/z_multiline.c252
-rw-r--r--src/z_multiplex.c171
-rw-r--r--src/z_noise.c312
-rw-r--r--src/z_nop.c78
-rw-r--r--src/z_pack.c344
-rw-r--r--src/z_pdf.c128
-rw-r--r--src/z_point.c110
-rw-r--r--src/z_prime.c50
-rw-r--r--src/z_quantize.c99
-rw-r--r--src/z_random.c143
-rw-r--r--src/z_sfplay.c660
-rw-r--r--src/z_sfrecord.c592
-rw-r--r--src/z_sigaverage.c287
-rw-r--r--src/z_sigbin.c801
-rw-r--r--src/z_sigmatrix.c538
-rw-r--r--src/z_sigpack.c198
-rw-r--r--src/z_sigzero.c100
-rw-r--r--src/z_skeleton.c57
-rw-r--r--src/z_skeleton_tilde.c61
-rw-r--r--src/z_sort.c114
-rw-r--r--src/z_stat.c164
-rw-r--r--src/z_strings.c251
-rw-r--r--src/z_swap.c89
-rw-r--r--src/z_tabread4.c249
-rw-r--r--src/z_testfun.c222
-rw-r--r--src/z_urn.c120
-rw-r--r--src/z_zdelay.c120
-rw-r--r--src/zexy.c286
-rw-r--r--src/zexy.dsp195
-rw-r--r--src/zexy.dsw29
-rw-r--r--src/zexy.h45
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