From bfb359fd22e61faaca3a6e49ad3b7a81f2d71551 Mon Sep 17 00:00:00 2001
From: "N.N." <krzyszcz@users.sourceforge.net>
Date: Thu, 27 Jan 2005 14:42:55 +0000
Subject: cyclone alpha52 and toxy alpha15 (see notes.txt for cyclone, toxy and
 shared)

svn path=/trunk/externals/miXed/; revision=2550
---
 Makefile.common                 |  20 +-
 ViCious/cyclone/makefile        |   2 +-
 ViCious/cyclone/objects         |   5 +
 ViCious/toxy/makefile           |   2 +-
 ViCious/toxy/objects            |   2 +
 cyclone/Makefile.objects        |  20 +-
 cyclone/Makefile.sources        |   8 +-
 cyclone/build_counter           |   4 +-
 cyclone/cyclone-shared.include  |   2 +
 cyclone/hammer/Append.c         |  13 +-
 cyclone/hammer/Decode.c         |   2 +-
 cyclone/hammer/Makefile.objects |   1 +
 cyclone/hammer/bangbang.c       |   2 +-
 cyclone/hammer/counter.c        |   2 +-
 cyclone/hammer/cycle.c          |   2 +-
 cyclone/hammer/gate.c           |   2 +-
 cyclone/hammer/hammer.c         |  38 +--
 cyclone/hammer/maximum.c        |   2 +-
 cyclone/hammer/minimum.c        |   2 +-
 cyclone/hammer/mtr.c            |   2 +-
 cyclone/hammer/past.c           |   2 +-
 cyclone/hammer/prepend.c        |  15 +-
 cyclone/hammer/prob.c           |   2 +-
 cyclone/hammer/seq.c            | 101 ++++++-
 cyclone/hammer/switch.c         |   2 +-
 cyclone/hammer/urn.c            |   2 +-
 cyclone/notes.txt               |  40 +++
 cyclone/shadow/Makefile.objects |   1 +
 cyclone/shadow/cyclone.c        |  38 +--
 cyclone/shadow/dummies.c        |   4 +
 cyclone/shadow/maxmode.c        |  84 +++---
 cyclone/sickle/Makefile.objects |   1 +
 cyclone/sickle/Makefile.sources |   1 +
 cyclone/sickle/Scope.c          |   2 +-
 cyclone/sickle/allsickles.c     |   4 +-
 cyclone/sickle/buffir.c         |   2 +-
 cyclone/sickle/linedrive.c      | 128 ++++++---
 cyclone/sickle/matrix.c         | 563 ++++++++++++++++++++++++++++++++++++++++
 cyclone/sickle/sickle.c         |  38 +--
 shared/common/Makefile.sources  |   2 +-
 shared/common/binport.c         |  16 +-
 shared/common/binport.h         |  14 +-
 shared/common/fi.c              |  54 ----
 shared/common/fi.h              |  11 -
 shared/common/fitter.c          |  33 +--
 shared/common/fitter.h          |   5 +-
 shared/common/loud.c            |  26 +-
 shared/common/os.c              | 235 +++++++++++++++++
 shared/common/os.h              |  13 +
 shared/common/port.c            |  28 +-
 shared/common/port.h            |   4 +-
 shared/getridof.baddeps         |   2 +-
 shared/hammer/file.c            | 117 ++++++++-
 shared/hammer/file.h            |  27 +-
 shared/notes.txt                |  29 +++
 shared/unstable/forky.c         |   3 +-
 shared/unstable/fragile.c       | 174 ++++++++++++-
 shared/unstable/fragile.h       |   9 +-
 shared/unstable/pd_imp.h        |   2 +
 test/cyclone/cyclone-test.pd    |  54 ++--
 test/cyclone/linedrive-test.pd  |  11 +
 test/cyclone/matrix-test.pd     | 165 ++++++++++++
 test/cyclone/maxmode-test.pd    |  72 ++---
 test/toxy/kb.wid                |   3 -
 test/toxy/multiscale.wid        |   6 +-
 test/toxy/setup.wid             |  49 +++-
 toxy/Makefile.objects           |   3 +
 toxy/build_counter              |   4 +-
 toxy/notes.txt                  |  26 ++
 toxy/toxy-shared.include        |   2 +
 toxy/widget.c                   |  29 +--
 71 files changed, 1992 insertions(+), 399 deletions(-)
 create mode 100644 cyclone/notes.txt
 create mode 100644 cyclone/sickle/matrix.c
 delete mode 100644 shared/common/fi.c
 delete mode 100644 shared/common/fi.h
 create mode 100644 shared/common/os.c
 create mode 100644 shared/common/os.h
 create mode 100644 shared/notes.txt
 create mode 100644 test/cyclone/linedrive-test.pd
 create mode 100644 test/cyclone/matrix-test.pd
 create mode 100644 toxy/notes.txt

diff --git a/Makefile.common b/Makefile.common
index aec8e9e..018a5ef 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -1,12 +1,6 @@
 # next line has to be edited manually
 PD_DIR = $(ROOT_DIR)/../../pd/src
 
-# remove this restriction LATER, when TCL_LIB is ./configured
-ifeq ($(shell whoami),krzYszcz)
-# TCL_LIB should be set (or not) before "include Makefile.sources"
-TCL_LIB = -l$(shell grep -osm1 'tcl8\.[345]' $(PD_DIR)/makefile)
-endif
-
 OS_NAME = $(shell uname -s)
 ifneq ($(OS_NAME),Linux)
 ifneq ($(OS_NAME),Darwin)
@@ -22,6 +16,14 @@ endif
 endif
 endif
 
+MY_NAME = $(shell id -un)
+
+# remove this restriction LATER, when TCL_LIB is ./configured
+ifeq ($(MY_NAME),krzYszcz)
+# TCL_LIB should be set (or not) before "include Makefile.sources"
+TCL_LIB = -l$(shell grep -osm1 'tcl8\.[345]' $(PD_DIR)/makefile)
+endif
+
 TILDE = ~
 
 -include Makefile.dirs
@@ -36,7 +38,7 @@ CC = gcc
 LFLAGS = -export_dynamic  -shared
 # FIXME strict-aliasing
 OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer -fno-strict-aliasing
-ifeq ($(shell whoami),krzYszcz)
+ifeq ($(MY_NAME),krzYszcz)
 DEFINES = -DUNIX -DKRZYSZCZ
 else
 DEFINES = -DUNIX
@@ -98,7 +100,7 @@ SOURCES = $(CX_SOURCES) $(AX_SOURCES) $(LX_SOURCES) $(OTHER_SOURCES) \
 
 INCLUDES = -I. -I$(PD_DIR) -I$(SHARED_DIR)
 
-ifeq ($(shell whoami),krzYszcz)
+ifeq ($(MY_NAME),krzYszcz)
 WARN_CFLAGS = -Wall -W -Wstrict-prototypes -Werror \
 	-Wno-unused -Wno-parentheses -Wno-switch
 else
@@ -213,7 +215,7 @@ SUBDIRS_DEFAULT = @for i in $(MIXED_DIRS) and_in_case_it_is_null ; \
 			cd $$i; $(MAKE) ; fi ) ; done
 
 define_build:
-	@if [[ -f build_counter && `whoami` == krzYszcz && \
+	@if [[ -f build_counter && `id -un` == krzYszcz && \
 		`date -r build_counter +%j` != `date +%j` ]] ; then \
 		mv build_counter build_counter~ ; \
 		echo -n 'increment build counter (y/n)? [n]' ; read doit ; \
diff --git a/ViCious/cyclone/makefile b/ViCious/cyclone/makefile
index 58c2457..4ae0367 100644
--- a/ViCious/cyclone/makefile
+++ b/ViCious/cyclone/makefile
@@ -12,7 +12,7 @@ VCLIBDIR = "e:\Program Files\Microsoft Visual Studio\Vc98\lib"
 ZIPCOMMAND = d:\dosowe\arc\info-zip\zip
 
 INCLUDES = /I.  /I$(SHAREDDIR) /I$(PDDIR)\src
-CFLAGS = /W3 /WX /DNT /DPD /nologo
+CFLAGS = /W3 /WX /DNT /DMSW /DPD /nologo
 
 LIBS = $(VCLIBDIR)\libc.lib \
 	$(VCLIBDIR)\oldnames.lib \
diff --git a/ViCious/cyclone/objects b/ViCious/cyclone/objects
index 34a9deb..893d04b 100644
--- a/ViCious/cyclone/objects
+++ b/ViCious/cyclone/objects
@@ -3,6 +3,7 @@ CYCLONE_OBJECTS = \
 	$(SRCDIR)\shadow\nettles.obj \
 	$(SHAREDDIR)\common\loud.obj \
 	$(SHAREDDIR)\common\grow.obj \
+	$(SHAREDDIR)\common\os.obj \
 	$(SHAREDDIR)\common\lex.obj \
 	$(SHAREDDIR)\common\binport.obj \
 	$(SHAREDDIR)\common\port.obj \
@@ -97,6 +98,7 @@ HAMMER_OBJECTS = $(ALL_HAMMERS) \
 	$(SRCDIR)\hammer\allhammers.obj \
 	$(SHAREDDIR)\common\loud.obj \
 	$(SHAREDDIR)\common\grow.obj \
+	$(SHAREDDIR)\common\os.obj \
 	$(SHAREDDIR)\common\fitter.obj \
 	$(SHAREDDIR)\common\rand.obj \
 	$(SHAREDDIR)\common\vefl.obj \
@@ -153,6 +155,7 @@ ALL_SICKLES = \
 	$(SRCDIR)\sickle\log.obj \
 	$(SRCDIR)\sickle\lookup.obj \
 	$(SRCDIR)\sickle\lores.obj \
+	$(SRCDIR)\sickle\matrix.obj \
 	$(SRCDIR)\sickle\maximum.obj \
 	$(SRCDIR)\sickle\minimum.obj \
 	$(SRCDIR)\sickle\minmax.obj \
@@ -194,6 +197,7 @@ SICKLE_OBJECTS = $(ALL_SICKLES) \
 	$(SRCDIR)\sickle\allsickles.obj \
 	$(SHAREDDIR)\common\loud.obj \
 	$(SHAREDDIR)\common\grow.obj \
+	$(SHAREDDIR)\common\os.obj \
 	$(SHAREDDIR)\common\fitter.obj \
 	$(SHAREDDIR)\common\vefl.obj \
 	$(SHAREDDIR)\common\clc.obj \
@@ -222,6 +226,7 @@ MAXMODE_OBJECTS = \
 	$(SRCDIR)\shadow\maxmode.obj \
 	$(SHAREDDIR)\common\loud.obj \
 	$(SHAREDDIR)\common\grow.obj \
+	$(SHAREDDIR)\common\os.obj \
 	$(SHAREDDIR)\common\fitter.obj \
 	$(SHAREDDIR)\common\lex.obj \
 	$(SHAREDDIR)\common\binport.obj \
diff --git a/ViCious/toxy/makefile b/ViCious/toxy/makefile
index 15e1bc5..2cf8c51 100644
--- a/ViCious/toxy/makefile
+++ b/ViCious/toxy/makefile
@@ -12,7 +12,7 @@ VCLIBDIR = "e:\Program Files\Microsoft Visual Studio\Vc98\lib"
 ZIPCOMMAND = d:\dosowe\arc\info-zip\zip
 
 INCLUDES = /I.  /I$(SHAREDDIR) /I$(PDDIR)\src
-CFLAGS = /W3 /WX /DNT /DPD /nologo
+CFLAGS = /W3 /WX /DNT /DMSW /DPD /nologo
 
 LIBS = $(VCLIBDIR)\libc.lib \
 	$(VCLIBDIR)\oldnames.lib \
diff --git a/ViCious/toxy/objects b/ViCious/toxy/objects
index f0c4d85..afe7080 100644
--- a/ViCious/toxy/objects
+++ b/ViCious/toxy/objects
@@ -2,6 +2,7 @@ TOT_OBJECTS = $(SRCDIR)\tot.obj \
 	$(SHAREDDIR)\unstable\forky.obj \
 	$(SHAREDDIR)\common\loud.obj \
 	$(SHAREDDIR)\common\grow.obj \
+	$(SHAREDDIR)\common\os.obj \
 	$(SHAREDDIR)\hammer\file.obj \
 	$(SHAREDDIR)\hammer\gui.obj \
 	$(SHAREDDIR)\common\props.obj \
@@ -17,6 +18,7 @@ WIDGET_OBJECTS = $(SRCDIR)\widget.obj \
 	$(SHAREDDIR)\common\loud.obj \
 	$(SHAREDDIR)\common\grow.obj \
 	$(SHAREDDIR)\common\dict.obj \
+	$(SHAREDDIR)\common\os.obj \
 	$(SHAREDDIR)\hammer\file.obj \
 	$(SHAREDDIR)\common\props.obj \
 	$(SHAREDDIR)\toxy\scriptlet.obj
diff --git a/cyclone/Makefile.objects b/cyclone/Makefile.objects
index 2a076ba..2641eee 100644
--- a/cyclone/Makefile.objects
+++ b/cyclone/Makefile.objects
@@ -4,22 +4,27 @@ HFORKY_OBJECTS = common/loud.o unstable/forky.o
 HFRAGILE_OBJECTS = common/loud.o unstable/fragile.o
 HGROW_OBJECTS = common/grow.o common/loud.o
 HGROWFITTER_OBJECTS = common/grow.o common/loud.o common/fitter.o
-HFILE_OBJECTS = hammer/file.o common/loud.o common/fitter.o unstable/forky.o
+HFILE_OBJECTS = hammer/file.o common/loud.o common/os.o \
+	common/fitter.o unstable/forky.o
 HRAND_OBJECTS = common/rand.o common/loud.o
-HRANDFILE_OBJECTS = common/rand.o hammer/file.o common/loud.o common/fitter.o \
+HRANDFILE_OBJECTS = common/rand.o hammer/file.o common/loud.o common/os.o \
+	 common/fitter.o \
 	unstable/forky.o
 HRANDGROW_OBJECTS = common/rand.o common/grow.o common/loud.o common/fitter.o
 HRANDGROWFILE_OBJECTS = common/rand.o common/grow.o hammer/file.o \
-	common/loud.o unstable/forky.o
+	common/loud.o common/os.o unstable/forky.o
 HTREE_OBJECTS = hammer/tree.o common/loud.o
-HTREEFILEVEFL_OBJECTS = hammer/tree.o hammer/file.o \
-	common/vefl.o common/loud.o unstable/forky.o unstable/fragile.o
+HTREEFILEVEFL_OBJECTS = hammer/tree.o hammer/file.o common/vefl.o \
+	common/loud.o common/os.o unstable/forky.o unstable/fragile.o
 HGUI_OBJECTS =  hammer/gui.o common/loud.o
 HSEQ_OBJECTS = common/mifi.o hammer/file.o \
-	common/grow.o common/loud.o common/fitter.o unstable/forky.o
+	common/grow.o common/loud.o common/os.o common/fitter.o unstable/forky.o
+SPLAINNOTILDE_OBJECTS = common/loud.o common/fitter.o
 SSIC_OBJECTS = sickle/sic.o common/loud.o
 SFORKY_OBJECTS = sickle/sic.o common/loud.o unstable/forky.o
 SFRAGILE_OBJECTS = sickle/sic.o common/loud.o unstable/fragile.o
+SFRAGILEFITTER_OBJECTS = sickle/sic.o common/loud.o common/fitter.o \
+	unstable/fragile.o
 SGROW_OBJECTS = common/grow.o sickle/sic.o common/loud.o
 SGROWCLC_OBJECTS = common/grow.o common/clc.o sickle/sic.o common/loud.o
 SGROWFORKY_OBJECTS = common/grow.o sickle/sic.o \
@@ -29,6 +34,7 @@ SARSIC_OBJECTS = sickle/sic.o sickle/arsic.o common/vefl.o \
 	common/loud.o unstable/fragile.o
 SARSICFITTER_OBJECTS = sickle/sic.o sickle/arsic.o common/vefl.o \
 	common/loud.o common/fitter.o unstable/fragile.o
-SFILE_OBJECTS = hammer/file.o sickle/sic.o common/loud.o unstable/forky.o
+SFILE_OBJECTS = hammer/file.o sickle/sic.o common/loud.o common/os.o \
+	unstable/forky.o
 RELEASE_LIBS = cyclone hammer sickle dummies maxmode
 RELEASE_APPS = cyclist
diff --git a/cyclone/Makefile.sources b/cyclone/Makefile.sources
index bcadba2..2ec02fc 100644
--- a/cyclone/Makefile.sources
+++ b/cyclone/Makefile.sources
@@ -1,8 +1,8 @@
 TYPES = HPLAIN HLOUD HFITTER HFORKY HFRAGILE HGROW HGROWFITTER \
 	HFILE HRAND HRANDFILE HRANDGROW HRANDGROWFILE \
 	HTREE HTREEFILEVEFL HGUI HSEQ \
-	SPLAINNOTILDE SPLAIN SSIC SFORKY SFRAGILE SGROW SGROWCLC SGROWFORKY \
-	SVEFL SARSIC SARSICFITTER SFILE
+	SPLAINNOTILDE SPLAIN SSIC SFORKY SFRAGILE SFRAGILEFITTER \
+	SGROW SGROWCLC SGROWFORKY SVEFL SARSIC SARSICFITTER SFILE
 
 HPLAIN_SOURCES = \
 hammer/testmess.c \
@@ -184,6 +184,10 @@ SFRAGILE_SOURCES = \
 sickle/cartopol.c \
 sickle/poltocar.c
 
+SFRAGILEFITTER_TILDE = $(TILDE)
+SFRAGILEFITTER_SOURCES = \
+sickle/matrix.c
+
 SGROW_TILDE = $(TILDE)
 SGROW_SOURCES = \
 sickle/click.c \
diff --git a/cyclone/build_counter b/cyclone/build_counter
index 10003f3..55027b1 100644
--- a/cyclone/build_counter
+++ b/cyclone/build_counter
@@ -1,7 +1,7 @@
 #define CYCLONE_VERSION "0.1"
 #define CYCLONE_RELEASE "alpha"
-#define CYCLONE_BUILD 51
+#define CYCLONE_BUILD 52
 
 #if 0
-CYCLONE_SNAPSHOT = 0.1-alpha51
+CYCLONE_SNAPSHOT = 0.1-alpha52
 #endif
diff --git a/cyclone/cyclone-shared.include b/cyclone/cyclone-shared.include
index 6b0cce8..2180624 100644
--- a/cyclone/cyclone-shared.include
+++ b/cyclone/cyclone-shared.include
@@ -15,6 +15,8 @@ shared/common/loud.c
 shared/common/loud.h
 shared/common/grow.c
 shared/common/grow.h
+shared/common/os.c
+shared/common/os.h
 shared/common/fitter.c
 shared/common/fitter.h
 shared/common/lex.c
diff --git a/cyclone/hammer/Append.c b/cyclone/hammer/Append.c
index 16b65cc..4be4807 100644
--- a/cyclone/hammer/Append.c
+++ b/cyclone/hammer/Append.c
@@ -34,8 +34,7 @@ typedef struct _appendxy
 static t_class *append_class;
 static t_class *appendxy_class;
 
-static t_symbol *appendps_compatibility = 0;
-static t_symbol *appendps_max;
+static int append_iscompatible = 0;  /* FIXME per-object */
 
 /* Usually a preallocation method is used, except in special cases of:
    1) reentrant output request, or 2) an output request which would cause
@@ -155,7 +154,7 @@ static void append_anything(t_append *x, t_symbol *s, int ac, t_atom *av)
 
 static void append_bang(t_append *x)
 {
-    if (appendps_compatibility == appendps_max)
+    if (append_iscompatible)
     {
 	/* CHECKED: a nop */
     }
@@ -325,6 +324,11 @@ static void *append_new(t_symbol *s, int ac, t_atom *av)
     return (x);
 }
 
+static void append_fitter(void)
+{
+    append_iscompatible = fittermax_get();
+}
+
 void Append_setup(void)
 {
     append_class = class_new(gensym("Append"),
@@ -348,6 +352,5 @@ void Append_setup(void)
     class_addlist(appendxy_class, appendxy_list);
     class_addanything(appendxy_class, appendxy_anything);
 
-    appendps_max = gensym("max");
-    fitter_setup(append_class, &appendps_compatibility, 0);
+    fitter_setup(append_class, append_fitter);
 }
diff --git a/cyclone/hammer/Decode.c b/cyclone/hammer/Decode.c
index 0342594..0d62237 100644
--- a/cyclone/hammer/Decode.c
+++ b/cyclone/hammer/Decode.c
@@ -108,5 +108,5 @@ void Decode_setup(void)
 		    gensym("ft1"), A_FLOAT, 0);
     class_addmethod(Decode_class, (t_method)Decode_alloff,
 		    gensym("ft2"), A_FLOAT, 0); 
-    fitter_setup(Decode_class, 0, 0);
+    fitter_setup(Decode_class, 0);
 }
