aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorN.N. <krzyszcz@users.sourceforge.net>2004-12-08 15:40:14 +0000
committerN.N. <krzyszcz@users.sourceforge.net>2004-12-08 15:40:14 +0000
commitd5a39ff6469f8762218c00a34f4b0a120a56332b (patch)
tree8b5d6f1008f1ce09daf3e2a63b71f9c142911e80
parentb88a64023a08ed9a0e520058ef8be200515d9639 (diff)
various bug-fixes, maxmode, toxy .#args
svn path=/trunk/externals/miXed/; revision=2360
-rw-r--r--Makefile.common15
-rw-r--r--ViCious/cyclone/makefile21
-rw-r--r--ViCious/cyclone/objects20
-rw-r--r--ViCious/cyclone/snapfiles1
-rw-r--r--ViCious/toxy/snapfiles3
-rw-r--r--cyclone/Makefile.objects5
-rw-r--r--cyclone/Makefile.sources7
-rw-r--r--cyclone/build_counter4
-rw-r--r--cyclone/cyclone-shared.include6
-rw-r--r--cyclone/hammer/Append.c121
-rw-r--r--cyclone/hammer/Decode.c1
-rw-r--r--cyclone/hammer/Makefile.objects3
-rw-r--r--cyclone/hammer/Table.c1
-rw-r--r--cyclone/hammer/bangbang.c3
-rw-r--r--cyclone/hammer/coll.c1
-rw-r--r--cyclone/hammer/comment.c23
-rw-r--r--cyclone/hammer/counter.c17
-rw-r--r--cyclone/hammer/cycle.c1
-rw-r--r--cyclone/hammer/funbuff.c83
-rw-r--r--cyclone/hammer/gate.c3
-rw-r--r--cyclone/hammer/hammer.c7
-rw-r--r--cyclone/hammer/maximum.c1
-rw-r--r--cyclone/hammer/minimum.c1
-rw-r--r--cyclone/hammer/mtr.c13
-rw-r--r--cyclone/hammer/offer.c17
-rw-r--r--cyclone/hammer/past.c1
-rw-r--r--cyclone/hammer/prepend.c255
-rw-r--r--cyclone/hammer/prob.c1
-rw-r--r--cyclone/hammer/seq.c574
-rw-r--r--cyclone/hammer/switch.c3
-rw-r--r--cyclone/hammer/urn.c1
-rw-r--r--cyclone/shadow/Makefile6
-rw-r--r--cyclone/shadow/Makefile.objects1
-rw-r--r--cyclone/shadow/Makefile.sources1
-rw-r--r--cyclone/shadow/cyclone.c7
-rw-r--r--cyclone/sickle/Makefile.objects2
-rw-r--r--cyclone/sickle/buffir.c12
-rw-r--r--cyclone/sickle/curve.c128
-rw-r--r--cyclone/sickle/sickle.c7
-rw-r--r--shared/common/Makefile.sources6
-rw-r--r--shared/common/binport.c353
-rw-r--r--shared/common/binport.h2
-rw-r--r--shared/common/dict.c57
-rw-r--r--shared/common/dict.h5
-rw-r--r--shared/common/loud.c288
-rw-r--r--shared/common/loud.h29
-rw-r--r--shared/common/mifi.c1712
-rw-r--r--shared/common/mifi.h157
-rw-r--r--shared/common/port.c10
-rw-r--r--shared/getridof.baddeps18
-rw-r--r--shared/hammer/gui.c224
-rw-r--r--shared/hammer/gui.h14
-rw-r--r--shared/hammer/tree.c494
-rw-r--r--shared/hammer/tree.h67
-rw-r--r--shared/toxy/scriptlet.c143
-rw-r--r--test/cyclone/offer-test.pd29
-rw-r--r--test/toxy/setup.wid38
-rw-r--r--toxy/Makefile1
-rw-r--r--toxy/plustot.print.c12
-rw-r--r--toxy/widget.c189
-rw-r--r--toxy/widgettype.c87
-rw-r--r--toxy/widgettype.h21
62 files changed, 3434 insertions, 1899 deletions
diff --git a/Makefile.common b/Makefile.common
index fd57c44..2184624 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -23,12 +23,16 @@ include Makefile.objects
default: define_build all
ifeq ($(OS_NAME),Linux)
-# FIXME
-CC = gcc-2.95
X_SUFFIX = pd_linux
-DEFINES = -DUNIX
-OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+CC = gcc
LFLAGS = -export_dynamic -shared
+# FIXME strict-aliasing
+OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer -fno-strict-aliasing
+ifeq ($(shell whoami),krzYszcz)
+DEFINES = -DUNIX -DKRZYSZCZ
+else
+DEFINES = -DUNIX
+endif
endif
ifeq ($(OS_NAME),MinGW)
@@ -40,7 +44,7 @@ LFLAGS = -shared $(PD_DIR)/../bin/pd.dll
endif
ifeq ($(OS_NAME),Darwin)
-CC = gcc2
+CC = gcc
X_SUFFIX = pd_darwin
DEFINES = -DUNIX -DMACOSX
OPT_CFLAGS = -O2 -funroll-loops -fomit-frame-pointer
@@ -87,6 +91,7 @@ INCLUDES = -I. -I$(PD_DIR) -I$(SHARED_DIR)
WARN_CFLAGS = -Wall -W -Wstrict-prototypes -Werror \
-Wno-unused -Wno-parentheses -Wno-switch
+
DBG_CFLAGS =
CFLAGS = $(WARN_CFLAGS) $(OPT_CFLAGS) $(DEFINES) $(INCLUDES)
diff --git a/ViCious/cyclone/makefile b/ViCious/cyclone/makefile
index 68fc15c..6fcc05f 100644
--- a/ViCious/cyclone/makefile
+++ b/ViCious/cyclone/makefile
@@ -25,7 +25,7 @@ LIBS = $(VCLIBDIR)\libc.lib \
!INCLUDE snapfiles
!INCLUDE $(SRCDIR)\build_counter
-cyclone: cyclone.dll hammer.dll sickle.dll dummies.dll cyclist.exe
+cyclone: cyclone.dll hammer.dll sickle.dll dummies.dll maxmode.dll cyclist.exe
@cd $(ROOTDIR)
@$(ZIPCOMMAND) cyclone-$(CYCLONE_SNAPSHOT).zip $(SNAPFILES)
@@ -57,12 +57,21 @@ dummies.dll: $(DUMMIES_OBJECTS)
-del $(@:.dll=.exp)
-del $(@:.dll=.lib)
-cyclist.exe: $(SHAREDDIR)\common\binport.c
- -del /S $(SHAREDDIR)\common\binport.obj
- -cl $(CFLAGS) $(INCLUDES) /DBINPORT_STANDALONE /o $@ \
- $(VCLIBDIR)\libc.lib $(SHAREDDIR)\common\binport.c
+maxmode.dll: $(MAXMODE_OBJECTS)
+ -link /dll /out:$@ $(LIBS) $** /export:$(@:.dll=_setup)
+ -@copy $@ $(EXTDIR)
+ -@move $@ $(BINDIR)
+ -del $(@:.dll=.exp)
+ -del $(@:.dll=.lib)
+
+cyclist.exe: $(SHAREDDIR)\common\binport.c \
+ $(SHAREDDIR)\common\lex.c $(SHAREDDIR)\unstable\standalone.c
+ -del /S $(SHAREDDIR)\common\binport.obj $(SHAREDDIR)\common\lex.obj
+ -cl $(CFLAGS) $(INCLUDES) /DMIXED_STANDALONE /o $@ \
+ $(VCLIBDIR)\libc.lib $(SHAREDDIR)\common\binport.c \
+ $(SHAREDDIR)\common\lex.c $(SHAREDDIR)\unstable\standalone.c
-@move $@ $(BINDIR)
- -del /S binport.obj
+ -del /S binport.obj lex.obj
.c.obj: ; cl /c $(CFLAGS) $(INCLUDES) /Fo$*.obj $*.c
diff --git a/ViCious/cyclone/objects b/ViCious/cyclone/objects
index 1790c79..c74d47b 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\lex.obj \
$(SHAREDDIR)\common\binport.obj \
$(SHAREDDIR)\common\port.obj \
$(SHAREDDIR)\hammer\file.obj \
@@ -98,9 +99,8 @@ HAMMER_OBJECTS = $(ALL_HAMMERS) \
$(SHAREDDIR)\common\grow.obj \
$(SHAREDDIR)\common\rand.obj \
$(SHAREDDIR)\common\vefl.obj \
- $(SHAREDDIR)\common\sq.obj \
- $(SHAREDDIR)\common\bifi.obj \
$(SHAREDDIR)\common\mifi.obj \
+ $(SHAREDDIR)\common\lex.obj \
$(SHAREDDIR)\common\binport.obj \
$(SHAREDDIR)\common\port.obj \
$(SHAREDDIR)\hammer\file.obj \
@@ -108,8 +108,7 @@ HAMMER_OBJECTS = $(ALL_HAMMERS) \
$(SHAREDDIR)\hammer\tree.obj \
$(SHAREDDIR)\unstable\forky.obj \
$(SHAREDDIR)\unstable\fragile.obj \
- $(SHAREDDIR)\unstable\fringe.obj \
- $(SHAREDDIR)\unstable\loader.obj
+ $(SHAREDDIR)\unstable\fringe.obj
ALL_SICKLES = \
$(SRCDIR)\sickle\abs.obj \
@@ -195,6 +194,8 @@ SICKLE_OBJECTS = $(ALL_SICKLES) \
$(SHAREDDIR)\common\loud.obj \
$(SHAREDDIR)\common\grow.obj \
$(SHAREDDIR)\common\vefl.obj \
+ $(SHAREDDIR)\common\clc.obj \
+ $(SHAREDDIR)\common\lex.obj \
$(SHAREDDIR)\common\binport.obj \
$(SHAREDDIR)\common\port.obj \
$(SHAREDDIR)\hammer\file.obj \
@@ -202,19 +203,20 @@ SICKLE_OBJECTS = $(ALL_SICKLES) \
$(SHAREDDIR)\sickle\arsic.obj \
$(SHAREDDIR)\unstable\forky.obj \
$(SHAREDDIR)\unstable\fragile.obj \
- $(SHAREDDIR)\unstable\fringe.obj \
- $(SHAREDDIR)\unstable\loader.obj
+ $(SHAREDDIR)\unstable\fringe.obj
DUMMIES_OBJECTS = \
$(SRCDIR)\shadow\dummies.obj \
$(SHAREDDIR)\common\loud.obj \
$(SHAREDDIR)\common\grow.obj \
+ $(SHAREDDIR)\common\lex.obj \
$(SHAREDDIR)\common\binport.obj \
$(SHAREDDIR)\common\port.obj \
$(SHAREDDIR)\unstable\forky.obj \
$(SHAREDDIR)\unstable\fragile.obj \
$(SHAREDDIR)\unstable\fringe.obj
-CYCLIST_OBJECTS = \
- $(SHAREDDIR)\common\binport.obj
-
+MAXMODE_OBJECTS = \
+ $(SRCDIR)\shadow\maxmode.obj \
+ $(SHAREDDIR)\common\loud.obj \
+ $(SHAREDDIR)\unstable\loader.obj
diff --git a/ViCious/cyclone/snapfiles b/ViCious/cyclone/snapfiles
index d5ce6de..d2b2a2f 100644
--- a/ViCious/cyclone/snapfiles
+++ b/ViCious/cyclone/snapfiles
@@ -3,6 +3,7 @@ SNAPFILES = \
miXed\bin\hammer.dll \
miXed\bin\sickle.dll \
miXed\bin\dummies.dll \
+ miXed\bin\maxmode.dll \
miXed\bin\cyclist.exe \
miXed\ViCious\cyclone\makefile \
miXed\ViCious\cyclone\objects \
diff --git a/ViCious/toxy/snapfiles b/ViCious/toxy/snapfiles
index d83b373..301180a 100644
--- a/ViCious/toxy/snapfiles
+++ b/ViCious/toxy/snapfiles
@@ -6,4 +6,5 @@ SNAPFILES = \
miXed\ViCious\toxy\objects \
miXed\ViCious\toxy\snapfiles \
miXed\LICENSE.txt \
- miXed\test\toxy\*.*
+ miXed\test\toxy*.* \
+ miXed\test\toxy\stress\*.*
diff --git a/cyclone/Makefile.objects b/cyclone/Makefile.objects
index db4f7f3..5199008 100644
--- a/cyclone/Makefile.objects
+++ b/cyclone/Makefile.objects
@@ -12,12 +12,13 @@ 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
HGUI_OBJECTS = hammer/gui.o common/loud.o
-HSEQ_OBJECTS = common/sq.o common/bifi.o common/mifi.o \
- hammer/file.o common/grow.o common/loud.o unstable/forky.o
+HSEQ_OBJECTS = common/mifi.o hammer/file.o \
+ common/grow.o common/loud.o unstable/forky.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
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 common/loud.o unstable/forky.o
SVEFL_OBJECTS = common/vefl.o sickle/sic.o common/loud.o unstable/fragile.o
SARSIC_OBJECTS = sickle/sic.o sickle/arsic.o common/vefl.o \
diff --git a/cyclone/Makefile.sources b/cyclone/Makefile.sources
index e9aacd5..0c338fe 100644
--- a/cyclone/Makefile.sources
+++ b/cyclone/Makefile.sources
@@ -11,7 +11,6 @@ hammer/asin.c \
hammer/Bucket.c \
hammer/cartopol.c \
hammer/cosh.c \
-hammer/counter.c \
hammer/flush.c \
hammer/forward.c \
hammer/fromsymbol.c \
@@ -40,6 +39,7 @@ HLOUD_SOURCES = \
hammer/anal.c \
hammer/bangbang.c \
hammer/Borax.c \
+hammer/counter.c \
hammer/cycle.c \
hammer/decide.c \
hammer/Decode.c \
@@ -182,11 +182,14 @@ sickle/poltocar.c
SGROW_TILDE = $(TILDE)
SGROW_SOURCES = \
sickle/click.c \
-sickle/curve.c \
sickle/frameaccum.c \
sickle/framedelta.c \
sickle/Line.c
+SGROWCLC_TILDE = $(TILDE)
+SGROWCLC_SOURCES = \
+sickle/curve.c
+
SGROWFORKY_TILDE = $(TILDE)
SGROWFORKY_SOURCES = \
sickle/Scope.c
diff --git a/cyclone/build_counter b/cyclone/build_counter
index fa90455..acc65a6 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 49
+#define CYCLONE_BUILD 50
#if 0
-CYCLONE_SNAPSHOT = 0.1-alpha49
+CYCLONE_SNAPSHOT = 0.1-alpha50
#endif
diff --git a/cyclone/cyclone-shared.include b/cyclone/cyclone-shared.include
index 6604d19..26662ac 100644
--- a/cyclone/cyclone-shared.include
+++ b/cyclone/cyclone-shared.include
@@ -21,10 +21,8 @@ shared/common/rand.c
shared/common/rand.h
shared/common/vefl.c
shared/common/vefl.h
-shared/common/sq.c
-shared/common/sq.h
-shared/common/bifi.c
-shared/common/bifi.h
+shared/common/clc.c
+shared/common/clc.h
shared/common/mifi.c
shared/common/mifi.h
shared/hammer/file.c
diff --git a/cyclone/hammer/Append.c b/cyclone/hammer/Append.c
index 0cdea60..ad615d5 100644
--- a/cyclone/hammer/Append.c
+++ b/cyclone/hammer/Append.c
@@ -1,4 +1,4 @@
-/* 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. */
@@ -21,9 +21,17 @@ typedef struct _append
int x_entered;
int x_auxsize;
t_atom *x_auxbuf;
+ t_pd *x_proxy;
} t_append;
+typedef struct _appendxy
+{
+ t_pd xy_pd;
+ t_append *xy_owner;
+} t_appendxy;
+
static t_class *append_class;
+static t_class *appendxy_class;
/* Usually a preallocation method is used, except in special cases of:
1) reentrant output request, or 2) an output request which would cause
@@ -32,8 +40,7 @@ static t_class *append_class;
A separately preallocated output buffer is not used, thus avoiding
memcpying of the stored message (a small performance gain when the
preallocation method is chosen). Instead, self-invoked 'set'
- messages are postponed, using an auxiliary buffer.
-*/
+ messages are postponed, using an auxiliary buffer. */
/* Any Append's output goes through outlet_anything() -> typedmess() */
@@ -132,9 +139,11 @@ static void append_symbol(t_append *x, t_symbol *s)
/* LATER gpointer */
-static void append_set(t_append *x, t_symbol *s, int ac, t_atom *av)
+static void append_doset(t_append *x, t_symbol *s, int ac, t_atom *av)
{
int newsize = ac * 2;
+ if (s)
+ newsize += 2;
if (newsize > 0)
{
if (x->x_entered)
@@ -147,7 +156,15 @@ static void append_set(t_append *x, t_symbol *s, int ac, t_atom *av)
}
if (x->x_auxbuf = getbytes(newsize * sizeof(*x->x_auxbuf)))
{
- memcpy(x->x_auxbuf + ac, av, ac * sizeof(*x->x_auxbuf));
+ t_atom *ap = x->x_auxbuf + ac;
+ if (s)
+ {
+ ap++;
+ SETSYMBOL(ap, s);
+ ap++;
+ }
+ if (ac)
+ memcpy(ap, av, ac * sizeof(*x->x_auxbuf));
x->x_auxsize = newsize;
}
}
@@ -161,19 +178,86 @@ static void append_set(t_append *x, t_symbol *s, int ac, t_atom *av)
APPEND_INISIZE, x->x_messini,
sizeof(*x->x_messbuf));
if (sz != newsize)
+ {
ac = sz / 2; /* LATER rethink */
+ if (s)
+ ac--;
+ }
+ }
+ if (s)
+ {
+ append_setnatoms(x, ac + 1);
+ ap = x->x_message;
+ SETSYMBOL(ap, s);
+ ap++;
+ }
+ else
+ {
+ append_setnatoms(x, ac);
+ ap = x->x_message;
}
- append_setnatoms(x, ac);
- ap = x->x_message;
while (ac--) *ap++ = *av++;
}
}
}
+static void append_set(t_append *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (shared_getmaxcompatibility())
+ append_doset(x, 0, ac, av);
+ else
+ append_anything(x, s, ac, av);
+}
+
+static void appendxy_bang(t_appendxy *xy)
+{
+ append_doset(xy->xy_owner, 0, 0, 0); /* LATER rethink */
+}
+
+static void appendxy_float(t_appendxy *xy, t_float f)
+{
+ t_atom at;
+ SETFLOAT(&at, f);
+ append_doset(xy->xy_owner, 0, 1, &at);
+}
+
+static void appendxy_symbol(t_appendxy *xy, t_symbol *s)
+{
+ t_atom at;
+ if (!s || s == &s_)
+ s = &s_symbol; /* LATER rethink */
+ SETSYMBOL(&at, s);
+ append_doset(xy->xy_owner, 0, 1, &at);
+}
+
+static void appendxy_list(t_appendxy *xy, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ append_doset(xy->xy_owner, 0, ac, av);
+ else
+ { /* LATER rethink */
+ t_atom at;
+ SETSYMBOL(&at, &s_list);
+ append_doset(xy->xy_owner, 0, 1, &at);
+ }
+}
+
+static void appendxy_anything(t_appendxy *xy, t_symbol *s, int ac, t_atom *av)
+{
+ append_doset(xy->xy_owner, s, ac, av);
+}
+
static void append_free(t_append *x)
{
if (x->x_messbuf != x->x_messini)
freebytes(x->x_messbuf, x->x_size * sizeof(*x->x_messbuf));
+ if (x->x_auxbuf)
+ {
+ bug("append_free"); /* LATER rethink */
+ freebytes(x->x_auxbuf, x->x_auxsize * sizeof(*x->x_auxbuf));
+ }
+ if (x->x_proxy)
+ pd_free(x->x_proxy);
}
static void *append_new(t_symbol *s, int ac, t_atom *av)
@@ -184,9 +268,20 @@ static void *append_new(t_symbol *s, int ac, t_atom *av)
x->x_messbuf = x->x_messini;
x->x_auxbuf = 0;
x->x_entered = 0;
- outlet_new((t_object *)x, &s_anything);
append_setnatoms(x, 0);
- append_set(x, 0, ac, av);
+ shared_usecompatibility();
+ if (ac)
+ {
+ x->x_proxy = 0;
+ append_doset(x, 0, ac, av);
+ }
+ else
+ {
+ x->x_proxy = pd_new(appendxy_class);
+ ((t_appendxy *)x->x_proxy)->xy_owner = x;
+ inlet_new((t_object *)x, x->x_proxy, 0, 0);
+ }
+ outlet_new((t_object *)x, &s_anything);
return (x);
}
@@ -204,4 +299,12 @@ void Append_setup(void)
class_addanything(append_class, append_anything);
class_addmethod(append_class, (t_method)append_set,
gensym("set"), A_GIMME, 0);
+
+ appendxy_class = class_new(gensym("append"), 0, 0, sizeof(t_appendxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addbang(appendxy_class, appendxy_bang);
+ class_addfloat(appendxy_class, appendxy_float);
+ class_addsymbol(appendxy_class, appendxy_symbol);
+ class_addlist(appendxy_class, appendxy_list);
+ class_addanything(appendxy_class, appendxy_anything);
}
diff --git a/cyclone/hammer/Decode.c b/cyclone/hammer/Decode.c
index 4dee7e0..77d8f38 100644
--- a/cyclone/hammer/Decode.c
+++ b/cyclone/hammer/Decode.c
@@ -78,6 +78,7 @@ static void *Decode_new(t_floatarg val)
nouts = DECODE_DEFOUTS;
if (nouts > DECODE_C74MAXOUTS)
{
+ shared_usecompatibility();
loud_incompatible_max(Decode_class, DECODE_C74MAXOUTS, "outlets");
if (!(outs = (t_outlet **)getbytes(nouts * sizeof(*outs))))
return (0);
diff --git a/cyclone/hammer/Makefile.objects b/cyclone/hammer/Makefile.objects
index 76de16f..78bff7e 100644
--- a/cyclone/hammer/Makefile.objects
+++ b/cyclone/hammer/Makefile.objects
@@ -6,9 +6,8 @@ common/loud.o \
common/grow.o \
common/rand.o \
common/vefl.o \
-common/sq.o \
-common/bifi.o \
common/mifi.o \
+common/lex.o \
common/binport.o \
common/port.o \
hammer/file.o \
diff --git a/cyclone/hammer/Table.c b/cyclone/hammer/Table.c
index e366cbb..e613293 100644
--- a/cyclone/hammer/Table.c
+++ b/cyclone/hammer/Table.c
@@ -233,6 +233,7 @@ static void tablecommon_doread(t_tablecommon *cc, t_symbol *fn, t_canvas *cv)
char buf[MAXPDSTRING];
if (!fn)
return; /* CHECKME complaint */
+ /* FIXME use open_via_path() */
if (cv || (cv = cc->c_lastcanvas)) /* !cv: 'read' w/o arg */
canvas_makefilename(cv, fn->s_name, buf, MAXPDSTRING);
else
diff --git a/cyclone/hammer/bangbang.c b/cyclone/hammer/bangbang.c
index 695a558..d1eb53a 100644
--- a/cyclone/hammer/bangbang.c
+++ b/cyclone/hammer/bangbang.c
@@ -47,7 +47,10 @@ static void *bangbang_new(t_floatarg val)
if (nouts < BANGBANG_MINOUTS)
nouts = BANGBANG_DEFOUTS;
if (nouts > BANGBANG_C74MAXOUTS)
+ {
+ shared_usecompatibility();
loud_incompatible_max(bangbang_class, BANGBANG_C74MAXOUTS, "outlets");
+ }
if (nouts > BANGBANG_DEFOUTS)
{
if (!(outs = (t_outlet **)getbytes(nouts * sizeof(*outs))))
diff --git a/cyclone/hammer/coll.c b/cyclone/hammer/coll.c
index 850c2c7..031f6c6 100644
--- a/cyclone/hammer/coll.c
+++ b/cyclone/hammer/coll.c
@@ -591,6 +591,7 @@ static void collcommon_doread(t_collcommon *cc, t_symbol *fn, t_canvas *cv)
char buf[MAXPDSTRING];
if (!fn && !(fn = cc->c_filename)) /* !fn: 'readagain' */
return;
+ /* FIXME use open_via_path() */
if (cv || (cv = cc->c_lastcanvas)) /* !cv: 'read' w/o arg, 'readagain' */
canvas_makefilename(cv, fn->s_name, buf, MAXPDSTRING);
else
diff --git a/cyclone/hammer/comment.c b/cyclone/hammer/comment.c
index 72e8a57..03d4d03 100644
--- a/cyclone/hammer/comment.c
+++ b/cyclone/hammer/comment.c
@@ -1,4 +1,4 @@
-/* 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. */
@@ -200,6 +200,9 @@ static void comment_validate(t_comment *x, t_glist *glist)
static void comment_grabbedkey(void *z, t_floatarg f)
{
/* LATER think about replacing #key binding/comment_float() with grabbing */
+#ifdef COMMENT_DEBUG
+ post("comment_grabbedkey %g", f);
+#endif
}
static void comment_dograb(t_comment *x)
@@ -520,7 +523,7 @@ static void comment_float(t_comment *x, t_float f)
/* LATER delete the box... this causes reentrancy
problems now. */
/* glist_delete(x->x_glist, &x->x_text->te_g); */
- return;
+ goto donefloat;
}
else if (x->x_selstart && (x->x_selstart == x->x_selend))
x->x_selstart--;
@@ -556,6 +559,10 @@ static void comment_float(t_comment *x, t_float f)
}
}
else bug("comment_float");
+ donefloat:;
+#ifdef COMMENT_DEBUG
+ post("donefloat");
+#endif
}
static void comment_list(t_comment *x, t_symbol *s, int ac, t_atom *av)
@@ -625,7 +632,7 @@ static void comment_list(t_comment *x, t_symbol *s, int ac, t_atom *av)
canvas_unsetcurrent(x->x_glist);
canvas_dirty(x->x_glist, 1);
clock_delay(x->x_transclock, 0); /* LATER rethink */
- return;
+ goto donelist;
}
else if (!strcmp(keysym->s_name, "F5"))
{
@@ -640,11 +647,15 @@ static void comment_list(t_comment *x, t_symbol *s, int ac, t_atom *av)
canvas_unsetcurrent(x->x_glist);
canvas_dirty(x->x_glist, 1);
binbuf_free(bb);
- return;
+ goto donelist;
}
- else return;
+ else goto donelist;
comment_update(x);
}
+ donelist:;
+#ifdef COMMENT_DEBUG
+ post("donelist");
+#endif
}
static void comment_free(t_comment *x)
@@ -830,6 +841,8 @@ void comment_setup(void)
pd $target _click $target [$cvname canvasx $x] [$cvname canvasy $y]\
[$cvname index $tag @$x,$y] [$cvname bbox $tag]\\;}\n");
+ /* LATER think how to conditionally (FORKY_VERSION >= 38)
+ replace puts with pdtk_post */
sys_gui("proc comment_entext {enc tt} {\n\
set rr [catch {encoding convertfrom $enc $tt} tt1]\n\
if {$rr == 0} {concat $tt1} else {\n\
diff --git a/cyclone/hammer/counter.c b/cyclone/hammer/counter.c
index 3117e6c..73cd841 100644
--- a/cyclone/hammer/counter.c
+++ b/cyclone/hammer/counter.c
@@ -1,4 +1,4 @@
-/* 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. */
@@ -11,6 +11,7 @@
of checking -- I will not bother, until there is some feedback. */
#include "m_pd.h"
+#include "common/loud.h"
#define COUNTER_UP 0
#define COUNTER_DOWN 1
@@ -315,12 +316,16 @@ static void *counter_new(t_floatarg f1, t_floatarg f2, t_floatarg f3)
int i2 = (int)f2;
int i3 = (int)f3;
int i;
- static int warned = 0;
- if (!warned)
+ shared_usecompatibility();
+ if (shared_getmaxcompatibility())
{
- post("warning: counter is not fully compatible, \
-please report differences");
- warned = 1;
+ static int warned = 0;
+ if (!warned)
+ {
+ post("warning: counter is not fully compatible,\
+ please report differences");
+ warned = 1;
+ }
}
x->x_dir = COUNTER_UP;
x->x_inc = 1; /* previous value required by counter_dir() */
diff --git a/cyclone/hammer/cycle.c b/cyclone/hammer/cycle.c
index 2e6dbd0..244a64d 100644
--- a/cyclone/hammer/cycle.c
+++ b/cyclone/hammer/cycle.c
@@ -119,6 +119,7 @@ static void *cycle_new(t_floatarg f1, t_floatarg f2)
nouts = CYCLE_DEFOUTS;
if (nouts > CYCLE_C74MAXOUTS)
{
+ shared_usecompatibility();
loud_incompatible_max(cycle_class, CYCLE_C74MAXOUTS, "outlets");
/* CHECKED: max clips with an error:
``perhaps you were trying to make an oscillator?'' */
diff --git a/cyclone/hammer/funbuff.c b/cyclone/hammer/funbuff.c
index 3ce6080..ff4773b 100644
--- a/cyclone/hammer/funbuff.c
+++ b/cyclone/hammer/funbuff.c
@@ -1,9 +1,8 @@
-/* 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. */
#include "m_pd.h"
-#include "unstable/fragile.h"
#include "common/loud.h"
#include "common/vefl.h"
#include "hammer/tree.h"
@@ -49,13 +48,16 @@ static void funbuff_bang(t_funbuff *x)
{
/* LATER consider using extra fields, updated on the fly */
count = 1;
- xmin = np->n_index;
- xmax = x->x_tree.t_last->n_index;
- ymin = ymax = np->n_value;
+ xmin = np->n_key;
+ xmax = x->x_tree.t_last->n_key;
+ ymin = ymax = HAMMERNODE_GETFLOAT(np);
while (np = np->n_next)
{
- if (np->n_value < ymin) ymin = np->n_value;
- else if (np->n_value > ymax) ymax = np->n_value;
+ t_float f = HAMMERNODE_GETFLOAT(np);
+ if (f < ymin)
+ ymin = f;
+ else if (f > ymax)
+ ymax = f;
count++;
}
}
@@ -75,15 +77,14 @@ static void funbuff_float(t_funbuff *x, t_float f)
t_hammernode *np;
if (x->x_valueset)
{
- if (np = hammertree_insert(&x->x_tree, ndx))
- np->n_value = x->x_value;
+ np = hammertree_insertfloat(&x->x_tree, ndx, x->x_value, 1);
x->x_valueset = 0;
}
else if (np = hammertree_closest(&x->x_tree, ndx, 0))
- funbuff_dooutput(x, np->n_value, x->x_lastdelta);
+ funbuff_dooutput(x, HAMMERNODE_GETFLOAT(np), x->x_lastdelta);
/* CHECKED pointer is updated --
'next' outputs np also in a !valueset case (it is sent twice) */
- x->x_pointer = np;
+ x->x_pointer = np; /* FIXME */
x->x_pointerset = 0;
}
@@ -120,9 +121,10 @@ static void funbuff_min(t_funbuff *x)
t_hammernode *np;
if (np = x->x_tree.t_first) /* CHECKED nop if empty */
{
- t_float result = np->n_value;
+ t_float result = HAMMERNODE_GETFLOAT(np);
while (np = np->n_next)
- if (np->n_value < result) result = np->n_value;
+ if (HAMMERNODE_GETFLOAT(np) < result)
+ result = HAMMERNODE_GETFLOAT(np);
funbuff_dooutput(x, result, x->x_lastdelta);
/* CHECKED pointer not updated */
}
@@ -134,9 +136,10 @@ static void funbuff_max(t_funbuff *x)
t_hammernode *np;
if (np = x->x_tree.t_first) /* CHECKED nop if empty */
{
- t_float result = np->n_value;
+ t_float result = HAMMERNODE_GETFLOAT(np);
while (np = np->n_next)
- if (np->n_value > result) result = np->n_value;
+ if (HAMMERNODE_GETFLOAT(np) > result)
+ result = HAMMERNODE_GETFLOAT(np);
funbuff_dooutput(x, result, x->x_lastdelta);
/* CHECKED pointer not updated */
}
@@ -156,10 +159,10 @@ static void funbuff_next(t_funbuff *x)
if (x->x_pointerset)
x->x_lastdelta = 0;
else if (np->n_prev)
- x->x_lastdelta = np->n_index - np->n_prev->n_index;
+ x->x_lastdelta = np->n_key - np->n_prev->n_key;
else
x->x_lastdelta = 0; /* CHECKED corrupt delta sent here... */
- funbuff_dooutput(x, np->n_value, x->x_lastdelta);
+ funbuff_dooutput(x, HAMMERNODE_GETFLOAT(np), x->x_lastdelta);
x->x_pointer = np->n_next;
x->x_pointerset = 0;
}
@@ -185,10 +188,9 @@ static void funbuff_set(t_funbuff *x, t_symbol *s, int ac, t_atom *av)
funbuff_clear(x); /* CHECKED the contents is replaced */
while (ac--)
{
- t_hammernode *np;
- if (np = hammertree_insert(&x->x_tree, (int)av++->a_w.w_float))
- np->n_value = av++->a_w.w_float;
- else return;
+ int ndx = (int)av++->a_w.w_float;
+ if (!hammertree_insertfloat(&x->x_tree, ndx, av++->a_w.w_float, 1))
+ return;
ac--;
}
}
@@ -199,6 +201,7 @@ static void funbuff_doread(t_funbuff *x, t_symbol *fn)
int ac;
t_atom *av;
char buf[MAXPDSTRING];
+ /* FIXME use open_via_path() */
canvas_makefilename(x->x_canvas, fn->s_name, buf, MAXPDSTRING);
binbuf_read(bb, buf, "", 0);
if ((ac = binbuf_getnatom(bb)) &&
@@ -226,7 +229,7 @@ static void funbuff_dowrite(t_funbuff *x, t_symbol *fn)
t_hammernode *np;
binbuf_addv(bb, "s", gensym("funbuff"));
for (np = x->x_tree.t_first; np; np = np->n_next)
- binbuf_addv(bb, "if", np->n_index, np->n_value);
+ binbuf_addv(bb, "if", np->n_key, HAMMERNODE_GETFLOAT(np));
canvas_makefilename(x->x_canvas, fn->s_name, buf, MAXPDSTRING);
binbuf_write(bb, buf, "", 0);
binbuf_free(bb);
@@ -248,7 +251,7 @@ static void funbuff_embedhook(t_pd *z, t_binbuf *bb, t_symbol *bindsym)
{
binbuf_addv(bb, "ss", bindsym, gensym("set"));
for (; np; np = np->n_next)
- binbuf_addv(bb, "if", np->n_index, np->n_value);
+ binbuf_addv(bb, "if", np->n_key, HAMMERNODE_GETFLOAT(np));
binbuf_addsemi(bb);
}
}
@@ -283,11 +286,11 @@ static void funbuff_delete(t_funbuff *x, t_symbol *s, int ac, t_atom *av)
int ndx = (int)av->a_w.w_float;
t_hammernode *np;
if ((np = hammertree_search(&x->x_tree, ndx)) &&
- (ac == 1 || np->n_value == av[1].a_w.w_float))
+ (ac == 1 || HAMMERNODE_GETFLOAT(np) == av[1].a_w.w_float))
{
if (np == x->x_pointer)
x->x_pointer = 0; /* CHECKED corrupt pointer left here... */
- hammertree_delete(&x->x_tree, np);
+ hammertree_delete(&x->x_tree, np); /* FIXME */
}
/* CHECKED mismatch silently ignored */
}
@@ -302,8 +305,8 @@ static void funbuff_find(t_funbuff *x, t_floatarg f)
do
{
/* CHECKED lastdelta preserved */
- if (np->n_value == f)
- funbuff_dooutput(x, np->n_index, x->x_lastdelta);
+ if (HAMMERNODE_GETFLOAT(np) == f)
+ funbuff_dooutput(x, np->n_key, x->x_lastdelta);
}
while (np = np->n_next);
/* CHECKED no bangout, no complaint if nothing found */
@@ -318,9 +321,9 @@ static void funbuff_dump(t_funbuff *x)
{
do
{
- x->x_lastdelta = np->n_value; /* CHECKED */
+ x->x_lastdelta = HAMMERNODE_GETFLOAT(np); /* CHECKED */
/* float value preserved (this is incompatible) */
- funbuff_dooutput(x, np->n_index, np->n_value);
+ funbuff_dooutput(x, np->n_key, x->x_lastdelta);
}
while (np = np->n_next);
/* CHECKED no bangout */
@@ -336,14 +339,14 @@ static void funbuff_dointerp(t_funbuff *x, t_floatarg f, int vsz, t_float *vec)
if (trunc > f) trunc--; /* CHECKME negative floats */
if (np1 = hammertree_closest(&x->x_tree, trunc, 0))
{
- float value = np1->n_value;
+ float value = HAMMERNODE_GETFLOAT(np1);
t_hammernode *np2 = np1->n_next;
if (np2)
{
- float delta = (float)(np2->n_index - np1->n_index);
+ float delta = (float)(np2->n_key - np1->n_key);
/* this is incompatible -- CHECKED float argument is silently
truncated (which does not make much sense here), CHECKME again */
- float frac = f - np1->n_index;
+ float frac = f - np1->n_key;
if (frac < 0 || frac >= delta)
{
bug("funbuff_dointerp");
@@ -364,12 +367,14 @@ static void funbuff_dointerp(t_funbuff *x, t_floatarg f, int vsz, t_float *vec)
vec += vndx;
frac = *vec + (vec[1] - *vec) * vfrac;
}
- value += (np2->n_value - np1->n_value) * frac;
+ value +=
+ (HAMMERNODE_GETFLOAT(np2) - HAMMERNODE_GETFLOAT(np1)) * frac;
}
funbuff_dooutput(x, value, x->x_lastdelta); /* CHECKME !np2 */
}
else if (np1 = hammertree_closest(&x->x_tree, trunc, 1))
- funbuff_dooutput(x, np1->n_value, x->x_lastdelta); /* CHECKME */
+ /* CHECKME */
+ funbuff_dooutput(x, HAMMERNODE_GETFLOAT(np1), x->x_lastdelta);
}
static void funbuff_interp(t_funbuff *x, t_floatarg f)
@@ -428,7 +433,7 @@ static void funbuff_undo(t_funbuff *x)
#ifdef HAMMERTREE_DEBUG
static void funbuff_debug(t_funbuff *x, t_floatarg f)
{
- hammertree_debug(&x->x_tree, (int)f);
+ hammertree_debug(&x->x_tree, (int)f, 0);
}
#endif
@@ -447,7 +452,7 @@ static void *funbuff_new(t_symbol *s)
x->x_pointerset = 0; /* CHECKME, rename to intraversal? */
x->x_lastdelta = 0;
x->x_embedflag = 0;
- hammertree_init(&x->x_tree, 0);
+ hammertree_inittyped(&x->x_tree, HAMMERTYPE_FLOAT, 0);
inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
outlet_new((t_object *)x, &s_float);
x->x_deltaout = outlet_new((t_object *)x, &s_float);
@@ -466,9 +471,9 @@ static void *funbuff_new(t_symbol *s)
void funbuff_setup(void)
{
funbuff_class = class_new(gensym("funbuff"),
- (t_newmethod)funbuff_new,
- (t_method)funbuff_free,
- sizeof(t_funbuff), 0, A_DEFSYM, 0);
+ (t_newmethod)funbuff_new,
+ (t_method)funbuff_free,
+ sizeof(t_funbuff), 0, A_DEFSYM, 0);
class_addbang(funbuff_class, funbuff_bang);
class_addfloat(funbuff_class, funbuff_float);
class_addmethod(funbuff_class, (t_method)funbuff_ft1,
diff --git a/cyclone/hammer/gate.c b/cyclone/hammer/gate.c
index 19035a5..80210cb 100644
--- a/cyclone/hammer/gate.c
+++ b/cyclone/hammer/gate.c
@@ -100,7 +100,10 @@ static void *gate_new(t_floatarg f1, t_floatarg f2)
if (nouts < GATE_MINOUTS)
nouts = GATE_DEFOUTS;
if (nouts > GATE_C74MAXOUTS)
+ {
+ shared_usecompatibility();
loud_incompatible_max(gate_class, GATE_C74MAXOUTS, "outlets");
+ }
nouts++; /* for convenience (the cost is one pointer) */
if (!(outs = (t_outlet **)getbytes(nouts * sizeof(*outs))))
return (0);
diff --git a/cyclone/hammer/hammer.c b/cyclone/hammer/hammer.c
index 3c4f3c2..ea4642c 100644
--- a/cyclone/hammer/hammer.c
+++ b/cyclone/hammer/hammer.c
@@ -1,4 +1,4 @@
-/* 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. */
@@ -76,6 +76,11 @@ void hammer_setup(void)
loud_errand(0, "without having hammer library preloaded");
return;
}
+ if (zgetfn(&pd_objectmaker, gensym("hammer")))
+ {
+ loud_error(0, "hammer is already loaded");
+ return;
+ }
if (!zgetfn(&pd_objectmaker, gensym("cyclone")))
post("this is hammer %s, %s %s build",
CYCLONE_VERSION, loud_ordinal(CYCLONE_BUILD), CYCLONE_RELEASE);
diff --git a/cyclone/hammer/maximum.c b/cyclone/hammer/maximum.c
index f7f01f1..b5f6069 100644
--- a/cyclone/hammer/maximum.c
+++ b/cyclone/hammer/maximum.c
@@ -75,6 +75,7 @@ static void *maximum_new(t_floatarg f)
t_maximum *x = (t_maximum *)pd_new(maximum_class);
x->x_last = 0; /* CHECKME */
x->x_test = f;
+ shared_usecompatibility();
floatinlet_new((t_object *)x, &x->x_test);
outlet_new((t_object *)x, &s_float);
return (x);
diff --git a/cyclone/hammer/minimum.c b/cyclone/hammer/minimum.c
index 415235d..71875fc 100644
--- a/cyclone/hammer/minimum.c
+++ b/cyclone/hammer/minimum.c
@@ -75,6 +75,7 @@ static void *minimum_new(t_floatarg f)
t_minimum *x = (t_minimum *)pd_new(minimum_class);
x->x_last = 0; /* CHECKME */
x->x_test = f;
+ shared_usecompatibility();
floatinlet_new((t_object *)x, &x->x_test);
outlet_new((t_object *)x, &s_float);
return (x);
diff --git a/cyclone/hammer/mtr.c b/cyclone/hammer/mtr.c
index ecc80d3..51ba856 100644
--- a/cyclone/hammer/mtr.c
+++ b/cyclone/hammer/mtr.c
@@ -336,11 +336,14 @@ static void mtrack_write(t_mtrack *tp, t_symbol *s)
static void mtrack_tempo(t_mtrack *tp, t_floatarg f)
{
float newtempo;
- static int warned = 0;
- if (!warned)
+ if (shared_getmaxcompatibility())
{
- loud_incompatible(mtr_class, "no 'tempo' control in Max");
- warned = 1;
+ static int warned = 0;
+ if (!warned)
+ {
+ loud_incompatible(mtr_class, "no 'tempo' control in Max");
+ warned = 1;
+ }
}
if (f < 1e-20)
f = 1e-20;
@@ -476,6 +479,7 @@ static void mtr_doread(t_mtr *x, t_mtrack *target, t_symbol *fname)
{
char path[MAXPDSTRING];
FILE *fp;
+ /* FIXME use open_via_path() */
if (x->x_glist)
canvas_makefilename(x->x_glist, fname->s_name, path, MAXPDSTRING);
else
@@ -756,6 +760,7 @@ static void *mtr_new(t_floatarg f)
x->x_glist = canvas_getcurrent();
x->x_filehandle = hammerfile_new((t_pd *)x, 0,
mtr_readhook, mtr_writehook, 0);
+ shared_usecompatibility();
if (ntracks > MTR_C74MAXTRACKS)
loud_incompatible_max(mtr_class, MTR_C74MAXTRACKS, "tracks");
x->x_ntracks = ntracks;
diff --git a/cyclone/hammer/offer.c b/cyclone/hammer/offer.c
index 3823c85..1e247e7 100644
--- a/cyclone/hammer/offer.c
+++ b/cyclone/hammer/offer.c
@@ -1,4 +1,4 @@
-/* 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. */
@@ -7,9 +7,9 @@
#include "hammer/tree.h"
/* As a class `derived' from the common hammertree code (also in funbuff),
- offer uses the auxiliary list, generally not needed here.
- As a side-effect, it gets a bonus of a small speedup of deletion,
- and a penalty of a small slowdown of insertion. */
+ offer maintains the auxiliary list, the main purpose of which is faster
+ traversal (not needed here). As a side-effect, there is a bonus of a small
+ speedup of deletion, and a penalty of a small slowdown of insertion. */
typedef struct _offer
{
@@ -29,13 +29,12 @@ static void offer_float(t_offer *x, t_float f)
t_hammernode *np;
if (x->x_valueset)
{
- if (np = hammertree_insert(&x->x_tree, ndx))
- np->n_value = x->x_value;
+ hammertree_insertfloat(&x->x_tree, ndx, x->x_value, 1);
x->x_valueset = 0;
}
else if (np = hammertree_search(&x->x_tree, ndx))
{
- outlet_float(((t_object *)x)->ob_outlet, np->n_value);
+ outlet_float(((t_object *)x)->ob_outlet, HAMMERNODE_GETFLOAT(np));
hammertree_delete(&x->x_tree, np);
}
}
@@ -57,7 +56,7 @@ static void offer_clear(t_offer *x)
#ifdef HAMMERTREE_DEBUG
static void offer_debug(t_offer *x, t_floatarg f)
{
- hammertree_debug(&x->x_tree, (int)f);
+ hammertree_debug(&x->x_tree, (int)f, 0);
}
#endif
@@ -70,7 +69,7 @@ static void *offer_new(void)
{
t_offer *x = (t_offer *)pd_new(offer_class);
x->x_valueset = 0;
- hammertree_init(&x->x_tree, 0);
+ hammertree_inittyped(&x->x_tree, HAMMERTYPE_FLOAT, 0);
inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
outlet_new((t_object *)x, &s_float);
return (x);
diff --git a/cyclone/hammer/past.c b/cyclone/hammer/past.c
index cb0b4ef..bf4300c 100644
--- a/cyclone/hammer/past.c
+++ b/cyclone/hammer/past.c
@@ -112,6 +112,7 @@ static void past_set(t_past *x, t_symbol *s, int ac, t_atom *av)
t_atom *vp = x->x_thresh;
if (ac > x->x_size)
{
+ shared_usecompatibility();
loud_incompatible_max(past_class, PAST_C74MAXSIZE, "guard points");
x->x_thresh = grow_nodata(&ac, &x->x_size, x->x_thresh,
PAST_C74MAXSIZE, x->x_thrini,
diff --git a/cyclone/hammer/prepend.c b/cyclone/hammer/prepend.c
index 052c8d6..1b3bd73 100644
--- a/cyclone/hammer/prepend.c
+++ b/cyclone/hammer/prepend.c
@@ -1,4 +1,4 @@
-/* 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. */
@@ -21,9 +21,17 @@ typedef struct _prepend
int x_entered;
int x_auxsize;
t_atom *x_auxbuf;
+ t_pd *x_proxy;
} t_prepend;
+typedef struct _prependxy
+{
+ t_pd xy_pd;
+ t_prepend *xy_owner;
+} t_prependxy;
+
static t_class *prepend_class;
+static t_class *prependxy_class;
/* Usually a preallocation method is used, except in special cases of:
1) reentrant output request, or 2) an output request which would cause
@@ -32,83 +40,86 @@ static t_class *prepend_class;
A separately preallocated output buffer is not used, thus avoiding
memcpying of the stored message (a small performance gain when the
preallocation method is chosen). Instead, self-invoked 'set'
- messages are postponed, using an auxiliary buffer.
-*/
+ messages are postponed, using an auxiliary buffer. */
-static void prepend_dooutput(t_prepend *x, t_symbol *s, int ac, t_atom *av)
+/* called only from prepend_doanything() */
+static void prepend_dooutput(t_prepend *x, int ac, t_atom *av)
{
- if (s == &s_float)
+ if (x->x_selector == &s_float)
{
if (ac > 1)
outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av);
else
outlet_float(((t_object *)x)->ob_outlet, av->a_w.w_float);
}
- else if (s == &s_list)
+ else if (x->x_selector == &s_list)
outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av);
- else if (s)
+ else /* x->x_selector guaranteed non-empty */
/* CHECKED: 'bang' is prepended -- we cannot do so...
('symbol' cannot be compatible too) */
- {
- outlet_anything(((t_object *)x)->ob_outlet, s, ac, av);
- }
+ outlet_anything(((t_object *)x)->ob_outlet, x->x_selector, ac, av);
}
-static void prepend_anything(t_prepend *x, t_symbol *s, int ac, t_atom *av)
+static void prepend_doanything(t_prepend *x, t_symbol *s, int ac, t_atom *av)
{
int reentered = x->x_entered;
- int prealloc = !reentered;
- int ntotal = x->x_natoms + ac;
- t_atom *buf;
x->x_entered = 1;
- if (s == &s_) s = 0;
- if (s)
- ntotal++;
- if (prealloc && ntotal > x->x_size)
- {
- if (ntotal > PREPEND_MAXSIZE)
- prealloc = 0;
- else
- {
- int nrequested = ntotal;
- x->x_message = grow_withdata(&nrequested, &x->x_natoms,
- &x->x_size, x->x_message,
- PREPEND_INISIZE, x->x_messini,
- sizeof(*x->x_message));
- prealloc = (nrequested == ntotal);
- }
- }
- if (prealloc)
+ if (s == &s_)
+ s = 0;
+ if (s || x->x_natoms)
{
- buf = x->x_message + x->x_natoms;
+ int prealloc = !reentered;
+ int ntotal = x->x_natoms + ac;
+ t_atom *buf;
if (s)
+ ntotal++;
+ if (prealloc && ntotal > x->x_size)
{
- SETSYMBOL(buf, s);
- buf++;
+ if (ntotal > PREPEND_MAXSIZE)
+ prealloc = 0;
+ else
+ {
+ int nrequested = ntotal;
+ x->x_message = grow_withdata(&nrequested, &x->x_natoms,
+ &x->x_size, x->x_message,
+ PREPEND_INISIZE, x->x_messini,
+ sizeof(*x->x_message));
+ prealloc = (nrequested == ntotal);
+ }
}
- if (ac)
- memcpy(buf, av, ac * sizeof(*buf));
- prepend_dooutput(x, x->x_selector, ntotal, x->x_message);
- }
- else
- {
- /* LATER consider using the stack if ntotal <= MAXSTACK */
- if (buf = getbytes(ntotal * sizeof(*buf)))
+ if (prealloc)
{
- t_atom *bp = buf + x->x_natoms;
- if (x->x_natoms)
- memcpy(buf, x->x_message, x->x_natoms * sizeof(*buf));
+ buf = x->x_message + x->x_natoms;
if (s)
{
- SETSYMBOL(bp, s);
- bp++;
+ SETSYMBOL(buf, s);
+ buf++;
}
if (ac)
- memcpy(bp, av, ac * sizeof(*bp));
- prepend_dooutput(x, x->x_selector, ntotal, buf);
- freebytes(buf, ntotal * sizeof(*buf));
+ memcpy(buf, av, ac * sizeof(*buf));
+ prepend_dooutput(x, ntotal, x->x_message);
+ }
+ else
+ {
+ /* LATER consider using the stack if ntotal <= MAXSTACK */
+ if (buf = getbytes(ntotal * sizeof(*buf)))
+ {
+ t_atom *bp = buf + x->x_natoms;
+ if (x->x_natoms)
+ memcpy(buf, x->x_message, x->x_natoms * sizeof(*buf));
+ if (s)
+ {
+ SETSYMBOL(bp, s);
+ bp++;
+ }
+ if (ac)
+ memcpy(bp, av, ac * sizeof(*bp));
+ prepend_dooutput(x, ntotal, buf);
+ freebytes(buf, ntotal * sizeof(*buf));
+ }
}
}
+ else prepend_dooutput(x, ac, av);
if (!reentered)
{
x->x_entered = 0;
@@ -136,51 +147,75 @@ static void prepend_anything(t_prepend *x, t_symbol *s, int ac, t_atom *av)
static void prepend_bang(t_prepend *x)
{
- t_atom at;
- SETSYMBOL(&at, &s_bang); /* CHECKED */
- prepend_anything(x, 0, 1, &at);
+ if (x->x_selector)
+ {
+ t_atom at;
+ SETSYMBOL(&at, &s_bang); /* CHECKED */
+ prepend_doanything(x, 0, 1, &at);
+ }
+ else outlet_bang(((t_object *)x)->ob_outlet);
}
static void prepend_float(t_prepend *x, t_float f)
{
- t_atom at;
- SETFLOAT(&at, f);
- prepend_anything(x, 0, 1, &at);
+ if (x->x_selector)
+ {
+ t_atom at;
+ SETFLOAT(&at, f);
+ prepend_doanything(x, 0, 1, &at);
+ }
+ else outlet_float(((t_object *)x)->ob_outlet, f);
}
static void prepend_symbol(t_prepend *x, t_symbol *s)
{
- t_atom at;
- SETSYMBOL(&at, s);
- prepend_anything(x, 0, 1, &at);
+ if (x->x_selector)
+ {
+ t_atom at;
+ SETSYMBOL(&at, s);
+ prepend_doanything(x, 0, 1, &at);
+ }
+ else outlet_symbol(((t_object *)x)->ob_outlet, s);
}
/* LATER gpointer */
static void prepend_list(t_prepend *x, t_symbol *s, int ac, t_atom *av)
{
- prepend_anything(x, 0, ac, av);
+ if (x->x_selector)
+ prepend_doanything(x, 0, ac, av);
+ else
+ outlet_list(((t_object *)x)->ob_outlet, s, ac, av);
}
-static void prepend_set(t_prepend *x, t_symbol *s, int ac, t_atom *av)
+static void prepend_anything(t_prepend *x, t_symbol *s, int ac, t_atom *av)
{
- if (ac)
+ if (x->x_selector)
+ prepend_doanything(x, s, ac, av);
+ else
+ outlet_anything(((t_object *)x)->ob_outlet, s, ac, av);
+}
+
+static void prepend_doset(t_prepend *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (s)
+ x->x_selector = s;
+ else if (ac)
{
- int newsize;
- if (av->a_type == A_FLOAT)
- {
- if (ac > 1) x->x_selector = &s_list;
- else x->x_selector = &s_float;
- }
- else if (av->a_type == A_SYMBOL)
+ if (av->a_type == A_SYMBOL)
{
x->x_selector = av->a_w.w_symbol;
- ac--;
- av++;
+ ac--; av++;
}
+ else if (av->a_type == A_FLOAT)
+ x->x_selector = (ac > 1 ? &s_list : &s_float);
else
return; /* LATER rethink */
- newsize = ac * 2;
+ }
+ else x->x_selector = 0;
+ if (ac)
+ {
+ int newsize = ac * 2;
if (x->x_entered)
{
if (x->x_auxbuf)
@@ -212,12 +247,56 @@ static void prepend_set(t_prepend *x, t_symbol *s, int ac, t_atom *av)
while (ac--) *ap++ = *av++;
}
}
+ else x->x_natoms = 0;
+}
+
+static void prepend_set(t_prepend *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (shared_getmaxcompatibility())
+ prepend_doset(x, 0, ac, av);
+ else
+ prepend_anything(x, s, ac, av);
+}
+
+static void prependxy_bang(t_prependxy *xy)
+{
+ prepend_doset(xy->xy_owner, 0, 0, 0); /* LATER rethink */
+}
+
+static void prependxy_float(t_prependxy *xy, t_float f)
+{
+ t_atom at;
+ SETFLOAT(&at, f);
+ prepend_doset(xy->xy_owner, &s_float, 1, &at);
+}
+
+static void prependxy_symbol(t_prependxy *xy, t_symbol *s)
+{
+ prepend_doset(xy->xy_owner,
+ (s && s != &s_ ? s : &s_symbol), 0, 0); /* LATER rethink */
+}
+
+static void prependxy_list(t_prependxy *xy, t_symbol *s, int ac, t_atom *av)
+{
+ prepend_doset(xy->xy_owner, &s_list, ac, av); /* LATER rethink */
+}
+
+static void prependxy_anything(t_prependxy *xy, t_symbol *s, int ac, t_atom *av)
+{
+ prepend_doset(xy->xy_owner, s, ac, av);
}
static void prepend_free(t_prepend *x)
{
if (x->x_message != x->x_messini)
freebytes(x->x_message, x->x_size * sizeof(*x->x_message));
+ if (x->x_auxbuf)
+ {
+ bug("prepend_free"); /* LATER rethink */
+ freebytes(x->x_auxbuf, x->x_auxsize * sizeof(*x->x_auxbuf));
+ }
+ if (x->x_proxy)
+ pd_free(x->x_proxy);
}
static void *prepend_new(t_symbol *s, int ac, t_atom *av)
@@ -229,15 +308,25 @@ static void *prepend_new(t_symbol *s, int ac, t_atom *av)
x->x_message = x->x_messini;
x->x_auxbuf = 0;
x->x_entered = 0;
- if (!ac)
+ shared_usecompatibility();
+ if (ac)
{
- loud_incompatible(prepend_class,
- "creating an object without an argument");
- /* CHECKED: this is not compatible -- in max an object without an outlet
- is created, and there is no warning if loading from a file. */
+ x->x_proxy = 0;
+ prepend_doset(x, 0, ac, av);
+ }
+ else
+ {
+ if (shared_getmaxcompatibility())
+ /* CHECKED: this is still not compatible -- in max an object
+ without an outlet is created, and there is no warning when
+ loading from a file. */
+ loud_incompatible(prepend_class,
+ "creating an object without an argument");
+ x->x_proxy = pd_new(prependxy_class);
+ ((t_prependxy *)x->x_proxy)->xy_owner = x;
+ inlet_new((t_object *)x, x->x_proxy, 0, 0);
}
outlet_new((t_object *)x, &s_anything);
- prepend_set(x, 0, ac, av);
return (x);
}
@@ -255,4 +344,12 @@ void prepend_setup(void)
class_addanything(prepend_class, prepend_anything);
class_addmethod(prepend_class, (t_method)prepend_set,
gensym("set"), A_GIMME, 0);
+
+ prependxy_class = class_new(gensym("prepend"), 0, 0, sizeof(t_prependxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addbang(prependxy_class, prependxy_bang);
+ class_addfloat(prependxy_class, prependxy_float);
+ class_addsymbol(prependxy_class, prependxy_symbol);
+ class_addlist(prependxy_class, prependxy_list);
+ class_addanything(prependxy_class, prependxy_anything);
}
diff --git a/cyclone/hammer/prob.c b/cyclone/hammer/prob.c
index e20e420..114a41d 100644
--- a/cyclone/hammer/prob.c
+++ b/cyclone/hammer/prob.c
@@ -274,6 +274,7 @@ static void *prob_new(void)
x->x_embedmode = 0; /* CHECKED */
x->x_silent = 0;
rand_seed(&x->x_seed, 0);
+ shared_usecompatibility();
outlet_new((t_object *)x, &s_float);
x->x_bangout = outlet_new((t_object *)x, &s_bang);
x->x_filehandle = hammerfile_new((t_pd *)x, prob_embedhook, 0, 0, 0);
diff --git a/cyclone/hammer/seq.c b/cyclone/hammer/seq.c
index edeff88..f29c803 100644
--- a/cyclone/hammer/seq.c
+++ b/cyclone/hammer/seq.c
@@ -1,4 +1,4 @@
-/* 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. */
@@ -11,26 +11,33 @@
#include "shared.h"
#include "common/loud.h"
#include "common/grow.h"
-#include "common/sq.h"
-#include "common/bifi.h"
#include "common/mifi.h"
+#include "unstable/forky.h"
#include "hammer/file.h"
-//#define SEQ_DEBUG
+#define SEQ_DEBUG
-#define SEQ_INISIZE 256 /* LATER rethink */
-#define SEQ_EOM 255 /* end of message marker, LATER rethink */
-#define SEQ_TICKSPERSEC 48
-#define SEQ_MINTICKDELAY 1. /* LATER rethink */
+#define SEQ_INISEQSIZE 256 /* LATER rethink */
+#define SEQ_INITEMPOMAPSIZE 128 /* LATER rethink */
+#define SEQ_EOM 255 /* end of message marker, LATER rethink */
+#define SEQ_TICKSPERSEC 48
+#define SEQ_MINTICKDELAY 1. /* LATER rethink */
+#define SEQ_TICKEPSILON ((double).0001)
enum { SEQ_IDLEMODE, SEQ_RECMODE, SEQ_PLAYMODE, SEQ_SLAVEMODE };
typedef struct _seqevent
{
- int e_delta;
+ double e_delta;
unsigned char e_bytes[4];
} t_seqevent;
+typedef struct _seqtempo
+{
+ double t_scoretime; /* score ticks from start */
+ double t_sr; /* score ticks per second */
+} t_seqtempo;
+
typedef struct _seq
{
t_object x_ob;
@@ -39,18 +46,24 @@ typedef struct _seq
t_hammerfile *x_filehandle;
int x_mode;
int x_playhead;
- float x_tempo;
- float x_newtempo;
+ float x_timescale;
+ float x_newtimescale;
double x_prevtime;
double x_slaveprevtime;
double x_clockdelay;
unsigned char x_status;
- int x_evesize;
- int x_expectedsize;
- int x_size; /* as allocated */
+ int x_evelength;
+ int x_expectedlength;
+ int x_eventreadhead;
+ int x_seqsize; /* as allocated */
int x_nevents; /* as used */
t_seqevent *x_sequence;
- t_seqevent x_seqini[SEQ_INISIZE];
+ t_seqevent x_seqini[SEQ_INISEQSIZE];
+ int x_temporeadhead;
+ int x_tempomapsize; /* as allocated */
+ int x_ntempi; /* as used */
+ t_seqtempo *x_tempomap;
+ t_seqtempo x_tempomapini[SEQ_INITEMPOMAPSIZE];
t_clock *x_clock;
t_clock *x_slaveclock;
t_outlet *x_bangout;
@@ -60,35 +73,85 @@ static t_class *seq_class;
static void seq_doclear(t_seq *x, int dofree)
{
- if (dofree && x->x_sequence != x->x_seqini)
+ if (dofree)
{
- freebytes(x->x_sequence, x->x_size * sizeof(*x->x_sequence));
- x->x_sequence = x->x_seqini;
- x->x_size = SEQ_INISIZE;
+ if (x->x_sequence != x->x_seqini)
+ {
+ freebytes(x->x_sequence, x->x_seqsize * sizeof(*x->x_sequence));
+ x->x_sequence = x->x_seqini;
+ x->x_seqsize = SEQ_INISEQSIZE;
+ }
+ if (x->x_tempomap != x->x_tempomapini)
+ {
+ freebytes(x->x_tempomap,
+ x->x_tempomapsize * sizeof(*x->x_tempomap));
+ x->x_tempomap = x->x_tempomapini;
+ x->x_tempomapsize = SEQ_INITEMPOMAPSIZE;
+ }
}
x->x_nevents = 0;
+ x->x_ntempi = 0;
+}
+
+static int seq_dogrowing(t_seq *x, int nevents, int ntempi)
+{
+ if (nevents > x->x_seqsize)
+ {
+ int nrequested = nevents;
+#ifdef SEQ_DEBUG
+ post("growing for %d events...", nevents);
+#endif
+ x->x_sequence =
+ grow_nodata(&nrequested, &x->x_seqsize, x->x_sequence,
+ SEQ_INISEQSIZE, x->x_seqini, sizeof(*x->x_sequence));
+ if (nrequested < nevents)
+ {
+ x->x_nevents = 0;
+ x->x_ntempi = 0;
+ return (0);
+ }
+ }
+ if (ntempi > x->x_tempomapsize)
+ {
+ int nrequested = ntempi;
+#ifdef SEQ_DEBUG
+ post("growing for %d tempi...", ntempi);
+#endif
+ x->x_tempomap =
+ grow_nodata(&nrequested, &x->x_tempomapsize, x->x_tempomap,
+ SEQ_INITEMPOMAPSIZE, x->x_tempomapini,
+ sizeof(*x->x_tempomap));
+ if (nrequested < ntempi)
+ {
+ x->x_ntempi = 0;
+ return (0);
+ }
+ }
+ x->x_nevents = nevents;
+ x->x_ntempi = ntempi;
+ return (1);
}
static void seq_complete(t_seq *x)
{
- if (x->x_evesize < x->x_expectedsize)
+ if (x->x_evelength < x->x_expectedlength)
{
/* CHECKED no warning if no data after status byte requiring data */
- if (x->x_evesize > 1)
+ if (x->x_evelength > 1)
post("seq: truncated midi message"); /* CHECKED */
/* CHECKED nothing stored */
}
else
{
t_seqevent *ep = &x->x_sequence[x->x_nevents];
- ep->e_delta = (int)clock_gettimesince(x->x_prevtime);
+ ep->e_delta = clock_gettimesince(x->x_prevtime);
x->x_prevtime = clock_getlogicaltime();
- if (x->x_evesize < 4)
- ep->e_bytes[x->x_evesize] = SEQ_EOM;
+ if (x->x_evelength < 4)
+ ep->e_bytes[x->x_evelength] = SEQ_EOM;
x->x_nevents++;
- if (x->x_nevents >= x->x_size)
+ if (x->x_nevents >= x->x_seqsize)
{
- int nexisting = x->x_size;
+ int nexisting = x->x_seqsize;
/* store-ahead scheme, LATER consider using x_currevent */
int nrequested = x->x_nevents + 1;
#ifdef SEQ_DEBUG
@@ -96,54 +159,55 @@ static void seq_complete(t_seq *x)
#endif
x->x_sequence =
grow_withdata(&nrequested, &nexisting,
- &x->x_size, x->x_sequence,
- SEQ_INISIZE, x->x_seqini, sizeof(*x->x_sequence));
+ &x->x_seqsize, x->x_sequence,
+ SEQ_INISEQSIZE, x->x_seqini,
+ sizeof(*x->x_sequence));
if (nrequested <= x->x_nevents)
x->x_nevents = 0;
}
}
- x->x_evesize = 0;
+ x->x_evelength = 0;
}
static void seq_checkstatus(t_seq *x, unsigned char c)
{
- if (x->x_status && x->x_evesize > 1) /* LATER rethink */
+ if (x->x_status && x->x_evelength > 1) /* LATER rethink */
seq_complete(x);
if (c < 192)
- x->x_expectedsize = 3;
+ x->x_expectedlength = 3;
else if (c < 224)
- x->x_expectedsize = 2;
+ x->x_expectedlength = 2;
else if (c < 240)
- x->x_expectedsize = 3;
+ x->x_expectedlength = 3;
else if (c < 248)
{
/* FIXME */
- x->x_expectedsize = -1;
+ x->x_expectedlength = -1;
}
else
{
x->x_sequence[x->x_nevents].e_bytes[0] = c;
- x->x_evesize = x->x_expectedsize = 1;
+ x->x_evelength = x->x_expectedlength = 1;
seq_complete(x);
return;
}
x->x_status = x->x_sequence[x->x_nevents].e_bytes[0] = c;
- x->x_evesize = 1;
+ x->x_evelength = 1;
}
static void seq_addbyte(t_seq *x, unsigned char c, int docomplete)
{
- x->x_sequence[x->x_nevents].e_bytes[x->x_evesize++] = c;
- if (x->x_evesize == x->x_expectedsize)
+ x->x_sequence[x->x_nevents].e_bytes[x->x_evelength++] = c;
+ if (x->x_evelength == x->x_expectedlength)
{
seq_complete(x);
if (x->x_status)
{
x->x_sequence[x->x_nevents].e_bytes[0] = x->x_status;
- x->x_evesize = 1;
+ x->x_evelength = 1;
}
}
- else if (x->x_evesize == 4)
+ else if (x->x_evelength == 4)
{
if (x->x_status != 240)
bug("seq_addbyte");
@@ -195,8 +259,8 @@ static void seq_startrecording(t_seq *x, int modechanged)
{
x->x_prevtime = clock_getlogicaltime();
x->x_status = 0;
- x->x_evesize = 0;
- x->x_expectedsize = -1; /* LATER rethink */
+ x->x_evelength = 0;
+ x->x_expectedlength = -1; /* LATER rethink */
}
/* CHECKED running status not used in playback */
@@ -210,19 +274,19 @@ static void seq_startplayback(t_seq *x, int modechanged)
x->x_playhead = 0;
/* 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_newtempo;
+ x->x_clockdelay = x->x_sequence->e_delta * x->x_newtimescale;
}
else
{
- /* CHECKED tempo change */
+ /* CHECKED timescale change */
x->x_clockdelay -= clock_gettimesince(x->x_prevtime);
- x->x_clockdelay *= x->x_newtempo / x->x_tempo;
+ x->x_clockdelay *= x->x_newtimescale / x->x_timescale;
}
if (x->x_clockdelay < 0.)
x->x_clockdelay = 0.;
clock_delay(x->x_clock, x->x_clockdelay);
x->x_prevtime = clock_getlogicaltime();
- x->x_tempo = x->x_newtempo;
+ x->x_timescale = x->x_newtimescale;
}
else x->x_mode = SEQ_IDLEMODE;
}
@@ -280,14 +344,14 @@ static void seq_setmode(t_seq *x, int newmode)
}
}
-static void seq_settempo(t_seq *x, float newtempo)
+static void seq_settimescale(t_seq *x, float newtimescale)
{
- if (newtempo < 1e-20)
- x->x_newtempo = 1e-20;
- else if (newtempo > 1e20)
- x->x_newtempo = 1e20;
+ if (newtimescale < 1e-20)
+ x->x_newtimescale = 1e-20;
+ else if (newtimescale > 1e20)
+ x->x_newtimescale = 1e20;
else
- x->x_newtempo = newtempo;
+ x->x_newtimescale = newtimescale;
}
static void seq_clocktick(t_seq *x)
@@ -313,7 +377,7 @@ nextevent:
if (x->x_playhead < x->x_nevents)
{
ep++;
- if (ep->e_delta <= 0)
+ if (ep->e_delta < SEQ_TICKEPSILON)
/* continue output in the same scheduler event, LATER rethink */
{
x->x_playhead++;
@@ -322,7 +386,7 @@ nextevent:
}
else
{
- x->x_clockdelay = ep->e_delta * x->x_tempo;
+ x->x_clockdelay = ep->e_delta * x->x_timescale;
if (x->x_clockdelay < 0.)
x->x_clockdelay = 0.;
clock_delay(x->x_clock, x->x_clockdelay);
@@ -355,36 +419,36 @@ static void seq_tick(t_seq *x)
if (elapsed < SEQ_MINTICKDELAY)
return;
clock_delay(x->x_slaveclock, elapsed);
- seq_settempo(x, (float)(elapsed * (SEQ_TICKSPERSEC / 1000.)));
+ seq_settimescale(x, (float)(elapsed * (SEQ_TICKSPERSEC / 1000.)));
if (x->x_prevtime > 0)
{
x->x_clockdelay -= clock_gettimesince(x->x_prevtime);
- x->x_clockdelay *= x->x_newtempo / x->x_tempo;
+ x->x_clockdelay *= x->x_newtimescale / x->x_timescale;
}
else x->x_clockdelay =
- x->x_sequence[x->x_playhead].e_delta * x->x_newtempo;
+ x->x_sequence[x->x_playhead].e_delta * x->x_newtimescale;
if (x->x_clockdelay < 0.)
x->x_clockdelay = 0.;
clock_delay(x->x_clock, x->x_clockdelay);
x->x_prevtime = clock_getlogicaltime();
x->x_slaveprevtime = x->x_prevtime;
- x->x_tempo = x->x_newtempo;
+ x->x_timescale = x->x_newtimescale;
}
else
{
x->x_clockdelay = 0.; /* redundant */
x->x_prevtime = 0.; /* redundant */
x->x_slaveprevtime = clock_getlogicaltime();
- x->x_tempo = 1.; /* redundant */
+ x->x_timescale = 1.; /* redundant */
}
}
}
-/* CHECKED bang does the same as 'start 1024', not 'start <current-tempo>'
+/* CHECKED bang does the same as 'start 1024', not 'start <current-timescale>'
(also if already in SEQ_PLAYMODE) */
static void seq_bang(t_seq *x)
{
- seq_settempo(x, 1.);
+ seq_settimescale(x, 1.);
seq_setmode(x, SEQ_PLAYMODE); /* CHECKED 'bang' stops recording */
}
@@ -450,7 +514,7 @@ static void seq_start(t_seq *x, t_floatarg f)
}
else
{
- seq_settempo(x, (f == 0 ? 1. : 1024. / f));
+ seq_settimescale(x, (f == 0 ? 1. : 1024. / f));
seq_setmode(x, SEQ_PLAYMODE); /* CHECKED 'start' stops recording */
}
}
@@ -465,7 +529,7 @@ static void seq_delay(t_seq *x, t_floatarg f)
{
if (x->x_nevents)
/* CHECKED signed/unsigned bug (not emulated) */
- x->x_sequence->e_delta = (f > 0 ? f : 0);
+ x->x_sequence->e_delta = (f > SEQ_TICKEPSILON ? f : 0.);
}
/* CHECKED all delta times are set permanently (they are stored in a file) */
@@ -481,223 +545,177 @@ static void seq_hook(t_seq *x, t_floatarg f)
}
}
-static int seq_dogrowing(t_seq *x, int nevents)
+static int seq_eventcomparehook(const void *e1, const void *e2)
{
- if (nevents > x->x_size)
- {
- int nrequested = nevents;
-#ifdef SEQ_DEBUG
- post("growing...");
-#endif
- x->x_sequence =
- grow_nodata(&nrequested, &x->x_size, x->x_sequence,
- SEQ_INISIZE, x->x_seqini, sizeof(*x->x_sequence));
- if (nrequested < nevents)
- {
- x->x_nevents = 0;
- return (0);
- }
- }
- x->x_nevents = nevents;
- return (1);
-}
-
-static int seq_seekhook(t_squiter *it, int offset)
-{
- t_seq *x = (t_seq *)it->i_owner;
- post("seek in %d", x->x_nevents);
- it->i_nelems = x->x_nevents;
- it->i_sequence = x->x_sequence;
- if (offset < 0)
- offset += it->i_nelems;
- if (offset >= 0 && offset < it->i_nelems)
- {
- it->i_element = (t_seqevent *)it->i_sequence + offset;
- it->i_index = offset;
- return (1);
- }
- else return (0);
-}
-
-static void seq_incrhook(t_squiter *it)
-{
- ((t_seqevent *)it->i_element)++;
- it->i_index++;
+ return (((t_seqevent *)e1)->e_delta > ((t_seqevent *)e2)->e_delta ? 1 : -1);
}
-/* LATER put seq_mfwrite_doit() functionality here */
-static void seq_getevehook(t_squiter *it, t_mifi_event *mev, int *ret)
+static int seq_tempocomparehook(const void *t1, const void *t2)
{
- *ret = 1;
+ return (((t_seqtempo *)t1)->t_scoretime >
+ ((t_seqtempo *)t2)->t_scoretime ? 1 : -1);
}
-static void seq_setevehook(t_squiter *it, t_mifi_event *mev, int *ret)
+static int seq_mrhook(t_mifiread *mr, void *hookdata, int evtype)
{
- t_seqevent *sev = it->i_element;
- sev->e_delta = mev->e_delay;
- sev->e_bytes[0] = mev->e_status | mev->e_channel;
- sev->e_bytes[1] = mev->e_data[0];
- if (MIFI_ONE_DATABYTE(mev->e_status))
- sev->e_bytes[2] = SEQ_EOM;
- else
+ t_seq *x = (t_seq *)hookdata;
+ double scoretime = mifiread_getscoretime(mr);
+ if (evtype >= 0xf0)
{
- sev->e_bytes[2] = mev->e_data[1];
- sev->e_bytes[3] = SEQ_EOM;
}
- *ret = 1;
-}
-
-static t_float seq_gettimhook(t_squiter *it, int *ret)
-{
- t_seqevent *sev = it->i_element;
- *ret = 1;
- return (sev->e_delta);
-}
-
-static void seq_settimhook(t_squiter *it, t_float f, int *ret)
-{
- t_seqevent *sev = it->i_element;
- sev->e_delta = f;
- *ret = 1;
-}
-
-static t_symbol *seq_gettarhook(t_squiter *it, int *ret)
-{
- *ret = 1;
- return (0);
-}
-
-static void seq_settarhook(t_squiter *it, t_symbol *s, int *ret)
-{
- *ret = 1;
-}
-
-static int seq_make_iterator(t_seq *x, t_mifi_stream *stp)
-{
- t_squiter *it = squiter_new(stp);
- if (it)
+ else if (evtype >= 0x80)
{
- it->i_owner = x;
- it->i_nelems = x->x_nevents;
- it->i_sequence = it->i_element = x->x_sequence;
- it->i_index = 0;
- it->i_hooks[SQUITER_SEEKHOOK] = (t_squiterhook)seq_seekhook;
- it->i_hooks[SQUITER_INCRHOOK] = (t_squiterhook)seq_incrhook;
- it->i_hooks[SQUITER_GETEVEHOOK] = (t_squiterhook)seq_getevehook;
- it->i_hooks[SQUITER_SETEVEHOOK] = (t_squiterhook)seq_setevehook;
- it->i_hooks[SQUITER_GETTIMHOOK] = (t_squiterhook)seq_gettimhook;
- it->i_hooks[SQUITER_SETTIMHOOK] = (t_squiterhook)seq_settimhook;
- it->i_hooks[SQUITER_GETTARHOOK] = (t_squiterhook)seq_gettarhook;
- it->i_hooks[SQUITER_SETTARHOOK] = (t_squiterhook)seq_settarhook;
- return (1);
+ if (x->x_eventreadhead < x->x_nevents)
+ {
+ t_seqevent *sev = &x->x_sequence[x->x_eventreadhead++];
+ int status = mifiread_getstatus(mr);
+ sev->e_delta = scoretime;
+ sev->e_bytes[0] = status | mifiread_getchannel(mr);
+ sev->e_bytes[1] = mifiread_getdata1(mr);
+ if (MIFI_ONEDATABYTE(status))
+ sev->e_bytes[2] = SEQ_EOM;
+ else
+ {
+ sev->e_bytes[2] = mifiread_getdata2(mr);
+ sev->e_bytes[3] = SEQ_EOM;
+ }
+ }
+ else if (x->x_eventreadhead == x->x_nevents)
+ {
+ bug("seq_mrhook 1");
+ x->x_eventreadhead++;
+ }
}
- else return (0);
-}
-
-static t_mifi_stream *seq_makestream(t_seq *x)
-{
- t_mifi_stream *stp = 0;
- if (stp = mifi_stream_new())
+ else if (evtype == MIFIMETA_TEMPO)
{
- if (seq_make_iterator(x, stp))
- return (stp);
- else
- mifi_stream_free(stp);
+ if (x->x_temporeadhead < x->x_ntempi)
+ {
+ t_seqtempo *stm = &x->x_tempomap[x->x_temporeadhead++];
+ stm->t_scoretime = scoretime;
+ stm->t_sr = mifiread_gettempo(mr);
+#ifdef SEQ_DEBUG
+ post("tempo %g at %g", stm->t_sr, scoretime);
+#endif
+ }
+ else if (x->x_temporeadhead == x->x_ntempi)
+ {
+ bug("seq_mrhook 2");
+ x->x_temporeadhead++;
+ }
}
- return (0);
+ return (1);
}
-static int seq_comparehook(const void *e1, const void *e2)
+/* apply tempo and fold */
+static void seq_foldtime(t_seq *x, double deftempo)
{
- return (((t_seqevent *)e1)->e_delta > ((t_seqevent *)e2)->e_delta ? 1 : -1);
+ t_seqevent *sev;
+ t_seqtempo *stm = x->x_tempomap;
+ double coef = 1000. / deftempo;
+ int ex, tx = 0;
+ double prevscoretime = 0.;
+ while (tx < x->x_ntempi && stm->t_scoretime < SEQ_TICKEPSILON)
+ tx++, coef = 1000. / stm++->t_sr;
+ for (ex = 0, sev = x->x_sequence; ex < x->x_nevents; ex++, sev++)
+ {
+ double clockdelta = 0.;
+ while (tx < x->x_ntempi && stm->t_scoretime <= sev->e_delta)
+ {
+ clockdelta += (stm->t_scoretime - prevscoretime) * coef;
+ prevscoretime = stm->t_scoretime;
+ tx++;
+ coef = 1000. / stm++->t_sr;
+ }
+ clockdelta += (sev->e_delta - prevscoretime) * coef;
+ prevscoretime = sev->e_delta;
+ sev->e_delta = clockdelta;
+ }
}
-/* FIXME */
static int seq_mfread(t_seq *x, char *path)
{
int result = 0;
- t_mifi_stream *stp = 0;
- if (!(stp = seq_makestream(x)) ||
- !mifi_read_start(stp, path, "", 0))
- goto readfailed;
+ t_mifiread *mr = mifiread_new((t_pd *)x);
+ if (!mifiread_open(mr, path, "", 0))
+ goto mfreadfailed;
#ifdef SEQ_DEBUG
- if (stp->s_nframes)
- post("midifile (format %d): %d tracks, %d ticks (%d smpte frames)",
- stp->s_format, stp->s_hdtracks, stp->s_nticks, stp->s_nframes);
+ startpost("midifile (format %d): %d tracks, %d ticks",
+ mifiread_getformat(mr), mifiread_gethdtracks(mr),
+ mifiread_getbeatticks(mr));
+ if (mifiread_getnframes(mr))
+ post(" (%d smpte frames)", mifiread_getnframes(mr));
else
- post("midifile (format %d): %d tracks, %d ticks per beat",
- stp->s_format, stp->s_hdtracks, stp->s_nticks);
+ post(" per beat");
#endif
- if (mifi_read_analyse(stp) != MIFI_READ_EOF ||
- !seq_dogrowing(x, stp->s_nevents) ||
- !mifi_read_restart(stp) ||
- mifi_read_doit(stp) != MIFI_READ_EOF)
- goto readfailed;
- squmpi_sort(stp);
- qsort(x->x_sequence, stp->s_nevents, sizeof(*x->x_sequence),
- seq_comparehook);
- sq_fold_time(stp);
+ if (!seq_dogrowing(x, mifiread_getnevents(mr), mifiread_getntempi(mr)))
+ goto mfreadfailed;
+ x->x_eventreadhead = 0;
+ x->x_temporeadhead = 0;
+ if (mifiread_doit(mr, seq_mrhook, x) != MIFIREAD_EOF)
+ goto mfreadfailed;
+ if (x->x_eventreadhead < x->x_nevents)
+ {
+ bug("seq_mfread 1");
+ post("declared %d events, got %d", x->x_nevents, x->x_eventreadhead);
+ x->x_nevents = x->x_eventreadhead;
+ }
+ if (x->x_nevents)
+ qsort(x->x_sequence, x->x_nevents, sizeof(*x->x_sequence),
+ seq_eventcomparehook);
+ if (x->x_temporeadhead < x->x_ntempi)
+ {
+ bug("seq_mfread 2");
+ post("declared %d tempi, got %d", x->x_ntempi, x->x_temporeadhead);
+ x->x_ntempi = x->x_temporeadhead;
+ }
+ if (x->x_ntempi)
+ qsort(x->x_tempomap, x->x_ntempi, sizeof(*x->x_tempomap),
+ seq_tempocomparehook);
+ seq_foldtime(x, mifiread_getdeftempo(mr));
#ifdef SEQ_DEBUG
- post("finished reading %d events from midifile", stp->s_nevents);
+ post("seq: got %d events from midi file", x->x_nevents);
#endif
result = 1;
-readfailed:
- if (stp)
- {
- mifi_read_end(stp);
- mifi_stream_free(stp);
- }
+mfreadfailed:
+ mifiread_free(mr);
return (result);
}
-/* FIXME */
-static int seq_mfwrite_doit(t_seq *x, t_mifi_stream *stp)
+static int seq_mfwrite(t_seq *x, char *path)
{
- t_mifi_event *mev = stp->s_auxeve;
+ int result = 0;
t_seqevent *sev = x->x_sequence;
int nevents = x->x_nevents;
+ t_mifiwrite *mw = mifiwrite_new((t_pd *)x);
+ if (!mifiwrite_open(mw, path, "", 1, 1))
+ goto mfwritefailed;
+ if (!mifiwrite_opentrack(mw, "seq-track", 1))
+ goto mfwritefailed;
while (nevents--)
{
unsigned char *bp = sev->e_bytes;
- int i;
- mev->e_delay = (uint32)(sev->e_delta * stp->s_timecoef);
- mev->e_status = *bp & 0xf0;
- mev->e_channel = *bp & 0x0f;
- /* FIXME sysex continuation */
- for (i = 0, bp++; i < 3 && *bp != SEQ_EOM; i++, bp++)
- mev->e_data[i] = *bp;
- if (!mifi_write_event(stp, mev))
- return (0);
+ unsigned status = *bp & 0xf0;
+ if (status > 127 && status < 240)
+ {
+ if (!mifiwrite_channelevent(mw, sev->e_delta, status, *bp & 0x0f,
+ bp[1], bp[2])) /* SEQ_EOM ignored */
+ {
+ loud_error((t_pd *)x, "cannot write channel event %d", status);
+ goto mfwritefailed;
+ }
+ }
+ /* FIXME system, sysex (first, and continuation) */
sev++;
}
- return (1);
-}
-
-/* FIXME */
-static int seq_mfwrite(t_seq *x, char *path)
-{
- int result = 0;
- t_mifi_stream *stp = 0;
- if (!(stp = seq_makestream(x)))
- goto writefailed;
- stp->s_ntracks = 1;
- stp->s_hdtracks = 1;
- stp->s_format = 0;
- if (!mifi_write_start(stp, path, ""))
- goto writefailed;
- mifi_event_settext(stp->s_auxeve, MIFI_META_TRACKNAME, "seq-track");
- if (!mifi_write_start_track(stp) ||
- !mifi_write_event(stp, stp->s_auxeve) ||
- !seq_mfwrite_doit(x, stp) ||
- !mifi_write_adjust_track(stp, 0))
- goto writefailed;
+ if (!mifiwrite_closetrack(mw, 0., 1))
+ goto mfwritefailed;
+ mifiwrite_close(mw);
result = 1;
-writefailed:
- if (stp)
- {
- mifi_write_end(stp);
- mifi_stream_free(stp);
- }
+mfwritefailed:
+ if (!result)
+ loud_errand((t_pd *)x,
+ "while saving sequence into midi file \"%s\"", path);
+ mifiwrite_free(mw);
return (result);
}
@@ -716,7 +734,7 @@ static int seq_frombinbuf(t_seq *x, t_binbuf *bb)
t_seqevent *ep;
float prevtime = 0;
int i = -1;
- if (!seq_dogrowing(x, nevents))
+ if (!seq_dogrowing(x, nevents, 0))
return (0);
nevents = 0;
ac = binbuf_getnatom(bb);
@@ -815,6 +833,7 @@ static void seq_textwrite(t_seq *x, char *path)
static void seq_doread(t_seq *x, t_symbol *fn, int creation)
{
char buf[MAXPDSTRING];
+ /* FIXME use open_via_path() */
if (x->x_canvas)
canvas_makefilename(x->x_canvas, fn->s_name, buf, MAXPDSTRING);
else
@@ -853,7 +872,8 @@ static void seq_dowrite(t_seq *x, t_symbol *fn)
/* save as text for any extension other then ".mid" */
if ((dotp = strrchr(fn->s_name, '.')) && strcmp(dotp + 1, "mid"))
seq_textwrite(x, buf);
- else /* save as mf for ".mid" or no extension at all, LATER rethink */
+ else /* save as mf for ".mid" (FIXME ignore case?) or no extension at all,
+ LATER rethink */
seq_mfwrite(x, buf);
}
@@ -884,6 +904,23 @@ static void seq_write(t_seq *x, t_symbol *s)
canvas_getdir(x->x_canvas), x->x_defname);
}
+static void seq_eventstring(t_seq *x, char *buf, t_seqevent *ep)
+{
+ unsigned char *bp = ep->e_bytes;
+ int i;
+ if (*bp < 128 || *bp == 247)
+ sprintf(buf, "(%g)->", ep->e_delta);
+ else
+ sprintf(buf, "(%g)", ep->e_delta);
+ buf += strlen(buf);
+ sprintf(buf, " %g", (float)*bp);
+ for (i = 0, bp++; i < 3 && *bp != SEQ_EOM; i++, bp++)
+ {
+ buf += strlen(buf);
+ sprintf(buf, " %g", (float)*bp);
+ }
+}
+
static void seq_print(t_seq *x)
{
int nevents = x->x_nevents;
@@ -891,39 +928,52 @@ static void seq_print(t_seq *x)
if (nevents)
{
t_seqevent *ep = x->x_sequence;
+ char buf[MAXPDSTRING+2];
int truncated;
if (nevents > 16)
nevents = 16, truncated = 1;
else
truncated = 0;
+ endpost();
while (nevents--)
{
- unsigned char *bp = ep->e_bytes;
- int i;
- if (*bp < 128 || *bp == 247)
- /* CHECKED (sysex continuation) */
- startpost("\n(%d)->", ep->e_delta);
- else
- startpost("\n(%d)", ep->e_delta);
- /* CHECKED space-separated, no semi */
- postfloat((float)*bp);
- for (i = 0, bp++; i < 3 && *bp != SEQ_EOM; i++, bp++)
- postfloat((float)*bp);
+ /* CHECKED bytes are space-separated, no semi */
+ seq_eventstring(x, buf, ep);
+ post(buf);
ep++;
}
- endpost();
if (truncated) post("..."); /* CHECKED */
}
else post(" no sequence"); /* CHECKED */
}
+static void seq_properties(t_gobj *z, t_glist *glist)
+{
+ t_seq *x = (t_seq *)z;
+ t_seqevent *ep = x->x_sequence;
+ int nevents = x->x_nevents;
+ char buf[MAXPDSTRING+2];
+ sprintf(buf, "seq: %s", (x->x_defname && x->x_defname != &s_ ?
+ x->x_defname->s_name : "<anonymous>"));
+ hammereditor_open(x->x_filehandle, buf);
+ while (nevents--)
+ {
+ seq_eventstring(x, buf, ep);
+ strcat(buf, "\n");
+ hammereditor_append(x->x_filehandle, buf);
+ ep++;
+ }
+}
+
static void seq_free(t_seq *x)
{
if (x->x_clock) clock_free(x->x_clock);
if (x->x_slaveclock) clock_free(x->x_slaveclock);
- hammerfile_free(x->x_filehandle);
+ if (x->x_filehandle) hammerfile_free(x->x_filehandle);
if (x->x_sequence != x->x_seqini)
- freebytes(x->x_sequence, x->x_size * sizeof(*x->x_sequence));
+ freebytes(x->x_sequence, x->x_seqsize * sizeof(*x->x_sequence));
+ if (x->x_tempomap != x->x_tempomapini)
+ freebytes(x->x_tempomap, x->x_tempomapsize * sizeof(*x->x_tempomap));
}
static void *seq_new(t_symbol *s)
@@ -938,13 +988,16 @@ static void *seq_new(t_symbol *s)
x->x_canvas = canvas_getcurrent();
x->x_filehandle = hammerfile_new((t_pd *)x, 0,
seq_readhook, seq_writehook, 0);
- x->x_tempo = 1.;
- x->x_newtempo = 1.;
+ x->x_timescale = 1.;
+ x->x_newtimescale = 1.;
x->x_prevtime = 0.;
x->x_slaveprevtime = 0.;
- x->x_size = SEQ_INISIZE;
+ x->x_seqsize = SEQ_INISEQSIZE;
x->x_nevents = 0;
x->x_sequence = x->x_seqini;
+ x->x_tempomapsize = SEQ_INITEMPOMAPSIZE;
+ x->x_ntempi = 0;
+ x->x_tempomap = x->x_tempomapini;
outlet_new((t_object *)x, &s_anything);
x->x_bangout = outlet_new((t_object *)x, &s_bang);
if (s && s != &s_)
@@ -991,5 +1044,6 @@ void seq_setup(void)
gensym("write"), A_DEFSYM, 0);
class_addmethod(seq_class, (t_method)seq_print,
gensym("print"), 0);
+ forky_setpropertiesfn(seq_class, seq_properties);
hammerfile_setup(seq_class, 0);
}
diff --git a/cyclone/hammer/switch.c b/cyclone/hammer/switch.c
index d69660d..03c9f7f 100644
--- a/cyclone/hammer/switch.c
+++ b/cyclone/hammer/switch.c
@@ -103,7 +103,10 @@ static void *switch_new(t_floatarg f1, t_floatarg f2)
if (nproxies < SWITCH_MININLETS)
nproxies = SWITCH_DEFINLETS;
if (nproxies > SWITCH_C74MAXINLETS)
+ {
+ shared_usecompatibility();
loud_incompatible_max(switch_class, SWITCH_C74MAXINLETS, "inlets");
+ }
if (!(proxies = (t_pd **)getbytes(nproxies * sizeof(*proxies))))
return (0);
for (ninlets = 0; ninlets < nproxies; ninlets++)
diff --git a/cyclone/hammer/urn.c b/cyclone/hammer/urn.c
index d6983a2..f496616 100644
--- a/cyclone/hammer/urn.c
+++ b/cyclone/hammer/urn.c
@@ -122,6 +122,7 @@ static void *urn_new(t_floatarg f1, t_floatarg f2)
x->x_urn = x->x_urnini;
urn_resize(x, f1, 1);
urn_seed(x, f2); /* CHECKME */
+ shared_usecompatibility();
inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
outlet_new((t_object *)x, &s_float);
x->x_bangout = outlet_new((t_object *)x, &s_bang);
diff --git a/cyclone/shadow/Makefile b/cyclone/shadow/Makefile
index b700e5e..dc39772 100644
--- a/cyclone/shadow/Makefile
+++ b/cyclone/shadow/Makefile
@@ -2,6 +2,6 @@ ROOT_DIR = ../..
redefault: default $(ROOT_DIR)/bin/cyclist
include $(ROOT_DIR)/Makefile.common
-$(ROOT_DIR)/bin/cyclist: $(SHARED_DIR)/common/binport.c
- $(CC) -DBINPORT_STANDALONE -o $@ $<
-
+$(ROOT_DIR)/bin/cyclist: $(SHARED_DIR)/common/binport.c \
+ $(SHARED_DIR)/common/lex.c $(SHARED_DIR)/unstable/standalone.c
+ $(CC) $(CFLAGS) -DMIXED_STANDALONE -o $@ $^
diff --git a/cyclone/shadow/Makefile.objects b/cyclone/shadow/Makefile.objects
index f1449e0..dd8fb57 100644
--- a/cyclone/shadow/Makefile.objects
+++ b/cyclone/shadow/Makefile.objects
@@ -1,6 +1,7 @@
SHARED_OBJECTS = \
common/loud.o \
common/grow.o \
+common/lex.o \
common/binport.o \
common/port.o \
hammer/file.o \
diff --git a/cyclone/shadow/Makefile.sources b/cyclone/shadow/Makefile.sources
index 061f37b..be9a840 100644
--- a/cyclone/shadow/Makefile.sources
+++ b/cyclone/shadow/Makefile.sources
@@ -1,5 +1,6 @@
CX_SOURCES = \
cyclone.c \
+maxmode.c \
dummies.c
OTHER_SOURCES = \
diff --git a/cyclone/shadow/cyclone.c b/cyclone/shadow/cyclone.c
index 20d1396..a702074 100644
--- a/cyclone/shadow/cyclone.c
+++ b/cyclone/shadow/cyclone.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2003 krzYszcz and others.
+/* Copyright (c) 2003-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. */
@@ -122,6 +122,11 @@ void cyclone_setup(void)
loud_errand(0, "without having cyclone library preloaded");
return;
}
+ if (zgetfn(&pd_objectmaker, gensym("cyclone")))
+ {
+ loud_error(0, "cyclone is already loaded");
+ return;
+ }
post("this is cyclone %s, %s %s build",
CYCLONE_VERSION, loud_ordinal(CYCLONE_BUILD), CYCLONE_RELEASE);
cyclone_class = class_new(gensym("cyclone"),
diff --git a/cyclone/sickle/Makefile.objects b/cyclone/sickle/Makefile.objects
index f9d4ae7..4528d83 100644
--- a/cyclone/sickle/Makefile.objects
+++ b/cyclone/sickle/Makefile.objects
@@ -5,6 +5,8 @@ unstable/fringe.o \
common/loud.o \
common/grow.o \
common/vefl.o \
+common/clc.o \
+common/lex.o \
common/binport.o \
common/port.o \
hammer/file.o \
diff --git a/cyclone/sickle/buffir.c b/cyclone/sickle/buffir.c
index 0551501..ee42af9 100644
--- a/cyclone/sickle/buffir.c
+++ b/cyclone/sickle/buffir.c
@@ -38,11 +38,14 @@ static void buffir_setrange(t_buffir *x, t_floatarg f1, t_floatarg f2)
{
int newsize, pos = x->x_lohead - x->x_histlo;
int oldbytes = x->x_histsize * sizeof(*x->x_histlo);
- static int warned = 0;
- if (!warned)
+ if (shared_getmaxcompatibility())
{
- loud_incompatible(buffir_class, "stretching history buffer");
- warned = 1;
+ static int warned = 0;
+ if (!warned)
+ {
+ loud_incompatible(buffir_class, "stretching history buffer");
+ warned = 1;
+ }
}
newsize = x->x_histsize * 2;
while (newsize < siz) newsize *= 2;
@@ -194,6 +197,7 @@ static void *buffir_new(t_symbol *s, t_floatarg f1, t_floatarg f2)
x->x_histlo = x->x_histini;
buffir_clear(x);
buffir_setrange(x, f1, f2);
+ shared_usecompatibility();
}
return (x);
}
diff --git a/cyclone/sickle/curve.c b/cyclone/sickle/curve.c
index e6bade1..2bad587 100644
--- a/cyclone/sickle/curve.c
+++ b/cyclone/sickle/curve.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2003 krzYszcz and others.
+/* 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. */
@@ -7,54 +7,14 @@
#include "shared.h"
#include "common/grow.h"
#include "common/loud.h"
+#include "common/clc.h"
#include "sickle/sic.h"
//#define CURVE_DEBUG
-/* CHECKED apparently c74's formula was not very carefully tuned. It has 5%
- deviation from the straight line for ccinput=0 (ccinput is user's curve
- control parameter, <0..1>) at half-domain, range=1. It generates nans for
- ccinput > .995.
-
- The formula below generates curves with < .000004% deviation and no nans.
-
- Problem: find a function f : ccinput -> cc, such that the curves will bend
- in a semi-linear way over the ccinput's range of 0..1. The curve function
- is then g(x, p) = (exp(f(p) * x) - 1) / (exp(f(p)) - 1), where x is curve's
- domain, and p is ccinput. If, for example, the points g(0.5, p) are to make
- a semi-linear pattern, then the solution is a function f that minimizes
- the integral of the error function e(p) = sqr(((1-p)/2)-g(.5, p)) over 0..1.
- Until someone does this analytically, we are left with a lame formula, which
- has been tweaked and tested in gnuplot: f(p) = h(p) / (1 - h(p)), where
- h(p) = (((p + 1e-20) * 1.2) ** .41) * .91. The file curve.gp, in the
- sickle's source directory, may come handy, in case there is anyone, who
- fancy tweaking it even further.
-
- To implement this, start from these equations:
- bb * mm ^ npoints = bb + 1
- (bb ^ 2) * (mm ^ npoints) = ((exp(ff/2) - 1) / (exp(ff) - 1)) ^ 2
-
- and calculate:
- hh = pow(((ccinput + c1) * c2), c3) * c4
- ff = hh / (1 - hh)
- eff = exp(ff) - 1
- gh = (exp(ff * .5) - 1) / eff
- bb = gh * (gh / (1 - (gh + gh)))
- mm = ((exp(ff * (1/npoints)) - 1) / (eff * bb)) + 1
-
- The loop is:
- for (vv = bb, i = 0; i < n; vv *= mm, i++)
- result = (vv - bb) * (y1 - y0) + y0
- where y0, y1 are start and destination values
-*/
-
-#define CURVE_C1 1e-20
-#define CURVE_C2 1.2
-#define CURVE_C3 0.41
-#define CURVE_C4 0.91
-
-#define CURVE_MINCCINPUT -1.
-#define CURVE_MAXCCINPUT 1.
+/* CHECKED apparently c74's formula has not been carefully tuned (yet?).
+ It has 5% deviation from the straight line for ccinput = 0 at half-domain,
+ range 1, and generates nans for ccinput > .995 (cf comment in clc.h). */
#define CURVE_INISIZE 64 /* LATER rethink */
#define CURVE_MAXSIZE 64
@@ -63,7 +23,7 @@ typedef struct _curveseg
{
float s_target;
float s_delta;
- int s_npoints;
+ int s_nhops;
float s_ccinput;
double s_bb;
double s_mm;
@@ -95,7 +55,7 @@ typedef struct _curve
#ifdef CURVE_DEBUG
int dbg_nretargets;
int dbg_exitpoint;
- int dbg_npoints;
+ int dbg_nhops;
#endif
} t_curve;
@@ -104,42 +64,10 @@ static double curve_coef;
static void curve_cc(t_curve *x, t_curveseg *segp, float f)
{
- int npoints = segp->s_delta * x->x_ksr + 0.5; /* LATER rethink */
+ int nhops = segp->s_delta * x->x_ksr + 0.5; /* LATER rethink */
segp->s_ccinput = f;
- if (npoints > 0)
- {
- double hh, ff, eff, gh;
- segp->s_npoints = npoints;
- if (f < 0)
- {
- if (f < CURVE_MINCCINPUT)
- f = CURVE_MINCCINPUT;
- hh = pow(((CURVE_C1 - f) * CURVE_C2), CURVE_C3) * CURVE_C4;
- ff = hh / (1. - hh);
- eff = exp(ff) - 1.;
- gh = (exp(ff * .5) - 1.) / eff;
- segp->s_bb = gh * (gh / (1. - (gh + gh)));
- segp->s_mm = 1. / (((exp(ff * (1. / (double)npoints)) - 1.) /
- (eff * segp->s_bb)) + 1.);
- }
- else
- {
- if (f > CURVE_MAXCCINPUT)
- f = CURVE_MAXCCINPUT;
- hh = pow(((f + CURVE_C1) * CURVE_C2), CURVE_C3) * CURVE_C4;
- ff = hh / (1. - hh);
- eff = exp(ff) - 1.;
- gh = (exp(ff * .5) - 1.) / eff;
- segp->s_bb = gh * (gh / (1. - (gh + gh)));
- segp->s_mm = ((exp(ff * (1. / (double)npoints)) - 1.) /
- (eff * segp->s_bb)) + 1.;
- }
- }
- else
- {
- segp->s_npoints = 0;
- segp->s_bb = segp->s_mm = 1.;
- }
+ segp->s_nhops = (nhops > 0 ? nhops : 0);
+ clccurve_coefs(segp->s_nhops, (double)f, &segp->s_bb, &segp->s_mm);
#ifdef CURVE_DEBUG
post("%g %g %g %g",
segp->s_target, segp->s_delta, segp->s_bb, segp->s_mm);
@@ -152,9 +80,9 @@ static void curve_tick(t_curve *x)
#ifdef CURVE_DEBUG
post("exit point %d, after %d retarget calls",
x->dbg_exitpoint, x->dbg_nretargets);
- post("at value %g, after last %d npoints, with bb %g, mm %g",
- x->x_value, x->dbg_npoints, x->x_bb, x->x_mm);
- x->dbg_nretargets = x->dbg_exitpoint = x->dbg_npoints = 0;
+ post("at value %g, after last %d nhops, with bb %g, mm %g",
+ x->x_value, x->dbg_nhops, x->x_bb, x->x_mm);
+ x->dbg_nretargets = x->dbg_exitpoint = x->dbg_nhops = 0;
#endif
}
@@ -177,42 +105,32 @@ retarget:
{
float target = x->x_curseg->s_target;
float delta = x->x_curseg->s_delta;
- int npoints = x->x_curseg->s_npoints;
+ int nhops = x->x_curseg->s_nhops;
+ bb = x->x_curseg->s_bb;
mm = x->x_curseg->s_mm;
if (x->x_curseg->s_ccinput < 0)
- {
- bb = x->x_curseg->s_bb + 1.;
dy = x->x_value - target;
- }
else
- {
- bb = x->x_curseg->s_bb;
dy = target - x->x_value;
- }
#ifdef CURVE_DEBUG
x->dbg_nretargets++;
#endif
x->x_nsegs--;
x->x_curseg++;
- while (npoints <= 0)
+ while (nhops <= 0)
{
curval = x->x_value = target;
if (x->x_nsegs)
{
target = x->x_curseg->s_target;
delta = x->x_curseg->s_delta;
- npoints = x->x_curseg->s_npoints;
+ nhops = x->x_curseg->s_nhops;
+ bb = x->x_curseg->s_bb;
mm = x->x_curseg->s_mm;
if (x->x_curseg->s_ccinput < 0)
- {
- bb = x->x_curseg->s_bb + 1.;
dy = x->x_value - target;
- }
else
- {
- bb = x->x_curseg->s_bb;
dy = target - x->x_value;
- }
x->x_nsegs--;
x->x_curseg++;
}
@@ -228,7 +146,7 @@ retarget:
return (w + 4);
}
}
- nxfer = x->x_nleft = npoints;
+ nxfer = x->x_nleft = nhops;
x->x_vv = vv = bb;
x->x_bb = bb;
x->x_mm = mm;
@@ -237,7 +155,7 @@ retarget:
x->x_target = target;
x->x_retarget = 0;
#ifdef CURVE_DEBUG
- x->dbg_npoints = npoints;
+ x->dbg_nhops = nhops;
#endif
}
if (nxfer >= nblock)
@@ -422,13 +340,7 @@ static void curve_free(t_curve *x)
static void *curve_new(t_floatarg f1, t_floatarg f2)
{
- static int initialized = 0;
t_curve *x = (t_curve *)pd_new(curve_class);
- if (!initialized)
- {
- curve_coef = CURVE_C2 / exp(CURVE_C3);
- initialized = 1;
- }
x->x_value = x->x_target = f1;
x->x_ccinput = f2;
x->x_deltaset = 0;
diff --git a/cyclone/sickle/sickle.c b/cyclone/sickle/sickle.c
index 8df7974..807c2ad 100644
--- a/cyclone/sickle/sickle.c
+++ b/cyclone/sickle/sickle.c
@@ -1,4 +1,4 @@
-/* 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. */
@@ -76,6 +76,11 @@ void sickle_setup(void)
loud_errand(0, "without having sickle library preloaded");
return;
}
+ if (zgetfn(&pd_objectmaker, gensym("sickle")))
+ {
+ loud_error(0, "sickle is already loaded");
+ return;
+ }
if (!zgetfn(&pd_objectmaker, gensym("cyclone")))
post("this is sickle %s, %s %s build",
CYCLONE_VERSION, loud_ordinal(CYCLONE_BUILD), CYCLONE_RELEASE);
diff --git a/shared/common/Makefile.sources b/shared/common/Makefile.sources
index 66d47e9..18847a5 100644
--- a/shared/common/Makefile.sources
+++ b/shared/common/Makefile.sources
@@ -1,12 +1,14 @@
OTHER_SOURCES = \
-bifi.c \
binport.c \
+clc.c \
dict.c \
+fi.c \
grow.c \
+lex.c \
loud.c \
mifi.c \
port.c \
props.c \
+qtree.c \
rand.c \
-sq.c \
vefl.c
diff --git a/shared/common/binport.c b/shared/common/binport.c
index e2c9d34..cb3d201 100644
--- a/shared/common/binport.c
+++ b/shared/common/binport.c
@@ -13,7 +13,7 @@
#define BINPORT_MAXSTRING 1000
#define BINPORT_SYMGROW 64
-#ifndef BINPORT_STANDALONE
+#ifndef MIXED_STANDALONE
/* load a max binary file into a Pd binbuf */
#include "m_pd.h"
@@ -22,44 +22,60 @@
/* make a max-textual listing from a max binary file */
/* This is a standalone version of a ``max binary to binbuf'' module.
- It uses certain Pd calls and structs, which are duplicated below.
- LATER should be linked to the Pd API library. */
+ It uses certain Pd calls and structs, which are duplicated in the
+ "standalone" module defined in shared/unstable.
+ LATER standalone binport should be linked to the Pd API library. */
+
+#include "unstable/standalone.h"
#define BINPORT_VERBOSE
//#define BINPORT_DEBUG
#endif
+#include "common/lex.h"
#include "binport.h"
static void binport_error(char *fmt, ...)
{
+ char buf[BINPORT_MAXSTRING];
va_list ap;
va_start(ap, fmt);
- fprintf(stderr, "ERROR (binport): ");
- vfprintf(stderr, fmt, ap);
- putc('\n', stderr);
+ vsprintf(buf, fmt, ap);
+#ifdef MIXED_STANDALONE
+ fprintf(stderr, "ERROR (binport): %s\n", buf);
+#else
+ post("ERROR (binport): %s", buf);
+#endif
va_end(ap);
}
static void binport_warning(char *fmt, ...)
{
-#if defined (BINPORT_STANDALONE) || defined(BINPORT_VERBOSE)
+#if defined (MIXED_STANDALONE) || defined(BINPORT_VERBOSE)
+ char buf[BINPORT_MAXSTRING];
va_list ap;
va_start(ap, fmt);
- fprintf(stderr, "warning (binport): ");
- vfprintf(stderr, fmt, ap);
- putc('\n', stderr);
+ vsprintf(buf, fmt, ap);
+#ifdef MIXED_STANDALONE
+ fprintf(stderr, "warning (binport): %s\n", buf);
+#else
+ post("warning (binport): %s", buf);
+#endif
va_end(ap);
#endif
}
static void binport_bug(char *fmt, ...)
{
+ char buf[BINPORT_MAXSTRING];
va_list ap;
va_start(ap, fmt);
- fprintf(stderr, "BUG (binport): ");
- vfprintf(stderr, fmt, ap);
- putc('\n', stderr);
+ vsprintf(buf, fmt, ap);
+#ifdef MIXED_STANDALONE
+ fprintf(stderr, "BUG (binport): %s\n", buf);
+#else
+ bug("(binport) %s", buf);
+#endif
va_end(ap);
}
@@ -74,118 +90,6 @@ static void binpold_failure(char *filename)
filename);
}
-#ifdef BINPORT_STANDALONE
-
-typedef int t_int;
-typedef float t_float;
-
-typedef struct _symbol
-{
- char *s_name;
- void *s_thing;
- struct _symbol *s_next;
-} t_symbol;
-
-typedef union word
-{
- t_float w_float;
- t_symbol *w_symbol;
- int w_index;
-} t_word;
-
-typedef enum
-{
- A_NULL,
- A_FLOAT,
- A_SYMBOL,
- A_POINTER,
- A_SEMI,
- A_COMMA,
- A_DEFFLOAT,
- A_DEFSYM,
- A_DOLLAR,
- A_DOLLSYM,
- A_GIMME,
- A_CANT
-} t_atomtype;
-
-typedef struct _atom
-{
- t_atomtype a_type;
- union word a_w;
-} t_atom;
-
-void *getbytes(size_t nbytes)
-{
- void *ret;
- if (nbytes < 1) nbytes = 1;
- ret = (void *)calloc(nbytes, 1);
- if (!ret)
- binport_error("getbytes() failed -- out of memory");
- return (ret);
-}
-
-void *resizebytes(void *old, size_t oldsize, size_t newsize)
-{
- void *ret;
- if (newsize < 1) newsize = 1;
- if (oldsize < 1) oldsize = 1;
- ret = (void *)realloc((char *)old, newsize);
- if (newsize > oldsize && ret)
- memset(((char *)ret) + oldsize, 0, newsize - oldsize);
- if (!ret)
- binport_error("resizebytes() failed -- out of memory");
- return (ret);
-}
-
-void freebytes(void *fatso, size_t nbytes)
-{
- free(fatso);
-}
-
-#define HASHSIZE 1024
-
-static t_symbol *symhash[HASHSIZE];
-
-t_symbol *dogensym(char *s, t_symbol *oldsym)
-{
- t_symbol **sym1, *sym2;
- unsigned int hash1 = 0, hash2 = 0;
- int length = 0;
- char *s2 = s;
- while (*s2)
- {
- hash1 += *s2;
- hash2 += hash1;
- length++;
- s2++;
- }
- sym1 = symhash + (hash2 & (HASHSIZE-1));
- while (sym2 = *sym1)
- {
- if (!strcmp(sym2->s_name, s)) return(sym2);
- sym1 = &sym2->s_next;
- }
- if (oldsym) sym2 = oldsym;
- else
- {
- sym2 = (t_symbol *)getbytes(sizeof(*sym2));
- sym2->s_name = getbytes(length+1);
- sym2->s_next = 0;
- sym2->s_thing = 0;
- strcpy(sym2->s_name, s);
- }
- *sym1 = sym2;
- return (sym2);
-}
-
-t_symbol *gensym(char *s)
-{
- return(dogensym(s, 0));
-}
-
-#endif /* end of Pd API */
-
enum {
BINPORT_NULLTYPE,
BINPORT_INTTYPE = 1, BINPORT_FLOATTYPE, BINPORT_SYMTYPE,
@@ -499,6 +403,7 @@ typedef struct _binport
int b_symsize;
t_symbol **b_symtable;
t_binpold *b_old;
+ t_lex *b_lex;
} t_binport;
static void binport_setint(t_atom *ap, int i)
@@ -566,134 +471,14 @@ static int binport_setbysymtable(t_binport *bp, t_atom *ap, int id)
return (s != 0);
}
-/* single pass of binbuf_text(), int-preserving version */
-static int maxtext_nextatom(FILE *fp, t_atom *ap)
-{
- char buf[BINPORT_MAXSTRING + 1], *bufp, *ebuf = buf + BINPORT_MAXSTRING;
- int ready;
- unsigned char ch;
- ap->a_type = A_NULL;
- while ((ready = binport_readbyte(fp, &ch)) &&
- (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'));
- if (!ready)
- return (0);
- if (ch == ';')
- ap->a_type = A_SEMI;
- else if (ch == ',')
- ap->a_type = A_COMMA;
- else
- {
- int floatstate = 0, slash = 0, lastslash = 0, firstslash = (ch == '\\');
- bufp = buf;
- do
- {
- *bufp = ch;
- lastslash = slash;
- slash = (ch == '\\');
-
- if (floatstate >= 0)
- {
- int digit = (ch >= '0' && ch <= '9'),
- dot = (ch == '.'), minus = (ch == '-'),
- plusminus = (minus || (ch == '+')),
- expon = (ch == 'e' || ch == 'E');
- if (floatstate == 0) /* beginning */
- {
- if (minus) floatstate = 1;
- else if (digit) floatstate = 2;
- else if (dot) floatstate = 3;
- else floatstate = -1;
- }
- else if (floatstate == 1) /* got minus */
- {
- if (digit) floatstate = 2;
- else if (dot) floatstate = 3;
- else floatstate = -1;
- }
- else if (floatstate == 2) /* got digits */
- {
- if (dot) floatstate = 4;
- else if (expon) floatstate = 6;
- else if (!digit) floatstate = -1;
- }
- else if (floatstate == 3) /* got '.' without digits */
- {
- if (digit) floatstate = 5;
- else floatstate = -1;
- }
- else if (floatstate == 4) /* got '.' after digits */
- {
- if (digit) floatstate = 5;
- else if (expon) floatstate = 6;
- else floatstate = -1;
- }
- else if (floatstate == 5) /* got digits after . */
- {
- if (expon) floatstate = 6;
- else if (!digit) floatstate = -1;
- }
- else if (floatstate == 6) /* got 'e' */
- {
- if (plusminus) floatstate = 7;
- else if (digit) floatstate = 8;
- else floatstate = -1;
- }
- else if (floatstate == 7) /* got plus or minus */
- {
- if (digit) floatstate = 8;
- else floatstate = -1;
- }
- else if (floatstate == 8) /* got digits */
- {
- if (!digit) floatstate = -1;
- }
- }
- if (!slash) bufp++;
- }
- while ((ready = binport_readbyte(fp, &ch)) && bufp != ebuf
- && (slash || (ch != ' ' && ch != '\n' && ch != '\r'
- && ch != '\t' && ch != ',' && ch != ';')));
- if (ready && (ch == ',' || ch == ';'))
- ungetc(ch, fp);
- *bufp = 0;
-#if 0
- fprintf(stderr, "buf %s\n", buf);
-#endif
- if (*buf == '$' && buf[1] >= '0' && buf[1] <= '9' && !firstslash)
- {
- for (bufp = buf+2; *bufp; bufp++)
- {
- if (*bufp < '0' || *bufp > '9')
- {
- ap->a_type = A_DOLLSYM;
- ap->a_w.w_symbol = gensym(buf+1);
- break;
- }
- }
- if (ap->a_type == A_NULL)
- {
- ap->a_type = A_DOLLAR;
- ap->a_w.w_index = atoi(buf+1);
- }
- }
- else if (floatstate == 2)
- binport_setint(ap, atoi(buf));
- else if (floatstate == 4 || floatstate == 5 || floatstate == 8)
- binport_setfloat(ap, (float)atof(buf));
- else
- binport_setsymbol(ap, gensym(buf));
- }
- return (1);
-}
-
static int binport_nextatom(t_binport *bp, t_atom *ap)
{
unsigned char opcode;
int opval;
char buf[64];
- if (bp->b_ftype == BINPORT_MAXTEXT)
- return (maxtext_nextatom(bp->b_fp, ap));
+ if (bp->b_ftype == BINPORT_MAXTEXT && bp->b_lex)
+ return (lex_nextatom(bp->b_lex, ap));
else if (bp->b_ftype == BINPORT_MAXOLD && bp->b_old)
return (binpold_nextatom(bp->b_old, ap));
@@ -823,6 +608,11 @@ static void binport_free(t_binport *bp)
bp->b_old->o_fp = 0;
binpold_free(bp->b_old);
}
+ if (bp->b_lex)
+ {
+ bp->b_lex->l_fp = 0;
+ lex_free(bp->b_lex);
+ }
freebytes(bp, sizeof(*bp));
}
@@ -851,6 +641,7 @@ static t_binport *binport_new(FILE *fp, int *ftypep)
bp->b_symtable = 0;
}
bp->b_old = 0;
+ bp->b_lex = 0;
}
else if (*ftypep != BINPORT_PDFILE)
binport_warning("unknown header: %02x%02x%02x%02x",
@@ -866,52 +657,6 @@ static t_binport *binport_new(FILE *fp, int *ftypep)
return (bp);
}
-static void binport_atomstring(t_atom *ap, char *buf, int bufsize)
-{
- char *sp, *bp, *ep;
- switch(ap->a_type)
- {
- case A_SEMI:
- strcpy(buf, ";"); break;
- case A_COMMA:
- strcpy(buf, ","); break;
- case A_INT:
- sprintf(buf, "%d", ap->a_w.w_index); break;
- case A_FLOAT:
- sprintf(buf, "%#f", ap->a_w.w_float);
- ep = buf + strlen(buf) - 1;
- while (ep > buf && *ep == '0') *ep-- = 0;
- break;
- case A_SYMBOL:
- sp = ap->a_w.w_symbol->s_name;
- bp = buf;
- ep = buf + (bufsize-5);
- while (bp < ep && *sp)
- {
- if (*sp == ';' || *sp == ',' || *sp == '\\' ||
- (*sp == '$' && bp == buf && sp[1] >= '0' && sp[1] <= '9'))
- *bp++ = '\\';
- if ((unsigned char)*sp < 127)
- *bp++ = *sp++;
- else
- /* FIXME this is temporary -- codepage horror */
- sprintf(bp, "\\%.3o", (unsigned char)*sp++), bp += 4;
- }
- if (*sp) *bp++ = '*';
- *bp = 0;
- break;
- case A_DOLLAR:
- sprintf(buf, "$%d", ap->a_w.w_index);
- break;
- case A_DOLLSYM:
- sprintf(buf, "$%s", ap->a_w.w_symbol->s_name);
- break;
- default:
- binport_bug("bad atom type");
- strcpy(buf, "???");
- }
-}
-
static void binport_print(t_binport *bp, FILE *fp)
{
char buf[BINPORT_MAXSTRING];
@@ -929,13 +674,13 @@ static void binport_print(t_binport *bp, FILE *fp)
else if (at.a_type != A_NULL)
{
if (cnt++) fputc(' ', fp);
- binport_atomstring(&at, buf, BINPORT_MAXSTRING);
+ lex_atomstring(&at, buf, BINPORT_MAXSTRING, A_INT);
fputs(buf, fp);
}
}
}
-#ifndef BINPORT_STANDALONE
+#ifndef MIXED_STANDALONE
static int binport_tobinbuf(t_binport *bp, t_binbuf *bb)
{
@@ -971,12 +716,16 @@ int binport_read(t_binbuf *bb, char *filename, char *dirname)
else if (ftype == BINPORT_MAXTEXT)
{
t_atom at;
- while (binport_nextatom(bp, &at))
- if (at.a_type == A_SEMI)
- break;
- binbuf_addv(bb, "ss;", gensym("max"), gensym("v2"));
- result = (binport_tobinbuf(bp, bb)
- ? BINPORT_OK : BINPORT_CORRUPT);
+ if (bp->b_lex = lex_new(fp, A_INT))
+ {
+ while (binport_nextatom(bp, &at))
+ if (at.a_type == A_SEMI)
+ break;
+ binbuf_addv(bb, "ss;", gensym("max"), gensym("v2"));
+ result = (binport_tobinbuf(bp, bb)
+ ? BINPORT_OK : BINPORT_CORRUPT);
+ }
+ else result = BINPORT_FAILED;
}
else if (ftype == BINPORT_MAXOLD)
{
@@ -1036,7 +785,7 @@ void binport_write(t_binbuf *bb, char *filename, char *dirname)
else if (ap->a_type != A_NULL)
{
if (cnt++) fputc(' ', fp);
- binport_atomstring(ap, buf, BINPORT_MAXSTRING);
+ lex_atomstring(ap, buf, BINPORT_MAXSTRING, A_INT);
fputs(buf, fp);
}
ap++;
diff --git a/shared/common/binport.h b/shared/common/binport.h
index 93120fa..f29d24d 100644
--- a/shared/common/binport.h
+++ b/shared/common/binport.h
@@ -8,7 +8,7 @@
enum { BINPORT_OK, BINPORT_MAXTEXT, BINPORT_MAXOLD, BINPORT_PDFILE,
BINPORT_INVALID, BINPORT_CORRUPT, BINPORT_FAILED };
-#ifndef BINPORT_STANDALONE
+#ifndef MIXED_STANDALONE
int binport_read(t_binbuf *bb, char *filename, char *dirname);
void binport_write(t_binbuf *bb, char *filename, char *dirname);
#endif
diff --git a/shared/common/dict.c b/shared/common/dict.c
index 33ee365..0871f81 100644
--- a/shared/common/dict.c
+++ b/shared/common/dict.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1997-2003 Miller Puckette, krzYszcz, and others.
+/* Copyright (c) 1997-2004 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. */
@@ -216,33 +216,52 @@ void dict_unbind(t_dict *x, t_pd *obj, t_symbol *s)
else pd_error(obj, "%s: couldn't unbind", s->s_name);
}
-/* adapted pd_findbyclass() from m_pd.c */
-t_pd *dict_value(t_dict *x, t_symbol *s)
+t_pd *dict_firstvalue(t_dict *dict, t_symbol *s, void **nextp)
{
- if (!s->s_thing) return (0);
- if (*s->s_thing == x->d_bindlist_class)
+ if (s->s_thing)
{
- t_pd *x = 0;
- t_dict_bindelem *e;
- int warned = 0;
- for (e = ((t_dict_bindlist *)s->s_thing)->b_list; e; e = e->e_next)
- {
- if (x && !warned)
- {
- post("warning: %s: multiply defined", s->s_name);
- warned = 1;
- }
- x = e->e_who;
- }
- return (x);
+ if (*s->s_thing == dict->d_bindlist_class)
+ {
+ t_dict_bindelem *e = ((t_dict_bindlist *)s->s_thing)->b_list;
+ if (e)
+ {
+ if (nextp)
+ *nextp = e->e_next;
+ return (e->e_who);
+ }
+ else return (0);
+ }
+ else
+ {
+ if (nextp)
+ *nextp = 0;
+ return (s->s_thing);
+ }
+ }
+ else return (0);
+}
+
+t_pd *dict_nextvalue(t_dict *dict, t_symbol *s, void **nextp)
+{
+ if (s->s_thing)
+ {
+ if (*s->s_thing == dict->d_bindlist_class && *nextp)
+ {
+ t_dict_bindelem *e = (t_dict_bindelem *)*nextp;
+ *nextp = e->e_next;
+ return (e->e_who);
+ }
}
- return (s->s_thing);
+ else bug("dict_nextvalue");
+ return (0);
}
+#if 0
t_pd *dict_xvalue(t_dict *x, t_symbol *s)
{
return (s && s != &s_ ? dict_value(x, dict_key(x, s->s_name)) : 0);
}
+#endif
int dict_forall(t_dict *x, t_symbol *s, t_dict_hook hook, void *hookarg)
{
diff --git a/shared/common/dict.h b/shared/common/dict.h
index 807bf9b..4ab48c8 100644
--- a/shared/common/dict.h
+++ b/shared/common/dict.h
@@ -20,8 +20,11 @@ t_symbol *dict_dokey(t_dict *x, char *s, t_symbol *oldsym);
t_symbol *dict_key(t_dict *x, char *s);
void dict_bind(t_dict *x, t_pd *obj, t_symbol *s);
void dict_unbind(t_dict *x, t_pd *obj, t_symbol *s);
-t_pd *dict_value(t_dict *x, t_symbol *s);
+t_pd *dict_firstvalue(t_dict *dict, t_symbol *s, void **nextp);
+t_pd *dict_nextvalue(t_dict *dict, t_symbol *s, void **nextp);
+#if 0
t_pd *dict_xvalue(t_dict *x, t_symbol *s);
+#endif
int dict_forall(t_dict *x, t_symbol *s, t_dict_hook hook, void *hookarg);
#endif
diff --git a/shared/common/loud.c b/shared/common/loud.c
index d176eb0..4f64110 100644
--- a/shared/common/loud.c
+++ b/shared/common/loud.c
@@ -9,23 +9,92 @@
#include "m_pd.h"
#include "common/loud.h"
-#define LOUD_ERROR_DEFAULT "error (miXed): "
+/* The 'shared_' calls do not really belong here,
+ LATER find them a permanent home. */
-/* LATER move it somewhere else */
-t_symbol *loud_floatsym(void)
+/* FIXME compatibility mode should be a standard Pd feature */
+static t_symbol *shared_compatibility = 0;
+static t_class *sharedcompatibility_class = 0;
+static t_pd *sharedcompatibility_target = 0;
+static t_symbol *sharedps_hashcompatibility = 0;
+static t_symbol *sharedps_max = 0;
+
+static void sharedcompatibility_bang(t_pd *x)
{
- static t_symbol *s = 0;
- return (s ? s : (s = gensym("noninteger float")));
+ if (sharedps_hashcompatibility)
+ {
+ if (shared_compatibility && sharedps_hashcompatibility->s_thing)
+ pd_symbol(sharedps_hashcompatibility->s_thing,
+ shared_compatibility);
+ }
+ else bug("sharedcompatibility_bang");
}
-/* LATER move it somewhere else */
-char *loud_symbolname(t_symbol *s, char *nullname)
+static void sharedcompatibility_symbol(t_pd *x, t_symbol *s)
{
- return (s && s != &s_ ? s->s_name : nullname);
+ shared_compatibility = s;
+}
+
+static void sharedcompatibility_setup(t_symbol *s)
+{
+ if (sharedcompatibility_class || sharedcompatibility_target)
+ bug("sharedcompatibility_setup");
+ sharedps_hashcompatibility = gensym("#compatibility");
+ sharedps_max = gensym("max");
+ sharedcompatibility_class = class_new(sharedps_hashcompatibility,
+ 0, 0, sizeof(t_pd),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addbang(sharedcompatibility_class, sharedcompatibility_bang);
+ class_addsymbol(sharedcompatibility_class, sharedcompatibility_symbol);
+ sharedcompatibility_target = pd_new(sharedcompatibility_class);
+ pd_bind(sharedcompatibility_target, sharedps_hashcompatibility);
+ if (s)
+ pd_symbol(sharedps_hashcompatibility->s_thing, s);
+ else
+ pd_bang(sharedps_hashcompatibility->s_thing);
}
-/* LATER move it somewhere else */
-int loud_matchignorecase(char *test, char *pattern)
+void shared_usecompatibility(void)
+{
+ if (!sharedcompatibility_class)
+ sharedcompatibility_setup(0);
+}
+
+void shared_setcompatibility(t_symbol *s)
+{
+ post("setting compatibility mode to '%s'", (s ? s->s_name : "none"));
+ if (sharedcompatibility_class)
+ {
+ if (sharedps_hashcompatibility->s_thing)
+ pd_symbol(sharedps_hashcompatibility->s_thing, s);
+ else
+ bug("shared_setcompatibility");
+ }
+ else sharedcompatibility_setup(s);
+}
+
+t_symbol *shared_getcompatibility(void)
+{
+ if (!sharedcompatibility_class)
+ sharedcompatibility_setup(0);
+ return (shared_compatibility);
+}
+
+void shared_setmaxcompatibility(void)
+{
+ if (!sharedcompatibility_class)
+ sharedcompatibility_setup(0);
+ shared_setcompatibility(sharedps_max);
+}
+
+int shared_getmaxcompatibility(void)
+{
+ if (!sharedcompatibility_class)
+ sharedcompatibility_setup(0);
+ return (shared_compatibility == sharedps_max);
+}
+
+int shared_matchignorecase(char *test, char *pattern)
{
char ct, cp;
for (ct = *test, cp = *pattern; ct && cp; ct = *++test, cp = *++pattern)
@@ -37,7 +106,20 @@ int loud_matchignorecase(char *test, char *pattern)
return (ct == cp);
}
-/* LATER move it somewhere else */
+struct _loudcontext
+{
+ t_pd *lc_caller; /* an object reporting trouble */
+ char *lc_callername;
+ int lc_cnsize;
+ /* during object creation, use the following: */
+ t_symbol *lc_selector; /* creation message selector (class name) */
+ int lc_ac; /* creation message arguments */
+ t_atom *lc_av; /* void out of creation context */
+ int lc_andindent;
+};
+
+#define LOUD_ERROR_DEFAULT "error (miXed):"
+
char *loud_ordinal(int n)
{
static char buf[16]; /* assuming 10-digit INT_MAX */
@@ -60,32 +142,27 @@ char *loud_ordinal(int n)
void loud_error(t_pd *x, char *fmt, ...)
{
+ char buf[MAXPDSTRING];
va_list ap;
va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
if (x)
{
- char buf[MAXPDSTRING];
- fprintf(stderr, "%s's ", class_getname(*x));
- vsprintf(buf, fmt, ap);
+ startpost("%s's ", class_getname(*x));
pd_error(x, buf);
}
- else
- {
- fputs(LOUD_ERROR_DEFAULT, stderr);
- vfprintf(stderr, fmt, ap);
- putc('\n', stderr);
- }
+ else post("%s %s", LOUD_ERROR_DEFAULT, buf);
va_end(ap);
}
void loud_errand(t_pd *x, char *fmt, ...)
{
+ char buf[MAXPDSTRING];
va_list ap;
va_start(ap, fmt);
- fprintf(stderr, "%*s", (int)(x ? strlen(class_getname(*x)) + 10
- : strlen(LOUD_ERROR_DEFAULT)), "");
- vfprintf(stderr, fmt, ap);
- putc('\n', stderr);
+ vsprintf(buf, fmt, ap);
+ post("%*s%s", (int)(x ? strlen(class_getname(*x)) + 10
+ : strlen(LOUD_ERROR_DEFAULT) + 1), "", buf);
va_end(ap);
}
@@ -113,11 +190,14 @@ int loud_checkint(t_pd *x, t_float f, int *valuep, t_symbol *mess)
return (1);
else
{
+ static t_symbol *floatsym = 0;
+ if (!floatsym)
+ floatsym = gensym("noninteger float");
if (mess == &s_float)
- loud_nomethod(x, loud_floatsym());
+ loud_nomethod(x, floatsym);
else if (mess)
loud_error(x, "\"%s\" argument invalid for message \"%s\"",
- loud_floatsym()->s_name, mess->s_name);
+ floatsym->s_name, mess->s_name);
return (0);
}
}
@@ -129,13 +209,13 @@ void loud_classarg(t_class *c)
void loud_warning(t_pd *x, char *who, char *fmt, ...)
{
+ char buf[MAXPDSTRING];
va_list ap;
va_start(ap, fmt);
- fprintf(stderr, "warning (%s): ",
- (x ? class_getname(*x) : (who ? who : "miXed")));
- vfprintf(stderr, fmt, ap);
+ vsprintf(buf, fmt, ap);
+ post("warning (%s): %s",
+ (x ? class_getname(*x) : (who ? who : "miXed")), buf);
va_end(ap);
- putc('\n', stderr);
}
void loud_notimplemented(t_pd *x, char *name)
@@ -148,13 +228,16 @@ void loud_notimplemented(t_pd *x, char *name)
void loud_incompatible(t_class *c, char *fmt, ...)
{
- va_list ap;
- va_start(ap, fmt);
- fprintf(stderr, "'%s' class incompatibility warning:\n\t",
- class_getname(c));
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- putc('\n', stderr);
+ if (shared_getmaxcompatibility())
+ {
+ char buf[MAXPDSTRING];
+ va_list ap;
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ post("'%s' class incompatibility warning:\n\t%s",
+ class_getname(c), buf);
+ va_end(ap);
+ }
}
void loud_incompatible_max(t_class *c, int maxmax, char *what)
@@ -222,3 +305,134 @@ int loud_floatarg(t_class *c, int which, int ac, t_atom *av,
}
return (result);
}
+
+void loudx_error(t_loudcontext *lc, char *fmt, ...)
+{
+ char buf[MAXPDSTRING];
+ va_list ap;
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ if (lc->lc_caller)
+ {
+ startpost("%s's ", (lc->lc_callername ?
+ lc->lc_callername : class_getname(*lc->lc_caller)));
+ pd_error(lc->lc_caller, buf);
+ }
+ else
+ {
+ if (lc->lc_callername)
+ post("error (%s): %s", lc->lc_callername, buf);
+ else if (lc->lc_selector)
+ post("error (%s): %s", lc->lc_selector->s_name, buf);
+ else
+ post("%s %s", LOUD_ERROR_DEFAULT, buf);
+ }
+ va_end(ap);
+}
+
+void loudx_errand(t_loudcontext *lc, char *fmt, ...)
+{
+ char buf[MAXPDSTRING];
+ va_list ap;
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ post("%*s%s", lc->lc_andindent, "", buf);
+ va_end(ap);
+}
+
+void loudx_nomethod(t_loudcontext *lc, t_symbol *s)
+{
+ loudx_error(lc, "doesn't understand \"%s\"", s->s_name);
+}
+
+void loudx_messarg(t_loudcontext *lc, t_symbol *s)
+{
+ loudx_error(lc, "bad arguments for message \"%s\"", s->s_name);
+}
+
+void loudx_warning(t_loudcontext *lc, char *fmt, ...)
+{
+ char buf[MAXPDSTRING];
+ va_list ap;
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ if (lc->lc_callername)
+ post("warning (%s): %s", lc->lc_callername, buf);
+ else if (lc->lc_selector)
+ post("warning (%s): %s", lc->lc_selector->s_name, buf);
+ else
+ post("warning (miXed): %s", buf);
+ va_end(ap);
+}
+
+void loudx_setcontext(t_loudcontext *lc, t_pd *caller, char *callername,
+ t_symbol *s, int ac, t_atom *av)
+{
+ if (lc->lc_callername)
+ freebytes(lc->lc_callername, lc->lc_cnsize);
+ lc->lc_caller = caller;
+ if (callername)
+ {
+ lc->lc_cnsize = strlen(callername) + 1;
+ lc->lc_callername = getbytes(lc->lc_cnsize);
+ strcpy(lc->lc_callername, callername);
+ }
+ else
+ {
+ lc->lc_callername = 0;
+ lc->lc_cnsize = 0;
+ }
+ lc->lc_selector = s;
+ lc->lc_ac = ac;
+ lc->lc_av = av;
+ if (callername)
+ lc->lc_andindent = lc->lc_cnsize + 9;
+ else if (caller)
+ lc->lc_andindent = strlen(class_getname(*caller)) + 10;
+ else if (s)
+ lc->lc_andindent = strlen(s->s_name) + 10;
+ else
+ lc->lc_andindent = strlen(LOUD_ERROR_DEFAULT) + 1;
+}
+
+/* must call before going out of creation context */
+void loudx_setcaller(t_loudcontext *lc, t_pd *caller, char *callerfmt, ...)
+{
+ va_list ap;
+ va_start(ap, callerfmt);
+ if (callerfmt)
+ {
+ char buf[MAXPDSTRING];
+ vsprintf(buf, callerfmt, ap);
+ loudx_setcontext(lc, caller, buf, lc->lc_selector, 0, 0);
+ }
+ else loudx_setcontext(lc, caller, 0, lc->lc_selector, 0, 0);
+ va_end(ap);
+}
+
+t_symbol *loudx_getselector(t_loudcontext *lc)
+{
+ return (lc->lc_selector);
+}
+
+t_atom *loudx_getarguments(t_loudcontext *lc, int *acp)
+{
+ *acp = lc->lc_ac;
+ return (lc->lc_av);
+}
+
+void loudx_freecontext(t_loudcontext *lc)
+{
+ if (lc->lc_callername)
+ freebytes(lc->lc_callername, lc->lc_cnsize);
+ freebytes(lc, sizeof(*lc));
+}
+
+t_loudcontext *loudx_newcontext(t_pd *caller, char *callername,
+ t_symbol *s, int ac, t_atom *av)
+{
+ t_loudcontext *lc = getbytes(sizeof(*lc));
+ lc->lc_callername = 0;
+ loudx_setcontext(lc, caller, callername, s, ac, av);
+ return (lc);
+}
diff --git a/shared/common/loud.h b/shared/common/loud.h
index 6073a85..3fdcefd 100644
--- a/shared/common/loud.h
+++ b/shared/common/loud.h
@@ -1,4 +1,4 @@
-/* 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. */
@@ -10,9 +10,16 @@
enum { LOUD_ARGOK, LOUD_ARGUNDER, LOUD_ARGOVER, LOUD_ARGTYPE, LOUD_ARGMISSING };
-t_symbol *loud_floatsym(void);
-char *loud_symbolname(t_symbol *s, char *nullname);
-int loud_matchignorecase(char *test, char *pattern);
+EXTERN_STRUCT _loudcontext;
+#define t_loudcontext struct _loudcontext
+
+void shared_usecompatibility(void);
+void shared_setcompatibility(t_symbol *s);
+t_symbol *shared_getcompatibility(void);
+void shared_setmaxcompatibility(void);
+int shared_getmaxcompatibility(void);
+int shared_matchignorecase(char *test, char *pattern);
+
char *loud_ordinal(int n);
void loud_error(t_pd *x, char *fmt, ...);
void loud_errand(t_pd *x, char *fmt, ...);
@@ -29,4 +36,18 @@ int loud_floatarg(t_class *c, int which, int ac, t_atom *av,
t_float *vp, t_float minval, t_float maxval,
int underaction, int overaction, char *what);
+void loudx_error(t_loudcontext *lc, char *fmt, ...);
+void loudx_errand(t_loudcontext *lc, char *fmt, ...);
+void loudx_nomethod(t_loudcontext *lc, t_symbol *s);
+void loudx_messarg(t_loudcontext *lc, t_symbol *s);
+void loudx_warning(t_loudcontext *lc, char *fmt, ...);
+void loudx_setcontext(t_loudcontext *lc, t_pd *caller, char *callername,
+ t_symbol *s, int ac, t_atom *av);
+void loudx_setcaller(t_loudcontext *lc, t_pd *caller, char *callerfmt, ...);
+t_symbol *loudx_getselector(t_loudcontext *lc);
+t_atom *loudx_getarguments(t_loudcontext *lc, int *acp);
+void loudx_freecontext(t_loudcontext *lc);
+t_loudcontext *loudx_newcontext(t_pd *caller, char *callername,
+ t_symbol *s, int ac, t_atom *av);
+
#endif
diff --git a/shared/common/mifi.c b/shared/common/mifi.c
index b2fea10..1b9d367 100644
--- a/shared/common/mifi.c
+++ b/shared/common/mifi.c
@@ -1,9 +1,7 @@
-/* Copyright (c) 2001-2003 krzYszcz and others.
+/* 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. */
-/* reading/writing midifiles, a prototype version */
-
#ifdef NT
#include <io.h>
#else
@@ -11,220 +9,321 @@
#endif
#include <stdlib.h>
#include <stdio.h>
+#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include "m_pd.h"
-#include "shared.h"
-#include "common/sq.h"
-#include "common/bifi.h"
-#include "common/mifi.h"
+#include "mifi.h"
+
+#ifdef __linux__
+#include <sys/types.h>
+#ifndef uint32
+typedef u_int32_t uint32;
+#endif
+#ifndef uint16
+typedef u_int16_t uint16;
+#endif
+#ifndef uchar
+typedef u_int8_t uchar;
+#endif
+#elif defined(NT)
+#ifndef uint32
+typedef unsigned long uint32;
+#endif
+#ifndef uint16
+typedef unsigned short uint16;
+#endif
+#ifndef uchar
+typedef unsigned char uchar;
+#endif
+#elif defined(IRIX)
+#ifndef uint32
+typedef unsigned long uint32;
+#endif
+#ifndef uint16
+typedef unsigned short uint16;
+#endif
+#ifndef uchar
+typedef unsigned char uchar;
+#endif
+#elif defined(__FreeBSD__)
+#include <sys/types.h>
+#ifndef uint32
+typedef u_int32_t uint32;
+#endif
+#ifndef uint16
+typedef u_int16_t uint16;
+#endif
+#ifndef uchar
+typedef u_int8_t uchar;
+#endif
+#else /* MACOSX */
+#ifndef uint32
+typedef unsigned int uint32;
+#endif
+#ifndef uint16
+typedef unsigned short uint16;
+#endif
+#ifndef uchar
+typedef unsigned char uchar;
+#endif
+#endif
-#define MIFI_VERBOSE
#define MIFI_DEBUG
+#define MIFI_VERBOSE
+
+#define MIFI_SHORTESTEVENT 2 /* singlebyte delta and one databyte */
+#define MIFI_TICKEPSILON ((double).0001)
+
+#define MIFIHARD_HEADERSIZE 14 /* in case t_mifiheader is padded to 16 */
+#define MIFIHARD_HEADERDATASIZE 6
+#define MIFIHARD_TRACKHEADERSIZE 8
-#define MIFI_SHORTEST_EVENT 2 /* singlebyte delta and one databyte */
-#define MIFI_EVENT_NALLOC 32 /* LATER do some research (average max?) */
-#define MIFI_HEADER_SIZE 14 /* in case t_mifi_header is padded to 16 */
-#define MIFI_HEADERDATA_SIZE 6
-#define MIFI_TRACKHEADER_SIZE 8
+/* midi file standard defaults */
+#define MIFIHARD_DEFBEATTICKS 192
+#define MIFIHARD_DEFTEMPO 500000 /* 120 bpm in microseconds per beat */
-/* header structures for midifile and track */
+/* user-space defaults */
+#define MIFIUSER_DEFWHOLETICKS ((double)241920) /* whole note, 256*27*5*7 */
+#define MIFIUSER_DEFTEMPO ((double)120960) /* 120 bpm in ticks/sec */
-typedef struct _mifi_header
+#define MIFIEVENT_NALLOC 256 /* LATER do some research (average max?) */
+#define MIFIEVENT_INISIZE 2 /* always be able to handle channel events */
+
+typedef struct _mifievent
+{
+ uint32 e_delay;
+ uchar e_status;
+ uchar e_channel;
+ uchar e_meta; /* meta-event type */
+ uint32 e_length;
+ size_t e_datasize;
+ uchar *e_data;
+ uchar e_dataini[MIFIEVENT_INISIZE];
+} t_mifievent;
+
+/* midi file header */
+typedef struct _mifiheader
{
char h_type[4];
uint32 h_length;
uint16 h_format;
uint16 h_ntracks;
uint16 h_division;
-} t_mifi_header;
+} t_mifiheader;
-typedef struct _mifi_trackheader
+/* midi file track header */
+typedef struct _mifitrackheader
{
- char h_type[4];
- uint32 h_length;
-} t_mifi_trackheader;
+ char th_type[4];
+ uint32 th_length;
+} t_mifitrackheader;
-/* reading helpers */
-
-static void mifi_earlyeof(t_mifi_stream *sp)
+typedef struct _mifireadtx
+{
+ double rt_wholeticks; /* userticks per whole note (set by user) */
+ double rt_deftempo; /* userticks per second (default, adjusted) */
+ double rt_tempo; /* userticks per second (current) */
+ double rt_tickscoef; /* userticks per hardtick */
+ double rt_mscoef; /* ms per usertick (current) */
+ double rt_userbar; /* userticks per bar */
+ uint16 rt_beatticks; /* hardticks per beat or per frame */
+ double rt_hardbar; /* hardticks per bar */
+} t_mifireadtx;
+
+struct _mifiread
+{
+ t_pd *mr_owner;
+ FILE *mr_fp;
+ t_mifiheader mr_header;
+ t_mifievent mr_event;
+ uint32 mr_scoretime; /* current time in hardticks */
+ uint32 mr_tempo; /* microseconds per beat */
+ uint32 mr_meternum;
+ uint32 mr_meterden;
+ uchar mr_status;
+ uchar mr_channel;
+ int mr_nevents;
+ int mr_ntempi;
+ uint16 mr_hdtracks; /* ntracks, as declared in the file header */
+ uint16 mr_ntracks; /* as actually contained in a file */
+ uint16 mr_trackndx;
+ t_symbol **mr_tracknames;
+ uchar mr_nframes; /* fps if nonzero, else use metrical time */
+ uint16 mr_format; /* anything > 0 handled as 1, FIXME */
+ uint32 mr_bytesleft; /* nbytes remaining to be read from a track */
+ int mr_pass;
+ int mr_eof; /* set in case of early eof (error) */
+ int mr_newtrack; /* reset after reading track's first event */
+ t_mifireadtx mr_ticks;
+};
+
+typedef struct _mifiwritetx
{
- sp->s_bytesleft = 0;
- sp->s_eof = 1;
+ double wt_wholeticks; /* userticks per whole note (set by user) */
+ double wt_deftempo; /* userticks per second (default, adjusted) */
+ double wt_tempo; /* userticks per second (set by user, quantized) */
+ double wt_tickscoef; /* hardticks per usertick */
+ uint16 wt_beatticks; /* hardticks per beat or per frame (set by user) */
+ double wt_mscoef; /* hardticks per ms */
+} t_mifiwritetx;
+
+struct _mifiwrite
+{
+ t_pd *mw_owner;
+ FILE *mw_fp;
+ t_mifiheader mw_header;
+ t_mifievent mw_event;
+ uint32 mw_tempo; /* microseconds per beat */
+ uint32 mw_meternum;
+ uint32 mw_meterden;
+ uchar mw_status;
+ uchar mw_channel;
+ int mw_ntempi;
+ uint16 mw_ntracks;
+ uint16 mw_trackndx;
+ t_symbol **mw_tracknames;
+ uchar mw_nframes; /* fps if nonzero, else use metrical time */
+ uint16 mw_format; /* anything > 0 handled as 1, FIXME */
+ uint32 mw_trackbytes; /* nbytes written to a track so far */
+ int mw_trackdirty; /* after opentrack, before adjusttrack */
+ t_mifiwritetx mw_ticks;
+};
+
+static int mifi_swapping = 1;
+
+static void mifi_initialize(void)
+{
+ unsigned short s = 1;
+ unsigned char c = *(char *)(&s);
+ mifi_swapping = (c != 0);
}
-/* Get next byte from track data.
- On error: return 0 (which is a valid result) and set sp->s_eof.
-*/
-static uchar mifi_getbyte(t_mifi_stream *sp)
+static void mifi_error(t_pd *x, char *fmt, ...)
{
- if (sp->s_bytesleft)
+ char buf[MAXPDSTRING];
+ va_list ap;
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ if (x)
{
- int c;
- if ((c = fgetc(sp->s_fp)) == EOF)
- {
- mifi_earlyeof(sp);
- return (0);
- }
- else
- {
- sp->s_bytesleft--;
- return ((uchar)c);
- }
+ startpost("%s's ", class_getname(*x));
+ pd_error(x, buf);
}
- else return (0);
+ else post("mifi error: %s", buf);
+ va_end(ap);
}
-static uint32 mifi_readbytes(t_mifi_stream *sp, uchar *buf, uint32 size)
+static void mifi_warning(t_pd *x, char *fmt, ...)
{
- size_t res;
- if (size > sp->s_bytesleft)
- size = sp->s_bytesleft;
- if ((res = fread(buf, 1, (size_t)size, sp->s_fp)) == size)
- sp->s_bytesleft -= res;
+ char buf[MAXPDSTRING];
+ va_list ap;
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ if (x)
+ post("%s's warning: %s", class_getname(*x), buf);
else
- mifi_earlyeof(sp);
- return (res);
+ post("mifi warning: %s", buf);
+ va_end(ap);
}
-static int mifi_skipbytes(t_mifi_stream *sp, uint32 size)
+static uint32 mifi_swap4(uint32 n)
{
- if (size > sp->s_bytesleft)
- size = sp->s_bytesleft;
- if (size)
- {
- int res = fseek(sp->s_fp, size, SEEK_CUR);
- if (res < 0)
- mifi_earlyeof(sp);
- else
- sp->s_bytesleft -= size;
- return res;
- }
- else return (0);
+ if (mifi_swapping)
+ return (((n & 0xff) << 24) | ((n & 0xff00) << 8) |
+ ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24));
+ else
+ return (n);
}
-/* helpers handling variable-length quantities */
-
-static size_t mifi_writevarlen(t_mifi_stream *sp, uint32 n)
+static uint16 mifi_swap2(uint16 n)
{
- uint32 buf = n & 0x7f;
- size_t length = 1;
- while ((n >>= 7) > 0)
- {
- buf <<= 8;
- buf |= 0x80;
- buf += n & 0x7f;
- length++;
- }
- return ((fwrite(&buf, 1, length, sp->s_fp) == length) ? length : 0);
+ if (mifi_swapping)
+ return (((n & 0xff) << 8) | ((n & 0xff00) >> 8));
+ else
+ return (n);
}
-static uint32 mifi_readvarlen(t_mifi_stream *sp)
+static int mifievent_initialize(t_mifievent *ep, size_t nalloc)
{
- uint32 n = 0;
- uchar c;
- uint32 count = sp->s_bytesleft;
- if (count > 4) count = 4;
- while (count--)
+ ep->e_length = 0;
+ if (ep->e_data = getbytes(nalloc))
{
- n = (n << 7) + ((c = mifi_getbyte(sp)) & 0x7f);
- if ((c & 0x80) == 0)
- break;
+ ep->e_datasize = nalloc;
+ return (1);
+ }
+ else
+ {
+ ep->e_data = ep->e_dataini;
+ ep->e_datasize = MIFIEVENT_INISIZE;
+ return (0);
}
- return (n);
}
-/* other helpers */
-
-static int mifi_read_start_track(t_mifi_stream *sp)
+static int mifievent_setlength(t_mifievent *ep, size_t length)
{
- t_mifi_trackheader header;
- long skip;
- int notyet = 1;
- do {
- if (fread(&header, 1,
- MIFI_TRACKHEADER_SIZE, sp->s_fp) < MIFI_TRACKHEADER_SIZE)
- goto nomoretracks;
- header.h_length = bifi_swap4(header.h_length);
- if (strncmp(header.h_type, "MTrk", 4))
- {
- char buf[5];
- strncpy(buf, header.h_type, 4);
- buf[5] = '\0';
- if (sp->s_anapass)
- post("unknown chunk %s in midifile -- skipped", buf);
- }
- else if (header.h_length < MIFI_SHORTEST_EVENT)
+ if (length > ep->e_datasize)
+ {
+ size_t newsize = ep->e_datasize;
+ while (newsize < length)
+ newsize *= 2;
+ if (ep->e_data = resizebytes(ep->e_data, ep->e_datasize, newsize))
+ ep->e_datasize = newsize;
+ else
{
- if (sp->s_anapass) post("empty track in midifile -- skipped");
+ ep->e_length = 0;
+ /* rather hopeless... */
+ newsize = MIFIEVENT_NALLOC;
+ if (ep->e_data = getbytes(newsize))
+ ep->e_datasize = newsize;
+ else
+ {
+ ep->e_data = ep->e_dataini;
+ ep->e_datasize = MIFIEVENT_INISIZE;
+ }
+ return (0);
}
- else notyet = 0;
- if (notyet && (skip = header.h_length) &&
- fseek(sp->s_fp, skip, SEEK_CUR) < 0)
- goto nomoretracks;
- } while (notyet);
-
- sp->s_track++;
- sp->s_newtrack = 1;
- sp->s_status = sp->s_channel = 0;
- sp->s_bytesleft = header.h_length;
- sp->s_time = 0;
-
+ }
+ ep->e_length = (uint32)length;
return (1);
-nomoretracks:
- if (sp->s_track == 0)
- if (sp->s_anapass) post("no valid miditracks");
- return (0);
}
-/* public interface */
-
-t_mifi_event *mifi_event_new(void)
+static int mifievent_settext(t_mifievent *ep, unsigned type, char *text)
{
- t_mifi_event *ep = getbytes(sizeof(*ep));
- if (ep && !(ep->e_data = getbytes(ep->e_bufsize = MIFI_EVENT_NALLOC)))
+ if (type > 127)
{
- freebytes(ep, sizeof(*ep));
+ bug("mifievent_settext");
return (0);
}
- return (ep);
-}
-
-void mifi_event_free(t_mifi_event *ep)
-{
- freebytes(ep->e_data, ep->e_bufsize);
- freebytes(ep, sizeof(*ep));
-}
-
-int mifi_event_settext(t_mifi_event *ep, int type, char *text)
-{
- ep->e_delay = 0;
- ep->e_status = MIFI_EVENT_META;
- ep->e_meta = type;
- ep->e_length = strlen(text);
- if (squb_checksize(ep, ep->e_length + 1, 1) <= ep->e_length)
+ if (mifievent_setlength(ep, strlen(text) + 1))
{
- ep->e_length = 0;
+ ep->e_status = MIFIEVENT_META;
+ ep->e_meta = (uchar)type;
+ strcpy(ep->e_data, text);
+ return (1);
+ }
+ else
+ {
+ ep->e_status = 0;
return (0);
}
- strcpy(ep->e_data, text);
- return (1);
}
#ifdef MIFI_DEBUG
-static void mifi_event_printsysex(t_mifi_event *ep)
+static void mifievent_printsysex(t_mifievent *ep)
{
int length = ep->e_length;
uchar *dp = ep->e_data;
startpost("sysex:");
- while (length--) postfloat((float)*dp++);
+ while (length--)
+ postfloat((float)*dp++);
endpost();
}
#endif
-void mifi_event_printmeta(t_mifi_event *ep)
+static void mifievent_printmeta(t_mifievent *ep)
{
- static int isprintable[MIFI_META_MAXPRINTABLE+1] =
+ static int isprintable[MIFIMETA_MAXPRINTABLE+1] =
{
#ifdef MIFI_DEBUG
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
@@ -232,173 +331,301 @@ void mifi_event_printmeta(t_mifi_event *ep)
0, 0, 1, 1, 1, 1, 1, 1
#endif
};
- static char *printformat[MIFI_META_MAXPRINTABLE+1] =
+ static char *printformat[MIFIMETA_MAXPRINTABLE+1] =
{
"", "text: %s", "copyright: %s", "track name: %s",
"instrument name: %s", "lyric: %s", "marker: %s", "cue point: %s"
};
- if (ep->e_meta <= MIFI_META_MAXPRINTABLE)
+ if (ep->e_meta <= MIFIMETA_MAXPRINTABLE)
{
+#if 0
if (isprintable[ep->e_meta] && printformat[ep->e_meta])
post(printformat[ep->e_meta], ep->e_data);
+#endif
}
-#ifdef MIFI_DEBUG /* in verbose mode tempo printout done only after sorting */
- else if (ep->e_meta == MIFI_META_TEMPO)
+#ifdef MIFI_DEBUG
+ else if (ep->e_meta == MIFIMETA_TEMPO)
{
- int tempo = bifi_swap4(*(uint32 *)ep->e_data);
- post("tempo %d after %d", tempo, ep->e_delay);
+ int tempo = mifi_swap4(*(uint32 *)ep->e_data);
+ post("tempo (hard) %d after %d", tempo, ep->e_delay);
+ }
+ else if (ep->e_meta == MIFIMETA_TIMESIG)
+ {
+ post("meter %d/%d after %d",
+ ep->e_data[0], (1 << ep->e_data[1]), ep->e_delay);
}
#endif
}
-void mifi_stream_reset(t_mifi_stream *sp)
+static void mifiread_earlyeof(t_mifiread *mr)
{
- sq_reset(sp);
- sp->s_status = sp->s_channel = 0;
- sp->s_timecoef = sq_msecs2ticks(sp, 0);
- sp->s_bytesleft = 0;
+ mr->mr_bytesleft = 0;
+ mr->mr_eof = 1;
}
-t_mifi_stream *mifi_stream_new(void)
+/* Get next byte from track data. On error: return 0 (which is a valid
+ result) and set mr->mr_eof. */
+static uchar mifiread_getbyte(t_mifiread *mr)
{
- t_mifi_stream *sp = sq_new();
- if (sp)
+ if (mr->mr_bytesleft)
{
- if (sp->s_auxeve = mifi_event_new())
+ int c;
+ if ((c = fgetc(mr->mr_fp)) == EOF)
{
- sp->s_hdtracks = 1;
- sp->s_alltracks = 0;
- mifi_stream_reset(sp); /* LATER avoid calling sq_reset() twice */
+ mifiread_earlyeof(mr);
+ return (0);
}
else
{
- mifi_stream_free(sp);
- return (0);
+ mr->mr_bytesleft--;
+ return ((uchar)c);
}
}
- return (sp);
+ else return (0);
}
-void mifi_stream_free(t_mifi_stream *sp)
+static uint32 mifiread_getbytes(t_mifiread *mr, uchar *buf, uint32 size)
{
- if (sp->s_auxeve)
- mifi_event_free(sp->s_auxeve);
- sq_free(sp);
+ size_t res;
+ if (size > mr->mr_bytesleft)
+ size = mr->mr_bytesleft;
+ if ((res = fread(buf, 1, (size_t)size, mr->mr_fp)) == size)
+ mr->mr_bytesleft -= res;
+ else
+ mifiread_earlyeof(mr);
+ return (res);
}
-/* Open midifile for reading, parse the header. May be used as t_mifi_stream
- allocator (if sp is a null pointer), to be freed by mifi_read_end() or
- explicitly.
-
- Return value: null on error, else sp if passed a valid pointer, else pointer
- to an allocated structure.
-*/
-t_mifi_stream *mifi_read_start(t_mifi_stream *sp,
- const char *filename, const char *dirname,
- int complain)
+static int mifiread_skipbytes(t_mifiread *mr, uint32 size)
{
- t_mifi_stream *result = sp;
- t_bifi bifi;
- t_bifi *bp = &bifi;
- t_mifi_header header;
- long skip;
+ if (size > mr->mr_bytesleft)
+ size = mr->mr_bytesleft;
+ if (size)
+ {
+ int res = fseek(mr->mr_fp, size, SEEK_CUR);
+ if (res < 0)
+ mifiread_earlyeof(mr);
+ else
+ mr->mr_bytesleft -= size;
+ return res;
+ }
+ else return (0);
+}
- bifi_new(bp, (char *)&header, MIFI_HEADER_SIZE);
- if (!bifi_read_start(bp, filename, dirname))
+static uint32 mifiread_getvarlen(t_mifiread *mr)
+{
+ uint32 n = 0;
+ uchar c;
+ uint32 count = mr->mr_bytesleft;
+ if (count > 4)
+ count = 4;
+ while (count--)
{
- bifi_error_report(bp);
- bifi_free(bp);
- return (0);
+ n = (n << 7) + ((c = mifiread_getbyte(mr)) & 0x7f);
+ if ((c & 0x80) == 0)
+ break;
}
- if (strncmp(header.h_type, "MThd", 4))
- goto badheader;
- header.h_length = bifi_swap4(header.h_length);
- if (header.h_length < MIFI_HEADERDATA_SIZE)
- goto badheader;
- if (skip = header.h_length - MIFI_HEADERDATA_SIZE)
+ return (n);
+}
+
+static size_t mifiwrite_putvarlen(t_mifiwrite *mw, uint32 n)
+{
+ uint32 buf = n & 0x7f;
+ size_t length = 1;
+ while ((n >>= 7) > 0)
{
- post("%ld extra bytes of midifile header -- skipped", skip);
- if (fseek(bp->b_fp, skip, SEEK_CUR) < 0)
- goto badstart;
+ buf <<= 8;
+ buf |= 0x80;
+ buf += n & 0x7f;
+ length++;
}
+ return ((fwrite(&buf, 1, length, mw->mw_fp) == length) ? length : 0);
+}
- /* since we will tolerate other incompatibilities, now we can allocate */
- if (sp) mifi_stream_reset(sp);
- else
+static void mifiread_updateticks(t_mifiread *mr)
+{
+ if (mr->mr_nframes)
{
- if (!(result = mifi_stream_new()))
- goto badstart;
- result->s_autoalloc = 1;
+ mr->mr_ticks.rt_userbar = mr->mr_ticks.rt_wholeticks;
+ /* LATER ntsc */
+ mr->mr_ticks.rt_tickscoef = mr->mr_ticks.rt_deftempo /
+ (mr->mr_nframes * mr->mr_ticks.rt_beatticks);
+ mr->mr_ticks.rt_hardbar = mr->mr_ticks.rt_userbar /
+ mr->mr_ticks.rt_tickscoef;
+ mr->mr_ticks.rt_tempo = mr->mr_ticks.rt_deftempo;
}
- result->s_fp = bp->b_fp;
- result->s_format = bifi_swap2(header.h_format);
- result->s_hdtracks = bifi_swap2(header.h_ntracks);
- result->s_nticks = bifi_swap2(header.h_division);
- if (result->s_nticks & 0x8000)
+ else
{
- result->s_nframes = (result->s_nticks >> 8);
- result->s_nticks &= 0xff;
+ mr->mr_ticks.rt_userbar =
+ (mr->mr_ticks.rt_wholeticks * mr->mr_meternum) / mr->mr_meterden;
+ mr->mr_ticks.rt_hardbar =
+ (mr->mr_ticks.rt_beatticks * 4. * mr->mr_meternum) /
+ mr->mr_meterden;
+ mr->mr_ticks.rt_tickscoef =
+ mr->mr_ticks.rt_wholeticks / (mr->mr_ticks.rt_beatticks * 4.);
+ mr->mr_ticks.rt_tempo =
+ ((double)MIFIHARD_DEFTEMPO * mr->mr_ticks.rt_deftempo) /
+ ((double)mr->mr_tempo);
+ if (mr->mr_ticks.rt_tempo < MIFI_TICKEPSILON)
+ {
+ bug("mifiread_updateticks");
+ mr->mr_ticks.rt_tempo = mr->mr_ticks.rt_deftempo;
+ }
}
- else result->s_nframes = 0;
- if (result->s_nticks == 0)
- goto badheader;
+ mr->mr_ticks.rt_mscoef = 1000. / mr->mr_ticks.rt_tempo;
+}
- return (result);
-badheader:
- if (complain)
- post("`%s\' is not a valid midifile", filename);
-badstart:
- if (result && !sp) mifi_stream_free(result);
- bifi_free(bp);
- return (0);
+static void mifiread_resetticks(t_mifiread *mr)
+{
+ mr->mr_ticks.rt_wholeticks = MIFIUSER_DEFWHOLETICKS;
+ mr->mr_ticks.rt_deftempo = MIFIUSER_DEFTEMPO;
+ mr->mr_ticks.rt_beatticks = MIFIHARD_DEFBEATTICKS;
}
-int mifi_read_restart(t_mifi_stream *sp)
+static void mifiread_reset(t_mifiread *mr)
{
- FILE *fp = sp->s_fp;
- mifi_stream_reset(sp);
- sp->s_anapass = 0;
- sp->s_fp = fp;
- return (fseek(fp, 0, SEEK_SET) ? 0 : 1);
+ mr->mr_eof = 0;
+ mr->mr_newtrack = 0;
+ mr->mr_fp = 0;
+ mr->mr_format = 0;
+ mr->mr_nframes = 0;
+ mr->mr_tempo = MIFIHARD_DEFTEMPO;
+ mr->mr_meternum = 4;
+ mr->mr_meterden = 4;
+ mr->mr_ntracks = 0;
+ mr->mr_status = 0;
+ mr->mr_channel = 0;
+ mr->mr_bytesleft = 0;
+ mr->mr_pass = 0;
+ mr->mr_hdtracks = 1;
+ mr->mr_tracknames = 0;
+ mifiread_updateticks(mr);
}
-/* Close midifile and free t_mifi_stream if it was allocated
- by mifi_read_start() */
-void mifi_read_end(t_mifi_stream *sp)
+/* Calling this is optional. The obligatory part is supplied elsewhere:
+ in the constructor (owner), and in the doit() call (hook function). */
+void mifiread_setuserticks(t_mifiread *mr, double wholeticks)
{
- if (sp->s_fp) fclose(sp->s_fp);
- if (sp->s_autoalloc) mifi_stream_free(sp);
+ mr->mr_ticks.rt_wholeticks = (wholeticks > MIFI_TICKEPSILON ?
+ wholeticks : MIFIUSER_DEFWHOLETICKS);
+ mr->mr_ticks.rt_deftempo = mr->mr_ticks.rt_wholeticks *
+ (MIFIUSER_DEFTEMPO / MIFIUSER_DEFWHOLETICKS);
+ mifiread_updateticks(mr);
}
-/* Read next event from midifile.
- Return value: see #defines in mifi.h.
-*/
-int mifi_read_event(t_mifi_stream *sp, t_mifi_event *ep)
+/* open a file and read its header */
+static int mifiread_startfile(t_mifiread *mr, const char *filename,
+ const char *dirname, int complain)
{
+ char errmess[MAXPDSTRING], path[MAXPDSTRING], *fnameptr;
+ int fd;
+ mr->mr_fp = 0;
+ if ((fd = open_via_path(dirname, filename,
+ "", path, &fnameptr, MAXPDSTRING, 1)) < 0)
+ {
+ strcpy(errmess, "cannot open");
+ goto rstartfailed;
+ }
+ close(fd);
+ if (path != fnameptr)
+ {
+ char *slashpos = path + strlen(path);
+ *slashpos++ = '/';
+ /* try not to be dependent on current open_via_path() implementation */
+ if (fnameptr != slashpos)
+ strcpy(slashpos, fnameptr);
+ }
+ sys_bashfilename(path, path);
+ if (!(mr->mr_fp = fopen(path, "rb")))
+ {
+ strcpy(errmess, "cannot open");
+ goto rstartfailed;
+ }
+ if (fread(&mr->mr_header, 1,
+ MIFIHARD_HEADERSIZE, mr->mr_fp) < MIFIHARD_HEADERSIZE)
+ {
+ strcpy(errmess, "missing header of");
+ goto rstartfailed;
+ }
+ return (1);
+rstartfailed:
+ if (complain)
+ mifi_error(mr->mr_owner, "%s file \"%s\" (errno %d: %s)",
+ errmess, filename, errno, strerror(errno));
+ if (mr->mr_fp)
+ {
+ fclose(mr->mr_fp);
+ mr->mr_fp = 0;
+ }
+ return (0);
+}
+
+static int mifiread_starttrack(t_mifiread *mr)
+{
+ t_mifitrackheader th;
+ long skip;
+ int notyet = 1;
+ do {
+ if (fread(&th, 1, MIFIHARD_TRACKHEADERSIZE,
+ mr->mr_fp) < MIFIHARD_TRACKHEADERSIZE)
+ goto nomoretracks;
+ th.th_length = mifi_swap4(th.th_length);
+ if (strncmp(th.th_type, "MTrk", 4))
+ {
+ char buf[8];
+ strncpy(buf, th.th_type, 4);
+ buf[4] = 0;
+ if (mr->mr_pass == 1)
+ mifi_warning(mr->mr_owner,
+ "unknown chunk %s in midi file... skipped", buf);
+ }
+ else if (th.th_length < MIFI_SHORTESTEVENT)
+ {
+ if (mr->mr_pass == 1)
+ mifi_warning(mr->mr_owner,
+ "empty track in midi file... skipped");
+ }
+ else notyet = 0;
+ if (notyet && (skip = th.th_length) &&
+ fseek(mr->mr_fp, skip, SEEK_CUR) < 0)
+ goto nomoretracks;
+ } while (notyet);
+ mr->mr_scoretime = 0;
+ mr->mr_newtrack = 1;
+ mr->mr_status = mr->mr_channel = 0;
+ mr->mr_bytesleft = th.th_length;
+ return (1);
+nomoretracks:
+ if (mr->mr_ntracks == 0 && mr->mr_pass == 1)
+ mifi_warning(mr->mr_owner, "no valid miditracks");
+ return (0);
+}
+
+static int mifiread_nextevent(t_mifiread *mr)
+{
+ t_mifievent *ep = &mr->mr_event;
uchar status, channel;
uint32 length;
-
- sp->s_newtrack = 0;
+ mr->mr_newtrack = 0;
nextattempt:
- if (sp->s_bytesleft < MIFI_SHORTEST_EVENT && !mifi_read_start_track(sp))
- return (MIFI_READ_EOF);
-
- sp->s_time += (ep->e_delay = mifi_readvarlen(sp));
-
- if ((status = mifi_getbyte(sp)) < 0x80)
+ if (mr->mr_bytesleft < MIFI_SHORTESTEVENT &&
+ !mifiread_starttrack(mr))
+ return (MIFIREAD_EOF);
+ mr->mr_scoretime += (mr->mr_event.e_delay = mifiread_getvarlen(mr));
+ if ((status = mifiread_getbyte(mr)) < 0x80)
{
- if (MIFI_IS_CHANNEL(sp->s_status))
+ if (MIFI_ISCHANNEL(mr->mr_status))
{
ep->e_data[0] = status;
ep->e_length = 1;
- status = sp->s_status;
- ep->e_channel = sp->s_channel;
+ status = mr->mr_status;
+ ep->e_channel = mr->mr_channel;
}
else
{
- if (sp->s_anapass)
- post("missing running status in midifile -- \
- skip to end of track");
+ if (mr->mr_pass == 1)
+ mifi_warning(mr->mr_owner,
+ "missing running status in midi file... skip to end of track");
goto endoftrack;
}
}
@@ -409,165 +636,257 @@ nextattempt:
{
if (ep->e_length == 0)
{
- ep->e_data[0] = mifi_getbyte(sp);
+ ep->e_data[0] = mifiread_getbyte(mr);
ep->e_length = 1;
- sp->s_status = status & 0xf0;
- sp->s_channel = ep->e_channel = status & 0x0f;
- status = sp->s_status;
+ mr->mr_status = status & 0xf0;
+ mr->mr_channel = ep->e_channel = status & 0x0f;
+ status = mr->mr_status;
}
- if (!MIFI_ONE_DATABYTE(status))
+ if (!MIFI_ONEDATABYTE(status))
{
- ep->e_data[1] = mifi_getbyte(sp);
+ ep->e_data[1] = mifiread_getbyte(mr);
ep->e_length = 2;
}
}
/* system exclusive */
- else if (status == MIFI_SYSEX_FIRST || status == MIFI_SYSEX_NEXT)
+ else if (status == MIFISYSEX_FIRST || status == MIFISYSEX_NEXT)
{
- length = mifi_readvarlen(sp);
- if (squb_checksize(ep, length, 1) < length)
- {
- if (mifi_skipbytes(sp, length) < 0)
- return (MIFI_READ_FATAL);
- goto nextattempt;
- }
- /* LATER make the allocation optional */
- if (mifi_readbytes(sp, ep->e_data, length) != length)
- return (MIFI_READ_FATAL);
- ep->e_length = length;
-#ifdef MIFI_DEBUG
- if (sp->s_anapass) mifi_event_printsysex(ep);
-#elif defined MIFI_VERBOSE
- if (sp->s_anapass) post("got %d bytes of sysex", length);
-#endif
+ length = mifiread_getvarlen(mr);
+ /* FIXME optional read */
+ if (mifiread_skipbytes(mr, length) < 0)
+ return (MIFIREAD_FATAL);
+ goto nextattempt;
}
/* meta-event */
- else if (status == MIFI_EVENT_META)
+ else if (status == MIFIEVENT_META)
{
- ep->e_meta = mifi_getbyte(sp);
- length = mifi_readvarlen(sp);
+ ep->e_meta = mifiread_getbyte(mr);
+ length = mifiread_getvarlen(mr);
if (ep->e_meta > 127)
{
/* try to skip corrupted meta-event (quietly) */
#ifdef MIFI_VERBOSE
- if (sp->s_anapass) post("bad meta: %d > 127", ep->e_meta);
+ if (mr->mr_pass == 1)
+ mifi_warning(mr->mr_owner, "bad meta: %d > 127", ep->e_meta);
#endif
- if (mifi_skipbytes(sp, length) < 0)
- return (MIFI_READ_FATAL);
+ if (mifiread_skipbytes(mr, length) < 0)
+ return (MIFIREAD_FATAL);
goto nextattempt;
}
switch (ep->e_meta)
{
- case MIFI_META_EOT:
+ case MIFIMETA_EOT:
if (length)
{
/* corrupted eot: ignore and skip to the real end of track */
#ifdef MIFI_VERBOSE
- if (sp->s_anapass) post("corrupted eot, length %d", length);
+ if (mr->mr_pass == 1)
+ mifi_warning(mr->mr_owner,
+ "corrupted eot, length %d", length);
#endif
goto endoftrack;
}
break;
- case MIFI_META_TEMPO:
+ case MIFIMETA_TEMPO:
if (length != 3)
{
- if (sp->s_anapass)
- post("corrupted event in midifile -- skip to end of track");
+ if (mr->mr_pass == 1)
+ mifi_warning(mr->mr_owner,
+ "corrupted tempo event in midi file... skip to end of track");
goto endoftrack;
}
- if (mifi_readbytes(sp, ep->e_data + 1, 3) != 3)
- return (MIFI_READ_FATAL);
+ if (mifiread_getbytes(mr, ep->e_data + 1, 3) != 3)
+ return (MIFIREAD_FATAL);
ep->e_data[0] = 0;
- sp->s_tempo = bifi_swap4(*(uint32 *)ep->e_data);
+ mr->mr_tempo = mifi_swap4(*(uint32 *)ep->e_data);
+ if (!mr->mr_tempo)
+ mr->mr_tempo = MIFIHARD_DEFTEMPO;
+ mifiread_updateticks(mr);
+ break;
+ case MIFIMETA_TIMESIG:
+ if (length != 4)
+ {
+ if (mr->mr_pass == 1)
+ mifi_warning(mr->mr_owner,
+ "corrupted time signature event in midi file... skip to end of track");
+ goto endoftrack;
+ }
+ if (mifiread_getbytes(mr, ep->e_data, 4) != 4)
+ return (MIFIREAD_FATAL);
+ mr->mr_meternum = ep->e_data[0];
+ mr->mr_meterden = (1 << ep->e_data[1]);
+ if (!mr->mr_meternum || !mr->mr_meterden)
+ mr->mr_meternum = mr->mr_meterden = 4;
+ mifiread_updateticks(mr);
+#ifdef MIFI_DEBUG
+ if (mr->mr_pass == 1)
+ post("barspan (hard) %g", mr->mr_ticks.rt_hardbar);
+#endif
break;
default:
- if (squb_checksize(ep, length + 1, 1) <= length)
+ if (length + 1 > MIFIEVENT_NALLOC)
{
- if (mifi_skipbytes(sp, length) < 0)
- return (MIFI_READ_FATAL);
+ if (mifiread_skipbytes(mr, length) < 0)
+ return (MIFIREAD_FATAL);
goto nextattempt;
}
- if (mifi_readbytes(sp, ep->e_data, length) != length)
- return (MIFI_READ_FATAL);
+ if (mifiread_getbytes(mr, ep->e_data, length) != length)
+ return (MIFIREAD_FATAL);
ep->e_length = length;
- if (ep->e_meta && ep->e_meta <= MIFI_META_MAXPRINTABLE)
+ if (ep->e_meta && ep->e_meta <= MIFIMETA_MAXPRINTABLE)
ep->e_data[length] = '\0'; /* text meta-event nultermination */
}
}
else
{
- if (sp->s_anapass)
- post("unknown event type in midifile -- skip to end of track");
+ if (mr->mr_pass == 1)
+ mifi_warning(mr->mr_owner,
+ "unknown event type in midi file... skip to end of track");
goto endoftrack;
}
+ return ((ep->e_status = status) == MIFIEVENT_META ? ep->e_meta : status);
+endoftrack:
+ if (mifiread_skipbytes(mr, mr->mr_bytesleft) < 0)
+ return (MIFIREAD_FATAL);
+ else
+ return (MIFIREAD_SKIP);
+}
- return ((ep->e_status = status) == MIFI_EVENT_META ? ep->e_meta : status);
+static int mifiread_restart(t_mifiread *mr, int complain)
+{
+ mr->mr_eof = 0;
+ mr->mr_newtrack = 0;
+ mr->mr_status = 0;
+ mr->mr_channel = 0;
+ mr->mr_bytesleft = 0;
+ mr->mr_pass = 0;
+ if (fseek(mr->mr_fp, 0, SEEK_SET))
+ {
+ if (complain)
+ mifi_error(mr->mr_owner,
+ "file error (errno %d: %s)", errno, strerror(errno));
+ return (0);
+ }
+ else return (1);
+}
-endoftrack:
- if (mifi_skipbytes(sp, sp->s_bytesleft) < 0)
- return (MIFI_READ_FATAL);
- return (MIFI_READ_SKIP);
+static int mifiread_doopen(t_mifiread *mr, const char *filename,
+ const char *dirname, int complain)
+{
+ long skip;
+ mifiread_reset(mr);
+ if (!mifiread_startfile(mr, filename, dirname, complain))
+ return (0);
+ if (strncmp(mr->mr_header.h_type, "MThd", 4))
+ goto badheader;
+ mr->mr_header.h_length = mifi_swap4(mr->mr_header.h_length);
+ if (mr->mr_header.h_length < MIFIHARD_HEADERDATASIZE)
+ goto badheader;
+ if (skip = mr->mr_header.h_length - MIFIHARD_HEADERDATASIZE)
+ {
+ mifi_warning(mr->mr_owner,
+ "%ld extra bytes of midi file header... skipped", skip);
+ if (fseek(mr->mr_fp, skip, SEEK_CUR) < 0)
+ goto badstart;
+ }
+ mr->mr_format = mifi_swap2(mr->mr_header.h_format);
+ mr->mr_hdtracks = mifi_swap2(mr->mr_header.h_ntracks);
+ if (mr->mr_hdtracks > 1000) /* a sanity check */
+ mifi_warning(mr->mr_owner, "%d tracks declared in midi file \"%s\"",
+ mr->mr_hdtracks, filename);
+ mr->mr_tracknames = getbytes(mr->mr_hdtracks * sizeof(*mr->mr_tracknames));
+ mr->mr_ticks.rt_beatticks = mifi_swap2(mr->mr_header.h_division);
+ if (mr->mr_ticks.rt_beatticks & 0x8000)
+ {
+ mr->mr_nframes = (mr->mr_ticks.rt_beatticks >> 8);
+ mr->mr_ticks.rt_beatticks &= 0xff;
+ }
+ else mr->mr_nframes = 0;
+ if (mr->mr_ticks.rt_beatticks == 0)
+ goto badheader;
+ mifiread_updateticks(mr);
+#ifdef MIFI_DEBUG
+ if (mr->mr_nframes)
+ post("midi file (format %d): %d tracks, %d ticks (%d smpte frames)",
+ mr->mr_format, mr->mr_hdtracks,
+ mr->mr_ticks.rt_beatticks, mr->mr_nframes);
+ else
+ post("midi file (format %d): %d tracks, %d ticks per beat",
+ mr->mr_format, mr->mr_hdtracks, mr->mr_ticks.rt_beatticks);
+#endif
+ return (1);
+badheader:
+ if (complain)
+ mifi_error(mr->mr_owner, "\"%s\" is not a valid midi file", filename);
+badstart:
+ fclose(mr->mr_fp);
+ mr->mr_fp = 0;
+ return (0);
}
/* Gather statistics (nevents, ntracks, ntempi), pick track names, and
allocate the maps. To be called in the first pass of reading.
-*/
-/* LATER consider optional reading of nonchannel events */
-int mifi_read_analyse(t_mifi_stream *sp)
-{
- t_mifi_event *ep = sp->s_auxeve;
- int evtype, result = MIFI_READ_FATAL;
- int isnewtrack = 0;
- int i;
+ LATER consider optional reading of nonchannel events. */
+/* FIXME complaining */
+static int mifiread_analyse(t_mifiread *mr, int complain)
+{
+ t_mifievent *ep = &mr->mr_event;
+ int i, evtype, isnewtrack = 0;
char tnamebuf[MAXPDSTRING];
- t_symbol *tnamesym = 0;
- t_squack *trp = 0;
+ t_symbol **tnamep = 0;
+ mr->mr_pass = 1;
*tnamebuf = '\0';
- sp->s_alltracks = sp->s_ntracks = 0;
- sp->s_nevents = 0;
- sp->s_ntempi = 0;
-
- while ((evtype = mifi_read_event(sp, ep)) >= MIFI_READ_SKIP)
+ mr->mr_ntracks = 0;
+ mr->mr_nevents = 0;
+ mr->mr_ntempi = 0;
+ while ((evtype = mifiread_nextevent(mr)) >= MIFIREAD_SKIP)
{
- if (evtype == MIFI_READ_SKIP)
+ if (evtype == MIFIREAD_SKIP)
continue;
- if (sp->s_newtrack)
+ if (mr->mr_newtrack)
{
#ifdef MIFI_VERBOSE
- post("track %d", sp->s_track);
+ post("track %d", mr->mr_ntracks);
#endif
isnewtrack = 1;
*tnamebuf = '\0';
- tnamesym = 0; /* set to nonzero for nonempty tracks only */
+ tnamep = 0; /* set to nonzero for nonempty tracks only */
}
- if (MIFI_IS_CHANNEL(evtype))
+ if (MIFI_ISCHANNEL(evtype))
{
if (isnewtrack)
{
isnewtrack = 0;
- sp->s_alltracks++;
- if (!(trp = squax_add(sp)))
+ tnamep = mr->mr_tracknames + mr->mr_ntracks;
+ mr->mr_ntracks++;
+ if (mr->mr_ntracks > mr->mr_hdtracks)
+ {
+ if (complain)
+ mifi_error(mr->mr_owner,
+ "midi file has more tracks than header-declared %d", mr->mr_hdtracks);
+ /* FIXME grow? */
goto anafail;
+ }
if (*tnamebuf)
{
- tnamesym = trp->tr_name = gensym(tnamebuf);
+ *tnamep = gensym(tnamebuf);
#ifdef MIFI_DEBUG
- post("nonempty track name %s", tnamesym->s_name);
+ post("nonempty track name %s", (*tnamep)->s_name);
#endif
}
- else tnamesym = trp->tr_name = &s_;
+ else *tnamep = &s_;
}
- sp->s_nevents++;
+ mr->mr_nevents++;
}
else if (evtype < 0x80)
{
- mifi_event_printmeta(ep);
- if (evtype == MIFI_META_TEMPO)
- sp->s_ntempi++;
- else if (evtype == MIFI_META_TRACKNAME)
+ mifievent_printmeta(ep);
+ if (evtype == MIFIMETA_TEMPO)
+ mr->mr_ntempi++;
+ else if (evtype == MIFIMETA_TRACKNAME)
{
char *p1 = ep->e_data;
if (*p1 &&
@@ -582,302 +901,581 @@ int mifi_read_analyse(t_mifi_stream *sp)
do if (*p2 == ' ' || *p2 == ',' || *p2 == ';')
*p2 = '-';
while (*++p2);
- if (tnamesym == &s_)
- { /* trackname after channel-event */
- if (trp) /* redundant check */
- tnamesym = trp->tr_name = gensym(p1);
+ if (tnamep)
+ {
+ if (*tnamep == &s_)
+ /* trackname after channel-event */
+ *tnamep = gensym(p1);
+ else
+ strcpy(tnamebuf, p1);
}
- else strcpy(tnamebuf, p1);
}
}
}
}
}
- if (evtype != MIFI_READ_EOF)
- goto anafail;
-
- i = sp->s_ntracks;
- while (--i >= 0)
+ if (evtype == MIFIREAD_EOF)
{
- if (!sp->s_track_name(i) || sp->s_track_name(i) == &s_)
+ for (i = 0, tnamep = mr->mr_tracknames; i < mr->mr_ntracks; i++, tnamep++)
{
- sprintf(tnamebuf, "%d-track", i);
- sp->s_track_name(i) = gensym(tnamebuf);
+ if (!*tnamep || *tnamep == &s_)
+ {
+ sprintf(tnamebuf, "%d-track", i);
+ *tnamep = gensym(tnamebuf);
+ }
}
+ return (MIFIREAD_EOF);
}
-
- /* now (re)allocate the buffers */
- if (squb_checksize(sp->s_mytempi,
- sp->s_ntempi, sizeof(t_squmpo)) < sp->s_ntempi)
- goto anafail;
- sp->s_track_nevents(0) = 0;
- sp->s_track_nevents(sp->s_ntracks) = sp->s_nevents; /* guard point */
-
- result = evtype;
+ else return (evtype);
anafail:
- return (result);
-}
-
-/* To be called in second pass of reading */
-/* LATER do not trust analysis: in case of inconsistency give up or checksize */
-int mifi_read_doit(t_mifi_stream *sp)
-{
- t_mifi_event *ep = sp->s_auxeve;
- t_squiter *it = sp->s_myiter;
- t_squiter_seekhook seekhook = squiter_seekhook(it);
- t_squiter_incrhook incrhook = squiter_incrhook(it);
- t_squiter_setevehook evehook = squiter_setevehook(it);
- t_squiter_settimhook timhook = squiter_settimhook(it);
- t_squiter_settarhook tarhook = squiter_settarhook(it);
- int evtype, result = MIFI_READ_FATAL;
- int nevents = sp->s_nevents; /* three proxies... */
- int ntracks = sp->s_ntracks;
- int ntempi = sp->s_ntempi;
- int trackno = 0;
- t_symbol *trackname = 0;
- int isnewtrack = 0;
- t_squmpo *tp = sp->s_tempomap;
-
- if (!it || !seekhook(it, 0))
- goto readfailed;
-
- while ((evtype = mifi_read_event(sp, ep)) >= MIFI_READ_SKIP)
- {
- if (evtype == MIFI_READ_SKIP)
+ return (MIFIREAD_FATAL);
+}
+
+/* to be called in the second pass of reading */
+int mifiread_doit(t_mifiread *mr, t_mifireadhook hook, void *hookdata)
+{
+ int evtype, ntracks = 0, isnewtrack = 0;
+ mr->mr_pass = 2;
+ mr->mr_trackndx = 0;
+ while ((evtype = mifiread_nextevent(mr)) >= MIFIREAD_SKIP)
+ {
+ if (evtype == MIFIREAD_SKIP)
continue;
- if (sp->s_newtrack)
+ if (mr->mr_newtrack)
isnewtrack = 1;
- if (MIFI_IS_CHANNEL(evtype))
+ if (isnewtrack && MIFI_ISCHANNEL(evtype))
{
- int ret;
- if (isnewtrack)
- {
- isnewtrack = 0;
- trackname = sp->s_track_name(trackno);
- trackno++;
- if (!trackname || trackname == &s_)
- {
- bug("mifi_read_doit: empty track name");
- trackname = gensym("bug-track");
- }
- }
- sp->s_track_nevents(trackno)++;
- if (ret = squiter_inrange(it))
+ isnewtrack = 0;
+ mr->mr_trackndx = ntracks++;
+ if (ntracks > mr->mr_ntracks)
{
- evehook(it, (t_squeve *)ep, &ret);
- /* We store onset times instead of delta times, because:
- 1) some deltas may represent delays since nonchannel events;
- 2) we'll need onsets while merging the tracks. */
- if (ret) timhook(it, (t_float)sp->s_time, &ret);
- if (ret) tarhook(it, trackname, &ret);
+ bug("mifiread_doit: too many tracks");
+ goto doitfail;
}
- if (ret)
- incrhook(it);
- else
- goto readfailed;
- }
- else if (evtype < 0x80)
- {
- if (evtype == MIFI_META_TEMPO)
+ if (!mr->mr_tracknames[mr->mr_trackndx] ||
+ mr->mr_tracknames[mr->mr_trackndx] == &s_)
{
- tp->te_onset = sp->s_time;
- tp->te_value = sp->s_tempo;
- tp++;
+ bug("mifiread_doit: empty track name");
+ mr->mr_tracknames[mr->mr_trackndx] = gensym("bug-track");
}
}
+ if (!hook(mr, hookdata, evtype))
+ goto doitfail;
}
- if (evtype != MIFI_READ_EOF)
- goto readfailed;
+ if (evtype == MIFIREAD_EOF)
+ {
+#ifdef MIFI_DEBUG
+ if (evtype == MIFIREAD_EOF)
+ post("finished reading %d events from midi file", mr->mr_nevents);
+#endif
+ return (MIFIREAD_EOF);
+ }
+doitfail:
+ return (MIFIREAD_FATAL);
+}
+
+/* mifiread_get... calls to be used in the main read routine */
- result = evtype;
-readfailed:
- return (result);
+int mifiread_getnevents(t_mifiread *mr)
+{
+ return (mr->mr_nevents);
}
-/* Open midifile for saving, write the header. May be used as t_mifi_stream
- allocator (if sp is a null pointer), to be freed by mifi_write_end() or
- explicitly.
+int mifiread_getntempi(t_mifiread *mr)
+{
+ return (mr->mr_ntempi);
+}
- Return value: null on error, else sp if passed a valid pointer, else pointer
- to allocated structure.
-*/
-t_mifi_stream *mifi_write_start(t_mifi_stream *sp,
- const char *filename, const char *dirname)
+int mifiread_gethdtracks(t_mifiread *mr)
{
- t_mifi_stream *result = sp;
- t_bifi bifi;
- t_bifi *bp = &bifi;
- t_mifi_header header;
+ return (mr->mr_hdtracks);
+}
- /* this must precede bifi_swap() calls */
- bifi_new(bp, (char *)&header, MIFI_HEADER_SIZE);
+int mifiread_getformat(t_mifiread *mr)
+{
+ return (mr->mr_format);
+}
- if (sp->s_format == 0)
- {
- if (sp->s_ntracks != 1)
- goto startfailure; /* LATER replace with a warning only? */
-#ifdef MIFI_VERBOSE
- post("writing singletrack midifile %s", filename);
-#endif
- }
-#ifdef MIFI_VERBOSE
- else post("writing midifile %s (%d tracks)", filename, sp->s_ntracks);
-#endif
+int mifiread_getnframes(t_mifiread *mr)
+{
+ return (mr->mr_nframes);
+}
- strncpy(header.h_type, "MThd", 4);
- header.h_length = bifi_swap4(MIFI_HEADERDATA_SIZE);
- if (sp)
- {
- if (!sp->s_hdtracks || !sp->s_nticks)
- goto startfailure;
- header.h_format = bifi_swap2(sp->s_format);
- header.h_ntracks = bifi_swap2(sp->s_hdtracks);
- if (sp->s_nframes)
- header.h_division = ((sp->s_nframes << 8) | sp->s_nticks) | 0x8000;
- else
- header.h_division = sp->s_nticks & 0x7fff;
- header.h_division = bifi_swap2(header.h_division);
- }
+int mifiread_getbeatticks(t_mifiread *mr)
+{
+ return (mr->mr_ticks.rt_beatticks);
+}
+
+double mifiread_getdeftempo(t_mifiread *mr)
+{
+ return (mr->mr_ticks.rt_deftempo);
+}
+
+/* mifiread_get... calls to be used in a mifireadhook */
+
+int mifiread_getbarindex(t_mifiread *mr)
+{
+ return (mr->mr_scoretime / (int)mr->mr_ticks.rt_hardbar);
+}
+
+double mifiread_getbarspan(t_mifiread *mr)
+{
+ return (mr->mr_ticks.rt_userbar);
+}
+
+double mifiread_gettick(t_mifiread *mr)
+{
+ return (mr->mr_ticks.rt_tickscoef *
+ (mr->mr_scoretime % (int)mr->mr_ticks.rt_hardbar));
+}
+
+double mifiread_getscoretime(t_mifiread *mr)
+{
+ return (mr->mr_ticks.rt_tickscoef * mr->mr_scoretime);
+}
+
+double mifiread_gettempo(t_mifiread *mr)
+{
+ return (mr->mr_ticks.rt_tempo);
+}
+
+double mifiread_getmscoef(t_mifiread *mr)
+{
+ return (mr->mr_ticks.rt_mscoef);
+}
+
+t_symbol *mifiread_gettrackname(t_mifiread *mr)
+{
+ if (mr->mr_pass == 2 &&
+ mr->mr_tracknames &&
+ mr->mr_trackndx < mr->mr_ntracks)
+ return (mr->mr_tracknames[mr->mr_trackndx]);
else
{
- header.h_format = 0;
- header.h_ntracks = bifi_swap2(1);
- /* LATER parametrize this somehow */
- header.h_division = bifi_swap2(192);
+ bug("mifiread_gettrackname");
+ return (0);
}
+}
- if (!bifi_write_start(bp, filename, dirname))
+unsigned mifiread_getstatus(t_mifiread *mr)
+{
+ if (mr->mr_pass != 2)
+ bug("mifiread_getstatus");
+ return (mr->mr_event.e_status);
+}
+
+unsigned mifiread_getdata1(t_mifiread *mr)
+{
+ if (mr->mr_pass != 2)
+ bug("mifiread_getdata1");
+ return (mr->mr_event.e_data[0]);
+}
+
+unsigned mifiread_getdata2(t_mifiread *mr)
+{
+ if (mr->mr_pass != 2)
+ bug("mifiread_getdata2");
+ if (mr->mr_event.e_length < 2)
+ bug("mifiread_getdata2");
+ return (mr->mr_event.e_data[1]);
+}
+
+unsigned mifiread_getchannel(t_mifiread *mr)
+{
+ if (mr->mr_pass != 2)
+ bug("mifiread_getchannel");
+ return (mr->mr_event.e_channel);
+}
+
+t_pd *mifiread_getowner(t_mifiread *mr)
+{
+ return (mr->mr_owner);
+}
+
+int mifiread_open(t_mifiread *mr, const char *filename,
+ const char *dirname, int complain)
+{
+ return (mifiread_doopen(mr, filename, dirname, complain) &&
+ (mifiread_analyse(mr, complain) == MIFIREAD_EOF) &&
+ mifiread_restart(mr, complain));
+}
+
+void mifiread_close(t_mifiread *mr)
+{
+ mr->mr_pass = 0;
+ if (mr->mr_fp)
{
- bifi_error_report(bp);
- bifi_free(bp);
- return (0);
+ fclose(mr->mr_fp);
+ mr->mr_fp = 0;
}
+ if (mr->mr_tracknames)
+ freebytes(mr->mr_tracknames,
+ mr->mr_hdtracks * sizeof(*mr->mr_tracknames));
+}
- if (sp) mifi_stream_reset(sp);
+void mifiread_free(t_mifiread *mr)
+{
+ mifiread_close(mr);
+ if (mr->mr_event.e_data != mr->mr_event.e_dataini)
+ freebytes(mr->mr_event.e_data, mr->mr_event.e_datasize);
+ freebytes(mr, sizeof(*mr));
+}
+
+t_mifiread *mifiread_new(t_pd *owner)
+{
+ t_mifiread *mr = getbytes(sizeof(*mr));
+ mifi_initialize();
+ mr->mr_owner = owner;
+ mifievent_initialize(&mr->mr_event, MIFIEVENT_NALLOC);
+ mifiread_resetticks(mr);
+ mifiread_reset(mr);
+ return (mr);
+}
+
+static void mifiwrite_updateticks(t_mifiwrite *mw)
+{
+ if (mw->mw_nframes)
+ {
+ /* LATER ntsc */
+ mw->mw_ticks.wt_tickscoef =
+ (mw->mw_nframes * mw->mw_ticks.wt_beatticks) /
+ mw->mw_ticks.wt_deftempo;
+ mw->mw_ticks.wt_tempo = mw->mw_ticks.wt_deftempo;
+ mw->mw_ticks.wt_mscoef =
+ .001 * (mw->mw_nframes * mw->mw_ticks.wt_beatticks);
+ }
else
{
- if (!(result = mifi_stream_new()))
- goto startfailure;
- result->s_autoalloc = 1;
+ mw->mw_ticks.wt_tickscoef =
+ (mw->mw_ticks.wt_beatticks * 4.) / mw->mw_ticks.wt_wholeticks;
+ mw->mw_ticks.wt_tempo =
+ ((double)MIFIHARD_DEFTEMPO * mw->mw_ticks.wt_deftempo) /
+ ((double)mw->mw_tempo);
+ if (mw->mw_ticks.wt_tempo < MIFI_TICKEPSILON)
+ {
+ bug("mifiwrite_updateticks");
+ mw->mw_ticks.wt_tempo = mw->mw_ticks.wt_deftempo;
+ }
+ mw->mw_ticks.wt_mscoef =
+ (1000. * mw->mw_ticks.wt_beatticks) / mw->mw_tempo;
}
- result->s_fp = bp->b_fp;
- result->s_track = 0;
+}
- return (result);
-startfailure:
- if (result && !sp) mifi_stream_free(result);
- bifi_free(bp);
- return (0);
+static void mifiwrite_resetticks(t_mifiwrite *mw)
+{
+ mw->mw_ticks.wt_wholeticks = MIFIUSER_DEFWHOLETICKS;
+ mw->mw_ticks.wt_deftempo = MIFIUSER_DEFTEMPO;
+ mw->mw_ticks.wt_beatticks = MIFIHARD_DEFBEATTICKS;
}
-/* Close midifile, free t_mifi_stream if it was allocated
- by mifi_write_start(). */
-void mifi_write_end(t_mifi_stream *sp)
+static void mifiwrite_reset(t_mifiwrite *mw)
{
- if (sp->s_autoalloc)
- {
- /* LATER adjust ntracks field in a file header, but do so only if
- a stream was autoallocated -- number of tracks must be known
- before calling mifi_write_start() for a preexisting stream. */
- }
- if (sp->s_fp) fclose(sp->s_fp);
- if (sp->s_autoalloc) mifi_stream_free(sp);
+ mw->mw_trackndx = 0;
+ mw->mw_trackdirty = 0;
+ mw->mw_fp = 0;
+ mw->mw_format = 1; /* LATER settable parameter */
+ mw->mw_nframes = 0;
+ mw->mw_meternum = 4;
+ mw->mw_meterden = 4;
+ mw->mw_status = 0;
+ mw->mw_channel = 0;
+ mw->mw_trackbytes = 0;
+ mifiwrite_updateticks(mw);
}
-int mifi_write_start_track(t_mifi_stream *sp)
+void mifiwrite_sethardticks(t_mifiwrite *mw, int beatticks)
{
- t_mifi_trackheader header;
- /* LATER check if (sp->s_track < sp->s_hdtracks)... after some thinking */
- strncpy(header.h_type, "MTrk", 4);
- header.h_length = 0;
- sp->s_trackid = sp->s_track_id(sp->s_track);
- sp->s_track++;
- sp->s_newtrack = 1;
- sp->s_status = sp->s_channel = 0;
- sp->s_bytesleft = 0;
- sp->s_time = 0;
- if (fwrite(&header, 1,
- MIFI_TRACKHEADER_SIZE, sp->s_fp) != MIFI_TRACKHEADER_SIZE)
- {
- post("unable to write midifile header");
- return (0);
- }
- return (1);
+ mw->mw_ticks.wt_beatticks =
+ (beatticks > 0 && beatticks < MIFI_MAXBEATTICKS ?
+ beatticks : MIFIHARD_DEFBEATTICKS);
+ mifiwrite_updateticks(mw);
}
-/* append eot meta and update length field in a track header */
-int mifi_write_adjust_track(t_mifi_stream *sp, uint32 eotdelay)
+void mifiwrite_setuserticks(t_mifiwrite *mw, double wholeticks)
{
- t_mifi_event *ep = sp->s_auxeve;
- long skip;
- uint32 length;
- ep->e_delay = eotdelay;
- ep->e_status = MIFI_EVENT_META;
- ep->e_meta = MIFI_META_EOT;
- ep->e_length = 0;
- if (!mifi_write_event(sp, ep))
- return (0);
- skip = sp->s_bytesleft + 4;
- length = bifi_swap4(sp->s_bytesleft);
-#ifdef MIFI_DEBUG
- post("adjusting track size to %d", sp->s_bytesleft);
-#endif
- /* LATER add sanity check (compare to saved filepos) */
- if (skip > 4 &&
- fseek(sp->s_fp, -skip, SEEK_CUR) < 0 ||
- fwrite(&length, 1, 4, sp->s_fp) != 4 ||
- fseek(sp->s_fp, 0, SEEK_END) < 0)
- {
- post("unable to adjust length field in midifile track header \
- (length %d)", sp->s_bytesleft);
- return (0);
- }
- return (1);
+ mw->mw_ticks.wt_wholeticks = (wholeticks > MIFI_TICKEPSILON ?
+ wholeticks : MIFIUSER_DEFWHOLETICKS);
+ mw->mw_ticks.wt_deftempo = mw->mw_ticks.wt_wholeticks *
+ (MIFIUSER_DEFTEMPO / MIFIUSER_DEFWHOLETICKS);
+ mifiwrite_updateticks(mw);
+}
+
+void mifiwrite_setusertempo(t_mifiwrite *mw, double tickspersec)
+{
+ mw->mw_tempo = (tickspersec > MIFI_TICKEPSILON ?
+ ((double)MIFIHARD_DEFTEMPO * mw->mw_ticks.wt_deftempo) /
+ tickspersec : MIFIHARD_DEFTEMPO);
+ mifiwrite_updateticks(mw);
}
/* LATER analyse shrinking effect caused by truncation */
-int mifi_write_event(t_mifi_stream *sp, t_mifi_event *ep)
+static int mifiwrite_putnextevent(t_mifiwrite *mw, t_mifievent *ep)
{
uchar buf[3], *ptr = buf;
- size_t size = mifi_writevarlen(sp, ep->e_delay);
+ size_t size = mifiwrite_putvarlen(mw, ep->e_delay);
if (!size)
return (0);
- sp->s_bytesleft += size;
- if (MIFI_IS_CHANNEL(ep->e_status))
+ mw->mw_trackbytes += size;
+ if (MIFI_ISCHANNEL(ep->e_status))
{
- if ((*ptr = ep->e_status | ep->e_channel) == sp->s_status)
+ if ((*ptr = ep->e_status | ep->e_channel) == mw->mw_status)
size = 1;
else
{
- sp->s_status = *ptr++;
+ mw->mw_status = *ptr++;
size = 2;
}
*ptr++ = ep->e_data[0];
- if (!MIFI_ONE_DATABYTE(ep->e_status))
+ if (!MIFI_ONEDATABYTE(ep->e_status))
{
*ptr = ep->e_data[1];
size++;
}
ptr = buf;
}
- else if (ep->e_status == MIFI_EVENT_META)
+ else if (ep->e_status == MIFIEVENT_META)
{
- sp->s_status = 0; /* sysex and meta-events cancel any running status */
+ mw->mw_status = 0; /* sysex and meta cancel any running status */
buf[0] = ep->e_status;
buf[1] = ep->e_meta;
- if (fwrite(buf, 1, 2, sp->s_fp) != 2)
+ if (fwrite(buf, 1, 2, mw->mw_fp) != 2)
return (0);
- sp->s_bytesleft += 2;
- size = mifi_writevarlen(sp, (uint32)(ep->e_length));
+ mw->mw_trackbytes += 2;
+ size = mifiwrite_putvarlen(mw, ep->e_length);
if (!size)
return (0);
- sp->s_bytesleft += size;
+ mw->mw_trackbytes += size;
size = ep->e_length;
ptr = ep->e_data;
}
else return (0);
- if (fwrite(ptr, 1, size, sp->s_fp) != size)
+ if (size)
+ {
+ if (fwrite(ptr, 1, size, mw->mw_fp) != size)
+ return (0);
+ mw->mw_trackbytes += size;
+ }
+ return (1);
+}
+
+/* open a midi file for saving, write the header */
+int mifiwrite_open(t_mifiwrite *mw, const char *filename,
+ const char *dirname, int ntracks, int complain)
+{
+ char errmess[MAXPDSTRING], fnamebuf[MAXPDSTRING];
+ if (ntracks < 1 || ntracks > MIFI_MAXTRACKS)
+ {
+ bug("mifiwrite_open 1");
+ complain = 0;
+ goto wopenfailed;
+ }
+ mw->mw_ntracks = ntracks;
+ mifiwrite_reset(mw);
+ if (mw->mw_format == 0)
+ {
+ if (mw->mw_ntracks != 1)
+ { /* LATER consider replacing with a warning */
+ bug("mifiwrite_open 2");
+ complain = 0;
+ goto wopenfailed;
+ }
+#ifdef MIFI_VERBOSE
+ post("writing single-track midi file \"%s\"", filename);
+#endif
+ }
+#ifdef MIFI_VERBOSE
+ else post("writing midi file \"%s\" (%d tracks)", filename, mw->mw_ntracks);
+#endif
+ strncpy(mw->mw_header.h_type, "MThd", 4);
+ mw->mw_header.h_length = mifi_swap4(MIFIHARD_HEADERDATASIZE);
+ mw->mw_header.h_format = mifi_swap2(mw->mw_format);
+ mw->mw_header.h_ntracks = mifi_swap2(mw->mw_ntracks);
+ if (mw->mw_nframes)
+ mw->mw_header.h_division =
+ ((mw->mw_nframes << 8) | mw->mw_ticks.wt_beatticks) | 0x8000;
+ else
+ mw->mw_header.h_division = mw->mw_ticks.wt_beatticks & 0x7fff;
+ mw->mw_header.h_division = mifi_swap2(mw->mw_header.h_division);
+ fnamebuf[0] = 0;
+ if (*dirname)
+ strcat(fnamebuf, dirname), strcat(fnamebuf, "/");
+ strcat(fnamebuf, filename);
+ sys_bashfilename(fnamebuf, fnamebuf);
+ if (!(mw->mw_fp = fopen(fnamebuf, "wb")))
+ {
+ strcpy(errmess, "cannot open");
+ goto wopenfailed;
+ }
+ if (fwrite(&mw->mw_header, 1,
+ MIFIHARD_HEADERSIZE, mw->mw_fp) < MIFIHARD_HEADERSIZE)
+ {
+ strcpy(errmess, "cannot write header of");
+ goto wopenfailed;
+ }
+ return (1);
+wopenfailed:
+ if (complain)
+ mifi_error(mw->mw_owner, "%s file \"%s\" (errno %d: %s)",
+ errmess, filename, errno, strerror(errno));
+ if (mw->mw_fp)
+ {
+ fclose(mw->mw_fp);
+ mw->mw_fp = 0;
+ }
+ return (0);
+}
+
+/* append eot meta and update length field in a track header */
+static int mifiwrite_adjusttrack(t_mifiwrite *mw, uint32 eotdelay, int complain)
+{
+ t_mifievent *ep = &mw->mw_event;
+ long skip;
+ uint32 length;
+ mw->mw_trackdirty = 0;
+ ep->e_delay = eotdelay;
+ ep->e_status = MIFIEVENT_META;
+ ep->e_meta = MIFIMETA_EOT;
+ ep->e_length = 0;
+ if (!mifiwrite_putnextevent(mw, ep))
return (0);
- sp->s_bytesleft += size;
+ skip = mw->mw_trackbytes + 4;
+ length = mifi_swap4(mw->mw_trackbytes);
+#ifdef MIFI_DEBUG
+ post("adjusting track size to %d", mw->mw_trackbytes);
+#endif
+ /* LATER add sanity check (compare to saved filepos) */
+ if (skip > 4 &&
+ fseek(mw->mw_fp, -skip, SEEK_CUR) < 0 ||
+ fwrite(&length, 1, 4, mw->mw_fp) != 4 ||
+ fseek(mw->mw_fp, 0, SEEK_END) < 0)
+ {
+ if (complain)
+ mifi_error(mw->mw_owner,
+ "unable to adjust length field to %d in a midi file\
+ track header (errno %d: %s)", mw->mw_trackbytes, errno, strerror(errno));
+ return (0);
+ }
return (1);
}
+
+int mifiwrite_opentrack(t_mifiwrite *mw, char *trackname, int complain)
+{
+ t_mifitrackheader th;
+ if (mw->mw_trackdirty && !mifiwrite_adjusttrack(mw, 0, complain))
+ return (0);
+ if (mw->mw_trackndx > mw->mw_ntracks)
+ return (0);
+ else if (mw->mw_trackndx++ == mw->mw_ntracks)
+ {
+ bug("mifiwrite_opentrack");
+ return (0);
+ }
+ strncpy(th.th_type, "MTrk", 4);
+ th.th_length = 0;
+ mw->mw_status = mw->mw_channel = 0;
+ mw->mw_trackbytes = 0;
+ if (fwrite(&th, 1, MIFIHARD_TRACKHEADERSIZE,
+ mw->mw_fp) != MIFIHARD_TRACKHEADERSIZE)
+ {
+ if (complain)
+ mifi_error(mw->mw_owner,
+ "unable to write midi file header (errno %d: %s)",
+ errno, strerror(errno));
+ return (0);
+ }
+ if (trackname)
+ {
+ if (!mifiwrite_textevent(mw, 0., MIFIMETA_TRACKNAME, trackname))
+ {
+ if (complain)
+ mifi_error(mw->mw_owner,
+ "unable to write midi file track name \"%s\" (errno %d: %s)",
+ trackname, errno, strerror(errno));
+ return (0);
+ }
+ }
+ mw->mw_trackdirty = 1;
+ return (1);
+}
+
+/* calling this is optional (if skipped, enddelay defaults to 0.) */
+int mifiwrite_closetrack(t_mifiwrite *mw, double enddelay, int complain)
+{
+ if (mw->mw_trackdirty)
+ {
+ uint32 eotdelay = (uint32)(enddelay * mw->mw_ticks.wt_mscoef);
+ return (mifiwrite_adjusttrack(mw, eotdelay, complain));
+ }
+ else
+ {
+ bug("mifiwrite_closetrack");
+ return (0);
+ }
+}
+
+int mifiwrite_textevent(t_mifiwrite *mw, double delay,
+ unsigned type, char *text)
+{
+ t_mifievent *ep = &mw->mw_event;
+ if (!mifievent_settext(ep, type, text))
+ return (0);
+ ep->e_delay = (uint32)(delay * mw->mw_ticks.wt_mscoef);
+ return (mifiwrite_putnextevent(mw, ep));
+}
+
+int mifiwrite_channelevent(t_mifiwrite *mw, double delay, unsigned status,
+ unsigned channel, unsigned data1, unsigned data2)
+{
+ t_mifievent *ep = &mw->mw_event;
+ int shorter = MIFI_ONEDATABYTE(status);
+ if (!MIFI_ISCHANNEL(status) || channel > 15 || data1 > 127
+ || (!shorter && data2 > 127))
+ {
+ bug("mifiwrite_channelevent");
+ return (0);
+ }
+ ep->e_delay = (uint32)(delay * mw->mw_ticks.wt_mscoef);
+ ep->e_status = (uchar)(status & 0xf0);
+ ep->e_channel = (uchar)channel;
+ ep->e_data[0] = (uchar)data1;
+ if (shorter)
+ ep->e_length = 1;
+ else
+ {
+ ep->e_data[1] = (uchar)data2;
+ ep->e_length = 2;
+ }
+ return (mifiwrite_putnextevent(mw, ep));
+}
+
+void mifiwrite_close(t_mifiwrite *mw)
+{
+ if (mw->mw_trackdirty)
+ mifiwrite_adjusttrack(mw, 0, 0);
+ if (mw->mw_fp)
+ {
+ fclose(mw->mw_fp);
+ mw->mw_fp = 0;
+ }
+}
+
+void mifiwrite_free(t_mifiwrite *mw)
+{
+ mifiwrite_close(mw);
+ if (mw->mw_event.e_data != mw->mw_event.e_dataini)
+ freebytes(mw->mw_event.e_data, mw->mw_event.e_datasize);
+ freebytes(mw, sizeof(*mw));
+}
+
+t_mifiwrite *mifiwrite_new(t_pd *owner)
+{
+ t_mifiwrite *mw = getbytes(sizeof(*mw));
+ mifi_initialize();
+ mw->mw_owner = owner;
+ mw->mw_ntracks = 0;
+ mw->mw_tempo = MIFIHARD_DEFTEMPO;
+ mifievent_initialize(&mw->mw_event, MIFIEVENT_NALLOC);
+ mifiwrite_resetticks(mw);
+ mifiwrite_reset(mw);
+ return (mw);
+}
diff --git a/shared/common/mifi.h b/shared/common/mifi.h
index 5524993..1163a5d 100644
--- a/shared/common/mifi.h
+++ b/shared/common/mifi.h
@@ -1,84 +1,97 @@
-/* Copyright (c) 2001-2003 krzYszcz and others.
+/* 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. */
-/* reading/writing midifiles, a prototype version */
-
#ifndef __MIFI_H__
#define __MIFI_H__
-/* event types, as returned by mifi_read_event() */
-#define MIFI_READ_FATAL -3 /* unexpected eof, error in last track, or file error */
-#define MIFI_READ_EOF -2 /* regular eof */
-#define MIFI_READ_SKIP -1 /* error and successful skip to the next track */
-#define MIFI_META_SEQNUM 0
-#define MIFI_META_TEXT 1
-#define MIFI_META_COPYRIGHT 2
-#define MIFI_META_TRACKNAME 3
-#define MIFI_META_INSTRUMENT 4
-#define MIFI_META_LYRIC 5
-#define MIFI_META_MARKER 6
-#define MIFI_META_CUE 7
-#define MIFI_META_MAXPRINTABLE 15 /* 1..15 are various text meta-events */
-#define MIFI_META_CHANNEL 0x20 /* channel prefix */
-#define MIFI_META_EOT 0x2f /* end of track */
-#define MIFI_META_TEMPO 0x51
-#define MIFI_META_SMPTE 0x54 /* SMPTE offset */
-#define MIFI_META_TIMESIG 0x58 /* time signature */
-#define MIFI_META_KEYSIG 0x59 /* key signature */
+EXTERN_STRUCT _mifiread;
+#define t_mifiread struct _mifiread
+EXTERN_STRUCT _mifiwrite;
+#define t_mifiwrite struct _mifiwrite
+
+typedef int (*t_mifireadhook)(t_mifiread *mf, void *hookdata, int evtype);
+
+#define MIFI_MAXTRACKS 0x7fff
+#define MIFI_MAXBEATTICKS 0x7fff
+
+/* event types, as returned by mifiread_nextevent(), ... */
+
+#define MIFIREAD_FATAL -3 /* unexpected eof, last track's or file error */
+#define MIFIREAD_EOF -2 /* regular eof */
+#define MIFIREAD_SKIP -1 /* error and successful skip to the next track */
+
+#define MIFIMETA_SEQNUM 0
+#define MIFIMETA_TEXT 1
+#define MIFIMETA_COPYRIGHT 2
+#define MIFIMETA_TRACKNAME 3
+#define MIFIMETA_INSTRUMENT 4
+#define MIFIMETA_LYRIC 5
+#define MIFIMETA_MARKER 6
+#define MIFIMETA_CUE 7
+#define MIFIMETA_MAXPRINTABLE 15 /* 1..15 are various text meta-events */
+#define MIFIMETA_CHANNEL 0x20 /* channel prefix */
+#define MIFIMETA_EOT 0x2f /* end of track */
+#define MIFIMETA_TEMPO 0x51
+#define MIFIMETA_SMPTE 0x54 /* SMPTE offset */
+#define MIFIMETA_TIMESIG 0x58 /* time signature */
+#define MIFIMETA_KEYSIG 0x59 /* key signature */
+
/* ...channel status codes go here, too obvious to #define... */
-#define MIFI_SYSEX_FIRST 0xf0
-#define MIFI_SYSEX_NEXT 0xf7
-/* this code is not returned as an event type, but in e_status of t_mifi_event */
-#define MIFI_EVENT_META 0xff
+
+#define MIFISYSEX_FIRST 0xf0
+#define MIFISYSEX_NEXT 0xf7
+
+/* this code is not returned as an event type, but in e_status of t_mifievent */
+#define MIFIEVENT_META 0xff
/* true if one of channel messages */
-#define MIFI_IS_CHANNEL(status) (((status) & 0x80) && (status) < 0xf0)
+#define MIFI_ISCHANNEL(status) (((status) & 0x80) && (status) < 0xf0)
/* true if one of the two shorter channel messages */
-#define MIFI_ONE_DATABYTE(status) (((status) & 0xe0) == 0xc0)
-
-/* derived from t_squeve */
-typedef struct _mifi_event
-{
- uint32 e_length;
- uchar *e_data;
- size_t e_bufsize;
- uint32 e_delay;
- uchar e_status;
- uchar e_channel;
- uchar e_meta; /* meta-event type */
-} t_mifi_event;
-
-/* This structure holds midi data stream properties, i.e. both the info stored
- in midifile header, and the current state according to position in a stream. */
-/* LATER clean up t_sq and derive t_mifi_stream */
-typedef struct _sq t_mifi_stream;
-
-/* prototypes of public interface routines */
-
-t_mifi_event *mifi_event_new(void);
-void mifi_event_free(t_mifi_event *ep);
-int mifi_event_settext(t_mifi_event *ep, int type, char *text);
-void mifi_event_printmeta(t_mifi_event *ep);
-
-t_mifi_stream *mifi_stream_new(void);
-void mifi_stream_reset(t_mifi_stream *sp);
-void mifi_stream_free(t_mifi_stream *sp);
-
-t_mifi_stream *mifi_read_start(t_mifi_stream *sp,
- const char *filename, const char *dirname,
- int complain);
-int mifi_read_restart(t_mifi_stream *sp);
-void mifi_read_end(t_mifi_stream *sp);
-int mifi_read_event(t_mifi_stream *sp, t_mifi_event *ep);
-int mifi_read_analyse(t_mifi_stream *sp);
-int mifi_read_doit(t_mifi_stream *sp);
-
-t_mifi_stream *mifi_write_start(t_mifi_stream *sp,
- const char *filename, const char *dirname);
-void mifi_write_end(t_mifi_stream *sp);
-int mifi_write_start_track(t_mifi_stream *sp);
-int mifi_write_adjust_track(t_mifi_stream *sp, uint32 eotdelay);
-int mifi_write_event(t_mifi_stream *sp, t_mifi_event *ep);
+#define MIFI_ONEDATABYTE(status) (((status) & 0xe0) == 0xc0)
+
+int mifiread_getnevents(t_mifiread *mr);
+int mifiread_getntempi(t_mifiread *mr);
+int mifiread_gethdtracks(t_mifiread *mr);
+int mifiread_getformat(t_mifiread *mr);
+int mifiread_getnframes(t_mifiread *mr);
+int mifiread_getbeatticks(t_mifiread *mr);
+double mifiread_getdeftempo(t_mifiread *mr);
+
+int mifiread_getbarindex(t_mifiread *mr);
+double mifiread_getbarspan(t_mifiread *mr);
+double mifiread_gettick(t_mifiread *mr);
+double mifiread_getscoretime(t_mifiread *mr);
+double mifiread_gettempo(t_mifiread *mr);
+double mifiread_getmscoef(t_mifiread *mr);
+t_symbol *mifiread_gettrackname(t_mifiread *mr);
+unsigned mifiread_getstatus(t_mifiread *mr);
+unsigned mifiread_getdata1(t_mifiread *mr);
+unsigned mifiread_getdata2(t_mifiread *mr);
+unsigned mifiread_getchannel(t_mifiread *mr);
+t_pd *mifiread_getowner(t_mifiread *mr);
+
+t_mifiread *mifiread_new(t_pd *owner);
+void mifiread_setuserticks(t_mifiread *mr, double wholeticks);
+int mifiread_open(t_mifiread *mr, const char *filename,
+ const char *dirname, int complain);
+int mifiread_doit(t_mifiread *mr, t_mifireadhook hook, void *hookdata);
+void mifiread_close(t_mifiread *mr);
+void mifiread_free(t_mifiread *mr);
+
+t_mifiwrite *mifiwrite_new(t_pd *owner);
+void mifiwrite_sethardticks(t_mifiwrite *mw, int beatticks);
+void mifiwrite_setuserticks(t_mifiwrite *mw, double wholeticks);
+void mifiwrite_setusertempo(t_mifiwrite *mw, double tickspersec);
+int mifiwrite_open(t_mifiwrite *mw, const char *filename,
+ const char *dirname, int ntracks, int complain);
+int mifiwrite_opentrack(t_mifiwrite *mw, char *trackname, int complain);
+int mifiwrite_textevent(t_mifiwrite *mw, double delay,
+ unsigned type, char *text);
+int mifiwrite_channelevent(t_mifiwrite *mw, double delay, unsigned status,
+ unsigned channel, unsigned data1, unsigned data2);
+int mifiwrite_closetrack(t_mifiwrite *mw, double enddelay, int complain);
+void mifiwrite_close(t_mifiwrite *mw);
+void mifiwrite_free(t_mifiwrite *mw);
#endif
diff --git a/shared/common/port.c b/shared/common/port.c
index 5ea4dcd..99f8211 100644
--- a/shared/common/port.c
+++ b/shared/common/port.c
@@ -715,8 +715,14 @@ static int imaction_P6_pack(t_port *x, char *arg)
{
t_symbol *s = x->x_inmess[i].a_w.w_symbol;
if (s->s_name[1])
+ {
+ loud_warning(0, "import",
+ "%s's argument '%s' bashed to 's'",
+ port_getsymbol(x, 6)->s_name, s->s_name);
x->x_inmess[i].a_w.w_symbol = gensym("s");
- else switch (*s->s_name) {
+ }
+ else switch (*s->s_name)
+ {
case 'b': case 'f': case 's': case 'l':
break;
case 'i':
@@ -1135,7 +1141,7 @@ secondpass:
while (nslots--)
{
if (slot->s_symbol == insym
- || (inname && loud_matchignorecase(inname, slot->s_name)))
+ || (inname && shared_matchignorecase(inname, slot->s_name)))
{
if (slot->s_subtree)
{
diff --git a/shared/getridof.baddeps b/shared/getridof.baddeps
index 9483b3b..478cf4e 100644
--- a/shared/getridof.baddeps
+++ b/shared/getridof.baddeps
@@ -3,16 +3,16 @@ Some are inevitable, but others can, and should be removed.
unstable/fragile -> common/loud
unstable/fringe -> unstable/forky
-toxy/plusbob -> common/loud
-toxy/scriptlet -> common/loud, common/grow, common/props
-sickle/sic -> common/loud
-sickle/arsic -> common/loud, common/vefl, sickle/sic, unstable/fragile
-hammer/file -> unstable/forky
-common/hyphen -> common/dict
common/props -> common/grow
common/vefl -> common/loud, unstable/fragile
+common/binport -> common/lex
common/port -> common/loud, common/grow, common/binport,
unstable/forky, unstable/fragile, unstable/fringe
-common/sofi -> common/bifi
-common/mifi -> common/bifi common/sq
-common/mfbb -> common/bifi, common/mifi, common/sq, common/squeal
+hammer/file -> unstable/forky
+sickle/sic -> common/loud
+sickle/arsic -> common/loud, common/vefl, sickle/sic, unstable/fragile
+toxy/plusbob -> common/loud
+toxy/scriptlet -> common/loud, common/grow, common/props
+xeq/squ* -> common/loud, common/fi, common/mifi, common/qtree, xeq/squ*
+vex/hyphen -> common/dict
+vex/sofi -> vex/bifi
diff --git a/shared/hammer/gui.c b/shared/hammer/gui.c
index ec6add7..7106a0a 100644
--- a/shared/hammer/gui.c
+++ b/shared/hammer/gui.c
@@ -5,6 +5,7 @@
/* FIXME use guiconnect */
#include <stdio.h>
+#include <string.h>
#include "m_pd.h"
#include "g_canvas.h"
#include "hammer/gui.h"
@@ -12,7 +13,9 @@
//#define HAMMERGUI_DEBUG
static t_class *hammergui_class = 0;
-static t_hammergui *sink = 0;
+static t_hammergui *hammergui_sink = 0;
+static t_symbol *ps_hashhammergui;
+static t_symbol *ps__hammergui;
static t_symbol *ps__up;
static t_symbol *ps__focus;
static t_symbol *ps__vised;
@@ -26,7 +29,7 @@ static void hammergui_anything(t_hammergui *snk,
#ifdef HAMMERGUI_DEBUG
startpost("%s", s->s_name);
postatom(ac, av);
- endpost();
+ post(" (sink %x)", (int)snk);
#endif
}
@@ -34,31 +37,36 @@ static void hammergui_anything(t_hammergui *snk,
static void hammergui__up(t_hammergui *snk, t_floatarg f)
{
#ifdef HAMMERGUI_DEBUG
- post("_up %g", f);
+ post("_up %g (sink %x)", f, (int)snk);
#endif
+ if (!snk->g_psmouse)
+ {
+ bug("hammergui__up");
+ return;
+ }
if ((int)f)
{
- if (!snk->g_up)
+ if (!snk->g_isup)
{
- snk->g_up = 1;
- if (snk->g_mouse->s_thing)
+ snk->g_isup = 1;
+ if (snk->g_psmouse->s_thing)
{
t_atom at;
SETFLOAT(&at, 1);
- pd_typedmess(snk->g_mouse->s_thing, ps__up, 1, &at);
+ pd_typedmess(snk->g_psmouse->s_thing, ps__up, 1, &at);
}
}
}
else
{
- if (snk->g_up)
+ if (snk->g_isup)
{
- snk->g_up = 0;
- if (snk->g_mouse->s_thing)
+ snk->g_isup = 0;
+ if (snk->g_psmouse->s_thing)
{
t_atom at;
SETFLOAT(&at, 0);
- pd_typedmess(snk->g_mouse->s_thing, ps__up, 1, &at);
+ pd_typedmess(snk->g_psmouse->s_thing, ps__up, 1, &at);
}
}
}
@@ -67,28 +75,38 @@ static void hammergui__up(t_hammergui *snk, t_floatarg f)
static void hammergui__focus(t_hammergui *snk, t_symbol *s, t_floatarg f)
{
#ifdef HAMMERGUI_DEBUG
- if (s) post("_focus %s %g", s->s_name, f);
+ post("_focus %s %g (sink %x)", (s ? s->s_name : "???"), f, (int)snk);
#endif
- if (snk->g_focus->s_thing)
+ if (!snk->g_psfocus)
+ {
+ bug("hammergui__focus");
+ return;
+ }
+ if (snk->g_psfocus->s_thing)
{
t_atom at[2];
SETSYMBOL(&at[0], s);
SETFLOAT(&at[1], f);
- pd_typedmess(snk->g_focus->s_thing, ps__focus, 2, at);
+ pd_typedmess(snk->g_psfocus->s_thing, ps__focus, 2, at);
}
}
static void hammergui__vised(t_hammergui *snk, t_symbol *s, t_floatarg f)
{
#ifdef HAMMERGUI_DEBUG
- if (s) post("_vised %s %g", s->s_name, f);
+ post("_vised %s %g (sink %x)", (s ? s->s_name : "???"), f, (int)snk);
#endif
- if (snk->g_vised->s_thing)
+ if (!snk->g_psvised)
+ {
+ bug("hammergui__vised");
+ return;
+ }
+ if (snk->g_psvised->s_thing)
{
t_atom at[2];
SETSYMBOL(&at[0], s);
SETFLOAT(&at[1], f);
- pd_typedmess(snk->g_vised->s_thing, ps__vised, 2, at);
+ pd_typedmess(snk->g_psvised->s_thing, ps__vised, 2, at);
}
#if 0
/* How to be notified about changes of button state, prior to gui objects
@@ -101,23 +119,31 @@ static void hammergui__vised(t_hammergui *snk, t_symbol *s, t_floatarg f)
static void hammergui_dobindmouse(t_hammergui *snk)
{
+#ifdef HAMMERGUI_DEBUG
+ post("dobindmouse (sink %x)", (int)snk);
+#endif
#if 0
/* How to be notified about changes of button state, prior to gui objects
in a canvas? LATER find a reliable way -- delete if failed */
sys_vgui("bind hammertag <<hammerdown>> {pd [concat %s _up 0 \\;]}\n",
- snk->g_gui->s_name);
+ snk->g_psgui->s_name);
sys_vgui("bind hammertag <<hammerup>> {pd [concat %s _up 1 \\;]}\n",
- snk->g_gui->s_name);
+ snk->g_psgui->s_name);
#endif
sys_vgui("bind all <<hammerdown>> {pd [concat %s _up 0 \\;]}\n",
- snk->g_gui->s_name);
+ snk->g_psgui->s_name);
sys_vgui("bind all <<hammerup>> {pd [concat %s _up 1 \\;]}\n",
- snk->g_gui->s_name);
+ snk->g_psgui->s_name);
}
static void hammergui__remouse(t_hammergui *snk)
{
- if (snk->g_mouse->s_thing)
+ if (!snk->g_psmouse)
+ {
+ bug("hammergui__remouse");
+ return;
+ }
+ if (snk->g_psmouse->s_thing)
{
/* if a new master was bound in a gray period, we need to
restore gui bindings */
@@ -132,15 +158,20 @@ static void hammergui_dobindfocus(t_hammergui *snk)
{
sys_vgui("bind Canvas <<hammerfocusin>> \
{if {[hammergui_ispatcher %%W]} \
- {pd [concat %s _focus %%W 1 \\;]}}\n", snk->g_gui->s_name);
+ {pd [concat %s _focus %%W 1 \\;]}}\n", snk->g_psgui->s_name);
sys_vgui("bind Canvas <<hammerfocusout>> \
{if {[hammergui_ispatcher %%W]} \
- {pd [concat %s _focus %%W 0 \\;]}}\n", snk->g_gui->s_name);
+ {pd [concat %s _focus %%W 0 \\;]}}\n", snk->g_psgui->s_name);
}
static void hammergui__refocus(t_hammergui *snk)
{
- if (snk->g_focus->s_thing)
+ if (!snk->g_psfocus)
+ {
+ bug("hammergui__refocus");
+ return;
+ }
+ if (snk->g_psfocus->s_thing)
{
/* if a new master was bound in a gray period, we need to
restore gui bindings */
@@ -153,17 +184,25 @@ static void hammergui__refocus(t_hammergui *snk)
static void hammergui_dobindvised(t_hammergui *snk)
{
+#ifdef HAMMERGUI_DEBUG
+ post("dobindvised (sink %x)", (int)snk);
+#endif
sys_vgui("bind Canvas <<hammervised>> \
{if {[hammergui_ispatcher %%W]} \
- {pd [concat %s _vised %%W 1 \\;]}}\n", snk->g_gui->s_name);
+ {pd [concat %s _vised %%W 1 \\;]}}\n", snk->g_psgui->s_name);
sys_vgui("bind Canvas <<hammerunvised>> \
{if {[hammergui_ispatcher %%W]} \
- {pd [concat %s _vised %%W 0 \\;]}}\n", snk->g_gui->s_name);
+ {pd [concat %s _vised %%W 0 \\;]}}\n", snk->g_psgui->s_name);
}
static void hammergui__revised(t_hammergui *snk)
{
- if (snk->g_vised->s_thing)
+ if (!snk->g_psvised)
+ {
+ bug("hammergui__revised");
+ return;
+ }
+ if (snk->g_psvised->s_thing)
{
/* if a new master was bound in a gray period, we need to
restore gui bindings */
@@ -174,9 +213,35 @@ static void hammergui__revised(t_hammergui *snk)
}
}
-static void hammergui_setup(void)
+static int hammergui_setup(void)
{
- hammergui_class = class_new(gensym("_hammergui"), 0, 0,
+ ps_hashhammergui = gensym("#hammergui");
+ ps__hammergui = gensym("_hammergui");
+ ps__up = gensym("_up");
+ ps__focus = gensym("_focus");
+ ps__vised = gensym("_vised");
+ if (ps_hashhammergui->s_thing)
+ {
+ char *cname = class_getname(*ps_hashhammergui->s_thing);
+#ifdef HAMMERGUI_DEBUG
+ post("'%s' already registered as the global hammergui sink ",
+ (cname ? cname : "???"));
+#endif
+ if (strcmp(cname, ps__hammergui->s_name))
+ {
+ /* FIXME protect against the danger of someone else
+ (e.g. receive) binding to #hammergui */
+ bug("hammergui_setup");
+ return (0);
+ }
+ else
+ {
+ /* FIXME compatibility test */
+ hammergui_class = *ps_hashhammergui->s_thing;
+ return (1);
+ }
+ }
+ hammergui_class = class_new(ps__hammergui, 0, 0,
sizeof(t_hammergui),
CLASS_PD | CLASS_NOINLET, 0);
class_addanything(hammergui_class, hammergui_anything);
@@ -186,13 +251,10 @@ static void hammergui_setup(void)
gensym("_refocus"), 0);
class_addmethod(hammergui_class, (t_method)hammergui__revised,
gensym("_revised"), 0);
- ps__up = gensym("_up");
class_addmethod(hammergui_class, (t_method)hammergui__up,
ps__up, A_FLOAT, 0);
- ps__focus = gensym("_focus");
class_addmethod(hammergui_class, (t_method)hammergui__focus,
ps__focus, A_SYMBOL, A_FLOAT, 0);
- ps__vised = gensym("_vised");
class_addmethod(hammergui_class, (t_method)hammergui__vised,
ps__vised, A_SYMBOL, A_FLOAT, 0);
@@ -255,21 +317,25 @@ static void hammergui_setup(void)
sys_gui(" bind Canvas <<hammerunvised>> {}\n");
sys_gui(" pd [concat #hammergui _revised \\;]\n");
sys_gui("}\n");
+ return (1);
}
static int hammergui_validate(int dosetup)
{
- if (dosetup)
+ if (dosetup && !hammergui_sink
+ && (hammergui_class || hammergui_setup()))
{
- if (!hammergui_class) hammergui_setup();
- if (!sink)
+ if (ps_hashhammergui->s_thing)
+ hammergui_sink = (t_hammergui *)ps_hashhammergui->s_thing;
+ else
{
- sink = (t_hammergui *)pd_new(hammergui_class);
- sink->g_gui = gensym("#hammergui");
- pd_bind((t_pd *)sink, sink->g_gui);
+ hammergui_sink = (t_hammergui *)pd_new(hammergui_class);
+ hammergui_sink->g_psgui = ps_hashhammergui;
+ pd_bind((t_pd *)hammergui_sink,
+ ps_hashhammergui); /* never unbound */
}
}
- if (hammergui_class && sink)
+ if (hammergui_class && hammergui_sink)
return (1);
else
{
@@ -280,13 +346,13 @@ static int hammergui_validate(int dosetup)
static int hammergui_mousevalidate(int dosetup)
{
- if (dosetup && !sink->g_mouse)
+ if (dosetup && !hammergui_sink->g_psmouse)
{
- sink->g_mouse = gensym("#hammermouse");
+ hammergui_sink->g_psmouse = gensym("#hammermouse");
sys_gui("event add <<hammerdown>> <ButtonPress>\n");
sys_gui("event add <<hammerup>> <ButtonRelease>\n");
}
- if (sink->g_mouse)
+ if (hammergui_sink->g_psmouse)
return (1);
else
{
@@ -297,12 +363,13 @@ static int hammergui_mousevalidate(int dosetup)
static int hammergui_pollvalidate(int dosetup)
{
- if (dosetup && !sink->g_poll)
+ if (dosetup && !hammergui_sink->g_pspoll)
{
- sink->g_poll = gensym("#hammerpoll");
- pd_bind((t_pd *)sink, sink->g_poll); /* never unbound */
+ hammergui_sink->g_pspoll = gensym("#hammerpoll");
+ pd_bind((t_pd *)hammergui_sink,
+ hammergui_sink->g_pspoll); /* never unbound */
}
- if (sink->g_poll)
+ if (hammergui_sink->g_pspoll)
return (1);
else
{
@@ -313,13 +380,13 @@ static int hammergui_pollvalidate(int dosetup)
static int hammergui_focusvalidate(int dosetup)
{
- if (dosetup && !sink->g_focus)
+ if (dosetup && !hammergui_sink->g_psfocus)
{
- sink->g_focus = gensym("#hammerfocus");
+ hammergui_sink->g_psfocus = gensym("#hammerfocus");
sys_gui("event add <<hammerfocusin>> <FocusIn>\n");
sys_gui("event add <<hammerfocusout>> <FocusOut>\n");
}
- if (sink->g_focus)
+ if (hammergui_sink->g_psfocus)
return (1);
else
{
@@ -330,15 +397,15 @@ static int hammergui_focusvalidate(int dosetup)
static int hammergui_visedvalidate(int dosetup)
{
- if (dosetup && !sink->g_vised)
+ if (dosetup && !hammergui_sink->g_psvised)
{
- sink->g_vised = gensym("#hammervised");
+ hammergui_sink->g_psvised = gensym("#hammervised");
/* subsequent map events have to be filtered out at the caller's side,
LATER investigate */
sys_gui("event add <<hammervised>> <Map>\n");
sys_gui("event add <<hammerunvised>> <Destroy>\n");
}
- if (sink->g_vised)
+ if (hammergui_sink->g_psvised)
return (1);
else
{
@@ -349,20 +416,23 @@ static int hammergui_visedvalidate(int dosetup)
void hammergui_bindmouse(t_pd *master)
{
+#ifdef HAMMERGUI_DEBUG
+ post("bindmouse, master %x", (int)master);
+#endif
hammergui_validate(1);
hammergui_mousevalidate(1);
- if (!sink->g_mouse->s_thing)
- hammergui_dobindmouse(sink);
- pd_bind(master, sink->g_mouse);
+ if (!hammergui_sink->g_psmouse->s_thing)
+ hammergui_dobindmouse(hammergui_sink);
+ pd_bind(master, hammergui_sink->g_psmouse);
}
void hammergui_unbindmouse(t_pd *master)
{
if (hammergui_validate(0) && hammergui_mousevalidate(0)
- && sink->g_mouse->s_thing)
+ && hammergui_sink->g_psmouse->s_thing)
{
- pd_unbind(master, sink->g_mouse);
- if (!sink->g_mouse->s_thing)
+ pd_unbind(master, hammergui_sink->g_psmouse);
+ if (!hammergui_sink->g_psmouse->s_thing)
sys_gui("hammergui_remouse\n");
}
else bug("hammergui_unbindmouse");
@@ -384,8 +454,9 @@ void hammergui_startpolling(t_pd *master)
{
if (hammergui_validate(0) && hammergui_pollvalidate(0))
{
- int doinit = (sink->g_poll->s_thing == (t_pd *)sink);
- pd_bind(master, sink->g_poll);
+ int doinit =
+ (hammergui_sink->g_pspoll->s_thing == (t_pd *)hammergui_sink);
+ pd_bind(master, hammergui_sink->g_pspoll);
if (doinit)
{
/* visibility hack for msw, LATER rethink */
@@ -400,8 +471,8 @@ void hammergui_stoppolling(t_pd *master)
{
if (hammergui_validate(0) && hammergui_pollvalidate(0))
{
- pd_unbind(master, sink->g_poll);
- if (sink->g_poll->s_thing == (t_pd *)sink)
+ pd_unbind(master, hammergui_sink->g_pspoll);
+ if (hammergui_sink->g_pspoll->s_thing == (t_pd *)hammergui_sink)
{
sys_gui("after cancel hammergui_poll\n");
/* visibility hack for msw, LATER rethink */
@@ -415,18 +486,18 @@ void hammergui_bindfocus(t_pd *master)
{
hammergui_validate(1);
hammergui_focusvalidate(1);
- if (!sink->g_focus->s_thing)
- hammergui_dobindfocus(sink);
- pd_bind(master, sink->g_focus);
+ if (!hammergui_sink->g_psfocus->s_thing)
+ hammergui_dobindfocus(hammergui_sink);
+ pd_bind(master, hammergui_sink->g_psfocus);
}
void hammergui_unbindfocus(t_pd *master)
{
if (hammergui_validate(0) && hammergui_focusvalidate(0)
- && sink->g_focus->s_thing)
+ && hammergui_sink->g_psfocus->s_thing)
{
- pd_unbind(master, sink->g_focus);
- if (!sink->g_focus->s_thing)
+ pd_unbind(master, hammergui_sink->g_psfocus);
+ if (!hammergui_sink->g_psfocus->s_thing)
sys_gui("hammergui_refocus\n");
}
else bug("hammergui_unbindfocus");
@@ -434,20 +505,23 @@ void hammergui_unbindfocus(t_pd *master)
void hammergui_bindvised(t_pd *master)
{
+#ifdef HAMMERGUI_DEBUG
+ post("bindvised, master %x", (int)master);
+#endif
hammergui_validate(1);
hammergui_visedvalidate(1);
- if (!sink->g_vised->s_thing)
- hammergui_dobindvised(sink);
- pd_bind(master, sink->g_vised);
+ if (!hammergui_sink->g_psvised->s_thing)
+ hammergui_dobindvised(hammergui_sink);
+ pd_bind(master, hammergui_sink->g_psvised);
}
void hammergui_unbindvised(t_pd *master)
{
if (hammergui_validate(0) && hammergui_visedvalidate(0)
- && sink->g_vised->s_thing)
+ && hammergui_sink->g_psvised->s_thing)
{
- pd_unbind(master, sink->g_vised);
- if (!sink->g_vised->s_thing)
+ pd_unbind(master, hammergui_sink->g_psvised);
+ if (!hammergui_sink->g_psvised->s_thing)
sys_gui("hammergui_revised\n");
}
else bug("hammergui_unbindvised");
diff --git a/shared/hammer/gui.h b/shared/hammer/gui.h
index 13afd0a..3cab055 100644
--- a/shared/hammer/gui.h
+++ b/shared/hammer/gui.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2003 krzYszcz and others.
+/* Copyright (c) 2003-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. */
@@ -8,12 +8,12 @@
typedef struct _hammergui
{
t_pd g_pd;
- t_symbol *g_gui;
- t_symbol *g_mouse;
- t_symbol *g_poll;
- t_symbol *g_focus;
- t_symbol *g_vised;
- int g_up;
+ t_symbol *g_psgui;
+ t_symbol *g_psmouse;
+ t_symbol *g_pspoll;
+ t_symbol *g_psfocus;
+ t_symbol *g_psvised;
+ int g_isup;
} t_hammergui;
void hammergui_bindmouse(t_pd *master);
diff --git a/shared/hammer/tree.c b/shared/hammer/tree.c
index 549dd09..9957da7 100644
--- a/shared/hammer/tree.c
+++ b/shared/hammer/tree.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2003 krzYszcz and others.
+/* Copyright (c) 2003-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. */
@@ -10,8 +10,10 @@
/* LATER freelist */
+typedef t_hammernode *(*t_hammertree_inserthook)(t_hammernode *);
+
#ifdef HAMMERTREE_DEBUG
-/* returns bh or 0 if failed */
+/* returns black-height or 0 if failed */
static int hammernode_verify(t_hammernode *np)
{
if (np)
@@ -43,55 +45,129 @@ static int hammernode_verify(t_hammernode *np)
else return (1);
}
-/* returns bh or 0 if failed */
+/* returns black-height or 0 if failed */
static int hammertree_verify(t_hammertree *tree)
{
return (hammernode_verify(tree->t_root));
}
-static void hammernode_post(t_hammernode *np)
+static int hammernode_checkmulti(t_hammernode *np1, t_hammernode *np2)
{
- startpost("%d %g %d (", np->n_index, np->n_value, np->n_black);
+ if (np1 && np2 && np1->n_key == np2->n_key)
+ {
+ if (np1 == np2)
+ bug("hammernode_checkmulti");
+ else
+ return (1);
+ }
+ return (0);
+}
+
+static void hammernode_post(t_hammertree *tree, t_hammernode *np,
+ t_hammernode_vshowhook hook, char *message)
+{
+ startpost("%d ", np->n_key);
+ if (tree->t_valuetype == HAMMERTYPE_FLOAT)
+ startpost("%g ", HAMMERNODE_GETFLOAT(np));
+ else if (tree->t_valuetype == HAMMERTYPE_SYMBOL)
+ startpost("%s ", HAMMERNODE_GETSYMBOL(np)->s_name);
+ else if (tree->t_valuetype == HAMMERTYPE_ATOM)
+ {
+ t_atom *ap = HAMMERNODE_GETATOMPTR(np);
+ if (ap->a_type == A_FLOAT)
+ startpost("%g ", ap->a_w.w_float);
+ else if (ap->a_type == A_SYMBOL)
+ startpost("%s ", ap->a_w.w_symbol->s_name);
+ }
+ else if (hook)
+ {
+ char buf[MAXPDSTRING];
+ (*hook)(np, buf, MAXPDSTRING);
+ startpost("%s ", buf);
+ }
+ else startpost("0x%08x ", (int)HAMMERNODE_GETSYMBOL(np));
+ startpost("%s ", (np->n_black ? "black" : "red"));
+
+ if (hammernode_checkmulti(np, np->n_parent) ||
+ hammernode_checkmulti(np, np->n_left) ||
+ hammernode_checkmulti(np, np->n_right) ||
+ hammernode_checkmulti(np->n_parent, np->n_left) ||
+ hammernode_checkmulti(np->n_parent, np->n_right) ||
+ hammernode_checkmulti(np->n_left, np->n_right))
+ startpost("multi ");
+
+ if (np->n_parent)
+ startpost("(%d -> ", np->n_parent->n_key);
+ else
+ startpost("(nul -> ");
if (np->n_left)
- startpost("%d, ", np->n_left->n_index);
+ startpost("%d, ", np->n_left->n_key);
else
startpost("nul, ");
if (np->n_right)
- post("%d)", np->n_right->n_index);
+ startpost("%d)", np->n_right->n_key);
else
- post("nul)");
+ startpost("nul)");
+ if (message)
+ post(": %s", message);
+ else
+ endpost();
}
-/* this is a standard stackless traversal, not the best one, obviously...
- (used only for debugging) */
-static int hammertree_traverse(t_hammertree *tree, int postit)
+/* Assert a standard stackless traversal producing the same sequence,
+ as the auxiliary list. */
+static int hammertree_checktraversal(t_hammertree *tree)
{
- t_hammernode *np = tree->t_root;
+ t_hammernode *treewalk = tree->t_root;
+ t_hammernode *listwalk = tree->t_first;
int count = 0;
- while (np)
+ while (treewalk)
{
- t_hammernode *prev = np->n_left;
+ t_hammernode *prev = treewalk->n_left;
if (prev)
{
- while (prev->n_right && prev->n_right != np) prev = prev->n_right;
+ while (prev->n_right && prev->n_right != treewalk)
+ prev = prev->n_right;
if (prev->n_right)
{
prev->n_right = 0;
- if (postit) hammernode_post(np);
count++;
- np = np->n_right;
+ if (treewalk == listwalk)
+ listwalk = listwalk->n_next;
+ else
+ {
+ bug("hammertree_checktraversal 1");
+ hammernode_post(tree, treewalk, 0, "treewalk");
+ if (listwalk)
+ hammernode_post(tree, listwalk, 0, "listwalk");
+ else
+ post("empty listwalk pointer");
+ listwalk = treewalk;
+ }
+ treewalk = treewalk->n_right;
}
else
{
- prev->n_right = np;
- np = np->n_left;
+ prev->n_right = treewalk;
+ treewalk = treewalk->n_left;
}
}
else
{
- if (postit) hammernode_post(np);
count++;
- np = np->n_right;
+ if (treewalk == listwalk)
+ listwalk = listwalk->n_next;
+ else
+ {
+ bug("hammertree_checktraversal 2");
+ hammernode_post(tree, treewalk, 0, "treewalk");
+ if (listwalk)
+ hammernode_post(tree, listwalk, 0, "listwalk");
+ else
+ post("empty listwalk pointer");
+ listwalk = treewalk;
+ }
+ treewalk = treewalk->n_right;
}
}
return (count);
@@ -108,22 +184,39 @@ static int hammernode_height(t_hammernode *np)
else return (0);
}
-void hammertree_debug(t_hammertree *tree, int level)
+void hammertree_debug(t_hammertree *tree, int level,
+ t_hammernode_vshowhook hook)
{
t_hammernode *np;
int count;
post("------------------------");
- count = hammertree_traverse(tree, level);
- if (level > 1)
+ count = hammertree_checktraversal(tree);
+ if (level)
{
- post("***");
- for (np = tree->t_last; np; np = np->n_prev)
- startpost("%d ", np->n_index);
- endpost();
+ for (np = tree->t_first; np; np = np->n_next)
+ hammernode_post(tree, np, hook, 0);
+ if (level > 1)
+ {
+ post("************");
+ for (np = tree->t_last; np; np = np->n_prev)
+ startpost("%d ", np->n_key);
+ endpost();
+ }
}
- post("count %d, height %d, root %d:",
- count, hammernode_height(tree->t_root),
- (tree->t_root ? tree->t_root->n_index : 0));
+ if (tree->t_root)
+ {
+ t_hammernode *first = tree->t_root, *last = tree->t_root;
+ while (first->n_left && first->n_left != tree->t_root)
+ first = first->n_left;
+ while (last->n_right && last->n_right != tree->t_root)
+ last = last->n_right;
+ post("count %d, height %d, root %d",
+ count, hammernode_height(tree->t_root), tree->t_root->n_key);
+ post("first %d, root->left* %d, last %d, root->right* %d",
+ (tree->t_first ? tree->t_first->n_key : 0), first->n_key,
+ (tree->t_last ? tree->t_last->n_key : 0), last->n_key);
+ }
+ else post("empty");
post("...verified (black-height is %d)", hammertree_verify(tree));
post("------------------------");
}
@@ -161,33 +254,101 @@ static void hammertree_rrotate(t_hammertree *tree, t_hammernode *np)
np->n_parent = target;
}
-/* returns a newly inserted or already existing node
- (or 0 if allocation failed) */
-t_hammernode *hammertree_insert(t_hammertree *tree, int ndx)
+static t_hammernode *hammertree_preinserthook(t_hammernode *np)
+{
+ while (np->n_prev && np->n_prev->n_key == np->n_key)
+ np = np->n_prev;
+ if (np->n_left)
+ {
+ np = np->n_prev;
+ if (np->n_right)
+ {
+ /* LATER revisit */
+ bug("hammertree_preinserthook");
+ return (0); /* do nothing */
+ }
+ }
+ return (np);
+}
+
+static t_hammernode *hammertree_postinserthook(t_hammernode *np)
+{
+ while (np->n_next && np->n_next->n_key == np->n_key)
+ np = np->n_next;
+ if (np->n_right)
+ {
+ np = np->n_next;
+ if (np->n_left)
+ {
+ /* LATER revisit */
+ bug("hammertree_postinserthook");
+ return (0); /* do nothing */
+ }
+ }
+ return (np);
+}
+
+/* Returns a newly inserted or already existing node (or 0 if allocation
+ failed). A caller is responsible for assigning a value. If hook is
+ supplied, it is called iff key is found. In case of key being found
+ (which means foundp returns 1), a new node is inserted, unless hook is
+ either empty, or returns null. Hook's nonempty return is the parent
+ for the new node. It is expected to have no more than one child. */
+static t_hammernode *hammertree_doinsert(t_hammertree *tree, int key,
+ t_hammertree_inserthook hook,
+ int *foundp)
{
t_hammernode *np, *parent, *result;
+ int leftchild;
+ *foundp = 0;
if (!(np = tree->t_root))
{
- if (!(np = getbytes(sizeof(*np))))
+ if (!(np = getbytes(tree->t_nodesize)))
return (0);
- np->n_index = ndx;
+ np->n_key = key;
np->n_black = 1;
tree->t_root = tree->t_first = tree->t_last = np;
return (np);
}
do
- if (np->n_index == ndx)
- return (np);
- else
- parent = np;
- while (np = (ndx < np->n_index ? np->n_left : np->n_right));
-
- if (!(np = getbytes(sizeof(*np))))
+ {
+ if (np->n_key == key)
+ {
+ *foundp = 1;
+ if (hook && (parent = (*hook)(np)))
+ {
+ if (parent->n_left && parent->n_right)
+ {
+ bug("hammertree_insert, callback return 1");
+ parent = parent->n_next;
+ }
+ if (leftchild = (key < parent->n_key))
+ {
+ if (parent->n_left)
+ {
+ bug("hammertree_insert, callback return 2");
+ leftchild = 0;
+ }
+ }
+ else if (parent->n_right)
+ leftchild = 1;
+ goto addit;
+ }
+ else return (np); /* a caller may then keep or replace the value */
+ }
+ else parent = np;
+ }
+ while (np = (key < np->n_key ? np->n_left : np->n_right));
+ leftchild = (key < parent->n_key);
+addit:
+ /* parent has no more than one child, new node becomes
+ parent's immediate successor or predecessor */
+ if (!(np = getbytes(tree->t_nodesize)))
return (0);
- np->n_index = ndx;
+ np->n_key = key;
np->n_parent = parent;
- if (ndx < parent->n_index)
+ if (leftchild)
{
parent->n_left = np;
/* update the auxiliary linked list structure */
@@ -269,35 +430,63 @@ t_hammernode *hammertree_insert(t_hammertree *tree, int ndx)
}
/* assuming that requested node exists */
-void hammertree_delete(t_hammertree *tree, t_hammernode *np)
+void hammertree_delete(t_hammertree *tree, t_hammernode *gone)
{
- t_hammernode *gone, *parent, *child;
- /* gone is the actual node to be deleted
- -- it has to be the parent of no more than one child: */
- if (np->n_left && np->n_right)
+ t_hammernode *parent; /* parent of gone, after relinking */
+ t_hammernode *child; /* gone's only child (or null), after relinking */
+ /* gone has to be the parent of no more than one child */
+ if (gone->n_left && gone->n_right)
{
- gone = np->n_next; /* gone always exists */
- child = gone->n_right; /* there is no left child of gone */
- /* gone is not a requested node, so we replace fields to be
- deleted with gone's fields: */
- np->n_index = gone->n_index;
- np->n_value = gone->n_value;
+ /* Successor is the new parent of gone's children, and a new child
+ of gone's parent (if any). Successor always exists in this context,
+ and it has no left child. The simplistic scheme is to replace
+ gone's fields with successor's fields, and delete the successor.
+ We cannot do so, however, because successor may be pointed at... */
+ t_hammernode *successor = gone->n_next;
+ child = successor->n_right;
+ successor->n_left = gone->n_left;
+ successor->n_left->n_parent = successor;
+ if (successor == gone->n_right)
+ parent = successor;
+ else
+ {
+ /* successor's parent always exists in this context,
+ successor is the left child of its parent */
+ parent = successor->n_parent;
+ parent->n_left = child;
+ if (child) /* (sentinel not used) */
+ child->n_parent = parent;
+ successor->n_right = gone->n_right;
+ successor->n_right->n_parent = successor;
+ }
+ if (gone->n_parent)
+ {
+ int swp;
+ if (gone == gone->n_parent->n_left)
+ gone->n_parent->n_left = successor;
+ else
+ gone->n_parent->n_right = successor;
+ successor->n_parent = gone->n_parent;
+ swp = gone->n_black;
+ gone->n_black = successor->n_black;
+ successor->n_black = swp;
+ }
+ else
+ {
+ tree->t_root = successor;
+ successor->n_parent = 0;
+ gone->n_black = successor->n_black;
+ successor->n_black = 1; /* LATER rethink */
+ }
+
/* update the auxiliary linked list structure */
- /* np->n_prev is up-to-date */
- if (np->n_prev)
- np->n_prev->n_next = np;
- else tree->t_first = np;
- if (np->n_next = gone->n_next)
- np->n_next->n_prev = np;
- else tree->t_last = np;
+ if (successor->n_prev = gone->n_prev)
+ gone->n_prev->n_next = successor;
+ else
+ tree->t_first = successor;
}
else
{
- gone = np;
- if (gone->n_left)
- child = gone->n_left;
- else
- child = gone->n_right;
/* update the auxiliary linked list structure */
if (gone->n_prev)
gone->n_prev->n_next = gone->n_next;
@@ -307,25 +496,30 @@ void hammertree_delete(t_hammertree *tree, t_hammernode *np)
gone->n_next->n_prev = gone->n_prev;
else
tree->t_last = gone->n_prev;
- }
- /* connect gone's child with gone's parent */
- if (!(parent = gone->n_parent))
- {
- if (tree->t_root = child)
+
+ /* connect gone's child with gone's parent */
+ if (gone->n_left)
+ child = gone->n_left;
+ else
+ child = gone->n_right;
+ if (parent = gone->n_parent)
{
- child->n_parent = 0;
- child->n_black = 1; /* LATER rethink */
+ if (child) /* (sentinel not used) */
+ child->n_parent = parent;
+ if (gone == parent->n_left)
+ parent->n_left = child;
+ else
+ parent->n_right = child;
}
- goto done;
- }
- else
- {
- if (child) /* (sentinel not used) */
- child->n_parent = parent;
- if (gone == parent->n_left)
- parent->n_left = child;
else
- parent->n_right = child;
+ {
+ if (tree->t_root = child)
+ {
+ child->n_parent = 0;
+ child->n_black = 1; /* LATER rethink */
+ }
+ goto done;
+ }
}
if (gone->n_black)
@@ -431,41 +625,149 @@ void hammertree_delete(t_hammertree *tree, t_hammernode *np)
child->n_black = 1;
}
done:
- freebytes(gone, sizeof(*gone));
+ freebytes(gone, tree->t_nodesize);
#ifdef HAMMERTREE_DEBUG
hammertree_verify(tree);
#endif
}
-t_hammernode *hammertree_search(t_hammertree *tree, int ndx)
+t_hammernode *hammertree_search(t_hammertree *tree, int key)
{
t_hammernode *np = tree->t_root;
- while (np && np->n_index != ndx)
- np = (ndx < np->n_index ? np->n_left : np->n_right);
+ while (np && np->n_key != key)
+ np = (key < np->n_key ? np->n_left : np->n_right);
return (np);
}
-t_hammernode *hammertree_closest(t_hammertree *tree, int ndx, int geqflag)
+t_hammernode *hammertree_closest(t_hammertree *tree, int key, int geqflag)
{
t_hammernode *np, *parent;
if (!(np = tree->t_root))
return (0);
do
- if (np->n_index == ndx)
+ if (np->n_key == key)
return (np);
else
parent = np;
- while (np = (ndx < np->n_index ? np->n_left : np->n_right));
+ while (np = (key < np->n_key ? np->n_left : np->n_right));
if (geqflag)
- return (ndx > parent->n_index ? parent->n_next : parent);
+ return (key > parent->n_key ? parent->n_next : parent);
else
- return (ndx < parent->n_index ? parent->n_prev : parent);
+ return (key < parent->n_key ? parent->n_prev : parent);
+}
+
+t_hammernode *hammertree_insert(t_hammertree *tree, int key, int *foundp)
+{
+ return (hammertree_doinsert(tree, key, 0, foundp));
+}
+
+t_hammernode *hammertree_multiinsert(t_hammertree *tree, int key, int fifoflag)
+{
+ int found;
+ return (hammertree_doinsert(tree, key, (fifoflag ?
+ hammertree_postinserthook :
+ hammertree_preinserthook), &found));
+}
+
+t_hammernode *hammertree_insertfloat(t_hammertree *tree, int key, t_float f,
+ int replaceflag)
+{
+ int found;
+ t_hammernode *np = hammertree_doinsert(tree, key, 0, &found);
+ if (np && (!found || replaceflag))
+ {
+ if (tree->t_valuetype == HAMMERTYPE_FLOAT)
+ {
+ t_hammernode_float *npf = (t_hammernode_float *)np;
+ npf->nf_value = f;
+ }
+ else if (tree->t_valuetype == HAMMERTYPE_ATOM)
+ {
+ t_hammernode_atom *npa = (t_hammernode_atom *)np;
+ t_atom *ap = &npa->na_value;
+ SETFLOAT(ap, f);
+ }
+ else bug("hammertree_insertfloat");
+ }
+ return (np);
+}
+
+t_hammernode *hammertree_insertsymbol(t_hammertree *tree, int key, t_symbol *s,
+ int replaceflag)
+{
+ int found;
+ t_hammernode *np = hammertree_doinsert(tree, key, 0, &found);
+ if (np && (!found || replaceflag))
+ {
+ if (tree->t_valuetype == HAMMERTYPE_SYMBOL)
+ {
+ t_hammernode_symbol *nps = (t_hammernode_symbol *)np;
+ nps->ns_value = s;
+ }
+ else if (tree->t_valuetype == HAMMERTYPE_ATOM)
+ {
+ t_hammernode_atom *npa = (t_hammernode_atom *)np;
+ t_atom *ap = &npa->na_value;
+ SETSYMBOL(ap, s);
+ }
+ else bug("hammertree_insertsymbol");
+ }
+ return (np);
+}
+
+t_hammernode *hammertree_insertatom(t_hammertree *tree, int key, t_atom *ap,
+ int replaceflag)
+{
+ int found;
+ t_hammernode *np = hammertree_doinsert(tree, key, 0, &found);
+ if (np && (!found || replaceflag))
+ {
+ if (tree->t_valuetype == HAMMERTYPE_ATOM)
+ {
+ t_hammernode_atom *npa = (t_hammernode_atom *)np;
+ npa->na_value = *ap;
+ }
+ else bug("hammertree_insertatom");
+ }
+ return (np);
}
/* LATER preallocate 'freecount' nodes */
-void hammertree_init(t_hammertree *tree, int freecount)
+static void hammertree_doinit(t_hammertree *tree, t_hammertype vtype,
+ size_t nodesize, int freecount)
{
tree->t_root = tree->t_first = tree->t_last = 0;
+ tree->t_valuetype = vtype;
+ tree->t_nodesize = nodesize;
+}
+
+void hammertree_inittyped(t_hammertree *tree,
+ t_hammertype vtype, int freecount)
+{
+ size_t nsize;
+ switch (vtype)
+ {
+ case HAMMERTYPE_FLOAT:
+ nsize = sizeof(t_hammernode_float);
+ break;
+ case HAMMERTYPE_SYMBOL:
+ nsize = sizeof(t_hammernode_symbol);
+ break;
+ case HAMMERTYPE_ATOM:
+ nsize = sizeof(t_hammernode_atom);
+ break;
+ default:
+ bug("hammertree_inittyped");
+ vtype = HAMMERTYPE_ILLEGAL;
+ nsize = sizeof(t_hammernode);
+ }
+ hammertree_doinit(tree, vtype, nsize, freecount);
+}
+
+void hammertree_initcustom(t_hammertree *tree,
+ size_t nodesize, int freecount)
+{
+ hammertree_doinit(tree, HAMMERTYPE_CUSTOM, nodesize, freecount);
}
/* LATER keep and/or preallocate 'freecount' nodes (if negative, keep all) */
@@ -476,7 +778,7 @@ void hammertree_clear(t_hammertree *tree, int freecount)
{
np = next;
next = next->n_next;
- freebytes(np, sizeof(*np));
+ freebytes(np, tree->t_nodesize);
}
- hammertree_init(tree, 0);
+ hammertree_doinit(tree, tree->t_valuetype, tree->t_nodesize, 0);
}
diff --git a/shared/hammer/tree.h b/shared/hammer/tree.h
index fcbc036..368fed2 100644
--- a/shared/hammer/tree.h
+++ b/shared/hammer/tree.h
@@ -1,17 +1,24 @@
-/* Copyright (c) 2003 krzYszcz and others.
+/* Copyright (c) 2003-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 __HAMMERTREE_H__
#define __HAMMERTREE_H__
+#ifdef KRZYSZCZ
#define HAMMERTREE_DEBUG
+#endif
+
+typedef enum
+{
+ HAMMERTYPE_FLOAT, HAMMERTYPE_SYMBOL, HAMMERTYPE_ATOM,
+ HAMMERTYPE_CUSTOM, HAMMERTYPE_ILLEGAL
+} t_hammertype;
typedef struct _hammernode
{
- int n_index;
- float n_value;
- int n_black;
+ int n_key;
+ int n_black;
struct _hammernode *n_left;
struct _hammernode *n_right;
struct _hammernode *n_parent;
@@ -19,19 +26,61 @@ typedef struct _hammernode
struct _hammernode *n_next;
} t_hammernode;
+typedef struct _hammernode_float
+{
+ t_hammernode nf_node;
+ t_float nf_value;
+} t_hammernode_float;
+
+typedef struct _hammernode_symbol
+{
+ t_hammernode ns_node;
+ t_symbol *ns_value;
+} t_hammernode_symbol;
+
+typedef struct _hammernode_atom
+{
+ t_hammernode na_node;
+ t_atom na_value;
+} t_hammernode_atom;
+
typedef struct _hammertree
{
t_hammernode *t_root;
t_hammernode *t_first;
t_hammernode *t_last;
+ t_hammertype t_valuetype;
+ size_t t_nodesize;
} t_hammertree;
-t_hammernode *hammertree_insert(t_hammertree *tree, int ndx);
+#define HAMMERNODE_GETFLOAT(np) (((t_hammernode_float *)(np))->nf_value)
+#define HAMMERNODE_GETSYMBOL(np) (((t_hammernode_symbol *)(np))->ns_value)
+#define HAMMERNODE_GETATOMPTR(np) (&((t_hammernode_atom *)(np))->na_value)
+
+typedef void (*t_hammernode_vshowhook)(t_hammernode *, char *, unsigned);
+
+t_hammernode *hammertree_search(t_hammertree *tree, int key);
+t_hammernode *hammertree_closest(t_hammertree *tree, int key, int geqflag);
+
+t_hammernode *hammertree_insert(t_hammertree *tree, int key, int *foundp);
+t_hammernode *hammertree_multiinsert(t_hammertree *tree, int key, int fifoflag);
+t_hammernode *hammertree_insertfloat(t_hammertree *tree, int key, t_float f,
+ int replaceflag);
+t_hammernode *hammertree_insertsymbol(t_hammertree *tree, int key, t_symbol *s,
+ int replaceflag);
+t_hammernode *hammertree_insertatom(t_hammertree *tree, int key, t_atom *ap,
+ int replaceflag);
void hammertree_delete(t_hammertree *tree, t_hammernode *np);
-t_hammernode *hammertree_search(t_hammertree *tree, int ndx);
-t_hammernode *hammertree_closest(t_hammertree *tree, int ndx, int geqflag);
-void hammertree_init(t_hammertree *tree, int freecount);
+
+void hammertree_inittyped(t_hammertree *tree,
+ t_hammertype vtype, int freecount);
+void hammertree_initcustom(t_hammertree *tree,
+ size_t nodesize, int freecount);
void hammertree_clear(t_hammertree *tree, int freecount);
-void hammertree_debug(t_hammertree *tree, int level);
+
+#ifdef HAMMERTREE_DEBUG
+void hammertree_debug(t_hammertree *tree, int level,
+ t_hammernode_vshowhook hook);
+#endif
#endif
diff --git a/shared/toxy/scriptlet.c b/shared/toxy/scriptlet.c
index df94e90..be5ff41 100644
--- a/shared/toxy/scriptlet.c
+++ b/shared/toxy/scriptlet.c
@@ -17,12 +17,13 @@
#include "common/props.h"
#include "scriptlet.h"
-//#define SCRIPTLET_DEBUG
+#define SCRIPTLET_DEBUG
-#define SCRIPTLET_INISIZE 1024
-#define SCRIPTLET_MARGIN 64
-#define SCRIPTLET_MAXARGS 9 /* do not increase (parser's constraint) */
-#define SCRIPTLET_MAXPUSH 20000 /* cf SOCKSIZE in t_tkcmd.c, LATER revisit */
+#define SCRIPTLET_INISIZE 1024
+#define SCRIPTLET_INIDOTSIZE 256
+#define SCRIPTLET_MARGIN 64
+#define SCRIPTLET_DOTMARGIN 16
+#define SCRIPTLET_MAXPUSH 20000 /* cf SOCKSIZE in t_tkcmd.c, LATER revisit */
enum { SCRIPTLET_CVOK, SCRIPTLET_CVUNKNOWN, SCRIPTLET_CVMISSING };
@@ -36,15 +37,17 @@ struct _scriptlet
t_scriptlet_cvfn s_cvfn; /* if empty, passing resolveall is a bug */
t_canvas *s_cv; /* as returned by cvfn */
int s_cvstate;
- int s_locked; /* append lock, for filtering, when reading from file */
- int s_size;
- char *s_buffer;
- char s_bufini[SCRIPTLET_INISIZE];
- char *s_head; /* ptr to the command part of a scriptlet */
- char *s_tail;
- char s_separator; /* current separator, set before a new token */
- int s_ac; /* the actual count */
- t_atom s_av[SCRIPTLET_MAXARGS]; /* always padded with zeros (if used) */
+ int s_locked; /* append lock, for filtering, when reading from file */
+ int s_size;
+ char *s_buffer;
+ char s_bufini[SCRIPTLET_INISIZE];
+ char *s_head; /* ptr to the command part of a scriptlet */
+ char *s_tail;
+ char s_separator; /* current separator, set before a new token */
+ int s_dotsize;
+ int s_dotoffset;
+ char *s_dotbuffer;
+ char s_dotbufini[SCRIPTLET_INIDOTSIZE];
};
static t_canvas *scriptlet_canvasvalidate(t_scriptlet *sp, int visedonly)
@@ -114,33 +117,85 @@ static int scriptlet_doappend(t_scriptlet *sp, char *buf)
return (1);
}
-static char *scriptlet_dedot(t_scriptlet *sp, char *ibuf, char *obuf,
+static int scriptlet_dotstring(t_scriptlet *sp, char *st)
+{
+ int len = strlen(st),
+ newsize = sp->s_dotoffset + len + SCRIPTLET_DOTMARGIN;
+ if (newsize > sp->s_dotsize)
+ {
+ int nrequested = newsize;
+ sp->s_dotbuffer = grow_withdata(&nrequested, &sp->s_dotoffset,
+ &sp->s_dotsize, sp->s_dotbuffer,
+ SCRIPTLET_INIDOTSIZE, sp->s_dotbufini,
+ sizeof(*sp->s_dotbuffer));
+ if (nrequested != newsize)
+ {
+ sp->s_dotoffset = 0;
+ sp->s_dotbuffer[0] = 0;
+ return (0);
+ }
+ }
+ strcpy(sp->s_dotbuffer + sp->s_dotoffset, st);
+ sp->s_dotoffset += len;
+ return (1);
+}
+
+static int scriptlet_dotfloat(t_scriptlet *sp, float f)
+{
+ char obuf[32];
+ sprintf(obuf, "%g", f);
+ return (scriptlet_dotstring(sp, obuf));
+}
+
+static char *scriptlet_dedot(t_scriptlet *sp, char *ibuf,
int resolveall, int visedonly,
int ac, t_atom *av, t_props *argprops)
{
int len = 0;
+ char *obuf = sp->s_dotbuffer;
+ sp->s_dotoffset = 0;
switch (*ibuf)
{
case '#':
- /* ac is ignored -- assuming av is padded to SCRIPTLET_MAXARGS atoms */
if (resolveall)
{
int which = ibuf[1] - '1';
- if (which >= 0 && which < SCRIPTLET_MAXARGS)
+ if (which >= 0 && which < 9)
{
- if (av)
+ if (which < ac)
{
- if (av[which].a_type == A_FLOAT)
- {
- sprintf(obuf, "%g", av[which].a_w.w_float);
- len = 2;
- }
- else if (av[which].a_type == A_SYMBOL)
- {
- strcpy(obuf, av[which].a_w.w_symbol->s_name);
- len = 2;
+ av += which;
+ if (av->a_type == A_FLOAT)
+ sprintf(obuf, "%g", av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL && av->a_w.w_symbol)
+ scriptlet_dotstring(sp, av->a_w.w_symbol->s_name);
+ else
+ obuf[0] = 0; /* LATER rethink */
+ }
+ else strcpy(obuf, "0");
+ len = 2;
+ }
+ else if (!strncmp(&ibuf[1], "args", 4))
+ {
+ if (ac) while (1)
+ {
+ if (av->a_type == A_FLOAT)
+ scriptlet_dotfloat(sp, av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL && av->a_w.w_symbol)
+ scriptlet_dotstring(sp, av->a_w.w_symbol->s_name);
+ else
+ { /* LATER rethink */
+ obuf[0] = 0;
+ break;
}
+ ac--; av++;
+ if (ac)
+ sp->s_dotbuffer[sp->s_dotoffset++] = ' ';
+ else
+ break;
}
+ else obuf[0] = 0;
+ len = 5;
}
else if (argprops)
{
@@ -157,7 +212,7 @@ static char *scriptlet_dedot(t_scriptlet *sp, char *ibuf, char *obuf,
}
if (optr = props_getvalue(argprops, ibuf + 1))
{
- strcpy(obuf, optr);
+ scriptlet_dotstring(sp, optr);
len = cnt;
}
if (c) *iptr = c;
@@ -379,20 +434,19 @@ static int scriptlet_addstring(t_scriptlet *sp, char *ibuf,
{
int result = 1;
char *bp = ibuf, *ep = ibuf, *ep1;
- char dotbuf[256]; /* FIXME requires a growable per-scriptlet buffer. */
if (!sp->s_separator)
sp->s_separator = ' ';
while (*ep)
{
if (*ep == '.'
- && (ep1 = scriptlet_dedot(sp, ep + 1, dotbuf,
- resolveall, visedonly, ac, av, argprops)))
+ && (ep1 = scriptlet_dedot(sp, ep + 1, resolveall, visedonly,
+ ac, av, argprops)))
{
*ep = 0;
if (!(result = scriptlet_doappend(sp, bp)))
break;
*ep = '.';
- if (!(result = scriptlet_doappend(sp, dotbuf)))
+ if (!(result = scriptlet_doappend(sp, sp->s_dotbuffer)))
break;
bp = ep = ep1;
}
@@ -504,20 +558,6 @@ int scriptlet_evaluate(t_scriptlet *insp, t_scriptlet *outsp, int visedonly,
int i;
char *bp;
char separator = 0;
- insp->s_ac = ac;
- for (i = 0, ap = insp->s_av; i < SCRIPTLET_MAXARGS; i++, ap++)
- {
- if (ac)
- {
- if (av->a_type == A_FLOAT ||
- (av->a_type == A_SYMBOL && av->a_w.w_symbol))
- *ap = *av;
- else
- SETFLOAT(ap, 0);
- ac--; av++;
- }
- else SETFLOAT(ap, 0);
- }
/* FIXME pregrowing of the transient scriptlet */
scriptlet_reset(outsp);
/* LATER abstract this into scriptlet_parse() */
@@ -546,8 +586,7 @@ int scriptlet_evaluate(t_scriptlet *insp, t_scriptlet *outsp, int visedonly,
}
}
outsp->s_separator = separator;
- scriptlet_addstring(outsp, bp, 1, visedonly,
- ac, insp->s_av, argprops);
+ scriptlet_addstring(outsp, bp, 1, visedonly, ac, av, argprops);
if (done)
break;
*ep = c;
@@ -703,6 +742,7 @@ int scriptlet_read(t_scriptlet *sp, t_symbol *fn)
FILE *fp;
char buf[MAXPDSTRING];
post("loading scriptlet file \"%s\"", fn->s_name);
+ /* FIXME use open_via_path() */
if (sp->s_glist)
canvas_makefilename(sp->s_glist, fn->s_name, buf, MAXPDSTRING);
else
@@ -789,6 +829,9 @@ void scriptlet_free(t_scriptlet *sp)
{
if (sp->s_buffer != sp->s_bufini)
freebytes(sp->s_buffer, sp->s_size * sizeof(*sp->s_buffer));
+ if (sp->s_dotbuffer != sp->s_dotbufini)
+ freebytes(sp->s_dotbuffer,
+ sp->s_dotsize * sizeof(*sp->s_dotbuffer));
freebytes(sp, sizeof(*sp));
}
}
@@ -810,6 +853,7 @@ t_scriptlet *scriptlet_new(t_pd *owner, t_symbol *rptarget, t_symbol *cbtarget,
sys_gui(" pd [concat $target _rp $::toxy::reply \\;]\n");
sys_gui(" unset ::toxy::reply\n");
sys_gui("}\n");
+ configured = 1;
}
sp->s_owner = owner;
sp->s_glist = gl;
@@ -819,6 +863,9 @@ t_scriptlet *scriptlet_new(t_pd *owner, t_symbol *rptarget, t_symbol *cbtarget,
sp->s_cvfn = cvfn;
sp->s_size = SCRIPTLET_INISIZE;
sp->s_buffer = sp->s_bufini;
+ sp->s_dotsize = SCRIPTLET_INIDOTSIZE;
+ sp->s_dotoffset = 0;
+ sp->s_dotbuffer = sp->s_dotbufini;
scriptlet_reset(sp);
}
return (sp);
diff --git a/test/cyclone/offer-test.pd b/test/cyclone/offer-test.pd
index 537a3b9..94cdfa7 100644
--- a/test/cyclone/offer-test.pd
+++ b/test/cyclone/offer-test.pd
@@ -1,11 +1,11 @@
#N canvas 299 297 735 363 12;
#X obj 49 244 offer;
-#X floatatom 49 279 5 0 0;
+#X floatatom 49 279 5 0 0 0 - - -;
#X msg 50 114 clear;
-#X floatatom 172 181 5 0 0;
+#X floatatom 172 181 5 0 0 0 - - -;
#X obj 212 244 * -1;
#X obj 172 209 t 0 0;
-#X floatatom 172 147 5 0 0;
+#X floatatom 172 147 5 0 0 0 - - -;
#X obj 279 110 Uzi;
#X msg 49 181 debug \$1;
#X msg 71 147 1;
@@ -30,11 +30,14 @@
#X obj 531 234 t 0 b;
#X msg 531 196 50;
#X msg 582 196 100;
-#X obj 429 234 Uzi;
-#X msg 429 196 50;
-#X msg 480 196 100;
-#X obj 429 271 urn 100;
+#X obj 409 218 Uzi;
+#X msg 330 147 50;
+#X msg 369 147 100;
#X msg 117 209 1.5;
+#X obj 409 181 t 0 0;
+#X obj 409 255 urn;
+#X msg 409 147 500;
+#X msg 449 147 5000;
#X connect 0 0 1 0;
#X connect 2 0 0 0;
#X connect 3 0 5 0;
@@ -69,8 +72,12 @@
#X connect 28 1 27 0;
#X connect 29 0 28 0;
#X connect 30 0 28 0;
-#X connect 31 0 34 0;
-#X connect 32 0 31 0;
-#X connect 33 0 31 0;
+#X connect 31 0 36 0;
+#X connect 32 0 35 0;
+#X connect 33 0 35 0;
#X connect 34 0 0 0;
-#X connect 35 0 0 0;
+#X connect 35 0 31 0;
+#X connect 35 1 36 1;
+#X connect 36 0 0 0;
+#X connect 37 0 35 0;
+#X connect 38 0 35 0;
diff --git a/test/toxy/setup.wid b/test/toxy/setup.wid
index 9da8775..3ae0a70 100644
--- a/test/toxy/setup.wid
+++ b/test/toxy/setup.wid
@@ -116,20 +116,20 @@ proc ::toxy::item_visconfig {path target name varname cvpath px py} {
}
}
- if {[info exists ::toxy::masterinits]} {
- set failed [catch {eval $::toxy::masterinits} res]
- unset ::toxy::masterinits
- if {$failed} { error [concat in ::toxy::masterinits: $res] }
+ if {[info exists ::toxy::masterinit]} {
+ set failed [catch {eval $::toxy::masterinit} res]
+ unset ::toxy::masterinit
+ if {$failed} { error [concat in ::toxy::masterinit: $res] }
}
- if {[info exists ::toxy::typeinits]} {
- set failed [catch {eval $::toxy::typeinits} res]
- unset ::toxy::typeinits
- if {$failed} { error [concat in ::toxy::typeinits: $res] }
+ if {[info exists ::toxy::typeinit]} {
+ set failed [catch {eval $::toxy::typeinit} res]
+ unset ::toxy::typeinit
+ if {$failed} { error [concat in ::toxy::typeinit: $res] }
}
- if {[info exists ::toxy::iteminits]} {
- set failed [catch {eval $::toxy::iteminits} res]
- unset ::toxy::iteminits
- if {$failed} { error [concat in ::toxy::iteminits: $res] }
+ if {[info exists ::toxy::iteminit]} {
+ set failed [catch {eval $::toxy::iteminit} res]
+ unset ::toxy::iteminit
+ if {$failed} { error [concat in ::toxy::iteminit: $res] }
}
::toxy::item_getconfig $path $target
@@ -204,7 +204,15 @@ proc ::toxy::master {path toppath cvpath target} {
# FIXME
proc ::toxy::scale_command {target sel v} {
- pd [concat $target $sel $v \;]
+ if {$::toxy::scale_isactive} {
+ pd [concat $target $sel $v \;]
+ }
+ set ::toxy::scale_isactive 1
+}
+
+proc ::toxy::scale_doset {path v} {
+ set ::toxy::scale_isactive 0
+ $path set $v
}
proc ::toxy::popup_command {path target remote i text} {
@@ -239,6 +247,9 @@ proc ::toxy::popup {path target remote entries args} {
::toxy::master .- .- .^.c .|
+# FIXME
+set ::toxy::scale_isactive 1
+
# standard widget types
#> bang button
@@ -250,6 +261,7 @@ proc ::toxy::popup {path target remote entries args} {
#. -command [concat ::toxy::scale_command .| _cb]
#. -bg pink -activebackground red -length 200
#. @float .- set .#1
+#. @vset ::toxy::scale_doset .- .#1
#> symbol entry
#. -bg pink -font .(helvetica 24.) -width 16
diff --git a/toxy/Makefile b/toxy/Makefile
index 3035cb4..cd9cd5a 100644
--- a/toxy/Makefile
+++ b/toxy/Makefile
@@ -8,6 +8,7 @@ checkwiq:
rm -f $(WIQFILE) ; fi
$(WIQFILE): $(WIDPATH)
@echo transferring widget definitions from \"$<\" to \"$@\"
+# LATER think how to replace puts with pdtk_post
@echo -e '// Do not edit this file (edit "$<", and run "make").\
\n//\nputs stderr [concat loading built-in widget definitions]' \
| cat - $< | sed \
diff --git a/toxy/plustot.print.c b/toxy/plustot.print.c
index 42ef385..0bd6357 100644
--- a/toxy/plustot.print.c
+++ b/toxy/plustot.print.c
@@ -16,6 +16,11 @@ typedef struct _plustot_print
static t_class *plustot_print_class;
+static char *plustot_print_symbolname(t_symbol *s)
+{
+ return (s && s != &s_ ? s->s_name : "???");
+}
+
static void plustot_print_symbol(t_plustot_print *x, t_symbol *s)
{
Tcl_Obj *ob = plustag_tobvalue(s, (t_pd *)x);
@@ -36,10 +41,9 @@ static void plustot_print_symbol(t_plustot_print *x, t_symbol *s)
t_atom *av = binbuf_getvec(x->x_bb);
if (av->a_type == A_SYMBOL || av->a_type == A_FLOAT)
{
- char *lstring =
- (x->x_label ? x->x_label->s_name :
- loud_symbolname(plustag_typename(s, 1, (t_pd *)x),
- "???"));
+ char *lstring = (x->x_label ? x->x_label->s_name :
+ plustot_print_symbolname(
+ plustag_typename(s, 1, (t_pd *)x)));
if (glname)
startpost("%s (%s):", lstring, glname->s_name);
else
diff --git a/toxy/widget.c b/toxy/widget.c
index d544145..7bfbb74 100644
--- a/toxy/widget.c
+++ b/toxy/widget.c
@@ -2,8 +2,6 @@
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
-/* LATER consider supporting a special @ini handler, also think about
- differentiating 'ini' from 'vis' */
/* LATER think about reloading method for .wid files */
#include <stdio.h>
@@ -39,6 +37,18 @@ typedef struct _widgetentry
struct _widgetentry *we_next;
} t_widgetentry;
+/* move to widgettype.c&h */
+typedef struct _widgethandlers
+{
+ t_scriptlet *wh_initializer;
+ t_scriptlet *wh_new;
+ t_scriptlet *wh_free;
+ t_scriptlet *wh_bang;
+ t_scriptlet *wh_float;
+ t_scriptlet *wh_symbol;
+ /* ... (varsized vector) */
+} t_widgethandlers;
+
typedef struct _widget
{
t_object x_ob;
@@ -55,6 +65,7 @@ typedef struct _widget
t_props *x_options; /* instance options */
t_props *x_handlers; /* instance handlers */
t_props *x_arguments; /* instance arguments */
+ t_widgethandlers x_cache; /* actual handlers */
t_scriptlet *x_iniscript; /* instance initializer */
t_scriptlet *x_optscript; /* option scriptlet */
t_scriptlet *x_auxscript; /* auxiliary scriptlet */
@@ -145,18 +156,35 @@ static t_symbol *widget_getmypathname(t_widget *x, t_glist *glist)
return (gensym(buf));
}
-static void widget_postatoms(char *msg, int ac, t_atom *av)
+/* pity cannot set sys_printtostderr... */
+static void widget_postatoms(FILE *fp, char *msg, int ac, t_atom *av)
{
- startpost(msg);
- while (ac--)
+ if (fp)
{
- if (av->a_type == A_FLOAT)
- postfloat(av->a_w.w_float);
- else if (av->a_type == A_SYMBOL)
- poststring(av->a_w.w_symbol->s_name);
- av++;
+ fputs(msg, fp);
+ while (ac--)
+ {
+ char buf[80];
+ atom_string(av, buf, 80);
+ fputc(' ', fp);
+ fputs(buf, fp);
+ av++;
+ }
+ fputc('\n', fp);
+ }
+ else
+ {
+ startpost(msg);
+ while (ac--)
+ {
+ if (av->a_type == A_FLOAT)
+ postfloat(av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL)
+ poststring(av->a_w.w_symbol->s_name);
+ av++;
+ }
+ endpost();
}
- endpost();
}
/* If Tk widget creation fails, gui will send the '_failure' message
@@ -292,26 +320,54 @@ static void widget_pushoptions(t_widget *x, int doit)
static void widget_pushinits(t_widget *x)
{
- if (masterwidget_evaluate(x->x_transient, 0, 0, 0, x->x_arguments))
- scriptlet_vpush(x->x_transient, "masterinits");
+ if (masterwidget_ievaluate(x->x_transient, 0, 0, 0, x->x_arguments))
+ scriptlet_vpush(x->x_transient, "masterinit");
else
bug("widget_pushinits (master)");
if (widgettype_isdefined(x->x_typedef))
{
int sz;
- if (widgettype_evaluate(x->x_typedef, x->x_transient, 0,
- 0, 0, x->x_arguments))
- scriptlet_vpush(x->x_transient, "typeinits");
- else if (*widgettype_getcontents(x->x_typedef, &sz) && sz > 0)
+ if (widgettype_ievaluate(x->x_typedef, x->x_transient, 0,
+ 0, 0, x->x_arguments))
+ scriptlet_vpush(x->x_transient, "typeinit");
+ else if (*widgettype_getinitializer(x->x_typedef, &sz) && sz > 0)
bug("widget_pushinits (type)");
}
if (scriptlet_evaluate(x->x_iniscript, x->x_transient, 0,
0, 0, x->x_arguments))
- scriptlet_vpush(x->x_transient, "iteminits");
+ scriptlet_vpush(x->x_transient, "iteminit");
else if (!scriptlet_isempty(x->x_iniscript))
bug("widget_pushinits (instance)");
}
+static void widget_pushconstructors(t_widget *x)
+{
+ /* LATER master constructor */
+ if (widgettype_isdefined(x->x_typedef))
+ {
+ int sz;
+ if (widgettype_cevaluate(x->x_typedef, x->x_transient, 0,
+ 0, 0, x->x_arguments))
+ scriptlet_push(x->x_transient);
+ else if (*widgettype_getconstructor(x->x_typedef, &sz) && sz > 0)
+ bug("widget_pushconstructors (type)");
+ }
+}
+
+static void widget_pushdestructors(t_widget *x)
+{
+ /* LATER master destructor */
+ if (widgettype_isdefined(x->x_typedef))
+ {
+ int sz;
+ if (widgettype_devaluate(x->x_typedef, x->x_transient, 0,
+ 0, 0, x->x_arguments))
+ scriptlet_push(x->x_transient);
+ else if (*widgettype_getdestructor(x->x_typedef, &sz) && sz > 0)
+ bug("widget_pushdestructors (type)");
+ }
+}
+
static void widget_getconfig(t_widget *x)
{
sys_vgui("::toxy::item_getconfig %s %s\n",
@@ -465,7 +521,9 @@ static void widget_update(t_widget *x, t_props *op)
}
else
{
- /* LATER cache handlers */
+ /* LATER cache handlers.
+ We get here both during construction, and after any change
+ in our handlers -- the cache never stales. */
}
}
@@ -697,7 +755,7 @@ static void widget_refresh(t_widget *x)
static void widget__failure(t_widget *x, t_symbol *s, int ac, t_atom *av)
{
#if 0
- /* moved to the gui side, in order to alow special chars in error message */
+ /* moved to the gui side -- supporting special chars in error message */
startpost("tcl error:");
postatom(ac, av);
endpost();
@@ -839,39 +897,56 @@ static void widget_debug(t_widget *x)
t_symbol *mn = widget_getmypathname(x, 0);
int sz, i, nopt;
t_atom *ap;
+ static char bempty[] = "<empty>";
char *bp, *key;
- post("containing glist: %x", x->x_glist);
- post("cv pathname%s %s", (pn ? ":" : ""), (pn ? pn->s_name : "unknown"));
- post("my pathname%s %s", (mn ? ":" : ""), (mn ? mn->s_name : "unknown"));
+ fprintf(stderr, "containing glist: %x\n", (int)x->x_glist);
+ fprintf(stderr, "cv pathname%s %s\n",
+ (pn ? ":" : ""), (pn ? pn->s_name : "unknown"));
+ fprintf(stderr, "my pathname%s %s\n",
+ (mn ? ":" : ""), (mn ? mn->s_name : "unknown"));
if (ap = props_getall(widgettype_getoptions(x->x_typedef), &nopt))
- widget_postatoms("default options:", nopt, ap);
+ widget_postatoms(stderr, "default options:", nopt, ap);
if (ap = props_getall(x->x_options, &nopt))
- widget_postatoms("instance options:", nopt, ap);
+ widget_postatoms(stderr, "instance options:", nopt, ap);
if (ap = props_getall(widgettype_gethandlers(x->x_typedef), &nopt))
- widget_postatoms("default handlers:", nopt, ap);
+ widget_postatoms(stderr, "default handlers:", nopt, ap);
if (ap = props_getall(x->x_handlers, &nopt))
- widget_postatoms("instance handlers:", nopt, ap);
+ widget_postatoms(stderr, "instance handlers:", nopt, ap);
if (ap = props_getall(widgettype_getarguments(x->x_typedef), &nopt))
- widget_postatoms("default arguments:", nopt, ap);
+ widget_postatoms(stderr, "default arguments:", nopt, ap);
if (ap = props_getall(x->x_arguments, &nopt))
- widget_postatoms("instance arguments:", nopt, ap);
- post("dictionary:");
+ widget_postatoms(stderr, "instance arguments:", nopt, ap);
+ fprintf(stderr, "dictionary:\n");
bp = props_firstvalue(x->x_arguments, &key);
while (bp)
{
- post("\t%s: \"%s\"", key, bp);
+ fprintf(stderr, "\t%s: \"%s\"\n", key, bp);
bp = props_nextvalue(x->x_arguments, &key);
}
bp = scriptlet_getcontents(x->x_transient, &sz);
- post("transient buffer (size %d):\n\"%s\"", sz, bp);
+ fprintf(stderr, "transient buffer (size %d):\n\"%s\"\n",
+ sz, (bp ? bp : bempty));
bp = scriptlet_getcontents(x->x_optscript, &sz);
- post("option buffer (size %d):\n\"%s\"", sz, bp);
- bp = widgettype_getcontents(x->x_typedef, &sz);
- post("type initializer (size %d):\n\"%s\"", sz, bp);
+ fprintf(stderr, "option buffer (size %d):\n\"%s\"\n",
+ sz, (bp ? bp : bempty));
+ bp = widgettype_getconstructor(x->x_typedef, &sz);
+ fprintf(stderr, "type constructor (size %d):\n\"%s\"\n",
+ sz, (bp ? bp : bempty));
+ bp = widgettype_getdestructor(x->x_typedef, &sz);
+ fprintf(stderr, "type destructor (size %d):\n\"%s\"\n",
+ sz, (bp ? bp : bempty));
+ bp = masterwidget_getinitializer(&sz);
+ fprintf(stderr, "master initializer (size %d):\n\"%s\"\n",
+ sz, (bp ? bp : bempty));
+ bp = widgettype_getinitializer(x->x_typedef, &sz);
+ fprintf(stderr, "type initializer (size %d):\n\"%s\"\n",
+ sz, (bp ? bp : bempty));
bp = scriptlet_getcontents(x->x_iniscript, &sz);
- post("instance initializer (size %d):\n\"%s\"", sz, bp);
+ fprintf(stderr, "instance initializer (size %d):\n\"%s\"\n",
+ sz, (bp ? bp : bempty));
bp = masterwidget_getcontents(&sz);
- post("setup definitions (size %d):\n\"%s\"", sz, bp);
+ fprintf(stderr, "setup definitions (size %d):\n\"%s\"\n",
+ sz, (bp ? bp : bempty));
}
#endif
@@ -889,6 +964,7 @@ static void gui_unbind(t_pd *x, t_symbol *s)
static void widget_free(t_widget *x)
{
widget_novis(x);
+ widget_pushdestructors(x);
gui_unbind((t_pd *)x, x->x_cbtarget);
gui_unbind((t_pd *)x, x->x_rptarget);
props_freeall(x->x_options);
@@ -907,7 +983,7 @@ static void *widget_new(t_symbol *s, int ac, t_atom *av)
char buf[MAXPDSTRING];
if (widget_transforming)
return (0);
- masterwidget_initialize();
+ masterwidget_validate();
x = (t_widget *)pd_new(widget_class);
x->x_type = 0;
x->x_name = 0;
@@ -978,6 +1054,7 @@ static void *widget_new(t_symbol *s, int ac, t_atom *av)
x->x_disabled = 0;
x->x_vised = 0;
widget_attach(x);
+ widget_pushconstructors(x);
return (x);
}
@@ -988,7 +1065,7 @@ static t_glist *tow_getglist(t_tow *x, int complain)
(t_glist *)pd_findbyclass(x->x_cvremote, canvas_class) : x->x_glist);
if (!glist && complain)
loud_error((t_pd *)x, "bad canvas name '%s'", x->x_cvname->s_name);
- return (glist);
+ return (glist_getcanvas(glist));
}
static void tow_bang(t_tow *x)
@@ -1160,20 +1237,22 @@ static void tow_detach(t_tow *x)
static void tow_debug(t_tow *x)
{
t_widgetentry *we;
- post("attached widgets:");
+ fprintf(stderr, "attached widgets:\n");
for (we = x->x_widgetlist; we; we = we->we_next)
{
t_widget *w = we->we_widget;
t_towentry *te;
int other = 0, found = 0;
- startpost("\t%s %s", w->x_type->s_name, w->x_cbtarget->s_name);
+ fprintf(stderr, "\t%s %s", w->x_type->s_name, w->x_cbtarget->s_name);
for (te = w->x_towlist; te; te = te->te_next)
if (te->te_tow == x)
found++;
else
other++;
- post(" (%d other tow%s)", other, (other == 1 ? "" : "s"));
- if (found != 1) post("BUG: listed %d times in widget's towlist", found);
+ fprintf(stderr, " (%d other tow%s)\n", other, (other == 1 ? "" : "s"));
+ if (found != 1)
+ fprintf(stderr, "BUG: listed %d times in widget's towlist\n",
+ found);
}
}
#endif
@@ -1207,8 +1286,28 @@ static void *tow_new(t_symbol *s1, t_symbol *s2, t_symbol *s3)
t_tow *x = (t_tow *)pd_new(tow_class);
char buf[64];
x->x_glist = canvas_getcurrent();
- if (s1 && s1 != &s_ && strcmp(s1->s_name, "."))
- x->x_cvremote = canvas_makebindsym(x->x_cvname = s1);
+ if (s1 == &s_ || !strcmp(s1->s_name, "."))
+ s1 = 0;
+ if (s1)
+ {
+ if (strcmp(s1->s_name, ".parent"))
+ x->x_cvremote = canvas_makebindsym(x->x_cvname = s1);
+ else
+ {
+ if (x->x_glist->gl_owner)
+ {
+ x->x_glist = x->x_glist->gl_owner;
+ x->x_cvremote = 0;
+ x->x_cvname = x->x_glist->gl_name;
+ }
+ else
+ {
+ /* FIXME */
+ loud_error((t_pd *)x, "no parent patch");
+ x->x_cvremote = canvas_makebindsym(x->x_cvname = s1);
+ }
+ }
+ }
else
{
x->x_cvremote = 0;
diff --git a/toxy/widgettype.c b/toxy/widgettype.c
index 3cb7d6e..0b8163f 100644
--- a/toxy/widgettype.c
+++ b/toxy/widgettype.c
@@ -16,7 +16,7 @@ static char masterwidget_builtin[] =
;
#define WIDGETTYPE_VERBOSE
-//#define WIDGETTYPE_DEBUG
+#define WIDGETTYPE_DEBUG
struct _widgettype
{
@@ -28,6 +28,8 @@ struct _widgettype
t_props *wt_handlers;
t_props *wt_arguments;
t_scriptlet *wt_iniscript;
+ t_scriptlet *wt_newscript;
+ t_scriptlet *wt_freescript;
};
struct _masterwidget
@@ -36,7 +38,7 @@ struct _masterwidget
t_symbol *mw_target;
t_scriptlet *mw_setupscript;
t_dict *mw_typemap;
- t_widgettype *mw_mastertype; /* contains master iniscript */
+ t_widgettype *mw_mastertype; /* contains master initializer */
t_widgettype *mw_parsedtype; /* the type currently parsed, if loading */
t_binbuf *mw_bb; /* auxiliary, LATER remove */
};
@@ -68,6 +70,10 @@ static t_widgettype *widgettype_new(t_masterwidget *mw,
wt->wt_arguments = props_new(0, "argument", "#", wt->wt_options, 0);
wt->wt_iniscript = scriptlet_new((t_pd *)wt, mw->mw_target, mw->mw_target,
0, 0, widgettype_cvhook);
+ wt->wt_newscript = scriptlet_new((t_pd *)wt, mw->mw_target, mw->mw_target,
+ 0, 0, widgettype_cvhook);
+ wt->wt_freescript = scriptlet_new((t_pd *)wt, mw->mw_target, mw->mw_target,
+ 0, 0, widgettype_cvhook);
dict_bind(mw->mw_typemap, (t_pd *)wt, wt->wt_typekey);
return (wt);
}
@@ -93,7 +99,7 @@ static t_scriptlet *masterwidget_cmnthook(t_pd *caller, char *rc,
if (!cls)
cls = buf;
typekey = dict_key(mw->mw_typemap, buf);
- typeval = (t_widgettype *)dict_value(mw->mw_typemap, typekey);
+ typeval = (t_widgettype *)dict_firstvalue(mw->mw_typemap, typekey, 0);
if (caller == (t_pd *)mw)
{ /* setup.wid or built-in defaults */
if (mw->mw_mastertype)
@@ -162,6 +168,24 @@ static t_scriptlet *masterwidget_cmnthook(t_pd *caller, char *rc,
}
}
}
+ else if (sel == '@')
+ { /* multiline definition of a handler */
+ scriptlet_nextword(buf);
+ if (mw->mw_parsedtype)
+ {
+ if (!strcmp(buf, "vis") || !strcmp(buf, "ini"))
+ return (mw->mw_parsedtype->wt_iniscript);
+ else if (!strcmp(buf, "new"))
+ return (mw->mw_parsedtype->wt_newscript);
+ else if (!strcmp(buf, "free"))
+ return (mw->mw_parsedtype->wt_freescript);
+ else
+ {
+ /* LATER start parsing any method handler: search for it,
+ create if not found, return */
+ }
+ }
+ }
return (SCRIPTLET_UNLOCK);
}
@@ -170,9 +194,9 @@ t_widgettype *widgettype_get(t_symbol *s)
t_widgettype *wt;
/* Design decision: setup.wid defs are NOT overridden by <type>.wid
(sacrificing flexibility for feature stability). */
- if (wt = (t_widgettype *)dict_value(masterwidget->mw_typemap,
- dict_key(masterwidget->mw_typemap,
- s->s_name)))
+ if (wt = (t_widgettype *)dict_firstvalue(masterwidget->mw_typemap,
+ dict_key(masterwidget->mw_typemap,
+ s->s_name), 0))
masterwidget->mw_parsedtype = 0;
else
{
@@ -193,7 +217,7 @@ t_widgettype *widgettype_get(t_symbol *s)
== SCRIPTLET_OK)
{
#ifdef WIDGETTYPE_VERBOSE
- post("using %s's initializer", s->s_name);
+ post("using a separate %s's definition file", s->s_name);
#endif
if (!scriptlet_isempty(mwsp))
{
@@ -239,18 +263,42 @@ t_props *widgettype_getarguments(t_widgettype *wt)
return (wt->wt_arguments);
}
-char *widgettype_getcontents(t_widgettype *wt, int *szp)
+char *widgettype_getinitializer(t_widgettype *wt, int *szp)
{
return (scriptlet_getcontents(wt->wt_iniscript, szp));
}
-int widgettype_evaluate(t_widgettype *wt, t_scriptlet *outsp,
- int visedonly, int ac, t_atom *av, t_props *argprops)
+char *widgettype_getconstructor(t_widgettype *wt, int *szp)
+{
+ return (scriptlet_getcontents(wt->wt_newscript, szp));
+}
+
+char *widgettype_getdestructor(t_widgettype *wt, int *szp)
+{
+ return (scriptlet_getcontents(wt->wt_freescript, szp));
+}
+
+int widgettype_ievaluate(t_widgettype *wt, t_scriptlet *outsp,
+ int visedonly, int ac, t_atom *av, t_props *argprops)
{
return (scriptlet_evaluate(wt->wt_iniscript, outsp,
visedonly, ac, av, argprops));
}
+int widgettype_cevaluate(t_widgettype *wt, t_scriptlet *outsp,
+ int visedonly, int ac, t_atom *av, t_props *argprops)
+{
+ return (scriptlet_evaluate(wt->wt_newscript, outsp,
+ visedonly, ac, av, argprops));
+}
+
+int widgettype_devaluate(t_widgettype *wt, t_scriptlet *outsp,
+ int visedonly, int ac, t_atom *av, t_props *argprops)
+{
+ return (scriptlet_evaluate(wt->wt_freescript, outsp,
+ visedonly, ac, av, argprops));
+}
+
void widgettype_setup(void)
{
static int done = 0;
@@ -264,11 +312,10 @@ void widgettype_setup(void)
}
}
-int masterwidget_evaluate(t_scriptlet *outsp, int visedonly,
- int ac, t_atom *av, t_props *argprops)
+char *masterwidget_getinitializer(int *szp)
{
- return (scriptlet_evaluate(masterwidget->mw_mastertype->wt_iniscript,
- outsp, visedonly, ac, av, argprops));
+ return (scriptlet_getcontents(masterwidget->mw_mastertype->wt_iniscript,
+ szp));
}
char *masterwidget_getcontents(int *szp)
@@ -276,7 +323,14 @@ char *masterwidget_getcontents(int *szp)
return (scriptlet_getcontents(masterwidget->mw_setupscript, szp));
}
-void masterwidget_initialize(void)
+int masterwidget_ievaluate(t_scriptlet *outsp, int visedonly,
+ int ac, t_atom *av, t_props *argprops)
+{
+ return (scriptlet_evaluate(masterwidget->mw_mastertype->wt_iniscript,
+ outsp, visedonly, ac, av, argprops));
+}
+
+void masterwidget_validate(void)
{
int rcresult;
t_symbol *typekey;
@@ -315,7 +369,8 @@ void masterwidget_initialize(void)
"no file 'setup.wid'... using built-in defaults");
}
typekey = dict_key(masterwidget->mw_typemap, "master");
- if ((typeval = (t_widgettype *)dict_value(masterwidget->mw_typemap, typekey))
+ if ((typeval = (t_widgettype *)dict_firstvalue(masterwidget->mw_typemap,
+ typekey, 0))
&& !scriptlet_isempty(masterwidget->mw_setupscript))
{
masterwidget->mw_mastertype = typeval;
diff --git a/toxy/widgettype.h b/toxy/widgettype.h
index d0df8c6..4894d00 100644
--- a/toxy/widgettype.h
+++ b/toxy/widgettype.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2003 krzYszcz and others.
+/* Copyright (c) 2003-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. */
@@ -18,14 +18,21 @@ t_props *widgettype_getoptions(t_widgettype *wt);
t_props *widgettype_gethandlers(t_widgettype *wt);
t_props *widgettype_getarguments(t_widgettype *wt);
char *widgettype_propname(t_symbol *s);
-char *widgettype_getcontents(t_widgettype *wt, int *szp);
-int widgettype_evaluate(t_widgettype *wt, t_scriptlet *outsp,
- int visedonly, int ac, t_atom *av, t_props *argprops);
+char *widgettype_getinitializer(t_widgettype *wt, int *szp);
+char *widgettype_getconstructor(t_widgettype *wt, int *szp);
+char *widgettype_getdestructor(t_widgettype *wt, int *szp);
+int widgettype_ievaluate(t_widgettype *wt, t_scriptlet *outsp,
+ int visedonly, int ac, t_atom *av, t_props *argprops);
+int widgettype_cevaluate(t_widgettype *wt, t_scriptlet *outsp,
+ int visedonly, int ac, t_atom *av, t_props *argprops);
+int widgettype_devaluate(t_widgettype *wt, t_scriptlet *outsp,
+ int visedonly, int ac, t_atom *av, t_props *argprops);
void widgettype_setup(void);
+char *masterwidget_getinitializer(int *szp);
char *masterwidget_getcontents(int *szp);
-int masterwidget_evaluate(t_scriptlet *outsp, int visedonly,
- int ac, t_atom *av, t_props *argprops);
-void masterwidget_initialize(void);
+int masterwidget_ievaluate(t_scriptlet *outsp, int visedonly,
+ int ac, t_atom *av, t_props *argprops);
+void masterwidget_validate(void);
#endif