aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuenter Geiger <ggeiger@users.sourceforge.net>2002-10-09 10:19:04 +0000
committerGuenter Geiger <ggeiger@users.sourceforge.net>2002-10-09 10:19:04 +0000
commitd2eec74a4d8c21aad495ba61539486b24d7ab8dc (patch)
tree8340a62efe3eb1d42dc40265723c2704d3bd6452
moved from zexy/zexy to zexysvn2git-root
svn path=/trunk/externals/zexy/; revision=169
-rw-r--r--README.txt40
-rw-r--r--examples/0.INTRO.txt105
-rw-r--r--examples/a2l.pd21
-rw-r--r--examples/any2list.pd23
-rw-r--r--examples/atoi.pd39
-rw-r--r--examples/avg~.pd22
-rw-r--r--examples/date.pd26
-rw-r--r--examples/demultiplex.pd35
-rw-r--r--examples/demultiplex~.pd33
-rw-r--r--examples/dfreq~.pd15
-rw-r--r--examples/digidistort.pd69
-rw-r--r--examples/dirac~.pd43
-rw-r--r--examples/drip.pd70
-rw-r--r--examples/envrms~.pd24
-rw-r--r--examples/glue.pd21
-rw-r--r--examples/index.pd87
-rw-r--r--examples/length.pd16
-rw-r--r--examples/limiter~.pd226
-rw-r--r--examples/list2int.pd17
-rw-r--r--examples/list2symbol.pd16
-rw-r--r--examples/lister.pd23
-rw-r--r--examples/lp.pd20
-rw-r--r--examples/makesymbol.pd58
-rw-r--r--examples/matrix.pd133
-rw-r--r--examples/matrix~.pd58
-rw-r--r--examples/mavg.pd16
-rw-r--r--examples/mean.pd9
-rw-r--r--examples/minmax.pd12
-rw-r--r--examples/msgfile.pd109
-rw-r--r--examples/mtx_binops.pd112
-rw-r--r--examples/mtx_element.pd64
-rw-r--r--examples/mtx_inverse.pd18
-rw-r--r--examples/mtx_mean.pd13
-rw-r--r--examples/mtx_rand.pd20
-rw-r--r--examples/mtx_size.pd44
-rw-r--r--examples/mtx_special.pd60
-rw-r--r--examples/mtx_trace.pd23
-rw-r--r--examples/mtx_transpose.pd59
-rw-r--r--examples/multiline~.pd63
-rw-r--r--examples/multiplex~.pd23
-rw-r--r--examples/niagara.pd21
-rw-r--r--examples/noish~.pd21
-rw-r--r--examples/noisi~.pd21
-rw-r--r--examples/nop.pd17
-rw-r--r--examples/nop~.pd17
-rw-r--r--examples/packel.pd20
-rw-r--r--examples/pack~.pd33
-rw-r--r--examples/pdf~.pd25
-rw-r--r--examples/quantize~.pd37
-rw-r--r--examples/repack.pd23
-rw-r--r--examples/scalarmult.pd73
-rw-r--r--examples/segregate.pd33
-rw-r--r--examples/sf-play_record.pd57
-rw-r--r--examples/sigbinops+.pd106
-rw-r--r--examples/sigzero~.pd50
-rw-r--r--examples/sort.pd77
-rw-r--r--examples/step~.pd74
-rw-r--r--examples/strcmp.pd26
-rw-r--r--examples/swap~.pd39
-rw-r--r--examples/tabdump.pd19
-rw-r--r--examples/tabread4.pd29
-rw-r--r--examples/tabset.pd19
-rw-r--r--examples/tavg~.pd28
-rw-r--r--examples/time.pd31
-rw-r--r--examples/unpack~.pd59
-rw-r--r--examples/z~.pd28
-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
-rw-r--r--z_install.bat9
-rw-r--r--zexy.pd303
117 files changed, 17239 insertions, 0 deletions
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..4f073c1
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,40 @@
+the zexy external
+
+
+general::
+the zexy external is a collection of externals for miller.s.puckette's realtime-computermusic-environment called "puredata" (or abbreviated "pd")
+this zexy external will be of no use, if you don't have a running version of pd on your system.
+check out for http://pd.iem.at to learn more about pd and how to get it
+
+note: the zexy external is published under the Gnu General Public License that is included (GnuGPL.txt). some parts of the code are taken directly from the pd source-code, they, of course, fall under the license pd is published under.
+
+
+installation::
+linux :
+change to directory source
+adapt the makefile to match your system (where is pd installed ?)
+"make clean"
+"make"
+"make install"
+this will install the zexy external into /usr/local/lib/pd/externs
+alternatively you can try "make everything"
+
+win32 :
+extract the zexy-0_x.zip to your pd-path (this file should be located at <mypdpath>/pd/zexy/)
+execute the "z_install.bat", this should copy all necessary files to the correct places
+if you want to compile it for yourself, i don't take any warranties for the makefile.nt; use the workspace zexy.dsw instead
+
+irix :
+though i have physical access to both SGI's O2s and indys, i haven't tried to compile the zexy externals there for years.
+Good luck !
+
+
+making pd run with the zexy external::
+make sure, that pd will be looking at this location (add "-path <mypath>/pd/externs" either to your .pdrc or each time you execute pd)
+make sure, that you somehow load the zexy external (either add "-lib zexy" (if you advised pd somehow to look at the correct place) or "-lib <myzexypath>/zexy" to your startup-script (.pdrc or whatever) or load it via the object "zexy" at runtime
+
+
+authors::
+this software is copyleft by iohannes m zmoelnig <zmoelnig@iem.kug.ac.at>
+with some contributions by winfried ritsch, guenter geiger, miller.s.puckette and maybe some others
+
diff --git a/examples/0.INTRO.txt b/examples/0.INTRO.txt
new file mode 100644
index 0000000..ffd209a
--- /dev/null
+++ b/examples/0.INTRO.txt
@@ -0,0 +1,105 @@
+These are the objects that come with the zexy-external
+
+============================ DSP~ ===============================
+
+---------------------------- IO~ --------------------------------
+sfplay play back (multi-channel) soundfiles
+sfrecord record (multichannel) soundfiles
+
+------------------------ generators~ ----------------------------
+dirac~ dirac-pulse
+step~ unity step
+noish~ downsampled noise (hold)
+noisi~ downsampled noise (interpolate)
+
+------------------------ processing~ ----------------------------
+limiter~ a limiter/compressor module
+quantize~ quantizes signals
+swap~ bytes swap a 16bit-signal
+z~ samplewise delay
+
+------------------------- analytic~ -----------------------------
+sigzero~ detects whether a signal is zero throughout the vector or not
+pdf~ probability density function
+envrms~ like env~, but outputting rms instead of dB
+avg~ arithmetic mean of 1 signal-vector
+tavg~ arithmetic mean between two bangs
+dfreq~ frequency detector
+
+------------------------- sigbinops~ ----------------------------
+>~, <~, ==~, &&~, ||~ logical operators
+abs~ absolute value of a signal
+sgn~ signum of a signal
+
+--------------------------- misc~ -------------------------------
+nop~ no-operation
+pack~ convert a signal to a list of floats
+unpack~ convert a list of floats to a signal
+matrix~ matrix-multiply m IN-signals to n OUT-signals
+multiplex~ multiplex 1-of-n inlets to 1 outlet
+demultiplex~ demultiplex 1 inlet to 1-of-n outlets
+
+
+========================= control ==============================
+
+-------------------------- basic -------------------------------
+nop no-operation
+lister store lists (like "float" for floats)
+repack (re)pack atoms to packages of a given size
+packel get a specified element of a list
+length get the length of a list
+niagara split 1 packages into 2
+glue append a package to another (glue them together)
+segregate segregate the input to various outlets, depending on the type
+any2list convert "anythings" to "lists"
+list2int cast each float of a list to integer
+atoi ascii to integer
+strcmp compare lists as strings
+list2symbol convert a list into a single symbol
+. scalar multiplication of vectors (=lists of floats)
+
+------------------------ advanced ------------------------------
+tabread4 interpolating tabread (obsolete since pd>=0.30)
+tabdump dump out a table as a list of floats
+tabset set a table with a list of floats
+makesymbol concatenate lists to formatted symbols
+date get system date
+time get system time
+index map symbols to indices
+msgfile a powerful "textfile" derivative
+mavg moving average filter for floats
+mean get the mean value of a list of floats
+minmax get minimum and maximum of a list of floats
+sort shell-sort a list of floats
+demultiplex demultiplex the input to a specified outlet
+drip extract the atoms of a package (opt. scheduled)
+lp write to the (parallel) port (linux only)
+
+-------------------------- matrix -------------------------------
+matrix create/store/... matrices
+mtx_element set elements of a matrix
+mtx_row set rows of a matrix
+mtx_col set columns of a matrix
+mtx_ones matrix with all elements==1
+mtx_zeros matrix with all elements==0
+mtx_eye identity matrix
+mtx_egg identity matrix (from upper-right to lower-left)
+mtx_diag diagonal matrix
+mtx_diegg diagonal matrix (from upper-right to lower-left)
+mtx_diag get the diagonal of a matrix
+mtx_trace get the trace of a matrix
+mtx_transpose transpose a matrix
+mtx_roll column-shift a matrix
+mtx_scroll row-shift a matrix
+mtx_pivot pivot-transform a matrix
+mtx_resize resize a matrix (evtl. with zero-padding)
+mtx_size get the size of a matrix
+mtx_inverse get the inverse of a matrix
+mtx_add, mtx_+ add 2 matrices (or an offset to 1 matrix)
+mtx_mul, mtx_* multiply 2 matrices (or a factor with 1 matrix)
+mtx_.* multiply 2 matrices element by element
+mtx_./ divide 2 matrices element by element
+mtx_mean get the mean value of each column
+mtx_rand matrix with random elements
+mtx_check check the consistency of a matrix and repair
+mtx_print print a matrix to the stderr \ No newline at end of file
diff --git a/examples/a2l.pd b/examples/a2l.pd
new file mode 100644
index 0000000..54416e8
--- /dev/null
+++ b/examples/a2l.pd
@@ -0,0 +1,21 @@
+#N canvas 165 209 450 458 10;
+#X obj 76 28 a2l;
+#X text 113 30 convert "anything" to lists;
+#X obj 35 256 a2l;
+#X text 116 56 pass through the rest;
+#X floatatom 46 229;
+#X symbolatom 46 203;
+#X msg 46 162 this is anything;
+#X msg 46 182 list this is a list;
+#X obj 35 276 print a2l;
+#X text 69 335 to make "anything"s out of lists \, try;
+#X obj 319 339 route list;
+#X msg 319 320 list this is a list;
+#X obj 319 358 print l2a;
+#X connect 2 0 8 0;
+#X connect 4 0 2 0;
+#X connect 5 0 2 0;
+#X connect 6 0 2 0;
+#X connect 7 0 2 0;
+#X connect 10 0 12 0;
+#X connect 11 0 10 0;
diff --git a/examples/any2list.pd b/examples/any2list.pd
new file mode 100644
index 0000000..9c460c0
--- /dev/null
+++ b/examples/any2list.pd
@@ -0,0 +1,23 @@
+#N canvas 319 129 450 458 10;
+#X text 113 30 convert "anything" to lists;
+#X text 116 56 pass through the rest;
+#X floatatom 46 229 0 0 0;
+#X symbolatom 46 203 0 0 0;
+#X msg 46 162 this is anything;
+#X msg 46 182 list this is a list;
+#X obj 35 276 print a2l;
+#X text 48 337 to make "anything"s out of lists \, try;
+#X obj 319 339 route list;
+#X msg 319 318 list this is a list;
+#X obj 319 359 print l2a;
+#X obj 56 30 any2list;
+#X text 245 223 alias;
+#X obj 280 223 a2l;
+#X obj 35 256 any2list;
+#X connect 2 0 14 0;
+#X connect 3 0 14 0;
+#X connect 4 0 14 0;
+#X connect 5 0 14 0;
+#X connect 8 0 10 0;
+#X connect 9 0 8 0;
+#X connect 14 0 6 0;
diff --git a/examples/atoi.pd b/examples/atoi.pd
new file mode 100644
index 0000000..c6a507a
--- /dev/null
+++ b/examples/atoi.pd
@@ -0,0 +1,39 @@
+#N canvas 271 320 749 300 10;
+#X obj 125 21 atoi;
+#X text 174 19 convert ascii to integer;
+#X obj 72 178 atoi;
+#X floatatom 72 201 4 0 0;
+#X obj 72 132 makefilename %4d;
+#X symbolatom 72 155 10 0 0;
+#X floatatom 72 110 4 0 0;
+#X floatatom 177 110 4 0 0;
+#X obj 177 132 makefilename 0%d;
+#X floatatom 280 110 4 0 0;
+#X obj 280 132 makefilename 0x%d;
+#X text 74 92 decimal;
+#X text 178 94 octal;
+#X text 280 93 sedecimal;
+#X floatatom 417 109 4 0 0;
+#X obj 417 127 makefilename %d;
+#X floatatom 502 106 4 0 0;
+#X text 506 93 base;
+#X obj 417 146 pack s 2;
+#X msg 417 86 101;
+#X msg 443 86 10011;
+#X text 241 214 symbols starting with "0x" are converted as hex-numbers;
+#X text 242 228 symbols starting with "0" are converted as octal numbers;
+#X text 241 243 symbols starting with numbers but "0" are converted as decimal numbers;
+#X connect 2 0 3 0;
+#X connect 4 0 5 0;
+#X connect 5 0 2 0;
+#X connect 6 0 4 0;
+#X connect 7 0 8 0;
+#X connect 8 0 5 0;
+#X connect 9 0 10 0;
+#X connect 10 0 5 0;
+#X connect 14 0 15 0;
+#X connect 15 0 18 0;
+#X connect 16 0 18 1;
+#X connect 18 0 2 0;
+#X connect 19 0 14 0;
+#X connect 20 0 14 0;
diff --git a/examples/avg~.pd b/examples/avg~.pd
new file mode 100644
index 0000000..9ae5626
--- /dev/null
+++ b/examples/avg~.pd
@@ -0,0 +1,22 @@
+#N canvas 288 18 580 361 10;
+#X floatatom 59 148;
+#X floatatom 59 254;
+#X floatatom 129 255;
+#X obj 59 276 dbtorms;
+#X floatatom 59 299;
+#X text 272 269 see also:;
+#X obj 277 296 env~;
+#X obj 373 296 tavg~;
+#X obj 71 51 avg~;
+#X obj 129 234 avg~;
+#X obj 59 233 env~;
+#X text 155 49 calculates the arithmetic mean of one signal vector;
+#X obj 315 296 envrms~;
+#X obj 59 173 osc~ 5512.5;
+#X connect 0 0 13 0;
+#X connect 1 0 3 0;
+#X connect 3 0 4 0;
+#X connect 9 0 2 0;
+#X connect 10 0 1 0;
+#X connect 13 0 9 0;
+#X connect 13 0 10 0;
diff --git a/examples/date.pd b/examples/date.pd
new file mode 100644
index 0000000..bfeeb0a
--- /dev/null
+++ b/examples/date.pd
@@ -0,0 +1,26 @@
+#N canvas 253 26 421 378 10;
+#X obj 71 203 date;
+#X msg 71 174 bang;
+#X floatatom 94 230;
+#X floatatom 82 254;
+#X floatatom 71 281;
+#X msg 285 173 bang;
+#X floatatom 336 227;
+#X floatatom 310 253;
+#X floatatom 285 280;
+#X obj 285 202 date GMT;
+#X obj 73 26 date;
+#X text 91 79 get the system date;
+#X text 180 229 day;
+#X text 175 253 month;
+#X text 179 279 year;
+#X text 70 151 local;
+#X text 284 151 GMT;
+#X connect 0 0 4 0;
+#X connect 0 1 3 0;
+#X connect 0 2 2 0;
+#X connect 1 0 0 0;
+#X connect 5 0 9 0;
+#X connect 9 0 8 0;
+#X connect 9 1 7 0;
+#X connect 9 2 6 0;
diff --git a/examples/demultiplex.pd b/examples/demultiplex.pd
new file mode 100644
index 0000000..1d69b08
--- /dev/null
+++ b/examples/demultiplex.pd
@@ -0,0 +1,35 @@
+#N canvas 350 196 655 292 10;
+#X obj 51 171 demux 1 2 3 4;
+#X obj 51 91 metro 320;
+#X obj 51 111 t b b;
+#X obj 51 130 random 100;
+#X msg 51 69 1;
+#X msg 76 69 0;
+#X floatatom 135 147;
+#X obj 51 239 print output0;
+#X obj 135 129 random 4;
+#X obj 75 222 print outpu1;
+#X obj 99 205 print outp2;
+#X obj 124 188 print out3;
+#X msg 51 150 bet \$1;
+#X text 231 10 demultiplex the inlet to the specified output;
+#X obj 111 12 demultiplex;
+#X obj 315 236 demux;
+#X text 271 237 alias;
+#X text 268 166 creation: "demultiplex [<in1?> [<in2?> [<in3?> ... ]]]";
+#X text 303 185 the number of arguments defines the number of outlets;
+#X text 277 81 the right inlet specifies \, to which outlet the left inlet is routed;
+#X text 280 119 outlets number from 0..(n-1);
+#X connect 0 0 7 0;
+#X connect 0 1 9 0;
+#X connect 0 2 10 0;
+#X connect 0 3 11 0;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 2 1 8 0;
+#X connect 3 0 12 0;
+#X connect 4 0 1 0;
+#X connect 5 0 1 0;
+#X connect 6 0 0 1;
+#X connect 8 0 6 0;
+#X connect 12 0 0 0;
diff --git a/examples/demultiplex~.pd b/examples/demultiplex~.pd
new file mode 100644
index 0000000..290fd72
--- /dev/null
+++ b/examples/demultiplex~.pd
@@ -0,0 +1,33 @@
+#N canvas 79 72 635 302 12;
+#X obj 72 139 sig~ 1;
+#X floatatom 110 93 4 0 0;
+#X obj 71 229 env~;
+#X floatatom 71 255 4 0 0;
+#X text 428 109 alias;
+#X obj 71 193 demultiplex~ . . . . .;
+#X obj 113 229 env~;
+#X floatatom 113 255 4 0 0;
+#X obj 156 230 env~;
+#X floatatom 156 256 4 0 0;
+#X obj 199 229 env~;
+#X floatatom 199 255 4 0 0;
+#X obj 242 227 env~;
+#X floatatom 242 253 4 0 0;
+#X text 156 94 select an outlet;
+#X obj 75 23 demultiplex~;
+#X text 210 22 demultiplex 1 signal to 1-of-n outlets;
+#X obj 480 110 demux~;
+#X text 154 174 the number of arguments specifies the number of outlets
+;
+#X connect 0 0 5 0;
+#X connect 1 0 5 0;
+#X connect 2 0 3 0;
+#X connect 5 0 2 0;
+#X connect 5 1 6 0;
+#X connect 5 2 8 0;
+#X connect 5 3 10 0;
+#X connect 5 4 12 0;
+#X connect 6 0 7 0;
+#X connect 8 0 9 0;
+#X connect 10 0 11 0;
+#X connect 12 0 13 0;
diff --git a/examples/dfreq~.pd b/examples/dfreq~.pd
new file mode 100644
index 0000000..a211c63
--- /dev/null
+++ b/examples/dfreq~.pd
@@ -0,0 +1,15 @@
+#N canvas 307 9 598 301 10;
+#X obj 61 163 dfreq~;
+#X obj 61 133 osc~ 440;
+#X obj 61 231 print~;
+#X msg 96 208 bang;
+#X obj 85 28 dfreq~;
+#X text 146 27 a frequency detector that counts zero-crossings;
+#X floatatom 61 109;
+#X text 182 104 every zero-crossing the frequency-estimation is updated \, therefore this estimation is given as a signal...;
+#X text 179 170 this detector won't work properly on complex signals (e.g. zero-crossings should not be caused by higher partials);
+#X text 177 205 on the other hand \, this is much cheaper than fft's or fiddle...;
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 3 0 2 0;
+#X connect 6 0 1 0;
diff --git a/examples/digidistort.pd b/examples/digidistort.pd
new file mode 100644
index 0000000..6764a3b
--- /dev/null
+++ b/examples/digidistort.pd
@@ -0,0 +1,69 @@
+#N canvas 0 -1 708 652 10;
+#X obj 99 529 swap~;
+#X text 172 515 byte-swap the signal;
+#X text 214 164 quantize a signal with a variable step-number;
+#X text 171 533 this object first converts the signal to 16bit \, then swaps upper and lower byte.;
+#X text 117 11 objects~ that are distorting in a very "digital" way;
+#X msg 128 113 8bit;
+#X msg 128 89 16bit;
+#X msg 128 66 float;
+#X floatatom 129 42;
+#X obj 77 273 dac~ 1;
+#X obj 77 248 *~;
+#X obj 39 199 dbtorms;
+#X floatatom 39 175;
+#X msg 122 441 0;
+#X msg 122 417 1;
+#X msg 121 466 bang;
+#X obj 35 136 osc~ 440;
+#X floatatom 35 112;
+#X obj 96 164 quantize~ 16;
+#X obj 35 496 osc~ 440;
+#X floatatom 35 472;
+#X msg 121 491 help;
+#X obj 83 609 *~;
+#X obj 45 560 dbtorms;
+#X floatatom 45 536;
+#X msg 127 137 help;
+#X obj 83 634 dac~ 2;
+#X msg 404 59 \; pd dsp 1;
+#X obj 78 223 sig~ 0.2;
+#X obj 83 584 sig~ 0.2;
+#X msg 482 61 \; pd dsp 0;
+#X graph graph5 0 -1 100 1 298 494 698 194;
+#X array scope 100 float;
+#X pop;
+#X obj 148 223 tabwrite~ scope;
+#X msg 148 198 bang;
+#X obj 178 634 tabwrite~ scope;
+#X msg 178 609 bang;
+#X text 161 466 toggle;
+#X text 154 416 on;
+#X text 156 440 off;
+#X connect 0 0 22 1;
+#X connect 0 0 34 0;
+#X connect 5 0 18 0;
+#X connect 6 0 18 0;
+#X connect 7 0 18 0;
+#X connect 8 0 18 0;
+#X connect 10 0 9 0;
+#X connect 11 0 28 0;
+#X connect 12 0 11 0;
+#X connect 13 0 0 0;
+#X connect 14 0 0 0;
+#X connect 15 0 0 0;
+#X connect 16 0 18 0;
+#X connect 17 0 16 0;
+#X connect 18 0 10 1;
+#X connect 18 0 32 0;
+#X connect 19 0 0 0;
+#X connect 20 0 19 0;
+#X connect 21 0 0 0;
+#X connect 22 0 26 0;
+#X connect 23 0 29 0;
+#X connect 24 0 23 0;
+#X connect 25 0 18 0;
+#X connect 28 0 10 0;
+#X connect 29 0 22 0;
+#X connect 33 0 32 0;
+#X connect 35 0 34 0;
diff --git a/examples/dirac~.pd b/examples/dirac~.pd
new file mode 100644
index 0000000..d1317dd
--- /dev/null
+++ b/examples/dirac~.pd
@@ -0,0 +1,43 @@
+#N canvas 202 49 564 290 8;
+#X obj 123 230 dirac~;
+#X floatatom 95 186;
+#X obj 95 208 t b f;
+#X obj 123 253 print~;
+#X text 40 30 dirac~ ::;
+#X text 40 60 IN :;
+#X text 115 30 produces a unit:sample:sequence;
+#X text 114 61 define the nth sample after the float::bang:message for the unit:sample to take place;
+#X text 98 165 position;
+#N canvas 0 0 765 385 application 0;
+#X obj 75 82 t b b b;
+#X msg 119 104 \; pd dsp 1;
+#X obj 97 139 dirac~;
+#X floatatom 181 141;
+#X obj 97 181 tabwrite~ unit::response;
+#X graph graph1 0 -1 64 1 358 325 758 25;
+#X array unit::response 64 float;
+#X pop;
+#X msg 70 283 \; unit::response resize 64;
+#X text 32 353 we thought it useful to have a tool that would be able to easily plot the unit::response of a system;
+#X text 111 61 press me;
+#X msg 75 61 bang;
+#X obj 97 160 hip~ 5000;
+#X connect 0 0 4 0;
+#X connect 0 1 2 0;
+#X connect 0 2 1 0;
+#X connect 2 0 10 0;
+#X connect 3 0 10 1;
+#X connect 9 0 0 0;
+#X connect 10 0 4 0;
+#X restore 270 148 page application;
+#X obj 53 208 t f b;
+#X msg 53 187 2;
+#X msg 185 225 2;
+#X connect 0 0 3 0;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 2 1 0 0;
+#X connect 10 0 3 0;
+#X connect 10 1 0 0;
+#X connect 11 0 10 0;
+#X connect 12 0 3 0;
diff --git a/examples/drip.pd b/examples/drip.pd
new file mode 100644
index 0000000..1aa7557
--- /dev/null
+++ b/examples/drip.pd
@@ -0,0 +1,70 @@
+#N canvas 378 65 854 849 10;
+#X msg 30 108 come on \, my house;
+#X obj 30 210 print UNFOLDED;
+#X msg 48 135 1 two tre quatre 5 se;
+#X text 72 10 drip;
+#X obj 30 183 drip;
+#X text 311 104 drip is like a medical drip - you can adjust the drop-speed;
+#X obj 316 198 drip 1000;
+#X obj 316 218 print DROP;
+#X msg 316 152 this is that slow;
+#X floatatom 365 179;
+#X text 439 545 drip without arguments will do no scheduling (this is: output all the atoms at once);
+#X text 424 182 drop-delay in [ms];
+#X obj 36 599 drip;
+#X obj 95 601 drip 0;
+#X msg 36 548 5 4 3 2 1 ready go;
+#X obj 36 569 t l l;
+#X obj 95 639 print SCHEDULED;
+#X obj 36 661 print DESCHEDUL;
+#X obj 248 592 drip -10;
+#X obj 248 621 print DESCHED;
+#X msg 248 556 bang;
+#X obj 639 805 unfold;
+#X text 423 790 for historical reasons (finding no proper object-name...) we still provide the obsolete alias;
+#X text 44 27 unfolds a package to a sequence;
+#X text 43 50 since you can switch to scheduled mode \, this might be used to reduce CPU-load;
+#X text 55 817 see also :;
+#X obj 127 819 repack;
+#X obj 35 299 t l l b;
+#X obj 151 350 t l l;
+#X obj 35 375 unfold 200 flush;
+#X obj 141 375 unfold 200;
+#X obj 151 309 del 250;
+#X msg 35 280 list some atoms could be saved while others;
+#X msg 151 329 list might get lost;
+#X obj 35 412 print TIGHT;
+#X obj 141 413 print LOOSE;
+#X obj 35 393 pipe s 1500;
+#X text 411 309 creation:;
+#X text 475 309 "drip [<n> [flush]]";
+#X text 457 397 <n> is the initial drop-delay in [ms];
+#X text 452 333 "flush" indicates whether non-empty buffers should be flushed when a new package arrives or not.;
+#X text 453 362 default is no_flush;
+#X text 457 430 n==0 will DO scheduling (and is therefore somewhat "slower" than without arguments;
+#X text 455 415 default is NO scheduling;
+#X text 456 465 negative values for <n> turn off scheduling;
+#X connect 0 0 4 0;
+#X connect 2 0 4 0;
+#X connect 4 0 1 0;
+#X connect 6 0 7 0;
+#X connect 8 0 6 0;
+#X connect 9 0 6 1;
+#X connect 12 0 17 0;
+#X connect 13 0 16 0;
+#X connect 14 0 15 0;
+#X connect 15 0 12 0;
+#X connect 15 1 13 0;
+#X connect 18 0 19 0;
+#X connect 20 0 18 0;
+#X connect 27 0 29 0;
+#X connect 27 1 30 0;
+#X connect 27 2 31 0;
+#X connect 28 0 29 0;
+#X connect 28 1 30 0;
+#X connect 29 0 36 0;
+#X connect 30 0 35 0;
+#X connect 31 0 33 0;
+#X connect 32 0 27 0;
+#X connect 33 0 28 0;
+#X connect 36 0 34 0;
diff --git a/examples/envrms~.pd b/examples/envrms~.pd
new file mode 100644
index 0000000..c0a4cc0
--- /dev/null
+++ b/examples/envrms~.pd
@@ -0,0 +1,24 @@
+#N canvas 288 18 580 361 10;
+#X obj 71 51 envrms~;
+#X text 174 51 an envelope follower that outputs rms instead of dB;
+#X obj 59 172 sig~ 3;
+#X floatatom 59 148;
+#X obj 59 233 env~;
+#X floatatom 59 254;
+#X floatatom 129 255;
+#X obj 129 234 envrms~;
+#X text 177 93 (i found it very often quite annoying \, to get dB all the times \, and i wouldn't use snapshot~ instead);
+#X obj 59 276 dbtorms;
+#X floatatom 59 299;
+#X text 179 172 of course \, this is cheaper than using env~ + dbtorms;
+#X text 272 269 see also:;
+#X obj 277 296 env~;
+#X obj 315 296 avg~;
+#X obj 354 296 tavg~;
+#X connect 2 0 7 0;
+#X connect 2 0 4 0;
+#X connect 3 0 2 0;
+#X connect 4 0 5 0;
+#X connect 5 0 9 0;
+#X connect 7 0 6 0;
+#X connect 9 0 10 0;
diff --git a/examples/glue.pd b/examples/glue.pd
new file mode 100644
index 0000000..ecc8603
--- /dev/null
+++ b/examples/glue.pd
@@ -0,0 +1,21 @@
+#N canvas 652 218 777 455 10;
+#X obj 111 58 glue;
+#X text 171 58 glue together 2 packages (append \, prepend \, ...)
+;
+#X msg 95 147 1 2 3;
+#X msg 127 174 4 you and me;
+#X obj 95 274 print;
+#X obj 277 270 print;
+#X msg 277 154 bang;
+#X msg 317 154 symbol click;
+#X text 104 335 creation argument: preset the second inlet;
+#X msg 51 179 bang;
+#X obj 95 210 glue;
+#X obj 277 206 glue and stick;
+#X connect 2 0 10 0;
+#X connect 3 0 10 1;
+#X connect 6 0 11 0;
+#X connect 7 0 11 0;
+#X connect 9 0 10 0;
+#X connect 10 0 4 0;
+#X connect 11 0 5 0;
diff --git a/examples/index.pd b/examples/index.pd
new file mode 100644
index 0000000..e7e1232
--- /dev/null
+++ b/examples/index.pd
@@ -0,0 +1,87 @@
+#N canvas 240 25 854 550 10;
+#X msg 117 288 reset;
+#X msg 216 288 auto 0;
+#X msg 354 287 help;
+#X floatatom 441 288;
+#X floatatom 192 439;
+#X obj 117 419 index 128 3;
+#X text 224 441 index;
+#X msg 216 313 auto 1;
+#X msg 128 85 add alias;
+#X msg 128 103 add bind;
+#X msg 128 121 add break;
+#X msg 128 140 add built-in;
+#X msg 128 159 add case;
+#X msg 384 103 delete bind;
+#X msg 384 121 delete break;
+#X msg 384 140 delete built-in;
+#X msg 384 159 delete case;
+#X obj 231 179 symbol;
+#X msg 250 159 case;
+#X msg 250 140 built-in;
+#X msg 250 121 break;
+#X msg 250 103 bind;
+#X msg 250 85 alias;
+#X obj 231 197 send 2index;
+#X obj 117 372 receive 2index;
+#X obj 372 197 send 2index;
+#X obj 114 197 send 2index;
+#X text 239 48 get item index;
+#X text 233 62 (evt. add new item);
+#X text 106 269 clear map;
+#X text 68 48 add new item to map;
+#X text 382 46 delete item from map;
+#X text 190 269 set/reset AUTO-adding;
+#X text 353 271 help;
+#X text 440 272 debug: which item has index #;
+#X text 61 9 index: create a symbol->int map;
+#X text 349 402 creation : "index [<n> [<auto>]]";
+#X text 290 517 in NON-AUTO mode \, only ADDED symbols (eg. "add <symbol>") are added to the map;
+#X text 289 495 in AUTO mode \, unknown symbols are automatically added to the map \;;
+#X msg 384 85 delete alias;
+#N canvas 601 96 333 308 print2screen 0;
+#X obj 114 58 inlet;
+#X obj 157 59 inlet;
+#X obj 114 231 pack 0 s;
+#X msg 114 252 \$2 -> \$1;
+#X obj 114 271 print mapped;
+#X obj 157 192 route add symbol delete;
+#X obj 157 212 symbol;
+#X obj 246 173 loadbang;
+#X connect 0 0 2 0;
+#X connect 1 0 5 0;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 5 0 6 0;
+#X connect 5 1 6 0;
+#X connect 5 2 6 0;
+#X connect 6 0 2 1;
+#X connect 7 0 6 0;
+#X restore 117 488 pd print2screen;
+#X text 387 420 n :: max. number of elements in list (defaults to 128);
+#X text 369 429 auto :: 1_sets auto ON \, 0_sets auto OFF (default off);
+#X connect 0 0 5 0;
+#X connect 1 0 5 0;
+#X connect 2 0 5 0;
+#X connect 3 0 5 0;
+#X connect 5 0 4 0;
+#X connect 5 0 40 0;
+#X connect 7 0 5 0;
+#X connect 8 0 26 0;
+#X connect 9 0 26 0;
+#X connect 10 0 26 0;
+#X connect 11 0 26 0;
+#X connect 12 0 26 0;
+#X connect 13 0 25 0;
+#X connect 14 0 25 0;
+#X connect 15 0 25 0;
+#X connect 16 0 25 0;
+#X connect 17 0 23 0;
+#X connect 18 0 17 0;
+#X connect 19 0 17 0;
+#X connect 20 0 17 0;
+#X connect 21 0 17 0;
+#X connect 22 0 17 0;
+#X connect 24 0 40 1;
+#X connect 24 0 5 0;
+#X connect 39 0 25 0;
diff --git a/examples/length.pd b/examples/length.pd
new file mode 100644
index 0000000..c75f45a
--- /dev/null
+++ b/examples/length.pd
@@ -0,0 +1,16 @@
+#N canvas 186 166 450 300 10;
+#X obj 77 40 length;
+#X text 141 43 get the length of a list;
+#X obj 72 186 length;
+#X floatatom 72 206 4 0 0;
+#X msg 72 109 list these are 4 elements;
+#X msg 83 128 1 2 3;
+#X msg 95 155 auralization by wave field synthesis;
+#X msg 25 113 bang;
+#X floatatom 14 146 4 0 0;
+#X connect 2 0 3 0;
+#X connect 4 0 2 0;
+#X connect 5 0 2 0;
+#X connect 6 0 2 0;
+#X connect 7 0 2 0;
+#X connect 8 0 2 0;
diff --git a/examples/limiter~.pd b/examples/limiter~.pd
new file mode 100644
index 0000000..3749f18
--- /dev/null
+++ b/examples/limiter~.pd
@@ -0,0 +1,226 @@
+#N canvas 283 98 625 388 8;
+#X text 189 15 limiter;
+#X text 187 25 ========;
+#N canvas 0 0 591 391 creation 0;
+#X text 211 152 creates a default limiter (MONO \, 9-samples-buffer)
+;
+#X text 213 189 creates a limiter(MONO \, 10ms-buffer);
+#X text 213 223 creates a limiter (multichannel \, 9-samples-buffer)
+;
+#X text 216 256 creates a limiter (multichannel \, 1ms-buffer !!);
+#X text 82 17 "limiter [<bufsize>] [<in1> [<in2> [...]]]";
+#X text 148 70 creating inlets depends ONLY on the number of arguments
+\, not on the arguments themselves... !;
+#X text 218 313 creates a limiter (multichannel \, 9-samples-buffer)
+;
+#X text 113 187 ______________;
+#X text 89 150 _________________;
+#X text 145 220 _________;
+#X text 114 254 ______________;
+#X text 199 311 __;
+#X obj 23 151 limiter~;
+#X obj 23 185 limiter~ 10;
+#X obj 22 219 limiter~ 0 1 2 3;
+#X obj 22 253 limiter~ 1 2;
+#X obj 18 310 limiter~ We need 4 inlets;
+#X restore 39 202 page creation;
+#N canvas 62 0 762 828 modes 0;
+#X text -259 189 MODE 0 : 1-treshold-limiter;
+#X text -261 384 MODE 1 : 2-tresholds-limiter;
+#X msg 62 255 print;
+#X obj 16 316 limiter~;
+#X obj 39 141 limiter~;
+#X msg 103 123 help;
+#X msg 102 104 print;
+#X msg 39 32 mode 0;
+#X msg 102 31 LIMIT;
+#X msg 39 50 mode 1;
+#X msg 102 49 CRACK;
+#X msg 39 67 mode 2;
+#X msg 102 66 COMPRESS;
+#X text 172 48 crack limiter (2 tresholds);
+#X text 172 66 compressor (1 treshold);
+#X text 181 102 context status;
+#X text 82 30 ==;
+#X text 81 49 ==;
+#X text 80 68 ==;
+#X msg 77 302 LIMIT;
+#X obj 77 286 loadbang;
+#X text 171 30 normal limiter (1 treshold) [default];
+#X msg 61 459 print;
+#X obj 13 522 limiter~;
+#X obj 74 492 loadbang;
+#X msg 74 508 CRACK;
+#X msg 47 716 print;
+#X obj 60 760 loadbang;
+#X text -255 590 MODE 2 : compressor;
+#X msg 60 776 COMPRESS;
+#X msg 52 629 ratio 0.5;
+#X text 159 628 set compress-ratio (0.5 == 1:2);
+#X text 159 605 set the treshold \, where the compressor should start
+to compress;
+#X text 162 677 set the compressor (limit/treshold/ratio);
+#X text 161 655 set limit/holdtime/releasetime at once;
+#X text 163 717 view actual settings;
+#X text 147 459 view actual settings;
+#X msg 64 188 limit 90;
+#X msg 64 211 set 105 40 150;
+#X msg 62 404 set 105 40 150;
+#X msg 65 426 set2 120 1 10;
+#X msg 51 654 set 110 40 150;
+#X msg 51 611 treshold 10;
+#X msg 50 677 compress 96 88 0.5;
+#X text 158 591 set the output-limit;
+#X msg 51 593 limit 98;
+#X text 148 254 view actual settings;
+#X text 149 212 set limit/holdtime/releasetime at once;
+#X text 149 185 set output limit;
+#X obj -1 790 limiter~;
+#X text 145 404 set limiter1 (output-limit/hold-time/release-time)
+;
+#X text -260 621 the output signal will never become louder than the
+specified output-limit.;
+#X text -260 643 if the input-signal becomes loader than the input-treshold
+\, a compressor will start working \, compressing the dynamic range
+by the specified ratio. Signals lesser than the treshold will pass
+through uncompressed.;
+#X text -231 59 set the limiter~ to one of the 3 modes;
+#X text 144 380 set both limits;
+#X text -261 220 this is simple : the output will not become bigger
+than the specified limit. When the input becomes small enough again
+so that this condition is matched even without (positive) amplification
+(this is \, when the input signal level falls below the limit) \, the
+amplification will increase gradually (depending on hold- & release-time)
+towards 1;
+#X text 144 427 set limiter2 (input-treshold/hold-time/release-time)
+;
+#X msg 62 381 limits 100 108;
+#X text -260 414 this limiter can be used to handle disgusting things
+like cracks \, which are much louder than the "normal" musical signal.
+Typically hold- and release-times for the second limiter are far smaller
+than those for the first \, to ensure that the disturbance will pass
+quite fast (since the crack would disturb the sensation anyhow \, we
+do not care much about the distortion caused by a fast limiter). The
+treshold for the 2nd limiter must be greater than the ouput-limit (if
+not \, the limiter will be reset to MODE 0);
+#X text -257 288 all levels (limts/tresholds) should be given in dB
+to produce satisfying results (following pd's agreement on the deziBel-scale
+\, 100dB are equal to 1 \, 0dB equals 0 \, ...);
+#X text 184 123 context(!) help;
+#X connect 2 0 3 0;
+#X connect 5 0 4 0;
+#X connect 6 0 4 0;
+#X connect 7 0 4 0;
+#X connect 8 0 4 0;
+#X connect 9 0 4 0;
+#X connect 10 0 4 0;
+#X connect 11 0 4 0;
+#X connect 12 0 4 0;
+#X connect 19 0 3 0;
+#X connect 20 0 19 0;
+#X connect 22 0 23 0;
+#X connect 24 0 25 0;
+#X connect 25 0 23 0;
+#X connect 26 0 49 0;
+#X connect 27 0 29 0;
+#X connect 29 0 49 0;
+#X connect 30 0 49 0;
+#X connect 37 0 3 0;
+#X connect 38 0 3 0;
+#X connect 39 0 23 0;
+#X connect 40 0 23 0;
+#X connect 41 0 49 0;
+#X connect 42 0 49 0;
+#X connect 43 0 49 0;
+#X connect 45 0 49 0;
+#X connect 57 0 23 0;
+#X restore 184 201 page modes;
+#X msg 338 192 print;
+#X obj 385 316 dac~;
+#X obj 385 259 *~;
+#X obj 416 259 *~;
+#X floatatom 401 112 0 0 0;
+#X floatatom 482 110 0 0 0;
+#X floatatom 440 111 0 0 0;
+#X text 437 98 both;
+#X text 396 98 left;
+#X text 478 98 right;
+#X obj 416 206 limiter~ 50 1;
+#N canvas 0 153 455 493 tabwrite 0;
+#X graph graph1 0 -1 32767 1 130 336 330 196;
+#X array array1 32768 float 0;
+#X pop;
+#X obj 111 63 inlet~;
+#X msg 214 78 \; array1 resize 32768;
+#X obj 111 85 tabwrite~ array1;
+#X obj 151 64 bang~;
+#X obj 214 59 loadbang;
+#X obj 337 88 block~ 32768 8;
+#X connect 1 0 3 0;
+#X connect 4 0 3 0;
+#X connect 5 0 2 0;
+#X restore 443 318 pd tabwrite;
+#X obj 416 317 env~;
+#X floatatom 416 335 4 0 0;
+#X text 30 184 to learn more about this object \, try these;
+#X text 48 301 http://iem.kug.ac.at/~zmoelnig;
+#N canvas 59 76 600 400 generator~ 0;
+#X obj 86 49 inlet;
+#X obj 252 54 inlet;
+#X obj 112 229 outlet~;
+#X obj 112 185 *~;
+#X obj 151 185 *~;
+#X obj 122 128 osc~ 440;
+#X obj 151 145 osc~ 689.062;
+#X obj 112 163 line~;
+#X obj 167 162 line~;
+#X msg 167 128 \$1 100;
+#X msg 112 111 \$1 100;
+#X obj 86 97 f;
+#X obj 252 98 f;
+#X obj 154 229 outlet~;
+#X obj 86 72 dbtorms;
+#X obj 252 78 dbtorms;
+#X connect 0 0 14 0;
+#X connect 1 0 15 0;
+#X connect 3 0 2 0;
+#X connect 4 0 13 0;
+#X connect 5 0 3 1;
+#X connect 6 0 4 0;
+#X connect 7 0 3 0;
+#X connect 8 0 4 1;
+#X connect 9 0 8 0;
+#X connect 10 0 7 0;
+#X connect 11 0 10 0;
+#X connect 12 0 9 0;
+#X connect 14 0 11 0;
+#X connect 15 0 12 0;
+#X restore 416 161 pd generator~;
+#X obj 426 240 nop~;
+#X obj 385 240 nop~;
+#X text 37 91 it is quite important to delay the original signals before
+the limiter-amplification is applied to prevent clicks !!!;
+#X text 52 283 1906:forum::für::umläute:2001;
+#X text 36 41 limiter will output the amplification-factor that has
+to be applied on all INlet~s to get a beautiful limited multichannel-signal
+that preserves the balance between the channels;
+#X text 401 72 level of the inlets;
+#X text 389 83 (give some 190dB and notice no clipping);
+#X connect 4 0 14 0;
+#X connect 6 0 5 0;
+#X connect 7 0 5 1;
+#X connect 7 0 16 0;
+#X connect 7 0 15 0;
+#X connect 8 0 20 0;
+#X connect 9 0 20 1;
+#X connect 10 0 20 0;
+#X connect 10 0 20 1;
+#X connect 14 0 7 0;
+#X connect 14 0 6 1;
+#X connect 16 0 17 0;
+#X connect 20 0 14 0;
+#X connect 20 0 22 0;
+#X connect 20 1 14 1;
+#X connect 20 1 21 0;
+#X connect 21 0 7 1;
+#X connect 22 0 6 0;
diff --git a/examples/list2int.pd b/examples/list2int.pd
new file mode 100644
index 0000000..d850396
--- /dev/null
+++ b/examples/list2int.pd
@@ -0,0 +1,17 @@
+#N canvas 104 89 612 302 12;
+#X obj 106 246 print;
+#X msg 141 139 3.14159 2 hello 1;
+#X msg 150 170 gosh 2.3 1;
+#X obj 106 212 list2int;
+#X text 145 23 list to integer;
+#X text 98 49 cast all floats of a list to integers;
+#X msg 106 110 1 2 -1.567 3 2;
+#X text 225 110 list of floats;
+#X text 316 138 list with symbols;
+#X text 240 169 anything;
+#X obj 412 248 l2i;
+#X text 365 248 alias;
+#X connect 1 0 3 0;
+#X connect 2 0 3 0;
+#X connect 3 0 0 0;
+#X connect 6 0 3 0;
diff --git a/examples/list2symbol.pd b/examples/list2symbol.pd
new file mode 100644
index 0000000..801803f
--- /dev/null
+++ b/examples/list2symbol.pd
@@ -0,0 +1,16 @@
+#N canvas 190 131 809 343 10;
+#X obj 135 48 list2symbol;
+#X text 219 48 convert a list into a symbol;
+#X obj 457 50 l2s;
+#X symbolatom 75 230 50 0 0;
+#X obj 75 202 list2symbol;
+#X msg 75 156 list this was a list and is now a symbol;
+#X msg 159 177 anythings work fine too;
+#X obj 507 212 l2s my bonnie is over the ocean;
+#X obj 507 232 print;
+#X msg 507 191 bang;
+#X connect 4 0 3 0;
+#X connect 5 0 4 0;
+#X connect 6 0 4 0;
+#X connect 7 0 8 0;
+#X connect 9 0 7 0;
diff --git a/examples/lister.pd b/examples/lister.pd
new file mode 100644
index 0000000..d6f3e45
--- /dev/null
+++ b/examples/lister.pd
@@ -0,0 +1,23 @@
+#N canvas 83 390 771 524 10;
+#X obj 160 14 lister;
+#X text 210 15 - store a list;
+#X msg 41 151 bang;
+#X text 76 152 outputs a list;
+#X text 257 196 sets and outputs a list;
+#X text 307 239 sets a list;
+#X text 214 263 creation argument initializes a list;
+#X obj 41 303 print;
+#X text 129 362 alias;
+#X obj 169 362 l;
+#X text 64 53 similar to the "float" \, "int" \, "symbol" \, ... objects;
+#X msg 204 240 2 3 5 7 11 prime;
+#X obj 41 262 lister 1 2 3 4 5 6 7 ordinal;
+#X msg 62 197 1 1 2 3 5 8 13 21 44 fibonacchi;
+#X text 64 77 of course \, this is similar to the "pack" object \, but here we handle list-lenghts dynamically and do not care about type checking !!!;
+#X text 40 434 of course \, this should be named "list" \, but there already appears to be a "list" object \, though i don't see any use in it;
+#X obj 434 443 list 1 two trois;
+#X text 40 471 it seems to store 1 atom only;
+#X connect 2 0 12 0;
+#X connect 11 0 12 1;
+#X connect 12 0 7 0;
+#X connect 13 0 12 0;
diff --git a/examples/lp.pd b/examples/lp.pd
new file mode 100644
index 0000000..2a317b7
--- /dev/null
+++ b/examples/lp.pd
@@ -0,0 +1,20 @@
+#N canvas 173 205 772 508 10;
+#X obj 90 33 lp;
+#X text 129 36 write data to the (parallel) port;
+#X text 82 70 this is LINUX ONLY !!!;
+#X text 17 125 note:;
+#X text 59 126 you might have to be root to get write-permissions on your specified port.;
+#X text 59 160 you can access all ports on your system when using "lp <hex-port-address>";
+#X text 59 194 if your port-address exceeds 0x3ff \, "lp" will try to get all permissions with the iopl()-command. this might be dangerous !;
+#X obj 81 411 lp 0;
+#X obj 110 411 lp 1;
+#X obj 139 411 lp 2;
+#X text 75 390 parallel ports 0 \, 1 \, 2;
+#X obj 294 415 lp 0x378;
+#X text 289 394 another port;
+#X obj 81 337 lp 1;
+#X obj 81 305 % 256;
+#X floatatom 81 283 4 0 0;
+#X text 122 284 write an 8bit-word;
+#X connect 14 0 13 0;
+#X connect 15 0 14 0;
diff --git a/examples/makesymbol.pd b/examples/makesymbol.pd
new file mode 100644
index 0000000..a9ac712
--- /dev/null
+++ b/examples/makesymbol.pd
@@ -0,0 +1,58 @@
+#N canvas 131 -9 723 652 10;
+#X obj 57 15 makesymbol;
+#X text 56 39 makesymbol is something between the "symbol" and the "makefilename" object.;
+#X text 56 79 Any list (with up to 10 members) on the first input will be applied on a C-like format-string that can be either given as an argument on the second input or as a creation-argument.;
+#X text 58 150 The result will be a symbol.;
+#X obj 59 267 makesymbol;
+#X obj 61 591 makesymbol %s_is_%s;
+#X msg 14 246 bang;
+#X msg 11 359 bang;
+#X msg 10 570 bang;
+#X msg 232 246 symbol cat;
+#X msg 59 208 symbol horse;
+#X msg 59 233 symbol cow;
+#X obj 58 380 makesymbol house;
+#X msg 61 349 symbol castle;
+#X msg 232 221 symbol %ss;
+#X symbolatom 233 196;
+#X symbolatom 59 182;
+#X symbolatom 232 310;
+#X msg 61 562 list conan back;
+#X floatatom 128 511;
+#X obj 61 536 pack s 12;
+#X msg 61 488 symbol eleven;
+#X obj 59 293 print A;
+#X obj 58 405 print B;
+#X obj 61 615 print C;
+#X msg 232 335 symbol %d;
+#X msg 232 359 symbol %s;
+#X text 320 360 only %s does;
+#X text 319 328 %d \, %f... won't work properly;
+#X text 321 241 if the right inlet (mask) does not have any format-tags \, the left one won't get through !!;
+#X floatatom 62 460;
+#X text 149 461 it doesn't matter whether you are using numbers \, symbols...;
+#X text 254 541 note:: every member of the list will be converted to a STRING \, so there's no use \, using %d \, %f...;
+#X floatatom 59 324;
+#X text 353 338 (at least \, you won't get what you normally want);
+#X connect 4 0 22 0;
+#X connect 5 0 24 0;
+#X connect 6 0 4 0;
+#X connect 7 0 12 0;
+#X connect 8 0 5 0;
+#X connect 9 0 4 1;
+#X connect 10 0 4 0;
+#X connect 11 0 4 0;
+#X connect 12 0 23 0;
+#X connect 13 0 12 0;
+#X connect 14 0 4 1;
+#X connect 15 0 4 1;
+#X connect 16 0 4 0;
+#X connect 17 0 12 1;
+#X connect 18 0 5 0;
+#X connect 19 0 20 1;
+#X connect 20 0 5 0;
+#X connect 21 0 20 0;
+#X connect 25 0 12 1;
+#X connect 26 0 12 1;
+#X connect 30 0 5 0;
+#X connect 33 0 12 0;
diff --git a/examples/matrix.pd b/examples/matrix.pd
new file mode 100644
index 0000000..a1c6332
--- /dev/null
+++ b/examples/matrix.pd
@@ -0,0 +1,133 @@
+#N canvas 94 0 1118 745 10;
+#X obj 258 -23 matrix;
+#X obj 61 187 mtx_check;
+#X obj 61 216 mtx_print;
+#X obj 544 -21 mtx;
+#X obj 30 535 mtx_print;
+#X obj 30 513 matrix;
+#X msg 42 372 zeros 5;
+#X msg 30 353 eye 3;
+#X msg 49 390 ones 4;
+#X msg 55 411 diag 1 2 3 4;
+#X obj 369 531 matrix;
+#X obj 471 496 loadbang;
+#X obj 471 516 mtx_diag 4 3 1 2;
+#X obj 369 553 print;
+#X msg 369 364 row;
+#X msg 539 497 bang;
+#X msg 379 404 row \$1;
+#X floatatom 379 385 4 0 0;
+#X floatatom 391 424 4 0 0;
+#X msg 391 443 row \$1 1 2 3 4;
+#X floatatom 498 382 4 0 0;
+#X floatatom 510 421 4 0 0;
+#X msg 488 362 col;
+#X msg 498 401 col \$1;
+#X msg 510 440 col \$1 1 2 3 4;
+#X msg 592 364 element;
+#X msg 623 406 element \$1;
+#X floatatom 643 428 4 0 0;
+#X msg 643 447 element 3 \$1;
+#X floatatom 623 386 4 0 0;
+#X msg 61 162 matrix 3 3 1 2 3 4 5 6 7;
+#X msg 39 136 matrix 3 3 1 2 3 4 5 6 7;
+#X text 43 79 this is \, how a matrix really looks...;
+#X text 216 134 an "illegal" matrix;
+#X text 122 187 make the "illegal" matrix consistent;
+#X text 216 103 a "legal" matrix;
+#X msg 40 103 matrix 3 3 1 2 3 1 2 4 7 6 5;
+#X obj 590 218 mtx_print;
+#X obj 590 196 matrix;
+#X obj 655 174 mtx_ones 10;
+#X msg 655 154 bang;
+#X text 121 218 print to stderr (like "print");
+#X msg 590 64 bang;
+#X floatatom 615 103 4 0 0;
+#X msg 604 85 matrix 2 3 10 10 30 20 -5 8;
+#X msg 627 126 1 2 3 1 2 3 10 20 30;
+#X text 758 118 a list of elements;
+#X text 759 132 has to fit the size of the "current" matrix;
+#X text 651 104 set all elements of the current matrix to a value;
+#X text 366 345 get/set rows;
+#X text 479 344 get/set columns;
+#X text 5 564 create various matrices;
+#X text 356 -21 matrix operations;
+#X text 636 197 ==;
+#X obj 660 197 mtx;
+#X msg 335 398 bang;
+#X text 586 344 get/set elements;
+#X msg 654 486 element \$1 2 10;
+#X floatatom 654 468 4 0 0;
+#X msg 702 406 element \$1 \$1;
+#X text 687 406 ==;
+#X obj 161 479 matrix 3 2;
+#X obj 161 525 mtx_print;
+#X msg 161 357 bang;
+#X text 143 542 an "empty" [3 \, 2] matrix;
+#X msg 73 433 egg 4;
+#X msg 75 455 diegg 3 2 1;
+#X obj 126 671 mtx_element;
+#X obj 225 646 mtx_size;
+#X obj 225 669 mtx_transpose;
+#X obj 427 650 mtx_mean;
+#X obj 427 669 mtx_rand;
+#X obj 338 670 mtx_inverse;
+#X obj 126 646 mtx_eye;
+#X obj 338 645 mtx_+;
+#X text 127 620 see also help for:;
+#X msg 912 383 write /tmp/my_matrix.mtx;
+#X msg 912 406 read /tmp/my_matrix.mtx;
+#X obj 810 412 mtx_rand;
+#X msg 810 390 4 5;
+#X msg 858 389 bang;
+#X obj 858 464 mtx_print;
+#X text 848 351 load and save matrices;
+#X obj 858 440 matrix test.mtx;
+#X connect 1 0 2 0;
+#X connect 5 0 4 0;
+#X connect 6 0 5 0;
+#X connect 7 0 5 0;
+#X connect 8 0 5 0;
+#X connect 9 0 5 0;
+#X connect 10 0 13 0;
+#X connect 11 0 12 0;
+#X connect 12 0 10 1;
+#X connect 14 0 10 0;
+#X connect 15 0 12 0;
+#X connect 16 0 10 0;
+#X connect 17 0 16 0;
+#X connect 18 0 19 0;
+#X connect 19 0 10 0;
+#X connect 20 0 23 0;
+#X connect 21 0 24 0;
+#X connect 22 0 10 0;
+#X connect 23 0 10 0;
+#X connect 24 0 10 0;
+#X connect 25 0 10 0;
+#X connect 26 0 10 0;
+#X connect 27 0 28 0;
+#X connect 28 0 10 0;
+#X connect 29 0 26 0;
+#X connect 30 0 1 0;
+#X connect 31 0 2 0;
+#X connect 36 0 2 0;
+#X connect 38 0 37 0;
+#X connect 39 0 38 1;
+#X connect 40 0 39 0;
+#X connect 42 0 38 0;
+#X connect 43 0 38 0;
+#X connect 44 0 38 0;
+#X connect 45 0 38 0;
+#X connect 55 0 10 0;
+#X connect 57 0 10 0;
+#X connect 58 0 57 0;
+#X connect 61 0 62 0;
+#X connect 63 0 61 0;
+#X connect 65 0 5 0;
+#X connect 66 0 5 0;
+#X connect 76 0 83 0;
+#X connect 77 0 83 0;
+#X connect 78 0 83 0;
+#X connect 79 0 78 0;
+#X connect 80 0 83 0;
+#X connect 83 0 81 0;
diff --git a/examples/matrix~.pd b/examples/matrix~.pd
new file mode 100644
index 0000000..5b0fa07
--- /dev/null
+++ b/examples/matrix~.pd
@@ -0,0 +1,58 @@
+#N canvas 59 -12 889 589 12;
+#X obj 68 271 osc~ 100;
+#X obj 68 297 *~ 0.2;
+#X obj 112 320 osc~ 1000;
+#X obj 112 346 *~ 1.5;
+#X obj 157 295 osc~ 432;
+#X obj 68 411 env~;
+#X floatatom 68 435 4 0 0;
+#X obj 127 410 env~;
+#X floatatom 127 434 4 0 0;
+#X obj 187 410 env~;
+#X floatatom 187 434 4 0 0;
+#X obj 247 409 env~;
+#X floatatom 247 433 4 0 0;
+#X floatatom 284 350 4 0 0;
+#X text 332 353 fade time in [ms];
+#X msg 265 100 bang;
+#X obj 265 127 mtx_eye 3 4;
+#X msg 362 100 bang;
+#X obj 362 127 mtx_egg 3 4;
+#X msg 261 179 bang;
+#X msg 362 178 bang;
+#X obj 261 206 mtx_ones 3 4;
+#X obj 362 205 mtx_zeros 3 4;
+#X obj 68 371 matrix~ 3 4 100 .......;
+#X obj 98 32 matrix~;
+#X text 174 24 matrix-multiply m IN~signals to n OUT~signals;
+#X text 174 37 matrices are interpolated a la line~;
+#X text 473 91 the one-before-last inlet eats;
+#X text 476 104 matrix-messages to control the gains;
+#X text 475 117 of the matrix~;
+#X text 484 333 the last inlet gets the fade-time between two matrix-messages.
+;
+#X obj 78 505 matrix~;
+#X text 154 503 creation: "matrix~ [<num_in> [<num_out> [<fade_time>]]]
+;
+#X connect 0 0 1 0;
+#X connect 1 0 23 0;
+#X connect 2 0 3 0;
+#X connect 3 0 23 1;
+#X connect 4 0 23 2;
+#X connect 5 0 6 0;
+#X connect 7 0 8 0;
+#X connect 9 0 10 0;
+#X connect 11 0 12 0;
+#X connect 13 0 23 4;
+#X connect 15 0 16 0;
+#X connect 16 0 23 3;
+#X connect 17 0 18 0;
+#X connect 18 0 23 3;
+#X connect 19 0 21 0;
+#X connect 20 0 22 0;
+#X connect 21 0 23 3;
+#X connect 22 0 23 3;
+#X connect 23 0 5 0;
+#X connect 23 1 7 0;
+#X connect 23 2 9 0;
+#X connect 23 3 11 0;
diff --git a/examples/mavg.pd b/examples/mavg.pd
new file mode 100644
index 0000000..55a5e0e
--- /dev/null
+++ b/examples/mavg.pd
@@ -0,0 +1,16 @@
+#N canvas 0 0 452 302 12;
+#X obj 119 132 metro 100;
+#X obj 119 155 random 10;
+#X floatatom 119 235 4 0 0;
+#X msg 120 107 1;
+#X msg 153 108 0;
+#X obj 119 202 mavg 4;
+#X floatatom 220 181 4 0 0;
+#X text 59 20 moving average filter;
+#X text 261 181 samples to average;
+#X connect 0 0 1 0;
+#X connect 1 0 5 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 2 0;
+#X connect 6 0 5 1;
diff --git a/examples/mean.pd b/examples/mean.pd
new file mode 100644
index 0000000..ca2851b
--- /dev/null
+++ b/examples/mean.pd
@@ -0,0 +1,9 @@
+#N canvas 186 94 383 302 12;
+#X obj 83 154 mean;
+#X floatatom 83 202 4 0 0;
+#X msg 96 96 2 4;
+#X text 46 17 get the mean value of a list of floats;
+#X msg 83 69 1 2 3 -4 5 6;
+#X connect 0 0 1 0;
+#X connect 2 0 0 0;
+#X connect 4 0 0 0;
diff --git a/examples/minmax.pd b/examples/minmax.pd
new file mode 100644
index 0000000..8675c12
--- /dev/null
+++ b/examples/minmax.pd
@@ -0,0 +1,12 @@
+#N canvas 230 189 450 300 10;
+#X obj 73 61 minmax;
+#X text 127 60 get minimum and maximum of a (list of floats);
+#X obj 45 152 minmax;
+#X floatatom 45 184 4 0 0;
+#X floatatom 76 184 4 0 0;
+#X msg 45 112 10 2;
+#X msg 80 129 1 2 3 4 9 6 -1 7;
+#X connect 2 0 3 0;
+#X connect 2 1 4 0;
+#X connect 5 0 2 0;
+#X connect 6 0 2 0;
diff --git a/examples/msgfile.pd b/examples/msgfile.pd
new file mode 100644
index 0000000..2e8ff56
--- /dev/null
+++ b/examples/msgfile.pd
@@ -0,0 +1,109 @@
+#N canvas 127 -1 1027 898 10;
+#X msg 463 10 rewind;
+#X obj 392 853 print done;
+#X text 575 665 read a file;
+#X text 609 686 write one;
+#X text 23 356 see also:;
+#X text 512 9 go to beginning;
+#X msg 466 223 bang;
+#X text 474 724 write a file \, terminating lines only with carriage return (omitting semicolons.) You can read files this way too \, in which case carriage returns are mapped to semicolons.;
+#X obj 355 871 print list;
+#X msg 466 281 clear;
+#X text 123 872 this outlet gets the lines in sequence.;
+#X msg 470 571 set 2 4 6 8;
+#X text 576 570 clear and then add one message;
+#X msg 466 388 add cis boom bah;
+#X msg 465 407 add2 bang;
+#X msg 465 782 print;
+#X text 507 784 debugging printout;
+#X obj 73 9 msgfile;
+#X text 127 9 read and write messages into text files;
+#X obj 355 815 msgfile;
+#X obj 84 357 textfile;
+#X text 18 57 The msgfile object is derived from the textfile object and expands its features.;
+#X text 15 97 new features are :;
+#X text 127 110 insert \, append \, delete \, replace;
+#X msg 464 33 end;
+#X text 511 33 go the the end;
+#X msg 462 84 skip -1;
+#X msg 463 181 next;
+#X msg 462 139 prev;
+#X msg 462 108 where;
+#X text 515 107 where are we now ?;
+#X msg 463 160 this;
+#X text 516 84 go to the <n>th line from here;
+#X text 512 58 go to line number <n>;
+#X text 515 220 output one line as a list and move to the next;
+#X text 520 282 empty the object;
+#X msg 467 321 delete 2;
+#X text 9 183 changed behaviour :;
+#X text 130 183 add2 : read "add too" \; append to an existing line;
+#X text 602 433 insert a message before the current line;
+#X text 605 455 add to the previous line (CHANGED BEHAVIOUR !!!);
+#X text 567 405 add to the last line (CHANGED BEHAVIOUR !!!);
+#X text 568 385 add a message at the end of the object;
+#X msg 467 489 append after the break of dawn;
+#X text 661 486 add a message at the current position;
+#X text 660 506 add to the current line (CHANGED BEHAVIOUR !!!);
+#X msg 468 537 replace the new day;
+#X text 660 537 replace the current line;
+#X msg 466 437 insert before sunrise;
+#X msg 466 455 insert2 inserted;
+#X msg 467 508 append2 appendix;
+#X msg 467 250 flush;
+#X text 516 249 output all lines;
+#X text 457 836 This outlet gets a bang when you hit the end of the sequence \; it will also get the current position when using "when";
+#X msg 467 666 read msgfile.txt;
+#X msg 467 708 write /tmp/msgfile2.txt cr;
+#X msg 466 761 read msgfile2.txt cr;
+#X text 511 139 output the previous line;
+#X text 513 179 output the next line;
+#X text 511 159 output the current line;
+#X msg 462 59 goto 8;
+#X msg 467 301 delete;
+#X text 521 302 delete the current line;
+#X text 524 321 delete the specified line;
+#X msg 467 340 delete 4 7;
+#X text 535 341 delete the specified region;
+#X msg 467 360 delete 7 4;
+#X msg 467 687 write /tmp/msgfile.txt;
+#X text 538 360 delete all but the specified region;
+#X msg 472 600 find test 6;
+#X msg 472 619 find test * 7 *;
+#X text 576 606 find a matching list ("*" is the only wildcard supported);
+#X text 127 97 end \, goto \, skip;
+#X text 131 127 flush \, where \, this \, prev \, next;
+#X text 128 145 find;
+#X text 73 163 read/write can handle csv files too;
+#X connect 0 0 19 0;
+#X connect 6 0 19 0;
+#X connect 9 0 19 0;
+#X connect 11 0 19 0;
+#X connect 13 0 19 0;
+#X connect 14 0 19 0;
+#X connect 15 0 19 0;
+#X connect 19 0 8 0;
+#X connect 19 1 1 0;
+#X connect 24 0 19 0;
+#X connect 26 0 19 0;
+#X connect 27 0 19 0;
+#X connect 28 0 19 0;
+#X connect 29 0 19 0;
+#X connect 31 0 19 0;
+#X connect 36 0 19 0;
+#X connect 43 0 19 0;
+#X connect 46 0 19 0;
+#X connect 48 0 19 0;
+#X connect 49 0 19 0;
+#X connect 50 0 19 0;
+#X connect 51 0 19 0;
+#X connect 54 0 19 0;
+#X connect 55 0 19 0;
+#X connect 56 0 19 0;
+#X connect 60 0 19 0;
+#X connect 61 0 19 0;
+#X connect 64 0 19 0;
+#X connect 66 0 19 0;
+#X connect 67 0 19 0;
+#X connect 69 0 19 0;
+#X connect 70 0 19 0;
diff --git a/examples/mtx_binops.pd b/examples/mtx_binops.pd
new file mode 100644
index 0000000..9c700f4
--- /dev/null
+++ b/examples/mtx_binops.pd
@@ -0,0 +1,112 @@
+#N canvas 95 74 802 673 10;
+#X obj 87 360 mtx_mul;
+#X obj 157 360 mtx_*;
+#X obj 88 163 mtx_add;
+#X obj 167 166 mtx_+;
+#X obj 155 134 mtx_diag 1 2 3 4 5;
+#X obj 88 134 mtx_ones 5;
+#X obj 88 111 t b b;
+#X obj 88 185 mtx_print;
+#X msg 88 92 bang;
+#X text 142 165 ==;
+#X obj 305 134 mtx_eye 4;
+#X obj 305 159 mtx_add 10;
+#X msg 305 107 bang;
+#X obj 305 186 mtx_print;
+#X floatatom 374 101 4 0 0;
+#X obj 374 119 t b f;
+#X obj 392 160 mtx_+ 10;
+#X text 371 161 ==;
+#X obj 87 394 mtx_print;
+#X msg 87 270 bang;
+#X obj 133 332 mtx_diag 1 2;
+#X obj 87 297 t b b;
+#X obj 87 332 mtx_+ 3;
+#X text 137 361 ==;
+#X obj 87 314 mtx_eye 3 2;
+#X obj 249 399 mtx_print;
+#X obj 249 292 t b f;
+#X floatatom 249 274 4 0 0;
+#X msg 249 315 4 2 1 3;
+#X obj 249 335 mtx_diag;
+#X obj 249 363 mtx_mul 2;
+#X obj 328 363 mtx_* 2;
+#X obj 393 363 mtx_.* 2;
+#X text 310 363 ==;
+#X text 376 364 ==;
+#X obj 522 366 mtx_.*;
+#X obj 522 401 mtx_print;
+#X obj 522 304 mtx_diag 1 2 3;
+#X obj 553 322 mtx_ones 3;
+#X obj 522 283 t b b;
+#X msg 522 264 bang;
+#X obj 553 341 mtx_* 2;
+#X text 80 214 add 2 matrices;
+#X text 274 218 add an offset to a matrix;
+#X text 70 423 multiply 2 matrices;
+#X text 245 422 multiply a matrix with a scalar;
+#X text 506 425 multiply 2 matrices element by element;
+#X text 334 19 matrix arithmetic;
+#X obj 88 599 mtx_print;
+#X obj 88 492 t b f;
+#X floatatom 88 474 4 0 0;
+#X msg 88 515 4 2 1 3;
+#X obj 88 535 mtx_diag;
+#X obj 323 600 mtx_print;
+#X obj 323 503 mtx_diag 1 2 3;
+#X obj 354 521 mtx_ones 3;
+#X obj 354 540 mtx_* 2;
+#X text 84 622 divide a matrix by a scalar;
+#X obj 88 563 mtx_./ 2;
+#X obj 323 565 mtx_./;
+#X text 307 624 divide 2 matrices element by element;
+#X obj 323 482 t b b f;
+#X floatatom 323 463 4 0 0;
+#X obj 709 538 matrix;
+#X text 592 538 see also help for;
+#X connect 0 0 18 0;
+#X connect 2 0 7 0;
+#X connect 4 0 2 1;
+#X connect 5 0 2 0;
+#X connect 6 0 5 0;
+#X connect 6 1 4 0;
+#X connect 8 0 6 0;
+#X connect 10 0 11 0;
+#X connect 11 0 13 0;
+#X connect 12 0 10 0;
+#X connect 14 0 15 0;
+#X connect 15 0 10 0;
+#X connect 15 1 11 1;
+#X connect 19 0 21 0;
+#X connect 20 0 0 1;
+#X connect 21 0 24 0;
+#X connect 21 1 20 0;
+#X connect 22 0 0 0;
+#X connect 24 0 22 0;
+#X connect 26 0 28 0;
+#X connect 26 1 30 1;
+#X connect 27 0 26 0;
+#X connect 28 0 29 0;
+#X connect 29 0 30 0;
+#X connect 30 0 25 0;
+#X connect 35 0 36 0;
+#X connect 37 0 35 0;
+#X connect 38 0 41 0;
+#X connect 39 0 37 0;
+#X connect 39 1 38 0;
+#X connect 40 0 39 0;
+#X connect 41 0 35 1;
+#X connect 49 0 51 0;
+#X connect 49 1 58 1;
+#X connect 50 0 49 0;
+#X connect 51 0 52 0;
+#X connect 52 0 58 0;
+#X connect 54 0 59 0;
+#X connect 55 0 56 0;
+#X connect 56 0 59 1;
+#X connect 58 0 48 0;
+#X connect 59 0 53 0;
+#X connect 61 0 54 0;
+#X connect 61 1 55 0;
+#X connect 61 2 56 1;
+#X connect 62 0 61 0;
diff --git a/examples/mtx_element.pd b/examples/mtx_element.pd
new file mode 100644
index 0000000..a69e642
--- /dev/null
+++ b/examples/mtx_element.pd
@@ -0,0 +1,64 @@
+#N canvas 220 134 544 776 10;
+#X obj 53 302 mtx_print;
+#X obj 53 283 mtx_element 4 3;
+#X obj 64 260 mtx_ones 5 3;
+#X msg 64 241 bang;
+#X floatatom 53 191 4 0 0;
+#X msg 138 184 3 2;
+#X msg 144 202 2 0;
+#X msg 144 219 0 1;
+#X msg 145 237 0 0;
+#X text 179 184 set element [3 \, 2];
+#X text 179 202 set all elements in row [2];
+#X text 177 217 set all elements in column [1];
+#X text 178 236 set all elements of matrix;
+#X text 153 285 creation: mtx_element [<row> <col> [<posR> <posC>]];
+#X obj 53 469 mtx_print;
+#X obj 64 427 mtx_ones 5 3;
+#X msg 64 408 bang;
+#X obj 53 450 mtx_row 4 3;
+#X msg 122 405 0;
+#X text 153 405 set all rows;
+#X msg 114 383 2;
+#X text 154 380 set row [2];
+#X msg 53 356 -1 2 3 4 5;
+#X obj 50 658 mtx_print;
+#X obj 61 616 mtx_ones 5 3;
+#X msg 61 597 bang;
+#X msg 131 592 0;
+#X msg 123 570 2;
+#X msg 50 545 -1 2 3 4 5;
+#X obj 50 639 mtx_col 4 3 3;
+#X text 163 567 set column [2];
+#X text 162 593 set all columns;
+#X text 137 640 creation: mtx_col [<row> <col> [<posC>]];
+#X text 133 452 creation: mtx_row [<row> <col> [<posR>]];
+#X text 52 163 set matrix elements;
+#X text 55 339 set matrix rows;
+#X text 49 529 set matrix columns;
+#X text 187 50 get/set elements/rows/columns of a matrix;
+#X obj 90 33 mtx_element;
+#X obj 89 53 mtx_row;
+#X obj 90 75 mtx_col;
+#X obj 210 738 matrix;
+#X text 98 737 see also help for;
+#X connect 1 0 0 0;
+#X connect 2 0 1 0;
+#X connect 3 0 2 0;
+#X connect 4 0 1 0;
+#X connect 5 0 1 1;
+#X connect 6 0 1 1;
+#X connect 7 0 1 1;
+#X connect 8 0 1 1;
+#X connect 15 0 17 0;
+#X connect 16 0 15 0;
+#X connect 17 0 14 0;
+#X connect 18 0 17 1;
+#X connect 20 0 17 1;
+#X connect 22 0 17 0;
+#X connect 24 0 29 0;
+#X connect 25 0 24 0;
+#X connect 26 0 29 1;
+#X connect 27 0 29 1;
+#X connect 28 0 29 0;
+#X connect 29 0 23 0;
diff --git a/examples/mtx_inverse.pd b/examples/mtx_inverse.pd
new file mode 100644
index 0000000..9cca9fe
--- /dev/null
+++ b/examples/mtx_inverse.pd
@@ -0,0 +1,18 @@
+#N canvas 50 156 465 427 10;
+#X obj 92 208 mtx_inverse;
+#X obj 92 292 mtx_print;
+#X msg 103 140 matrix 3 3 1 2 3 2 3 4 3 4 5;
+#X text 280 142 singular;
+#X msg 92 108 matrix 3 3 1 2 4 2 3 4 3 4 5;
+#X text 265 107 regular;
+#X text 85 310 get the inverse of a matrix;
+#X text 286 158 regular;
+#X text 287 168 but badly conditioned;
+#X msg 111 164 matrix 3 3 1 2 3 2 4 4 3 4 5;
+#X text 82 26 get the inverse of a matrix;
+#X obj 233 381 matrix;
+#X text 116 381 see also help for;
+#X connect 0 0 1 0;
+#X connect 2 0 0 0;
+#X connect 4 0 0 0;
+#X connect 9 0 0 0;
diff --git a/examples/mtx_mean.pd b/examples/mtx_mean.pd
new file mode 100644
index 0000000..02b02fb
--- /dev/null
+++ b/examples/mtx_mean.pd
@@ -0,0 +1,13 @@
+#N canvas 128 104 450 300 10;
+#X obj 57 146 mtx_mean;
+#X obj 63 91 mtx_print;
+#X obj 57 201 print mean_row;
+#X obj 57 76 mtx_rand;
+#X msg 57 52 4 5;
+#X text 55 229 get the mean value of each column;
+#X obj 175 275 matrix;
+#X text 58 275 see also help for;
+#X connect 0 0 2 0;
+#X connect 3 0 1 0;
+#X connect 3 0 0 0;
+#X connect 4 0 3 0;
diff --git a/examples/mtx_rand.pd b/examples/mtx_rand.pd
new file mode 100644
index 0000000..491d6de
--- /dev/null
+++ b/examples/mtx_rand.pd
@@ -0,0 +1,20 @@
+#N canvas 120 116 450 300 10;
+#X obj 59 148 mtx_rand;
+#X obj 59 194 mtx_print;
+#X obj 83 100 mtx_ones 6 3;
+#X msg 83 82 bang;
+#X msg 74 58 5 7;
+#X msg 59 35 3;
+#X msg 115 133 seed 12;
+#X text 51 219 get a matrix containing;
+#X text 51 232 random elements (0..1];
+#X text 165 131 set seed;
+#X obj 357 274 matrix;
+#X text 240 274 see also help for;
+#X text 129 11 fill a matrix with random values;
+#X connect 0 0 1 0;
+#X connect 2 0 0 0;
+#X connect 3 0 2 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 0;
diff --git a/examples/mtx_size.pd b/examples/mtx_size.pd
new file mode 100644
index 0000000..85d7747
--- /dev/null
+++ b/examples/mtx_size.pd
@@ -0,0 +1,44 @@
+#N canvas 161 60 833 285 10;
+#X obj 386 214 mtx_print;
+#X obj 386 106 mtx_ones;
+#X msg 386 83 3 5;
+#X obj 386 192 mtx_resize;
+#X text 383 67 resize a matrix;
+#X msg 441 91 3 2;
+#X msg 447 109 2 0;
+#X msg 448 144 0 0;
+#X text 482 91 resize to [3 \, 2];
+#X text 482 109 resize to 2 rows \, leave row-length unchanged;
+#X text 481 143 don't resize;
+#X msg 452 169 2;
+#X text 484 171 resize to [2 \, 2];
+#X text 458 192 creation: mtx_resize [<rows> [<cols>]];
+#X msg 447 126 0 4;
+#X text 482 124 resize to 4 columns \, leave column-length unchanged;
+#X floatatom 81 178 4 0 0;
+#X text 78 68 get the size of a matrix;
+#X obj 81 140 mtx_size;
+#X msg 115 91 3 2;
+#X msg 81 91 7;
+#X obj 81 115 mtx_ones;
+#X floatatom 124 178 4 0 0;
+#X text 122 194 columns;
+#X text 82 195 rows;
+#X obj 150 22 mtx_size;
+#X obj 421 23 mtx_resize;
+#X text 223 24 get/set the size of a matrix;
+#X obj 306 252 matrix;
+#X text 189 252 see also help for;
+#X connect 1 0 3 0;
+#X connect 2 0 1 0;
+#X connect 3 0 0 0;
+#X connect 5 0 3 1;
+#X connect 6 0 3 1;
+#X connect 7 0 3 1;
+#X connect 11 0 3 1;
+#X connect 14 0 3 1;
+#X connect 18 0 16 0;
+#X connect 18 1 22 0;
+#X connect 19 0 21 0;
+#X connect 20 0 21 0;
+#X connect 21 0 18 0;
diff --git a/examples/mtx_special.pd b/examples/mtx_special.pd
new file mode 100644
index 0000000..b230a0f
--- /dev/null
+++ b/examples/mtx_special.pd
@@ -0,0 +1,60 @@
+#N canvas 113 77 498 667 10;
+#X obj 117 136 mtx_eye 5;
+#X obj 117 162 mtx_print;
+#X msg 117 65 bang;
+#X msg 147 109 3 5;
+#X msg 133 85 10;
+#X obj 120 332 mtx_print;
+#X msg 120 234 bang;
+#X msg 150 279 3 5;
+#X msg 136 255 10;
+#X obj 311 337 mtx_print;
+#X msg 311 239 bang;
+#X msg 341 284 3 5;
+#X msg 327 260 10;
+#X obj 120 306 mtx_ones 5;
+#X obj 311 311 mtx_zeros 5;
+#X obj 124 496 mtx_print;
+#X msg 136 417 1 2 3 4 5;
+#X msg 124 395 bang;
+#X obj 124 468 mtx_diag 7 6 5 4;
+#X text 93 181 identity matrix;
+#X text 104 358 all matrix elements=1;
+#X text 290 359 all matrix elements=0;
+#X text 113 522 diagonal-matrix;
+#X obj 333 162 mtx_print;
+#X msg 333 65 bang;
+#X msg 363 109 3 5;
+#X msg 349 85 10;
+#X obj 333 136 mtx_egg 5;
+#X obj 316 491 mtx_print;
+#X msg 328 412 1 2 3 4 5;
+#X msg 316 390 bang;
+#X obj 316 463 mtx_diegg 7 6 5 4;
+#X text 305 517 turned diagonal-matrix;
+#X text 309 181 turned identity matrix;
+#X text 173 19 create special matrices;
+#X obj 245 612 matrix;
+#X text 128 612 see also help for;
+#X connect 0 0 1 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 6 0 13 0;
+#X connect 7 0 13 0;
+#X connect 8 0 13 0;
+#X connect 10 0 14 0;
+#X connect 11 0 14 0;
+#X connect 12 0 14 0;
+#X connect 13 0 5 0;
+#X connect 14 0 9 0;
+#X connect 16 0 18 0;
+#X connect 17 0 18 0;
+#X connect 18 0 15 0;
+#X connect 24 0 27 0;
+#X connect 25 0 27 0;
+#X connect 26 0 27 0;
+#X connect 27 0 23 0;
+#X connect 29 0 31 0;
+#X connect 30 0 31 0;
+#X connect 31 0 28 0;
diff --git a/examples/mtx_trace.pd b/examples/mtx_trace.pd
new file mode 100644
index 0000000..7925d5b
--- /dev/null
+++ b/examples/mtx_trace.pd
@@ -0,0 +1,23 @@
+#N canvas 137 140 916 465 10;
+#X obj 79 361 mtx_diag;
+#X obj 79 389 print;
+#X obj 79 308 mtx_ones 7;
+#X msg 79 288 bang;
+#X obj 84 106 mtx_ones 7;
+#X msg 84 83 bang;
+#X obj 84 147 mtx_trace;
+#X floatatom 84 189 4 0 0;
+#X text 86 68 get trace of a matrix;
+#X text 79 271 get diagonal of a matrix;
+#X text 81 204 trace = sum(diagonal elements);
+#X text 243 28 get information of the diagonale of a matrix;
+#X text 440 176 see also help for;
+#X obj 555 177 matrix;
+#X text 425 265 to create diagonale matrices \, see;
+#X obj 629 265 mtx_eye;
+#X connect 0 0 1 0;
+#X connect 2 0 0 0;
+#X connect 3 0 2 0;
+#X connect 4 0 6 0;
+#X connect 5 0 4 0;
+#X connect 6 0 7 0;
diff --git a/examples/mtx_transpose.pd b/examples/mtx_transpose.pd
new file mode 100644
index 0000000..dd042b2
--- /dev/null
+++ b/examples/mtx_transpose.pd
@@ -0,0 +1,59 @@
+#N canvas 204 56 718 799 10;
+#X obj 48 162 mtx_print;
+#X obj 48 134 mtx_transpose;
+#X obj 48 81 mtx_ones;
+#X msg 48 59 3 5;
+#X text 45 42 transpose a matrix;
+#X text 158 13 tranpose/shift matrices;
+#X obj 37 349 mtx_print;
+#X msg 37 246 1 2 3 4 5;
+#X text 33 229 shift rows of a matrix;
+#X floatatom 104 301 4 0 0;
+#X obj 37 321 mtx_scroll 1;
+#X obj 37 268 mtx_diag;
+#X obj 32 524 mtx_print;
+#X msg 32 421 1 2 3 4 5;
+#X floatatom 99 476 4 0 0;
+#X obj 32 443 mtx_diag;
+#X text 28 404 shift columns of a matrix;
+#X obj 32 497 mtx_roll 1;
+#X text 135 477 shift amount (0=no-shift \; 1=1-column-right \; -2=2-columns-left \; ...);
+#X text 143 299 shift amount (0=no-shift \; 1=1-row-down \; -2=2-rows-up \; ...);
+#X text 30 594 pivot-transform a matrix;
+#X obj 34 669 mtx_pivot;
+#N canvas 352 114 190 367 rand-matrix 0;
+#X obj 74 163 inlet;
+#X obj 74 270 outlet;
+#X obj 74 195 mtx_rand;
+#X obj 74 215 mtx_* 10;
+#X obj 74 237 l2i;
+#X connect 0 0 2 0;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X restore 34 633 pd rand-matrix;
+#X msg 34 611 4 3;
+#X obj 83 690 mtx_print post;
+#X obj 58 710 mtx_print pre;
+#X obj 34 760 mtx_print pivot;
+#X obj 485 95 matrix;
+#X text 375 95 see also help for;
+#X text 282 620 this will tranform the columns and rows \, so that the result will have all maximum values in the diagonale. the maximum of the matrix will be located at the upper-lft corner.;
+#X text 281 669 the first outlet is the pivot-transformed matrix.;
+#X text 280 695 the other outlets are the 1/0-matrices that have to be pre-multiplied (row-tranform) and post-multiplied (column-tranform) to the original matrix to get the pivot-tranformation. this is useful for de-pivoting.;
+#X connect 1 0 0 0;
+#X connect 2 0 1 0;
+#X connect 3 0 2 0;
+#X connect 7 0 11 0;
+#X connect 9 0 10 1;
+#X connect 10 0 6 0;
+#X connect 11 0 10 0;
+#X connect 13 0 15 0;
+#X connect 14 0 17 1;
+#X connect 15 0 17 0;
+#X connect 17 0 12 0;
+#X connect 21 0 26 0;
+#X connect 21 1 25 0;
+#X connect 21 2 24 0;
+#X connect 22 0 21 0;
+#X connect 23 0 22 0;
diff --git a/examples/multiline~.pd b/examples/multiline~.pd
new file mode 100644
index 0000000..ae9d791
--- /dev/null
+++ b/examples/multiline~.pd
@@ -0,0 +1,63 @@
+#N canvas 262 397 898 508 10;
+#X obj 67 53 multiline~;
+#X text 209 55 line~d multiplication of multiple signals;
+#X obj 47 201 sig~ 1;
+#X obj 89 201 sig~ 10;
+#X floatatom 57 281 4 0 0;
+#X floatatom 154 282 4 0 0;
+#X msg 153 181 0 -1;
+#X obj 57 261 avg~;
+#X obj 154 262 avg~;
+#X floatatom 215 208 4 0 0;
+#X text 252 209 line-time;
+#X floatatom 121 129 4 0 0;
+#X text 157 132 multiply all signals with the same value;
+#X obj 57 223 multiline~ 1 2 50;
+#X msg 154 154 2 1;
+#X obj 452 235 multiline~ 1 1 1 1 1000;
+#X obj 452 253 avg~;
+#X floatatom 452 272 4 0 0;
+#X obj 452 193 sig~ 1;
+#X obj 496 253 avg~;
+#X floatatom 496 272 4 0 0;
+#X obj 496 193 sig~ 1;
+#X obj 540 253 avg~;
+#X floatatom 540 272 4 0 0;
+#X obj 540 193 sig~ 1;
+#X obj 585 254 avg~;
+#X floatatom 585 273 4 0 0;
+#X obj 585 194 sig~ 1;
+#X msg 653 171 0 0 0 0;
+#X msg 653 207 1 0 2 0;
+#X msg 653 189 0 1 0 2;
+#X msg 653 225 1 1;
+#X text 49 397 creation:;
+#X obj 121 400 multiline~ g1 g2 g3 ... g<n> fade-time;
+#X text 194 166 gain1 gain2 ...;
+#X text 367 394 will make <n> outlets and (n+2) inlets (1 extra for the gain-list \, 1 extra for the fade-time);
+#X connect 2 0 13 0;
+#X connect 3 0 13 1;
+#X connect 6 0 13 2;
+#X connect 7 0 4 0;
+#X connect 8 0 5 0;
+#X connect 9 0 13 3;
+#X connect 11 0 13 2;
+#X connect 13 0 7 0;
+#X connect 13 1 8 0;
+#X connect 14 0 13 2;
+#X connect 15 0 16 0;
+#X connect 15 1 19 0;
+#X connect 15 2 22 0;
+#X connect 15 3 25 0;
+#X connect 16 0 17 0;
+#X connect 18 0 15 0;
+#X connect 19 0 20 0;
+#X connect 21 0 15 1;
+#X connect 22 0 23 0;
+#X connect 24 0 15 2;
+#X connect 25 0 26 0;
+#X connect 27 0 15 3;
+#X connect 28 0 15 4;
+#X connect 29 0 15 4;
+#X connect 30 0 15 4;
+#X connect 31 0 15 4;
diff --git a/examples/multiplex~.pd b/examples/multiplex~.pd
new file mode 100644
index 0000000..90e64aa
--- /dev/null
+++ b/examples/multiplex~.pd
@@ -0,0 +1,23 @@
+#N canvas 79 72 637 304 12;
+#X obj 75 23 multiplex~;
+#X obj 72 193 multiplex~ . . . . .;
+#X text 210 23 multiplex 1-of-n signals to 1 outlet;
+#X obj 72 139 sig~ 1;
+#X obj 110 161 sig~ 0.5;
+#X obj 149 137 sig~ 50;
+#X obj 227 158 sig~ 0.1;
+#X floatatom 110 93 4 0 0;
+#X obj 72 229 env~;
+#X floatatom 72 255 4 0 0;
+#X text 156 93 select a signal;
+#X obj 306 262 mux~;
+#X text 254 261 alias;
+#X text 135 214 the number of arguments specifies the number of inlets
+;
+#X connect 1 0 8 0;
+#X connect 3 0 1 0;
+#X connect 4 0 1 1;
+#X connect 5 0 1 2;
+#X connect 6 0 1 4;
+#X connect 7 0 1 0;
+#X connect 8 0 9 0;
diff --git a/examples/niagara.pd b/examples/niagara.pd
new file mode 100644
index 0000000..f5528ca
--- /dev/null
+++ b/examples/niagara.pd
@@ -0,0 +1,21 @@
+#N canvas 87 562 895 337 10;
+#X floatatom 124 175;
+#X obj 69 206 niagara 12;
+#X obj 69 288 print LEFT;
+#X obj 124 269 print RIGHT;
+#X msg 85 139 1 2 3 4 5 6 7 all good children go to heaven;
+#X obj 159 25 niagara;
+#X text 374 28 divide a package into 2 sub-packages;
+#X text 241 53 creation : "niagara <n>" creates a niagara-fall with a rock at point <n>;
+#X text 159 176 where to divide;
+#X text 451 143 list;
+#X text 451 111 anything;
+#X text 420 219 note :;
+#X text 467 233 if <anything> is passed \, then 2 <anything>s appear at the outputs;
+#X text 467 219 if a <list> is passed \, then 2 <list>s appear at the outputs;
+#X msg 69 102 some water will go down on the left side of the rock and the rest will come down on the other side;
+#X connect 0 0 1 1;
+#X connect 1 0 2 0;
+#X connect 1 1 3 0;
+#X connect 4 0 1 0;
+#X connect 14 0 1 0;
diff --git a/examples/noish~.pd b/examples/noish~.pd
new file mode 100644
index 0000000..72e7913
--- /dev/null
+++ b/examples/noish~.pd
@@ -0,0 +1,21 @@
+#N canvas 183 18 591 404 8;
+#X text 119 43 draws a random number every n samples and interpolates between;
+#X text 121 87 DODGE:JERSE::computer:music::c3:9;
+#X floatatom 91 222;
+#X text 85 199 drawing rate in Hz;
+#X obj 91 321 dac~;
+#X obj 132 322 print~;
+#X msg 132 298 bang;
+#X obj 55 321 env~;
+#X floatatom 55 347;
+#X text 223 219 maybe the input should be fixed to signal;
+#X text 45 44 noish~ ::;
+#X text 120 117 the effect is that you get a bandlimited noise of which the bandwidth of which can be conrtolled via the drawing:rate without having to use expensive filters;
+#X obj 91 245 noish~ 2756.25;
+#X connect 2 0 12 0;
+#X connect 6 0 5 0;
+#X connect 7 0 8 0;
+#X connect 12 0 5 0;
+#X connect 12 0 4 1;
+#X connect 12 0 4 0;
+#X connect 12 0 7 0;
diff --git a/examples/noisi~.pd b/examples/noisi~.pd
new file mode 100644
index 0000000..c76c6d4
--- /dev/null
+++ b/examples/noisi~.pd
@@ -0,0 +1,21 @@
+#N canvas 183 18 588 401 8;
+#X text 45 44 noisi~ ::;
+#X text 119 43 draws a random number every n samples and interpolates between;
+#X text 116 87 DODGE:JERSE::computer:music::c3:9;
+#X floatatom 91 222;
+#X text 85 199 drawing rate in Hz;
+#X obj 91 321 dac~;
+#X obj 132 322 print~;
+#X msg 132 298 bang;
+#X obj 55 321 env~;
+#X floatatom 55 347;
+#X text 223 219 maybe the input should be fixed to signal;
+#X text 117 120 the effect is that you get a bandlimited:noise the bandwidth of which can be controlled via the drawing:rate without having to use expensive filters;
+#X obj 91 244 noisi~ 2756.25;
+#X connect 3 0 12 0;
+#X connect 7 0 6 0;
+#X connect 8 0 9 0;
+#X connect 12 0 5 0;
+#X connect 12 0 5 1;
+#X connect 12 0 6 0;
+#X connect 12 0 8 0;
diff --git a/examples/nop.pd b/examples/nop.pd
new file mode 100644
index 0000000..aed3b61
--- /dev/null
+++ b/examples/nop.pd
@@ -0,0 +1,17 @@
+#N canvas 456 395 450 428 10;
+#X obj 121 331 nop;
+#X msg 155 157 bang;
+#X floatatom 155 175;
+#X symbolatom 156 196;
+#X obj 121 350 print;
+#X msg 156 240 set mummy;
+#X obj 132 26 nop;
+#X text 95 71 maybe this is not very intelligent;
+#X text 97 89 it just passes through what it gets;
+#X msg 157 218 1 to 3 for 5;
+#X connect 0 0 4 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 5 0 0 0;
+#X connect 9 0 0 0;
diff --git a/examples/nop~.pd b/examples/nop~.pd
new file mode 100644
index 0000000..96673bc
--- /dev/null
+++ b/examples/nop~.pd
@@ -0,0 +1,17 @@
+#N canvas 25 -4 689 488 10;
+#X obj 89 71 nop~;
+#X text 134 73 will do nothing !!! but nevertheless it takes some time;
+#X text 132 85 so the signal is delay for 1 block...;
+#X text 131 98 Use this to synchronize signals;
+#X obj 60 216 osc~ 440;
+#X obj 60 312 -~;
+#X obj 60 339 env~;
+#X floatatom 59 364;
+#X obj 88 247 nop~;
+#X text 132 121 by the way \, you can use it as a cheap and very short delay too;
+#X text 135 158 ...or as a dummy for anything~...;
+#X connect 4 0 5 0;
+#X connect 4 0 8 0;
+#X connect 5 0 6 0;
+#X connect 6 0 7 0;
+#X connect 8 0 5 1;
diff --git a/examples/packel.pd b/examples/packel.pd
new file mode 100644
index 0000000..b7f2b56
--- /dev/null
+++ b/examples/packel.pd
@@ -0,0 +1,20 @@
+#N canvas 169 380 720 387 10;
+#X obj 48 34 packel;
+#X text 112 33 get the nth element of a package;
+#X msg 62 161 uno dva drei quattre five;
+#X floatatom 105 219;
+#X obj 62 239 packel 3;
+#X obj 62 268 print ELEMENT;
+#X msg 62 307 uno dva drei quattre five;
+#X obj 62 327 packel -2;
+#X obj 62 351 print REVERSE_ELEMENT;
+#X text 275 210 creation: packel [<n>];
+#X text 140 220 n;
+#X text 314 227 n indicates the index of the element to be output;
+#X text 314 245 n==0 ouputs the whole package;
+#X text 314 262 n<0 ouputs the nth-last element;
+#X connect 2 0 4 0;
+#X connect 3 0 4 1;
+#X connect 4 0 5 0;
+#X connect 6 0 7 0;
+#X connect 7 0 8 0;
diff --git a/examples/pack~.pd b/examples/pack~.pd
new file mode 100644
index 0000000..24a9ec9
--- /dev/null
+++ b/examples/pack~.pd
@@ -0,0 +1,33 @@
+#N canvas 420 353 697 479 10;
+#X floatatom 83 92;
+#X obj 83 111 osc~ 689.062;
+#X obj 83 320 unpack 0 0 0;
+#X obj 240 302 print;
+#X floatatom 83 359;
+#X floatatom 150 339;
+#X obj 83 230 t l l;
+#X obj 240 282 spigot;
+#X msg 271 262 1;
+#X msg 297 262 0;
+#X obj 83 300 spigot;
+#X msg 114 280 1;
+#X msg 140 280 0;
+#X obj 83 162 pack~;
+#X text 154 40 pack~;
+#X text 178 65 convert signals to float-packages;
+#X text 460 14 see also;
+#X obj 461 33 unpack~;
+#X text 98 379 1st and 3rd sample of each signal-vector;
+#X connect 0 0 1 0;
+#X connect 1 0 13 0;
+#X connect 2 0 4 0;
+#X connect 2 2 5 0;
+#X connect 6 0 10 0;
+#X connect 6 1 7 0;
+#X connect 7 0 3 0;
+#X connect 8 0 7 1;
+#X connect 9 0 7 1;
+#X connect 10 0 2 0;
+#X connect 11 0 10 1;
+#X connect 12 0 10 1;
+#X connect 13 0 6 0;
diff --git a/examples/pdf~.pd b/examples/pdf~.pd
new file mode 100644
index 0000000..c6505b3
--- /dev/null
+++ b/examples/pdf~.pd
@@ -0,0 +1,25 @@
+#N canvas 160 310 829 485 10;
+#X obj 90 43 pdf~;
+#X text 175 44 probability density function;
+#X obj 14 166 osc~ 440;
+#X msg 97 193 bang;
+#X obj 14 387 tabwrite array99;
+#X obj 14 303 pdf~ 128;
+#X msg 96 246 clear;
+#X msg 97 215 1;
+#X msg 96 269 0;
+#X text 146 260 clear the buffer;
+#X text 140 203 send the pdf to the outlet;
+#X obj 137 387 print;
+#X text 90 302 creation argument : number of steps;
+#X text 227 315 default is 64;
+#X graph graph1 0 -1 128 1 428 431 828 131;
+#X array array99 128 float;
+#X pop;
+#X connect 2 0 5 0;
+#X connect 3 0 5 0;
+#X connect 5 0 4 0;
+#X connect 5 0 11 0;
+#X connect 6 0 5 0;
+#X connect 7 0 5 0;
+#X connect 8 0 5 0;
diff --git a/examples/quantize~.pd b/examples/quantize~.pd
new file mode 100644
index 0000000..02bd567
--- /dev/null
+++ b/examples/quantize~.pd
@@ -0,0 +1,37 @@
+#N canvas 0 -1 705 533 10;
+#X text 242 9 quantize a signal with a variable step-number;
+#X msg 119 204 8bit;
+#X msg 119 180 16bit;
+#X msg 119 157 float;
+#X floatatom 120 133;
+#X obj 71 367 dac~ 1;
+#X obj 71 342 *~;
+#X obj 32 293 dbtorms;
+#X floatatom 32 269;
+#X obj 26 227 osc~ 440;
+#X floatatom 26 203;
+#X obj 87 255 quantize~ 16;
+#X msg 118 228 help;
+#X msg 404 59 \; pd dsp 1;
+#X obj 71 317 sig~ 0.2;
+#X msg 482 61 \; pd dsp 0;
+#X graph graph5 0 -1 100 1 298 494 698 194;
+#X array scope 100 float;
+#X pop;
+#X obj 139 314 tabwrite~ scope;
+#X msg 139 289 bang;
+#X obj 123 12 quantize~;
+#X connect 1 0 11 0;
+#X connect 2 0 11 0;
+#X connect 3 0 11 0;
+#X connect 4 0 11 0;
+#X connect 6 0 5 0;
+#X connect 7 0 14 0;
+#X connect 8 0 7 0;
+#X connect 9 0 11 0;
+#X connect 10 0 9 0;
+#X connect 11 0 6 1;
+#X connect 11 0 17 0;
+#X connect 12 0 11 0;
+#X connect 14 0 6 0;
+#X connect 18 0 17 0;
diff --git a/examples/repack.pd b/examples/repack.pd
new file mode 100644
index 0000000..3b2560b
--- /dev/null
+++ b/examples/repack.pd
@@ -0,0 +1,23 @@
+#N canvas 222 219 739 549 10;
+#X obj 78 35 repack;
+#X obj 73 303 print;
+#X floatatom 73 120;
+#X msg 73 138 1 2 3 4 5 6 7 8 9 10;
+#X obj 73 265 repack 7;
+#X msg 73 157 hallo;
+#X text 149 33 (re)packs (packages of) floats/symbols/pointers/anythings to packages of a (given) size;
+#X msg 120 187 bang;
+#X floatatom 116 235;
+#X text 172 236 set the package-size;
+#X text 173 191 output the currently made package immediately;
+#X obj 56 501 repack 1;
+#X text 118 502 unfolds packages to atoms \; see also;
+#X obj 337 503 drip;
+#X text 72 407 creation:;
+#X text 140 408 "repack <n>" create packages of the length n;
+#X connect 2 0 4 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 5 0 4 0;
+#X connect 7 0 4 0;
+#X connect 8 0 4 1;
diff --git a/examples/scalarmult.pd b/examples/scalarmult.pd
new file mode 100644
index 0000000..1b988ef
--- /dev/null
+++ b/examples/scalarmult.pd
@@ -0,0 +1,73 @@
+#N canvas 193 440 857 589 10;
+#X obj 83 45 .;
+#X text 130 46 scalar multilicaton ("dot");
+#X msg 71 156 1 2 3;
+#X msg 110 182 4 3 2;
+#X obj 71 241 print;
+#X msg 177 157 1 2 3;
+#X msg 235 185 4 3 2;
+#X obj 177 242 print;
+#X obj 177 216 . 10 10 1;
+#X obj 71 215 .;
+#X msg 375 159 1 2 3;
+#X obj 375 244 print;
+#X msg 481 160 1 2 3;
+#X obj 481 245 print;
+#X obj 375 218 . 0;
+#X floatatom 409 193 4 0 0;
+#X obj 481 219 . 7;
+#X floatatom 514 194 4 0 0;
+#X obj 62 456 .;
+#X msg 62 377 1 2 3;
+#X msg 178 378 1 2 3;
+#X obj 178 454 . 0;
+#X text 58 342 these are NOT the same !!;
+#X obj 178 485 print SCAL;
+#X obj 62 485 print VECT;
+#X msg 78 411 2 2 1;
+#X msg 114 437 3;
+#X msg 207 430 2 2 1;
+#X msg 194 407 3;
+#X text 233 406 good;
+#X text 247 430 bad;
+#X text 126 411 good;
+#X text 140 435 bad;
+#X text 420 334 tricky:;
+#X obj 431 453 print;
+#X msg 447 403 1 2 3;
+#X floatatom 431 377 4 0 0;
+#X obj 431 430 .;
+#X obj 536 460 print;
+#X msg 536 414 1 2 3;
+#X obj 536 437 .;
+#X obj 536 392 t b l;
+#X floatatom 536 368 4 0 0;
+#X text 582 393 note that we "cast" the float to list;
+#X connect 2 0 9 0;
+#X connect 3 0 9 1;
+#X connect 5 0 8 0;
+#X connect 6 0 8 1;
+#X connect 8 0 7 0;
+#X connect 9 0 4 0;
+#X connect 10 0 14 0;
+#X connect 12 0 16 0;
+#X connect 14 0 11 0;
+#X connect 15 0 14 1;
+#X connect 16 0 13 0;
+#X connect 17 0 16 1;
+#X connect 18 0 24 0;
+#X connect 19 0 18 0;
+#X connect 20 0 21 0;
+#X connect 21 0 23 0;
+#X connect 25 0 18 1;
+#X connect 26 0 18 1;
+#X connect 27 0 21 1;
+#X connect 28 0 21 1;
+#X connect 35 0 37 1;
+#X connect 36 0 37 0;
+#X connect 37 0 34 0;
+#X connect 39 0 40 0;
+#X connect 40 0 38 0;
+#X connect 41 0 39 0;
+#X connect 41 1 40 1;
+#X connect 42 0 41 0;
diff --git a/examples/segregate.pd b/examples/segregate.pd
new file mode 100644
index 0000000..0e47699
--- /dev/null
+++ b/examples/segregate.pd
@@ -0,0 +1,33 @@
+#N canvas 543 205 450 496 10;
+#X obj 136 344 segregate;
+#X obj 136 447 print BANG;
+#X obj 145 430 print FLOAT;
+#X obj 155 413 print SYMBOL;
+#X obj 175 379 print POINTER;
+#X obj 165 396 print LIST;
+#X floatatom 155 226;
+#X symbolatom 171 255;
+#X msg 136 197 bang;
+#X msg 184 281 1 2 3 4;
+#X msg 185 307 come on \, my house;
+#X text 131 31 segregate;
+#X text 51 87 segregates the inputs by their type;
+#X text 50 112 known types (in order of their outlets)::;
+#X text 93 131 BANG \, FLOAT \, SYMBOL \, LIST \, POINTER;
+#X text 86 196 bang;
+#X text 86 226 float;
+#X text 87 256 symbol;
+#X obj 185 362 print ANYTHING;
+#X text 88 309 anythings;
+#X text 87 284 list;
+#X connect 0 0 1 0;
+#X connect 0 1 2 0;
+#X connect 0 2 3 0;
+#X connect 0 3 5 0;
+#X connect 0 4 4 0;
+#X connect 0 5 18 0;
+#X connect 6 0 0 0;
+#X connect 7 0 0 0;
+#X connect 8 0 0 0;
+#X connect 9 0 0 0;
+#X connect 10 0 0 0;
diff --git a/examples/sf-play_record.pd b/examples/sf-play_record.pd
new file mode 100644
index 0000000..d44b65e
--- /dev/null
+++ b/examples/sf-play_record.pd
@@ -0,0 +1,57 @@
+#N canvas 153 6 588 488 10;
+#X obj 436 382 sfplay 2;
+#X obj 38 385 sfrecord 2;
+#X msg 436 200 help;
+#X obj 436 412 dac~;
+#X msg 436 226 open test.raw l;
+#X msg 436 249 start;
+#X msg 485 249 bang;
+#X msg 525 249 1;
+#X msg 436 272 stop;
+#X msg 525 272 0;
+#X msg 436 321 goto 100;
+#X msg 436 298 rewind;
+#X msg 495 410 done;
+#X obj 495 435 print;
+#X msg 38 201 help;
+#X msg 38 250 start;
+#X msg 38 274 stop;
+#X msg 38 298 close;
+#X msg 38 226 open test.raw l;
+#X msg 38 323 bang;
+#X floatatom 38 411;
+#X text 72 411 status (1-recording / 0-not_recording);
+#X obj 45 361 osc~ 100;
+#X obj 113 361 osc~ 578;
+#X msg 436 347 close;
+#X text 122 47 a little harddisk-recording system;
+#X text 77 324 retrigger status-output;
+#X text 261 224 <name> <endianity>;
+#X text 205 226 open;
+#X text 135 385 sfrecord/sfplay <num. of channels>;
+#X text 53 77 this makes it possible to do multi-track recordings;
+#X text 52 92 up to now \, the "sfrecord" only supports .RAW format;
+#X text 51 107 "sfplay" can skip any header \, if you know it's size:: just call "sfplay <num.of.chan> <skip.bytes>;
+#X connect 0 0 3 0;
+#X connect 0 1 3 1;
+#X connect 0 2 12 0;
+#X connect 1 0 20 0;
+#X connect 2 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 0;
+#X connect 7 0 0 0;
+#X connect 8 0 0 0;
+#X connect 9 0 0 0;
+#X connect 10 0 0 0;
+#X connect 11 0 0 0;
+#X connect 12 0 13 0;
+#X connect 14 0 1 0;
+#X connect 15 0 1 0;
+#X connect 16 0 1 0;
+#X connect 17 0 1 0;
+#X connect 18 0 1 0;
+#X connect 19 0 1 0;
+#X connect 22 0 1 0;
+#X connect 23 0 1 1;
+#X connect 24 0 0 0;
diff --git a/examples/sigbinops+.pd b/examples/sigbinops+.pd
new file mode 100644
index 0000000..3797df9
--- /dev/null
+++ b/examples/sigbinops+.pd
@@ -0,0 +1,106 @@
+#N canvas 470 149 594 490 10;
+#X obj 62 193 abs~;
+#X obj 120 194 sgn~;
+#X obj 262 191 <~;
+#X obj 296 190 ==~;
+#X obj 330 191 >~;
+#X obj 388 190 &&~;
+#X obj 423 190 ||~;
+#X floatatom 423 238;
+#X floatatom 388 238;
+#X floatatom 330 239;
+#X floatatom 296 239;
+#X floatatom 120 242;
+#X floatatom 62 243;
+#X obj 62 221 avg~;
+#X obj 120 220 avg~;
+#X floatatom 262 239;
+#X obj 262 217 avg~;
+#X obj 296 216 avg~;
+#X obj 330 216 avg~;
+#X obj 388 216 avg~;
+#X obj 423 216 avg~;
+#X obj 62 163 sig~;
+#X floatatom 62 141;
+#X obj 330 126 sig~;
+#X floatatom 330 104;
+#X obj 404 126 sig~;
+#X floatatom 404 104;
+#X floatatom 440 448;
+#X floatatom 400 448;
+#X floatatom 349 448;
+#X floatatom 308 449;
+#X floatatom 274 449;
+#X obj 274 427 avg~;
+#X obj 308 426 avg~;
+#X obj 349 425 avg~;
+#X obj 400 426 avg~;
+#X obj 440 426 avg~;
+#X obj 349 337 sig~;
+#X floatatom 349 315;
+#X floatatom 430 316;
+#X obj 274 401 <~ 2;
+#X obj 308 400 ==~ 2;
+#X obj 349 400 >~ 2;
+#X obj 400 400 &&~ 2;
+#X obj 440 400 ||~ 2;
+#X text 83 30 more math and binary operations for signals;
+#X text 28 263 absolute;
+#X text 50 278 value;
+#X text 112 263 signum;
+#X text 249 267 greater;
+#X text 330 268 less;
+#X text 296 284 equal;
+#X text 393 261 logical;
+#X text 386 274 AND;
+#X text 431 274 OR;
+#X text 72 58 (this patch might be very CPU-consupmtious \, because of the float-atoms....);
+#X connect 0 0 13 0;
+#X connect 1 0 14 0;
+#X connect 2 0 16 0;
+#X connect 3 0 17 0;
+#X connect 4 0 18 0;
+#X connect 5 0 19 0;
+#X connect 6 0 20 0;
+#X connect 13 0 12 0;
+#X connect 14 0 11 0;
+#X connect 16 0 15 0;
+#X connect 17 0 10 0;
+#X connect 18 0 9 0;
+#X connect 19 0 8 0;
+#X connect 20 0 7 0;
+#X connect 21 0 0 0;
+#X connect 21 0 1 0;
+#X connect 22 0 21 0;
+#X connect 23 0 2 0;
+#X connect 23 0 3 0;
+#X connect 23 0 4 0;
+#X connect 23 0 5 0;
+#X connect 23 0 6 0;
+#X connect 24 0 23 0;
+#X connect 25 0 6 1;
+#X connect 25 0 5 1;
+#X connect 25 0 4 1;
+#X connect 25 0 3 1;
+#X connect 25 0 2 1;
+#X connect 26 0 25 0;
+#X connect 32 0 31 0;
+#X connect 33 0 30 0;
+#X connect 34 0 29 0;
+#X connect 35 0 28 0;
+#X connect 36 0 27 0;
+#X connect 37 0 40 0;
+#X connect 37 0 41 0;
+#X connect 37 0 42 0;
+#X connect 37 0 43 0;
+#X connect 37 0 44 0;
+#X connect 38 0 37 0;
+#X connect 39 0 43 1;
+#X connect 39 0 42 1;
+#X connect 39 0 41 1;
+#X connect 39 0 40 1;
+#X connect 40 0 32 0;
+#X connect 41 0 33 0;
+#X connect 42 0 34 0;
+#X connect 43 0 35 0;
+#X connect 44 0 36 0;
diff --git a/examples/sigzero~.pd b/examples/sigzero~.pd
new file mode 100644
index 0000000..4b5d09b
--- /dev/null
+++ b/examples/sigzero~.pd
@@ -0,0 +1,50 @@
+#N canvas 0 0 594 494 10;
+#X obj 79 235 sigzero~;
+#X obj 79 187 sig~;
+#X floatatom 79 129;
+#X floatatom 79 262;
+#X obj 117 313 print signal;
+#X obj 117 264 select 0;
+#X msg 117 289 off;
+#X msg 176 288 on;
+#X text 72 42 sigzero~ detects whether there is a signal or not (e.g. zeroes throughout);
+#X obj 74 25 sigzero~;
+#X msg 136 161 bang;
+#X msg 135 185 off;
+#X floatatom 135 208;
+#X text 216 163 turn the detector on;
+#X text 216 188 turn it off;
+#X text 217 210 turn it on/off;
+#X text 114 128 try me;
+#X text 56 368;
+#N canvas 0 0 594 394 sub 0;
+#X obj 152 104 inlet~;
+#X obj 152 155 nop~;
+#X obj 152 210 outlet~;
+#X text 190 157 imagine we were doing some VERY heavy calcs here;
+#X obj 427 48 inlet;
+#X obj 427 75 switch~;
+#X text 35 272 if the heavy calculations done here are done in vain because there is no incoming signal \, it would be better to turn the whole sub-patch off...;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 4 0 5 0;
+#X restore 76 433 page sub;
+#X obj 76 383 adc~ 1;
+#X obj 76 458 dac~ 1;
+#X obj 135 410 sigzero~;
+#X text 213 410 that's how i use it;
+#X connect 0 0 3 0;
+#X connect 0 0 5 0;
+#X connect 1 0 0 0;
+#X connect 2 0 1 0;
+#X connect 5 0 6 0;
+#X connect 5 1 7 0;
+#X connect 6 0 4 0;
+#X connect 7 0 4 0;
+#X connect 10 0 0 0;
+#X connect 11 0 0 0;
+#X connect 12 0 0 0;
+#X connect 18 0 20 0;
+#X connect 19 0 18 0;
+#X connect 19 0 21 0;
+#X connect 21 0 18 1;
diff --git a/examples/sort.pd b/examples/sort.pd
new file mode 100644
index 0000000..97729d3
--- /dev/null
+++ b/examples/sort.pd
@@ -0,0 +1,77 @@
+#N canvas 390 217 721 511 10;
+#X obj 86 231 print UNSORTED;
+#X msg 37 107 bang;
+#X obj 198 23 sort;
+#X text 314 87 any package-elements that are non-float will be interpreted as "0.0".;
+#X text 270 87 note :;
+#X obj 53 329 sort 1;
+#X obj 53 470 print ASCENDING;
+#X obj 37 347 sort -1;
+#X obj 37 487 print DESCENDING;
+#X text 278 297 creation : "sort [<dir>]";
+#X text 457 310 dir < 0 :: descending sort;
+#X text 456 297 dir >= 0 :: ascending sort;
+#X text 460 328 dir defaults to ascending;
+#N canvas 360 175 475 254 randompackage 0;
+#X obj 37 190 pack 0 0 0 0 0 0 0 0 0 0 0;
+#X obj 170 87 random 15;
+#X obj 156 104 random 15;
+#X obj 143 121 random 15;
+#X obj 130 138 random 15;
+#X obj 116 155 random 15;
+#X obj 103 172 random 15;
+#X obj 90 87 random 15;
+#X obj 76 104 random 15;
+#X obj 63 121 random 15;
+#X obj 50 138 random 15;
+#X obj 37 155 random 15;
+#X obj 37 52 inlet;
+#X obj 37 69 t b b b b b b b b b b b;
+#X obj 37 210 outlet;
+#X connect 0 0 14 0;
+#X connect 1 0 0 10;
+#X connect 2 0 0 9;
+#X connect 3 0 0 8;
+#X connect 4 0 0 7;
+#X connect 5 0 0 6;
+#X connect 6 0 0 5;
+#X connect 7 0 0 4;
+#X connect 8 0 0 3;
+#X connect 9 0 0 2;
+#X connect 10 0 0 1;
+#X connect 11 0 0 0;
+#X connect 12 0 13 0;
+#X connect 13 0 11 0;
+#X connect 13 1 10 0;
+#X connect 13 2 9 0;
+#X connect 13 3 8 0;
+#X connect 13 4 7 0;
+#X connect 13 5 6 0;
+#X connect 13 6 5 0;
+#X connect 13 7 4 0;
+#X connect 13 8 3 0;
+#X connect 13 9 2 0;
+#X connect 13 10 1 0;
+#X restore 37 195 pd randompackage;
+#X obj 72 177 print;
+#X msg 72 160 -----;
+#X obj 37 141 t b b;
+#X floatatom 88 293;
+#X text 122 295 direction;
+#X obj 37 213 t l l l l;
+#X obj 69 312 sort;
+#X obj 69 453 print SORTED;
+#X text 237 23 shell-sort a package of floats;
+#X connect 1 0 16 0;
+#X connect 5 0 6 0;
+#X connect 7 0 8 0;
+#X connect 13 0 19 0;
+#X connect 15 0 14 0;
+#X connect 16 0 13 0;
+#X connect 16 1 15 0;
+#X connect 17 0 20 1;
+#X connect 19 0 7 0;
+#X connect 19 1 5 0;
+#X connect 19 2 20 0;
+#X connect 19 3 0 0;
+#X connect 20 0 21 0;
diff --git a/examples/step~.pd b/examples/step~.pd
new file mode 100644
index 0000000..8b85d3d
--- /dev/null
+++ b/examples/step~.pd
@@ -0,0 +1,74 @@
+#N canvas 179 22 564 331 8;
+#X obj 243 283 step~;
+#X obj 243 309 print~;
+#X msg 186 236 bang;
+#X floatatom 283 259;
+#X floatatom 243 237;
+#X obj 186 259 t b b;
+#X obj 243 259 t f b;
+#X text 50 20 step~ ::;
+#X text 50 70 IN1 :;
+#X text 50 110 IN2 :;
+#X text 50 180 note :;
+#X text 100 20 produces a unit:step:sequence or a rectangle:window;
+#X text 100 70 define \, how many samples after the float::bang:message the rectangle:window will start;
+#X text 100 110 define the length of the rectangle:window choosing 1 will produce a dirac:impulse :: unit:sample:sequence) choosing 0 will make the rectangle infinitely long :: unit:step:sequence;
+#X text 100 180 1 sample equals 1:over:samplerate secs;
+#X text 235 217 position;
+#X text 303 239 length;
+#N canvas 169 79 597 397 application 0;
+#X obj 88 188 sig~ 440;
+#X obj 88 211 osc~;
+#X obj 88 235 *~;
+#X obj 149 211 osc~;
+#X obj 149 235 *~;
+#X obj 149 188 sig~ 550;
+#X floatatom 88 163;
+#X floatatom 149 163;
+#X obj 276 189 sig~ -1;
+#X obj 228 189 step~;
+#X msg 258 166 0;
+#X msg 291 166 44100;
+#X floatatom 338 166;
+#X msg 228 142 bang;
+#X obj 149 320 dac~;
+#X obj 149 290 *~;
+#X obj 431 227 dbtorms;
+#X obj 431 249 pack 0 100;
+#X obj 431 271 line~;
+#X floatatom 431 204;
+#X text 193 118 toggle::press;
+#X text 38 23 This \, of course \, is a quite barbarious use of the step~-object;
+#X text 124 51 but it was fast to do and I do think it illustrates the way it works.;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 15 0;
+#X connect 3 0 4 0;
+#X connect 4 0 15 0;
+#X connect 5 0 3 0;
+#X connect 6 0 0 0;
+#X connect 7 0 5 0;
+#X connect 8 0 4 1;
+#X connect 9 0 2 1;
+#X connect 9 0 4 1;
+#X connect 10 0 9 1;
+#X connect 11 0 9 1;
+#X connect 12 0 9 1;
+#X connect 13 0 9 0;
+#X connect 15 0 14 0;
+#X connect 15 0 14 1;
+#X connect 16 0 17 0;
+#X connect 17 0 18 0;
+#X connect 18 0 15 1;
+#X connect 19 0 16 0;
+#X restore 439 186 page application;
+#X msg 186 283 1;
+#X connect 0 0 1 0;
+#X connect 2 0 5 0;
+#X connect 3 0 0 1;
+#X connect 4 0 6 0;
+#X connect 5 0 0 0;
+#X connect 5 1 18 0;
+#X connect 6 0 0 0;
+#X connect 6 1 1 0;
+#X connect 18 0 1 0;
diff --git a/examples/strcmp.pd b/examples/strcmp.pd
new file mode 100644
index 0000000..a2a64ee
--- /dev/null
+++ b/examples/strcmp.pd
@@ -0,0 +1,26 @@
+#N canvas 45 175 628 611 10;
+#X obj 90 54 strcmp;
+#X text 147 54 -- compare 2 lists as if they were strings;
+#X obj 71 398 strcmp this is list # 3;
+#X floatatom 71 423;
+#X obj 96 423 print strcmp;
+#X msg 71 184 list this is list # 3;
+#X msg 71 221 list this is list # 4;
+#X msg 71 239 1 2 3 4 5;
+#X msg 71 256 list yet another list;
+#X floatatom 83 286;
+#X msg 204 313 list yet another list;
+#X msg 222 366 list \$1;
+#X floatatom 222 349;
+#X text 278 357 to compare symbols/floats you have to make sure that they go to the 2nd inlet as lists;
+#X text 98 442 the output follows the "strcmp" of the C programming language;
+#X connect 2 0 4 0;
+#X connect 2 0 3 0;
+#X connect 5 0 2 0;
+#X connect 6 0 2 0;
+#X connect 7 0 2 0;
+#X connect 8 0 2 0;
+#X connect 9 0 2 0;
+#X connect 10 0 2 1;
+#X connect 11 0 2 1;
+#X connect 12 0 11 0;
diff --git a/examples/swap~.pd b/examples/swap~.pd
new file mode 100644
index 0000000..599811e
--- /dev/null
+++ b/examples/swap~.pd
@@ -0,0 +1,39 @@
+#N canvas 0 -1 718 576 10;
+#X obj 97 321 swap~;
+#X text 138 102 this object first converts the signal to 16bit \, then swaps upper and lower byte.;
+#X msg 120 233 0;
+#X msg 120 209 1;
+#X msg 119 258 bang;
+#X obj 33 288 osc~ 440;
+#X floatatom 33 264;
+#X msg 119 283 help;
+#X obj 81 401 *~;
+#X obj 43 352 dbtorms;
+#X floatatom 43 328;
+#X msg 445 28 \; pd dsp 1;
+#X obj 81 376 sig~ 0.2;
+#X msg 520 28 \; pd dsp 0;
+#X graph graph5 0 -1 100 1 298 494 698 194;
+#X array scope 100 float;
+#X pop;
+#X obj 176 426 tabwrite~ scope;
+#X msg 176 401 bang;
+#X text 159 258 toggle;
+#X text 152 208 on;
+#X text 154 232 off;
+#X obj 87 27 swap~;
+#X text 149 25 byte-swap a 16bit signal;
+#X obj 81 425 dac~ 1;
+#X connect 0 0 8 1;
+#X connect 0 0 15 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 5 0;
+#X connect 7 0 0 0;
+#X connect 8 0 22 0;
+#X connect 9 0 12 0;
+#X connect 10 0 9 0;
+#X connect 12 0 8 0;
+#X connect 16 0 15 0;
diff --git a/examples/tabdump.pd b/examples/tabdump.pd
new file mode 100644
index 0000000..e9379bd
--- /dev/null
+++ b/examples/tabdump.pd
@@ -0,0 +1,19 @@
+#N canvas 178 229 861 353 10;
+#X graph graph2 0 -1 8 1 603 257 803 117;
+#X array my_array66 5 float;
+#X array my_array77 8 float;
+#X pop;
+#X obj 283 138 loadbang;
+#X obj 83 168 tabdump my_array66;
+#X msg 83 100 bang;
+#X obj 83 193 print;
+#X msg 133 148 set my_array77;
+#X msg 283 164 \; my_array66 resize 5 \; my_array77 resize 8 \; my_array66 0.1 0.3 0.2 0.5 0.2 -0.1 \; my_array77 0.1 0.1 0.2 0.3 0.5 0.8 0.13 0.21 0.34;
+#X obj 176 22 tabdump;
+#X text 273 24 dump the contents of a table as a list;
+#X msg 132 126 set my_array66;
+#X connect 1 0 6 0;
+#X connect 2 0 4 0;
+#X connect 3 0 2 0;
+#X connect 5 0 2 0;
+#X connect 9 0 2 0;
diff --git a/examples/tabread4.pd b/examples/tabread4.pd
new file mode 100644
index 0000000..8fff4e5
--- /dev/null
+++ b/examples/tabread4.pd
@@ -0,0 +1,29 @@
+#N canvas 0 0 884 549 8;
+#X obj 85 45 tabread4;
+#X text 87 96 "tabread4" is missing in the pd-distribution \, and i really don't know why \, because sometimes one might need it...;
+#X text 89 132 so here it is;
+#X msg 495 140 \; readout 1 \; array99 resize 10 \; array99 bounds 0 0 10 10 \; array99 xlabel -0.5 0 1 2 3 4 5 6 7 8 9 10 \; array99 ylabel -1 0 1 2 3 4 5 6 7 8 9 10 \; array99 0 1 4 2 8 5 6 1 4 2 8;
+#X floatatom 204 185;
+#X floatatom 204 351;
+#X text 242 369 output = array99[index];
+#X text 323 303 creation argument;
+#X text 323 318 gives array name;
+#X msg 214 277 set array99;
+#X text 303 278 change array name;
+#X obj 204 317 tabread4 array99;
+#X graph graph1 0 0 10 10 504 467 754 267;
+#X array array99 10 float;
+#X pop;
+#X obj 94 317 tabread array99;
+#X floatatom 94 356;
+#X text -7 335 this is how it was;
+#X msg 214 255 help;
+#X text 235 184 index (try non-integer :: 1.5);
+#X obj 495 119 loadbang;
+#X connect 4 0 11 0;
+#X connect 4 0 13 0;
+#X connect 9 0 11 0;
+#X connect 11 0 5 0;
+#X connect 13 0 14 0;
+#X connect 16 0 11 0;
+#X connect 18 0 3 0;
diff --git a/examples/tabset.pd b/examples/tabset.pd
new file mode 100644
index 0000000..28bfb68
--- /dev/null
+++ b/examples/tabset.pd
@@ -0,0 +1,19 @@
+#N canvas 140 193 861 353 10;
+#X graph graph2 0 -1 8 1 603 257 803 117;
+#X array my_array99 5 float;
+#X array my_array97 8 float;
+#X pop;
+#X obj 283 138 loadbang;
+#X msg 132 126 set my_array99;
+#X msg 133 148 set my_array97;
+#X msg 283 164 \; my_array99 resize 5 \; my_array97 resize 8 \; my_array99 0.1 0.3 0.2 0.5 0.2 -0.1 \; my_array97 0.1 0.1 0.2 0.3 0.5 0.8 0.13 0.21 0.34;
+#X obj 176 22 tabdump;
+#X text 273 24 dump the contents of a table as a list;
+#X msg 83 73 1 0.7 0.5 0.3 0.2 0.1;
+#X obj 83 168 tabset my_array99;
+#X floatatom 97 95 4 0 0;
+#X connect 1 0 4 0;
+#X connect 2 0 8 0;
+#X connect 3 0 8 0;
+#X connect 7 0 8 0;
+#X connect 9 0 8 0;
diff --git a/examples/tavg~.pd b/examples/tavg~.pd
new file mode 100644
index 0000000..03c7b20
--- /dev/null
+++ b/examples/tavg~.pd
@@ -0,0 +1,28 @@
+#N canvas 288 18 580 361 10;
+#X floatatom 59 148;
+#X floatatom 59 254;
+#X floatatom 129 255;
+#X obj 59 276 dbtorms;
+#X floatatom 59 299;
+#X text 272 269 see also:;
+#X obj 277 296 env~;
+#X obj 59 233 env~;
+#X obj 315 296 envrms~;
+#X obj 59 173 osc~ 5512.5;
+#X obj 373 296 avg~;
+#X obj 129 234 tavg~;
+#X obj 71 51 tavg~;
+#X text 130 51 calculates the arithmetic mean of a signal between 2 bangs;
+#X obj 176 195 metro 1000;
+#X msg 176 167 bang;
+#X msg 211 167 stop;
+#X connect 0 0 9 0;
+#X connect 1 0 3 0;
+#X connect 3 0 4 0;
+#X connect 7 0 1 0;
+#X connect 9 0 7 0;
+#X connect 9 0 11 0;
+#X connect 11 0 2 0;
+#X connect 14 0 11 0;
+#X connect 15 0 14 0;
+#X connect 16 0 14 0;
diff --git a/examples/time.pd b/examples/time.pd
new file mode 100644
index 0000000..e179e13
--- /dev/null
+++ b/examples/time.pd
@@ -0,0 +1,31 @@
+#N canvas 253 26 421 378 10;
+#X msg 71 174 bang;
+#X floatatom 86 261;
+#X floatatom 78 284;
+#X floatatom 71 307;
+#X obj 71 203 time;
+#X floatatom 94 238;
+#X text 151 241 msec;
+#X text 152 263 sec;
+#X text 153 284 min;
+#X text 152 306 hours;
+#X msg 219 175 bang;
+#X floatatom 253 259;
+#X floatatom 236 284;
+#X floatatom 219 308;
+#X floatatom 270 234;
+#X obj 219 204 time GMT;
+#X text 91 79 get the system time;
+#X text 64 149 local;
+#X text 222 152 GMT;
+#X obj 73 27 time;
+#X connect 0 0 4 0;
+#X connect 4 0 3 0;
+#X connect 4 1 2 0;
+#X connect 4 2 1 0;
+#X connect 4 3 5 0;
+#X connect 10 0 15 0;
+#X connect 15 0 13 0;
+#X connect 15 1 12 0;
+#X connect 15 2 11 0;
+#X connect 15 3 14 0;
diff --git a/examples/unpack~.pd b/examples/unpack~.pd
new file mode 100644
index 0000000..c8cee41
--- /dev/null
+++ b/examples/unpack~.pd
@@ -0,0 +1,59 @@
+#N canvas 299 436 736 292 10;
+#X text 460 14 see also;
+#X obj 461 33 pack~;
+#X text 147 40 unpack~;
+#X text 178 65 convert float-packages to signals;
+#X obj 85 132 unpack~ 512;
+#X text 234 156 creation: "unpack~ [<bufsize>]";
+#X text 255 181 <bufsize>: in samples (defaults to 64) \; could be fine if you don't have a constant stream of floats;
+#N canvas 94 221 839 437 example 0;
+#X obj 69 75 osc~ 689.062;
+#X obj 69 123 pack~;
+#X obj 69 94 *~ 0.2;
+#X obj 69 142 unfold;
+#X obj 69 160 t b f;
+#X obj 69 178 +;
+#X obj 69 198 + 1;
+#X obj 69 236 select 0;
+#X obj 69 256 f;
+#X obj 69 332 unpack~;
+#X floatatom 69 50;
+#X obj 69 218 % 8;
+#X text 74 6 a simple samplerate-reducer;
+#X text 116 129 samplerate = 44.1kHz;
+#X text 126 258 samplerate = 5.5125kHz;
+#X text 108 363 reconstructed signal @ 44.1kHz;
+#X obj 127 114 dac~ 2;
+#X obj 69 387 dac~ 1;
+#X msg 69 276 \$1 \$1 \$1 \$1 \$1 \$1 \$1 \$1;
+#X graph graph2 0 -1 64 1 526 213 826 13;
+#X array high_rate 100 float;
+#X pop;
+#X graph graph3 0 -1 64 1 526 441 826 241;
+#X array low_rate 100 float;
+#X pop;
+#X obj 170 113 tabsend~ high_rate;
+#X obj 114 388 tabsend~ low_rate;
+#X msg 349 240 \; pd dsp 0;
+#X msg 349 179 \; pd dsp 1;
+#X obj 349 221 loadbang;
+#X connect 0 0 2 0;
+#X connect 1 0 3 0;
+#X connect 2 0 1 0;
+#X connect 2 0 16 0;
+#X connect 2 0 21 0;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 4 1 8 1;
+#X connect 5 0 6 0;
+#X connect 6 0 11 0;
+#X connect 7 0 8 0;
+#X connect 8 0 18 0;
+#X connect 9 0 17 0;
+#X connect 9 0 22 0;
+#X connect 10 0 0 0;
+#X connect 11 0 5 1;
+#X connect 11 0 7 0;
+#X connect 18 0 9 0;
+#X connect 25 0 23 0;
+#X restore 85 249 pd example;
diff --git a/examples/z~.pd b/examples/z~.pd
new file mode 100644
index 0000000..49e5560
--- /dev/null
+++ b/examples/z~.pd
@@ -0,0 +1,28 @@
+#N canvas 267 156 597 497 8;
+#X obj 125 42 z~;
+#X text 177 41 samplewise delay;
+#X text 168 89 should make FIR-filter design possible;
+#X obj 65 222 osc~ 440;
+#X floatatom 65 191;
+#X obj 97 270 z~;
+#X obj 127 270 z~ 2;
+#X obj 167 270 z~ 3;
+#X obj 65 310 +~;
+#X obj 65 336 * 0.25;
+#X obj 65 366 dac~;
+#X text 235 269 4th order moving average filter;
+#X text 185 324 creation argument : delay in samples (default is 1);
+#X text 167 119 (note that you cannot do IIR-filters easily this way !);
+#X text 351 42 z;
+#X text 359 36 -N;
+#X connect 3 0 8 0;
+#X connect 3 0 5 0;
+#X connect 3 0 6 0;
+#X connect 3 0 7 0;
+#X connect 4 0 3 0;
+#X connect 5 0 8 0;
+#X connect 6 0 8 0;
+#X connect 7 0 8 0;
+#X connect 8 0 9 0;
+#X connect 9 0 10 0;
+#X connect 9 0 10 1;
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
diff --git a/z_install.bat b/z_install.bat
new file mode 100644
index 0000000..52c3a86
--- /dev/null
+++ b/z_install.bat
@@ -0,0 +1,9 @@
+@echo off
+echo installing zexy on your system
+mkdir ..\externs
+copy zexy.dll ..\externs
+echo copying help files
+mkdir ..\doc\5.reference\zexy
+copy examples\* ..\doc\5.reference\zexy
+echo done
+echo on
diff --git a/zexy.pd b/zexy.pd
new file mode 100644
index 0000000..7114d02
--- /dev/null
+++ b/zexy.pd
@@ -0,0 +1,303 @@
+#N canvas 236 146 761 706 10;
+#X obj 101 83 zexy;
+#X msg 101 59 help;
+#X text 430 82 bug-reports: zmoelnig@iem.kug.ac.at;
+#X text 428 66 (c) forum::für::umlute 1999-2001;
+#N canvas 259 142 708 221 io~ 0;
+#X obj 41 184 sfplay;
+#X obj 137 185 sfrecord;
+#X msg 41 162 help;
+#X msg 137 163 help;
+#X text 297 186 harddisk-recording tools;
+#X text 144 19 input~/output~ objects;
+#X connect 2 0 0 0;
+#X connect 3 0 1 0;
+#X restore 74 187 pd io~;
+#N canvas 320 195 583 254 generators~ 0;
+#X obj 125 173 noisi~;
+#X msg 125 151 help;
+#X msg 29 149 help;
+#X msg 125 103 help;
+#X msg 29 101 help;
+#X obj 29 171 noish~;
+#X obj 29 123 dirac~;
+#X obj 125 125 step~;
+#X text 296 174 bandlimited noise~ generators;
+#X text 290 127 scientific test-functions;
+#X text 152 26 generator~ objects;
+#X connect 1 0 0 0;
+#X connect 2 0 5 0;
+#X connect 3 0 7 0;
+#X connect 4 0 6 0;
+#X restore 74 212 pd generators~;
+#N canvas 362 224 638 326 processing~ 0;
+#X obj 52 93 limiter~;
+#X obj 51 143 quantize~;
+#X obj 52 193 swap~;
+#X msg 51 121 help;
+#X msg 52 71 help;
+#X msg 52 171 help;
+#X text 280 92 a limiter/compressor module;
+#X text 121 16 signal~processing objects;
+#X text 280 131 quantizes signals by various degrees;
+#X text 281 186 byte-swapps a 16bit signal;
+#X obj 55 254 z~;
+#X msg 55 231 help;
+#X text 245 228 a samplewise delay \, great for designing FIR-filters;
+#X text 253 247 (you cannot use it for IIR-filters !);
+#X connect 3 0 1 0;
+#X connect 4 0 0 0;
+#X connect 5 0 2 0;
+#X connect 11 0 10 0;
+#X restore 74 236 pd processing~;
+#N canvas 319 68 585 573 analytic~ 0;
+#X obj 26 173 sigzero~;
+#X msg 26 151 help;
+#X text 164 171 detects whether a signal-block is zero throughout or not;
+#X obj 25 236 pdf~;
+#X msg 25 213 help;
+#X text 165 237 get the probability density function of a signal;
+#X text 130 48 signal~analyzing objectsd;
+#X obj 27 303 envrms~;
+#X obj 28 356 avg~;
+#X obj 29 407 tavg~;
+#X msg 27 282 help;
+#X msg 28 335 help;
+#X msg 29 386 help;
+#X text 158 300 the same as env~ \, except that this outputs rms instead of dB;
+#X text 158 356 arithmetic mean of one signal~vector;
+#X text 161 407 arithmetic mean between two bangs;
+#X msg 31 448 help;
+#X obj 31 469 dfreq~;
+#X text 164 469 frequency detector;
+#X connect 1 0 0 0;
+#X connect 4 0 3 0;
+#X connect 10 0 7 0;
+#X connect 11 0 8 0;
+#X connect 12 0 9 0;
+#X connect 16 0 17 0;
+#X restore 74 261 pd analytic~;
+#N canvas 299 114 664 548 others~ 0;
+#X obj 31 70 nop~;
+#X msg 31 48 help;
+#X text 246 63 do_nothing but delay for one-block (useful for synchronising);
+#X text 175 11 miscanellous signal~ objects;
+#X msg 31 127 help;
+#X obj 31 149 pack~;
+#X msg 77 128 help;
+#X obj 77 150 unpack~;
+#X text 245 138 convert a signal to (packages of) floats and vice-versa;
+#X obj 31 257 matrix~;
+#X msg 31 236 help;
+#X msg 31 350 help;
+#X msg 32 394 help;
+#X obj 31 371 multiplex~;
+#X obj 32 415 demultiplex~;
+#X msg 109 350 help;
+#X msg 110 394 help;
+#X obj 109 371 mux~;
+#X obj 110 416 demux~;
+#X text 240 237 matrix-multiply m IN~signals to n OUT~signals;
+#X text 240 250 matrices are interpolated a la line~;
+#X text 245 416 multiplex 1 IN~signal to 1-of-n OUT~signals;
+#X text 246 369 multiplex 1-of-n IN~signals to 1 OUT~signal;
+#X msg 31 297 help;
+#X obj 31 319 multiline~;
+#X text 239 316 a line~d multiplication for multiple streams;
+#X connect 1 0 0 0;
+#X connect 4 0 5 0;
+#X connect 6 0 7 0;
+#X connect 10 0 9 0;
+#X connect 11 0 13 0;
+#X connect 12 0 14 0;
+#X connect 15 0 17 0;
+#X connect 16 0 18 0;
+#X connect 23 0 24 0;
+#X restore 74 332 pd others~;
+#X text 289 183 alternative i/o-devices (harddisk \, net \, ...);
+#X text 288 207 useful signal generators;
+#X text 291 231 process your own signals;
+#X text 290 257 and analyze them;
+#X text 290 328 none of the above;
+#N canvas 0 0 591 430 sigbinops~ 0;
+#X obj 81 96 >~;
+#X obj 81 129 <~;
+#X obj 81 162 ==~;
+#X obj 81 244 &&~;
+#X obj 81 277 ||~;
+#X text 159 95 greater;
+#X text 158 131 less;
+#X text 157 165 equal;
+#X text 156 246 logical AND;
+#X text 154 278 logical OR;
+#X obj 80 347 abs~;
+#X obj 80 375 sgn~;
+#X text 158 348 absolute value (I think this is included at GEM too);
+#X text 158 375 sign of a function;
+#X text 148 32 binary and math operators for signals~;
+#X restore 74 286 pd sigbinops~;
+#X text 289 284 some mathematical and logical functions that were missing;
+#N canvas 345 88 652 713 basic 0;
+#X obj 41 28 nop;
+#X text 222 28 a do nothing - pass through everything;
+#X obj 41 85 lister;
+#X obj 98 86 l;
+#X text 216 87 store a list (like "float" \, "int" \, ...);
+#X text 83 86 ==;
+#X obj 40 184 repack;
+#X text 211 182 (re)packs atoms to packages of a given size;
+#X obj 40 215 packel;
+#X text 209 212 the specified element of a list;
+#X obj 39 256 niagara;
+#X text 214 255 split 1 package into 2 at a specifique point;
+#X obj 43 464 segregate;
+#X text 210 463 segregates the input to various outputs depending on the type;
+#X text 210 117 convert anythings to lists;
+#X obj 53 626 matrix;
+#X text 211 626 store/create/... matrices;
+#X obj 39 336 list2int;
+#X text 94 337 ==;
+#X obj 112 337 l2i;
+#X text 207 339 cast each float of a list/anything to an integer;
+#X obj 41 115 any2list;
+#X text 98 117 ==;
+#X obj 116 117 a2l;
+#X obj 41 375 atoi;
+#X text 209 373 ascii to integer;
+#X obj 39 155 length;
+#X text 210 154 get the length of a list;
+#X obj 41 291 glue;
+#X text 216 285 append a list to another;
+#X obj 42 409 list2symbol;
+#X text 114 412 ==;
+#X obj 129 411 l2s;
+#X text 207 410 convert a list into a single symbol;
+#X restore 72 416 pd basic control;
+#N canvas 401 27 602 871 advanced 0;
+#X obj 29 58 tabread4 table;
+#X obj 28 189 makesymbol;
+#X msg 28 167 help;
+#X msg 29 39 help;
+#X text 205 56 read out a table doing 4point-interpolation;
+#X text 202 189 concatenate lists to formatted symbols;
+#X msg 28 214 help;
+#X obj 28 236 date;
+#X msg 67 214 help;
+#X obj 67 236 time;
+#X text 201 233 get the current system date/time;
+#X obj 28 289 index;
+#X msg 28 264 help;
+#X text 202 286 map symbols to indices;
+#X text 163 565 (no "help"-message available...);
+#X obj 28 643 demultiplex;
+#X obj 114 643 demux;
+#X text 99 644 ==;
+#X text 199 644 demultiplex the inlet to a specified outlet;
+#X obj 76 696 unfold;
+#X obj 28 695 drip;
+#X text 58 696 ==;
+#X text 201 694 extract the atoms of a package (opt. scheduled);
+#X obj 28 745 sort;
+#X text 204 748 shell-sort a package of floats;
+#X msg 28 338 help;
+#X obj 28 362 msgfile;
+#X text 197 360 a powerful "textfile" derivative;
+#X obj 28 423 mavg;
+#X msg 28 403 help;
+#X text 200 427 a moving average filter;
+#X msg 29 76 help;
+#X obj 29 95 tabdump table;
+#X text 205 93 dump a table as a list of floats;
+#X obj 27 466 mean;
+#X msg 27 447 help;
+#X msg 26 487 help;
+#X obj 26 506 minmax;
+#X text 195 463 get the mean value of a list of floats (==vector);
+#X text 194 503 get the minimum and the maximum of a vector;
+#X obj 29 613 .;
+#X text 199 615 scalar multiplication of 2 vectors;
+#X msg 30 115 help;
+#X obj 30 134 tabset table;
+#X text 206 132 set a table with a list of floats;
+#X obj 28 809 lp;
+#X text 199 805 write data to the (parallel) port (linux only);
+#X connect 2 0 1 0;
+#X connect 3 0 0 0;
+#X connect 6 0 7 0;
+#X connect 8 0 9 0;
+#X connect 12 0 11 0;
+#X connect 25 0 26 0;
+#X connect 29 0 28 0;
+#X connect 31 0 32 0;
+#X connect 35 0 34 0;
+#X connect 36 0 37 0;
+#X connect 42 0 43 0;
+#X restore 71 446 pd advanced control;
+#X text 283 442 some more complex control objects (systime \, tabread4 \, ...);
+#X text 282 416 some useful control objects (nop...);
+#N canvas 201 65 784 833 matrix 0;
+#X obj 74 10 matrix;
+#X obj 123 10 mtx;
+#X text 188 10 create/store/... matrices;
+#X obj 75 128 mtx_eye;
+#X obj 75 169 mtx_ones;
+#X obj 75 193 mtx_zeros;
+#X obj 75 213 mtx_diag;
+#X obj 74 262 mtx_trace;
+#X obj 69 557 mtx_mul;
+#X obj 142 558 mtx_*;
+#X obj 68 584 mtx_mul 0;
+#X obj 141 586 mtx_* 0;
+#X obj 194 586 mtx_.* 0;
+#X obj 68 609 mtx_.*;
+#X obj 70 494 mtx_add;
+#X obj 143 495 mtx_+;
+#X obj 70 516 mtx_add 0;
+#X obj 143 517 mtx_+ 0;
+#X obj 74 288 mtx_transpose;
+#X obj 65 707 mtx_check;
+#X obj 65 736 mtx_print;
+#X text 281 121 identity matrix;
+#X text 286 162 matrix (all elements == 1);
+#X text 286 185 matrix (all elements == 0);
+#X text 282 205 create diagonal matrix out of the diagonal-vector;
+#X text 282 216 return the diagonal-vector of a matrix;
+#X text 281 256 return the trace of a matrix;
+#X text 280 296 transpose a matrix;
+#X text 281 489 add two matrices;
+#X text 280 513 add a scalar two a matrix;
+#X text 293 556 mutiply two matrices;
+#X text 292 580 multiply a matrix with a scalar;
+#X text 290 609 mutiply two matrices alement by element;
+#X text 286 702 check the consistency of a matrix and regenerate it;
+#X text 282 734 print a matrix to the stderr;
+#X obj 74 40 mtx_element;
+#X obj 74 63 mtx_row;
+#X obj 74 86 mtx_col;
+#X obj 74 400 mtx_resize;
+#X obj 73 422 mtx_size;
+#X text 284 421 get the size of a matrix;
+#X text 283 403 resize a matrix;
+#X text 287 38 set elements of a matrix;
+#X text 286 61 set rows of a matrix;
+#X text 285 87 set columns of a matrix;
+#X obj 66 644 mtx_mean;
+#X obj 65 671 mtx_rand;
+#X text 290 642 get the mean value of each column;
+#X text 287 670 fill a matrix with random values;
+#X obj 75 149 mtx_egg;
+#X text 285 145 identity matrix with rectangular diagonale;
+#X obj 75 233 mtx_diegg;
+#X text 281 233 like mtx_diag \, but with the diagonale flipped for 90deg;
+#X obj 71 455 mtx_inverse;
+#X text 277 452 calculate the inverse of a matrix;
+#X obj 73 311 mtx_scroll;
+#X text 280 316 shift the rows of a matrix;
+#X obj 73 330 mtx_roll;
+#X text 280 335 shift the column of a matrix;
+#X obj 72 363 mtx_pivot;
+#X text 281 359 pivot-transform a matrix;
+#X restore 69 500 pd matrix control;
+#X text 284 497 some objects to work with matrices;
+#X text 228 7 the zexy external v1.0;
+#X connect 1 0 0 0;