diff --git a/cyclone/hammer/Makefile.objects b/cyclone/hammer/Makefile.objects
index eb54f17..a7099d8 100644
--- a/cyclone/hammer/Makefile.objects
+++ b/cyclone/hammer/Makefile.objects
@@ -4,6 +4,7 @@ unstable/fragile.o \
 unstable/fringe.o \
 common/loud.o \
 common/grow.o \
+common/os.o \
 common/fitter.o \
 common/rand.o \
 common/vefl.o \
diff --git a/cyclone/hammer/bangbang.c b/cyclone/hammer/bangbang.c
index 5ae3506..aa8363d 100644
--- a/cyclone/hammer/bangbang.c
+++ b/cyclone/hammer/bangbang.c
@@ -71,5 +71,5 @@ void bangbang_setup(void)
 			       sizeof(t_bangbang), 0, A_DEFFLOAT, 0);
     class_addbang(bangbang_class, bangbang_bang);
     class_addanything(bangbang_class, bangbang_anything);
-    fitter_setup(bangbang_class, 0, 0);
+    fitter_setup(bangbang_class, 0);
 }
diff --git a/cyclone/hammer/counter.c b/cyclone/hammer/counter.c
index 0b29b3f..dd987d4 100644
--- a/cyclone/hammer/counter.c
+++ b/cyclone/hammer/counter.c
@@ -398,5 +398,5 @@ void counter_setup(void)
 				    CLASS_PD | CLASS_NOINLET, 0);
     class_addbang(counter_proxy_class, counter_proxy_bang);
     class_addfloat(counter_proxy_class, counter_proxy_float);
-    fitter_setup(counter_class, 0, 0);
+    fitter_setup(counter_class, 0);
 }
diff --git a/cyclone/hammer/cycle.c b/cyclone/hammer/cycle.c
index 73f3b80..5063629 100644
--- a/cyclone/hammer/cycle.c
+++ b/cyclone/hammer/cycle.c
@@ -151,5 +151,5 @@ void cycle_setup(void)
 		    gensym("set"), A_FLOAT, 0);  /* CHECKED: arg required */
     class_addmethod(cycle_class, (t_method)cycle_thresh,
 		    gensym("thresh"), A_FLOAT, 0);
-    fitter_setup(cycle_class, 0, 0);
+    fitter_setup(cycle_class, 0);
 }
diff --git a/cyclone/hammer/gate.c b/cyclone/hammer/gate.c
index 6fa2ac5..d626906 100644
--- a/cyclone/hammer/gate.c
+++ b/cyclone/hammer/gate.c
@@ -145,5 +145,5 @@ void gate_setup(void)
     class_addpointer(gate_proxy_class, gate_proxy_pointer);
     class_addlist(gate_proxy_class, gate_proxy_list);
     class_addanything(gate_proxy_class, gate_proxy_anything);
-    fitter_setup(gate_class, 0, 0);
+    fitter_setup(gate_class, 0);
 }
diff --git a/cyclone/hammer/hammer.c b/cyclone/hammer/hammer.c
index a728ec7..7e0d6e4 100644
--- a/cyclone/hammer/hammer.c
+++ b/cyclone/hammer/hammer.c
@@ -13,8 +13,6 @@ void allhammers_setup(void);
 typedef struct _hammer
 {
     t_object       x_ob;
-    t_symbol      *x_dir;
-    t_symbol      *x_canvasdir;
     t_hammerfile  *x_filehandle;
 } t_hammer;
 
@@ -24,39 +22,43 @@ static int hammer_lastndx;
 
 static void hammer_readhook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
 {
-    import_max(fn->s_name, "");
+    int result = import_max(fn->s_name, "");
+    outlet_float(((t_object *)z)->ob_outlet, (t_float)result);
 }
 
-static void hammer_doimport(t_hammer *x, t_symbol *fn, t_symbol *dir)
+static void hammer_doimport(t_hammer *x, t_symbol *fn)
 {
-    if (!dir || dir == &s_)
-	dir = x->x_dir;
     if (fn && fn != &s_)
-	import_max(fn->s_name, (dir && dir != &s_) ? dir->s_name : "");
-    else
-	hammerpanel_open(x->x_filehandle, dir);
+    {
+	t_symbol *dir = hammerpanel_getopendir(x->x_filehandle);
+	int result =
+	    import_max(fn->s_name, (dir && dir != &s_ ? dir->s_name : ""));
+	outlet_float(((t_object *)x)->ob_outlet, (t_float)result);
+    }
+    else hammerpanel_open(x->x_filehandle, 0);
 }
 
 static void hammer_click(t_hammer *x, t_floatarg xpos, t_floatarg ypos,
 			 t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
 {
-    hammer_doimport(x, 0, 0);
+    hammer_doimport(x, 0);
 }
 
 static void hammer_import(t_hammer *x, t_symbol *fn)
 {
-    hammer_doimport(x, fn, 0);
+    hammer_doimport(x, fn);
 }
 
 static void hammer_cd(t_hammer *x, t_symbol *dir)
 {
-    /* LATER hammerfile interface for relative jumps, etc. */
-    x->x_dir = (dir && dir != &s_ ? dir : x->x_canvasdir);
+    hammerpanel_setopendir(x->x_filehandle, dir);
 }
 
-static void hammer_pwd(t_hammer *x)
+static void hammer_pwd(t_hammer *x, t_symbol *s)
 {
-    outlet_symbol(((t_object *)x)->ob_outlet, x->x_dir);
+    t_symbol *dir;
+    if (s && s->s_thing && (dir = hammerpanel_getopendir(x->x_filehandle)))
+	pd_symbol(s->s_thing, dir);
 }
 
 static void hammer_bang(t_hammer *x)
@@ -74,9 +76,7 @@ static void *hammer_new(void)
 {
     t_hammer *x = (t_hammer *)pd_new(hammer_class);
     x->x_filehandle = hammerfile_new((t_pd *)x, 0, hammer_readhook, 0, 0);
-    x->x_canvasdir = canvas_getdir(x->x_filehandle->f_canvas);
-    x->x_dir = x->x_canvasdir;
-    outlet_new((t_object *)x, &s_symbol);
+    outlet_new((t_object *)x, &s_float);
     return (x);
 }
 
@@ -106,7 +106,7 @@ void hammer_setup(void)
     class_addmethod(hammer_class, (t_method)hammer_cd,
 		    gensym("cd"), A_DEFSYM, 0);
     class_addmethod(hammer_class, (t_method)hammer_pwd,
-		    gensym("pwd"), 0);
+		    gensym("pwd"), A_SYMBOL, 0);
     class_addmethod(hammer_class, (t_method)hammer_import,
 		    gensym("import"), A_DEFSYM, 0);
     class_addmethod(hammer_class, (t_method)hammer_click,
diff --git a/cyclone/hammer/maximum.c b/cyclone/hammer/maximum.c
index 5f49765..42ab22d 100644
--- a/cyclone/hammer/maximum.c
+++ b/cyclone/hammer/maximum.c
@@ -89,5 +89,5 @@ void maximum_setup(void)
     class_addbang(maximum_class, maximum_bang);
     class_addfloat(maximum_class, maximum_float);
     class_addlist(maximum_class, maximum_list);
-    fitter_setup(maximum_class, 0, 0);
+    fitter_setup(maximum_class, 0);
 }
diff --git a/cyclone/hammer/minimum.c b/cyclone/hammer/minimum.c
index a1124a5..c679799 100644
--- a/cyclone/hammer/minimum.c
+++ b/cyclone/hammer/minimum.c
@@ -89,5 +89,5 @@ void minimum_setup(void)
     class_addbang(minimum_class, minimum_bang);
     class_addfloat(minimum_class, minimum_float);
     class_addlist(minimum_class, minimum_list);
-    fitter_setup(minimum_class, 0, 0);
+    fitter_setup(minimum_class, 0);
 }
diff --git a/cyclone/hammer/mtr.c b/cyclone/hammer/mtr.c
index cf9927f..15dc5f6 100644
--- a/cyclone/hammer/mtr.c
+++ b/cyclone/hammer/mtr.c
@@ -860,5 +860,5 @@ void mtr_setup(void)
 		    gensym("debug"), 0);
 #endif
     hammerfile_setup(mtr_class, 0);
-    fitter_setup(mtr_class, 0, 0);
+    fitter_setup(mtr_class, 0);
 }
diff --git a/cyclone/hammer/past.c b/cyclone/hammer/past.c
index 553ccfa..2ed2193 100644
--- a/cyclone/hammer/past.c
+++ b/cyclone/hammer/past.c
@@ -152,5 +152,5 @@ void past_setup(void)
     class_addlist(past_class, past_list);
     class_addmethod(past_class, (t_method)past_clear, gensym("clear"), 0);
     class_addmethod(past_class, (t_method)past_set, gensym("set"), A_GIMME, 0);
-    fitter_setup(past_class, 0, 0);
+    fitter_setup(past_class, 0);
 }
diff --git a/cyclone/hammer/prepend.c b/cyclone/hammer/prepend.c
index 2dbe7be..b305f2f 100644
--- a/cyclone/hammer/prepend.c
+++ b/cyclone/hammer/prepend.c
@@ -34,8 +34,7 @@ typedef struct _prependxy
 static t_class *prepend_class;
 static t_class *prependxy_class;
 
-static t_symbol *prependps_compatibility = 0;
-static t_symbol *prependps_max;
+static int prepend_iscompatible = 0;  /* FIXME per-object */
 
 /* Usually a preallocation method is used, except in special cases of:
    1) reentrant output request, or 2) an output request which would cause
@@ -153,7 +152,7 @@ static void prepend_bang(t_prepend *x)
 {
     if (x->x_selector)
     {
-	if (prependps_compatibility == prependps_max)
+	if (prepend_iscompatible)
 	{
 	    t_atom at;
 	    SETSYMBOL(&at, &s_bang);  /* CHECKED */
@@ -324,7 +323,7 @@ static void *prepend_new(t_symbol *s, int ac, t_atom *av)
     }
     else
     {
-	if (prependps_compatibility == prependps_max)
+	if (prepend_iscompatible)
 	    /* CHECKED in max an object without an outlet is created,
 	       and there is no warning when loading from a file. */
 	    fittermax_warning(prepend_class,
@@ -337,6 +336,11 @@ static void *prepend_new(t_symbol *s, int ac, t_atom *av)
     return (x);
 }
 
+static void prepend_fitter(void)
+{
+    prepend_iscompatible = fittermax_get();
+}
+
 void prepend_setup(void)
 {
     prepend_class = class_new(gensym("prepend"),
@@ -360,6 +364,5 @@ void prepend_setup(void)
     class_addlist(prependxy_class, prependxy_list);
     class_addanything(prependxy_class, prependxy_anything);
 
-    prependps_max = gensym("max");
-    fitter_setup(prepend_class, &prependps_compatibility, 0);
+    fitter_setup(prepend_class, prepend_fitter);
 }
diff --git a/cyclone/hammer/prob.c b/cyclone/hammer/prob.c
index 8772d83..2794858 100644
--- a/cyclone/hammer/prob.c
+++ b/cyclone/hammer/prob.c
@@ -307,5 +307,5 @@ void prob_setup(void)
 		    gensym("click"),
 		    A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
     hammerfile_setup(prob_class, 1);
-    fitter_setup(prob_class, 0, 0);
+    fitter_setup(prob_class, 0);
 }
diff --git a/cyclone/hammer/seq.c b/cyclone/hammer/seq.c
index 97fd733..030a7ab 100644
--- a/cyclone/hammer/seq.c
+++ b/cyclone/hammer/seq.c
@@ -49,6 +49,7 @@ typedef struct _seq
     t_hammerfile  *x_filehandle;
     int            x_mode;
     int            x_playhead;
+    double         x_nextscoretime;
     float          x_timescale;
     float          x_newtimescale;
     double         x_prevtime;
@@ -248,6 +249,7 @@ static void seq_stopplayback(t_seq *x)
     /* CHECKED bang not sent if playback stopped early */
     clock_unset(x->x_clock);
     x->x_playhead = 0;
+    x->x_nextscoretime = 0.;
 }
 
 static void seq_stopslavery(t_seq *x)
@@ -256,6 +258,7 @@ static void seq_stopslavery(t_seq *x)
     clock_unset(x->x_clock);
     clock_unset(x->x_slaveclock);
     x->x_playhead = 0;
+    x->x_nextscoretime = 0.;
 }
 
 static void seq_startrecording(t_seq *x, int modechanged)
@@ -275,21 +278,22 @@ static void seq_startplayback(t_seq *x, int modechanged)
 	if (modechanged)
 	{
 	    x->x_playhead = 0;
+	    x->x_nextscoretime = x->x_sequence->e_delta;
 	    /* playback data never sent within the scheduler event of
 	       a start message (even for the first delta <= 0), LATER rethink */
 	    x->x_clockdelay = x->x_sequence->e_delta * x->x_newtimescale;
 	}
 	else
-	{
-	    /* CHECKED timescale change */
-	    x->x_clockdelay -= clock_gettimesince(x->x_prevtime);
+	{  /* CHECKED timescale change */
+	    if (x->x_prevtime > 0.)  /* running state */
+		x->x_clockdelay -= clock_gettimesince(x->x_prevtime);
 	    x->x_clockdelay *= x->x_newtimescale / x->x_timescale;
 	}
 	if (x->x_clockdelay < 0.)
 	    x->x_clockdelay = 0.;
+	x->x_timescale = x->x_newtimescale;
 	clock_delay(x->x_clock, x->x_clockdelay);
 	x->x_prevtime = clock_getlogicaltime();
-	x->x_timescale = x->x_newtimescale;
     }
     else x->x_mode = SEQ_IDLEMODE;
 }
@@ -299,6 +303,7 @@ static void seq_startslavery(t_seq *x, int modechanged)
     if (x->x_nevents)
     {
 	x->x_playhead = 0;
+	x->x_nextscoretime = 0.;
 	x->x_prevtime = 0.;
 	x->x_slaveprevtime = 0.;
     }
@@ -380,6 +385,7 @@ nextevent:
 	if (x->x_playhead < x->x_nevents)
 	{
 	    ep++;
+	    x->x_nextscoretime += ep->e_delta;
 	    if (ep->e_delta < SEQ_TICKEPSILON)
 		/* continue output in the same scheduler event, LATER rethink */
 	    {
@@ -556,7 +562,8 @@ static void seq_pause(t_seq *x)
 	fittermax_warning(*(t_pd *)x, "'pause' not supported in Max");
 	warned = 1;
     }
-    if (x->x_mode == SEQ_PLAYMODE && x->x_prevtime > 0.)
+    if (x->x_mode == SEQ_PLAYMODE &&
+	x->x_prevtime > 0.)  /* running state */
     {
 	x->x_clockdelay -= clock_gettimesince(x->x_prevtime);
 	if (x->x_clockdelay < 0.)
@@ -574,7 +581,8 @@ static void seq_continue(t_seq *x)
 	fittermax_warning(*(t_pd *)x, "'continue' not supported in Max");
 	warned = 1;
     }
-    if (x->x_mode == SEQ_PLAYMODE)
+    if (x->x_mode == SEQ_PLAYMODE &&
+	x->x_prevtime <= 0.)  /* pause state */
     {
 	if (x->x_clockdelay < 0.)
 	    x->x_clockdelay = 0.;
@@ -591,30 +599,91 @@ static void seq_goto(t_seq *x, t_floatarg f1, t_floatarg f2)
 	fittermax_warning(*(t_pd *)x, "'goto' not supported in Max");
 	warned = 1;
     }
-    if (x->x_nevents && x->x_mode == SEQ_PLAYMODE)
+    if (x->x_nevents)
     {
 	t_seqevent *ev;
 	int ndx, nevents = x->x_nevents;
 	double ms = f1 * 1000. + f2, sum;
 	if (ms < SEQ_TICKEPSILON)
 	    ms = 0.;
+	if (x->x_mode != SEQ_PLAYMODE)
+	{
+	    seq_settimescale(x, x->x_timescale);
+	    seq_setmode(x, SEQ_PLAYMODE);
+	    /* clock_delay() has been called in setmode, LATER avoid */
+	    clock_unset(x->x_clock);
+	    x->x_prevtime = 0.;
+	}
 	for (ndx = 0, ev = x->x_sequence, sum = SEQ_TICKEPSILON; ndx < nevents;
 	     ndx++, ev++)
 	{
 	    if ((sum += ev->e_delta) >= ms)
 	    {
 		x->x_playhead = ndx;
+		x->x_nextscoretime = sum;
 		x->x_clockdelay = sum - SEQ_TICKEPSILON - ms;
 		if (x->x_clockdelay < 0.)
 		    x->x_clockdelay = 0.;
-		clock_delay(x->x_clock, x->x_clockdelay);
-		x->x_prevtime = clock_getlogicaltime();
+		if (x->x_prevtime > 0.)  /* running state */
+		{
+		    clock_delay(x->x_clock, x->x_clockdelay);
+		    x->x_prevtime = clock_getlogicaltime();
+		}
 		break;
 	    }
 	}
     }
 }
 
+static void seq_scoretime(t_seq *x, t_symbol *s)
+{
+    static int warned = 0;
+    if (fittermax_get() && !warned)
+    {
+	fittermax_warning(*(t_pd *)x, "'scoretime' not supported in Max");
+	warned = 1;
+    }
+    if (s && s->s_thing &&
+	x->x_mode == SEQ_PLAYMODE)  /* LATER other modes */
+    {
+	t_atom aout[2];
+	double ms, clockdelay = x->x_clockdelay;
+	t_float f1, f2;
+	if (x->x_prevtime > 0.)  /* running state */
+	    clockdelay -= clock_gettimesince(x->x_prevtime);
+	ms = x->x_nextscoretime - clockdelay / x->x_timescale;
+	f1 = ms / 1000.;
+	f2 = ms - f1;
+	SETFLOAT(&aout[0], f1);
+	SETFLOAT(&aout[1], f2);
+	pd_list(s->s_thing, &s_list, 2, aout);
+    }
+}
+
+static void seq_cd(t_seq *x, t_symbol *s)
+{
+    static int warned = 0;
+    if (fittermax_get() && !warned)
+    {
+	fittermax_warning(*(t_pd *)x, "'cd' not supported in Max");
+	warned = 1;
+    }
+    hammerpanel_setopendir(x->x_filehandle, s);
+}
+
+static void seq_pwd(t_seq *x, t_symbol *s)
+{
+    t_symbol *dir;
+    static int warned = 0;
+    if (fittermax_get() && !warned)
+    {
+	fittermax_warning(*(t_pd *)x, "'pwd' not supported in Max");
+	warned = 1;
+    }
+    if (s && s->s_thing && (dir = hammerpanel_getopendir(x->x_filehandle)))
+	pd_symbol(s->s_thing, dir);
+}
+
 static int seq_eventcomparehook(const void *e1, const void *e2)
 {
     return (((t_seqevent *)e1)->e_delta > ((t_seqevent *)e2)->e_delta ? 1 : -1);
@@ -963,7 +1032,8 @@ static void seq_read(t_seq *x, t_symbol *s)
 {
     if (s && s != &s_)
 	seq_doread(x, s, 0);
-    else  /* CHECKED no default */
+    else  /* CHECKED no default file name */
+	/* start in a dir last read from, if any, otherwise in a canvas dir */
 	hammerpanel_open(x->x_filehandle, 0);
 }
 
@@ -971,8 +1041,9 @@ static void seq_write(t_seq *x, t_symbol *s)
 {
     if (s && s != &s_)
 	seq_dowrite(x, s);
-    else  /* CHECKED creation arg is a default */
+    else  /* CHECKED creation arg is a default file name */
 	hammerpanel_save(x->x_filehandle,
+			 /* always start in canvas dir */
 			 canvas_getdir(x->x_canvas), x->x_defname);
 }
 
@@ -1123,8 +1194,14 @@ void seq_setup(void)
 		    gensym("continue"), 0);
     class_addmethod(seq_class, (t_method)seq_goto,
 		    gensym("goto"), A_DEFFLOAT, A_DEFFLOAT, 0);
+    class_addmethod(seq_class, (t_method)seq_scoretime,
+		    gensym("scoretime"), A_SYMBOL, 0);
+    class_addmethod(seq_class, (t_method)seq_cd,
+		    gensym("cd"), A_DEFSYM, 0);
+    class_addmethod(seq_class, (t_method)seq_pwd,
+		    gensym("pwd"), A_SYMBOL, 0);
 
     forky_setpropertiesfn(seq_class, seq_properties);
     hammerfile_setup(seq_class, 0);
-    fitter_setup(seq_class, 0, 0);
+    fitter_setup(seq_class, 0);
 }
diff --git a/cyclone/hammer/switch.c b/cyclone/hammer/switch.c
index ce985de..2a6846e 100644
--- a/cyclone/hammer/switch.c
+++ b/cyclone/hammer/switch.c
@@ -150,5 +150,5 @@ void switch_setup(void)
     class_addpointer(switch_proxy_class, switch_proxy_pointer);
     class_addlist(switch_proxy_class, switch_proxy_list);
     class_addanything(switch_proxy_class, switch_proxy_anything);
