aboutsummaryrefslogtreecommitdiff
path: root/gfsm/src
diff options
context:
space:
mode:
authorBryan Jurish <mukau@users.sourceforge.net>2006-02-02 12:49:19 +0000
committerBryan Jurish <mukau@users.sourceforge.net>2006-02-02 12:49:19 +0000
commit0727bfcaf2bd48bf501a7fa95515c400a1996902 (patch)
tree81a3774a9601ba1242482696344f3de3e08f8f22 /gfsm/src
parent6a4001a8538862ac02714a03fedd07c3b6f79366 (diff)
initial cvs import
svn path=/trunk/externals/moocow/; revision=4536
Diffstat (limited to 'gfsm/src')
-rw-r--r--gfsm/src/Makefile.am152
-rw-r--r--gfsm/src/atom_alphabet.c139
-rw-r--r--gfsm/src/atom_alphabet.h80
-rw-r--r--gfsm/src/gfsm-help.pd15
-rw-r--r--gfsm/src/gfsm-help.tfst3
-rw-r--r--gfsm/src/gfsm_alphabet-help.pd64
-rw-r--r--gfsm/src/gfsm_automaton-help.pd288
-rw-r--r--gfsm/src/gfsm_markov-help.pd68
-rw-r--r--gfsm/src/gfsm_markov.pd414
-rw-r--r--gfsm/src/gfsm_state-help.pd55
-rw-r--r--gfsm/src/lkpin.tfst4
-rw-r--r--gfsm/src/lkptest.tfst8
-rw-r--r--gfsm/src/pd_algebra.c299
-rw-r--r--gfsm/src/pd_alphabet.c494
-rw-r--r--gfsm/src/pd_alphabet.h78
-rw-r--r--gfsm/src/pd_automaton.c765
-rw-r--r--gfsm/src/pd_automaton.h85
-rw-r--r--gfsm/src/pd_gfsm.c93
-rw-r--r--gfsm/src/pd_gfsm.h54
-rw-r--r--gfsm/src/pd_io.c75
-rw-r--r--gfsm/src/pd_io.h47
-rw-r--r--gfsm/src/pd_state.c303
-rw-r--r--gfsm/src/pd_state.h58
-rw-r--r--gfsm/src/test-alphabet.pd3
-rw-r--r--gfsm/src/test-alphabet2.pd44
-rw-r--r--gfsm/src/test-automaton.pd260
-rw-r--r--gfsm/src/test-automaton2.pd196
-rw-r--r--gfsm/src/test-fsm.pd2
-rw-r--r--gfsm/src/test-markov.pd211
-rw-r--r--gfsm/src/test-state.pd427
-rw-r--r--gfsm/src/test-state2.pd415
-rw-r--r--gfsm/src/test.lab5
-rw-r--r--gfsm/src/test.tfst3
-rw-r--r--gfsm/src/test2.lab6
-rw-r--r--gfsm/src/test2.tfst4
-rw-r--r--gfsm/src/test3.tfst4
36 files changed, 5221 insertions, 0 deletions
diff --git a/gfsm/src/Makefile.am b/gfsm/src/Makefile.am
new file mode 100644
index 0000000..05d3eda
--- /dev/null
+++ b/gfsm/src/Makefile.am
@@ -0,0 +1,152 @@
+# File: ./src/Makefile.am
+# Package: pd-gfsm
+# Description:
+# + src-level automake file
+#
+# Process this file with Automake to create Makefile.in.
+#-----------------------------------------------------------------------
+
+#-----------------------------------------------------------------------
+# Options & Subdirectories
+#-----------------------------------------------------------------------
+
+## --- recursion subdirectories
+#SUBDIRS =
+
+## --- pseudo-deps for '.SUFFIXES'
+SUFFIXES = .@PDEXT@
+
+#-----------------------------------------------------------------------
+# Flags and variables
+#-----------------------------------------------------------------------
+PDEXT = @PDEXT@
+EXEEXT = .@PDEXT@
+
+#-----------------------------------------------------------------------
+# pd externals (hacked _PROGRAMS target)
+#-----------------------------------------------------------------------
+
+## --- externals
+pdexterns_PROGRAMS = gfsm
+
+## --- patches
+pdexterns_DATA = \
+ gfsm_markov.pd
+
+## --- documentation
+pddoc_DATA = \
+ gfsm-help.pd \
+ gfsm_alphabet-help.pd \
+ gfsm_automaton-help.pd \
+ gfsm_state-help.pd \
+ gfsm_markov-help.pd
+
+#-----------------------------------------------------------------------
+# sources
+#-----------------------------------------------------------------------
+
+gfsm_SOURCES = \
+ config.h \
+ atom_alphabet.h atom_alphabet.c \
+ pd_alphabet.h pd_alphabet.c \
+ \
+ pd_automaton.h pd_automaton.c \
+ pd_algebra.c \
+ \
+ pd_state.h pd_state.c \
+ \
+ pd_io.h pd_io.c \
+ \
+ pd_gfsm.h pd_gfsm.c
+
+
+#----------------------------------------------------------------------
+# external compilation : flags
+#-----------------------------------------------------------------------
+DEFS = @DEFS@
+AFLAGS = @AFLAGS@
+DFLAGS = @DFLAGS@
+IFLAGS = @IFLAGS@
+LFLAGS = @LFLAGS@
+OFLAGS = @OFLAGS@
+WFLAGS = -Wall
+
+AM_CPPFLAGS = $(IFLAGS) $(DFLAGS)
+AM_CFLAGS = $(OFLAGS) $(WFLAGS) $(AFLAGS)
+AM_CXXFLAGS = $(OFLAGS) $(WFLAGS) $(AFLAGS)
+
+gfsm_LDFLAGS = $(LFLAGS)
+#gfsm_LDADD =
+
+#-----------------------------------------------------------------------
+# additional hacks
+#-----------------------------------------------------------------------
+#(none)
+
+#-----------------------------------------------------------------------
+# Variables: cleanup
+#-----------------------------------------------------------------------
+## --- mostlyclean: built by 'make' & commonly rebuilt
+#MOSTLYCLEANFILES =
+
+## --- clean: built by 'make'
+CLEANFILES = *$(EXEEXT)
+
+## --- distclean: built by 'configure'
+DISTCLEANFILES = \
+ config.log \
+ config.cache \
+ config.status
+
+## -- maintainerclean: built by maintainer / by hand
+MAINTAINERCLEANFILES = *~ \
+ $(PODS:.pod=.txt) \
+ Makefile Makefile.in \
+ aclocal.m4 \
+ configure \
+ install-sh \
+ stamp-h.in \
+ config.h.in
+
+maintainer-clean-local:
+ rm -rf autom4te.cache
+
+#CVSCLEAN_SUBDIRS = $(SUBDIRS)
+
+#CVSCLEANFILES = Makefile.in Makefile
+
+
+#-----------------------------------------------------------------------
+# Variables: distribution
+#-----------------------------------------------------------------------
+
+## --- extra distribution files
+EXTRA_DIST = \
+ $(pddoc_DATA) \
+ $(pdexterns_DATA)
+
+
+## --- recursion subdirectories for 'make dist'
+DIST_SUBDIRS = $(SUBDIRS)
+
+## --- dist-hook: when another 'Makefile.am' is overkill
+#DISTHOOK_DIRS = foo
+#DISTHOOK_FILES = foo/bar.txt foo/baz.txt
+#dist-hook:
+# for d in $(DISTHOOK_DIRS); do\
+# mkdir -p $(distdir)/$$d ;\
+# done
+# for f in $(DISTHOOK_FILES); do\
+# cp -p $(srcdir)/$$f $(distdir)/$$f ;\
+# done
+
+#dist-bz2: dist-bzip2 ;
+
+
+#-----------------------------------------------------------------------
+# Rules: cleanup
+#-----------------------------------------------------------------------
+.PHONY: cvsclean cvsclean-hook
+
+cvsclean: maintainer-clean ;
+
diff --git a/gfsm/src/atom_alphabet.c b/gfsm/src/atom_alphabet.c
new file mode 100644
index 0000000..16f4bdd
--- /dev/null
+++ b/gfsm/src/atom_alphabet.c
@@ -0,0 +1,139 @@
+/*=============================================================================*\
+ * File: atom_alphabet.c
+ * Author: Bryan Jurish <moocow@ling.uni-potsdam.de>
+ * Description: finite state automata for Pd: atom alphabet
+ *
+ * Copyright (c) 2004 Bryan Jurish.
+ *
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * See file LICENSE for further informations on licensing terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *=============================================================================*/
+
+#include <atom_alphabet.h>
+#include <string.h>
+
+/*======================================================================
+ * constants
+ */
+gfsmUserAlphabetMethods pd_atom_alphabet_methods =
+ {
+ NULL, //-- key->label lookup function
+ NULL, //-- label->key lookup function
+ NULL, //-- insertion function: receives a newly copied key!
+ NULL, //-- label removal function
+ (gfsmAlphabetKeyReadFunc)gfsm_pd_atom_read, //-- key input function
+ (gfsmAlphabetKeyWriteFunc)gfsm_pd_atom_write //-- key output function
+ };
+
+/*======================================================================
+ * gfsmPdAtomAlphabet: user methods
+ */
+
+
+/*--------------------------------------------------------------
+ * hash()
+ */
+guint gfsm_pd_atom_hash(t_atom *a)
+{
+ if (!a) return 0;
+ switch (a->a_type) {
+ case A_FLOAT: return (guint)(a->a_w.w_float);
+ case A_SYMBOL: return (guint)(a->a_w.w_symbol);
+ case A_SEMI: return (guint)';';
+ case A_COMMA: return (guint)',';
+ default: return 0;
+ }
+ return 0; //-- never reached
+}
+
+/*--------------------------------------------------------------
+ * equal()
+ */
+gboolean gfsm_pd_atom_equal(t_atom *a1, t_atom *a2)
+{
+ if (a1->a_type != a2->a_type) return FALSE;
+ switch (a1->a_type) {
+ case A_FLOAT: return a1->a_w.w_float == a2->a_w.w_float;
+ case A_SYMBOL: return a1->a_w.w_symbol == a2->a_w.w_symbol;
+ default: return memcmp(a1,a2,sizeof(t_atom))==0;
+ }
+}
+
+/*--------------------------------------------------------------
+ * dup()
+ */
+t_atom *gfsm_pd_atom_dup(gfsmPdAtomAlphabet *alph, t_atom *a)
+{
+ //return (a ? copybytes(a, sizeof(t_atom)) : NULL);
+ return (a ? gfsm_mem_dup_n(a,sizeof(t_atom)) : NULL);
+}
+
+/*--------------------------------------------------------------
+ * free()
+ */
+void gfsm_pd_atom_free(t_atom *a)
+{ g_free(a); }
+
+/*--------------------------------------------------------------
+ * read()
+ */
+t_atom *gfsm_pd_atom_read(gfsmPdAtomAlphabet *alph, GString *gstr)
+{
+ binbuf_clear(alph->aa_binbuf);
+ binbuf_text(alph->aa_binbuf, gstr->str, gstr->len);
+ return binbuf_getvec(alph->aa_binbuf);
+}
+
+/*--------------------------------------------------------------
+ * write()
+ */
+void gfsm_pd_atom_write(gfsmPdAtomAlphabet *alph, t_atom *a, GString *gstr)
+{
+ atom_string(a, alph->aa_strbuf, PdGfsmStrBufSize);
+ g_string_assign(gstr, alph->aa_strbuf);
+}
+
+/*======================================================================
+ * gfsmPdAtomAlphabet: shortcuts
+ */
+
+/*--------------------------------------------------------------
+ * new
+ */
+gfsmPdAtomAlphabet *gfsm_pd_atom_alphabet_new(void)
+{
+ gfsmPdAtomAlphabet *alph = g_new0(gfsmPdAtomAlphabet,1);
+ ((gfsmAlphabet*)alph)->type = gfsmATUser;
+ gfsm_user_alphabet_init((gfsmUserAlphabet*)alph,
+ (gfsmAlphabetKeyDupFunc)gfsm_pd_atom_dup,
+ (GHashFunc)gfsm_pd_atom_hash,
+ (GEqualFunc)gfsm_pd_atom_equal,
+ (GDestroyNotify)gfsm_pd_atom_free,
+ NULL,
+ &pd_atom_alphabet_methods);
+ alph->aa_binbuf = binbuf_new();
+ return alph;
+}
+
+//-- destructor
+void gfsm_pd_atom_alphabet_free(gfsmPdAtomAlphabet *alph)
+{
+ if (alph->aa_binbuf) binbuf_free(alph->aa_binbuf);
+ gfsm_alphabet_free((gfsmAlphabet*)alph);
+}
diff --git a/gfsm/src/atom_alphabet.h b/gfsm/src/atom_alphabet.h
new file mode 100644
index 0000000..262ea2c
--- /dev/null
+++ b/gfsm/src/atom_alphabet.h
@@ -0,0 +1,80 @@
+/*=============================================================================*\
+ * File: atom_alphabet.h
+ * Author: Bryan Jurish <moocow@ling.uni-potsdam.de>
+ * Description: finite state automata for Pd: atom alphabet
+ *
+ * Copyright (c) 2004 Bryan Jurish.
+ *
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * See file LICENSE for further informations on licensing terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *=============================================================================*/
+
+#ifndef _PD_GFSM_ATOM_ALPHABET_H
+#define _PD_GFSM_ATOM_ALPHABET_H
+
+#include <m_pd.h>
+#include <gfsm.h>
+
+/*--------------------------------------------------------------
+ * Constants
+ */
+#define PdGfsmStrBufSize 256
+
+extern gfsmUserAlphabetMethods pd_atom_alphabet_methods;
+
+/*--------------------------------------------------------------
+ * Types: gfsmPdAtomAlphabet
+ */
+typedef struct {
+ gfsmUserAlphabet aa_alph;
+ t_binbuf *aa_binbuf;
+ char aa_strbuf[PdGfsmStrBufSize];
+} gfsmPdAtomAlphabet;
+
+/*--------------------------------------------------------------
+ * gfsmPdAtomAlphabet: user methods
+ */
+//-- hash function for pd atoms
+guint gfsm_pd_atom_hash(t_atom *a);
+
+//-- equality check for pd atoms
+gboolean gfsm_pd_atom_equal(t_atom *a1, t_atom *a2);
+
+//-- dup function for pd atoms
+t_atom *gfsm_pd_atom_dup(gfsmPdAtomAlphabet *alph, t_atom *a);
+
+//-- free function for pd atoms
+void gfsm_pd_atom_free(t_atom *a);
+
+//-- string read function for pd atoms
+t_atom *gfsm_pd_atom_read(gfsmPdAtomAlphabet *alph, GString *gstr);
+
+//-- string write function for pd atoms
+void gfsm_pd_atom_write(gfsmPdAtomAlphabet *alph, t_atom *a, GString *gstr);
+
+/*--------------------------------------------------------------
+ * gfsmPdAtomAlphabet: utilities
+ */
+//-- constructor
+gfsmPdAtomAlphabet *gfsm_pd_atom_alphabet_new(void);
+
+//-- destructor
+void gfsm_pd_atom_alphabet_free(gfsmPdAtomAlphabet *alph);
+
+#endif /* _PD_GFSM_ATOM_ALPHABET_H */
diff --git a/gfsm/src/gfsm-help.pd b/gfsm/src/gfsm-help.pd
new file mode 100644
index 0000000..c91aa46
--- /dev/null
+++ b/gfsm/src/gfsm-help.pd
@@ -0,0 +1,15 @@
+#N canvas 0 0 430 269 10;
+#X obj 66 7 gfsm;
+#X text 126 232 Bryan Jurish <moocow@ling.uni-potsdam.de>;
+#X text 21 43 EXTERNALS:;
+#X obj 41 72 gfsm_alphabet;
+#X obj 41 98 gfsm_automaton;
+#X text 159 71 integer <-> atom mapping;
+#X obj 41 124 gfsm_state;
+#X text 161 125 automaton position;
+#X text 160 98 weighted finite state machine;
+#X text 21 184 SEE ALSO:;
+#X text 38 201 gfsmutils(1);
+#X text 99 8 : finite state machine external library;
+#X obj 40 150 gfsm_markov;
+#X text 161 151 trainable Markov chain;
diff --git a/gfsm/src/gfsm-help.tfst b/gfsm/src/gfsm-help.tfst
new file mode 100644
index 0000000..67e2bea
--- /dev/null
+++ b/gfsm/src/gfsm-help.tfst
@@ -0,0 +1,3 @@
+0 2 42 24 0.7
+0 1 2 3 4
+1 0
diff --git a/gfsm/src/gfsm_alphabet-help.pd b/gfsm/src/gfsm_alphabet-help.pd
new file mode 100644
index 0000000..b3d6653
--- /dev/null
+++ b/gfsm/src/gfsm_alphabet-help.pd
@@ -0,0 +1,64 @@
+#N canvas 16 0 646 547 10;
+#X text 289 523 Bryan Jurish <moocow@ling.uni-potsdam.de>;
+#X text 9 524 SEE ALSO:;
+#X text 9 69 INLETS:;
+#X text 27 83 1 - control messages;
+#X text 244 68 OUTLETS:;
+#X obj 80 525 gfsm;
+#X text 48 48 NAME - symbolic name of the alphabet;
+#X text 260 81 1 - value outlet;
+#X text 260 96 2 - bang on missing value;
+#X text 14 31 SYNTAX: gfsm_alphabet [NAME];
+#X obj 13 493 print CHAR;
+#X obj 197 492 print ATOM;
+#X msg 29 182 insert x 1;
+#X text 163 185 "insert ATOM CHAR" : map ATOM<->CHAR;
+#X msg 33 203 insert y;
+#X text 198 203 "insert ATOM" : map ATOM to a new character label;
+#X msg 48 232 atom2char x;
+#X text 177 233 "atom2char ATOM" : lookup character label for ATOM
+;
+#X text 170 253 "atom2char! ATOM" : lookup or insert label for ATOM
+;
+#X text 184 284 "char2atom INT" : lookup atom for label INT;
+#X text 177 301 "char2atom! INT" : lookup or insert atom for INT;
+#X msg 63 281 char2atom 1;
+#X msg 65 301 char2atom! 42;
+#X msg 52 252 atom2char! foo;
+#X text 184 129 "alphabet NAME" : sets current alphabet;
+#X msg 19 151 alphabet;
+#X text 219 145 "alphabet" : use private alphabet;
+#X text 309 159 NOTE: alphabets of the same name share data;
+#X msg 75 332 clear;
+#X msg 91 405 print;
+#X text 240 404 "print" : dump alphabet contents to the console;
+#X msg 91 445 save tmp.lab;
+#X text 212 425 "load FILE" : load alphabet contents from a file;
+#X text 212 445 "save FILE" : save alphabet contents to a file;
+#X text 67 4 gfsm_alphabet : integer<->atom map for finite state machines
+;
+#X text 240 333 "clear" : clears entire alphabet;
+#X msg 76 353 rmatom x;
+#X msg 77 374 rmchar 1;
+#X text 205 372 "rmchar INT" : remove mapping for label INT;
+#X text 198 353 "rmatom ATOM" : remove mapping for atom ATOM;
+#X obj 117 525 gfsm_automaton;
+#X obj 13 471 gfsm_alphabet help-alphabet;
+#X msg 13 127 alphabet help-alphabet;
+#X msg 92 425 load tmp.lab;
+#X connect 12 0 41 0;
+#X connect 14 0 41 0;
+#X connect 16 0 41 0;
+#X connect 21 0 41 0;
+#X connect 22 0 41 0;
+#X connect 23 0 41 0;
+#X connect 25 0 41 0;
+#X connect 28 0 41 0;
+#X connect 29 0 41 0;
+#X connect 31 0 41 0;
+#X connect 36 0 41 0;
+#X connect 37 0 41 0;
+#X connect 41 0 10 0;
+#X connect 41 1 11 0;
+#X connect 42 0 41 0;
+#X connect 43 0 41 0;
diff --git a/gfsm/src/gfsm_automaton-help.pd b/gfsm/src/gfsm_automaton-help.pd
new file mode 100644
index 0000000..10f35ba
--- /dev/null
+++ b/gfsm/src/gfsm_automaton-help.pd
@@ -0,0 +1,288 @@
+#N canvas 126 0 473 476 10;
+#X text 89 7 gfsm_automaton : weighted finite state machine;
+#X text 173 441 Bryan Jurish <moocow@ling.uni-potsdam.de>;
+#X text 7 379 SEE ALSO:;
+#X obj 22 399 gfsm;
+#X text 12 73 INLETS:;
+#X text 30 87 1 - control messages;
+#X text 244 74 OUTLETS:;
+#X text 260 87 1 - value outlet;
+#X text 48 48 NAME - symbolic name of the machine;
+#X text 14 31 SYNTAX: gfsm_automaton [NAME];
+#X text 7 211 SUBTOPICS:;
+#X text 10 114 DESCRIPTION:;
+#X text 245 211 GUTS:;
+#X text 28 130 gfsm_automaton objects represent weighted finite state
+machines (acceptors or transducers) -- rooted \, acyclic graphs whose
+edges are labelled with triples (LO \, HI \, WEIGHT) \, where LO and
+HI are alphabet labels (see gfsm_alphabet) \, and WEIGHT is a floating
+point number.;
+#X obj 265 272 print fsm-help-out;
+#X obj 137 400 gfsm_alphabet;
+#N canvas 192 14 651 458 help-automaton-flags 0;
+#X text 167 4 gfsm_automaton : flags;
+#X msg 22 36 weighted;
+#X msg 32 171 transducer 1;
+#X msg 33 192 transducer 0;
+#X msg 22 151 transducer;
+#X msg 33 57 weighted 1;
+#X msg 34 78 weighted 0;
+#X msg 24 275 semiring;
+#X msg 37 299 semiring boolean;
+#X msg 37 320 semiring log;
+#X msg 37 361 semiring real;
+#X msg 37 382 semiring trivial;
+#X msg 38 402 semiring tropical;
+#X text 192 35 "weighted" : get value of the boolean "weighted" flag
+;
+#X text 157 57 "weighted BOOL" : set "weighted" flag;
+#X text 214 87 weighted automata may behave differently than unweighted
+automata with respect to certain algebraic operations.;
+#X text 178 148 "transducer" : get value of the boolean "transducer"
+flag;
+#X text 143 170 "transducer BOOL" : set "transducer" flag;
+#X text 216 195 transducers may behave differently than acceptors (which
+have only one label per arc) with respect to certain algebraic operations.
+;
+#X text 157 297 "semiring TYPE" : set semiring to use for weight arithmetic
+;
+#X text 192 272 "semiring" : get semiring type used for weight arithmetic
+;
+#X text 336 434 Bryan Jurish <moocow@ling.uni-potsdam.de>;
+#X text 218 328 algebraic operations may be called on to alter arc
+weights \; in this case \, the semiring type associated with the automaton
+will be used to interpret arc weights. work in progress -- if you need
+this for something \, let me know.;
+#X obj 22 101 s fsm-help-in;
+#X obj 22 216 s fsm-help-in;
+#X obj 24 428 s fsm-help-in;
+#X msg 37 341 semiring plog;
+#X connect 1 0 23 0;
+#X connect 2 0 24 0;
+#X connect 3 0 24 0;
+#X connect 4 0 24 0;
+#X connect 5 0 23 0;
+#X connect 6 0 23 0;
+#X connect 7 0 25 0;
+#X connect 8 0 25 0;
+#X connect 9 0 25 0;
+#X connect 10 0 25 0;
+#X connect 11 0 25 0;
+#X connect 12 0 25 0;
+#X connect 26 0 25 0;
+#X restore 19 230 pd help-automaton-flags;
+#N canvas 71 31 651 409 help-automaton-basic 0;
+#X text 345 383 Bryan Jurish <moocow@ling.uni-potsdam.de>;
+#X obj 21 119 s fsm-help-in;
+#X text 167 4 gfsm_automaton : basic operations;
+#X msg 21 45 automaton;
+#X msg 28 69 automaton fsm-help-2;
+#X msg 29 91 automaton fsm-help;
+#X text 179 38 "automaton" : use an object-local machine;
+#X text 145 51 "automaton NAME" : use a shared machine named NAME;
+#X msg 29 193 clear;
+#X text 124 192 "clear" : clears the automaton;
+#X msg 34 217 info;
+#X text 130 215 "info" : prints summary information to the Pd console
+;
+#X msg 35 241 print;
+#X text 221 74 data is shared between automata of the same name. when
+using multiple shared automata \, take care always to leave at least
+one object "pointing" to each name \, since the underlying data structures
+are freed when all references are lost.;
+#X text 124 236 "print" : prints automaton in at&t text format to stdout
+;
+#X obj 19 269 s fsm-help-in;
+#X text 145 262 WARNING: these methods may hog the cpu for extended
+periods of time when called for large machines.;
+#X msg 22 169 renumber;
+#X text 102 170 "renumber" : renumber automaton states \, closing gaps
+;
+#X connect 3 0 1 0;
+#X connect 4 0 1 0;
+#X connect 5 0 1 0;
+#X connect 8 0 15 0;
+#X connect 10 0 15 0;
+#X connect 12 0 15 0;
+#X connect 17 0 15 0;
+#X restore 19 252 pd help-automaton-basic;
+#N canvas 27 14 658 321 help-automaton-io 0;
+#X text 101 2 gfsm_automaton : input/output;
+#X obj 13 93 s fsm-help-in;
+#X text 211 44 "load FILE" : load an automaton in at&t-style text format
+;
+#X text 212 68 "save FILE" : save automaton in at&t-style text format
+;
+#X obj 10 235 s fsm-help-in;
+#X text 225 160 "load_bin FILE" : load an automaton in GFSM binary
+format;
+#X text 354 292 Bryan Jurish <moocow@ling.uni-potsdam.de>;
+#X msg 23 48 load gfsm-help.tfst;
+#X msg 17 162 load_bin gfsm-help.gfst;
+#X msg 23 69 save gfsm-help.tfst;
+#X text 243 240 NOTE: gfsm binary format is not portable across different
+architectures.;
+#X text 235 87 NOTE: currently \, all text i/o is done in "weighted
+transducer" format \, regardless of automaton flags or input file content.
+;
+#X text 227 184 "save_bin FILE" : save automaton in GFSM binary format
+;
+#X msg 18 184 save_bin gfsm-help.gfst;
+#X text 228 209 "save_bin FILE ZLEVEL" : save with zlib compression
+;
+#X msg 24 208 save_bin gfsm-help.gfst 9;
+#X connect 7 0 1 0;
+#X connect 8 0 4 0;
+#X connect 9 0 1 0;
+#X connect 13 0 4 0;
+#X connect 15 0 4 0;
+#X restore 21 296 pd help-automaton-io;
+#N canvas 199 1 636 611 help-automaton-algebra 0;
+#X msg 24 33 complement;
+#X msg 24 62 closure 0;
+#X msg 24 79 closure 1;
+#X msg 24 170 determinize;
+#X msg 24 201 difference fsm-help-2;
+#X msg 24 235 intersect fsm-help-2;
+#X msg 24 267 invert;
+#X msg 24 352 product fsm-help-2;
+#X msg 24 413 reverse;
+#X msg 24 444 rmepsilon;
+#X msg 24 479 union fsm-help-2;
+#X text 222 32 "complement" : compute complement of an acceptor;
+#X msg 24 140 concat fsm-help;
+#X text 215 141 "concat FSM2" : concatenate with automaton named FSM2
+;
+#X text 187 197 "difference FSM2" : remove language of automaton named
+FSM2;
+#X text 194 228 "intersect FSM2" : intersect with automaton named FSM2
+;
+#X text 250 266 "invert" : swap upper and lower labels;
+#X msg 24 302 project 0;
+#X msg 24 319 project 1;
+#X text 208 298 "project SIDE" : project one label side;
+#X text 327 311 SIDE=0: project lower labels;
+#X text 328 323 SIDE=1: project upper labels;
+#X text 208 348 "product FSM2" : compute Cartesian product with FSM2
+;
+#X text 243 407 "reverse" : reverse language of an automaton;
+#X text 95 6 gfsm_automaton : algebraic operations;
+#X text 229 439 "rmepsilon" : remove epsilon arcs;
+#X text 222 478 "union FSM2" : compute union with automaton FSM2;
+#X obj 24 505 s fsm-help-in;
+#X text 31 551 WARNING: these methods may block for long periods of
+time for large automata.;
+#X text 329 578 Bryan Jurish <moocow@ling.uni-potsdam.de>;
+#X msg 24 109 compose fsm-help-2;
+#X text 208 109 "compose FSM2" : compose with transducer FSM2;
+#X text 229 70 "closure N" : compute N-ary closure;
+#X text 215 170 "determinize" : determinize an acceptor;
+#X msg 24 383 connect;
+#X text 244 382 "connect" : remove useless states and arcs;
+#X connect 0 0 27 0;
+#X connect 1 0 27 0;
+#X connect 2 0 27 0;
+#X connect 3 0 27 0;
+#X connect 4 0 27 0;
+#X connect 5 0 27 0;
+#X connect 6 0 27 0;
+#X connect 7 0 27 0;
+#X connect 8 0 27 0;
+#X connect 9 0 27 0;
+#X connect 10 0 27 0;
+#X connect 12 0 27 0;
+#X connect 17 0 27 0;
+#X connect 18 0 27 0;
+#X connect 30 0 27 0;
+#X connect 34 0 27 0;
+#X restore 21 342 pd help-automaton-algebra;
+#X obj 59 400 gfsm_state;
+#X obj 265 230 r fsm-help-in;
+#N canvas 293 117 651 504 help-automaton-access 0;
+#X msg 22 42 size;
+#X floatatom 33 66 5 0 0 0 - - -;
+#X msg 33 82 size \$1;
+#X obj 22 104 s fsm-help-in;
+#X text 118 38 "size" : get number of states in the machine;
+#X text 90 51 "size INT" : grow machine to at least INT states;
+#X text 99 5 gfsm_automaton : automaton access;
+#X floatatom 35 177 5 0 0 0 - - -;
+#X obj 24 215 s fsm-help-in;
+#X msg 24 153 root;
+#X msg 35 193 root \$1;
+#X text 120 149 "root" : get id of machine's initial state or "bang"
+;
+#X text 134 72 note that values reported do not take the VALIDITY of
+states into account -- your mileage may vary.;
+#X text 132 180 in the second form \, the state will be created if
+it does not already exist. states are internally stored in an array
+\, and indexed with positive integer IDs beginning from 0 (zero) --
+i.e. \, a message such as "root 1E+37" is likely to crash Pd.;
+#X text 99 162 "root ID" : set machine's initial state to ID (an integer)
+;
+#X text 139 273 "final ID" : check whether state ID is marked as final
+;
+#X text 104 297 "final ID BOOL" : set final-status of state ID to BOOL
+;
+#X obj 23 344 s fsm-help-in;
+#X text 143 314 same caveats as for "root";
+#X obj 26 436 s fsm-help-in;
+#X msg 23 276 final 1;
+#X msg 30 299 final 1 1;
+#X msg 31 319 final 1 0;
+#X text 207 388 "add_arc FROM TO LO HI WEIGHT" : add an arc;
+#X text 242 403 adds an arc from state FROM to state TO on lower (input)
+label LO and upper (output) label HI with weight WEIGHT. states FROM
+and TO are implicitly created.;
+#X msg 26 390 add_arc 0 1 2 3 4;
+#X msg 38 412 add_arc 0 2 42 24 0.7;
+#X text 349 480 Bryan Jurish <moocow@ling.uni-potsdam.de>;
+#X connect 0 0 3 0;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 7 0 10 0;
+#X connect 9 0 8 0;
+#X connect 10 0 8 0;
+#X connect 20 0 17 0;
+#X connect 21 0 17 0;
+#X connect 22 0 17 0;
+#X connect 25 0 19 0;
+#X connect 26 0 19 0;
+#X restore 20 274 pd help-automaton-access;
+#N canvas 15 0 687 348 help-automaton-draw 0;
+#X obj 13 256 s fsm-help-in;
+#X text 246 63 NOTE: interpreting the resulting file requires the 'graphviz'
+package from at&t.;
+#X text 225 39 "draw_dot FILE [OPTIONS]" : save a 'dot' graph specification
+;
+#X text 235 97 OPTIONS:;
+#X text 318 113 title TITLE : graph title;
+#X text 318 168 width WIDTH : graph width (inches);
+#X text 248 127 ilabels ALPHABET_NAME : lower-label alphabet name;
+#X text 248 140 olabels ALPHABET_NAME : upper-label alphabet name;
+#X text 248 154 slabels ALPHABET_NAME : state-label alphabet name;
+#X text 304 180 height HEIGHT : graph height (inches);
+#X text 304 193 fontsize SIZE : font size (points?);
+#X text 304 206 fontname NAME : font name (?);
+#X text 304 219 portrait BOOL : draw in portrait mode? (default=no)
+;
+#X text 304 231 vertical BOOL : draw top-to-bottom? (default=no);
+#X text 297 244 nodesep INCHES : node-separation distance;
+#X text 297 257 ranksep INCHES : rank-separation distance;
+#X text 115 9 gfsm_automaton : draw;
+#X text 370 326 Bryan Jurish <moocow@ling.uni-potsdam.de>;
+#X msg 13 40 draw_dot fsm-help.dot;
+#X obj 14 311 shell;
+#X msg 14 291 dotty fsm-help.dot;
+#X text 235 291 ... try this if you have the "graphviz" package installed
+;
+#X connect 18 0 0 0;
+#X connect 20 0 19 0;
+#X restore 20 318 pd help-automaton-draw;
+#X text 239 401 gfsmutils(1);
+#X obj 265 344 gfsm_automaton fsm-help-2;
+#X text 248 303 PLACEHOLDERS:;
+#X obj 265 323 gfsm_automaton fsm-help;
+#X obj 265 251 gfsm_automaton fsm-help;
+#X connect 21 0 28 0;
+#X connect 28 0 14 0;
diff --git a/gfsm/src/gfsm_markov-help.pd b/gfsm/src/gfsm_markov-help.pd
new file mode 100644
index 0000000..8d7a3a2
--- /dev/null
+++ b/gfsm/src/gfsm_markov-help.pd
@@ -0,0 +1,68 @@
+#N canvas 39 25 680 536 10;
+#X text 150 -2 gfsm_markov : Markov chain using gfsm;
+#X text 15 41 INLETS:;
+#X text 28 56 1 - control messages;
+#X text 233 41 OUTLETS:;
+#X text 17 21 SYNTAX: gfsm_markov OBJNAME;
+#X text 365 24 REQUIRES:;
+#X obj 433 24 gfsm;
+#X obj 469 24 zexy;
+#X text 246 83 3 - bang when stuck;
+#X text 247 69 2 - upper side atoms on "next";
+#X text 247 55 1 - lower side atoms on "next";
+#X obj 39 494 print lo;
+#X obj 134 494 print hi;
+#X obj 230 494 print stuck;
+#X obj 39 473 gfsm_markov help-gfsm-markov;
+#X msg 48 175 load_bin help-gfsm_markov;
+#X msg 49 192 save-bin help-gfsm_markov;
+#X msg 39 125 load help-gfsm_markov;
+#X msg 40 142 save help-gfsm_markov;
+#X msg 55 250 set foo;
+#X msg 61 267 set;
+#X msg 60 298 add foo bar 0.42;
+#X msg 65 361 addi foo baz 1;
+#X msg 78 408 next \$1;
+#X floatatom 78 392 5 0 0 0 - - -;
+#X msg 78 428 next;
+#X msg 78 450 bang;
+#X msg 53 223 clear;
+#X text 273 126 load BASE : load text files BASE.lab and BASE.tfst
+;
+#X text 274 142 save BASE : save text files BASE.lab \, BASE.tfst;
+#X text 246 175 load_bin BASE : load files BASE.lab \, BASE.gfst;
+#X text 246 192 save_bin BASE : save files BASE.lab \, BASE.gfst;
+#X text 302 224 clear : clear underlying objects;
+#X text 281 250 set ATOM : set current state to ATOM;
+#X text 316 268 set : reset to initial (root) state;
+#X text 227 297 add A1 A2 WEIGHT : add WEIGHT to arc on atom-pair A1:A2
+;
+#X text 276 316 add A1 A2 : like "add A1 A2 1";
+#X msg 62 315 add foo baz;
+#X text 297 332 add A1 : like "add A1 0 1";
+#X text 219 361 addi A1 A2 WEIGHT : add WEIGHT to initial arc on A1:A2
+;
+#X text 273 408 next PROB : follow next arc with PROB hint-probability
+;
+#X text 308 429 next : follow next arc \, random probability;
+#X text 308 450 bang : alias for "next";
+#X text 375 516 Bryan Jurish <moocow@ling.uni-potsdam.de>;
+#X msg 65 332 add foo;
+#X connect 14 0 11 0;
+#X connect 14 1 12 0;
+#X connect 14 2 13 0;
+#X connect 15 0 14 0;
+#X connect 16 0 14 0;
+#X connect 17 0 14 0;
+#X connect 18 0 14 0;
+#X connect 19 0 14 0;
+#X connect 20 0 14 0;
+#X connect 21 0 14 0;
+#X connect 22 0 14 0;
+#X connect 23 0 14 0;
+#X connect 24 0 23 0;
+#X connect 25 0 14 0;
+#X connect 26 0 14 0;
+#X connect 27 0 14 0;
+#X connect 37 0 14 0;
+#X connect 44 0 14 0;
diff --git a/gfsm/src/gfsm_markov.pd b/gfsm/src/gfsm_markov.pd
new file mode 100644
index 0000000..ab7142d
--- /dev/null
+++ b/gfsm/src/gfsm_markov.pd
@@ -0,0 +1,414 @@
+#N canvas 386 0 450 300 10;
+#X text 85 2 gfsm_markov : Markov chain using gfsm;
+#X text 181 17 for details \, see:;
+#N canvas 266 0 499 471 gfsm_markov_doc 0;
+#X text 85 2 gfsm_markov : Markov chain using gfsm;
+#X text 15 67 INLETS:;
+#X text 28 84 1 - control messages;
+#X text 203 64 OUTLETS:;
+#X text 17 128 MESSAGES:;
+#X text 81 219 set ATOM : set current state to ATOM;
+#X text 116 231 set : reset to initial (root) state;
+#X text 107 441 bang : synonym for "next";
+#X text 16 24 SYNTAX: gfsm_markov OBJNAME;
+#X text 15 44 REQUIRES:;
+#X obj 83 44 gfsm;
+#X text 75 147 load BASE : load text files BASE.lab and BASE.tfst;
+#X text 75 159 save BASE : save text files BASE.lab \, BASE.tfst;
+#X text 47 182 load_bin BASE : load files BASE.lab \, BASE.gfst;
+#X text 47 194 save_bin BASE : save files BASE.lab \, BASE.gfst;
+#X obj 121 45 zexy;
+#X text 156 294 from current state \, and move to;
+#X text 23 281 add A1 A2 WEIGHT : add WEIGHT to arc on atom-pair A1:A2
+;
+#X text 73 411 next PROB : get next arc with PROB as nearest probability
+;
+#X text 107 427 next : get next arc with random probability;
+#X text 216 106 3 - bang when stuck;
+#X text 157 330 + WEIGHT defaults to 1;
+#X text 157 318 + A2 defaults to 0 (epsilon);
+#X text 157 378 + WEIGHT defaults to 1;
+#X text 157 366 + A2 defaults to 0 (epsilon);
+#X text 18 354 addi A1 A2 WEIGHT : add WEIGHT to initial arc on atoms
+A1:A2;
+#X text 156 305 (possibly new) state for atom A1;
+#X text 217 92 2 - upper side atoms on "next";
+#X text 217 78 1 - lower side atoms on "next";
+#X text 102 250 clear : clear underlying objects;
+#X restore 309 19 pd gfsm_markov_doc;
+#X obj 20 60 inlet;
+#X obj 22 261 outlet;
+#X obj 103 260 outlet;
+#N canvas 27 71 720 463 gfsm_markov_control_guts 0;
+#X obj 22 8 inlet;
+#X obj 450 32 print gfsm_markov_bad_message;
+#X obj 183 230 s \$0-load;
+#X obj 215 209 s \$0-save;
+#X obj 247 187 s \$0-load_bin;
+#X obj 280 164 s \$0-save_bin;
+#X obj 86 373 s \$0-set;
+#X obj 312 125 s \$0-clear;
+#X obj 118 337 s \$0-add;
+#X obj 22 409 s \$0-next;
+#X obj 303 99 s \$0-fsm;
+#X obj 335 78 s \$0-alph;
+#X obj 151 295 s \$0-addi;
+#X obj 415 79 s \$0-state-r;
+#X obj 22 28 route next bang set add addi load save load_bin save_bin
+clear fsm alph state add2;
+#X obj 449 122 s \$0-add2;
+#X connect 0 0 14 0;
+#X connect 14 0 9 0;
+#X connect 14 1 9 0;
+#X connect 14 2 6 0;
+#X connect 14 3 8 0;
+#X connect 14 4 12 0;
+#X connect 14 5 2 0;
+#X connect 14 6 3 0;
+#X connect 14 7 4 0;
+#X connect 14 8 5 0;
+#X connect 14 9 7 0;
+#X connect 14 10 10 0;
+#X connect 14 11 11 0;
+#X connect 14 12 13 0;
+#X connect 14 13 15 0;
+#X connect 14 14 1 0;
+#X restore 20 82 pd gfsm_markov_control_guts;
+#N canvas 0 252 310 205 gfsm_markov_fsm_guts 0;
+#X obj 40 121 gfsm_automaton \$1-fsm;
+#X obj 40 53 gfsm_alphabet \$1-alph;
+#X obj 40 100 r \$0-fsm;
+#X obj 40 33 r \$0-alph;
+#X connect 2 0 0 0;
+#X connect 3 0 1 0;
+#X restore 21 113 pd gfsm_markov_fsm_guts;
+#N canvas 114 67 710 486 gfsm_markov_io_guts 0;
+#X obj 21 87 symbol;
+#X msg 209 301 load \$1;
+#X obj 178 86 symbol;
+#X msg 556 308 save \$1;
+#X msg 21 215 load \$1;
+#X obj 367 85 symbol;
+#X obj 526 79 symbol;
+#X obj 21 20 r \$0-load;
+#X obj 367 22 r \$0-save;
+#X obj 526 26 r \$0-save_bin;
+#X obj 178 19 r \$0-load_bin;
+#X obj 21 110 t s s;
+#X obj 178 106 t s s;
+#X obj 367 107 t s s;
+#X obj 526 100 t s s;
+#X msg 179 215 load_bin \$1;
+#X msg 526 216 save_bin \$1;
+#X msg 367 215 save \$1;
+#X obj 21 193 makefilename %s.tfst;
+#X obj 178 192 makefilename %s.gfst;
+#X obj 367 193 makefilename %s.tfst;
+#X obj 526 193 makefilename %s.gfst;
+#X obj 556 286 makefilename %s.lab;
+#X obj 209 280 makefilename %s.lab;
+#X obj 179 434 s \$0-fsm;
+#X obj 367 429 s \$0-alph;
+#X connect 0 0 11 0;
+#X connect 1 0 25 0;
+#X connect 2 0 12 0;
+#X connect 3 0 25 0;
+#X connect 4 0 24 0;
+#X connect 5 0 13 0;
+#X connect 6 0 14 0;
+#X connect 7 0 0 0;
+#X connect 8 0 5 0;
+#X connect 9 0 6 0;
+#X connect 10 0 2 0;
+#X connect 11 0 18 0;
+#X connect 11 1 23 0;
+#X connect 12 0 19 0;
+#X connect 12 1 23 0;
+#X connect 13 0 20 0;
+#X connect 13 1 22 0;
+#X connect 14 0 21 0;
+#X connect 14 1 22 0;
+#X connect 15 0 24 0;
+#X connect 16 0 24 0;
+#X connect 17 0 24 0;
+#X connect 18 0 4 0;
+#X connect 19 0 15 0;
+#X connect 20 0 17 0;
+#X connect 21 0 16 0;
+#X connect 22 0 3 0;
+#X connect 23 0 1 0;
+#X restore 21 138 pd gfsm_markov_io_guts;
+#N canvas 150 351 551 242 gfsm_markov_set_guts 0;
+#X obj 32 18 r \$0-set;
+#X obj 32 40 route bang;
+#X obj 97 133 gfsm_alphabet \$1-alph;
+#X obj 97 61 route float list;
+#X msg 97 110 atom2char! \$1;
+#X obj 204 83 symbol;
+#X msg 97 156 set \$1;
+#X obj 97 178 s \$0-state;
+#X msg 32 83 0;
+#X obj 345 15 r \$0-clear;
+#X obj 389 78 s \$0-alph;
+#X obj 367 126 s \$0-fsm;
+#X msg 367 105 clear \, root 0;
+#X msg 389 57 clear \, atom2char! 0;
+#X obj 345 35 t b b b;
+#X msg 345 150 set 0;
+#X obj 346 170 s \$0-state;
+#X connect 0 0 1 0;
+#X connect 1 0 8 0;
+#X connect 1 1 3 0;
+#X connect 2 0 6 0;
+#X connect 3 0 4 0;
+#X connect 3 1 4 0;
+#X connect 3 2 5 0;
+#X connect 4 0 2 0;
+#X connect 5 0 4 0;
+#X connect 6 0 7 0;
+#X connect 8 0 4 0;
+#X connect 9 0 14 0;
+#X connect 12 0 11 0;
+#X connect 13 0 10 0;
+#X connect 14 0 15 0;
+#X connect 14 1 12 0;
+#X connect 14 2 13 0;
+#X connect 15 0 16 0;
+#X restore 21 162 pd gfsm_markov_set_guts;
+#X obj 261 60 loadbang;
+#N canvas 142 144 416 223 gfsm_markov_init_guts 0;
+#X obj 15 9 inlet;
+#X msg 15 97 char2atom! 0;
+#X obj 15 118 s \$0-alph;
+#X obj 15 66 t b b;
+#X obj 74 10 r \$0-loadbang;
+#X obj 179 124 gfsm_automaton \$1-fsm;
+#X msg 206 97 root;
+#X obj 179 145 route root;
+#X obj 179 168 route bang;
+#X msg 155 98 root 0;
+#X connect 0 0 3 0;
+#X connect 1 0 2 0;
+#X connect 3 0 1 0;
+#X connect 3 1 6 0;
+#X connect 4 0 3 0;
+#X connect 5 0 7 0;
+#X connect 6 0 5 0;
+#X connect 7 0 8 0;
+#X connect 8 0 9 0;
+#X connect 9 0 5 0;
+#X restore 261 81 pd gfsm_markov_init_guts;
+#N canvas 66 12 666 508 gfsm_markov_add_guts 0;
+#X obj 28 231 gfsm_alphabet \$1-alph;
+#X obj 28 167 route float list;
+#X msg 28 211 atom2char! \$1;
+#X obj 95 190 symbol;
+#X obj 58 426 gfsm_state \$1-fsm;
+#X obj 71 402 r \$0-state;
+#X msg 508 322 set \$1;
+#X obj 508 428 s \$0-state;
+#X obj 28 12 r \$0-add1;
+#X obj 121 12 r \$0-add;
+#X obj 123 320 1;
+#X obj 28 260 t f f;
+#X obj 413 14 r \$0-addi1;
+#X obj 492 14 r \$0-addi;
+#X obj 443 89 gfsm_automaton \$1-fsm;
+#X msg 443 67 root;
+#X obj 413 39 t a b;
+#X obj 443 110 route root;
+#X obj 443 132 route bang;
+#X msg 481 67 root 0;
+#X msg 58 372 add_weight \$1 \$1 \$2 \$3;
+#X obj 28 89 t a b b;
+#X obj 58 347 pack 0 0 0;
+#X obj 90 320 0;
+#X text 139 347 <-- Q=LO HI WEIGHT;
+#X obj 28 112 niagara 1;
+#X obj 231 129 niagara 1;
+#X obj 231 236 gfsm_alphabet \$1-alph;
+#X obj 231 172 route float list;
+#X msg 231 216 atom2char! \$1;
+#X obj 298 195 symbol;
+#X obj 204 12 r \$0-add2;
+#X obj 28 42 t a b;
+#X obj 205 35 t a b;
+#X obj 446 297 spigot;
+#X obj 454 273 0;
+#X obj 479 273 1;
+#X connect 0 0 11 0;
+#X connect 1 0 2 0;
+#X connect 1 1 2 0;
+#X connect 1 2 3 0;
+#X connect 2 0 0 0;
+#X connect 3 0 2 0;
+#X connect 5 0 4 0;
+#X connect 6 0 7 0;
+#X connect 8 0 32 0;
+#X connect 9 0 32 0;
+#X connect 10 0 22 2;
+#X connect 11 0 34 0;
+#X connect 11 1 22 0;
+#X connect 12 0 16 0;
+#X connect 13 0 16 0;
+#X connect 14 0 17 0;
+#X connect 15 0 14 0;
+#X connect 16 0 21 0;
+#X connect 16 1 15 0;
+#X connect 17 0 18 0;
+#X connect 18 0 19 0;
+#X connect 18 1 6 0;
+#X connect 19 0 14 0;
+#X connect 20 0 4 0;
+#X connect 21 0 25 0;
+#X connect 21 1 23 0;
+#X connect 21 2 10 0;
+#X connect 22 0 20 0;
+#X connect 23 0 22 1;
+#X connect 25 0 1 0;
+#X connect 25 1 26 0;
+#X connect 26 0 28 0;
+#X connect 26 1 22 2;
+#X connect 27 0 22 1;
+#X connect 28 0 29 0;
+#X connect 28 1 29 0;
+#X connect 28 2 30 0;
+#X connect 29 0 27 0;
+#X connect 30 0 29 0;
+#X connect 31 0 33 0;
+#X connect 32 0 21 0;
+#X connect 32 1 36 0;
+#X connect 33 0 21 0;
+#X connect 33 1 35 0;
+#X connect 34 0 6 0;
+#X connect 35 0 34 1;
+#X connect 36 0 34 1;
+#X restore 21 186 pd gfsm_markov_add_guts;
+#N canvas 27 0 738 524 gfsm_markov_next_guts 0;
+#X obj 86 25 r \$0-next;
+#X obj 243 464 outlet;
+#X obj 86 47 route bang;
+#X obj 151 158 * -1;
+#X obj 151 136 * 1;
+#X obj 559 376 t b b;
+#N canvas 75 18 312 424 weight_sum 0;
+#X obj 24 9 inlet;
+#X msg 24 114 arc_next;
+#X obj 24 319 f 0;
+#X obj 199 92 0;
+#X obj 89 238 unpack 0 0 0 0;
+#X obj 183 262 + 0;
+#X obj 88 263 t f f;
+#X obj 24 350 outlet;
+#X obj 60 146 r \$0-state;
+#X obj 24 90 until;
+#X obj 24 214 route bang;
+#X obj 24 235 t b b;
+#X obj 24 192 route arc_next;
+#X obj 24 43 t b b b b;
+#X msg 91 114 arc_reset;
+#X obj 24 167 gfsm_state \$1-fsm 0;
+#X connect 0 0 13 0;
+#X connect 1 0 15 0;
+#X connect 2 0 7 0;
+#X connect 3 0 5 1;
+#X connect 4 3 5 0;
+#X connect 5 0 6 0;
+#X connect 6 0 5 1;
+#X connect 6 1 2 1;
+#X connect 8 0 15 0;
+#X connect 9 0 1 0;
+#X connect 10 0 11 0;
+#X connect 10 1 4 0;
+#X connect 11 0 2 0;
+#X connect 11 1 9 1;
+#X connect 12 0 10 0;
+#X connect 13 0 9 0;
+#X connect 13 1 3 0;
+#X connect 13 2 14 0;
+#X connect 13 3 9 1;
+#X connect 14 0 15 0;
+#X connect 15 0 12 0;
+#X restore 167 115 pd weight_sum;
+#X obj 25 95 random 131072;
+#X obj 25 116 / 131072;
+#X obj 86 69 t b b b;
+#X obj 151 69 t f b b;
+#X msg 559 227 arc_next;
+#X obj 594 269 r \$0-state;
+#X obj 559 205 until;
+#X obj 559 349 route bang;
+#X obj 559 326 route arc_next;
+#X msg 625 226 arc_reset;
+#X obj 151 180 t b b f;
+#X obj 405 461 outlet;
+#X obj 101 429 gfsm_alphabet \$1-alph;
+#X msg 101 407 char2atom! \$1;
+#X obj 179 296 moses 0;
+#X obj 179 251 + 0;
+#X obj 179 274 t f f;
+#X obj 86 225 unpack 0 0 0 0;
+#X obj 18 386 f 0;
+#X msg 18 411 set \$1;
+#X obj 18 432 s \$0-state;
+#X obj 559 292 gfsm_state \$1-fsm 0;
+#X obj 559 457 outlet;
+#X obj 263 428 gfsm_alphabet \$1-alph;
+#X msg 263 406 char2atom! \$1;
+#X obj 263 384 f 0;
+#X obj 101 385 f 0;
+#X obj 225 316 t b b b b;
+#X connect 0 0 2 0;
+#X connect 2 0 9 0;
+#X connect 2 1 10 0;
+#X connect 3 0 17 0;
+#X connect 4 0 3 0;
+#X connect 5 0 29 0;
+#X connect 5 1 13 1;
+#X connect 6 0 4 1;
+#X connect 7 0 8 0;
+#X connect 8 0 4 0;
+#X connect 9 0 7 0;
+#X connect 9 1 6 0;
+#X connect 9 2 13 1;
+#X connect 10 0 4 0;
+#X connect 10 1 6 0;
+#X connect 10 2 13 1;
+#X connect 11 0 28 0;
+#X connect 12 0 28 0;
+#X connect 13 0 11 0;
+#X connect 14 0 5 0;
+#X connect 14 1 24 0;
+#X connect 15 0 14 0;
+#X connect 16 0 28 0;
+#X connect 17 0 13 0;
+#X connect 17 1 16 0;
+#X connect 17 2 22 1;
+#X connect 19 1 1 0;
+#X connect 20 0 19 0;
+#X connect 21 1 34 0;
+#X connect 22 0 23 0;
+#X connect 23 0 21 0;
+#X connect 23 1 22 1;
+#X connect 24 0 25 1;
+#X connect 24 1 33 1;
+#X connect 24 2 32 1;
+#X connect 24 3 22 0;
+#X connect 25 0 26 0;
+#X connect 26 0 27 0;
+#X connect 28 0 15 0;
+#X connect 30 1 18 0;
+#X connect 31 0 30 0;
+#X connect 32 0 31 0;
+#X connect 33 0 20 0;
+#X connect 34 0 25 0;
+#X connect 34 1 33 0;
+#X connect 34 2 32 0;
+#X connect 34 3 13 1;
+#X restore 22 216 pd gfsm_markov_next_guts;
+#X obj 185 260 outlet;
+#X connect 3 0 6 0;
+#X connect 10 0 11 0;
+#X connect 13 0 4 0;
+#X connect 13 1 5 0;
+#X connect 13 2 14 0;
diff --git a/gfsm/src/gfsm_state-help.pd b/gfsm/src/gfsm_state-help.pd
new file mode 100644
index 0000000..e26ace2
--- /dev/null
+++ b/gfsm/src/gfsm_state-help.pd
@@ -0,0 +1,55 @@
+#N canvas 232 0 651 599 10;
+#X obj 85 569 gfsm;
+#X text 15 569 SEE ALSO:;
+#X text 41 6 gfsm_state : position "pointer" for finite-state automata
+;
+#X text 267 563 Bryan Jurish <moocow@ling.uni-potsdam.de>;
+#X text 17 79 INLETS:;
+#X text 35 93 1 - control messages;
+#X text 255 82 OUTLETS:;
+#X text 271 95 1 - value outlet;
+#X text 18 30 SYNTAX: gfsm_state [FSM_NAME [STATE_ID]];
+#X text 52 47 FSM_NAME - symbolic name of a gfsm_automaton;
+#X text 52 61 STATE_ID - numeric Id of the target state;
+#X obj 26 531 print gfsm-state-out;
+#X msg 44 182 id;
+#X text 164 185 "id" : get current state Id;
+#X text 135 205 "set ID" : set current state Id;
+#X msg 50 205 set 0;
+#X msg 26 127 automaton;
+#X msg 31 149 automaton fsm-help;
+#X text 197 128 "automaton" : use an object-local machine;
+#X text 163 151 "automaton NAME" : use a shared machine named NAME
+;
+#X msg 58 239 degree;
+#X text 137 240 "degree" : get number of outgoing arcs (linear time)
+;
+#X msg 58 295 arc_first;
+#X msg 58 317 arc_next;
+#X msg 59 382 arc_reset;
+#X obj 26 508 gfsm_state fsm-help 0;
+#X text 229 398 arcs are output as a list:;
+#X text 277 414 NEXT_STATEID LO HI WEIGHT;
+#X text 306 359 (negative labels are ignored);
+#X msg 58 345 arc_seek 202 -1;
+#X text 208 294 "arc_first" : get first outgoing arc;
+#X text 214 318 "arc_next" : get next available outgoing arc (maybe
+first);
+#X text 173 344 "arc_seek LO HI" : get next arc with labels LO:HI;
+#X text 207 383 "arc_reset" : close internal arc iterator;
+#X msg 54 447 add_weight 1 -1 101 0.9;
+#X text 233 450 "add_weight ID LO HI W" : add W to 1st arc to state
+ID;
+#X text 416 463 with labels LO:HI;
+#X text 271 479 (implicitly resets arc iterator);
+#X connect 12 0 25 0;
+#X connect 15 0 25 0;
+#X connect 16 0 25 0;
+#X connect 17 0 25 0;
+#X connect 20 0 25 0;
+#X connect 22 0 25 0;
+#X connect 23 0 25 0;
+#X connect 24 0 25 0;
+#X connect 25 0 11 0;
+#X connect 29 0 25 0;
+#X connect 34 0 25 0;
diff --git a/gfsm/src/lkpin.tfst b/gfsm/src/lkpin.tfst
new file mode 100644
index 0000000..a9adbc9
--- /dev/null
+++ b/gfsm/src/lkpin.tfst
@@ -0,0 +1,4 @@
+0 1 2 2
+1 2 2 2
+2 3 3 3
+3
diff --git a/gfsm/src/lkptest.tfst b/gfsm/src/lkptest.tfst
new file mode 100644
index 0000000..11f371e
--- /dev/null
+++ b/gfsm/src/lkptest.tfst
@@ -0,0 +1,8 @@
+0 0 1 2 1
+0 0 2 3 1
+0 0 3 1 1
+0 1 2 2 1
+0 0
+1 2 2 2 1
+2 3 3 3 1
+3 0
diff --git a/gfsm/src/pd_algebra.c b/gfsm/src/pd_algebra.c
new file mode 100644
index 0000000..eecde1e
--- /dev/null
+++ b/gfsm/src/pd_algebra.c
@@ -0,0 +1,299 @@
+/*=============================================================================*\
+ * File: pd_algebra.c
+ * Author: Bryan Jurish <moocow@ling.uni-potsdam.de>
+ * Description: finite state automata for Pd
+ *
+ * Copyright (c) 2004 Bryan Jurish.
+ *
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * See file LICENSE for further informations on licensing terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *=============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <pd_gfsm.h>
+#include <pd_automaton.h>
+#include <m_pd.h>
+
+/*--------------------------------------------------------------------
+ * DEBUG
+ *--------------------------------------------------------------------*/
+//#define PDFSM_DEBUG 1
+
+/*=====================================================================
+ * Structures and Types
+ *=====================================================================*/
+//(none)
+
+/*=====================================================================
+ * pd_gfsm_automaton_obj: Utilities
+ *=====================================================================*/
+//(none)
+
+/*=====================================================================
+ * pd_gfsm_automaton_obj: Algebra
+ *=====================================================================*/
+
+/*--------------------------------------------------------------------
+ * complement
+ */
+static void pd_gfsm_automaton_complement(t_pd_gfsm_automaton_obj *x)
+{
+ gfsm_automaton_complement(x->x_automaton_pd->x_automaton);
+ pd_gfsm_automaton_obj_outlet_bang(x, gensym("complement"));
+}
+
+/*--------------------------------------------------------------------
+ * closure
+ */
+static void pd_gfsm_automaton_closure(t_pd_gfsm_automaton_obj *x, t_float nf)
+{
+ gfsm_automaton_n_closure(x->x_automaton_pd->x_automaton, (guint)nf);
+ pd_gfsm_automaton_obj_outlet_float(x, gensym("closure"), nf);
+}
+
+/*--------------------------------------------------------------------
+ * compose
+ */
+static void pd_gfsm_automaton_compose(t_pd_gfsm_automaton_obj *x, t_symbol *fsm2_name)
+{
+ t_pd_gfsm_automaton_pd *fsm2_pd = pd_gfsm_automaton_pd_find(fsm2_name);
+ if (!fsm2_pd) {
+ error("pd_gfsm_automaton_compose(): no fsm named '%s'", fsm2_name->s_name);
+ return;
+ } else {
+ ++fsm2_pd->x_refcnt;
+ gfsm_automaton_compose(x->x_automaton_pd->x_automaton, fsm2_pd->x_automaton);
+ pd_gfsm_automaton_pd_release(fsm2_pd);
+ }
+ pd_gfsm_automaton_obj_outlet_symbol(x, gensym("compose"), fsm2_name);
+}
+
+/*--------------------------------------------------------------------
+ * concat
+ */
+static void pd_gfsm_automaton_concat(t_pd_gfsm_automaton_obj *x, t_symbol *fsm2_name)
+{
+ t_pd_gfsm_automaton_pd *fsm2_pd = pd_gfsm_automaton_pd_find(fsm2_name);
+ if (!fsm2_pd) {
+ error("pd_gfsm_automaton_concat(): no fsm named '%s'", fsm2_name->s_name);
+ return;
+ } else {
+ ++fsm2_pd->x_refcnt;
+ gfsm_automaton_concat(x->x_automaton_pd->x_automaton, fsm2_pd->x_automaton);
+ pd_gfsm_automaton_pd_release(fsm2_pd);
+ }
+ pd_gfsm_automaton_obj_outlet_symbol(x, gensym("concat"), fsm2_name);
+}
+
+/*--------------------------------------------------------------------
+ * determinize
+ */
+static void pd_gfsm_automaton_determinize(t_pd_gfsm_automaton_obj *x)
+{
+ gfsm_automaton_determinize(x->x_automaton_pd->x_automaton);
+ pd_gfsm_automaton_obj_outlet_bang(x, gensym("determinize"));
+}
+
+/*--------------------------------------------------------------------
+ * difference
+ */
+static void pd_gfsm_automaton_difference(t_pd_gfsm_automaton_obj *x, t_symbol *fsm2_name)
+{
+ t_pd_gfsm_automaton_pd *fsm2_pd = pd_gfsm_automaton_pd_find(fsm2_name);
+ if (!fsm2_pd) {
+ error("pd_gfsm_automaton_difference(): no fsm named '%s'", fsm2_name->s_name);
+ return;
+ } else {
+ ++fsm2_pd->x_refcnt;
+ gfsm_automaton_difference(x->x_automaton_pd->x_automaton, fsm2_pd->x_automaton);
+ pd_gfsm_automaton_pd_release(fsm2_pd);
+ }
+ pd_gfsm_automaton_obj_outlet_symbol(x, gensym("difference"), fsm2_name);
+}
+
+/*--------------------------------------------------------------------
+ * intersection
+ */
+static void pd_gfsm_automaton_intersect(t_pd_gfsm_automaton_obj *x, t_symbol *fsm2_name)
+{
+ t_pd_gfsm_automaton_pd *fsm2_pd = pd_gfsm_automaton_pd_find(fsm2_name);
+ if (!fsm2_pd) {
+ error("pd_gfsm_automaton_intersect(): no fsm named '%s'", fsm2_name->s_name);
+ return;
+ } else {
+ ++fsm2_pd->x_refcnt;
+ gfsm_automaton_intersect(x->x_automaton_pd->x_automaton, fsm2_pd->x_automaton);
+ pd_gfsm_automaton_pd_release(fsm2_pd);
+ }
+ pd_gfsm_automaton_obj_outlet_symbol(x, gensym("intersect"), fsm2_name);
+}
+
+/*--------------------------------------------------------------------
+ * invert
+ */
+static void pd_gfsm_automaton_invert(t_pd_gfsm_automaton_obj *x)
+{
+ gfsm_automaton_invert(x->x_automaton_pd->x_automaton);
+ pd_gfsm_automaton_obj_outlet_bang(x, gensym("invert"));
+}
+
+/*--------------------------------------------------------------------
+ * product
+ */
+static void pd_gfsm_automaton_product(t_pd_gfsm_automaton_obj *x, t_symbol *fsm2_name)
+{
+ t_pd_gfsm_automaton_pd *fsm2_pd = pd_gfsm_automaton_pd_find(fsm2_name);
+ if (!fsm2_pd) {
+ error("pd_gfsm_automaton_product(): no fsm named '%s'", fsm2_name->s_name);
+ return;
+ } else {
+ ++fsm2_pd->x_refcnt;
+ gfsm_automaton_product(x->x_automaton_pd->x_automaton, fsm2_pd->x_automaton);
+ pd_gfsm_automaton_pd_release(fsm2_pd);
+ }
+ pd_gfsm_automaton_obj_outlet_symbol(x, gensym("intersect"), fsm2_name);
+}
+
+/*--------------------------------------------------------------------
+ * project
+ */
+static void pd_gfsm_automaton_project(t_pd_gfsm_automaton_obj *x, t_float which)
+{
+ gfsm_automaton_project(x->x_automaton_pd->x_automaton,
+ (which==0 ? gfsmLSLower : gfsmLSUpper));
+ pd_gfsm_automaton_obj_outlet_float(x, gensym("project"), which);
+}
+
+/*--------------------------------------------------------------------
+ * prune
+ */
+static void pd_gfsm_automaton_connect(t_pd_gfsm_automaton_obj *x)
+{
+ gfsm_automaton_connect(x->x_automaton_pd->x_automaton);
+ pd_gfsm_automaton_obj_outlet_bang(x, gensym("connect"));
+}
+
+/*--------------------------------------------------------------------
+ * renumber
+ */
+static void pd_gfsm_automaton_renumber(t_pd_gfsm_automaton_obj *x)
+{
+ gfsm_automaton_renumber_states(x->x_automaton_pd->x_automaton);
+ pd_gfsm_automaton_obj_outlet_bang(x, gensym("renumber"));
+}
+
+
+/*--------------------------------------------------------------------
+ * reverse
+ */
+static void pd_gfsm_automaton_reverse(t_pd_gfsm_automaton_obj *x)
+{
+ gfsm_automaton_reverse(x->x_automaton_pd->x_automaton);
+ pd_gfsm_automaton_obj_outlet_bang(x, gensym("reverse"));
+}
+
+/*--------------------------------------------------------------------
+ * rmepsilon
+ */
+static void pd_gfsm_automaton_rmepsilon(t_pd_gfsm_automaton_obj *x)
+{
+ gfsm_automaton_rmepsilon(x->x_automaton_pd->x_automaton);
+ pd_gfsm_automaton_obj_outlet_bang(x, gensym("rmepsilon"));
+}
+
+/*--------------------------------------------------------------------
+ * union
+ */
+static void pd_gfsm_automaton_union(t_pd_gfsm_automaton_obj *x, t_symbol *fsm2_name)
+{
+ t_pd_gfsm_automaton_pd *fsm2_pd = pd_gfsm_automaton_pd_find(fsm2_name);
+ if (!fsm2_pd) {
+ error("pd_gfsm_automaton_union(): no fsm named '%s'", fsm2_name->s_name);
+ return;
+ }
+ else if (fsm2_pd != x->x_automaton_pd) {
+ ++fsm2_pd->x_refcnt;
+ gfsm_automaton_union(x->x_automaton_pd->x_automaton, fsm2_pd->x_automaton);
+ pd_gfsm_automaton_pd_release(fsm2_pd);
+ }
+ pd_gfsm_automaton_obj_outlet_symbol(x, gensym("union"), fsm2_name);
+}
+
+
+/*=====================================================================
+ * setup
+ *=====================================================================*/
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: setup()
+ */
+void pd_gfsm_algebra_setup(t_class *automaton_class)
+{
+ //-- methods: algebra
+ class_addmethod(automaton_class, (t_method)pd_gfsm_automaton_complement,
+ gensym("complement"), A_NULL);
+
+ class_addmethod(automaton_class, (t_method)pd_gfsm_automaton_closure,
+ gensym("closure"), A_DEFFLOAT, A_NULL);
+
+ class_addmethod(automaton_class, (t_method)pd_gfsm_automaton_compose,
+ gensym("compose"), A_SYMBOL, A_NULL);
+
+ class_addmethod(automaton_class, (t_method)pd_gfsm_automaton_concat,
+ gensym("concat"), A_SYMBOL, A_NULL);
+
+ class_addmethod(automaton_class, (t_method)pd_gfsm_automaton_determinize,
+ gensym("determinize"), A_NULL);
+
+ class_addmethod(automaton_class, (t_method)pd_gfsm_automaton_difference,
+ gensym("difference"), A_SYMBOL, A_NULL);
+
+ class_addmethod(automaton_class, (t_method)pd_gfsm_automaton_intersect,
+ gensym("intersect"), A_SYMBOL, A_NULL);
+
+ class_addmethod(automaton_class, (t_method)pd_gfsm_automaton_invert,
+ gensym("invert"), A_NULL);
+
+ class_addmethod(automaton_class, (t_method)pd_gfsm_automaton_product,
+ gensym("product"), A_SYMBOL, A_NULL);
+
+ class_addmethod(automaton_class, (t_method)pd_gfsm_automaton_project,
+ gensym("project"), A_DEFFLOAT, A_NULL);
+
+ class_addmethod(automaton_class, (t_method)pd_gfsm_automaton_connect,
+ gensym("connect"), A_NULL);
+ class_addmethod(automaton_class, (t_method)pd_gfsm_automaton_connect,
+ gensym("prune"), A_NULL); //-- backwards-compatible alias
+
+
+ class_addmethod(automaton_class, (t_method)pd_gfsm_automaton_renumber,
+ gensym("renumber"), A_NULL);
+
+ class_addmethod(automaton_class, (t_method)pd_gfsm_automaton_reverse,
+ gensym("reverse"), A_NULL);
+
+ class_addmethod(automaton_class, (t_method)pd_gfsm_automaton_rmepsilon,
+ gensym("rmepsilon"), A_NULL);
+
+ class_addmethod(automaton_class, (t_method)pd_gfsm_automaton_union,
+ gensym("union"), A_SYMBOL, A_NULL);
+}
diff --git a/gfsm/src/pd_alphabet.c b/gfsm/src/pd_alphabet.c
new file mode 100644
index 0000000..480a74a
--- /dev/null
+++ b/gfsm/src/pd_alphabet.c
@@ -0,0 +1,494 @@
+/*=============================================================================*\
+ * File: pd_alphabet.c
+ * Author: Bryan Jurish <moocow@ling.uni-potsdam.de>
+ * Description: finite state automata for Pd: alphabet
+ *
+ * Copyright (c) 2004 Bryan Jurish.
+ *
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * See file LICENSE for further informations on licensing terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *=============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <pd_alphabet.h>
+#include <pd_io.h>
+#include <string.h>
+
+/*=====================================================================
+ * DEBUG
+ *=====================================================================*/
+//#define ALPHABET_DEBUG
+
+/*=====================================================================
+ * Pd Constants
+ *=====================================================================*/
+static t_class *pd_gfsm_alphabet_pd_class;
+static t_class *pd_gfsm_alphabet_obj_class;
+
+/*=====================================================================
+ * pd_gfsm_alphabet_pd: Methods
+ *=====================================================================*/
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_pd: new
+ */
+static void *pd_gfsm_alphabet_pd_new(t_symbol *name)
+{
+ t_pd_gfsm_alphabet_pd *x = (t_pd_gfsm_alphabet_pd *)pd_new(pd_gfsm_alphabet_pd_class);
+
+#ifdef ALPHABET_DEBUG
+ post("pd_gfsm_alphabet_pd_new() called ; name=%s ; x=%p",
+ (name ? name->s_name : "(null)"),
+ x);
+#endif
+
+ //-- defaults
+ x->x_refcnt = 0;
+ x->x_name = name;
+ x->x_alphabet = (gfsmAlphabet*)gfsm_pd_atom_alphabet_new();
+
+ //-- bindings
+ if (name != &s_) pd_bind((t_pd*)x, name);
+
+ return (void *)x;
+}
+
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_pd: free
+ */
+static void pd_gfsm_alphabet_pd_free(t_pd_gfsm_alphabet_pd *x)
+{
+#ifdef ALPHABET_DEBUG
+ post("pd_gfsm_alphabet_pd_free() called ; x=%p", x);
+#endif
+
+ if (x->x_alphabet) gfsm_pd_atom_alphabet_free((gfsmPdAtomAlphabet*)(x->x_alphabet));
+
+ /* unbind the symbol of the name of hashtable in pd's global namespace */
+ if (x->x_name != &s_) pd_unbind((t_pd*)x, x->x_name);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_pd: find
+ */
+t_pd_gfsm_alphabet_pd *pd_gfsm_alphabet_pd_find(t_symbol *name)
+{
+ if (name != &s_)
+ return (t_pd_gfsm_alphabet_pd*)pd_findbyclass(name,pd_gfsm_alphabet_pd_class);
+ return NULL;
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_pd: get
+ */
+t_pd_gfsm_alphabet_pd *pd_gfsm_alphabet_pd_get(t_symbol *name)
+{
+ t_pd_gfsm_alphabet_pd *x = pd_gfsm_alphabet_pd_find(name);
+ if (!x) {
+ x = (t_pd_gfsm_alphabet_pd*)pd_gfsm_alphabet_pd_new(name);
+ x->x_refcnt = 0;
+ }
+ return x;
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_pd: release
+ */
+void pd_gfsm_alphabet_pd_release(t_pd_gfsm_alphabet_pd *x)
+{
+ if (x) {
+ if (x->x_refcnt) --x->x_refcnt;
+ if (!x->x_refcnt) pd_gfsm_alphabet_pd_free(x);
+ }
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_pd: setup
+ */
+void pd_gfsm_alphabet_pd_setup(void)
+{
+ //-- class
+ pd_gfsm_alphabet_pd_class = class_new(gensym("gfsm_alphabet_pd"),
+ (t_newmethod)pd_gfsm_alphabet_pd_new,
+ (t_method)pd_gfsm_alphabet_pd_free,
+ sizeof(t_pd_gfsm_alphabet_pd),
+ CLASS_PD,
+ A_DEFSYM,
+ A_NULL);
+}
+
+
+/*=====================================================================
+ * pd_gfsm_alphabet: Methods
+ *=====================================================================*/
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_obj: new
+ */
+static void *pd_gfsm_alphabet_obj_new(t_symbol *name)
+{
+ t_pd_gfsm_alphabet_obj *x = (t_pd_gfsm_alphabet_obj *)pd_new(pd_gfsm_alphabet_obj_class);
+
+#ifdef ALPHABET_DEBUG
+ post("pd_gfsm_alphabet_obj_new() called: name=%s ; x=%p",
+ (name ? name->s_name : "(null)"),
+ x);
+#endif
+
+ //-- defaults
+ x->x_alphabet_pd = NULL;
+
+ //-- bindings
+ x->x_alphabet_pd = pd_gfsm_alphabet_pd_get(name);
+ x->x_alphabet_pd->x_refcnt++;
+
+ //-- outlets
+ x->x_labout = outlet_new(&x->x_obj, &s_float); //-- label / "char" outlet
+ x->x_keyout = outlet_new(&x->x_obj, &s_anything); //-- atom outlet
+
+ return (void *)x;
+}
+
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_obj: free
+ */
+static void pd_gfsm_alphabet_obj_free(t_pd_gfsm_alphabet_obj *x)
+{
+#ifdef ALPHABET_DEBUG
+ post("pd_gfsm_alphabet_obj_free() called: x=%p", x);
+#endif
+
+ pd_gfsm_alphabet_pd_release(x->x_alphabet_pd);
+
+ //-- do we need to do this?
+ outlet_free(x->x_labout);
+ outlet_free(x->x_keyout);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_obj: set
+ */
+static void pd_gfsm_alphabet_obj_alphabet(t_pd_gfsm_alphabet_obj *x, t_symbol *name)
+{
+#ifdef ALPHABET_DEBUG
+ post("pd_gfsm_alphabet_obj_alphabet() called ; oldname=%p=%s ; newname=%p=%s",
+ x->x_alphabet_pd->x_name, x->x_alphabet_pd->x_name->s_name, name, name->s_name);
+#endif
+ if (name == x->x_alphabet_pd->x_name) return;
+ pd_gfsm_alphabet_pd_release(x->x_alphabet_pd);
+
+ x->x_alphabet_pd = pd_gfsm_alphabet_pd_get(name);
+ ++x->x_alphabet_pd->x_refcnt;
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_obj: load
+ */
+static void pd_gfsm_alphabet_obj_load(t_pd_gfsm_alphabet_obj *x, t_symbol *s)
+{
+ gfsmError *errp = NULL;
+ gfsm_alphabet_load_filename(x->x_alphabet_pd->x_alphabet, s->s_name, &errp);
+ if (errp != NULL) {
+ error("gfsm_alphabet: load %s: %s", s->s_name, errp->message);
+ g_error_free(errp);
+ }
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_obj: print
+ */
+static void pd_gfsm_alphabet_obj_print(t_pd_gfsm_alphabet_obj *x)
+{
+ gfsmError *errp = NULL;
+ gfsmIOHandle *ioh = pd_gfsm_console_handle_new();
+ gfsm_alphabet_save_handle(x->x_alphabet_pd->x_alphabet, ioh, &errp);
+ if (errp != NULL) {
+ error("gfsm_alphabet: print: %s", errp->message);
+ g_error_free(errp);
+ }
+ pd_gfsm_console_handle_free(ioh);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_obj: save
+ */
+static void pd_gfsm_alphabet_obj_save(t_pd_gfsm_alphabet_obj *x, t_symbol *s)
+{
+ gfsmError *errp = NULL;
+ gfsm_alphabet_save_filename(x->x_alphabet_pd->x_alphabet, s->s_name, &errp);
+ if (errp != NULL) {
+ error("gfsm_alphabet: save %s: %s", s->s_name, errp->message);
+ g_error_free(errp);
+ }
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_obj: clear
+ */
+static void pd_gfsm_alphabet_obj_clear(t_pd_gfsm_alphabet_obj *x)
+{
+ gfsm_alphabet_clear(x->x_alphabet_pd->x_alphabet);
+}
+
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_obj: outlet_pair
+ */
+static void pd_gfsm_alphabet_obj_outlet_pair(t_pd_gfsm_alphabet_obj *x, t_float lab, t_atom *a)
+{
+ if (a) {
+ switch (a->a_type) {
+ case A_SYMBOL:
+ outlet_symbol(x->x_keyout, a->a_w.w_symbol);
+ break;
+ case A_FLOAT:
+ outlet_float(x->x_keyout, a->a_w.w_float);
+ break;
+ default:
+ outlet_symbol(x->x_keyout, atom_getsymbol(a));
+ break;
+ }
+ } else {
+ outlet_bang(x->x_keyout);
+ }
+
+ if (lab != gfsmNoLabel) outlet_float(x->x_obj.ob_outlet, lab);
+ else outlet_bang(x->x_obj.ob_outlet);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_obj: insert
+ */
+static void pd_gfsm_alphabet_obj_insert(t_pd_gfsm_alphabet_obj *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc < 1) {
+ error("pd_gfsm_alphabet_obj_insert(): no atom to insert?");
+ return;
+ }
+ t_float labf = argc > 1 ? atom_getfloat(argv+1) : (t_float)gfsmNoLabel;
+
+ gfsm_alphabet_get_full(x->x_alphabet_pd->x_alphabet, argv, (gfsmLabelVal)labf);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_obj: atom2label
+ */
+static void pd_gfsm_alphabet_obj_atom2label(t_pd_gfsm_alphabet_obj *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc < 1) {
+ error("pd_gfsm_alphabet_obj_atom2label(): no arguments?");
+ return;
+ }
+ t_float labf = (t_float)(gfsm_alphabet_find_label(x->x_alphabet_pd->x_alphabet, argv));
+
+ pd_gfsm_alphabet_obj_outlet_pair(x, labf, argv);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_obj: atom2label_force
+ */
+static void pd_gfsm_alphabet_obj_atom2label_force(t_pd_gfsm_alphabet_obj *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc < 1) {
+ error("pd_gfsm_alphabet_obj_atom2label_force(): no arguments?");
+ return;
+ }
+ t_float labf = (t_float)(gfsm_alphabet_get_label(x->x_alphabet_pd->x_alphabet, argv));
+
+ pd_gfsm_alphabet_obj_outlet_pair(x, labf, argv);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_obj: label2atom
+ */
+static void pd_gfsm_alphabet_obj_label2atom(t_pd_gfsm_alphabet_obj *x, t_float labf)
+{
+ t_atom *key = (t_atom*)gfsm_alphabet_find_key(x->x_alphabet_pd->x_alphabet, (gfsmLabelVal)labf);
+
+ if (key==NULL) pd_gfsm_alphabet_obj_outlet_pair(x, labf, NULL);
+ else pd_gfsm_alphabet_obj_outlet_pair(x, labf, key);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_obj: label2atom_force
+ */
+static void pd_gfsm_alphabet_obj_label2atom_force(t_pd_gfsm_alphabet_obj *x, t_float labf)
+{
+ t_atom *key = (t_atom*)gfsm_alphabet_find_key(x->x_alphabet_pd->x_alphabet,
+ (gfsmLabelVal)labf);
+ if (key==NULL) {
+ t_atom labatom;
+ SETFLOAT(&labatom, labf);
+ gfsm_alphabet_insert(x->x_alphabet_pd->x_alphabet, &labatom, (gfsmLabelVal)labf);
+ pd_gfsm_alphabet_obj_outlet_pair(x, labf, &labatom);
+ }
+ else {
+ pd_gfsm_alphabet_obj_outlet_pair(x, labf, key);
+ }
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_obj: rmatom()
+ */
+static void pd_gfsm_alphabet_obj_rmatom(t_pd_gfsm_alphabet_obj *x, t_symbol *sel, int argc, t_atom *argv)
+{
+ if (argc < 1) return;
+ gfsm_alphabet_remove_key(x->x_alphabet_pd->x_alphabet, argv);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet_obj: rmlabel()
+ */
+static void pd_gfsm_alphabet_obj_rmlabel(t_pd_gfsm_alphabet_obj *x, t_float labf)
+{
+ gfsm_alphabet_remove_label(x->x_alphabet_pd->x_alphabet, (gfsmLabelVal)labf);
+}
+
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_alphabet: setup
+ */
+void pd_gfsm_alphabet_setup(void)
+{
+ //-- pd_gfsm_alphabet_pd
+ pd_gfsm_alphabet_pd_setup();
+
+ //-- class
+ pd_gfsm_alphabet_obj_class = class_new(gensym("gfsm_alphabet"),
+ (t_newmethod)pd_gfsm_alphabet_obj_new,
+ (t_method)pd_gfsm_alphabet_obj_free,
+ sizeof(t_pd_gfsm_alphabet_obj),
+ CLASS_DEFAULT,
+ A_DEFSYM,
+ A_NULL);
+
+ //-- methods: I/O
+ class_addmethod(pd_gfsm_alphabet_obj_class,
+ (t_method)pd_gfsm_alphabet_obj_print,
+ gensym("print"),
+ A_NULL);
+ class_addmethod(pd_gfsm_alphabet_obj_class,
+ (t_method)pd_gfsm_alphabet_obj_load,
+ gensym("load"),
+ A_SYMBOL,
+ A_NULL);
+ class_addmethod(pd_gfsm_alphabet_obj_class,
+ (t_method)pd_gfsm_alphabet_obj_save,
+ gensym("save"),
+ A_SYMBOL,
+ A_NULL);
+
+
+ //-- methods: whole-object manipulation
+ class_addmethod(pd_gfsm_alphabet_obj_class,
+ (t_method)pd_gfsm_alphabet_obj_clear,
+ gensym("clear"),
+ A_NULL);
+ class_addmethod(pd_gfsm_alphabet_obj_class,
+ (t_method)pd_gfsm_alphabet_obj_alphabet,
+ gensym("alphabet"),
+ A_DEFSYM,
+ A_NULL);
+
+
+ //-- methods: insert
+ class_addmethod(pd_gfsm_alphabet_obj_class,
+ (t_method)pd_gfsm_alphabet_obj_insert,
+ gensym("insert"),
+ A_GIMME,
+ A_NULL);
+
+ //-- methods: safe access: atom->label
+ class_addmethod(pd_gfsm_alphabet_obj_class,
+ (t_method)pd_gfsm_alphabet_obj_atom2label,
+ gensym("atom2char"),
+ A_GIMME,
+ A_NULL);
+ /*
+ class_addmethod(pd_gfsm_alphabet_obj_class,
+ (t_method)pd_gfsm_alphabet_obj_atom2label,
+ gensym("a2c"),
+ A_GIMME,
+ A_NULL);
+ */
+
+ //-- methods: destructive access: atom->label
+ class_addmethod(pd_gfsm_alphabet_obj_class,
+ (t_method)pd_gfsm_alphabet_obj_atom2label_force,
+ gensym("atom2char!"),
+ A_GIMME,
+ A_NULL);
+ /*
+ class_addmethod(pd_gfsm_alphabet_obj_class,
+ (t_method)pd_gfsm_alphabet_obj_atom2label_force,
+ gensym("a2c!"),
+ A_GIMME,
+ A_NULL);
+ */
+
+
+ //-- methods: safe access: label->atom
+ class_addmethod(pd_gfsm_alphabet_obj_class,
+ (t_method)pd_gfsm_alphabet_obj_label2atom,
+ gensym("char2atom"),
+ A_FLOAT,
+ A_NULL);
+ /*
+ class_addmethod(pd_gfsm_alphabet_obj_class,
+ (t_method)pd_gfsm_alphabet_obj_label2atom,
+ gensym("c2a"),
+ A_FLOAT,
+ A_NULL);
+ */
+
+ //-- methods: destructive access: label->atom
+ class_addmethod(pd_gfsm_alphabet_obj_class,
+ (t_method)pd_gfsm_alphabet_obj_label2atom_force,
+ gensym("char2atom!"),
+ A_FLOAT,
+ A_NULL);
+ /*
+ class_addmethod(pd_gfsm_alphabet_obj_class,
+ (t_method)pd_gfsm_alphabet_obj_label2atom_force,
+ gensym("c2a!"),
+ A_FLOAT,
+ A_NULL);
+ */
+
+ //-- methods: removal
+ class_addmethod(pd_gfsm_alphabet_obj_class,
+ (t_method)pd_gfsm_alphabet_obj_rmatom,
+ gensym("rmatom"),
+ A_GIMME,
+ A_NULL);
+ class_addmethod(pd_gfsm_alphabet_obj_class,
+ (t_method)pd_gfsm_alphabet_obj_rmlabel,
+ gensym("rmchar"),
+ A_FLOAT,
+ A_NULL);
+
+
+ //-- help symbol
+ class_sethelpsymbol(pd_gfsm_alphabet_obj_class, gensym("gfsm_alphabet-help.pd"));
+}
diff --git a/gfsm/src/pd_alphabet.h b/gfsm/src/pd_alphabet.h
new file mode 100644
index 0000000..e426fd4
--- /dev/null
+++ b/gfsm/src/pd_alphabet.h
@@ -0,0 +1,78 @@
+/*=============================================================================*\
+ * File: pd_alphabet.h
+ * Author: Bryan Jurish <moocow@ling.uni-potsdam.de>
+ * Description: finite state automata for Pd
+ *
+ * Copyright (c) 2004 Bryan Jurish.
+ *
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * See file LICENSE for further informations on licensing terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *=============================================================================*/
+
+#ifndef _PD_GFSM_ALPHABET_H
+#define _PD_GFSM_ALPHABET_H
+
+#include <m_pd.h>
+#include <gfsm.h>
+#include <atom_alphabet.h>
+
+
+/*--------------------------------------------------------------
+ * pd_gfsm_alphabet
+ */
+typedef struct _pd_gfsm_alphabet_pd
+{
+ t_pd x_pd;
+ t_symbol *x_name;
+ size_t x_refcnt;
+ gfsmAlphabet *x_alphabet; //-- really a (gfsmPdAtomAlphabet*)
+} t_pd_gfsm_alphabet_pd;
+
+
+/*--------------------------------------------------------------
+ * pd_gfsm_alphabet
+ */
+typedef struct _pd_gfsm_alphabet_obj
+{
+ t_object x_obj;
+ t_pd_gfsm_alphabet_pd *x_alphabet_pd;
+ t_outlet *x_labout;
+ t_outlet *x_keyout;
+} t_pd_gfsm_alphabet_obj;
+
+
+/*--------------------------------------------------------------
+ * pd_gfsm_alphabet: methods
+ */
+//-- finds pd_gfsm_alphabet named 'name', returns NULL if it doesn't exist
+t_pd_gfsm_alphabet_pd *pd_gfsm_alphabet_pd_find(t_symbol *name);
+
+//-- finds pd_gfsm_alphabet named 'name', creating it if it doesn't exist
+t_pd_gfsm_alphabet_pd *pd_gfsm_alphabet_pd_get(t_symbol *name);
+
+//-- releases one reference to pd_gfsm_alphabet named 'name', possibly freeing the pd_gfsm_alphabet
+void pd_gfsm_alphabet_pd_release(t_pd_gfsm_alphabet_pd *x);
+
+/*--------------------------------------------------------------
+ * setup methods
+ */
+void pd_gfsm_alphabet_setup(void);
+
+
+#endif /* _PD_GFSM_ALPHABET_H */
diff --git a/gfsm/src/pd_automaton.c b/gfsm/src/pd_automaton.c
new file mode 100644
index 0000000..47ce4cd
--- /dev/null
+++ b/gfsm/src/pd_automaton.c
@@ -0,0 +1,765 @@
+/*=============================================================================*\
+ * File: pd_automaton.c
+ * Author: Bryan Jurish <moocow@ling.uni-potsdam.de>
+ * Description: finite state automata for Pd
+ *
+ * Copyright (c) 2004 Bryan Jurish.
+ *
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * See file LICENSE for further informations on licensing terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *=============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <pd_automaton.h>
+#include <pd_io.h>
+#include <m_pd.h>
+
+/*--------------------------------------------------------------------
+ * DEBUG
+ *--------------------------------------------------------------------*/
+//#define PDFSM_DEBUG 1
+
+/*=====================================================================
+ * Structures and Types
+ *=====================================================================*/
+static t_class *pd_gfsm_automaton_pd_class;
+static t_class *pd_gfsm_automaton_obj_class;
+
+/*=====================================================================
+ * pd_gfsm_automaton_pd: Methods
+ *=====================================================================*/
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_pd: new()
+ */
+static void *pd_gfsm_automaton_pd_new(t_symbol *name)
+{
+ t_pd_gfsm_automaton_pd *x = (t_pd_gfsm_automaton_pd *)pd_new(pd_gfsm_automaton_pd_class);
+
+ //-- debug
+#ifdef PDFSM_DEBUG
+ post("pd_gfsm_automaton_pd_new() called; name=%s ; x=%p\n", name->s_name, x);
+#endif
+
+ //-- defaults
+ x->x_refcnt = 0;
+ x->x_name = name;
+ x->x_automaton = gfsm_automaton_new();
+
+ //-- bindings
+ if (name != &s_) pd_bind((t_pd*)x, name);
+
+ return (void *)x;
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_pd: free()
+ */
+static void pd_gfsm_automaton_pd_free(t_pd_gfsm_automaton_pd *x)
+{
+#ifdef PDFSM_DEBUG
+ post("pd_gfsm_automaton_pd_free() called ; x=%p", x);
+#endif
+
+ if (x->x_automaton) gfsm_automaton_free(x->x_automaton);
+ x->x_automaton = NULL;
+
+ /* unbind the symbol of the name of hashtable in pd's global namespace */
+ if (x->x_name != &s_) pd_unbind((t_pd*)x, x->x_name);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_pd: setup()
+ */
+void pd_gfsm_automaton_pd_setup(void)
+{
+ //-- class
+ pd_gfsm_automaton_pd_class = class_new(gensym("pd_gfsm_automaton_pd"),
+ (t_newmethod)pd_gfsm_automaton_pd_new,
+ (t_method)pd_gfsm_automaton_pd_free,
+ sizeof(t_pd_gfsm_automaton_pd),
+ CLASS_PD,
+ A_DEFSYM,
+ A_NULL);
+}
+
+/*=====================================================================
+ * Utilities
+ *=====================================================================*/
+
+/*--------------------------------------------------------------------
+ * Utilties: pd_gfsm_automaton_pd_find()
+ */
+t_pd_gfsm_automaton_pd *pd_gfsm_automaton_pd_find(t_symbol *name)
+{
+ if (name != &s_)
+ return (t_pd_gfsm_automaton_pd*)pd_findbyclass(name,pd_gfsm_automaton_pd_class);
+ return NULL;
+}
+
+/*--------------------------------------------------------------------
+ * Utilties: pd_gfsm_automaton_pd_get()
+ */
+t_pd_gfsm_automaton_pd *pd_gfsm_automaton_pd_get(t_symbol *name)
+{
+ t_pd_gfsm_automaton_pd *x = pd_gfsm_automaton_pd_find(name);
+ if (!x) {
+ x = (t_pd_gfsm_automaton_pd*)pd_gfsm_automaton_pd_new(name);
+ x->x_refcnt = 0;
+ }
+ return x;
+}
+
+/*--------------------------------------------------------------------
+ * Utilties: pd_gfsm_automaton_pd: release()
+ */
+void pd_gfsm_automaton_pd_release(t_pd_gfsm_automaton_pd *x)
+{
+ if (x) {
+ if (x->x_refcnt) --x->x_refcnt;
+ if (!x->x_refcnt) pd_gfsm_automaton_pd_free(x);
+ }
+}
+
+/*--------------------------------------------------------------------
+ * Utilties: pd_gfsm_automaton_obj: outlet_symbol()
+ */
+void pd_gfsm_automaton_obj_outlet_symbol(t_pd_gfsm_automaton_obj *x, t_symbol *sel, t_symbol *val)
+{
+ SETSYMBOL(x->x_argv, val);
+ outlet_anything(x->x_valout, sel, 1, x->x_argv);
+}
+
+/*--------------------------------------------------------------------
+ * Utilties: pd_gfsm_automaton_obj: outlet_symbol()
+ */
+void pd_gfsm_automaton_obj_outlet_symbol_float(t_pd_gfsm_automaton_obj *x, t_symbol *sel, t_symbol *sym, t_float f)
+{
+ SETSYMBOL(x->x_argv, sym);
+ SETFLOAT(x->x_argv+1, f);
+ outlet_anything(x->x_valout, sel, 2, x->x_argv);
+}
+
+/*--------------------------------------------------------------------
+ * Utilties: pd_gfsm_automaton_obj: outlet_float()
+ */
+void pd_gfsm_automaton_obj_outlet_float(t_pd_gfsm_automaton_obj *x, t_symbol *sel, t_float f)
+{
+ SETFLOAT(x->x_argv, f);
+ outlet_anything(x->x_valout, sel, 1, x->x_argv);
+}
+
+/*--------------------------------------------------------------------
+ * Utilties: pd_gfsm_automaton_obj: outlet_float_2()
+ */
+void pd_gfsm_automaton_obj_outlet_float_2(t_pd_gfsm_automaton_obj *x, t_symbol *sel, t_float f1, t_float f2)
+{
+ SETFLOAT(x->x_argv , f1);
+ SETFLOAT(x->x_argv+1, f2);
+ outlet_anything(x->x_valout, sel, 2, x->x_argv);
+}
+
+/*--------------------------------------------------------------------
+ * Utilties: pd_gfsm_automaton_obj: outlet_bang()
+ */
+void pd_gfsm_automaton_obj_outlet_bang(t_pd_gfsm_automaton_obj *x, t_symbol *sel)
+{
+ SETSYMBOL(x->x_argv, &s_bang);
+ outlet_anything(x->x_valout, sel, 1, x->x_argv);
+}
+
+
+
+/*=====================================================================
+ * pd_gfsm_automaton_obj: Methods
+ *=====================================================================*/
+
+/*=====================================================================
+ * Constructors, etc.
+ */
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: new
+ */
+static void *pd_gfsm_automaton_obj_new(t_symbol *name)
+{
+ t_pd_gfsm_automaton_obj *x =
+ (t_pd_gfsm_automaton_obj *)pd_new(pd_gfsm_automaton_obj_class);
+
+#ifdef PDFSM_DEBUG
+ post("pd_gfsm_automaton_obj_new() called: name=%s ; x=%p",
+ (name ? name->s_name : "(null)"),
+ x);
+#endif
+
+ //-- defaults
+ //x->x_automaton_pd = NULL;
+
+ //-- bindings
+ x->x_automaton_pd = pd_gfsm_automaton_pd_get(name);
+ x->x_automaton_pd->x_refcnt++;
+
+ //-- outlets
+ x->x_valout = outlet_new(&x->x_obj, &s_anything); //-- value outlet
+
+ return (void *)x;
+}
+
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: free
+ */
+static void pd_gfsm_automaton_obj_free(t_pd_gfsm_automaton_obj *x)
+{
+#ifdef PDFSM_DEBUG
+ post("pd_gfsm_automaton_obj_free() called: x=%p", x);
+#endif
+
+ pd_gfsm_automaton_pd_release(x->x_automaton_pd);
+
+ //-- do we need to do this?
+ outlet_free(x->x_valout);
+}
+
+/*=====================================================================
+ * automaton_obj: Basic Accessors
+ */
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: automaton
+ */
+static void pd_gfsm_automaton_obj_automaton(t_pd_gfsm_automaton_obj *x, t_symbol *name)
+{
+ if (name != x->x_automaton_pd->x_name) {
+ pd_gfsm_automaton_pd_release(x->x_automaton_pd);
+ x->x_automaton_pd = pd_gfsm_automaton_pd_get(name);
+ ++x->x_automaton_pd->x_refcnt;
+ }
+ pd_gfsm_automaton_obj_outlet_symbol(x, gensym("automaton"), name);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: size()
+ */
+static void pd_gfsm_automaton_obj_size(t_pd_gfsm_automaton_obj *x, GIMME_ARGS)
+{
+ if (argc > 0) {
+ gfsmStateId n = (gfsmStateId)atom_getfloatarg(0,argc,argv);
+ gfsm_automaton_reserve(x->x_automaton_pd->x_automaton, n);
+ }
+ pd_gfsm_automaton_obj_outlet_float
+ (x, sel, (t_float)gfsm_automaton_n_states(x->x_automaton_pd->x_automaton));
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: clear()
+ */
+static void pd_gfsm_automaton_obj_clear(t_pd_gfsm_automaton_obj *x)
+{
+ gfsm_automaton_clear(x->x_automaton_pd->x_automaton);
+ pd_gfsm_automaton_obj_outlet_bang(x, gensym("clear"));
+}
+
+/*=====================================================================
+ * automaton_obj: flags
+ */
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: root()
+ */
+static void pd_gfsm_automaton_obj_root(t_pd_gfsm_automaton_obj *x, GIMME_ARGS)
+{
+ gfsmStateId q0;
+ if (argc > 0) {
+ q0 = (gfsmStateId)atom_getintarg(0,argc,argv);
+ gfsm_automaton_set_root(x->x_automaton_pd->x_automaton, q0);
+ } else {
+ q0 = gfsm_automaton_get_root(x->x_automaton_pd->x_automaton);
+ }
+
+ if (q0==gfsmNoState) pd_gfsm_automaton_obj_outlet_bang(x, sel);
+ else pd_gfsm_automaton_obj_outlet_float(x, sel, (t_float)q0);
+}
+
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: weighted()
+ */
+static void pd_gfsm_automaton_obj_weighted(t_pd_gfsm_automaton_obj *x, GIMME_ARGS)
+{
+ if (argc > 0)
+ x->x_automaton_pd->x_automaton->flags.is_weighted = atom_getboolarg(0,argc,argv);
+ pd_gfsm_automaton_obj_outlet_float
+ (x, sel, (t_float)(x->x_automaton_pd->x_automaton->flags.is_weighted));
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: transducer()
+ */
+static void pd_gfsm_automaton_obj_transducer(t_pd_gfsm_automaton_obj *x, GIMME_ARGS)
+{
+ if (argc > 0)
+ x->x_automaton_pd->x_automaton->flags.is_transducer = atom_getboolarg(0,argc,argv);
+ pd_gfsm_automaton_obj_outlet_float
+ (x, sel, (t_float)(x->x_automaton_pd->x_automaton->flags.is_transducer));
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: semiring()
+ */
+static void pd_gfsm_automaton_obj_semiring(t_pd_gfsm_automaton_obj *x, GIMME_ARGS)
+{
+ t_symbol *srsym;
+ if (argc > 0) {
+ srsym = atom_getsymbolarg(0,argc,argv);
+ gfsm_automaton_set_semiring_type(x->x_automaton_pd->x_automaton,
+ gfsm_sr_name_to_type(srsym->s_name));
+ }
+ srsym = gensym(gfsm_sr_type_to_name(x->x_automaton_pd->x_automaton->sr->type));
+ pd_gfsm_automaton_obj_outlet_symbol(x, sel, srsym);
+}
+
+/*=====================================================================
+ * automaton_obj: state properties
+ */
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: final()
+ */
+static void pd_gfsm_automaton_obj_final(t_pd_gfsm_automaton_obj *x, GIMME_ARGS)
+{
+ gboolean ans = FALSE;
+ t_float qf = atom_getfloatarg(0,argc,argv);
+ if (qf<0) qf = -qf;
+ if (argc > 1) {
+ ans = atom_getboolarg(1,argc,argv);
+ gfsm_automaton_set_final_state(x->x_automaton_pd->x_automaton, (gfsmStateId)qf, ans);
+ } else {
+ ans = gfsm_automaton_is_final_state(x->x_automaton_pd->x_automaton, (gfsmStateId)qf);
+ }
+ pd_gfsm_automaton_obj_outlet_float_2(x, sel, qf, (t_float)ans);
+}
+
+
+/*=====================================================================
+ * automaton_obj: states & arcs
+ */
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: add_state()
+ */
+static void pd_gfsm_automaton_obj_add_state(t_pd_gfsm_automaton_obj *x, GIMME_ARGS)
+{
+ gfsmStateId id;
+ if (argc>0) id = (gfsmStateId)atom_getfloatarg(0,argc,argv);
+ else id = gfsmNoState;
+
+ id = gfsm_automaton_ensure_state(x->x_automaton_pd->x_automaton, id);
+ pd_gfsm_automaton_obj_outlet_float(x, sel, (t_float)id);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: add_arc()
+ */
+static void pd_gfsm_automaton_obj_add_arc(t_pd_gfsm_automaton_obj *x, GIMME_ARGS)
+{
+ t_float qsrc=0, qdst=0;
+ t_float clo=0, chi=0;
+ t_float w=0;
+ if (argc < 2) {
+ error("gfsm_automaton: add_arc(): not enough arguments!");
+ return;
+ }
+ switch (argc) {
+ case 5: //-- +from, +to, +lo, +hi, +weight
+ w = atom_getfloat(argv+4);
+ case 4: //-- +from, +to, +lo, +hi, -weight
+ chi = atom_getfloat(argv+3);
+ case 3: //-- +from, +to, +lo, -hi, -weight
+ clo = atom_getfloat(argv+2);
+ case 2: //-- +from, +to, -lo, -hi, -weight
+ default:
+ qdst = atom_getfloat(argv+1);
+ qsrc = atom_getfloat(argv);
+
+ if (qdst<0) qdst = -qdst;
+ if (qsrc<0) qsrc = -qsrc;
+ break;
+ }
+
+ gfsm_automaton_add_arc(x->x_automaton_pd->x_automaton,
+ (gfsmStateId)qsrc,
+ (gfsmStateId)qdst,
+ (gfsmLabelId)clo,
+ (gfsmLabelId)chi,
+ (gfsmWeight)w);
+
+#ifdef PDFSM_DEBUG
+ post("pd_gfsm_automaton_obj_add_arc(): node(qsrc=%ld).out_degree=%u",
+ qsrc,
+ gfsm_automaton_out_degree(x->x_automaton_pd->x_automaton, qsrc));
+#endif
+
+ //-- output
+ SETFLOAT(x->x_argv , (t_float)qsrc);
+ SETFLOAT(x->x_argv+1, (t_float)qdst);
+ SETFLOAT(x->x_argv+2, (t_float)clo);
+ SETFLOAT(x->x_argv+3, (t_float)chi);
+ SETFLOAT(x->x_argv+4, (t_float)w);
+ outlet_anything(x->x_valout, sel, 5, x->x_argv);
+}
+
+/*=====================================================================
+ * automaton_obj: Text I/O
+ */
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: print()
+ */
+static void pd_gfsm_automaton_obj_print(t_pd_gfsm_automaton_obj *x)
+{
+ gfsmError *errp = NULL;
+ gfsmIOHandle *ioh = pd_gfsm_console_handle_new();
+ gfsm_automaton_print_handle(x->x_automaton_pd->x_automaton,
+ ioh, NULL,NULL,NULL, &errp);
+ if (errp) {
+ error("gfsm_automaton: print(): Error: %s\n", errp->message);
+ g_error_free(errp);
+ }
+ pd_gfsm_console_handle_free(ioh);
+ pd_gfsm_automaton_obj_outlet_bang(x, gensym("print"));
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: load_txt()
+ */
+static void pd_gfsm_automaton_obj_load_txt(t_pd_gfsm_automaton_obj *x, t_symbol *s)
+{
+ gfsmError *errp = NULL;
+ gfsm_automaton_compile_filename(x->x_automaton_pd->x_automaton, s->s_name, &errp);
+ if (errp) {
+ error("gfsm_automaton: load_txt(%s): Error: %s\n", s->s_name, errp->message);
+ g_error_free(errp);
+ }
+ pd_gfsm_automaton_obj_outlet_symbol(x, gensym("load"), s);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: save_txt()
+ */
+static void pd_gfsm_automaton_obj_save_txt(t_pd_gfsm_automaton_obj *x, t_symbol *s)
+{
+ gfsmError *errp = NULL;
+ gfsm_automaton_print_filename(x->x_automaton_pd->x_automaton, s->s_name, &errp);
+ if (errp) {
+ error("gfsm_automaton: save_txt(%s): Error: %s\n", s->s_name, errp->message);
+ g_error_free(errp);
+ }
+ pd_gfsm_automaton_obj_outlet_symbol(x, gensym("save"), s);
+}
+
+
+/*=====================================================================
+ * automaton_obj: Binary I/O
+ */
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: load_bin()
+ */
+static void pd_gfsm_automaton_obj_load_bin(t_pd_gfsm_automaton_obj *x, t_symbol *s)
+{
+ gfsmError *errp = NULL;
+ gfsm_automaton_load_bin_filename(x->x_automaton_pd->x_automaton, s->s_name, &errp);
+ if (errp) {
+ error("gfsm_automaton: load_bin(%s): Error: %s\n", s->s_name, errp->message);
+ g_error_free(errp);
+ }
+ pd_gfsm_automaton_obj_outlet_symbol(x, gensym("load_bin"), s);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: save_bin()
+ */
+static void pd_gfsm_automaton_obj_save_bin(t_pd_gfsm_automaton_obj *x, t_symbol *s, t_float zlevel)
+{
+ gfsmError *errp = NULL;
+ gfsm_automaton_save_bin_filename(x->x_automaton_pd->x_automaton, s->s_name, (int)zlevel, &errp);
+ if (errp) {
+ error("gfsm_automaton: save_bin(%s,%d): Error: %s\n", s->s_name, (int)zlevel, errp->message);
+ g_error_free(errp);
+ }
+ pd_gfsm_automaton_obj_outlet_symbol_float(x, gensym("save_bin"), s, (int)zlevel);
+}
+
+
+/*=====================================================================
+ * automaton_obj: info
+ */
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: info()
+ */
+static void pd_gfsm_automaton_obj_info(t_pd_gfsm_automaton_obj *x)
+{
+ gfsmAutomaton *fsm = x->x_automaton_pd->x_automaton;
+ guint n_eps_i, n_eps_o, n_eps_io;
+
+#define bool2char(b) ((b) ? 'y' : 'n')
+
+ post("-- GFSM Automaton Info --");
+ post("%-24s: %s", "Name", x->x_automaton_pd->x_name->s_name);
+ post("%-24s: %s", "Semiring", gfsm_sr_type_to_name(fsm->sr->type));
+ post("%-24s: %c", "Transducer?", bool2char(gfsm_automaton_is_transducer(fsm)));
+ post("%-24s: %c", "Weighted?", bool2char(gfsm_automaton_is_weighted(fsm)));
+ post("%-24s: %c", "Deterministic?", bool2char(fsm->flags.is_deterministic));
+ post("%-24s: %s", "Sort Mode", gfsm_arc_sortmode_to_name(gfsm_automaton_sortmode(fsm)));
+ if (fsm->root_id == gfsmNoState)
+ post("%-24s: %s", "Initial state", "(none)");
+ else
+ post("%-24s: %u", "Initial state", fsm->root_id);
+ post("%-24s: %u", "# of states", gfsm_automaton_n_states(fsm));
+ post("%-24s: %u", "# of final states", gfsm_automaton_n_final_states(fsm));
+ post("%-24s: %u", "# of arcs", gfsm_automaton_n_arcs_full(fsm, &n_eps_i, &n_eps_o, &n_eps_io));
+ post("%-24s: %u", "# of i/o epsilon arcs", n_eps_io);
+ post("%-24s: %u", "# of input epsilon arcs", n_eps_i);
+ post("%-24s: %u", "# of output epsilon arcs", n_eps_o);
+ post("%-24s: %c", "cyclic?", bool2char(gfsm_automaton_is_cyclic(fsm)));
+ //...
+
+#undef bool2char
+
+ pd_gfsm_automaton_obj_outlet_bang(x, gensym("info"));
+}
+
+
+/*=====================================================================
+ * automaton_obj: draw
+ */
+
+/*--------------------------------------------------------------------
+ * automaton_obj: draw_dot()
+ */
+static void pd_gfsm_automaton_obj_draw_dot(t_pd_gfsm_automaton_obj *x, GIMME_ARGS)
+{
+ t_pd_gfsm_alphabet_pd *ialph=NULL, *oalph=NULL, *salph=NULL;
+ t_symbol
+ *filename = atom_getsymbolarg(0,argc,argv),
+ *title = x->x_automaton_pd->x_name,
+ *fontname = NULL;
+ float
+ width=0,
+ height=0,
+ nodesep=0,
+ ranksep=0;
+ int fontsize=0;
+ gboolean
+ portrait=FALSE,
+ vertical=FALSE;
+ gfsmError *errp = NULL;
+ int i;
+
+ for (i=1; i < argc; i++) {
+ t_symbol *opt = atom_getsymbolarg(i,argc,argv);
+
+ //--debug
+ //post("gfsm_automaton: draw_dot: checking option '%s'", opt->s_name);
+
+ if (opt==gensym("ilabels")) {
+ if (ialph) pd_gfsm_alphabet_pd_release(ialph);
+ ialph = pd_gfsm_alphabet_pd_find(atom_getsymbolarg(++i,argc,argv));
+ if (ialph) ialph->x_refcnt++;
+ }
+ else if (opt==gensym("olabels")) {
+ if (oalph) pd_gfsm_alphabet_pd_release(oalph);
+ oalph = pd_gfsm_alphabet_pd_find(atom_getsymbolarg(++i,argc,argv));
+ if (oalph) oalph->x_refcnt++;
+ }
+ else if (opt==gensym("slabels")) {
+ if (salph) pd_gfsm_alphabet_pd_release(salph);
+ salph = pd_gfsm_alphabet_pd_find(atom_getsymbolarg(++i,argc,argv));
+ if (salph) salph->x_refcnt++;
+ }
+ else if (opt==gensym("title")) title = atom_getsymbolarg(++i,argc,argv);
+ else if (opt==gensym("width")) width = atom_getfloatarg(++i,argc,argv);
+ else if (opt==gensym("height")) height = atom_getfloatarg(++i,argc,argv);
+ else if (opt==gensym("fontsize")) fontsize = atom_getintarg(++i,argc,argv);
+ else if (opt==gensym("fontname")) fontname = atom_getsymbolarg(++i,argc,argv);
+ else if (opt==gensym("portrait")) portrait = atom_getboolarg(++i,argc,argv);
+ else if (opt==gensym("vertical")) vertical = atom_getboolarg(++i,argc,argv);
+ else if (opt==gensym("nodesep")) nodesep = atom_getfloatarg(++i,argc,argv);
+ else if (opt==gensym("ranksep")) ranksep = atom_getfloatarg(++i,argc,argv);
+ else {
+ char buf[64];
+ atom_string(argv+i, buf, 64);
+ error("gfsm_automaton: draw_dot: unknown option '%s' ignored", buf);
+ }
+ }
+
+ gfsm_automaton_draw_dot_filename_full(x->x_automaton_pd->x_automaton,
+ filename->s_name,
+ (ialph ? ialph->x_alphabet : NULL),
+ (oalph ? oalph->x_alphabet : NULL),
+ (salph ? salph->x_alphabet : NULL),
+ title->s_name,
+ width,
+ height,
+ fontsize,
+ (fontname ? fontname->s_name : NULL),
+ portrait,
+ vertical,
+ nodesep,
+ ranksep,
+ &errp);
+
+ if (errp) {
+ error("gfsm_automaton: draw_dot(%s): Error: %s\n", filename->s_name, errp->message);
+ g_error_free(errp);
+ }
+
+ //-- cleanup
+ if (ialph) pd_gfsm_alphabet_pd_release(ialph);
+ if (oalph) pd_gfsm_alphabet_pd_release(oalph);
+ if (salph) pd_gfsm_alphabet_pd_release(salph);
+
+ pd_gfsm_automaton_obj_outlet_symbol(x, gensym("draw_dot"), filename);
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton_obj: setup()
+ */
+static void pd_gfsm_automaton_obj_setup(void)
+{
+ //-- class
+ pd_gfsm_automaton_obj_class = class_new(gensym("gfsm_automaton"),
+ (t_newmethod)pd_gfsm_automaton_obj_new,
+ (t_method)pd_gfsm_automaton_obj_free,
+ sizeof(t_pd_gfsm_automaton_obj),
+ CLASS_DEFAULT,
+ A_DEFSYM,
+ A_NULL);
+
+ //-- methods: automaton
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_automaton,
+ gensym("automaton"),
+ A_DEFSYM, A_NULL);
+
+ //-- methods: flags
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_root,
+ gensym("root"),
+ A_GIMME, A_NULL);
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_weighted,
+ gensym("weighted"),
+ A_GIMME, A_NULL);
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_transducer,
+ gensym("transducer"),
+ A_GIMME, A_NULL);
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_semiring,
+ gensym("semiring"),
+ A_GIMME, A_NULL);
+
+ //-- methods: size
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_size,
+ gensym("size"),
+ A_GIMME, A_NULL);
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_clear,
+ gensym("clear"),
+ A_NULL);
+
+ //-- methods: state properties
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_final,
+ gensym("final"),
+ A_GIMME, A_NULL);
+
+ //-- methods: states & arcs
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_add_state,
+ gensym("add_state"),
+ A_GIMME, A_NULL);
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_add_arc,
+ gensym("add_arc"),
+ A_GIMME, //-- qsrc,qdst,clo,chi,weight
+ A_NULL);
+
+
+ //-- methods: I/O: text
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_print,
+ gensym("print"),
+ A_NULL);
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_load_txt,
+ gensym("load"),
+ A_SYMBOL, A_NULL);
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_save_txt,
+ gensym("save"),
+ A_SYMBOL, A_NULL);
+
+ //-- methods: I/O: binary
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_load_bin,
+ gensym("load_bin"),
+ A_SYMBOL, A_NULL);
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_save_bin,
+ gensym("save_bin"),
+ A_SYMBOL, A_DEFFLOAT, A_NULL);
+
+ //-- methods: info
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_info,
+ gensym("info"),
+ A_NULL);
+
+ //-- methods: draw
+ class_addmethod(pd_gfsm_automaton_obj_class,
+ (t_method)pd_gfsm_automaton_obj_draw_dot,
+ gensym("draw_dot"),
+ A_GIMME, A_NULL);
+
+ //-- help symbol
+ class_sethelpsymbol(pd_gfsm_automaton_obj_class, gensym("gfsm_automaton-help.pd"));
+}
+
+
+/*=====================================================================
+ * automaton setup
+ *=====================================================================*/
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_automaton: setup()
+ */
+void pd_gfsm_automaton_setup(void)
+{
+ pd_gfsm_automaton_pd_setup();
+ pd_gfsm_automaton_obj_setup();
+ pd_gfsm_algebra_setup(pd_gfsm_automaton_obj_class);
+}
diff --git a/gfsm/src/pd_automaton.h b/gfsm/src/pd_automaton.h
new file mode 100644
index 0000000..ed95954
--- /dev/null
+++ b/gfsm/src/pd_automaton.h
@@ -0,0 +1,85 @@
+/*=============================================================================*\
+ * File: pd_automaton.h
+ * Author: Bryan Jurish <moocow@ling.uni-potsdam.de>
+ * Description: finite state automata for Pd
+ *
+ * Copyright (c) 2004 Bryan Jurish.
+ *
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * See file LICENSE for further informations on licensing terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *=============================================================================*/
+
+/*=====================================================================
+ * Protos
+ *=====================================================================*/
+#ifndef PD_GFSM_AUTOMATON_H
+#define PD_GFSM_AUTOMATON_H
+
+/*----------------------------------------------------------------------
+ * includes
+ */
+#include <m_pd.h>
+#include <gfsm.h>
+#include <pd_alphabet.h>
+
+/*--------------------------------------------------------------
+ * pd_fsm_automaton_pd
+ */
+typedef struct _pd_gfsm_automaton_pd
+{
+ t_pd x_pd;
+ t_symbol *x_name;
+ size_t x_refcnt;
+ gfsmAutomaton *x_automaton;
+} t_pd_gfsm_automaton_pd;
+
+typedef struct _pd_gfsm_automaton_obj
+{
+ t_object x_obj;
+ t_pd_gfsm_automaton_pd *x_automaton_pd;
+ t_atom x_argv[5];
+ t_outlet *x_valout;
+} t_pd_gfsm_automaton_obj;
+
+/*--------------------------------------------------------------------
+ * utility macros
+ */
+#define atom_getboolarg(which,argc,argv) (atom_getintarg(which,argc,argv)==0 ? FALSE : TRUE)
+#define GIMME_ARGS t_symbol *sel, int argc, t_atom *argv
+
+/*----------------------------------------------------------------------
+ * utilities
+ */
+t_pd_gfsm_automaton_pd *pd_gfsm_automaton_pd_find(t_symbol *name);
+t_pd_gfsm_automaton_pd *pd_gfsm_automaton_pd_get(t_symbol *name);
+void pd_gfsm_automaton_pd_release(t_pd_gfsm_automaton_pd *x);
+
+void pd_gfsm_automaton_obj_outlet_symbol(t_pd_gfsm_automaton_obj *x, t_symbol *sel, t_symbol *val);
+void pd_gfsm_automaton_obj_outlet_float(t_pd_gfsm_automaton_obj *x, t_symbol *sel, t_float f);
+void pd_gfsm_automaton_obj_outlet_float_2(t_pd_gfsm_automaton_obj *x, t_symbol *sel, t_float f1, t_float f2);
+void pd_gfsm_automaton_obj_outlet_bang(t_pd_gfsm_automaton_obj *x, t_symbol *sel);
+
+/*----------------------------------------------------------------------
+ * setup routines
+ */
+extern void pd_gfsm_algebra_setup(t_class *automaton_class);
+
+void pd_gfsm_automaton_setup(void);
+
+#endif /* PD_GFSM_AUTOMATON_H */
diff --git a/gfsm/src/pd_gfsm.c b/gfsm/src/pd_gfsm.c
new file mode 100644
index 0000000..2deb6c8
--- /dev/null
+++ b/gfsm/src/pd_gfsm.c
@@ -0,0 +1,93 @@
+/*=============================================================================*\
+ * File: pd_gfsm.c
+ * Author: Bryan Jurish <moocow@ling.uni-potsdam.de>
+ * Description: finite state automata for Pd
+ *
+ * Copyright (c) 2004 Bryan Jurish.
+ *
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * See file LICENSE for further informations on licensing terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *=============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <pd_gfsm.h>
+#include <pd_alphabet.h>
+
+#define USE_AUTOMATA
+
+#ifdef USE_AUTOMATA
+# include <pd_automaton.h>
+# include <pd_state.h>
+#endif
+
+/*=====================================================================
+ * Structures and Types
+ *=====================================================================*/
+static t_class *pd_gfsm_dummy_class;
+
+/*=====================================================================
+ * pd_gfsm_dummy
+ *=====================================================================*/
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_dummy: new()
+ */
+static void *pd_gfsm_dummy_new(void)
+{
+ t_pd_gfsm_dummy *x = (t_pd_gfsm_dummy *)pd_new(pd_gfsm_dummy_class);
+ return (void *)x;
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_dummy: free()
+ */
+static void pd_gfsm_dummy_free(t_pd_gfsm_dummy *x)
+{}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_dummy: setup()
+ */
+void gfsm_setup(void)
+{
+ //-- banner
+ post("");
+ post("gfsm: finite state machine externals v%s by Bryan Jurish", PACKAGE_VERSION);
+ //post("fsm: based on code by Helmut Schmid");
+
+ //-- library
+ pd_gfsm_alphabet_setup();
+#ifdef USE_AUTOMATA
+ pd_gfsm_automaton_setup();
+ pd_gfsm_state_setup();
+#endif
+
+ //-- class (dummy)
+ pd_gfsm_dummy_class = class_new(gensym("gfsm"),
+ (t_newmethod)pd_gfsm_dummy_new,
+ (t_method)pd_gfsm_dummy_free,
+ sizeof(t_pd_gfsm_dummy),
+ CLASS_DEFAULT,
+ A_NULL);
+
+ //-- help symbol
+ class_sethelpsymbol(pd_gfsm_dummy_class, gensym("gfsm-help.pd"));
+}
diff --git a/gfsm/src/pd_gfsm.h b/gfsm/src/pd_gfsm.h
new file mode 100644
index 0000000..e65069e
--- /dev/null
+++ b/gfsm/src/pd_gfsm.h
@@ -0,0 +1,54 @@
+/*=============================================================================*\
+ * File: pd_gfsm.h
+ * Author: Bryan Jurish <moocow@ling.uni-potsdam.de>
+ * Description: finite state automata for Pd
+ *
+ * Copyright (c) 2004 Bryan Jurish.
+ *
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * See file LICENSE for further informations on licensing terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *=============================================================================*/
+
+/*=====================================================================
+ * Protos
+ *=====================================================================*/
+#ifndef PD_GFSM_H
+#define PD_GFSM_H
+
+/*----------------------------------------------------------------------
+ * includes
+ */
+#include <m_pd.h>
+#include <gfsm.h>
+
+/*----------------------------------------------------------------------
+ * structures and types
+ */
+typedef struct _pd_gfsm_dummy
+{
+ t_object x_obj;
+} t_pd_gfsm_dummy;
+
+
+/*----------------------------------------------------------------------
+ * setup routines
+ */
+void gfsm_setup(void);
+
+#endif /* PD_GFSM_H */
diff --git a/gfsm/src/pd_io.c b/gfsm/src/pd_io.c
new file mode 100644
index 0000000..5f82c2c
--- /dev/null
+++ b/gfsm/src/pd_io.c
@@ -0,0 +1,75 @@
+/*=============================================================================*\
+ * File: pd_io.c
+ * Author: Bryan Jurish <moocow@ling.uni-potsdam.de>
+ * Description: finite state automata for Pd: I/O
+ *
+ * Copyright (c) 2006 Bryan Jurish.
+ *
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * See file LICENSE for further informations on licensing terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *=============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <pd_io.h>
+
+/*=====================================================================
+ * I/O utilities
+ *=====================================================================*/
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_console_handle_flush()
+ */
+static void pd_gfsm_console_handle_flush(gfsmPosGString *pgs)
+{
+ if (pgs->gs->len) post(pgs->gs->str);
+ g_string_truncate(pgs->gs,0);
+ pgs->pos = 0;
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_console_handle_new()
+ */
+gfsmIOHandle *pd_gfsm_console_handle_new(void)
+{
+ GString *gs = g_string_new("");
+ gfsmPosGString *pgs = g_new(gfsmPosGString,1);
+ gfsmIOHandle *ioh;
+ pgs->gs = gs;
+ pgs->pos = 0;
+
+ ioh = gfsmio_new_gstring(pgs);
+ ioh->flush_func = (gfsmIOFlushFunc)pd_gfsm_console_handle_flush;
+
+ return ioh;
+}
+
+/*--------------------------------------------------------------------
+ * pd_gfsm_console_handle_free()
+ */
+void pd_gfsm_console_handle_free(gfsmIOHandle *ioh)
+{
+ gfsmPosGString *pgs = (gfsmPosGString*)ioh->handle;
+ gfsmio_flush(ioh);
+ g_string_free(pgs->gs,TRUE);
+ g_free(pgs);
+ g_free(ioh);
+}
diff --git a/gfsm/src/pd_io.h b/gfsm/src/pd_io.h
new file mode 100644
index 0000000..83de85b
--- /dev/null
+++ b/gfsm/src/pd_io.h
@@ -0,0 +1,47 @@
+/*=============================================================================*\
+ * File: pd_io.h
+ * Author: Bryan Jurish <moocow@ling.uni-potsdam.de>
+ * Description: finite state automata for Pd; I/O
+ *
+ * Copyright (c) 2006 Bryan Jurish.
+ *
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * See file LICENSE for further informations on licensing terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *=============================================================================*/
+
+/*=====================================================================
+ * Protos
+ *=====================================================================*/
+#ifndef PD_GFSM_IO_H
+#define PD_GFSM_IO_H
+
+/*----------------------------------------------------------------------
+ * includes
+ */
+#include <m_pd.h>
+#include <gfsm.h>
+
+/*----------------------------------------------------------------------
+ * I/O stuff
+ */
+gfsmIOHandle *pd_gfsm_console_handle_new(void);
+
+void pd_gfsm_console_handle_free(gfsmIOHandle *ioh);
+
+#endif /* PD_GFSM_IO_H */
diff --git a/gfsm/src/pd_state.c b/gfsm/src/pd_state.c
new file mode 100644
index 0000000..b7cd938
--- /dev/null
+++ b/gfsm/src/pd_state.c
@@ -0,0 +1,303 @@
+/*=============================================================================*\
+ * File: pd_state.c
+ * Author: Bryan Jurish <moocow@ling.uni-potsdam.de>
+ * Description: finite state automata for Pd
+ *
+ * Copyright (c) 2004 Bryan Jurish.
+ *
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * See file LICENSE for further informations on licensing terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *=============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <pd_state.h>
+
+/*=====================================================================
+ * Structures and Types
+ *=====================================================================*/
+static t_class *pd_gfsm_state_class;
+
+
+/*=====================================================================
+ * pd_gfsm_state: Methods
+ *=====================================================================*/
+
+/*=====================================================================
+ * Constructors, etc.
+ */
+
+/*--------------------------------------------------------------------
+ * new()
+ */
+static void *pd_gfsm_state_new(t_symbol *sel, int argc, t_atom *argv)
+{
+ t_symbol *name = &s_;
+ t_pd_gfsm_state *x = (t_pd_gfsm_state *)pd_new(pd_gfsm_state_class);
+
+ //-- defaults
+ x->x_id = gfsmNoState;
+ gfsm_arciter_close(&x->x_arci);
+ x->x_open = FALSE;
+
+ //-- args
+ if (argc > 0) {
+ name = atom_getsymbolarg(0,argc,argv);
+ if (argc > 1) x->x_id = (gfsmStateId)atom_getfloatarg(1,argc,argv);
+ }
+
+ //-- bindings
+ x->x_automaton_pd = pd_gfsm_automaton_pd_get(name);
+ x->x_automaton_pd->x_refcnt++;
+
+ //-- outlets
+ x->x_valout = outlet_new(&x->x_obj, &s_anything); //-- value outlet
+
+ return (void *)x;
+}
+
+/*--------------------------------------------------------------------
+ * free
+ */
+static void pd_gfsm_state_free(t_pd_gfsm_state *x)
+{
+ gfsm_arciter_close(&x->x_arci);
+ pd_gfsm_automaton_pd_release(x->x_automaton_pd);
+
+ //-- do we need to do this?
+ outlet_free(x->x_valout);
+}
+
+/*=====================================================================
+ * Basic Accessors
+ */
+
+/*--------------------------------------------------------------------
+ * automaton
+ */
+static void pd_gfsm_state_automaton(t_pd_gfsm_state *x, t_symbol *name)
+{
+ gfsm_arciter_close(&x->x_arci);
+ x->x_open = FALSE;
+
+ if (name == x->x_automaton_pd->x_name) return;
+ pd_gfsm_automaton_pd_release(x->x_automaton_pd);
+
+ x->x_automaton_pd = pd_gfsm_automaton_pd_get(name);
+ ++x->x_automaton_pd->x_refcnt;
+}
+
+
+/*--------------------------------------------------------------------
+ * id
+ */
+static void pd_gfsm_state_id(t_pd_gfsm_state *x)
+{
+ SETSYMBOL(x->x_argv, gensym("id"));
+ if (x->x_id==gfsmNoState) SETSYMBOL(x->x_argv, &s_bang);
+ else SETFLOAT(x->x_argv, (t_float)(x->x_id));
+ outlet_anything(x->x_valout, gensym("id"), 1, x->x_argv);
+}
+
+/*--------------------------------------------------------------------
+ * set
+ */
+static void pd_gfsm_state_set(t_pd_gfsm_state *x, t_floatarg qf)
+{
+ if (qf<0) qf = -qf;
+ gfsm_arciter_close(&x->x_arci);
+ x->x_open = FALSE;
+ x->x_id = gfsm_automaton_ensure_state(x->x_automaton_pd->x_automaton, (gfsmStateId)qf);
+}
+
+/*--------------------------------------------------------------------
+ * degree
+ */
+static void pd_gfsm_state_degree(t_pd_gfsm_state *x)
+{
+ gfsmState *s = gfsm_automaton_find_state(x->x_automaton_pd->x_automaton, x->x_id);
+ SETFLOAT(x->x_argv, (s ? (t_float)gfsm_state_out_degree(s) : 0));
+ outlet_anything(x->x_valout, gensym("degree"), 1, x->x_argv);
+}
+
+/*=====================================================================
+ * Navigation
+ */
+
+/*--------------------------------------------------------------------
+ * utility: outlet_arc()
+ */
+static void pd_gfsm_state_outlet_arc(t_pd_gfsm_state *x, t_symbol *sel)
+{
+ //outlet_anything(x->x_opout, op, 0, NULL);
+ if (gfsm_arciter_ok(&x->x_arci)) {
+ gfsmArc *a = gfsm_arciter_arc(&x->x_arci);
+ SETFLOAT(x->x_argv, (t_float)(a->target));
+ SETFLOAT(x->x_argv+1, (t_float)(a->lower));
+ SETFLOAT(x->x_argv+2, (t_float)(a->upper));
+ SETFLOAT(x->x_argv+3, (t_float)(a->weight));
+ outlet_anything(x->x_valout, sel, 4, x->x_argv);
+ }
+ else {
+ SETSYMBOL(x->x_argv, &s_bang);
+ outlet_anything(x->x_valout, sel, 1, x->x_argv);
+ }
+}
+
+/*--------------------------------------------------------------------
+ * arc_first
+ */
+static void pd_gfsm_state_arc_first(t_pd_gfsm_state *x)
+{
+ gfsm_arciter_close(&x->x_arci);
+ gfsm_arciter_open(&x->x_arci, x->x_automaton_pd->x_automaton, x->x_id);
+ x->x_open = TRUE;
+ pd_gfsm_state_outlet_arc(x, gensym("arc_first"));
+}
+
+/*--------------------------------------------------------------------
+ * arc_next
+ */
+static void pd_gfsm_state_arc_next(t_pd_gfsm_state *x)
+{
+ gfsmState *s = gfsm_automaton_find_state(x->x_automaton_pd->x_automaton, x->x_id);
+ if (s) {
+ if (x->x_open && gfsm_arciter_ok(&x->x_arci)) {
+ gfsm_arciter_next(&x->x_arci);
+ } else if (!x->x_open) {
+ gfsm_arciter_open(&x->x_arci, x->x_automaton_pd->x_automaton, x->x_id);
+ x->x_open = TRUE;
+ }
+ }
+ pd_gfsm_state_outlet_arc(x, gensym("arc_next"));
+}
+
+/*--------------------------------------------------------------------
+ * arc_seek
+ */
+static void pd_gfsm_state_arc_seek(t_pd_gfsm_state *x, t_float flo, t_float fhi)
+{
+ gfsmState *s = gfsm_automaton_find_state(x->x_automaton_pd->x_automaton, x->x_id);
+ if (s) {
+ if (x->x_open && gfsm_arciter_ok(&x->x_arci)) {
+ gfsm_arciter_next(&x->x_arci);
+ } else if (!x->x_open) {
+ gfsm_arciter_open(&x->x_arci, x->x_automaton_pd->x_automaton, x->x_id);
+ x->x_open = TRUE;
+ }
+ }
+ gfsm_arciter_seek_both(&x->x_arci,
+ (flo < 0 ? gfsmNoLabel : ((gfsmLabelVal)flo)),
+ (fhi < 0 ? gfsmNoLabel : ((gfsmLabelVal)fhi)));
+ pd_gfsm_state_outlet_arc(x, gensym("arc_seek"));
+}
+
+
+/*--------------------------------------------------------------------
+ * arc_reset
+ */
+static void pd_gfsm_state_arc_reset(t_pd_gfsm_state *x)
+{
+ gfsm_arciter_close(&x->x_arci);
+ x->x_open = FALSE;
+}
+
+/*--------------------------------------------------------------------
+ * add_weight
+ */
+static void pd_gfsm_state_add_weight(t_pd_gfsm_state *x,
+ t_float fto,
+ t_float flo,
+ t_float fhi,
+ t_float w)
+{
+ gfsmStateId to = (fto < 0 ? (-fto) : ((gfsmStateId)fto));
+ gfsmLabelVal lo = (flo < 0 ? gfsmNoLabel : ((gfsmLabelVal)flo));
+ gfsmLabelVal hi = (fhi < 0 ? gfsmNoLabel : ((gfsmLabelVal)fhi));
+
+ if (x->x_open) pd_gfsm_state_arc_reset(x);
+
+ gfsm_arciter_open(&x->x_arci, x->x_automaton_pd->x_automaton, x->x_id);
+ gfsm_arciter_seek_both(&x->x_arci, lo, hi);
+
+ if (gfsm_arciter_ok(&x->x_arci)) {
+ gfsm_arciter_arc(&x->x_arci)->weight += w;
+ } else {
+ if (lo==gfsmNoLabel) lo = gfsmEpsilon;
+ if (hi==gfsmNoLabel) hi = gfsmEpsilon;
+ gfsm_automaton_add_arc(x->x_automaton_pd->x_automaton, x->x_id, to, lo, hi, w);
+ }
+
+ pd_gfsm_state_arc_reset(x);
+}
+
+
+
+/*=====================================================================
+ * Setup
+ */
+
+/*--------------------------------------------------------------------
+ * setup()
+ */
+void pd_gfsm_state_setup(void)
+{
+ //-- class
+ pd_gfsm_state_class = class_new(gensym("gfsm_state"),
+ (t_newmethod)pd_gfsm_state_new,
+ (t_method)pd_gfsm_state_free,
+ sizeof(t_pd_gfsm_state),
+ CLASS_DEFAULT,
+ A_GIMME, A_NULL);
+
+ //-- methods: automaton
+ class_addmethod(pd_gfsm_state_class,
+ (t_method)pd_gfsm_state_automaton,
+ gensym("automaton"),
+ A_DEFSYM, A_NULL);
+
+ //-- methods: id
+ class_addmethod(pd_gfsm_state_class, (t_method)pd_gfsm_state_id,
+ gensym("id"), A_NULL);
+ class_addmethod(pd_gfsm_state_class, (t_method)pd_gfsm_state_set,
+ gensym("set"), A_DEFFLOAT, A_NULL);
+
+ //-- methods: degree
+ class_addmethod(pd_gfsm_state_class, (t_method)pd_gfsm_state_degree,
+ gensym("degree"), A_NULL);
+
+ //-- methods: navigation
+ class_addmethod(pd_gfsm_state_class, (t_method)pd_gfsm_state_arc_first,
+ gensym("arc_first"), A_NULL);
+ class_addmethod(pd_gfsm_state_class, (t_method)pd_gfsm_state_arc_next,
+ gensym("arc_next"), A_NULL);
+ class_addmethod(pd_gfsm_state_class, (t_method)pd_gfsm_state_arc_seek,
+ gensym("arc_seek"), A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(pd_gfsm_state_class, (t_method)pd_gfsm_state_arc_reset,
+ gensym("arc_reset"), A_NULL);
+
+ //-- methods: manipulation
+ class_addmethod(pd_gfsm_state_class, (t_method)pd_gfsm_state_add_weight,
+ gensym("add_weight"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+
+ //-- help symbol
+ class_sethelpsymbol(pd_gfsm_state_class, gensym("gfsm_state-help.pd"));
+}
diff --git a/gfsm/src/pd_state.h b/gfsm/src/pd_state.h
new file mode 100644
index 0000000..b2e7576
--- /dev/null
+++ b/gfsm/src/pd_state.h
@@ -0,0 +1,58 @@
+/*=============================================================================*\
+ * File: pd_state.h
+ * Author: Bryan Jurish <moocow@ling.uni-potsdam.de>
+ * Description: finite state automata for Pd
+ *
+ * Copyright (c) 2004 Bryan Jurish.
+ *
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * See file LICENSE for further informations on licensing terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *=============================================================================*/
+
+/*=====================================================================
+ * Protos
+ *=====================================================================*/
+#ifndef PD_GFSM_STATE_H
+#define PD_GFSM_STATE_H
+
+/*----------------------------------------------------------------------
+ * includes
+ */
+#include <pd_automaton.h>
+
+/*--------------------------------------------------------------
+ * pd_fsm_automaton_pd
+ */
+typedef struct _pd_gfsm_state
+{
+ t_object x_obj;
+ t_pd_gfsm_automaton_pd *x_automaton_pd;
+ gfsmStateId x_id;
+ gfsmArcIter x_arci;
+ gboolean x_open;
+ t_atom x_argv[4];
+ t_outlet *x_valout;
+} t_pd_gfsm_state;
+
+/*----------------------------------------------------------------------
+ * setup routines
+ */
+void pd_gfsm_state_setup(void);
+
+#endif /* PD_GFSM_STATE_H */
diff --git a/gfsm/src/test-alphabet.pd b/gfsm/src/test-alphabet.pd
new file mode 100644
index 0000000..4434b96
--- /dev/null
+++ b/gfsm/src/test-alphabet.pd
@@ -0,0 +1,3 @@
+#N canvas 0 0 450 300 10;
+#X obj 366 21 fsm;
+#X obj 130 127 fsm_alphabet;
diff --git a/gfsm/src/test-alphabet2.pd b/gfsm/src/test-alphabet2.pd
new file mode 100644
index 0000000..04e5928
--- /dev/null
+++ b/gfsm/src/test-alphabet2.pd
@@ -0,0 +1,44 @@
+#N canvas 484 16 460 391 10;
+#X obj 33 324 print LEFT;
+#X obj 112 324 print RIGHT;
+#X msg 24 13 alphabet foo;
+#X msg 30 37 alphabet;
+#X msg 132 7 insert x;
+#X msg 136 29 insert life 42;
+#X msg 201 79 atom2char x;
+#X msg 218 135 char2atom 42;
+#X msg 262 246 clear;
+#X msg 204 100 a2c life;
+#X msg 219 154 c2a 1;
+#X msg 262 274 print;
+#X floatatom 316 171 8 0 0 0 - - -;
+#X msg 317 191 insert z \$1;
+#X msg 405 190 c2a \$1;
+#X floatatom 408 171 5 0 0 0 - - -;
+#X msg 325 95 a2c \$1;
+#X msg 321 42 x;
+#X msg 349 42 life;
+#X msg 385 41 z;
+#X obj 324 73 symbol;
+#X obj 33 302 gfsm_alphabet foo;
+#X connect 2 0 21 0;
+#X connect 3 0 21 0;
+#X connect 4 0 21 0;
+#X connect 5 0 21 0;
+#X connect 6 0 21 0;
+#X connect 7 0 21 0;
+#X connect 8 0 21 0;
+#X connect 9 0 21 0;
+#X connect 10 0 21 0;
+#X connect 11 0 21 0;
+#X connect 12 0 13 0;
+#X connect 13 0 21 0;
+#X connect 14 0 21 0;
+#X connect 15 0 14 0;
+#X connect 16 0 21 0;
+#X connect 17 0 20 0;
+#X connect 18 0 20 0;
+#X connect 19 0 20 0;
+#X connect 20 0 16 0;
+#X connect 21 0 0 0;
+#X connect 21 1 1 0;
diff --git a/gfsm/src/test-automaton.pd b/gfsm/src/test-automaton.pd
new file mode 100644
index 0000000..6cdf837
--- /dev/null
+++ b/gfsm/src/test-automaton.pd
@@ -0,0 +1,260 @@
+#N canvas 31 7 974 447 10;
+#X obj 13 7 gfsm;
+#X obj 22 324 gfsm_automaton;
+#X obj 22 359 print GFSM-1;
+#X msg 26 70 automaton;
+#X msg 24 29 automaton a1;
+#X obj 16 91 s \$0-fsm;
+#X obj 23 300 r \$0-fsm;
+#X msg 153 75 size;
+#X floatatom 237 34 5 0 0 0 - - -;
+#X obj 237 16 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 144 34 5 0 0 0 - - -;
+#X msg 257 15 0;
+#X msg 145 13 42;
+#X floatatom 375 18 5 0 0 0 - - -;
+#X msg 347 17 0;
+#X floatatom 388 61 5 0 0 0 - - -;
+#X floatatom 517 34 5 0 0 0 - - -;
+#X floatatom 560 33 5 0 0 0 - - -;
+#X floatatom 603 33 5 0 0 0 - - -;
+#X floatatom 644 34 5 0 0 0 - - -;
+#X obj 543 59 pack 0 0 0 0 0;
+#X obj 494 24 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 494 57 t b b;
+#X msg 569 7 0;
+#X msg 495 105 add_arc \$1 \$2 \$3 \$4 \$5;
+#X obj 144 98 s \$0-fsm;
+#X obj 237 97 s \$0-fsm;
+#X obj 349 121 s \$0-fsm;
+#X obj 496 126 s \$0-fsm;
+#X msg 104 148 load test.tfst;
+#X msg 103 188 save tmp.tfst;
+#X msg 229 148 load_bin test.gfst;
+#X msg 250 304 save_bin tmp.gfst;
+#X msg 26 202 print;
+#X msg 22 179 clear;
+#X msg 18 158 info;
+#X obj 17 226 s \$0-fsm;
+#X obj 88 246 s \$0-fsm;
+#X obj 236 338 s \$0-fsm;
+#X msg 437 170 complement;
+#X msg 450 211 closure \$1;
+#X floatatom 466 193 5 0 0 0 - - -;
+#X obj 437 370 s \$0-fsm;
+#X obj 16 132 bng 20 250 50 0 \$0-draw-s empty DRAW 0 -6 0 8 -24198
+-1 -1;
+#X obj 450 193 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 457 236 compose a2;
+#X msg 462 264 concat a2;
+#X obj 51 6 zexy;
+#X obj 495 84 lister;
+#X msg 25 48 automaton a2;
+#X msg 464 291 determinize;
+#X msg 469 319 difference a2;
+#X msg 475 343 intersect a2;
+#X obj 603 368 s \$0-fsm;
+#X msg 598 148 invert;
+#X msg 607 174 product a2;
+#X msg 621 217 project \$1;
+#X floatatom 638 196 5 0 0 0 - - -;
+#X obj 619 198 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 631 269 reverse;
+#X msg 631 296 rmepsilon;
+#X msg 634 320 union a2;
+#X msg 103 168 load test2.tfst;
+#X msg 233 169 load_bin test2.gfst;
+#X msg 238 190 load_bin test3.gfst;
+#X obj 46 131 tgl 20 0 \$0-drawmode-s empty mode 0 -6 0 8 -225271 -1
+-1 0 1;
+#X msg 246 74 root;
+#X msg 237 51 root \$1;
+#X floatatom 618 8 5 0 0 0 - - -;
+#X msg 144 52 size \$1;
+#X msg 349 37 final \$1;
+#X obj 430 61 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 365 79 pack 0 0;
+#X msg 363 99 final \$1 \$2;
+#X msg 637 343 renumber;
+#X msg 252 282 load_bin tmp.gfst;
+#N canvas 0 0 450 300 flags 0;
+#X obj 26 67 s \$0-fsm;
+#X msg 36 21 weighted \$1;
+#X obj 19 21 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X msg 39 43 weighted;
+#X obj 145 19 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 155 65 s \$0-fsm;
+#X msg 162 19 transducer \$1;
+#X msg 165 41 transducer;
+#X obj 30 220 s \$0-fsm;
+#X msg 40 196 semiring;
+#X msg 30 174 semiring \$1;
+#X msg 29 125 boolean;
+#X msg 90 125 log;
+#X msg 122 126 real;
+#X msg 160 125 trivial;
+#X msg 218 125 tropical;
+#X obj 30 153 symbol;
+#X msg 286 125 OTHER;
+#X connect 1 0 0 0;
+#X connect 2 0 1 0;
+#X connect 3 0 0 0;
+#X connect 4 0 6 0;
+#X connect 6 0 5 0;
+#X connect 7 0 5 0;
+#X connect 9 0 8 0;
+#X connect 10 0 8 0;
+#X connect 11 0 16 0;
+#X connect 12 0 16 0;
+#X connect 13 0 16 0;
+#X connect 14 0 16 0;
+#X connect 15 0 16 0;
+#X connect 16 0 10 0;
+#X connect 17 0 16 0;
+#X restore 711 65 pd flags;
+#X obj 600 8 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 361 336 concat a1;
+#X floatatom 689 35 5 0 0 0 - - -;
+#X obj 366 59 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 113 360 s \$0-fsm-out;
+#X obj 741 16 pool;
+#X msg 94 120 automaton fsm-help;
+#X msg 105 220 load gfsm-help.tfst;
+#N canvas 22 7 466 454 draw 0;
+#X obj 361 16 zexy;
+#X obj 26 15 r \$0-draw-s;
+#X obj 68 68 f \$0;
+#X obj 68 110 s \$0-fsm;
+#X obj 68 47 t b;
+#X obj 99 352 t b;
+#X obj 98 418 shell;
+#X obj 172 20 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 69 331 shell;
+#X obj 125 215 r \$0-drawmode-s;
+#X obj 67 238 demux 0 1;
+#X obj 240 214 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X msg 68 89 draw_dot \$1draw.dot;
+#X obj 67 136 r \$0-fsm-out;
+#X obj 67 158 route draw_dot;
+#X obj 67 180 symbol;
+#X msg 48 295 dotgv.sh \$1;
+#X msg 145 294 dotty \$1;
+#X obj 67 203 t s s;
+#X obj 98 372 symbol;
+#X msg 98 395 rm -f \$1;
+#X connect 1 0 4 0;
+#X connect 2 0 12 0;
+#X connect 4 0 2 0;
+#X connect 5 0 19 0;
+#X connect 7 0 4 0;
+#X connect 8 1 5 0;
+#X connect 9 0 10 1;
+#X connect 10 0 16 0;
+#X connect 10 1 17 0;
+#X connect 11 0 10 1;
+#X connect 12 0 3 0;
+#X connect 13 0 14 0;
+#X connect 14 0 15 0;
+#X connect 15 0 18 0;
+#X connect 16 0 8 0;
+#X connect 17 0 8 0;
+#X connect 18 0 10 0;
+#X connect 18 1 19 1;
+#X connect 19 0 20 0;
+#X connect 20 0 6 0;
+#X restore 16 251 pd draw;
+#X msg 258 216 load_bin lkptest.gfst;
+#X msg 261 238 load_bin lkpin.gfst;
+#X obj 21 385 gfsm_automaton a1;
+#X obj 22 404 gfsm_automaton a2;
+#X msg 626 245 connect;
+#X msg 739 352 clear;
+#X connect 1 0 2 0;
+#X connect 1 0 81 0;
+#X connect 3 0 5 0;
+#X connect 4 0 5 0;
+#X connect 6 0 1 0;
+#X connect 7 0 25 0;
+#X connect 8 0 67 0;
+#X connect 9 0 8 0;
+#X connect 10 0 69 0;
+#X connect 11 0 8 0;
+#X connect 12 0 10 0;
+#X connect 13 0 70 0;
+#X connect 14 0 13 0;
+#X connect 15 0 72 0;
+#X connect 16 0 20 0;
+#X connect 17 0 20 1;
+#X connect 18 0 20 2;
+#X connect 19 0 20 3;
+#X connect 20 0 48 1;
+#X connect 21 0 22 0;
+#X connect 22 0 48 0;
+#X connect 22 1 20 0;
+#X connect 23 0 16 0;
+#X connect 23 0 17 0;
+#X connect 23 0 18 0;
+#X connect 23 0 19 0;
+#X connect 24 0 28 0;
+#X connect 29 0 37 0;
+#X connect 30 0 37 0;
+#X connect 31 0 38 0;
+#X connect 32 0 38 0;
+#X connect 33 0 36 0;
+#X connect 34 0 36 0;
+#X connect 35 0 36 0;
+#X connect 39 0 42 0;
+#X connect 40 0 42 0;
+#X connect 41 0 40 0;
+#X connect 44 0 41 0;
+#X connect 45 0 42 0;
+#X connect 46 0 42 0;
+#X connect 48 0 24 0;
+#X connect 49 0 5 0;
+#X connect 50 0 42 0;
+#X connect 51 0 42 0;
+#X connect 52 0 42 0;
+#X connect 54 0 53 0;
+#X connect 55 0 53 0;
+#X connect 56 0 53 0;
+#X connect 57 0 56 0;
+#X connect 58 0 57 0;
+#X connect 59 0 53 0;
+#X connect 60 0 53 0;
+#X connect 61 0 53 0;
+#X connect 62 0 37 0;
+#X connect 63 0 38 0;
+#X connect 64 0 38 0;
+#X connect 66 0 26 0;
+#X connect 67 0 26 0;
+#X connect 68 0 17 0;
+#X connect 68 0 18 0;
+#X connect 68 0 19 0;
+#X connect 69 0 25 0;
+#X connect 70 0 27 0;
+#X connect 71 0 72 1;
+#X connect 72 0 73 0;
+#X connect 73 0 27 0;
+#X connect 74 0 53 0;
+#X connect 75 0 38 0;
+#X connect 77 0 68 0;
+#X connect 78 0 42 0;
+#X connect 79 0 20 4;
+#X connect 80 0 15 0;
+#X connect 83 0 5 0;
+#X connect 84 0 37 0;
+#X connect 86 0 38 0;
+#X connect 87 0 38 0;
+#X connect 90 0 53 0;
+#X connect 91 0 53 0;
diff --git a/gfsm/src/test-automaton2.pd b/gfsm/src/test-automaton2.pd
new file mode 100644
index 0000000..f503014
--- /dev/null
+++ b/gfsm/src/test-automaton2.pd
@@ -0,0 +1,196 @@
+#N canvas 110 261 845 398 10;
+#X obj 13 7 gfsm;
+#X obj 23 362 print GFSM-1;
+#X obj 116 362 print GFSM-2;
+#X obj 208 363 print GFSM-3;
+#X msg 26 70 automaton;
+#X msg 24 29 automaton a1;
+#X obj 16 91 s \$0-fsm;
+#X obj 93 294 r \$0-fsm;
+#X msg 153 75 size;
+#X floatatom 237 34 5 0 0 0 - - -;
+#X obj 237 16 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 237 51 set_root \$1;
+#X msg 246 74 get_root;
+#X msg 144 52 reserve \$1;
+#X floatatom 144 34 5 0 0 0 - - -;
+#X msg 257 15 0;
+#X msg 145 13 42;
+#X msg 349 37 is_final \$1;
+#X floatatom 375 18 5 0 0 0 - - -;
+#X msg 347 17 0;
+#X floatatom 388 61 5 0 0 0 - - -;
+#X msg 360 60 0;
+#X msg 363 80 set_final \$1 1;
+#X floatatom 517 34 5 0 0 0 - - -;
+#X floatatom 560 33 5 0 0 0 - - -;
+#X floatatom 603 33 5 0 0 0 - - -;
+#X floatatom 644 34 5 0 0 0 - - -;
+#X obj 543 59 pack 0 0 0 0 0;
+#X obj 494 24 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 494 57 t b b;
+#X msg 569 7 0;
+#X msg 495 105 add_arc \$1 \$2 \$3 \$4 \$5;
+#X obj 144 98 s \$0-fsm;
+#X obj 237 97 s \$0-fsm;
+#X obj 349 102 s \$0-fsm;
+#X obj 496 126 s \$0-fsm;
+#X msg 104 148 load test.tfst;
+#X msg 103 188 save tmp.tfst;
+#X msg 229 148 load_bin test.gfst;
+#X msg 234 232 save_bin tmp.gfst;
+#X msg 26 202 print;
+#X msg 22 179 clear;
+#X msg 18 158 info;
+#X obj 16 224 s \$0-fsm;
+#X obj 95 209 s \$0-fsm;
+#X obj 228 254 s \$0-fsm;
+#X msg 437 170 complement;
+#X msg 450 211 closure \$1;
+#X floatatom 466 193 5 0 0 0 - - -;
+#X obj 437 370 s \$0-fsm;
+#X obj 16 132 bng 20 250 50 0 \$0-draw-s empty DRAW 0 -6 0 8 -24198
+-1 -1;
+#X obj 450 193 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 457 236 compose a2;
+#X msg 462 264 concat a2;
+#X obj 51 6 zexy;
+#X obj 495 84 lister;
+#X msg 25 48 automaton a2;
+#X msg 464 291 determinize;
+#X msg 469 319 difference a2;
+#X msg 475 343 intersect a2;
+#X obj 603 368 s \$0-fsm;
+#X msg 603 165 invert;
+#X msg 612 191 product a2;
+#X msg 626 234 project \$1;
+#X floatatom 643 213 5 0 0 0 - - -;
+#X obj 624 215 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 631 262 prune;
+#X msg 636 286 reverse;
+#X msg 636 313 rmepsilon;
+#X msg 639 337 union a2;
+#X msg 103 168 load test2.tfst;
+#X msg 233 169 load_bin test2.gfst;
+#X obj 92 318 gfsm_automaton a2;
+#X msg 238 190 load_bin test3.gfst;
+#X floatatom 626 5 5 0 0 0 - - -;
+#N canvas 0 0 466 454 draw 0;
+#X obj 67 25 r \$0-draw-s;
+#X obj 68 68 f \$0;
+#X msg 176 74 save_bin \$1draw.gfst;
+#X obj 176 98 s \$0-fsm;
+#X obj 68 162 shell;
+#X obj 68 47 t b;
+#X obj 68 91 t f f;
+#X msg 69 237 dotgv.sh \$1draw.dot;
+#X obj 171 311 f \$0;
+#X obj 172 291 t b;
+#X obj 171 357 shell;
+#X obj 172 20 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 68 137 gfsmdraw \$1draw.gfst -F \$1draw.dot;
+#X msg 171 334 rm -f \$1draw.gfst \$1draw.dot;
+#X obj 142 270 shell;
+#X msg 220 236 dotty \$1draw.dot;
+#X obj 169 183 r \$0-drawmode-s;
+#X obj 111 206 demux 0 1;
+#X obj 110 163 t b;
+#X obj 111 184 f \$0;
+#X obj 284 182 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X connect 0 0 5 0;
+#X connect 1 0 6 0;
+#X connect 2 0 3 0;
+#X connect 4 1 18 0;
+#X connect 5 0 1 0;
+#X connect 6 0 12 0;
+#X connect 6 1 2 0;
+#X connect 7 0 14 0;
+#X connect 8 0 13 0;
+#X connect 9 0 8 0;
+#X connect 11 0 5 0;
+#X connect 12 0 4 0;
+#X connect 13 0 10 0;
+#X connect 14 1 9 0;
+#X connect 15 0 14 0;
+#X connect 16 0 17 1;
+#X connect 17 0 7 0;
+#X connect 17 1 15 0;
+#X connect 18 0 19 0;
+#X connect 19 0 17 0;
+#X connect 20 0 17 1;
+#X restore 71 118 pd draw;
+#X obj 44 130 tgl 20 0 \$0-drawmode-s empty mode 0 -6 0 8 -225271 -1
+-1 0 1;
+#X msg 152 120 automaton fsm-help-2;
+#X connect 4 0 6 0;
+#X connect 5 0 6 0;
+#X connect 7 0 72 0;
+#X connect 8 0 32 0;
+#X connect 9 0 11 0;
+#X connect 10 0 9 0;
+#X connect 11 0 33 0;
+#X connect 12 0 33 0;
+#X connect 13 0 32 0;
+#X connect 14 0 13 0;
+#X connect 15 0 9 0;
+#X connect 16 0 14 0;
+#X connect 17 0 34 0;
+#X connect 18 0 17 0;
+#X connect 19 0 18 0;
+#X connect 20 0 22 0;
+#X connect 21 0 20 0;
+#X connect 22 0 34 0;
+#X connect 23 0 27 0;
+#X connect 24 0 27 1;
+#X connect 25 0 27 2;
+#X connect 26 0 27 3;
+#X connect 27 0 55 1;
+#X connect 28 0 29 0;
+#X connect 29 0 55 0;
+#X connect 29 1 27 0;
+#X connect 30 0 23 0;
+#X connect 30 0 24 0;
+#X connect 30 0 25 0;
+#X connect 30 0 26 0;
+#X connect 31 0 35 0;
+#X connect 36 0 44 0;
+#X connect 37 0 44 0;
+#X connect 38 0 45 0;
+#X connect 39 0 45 0;
+#X connect 40 0 43 0;
+#X connect 41 0 43 0;
+#X connect 42 0 43 0;
+#X connect 46 0 49 0;
+#X connect 47 0 49 0;
+#X connect 48 0 47 0;
+#X connect 51 0 48 0;
+#X connect 52 0 49 0;
+#X connect 53 0 49 0;
+#X connect 55 0 31 0;
+#X connect 56 0 6 0;
+#X connect 57 0 49 0;
+#X connect 58 0 49 0;
+#X connect 59 0 49 0;
+#X connect 61 0 60 0;
+#X connect 62 0 60 0;
+#X connect 63 0 60 0;
+#X connect 64 0 63 0;
+#X connect 65 0 64 0;
+#X connect 66 0 60 0;
+#X connect 67 0 60 0;
+#X connect 68 0 60 0;
+#X connect 69 0 60 0;
+#X connect 70 0 44 0;
+#X connect 71 0 45 0;
+#X connect 72 0 1 0;
+#X connect 73 0 45 0;
+#X connect 74 0 24 0;
+#X connect 74 0 25 0;
+#X connect 74 0 26 0;
+#X connect 77 0 6 0;
diff --git a/gfsm/src/test-fsm.pd b/gfsm/src/test-fsm.pd
new file mode 100644
index 0000000..ed74881
--- /dev/null
+++ b/gfsm/src/test-fsm.pd
@@ -0,0 +1,2 @@
+#N canvas 0 0 450 300 10;
+#X obj 166 146 fsm;
diff --git a/gfsm/src/test-markov.pd b/gfsm/src/test-markov.pd
new file mode 100644
index 0000000..7ab52e8
--- /dev/null
+++ b/gfsm/src/test-markov.pd
@@ -0,0 +1,211 @@
+#N canvas 79 27 832 322 10;
+#X obj 21 23 bng 20 250 50 0 \$0-draw-s empty DRAW 0 -6 0 8 -24198
+-1 -1;
+#N canvas 0 0 466 454 draw 0;
+#X obj 361 16 zexy;
+#X obj 67 25 r \$0-draw-s;
+#X obj 68 68 f \$0;
+#X obj 67 177 shell;
+#X obj 68 47 t b;
+#X obj 68 91 t f f;
+#X msg 68 252 dotgv.sh \$1draw.dot;
+#X obj 170 326 f \$0;
+#X obj 171 306 t b;
+#X obj 170 372 shell;
+#X obj 172 20 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 170 349 rm -f \$1draw.gfst \$1draw.dot;
+#X obj 141 285 shell;
+#X msg 219 251 dotty \$1draw.dot;
+#X obj 168 198 r \$0-drawmode-s;
+#X obj 110 221 demux 0 1;
+#X obj 109 178 t b;
+#X obj 110 199 f \$0;
+#X obj 283 197 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 176 98 s \$0-markov;
+#X msg 176 74 save_bin \$1draw;
+#X msg 68 137 gfsmdraw -i \$1draw.lab -o \$1draw.lab \$1draw.gfst -F
+\$1draw.dot;
+#X connect 1 0 4 0;
+#X connect 2 0 5 0;
+#X connect 3 1 16 0;
+#X connect 4 0 2 0;
+#X connect 5 0 21 0;
+#X connect 5 1 20 0;
+#X connect 6 0 12 0;
+#X connect 7 0 11 0;
+#X connect 8 0 7 0;
+#X connect 10 0 4 0;
+#X connect 11 0 9 0;
+#X connect 12 1 8 0;
+#X connect 13 0 12 0;
+#X connect 14 0 15 1;
+#X connect 15 0 6 0;
+#X connect 15 1 13 0;
+#X connect 16 0 17 0;
+#X connect 17 0 15 0;
+#X connect 18 0 15 1;
+#X connect 20 0 19 0;
+#X connect 21 0 3 0;
+#X restore 22 47 pd draw;
+#X obj 34 203 r \$0-markov;
+#X obj 104 6 bng 15 250 50 0 empty empty empty 0 -6 0 8 -225280 -1
+-1;
+#X obj 104 24 openpanel;
+#X msg 104 90 load_bin \$1;
+#X obj 104 68 symbol;
+#X msg 111 45 markov;
+#X obj 103 110 s \$0-markov;
+#X obj 204 6 bng 15 250 50 0 empty empty empty 0 -6 0 8 -228992 -1
+-1;
+#X obj 204 68 symbol;
+#X obj 203 110 s \$0-markov;
+#X obj 204 24 savepanel;
+#X msg 204 90 save_bin \$1;
+#X msg 211 45 markov2;
+#X obj 49 22 tgl 20 0 \$0-drawmode-s empty mode 0 -6 0 8 -225271 -1
+-1 0 1;
+#X msg 336 8 fsm info;
+#X msg 342 28 clear;
+#X obj 336 75 s \$0-markov;
+#X msg 339 151 next;
+#X obj 339 172 s \$0-markov;
+#X obj 339 108 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 339 127 metro 500;
+#X obj 302 153 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 364 107 6 0 0 0 - - -;
+#X msg 382 255 add1 \$1;
+#X floatatom 341 207 5 0 0 0 - - -;
+#X msg 382 208 foo;
+#X msg 413 208 bar;
+#X msg 442 209 baz;
+#X obj 382 279 s \$0-markov;
+#X obj 34 225 gfsm_markov markov;
+#X obj 384 234 symbol;
+#X floatatom 481 210 5 0 0 0 - - -;
+#X msg 522 211 foo;
+#X msg 553 211 bar;
+#X msg 582 212 baz;
+#X obj 522 282 s \$0-markov;
+#X obj 524 237 symbol;
+#X msg 521 258 addi1 \$1;
+#X msg 349 51 set;
+#X floatatom 538 57 5 0 0 0 - - -;
+#X msg 480 138 add1 \$1;
+#X floatatom 480 119 5 0 0 0 - - -;
+#X obj 539 170 s \$0-markov;
+#X floatatom 513 11 5 0 0 0 - - -;
+#X obj 480 29 metro 100;
+#X obj 480 11 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 480 98 + 1;
+#X floatatom 649 59 5 0 0 0 - - -;
+#X floatatom 591 121 5 0 0 0 - - -;
+#X floatatom 624 13 5 0 0 0 - - -;
+#X obj 591 31 metro 100;
+#X obj 591 13 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 591 100 + 1;
+#X msg 591 140 addi1 \$1;
+#X obj 480 77 random 16;
+#X obj 591 79 random 16;
+#X obj 34 260 spigot;
+#X obj 83 262 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 687 207 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 687 227 metro 2000;
+#X floatatom 715 208 5 0 0 0 - - -;
+#X msg 689 247 set;
+#X obj 689 267 s \$0-markov;
+#X obj 667 227 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 692 117 5 0 0 0 - - -;
+#X msg 692 137 addi \$1 42 5;
+#X obj 32 284 print MARKOV-LO;
+#X obj 155 284 print MARKOV-HI;
+#X obj 175 241 print MARKOV-X;
+#X obj 152 262 spigot;
+#X obj 201 264 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X floatatom 706 52 5 0 0 0 - - -;
+#X msg 705 70 add \$1 24 5;
+#X msg 138 192 set 0 \, next;
+#X obj 176 219 spigot;
+#X obj 224 221 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X msg 162 45 big;
+#X msg 270 44 big2;
+#X msg 49 73 markov2;
+#X connect 2 0 31 0;
+#X connect 3 0 4 0;
+#X connect 4 0 6 0;
+#X connect 5 0 8 0;
+#X connect 6 0 5 0;
+#X connect 7 0 6 0;
+#X connect 9 0 12 0;
+#X connect 10 0 13 0;
+#X connect 12 0 10 0;
+#X connect 13 0 11 0;
+#X connect 14 0 10 0;
+#X connect 16 0 18 0;
+#X connect 17 0 18 0;
+#X connect 19 0 20 0;
+#X connect 21 0 22 0;
+#X connect 22 0 19 0;
+#X connect 24 0 22 1;
+#X connect 25 0 30 0;
+#X connect 26 0 25 0;
+#X connect 27 0 32 0;
+#X connect 28 0 32 0;
+#X connect 29 0 32 0;
+#X connect 31 0 58 0;
+#X connect 31 1 71 0;
+#X connect 31 2 75 0;
+#X connect 31 2 76 0;
+#X connect 32 0 25 0;
+#X connect 33 0 39 0;
+#X connect 34 0 38 0;
+#X connect 35 0 38 0;
+#X connect 36 0 38 0;
+#X connect 38 0 39 0;
+#X connect 39 0 37 0;
+#X connect 40 0 18 0;
+#X connect 41 0 56 1;
+#X connect 42 0 44 0;
+#X connect 43 0 42 0;
+#X connect 45 0 46 1;
+#X connect 46 0 56 0;
+#X connect 47 0 46 0;
+#X connect 48 0 43 0;
+#X connect 49 0 57 1;
+#X connect 50 0 55 0;
+#X connect 51 0 52 1;
+#X connect 52 0 57 0;
+#X connect 53 0 52 0;
+#X connect 54 0 50 0;
+#X connect 55 0 44 0;
+#X connect 56 0 48 0;
+#X connect 57 0 54 0;
+#X connect 58 0 68 0;
+#X connect 59 0 58 1;
+#X connect 60 0 61 0;
+#X connect 61 0 63 0;
+#X connect 61 0 65 0;
+#X connect 62 0 61 1;
+#X connect 63 0 64 0;
+#X connect 66 0 67 0;
+#X connect 67 0 44 0;
+#X connect 71 0 69 0;
+#X connect 72 0 71 1;
+#X connect 73 0 74 0;
+#X connect 74 0 44 0;
+#X connect 75 0 31 0;
+#X connect 76 0 70 0;
+#X connect 77 0 76 1;
+#X connect 78 0 6 0;
+#X connect 79 0 10 0;
+#X connect 80 0 6 0;
diff --git a/gfsm/src/test-state.pd b/gfsm/src/test-state.pd
new file mode 100644
index 0000000..2ee2b77
--- /dev/null
+++ b/gfsm/src/test-state.pd
@@ -0,0 +1,427 @@
+#N canvas 430 0 616 494 10;
+#X obj 13 7 gfsm;
+#X msg 23 84 automaton;
+#X msg 21 43 automaton a1;
+#X obj 51 6 zexy;
+#X msg 22 62 automaton a2;
+#X obj 30 285 r \$0-state;
+#X obj 19 332 print STATE-1;
+#X obj 136 76 s \$0-state;
+#X msg 150 48 id;
+#X msg 136 27 set \$1;
+#X floatatom 153 9 5 0 0 0 - - -;
+#X obj 19 308 gfsm_state a1;
+#X obj 135 10 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 218 11 degree;
+#X obj 218 74 s \$0-state;
+#X msg 25 147 arc_first;
+#X msg 29 171 arc_next;
+#X obj 243 314 gfsm_automaton a1;
+#X obj 243 180 bng 15 250 50 0 empty empty empty 0 -6 0 8 -225280 -1
+-1;
+#X obj 243 198 openpanel;
+#X msg 243 264 load_bin \$1;
+#X obj 243 335 print A1-1;
+#X obj 254 293 r \$0-fsm;
+#X obj 337 226 bng 20 250 50 0 \$0-draw-s empty DRAW 0 -6 0 8 -24198
+-1 -1;
+#N canvas 0 0 466 454 draw 0;
+#X obj 361 16 zexy;
+#X obj 67 25 r \$0-draw-s;
+#X obj 68 68 f \$0;
+#X msg 176 74 save_bin \$1draw.gfst;
+#X obj 176 98 s \$0-fsm;
+#X obj 68 162 shell;
+#X obj 68 47 t b;
+#X obj 68 91 t f f;
+#X msg 69 237 dotgv.sh \$1draw.dot;
+#X obj 171 311 f \$0;
+#X obj 172 291 t b;
+#X obj 171 357 shell;
+#X obj 172 20 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 68 137 gfsmdraw \$1draw.gfst -F \$1draw.dot;
+#X msg 171 334 rm -f \$1draw.gfst \$1draw.dot;
+#X obj 142 270 shell;
+#X msg 220 236 dotty \$1draw.dot;
+#X obj 169 183 r \$0-drawmode-s;
+#X obj 111 206 demux 0 1;
+#X obj 110 163 t b;
+#X obj 111 184 f \$0;
+#X obj 284 182 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X connect 1 0 6 0;
+#X connect 2 0 7 0;
+#X connect 3 0 4 0;
+#X connect 5 1 19 0;
+#X connect 6 0 2 0;
+#X connect 7 0 13 0;
+#X connect 7 1 3 0;
+#X connect 8 0 15 0;
+#X connect 9 0 14 0;
+#X connect 10 0 9 0;
+#X connect 12 0 6 0;
+#X connect 13 0 5 0;
+#X connect 14 0 11 0;
+#X connect 15 1 10 0;
+#X connect 16 0 15 0;
+#X connect 17 0 18 1;
+#X connect 18 0 8 0;
+#X connect 18 1 16 0;
+#X connect 19 0 20 0;
+#X connect 20 0 18 0;
+#X connect 21 0 18 1;
+#X restore 338 250 pd draw;
+#X obj 365 226 tgl 20 0 \$0-drawmode-s empty mode 0 -6 0 8 -225271
+-1 -1 0 1;
+#X msg 250 219 test3.gfst;
+#X obj 243 242 symbol;
+#X obj 115 141 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#N canvas 38 17 452 375 weight_sum 0;
+#X obj 34 11 inlet;
+#X msg 34 61 arc_first;
+#X msg 46 88 arc_next;
+#X obj 34 292 f 0;
+#X obj 238 59 0;
+#X obj 34 177 route arc_first arc_next;
+#X obj 34 203 route bang;
+#X obj 99 222 t b l;
+#X obj 129 244 unpack 0 0 0 0;
+#X obj 222 268 + 0;
+#X obj 178 267 t f f;
+#X obj 87 11 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 34 323 outlet;
+#X obj 34 224 t b;
+#X obj 34 143 gfsm_state a1 0;
+#X obj 45 119 r \$0-state;
+#X obj 88 323 s \$0-wsum-out;
+#X obj 113 13 r \$0-wsum-in;
+#X obj 71 250 delay 1;
+#X obj 34 33 t b b b;
+#X msg 290 56 stop;
+#X floatatom 240 293 5 0 0 0 - - -;
+#X obj 322 168 until;
+#X connect 0 0 19 0;
+#X connect 1 0 14 0;
+#X connect 2 0 14 0;
+#X connect 3 0 12 0;
+#X connect 3 0 16 0;
+#X connect 4 0 9 1;
+#X connect 5 0 6 0;
+#X connect 5 1 6 0;
+#X connect 6 0 13 0;
+#X connect 6 1 7 0;
+#X connect 7 0 18 0;
+#X connect 7 1 8 0;
+#X connect 8 3 9 0;
+#X connect 9 0 10 0;
+#X connect 9 0 21 0;
+#X connect 10 0 9 1;
+#X connect 10 1 3 1;
+#X connect 11 0 19 0;
+#X connect 13 0 3 0;
+#X connect 14 0 5 0;
+#X connect 15 0 14 0;
+#X connect 17 0 19 0;
+#X connect 18 0 2 0;
+#X connect 19 0 1 0;
+#X connect 19 1 4 0;
+#X connect 19 2 20 0;
+#X connect 20 0 18 0;
+#X restore 115 161 pd weight_sum;
+#X obj 114 332 s \$0-state-out;
+#X floatatom 114 182 8 0 0 0 - - -;
+#X obj 114 224 print WSUM;
+#X obj 252 97 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#N canvas 302 0 392 492 rand_arc 0;
+#X obj 40 9 inlet;
+#X obj 83 9 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 -1
+;
+#X msg 41 56 arc_first;
+#X msg 56 93 arc_next;
+#X obj 41 177 route arc_first arc_next;
+#X obj 41 203 route bang;
+#X obj 150 244 unpack 0 0 0 0;
+#X obj 41 451 outlet;
+#X obj 41 143 gfsm_state a1 0;
+#X obj 77 122 r \$0-state;
+#X obj 257 73 s \$0-wsum-in;
+#X obj 259 95 r \$0-wsum-out;
+#X obj 259 142 random 131072;
+#X obj 259 116 t b f;
+#X obj 259 166 / 131072;
+#X obj 259 190 * 1;
+#X obj 41 224 t b;
+#X obj 243 316 moses 0;
+#X obj 259 213 * -1;
+#X obj 243 271 + 0;
+#X obj 243 294 t f f;
+#X obj 242 335 t b b;
+#X obj 128 403 spigot;
+#X obj 165 381 0;
+#X obj 192 381 1;
+#X obj 106 306 spigot;
+#X obj 106 222 t b l l;
+#X obj 286 335 t b b;
+#X obj 169 284 0;
+#X obj 143 284 1;
+#X obj 107 10 r \$0-randarc-in;
+#X obj 92 451 s \$0-randarc-out;
+#X obj 81 326 delay 1;
+#X obj 41 30 t b b b;
+#X msg 177 127 stop;
+#X connect 0 0 33 0;
+#X connect 1 0 33 0;
+#X connect 2 0 8 0;
+#X connect 3 0 8 0;
+#X connect 4 0 5 0;
+#X connect 4 1 5 0;
+#X connect 5 0 16 0;
+#X connect 5 1 26 0;
+#X connect 6 3 19 0;
+#X connect 8 0 4 0;
+#X connect 9 0 8 0;
+#X connect 11 0 13 0;
+#X connect 12 0 14 0;
+#X connect 13 0 12 0;
+#X connect 13 1 15 1;
+#X connect 14 0 15 0;
+#X connect 15 0 18 0;
+#X connect 16 0 7 0;
+#X connect 16 0 31 0;
+#X connect 17 0 21 0;
+#X connect 17 1 27 0;
+#X connect 18 0 19 1;
+#X connect 19 0 20 0;
+#X connect 20 0 17 0;
+#X connect 20 1 19 1;
+#X connect 21 0 29 0;
+#X connect 21 1 23 0;
+#X connect 22 0 7 0;
+#X connect 22 0 31 0;
+#X connect 23 0 22 1;
+#X connect 24 0 22 1;
+#X connect 25 0 32 0;
+#X connect 26 0 25 0;
+#X connect 26 1 22 0;
+#X connect 26 2 6 0;
+#X connect 27 0 24 0;
+#X connect 27 1 28 0;
+#X connect 28 0 25 1;
+#X connect 29 0 25 1;
+#X connect 30 0 33 0;
+#X connect 32 0 3 0;
+#X connect 33 0 2 0;
+#X connect 33 1 10 0;
+#X connect 33 2 34 0;
+#X connect 34 0 32 0;
+#X restore 252 116 pd rand_arc;
+#X obj 395 113 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#N canvas 102 2 392 492 rand_incr 0;
+#X obj 40 9 inlet;
+#X obj 83 9 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 -1
+;
+#X obj 41 54 s \$0-randarc-in;
+#X obj 43 76 r \$0-randarc-out;
+#X obj 42 98 route bang;
+#X obj 41 30 t b;
+#X obj 42 177 gfsm_automaton a1;
+#X obj 209 157 unpack 0 0 0 0;
+#X obj 55 154 r \$0-automaton;
+#X msg 42 131 root;
+#X obj 42 199 route root;
+#X obj 42 221 route bang;
+#X obj 107 336 outlet;
+#X obj 211 337 outlet;
+#X obj 271 335 outlet;
+#X msg 8 247 root 0;
+#X obj 107 254 t f f;
+#X obj 137 295 s \$0-state;
+#X msg 137 274 set \$1;
+#X obj 326 336 outlet;
+#X connect 0 0 5 0;
+#X connect 1 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 9 0;
+#X connect 4 1 7 0;
+#X connect 5 0 2 0;
+#X connect 6 0 10 0;
+#X connect 7 0 16 0;
+#X connect 7 1 13 0;
+#X connect 7 2 14 0;
+#X connect 7 3 19 0;
+#X connect 8 0 6 0;
+#X connect 9 0 6 0;
+#X connect 10 0 11 0;
+#X connect 11 0 15 0;
+#X connect 11 1 16 0;
+#X connect 15 0 6 0;
+#X connect 16 0 12 0;
+#X connect 16 1 18 0;
+#X connect 18 0 17 0;
+#X restore 395 132 pd rand_incr;
+#X obj 254 157 print RAND_ARC;
+#X obj 336 33 s \$0-state;
+#X obj 326 54 s \$0-fsm;
+#X obj 13 105 s \$0-automaton;
+#X obj 326 12 r \$0-automaton;
+#X obj 21 197 s \$0-state-a;
+#X obj 19 262 r \$0-state-a;
+#X obj 195 192 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 230 140 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 470 10 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 493 10 5 0 0 0 - - -;
+#X obj 471 30 metro 1000;
+#X obj 417 300 gfsm_alphabet alph1;
+#X obj 518 214 bng 15 250 50 0 empty empty empty 0 -6 0 8 -225280 -1
+-1;
+#X obj 518 232 openpanel;
+#X obj 518 254 symbol;
+#X msg 518 275 load \$1;
+#X obj 452 342 print RI-ATOM;
+#X msg 419 273 char2atom \$1;
+#X floatatom 436 245 5 0 0 0 - - -;
+#X obj 452 321 fromsymbol;
+#N canvas 0 0 450 300 ri_print 0;
+#X obj 48 22 inlet;
+#X obj 101 22 inlet;
+#X obj 155 22 inlet;
+#X obj 206 22 inlet;
+#X obj 319 22 inlet;
+#X obj 93 97 spigot;
+#X obj 93 57 pack 0 0 0 0;
+#X obj 93 122 unpack 0 0 0 0;
+#X obj 124 196 print RI-LO;
+#X obj 186 155 print RI-WT;
+#X obj 155 175 print RI-HI;
+#X obj 93 215 print RI-NXT;
+#X connect 0 0 6 0;
+#X connect 1 0 6 1;
+#X connect 2 0 6 2;
+#X connect 3 0 6 3;
+#X connect 4 0 5 1;
+#X connect 5 0 7 0;
+#X connect 6 0 5 0;
+#X connect 7 0 11 0;
+#X connect 7 1 8 0;
+#X connect 7 2 10 0;
+#X connect 7 3 9 0;
+#X restore 420 160 pd ri_print;
+#X obj 488 131 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 114 203 spigot;
+#X obj 162 203 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 253 138 spigot;
+#X obj 301 138 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 29 410 grattsdict;
+#X obj 247 417 gvol~;
+#X obj 246 454 dac~;
+#X obj 470 51 t b b;
+#X obj 475 100 spigot;
+#X msg 506 80 0;
+#X msg 534 80 1;
+#X obj 548 456 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#N canvas 0 0 450 300 load_dict 0;
+#X obj 31 16 inlet;
+#X obj 31 38 t b;
+#X msg 31 67 load /home/moocow/src/pd/externs/ratts/dict/beep-b.txt
+cr;
+#X obj 33 108 outlet;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X restore 30 391 pd load_dict;
+#X obj 31 371 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 366 367 gpratts~ 10 \$0p /gpratts;
+#X obj 171 396 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X msg 171 417 \; pd dsp \$1;
+#X obj 434 74 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 435 103 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 424 202 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 367 340 route 0;
+#X connect 1 0 40 0;
+#X connect 2 0 40 0;
+#X connect 4 0 40 0;
+#X connect 5 0 11 0;
+#X connect 8 0 7 0;
+#X connect 9 0 7 0;
+#X connect 10 0 9 0;
+#X connect 11 0 6 0;
+#X connect 11 0 30 0;
+#X connect 12 0 10 0;
+#X connect 13 0 14 0;
+#X connect 15 0 42 0;
+#X connect 16 0 42 0;
+#X connect 17 0 21 0;
+#X connect 18 0 19 0;
+#X connect 19 0 27 0;
+#X connect 20 0 17 0;
+#X connect 22 0 17 0;
+#X connect 26 0 27 0;
+#X connect 27 0 20 0;
+#X connect 28 0 29 0;
+#X connect 29 0 31 0;
+#X connect 29 0 44 0;
+#X connect 31 0 60 0;
+#X connect 33 0 34 0;
+#X connect 34 0 45 0;
+#X connect 34 0 62 0;
+#X connect 35 0 36 0;
+#X connect 36 0 58 0;
+#X connect 36 0 55 0;
+#X connect 36 0 79 0;
+#X connect 36 1 58 1;
+#X connect 36 2 58 2;
+#X connect 36 3 58 3;
+#X connect 41 0 39 0;
+#X connect 41 0 38 0;
+#X connect 43 0 11 0;
+#X connect 46 0 48 0;
+#X connect 47 0 48 1;
+#X connect 48 0 67 0;
+#X connect 49 1 57 0;
+#X connect 50 0 51 0;
+#X connect 51 0 52 0;
+#X connect 52 0 53 0;
+#X connect 53 0 49 0;
+#X connect 55 0 49 0;
+#X connect 56 0 55 0;
+#X connect 57 0 54 0;
+#X connect 57 0 80 0;
+#X connect 59 0 58 4;
+#X connect 60 0 32 0;
+#X connect 61 0 60 1;
+#X connect 62 0 37 0;
+#X connect 63 0 62 1;
+#X connect 65 0 66 0;
+#X connect 65 0 66 1;
+#X connect 67 0 69 0;
+#X connect 67 0 77 0;
+#X connect 67 1 68 0;
+#X connect 68 0 36 0;
+#X connect 68 0 78 0;
+#X connect 69 0 68 1;
+#X connect 70 0 68 1;
+#X connect 72 0 64 0;
+#X connect 73 0 72 0;
+#X connect 74 0 65 0;
+#X connect 74 1 71 0;
+#X connect 74 1 70 0;
+#X connect 75 0 76 0;
+#X connect 80 1 74 0;
diff --git a/gfsm/src/test-state2.pd b/gfsm/src/test-state2.pd
new file mode 100644
index 0000000..a9983d0
--- /dev/null
+++ b/gfsm/src/test-state2.pd
@@ -0,0 +1,415 @@
+#N canvas 346 27 616 494 10;
+#X obj 13 7 gfsm;
+#X msg 23 84 automaton;
+#X msg 21 43 automaton a1;
+#X obj 51 6 zexy;
+#X msg 22 62 automaton a2;
+#X obj 30 285 r \$0-state;
+#X obj 19 332 print STATE-1;
+#X obj 136 76 s \$0-state;
+#X msg 150 48 id;
+#X msg 136 27 set \$1;
+#X floatatom 153 9 5 0 0 0 - - -;
+#X obj 19 308 gfsm_state a1;
+#X obj 135 10 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 218 11 degree;
+#X obj 218 74 s \$0-state;
+#X msg 19 164 arc_first;
+#X msg 23 188 arc_next;
+#X obj 243 314 gfsm_automaton a1;
+#X obj 243 180 bng 15 250 50 0 empty empty empty 0 -6 0 8 -225280 -1
+-1;
+#X obj 243 198 openpanel;
+#X msg 243 264 load_bin \$1;
+#X obj 243 335 print A1-1;
+#X obj 254 293 r \$0-fsm;
+#X obj 337 226 bng 20 250 50 0 \$0-draw-s empty DRAW 0 -6 0 8 -24198
+-1 -1;
+#N canvas 0 0 466 454 draw 0;
+#X obj 361 16 zexy;
+#X obj 67 25 r \$0-draw-s;
+#X obj 68 68 f \$0;
+#X msg 176 74 save_bin \$1draw.gfst;
+#X obj 176 98 s \$0-fsm;
+#X obj 68 162 shell;
+#X obj 68 47 t b;
+#X obj 68 91 t f f;
+#X msg 69 237 dotgv.sh \$1draw.dot;
+#X obj 171 311 f \$0;
+#X obj 172 291 t b;
+#X obj 171 357 shell;
+#X obj 172 20 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 68 137 gfsmdraw \$1draw.gfst -F \$1draw.dot;
+#X msg 171 334 rm -f \$1draw.gfst \$1draw.dot;
+#X obj 142 270 shell;
+#X msg 220 236 dotty \$1draw.dot;
+#X obj 169 183 r \$0-drawmode-s;
+#X obj 111 206 demux 0 1;
+#X obj 110 163 t b;
+#X obj 111 184 f \$0;
+#X obj 284 182 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X connect 1 0 6 0;
+#X connect 2 0 7 0;
+#X connect 3 0 4 0;
+#X connect 5 1 19 0;
+#X connect 6 0 2 0;
+#X connect 7 0 13 0;
+#X connect 7 1 3 0;
+#X connect 8 0 15 0;
+#X connect 9 0 14 0;
+#X connect 10 0 9 0;
+#X connect 12 0 6 0;
+#X connect 13 0 5 0;
+#X connect 14 0 11 0;
+#X connect 15 1 10 0;
+#X connect 16 0 15 0;
+#X connect 17 0 18 1;
+#X connect 18 0 8 0;
+#X connect 18 1 16 0;
+#X connect 19 0 20 0;
+#X connect 20 0 18 0;
+#X connect 21 0 18 1;
+#X restore 338 250 pd draw;
+#X obj 365 226 tgl 20 0 \$0-drawmode-s empty mode 0 -6 0 8 -225271
+-1 -1 0 1;
+#X obj 243 242 symbol;
+#X obj 115 141 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#N canvas 486 0 310 377 weight_sum 1;
+#X obj 34 11 inlet;
+#X msg 34 104 arc_next;
+#X obj 34 309 f 0;
+#X obj 209 82 0;
+#X obj 99 228 unpack 0 0 0 0;
+#X obj 193 252 + 0;
+#X obj 98 253 t f f;
+#X obj 87 11 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 34 340 outlet;
+#X obj 34 157 gfsm_state a1 0;
+#X obj 70 136 r \$0-state;
+#X obj 88 340 s \$0-wsum-out;
+#X obj 113 13 r \$0-wsum-in;
+#X obj 34 80 until;
+#X obj 34 204 route bang;
+#X obj 34 225 t b b;
+#X obj 34 182 route arc_next;
+#X obj 34 33 t b b b b;
+#X msg 101 104 arc_reset;
+#X connect 0 0 17 0;
+#X connect 1 0 9 0;
+#X connect 2 0 8 0;
+#X connect 2 0 11 0;
+#X connect 3 0 5 1;
+#X connect 4 3 5 0;
+#X connect 5 0 6 0;
+#X connect 6 0 5 1;
+#X connect 6 1 2 1;
+#X connect 7 0 17 0;
+#X connect 9 0 16 0;
+#X connect 10 0 9 0;
+#X connect 12 0 17 0;
+#X connect 13 0 1 0;
+#X connect 14 0 15 0;
+#X connect 14 1 4 0;
+#X connect 15 0 2 0;
+#X connect 15 1 13 1;
+#X connect 16 0 14 0;
+#X connect 17 0 13 0;
+#X connect 17 1 3 0;
+#X connect 17 2 18 0;
+#X connect 17 3 13 1;
+#X connect 18 0 9 0;
+#X restore 115 161 pd weight_sum;
+#X obj 114 332 s \$0-state-out;
+#X obj 114 224 print WSUM;
+#X obj 252 97 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#N canvas 298 9 405 465 rand_arc 0;
+#X obj 40 9 inlet;
+#X obj 83 9 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 -1
+;
+#X msg 41 98 arc_next;
+#X obj 136 266 unpack 0 0 0 0;
+#X obj 41 415 outlet;
+#X obj 41 163 gfsm_state a1 0;
+#X obj 76 140 r \$0-state;
+#X obj 243 97 s \$0-wsum-in;
+#X obj 245 119 r \$0-wsum-out;
+#X obj 245 166 random 131072;
+#X obj 245 140 t b f;
+#X obj 245 190 / 131072;
+#X obj 245 214 * 1;
+#X obj 229 334 moses 0;
+#X obj 245 237 * -1;
+#X obj 229 289 + 0;
+#X obj 229 312 t f f;
+#X obj 106 327 spigot;
+#X obj 143 304 0;
+#X obj 170 304 1;
+#X obj 107 10 r \$0-randarc-in;
+#X obj 92 415 s \$0-randarc-out;
+#X obj 41 76 until;
+#X obj 41 220 route bang;
+#X obj 106 244 t l l;
+#X obj 228 353 t b;
+#X obj 272 353 t b;
+#X obj 106 348 t l b;
+#X obj 41 348 t b b;
+#X obj 41 197 route arc_next;
+#X msg 107 97 arc_reset;
+#X obj 41 30 t b b b b;
+#X connect 0 0 31 0;
+#X connect 1 0 31 0;
+#X connect 2 0 5 0;
+#X connect 3 3 15 0;
+#X connect 5 0 29 0;
+#X connect 6 0 5 0;
+#X connect 8 0 10 0;
+#X connect 9 0 11 0;
+#X connect 10 0 9 0;
+#X connect 10 1 12 1;
+#X connect 11 0 12 0;
+#X connect 12 0 14 0;
+#X connect 13 0 25 0;
+#X connect 13 1 26 0;
+#X connect 14 0 15 1;
+#X connect 15 0 16 0;
+#X connect 16 0 13 0;
+#X connect 16 1 15 1;
+#X connect 17 0 27 0;
+#X connect 18 0 17 1;
+#X connect 19 0 17 1;
+#X connect 20 0 31 0;
+#X connect 22 0 2 0;
+#X connect 23 0 28 0;
+#X connect 23 1 24 0;
+#X connect 24 0 17 0;
+#X connect 24 1 3 0;
+#X connect 25 0 18 0;
+#X connect 26 0 19 0;
+#X connect 27 0 21 0;
+#X connect 27 0 4 0;
+#X connect 27 1 22 1;
+#X connect 28 0 4 0;
+#X connect 28 0 21 0;
+#X connect 28 1 22 1;
+#X connect 29 0 23 0;
+#X connect 30 0 5 0;
+#X connect 31 0 22 0;
+#X connect 31 1 30 0;
+#X connect 31 2 7 0;
+#X connect 31 3 22 1;
+#X restore 252 116 pd rand_arc;
+#X obj 395 113 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#N canvas 102 2 392 492 rand_incr 0;
+#X obj 40 9 inlet;
+#X obj 83 9 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1 -1
+;
+#X obj 41 54 s \$0-randarc-in;
+#X obj 43 76 r \$0-randarc-out;
+#X obj 42 98 route bang;
+#X obj 41 30 t b;
+#X obj 42 177 gfsm_automaton a1;
+#X obj 209 157 unpack 0 0 0 0;
+#X obj 55 154 r \$0-automaton;
+#X msg 42 131 root;
+#X obj 42 199 route root;
+#X obj 42 221 route bang;
+#X obj 107 336 outlet;
+#X obj 211 337 outlet;
+#X obj 271 335 outlet;
+#X msg 8 247 root 0;
+#X obj 107 254 t f f;
+#X obj 137 295 s \$0-state;
+#X msg 137 274 set \$1;
+#X obj 326 336 outlet;
+#X connect 0 0 5 0;
+#X connect 1 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 9 0;
+#X connect 4 1 7 0;
+#X connect 5 0 2 0;
+#X connect 6 0 10 0;
+#X connect 7 0 16 0;
+#X connect 7 1 13 0;
+#X connect 7 2 14 0;
+#X connect 7 3 19 0;
+#X connect 8 0 6 0;
+#X connect 9 0 6 0;
+#X connect 10 0 11 0;
+#X connect 11 0 15 0;
+#X connect 11 1 16 0;
+#X connect 15 0 6 0;
+#X connect 16 0 12 0;
+#X connect 16 1 18 0;
+#X connect 18 0 17 0;
+#X restore 395 132 pd rand_incr;
+#X obj 254 157 print RAND_ARC;
+#X obj 336 33 s \$0-state;
+#X obj 326 54 s \$0-fsm;
+#X obj 13 105 s \$0-automaton;
+#X obj 326 12 r \$0-automaton;
+#X obj 13 214 s \$0-state-a;
+#X obj 19 262 r \$0-state-a;
+#X obj 195 192 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 230 140 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 470 10 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 493 10 5 0 0 0 - - -;
+#X obj 471 30 metro 1000;
+#X obj 417 300 gfsm_alphabet alph1;
+#X obj 518 214 bng 15 250 50 0 empty empty empty 0 -6 0 8 -225280 -1
+-1;
+#X obj 518 232 openpanel;
+#X obj 518 254 symbol;
+#X msg 518 275 load \$1;
+#X obj 481 375 print RI-ATOM;
+#X msg 419 273 char2atom \$1;
+#X floatatom 436 245 5 0 0 0 - - -;
+#X obj 482 332 fromsymbol;
+#N canvas 0 0 450 300 ri_print 0;
+#X obj 48 22 inlet;
+#X obj 101 22 inlet;
+#X obj 155 22 inlet;
+#X obj 206 22 inlet;
+#X obj 319 22 inlet;
+#X obj 93 97 spigot;
+#X obj 93 57 pack 0 0 0 0;
+#X obj 93 122 unpack 0 0 0 0;
+#X obj 124 196 print RI-LO;
+#X obj 186 155 print RI-WT;
+#X obj 155 175 print RI-HI;
+#X obj 93 215 print RI-NXT;
+#X connect 0 0 6 0;
+#X connect 1 0 6 1;
+#X connect 2 0 6 2;
+#X connect 3 0 6 3;
+#X connect 4 0 5 1;
+#X connect 5 0 7 0;
+#X connect 6 0 5 0;
+#X connect 7 0 11 0;
+#X connect 7 1 8 0;
+#X connect 7 2 10 0;
+#X connect 7 3 9 0;
+#X restore 420 160 pd ri_print;
+#X obj 488 131 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 114 181 spigot;
+#X obj 162 181 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 253 138 spigot;
+#X obj 301 138 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 29 410 grattsdict;
+#X obj 470 51 t b b;
+#X obj 475 100 spigot;
+#X msg 506 80 0;
+#X msg 534 80 1;
+#X obj 548 456 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#N canvas 0 0 450 300 load_dict 0;
+#X obj 31 16 inlet;
+#X obj 31 38 t b;
+#X msg 31 67 load /home/moocow/src/pd/externs/ratts/dict/beep-b.txt
+cr;
+#X obj 33 108 outlet;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X restore 30 391 pd load_dict;
+#X obj 31 371 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 243 365 gpratts~ 10 \$0p /gpratts;
+#X obj 30 432 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X msg 30 453 \; pd dsp \$1;
+#X obj 434 74 bng 15 250 20 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 435 103 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 424 202 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 367 340 route 0;
+#X msg 202 284 info;
+#X msg 13 141 arc_reset;
+#X msg 250 219 markov.gfst;
+#X msg 538 211 markov.lab;
+#X floatatom 114 204 8 0 0 0 - - -;
+#X obj 481 355 spigot;
+#X obj 533 354 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 145 359 ms8a~ p gpr;
+#X connect 1 0 38 0;
+#X connect 2 0 38 0;
+#X connect 4 0 38 0;
+#X connect 5 0 11 0;
+#X connect 8 0 7 0;
+#X connect 9 0 7 0;
+#X connect 10 0 9 0;
+#X connect 11 0 6 0;
+#X connect 11 0 29 0;
+#X connect 12 0 10 0;
+#X connect 13 0 14 0;
+#X connect 15 0 40 0;
+#X connect 16 0 40 0;
+#X connect 17 0 21 0;
+#X connect 18 0 19 0;
+#X connect 19 0 26 0;
+#X connect 20 0 17 0;
+#X connect 22 0 17 0;
+#X connect 26 0 20 0;
+#X connect 27 0 28 0;
+#X connect 31 0 32 0;
+#X connect 32 0 60 0;
+#X connect 33 0 34 0;
+#X connect 34 0 56 0;
+#X connect 34 0 53 0;
+#X connect 34 1 56 1;
+#X connect 34 2 56 2;
+#X connect 34 3 56 3;
+#X connect 39 0 37 0;
+#X connect 39 0 36 0;
+#X connect 41 0 11 0;
+#X connect 44 0 46 0;
+#X connect 45 0 46 1;
+#X connect 46 0 63 0;
+#X connect 47 1 55 0;
+#X connect 48 0 49 0;
+#X connect 49 0 50 0;
+#X connect 50 0 51 0;
+#X connect 51 0 47 0;
+#X connect 53 0 47 0;
+#X connect 54 0 53 0;
+#X connect 55 0 76 0;
+#X connect 55 0 82 0;
+#X connect 57 0 56 4;
+#X connect 58 0 81 0;
+#X connect 59 0 58 1;
+#X connect 60 0 35 0;
+#X connect 61 0 60 1;
+#X connect 63 0 65 0;
+#X connect 63 1 64 0;
+#X connect 64 0 34 0;
+#X connect 65 0 64 1;
+#X connect 66 0 64 1;
+#X connect 68 0 62 0;
+#X connect 69 0 68 0;
+#X connect 70 0 84 0;
+#X connect 70 0 84 1;
+#X connect 70 1 66 0;
+#X connect 71 0 72 0;
+#X connect 76 1 70 0;
+#X connect 77 0 17 0;
+#X connect 78 0 40 0;
+#X connect 79 0 26 0;
+#X connect 80 0 50 0;
+#X connect 81 0 30 0;
+#X connect 82 0 52 0;
+#X connect 83 0 82 1;
diff --git a/gfsm/src/test.lab b/gfsm/src/test.lab
new file mode 100644
index 0000000..a339b5f
--- /dev/null
+++ b/gfsm/src/test.lab
@@ -0,0 +1,5 @@
+<epsilon> 0
+a 1
+b 2
+c 3
+foo 42
diff --git a/gfsm/src/test.tfst b/gfsm/src/test.tfst
new file mode 100644
index 0000000..e07da8c
--- /dev/null
+++ b/gfsm/src/test.tfst
@@ -0,0 +1,3 @@
+0 1 1 1 0
+1 2 2 2 0
+2
diff --git a/gfsm/src/test2.lab b/gfsm/src/test2.lab
new file mode 100644
index 0000000..08f153a
--- /dev/null
+++ b/gfsm/src/test2.lab
@@ -0,0 +1,6 @@
+<epsilon> 0
+a 1
+b 2
+c 3
+foo 42
+x 1
diff --git a/gfsm/src/test2.tfst b/gfsm/src/test2.tfst
new file mode 100644
index 0000000..e5e2be6
--- /dev/null
+++ b/gfsm/src/test2.tfst
@@ -0,0 +1,4 @@
+0 1 3 30 0
+0 2 4 40 0
+1 0
+2 0
diff --git a/gfsm/src/test3.tfst b/gfsm/src/test3.tfst
new file mode 100644
index 0000000..e124810
--- /dev/null
+++ b/gfsm/src/test3.tfst
@@ -0,0 +1,4 @@
+0 1 3 30 0.3
+0 2 4 40 0.7
+1 0
+2 0