aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans-Christoph Steiner <eighthave@users.sourceforge.net>2007-07-09 20:45:58 +0000
committerHans-Christoph Steiner <eighthave@users.sourceforge.net>2007-07-09 20:45:58 +0000
commit17ec1deb74e2e934dc11fb4d9a2f8c6cef34c5a7 (patch)
treece721cdc62bab6b69dbd023abfc3075d2609f64c
This commit was generated by cvs2svn to compensate for changes in r7949,svn2git-root
which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/moonlib/; revision=7950
-rw-r--r--.directory47
-rw-r--r--Makefile18
-rw-r--r--README.txt113
-rw-r--r--XFS.txt1
-rw-r--r--absolutepath.c140
-rw-r--r--basedir.c72
-rw-r--r--char2f.c53
-rw-r--r--comma.c53
-rw-r--r--dinlet~.c136
-rw-r--r--dispatch.c194
-rw-r--r--dripchar.c82
-rw-r--r--f2char.c53
-rw-r--r--gamme.c558
-rw-r--r--help/absolutepath-help.pd13
-rw-r--r--help/basedir-help.pd18
-rw-r--r--help/char2f-help.pd18
-rw-r--r--help/comma-help.pd40
-rw-r--r--help/d/d0.gifbin0 -> 231 bytes
-rw-r--r--help/d/d1.gifbin0 -> 232 bytes
-rw-r--r--help/d/d10.gifbin0 -> 239 bytes
-rw-r--r--help/d/d11.gifbin0 -> 238 bytes
-rw-r--r--help/d/d12.gifbin0 -> 236 bytes
-rw-r--r--help/d/d13.gifbin0 -> 237 bytes
-rw-r--r--help/d/d14.gifbin0 -> 237 bytes
-rw-r--r--help/d/d15.gifbin0 -> 239 bytes
-rw-r--r--help/d/d16.gifbin0 -> 238 bytes
-rw-r--r--help/d/d17.gifbin0 -> 234 bytes
-rw-r--r--help/d/d18.gifbin0 -> 232 bytes
-rw-r--r--help/d/d19.gifbin0 -> 239 bytes
-rw-r--r--help/d/d2.gifbin0 -> 237 bytes
-rw-r--r--help/d/d20.gifbin0 -> 240 bytes
-rw-r--r--help/d/d21.gifbin0 -> 236 bytes
-rw-r--r--help/d/d22.gifbin0 -> 236 bytes
-rw-r--r--help/d/d23.gifbin0 -> 236 bytes
-rw-r--r--help/d/d24.gifbin0 -> 236 bytes
-rw-r--r--help/d/d25.gifbin0 -> 234 bytes
-rw-r--r--help/d/d26.gifbin0 -> 234 bytes
-rw-r--r--help/d/d27.gifbin0 -> 236 bytes
-rw-r--r--help/d/d28.gifbin0 -> 235 bytes
-rw-r--r--help/d/d29.gifbin0 -> 234 bytes
-rw-r--r--help/d/d3.gifbin0 -> 234 bytes
-rw-r--r--help/d/d30.gifbin0 -> 233 bytes
-rw-r--r--help/d/d31.gifbin0 -> 233 bytes
-rw-r--r--help/d/d32.gifbin0 -> 238 bytes
-rw-r--r--help/d/d33.gifbin0 -> 233 bytes
-rw-r--r--help/d/d34.gifbin0 -> 236 bytes
-rw-r--r--help/d/d35.gifbin0 -> 233 bytes
-rw-r--r--help/d/d36.gifbin0 -> 235 bytes
-rw-r--r--help/d/d37.gifbin0 -> 236 bytes
-rw-r--r--help/d/d38.gifbin0 -> 237 bytes
-rw-r--r--help/d/d39.gifbin0 -> 236 bytes
-rw-r--r--help/d/d4.gifbin0 -> 231 bytes
-rw-r--r--help/d/d40.gifbin0 -> 237 bytes
-rw-r--r--help/d/d41.gifbin0 -> 235 bytes
-rw-r--r--help/d/d42.gifbin0 -> 238 bytes
-rw-r--r--help/d/d43.gifbin0 -> 236 bytes
-rw-r--r--help/d/d44.gifbin0 -> 230 bytes
-rw-r--r--help/d/d45.gifbin0 -> 235 bytes
-rw-r--r--help/d/d46.gifbin0 -> 236 bytes
-rw-r--r--help/d/d47.gifbin0 -> 235 bytes
-rw-r--r--help/d/d48.gifbin0 -> 240 bytes
-rw-r--r--help/d/d49.gifbin0 -> 236 bytes
-rw-r--r--help/d/d5.gifbin0 -> 238 bytes
-rw-r--r--help/d/d50.gifbin0 -> 237 bytes
-rw-r--r--help/d/d51.gifbin0 -> 236 bytes
-rw-r--r--help/d/d52.gifbin0 -> 234 bytes
-rw-r--r--help/d/d53.gifbin0 -> 239 bytes
-rw-r--r--help/d/d54.gifbin0 -> 238 bytes
-rw-r--r--help/d/d55.gifbin0 -> 240 bytes
-rw-r--r--help/d/d56.gifbin0 -> 235 bytes
-rw-r--r--help/d/d57.gifbin0 -> 236 bytes
-rw-r--r--help/d/d58.gifbin0 -> 236 bytes
-rw-r--r--help/d/d59.gifbin0 -> 236 bytes
-rw-r--r--help/d/d6.gifbin0 -> 236 bytes
-rw-r--r--help/d/d60.gifbin0 -> 235 bytes
-rw-r--r--help/d/d61.gifbin0 -> 236 bytes
-rw-r--r--help/d/d62.gifbin0 -> 235 bytes
-rw-r--r--help/d/d63.gifbin0 -> 229 bytes
-rw-r--r--help/d/d7.gifbin0 -> 237 bytes
-rw-r--r--help/d/d8.gifbin0 -> 240 bytes
-rw-r--r--help/d/d9.gifbin0 -> 237 bytes
-rw-r--r--help/dinlet~-help.pd37
-rw-r--r--help/dispatch-help.pd65
-rw-r--r--help/dripchar-help.pd28
-rw-r--r--help/f2char-help.pd18
-rw-r--r--help/f2s-help.pd17
-rw-r--r--help/gamme-help.pd171
-rw-r--r--help/image-help.pd104
-rw-r--r--help/joystik-help.pd44
-rw-r--r--help/makecolor-help.pd18
-rw-r--r--help/mknob-help.pd53
-rw-r--r--help/panvol~-help.pd34
-rw-r--r--help/pause.gifbin0 -> 61 bytes
-rw-r--r--help/play.gifbin0 -> 58 bytes
-rw-r--r--help/playy.gifbin0 -> 58 bytes
-rw-r--r--help/popen-help.pd68
-rw-r--r--help/readsfv~-help.pd60
-rw-r--r--help/rec.gifbin0 -> 58 bytes
-rw-r--r--help/relativepath-help.pd13
-rw-r--r--help/s2f-help.pd18
-rw-r--r--help/sarray-help.pd93
-rw-r--r--help/saww.gifbin0 -> 61 bytes
-rw-r--r--help/sfread2~-help.pd60
-rw-r--r--help/sin.gifbin0 -> 58 bytes
-rw-r--r--help/sinw.gifbin0 -> 61 bytes
-rw-r--r--help/slist-help.pd61
-rw-r--r--help/squarew.gifbin0 -> 61 bytes
-rw-r--r--help/ssaw~-help.pd21
-rw-r--r--help/tabdump2-help.pd31
-rw-r--r--help/tabenv-help.pd25
-rw-r--r--help/tabreadl-help.pd26
-rw-r--r--help/tabsort-help.pd32
-rw-r--r--help/tabsort2-help.pd84
-rw-r--r--image.c306
-rw-r--r--joystik.c191
-rw-r--r--mknob.c870
-rw-r--r--panvol~.c119
-rw-r--r--popen.c211
-rw-r--r--readsfv~.c1683
-rw-r--r--relativepath.c146
-rw-r--r--s2f.c53
-rw-r--r--sarray.c264
-rw-r--r--sfread2~.c410
-rw-r--r--slist.c233
-rw-r--r--ssaw~.c213
-rw-r--r--tabdump2.c120
-rw-r--r--tabenv.c294
-rw-r--r--tabreadl.c84
-rw-r--r--tabsort.c124
-rw-r--r--tabsort2.c164
-rw-r--r--wac.c253
131 files changed, 8528 insertions, 0 deletions
diff --git a/.directory b/.directory
new file mode 100644
index 0000000..30a00cb
--- /dev/null
+++ b/.directory
@@ -0,0 +1,47 @@
+[IconPosition::README]
+X=456
+Y=60
+
+[IconPosition::docs]
+X=28
+Y=5
+
+[IconPosition::externs]
+X=113
+Y=5
+
+[IconPosition::externs0.37]
+X=190
+Y=5
+
+[IconPosition::makefile]
+X=287
+Y=60
+
+[IconPosition::nilib_0.1.0]
+X=281
+Y=5
+
+[IconPosition::nilib_0.2.0]
+X=368
+Y=5
+
+[IconPosition::others_0.2]
+X=453
+Y=5
+
+[IconPosition::paths.txt]
+X=370
+Y=60
+
+[IconPosition::sublib_0.1.0]
+X=16
+Y=60
+
+[IconPosition::sublib_0.2.0]
+X=103
+Y=60
+
+[IconPosition::sublib_0.3.0]
+X=190
+Y=60
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..ae29994
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,18 @@
+TARGET := $(shell pwd | sed 's|.*/\(.*\)$$|\1|')
+EXTERNALS_ROOT := $(shell pwd | sed 's|^\(/.*externals\).*|\1|')
+
+default:
+ make -C $(EXTERNALS_ROOT) $(TARGET)
+
+install:
+ make -C $(EXTERNALS_ROOT) $(TARGET)_install
+
+clean:
+ make -C $(EXTERNALS_ROOT) $(TARGET)_clean
+
+test_locations:
+ make -C $(EXTERNALS_ROOT) test_locations
+
+etags:
+ etags *.[ch] $(EXTERNALS_ROOT)/../pd/src/*.[ch] /usr/include/*.h \
+ /usr/include/*/*.h
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..e4e5d5a
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,113 @@
+Here are the libs I've written for Pd.
+They can be splitted in three parts:
+
+ 1. the nilib library, which is a kind of wrapper between Pd and Gtk, and its
+ objects:
+ nifs (a one-click file selector, with some special tricks...), niscope (a
+ simple oscilloscope), and nileon (a simple drum machine, but it's the
+ replication of an enormous mechanical one, named Leon Napakatbra, which was
+ built from a 8 meters diameter merry-go-round...).
+ There was also nimouse (giving mouse position/buttons) and nitab (the same
+ for wacom serial graphire tablet) but i don't use these anymore: it's too
+ dangerous to access a device file directly from pd. Beter use gtkmouse and
+ wac/wacusb programs with pdsend/pdreceive.
+
+ 2. the sub library, which is a collection of gui control objects (subdial,
+ subslider, subbang and subtoggle) that are placed into a subpatch but are
+ visible in the parent window, into the subpatch's box. The idea was to build
+ easy-to-use complex subpatchs, or abstractions. I wrote it before
+ "graph-on-parent" was implemented in Pd, so it's a bit deprecated now, but
+ it has the advantage that subs values (positions of the buttons) are saved
+ into the parent patch... very useful in case of abstractions.
+ About of these questions, have a look to my AutoPreset abstractions, which
+ adds a manner to save the value of regular gui objects (hslider etc...) into
+ either a file or the parent patch, even those nested in abstractions (and
+ recursively in abstractions of abstractions...). It works also with tables,
+ symbols and symbol arrays.
+
+ 3. some other objects, such as:
+
+ tabenv : like env~, an enveloppe follower, but computing on a table, so
+ possibly much speeder than real-time env~'s computation.
+ tabsort and tabsort2 : returns the indices of the sorted table (tabsort2
+ is bidimentionnal).
+ gamme : one octave of a piano keyboard used to filter/choose notes in a
+ selected scale.
+ absolutepath/relativepath : to use datas (sounds, texts, presets, images,
+ programs...) nested in the patch's directory (and in subdirs).
+ sarray and slist : to creates shared dynamic arrays or lists with symbols.
+ sfread2~ and readsfv~ : to pitch the direct-from-disk reading of sound files.
+ dinlet~ : an inlet~ with a default value (when nothing is connected to it).
+ mknob : a round knob ala iemgui vslider (with its "properties" window).
+ dispatch : creates one bus name for many buttons' buses: from the N pairs
+ (slider1-snd/slider1-rcv) ... (sliderN-snd/sliderN-rcv), creates only
+ one pair of buses named (slider-snd/slider-rcv) , in which datas are
+ prepended by the number of the "sub-bus".
+ joystik : an improvment of Joseph A. Sarlo's joystick.
+ image : an improvment of Guenter Geiger's one. Same name, but it's
+ compatible. Here you can share images through different objects, preload
+ a list of images, and animate this list.
+
+ and some others...
+
+CAUTION:
+
+ This stuff was written with Pd v0.34-4 to v0.37 on a PC under Linux. It
+ hasn't be tested under other conditions; nilib will only work under Linux
+ (but I think it will be OK on other machines than PC), because of use of
+ multithreading and GTK .
+ Anyway makefiles are only working for Linux for the moment...
+ Moreover I think sub library is potentially very sensible to possible
+ modifications of Pd sources.
+
+
+
+To install:
+
+sublib_0.1.0 is for Pd 0.33
+sublib_0.2.0 is for Pd 0.35
+sublib_0.3.0 is for Pd 0.37
+
+nilib_0.1.0 is for Pd 0.35
+nilib_0.2.0 is for Pd 0.37
+
+others_0.1.0 is for Pd 0.35
+others_0.2.0 is for Pd 0.37
+
+
+
+Edit paths.txt to tune install paths and pure-data's location.
+Edit this makefile if you want to select older versions of externals (if you
+ are using pd0.37 it should be ok).
+
+Then:
+
+make
+make install
+
+
+
+If you keep externals locally inside moonlibs directory, then you should add it
+to your pdrc file:
+
+-path moonlibs-0.2/externs
+-helppath moonlibs-0.2/docs
+
+
+CAUTION :
+ 1) (pd 0.35) You MUST fix a bug pd sources and recompile them in order to have
+ dinlet~ working !!
+ You have to replace the function obj_findsignalscalar() in file m_obj.c
+ by the one written in dinlet~.c .
+
+ (dinlet~ is a signal inlet where you can choose the default float value it
+ outputs when no signal is connected into.)
+
+
+ 2) In order to have sfread~ working with big files in direct-from-disk
+ mode you have to hack pd sources: change
+ mlockall(MCL_FUTURE)
+ with
+ mlockall(MCL_CURRENT)
+ in s_linux.c (pd0.35) or s_inter.c (pd0.37). If not the whole file will be loaded in memory when
+ opening it.
diff --git a/XFS.txt b/XFS.txt
new file mode 100644
index 0000000..d50aece
--- /dev/null
+++ b/XFS.txt
@@ -0,0 +1 @@
+xfs -port -1 -daemon -droppriv -user xfs
diff --git a/absolutepath.c b/absolutepath.c
new file mode 100644
index 0000000..3e75df6
--- /dev/null
+++ b/absolutepath.c
@@ -0,0 +1,140 @@
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+/*#include <m_imp.h>*/
+#include "m_pd.h"
+#include "g_canvas.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <libgen.h>
+#include <string.h>
+
+extern t_canvas *canvas_list; /* list of all root canvases */
+extern int canvas_getdollarzero( void);
+
+struct _canvasenvironment
+{
+ t_symbol *ce_dir; /* directory patch lives in */
+ int ce_argc; /* number of "$" arguments */
+ t_atom *ce_argv; /* array of "$" arguments */
+ int ce_dollarzero; /* value of "$0" */
+};
+
+typedef struct _absolutepath
+{
+ t_object x_obj;
+ t_canvas *x_canvas;
+ int x_dolzero;
+ int x_realized;
+}t_absolutepath;
+
+t_class *absolutepath_class;
+
+void absolutepath_setup(void);
+
+static t_glist *getcanvas(t_glist *can,int d0)
+{
+ t_canvas *retcan=0;
+ t_gobj *ob;
+
+ if((can->gl_env)&&(can->gl_env->ce_dollarzero==d0)){
+ return can;
+ }
+
+ ob=can->gl_list;
+ while(ob&&(retcan==0)) {
+ if (pd_class(&ob->g_pd) == canvas_class)
+ retcan=getcanvas((t_glist *)ob,d0);
+ ob=ob->g_next;
+ }
+
+ if((!retcan)&&(can->gl_next)) retcan=getcanvas((t_glist *)can->gl_next,d0);
+ return retcan;
+}
+
+
+static void absolutepath_symbol(t_absolutepath *x,t_symbol *sym)
+{
+ t_canvas *can=0;
+ char buf[MAXPDSTRING], *bufptr,
+ *instr=sym->s_name,
+ canname[MAXPDSTRING],totaldir[MAXPDSTRING],
+ *cnamedir,
+ *candir;
+ unsigned int n,i=0;
+ int fd;
+
+ if(!x->x_realized) can=(t_canvas*)getcanvas(canvas_list,x->x_dolzero);
+ if(can) {
+ x->x_canvas = can;
+ x->x_realized = 1;
+ //post("found $0 canvas : %x %d ",x->x_canvas, x->x_canvas->gl_env->ce_dollarzero );
+ }
+
+ if(!instr) return;
+
+ candir=canvas_getdir(x->x_canvas)->s_name;
+ if(!candir) candir="";
+
+ //post("input= %s candir= %s glname=%s",instr,candir,x->x_canvas->gl_name->s_name);
+
+ strcpy(canname,x->x_canvas->gl_name->s_name);
+ cnamedir=dirname(canname);
+
+ if (strcmp(cnamedir,".")) {
+ sprintf(totaldir,"%s/%s",candir,cnamedir);
+ fd=open_via_path(totaldir,instr ,"",buf, &bufptr, MAXPDSTRING, 1);
+ }
+ else
+ fd=open_via_path(candir, instr, "",buf, &bufptr, MAXPDSTRING, 1);
+
+ if (fd>=0) {
+ close(fd);
+ buf[strlen(buf)]='/';
+ outlet_symbol(x->x_obj.ob_outlet,gensym(buf));
+ }
+ return;
+}
+
+
+static void *absolutepath_new(t_float dolzero)
+{
+ t_absolutepath *x = (t_absolutepath *)pd_new(absolutepath_class);
+ t_canvas *can=canvas_list;
+ int d0;
+
+ outlet_new(&x->x_obj, 0);
+ x->x_canvas = canvas_getcurrent();
+ x->x_dolzero = dolzero;
+ x->x_realized=dolzero?0:1;
+
+ return (void *)x;
+}
+
+void absolutepath_setup(void)
+{
+ absolutepath_class = class_new(gensym("absolutepath"),(t_newmethod)absolutepath_new,
+ 0, sizeof(t_absolutepath), 0,A_DEFFLOAT, 0);
+
+ class_addsymbol(absolutepath_class, absolutepath_symbol);
+}
+
diff --git a/basedir.c b/basedir.c
new file mode 100644
index 0000000..ad2f4f6
--- /dev/null
+++ b/basedir.c
@@ -0,0 +1,72 @@
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+/*#include <m_imp.h>*/
+#include "m_pd.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <libgen.h>
+#include <string.h>
+
+typedef struct _basedir
+{
+ t_object x_obj;
+}t_basedir;
+
+t_class *basedir_class;
+
+void basedir_setup(void);
+
+static void basedir_symbol(t_basedir *x,t_symbol *sym)
+{
+ static t_binbuf *binbuf=0;
+ t_atom at[2];
+ char *b,*d;
+ int l;
+
+ if(!sym->s_name) return;
+
+ b=strdup(sym->s_name);
+ d=strdup(sym->s_name);
+
+ SETSYMBOL(&at[0],gensym(basename(b)));
+ SETSYMBOL(&at[1],gensym(dirname(d)));
+
+ outlet_list(x->x_obj.ob_outlet,0,2,at);
+}
+
+
+static void *basedir_new(void)
+{
+ t_basedir *x = (t_basedir *)pd_new(basedir_class);
+ outlet_new(&x->x_obj, 0);
+ return (void *)x;
+}
+
+void basedir_setup(void)
+{
+ basedir_class = class_new(gensym("basedir"),(t_newmethod)basedir_new,
+ 0, sizeof(t_basedir), 0, 0);
+
+ class_addsymbol(basedir_class, basedir_symbol);
+}
+
diff --git a/char2f.c b/char2f.c
new file mode 100644
index 0000000..ef8af99
--- /dev/null
+++ b/char2f.c
@@ -0,0 +1,53 @@
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+#include "m_pd.h"
+
+
+typedef struct _char2f
+{
+ t_object x_obj;
+}t_char2f;
+
+t_class *char2f_class;
+
+void char2f_setup(void);
+
+static void char2f_symbol(t_char2f *x,t_symbol *sym)
+{
+ if(!sym->s_name) return;
+
+ outlet_float(x->x_obj.ob_outlet,(float)sym->s_name[0]);
+}
+
+static void *char2f_new(void)
+{
+ t_char2f *x = (t_char2f *)pd_new(char2f_class);
+ outlet_new(&x->x_obj, &s_float);
+ return (void *)x;
+}
+
+void char2f_setup(void)
+{
+ char2f_class = class_new(gensym("char2f"),(t_newmethod)char2f_new,
+ 0, sizeof(t_char2f), 0, 0);
+
+ class_addsymbol(char2f_class, char2f_symbol);
+}
+
diff --git a/comma.c b/comma.c
new file mode 100644
index 0000000..737d2b7
--- /dev/null
+++ b/comma.c
@@ -0,0 +1,53 @@
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+#include "m_pd.h"
+
+static t_atom _commaatom_;
+
+typedef struct _comma
+{
+ t_object x_obj;
+}t_comma;
+
+t_class *comma_class;
+
+void comma_setup(void);
+
+static void comma_bang(t_comma *x)
+{
+ outlet_list(x->x_obj.ob_outlet, &s_list, 1, &_commaatom_);
+}
+
+static void *comma_new(void)
+{
+ t_comma *x = (t_comma *)pd_new(comma_class);
+ outlet_new(&x->x_obj,&s_symbol);
+ return (void *)x;
+}
+
+void comma_setup(void)
+{
+ comma_class = class_new(gensym("comma"),(t_newmethod)comma_new,
+ 0, sizeof(t_comma), 0, 0);
+
+ class_addbang(comma_class, comma_bang);
+ SETCOMMA(&_commaatom_);
+}
+
diff --git a/dinlet~.c b/dinlet~.c
new file mode 100644
index 0000000..dc7f260
--- /dev/null
+++ b/dinlet~.c
@@ -0,0 +1,136 @@
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+/* this file is made from parts of m_object.c and g_io.c
+* it defines a signal inlet named dinlet~ which is the same as inlet~
+* exepts you can give a default float value for the case none signal
+* is connected to this inlet~. */
+
+/***********************************************************************/
+/* CAUTION :
+ You MUST fix a bug pd sources and recompile them in order to have
+ dinlet~ working !!
+
+ this function must be fixed in pd/m_obj.c: */
+#if 0
+t_sample *obj_findsignalscalar(t_object *x, int m)
+{
+ int n = 0,mbak=m;
+ t_inlet *i;
+ post("my obj_findsignalscalar");
+ if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin)
+ {
+ if (!m--)
+ return (x->ob_pd->c_floatsignalin > 0 ?
+ (t_sample *)(((char *)x) + x->ob_pd->c_floatsignalin) : 0);
+ n++;
+ }
+ for (i = x->ob_inlet; i; i = i->i_next, m--)
+ if (i->i_symfrom == &s_signal)
+ {
+ /*if (m == 0)*/
+ if(n==mbak)
+ return (&i->i_un.iu_floatsignalvalue);
+ n++;
+ }
+ return (0);
+}
+#endif
+/***********************************************************************/
+
+#include "m_pd.h"
+#include "m_imp.h"
+#include "g_canvas.h"
+#include <string.h>
+
+/******************** from m_obj.c: **************************/
+/* only because inlet_float() is not public... */
+union inletunion
+{
+ t_symbol *iu_symto;
+ t_gpointer *iu_pointerslot;
+ t_float *iu_floatslot;
+ t_symbol **iu_symslot;
+ t_sample iu_floatsignalvalue;
+};
+
+struct _inlet
+{
+ t_pd i_pd;
+ struct _inlet *i_next;
+ t_object *i_owner;
+ t_pd *i_dest;
+ t_symbol *i_symfrom;
+ union inletunion i_un;
+};
+
+#define i_symto i_un.iu_symto
+
+static void dinlet_float(t_inlet *x, t_float f)
+{
+ if (x->i_symfrom == &s_float)
+ pd_vmess(x->i_dest, x->i_symto, "f", (t_floatarg)f);
+ else if (x->i_symfrom == &s_signal)
+ x->i_un.iu_floatsignalvalue = f;
+ else if (!x->i_symfrom)
+ pd_float(x->i_dest, f);
+ /*else inlet_wrong(x, &s_float);*/
+}
+/**************** from g_io.c : *********************************/
+
+void signal_setborrowed(t_signal *sig, t_signal *sig2);
+void signal_makereusable(t_signal *sig);
+
+/* ------------------------- vinlet -------------------------- */
+t_class *vinlet_class;
+
+typedef struct _vinlet
+{
+ t_object x_obj;
+ t_canvas *x_canvas;
+ t_inlet *x_inlet;
+ int x_bufsize;
+ t_float *x_buf; /* signal buffer; zero if not a signal */
+ t_float *x_endbuf;
+ t_float *x_fill;
+ t_float *x_read;
+ int x_hop;
+ /* if not reblocking, the next slot communicates the parent's inlet
+ signal from the prolog to the DSP routine: */
+ t_signal *x_directsignal;
+} t_vinlet;
+
+
+static void *dinlet_newsig(t_floatarg f)
+{
+ t_vinlet *x = (t_vinlet *)pd_new(vinlet_class);
+ x->x_canvas = canvas_getcurrent();
+ x->x_inlet = canvas_addinlet(x->x_canvas, &x->x_obj.ob_pd, &s_signal,0);
+ x->x_endbuf = x->x_buf = (t_float *)getbytes(0);
+ x->x_bufsize = 0;
+ x->x_directsignal = 0;
+ x->x_inlet->i_un.iu_floatsignalvalue=f;
+ outlet_new(&x->x_obj, &s_signal);
+ return (x);
+}
+
+void dinlet_tilde_setup(void)
+{
+ class_addcreator((t_newmethod)dinlet_newsig, gensym("dinlet~"), A_DEFFLOAT,0);
+}
diff --git a/dispatch.c b/dispatch.c
new file mode 100644
index 0000000..f8a937a
--- /dev/null
+++ b/dispatch.c
@@ -0,0 +1,194 @@
+/*
+Copyright (C) 2003 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+/* a shared symbol array, ala "value" .*/
+
+#include "m_pd.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+static t_class *dispatch_class, *dispsnd_class;
+static t_symbol *s__;
+
+typedef struct _dispatch t_dispatch;
+
+typedef struct dispsnd
+{
+ t_pd d_pd;
+ t_symbol *d_eachsnd;
+ t_symbol *d_allsnd;
+ t_int d_num;
+} t_dispsnd;
+
+struct _dispatch
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+ int x_from;
+ int x_to;
+
+ t_dispsnd **x_snds;
+
+ t_symbol *x_allrcv;
+ t_symbol **x_eachrcvs;
+};
+
+/*--------------------- dispsnd ------------------------------------*/
+
+static void dispsnd_ff(t_dispsnd *x)
+{
+ pd_unbind((t_pd*)x, x->d_eachsnd);
+}
+
+static void *dispsnd_new(t_symbol *eachsnd,t_symbol *allsnd,int num)
+{
+ t_dispsnd *x = (t_dispsnd *)pd_new(dispsnd_class);
+
+ //post("new dispsnd: num=%d rcv=%s snd=%s",num,eachsnd->s_name,allsnd->s_name);
+ x->d_eachsnd=eachsnd;
+ x->d_allsnd=allsnd;
+ x->d_num=num;
+
+ pd_bind((t_pd*)x, x->d_eachsnd);
+
+ return (x);
+}
+
+static void dispsnd_float(t_dispsnd *x, t_float f)
+{
+ t_atom out[2];
+
+ if (x->d_allsnd->s_thing) {
+ SETFLOAT(&out[0],x->d_num);
+ SETFLOAT(&out[1],f);
+
+ typedmess(x->d_allsnd->s_thing, &s_list, 2, out);
+ }
+}
+
+static void dispsnd_anything(t_dispsnd *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_atom *out;
+
+ if (x->d_allsnd->s_thing) {
+ out = (t_atom*)getbytes(sizeof(t_atom)*(argc+2));
+ memcpy(&out[2], argv, argc*sizeof(t_atom));
+ SETFLOAT(&out[0],x->d_num);
+ SETSYMBOL(&out[1],s);
+
+ typedmess(x->d_allsnd->s_thing, &s_list, argc+2, out);
+
+ freebytes(out, sizeof(t_atom)*(argc+2));
+ }
+}
+
+
+
+/*--------------------- dispatch ------------------------------------*/
+
+static void *dispatch_new(t_symbol *s,t_float from,t_float to)
+{
+ int i,len;
+ t_dispatch *x = (t_dispatch *)pd_new(dispatch_class);
+ char str[512];
+ t_symbol *allsnd,*eachsnd;
+
+ x->x_snds=0;
+ x->x_sym = s;
+ x->x_from = from;
+ x->x_to = to;
+ len=x->x_to-x->x_from+1;
+
+ if(len>0){
+ sprintf(str,"%s-snd",x->x_sym->s_name);
+ allsnd=gensym(str);
+
+ sprintf(str,"%s-rcv",x->x_sym->s_name);
+ x->x_allrcv=gensym(str);
+ pd_bind((t_pd*)x, x->x_allrcv);
+
+ x->x_snds=getbytes(len*sizeof(t_dispsnd *));
+ x->x_eachrcvs=getbytes(len*sizeof(t_symbol *));
+
+ for(i=0;i<len;i++){
+ sprintf(str,"%s%d-snd",x->x_sym->s_name,i+x->x_from);
+ eachsnd=gensym(str);
+ x->x_snds[i]=dispsnd_new(eachsnd,allsnd,i+x->x_from);
+
+ sprintf(str,"%s%d-rcv",x->x_sym->s_name,i+x->x_from);
+ x->x_eachrcvs[i]=gensym(str);
+ }
+ }
+ return (x);
+}
+
+static void dispatch_ff(t_dispatch *x)
+{
+ int i,len=x->x_to-x->x_from+1;
+
+ if(len<=0) return;
+
+ pd_unbind((t_pd*)x, x->x_allrcv);
+
+ for(i=0;i<len;i++) pd_free((t_pd*)x->x_snds[i]);
+
+ freebytes(x->x_snds,len*sizeof(t_dispsnd *));
+ freebytes(x->x_eachrcvs,len*sizeof(t_symbol *));
+}
+
+
+static void dispatch_list(t_dispatch *x, t_symbol *s, int argc, t_atom *argv)
+{
+ int num;
+
+ if((!argc)|(argv[0].a_type!=A_FLOAT)) {
+ error("dispatch: bad list format");
+ return;
+ }
+
+ num=atom_getint(&argv[0]);
+
+ if((num<x->x_from)|(num>x->x_to)) {
+ //error("dispatch: bad num");
+ return;
+ }
+
+ if (x->x_eachrcvs[num-x->x_from]->s_thing)
+ pd_forwardmess(x->x_eachrcvs[num-x->x_from]->s_thing, argc-1, argv+1);
+}
+
+
+
+
+/*--------------------------------------------------------------*/
+
+void dispatch_setup(void)
+{
+ dispatch_class = class_new(gensym("dispatch"), (t_newmethod)dispatch_new,
+ (t_method)dispatch_ff,
+ sizeof(t_dispatch), 0, A_SYMBOL, A_FLOAT, A_FLOAT,0);
+
+ class_addlist(dispatch_class, dispatch_list);
+ dispsnd_class = class_new(gensym("dispatch"), 0, (t_method)dispsnd_ff,
+ sizeof(t_dispsnd), CLASS_PD, 0);
+ class_addanything(dispsnd_class, dispsnd_anything);
+ class_addfloat(dispsnd_class, dispsnd_float);
+}
+
diff --git a/dripchar.c b/dripchar.c
new file mode 100644
index 0000000..184e204
--- /dev/null
+++ b/dripchar.c
@@ -0,0 +1,82 @@
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+/*#include <m_imp.h>*/
+#include "m_pd.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+typedef struct _dripchar
+{
+ t_object x_obj;
+}t_dripchar;
+
+t_class *dripchar_class;
+
+void dripchar_setup(void);
+
+static void dripchar_symbol(t_dripchar *x,t_symbol *sym)
+{
+ static t_binbuf *binbuf=0;
+ t_atom at;
+ char *c,s[2]={0};
+ int l;
+
+ if(!binbuf) binbuf=binbuf_new();
+ /*post("dripchar_symbol");*/
+ if(!sym->s_name) return;
+
+ c=sym->s_name;
+ while(*c) {
+ s[0]=*c++;
+ SETSYMBOL(&at,gensym(s));
+ binbuf_add(binbuf,1,&at);
+ }
+
+
+ outlet_list(x->x_obj.ob_outlet,0,
+ binbuf_getnatom(binbuf),binbuf_getvec(binbuf));
+ binbuf_clear(binbuf);
+}
+
+static void dripchar_float(t_dripchar *x,t_floatarg f)
+{
+ post("dripchar_float");
+ /*outlet_symbol(x->x_obj.ob_outlet,*/
+}
+
+static void *dripchar_new(void)
+{
+ t_dripchar *x = (t_dripchar *)pd_new(dripchar_class);
+ outlet_new(&x->x_obj, 0);
+ return (void *)x;
+}
+
+void dripchar_setup(void)
+{
+ dripchar_class = class_new(gensym("dripchar"),(t_newmethod)dripchar_new,
+ 0, sizeof(t_dripchar), 0, 0);
+
+ class_addsymbol(dripchar_class, dripchar_symbol);
+ class_addfloat(dripchar_class, dripchar_float);
+}
+
diff --git a/f2char.c b/f2char.c
new file mode 100644
index 0000000..e14c5cf
--- /dev/null
+++ b/f2char.c
@@ -0,0 +1,53 @@
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+#include "m_pd.h"
+
+typedef struct _f2char
+{
+ t_object x_obj;
+}t_f2char;
+
+t_class *f2char_class;
+
+void f2char_setup(void);
+
+static void f2char_float(t_f2char *x,t_floatarg f)
+{
+ char s[2]={0};
+
+ s[0]=(char)f;
+ outlet_symbol(x->x_obj.ob_outlet,gensym(s));
+}
+
+static void *f2char_new(void)
+{
+ t_f2char *x = (t_f2char *)pd_new(f2char_class);
+ outlet_new(&x->x_obj,&s_symbol);
+ return (void *)x;
+}
+
+void f2char_setup(void)
+{
+ f2char_class = class_new(gensym("f2char"),(t_newmethod)f2char_new,
+ 0, sizeof(t_f2char), 0, 0);
+
+ class_addfloat(f2char_class, f2char_float);
+}
+
diff --git a/gamme.c b/gamme.c
new file mode 100644
index 0000000..d4ddd01
--- /dev/null
+++ b/gamme.c
@@ -0,0 +1,558 @@
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+#include <math.h>
+#include <stdlib.h>
+#include <m_pd.h>
+#include "g_canvas.h"
+
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+/* ------------------------ gamme ----------------------------- */
+#define BACKGROUND "-fill grey"
+#define BACKGROUNDCOLOR "grey"
+
+#ifndef PD_VERSION_MINOR
+#define PD_VERSION_MINOR 32
+#endif
+
+#define IS_A_POINTER(atom,index) ((atom+index)->a_type == A_POINTER)
+#define IS_A_FLOAT(atom,index) ((atom+index)->a_type == A_FLOAT)
+#define IS_A_SYMBOL(atom,index) ((atom+index)->a_type == A_SYMBOL)
+
+
+#define DEFAULTSIZE 15
+#define DEFAULTWIDTH 90
+#define DEFAULTHEIGHT 40
+
+#define DEFAULTCOLOR "black"
+#define BLACKCOLOR "black"
+#define WHITECOLOR "white"
+#define SELBLACKCOLOR "gold"
+#define SELWHITECOLOR "yellow"
+
+
+static t_class *gamme_class;
+
+static char *NoteNames[]=
+ { "C","C#","D","D#","E","F","F#","G","G#","A","A#","B" };
+static char NoteColPos[]=
+ { 1,-1,2,-2,3,4,-4,5,-5,6,-6,7 };
+static char Whites[]={0,2,4,5,7,9,11};
+static char Blacks[]={1,3,6,8,10};
+static char BlacksWhites[]={1,3,6,8,10,0,2,4,5,7,9,11};
+static char WhitesBlacks[]={0,2,4,5,7,9,11,1,3,6,8,10};
+
+#define ISWHITE(x) (NoteColPos[x]>0)
+#define ISBLACK(x) (!ISWHITE(x))
+
+#define te_xpos te_xpix
+#define te_ypos te_ypix
+
+typedef struct _gamme
+{
+ t_object x_obj;
+ t_outlet *x_out_n; /*gives the number of selected notes when change occurs*/
+ t_outlet *x_out_note; /*gives the number and new value of the changed notes when change occurs*/
+ t_glist * x_glist;
+ int x_width;
+ int x_height;
+ char x_n;
+ char x_notes[12];
+ char x_on_notes[12];
+} t_gamme;
+
+/* widget helper functions */
+
+
+#define INTERSPACE 0.02
+#define NOTEWIDTH ((1-INTERSPACE*6.0)/7.0)
+#define BLACK1st ((NOTEWIDTH+INTERSPACE)/2.0)
+#define BLACKH 0.6
+static void note_get_rel_rect(int x, float *xp1, float *yp1, float *xp2, float *yp2)
+{
+ int cp=NoteColPos[x];
+
+ *xp1=(abs(cp)-1)*(NOTEWIDTH+INTERSPACE) + (cp<0)*BLACK1st;
+ *xp2=*xp1+NOTEWIDTH;
+
+ *yp1=0;
+ *yp2=cp<0?BLACKH:1;
+}
+
+static int get_touched_note(float x, float y)
+{
+ int i,j;
+ float xp1,xp2,yp1,yp2;
+
+ for(j=0;j<12;j++) {
+ i=BlacksWhites[j];
+ note_get_rel_rect(i,&xp1,&yp1,&xp2,&yp2);
+ if((x>=xp1)&&(x<=xp2)&&(y>=yp1)&&(y<=yp2))
+ return i;
+ }
+ /*post("gamme::get_touched_note note not found: x=%f y=%f",x,y);*/
+ return -1;
+}
+
+static void draw_inlets(t_gamme *x, t_glist *glist, int firsttime, int nin, int nout)
+{
+ int n = nout;
+ int nplus, i;
+ int xpos=text_xpix(&x->x_obj, glist);
+ int ypos=text_ypix(&x->x_obj, glist);
+
+ nplus = (n == 1 ? 1 : n-1);
+ for (i = 0; i < n; i++)
+ {
+ int onset = xpos + (x->x_width - IOWIDTH) * i / nplus;
+ if (firsttime)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xo%d\n",
+ glist_getcanvas(glist),
+ onset, ypos + x->x_height - 1,
+ onset + IOWIDTH, ypos + x->x_height,
+ x, i);
+ else
+ sys_vgui(".x%x.c coords %xo%d %d %d %d %d\n",
+ glist_getcanvas(glist), x, i,
+ onset, ypos + x->x_height - 1,
+ onset + IOWIDTH, ypos + x->x_height);
+ }
+ n = nin;
+ nplus = (n == 1 ? 1 : n-1);
+ for (i = 0; i < n; i++)
+ {
+ int onset = xpos + (x->x_width - IOWIDTH) * i / nplus;
+ if (firsttime)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xi%d\n",
+ glist_getcanvas(glist),
+ onset, ypos,
+ onset + IOWIDTH, ypos + 1,
+ x, i);
+ else
+ sys_vgui(".x%x.c coords %xi%d %d %d %d %d\n",
+ glist_getcanvas(glist), x, i,
+ onset, ypos,
+ onset + IOWIDTH, ypos + 1);
+
+ }
+}
+
+void gamme_drawme(t_gamme *x, t_glist *glist, int firsttime)
+{
+ int i,j;
+ float x1,y1,x2,y2;
+ int xi1,yi1,xi2,yi2;
+ char *color;
+ int xpos=text_xpix(&x->x_obj, glist);
+ int ypos=text_ypix(&x->x_obj, glist);
+
+ if (firsttime) {
+ sys_vgui(".x%x.c create rectangle \
+%d %d %d %d -tags %xS "BACKGROUND"\n",
+ glist_getcanvas(glist),
+ xpos, ypos,
+ xpos + x->x_width, ypos + x->x_height,
+ x);
+
+ }
+ else {
+ sys_vgui(".x%x.c coords %xS \
+%d %d %d %d\n",
+ glist_getcanvas(glist), x,
+ xpos, ypos,
+ xpos + x->x_width, ypos + x->x_height);
+ }
+
+ for(j=0;j<12;j++){
+ i=WhitesBlacks[j];
+ note_get_rel_rect(i,&x1,&y1,&x2,&y2);
+ xi1=xpos + x->x_width*x1;
+ xi2=xpos + x->x_width*x2;
+ yi1=ypos + x->x_height*y1;
+ yi2=ypos + x->x_height*y2;
+
+ if (firsttime) {
+ color=x->x_notes[i]? (ISWHITE(i)?SELWHITECOLOR:SELBLACKCOLOR):
+ (ISWHITE(i)?WHITECOLOR:BLACKCOLOR);
+ sys_vgui(".x%x.c create rectangle \
+%d %d %d %d -tags %x%s -fill %s\n",
+ glist_getcanvas(glist),xi1,yi1,xi2,yi2,
+ x,NoteNames[i],color);
+ }
+ else {
+ sys_vgui(".x%x.c coords %x%s \
+%d %d %d %d\n",
+ glist_getcanvas(glist),x,NoteNames[i],xi1,yi1,xi2,yi2);
+ }
+ }
+
+ draw_inlets(x, glist, firsttime, 1,3);
+
+}
+
+void gamme_erase(t_gamme* x,t_glist* glist)
+{
+ int n;
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c delete %xS\n",canvas, x);
+
+ for(n=0;n<12;n++)
+ sys_vgui(".x%x.c delete %x%s\n",canvas,x,NoteNames[n]);
+
+ n = 1;
+ while (n--) {
+ sys_vgui(".x%x.c delete %xi%d\n",canvas,x,n);
+ }
+ n = 3;
+ while (n--) {
+ sys_vgui(".x%x.c delete %xo%d\n",canvas,x,n);
+ }
+}
+
+
+
+/* ------------------------ gamme widgetbehaviour----------------------------- */
+
+
+static void gamme_getrect(t_gobj *z, t_glist *glist,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_gamme *x = (t_gamme *)z;
+ int width, height;
+ t_gamme* s = (t_gamme*)z;
+
+
+ width = s->x_width;
+ height = s->x_height;
+ *xp1 = text_xpix(&x->x_obj, glist);
+ *yp1 = text_ypix(&x->x_obj, glist);
+ *xp2 = *xp1 + width;
+ *yp2 = *yp1 + height;
+}
+
+static void gamme_displace(t_gobj *z, t_glist *glist,
+ int dx, int dy)
+{
+ t_gamme *x = (t_gamme *)z;
+ x->x_obj.te_xpos += dx;
+ x->x_obj.te_ypos += dy;
+ gamme_drawme(x, glist, 0);
+ canvas_fixlinesfor(glist_getcanvas(glist),(t_text*) x);
+}
+
+static void gamme_select(t_gobj *z, t_glist *glist, int state)
+{
+ t_gamme *x = (t_gamme *)z;
+ sys_vgui(".x%x.c itemconfigure %xS -fill %s\n", glist,
+ x, (state? "blue" : BACKGROUNDCOLOR));
+}
+
+
+static void gamme_activate(t_gobj *z, t_glist *glist, int state)
+{
+/* t_text *x = (t_text *)z;
+ t_rtext *y = glist_findrtext(glist, x);
+ if (z->g_pd != gatom_class) rtext_activate(y, state);*/
+}
+
+static void gamme_delete(t_gobj *z, t_glist *glist)
+{
+ t_text *x = (t_text *)z;
+ canvas_deletelinesfor(glist, x);
+}
+
+
+static void gamme_vis(t_gobj *z, t_glist *glist, int vis)
+{
+ t_gamme* s = (t_gamme*)z;
+ if (vis)
+ gamme_drawme(s, glist, 1);
+ else
+ gamme_erase(s,glist);
+}
+
+/* can we use the normal text save function ?? */
+
+static void gamme_save(t_gobj *z, t_binbuf *b)
+{
+ t_gamme *x = (t_gamme *)z;
+ char *c=x->x_notes;
+
+ binbuf_addv(b, "ssiisiiiiiiiiiiiiii", gensym("#X"),gensym("obj"),
+ (t_int)x->x_obj.te_xpos, (t_int)x->x_obj.te_ypos,
+ gensym("gamme"),x->x_width,x->x_height,
+ c[0],c[1],c[2],c[3],c[4],c[5],c[6],c[7],c[8],c[9],c[10],c[11]);
+ binbuf_addv(b, ";");
+}
+
+void gamme_getn(t_gamme *x)
+{
+ outlet_float(x->x_out_n,x->x_n);
+}
+
+void gamme_out_changed(t_gamme *x,int note)
+{
+ t_atom ats[2];
+ SETFLOAT(&ats[0],note);
+ SETFLOAT(&ats[1],x->x_notes[note]);
+
+ outlet_list(x->x_out_note,0,2,ats);
+}
+
+inline float my_mod(float x,int n)
+{
+ float y=fmod(x,n);
+ return y<0?y+n:y;
+}
+
+#define my_div(x,y) (floor(x/y))
+#define tonotei(x) (my_mod(rint(x),12U))
+
+void gamme_set(t_gamme *x,t_floatarg note,t_floatarg on)
+{
+ unsigned int i,notei=tonotei(note),changed=0;
+ char *color;
+ t_canvas *canvas=glist_getcanvas(x->x_glist);
+
+
+ if(x->x_notes[notei]!=on) changed=1;
+ if(on<0) x->x_notes[notei]=!(x->x_notes[notei]);
+ else x->x_notes[notei]=on;
+ if(changed) gamme_out_changed(x,notei);
+
+ color=x->x_notes[notei]?(ISWHITE(notei)?SELWHITECOLOR:SELBLACKCOLOR):
+ (ISWHITE(notei)?WHITECOLOR:BLACKCOLOR);
+
+ if(glist_isvisible(x->x_glist))
+ sys_vgui(".x%x.c itemconfigure %x%s -fill %s\n", canvas,
+ x, NoteNames[notei],color);
+
+ x->x_n=0;
+ for(i=0;i<12;i++) if(x->x_notes[i]) x->x_on_notes[(int)(x->x_n++)]=i;
+ gamme_getn(x);
+}
+
+#define getnote(n) \
+ (my_div(n,(int)x->x_n)*12+x->x_on_notes[(int)my_mod(n,x->x_n)])
+void gamme_get(t_gamme *x,t_floatarg ref_octave,t_floatarg note)
+{
+ int no0,no1,ni0,ni1,n0,n1,n;
+ float xn,xx,nn;
+
+ if(!x->x_n) return;
+ no0=floor(note);
+ no1=ceil(note);
+ xx=note-no0;
+
+ nn=getnote((float)no0)*(1-xx)+getnote((float)(no0+1))*xx+ref_octave*12;
+ n=getnote((float)no0)+ref_octave*12;
+ outlet_float(x->x_obj.ob_outlet,nn);
+}
+
+static void gamme_click(t_gamme *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ int note;
+ int x0=text_xpix(&x->x_obj, x->x_glist);
+ int y0=text_ypix(&x->x_obj, x->x_glist);
+
+ note=get_touched_note(
+ (xpos-x0)/x->x_width,
+ (ypos-y0)/x->x_height);
+
+ if(note>=0) gamme_set(x,note,!x->x_notes[note]);
+}
+
+static int gamme_newclick(t_gobj *z, struct _glist *glist,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ t_gamme* x = (t_gamme *)z;
+
+ if(doit)
+ {
+ gamme_click( x, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift,
+ 0, (t_floatarg)alt);
+ }
+ return (1);
+}
+
+void gamme_float(t_gamme *x,t_floatarg f)
+{
+ unsigned int notei=tonotei(f);
+
+ /*post("notei=%d",notei);*/
+ if(x->x_notes[notei])
+ outlet_float(x->x_obj.ob_outlet,f);
+}
+
+void gamme_round(t_gamme *x,t_floatarg f,t_floatarg round)
+{
+ unsigned int notei=tonotei(f);
+ int imin=floor(f),imax=ceil(f);
+ float norm;
+
+ if(!x->x_n) return;
+
+ while(!x->x_notes[(int)my_mod((imin),12U)]) imin--;
+ while(!x->x_notes[(int)my_mod((imax),12U)]) imax++;
+
+ /*post("min: %d max: %d",imin,imax);*/
+
+ if((imin!=imax)&&round) {
+ round*=round;
+ norm=(f-imin)/(imax-imin)*2-1;
+ norm=norm/sqrt(1+round*norm*norm)*sqrt(1+round)/2+.5;
+ f=norm*(imax-imin)+imin;
+ }
+ outlet_float(x->x_obj.ob_outlet,f);
+}
+
+void gamme_setall(t_gamme *x,t_symbol *s, int argc, t_atom *argv)
+{
+ int i=0,err=0;
+
+ if(argc==12)
+ {
+ for(i=0;i<12;i++) err+=!IS_A_FLOAT(argv,i);
+ if(!err) for(i=0;i<12;i++) gamme_set(x,i,atom_getfloat(&argv[i]));
+ }
+}
+
+void gamme_getall(t_gamme *x)
+{
+ int i=0;
+
+ for(i=0;i<12;i++) gamme_out_changed(x,i);
+ gamme_getn(x);
+}
+
+extern int sys_noloadbang;
+static void gamme_loadbang(t_gamme *x)
+{
+ int i;
+
+ if(sys_noloadbang) return;
+ for(i=0;i<12;i++) gamme_out_changed(x,i);
+ gamme_getn(x);
+}
+
+void gamme_size(t_gamme* x,t_floatarg w,t_floatarg h) {
+ x->x_width = w;
+ x->x_height = h;
+ gamme_drawme(x, x->x_glist, 0);
+}
+
+t_widgetbehavior gamme_widgetbehavior;
+
+static void gamme_setwidget(void)
+{
+ gamme_widgetbehavior.w_getrectfn = gamme_getrect;
+ gamme_widgetbehavior.w_displacefn = gamme_displace;
+ gamme_widgetbehavior.w_selectfn = gamme_select;
+ gamme_widgetbehavior.w_activatefn = gamme_activate;
+ gamme_widgetbehavior.w_deletefn = gamme_delete;
+ gamme_widgetbehavior.w_visfn = gamme_vis;
+ gamme_widgetbehavior.w_clickfn = gamme_newclick;
+ //gamme_widgetbehavior.w_propertiesfn = NULL;
+ //gamme_widgetbehavior.w_savefn = gamme_save;
+}
+
+
+static void *gamme_new(t_symbol *s, int argc, t_atom *argv)
+{
+ int i=0,err=0;
+
+ t_gamme *x = (t_gamme *)pd_new(gamme_class);
+
+ x->x_glist = (t_glist*) canvas_getcurrent();
+ x->x_width = DEFAULTWIDTH;
+ x->x_height = DEFAULTHEIGHT;
+ outlet_new(&x->x_obj, &s_float);
+ x->x_out_n=outlet_new(&x->x_obj, &s_float);
+ x->x_out_note=outlet_new(&x->x_obj, &s_float);
+
+ x->x_n=0;
+ for(i=0;i<12;i++) x->x_notes[i]=0;
+ for(i=0;i<12;i++) x->x_on_notes[i]=0;
+
+ if((argc>1)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1))
+ {
+ if(atom_getfloat(&argv[0])) x->x_width = atom_getfloat(&argv[0]);
+ if(atom_getfloat(&argv[1])) x->x_height = atom_getfloat(&argv[1]);
+
+ if(argc==14)
+ {
+ for(i=0;i<12;i++) err+=(!IS_A_FLOAT(argv,i+2));
+ if(!err) {
+ for(i=0;i<12;i++) if(x->x_notes[i]=atom_getfloat(&argv[i+2]))
+ x->x_on_notes[(int)(x->x_n++)]=i;
+ /*gamme_set(x,i,atom_getfloat(&argv[i+2]));gamme_getn(x);*/
+ }
+ else post("gamme_new : error in creation arguments");
+ }
+ /*if(argc==14) gamme_setall(x,s,argc-2,&argv[2]);*/
+ }
+
+ return (x);
+}
+
+void gamme_setup(void)
+{
+ post("gamme_setup");
+ gamme_class = class_new(gensym("gamme"), (t_newmethod)gamme_new, 0,
+ sizeof(t_gamme),0, A_GIMME,0);
+
+ class_addfloat(gamme_class,gamme_float);
+
+ class_addmethod(gamme_class, (t_method)gamme_click, gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+
+ class_addmethod(gamme_class, (t_method)gamme_size, gensym("size"),
+ A_FLOAT, A_FLOAT, 0);
+
+ class_addmethod(gamme_class, (t_method)gamme_set, gensym("set"),
+ A_FLOAT, A_FLOAT, 0);
+
+ class_addmethod(gamme_class, (t_method)gamme_get, gensym("get"),
+ A_FLOAT, A_FLOAT, 0);
+
+ class_addmethod(gamme_class, (t_method)gamme_round, gensym("round"),
+ A_FLOAT, A_FLOAT, 0);
+
+ class_addmethod(gamme_class, (t_method)gamme_setall, gensym("setall"),
+ A_GIMME, 0);
+
+ class_addmethod(gamme_class, (t_method)gamme_getall, gensym("getall"), 0);
+
+ class_addmethod(gamme_class, (t_method)gamme_getn, gensym("getn"), 0);
+
+ /*class_addmethod(gamme_class, (t_method)gamme_loadbang, gensym("loadbang"), 0);*/
+
+
+ gamme_setwidget();
+ class_setwidget(gamme_class,&gamme_widgetbehavior);
+ class_setsavefn(gamme_class, gamme_save);
+
+}
+
+
diff --git a/help/absolutepath-help.pd b/help/absolutepath-help.pd
new file mode 100644
index 0000000..b056f4a
--- /dev/null
+++ b/help/absolutepath-help.pd
@@ -0,0 +1,13 @@
+#N canvas 14 323 660 379 10;
+#X text 17 352 (c) Antoine Rousseau 2004;
+#X obj 33 108 absolutepath;
+#X symbolatom 33 131 0 0 0;
+#X msg 33 51 symbol absolutepath.pd;
+#X obj 33 220 relativepath;
+#X symbolatom 33 245 0 0 0;
+#X text 14 6 absolutepath / relativepath : use filenames relatively
+to the patch's path.;
+#X connect 1 0 2 0;
+#X connect 2 0 4 0;
+#X connect 3 0 1 0;
+#X connect 4 0 5 0;
diff --git a/help/basedir-help.pd b/help/basedir-help.pd
new file mode 100644
index 0000000..cbf9c9e
--- /dev/null
+++ b/help/basedir-help.pd
@@ -0,0 +1,18 @@
+#N canvas 136 196 430 247 10;
+#X obj 0 0 cnv 8 100 60 empty empty basedir 20 20 1 18 -262144 -1109
+0;
+#X text 7 221 (c) Moonix: Antoine Rousseau 2003;
+#X text 135 12 basename/dirname functions;
+#X obj 124 102 basedir;
+#X obj 124 136 unpack s s;
+#X symbolatom 124 158 0 0 0;
+#X symbolatom 189 158 0 0 0;
+#X msg 124 62 symbol /usr/local/bin/pd;
+#X obj 124 42 loadbang;
+#X text 108 175 basename;
+#X text 212 175 dirname;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 4 1 6 0;
+#X connect 7 0 3 0;
+#X connect 8 0 7 0;
diff --git a/help/char2f-help.pd b/help/char2f-help.pd
new file mode 100644
index 0000000..f133288
--- /dev/null
+++ b/help/char2f-help.pd
@@ -0,0 +1,18 @@
+#N canvas 134 318 430 247 10;
+#X obj 0 0 cnv 8 100 60 empty empty char2f_f2char 10 20 1 18 -262144
+-1109 0;
+#X text 7 221 (c) Moonix: Antoine Rousseau 2003;
+#X text 160 14 ascii utilities;
+#X obj 131 115 char2f;
+#X floatatom 131 136 5 0 0;
+#X msg 131 69 symbol A;
+#X obj 131 173 f2char;
+#X symbolatom 131 194 2 0 0;
+#X obj 131 49 loadbang;
+#X msg 216 70 symbol a;
+#X connect 3 0 4 0;
+#X connect 4 0 6 0;
+#X connect 5 0 3 0;
+#X connect 6 0 7 0;
+#X connect 8 0 5 0;
+#X connect 9 0 3 0;
diff --git a/help/comma-help.pd b/help/comma-help.pd
new file mode 100644
index 0000000..b8a8e63
--- /dev/null
+++ b/help/comma-help.pd
@@ -0,0 +1,40 @@
+#N canvas 172 316 715 428 10;
+#X obj 0 0 cnv 8 100 60 empty empty comma 10 20 1 18 -262144 -1109
+0;
+#X text 109 12 how to write " \, " in a message...;
+#X text 2 388 (c) Moonix: Antoine Rousseau 2004;
+#X msg 71 101 foo 1 \, bar 2;
+#X floatatom 70 340 5 0 0 0 - - -;
+#X floatatom 113 341 5 0 0 0 - - -;
+#X obj 70 318 route foo bar;
+#X text 59 85 build a message like this:;
+#X text 106 118 | notice the comma...;
+#X text 106 116 ^;
+#X obj 437 192 drip;
+#X obj 396 192 comma;
+#X msg 417 222 add2 \$1;
+#X msg 372 110 foo 10;
+#X obj 407 171 t b a;
+#X msg 331 82 set;
+#X msg 427 110 bar 20;
+#X msg 417 249 foo 10 \, bar 20 \,;
+#X obj 517 171 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 39 72 0: what we want to do is to;
+#X text 299 64 1: reset the message;
+#X text 375 92 2: add parts;
+#X text 467 153 (or click the message directly);
+#X text 453 142 3: send the message;
+#X connect 3 0 6 0;
+#X connect 6 0 4 0;
+#X connect 6 1 5 0;
+#X connect 10 0 12 0;
+#X connect 11 0 12 0;
+#X connect 12 0 17 0;
+#X connect 13 0 14 0;
+#X connect 14 0 11 0;
+#X connect 14 1 10 0;
+#X connect 15 0 17 0;
+#X connect 16 0 14 0;
+#X connect 17 0 6 0;
+#X connect 18 0 17 0;
diff --git a/help/d/d0.gif b/help/d/d0.gif
new file mode 100644
index 0000000..89fd454
--- /dev/null
+++ b/help/d/d0.gif
Binary files differ
diff --git a/help/d/d1.gif b/help/d/d1.gif
new file mode 100644
index 0000000..3bdd5b6
--- /dev/null
+++ b/help/d/d1.gif
Binary files differ
diff --git a/help/d/d10.gif b/help/d/d10.gif
new file mode 100644
index 0000000..13941b5
--- /dev/null
+++ b/help/d/d10.gif
Binary files differ
diff --git a/help/d/d11.gif b/help/d/d11.gif
new file mode 100644
index 0000000..05489a9
--- /dev/null
+++ b/help/d/d11.gif
Binary files differ
diff --git a/help/d/d12.gif b/help/d/d12.gif
new file mode 100644
index 0000000..b6f2e79
--- /dev/null
+++ b/help/d/d12.gif
Binary files differ
diff --git a/help/d/d13.gif b/help/d/d13.gif
new file mode 100644
index 0000000..95ac806
--- /dev/null
+++ b/help/d/d13.gif
Binary files differ
diff --git a/help/d/d14.gif b/help/d/d14.gif
new file mode 100644
index 0000000..c820bcb
--- /dev/null
+++ b/help/d/d14.gif
Binary files differ
diff --git a/help/d/d15.gif b/help/d/d15.gif
new file mode 100644
index 0000000..aadd006
--- /dev/null
+++ b/help/d/d15.gif
Binary files differ
diff --git a/help/d/d16.gif b/help/d/d16.gif
new file mode 100644
index 0000000..b6b7429
--- /dev/null
+++ b/help/d/d16.gif
Binary files differ
diff --git a/help/d/d17.gif b/help/d/d17.gif
new file mode 100644
index 0000000..dbc581a
--- /dev/null
+++ b/help/d/d17.gif
Binary files differ
diff --git a/help/d/d18.gif b/help/d/d18.gif
new file mode 100644
index 0000000..d2699d0
--- /dev/null
+++ b/help/d/d18.gif
Binary files differ
diff --git a/help/d/d19.gif b/help/d/d19.gif
new file mode 100644
index 0000000..082ad9a
--- /dev/null
+++ b/help/d/d19.gif
Binary files differ
diff --git a/help/d/d2.gif b/help/d/d2.gif
new file mode 100644
index 0000000..c1cd34f
--- /dev/null
+++ b/help/d/d2.gif
Binary files differ
diff --git a/help/d/d20.gif b/help/d/d20.gif
new file mode 100644
index 0000000..2bf3398
--- /dev/null
+++ b/help/d/d20.gif
Binary files differ
diff --git a/help/d/d21.gif b/help/d/d21.gif
new file mode 100644
index 0000000..e1b9463
--- /dev/null
+++ b/help/d/d21.gif
Binary files differ
diff --git a/help/d/d22.gif b/help/d/d22.gif
new file mode 100644
index 0000000..b33a110
--- /dev/null
+++ b/help/d/d22.gif
Binary files differ
diff --git a/help/d/d23.gif b/help/d/d23.gif
new file mode 100644
index 0000000..cef38bf
--- /dev/null
+++ b/help/d/d23.gif
Binary files differ
diff --git a/help/d/d24.gif b/help/d/d24.gif
new file mode 100644
index 0000000..629442d
--- /dev/null
+++ b/help/d/d24.gif
Binary files differ
diff --git a/help/d/d25.gif b/help/d/d25.gif
new file mode 100644
index 0000000..87b766a
--- /dev/null
+++ b/help/d/d25.gif
Binary files differ
diff --git a/help/d/d26.gif b/help/d/d26.gif
new file mode 100644
index 0000000..3a45164
--- /dev/null
+++ b/help/d/d26.gif
Binary files differ
diff --git a/help/d/d27.gif b/help/d/d27.gif
new file mode 100644
index 0000000..257f589
--- /dev/null
+++ b/help/d/d27.gif
Binary files differ
diff --git a/help/d/d28.gif b/help/d/d28.gif
new file mode 100644
index 0000000..0de8ba8
--- /dev/null
+++ b/help/d/d28.gif
Binary files differ
diff --git a/help/d/d29.gif b/help/d/d29.gif
new file mode 100644
index 0000000..588f65c
--- /dev/null
+++ b/help/d/d29.gif
Binary files differ
diff --git a/help/d/d3.gif b/help/d/d3.gif
new file mode 100644
index 0000000..1d6528b
--- /dev/null
+++ b/help/d/d3.gif
Binary files differ
diff --git a/help/d/d30.gif b/help/d/d30.gif
new file mode 100644
index 0000000..1962cb8
--- /dev/null
+++ b/help/d/d30.gif
Binary files differ
diff --git a/help/d/d31.gif b/help/d/d31.gif
new file mode 100644
index 0000000..4b5dd54
--- /dev/null
+++ b/help/d/d31.gif
Binary files differ
diff --git a/help/d/d32.gif b/help/d/d32.gif
new file mode 100644
index 0000000..37391dc
--- /dev/null
+++ b/help/d/d32.gif
Binary files differ
diff --git a/help/d/d33.gif b/help/d/d33.gif
new file mode 100644
index 0000000..5ce47b2
--- /dev/null
+++ b/help/d/d33.gif
Binary files differ
diff --git a/help/d/d34.gif b/help/d/d34.gif
new file mode 100644
index 0000000..29f5804
--- /dev/null
+++ b/help/d/d34.gif
Binary files differ
diff --git a/help/d/d35.gif b/help/d/d35.gif
new file mode 100644
index 0000000..0f2ac0f
--- /dev/null
+++ b/help/d/d35.gif
Binary files differ
diff --git a/help/d/d36.gif b/help/d/d36.gif
new file mode 100644
index 0000000..2c59cf6
--- /dev/null
+++ b/help/d/d36.gif
Binary files differ
diff --git a/help/d/d37.gif b/help/d/d37.gif
new file mode 100644
index 0000000..290e514
--- /dev/null
+++ b/help/d/d37.gif
Binary files differ
diff --git a/help/d/d38.gif b/help/d/d38.gif
new file mode 100644
index 0000000..246422c
--- /dev/null
+++ b/help/d/d38.gif
Binary files differ
diff --git a/help/d/d39.gif b/help/d/d39.gif
new file mode 100644
index 0000000..c09316e
--- /dev/null
+++ b/help/d/d39.gif
Binary files differ
diff --git a/help/d/d4.gif b/help/d/d4.gif
new file mode 100644
index 0000000..16c157c
--- /dev/null
+++ b/help/d/d4.gif
Binary files differ
diff --git a/help/d/d40.gif b/help/d/d40.gif
new file mode 100644
index 0000000..15a4f98
--- /dev/null
+++ b/help/d/d40.gif
Binary files differ
diff --git a/help/d/d41.gif b/help/d/d41.gif
new file mode 100644
index 0000000..a618a8a
--- /dev/null
+++ b/help/d/d41.gif
Binary files differ
diff --git a/help/d/d42.gif b/help/d/d42.gif
new file mode 100644
index 0000000..0a2f7ab
--- /dev/null
+++ b/help/d/d42.gif
Binary files differ
diff --git a/help/d/d43.gif b/help/d/d43.gif
new file mode 100644
index 0000000..9a52db3
--- /dev/null
+++ b/help/d/d43.gif
Binary files differ
diff --git a/help/d/d44.gif b/help/d/d44.gif
new file mode 100644
index 0000000..b649b7c
--- /dev/null
+++ b/help/d/d44.gif
Binary files differ
diff --git a/help/d/d45.gif b/help/d/d45.gif
new file mode 100644
index 0000000..6926b51
--- /dev/null
+++ b/help/d/d45.gif
Binary files differ
diff --git a/help/d/d46.gif b/help/d/d46.gif
new file mode 100644
index 0000000..ef6966c
--- /dev/null
+++ b/help/d/d46.gif
Binary files differ
diff --git a/help/d/d47.gif b/help/d/d47.gif
new file mode 100644
index 0000000..f22a248
--- /dev/null
+++ b/help/d/d47.gif
Binary files differ
diff --git a/help/d/d48.gif b/help/d/d48.gif
new file mode 100644
index 0000000..b76e2e2
--- /dev/null
+++ b/help/d/d48.gif
Binary files differ
diff --git a/help/d/d49.gif b/help/d/d49.gif
new file mode 100644
index 0000000..4db26a3
--- /dev/null
+++ b/help/d/d49.gif
Binary files differ
diff --git a/help/d/d5.gif b/help/d/d5.gif
new file mode 100644
index 0000000..5245f49
--- /dev/null
+++ b/help/d/d5.gif
Binary files differ
diff --git a/help/d/d50.gif b/help/d/d50.gif
new file mode 100644
index 0000000..acae768
--- /dev/null
+++ b/help/d/d50.gif
Binary files differ
diff --git a/help/d/d51.gif b/help/d/d51.gif
new file mode 100644
index 0000000..345177e
--- /dev/null
+++ b/help/d/d51.gif
Binary files differ
diff --git a/help/d/d52.gif b/help/d/d52.gif
new file mode 100644
index 0000000..371ee22
--- /dev/null
+++ b/help/d/d52.gif
Binary files differ
diff --git a/help/d/d53.gif b/help/d/d53.gif
new file mode 100644
index 0000000..0aaeed8
--- /dev/null
+++ b/help/d/d53.gif
Binary files differ
diff --git a/help/d/d54.gif b/help/d/d54.gif
new file mode 100644
index 0000000..4eae9e5
--- /dev/null
+++ b/help/d/d54.gif
Binary files differ
diff --git a/help/d/d55.gif b/help/d/d55.gif
new file mode 100644
index 0000000..f7579f0
--- /dev/null
+++ b/help/d/d55.gif
Binary files differ
diff --git a/help/d/d56.gif b/help/d/d56.gif
new file mode 100644
index 0000000..56157aa
--- /dev/null
+++ b/help/d/d56.gif
Binary files differ
diff --git a/help/d/d57.gif b/help/d/d57.gif
new file mode 100644
index 0000000..eba1418
--- /dev/null
+++ b/help/d/d57.gif
Binary files differ
diff --git a/help/d/d58.gif b/help/d/d58.gif
new file mode 100644
index 0000000..9952fb4
--- /dev/null
+++ b/help/d/d58.gif
Binary files differ
diff --git a/help/d/d59.gif b/help/d/d59.gif
new file mode 100644
index 0000000..ec69b2c
--- /dev/null
+++ b/help/d/d59.gif
Binary files differ
diff --git a/help/d/d6.gif b/help/d/d6.gif
new file mode 100644
index 0000000..fd27e6d
--- /dev/null
+++ b/help/d/d6.gif
Binary files differ
diff --git a/help/d/d60.gif b/help/d/d60.gif
new file mode 100644
index 0000000..8cfd531
--- /dev/null
+++ b/help/d/d60.gif
Binary files differ
diff --git a/help/d/d61.gif b/help/d/d61.gif
new file mode 100644
index 0000000..937089a
--- /dev/null
+++ b/help/d/d61.gif
Binary files differ
diff --git a/help/d/d62.gif b/help/d/d62.gif
new file mode 100644
index 0000000..1ac6be2
--- /dev/null
+++ b/help/d/d62.gif
Binary files differ
diff --git a/help/d/d63.gif b/help/d/d63.gif
new file mode 100644
index 0000000..3642bb1
--- /dev/null
+++ b/help/d/d63.gif
Binary files differ
diff --git a/help/d/d7.gif b/help/d/d7.gif
new file mode 100644
index 0000000..dd74b47
--- /dev/null
+++ b/help/d/d7.gif
Binary files differ
diff --git a/help/d/d8.gif b/help/d/d8.gif
new file mode 100644
index 0000000..59251c0
--- /dev/null
+++ b/help/d/d8.gif
Binary files differ
diff --git a/help/d/d9.gif b/help/d/d9.gif
new file mode 100644
index 0000000..782e7b9
--- /dev/null
+++ b/help/d/d9.gif
Binary files differ
diff --git a/help/dinlet~-help.pd b/help/dinlet~-help.pd
new file mode 100644
index 0000000..8033afe
--- /dev/null
+++ b/help/dinlet~-help.pd
@@ -0,0 +1,37 @@
+#N canvas 196 161 422 282 10;
+#X text 6 248 (c) Antoine Rousseau 2001;
+#X obj 9 5 dinlet~;
+#X text 66 6 A signal inlet with a default value.;
+#N canvas 178 154 300 161 --- 0;
+#X obj 108 70 unsig~ 50;
+#X obj 108 96 outlet;
+#X obj 196 71 unsig~ 50;
+#X obj 196 97 outlet;
+#X obj 108 43 dinlet~ 1;
+#X obj 196 44 dinlet~ 2;
+#X obj 29 70 unsig~ 50;
+#X obj 29 96 outlet;
+#X obj 29 43 inlet~;
+#X connect 0 0 1 0;
+#X connect 2 0 3 0;
+#X connect 4 0 0 0;
+#X connect 5 0 2 0;
+#X connect 6 0 7 0;
+#X connect 8 0 6 0;
+#X restore 112 100 pd ---;
+#X floatatom 130 158 5 0 0;
+#X floatatom 33 159 5 0 0;
+#X floatatom 242 157 5 0 0;
+#X obj 129 56 sig~ 5;
+#X text 3 180 normal inlet~;
+#X text 129 177 dinlet~ with;
+#X text 128 192 default 1;
+#X text 242 177 dinlet~ with;
+#X text 241 192 default 2;
+#X text 199 61 try connect and deconnect;
+#X text 198 77 sig~ object to each of;
+#X text 198 93 the subpatch inlets.;
+#X connect 3 0 5 0;
+#X connect 3 1 4 0;
+#X connect 3 2 6 0;
+#X connect 7 0 3 2;
diff --git a/help/dispatch-help.pd b/help/dispatch-help.pd
new file mode 100644
index 0000000..16231ef
--- /dev/null
+++ b/help/dispatch-help.pd
@@ -0,0 +1,65 @@
+#N canvas 479 347 565 404 10;
+#X obj 0 0 cnv 8 100 60 empty empty dispatch 10 20 1 18 -262144 -1109
+0;
+#X obj 40 131 r foo1-rcv;
+#X obj 40 151 print foo1;
+#X obj 121 131 r foo2-rcv;
+#X obj 121 151 print foo2;
+#X obj 198 132 r foo3-rcv;
+#X obj 198 152 print foo3;
+#X obj 293 78 dispatch foo 1 3;
+#X text 291 60 args: name min-index max-index;
+#X msg 310 102 2 truc;
+#X text 132 12 link several pairs of send/receive addresses to;
+#X msg 39 82 f1snd;
+#X msg 119 83 f2snd;
+#X msg 197 83 f3snd;
+#X obj 39 102 s foo1-snd;
+#X obj 119 103 s foo2-snd;
+#X obj 197 103 s foo3-snd;
+#X obj 310 154 r foo-snd;
+#X obj 310 122 s foo-rcv;
+#X obj 310 175 print foo-snd;
+#X text 406 162 one "send" from all;
+#X text 382 110 one "receive" to all;
+#X obj 35 208 cnv 15 300 150 empty empty empty 20 12 0 14 -261681 -66577
+0;
+#X obj 77 223 tgl 15 0 \$0-bar1-snd \$0-bar1-rcv bar1 0 -6 1 8 -262144
+-1 -1 0 1;
+#X obj 104 223 tgl 15 0 \$0-bar2-snd \$0-bar2-rcv bar2 0 -6 1 8 -262144
+-1 -1 0 1;
+#X obj 132 223 tgl 15 0 \$0-bar3-snd \$0-bar3-rcv bar3 0 -6 1 8 -262144
+-1 -1 0 1;
+#X obj 49 223 tgl 15 0 \$0-bar0-snd \$0-bar0-rcv bar0 0 -6 1 8 -262144
+-1 -1 0 1;
+#X obj 173 321 s \$0-bar-rcv;
+#X obj 49 276 r \$0-bar-snd;
+#X obj 173 276 hdl 15 0 0 4 empty empty empty 0 -6 0 8 -262144 -1 -1
+1;
+#X obj 185 221 dispatch \$0-bar 0 3;
+#X msg 173 297 \$1 bang;
+#X obj 49 298 unpack f f;
+#X floatatom 49 319 2 0 0 0 - - -;
+#X floatatom 114 320 2 0 0 0 - - -;
+#X text 5 383 (c) Moonix: Antoine Rousseau 2004;
+#X text 362 238 Warning: you HAVE to name;
+#X text 343 254 your boutton buses like this:;
+#X text 362 241 _______;
+#X text 351 280 (notice the -snd and -rcv);
+#X text 351 268 skeletonX-snd skeletonX-rcv;
+#X text 134 24 a single one \, in which datas are prepended by the
+number;
+#X text 134 37 of the receiver/sender.;
+#X connect 1 0 2 0;
+#X connect 3 0 4 0;
+#X connect 5 0 6 0;
+#X connect 9 0 18 0;
+#X connect 11 0 14 0;
+#X connect 12 0 15 0;
+#X connect 13 0 16 0;
+#X connect 17 0 19 0;
+#X connect 28 0 32 0;
+#X connect 29 0 31 0;
+#X connect 31 0 27 0;
+#X connect 32 0 33 0;
+#X connect 32 1 34 0;
diff --git a/help/dripchar-help.pd b/help/dripchar-help.pd
new file mode 100644
index 0000000..6318f36
--- /dev/null
+++ b/help/dripchar-help.pd
@@ -0,0 +1,28 @@
+#N canvas 117 153 430 247 10;
+#X obj 0 0 cnv 8 100 60 empty empty dripchar 10 20 1 18 -262144 -1109
+0;
+#X text 7 221 (c) Moonix: Antoine Rousseau 2003;
+#X obj 131 49 loadbang;
+#X obj 131 95 dripchar;
+#X msg 131 69 symbol Antoine;
+#X text 132 12 drip characters from a symbol to a list;
+#X obj 131 117 unpack s s s s s s s;
+#X symbolatom 131 142 1 0 0;
+#X symbolatom 153 142 1 0 0;
+#X symbolatom 176 142 1 0 0;
+#X symbolatom 198 142 1 0 0;
+#X symbolatom 221 142 1 0 0;
+#X symbolatom 243 142 1 0 0;
+#X symbolatom 266 142 1 0 0;
+#X msg 245 69 symbol moonix_;
+#X connect 2 0 4 0;
+#X connect 3 0 6 0;
+#X connect 4 0 3 0;
+#X connect 6 0 7 0;
+#X connect 6 1 8 0;
+#X connect 6 2 9 0;
+#X connect 6 3 10 0;
+#X connect 6 4 11 0;
+#X connect 6 5 12 0;
+#X connect 6 6 13 0;
+#X connect 14 0 3 0;
diff --git a/help/f2char-help.pd b/help/f2char-help.pd
new file mode 100644
index 0000000..f133288
--- /dev/null
+++ b/help/f2char-help.pd
@@ -0,0 +1,18 @@
+#N canvas 134 318 430 247 10;
+#X obj 0 0 cnv 8 100 60 empty empty char2f_f2char 10 20 1 18 -262144
+-1109 0;
+#X text 7 221 (c) Moonix: Antoine Rousseau 2003;
+#X text 160 14 ascii utilities;
+#X obj 131 115 char2f;
+#X floatatom 131 136 5 0 0;
+#X msg 131 69 symbol A;
+#X obj 131 173 f2char;
+#X symbolatom 131 194 2 0 0;
+#X obj 131 49 loadbang;
+#X msg 216 70 symbol a;
+#X connect 3 0 4 0;
+#X connect 4 0 6 0;
+#X connect 5 0 3 0;
+#X connect 6 0 7 0;
+#X connect 8 0 5 0;
+#X connect 9 0 3 0;
diff --git a/help/f2s-help.pd b/help/f2s-help.pd
new file mode 100644
index 0000000..005754a
--- /dev/null
+++ b/help/f2s-help.pd
@@ -0,0 +1,17 @@
+#N canvas -5 264 527 298 10;
+#X text 27 268 (c) Antoine Rousseau 2001;
+#X obj 44 31 f2s;
+#X text 80 32 A float-to-symbol converter \, with scientific-mode writing.
+;
+#X floatatom 196 85 5 0 300;
+#X obj 163 136 f2s;
+#X obj 196 106 dbtorms;
+#X symbolatom 163 158 4 0 0;
+#X floatatom 207 158 0 0 0;
+#X text 244 85 Touch this;
+#X text 57 196 The idea: many decades in an always 4 characters long
+symbol...;
+#X connect 3 0 5 0;
+#X connect 4 0 6 0;
+#X connect 5 0 4 0;
+#X connect 5 0 7 0;
diff --git a/help/gamme-help.pd b/help/gamme-help.pd
new file mode 100644
index 0000000..8f87eb0
--- /dev/null
+++ b/help/gamme-help.pd
@@ -0,0 +1,171 @@
+#N canvas 246 348 520 515 10;
+#X text 10 491 (c) Antoine Rousseau 2001;
+#X text 85 3 gamme: a musical scale selector.;
+#X obj 113 187 gamme 90 40 1 0 0 0 1 0 0 1 0 0 0 0;
+#X floatatom 51 244 6 0 0 0 - - -;
+#X floatatom 134 71 4 0 0 0 - - -;
+#X floatatom 33 78 4 0 0 0 - - -;
+#X floatatom 154 244 4 0 0 0 - - -;
+#X msg 280 256 set \$1 \$2;
+#X obj 280 288 gamme 90 40 1 0 0 0 1 0 0 1 0 0 0 0;
+#X msg 401 177 getall;
+#X floatatom 322 336 4 0 0 0 - - -;
+#X floatatom 282 72 6 0 0 0 - - -;
+#X msg 282 138 round \$1 \$2;
+#X obj 282 116 pack f f;
+#X floatatom 363 71 4 0 200 0 - - -;
+#X obj 281 227 print changed;
+#X obj 134 119 pack f f;
+#X floatatom 190 71 4 0 0 0 - - -;
+#X obj 156 99 t b f;
+#X msg 134 141 get \$1 \$2;
+#X text 126 53 octave;
+#X text 188 53 note;
+#X text 271 56 semitone;
+#X text 344 55 rounding strength;
+#X obj 303 93 t b f;
+#X text 19 59 semitone;
+#X text 152 33 ARPEGE;
+#X text 28 39 FILTER;
+#X text 324 36 ROUNDING;
+#X text 51 263 Result;
+#X text 139 261 Number of;
+#X text 127 273 selected notes;
+#X text 377 238 in the key set.;
+#X text 383 225 Last change;
+#X text 371 158 get all the key set.;
+#N canvas 483 118 375 520 audio 0;
+#X obj 4 356 gamme 90 40 1 0 1 0 1 0 0 1 0 1 0 0;
+#X obj 28 464 *~;
+#X obj 4 419 mtof;
+#X obj 4 442 osc~;
+#N canvas 394 93 600 400 env 0;
+#X obj 19 122 inlet;
+#X obj 105 121 inlet;
+#X msg 19 143 bang;
+#X obj 89 280 line~;
+#X obj 114 329 outlet~;
+#X obj 114 307 *~;
+#X obj 130 280 +~ 1;
+#X obj 130 258 *~ 0.6;
+#X obj 130 237 osc~ 12;
+#X msg 89 228 0 \$1;
+#X obj 89 206 200;
+#X obj 48 206 0.2;
+#X obj 64 121 inlet;
+#X text 18 101 trig;
+#X text 62 101 vol;
+#X text 103 102 sustain;
+#X text 133 219 lfo...;
+#X msg 48 228 \$1 2;
+#X obj 89 183 delay 2;
+#X connect 0 0 2 0;
+#X connect 1 0 10 1;
+#X connect 2 0 11 0;
+#X connect 2 0 18 0;
+#X connect 3 0 5 0;
+#X connect 5 0 4 0;
+#X connect 6 0 5 1;
+#X connect 7 0 6 0;
+#X connect 8 0 7 0;
+#X connect 9 0 3 0;
+#X connect 10 0 9 0;
+#X connect 11 0 17 0;
+#X connect 12 0 11 1;
+#X connect 17 0 3 0;
+#X connect 18 0 10 0;
+#X restore 44 441 pd env;
+#X floatatom 51 236 5 0 0 0 - - -;
+#X obj 17 499 dac~;
+#X obj 62 421 pow 4;
+#X obj 4 189 metro 180;
+#X obj 4 211 i;
+#X obj 4 162 tgl 20 0 empty empty play 0 -8 1 10 -262144 -1 -1 1 1
+;
+#X obj 29 211 + 1;
+#X obj 4 286 spigot;
+#X obj 49 286 == 0;
+#X obj 54 211 mod 16;
+#X obj 91 287 spigot;
+#X obj 136 287 == 1;
+#X msg 91 309 get 4 \$1;
+#X obj 233 251 unpack f;
+#X obj 188 279 spigot;
+#X msg 188 345 round \$1 \$2;
+#X obj 188 323 pack f f;
+#X obj 233 279 == 2;
+#X obj 4 306 + 60;
+#X obj 188 301 + 60.05;
+#X obj 191 375 hsl 50 10 0 500 0 1 empty empty Sustain -2 -6 1 10 -262144
+-1 -1 1700 1;
+#X obj 52 165 hsl 50 10 5 500 0 1 empty empty Metro(ms) -2 -6 1 10
+-262144 -1 -1 1200 1;
+#X obj 318 165 vsl 10 40 0 100 0 1 empty empty Round 0 -8 1 10 -262144
+-1 -1 600 1;
+#X obj 191 486 hsl 60 15 0 1 0 1 empty empty Volume -2 -6 1 10 -258699
+-1 -1 4300 1;
+#X obj 149 88 cnv 15 90 47 empty empty filter/arpeg/round 2 8 1 10
+-233017 -1 0;
+#X obj 149 162 hdl 30 0 1 3 empty empty empty 20 8 0 8 -262144 -1 -1
+0;
+#X obj 13 328 inlet;
+#X connect 0 0 4 0;
+#X connect 0 0 2 0;
+#X connect 1 0 6 0;
+#X connect 1 0 6 1;
+#X connect 2 0 3 0;
+#X connect 3 0 1 0;
+#X connect 4 0 1 1;
+#X connect 5 0 15 0;
+#X connect 5 0 12 0;
+#X connect 5 0 19 0;
+#X connect 7 0 4 1;
+#X connect 8 0 9 0;
+#X connect 9 0 5 0;
+#X connect 9 0 11 0;
+#X connect 10 0 8 0;
+#X connect 11 0 14 0;
+#X connect 12 0 23 0;
+#X connect 13 0 12 1;
+#X connect 14 0 9 1;
+#X connect 15 0 17 0;
+#X connect 16 0 15 1;
+#X connect 17 0 0 0;
+#X connect 18 0 16 0;
+#X connect 18 0 22 0;
+#X connect 18 0 13 0;
+#X connect 19 0 24 0;
+#X connect 20 0 0 0;
+#X connect 21 0 20 0;
+#X connect 22 0 19 1;
+#X connect 23 0 0 0;
+#X connect 24 0 21 0;
+#X connect 25 0 4 2;
+#X connect 26 0 8 1;
+#X connect 27 0 21 1;
+#X connect 28 0 7 0;
+#X connect 30 0 18 0;
+#X connect 31 0 0 0;
+#X coords 0 0 1 1 210 110 1;
+#X restore 33 325 pd audio demo;
+#X connect 2 0 3 0;
+#X connect 2 1 6 0;
+#X connect 2 2 7 0;
+#X connect 2 2 15 0;
+#X connect 4 0 16 0;
+#X connect 5 0 2 0;
+#X connect 7 0 8 0;
+#X connect 7 0 35 0;
+#X connect 8 1 10 0;
+#X connect 9 0 2 0;
+#X connect 11 0 13 0;
+#X connect 12 0 2 0;
+#X connect 13 0 12 0;
+#X connect 14 0 24 0;
+#X connect 16 0 19 0;
+#X connect 17 0 18 0;
+#X connect 18 0 16 0;
+#X connect 18 1 16 1;
+#X connect 19 0 2 0;
+#X connect 24 0 13 0;
+#X connect 24 1 13 1;
diff --git a/help/image-help.pd b/help/image-help.pd
new file mode 100644
index 0000000..12a5e9f
--- /dev/null
+++ b/help/image-help.pd
@@ -0,0 +1,104 @@
+#N canvas 150 138 585 548 10;
+#X obj 0 0 cnv 8 100 60 empty empty image 20 20 1 18 -262144 -1109
+0;
+#X text 14 510 (c) moonix: Antoine Rousseau 2004;
+#X text 118 15 image viewer;
+#X text 79 33 usage: image image_symbol [type];
+#X text 97 48 if type=0 (or absent) \, image_symbol is a file.;
+#X text 444 63 see "load" and "set";
+#X text 98 63 if type=1 \, image_symbol means a pre-loaded image \;
+;
+#X text 248 510 \, but it's a hack of Gunter Geiger's image...;
+#X obj 112 134 cnv 15 80 40 empty empty empty 20 12 0 14 -1 -66577
+0;
+#X obj 122 148 image play.gif 0;
+#X obj 348 216 cnv 15 20 20 empty empty empty 20 12 0 14 -1 -66577
+0;
+#X obj 372 197 t a;
+#X msg 424 105 open play.gif;
+#X msg 425 125 open playy.gif;
+#X msg 424 144 open rec.gif;
+#X msg 424 162 open pause.gif;
+#X msg 424 180 open sinw.gif;
+#X msg 425 198 open squarew.gif;
+#X msg 425 215 open saww.gif;
+#X obj 360 227 image play.gif 0;
+#X obj 136 148 image rec.gif 0;
+#X obj 152 148 image pause.gif 0;
+#X obj 185 144 image sinw.gif 0;
+#X obj 185 156 image squarew.gif 0;
+#X obj 185 168 image saww.gif 0;
+#N canvas 183 192 77 40 /SUBPATCH/ 0;
+#X obj 87 205 t a;
+#X msg 127 127 open sinw.gif;
+#X msg 146 150 open squarew.gif;
+#X msg 165 171 open saww.gif;
+#X obj -1 0 tgl 40 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1;
+#X obj 0 1 cnv 15 40 40 empty empty empty 20 12 0 14 -1 -66577 0;
+#X obj 26 20 image sinw.gif 0;
+#X obj 127 84 i;
+#X obj 153 85 + 1;
+#X obj 179 85 mod 3;
+#X obj 127 105 sel 0 1 2;
+#X obj 127 63 b;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 11 0;
+#X connect 7 0 8 0;
+#X connect 7 0 10 0;
+#X connect 8 0 9 0;
+#X connect 9 0 7 1;
+#X connect 10 0 1 0;
+#X connect 10 1 2 0;
+#X connect 10 2 3 0;
+#X connect 11 0 7 0;
+#X coords 0 0 1 1 40 40 1;
+#X restore 246 133 pd;
+#X text 241 118 click !;
+#X obj 65 348 t f f;
+#X obj 65 410 pack s s;
+#X msg 65 430 load \$1 \$2;
+#X msg 295 397 set \$1;
+#X obj 298 304 hsl 128 15 0 63 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 295 326 i;
+#X obj 202 446 image d15 1;
+#X obj 295 349 change;
+#X obj 65 370 makesymbol d%s;
+#X obj 95 390 makesymbol d/d%s.gif;
+#X obj 295 376 makesymbol d%s;
+#X text 6 253 For animations \, it's beter to preload images:;
+#X obj 402 377 loadbang;
+#X msg 402 397 open rec.gif;
+#X text 95 274 1: load img_sym file;
+#X text 291 287 2: set img_sym;
+#X text 270 443 rem: when a img_symbol is loaded \, it;
+#X text 305 455 can be used in any image object.;
+#X text 17 94 ONLY GIF FILES ACCEPTED !! (because of Tk...);
+#X msg 62 276 64;
+#X obj 63 299 until;
+#X obj 64 325 float;
+#X obj 101 325 + 1;
+#X connect 12 0 11 0;
+#X connect 13 0 11 0;
+#X connect 14 0 11 0;
+#X connect 15 0 11 0;
+#X connect 16 0 11 0;
+#X connect 17 0 11 0;
+#X connect 18 0 11 0;
+#X connect 27 0 35 0;
+#X connect 27 1 36 0;
+#X connect 28 0 29 0;
+#X connect 31 0 32 0;
+#X connect 32 0 34 0;
+#X connect 34 0 37 0;
+#X connect 35 0 28 0;
+#X connect 36 0 28 1;
+#X connect 37 0 30 0;
+#X connect 39 0 40 0;
+#X connect 46 0 47 0;
+#X connect 47 0 48 0;
+#X connect 48 0 27 0;
+#X connect 48 0 49 0;
+#X connect 49 0 48 1;
diff --git a/help/joystik-help.pd b/help/joystik-help.pd
new file mode 100644
index 0000000..7915d33
--- /dev/null
+++ b/help/joystik-help.pd
@@ -0,0 +1,44 @@
+#N canvas 42 155 422 423 10;
+#X obj 173 137 tgl 20 1 empty empty empty 20 8 0 8 -262144 -1 -1 1
+1;
+#X text 103 121 in order to work.;
+#X text 25 391 (c) Antoine Rousseau 2001;
+#X obj 233 236 route 0 1;
+#X obj 307 235 route 0 1;
+#X obj 307 267 tgl 15 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 336 268 tgl 15 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X floatatom 225 265 4 0 0;
+#X floatatom 262 265 4 0 0;
+#X obj 45 206 joystik;
+#X obj 24 236 route 0 1;
+#X obj 112 238 route 0 1;
+#X obj 112 270 tgl 15 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 141 270 tgl 15 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X floatatom 17 267 4 0 0;
+#X floatatom 53 267 4 0 0;
+#X obj 21 19 joystik;
+#X text 104 109 joystiks must be switched on;
+#X text 36 290 Axis;
+#X text 112 291 Buttons;
+#X text 78 20 A joystik reporter.;
+#X text 28 55 args: [joystick number [is_usb]];
+#X obj 233 207 joystik 1 0;
+#X text 22 345 CAUTION: usb untested !;
+#X connect 0 0 9 0;
+#X connect 0 0 22 0;
+#X connect 3 0 7 0;
+#X connect 3 1 8 0;
+#X connect 4 0 5 0;
+#X connect 4 1 6 0;
+#X connect 9 0 10 0;
+#X connect 9 1 11 0;
+#X connect 10 0 14 0;
+#X connect 10 1 15 0;
+#X connect 11 0 12 0;
+#X connect 11 1 13 0;
+#X connect 22 0 3 0;
+#X connect 22 1 4 0;
diff --git a/help/makecolor-help.pd b/help/makecolor-help.pd
new file mode 100644
index 0000000..ac52e81
--- /dev/null
+++ b/help/makecolor-help.pd
@@ -0,0 +1,18 @@
+#N canvas 36 264 527 298 10;
+#X text 27 268 (c) Antoine Rousseau 2001;
+#X obj 18 27 makecolor;
+#X text 91 22 A color-symbol builder \, transforming RGB values in
+one hexa symbol.;
+#X obj 161 149 makecolor;
+#X symbolatom 161 186 10 0 0;
+#X floatatom 144 85 5 0 0;
+#X floatatom 190 85 5 0 0;
+#X floatatom 235 86 5 0 0;
+#X obj 161 127 b;
+#X connect 3 0 4 0;
+#X connect 5 0 3 0;
+#X connect 6 0 3 1;
+#X connect 6 0 8 0;
+#X connect 7 0 3 2;
+#X connect 7 0 8 0;
+#X connect 8 0 3 0;
diff --git a/help/mknob-help.pd b/help/mknob-help.pd
new file mode 100644
index 0000000..90f4fb2
--- /dev/null
+++ b/help/mknob-help.pd
@@ -0,0 +1,53 @@
+#N canvas 19 167 677 325 10;
+#X obj 0 0 cnv 8 100 60 empty empty mknob 20 20 1 18 -262144 -1109
+0;
+#X floatatom 55 149 5 0 0 0 - - -;
+#X floatatom 55 68 5 0 0 0 - - -;
+#X text 104 208 Just an adaptation of musil's slider.;
+#X obj 138 224 hsl 128 15 0 127 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X text 103 222 See:;
+#X msg 3 107 set \$1;
+#X floatatom 190 114 5 0 0 0 - - -;
+#X obj 190 95 r foo-snd;
+#X floatatom 190 60 5 0 0 0 - - -;
+#X obj 190 76 s foo-rcv;
+#X text 135 12 gui-round-knob;
+#X text 2 302 (c) moonix: Antoine Rousseau 2003;
+#X obj 149 57 mknob 25 100 0 100 0 0 foo-snd foo-rcv empty -2 -6 192
+8 -225271 -1 -1 0 1;
+#X obj 55 85 mknob 30 100 0 127 0 0 empty empty empty -2 -6 0 8 -241291
+-24198 -1 0 1;
+#X obj 55 126 mknob 15 100 127 0 0 0 empty empty empty -2 -6 0 8 -258699
+-24198 -1 0 1;
+#X text 306 40 "mouse" parameter sets mouse;
+#X text 309 50 excursion for full range.;
+#X text 309 62 Set it with "size" parameter:;
+#X obj 398 201 mknob 25 -1 0 127 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X msg 369 96 size 25 300;
+#X msg 398 119 size 25 10;
+#X text 452 96 low sensibility;
+#X text 474 120 high sens;
+#X text 494 142 default;
+#X msg 413 141 size 25 100;
+#X text 497 164 angular control;
+#X msg 427 165 size 25 0;
+#X text 518 187 full angular control;
+#X msg 443 188 size 25 -1;
+#X text 273 253 Note: there is in the sources a patch named mknob.pd.tk.diff
+to add (in pd.tk) mknob in the Pd "Put" menu \, and to give the hotkey
+"Alt-k" to it. It will only work for Pd0.37 \, but it can help to do
+the modif by hand for another version.;
+#X connect 2 0 14 0;
+#X connect 6 0 14 0;
+#X connect 8 0 7 0;
+#X connect 9 0 10 0;
+#X connect 14 0 15 0;
+#X connect 15 0 6 0;
+#X connect 15 0 1 0;
+#X connect 20 0 19 0;
+#X connect 21 0 19 0;
+#X connect 25 0 19 0;
+#X connect 27 0 19 0;
+#X connect 29 0 19 0;
diff --git a/help/panvol~-help.pd b/help/panvol~-help.pd
new file mode 100644
index 0000000..f7ad351
--- /dev/null
+++ b/help/panvol~-help.pd
@@ -0,0 +1,34 @@
+#N canvas 117 381 340 290 10;
+#X obj 0 0 cnv 8 100 60 empty empty panvol~ 10 20 1 18 -262144 -1109
+0;
+#X text 3 269 (c) Moonix: Antoine Rousseau 2003;
+#X text 132 12 pan & volume;
+#X obj 138 69 hsl 60 10 -45 45 0 0 empty empty pan -2 -6 0 8 -262144
+-1 -1 2950 1;
+#X obj 238 61 vsl 10 60 0 1 0 0 empty empty vol 0 -8 0 8 -262144 -1
+-1 5900 1;
+#X floatatom 135 85 5 0 0;
+#X floatatom 238 127 5 0 0;
+#X obj 113 141 panvol~;
+#X obj 94 190 unsig~ 100;
+#X floatatom 94 210 5 0 0;
+#X obj 60 85 osc~ 440;
+#X obj 173 190 unsig~ 100;
+#X floatatom 173 210 5 0 0;
+#X obj 94 170 envrms~;
+#X obj 173 170 envrms~;
+#X obj 60 104 *~ 2;
+#X msg 174 49 0;
+#X connect 3 0 5 0;
+#X connect 4 0 6 0;
+#X connect 5 0 7 1;
+#X connect 6 0 7 2;
+#X connect 7 0 13 0;
+#X connect 7 1 14 0;
+#X connect 8 0 9 0;
+#X connect 10 0 15 0;
+#X connect 11 0 12 0;
+#X connect 13 0 8 0;
+#X connect 14 0 11 0;
+#X connect 15 0 7 0;
+#X connect 16 0 3 0;
diff --git a/help/pause.gif b/help/pause.gif
new file mode 100644
index 0000000..684f755
--- /dev/null
+++ b/help/pause.gif
Binary files differ
diff --git a/help/play.gif b/help/play.gif
new file mode 100644
index 0000000..10ae809
--- /dev/null
+++ b/help/play.gif
Binary files differ
diff --git a/help/playy.gif b/help/playy.gif
new file mode 100644
index 0000000..c710c7e
--- /dev/null
+++ b/help/playy.gif
Binary files differ
diff --git a/help/popen-help.pd b/help/popen-help.pd
new file mode 100644
index 0000000..e37d8e9
--- /dev/null
+++ b/help/popen-help.pd
@@ -0,0 +1,68 @@
+#N canvas 0 195 644 383 10;
+#X obj 0 0 cnv 8 100 60 empty empty popen 10 20 1 18 -262144 -1109
+0;
+#X text 13 362 (c) Moonix: Antoine Rousseau 2003;
+#X msg 31 74 open process;
+#X text 12 57 open: popen for writing;
+#X msg 240 76 ropen process;
+#X text 221 59 ropen: popen for reading;
+#X msg 466 76 close;
+#X text 428 60 close (quit) current process;
+#X text 108 13 processus in/out (linux only);
+#X text 108 26 DANGEROUS: deadlocks are easy!!!!;
+#N canvas 0 0 850 359 example 0;
+#X obj 458 194 popen;
+#X msg 516 167 close;
+#X obj 82 311 popen;
+#X msg 151 261 close;
+#X msg 76 190 list cat to where you want;
+#X msg 24 145 open cat > /tmp/tmp_fifo;
+#X msg 431 138 ropen cat /tmp/tmp_fifo;
+#X obj 38 89 system;
+#X msg 38 67 mkfifo /tmp/tmp_fifo;
+#X obj 76 258 symbol \;;
+#X obj 76 236 t b a;
+#X symbolatom 433 284 0 0 0 0 - - -;
+#X text 10 17 example: fifo read/write. RESPECT THE NUMBERS for commands
+!;
+#X text 430 120 3: open for reading;
+#X msg 92 213 list Caution not to lock your computer...;
+#X text 517 183 6: close reading process;
+#X obj 433 260 l2s;
+#X obj 458 227 print ropen;
+#X text 76 173 4: write to fifo (as many times you want);
+#X text 36 46 1: create the fifo (if not done);
+#X text 147 244 5: close writing process FIRST;
+#X text 23 125 2: open the fifo for writing FIRST;
+#X text 503 248 Caution: popen/ropen waits for a " \; ";
+#X text 565 260 to send its buffer (pd style).;
+#X connect 0 0 17 0;
+#X connect 0 0 16 0;
+#X connect 1 0 0 0;
+#X connect 3 0 2 0;
+#X connect 4 0 10 0;
+#X connect 5 0 2 0;
+#X connect 6 0 0 0;
+#X connect 8 0 7 0;
+#X connect 9 0 2 0;
+#X connect 10 0 9 0;
+#X connect 10 1 2 0;
+#X connect 14 0 10 0;
+#X connect 16 0 11 0;
+#X restore 19 161 pd example;
+#X obj 31 109 popen;
+#X text 20 191 Remarks:;
+#X text 46 204 The danger here comes from the fact processes lauched
+by;
+#X text 47 215 popen runs concurrently with pd: if they are blocking
+\, pd;
+#X text 46 228 is blocking too. Very dangerous if pd has real-time
+priority: it blocks all the sytem. You have to switch off the computer...
+;
+#X text 47 267 It's much safer to use netsend/netreceive in conjonction
+with pdsend/pdreceive.;
+#X obj 206 333 system;
+#X text 46 297 You can use "at now" to lauch programs totally independantly
+from Pd:;
+#X msg 206 313 echo xclock -display 0:0 | at now;
+#X connect 19 0 17 0;
diff --git a/help/readsfv~-help.pd b/help/readsfv~-help.pd
new file mode 100644
index 0000000..5870912
--- /dev/null
+++ b/help/readsfv~-help.pd
@@ -0,0 +1,60 @@
+#N canvas 117 77 546 422 10;
+#X obj 0 0 cnv 8 100 60 empty empty readsfv~ 10 20 1 18 -262144 -1109
+0;
+#X text 4 400 (c) Moonix: Antoine Rousseau 2003;
+#X obj 124 367 dac~;
+#X obj 132 331 readsfv~;
+#X obj 132 188 delay 20;
+#X msg 132 207 start;
+#X msg 193 207 1;
+#X obj 132 158 bng 15 250 50 0 empty empty play -25 4 0 8 -24198 -1
+-1;
+#X obj 183 351 s replay;
+#X obj 132 60 r replay;
+#X obj 159 284 symbol;
+#X msg 159 304 open \$1;
+#X msg 229 283 symbol /usr/local/lib/pd/doc/sound/bell.aiff;
+#X msg 229 262 symbol ../../sound/bell.aiff;
+#X msg 47 298 speed \$1;
+#X obj 266 239 openpanel;
+#X obj 266 220 bng 15 250 50 0 empty empty open 0 -6 1 8 -195568 -1
+-1;
+#X obj 132 126 spigot;
+#X obj 169 109 tgl 15 1 empty empty loop 0 -6 1 8 -241291 -1 -1 1 1
+;
+#X obj 47 58 vsl 15 128 0.08 8 1 0 empty empty speed 0 -8 1 8 -260818
+-1 -1 6965 1;
+#X obj 1 57 init 1;
+#X obj 47 278 f;
+#X text 171 207 (or;
+#X text 220 207 );
+#X obj 57 253 b;
+#X obj 113 106 del 100;
+#X text 129 8 read a big soundfile in direct-to-disk mode;
+#X text 131 20 at variable speed.;
+#X text 230 104 read manual of;
+#X text 390 103 for more details...;
+#X obj 335 102 readsf~;
+#X connect 3 0 2 0;
+#X connect 3 0 2 1;
+#X connect 3 1 8 0;
+#X connect 4 0 5 0;
+#X connect 5 0 3 0;
+#X connect 5 0 24 0;
+#X connect 7 0 4 0;
+#X connect 7 0 10 0;
+#X connect 9 0 25 0;
+#X connect 10 0 11 0;
+#X connect 11 0 3 0;
+#X connect 12 0 10 1;
+#X connect 13 0 10 1;
+#X connect 14 0 3 0;
+#X connect 15 0 10 1;
+#X connect 16 0 15 0;
+#X connect 17 0 7 0;
+#X connect 18 0 17 1;
+#X connect 19 0 21 0;
+#X connect 20 0 19 0;
+#X connect 21 0 14 0;
+#X connect 24 0 21 0;
+#X connect 25 0 17 0;
diff --git a/help/rec.gif b/help/rec.gif
new file mode 100644
index 0000000..d49b027
--- /dev/null
+++ b/help/rec.gif
Binary files differ
diff --git a/help/relativepath-help.pd b/help/relativepath-help.pd
new file mode 100644
index 0000000..b056f4a
--- /dev/null
+++ b/help/relativepath-help.pd
@@ -0,0 +1,13 @@
+#N canvas 14 323 660 379 10;
+#X text 17 352 (c) Antoine Rousseau 2004;
+#X obj 33 108 absolutepath;
+#X symbolatom 33 131 0 0 0;
+#X msg 33 51 symbol absolutepath.pd;
+#X obj 33 220 relativepath;
+#X symbolatom 33 245 0 0 0;
+#X text 14 6 absolutepath / relativepath : use filenames relatively
+to the patch's path.;
+#X connect 1 0 2 0;
+#X connect 2 0 4 0;
+#X connect 3 0 1 0;
+#X connect 4 0 5 0;
diff --git a/help/s2f-help.pd b/help/s2f-help.pd
new file mode 100644
index 0000000..2192924
--- /dev/null
+++ b/help/s2f-help.pd
@@ -0,0 +1,18 @@
+#N canvas 106 74 492 266 10;
+#X obj 0 0 cnv 8 100 60 empty empty s2f 10 20 1 18 -262144 -1109 0
+;
+#X text 1 244 (c) Moonix: Antoine Rousseau 2003;
+#X text 129 8 symbol to float converter;
+#X obj 197 159 s2f;
+#X floatatom 197 184 0 0 0;
+#X symbolatom 197 142 0 0 0;
+#X obj 345 105 makesymbol %s;
+#X msg 48 84 symbol 0.0003125foo;
+#X msg 197 85 symbol 54.123e-3bar;
+#X msg 345 85 13.25;
+#X connect 3 0 4 0;
+#X connect 5 0 3 0;
+#X connect 6 0 5 0;
+#X connect 7 0 5 0;
+#X connect 8 0 5 0;
+#X connect 9 0 6 0;
diff --git a/help/sarray-help.pd b/help/sarray-help.pd
new file mode 100644
index 0000000..157d245
--- /dev/null
+++ b/help/sarray-help.pd
@@ -0,0 +1,93 @@
+#N canvas 158 412 745 484 10;
+#X obj 0 0 cnv 8 100 60 empty empty sarray 10 20 1 18 -262144 -1109
+0;
+#X text 2 467 (c) Moonix: Antoine Rousseau 2003;
+#X msg 74 275 1;
+#X msg 103 275 2;
+#X msg 131 275 3;
+#X symbolatom 139 356 10 0 0;
+#X msg 533 269 reset;
+#X text 109 12 shared array of symbols;
+#X obj 47 146 sarray foo 8;
+#X text 23 48 1) set the length;
+#X msg 47 71 setlen 10;
+#X text 236 43 2) set the nth element;
+#X msg 266 85 set 2 two;
+#X msg 274 106 set 3 three;
+#X obj 258 169 sarray foo;
+#X msg 129 110 print;
+#X msg 44 299 get \$1;
+#X obj 44 320 sarray foo;
+#X obj 44 339 route bang;
+#X msg 159 275 4;
+#X obj 44 359 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 44 275 0;
+#X text 12 256 3) get the nth symbol (first:0);
+#X obj 533 289 sarray foo;
+#X text 1 376 (bang when empty);
+#X text 298 252 4) dump the whole array;
+#X obj 299 379 sarray foo;
+#X msg 299 272 dump;
+#X obj 299 400 print dump;
+#X msg 334 325 dump _null_;
+#X msg 334 345 dump *?!;
+#X text 315 298 specify a default symbol;
+#X text 329 309 for empty elements;
+#X obj 472 175 sarray foo;
+#X text 494 85 specify a default symbol;
+#X text 494 97 for empty elements;
+#X msg 294 147 print;
+#X msg 428 146 print;
+#X text 531 251 6) clear the sarray;
+#X msg 578 269 print;
+#X text 6 165 args: sarray name [length];
+#X text 258 193 args: set [empty_symbol] first_index sym1 [sym2 [sym3...]]]
+;
+#X text 286 425 args: dump [empty_symbol];
+#X msg 258 61 set 0 zero;
+#X text 453 43 3) set many elements;
+#X text 533 134 ...erase one element;
+#X msg 281 127 set 4 four;
+#X msg 57 93 setlen 4;
+#X msg 534 149 set _niet_ 3 _niet_;
+#X msg 499 113 set _ 0 zero un _ trois _ cinq;
+#X msg 472 60 set 0 zero ein zwei drei;
+#X text 528 328 7) switch to another array;
+#X obj 523 370 sarray foo2 4;
+#X msg 523 351 set 0 zero2 one2 two2 three2;
+#X obj 528 442 sarray;
+#X msg 528 402 print;
+#X msg 577 403 setarray foo;
+#X msg 577 422 setarray foo2;
+#X connect 2 0 16 0;
+#X connect 3 0 16 0;
+#X connect 4 0 16 0;
+#X connect 6 0 23 0;
+#X connect 10 0 8 0;
+#X connect 12 0 14 0;
+#X connect 13 0 14 0;
+#X connect 15 0 8 0;
+#X connect 16 0 17 0;
+#X connect 17 0 18 0;
+#X connect 18 0 20 0;
+#X connect 18 1 5 0;
+#X connect 19 0 16 0;
+#X connect 21 0 16 0;
+#X connect 26 0 28 0;
+#X connect 27 0 26 0;
+#X connect 29 0 26 0;
+#X connect 30 0 26 0;
+#X connect 36 0 14 0;
+#X connect 37 0 33 0;
+#X connect 39 0 23 0;
+#X connect 43 0 14 0;
+#X connect 46 0 14 0;
+#X connect 47 0 8 0;
+#X connect 48 0 33 0;
+#X connect 49 0 33 0;
+#X connect 50 0 33 0;
+#X connect 53 0 52 0;
+#X connect 55 0 54 0;
+#X connect 56 0 54 0;
+#X connect 57 0 54 0;
diff --git a/help/saww.gif b/help/saww.gif
new file mode 100644
index 0000000..32997ad
--- /dev/null
+++ b/help/saww.gif
Binary files differ
diff --git a/help/sfread2~-help.pd b/help/sfread2~-help.pd
new file mode 100644
index 0000000..ad8ae16
--- /dev/null
+++ b/help/sfread2~-help.pd
@@ -0,0 +1,60 @@
+#N canvas 38 250 582 490 10;
+#X obj 0 0 cnv 8 100 60 empty empty sfread2~ 10 20 1 18 -262144 -1109
+0;
+#X text 2 459 (c) Moonix: Antoine Rousseau 2003;
+#X text 66 390 Change "mlockall(MCL_FUTURE)" with "mlockall(MCL_CURRENT)
+;
+#X obj 155 262 sfread2~ 2;
+#X msg 155 202 open \$1;
+#X obj 19 151 bng 15 250 50 0 empty empty play 20 8 1 8 -24198 -1 -1
+;
+#X msg 278 225 loop \$1;
+#X obj 278 207 tgl 15 1 empty empty loop 20 8 0 8 -241291 -1 -1 1 1
+;
+#X obj 57 103 tgl 15 1 empty empty interpolation 20 8 1 8 -257472 -1
+-1 1 1;
+#X msg 57 121 interp \$1;
+#X obj 458 181 vsl 15 128 -8 8 0 0 empty empty speed 0 -8 1 8 -260818
+-1 -1 7144 1;
+#X text 135 12 soundfile reader at variable speed (possibly negative)
+\, whith 4-point interpolation and loop.;
+#X obj 154 296 dac~;
+#X obj 155 92 openpanel;
+#X obj 155 72 bng 15 250 50 0 empty empty open 0 -6 1 8 -166441 -1
+-1;
+#X obj 18 179 bng 15 250 50 0 empty empty stop 20 8 1 8 -1 -1 -1;
+#X msg 18 196 0;
+#X obj 148 339 sfread~;
+#X text 43 341 read manual of;
+#X text 202 339 for more details...;
+#X text 235 159 resets sound to position;
+#X text 234 148 start position in samples;
+#X msg 238 174 index 20000;
+#X obj 497 177 loadbang;
+#X msg 497 196 1;
+#X msg 261 99 symbol /usr/local/lib/pd/doc/sound/voice.wav;
+#X msg 261 78 symbol ../../sound/voice.wav;
+#X text 66 414 If not \, the whole file will be loaded in memory when
+opened (use of C function mmap()).;
+#X text 66 401 in s_linux.c... SORRY \, I mean in s_inter.c (since
+0.37...);
+#X text 59 378 CAUTION: you should hack pd sources to have d-t-d working.
+;
+#X connect 3 0 12 0;
+#X connect 3 1 12 1;
+#X connect 4 0 3 0;
+#X connect 5 0 3 0;
+#X connect 6 0 3 0;
+#X connect 7 0 6 0;
+#X connect 8 0 9 0;
+#X connect 9 0 3 0;
+#X connect 10 0 3 1;
+#X connect 13 0 4 0;
+#X connect 14 0 13 0;
+#X connect 15 0 16 0;
+#X connect 16 0 3 0;
+#X connect 22 0 3 0;
+#X connect 23 0 24 0;
+#X connect 24 0 10 0;
+#X connect 25 0 4 0;
+#X connect 26 0 4 0;
diff --git a/help/sin.gif b/help/sin.gif
new file mode 100644
index 0000000..c84ad79
--- /dev/null
+++ b/help/sin.gif
Binary files differ
diff --git a/help/sinw.gif b/help/sinw.gif
new file mode 100644
index 0000000..8bedc66
--- /dev/null
+++ b/help/sinw.gif
Binary files differ
diff --git a/help/slist-help.pd b/help/slist-help.pd
new file mode 100644
index 0000000..f499120
--- /dev/null
+++ b/help/slist-help.pd
@@ -0,0 +1,61 @@
+#N canvas 459 312 690 375 10;
+#X obj 0 0 cnv 8 100 60 empty empty slist 10 20 1 18 -262144 -1109
+0;
+#X text 3 354 (c) Moonix: Antoine Rousseau 2003;
+#X text 109 12 shared list of symbols \, with a "find" feature;
+#X obj 80 107 slist foo;
+#X obj 261 100 slist foo;
+#X text 24 55 1) fill the slist;
+#X msg 261 79 len;
+#X text 260 58 2) get the slist length;
+#X floatatom 319 121 5 0 0;
+#X obj 480 106 slist foo;
+#X msg 451 79 1;
+#X msg 480 79 2;
+#X msg 508 79 3;
+#X symbolatom 509 127 10 0 0;
+#X obj 157 218 slist foo;
+#X text 448 59 3) get the nth symbol (first:1);
+#X msg 21 189 find boo;
+#X msg 225 189 find bar;
+#X floatatom 157 242 5 0 0;
+#X msg 91 189 find bee;
+#X msg 157 189 find baa;
+#X obj 548 212 slist foo;
+#X text 21 168 4) find the index of a symbol (0 = not found);
+#X msg 548 192 reset;
+#X msg 144 77 add baa;
+#X msg 26 77 add boo \, add bee;
+#X obj 378 223 slist foo;
+#X text 364 169 5) print to console;
+#X text 546 171 6) clear the slist;
+#X msg 378 203 print;
+#X text 383 184 (debug);
+#X obj 256 318 slist foo2;
+#X text 256 271 7) switch to another slist;
+#X obj 476 345 slist;
+#X msg 503 296 setlist foo;
+#X msg 503 318 setlist foo2;
+#X msg 460 296 print;
+#X msg 256 297 add boo2 \, add bee2 \, add baa2;
+#X msg 212 297 print;
+#X connect 4 2 8 0;
+#X connect 6 0 4 0;
+#X connect 9 1 13 0;
+#X connect 10 0 9 0;
+#X connect 11 0 9 0;
+#X connect 12 0 9 0;
+#X connect 14 0 18 0;
+#X connect 16 0 14 0;
+#X connect 17 0 14 0;
+#X connect 19 0 14 0;
+#X connect 20 0 14 0;
+#X connect 23 0 21 0;
+#X connect 24 0 3 0;
+#X connect 25 0 3 0;
+#X connect 29 0 26 0;
+#X connect 34 0 33 0;
+#X connect 35 0 33 0;
+#X connect 36 0 33 0;
+#X connect 37 0 31 0;
+#X connect 38 0 31 0;
diff --git a/help/squarew.gif b/help/squarew.gif
new file mode 100644
index 0000000..3e689c7
--- /dev/null
+++ b/help/squarew.gif
Binary files differ
diff --git a/help/ssaw~-help.pd b/help/ssaw~-help.pd
new file mode 100644
index 0000000..25903d1
--- /dev/null
+++ b/help/ssaw~-help.pd
@@ -0,0 +1,21 @@
+#N canvas 106 74 492 266 10;
+#X obj 0 0 cnv 8 100 60 empty empty ssaw 10 20 1 18 -262144 -1109 0
+;
+#X text 8 243 (c) Moonix: Antoine Rousseau 2004;
+#X obj 162 103 ssaw~ 440;
+#X obj 163 149 *~;
+#X obj 162 77 mtof;
+#X floatatom 161 57 5 0 0 0 - - -;
+#X floatatom 207 77 0 0 0 0 - - -;
+#X obj 197 128 hsl 128 15 0 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 159 193 dac~;
+#X text 124 19 sweet sawtooth generator;
+#X text 121 32 (not to much aliasing below 10kHz);
+#X connect 2 0 3 0;
+#X connect 3 0 8 0;
+#X connect 3 0 8 1;
+#X connect 4 0 6 0;
+#X connect 4 0 2 0;
+#X connect 5 0 4 0;
+#X connect 7 0 3 1;
diff --git a/help/tabdump2-help.pd b/help/tabdump2-help.pd
new file mode 100644
index 0000000..b69458c
--- /dev/null
+++ b/help/tabdump2-help.pd
@@ -0,0 +1,31 @@
+#N canvas 21 53 496 358 10;
+#X obj 13 21 tabdump2;
+#X obj 187 37 tabdump;
+#X text 22 332 (c) Antoine Rousseau 2004;
+#X text 104 21 dump the contents of a table as a list;
+#X text 104 37 like zexy's;
+#X text 244 38 but with min/max dumping limits.;
+#N canvas 0 0 450 300 graph5 0;
+#X array \$0-array 10 float 0;
+#X coords 0 1 9 0 100 80 1;
+#X restore 330 71 graph;
+#X obj 17 132 s \$0-array;
+#X msg 17 112 0 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9;
+#X obj 17 92 loadbang;
+#X obj 34 243 tabdump2 \$0-array;
+#X obj 34 269 l2s;
+#X symbolatom 34 293 0 0 0 0 - - -;
+#X obj 258 204 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 22 204 dump 0 5;
+#X msg 95 203 dump 5 10;
+#X text 18 177 dump N M: from N to (M-1);
+#X msg 174 203 dump 5 6;
+#X connect 8 0 7 0;
+#X connect 9 0 8 0;
+#X connect 10 0 11 0;
+#X connect 11 0 12 0;
+#X connect 13 0 10 0;
+#X connect 14 0 10 0;
+#X connect 15 0 10 0;
+#X connect 17 0 10 0;
diff --git a/help/tabenv-help.pd b/help/tabenv-help.pd
new file mode 100644
index 0000000..cb719d0
--- /dev/null
+++ b/help/tabenv-help.pd
@@ -0,0 +1,25 @@
+#N canvas 205 155 534 360 10;
+#X text 22 332 (c) Antoine Rousseau 2001;
+#X obj 21 19 tabenv;
+#X text 78 21 A envelope follower for table (not in real-time).;
+#X text 35 65 args: arrayname [computation_num_points [output_period]]
+;
+#X text 147 151 change the array;
+#X msg 64 181 reset;
+#X msg 64 152 set Array1;
+#X obj 64 255 tabenv Array0;
+#X floatatom 64 283 5 0 0;
+#X msg 64 209 0 44100;
+#X text 125 209 compute 1 sec from the beginning;
+#X text 126 181 reset the computation buffers;
+#X obj 258 86 env~;
+#X text 294 85 );
+#X text 217 86 (like;
+#X text 151 84 );
+#X text 47 86 (like;
+#X obj 90 86 tabplay~;
+#X text 79 38 (in fact it's a mix between tabplay and env~);
+#X connect 5 0 7 0;
+#X connect 6 0 7 0;
+#X connect 7 0 8 0;
+#X connect 9 0 7 0;
diff --git a/help/tabreadl-help.pd b/help/tabreadl-help.pd
new file mode 100644
index 0000000..feebabe
--- /dev/null
+++ b/help/tabreadl-help.pd
@@ -0,0 +1,26 @@
+#N canvas 502 181 672 415 10;
+#X obj 10 11 tabreadl;
+#X text 22 332 (c) Antoine Rousseau 2004;
+#X floatatom 15 173 0 0 0;
+#X floatatom 15 278 0 0 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-array 10 float 0;
+#X coords 0 0 10 10 250 200 1;
+#X restore 362 179 graph;
+#X text 60 276 output = array99[index];
+#X text 34 50 click here to initialize;
+#X text 159 236 creation argument;
+#X text 155 254 gives array name;
+#X text 137 204 change array name;
+#X msg 25 204 set \$0-array99;
+#X msg 33 65 resize 10 \, bounds 0 0 10 10 \, xlabel -0.5 0 1 2 3 4
+5 6 7 8 9 10 \, ylabel -1 0 1 2 3 4 5 6 7 8 9 10 \, 0 1 4 2 8 5 6 1
+4 2 8;
+#X obj 34 139 s \$0-array;
+#X text 110 8 - linear interpolating read from a table;
+#X text 46 174 index(float);
+#X obj 15 245 tabreadl \$0-array;
+#X connect 2 0 15 0;
+#X connect 10 0 15 0;
+#X connect 11 0 12 0;
+#X connect 15 0 3 0;
diff --git a/help/tabsort-help.pd b/help/tabsort-help.pd
new file mode 100644
index 0000000..805f12a
--- /dev/null
+++ b/help/tabsort-help.pd
@@ -0,0 +1,32 @@
+#N canvas 118 208 534 360 10;
+#X text 22 332 (c) Antoine Rousseau 2001;
+#X floatatom 39 303 5 0 0 0 - - -;
+#X obj 21 19 tabsort;
+#X text 20 58 args: source_table dest_table;
+#N canvas 0 0 450 300 graph29 0;
+#X array source 10 float 1;
+#A 0 -0.0571429 -0.985715 -0.942858 -0.857143 -0.757143 -0.542857 -0.171429
+0.528571 0.842858 0.914287;
+#X coords 0 1 9 -1 200 140 1;
+#X restore 51 92 graph;
+#N canvas 0 0 450 300 graph29 0;
+#X array dest 10 float 1;
+#A 0 9 8 7 0 6 5 4 3 2 1;
+#X coords 0 10 9 0 200 140 1;
+#X restore 304 89 graph;
+#X obj 39 282 tabsort source dest;
+#X msg 39 262 10;
+#X text 79 12 write to dest_table the indices of source_table's elements
+sorted by decreasing order (biggest first);
+#X text 38 248 sort the n first elements;
+#X obj 304 264 tabread dest;
+#X obj 304 285 tabread source;
+#X floatatom 304 246 5 0 0 0 - - -;
+#X floatatom 304 305 5 0 0 0 - - -;
+#X text 347 244 try it!;
+#X text 300 321 it should decrease with input;
+#X connect 6 0 1 0;
+#X connect 7 0 6 0;
+#X connect 10 0 11 0;
+#X connect 11 0 13 0;
+#X connect 12 0 10 0;
diff --git a/help/tabsort2-help.pd b/help/tabsort2-help.pd
new file mode 100644
index 0000000..4f4e29a
--- /dev/null
+++ b/help/tabsort2-help.pd
@@ -0,0 +1,84 @@
+#N canvas 133 15 811 538 10;
+#X floatatom 62 381 5 0 0 0 - - -;
+#N canvas 0 0 450 300 graph29 0;
+#X array source1 100 float 1;
+#A 0 -0.0428565 -0.0571422 0.085715 0.228572 0.442858 0.657144 0.871429
+1.08572 1.22857 1.51429 1.72857 1.94286 2.22857 2.37143 2.58571 2.72857
+2.87143 2.94286 3.15714 3.3 3.3 3.44286 3.58571 3.65714 3.72857 3.8
+3.94286 4.01429 4.08571 4.22857 4.3 4.13929 3.97857 3.81786 3.51429
+3.22857 2.8 2.37143 2.3 2.3 2.3 2.37143 2.44286 2.51429 2.51429 2.58572
+2.55 2.37143 2.22857 1.94286 1.72857 1.58572 1.44286 1.44286 1.37144
+1.37144 1.37144 1.44286 1.44286 1.44286 1.44286 1.51429 1.51429 1.58572
+1.65714 1.65714 1.70476 1.75238 1.8 1.87143 2.01429 2.15714 2.22857
+4.58572 4.94286 5.22857 5.44286 5.58572 5.58572 5.39524 5.20477 5.01429
+4.82381 4.63334 4.44286 4.25238 4.06191 3.8 3.72857 3.65715 3.65715
+3.58572 3.58572 4.15715 4.51429 4.58572 4.72858 4.87143 5.08572 5.44286
+;
+#X coords 0 10 99 0 200 140 1;
+#X restore 60 133 graph;
+#N canvas 0 0 450 300 graph29 0;
+#X array dest 100 float 0;
+#X coords 0 100 99 0 200 140 1;
+#X restore 547 129 graph;
+#X obj 10 8 tabsort2;
+#X text 75 9 2 dimensionnal sort.;
+#X text 24 99 args: source_table1 source_table2 dest_table;
+#X text 248 8 write to dest_table the indices of the first N source_table1's
+elements sorted by decreasing order (biggest first) \, then sort the
+"columns" of sqrt(N) indices decreasingly according to their values
+in source_table2 (is it clear?).;
+#N canvas 0 0 450 300 graph29 0;
+#X array source2 100 float 1;
+#A 0 7.71429 7.64286 7.64286 7.57143 7.5 7.35714 7.21428 6.92857 6.57143
+6 5.71428 5.57143 5.21428 4.5 4.35714 4.28571 4.28571 4.28571 4.28571
+4.28571 4.42857 4.57143 4.64285 4.78571 4.92857 5.14285 5.35714 5.71428
+6 6.21428 6.42857 6.57143 6.64286 6.64286 6.64286 6.64286 6.57143 6.57143
+6.42857 6.35714 6.28571 6.14286 5.92857 5.78571 5.64286 5.42857 7.85714
+7.92857 8.42857 8.71428 8.92857 8.92857 8.92857 8.92857 8.85714 8.78571
+8.78571 8.78571 8.5 8.28571 8.07143 7.5 7.28571 6.85714 6.57143 5.78571
+5.5 5.21428 4.78571 4.64286 4.64286 4.78571 4.92857 5.07143 5.21428
+5.42857 5.57143 5.71428 5.92857 6.28571 6.5 6.85714 7.14286 7.35714
+7.64286 7.71429 7.78572 7.85714 7.85714 7.85714 7.71429 7.64286 7.5
+7.35714 7.14286 7.07143 7 6.85714 4.5 -0.342857;
+#X coords 0 10 99 0 200 140 1;
+#X restore 311 131 graph;
+#X msg 62 340 100;
+#X obj 62 360 tabsort2 source1 source2 dest;
+#X obj 500 416 tabread dest;
+#X obj 452 362 * 10;
+#X obj 500 391 +;
+#X floatatom 451 346 5 0 9 0 - - -;
+#X obj 528 361 t b f;
+#X floatatom 528 344 5 0 9 0 - - -;
+#X floatatom 407 485 0 0 0 0 - - -;
+#X obj 407 465 tabread source1;
+#X obj 557 467 tabread source2;
+#X floatatom 557 487 0 0 0 0 - - -;
+#X floatatom 527 393 5 0 0 0 - - -;
+#X text 433 328 x(columns);
+#X text 521 327 y(lines);
+#X text 403 504 decrease with x;
+#X text 555 505 decrease with y;
+#X text 49 305 1) Sort it:;
+#X text 381 304 2) Try it:;
+#X text 8 520 (c) Antoine Rousseau 2002;
+#X floatatom 603 441 5 0 0 0 - - -;
+#X text 604 416 index of sources;
+#X text 606 426 elements;
+#X text 28 396 output=sqrt(N)=the width/height;
+#X text 28 410 of the destination "square".;
+#X text 61 326 sort the N first elements;
+#X connect 8 0 9 0;
+#X connect 9 0 0 0;
+#X connect 10 0 17 0;
+#X connect 10 0 18 0;
+#X connect 10 0 28 0;
+#X connect 11 0 12 0;
+#X connect 12 0 10 0;
+#X connect 12 0 20 0;
+#X connect 13 0 11 0;
+#X connect 14 0 12 0;
+#X connect 14 1 12 1;
+#X connect 15 0 14 0;
+#X connect 17 0 16 0;
+#X connect 18 0 19 0;
diff --git a/image.c b/image.c
new file mode 100644
index 0000000..f38078d
--- /dev/null
+++ b/image.c
@@ -0,0 +1,306 @@
+#include <m_pd.h>
+#include "g_canvas.h"
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+/* ------------------------ image ----------------------------- */
+
+static t_class *image_class;
+
+typedef struct _image
+{
+ t_object x_obj;
+ t_glist * x_glist;
+ int x_width;
+ int x_height;
+ t_symbol* x_image;
+ int x_type; //0=file 1=tk_image
+ t_int x_localimage; //localimage "img%x" done
+} t_image;
+
+/* widget helper functions */
+
+const char* image_get_filename(t_image *x,char *file)
+{
+ static char fname[MAXPDSTRING];
+ char *bufptr;
+ int fd;
+
+ fd=open_via_path(canvas_getdir(glist_getcanvas(x->x_glist))->s_name,
+ file, "",fname, &bufptr, MAXPDSTRING, 1);
+ if(fd>0){
+ fname[strlen(fname)]='/';
+ //post("image file: %s",fname);
+ close(fd);
+ return fname;
+ }
+ else return 0;
+}
+
+void image_drawme(t_image *x, t_glist *glist, int firsttime)
+{
+ if (firsttime) {
+ if(x->x_type) {
+ sys_vgui(".x%x.c create image %d %d -tags %xS\n",
+ glist_getcanvas(glist),
+ text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),x);
+ sys_vgui(".x%x.c itemconfigure %xS -image %s\n",
+ glist_getcanvas(glist),x,x->x_image->s_name);
+ }
+ else {
+ const char *fname=image_get_filename(x,x->x_image->s_name);
+ if(!x->x_localimage) {
+ sys_vgui("image create photo img%x\n",x);
+ x->x_localimage=1;
+ }
+ if(fname) sys_vgui("img%x configure -file %s\n",x,fname);
+ sys_vgui(".x%x.c create image %d %d -image img%x -tags %xS\n",
+ glist_getcanvas(glist),
+ text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),x,x);
+ }
+ /* TODO callback from gui
+ sys_vgui("image_size logo");
+ */
+ }
+ else {
+ sys_vgui(".x%x.c coords %xS \
+%d %d\n",
+ glist_getcanvas(glist), x,
+ text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist));
+ }
+
+}
+
+
+void image_erase(t_image* x,t_glist* glist)
+{
+ int n;
+ sys_vgui(".x%x.c delete %xS\n",
+ glist_getcanvas(glist), x);
+
+}
+
+
+
+/* ------------------------ image widgetbehaviour----------------------------- */
+
+
+static void image_getrect(t_gobj *z, t_glist *glist,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ int width, height;
+ t_image* x = (t_image*)z;
+
+
+ width = x->x_width;
+ height = x->x_height;
+ *xp1 = text_xpix(&x->x_obj, glist);
+ *yp1 = text_ypix(&x->x_obj, glist);
+ *xp2 = text_xpix(&x->x_obj, glist) + width;
+ *yp2 = text_ypix(&x->x_obj, glist) + height;
+}
+
+static void image_displace(t_gobj *z, t_glist *glist,
+ int dx, int dy)
+{
+ t_image *x = (t_image *)z;
+ x->x_obj.te_xpix += dx;
+ x->x_obj.te_ypix += dy;
+ sys_vgui(".x%x.c coords %xSEL %d %d %d %d\n",
+ glist_getcanvas(glist), x,
+ text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),
+ text_xpix(&x->x_obj, glist) + x->x_width, text_ypix(&x->x_obj, glist) + x->x_height);
+
+ image_drawme(x, glist, 0);
+ canvas_fixlinesfor(glist_getcanvas(glist),(t_text*) x);
+}
+
+static void image_select(t_gobj *z, t_glist *glist, int state)
+{
+ t_image *x = (t_image *)z;
+ if (state) {
+ sys_vgui(".x%x.c create rectangle \
+%d %d %d %d -tags %xSEL -outline blue\n",
+ glist_getcanvas(glist),
+ text_xpix(&x->x_obj, glist), text_ypix(&x->x_obj, glist),
+ text_xpix(&x->x_obj, glist) + x->x_width, text_ypix(&x->x_obj, glist) + x->x_height,
+ x);
+ }
+ else {
+ sys_vgui(".x%x.c delete %xSEL\n",
+ glist_getcanvas(glist), x);
+ }
+
+
+
+}
+
+
+static void image_activate(t_gobj *z, t_glist *glist, int state)
+{
+/* t_text *x = (t_text *)z;
+ t_rtext *y = glist_findrtext(glist, x);
+ if (z->g_pd != gatom_class) rtext_activate(y, state);*/
+}
+
+static void image_delete(t_gobj *z, t_glist *glist)
+{
+ t_text *x = (t_text *)z;
+ //canvas_deletelinesfor(glist_getcanvas(glist), x);
+ canvas_deletelinesfor(glist, x);
+}
+
+
+static void image_vis(t_gobj *z, t_glist *glist, int vis)
+{
+ t_image* s = (t_image*)z;
+ if (vis)
+ image_drawme(s, glist, 1);
+ else
+ image_erase(s,glist);
+}
+
+/* can we use the normal text save function ?? */
+
+static void image_save(t_gobj *z, t_binbuf *b)
+{
+ t_image *x = (t_image *)z;
+ binbuf_addv(b, "ssiissi", gensym("#X"),gensym("obj"),
+ x->x_obj.te_xpix, x->x_obj.te_ypix,
+ gensym("image"),x->x_image,x->x_type);
+ binbuf_addv(b, ";");
+}
+
+
+t_widgetbehavior image_widgetbehavior;
+
+void image_size(t_image* x,t_floatarg w,t_floatarg h) {
+ x->x_width = w;
+ x->x_height = h;
+}
+
+void image_color(t_image* x,t_symbol* col)
+{
+/* outlet_bang(x->x_obj.ob_outlet); only bang if there was a bang ..
+ so color black does the same as bang, but doesn't forward the bang
+*/
+}
+
+void image_open(t_gobj *z,t_symbol* file)
+{
+ t_image* x = (t_image*)z;
+ const char *fname;
+ int oldtype=x->x_type;
+
+
+ fname=image_get_filename(x,file->s_name);
+ if(fname){
+ x->x_image=file;
+ x->x_type=0;
+ if(glist_isvisible(x->x_glist)) {
+ if(!x->x_localimage) {
+ sys_vgui("image create photo img%x\n",x);
+ x->x_localimage=1;
+ }
+ sys_vgui("img%x blank\n",x);
+ sys_vgui("img%x configure -file %s\n",x,fname);
+ if(oldtype) sys_vgui(".x%x.c itemconfigure %xS -image img%x\n",
+ glist_getcanvas(x->x_glist),x,x);
+ }
+ }
+}
+
+void image_load(t_gobj *z,t_symbol* image,t_symbol* file)
+{
+ t_image* x = (t_image*)z;
+ const char *fname;
+
+ fname=image_get_filename(x,file->s_name);
+ if(fname){
+ sys_vgui("image create photo %s -file %s\n",image->s_name,fname);
+ }
+}
+
+void image_set(t_gobj *z,t_symbol* image)
+{
+ t_image* x = (t_image*)z;
+
+ x->x_image=image;
+ x->x_type=1;
+
+ if(glist_isvisible(x->x_glist)) {
+ sys_vgui(".x%x.c itemconfigure %xS -image %s\n",
+ glist_getcanvas(x->x_glist),x,x->x_image->s_name);
+ }
+}
+
+
+static void image_setwidget(void)
+{
+ image_widgetbehavior.w_getrectfn = image_getrect;
+ image_widgetbehavior.w_displacefn = image_displace;
+ image_widgetbehavior.w_selectfn = image_select;
+ image_widgetbehavior.w_activatefn = image_activate;
+ image_widgetbehavior.w_deletefn = image_delete;
+ image_widgetbehavior.w_visfn = image_vis;
+#if (PD_VERSION_MINOR > 31)
+ image_widgetbehavior.w_clickfn = NULL;
+ image_widgetbehavior.w_propertiesfn = NULL;
+#endif
+#if PD_MINOR_VERSION < 37
+ image_widgetbehavior.w_savefn = image_save;
+#endif
+}
+
+
+static void *image_new(t_symbol* image,int type)
+{
+ t_image *x = (t_image *)pd_new(image_class);
+
+ x->x_glist = (t_glist*) canvas_getcurrent();
+
+ x->x_width = 15;
+ x->x_height = 15;
+ x->x_type=type;
+ x->x_localimage=0;
+ x->x_image = image;
+
+ outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+void image_setup(void)
+{
+ image_class = class_new(gensym("image"), (t_newmethod)image_new, 0,
+ sizeof(t_image),0, A_DEFSYM,A_DEFFLOAT,0);
+
+/*
+ class_addmethod(image_class, (t_method)image_size, gensym("size"),
+ A_FLOAT, A_FLOAT, 0);
+
+ class_addmethod(image_class, (t_method)image_color, gensym("color"),
+ A_SYMBOL, 0);
+*/
+
+ class_addmethod(image_class, (t_method)image_open, gensym("open"),
+ A_SYMBOL, 0);
+ class_addmethod(image_class, (t_method)image_set, gensym("set"),
+ A_SYMBOL, 0);
+ class_addmethod(image_class, (t_method)image_load, gensym("load"),
+ A_SYMBOL, A_SYMBOL, 0);
+
+ image_setwidget();
+ class_setwidget(image_class,&image_widgetbehavior);
+#if PD_MINOR_VERSION >= 37
+ class_setsavefn(image_class,&image_save);
+#endif
+
+}
+
+
diff --git a/joystik.c b/joystik.c
new file mode 100644
index 0000000..2c09093
--- /dev/null
+++ b/joystik.c
@@ -0,0 +1,191 @@
+/*
+'pd_joystik' (An external library for Miller Puckette's 'PD' software
+adding PC and/or USB joystik control capabilities)
+
+Copyright (C) 2001 Antoine Rousseau (from the initial file of Joseph A. Sarlo)
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+#include <m_pd.h>
+#include <s_stuff.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <linux/joystick.h>
+#include <glib.h>
+
+/*0=normal joystick: /dev/jsXX 1=usb joystick: /dev/input/jsXX */
+
+static GList *(joy_lists)[2][16]={{0},{0}};
+static int fds[2][16];
+
+typedef struct _joystik
+{
+ t_object t_ob;
+ t_outlet *x_axis_out;
+ t_outlet *x_button_out;
+ guchar x_connected;
+ guchar x_usb; /*0:normal 1:usb*/
+ gushort x_number; /*0 to 15*/
+}t_joystik;
+
+t_class *joystik_class;
+
+void joystik_setup(void);
+static void joystik_read(GList *l,int fd);
+
+static void fd_open(int usb,int n)
+{
+ char filename[128];
+ int *fd=&fds[(int)usb][(int)n];
+ GList *l=joy_lists[(int)usb][(int)n];
+
+ if(usb) sprintf(filename,"/dev/input/js%d",n);
+ else sprintf(filename,"/dev/js%d",n);
+
+ if(*fd<=0){
+ *fd = open (filename, O_RDONLY | O_NONBLOCK);
+ if(*fd<0){
+ post("open (%s, O_RDONLY | O_NONBLOCK)",filename);
+ perror("open");
+ return;
+ }
+ }
+ sys_addpollfn(*fd,(t_fdpollfn)joystik_read,(void*)l);
+ /*post("joystick: adding poll");*/
+}
+
+static void fd_close(int usb,int n)
+{
+ int *fd=&fds[(int)usb][(int)n];
+
+ sys_rmpollfn(*fd);
+ close(*fd);
+ *fd=-1;
+ /*post("joystick: removing poll");*/
+}
+
+static void joystik_connect(t_joystik *x)
+{
+ GList *l=joy_lists[x->x_usb][x->x_number];
+
+ if(g_list_find(l,(void*)x)) return;
+
+ g_list_append(l,(void*)x);
+
+ if(g_list_length(l)==2){
+ fd_open(x->x_usb,x->x_number);
+ }
+}
+static void joystik_deconnect(t_joystik *x)
+{
+ GList *l=joy_lists[x->x_usb][x->x_number];
+
+ if(!g_list_find(l,(void*)x)) return;
+
+ g_list_remove(l,(void*)x);
+
+ if(g_list_length(l)==1){
+ fd_close(x->x_usb,x->x_number);
+ }
+}
+
+static void joystik_float(t_joystik *x,t_floatarg connect)
+{
+ connect=(connect!=0);
+
+ if(x->x_connected==connect) return;
+
+ if(connect) joystik_connect(x);
+ else joystik_deconnect(x);
+
+ x->x_connected=connect;
+}
+
+static void *joystik_new(t_float num, t_float usb)
+{
+ t_joystik *x = (t_joystik *)pd_new(joystik_class);
+ int n=num;
+ GList **l=0;
+
+ if((n<0)||(n>16)) {
+ post("ERROR in joystik_new : device number out of range");
+ return (void*)x;
+ }
+
+ usb=(usb!=0);
+ x->x_axis_out = outlet_new(&x->t_ob, &s_list);
+ x->x_button_out = outlet_new(&x->t_ob, &s_list);
+
+ x->x_connected=0;
+ x->x_usb=usb;
+ x->x_number=n;
+
+ l=&joy_lists[(int)usb][(int)n];
+
+ if(!*l) *l=g_list_alloc();
+
+ return (void *)x;
+}
+
+void joystik_setup(void)
+{
+ joystik_class = class_new(gensym("joystik"),(t_newmethod)joystik_new,
+ (t_method)joystik_deconnect, sizeof(t_joystik), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addfloat(joystik_class, joystik_float);
+
+
+}
+
+static void joystik_read(GList *l,int fd)
+{
+ #define AMP 32767.0
+ int rt;
+ struct js_event e;
+ t_atom ats[2];
+ GList *ltmp;
+
+ while (read (fd, &e, sizeof(struct js_event)) > -1)
+ {
+ SETFLOAT(&ats[0],e.number);
+ if (e.type == JS_EVENT_AXIS)
+ {
+ SETFLOAT(&ats[1],e.value/AMP);
+ ltmp=l;
+ while(ltmp->next){
+ ltmp=ltmp->next;
+ outlet_list(((t_joystik*)ltmp->data)->x_axis_out,0,2,ats);
+ }
+ }
+ else if (e.type == JS_EVENT_BUTTON)
+ {
+ SETFLOAT(&ats[1],e.value);
+ ltmp=l;
+ while(ltmp->next){
+ ltmp=ltmp->next;
+ outlet_list(((t_joystik*)ltmp->data)->x_button_out,0,2,ats);
+ }
+ }
+ }
+}
+
diff --git a/mknob.c b/mknob.c
new file mode 100644
index 0000000..4cf5cbe
--- /dev/null
+++ b/mknob.c
@@ -0,0 +1,870 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* mknob.c written by Antoine Rousseau from g_vslider.c.*/
+/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
+/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "m_pd.h"
+#include "g_canvas.h"
+#include "t_tk.h"
+#include "g_all_guis.h"
+#include <math.h>
+
+#ifdef NT
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+
+#define MKNOB_TANGLE 100
+#define MKNOB_DEFAULTH 100
+#define MKNOB_DEFAULTSIZE 25
+#define MKNOB_MINSIZE 12
+#define MKNOB_THICK 3
+/* ------------ mknob ----------------------- */
+typedef struct _mknob
+{
+ t_iemgui x_gui;
+ int x_pos;
+ int x_val;
+ int x_center;
+ int x_thick;
+ int x_lin0_log1;
+ int x_steady;
+ double x_min;
+ double x_max;
+ int x_H;
+ double x_k;
+} t_mknob;
+
+t_widgetbehavior mknob_widgetbehavior;
+static t_class *mknob_class;
+
+/* widget helper functions */
+static void mknob_update_knob(t_mknob *x, t_glist *glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+// float val=(x->x_val + 50.0)/100.0/MKNOB_TANGLE;
+ float val=(x->x_val + 50.0)/100.0/x->x_H;
+ float angle,
+ radius=x->x_gui.x_w/2.0,
+ miniradius=MKNOB_THICK;
+ int x0,y0,x1,y1,xc,yc,xp,yp,xpc,ypc;
+ x0=text_xpix(&x->x_gui.x_obj, glist);
+ y0=text_ypix(&x->x_gui.x_obj, glist);
+ x1=x0+x->x_gui.x_w;
+ y1=y0+x->x_gui.x_w;
+ xc=(x0+x1)/2;
+ yc=(y0+y1)/2;
+
+ if(x->x_gui.x_h<0)
+ angle=val*(M_PI*2)+M_PI/2.0;
+ else
+ angle=val*(M_PI*1.5)+3.0*M_PI/4.0;
+
+ xp=xc+radius*cos(angle);
+ yp=yc+radius*sin(angle);
+ xpc=miniradius*cos(angle-M_PI/2);
+ ypc=miniradius*sin(angle-M_PI/2);
+
+ sys_vgui(".x%x.c coords %xKNOB %d %d %d %d %d %d\n",
+ canvas,x,xp,yp,xc+xpc,yc+ypc,xc-xpc,yc-ypc);
+}
+
+static void mknob_draw_update(t_mknob *x, t_glist *glist)
+{
+ if (glist_isvisible(glist))
+ {
+ mknob_update_knob(x,glist);
+
+ /*if(x->x_val == x->x_center)
+ {
+ if(!x->x_thick)
+ {
+ sys_vgui(".x%x.c itemconfigure %xKNOB -width 7\n", canvas, x);
+ x->x_thick = 1;
+ }
+ }
+ else
+ {
+ if(x->x_thick)
+ {
+ sys_vgui(".x%x.c itemconfigure %xKNOB -width 3\n", canvas, x);
+ x->x_thick = 0;
+ }
+ }*/
+ }
+}
+
+static void mknob_draw_new(t_mknob *x, t_glist *glist)
+{
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ int r = xpos + (x->x_val + 50)/100;
+ int xc=xpos+x->x_gui.x_w/2;
+ int yc=ypos+x->x_gui.x_w/2;
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c create oval %d %d %d %d -fill #%6.6x -tags %xBASE\n",
+ canvas,xpos,ypos,xpos + x->x_gui.x_w, ypos + x->x_gui.x_w,
+ x->x_gui.x_bcol,x);
+ sys_vgui(".x%x.c create polygon %d %d %d %d %d %d -fill #%6.6x -tags %xKNOB\n",
+ glist_getcanvas(glist),
+ xc,ypos,xc-4,yc,xc+4,yc,x->x_gui.x_fcol,x);
+ mknob_update_knob(x,glist);
+ sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
+ -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
+ canvas, xpos+x->x_gui.x_ldx,
+ ypos+x->x_gui.x_ldy,
+ strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
+ x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
+ /*if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+ canvas, xpos+ x->x_gui.x_w/2-3, ypos + x->x_gui.x_w-1,
+ xpos+ x->x_gui.x_w/2+4, ypos + x->x_gui.x_w, x, 0);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
+ canvas, xpos+ x->x_gui.x_w/2-3, ypos,
+ xpos+ x->x_gui.x_w/2+4, ypos+1, x, 0);*/
+}
+
+static void mknob_draw_move(t_mknob *x, t_glist *glist)
+{
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ int r = xpos + (x->x_val + 50)/100;
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c coords %xBASE %d %d %d %d\n",
+ canvas, x,
+ xpos, ypos,
+ xpos + x->x_gui.x_w, ypos + x->x_gui.x_w);
+ mknob_update_knob(x,glist);
+ sys_vgui(".x%x.c coords %xLABEL %d %d\n",
+ canvas, x, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy);
+ /*if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
+ canvas, x, 0,
+ xpos+ x->x_gui.x_w/2-3, ypos + x->x_gui.x_w-1,
+ xpos+ x->x_gui.x_w/2+4, ypos + x->x_gui.x_w);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
+ canvas, x, 0,
+ xpos+ x->x_gui.x_w/2-3, ypos,
+ xpos+ x->x_gui.x_w/2+4, ypos+1);*/
+}
+
+static void mknob_draw_erase(t_mknob* x,t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c delete %xBASE\n", canvas, x);
+ sys_vgui(".x%x.c delete %xKNOB\n", canvas, x);
+ sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
+ /*if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);*/
+}
+
+static void mknob_draw_config(t_mknob* x,t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
+ canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
+ x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
+ strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
+ sys_vgui(".x%x.c itemconfigure %xKNOB -fill #%6.6x\n", canvas, x, x->x_gui.x_fcol);
+ sys_vgui(".x%x.c itemconfigure %xBASE -fill #%6.6x\n", canvas, x, x->x_gui.x_bcol);
+}
+
+static void mknob_draw_io(t_mknob* x,t_glist* glist, int old_snd_rcv_flags)
+{
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ /*if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+ canvas, xpos+ x->x_gui.x_w/2-3, ypos + x->x_gui.x_w-1,
+ xpos+ x->x_gui.x_w/2+4, ypos + x->x_gui.x_w, x, 0);
+ if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
+ if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
+ canvas, xpos+ x->x_gui.x_w/2-3, ypos,
+ xpos+ x->x_gui.x_w/2+4, ypos+1, x, 0);
+ if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);*/
+}
+
+static void mknob_draw_select(t_mknob* x,t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if(x->x_gui.x_fsf.x_selected)
+ {
+ //pd_bind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+ sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+ }
+ else
+ {
+ //pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
+ sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol);
+ }
+}
+
+void mknob_draw(t_mknob *x, t_glist *glist, int mode)
+{
+ if(mode == IEM_GUI_DRAW_MODE_UPDATE)
+ mknob_draw_update(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_MOVE)
+ mknob_draw_move(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_NEW)
+ mknob_draw_new(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_SELECT)
+ mknob_draw_select(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_ERASE)
+ mknob_draw_erase(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
+ mknob_draw_config(x, glist);
+ /*else if(mode >= IEM_GUI_DRAW_MODE_IO)
+ mknob_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);*/
+}
+
+/* ------------------------ mknob widgetbehaviour----------------------------- */
+
+
+static void mknob_getrect(t_gobj *z, t_glist *glist,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_mknob* x = (t_mknob*)z;
+
+ *xp1 = text_xpix(&x->x_gui.x_obj, glist);
+ *yp1 = text_ypix(&x->x_gui.x_obj, glist);
+ *xp2 = *xp1 + x->x_gui.x_w;
+ *yp2 = *yp1 + x->x_gui.x_w;
+}
+
+static void mknob_save(t_gobj *z, t_binbuf *b)
+{
+ t_mknob *x = (t_mknob *)z;
+ int bflcol[3], *ip1, *ip2;
+ t_symbol *srl[3];
+
+ iemgui_save(&x->x_gui, srl, bflcol);
+ ip1 = (int *)(&x->x_gui.x_isa);
+ ip2 = (int *)(&x->x_gui.x_fsf);
+ binbuf_addv(b, "ssiisiiffiisssiiiiiiiii", gensym("#X"),gensym("obj"),
+ (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
+ gensym("mknob"), x->x_gui.x_w, x->x_gui.x_h,
+ (float)x->x_min, (float)x->x_max,
+ x->x_lin0_log1, (*ip1)&IEM_INIT_ARGS_ALL,
+ srl[0], srl[1], srl[2],
+ x->x_gui.x_ldx, x->x_gui.x_ldy,
+ (*ip2)&IEM_FSTYLE_FLAGS_ALL, x->x_gui.x_fontsize,
+ bflcol[0], bflcol[1], bflcol[2],
+ x->x_val, x->x_steady);
+ binbuf_addv(b, ";");
+}
+
+void mknob_check_wh(t_mknob *x, int w, int h)
+{
+ int H;
+
+ if(w < MKNOB_MINSIZE) w = MKNOB_MINSIZE;
+ x->x_gui.x_w = w;
+
+ if(h < -1) h=-1;
+ if((h>0)&&(h<20)) h=20;
+ x->x_gui.x_h = h;
+
+ H=x->x_gui.x_h;
+ if(H<0) H=360;
+ if(H==0) H=270;
+ x->x_H=H;
+
+ if(x->x_lin0_log1)
+ x->x_k = log(x->x_max/x->x_min)/(double)(x->x_H - 1);
+ else
+ x->x_k = (x->x_max - x->x_min)/(double)(x->x_H - 1);
+
+ /*x->x_center = (x->x_gui.x_w-1)*50;
+ if(x->x_val > (x->x_gui.x_w*100 - 100))
+ {
+ x->x_pos = x->x_gui.x_w*100 - 100;
+ x->x_val = x->x_pos;
+ }
+ if(x->x_lin0_log1)
+ x->x_k = log(x->x_max/x->x_min)/(double)(x->x_gui.x_w - 1);
+ else
+ x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_w - 1);*/
+}
+
+void mknob_check_minmax(t_mknob *x, double min, double max)
+{
+ int H;
+
+ if(x->x_lin0_log1)
+ {
+ if((min == 0.0)&&(max == 0.0))
+ max = 1.0;
+ if(max > 0.0)
+ {
+ if(min <= 0.0)
+ min = 0.01*max;
+ }
+ else
+ {
+ if(min > 0.0)
+ max = 0.01*min;
+ }
+ }
+ x->x_min = min;
+ x->x_max = max;
+ if(x->x_min > x->x_max) /* bugfix */
+ x->x_gui.x_isa.x_reverse = 1;
+ else
+ x->x_gui.x_isa.x_reverse = 0;
+
+ if(x->x_lin0_log1)
+ x->x_k = log(x->x_max/x->x_min)/(double)(x->x_H - 1);
+ else
+ x->x_k = (x->x_max - x->x_min)/(double)(x->x_H - 1);
+ /*if(x->x_lin0_log1)
+ x->x_k = log(x->x_max/x->x_min)/(double)(MKNOB_TANGLE - 1);
+ else
+ x->x_k = (x->x_max - x->x_min)/(double)(MKNOB_TANGLE - 1);*/
+}
+
+static void mknob_properties(t_gobj *z, t_glist *owner)
+{
+ t_mknob *x = (t_mknob *)z;
+ char buf[800];
+ t_symbol *srl[3];
+
+ iemgui_properties(&x->x_gui, srl);
+ sprintf(buf, "pdtk_iemgui_dialog %%s mknob \
+ --------dimension(pix):-------- %d %d width: %d %d mouse: \
+ -----------output-range:----------- %g left: %g right: %g \
+ %d lin log %d %d empty %d \
+ %s %s \
+ %s %d %d \
+ %d %d \
+ %d %d %d\n",
+ x->x_gui.x_w, MKNOB_MINSIZE, x->x_gui.x_h, -1,
+ x->x_min, x->x_max, 0.0,/*no_schedule*/
+ x->x_lin0_log1, x->x_gui.x_isa.x_loadinit, x->x_steady, -1,/*no multi, but iem-characteristic*/
+ srl[0]->s_name, srl[1]->s_name,
+ srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
+ x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
+ 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
+ gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
+}
+
+static void mknob_set(t_mknob *x, t_floatarg f) /* bugfix */
+{
+ double g;
+
+ if(x->x_gui.x_isa.x_reverse) /* bugfix */
+ {
+ if(f > x->x_min)
+ f = x->x_min;
+ if(f < x->x_max)
+ f = x->x_max;
+ }
+ else
+ {
+ if(f > x->x_max)
+ f = x->x_max;
+ if(f < x->x_min)
+ f = x->x_min;
+ }
+ if(x->x_lin0_log1)
+ g = log(f/x->x_min)/x->x_k;
+ else
+ g = (f - x->x_min) / x->x_k;
+ x->x_val = (int)(100.0*g + 0.49999);
+ x->x_pos = x->x_val;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+}
+
+static void mknob_bang(t_mknob *x)
+{
+ double out;
+
+ if(x->x_lin0_log1)
+ out = x->x_min*exp(x->x_k*(double)(x->x_val)*0.01);
+ else
+ out = (double)(x->x_val)*0.01*x->x_k + x->x_min;
+ if((out < 1.0e-10)&&(out > -1.0e-10))
+ out = 0.0;
+ outlet_float(x->x_gui.x_obj.ob_outlet, out);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_float(x->x_gui.x_snd->s_thing, out);
+}
+
+static void mknob_dialog(t_mknob *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_symbol *srl[3];
+ int w = (int)atom_getintarg(0, argc, argv);
+ int h = (int)atom_getintarg(1, argc, argv);
+ double min = (double)atom_getfloatarg(2, argc, argv);
+ double max = (double)atom_getfloatarg(3, argc, argv);
+ int lilo = (int)atom_getintarg(4, argc, argv);
+ int steady = (int)atom_getintarg(17, argc, argv);
+ int sr_flags;
+
+ if(lilo != 0) lilo = 1;
+ x->x_lin0_log1 = lilo;
+ if(steady)
+ x->x_steady = 1;
+ else
+ x->x_steady = 0;
+ sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
+ //x->x_gui.x_h = iemgui_clip_size(h);
+ //x->x_gui.x_w = iemgui_clip_size(w);
+ mknob_check_wh(x, w, h);
+ mknob_check_minmax(x, min, max);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
+}
+
+static int xm0,ym0,xm,ym;
+
+static void mknob_motion(t_mknob *x, t_floatarg dx, t_floatarg dy)
+{
+ int old = x->x_val;
+ float d=-dy;
+
+ if (abs(dx)>abs(dy)) d=dx;
+
+ if(x->x_gui.x_fsf.x_finemoved)
+ x->x_pos += (int)d;
+ else
+ x->x_pos += 100*(int)d;
+ x->x_val = x->x_pos;
+ if(x->x_val > (100*x->x_H - 100))
+ {
+ x->x_val = 100*x->x_H - 100;
+ x->x_pos += 50;
+ x->x_pos -= x->x_pos%100;
+ }
+ if(x->x_val < 0)
+ {
+ x->x_val = 0;
+ x->x_pos -= 50;
+ x->x_pos -= x->x_pos%100;
+ }
+ if(old != x->x_val)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ mknob_bang(x);
+ }
+}
+
+static void mknob_motion_circular(t_mknob *x, t_floatarg dx, t_floatarg dy)
+{
+ int xc=text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist)+x->x_gui.x_w/2;
+ int yc=text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist)+x->x_gui.x_w/2;
+ int old = x->x_val;
+ float alpha;
+
+ xm+=dx;
+ ym+=dy;
+
+ alpha=atan2(xm-xc,ym-yc)*180.0/M_PI;
+
+ x->x_pos=(int)(31500-alpha*100.0)%36000;
+ if(x->x_pos>31500) x->x_pos=0;
+ else if(x->x_pos>(27000-100)) x->x_pos=(27000-100);
+
+ x->x_val=x->x_pos;
+
+ if(old != x->x_val)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ mknob_bang(x);
+ }
+}
+
+static void mknob_motion_fullcircular(t_mknob *x, t_floatarg dx, t_floatarg dy)
+{
+ int xc=text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist)+x->x_gui.x_w/2;
+ int yc=text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist)+x->x_gui.x_w/2;
+ int old = x->x_val;
+ float alpha;
+
+ xm+=dx;
+ ym+=dy;
+
+ alpha=atan2(xm-xc,ym-yc)*180.0/M_PI;
+
+ x->x_pos=(int)(36000-alpha*100.0)%36000;
+ /*if(x->x_pos>31500) x->x_pos=0;
+ else if(x->x_pos>(27000-100)) x->x_pos=(27000-100);*/
+
+ if(x->x_pos>(36000-100)) x->x_pos=(36000-100);
+ x->x_val=x->x_pos;
+
+ if(old != x->x_val)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ mknob_bang(x);
+ }
+}
+
+static void mknob_click(t_mknob *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ xm0=xm=xpos;
+ ym0=ym=ypos;
+ //if(!x->x_steady)
+ //x->x_val = (int)(100.0 * (xpos - text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist)));
+ if(x->x_val > (100*x->x_H - 100))
+ x->x_val = 100*x->x_H - 100;
+ if(x->x_val < 0)
+ x->x_val = 0;
+ x->x_pos = x->x_val;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ mknob_bang(x);
+
+ if(x->x_gui.x_h<0)
+ glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g,
+ (t_glistmotionfn)mknob_motion_fullcircular, 0, xpos, ypos);
+ else if(x->x_gui.x_h==0)
+ glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g,
+ (t_glistmotionfn)mknob_motion_circular, 0, xpos, ypos);
+ else
+ glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g,
+ (t_glistmotionfn)mknob_motion, 0, xpos, ypos);
+
+}
+
+static int mknob_newclick(t_gobj *z, struct _glist *glist,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ t_mknob* x = (t_mknob *)z;
+
+ if(doit)
+ {
+ mknob_click( x, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift,
+ 0, (t_floatarg)alt);
+ if(shift)
+ x->x_gui.x_fsf.x_finemoved = 1;
+ else
+ x->x_gui.x_fsf.x_finemoved = 0;
+ }
+ return (1);
+}
+
+static void mknob_size(t_mknob *x, t_symbol *s, int ac, t_atom *av)
+{
+ int w=(int)atom_getintarg(0, ac, av),
+ h=x->x_gui.x_h;
+
+ if(ac > 1) h=(int)atom_getintarg(1, ac, av);
+
+ mknob_check_wh(x, w, h);
+ iemgui_size((void *)x, &x->x_gui);
+}
+
+static void mknob_delta(t_mknob *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
+
+static void mknob_pos(t_mknob *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
+
+static void mknob_range(t_mknob *x, t_symbol *s, int ac, t_atom *av)
+{
+ mknob_check_minmax(x, (double)atom_getfloatarg(0, ac, av),
+ (double)atom_getfloatarg(1, ac, av));
+}
+
+static void mknob_color(t_mknob *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
+
+static void mknob_send(t_mknob *x, t_symbol *s)
+{iemgui_send(x, &x->x_gui, s);}
+
+static void mknob_receive(t_mknob *x, t_symbol *s)
+{iemgui_receive(x, &x->x_gui, s);}
+
+static void mknob_label(t_mknob *x, t_symbol *s)
+{iemgui_label((void *)x, &x->x_gui, s);}
+
+static void mknob_label_pos(t_mknob *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
+
+static void mknob_label_font(t_mknob *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
+
+static void mknob_log(t_mknob *x)
+{
+ x->x_lin0_log1 = 1;
+ mknob_check_minmax(x, x->x_min, x->x_max);
+}
+
+static void mknob_lin(t_mknob *x)
+{
+ x->x_lin0_log1 = 0;
+ x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_w - 1);
+}
+
+static void mknob_init(t_mknob *x, t_floatarg f)
+{
+ x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
+}
+
+static void mknob_steady(t_mknob *x, t_floatarg f)
+{
+ x->x_steady = (f==0.0)?0:1;
+}
+
+static void mknob_float(t_mknob *x, t_floatarg f)
+{
+ double out;
+
+ mknob_set(x, f);
+ if(x->x_lin0_log1)
+ out = x->x_min*exp(x->x_k*(double)(x->x_val)*0.01);
+ else
+ out = (double)(x->x_val)*0.01*x->x_k + x->x_min;
+ if((out < 1.0e-10)&&(out > -1.0e-10))
+ out = 0.0;
+ if(x->x_gui.x_fsf.x_put_in2out)
+ {
+ outlet_float(x->x_gui.x_obj.ob_outlet, out);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_float(x->x_gui.x_snd->s_thing, out);
+ }
+}
+
+static void mknob_loadbang(t_mknob *x)
+{
+ if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ mknob_bang(x);
+ }
+}
+
+/*static void mknob_list(t_mknob *x, t_symbol *s, int ac, t_atom *av)
+{
+ int l=iemgui_list((void *)x, &x->x_gui, s, ac, av);
+
+ if(l < 0)
+ {
+ if(IS_A_FLOAT(av,0))
+ mknob_float(x, atom_getfloatarg(0, ac, av));
+ }
+ else if(l > 0)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
+ }
+}*/
+
+static void *mknob_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_mknob *x = (t_mknob *)pd_new(mknob_class);
+ int bflcol[]={-262144, -1, -1};
+ //t_symbol *srl[3];
+ int w=MKNOB_DEFAULTSIZE, h=MKNOB_DEFAULTH;
+ int fs=8 ,lilo=0, ldx=-2, ldy=-6, f=0, v=0, steady=1;
+ //int iinit=0, ifstyle=0;
+ double min=0.0, max=(double)(IEM_SL_DEFAULTSIZE-1);
+ //t_iem_init_symargs *init=(t_iem_init_symargs *)(&iinit);
+ //t_iem_fstyle_flags *fstyle=(t_iem_fstyle_flags *)(&ifstyle);
+ char str[144];
+
+ /*srl[0] = gensym("empty");
+ srl[1] = gensym("empty");
+ srl[2] = gensym("empty");*/
+
+ if(((argc == 17)||(argc == 18))&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)
+ &&IS_A_FLOAT(argv,2)&&IS_A_FLOAT(argv,3)
+ &&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5)
+ &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
+ &&(IS_A_SYMBOL(argv,7)||IS_A_FLOAT(argv,7))
+ &&(IS_A_SYMBOL(argv,8)||IS_A_FLOAT(argv,8))
+ &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)
+ &&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)
+ &&IS_A_FLOAT(argv,14)&&IS_A_FLOAT(argv,15)&&IS_A_FLOAT(argv,16))
+ {
+ w = (int)atom_getintarg(0, argc, argv);
+ h = (int)atom_getintarg(1, argc, argv);
+ min = (double)atom_getfloatarg(2, argc, argv);
+ max = (double)atom_getfloatarg(3, argc, argv);
+ lilo = (int)atom_getintarg(4, argc, argv);
+ iem_inttosymargs(&x->x_gui.x_isa, atom_getintarg(5, argc, argv));
+ iemgui_new_getnames(&x->x_gui, 6, argv);
+ ldx = (int)atom_getintarg(9, argc, argv);
+ ldy = (int)atom_getintarg(10, argc, argv);
+ iem_inttofstyle(&x->x_gui.x_fsf, atom_getintarg(11, argc, argv));
+ fs = (int)atom_getintarg(12, argc, argv);
+ bflcol[0] = (int)atom_getintarg(13, argc, argv);
+ bflcol[1] = (int)atom_getintarg(14, argc, argv);
+ bflcol[2] = (int)atom_getintarg(15, argc, argv);
+ v = (int)atom_getintarg(16, argc, argv);
+ /*iinit = (int)atom_getintarg(5, argc, argv);
+ if(IS_A_SYMBOL(argv,6))
+ srl[0] = atom_getsymbolarg(6, argc, argv);
+ else if(IS_A_FLOAT(argv,6))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(6, argc, argv));
+ srl[0] = gensym(str);
+ }
+ if(IS_A_SYMBOL(argv,7))
+ srl[1] = atom_getsymbolarg(7, argc, argv);
+ else if(IS_A_FLOAT(argv,7))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(7, argc, argv));
+ srl[1] = gensym(str);
+ }
+ if(IS_A_SYMBOL(argv,8))
+ srl[2] = atom_getsymbolarg(8, argc, argv);
+ else if(IS_A_FLOAT(argv,8))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(8, argc, argv));
+ srl[2] = gensym(str);
+ }*/
+ //ifstyle = (int)atom_getintarg(11, argc, argv);
+ }
+ else iemgui_new_getnames(&x->x_gui, 6, 0);
+
+ if((argc == 18)&&IS_A_FLOAT(argv,17))
+ steady = (int)atom_getintarg(17, argc, argv);
+
+ /*iinit &= IEM_INIT_ARGS_ALL;
+ ifstyle &= IEM_FSTYLE_FLAGS_ALL;
+ fstyle->x_snd_able = 1;
+ fstyle->x_rcv_able = 1;*/
+ x->x_gui.x_draw = (t_iemfunptr)mknob_draw;
+ x->x_gui.x_fsf.x_snd_able = 1;
+ x->x_gui.x_fsf.x_rcv_able = 1;
+ x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
+ //x->x_gui.x_isa = *init;
+ if(x->x_gui.x_isa.x_loadinit)
+ x->x_val = v;
+ else
+ x->x_val = 0;
+ x->x_pos = x->x_val;
+ if(lilo != 0) lilo = 1;
+ x->x_lin0_log1 = lilo;
+ if(steady != 0) steady = 1;
+ x->x_steady = steady;
+ if(!strcmp(x->x_gui.x_snd->s_name, "empty")) x->x_gui.x_fsf.x_snd_able = 0;
+ if(!strcmp(x->x_gui.x_rcv->s_name, "empty")) x->x_gui.x_fsf.x_rcv_able = 0;
+ //if(!strcmp(srl[0]->s_name, "empty")) fstyle->x_snd_able = 0;
+ //if(!strcmp(srl[1]->s_name, "empty")) fstyle->x_rcv_able = 0;
+ //x->x_gui.x_unique_num = 0;
+ if(x->x_gui.x_fsf.x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
+ else if(x->x_gui.x_fsf.x_font_style == 2) strcpy(x->x_gui.x_font, "times");
+ else { x->x_gui.x_fsf.x_font_style = 0;
+ /*if(fstyle->x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
+ else if(fstyle->x_font_style == 2) strcpy(x->x_gui.x_font, "times");
+ else { fstyle->x_font_style = 0;*/
+ strcpy(x->x_gui.x_font, "courier"); }
+ //x->x_gui.x_fsf = *fstyle;
+ //iemgui_first_dollararg2sym(&x->x_gui, srl);
+ //if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, srl[1]);
+ /*x->x_gui.x_snd = srl[0];
+ x->x_gui.x_rcv = srl[1];
+ x->x_gui.x_lab = srl[2];*/
+ if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
+ x->x_gui.x_ldx = ldx;
+ x->x_gui.x_ldy = ldy;
+ if(fs < 4)
+ fs = 4;
+ x->x_gui.x_fontsize = fs;
+ //x->x_gui.x_h = iemgui_clip_size(h);
+ //x->x_gui.x_w = iemgui_clip_size(w);
+ mknob_check_wh(x, w, h);
+ //mknob_check_width(x, w);
+ mknob_check_minmax(x, min, max);
+ iemgui_all_colfromload(&x->x_gui, bflcol);
+ x->x_thick = 0;
+ iemgui_verify_snd_ne_rcv(&x->x_gui);
+ outlet_new(&x->x_gui.x_obj, &s_float);
+ return (x);
+}
+
+static void mknob_free(t_mknob *x)
+{
+ /*if(x->x_gui.x_fsf.x_selected)
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);*/
+ if(x->x_gui.x_fsf.x_rcv_able)
+ pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
+ gfxstub_deleteforkey(x);
+}
+
+extern void canvas_iemguis(t_glist *gl, t_symbol *guiobjname);
+
+void canvas_mknob(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
+{
+ canvas_iemguis(gl, gensym("mknob"));
+}
+
+void mknob_setup(void)
+{
+ mknob_class = class_new(gensym("mknob"), (t_newmethod)mknob_new,
+ (t_method)mknob_free, sizeof(t_mknob), 0, A_GIMME, 0);
+#ifndef GGEE_mknob_COMPATIBLE
+// class_addcreator((t_newmethod)mknob_new, gensym("mknob"), A_GIMME, 0);
+#endif
+ class_addbang(mknob_class,mknob_bang);
+ class_addfloat(mknob_class,mknob_float);
+ //class_addlist(mknob_class, mknob_list);
+ class_addmethod(mknob_class, (t_method)mknob_click, gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(mknob_class, (t_method)mknob_motion, gensym("motion"),
+ A_FLOAT, A_FLOAT, 0);
+ class_addmethod(mknob_class, (t_method)mknob_dialog, gensym("dialog"), A_GIMME, 0);
+ class_addmethod(mknob_class, (t_method)mknob_loadbang, gensym("loadbang"), 0);
+ class_addmethod(mknob_class, (t_method)mknob_set, gensym("set"), A_FLOAT, 0);
+ class_addmethod(mknob_class, (t_method)mknob_size, gensym("size"), A_GIMME, 0);
+ class_addmethod(mknob_class, (t_method)mknob_delta, gensym("delta"), A_GIMME, 0);
+ class_addmethod(mknob_class, (t_method)mknob_pos, gensym("pos"), A_GIMME, 0);
+ class_addmethod(mknob_class, (t_method)mknob_range, gensym("range"), A_GIMME, 0);
+ class_addmethod(mknob_class, (t_method)mknob_color, gensym("color"), A_GIMME, 0);
+ class_addmethod(mknob_class, (t_method)mknob_send, gensym("send"), A_DEFSYM, 0);
+ class_addmethod(mknob_class, (t_method)mknob_receive, gensym("receive"), A_DEFSYM, 0);
+ class_addmethod(mknob_class, (t_method)mknob_label, gensym("label"), A_DEFSYM, 0);
+ class_addmethod(mknob_class, (t_method)mknob_label_pos, gensym("label_pos"), A_GIMME, 0);
+ class_addmethod(mknob_class, (t_method)mknob_label_font, gensym("label_font"), A_GIMME, 0);
+ class_addmethod(mknob_class, (t_method)mknob_log, gensym("log"), 0);
+ class_addmethod(mknob_class, (t_method)mknob_lin, gensym("lin"), 0);
+ class_addmethod(mknob_class, (t_method)mknob_init, gensym("init"), A_FLOAT, 0);
+ class_addmethod(mknob_class, (t_method)mknob_steady, gensym("steady"), A_FLOAT, 0);
+ /*if(!iemgui_key_sym)
+ iemgui_key_sym = gensym("#keyname");*/
+ mknob_widgetbehavior.w_getrectfn = mknob_getrect;
+ mknob_widgetbehavior.w_displacefn = iemgui_displace;
+ mknob_widgetbehavior.w_selectfn = iemgui_select;
+ mknob_widgetbehavior.w_activatefn = NULL;
+ mknob_widgetbehavior.w_deletefn = iemgui_delete;
+ mknob_widgetbehavior.w_visfn = iemgui_vis;
+ mknob_widgetbehavior.w_clickfn = mknob_newclick;
+ //mknob_widgetbehavior.w_propertiesfn = mknob_properties;
+ //mknob_widgetbehavior.w_savefn = mknob_save;
+ class_setwidget(mknob_class, &mknob_widgetbehavior);
+
+ class_setsavefn(mknob_class, mknob_save);
+ class_setpropertiesfn(mknob_class, mknob_properties);
+ class_addmethod(canvas_class, (t_method)canvas_mknob, gensym("mknob"),
+ A_GIMME, A_NULL);
+}
diff --git a/panvol~.c b/panvol~.c
new file mode 100644
index 0000000..2e302c6
--- /dev/null
+++ b/panvol~.c
@@ -0,0 +1,119 @@
+/***************************************************************************
+ * File: pan~.c
+ * Auth: Iain Mott [iain.mott@bigpond.com]
+ * Maintainer: Iain Mott [iain.mott@bigpond.com]
+ * Version: Part of motex_1.1.2
+ * Date: January 2001
+ *
+ * Description: Pd signal external. Equal-power stereo panning
+ * Angle input specified in degrees. -45 left, 0 centre, 45 right.
+ * See supporting Pd patch: pan~.pd
+ *
+ * Copyright (C) 2001 by Iain Mott [iain.mott@bigpond.com]
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License, which should be included with this
+ * program, for more details.
+ *
+ ****************************************************************************/
+
+/* I've only add a global volume... Antoine Rousseau 2003*/
+
+#include "m_pd.h"
+#include <math.h>
+
+static t_class *pan_class;
+#define RADCONST 0.017453293
+#define ROOT2DIV2 0.707106781
+
+typedef struct _pan
+{
+ t_object x_obj;
+ float x_f;
+ float pan;
+ float left;
+ float right;
+ float vol;
+} t_pan;
+
+static void *pan_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_pan *x = (t_pan *)pd_new(pan_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("panf"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("volf"));
+
+ x->x_f = 0;
+ x->left = ROOT2DIV2;
+ x->right = ROOT2DIV2;
+ x->vol = 1;
+ return (x);
+}
+
+static t_int *pan_perform(t_int *w)
+{
+ float *in1 = (t_float *)(w[1]);
+ float *out1 = (t_float *)(w[2]);
+ float *out2 = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ t_pan *x = (t_pan *)(w[5]);
+ float left=x->left*x->vol;
+ float right=x->right*x->vol;
+ float value;
+
+ while (n--)
+ {
+ value = *in1++;
+ *out1++ = value * left;
+ *out2++ = value * right;
+ }
+ return (w+6);
+}
+
+static void pan_dsp(t_pan *x, t_signal **sp)
+{
+ int n = sp[0]->s_n;
+ float *in1 = sp[0]->s_vec;
+ float *out1 = sp[1]->s_vec;
+ float *out2 = sp[2]->s_vec;
+
+ dsp_add(pan_perform, 5,
+ in1, out1, out2, n, x);
+}
+
+static void pan_f(t_pan *x, t_floatarg f)
+{
+ double angle;
+ f = f < -45 ? -45 : f;
+ f = f > 45 ? 45 : f;
+ angle = f * RADCONST; // convert degrees to radians
+ x->right = ROOT2DIV2 * (cos(angle) + sin(angle));
+ x->left = ROOT2DIV2 * (cos(angle) - sin(angle));
+/* post("left = %f : right = %f", x->left, x->right); */
+}
+
+static void vol_f(t_pan *x, t_floatarg f)
+{
+ f = f < 0 ? 0 : f;
+ x->vol=f;
+}
+
+void panvol_tilde_setup(void)
+{
+ pan_class = class_new(gensym("panvol~"), (t_newmethod)pan_new, 0,
+ sizeof(t_pan), 0, A_GIMME, 0);
+
+ class_addmethod(pan_class, nullfn, gensym("signal"), 0);
+
+ class_addmethod(pan_class, (t_method)pan_dsp, gensym("dsp"), 0);
+ class_addmethod(pan_class, (t_method)pan_f, gensym("panf"), A_FLOAT, 0);
+ class_addmethod(pan_class, (t_method)vol_f, gensym("volf"), A_FLOAT, 0);
+}
diff --git a/popen.c b/popen.c
new file mode 100644
index 0000000..c97a17c
--- /dev/null
+++ b/popen.c
@@ -0,0 +1,211 @@
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#define BUFSIZE 4096
+
+typedef struct popen
+{
+ t_object x_obj;
+ FILE *x_file;
+ char x_data[BUFSIZE];
+ int x_count;
+ int x_ropened;
+ t_outlet *x_msgout;
+} t_popen;
+
+t_class *popen_class;
+static t_binbuf *inbinbuf;
+
+
+static void *popen_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_popen *x;
+
+ x = (t_popen *)pd_new(popen_class);
+
+ x->x_file = NULL;
+ x->x_count=0;
+ x->x_msgout = outlet_new(&x->x_obj, &s_anything);
+ x->x_ropened=0;
+ return (x);
+}
+
+static void popen_close(t_popen *x)
+{
+ if(x->x_ropened) {
+ sys_rmpollfn(fileno(x->x_file));
+ //fflush(x->x_file);
+ }
+ if(x->x_file) pclose(x->x_file);
+ x->x_file=0;
+ x->x_ropened=0;
+}
+
+static void popen_ff(t_popen *x)
+{
+
+}
+
+static void popen_open(t_popen *x, t_symbol *s,int argc, t_atom *argv)
+{
+ char cmd[512],*text;
+ int cmd_len;
+
+ t_binbuf *bb=binbuf_new();
+
+ popen_close(x);
+
+ //post("argc=%d",argc);
+ //post("argv[0]=%s",atom_getsymbol(&argv[0])->s_name);
+
+ binbuf_add(bb,argc,argv);
+ binbuf_gettext(bb, &text,&cmd_len);
+ binbuf_free(bb);
+
+ strncpy(cmd,text,cmd_len);
+ cmd[cmd_len]=0;
+ //post("cmd=%s",cmd);
+
+ x->x_file=popen(cmd,"w");
+
+}
+
+static void popen_list(t_popen *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ t_binbuf *bb;
+ char *buf;
+ int l;
+
+ if(!x->x_file) return;
+
+ bb=binbuf_new();
+ binbuf_add(bb,argc,argv);
+ //binbuf_print(bb);
+ binbuf_gettext(bb, &buf,&l);
+ buf[l]=0;
+
+ //printf("popen list: %s\n",buf);
+ fprintf(x->x_file,"%s\n",buf);fflush(x->x_file);
+
+ freebytes(buf,l);
+ binbuf_free(bb);
+}
+
+static void popen_out(t_popen *x, t_binbuf *b)
+{
+ t_atom messbuf[1024];
+ int msg, natom = binbuf_getnatom(b);
+ t_atom *at = binbuf_getvec(b);
+ for (msg = 0; msg < natom;)
+ {
+ int emsg;
+ for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA
+ && at[emsg].a_type != A_SEMI; emsg++)
+ ;
+ if (emsg > msg)
+ {
+ int i;
+ for (i = msg; i < emsg; i++)
+ if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM)
+ {
+ pd_error(x, "popen: got dollar sign in message");
+ goto nodice;
+ }
+ if (at[msg].a_type == A_FLOAT)
+ {
+ if (emsg > msg + 1)
+ outlet_list(x->x_msgout, 0, emsg-msg, at + msg);
+ else outlet_float(x->x_msgout, at[msg].a_w.w_float);
+ }
+ else if (at[msg].a_type == A_SYMBOL)
+ outlet_anything(x->x_msgout, at[msg].a_w.w_symbol,
+ emsg-msg-1, at + msg + 1);
+ }
+ nodice:
+ msg = emsg + 1;
+ }
+}
+
+static void popen_read(t_popen *x,int fd)
+{
+ int len,i=0;
+ unsigned char b;
+ unsigned char buffer[BUFSIZE];
+
+ if((len=read(fd,buffer,BUFSIZE))> 0){
+
+ for(i=0;i<len;i++){
+ if(x->x_count>=BUFSIZE) x->x_count=0;
+ x->x_data[x->x_count++]=buffer[i];
+ if(buffer[i]==';') {
+ binbuf_text(inbinbuf, x->x_data, x->x_count);
+ x->x_count=0;
+ popen_out(x,inbinbuf);
+ }
+ }
+ }
+}
+
+static void popen_ropen(t_popen *x, t_symbol *s,int argc, t_atom *argv)
+{
+ char cmd[512],*text;
+ int cmd_len;
+
+ t_binbuf *bb=binbuf_new();
+
+ popen_close(x);
+
+ //post("argc=%d",argc);
+ //post("argv[0]=%s",atom_getsymbol(&argv[0])->s_name);
+
+ binbuf_add(bb,argc,argv);
+ binbuf_gettext(bb, &text,&cmd_len);
+ binbuf_free(bb);
+
+ strncpy(cmd,text,cmd_len);
+ cmd[cmd_len]=0;
+ //post("cmd=%s",cmd);
+
+ x->x_file=popen(cmd,"r");
+ sys_addpollfn(fileno(x->x_file),(t_fdpollfn)popen_read,(void*)x);
+ x->x_ropened=1;
+}
+
+void popen_setup(void )
+{
+ inbinbuf = binbuf_new();
+ popen_class = class_new(gensym("popen"), (t_newmethod)popen_new,
+ (t_method)popen_close,sizeof(t_popen), 0, A_GIMME, 0);
+ class_addmethod(popen_class, (t_method)popen_close,
+ gensym("close"), 0);
+ class_addmethod(popen_class, (t_method)popen_open,
+ gensym("open"), A_GIMME, 0);
+ class_addmethod(popen_class, (t_method)popen_ropen,
+ gensym("ropen"), A_GIMME, 0);
+ class_addlist(popen_class, popen_list);
+
+}
+
diff --git a/readsfv~.c b/readsfv~.c
new file mode 100644
index 0000000..6707cf1
--- /dev/null
+++ b/readsfv~.c
@@ -0,0 +1,1683 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* this file contains, first, a collection of soundfile access routines, a
+sort of soundfile library. Second, the "soundfiler" object is defined which
+uses the routines to read or write soundfiles, synchronously, from garrays.
+These operations are not to be done in "real time" as they may have to wait
+for disk accesses (even the write routine.) Finally, the realtime objects
+readsf~ and writesf~ are defined which confine disk operations to a separate
+thread so that they can be used in real time. The real-time disk access
+objects are available for linux only so far, although they could be compiled
+for Windows if someone were willing to find a Pthreads package for it. */
+
+/* this is a partial copy of d_soundfile, with some hacking:
+ 1: a fix in soundfiler to compute the normalization factor only on
+ the samples we want to write on the disk...
+ 2: a version of readsf~ that works with a (positive) speed parameter.
+
+ Antoine Rousseau
+*/
+
+#ifdef UNIX
+#include <unistd.h>
+#include <fcntl.h>
+#endif
+#include <pthread.h>
+#ifdef NT
+#include <io.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "m_pd.h"
+
+#define MAXSFCHANS 4
+
+
+/***************** soundfile header structures ************************/
+
+typedef unsigned short uint16;
+typedef unsigned long uint32;
+
+#define FORMAT_WAVE 0
+#define FORMAT_AIFF 1
+#define FORMAT_NEXT 2
+
+/* the NeXTStep sound header structure; can be big or little endian */
+
+typedef struct _nextstep
+{
+ char ns_fileid[4]; /* magic number '.snd' if file is big-endian */
+ uint32 ns_onset; /* byte offset of first sample */
+ uint32 ns_length; /* length of sound in bytes */
+ uint32 ns_format; /* format; see below */
+ uint32 ns_sr; /* sample rate */
+ uint32 ns_nchans; /* number of channels */
+ char ns_info[4]; /* comment */
+} t_nextstep;
+
+#define NS_FORMAT_LINEAR_16 3
+#define NS_FORMAT_LINEAR_24 4
+#define NS_FORMAT_FLOAT 6
+#define SCALE (1./(1024. * 1024. * 1024. * 2.))
+
+/* the WAVE header. All Wave files are little endian. We assume
+ the "fmt" chunk comes first which is usually the case but perhaps not
+ always; same for AIFF and the "COMM" chunk. */
+
+typedef unsigned word;
+typedef unsigned long dword;
+
+typedef struct _wave
+{
+ char w_fileid[4]; /* chunk id 'RIFF' */
+ uint32 w_chunksize; /* chunk size */
+ char w_waveid[4]; /* wave chunk id 'WAVE' */
+ char w_fmtid[4]; /* format chunk id 'fmt ' */
+ uint32 w_fmtchunksize; /* format chunk size */
+ uint16 w_fmttag; /* format tag, 1 for PCM */
+ uint16 w_nchannels; /* number of channels */
+ uint32 w_samplespersec; /* sample rate in hz */
+ uint32 w_navgbytespersec; /* average bytes per second */
+ uint16 w_nblockalign; /* number of bytes per sample */
+ uint16 w_nbitspersample; /* number of bits in a sample */
+ char w_datachunkid[4]; /* data chunk id 'data' */
+ uint32 w_datachunksize; /* length of data chunk */
+} t_wave;
+
+typedef struct _fmt /* format chunk */
+{
+ uint16 f_fmttag; /* format tag, 1 for PCM */
+ uint16 f_nchannels; /* number of channels */
+ uint32 f_samplespersec; /* sample rate in hz */
+ uint32 f_navgbytespersec; /* average bytes per second */
+ uint16 f_nblockalign; /* number of bytes per frame */
+ uint16 f_nbitspersample; /* number of bits in a sample */
+} t_fmt;
+
+typedef struct _wavechunk /* ... and the last two items */
+{
+ char wc_id[4]; /* data chunk id, e.g., 'data' or 'fmt ' */
+ uint32 wc_size; /* length of data chunk */
+} t_wavechunk;
+
+/* the AIFF header. I'm assuming AIFC is compatible but don't really know
+ that. */
+
+typedef struct _datachunk
+{
+ char dc_id[4]; /* data chunk id 'SSND' */
+ uint32 dc_size; /* length of data chunk */
+} t_datachunk;
+
+//#define CHUNKHDRSIZE sizeof(t_datachunk)
+
+typedef struct _comm
+{
+ uint16 c_nchannels; /* number of channels */
+ uint16 c_nframeshi; /* # of sample frames (hi) */
+ uint16 c_nframeslo; /* # of sample frames (lo) */
+ uint16 c_bitspersamp; /* bits per sample */
+ unsigned char c_samprate[10]; /* sample rate, 80-bit float! */
+} t_comm;
+
+ /* this version is more convenient for writing them out: */
+typedef struct _aiff
+{
+ char a_fileid[4]; /* chunk id 'FORM' */
+ uint32 a_chunksize; /* chunk size */
+ char a_aiffid[4]; /* aiff chunk id 'AIFF' */
+ char a_fmtid[4]; /* format chunk id 'COMM' */
+ uint32 a_fmtchunksize; /* format chunk size, 18 */
+ uint16 a_nchannels; /* number of channels */
+ uint16 a_nframeshi; /* # of sample frames (hi) */
+ uint16 a_nframeslo; /* # of sample frames (lo) */
+ uint16 a_bitspersamp; /* bits per sample */
+ unsigned char a_samprate[10]; /* sample rate, 80-bit float! */
+} t_aiff;
+
+#define AIFFHDRSIZE 38 /* probably not what sizeof() gives */
+
+
+#define AIFFPLUS (AIFFHDRSIZE + 8) /* header size including first chunk hdr */
+
+#define WHDR1 sizeof(t_nextstep)
+#define WHDR2 (sizeof(t_wave) > WHDR1 ? sizeof (t_wave) : WHDR1)
+#define WRITEHDRSIZE (AIFFPLUS > WHDR2 ? AIFFPLUS : WHDR2)
+
+#define READHDRSIZE (16 > WHDR2 ? 16 : WHDR2)
+
+#define OBUFSIZE MAXPDSTRING /* assume MAXPDSTRING is bigger than headers */
+
+#ifdef NT
+#include <fcntl.h>
+#define BINCREATE _O_WRONLY | _O_CREAT | _O_BINARY | _O_TRUNC |
+#else
+#define BINCREATE O_WRONLY|O_CREAT|O_TRUNC
+#endif
+
+/* this routine returns 1 if the high order byte comes at the lower
+address on our architecture (big-endianness.). It's 1 for Motorola,
+0 for Intel: */
+
+extern int garray_ambigendian(void);
+
+/* byte swappers */
+
+static uint32 swap4(uint32 n, int doit)
+{
+ if (doit)
+ return (((n & 0xff) << 24) | ((n & 0xff00) << 8) |
+ ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24));
+ else return (n);
+}
+
+static uint16 swap2(uint32 n, int doit)
+{
+ if (doit)
+ return (((n & 0xff) << 8) | ((n & 0xff00) >> 8));
+ else return (n);
+}
+
+static void swapstring(char *foo, int doit)
+{
+ if (doit)
+ {
+ char a = foo[0], b = foo[1], c = foo[2], d = foo[3];
+ foo[0] = d; foo[1] = c; foo[2] = b; foo[3] = a;
+ }
+}
+
+/******************** soundfile access routines **********************/
+
+void readsf_banana( void); /* debugging */
+
+/* This routine opens a file, looks for either a nextstep or "wave" header,
+* seeks to end of it, and fills in bytes per sample and number of channels.
+* Only 2- and 3-byte fixed-point samples and 4-byte floating point samples
+* are supported. If "headersize" is nonzero, the
+* caller should supply the number of channels, endinanness, and bytes per
+* sample; the header is ignored. Otherwise, the routine tries to read the
+* header and fill in the properties.
+*/
+
+extern int open_soundfile(const char *dirname, const char *filename, int headersize,
+ int *p_bytespersamp, int *p_bigendian, int *p_nchannels, long *p_bytelimit,
+ long skipframes);
+
+
+static void soundfile_xferin(int sfchannels, int nvecs, float **vecs,
+ long itemsread, unsigned char *buf, int nitems, int bytespersamp,
+ int bigendian)
+{
+ int i, j;
+ unsigned char *sp, *sp2;
+ float *fp;
+ int nchannels = (sfchannels < nvecs ? sfchannels : nvecs);
+ int bytesperframe = bytespersamp * sfchannels;
+ for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp)
+ {
+ if (bytespersamp == 2)
+ {
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16));
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *fp = SCALE * ((sp2[1] << 24) | (sp2[0] << 16));
+ }
+ }
+ else if (bytespersamp == 3)
+ {
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16)
+ | (sp2[2] << 8));
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *fp = SCALE * ((sp2[2] << 24) | (sp2[1] << 16)
+ | (sp2[0] << 8));
+ }
+ }
+ else if (bytespersamp == 4)
+ {
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *(long *)fp = ((sp2[0] << 24) | (sp2[1] << 16)
+ | (sp2[2] << 8) | sp2[3]);
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *(long *)fp = ((sp2[3] << 24) | (sp2[2] << 16)
+ | (sp2[1] << 8) | sp2[0]);
+ }
+ }
+ }
+ /* zero out other outputs */
+ for (i = sfchannels; i < nvecs; i++)
+ for (j = nitems, fp = vecs[i]; j--; )
+ *fp++ = 0;
+
+}
+
+static void interpolate(int nvec,float **invec,int nin,
+ float **outvec,int nout)
+{
+
+ float r=nin/(float)nout;
+ int i,j;
+
+
+ for(i=0;i<nout;i++)
+ for(j=0;j<nvec;j++)
+ outvec[j][i]=invec[j][(int)(i*r)];
+
+}
+ /* soundfiler2_write ...
+
+ usage: write [flags] filename table ...
+ flags:
+ -nframes <frames>
+ -skip <frames>
+ -bytes <bytes per sample>
+ -normalize
+ -nextstep
+ -wave
+ -big
+ -little
+ */
+
+ /* the routine which actually does the work should LATER also be called
+ from garray_write16. */
+
+
+ /* Parse arguments for writing. The "obj" argument is only for flagging
+ errors. For streaming to a file the "normalize", "onset" and "nframes"
+ arguments shouldn't be set but the calling routine flags this. */
+
+static int soundfiler2_writeargparse(void *obj, int *p_argc, t_atom **p_argv,
+ t_symbol **p_filesym,
+ int *p_filetype, int *p_bytespersamp, int *p_swap, int *p_bigendian,
+ int *p_normalize, long *p_onset, long *p_nframes,float *p_amp)
+{
+ int argc = *p_argc;
+ t_atom *argv = *p_argv;
+ int bytespersamp = 2, bigendian = 0,
+ endianness = -1, swap, filetype = FORMAT_WAVE, normalize = 0;
+ long onset = 0, nframes = 0x7fffffff;
+ float amp=1;
+ t_symbol *filesym;
+ while (argc > 0 && argv->a_type == A_SYMBOL &&
+ *argv->a_w.w_symbol->s_name == '-')
+ {
+ char *flag = argv->a_w.w_symbol->s_name + 1;
+ if (!strcmp(flag, "skip"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((onset = argv[1].a_w.w_float) < 0))
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(flag, "nframes"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((nframes = argv[1].a_w.w_float) < 0))
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(flag, "bytes"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((bytespersamp = argv[1].a_w.w_float) < 2) ||
+ bytespersamp > 4)
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(flag, "normalize"))
+ {
+ normalize = 1;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "amp"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT)
+ goto usage;
+ amp = argv[1].a_w.w_float;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(flag, "wave"))
+ {
+ filetype = FORMAT_WAVE;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "nextstep"))
+ {
+ filetype = FORMAT_NEXT;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "aiff"))
+ {
+ filetype = FORMAT_AIFF;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "big"))
+ {
+ endianness = 1;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "little"))
+ {
+ endianness = 1;
+ argc -= 1; argv += 1;
+ }
+ else goto usage;
+ }
+ /* only NextStep handles floating point samples */
+ if (bytespersamp == 4)
+ filetype = FORMAT_NEXT;
+
+ /* for WAVE force little endian; for nextstep use machine native */
+ if (filetype == FORMAT_WAVE)
+ {
+ bigendian = 0;
+ if (endianness == 1)
+ pd_error(obj, "WAVE file forced to little endian");
+ }
+ else if (filetype == FORMAT_AIFF)
+ {
+ bigendian = 1;
+ if (endianness == 0)
+ pd_error(obj, "AIFF file forced to big endian");
+ }
+ else if (endianness == -1)
+ {
+ bigendian = garray_ambigendian();
+ }
+ swap = (bigendian != garray_ambigendian());
+ if (!argc || argv->a_type != A_SYMBOL)
+ goto usage;
+ filesym = argv->a_w.w_symbol;
+ argc--; argv++;
+
+ *p_argc = argc;
+ *p_argv = argv;
+ *p_filesym = filesym;
+ *p_filetype = filetype;
+ *p_bytespersamp = bytespersamp;
+ *p_swap = swap;
+ *p_normalize = normalize;
+ *p_onset = onset;
+ *p_nframes = nframes;
+ *p_bigendian = bigendian;
+ *p_amp = amp;
+ return (0);
+usage:
+ return (-1);
+}
+
+static int create_soundfile2(t_canvas *canvas, const char *filename,
+ int filetype, int nframes, int bytespersamp,
+ int bigendian, int nchannels, int swap)
+{
+ char filenamebuf[MAXPDSTRING], buf2[MAXPDSTRING];
+ char headerbuf[WRITEHDRSIZE];
+ t_wave *wavehdr = (t_wave *)headerbuf;
+ t_nextstep *nexthdr = (t_nextstep *)headerbuf;
+ t_aiff *aiffhdr = (t_aiff *)headerbuf;
+ int fd, headersize = 0;
+
+ strncpy(filenamebuf, filename, MAXPDSTRING-10);
+ filenamebuf[MAXPDSTRING-10] = 0;
+
+ if (filetype == FORMAT_NEXT)
+ {
+ if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".snd"))
+ strcat(filenamebuf, ".snd");
+ if (bigendian)
+ strncpy(nexthdr->ns_fileid, ".snd", 4);
+ else strncpy(nexthdr->ns_fileid, "dns.", 4);
+ nexthdr->ns_onset = swap4(sizeof(*nexthdr), swap);
+ nexthdr->ns_length = 0;
+ nexthdr->ns_format = swap4((bytespersamp == 3 ? NS_FORMAT_LINEAR_24 :
+ (bytespersamp == 4 ? NS_FORMAT_FLOAT : NS_FORMAT_LINEAR_16)), swap);;
+ nexthdr->ns_sr = swap4(44100, swap); /* lie */
+ nexthdr->ns_nchans = swap4(nchannels, swap);
+ strcpy(nexthdr->ns_info, "Pd ");
+ swapstring(nexthdr->ns_info, swap);
+ headersize = sizeof(t_nextstep);
+ }
+ else if (filetype == FORMAT_AIFF)
+ {
+ long datasize = nframes * nchannels * bytespersamp;
+ long longtmp;
+ static unsigned char dogdoo[] =
+ {0x40, 0x0e, 0xac, 0x44, 0, 0, 0, 0, 0, 0, 'S', 'S', 'N', 'D'};
+ if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".aif") &&
+ strcmp(filenamebuf + strlen(filenamebuf)-5, ".aiff"))
+ strcat(filenamebuf, ".aif");
+ strncpy(aiffhdr->a_fileid, "FORM", 4);
+ aiffhdr->a_chunksize = swap4(datasize + sizeof(*aiffhdr) + 4, swap);
+ strncpy(aiffhdr->a_aiffid, "AIFF", 4);
+ strncpy(aiffhdr->a_fmtid, "COMM", 4);
+ aiffhdr->a_fmtchunksize = swap4(18, swap);
+ aiffhdr->a_nchannels = swap2(nchannels, swap);
+ longtmp = swap4(nframes, swap);
+ memcpy(&aiffhdr->a_nframeshi, &longtmp, 4);
+ aiffhdr->a_bitspersamp = swap2(8 * bytespersamp, swap);
+ memcpy(aiffhdr->a_samprate, dogdoo, sizeof(dogdoo));
+ longtmp = swap4(datasize, swap);
+ memcpy(aiffhdr->a_samprate + sizeof(dogdoo), &longtmp, 4);
+ headersize = AIFFPLUS;
+ }
+ else /* WAVE format */
+ {
+ long datasize = nframes * nchannels * bytespersamp;
+ if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".wav"))
+ strcat(filenamebuf, ".wav");
+ strncpy(wavehdr->w_fileid, "RIFF", 4);
+ wavehdr->w_chunksize = swap4(datasize + sizeof(*wavehdr) - 8, swap);
+ strncpy(wavehdr->w_waveid, "WAVE", 4);
+ strncpy(wavehdr->w_fmtid, "fmt ", 4);
+ wavehdr->w_fmtchunksize = swap4(16, swap);
+ wavehdr->w_fmttag = swap2(1, swap);
+ wavehdr->w_nchannels = swap2(nchannels, swap);
+ wavehdr->w_samplespersec = swap4(44100, swap);
+ wavehdr->w_navgbytespersec = swap4(44100 * nchannels * bytespersamp, swap);
+ wavehdr->w_nblockalign = swap2(bytespersamp, swap);
+ wavehdr->w_nbitspersample = swap2(8 * bytespersamp, swap);
+ strncpy(wavehdr->w_datachunkid, "data", 4);
+ wavehdr->w_datachunksize = swap4(datasize, swap);
+ headersize = sizeof(t_wave);
+ }
+
+ canvas_makefilename(canvas, filenamebuf, buf2, MAXPDSTRING);
+ sys_bashfilename(buf2, buf2);
+ if ((fd = open(buf2, BINCREATE, 0666)) < 0)
+ return (-1);
+
+ if (write(fd, headerbuf, headersize) < headersize)
+ {
+ close (fd);
+ return (-1);
+ }
+ return (fd);
+}
+
+static void soundfile_finishwrite(void *obj, char *filename, int fd,
+ int filetype, long nframes, long itemswritten, int bytesperframe, int swap)
+{
+ if (itemswritten < nframes)
+ {
+ if (nframes < 0x7fffffff)
+ pd_error(obj, "soundfiler2_write: %d out of %d bytes written",
+ itemswritten, nframes);
+ /* try to fix size fields in header */
+ if (filetype == FORMAT_WAVE)
+ {
+ long datasize = itemswritten * bytesperframe, mofo;
+
+ if (lseek(fd,
+ ((char *)(&((t_wave *)0)->w_chunksize)) - (char *)0,
+ SEEK_SET) == 0)
+ goto baddonewrite;
+ mofo = swap4(datasize + sizeof(t_wave) - 8, swap);
+ if (write(fd, (char *)(&mofo), 4) < 4)
+ goto baddonewrite;
+ if (lseek(fd,
+ ((char *)(&((t_wave *)0)->w_datachunksize)) - (char *)0,
+ SEEK_SET) == 0)
+ goto baddonewrite;
+ mofo = swap4(datasize, swap);
+ if (write(fd, (char *)(&mofo), 4) < 4)
+ goto baddonewrite;
+ }
+ if (filetype == FORMAT_AIFF)
+ {
+ long mofo;
+ if (lseek(fd,
+ ((char *)(&((t_aiff *)0)->a_nframeshi)) - (char *)0,
+ SEEK_SET) == 0)
+ goto baddonewrite;
+ mofo = swap4(nframes, swap);
+ if (write(fd, (char *)(&mofo), 4) < 4)
+ goto baddonewrite;
+ }
+ }
+ return;
+baddonewrite:
+ post("%s: %s", filename, strerror(errno));
+}
+
+static void soundfile_xferout(int nchannels, float **vecs,
+ unsigned char *buf, int nitems, long onset, int bytespersamp,
+ int bigendian, float normalfactor)
+{
+ int i, j;
+ unsigned char *sp, *sp2;
+ float *fp;
+ int bytesperframe = bytespersamp * nchannels;
+ long xx;
+ for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp)
+ {
+ if (bytespersamp == 2)
+ {
+ float ff = normalfactor * 32768.;
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp = vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ int xx = 32768. + (*fp * ff);
+ xx -= 32768;
+ if (xx < -32767)
+ xx = -32767;
+ if (xx > 32767)
+ xx = 32767;
+ sp2[0] = (xx >> 8);
+ sp2[1] = xx;
+ }
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ int xx = 32768. + (*fp * ff);
+ xx -= 32768;
+ if (xx < -32767)
+ xx = -32767;
+ if (xx > 32767)
+ xx = 32767;
+ sp2[1] = (xx >> 8);
+ sp2[0] = xx;
+ }
+ }
+ }
+ else if (bytespersamp == 3)
+ {
+ float ff = normalfactor * 8388608.;
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ int xx = 8388608. + (*fp * ff);
+ xx -= 8388608;
+ if (xx < -8388607)
+ xx = -8388607;
+ if (xx > 8388607)
+ xx = 8388607;
+ sp2[0] = (xx >> 16);
+ sp2[1] = (xx >> 8);
+ sp2[2] = xx;
+ }
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ int xx = 8388608. + (*fp * ff);
+ xx -= 8388608;
+ if (xx < -8388607)
+ xx = -8388607;
+ if (xx > 8388607)
+ xx = 8388607;
+ sp2[2] = (xx >> 16);
+ sp2[1] = (xx >> 8);
+ sp2[0] = xx;
+ }
+ }
+ }
+ else if (bytespersamp == 4)
+ {
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ float f2 = *fp * normalfactor;
+ xx = *(long *)&f2;
+ sp2[0] = (xx >> 24); sp2[1] = (xx >> 24);
+ sp2[2] = (xx >> 24); sp2[3] = xx;
+ }
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ float f2 = *fp * normalfactor;
+ xx = *(long *)&f2;
+ sp2[3] = (xx >> 24); sp2[2] = (xx >> 24);
+ sp2[1] = (xx >> 24); sp2[0] = xx;
+ }
+ }
+ }
+ }
+}
+
+
+/* ------- soundfiler - reads and writes soundfiles to/from "garrays" ---- */
+#define DEFMAXSIZE 4000000 /* default maximum 16 MB per channel */
+#define SAMPBUFSIZE 1024
+
+
+static t_class *soundfiler2_class;
+
+typedef struct _soundfiler2
+{
+ t_object x_obj;
+ t_canvas *x_canvas;
+} t_soundfiler2;
+
+static t_soundfiler2 *soundfiler2_new(void)
+{
+ t_soundfiler2 *x = (t_soundfiler2 *)pd_new(soundfiler2_class);
+ x->x_canvas = canvas_getcurrent();
+ outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+ /* soundfiler2_read ...
+
+ usage: read [flags] filename table ...
+ flags:
+ -skip <frames> ... frames to skip in file
+ -nframes <frames>
+ -onset <frames> ... onset in table to read into (NOT DONE YET)
+ -raw <headersize channels bytes endian>
+ -resize
+ -maxsize <max-size>
+ */
+
+static void soundfiler2_read(t_soundfiler2 *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ int headersize = -1, channels = 0, bytespersamp = 0, bigendian = 0,
+ resize = 0, i, j;
+ long skipframes = 0, nframes = 0, finalsize = 0, itemsleft,
+ maxsize = DEFMAXSIZE, itemsread = 0, bytelimit = 0x7fffffff;
+ int fd = -1;
+ char endianness, *filename;
+ t_garray *garrays[MAXSFCHANS];
+ t_float *vecs[MAXSFCHANS];
+ char sampbuf[SAMPBUFSIZE];
+ int bufframes, nitems;
+ FILE *fp;
+ while (argc > 0 && argv->a_type == A_SYMBOL &&
+ *argv->a_w.w_symbol->s_name == '-')
+ {
+ char *flag = argv->a_w.w_symbol->s_name + 1;
+ if (!strcmp(flag, "skip"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((skipframes = argv[1].a_w.w_float) < 0))
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(flag, "nframes"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((nframes = argv[1].a_w.w_float) < 0))
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(flag, "raw"))
+ {
+ if (argc < 5 ||
+ argv[1].a_type != A_FLOAT ||
+ ((headersize = argv[1].a_w.w_float) < 0) ||
+ argv[2].a_type != A_FLOAT ||
+ ((channels = argv[2].a_w.w_float) < 1) ||
+ (channels > MAXSFCHANS) ||
+ argv[3].a_type != A_FLOAT ||
+ ((bytespersamp = argv[3].a_w.w_float) < 2) ||
+ (bytespersamp > 4) ||
+ argv[4].a_type != A_SYMBOL ||
+ ((endianness = argv[4].a_w.w_symbol->s_name[0]) != 'b'
+ && endianness != 'l' && endianness != 'n'))
+ goto usage;
+ if (endianness == 'b')
+ bigendian = 1;
+ else if (endianness == 'l')
+ bigendian = 0;
+ else
+ bigendian = garray_ambigendian();
+ argc -= 5; argv += 5;
+ }
+ else if (!strcmp(flag, "resize"))
+ {
+ resize = 1;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "maxsize"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((maxsize = argv[1].a_w.w_float) < 0))
+ goto usage;
+ resize = 1; /* maxsize implies resize. */
+ argc -= 2; argv += 2;
+ }
+ else goto usage;
+ }
+ if (argc < 2 || argc > MAXSFCHANS + 1 || argv[0].a_type != A_SYMBOL)
+ goto usage;
+ filename = argv[0].a_w.w_symbol->s_name;
+ argc--; argv++;
+
+ for (i = 0; i < argc; i++)
+ {
+ int vecsize;
+ if (argv[i].a_type != A_SYMBOL)
+ goto usage;
+ if (!(garrays[i] =
+ (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class)))
+ {
+ pd_error(x, "%s: no such table", argv[i].a_w.w_symbol->s_name);
+ goto done;
+ }
+ else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
+ error("%s: bad template for tabwrite",
+ argv[i].a_w.w_symbol->s_name);
+ if (finalsize && finalsize != vecsize && !resize)
+ {
+ post("soundfiler2_read: arrays have different lengths; resizing...");
+ resize = 1;
+ }
+ finalsize = vecsize;
+ }
+ fd = open_soundfile(canvas_getdir(x->x_canvas)->s_name, filename,
+ headersize, &bytespersamp, &bigendian, &channels, &bytelimit,
+ skipframes);
+
+ if (fd < 0)
+ {
+ pd_error(x, "soundfiler2_read: %s: %s", filename, (errno == EIO ?
+ "unknown or bad header format" : strerror(errno)));
+ goto done;
+ }
+
+ if (resize)
+ {
+ /* figure out what to resize to */
+ long poswas, eofis, framesinfile;
+
+ poswas = lseek(fd, 0, SEEK_CUR);
+ eofis = lseek(fd, 0, SEEK_END);
+ if (poswas < 0 || eofis < 0)
+ {
+ pd_error(x, "lseek failed");
+ goto done;
+ }
+ lseek(fd, poswas, SEEK_SET);
+ framesinfile = (eofis - poswas) / (channels * bytespersamp);
+ if (framesinfile > maxsize)
+ {
+ pd_error(x, "soundfiler2_read: truncated to %d elements", maxsize);
+ framesinfile = maxsize;
+ }
+ if (framesinfile > bytelimit / bytespersamp)
+ framesinfile = bytelimit / bytespersamp;
+ finalsize = framesinfile;
+ for (i = 0; i < argc; i++)
+ {
+ int vecsize;
+
+ garray_resize(garrays[i], finalsize);
+ /* for sanity's sake let's clear the save-in-patch flag here */
+ garray_setsaveit(garrays[i], 0);
+ garray_getfloatarray(garrays[i], &vecsize, &vecs[i]);
+ /* if the resize failed, garray_resize reported the error */
+ if (vecsize != framesinfile)
+ {
+ pd_error(x, "resize failed");
+ goto done;
+ }
+ }
+ }
+ if (!finalsize) finalsize = 0x7fffffff;
+ if (finalsize > bytelimit / bytespersamp)
+ finalsize = bytelimit / bytespersamp;
+ fp = fdopen(fd, "rb");
+ bufframes = SAMPBUFSIZE / (channels * bytespersamp);
+
+ for (itemsread = 0; itemsread < finalsize; )
+ {
+ int thisread = finalsize - itemsread;
+ thisread = (thisread > bufframes ? bufframes : thisread);
+ nitems = fread(sampbuf, channels * bytespersamp, thisread, fp);
+ if (nitems <= 0) break;
+ soundfile_xferin(channels, argc, vecs, itemsread,
+ (unsigned char *)sampbuf, nitems, bytespersamp, bigendian);
+ itemsread += nitems;
+ }
+ /* zero out remaining elements of vectors */
+
+ for (i = 0; i < argc; i++)
+ {
+ int nzero, vecsize;
+ garray_getfloatarray(garrays[i], &vecsize, &vecs[i]);
+ for (j = itemsread; j < vecsize; j++)
+ vecs[i][j] = 0;
+ }
+ /* zero out vectors in excess of number of channels */
+ for (i = channels; i < argc; i++)
+ {
+ int vecsize;
+ float *foo;
+ garray_getfloatarray(garrays[i], &vecsize, &foo);
+ for (j = 0; j < vecsize; j++)
+ foo[j] = 0;
+ }
+ /* do all graphics updates */
+ for (i = 0; i < argc; i++)
+ garray_redraw(garrays[i]);
+ fclose(fp);
+ fd = -1;
+ goto done;
+usage:
+ pd_error(x, "usage: read [flags] filename tablename...");
+ post("flags: -skip <n> -nframes <n> -resize -maxsize <n> ...");
+ post("-raw <headerbytes> <channels> <bytespersamp> <endian (b, l, or n)>.");
+done:
+ if (fd >= 0)
+ close (fd);
+ outlet_float(x->x_obj.ob_outlet, (float)itemsread);
+}
+
+ /* this is broken out from soundfiler2_write below so garray_write can
+ call it too... not done yet though. */
+
+static long soundfiler2_dowrite(void *obj, t_canvas *canvas,
+ int argc, t_atom *argv)
+{
+ int headersize, bytespersamp, bigendian,
+ endianness, swap, filetype, normalize, i, j, nchannels;
+ long onset, nframes, itemsleft,
+ maxsize = DEFMAXSIZE, itemswritten = 0;
+ t_garray *garrays[MAXSFCHANS];
+ t_float *vecs[MAXSFCHANS];
+ char sampbuf[SAMPBUFSIZE];
+ int bufframes, nitems;
+ int fd = -1;
+ float normfactor, biggest = 0,ftmp,amp;
+ t_symbol *filesym;
+
+ if (soundfiler2_writeargparse(obj, &argc, &argv, &filesym, &filetype,
+ &bytespersamp, &swap, &bigendian, &normalize, &onset, &nframes,&amp))
+ goto usage;
+ nchannels = argc;
+ if (nchannels < 1 || nchannels > MAXSFCHANS)
+ goto usage;
+
+ for (i = 0; i < nchannels; i++)
+ {
+ int vecsize;
+
+ if (argv[i].a_type != A_SYMBOL) goto usage;
+
+ if (!(garrays[i] =
+ (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class)))
+ {
+ pd_error(obj, "%s: no such table", argv[i].a_w.w_symbol->s_name);
+ goto fail;
+ }
+ else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
+ error("%s: bad template for tabwrite",argv[i].a_w.w_symbol->s_name);
+ if (nframes > vecsize - onset)
+ nframes = vecsize - onset;
+
+ for (j = 0; j < nframes; j++) /* FIXED (Antoine Rousseau)*/
+ {
+ ftmp=vecs[i][j+onset];
+ if (ftmp > biggest) biggest = ftmp;
+ else if (-ftmp > biggest) biggest = -ftmp;
+ }
+ }
+
+ if (nframes <= 0)
+ {
+ pd_error(obj, "soundfiler2_write: no samples at onset %ld", onset);
+ goto fail;
+ }
+
+ if ((fd = create_soundfile2(canvas, filesym->s_name, filetype,
+ nframes, bytespersamp, bigendian, nchannels,
+ swap)) < 0)
+ {
+ post("%s: %s\n", filesym->s_name, strerror(errno));
+ goto fail;
+ }
+ if (!normalize)
+ {
+ if ((bytespersamp != 4) && (biggest > 1))
+ {
+ //post("%s: normalizing max amplitude %f to 1", filesym->s_name, biggest);
+ normalize = 1;
+ }
+ //else post("%s: biggest amplitude = %f", filesym->s_name, biggest);
+ }
+ if (normalize)
+ normfactor = (biggest > 0 ? 32767./(32768. * biggest) : 1);
+ else normfactor = amp;
+
+ /*post("%s: biggest amplitude = %f , normfactor = %f",
+ filesym->s_name, biggest,normfactor);*/
+
+ bufframes = SAMPBUFSIZE / (nchannels * bytespersamp);
+
+ for (itemswritten = 0; itemswritten < nframes; )
+ {
+ int thiswrite = nframes - itemswritten, nitems, nbytes;
+ thiswrite = (thiswrite > bufframes ? bufframes : thiswrite);
+ soundfile_xferout(argc, vecs, (unsigned char *)sampbuf, thiswrite,
+ onset, bytespersamp, bigendian, normfactor);
+ nbytes = write(fd, sampbuf, nchannels * bytespersamp * thiswrite);
+ if (nbytes < nchannels * bytespersamp * thiswrite)
+ {
+ post("%s: %s", filesym->s_name, strerror(errno));
+ if (nbytes > 0)
+ itemswritten += nbytes / (nchannels * bytespersamp);
+ break;
+ }
+ itemswritten += thiswrite;
+ onset += thiswrite;
+ }
+ if (fd >= 0)
+ {
+ soundfile_finishwrite(obj, filesym->s_name, fd,
+ filetype, nframes, itemswritten, nchannels * bytespersamp, swap);
+ close (fd);
+ }
+ return ((float)itemswritten);
+usage:
+ pd_error(obj, "usage: write [flags] filename tablename...");
+ post("flags: -skip <n> -nframes <n> -bytes <n> -wave -aiff -nextstep ...");
+ post("-big -little -normalize -amp <n>");
+ post("(defaults to a 16-bit wave file).");
+fail:
+ if (fd >= 0)
+ close (fd);
+ return (0);
+}
+
+static void soundfiler2_write(t_soundfiler2 *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ long bozo = soundfiler2_dowrite(x, x->x_canvas,
+ argc, argv);
+ outlet_float(x->x_obj.ob_outlet, (float)bozo);
+}
+
+void soundfiler2_setup(void)
+{
+ soundfiler2_class = class_new(gensym("soundfiler2"), (t_newmethod)soundfiler2_new,
+ 0, sizeof(t_soundfiler2), 0, 0);
+ class_addmethod(soundfiler2_class, (t_method)soundfiler2_read, gensym("read"),
+ A_GIMME, 0);
+ class_addmethod(soundfiler2_class, (t_method)soundfiler2_write,
+ gensym("write"), A_GIMME, 0);
+}
+
+/************************* readsf object ******************************/
+
+/* READSF uses the Posix threads package; for the moment we're Linux
+only although this should be portable to the other platforms.
+
+Each instance of readsf~ owns a "child" thread for doing the UNIX (NT?) file
+reading. The parent thread signals the child each time:
+ (1) a file wants opening or closing;
+ (2) we've eaten another 1/16 of the shared buffer (so that the
+ child thread should check if it's time to read some more.)
+The child signals the parent whenever a read has completed. Signalling
+is done by setting "conditions" and putting data in mutex-controlled common
+areas.
+*/
+
+#ifdef __linux__
+
+#define MAXBYTESPERSAMPLE 4
+#define MAXVECSIZE 128
+
+#define READSIZE 65536
+#define WRITESIZE 65536
+#define DEFBUFPERCHAN 262144
+#define MINBUFSIZE (4 * READSIZE)
+#define MAXBUFSIZE 16777216 /* arbitrary; just don't want to hang malloc */
+
+#define REQUEST_NOTHING 0
+#define REQUEST_OPEN 1
+#define REQUEST_CLOSE 2
+#define REQUEST_QUIT 3
+#define REQUEST_BUSY 4
+
+#define STATE_IDLE 0
+#define STATE_STARTUP 1
+#define STATE_STREAM 2
+
+static t_class *readsfv_class;
+
+static t_sample *(tmpvec[MAXSFCHANS]);
+
+typedef struct _readsf
+{
+ t_object x_obj;
+ t_canvas *x_canvas;
+ t_clock *x_clock;
+ char *x_buf; /* soundfile buffer */
+ int x_bufsize; /* buffer size in bytes */
+ int x_noutlets; /* number of audio outlets */
+ t_sample *(x_outvec[MAXSFCHANS]); /* audio vectors */
+ int x_vecsize; /* vector size for transfers */
+ t_outlet *x_bangout; /* bang-on-done outlet */
+ int x_state; /* opened, running, or idle */
+ /* parameters to communicate with subthread */
+ int x_requestcode; /* pending request from parent to I/O thread */
+ char *x_filename; /* file to open (string is permanently allocated) */
+ int x_fileerror; /* slot for "errno" return */
+ int x_skipheaderbytes; /* size of header we'll skip */
+ int x_bytespersample; /* bytes per sample (2 or 3) */
+ int x_bigendian; /* true if file is big-endian */
+ int x_sfchannels; /* number of channels in soundfile */
+ long x_onsetframes; /* number of sample frames to skip */
+ long x_bytelimit; /* max number of data bytes to read */
+ int x_fd; /* filedesc */
+ int x_fifosize; /* buffer size appropriately rounded down */
+ int x_fifohead; /* index of next byte to get from file */
+ int x_fifotail; /* index of next byte the ugen will read */
+ int x_eof; /* true if fifohead has stopped changing */
+ int x_sigcountdown; /* counter for signalling child for more data */
+ int x_sigperiod; /* number of ticks per signal */
+ int x_filetype; /* writesf~ only; type of file to create */
+ int x_itemswritten; /* writesf~ only; items writen */
+ int x_swap; /* writesf~ only; true if byte swapping */
+ float x_f; /* writesf~ only; scalar for signal inlet */
+ /*----HACK------*/
+ float x_speed; /*speed of reading*/
+ float x_frac; /*fractionnal part of sample to play next buffer*/
+
+ pthread_mutex_t x_mutex;
+ pthread_cond_t x_requestcondition;
+ pthread_cond_t x_answercondition;
+ pthread_t x_childthread;
+} t_readsf;
+
+
+/************** the child thread which performs file I/O ***********/
+
+#if 0
+static void pute(char *s) /* debug routine */
+{
+ write(2, s, strlen(s));
+}
+#else
+#define pute(x)
+#endif
+
+#if 1
+#define sfread_cond_wait pthread_cond_wait
+#define sfread_cond_signal pthread_cond_signal
+#else
+#include <sys/time.h> /* debugging version... */
+#include <sys/types.h>
+static void readsf_fakewait(pthread_mutex_t *b)
+{
+ struct timeval timout;
+ timout.tv_sec = 0;
+ timout.tv_usec = 1000000;
+ pthread_mutex_unlock(b);
+ select(0, 0, 0, 0, &timout);
+ pthread_mutex_lock(b);
+}
+
+static void readsf_banana( void)
+{
+ struct timeval timout;
+ timout.tv_sec = 0;
+ timout.tv_usec = 200000;
+ pute("banana1\n");
+ select(0, 0, 0, 0, &timout);
+ pute("banana2\n");
+}
+
+
+#define sfread_cond_wait(a,b) readsf_fakewait(b)
+#define sfread_cond_signal(a)
+#endif
+
+static void *readsf_child_main(void *zz)
+{
+ t_readsf *x = zz;
+ pute("1\n");
+ pthread_mutex_lock(&x->x_mutex);
+ while (1)
+ {
+ int fd, fifohead;
+ char *buf;
+ pute("0\n");
+ if (x->x_requestcode == REQUEST_NOTHING)
+ {
+ pute("wait 2\n");
+ sfread_cond_signal(&x->x_answercondition);
+ sfread_cond_wait(&x->x_requestcondition, &x->x_mutex);
+ pute("3\n");
+ }
+ else if (x->x_requestcode == REQUEST_OPEN)
+ {
+ char boo[80];
+ int sysrtn, wantbytes;
+
+ /* copy file stuff out of the data structure so we can
+ relinquish the mutex while we're in open_soundfile(). */
+ long onsetframes = x->x_onsetframes;
+ long bytelimit = 0x7fffffff;
+ int skipheaderbytes = x->x_skipheaderbytes;
+ int bytespersample = x->x_bytespersample;
+ int sfchannels = x->x_sfchannels;
+ int bigendian = x->x_bigendian;
+ char *filename = x->x_filename;
+ char *dirname = canvas_getdir(x->x_canvas)->s_name;
+ /* alter the request code so that an ensuing "open" will get
+ noticed. */
+ pute("4\n");
+ x->x_requestcode = REQUEST_BUSY;
+ x->x_fileerror = 0;
+
+ /* if there's already a file open, close it */
+ if (x->x_fd >= 0)
+ {
+ fd = x->x_fd;
+ pthread_mutex_unlock(&x->x_mutex);
+ close (fd);
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_fd = -1;
+ if (x->x_requestcode != REQUEST_BUSY)
+ goto lost;
+ }
+ /* open the soundfile with the mutex unlocked */
+ pthread_mutex_unlock(&x->x_mutex);
+ fd = open_soundfile(dirname, filename,
+ skipheaderbytes, &bytespersample, &bigendian,
+ &sfchannels, &bytelimit, onsetframes);
+ pthread_mutex_lock(&x->x_mutex);
+
+ pute("5\n");
+ /* copy back into the instance structure. */
+ x->x_bytespersample = bytespersample;
+ x->x_sfchannels = sfchannels;
+ x->x_bigendian = bigendian;
+ x->x_fd = fd;
+ x->x_bytelimit = bytelimit;
+ if (fd < 0)
+ {
+ x->x_fileerror = errno;
+ x->x_eof = 1;
+ pute("open failed\n");
+ pute(filename);
+ pute(dirname);
+ goto lost;
+ }
+ /* check if another request has been made; if so, field it */
+ if (x->x_requestcode != REQUEST_BUSY)
+ goto lost;
+ pute("6\n");
+ x->x_fifohead = 0;
+ /* set fifosize from bufsize. fifosize must be a
+ multiple of the number of bytes eaten for each DSP
+ tick. We pessimistically assume MAXVECSIZE samples
+ per tick since that could change. There could be a
+ problem here if the vector size increases while a
+ soundfile is being played... */
+ x->x_fifosize = x->x_bufsize - (x->x_bufsize %
+ (x->x_bytespersample * x->x_sfchannels * MAXVECSIZE));
+ /* arrange for the "request" condition to be signalled 16
+ times per buffer */
+ sprintf(boo, "fifosize %d\n",
+ x->x_fifosize);
+ pute(boo);
+ x->x_sigcountdown = x->x_sigperiod =
+ (x->x_fifosize /
+ (16 * x->x_bytespersample * x->x_sfchannels *
+ x->x_vecsize));
+ /* in a loop, wait for the fifo to get hungry and feed it */
+
+ while (x->x_requestcode == REQUEST_BUSY)
+ {
+ int fifosize = x->x_fifosize;
+ pute("77\n");
+ if (x->x_eof)
+ break;
+ if (x->x_fifohead >= x->x_fifotail)
+ {
+ /* if the head is >= the tail, we can immediately read
+ to the end of the fifo. Unless, that is, we would
+ read all the way to the end of the buffer and the
+ "tail" is zero; this would fill the buffer completely
+ which isn't allowed because you can't tell a completely
+ full buffer from an empty one. */
+ if (x->x_fifotail || (fifosize - x->x_fifohead > READSIZE))
+ {
+ wantbytes = fifosize - x->x_fifohead;
+ if (wantbytes > READSIZE)
+ wantbytes = READSIZE;
+ if (wantbytes > x->x_bytelimit)
+ wantbytes = x->x_bytelimit;
+ sprintf(boo, "head %d, tail %d, size %d\n",
+ x->x_fifohead, x->x_fifotail, wantbytes);
+ pute(boo);
+ }
+ else
+ {
+ pute("wait 7a ...\n");
+ sfread_cond_signal(&x->x_answercondition);
+ pute("signalled\n");
+ sfread_cond_wait(&x->x_requestcondition,
+ &x->x_mutex);
+ pute("7a done\n");
+ continue;
+ }
+ }
+ else
+ {
+ /* otherwise check if there are at least READSIZE
+ bytes to read. If not, wait and loop back. */
+ wantbytes = x->x_fifotail - x->x_fifohead - 1;
+ if (wantbytes < READSIZE)
+ {
+ pute("wait 7...\n");
+ sfread_cond_signal(&x->x_answercondition);
+ sfread_cond_wait(&x->x_requestcondition,
+ &x->x_mutex);
+ pute("7 done\n");
+ continue;
+ }
+ else wantbytes = READSIZE;
+ }
+ pute("8\n");
+ fd = x->x_fd;
+ buf = x->x_buf;
+ fifohead = x->x_fifohead;
+ pthread_mutex_unlock(&x->x_mutex);
+ sysrtn = read(fd, buf + fifohead, wantbytes);
+ pthread_mutex_lock(&x->x_mutex);
+ if (x->x_requestcode != REQUEST_BUSY)
+ break;
+ if (sysrtn < 0)
+ {
+ pute("fileerror\n");
+ x->x_fileerror = errno;
+ break;
+ }
+ else if (sysrtn == 0)
+ {
+ x->x_eof = 1;
+ break;
+ }
+ else
+ {
+ x->x_fifohead += sysrtn;
+ x->x_bytelimit -= sysrtn;
+ if (x->x_bytelimit <= 0)
+ {
+ x->x_eof = 1;
+ break;
+ }
+ if (x->x_fifohead == fifosize)
+ x->x_fifohead = 0;
+ }
+ sprintf(boo, "after: head %d, tail %d\n",
+ x->x_fifohead, x->x_fifotail);
+ pute(boo);
+ /* signal parent in case it's waiting for data */
+ sfread_cond_signal(&x->x_answercondition);
+ }
+ lost:
+
+ if (x->x_requestcode == REQUEST_BUSY)
+ x->x_requestcode = REQUEST_NOTHING;
+ /* fell out of read loop: close file if necessary,
+ set EOF and signal once more */
+ if (x->x_fd >= 0)
+ {
+ fd = x->x_fd;
+ pthread_mutex_unlock(&x->x_mutex);
+ close (fd);
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_fd = -1;
+ }
+ sfread_cond_signal(&x->x_answercondition);
+
+ }
+ else if (x->x_requestcode == REQUEST_CLOSE)
+ {
+ if (x->x_fd >= 0)
+ {
+ fd = x->x_fd;
+ pthread_mutex_unlock(&x->x_mutex);
+ close (fd);
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_fd = -1;
+ }
+ if (x->x_requestcode == REQUEST_CLOSE)
+ x->x_requestcode = REQUEST_NOTHING;
+ sfread_cond_signal(&x->x_answercondition);
+ }
+ else if (x->x_requestcode == REQUEST_QUIT)
+ {
+ if (x->x_fd >= 0)
+ {
+ fd = x->x_fd;
+ pthread_mutex_unlock(&x->x_mutex);
+ close (fd);
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_fd = -1;
+ }
+ x->x_requestcode = REQUEST_NOTHING;
+ sfread_cond_signal(&x->x_answercondition);
+ break;
+ }
+ else
+ {
+ pute("13\n");
+ }
+ }
+ pute("thread exit\n");
+ pthread_mutex_unlock(&x->x_mutex);
+ return (0);
+}
+
+/******** the object proper runs in the calling (parent) thread ****/
+
+static void readsf_tick(t_readsf *x);
+
+static void *readsf_new(t_floatarg fnchannels, t_floatarg fbufsize)
+{
+ t_readsf *x;
+ int nchannels = fnchannels, bufsize = fbufsize, i;
+ char *buf;
+
+ if (nchannels < 1)
+ nchannels = 1;
+ else if (nchannels > MAXSFCHANS)
+ nchannels = MAXSFCHANS;
+ if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels;
+ else if (bufsize < MINBUFSIZE)
+ bufsize = MINBUFSIZE;
+ else if (bufsize > MAXBUFSIZE)
+ bufsize = MAXBUFSIZE;
+ buf = getbytes(bufsize);
+ if (!buf) return (0);
+
+ x = (t_readsf *)pd_new(readsfv_class);
+
+ for (i = 0; i < nchannels; i++)
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_noutlets = nchannels;
+ x->x_bangout = outlet_new(&x->x_obj, &s_bang);
+ pthread_mutex_init(&x->x_mutex, 0);
+ pthread_cond_init(&x->x_requestcondition, 0);
+ pthread_cond_init(&x->x_answercondition, 0);
+ x->x_vecsize = MAXVECSIZE;
+ x->x_state = STATE_IDLE;
+ x->x_clock = clock_new(x, (t_method)readsf_tick);
+ x->x_canvas = canvas_getcurrent();
+ x->x_bytespersample = 2;
+ x->x_sfchannels = 1;
+ x->x_fd = -1;
+ x->x_buf = buf;
+ x->x_bufsize = bufsize;
+ x->x_fifosize = x->x_fifohead = x->x_fifotail = x->x_requestcode = 0;
+ pthread_create(&x->x_childthread, 0, readsf_child_main, x);
+ return (x);
+}
+
+static void readsf_tick(t_readsf *x)
+{
+ outlet_bang(x->x_bangout);
+}
+
+static t_int *readsf_perform(t_int *w)
+{
+ t_readsf *x = (t_readsf *)(w[1]);
+ int vecsize = x->x_vecsize, noutlets = x->x_noutlets, i, j,
+ bytespersample = x->x_bytespersample,
+ bigendian = x->x_bigendian,wantsamples;
+ float *fp,tmp,speed=x->x_speed;
+ if (x->x_state == STATE_STREAM)
+ {
+ int wantbytes, nchannels, sfchannels = x->x_sfchannels;
+ pthread_mutex_lock(&x->x_mutex);
+ tmp=vecsize *speed+x->x_frac;
+ wantsamples=(int)tmp;
+ x->x_frac=tmp-wantsamples;
+
+ if(!speed) goto idle;
+
+ wantbytes = sfchannels * wantsamples * bytespersample;
+
+ while (
+ !x->x_eof && x->x_fifohead >= x->x_fifotail &&
+ x->x_fifohead < x->x_fifotail + wantbytes-1)
+ {
+ pute("wait...\n");
+ sfread_cond_signal(&x->x_requestcondition);
+ sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
+ pute("done\n");
+ }
+ if (x->x_eof && x->x_fifohead >= x->x_fifotail &&
+ x->x_fifohead < x->x_fifotail + wantbytes-1)
+ {
+ if (x->x_fileerror)
+ {
+ pd_error(x, "dsp: %s: %s", x->x_filename,
+ (x->x_fileerror == EIO ?
+ "unknown or bad header format" :
+ strerror(x->x_fileerror)));
+ }
+ clock_delay(x->x_clock, 0);
+ x->x_state = STATE_IDLE;
+ sfread_cond_signal(&x->x_requestcondition);
+ pthread_mutex_unlock(&x->x_mutex);
+ goto idle;
+ }
+
+ if(speed==1)
+ soundfile_xferin(sfchannels, noutlets, x->x_outvec, 0,
+ (unsigned char *)(x->x_buf + x->x_fifotail), vecsize,
+ bytespersample, bigendian);
+ else {
+ soundfile_xferin(sfchannels, noutlets, tmpvec, 0,
+ (unsigned char *)(x->x_buf + x->x_fifotail), wantsamples,
+ bytespersample, bigendian);
+ interpolate(noutlets,tmpvec,wantsamples,x->x_outvec,vecsize);
+ }
+
+ x->x_fifotail += wantbytes;
+ if (x->x_fifotail >= x->x_fifosize)
+ x->x_fifotail = 0;
+ if ((--x->x_sigcountdown) <= 0)
+ {
+ sfread_cond_signal(&x->x_requestcondition);
+ x->x_sigcountdown = x->x_sigperiod;
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+ }
+ else
+ {
+ idle:
+ for (i = 0; i < noutlets; i++)
+ for (j = vecsize, fp = x->x_outvec[i]; j--; )
+ *fp++ = 0;
+ }
+ return (w+2);
+}
+
+static void readsf_start(t_readsf *x)
+{
+ /* start making output. If we're in the "startup" state change
+ to the "running" state. */
+ if (x->x_state == STATE_STARTUP)
+ x->x_state = STATE_STREAM;
+ else pd_error(x, "readsf: start requested with no prior 'open'");
+}
+
+static void readsf_stop(t_readsf *x)
+{
+ /* LATER rethink whether you need the mutex just to set a variable? */
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_state = STATE_IDLE;
+ x->x_requestcode = REQUEST_CLOSE;
+ sfread_cond_signal(&x->x_requestcondition);
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+static void readsf_float(t_readsf *x, t_floatarg f)
+{
+ if (f != 0)
+ readsf_start(x);
+ else readsf_stop(x);
+}
+
+static void readsf_speed(t_readsf *x, t_floatarg f)
+{
+ if((f>=0)&&(f<=8))
+ x->x_speed=f;
+}
+
+ /* open method. Called as:
+ open filename [skipframes headersize channels bytespersamp endianness]
+ (if headersize is zero, header is taken to be automatically
+ detected; thus, use the special "-1" to mean a truly headerless file.)
+ */
+
+static void readsf_open(t_readsf *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_symbol *filesym = atom_getsymbolarg(0, argc, argv);
+ t_float onsetframes = atom_getfloatarg(1, argc, argv);
+ t_float headerbytes = atom_getfloatarg(2, argc, argv);
+ t_float channels = atom_getfloatarg(3, argc, argv);
+ t_float bytespersamp = atom_getfloatarg(4, argc, argv);
+ t_symbol *endian = atom_getsymbolarg(5, argc, argv);
+ if (!*filesym->s_name)
+ return;
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_requestcode = REQUEST_OPEN;
+ x->x_filename = filesym->s_name;
+ x->x_fifotail = 0;
+ x->x_fifohead = 0;
+ if (*endian->s_name == 'b')
+ x->x_bigendian = 1;
+ else if (*endian->s_name == 'l')
+ x->x_bigendian = 0;
+ else if (*endian->s_name)
+ pd_error(x, "endianness neither 'b' nor 'l'");
+ else x->x_bigendian = garray_ambigendian();
+ x->x_onsetframes = (onsetframes > 0 ? onsetframes : 0);
+ x->x_skipheaderbytes = (headerbytes > 0 ? headerbytes :
+ (headerbytes == 0 ? -1 : 0));
+ x->x_sfchannels = (channels >= 1 ? channels : 1);
+ x->x_bytespersample = (bytespersamp > 2 ? bytespersamp : 2);
+ x->x_eof = 0;
+ x->x_fileerror = 0;
+ x->x_state = STATE_STARTUP;
+ x->x_speed=1;
+ x->x_frac=0;
+ sfread_cond_signal(&x->x_requestcondition);
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+static void readsf_dsp(t_readsf *x, t_signal **sp)
+{
+ int i, noutlets = x->x_noutlets;
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_vecsize = sp[0]->s_n;
+
+ x->x_sigperiod = (x->x_fifosize /
+ (x->x_bytespersample * x->x_sfchannels * x->x_vecsize));
+ for (i = 0; i < noutlets; i++)
+ x->x_outvec[i] = sp[i]->s_vec;
+ pthread_mutex_unlock(&x->x_mutex);
+ dsp_add(readsf_perform, 1, x);
+}
+
+static void readsf_print(t_readsf *x)
+{
+ post("state %d", x->x_state);
+ post("fifo head %d", x->x_fifohead);
+ post("fifo tail %d", x->x_fifotail);
+ post("fifo size %d", x->x_fifosize);
+ post("fd %d", x->x_fd);
+ post("eof %d", x->x_eof);
+}
+
+static void readsf_free(t_readsf *x)
+{
+ /* request QUIT and wait for acknowledge */
+ void *threadrtn;
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_requestcode = REQUEST_QUIT;
+ post("stopping readsf thread...");
+ sfread_cond_signal(&x->x_requestcondition);
+ while (x->x_requestcode != REQUEST_NOTHING)
+ {
+ post("signalling...");
+ sfread_cond_signal(&x->x_requestcondition);
+ sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+ if (pthread_join(x->x_childthread, &threadrtn))
+ error("readsf_free: join failed");
+ post("... done.");
+
+ pthread_cond_destroy(&x->x_requestcondition);
+ pthread_cond_destroy(&x->x_answercondition);
+ pthread_mutex_destroy(&x->x_mutex);
+ freebytes(x->x_buf, x->x_bufsize);
+ clock_free(x->x_clock);
+}
+
+#endif /* __linux__ */
+
+void readsfv_tilde_setup(void)
+{
+#ifdef __linux__
+ int i;
+
+ readsfv_class = class_new(gensym("readsfv~"), (t_newmethod)readsf_new,
+ (t_method)readsf_free, sizeof(t_readsf), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+
+ class_addfloat(readsfv_class, (t_method)readsf_float);
+ class_addmethod(readsfv_class, (t_method)readsf_speed, gensym("speed"), A_FLOAT,0);
+ class_addmethod(readsfv_class, (t_method)readsf_start, gensym("start"), 0);
+ class_addmethod(readsfv_class, (t_method)readsf_stop, gensym("stop"), 0);
+ class_addmethod(readsfv_class, (t_method)readsf_dsp, gensym("dsp"), 0);
+ class_addmethod(readsfv_class, (t_method)readsf_open, gensym("open"),
+ A_GIMME, 0);
+ class_addmethod(readsfv_class, (t_method)readsf_print, gensym("print"), 0);
+
+ for(i=0;i<MAXSFCHANS;i++)
+ tmpvec[i]=getbytes(sizeof(t_sample)*8*1024);
+#endif /* __linux__ */
+}
+
+
+
+
diff --git a/relativepath.c b/relativepath.c
new file mode 100644
index 0000000..f599222
--- /dev/null
+++ b/relativepath.c
@@ -0,0 +1,146 @@
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+/*#include <m_imp.h>*/
+#include "m_pd.h"
+#include "g_canvas.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <libgen.h>
+#include <string.h>
+
+extern t_canvas *canvas_list; /* list of all root canvases */
+extern int canvas_getdollarzero( void);
+
+struct _canvasenvironment
+{
+ t_symbol *ce_dir; /* directory patch lives in */
+ int ce_argc; /* number of "$" arguments */
+ t_atom *ce_argv; /* array of "$" arguments */
+ int ce_dollarzero; /* value of "$0" */
+};
+
+typedef struct _relativepath
+{
+ t_object x_obj;
+ t_canvas *x_canvas;
+ int x_dolzero;
+ int x_realized;
+}t_relativepath;
+
+t_class *relativepath_class;
+
+void relativepath_setup(void);
+
+static t_glist *getcanvas(t_glist *can,int d0)
+{
+ t_canvas *retcan=0;
+ t_gobj *ob;
+
+ if((can->gl_env)&&(can->gl_env->ce_dollarzero==d0)){
+ return can;
+ }
+
+ ob=can->gl_list;
+ while(ob&&(retcan==0)) {
+ if (pd_class(&ob->g_pd) == canvas_class)
+ retcan=getcanvas((t_glist *)ob,d0);
+ ob=ob->g_next;
+ }
+
+ if((!retcan)&&(can->gl_next)) retcan=getcanvas((t_glist *)can->gl_next,d0);
+ return retcan;
+}
+
+static void relativepath_symbol(t_relativepath *x,t_symbol *sym)
+{
+ t_canvas *can=0;
+ t_symbol *s=sym;
+ char *instr=sym->s_name,*outstr=instr,
+ *candir,
+ canname[MAXPDSTRING],totaldir[MAXPDSTRING],
+ *cnamedir;
+ unsigned int n,i=0;
+
+ if(!x->x_realized) can=(t_canvas*)getcanvas(canvas_list,x->x_dolzero);
+ if(can) {
+ x->x_canvas = can;
+ x->x_realized = 1;
+ //post("found $0 canvas : %x %d ",x->x_canvas, x->x_canvas->gl_env->ce_dollarzero );
+ }
+
+ if(!instr) return;
+
+ candir=canvas_getdir(x->x_canvas)->s_name;
+ if(!candir) candir="";
+
+ strcpy(canname,x->x_canvas->gl_name->s_name);
+ //post("canname=%s",canname);
+ cnamedir=dirname(canname);
+
+ if (strcmp(cnamedir,".")) {
+ sprintf(totaldir,"%s/%s",candir,cnamedir);
+ }
+ else
+ strcpy(totaldir,candir);
+
+ //post("dir=%s",totaldir);
+
+ n=strlen(totaldir);
+ if(strlen(instr)<=n) goto end;
+
+ while(i<n) {
+ if(instr[i]!=totaldir[i]) goto end;
+ i++;
+ }
+
+ if(instr[n]=='/'){
+ outstr=strdup(instr+n+1);
+ s=gensym(outstr);
+ }
+
+end:
+ outlet_symbol(x->x_obj.ob_outlet,s);
+}
+
+
+static void *relativepath_new(t_float dolzero)
+{
+ t_relativepath *x = (t_relativepath *)pd_new(relativepath_class);
+ int d0;
+
+ outlet_new(&x->x_obj, 0);
+ x->x_canvas = canvas_getcurrent();
+ x->x_dolzero = dolzero;
+ x->x_realized=dolzero?0:1;
+
+ return (void *)x;
+}
+
+void relativepath_setup(void)
+{
+ relativepath_class = class_new(gensym("relativepath"),(t_newmethod)relativepath_new,
+ 0, sizeof(t_relativepath), 0,A_DEFFLOAT,0);
+
+ class_addsymbol(relativepath_class, relativepath_symbol);
+}
+
diff --git a/s2f.c b/s2f.c
new file mode 100644
index 0000000..3e36b22
--- /dev/null
+++ b/s2f.c
@@ -0,0 +1,53 @@
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+#include "m_pd.h"
+#include <stdlib.h>
+
+typedef struct _s2f
+{
+ t_object x_obj;
+}t_s2f;
+
+t_class *s2f_class;
+
+void s2f_setup(void);
+
+static void s2f_symbol(t_s2f *x,t_symbol *sym)
+{
+ if(!sym->s_name) return;
+
+ outlet_float(x->x_obj.ob_outlet,(float)strtod(sym->s_name,0));
+}
+
+static void *s2f_new(void)
+{
+ t_s2f *x = (t_s2f *)pd_new(s2f_class);
+ outlet_new(&x->x_obj, &s_float);
+ return (void *)x;
+}
+
+void s2f_setup(void)
+{
+ s2f_class = class_new(gensym("s2f"),(t_newmethod)s2f_new,
+ 0, sizeof(t_s2f), 0, 0);
+
+ class_addsymbol(s2f_class, s2f_symbol);
+}
+
diff --git a/sarray.c b/sarray.c
new file mode 100644
index 0000000..d44f7ce
--- /dev/null
+++ b/sarray.c
@@ -0,0 +1,264 @@
+/*
+Copyright (C) 2003 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+/* a shared symbol array, ala "value" .*/
+
+#include "m_pd.h"
+#include <stdlib.h>
+#include <string.h>
+
+static t_class *sarray_class, *scommon_class;
+static t_symbol *s__;
+
+typedef struct scommon
+{
+ t_pd c_pd;
+ t_symbol *c_sym;
+ int c_refcount;
+ int c_len;
+ t_symbol **c_array;
+} t_scommon;
+
+typedef struct _sarray
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+ t_scommon *x_c;
+ //t_outlet *x_symout;
+ //t_outlet *x_lenout;
+} t_sarray;
+
+/*static int scommon_find(t_scommon *x, t_symbol *s)
+{
+ t_sitem *si=x->first;
+ t_int i=1;
+
+ while(si) {
+ if(!strcmp(si->s->s_name,s->s_name)) return i;
+ si=si->next;
+ i++;
+ }
+ return 0;
+}*/
+
+static t_symbol *scommon_get(t_scommon *x, t_float f)
+{
+ int i=(int)f;
+
+ if(i<0) i=0;
+ if(i>=x->c_len) i=x->c_len-1;
+ return x->c_array[i];
+}
+
+static void scommon_set(t_scommon *x, t_float f, t_symbol *s)
+{
+ int i=(int)f;
+
+ if((i<0)||(i>=x->c_len)) return;
+ x->c_array[i]=s;
+ //x->c_array[i]=gensym(strdup(s->s_name));
+ //x->c_array[i]=gensym("ok");
+}
+
+static void scommon_setlen(t_scommon *x, t_float flen)
+{
+ int i,oldlen=x->c_len,len=flen;
+
+ if(len<1) len=1;
+ x->c_len=len;
+
+ x->c_array=realloc(x->c_array,sizeof(t_symbol *)*len);
+
+ if(len>oldlen) for(i=oldlen;i<len;i++) x->c_array[i]=&s_;
+}
+
+static void scommon_reset(t_scommon *x)
+{
+ int i;
+
+ for(i=0;i<x->c_len;i++) x->c_array[i]=&s_;
+}
+
+static t_atom *scommon_dump(t_scommon *x,t_symbol *s)
+{
+ int i;
+ t_atom *atombuf;
+
+ atombuf = (t_atom *)getbytes(sizeof(t_atom)*x->c_len);
+
+ for(i=0;i<x->c_len;i++) {
+ if(x->c_array[i]==&s_) SETSYMBOL(&atombuf[i],s);
+ else SETSYMBOL(&atombuf[i],x->c_array[i]);
+ }
+
+ return atombuf;
+}
+
+static void scommon_ff(t_scommon *x)
+{
+ //scommon_reset(x);
+ pd_unbind((t_pd*)x, x->c_sym);
+}
+
+static void *scommon_new(t_symbol *s)
+{
+ t_scommon *x = (t_scommon *)pd_new(scommon_class);
+
+ x->c_refcount = 0;
+ x->c_sym=s;
+ pd_bind((t_pd*)x, s);
+
+ x->c_len=1;
+ x->c_array=malloc(sizeof(t_symbol *)*1);
+ scommon_reset(x);
+
+ return (x);
+}
+
+
+ /* get a pointer to a named symbol list (a "scommon" object),
+ which is created if necessary. */
+t_scommon *sarray_scget(t_symbol *s)
+{
+ t_scommon *c = (t_scommon *)pd_findbyclass(s, scommon_class);
+
+ if (!c) c = (t_scommon *)scommon_new(s);
+ c->c_refcount++;
+ return (c);
+}
+
+ /* release a variable. This only frees the "scommon" resource when the
+ last interested party releases it. */
+void sarray_release(t_scommon *c)
+{
+ if (!--c->c_refcount) scommon_ff(c);
+}
+
+
+static void *sarray_new(t_symbol *s,t_float len)
+{
+ t_sarray *x = (t_sarray *)pd_new(sarray_class);
+
+ x->x_sym = s;
+ x->x_c = sarray_scget(s);
+ if(len) scommon_setlen(x->x_c,len);
+
+ outlet_new(&x->x_obj, &s_anything);
+ //x->x_symout=outlet_new(&x->x_obj, &s_anything);
+ //x->x_lenout=outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+static void sarray_ff(t_sarray *x)
+{
+ sarray_release(x->x_c);
+}
+
+static void sarray_print(t_sarray *x)
+{
+ int i;
+
+ for(i=0;i<x->x_c->c_len;i++){
+ post("item %d: %s",i,x->x_c->c_array[i]->s_name);
+ }
+}
+
+static void sarray_reset(t_sarray *x)
+{
+ scommon_reset(x->x_c);
+}
+
+static void sarray_set(t_sarray *x, t_symbol *sfoo,int argc, t_atom *argv)
+{
+ int i,j=0;
+ t_symbol *snull=&s_,*s;
+
+ /*if((argc<2)||(argv[0].a_type!=A_FLOAT))
+ {
+ error("Bad arguments for message 'set' to object 'sarray'");
+ return ;
+ }*/
+ if(argv[0].a_type==A_SYMBOL) {
+ snull=atom_getsymbol(&argv[0]);
+ j=1;
+ }
+
+ if(argv[j].a_type!=A_FLOAT){
+ error("Bad arguments for message 'set' to object 'sarray'");
+ return ;
+ }
+
+ i=atom_getfloat(&argv[j++]);
+
+ while((j<argc)&&(argv[j].a_type==A_SYMBOL)){
+ s=atom_getsymbol(&argv[j++]);
+ if(s==snull) s=&s_;
+ scommon_set(x->x_c,i++,s);
+ }
+}
+
+static void sarray_get(t_sarray *x,t_float i)
+{
+ t_symbol *s=scommon_get(x->x_c,i);
+
+ if(s==&s_) outlet_bang(x->x_obj.ob_outlet);
+ else outlet_symbol(x->x_obj.ob_outlet,scommon_get(x->x_c,i));
+}
+
+static void sarray_dump(t_sarray *x,t_symbol *s)
+{
+ t_atom *l=scommon_dump(x->x_c,s);
+
+ outlet_list(x->x_obj.ob_outlet, &s_list, x->x_c->c_len, l);
+ free(l);
+}
+
+static void sarray_setarray(t_sarray *x,t_symbol *s)
+{
+ sarray_release(x->x_c);
+ x->x_c = sarray_scget(s);
+ x->x_sym = s;
+}
+
+static void sarray_setlen(t_sarray *x,t_float len)
+{
+ scommon_setlen(x->x_c,len);
+}
+
+
+void sarray_setup(void)
+{
+ s__=gensym("_");
+ sarray_class = class_new(gensym("sarray"), (t_newmethod)sarray_new,
+ (t_method)sarray_ff,
+ sizeof(t_sarray), 0, A_DEFSYM, A_DEFFLOAT,0);
+
+ //class_addbang(sarray_class, sarray_bang);
+ //class_addfloat(sarray_class, sarray_float);
+ class_addmethod(sarray_class,(t_method)sarray_set, gensym("set"),A_GIMME,0);
+ class_addmethod(sarray_class,(t_method)sarray_get, gensym("get"),A_FLOAT,0);
+ class_addmethod(sarray_class,(t_method)sarray_reset, gensym("reset"),0);
+ class_addmethod(sarray_class,(t_method)sarray_print, gensym("print"),0);
+ class_addmethod(sarray_class,(t_method)sarray_setlen, gensym("setlen"),A_FLOAT,0);
+ class_addmethod(sarray_class,(t_method)sarray_dump, gensym("dump"),A_DEFSYM,0);
+ class_addmethod(sarray_class,(t_method)sarray_setarray, gensym("setarray"),A_SYMBOL,0);
+ scommon_class = class_new(gensym("sarray"), 0, 0,
+ sizeof(t_scommon), CLASS_PD, 0);
+}
+
diff --git a/sfread2~.c b/sfread2~.c
new file mode 100644
index 0000000..aceb39e
--- /dev/null
+++ b/sfread2~.c
@@ -0,0 +1,410 @@
+#include <m_pd.h>
+//#include <m_imp.h>
+#include "g_canvas.h"
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifndef NT
+#include <unistd.h>
+#include <sys/mman.h>
+#else
+#include <io.h>
+#endif
+
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/* ------------------------ sfread~ ----------------------------- */
+
+#ifdef NT
+#define BINREADMODE "rb"
+#else
+#define BINREADMODE "r"
+#endif
+
+static t_class *sfread_class;
+
+
+typedef struct _sfread
+{
+ t_object x_obj;
+ void* x_mapaddr;
+ int x_fd;
+
+ t_int x_play;
+ t_int x_outchannels;
+ t_int x_loop;
+ double x_index; //samples
+ t_float x_speed; //1=sample rate
+ t_int x_interp;
+
+ t_int x_size; // bytes
+ t_int x_fchannels; // file channels
+ t_int x_len; // samples
+ t_int x_skip; //bytes
+ t_clock *x_clock;
+
+
+ t_glist * x_glist;
+ t_outlet *x_stateout;
+ t_outlet *x_sizeout;
+} t_sfread;
+
+#define MAX_CHANS 4
+
+
+
+//1 -> 2
+
+//1 -> 4
+
+//2 -> 4
+
+
+static t_int *sfread_perform(t_int *w)
+{
+ t_sfread* x = (t_sfread*)(w[1]);
+ short *fp, *buf = x->x_mapaddr+x->x_skip;
+/* t_float *in = (t_float *)(w[2]); will we need this (indexing) ?*/
+ int c = x->x_outchannels;
+ int fc = x->x_fchannels,fc2=2*fc;
+ double findex = x->x_index;
+ t_float speed = x->x_speed;
+ float frac, a, b, cc, d, cminusb;
+ int i,n,index,rindex;
+ int end = x->x_len -3;/* -3 is for safe interpolation*/
+ t_float* out[MAX_CHANS];
+ t_int in_off[MAX_CHANS];
+ t_int loground=(fc==1?0:fc==2?1:2);
+
+ if(!x->x_mapaddr) return(w+c+4);
+
+ for (i=0;i<c;i++){
+ out[i] = (t_float *)(w[3+i]);
+ in_off[i]=i%fc;
+ }
+ n = (int)(w[3+c]);
+
+ /* loop */
+
+ if (findex > end)
+ findex = end;
+
+ if (findex + n*speed > end) { // playing forward end
+ if (!x->x_loop) {
+ x->x_play=0;
+ findex = 0;
+ clock_delay(x->x_clock, 0);
+ }
+ }
+
+ if (findex + n*speed < 1) { // playing backwards end
+ if (!x->x_loop) {
+ x->x_play=0;
+ findex = end;
+ clock_delay(x->x_clock, 0);
+ }
+
+ }
+
+
+ if (x->x_play && x->x_mapaddr) {
+
+ if (speed != 1) { /* different speed */
+ if (x->x_interp) while (n--) {
+ index=findex;
+ rindex=index<<loground;
+ frac = findex - index;
+ for (i=0;i<c;i++) {
+ fp=buf + rindex +in_off[i];
+ a = fp[-fc];
+ b = fp[0];
+ cc = fp[fc];
+ d = fp[fc2];
+ cminusb = cc-b;
+ *out[i]++ = 3.052689e-05*
+ (b + frac * (cminusb - 0.5f * (frac-1.) *
+ ((a - d + 3.0f * cminusb) * frac + (b - a - cminusb))));
+ //*out[i]++ = *(buf+rindex+in_off[i])*3.052689e-05;
+ }
+ findex=findex+speed;
+ if (findex > end) {
+ if (x->x_loop) findex = 1;
+ else break;
+ }
+ if (findex < 1) {
+ if (x->x_loop) findex = end;
+ else break;
+ }
+ }
+ else while (n--) {
+ rindex=((int)findex)<<loground;
+ for (i=0;i<c;i++) {
+ *out[i]++ = *(buf+rindex+in_off[i])*3.052689e-05;
+ }
+ findex+=speed;
+ if (findex > end) {
+ if (x->x_loop) findex = 1;
+ else break;
+ }
+ if (findex < 1) {
+ if (x->x_loop) findex = end;
+ else break;
+ }
+ }
+ /* Fill with zero in case of end */
+ n++;
+ while (n--)
+ for (i=0;i<c;i++)
+ *out[i]++ = 0;
+ //offset = aoff;
+ }
+ else { /* speed == 1 */
+ int end2=end*fc;
+ rindex=((int)findex)<<loground;
+ while (n--) {
+ for (i=0;i<c;i++) {
+ *out[i]++ = *(buf+rindex+in_off[i])*3.052689e-05;
+ }
+ rindex+=fc;
+ if (rindex > end2) {
+ if (x->x_loop) rindex = 1;
+ else break;
+ }
+ }
+
+ /* Fill with zero in case of end */
+ n++;
+ while (n--)
+ for (i=0;i<c;i++)
+ *out[i]++ = 0.;
+ findex=rindex>>loground;
+ }
+
+ }
+ else {
+ while (n--) {
+ for (i=0;i<c;i++)
+ *out[i]++ = 0.;
+ }
+ }
+ x->x_index = findex;
+ return (w+c+4);
+}
+
+
+static void sfread_loop(t_sfread *x, t_floatarg f)
+{
+ x->x_loop = f;
+}
+
+static void sfread_interp(t_sfread *x, t_floatarg f)
+{
+ x->x_interp = (f!=0);
+}
+
+static void sfread_index(t_sfread *x, t_floatarg f)
+{
+ x->x_index = f;
+}
+
+
+static void sfread_size(t_sfread* x)
+{
+ outlet_float(x->x_sizeout,x->x_len);
+}
+
+static void sfread_state(t_sfread* x)
+{
+ outlet_float(x->x_stateout, x->x_play);
+}
+
+static void sfread_float(t_sfread *x, t_floatarg f)
+{
+ int t = f;
+ if (t && x->x_mapaddr) {
+ x->x_play=1;
+ }
+ else {
+ x->x_play=0;
+ }
+ sfread_state(x);
+}
+
+
+static void sfread_bang(t_sfread* x)
+{
+ x->x_index = x->x_speed>0?1:x->x_len-3;
+ sfread_float(x,1.0);
+}
+
+
+static void sfread_dsp(t_sfread *x, t_signal **sp)
+{
+/* post("sfread: dsp"); */
+ switch (x->x_outchannels) {
+ case 1:
+ dsp_add(sfread_perform, 4, x, sp[0]->s_vec,
+ sp[1]->s_vec, sp[0]->s_n);
+ break;
+ case 2:
+ dsp_add(sfread_perform, 5, x, sp[0]->s_vec,
+ sp[1]->s_vec,sp[2]->s_vec, sp[0]->s_n);
+ break;
+ case 4:
+ dsp_add(sfread_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;
+ }
+}
+
+
+extern int open_soundfile(const char *dirname, const char *filename, int headersize,
+ int *p_bytespersamp, int *p_bigendian, int *p_nchannels, long *p_bytelimit,
+ long skipframes); /* in pd/src/d_soundfile.c */
+
+
+static void sfread_open(t_sfread *x,t_symbol *filename)
+{
+ struct stat fstate;
+ char fname[MAXPDSTRING];
+ int bytespersamp=0,bigendian=0,channels=0;
+ long bytelimit= 0x7fffffff,skipframes = 0;
+
+ if (filename == &s_) {
+ post("sfread: open without filename");
+ return;
+ }
+
+ canvas_makefilename(glist_getcanvas(x->x_glist), filename->s_name,
+ fname, MAXPDSTRING);
+
+
+ /* close the old file */
+
+ if (x->x_mapaddr) munmap(x->x_mapaddr,x->x_size);
+ if (x->x_fd >= 0) close(x->x_fd);
+
+ /*if ((x->x_fd = open(fname,O_RDONLY)) < 0)*/
+ //post("fname: %s",fname);
+
+ if ((x->x_fd = open_soundfile("",fname, -1,&bytespersamp,&bigendian,
+ &channels, &bytelimit,0)) < 0)
+ {
+ error("can't open %s",fname);
+ x->x_play = 0;
+ x->x_mapaddr = NULL;
+ return;
+ }
+
+ if( ((x->x_fchannels!=1)&&(x->x_fchannels!=2)&&(x->x_fchannels!=4)) ||
+ (bytespersamp!=2) )
+ {
+ error("file %s error: not a 1 or 2 or 4 channels soundfile, or not a 16 bits soundfile",fname);
+ post("channels:%d bytes:%d ",x->x_fchannels,bytespersamp);
+ x->x_play = 0;
+ x->x_mapaddr = NULL;
+ return;
+ }
+
+ x->x_fchannels=channels;
+
+ /* get the size */
+
+ fstat(x->x_fd,&fstate);
+ x->x_size = (int)fstate.st_size;
+ x->x_skip=x->x_size-bytelimit;
+ x->x_len = (bytelimit)/(bytespersamp*x->x_fchannels);
+
+ //post("bytelimit=%d x->x_size-x->x_skip=%d x->x_size=%d x->x_skip=%d",bytelimit,x->x_size-x->x_skip,x->x_size,x->x_skip);
+
+ /* map the file into memory */
+
+ if (!(x->x_mapaddr = mmap(NULL,x->x_size,PROT_READ,MAP_PRIVATE,x->x_fd,0)))
+ {
+ error("can't mmap %s",fname);
+ return;
+ }
+ sfread_size(x);
+}
+
+static void *sfread_new(t_floatarg chan,t_floatarg interp)
+{
+ t_sfread *x = (t_sfread *)pd_new(sfread_class);
+ t_int c = chan;
+
+ x->x_glist = (t_glist*) canvas_getcurrent();
+
+ if (c<1 || c > MAX_CHANS) c = 1;
+ floatinlet_new(&x->x_obj, &x->x_speed);
+
+
+ x->x_fd = -1;
+ x->x_mapaddr = NULL;
+
+ x->x_size = 0;
+ x->x_len = 0;
+ x->x_loop = 0;
+ x->x_outchannels = c;
+ x->x_fchannels = 1;
+ x->x_mapaddr=NULL;
+ x->x_index = 1;
+ x->x_skip = 0;
+ x->x_speed = 1.0;
+ x->x_play = 0;
+ x->x_interp = (interp!=0);
+ x->x_clock = clock_new(x, (t_method)sfread_state);
+
+ while (c--) {
+ outlet_new(&x->x_obj, gensym("signal"));
+ }
+
+ x->x_stateout = outlet_new(&x->x_obj, &s_float);
+ x->x_sizeout = outlet_new(&x->x_obj, &s_float);
+
+/* post("sfread: x_channels = %d, x_speed = %f",x->x_channels,x->x_speed);*/
+
+ return (x);
+}
+
+static void sfread_free(t_sfread *x)
+{
+ clock_free(x->x_clock);
+}
+
+void sfread2_tilde_setup(void)
+{
+ /* sfread */
+
+ sfread_class = class_new(gensym("sfread2~"), (t_newmethod)sfread_new,
+ (t_method)sfread_free,sizeof(t_sfread), 0,A_DEFFLOAT,A_DEFFLOAT,0);
+
+ class_addmethod(sfread_class, nullfn, gensym("signal"), 0);
+ class_addmethod(sfread_class, (t_method) sfread_dsp, gensym("dsp"), 0);
+ class_addmethod(sfread_class, (t_method) sfread_open, gensym("open"), A_SYMBOL,A_NULL);
+ class_addmethod(sfread_class, (t_method) sfread_size, gensym("size"), 0);
+ class_addmethod(sfread_class, (t_method) sfread_state, gensym("state"), 0);
+ class_addfloat(sfread_class, sfread_float);
+ class_addbang(sfread_class,sfread_bang);
+ class_addmethod(sfread_class,(t_method)sfread_loop,gensym("loop"),A_FLOAT,A_NULL);
+ class_addmethod(sfread_class,(t_method)sfread_interp,gensym("interp"),A_FLOAT,A_NULL);
+ class_addmethod(sfread_class,(t_method)sfread_index,gensym("index"),A_FLOAT,A_NULL);
+
+
+ // Impossible with pd-0.35 because it leaves super-user mode.
+ //if(munlockall()) perror("munlockall()");
+ //if(mlockall(MCL_CURRENT)) perror("mlockall(MCL_CURRENT)");
+}
+
+
+
+
+
+
diff --git a/slist.c b/slist.c
new file mode 100644
index 0000000..6af28c6
--- /dev/null
+++ b/slist.c
@@ -0,0 +1,233 @@
+/*
+Copyright (C) 2003 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+/* a shared symbol list, ala "value" .*/
+
+#include <m_pd.h>
+#include <stdlib.h>
+#include <string.h>
+
+static t_class *slist_class, *scommon_class;
+
+typedef struct _sitem t_sitem;
+
+struct _sitem
+{
+ t_sitem *next;
+ t_symbol *s;
+};
+
+typedef struct scommon
+{
+ t_pd c_pd;
+ t_symbol *c_sym;
+ int c_refcount;
+ t_sitem *first;
+} t_scommon;
+
+typedef struct _slist
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+ t_scommon *x_c;
+ t_outlet *x_symout;
+ t_outlet *x_lenout;
+} t_slist;
+
+
+static void sitem_delete(t_sitem **x)
+{
+ t_sitem *next=(*x)->next;
+
+ //freebytes((*x)->name,strlen((*x)->name)+1);
+ freebytes(*x,sizeof(t_sitem));
+ (*x)=next;
+}
+
+static void sitem_add(t_sitem **x,t_symbol *s)
+{
+ t_int l;
+ t_sitem *newone=getbytes(sizeof(t_sitem));
+
+ //newone->name=getbytes(l=(strlen(s->s_name)+1));
+ //strncpy(newone->name,s->s_name,l);
+ newone->s=s;
+ newone->next=0;
+
+ while(*x) x=&((*x)->next);
+
+ *x=newone;
+}
+
+static void *scommon_new(t_symbol *s)
+{
+ t_scommon *x = (t_scommon *)pd_new(scommon_class);
+
+ x->c_refcount = 0;
+ x->c_sym=s;
+ pd_bind((t_pd*)x, s);
+
+ x->first=0;
+
+ return (x);
+}
+
+static int scommon_find(t_scommon *x, t_symbol *s)
+{
+ t_sitem *si=x->first;
+ t_int i=1;
+
+ while(si) {
+ if(!strcmp(si->s->s_name,s->s_name)) return i;
+ si=si->next;
+ i++;
+ }
+ return 0;
+}
+
+static void scommon_add(t_scommon *x, t_symbol *s)
+{
+ sitem_add(&x->first,s);
+}
+
+static void scommon_reset(t_scommon *x)
+{
+ while(x->first) sitem_delete(&x->first);
+}
+
+static void scommon_ff(t_scommon *x)
+{
+ scommon_reset(x);
+ pd_unbind((t_pd*)x, x->c_sym);
+}
+
+
+ /* get a pointer to a named symbol list (a "scommon" object),
+ which is created if necessary. */
+t_scommon *slist_get(t_symbol *s)
+{
+ t_scommon *c = (t_scommon *)pd_findbyclass(s, scommon_class);
+
+ if (!c) c = (t_scommon *)scommon_new(s);
+ c->c_refcount++;
+ return (c);
+}
+
+ /* release a variable. This only frees the "scommon" resource when the
+ last interested party releases it. */
+void slist_release(t_scommon *c)
+{
+ if (!--c->c_refcount) scommon_ff(c);
+}
+
+
+static void *slist_new(t_symbol *s)
+{
+ t_slist *x = (t_slist *)pd_new(slist_class);
+ x->x_sym = s;
+ x->x_c = slist_get(s);
+ outlet_new(&x->x_obj, &s_float);
+ x->x_symout=outlet_new(&x->x_obj, &s_symbol);
+ x->x_lenout=outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+static void slist_ff(t_slist *x)
+{
+ slist_release(x->x_c);
+}
+
+static void slist_print(t_slist *x)
+{
+ t_sitem *t=x->x_c->first;
+ int i=0;
+
+ while(t){
+ post("item %d: %s",++i,t->s->s_name);
+ t=t->next;
+ }
+}
+
+static void slist_reset(t_slist *x)
+{
+ scommon_reset(x->x_c);
+}
+
+static void slist_add(t_slist *x,t_symbol *s)
+{
+ scommon_add(x->x_c,s);
+}
+
+static void slist_find(t_slist *x,t_symbol *s)
+{
+ outlet_float(x->x_obj.ob_outlet,scommon_find(x->x_c,s));
+}
+
+static void slist_setlist(t_slist *x,t_symbol *s)
+{
+ slist_release(x->x_c);
+ x->x_c = slist_get(s);
+}
+
+static void slist_float(t_slist *x, t_float f)
+{
+ t_sitem *t=x->x_c->first;
+ int i=0;
+
+ if(!f) return;
+
+ while(t&&((++i)!=f)){
+ t=t->next;
+ }
+
+ if(t) outlet_symbol(x->x_symout,t->s);
+}
+
+static void slist_len(t_slist *x)
+{
+ t_sitem *t=x->x_c->first;
+ int i=0;
+
+ while(t){
+ t=t->next;
+ i++;
+ }
+
+ outlet_float(x->x_lenout,i);
+}
+
+
+void slist_setup(void)
+{
+ slist_class = class_new(gensym("slist"), (t_newmethod)slist_new,
+ (t_method)slist_ff,
+ sizeof(t_slist), 0, A_DEFSYM, 0);
+
+ //class_addbang(slist_class, slist_bang);
+ class_addfloat(slist_class, slist_float);
+ class_addmethod(slist_class,(t_method)slist_add, gensym("add"),A_SYMBOL,0);
+ class_addmethod(slist_class,(t_method)slist_find, gensym("find"),A_SYMBOL,0);
+ class_addmethod(slist_class,(t_method)slist_setlist, gensym("setlist"),A_SYMBOL,0);
+ class_addmethod(slist_class,(t_method)slist_reset, gensym("reset"),0);
+ class_addmethod(slist_class,(t_method)slist_print, gensym("print"),0);
+ class_addmethod(slist_class,(t_method)slist_len, gensym("len"),0);
+ scommon_class = class_new(gensym("slist"), 0, 0,
+ sizeof(t_scommon), CLASS_PD, 0);
+}
+
diff --git a/ssaw~.c b/ssaw~.c
new file mode 100644
index 0000000..07454ef
--- /dev/null
+++ b/ssaw~.c
@@ -0,0 +1,213 @@
+/*
+Copyright (C) 2004 Antoine Rousseau
+all material Copyright (c) 1997-1999 Miller Puckette.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+/* a "sweet" saw generator, as described in pddoc/3.audio/K05.bandlimited .*/
+
+#include "m_pd.h"
+#include "math.h"
+#include <stdlib.h>
+
+#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */
+
+ /* machine-dependent definitions. These ifdefs really
+ should have been by CPU type and not by operating system! */
+#ifdef IRIX
+ /* big-endian. Most significant byte is at low address in memory */
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#define int32 long /* a data type that has 32 bits */
+#else
+#ifdef MSW
+ /* little-endian; most significant byte is at highest address */
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#define int32 long
+#else
+#ifdef __FreeBSD__
+#include <machine/endian.h>
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#else
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#endif /* BYTE_ORDER */
+#include <sys/types.h>
+#define int32 int32_t
+#endif
+#ifdef __linux__
+
+#include <endian.h>
+
+#if !defined(__BYTE_ORDER) || !defined(__LITTLE_ENDIAN)
+#error No byte order defined
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#else
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#endif /* __BYTE_ORDER */
+
+#include <sys/types.h>
+#define int32 int32_t
+
+#else
+#ifdef MACOSX
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#define int32 int /* a data type that has 32 bits */
+
+#endif /* MACOSX */
+#endif /* __linux__ */
+#endif /* MSW */
+#endif /* SGI */
+
+union tabfudge
+{
+ double tf_d;
+ int32 tf_i[2];
+};
+
+
+/* -------------------------- ssaw~ ------------------------------ */
+static t_class *ssaw_class, *scalarssaw_class;
+static float ssaw_array[1002];
+#define SAW_ARRAY_LEN 1002
+
+typedef struct _ssaw
+{
+ t_object x_obj;
+ //from phasor~:
+ double x_phase;
+ float x_conv;
+ float x_f; /* scalar frequency */
+ float x_band; /* band limit (Hertz)*/
+} t_ssaw;
+
+static void *ssaw_new(t_floatarg f)
+{
+ t_ssaw *x = (t_ssaw *)pd_new(ssaw_class);
+ x->x_f = f;
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
+ x->x_phase = 0;
+ x->x_conv = 0;
+ x->x_band = 22000;
+ outlet_new(&x->x_obj, gensym("signal"));
+ return (x);
+}
+
+static t_int *ssaw_perform(t_int *w)
+{
+ t_ssaw *x = (t_ssaw *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int i,n = (int)(w[4]);
+ double dphase = x->x_phase + UNITBIT32;
+ union tabfudge tf;
+ int normhipart;
+ float conv = x->x_conv;
+ float band=x->x_band*.33;
+ float *buf = ssaw_array;
+
+ tf.tf_d = UNITBIT32;
+ normhipart = tf.tf_i[HIOFFSET];
+ tf.tf_d = dphase;
+
+ for (i = 0; i < n; i++)
+ //while (n--)
+ {
+ float phase,band2,findex /*= *in++*/;
+ int index /*= findex*/;
+ float frac, a, b, c, d, cminusb, *fp;
+
+ tf.tf_i[HIOFFSET] = normhipart;
+ band2=abs(*in);
+ if(band2>999999) band2=999999; else if(band2<1) band2=1;
+ band2=band/band2;
+ dphase += *in++ * conv;
+ /**out++*/phase = (tf.tf_d - UNITBIT32)-0.5;
+ tf.tf_d = dphase;
+
+ findex=phase*band2;
+ if(findex>0.5) findex=0.5; else if(findex<-0.5) findex=-0.5;
+
+ /*findex=findex*1000+501;
+ index=findex;*/
+ /*if (index < 1)
+ index = 1, frac = 0;
+ else if (index > maxindex)
+ index = maxindex, frac = 1;
+ else*/ frac = findex - index;
+ /*fp = buf + index;
+ a = fp[-1];
+ b = fp[0];
+ c = fp[1];
+ d = fp[2];
+ cminusb = c-b;
+ *out++ = 0.5+ phase - (
+ b + frac * ( cminusb - 0.1666667f * (1.-frac) * (
+ (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)))
+ );*/
+ *out++ = 0.5+ phase - buf[(int)(findex*1000+501)];
+ }
+
+ tf.tf_i[HIOFFSET] = normhipart;
+ x->x_phase = tf.tf_d - UNITBIT32;
+ return (w+5);
+}
+
+static void ssaw_dsp(t_ssaw *x, t_signal **sp)
+{
+ x->x_conv = 1./sp[0]->s_sr;
+ dsp_add(ssaw_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void ssaw_ft1(t_ssaw *x, t_float f)
+{
+ x->x_phase = f;
+}
+
+static void ssaw_initarray(void)
+{
+ int i;
+ float j;
+
+ for(i=0;i<1002;i++){
+ j=(i-1)*M_PI/1000.0; //period 2000 sample, 1 sample back phase
+ ssaw_array[i]= 0.57692*
+ (-1*cos(j) + 0.333333*cos(j*3.0) -0.2* cos(j*5.0));
+ }
+}
+
+void ssaw_tilde_setup(void)
+{
+ ssaw_class = class_new(gensym("ssaw~"), (t_newmethod)ssaw_new, 0,
+ sizeof(t_ssaw), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(ssaw_class, t_ssaw, x_f);
+ class_addmethod(ssaw_class, (t_method)ssaw_dsp, gensym("dsp"), 0);
+ class_addmethod(ssaw_class, (t_method)ssaw_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ ssaw_initarray();
+
+}
+
diff --git a/tabdump2.c b/tabdump2.c
new file mode 100644
index 0000000..9c779e9
--- /dev/null
+++ b/tabdump2.c
@@ -0,0 +1,120 @@
+/*
+Copyright (C) 2004 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+/*
+ tabdump2 -- from tabdump (from zexy) but with min/max dumping limits.
+*/
+
+#include <m_pd.h>
+
+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_dump(t_tabdump *x, t_float min, t_float max)
+{
+ t_garray *A;
+ int npoints,nmin=(int)min,nmax=(int)max;
+ 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 if ((min<0)||(max<=min)||(max>npoints))
+ error("tabdump: bad arguments min=%d max=%d for %s (%d elements)",
+ nmin,nmax,x->x_arrayname->s_name,npoints);
+ else
+ {
+ int n;
+ t_atom *atombuf;
+
+ npoints=nmax-nmin;
+ atombuf = (t_atom *)getbytes(sizeof(t_atom)*npoints);
+
+ for (n = 0; n < npoints; n++) SETFLOAT(&atombuf[n], vec[n+nmin]);
+ 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 tabdump2 - object : dumps a table as a package of floats");
+ post("'set <table>'\t: read out another table\n"
+ "'bang'\t\t: dump the table\n"
+ "'dump <min> <max>'\t\t: dump the table from <min> to <max> (without <max>)\n"
+ "outlet\t\t: table-data as package of floats");
+ post("creation\t: \"tabdump2 <table>\"");
+
+}
+
+void tabdump2_setup(void)
+{
+ tabdump_class = class_new(gensym("tabdump2"), (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_dump,gensym("dump"),
+ A_FLOAT,A_FLOAT);
+ class_addmethod(tabdump_class, (t_method)tabdump_set, gensym("set"),
+ A_SYMBOL, 0);
+
+ class_addmethod(tabdump_class, (t_method)tabdump_helper, gensym("help"), 0);
+
+}
+
diff --git a/tabenv.c b/tabenv.c
new file mode 100644
index 0000000..9b52fbe
--- /dev/null
+++ b/tabenv.c
@@ -0,0 +1,294 @@
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+#include "m_pd.h"
+#include "math.h"
+
+
+/* ---------------- tabenv - table envelope computer. ----------------- */
+/*------- (in fact it's a mix between env~ and tabplay~)----------------*/
+
+#define MAXOVERLAP 10
+#define MAXVSTAKEN 64
+
+typedef struct tabenv
+{
+ /*env part*/
+ t_object x_obj; /* header */
+ t_outlet *x_outlet; /* a "float" outlet */
+ t_clock *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 */
+ float x_f;
+
+ /*tabplay part*/
+ int x_tabphase;
+ int x_nsampsintab;
+ int x_limit;
+ float *x_vec;
+ t_symbol *x_arrayname;
+} t_tabenv;
+
+t_class *tabenv_class;
+static void tabenv_tick(t_tabenv *x);
+
+static void *tabenv_new(t_symbol *s,t_floatarg fnpoints, t_floatarg fperiod)
+{
+ int npoints = fnpoints;
+ int period = fperiod;
+ t_tabenv *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_tabenv *)pd_new(tabenv_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.14159 * i) / npoints))/npoints;
+ for (; i < npoints+MAXVSTAKEN; i++) buf[i] = 0;
+ x->x_clock = clock_new(x, (t_method)tabenv_tick);
+ x->x_outlet = outlet_new(&x->x_obj, gensym("float"));
+ x->x_f = 0;
+
+ /* tabplay */
+ x->x_tabphase = 0x7fffffff;
+ x->x_limit = 0;
+ x->x_arrayname = s;
+
+ return (x);
+}
+
+static t_int *sigenv_perform(t_int *w)
+{
+ t_tabenv *x = (t_tabenv *)(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 t_int *tabplay_tilde_perform(t_int *w)
+{
+ t_tabenv *x = (t_tabenv *)(w[1]);
+ t_float *out = (t_float *)(w[2]), *fp;
+ int n = (int)(w[3]), phase = x->x_phase,
+ endphase = (x->x_nsampsintab < x->x_limit ?
+ x->x_nsampsintab : x->x_limit), nxfer, n3;
+ if (!x->x_vec || phase >= endphase)
+ goto zero;
+
+ nxfer = endphase - phase;
+ fp = x->x_vec + phase;
+ if (nxfer > n)
+ nxfer = n;
+ n3 = n - nxfer;
+ phase += nxfer;
+ while (nxfer--)
+ *out++ = *fp++;
+ if (phase >= endphase)
+ {
+ clock_delay(x->x_clock, 0);
+ x->x_phase = 0x7fffffff;
+ while (n3--)
+ *out++ = 0;
+ }
+ else x->x_phase = phase;
+
+ return (w+4);
+zero:
+ while (n--) *out++ = 0;
+ return (w+4);
+}
+
+
+static void tabenv_perform_64(t_tabenv *x,t_float *in)
+{
+ int n = 64;
+ 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);*/
+ outlet_float(x->x_outlet, powtodb(x->x_result));
+ }
+}
+
+
+static void tabenv_set(t_tabenv *x, t_symbol *s)
+{
+ t_garray *a;
+
+ x->x_arrayname = s;
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*s->s_name) pd_error(x, "tabenv: %s: no such array",
+ x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if (!garray_getfloatarray(a, &x->x_nsampsintab, &x->x_vec))
+ {
+ error("%s: bad template for tabenv", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else garray_usedindsp(a);
+}
+
+static void sigenv_dsp(t_tabenv *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(sigenv_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+ if (sp[0]->s_n > MAXVSTAKEN) bug("sigenv_dsp");
+}
+
+static void tabenv_list(t_tabenv *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ long start = atom_getfloatarg(0, argc, argv);
+ long length = atom_getfloatarg(1, argc, argv);
+ float *limitp,*p;
+ int i;
+
+ tabenv_set(x, x->x_arrayname);
+
+ if (start < 0) start = 0;
+ if (length <= 0)
+ x->x_limit = 0x7fffffff;
+ else
+ x->x_limit = start + length;
+ x->x_tabphase = start;
+
+ if(length <= 0) length = x->x_nsampsintab - 1;
+ if(start >= x->x_nsampsintab) start = x->x_nsampsintab - 1;
+ if((start + length) >= x->x_nsampsintab)
+ length = x->x_nsampsintab - 1 - start;
+
+ limitp = x->x_vec + start + length - 63;
+ /*limitp = x->x_vec + 2048;*/
+ /*if (x->x_period % length) x->x_realperiod =
+ x->x_period + length - (x->x_period % length);
+ else*/ x->x_realperiod = x->x_period;
+
+ for(p = x->x_vec + start; p < limitp ; p += 64)
+ tabenv_perform_64( x , p );
+}
+
+static void tabenv_reset(t_tabenv *x)
+{
+ int i;
+ x->x_phase = 0;
+ for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0;
+}
+
+static void tabenv_tick(t_tabenv *x) /* callback function for the env clock */
+{
+ outlet_float(x->x_outlet, powtodb(x->x_result));
+}
+
+static void tabenv_ff(t_tabenv *x) /* cleanup on free */
+{
+ clock_free(x->x_clock);
+ freebytes(x->x_buf, (x->x_npoints + MAXVSTAKEN) * sizeof(float));
+}
+
+
+void tabenv_setup(void )
+{
+ tabenv_class = class_new(gensym("tabenv"), (t_newmethod)tabenv_new,
+ (t_method)tabenv_ff, sizeof(t_tabenv), 0, A_DEFSYM, A_DEFFLOAT, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(tabenv_class, t_tabenv, x_f);
+ class_addmethod(tabenv_class, (t_method)tabenv_reset,
+ gensym("reset"), 0);
+ class_addmethod(tabenv_class, (t_method)tabenv_set,
+ gensym("set"), A_DEFSYM, 0);
+ class_addlist(tabenv_class, tabenv_list);
+
+}
+
diff --git a/tabreadl.c b/tabreadl.c
new file mode 100644
index 0000000..e669bd8
--- /dev/null
+++ b/tabreadl.c
@@ -0,0 +1,84 @@
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+#include "m_pd.h"
+#include "math.h"
+
+/* ---------- tabreadl: control, linear interpolating ------------------------ */
+
+static t_class *tabreadl_class;
+
+typedef struct _tabreadl
+{
+ t_object x_obj;
+ t_symbol *x_arrayname;
+} t_tabreadl;
+
+static void tabreadl_float(t_tabreadl *x, t_float 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 tabreadl", x->x_arrayname->s_name);
+ else
+ {
+ int n ;
+ float r,v;
+
+ if (f < 0) f = 0;
+ else if (f >= npoints) f = npoints - 1;
+ n=f;
+ if(npoints>1){
+ r=f-n;
+ v=vec[n]*(1-r)+vec[n+1]*r;
+ outlet_float(x->x_obj.ob_outlet, v );
+ }
+ else
+ outlet_float(x->x_obj.ob_outlet, (npoints ? vec[n] : 0));
+ }
+}
+
+static void tabreadl_set(t_tabreadl *x, t_symbol *s)
+{
+ x->x_arrayname = s;
+}
+
+static void *tabreadl_new(t_symbol *s)
+{
+ t_tabreadl *x = (t_tabreadl *)pd_new(tabreadl_class);
+ x->x_arrayname = s;
+ outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+void tabreadl_setup(void)
+{
+ tabreadl_class = class_new(gensym("tabreadl"), (t_newmethod)tabreadl_new,
+ 0, sizeof(t_tabreadl), 0, A_DEFSYM, 0);
+ class_addfloat(tabreadl_class, (t_method)tabreadl_float);
+ class_addmethod(tabreadl_class, (t_method)tabreadl_set, gensym("set"),
+ A_SYMBOL, 0);
+
+}
+
+
diff --git a/tabsort.c b/tabsort.c
new file mode 100644
index 0000000..ec8fcf0
--- /dev/null
+++ b/tabsort.c
@@ -0,0 +1,124 @@
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+#include "m_pd.h"
+#include "math.h"
+
+
+/* ---------------- tabsort - sort a table to a table ----------------- */
+
+
+typedef struct tabsort
+{
+ /*env part*/
+ t_object x_obj; /* header */
+ t_symbol *x_arrayname1;
+ t_symbol *x_arrayname2;
+} t_tabsort;
+
+t_class *tabsort_class;
+
+static void *tabsort_new(t_symbol *tab1,t_symbol *tab2)
+{
+ t_tabsort *x;
+ x = (t_tabsort *)pd_new(tabsort_class);
+
+ x->x_arrayname1 = tab1;
+ x->x_arrayname2 = tab2;
+ outlet_new((t_object*)x, &s_bang);
+
+ return (x);
+}
+
+static void tabsort_set1(t_tabsort *x, t_symbol *s)
+{
+ x->x_arrayname1 = s;
+}
+static void tabsort_set2(t_tabsort *x, t_symbol *s)
+{
+ x->x_arrayname2 = s;
+}
+
+static void tabsort_float(t_tabsort *x, t_floatarg n)
+{
+ t_garray *a;
+ int n1,n2,i,j;
+ float *vec1,*vec2,tmp;
+
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname1, garray_class)))
+ {
+ if (*x->x_arrayname1->s_name) pd_error(x, "tabsort: %s: no such array",
+ x->x_arrayname1->s_name);
+ return;
+ }
+ else if (!garray_getfloatarray(a, &n1, &vec1))
+ {
+ error("%s: bad template for tabsort", x->x_arrayname1->s_name);
+ return;
+ }
+
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname2, garray_class)))
+ {
+ if (*x->x_arrayname2->s_name) pd_error(x, "tabsort: %s: no such array",
+ x->x_arrayname2->s_name);
+ return;
+ }
+ else if (!garray_getfloatarray(a, &n2, &vec2))
+ {
+ error("%s: bad template for tabsort", x->x_arrayname2->s_name);
+ return;
+ }
+
+ if(n>n1) n=n1;
+ if(n>n2) n=n2;
+
+
+ for(i=0;i<n;vec2[i]=i++);
+
+ for(i=0;i<n-1;i++)
+ for(j=n-1;j>i;j--)
+ if(vec1[(int)vec2[j-1]]<vec1[(int)vec2[j]])
+ {
+ tmp=vec2[j];
+ vec2[j]=vec2[j-1];
+ vec2[j-1]=tmp;
+ }
+
+ garray_redraw(a);
+ outlet_bang(((t_object *)x)->ob_outlet);
+}
+
+
+static void tabsort_ff(t_tabsort *x) /* cleanup on free */
+{
+}
+
+
+void tabsort_setup(void )
+{
+ tabsort_class = class_new(gensym("tabsort"), (t_newmethod)tabsort_new,
+ (t_method)tabsort_ff, sizeof(t_tabsort), 0, A_DEFSYM, A_DEFSYM, 0);
+ class_addmethod(tabsort_class, (t_method)tabsort_set1,
+ gensym("set1"), A_DEFSYM, 0);
+ class_addmethod(tabsort_class, (t_method)tabsort_set2,
+ gensym("set2"), A_DEFSYM, 0);
+ class_addfloat(tabsort_class, tabsort_float);
+
+}
+
diff --git a/tabsort2.c b/tabsort2.c
new file mode 100644
index 0000000..63d0fd6
--- /dev/null
+++ b/tabsort2.c
@@ -0,0 +1,164 @@
+/*
+Copyright (C) 2002 Antoine Rousseau
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+#include "m_pd.h"
+#include "math.h"
+
+
+/* ---------------- tabsort2 - sort a table to a table ----------------- */
+
+
+typedef struct tabsort2
+{
+ t_object x_obj; /* header */
+ t_symbol *x_arrayname1;
+ t_symbol *x_arrayname2;
+ t_symbol *x_arrayname3;
+ t_clock *x_clock; /* a "clock" object */
+} t_tabsort2;
+
+t_class *tabsort2_class;
+
+static void tabsort2_tick(t_tabsort2 *x);
+
+static void *tabsort2_new(t_symbol *tab1,t_symbol *tab2,t_symbol *tab3)
+{
+ t_tabsort2 *x;
+ x = (t_tabsort2 *)pd_new(tabsort2_class);
+
+ x->x_arrayname1 = tab1;
+ x->x_arrayname2 = tab2;
+ x->x_arrayname3 = tab3;
+ x->x_clock = clock_new(x, (t_method)tabsort2_tick);
+ outlet_new((t_object*)x, &s_float);
+
+ return (x);
+}
+
+static void tabsort2_set1(t_tabsort2 *x, t_symbol *s)
+{
+ x->x_arrayname1 = s;
+}
+static void tabsort2_set2(t_tabsort2 *x, t_symbol *s)
+{
+ x->x_arrayname2 = s;
+}
+
+static void tabsort2_set3(t_tabsort2 *x, t_symbol *s)
+{
+ x->x_arrayname3 = s;
+}
+
+static void tabsort2_float(t_tabsort2 *x, t_floatarg n)
+{
+ t_garray *a;
+ int n1,n2,n3,i,j,h,sqn;
+ float *vec1,*vec2,*vec3,tmp;
+
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname1, garray_class)))
+ {
+ if (*x->x_arrayname1->s_name) pd_error(x, "tabsort2: %s: no such array",
+ x->x_arrayname1->s_name);
+ return;
+ }
+ else if (!garray_getfloatarray(a, &n1, &vec1))
+ {
+ error("%s: bad template for tabsort2", x->x_arrayname1->s_name);
+ return;
+ }
+
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname2, garray_class)))
+ {
+ if (*x->x_arrayname2->s_name) pd_error(x, "tabsort2: %s: no such array",
+ x->x_arrayname2->s_name);
+ return;
+ }
+ else if (!garray_getfloatarray(a, &n2, &vec2))
+ {
+ error("%s: bad template for tabsort2", x->x_arrayname2->s_name);
+ return;
+ }
+
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname3, garray_class)))
+ {
+ if (*x->x_arrayname3->s_name) pd_error(x, "tabsort2: %s: no such array",
+ x->x_arrayname3->s_name);
+ return;
+ }
+ else if (!garray_getfloatarray(a, &n3, &vec3))
+ {
+ error("%s: bad template for tabsort2", x->x_arrayname3->s_name);
+ return;
+ }
+
+ if(n>n1) n=n1;
+ if(n>n2) n=n2;
+ if(n>n3) n=n3;
+
+ for(i=0;i<n;vec3[i]=i++);
+
+ for(i=0;i<n-1;i++)
+ for(j=n-1;j>i;j--)
+ if(vec1[(int)vec3[j-1]]<vec1[(int)vec3[j]])
+ {
+ tmp=vec3[j];
+ vec3[j]=vec3[j-1];
+ vec3[j-1]=tmp;
+ }
+
+ sqn=(int)sqrt(n);
+
+ for(h=0;h<sqn;h++)
+ for(i=0;i<sqn-1;i++)
+ for(j=sqn-1;j>i;j--)
+ if(vec2[(int)vec3[h*sqn+j-1]]<vec2[(int)vec3[h*sqn+j]])
+ {
+ tmp=vec3[h*sqn+j];
+ vec3[h*sqn+j]=vec3[h*sqn+j-1];
+ vec3[h*sqn+j-1]=tmp;
+ }
+
+ garray_redraw(a);
+ outlet_float(((t_object *)x)->ob_outlet,(float)sqn);
+}
+
+static void tabsort2_tick(t_tabsort2 *x) /* callback function for the env clock */
+{
+
+ //clock_delay(x->x_clock, 0L);
+}
+
+static void tabsort2_ff(t_tabsort2 *x) /* cleanup on free */
+{
+ clock_free(x->x_clock);
+}
+
+
+void tabsort2_setup(void )
+{
+ tabsort2_class = class_new(gensym("tabsort2"), (t_newmethod)tabsort2_new,
+ (t_method)tabsort2_ff, sizeof(t_tabsort2), 0, A_DEFSYM, A_DEFSYM, A_DEFSYM, 0);
+ class_addmethod(tabsort2_class, (t_method)tabsort2_set1,
+ gensym("set1"), A_DEFSYM, 0);
+ class_addmethod(tabsort2_class, (t_method)tabsort2_set2,
+ gensym("set2"), A_DEFSYM, 0);
+ class_addfloat(tabsort2_class, tabsort2_float);
+
+}
+
diff --git a/wac.c b/wac.c
new file mode 100644
index 0000000..1bf132e
--- /dev/null
+++ b/wac.c
@@ -0,0 +1,253 @@
+ /*
+ wacom graphire on serial port only...
+*/
+
+#include <m_imp.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#define BUFSIZE 256
+#define HEADER_BIT 0x80
+#define ZAXIS_SIGN_BIT 0x40
+#define ZAXIS_BIT 0x04
+#define ZAXIS_BITS 0x3f
+#define POINTER_BIT 0x20
+#define PROXIMITY_BIT 0x40
+#define BUTTON_FLAG 0x08
+#define BUTTONS_BITS 0x78
+#define TILT_SIGN_BIT 0x40
+#define TILT_BITS 0x3f
+
+/* defines to discriminate second side button and the eraser */
+#define ERASER_PROX 4
+#define OTHER_PROX 1
+
+#define Threshold 1000
+unsigned char data[7];
+
+typedef struct _wac
+{
+ t_object t_ob;
+ t_outlet *axis_out;
+ t_outlet *button_out;
+ t_symbol *file;
+ int fd;
+ int count;
+ int oldbuttons;
+ unsigned char data[BUFSIZE];
+}t_wac;
+
+t_class *wac_class;
+
+void wac_setup(void);
+static void wac_read(t_wac *x,int fd);
+static void wac_process(t_wac *x);
+
+static void wac_open(t_wac *x)
+{
+ if(x->fd>=0) return;
+
+ x->fd = open (x->file->s_name, O_RDONLY | O_NONBLOCK);
+ if(x->fd<0){
+ post("open (%s, O_RDONLY | O_NONBLOCK)",x->file->s_name);
+ perror("open");
+ return;
+ }
+ sys_addpollfn(x->fd,(t_fdpollfn)wac_read,(void*)x);
+}
+
+static void wac_close(t_wac *x)
+{
+ if(x->fd<0) return;
+
+ sys_rmpollfn(x->fd);
+ close(x->fd);
+ x->fd=-1;
+}
+
+static void wac_float(t_wac *x,t_floatarg connect)
+{
+ if(connect!=0) wac_open(x);
+ else wac_close(x);
+}
+
+static void *wac_new(t_symbol *file)
+{
+ t_wac *x = (t_wac *)pd_new(wac_class);
+
+ //if(file->s_name)
+ if(file!=&s_)
+ x->file=file;
+ else x->file=gensym("/dev/ttyS0");
+
+ post("wac_new file=%s",x->file->s_name);
+ x->axis_out = outlet_new(&x->t_ob, &s_list);
+ x->button_out = outlet_new(&x->t_ob, &s_list);
+
+ x->fd=-1;
+
+ return (void *)x;
+}
+
+void wac_setup(void)
+{
+ wac_class = class_new(gensym("wac"),(t_newmethod)wac_new,
+ (t_method)wac_close, sizeof(t_wac), 0, A_DEFSYM, 0);
+ class_addfloat(wac_class, wac_float);
+
+
+}
+
+
+static void wac_read(t_wac *x,int fd)
+{
+ int len,i=0;
+ unsigned char b;
+ unsigned char buffer[BUFSIZE];
+
+ while((len=read(fd,buffer,BUFSIZE))> -1){
+
+ for(i=0;i<len;i++){
+ if(buffer[i]&128) x->count=0;
+ x->data[x->count++]=buffer[i];
+ if(x->count==7) wac_process(x);
+ }
+ }
+}
+
+static void wac_process(t_wac *X)
+{
+ int is_stylus = 1, is_button, is_proximity, wheel=0;
+ int x, y, z, buttons, tx = 0, ty = 0;
+ unsigned char *data=X->data;
+ t_atom ats[3];
+
+ is_stylus = (data[0] & POINTER_BIT);
+
+ if(!is_stylus) return;
+
+ x = (((data[0] & 0x3) << 14) +
+ (data[1] << 7) +
+ data[2]);
+ y = (((data[3] & 0x3) << 14) +
+ (data[4] << 7) +
+ data[5]);
+
+
+ z = ((data[6] & ZAXIS_BITS) * 2) +
+ ((data[3] & ZAXIS_BIT) >> 2);
+
+ //z = z*4 + ((data[0] & ZAXIS_BIT) >> 1);
+
+ if (!(data[6] & ZAXIS_SIGN_BIT)) {
+ z += 128;
+ }
+
+ is_proximity = (data[0] & PROXIMITY_BIT);
+
+ buttons = ((data[3] & 0x38) >> 3);
+ /*if (is_stylus) {
+ buttons = ((data[3] & 0x30) >> 3) |
+ (z >= Threshold ? 1 : 0);
+ }
+ else {
+ buttons = (data[3] & 0x38) >> 3;
+
+ wheel = (data[6] & 0x30) >> 4;
+
+ if (data[6] & 0x40) {
+ wheel = -wheel;
+ }
+ }*/
+ //is_button = (buttons != 0);
+ if(buttons!=X->oldbuttons)
+ {
+ X->oldbuttons=buttons;
+
+ SETFLOAT(&ats[0],buttons&1);
+ SETFLOAT(&ats[1],(buttons&2)!=0);
+ SETFLOAT(&ats[2],(buttons&4)!=0);
+ outlet_list(X->button_out,0,3,ats);
+ }
+ SETFLOAT(&ats[0],x/5103.0);
+ SETFLOAT(&ats[1],y/3711.0);
+ SETFLOAT(&ats[2],z/256.0);
+ outlet_list(X->axis_out,0,3,ats);
+}
+ /* Format of 7 bytes data packet for Wacom Tablets
+ Byte 1
+ bit 7 Sync bit always 1
+ bit 6 Pointing device detected
+ bit 5 Cursor = 0 / Stylus = 1
+ bit 4 Reserved
+ bit 3 1 if a button on the pointing device has been pressed
+ bit 2 Reserved
+ bit 1 X15
+ bit 0 X14
+
+ Byte 2
+ bit 7 Always 0
+ bits 6-0 = X13 - X7
+
+ Byte 3
+ bit 7 Always 0
+ bits 6-0 = X6 - X0
+
+ Byte 4
+ bit 7 Always 0
+ bit 6 B3
+ bit 5 B2
+ bit 4 B1
+ bit 3 B0
+ bit 2 P0
+ bit 1 Y15
+ bit 0 Y14
+
+ Byte 5
+ bit 7 Always 0
+ bits 6-0 = Y13 - Y7
+
+ Byte 6
+ bit 7 Always 0
+ bits 6-0 = Y6 - Y0
+
+ Byte 7
+ bit 7 Always 0
+ bit 6 Sign of pressure data
+ bit 5 P6
+ bit 4 P5
+ bit 3 P4
+ bit 2 P3
+ bit 1 P2
+ bit 0 P1
+
+ byte 8 and 9 are optional and present only
+ in tilt mode.
+
+ Byte 8
+ bit 7 Always 0
+ bit 6 Sign of tilt X
+ bit 5 Xt6
+ bit 4 Xt5
+ bit 3 Xt4
+ bit 2 Xt3
+ bit 1 Xt2
+ bit 0 Xt1
+
+ Byte 9
+ bit 7 Always 0
+ bit 6 Sign of tilt Y
+ bit 5 Yt6
+ bit 4 Yt5
+ bit 3 Yt4
+ bit 2 Yt3
+ bit 1 Yt2
+ bit 0 Yt1
+
+ */
+