-    fitter_setup(switch_class, 0, 0);
+    fitter_setup(switch_class, 0);
 }
diff --git a/cyclone/hammer/urn.c b/cyclone/hammer/urn.c
index b02d891..a3ee8ae 100644
--- a/cyclone/hammer/urn.c
+++ b/cyclone/hammer/urn.c
@@ -146,5 +146,5 @@ void urn_setup(void)
 		    gensym("seed"), A_FLOAT, 0);  /* CHECKED arg obligatory */
     class_addmethod(urn_class, (t_method)urn_clear,
 		    gensym("clear"), 0);
-    fitter_setup(urn_class, 0, 0);
+    fitter_setup(urn_class, 0);
 }
diff --git a/cyclone/notes.txt b/cyclone/notes.txt
new file mode 100644
index 0000000..6f83d33
--- /dev/null
+++ b/cyclone/notes.txt
@@ -0,0 +1,40 @@
+TODO for cyclone
+  * using maxmode object arguments for abstraction-scoped, selective
+    compatibility control
+  * comment behaving better in windows (or is it gatom's fault?)
+
+DONE for cyclone
+
+alpha52
+  * compatibility mode interface in maxmode object:
+    messages 'set', 'get' (reply through the second outlet)
+  * better handling of initial directory in open panels
+  * relative path handling in 'cd' (library objects, seq, more to come)
+  * remote reply to 'pwd' message of library objects (target argument required)
+  * instead, left outlet of library objects sends return code from import
+    (negative value indicates an error)
+  * new class: matrix~
+  * linedrive: more compatible in maxmode, bipolar otherwise
+  * seq:
+    . paused state fixes (state preserved in 'goto', proper delay in 'start')
+    . 'goto' fix (works in idlemode)
+    . more incompatible messages: 'scoretime', 'cd', 'pwd'
+
+alpha51
+  * dummies loaded by maxmode, not cyclone
+  * setting directory in creation argument replaced with 'cd' message
+    to library objects (cyclone, maxmode, hammer and sickle)
+  * 'pwd' message to library objects sends directory symbol to an outlet
+  * creating cyclone and maxmode library objects possible without
+    loading component libraries
+  * prepend and Append:
+    . bang handling, controlled by maxmode
+    . restored max-like 'set' handling as default for objects with arguments
+  * fix for parsing creation arguments in svf~
+  * incompatible additions to seq: 'pause', 'continue', 'goto'
+
+alpha50
+  * max-compatibility mode switch for cyclone
+    . turned on by loading cyclone libs through "-lib maxmode"
+    . affects max-compatibility of prepend and Append, controls
+      compatibility warnings
diff --git a/cyclone/shadow/Makefile.objects b/cyclone/shadow/Makefile.objects
index 66aea0d..1ddea9c 100644
--- a/cyclone/shadow/Makefile.objects
+++ b/cyclone/shadow/Makefile.objects
@@ -1,6 +1,7 @@
 SHARED_OBJECTS = \
 common/loud.o \
 common/grow.o \
+common/os.o \
 common/fitter.o \
 common/lex.o \
 common/binport.o \
diff --git a/cyclone/shadow/cyclone.c b/cyclone/shadow/cyclone.c
index 30f1c84..cb051b6 100644
--- a/cyclone/shadow/cyclone.c
+++ b/cyclone/shadow/cyclone.c
@@ -19,8 +19,6 @@
 typedef struct _cyclone
 {
     t_object       x_ob;
-    t_symbol      *x_dir;
-    t_symbol      *x_canvasdir;
     t_hammerfile  *x_filehandle;
 } t_cyclone;
 
@@ -32,39 +30,43 @@ static int cyclone_lastndx;
 
 static void cyclone_readhook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
 {
-    import_max(fn->s_name, "");
+    int result = import_max(fn->s_name, "");
+    outlet_float(((t_object *)z)->ob_outlet, (t_float)result);
 }
 
-static void cyclone_doimport(t_cyclone *x, t_symbol *fn, t_symbol *dir)
+static void cyclone_doimport(t_cyclone *x, t_symbol *fn)
 {
-    if (!dir || dir == &s_)
-	dir = x->x_dir;
     if (fn && fn != &s_)
-	import_max(fn->s_name, (dir && dir != &s_) ? dir->s_name : "");
-    else
-	hammerpanel_open(x->x_filehandle, dir);
+    {
+	t_symbol *dir = hammerpanel_getopendir(x->x_filehandle);
+	int result =
+	    import_max(fn->s_name, (dir && dir != &s_ ? dir->s_name : ""));
+	outlet_float(((t_object *)x)->ob_outlet, (t_float)result);
+    }
+    else hammerpanel_open(x->x_filehandle, 0);
 }
 
 static void cyclone_click(t_cyclone *x, t_floatarg xpos, t_floatarg ypos,
 			  t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
 {
-    cyclone_doimport(x, 0, 0);
+    cyclone_doimport(x, 0);
 }
 
 static void cyclone_import(t_cyclone *x, t_symbol *fn)
 {
-    cyclone_doimport(x, fn, 0);
+    cyclone_doimport(x, fn);
 }
 
 static void cyclone_cd(t_cyclone *x, t_symbol *dir)
 {
-    /* LATER hammerfile interface for relative jumps, etc. */
-    x->x_dir = (dir && dir != &s_ ? dir : x->x_canvasdir);
+    hammerpanel_setopendir(x->x_filehandle, dir);
 }
 
-static void cyclone_pwd(t_cyclone *x)
+static void cyclone_pwd(t_cyclone *x, t_symbol *s)
 {
-    outlet_symbol(((t_object *)x)->ob_outlet, x->x_dir);
+    t_symbol *dir;
+    if (s && s->s_thing && (dir = hammerpanel_getopendir(x->x_filehandle)))
+	pd_symbol(s->s_thing, dir);
 }
 
 static void cyclone_bang(t_cyclone *x)
@@ -89,9 +91,7 @@ static void *cyclone_new(void)
 {
     t_cyclone *x = (t_cyclone *)pd_new(cyclone_class);
     x->x_filehandle = hammerfile_new((t_pd *)x, 0, cyclone_readhook, 0, 0);
-    x->x_canvasdir = canvas_getdir(x->x_filehandle->f_canvas);
-    x->x_dir = x->x_canvasdir;
-    outlet_new((t_object *)x, &s_symbol);
+    outlet_new((t_object *)x, &s_float);
     return (x);
 }
 
@@ -114,7 +114,7 @@ void cyclone_setup(void)
     class_addmethod(cyclone_class, (t_method)cyclone_cd,
 		    gensym("cd"), A_DEFSYM, 0);
     class_addmethod(cyclone_class, (t_method)cyclone_pwd,
-		    gensym("pwd"), 0);
+		    gensym("pwd"), A_SYMBOL, 0);
     class_addmethod(cyclone_class, (t_method)cyclone_import,
 		    gensym("import"), A_DEFSYM, 0);
     class_addmethod(cyclone_class, (t_method)cyclone_click,
diff --git a/cyclone/shadow/dummies.c b/cyclone/shadow/dummies.c
index 5ad7cc1..f55c683 100644
--- a/cyclone/shadow/dummies.c
+++ b/cyclone/shadow/dummies.c
@@ -148,6 +148,7 @@ static void *dummy_if_new(t_symbol *s, int ac, t_atom *av)
     return (x);
 }
 
+#if 0
 static void *dummy_matrix_tilde_new(t_symbol *s, int ac, t_atom *av)
 {
     t_dummy_slot *sl;
@@ -168,6 +169,7 @@ static void *dummy_matrix_tilde_new(t_symbol *s, int ac, t_atom *av)
     dummy_io(x, nins, nouts + 1);  /* CHECKME */
     return (x);
 }
+#endif
 
 static void *dummy_rewire_tilde_new(t_symbol *s, int ac, t_atom *av)
 {
@@ -406,7 +408,9 @@ static t_dummy_slot dummy_slots[] =
     { "lcd",             1, 4, 0, 0 },  /* CHECKME nouts */
     { "led",             1, 1, 0, 0 },
     { "matrixctrl",      1, 1, 0, 0 },  /* CHECKME nins, nouts */
+#if 0
     { "matrix~",        -1, -1, 0, (t_newmethod)dummy_matrix_tilde_new },
+#endif
     { "menubar",         1, 4, 0, 0 },  /* LATER parse #Xs (additional outs) */
     { "meter~",          1, 1, 0, 0 },  /* LATER consider mapping to the vu */
     { "movie",           1, 3, 0, 0 },
diff --git a/cyclone/shadow/maxmode.c b/cyclone/shadow/maxmode.c
index 9cd1055..189c83e 100644
--- a/cyclone/shadow/maxmode.c
+++ b/cyclone/shadow/maxmode.c
@@ -16,9 +16,8 @@
 typedef struct _maxmode
 {
     t_object       x_ob;
-    t_symbol      *x_dir;
-    t_symbol      *x_canvasdir;
     t_hammerfile  *x_filehandle;
+    t_outlet      *x_modeout;
 } t_maxmode;
 
 static t_class *maxmode_class;
@@ -29,39 +28,59 @@ static int maxmode_withbanner = 0;
 
 static void maxmode_readhook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
 {
-    import_max(fn->s_name, "");
+    int result = import_max(fn->s_name, "");
+    outlet_float(((t_object *)z)->ob_outlet, (t_float)result);
 }
 
-static void maxmode_doimport(t_maxmode *x, t_symbol *fn, t_symbol *dir)
+static void maxmode_doimport(t_maxmode *x, t_symbol *fn)
 {
-    if (!dir || dir == &s_)
-	dir = x->x_dir;
     if (fn && fn != &s_)
-	import_max(fn->s_name, (dir && dir != &s_) ? dir->s_name : "");
-    else
-	hammerpanel_open(x->x_filehandle, dir);
+    {
+	t_symbol *dir = hammerpanel_getopendir(x->x_filehandle);
+	int result =
+	    import_max(fn->s_name, (dir && dir != &s_ ? dir->s_name : ""));
+	outlet_float(((t_object *)x)->ob_outlet, (t_float)result);
+    }
+    else hammerpanel_open(x->x_filehandle, 0);
+
 }
 
 static void maxmode_click(t_maxmode *x, t_floatarg xpos, t_floatarg ypos,
 			  t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
 {
-    maxmode_doimport(x, 0, 0);
+    maxmode_doimport(x, 0);
 }
 
 static void maxmode_import(t_maxmode *x, t_symbol *fn)
 {
-    maxmode_doimport(x, fn, 0);
+    maxmode_doimport(x, fn);
 }
 
 static void maxmode_cd(t_maxmode *x, t_symbol *dir)
 {
-    /* LATER hammerfile interface for relative jumps, etc. */
-    x->x_dir = (dir && dir != &s_ ? dir : x->x_canvasdir);
+    hammerpanel_setopendir(x->x_filehandle, dir);
 }
 
-static void maxmode_pwd(t_maxmode *x)
+static void maxmode_pwd(t_maxmode *x, t_symbol *s)
 {
-    outlet_symbol(((t_object *)x)->ob_outlet, x->x_dir);
+    t_symbol *dir;
+    if (s && s->s_thing && (dir = hammerpanel_getopendir(x->x_filehandle)))
+	pd_symbol(s->s_thing, dir);
+}
+
+static void maxmode_set(t_maxmode *x, t_symbol *s)
+{
+    if (!s || s == &s_)
+	s = gensym("none");
+    if (s != fitter_getmode())
+	fitter_setmode(s);
+}
+
+static void maxmode_get(t_maxmode *x)
+{
+    t_symbol *mode;
+    if (mode = fitter_getmode())
+	outlet_symbol(x->x_modeout, mode);
 }
 
 static void maxmode_bang(t_maxmode *x)
@@ -79,12 +98,14 @@ static void maxmode_bang(t_maxmode *x)
 
 static void maxmode_free(t_maxmode *x)
 {
+    /* FIXME cancel registration */
     hammerfile_free(x->x_filehandle);
 }
 
 static void *maxmode_new(t_symbol *s, int ac, t_atom *av)
 {
     t_maxmode *x = (t_maxmode *)pd_new(maxmode_class);
+    int selective = ac;
     if (maxmode_withbanner && !ac)
     {
 	post("this is maxmode %s, %s %s build",
@@ -93,25 +114,22 @@ static void *maxmode_new(t_symbol *s, int ac, t_atom *av)
  "creating maxmode object without loading cyclone components");
 	maxmode_withbanner = 0;
     }
-    if (!fittermax_get())
+    if (selective)
     {
-	int selective = 0;
-	if (ac)
+	/* a numeric argument is valid -- transparent object is created
+	   (global mode is not set, nothing is registered) */
+	while (ac--) if (av->a_type == A_SYMBOL)
 	{
-	    while (ac--) if (av->a_type == A_SYMBOL)
-	    {
-		/* FIXME register into fitter for per-patch, selective
-		   compatibility control */
-		av++;
-	    }
+	    /* FIXME register into fitter for per-patch-file, selective
+	       compatibility control */
+	    av++;
 	}
-	if (!selective)
-	    fittermax_set();
     }
+    else if (!fittermax_get())
+	fittermax_set();
     x->x_filehandle = hammerfile_new((t_pd *)x, 0, maxmode_readhook, 0, 0);
-    x->x_canvasdir = canvas_getdir(x->x_filehandle->f_canvas);
-    x->x_dir = x->x_canvasdir;
-    outlet_new((t_object *)x, &s_symbol);
+    outlet_new((t_object *)x, &s_float);
+    x->x_modeout = outlet_new((t_object *)x, &s_symbol);
     return (x);
 }
 
@@ -128,10 +146,14 @@ void maxmode_setup(void)
 			      (t_method)maxmode_free,
 			      sizeof(t_maxmode), 0, A_GIMME, 0);
     class_addbang(maxmode_class, maxmode_bang);
+    class_addmethod(maxmode_class, (t_method)maxmode_set,
+		    gensym("set"), A_DEFSYM, 0);
+    class_addmethod(maxmode_class, (t_method)maxmode_get,
+		    gensym("get"), 0);
     class_addmethod(maxmode_class, (t_method)maxmode_cd,
 		    gensym("cd"), A_DEFSYM, 0);
     class_addmethod(maxmode_class, (t_method)maxmode_pwd,
-		    gensym("pwd"), 0);
+		    gensym("pwd"), A_SYMBOL, 0);
     class_addmethod(maxmode_class, (t_method)maxmode_import,
 		    gensym("import"), A_DEFSYM, 0);
     class_addmethod(maxmode_class, (t_method)maxmode_click,
@@ -141,7 +163,7 @@ void maxmode_setup(void)
 
     if (canvas_getcurrent())
     {
-	fitter_setup(0, 0, 0);
+	fitter_setup(0, 0);
 	if (!zgetfn(&pd_objectmaker, gensym("cyclone")))
 	    /* cycloneless maxmode -- banner is posted by the oldest
 	       maxmode object with no creation arguments */
diff --git a/cyclone/sickle/Makefile.objects b/cyclone/sickle/Makefile.objects
index 1d80296..e85d2c9 100644
--- a/cyclone/sickle/Makefile.objects
+++ b/cyclone/sickle/Makefile.objects
@@ -4,6 +4,7 @@ unstable/fragile.o \
 unstable/fringe.o \
 common/loud.o \
 common/grow.o \
+common/os.o \
 common/fitter.o \
 common/vefl.o \
 common/clc.o \
diff --git a/cyclone/sickle/Makefile.sources b/cyclone/sickle/Makefile.sources
index 901be5b..c66b33e 100644
--- a/cyclone/sickle/Makefile.sources
+++ b/cyclone/sickle/Makefile.sources
@@ -44,6 +44,7 @@ linedrive.c \
 log.c \
 lookup.c \
 lores.c \
+matrix.c \
 maximum.c \
 minimum.c \
 minmax.c \
diff --git a/cyclone/sickle/Scope.c b/cyclone/sickle/Scope.c
index 8a71cb5..4668afe 100644
--- a/cyclone/sickle/Scope.c
+++ b/cyclone/sickle/Scope.c
@@ -1051,5 +1051,5 @@ void Scope_tilde_setup(void)
 		    gensym("_click"), A_FLOAT, 0);
     class_addmethod(scopehandle_class, (t_method)scopehandle__motionhook,
 		    gensym("_motion"), A_FLOAT, A_FLOAT, 0);
-    fitter_setup(scope_class, 0, 0);
+    fitter_setup(scope_class, 0);
 }
diff --git a/cyclone/sickle/allsickles.c b/cyclone/sickle/allsickles.c
index 7771cf8..b8432d5 100644
--- a/cyclone/sickle/allsickles.c
+++ b/cyclone/sickle/allsickles.c
@@ -1,6 +1,6 @@
 // Do not edit this file, run "make" instead.
 
-/* Copyright (c) 2002-2003 krzYszcz and others.
+/* Copyright (c) 2002-2004 krzYszcz and others.
  * For information on usage and redistribution, and for a DISCLAIMER OF ALL
  * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
 
@@ -45,6 +45,7 @@ void linedrive_setup(void);
 void log_tilde_setup(void);
 void lookup_tilde_setup(void);
 void lores_tilde_setup(void);
+void matrix_tilde_setup(void);
 void maximum_tilde_setup(void);
 void minimum_tilde_setup(void);
 void minmax_tilde_setup(void);
@@ -124,6 +125,7 @@ void allsickles_setup(void)
     log_tilde_setup();
     lookup_tilde_setup();
     lores_tilde_setup();
+    matrix_tilde_setup();
     maximum_tilde_setup();
     minimum_tilde_setup();
     minmax_tilde_setup();
diff --git a/cyclone/sickle/buffir.c b/cyclone/sickle/buffir.c
index 1fd9d23..13eee79 100644
--- a/cyclone/sickle/buffir.c
+++ b/cyclone/sickle/buffir.c
@@ -211,5 +211,5 @@ void buffir_tilde_setup(void)
 		    gensym("clear"), 0);
     class_addmethod(buffir_class, (t_method)buffir_set,
 		    gensym("set"), A_SYMBOL, A_DEFFLOAT, A_DEFFLOAT, 0);
-    fitter_setup(buffir_class, 0, 0);
+    fitter_setup(buffir_class, 0);
 }
diff --git a/cyclone/sickle/linedrive.c b/cyclone/sickle/linedrive.c
index 8b133ab..99c3720 100644
--- a/cyclone/sickle/linedrive.c
+++ b/cyclone/sickle/linedrive.c
@@ -1,67 +1,134 @@
-/* Copyright (c) 2002-2003 krzYszcz and others.
+/* Copyright (c) 2002-2005 krzYszcz and others.
  * For information on usage and redistribution, and for a DISCLAIMER OF ALL
  * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
 
-/* CHECKME polarity */
-
 #include <math.h>
 #include "m_pd.h"
+#include "common/fitter.h"
 
 #if defined(NT) || defined(MACOSX)
 #define logf  log
 #define expf  exp
 #endif
 
-static t_class *linedrive_class;
+#define LINEDRIVE_MININPUT   .5  /* CHECKED */
+#define LINEDRIVE_MINCURVE  1.   /* CHECKED */
+
+#define LINEDRIVE_INPUTEPSILON  1e-19f
+#define LINEDRIVE_CURVEEPSILON  1e-19f
 
 typedef struct _linedrive
 {
     t_object  x_ob;
+    t_float   x_usermaxin;
+    t_float   x_usermaxout;
+    t_float   x_usercurve;
     t_float   x_maxin;
     t_float   x_maxout;
     t_float   x_expcoef;
     t_float   x_lincoef;
-    t_atom    x_vec[2];
-    int       x_linear;
+    int       x_islinear;
+    int       x_iscompatible;
+    t_atom    x_outvec[2];
 } t_linedrive;
 
+static t_class *linedrive_class;
+
 static void linedrive_float(t_linedrive *x, t_floatarg f)
 {
-    float outval = f - x->x_maxin;
-    if (outval >= 0)
-	outval = x->x_maxout;  /* CHECKED */
-    else if (x->x_linear)
-	outval = x->x_maxout + outval * x->x_lincoef;
+    t_float outval;
+    if (x->x_iscompatible)
+    {
+	if (f < LINEDRIVE_MININPUT)  /* CHECKED */
+	    outval = 0.;
+	else if (f >= x->x_maxin)  /* CHECKED */
+	    outval = x->x_maxin;
+	else
+	    outval = expf((f - x->x_maxin) * x->x_expcoef) * x->x_maxout;
+    }
     else
-	outval = expf(outval * x->x_expcoef) * x->x_maxout;
-    SETFLOAT(x->x_vec, outval);
-    outlet_list(((t_object *)x)->ob_outlet, 0, 2, x->x_vec);
+    {
+	if (x->x_islinear)
+	    outval = x->x_maxout + (f - x->x_maxin) * x->x_lincoef;
+	else if (f < -LINEDRIVE_INPUTEPSILON)
+	    outval = -expf((-f - x->x_maxin) * x->x_expcoef) * x->x_maxout;
+	else if (f > LINEDRIVE_INPUTEPSILON)
+	    outval = expf((f - x->x_maxin) * x->x_expcoef) * x->x_maxout;
+	else
+	    outval = 0.;
+    }
+    SETFLOAT(x->x_outvec, outval);
+    outlet_list(((t_object *)x)->ob_outlet, 0, 2, x->x_outvec);
 }
 
-static void *linedrive_new(t_floatarg maxin, t_floatarg maxout,
-			   t_floatarg curve, t_floatarg deltime)
+static void linedrive_calculate(t_linedrive *x)
 {
-    t_linedrive *x = (t_linedrive *)pd_new(linedrive_class);
-    x->x_maxin = (maxin < 1.0e-20f && maxin > -1e-20f ? 0 : maxin);
-    x->x_maxout = maxout;
-    if (curve < 1.0e-20f) curve = 1.0;  /* a bug in msp? */
-    if (curve == 1.0)
+    t_float maxin = x->x_usermaxin;
+    t_float maxout = x->x_usermaxout;
+    t_float curve = x->x_usercurve;
+    if (x->x_iscompatible = fittermax_get())
     {
-	x->x_expcoef = 0;
-	x->x_lincoef = (x->x_maxin == 0 ? 0 : x->x_maxout / x->x_maxin);
-	x->x_linear = 1;
+	/* CHECKED */
+	x->x_maxin = (maxin > LINEDRIVE_MININPUT ? maxin : LINEDRIVE_MININPUT);
+	/* CHECKED */
+	x->x_expcoef = (curve > LINEDRIVE_MINCURVE ? logf(curve) : 0.);
+	x->x_lincoef = 0.;
+	x->x_islinear = 0;
     }
-    else {
-	x->x_expcoef = logf(curve);
-	x->x_lincoef = 0;
-	x->x_linear = 0;
+    else
+    {
+	if (maxin >= -LINEDRIVE_INPUTEPSILON && maxin <= LINEDRIVE_INPUTEPSILON)
+	{
+	    x->x_maxin = 0.;
+	    x->x_expcoef = 0.;
+	    x->x_lincoef = 0.;
+	    x->x_islinear = 1;
+	}
+	else if (curve >= (1. - LINEDRIVE_CURVEEPSILON) &&
+		 curve <= (1. + LINEDRIVE_CURVEEPSILON))
+	{
+	    x->x_maxin = maxin;
+	    x->x_expcoef = 0.;
+	    x->x_lincoef = maxout / maxin;
+	    x->x_islinear = 1;
+	}
+	else
+	{
+	    if (maxin < 0.)
+	    {
+		x->x_maxin = -maxin;
+		maxout = -maxout;
+	    }
+	    else x->x_maxin = maxin;
+	    if (curve < LINEDRIVE_CURVEEPSILON)
+		curve = LINEDRIVE_CURVEEPSILON;
+	    x->x_expcoef = logf(curve);
+	    x->x_lincoef = 0.;
+	    x->x_islinear = 0;
+	}
     }
-    SETFLOAT(&x->x_vec[1], deltime);  /* CHECKED: any value accepted */
-    floatinlet_new((t_object *)x, &x->x_vec[1].a_w.w_float);
+    x->x_maxout = maxout;  /* CHECKED negative value accepted and used */
+}
+
+static void *linedrive_new(t_floatarg maxin, t_floatarg maxout,
+			   t_floatarg curve, t_floatarg deltime)
+{
+    t_linedrive *x = (t_linedrive *)pd_new(linedrive_class);
+    x->x_usermaxin = maxin;
+    x->x_usermaxout = maxout;
+    x->x_usercurve = curve;
+    linedrive_calculate(x);
+    SETFLOAT(&x->x_outvec[1], deltime);  /* CHECKED any value accepted */
+    floatinlet_new((t_object *)x, &x->x_outvec[1].a_w.w_float);
     outlet_new((t_object *)x, &s_list);
     return (x);
 }
 
+static void linedrive_fitter(void)
+{
+    /* FIXME for all objects in scope do recalculate */
+}
+
 void linedrive_setup(void)
 {
     linedrive_class = class_new(gensym("linedrive"),
@@ -70,4 +137,5 @@ void linedrive_setup(void)
 				A_DEFFLOAT, A_DEFFLOAT,
 				A_DEFFLOAT, A_DEFFLOAT, 0);
     class_addfloat(linedrive_class, linedrive_float);
+    fitter_setup(linedrive_class, linedrive_fitter);
 }
diff --git a/cyclone/sickle/matrix.c b/cyclone/sickle/matrix.c
new file mode 100644
index 0000000..a0772dc
--- /dev/null
+++ b/cyclone/sickle/matrix.c
@@ -0,0 +1,563 @@
+/* Copyright (c) 2005 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
+
+#include "m_pd.h"
+#include "common/loud.h"
+#include "common/fitter.h"
+#include "unstable/fragile.h"
+#include "sickle/sic.h"
+
+#ifdef KRZYSZCZ
+#define MATRIX_DEBUG
+#endif
+
+#define MATRIX_DEFGAIN  0.  /* CHECKED */
+#define MATRIX_DEFRAMP  0.  /* CHECKED */
+
+#define MATRIX_GAINEPSILON  1e-20f
+#define MATRIX_MINRAMP      .001  /* LATER rethink */
+
+typedef struct _matrix
+{
+    t_sic      x_sic;
+    int        x_ninlets;
+    int        x_noutlets;
+    int        x_nblock;
+    int        x_maxblock;
+    t_float  **x_ivecs;
+    t_float  **x_ovecs;
+    t_float  **x_osums;
+    int        x_ncells;
+    int       *x_cells;
+    t_outlet  *x_dumpout;
+    /* The following fields are specific to nonbinary mode, i.e. we keep them
+       unallocated in binary mode.  This is CHECKED to be incompatible:  c74
+       always accepts (and reports) gains and ramps, although they are actually
+       meaningless in binary mode, and switching modes is not supported. */
+    float      x_defgain;
+    float     *x_gains;  /* target gains */
+    float      x_deframp;
+    float     *x_ramps;
+    float      x_ksr;
+    float     *x_coefs;  /* current coefs */
+    float     *x_incrs;
+    float     *x_bigincrs;
+    int       *x_remains;
+} t_matrix;
+
+typedef void (*t_matrix_cellfn)(t_matrix *x, int indx, int ondx,
+				int onoff, float gain);
+
+static t_class *matrix_class;
+static t_symbol *matrixps_matrixtilde;
+
+/* called only in nonbinary mode;  LATER deal with changing nblock/ksr */
+static void matrix_retarget(t_matrix *x, int cellndx)
+{
+    float target = (x->x_cells[cellndx] ? x->x_gains[cellndx] : 0.);
+    if (x->x_ramps[cellndx] < MATRIX_MINRAMP)
+    {
+	x->x_coefs[cellndx] = target;
+	x->x_remains[cellndx] = 0;
+    }
+    else
+    {
+    	x->x_remains[cellndx] =
+	    x->x_ramps[cellndx] * x->x_ksr + 0.5;  /* LATER rethink */
+    	x->x_incrs[cellndx] =
+	    (target - x->x_coefs[cellndx]) / (float)x->x_remains[cellndx];
+	x->x_bigincrs[cellndx] = x->x_nblock * x->x_incrs[cellndx];
+    }
+}
+
+static void matrix_float(t_matrix *x, t_float f)
+{
+    loud_nomethod((t_pd *)x, &s_float);  /* CHECKED */
+}
+
+static void matrix_list(t_matrix *x, t_symbol *s, int ac, t_atom *av)
+{
+    int indx, ondx, cellndx, onoff;
+    float gain;
+    if (ac < 3)
+	return;  /* CHECKED list silently ignored if ac < 3 */
+    /* CHECKED floats silently clipped, symbols converted to 0 */
+    indx = (av->a_type == A_FLOAT ? (int)av->a_w.w_float : 0);
+    if (indx < 0 || indx >= x->x_ninlets)
+    {  /* CHECKED */
+	loud_error((t_pd *)x, "invalid inlet number %d", indx);
+	return;
+    }
+    ac--; av++;
+    /* CHECKED floats silently clipped, symbols converted to 0 */
+    ondx = (av->a_type == A_FLOAT ? (int)av->a_w.w_float : 0);
+    if (ondx < 0 || ondx >= x->x_noutlets)
+    {  /* CHECKED */
+	loud_error((t_pd *)x, "invalid outlet number %d", ondx);
+	return;
+    }
+    cellndx = indx * x->x_noutlets + ondx;
+    ac--; av++;
+    /* CHECKED negative gain used in nonbinary mode, accepted as 1 in binary */
+    gain = (av->a_type == A_FLOAT ? av->a_w.w_float : 0.);
+    onoff = (gain < -MATRIX_GAINEPSILON || gain > MATRIX_GAINEPSILON);
+    x->x_cells[cellndx] = onoff;
+    if (x->x_gains)
+    {
+	if (onoff)  /* CHECKME */
+	    x->x_gains[cellndx] = gain;
+	ac--; av++;
+	if (ac)
+	{
+	    float ramp = (av->a_type == A_FLOAT ? av->a_w.w_float : 0.);
+	    x->x_ramps[cellndx] = (ramp < MATRIX_MINRAMP ? 0. : ramp);
+	}
+	matrix_retarget(x, cellndx);
+    }
+}
+
+static void matrix_clear(t_matrix *x)
+{
+    int i;
+    for (i = 0; i < x->x_ncells; i++)
+	x->x_cells[i] = 0;
+}
+
+/* CHECKED c74's refman and help patch are wrong about int pairs --
+   the actual syntax is "[dis]connect indx ondx1 [ondx2 [ondx3..." */
+static void matrix_connect(t_matrix *x, t_symbol *s, int ac, t_atom *av)
+{
+    int onoff = (s == gensym("connect")), indx, celloffset;
+    if (ac < 2)
+	return;  /* CHECKED */
+    /* CHECKED floats silently clipped, symbols converted to 0 */
+    indx = (av->a_type == A_FLOAT ? (int)av->a_w.w_float : 0);
+    if (indx < 0 || indx >= x->x_ninlets)
+    {  /* CHECKED */
+	loud_error((t_pd *)x, "invalid inlet number %d", indx);
+	return;
+    }
+    celloffset = indx * x->x_noutlets;
+    ac--; av++;
+    while (ac)
+    {
+	/* CHECKED floats silently clipped, symbols converted to 0 */
+	int cellndx, ondx = (av->a_type == A_FLOAT ? (int)av->a_w.w_float : 0);
+	if (ondx < 0 || ondx >= x->x_noutlets)
+	{  /* CHECKED */
+	    loud_error((t_pd *)x, "invalid outlet number %d", ondx);
+	    return;
+	}
+	cellndx = celloffset + ondx;
+	x->x_cells[cellndx] = onoff;
+	if (x->x_gains)
+	    matrix_retarget(x, cellndx);
+	ac--; av++;
+    }
+}
+
+/* CHECKED active ramps are not retargeted */
+static void matrix_ramp(t_matrix *x, t_floatarg f)
+{
+    if (x->x_ramps)
+    {
+	int i;
+	x->x_deframp = (f < MATRIX_MINRAMP ? 0. : f);
+	/* CHECKED cell-specific ramps are lost */
+	for (i = 0; i < x->x_ncells; i++)
+	    x->x_ramps[i] = x->x_deframp;
+    }
+}
+
+static t_int *matrix01_perform(t_int *w)
+{
+    t_matrix *x = (t_matrix *)(w[1]);
+    int nblock = (int)(w[2]);
+    t_float **ivecs = x->x_ivecs;
+    t_float **ovecs = x->x_ovecs;
+    t_float **osums = x->x_osums;
+    int *cellp = x->x_cells;
+    int indx = x->x_ninlets;
+    while (indx--)
+    {
+	t_float *ivec = *ivecs++;
+	t_float **ovecp = osums;
+	int ondx = x->x_noutlets;
+	while (ondx--)
+	{
+	    if (*cellp++)
+	    {
+		t_float *in = ivec;
+		t_float *out = *ovecp;
+		int sndx = nblock;
+		while (sndx--)
+		    *out++ += *in++;
+	    }
+	    ovecp++;
+	}
+    }
+    osums = x->x_osums;
+    indx = x->x_noutlets;
+    while (indx--)
+    {
+	t_float *in = *osums++;
+	t_float *out = *ovecs++;
+	int sndx = nblock;
+	while (sndx--)
+	{
+	    *out++ = *in;
+	    *in++ = 0.;
+	}
+    }
+    return (w + 3);
+}
+
+static t_int *matrixnb_perform(t_int *w)
+{
+    t_matrix *x = (t_matrix *)(w[1]);
+    int nblock = (int)(w[2]);
+    t_float **ivecs = x->x_ivecs;
+    t_float **ovecs = x->x_ovecs;
+    t_float **osums = x->x_osums;
+    int *cellp = x->x_cells;
+    float *gainp = x->x_gains;
+    float *coefp = x->x_coefs;
+    float *incrp = x->x_incrs;
+    float *bigincrp = x->x_bigincrs;
+    int *nleftp = x->x_remains;
+    int indx = x->x_ninlets;
+    while (indx--)
+    {
+	t_float *ivec = *ivecs++;
+	t_float **ovecp = osums;
+	int ondx = x->x_noutlets;
+	while (ondx--)
+	{
+	    t_float *in = ivec;
+	    t_float *out = *ovecp;
+	    float nleft = *nleftp;
+	    int sndx = nblock;
+	    if (nleft >= nblock)
+	    {
+		float coef = *coefp;
+		float incr = *incrp;
+		if ((*nleftp -= nblock) == 0)
+		    *coefp = (*cellp ? *gainp : 0.);
+		else
+		    *coefp += *bigincrp;
+		while (sndx--)
+		    *out++ += *in++ * coef, coef += incr;
+	    }
+	    else if (nleft > 0)
+	    {
+		float coef = *coefp;
+		float incr = *incrp;
+		sndx -= nleft;
+		do
+		    *out++ += *in++ * coef, coef += incr;
+		while (--nleft);
+		if (*cellp)
+		{
+		    coef = *coefp = *gainp;
+		    while (sndx--)
+			*out++ += *in++ * coef;
+		}
+		else *coefp = 0.;
+		*nleftp = 0;
+	    }
+	    else if (*cellp)
+	    {
+		float coef = *coefp;
+		while (sndx--)
+		    *out++ += *in++ * coef;
+	    }
+	    cellp++;
+	    ovecp++;
+	    gainp++;
+	    coefp++;
+	    incrp++;
+	    bigincrp++;
+	    nleftp++;
+	}
+    }
+    osums = x->x_osums;
+    indx = x->x_noutlets;
+    while (indx--)
+    {
+	t_float *in = *osums++;
+	t_float *out = *ovecs++;
+	int sndx = nblock;
+	while (sndx--)
+	{
+	    *out++ = *in;
+	    *in++ = 0.;
+	}
+    }
+    return (w + 3);
+}
+
+static void matrix_dsp(t_matrix *x, t_signal **sp)
+{
+    int i, nblock = sp[0]->s_n;
+    t_float **vecp = x->x_ivecs;
+    t_signal **sigp = sp;
+    for (i = 0; i < x->x_ninlets; i++)
+	*vecp++ = (*sigp++)->s_vec;
+    vecp = x->x_ovecs;
+    for (i = 0; i < x->x_noutlets; i++)
+	*vecp++ = (*sigp++)->s_vec;
+    if (nblock != x->x_nblock)
+    {
+	if (nblock > x->x_maxblock)
+	{
+	    size_t oldsize = x->x_maxblock * sizeof(*x->x_osums[i]),
+		newsize = nblock * sizeof(*x->x_osums[i]);
+	    for (i = 0; i < x->x_noutlets; i++)
+		x->x_osums[i] = resizebytes(x->x_osums[i], oldsize, newsize);
+	    x->x_maxblock = nblock;
+	}
+	x->x_nblock = nblock;
+    }
+    if (x->x_gains)
+    {
+	x->x_ksr = sp[0]->s_sr * .001;
+	dsp_add(matrixnb_perform, 2, x, nblock);
+    }
+    else dsp_add(matrix01_perform, 2, x, nblock);
+}
+
+static void matrix_cellout(t_matrix *x, int indx, int ondx,
+			   int onoff, float gain)
+{
+    t_atom atout[3];
+    SETFLOAT(&atout[0], (t_float)indx);
+    SETFLOAT(&atout[1], (t_float)ondx);
+    if (onoff)
+	SETFLOAT(&atout[2], gain);
+    else
+	SETFLOAT(&atout[2], 0.);
+    outlet_list(x->x_dumpout, &s_list, 3, atout);
+}
+
+static void matrix_cellprint(t_matrix *x, int indx, int ondx,
+			     int onoff, float gain)
+{
+    post("%d %d %g", indx, ondx, (onoff ? gain : 0.));
+}
+
+#ifdef MATRIX_DEBUG
+static void matrix_celldebug(t_matrix *x, int indx, int ondx,
+			     int onoff, float gain)
+{
+    loudbug_post("%d %d %g", indx, ondx, gain);
+}
+#endif
+
+static void matrix_report(t_matrix *x, float *gains, float defgain,
+			  t_matrix_cellfn cellfn)
+{
+    if (gains)
+    {
+	int *cellp = x->x_cells;
+	float *gp = gains;
+	int indx, ondx;
+	for (indx = 0; indx < x->x_ninlets; indx++)
+	    for (ondx = 0; ondx < x->x_noutlets; ondx++, cellp++, gp++)
+		/* CHECKED all cells are printed */
+		(*cellfn)(x, indx, ondx, *cellp, *gp);
+    }
+    else  /* CHECKED incompatible: gains confusingly printed in binary mode */
+    {
+	int *cellp = x->x_cells;
+	int indx, ondx;
+	for (indx = 0; indx < x->x_ninlets; indx++)
+	    for (ondx = 0; ondx < x->x_noutlets; ondx++, cellp++)
+		/* CHECKED all cells are printed */
+		(*cellfn)(x, indx, ondx, *cellp, defgain);
+    }
+}
+
+static void matrix_dump(t_matrix *x)
+{
+    matrix_report(x, x->x_coefs, 1., matrix_cellout);
+}
+
+static void matrix_dumptarget(t_matrix *x)
+{
+    matrix_report(x, x->x_gains, 1., matrix_cellout);
+}
+
+static void matrix_print(t_matrix *x)
+{
+    /* CHECKED same output as 'dump' -> [matrix~] -> [print] */
+    matrix_report(x, x->x_coefs, 1., matrix_cellprint);
+}
+
+#ifdef MATRIX_DEBUG
+static void matrix_debugramps(t_matrix *x)
+{
+    matrix_report(x, x->x_ramps, 0., matrix_celldebug);
+}
+
+static void matrix_debugsums(t_matrix *x)
+{
+    int i;
+    loudbug_startpost("nblock %d (max %d), vectors:",
+		      x->x_nblock, x->x_maxblock);
+    for (i = 0; i < x->x_noutlets; i++)
+	loudbug_startpost(" %x", (int)x->x_osums[i]);
+    loudbug_endpost();
+}
+
+static void matrix_debug(t_matrix *x, t_symbol *s)
+{
+    if (s == gensym("ramps"))
+	matrix_debugramps(x);
+    else if (s == gensym("sums"))
+	matrix_debugsums(x);
+    else
+    {
+	matrix_debugramps(x);
+	matrix_debugsums(x);
+    }
+}
+#endif
+
+static void matrix_free(t_matrix *x)
+{
+    if (x->x_ivecs)
+	freebytes(x->x_ivecs, x->x_ninlets * sizeof(*x->x_ivecs));
+    if (x->x_ovecs)
+	freebytes(x->x_ovecs, x->x_noutlets * sizeof(*x->x_ovecs));
+    if (x->x_osums)
+    {
+	int i;
+	for (i = 0; i < x->x_noutlets; i++)
+	    freebytes(x->x_osums[i], x->x_maxblock * sizeof(*x->x_osums[i]));
+	freebytes(x->x_osums, x->x_noutlets * sizeof(*x->x_osums));
+    }
+    if (x->x_cells)
+	freebytes(x->x_cells, x->x_ncells * sizeof(*x->x_cells));
+    if (x->x_gains)
+	freebytes(x->x_gains, x->x_ncells * sizeof(*x->x_gains));
+    if (x->x_ramps)
+	freebytes(x->x_ramps, x->x_ncells * sizeof(*x->x_ramps));
+    if (x->x_coefs)
+	freebytes(x->x_coefs, x->x_ncells * sizeof(*x->x_coefs));
+    if (x->x_incrs)
+	freebytes(x->x_incrs, x->x_ncells * sizeof(*x->x_incrs));
+    if (x->x_bigincrs)
+	freebytes(x->x_bigincrs, x->x_ncells * sizeof(*x->x_bigincrs));
+    if (x->x_remains)
+	freebytes(x->x_remains, x->x_ncells * sizeof(*x->x_remains));
+}
+
+static void *matrix_new(t_symbol *s, int ac, t_atom *av)
+{
+    t_pd *z;
+    if (!fittermax_get() &&
+	(z = fragile_class_mutate(matrixps_matrixtilde,
+				  (t_newmethod)matrix_new, ac, av)))
+	return (z);
+    else if (ac < 2)
+    {
+	loud_error(0, "bad creation arguments for class '%s'",
+		   matrixps_matrixtilde->s_name);
+	loud_errand(0, "missing number of %s", (ac ? "outlets" : "inlets"));
+	return (0);  /* CHECKED */
+    }
+    else
+    {
+	t_matrix *x = (t_matrix *)pd_new(matrix_class);
+	int i;
+	if (av[0].a_type == A_FLOAT)
+	{
+	    if ((x->x_ninlets = (int)av[0].a_w.w_float) < 1)
+		x->x_ninlets = 1;
+	}
+	else x->x_ninlets = 1;  /* CHECKED */
+	if (av[1].a_type == A_FLOAT)
+	{
+	    if ((x->x_noutlets = (int)av[1].a_w.w_float) < 1)
+		x->x_noutlets = 1;
+	}
+	else x->x_noutlets = 1;  /* CHECKED */
+	x->x_ncells = x->x_ninlets * x->x_noutlets;
+	x->x_ivecs = getbytes(x->x_ninlets * sizeof(*x->x_ivecs));
+	x->x_ovecs = getbytes(x->x_noutlets * sizeof(*x->x_ovecs));
+	x->x_nblock = x->x_maxblock = sys_getblksize();
+	x->x_osums = getbytes(x->x_noutlets * sizeof(*x->x_osums));
+	for (i = 0; i < x->x_noutlets; i++)
+	    x->x_osums[i] = getbytes(x->x_maxblock * sizeof(*x->x_osums[i]));
+	x->x_cells = getbytes(x->x_ncells * sizeof(*x->x_cells));
+	matrix_clear(x);
+	if (ac >= 3)
+	{
+	    if (av[2].a_type == A_FLOAT)
+		x->x_defgain = av[2].a_w.w_float;
+	    else
+		x->x_defgain = MATRIX_DEFGAIN;
+	    x->x_gains = getbytes(x->x_ncells * sizeof(*x->x_gains));
+	    for (i = 0; i < x->x_ncells; i++)
+		x->x_gains[i] = x->x_defgain;
+	    x->x_ramps = getbytes(x->x_ncells * sizeof(*x->x_ramps));
+	    matrix_ramp(x, MATRIX_DEFRAMP);
+	    x->x_coefs = getbytes(x->x_ncells * sizeof(*x->x_coefs));
+	    for (i = 0; i < x->x_ncells; i++)
+		x->x_coefs[i] = 0.;
+	    x->x_ksr = sys_getsr() * .001;
+	    x->x_incrs = getbytes(x->x_ncells * sizeof(*x->x_incrs));
+	    x->x_bigincrs = getbytes(x->x_ncells * sizeof(*x->x_bigincrs));
+	    x->x_remains = getbytes(x->x_ncells * sizeof(*x->x_remains));
+	    for (i = 0; i < x->x_ncells; i++)
+		x->x_remains[i] = 0;
+	}
+	else
+	{
+	    x->x_gains = 0;
+	    x->x_ramps = 0;
+	    x->x_coefs = 0;
+	    x->x_incrs = 0;
+	    x->x_bigincrs = 0;
+	    x->x_remains = 0;
+	}
+	for (i = 1; i < x->x_ninlets; i++)
+	    sic_newinlet((t_sic *)x, 0.);
+	for (i = 0; i < x->x_noutlets; i++)
+	    outlet_new((t_object *)x, &s_signal);
+	x->x_dumpout = outlet_new((t_object *)x, &s_list);
+	return (x);
+    }
+}
+
+void matrix_tilde_setup(void)
+{
+    matrixps_matrixtilde = gensym("matrix~");
+    matrix_class = class_new(matrixps_matrixtilde,
+			     (t_newmethod)matrix_new,
+			     (t_method)matrix_free,
+			     sizeof(t_matrix), 0, A_GIMME, 0);
+    fragile_class_raise(matrixps_matrixtilde, (t_newmethod)matrix_new);
+    sic_setup(matrix_class, matrix_dsp, matrix_float);
+    class_addlist(matrix_class, matrix_list);
+    class_addmethod(matrix_class, (t_method)matrix_clear,
+		    gensym("clear"), 0);
+    class_addmethod(matrix_class, (t_method)matrix_connect,
+		    gensym("connect"), A_GIMME, 0);
+    class_addmethod(matrix_class, (t_method)matrix_connect,
+		    gensym("disconnect"), A_GIMME, 0);
+    class_addmethod(matrix_class, (t_method)matrix_ramp,
+		    gensym("ramp"), A_FLOAT, 0);
+    class_addmethod(matrix_class, (t_method)matrix_dump,
+		    gensym("dump"), 0);
+    class_addmethod(matrix_class, (t_method)matrix_dumptarget,
+		    gensym("dumptarget"), 0);
+    class_addmethod(matrix_class, (t_method)matrix_print,
+		    gensym("print"), 0);
+#ifdef MATRIX_DEBUG
+    class_addmethod(matrix_class, (t_method)matrix_debug,
+		    gensym("debug"), A_DEFSYM, 0);
+#endif
+    fitter_setup(matrix_class, 0);
+}
diff --git a/cyclone/sickle/sickle.c b/cyclone/sickle/sickle.c
index 1d46050..c83f543 100644
--- a/cyclone/sickle/sickle.c
+++ b/cyclone/sickle/sickle.c
@@ -13,8 +13,6 @@ void allsickles_setup(void);
 typedef struct _sickle
 {
     t_object       x_ob;
-    t_symbol      *x_dir;
-    t_symbol      *x_canvasdir;
     t_hammerfile  *x_filehandle;
 } t_sickle;
 
@@ -24,39 +22,43 @@ static int sickle_lastndx;
 
 static void sickle_readhook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
 {
-    import_max(fn->s_name, "");
+    int result = import_max(fn->s_name, "");
+    outlet_float(((t_object *)z)->ob_outlet, (t_float)result);
 }
 
-static void sickle_doimport(t_sickle *x, t_symbol *fn, t_symbol *dir)
+static void sickle_doimport(t_sickle *x, t_symbol *fn)
 {
-    if (!dir || dir == &s_)
-	dir = x->x_dir;
     if (fn && fn != &s_)
-	import_max(fn->s_name, (dir && dir != &s_) ? dir->s_name : "");
-    else
-	hammerpanel_open(x->x_filehandle, dir);
+    {
+	t_symbol *dir = hammerpanel_getopendir(x->x_filehandle);
+	int result =
+	    import_max(fn->s_name, (dir && dir != &s_ ? dir->s_name : ""));
+	outlet_float(((t_object *)x)->ob_outlet, (t_float)result);
+    }
+    else hammerpanel_open(x->x_filehandle, 0);
 }
 
 static void sickle_click(t_sickle *x, t_floatarg xpos, t_floatarg ypos,
 			 t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
 {
-    sickle_doimport(x, 0, 0);
+    sickle_doimport(x, 0);
 }
 
 static void sickle_import(t_sickle *x, t_symbol *fn)
 {
-    sickle_doimport(x, fn, 0);
+    sickle_doimport(x, fn);
 }
 
 static void sickle_cd(t_sickle *x, t_symbol *dir)
 {
-    /* LATER hammerfile interface for relative jumps, etc. */
-    x->x_dir = (dir && dir != &s_ ? dir : x->x_canvasdir);
+    hammerpanel_setopendir(x->x_filehandle, dir);
 }
 
-static void sickle_pwd(t_sickle *x)
+static void sickle_pwd(t_sickle *x, t_symbol *s)
 {
-    outlet_symbol(((t_object *)x)->ob_outlet, x->x_dir);
+    t_symbol *dir;
+    if (s && s->s_thing && (dir = hammerpanel_getopendir(x->x_filehandle)))
+	pd_symbol(s->s_thing, dir);
 }
 
 static void sickle_bang(t_sickle *x)
@@ -74,9 +76,7 @@ static void *sickle_new(void)
 {
     t_sickle *x = (t_sickle *)pd_new(sickle_class);
     x->x_filehandle = hammerfile_new((t_pd *)x, 0, sickle_readhook, 0, 0);
-    x->x_canvasdir = canvas_getdir(x->x_filehandle->f_canvas);
-    x->x_dir = x->x_canvasdir;
-    outlet_new((t_object *)x, &s_symbol);
+    outlet_new((t_object *)x, &s_float);
     return (x);
 }
 
@@ -106,7 +106,7 @@ void sickle_setup(void)
     class_addmethod(sickle_class, (t_method)sickle_cd,
 		    gensym("cd"), A_DEFSYM, 0);
     class_addmethod(sickle_class, (t_method)sickle_pwd,
-		    gensym("pwd"), 0);
+		    gensym("pwd"), A_SYMBOL, 0);
     class_addmethod(sickle_class, (t_method)sickle_import,
 		    gensym("import"), A_DEFSYM, 0);
     class_addmethod(sickle_class, (t_method)sickle_click,
diff --git a/shared/common/Makefile.sources b/shared/common/Makefile.sources
index f605df4..76fd3cc 100644
--- a/shared/common/Makefile.sources
+++ b/shared/common/Makefile.sources
@@ -2,12 +2,12 @@ OTHER_SOURCES = \
 binport.c \
 clc.c \
 dict.c \
-fi.c \
 fitter.c \
 grow.c \
 lex.c \
 loud.c \
 mifi.c \
+os.c \
 port.c \
 props.c \
 qtree.c \
diff --git a/shared/common/binport.c b/shared/common/binport.c
index 4fe46e8..1df9571 100644
--- a/shared/common/binport.c
+++ b/shared/common/binport.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997-2004 Miller Puckette, krzYszcz, and others.
+/* Copyright (c) 1997-2005 Miller Puckette, krzYszcz, and others.
  * For information on usage and redistribution, and for a DISCLAIMER OF ALL
  * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
 
@@ -584,7 +584,7 @@ static int binport_alike(char *header, int *ftypep)
     static char text_header[4] = { 'm', 'a', 'x', ' ' };
     static char pd_header[3] = { '#', 'N', ' ' };  /* canvas or struct */
     if (memcmp(header, bin_header, 4) == 0)
-	*ftypep = BINPORT_OK;
+	*ftypep = BINPORT_MAXBINARY;
     else if (memcmp(header, text_header, 4) == 0)
 	*ftypep = BINPORT_MAXTEXT;
     else if (memcmp(header, old_header, 4) == 0)
@@ -631,7 +631,7 @@ static t_binport *binport_new(FILE *fp, int *ftypep)
 	    bp->b_fp = fp;
 	    bp->b_ftype = *ftypep;
 	    bp->b_nsymbols = 0;
-	    if (*ftypep == BINPORT_OK)
+	    if (*ftypep == BINPORT_MAXBINARY)
 	    {
 		bp->b_symsize = BINPORT_SYMGROW;
 		bp->b_symtable =
@@ -712,9 +712,9 @@ int binport_read(t_binbuf *bb, char *filename, char *dirname)
 	t_binport *bp = binport_new(fp, &ftype);
 	if (bp)
 	{
-	    if (ftype == BINPORT_OK)
+	    if (ftype == BINPORT_MAXBINARY)
 		result = (binport_tobinbuf(bp, bb)
-			  ? BINPORT_OK : BINPORT_CORRUPT);
+			  ? BINPORT_MAXBINARY : BINPORT_CORRUPT);
 	    else if (ftype == BINPORT_MAXTEXT)
 	    {
 		t_atom at;
@@ -725,7 +725,7 @@ int binport_read(t_binbuf *bb, char *filename, char *dirname)
 			    break;
 		    binbuf_addv(bb, "ss;", gensym("max"), gensym("v2"));
 		    result = (binport_tobinbuf(bp, bb)
-			      ? BINPORT_OK : BINPORT_CORRUPT);
+			      ? BINPORT_MAXTEXT : BINPORT_CORRUPT);
 		}
 		else result = BINPORT_FAILED;
 	    }
@@ -737,7 +737,7 @@ int binport_read(t_binbuf *bb, char *filename, char *dirname)
 		{
 		    bp->b_old = old;
 		    if (binpold_load(old) && binport_tobinbuf(bp, bb))
-			result = BINPORT_OK;
+			result = BINPORT_MAXOLD;
 		}
 		else binpold_failure(filename);
 	    }
@@ -809,7 +809,7 @@ int main(int ac, char **av)
 	    t_binport *bp = binport_new(fp, &ftype);
 	    if (bp)
 	    {
-		if (ftype == BINPORT_OK)
+		if (ftype == BINPORT_MAXBINARY)
 		    binport_print(bp, stdout);
 		else if (ftype == BINPORT_MAXTEXT)
 		    binport_warning("\"%s\" looks like a Max text file", av[1]);
diff --git a/shared/common/binport.h b/shared/common/binport.h
index f29d24d..b70c555 100644
--- a/shared/common/binport.h
+++ b/shared/common/binport.h
@@ -1,12 +1,20 @@
-/* Copyright (c) 2003-2004 krzYszcz and others.
+/* Copyright (c) 2003-2005 krzYszcz and others.
  * For information on usage and redistribution, and for a DISCLAIMER OF ALL
  * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
 
 #ifndef __BINPORT_H__
 #define __BINPORT_H__
 
-enum { BINPORT_OK, BINPORT_MAXTEXT, BINPORT_MAXOLD, BINPORT_PDFILE,
-       BINPORT_INVALID, BINPORT_CORRUPT, BINPORT_FAILED };
+/* return values of binport_read() and import_max(), also passed to
+   outlet_float() by cyclone library objects (cyclone, maxmode...) */
+#define BINPORT_FAILED    -4  /* internal error */
+#define BINPORT_CORRUPT   -3  /* file contents inconsistency */
+#define BINPORT_INVALID   -2  /* file type not recognized */
+#define BINPORT_NOFILE    -1  /* file not found */
+#define BINPORT_MAXBINARY  0
+#define BINPORT_MAXTEXT    1
+#define BINPORT_MAXOLD     2
+#define BINPORT_PDFILE     3
 
 #ifndef MIXED_STANDALONE
 int binport_read(t_binbuf *bb, char *filename, char *dirname);
diff --git a/shared/common/fi.c b/shared/common/fi.c
deleted file mode 100644
index e46d001..0000000
--- a/shared/common/fi.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Copyright (c) 2004 krzYszcz and others.
- * For information on usage and redistribution, and for a DISCLAIMER OF ALL
- * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
-
-#ifdef NT
-#include <io.h>
-#else
-#include <unistd.h>
-#endif
-#include <stdio.h>
-#include <string.h>
-#include "m_pd.h"
-#include "fi.h"
-
-FILE *firead_open(char *filename, t_canvas *cv, int textmode)
-{
-    int fd;
-    char path[MAXPDSTRING+2], *nameptr;
-    t_symbol *dirsym = (cv ? canvas_getdir(cv) : 0);
-    /* path arg is returned unbashed (system-independent) */
-    if ((fd = open_via_path((dirsym ? dirsym->s_name : ""), filename,
-			    "", path, &nameptr, MAXPDSTRING, 1)) < 0)
-    	return (0);
-    /* Closing/reopening dance.  This is unnecessary under linux, and we
-       could have tried to convert fd to fp, but under windows open_via_path()
-       returns what seems to be an invalid fd.
-       LATER try to understand what is going on here... */
-    close(fd);
-    if (path != nameptr)
-    {
-	char *slashpos = path + strlen(path);
-	*slashpos++ = '/';
-	/* try not to be dependent on current open_via_path() implementation */
-	if (nameptr != slashpos)
-	    strcpy(slashpos, nameptr);
-    }
-    sys_bashfilename(path, path);
-    return (fopen(path, (textmode ? "r" : "rb")));
-}
-
-FILE *fiwrite_open(char *filename, t_canvas *cv, int textmode)
-{
-    char path[MAXPDSTRING+2];
-    if (cv)
-	/* path arg is returned unbashed (system-independent) */
-	canvas_makefilename(cv, filename, path, MAXPDSTRING);
-    else
-    {
-    	strncpy(path, filename, MAXPDSTRING);
-    	path[MAXPDSTRING-1] = 0;
-    }
-    sys_bashfilename(path, path);
-    return (fopen(path, (textmode ? "w" : "wb")));
-}
diff --git a/shared/common/fi.h b/shared/common/fi.h
deleted file mode 100644
index c6e8401..0000000
--- a/shared/common/fi.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* Copyright (c) 2004 krzYszcz and others.
- * For information on usage and redistribution, and for a DISCLAIMER OF ALL
- * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
-
-#ifndef __FI_H__
-#define __FI_H__
-
-FILE *firead_open(char *filename, t_canvas *cv, int textmode);
-FILE *fiwrite_open(char *filename, t_canvas *cv, int textmode);
-
-#endif
diff --git a/shared/common/fitter.c b/shared/common/fitter.c
index 2ccdd53..faba970 100644
--- a/shared/common/fitter.c
+++ b/shared/common/fitter.c
@@ -25,7 +25,7 @@ static t_symbol *fittermode_value = 0;
 typedef struct _fittermode_client
 {
     t_class                    *fc_owner;
-    t_symbol                  **fc_mirror;
+    t_canvas                   *fc_canvas;
     t_fittermode_callback       fc_callback;
     struct _fittermode_client  *fc_next;
 } t_fittermode_client;
@@ -36,6 +36,7 @@ static t_pd *fittermode_target = 0;
 static int fittermode_ready = 0;
 static t_symbol *fitterps_hashcompatibility = 0;
 static t_symbol *fitterps_max = 0;
+static t_symbol *fitterps_none = 0;
 
 /* read access (query), only from fittermode_dosetup() */
 static void fittermode_bang(t_pd *x)
@@ -55,6 +56,11 @@ static void fittermode_bang(t_pd *x)
 /* read access (reply), only from fitter_dosetup() */
 static void fittermode_symbol(t_pd *x, t_symbol *s)
 {
+    if (!s || s == &s_)
+    {
+	loudbug_bug("fittermode_symbol");
+	s = fitterps_none;
+    }
     fittermode_value = s;
 }
 
@@ -64,12 +70,8 @@ static void fittermode_set(t_pd *x, t_symbol *s)
     t_fittermode_client *fc;
     fittermode_value = s;
     for (fc = fittermode_clients; fc; fc = fc->fc_next)
-    {
-	if (fc->fc_mirror)
-	    *fc->fc_mirror = s;
 	if (fc->fc_callback)
-	    fc->fc_callback(s);
-    }
+	    fc->fc_callback();
 }
 
 static void fittermode_dosetup(int noquery)
@@ -78,9 +80,11 @@ static void fittermode_dosetup(int noquery)
 	loudbug_bug("fittermode_dosetup");
     fitterps_hashcompatibility = gensym("#compatibility");
     fitterps_max = gensym("max");
+    fitterps_none = gensym("none");
+    fittermode_value = fitterps_none;
     fittermode_class = class_new(fitterps_hashcompatibility,
-					  0, 0, sizeof(t_pd),
-					  CLASS_PD | CLASS_NOINLET, 0);
+				 0, 0, sizeof(t_pd),
+				 CLASS_PD | CLASS_NOINLET, 0);
     class_addbang(fittermode_class, fittermode_bang);
     class_addsymbol(fittermode_class, fittermode_symbol);
     class_addmethod(fittermode_class,
@@ -93,21 +97,18 @@ static void fittermode_dosetup(int noquery)
     fittermode_ready = 1;
 }
 
-void fitter_setup(t_class *owner, t_symbol **mirror,
-		  t_fittermode_callback callback)
+void fitter_setup(t_class *owner, t_fittermode_callback callback)
 {
     if (!fittermode_class)
 	fittermode_dosetup(0);
-    if (mirror || callback)
+    if (callback)
     {
 	t_fittermode_client *fc = getbytes(sizeof(*fc));
 	fc->fc_owner = owner;
-	fc->fc_mirror = mirror;
+	fc->fc_canvas = 0;  /* a global client */
 	fc->fc_callback = callback;
 	fc->fc_next = fittermode_clients;
 	fittermode_clients = fc;
-	if (mirror)
-	    *mirror = fittermode_value;
     }
 }
 
@@ -140,7 +141,9 @@ void fitter_drop(t_class *owner)
 
 void fitter_setmode(t_symbol *s)
 {
-    post("setting compatibility mode to '%s'", (s ? s->s_name : "none"));
+    if (!s || s == &s_)
+	s = fitterps_none;
+    post("setting compatibility mode to '%s'", s->s_name);
     if (!fittermode_class)
 	fittermode_dosetup(1);
     if (fitterps_hashcompatibility->s_thing)
diff --git a/shared/common/fitter.h b/shared/common/fitter.h
index 3f3303c..2e5c24d 100644
--- a/shared/common/fitter.h
+++ b/shared/common/fitter.h
@@ -5,10 +5,9 @@
 #ifndef __FITTER_H__
 #define __FITTER_H__
 
-typedef void (*t_fittermode_callback)(t_symbol *s);
+typedef void (*t_fittermode_callback)(void);
 
-void fitter_setup(t_class *owner, t_symbol **mirror,
-		  t_fittermode_callback callback);
+void fitter_setup(t_class *owner, t_fittermode_callback callback);
 void fitter_drop(t_class *owner);
 void fitter_setmode(t_symbol *s);
 t_symbol *fitter_getmode(void);
diff --git a/shared/common/loud.c b/shared/common/loud.c
index 6229a77..d87d3c0 100644
--- a/shared/common/loud.c
+++ b/shared/common/loud.c
@@ -348,6 +348,9 @@ void loudbug_post(char *fmt, ...)
     vsnprintf(buf, MAXPDSTRING-1, fmt, ap);
     va_end(ap);
     fprintf(stderr, "%s\n", buf);
+#ifdef MSW
+    fflush(stderr);
+#endif
 }
 
 void loudbug_startpost(char *fmt, ...)
@@ -358,11 +361,17 @@ void loudbug_startpost(char *fmt, ...)
     vsnprintf(buf, MAXPDSTRING-1, fmt, ap);
     va_end(ap);
     fputs(buf, stderr);
+#ifdef MSW
+    fflush(stderr);
+#endif
 }
 
 void loudbug_endpost(void)
 {
     fputs("\n", stderr);
+#ifdef MSW
+    fflush(stderr);
+#endif
 }
 
 void loudbug_postatom(int ac, t_atom *av)
@@ -372,6 +381,9 @@ void loudbug_postatom(int ac, t_atom *av)
         char buf[MAXPDSTRING];
         atom_string(av++, buf, MAXPDSTRING);
 	fprintf(stderr, " %s", buf);
+#ifdef MSW
+	fflush(stderr);
+#endif
     }
 }
 
@@ -391,9 +403,18 @@ void loudbug_postbinbuf(t_binbuf *bb)
 		fprintf(stderr, " %s", buf);
 	}
 	else fprintf(stderr, "%s", buf);
+#ifdef MSW
+	fflush(stderr);
+#endif
 	aprev = ap++;
     }
-    if (aprev) fputs("\n", stderr);
+    if (aprev)
+    {
+	fputs("\n", stderr);
+#ifdef MSW
+	fflush(stderr);
+#endif
+    }
 }
 
 void loudbug_bug(char *fmt, ...)
@@ -404,5 +425,8 @@ void loudbug_bug(char *fmt, ...)
     vsnprintf(buf, MAXPDSTRING-1, fmt, ap);
     va_end(ap);
     fprintf(stderr, "miXed consistency check failed: %s\n", buf);
+#ifdef MSW
+    fflush(stderr);
+#endif
     bug(buf);
 }
diff --git a/shared/common/os.c b/shared/common/os.c
new file mode 100644
index 0000000..9129f82
--- /dev/null
+++ b/shared/common/os.c
@@ -0,0 +1,235 @@
+/* Copyright (c) 2004-2005 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
+
+#ifdef MSW
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "m_pd.h"
+#include "os.h"
+
+static int ospath_doabsolute(char *path, char *cwd, char *result)
+{
+    if (*path == 0)
+    {
+	if (result)
+	    strcpy(result, cwd);
+	else
+	    return (strlen(cwd));
+    }
+    else if (*path == '~')
+    {
+	path++;
+	if (*path == '/' || *path == 0)
+	{
+#ifdef UNIX
+	    char *home = getenv("HOME");
+	    if (home)
+	    {
+		if (result)
+		{
+		    strcpy(result, home);
+		    if (*path)
+			strcat(result, path);
+		}
+		else return (strlen(home) + strlen(path));
+	    }
+	    else goto badpath;
+#else
+	    goto badpath;
+#endif
+	}
+	else goto badpath;
+    }
+    else if (*path == '/')
+    {
+#ifdef MSW
+	/* path is absolute, drive is implicit, LATER UNC? */
+	if (*cwd && cwd[1] == ':')
+	{
+	    if (result)
+	    {
+		*result = *cwd;
+		result[1] = ':';
+		strcpy(result + 2, path);
+	    }
+	    else return (2 + strlen(path));
+	}
+	else goto badpath;
+#else
+	/* path is absolute */
+	if (result)
+	    strcpy(result, path);
+	else
+	    return (strlen(path));
+#endif
+    }
+    else
+    {
+#ifdef MSW
+	if (path[1] == ':')
+	{
+	    if (path[2] == '/')
+	    {
+		/* path is absolute */
+		if (result)
+		    strcpy(result, path);
+		else
+		    return (strlen(path));
+	    }
+	    else if (*cwd == *path)
+	    {
+		/* path is relative, drive is explicitly current */
+		if (result)
+		{
+		    int ndx = strlen(cwd);
+		    strcpy(result, cwd);
+		    result[ndx++] = '/';
+		    strcpy(result + ndx, path + 2);
+		}
+		else return (strlen(cwd) + strlen(path) - 1);
+	    }
+	    /* we do not maintain per-drive cwd, LATER rethink */
+	    else goto badpath;
+	}
+	/* LATER devices? */
+	else
+	{
+	    /* path is relative */
+	    if (result)
+	    {
+		int ndx = strlen(cwd);
+		strcpy(result, cwd);
+		result[ndx++] = '/';
+		strcpy(result + ndx, path);
+	    }
+	    else return (strlen(cwd) + 1 + strlen(path));
+	}
+#else
+	/* path is relative */
+	if (result)
+	{
+	    int ndx = strlen(cwd);
+	    strcpy(result, cwd);
+	    result[ndx++] = '/';
+	    strcpy(result + ndx, path);
+	}
+	else return (strlen(cwd) + 1 + strlen(path));
+#endif
+    }
+    if (result && *result && *result != '.')
+    {
+	/* clean-up */
+	char *inptr, *outptr = result;
+	int ndx = strlen(result);
+	if (result[ndx - 1] == '.')
+	{
+	    result[ndx] = '/';  /* guarding slash */
+	    result[ndx + 1] = 0;
+	}
+	for (inptr = result + 1; *inptr; inptr++)
+	{
+	    if (*inptr == '/')
+	    {
+		if (*outptr == '/')
+		    continue;
+		else if (*outptr == '.')
+		{
+		    if (outptr[-1] == '/')
+		    {
+			outptr--;
+			continue;
+		    }
+		    else if (outptr[-1] == '.' && outptr[-2] == '/')
+		    {
+			outptr -= 2;
+			if (outptr == result)
+			    continue;
+			else for (outptr--; outptr != result; outptr--)
+			    if (*outptr == '/')
+				break;
+			continue;
+		    }
+		}
+	    }
+	    *++outptr = *inptr;
+	}
+	if (*outptr == '/' && outptr != result)
+	    *outptr = 0;
+	else
+	    outptr[1] = 0;
+    }
+    else bug("ospath_doabsolute 1");
+    return (0);
+badpath:
+    if (result)
+	bug("ospath_doabsolute 2");
+    return (0);
+}
+
+/* Returns an estimated length of an absolute path made up from the first arg.
+   The actual ospath_absolute()'s length may be shorter (since it erases
+   superfluous slashes and dots), but not longer.  Both args should be unbashed
+   (system-independent), cwd should be absolute.  Returns 0 in case of any
+   error (LATER revisit). */
+int ospath_length(char *path, char *cwd)
+{
+    /* one extra byte used internally (guarding slash) */
+    return (ospath_doabsolute(path, cwd, 0) + 1);
+}
+
+/* Copies an absolute path to result.  Arguments: path and cwd, are the same
+   as in ospath_length().  Caller should first consult ospath_length(), and
+   allocate at least ospath_length() + 1 bytes to the result buffer.
+   Should never fail (failure is a bug). */
+char *ospath_absolute(char *path, char *cwd, char *result)
+{
+    ospath_doabsolute(path, cwd, result);
+    return (result);
+}
+
+FILE *fileread_open(char *filename, t_canvas *cv, int textmode)
+{
+    int fd;
+    char path[MAXPDSTRING+2], *nameptr;
+    t_symbol *dirsym = (cv ? canvas_getdir(cv) : 0);
+    /* path arg is returned unbashed (system-independent) */
+    if ((fd = open_via_path((dirsym ? dirsym->s_name : ""), filename,
+			    "", path, &nameptr, MAXPDSTRING, 1)) < 0)
+    	return (0);
+    /* Closing/reopening dance.  This is unnecessary under linux, and we
+       could have tried to convert fd to fp, but under windows open_via_path()
+       returns what seems to be an invalid fd.
+       LATER try to understand what is going on here... */
+    close(fd);
+    if (path != nameptr)
+    {
+	char *slashpos = path + strlen(path);
+	*slashpos++ = '/';
+	/* try not to be dependent on current open_via_path() implementation */
+	if (nameptr != slashpos)
+	    strcpy(slashpos, nameptr);
+    }
+    sys_bashfilename(path, path);
+    return (fopen(path, (textmode ? "r" : "rb")));
+}
+
+FILE *filewrite_open(char *filename, t_canvas *cv, int textmode)
+{
+    char path[MAXPDSTRING+2];
+    if (cv)
+	/* path arg is returned unbashed (system-independent) */
+	canvas_makefilename(cv, filename, path, MAXPDSTRING);
+    else
+    {
+    	strncpy(path, filename, MAXPDSTRING);
+    	path[MAXPDSTRING-1] = 0;
+    }
+    sys_bashfilename(path, path);
+    return (fopen(path, (textmode ? "w" : "wb")));
+}
diff --git a/shared/common/os.h b/shared/common/os.h
new file mode 100644
index 0000000..f3dde89
--- /dev/null
+++ b/shared/common/os.h
@@ -0,0 +1,13 @@
+/* Copyright (c) 2004-2005 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
+
+#ifndef __OS_H__
+#define __OS_H__
+
+int ospath_length(char *path, char *cwd);
+char *ospath_absolute(char *path, char *cwd, char *result);
+FILE *fileread_open(char *filename, t_canvas *cv, int textmode);
+FILE *filewrite_open(char *filename, t_canvas *cv, int textmode);
+
+#endif
diff --git a/shared/common/port.c b/shared/common/port.c
index 159eab1..5845210 100644
--- a/shared/common/port.c
+++ b/shared/common/port.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997-2004 Miller Puckette, krzYszcz, and others.
+/* Copyright (c) 1997-2005 Miller Puckette, krzYszcz, and others.
  * For information on usage and redistribution, and for a DISCLAIMER OF ALL
  * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
 
@@ -1596,11 +1596,12 @@ endparsing:
     return (result);
 }
 
-void import_max(char *fn, char *dir)
+int import_max(char *fn, char *dir)
 {
+    int result;
     t_port *x;
     t_binbuf *inbb, *outbb;
-    int fd, ftype;
+    int fd;
     char buf[MAXPDSTRING], *bufp;
     t_pd *stackp = 0;
     int dspstate = canvas_suspend_dsp();
@@ -1608,23 +1609,30 @@ void import_max(char *fn, char *dir)
     if ((fd = open_via_path(dir, fn, "", buf, &bufp, MAXPDSTRING, 0)) < 0)
     {
     	loud_error(0, "%s: can't open", fn);
-    	return;
+    	return (BINPORT_NOFILE);
     }
     else close (fd);
 
     x = port_new();
     inbb = binbuf_new();
     glob_setfilename(0, gensym(bufp), gensym(buf));
-    ftype = binport_read(inbb, bufp, buf);
-    if (ftype == BINPORT_OK)
+    result = binport_read(inbb, bufp, buf);
+    if (result == BINPORT_MAXBINARY ||
+	result == BINPORT_MAXTEXT ||
+	result == BINPORT_MAXOLD)
     {
+	int bbresult;
 #ifdef PORT_DEBUG
 	binport_write(inbb, "import-debug.pat", "");
 #endif
 	outbb = binbuf_new();
-	if (import_binbuf(x, inbb, outbb) != PORT_OK)
+	if ((bbresult = import_binbuf(x, inbb, outbb)) != PORT_OK)
 	{
-	    loud_error(0, "%s: import failed", fn);
+	    loud_error(0, "%s: import failed (%d)", fn, bbresult);
+	    if (bbresult == PORT_CORRUPT)
+		result = BINPORT_CORRUPT;
+	    else
+		result = BINPORT_FAILED;
 	    binbuf_free(outbb);
 	    outbb = 0;
 	}		
@@ -1633,7 +1641,7 @@ void import_max(char *fn, char *dir)
 	if (outbb) binbuf_write(outbb, "import-result.pd", "", 0);
 #endif
     }
-    else if (ftype == BINPORT_PDFILE)
+    else if (result == BINPORT_PDFILE)
 	outbb = inbb;
     else
     {
@@ -1656,4 +1664,6 @@ void import_max(char *fn, char *dir)
 #if 0  /* LATER */
     pd_doloadbang();
 #endif
+
+    return (result);
 }
diff --git a/shared/common/port.h b/shared/common/port.h
index 2053c20..48f58bd 100644
--- a/shared/common/port.h
+++ b/shared/common/port.h
@@ -1,11 +1,11 @@
-/* Copyright (c) 2003-2004 krzYszcz and others.
+/* Copyright (c) 2003-2005 krzYszcz and others.
  * For information on usage and redistribution, and for a DISCLAIMER OF ALL
  * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
 
 #ifndef __PORT_H__
 #define __PORT_H__
 
-void import_max(char *fn, char *dir);
+int import_max(char *fn, char *dir);
 void import_setmapping(int size, char **mapping);
 char **import_getmapping(int *sizep);
 char *port_usemapping(char *from, int mapsize, char **mapping);
diff --git a/shared/getridof.baddeps b/shared/getridof.baddeps
index 77c055a..ebbf3df 100644
--- a/shared/getridof.baddeps
+++ b/shared/getridof.baddeps
@@ -9,7 +9,7 @@ common/qtree -> common/loud
 common/binport -> common/lex
 common/port -> common/loud, common/grow, common/binport,
 	unstable/forky, unstable/fragile, unstable/fringe
-hammer/file -> unstable/forky
+hammer/file -> common/os unstable/forky
 sickle/sic -> common/loud
 sickle/arsic -> common/loud, common/vefl, sickle/sic, unstable/fragile
 toxy/plusbob -> common/loud
diff --git a/shared/hammer/file.c b/shared/hammer/file.c
index 1cd6bfc..ecb5006 100644
--- a/shared/hammer/file.c
+++ b/shared/hammer/file.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002-2003 krzYszcz and others.
+/* Copyright (c) 2002-2005 krzYszcz and others.
  * For information on usage and redistribution, and for a DISCLAIMER OF ALL
  * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
 
@@ -22,9 +22,29 @@
 #include <string.h>
 #include "m_pd.h"
 #include "g_canvas.h"
+#include "common/os.h"
 #include "unstable/forky.h"
 #include "hammer/file.h"
 
+struct _hammerfile
+{
+    t_pd                 f_pd;
+    t_pd                *f_master;
+    t_canvas            *f_canvas;
+    t_symbol            *f_bindname;
+    t_symbol            *f_currentdir;
+    t_symbol            *f_inidir;
+    t_symbol            *f_inifile;
+    t_hammerfilefn       f_panelfn;
+    t_hammerfilefn       f_editorfn;
+    t_hammerembedfn      f_embedfn;
+    t_binbuf            *f_binbuf;
+    t_clock             *f_panelclock;
+    t_clock             *f_editorclock;
+    struct _hammerfile  *f_savepanel;
+    struct _hammerfile  *f_next;
+};
+
 static t_class *hammerfile_class = 0;
 static t_hammerfile *hammerfile_proxies;
 static t_symbol *ps__C;
@@ -183,12 +203,14 @@ static void hammerpanel_guidefs(void)
     sys_gui(" set filename [tk_getOpenFile \\\n");
     sys_gui("  -initialdir $inidir]\n");
     sys_gui(" if {$filename != \"\"} {\n");
-#if 0
     sys_gui("  set directory [string range $filename 0 \\\n");
     sys_gui("   [expr [string last / $filename ] - 1]]\n");
-    sys_gui("  set pd_opendir $directory\n");
+    sys_gui("  if {$directory == \"\"} {set directory \"/\"}\n");
+#if 1
+    sys_gui("  puts stderr [concat $directory]\n");
 #endif
-    sys_gui("  pd [concat $target symbol [pdtk_enquote $filename] \\;]\n");
+    sys_gui("  pd [concat $target path \\\n");
+    sys_gui("   [pdtk_enquote $filename] [pdtk_enquote $directory] \\;]\n");
     sys_gui(" }\n");
     sys_gui("}\n");
 
@@ -200,17 +222,39 @@ static void hammerpanel_guidefs(void)
     sys_gui("  set filename [tk_getSaveFile]\n");
     sys_gui(" }\n");
     sys_gui(" if {$filename != \"\"} {\n");
-    sys_gui("  pd [concat $target symbol [pdtk_enquote $filename] \\;]\n");
+    sys_gui("  set directory [string range $filename 0 \\\n");
+    sys_gui("   [expr [string last / $filename ] - 1]]\n");
+    sys_gui("  if {$directory == \"\"} {set directory \"/\"}\n");
+    sys_gui("  pd [concat $target path \\\n");
+    sys_gui("   [pdtk_enquote $filename] [pdtk_enquote $directory] \\;]\n");
     sys_gui(" }\n");
     sys_gui("}\n");
 }
 
+/* There are two modes of -initialdir persistence:
+   1. Using last reply from gui (if any, default is canvas directory):
+   pass null to hammerpanel_open/save() (for explicit cd, optionally call
+   hammerpanel_setopen/savedir() first).
+   2. Starting always in the same directory (eg. canvasdir):
+   feed hammerpanel_open/save().
+   Usually, first mode fits opening better, the second -- saving. */
+
+/* This is obsolete, but has to stay, because older versions of miXed libraries
+   might overwrite new hammerpanel_guidefs().  FIXME we need version control. */
 static void hammerpanel_symbol(t_hammerfile *f, t_symbol *s)
 {
     if (s && s != &s_ && f->f_panelfn)
 	(*f->f_panelfn)(f->f_master, s, 0, 0);
 }
 
+static void hammerpanel_path(t_hammerfile *f, t_symbol *s1, t_symbol *s2)
+{
+    if (s2 && s2 != &s_)
+	f->f_currentdir = s2;
+    if (s1 && s1 != &s_ && f->f_panelfn)
+	(*f->f_panelfn)(f->f_master, s1, 0, 0);
+}
+
 static void hammerpanel_tick(t_hammerfile *f)
 {
     if (f->f_savepanel)
@@ -225,16 +269,63 @@ static void hammerpanel_tick(t_hammerfile *f)
    a message box redraw to happen -- LATER investigate */
 void hammerpanel_open(t_hammerfile *f, t_symbol *inidir)
 {
-    f->f_inidir = (inidir ? inidir : &s_);
+    if (inidir)
+	f->f_inidir = inidir;
+    else
+	f->f_inidir = (f->f_currentdir ? f->f_currentdir : &s_);
     clock_delay(f->f_panelclock, 0);
 }
 
+void hammerpanel_setopendir(t_hammerfile *f, t_symbol *dir)
+{
+    if (f->f_currentdir && f->f_currentdir != &s_)
+    {
+	if (dir && dir != &s_)
+	{
+	    int length;
+	    if (length = ospath_length(dir->s_name, f->f_currentdir->s_name))
+	    {
+		char *path = getbytes(length + 1);
+		if (ospath_absolute(dir->s_name, f->f_currentdir->s_name, path))
+		    /* LATER stat (think how to report a failure) */
+		    f->f_currentdir = gensym(path);
+		freebytes(path, length + 1);
+	    }
+	}
+	else if (f->f_canvas)
+	    f->f_currentdir = canvas_getdir(f->f_canvas);
+    }
+    else bug("hammerpanel_setopendir");
+}
+
+t_symbol *hammerpanel_getopendir(t_hammerfile *f)
+{
+    return (f->f_currentdir);
+}
+
 void hammerpanel_save(t_hammerfile *f, t_symbol *inidir, t_symbol *inifile)
 {
-    /* LATER ask if we can rely on s_ pointing to "" */
-    f->f_savepanel->f_inidir = (inidir ? inidir : &s_);
-    f->f_savepanel->f_inifile = (inifile ? inifile : &s_);
-    clock_delay(f->f_savepanel->f_panelclock, 0);
+    if (f = f->f_savepanel)
+    {
+	if (inidir)
+	    f->f_inidir = inidir;
+	else
+	    /* LATER ask if we can rely on s_ pointing to "" */
+	    f->f_inidir = (f->f_currentdir ? f->f_currentdir : &s_);
+	f->f_inifile = (inifile ? inifile : &s_);
+	clock_delay(f->f_panelclock, 0);
+    }
+}
+
+void hammerpanel_setsavedir(t_hammerfile *f, t_symbol *dir)
+{
+    if (f = f->f_savepanel)
+	hammerpanel_setopendir(f, dir);
+}
+
+t_symbol *hammerpanel_getsavedir(t_hammerfile *f)
+{
+    return (f->f_savepanel ? f->f_savepanel->f_currentdir : 0);
 }
 
 /* Currently embeddable hammer classes do not use the 'saveto' method.
@@ -363,13 +454,17 @@ t_hammerfile *hammerfile_new(t_pd *master, t_hammerembedfn embedfn,
 	sprintf(buf, "miXed.%x", (int)result);
 	result->f_bindname = gensym(buf);
 	pd_bind((t_pd *)result, result->f_bindname);
+	result->f_currentdir =
+	    result->f_inidir = canvas_getdir(result->f_canvas);
 	result->f_panelfn = readfn;
 	result->f_panelclock = clock_new(result, (t_method)hammerpanel_tick);
 	f = (t_hammerfile *)pd_new(hammerfile_class);
 	f->f_master = master;
+	f->f_canvas = result->f_canvas;
 	sprintf(buf, "miXed.%x", (int)f);
 	f->f_bindname = gensym(buf);
 	pd_bind((t_pd *)f, f->f_bindname);
+	f->f_currentdir = f->f_inidir = result->f_currentdir;
 	f->f_panelfn = writefn;	
 	f->f_panelclock = clock_new(f, (t_method)hammerpanel_tick);
 	result->f_savepanel = f;
@@ -406,6 +501,8 @@ void hammerfile_setup(t_class *c, int embeddable)
 				     sizeof(t_hammerfile),
 				     CLASS_PD | CLASS_NOINLET, 0);
 	class_addsymbol(hammerfile_class, hammerpanel_symbol);
+	class_addmethod(hammerfile_class, (t_method)hammerpanel_path,
+			gensym("path"), A_SYMBOL, A_DEFSYM, 0);
 	class_addmethod(hammerfile_class, (t_method)hammereditor_clear,
 			gensym("clear"), 0);
 	class_addmethod(hammerfile_class, (t_method)hammereditor_addline,
diff --git a/shared/hammer/file.h b/shared/hammer/file.h
index fb87ed1..13be3b8 100644
--- a/shared/hammer/file.h
+++ b/shared/hammer/file.h
@@ -1,36 +1,25 @@
-/* Copyright (c) 2002-2003 krzYszcz and others.
+/* Copyright (c) 2002-2005 krzYszcz and others.
  * For information on usage and redistribution, and for a DISCLAIMER OF ALL
  * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
 
 #ifndef __HAMMERFILE_H__
 #define __HAMMERFILE_H__
 
+EXTERN_STRUCT _hammerfile;
+#define t_hammerfile  struct _hammerfile
+
 typedef void (*t_hammerfilefn)(t_pd *, t_symbol *, int, t_atom *);
 typedef void (*t_hammerembedfn)(t_pd *, t_binbuf *, t_symbol *);
 
-typedef struct _hammerfile
-{
-    t_pd                 f_pd;
-    t_pd                *f_master;
-    t_canvas            *f_canvas;
-    t_symbol            *f_bindname;
-    t_symbol            *f_inidir;
-    t_symbol            *f_inifile;
-    t_hammerfilefn       f_panelfn;
-    t_hammerfilefn       f_editorfn;
-    t_hammerembedfn      f_embedfn;
-    t_binbuf            *f_binbuf;
-    t_clock             *f_panelclock;
-    t_clock             *f_editorclock;
-    struct _hammerfile  *f_savepanel;
-    struct _hammerfile  *f_next;
-} t_hammerfile;
-
 void hammereditor_open(t_hammerfile *f, char *title);
 void hammereditor_close(t_hammerfile *f, int ask);
 void hammereditor_append(t_hammerfile *f, char *contents);
 void hammerpanel_open(t_hammerfile *f, t_symbol *inidir);
+void hammerpanel_setopendir(t_hammerfile *f, t_symbol *dir);
+t_symbol *hammerpanel_getopendir(t_hammerfile *f);
 void hammerpanel_save(t_hammerfile *f, t_symbol *inidir, t_symbol *inifile);
+void hammerpanel_setsavedir(t_hammerfile *f, t_symbol *dir);
+t_symbol *hammerpanel_getsavedir(t_hammerfile *f);
 int hammerfile_ismapped(t_hammerfile *f);
 int hammerfile_isloading(t_hammerfile *f);
 int hammerfile_ispasting(t_hammerfile *f);
diff --git a/shared/notes.txt b/shared/notes.txt
new file mode 100644
index 0000000..44c0c11
--- /dev/null
+++ b/shared/notes.txt
@@ -0,0 +1,29 @@
+TODO for root and shared
+  * fitter: abstraction-scoped, class-selective compatibility control
+  * fitter: mode list
+  * hammerfile, hammergui: version control
+
+DONE for root and shared
+
+with cyclone alpha52
+  * fragile: class name resolution based on voluntary mutation and raising
+  * fitter: mirroring removed
+  * new module, os: opening files, parsing path
+  * hammerpanel: two modes of -initialdir persistence
+  * more mingw fixes
+
+with cyclone alpha51
+  * new module, fitter: encapsulates compatibility support (formerly in maxmode)
+  * fitter: per-class callback and mirroring interface to compatibility mode
+  * mingw fixes
+
+with toxy alpha14
+  * scriptlet: version control (verslet_ routines)
+  * debug printout restricted to krzYszcz, sent to stderr
+
+with cyclone alpha50
+  * bug fixes
+    . hammertree crasher (affecting funbuff and offer)
+    . MouseState/toxy clash
+  * builds with gcc3 by default (no need to edit Makefile.common)
+  * midi file code has been cleaned, now ready for using in qlist
diff --git a/shared/unstable/forky.c b/shared/unstable/forky.c
index fcdbd61..3383dac 100644
--- a/shared/unstable/forky.c
+++ b/shared/unstable/forky.c
@@ -78,7 +78,8 @@ int forky_hasfeeders(t_object *x, t_glist *glist, int inno, t_symbol *outsym)
 }
 
 /* Not really a forky, just found no better place to put it in.
-   Used in bitwise signal binops (sickle).  Checked against msp2. */
+   Used in sickle's bitwise signal binops (which use forky_hasfeeders() too).
+   Checked against msp2. */
 t_int forky_getbitmask(int ac, t_atom *av)
 {
     t_int result = 0;
diff --git a/shared/unstable/fragile.c b/shared/unstable/fragile.c
index cd92b72..aed4d83 100644
--- a/shared/unstable/fragile.c
+++ b/shared/unstable/fragile.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997-2003 Miller Puckette, krzYszcz, and others.
+/* Copyright (c) 1997-2005 Miller Puckette, krzYszcz, and others.
  * For information on usage and redistribution, and for a DISCLAIMER OF ALL
  * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
 
@@ -15,6 +15,178 @@ int fragile_class_count(void)
     return (pd_objectmaker->c_nmethod);
 }
 
+/* Raising and voluntary mutation is a method of resolving name clashes.
+   A raised class hides other equivocal candidates.  A simpler method,
+   raising and lowering, works only in global scope, because, currently, Pd
+   has only one visibility stack.  Until this is changed, abstraction scope
+   will involve some kind of a hack for overriding global visibility stack. */
+
+void fragile_class_raise(t_symbol *cname, t_newmethod thiscall)
+{
+    t_methodentry *mp = pd_objectmaker->c_methods, *topmp = 0;
+    int count = pd_objectmaker->c_nmethod;
+    while (count--)
+    {
+	if (mp->me_name == cname)
+	{
+	    if (mp->me_fun == (t_gotfn)thiscall)
+	    {
+		if (topmp)
+		{
+		    t_methodentry auxmp;
+		    /* no linkage there, but anyway... */
+		    loud_warning(0, 0, "%s is raising itself...",
+				 cname->s_name);
+		    memcpy(&auxmp, mp, sizeof(t_methodentry));
+		    memcpy(mp, topmp, sizeof(t_methodentry));
+		    memcpy(topmp, &auxmp, sizeof(t_methodentry));
+		}
+		return;
+	    }
+	    else if (!topmp)
+		topmp = mp;
+	}
+	mp++;
+    }
+    loudbug_bug("fragile_class_raise");
+}
+
+t_pd *fragile_class_mutate(t_symbol *cname, t_newmethod thiscall,
+			   int ac, t_atom *av)
+{
+    t_newmethod fn;
+    t_atomtype *argtypes;
+    if (fn = fragile_class_getalien(cname, thiscall, &argtypes))
+    {
+	t_pd *z;
+	loud_warning(0, 0, "%s is mutating now...", cname->s_name);
+	if (z = fragile_class_createobject(cname, fn, argtypes, ac, av))
+	{
+	    post("...succeeded");
+	    return (z);
+	}
+	else post("...failed");
+    }
+    return (0);
+}
+
+t_newmethod fragile_class_getalien(t_symbol *cname, t_newmethod thiscall,
+				   t_atomtype **argtypesp)
+{
+    t_methodentry *mp = pd_objectmaker->c_methods;
+    int count = pd_objectmaker->c_nmethod;
+    while (count--)
+    {
+	if (mp->me_name == cname && mp->me_fun != (t_gotfn)thiscall)
+	{
+	    *argtypesp = mp->me_arg;
+	    return ((t_newmethod)mp->me_fun);
+	}
+	mp++;
+    }
+    return (0);
+}
+
+/* A specialized copy of pd_typedmess() from m_class.c,
+   somewhat simplified for readability. */
+
+typedef t_pd *(*t_newgimme)(t_symbol *s, int ac, t_atom *av);
+typedef t_pd *(*t_new0)(
+    t_floatarg, t_floatarg, t_floatarg, t_floatarg, t_floatarg);
+typedef t_pd *(*t_new1)(
+    t_symbol*,
+    t_floatarg, t_floatarg, t_floatarg, t_floatarg, t_floatarg);
+typedef t_pd *(*t_new2)(
+    t_symbol*, t_symbol*,
+    t_floatarg, t_floatarg, t_floatarg, t_floatarg, t_floatarg);
+typedef t_pd *(*t_new3)(
+    t_symbol*, t_symbol*, t_symbol*,
+    t_floatarg, t_floatarg, t_floatarg, t_floatarg, t_floatarg);
+typedef t_pd *(*t_new4)(
+    t_symbol*, t_symbol*, t_symbol*, t_symbol*,
+    t_floatarg, t_floatarg, t_floatarg, t_floatarg, t_floatarg);
+typedef t_pd *(*t_new5)(
+    t_symbol*, t_symbol*, t_symbol*, t_symbol*, t_symbol*,
+    t_floatarg, t_floatarg, t_floatarg, t_floatarg, t_floatarg);
+typedef t_pd *(*t_new6)(
+    t_symbol*, t_symbol*, t_symbol*, t_symbol*, t_symbol*, t_symbol*,
+    t_floatarg, t_floatarg, t_floatarg, t_floatarg, t_floatarg);
+
+t_pd *fragile_class_createobject(t_symbol *cname, t_newmethod callthis,
+				 t_atomtype *argtypes, int ac, t_atom *av)
+{
+    t_floatarg ff[MAXPDARG+1], *fp = ff;
+    t_symbol *ss[MAXPDARG+1], **sp = ss;
+    int nsymbols = 0;
+    t_atomtype wanttype;
+    if (*argtypes == A_GIMME)
+	return ((*((t_newgimme)(callthis)))(cname, ac, av));
+    if (ac > MAXPDARG)
+	ac = MAXPDARG;
+    while (wanttype = *argtypes++)
+    {
+	switch (wanttype)
+	{
+	case A_POINTER:
+	    goto badarg;
+	case A_FLOAT:
+	    if (!ac) goto badarg;
+	case A_DEFFLOAT:
+	    if (!ac) *fp = 0;
+	    else
+	    {
+		if (av->a_type == A_FLOAT)
+		    *fp = av->a_w.w_float;
+		else goto badarg;
+		ac--; av++;
+	    }
+	    fp++;
+	    break;
+	case A_SYMBOL:
+	    if (!ac) goto badarg;
+	case A_DEFSYM:
+	    if (!ac) *sp = &s_;
+	    else
+	    {
+		if (av->a_type == A_SYMBOL)
+		    *sp = av->a_w.w_symbol;
+		else if (av->a_type == A_FLOAT && av->a_w.w_float == 0)
+		    *sp = &s_;
+		else goto badarg;
+		ac--; av++;
+	    }
+	    nsymbols++;
+	    sp++;
+	}
+    }
+    switch (nsymbols)
+    {
+    case 0: return ((*(t_new0)(callthis))
+		    (ff[0], ff[1], ff[2], ff[3], ff[4]));
+    case 1: return ((*(t_new1)(callthis))
+		    (ss[0],
+		     ff[0], ff[1], ff[2], ff[3], ff[4]));
+    case 2: return ((*(t_new2)(callthis))
+		    (ss[0], ss[1],
+		     ff[0], ff[1], ff[2], ff[3], ff[4]));
+    case 3: return ((*(t_new3)(callthis))
+		    (ss[0], ss[1], ss[2],
+		     ff[0], ff[1], ff[2], ff[3], ff[4]));
+    case 4: return ((*(t_new4)(callthis))
+		    (ss[0], ss[1], ss[2], ss[3],
+		     ff[0], ff[1], ff[2], ff[3], ff[4]));
+    case 5: return ((*(t_new5)(callthis))
+		    (ss[0], ss[1], ss[2], ss[3], ss[4],
+		     ff[0], ff[1], ff[2], ff[3], ff[4]));
+    case 6: return ((*(t_new6)(callthis))
+		    (ss[0], ss[1], ss[2], ss[3], ss[4], ss[5],
+		     ff[0], ff[1], ff[2], ff[3], ff[4]));
+    }
+badarg:
+    loud_error(0, "bad creation arguments for class '%s'", cname->s_name);
+    return (0);
+}
+
 void fragile_class_printnames(char *msg, int firstndx, int lastndx)
 {
     t_methodentry *mp = pd_objectmaker->c_methods;
diff --git a/shared/unstable/fragile.h b/shared/unstable/fragile.h
index ad26384..6e79475 100644
--- a/shared/unstable/fragile.h
+++ b/shared/unstable/fragile.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2003 krzYszcz and others.
+/* Copyright (c) 2005 krzYszcz and others.
  * For information on usage and redistribution, and for a DISCLAIMER OF ALL
  * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
 
@@ -6,6 +6,13 @@
 #define __FRAGILE_H__
 
 int fragile_class_count(void);
+void fragile_class_raise(t_symbol *cname, t_newmethod thiscall);
+t_pd *fragile_class_mutate(t_symbol *cname, t_newmethod thiscall,
+			   int ac, t_atom *av);
+t_newmethod fragile_class_getalien(t_symbol *cname, t_newmethod thiscall,
+				   t_atomtype **argtypesp);
+t_pd *fragile_class_createobject(t_symbol *cname, t_newmethod callthis,
+				 t_atomtype *argtypes, int ac, t_atom *av);
 void fragile_class_printnames(char *msg, int firstndx, int lastndx);
 t_glist *fragile_garray_glist(void *arr);
 t_outconnect *fragile_outlet_connections(t_outlet *o);
diff --git a/shared/unstable/pd_imp.h b/shared/unstable/pd_imp.h
index bf659ed..513f927 100644
--- a/shared/unstable/pd_imp.h
+++ b/shared/unstable/pd_imp.h
@@ -6,8 +6,10 @@
 #define __PD_IMP_H__
 
 #ifdef PD_MINOR_VERSION
+/* 0.37 and up */
 #include "m_imp.h"
 #else
+/* 0.36 and down */
 
 typedef struct _methodentry
 {
diff --git a/test/cyclone/cyclone-test.pd b/test/cyclone/cyclone-test.pd
index f60a320..fefeb16 100644
--- a/test/cyclone/cyclone-test.pd
+++ b/test/cyclone/cyclone-test.pd
@@ -1,7 +1,7 @@
-#N canvas 150 47 650 459 12;
+#N canvas 331 48 650 459 12;
 #X obj 37 419 cyclone;
-#X msg 37 58 bang;
-#X msg 66 24 import;
+#X msg 76 133 bang;
+#X msg 61 95 import;
 #X obj 41 240 forward texthelp;
 #X obj 61 302 r texthelp;
 #X msg 50 272 send binhelp;
@@ -9,19 +9,30 @@
 #X obj 88 329 r binhelp;
 #X obj 88 358 sprintf import ../../../ref/c74help/bin/%s.help;
 #X obj 61 389 sprintf import ../../../ref/c74help/text/%s.help;
-#X msg 123 201 buffir~;
-#X msg 41 197 record~;
-#X msg 209 201 fffb~;
-#X msg 284 201 pictctrl;
+#X msg 130 203 buffir~;
+#X msg 41 203 record~;
+#X msg 220 203 fffb~;
+#X msg 295 203 pictctrl;
 #X msg 41 168 universal;
 #X msg 138 168 funbuff;
 #X msg 220 168 prob;
-#X obj 137 24 loadbang;
-#X obj 137 126 cyclone;
-#X msg 177 91 cd ../../../rob;
-#X msg 137 53 cd ../../../../ref;
-#X msg 213 126 pwd;
-#X obj 72 126 print;
+#X obj 137 16 loadbang;
+#X obj 137 133 cyclone;
+#X msg 183 95 cd ../../../rob;
+#X obj 307 272 cyclone;
+#X obj 390 240 loadbang;
+#X msg 390 269 cd ../krzYszcz/max-help;
+#X msg 393 203 import scope~;
+#X obj 307 310 print result;
+#X obj 394 168 print pwd;
+#X obj 394 133 r \$0-pwd;
+#X msg 321 133 pwd \$1;
+#X msg 321 51 bang;
+#X obj 321 95 symbol \$0-pwd;
+#X msg 145 95 cd;
+#X obj 206 133 print result;
+#X msg 296 168 matrix~;
+#X msg 137 55 cd ../../../ref;
 #X connect 1 0 18 0;
 #X connect 2 0 18 0;
 #X connect 4 0 9 0;
@@ -37,8 +48,17 @@
 #X connect 14 0 3 0;
 #X connect 15 0 3 0;
 #X connect 16 0 3 0;
-#X connect 17 0 20 0;
-#X connect 18 0 22 0;
+#X connect 17 0 33 0;
+#X connect 18 0 31 0;
 #X connect 19 0 18 0;
-#X connect 20 0 18 0;
-#X connect 21 0 18 0;
+#X connect 20 0 24 0;
+#X connect 21 0 22 0;
+#X connect 22 0 20 0;
+#X connect 23 0 20 0;
+#X connect 26 0 25 0;
+#X connect 27 0 18 0;
+#X connect 28 0 29 0;
+#X connect 29 0 27 0;
+#X connect 30 0 18 0;
+#X connect 32 0 3 0;
+#X connect 33 0 18 0;
diff --git a/test/cyclone/linedrive-test.pd b/test/cyclone/linedrive-test.pd
new file mode 100644
index 0000000..2a1dc36
--- /dev/null
+++ b/test/cyclone/linedrive-test.pd
@@ -0,0 +1,11 @@
+#N canvas 204 82 318 300 12;
+#X floatatom 34 39 5 0 0 0 - - -;
+#X floatatom 34 118 0 0 0 0 - - -;
+#X obj 34 76 linedrive 100 100 1.01 0;
+#X obj 32 209 maxmode;
+#X msg 124 171 set max;
+#X msg 32 171 set none;
+#X connect 0 0 2 0;
+#X connect 2 0 1 0;
+#X connect 4 0 3 0;
+#X connect 5 0 3 0;
diff --git a/test/cyclone/matrix-test.pd b/test/cyclone/matrix-test.pd
new file mode 100644
index 0000000..23ba18a
--- /dev/null
+++ b/test/cyclone/matrix-test.pd
@@ -0,0 +1,165 @@
+#N canvas 414 169 541 334 12;
+#X obj 21 60 sig~;
+#X floatatom 21 25 5 0 0 0 - - -;
+#X floatatom 21 258 5 0 0 0 - - -;
+#X obj 21 222 Snapshot~ 10;
+#X floatatom 143 258 5 0 0 0 - - -;
+#X obj 143 222 Snapshot~ 10;
+#X obj 104 60 sig~;
+#X floatatom 104 25 5 0 0 0 - - -;
+#X obj 186 179 matrix~ 3 3;
+#X floatatom 269 258 5 0 0 0 - - -;
+#X obj 269 222 Snapshot~ 10;
+#X obj 184 60 sig~;
+#X floatatom 184 25 5 0 0 0 - - -;
+#X msg 26 179 print;
+#X msg 284 101 connect 1 2;
+#X msg 283 138 connect 0 1;
+#X msg 388 101 disconnect 1 2;
+#X msg 390 138 disconnect 0 1;
+#X msg 285 25 connect 2 2;
+#X msg 389 25 disconnect 2 2;
+#X msg 284 60 connect 1 1;
+#X msg 391 60 disconnect 1 1;
+#N canvas 172 110 546 362 bigblock 0;
+#X obj 21 60 sig~;
+#X floatatom 21 25 5 0 0 0 - - -;
+#X floatatom 21 258 5 0 0 0 - - -;
+#X obj 21 222 Snapshot~ 10;
+#X floatatom 143 258 5 0 0 0 - - -;
+#X obj 143 222 Snapshot~ 10;
+#X obj 104 60 sig~;
+#X floatatom 104 25 5 0 0 0 - - -;
+#X floatatom 269 258 5 0 0 0 - - -;
+#X obj 269 222 Snapshot~ 10;
+#X obj 184 60 sig~;
+#X floatatom 184 25 5 0 0 0 - - -;
+#X msg 284 101 connect 1 2;
+#X msg 283 137 connect 0 1;
+#X msg 388 101 disconnect 1 2;
+#X msg 390 137 disconnect 0 1;
+#X msg 285 25 connect 2 2;
+#X msg 389 25 disconnect 2 2;
+#X msg 284 60 connect 1 1;
+#X msg 391 60 disconnect 1 1;
+#X obj 406 258 block~ 4096;
+#X msg 62 181 print;
+#X msg 62 143 debug;
+#X obj 343 181 print;
+#X obj 186 181 matrix~ 3 3 0.5;
+#X msg 22 101 ramp 3000;
+#X connect 0 0 24 0;
+#X connect 1 0 0 0;
+#X connect 3 0 2 0;
+#X connect 5 0 4 0;
+#X connect 6 0 24 1;
+#X connect 7 0 6 0;
+#X connect 9 0 8 0;
+#X connect 10 0 24 2;
+#X connect 11 0 10 0;
+#X connect 12 0 24 0;
+#X connect 13 0 24 0;
+#X connect 14 0 24 0;
+#X connect 15 0 24 0;
+#X connect 16 0 24 0;
+#X connect 17 0 24 0;
+#X connect 18 0 24 0;
+#X connect 19 0 24 0;
+#X connect 21 0 24 0;
+#X connect 22 0 24 0;
+#X connect 24 0 3 0;
+#X connect 24 1 5 0;
+#X connect 24 2 9 0;
+#X connect 24 3 23 0;
+#X connect 25 0 24 0;
+#X restore 413 258 pd bigblock;
+#X msg 88 139 debug;
+#X obj 306 179 print;
+#X msg 26 138 dump;
+#X msg 23 101 dumptarget;
+#N canvas 179 79 698 356 lists 0;
+#X obj 363 29 osc~ 220;
+#X obj 450 29 osc~ 230;
+#X obj 362 73 matrix~ 3 2 1;
+#X obj 362 165 dac~;
+#X obj 492 73 r \$0-mixer;
+#X floatatom 30 213 5 0 0 0 - - -;
+#X floatatom 112 213 5 0 0 0 - - -;
+#X obj 30 297 s \$0-mixer;
+#X msg 30 253 1 0 1 \$1;
+#X msg 112 253 1 1 1 \$1;
+#X msg 180 73 disconnect 0 0 1;
+#X floatatom 33 73 5 0 0 0 - - -;
+#X floatatom 115 73 5 0 0 0 - - -;
+#X obj 33 165 s \$0-mixer;
+#X msg 33 117 0 0 1 \$1;
+#X msg 115 117 0 1 1 \$1;
+#X msg 186 213 disconnect 1 0 1;
+#X floatatom 361 213 5 0 0 0 - - -;
+#X floatatom 443 213 5 0 0 0 - - -;
+#X obj 361 297 s \$0-mixer;
+#X msg 256 29 ramp 1000;
+#X msg 361 253 2 0 1 \$1;
+#X msg 443 253 2 1 1 \$1;
+#X msg 511 213 disconnect 2 0 1;
+#X msg 35 29 connect 0 0 1;
+#X msg 188 165 connect 1 0 1;
+#X msg 513 165 connect 2 0 1;
+#X obj 540 29 osc~ 235;
+#X obj 361 117 *~ 0.01;
+#X obj 443 117 *~ 0.01;
+#X msg 174 29 ramp 0;
+#X connect 0 0 2 0;
+#X connect 1 0 2 1;
+#X connect 2 0 28 0;
+#X connect 2 1 29 0;
+#X connect 4 0 2 0;
+#X connect 5 0 8 0;
+#X connect 6 0 9 0;
+#X connect 8 0 7 0;
+#X connect 9 0 7 0;
+#X connect 10 0 13 0;
+#X connect 11 0 14 0;
+#X connect 12 0 15 0;
+#X connect 14 0 13 0;
+#X connect 15 0 13 0;
+#X connect 16 0 7 0;
+#X connect 17 0 21 0;
+#X connect 18 0 22 0;
+#X connect 20 0 2 0;
+#X connect 21 0 19 0;
+#X connect 22 0 19 0;
+#X connect 23 0 19 0;
+#X connect 24 0 2 0;
+#X connect 25 0 2 0;
+#X connect 26 0 2 0;
+#X connect 27 0 2 2;
+#X connect 28 0 3 0;
+#X connect 29 0 3 1;
+#X connect 30 0 2 0;
+#X restore 413 221 pd lists;
+#X connect 0 0 8 0;
+#X connect 1 0 0 0;
+#X connect 3 0 2 0;
+#X connect 5 0 4 0;
+#X connect 6 0 8 1;
+#X connect 7 0 6 0;
+#X connect 8 0 3 0;
+#X connect 8 1 5 0;
+#X connect 8 2 10 0;
+#X connect 8 3 24 0;
+#X connect 10 0 9 0;
+#X connect 11 0 8 2;
+#X connect 12 0 11 0;
+#X connect 13 0 8 0;
+#X connect 14 0 8 0;
+#X connect 15 0 8 0;
+#X connect 16 0 8 0;
+#X connect 17 0 8 0;
+#X connect 18 0 8 0;
+#X connect 19 0 8 0;
+#X connect 20 0 8 0;
+#X connect 21 0 8 0;
+#X connect 23 0 8 0;
+#X connect 25 0 8 0;
+#X connect 26 0 8 0;
diff --git a/test/cyclone/maxmode-test.pd b/test/cyclone/maxmode-test.pd
index 75271e8..685814b 100644
--- a/test/cyclone/maxmode-test.pd
+++ b/test/cyclone/maxmode-test.pd
@@ -1,36 +1,38 @@
-#N canvas 356 180 524 287 12;
-#X obj 310 29 r #compatibility;
-#X obj 23 66 s #compatibility;
-#X msg 23 29 bang;
-#X obj 25 193 prepend test;
-#X msg 136 122 set this;
-#X msg 137 159 set that;
-#X msg 25 122 x;
-#X obj 310 66 print mode;
-#X msg 78 29 set max;
-#X msg 165 29 set barry;
-#X msg 77 122 bang;
-#X obj 25 228 print pp;
-#X msg 366 122 set this;
-#X msg 367 159 set that;
-#X msg 255 122 x;
-#X msg 307 122 bang;
-#X obj 255 228 print aa;
-#X obj 255 193 Append test;
-#X msg 155 193 bang;
-#X obj 155 228 maxmode;
-#X connect 0 0 7 0;
-#X connect 2 0 1 0;
-#X connect 3 0 11 0;
-#X connect 4 0 3 0;
-#X connect 5 0 3 0;
-#X connect 6 0 3 0;
-#X connect 8 0 1 0;
-#X connect 9 0 1 0;
-#X connect 10 0 3 0;
-#X connect 12 0 17 0;
-#X connect 13 0 17 0;
-#X connect 14 0 17 0;
-#X connect 15 0 17 0;
+#N canvas 289 109 635 329 12;
+#X obj 31 245 prepend test;
+#X msg 142 174 set this;
+#X msg 143 211 set that;
+#X msg 31 174 x;
+#X obj 273 111 print mode;
+#X msg 182 34 set max;
+#X msg 273 34 set barry;
+#X msg 83 174 bang;
+#X obj 31 280 print pp;
+#X msg 372 174 set this;
+#X msg 373 211 set that;
+#X msg 261 174 x;
+#X msg 313 174 bang;
+#X obj 261 280 print aa;
+#X obj 261 245 Append test;
+#X msg 397 34 bang;
+#X obj 182 75 maxmode;
+#X msg 112 34 set;
+#X obj 127 111 print result;
+#X msg 46 34 get;
+#X connect 0 0 8 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 5 0 16 0;
+#X connect 6 0 16 0;
+#X connect 7 0 0 0;
+#X connect 9 0 14 0;
+#X connect 10 0 14 0;
+#X connect 11 0 14 0;
+#X connect 12 0 14 0;
+#X connect 14 0 13 0;
+#X connect 15 0 16 0;
+#X connect 16 0 18 0;
+#X connect 16 1 4 0;
 #X connect 17 0 16 0;
-#X connect 18 0 19 0;
+#X connect 19 0 16 0;
diff --git a/test/toxy/kb.wid b/test/toxy/kb.wid
index 901db15..b3bd051 100644
--- a/test/toxy/kb.wid
+++ b/test/toxy/kb.wid
@@ -208,9 +208,6 @@ proc ::toxy::kbset {path target remote args} {
 
 ::toxy::kb .- .| . .#oct .#size
 
-# undo the "bind Canvas <1> {+focus %W}" from the setup.wid
-bind .- <FocusIn> {focus .^.c}
-
 #@ new
 set ::toxy::kbchord(.|) {}
 
diff --git a/test/toxy/multiscale.wid b/test/toxy/multiscale.wid
index bff9c4f..063146b 100644
--- a/test/toxy/multiscale.wid
+++ b/test/toxy/multiscale.wid
@@ -35,8 +35,7 @@ proc ::toxy::multiscale {path cvpath target remote count lo hi res dx dy bg} {
 	    }
 	    set id [$path create window $px $py -width $dx -height $dy \
 		-anchor nw -window $path.s$ndx -tags $path.s$ndx]
-#	    ::toxy::master $path.s$ndx $path $cvpath $target
-	    ::toxy::master $path.s$ndx $cvpath $target
+	    ::toxy::subwidget $path.s$ndx $path $cvpath $target
 	    incr px $dx
 	}
     }
@@ -51,6 +50,3 @@ proc ::toxy::multiscale {path cvpath target remote count lo hi res dx dy bg} {
 #. @list ::toxy::multiscale_list .- .#n .#2 .#1
 
 ::toxy::multiscale .- .^.c .| . .#n .#lo .#hi .#res .#dx .#dy .#bg
-
-# undo the "bind Canvas <1> {+focus %W}" from the setup.wid
-bind .- <FocusIn> {focus .^.c}
diff --git a/test/toxy/setup.wid b/test/toxy/setup.wid
index 98fe7fb..1d544c9 100644
--- a/test/toxy/setup.wid
+++ b/test/toxy/setup.wid
@@ -1,4 +1,4 @@
-package provide toxywidgets 0.1.0.14
+package provide toxywidgets 0.1.0.15
 
 # LATER keep standard widget setup in a .tcl file (transfered into a .wiq), and
 # glue separate .wid files with standard widget definitions into another .wiq
@@ -81,8 +81,15 @@ proc ::toxy::item_destroy {path varname} {
 }
 
 proc ::toxy::item_getconfig {path target} {
-    pd $target.rp _config $target.rp [$path cget -bg] \
-	[winfo reqwidth $path] [winfo reqheight $path] \
+    set wd [winfo reqwidth $path]
+    set ht [winfo reqheight $path]
+    if {$wd < 2 || $ht < 2} {
+# LATER rethink
+	update idletasks
+	set wd [winfo width $path]
+	set ht [winfo height $path]
+    }
+    pd $target.rp _config $target.rp [$path cget -bg] $wd $ht \
 	[catch {$path config -state normal}]\;
 }
 
@@ -185,7 +192,6 @@ proc ::toxy::master_motion {target cvpath x y} {
 }
 
 proc ::toxy::master {path cvpath target} {
-# FIXME subitem handling in megawidgets
     bind $path <ButtonRelease> "::toxy::master_release $target $cvpath %X %Y %b"
     bind $path <1> "::toxy::item_click $target $cvpath %X %Y %b 0"
     bind $path <Shift-1> "::toxy::item_click $target $cvpath %X %Y %b 1"
@@ -202,6 +208,41 @@ proc ::toxy::master {path cvpath target} {
     bind $path <B1-Motion> "::toxy::master_motion $target $cvpath %X %Y"
     bind $path <Enter> "::toxy::item_inout $target 1"
     bind $path <Leave> "::toxy::item_inout $target 0"
+
+    if {[catch {$path config -state normal}] == 0} {
+	bind $path <<disable>> "$path config -state disabled"
+	bind $path <<enable>> "$path config -state normal"
+    }
+
+    if {[winfo class $path] == "Canvas"} {
+# undo the "bind Canvas <1> {+focus %W}" from above
+	bind $path <FocusIn> "focus $cvpath"
+    }
+}
+
+# to be called explicitly from type initializer, LATER rethink
+proc ::toxy::subwidget {path parent cvpath target} {
+    bind $path <ButtonRelease> "::toxy::master_release $target $cvpath %X %Y %b"
+    bind $path <1> "::toxy::item_click $target $cvpath %X %Y %b 0"
+    bind $path <Shift-1> "::toxy::item_click $target $cvpath %X %Y %b 1"
+    bind $path <Control-1> "::toxy::item_click $target $cvpath %X %Y %b 2"
+    bind $path <Control-Shift-1> "::toxy::item_click $target $cvpath %X %Y %b 3"
+    bind $path <Alt-1> "::toxy::item_click $target $cvpath %X %Y %b 4"
+    bind $path <Alt-Shift-1> "::toxy::item_click $target $cvpath %X %Y %b 5"
+    bind $path <Alt-Control-1> "::toxy::item_click $target $cvpath %X %Y %b 6"
+    bind $path <Alt-Control-Shift-1> \
+	"::toxy::item_click $target $cvpath %X %Y %b 7"
+    bind $path <3> "::toxy::item_click $target $cvpath %X %Y %b 8"
+
+    bind $path <Motion> "::toxy::master_motion $target $cvpath %X %Y"
+    bind $path <B1-Motion> "::toxy::master_motion $target $cvpath %X %Y"
+    bind $path <Enter> "::toxy::item_inout $target 1"
+    bind $path <Leave> "::toxy::item_inout $target 0"
+
+    if {[catch {$path config -state normal}] == 0} {
+	bind $parent <<disable>> "+$path config -state disabled"
+	bind $parent <<enable>> "+$path config -state normal"
+    }
 }
 
 # standard widget types, LATER move to separate .wid files
diff --git a/toxy/Makefile.objects b/toxy/Makefile.objects
index f063097..1ac718e 100644
--- a/toxy/Makefile.objects
+++ b/toxy/Makefile.objects
@@ -2,6 +2,7 @@ TOT_OBJECTS = \
 unstable/forky.o \
 common/loud.o \
 common/grow.o \
+common/os.o \
 hammer/file.o \
 hammer/gui.o \
 common/props.o \
@@ -12,6 +13,7 @@ unstable/fragile.o \
 unstable/forky.o \
 common/loud.o \
 common/grow.o \
+common/os.o \
 hammer/file.o \
 common/props.o \
 toxy/scriptlet.o \
@@ -36,6 +38,7 @@ unstable/forky.o \
 common/loud.o \
 common/grow.o \
 common/dict.o \
+common/os.o \
 hammer/file.o \
 common/props.o \
 toxy/scriptlet.o
diff --git a/toxy/build_counter b/toxy/build_counter
index 3be6b67..3c2910e 100644
--- a/toxy/build_counter
+++ b/toxy/build_counter
@@ -1,7 +1,7 @@
 #define TOXY_VERSION "0.1"
 #define TOXY_RELEASE "alpha"
-#define TOXY_BUILD 14
+#define TOXY_BUILD 15
 
 #if 0
-TOXY_SNAPSHOT = 0.1-alpha14
+TOXY_SNAPSHOT = 0.1-alpha15
 #endif
diff --git a/toxy/notes.txt b/toxy/notes.txt
new file mode 100644
index 0000000..aa5119a
--- /dev/null
+++ b/toxy/notes.txt
@@ -0,0 +1,26 @@
+TODO for toxy
+
+DONE for toxy
+
+alpha15
+  * fixes for megawidgets
+    . setting sub-item bindings in ::toxy::subwidget
+      (to be called explicitly from type initializer)
+    . handling widget's state through virtual events
+    . getting implicit geometry (needed for Frame widgets)
+    . automatically rebinding focus for Canvas widgets
+
+alpha14
+  * 'redefine' message to widget
+  * version control, using package provide (both in tcl and parsed from pd)
+  * "> master" section removed:  master initializer defined directly
+    by proc ::toxy::master
+  * better kb: chords (shift-click), latch (control-click), dragging
+
+alpha13
+  * @new and @free handlers, defined in #@ new and  #@ free sections,
+    invoked by widget object creation and destruction
+  * optional sections #@ ini (aka #@ vis) appended to initializer (which still
+    defines in default section too -- old .wid files do not need updating)
+  * .#args parameter of message handlers, replaced (during scriptlet
+    evaluation) by all arguments of an invoking message
diff --git a/toxy/toxy-shared.include b/toxy/toxy-shared.include
index ec6c42c..69322e7 100644
--- a/toxy/toxy-shared.include
+++ b/toxy/toxy-shared.include
@@ -5,6 +5,8 @@ shared/common/grow.c
 shared/common/grow.h
 shared/common/dict.c
 shared/common/dict.h
+shared/common/os.c
+shared/common/os.h
 shared/hammer/file.c
 shared/hammer/file.h
 shared/hammer/gui.c
diff --git a/toxy/widget.c b/toxy/widget.c
index 6700812..9481b89 100644
--- a/toxy/widget.c
+++ b/toxy/widget.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2003-2004 krzYszcz and others.
+/* Copyright (c) 2003-2005 krzYszcz and others.
  * For information on usage and redistribution, and for a DISCLAIMER OF ALL
  * WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
 
@@ -21,7 +21,7 @@
 static t_class *makeshift_class;
 
 #ifdef KRZYSZCZ
-#define WIDGET_DEBUG
+//#define WIDGET_DEBUG
 //#define TOW_DEBUG
 //#define WIDGET_PROFILE
 #endif
@@ -77,7 +77,7 @@ typedef struct _widget
     int            x_width;
     int            x_height;
     t_symbol      *x_background;
-    int            x_hasstate;
+    int            x_hasstate;    /* no longer used, LATER rethink */
     int            x_disabled;
     int            x_selected;
     int            x_update;      /* see widget_update() */
@@ -293,8 +293,9 @@ static void widget_displace(t_gobj *z, t_glist *glist, int dx, int dy)
     t_widget *x = (t_widget *)z;
     t_text *t = (t_text *)z;
 #if 0
-    post("displace %d %d (%d %d -> %d %d)",
-	 dx, dy, t->te_xpix, t->te_ypix, t->te_xpix + dx, t->te_ypix + dy);
+    loudbug_post("displace %d %d (%d %d -> %d %d)",
+		 dx, dy, t->te_xpix, t->te_ypix,
+		 t->te_xpix + dx, t->te_ypix + dy);
 #endif
     t->te_xpix += dx;
     t->te_ypix += dy;
@@ -311,8 +312,8 @@ static void widget_select(t_gobj *z, t_glist *glist, int flag)
     char *mypathname = widget_getmypathname(x, glist)->s_name;
     if (flag)
     {
-	sys_vgui("%s config -bg blue %s\n", mypathname,
-		 (x->x_hasstate ? "-state disabled" : ""));
+	sys_vgui("%s config -bg blue\n", mypathname);
+	sys_vgui("event generate %s <<disable>>\n", mypathname);
 	x->x_selected = 1;
     }
     else
@@ -321,9 +322,9 @@ static void widget_select(t_gobj *z, t_glist *glist, int flag)
 	    sys_vgui("%s config -bg %s\n", mypathname,
 		     (x->x_background ? x->x_background->s_name : "gray"));
 	else
-	    sys_vgui("%s config -bg %s %s\n", mypathname,
-		     (x->x_background ? x->x_background->s_name : "gray"),
-		     (x->x_hasstate ? "-state normal" : ""));
+	    sys_vgui("%s config -bg %s \n", mypathname,
+		     (x->x_background ? x->x_background->s_name : "gray"));
+	sys_vgui("event generate %s <<enable>>\n", mypathname);
 	x->x_selected = 0;
     }
 }
@@ -342,7 +343,7 @@ static void widget_pushoptions(t_widget *x, int doit)
 #ifdef WIDGET_DEBUG
 	int sz;
 	char *dp = scriptlet_getcontents(x->x_transient, &sz);
-	post("vis: \"%s\"", dp);
+	loudbug_post("vis: \"%s\"", dp);
 #endif
 	if (doit)
 	{
@@ -898,8 +899,7 @@ static void widget__inout(t_widget *x, t_floatarg f)
 	    if (!x->x_selected)
 	    {
 		char *mypathname = widget_getmypathname(x, x->x_glist)->s_name;
-		if (x->x_hasstate)
-		    sys_vgui("%s config -state normal\n", mypathname);
+		sys_vgui("event generate %s <<enable>>\n", mypathname);
 	    }
 	    x->x_disabled = 0;
 	}
@@ -909,8 +909,7 @@ static void widget__inout(t_widget *x, t_floatarg f)
 	if (!x->x_selected)
 	{
 	    char *mypathname = widget_getmypathname(x, x->x_glist)->s_name;
-	    if (x->x_hasstate)
-		sys_vgui("%s config -state disabled\n", mypathname);
+	    sys_vgui("event generate %s <<disable>>\n", mypathname);
 	}
 	x->x_disabled = 1;
     }
-- 
cgit v1.2.1