aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorN.N. <krzyszcz@users.sourceforge.net>2003-05-23 12:29:55 +0000
committerN.N. <krzyszcz@users.sourceforge.net>2003-05-23 12:29:55 +0000
commitfaada59567f8cb252f4a909116595ce309ff5828 (patch)
tree5874954c6f2d5392d921208e49a45ef266beeb7f
This commit was generated by cvs2svn to compensate for changes in r647,svn2git-root
which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/miXed/; revision=648
-rw-r--r--LICENSE.txt31
-rw-r--r--Makefile.common285
-rw-r--r--ViCious/cyclone/sources184
-rw-r--r--cyclone/Makefile2
-rw-r--r--cyclone/Makefile.dirs2
-rw-r--r--cyclone/Makefile.objects24
-rw-r--r--cyclone/Makefile.sources191
-rw-r--r--cyclone/build_counter3
-rw-r--r--cyclone/cyclone-all.exclude9
-rw-r--r--cyclone/cyclone-shared.include35
-rw-r--r--cyclone/cyclone-test.exclude4
-rw-r--r--cyclone/cyclone-vicious.exclude3
-rw-r--r--cyclone/hammer/Append.c207
-rw-r--r--cyclone/hammer/Borax.c177
-rw-r--r--cyclone/hammer/Bucket.c137
-rw-r--r--cyclone/hammer/Clip.c149
-rw-r--r--cyclone/hammer/Decode.c110
-rw-r--r--cyclone/hammer/Histo.c103
-rw-r--r--cyclone/hammer/Makefile3
-rw-r--r--cyclone/hammer/Makefile.objects14
-rw-r--r--cyclone/hammer/Makefile.sources80
-rw-r--r--cyclone/hammer/MouseState.c153
-rw-r--r--cyclone/hammer/Peak.c63
-rw-r--r--cyclone/hammer/TogEdge.c71
-rw-r--r--cyclone/hammer/Trough.c63
-rw-r--r--cyclone/hammer/Uzi.c108
-rw-r--r--cyclone/hammer/accum.c68
-rw-r--r--cyclone/hammer/acos.c48
-rw-r--r--cyclone/hammer/active.c55
-rw-r--r--cyclone/hammer/allhammers.c160
-rw-r--r--cyclone/hammer/anal.c108
-rw-r--r--cyclone/hammer/asin.c48
-rw-r--r--cyclone/hammer/bangbang.c73
-rw-r--r--cyclone/hammer/bondo.c394
-rw-r--r--cyclone/hammer/buddy.c253
-rw-r--r--cyclone/hammer/capture.c291
-rw-r--r--cyclone/hammer/cartopol.c44
-rw-r--r--cyclone/hammer/coll.c1597
-rw-r--r--cyclone/hammer/comment.c835
-rw-r--r--cyclone/hammer/cosh.c48
-rw-r--r--cyclone/hammer/counter.c399
-rw-r--r--cyclone/hammer/cycle.c153
-rw-r--r--cyclone/hammer/decide.c75
-rw-r--r--cyclone/hammer/drunk.c140
-rw-r--r--cyclone/hammer/flush.c79
-rw-r--r--cyclone/hammer/forward.c71
-rw-r--r--cyclone/hammer/fromsymbol.c88
-rw-r--r--cyclone/hammer/funbuff.c521
-rw-r--r--cyclone/hammer/funnel.c179
-rw-r--r--cyclone/hammer/gate.c147
-rw-r--r--cyclone/hammer/grab.c279
-rw-r--r--cyclone/hammer/hammer.c93
-rw-r--r--cyclone/hammer/iter.c112
-rw-r--r--cyclone/hammer/match.c216
-rw-r--r--cyclone/hammer/maximum.c88
-rw-r--r--cyclone/hammer/mean.c79
-rw-r--r--cyclone/hammer/midiflush.c102
-rw-r--r--cyclone/hammer/midiformat.c112
-rw-r--r--cyclone/hammer/midiparse.c132
-rw-r--r--cyclone/hammer/minimum.c88
-rw-r--r--cyclone/hammer/mousefilter.c70
-rw-r--r--cyclone/hammer/next.c58
-rw-r--r--cyclone/hammer/offer.c94
-rw-r--r--cyclone/hammer/onebang.c46
-rw-r--r--cyclone/hammer/past.c154
-rw-r--r--cyclone/hammer/pd-lib-notes.txt61
-rw-r--r--cyclone/hammer/poltocar.c44
-rw-r--r--cyclone/hammer/prepend.c258
-rw-r--r--cyclone/hammer/prob.c312
-rw-r--r--cyclone/hammer/pv.c457
-rw-r--r--cyclone/hammer/seq.c825
-rw-r--r--cyclone/hammer/sinh.c48
-rw-r--r--cyclone/hammer/speedlim.c173
-rw-r--r--cyclone/hammer/spell.c149
-rw-r--r--cyclone/hammer/split.c64
-rw-r--r--cyclone/hammer/spray.c93
-rw-r--r--cyclone/hammer/sprintf.c634
-rw-r--r--cyclone/hammer/substitute.c340
-rw-r--r--cyclone/hammer/sustain.c85
-rw-r--r--cyclone/hammer/switch.c152
-rw-r--r--cyclone/hammer/tanh.c48
-rw-r--r--cyclone/hammer/testmess.c245
-rw-r--r--cyclone/hammer/thresh.c134
-rw-r--r--cyclone/hammer/tosymbol.c184
-rw-r--r--cyclone/hammer/universal.c167
-rw-r--r--cyclone/hammer/urn.c148
-rw-r--r--cyclone/hammer/xbendin.c93
-rw-r--r--cyclone/hammer/xbendin2.c99
-rw-r--r--cyclone/hammer/xbendout.c54
-rw-r--r--cyclone/hammer/xbendout2.c60
-rw-r--r--cyclone/hammer/xnotein.c100
-rw-r--r--cyclone/hammer/xnoteout.c62
-rw-r--r--cyclone/hammer/zl.c982
-rw-r--r--cyclone/shadow/Makefile7
-rw-r--r--cyclone/shadow/Makefile.objects9
-rw-r--r--cyclone/shadow/Makefile.sources6
-rw-r--r--cyclone/shadow/cyclone.c159
-rw-r--r--cyclone/shadow/dummies.c664
-rw-r--r--cyclone/shadow/nettles.c549
-rw-r--r--cyclone/shadow/shadow.h13
-rw-r--r--cyclone/sickle/Clip.c59
-rw-r--r--cyclone/sickle/Line.c299
-rw-r--r--cyclone/sickle/Makefile3
-rw-r--r--cyclone/sickle/Makefile.objects11
-rw-r--r--cyclone/sickle/Makefile.sources67
-rw-r--r--cyclone/sickle/Scope.c1043
-rw-r--r--cyclone/sickle/Snapshot.c161
-rw-r--r--cyclone/sickle/abs.c42
-rw-r--r--cyclone/sickle/acos.c48
-rw-r--r--cyclone/sickle/acosh.c48
-rw-r--r--cyclone/sickle/allpass.c153
-rw-r--r--cyclone/sickle/allsickles.c134
-rw-r--r--cyclone/sickle/asin.c48
-rw-r--r--cyclone/sickle/asinh.c48
-rw-r--r--cyclone/sickle/atan.c48
-rw-r--r--cyclone/sickle/atan2.c53
-rw-r--r--cyclone/sickle/atanh.c48
-rw-r--r--cyclone/sickle/average.c194
-rw-r--r--cyclone/sickle/avg.c62
-rw-r--r--cyclone/sickle/bitand.c144
-rw-r--r--cyclone/sickle/bitnot.c66
-rw-r--r--cyclone/sickle/bitor.c144
-rw-r--r--cyclone/sickle/bitshift.c130
-rw-r--r--cyclone/sickle/bitxor.c144
-rw-r--r--cyclone/sickle/capture.c408
-rw-r--r--cyclone/sickle/cartopol.c79
-rw-r--r--cyclone/sickle/change.c52
-rw-r--r--cyclone/sickle/click.c119
-rw-r--r--cyclone/sickle/comb.c162
-rw-r--r--cyclone/sickle/cosh.c48
-rw-r--r--cyclone/sickle/cosx.c51
-rw-r--r--cyclone/sickle/count.c145
-rw-r--r--cyclone/sickle/cycle.c173
-rw-r--r--cyclone/sickle/delay.c101
-rw-r--r--cyclone/sickle/delta.c52
-rw-r--r--cyclone/sickle/deltaclip.c67
-rw-r--r--cyclone/sickle/edge.c106
-rw-r--r--cyclone/sickle/frameaccum.c71
-rw-r--r--cyclone/sickle/framedelta.c76
-rw-r--r--cyclone/sickle/index.c107
-rw-r--r--cyclone/sickle/kink.c62
-rw-r--r--cyclone/sickle/linedrive.c73
-rw-r--r--cyclone/sickle/log.c74
-rw-r--r--cyclone/sickle/lookup.c94
-rw-r--r--cyclone/sickle/minmax.c78
-rw-r--r--cyclone/sickle/peakamp.c107
-rw-r--r--cyclone/sickle/peek.c147
-rw-r--r--cyclone/sickle/phasewrap.c131
-rw-r--r--cyclone/sickle/play.c122
-rw-r--r--cyclone/sickle/poltocar.c79
-rw-r--r--cyclone/sickle/pow.c54
-rw-r--r--cyclone/sickle/rampsmooth.c206
-rw-r--r--cyclone/sickle/rand.c95
-rw-r--r--cyclone/sickle/record.c242
-rw-r--r--cyclone/sickle/sah.c70
-rw-r--r--cyclone/sickle/sickle.c93
-rw-r--r--cyclone/sickle/sinh.c48
-rw-r--r--cyclone/sickle/sinx.c51
-rw-r--r--cyclone/sickle/slide.c77
-rw-r--r--cyclone/sickle/spike.c109
-rw-r--r--cyclone/sickle/tanh.c48
-rw-r--r--cyclone/sickle/tanx.c51
-rw-r--r--cyclone/sickle/train.c117
-rw-r--r--cyclone/sickle/trapezoid.c105
-rw-r--r--cyclone/sickle/triangle.c95
-rw-r--r--cyclone/sickle/vectral.c235
-rw-r--r--cyclone/sickle/wave.c161
-rwxr-xr-xdumpsetups15
-rw-r--r--shared/Makefile2
-rw-r--r--shared/Makefile.dirs1
-rw-r--r--shared/Makefile.objects0
-rw-r--r--shared/Makefile.sources2
-rw-r--r--shared/common/Makefile4
-rw-r--r--shared/common/Makefile.objects0
-rw-r--r--shared/common/Makefile.sources16
-rw-r--r--shared/common/bifi.c217
-rw-r--r--shared/common/bifi.h40
-rw-r--r--shared/common/binport.c559
-rw-r--r--shared/common/binport.h15
-rw-r--r--shared/common/grow.c105
-rw-r--r--shared/common/grow.h17
-rw-r--r--shared/common/loud.c210
-rw-r--r--shared/common/loud.h31
-rw-r--r--shared/common/mifi.c867
-rw-r--r--shared/common/mifi.h84
-rw-r--r--shared/common/port.c612
-rw-r--r--shared/common/port.h10
-rw-r--r--shared/common/rand.c61
-rw-r--r--shared/common/rand.h14
-rw-r--r--shared/common/sq.c371
-rw-r--r--shared/common/sq.h169
-rw-r--r--shared/common/vefl.c233
-rw-r--r--shared/common/vefl.h36
-rw-r--r--shared/hammer/Makefile4
-rw-r--r--shared/hammer/Makefile.objects0
-rw-r--r--shared/hammer/Makefile.sources4
-rw-r--r--shared/hammer/file.c402
-rw-r--r--shared/hammer/file.h43
-rw-r--r--shared/hammer/gui.c438
-rw-r--r--shared/hammer/gui.h30
-rw-r--r--shared/hammer/tree.c482
-rw-r--r--shared/hammer/tree.h37
-rw-r--r--shared/shared.c11
-rw-r--r--shared/shared.h166
-rw-r--r--shared/sickle/Makefile4
-rw-r--r--shared/sickle/Makefile.objects0
-rw-r--r--shared/sickle/Makefile.sources3
-rw-r--r--shared/sickle/arsic.c221
-rw-r--r--shared/sickle/arsic.h38
-rw-r--r--shared/sickle/sic.c119
-rw-r--r--shared/sickle/sic.h25
-rw-r--r--shared/unstable/Makefile4
-rw-r--r--shared/unstable/Makefile.objects0
-rw-r--r--shared/unstable/Makefile.sources4
-rw-r--r--shared/unstable/forky.c56
-rw-r--r--shared/unstable/forky.h11
-rw-r--r--shared/unstable/fragile.c67
-rw-r--r--shared/unstable/fragile.h13
-rw-r--r--shared/unstable/loader.c139
-rw-r--r--shared/unstable/loader.h12
-rw-r--r--shared/unstable/pd_imp.h60
-rw-r--r--test/cyclone/Borax-test.pd120
-rw-r--r--test/cyclone/Bucket-test.pd40
-rw-r--r--test/cyclone/Decode-test.pd18
-rw-r--r--test/cyclone/Histo-test.pd20
-rw-r--r--test/cyclone/MouseState-test.pd54
-rw-r--r--test/cyclone/TogEdge-test.pd16
-rw-r--r--test/cyclone/Uzi-test.pd27
-rw-r--r--test/cyclone/active-test.pd19
-rw-r--r--test/cyclone/anal-test.pd17
-rw-r--r--test/cyclone/append-test.pd78
-rw-r--r--test/cyclone/bad.coll4
-rw-r--r--test/cyclone/bondo-test.pd73
-rw-r--r--test/cyclone/buddy-test.pd28
-rw-r--r--test/cyclone/capture-test.pd48
-rw-r--r--test/cyclone/click-test.pd26
-rw-r--r--test/cyclone/clip-test.pd41
-rw-r--r--test/cyclone/coll-print.pd12
-rw-r--r--test/cyclone/coll-test.pd117
-rw-r--r--test/cyclone/comb-test.pd80
-rw-r--r--test/cyclone/comment-dotest.pd37
-rw-r--r--test/cyclone/comment-ogonki.pd9
-rw-r--r--test/cyclone/comment-test.pd21
-rw-r--r--test/cyclone/count-test.pd19
-rw-r--r--test/cyclone/counter-test.pd46
-rw-r--r--test/cyclone/cycle-test.pd30
-rw-r--r--test/cyclone/cyclone-test.pd54
-rw-r--r--test/cyclone/decide-test.pd27
-rw-r--r--test/cyclone/drunk-test.pd45
-rw-r--r--test/cyclone/forward-test.pd27
-rw-r--r--test/cyclone/frameaccum-test.pd15
-rw-r--r--test/cyclone/fromsymbol-test.pd64
-rw-r--r--test/cyclone/funbuff-etest.pd164
-rw-r--r--test/cyclone/funbuff-test.pd149
-rw-r--r--test/cyclone/funnel-test.pd33
-rw-r--r--test/cyclone/gate-test.pd48
-rw-r--r--test/cyclone/good.coll4
-rw-r--r--test/cyclone/grab-test.pd42
-rw-r--r--test/cyclone/index-test.pd51
-rw-r--r--test/cyclone/kanon.midbin0 -> 5282 bytes
-rw-r--r--test/cyclone/kink-test.pd22
-rw-r--r--test/cyclone/line-test.pd54
-rw-r--r--test/cyclone/match-reentrant.pd20
-rw-r--r--test/cyclone/match-test.pd33
-rw-r--r--test/cyclone/maxmin-test.pd65
-rw-r--r--test/cyclone/mean-test.pd16
-rw-r--r--test/cyclone/midi-test.pd33
-rw-r--r--test/cyclone/midiparse-test.pd28
-rw-r--r--test/cyclone/mousefilter-test.pd28
-rw-r--r--test/cyclone/next-test.pd16
-rw-r--r--test/cyclone/offer-test.pd76
-rw-r--r--test/cyclone/onebang-test.pd26
-rw-r--r--test/cyclone/past-test.pd38
-rw-r--r--test/cyclone/peakamp-test.pd25
-rw-r--r--test/cyclone/peek-test.pd51
-rw-r--r--test/cyclone/prepend-test.pd73
-rw-r--r--test/cyclone/prob-test.pd33
-rw-r--r--test/cyclone/pv-test.pd83
-rw-r--r--test/cyclone/rand-test.pd37
-rw-r--r--test/cyclone/record-sync-test.pd64
-rw-r--r--test/cyclone/record-test.pd60
-rw-r--r--test/cyclone/scope-gop.pd2
-rw-r--r--test/cyclone/scope-test.pd125
-rw-r--r--test/cyclone/scope-test1.pd28
-rw-r--r--test/cyclone/scope-test2.pd31
-rw-r--r--test/cyclone/seq-test.pd58
-rw-r--r--test/cyclone/sigbits-test.pd157
-rw-r--r--test/cyclone/sigcapture-test.pd25
-rw-r--r--test/cyclone/sigcycle-test.pd156
-rw-r--r--test/cyclone/sigmeters-test.pd45
-rw-r--r--test/cyclone/sigops-test.pd64
-rw-r--r--test/cyclone/sigsmoothers-test.pd34
-rw-r--r--test/cyclone/sigtrig-test.pd80
-rw-r--r--test/cyclone/sigwrappers-speed.pd101
-rw-r--r--test/cyclone/sigwrappers-speed20.pd63
-rw-r--r--test/cyclone/sigwrappers-test.pd34
-rw-r--r--test/cyclone/spectrum-pm.pd34
-rw-r--r--test/cyclone/speedlim-test.pd63
-rw-r--r--test/cyclone/spell-test.pd26
-rw-r--r--test/cyclone/spike-test.pd23
-rw-r--r--test/cyclone/split-test.pd48
-rw-r--r--test/cyclone/spray-test.pd82
-rw-r--r--test/cyclone/substitute-test.pd56
-rw-r--r--test/cyclone/switch-test.pd35
-rw-r--r--test/cyclone/test.capture2
-rw-r--r--test/cyclone/test.funbuff10
-rw-r--r--test/cyclone/test.midbin0 -> 4855 bytes
-rw-r--r--test/cyclone/test.pool2
-rw-r--r--test/cyclone/test.seq1208
-rw-r--r--test/cyclone/test1.seq1208
-rw-r--r--test/cyclone/testmess-reentrant.pd25
-rw-r--r--test/cyclone/testmess-test.pd69
-rw-r--r--test/cyclone/thresh-test.pd41
-rw-r--r--test/cyclone/tosymbol-test.pd44
-rw-r--r--test/cyclone/train-test.pd17
-rw-r--r--test/cyclone/trig-test.pd66
-rw-r--r--test/cyclone/universal-test.pd55
-rw-r--r--test/cyclone/urn-test.pd15
-rw-r--r--test/cyclone/vectral-test.pd56
-rw-r--r--test/cyclone/xbend-test.pd89
-rw-r--r--test/cyclone/xnote-test.pd50
-rw-r--r--test/cyclone/zl-test.pd148
322 files changed, 38287 insertions, 0 deletions
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..34ee839
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,31 @@
+This software is copyrighted by Miller Puckette and others. The following
+terms apply to all files associated with the software unless explicitly
+disclaimed in individual files.
+
+The authors hereby grant permission to use, copy, modify, distribute,
+and license this software and its documentation for any purpose, provided
+that existing copyright notices are retained in all copies and that this
+notice is included verbatim in any distributions. No written agreement,
+license, or royalty fee is required for any of the authorized uses.
+Modifications to this software may be copyrighted by their authors
+and need not follow the licensing terms described here, provided that
+the new terms are clearly indicated on the first page of each file where
+they apply.
+
+IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
+FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
+DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
+IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
+NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+MODIFICATIONS.
+
+RESTRICTED RIGHTS: Use, duplication or disclosure by the government
+is subject to the restrictions as set forth in subparagraph (c) (1) (ii)
+of the Rights in Technical Data and Computer Software Clause as DFARS
+252.227-7013 and FAR 52.227-19.
diff --git a/Makefile.common b/Makefile.common
new file mode 100644
index 0000000..3db7717
--- /dev/null
+++ b/Makefile.common
@@ -0,0 +1,285 @@
+# next line has to be edited manually
+PD_DIR = $(ROOT_DIR)/../pd/src
+
+OS_NAME = $(shell uname -s)
+ifneq ($(OS_NAME),Linux)
+ifneq ($(OS_NAME),Darwin)
+# FIXME
+endif
+endif
+
+TILDE = ~
+
+-include Makefile.dirs
+include Makefile.sources
+include Makefile.objects
+
+CC = gcc
+
+default: define_build all
+
+SHARED_DIR = $(ROOT_DIR)/shared
+OBJ_DIR = .
+OUT_DIR = $(ROOT_DIR)/bin
+
+BASE_DIR = $(shell basename `pwd`)
+BASE_NAME = $(shell basename `pwd` | awk -F - '{print $$1}')
+
+# CX: control external's main file
+# AX: audio (tilde) external's main file
+# LX: symlink external's main file
+# (if symlink external is tilde-only, use OTHER_SOURCES and AX_CLASSES)
+
+CX_NAMES = $(notdir $(CX_SOURCES))
+AX_NAMES = $(notdir $(AX_SOURCES))
+LX_NAMES = $(notdir $(LX_SOURCES))
+TYPES_NAMES = $(notdir $($1_SOURCES))
+
+CX_DIR = $(dir $(firstword $(CX_SOURCES)))
+AX_DIR = $(dir $(firstword $(AX_SOURCES)))
+TYPES_DIR = $(dir $(firstword $($1_SOURCES)))
+
+TYPES_EXTERNS = \
+ $(patsubst %.c,%$($1_TILDE).$(X_SUFFIX),$(call TYPES_NAMES,$1))
+
+SOURCES = $(CX_SOURCES) $(AX_SOURCES) $(LX_SOURCES) $(OTHER_SOURCES) \
+ $(foreach type,$(TYPES),$($(type)_SOURCES))
+
+INCLUDES = -I. -I$(PD_DIR) -I$(SHARED_DIR)
+
+ifeq ($(OS_NAME),Linux)
+X_SUFFIX = pd_linux
+DEFINES = -DUNIX
+OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+LFLAGS = -export_dynamic -shared
+endif
+
+ifeq ($(OS_NAME),Darwin)
+X_SUFFIX = pd_darwin
+DEFINES = -DUNIX -DMACOSX
+OPT_CFLAGS = -O2 -funroll-loops -fomit-frame-pointer
+# -private_bundle is a guess, LATER check this
+LFLAGS = -bundle -undefined suppress -flat_namespace
+endif
+
+WARN_CFLAGS = -Wall -W -Wstrict-prototypes -Werror \
+ -Wno-unused -Wno-parentheses -Wno-switch
+DBG_CFLAGS =
+CFLAGS = $(WARN_CFLAGS) $(OPT_CFLAGS) $(DEFINES) $(INCLUDES)
+
+EXTERNS = $(foreach fn,$(CX_NAMES:.c=.$(X_SUFFIX)),$(OUT_DIR)/$(fn)) \
+ $(foreach fn,$(AX_NAMES:.c=~.$(X_SUFFIX)),$(OUT_DIR)/$(fn)) \
+ $(foreach fn,$(LX_SOURCES:.c=.$(X_SUFFIX)),$(OUT_DIR)/$(fn)) \
+ $(foreach fn,$(CX_CLASSES:=.$(X_SUFFIX)),$(OUT_DIR)/$(fn)) \
+ $(foreach fn,$(AX_CLASSES:=~.$(X_SUFFIX)),$(OUT_DIR)/$(fn)) \
+ $(foreach type,$(TYPES),\
+ $(foreach fn,$(call TYPES_EXTERNS,$(type)),$(OUT_DIR)/$(fn)))
+
+TYPES_RULE = $(foreach fn,$(call TYPES_EXTERNS,$1),$(OUT_DIR)/$(fn)): \
+ $(OUT_DIR)/%$($1_TILDE).$(X_SUFFIX) \
+ : $(call TYPES_DIR,$1)%.o $($1_PRIVATEOBJECTS) \
+ $(foreach obj,$($1_OBJECTS),$(SHARED_DIR)/$(obj)) \
+ ; $(CC) -o $$@ $(CFLAGS) $(LFLAGS) $$+
+
+# LATER find a better way...
+$(if $(word 1,$(TYPES)),$(call TYPES_RULE,$(word 1,$(TYPES))))
+$(if $(word 2,$(TYPES)),$(call TYPES_RULE,$(word 2,$(TYPES))))
+$(if $(word 3,$(TYPES)),$(call TYPES_RULE,$(word 3,$(TYPES))))
+$(if $(word 4,$(TYPES)),$(call TYPES_RULE,$(word 4,$(TYPES))))
+$(if $(word 5,$(TYPES)),$(call TYPES_RULE,$(word 5,$(TYPES))))
+$(if $(word 6,$(TYPES)),$(call TYPES_RULE,$(word 6,$(TYPES))))
+$(if $(word 7,$(TYPES)),$(call TYPES_RULE,$(word 7,$(TYPES))))
+$(if $(word 8,$(TYPES)),$(call TYPES_RULE,$(word 8,$(TYPES))))
+$(if $(word 9,$(TYPES)),$(call TYPES_RULE,$(word 9,$(TYPES))))
+$(if $(word 10,$(TYPES)),$(call TYPES_RULE,$(word 10,$(TYPES))))
+$(if $(word 11,$(TYPES)),$(call TYPES_RULE,$(word 11,$(TYPES))))
+$(if $(word 12,$(TYPES)),$(call TYPES_RULE,$(word 12,$(TYPES))))
+$(if $(word 13,$(TYPES)),$(call TYPES_RULE,$(word 13,$(TYPES))))
+$(if $(word 14,$(TYPES)),$(call TYPES_RULE,$(word 14,$(TYPES))))
+$(if $(word 15,$(TYPES)),$(call TYPES_RULE,$(word 15,$(TYPES))))
+$(if $(word 16,$(TYPES)),$(call TYPES_RULE,$(word 16,$(TYPES))))
+$(if $(word 17,$(TYPES)),$(call TYPES_RULE,$(word 17,$(TYPES))))
+$(if $(word 18,$(TYPES)),$(call TYPES_RULE,$(word 18,$(TYPES))))
+$(if $(word 19,$(TYPES)),$(call TYPES_RULE,$(word 19,$(TYPES))))
+$(if $(word 20,$(TYPES)),$(call TYPES_RULE,$(word 20,$(TYPES))))
+$(if $(word 21,$(TYPES)),$(call TYPES_RULE,$(word 21,$(TYPES))))
+$(if $(word 22,$(TYPES)),$(call TYPES_RULE,$(word 22,$(TYPES))))
+$(if $(word 23,$(TYPES)),$(call TYPES_RULE,$(word 23,$(TYPES))))
+$(if $(word 24,$(TYPES)),$(call TYPES_RULE,$(word 24,$(TYPES))))
+
+OBJECTS = $(foreach fn,$(OTHER_SOURCES:.c=.o),$(OBJ_DIR)/$(fn)) \
+ $(foreach fn,$(LX_SOURCES:.c=.o),$(OBJ_DIR)/$(fn)) \
+ $(foreach fn,$(SHARED_OBJECTS),$(SHARED_DIR)/$(fn))
+
+# lame...
+.PRECIOUS: %.o
+
+# rules for symlink externals must precede generic extern rules
+$(OUT_DIR)/$(BASE_NAME)_%~.$(X_SUFFIX): $(OUT_DIR)/$(BASE_NAME).$(X_SUFFIX)
+ -ln -sf $(BASE_NAME).$(X_SUFFIX) $@
+$(OUT_DIR)/$(BASE_NAME)_%.$(X_SUFFIX): $(OUT_DIR)/$(BASE_NAME).$(X_SUFFIX)
+ -ln -sf $(BASE_NAME).$(X_SUFFIX) $@
+
+# library stub
+# if not equal BASE_NAME, it has to be declared explicitly in BASE_DIR/Makefile
+$(OUT_DIR)/$(LX_STUB)_%~.$(X_SUFFIX): $(OUT_DIR)/$(BASE_NAME).$(X_SUFFIX)
+ -ln -sf $(BASE_NAME).$(X_SUFFIX) $@
+$(OUT_DIR)/$(LX_STUB)_%.$(X_SUFFIX): $(OUT_DIR)/$(BASE_NAME).$(X_SUFFIX)
+ -ln -sf $(BASE_NAME).$(X_SUFFIX) $@
+$(OUT_DIR)/$(LX_STUB).$(X_SUFFIX): $(OUT_DIR)/$(BASE_NAME).$(X_SUFFIX)
+ -ln -sf $(BASE_NAME).$(X_SUFFIX) $@
+
+# generic rule for audio externals
+$(OUT_DIR)/%~.$(X_SUFFIX): $(AX_DIR)%.c $(OBJECTS)
+ $(CC) -o $@ $(CFLAGS) $(LFLAGS) $(OBJECTS) $<
+
+# generic rule for control externals
+$(OUT_DIR)/%.$(X_SUFFIX): $(CX_DIR)%.c $(OBJECTS)
+ $(CC) -o $@ $(CFLAGS) $(LFLAGS) $(OBJECTS) $<
+
+SUBDIRS = @for i in $(MIXED_DIRS) and_in_case_it_is_null ; \
+ do ( if [ -d $$i ] ; then \
+ cd $$i; $(MAKE) $@ ; fi ) ; done
+
+SUBDIRS_DEFAULT = @for i in $(MIXED_DIRS) and_in_case_it_is_null ; \
+ do ( if [ -d $$i ] ; then \
+ cd $$i; $(MAKE) ; fi ) ; done
+
+define_build:
+ @if [[ -f build_counter && \
+ `date -r build_counter +%j` != `date +%j` ]] ; then \
+ mv build_counter build_counter~ ; \
+ echo -n 'increment build counter (y/n)? [n]' ; read doit ; \
+ if [ $$doit ] && [ $$doit == 'y' ] ; then \
+ cat build_counter~ | \
+ awk '{if (index($$2,"BUILD")) print $$1, $$2, $$3+1; else print}' \
+ > build_counter ; \
+ cat build_counter | \
+ awk 'BEGIN {printf toupper("$(BASE_NAME)_VERSION = ")} \
+ {gsub("\"","",$$3); printf $$3; if (NR==1) printf "-"} \
+ END {printf "\r\n" }' > $(ROOT_DIR)/ViCious/$(BASE_DIR)/version ; \
+ else cat build_counter~ > build_counter ; fi \
+ fi
+
+all$(BASE_NAME)s.c: Makefile.sources
+ $(ROOT_DIR)/dumpsetups > $@
+
+all: $(EXTERNS)
+ $(SUBDIRS_DEFAULT)
+
+clean: emptydeps
+# remove all objects and externs that are contained in current directory
+ -rm -f *.o *.$(X_SUFFIX)
+ $(SUBDIRS)
+
+cleanall: clean
+# remove default target externs
+ -rm -f $(EXTERNS)
+
+OLDROOT_DIR = $(shell ls -d -1 ../../Mixed-* | tail -1)
+
+diff:
+ @echo -n > diff.out ; \
+ for f in {*.h,*.c} ; do \
+ if [ -f $$f ] ; then \
+ diff -u $(OLDROOT_DIR)/$(BASE_DIR)/$$f $$f >> diff.out ; \
+ fi \
+ done
+
+VERSION = $(shell awk \
+ '{if (index($$2,"VERSION")) print substr($$3,2,length($$3)-2)}' \
+ build_counter)
+RELEASE = $(shell awk \
+ '{if (index($$2,"RELEASE")) print substr($$3,2,length($$3)-2)}' \
+ build_counter)
+BUILD = $(shell awk '{if (index($$2,"BUILD")) print $$3}' build_counter)
+
+RELEASE_STUB = release/$(BASE_NAME)-$(VERSION)-$(RELEASE)$(BUILD)
+SRC_TAR = $(RELEASE_STUB)-src.tar
+BIN_TAR = $(RELEASE_STUB)-bin.tar
+LIB_TAR = $(RELEASE_STUB)-lib.tar
+DOC_TAR = $(RELEASE_STUB)-doc.tar
+ALL_TAR = $(RELEASE_STUB)-all.tar
+REL_BINDIR = bin
+
+REL_LIBNAMES = $(foreach fn,$(RELEASE_LIBS:=.$(X_SUFFIX)),$(REL_BINDIR)/$(fn))
+
+REL_EXTERNS = $(foreach fn,$(CX_NAMES:.c=.$(X_SUFFIX)),$(REL_BINDIR)/$(fn)) \
+ $(foreach fn,$(AX_NAMES:.c=~.$(X_SUFFIX)),$(REL_BINDIR)/$(fn)) \
+ $(REL_LIBNAMES) $(REL_BINDIR)/$(RELEASE_APPS) \
+ $(foreach type,$(TYPES),\
+ $(foreach fn,$(call TYPES_EXTERNS,$(type)),$(REL_BINDIR)/$(fn)))
+
+REL_ROOTSRC = LICENSE.txt Makefile.common dumpsetups
+
+srelease: emptydeps define_build
+ cd $(ROOT_DIR)/shared; $(MAKE) emptydeps
+ cd $(ROOT_DIR); tar -X $(BASE_DIR)/$(BASE_NAME)-all.exclude -cf \
+ $(SRC_TAR) $(BASE_DIR)/* $(REL_ROOTSRC)
+ cd $(ROOT_DIR); tar -T $(BASE_DIR)/$(BASE_NAME)-shared.include -rf \
+ $(SRC_TAR)
+ cd $(ROOT_DIR); gzip -f $(SRC_TAR)
+
+stestrelease: emptydeps define_build
+ cd $(ROOT_DIR)/shared; $(MAKE) emptydeps
+ cd $(ROOT_DIR); tar -X $(BASE_DIR)/$(BASE_NAME)-all.exclude -cf \
+ $(SRC_TAR) $(BASE_DIR)/* $(REL_ROOTSRC)
+ cd $(ROOT_DIR); tar -T $(BASE_DIR)/$(BASE_NAME)-shared.include -rf \
+ $(SRC_TAR)
+ cd $(ROOT_DIR); tar -X $(BASE_DIR)/$(BASE_NAME)-test.exclude -rf \
+ $(SRC_TAR) test/$(BASE_NAME)/*
+ cd $(ROOT_DIR); tar -X $(BASE_DIR)/$(BASE_NAME)-vicious.exclude -rf \
+ $(SRC_TAR) ViCious/$(BASE_DIR)/*
+ cd $(ROOT_DIR); gzip -f $(SRC_TAR)
+
+brelease: define_build
+ cd $(ROOT_DIR); tar zcf \
+ $(BIN_TAR).gz $(REL_EXTERNS)
+
+rellibs:
+ cd $(ROOT_DIR); tar zcf \
+ $(LIB_TAR).gz $(REL_LIBNAMES)
+
+drelease: define_build
+ cd $(ROOT_DIR); tar -X $(BASE_DIR)/$(BASE_NAME)-doc.exclude -zcf \
+ $(DOC_TAR).gz doc/examples/$(BASE_NAME)/*
+
+release: srelease brelease drelease
+ cd $(ROOT_DIR); tar -X $(BASE_DIR)/$(BASE_NAME)-all.exclude -cf \
+ $(ALL_TAR) $(BASE_DIR)/* $(REL_ROOTSRC) $(REL_EXTERNS)
+ cd $(ROOT_DIR); tar -T $(BASE_DIR)/$(BASE_NAME)-shared.include -rf \
+ $(ALL_TAR)
+ cd $(ROOT_DIR); tar -X $(BASE_DIR)/$(BASE_NAME)-doc.exclude -rf \
+ $(ALL_TAR) doc/examples/$(BASE_NAME)/*
+ cd $(ROOT_DIR); gzip -f $(ALL_TAR)
+
+testrelease: stestrelease brelease
+ cd $(ROOT_DIR); tar -X $(BASE_DIR)/$(BASE_NAME)-all.exclude -cf \
+ $(ALL_TAR) $(BASE_DIR)/* $(REL_ROOTSRC) $(REL_EXTERNS)
+ cd $(ROOT_DIR); tar -T $(BASE_DIR)/$(BASE_NAME)-shared.include -rf \
+ $(ALL_TAR)
+ cd $(ROOT_DIR); tar -X $(BASE_DIR)/$(BASE_NAME)-test.exclude -rf \
+ $(ALL_TAR) test/$(BASE_NAME)/*
+ cd $(ROOT_DIR); tar -X $(BASE_DIR)/$(BASE_NAME)-vicious.exclude -rf \
+ $(ALL_TAR) ViCious/$(BASE_DIR)/*
+ cd $(ROOT_DIR); gzip -f $(ALL_TAR)
+
+snap: emptyalldeps testrelease rellibs
+
+depend:
+ $(CC) $(CFLAGS) -M $(SOURCES) > Makefile.deps
+ $(SUBDIRS)
+
+emptydeps:
+ -rm -f Makefile.deps
+ touch Makefile.deps
+ chmod 666 Makefile.deps
+
+emptyalldeps: emptydeps
+ $(SUBDIRS)
+
+Makefile.deps:
+ touch Makefile.deps
+ chmod 666 Makefile.deps
+
+-include Makefile.deps
diff --git a/ViCious/cyclone/sources b/ViCious/cyclone/sources
new file mode 100644
index 0000000..cf37233
--- /dev/null
+++ b/ViCious/cyclone/sources
@@ -0,0 +1,184 @@
+LIB_CYCLONE = \
+ shadow\cyclone.c \
+ shadow\nettles.c \
+ shadow\dummies.c \
+ shared\common\loud.c \
+ shared\common\grow.c \
+ shared\common\binport.c \
+ shared\common\port.c \
+ shared\hammer\file.c \
+ shared\sickle\sic.c \
+ shared\unstable\fragile.c \
+ shared\unstable\loader.c
+
+LIB_HAMMER = \
+ hammer\hammer.c \
+ hammer\allhammers.c \
+ shared\common\loud.c \
+ shared\common\grow.c \
+ shared\common\rand.c \
+ shared\common\vefl.c \
+ shared\common\sq.c \
+ shared\common\bifi.c \
+ shared\common\mifi.c \
+ shared\common\binport.c \
+ shared\common\port.c \
+ shared\hammer\file.c \
+ shared\hammer\gui.c \
+ shared\hammer\tree.c \
+ shared\unstable\fragile.c
+
+ALL_HAMMERS = \
+ hammer\testmess.c \
+ hammer\accum.c \
+ hammer\acos.c \
+ hammer\active.c \
+ hammer\anal.c \
+ hammer\Append.c \
+ hammer\asin.c \
+ hammer\bangbang.c \
+ hammer\bondo.c \
+ hammer\Borax.c \
+ hammer\Bucket.c \
+ hammer\buddy.c \
+ hammer\capture.c \
+ hammer\cartopol.c \
+ hammer\Clip.c \
+ hammer\coll.c \
+ hammer\comment.c \
+ hammer\cosh.c \
+ hammer\counter.c \
+ hammer\cycle.c \
+ hammer\decide.c \
+ hammer\Decode.c \
+ hammer\drunk.c \
+ hammer\flush.c \
+ hammer\forward.c \
+ hammer\fromsymbol.c \
+ hammer\funbuff.c \
+ hammer\funnel.c \
+ hammer\gate.c \
+ hammer\grab.c \
+ hammer\Histo.c \
+ hammer\iter.c \
+ hammer\match.c \
+ hammer\maximum.c \
+ hammer\mean.c \
+ hammer\midiflush.c \
+ hammer\midiformat.c \
+ hammer\midiparse.c \
+ hammer\minimum.c \
+ hammer\mousefilter.c \
+ hammer\MouseState.c \
+ hammer\next.c \
+ hammer\offer.c \
+ hammer\onebang.c \
+ hammer\past.c \
+ hammer\Peak.c \
+ hammer\poltocar.c \
+ hammer\prepend.c \
+ hammer\prob.c \
+ hammer\pv.c \
+ hammer\seq.c \
+ hammer\sinh.c \
+ hammer\speedlim.c \
+ hammer\spell.c \
+ hammer\split.c \
+ hammer\spray.c \
+ hammer\sprintf.c \
+ hammer\substitute.c \
+ hammer\sustain.c \
+ hammer\switch.c \
+ hammer\tanh.c \
+ hammer\thresh.c \
+ hammer\TogEdge.c \
+ hammer\tosymbol.c \
+ hammer\Trough.c \
+ hammer\universal.c \
+ hammer\urn.c \
+ hammer\Uzi.c \
+ hammer\xbendin.c \
+ hammer\xbendin2.c \
+ hammer\xbendout.c \
+ hammer\xbendout2.c \
+ hammer\xnotein.c \
+ hammer\xnoteout.c \
+ hammer\zl.c
+
+LIB_SICKLE = \
+ sickle\sickle.c \
+ sickle\allsickles.c \
+ shared\common\loud.c \
+ shared\common\grow.c \
+ shared\common\vefl.c \
+ shared\common\binport.c \
+ shared\common\port.c \
+ shared\hammer\file.c \
+ shared\sickle\sic.c \
+ shared\sickle\arsic.c \
+ shared\unstable\forky.c \
+ shared\unstable\fragile.c
+
+ALL_SICKLES = \
+ sickle\abs.c \
+ sickle\acos.c \
+ sickle\acosh.c \
+ sickle\allpass.c \
+ sickle\asin.c \
+ sickle\asinh.c \
+ sickle\atan.c \
+ sickle\atan2.c \
+ sickle\atanh.c \
+ sickle\average.c \
+ sickle\avg.c \
+ sickle\bitand.c \
+ sickle\bitnot.c \
+ sickle\bitor.c \
+ sickle\bitshift.c \
+ sickle\bitxor.c \
+ sickle\capture.c \
+ sickle\cartopol.c \
+ sickle\change.c \
+ sickle\click.c \
+ sickle\Clip.c \
+ sickle\comb.c \
+ sickle\cosh.c \
+ sickle\cosx.c \
+ sickle\count.c \
+ sickle\cycle.c \
+ sickle\delay.c \
+ sickle\delta.c \
+ sickle\deltaclip.c \
+ sickle\edge.c \
+ sickle\frameaccum.c \
+ sickle\framedelta.c \
+ sickle\index.c \
+ sickle\kink.c \
+ sickle\Line.c \
+ sickle\linedrive.c \
+ sickle\log.c \
+ sickle\lookup.c \
+ sickle\minmax.c \
+ sickle\peakamp.c \
+ sickle\peek.c \
+ sickle\phasewrap.c \
+ sickle\play.c \
+ sickle\poltocar.c \
+ sickle\pow.c \
+ sickle\rand.c \
+ sickle\rampsmooth.c \
+ sickle\record.c \
+ sickle\sah.c \
+ sickle\Scope.c \
+ sickle\sinh.c \
+ sickle\sinx.c \
+ sickle\slide.c \
+ sickle\Snapshot.c \
+ sickle\spike.c \
+ sickle\tanh.c \
+ sickle\tanx.c \
+ sickle\train.c \
+ sickle\trapezoid.c \
+ sickle\triangle.c \
+ sickle\vectral.c \
+ sickle\wave.c
diff --git a/cyclone/Makefile b/cyclone/Makefile
new file mode 100644
index 0000000..fc022be
--- /dev/null
+++ b/cyclone/Makefile
@@ -0,0 +1,2 @@
+ROOT_DIR = ..
+include $(ROOT_DIR)/Makefile.common
diff --git a/cyclone/Makefile.dirs b/cyclone/Makefile.dirs
new file mode 100644
index 0000000..0dde72f
--- /dev/null
+++ b/cyclone/Makefile.dirs
@@ -0,0 +1,2 @@
+MIXED_DIRS = shadow hammer sickle
+RELEASE_DIRS = shadow hammer sickle
diff --git a/cyclone/Makefile.objects b/cyclone/Makefile.objects
new file mode 100644
index 0000000..9b421fe
--- /dev/null
+++ b/cyclone/Makefile.objects
@@ -0,0 +1,24 @@
+HLOUD_OBJECTS = common/loud.o
+HFRAGILE_OBJECTS = common/loud.o unstable/fragile.o
+HGROW_OBJECTS = common/grow.o common/loud.o
+HFILE_OBJECTS = hammer/file.o common/loud.o
+HRAND_OBJECTS = common/rand.o common/loud.o
+HRANDFILE_OBJECTS = common/rand.o hammer/file.o common/loud.o
+HRANDGROW_OBJECTS = common/rand.o common/grow.o common/loud.o
+HTREE_OBJECTS = hammer/tree.o common/loud.o
+HTREEFILEVEFL_OBJECTS = hammer/tree.o hammer/file.o \
+ common/vefl.o common/loud.o unstable/fragile.o
+HGUI_OBJECTS = hammer/gui.o common/loud.o
+HSEQ_OBJECTS = common/sq.o common/bifi.o common/mifi.o \
+ hammer/file.o common/grow.o common/loud.o
+SSIC_OBJECTS = sickle/sic.o common/loud.o
+SFORKY_OBJECTS = sickle/sic.o common/loud.o unstable/forky.o
+SFRAGILE_OBJECTS = sickle/sic.o common/loud.o unstable/fragile.o
+SGROW_OBJECTS = common/grow.o sickle/sic.o common/loud.o
+SGROWFORKY_OBJECTS = common/grow.o sickle/sic.o common/loud.o unstable/forky.o
+SVEFL_OBJECTS = common/vefl.o sickle/sic.o common/loud.o unstable/fragile.o
+SARSIC_OBJECTS = sickle/sic.o sickle/arsic.o common/vefl.o \
+ common/loud.o unstable/fragile.o
+SFILE_OBJECTS = hammer/file.o sickle/sic.o common/loud.o
+RELEASE_LIBS = cyclone hammer sickle
+RELEASE_APPS = cyclist
diff --git a/cyclone/Makefile.sources b/cyclone/Makefile.sources
new file mode 100644
index 0000000..4d6cc29
--- /dev/null
+++ b/cyclone/Makefile.sources
@@ -0,0 +1,191 @@
+TYPES = HPLAIN HLOUD HFRAGILE HGROW HFILE HRAND HRANDFILE HRANDGROW \
+ HTREE HTREEFILEVEFL HGUI HSEQ \
+ SPLAINNOTILDE SPLAIN SSIC SFORKY SFRAGILE SGROW SGROWFORKY \
+ SVEFL SARSIC SFILE
+
+HPLAIN_SOURCES = \
+hammer/testmess.c \
+hammer/accum.c \
+hammer/acos.c \
+hammer/asin.c \
+hammer/Bucket.c \
+hammer/cartopol.c \
+hammer/cosh.c \
+hammer/counter.c \
+hammer/flush.c \
+hammer/forward.c \
+hammer/fromsymbol.c \
+hammer/mean.c \
+hammer/midiflush.c \
+hammer/midiformat.c \
+hammer/midiparse.c \
+hammer/next.c \
+hammer/onebang.c \
+hammer/Peak.c \
+hammer/poltocar.c \
+hammer/sinh.c \
+hammer/split.c \
+hammer/sustain.c \
+hammer/tanh.c \
+hammer/Trough.c \
+hammer/Uzi.c \
+hammer/xbendin.c \
+hammer/xbendin2.c \
+hammer/xbendout.c \
+hammer/xbendout2.c \
+hammer/xnotein.c \
+hammer/xnoteout.c
+
+HLOUD_SOURCES = \
+hammer/anal.c \
+hammer/bangbang.c \
+hammer/Borax.c \
+hammer/comment.c \
+hammer/cycle.c \
+hammer/decide.c \
+hammer/Decode.c \
+hammer/gate.c \
+hammer/Histo.c \
+hammer/maximum.c \
+hammer/minimum.c \
+hammer/spell.c \
+hammer/spray.c \
+hammer/sprintf.c \
+hammer/switch.c \
+hammer/TogEdge.c
+
+HFRAGILE_SOURCES = \
+hammer/grab.c \
+hammer/universal.c
+
+HGROW_SOURCES = \
+hammer/Append.c \
+hammer/bondo.c \
+hammer/buddy.c \
+hammer/Clip.c \
+hammer/funnel.c \
+hammer/iter.c \
+hammer/match.c \
+hammer/past.c \
+hammer/prepend.c \
+hammer/pv.c \
+hammer/speedlim.c \
+hammer/substitute.c \
+hammer/thresh.c \
+hammer/tosymbol.c \
+hammer/zl.c
+
+HFILE_SOURCES = \
+hammer/capture.c \
+hammer/coll.c
+
+HRAND_SOURCES = \
+hammer/drunk.c
+
+HRANDFILE_SOURCES = \
+hammer/prob.c
+
+HRANDGROW_SOURCES = \
+hammer/urn.c
+
+HTREE_SOURCES = \
+hammer/offer.c
+
+HTREEFILEVEFL_SOURCES = \
+hammer/funbuff.c
+
+HGUI_SOURCES = \
+hammer/active.c \
+hammer/mousefilter.c \
+hammer/MouseState.c
+
+HSEQ_SOURCES = \
+hammer/seq.c
+
+SPLAINNOTILDE_SOURCES = \
+sickle/linedrive.c
+
+SSIC_TILDE = $(TILDE)
+SSIC_SOURCES = \
+sickle/abs.c \
+sickle/acos.c \
+sickle/acosh.c \
+sickle/allpass.c \
+sickle/asin.c \
+sickle/asinh.c \
+sickle/atan.c \
+sickle/atan2.c \
+sickle/atanh.c \
+sickle/average.c \
+sickle/avg.c \
+sickle/bitnot.c \
+sickle/bitshift.c \
+sickle/change.c \
+sickle/Clip.c \
+sickle/comb.c \
+sickle/cosh.c \
+sickle/cosx.c \
+sickle/count.c \
+sickle/delay.c \
+sickle/delta.c \
+sickle/deltaclip.c \
+sickle/edge.c \
+sickle/kink.c \
+sickle/log.c \
+sickle/minmax.c \
+sickle/peakamp.c \
+sickle/phasewrap.c \
+sickle/pow.c \
+sickle/rampsmooth.c \
+sickle/rand.c \
+sickle/sah.c \
+sickle/sinh.c \
+sickle/sinx.c \
+sickle/slide.c \
+sickle/Snapshot.c \
+sickle/spike.c \
+sickle/tanh.c \
+sickle/tanx.c \
+sickle/train.c \
+sickle/trapezoid.c \
+sickle/triangle.c \
+sickle/vectral.c
+
+SFORKY_TILDE = $(TILDE)
+SFORKY_SOURCES = \
+sickle/bitand.c \
+sickle/bitor.c \
+sickle/bitxor.c
+
+SFRAGILE_TILDE = $(TILDE)
+SFRAGILE_SOURCES = \
+sickle/cartopol.c \
+sickle/poltocar.c
+
+SGROW_TILDE = $(TILDE)
+SGROW_SOURCES = \
+sickle/click.c \
+sickle/frameaccum.c \
+sickle/framedelta.c \
+sickle/Line.c
+
+SGROWFORKY_TILDE = $(TILDE)
+SGROWFORKY_SOURCES = \
+sickle/Scope.c
+
+SVEFL_TILDE = $(TILDE)
+SVEFL_SOURCES = \
+sickle/cycle.c
+
+SARSIC_TILDE = $(TILDE)
+SARSIC_SOURCES = \
+sickle/index.c \
+sickle/lookup.c \
+sickle/peek.c \
+sickle/play.c \
+sickle/record.c \
+sickle/wave.c
+
+SFILE_TILDE = $(TILDE)
+SFILE_SOURCES = \
+sickle/capture.c
diff --git a/cyclone/build_counter b/cyclone/build_counter
new file mode 100644
index 0000000..1e05d4b
--- /dev/null
+++ b/cyclone/build_counter
@@ -0,0 +1,3 @@
+#define CYCLONE_VERSION "0.1"
+#define CYCLONE_RELEASE "alpha"
+#define CYCLONE_BUILD 42
diff --git a/cyclone/cyclone-all.exclude b/cyclone/cyclone-all.exclude
new file mode 100644
index 0000000..8b8d91f
--- /dev/null
+++ b/cyclone/cyclone-all.exclude
@@ -0,0 +1,9 @@
+*~
+*.o
+*.gz
+*.html
+*.out
+*/*/old
+*/*/old/*
+*/*/ref
+*/*/ref/*
diff --git a/cyclone/cyclone-shared.include b/cyclone/cyclone-shared.include
new file mode 100644
index 0000000..49cc815
--- /dev/null
+++ b/cyclone/cyclone-shared.include
@@ -0,0 +1,35 @@
+shared/shared.c
+shared/shared.h
+shared/unstable/forky.c
+shared/unstable/forky.h
+shared/unstable/fragile.c
+shared/unstable/fragile.h
+shared/unstable/pd_imp.h
+shared/common/grow.c
+shared/common/grow.h
+shared/common/loud.c
+shared/common/loud.h
+shared/common/binport.c
+shared/common/binport.h
+shared/common/port.c
+shared/common/port.h
+shared/common/rand.c
+shared/common/rand.h
+shared/common/vefl.c
+shared/common/vefl.h
+shared/common/sq.c
+shared/common/sq.h
+shared/common/bifi.c
+shared/common/bifi.h
+shared/common/mifi.c
+shared/common/mifi.h
+shared/hammer/file.c
+shared/hammer/file.h
+shared/hammer/gui.c
+shared/hammer/gui.h
+shared/hammer/tree.c
+shared/hammer/tree.h
+shared/sickle/sic.c
+shared/sickle/sic.h
+shared/sickle/arsic.c
+shared/sickle/arsic.h
diff --git a/cyclone/cyclone-test.exclude b/cyclone/cyclone-test.exclude
new file mode 100644
index 0000000..ec84f87
--- /dev/null
+++ b/cyclone/cyclone-test.exclude
@@ -0,0 +1,4 @@
+*~
+import-result.pd
+temporary
+temporary/*
diff --git a/cyclone/cyclone-vicious.exclude b/cyclone/cyclone-vicious.exclude
new file mode 100644
index 0000000..5e5a82e
--- /dev/null
+++ b/cyclone/cyclone-vicious.exclude
@@ -0,0 +1,3 @@
+*~
+old
+old/*
diff --git a/cyclone/hammer/Append.c b/cyclone/hammer/Append.c
new file mode 100644
index 0000000..19978c7
--- /dev/null
+++ b/cyclone/hammer/Append.c
@@ -0,0 +1,207 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/loud.h"
+#include "common/grow.h"
+
+#define APPEND_INISIZE 32 /* LATER rethink */
+#define APPEND_MAXSIZE 256
+
+typedef struct _append
+{
+ t_object x_ob;
+ int x_size; /* as allocated */
+ int x_natoms; /* as used */
+ t_atom *x_message;
+ t_atom *x_messbuf;
+ t_atom x_messini[APPEND_INISIZE];
+ int x_entered;
+ int x_auxsize;
+ t_atom *x_auxbuf;
+} t_append;
+
+static t_class *append_class;
+
+/* Usually a preallocation method is used, except in special cases of:
+ 1) reentrant output request, or 2) an output request which would cause
+ resizing to more than MAXSIZE (no such limit for a 'set' message).
+ In both special cases, a temporary output buffer is allocated.
+ A separately preallocated output buffer is not used, thus avoiding
+ memcpying of the stored message (a small performance gain when the
+ preallocation method is chosen). Instead, self-invoked 'set'
+ messages are postponed, using an auxiliary buffer.
+*/
+
+/* Any Append's output goes through outlet_anything() -> typedmess() */
+
+static void append_setnatoms(t_append *x, int natoms)
+{
+ x->x_message = x->x_messbuf + x->x_size - natoms;
+ x->x_natoms = natoms;
+}
+
+static void append_anything(t_append *x, t_symbol *s, int ac, t_atom *av)
+{
+ int reentered = x->x_entered;
+ int prealloc = !reentered;
+ int ntotal = x->x_natoms + ac;
+ t_atom *buf;
+ x->x_entered = 1;
+ if (prealloc && ntotal > x->x_size)
+ {
+ if (ntotal > APPEND_MAXSIZE)
+ prealloc = 0;
+ else
+ {
+ int nrequested = ntotal;
+ x->x_messbuf = grow_withtail(&nrequested, &x->x_natoms,
+ (char **)&x->x_message,
+ &x->x_size, x->x_messbuf,
+ APPEND_INISIZE, x->x_messini,
+ sizeof(*x->x_message));
+ prealloc = (nrequested == ntotal);
+ }
+ }
+ if (prealloc)
+ {
+ buf = x->x_message - ac;
+ if (ac)
+ memcpy(buf, av, ac * sizeof(*buf));
+ outlet_anything(((t_object *)x)->ob_outlet, s, ntotal, buf);
+ }
+ else
+ {
+ /* LATER consider using the stack if ntotal <= MAXSTACK */
+ if (buf = getbytes(ntotal * sizeof(*buf)))
+ {
+ if (ac)
+ memcpy(buf, av, ac * sizeof(*buf));
+ if (x->x_natoms)
+ memcpy(buf + ac, x->x_message, x->x_natoms * sizeof(*buf));
+ outlet_anything(((t_object *)x)->ob_outlet, s, ntotal, buf);
+ freebytes(buf, ntotal * sizeof(*buf));
+ }
+ }
+ if (!reentered)
+ {
+ x->x_entered = 0;
+ if (x->x_auxbuf)
+ {
+ if (x->x_auxsize <= x->x_size)
+ {
+ append_setnatoms(x, x->x_auxsize / 2);
+ memcpy(x->x_message, x->x_auxbuf + x->x_natoms,
+ x->x_natoms * sizeof(*x->x_message));
+ freebytes(x->x_auxbuf, x->x_auxsize * sizeof(*x->x_auxbuf));
+ }
+ else
+ {
+ if (x->x_messbuf != x->x_messini)
+ freebytes(x->x_messbuf, x->x_size * sizeof(*x->x_messbuf));
+ x->x_size = x->x_auxsize;
+ x->x_messbuf = x->x_auxbuf;
+ append_setnatoms(x, x->x_auxsize / 2);
+ }
+ x->x_auxbuf = 0;
+ }
+ }
+}
+
+static void append_bang(t_append *x)
+{
+ /* CHECKED: a nop */
+}
+
+static void append_float(t_append *x, t_float f)
+{
+ t_atom at;
+ SETFLOAT(&at, f);
+ append_anything(x, &s_list, 1, &at); /* CHECKED: converted to list */
+}
+
+/* CHECKED: incompatible -- LATER consider converting to anything */
+static void append_symbol(t_append *x, t_symbol *s)
+{
+ t_atom at;
+ SETSYMBOL(&at, s);
+ append_anything(x, &s_symbol, 1, &at);
+}
+
+/* LATER gpointer */
+
+static void append_set(t_append *x, t_symbol *s, int ac, t_atom *av)
+{
+ int newsize = ac * 2;
+ if (newsize > 0)
+ {
+ if (x->x_entered)
+ {
+ if (x->x_auxbuf)
+ {
+ loud_warning((t_pd *)x, "\'set\' message overridden");
+ freebytes(x->x_auxbuf, x->x_auxsize * sizeof(*x->x_auxbuf));
+ x->x_auxsize = 0;
+ }
+ if (x->x_auxbuf = getbytes(newsize * sizeof(*x->x_auxbuf)))
+ {
+ memcpy(x->x_auxbuf + ac, av, ac * sizeof(*x->x_auxbuf));
+ x->x_auxsize = newsize;
+ }
+ }
+ else
+ {
+ t_atom *ap;
+ if (newsize > x->x_size)
+ {
+ int sz = newsize;
+ x->x_messbuf = grow_nodata(&sz, &x->x_size, x->x_messbuf,
+ APPEND_INISIZE, x->x_messini,
+ sizeof(*x->x_messbuf));
+ if (sz != newsize)
+ ac = sz / 2; /* LATER rethink */
+ }
+ append_setnatoms(x, ac);
+ ap = x->x_message;
+ while (ac--) *ap++ = *av++;
+ }
+ }
+}
+
+static void append_free(t_append *x)
+{
+ if (x->x_messbuf != x->x_messini)
+ freebytes(x->x_messbuf, x->x_size * sizeof(*x->x_messbuf));
+}
+
+static void *append_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_append *x = (t_append *)pd_new(append_class);
+ x->x_size = APPEND_INISIZE;
+ x->x_natoms = 0;
+ x->x_messbuf = x->x_messini;
+ x->x_auxbuf = 0;
+ x->x_entered = 0;
+ outlet_new((t_object *)x, &s_anything);
+ append_setnatoms(x, 0);
+ append_set(x, 0, ac, av);
+ return (x);
+}
+
+void Append_setup(void)
+{
+ append_class = class_new(gensym("Append"),
+ (t_newmethod)append_new,
+ (t_method)append_free,
+ sizeof(t_append), 0,
+ A_GIMME, 0);
+ class_addbang(append_class, append_bang);
+ class_addfloat(append_class, append_float);
+ class_addsymbol(append_class, append_symbol);
+ class_addlist(append_class, append_anything); /* LATER rethink */
+ class_addanything(append_class, append_anything);
+ class_addmethod(append_class, (t_method)append_set,
+ gensym("set"), A_GIMME, 0);
+}
diff --git a/cyclone/hammer/Borax.c b/cyclone/hammer/Borax.c
new file mode 100644
index 0000000..26e0ef8
--- /dev/null
+++ b/cyclone/hammer/Borax.c
@@ -0,0 +1,177 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* The first version of this code was written by Olaf Matthes.
+ It was entirely reimplemented in the hope of adapting it to the
+ cyclone's guidelines. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/loud.h"
+
+#define BORAX_MAXVOICES 128 /* CHECKME */
+
+typedef struct _Borax_voice
+{
+ int v_index; /* free iff zero */
+ double v_onset;
+ int v_nonsets;
+} t_Borax_voice;
+
+typedef struct _Borax
+{
+ t_object x_ob;
+ int x_vel; /* CHECKME t_float controlled with floatinlet
+ (CHECKME the same in flush) */
+ double x_onset;
+ int x_nonsets;
+ int x_ndurs;
+ int x_ndtimes;
+ int x_minindex;
+ int x_indices[BORAX_MAXVOICES]; /* 0 (free) or 1 (used) */
+ int x_nvoices;
+ t_Borax_voice x_voices[BORAX_MAXVOICES];
+ t_outlet *x_voiceout;
+ t_outlet *x_nvoicesout;
+ t_outlet *x_pitchout;
+ t_outlet *x_velout;
+ t_outlet *x_ndursout;
+ t_outlet *x_durout;
+ t_outlet *x_ndtimesout;
+ t_outlet *x_dtimeout;
+} t_Borax;
+
+static t_class *Borax_class;
+
+static void Borax_delta(t_Borax *x)
+{
+ /* CHECKME first note */
+ float dtime = clock_gettimesince(x->x_onset); /* CHECKME */
+ outlet_float(x->x_dtimeout, dtime);
+ outlet_float(x->x_ndtimesout, ++x->x_ndtimes); /* CHECKME */
+}
+
+static void Borax_durout(t_Borax *x, int pitch)
+{
+ float dur = clock_gettimesince(x->x_voices[pitch].v_onset); /* CHECKME */
+ outlet_float(x->x_durout, dur);
+ outlet_float(x->x_ndursout, ++x->x_ndurs); /* CHECKME */
+}
+
+static void Borax_float(t_Borax *x, t_float f)
+{
+ int pitch;
+ if (loud_checkint((t_pd *)x, f, &pitch, &s_float)) /* CHECKME */
+ {
+ int index;
+ if (pitch < 0 || pitch >= BORAX_MAXVOICES)
+ {
+ /* CHECKME pitch range, complaints */
+ return;
+ }
+ index = x->x_voices[pitch].v_index;
+ if (x->x_vel)
+ {
+ if (index)
+ return; /* CHECKME */
+ x->x_indices[index = x->x_minindex] = 1;
+ while (x->x_indices[++x->x_minindex]);
+ index++; /* CHECKME one-based? */
+ Borax_delta(x);
+ x->x_onset = clock_getlogicaltime(); /* CHECKME (in delta?) */
+ x->x_voices[pitch].v_index = index;
+ x->x_voices[pitch].v_onset = x->x_onset;
+ x->x_voices[pitch].v_nonsets = ++x->x_nonsets;
+ x->x_nvoices++;
+ }
+ else
+ {
+ if (!index)
+ return; /* CHECKME */
+ index--;
+ x->x_indices[index] = 0;
+ if (index < x->x_minindex) x->x_minindex = index;
+ index++;
+ Borax_durout(x, pitch);
+ x->x_voices[pitch].v_index = 0;
+ x->x_nvoices--;
+ }
+ outlet_float(x->x_velout, x->x_vel);
+ outlet_float(x->x_pitchout, pitch);
+ outlet_float(x->x_nvoicesout, x->x_nvoices);
+ outlet_float(x->x_voiceout, index);
+ outlet_float(((t_object *)x)->ob_outlet, x->x_voices[pitch].v_nonsets);
+ }
+}
+
+static void Borax_ft1(t_Borax *x, t_floatarg f)
+{
+ x->x_vel = (int)f; /* CHECKME */
+}
+
+static void Borax_reset(t_Borax *x)
+{
+ x->x_vel = 0;
+ x->x_onset = clock_getlogicaltime();
+ x->x_nonsets = x->x_ndurs = x->x_ndtimes = 0;
+ x->x_minindex = 0;
+ memset(x->x_indices, 0, sizeof(x->x_indices));
+ x->x_nvoices = 0;
+ memset(x->x_voices, 0, sizeof(x->x_voices));
+}
+
+static void Borax_bang2(t_Borax *x)
+{
+ int pitch;
+ for (pitch = 0; pitch < BORAX_MAXVOICES; pitch++)
+ {
+ if (x->x_voices[pitch].v_index)
+ {
+ /* CHECKME counters, etc. */
+ Borax_durout(x, pitch);
+ outlet_float(x->x_velout, 0);
+ outlet_float(x->x_pitchout, pitch);
+ outlet_float(x->x_nvoicesout, --x->x_nvoices);
+ outlet_float(x->x_voiceout, x->x_voices[pitch].v_index);
+ outlet_float(((t_object *)x)->ob_outlet,
+ x->x_voices[pitch].v_nonsets);
+ }
+ }
+ Borax_reset(x);
+}
+
+/* CHECKME flush in a destructor */
+
+static void *Borax_new(void)
+{
+ t_Borax *x = (t_Borax *)pd_new(Borax_class);
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ inlet_new((t_object *)x, (t_pd *)x, &s_bang, gensym("bang2"));
+ outlet_new((t_object *)x, &s_float);
+ x->x_voiceout = outlet_new((t_object *)x, &s_float);
+ x->x_nvoicesout = outlet_new((t_object *)x, &s_float);
+ x->x_pitchout = outlet_new((t_object *)x, &s_float);
+ x->x_velout = outlet_new((t_object *)x, &s_float);
+ x->x_ndursout = outlet_new((t_object *)x, &s_float);
+ x->x_durout = outlet_new((t_object *)x, &s_float);
+ x->x_ndtimesout = outlet_new((t_object *)x, &s_float);
+ x->x_dtimeout = outlet_new((t_object *)x, &s_float);
+ Borax_reset(x);
+ return (x);
+}
+
+void Borax_setup(void)
+{
+ Borax_class = class_new(gensym("Borax"),
+ (t_newmethod)Borax_new, 0,
+ sizeof(t_Borax), 0, 0);
+ class_addfloat(Borax_class, Borax_float);
+ /* CHECKME list unfolding */
+ class_addmethod(Borax_class, (t_method)Borax_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(Borax_class, (t_method)Borax_bang2,
+ gensym("bang2"), 0);
+ class_addmethod(Borax_class, (t_method)Borax_delta,
+ gensym("delta"), 0);
+}
diff --git a/cyclone/hammer/Bucket.c b/cyclone/hammer/Bucket.c
new file mode 100644
index 0000000..036f836
--- /dev/null
+++ b/cyclone/hammer/Bucket.c
@@ -0,0 +1,137 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* This is a modified version of Joseph A. Sarlo's code.
+ The most important changes are listed in "pd-lib-notes.txt" file. */
+
+#include "m_pd.h"
+
+typedef struct _Bucket
+{
+ t_object x_ob;
+ int x_numbucks;
+ t_float *x_bucks; /* CHECKED: no limit */
+ t_outlet **x_outs;
+ short int x_frozen; /* 0 for thawed, 1 for frozen */
+ short int x_dir; /* 0 for L2R, 1 for R2L */
+} t_Bucket;
+
+static t_class *Bucket_class;
+
+static void Bucket_bang(t_Bucket *x)
+{
+ int i = x->x_numbucks;
+ /* CHECKED: outlets output in right-to-left order */
+ while (i--) outlet_float(x->x_outs[i], x->x_bucks[i]);
+}
+
+static void Bucket_float(t_Bucket *x, t_float val)
+{
+ int i;
+
+ if (!x->x_frozen)
+ Bucket_bang(x);
+ if (!x->x_dir)
+ {
+ for (i = x->x_numbucks - 1; i > 0; i--)
+ x->x_bucks[i] = x->x_bucks[i - 1];
+ x->x_bucks[0] = val;
+ }
+ else
+ {
+ for (i = 0; i < x->x_numbucks - 1; i++)
+ x->x_bucks[i] = x->x_bucks[i + 1];
+ x->x_bucks[x->x_numbucks - 1] = val;
+ }
+}
+
+static void Bucket_freeze(t_Bucket *x)
+{
+ x->x_frozen = 1;
+}
+
+static void Bucket_thaw(t_Bucket *x)
+{
+ x->x_frozen = 0;
+}
+
+static void Bucket_roll(t_Bucket *x)
+{
+ if (x->x_dir)
+ Bucket_float(x, x->x_bucks[0]);
+ else
+ Bucket_float(x, x->x_bucks[x->x_numbucks - 1]);
+}
+
+static void Bucket_rtol(t_Bucket *x)
+{
+ x->x_dir = 1;
+}
+
+static void Bucket_ltor(t_Bucket *x)
+{
+ x->x_dir = 0;
+}
+
+static void Bucket_set(t_Bucket *x, t_floatarg f)
+{
+ int i = x->x_numbucks;
+ while (i--) x->x_bucks[i] = f;
+ if (!x->x_frozen) /* CHECKED */
+ Bucket_bang(x);
+}
+
+static void Bucket_free(t_Bucket *x)
+{
+ if (x->x_bucks)
+ freebytes(x->x_bucks, x->x_numbucks * sizeof(*x->x_bucks));
+ if (x->x_outs)
+ freebytes(x->x_outs, x->x_numbucks * sizeof(*x->x_outs));
+}
+
+static void *Bucket_new(t_floatarg val)
+{
+ t_Bucket *x;
+ int i, nbucks = (int)val;
+ t_float *bucks;
+ t_outlet **outs;
+ if (nbucks < 1)
+ nbucks = 1;
+ if (!(bucks = (t_float *)getbytes(nbucks * sizeof(*bucks))))
+ return (0);
+ if (!(outs = (t_outlet **)getbytes(nbucks * sizeof(*outs))))
+ {
+ freebytes(bucks, nbucks * sizeof(*bucks));
+ return (0);
+ }
+ x = (t_Bucket *)pd_new(Bucket_class);
+ x->x_numbucks = nbucks;
+ x->x_bucks = bucks;
+ x->x_outs = outs;
+ x->x_frozen = 0;
+ x->x_dir = 0;
+ while (nbucks--) *outs++ = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void Bucket_setup(void)
+{
+ Bucket_class = class_new(gensym("Bucket"),
+ (t_newmethod)Bucket_new,
+ (t_method)Bucket_free,
+ sizeof(t_Bucket), 0, A_DEFFLOAT, 0);
+ class_addbang(Bucket_class, Bucket_bang);
+ class_addfloat(Bucket_class, Bucket_float);
+ class_addmethod(Bucket_class, (t_method)Bucket_freeze, gensym("freeze"), 0);
+ class_addmethod(Bucket_class, (t_method)Bucket_thaw, gensym("thaw"), 0);
+ class_addmethod(Bucket_class, (t_method)Bucket_ltor, gensym("L2R"), 0);
+ class_addmethod(Bucket_class, (t_method)Bucket_rtol, gensym("R2L"), 0);
+ /* CHECKED (refman error) roll has no argument */
+ class_addmethod(Bucket_class, (t_method)Bucket_roll, gensym("roll"), 0);
+ /* 3.5 additions */
+ class_addmethod(Bucket_class, (t_method)Bucket_set,
+ gensym("set"), A_FLOAT, 0);
+ class_addmethod(Bucket_class, (t_method)Bucket_ltor, gensym("l2r"), 0);
+ class_addmethod(Bucket_class, (t_method)Bucket_rtol, gensym("r2l"), 0);
+}
diff --git a/cyclone/hammer/Clip.c b/cyclone/hammer/Clip.c
new file mode 100644
index 0000000..a06d3a8
--- /dev/null
+++ b/cyclone/hammer/Clip.c
@@ -0,0 +1,149 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+#define CLIP_INISIZE 32 /* LATER rethink */
+#define CLIP_MAXSIZE 256
+
+typedef struct _clip
+{
+ t_object x_ob;
+ float x_f1;
+ float x_f2;
+ int x_size; /* as allocated */
+ t_atom *x_message;
+ t_atom x_messini[CLIP_INISIZE];
+ int x_entered;
+} t_clip;
+
+static t_class *clip_class;
+
+/* CHECKED case of f1 > f2: x <= f2 => f1, x > f2 => f2
+ (Pd implementation of clip has it the other way around) */
+static void clip_float(t_clip *x, t_float f)
+{
+ outlet_float(((t_object *)x)->ob_outlet,
+ (f > x->x_f2 ? x->x_f2 : (f < x->x_f1 ? x->x_f1 : f)));
+}
+
+static void clip_list(t_clip *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ int docopy = 0;
+ int i;
+ t_atom *ap;
+ t_float f1 = x->x_f1;
+ t_float f2 = x->x_f2;
+ for (i = 0, ap = av; i < ac; i++, ap++)
+ {
+ t_float f;
+ if (ap->a_type == A_FLOAT)
+ f = ap->a_w.w_float;
+ else
+ {
+ docopy = 1;
+ /* CHECKED: symbols inside lists are converted to zeros */
+ f = 0;
+ }
+ if (f < f1 || f > f2) docopy = 1;
+ }
+ if (docopy)
+ {
+ t_atom *buf;
+ t_atom *bp;
+ int reentered = x->x_entered;
+ int prealloc = !reentered;
+ x->x_entered = 1;
+ if (prealloc && ac > x->x_size)
+ {
+ if (ac > CLIP_MAXSIZE)
+ prealloc = 0;
+ else
+ x->x_message = grow_nodata(&ac, &x->x_size, x->x_message,
+ CLIP_INISIZE, x->x_messini,
+ sizeof(*x->x_message));
+ }
+ if (prealloc) buf = x->x_message;
+ else
+ /* LATER consider using the stack if ntotal <= MAXSTACK */
+ buf = getbytes(ac * sizeof(*buf));
+ if (buf)
+ {
+ for (i = 0, ap = av, bp = buf; i < ac; i++, ap++, bp++)
+ {
+ t_float f = (ap->a_type == A_FLOAT ? ap->a_w.w_float : 0);
+ if (f < f1)
+ f = f1;
+ else if (f > f2)
+ f = f2;
+ SETFLOAT(bp, f);
+ }
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, buf);
+ if (buf != x->x_message)
+ freebytes(buf, ac * sizeof(*buf));
+ }
+ if (!reentered)
+ {
+ x->x_entered = 0;
+ }
+ }
+ else outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av);
+ }
+}
+
+static void clip_set(t_clip *x, t_symbol *s, int ac, t_atom *av)
+{
+ x->x_f1 = 0;
+ x->x_f2 = 0;
+ if (ac) /* CHECKED: 'set' without arguments sets both values to 0 */
+ {
+ if (av->a_type == A_FLOAT) /* CHECKED: symbol is converted to 0 */
+ x->x_f1 = av->a_w.w_float;
+ av++;
+ if (--ac)
+ {
+ if (av->a_type == A_FLOAT)
+ x->x_f2 = av->a_w.w_float;
+ }
+ else x->x_f2 = x->x_f1; /* CHECKED */
+ }
+}
+
+static void clip_free(t_clip *x)
+{
+ if (x->x_message != x->x_messini)
+ freebytes(x->x_message, x->x_size * sizeof(*x->x_message));
+}
+
+static void *clip_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_clip *x = (t_clip *)pd_new(clip_class);
+ x->x_f1 = 0;
+ x->x_f2 = 0;
+ x->x_size = CLIP_INISIZE;
+ x->x_message = x->x_messini;
+ x->x_entered = 0;
+ floatinlet_new((t_object *)x, &x->x_f1);
+ floatinlet_new((t_object *)x, &x->x_f2);
+ outlet_new(&x->x_ob, &s_anything);
+ clip_set(x, 0, ac, av);
+ return (x);
+}
+
+void Clip_setup(void)
+{
+ clip_class = class_new(gensym("Clip"),
+ (t_newmethod)clip_new,
+ (t_method)clip_free,
+ sizeof(t_clip), 0,
+ A_GIMME, 0);
+ class_addfloat(clip_class, clip_float);
+ class_addlist(clip_class, clip_list);
+ class_addmethod(clip_class, (t_method)clip_set,
+ gensym("set"), A_GIMME, 0);
+}
diff --git a/cyclone/hammer/Decode.c b/cyclone/hammer/Decode.c
new file mode 100644
index 0000000..8317d7e
--- /dev/null
+++ b/cyclone/hammer/Decode.c
@@ -0,0 +1,110 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* This is an entirely rewritten version of Joseph A. Sarlo's code.
+ The most important changes are listed in "pd-lib-notes.txt" file. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+
+#define DECODE_MAXOUTS 8 /* CHECKED (does it make any sense?) */
+#define DECODE_DEFOUTS 1
+
+typedef struct _Decode
+{
+ t_object x_ob;
+ int x_numouts;
+ int x_onout;
+ int x_allon; /* submaster switch */
+ int x_alloff; /* master switch */
+ t_outlet **x_outs;
+ t_outlet *x_outbuf[DECODE_MAXOUTS];
+} t_Decode;
+
+static t_class *Decode_class;
+
+/* CHECKED: all outlets deliver after any action */
+/* CHECKED: outlets output in right-to-left order */
+
+static void Decode_deliver(t_Decode *x)
+{
+ int i = x->x_numouts;
+ if (x->x_alloff)
+ while (i--) outlet_float(x->x_outs[i], 0);
+ else if (x->x_allon)
+ while (i--) outlet_float(x->x_outs[i], 1);
+ else
+ while (i--) outlet_float(x->x_outs[i], (i == x->x_onout ? 1 : 0));
+}
+
+static void Decode_float(t_Decode *x, t_floatarg f)
+{
+ int val = (int)f;
+ /* CHECKED: out-of-range input is clipped, not ignored */
+ if (val < 0)
+ val = 0;
+ else if (val >= x->x_numouts)
+ val = x->x_numouts - 1;
+ /* CHECKED: while in all-off mode, input is stored, not ignored */
+ x->x_onout = val;
+ Decode_deliver(x);
+}
+
+static void Decode_allon(t_Decode *x, t_floatarg f)
+{
+ x->x_allon = (f != 0);
+ Decode_deliver(x);
+}
+
+static void Decode_alloff(t_Decode *x, t_floatarg f)
+{
+ x->x_alloff = (f != 0);
+ Decode_deliver(x);
+}
+
+static void Decode_free(t_Decode *x)
+{
+ if (x->x_outs != x->x_outbuf)
+ freebytes(x->x_outs, x->x_numouts * sizeof(*x->x_outs));
+}
+
+static void *Decode_new(t_floatarg val)
+{
+ t_Decode *x;
+ int i, nouts = (int)val;
+ t_outlet **outs;
+ if (nouts < 1)
+ nouts = DECODE_DEFOUTS;
+ if (nouts > DECODE_MAXOUTS)
+ {
+ loud_incompatible_max(Decode_class, DECODE_MAXOUTS, "outlets");
+ if (!(outs = (t_outlet **)getbytes(nouts * sizeof(*outs))))
+ return (0);
+ }
+ else outs = 0;
+ x = (t_Decode *)pd_new(Decode_class);
+ x->x_numouts = nouts;
+ x->x_outs = (outs ? outs : x->x_outbuf);
+ x->x_onout = 0;
+ x->x_allon = 0;
+ x->x_alloff = 0;
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft2"));
+ for (i = 0; i < nouts; i++)
+ x->x_outs[i] = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void Decode_setup(void)
+{
+ Decode_class = class_new(gensym("Decode"),
+ (t_newmethod)Decode_new,
+ (t_method)Decode_free,
+ sizeof(t_Decode), 0, A_DEFFLOAT, 0);
+ class_addfloat(Decode_class, Decode_float);
+ class_addmethod(Decode_class, (t_method)Decode_allon,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(Decode_class, (t_method)Decode_alloff,
+ gensym("ft2"), A_FLOAT, 0);
+}
diff --git a/cyclone/hammer/Histo.c b/cyclone/hammer/Histo.c
new file mode 100644
index 0000000..efb0deb
--- /dev/null
+++ b/cyclone/hammer/Histo.c
@@ -0,0 +1,103 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* This is an entirely rewritten version of Joseph A. Sarlo's code.
+ The most important changes are listed in "pd-lib-notes.txt" file. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+
+#define HISTO_DEFSIZE 128
+
+typedef struct _Histo
+{
+ t_object x_ob;
+ int x_size;
+ unsigned *x_hist; /* LATER consider using 64 bits */
+ int x_lastinput;
+ t_outlet *x_countout;
+} t_Histo;
+
+static t_class *Histo_class;
+
+static void Histo_clear(t_Histo *x)
+{
+ int i = x->x_size;
+ while (i--) x->x_hist[i] = 0;
+ /* CHECKED: last input is kept */
+}
+
+static void Histo_doit(t_Histo *x, int val, int doincr)
+{
+ if (val >= 0 && val < x->x_size)
+ {
+ if (doincr)
+ {
+ /* CHECKED: only in-range numbers are stored */
+ x->x_lastinput = val;
+ x->x_hist[val]++;
+ }
+ outlet_float(x->x_countout, x->x_hist[val]);
+ /* CHECKED: out-of-range numbers are never passed thru */
+ outlet_float(((t_object *)x)->ob_outlet, val);
+ }
+}
+
+static void Histo_bang(t_Histo *x)
+{
+ Histo_doit(x, x->x_lastinput, 0);
+}
+
+static void Histo_float(t_Histo *x, t_floatarg f)
+{
+ int i;
+ if (loud_checkint((t_pd *)x, f, &i, &s_float)) /* CHECKED */
+ Histo_doit(x, i, 1);
+}
+
+static void Histo_ft1(t_Histo *x, t_floatarg f)
+{
+ /* CHECKED: floats are accepted in second inlet (truncated) */
+ Histo_doit(x, (int)f, 0);
+}
+
+static void Histo_free(t_Histo *x)
+{
+ if (x->x_hist)
+ freebytes(x->x_hist, x->x_size * sizeof(*x->x_hist));
+}
+
+static void *Histo_new(t_floatarg f)
+{
+ t_Histo *x;
+ int size = (int)f;
+ unsigned *hist;
+ if (size < 1) /* CHECKED: 1 is allowed */
+ size = HISTO_DEFSIZE;
+ if (!(hist = (unsigned *)getbytes(size * sizeof(*hist))))
+ return (0);
+ x = (t_Histo *)pd_new(Histo_class);
+ x->x_size = size;
+ x->x_hist = hist;
+ x->x_lastinput = 0;
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_float);
+ x->x_countout = outlet_new((t_object *)x, &s_float);
+ Histo_clear(x);
+ return (x);
+}
+
+void Histo_setup(void)
+{
+ Histo_class = class_new(gensym("Histo"),
+ (t_newmethod)Histo_new,
+ (t_method)Histo_free,
+ sizeof(t_Histo), 0, A_DEFFLOAT, 0);
+ class_addbang(Histo_class, Histo_bang);
+ class_addfloat(Histo_class, Histo_float);
+ class_addmethod(Histo_class, (t_method)Histo_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(Histo_class, (t_method)Histo_clear,
+ gensym("clear"), 0);
+}
diff --git a/cyclone/hammer/Makefile b/cyclone/hammer/Makefile
new file mode 100644
index 0000000..54383c3
--- /dev/null
+++ b/cyclone/hammer/Makefile
@@ -0,0 +1,3 @@
+ROOT_DIR = ../..
+redefault: allhammers.c default
+include $(ROOT_DIR)/Makefile.common
diff --git a/cyclone/hammer/Makefile.objects b/cyclone/hammer/Makefile.objects
new file mode 100644
index 0000000..0ac0a87
--- /dev/null
+++ b/cyclone/hammer/Makefile.objects
@@ -0,0 +1,14 @@
+SHARED_OBJECTS = \
+unstable/fragile.o \
+common/loud.o \
+common/grow.o \
+common/rand.o \
+common/vefl.o \
+common/sq.o \
+common/bifi.o \
+common/mifi.o \
+common/binport.o \
+common/port.o \
+hammer/file.o \
+hammer/gui.o \
+hammer/tree.o
diff --git a/cyclone/hammer/Makefile.sources b/cyclone/hammer/Makefile.sources
new file mode 100644
index 0000000..5df97f5
--- /dev/null
+++ b/cyclone/hammer/Makefile.sources
@@ -0,0 +1,80 @@
+CX_SOURCES = \
+hammer.c
+
+OTHER_SOURCES = \
+allhammers.c \
+testmess.c \
+accum.c \
+acos.c \
+active.c \
+anal.c \
+Append.c \
+asin.c \
+bangbang.c \
+bondo.c \
+Borax.c \
+Bucket.c \
+buddy.c \
+capture.c \
+cartopol.c \
+Clip.c \
+coll.c \
+comment.c \
+cosh.c \
+counter.c \
+cycle.c \
+decide.c \
+Decode.c \
+drunk.c \
+flush.c \
+forward.c \
+fromsymbol.c \
+funbuff.c \
+funnel.c \
+gate.c \
+grab.c \
+Histo.c \
+iter.c \
+match.c \
+maximum.c \
+mean.c \
+midiflush.c \
+midiformat.c \
+midiparse.c \
+minimum.c \
+mousefilter.c \
+MouseState.c \
+next.c \
+offer.c \
+onebang.c \
+past.c \
+Peak.c \
+poltocar.c \
+prepend.c \
+prob.c \
+pv.c \
+seq.c \
+sinh.c \
+speedlim.c \
+spell.c \
+split.c \
+spray.c \
+sprintf.c \
+substitute.c \
+sustain.c \
+switch.c \
+tanh.c \
+thresh.c \
+TogEdge.c \
+tosymbol.c \
+Trough.c \
+universal.c \
+urn.c \
+Uzi.c \
+xbendin.c \
+xbendin2.c \
+xbendout.c \
+xbendout2.c \
+xnotein.c \
+xnoteout.c \
+zl.c
diff --git a/cyclone/hammer/MouseState.c b/cyclone/hammer/MouseState.c
new file mode 100644
index 0000000..3b831bf
--- /dev/null
+++ b/cyclone/hammer/MouseState.c
@@ -0,0 +1,153 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "hammer/gui.h"
+
+typedef struct _MouseState
+{
+ t_object x_ob;
+ int x_ispolling;
+ int x_wasbanged;
+ int x_waszeroed;
+ int x_hlast;
+ int x_vlast;
+ int x_hzero;
+ int x_vzero;
+ t_outlet *x_hposout;
+ t_outlet *x_vposout;
+ t_outlet *x_hdiffout;
+ t_outlet *x_vdiffout;
+} t_MouseState;
+
+static t_class *MouseState_class;
+
+static void MouseState_anything(t_MouseState *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ /* dummy method, filtering out those messages from gui,
+ which are not handled explicitly */
+}
+
+static void MouseState_doup(t_MouseState *x, t_floatarg f)
+{
+ outlet_float(((t_object *)x)->ob_outlet, ((int)f ? 0 : 1));
+}
+
+static void MouseState_dobang(t_MouseState *x, t_floatarg f1, t_floatarg f2)
+{
+ if (x->x_wasbanged)
+ {
+ int h = (int)f1, v = (int)f2;
+ outlet_float(x->x_vdiffout, v - x->x_vlast);
+ outlet_float(x->x_hdiffout, h - x->x_hlast);
+ outlet_float(x->x_vposout, v - x->x_vzero);
+ outlet_float(x->x_hposout, h - x->x_hzero);
+ x->x_hlast = h;
+ x->x_vlast = v;
+ x->x_wasbanged = 0;
+ }
+}
+
+static void MouseState_dozero(t_MouseState *x, t_floatarg f1, t_floatarg f2)
+{
+ if (x->x_waszeroed)
+ {
+ int h = (int)f1, v = (int)f2;
+ x->x_hzero = h;
+ x->x_vzero = v;
+ x->x_waszeroed = 0;
+ }
+}
+
+static void MouseState_dopoll(t_MouseState *x, t_floatarg f1, t_floatarg f2)
+{
+ if (x->x_ispolling)
+ {
+ x->x_wasbanged = 1;
+ MouseState_dobang(x, f1, f2);
+ }
+}
+
+static void MouseState_bang(t_MouseState *x)
+{
+ hammergui_mousexy(gensym("_bang"));
+ x->x_wasbanged = 1;
+}
+
+static void MouseState_poll(t_MouseState *x)
+{
+ if (!x->x_ispolling)
+ {
+ x->x_ispolling = 1;
+ hammergui_startpolling((t_pd *)x);
+ }
+}
+
+static void MouseState_nopoll(t_MouseState *x)
+{
+ if (x->x_ispolling)
+ {
+ x->x_ispolling = 0;
+ hammergui_stoppolling((t_pd *)x);
+ }
+}
+
+static void MouseState_zero(t_MouseState *x)
+{
+ hammergui_mousexy(gensym("_zero"));
+ x->x_waszeroed = 1;
+}
+
+static void MouseState_reset(t_MouseState *x)
+{
+ x->x_hzero = x->x_vzero = 0;
+}
+
+static void MouseState_free(t_MouseState *x)
+{
+ MouseState_nopoll(x);
+ hammergui_unbindmouse((t_pd *)x);
+}
+
+static void *MouseState_new(void)
+{
+ t_MouseState *x = (t_MouseState *)pd_new(MouseState_class);
+ x->x_ispolling = x->x_wasbanged = x->x_waszeroed = 0;
+ outlet_new((t_object *)x, &s_float);
+ x->x_hposout = outlet_new((t_object *)x, &s_float);
+ x->x_vposout = outlet_new((t_object *)x, &s_float);
+ x->x_hdiffout = outlet_new((t_object *)x, &s_float);
+ x->x_vdiffout = outlet_new((t_object *)x, &s_float);
+ hammergui_bindmouse((t_pd *)x);
+ hammergui_willpoll();
+ MouseState_reset(x);
+ return (x);
+}
+
+void MouseState_setup(void)
+{
+ MouseState_class = class_new(gensym("MouseState"),
+ (t_newmethod)MouseState_new,
+ (t_method)MouseState_free,
+ sizeof(t_MouseState), 0, 0);
+ class_addanything(MouseState_class, MouseState_anything);
+ class_addmethod(MouseState_class, (t_method)MouseState_doup,
+ gensym("_up"), A_FLOAT, 0);
+ class_addmethod(MouseState_class, (t_method)MouseState_dobang,
+ gensym("_bang"), A_FLOAT, A_FLOAT, 0);
+ class_addmethod(MouseState_class, (t_method)MouseState_dozero,
+ gensym("_zero"), A_FLOAT, A_FLOAT, 0);
+ class_addmethod(MouseState_class, (t_method)MouseState_dopoll,
+ gensym("_poll"), A_FLOAT, A_FLOAT, 0);
+ class_addbang(MouseState_class, MouseState_bang);
+ class_addmethod(MouseState_class, (t_method)MouseState_poll,
+ gensym("poll"), 0);
+ class_addmethod(MouseState_class, (t_method)MouseState_nopoll,
+ gensym("nopoll"), 0);
+ class_addmethod(MouseState_class, (t_method)MouseState_zero,
+ gensym("zero"), 0);
+ class_addmethod(MouseState_class, (t_method)MouseState_reset,
+ gensym("reset"), 0);
+}
diff --git a/cyclone/hammer/Peak.c b/cyclone/hammer/Peak.c
new file mode 100644
index 0000000..6f7e30c
--- /dev/null
+++ b/cyclone/hammer/Peak.c
@@ -0,0 +1,63 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+
+#define PEAK_INITIAL 0
+
+typedef struct _Peak
+{
+ t_object x_ob;
+ t_float x_value;
+ t_outlet *x_out2;
+ t_outlet *x_out3;
+} t_Peak;
+
+static t_class *Peak_class;
+
+static void Peak_bang(t_Peak *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+}
+
+static void Peak_ft1(t_Peak *x, t_floatarg f)
+{
+ /* CHECKME loud_checkint */
+ outlet_float(x->x_out3, 0); /* CHECKME */
+ outlet_float(x->x_out2, 1);
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value = f);
+}
+
+static void Peak_float(t_Peak *x, t_float f)
+{
+ /* CHECKME loud_checkint */
+ if (f > x->x_value) Peak_ft1(x, f);
+ else
+ {
+ outlet_float(x->x_out3, 1);
+ outlet_float(x->x_out2, 0);
+ }
+}
+
+static void *Peak_new(t_floatarg f)
+{
+ t_Peak *x = (t_Peak *)pd_new(Peak_class);
+ x->x_value = PEAK_INITIAL;
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_float);
+ x->x_out2 = outlet_new((t_object *)x, &s_float);
+ x->x_out3 = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void Peak_setup(void)
+{
+ Peak_class = class_new(gensym("Peak"),
+ (t_newmethod)Peak_new, 0,
+ sizeof(t_Peak), 0, 0);
+ class_addbang(Peak_class, Peak_bang);
+ class_addfloat(Peak_class, Peak_float);
+ class_addmethod(Peak_class, (t_method)Peak_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
diff --git a/cyclone/hammer/TogEdge.c b/cyclone/hammer/TogEdge.c
new file mode 100644
index 0000000..79c26ec
--- /dev/null
+++ b/cyclone/hammer/TogEdge.c
@@ -0,0 +1,71 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+
+typedef struct _TogEdge
+{
+ t_object x_ob;
+ int x_wason;
+ t_outlet *x_out1;
+} t_TogEdge;
+
+static t_class *TogEdge_class;
+
+static void TogEdge_bang(t_TogEdge *x)
+{
+ if (x->x_wason)
+ {
+ x->x_wason = 0;
+ outlet_bang(x->x_out1);
+ }
+ else
+ {
+ x->x_wason = 1;
+ outlet_bang(((t_object *)x)->ob_outlet);
+ }
+}
+
+static void TogEdge_float(t_TogEdge *x, t_float f)
+{
+ int i;
+ if (loud_checkint((t_pd *)x, f, &i, &s_float)) /* CHECKED */
+ {
+ if (x->x_wason)
+ {
+ if (!i)
+ {
+ x->x_wason = 0;
+ outlet_bang(x->x_out1);
+ }
+ }
+ else
+ {
+ if (i)
+ {
+ x->x_wason = 1;
+ outlet_bang(((t_object *)x)->ob_outlet);
+ }
+ }
+ }
+}
+
+static void *TogEdge_new(void)
+{
+ t_TogEdge *x = (t_TogEdge *)pd_new(TogEdge_class);
+ x->x_wason = 0; /* CHECKED */
+ outlet_new((t_object *)x, &s_bang);
+ x->x_out1 = outlet_new((t_object *)x, &s_bang);
+ return (x);
+}
+
+void TogEdge_setup(void)
+{
+ TogEdge_class = class_new(gensym("TogEdge"),
+ (t_newmethod)TogEdge_new, 0,
+ sizeof(t_TogEdge), 0, 0);
+ class_addbang(TogEdge_class, TogEdge_bang);
+ class_addfloat(TogEdge_class, TogEdge_float);
+}
diff --git a/cyclone/hammer/Trough.c b/cyclone/hammer/Trough.c
new file mode 100644
index 0000000..27b19ba
--- /dev/null
+++ b/cyclone/hammer/Trough.c
@@ -0,0 +1,63 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+
+#define TROUGH_INITIAL 128 /* CHECKME */
+
+typedef struct _Trough
+{
+ t_object x_ob;
+ t_float x_value;
+ t_outlet *x_out2;
+ t_outlet *x_out3;
+} t_Trough;
+
+static t_class *Trough_class;
+
+static void Trough_bang(t_Trough *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+}
+
+static void Trough_ft1(t_Trough *x, t_floatarg f)
+{
+ /* CHECKME loud_checkint */
+ outlet_float(x->x_out3, 0); /* CHECKME */
+ outlet_float(x->x_out2, 1);
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value = f);
+}
+
+static void Trough_float(t_Trough *x, t_float f)
+{
+ /* CHECKME loud_checkint */
+ if (f < x->x_value) Trough_ft1(x, f);
+ else
+ {
+ outlet_float(x->x_out3, 1);
+ outlet_float(x->x_out2, 0);
+ }
+}
+
+static void *Trough_new(t_floatarg f)
+{
+ t_Trough *x = (t_Trough *)pd_new(Trough_class);
+ x->x_value = TROUGH_INITIAL;
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_float);
+ x->x_out2 = outlet_new((t_object *)x, &s_float);
+ x->x_out3 = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void Trough_setup(void)
+{
+ Trough_class = class_new(gensym("Trough"),
+ (t_newmethod)Trough_new, 0,
+ sizeof(t_Trough), 0, 0);
+ class_addbang(Trough_class, Trough_bang);
+ class_addfloat(Trough_class, Trough_float);
+ class_addmethod(Trough_class, (t_method)Trough_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
diff --git a/cyclone/hammer/Uzi.c b/cyclone/hammer/Uzi.c
new file mode 100644
index 0000000..c773c6b
--- /dev/null
+++ b/cyclone/hammer/Uzi.c
@@ -0,0 +1,108 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* CHECKME negative 'nbangs' value set during run-time */
+
+#include "m_pd.h"
+
+typedef struct _Uzi
+{
+ t_object x_obj;
+ t_float x_nbangs;
+ int x_count;
+ int x_running;
+ t_outlet *x_out2;
+ t_outlet *x_out3;
+} t_Uzi;
+
+static t_class *Uzi_class;
+
+#define UZI_RUNNING 1
+#define UZI_PAUSED 2
+
+static void Uzi_dobang(t_Uzi *x)
+{
+ /* CHECKME reentrancy */
+ if (!x->x_running)
+ {
+ int count, nbangs = (int)x->x_nbangs;
+ x->x_running = UZI_RUNNING;
+ for (count = x->x_count + 1; count <= nbangs; count++)
+ {
+ outlet_float(x->x_out3, count);
+ outlet_bang(((t_object *)x)->ob_outlet);
+ if (x->x_running == UZI_PAUSED)
+ {
+ /* CHECKED: carry bang not sent, even if this is last bang */
+ x->x_count = count;
+ return;
+ }
+ }
+ /* CHECKED: carry bang sent also when there are no left-outlet bangs */
+ /* CHECKED: sent after left outlet, not before */
+ outlet_bang(x->x_out2);
+ x->x_count = 0;
+ x->x_running = 0;
+ }
+}
+
+static void Uzi_bang(t_Uzi *x)
+{
+ /* CHECKED: always restarts (when paused too) */
+ x->x_count = 0;
+ x->x_running = 0;
+ Uzi_dobang(x);
+}
+
+static void Uzi_float(t_Uzi *x, t_float f)
+{
+ /* CHECKED: always sets a new value and restarts (when paused too) */
+ x->x_nbangs = f;
+ Uzi_bang(x);
+}
+
+/* CHECKED: 'pause, resume' (but not just 'resume')
+ sends a carry bang when not running (a bug?) */
+static void Uzi_pause(t_Uzi *x)
+{
+ if (!x->x_running)
+ x->x_count = (int)x->x_nbangs; /* bug emulation? */
+ x->x_running = UZI_PAUSED;
+}
+
+static void Uzi_resume(t_Uzi *x)
+{
+ if (x->x_running == UZI_PAUSED)
+ {
+ x->x_running = 0;
+ Uzi_dobang(x);
+ }
+}
+
+static void *Uzi_new(t_floatarg f)
+{
+ t_Uzi *x = (t_Uzi *)pd_new(Uzi_class);
+ x->x_nbangs = (f > 1. ? f : 1.);
+ x->x_count = 0;
+ x->x_running = 0;
+ /* CHECKED: set when paused, but then 'resume' is blocked (a bug?) */
+ floatinlet_new((t_object *)x, &x->x_nbangs);
+ outlet_new((t_object *)x, &s_bang);
+ x->x_out2 = outlet_new((t_object *)x, &s_bang);
+ x->x_out3 = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void Uzi_setup(void)
+{
+ Uzi_class = class_new(gensym("Uzi"),
+ (t_newmethod)Uzi_new, 0,
+ sizeof(t_Uzi), 0, A_DEFFLOAT, 0);
+ class_addbang(Uzi_class, Uzi_bang);
+ class_addfloat(Uzi_class, Uzi_float);
+ class_addmethod(Uzi_class, (t_method)Uzi_pause, gensym("pause"), 0);
+ class_addmethod(Uzi_class, (t_method)Uzi_pause, gensym("break"), 0);
+ class_addmethod(Uzi_class, (t_method)Uzi_resume, gensym("resume"), 0);
+ class_addmethod(Uzi_class, (t_method)Uzi_resume, gensym("continue"), 0);
+}
diff --git a/cyclone/hammer/accum.c b/cyclone/hammer/accum.c
new file mode 100644
index 0000000..d266fb3
--- /dev/null
+++ b/cyclone/hammer/accum.c
@@ -0,0 +1,68 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* This is a slightly edited version of Joseph A. Sarlo's code.
+ The most important changes are listed in "pd-lib-notes.txt" file. */
+
+#include "m_pd.h"
+
+typedef struct _accum
+{
+ t_object x_ob;
+ t_float x_total;
+} t_accum;
+
+static t_class *accum_class;
+
+static void accum_set(t_accum *x, t_floatarg val)
+{
+ x->x_total = val;
+}
+
+static void accum_bang(t_accum *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_total);
+}
+
+static void accum_float(t_accum *x, t_floatarg val)
+{
+ /* LATER reconsider int/float dilemma */
+ accum_set(x, val);
+ accum_bang(x);
+}
+
+static void accum_add(t_accum *x, t_floatarg val)
+{
+ /* LATER reconsider int/float dilemma */
+ x->x_total += val;
+}
+
+static void accum_mult(t_accum *x, t_floatarg val)
+{
+ x->x_total *= val;
+}
+
+static void *accum_new(t_floatarg val)
+{
+ t_accum *x = (t_accum *)pd_new(accum_class);
+ x->x_total = val;
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft2"));
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void accum_setup(void)
+{
+ accum_class = class_new(gensym("accum"), (t_newmethod)accum_new, 0,
+ sizeof(t_accum), 0, A_DEFFLOAT, 0);
+ class_addbang(accum_class, accum_bang);
+ class_addfloat(accum_class, accum_float);
+ class_addmethod(accum_class, (t_method)accum_add,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(accum_class, (t_method)accum_mult,
+ gensym("ft2"), A_FLOAT, 0);
+ class_addmethod(accum_class, (t_method)accum_set,
+ gensym("set"), A_FLOAT, 0);
+}
diff --git a/cyclone/hammer/acos.c b/cyclone/hammer/acos.c
new file mode 100644
index 0000000..3f3abea
--- /dev/null
+++ b/cyclone/hammer/acos.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define acosf acos
+#endif
+
+typedef struct _acos
+{
+ t_object x_ob;
+ float x_value;
+} t_acos;
+
+static t_class *acos_class;
+
+static void acos_bang(t_acos *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+}
+
+static void acos_float(t_acos *x, t_float f)
+{
+ if (f < -1.0) f = -1.0; else if (f > 1.0) f = 1.0; /* CHECKME */
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value = acosf(f));
+}
+
+static void *acos_new(t_floatarg f)
+{
+ t_acos *x = (t_acos *)pd_new(acos_class);
+ if (f < -1.0) f = -1.0; else if (f > 1.0) f = 1.0; /* CHECKME */
+ x->x_value = acosf(f);
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void acos_setup(void)
+{
+ acos_class = class_new(gensym("acos"),
+ (t_newmethod)acos_new, 0,
+ sizeof(t_acos), 0, A_DEFFLOAT, 0);
+ class_addbang(acos_class, acos_bang);
+ class_addfloat(acos_class, acos_float);
+}
diff --git a/cyclone/hammer/active.c b/cyclone/hammer/active.c
new file mode 100644
index 0000000..9d10f80
--- /dev/null
+++ b/cyclone/hammer/active.c
@@ -0,0 +1,55 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <stdio.h>
+#include "m_pd.h"
+#include "hammer/gui.h"
+
+typedef struct _active
+{
+ t_object x_ob;
+ t_symbol *x_cvname;
+ int x_on;
+} t_active;
+
+static t_class *active_class;
+
+static void active_dofocus(t_active *x, t_symbol *s, t_floatarg f)
+{
+ if ((int)f)
+ {
+ int on = (s == x->x_cvname);
+ if (on != x->x_on)
+ outlet_float(((t_object *)x)->ob_outlet, x->x_on = on);
+ }
+ else if (x->x_on && s == x->x_cvname)
+ outlet_float(((t_object *)x)->ob_outlet, x->x_on = 0);
+}
+
+static void active_free(t_active *x)
+{
+ hammergui_unbindfocus((t_pd *)x);
+}
+
+static void *active_new(void)
+{
+ t_active *x = (t_active *)pd_new(active_class);
+ char buf[32];
+ sprintf(buf, ".x%x.c", (int)canvas_getcurrent());
+ x->x_cvname = gensym(buf);
+ x->x_on = 0;
+ outlet_new((t_object *)x, &s_float);
+ hammergui_bindfocus((t_pd *)x);
+ return (x);
+}
+
+void active_setup(void)
+{
+ active_class = class_new(gensym("active"),
+ (t_newmethod)active_new,
+ (t_method)active_free,
+ sizeof(t_active), CLASS_NOINLET, 0);
+ class_addmethod(active_class, (t_method)active_dofocus,
+ gensym("_focus"), A_SYMBOL, A_FLOAT, 0);
+}
diff --git a/cyclone/hammer/allhammers.c b/cyclone/hammer/allhammers.c
new file mode 100644
index 0000000..e6d8235
--- /dev/null
+++ b/cyclone/hammer/allhammers.c
@@ -0,0 +1,160 @@
+// Do not edit this file, run "make" instead.
+
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+void accum_setup(void);
+void acos_setup(void);
+void active_setup(void);
+void anal_setup(void);
+void Append_setup(void);
+void asin_setup(void);
+void bangbang_setup(void);
+void bondo_setup(void);
+void Borax_setup(void);
+void Bucket_setup(void);
+void buddy_setup(void);
+void capture_setup(void);
+void cartopol_setup(void);
+void Clip_setup(void);
+void coll_setup(void);
+void comment_setup(void);
+void cosh_setup(void);
+void counter_setup(void);
+void cycle_setup(void);
+void decide_setup(void);
+void Decode_setup(void);
+void drunk_setup(void);
+void flush_setup(void);
+void forward_setup(void);
+void fromsymbol_setup(void);
+void funbuff_setup(void);
+void funnel_setup(void);
+void gate_setup(void);
+void grab_setup(void);
+void Histo_setup(void);
+void iter_setup(void);
+void match_setup(void);
+void maximum_setup(void);
+void mean_setup(void);
+void midiflush_setup(void);
+void midiformat_setup(void);
+void midiparse_setup(void);
+void minimum_setup(void);
+void mousefilter_setup(void);
+void MouseState_setup(void);
+void next_setup(void);
+void offer_setup(void);
+void onebang_setup(void);
+void past_setup(void);
+void Peak_setup(void);
+void poltocar_setup(void);
+void prepend_setup(void);
+void prob_setup(void);
+void pv_setup(void);
+void seq_setup(void);
+void sinh_setup(void);
+void speedlim_setup(void);
+void spell_setup(void);
+void split_setup(void);
+void spray_setup(void);
+void sprintf_setup(void);
+void substitute_setup(void);
+void sustain_setup(void);
+void switch_setup(void);
+void tanh_setup(void);
+void testmess_setup(void);
+void thresh_setup(void);
+void TogEdge_setup(void);
+void tosymbol_setup(void);
+void Trough_setup(void);
+void universal_setup(void);
+void urn_setup(void);
+void Uzi_setup(void);
+void xbendin2_setup(void);
+void xbendin_setup(void);
+void xbendout2_setup(void);
+void xbendout_setup(void);
+void xnotein_setup(void);
+void xnoteout_setup(void);
+void zl_setup(void);
+
+void allhammers_setup(void)
+{
+ accum_setup();
+ acos_setup();
+ active_setup();
+ anal_setup();
+ Append_setup();
+ asin_setup();
+ bangbang_setup();
+ bondo_setup();
+ Borax_setup();
+ Bucket_setup();
+ buddy_setup();
+ capture_setup();
+ cartopol_setup();
+ Clip_setup();
+ coll_setup();
+ comment_setup();
+ cosh_setup();
+ counter_setup();
+ cycle_setup();
+ decide_setup();
+ Decode_setup();
+ drunk_setup();
+ flush_setup();
+ forward_setup();
+ fromsymbol_setup();
+ funbuff_setup();
+ funnel_setup();
+ gate_setup();
+ grab_setup();
+ Histo_setup();
+ iter_setup();
+ match_setup();
+ maximum_setup();
+ mean_setup();
+ midiflush_setup();
+ midiformat_setup();
+ midiparse_setup();
+ minimum_setup();
+ mousefilter_setup();
+ MouseState_setup();
+ next_setup();
+ offer_setup();
+ onebang_setup();
+ past_setup();
+ Peak_setup();
+ poltocar_setup();
+ prepend_setup();
+ prob_setup();
+ pv_setup();
+ seq_setup();
+ sinh_setup();
+ speedlim_setup();
+ spell_setup();
+ split_setup();
+ spray_setup();
+ sprintf_setup();
+ substitute_setup();
+ sustain_setup();
+ switch_setup();
+ tanh_setup();
+ testmess_setup();
+ thresh_setup();
+ TogEdge_setup();
+ tosymbol_setup();
+ Trough_setup();
+ universal_setup();
+ urn_setup();
+ Uzi_setup();
+ xbendin2_setup();
+ xbendin_setup();
+ xbendout2_setup();
+ xbendout_setup();
+ xnotein_setup();
+ xnoteout_setup();
+ zl_setup();
+}
diff --git a/cyclone/hammer/anal.c b/cyclone/hammer/anal.c
new file mode 100644
index 0000000..477eb20
--- /dev/null
+++ b/cyclone/hammer/anal.c
@@ -0,0 +1,108 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/loud.h"
+
+#define ANAL_DEFSIZE 128
+#define ANAL_MAXSIZE 1024
+
+typedef struct _anal
+{
+ t_object x_ob;
+ int x_value; /* negative, if initialized or reset */
+ int x_size;
+ int x_bytesize;
+ int *x_table;
+ /* CHECKED: the 'weight' count is a signed short (2 bytes),
+ wrapping into negative domain without any warning.
+ LATER consider complaining at == SHRT_MAX. */
+} t_anal;
+
+static t_class *anal_class;
+
+static void anal_reset(t_anal *x)
+{
+ x->x_value = -1;
+}
+
+static void anal_clear(t_anal *x)
+{
+ memset(x->x_table, 0, x->x_bytesize);
+}
+
+static void anal_float(t_anal *x, t_float f)
+{
+ int value;
+ if (loud_checkint((t_pd *)x, f, &value, &s_float)) /* CHECKED */
+ {
+ /* CHECKED: any input negative or >= size is ignored with an error
+ -- there is no output, and a previous state is kept. */
+ if (value >= 0 && value < x->x_size)
+ {
+ if (x->x_value >= 0)
+ {
+ t_atom at[3];
+ int ndx = x->x_value * x->x_size + value;
+ x->x_table[ndx]++;
+ SETFLOAT(at, x->x_value);
+ SETFLOAT(&at[1], value);
+ SETFLOAT(&at[2], x->x_table[ndx]);
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, 3, at);
+ }
+ x->x_value = value;
+ }
+ else loud_error((t_pd *)x, "%d outside of table bounds", value);
+ }
+}
+
+static void anal_free(t_anal *x)
+{
+ if (x->x_table)
+ freebytes(x->x_table, x->x_bytesize);
+}
+
+static void *anal_new(t_floatarg f)
+{
+ t_anal *x;
+ int size = (int)f;
+ int bytesize;
+ int *table;
+ if (size < 1)
+ /* CHECKED: 1 is allowed (such an object rejects any nonzero input) */
+ size = ANAL_DEFSIZE;
+ else if (size > ANAL_MAXSIZE)
+ {
+ /* CHECKED: */
+ loud_warning(&anal_class, "size too large, using %d", ANAL_MAXSIZE);
+ size = ANAL_MAXSIZE; /* LATER switch into a 'sparse' mode */
+ }
+ /* CHECKED: actually the bytesize is size * size * sizeof(short),
+ and it shows up in */
+ bytesize = size * size * sizeof(*table);
+ if (!(table = (int *)getbytes(bytesize)))
+ return (0);
+ x = (t_anal *)pd_new(anal_class);
+ x->x_size = size;
+ x->x_bytesize = bytesize;
+ x->x_table = table;
+ outlet_new((t_object *)x, &s_list);
+ anal_reset(x);
+ anal_clear(x);
+ return (x);
+}
+
+void anal_setup(void)
+{
+ anal_class = class_new(gensym("anal"),
+ (t_newmethod)anal_new,
+ (t_method)anal_free,
+ sizeof(t_anal), 0, A_DEFFLOAT, 0);
+ class_addfloat(anal_class, anal_float);
+ class_addmethod(anal_class, (t_method)anal_reset,
+ gensym("reset"), 0);
+ class_addmethod(anal_class, (t_method)anal_clear,
+ gensym("clear"), 0);
+}
diff --git a/cyclone/hammer/asin.c b/cyclone/hammer/asin.c
new file mode 100644
index 0000000..0aa8db7
--- /dev/null
+++ b/cyclone/hammer/asin.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define asinf asin
+#endif
+
+typedef struct _asin
+{
+ t_object x_ob;
+ float x_value;
+} t_asin;
+
+static t_class *asin_class;
+
+static void asin_bang(t_asin *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+}
+
+static void asin_float(t_asin *x, t_float f)
+{
+ if (f < -1.0) f = -1.0; else if (f > 1.0) f = 1.0; /* CHECKME */
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value = asinf(f));
+}
+
+static void *asin_new(t_floatarg f)
+{
+ t_asin *x = (t_asin *)pd_new(asin_class);
+ if (f < -1.0) f = -1.0; else if (f > 1.0) f = 1.0; /* CHECKME */
+ x->x_value = asinf(f);
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void asin_setup(void)
+{
+ asin_class = class_new(gensym("asin"),
+ (t_newmethod)asin_new, 0,
+ sizeof(t_asin), 0, A_DEFFLOAT, 0);
+ class_addbang(asin_class, asin_bang);
+ class_addfloat(asin_class, asin_float);
+}
diff --git a/cyclone/hammer/bangbang.c b/cyclone/hammer/bangbang.c
new file mode 100644
index 0000000..bebd26e
--- /dev/null
+++ b/cyclone/hammer/bangbang.c
@@ -0,0 +1,73 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* This is a modified version of Joseph A. Sarlo's code.
+ The most important changes are listed in "pd-lib-notes.txt" file. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+
+#define BANGBANG_MINOUTS 1
+#define BANGBANG_MAXOUTS 40 /* CHECKED (just clipped without warning) */
+#define BANGBANG_DEFOUTS 2
+
+typedef struct _bangbang
+{
+ t_object x_ob;
+ int x_nouts;
+ t_outlet **x_outs;
+ t_outlet *x_outbuf[BANGBANG_DEFOUTS];
+} t_bangbang;
+
+static t_class *bangbang_class;
+
+static void bangbang_bang(t_bangbang *x)
+{
+ int i = x->x_nouts;
+ while (i--) outlet_bang(x->x_outs[i]);
+}
+
+static void bangbang_anything(t_bangbang *x, t_symbol *s, int ac, t_atom *av)
+{
+ bangbang_bang(x);
+}
+
+static void bangbang_free(t_bangbang *x)
+{
+ if (x->x_outs != x->x_outbuf)
+ freebytes(x->x_outs, x->x_nouts * sizeof(*x->x_outs));
+}
+
+static void *bangbang_new(t_floatarg val)
+{
+ t_bangbang *x;
+ int i, nouts = (int)val;
+ t_outlet **outs;
+ if (nouts < BANGBANG_MINOUTS)
+ nouts = BANGBANG_DEFOUTS;
+ if (nouts > BANGBANG_MAXOUTS)
+ loud_incompatible_max(bangbang_class, BANGBANG_MAXOUTS, "outlets");
+ if (nouts > BANGBANG_DEFOUTS)
+ {
+ if (!(outs = (t_outlet **)getbytes(nouts * sizeof(*outs))))
+ return (0);
+ }
+ else outs = 0;
+ x = (t_bangbang *)pd_new(bangbang_class);
+ x->x_nouts = nouts;
+ x->x_outs = (outs ? outs : x->x_outbuf);
+ for (i = 0; i < nouts; i++)
+ x->x_outs[i] = outlet_new((t_object *)x, &s_bang);
+ return (x);
+}
+
+void bangbang_setup(void)
+{
+ bangbang_class = class_new(gensym("bangbang"),
+ (t_newmethod)bangbang_new,
+ (t_method)bangbang_free,
+ sizeof(t_bangbang), 0, A_DEFFLOAT, 0);
+ class_addbang(bangbang_class, bangbang_bang);
+ class_addanything(bangbang_class, bangbang_anything);
+}
diff --git a/cyclone/hammer/bondo.c b/cyclone/hammer/bondo.c
new file mode 100644
index 0000000..2fcdce3
--- /dev/null
+++ b/cyclone/hammer/bondo.c
@@ -0,0 +1,394 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* LATER revisit buffer handling (maxsize, reentrancy) */
+/* LATER rethink handling of symbols */
+
+/* CHECKED: if 'n' argument is given, then store whole messages, instead of
+ distributing atoms across successive slots. This is a new, buddy-like
+ behaviour. */
+/* CHECKED: without 'n' argument, 'symbol test' is parsed as two symbol atoms,
+ but 'float 1' (or 'list 1') as a single float. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+#define BONDO_MINSLOTS 2
+#define BONDO_INISIZE 4 /* LATER rethink (useful only in multiatom mode) */
+
+typedef struct _bondo
+{
+ t_object x_ob;
+ t_float x_delay;
+ int x_multiatom;
+ int x_nslots;
+ int x_nproxies; /* as requested (and allocated) */
+ t_pd **x_proxies;
+ t_outlet **x_outs;
+ t_clock *x_clock;
+} t_bondo;
+
+typedef struct _bondo_proxy
+{
+ t_object p_ob;
+ t_bondo *p_master;
+ int p_id;
+ t_symbol *p_selector;
+ t_float p_float;
+ t_symbol *p_symbol;
+ t_gpointer *p_pointer;
+ int p_size; /* as allocated */
+ int p_natoms; /* as used */
+ t_atom *p_message;
+ t_atom p_messini[BONDO_INISIZE];
+} t_bondo_proxy;
+
+static t_class *bondo_class;
+static t_class *bondo_proxy_class;
+
+static void bondo_doit(t_bondo *x)
+{
+ t_bondo_proxy **p = (t_bondo_proxy **)x->x_proxies;
+ int i = x->x_nslots;
+ p = (t_bondo_proxy **)x->x_proxies;
+ i = x->x_nslots;
+ while (i--)
+ {
+ t_symbol *s = p[i]->p_selector;
+ /* LATER consider complaining about extra arguments (CHECKED) */
+ if (s == &s_bang)
+ outlet_bang(x->x_outs[i]);
+ else if (s == &s_float)
+ outlet_float(x->x_outs[i], p[i]->p_float);
+ else if (s == &s_symbol && p[i]->p_symbol)
+ {
+ /* LATER rethink */
+ if (x->x_multiatom)
+ outlet_symbol(x->x_outs[i], p[i]->p_symbol);
+ else
+ outlet_anything(x->x_outs[i], p[i]->p_symbol, 0, 0);
+ }
+ else if (s == &s_pointer)
+ {
+ /* LATER */
+ }
+ else if (s == &s_list)
+ outlet_list(x->x_outs[i], s, p[i]->p_natoms, p[i]->p_message);
+ else if (s) /* CHECKED: a slot may be inactive (in multiatom mode) */
+ outlet_anything(x->x_outs[i], s, p[i]->p_natoms, p[i]->p_message);
+ }
+}
+
+static void bondo_arm(t_bondo *x)
+{
+ if (x->x_delay <= 0) bondo_doit(x);
+ else clock_delay(x->x_clock, x->x_delay);
+}
+
+static void bondo_proxy_bang(t_bondo_proxy *x)
+{
+ bondo_arm(x->p_master); /* CHECKED: bang in any inlet works in this way */
+}
+
+static void bondo_proxy_dofloat(t_bondo_proxy *x, t_float f, int doit)
+{
+ x->p_selector = &s_float;
+ x->p_float = f;
+ x->p_natoms = 0; /* defensive */
+ if (doit) bondo_arm(x->p_master);
+}
+
+static void bondo_proxy_float(t_bondo_proxy *x, t_float f)
+{
+ bondo_proxy_dofloat(x, f, 1);
+}
+
+static void bondo_proxy_dosymbol(t_bondo_proxy *x, t_symbol *s, int doit)
+{
+ x->p_selector = &s_symbol;
+ x->p_symbol = s;
+ x->p_natoms = 0; /* defensive */
+ if (doit) bondo_arm(x->p_master);
+}
+
+static void bondo_proxy_symbol(t_bondo_proxy *x, t_symbol *s)
+{
+ bondo_proxy_dosymbol(x, s, 1);
+}
+
+static void bondo_proxy_dopointer(t_bondo_proxy *x, t_gpointer *gp, int doit)
+{
+ x->p_selector = &s_pointer;
+ x->p_pointer = gp;
+ x->p_natoms = 0; /* defensive */
+ if (doit) bondo_arm(x->p_master);
+}
+
+static void bondo_proxy_pointer(t_bondo_proxy *x, t_gpointer *gp)
+{
+ bondo_proxy_dopointer(x, gp, 1);
+}
+
+/* CHECKED: the slots fire in right-to-left order,
+ but they trigger only once (refman error) */
+static void bondo_distribute(t_bondo *x, int startid,
+ t_symbol *s, int ac, t_atom *av, int doit)
+{
+ t_atom *ap = av;
+ t_bondo_proxy **pp;
+ int id = startid + ac;
+ if (s) id++;
+ if (id > x->x_nslots)
+ id = x->x_nslots;
+ ap += id - startid;
+ pp = (t_bondo_proxy **)(x->x_proxies + id);
+ if (s) ap--;
+ while (ap-- > av)
+ {
+ pp--;
+ if (ap->a_type == A_FLOAT)
+ bondo_proxy_dofloat(*pp, ap->a_w.w_float, 0);
+ else if (ap->a_type == A_SYMBOL)
+ bondo_proxy_dosymbol(*pp, ap->a_w.w_symbol, 0);
+ else if (ap->a_type == A_POINTER)
+ bondo_proxy_dopointer(*pp, ap->a_w.w_gpointer, 0);
+ }
+ if (s)
+ bondo_proxy_dosymbol((t_bondo_proxy *)x->x_proxies[startid], s, 0);
+ if (doit) bondo_arm(x);
+}
+
+static void bondo_proxy_domultiatom(t_bondo_proxy *x,
+ int ac, t_atom *av, int doit)
+{
+ if (ac > x->p_size)
+ {
+ /* LATER consider using BONDO_MAXSIZE (and warning if exceeded) */
+ x->p_message = grow_nodata(&ac, &x->p_size, x->p_message,
+ BONDO_INISIZE, x->p_messini,
+ sizeof(*x->p_message));
+ }
+ x->p_natoms = ac;
+ memcpy(x->p_message, av, ac * sizeof(*x->p_message));
+ if (doit) bondo_arm(x->p_master);
+}
+
+static void bondo_proxy_dolist(t_bondo_proxy *x, int ac, t_atom *av, int doit)
+{
+ if (x->p_master->x_multiatom)
+ {
+ x->p_selector = &s_list;
+ bondo_proxy_domultiatom(x, ac, av, doit);
+ }
+ else bondo_distribute(x->p_master, x->p_id, 0, ac, av, doit);
+}
+
+static void bondo_proxy_list(t_bondo_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ bondo_proxy_dolist(x, ac, av, 1);
+}
+
+static void bondo_proxy_doanything(t_bondo_proxy *x,
+ t_symbol *s, int ac, t_atom *av, int doit)
+{
+ if (x->p_master->x_multiatom)
+ {
+ /* LATER rethink and CHECKME */
+ if (s == &s_symbol)
+ {
+ if (ac && av->a_type == A_SYMBOL)
+ bondo_proxy_dosymbol(x, av->a_w.w_symbol, doit);
+ else
+ bondo_proxy_dosymbol(x, &s_symbol, doit);
+ }
+ else
+ {
+ x->p_selector = s;
+ bondo_proxy_domultiatom(x, ac, av, doit);
+ }
+ }
+ else bondo_distribute(x->p_master, x->p_id, s, ac, av, doit);
+}
+
+static void bondo_proxy_anything(t_bondo_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ bondo_proxy_doanything(x, s, ac, av, 1);
+}
+
+static void bondo_proxy_set(t_bondo_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ if (av->a_type == A_FLOAT)
+ {
+ if (ac > 1)
+ bondo_proxy_dolist(x, ac, av, 0);
+ else
+ bondo_proxy_dofloat(x, av->a_w.w_float, 0);
+ }
+ else if (av->a_type == A_SYMBOL)
+ /* CHECKED: no tests for 'set float ...' and 'set list...' --
+ the parsing is made in an output routine */
+ bondo_proxy_doanything(x, av->a_w.w_symbol, ac-1, av+1, 0);
+ else if (av->a_type == A_POINTER)
+ bondo_proxy_dopointer(x, av->a_w.w_gpointer, 0);
+ }
+ /* CHECKED: 'set' without arguments makes a slot inactive,
+ if multiatom, but is ignored, if !multiatom */
+ else if (x->p_master->x_multiatom) x->p_selector = 0;
+}
+
+static void bondo_bang(t_bondo *x)
+{
+ bondo_proxy_bang((t_bondo_proxy *)x->x_proxies[0]);
+}
+
+static void bondo_float(t_bondo *x, t_float f)
+{
+ bondo_proxy_dofloat((t_bondo_proxy *)x->x_proxies[0], f, 1);
+}
+
+static void bondo_symbol(t_bondo *x, t_symbol *s)
+{
+ bondo_proxy_dosymbol((t_bondo_proxy *)x->x_proxies[0], s, 1);
+}
+
+static void bondo_pointer(t_bondo *x, t_gpointer *gp)
+{
+ bondo_proxy_dopointer((t_bondo_proxy *)x->x_proxies[0], gp, 1);
+}
+
+static void bondo_list(t_bondo *x, t_symbol *s, int ac, t_atom *av)
+{
+ bondo_proxy_dolist((t_bondo_proxy *)x->x_proxies[0], ac, av, 1);
+}
+
+static void bondo_anything(t_bondo *x, t_symbol *s, int ac, t_atom *av)
+{
+ bondo_proxy_doanything((t_bondo_proxy *)x->x_proxies[0], s, ac, av, 1);
+}
+
+static void bondo_set(t_bondo *x, t_symbol *s, int ac, t_atom *av)
+{
+ bondo_proxy_set((t_bondo_proxy *)x->x_proxies[0], s, ac, av);
+}
+
+static void bondo_free(t_bondo *x)
+{
+ if (x->x_clock) clock_free(x->x_clock);
+ if (x->x_proxies)
+ {
+ int i = x->x_nslots;
+ while (i--)
+ {
+ t_bondo_proxy *y = (t_bondo_proxy *)x->x_proxies[i];
+ if (y->p_message != y->p_messini)
+ freebytes(y->p_message, y->p_size * sizeof(*y->p_message));
+ pd_free((t_pd *)y);
+ }
+ freebytes(x->x_proxies, x->x_nproxies * sizeof(*x->x_proxies));
+ }
+ if (x->x_outs)
+ freebytes(x->x_outs, x->x_nslots * sizeof(*x->x_outs));
+}
+
+static void *bondo_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_bondo *x;
+ int i, nslots, nproxies = BONDO_MINSLOTS;
+ int multiatom = 0;
+ t_float delay = 0;
+ t_pd **proxies;
+ t_outlet **outs;
+ i = 0;
+ while (ac--)
+ {
+ /* CHECKED: no warnings */
+ if (av->a_type == A_FLOAT)
+ {
+ if (i == 0)
+ nproxies = (int)av->a_w.w_float;
+ else if (i == 1)
+ delay = av->a_w.w_float;
+ i++;
+ }
+ else if (av->a_type == A_SYMBOL)
+ {
+ if (av->a_w.w_symbol == gensym("n")) multiatom = 1;
+ /* CHECKED: 'n' has to be the last argument given;
+ the arguments after any symbol are silently ignored --
+ LATER decide if we should comply and break here */
+ }
+ av++;
+ }
+ if (nproxies < BONDO_MINSLOTS)
+ nproxies = BONDO_MINSLOTS;
+ if (!(proxies = (t_pd **)getbytes(nproxies * sizeof(*proxies))))
+ return (0);
+ for (nslots = 0; nslots < nproxies; nslots++)
+ if (!(proxies[nslots] = pd_new(bondo_proxy_class))) break;
+ if (nslots < BONDO_MINSLOTS
+ || !(outs = (t_outlet **)getbytes(nslots * sizeof(*outs))))
+ {
+ i = nslots;
+ while (i--) pd_free(proxies[i]);
+ freebytes(proxies, nproxies * sizeof(*proxies));
+ return (0);
+ }
+ x = (t_bondo *)pd_new(bondo_class);
+ x->x_delay = delay;
+ x->x_multiatom = multiatom;
+ x->x_nslots = nslots;
+ x->x_nproxies = nproxies;
+ x->x_proxies = proxies;
+ x->x_outs = outs;
+ for (i = 0; i < nslots; i++)
+ {
+ t_bondo_proxy *y = (t_bondo_proxy *)proxies[i];
+ y->p_master = x;
+ y->p_id = i;
+ y->p_selector = &s_float; /* CHECKED: it is so in multiatom mode too */
+ y->p_float = 0;
+ y->p_symbol = 0;
+ y->p_pointer = 0;
+ y->p_size = BONDO_INISIZE;
+ y->p_natoms = 0;
+ y->p_message = y->p_messini;
+ if (i) inlet_new((t_object *)x, (t_pd *)y, 0, 0);
+ x->x_outs[i] = outlet_new((t_object *)x, &s_anything);
+ }
+ x->x_clock = clock_new(x, (t_method)bondo_doit);
+ return (x);
+}
+
+void bondo_setup(void)
+{
+ bondo_class = class_new(gensym("bondo"),
+ (t_newmethod)bondo_new,
+ (t_method)bondo_free,
+ sizeof(t_bondo), 0, A_GIMME, 0);
+ class_addbang(bondo_class, bondo_bang);
+ class_addfloat(bondo_class, bondo_float);
+ class_addsymbol(bondo_class, bondo_symbol);
+ class_addpointer(bondo_class, bondo_pointer);
+ class_addlist(bondo_class, bondo_list);
+ class_addanything(bondo_class, bondo_anything);
+ class_addmethod(bondo_class, (t_method)bondo_set,
+ gensym("set"), A_GIMME, 0);
+ bondo_proxy_class = class_new(gensym("_bondo_proxy"), 0, 0,
+ sizeof(t_bondo_proxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addbang(bondo_proxy_class, bondo_proxy_bang);
+ class_addfloat(bondo_proxy_class, bondo_proxy_float);
+ class_addsymbol(bondo_proxy_class, bondo_proxy_symbol);
+ class_addpointer(bondo_proxy_class, bondo_proxy_pointer);
+ class_addlist(bondo_proxy_class, bondo_proxy_list);
+ class_addanything(bondo_proxy_class, bondo_proxy_anything);
+ class_addmethod(bondo_proxy_class, (t_method)bondo_proxy_set,
+ gensym("set"), A_GIMME, 0);
+}
diff --git a/cyclone/hammer/buddy.c b/cyclone/hammer/buddy.c
new file mode 100644
index 0000000..f272739
--- /dev/null
+++ b/cyclone/hammer/buddy.c
@@ -0,0 +1,253 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* LATER compare with buddy.c from max sdk */
+/* LATER revisit buffer handling (maxsize, reentrancy) */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+#define BUDDY_MINSLOTS 2
+#define BUDDY_INISIZE 4 /* LATER rethink */
+
+typedef struct _buddy
+{
+ t_object x_ob;
+ int x_nslots;
+ int x_nproxies; /* as requested (and allocated) */
+ t_pd **x_proxies;
+ t_outlet **x_outs;
+} t_buddy;
+
+typedef struct _buddy_proxy
+{
+ t_object p_ob;
+ t_buddy *p_master;
+ t_symbol *p_selector;
+ t_float p_float;
+ t_symbol *p_symbol;
+ t_gpointer *p_pointer;
+ int p_size; /* as allocated */
+ int p_natoms; /* as used */
+ t_atom *p_message;
+ t_atom p_messini[BUDDY_INISIZE];
+} t_buddy_proxy;
+
+static t_class *buddy_class;
+static t_class *buddy_proxy_class;
+
+static void buddy_clear(t_buddy *x)
+{
+ t_buddy_proxy **p = (t_buddy_proxy **)x->x_proxies;
+ int i = x->x_nslots;
+ while (i--)
+ {
+ (*p)->p_selector = 0;
+ (*p++)->p_natoms = 0; /* defensive */
+ }
+}
+
+static void buddy_check(t_buddy *x)
+{
+ t_buddy_proxy **p = (t_buddy_proxy **)x->x_proxies;
+ int i = x->x_nslots;
+ while (i--)
+ if (!(*p++)->p_selector)
+ return;
+ p = (t_buddy_proxy **)x->x_proxies;
+ i = x->x_nslots;
+ while (i--)
+ {
+ t_symbol *s = p[i]->p_selector;
+ if (s == &s_bang)
+ outlet_bang(x->x_outs[i]);
+ else if (s == &s_float)
+ outlet_float(x->x_outs[i], p[i]->p_float);
+ else if (s == &s_symbol && p[i]->p_symbol)
+ outlet_symbol(x->x_outs[i], p[i]->p_symbol);
+ else if (s == &s_pointer)
+ {
+ /* LATER */
+ }
+ else if (s == &s_list)
+ outlet_list(x->x_outs[i], s, p[i]->p_natoms, p[i]->p_message);
+ else if (s)
+ outlet_anything(x->x_outs[i], s, p[i]->p_natoms, p[i]->p_message);
+ }
+ buddy_clear(x);
+}
+
+static void buddy_proxy_bang(t_buddy_proxy *x)
+{
+ x->p_selector = &s_bang;
+ x->p_natoms = 0; /* defensive */
+ buddy_check(x->p_master);
+}
+
+static void buddy_proxy_float(t_buddy_proxy *x, t_float f)
+{
+ x->p_selector = &s_float;
+ x->p_float = f;
+ x->p_natoms = 0; /* defensive */
+ buddy_check(x->p_master);
+}
+
+static void buddy_proxy_symbol(t_buddy_proxy *x, t_symbol *s)
+{
+ x->p_selector = &s_symbol;
+ x->p_symbol = s;
+ x->p_natoms = 0; /* defensive */
+ buddy_check(x->p_master);
+}
+
+static void buddy_proxy_pointer(t_buddy_proxy *x, t_gpointer *gp)
+{
+ x->p_selector = &s_pointer;
+ x->p_pointer = gp;
+ x->p_natoms = 0; /* defensive */
+ buddy_check(x->p_master);
+}
+
+static void buddy_proxy_domessage(t_buddy_proxy *x, int ac, t_atom *av)
+{
+ if (ac > x->p_size)
+ {
+ /* LATER consider using BUDDY_MAXSIZE (and warning if exceeded) */
+ x->p_message = grow_nodata(&ac, &x->p_size, x->p_message,
+ BUDDY_INISIZE, x->p_messini,
+ sizeof(*x->p_message));
+ }
+ x->p_natoms = ac;
+ memcpy(x->p_message, av, ac * sizeof(*x->p_message));
+ buddy_check(x->p_master);
+}
+
+static void buddy_proxy_list(t_buddy_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ x->p_selector = &s_list; /* LATER rethink */
+ buddy_proxy_domessage(x, ac, av);
+}
+
+static void buddy_proxy_anything(t_buddy_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ x->p_selector = s; /* LATER rethink */
+ buddy_proxy_domessage(x, ac, av);
+}
+
+static void buddy_bang(t_buddy *x)
+{
+ buddy_proxy_bang((t_buddy_proxy *)x->x_proxies[0]);
+}
+
+static void buddy_float(t_buddy *x, t_float f)
+{
+ buddy_proxy_float((t_buddy_proxy *)x->x_proxies[0], f);
+}
+
+static void buddy_symbol(t_buddy *x, t_symbol *s)
+{
+ buddy_proxy_symbol((t_buddy_proxy *)x->x_proxies[0], s);
+}
+
+static void buddy_pointer(t_buddy *x, t_gpointer *gp)
+{
+ buddy_proxy_pointer((t_buddy_proxy *)x->x_proxies[0], gp);
+}
+
+static void buddy_list(t_buddy *x, t_symbol *s, int ac, t_atom *av)
+{
+ buddy_proxy_list((t_buddy_proxy *)x->x_proxies[0], s, ac, av);
+}
+
+static void buddy_anything(t_buddy *x, t_symbol *s, int ac, t_atom *av)
+{
+ buddy_proxy_anything((t_buddy_proxy *)x->x_proxies[0], s, ac, av);
+}
+
+static void buddy_free(t_buddy *x)
+{
+ if (x->x_proxies)
+ {
+ int i = x->x_nslots;
+ while (i--)
+ {
+ t_buddy_proxy *y = (t_buddy_proxy *)x->x_proxies[i];
+ if (y->p_message != y->p_messini)
+ freebytes(y->p_message, y->p_size * sizeof(*y->p_message));
+ pd_free((t_pd *)y);
+ }
+ freebytes(x->x_proxies, x->x_nproxies * sizeof(*x->x_proxies));
+ }
+ if (x->x_outs)
+ freebytes(x->x_outs, x->x_nslots * sizeof(*x->x_outs));
+}
+
+static void *buddy_new(t_floatarg f)
+{
+ t_buddy *x;
+ int i, nslots, nproxies = (int)f;
+ t_pd **proxies;
+ t_outlet **outs;
+ if (nproxies < BUDDY_MINSLOTS)
+ nproxies = BUDDY_MINSLOTS;
+ if (!(proxies = (t_pd **)getbytes(nproxies * sizeof(*proxies))))
+ return (0);
+ for (nslots = 0; nslots < nproxies; nslots++)
+ if (!(proxies[nslots] = pd_new(buddy_proxy_class))) break;
+ if (nslots < BUDDY_MINSLOTS
+ || !(outs = (t_outlet **)getbytes(nslots * sizeof(*outs))))
+ {
+ int i = nslots;
+ while (i--) pd_free(proxies[i]);
+ freebytes(proxies, nproxies * sizeof(*proxies));
+ return (0);
+ }
+ x = (t_buddy *)pd_new(buddy_class);
+ x->x_nslots = nslots;
+ x->x_nproxies = nproxies;
+ x->x_proxies = proxies;
+ x->x_outs = outs;
+ for (i = 0; i < nslots; i++)
+ {
+ t_buddy_proxy *y = (t_buddy_proxy *)proxies[i];
+ y->p_master = x;
+ y->p_selector = 0;
+ y->p_float = 0;
+ y->p_symbol = 0;
+ y->p_pointer = 0;
+ y->p_size = BUDDY_INISIZE;
+ y->p_natoms = 0;
+ y->p_message = y->p_messini;
+ if (i) inlet_new((t_object *)x, (t_pd *)y, 0, 0);
+ x->x_outs[i] = outlet_new((t_object *)x, &s_anything);
+ }
+ return (x);
+}
+
+void buddy_setup(void)
+{
+ buddy_class = class_new(gensym("buddy"),
+ (t_newmethod)buddy_new,
+ (t_method)buddy_free,
+ sizeof(t_buddy), 0, A_DEFFLOAT, 0);
+ class_addbang(buddy_class, buddy_bang);
+ class_addfloat(buddy_class, buddy_float);
+ class_addsymbol(buddy_class, buddy_symbol);
+ class_addpointer(buddy_class, buddy_pointer);
+ class_addlist(buddy_class, buddy_list);
+ class_addanything(buddy_class, buddy_anything);
+ class_addmethod(buddy_class, (t_method)buddy_clear, gensym("clear"), 0);
+ buddy_proxy_class = class_new(gensym("_buddy_proxy"), 0, 0,
+ sizeof(t_buddy_proxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addbang(buddy_proxy_class, buddy_proxy_bang);
+ class_addfloat(buddy_proxy_class, buddy_proxy_float);
+ class_addsymbol(buddy_proxy_class, buddy_proxy_symbol);
+ class_addpointer(buddy_proxy_class, buddy_proxy_pointer);
+ class_addlist(buddy_proxy_class, buddy_proxy_list);
+ class_addanything(buddy_proxy_class, buddy_proxy_anything);
+}
diff --git a/cyclone/hammer/capture.c b/cyclone/hammer/capture.c
new file mode 100644
index 0000000..b36c421
--- /dev/null
+++ b/cyclone/hammer/capture.c
@@ -0,0 +1,291 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <stdio.h>
+#include "m_pd.h"
+#include "common/loud.h"
+#include "hammer/file.h"
+
+#define CAPTURE_DEFSIZE 512
+
+typedef struct _capture
+{
+ t_object x_ob;
+ t_canvas *x_canvas;
+ char x_intmode; /* if nonzero ('x' or 'm') floats are ignored */
+ float *x_buffer;
+ int x_bufsize;
+ int x_count;
+ int x_head;
+ t_hammerfile *x_filehandle;
+} t_capture;
+
+static t_class *capture_class;
+
+static void capture_float(t_capture *x, t_float f)
+{
+ if (x->x_intmode && f != (int)f) /* CHECKME float */
+ return;
+ x->x_buffer[x->x_head++] = f;
+ if (x->x_head >= x->x_bufsize)
+ x->x_head = 0;
+ if (x->x_count < x->x_bufsize)
+ x->x_count++;
+}
+
+static void capture_list(t_capture *x, t_symbol *s, int ac, t_atom *av)
+{
+ while (ac--)
+ {
+ if (av->a_type == A_FLOAT) /* CHECKME */
+ capture_float(x, av->a_w.w_float);
+ av++;
+ }
+}
+
+static void capture_clear(t_capture *x)
+{
+ x->x_count = 0;
+ x->x_head = 0;
+}
+
+static void capture_count(t_capture *x)
+{
+ post("capture: %d items received", /* CHECKED */
+ x->x_count); /* CHECKED incompatible (4.07 seems buggy here) */
+}
+
+static void capture_dump(t_capture *x)
+{
+ int count = x->x_count;
+ if (count < x->x_bufsize)
+ {
+ float *bp = x->x_buffer;
+ while (count--)
+ outlet_float(((t_object *)x)->ob_outlet, *bp++);
+ }
+ else
+ {
+ float *bp = x->x_buffer + x->x_head;
+ count = x->x_bufsize - x->x_head;
+ while (count--)
+ outlet_float(((t_object *)x)->ob_outlet, *bp++);
+ bp = x->x_buffer;
+ count = x->x_head;
+ while (count--)
+ outlet_float(((t_object *)x)->ob_outlet, *bp++);
+ }
+}
+
+static int capture_formatint(int i, char *buf, int col,
+ int maxcol, char *fmt)
+{
+ char *bp = buf;
+ int cnt = 0;
+ if (col > 0)
+ *bp++ = ' ', cnt++;
+ cnt += sprintf(bp, fmt, i);
+ if (col + cnt > maxcol)
+ buf[0] = '\n', col = cnt;
+ else
+ col += cnt;
+ return (col);
+}
+
+static int capture_formatfloat(float f, char *buf, int col,
+ int maxcol, char *fmt)
+{
+ char *bp = buf;
+ int cnt = 0;
+ if (col > 0)
+ *bp++ = ' ', cnt++;
+ cnt += sprintf(bp, fmt, f);
+ if (col + cnt > maxcol)
+ buf[0] = '\n', col = cnt;
+ else
+ col += cnt;
+ return (col);
+}
+
+static int capture_formatnumber(t_capture *x, float f, char *buf,
+ int col, int maxcol)
+{
+ char intmode = x->x_intmode;
+ if (intmode == 'm')
+ intmode = (f < 128 && f > -128 ? 'd' : 'x'); /* CHECKME */
+ if (intmode == 'x')
+ col = capture_formatint((int)f, buf, col, maxcol, "%x");
+ else if (intmode)
+ col = capture_formatint((int)f, buf, col, maxcol, "%d");
+ else
+ col = capture_formatfloat(f, buf, col, maxcol, "%g");
+ return (col);
+}
+
+static int capture_writefloat(t_capture *x, float f, char *buf, int col,
+ FILE *fp)
+{
+ /* CHECKED no linebreaks (FIXME) */
+ col = capture_formatnumber(x, f, buf, col, 80);
+ return (fputs(buf, fp) < 0 ? -1 : col);
+}
+
+static void capture_dowrite(t_capture *x, t_symbol *fn)
+{
+ FILE *fp = 0;
+ int count = x->x_count;
+ char buf[MAXPDSTRING];
+ canvas_makefilename(x->x_canvas, fn->s_name, buf, MAXPDSTRING);
+ if (fp = fopen(buf, "w")) /* LATER ask if overwriting, CHECKED */
+ {
+ int col = 0;
+ if (count < x->x_bufsize)
+ {
+ float *bp = x->x_buffer;
+ while (count--)
+ if ((col = capture_writefloat(x, *bp++, buf, col, fp)) < 0)
+ goto fail;
+ }
+ else
+ {
+ float *bp = x->x_buffer + x->x_head;
+ count = x->x_bufsize - x->x_head;
+ while (count--)
+ if ((col = capture_writefloat(x, *bp++, buf, col, fp)) < 0)
+ goto fail;
+ bp = x->x_buffer;
+ count = x->x_head;
+ while (count--)
+ if ((col = capture_writefloat(x, *bp++, buf, col, fp)) < 0)
+ goto fail;
+ }
+ if (col) fputc('\n', fp);
+ fclose(fp);
+ return;
+ }
+fail:
+ if (fp) fclose(fp);
+ loud_syserror((t_pd *)x, 0);
+}
+
+static void capture_writehook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ capture_dowrite((t_capture *)z, fn);
+}
+
+static void capture_write(t_capture *x, t_symbol *s)
+{
+ if (s && s != &s_)
+ capture_dowrite(x, s);
+ else
+ hammerpanel_save(x->x_filehandle, 0, 0);
+}
+
+static int capture_appendfloat(t_capture *x, float f, char *buf, int col)
+{
+ /* CHECKED 80 columns */
+ col = capture_formatnumber(x, f, buf, col, 80);
+ hammereditor_append(x->x_filehandle, buf);
+ return (col);
+}
+
+static void capture_open(t_capture *x)
+{
+ int count = x->x_count;
+ char buf[MAXPDSTRING];
+ hammereditor_open(x->x_filehandle, "t_capture"); /* CHECKED */
+ if (count < x->x_bufsize)
+ {
+ float *bp = x->x_buffer;
+ int col = 0;
+ while (count--)
+ col = capture_appendfloat(x, *bp++, buf, col);
+ }
+ else
+ {
+ float *bp = x->x_buffer + x->x_head;
+ int col = 0;
+ count = x->x_bufsize - x->x_head;
+ while (count--)
+ col = capture_appendfloat(x, *bp++, buf, col);
+ bp = x->x_buffer;
+ count = x->x_head;
+ while (count--)
+ col = capture_appendfloat(x, *bp++, buf, col);
+ }
+}
+
+/* CHECKED without asking and storing the changes */
+static void capture_wclose(t_capture *x)
+{
+ hammereditor_close(x->x_filehandle, 0);
+}
+
+static void capture_click(t_capture *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ capture_open(x);
+}
+
+static void capture_free(t_capture *x)
+{
+ hammerfile_free(x->x_filehandle);
+ if (x->x_buffer)
+ freebytes(x->x_buffer, x->x_bufsize * sizeof(*x->x_buffer));
+}
+
+static void *capture_new(t_symbol *s, t_floatarg f)
+{
+ t_capture *x = 0;
+ float *buffer;
+ int bufsize = (int)f; /* CHECKME */
+ if (bufsize <= 0) /* CHECKME */
+ bufsize = CAPTURE_DEFSIZE;
+ if (buffer = getbytes(bufsize * sizeof(*buffer)))
+ {
+ x = (t_capture *)pd_new(capture_class);
+ x->x_canvas = canvas_getcurrent();
+ if (s && s != &s_)
+ {
+ if (s == gensym("x"))
+ x->x_intmode = 'x';
+ else if (s == gensym("m"))
+ x->x_intmode = 'm';
+ else
+ x->x_intmode = 'd'; /* ignore floats */
+ }
+ x->x_buffer = buffer;
+ x->x_bufsize = bufsize;
+ outlet_new((t_object *)x, &s_float);
+ x->x_filehandle = hammerfile_new((t_pd *)x, 0, 0, capture_writehook, 0);
+ capture_clear(x);
+ }
+ return (x);
+}
+
+void capture_setup(void)
+{
+ capture_class = class_new(gensym("capture"),
+ (t_newmethod)capture_new,
+ (t_method)capture_free,
+ sizeof(t_capture), 0, A_DEFFLOAT, A_DEFSYM, 0);
+ class_addfloat(capture_class, capture_float);
+ class_addlist(capture_class, capture_list);
+ class_addmethod(capture_class, (t_method)capture_clear,
+ gensym("clear"), 0);
+ class_addmethod(capture_class, (t_method)capture_count,
+ gensym("count"), 0);
+ class_addmethod(capture_class, (t_method)capture_dump,
+ gensym("dump"), 0);
+ class_addmethod(capture_class, (t_method)capture_write,
+ gensym("write"), A_DEFSYM, 0);
+ class_addmethod(capture_class, (t_method)capture_open,
+ gensym("open"), 0);
+ class_addmethod(capture_class, (t_method)capture_wclose,
+ gensym("wclose"), 0);
+ class_addmethod(capture_class, (t_method)capture_click,
+ gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ hammerfile_setup(capture_class, 0);
+}
diff --git a/cyclone/hammer/cartopol.c b/cyclone/hammer/cartopol.c
new file mode 100644
index 0000000..4200686
--- /dev/null
+++ b/cyclone/hammer/cartopol.c
@@ -0,0 +1,44 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define atan2f atan2
+#define hypotf hypot
+#endif
+
+typedef struct _cartopol
+{
+ t_object x_ob;
+ t_float x_imag;
+ t_outlet *x_out2;
+} t_cartopol;
+
+static t_class *cartopol_class;
+
+static void cartopol_float(t_cartopol *x, t_float f)
+{
+ outlet_float(x->x_out2, atan2f(x->x_imag, f));
+ outlet_float(((t_object *)x)->ob_outlet, hypotf(f, x->x_imag));
+}
+
+static void *cartopol_new(void)
+{
+ t_cartopol *x = (t_cartopol *)pd_new(cartopol_class);
+ floatinlet_new((t_object *)x, &x->x_imag);
+ outlet_new((t_object *)x, &s_float);
+ x->x_out2 = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void cartopol_setup(void)
+{
+ cartopol_class = class_new(gensym("cartopol"),
+ (t_newmethod)cartopol_new, 0,
+ sizeof(t_cartopol), 0, 0);
+ class_addfloat(cartopol_class, cartopol_float);
+}
diff --git a/cyclone/hammer/coll.c b/cyclone/hammer/coll.c
new file mode 100644
index 0000000..c4a3388
--- /dev/null
+++ b/cyclone/hammer/coll.c
@@ -0,0 +1,1597 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <stdio.h>
+#include <string.h>
+#include "m_pd.h"
+#include "g_canvas.h"
+#include "common/loud.h"
+#include "hammer/file.h"
+
+/* FIXME sort crashes after (corrupt?) transfers from the editor */
+/* LATER make sure that ``reentrancy protection hack'' is really working... */
+/* CHECKME default fname for 'write' -- c_filename, x_name, nothing? */
+
+#define COLL_DEBUG
+
+typedef struct _collelem
+{
+ int e_hasnumkey;
+ int e_numkey;
+ t_symbol *e_symkey;
+ struct _collelem *e_prev;
+ struct _collelem *e_next;
+ int e_size;
+ t_atom *e_data;
+} t_collelem;
+
+typedef struct _collcommon
+{
+ t_pd c_pd;
+ struct _coll *c_refs; /* used in read-banging and dirty flag handling */
+ int c_embedflag; /* common field (CHECKED in 'TEXT') */
+ int c_loading;
+ int c_relinked;
+ int c_selfmodified;
+ int c_entered; /* a counter, LATER rethink */
+ t_symbol *c_filename;
+ t_canvas *c_lastcanvas;
+ t_hammerfile *c_filehandle;
+ t_collelem *c_first;
+ t_collelem *c_last;
+ t_collelem *c_ahead;
+ t_collelem *c_back;
+} t_collcommon;
+
+typedef struct _coll
+{
+ t_object x_ob;
+ t_canvas *x_canvas;
+ t_symbol *x_name;
+ t_collcommon *x_common;
+ t_hammerfile *x_filehandle;
+ t_outlet *x_keyout;
+ t_outlet *x_filebangout;
+ t_outlet *x_dumpbangout;
+ struct _coll *x_next;
+} t_coll;
+
+static t_class *coll_class;
+static t_class *collcommon_class;
+
+static t_collelem *collelem_new(int ac, t_atom *av, int *np, t_symbol *s)
+{
+ t_collelem *ep = (t_collelem *)getbytes(sizeof(*ep));
+ if (ep->e_hasnumkey = (np != 0))
+ ep->e_numkey = *np;
+ ep->e_symkey = s;
+ ep->e_prev = ep->e_next = 0;
+ if (ep->e_size = ac)
+ {
+ t_atom *ap = getbytes(ac * sizeof(*ap));
+ ep->e_data = ap;
+ if (av) while (ac--)
+ *ap++ = *av++;
+ else while (ac--)
+ {
+ SETFLOAT(ap, 0);
+ ap++;
+ }
+ }
+ else ep->e_data = 0;
+ return (ep);
+}
+
+static void collelem_free(t_collelem *ep)
+{
+ if (ep->e_data)
+ freebytes(ep->e_data, ep->e_size * sizeof(*ep->e_data));
+ freebytes(ep, sizeof(*ep));
+}
+
+/* CHECKME again... apparently c74 is not able to fix this for good */
+/* result: 1 for ep1 < ep2, otherwise 0 (symbols are less then floats) */
+static int collelem_less(t_collelem *ep1, t_collelem *ep2, int ndx)
+{
+ if (ndx < 0)
+ {
+ if (ep1->e_symkey)
+ return (ep2->e_symkey ?
+ strcmp(ep1->e_symkey->s_name,
+ ep2->e_symkey->s_name) < 0
+ : 1); /* CHECKED incompatible with 4.07, but consistent */
+ else if (ep2->e_symkey)
+ return (0); /* CHECKED incompatible with 4.07, but consistent */
+ else
+ return (ep1->e_numkey < ep2->e_numkey); /* CHECKED in 4.07 */
+ }
+ else
+ {
+ t_atom *ap1 = (ndx < ep1->e_size ?
+ ep1->e_data + ndx : ep1->e_data + ep1->e_size - 1);
+ t_atom *ap2 = (ndx < ep2->e_size ?
+ ep2->e_data + ndx : ep2->e_data + ep2->e_size - 1);
+ if (ap1->a_type == A_FLOAT)
+ {
+ if (ap2->a_type == A_FLOAT)
+ return (ap1->a_w.w_float < ap2->a_w.w_float);
+ else if (ap2->a_type == A_SYMBOL)
+ return (0);
+ else
+ return (1);
+ }
+ else if (ap1->a_type == A_SYMBOL)
+ {
+ if (ap2->a_type == A_FLOAT)
+ return (1);
+ else if (ap2->a_type == A_SYMBOL)
+ return (strcmp(ap1->a_w.w_symbol->s_name,
+ ap2->a_w.w_symbol->s_name) < 0);
+ else
+ return (1);
+ }
+ else
+ return (0);
+ }
+}
+
+static void collelem_post(t_collelem *ep)
+{
+ if (ep->e_hasnumkey && ep->e_symkey)
+ startpost("%d %s:", ep->e_numkey, ep->e_symkey->s_name);
+ else if (ep->e_hasnumkey)
+ startpost("%d:", ep->e_numkey);
+ else if (ep->e_symkey)
+ startpost("%s:", ep->e_symkey->s_name);
+ else bug("collcommon_post");
+ postatom(ep->e_size, ep->e_data);
+ endpost();
+}
+
+static void collcommon_post(t_collcommon *cc)
+{
+ t_collelem *ep;
+ for (ep = cc->c_first; ep; ep = ep->e_next) collelem_post(ep);
+}
+
+static t_collelem *collcommon_numkey(t_collcommon *cc, int numkey)
+{
+ t_collelem *ep;
+ for (ep = cc->c_first; ep; ep = ep->e_next)
+ if (ep->e_hasnumkey && ep->e_numkey == numkey)
+ return (ep);
+ return (0);
+}
+
+static t_collelem *collcommon_symkey(t_collcommon *cc, t_symbol *symkey)
+{
+ t_collelem *ep;
+ for (ep = cc->c_first; ep; ep = ep->e_next)
+ if (ep->e_symkey == symkey)
+ return (ep);
+ return (0);
+}
+
+static void collcommon_takeout(t_collcommon *cc, t_collelem *ep)
+{
+ if (ep->e_prev)
+ ep->e_prev->e_next = ep->e_next;
+ else
+ cc->c_first = ep->e_next;
+ if (ep->e_next)
+ ep->e_next->e_prev = ep->e_prev;
+ else
+ cc->c_last = ep->e_prev;
+ if (cc->c_ahead == ep)
+ cc->c_ahead = ep->e_next;
+ if (cc->c_back == ep)
+ cc->c_back = ep->e_prev;
+}
+
+static void collcommon_modified(t_collcommon *cc, int relinked)
+{
+ if (cc->c_loading)
+ return;
+ if (relinked)
+ {
+ cc->c_relinked = 1;
+ }
+ if (cc->c_embedflag)
+ {
+ t_coll *x;
+ for (x = cc->c_refs; x; x = x->x_next)
+ if (x->x_canvas && glist_isvisible(x->x_canvas))
+ canvas_dirty(x->x_canvas, 1);
+ }
+}
+
+/* atomic collcommon modifiers: clearall, remove, replace,
+ putbefore, putafter, swaplinks, swapkeys, changesymkey, renumber, sort */
+
+static void collcommon_clearall(t_collcommon *cc)
+{
+ if (cc->c_first)
+ {
+ t_collelem *ep1 = cc->c_first, *ep2;
+ do
+ {
+ ep2 = ep1->e_next;
+ collelem_free(ep1);
+ }
+ while (ep1 = ep2);
+ cc->c_first = cc->c_last = 0;
+ cc->c_ahead = cc->c_back = 0;
+ collcommon_modified(cc, 1);
+ }
+}
+
+static void collcommon_remove(t_collcommon *cc, t_collelem *ep)
+{
+ collcommon_takeout(cc, ep);
+ collelem_free(ep);
+ collcommon_modified(cc, 1);
+}
+
+static void collcommon_replace(t_collcommon *cc, t_collelem *ep,
+ int ac, t_atom *av, int *np, t_symbol *s)
+{
+ if (ep->e_hasnumkey = (np != 0))
+ ep->e_numkey = *np;
+ ep->e_symkey = s;
+ if (ac)
+ {
+ int i = ac;
+ t_atom *ap;
+ if (ep->e_data)
+ {
+ if (ep->e_size != ac)
+ ap = resizebytes(ep->e_data,
+ ep->e_size * sizeof(*ap), ac * sizeof(*ap));
+ else ap = ep->e_data;
+ }
+ else
+ ap = getbytes(ac * sizeof(*ap));
+ ep->e_data = ap;
+ if (av) while (i --)
+ *ap++ = *av++;
+ else while (i --)
+ {
+ SETFLOAT(ap, 0);
+ ap++;
+ }
+ }
+ else
+ {
+ if (ep->e_data)
+ freebytes(ep->e_data, ep->e_size * sizeof(*ep->e_data));
+ ep->e_data = 0;
+ }
+ ep->e_size = ac;
+ collcommon_modified(cc, 0);
+}
+
+static void collcommon_putbefore(t_collcommon *cc,
+ t_collelem *ep, t_collelem *next)
+{
+ if (next)
+ {
+ ep->e_next = next;
+ if (ep->e_prev = next->e_prev)
+ ep->e_prev->e_next = ep;
+ else
+ cc->c_first = ep;
+ next->e_prev = ep;
+ }
+ else if (cc->c_first || cc->c_last)
+ bug("collcommon_putbefore");
+ else
+ cc->c_first = cc->c_last = ep;
+ collcommon_modified(cc, 1);
+}
+
+static void collcommon_putafter(t_collcommon *cc,
+ t_collelem *ep, t_collelem *prev)
+{
+ if (prev)
+ {
+ ep->e_prev = prev;
+ if (ep->e_next = prev->e_next)
+ ep->e_next->e_prev = ep;
+ else
+ cc->c_last = ep;
+ prev->e_next = ep;
+ }
+ else if (cc->c_first || cc->c_last)
+ bug("collcommon_putafter");
+ else
+ cc->c_first = cc->c_last = ep;
+ collcommon_modified(cc, 1);
+}
+
+/* LATER consider making it faster, if there is a real need.
+ Now called only in the sort routine, once per sort. */
+static void collcommon_swaplinks(t_collcommon *cc,
+ t_collelem *ep1, t_collelem *ep2)
+{
+ if (ep1 != ep2)
+ {
+ t_collelem *prev1 = ep1->e_prev, *prev2 = ep2->e_prev;
+ if (prev1 == ep2)
+ {
+ collcommon_takeout(cc, ep2);
+ collcommon_putafter(cc, ep2, ep1);
+ }
+ else if (prev2 == ep1)
+ {
+ collcommon_takeout(cc, ep1);
+ collcommon_putafter(cc, ep1, ep2);
+ }
+ else if (prev1)
+ {
+ if (prev2)
+ {
+ collcommon_takeout(cc, ep1);
+ collcommon_takeout(cc, ep2);
+ collcommon_putafter(cc, ep1, prev2);
+ collcommon_putafter(cc, ep2, prev1);
+ }
+ else
+ {
+ t_collelem *next2 = ep2->e_next;
+ collcommon_takeout(cc, ep1);
+ collcommon_takeout(cc, ep2);
+ collcommon_putbefore(cc, ep1, next2);
+ collcommon_putafter(cc, ep2, prev1);
+ }
+ }
+ else if (prev2)
+ {
+ t_collelem *next1 = ep1->e_next;
+ collcommon_takeout(cc, ep1);
+ collcommon_takeout(cc, ep2);
+ collcommon_putafter(cc, ep1, prev2);
+ collcommon_putbefore(cc, ep2, next1);
+ }
+ else bug("collcommon_swaplinks");
+ }
+}
+
+static void collcommon_swapkeys(t_collcommon *cc,
+ t_collelem *ep1, t_collelem *ep2)
+{
+ int hasnumkey = ep2->e_hasnumkey, numkey = ep2->e_numkey;
+ t_symbol *symkey = ep2->e_symkey;
+ ep2->e_hasnumkey = ep1->e_hasnumkey;
+ ep2->e_numkey = ep1->e_numkey;
+ ep2->e_symkey = ep1->e_symkey;
+ ep1->e_hasnumkey = hasnumkey;
+ ep1->e_numkey = numkey;
+ ep1->e_symkey = symkey;
+ collcommon_modified(cc, 0);
+}
+
+static void collcommon_changesymkey(t_collcommon *cc,
+ t_collelem *ep, t_symbol *s)
+{
+ ep->e_symkey = s;
+ collcommon_modified(cc, 0);
+}
+
+static void collcommon_renumber(t_collcommon *cc, int startkey)
+{
+ t_collelem *ep;
+ for (ep = cc->c_first; ep; ep = ep->e_next)
+ if (ep->e_hasnumkey)
+ ep->e_numkey = startkey++;
+ collcommon_modified(cc, 0);
+}
+
+/* LATER choose a better algo, after coll's storage structures stabilize.
+ Note, that even the simple insertion sort below (n-square) might prove
+ better for dlls, than theoretically efficient algo (nlogn) which requires
+ random access emulation. Avoiding recursion is not a bad idea, too. */
+static void collcommon_sort(t_collcommon *cc, int asc, int ndx)
+{
+ t_collelem *min = cc->c_first;
+ t_collelem *ep;
+ if (min && (ep = min->e_next))
+ {
+ cc->c_loading = 1;
+ /* search for a sentinel element */
+ do
+ if (collelem_less(ep, min, ndx) == asc) min = ep;
+ while (ep = ep->e_next);
+ /* prepend it */
+ collcommon_swaplinks(cc, cc->c_first, min);
+ /* sort */
+ ep = min->e_next->e_next;
+ while (ep)
+ {
+ t_collelem *next = ep->e_next;
+ for (min = ep->e_prev;
+ collelem_less(ep, min, ndx) == asc;
+ min = min->e_prev);
+ if (ep != min->e_next)
+ {
+ collcommon_takeout(cc, ep);
+ collcommon_putafter(cc, ep, min);
+ }
+ ep = next;
+ }
+ cc->c_loading = 0;
+ collcommon_modified(cc, 1);
+ }
+}
+
+static void collcommon_adddata(t_collcommon *cc, t_collelem *ep,
+ int ac, t_atom *av)
+{
+ if (ac)
+ {
+ t_atom *ap;
+ int newsize = ep->e_size + ac;
+ if (ep->e_data)
+ ap = resizebytes(ep->e_data,
+ ep->e_size * sizeof(*ap), newsize * sizeof(*ap));
+ else
+ {
+ ep->e_size = 0; /* redundant, hopefully */
+ ap = getbytes(newsize * sizeof(*ap));
+ }
+ ep->e_data = ap;
+ ap += ep->e_size;
+ if (av) while (ac--)
+ *ap++ = *av++;
+ else while (ac--)
+ {
+ SETFLOAT(ap, 0);
+ ap++;
+ }
+ ep->e_size = newsize;
+ collcommon_modified(cc, 0);
+ }
+}
+
+static t_collelem *collcommon_tonumkey(t_collcommon *cc, int numkey,
+ int ac, t_atom *av, int replace)
+{
+ t_collelem *old = collcommon_numkey(cc, numkey), *new;
+ if (old && replace)
+ collcommon_replace(cc, new = old, ac, av, &numkey, 0);
+ else
+ {
+ new = collelem_new(ac, av, &numkey, 0);
+ if (old)
+ {
+ collcommon_putbefore(cc, new, old);
+ do
+ if (old->e_hasnumkey) old->e_numkey++; /* LATER rethink */
+ while (old = old->e_next);
+ }
+ else
+ {
+ int closestkey = 0; /* LATER rethink */
+ t_collelem *closest = 0, *ep;
+ for (ep = cc->c_first; ep; ep = ep->e_next)
+ {
+ if (ep->e_hasnumkey)
+ {
+ if (numkey >= closestkey && numkey <= ep->e_numkey)
+ {
+ collcommon_putbefore(cc, new, ep);
+ break;
+ }
+ closestkey = ep->e_numkey;
+ }
+ closest = ep;
+ }
+ if (!ep)
+ {
+ if (numkey <= closestkey)
+ collcommon_putbefore(cc, new, closest);
+ else
+ collcommon_putafter(cc, new, closest);
+ }
+ }
+ }
+ return (new);
+}
+
+static t_collelem *collcommon_tosymkey(t_collcommon *cc, t_symbol *symkey,
+ int ac, t_atom *av, int replace)
+{
+ t_collelem *old = collcommon_symkey(cc, symkey), *new;
+ if (old && replace)
+ collcommon_replace(cc, new = old, ac, av, 0, symkey);
+ else
+ collcommon_putafter(cc, new = collelem_new(ac, av, 0, symkey),
+ cc->c_last);
+ return (new);
+}
+
+static int collcommon_fromlist(t_collcommon *cc, int ac, t_atom *av)
+{
+ int hasnumkey = 0, numkey;
+ t_symbol *symkey = 0;
+ int size = 0;
+ t_atom *data = 0;
+ int nlines = 0;
+ cc->c_loading = 1;
+ collcommon_clearall(cc);
+ while (ac--)
+ {
+ if (data)
+ {
+ if (av->a_type == A_SEMI)
+ {
+ t_collelem *ep = collelem_new(size, data,
+ hasnumkey ? &numkey : 0, symkey);
+ collcommon_putafter(cc, ep, cc->c_last);
+ hasnumkey = 0;
+ symkey = 0;
+ data = 0;
+ nlines++;
+ }
+ if (av->a_type == A_COMMA)
+ {
+ /* CHECKED rejecting a comma */
+ collcommon_clearall(cc); /* LATER rethink */
+ cc->c_loading = 0;
+ return (-nlines);
+ }
+ else size++;
+ }
+ else if (av->a_type == A_COMMA)
+ {
+ size = 0;
+ data = av + 1;
+ }
+ else if (av->a_type == A_SYMBOL)
+ symkey = av->a_w.w_symbol;
+ else if (av->a_type == A_FLOAT &&
+ loud_checkint(0, av->a_w.w_float, &numkey, 0))
+ hasnumkey = 1;
+ else
+ {
+ loud_error(0, "coll: bad atom");
+ collcommon_clearall(cc); /* LATER rethink */
+ cc->c_loading = 0;
+ return (-nlines);
+ }
+ av++;
+ }
+ if (data)
+ {
+ loud_error(0, "coll: incomplete");
+ collcommon_clearall(cc); /* LATER rethink */
+ cc->c_loading = 0;
+ return (-nlines);
+ }
+ cc->c_loading = 0;
+ return (nlines);
+}
+
+static int collcommon_frombinbuf(t_collcommon *cc, t_binbuf *bb)
+{
+ return (collcommon_fromlist(cc, binbuf_getnatom(bb), binbuf_getvec(bb)));
+}
+
+static void collcommon_doread(t_collcommon *cc, t_symbol *fn, t_canvas *cv)
+{
+ t_binbuf *bb;
+ int ac;
+ t_atom *av;
+ char buf[MAXPDSTRING];
+ if (!fn && !(fn = cc->c_filename)) /* !fn: 'readagain' */
+ return;
+ if (cv || (cv = cc->c_lastcanvas)) /* !cv: 'read' w/o arg, 'readagain' */
+ canvas_makefilename(cv, fn->s_name, buf, MAXPDSTRING);
+ else
+ {
+ strncpy(buf, fn->s_name, MAXPDSTRING);
+ buf[MAXPDSTRING-1] = 0;
+ }
+ if (!cc->c_refs)
+ {
+ /* loading during object creation --
+ avoid binbuf_read()'s complaints, LATER rethink */
+ FILE *fp;
+ char fname[MAXPDSTRING];
+ sys_bashfilename(buf, fname);
+ if (!(fp = fopen(fname, "r")))
+ {
+ loud_warning(&coll_class, "no coll file '%s'", fname);
+ return;
+ }
+ fclose(fp);
+ }
+ bb = binbuf_new();
+ if (binbuf_read(bb, buf, "", 0))
+ loud_error(0, "coll: error reading text file '%s'", fn->s_name);
+ else
+ {
+ int nlines = collcommon_frombinbuf(cc, bb);
+ if (nlines > 0)
+ {
+ t_coll *x;
+ /* LATER consider making this more robust */
+ for (x = cc->c_refs; x; x = x->x_next)
+ outlet_bang(x->x_filebangout);
+ cc->c_lastcanvas = cv;
+ cc->c_filename = fn;
+ post("coll: finished reading %d lines from text file '%s'",
+ nlines, fn->s_name);
+ }
+ else if (nlines < 0)
+ loud_error(0, "coll: error in line %d of text file '%s'",
+ 1 - nlines, fn->s_name);
+ else
+ loud_error(0, "coll: error reading text file '%s'", fn->s_name);
+ if (cc->c_refs)
+ collcommon_modified(cc, 1);
+ }
+ binbuf_free(bb);
+}
+
+static void collcommon_readhook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ collcommon_doread((t_collcommon *)z, fn, 0);
+}
+
+static void collcommon_tobinbuf(t_collcommon *cc, t_binbuf *bb)
+{
+ t_collelem *ep;
+ t_atom at[3];
+ for (ep = cc->c_first; ep; ep = ep->e_next)
+ {
+ t_atom *ap = at;
+ int cnt = 1;
+ if (ep->e_hasnumkey)
+ {
+ SETFLOAT(ap, ep->e_numkey);
+ ap++; cnt++;
+ }
+ if (ep->e_symkey)
+ {
+ SETSYMBOL(ap, ep->e_symkey);
+ ap++; cnt++;
+ }
+ SETCOMMA(ap);
+ binbuf_add(bb, cnt, at);
+ binbuf_add(bb, ep->e_size, ep->e_data);
+ binbuf_addsemi(bb);
+ }
+}
+
+static void collcommon_dowrite(t_collcommon *cc, t_symbol *fn, t_canvas *cv)
+{
+ t_binbuf *bb;
+ int ac;
+ t_atom *av;
+ char buf[MAXPDSTRING];
+ if (!fn && !(fn = cc->c_filename)) /* !fn: 'writeagain' */
+ return;
+ if (cv || (cv = cc->c_lastcanvas)) /* !cv: 'write' w/o arg, 'writeagain' */
+ canvas_makefilename(cv, fn->s_name, buf, MAXPDSTRING);
+ else
+ {
+ strncpy(buf, fn->s_name, MAXPDSTRING);
+ buf[MAXPDSTRING-1] = 0;
+ }
+ bb = binbuf_new();
+ collcommon_tobinbuf(cc, bb);
+ if (binbuf_write(bb, buf, "", 0))
+ loud_error(0, "coll: error writing text file '%s'", fn->s_name);
+ else
+ {
+ cc->c_lastcanvas = cv;
+ cc->c_filename = fn;
+ }
+ binbuf_free(bb);
+}
+
+static void collcommon_writehook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ collcommon_dowrite((t_collcommon *)z, fn, 0);
+}
+
+static void coll_embedhook(t_pd *z, t_binbuf *bb, t_symbol *bindsym)
+{
+ t_coll *x = (t_coll *)z;
+ t_collcommon *cc = x->x_common;
+ if (cc->c_embedflag)
+ {
+ t_collelem *ep;
+ t_atom at[6];
+ binbuf_addv(bb, "ssii;", bindsym, gensym("flags"), 1, 0);
+ SETSYMBOL(at, bindsym);
+ for (ep = cc->c_first; ep; ep = ep->e_next)
+ {
+ t_atom *ap = at + 1;
+ int cnt;
+ if (ep->e_hasnumkey && ep->e_symkey)
+ {
+ SETSYMBOL(ap, gensym("nstore"));
+ ap++;
+ SETSYMBOL(ap, ep->e_symkey);
+ ap++;
+ SETFLOAT(ap, ep->e_numkey);
+ cnt = 4;
+ }
+ else if (ep->e_symkey)
+ {
+ SETSYMBOL(ap, gensym("store"));
+ ap++;
+ SETSYMBOL(ap, ep->e_symkey);
+ cnt = 3;
+ }
+ else
+ {
+ SETFLOAT(ap, ep->e_numkey);
+ cnt = 2;
+ }
+ binbuf_add(bb, cnt, at);
+ binbuf_add(bb, ep->e_size, ep->e_data);
+ binbuf_addsemi(bb);
+ }
+ }
+}
+
+static void collcommon_editorhook(t_pd *z, t_symbol *s, int ac, t_atom *av)
+{
+ int nlines = collcommon_fromlist((t_collcommon *)z, ac, av);
+ if (nlines < 0)
+ loud_error(0, "coll: editing error in line %d", 1 - nlines);
+}
+
+static t_collcommon *coll_checkcommon(t_coll *x)
+{
+ if (x->x_name &&
+ x->x_common != (t_collcommon *)pd_findbyclass(x->x_name,
+ collcommon_class))
+ {
+ bug("coll_checkcommon");
+ return (0);
+ }
+ return (x->x_common);
+}
+
+static void coll_unbind(t_coll *x)
+{
+ /* LATER consider calling coll_checkcommon(x) */
+ t_collcommon *cc = x->x_common;
+ t_coll *prev, *next;
+ if ((prev = cc->c_refs) == x)
+ {
+ if (!(cc->c_refs = x->x_next))
+ {
+ hammerfile_free(cc->c_filehandle);
+ cc->c_loading = 1; /* disable dirty-flag handling, LATER rethink */
+ collcommon_clearall(cc);
+ if (x->x_name) pd_unbind(&cc->c_pd, x->x_name);
+ pd_free(&cc->c_pd);
+ }
+ }
+ else if (prev)
+ {
+ while (next = prev->x_next)
+ {
+ if (next == x)
+ {
+ prev->x_next = next->x_next;
+ break;
+ }
+ prev = next;
+ }
+ }
+ x->x_common = 0;
+ x->x_name = 0;
+ x->x_next = 0;
+}
+
+static void coll_bind(t_coll *x, t_symbol *name)
+{
+ t_collcommon *cc = 0;
+ if (name == &s_)
+ name = 0;
+ else if (name)
+ cc = (t_collcommon *)pd_findbyclass(name, collcommon_class);
+ if (!cc)
+ {
+ cc = (t_collcommon *)pd_new(collcommon_class);
+ cc->c_refs = 0;
+ cc->c_embedflag = 0;
+ cc->c_loading = 0;
+ if (name)
+ {
+ pd_bind(&cc->c_pd, name);
+ /* LATER rethink canvas unpredictability */
+ collcommon_doread(cc, name, x->x_canvas);
+ }
+ else
+ {
+ cc->c_filename = 0;
+ cc->c_lastcanvas = 0;
+ }
+ cc->c_filehandle = hammerfile_new((t_pd *)cc, 0, collcommon_readhook,
+ collcommon_writehook,
+ collcommon_editorhook);
+ }
+ x->x_common = cc;
+ x->x_name = name;
+ x->x_next = cc->c_refs;
+ cc->c_refs = x;
+}
+
+static int coll_rebind(t_coll *x, t_symbol *name)
+{
+ t_collcommon *cc;
+ if (name && name != &s_ &&
+ (cc = (t_collcommon *)pd_findbyclass(name, collcommon_class)))
+ {
+ coll_unbind(x);
+ x->x_common = cc;
+ x->x_name = name;
+ x->x_next = cc->c_refs;
+ cc->c_refs = x;
+ return (1);
+ }
+ else return (0);
+}
+
+static void coll_dooutput(t_coll *x, int ac, t_atom *av)
+{
+ if (ac > 1)
+ {
+ if (av->a_type == A_FLOAT)
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av);
+ else if (av->a_type == A_SYMBOL)
+ outlet_anything(((t_object *)x)->ob_outlet,
+ av->a_w.w_symbol, ac-1, av+1);
+ }
+ else if (ac)
+ {
+ if (av->a_type == A_FLOAT)
+ outlet_float(((t_object *)x)->ob_outlet, av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL)
+ outlet_symbol(((t_object *)x)->ob_outlet, av->a_w.w_symbol);
+ }
+}
+
+static void coll_keyoutput(t_coll *x, t_collelem *ep)
+{
+ t_collcommon *cc = x->x_common;
+ if (!cc->c_entered++) cc->c_selfmodified = 0;
+ cc->c_relinked = 0;
+ if (ep->e_hasnumkey)
+ outlet_float(x->x_keyout, ep->e_numkey);
+ else if (ep->e_symkey)
+ outlet_symbol(x->x_keyout, ep->e_symkey);
+ else
+ outlet_float(x->x_keyout, 0);
+ if (cc->c_relinked) cc->c_selfmodified = 1;
+ cc->c_entered--;
+}
+
+static t_collelem *coll_findkey(t_coll *x, t_atom *key, t_symbol *mess)
+{
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep = 0;
+ if (key->a_type == A_FLOAT)
+ {
+ int numkey;
+ if (loud_checkint((t_pd *)x, key->a_w.w_float, &numkey, mess))
+ ep = collcommon_numkey(cc, numkey);
+ else
+ mess = 0;
+ }
+ else if (key->a_type == A_SYMBOL)
+ ep = collcommon_symkey(cc, key->a_w.w_symbol);
+ else if (mess)
+ {
+ loud_messarg((t_pd *)x, mess);
+ mess = 0;
+ }
+ if (!ep && mess)
+ loud_error((t_pd *)x, "no such key");
+ return (ep);
+}
+
+static t_collelem *coll_tokey(t_coll *x, t_atom *key, int ac, t_atom *av,
+ int replace, t_symbol *mess)
+{
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep = 0;
+ if (key->a_type == A_FLOAT)
+ {
+ int numkey;
+ if (loud_checkint((t_pd *)x, key->a_w.w_float, &numkey, mess))
+ ep = collcommon_tonumkey(cc, numkey, ac, av, replace);
+ }
+ else if (key->a_type == A_SYMBOL)
+ ep = collcommon_tosymkey(cc, key->a_w.w_symbol, ac, av, replace);
+ else if (mess)
+ loud_messarg((t_pd *)x, mess);
+ return (ep);
+}
+
+static t_collelem *coll_firsttyped(t_coll *x, int ndx, t_atomtype type)
+{
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep;
+ for (ep = cc->c_first; ep; ep = ep->e_next)
+ if (ep->e_size > ndx && ep->e_data[ndx].a_type == type)
+ return (ep);
+ return (0);
+}
+
+/* the methods */
+
+static void coll_float(t_coll *x, t_float f)
+{
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep;
+ int numkey;
+ if (loud_checkint((t_pd *)x, f, &numkey, &s_float) &&
+ (ep = collcommon_numkey(cc, numkey)))
+ {
+ coll_keyoutput(x, ep);
+ if (!cc->c_selfmodified || (ep = collcommon_numkey(cc, numkey)))
+ coll_dooutput(x, ep->e_size, ep->e_data);
+ }
+}
+
+static void coll_symbol(t_coll *x, t_symbol *s)
+{
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep;
+ if (ep = collcommon_symkey(cc, s))
+ {
+ coll_keyoutput(x, ep);
+ if (!cc->c_selfmodified || (ep = collcommon_symkey(cc, s)))
+ coll_dooutput(x, ep->e_size, ep->e_data);
+ }
+}
+
+static void coll_list(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac >= 2 && av->a_type == A_FLOAT)
+ coll_tokey(x, av, ac-1, av+1, 1, &s_list);
+ else
+ loud_messarg((t_pd *)x, &s_list);
+}
+
+static void coll_anything(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ coll_symbol(x, s);
+}
+
+static void coll_store(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac >= 2)
+ coll_tokey(x, av, ac-1, av+1, 1, s);
+ else
+ loud_messarg((t_pd *)x, s);
+}
+
+static void coll_nstore(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac >= 3)
+ {
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep;
+ int numkey;
+ if (av->a_type == A_FLOAT && av[1].a_type == A_SYMBOL)
+ {
+ if (loud_checkint((t_pd *)x, av->a_w.w_float, &numkey, s))
+ {
+ if (ep = collcommon_symkey(cc, av[1].a_w.w_symbol))
+ collcommon_remove(cc, ep);
+ ep = collcommon_tonumkey(cc, numkey, ac-2, av+2, 1);
+ ep->e_symkey = av[1].a_w.w_symbol;
+ }
+ }
+ else if (av->a_type == A_SYMBOL && av[1].a_type == A_FLOAT)
+ {
+ if (loud_checkint((t_pd *)x, av[1].a_w.w_float, &numkey, s))
+ {
+ if (ep = collcommon_numkey(cc, numkey))
+ collcommon_remove(cc, ep);
+ ep = collcommon_tosymkey(cc, av->a_w.w_symbol, ac-2, av+2, 1);
+ ep->e_hasnumkey = 1;
+ ep->e_numkey = numkey;
+ }
+ }
+ else loud_messarg((t_pd *)x, s);
+ }
+ else loud_messarg((t_pd *)x, s);
+}
+
+static void coll_insert(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac >= 2 && av->a_type == A_FLOAT)
+ coll_tokey(x, av, ac-1, av+1, 0, s);
+ else
+ loud_messarg((t_pd *)x, s);
+}
+
+static void coll_remove(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ t_collelem *ep;
+ if (ep = coll_findkey(x, av, s))
+ collcommon_remove(x->x_common, ep);
+ }
+ else loud_messarg((t_pd *)x, s);
+}
+
+static void coll_delete(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ t_collelem *ep;
+ if (ep = coll_findkey(x, av, s))
+ {
+ if (av->a_type == A_FLOAT)
+ {
+ int numkey = ep->e_numkey;
+ t_collelem *next;
+ for (next = ep->e_next; next; next = next->e_next)
+ if (next->e_hasnumkey && next->e_numkey > numkey)
+ next->e_numkey--;
+ }
+ collcommon_remove(x->x_common, ep);
+ }
+ }
+ else loud_messarg((t_pd *)x, s);
+}
+
+static void coll_assoc(t_coll *x, t_symbol *s, t_floatarg f)
+{
+ int numkey;
+ if (loud_checkint((t_pd *)x, f, &numkey, gensym("assoc")))
+ {
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep1, *ep2;
+ if ((ep1 = collcommon_numkey(cc, numkey)) &&
+ ep1->e_symkey != s) /* LATER rethink */
+ {
+ if (ep2 = collcommon_symkey(cc, s))
+ collcommon_remove(cc, ep2);
+ collcommon_changesymkey(cc, ep1, s);
+ }
+ }
+}
+
+static void coll_deassoc(t_coll *x, t_symbol *s, t_floatarg f)
+{
+ int numkey;
+ if (loud_checkint((t_pd *)x, f, &numkey, gensym("deassoc")))
+ {
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep;
+ if (ep = collcommon_numkey(cc, numkey))
+ collcommon_changesymkey(cc, ep, 0);
+ }
+}
+
+static void coll_subsym(t_coll *x, t_symbol *s1, t_symbol *s2)
+{
+ t_collelem *ep;
+ if (s1 != s2 && (ep = collcommon_symkey(x->x_common, s2)))
+ collcommon_changesymkey(x->x_common, ep, s1);
+}
+
+static void coll_renumber(t_coll *x, t_floatarg f)
+{
+ int startkey;
+ if (loud_checkint((t_pd *)x, f, &startkey, gensym("renumber")))
+ collcommon_renumber(x->x_common, startkey);
+}
+
+static void coll_merge(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac >= 2)
+ {
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep;
+ if (av->a_type == A_FLOAT)
+ {
+ int numkey;
+ if (loud_checkint((t_pd *)x, av->a_w.w_float, &numkey, s))
+ {
+ if (ep = collcommon_numkey(cc, numkey))
+ collcommon_adddata(cc, ep, ac-1, av+1);
+ else /* LATER consider defining collcommon_toclosest() */
+ collcommon_tonumkey(cc, numkey, ac-1, av+1, 1);
+ }
+ }
+ else if (av->a_type == A_SYMBOL)
+ {
+ if (ep = collcommon_symkey(cc, av->a_w.w_symbol))
+ collcommon_adddata(cc, ep, ac-1, av+1);
+ else
+ {
+ ep = collelem_new(ac-1, av+1, 0, av->a_w.w_symbol);
+ collcommon_putafter(cc, ep, cc->c_last);
+ }
+ }
+ else loud_messarg((t_pd *)x, s);
+ }
+ else loud_messarg((t_pd *)x, s);
+}
+
+static void coll_sub(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ t_collelem *ep;
+ if (ep = coll_findkey(x, av, s))
+ {
+ t_collcommon *cc = x->x_common;
+ t_atom *key = av++;
+ ac--;
+ while (ac >= 2)
+ {
+ if (av->a_type == A_FLOAT)
+ {
+ int ndx;
+ if (loud_checkint((t_pd *)x, av->a_w.w_float, &ndx, 0)
+ && ndx >= 1 && ndx <= ep->e_size)
+ ep->e_data[ndx-1] = av[1];
+ }
+ ac -= 2;
+ av += 2;
+ }
+ if (s == gensym("sub"))
+ {
+ coll_keyoutput(x, ep);
+ if (!cc->c_selfmodified || (ep = coll_findkey(x, key, 0)))
+ coll_dooutput(x, ep->e_size, ep->e_data);
+ }
+ }
+ }
+ else loud_messarg((t_pd *)x, s);
+}
+
+static void coll_sort(t_coll *x, t_floatarg f1, t_floatarg f2)
+{
+ int dir, ndx;
+ if (loud_checkint((t_pd *)x, f1, &dir, gensym("sort")) &&
+ loud_checkint((t_pd *)x, f2, &ndx, gensym("sort")))
+ collcommon_sort(x->x_common, (dir < 0 ? 1 : 0),
+ (ndx < 0 ? -1 : (ndx ? ndx - 1 : 0)));
+}
+
+static void coll_clear(t_coll *x)
+{
+ collcommon_clearall(x->x_common);
+}
+
+/* According to the refman, the data should be swapped, rather than the keys
+ -- easy here, but apparently c74 people have chosen to avoid some effort
+ needed in case of their implementation... */
+static void coll_swap(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac == 2)
+ {
+ t_collelem *ep1, *ep2;
+ if ((ep1 = coll_findkey(x, av, s)) &&
+ (ep2 = coll_findkey(x, av + 1, s)))
+ collcommon_swapkeys(x->x_common, ep1, ep2);
+ }
+ else loud_messarg((t_pd *)x, s);
+}
+
+static void coll_next(t_coll *x)
+{
+ t_collcommon *cc = x->x_common;
+ if (!cc->c_ahead && !(cc->c_ahead = cc->c_first))
+ return;
+ coll_keyoutput(x, cc->c_ahead);
+ if (cc->c_selfmodified && !cc->c_ahead)
+ return;
+ coll_dooutput(x, cc->c_ahead->e_size, cc->c_ahead->e_data);
+ /* LATER think why c74 updates the heads prior to sendout
+ (it seems so clumsy...) */
+ if (!cc->c_ahead && !(cc->c_ahead = cc->c_first))
+ {
+ cc->c_back = 0;
+ return;
+ }
+ if (cc->c_ahead->e_next)
+ {
+ cc->c_ahead = cc->c_ahead->e_next;
+ if (!(cc->c_back = cc->c_ahead->e_prev)) /* LATER rethink */
+ cc->c_back = cc->c_last;
+ }
+ else
+ {
+ /* CHECKED wraping */
+ cc->c_back = cc->c_ahead;
+ cc->c_ahead = 0;
+ }
+}
+
+static void coll_prev(t_coll *x)
+{
+ t_collcommon *cc = x->x_common;
+ if (!cc->c_back && !(cc->c_back = cc->c_last))
+ return;
+ coll_keyoutput(x, cc->c_back);
+ if (cc->c_selfmodified && !cc->c_back)
+ return;
+ coll_dooutput(x, cc->c_back->e_size, cc->c_back->e_data);
+ /* LATER think why c74 updates the heads prior to sendout
+ (it seems so clumsy...) */
+ if (!cc->c_back && !(cc->c_back = cc->c_last))
+ {
+ cc->c_ahead = 0;
+ return;
+ }
+ if (cc->c_back->e_prev)
+ {
+ cc->c_back = cc->c_back->e_prev;
+ if (!(cc->c_ahead = cc->c_back->e_next)) /* LATER rethink */
+ cc->c_ahead = cc->c_first;
+ }
+ else
+ {
+ /* CHECKED wraping */
+ cc->c_ahead = cc->c_back;
+ cc->c_back = 0;
+ }
+}
+
+static void coll_end(t_coll *x)
+{
+ t_collcommon *cc = x->x_common;
+ cc->c_back = cc->c_ahead = cc->c_last;
+}
+
+static void coll_goto(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ t_collelem *ep = coll_findkey(x, av, s);
+ if (ep)
+ x->x_common->c_back = x->x_common->c_ahead = ep;
+ }
+ else loud_messarg((t_pd *)x, s);
+}
+
+static void coll_nth(t_coll *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac >= 2 && av[1].a_type == A_FLOAT)
+ {
+ int ndx;
+ t_collelem *ep;
+ if (loud_checkint((t_pd *)x, av[1].a_w.w_float, &ndx, s) &&
+ (ep = coll_findkey(x, av, s)) &&
+ ep->e_size >= ndx)
+ {
+ t_atom *ap = ep->e_data + --ndx;
+ if (ap->a_type == A_FLOAT)
+ outlet_float(((t_object *)x)->ob_outlet, ap->a_w.w_float);
+ else if (ap->a_type == A_SYMBOL)
+ outlet_symbol(((t_object *)x)->ob_outlet, ap->a_w.w_symbol);
+ }
+ }
+ else loud_messarg((t_pd *)x, s);
+}
+
+static void coll_length(t_coll *x)
+{
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep = cc->c_first;
+ int result = 0;
+ while (ep) result++, ep = ep->e_next;
+ outlet_float(((t_object *)x)->ob_outlet, result);
+}
+
+static void coll_min(t_coll *x, t_floatarg f)
+{
+ int ndx;
+ if (loud_checkint((t_pd *)x, f, &ndx, gensym("min")))
+ {
+ t_collelem *found;
+ if (ndx <= 0)
+ ndx = 0; /* LATER consider complaining, CHECKME */
+ else ndx--;
+ if (found = coll_firsttyped(x, ndx, A_FLOAT))
+ {
+ t_float result = found->e_data[ndx].a_w.w_float;
+ t_collelem *ep;
+ for (ep = found->e_next; ep; ep = ep->e_next)
+ {
+ if (ep->e_size > ndx &&
+ ep->e_data[ndx].a_type == A_FLOAT &&
+ ep->e_data[ndx].a_w.w_float < result)
+ {
+ found = ep;
+ result = ep->e_data[ndx].a_w.w_float;
+ }
+ }
+ coll_keyoutput(x, found);
+ outlet_float(((t_object *)x)->ob_outlet, result);
+ }
+ }
+}
+
+static void coll_max(t_coll *x, t_floatarg f)
+{
+ int ndx;
+ if (loud_checkint((t_pd *)x, f, &ndx, gensym("max")))
+ {
+ t_collelem *found;
+ if (ndx <= 0)
+ ndx = 0; /* LATER consider complaining, CHECKME */
+ else ndx--;
+ if (found = coll_firsttyped(x, ndx, A_FLOAT))
+ {
+ t_float result = found->e_data[ndx].a_w.w_float;
+ t_collelem *ep;
+ for (ep = found->e_next; ep; ep = ep->e_next)
+ {
+ if (ep->e_size > ndx &&
+ ep->e_data[ndx].a_type == A_FLOAT &&
+ ep->e_data[ndx].a_w.w_float > result)
+ {
+ found = ep;
+ result = ep->e_data[ndx].a_w.w_float;
+ }
+ }
+ coll_keyoutput(x, found);
+ outlet_float(((t_object *)x)->ob_outlet, result);
+ }
+ }
+}
+
+static void coll_refer(t_coll *x, t_symbol *s)
+{
+ if (!coll_rebind(x, s))
+ {
+ /* LATER consider complaining */
+ }
+}
+
+static void coll_flags(t_coll *x, t_float f1, t_float f2)
+{
+ int i1;
+ if (loud_checkint((t_pd *)x, f1, &i1, gensym("flags")))
+ {
+ t_collcommon *cc = x->x_common;
+ cc->c_embedflag = (i1 != 0);
+ }
+}
+
+static void coll_read(t_coll *x, t_symbol *s)
+{
+ t_collcommon *cc = x->x_common;
+ if (s && s != &s_)
+ collcommon_doread(cc, s, x->x_canvas);
+ else
+ hammerpanel_open(cc->c_filehandle);
+}
+
+static void coll_write(t_coll *x, t_symbol *s)
+{
+ t_collcommon *cc = x->x_common;
+ if (s && s != &s_)
+ collcommon_dowrite(cc, s, x->x_canvas);
+ else
+ hammerpanel_save(cc->c_filehandle, 0, 0); /* CHECKME default name */
+}
+
+static void coll_readagain(t_coll *x)
+{
+ t_collcommon *cc = x->x_common;
+ if (cc->c_filename)
+ collcommon_doread(cc, 0, 0);
+ else
+ hammerpanel_open(cc->c_filehandle);
+}
+
+static void coll_writeagain(t_coll *x)
+{
+ t_collcommon *cc = x->x_common;
+ if (cc->c_filename)
+ collcommon_dowrite(cc, 0, 0);
+ else
+ hammerpanel_save(cc->c_filehandle, 0, 0); /* CHECKME default name */
+}
+
+static void coll_filetype(t_coll *x, t_symbol *s)
+{
+ /* dummy */
+}
+
+static void coll_dump(t_coll *x)
+{
+ t_collcommon *cc = x->x_common;
+ t_collelem *ep;
+ for (ep = cc->c_first; ep; ep = ep->e_next)
+ {
+ coll_keyoutput(x, ep);
+ if (cc->c_selfmodified)
+ break;
+ coll_dooutput(x, ep->e_size, ep->e_data);
+ }
+ outlet_bang(x->x_dumpbangout);
+}
+
+static void coll_open(t_coll *x)
+{
+ t_collcommon *cc = x->x_common;
+ t_binbuf *bb = binbuf_new();
+ int i, natoms, newline;
+ t_atom *ap;
+ char buf[MAXPDSTRING];
+ /* LATER prepend "coll: " */
+ hammereditor_open(cc->c_filehandle,
+ x->x_name ? x->x_name->s_name : "Untitled");
+ collcommon_tobinbuf(cc, bb);
+ natoms = binbuf_getnatom(bb);
+ ap = binbuf_getvec(bb);
+ newline = 1;
+ while (natoms--)
+ {
+ char *ptr = buf;
+ if (ap->a_type != A_SEMI && ap->a_type != A_COMMA && !newline)
+ *ptr++ = ' ';
+ atom_string(ap, ptr, MAXPDSTRING);
+ if (ap->a_type == A_SEMI)
+ {
+ strcat(buf, "\n");
+ newline = 1;
+ }
+ else newline = 0;
+ hammereditor_append(cc->c_filehandle, buf);
+ ap++;
+ }
+ binbuf_free(bb);
+}
+
+/* asking and storing the changes -- CHECKME close window, and 'wclose' */
+static void coll_wclose(t_coll *x)
+{
+ hammereditor_close(x->x_common->c_filehandle, 1);
+}
+
+static void coll_click(t_coll *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ coll_open(x);
+}
+
+#ifdef COLL_DEBUG
+static void coll_debug(t_coll *x, t_floatarg f)
+{
+ t_collcommon *cc = coll_checkcommon(x);
+ if (cc)
+ {
+ t_coll *x1 = cc->c_refs;
+ t_collelem *ep, *last;
+ int i = 0;
+ while (x1) i++, x1 = x1->x_next;
+ post("refcount %d", i);
+ for (ep = cc->c_first, last = 0; ep; ep = ep->e_next) last = ep;
+ if (last != cc->c_last) bug("coll_debug: last element");
+ collcommon_post(cc);
+ }
+}
+#endif
+
+static void coll_free(t_coll *x)
+{
+ hammerfile_free(x->x_filehandle);
+ coll_unbind(x);
+}
+
+static void *coll_new(t_symbol *s)
+{
+ t_coll *x = (t_coll *)pd_new(coll_class);
+ x->x_canvas = canvas_getcurrent();
+ outlet_new((t_object *)x, &s_);
+ x->x_keyout = outlet_new((t_object *)x, &s_);
+ x->x_filebangout = outlet_new((t_object *)x, &s_bang);
+ x->x_dumpbangout = outlet_new((t_object *)x, &s_bang);
+ x->x_filehandle = hammerfile_new((t_pd *)x, coll_embedhook, 0, 0, 0);
+ coll_bind(x, s);
+ return (x);
+}
+
+void coll_setup(void)
+{
+ coll_class = class_new(gensym("coll"),
+ (t_newmethod)coll_new,
+ (t_method)coll_free,
+ sizeof(t_coll), 0, A_DEFSYM, 0);
+ class_addbang(coll_class, coll_next);
+ class_addfloat(coll_class, coll_float);
+ class_addsymbol(coll_class, coll_symbol);
+ class_addlist(coll_class, coll_list);
+ class_addanything(coll_class, coll_anything);
+ class_addmethod(coll_class, (t_method)coll_store,
+ gensym("store"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_nstore,
+ gensym("nstore"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_insert,
+ gensym("insert"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_remove,
+ gensym("remove"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_delete,
+ gensym("delete"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_assoc,
+ gensym("assoc"), A_SYMBOL, A_FLOAT, 0);
+ class_addmethod(coll_class, (t_method)coll_deassoc,
+ gensym("deassoc"), A_SYMBOL, A_FLOAT, 0);
+ class_addmethod(coll_class, (t_method)coll_subsym,
+ gensym("subsym"), A_SYMBOL, A_SYMBOL, 0);
+ class_addmethod(coll_class, (t_method)coll_renumber,
+ gensym("renumber"), A_DEFFLOAT, 0);
+ class_addmethod(coll_class, (t_method)coll_merge,
+ gensym("merge"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_sub,
+ gensym("sub"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_sub,
+ gensym("nsub"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_clear,
+ gensym("clear"), 0);
+ class_addmethod(coll_class, (t_method)coll_sort,
+ gensym("sort"), A_FLOAT, A_DEFFLOAT, 0);
+ class_addmethod(coll_class, (t_method)coll_swap,
+ gensym("swap"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_next,
+ gensym("next"), 0);
+ class_addmethod(coll_class, (t_method)coll_prev,
+ gensym("prev"), 0);
+ class_addmethod(coll_class, (t_method)coll_end,
+ gensym("end"), 0);
+ class_addmethod(coll_class, (t_method)coll_goto,
+ gensym("goto"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_nth,
+ gensym("nth"), A_GIMME, 0);
+ class_addmethod(coll_class, (t_method)coll_length,
+ gensym("length"), 0);
+ class_addmethod(coll_class, (t_method)coll_min,
+ gensym("min"), A_DEFFLOAT, 0);
+ class_addmethod(coll_class, (t_method)coll_max,
+ gensym("max"), A_DEFFLOAT, 0);
+ class_addmethod(coll_class, (t_method)coll_refer,
+ gensym("refer"), A_SYMBOL, 0);
+ class_addmethod(coll_class, (t_method)coll_flags,
+ gensym("flags"), A_FLOAT, A_FLOAT, 0);
+ class_addmethod(coll_class, (t_method)coll_read,
+ gensym("read"), A_DEFSYM, 0);
+ class_addmethod(coll_class, (t_method)coll_write,
+ gensym("write"), A_DEFSYM, 0);
+ class_addmethod(coll_class, (t_method)coll_readagain,
+ gensym("readagain"), 0);
+ class_addmethod(coll_class, (t_method)coll_writeagain,
+ gensym("writeagain"), 0);
+ class_addmethod(coll_class, (t_method)coll_filetype,
+ gensym("filetype"), A_SYMBOL, 0);
+ class_addmethod(coll_class, (t_method)coll_dump,
+ gensym("dump"), 0);
+ class_addmethod(coll_class, (t_method)coll_open,
+ gensym("open"), 0);
+ class_addmethod(coll_class, (t_method)coll_wclose,
+ gensym("wclose"), 0);
+ class_addmethod(coll_class, (t_method)coll_click,
+ gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+#ifdef COLL_DEBUG
+ class_addmethod(coll_class, (t_method)coll_debug,
+ gensym("debug"), A_DEFFLOAT, 0);
+#endif
+ hammerfile_setup(coll_class, 1);
+ collcommon_class = class_new(gensym("coll"), 0, 0,
+ sizeof(t_collcommon), CLASS_PD, 0);
+ /* this call is a nop (collcommon does not embed, and the hammerfile
+ class itself has been already set up above), but it is better to
+ have it around, just in case... */
+ hammerfile_setup(collcommon_class, 0);
+}
diff --git a/cyclone/hammer/comment.c b/cyclone/hammer/comment.c
new file mode 100644
index 0000000..e5cd5ab
--- /dev/null
+++ b/cyclone/hammer/comment.c
@@ -0,0 +1,835 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* FIXME creation lag (X-specific) */
+/* LATER think about pushing text to the text editor (ctrl-t)
+ -- not easy, because we are not 'textedfor' */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "m_pd.h"
+#include "g_canvas.h"
+#include "common/loud.h"
+
+/* our proxy of the text_class (not in the API), LATER do not cheat */
+static t_class *makeshift_class;
+
+//#define COMMENT_DEBUG
+
+#define COMMENT_LMARGIN 1
+#define COMMENT_RMARGIN 1
+#define COMMENT_TMARGIN 2
+#define COMMENT_BMARGIN 2
+#define COMMENT_MINWIDTH 8
+#define COMMENT_HANDLEWIDTH 8
+#define COMMENT_OUTBUFSIZE 1000
+
+typedef struct _comment
+{
+ t_object x_ob;
+ t_glist *x_glist;
+ t_canvas *x_canvas; /* also an 'isvised' flag */
+ t_symbol *x_bindsym;
+ char x_tag[32];
+ char x_texttag[32];
+ char x_outlinetag[32];
+ t_clock *x_transclock;
+ t_binbuf *x_binbuf;
+ char *x_textbuf;
+ int x_textbufsize;
+ int x_pixwidth;
+ int x_bbset;
+ int x_bbpending;
+ int x_x1;
+ int x_y1;
+ int x_x2;
+ int x_y2;
+ int x_newx2;
+ int x_dragon;
+ int x_fontsize; /* requested size */
+ t_symbol *x_fontfamily; /* requested family */
+ int x_fontprops; /* LATER pack weight and slant */
+ t_symbol *x_encoding; /* requested encoding */
+ unsigned char x_red;
+ unsigned char x_green;
+ unsigned char x_blue;
+ char x_color[8];
+ int x_selstart;
+ int x_selend;
+ int x_active;
+ int x_ready;
+} t_comment;
+
+static t_class *comment_class;
+static t_class *commentsink_class;
+
+static t_pd *commentsink = 0;
+
+static void comment_draw(t_comment *x)
+{
+ char buf[COMMENT_OUTBUFSIZE], *outbuf, *outp;
+ int cvid = (int)x->x_canvas;
+ int reqsize = x->x_textbufsize + 350; /* FIXME estimation */
+ if (reqsize > COMMENT_OUTBUFSIZE)
+ {
+#ifdef COMMENT_DEBUG
+ post("allocating %d outbuf bytes", reqsize);
+#endif
+ if (!(outbuf = getbytes(reqsize)))
+ return;
+ }
+ else outbuf = buf;
+ outp = outbuf;
+ if (x->x_encoding)
+ sprintf(outp, "set tt [comment_entext %s {%.*s}]\n",
+ x->x_encoding->s_name, x->x_textbufsize, x->x_textbuf);
+ else
+ sprintf(outp, "set tt {%.*s}\n", x->x_textbufsize, x->x_textbuf);
+ outp += strlen(outp);
+ sprintf(outp, ".x%x.c create text %f %f -text $tt \
+ -tags {%s %s} -font {%s %d} -fill %s", cvid,
+ (float)(text_xpix((t_text *)x, x->x_glist) + COMMENT_LMARGIN),
+ (float)(text_ypix((t_text *)x, x->x_glist) + COMMENT_TMARGIN),
+ x->x_texttag, x->x_tag, x->x_fontfamily->s_name, x->x_fontsize,
+ (glist_isselected(x->x_glist, &x->x_glist->gl_gobj) ?
+ "blue" : x->x_color));
+ outp += strlen(outp);
+ if (x->x_pixwidth)
+ sprintf(outp, " -width %d -anchor nw\n", x->x_pixwidth);
+ else
+ strcpy(outp, " -anchor nw\n");
+ outp += strlen(outp);
+ sprintf(outp, "comment_bbox %s .x%x.c %s\n",
+ x->x_bindsym->s_name, cvid, x->x_texttag);
+ outp += strlen(outp);
+ sprintf(outp, ".x%x.c bind %s <Button> {comment_click %s %%W %%x %%y %s}\n",
+ cvid, x->x_texttag, x->x_bindsym->s_name, x->x_texttag);
+ x->x_bbpending = 1;
+ sys_gui(outbuf);
+ if (outbuf != buf) freebytes(outbuf, reqsize);
+}
+
+static void comment_update(t_comment *x)
+{
+ char buf[COMMENT_OUTBUFSIZE], *outbuf, *outp;
+ int cvid = (int)x->x_canvas;
+ int reqsize = x->x_textbufsize + 250; /* FIXME estimation */
+ if (reqsize > COMMENT_OUTBUFSIZE)
+ {
+#ifdef COMMENT_DEBUG
+ post("allocating %d outbuf bytes", reqsize);
+#endif
+ if (!(outbuf = getbytes(reqsize)))
+ return;
+ }
+ else outbuf = buf;
+ outp = outbuf;
+ if (x->x_encoding)
+ sprintf(outp, "set tt [comment_entext %s {%.*s}]\n",
+ x->x_encoding->s_name, x->x_textbufsize, x->x_textbuf);
+ else
+ sprintf(outp, "set tt {%.*s}\n", x->x_textbufsize, x->x_textbuf);
+ outp += strlen(outp);
+ if (x->x_pixwidth)
+ sprintf(outp, ".x%x.c itemconfig %s -text $tt -width %d\n",
+ cvid, x->x_texttag, x->x_pixwidth);
+ else
+ sprintf(outp, ".x%x.c itemconfig %s -text $tt\n", cvid, x->x_texttag);
+ outp += strlen(outp);
+ if (x->x_active)
+ {
+ if (x->x_selend > x->x_selstart)
+ {
+ sprintf(outp, ".x%x.c select from %s %d\n",
+ cvid, x->x_texttag, x->x_selstart);
+ outp += strlen(outp);
+ sprintf(outp, ".x%x.c select to %s %d\n",
+ cvid, x->x_texttag, x->x_selend);
+ outp += strlen(outp);
+ sprintf(outp, ".x%x.c focus {}\n", cvid);
+ }
+ else
+ {
+ sprintf(outp, ".x%x.c select clear\n", cvid);
+ outp += strlen(outp);
+ sprintf(outp, ".x%x.c icursor %s %d\n",
+ cvid, x->x_texttag, x->x_selstart);
+ outp += strlen(outp);
+ sprintf(outp, ".x%x.c focus %s\n", cvid, x->x_texttag);
+ }
+ outp += strlen(outp);
+ }
+ sprintf(outp, "comment_bbox %s .x%x.c %s\n",
+ x->x_bindsym->s_name, cvid, x->x_texttag);
+ x->x_bbpending = 1;
+ sys_gui(outbuf);
+ if (outbuf != buf) freebytes(outbuf, reqsize);
+}
+
+static void comment_validate(t_comment *x, t_glist *glist)
+{
+ if (!x->x_ready)
+ {
+ t_text *t = (t_text *)x;
+ binbuf_free(t->te_binbuf);
+ t->te_binbuf = x->x_binbuf;
+ if (x->x_textbuf) freebytes(x->x_textbuf, x->x_textbufsize);
+ binbuf_gettext(x->x_binbuf, &x->x_textbuf, &x->x_textbufsize);
+ x->x_ready = 1;
+#ifdef COMMENT_DEBUG
+ post("validation done");
+#endif
+ }
+ if (glist)
+ {
+ if (glist != x->x_glist)
+ {
+ bug("comment_getcanvas");
+ x->x_glist = glist;
+ }
+ x->x_canvas = glist_getcanvas(glist);
+ }
+}
+
+static void comment_grabbedkey(void *z, t_floatarg f)
+{
+ /* LATER think about replacing #key binding/comment_float() with grabbing */
+}
+
+static void comment_dograb(t_comment *x)
+{
+ /* LATER investigate the grabbing feature.
+ Here we use it just to prevent backspace from erasing entire text.
+ This has to be done also when we are already active, because
+ after being clicked at we have lost our previous grab. */
+ glist_grab(x->x_glist, (t_gobj *)x, 0, comment_grabbedkey, 0, 0);
+}
+
+static void comment__bboxhook(t_comment *x, t_symbol *bindsym,
+ t_floatarg x1, t_floatarg y1,
+ t_floatarg x2, t_floatarg y2)
+{
+#ifdef COMMENT_DEBUG
+ post("bbox %g %g %g %g", x1, y1, x2, y2);
+#endif
+ x->x_x1 = x1;
+ x->x_y1 = y1;
+ x->x_x2 = x2;
+ x->x_y2 = y2;
+ x->x_bbset = 1;
+ x->x_bbpending = 0;
+}
+
+static void comment__clickhook(t_comment *x, t_symbol *s, int ac, t_atom *av)
+{
+ int xx, yy, ndx;
+ if (ac == 8 && av->a_type == A_SYMBOL
+ && av[1].a_type == A_FLOAT && av[2].a_type == A_FLOAT
+ && av[3].a_type == A_FLOAT
+ && av[4].a_type == A_FLOAT && av[5].a_type == A_FLOAT
+ && av[6].a_type == A_FLOAT && av[7].a_type == A_FLOAT)
+ {
+ xx = (int)av[1].a_w.w_float;
+ yy = (int)av[2].a_w.w_float;
+ ndx = (int)av[3].a_w.w_float;
+ comment__bboxhook(x, av->a_w.w_symbol,
+ av[4].a_w.w_float, av[5].a_w.w_float,
+ av[6].a_w.w_float, av[7].a_w.w_float);
+ }
+ else
+ {
+ bug("comment__clickhook");
+ return;
+ }
+ if (x->x_glist->gl_edit)
+ {
+ if (x->x_active)
+ {
+ if (ndx >= 0 && ndx < x->x_textbufsize)
+ {
+ /* set selection, LATER shift-click and drag */
+ x->x_selstart = x->x_selend = ndx;
+ comment_dograb(x);
+ comment_update(x);
+ }
+ }
+ else if (xx > x->x_x2 - COMMENT_HANDLEWIDTH)
+ {
+ /* start resizing */
+ char buf[COMMENT_OUTBUFSIZE], *outp = buf;
+ int cvid = (int)x->x_canvas;
+ sprintf(outp, ".x%x.c bind %s <ButtonRelease> \
+ {pd [concat %s _release %s \\;]}\n", cvid, x->x_texttag,
+ x->x_bindsym->s_name, x->x_bindsym->s_name);
+ outp += strlen(outp);
+ sprintf(outp, ".x%x.c bind %s <Motion> \
+ {pd [concat %s _motion %s %%x %%y \\;]}\n", cvid, x->x_texttag,
+ x->x_bindsym->s_name, x->x_bindsym->s_name);
+ outp += strlen(outp);
+ sprintf(outp, ".x%x.c create rectangle %d %d %d %d -outline blue \
+ -tags {%s %s}\n",
+ cvid, x->x_x1, x->x_y1, x->x_x2, x->x_y2,
+ x->x_outlinetag, x->x_tag);
+ sys_gui(buf);
+ x->x_newx2 = x->x_x2;
+ x->x_dragon = 1;
+ }
+ }
+}
+
+static void comment__releasehook(t_comment *x, t_symbol *bindsym)
+{
+ int cvid = (int)x->x_canvas;
+ sys_vgui(".x%x.c bind %s <ButtonRelease> {}\n", cvid, x->x_texttag);
+ sys_vgui(".x%x.c bind %s <Motion> {}\n", cvid, x->x_texttag);
+ sys_vgui(".x%x.c delete %s\n", cvid, x->x_outlinetag);
+ x->x_dragon = 0;
+ if (x->x_newx2 != x->x_x2)
+ {
+ x->x_pixwidth = x->x_newx2 - x->x_x1;
+ x->x_x2 = x->x_newx2;
+ comment_update(x);
+ }
+}
+
+static void comment__motionhook(t_comment *x, t_symbol *bindsym,
+ t_floatarg xx, t_floatarg yy)
+{
+ int cvid = (int)x->x_canvas;
+ if (xx > x->x_x1 + COMMENT_MINWIDTH)
+ sys_vgui(".x%x.c coords %s %d %d %d %d\n",
+ cvid, x->x_outlinetag,
+ x->x_x1, x->x_y1, x->x_newx2 = xx, x->x_y2);
+}
+
+static void commentsink__bboxhook(t_pd *x, t_symbol *bindsym,
+ t_floatarg x1, t_floatarg y1,
+ t_floatarg x2, t_floatarg y2)
+{
+ if (bindsym->s_thing == x) /* is the comment gone? */
+ {
+ pd_unbind(x, bindsym); /* if so, no need for this binding anymore */
+#ifdef COMMENT_DEBUG
+ post("sink: %s unbound", bindsym->s_name);
+#endif
+ }
+}
+
+static void commentsink_anything(t_pd *x, t_symbol *s, int ac, t_atom *av)
+{
+ /* nop */
+}
+
+static void comment_getrect(t_gobj *z, t_glist *glist,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_comment *x = (t_comment *)z;
+ if (!glist->gl_havewindow)
+ {
+ /* LATER revisit gop behaviour. Currently text_shouldvis() returns
+ true if we are on parent. Here we return a null rectangle,
+ so that any true ui object is accessible, even if it happens
+ to be covered by a comment. */
+ *xp1 = *yp1 = *xp2 = *yp2 = 0;
+ return;
+ }
+ if (x->x_bbset)
+ {
+ /* LATER think about margins */
+ *xp1 = x->x_x1;
+ *yp1 = x->x_y1;
+ *xp2 = x->x_x2;
+ *yp2 = x->x_y2;
+ }
+ else
+ {
+ int width, height;
+ float x1, y1, x2, y2;
+ comment_validate(x, glist);
+ if ((width = x->x_pixwidth) < 1)
+ /* FIXME estimation */
+ width = x->x_fontsize * x->x_textbufsize;
+ width += COMMENT_LMARGIN + COMMENT_RMARGIN;
+ /* FIXME estimation */
+ height = x->x_fontsize + COMMENT_TMARGIN + COMMENT_BMARGIN;
+ x1 = text_xpix((t_text *)x, glist);
+ y1 = text_ypix((t_text *)x, glist) + 1; /* LATER revisit */
+ x2 = x1 + width;
+ y2 = y1 + height - 2; /* LATER revisit */
+#ifdef COMMENT_DEBUG
+ post("estimated rectangle: %g %g %g %g", x1, y1, x2, y2);
+#endif
+ *xp1 = x1;
+ *yp1 = y1;
+ *xp2 = x2;
+ *yp2 = y2;
+ }
+}
+
+static void comment_displace(t_gobj *z, t_glist *glist, int dx, int dy)
+{
+ t_comment *x = (t_comment *)z;
+ if (!x->x_active && !x->x_dragon) /* LATER rethink */
+ {
+ t_text *t = (t_text *)z;
+ comment_validate(x, glist);
+ t->te_xpix += dx;
+ t->te_ypix += dy;
+ if (x->x_bbset)
+ {
+ x->x_x1 += dx;
+ x->x_y1 += dy;
+ x->x_x2 += dx;
+ x->x_y2 += dy;
+ }
+ if (glist_isvisible(glist))
+ sys_vgui(".x%x.c move %s %d %d\n", x->x_canvas, x->x_tag, dx, dy);
+ }
+}
+
+static void comment_activate(t_gobj *z, t_glist *glist, int state)
+{
+ t_comment *x = (t_comment *)z;
+ comment_validate(x, glist);
+ if (state)
+ {
+ comment_dograb(x);
+ if (x->x_active)
+ return;
+ sys_vgui(".x%x.c focus %s\n", x->x_canvas, x->x_texttag);
+ x->x_selstart = 0;
+ x->x_selend = x->x_textbufsize;
+ x->x_active = 1;
+ pd_bind((t_pd *)x, gensym("#key"));
+ pd_bind((t_pd *)x, gensym("#keyname"));
+ }
+ else
+ {
+ if (!x->x_active)
+ return;
+ pd_unbind((t_pd *)x, gensym("#key"));
+ pd_unbind((t_pd *)x, gensym("#keyname"));
+ sys_vgui("selection clear .x%x.c\n", x->x_canvas);
+ sys_vgui(".x%x.c focus {}\n", x->x_canvas);
+ x->x_active = 0;
+ }
+ comment_update(x);
+}
+
+static void comment_select(t_gobj *z, t_glist *glist, int state)
+{
+ t_comment *x = (t_comment *)z;
+ comment_validate(x, glist);
+ if (!state && x->x_active) comment_activate(z, glist, 0);
+ sys_vgui(".x%x.c itemconfigure %s -fill %s\n", x->x_canvas,
+ x->x_texttag, (state ? "blue" : x->x_color));
+ /* A regular rtext should now set 'canvas_editing' variable to its canvas,
+ but we do not do that, because we get the keys through a global binding
+ to "#key" (and because 'canvas_editing' is not exported). */
+}
+
+static void comment_vis(t_gobj *z, t_glist *glist, int vis)
+{
+ t_comment *x = (t_comment *)z;
+ t_text *t = (t_text *)z;
+ comment_validate(x, glist);
+ if (vis)
+ {
+ /* We do not need no rtext -- we are never 'textedfor' (thus
+ avoiding rtext calls). Creating an rtext has no other purpose
+ than complying to a Pd's assumption about every visible object
+ having an rtext (thus preventing canvas_doclick() from sending
+ garbage warnings). LATER revisit. */
+#ifndef PD_MINOR_VERSION
+ rtext_new(glist, t, glist->gl_editor->e_rtext, 0);
+#endif
+ if (glist->gl_havewindow)
+ comment_draw(x);
+ }
+ else
+ {
+#ifndef PD_MINOR_VERSION
+ t_rtext *rt = glist_findrtext(glist, t);
+ if (rt) rtext_free(rt);
+#endif
+ /* FIXME should we test for having a window? */
+#ifdef COMMENT_DEBUG
+ post("deleting...");
+#endif
+ sys_vgui(".x%x.c delete %s\n", x->x_canvas, x->x_tag);
+ }
+}
+
+static void comment_save(t_gobj *z, t_binbuf *b)
+{
+ t_comment *x = (t_comment *)z;
+ t_text *t = (t_text *)x;
+ comment_validate(x, 0);
+ binbuf_addv(b, "ssiisiissiiii", gensym("#X"), gensym("obj"),
+ (int)t->te_xpix, (int)t->te_ypix,
+ gensym("comment"),
+ x->x_pixwidth, x->x_fontsize, x->x_fontfamily,
+ (x->x_encoding ? x->x_encoding : gensym("?")),
+ x->x_fontprops,
+ (int)x->x_red, (int)x->x_green, (int)x->x_blue);
+ binbuf_addbinbuf(b, t->te_binbuf);
+ binbuf_addv(b, ";");
+}
+
+static t_widgetbehavior comment_widgetbehavior =
+{
+ comment_getrect,
+ comment_displace,
+ comment_select,
+ comment_activate,
+ 0,
+ comment_vis,
+ 0,
+ comment_save,
+ 0,
+};
+
+/* this fires if a transform request was sent to a symbol we are bound to */
+static void comment_transtick(t_comment *x)
+{
+ glist_delete(x->x_glist, (t_gobj *)x);
+}
+
+/* what follows is basically the original code of rtext_key() */
+
+static void comment_float(t_comment *x, t_float f)
+{
+ if (x->x_active)
+ {
+ int keynum = (int)f;
+ if (keynum)
+ {
+ int i, newsize, ndel;
+ char *s1, *s2;
+ int n = keynum;
+ if (n == '\r') n = '\n';
+ if (n == '\b')
+ {
+ if ((!x->x_selstart) && (x->x_selend == x->x_textbufsize))
+ {
+ /* LATER delete the box... this causes reentrancy
+ problems now. */
+ /* glist_delete(x->x_glist, &x->x_text->te_g); */
+ return;
+ }
+ else if (x->x_selstart && (x->x_selstart == x->x_selend))
+ x->x_selstart--;
+ }
+ ndel = x->x_selend - x->x_selstart;
+ for (i = x->x_selend; i < x->x_textbufsize; i++)
+ x->x_textbuf[i- ndel] = x->x_textbuf[i];
+ newsize = x->x_textbufsize - ndel;
+ x->x_textbuf = resizebytes(x->x_textbuf, x->x_textbufsize, newsize);
+ x->x_textbufsize = newsize;
+
+ if (n == '\n' || !iscntrl(n))
+ {
+#ifdef COMMENT_DEBUG
+ post("%d accepted", n);
+#endif
+ newsize = x->x_textbufsize+1;
+ x->x_textbuf = resizebytes(x->x_textbuf,
+ x->x_textbufsize, newsize);
+ for (i = x->x_textbufsize; i > x->x_selstart; i--)
+ x->x_textbuf[i] = x->x_textbuf[i-1];
+ x->x_textbuf[x->x_selstart] = n;
+ x->x_textbufsize = newsize;
+ x->x_selstart = x->x_selstart + 1;
+ }
+#ifdef COMMENT_DEBUG
+ else post("%d rejected", n);
+#endif
+ x->x_selend = x->x_selstart;
+ x->x_glist->gl_editor->e_textdirty = 1;
+ binbuf_text(x->x_binbuf, x->x_textbuf, x->x_textbufsize);
+ comment_update(x);
+ }
+ }
+ else bug("comment_float");
+}
+
+static void comment_list(t_comment *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (!x->x_active)
+ bug("comment_list");
+ else if (ac > 1 && av->a_type == A_FLOAT && (int)av->a_w.w_float
+ && av[1].a_type == A_SYMBOL)
+ {
+ t_symbol *keysym = av[1].a_w.w_symbol;
+ if (!strcmp(keysym->s_name, "Right"))
+ {
+ if (x->x_selend == x->x_selstart &&
+ x->x_selstart < x->x_textbufsize)
+ x->x_selend = x->x_selstart = x->x_selstart + 1;
+ else
+ x->x_selstart = x->x_selend;
+ }
+ else if (!strcmp(keysym->s_name, "Left"))
+ {
+ if (x->x_selend == x->x_selstart && x->x_selstart > 0)
+ x->x_selend = x->x_selstart = x->x_selstart - 1;
+ else
+ x->x_selend = x->x_selstart;
+ }
+ /* this should be improved... life's too short */
+ else if (!strcmp(keysym->s_name, "Up"))
+ {
+ if (x->x_selstart)
+ x->x_selstart--;
+ while (x->x_selstart > 0 && x->x_textbuf[x->x_selstart] != '\n')
+ x->x_selstart--;
+ x->x_selend = x->x_selstart;
+ }
+ else if (!strcmp(keysym->s_name, "Down"))
+ {
+ while (x->x_selend < x->x_textbufsize &&
+ x->x_textbuf[x->x_selend] != '\n')
+ x->x_selend++;
+ if (x->x_selend < x->x_textbufsize)
+ x->x_selend++;
+ x->x_selstart = x->x_selend;
+ }
+ else if (!strcmp(keysym->s_name, "F4"))
+ {
+ t_text *newt, *oldt = (t_text *)x;
+ t_binbuf *bb = binbuf_new();
+ int ac = binbuf_getnatom(x->x_binbuf);
+ binbuf_addv(bb, "siissiiii", gensym("comment"), x->x_pixwidth,
+ x->x_fontsize, x->x_fontfamily,
+ (x->x_encoding ? x->x_encoding : gensym("?")),
+ x->x_fontprops,
+ (int)x->x_red, (int)x->x_green, (int)x->x_blue);
+ binbuf_add(bb, ac, binbuf_getvec(x->x_binbuf));
+ canvas_setcurrent(x->x_glist);
+ newt = (t_text *)pd_new(makeshift_class);
+ newt->te_width = 0;
+ newt->te_type = T_OBJECT;
+ newt->te_binbuf = bb;
+ newt->te_xpix = oldt->te_xpix;
+ newt->te_ypix = oldt->te_ypix;
+ glist_add(x->x_glist, &newt->te_g);
+ glist_noselect(x->x_glist);
+ glist_select(x->x_glist, &newt->te_g);
+ gobj_activate(&newt->te_g, x->x_glist, 1);
+ x->x_glist->gl_editor->e_textdirty = 1; /* force evaluation */
+ canvas_unsetcurrent(x->x_glist);
+ canvas_dirty(x->x_glist, 1);
+ clock_delay(x->x_transclock, 0); /* LATER rethink */
+ return;
+ }
+ else if (!strcmp(keysym->s_name, "F5"))
+ {
+ t_text *t = (t_text *)x;
+ t_binbuf *bb = binbuf_new();
+ int ac = binbuf_getnatom(x->x_binbuf);
+ binbuf_addv(bb, "ii", (int)t->te_xpix + 5, (int)t->te_ypix + 5);
+ binbuf_add(bb, ac, binbuf_getvec(x->x_binbuf));
+ canvas_setcurrent(x->x_glist);
+ typedmess((t_pd *)x->x_glist, gensym("text"),
+ ac + 2, binbuf_getvec(bb));
+ canvas_unsetcurrent(x->x_glist);
+ canvas_dirty(x->x_glist, 1);
+ binbuf_free(bb);
+ return;
+ }
+ else return;
+ comment_update(x);
+ }
+}
+
+static void comment_free(t_comment *x)
+{
+ if (x->x_active)
+ {
+ bug("comment_free");
+ pd_unbind((t_pd *)x, gensym("#key"));
+ pd_unbind((t_pd *)x, gensym("#keyname"));
+ }
+ if (x->x_transclock) clock_free(x->x_transclock);
+ if (x->x_bindsym)
+ {
+ pd_unbind((t_pd *)x, x->x_bindsym);
+ if (!x->x_bbpending)
+ pd_unbind(commentsink, x->x_bindsym);
+ }
+ if (x->x_binbuf && !x->x_ready) binbuf_free(x->x_binbuf);
+ if (x->x_textbuf) freebytes(x->x_textbuf, x->x_textbufsize);
+}
+
+/* the arguments in the full form of a creation message are:
+
+ width fontsize fontfamily encoding fontprops red green blue text...
+
+ For comments typed into an object box, the text part begins with
+ the first atom satisfying one of the following conditions (skipped
+ arguments get default values):
+
+ . having a different type than the corresponding argument of the
+ full form
+
+ . being preceded with a dot atom ('.') put in place of a symbol
+ argument (fontfamily or encoding)
+
+ . being the 10th atom in a box
+
+ The question mark atom ('?') may be used to supply a default fontfamily
+ or an empty encoding value.
+*/
+
+static void *comment_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_comment *x = (t_comment *)pd_new(comment_class);
+ t_text *t = (t_text *)x;
+ t_atom at;
+ char buf[32];
+ t->te_type = T_TEXT;
+ x->x_glist = canvas_getcurrent();
+ x->x_canvas = 0;
+ sprintf(x->x_tag, "all%x", (int)x);
+ sprintf(x->x_texttag, "t%x", (int)x);
+ sprintf(x->x_outlinetag, "h%x", (int)x);
+ x->x_pixwidth = 0;
+ x->x_fontsize = 0;
+ x->x_fontfamily = 0;
+ x->x_encoding = 0;
+ x->x_fontprops = 0;
+ x->x_red = 0;
+ x->x_green = 0;
+ x->x_blue = 0;
+
+ if (ac && av->a_type == A_FLOAT)
+ {
+ x->x_pixwidth = (int)av->a_w.w_float;
+ ac--; av++;
+ if (ac && av->a_type == A_FLOAT)
+ {
+ x->x_fontsize = (int)av->a_w.w_float;
+ ac--; av++;
+ if (ac && av->a_type == A_SYMBOL)
+ {
+ if (av->a_w.w_symbol == gensym("."))
+ {
+ ac--; av++;
+ goto textpart;
+ }
+ else if (av->a_w.w_symbol != gensym("?"))
+ x->x_fontfamily = av->a_w.w_symbol;
+ ac--; av++;
+ if (ac && av->a_type == A_SYMBOL)
+ {
+ if (av->a_w.w_symbol == gensym("."))
+ {
+ ac--; av++;
+ goto textpart;
+ }
+ else if (av->a_w.w_symbol != gensym("?"))
+ x->x_encoding = av->a_w.w_symbol;
+ ac--; av++;
+ if (ac && av->a_type == A_FLOAT)
+ {
+ x->x_fontprops = (int)av->a_w.w_float;
+ ac--; av++;
+ if (ac && av->a_type == A_FLOAT)
+ {
+ x->x_red = (unsigned char)av->a_w.w_float;
+ ac--; av++;
+ if (ac && av->a_type == A_FLOAT)
+ {
+ x->x_green = (unsigned char)av->a_w.w_float;
+ ac--; av++;
+ if (ac && av->a_type == A_FLOAT)
+ {
+ x->x_blue = (unsigned char)av->a_w.w_float;
+ ac--; av++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+textpart:
+ if (x->x_fontsize < 1)
+ x->x_fontsize = glist_getfont(x->x_glist);
+ if (!x->x_fontfamily)
+ x->x_fontfamily = gensym("helvetica");
+ sprintf(x->x_color, "#%2.2x%2.2x%2.2x", x->x_red, x->x_green, x->x_blue);
+
+ x->x_binbuf = binbuf_new();
+ if (ac) binbuf_restore(x->x_binbuf, ac, av);
+ else
+ {
+ SETSYMBOL(&at, gensym("comment"));
+ binbuf_restore(x->x_binbuf, 1, &at);
+ }
+ x->x_textbuf = 0;
+ x->x_textbufsize = 0;
+ x->x_transclock = clock_new(x, (t_method)comment_transtick);
+ x->x_bbset = 0;
+ x->x_bbpending = 0;
+ sprintf(buf, "miXed%x", (int)x);
+ x->x_bindsym = gensym(buf);
+ pd_bind((t_pd *)x, x->x_bindsym);
+ if (!commentsink)
+ commentsink = pd_new(commentsink_class);
+ pd_bind(commentsink, x->x_bindsym);
+ x->x_ready = 0;
+ x->x_dragon = 0;
+ return (x);
+}
+
+void comment_setup(void)
+{
+ comment_class = class_new(gensym("comment"),
+ (t_newmethod)comment_new,
+ (t_method)comment_free,
+ sizeof(t_comment),
+ CLASS_NOINLET | CLASS_PATCHABLE,
+ A_GIMME, 0);
+ class_addfloat(comment_class, comment_float);
+ class_addlist(comment_class, comment_list);
+ class_addmethod(comment_class, (t_method)comment__bboxhook,
+ gensym("_bbox"),
+ A_SYMBOL, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(comment_class, (t_method)comment__clickhook,
+ gensym("_click"), A_GIMME, 0);
+ class_addmethod(comment_class, (t_method)comment__releasehook,
+ gensym("_release"), A_SYMBOL, 0);
+ class_addmethod(comment_class, (t_method)comment__motionhook,
+ gensym("_motion"), A_SYMBOL, A_FLOAT, A_FLOAT, 0);
+ class_setwidget(comment_class, &comment_widgetbehavior);
+
+ makeshift_class = class_new(gensym("text"), 0, 0,
+ sizeof(t_text),
+ CLASS_NOINLET | CLASS_PATCHABLE, 0);
+
+ commentsink_class = class_new(gensym("_commentsink"), 0, 0,
+ sizeof(t_pd), CLASS_PD, 0);
+ class_addanything(commentsink_class, commentsink_anything);
+ class_addmethod(commentsink_class, (t_method)commentsink__bboxhook,
+ gensym("_bbox"),
+ A_SYMBOL, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+
+ sys_gui("proc comment_bbox {target cvname tag} {\n\
+ pd $target _bbox $target [$cvname bbox $tag]\\;}\n");
+
+ /* LATER think about window vs canvas coords */
+ sys_gui("proc comment_click {target cvname x y tag} {\n\
+ pd $target _click $target [$cvname canvasx $x] [$cvname canvasy $y]\
+ [$cvname index $tag @$x,$y] [$cvname bbox $tag]\\;}\n");
+
+ sys_gui("proc comment_entext {enc tt} {\n\
+ set rr [catch {encoding convertfrom $enc $tt} tt1]\n\
+ if {$rr == 0} {concat $tt1} else {\n\
+ puts stderr [concat tcl/tk error: $tt1]\n\
+ concat $tt}}\n");
+}
diff --git a/cyclone/hammer/cosh.c b/cyclone/hammer/cosh.c
new file mode 100644
index 0000000..77d1567
--- /dev/null
+++ b/cyclone/hammer/cosh.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define coshf cosh
+#endif
+
+typedef struct _cosh
+{
+ t_object x_ob;
+ float x_value;
+} t_cosh;
+
+static t_class *cosh_class;
+
+static void cosh_bang(t_cosh *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+}
+
+static void cosh_float(t_cosh *x, t_float f)
+{
+ /* CHECKME large values */
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value = coshf(f));
+}
+
+static void *cosh_new(t_floatarg f)
+{
+ t_cosh *x = (t_cosh *)pd_new(cosh_class);
+ /* CHECKME large values */
+ x->x_value = coshf(f);
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void cosh_setup(void)
+{
+ cosh_class = class_new(gensym("cosh"),
+ (t_newmethod)cosh_new, 0,
+ sizeof(t_cosh), 0, A_DEFFLOAT, 0);
+ class_addbang(cosh_class, cosh_bang);
+ class_addfloat(cosh_class, cosh_float);
+}
diff --git a/cyclone/hammer/counter.c b/cyclone/hammer/counter.c
new file mode 100644
index 0000000..3117e6c
--- /dev/null
+++ b/cyclone/hammer/counter.c
@@ -0,0 +1,399 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* This is an entirely rewritten version of Joseph A. Sarlo's code.
+ The most important changes are listed in "pd-lib-notes.txt" file. */
+
+/* Beware -- the max reference manual page for the counter object
+ reflects mostly opcode max features. Apparently counter works
+ differently in cycling max (e.g. inlets 3 and 4). But I am sick
+ of checking -- I will not bother, until there is some feedback. */
+
+#include "m_pd.h"
+
+#define COUNTER_UP 0
+#define COUNTER_DOWN 1
+#define COUNTER_UPDOWN 2
+#define COUNTER_DEFMAX 0x7fffffff /* CHECKED (man says otherwise) */
+
+typedef struct _counter
+{
+ t_object x_ob;
+ int x_count;
+ int x_maxcount;
+ int x_dir;
+ int x_inc;
+ int x_min;
+ int x_max;
+ int x_carrybang;
+ int x_minhitflag;
+ int x_maxhitflag;
+ t_pd *x_proxies[4];
+ t_outlet *x_out2;
+ t_outlet *x_out3;
+ t_outlet *x_out4;
+} t_counter;
+
+typedef struct _counter_proxy
+{
+ t_object p_ob;
+ t_counter *p_master;
+ void (*p_bangmethod)(t_counter *x);
+ void (*p_floatmethod)(t_counter *x, t_float f);
+} t_counter_proxy;
+
+static t_class *counter_class;
+static t_class *counter_proxy_class;
+
+static void counter_up(t_counter *x)
+{
+ x->x_dir = COUNTER_UP;
+ x->x_inc = 1;
+}
+
+static void counter_down(t_counter *x)
+{
+ /* CHECKED: no explicit minimum needed */
+ x->x_dir = COUNTER_DOWN;
+ x->x_inc = -1;
+}
+
+static void counter_updown(t_counter *x)
+{
+ /* CHECKED: neither explicit maximum, nor minimum needed */
+ x->x_dir = COUNTER_UPDOWN;
+ /* CHECKED: x->x_inc unchanged (continuation) */
+}
+
+static void counter_dir(t_counter *x, t_floatarg f)
+{
+ switch ((int)f)
+ {
+ case COUNTER_UP:
+ counter_up(x);
+ break;
+ case COUNTER_DOWN:
+ counter_down(x);
+ break;
+ case COUNTER_UPDOWN:
+ counter_updown(x);
+ break;
+ default:
+ counter_up(x); /* CHECKED: invalid == default */
+ /* CHECKED: no warning */
+ }
+}
+
+static void counter_dobang(t_counter *x, int notjam)
+{
+ int offmin = 0, offmax = 0, onmin = 0, onmax = 0;
+ /* CHECKED: carry-off is not sent if min >= max */
+ /* LATER rethink (this is a hack) */
+ if (x->x_min < x->x_max)
+ offmin = x->x_minhitflag, offmax = x->x_maxhitflag;
+ x->x_minhitflag = x->x_maxhitflag = 0;
+
+ if (x->x_count < x->x_min)
+ {
+ if (x->x_inc == 1)
+ {
+ /* min has changed, which should imply x->x_count == x->x_min */
+ bug("counter_dobang (count < min)");
+ }
+ else if (x->x_dir == COUNTER_UPDOWN)
+ {
+ x->x_inc = 1;
+ if ((x->x_count = x->x_min + 1) > x->x_max) x->x_count = x->x_min;
+ }
+ else if ((x->x_count = x->x_max) < x->x_min) x->x_count = x->x_min;
+ }
+ else if (x->x_count > x->x_max)
+ {
+ if (x->x_inc == -1)
+ {
+ /* CHECKED: ignored */
+ }
+ else if (x->x_dir == COUNTER_UPDOWN)
+ {
+ x->x_inc = -1;
+ if ((x->x_count = x->x_max - 1) < x->x_min) x->x_count = x->x_min;
+ }
+ else x->x_count = x->x_min;
+ }
+
+ if (x->x_count == x->x_min && x->x_inc == -1)
+ {
+ /* CHECKED: 'jam' inhibits middle outlets (unless carry-off)
+ carry-on is never sent if max < min, but sent if max == min */
+ if (notjam
+ && x->x_min <= x->x_max) /* LATER rethink (this is a hack) */
+ onmin = 1;
+ }
+ else if (x->x_count == x->x_max && x->x_inc == 1)
+ {
+ /* CHECKED: this counter is never reset (and goes up to INT_MAX)
+ -- neither after dir change, nor after max change */
+ x->x_maxcount++; /* CHECKED: 'jam' does the increment */
+ outlet_float(x->x_out4, x->x_maxcount);
+ /* CHECKED: 'jam' inhibits middle outlets (unless carry-off)
+ carry-on is never sent if max < min, but sent if max == min */
+ if (notjam
+ && x->x_min <= x->x_max) /* LATER rethink (this is a hack) */
+ onmax = 1;
+ }
+
+ /* CHECKED: outlets deliver in right-to-left order */
+ if (onmax)
+ {
+ if (x->x_carrybang) outlet_bang(x->x_out3);
+ else
+ {
+ outlet_float(x->x_out3, 1);
+ x->x_maxhitflag = 1;
+ }
+ }
+ else if (offmax) outlet_float(x->x_out3, 0);
+ else if (onmin)
+ {
+ if (x->x_carrybang) outlet_bang(x->x_out2);
+ else
+ {
+ outlet_float(x->x_out2, 1);
+ x->x_minhitflag = 1;
+ }
+ }
+ else if (offmin) outlet_float(x->x_out2, 0);
+
+ outlet_float(((t_object *)x)->ob_outlet, x->x_count);
+}
+
+static void counter_bang(t_counter *x)
+{
+ x->x_count += x->x_inc;
+ counter_dobang(x, 1);
+}
+
+static void counter_float(t_counter *x, t_float dummy)
+{
+ counter_bang(x);
+}
+
+/* CHECKED: out-of-range values are ignored */
+/* CHECKED: 'down, set 3, up, bang' gives 5 */
+static void counter_set(t_counter *x, t_floatarg f)
+{
+ int i = (int)f;
+ if (i >= x->x_min && i <= x->x_max)
+ x->x_count = i - x->x_inc;
+}
+
+/* CHECKED: out-of-range values are ignored */
+static void counter_jam(t_counter *x, t_floatarg f)
+{
+ int i = (int)f;
+ if (i >= x->x_min && i <= x->x_max)
+ {
+ x->x_count = i;
+ counter_dobang(x, 0);
+ }
+}
+
+/* CHECKED: sends max carry on/off in any mode */
+static void counter_inc(t_counter *x)
+{
+ int tempdir = x->x_dir;
+ int tempinc = x->x_inc;
+ counter_up(x);
+ counter_bang(x);
+ x->x_dir = tempdir;
+ x->x_inc = tempinc;
+}
+
+/* CHECKED: sends min carry on/off in any mode */
+static void counter_dec(t_counter *x)
+{
+ int tempdir = x->x_dir;
+ int tempinc = x->x_inc;
+ counter_down(x);
+ counter_bang(x);
+ x->x_dir = tempdir;
+ x->x_inc = tempinc;
+}
+
+/* CHECKED: min can be set over max */
+static void counter_min(t_counter *x, t_floatarg f)
+{
+ /* CHECKED: min change always sets count to min and bangs */
+ /* do not use counter_jam() here -- avoid range checking */
+ x->x_count = x->x_min = (int)f;
+ counter_dobang(x, 0);
+}
+
+/* CHECKED: max can be set below min */
+static void counter_max(t_counter *x, t_floatarg f)
+{
+ x->x_max = (int)f;
+}
+
+static void counter_carrybang(t_counter *x)
+{
+ x->x_carrybang = 1;
+}
+
+static void counter_carryint(t_counter *x)
+{
+ x->x_carrybang = 0;
+}
+
+/* CHECKED: up/down switch */
+static void counter_bang1(t_counter *x)
+{
+ if (x->x_dir == COUNTER_UP)
+ counter_down(x);
+ else if (x->x_dir == COUNTER_DOWN)
+ counter_up(x);
+ else
+ x->x_inc = -x->x_inc; /* CHECKED */
+}
+
+/* CHECKED */
+static void counter_bang2(t_counter *x)
+{
+ counter_set(x, x->x_min);
+}
+
+/* CHECKED: out-of-range values are accepted (LATER rethink) */
+/* CHECKED: no resetting of min, nor of max (contrary to the man) */
+/* CHECKED: 'down, float2 3, up, bang' gives 3 (LATER rethink) */
+static void counter_float2(t_counter *x, t_floatarg f)
+{
+ counter_set(x, f); /* FIXME */
+}
+
+/* CHECKED */
+static void counter_bang3(t_counter *x)
+{
+ counter_jam(x, x->x_min);
+}
+
+/* CHECKED: out-of-range values are accepted (LATER rethink) */
+/* CHECKED: no resetting of min, nor of max (contrary to the man) */
+static void counter_float3(t_counter *x, t_floatarg f)
+{
+ counter_jam(x, f); /* FIXME */
+}
+
+/* CHECKED */
+static void counter_bang4(t_counter *x)
+{
+ counter_set(x, x->x_max);
+}
+
+static void counter_proxy_bang(t_counter_proxy *x)
+{
+ x->p_bangmethod(x->p_master);
+}
+
+static void counter_proxy_float(t_counter_proxy *x, t_float f)
+{
+ x->p_floatmethod(x->p_master, f);
+}
+
+static void counter_free(t_counter *x)
+{
+ int i;
+ for (i = 0; i < 4; i++)
+ if (x->x_proxies[i]) pd_free(x->x_proxies[i]);
+}
+
+static void *counter_new(t_floatarg f1, t_floatarg f2, t_floatarg f3)
+{
+ t_counter *x = (t_counter *)pd_new(counter_class);
+ t_counter_proxy **pp = (t_counter_proxy **)x->x_proxies;
+ int i1 = (int)f1;
+ int i2 = (int)f2;
+ int i3 = (int)f3;
+ int i;
+ static int warned = 0;
+ if (!warned)
+ {
+ post("warning: counter is not fully compatible, \
+please report differences");
+ warned = 1;
+ }
+ x->x_dir = COUNTER_UP;
+ x->x_inc = 1; /* previous value required by counter_dir() */
+ x->x_min = 0;
+ x->x_max = COUNTER_DEFMAX;
+ if (i3) x->x_dir = i1, x->x_min = i2, x->x_max = i3;
+ else if (i2) x->x_min = i1, x->x_max = i2;
+ else if (i1) x->x_max = i1;
+ x->x_carrybang = 0; /* CHECKED */
+ x->x_minhitflag = x->x_maxhitflag = 0;
+ x->x_maxcount = 0;
+ counter_dir(x, x->x_dir);
+ /* CHECKED: [counter 1 <min> <max>] starts from <max> */
+ x->x_count = (x->x_dir == COUNTER_DOWN ? x->x_max : x->x_min);
+ for (i = 0; i < 4; i++)
+ {
+ x->x_proxies[i] = pd_new(counter_proxy_class);
+ ((t_counter_proxy *)x->x_proxies[i])->p_master = x;
+ inlet_new((t_object *)x, x->x_proxies[i], 0, 0);
+ }
+ (*pp)->p_bangmethod = counter_bang1;
+ (*pp++)->p_floatmethod = counter_dir; /* CHECKED: same as dir */
+ (*pp)->p_bangmethod = counter_bang2;
+ (*pp++)->p_floatmethod = counter_float2;
+ (*pp)->p_bangmethod = counter_bang3;
+ (*pp++)->p_floatmethod = counter_float3;
+ (*pp)->p_bangmethod = counter_bang4;
+ (*pp++)->p_floatmethod = counter_max; /* CHECKED: same as max */
+ outlet_new((t_object *)x, &s_float);
+ x->x_out2 = outlet_new((t_object *)x, &s_anything); /* float/bang */
+ x->x_out3 = outlet_new((t_object *)x, &s_anything); /* float/bang */
+ x->x_out4 = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void counter_setup(void)
+{
+ counter_class = class_new(gensym("counter"),
+ (t_newmethod)counter_new,
+ (t_method)counter_free,
+ sizeof(t_counter), 0,
+ A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addbang(counter_class, counter_bang);
+ class_addfloat(counter_class, counter_float);
+ class_addmethod(counter_class, (t_method)counter_bang,
+ gensym("next"), 0);
+ class_addmethod(counter_class, (t_method)counter_set,
+ gensym("set"), A_FLOAT, 0);
+ class_addmethod(counter_class, (t_method)counter_set,
+ gensym("goto"), A_FLOAT, 0);
+ class_addmethod(counter_class, (t_method)counter_jam,
+ gensym("jam"), A_FLOAT, 0);
+ class_addmethod(counter_class, (t_method)counter_up,
+ gensym("up"), 0);
+ class_addmethod(counter_class, (t_method)counter_down,
+ gensym("down"), 0);
+ class_addmethod(counter_class, (t_method)counter_updown,
+ gensym("updown"), 0);
+ class_addmethod(counter_class, (t_method)counter_inc,
+ gensym("inc"), 0);
+ class_addmethod(counter_class, (t_method)counter_dec,
+ gensym("dec"), 0);
+ class_addmethod(counter_class, (t_method)counter_min,
+ gensym("min"), A_FLOAT, 0);
+ class_addmethod(counter_class, (t_method)counter_max,
+ gensym("max"), A_FLOAT, 0);
+ class_addmethod(counter_class, (t_method)counter_carrybang,
+ gensym("carrybang"), 0);
+ class_addmethod(counter_class, (t_method)counter_carryint,
+ gensym("carryint"), 0);
+ counter_proxy_class = class_new(gensym("_counter_proxy"), 0, 0,
+ sizeof(t_counter_proxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addbang(counter_proxy_class, counter_proxy_bang);
+ class_addfloat(counter_proxy_class, counter_proxy_float);
+}
diff --git a/cyclone/hammer/cycle.c b/cyclone/hammer/cycle.c
new file mode 100644
index 0000000..faffc01
--- /dev/null
+++ b/cyclone/hammer/cycle.c
@@ -0,0 +1,153 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* This is a modified version of Joseph A. Sarlo's code.
+ The most important changes are listed in "pd-lib-notes.txt" file. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+
+//#define CYCLE_USEEVENTNO
+
+#define CYCLE_MINOUTS 1
+#define CYCLE_MAXOUTS 100 /* CHECKED */
+#define CYCLE_DEFOUTS 1
+
+typedef struct _cycle
+{
+ t_object x_ob;
+ int x_eventmode;
+#ifdef CYCLE_USEEVENTNO
+ int x_lastevent;
+#else
+ double x_lastevent;
+#endif
+ int x_index;
+ int x_nouts;
+ t_outlet **x_outs;
+} t_cycle;
+
+static t_class *cycle_class;
+
+static int cycle_isnextevent(t_cycle *x)
+{
+#ifdef CYCLE_USEEVENTNO
+ int nextevent = sys_geteventno();
+#else
+ double nextevent = clock_getlogicaltime();
+#endif
+ if (x->x_lastevent == nextevent)
+ return (0);
+ else
+ {
+ x->x_lastevent = nextevent;
+ return (1);
+ }
+}
+
+static void cycle_bang(t_cycle *x)
+{
+ /* CHECKED: bangs ignored (but message 'bang' is an error -- why?) */
+}
+
+static void cycle_float(t_cycle *x, t_float f)
+{
+ if ((x->x_eventmode && cycle_isnextevent(x)) || x->x_index >= x->x_nouts)
+ x->x_index = 0;
+ outlet_float(x->x_outs[x->x_index++], f);
+}
+
+static void cycle_symbol(t_cycle *x, t_symbol *s)
+{
+ if ((x->x_eventmode && cycle_isnextevent(x)) || x->x_index >= x->x_nouts)
+ x->x_index = 0;
+ outlet_symbol(x->x_outs[x->x_index++], s);
+}
+
+/* LATER gpointer */
+
+static void cycle_list(t_cycle *x, t_symbol *s, int ac, t_atom *av)
+{
+ if ((x->x_eventmode && cycle_isnextevent(x)) || x->x_index >= x->x_nouts)
+ x->x_index = 0;
+ while (ac--)
+ {
+ if (av->a_type == A_FLOAT)
+ outlet_float(x->x_outs[x->x_index], av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL)
+ outlet_symbol(x->x_outs[x->x_index], av->a_w.w_symbol);
+ av++;
+ if (++(x->x_index) >= x->x_nouts) x->x_index = 0;
+ }
+}
+
+static void cycle_anything(t_cycle *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (s && s != &s_) cycle_symbol(x, s); /* CHECKED */
+ cycle_list(x, 0, ac, av);
+}
+
+static void cycle_set(t_cycle *x, t_floatarg f)
+{
+ int i = (int)f;
+ if (i >= 0 && i < x->x_nouts) x->x_index = i;
+}
+
+static void cycle_thresh(t_cycle *x, t_floatarg f)
+{
+ if (x->x_eventmode = (f != 0))
+#ifdef CYCLE_USEEVENTNO
+ x->x_lastevent = sys_geteventno();
+#else
+ x->x_lastevent = clock_getlogicaltime();
+#endif
+}
+
+static void cycle_free(t_cycle *x)
+{
+ if (x->x_outs)
+ freebytes(x->x_outs, x->x_nouts * sizeof(*x->x_outs));
+}
+
+static void *cycle_new(t_floatarg f1, t_floatarg f2)
+{
+ t_cycle *x;
+ int i, nouts = (int)f1;
+ t_outlet **outs;
+ if (nouts < CYCLE_MINOUTS)
+ nouts = CYCLE_DEFOUTS;
+ if (nouts > CYCLE_MAXOUTS)
+ {
+ loud_incompatible_max(cycle_class, CYCLE_MAXOUTS, "outlets");
+ /* CHECKED: max clips with an error:
+ ``perhaps you were trying to make an oscillator?'' */
+ }
+ if (!(outs = (t_outlet **)getbytes(nouts * sizeof(*outs))))
+ return (0);
+ x = (t_cycle *)pd_new(cycle_class);
+ x->x_nouts = nouts;
+ x->x_outs = outs;
+ x->x_index = 0;
+ for (i = 0; i < nouts; i++)
+ x->x_outs[i] = outlet_new((t_object *)x, &s_anything);
+ cycle_thresh(x, f2);
+ return (x);
+}
+
+void cycle_setup(void)
+{
+ cycle_class = class_new(gensym("cycle"),
+ (t_newmethod)cycle_new,
+ (t_method)cycle_free,
+ sizeof(t_cycle), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addbang(cycle_class, cycle_bang);
+ class_addfloat(cycle_class, cycle_float);
+ class_addsymbol(cycle_class, cycle_symbol);
+ class_addlist(cycle_class, cycle_list);
+ class_addanything(cycle_class, cycle_anything);
+ class_addmethod(cycle_class, (t_method)cycle_set,
+ gensym("set"), A_FLOAT, 0); /* CHECKED: arg required */
+ class_addmethod(cycle_class, (t_method)cycle_thresh,
+ gensym("thresh"), A_FLOAT, 0);
+}
diff --git a/cyclone/hammer/decide.c b/cyclone/hammer/decide.c
new file mode 100644
index 0000000..a612fbf
--- /dev/null
+++ b/cyclone/hammer/decide.c
@@ -0,0 +1,75 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+
+typedef struct _decide
+{
+ t_object x_ob;
+ unsigned int x_seed;
+} t_decide;
+
+static t_class *decide_class;
+
+/* the random bit algo is taken from NR (method II in 7.4) -- CHECKED */
+#define RBIT1 1
+#define RBIT2 2
+#define RBIT5 16
+#define RBIT18 131072
+#define RBIT_MASK (RBIT1 + RBIT2 + RBIT5)
+
+static void decide_bang(t_decide *x)
+{
+ if (x->x_seed & RBIT18)
+ {
+ x->x_seed = ((x->x_seed ^ RBIT_MASK) << 1) | RBIT1;
+ outlet_float(((t_object *)x)->ob_outlet, 1);
+ }
+ else
+ {
+ x->x_seed <<= 1;
+ outlet_float(((t_object *)x)->ob_outlet, 0);
+ }
+}
+
+static void decide_float(t_decide *x, t_float f)
+{
+ /* CHECKED: float loudly rejected, int (any value) same as bang */
+ int i;
+ if (loud_checkint((t_pd *)x, f, &i, &s_float))
+ decide_bang(x);
+}
+
+static void decide_ft1(t_decide *x, t_floatarg f)
+{
+ int i = (int)f; /* CHECKED */
+ if (i) /* CHECKED: negative numbers are accepted */
+ x->x_seed = i;
+ else
+ x->x_seed = 123456789; /* FIXME */
+}
+
+static void *decide_new(t_floatarg f)
+{
+ t_decide *x = (t_decide *)pd_new(decide_class);
+ x->x_seed = 123456789; /* FIXME */
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void decide_setup(void)
+{
+ decide_class = class_new(gensym("decide"),
+ (t_newmethod)decide_new, 0,
+ sizeof(t_decide), 0,
+ A_DEFFLOAT, 0);
+ class_addbang(decide_class, decide_bang);
+ class_addfloat(decide_class, decide_float);
+ class_addmethod(decide_class, (t_method)decide_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ /* CHECKED list is auto-unfolded */
+ /* CHECKED doesn't understand "seed" */
+}
diff --git a/cyclone/hammer/drunk.c b/cyclone/hammer/drunk.c
new file mode 100644
index 0000000..e08800d
--- /dev/null
+++ b/cyclone/hammer/drunk.c
@@ -0,0 +1,140 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* The first version of this code was written by Nicola Bernardini.
+ It was entirely reimplemented in the hope of adapting it to the
+ cyclone's guidelines. */
+
+#include "m_pd.h"
+#include "common/rand.h"
+
+#define DRUNK_DEFMAXVALUE 128
+#define DRUNK_DEFMAXSTEP 2
+
+typedef struct _drunk
+{
+ t_object x_ob;
+ int x_value;
+ int x_maxvalue;
+ int x_maxstep;
+ int x_minstep;
+ unsigned int x_seed;
+ unsigned int x_bitseed;
+} t_drunk;
+
+static t_class *drunk_class;
+
+static void drunk_set(t_drunk *x, t_floatarg f)
+{
+ int i = (int)f; /* CHECKED float silently truncated */
+ if (i > x->x_maxvalue)
+ x->x_value = x->x_maxvalue; /* CHECKED */
+ else if (i < 0)
+ x->x_value = 0; /* CHECKED */
+ else x->x_value = i;
+}
+
+/* CHECKED: this is a superposition of two rngs -- the random bit generator,
+ and the random integer generator, which is the same (CHECKED) as the one
+ used in the 'random' class (quite lame: period 35730773, nonuniform for
+ large ranges, so I would rather not RE it...) */
+#define RBIT1 1
+#define RBIT2 2
+#define RBIT5 16
+#define RBIT18 131072
+#define RBIT_MASK (RBIT1 + RBIT2 + RBIT5)
+
+static void drunk_bang(t_drunk *x)
+{
+ int rnd = rand_int(&x->x_seed, x->x_maxstep) + x->x_minstep;
+ int val;
+ if (x->x_bitseed & RBIT18)
+ {
+ x->x_bitseed = ((x->x_bitseed ^ RBIT_MASK) << 1) | RBIT1;
+ if ((val = x->x_value + rnd) > x->x_maxvalue)
+ val = x->x_value - rnd; /* CHECKED */
+ if (val < 0)
+ val = 0; /* CHECKED (needed for maxstep > maxvalue) */
+ }
+ else
+ {
+ x->x_bitseed <<= 1;
+ if ((val = x->x_value - rnd) < 0)
+ val = x->x_value + rnd; /* CHECKED */
+ if (val > x->x_maxvalue)
+ val = x->x_maxvalue; /* CHECKED (needed for maxstep > maxvalue) */
+ }
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value = val);
+}
+
+static void drunk_float(t_drunk *x, t_float f)
+{
+ drunk_set(x, f);
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+}
+
+static void drunk_ft1(t_drunk *x, t_floatarg f)
+{
+ int i = (int)f; /* CHECKED float silently truncated */
+ x->x_maxvalue = (i < 0 ? 1 : i); /* CHECKED zero allowed */
+ /* CHECKED maxstep not updated */
+}
+
+static void drunk_ft2(t_drunk *x, t_floatarg f)
+{
+ int i = (int)f; /* CHECKED float silently truncated */
+ if (i < 0)
+ {
+ x->x_minstep = 1;
+ i = -i;
+ }
+ else x->x_minstep = 0;
+ /* CHECKED maxstep not clipped to the maxvalue */
+ x->x_maxstep = (x->x_minstep ? i - 1 : i); /* CHECKED zero allowed */
+}
+
+/* apparently, bitseed cannot be controlled, but LATER recheck */
+static void drunk_seed(t_drunk *x, t_floatarg f)
+{
+ int i = (int)f; /* CHECKED */
+ if (i < 0)
+ i = 1; /* CHECKED */
+ rand_seed(&x->x_seed, (unsigned int)i);
+}
+
+static void *drunk_new(t_floatarg f1, t_floatarg f2)
+{
+ t_drunk *x = (t_drunk *)pd_new(drunk_class);
+ x->x_maxvalue = ((int)f1 > 0 ? (int)f1 : 128); /* CHECKED */
+ x->x_maxstep = 2;
+ x->x_minstep = 0;
+ if ((int)f2) /* CHECKED */
+ drunk_ft2(x, f2);
+ x->x_value = x->x_maxvalue / 2; /* CHECKED */
+ rand_seed(&x->x_seed, 0); /* CHECKED third arg silently ignored */
+ x->x_bitseed = 123456789; /* FIXME */
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft2"));
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void drunk_setup(void)
+{
+ drunk_class = class_new(gensym("drunk"),
+ (t_newmethod)drunk_new, 0,
+ sizeof(t_drunk), 0,
+ A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addbang(drunk_class, drunk_bang);
+ class_addfloat(drunk_class, drunk_float);
+ class_addmethod(drunk_class, (t_method)drunk_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(drunk_class, (t_method)drunk_ft2,
+ gensym("ft2"), A_FLOAT, 0);
+ /* CHECKED list is auto-unfolded */
+ class_addmethod(drunk_class, (t_method)drunk_seed,
+ gensym("seed"), A_FLOAT, 0); /* CHECKED arg obligatory */
+ class_addmethod(drunk_class, (t_method)drunk_set,
+ gensym("set"), A_FLOAT, 0); /* CHECKED arg obligatory */
+}
diff --git a/cyclone/hammer/flush.c b/cyclone/hammer/flush.c
new file mode 100644
index 0000000..751fc24
--- /dev/null
+++ b/cyclone/hammer/flush.c
@@ -0,0 +1,79 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+
+#define FLUSH_NPITCHES 128
+
+typedef struct _flush
+{
+ t_object x_ob;
+ t_float x_velocity;
+ unsigned char x_pitches[FLUSH_NPITCHES]; /* CHECKED */
+ t_outlet *x_voutlet;
+} t_flush;
+
+static t_class *flush_class;
+
+static void flush_float(t_flush *x, t_float f)
+{
+ int pitch = (int)f;
+ if (pitch >= 0 && pitch < FLUSH_NPITCHES)
+ {
+ outlet_float(x->x_voutlet, x->x_velocity);
+ outlet_float(((t_object *)x)->ob_outlet, pitch);
+ if (x->x_velocity != 0)
+ {
+ x->x_pitches[pitch]++; /* CHECKED (lame) */
+ }
+ else if (x->x_pitches[pitch])
+ {
+ x->x_pitches[pitch]--; /* CHECKED (lame) */
+ }
+ }
+}
+
+static void flush_bang(t_flush *x)
+{
+ int i;
+ unsigned char *pp;
+ for (i = 0, pp = x->x_pitches; i < FLUSH_NPITCHES; i++, pp++)
+ {
+ while (*pp)
+ {
+ outlet_float(x->x_voutlet, 0);
+ outlet_float(((t_object *)x)->ob_outlet, i);
+ (*pp)--;
+ }
+ }
+}
+
+static void flush_clear(t_flush *x)
+{
+ memset(x->x_pitches, 0, sizeof(x->x_pitches));
+}
+
+static void *flush_new(void)
+{
+ t_flush *x = (t_flush *)pd_new(flush_class);
+ x->x_velocity = 0;
+ flush_clear(x);
+ floatinlet_new((t_object *)x, &x->x_velocity);
+ outlet_new((t_object *)x, &s_float);
+ x->x_voutlet = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void flush_setup(void)
+{
+ flush_class = class_new(gensym("flush"),
+ (t_newmethod)flush_new,
+ 0, /* CHECKED: no flushout */
+ sizeof(t_flush), 0, 0);
+ class_addfloat(flush_class, flush_float);
+ class_addbang(flush_class, flush_bang);
+ class_addmethod(flush_class, (t_method)flush_clear,
+ gensym("clear"), 0);
+}
diff --git a/cyclone/hammer/forward.c b/cyclone/hammer/forward.c
new file mode 100644
index 0000000..995e765
--- /dev/null
+++ b/cyclone/hammer/forward.c
@@ -0,0 +1,71 @@
+/* Copyright (c) 1997-2002 Miller Puckette, krzYszcz, and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+
+typedef struct _forward
+{
+ t_object x_ob;
+ t_symbol *x_sym;
+} t_forward;
+
+static t_class *forward_class;
+
+static void forward_bang(t_forward *x)
+{
+ if (x->x_sym->s_thing) pd_bang(x->x_sym->s_thing);
+}
+
+static void forward_float(t_forward *x, t_float f)
+{
+ if (x->x_sym->s_thing) pd_float(x->x_sym->s_thing, f);
+}
+
+static void forward_symbol(t_forward *x, t_symbol *s)
+{
+ if (x->x_sym->s_thing) pd_symbol(x->x_sym->s_thing, s);
+}
+
+static void forward_pointer(t_forward *x, t_gpointer *gp)
+{
+ if (x->x_sym->s_thing) pd_pointer(x->x_sym->s_thing, gp);
+}
+
+static void forward_list(t_forward *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (x->x_sym->s_thing) pd_list(x->x_sym->s_thing, s, ac, av);
+}
+
+static void forward_anything(t_forward *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (x->x_sym->s_thing) typedmess(x->x_sym->s_thing, s, ac, av);
+}
+
+static void forward_send(t_forward *x, t_symbol *s)
+{
+ /* CHECKED: 'send' without arguments erases destination */
+ if (s) x->x_sym = s;
+}
+
+static void *forward_new(t_symbol *s)
+{
+ t_forward *x = (t_forward *)pd_new(forward_class);
+ x->x_sym = s;
+ return (x);
+}
+
+void forward_setup(void)
+{
+ forward_class = class_new(gensym("forward"),
+ (t_newmethod)forward_new, 0,
+ sizeof(t_forward), 0, A_DEFSYM, 0);
+ class_addbang(forward_class, forward_bang);
+ class_addfloat(forward_class, forward_float);
+ class_addsymbol(forward_class, forward_symbol);
+ class_addpointer(forward_class, forward_pointer);
+ class_addlist(forward_class, forward_list);
+ class_addanything(forward_class, forward_anything);
+ class_addmethod(forward_class, (t_method)forward_send,
+ gensym("send"), A_DEFSYM, 0);
+}
diff --git a/cyclone/hammer/fromsymbol.c b/cyclone/hammer/fromsymbol.c
new file mode 100644
index 0000000..3d508e9
--- /dev/null
+++ b/cyclone/hammer/fromsymbol.c
@@ -0,0 +1,88 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+
+typedef struct _fromsymbol
+{
+ t_object x_ob;
+} t_fromsymbol;
+
+static t_class *fromsymbol_class;
+
+static void fromsymbol_bang(t_fromsymbol *x)
+{
+ outlet_bang(((t_object *)x)->ob_outlet); /* CHECKED */
+}
+
+static void fromsymbol_float(t_fromsymbol *x, t_float f)
+{
+ /* CHECKED: fromsymbol: doesn't understand "int", "float" */
+}
+
+static void fromsymbol_symbol(t_fromsymbol *x, t_symbol *s)
+{
+ static char zero = 0;
+ char *sname = &zero;
+ if (s)
+ {
+ sname = s->s_name;
+ while (*sname == ' ' || *sname == '\t'
+ || *sname == '\n' || *sname == '\r') sname++;
+ }
+ if (*sname)
+ {
+ t_binbuf *bb = binbuf_new();
+ int ac;
+ t_atom *av;
+ binbuf_text(bb, sname, strlen(sname));
+ ac = binbuf_getnatom(bb);
+ av = binbuf_getvec(bb);
+ if (ac)
+ {
+ if (av->a_type == A_SYMBOL)
+ outlet_anything(((t_object *)x)->ob_outlet,
+ av->a_w.w_symbol, ac - 1, av + 1);
+ else if (av->a_type == A_FLOAT)
+ {
+ if (ac > 1)
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av);
+ else
+ outlet_float(((t_object *)x)->ob_outlet, av->a_w.w_float);
+ }
+ }
+ binbuf_free(bb);
+ }
+}
+
+static void fromsymbol_list(t_fromsymbol *x, t_symbol *s, int ac, t_atom *av)
+{
+ /* CHECKED: fromsymbol: doesn't understand "int", "float",
+ 'list <symbol>' ignored without complaining. */
+}
+
+static void fromsymbol_anything(t_fromsymbol *x, t_symbol *s, int ac, t_atom *av)
+{
+ fromsymbol_symbol(x, s); /* CHECKED */
+}
+
+static void *fromsymbol_new(void)
+{
+ t_fromsymbol *x = (t_fromsymbol *)pd_new(fromsymbol_class);
+ outlet_new((t_object *)x, &s_anything);
+ return (x);
+}
+
+void fromsymbol_setup(void)
+{
+ fromsymbol_class = class_new(gensym("fromsymbol"),
+ (t_newmethod)fromsymbol_new, 0,
+ sizeof(t_fromsymbol), 0, 0);
+ class_addbang(fromsymbol_class, fromsymbol_bang);
+ class_addfloat(fromsymbol_class, fromsymbol_float);
+ class_addsymbol(fromsymbol_class, fromsymbol_symbol);
+ class_addlist(fromsymbol_class, fromsymbol_list);
+ class_addanything(fromsymbol_class, fromsymbol_anything);
+}
diff --git a/cyclone/hammer/funbuff.c b/cyclone/hammer/funbuff.c
new file mode 100644
index 0000000..8d9d698
--- /dev/null
+++ b/cyclone/hammer/funbuff.c
@@ -0,0 +1,521 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "unstable/fragile.h"
+#include "common/loud.h"
+#include "common/vefl.h"
+#include "hammer/tree.h"
+#include "hammer/file.h"
+
+typedef struct _funbuff
+{
+ t_object x_ob;
+ t_canvas *x_canvas;
+ t_symbol *x_defname;
+ t_float x_value;
+ int x_valueset;
+ /* CHECKED filling with a large set, then sending 'goto', 'read', 'next'...
+ outputs the previous, replaced contents (same with deletion)
+ -- apparently a node pointer is stored, corrupt in these cases */
+ t_hammernode *x_pointer;
+ int x_pointerset; /* set-with-goto flag */
+ int x_lastdelta;
+ int x_embedflag;
+ t_hammerfile *x_filehandle;
+ t_hammertree x_tree;
+ t_outlet *x_deltaout;
+ t_outlet *x_bangout;
+} t_funbuff;
+
+static t_class *funbuff_class;
+
+static void funbuff_dooutput(t_funbuff *x, float value, float delta)
+{
+ /* CHECKED lastdelta sent for 'next', 'float', 'min', 'max',
+ 'interp', 'find' */
+ outlet_float(x->x_deltaout, delta);
+ outlet_float(((t_object *)x)->ob_outlet, value);
+}
+
+static void funbuff_bang(t_funbuff *x)
+{
+ t_hammernode *np;
+ int count = 0;
+ int xmin = 0, xmax = 0;
+ t_float ymin = 0, ymax = 0;
+ if (np = x->x_tree.t_first)
+ {
+ /* LATER consider using extra fields, updated on the fly */
+ count = 1;
+ xmin = np->n_index;
+ xmax = x->x_tree.t_last->n_index;
+ ymin = ymax = np->n_value;
+ while (np = np->n_next)
+ {
+ if (np->n_value < ymin) ymin = np->n_value;
+ else if (np->n_value > ymax) ymax = np->n_value;
+ count++;
+ }
+ }
+ /* format CHECKED */
+ post("funbuff info: %d elements long", count); /* CHECKED 0 and 1 */
+ if (count)
+ {
+ post(" -> minX= %d maxX= %d", xmin, xmax);
+ post(" -> minY= %g maxY= %g", ymin, ymax);
+ post(" -> domain= %d range= %g", xmax - xmin, ymax - ymin);
+ }
+}
+
+static void funbuff_float(t_funbuff *x, t_float f)
+{
+ int ndx = (int)f; /* CHECKED float is silently truncated */
+ t_hammernode *np;
+ if (x->x_valueset)
+ {
+ if (np = hammertree_insert(&x->x_tree, ndx))
+ np->n_value = x->x_value;
+ x->x_valueset = 0;
+ }
+ else if (np = hammertree_closest(&x->x_tree, ndx, 0))
+ funbuff_dooutput(x, np->n_value, x->x_lastdelta);
+ /* CHECKED pointer is updated --
+ 'next' outputs np also in a !valueset case (it is sent twice) */
+ x->x_pointer = np;
+ x->x_pointerset = 0;
+}
+
+static void funbuff_ft1(t_funbuff *x, t_floatarg f)
+{
+ /* this is incompatible -- CHECKED float is silently truncated */
+ x->x_value = f;
+ x->x_valueset = 1;
+}
+
+static void funbuff_clear(t_funbuff *x)
+{
+ hammertree_clear(&x->x_tree, 0);
+ /* CHECKED valueset is not cleared */
+ x->x_pointer = 0;
+}
+
+/* LATER dirty flag handling */
+static void funbuff_embed(t_funbuff *x, t_floatarg f)
+{
+ x->x_embedflag = (f != 0);
+}
+
+static void funbuff_goto(t_funbuff *x, t_floatarg f)
+{
+ /* CHECKED truncation */
+ x->x_pointer = hammertree_closest(&x->x_tree, (int)f, 1);
+ x->x_pointerset = 1; /* CHECKED delta output by 'next' will be zero */
+}
+
+/* LATER consider using an extra field, updated on the fly */
+static void funbuff_min(t_funbuff *x)
+{
+ t_hammernode *np;
+ if (np = x->x_tree.t_first) /* CHECKED nop if empty */
+ {
+ t_float result = np->n_value;
+ while (np = np->n_next)
+ if (np->n_value < result) result = np->n_value;
+ funbuff_dooutput(x, result, x->x_lastdelta);
+ /* CHECKED pointer not updated */
+ }
+}
+
+/* LATER consider using an extra field, updated on the fly */
+static void funbuff_max(t_funbuff *x)
+{
+ t_hammernode *np;
+ if (np = x->x_tree.t_first) /* CHECKED nop if empty */
+ {
+ t_float result = np->n_value;
+ while (np = np->n_next)
+ if (np->n_value > result) result = np->n_value;
+ funbuff_dooutput(x, result, x->x_lastdelta);
+ /* CHECKED pointer not updated */
+ }
+}
+
+static void funbuff_next(t_funbuff *x)
+{
+ t_hammernode *np;
+ if (!x->x_tree.t_root)
+ return;
+ if (!(np = x->x_pointer))
+ {
+ outlet_bang(x->x_bangout);
+ /* CHECKED banging until reset */
+ return;
+ }
+ if (x->x_pointerset)
+ x->x_lastdelta = 0;
+ else if (np->n_prev)
+ x->x_lastdelta = np->n_index - np->n_prev->n_index;
+ else
+ x->x_lastdelta = 0; /* CHECKED corrupt delta sent here... */
+ funbuff_dooutput(x, np->n_value, x->x_lastdelta);
+ x->x_pointer = np->n_next;
+ x->x_pointerset = 0;
+}
+
+static void funbuff_set(t_funbuff *x, t_symbol *s, int ac, t_atom *av)
+{
+ /* CHECKED symbols somehow bashed to zeros,
+ decreasing x coords corrupt the funbuff -- not emulated here... */
+ int i = ac;
+ t_atom *ap = av;
+ while (i--) if (ap++->a_type != A_FLOAT)
+ {
+ loud_error((t_pd *)x, "bad input (not a number) -- no data to set");
+ return;
+ }
+ if (!ac || (ac % 2))
+ {
+ /* CHECKED odd/null ac loudly rejected, current contents preserved */
+ loud_error((t_pd *)x, "bad input (%s) -- no data to set",
+ (ac ? "odd arg count" : "no input"));
+ return;
+ }
+ funbuff_clear(x); /* CHECKED the contents is replaced */
+ while (ac--)
+ {
+ t_hammernode *np;
+ if (np = hammertree_insert(&x->x_tree, (int)av++->a_w.w_float))
+ np->n_value = av++->a_w.w_float;
+ else return;
+ ac--;
+ }
+}
+
+static void funbuff_doread(t_funbuff *x, t_symbol *fn)
+{
+ t_binbuf *bb = binbuf_new();
+ int ac;
+ t_atom *av;
+ char buf[MAXPDSTRING];
+ canvas_makefilename(x->x_canvas, fn->s_name, buf, MAXPDSTRING);
+ binbuf_read(bb, buf, "", 0);
+ if ((ac = binbuf_getnatom(bb)) &&
+ (av = binbuf_getvec(bb)) &&
+ av->a_type == A_SYMBOL &&
+ av->a_w.w_symbol == gensym("funbuff"))
+ {
+ post("funbuff_read: %s read successful", fn->s_name); /* CHECKED */
+ funbuff_set(x, 0, ac-1, av+1);
+ }
+ else /* CHECKED no complaints... */
+ loud_error((t_pd *)x, "invalid file %s", fn->s_name);
+ binbuf_free(bb);
+}
+
+static void funbuff_readhook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ funbuff_doread((t_funbuff *)z, fn);
+}
+
+static void funbuff_dowrite(t_funbuff *x, t_symbol *fn)
+{
+ t_binbuf *bb = binbuf_new();
+ char buf[MAXPDSTRING];
+ t_hammernode *np;
+ binbuf_addv(bb, "s", gensym("funbuff"));
+ for (np = x->x_tree.t_first; np; np = np->n_next)
+ binbuf_addv(bb, "if", np->n_index, np->n_value);
+ canvas_makefilename(x->x_canvas, fn->s_name, buf, MAXPDSTRING);
+ binbuf_write(bb, buf, "", 0);
+ binbuf_free(bb);
+}
+
+static void funbuff_writehook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ funbuff_dowrite((t_funbuff *)z, fn);
+}
+
+static void funbuff_embedhook(t_pd *z, t_binbuf *bb, t_symbol *bindsym)
+{
+ t_funbuff *x = (t_funbuff *)z;
+ if (x->x_embedflag)
+ {
+ t_hammernode *np;
+ binbuf_addv(bb, "ssi;", bindsym, gensym("embed"), 1);
+ if (np = x->x_tree.t_first)
+ {
+ binbuf_addv(bb, "ss", bindsym, gensym("set"));
+ for (; np; np = np->n_next)
+ binbuf_addv(bb, "if", np->n_index, np->n_value);
+ binbuf_addsemi(bb);
+ }
+ }
+}
+
+/* CHECKED symbol arg ok */
+static void funbuff_read(t_funbuff *x, t_symbol *s)
+{
+ if (s && s != &s_)
+ funbuff_doread(x, s);
+ else
+ hammerpanel_open(x->x_filehandle);
+}
+
+/* CHECKED symbol arg not allowed --
+ a bug? but CHECKME other classes (cf seq's filetype dilemma) */
+static void funbuff_write(t_funbuff *x, t_symbol *s)
+{
+ if (s && s != &s_)
+ funbuff_dowrite(x, s);
+ else /* CHECKME default name */
+ hammerpanel_save(x->x_filehandle,
+ canvas_getdir(x->x_canvas), x->x_defname);
+}
+
+static void funbuff_delete(t_funbuff *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac && av->a_type == A_FLOAT &&
+ (ac == 1 || (ac == 2 && av[1].a_type == A_FLOAT)))
+ {
+ /* CHECKED float is silently truncated */
+ int ndx = (int)av->a_w.w_float;
+ t_hammernode *np;
+ if ((np = hammertree_search(&x->x_tree, ndx)) &&
+ (ac == 1 || np->n_value == av[1].a_w.w_float))
+ {
+ if (np == x->x_pointer)
+ x->x_pointer = 0; /* CHECKED corrupt pointer left here... */
+ hammertree_delete(&x->x_tree, np);
+ }
+ /* CHECKED mismatch silently ignored */
+ }
+ else loud_messarg((t_pd *)x, s); /* CHECKED */
+}
+
+static void funbuff_find(t_funbuff *x, t_floatarg f)
+{
+ t_hammernode *np;
+ if (np = x->x_tree.t_first)
+ {
+ do
+ {
+ /* CHECKED lastdelta preserved */
+ if (np->n_value == f)
+ funbuff_dooutput(x, np->n_index, x->x_lastdelta);
+ }
+ while (np = np->n_next);
+ /* CHECKED no bangout, no complaint if nothing found */
+ }
+ else loud_error((t_pd *)x, "nothing to find"); /* CHECKED */
+}
+
+static void funbuff_dump(t_funbuff *x)
+{
+ t_hammernode *np;
+ if (np = x->x_tree.t_first)
+ {
+ do
+ {
+ x->x_lastdelta = np->n_value; /* CHECKED */
+ /* float value preserved (this is incompatible) */
+ funbuff_dooutput(x, np->n_index, np->n_value);
+ }
+ while (np = np->n_next);
+ /* CHECKED no bangout */
+ }
+ else loud_error((t_pd *)x, "nothing to dump"); /* CHECKED */
+}
+
+/* CHECKME if pointer is updated */
+static void funbuff_dointerp(t_funbuff *x, t_floatarg f, int vsz, t_float *vec)
+{
+ t_hammernode *np1;
+ int trunc = (int)f;
+ if (trunc > f) trunc--; /* CHECKME negative floats */
+ if (np1 = hammertree_closest(&x->x_tree, trunc, 0))
+ {
+ float value = np1->n_value;
+ t_hammernode *np2 = np1->n_next;
+ if (np2)
+ {
+ float delta = (float)(np2->n_index - np1->n_index);
+ /* this is incompatible -- CHECKED float argument is silently
+ truncated (which does not make much sense here), CHECKME again */
+ float frac = f - np1->n_index;
+ if (frac < 0 || frac >= delta)
+ {
+ bug("funbuff_dointerp");
+ return;
+ }
+ frac /= delta;
+ if (vec)
+ {
+ /* CHECKME */
+ float vpos = (vsz - 1) * frac;
+ int vndx = (int)vpos;
+ float vfrac = vpos - vndx;
+ if (vndx < 0 || vndx >= vsz - 1)
+ {
+ bug("funbuff_dointerp redundant test...");
+ return;
+ }
+ vec += vndx;
+ frac = *vec + (vec[1] - *vec) * vfrac;
+ }
+ value += (np2->n_value - np1->n_value) * frac;
+ }
+ funbuff_dooutput(x, value, x->x_lastdelta); /* CHECKME !np2 */
+ }
+ else if (np1 = hammertree_closest(&x->x_tree, trunc, 1))
+ funbuff_dooutput(x, np1->n_value, x->x_lastdelta); /* CHECKME */
+}
+
+static void funbuff_interp(t_funbuff *x, t_floatarg f)
+{
+ funbuff_dointerp(x, f, 0, 0);
+}
+
+static void funbuff_interptab(t_funbuff *x, t_symbol *s, t_floatarg f)
+{
+ int vsz;
+ t_float *vec;
+ if (vec = vefl_get(s, &vsz, 0, (t_pd *)x))
+ {
+ if (vsz > 2)
+ funbuff_dointerp(x, f, vsz, vec);
+ else
+ funbuff_dointerp(x, f, 0, 0);
+ }
+}
+
+static void funbuff_reduce(t_funbuff *x, t_floatarg f)
+{
+ loud_notimplemented((t_pd *)x, "reduce");
+}
+
+static void funbuff_select(t_funbuff *x, t_floatarg f1, t_floatarg f2)
+{
+ loud_notimplemented((t_pd *)x, "select");
+}
+
+/* CHECKED (sub)buffer's copy is stored, as expected --
+ 'delete' does not modify the clipboard */
+/* CHECKED cut entire contents if no selection */
+static void funbuff_cut(t_funbuff *x)
+{
+ loud_notimplemented((t_pd *)x, "cut");
+}
+
+/* CHECKED copy entire contents if no selection */
+static void funbuff_copy(t_funbuff *x)
+{
+ loud_notimplemented((t_pd *)x, "copy");
+}
+
+static void funbuff_paste(t_funbuff *x)
+{
+ loud_notimplemented((t_pd *)x, "paste");
+}
+
+static void funbuff_undo(t_funbuff *x)
+{
+ /* CHECKED apparently not working in 4.07 */
+ loud_notimplemented((t_pd *)x, "undo");
+}
+
+#ifdef HAMMERTREE_DEBUG
+static void funbuff_debug(t_funbuff *x, t_floatarg f)
+{
+ hammertree_debug(&x->x_tree, (int)f);
+}
+#endif
+
+static void funbuff_free(t_funbuff *x)
+{
+ hammerfile_free(x->x_filehandle);
+ hammertree_clear(&x->x_tree, 0);
+}
+
+static void *funbuff_new(t_symbol *s)
+{
+ t_funbuff *x = (t_funbuff *)pd_new(funbuff_class);
+ x->x_canvas = canvas_getcurrent();
+ x->x_valueset = 0;
+ x->x_pointer = 0;
+ x->x_pointerset = 0;
+ x->x_lastdelta = 0;
+ x->x_embedflag = 0;
+ hammertree_init(&x->x_tree, 0);
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_float);
+ x->x_deltaout = outlet_new((t_object *)x, &s_float);
+ x->x_bangout = outlet_new((t_object *)x, &s_bang);
+ if (s && s != &s_)
+ {
+ x->x_defname = s; /* CHECKME if 'read' changes this */
+ funbuff_doread(x, s);
+ }
+ else x->x_defname = &s_;
+ x->x_filehandle = hammerfile_new((t_pd *)x, funbuff_embedhook,
+ funbuff_readhook, funbuff_writehook, 0);
+ return (x);
+}
+
+void funbuff_setup(void)
+{
+ funbuff_class = class_new(gensym("funbuff"),
+ (t_newmethod)funbuff_new,
+ (t_method)funbuff_free,
+ sizeof(t_funbuff), 0, A_DEFSYM, 0);
+ class_addbang(funbuff_class, funbuff_bang);
+ class_addfloat(funbuff_class, funbuff_float);
+ class_addmethod(funbuff_class, (t_method)funbuff_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_clear,
+ gensym("clear"), 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_goto,
+ gensym("goto"), A_FLOAT, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_min,
+ gensym("min"), 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_max,
+ gensym("max"), 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_next,
+ gensym("next"), 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_embed,
+ gensym("embed"), A_FLOAT, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_read,
+ gensym("read"), A_DEFSYM, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_write,
+ gensym("write"), A_DEFSYM, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_set,
+ gensym("set"), A_GIMME, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_delete,
+ gensym("delete"), A_GIMME, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_find,
+ gensym("find"), A_FLOAT, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_dump,
+ gensym("dump"), 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_interp,
+ gensym("interp"), A_FLOAT, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_interptab,
+ gensym("interptab"), A_FLOAT, A_SYMBOL, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_reduce,
+ gensym("reduce"), A_FLOAT, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_select,
+ gensym("select"), A_FLOAT, A_FLOAT, 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_cut,
+ gensym("cut"), 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_copy,
+ gensym("copy"), 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_paste,
+ gensym("paste"), 0);
+ class_addmethod(funbuff_class, (t_method)funbuff_undo,
+ gensym("undo"), 0);
+#ifdef HAMMERTREE_DEBUG
+ class_addmethod(funbuff_class, (t_method)funbuff_debug,
+ gensym("debug"), A_DEFFLOAT, 0);
+#endif
+ hammerfile_setup(funbuff_class, 1);
+}
diff --git a/cyclone/hammer/funnel.c b/cyclone/hammer/funnel.c
new file mode 100644
index 0000000..d289d8d
--- /dev/null
+++ b/cyclone/hammer/funnel.c
@@ -0,0 +1,179 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+#define FUNNEL_MINSLOTS 2
+#define FUNNEL_INISIZE 32 /* LATER rethink */
+#define FUNNEL_MAXSIZE 256
+
+typedef struct _funnel
+{
+ t_object x_ob;
+ int x_nslots;
+ int x_nproxies; /* as requested (and allocated) */
+ t_pd **x_proxies;
+} t_funnel;
+
+typedef struct _funnel_proxy
+{
+ t_object p_ob;
+ t_outlet *p_out; /* master outlet (the same value for each slot) */
+ int p_id; /* adjusted according to an offset argument */
+ t_float p_value;
+ int p_size; /* as allocated */
+ t_atom *p_message;
+ t_atom p_messini[FUNNEL_INISIZE];
+ int p_entered;
+} t_funnel_proxy;
+
+static t_class *funnel_class;
+static t_class *funnel_proxy_class;
+
+static void funnel_proxy_bang(t_funnel_proxy *x)
+{
+ t_atom at[2];
+ SETFLOAT(&at[0], x->p_id);
+ SETFLOAT(&at[1], x->p_value);
+ outlet_list(x->p_out, &s_list, 2, at);
+}
+
+static void funnel_proxy_float(t_funnel_proxy *x, t_float f)
+{
+ x->p_value = f;
+ funnel_proxy_bang(x);
+}
+
+static void funnel_proxy_list(t_funnel_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ int reentered = x->p_entered;
+ int prealloc = !reentered;
+ int ntotal = ac + 1;
+ x->p_entered = 1;
+ if (prealloc && ntotal > x->p_size)
+ {
+ if (ntotal > FUNNEL_MAXSIZE)
+ prealloc = 0;
+ else
+ {
+ x->p_message = grow_nodata(&ntotal, &x->p_size, x->p_message,
+ FUNNEL_INISIZE, x->p_messini,
+ sizeof(*x->p_message));
+ ac = ntotal - 1;
+ }
+ }
+ /* LATER consider a compatibility warning if av->a_type != A_FLOAT */
+ x->p_value = ((ac && av->a_type == A_FLOAT) ? av->a_w.w_float : 0);
+ if (prealloc)
+ {
+ SETFLOAT(x->p_message, x->p_id);
+ if (ac)
+ memcpy(x->p_message + 1, av, ac * sizeof(*x->p_message));
+ outlet_list(x->p_out, &s_list, ntotal, x->p_message);
+ }
+ else
+ {
+ /* LATER consider using the stack if ntotal <= MAXSTACK */
+ t_atom *buf = getbytes(ntotal * sizeof(*buf));
+ if (buf)
+ {
+ SETFLOAT(buf, x->p_id);
+ if (ac)
+ memcpy(buf + 1, av, ac * sizeof(*buf));
+ outlet_list(x->p_out, &s_list, ntotal, buf);
+ freebytes(buf, ntotal * sizeof(*buf));
+ }
+ }
+ if (!reentered) x->p_entered = 0;
+}
+
+static void funnel_bang(t_funnel *x)
+{
+ funnel_proxy_bang((t_funnel_proxy *)x->x_proxies[0]);
+}
+
+static void funnel_float(t_funnel *x, t_float f)
+{
+ funnel_proxy_float((t_funnel_proxy *)x->x_proxies[0], f);
+}
+
+static void funnel_list(t_funnel *x, t_symbol *s, int ac, t_atom *av)
+{
+ funnel_proxy_list((t_funnel_proxy *)x->x_proxies[0], s, ac, av);
+}
+
+static void funnel_free(t_funnel *x)
+{
+ if (x->x_proxies)
+ {
+ int i = x->x_nslots;
+ while (i--)
+ {
+ t_funnel_proxy *y = (t_funnel_proxy *)x->x_proxies[i];
+ if (y->p_message != y->p_messini)
+ freebytes(y->p_message, y->p_size * sizeof(*y->p_message));
+ pd_free((t_pd *)y);
+ }
+ freebytes(x->x_proxies, x->x_nproxies * sizeof(*x->x_proxies));
+ }
+}
+
+static void *funnel_new(t_floatarg f1, t_floatarg f2)
+{
+ t_funnel *x;
+ int i, nslots, nproxies = (int)f1;
+ int offset = (int)f2;
+ t_outlet *out;
+ t_pd **proxies;
+ if (nproxies < 1) /* CHECKED: one-slot funnel may be created */
+ nproxies = FUNNEL_MINSLOTS;
+ if (!(proxies = (t_pd **)getbytes(nproxies * sizeof(*proxies))))
+ return (0);
+ for (nslots = 0; nslots < nproxies; nslots++)
+ if (!(proxies[nslots] = pd_new(funnel_proxy_class))) break;
+ if (!nslots)
+ {
+ freebytes(proxies, nproxies * sizeof(*proxies));
+ return (0);
+ }
+ x = (t_funnel *)pd_new(funnel_class);
+ x->x_nslots = nslots;
+ x->x_nproxies = nproxies;
+ x->x_proxies = proxies;
+ out = outlet_new((t_object *)x, &s_list);
+ for (i = 0; i < nslots; i++)
+ {
+ t_funnel_proxy *y = (t_funnel_proxy *)proxies[i];
+ y->p_out = out;
+ y->p_id = offset++;
+ y->p_value = 0;
+ y->p_size = FUNNEL_INISIZE;
+ y->p_message = y->p_messini;
+ y->p_entered = 0;
+ if (i) inlet_new((t_object *)x, (t_pd *)y, 0, 0);
+ }
+ return (x);
+}
+
+void funnel_setup(void)
+{
+ funnel_class = class_new(gensym("funnel"),
+ (t_newmethod)funnel_new,
+ (t_method)funnel_free,
+ sizeof(t_funnel), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addbang(funnel_class, funnel_bang);
+ class_addfloat(funnel_class, funnel_float);
+ class_addlist(funnel_class, funnel_list);
+ /* CHECKED: funnel doesn't understand symbol, anything */
+ funnel_proxy_class = class_new(gensym("_funnel_proxy"), 0, 0,
+ sizeof(t_funnel_proxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addbang(funnel_proxy_class, funnel_proxy_bang);
+ class_addfloat(funnel_proxy_class, funnel_proxy_float);
+ class_addlist(funnel_proxy_class, funnel_proxy_list);
+ /* CHECKED: funnel doesn't understand symbol, anything */
+}
diff --git a/cyclone/hammer/gate.c b/cyclone/hammer/gate.c
new file mode 100644
index 0000000..2dbae57
--- /dev/null
+++ b/cyclone/hammer/gate.c
@@ -0,0 +1,147 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+
+#define GATE_MINOUTS 1
+#define GATE_MAXOUTS 100
+#define GATE_DEFOUTS 1
+
+typedef struct _gate
+{
+ t_object x_ob;
+ int x_open;
+ t_pd *x_proxy;
+ int x_nouts; /* requested + 1 (as allocated) */
+ t_outlet **x_outs;
+} t_gate;
+
+typedef struct _gate_proxy
+{
+ t_object p_ob;
+ t_gate *p_master;
+} t_gate_proxy;
+
+static t_class *gate_class;
+static t_class *gate_proxy_class;
+
+static void gate_proxy_bang(t_gate_proxy *x)
+{
+ t_gate *master = x->p_master;
+ if (master->x_open)
+ outlet_bang(master->x_outs[master->x_open]);
+}
+
+static void gate_proxy_float(t_gate_proxy *x, t_float f)
+{
+ t_gate *master = x->p_master;
+ if (master->x_open)
+ outlet_float(master->x_outs[master->x_open], f);
+}
+
+static void gate_proxy_symbol(t_gate_proxy *x, t_symbol *s)
+{
+ t_gate *master = x->p_master;
+ if (master->x_open)
+ outlet_symbol(master->x_outs[master->x_open], s);
+}
+
+static void gate_proxy_pointer(t_gate_proxy *x, t_gpointer *gp)
+{
+ t_gate *master = x->p_master;
+ if (master->x_open)
+ outlet_pointer(master->x_outs[master->x_open], gp);
+}
+
+static void gate_proxy_list(t_gate_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ t_gate *master = x->p_master;
+ if (master->x_open)
+ outlet_list(master->x_outs[master->x_open], s, ac, av);
+}
+
+static void gate_proxy_anything(t_gate_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ t_gate *master = x->p_master;
+ if (master->x_open)
+ outlet_anything(master->x_outs[master->x_open], s, ac, av);
+}
+
+static void gate_float(t_gate *x, t_float f)
+{
+ int i = (int)f;
+ if (i < 0) i = 1;
+ if (i >= x->x_nouts) i = x->x_nouts - 1;
+ x->x_open = i;
+}
+
+static void gate_bang(t_gate *x)
+{
+ outlet_float(x->x_outs[1], x->x_open);
+}
+
+static void gate_free(t_gate *x)
+{
+ if (x->x_proxy) pd_free(x->x_proxy);
+ if (x->x_outs)
+ freebytes(x->x_outs, x->x_nouts * sizeof(*x->x_outs));
+}
+
+static void *gate_new(t_floatarg f1, t_floatarg f2)
+{
+ t_gate *x;
+ int i, nouts = (int)f1;
+ t_outlet **outs;
+ t_pd *proxy;
+ if (nouts < GATE_MINOUTS)
+ nouts = GATE_DEFOUTS;
+ if (nouts > GATE_MAXOUTS)
+ loud_incompatible_max(gate_class, GATE_MAXOUTS, "outlets");
+ nouts++; /* for convenience (the cost is one pointer) */
+ if (!(outs = (t_outlet **)getbytes(nouts * sizeof(*outs))))
+ return (0);
+ if (!(proxy = pd_new(gate_proxy_class)))
+ {
+ freebytes(outs, nouts * sizeof(*outs));
+ return (0);
+ }
+ x = (t_gate *)pd_new(gate_class);
+ x->x_nouts = nouts;
+ x->x_outs = outs;
+ x->x_proxy = proxy;
+ ((t_gate_proxy *)proxy)->p_master = x;
+ /* from max sdk manual: ``The dst parameter can be changed (or set to 0)
+ dynamically with the inlet_to function... The gate object uses this
+ technique to assign its inlet to one of several outlets, or no outlet
+ at all.'' We have to use a proxy, because Pd's outlet is not a t_pd
+ (besides, Pd does not handle inlets with null destination). */
+ inlet_new((t_object *)x, proxy, 0, 0);
+ for (i = 1; i < nouts; i++)
+ x->x_outs[i] = outlet_new((t_object *)x, &s_anything);
+ gate_float(x, (f2 > 0 ? f2 : 0)); /* CHECKED */
+ return (x);
+}
+
+void gate_setup(void)
+{
+ gate_class = class_new(gensym("gate"),
+ (t_newmethod)gate_new,
+ (t_method)gate_free,
+ sizeof(t_gate), 0,
+ A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addfloat(gate_class, gate_float);
+ class_addbang(gate_class, gate_bang);
+ gate_proxy_class = class_new(gensym("_gate_proxy"), 0, 0,
+ sizeof(t_gate_proxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addfloat(gate_proxy_class, gate_proxy_float);
+ class_addbang(gate_proxy_class, gate_proxy_bang);
+ class_addsymbol(gate_proxy_class, gate_proxy_symbol);
+ class_addpointer(gate_proxy_class, gate_proxy_pointer);
+ class_addlist(gate_proxy_class, gate_proxy_list);
+ class_addanything(gate_proxy_class, gate_proxy_anything);
+}
diff --git a/cyclone/hammer/grab.c b/cyclone/hammer/grab.c
new file mode 100644
index 0000000..a54a3eb
--- /dev/null
+++ b/cyclone/hammer/grab.c
@@ -0,0 +1,279 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "unstable/pd_imp.h"
+#include "unstable/fragile.h"
+#include "common/loud.h"
+
+/* LATER handle canvas grabbing (bypass) */
+/* LATER check self-grabbing */
+/* LATER fragilize */
+
+/* It would be nice to have write access to o_connections field... */
+
+struct _outlet
+{
+ t_object *o_owner;
+ struct _outlet *o_next;
+ t_outconnect *o_connections;
+ t_symbol *o_sym;
+};
+
+/* ...and to have bindlist traversal routines in Pd API. */
+
+static t_class *bindlist_class = 0;
+
+typedef struct _bindelem
+{
+ t_pd *e_who;
+ struct _bindelem *e_next;
+} t_bindelem;
+
+typedef struct _bindlist
+{
+ t_pd b_pd;
+ t_bindelem *b_list;
+} t_bindlist;
+
+typedef struct _grab
+{
+ t_object x_ob;
+ t_symbol *x_target;
+ int x_noutlets; /* not counting right one */
+ t_outconnect **x_grabcons; /* grabbed connections */
+ t_outlet *x_rightout; /* right outlet */
+ /* traversal helpers: */
+ t_object *x_grabbed; /* currently grabbed object */
+ t_outconnect *x_tograbbed; /* a connection to grabbed object */
+ int x_ngrabout; /* number of grabbed object's outlets */
+ t_bindelem *x_bindelem;
+} t_grab;
+
+static t_class *grab_class;
+
+static void grab_start(t_grab *x)
+{
+ x->x_tograbbed = 0;
+ x->x_bindelem = 0;
+ if (x->x_target)
+ {
+ t_pd *proxy = x->x_target->s_thing;
+ t_object *ob;
+ if (proxy && bindlist_class)
+ {
+ if (*proxy == bindlist_class)
+ {
+ x->x_bindelem = ((t_bindlist *)proxy)->b_list;
+ while (x->x_bindelem)
+ {
+ if (ob = pd_checkobject(x->x_bindelem->e_who))
+ {
+ x->x_tograbbed =
+ fragile_outlet_connections(ob->ob_outlet);
+ return;
+ }
+ x->x_bindelem = x->x_bindelem->e_next;
+ }
+ }
+ else if (ob = pd_checkobject(proxy))
+ x->x_tograbbed = fragile_outlet_connections(ob->ob_outlet);
+ }
+ }
+ else x->x_tograbbed = fragile_outlet_connections(x->x_rightout);
+}
+
+static t_pd *grab_next(t_grab *x)
+{
+nextremote:
+ if (x->x_tograbbed)
+ {
+ t_inlet *ip;
+ int inno;
+ x->x_tograbbed = obj_nexttraverseoutlet(x->x_tograbbed,
+ &x->x_grabbed, &ip, &inno);
+ if (x->x_grabbed)
+ {
+ if (inno)
+ {
+ if (x->x_target)
+ loud_error((t_pd *)x,
+ "right outlet must feed leftmost inlet");
+ else
+ loud_error((t_pd *)x,
+ "remote proxy must feed leftmost inlet");
+ }
+ else
+ {
+ t_outlet *op;
+ t_outlet *goutp;
+ int goutno = x->x_noutlets;
+ x->x_ngrabout = obj_noutlets(x->x_grabbed);
+ if (goutno > x->x_ngrabout) goutno = x->x_ngrabout;
+ while (goutno--)
+ {
+ x->x_grabcons[goutno] =
+ obj_starttraverseoutlet(x->x_grabbed, &goutp, goutno);
+ goutp->o_connections =
+ obj_starttraverseoutlet((t_object *)x, &op, goutno);
+ }
+ return ((t_pd *)x->x_grabbed);
+ }
+ }
+ }
+ if (x->x_bindelem) while (x->x_bindelem = x->x_bindelem->e_next)
+ {
+ t_object *ob;
+ if (ob = pd_checkobject(x->x_bindelem->e_who))
+ {
+ x->x_tograbbed = fragile_outlet_connections(ob->ob_outlet);
+ goto nextremote;
+ }
+ }
+ return (0);
+}
+
+static void grab_restore(t_grab *x)
+{
+ t_outlet *goutp;
+ int goutno = x->x_noutlets;
+ if (goutno > x->x_ngrabout) goutno = x->x_ngrabout;
+ while (goutno--)
+ {
+ obj_starttraverseoutlet(x->x_grabbed, &goutp, goutno);
+ goutp->o_connections = x->x_grabcons[goutno];
+ }
+}
+
+static void grab_bang(t_grab *x)
+{
+ t_pd *grabbed;
+ grab_start(x);
+ while (grabbed = grab_next(x))
+ {
+ pd_bang(grabbed);
+ grab_restore(x);
+ }
+}
+
+static void grab_float(t_grab *x, t_float f)
+{
+ t_pd *grabbed;
+ grab_start(x);
+ while (grabbed = grab_next(x))
+ {
+ pd_float(grabbed, f);
+ grab_restore(x);
+ }
+}
+
+static void grab_symbol(t_grab *x, t_symbol *s)
+{
+ t_pd *grabbed;
+ grab_start(x);
+ while (grabbed = grab_next(x))
+ {
+ pd_symbol(grabbed, s);
+ grab_restore(x);
+ }
+}
+
+static void grab_pointer(t_grab *x, t_gpointer *gp)
+{
+ t_pd *grabbed;
+ grab_start(x);
+ while (grabbed = grab_next(x))
+ {
+ pd_pointer(grabbed, gp);
+ grab_restore(x);
+ }
+}
+
+static void grab_list(t_grab *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_pd *grabbed;
+ grab_start(x);
+ while (grabbed = grab_next(x))
+ {
+ pd_list(grabbed, s, ac, av);
+ grab_restore(x);
+ }
+}
+
+static void grab_anything(t_grab *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_pd *grabbed;
+ grab_start(x);
+ while (grabbed = grab_next(x))
+ {
+ typedmess(grabbed, s, ac, av);
+ grab_restore(x);
+ }
+}
+
+static void grab_set(t_grab *x, t_symbol *s)
+{
+ if (x->x_target && s && s != &s_) x->x_target = s;
+}
+
+/* LATER use A_GIMME */
+static void *grab_new(t_symbol *s, t_floatarg f)
+{
+ t_grab *x;
+ t_outconnect **grabcons;
+ int i, noutlets = (int)f;
+ if (noutlets < 1) noutlets = 1;
+ if (!(grabcons = getbytes(noutlets * sizeof(*grabcons))))
+ return (0);
+ x = (t_grab *)pd_new(grab_class);
+ x->x_noutlets = noutlets;
+ x->x_grabcons = grabcons;
+ while (noutlets--) outlet_new((t_object *)x, &s_anything);
+ if (s && s != &s_)
+ {
+ x->x_target = s;
+ x->x_rightout = 0;
+ }
+ else
+ {
+ x->x_target = 0;
+ x->x_rightout = outlet_new((t_object *)x, &s_anything);
+ }
+ return (x);
+}
+
+static void grab_free(t_grab *x)
+{
+ if (x->x_grabcons)
+ freebytes(x->x_grabcons, x->x_noutlets * sizeof(*x->x_grabcons));
+}
+
+void grab_setup(void)
+{
+ t_symbol *s = gensym("grab");
+ grab_class = class_new(s, (t_newmethod)grab_new,
+ (t_method)grab_free,
+ sizeof(t_grab), 0,
+ A_DEFFLOAT, A_DEFSYMBOL, 0);
+ class_addfloat(grab_class, grab_float);
+ class_addbang(grab_class, grab_bang);
+ class_addsymbol(grab_class, grab_symbol);
+ class_addpointer(grab_class, grab_pointer);
+ class_addlist(grab_class, grab_list);
+ class_addanything(grab_class, grab_anything);
+ class_addmethod(grab_class, (t_method)grab_set,
+ gensym("set"), A_SYMBOL, 0);
+ if (!bindlist_class)
+ {
+ t_class *c = grab_class;
+ pd_bind(&grab_class, s);
+ pd_bind(&c, s);
+ if (!s->s_thing
+ || !(bindlist_class = *s->s_thing)
+ || bindlist_class->c_name != gensym("bindlist"))
+ error("grab: failure to initialize remote grabbing feature");
+ pd_unbind(&c, s);
+ pd_unbind(&grab_class, s);
+ }
+}
diff --git a/cyclone/hammer/hammer.c b/cyclone/hammer/hammer.c
new file mode 100644
index 0000000..a4d7efe
--- /dev/null
+++ b/cyclone/hammer/hammer.c
@@ -0,0 +1,93 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <stdio.h>
+#include "m_pd.h"
+#include "unstable/fragile.h"
+#include "common/loud.h"
+#include "common/port.h"
+#include "hammer/file.h"
+#include "../build_counter"
+void allhammers_setup(void);
+
+typedef struct _hammer
+{
+ t_object x_ob;
+ t_symbol *x_dir;
+ t_hammerfile *x_filehandle;
+} t_hammer;
+
+static t_class *hammer_class;
+static int hammer_firstndx;
+static int hammer_lastndx;
+
+static void hammer_readhook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ import_max(fn->s_name, "");
+}
+
+static void hammer_import(t_hammer *x, t_symbol *fn, t_symbol *dir)
+{
+ if (fn && fn != &s_)
+ {
+ if (!dir || dir == &s_) dir = x->x_dir;
+ import_max(fn->s_name, (dir && dir != &s_) ? dir->s_name : "");
+ }
+ else
+ hammerpanel_open(x->x_filehandle);
+}
+
+static void hammer_click(t_hammer *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ hammer_import(x, 0, 0);
+}
+
+static void hammer_bang(t_hammer *x)
+{
+ fragile_class_printnames("hammer classes are: ",
+ hammer_firstndx, hammer_lastndx);
+}
+
+static void hammer_free(t_hammer *x)
+{
+ hammerfile_free(x->x_filehandle);
+}
+
+static void *hammer_new(t_symbol *s)
+{
+ t_hammer *x = (t_hammer *)pd_new(hammer_class);
+ x->x_filehandle = hammerfile_new((t_pd *)x, 0, hammer_readhook, 0, 0);
+ x->x_dir = (s && s != &s_ ? s : canvas_getdir(x->x_filehandle->f_canvas));
+ return (x);
+}
+
+void hammer_setup(void)
+{
+ if (canvas_getcurrent())
+ {
+ /* Loading the library by object creation is banned, because of a danger
+ of having some of the classes already loaded. LATER rethink. */
+ loud_error(0, "apparently an attempt to create a 'hammer' object");
+ loud_errand(0, "without having hammer library preloaded");
+ return;
+ }
+ if (!zgetfn(&pd_objectmaker, gensym("cyclone")))
+ post("this is hammer %s, %s %s build",
+ CYCLONE_VERSION, loud_ordinal(CYCLONE_BUILD), CYCLONE_RELEASE);
+ hammer_class = class_new(gensym("hammer"),
+ (t_newmethod)hammer_new,
+ (t_method)hammer_free,
+ sizeof(t_hammer), 0, A_DEFSYM, 0);
+ class_addbang(hammer_class, hammer_bang);
+ class_addmethod(hammer_class, (t_method)hammer_import,
+ gensym("import"), A_DEFSYM, A_DEFSYM, 0);
+ class_addmethod(hammer_class, (t_method)hammer_click,
+ gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ hammerfile_setup(hammer_class, 0);
+ hammer_firstndx = fragile_class_count();
+ allhammers_setup();
+ hammer_lastndx = fragile_class_count() - 1;
+}
diff --git a/cyclone/hammer/iter.c b/cyclone/hammer/iter.c
new file mode 100644
index 0000000..0aa5ef8
--- /dev/null
+++ b/cyclone/hammer/iter.c
@@ -0,0 +1,112 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* This is a modified version of Joseph A. Sarlo's code.
+ The most important changes are listed in "pd-lib-notes.txt" file. */
+
+/* LATER compare with iter.c from max sdk */
+/* LATER clean up buffer handling */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+#define ITER_INISIZE 8 /* LATER rethink */
+
+typedef struct _iter
+{
+ t_object x_ob;
+ int x_size; /* as allocated */
+ int x_natoms; /* as used */
+ t_symbol *x_selector;
+ t_atom *x_message;
+ t_atom x_messini[ITER_INISIZE];
+} t_iter;
+
+static t_class *iter_class;
+
+/* CHECKED: both floats and symbols */
+static void iter_dobang(t_iter *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (s && s != &s_)
+ outlet_symbol(((t_object *)x)->ob_outlet, s);
+ while (ac--)
+ {
+ if (av->a_type == A_FLOAT)
+ outlet_float(((t_object *)x)->ob_outlet, av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL)
+ outlet_symbol(((t_object *)x)->ob_outlet, av->a_w.w_symbol);
+ av++;
+ }
+}
+
+static void iter_bang(t_iter *x)
+{
+ iter_dobang(x, x->x_selector, x->x_natoms, x->x_message);
+}
+
+static void iter_float(t_iter *x, t_float f)
+{
+ outlet_float(((t_object *)x)->ob_outlet, f);
+ x->x_selector = 0;
+ x->x_natoms = 1;
+ SETFLOAT(x->x_message, f);
+}
+
+/* CHECKME */
+static void iter_symbol(t_iter *x, t_symbol *s)
+{
+ outlet_symbol(((t_object *)x)->ob_outlet, s);
+ x->x_selector = 0;
+ x->x_natoms = 1;
+ SETSYMBOL(x->x_message, s);
+}
+
+/* LATER gpointer */
+
+static void iter_anything(t_iter *x, t_symbol *s, int ac, t_atom *av)
+{
+ iter_dobang(x, s, ac, av);
+ x->x_selector = s;
+ if (ac > x->x_size)
+ x->x_message = grow_nodata(&ac, &x->x_size, x->x_message,
+ ITER_INISIZE, x->x_messini,
+ sizeof(*x->x_message));
+ x->x_natoms = ac;
+ memcpy(x->x_message, av, ac * sizeof(*x->x_message));
+}
+
+static void iter_list(t_iter *x, t_symbol *s, int ac, t_atom *av)
+{
+ iter_anything(x, 0, ac, av);
+}
+
+static void iter_free(t_iter *x)
+{
+ if (x->x_message != x->x_messini)
+ freebytes(x->x_message, x->x_natoms * sizeof(*x->x_message));
+}
+
+static void *iter_new(void)
+{
+ t_iter *x = (t_iter *)pd_new(iter_class);
+ x->x_size = ITER_INISIZE;
+ x->x_natoms = 0;
+ x->x_message = x->x_messini;
+ outlet_new((t_object *)x, &s_anything);
+ return (x);
+}
+
+void iter_setup(void)
+{
+ iter_class = class_new(gensym("iter"),
+ (t_newmethod)iter_new,
+ (t_method)iter_free,
+ sizeof(t_iter), 0, 0);
+ class_addbang(iter_class, iter_bang);
+ class_addfloat(iter_class, iter_float);
+ class_addsymbol(iter_class, iter_symbol);
+ class_addlist(iter_class, iter_list);
+ class_addanything(iter_class, iter_anything);
+}
diff --git a/cyclone/hammer/match.c b/cyclone/hammer/match.c
new file mode 100644
index 0000000..d5b03c7
--- /dev/null
+++ b/cyclone/hammer/match.c
@@ -0,0 +1,216 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* LATER compare with match.c from max sdk */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+#define MATCH_INISIZE 8 /* LATER rethink */
+
+typedef struct _match
+{
+ t_object x_ob;
+ int x_size; /* as allocated */
+ int x_patlen; /* as used */
+ t_atom *x_pattern;
+ t_atom x_patini[MATCH_INISIZE];
+ int x_quelen;
+ t_atom *x_queue;
+ t_atom x_queini[MATCH_INISIZE];
+ t_atom *x_queend;
+ t_atom *x_queptr; /* writing head, post-incremented (oldest-pointing) */
+} t_match;
+
+static t_class *match_class;
+
+static void match_clear(t_match *x)
+{
+ x->x_quelen = 0;
+ x->x_queptr = x->x_queue;
+}
+
+/* x->x_patlen > 0 is assumed */
+/* LATER use a lock to disable reentrant calls. I do not see any
+ purpose of reentering match, but lets CHECKME first... */
+static void match_checkin(t_match *x)
+{
+ int i, patlen = x->x_patlen;
+ t_atom *queptr, *pp, *qp;
+ if (x->x_queptr >= x->x_queend)
+ x->x_queptr = x->x_queue;
+ else x->x_queptr++;
+ if (x->x_quelen < patlen && ++(x->x_quelen) < patlen)
+ return;
+
+ qp = queptr = x->x_queptr;
+ for (i = 0, pp = x->x_pattern; i < patlen; i++, pp++)
+ {
+ if (pp->a_type == A_FLOAT)
+ {
+ if (qp->a_type != A_FLOAT || qp->a_w.w_float != pp->a_w.w_float)
+ break;
+ }
+ else if (pp->a_type == A_SYMBOL)
+ {
+ if (qp->a_type != A_SYMBOL || qp->a_w.w_symbol != pp->a_w.w_symbol)
+ break;
+ }
+ else if (pp->a_type == A_NULL)
+ {
+ if (qp->a_type == A_FLOAT || qp->a_type == A_SYMBOL)
+ {
+ /* instantiating a pattern */
+ *pp = *qp;
+ qp->a_type = A_NULL;
+ }
+ else break; /* LATER rethink */
+ }
+ else break; /* LATER rethink */
+ if (qp >= x->x_queend)
+ qp = x->x_queue;
+ else qp++;
+ }
+ if (i == patlen)
+ {
+ pp = x->x_pattern;
+ if (pp->a_type == A_FLOAT)
+ {
+ if (patlen == 1)
+ outlet_float(((t_object *)x)->ob_outlet, pp->a_w.w_float);
+ else
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, patlen, pp);
+ }
+ else /* assuming A_SYMBOL (see above) */
+ {
+ if (pp->a_w.w_symbol == &s_symbol /* bypassing typedmess() */
+ && patlen == 2 && pp[1].a_type == A_SYMBOL)
+ outlet_symbol(((t_object *)x)->ob_outlet, pp[1].a_w.w_symbol);
+ else
+ outlet_anything(((t_object *)x)->ob_outlet, pp->a_w.w_symbol,
+ patlen - 1, pp + 1);
+ }
+ /* CHECKED: no implicit clear (resolving overlapping patterns) */
+ }
+ /* restoring a pattern */
+ for (i = 0, pp = x->x_pattern; i < patlen; i++, pp++)
+ {
+ if (queptr->a_type == A_NULL)
+ {
+ queptr->a_type = pp->a_type;
+ pp->a_type = A_NULL;
+ }
+ if (queptr >= x->x_queend)
+ queptr = x->x_queue;
+ else queptr++;
+ }
+}
+
+static void match_float(t_match *x, t_float f)
+{
+ if (x->x_patlen)
+ {
+ SETFLOAT(x->x_queptr, f);
+ match_checkin(x);
+ }
+}
+
+static void match_symbol(t_match *x, t_symbol *s)
+{
+ if (s && s != &s_ && x->x_patlen)
+ {
+ SETSYMBOL(x->x_queptr, s);
+ match_checkin(x);
+ }
+}
+
+/* LATER gpointer */
+
+static void match_list(t_match *x, t_symbol *s, int ac, t_atom *av)
+{
+ while (ac--)
+ {
+ if (av->a_type == A_FLOAT) match_float(x, av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL) match_symbol(x, av->a_w.w_symbol);
+ av++;
+ }
+}
+
+static void match_anything(t_match *x, t_symbol *s, int ac, t_atom *av)
+{
+ match_symbol(x, s);
+ match_list(x, 0, ac, av);
+}
+
+static void match_set(t_match *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac) /* CHECKED */
+ {
+ t_atom *pp;
+ t_symbol *ps_nn;
+ int newlen = ac * 2;
+ if (newlen > x->x_size)
+ {
+ x->x_pattern = grow_nodata(&newlen, &x->x_size, x->x_pattern,
+ MATCH_INISIZE * 2, x->x_patini,
+ sizeof(*x->x_pattern));
+ if (newlen == MATCH_INISIZE * 2)
+ {
+ x->x_queue = x->x_queini;
+ ac = MATCH_INISIZE;
+ }
+ else x->x_queue = x->x_pattern + x->x_size / 2;
+ }
+ x->x_patlen = ac;
+ x->x_queend = x->x_queue + ac - 1;
+ match_clear(x); /* CHECKED */
+ memcpy(x->x_pattern, av, ac * sizeof(*x->x_pattern));
+ pp = x->x_pattern;
+ ps_nn = gensym("nn");
+ while (ac--)
+ {
+ if (pp->a_type == A_SYMBOL && pp->a_w.w_symbol == ps_nn)
+ pp->a_type = A_NULL;
+ pp++;
+ }
+ }
+}
+
+static void match_free(t_match *x)
+{
+ if (x->x_pattern != x->x_patini)
+ freebytes(x->x_pattern, 2 * x->x_size * sizeof(*x->x_pattern));
+}
+
+static void *match_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_match *x = (t_match *)pd_new(match_class);
+ x->x_size = MATCH_INISIZE * 2;
+ x->x_patlen = 0;
+ x->x_pattern = x->x_patini;
+ x->x_queue = x->x_queini;
+ /* x->x_queend is not used unless x->x_patlen > 0,
+ LATER consider chosing a more defensive way... */
+ outlet_new((t_object *)x, &s_anything);
+ match_clear(x);
+ match_set(x, 0, ac, av);
+ return (x);
+}
+
+void match_setup(void)
+{
+ match_class = class_new(gensym("match"),
+ (t_newmethod)match_new,
+ (t_method)match_free,
+ sizeof(t_match), 0, A_GIMME, 0);
+ class_addfloat(match_class, match_float);
+ class_addsymbol(match_class, match_symbol);
+ class_addlist(match_class, match_list);
+ class_addanything(match_class, match_anything);
+ class_addmethod(match_class, (t_method)match_set,
+ gensym("set"), A_GIMME, 0);
+ class_addmethod(match_class, (t_method)match_clear,
+ gensym("clear"), 0);
+}
diff --git a/cyclone/hammer/maximum.c b/cyclone/hammer/maximum.c
new file mode 100644
index 0000000..038d8f1
--- /dev/null
+++ b/cyclone/hammer/maximum.c
@@ -0,0 +1,88 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+
+typedef struct _maximum
+{
+ t_object x_ob;
+ t_float x_last;
+ t_float x_test;
+} t_maximum;
+
+static t_class *maximum_class;
+
+static void maximum_bang(t_maximum *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_last);
+}
+
+static void maximum_float(t_maximum *x, t_float f)
+{
+ outlet_float(((t_object *)x)->ob_outlet,
+ x->x_last = (f > x->x_test ? f : x->x_test));
+}
+
+static void maximum_list(t_maximum *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac > 256) loud_incompatible_max(*(t_pd *)x, 256, "items");
+ while (ac && av->a_type != A_FLOAT) ac--, av++; /* CHECKME (a warning?) */
+ if (ac)
+ {
+ t_float fpick = av->a_w.w_float;
+ ac--; av++;
+ while (ac && av->a_type != A_FLOAT) ac--, av++; /* CHECKME */
+ if (ac)
+ {
+ t_float fnext, f = av->a_w.w_float;
+ if (f > fpick)
+ {
+ fnext = fpick;
+ fpick = f;
+ }
+ else fnext = f;
+ ac--; av++;
+ while (ac--)
+ {
+ if (av->a_type == A_FLOAT)
+ {
+ f = av->a_w.w_float;
+ if (f > fpick)
+ {
+ fnext = fpick;
+ fpick = f;
+ }
+ else if (f > fnext) fnext = f;
+ }
+ /* CHECKME else */
+ av++;
+ }
+ x->x_test = fnext;
+ outlet_float(((t_object *)x)->ob_outlet, x->x_last = fpick);
+ }
+ else maximum_float(x, fpick); /* CHECKME */
+ }
+ /* CHECKME else */
+}
+
+static void *maximum_new(t_floatarg f)
+{
+ t_maximum *x = (t_maximum *)pd_new(maximum_class);
+ x->x_last = 0; /* CHECKME */
+ x->x_test = f;
+ floatinlet_new((t_object *)x, &x->x_test);
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void maximum_setup(void)
+{
+ maximum_class = class_new(gensym("maximum"),
+ (t_newmethod)maximum_new, 0,
+ sizeof(t_maximum), 0, A_DEFFLOAT, 0);
+ class_addbang(maximum_class, maximum_bang);
+ class_addfloat(maximum_class, maximum_float);
+ class_addlist(maximum_class, maximum_list);
+}
diff --git a/cyclone/hammer/mean.c b/cyclone/hammer/mean.c
new file mode 100644
index 0000000..13d69ff
--- /dev/null
+++ b/cyclone/hammer/mean.c
@@ -0,0 +1,79 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+
+typedef struct _mean
+{
+ t_object x_ob;
+ double x_accum;
+ unsigned x_count;
+ t_float x_mean;
+ t_outlet *x_countout;
+} t_mean;
+
+static t_class *mean_class;
+
+static void mean_clear(t_mean *x)
+{
+ x->x_accum = 0;
+ x->x_count = 0;
+ x->x_mean = 0;
+}
+
+static void mean_bang(t_mean *x)
+{
+ /* CHECKED: count is always sent (first) */
+ outlet_float(x->x_countout, x->x_count);
+ outlet_float(((t_object *)x)->ob_outlet, x->x_mean);
+}
+
+static void mean_float(t_mean *x, t_float f)
+{
+ x->x_accum += f;
+ if (++x->x_count)
+ x->x_mean = (t_float)(x->x_accum / (double)x->x_count);
+ else mean_clear(x);
+ mean_bang(x);
+}
+
+static void mean_list(t_mean *x, t_symbol *s, int ac, t_atom *av)
+{
+ mean_clear(x);
+ while (ac--)
+ {
+ if (av->a_type == A_FLOAT)
+ {
+ x->x_accum += av->a_w.w_float;
+ x->x_count++;
+ }
+ av++;
+ }
+ if (x->x_count)
+ x->x_mean = (t_float)(x->x_accum / (double)x->x_count);
+ else mean_clear(x);
+ mean_bang(x);
+ /* CHECKED: no clear after list -- subsequent floats are added */
+}
+
+static void *mean_new(void)
+{
+ t_mean *x = (t_mean *)pd_new(mean_class);
+ mean_clear(x);
+ outlet_new((t_object *)x, &s_float);
+ x->x_countout = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void mean_setup(void)
+{
+ mean_class = class_new(gensym("mean"),
+ (t_newmethod)mean_new, 0,
+ sizeof(t_mean), 0, 0);
+ class_addbang(mean_class, mean_bang);
+ class_addfloat(mean_class, mean_float);
+ class_addlist(mean_class, mean_list);
+ class_addmethod(mean_class, (t_method)mean_clear,
+ gensym("clear"), 0);
+}
diff --git a/cyclone/hammer/midiflush.c b/cyclone/hammer/midiflush.c
new file mode 100644
index 0000000..592d9e0
--- /dev/null
+++ b/cyclone/hammer/midiflush.c
@@ -0,0 +1,102 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+
+#define MIDIFLUSH_NCHANNELS 16
+#define MIDIFLUSH_NPITCHES 128
+#define MIDIFLUSH_VOIDPITCH 0xFF
+
+typedef struct _midiflush
+{
+ t_object x_ob;
+ unsigned char x_status;
+ unsigned char x_channel;
+ unsigned char x_pitch;
+ unsigned char x_notes[MIDIFLUSH_NCHANNELS][MIDIFLUSH_NPITCHES];
+} t_midiflush;
+
+static t_class *midiflush_class;
+
+static void midiflush_float(t_midiflush *x, t_float f)
+{
+ int ival = (int)f;
+ if (ival >= 0 && ival < 256)
+ {
+ unsigned char bval = ival;
+ outlet_float(((t_object *)x)->ob_outlet, bval);
+ if (bval & 0x80)
+ {
+ x->x_status = bval & 0xF0;
+ if (x->x_status == 0x80 || x->x_status == 0x90)
+ x->x_channel = bval & 0x0F;
+ else
+ x->x_status = 0;
+ }
+ else if (x->x_status)
+ {
+ if (x->x_pitch == MIDIFLUSH_VOIDPITCH)
+ {
+ x->x_pitch = bval;
+ return;
+ }
+ else if (x->x_status == 0x90 && bval)
+ {
+ x->x_notes[x->x_channel][x->x_pitch]++;
+ }
+ else
+ {
+ x->x_notes[x->x_channel][x->x_pitch]--;
+ }
+ }
+ }
+ x->x_pitch = MIDIFLUSH_VOIDPITCH;
+}
+
+static void midiflush_bang(t_midiflush *x)
+{
+ int chn, pch;
+ for (chn = 0; chn < MIDIFLUSH_NCHANNELS; chn++)
+ {
+ for (pch = 0; pch < MIDIFLUSH_NPITCHES; pch++)
+ {
+ int status = 0x090 | chn;
+ while (x->x_notes[chn][pch])
+ {
+ outlet_float(((t_object *)x)->ob_outlet, status);
+ outlet_float(((t_object *)x)->ob_outlet, pch);
+ outlet_float(((t_object *)x)->ob_outlet, 0);
+ x->x_notes[chn][pch]--;
+ }
+ }
+ }
+}
+
+static void midiflush_clear(t_midiflush *x)
+{
+ memset(x->x_notes, 0, sizeof(x->x_notes));
+}
+
+static void *midiflush_new(void)
+{
+ t_midiflush *x = (t_midiflush *)pd_new(midiflush_class);
+ x->x_status = 0; /* `not a note' */
+ x->x_pitch = MIDIFLUSH_VOIDPITCH;
+ midiflush_clear(x);
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void midiflush_setup(void)
+{
+ midiflush_class = class_new(gensym("midiflush"),
+ (t_newmethod)midiflush_new,
+ 0, /* CHECKED: no flushout */
+ sizeof(t_midiflush), 0, 0);
+ class_addfloat(midiflush_class, midiflush_float);
+ class_addbang(midiflush_class, midiflush_bang);
+ class_addmethod(midiflush_class, (t_method)midiflush_clear,
+ gensym("clear"), 0);
+}
diff --git a/cyclone/hammer/midiformat.c b/cyclone/hammer/midiformat.c
new file mode 100644
index 0000000..fa0612b
--- /dev/null
+++ b/cyclone/hammer/midiformat.c
@@ -0,0 +1,112 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+
+typedef struct _midiformat
+{
+ t_object x_ob;
+ t_float x_channel;
+} t_midiformat;
+
+static t_class *midiformat_class;
+
+static int midiformat_channel(t_midiformat *x)
+{
+ int ch = (int)x->x_channel;
+ return (ch > 0 ? (ch - 1) & 0x0F : 0);
+}
+
+static void midiformat_note(t_midiformat *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac >= 2 && av[0].a_type == A_FLOAT && av[1].a_type == A_FLOAT)
+ {
+ int pitch = (int)av[0].a_w.w_float; /* CHECKED: anything goes */
+ int velocity = (int)av[1].a_w.w_float;
+ outlet_float(((t_object *)x)->ob_outlet, 0x90 | midiformat_channel(x));
+ outlet_float(((t_object *)x)->ob_outlet, pitch);
+ outlet_float(((t_object *)x)->ob_outlet, velocity);
+ }
+}
+
+static void midiformat_polytouch(t_midiformat *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ if (ac >= 2 && av[0].a_type == A_FLOAT && av[1].a_type == A_FLOAT)
+ {
+ int touch = (int)av[0].a_w.w_float;
+ int key = (int)av[1].a_w.w_float;
+ outlet_float(((t_object *)x)->ob_outlet, 0xA0 | midiformat_channel(x));
+ outlet_float(((t_object *)x)->ob_outlet, key);
+ outlet_float(((t_object *)x)->ob_outlet, touch);
+ }
+}
+
+static void midiformat_controller(t_midiformat *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ if (ac >= 2 && av[0].a_type == A_FLOAT && av[1].a_type == A_FLOAT)
+ {
+ int val = (int)av[0].a_w.w_float;
+ int ctl = (int)av[1].a_w.w_float;
+ outlet_float(((t_object *)x)->ob_outlet, 0xB0 | midiformat_channel(x));
+ outlet_float(((t_object *)x)->ob_outlet, ctl);
+ outlet_float(((t_object *)x)->ob_outlet, val);
+ }
+}
+
+static void midiformat_program(t_midiformat *x, t_floatarg f)
+{
+ int pgm = (int)f;
+ outlet_float(((t_object *)x)->ob_outlet, 0xC0 | midiformat_channel(x));
+ outlet_float(((t_object *)x)->ob_outlet, pgm);
+}
+
+static void midiformat_touch(t_midiformat *x, t_floatarg f)
+{
+ int touch = (int)f;
+ outlet_float(((t_object *)x)->ob_outlet, 0xD0 | midiformat_channel(x));
+ outlet_float(((t_object *)x)->ob_outlet, touch);
+}
+
+static void midiformat_bend(t_midiformat *x, t_floatarg f)
+{
+ int val = (int)f;
+ outlet_float(((t_object *)x)->ob_outlet, 0xE0 | midiformat_channel(x));
+ outlet_float(((t_object *)x)->ob_outlet, 0);
+ outlet_float(((t_object *)x)->ob_outlet, val);
+}
+
+static void *midiformat_new(t_floatarg f)
+{
+ t_midiformat *x = (t_midiformat *)pd_new(midiformat_class);
+ x->x_channel = f;
+ inlet_new((t_object *)x, (t_pd *)x, &s_list, gensym("lst1"));
+ inlet_new((t_object *)x, (t_pd *)x, &s_list, gensym("lst2"));
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft3"));
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft4"));
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft5"));
+ floatinlet_new((t_object *)x, &x->x_channel);
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void midiformat_setup(void)
+{
+ midiformat_class = class_new(gensym("midiformat"),
+ (t_newmethod)midiformat_new, 0,
+ sizeof(t_midiformat), 0,
+ A_DEFFLOAT, 0);
+ class_addlist(midiformat_class, midiformat_note);
+ class_addmethod(midiformat_class, (t_method)midiformat_polytouch,
+ gensym("lst1"), A_GIMME, 0);
+ class_addmethod(midiformat_class, (t_method)midiformat_controller,
+ gensym("lst2"), A_GIMME, 0);
+ class_addmethod(midiformat_class, (t_method)midiformat_program,
+ gensym("ft3"), A_FLOAT, 0);
+ class_addmethod(midiformat_class, (t_method)midiformat_touch,
+ gensym("ft4"), A_FLOAT, 0);
+ class_addmethod(midiformat_class, (t_method)midiformat_bend,
+ gensym("ft5"), A_FLOAT, 0);
+}
diff --git a/cyclone/hammer/midiparse.c b/cyclone/hammer/midiparse.c
new file mode 100644
index 0000000..9a79a39
--- /dev/null
+++ b/cyclone/hammer/midiparse.c
@@ -0,0 +1,132 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+
+typedef struct _midiparse
+{
+ t_object x_ob;
+ unsigned char x_ready;
+ unsigned char x_status;
+ unsigned char x_channel;
+ unsigned char x_data1;
+ t_outlet *x_polyout;
+ t_outlet *x_ctlout;
+ t_outlet *x_pgmout;
+ t_outlet *x_touchout;
+ t_outlet *x_bendout;
+ t_outlet *x_chanout;
+} t_midiparse;
+
+static t_class *midiparse_class;
+
+static void midiparse_clear(t_midiparse *x)
+{
+ x->x_status = 0;
+ x->x_ready = 0;
+}
+
+static void midiparse_float(t_midiparse *x, t_float f)
+{
+ int ival = (int)f; /* CHECKED */
+ if (ival < 0)
+ {
+ /* CHECKME */
+ return;
+ }
+ if (ival < 256) /* CHECKED clear if input over 255 */
+ {
+ unsigned char bval = ival;
+ if (bval & 0x80)
+ {
+ unsigned char status = bval & 0xF0;
+ if (status == 0xF0)
+ {
+ /* CHECKED no such test in max -- this is incompatible,
+ but real-time messages are out-of-band, and they
+ should be ignored here. LATER rethink the 0xFE case. */
+ if (bval < 0xF8)
+ midiparse_clear(x);
+ }
+ else
+ {
+ x->x_status = status;
+ x->x_channel = bval & 0x0F;
+ x->x_ready = (status == 0xC0 || status == 0xD0);
+ }
+ }
+ else if (x->x_ready)
+ {
+ t_atom at[2];
+ x->x_ready = 0;
+ outlet_float(x->x_chanout, x->x_channel + 1);
+ switch (x->x_status)
+ {
+ case 0x80:
+ SETFLOAT(&at[0], x->x_data1);
+ SETFLOAT(&at[1], 0);
+ outlet_list(((t_object *)x)->ob_outlet, 0, 2, at);
+ break;
+ case 0x90:
+ SETFLOAT(&at[0], x->x_data1);
+ SETFLOAT(&at[1], bval);
+ outlet_list(((t_object *)x)->ob_outlet, 0, 2, at);
+ break;
+ case 0xA0:
+ SETFLOAT(&at[0], bval);
+ SETFLOAT(&at[1], x->x_data1);
+ outlet_list(x->x_polyout, 0, 2, at);
+ break;
+ case 0xB0:
+ SETFLOAT(&at[0], bval);
+ SETFLOAT(&at[1], x->x_data1);
+ outlet_list(x->x_ctlout, 0, 2, at);
+ break;
+ case 0xC0:
+ outlet_float(x->x_pgmout, bval);
+ x->x_ready = 1;
+ break;
+ case 0xD0:
+ outlet_float(x->x_touchout, bval);
+ x->x_ready = 1;
+ break;
+ case 0xE0:
+ /* CHECKED: ignores data1 */
+ outlet_float(x->x_bendout, bval);
+ break;
+ default:;
+ }
+ }
+ else if (x->x_status)
+ {
+ x->x_data1 = bval; /* CHECKED key #0 accepted */
+ x->x_ready = 1;
+ }
+ }
+ else midiparse_clear(x);
+}
+
+static void *midiparse_new(void)
+{
+ t_midiparse *x = (t_midiparse *)pd_new(midiparse_class);
+ outlet_new((t_object *)x, &s_list);
+ x->x_polyout = outlet_new((t_object *)x, &s_list);
+ x->x_ctlout = outlet_new((t_object *)x, &s_list);
+ x->x_pgmout = outlet_new((t_object *)x, &s_float);
+ x->x_touchout = outlet_new((t_object *)x, &s_float);
+ x->x_bendout = outlet_new((t_object *)x, &s_float);
+ x->x_chanout = outlet_new((t_object *)x, &s_float);
+ midiparse_clear(x);
+ return (x);
+}
+
+void midiparse_setup(void)
+{
+ midiparse_class = class_new(gensym("midiparse"),
+ (t_newmethod)midiparse_new, 0,
+ sizeof(t_midiparse), 0, 0);
+ class_addbang(midiparse_class, midiparse_clear);
+ class_addfloat(midiparse_class, midiparse_float);
+ /* CHECKED autocasting lists to floats */
+}
diff --git a/cyclone/hammer/minimum.c b/cyclone/hammer/minimum.c
new file mode 100644
index 0000000..466b6f8
--- /dev/null
+++ b/cyclone/hammer/minimum.c
@@ -0,0 +1,88 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+
+typedef struct _minimum
+{
+ t_object x_ob;
+ t_float x_last;
+ t_float x_test;
+} t_minimum;
+
+static t_class *minimum_class;
+
+static void minimum_bang(t_minimum *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_last);
+}
+
+static void minimum_float(t_minimum *x, t_float f)
+{
+ outlet_float(((t_object *)x)->ob_outlet,
+ x->x_last = (f < x->x_test ? f : x->x_test));
+}
+
+static void minimum_list(t_minimum *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac > 256) loud_incompatible_max(*(t_pd *)x, 256, "items");
+ while (ac && av->a_type != A_FLOAT) ac--, av++; /* CHECKME (a warning?) */
+ if (ac)
+ {
+ t_float fpick = av->a_w.w_float;
+ ac--; av++;
+ while (ac && av->a_type != A_FLOAT) ac--, av++; /* CHECKME */
+ if (ac)
+ {
+ t_float fnext, f = av->a_w.w_float;
+ if (f < fpick)
+ {
+ fnext = fpick;
+ fpick = f;
+ }
+ else fnext = f;
+ ac--; av++;
+ while (ac--)
+ {
+ if (av->a_type == A_FLOAT)
+ {
+ f = av->a_w.w_float;
+ if (f < fpick)
+ {
+ fnext = fpick;
+ fpick = f;
+ }
+ else if (f < fnext) fnext = f;
+ }
+ /* CHECKME else */
+ av++;
+ }
+ x->x_test = fnext;
+ outlet_float(((t_object *)x)->ob_outlet, x->x_last = fpick);
+ }
+ else minimum_float(x, fpick); /* CHECKME */
+ }
+ /* CHECKME else */
+}
+
+static void *minimum_new(t_floatarg f)
+{
+ t_minimum *x = (t_minimum *)pd_new(minimum_class);
+ x->x_last = 0; /* CHECKME */
+ x->x_test = f;
+ floatinlet_new((t_object *)x, &x->x_test);
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void minimum_setup(void)
+{
+ minimum_class = class_new(gensym("minimum"),
+ (t_newmethod)minimum_new, 0,
+ sizeof(t_minimum), 0, A_DEFFLOAT, 0);
+ class_addbang(minimum_class, minimum_bang);
+ class_addfloat(minimum_class, minimum_float);
+ class_addlist(minimum_class, minimum_list);
+}
diff --git a/cyclone/hammer/mousefilter.c b/cyclone/hammer/mousefilter.c
new file mode 100644
index 0000000..e2e3cc5
--- /dev/null
+++ b/cyclone/hammer/mousefilter.c
@@ -0,0 +1,70 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "hammer/gui.h"
+
+typedef struct _mousefilter
+{
+ t_object x_ob;
+ int x_isup;
+ int x_ispending;
+ t_float x_value;
+} t_mousefilter;
+
+static t_class *mousefilter_class;
+
+static void mousefilter_float(t_mousefilter *x, t_float f)
+{
+ if (x->x_isup)
+ outlet_float(((t_object *)x)->ob_outlet, f);
+ else
+ {
+ x->x_ispending = 1;
+ x->x_value = f;
+ }
+}
+
+static void mousefilter_anything(t_mousefilter *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ /* dummy method, filtering out those messages from gui,
+ which are not handled explicitly */
+}
+
+static void mousefilter_doup(t_mousefilter *x, t_floatarg f)
+{
+ if ((x->x_isup = (int)f) && x->x_ispending)
+ {
+ x->x_ispending = 0;
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+ }
+}
+
+static void mousefilter_free(t_mousefilter *x)
+{
+ hammergui_unbindmouse((t_pd *)x);
+}
+
+static void *mousefilter_new(void)
+{
+ t_mousefilter *x = (t_mousefilter *)pd_new(mousefilter_class);
+ x->x_isup = 0; /* LATER rethink */
+ x->x_ispending = 0;
+ outlet_new((t_object *)x, &s_float);
+ hammergui_bindmouse((t_pd *)x);
+ return (x);
+}
+
+void mousefilter_setup(void)
+{
+ mousefilter_class = class_new(gensym("mousefilter"),
+ (t_newmethod)mousefilter_new,
+ (t_method)mousefilter_free,
+ sizeof(t_mousefilter), 0, 0);
+ class_addfloat(mousefilter_class, mousefilter_float);
+ class_addanything(mousefilter_class, mousefilter_anything);
+ class_addmethod(mousefilter_class, (t_method)mousefilter_doup,
+ gensym("_up"), A_FLOAT, 0);
+}
diff --git a/cyclone/hammer/next.c b/cyclone/hammer/next.c
new file mode 100644
index 0000000..3fe7d6e
--- /dev/null
+++ b/cyclone/hammer/next.c
@@ -0,0 +1,58 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+
+//#define NEXT_USEEVENTNO
+
+typedef struct _next
+{
+ t_object x_ob;
+#ifdef NEXT_USEEVENTNO
+ int x_lastevent;
+#else
+ double x_lastevent;
+#endif
+ t_outlet *x_out2;
+} t_next;
+
+static t_class *next_class;
+
+/* CHECKME first call, CHECKME if the outlets are not swapped */
+static void next_anything(t_next *x, t_symbol *s, int ac, t_atom *av)
+{
+#ifdef NEXT_USEEVENTNO
+ int nextevent = sys_geteventno();
+#else
+ double nextevent = clock_getlogicaltime();
+#endif
+ if (x->x_lastevent == nextevent)
+ outlet_bang(x->x_out2);
+ else
+ {
+ x->x_lastevent = nextevent;
+ outlet_bang(((t_object *)x)->ob_outlet);
+ }
+}
+
+static void *next_new(void)
+{
+ t_next *x = (t_next *)pd_new(next_class);
+ outlet_new((t_object *)x, &s_bang);
+ x->x_out2 = outlet_new((t_object *)x, &s_bang);
+#ifdef NEXT_USEEVENTNO
+ x->x_lastevent = sys_geteventno();
+#else
+ x->x_lastevent = clock_getlogicaltime();
+#endif
+ return (x);
+}
+
+void next_setup(void)
+{
+ next_class = class_new(gensym("next"),
+ (t_newmethod)next_new, 0,
+ sizeof(t_next), 0, 0);
+ class_addanything(next_class, next_anything);
+}
diff --git a/cyclone/hammer/offer.c b/cyclone/hammer/offer.c
new file mode 100644
index 0000000..3823c85
--- /dev/null
+++ b/cyclone/hammer/offer.c
@@ -0,0 +1,94 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+#include "hammer/tree.h"
+
+/* As a class `derived' from the common hammertree code (also in funbuff),
+ offer uses the auxiliary list, generally not needed here.
+ As a side-effect, it gets a bonus of a small speedup of deletion,
+ and a penalty of a small slowdown of insertion. */
+
+typedef struct _offer
+{
+ t_object x_ob;
+ t_float x_value;
+ int x_valueset;
+ t_hammertree x_tree;
+} t_offer;
+
+static t_class *offer_class;
+
+static void offer_float(t_offer *x, t_float f)
+{
+ int ndx;
+ if (loud_checkint((t_pd *)x, f, &ndx, &s_float)) /* CHECKED */
+ {
+ t_hammernode *np;
+ if (x->x_valueset)
+ {
+ if (np = hammertree_insert(&x->x_tree, ndx))
+ np->n_value = x->x_value;
+ x->x_valueset = 0;
+ }
+ else if (np = hammertree_search(&x->x_tree, ndx))
+ {
+ outlet_float(((t_object *)x)->ob_outlet, np->n_value);
+ hammertree_delete(&x->x_tree, np);
+ }
+ }
+}
+
+static void offer_ft1(t_offer *x, t_floatarg f)
+{
+ /* this is incompatible -- CHECKED float is silently truncated */
+ x->x_value = f;
+ x->x_valueset = 1;
+}
+
+static void offer_clear(t_offer *x)
+{
+ hammertree_clear(&x->x_tree, 0);
+ /* CHECKED valueset is not cleared */
+}
+
+#ifdef HAMMERTREE_DEBUG
+static void offer_debug(t_offer *x, t_floatarg f)
+{
+ hammertree_debug(&x->x_tree, (int)f);
+}
+#endif
+
+static void offer_free(t_offer *x)
+{
+ hammertree_clear(&x->x_tree, 0);
+}
+
+static void *offer_new(void)
+{
+ t_offer *x = (t_offer *)pd_new(offer_class);
+ x->x_valueset = 0;
+ hammertree_init(&x->x_tree, 0);
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void offer_setup(void)
+{
+ offer_class = class_new(gensym("offer"),
+ (t_newmethod)offer_new,
+ (t_method)offer_free,
+ sizeof(t_offer), 0, 0);
+ class_addfloat(offer_class, offer_float);
+ class_addmethod(offer_class, (t_method)offer_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(offer_class, (t_method)offer_clear,
+ gensym("clear"), 0);
+#ifdef HAMMERTREE_DEBUG
+ class_addmethod(offer_class, (t_method)offer_debug,
+ gensym("debug"), A_DEFFLOAT, 0);
+#endif
+}
diff --git a/cyclone/hammer/onebang.c b/cyclone/hammer/onebang.c
new file mode 100644
index 0000000..a4132dc
--- /dev/null
+++ b/cyclone/hammer/onebang.c
@@ -0,0 +1,46 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+
+typedef struct _onebang
+{
+ t_object x_ob;
+ int x_isopen;
+} t_onebang;
+
+static t_class *onebang_class;
+
+static void onebang_bang(t_onebang *x)
+{
+ if (x->x_isopen)
+ {
+ outlet_bang(((t_object *)x)->ob_outlet);
+ x->x_isopen = 0;
+ }
+}
+
+static void onebang_bang1(t_onebang *x)
+{
+ x->x_isopen = 1;
+}
+
+static void *onebang_new(t_floatarg f)
+{
+ t_onebang *x = (t_onebang *)pd_new(onebang_class);
+ x->x_isopen = ((int)f != 0); /* CHECKED */
+ inlet_new((t_object *)x, (t_pd *)x, &s_bang, gensym("bang1"));
+ outlet_new((t_object *)x, &s_bang);
+ return (x);
+}
+
+void onebang_setup(void)
+{
+ onebang_class = class_new(gensym("onebang"),
+ (t_newmethod)onebang_new, 0,
+ sizeof(t_onebang), 0, A_DEFFLOAT, 0);
+ class_addbang(onebang_class, onebang_bang);
+ class_addmethod(onebang_class, (t_method)onebang_bang1,
+ gensym("bang1"), 0);
+}
diff --git a/cyclone/hammer/past.c b/cyclone/hammer/past.c
new file mode 100644
index 0000000..eb29c8e
--- /dev/null
+++ b/cyclone/hammer/past.c
@@ -0,0 +1,154 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* CHECKED:
+ bang for a float at > (refman error: >=)
+ bang for a list if all >= (refman page says the same)
+ bang for a list if any is >, even if the rest (but not previous) is <
+ well...
+*/
+
+#include "m_pd.h"
+#include "common/loud.h"
+#include "common/grow.h"
+
+#define PAST_MAXSIZE 8 /* CHECKED */
+
+typedef struct past
+{
+ t_object x_ob;
+ int x_low;
+ int x_size; /* as allocated */
+ int x_nthresh; /* as used */
+ t_atom *x_thresh;
+ t_atom x_thrini[PAST_MAXSIZE];
+} t_past;
+
+static t_class *past_class;
+
+static int past_compare(t_past *x, t_float f, t_atom *ap)
+{
+ if (ap->a_type == A_FLOAT)
+ {
+ if (f > ap->a_w.w_float)
+ return (1);
+ else if (f == ap->a_w.w_float)
+ return (0);
+ else
+ return (-1);
+ }
+ else /* CHECKED */
+ {
+ if (f > 0.)
+ return (1);
+ else if (f == 0.)
+ return (0);
+ else
+ return (-1);
+ }
+}
+
+static void past_float(t_past *x, t_float f)
+{
+ if (x->x_nthresh == 1)
+ {
+ if (past_compare(x, f, x->x_thresh) > 0) /* CHECKED: equal is low */
+ {
+ if (x->x_low)
+ {
+ x->x_low = 0;
+ outlet_bang(((t_object *)x)->ob_outlet);
+ }
+ }
+ else x->x_low = 1;
+ }
+ else if (past_compare(x, f, x->x_thresh) < 0) x->x_low = 1;
+}
+
+/* CHECKME: x_low handling */
+static void past_list(t_past *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac && ac <= x->x_nthresh)
+ {
+ int result;
+ t_atom *vp = x->x_thresh;
+ if (av->a_type == A_FLOAT
+ && (result = past_compare(x, av->a_w.w_float, vp)) >= 0)
+ {
+ if (!result)
+ {
+ for (ac--, av++, vp++; ac; ac--, av++, vp++)
+ {
+ if (av->a_type != A_FLOAT
+ || (result =
+ past_compare(x, av->a_w.w_float, vp++)) < 0)
+ {
+ x->x_low = 1;
+ return;
+ }
+ if (result) break;
+ }
+ }
+ if (x->x_low)
+ {
+ x->x_low = 0;
+ outlet_bang(((t_object *)x)->ob_outlet);
+ }
+ }
+ else x->x_low = 1;
+ }
+}
+
+static void past_clear(t_past *x)
+{
+ x->x_low = 1;
+}
+
+static void past_set(t_past *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ t_atom *vp = x->x_thresh;
+ if (ac > x->x_size)
+ {
+ loud_incompatible_max(past_class, PAST_MAXSIZE, "guard points");
+ x->x_thresh = grow_nodata(&ac, &x->x_size, x->x_thresh,
+ PAST_MAXSIZE, x->x_thrini,
+ sizeof(*x->x_thresh));
+ }
+ x->x_nthresh = ac;
+ while (ac--) *vp++ = *av++;
+ /* CHECKED: x_low is not set here */
+ }
+}
+
+static void past_free(t_past *x)
+{
+ if (x->x_thresh != x->x_thrini)
+ freebytes(x->x_thresh, x->x_size * sizeof(*x->x_thresh));
+}
+
+static void *past_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_past *x = (t_past *)pd_new(past_class);
+ x->x_low = 1;
+ x->x_nthresh = 0;
+ x->x_size = PAST_MAXSIZE;
+ x->x_thresh = x->x_thrini;
+ outlet_new((t_object *)x, &s_bang);
+ past_set(x, 0, ac, av);
+ return (x);
+}
+
+void past_setup(void)
+{
+ past_class = class_new(gensym("past"),
+ (t_newmethod)past_new,
+ (t_method)past_free,
+ sizeof(t_past), 0, A_GIMME, 0);
+ class_addfloat(past_class, past_float);
+ class_addlist(past_class, past_list);
+ class_addmethod(past_class, (t_method)past_clear, gensym("clear"), 0);
+ class_addmethod(past_class, (t_method)past_set, gensym("set"), A_GIMME, 0);
+}
diff --git a/cyclone/hammer/pd-lib-notes.txt b/cyclone/hammer/pd-lib-notes.txt
new file mode 100644
index 0000000..8b45005
--- /dev/null
+++ b/cyclone/hammer/pd-lib-notes.txt
@@ -0,0 +1,61 @@
+modifications to Joseph A. Sarlo's code (formerly part of `pd-lib')
+-------------------------------------------------------------------
+
+LATER: more testing, max-checking, resolving reentrancy, gc, etc.
+
+accum: only cosmetics
+
+bangbang:
+- if argument > 2 the array is dynamically allocated
+- if argument > 40 (max in max), a warning is printed
+- accepts any message
+
+Bucket:
+- arrays are dynamically allocated, no upper limit (max has no limit too)
+- outlets output in right-to-left order
+- added: 'set' method, 'l2r' and 'r2l' aliases
+
+buddy: coded from scratch
+- using array of proxy objects (accepting any message)
+- no upper limit for number of slots
+
+capture: coded from scratch
+- text editor, savepanel
+- any size
+- circular buffering
+
+counter (rewritten entirely):
+- using proxies to handle bangs and floats in other inlets than first
+- new `engine', counter_dobang(), coded from scratch
+- various adjustments of things that turned out to work differently in max,
+ too many to list here (and probably more are required -- please let me know!)
+
+cycle:
+- the array of outlets is dynamically allocated
+- fixing cycle_list()'s bugs
+- accepting (and sending) both floats and symbols, accepting anything
+- 'thresh' and 'set' methods
+- event-sensitive mode emulation (a temporary hack)
+
+Decode (rewritten entirely):
+- if argument > 8 the array is dynamically allocated (with a warning)
+- all outlets deliver after any action
+- outlets output in right-to-left order
+- while in all-off mode, input is stored, not ignored
+- out-of-range input is clipped, not ignored
+
+Histo (rewritten entirely):
+- creation argument added (size)
+- the array is dynamically allocated, no upper limit (max has no limit too)
+- check if input is in range, to prevent crashes :)
+- 'bang' method
+
+iter:
+- different method of memory allocation
+- dripping both floats and symbols (max4 feature)
+- 'anything' method
+
+match: coded from scratch
+- matching stream of both floats and symbols (max4 feature)
+- scanning all kinds of messages, not only separate floats
+- recognizing overlapping patterns
diff --git a/cyclone/hammer/poltocar.c b/cyclone/hammer/poltocar.c
new file mode 100644
index 0000000..486eead
--- /dev/null
+++ b/cyclone/hammer/poltocar.c
@@ -0,0 +1,44 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define sinf sin
+#define cosf cos
+#endif
+
+typedef struct _poltocar
+{
+ t_object x_ob;
+ t_float x_phase;
+ t_outlet *x_out2;
+} t_poltocar;
+
+static t_class *poltocar_class;
+
+static void poltocar_float(t_poltocar *x, t_float f)
+{
+ outlet_float(x->x_out2, f * sinf(x->x_phase));
+ outlet_float(((t_object *)x)->ob_outlet, f * cosf(x->x_phase));
+}
+
+static void *poltocar_new(void)
+{
+ t_poltocar *x = (t_poltocar *)pd_new(poltocar_class);
+ floatinlet_new((t_object *)x, &x->x_phase);
+ outlet_new((t_object *)x, &s_float);
+ x->x_out2 = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void poltocar_setup(void)
+{
+ poltocar_class = class_new(gensym("poltocar"),
+ (t_newmethod)poltocar_new, 0,
+ sizeof(t_poltocar), 0, 0);
+ class_addfloat(poltocar_class, poltocar_float);
+}
diff --git a/cyclone/hammer/prepend.c b/cyclone/hammer/prepend.c
new file mode 100644
index 0000000..567bb73
--- /dev/null
+++ b/cyclone/hammer/prepend.c
@@ -0,0 +1,258 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/loud.h"
+#include "common/grow.h"
+
+#define PREPEND_INISIZE 32 /* LATER rethink */
+#define PREPEND_MAXSIZE 256
+
+typedef struct _prepend
+{
+ t_object x_ob;
+ t_symbol *x_selector;
+ int x_size; /* as allocated */
+ int x_natoms; /* as used */
+ t_atom *x_message;
+ t_atom x_messini[PREPEND_INISIZE];
+ int x_entered;
+ int x_auxsize;
+ t_atom *x_auxbuf;
+} t_prepend;
+
+static t_class *prepend_class;
+
+/* Usually a preallocation method is used, except in special cases of:
+ 1) reentrant output request, or 2) an output request which would cause
+ resizing to more than MAXSIZE (no such limit for a 'set' message).
+ In both special cases, a temporary output buffer is allocated.
+ A separately preallocated output buffer is not used, thus avoiding
+ memcpying of the stored message (a small performance gain when the
+ preallocation method is chosen). Instead, self-invoked 'set'
+ messages are postponed, using an auxiliary buffer.
+*/
+
+static void prepend_dooutput(t_prepend *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (s == &s_float)
+ {
+ if (ac > 1)
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av);
+ else
+ outlet_float(((t_object *)x)->ob_outlet, av->a_w.w_float);
+ }
+ else if (s == &s_list)
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av);
+ else if (s)
+ /* CHECKED: 'bang' is prepended -- we cannot do so...
+ ('symbol' cannot be compatible too) */
+ {
+ outlet_anything(((t_object *)x)->ob_outlet, s, ac, av);
+ }
+}
+
+static void prepend_anything(t_prepend *x, t_symbol *s, int ac, t_atom *av)
+{
+ int reentered = x->x_entered;
+ int prealloc = !reentered;
+ int ntotal = x->x_natoms + ac;
+ t_atom *buf;
+ x->x_entered = 1;
+ if (s == &s_) s = 0;
+ if (s)
+ ntotal++;
+ if (prealloc && ntotal > x->x_size)
+ {
+ if (ntotal > PREPEND_MAXSIZE)
+ prealloc = 0;
+ else
+ {
+ int nrequested = ntotal;
+ x->x_message = grow_withdata(&nrequested, &x->x_natoms,
+ &x->x_size, x->x_message,
+ PREPEND_INISIZE, x->x_messini,
+ sizeof(*x->x_message));
+ prealloc = (nrequested == ntotal);
+ }
+ }
+ if (prealloc)
+ {
+ buf = x->x_message + x->x_natoms;
+ if (s)
+ {
+ SETSYMBOL(buf, s);
+ buf++;
+ }
+ if (ac)
+ memcpy(buf, av, ac * sizeof(*buf));
+ prepend_dooutput(x, x->x_selector, ntotal, x->x_message);
+ }
+ else
+ {
+ /* LATER consider using the stack if ntotal <= MAXSTACK */
+ if (buf = getbytes(ntotal * sizeof(*buf)))
+ {
+ t_atom *bp = buf + x->x_natoms;
+ if (x->x_natoms)
+ memcpy(buf, x->x_message, x->x_natoms * sizeof(*buf));
+ if (s)
+ {
+ SETSYMBOL(bp, s);
+ bp++;
+ }
+ if (ac)
+ memcpy(bp, av, ac * sizeof(*bp));
+ prepend_dooutput(x, x->x_selector, ntotal, buf);
+ freebytes(buf, ntotal * sizeof(*buf));
+ }
+ }
+ if (!reentered)
+ {
+ x->x_entered = 0;
+ if (x->x_auxbuf)
+ {
+ if (x->x_auxsize <= x->x_size)
+ {
+ x->x_natoms = x->x_auxsize / 2;
+ memcpy(x->x_message, x->x_auxbuf,
+ x->x_natoms * sizeof(*x->x_message));
+ freebytes(x->x_auxbuf, x->x_auxsize * sizeof(*x->x_auxbuf));
+ }
+ else
+ {
+ if (x->x_message != x->x_messini)
+ freebytes(x->x_message, x->x_size * sizeof(*x->x_message));
+ x->x_size = x->x_auxsize;
+ x->x_message = x->x_auxbuf;
+ x->x_natoms = x->x_auxsize / 2;
+ }
+ x->x_auxbuf = 0;
+ }
+ }
+}
+
+static void prepend_bang(t_prepend *x)
+{
+ t_atom at;
+ SETSYMBOL(&at, &s_bang); /* CHECKED */
+ prepend_anything(x, 0, 1, &at);
+}
+
+static void prepend_float(t_prepend *x, t_float f)
+{
+ t_atom at;
+ SETFLOAT(&at, f);
+ prepend_anything(x, 0, 1, &at);
+}
+
+static void prepend_symbol(t_prepend *x, t_symbol *s)
+{
+ t_atom at;
+ SETSYMBOL(&at, s);
+ prepend_anything(x, 0, 1, &at);
+}
+
+/* LATER gpointer */
+
+static void prepend_list(t_prepend *x, t_symbol *s, int ac, t_atom *av)
+{
+ prepend_anything(x, 0, ac, av);
+}
+
+static void prepend_set(t_prepend *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ int newsize;
+ if (av->a_type == A_FLOAT)
+ {
+ if (ac > 1) x->x_selector = &s_list;
+ else x->x_selector = &s_float;
+ }
+ else if (av->a_type == A_SYMBOL)
+ {
+ x->x_selector = av->a_w.w_symbol;
+ ac--;
+ av++;
+ }
+ else
+ return; /* LATER rethink */
+ newsize = ac * 2;
+ if (x->x_entered)
+ {
+ if (x->x_auxbuf)
+ {
+ loud_warning((t_pd *)x, "'set' message overridden");
+ freebytes(x->x_auxbuf, x->x_auxsize * sizeof(*x->x_auxbuf));
+ x->x_auxsize = 0;
+ }
+ if (x->x_auxbuf = getbytes(newsize * sizeof(*x->x_auxbuf)))
+ {
+ memcpy(x->x_auxbuf, av, ac * sizeof(*x->x_auxbuf));
+ x->x_auxsize = newsize;
+ }
+ }
+ else
+ {
+ t_atom *ap;
+ if (newsize > x->x_size)
+ {
+ int sz = newsize;
+ x->x_message = grow_nodata(&sz, &x->x_size, x->x_message,
+ PREPEND_INISIZE, x->x_messini,
+ sizeof(*x->x_message));
+ if (sz != newsize)
+ ac = sz / 2; /* LATER rethink */
+ }
+ x->x_natoms = ac;
+ ap = x->x_message;
+ while (ac--) *ap++ = *av++;
+ }
+ }
+}
+
+static void prepend_free(t_prepend *x)
+{
+ if (x->x_message != x->x_messini)
+ freebytes(x->x_message, x->x_size * sizeof(*x->x_message));
+}
+
+static void *prepend_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_prepend *x = (t_prepend *)pd_new(prepend_class);
+ x->x_selector = 0;
+ x->x_size = PREPEND_INISIZE;
+ x->x_natoms = 0;
+ x->x_message = x->x_messini;
+ x->x_auxbuf = 0;
+ x->x_entered = 0;
+ if (!ac)
+ {
+ loud_incompatible(prepend_class,
+ "creating an object without an argument");
+ /* CHECKED: this is not compatible -- in max an object without an outlet
+ is created, and there is no warning if loading from a file. */
+ }
+ outlet_new((t_object *)x, &s_anything);
+ prepend_set(x, 0, ac, av);
+ return (x);
+}
+
+void prepend_setup(void)
+{
+ prepend_class = class_new(gensym("prepend"),
+ (t_newmethod)prepend_new,
+ (t_method)prepend_free,
+ sizeof(t_prepend), 0,
+ A_GIMME, 0);
+ class_addbang(prepend_class, prepend_bang);
+ class_addfloat(prepend_class, prepend_float);
+ class_addsymbol(prepend_class, prepend_symbol);
+ class_addlist(prepend_class, prepend_list);
+ class_addanything(prepend_class, prepend_anything);
+ class_addmethod(prepend_class, (t_method)prepend_set,
+ gensym("set"), A_GIMME, 0);
+}
diff --git a/cyclone/hammer/prob.c b/cyclone/hammer/prob.c
new file mode 100644
index 0000000..5227870
--- /dev/null
+++ b/cyclone/hammer/prob.c
@@ -0,0 +1,312 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <stdio.h>
+#include "m_pd.h"
+#include "common/loud.h"
+#include "common/rand.h"
+#include "hammer/file.h"
+
+/* CHECKED: no preallocation. Apparently, it looks like if the new
+ state-entries were added to the list's head, and the new transition-entries
+ were added to the sublist's head. No sorting of any kind. */
+
+#define PROB_DEBUG 0
+
+typedef struct _probtrans
+{
+ int tr_value; /* state (if a header trans), or suffix value (otherwise) */
+ int tr_count; /* (a total in case of a header trans) */
+ struct _probtrans *tr_suffix; /* header trans of a suffix state */
+ struct _probtrans *tr_nexttrans; /* next trans of this state */
+ struct _probtrans *tr_nextstate; /* header trans of a next state */
+} t_probtrans;
+
+typedef struct _prob
+{
+ t_object x_ob;
+ t_probtrans *x_translist;
+ t_probtrans *x_state;
+ t_probtrans *x_default;
+ int x_embedmode;
+ int x_silent;
+ unsigned int x_seed;
+ t_outlet *x_bangout;
+ t_hammerfile *x_filehandle;
+} t_prob;
+
+static t_class *prob_class;
+
+static t_probtrans *prob_findstate(t_prob *x, int value, int complain)
+{
+ t_probtrans *state;
+ for (state = x->x_translist; state; state = state->tr_nextstate)
+ if (state->tr_value == value)
+ break;
+ if (!state && complain && !x->x_silent)
+ loud_error((t_pd *)x, "no state %d", value); /* CHECKED */
+ return (state);
+}
+
+static void prob_reset(t_prob *x, t_floatarg f)
+{
+ int value = (int)f; /* CHECKED: float converted to int */
+ t_probtrans *state = prob_findstate(x, value, 1);
+ if (state) /* CHECKED */
+ {
+ x->x_default = state;
+ /* CHECKED (sort of): */
+ if (!x->x_state->tr_nexttrans)
+ x->x_state = state;
+ }
+}
+
+/*
+CHECKED: embedmode off:
+#N prob;
+#P newobj ... prob;
+
+CHECKED: embedmode on, after clear:
+#N prob;
+#T embed 1;
+#P newobj ... prob;
+
+CHECKED: embedmode on, filled:
+#N prob;
+#T <preffix> <suffix> <count>
+...
+#T embed 1;
+#T reset <default>; (if set)
+#P newobj ... prob;
+*/
+static void prob_embed(t_prob *x, t_floatarg f)
+{
+ x->x_embedmode = ((int)f != 0);
+ if (x->x_embedmode)
+ loud_incompatible(prob_class, "embedding not supported (yet)...");
+}
+
+static void prob_clear(t_prob *x)
+{
+ t_probtrans *state, *nextstate;
+ for (state = x->x_translist; state; state = nextstate)
+ {
+ t_probtrans *trans, *nexttrans;
+ for (trans = state->tr_nexttrans; trans; trans = nexttrans)
+ {
+ nexttrans = trans->tr_nexttrans;
+ freebytes(trans, sizeof(*trans));
+ }
+ nextstate = state->tr_nextstate;
+ freebytes(state, sizeof(*state));
+ }
+ x->x_translist = 0;
+ x->x_state = 0;
+ x->x_default = 0; /* CHECKED: default number is not kept */
+ /* CHECKED embedmode is kept */
+}
+
+/* CHECKED */
+static void prob_dump(t_prob *x)
+{
+ t_probtrans *state;
+ post("transition probabilities:");
+ for (state = x->x_translist; state; state = state->tr_nextstate)
+ {
+ t_probtrans *trans;
+ for (trans = state->tr_nexttrans; trans; trans = trans->tr_nexttrans)
+ post(" from %3d to %3d: %d",
+ state->tr_value, trans->tr_value, trans->tr_count);
+ /* CHECKED: dead-ends are reported */
+ post("total weights for state %d: %d",
+ state->tr_value, state->tr_count);
+ }
+}
+
+static void prob_bang(t_prob *x)
+{
+ if (x->x_state) /* CHECKED: no output after clear */
+ {
+ int rnd = rand_int(&x->x_seed, x->x_state->tr_count);
+ t_probtrans *trans = x->x_state->tr_nexttrans;
+ if (trans)
+ {
+ for (trans = x->x_state->tr_nexttrans; trans;
+ trans = trans->tr_nexttrans)
+ if ((rnd -= trans->tr_count) < 0)
+ break;
+ if (trans)
+ {
+ t_probtrans *nextstate = trans->tr_suffix;
+ if (nextstate)
+ {
+ outlet_float(((t_object *)x)->ob_outlet,
+ nextstate->tr_value);
+ x->x_state = nextstate;
+ }
+ else bug("prob_bang: void suffix");
+ }
+ else bug("prob_bang: search overflow");
+ }
+ else
+ {
+ outlet_bang(x->x_bangout);
+ if (x->x_default) /* CHECKED: stays at dead-end if no default */
+ x->x_state = x->x_default;
+ }
+ }
+}
+
+static void prob_float(t_prob *x, t_float f)
+{
+ int value;
+ if (loud_checkint((t_pd *)x, f, &value, &s_float)) /* CHECKED */
+ {
+ t_probtrans *state = prob_findstate(x, value, 1);
+ if (state) /* CHECKED */
+ x->x_state = state;
+ }
+}
+
+static void prob_list(t_prob *x, t_symbol *s, int ac, t_atom *av)
+{
+ int prefval, suffval, count;
+ if (ac == 3 && av->a_type == A_FLOAT
+ && av[1].a_type == A_FLOAT && av[2].a_type == A_FLOAT
+ && (prefval = (int)av->a_w.w_float) == av->a_w.w_float
+ && (suffval = (int)av[1].a_w.w_float) == av[1].a_w.w_float
+ && (count = (int)av[2].a_w.w_float) == av[2].a_w.w_float)
+ {
+ t_probtrans *prefix = prob_findstate(x, prefval, 0);
+ t_probtrans *suffix = prob_findstate(x, suffval, 0);
+ t_probtrans *trans;
+ if (prefix && suffix)
+ {
+ for (trans = prefix->tr_nexttrans; trans;
+ trans = trans->tr_nexttrans)
+ if (trans->tr_suffix == suffix)
+ break;
+ if (trans)
+ {
+ /* the transition already exists... */
+ prefix->tr_count += (count - trans->tr_count);
+ trans->tr_count = count;
+ return;
+ }
+ }
+ if (!prefix)
+ {
+ if (!(prefix = getbytes(sizeof(*prefix))))
+ return;
+ prefix->tr_value = prefval;
+ prefix->tr_count = 0;
+ prefix->tr_suffix = 0;
+ prefix->tr_nexttrans = 0;
+ prefix->tr_nextstate = x->x_translist;
+ x->x_translist = prefix;
+ if (suffval == prefval)
+ suffix = prefix;
+ }
+ if (!suffix)
+ {
+ if (!(suffix = getbytes(sizeof(*suffix))))
+ return;
+ suffix->tr_value = suffval;
+ suffix->tr_count = 0;
+ suffix->tr_suffix = 0;
+ suffix->tr_nexttrans = 0;
+ suffix->tr_nextstate = x->x_translist;
+ x->x_translist = suffix;
+ }
+ if (trans = getbytes(sizeof(*trans)))
+ {
+ trans->tr_value = suffval;
+ trans->tr_count = count;
+ trans->tr_suffix = suffix;
+ trans->tr_nexttrans = prefix->tr_nexttrans;
+ trans->tr_nextstate = prefix->tr_nextstate;
+ prefix->tr_count += count;
+ prefix->tr_nexttrans = trans;
+ }
+ if (!x->x_state) /* CHECKED */
+ x->x_state = prefix; /* CHECKED */
+ }
+ else loud_error((t_pd *)x, "bad list message format"); /* CHECKED */
+}
+
+static void prob_silent(t_prob *x)
+{
+ if (!x->x_silent)
+ {
+ loud_incompatible(prob_class, "no 'silent' message in max");
+ x->x_silent = 1;
+ }
+}
+
+static void prob_click(t_prob *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ t_probtrans *state;
+ char buf[64];
+ hammereditor_open(x->x_filehandle, "prob");
+ for (state = x->x_translist; state; state = state->tr_nextstate)
+ {
+ t_probtrans *trans;
+ for (trans = state->tr_nexttrans; trans; trans = trans->tr_nexttrans)
+ {
+ sprintf(buf, "%d %d %d\n",
+ state->tr_value, trans->tr_value, trans->tr_count);
+ hammereditor_append(x->x_filehandle, buf);
+ }
+ }
+}
+
+static void prob_free(t_prob *x)
+{
+ prob_clear(x);
+ hammerfile_free(x->x_filehandle);
+}
+
+static void *prob_new(void)
+{
+ t_prob *x = (t_prob *)pd_new(prob_class);
+ x->x_translist = 0;
+ x->x_state = 0;
+ x->x_default = 0;
+ x->x_embedmode = 0; /* CHECKED */
+ x->x_silent = 0;
+ rand_seed(&x->x_seed, 0);
+ outlet_new((t_object *)x, &s_float);
+ x->x_bangout = outlet_new((t_object *)x, &s_bang);
+ x->x_filehandle = hammerfile_new((t_pd *)x, 0, 0, 0, 0);
+ return (x);
+}
+
+void prob_setup(void)
+{
+ prob_class = class_new(gensym("prob"),
+ (t_newmethod)prob_new,
+ (t_method)prob_free,
+ sizeof(t_prob), 0, 0);
+ class_addbang(prob_class, prob_bang);
+ class_addfloat(prob_class, prob_float);
+ class_addlist(prob_class, prob_list);
+ class_addmethod(prob_class, (t_method)prob_embed,
+ gensym("embed"), A_FLOAT, 0);
+ class_addmethod(prob_class, (t_method)prob_reset,
+ gensym("reset"), A_FLOAT, 0);
+ class_addmethod(prob_class, (t_method)prob_clear,
+ gensym("clear"), 0);
+ class_addmethod(prob_class, (t_method)prob_dump,
+ gensym("dump"), 0);
+ /* CHECKED: doesn't understand "seed" */
+
+ /* below are the incompatible extensions... */
+ class_addmethod(prob_class, (t_method)prob_silent,
+ gensym("silent"), 0);
+ class_addmethod(prob_class, (t_method)prob_click,
+ gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ hammerfile_setup(prob_class, 0); /* LATER embedding (, 1) */
+}
diff --git a/cyclone/hammer/pv.c b/cyclone/hammer/pv.c
new file mode 100644
index 0000000..235da2c
--- /dev/null
+++ b/cyclone/hammer/pv.c
@@ -0,0 +1,457 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* CHECKED (it cannot be emulated): creating [s/r <pv-symbol>] prints
+ "error:send/receive:<pv-symbol>:already exists"
+*/
+
+#include <string.h>
+#include "m_pd.h"
+#include "g_canvas.h"
+#include "common/loud.h"
+#include "common/grow.h"
+
+#define PV_INISIZE 32 /* LATER rethink */
+#define PV_MAXSIZE 256
+
+typedef struct _pvfamily
+{
+ t_symbol *f_selector;
+ t_float f_float;
+ t_symbol *f_symbol;
+ t_gpointer *f_pointer;
+ int f_size; /* as allocated */
+ int f_natoms; /* as used */
+ t_atom *f_message;
+ t_atom f_messini[PV_INISIZE];
+ t_glist *f_glist; /* root glist of a family */
+ t_symbol *f_name;
+ struct _pvfamily *f_next;
+} t_pvfamily;
+
+typedef struct _pvlist
+{
+ t_pd l_pd;
+ int l_refcount;
+ t_symbol *l_name;
+ t_pvfamily *l_pvlist;
+} t_pvlist;
+
+typedef struct _pv
+{
+ t_object x_ob;
+ t_glist *x_glist;
+ t_symbol *x_name;
+ t_pvfamily *x_family;
+} t_pv;
+
+static t_class *pv_class;
+static t_class *pvlist_class;
+
+static void pvlist_decrement(t_pvlist *pl)
+{
+ if (!--pl->l_refcount)
+ {
+ pd_unbind(&pl->l_pd, pl->l_name);
+ pd_free(&pl->l_pd);
+ }
+}
+
+static t_pvlist *pv_getlist(t_symbol *s, int create)
+{
+ t_pvlist *pl = (t_pvlist *)pd_findbyclass(s, pvlist_class);
+ if (pl)
+ {
+ if (create) pl->l_refcount++;
+ }
+ else
+ {
+ if (create)
+ {
+ pl = (t_pvlist *)pd_new(pvlist_class);
+ pl->l_refcount = 1;
+ pl->l_name = s;
+ pl->l_pvlist = 0;
+ pd_bind(&pl->l_pd, s);
+ }
+ else bug("pv_getlist");
+ }
+ return (pl);
+}
+
+static t_pvfamily *pv_newfamily(t_pvlist *pvlist)
+{
+ t_pvfamily *pf = (t_pvfamily *)getbytes(sizeof(*pf));
+ pf->f_name = pvlist->l_name;
+ pf->f_next = pvlist->l_pvlist;
+ pvlist->l_pvlist = pf;
+ pf->f_selector = 0;
+ pf->f_float = 0;
+ pf->f_symbol = 0;
+ pf->f_pointer = 0;
+ pf->f_size = PV_INISIZE;
+ pf->f_natoms = 0;
+ pf->f_message = pf->f_messini;
+ return (pf);
+}
+
+static void pvfamily_free(t_pvfamily *pf)
+{
+ if (pf->f_message != pf->f_messini)
+ freebytes(pf->f_message, pf->f_size * sizeof(*pf->f_message));
+ freebytes(pf, sizeof(*pf));
+}
+
+static void pv_update(t_glist *glist, t_pvfamily *pf)
+{
+ t_gobj *g;
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd) == canvas_class) /* LATER rethink */
+ pv_update((t_glist *)g, pf);
+ else if (pd_class(&g->g_pd) == pv_class
+ && ((t_pv *)g)->x_name == pf->f_name)
+ ((t_pv *)g)->x_family = pf;
+}
+
+static t_pvfamily *pvfamily_reusable;
+
+static void pv_breakup(t_pvlist *pvlist, t_glist *glist)
+{
+ t_gobj *g;
+ for (g = glist->gl_list; g; g = g->g_next)
+ {
+ if (pd_class(&g->g_pd) == pv_class
+ && ((t_pv *)g)->x_name == pvlist->l_name)
+ {
+ t_pvfamily *pf;
+ if (!(pf = pvfamily_reusable))
+ pf = pv_newfamily(pvlist);
+ else pvfamily_reusable = 0;
+ pf->f_glist = glist;
+ pv_update(glist, pf);
+ /* LATER keep current value */
+ return;
+ }
+ }
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd) == canvas_class) /* LATER rethink */
+ pv_breakup(pvlist, (t_glist *)g);
+}
+
+/* join all families of a 'pvlist' rooted in any subglist of a 'glist' */
+static t_pvfamily *pv_joinup(t_pvlist *pvlist, t_glist *glist)
+{
+ t_pvfamily *result = 0;
+ t_pvfamily *pf, *pfprev, *pfnext;
+ for (pfprev = 0, pf = pvlist->l_pvlist; pf; pfprev = pf, pf = pfnext)
+ {
+ t_glist *gl;
+ pfnext = pf->f_next;
+ for (gl = pf->f_glist; gl; gl = gl->gl_owner)
+ {
+ if (gl == glist)
+ {
+ if (result)
+ {
+ pvfamily_free(pf);
+ if (pfprev)
+ pfprev->f_next = pfnext;
+ else
+ pvlist->l_pvlist = pfnext;
+ pf = pfprev;
+ }
+ else result = pf;
+ break;
+ }
+ }
+ }
+ return (result);
+}
+
+/* Called normally with either 'create' or 'destroy' set to 1,
+ but it might be called with both set to 0 for testing. */
+static t_pvfamily *pv_getfamily(t_glist *glist, t_symbol *s,
+ int create, int destroy)
+{
+ t_pvlist *pl = pv_getlist(s, create);
+ if (pl)
+ {
+ if (destroy)
+ {
+ t_pvfamily *pf, *mypf;
+ t_glist *gl;
+ for (mypf = pl->l_pvlist; mypf; mypf = mypf->f_next)
+ if (mypf->f_glist == glist)
+ break;
+ /* mypf is not null iff we are invoked via a [pv] in root */
+ /* now check if there is a family rooted in a super-branch */
+ for (gl = glist->gl_owner; gl; gl = gl->gl_owner)
+ {
+ for (pf = pl->l_pvlist; pf; pf = pf->f_next)
+ {
+ if (pf->f_glist == gl)
+ {
+ if (mypf)
+ bug("pv_getfamily 1: %s in %s",
+ mypf->f_name->s_name,
+ mypf->f_glist->gl_name->s_name);
+ else
+ return (0);
+ }
+ }
+ }
+ if (mypf)
+ {
+ pvfamily_reusable = mypf;
+ pv_breakup(pl, glist);
+ if (pvfamily_reusable == mypf)
+ {
+ pvfamily_reusable = 0;
+ if (pl->l_pvlist == mypf)
+ pl->l_pvlist = mypf->f_next;
+ else
+ {
+ for (pf = pl->l_pvlist; pf; pf = pf->f_next)
+ {
+ if (pf->f_next == mypf)
+ {
+ pf->f_next = mypf->f_next;
+ break;
+ }
+ }
+ if (!pf) bug("pv_getfamily 2");
+ }
+ pvfamily_free(mypf);
+ }
+ }
+ else bug("pv_getfamily 3");
+ pvlist_decrement(pl);
+ }
+ else
+ {
+ t_pvfamily *pf;
+ t_glist *gl;
+ for (gl = glist; gl; gl = gl->gl_owner)
+ for (pf = pl->l_pvlist; pf; pf = pf->f_next)
+ if (pf->f_glist == gl)
+ return (pf);
+ if (create)
+ {
+ if (!(pf = pv_joinup(pl, glist)))
+ pf = pv_newfamily(pl);
+ pf->f_glist = glist;
+ pv_update(glist, pf);
+ return (pf);
+ }
+ else bug("pv_getfamily 4");
+ }
+ }
+ else bug("pv_getfamily 5");
+ return (0);
+}
+
+static t_pvfamily *pv_checkfamily(t_pv *x)
+{
+ if (!x->x_family)
+ {
+ bug("pv_checkfamily");
+ x->x_family = pv_getfamily(x->x_glist, x->x_name, 0, 0);
+ }
+ return (x->x_family);
+}
+
+static void pv_bang(t_pv *x)
+{
+ t_pvfamily *pf = pv_checkfamily(x);
+ if (pf)
+ {
+ t_symbol *s = pf->f_selector;
+ if (s == &s_bang)
+ outlet_bang(((t_object *)x)->ob_outlet);
+ else if (s == &s_float)
+ outlet_float(((t_object *)x)->ob_outlet, pf->f_float);
+ else if (s == &s_symbol && pf->f_symbol)
+ outlet_symbol(((t_object *)x)->ob_outlet, pf->f_symbol);
+ else if (s == &s_pointer)
+ {
+ /* LATER */
+ }
+ else if (s == &s_list)
+ outlet_list(((t_object *)x)->ob_outlet,
+ s, pf->f_natoms, pf->f_message);
+ else if (s)
+ outlet_anything(((t_object *)x)->ob_outlet,
+ s, pf->f_natoms, pf->f_message);
+ }
+}
+
+static void pv_float(t_pv *x, t_float f)
+{
+ t_pvfamily *pf = pv_checkfamily(x);
+ if (pf)
+ {
+ pf->f_selector = &s_float;
+ pf->f_float = f;
+ pf->f_natoms = 0; /* defensive */
+ }
+}
+
+static void pv_symbol(t_pv *x, t_symbol *s)
+{
+ t_pvfamily *pf = pv_checkfamily(x);
+ if (pf)
+ {
+ pf->f_selector = &s_symbol;
+ pf->f_symbol = s;
+ pf->f_natoms = 0; /* defensive */
+ }
+}
+
+static void pv_pointer(t_pv *x, t_gpointer *gp)
+{
+ t_pvfamily *pf = pv_checkfamily(x);
+ if (pf)
+ {
+ pf->f_selector = &s_pointer;
+ pf->f_pointer = gp;
+ pf->f_natoms = 0; /* defensive */
+ }
+}
+
+static void pvfamily_domessage(t_pvfamily *pf, int ac, t_atom *av)
+{
+ if (ac > pf->f_size)
+ {
+ /* LATER consider using PV_MAXSIZE (and warning if exceeded) */
+ pf->f_message = grow_nodata(&ac, &pf->f_size, pf->f_message,
+ PV_INISIZE, pf->f_messini,
+ sizeof(*pf->f_message));
+ }
+ pf->f_natoms = ac;
+ memcpy(pf->f_message, av, ac * sizeof(*pf->f_message));
+}
+
+static void pv_list(t_pv *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_pvfamily *pf = pv_checkfamily(x);
+ if (pf)
+ {
+ pf->f_selector = &s_list; /* LATER rethink */
+ pvfamily_domessage(pf, ac, av);
+ }
+}
+
+static void pv_anything(t_pv *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_pvfamily *pf = pv_checkfamily(x);
+ if (pf)
+ {
+ pf->f_selector = s; /* LATER rethink */
+ pvfamily_domessage(pf, ac, av);
+ }
+}
+
+static void pv_objstatus(t_pv *x, t_glist *glist)
+{
+ t_gobj *g;
+ for (g = glist->gl_list; g; g = g->g_next)
+ {
+ if (g == (t_gobj *)x)
+ post("%x (this object) owning patcher [%s]",
+ (int)g, glist->gl_name->s_name);
+ else if (pd_class(&g->g_pd) == pv_class
+ && ((t_pv *)g)->x_name == x->x_name)
+ post("%x owning patcher [%s]", (int)g, glist->gl_name->s_name);
+ }
+}
+
+static void pv_status(t_pv *x)
+{
+ t_pvlist *pl = pv_getlist(x->x_name, 0);
+ post("pv status: Tied to %s", x->x_name->s_name);
+ if (pl)
+ {
+ t_pvfamily *pf;
+ int fcount;
+ for (pf = pl->l_pvlist, fcount = 1; pf; pf = pf->f_next, fcount++)
+ {
+ t_glist *glist = pf->f_glist;
+ t_gobj *g;
+ post("Family %d:", fcount);
+ pv_objstatus(x, glist);
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd) == canvas_class) /* LATER rethink */
+ pv_objstatus(x, (t_glist *)g);
+ }
+ }
+}
+
+static void pv_free(t_pv *x)
+{
+ pv_getfamily(x->x_glist, x->x_name, 0, 1);
+}
+
+static void *pv_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_pv *x = 0;
+ if (ac && av->a_type == A_SYMBOL)
+ s = av->a_w.w_symbol;
+ else s = 0;
+ if (s && s != &s_)
+ {
+ t_glist *gl = canvas_getcurrent();
+ t_pvfamily *pf = pv_getfamily(gl, s, 1, 0);
+ x = (t_pv *)pd_new(pv_class);
+ x->x_glist = gl;
+ x->x_name = s;
+ x->x_family = pf;
+ outlet_new((t_object *)x, &s_float);
+ if (--ac)
+ {
+ av++;
+ if (av->a_type == A_SYMBOL)
+ {
+ if (av->a_w.w_symbol == &s_symbol)
+ {
+ if (ac > 1 && av[1].a_type == A_SYMBOL)
+ pv_symbol(x, av[1].a_w.w_symbol);
+ }
+ /* LATER rethink 'pv <name> bang' (now it is accepted) */
+ else pv_anything(x, av->a_w.w_symbol, ac - 1, av + 1);
+ }
+ else if (av->a_type == A_FLOAT)
+ {
+ if (ac > 1)
+ pv_list(x, &s_list, ac, av);
+ else pv_float(x, av->a_w.w_float);
+ }
+ }
+
+ }
+ else
+ /* CHECKED: "error: missing or bad arguments",
+ a box is created without inlets and outlets */
+ loud_classarg(pv_class);
+ return (x);
+}
+
+void pv_setup(void)
+{
+ pv_class = class_new(gensym("pv"),
+ (t_newmethod)pv_new,
+ (t_method)pv_free,
+ sizeof(t_pv), 0, A_GIMME, 0);
+ class_addbang(pv_class, pv_bang);
+ class_addfloat(pv_class, pv_float);
+ class_addsymbol(pv_class, pv_symbol);
+ class_addpointer(pv_class, pv_pointer);
+ class_addlist(pv_class, pv_list);
+ class_addanything(pv_class, pv_anything);
+ class_addmethod(pv_class, (t_method)pv_status,
+ gensym("status"), 0);
+ /* CHECKED: sending bang (or int, list, status, etc.) with '; <pv-symbol>'
+ "error::doesn't understand bang" (class name is an empty string) */
+ pvlist_class = class_new(&s_, 0, 0,
+ sizeof(t_pvlist), CLASS_PD, 0);
+}
diff --git a/cyclone/hammer/seq.c b/cyclone/hammer/seq.c
new file mode 100644
index 0000000..503b205
--- /dev/null
+++ b/cyclone/hammer/seq.c
@@ -0,0 +1,825 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* CHECKED no sharing of data among seq objects having the same creation arg */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "m_pd.h"
+#include "shared.h"
+#include "common/loud.h"
+#include "common/grow.h"
+#include "common/sq.h"
+#include "common/bifi.h"
+#include "common/mifi.h"
+#include "hammer/file.h"
+
+#define SEQ_DEBUG
+
+#define SEQ_INISIZE 256 /* LATER rethink */
+#define SEQ_EOM 255 /* end of message marker, LATER rethink */
+
+typedef struct _seqevent
+{
+ int e_delta;
+ unsigned char e_bytes[4];
+} t_seqevent;
+
+typedef struct _seq
+{
+ t_object x_ob;
+ t_canvas *x_canvas;
+ t_symbol *x_defname;
+ t_hammerfile *x_filehandle;
+ int x_isplaying;
+ int x_isrecording;
+ int x_playhead;
+ float x_tempo;
+ double x_prevtime;
+ unsigned char x_status;
+ int x_evesize;
+ int x_expectedsize;
+ int x_size; /* as allocated */
+ int x_nevents; /* as used */
+ t_seqevent *x_sequence;
+ t_seqevent x_seqini[SEQ_INISIZE];
+ t_clock *x_clock;
+ t_outlet *x_bangout;
+} t_seq;
+
+static t_class *seq_class;
+
+static void seq_doclear(t_seq *x, int dofree)
+{
+ if (dofree && x->x_sequence != x->x_seqini)
+ {
+ freebytes(x->x_sequence, x->x_size * sizeof(*x->x_sequence));
+ x->x_sequence = x->x_seqini;
+ x->x_size = SEQ_INISIZE;
+ }
+ x->x_nevents = 0;
+}
+
+static void seq_complete(t_seq *x)
+{
+ if (x->x_evesize < x->x_expectedsize)
+ {
+ /* CHECKED no warning if no data after status byte requiring data */
+ if (x->x_evesize > 1)
+ post("seq: truncated midi message"); /* CHECKED */
+ /* CHECKED nothing stored */
+ }
+ else
+ {
+ t_seqevent *ep = &x->x_sequence[x->x_nevents];
+ double elapsed = clock_gettimesince(x->x_prevtime);
+ ep->e_delta = (int)elapsed;
+ x->x_prevtime = clock_getlogicaltime();
+ if (x->x_evesize < 4)
+ ep->e_bytes[x->x_evesize] = SEQ_EOM;
+ x->x_nevents++;
+ if (x->x_nevents >= x->x_size)
+ {
+ int nexisting = x->x_size;
+ /* store-ahead scheme, LATER consider using x_currevent */
+ int nrequested = x->x_nevents + 1;
+#ifdef SEQ_DEBUG
+ post("growing...");
+#endif
+ x->x_sequence =
+ grow_withdata(&nrequested, &nexisting,
+ &x->x_size, x->x_sequence,
+ SEQ_INISIZE, x->x_seqini, sizeof(*x->x_sequence));
+ if (nrequested <= x->x_nevents)
+ x->x_nevents = 0;
+ }
+ }
+ x->x_evesize = 0;
+}
+
+static void seq_checkstatus(t_seq *x, unsigned char c)
+{
+ if (x->x_status && x->x_evesize > 1) /* LATER rethink */
+ seq_complete(x);
+ if (c < 192)
+ x->x_expectedsize = 3;
+ else if (c < 224)
+ x->x_expectedsize = 2;
+ else if (c < 240)
+ x->x_expectedsize = 3;
+ else if (c < 248)
+ {
+ /* FIXME */
+ x->x_expectedsize = -1;
+ }
+ else
+ {
+ x->x_sequence[x->x_nevents].e_bytes[0] = c;
+ x->x_evesize = x->x_expectedsize = 1;
+ seq_complete(x);
+ return;
+ }
+ x->x_status = x->x_sequence[x->x_nevents].e_bytes[0] = c;
+ x->x_evesize = 1;
+}
+
+static void seq_addbyte(t_seq *x, unsigned char c, int docomplete)
+{
+ x->x_sequence[x->x_nevents].e_bytes[x->x_evesize++] = c;
+ if (x->x_evesize == x->x_expectedsize)
+ {
+ seq_complete(x);
+ if (x->x_status)
+ {
+ x->x_sequence[x->x_nevents].e_bytes[0] = x->x_status;
+ x->x_evesize = 1;
+ }
+ }
+ else if (x->x_evesize == 4)
+ {
+ if (x->x_status != 240)
+ bug("seq_addbyte");
+ /* CHECKED sysex is broken into 4-byte packets marked with
+ the actual delta time of last byte received in a packet */
+ seq_complete(x);
+ }
+ else if (docomplete) seq_complete(x);
+}
+
+static void seq_endofsysex(t_seq *x)
+{
+ seq_addbyte(x, 247, 1);
+ x->x_status = 0;
+}
+
+static void seq_stopplayback(t_seq *x)
+{
+ /* FIXME */
+ /* CHECKED "seq: incomplete sysex" at playback stop, 247 added implicitly */
+ /* CHECKME resetting controllers, etc. */
+ /* CHECKED bang not sent if playback stopped early */
+ clock_unset(x->x_clock);
+ x->x_playhead = 0;
+ x->x_isplaying = 0;
+}
+
+static void seq_stoprecording(t_seq *x)
+{
+ if (x->x_status == 240)
+ {
+ post("seq: incomplete sysex"); /* CHECKED */
+ seq_endofsysex(x); /* CHECKED 247 added implicitly */
+ }
+ else if (x->x_status)
+ seq_complete(x);
+ /* CHECKED running status used in recording, but not across recordings */
+ x->x_status = 0;
+ x->x_isrecording = 0;
+}
+
+static void seq_tick(t_seq *x)
+{
+ if (x->x_isplaying)
+ {
+ t_seqevent *ep = &x->x_sequence[x->x_playhead++];
+ unsigned char *bp = ep->e_bytes;
+nextevent:
+ outlet_float(((t_object *)x)->ob_outlet, *bp++);
+ if (*bp != SEQ_EOM)
+ {
+ outlet_float(((t_object *)x)->ob_outlet, *bp++);
+ if (*bp != SEQ_EOM)
+ {
+ outlet_float(((t_object *)x)->ob_outlet, *bp++);
+ if (*bp != SEQ_EOM)
+ outlet_float(((t_object *)x)->ob_outlet, *bp++);
+ }
+ }
+ if (!x->x_isplaying) /* reentrancy protection */
+ return;
+ if (x->x_playhead < x->x_nevents)
+ {
+ ep++;
+ if (ep->e_delta <= 0)
+ /* continue output in the same scheduler event, LATER rethink */
+ {
+ x->x_playhead++;
+ bp = ep->e_bytes;
+ goto nextevent;
+ }
+ else clock_delay(x->x_clock, ep->e_delta);
+ }
+ else
+ {
+ seq_stopplayback(x);
+ /* CHECKED bang sent immediately _after_ last byte */
+ outlet_bang(x->x_bangout); /* LATER think about reentrancy */
+ }
+ }
+}
+
+/* CHECKED running status not used in playback */
+static void seq_dostart(t_seq *x, float tempo)
+{
+ if (x->x_isplaying)
+ {
+ /* CHECKED tempo change */
+ x->x_tempo = tempo;
+ /* FIXME update the clock */
+ }
+ else
+ {
+ if (x->x_isrecording) /* CHECKED 'start' stops recording */
+ seq_stoprecording(x);
+ /* CHECKED bang not sent if a sequence is empty */
+ if (x->x_nevents)
+ {
+ x->x_tempo = tempo;
+ x->x_playhead = 0;
+ x->x_isplaying = 1;
+ /* playback data never sent within the scheduler event of
+ a start message (even for the first delta <= 0), LATER rethink */
+ clock_delay(x->x_clock, x->x_sequence->e_delta);
+ }
+ }
+}
+
+static void seq_bang(t_seq *x)
+{
+ seq_dostart(x, 1.0);
+}
+
+static void seq_float(t_seq *x, t_float f)
+{
+ if (x->x_isrecording)
+ {
+ /* CHECKED noninteger and out of range silently truncated */
+ unsigned char c = (unsigned char)f;
+ if (c < 128)
+ {
+ if (x->x_status) seq_addbyte(x, c, 0);
+ }
+ else if (c != 254) /* CHECKED active sensing ignored */
+ {
+ if (x->x_status == 240)
+ {
+ if (c == 247) seq_endofsysex(x);
+ else
+ {
+ /* CHECKED rt bytes alike */
+ post("seq: unterminated sysex"); /* CHECKED */
+ seq_endofsysex(x); /* CHECKED 247 added implicitly */
+ seq_checkstatus(x, c);
+ }
+ }
+ else if (c != 247) seq_checkstatus(x, c);
+ }
+ }
+}
+
+static void seq_symbol(t_seq *x, t_symbol *s)
+{
+ loud_nomethod((t_pd *)x, &s_symbol); /* CHECKED */
+}
+
+static void seq_list(t_seq *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac && av->a_type == A_FLOAT) seq_float(x, av->a_w.w_float);
+ /* CHECKED anything else/more silently ignored */
+}
+
+static void seq_record(t_seq *x)
+{
+ /* CHECKED 'record' resets recording */
+ if (x->x_isplaying) /* CHECKED 'record' stops playback */
+ seq_stopplayback(x);
+ seq_doclear(x, 0);
+ x->x_isrecording = 1;
+ x->x_prevtime = clock_getlogicaltime();
+ x->x_status = 0;
+ x->x_evesize = 0;
+ x->x_expectedsize = -1; /* LATER rethink */
+}
+
+static void seq_append(t_seq *x)
+{
+ if (x->x_isrecording)
+ return; /* CHECKME 'append' does not reset recording */
+ if (x->x_isplaying) /* CHECKME 'append' stops playback */
+ seq_stopplayback(x);
+ x->x_isrecording = 1;
+ x->x_prevtime = clock_getlogicaltime();
+ x->x_status = 0;
+ x->x_evesize = 0;
+ x->x_expectedsize = -1; /* LATER rethink */
+}
+
+static void seq_stop(t_seq *x)
+{
+ if (x->x_isplaying)
+ seq_stopplayback(x);
+ else if (x->x_isrecording)
+ seq_stoprecording(x);
+}
+
+static int seq_dogrowing(t_seq *x, int nevents)
+{
+ if (nevents > x->x_size)
+ {
+ int nrequested = nevents;
+#ifdef SEQ_DEBUG
+ post("growing...");
+#endif
+ x->x_sequence =
+ grow_nodata(&nrequested, &x->x_size, x->x_sequence,
+ SEQ_INISIZE, x->x_seqini, sizeof(*x->x_sequence));
+ if (nrequested < nevents)
+ {
+ x->x_nevents = 0;
+ return (0);
+ }
+ }
+ x->x_nevents = nevents;
+ return (1);
+}
+
+static int seq_seekhook(t_squiter *it, int offset)
+{
+ t_seq *x = (t_seq *)it->i_owner;
+ post("seek in %d", x->x_nevents);
+ it->i_nelems = x->x_nevents;
+ it->i_sequence = x->x_sequence;
+ if (offset < 0)
+ offset += it->i_nelems;
+ if (offset >= 0 && offset < it->i_nelems)
+ {
+ it->i_element = (t_seqevent *)it->i_sequence + offset;
+ it->i_index = offset;
+ return (1);
+ }
+ else return (0);
+}
+
+static void seq_incrhook(t_squiter *it)
+{
+ ((t_seqevent *)it->i_element)++;
+ it->i_index++;
+}
+
+/* LATER put seq_mfwrite_doit() functionality here */
+static void seq_getevehook(t_squiter *it, t_mifi_event *mev, int *ret)
+{
+ *ret = 1;
+}
+
+static void seq_setevehook(t_squiter *it, t_mifi_event *mev, int *ret)
+{
+ t_seqevent *sev = it->i_element;
+ sev->e_delta = mev->e_delay;
+ sev->e_bytes[0] = mev->e_status | mev->e_channel;
+ sev->e_bytes[1] = mev->e_data[0];
+ if (MIFI_ONE_DATABYTE(mev->e_status))
+ sev->e_bytes[2] = SEQ_EOM;
+ else
+ {
+ sev->e_bytes[2] = mev->e_data[1];
+ sev->e_bytes[3] = SEQ_EOM;
+ }
+ *ret = 1;
+}
+
+static t_float seq_gettimhook(t_squiter *it, int *ret)
+{
+ t_seqevent *sev = it->i_element;
+ *ret = 1;
+ return (sev->e_delta);
+}
+
+static void seq_settimhook(t_squiter *it, t_float f, int *ret)
+{
+ t_seqevent *sev = it->i_element;
+ sev->e_delta = f;
+ *ret = 1;
+}
+
+static t_symbol *seq_gettarhook(t_squiter *it, int *ret)
+{
+ *ret = 1;
+ return (0);
+}
+
+static void seq_settarhook(t_squiter *it, t_symbol *s, int *ret)
+{
+ *ret = 1;
+}
+
+static int seq_make_iterator(t_seq *x, t_mifi_stream *stp)
+{
+ t_squiter *it = squiter_new(stp);
+ if (it)
+ {
+ it->i_owner = x;
+ it->i_nelems = x->x_nevents;
+ it->i_sequence = it->i_element = x->x_sequence;
+ it->i_index = 0;
+ it->i_hooks[SQUITER_SEEKHOOK] = (t_squiterhook)seq_seekhook;
+ it->i_hooks[SQUITER_INCRHOOK] = (t_squiterhook)seq_incrhook;
+ it->i_hooks[SQUITER_GETEVEHOOK] = (t_squiterhook)seq_getevehook;
+ it->i_hooks[SQUITER_SETEVEHOOK] = (t_squiterhook)seq_setevehook;
+ it->i_hooks[SQUITER_GETTIMHOOK] = (t_squiterhook)seq_gettimhook;
+ it->i_hooks[SQUITER_SETTIMHOOK] = (t_squiterhook)seq_settimhook;
+ it->i_hooks[SQUITER_GETTARHOOK] = (t_squiterhook)seq_gettarhook;
+ it->i_hooks[SQUITER_SETTARHOOK] = (t_squiterhook)seq_settarhook;
+ return (1);
+ }
+ else return (0);
+}
+
+static t_mifi_stream *seq_makestream(t_seq *x)
+{
+ t_mifi_stream *stp = 0;
+ if (stp = mifi_stream_new())
+ {
+ if (seq_make_iterator(x, stp))
+ return (stp);
+ else
+ mifi_stream_free(stp);
+ }
+ return (0);
+}
+
+static int seq_comparehook(const void *e1, const void *e2)
+{
+ return (((t_seqevent *)e1)->e_delta > ((t_seqevent *)e2)->e_delta ? 1 : -1);
+}
+
+/* FIXME */
+static int seq_mfread(t_seq *x, char *path)
+{
+ int result = 0;
+ t_mifi_stream *stp = 0;
+ if (!(stp = seq_makestream(x)) ||
+ !mifi_read_start(stp, path, "", 0))
+ goto readfailed;
+#ifdef SEQ_DEBUG
+ if (stp->s_nframes)
+ post("midifile (format %d): %d tracks, %d ticks (%d smpte frames)",
+ stp->s_format, stp->s_hdtracks, stp->s_nticks, stp->s_nframes);
+ else
+ post("midifile (format %d): %d tracks, %d ticks per beat",
+ stp->s_format, stp->s_hdtracks, stp->s_nticks);
+#endif
+ if (mifi_read_analyse(stp) != MIFI_READ_EOF ||
+ !seq_dogrowing(x, stp->s_nevents) ||
+ !mifi_read_restart(stp) ||
+ mifi_read_doit(stp) != MIFI_READ_EOF)
+ goto readfailed;
+ squmpi_sort(stp);
+ qsort(x->x_sequence, stp->s_nevents, sizeof(*x->x_sequence),
+ seq_comparehook);
+ sq_fold_time(stp);
+#ifdef SEQ_DEBUG
+ post("finished reading %d events from midifile", stp->s_nevents);
+#endif
+ result = 1;
+readfailed:
+ if (stp)
+ {
+ mifi_read_end(stp);
+ mifi_stream_free(stp);
+ }
+ return (result);
+}
+
+/* FIXME */
+static int seq_mfwrite_doit(t_seq *x, t_mifi_stream *stp)
+{
+ t_mifi_event *mev = stp->s_auxeve;
+ t_seqevent *sev = x->x_sequence;
+ int nevents = x->x_nevents;
+ while (nevents--)
+ {
+ unsigned char *bp = sev->e_bytes;
+ int i;
+ mev->e_delay = (uint32)(sev->e_delta * stp->s_timecoef);
+ mev->e_status = *bp & 0xf0;
+ mev->e_channel = *bp & 0x0f;
+ /* FIXME sysex continuation */
+ for (i = 0, bp++; i < 3 && *bp != SEQ_EOM; i++, bp++)
+ mev->e_data[i] = *bp;
+ if (!mifi_write_event(stp, mev))
+ return (0);
+ sev++;
+ }
+ return (1);
+}
+
+/* FIXME */
+static int seq_mfwrite(t_seq *x, char *path)
+{
+ int result = 0;
+ t_mifi_stream *stp = 0;
+ if (!(stp = seq_makestream(x)))
+ goto writefailed;
+ stp->s_ntracks = 1;
+ stp->s_hdtracks = 1;
+ stp->s_format = 0;
+ if (!mifi_write_start(stp, path, ""))
+ goto writefailed;
+ mifi_event_settext(stp->s_auxeve, MIFI_META_TRACKNAME, "seq-track");
+ if (!mifi_write_start_track(stp) ||
+ !mifi_write_event(stp, stp->s_auxeve) ||
+ !seq_mfwrite_doit(x, stp) ||
+ !mifi_write_adjust_track(stp, 0))
+ goto writefailed;
+ result = 1;
+writefailed:
+ if (stp)
+ {
+ mifi_write_end(stp);
+ mifi_stream_free(stp);
+ }
+ return (result);
+}
+
+/* FIXME */
+/* CHECKED absolute timestamps, semi-terminated, verified */
+static int seq_frombinbuf(t_seq *x, t_binbuf *bb)
+{
+ int nevents = 0;
+ int ac = binbuf_getnatom(bb);
+ t_atom *av = binbuf_getvec(bb);
+ while (ac--)
+ if (av++->a_type == A_SEMI) /* FIXME parsing */
+ nevents++;
+ if (nevents)
+ {
+ t_seqevent *ep;
+ float prevtime = 0;
+ int i = -1;
+ if (!seq_dogrowing(x, nevents))
+ return (0);
+ nevents = 0;
+ ac = binbuf_getnatom(bb);
+ av = binbuf_getvec(bb);
+ ep = x->x_sequence;
+ while (ac--)
+ {
+ if (av->a_type == A_FLOAT)
+ {
+ if (i < 0)
+ {
+ ep->e_delta = av->a_w.w_float - prevtime;
+ prevtime = av->a_w.w_float;
+ i = 0;
+ }
+ else if (i < 4)
+ ep->e_bytes[i++] = av->a_w.w_float;
+ /* CHECKME else */
+ }
+ else if (av->a_type == A_SEMI && i > 0)
+ {
+ if (i < 4)
+ ep->e_bytes[i] = SEQ_EOM;
+ nevents++;
+ ep++;
+ i = -1;
+ }
+ /* CHECKME else */
+ av++;
+ }
+ x->x_nevents = nevents;
+ }
+ return (nevents);
+}
+
+static void seq_tobinbuf(t_seq *x, t_binbuf *bb)
+{
+ int nevents = x->x_nevents;
+ t_seqevent *ep = x->x_sequence;
+ t_atom at[5];
+ float timestamp = 0;
+ while (nevents--)
+ {
+ unsigned char *bp = ep->e_bytes;
+ int i;
+ t_atom *ap = at;
+ timestamp += ep->e_delta;
+ SETFLOAT(ap, timestamp); /* CHECKED same for sysex continuation */
+ ap++;
+ SETFLOAT(ap, *bp);
+ for (i = 0, ap++, bp++; i < 3 && *bp != SEQ_EOM; i++, ap++, bp++)
+ SETFLOAT(ap, *bp);
+ binbuf_add(bb, i + 2, at);
+ binbuf_addsemi(bb);
+ ep++;
+ }
+}
+
+static void seq_textread(t_seq *x, char *path)
+{
+ t_binbuf *bb;
+ bb = binbuf_new();
+ if (binbuf_read(bb, path, "", 0))
+ {
+ /* CHECKED no complaint, open dialog presented */
+ hammerpanel_open(x->x_filehandle); /* LATER rethink */
+ }
+ else
+ {
+ int nlines = seq_frombinbuf(x, bb);
+ if (nlines < 0)
+ /* CHECKED "bad MIDI file (truncated)" alert, even if a text file */
+ loud_error((t_pd *)x, "bad text file (truncated)");
+ else if (nlines == 0)
+ {
+ /* CHECKED no complaint, sequence erased, LATER rethink */
+ }
+ }
+ binbuf_free(bb);
+}
+
+static void seq_textwrite(t_seq *x, char *path)
+{
+ t_binbuf *bb;
+ bb = binbuf_new();
+ seq_tobinbuf(x, bb);
+ /* CHECKED empty sequence stored as an empty file */
+ if (binbuf_write(bb, path, "", 0))
+ {
+ /* CHECKME complaint and FIXME */
+ loud_error((t_pd *)x, "error writing text file");
+ }
+ binbuf_free(bb);
+}
+
+static void seq_doread(t_seq *x, t_symbol *fn, int creation)
+{
+ char buf[MAXPDSTRING];
+ if (x->x_canvas)
+ canvas_makefilename(x->x_canvas, fn->s_name, buf, MAXPDSTRING);
+ else
+ {
+ strncpy(buf, fn->s_name, MAXPDSTRING);
+ buf[MAXPDSTRING-1] = 0;
+ }
+ if (creation)
+ {
+ /* loading during object creation -- CHECKED no warning if a file
+ specified with an arg does not exist, LATER rethink */
+ FILE *fp;
+ char path[MAXPDSTRING];
+ sys_bashfilename(buf, path);
+ if (!(fp = fopen(path, "r")))
+ return;
+ fclose(fp);
+ }
+ /* CHECKED all cases: arg or not, message and creation */
+ post("seq: reading %s", fn->s_name);
+ if (!seq_mfread(x, buf))
+ seq_textread(x, buf);
+}
+
+static void seq_dowrite(t_seq *x, t_symbol *fn)
+{
+ char buf[MAXPDSTRING], *dotp;
+ if (x->x_canvas)
+ canvas_makefilename(x->x_canvas, fn->s_name, buf, MAXPDSTRING);
+ else
+ {
+ strncpy(buf, fn->s_name, MAXPDSTRING);
+ buf[MAXPDSTRING-1] = 0;
+ }
+ post("seq: writing %s", fn->s_name); /* CHECKED arg or not */
+ /* save as text for any extension other then ".mid" */
+ if ((dotp = strrchr(fn->s_name, '.')) && strcmp(dotp + 1, "mid"))
+ seq_textwrite(x, buf);
+ else /* save as mf for ".mid" or no extension at all, LATER rethink */
+ seq_mfwrite(x, buf);
+}
+
+static void seq_readhook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ seq_doread((t_seq *)z, fn, 0);
+}
+
+static void seq_writehook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ seq_dowrite((t_seq *)z, fn);
+}
+
+static void seq_read(t_seq *x, t_symbol *s)
+{
+ if (s && s != &s_)
+ seq_doread(x, s, 0);
+ else /* CHECKED no default */
+ hammerpanel_open(x->x_filehandle);
+}
+
+static void seq_write(t_seq *x, t_symbol *s)
+{
+ if (s && s != &s_)
+ seq_dowrite(x, s);
+ else /* CHECKED creation arg is a default */
+ hammerpanel_save(x->x_filehandle,
+ canvas_getdir(x->x_canvas), x->x_defname);
+}
+
+static void seq_print(t_seq *x)
+{
+ int nevents = x->x_nevents;
+ startpost("midiseq:"); /* CHECKED */
+ if (nevents)
+ {
+ t_seqevent *ep = x->x_sequence;
+ int truncated;
+ if (nevents > 16)
+ nevents = 16, truncated = 1;
+ else
+ truncated = 0;
+ while (nevents--)
+ {
+ unsigned char *bp = ep->e_bytes;
+ int i;
+ if (*bp < 128 || *bp == 247)
+ /* CHECKED (sysex continuation) */
+ startpost("\n(%d)->", ep->e_delta);
+ else
+ startpost("\n(%d)", ep->e_delta);
+ /* CHECKED space-separated, no semi */
+ postfloat((float)*bp);
+ for (i = 0, bp++; i < 3 && *bp != SEQ_EOM; i++, bp++)
+ postfloat((float)*bp);
+ ep++;
+ }
+ endpost();
+ if (truncated) post("..."); /* CHECKED */
+ }
+ else post(" no sequence"); /* CHECKED */
+}
+
+static void seq_free(t_seq *x)
+{
+ if (x->x_clock) clock_free(x->x_clock);
+ hammerfile_free(x->x_filehandle);
+ if (x->x_sequence != x->x_seqini)
+ freebytes(x->x_sequence, x->x_size * sizeof(*x->x_sequence));
+}
+
+static void *seq_new(t_symbol *s)
+{
+ t_seq *x = (t_seq *)pd_new(seq_class);
+ static int warned = 0;
+ if (!warned)
+ {
+ loud_warning((t_pd *)x, "seq is not ready yet");
+ warned = 1;
+ }
+ x->x_canvas = canvas_getcurrent();
+ x->x_filehandle = hammerfile_new((t_pd *)x, 0,
+ seq_readhook, seq_writehook, 0);
+ x->x_prevtime = 0;
+ x->x_size = SEQ_INISIZE;
+ x->x_nevents = 0;
+ x->x_sequence = x->x_seqini;
+ outlet_new((t_object *)x, &s_anything);
+ x->x_bangout = outlet_new((t_object *)x, &s_bang);
+ if (s && s != &s_)
+ {
+ x->x_defname = s; /* CHECKME if 'read' changes this */
+ seq_doread(x, s, 1);
+ }
+ else x->x_defname = &s_;
+ x->x_clock = clock_new(x, (t_method)seq_tick);
+ return (x);
+}
+
+void seq_setup(void)
+{
+ seq_class = class_new(gensym("seq"),
+ (t_newmethod)seq_new,
+ (t_method)seq_free,
+ sizeof(t_seq), 0,
+ A_DEFSYM, 0);
+ class_addbang(seq_class, seq_bang);
+ class_addfloat(seq_class, seq_float);
+ /* CHECKED symbol rejected */
+ class_addsymbol(seq_class, seq_symbol);
+ /* CHECKED 1st atom of a list accepted if a float, ignored if a symbol */
+ class_addlist(seq_class, seq_list);
+ class_addmethod(seq_class, (t_method)seq_record,
+ gensym("record"), 0);
+ class_addmethod(seq_class, (t_method)seq_append,
+ gensym("append"), 0);
+ class_addmethod(seq_class, (t_method)seq_stop,
+ gensym("stop"), 0);
+ class_addmethod(seq_class, (t_method)seq_read,
+ gensym("read"), A_DEFSYM, 0);
+ class_addmethod(seq_class, (t_method)seq_write,
+ gensym("write"), A_DEFSYM, 0);
+ class_addmethod(seq_class, (t_method)seq_print,
+ gensym("print"), 0);
+ hammerfile_setup(seq_class, 0);
+}
diff --git a/cyclone/hammer/sinh.c b/cyclone/hammer/sinh.c
new file mode 100644
index 0000000..93fb6fa
--- /dev/null
+++ b/cyclone/hammer/sinh.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define sinhf sinh
+#endif
+
+typedef struct _sinh
+{
+ t_object x_ob;
+ float x_value;
+} t_sinh;
+
+static t_class *sinh_class;
+
+static void sinh_bang(t_sinh *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+}
+
+static void sinh_float(t_sinh *x, t_float f)
+{
+ /* CHECKME large values */
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value = sinhf(f));
+}
+
+static void *sinh_new(t_floatarg f)
+{
+ t_sinh *x = (t_sinh *)pd_new(sinh_class);
+ /* CHECKME large values */
+ x->x_value = sinhf(f);
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void sinh_setup(void)
+{
+ sinh_class = class_new(gensym("sinh"),
+ (t_newmethod)sinh_new, 0,
+ sizeof(t_sinh), 0, A_DEFFLOAT, 0);
+ class_addbang(sinh_class, sinh_bang);
+ class_addfloat(sinh_class, sinh_float);
+}
diff --git a/cyclone/hammer/speedlim.c b/cyclone/hammer/speedlim.c
new file mode 100644
index 0000000..3cad0f7
--- /dev/null
+++ b/cyclone/hammer/speedlim.c
@@ -0,0 +1,173 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* LATER 'clock' method */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+#define SPEEDLIM_INISIZE 32 /* LATER rethink */
+#define SPEEDLIM_MAXSIZE 256 /* not used */
+
+typedef struct _speedlim
+{
+ t_object x_ob;
+ int x_open;
+ t_float x_delta;
+ t_symbol *x_selector;
+ t_float x_float;
+ t_symbol *x_symbol;
+ t_gpointer *x_pointer;
+ int x_size; /* as allocated */
+ int x_natoms; /* as used */
+ t_atom *x_message;
+ t_atom x_messini[SPEEDLIM_INISIZE];
+ int x_entered;
+ t_clock *x_clock;
+} t_speedlim;
+
+static t_class *speedlim_class;
+
+static void speedlim_dooutput(t_speedlim *x, t_symbol *s, int ac, t_atom *av)
+{
+ x->x_open = 0; /* so there will be no reentrant calls of dooutput */
+ x->x_entered = 1; /* this prevents a message from being overridden */
+ clock_unset(x->x_clock);
+ if (s == &s_bang)
+ outlet_bang(((t_object *)x)->ob_outlet);
+ else if (s == &s_float)
+ outlet_float(((t_object *)x)->ob_outlet, x->x_float);
+ else if (s == &s_symbol && x->x_symbol)
+ {
+ /* if x_symbol is null, then symbol &s_ is passed
+ by outlet_anything() -> typedmess() */
+ outlet_symbol(((t_object *)x)->ob_outlet, x->x_symbol);
+ x->x_symbol = 0;
+ }
+ else if (s == &s_pointer && x->x_pointer)
+ {
+ /* LATER */
+ x->x_pointer = 0;
+ }
+ else if (s == &s_list)
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av);
+ else if (s)
+ outlet_anything(((t_object *)x)->ob_outlet, s, ac, av);
+ x->x_selector = 0;
+ x->x_natoms = 0;
+ if (x->x_delta > 0)
+ clock_delay(x->x_clock, x->x_delta);
+ else
+ x->x_open = 1;
+ x->x_entered = 0;
+}
+
+static void speedlim_tick(t_speedlim *x)
+{
+ if (x->x_selector)
+ speedlim_dooutput(x, x->x_selector, x->x_natoms, x->x_message);
+ else
+ x->x_open = 1;
+}
+
+static void speedlim_anything(t_speedlim *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (x->x_open)
+ speedlim_dooutput(x, s, ac, av);
+ else if (s && s != &s_ && !x->x_entered)
+ {
+ if (ac > x->x_size)
+ /* MAXSIZE not used, not even a warning...
+ LATER consider clipping */
+ x->x_message = grow_nodata(&ac, &x->x_size, x->x_message,
+ SPEEDLIM_INISIZE, x->x_messini,
+ sizeof(*x->x_message));
+ x->x_selector = s;
+ x->x_natoms = ac;
+ if (ac)
+ memcpy(x->x_message, av, ac * sizeof(*x->x_message));
+ }
+}
+
+static void speedlim_bang(t_speedlim *x)
+{
+ x->x_selector = &s_bang;
+ speedlim_anything(x, x->x_selector, 0, 0);
+}
+
+static void speedlim_float(t_speedlim *x, t_float f)
+{
+ x->x_selector = &s_float;
+ x->x_float = f;
+ speedlim_anything(x, x->x_selector, 0, 0);
+}
+
+static void speedlim_symbol(t_speedlim *x, t_symbol *s)
+{
+ x->x_selector = &s_symbol;
+ x->x_symbol = s;
+ speedlim_anything(x, x->x_selector, 0, 0);
+}
+
+/* LATER gpointer */
+
+static void speedlim_list(t_speedlim *x, t_symbol *s, int ac, t_atom *av)
+{
+ x->x_selector = &s_list;
+ speedlim_anything(x, x->x_selector, ac, av);
+}
+
+static void speedlim_ft1(t_speedlim *x, t_floatarg f)
+{
+ if (f < 0)
+ f = 0; /* redundant (and CHECKED) */
+ x->x_delta = f;
+ /* CHECKED: no rearming --
+ if clock is set, then new delta value is not used until next tick */
+}
+
+static void speedlim_free(t_speedlim *x)
+{
+ if (x->x_message != x->x_messini)
+ freebytes(x->x_message, x->x_size * sizeof(*x->x_message));
+ if (x->x_clock)
+ clock_free(x->x_clock);
+}
+
+static void *speedlim_new(t_floatarg f)
+{
+ t_speedlim *x = (t_speedlim *)pd_new(speedlim_class);
+ x->x_open = 1; /* CHECKED */
+ x->x_delta = 0;
+ x->x_selector = 0;
+ x->x_float = 0;
+ x->x_symbol = 0;
+ x->x_pointer = 0;
+ x->x_size = SPEEDLIM_INISIZE;
+ x->x_natoms = 0;
+ x->x_message = x->x_messini;
+ x->x_entered = 0;
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_anything);
+ x->x_clock = clock_new(x, (t_method)speedlim_tick);
+ speedlim_ft1(x, f);
+ return (x);
+}
+
+void speedlim_setup(void)
+{
+ speedlim_class = class_new(gensym("speedlim"),
+ (t_newmethod)speedlim_new,
+ (t_method)speedlim_free,
+ sizeof(t_speedlim), 0,
+ A_DEFFLOAT, 0);
+ class_addbang(speedlim_class, speedlim_bang);
+ class_addfloat(speedlim_class, speedlim_float);
+ class_addsymbol(speedlim_class, speedlim_symbol);
+ class_addlist(speedlim_class, speedlim_list);
+ class_addanything(speedlim_class, speedlim_anything);
+ class_addmethod(speedlim_class, (t_method)speedlim_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
diff --git a/cyclone/hammer/spell.c b/cyclone/hammer/spell.c
new file mode 100644
index 0000000..f9a32d6
--- /dev/null
+++ b/cyclone/hammer/spell.c
@@ -0,0 +1,149 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <stdio.h>
+#include "m_pd.h"
+#include "common/loud.h"
+
+typedef struct _spell
+{
+ t_object x_ob;
+ int x_minsize;
+ int x_padchar; /* actually, any nonnegative integer (CHECKED) */
+} t_spell;
+
+static t_class *spell_class;
+
+static void spell_fill(t_spell *x, int cnt)
+{
+ for (; cnt < x->x_minsize; cnt++)
+ outlet_float(((t_object *)x)->ob_outlet, x->x_padchar);
+}
+
+/* CHECKED: chars are spelled as signed */
+static int spell_out(t_spell *x, char *ptr, int flush)
+{
+ int cnt = 0;
+ while (*ptr)
+ outlet_float(((t_object *)x)->ob_outlet, *ptr++), cnt++;
+ if (flush)
+ {
+ spell_fill(x, cnt);
+ return (0);
+ }
+ return (cnt);
+}
+
+static void spell_bang(t_spell *x)
+{
+ /* need to somehow override a default bang-to-empty-list conversion... */
+ loud_nomethod((t_pd *)x, &s_bang); /* CHECKED */
+}
+
+static void spell_float(t_spell *x, t_float f)
+{
+ int i;
+ if (loud_checkint((t_pd *)x, f, &i, &s_float)) /* CHECKED */
+ {
+ char buf[16];
+ sprintf(buf, "%d", i); /* CHECKED (negative numbers) */
+ spell_out(x, buf, 1);
+ }
+}
+
+/* CHECKED: 'symbol' selector is not spelled! */
+static void spell_symbol(t_spell *x, t_symbol *s)
+{
+ spell_out(x, s->s_name, 1);
+}
+
+static void spell_list(t_spell *x, t_symbol *s, int ac, t_atom *av)
+{
+ int cnt = 0;
+ int addsep = 0;
+ while (ac--)
+ {
+ if (addsep)
+ {
+ outlet_float(((t_object *)x)->ob_outlet, x->x_padchar);
+ cnt++;
+ }
+ else addsep = 1;
+ if (av->a_type == A_FLOAT)
+ {
+ int i;
+ /* CHECKME */
+ if (loud_checkint((t_pd *)x, av->a_w.w_float, &i, &s_list))
+ {
+ char buf[16];
+ sprintf(buf, "%d", i); /* CHECKED (negative numbers) */
+ cnt += spell_out(x, buf, 0);
+ }
+ /* CHECKED: floats as empty strings (separator is added) */
+ }
+ /* CHECKED: symbols as empty strings (separator is added) */
+ av++;
+ }
+ if (cnt) /* CHECKED: empty list is silently ignored */
+ spell_fill(x, cnt);
+}
+
+static void spell_anything(t_spell *x, t_symbol *s, int ac, t_atom *av)
+{
+ int cnt = 0;
+ int addsep = 0;
+ if (s)
+ {
+ cnt += spell_out(x, s->s_name, 0);
+ addsep = 1;
+ }
+ while (ac--)
+ {
+ if (addsep)
+ {
+ outlet_float(((t_object *)x)->ob_outlet, x->x_padchar);
+ cnt++;
+ }
+ else addsep = 1;
+ if (av->a_type == A_FLOAT)
+ {
+ int i;
+ /* CHECKME */
+ if (loud_checkint((t_pd *)x, av->a_w.w_float, &i, &s_list))
+ {
+ char buf[16];
+ sprintf(buf, "%d", i); /* CHECKED (negative numbers) */
+ cnt += spell_out(x, buf, 0);
+ }
+ /* CHECKED: floats as empty strings (separator is added) */
+ }
+ else if (av->a_type == A_SYMBOL && av->a_w.w_symbol)
+ cnt += spell_out(x, av->a_w.w_symbol->s_name, 0);
+ av++;
+ }
+ if (cnt) /* CHECKED: empty list is silently ignored */
+ spell_fill(x, cnt);
+}
+
+static void *spell_new(t_floatarg f1, t_floatarg f2)
+{
+ t_spell *x = (t_spell *)pd_new(spell_class);
+ int i2 = (int)f2; /* CHECKED */
+ x->x_minsize = (f1 > 0 ? (int)f1 : 0);
+ x->x_padchar = (i2 < 0 ? 0 : (i2 > 0 ? i2 : ' ')); /* CHECKED */
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void spell_setup(void)
+{
+ spell_class = class_new(gensym("spell"),
+ (t_newmethod)spell_new, 0,
+ sizeof(t_spell), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addbang(spell_class, spell_bang);
+ class_addfloat(spell_class, spell_float);
+ class_addsymbol(spell_class, spell_symbol);
+ class_addlist(spell_class, spell_list);
+ class_addanything(spell_class, spell_anything);
+}
diff --git a/cyclone/hammer/split.c b/cyclone/hammer/split.c
new file mode 100644
index 0000000..2865f66
--- /dev/null
+++ b/cyclone/hammer/split.c
@@ -0,0 +1,64 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+
+/* CHECKED:
+ 'list <symbol>' silently ignored (LATER remove a warning)
+ '<number> <symbol>' as '<number>' (LATER remove a warning)
+ LATER more compatibility checks are needed...
+ LATER sort out float/int dilemmas
+*/
+
+typedef struct _split
+{
+ t_object x_ob;
+ int x_floatmode;
+ t_float x_min;
+ t_float x_max;
+ t_outlet *x_out2;
+} t_split;
+
+static t_class *split_class;
+
+static void split_float(t_split *x, t_float f)
+{
+ if (x->x_floatmode)
+ {
+ if (f >= x->x_min && f <= x->x_max)
+ outlet_float(((t_object *)x)->ob_outlet, f);
+ else outlet_float(x->x_out2, f);
+ }
+ else
+ {
+ /* CHECKED: no pre-truncation */
+ if (f >= x->x_min && f <= x->x_max)
+ outlet_float(((t_object *)x)->ob_outlet, (int)f);
+ else outlet_float(x->x_out2, (int)f);
+ }
+}
+
+static void *split_new(t_floatarg f1, t_floatarg f2)
+{
+ t_split *x = (t_split *)pd_new(split_class);
+ x->x_floatmode = (f1 != (int)f1);
+ /* CHECKED: defaults are [0..0] and [0..f1] (for positive f1) or [f1..0] */
+ if (f1 < f2) /* CHECKED */
+ x->x_min = f1, x->x_max = f2;
+ else
+ x->x_min = f2, x->x_max = f1;
+ floatinlet_new((t_object *)x, &x->x_min);
+ floatinlet_new((t_object *)x, &x->x_max);
+ outlet_new((t_object *)x, &s_float);
+ x->x_out2 = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void split_setup(void)
+{
+ split_class = class_new(gensym("split"),
+ (t_newmethod)split_new, 0,
+ sizeof(t_split), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addfloat(split_class, split_float);
+}
diff --git a/cyclone/hammer/spray.c b/cyclone/hammer/spray.c
new file mode 100644
index 0000000..8aa0556
--- /dev/null
+++ b/cyclone/hammer/spray.c
@@ -0,0 +1,93 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+
+#define SPRAY_MINOUTS 1
+/* CHECKED: no upper limit */
+#define SPRAY_DEFOUTS 2
+
+typedef struct _spray
+{
+ t_object x_ob;
+ int x_offset;
+ int x_nouts;
+ t_outlet **x_outs;
+} t_spray;
+
+static t_class *spray_class;
+
+static void spray_float(t_spray *x, t_float f)
+{
+ /* CHECKED: floats ignored (LATER rethink), ints loudly rejected */
+ if (f == (int)f) loud_error((t_pd *)x, "requires list");
+}
+
+/* LATER decide, whether float in first atom is to be truncated,
+ or causing a list to be ignored as in max (CHECKED) */
+static void spray_list(t_spray *x, t_symbol *s, int ac, t_atom *av)
+{
+ int ndx;
+ if (ac >= 2 && av->a_type == A_FLOAT
+ /* CHECKED: lists with negative effective ndx are ignored */
+ && (ndx = (int)av->a_w.w_float - x->x_offset) >= 0
+ && ndx < x->x_nouts)
+ {
+ /* CHECKED: ignored atoms (symbols and floats) are counted */
+ /* CHECKED: we must spray in right-to-left order */
+ t_atom *argp;
+ t_outlet **outp;
+ int last = ac - 1 + ndx; /* ndx of last outlet filled (first is 1) */
+ if (last > x->x_nouts)
+ {
+ argp = av + 1 + x->x_nouts - ndx;
+ outp = x->x_outs + x->x_nouts;
+ }
+ else
+ {
+ argp = av + ac;
+ outp = x->x_outs + last;
+ }
+ /* argp/outp now point to one after the first atom/outlet to deliver */
+ for (argp--, outp--; argp > av; argp--, outp--)
+ if (argp->a_type == A_FLOAT)
+ outlet_float(*outp, argp->a_w.w_float);
+ }
+}
+
+static void spray_free(t_spray *x)
+{
+ if (x->x_outs)
+ freebytes(x->x_outs, x->x_nouts * sizeof(*x->x_outs));
+}
+
+static void *spray_new(t_floatarg f1, t_floatarg f2)
+{
+ t_spray *x;
+ int i, nouts = (int)f1;
+ t_outlet **outs;
+ if (nouts < SPRAY_MINOUTS)
+ nouts = SPRAY_DEFOUTS;
+ if (!(outs = (t_outlet **)getbytes(nouts * sizeof(*outs))))
+ return (0);
+ x = (t_spray *)pd_new(spray_class);
+ x->x_nouts = nouts;
+ x->x_outs = outs;
+ x->x_offset = (int)f2;
+ for (i = 0; i < nouts; i++)
+ x->x_outs[i] = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void spray_setup(void)
+{
+ spray_class = class_new(gensym("spray"),
+ (t_newmethod)spray_new,
+ (t_method)spray_free,
+ sizeof(t_spray), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ /* CHECKED: bang, symbol, anything -- ``doesn't understand'' */
+ class_addfloat(spray_class, spray_float);
+ class_addlist(spray_class, spray_list);
+}
diff --git a/cyclone/hammer/sprintf.c b/cyclone/hammer/sprintf.c
new file mode 100644
index 0000000..aebfed3
--- /dev/null
+++ b/cyclone/hammer/sprintf.c
@@ -0,0 +1,634 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* FIXME empty string as a default for %s */
+
+#include <stdio.h>
+#include <string.h>
+#include "m_pd.h"
+#include "common/loud.h"
+
+#define SPRINTF_DEBUG 0
+
+/* Pattern types. These are the parsing routine's return values.
+ If returned value is >= SPRINTF_MINSLOTTYPE, then another slot
+ is created (i.e. an inlet, and a proxy handling it). */
+#define SPRINTF_UNSUPPORTED 0
+#define SPRINTF_LITERAL 1
+#define SPRINTF_MINSLOTTYPE 2
+#define SPRINTF_INT 2
+#define SPRINTF_FLOAT 3
+#define SPRINTF_CHAR 4
+#define SPRINTF_STRING 5
+
+/* Numbers: assuming max 62 digits preceding a decimal point in any
+ fixed-point representation of a t_float (39 in my system)
+ -- need to be sure, that using max precision would never produce
+ a representation longer than max width. If this is so, then no number
+ representation would exceed max width (presumably...).
+ Strings: for the time being, any string longer than max width would
+ be truncated (somehow compatible with Str256, but LATER warn-and-allow). */
+/* LATER rethink it all */
+#define SPRINTF_MAXPRECISION 192
+#define SPRINTF_MAXWIDTH 256
+
+typedef struct _sprintf
+{
+ t_object x_ob;
+ int x_nslots;
+ int x_nproxies; /* as requested (and allocated) */
+ t_pd **x_proxies;
+ int x_fsize; /* as allocated (i.e. including a terminating 0) */
+ char *x_fstring;
+} t_sprintf;
+
+typedef struct _sprintf_proxy
+{
+ t_object p_ob;
+ t_sprintf *p_master;
+ int p_id;
+ int p_type; /* a value #defined above */
+ char *p_pattern;
+ char *p_pattend;
+ t_atom p_atom; /* current input */
+ int p_size; /* also an input validation flag */
+} t_sprintf_proxy;
+
+static t_class *sprintf_class;
+static t_class *sprintf_proxy_class;
+
+/* CHECKED: 'symout' argument has no special meaning in max4.07,
+ LATER investigate */
+
+/* LATER use snprintf, if it is available on other systems (should be...) */
+static void sprintf_proxy_checkit(t_sprintf_proxy *x, char *buf, int checkin)
+{
+ int result = 0;
+ char *pattend = x->p_pattend;
+ if (pattend)
+ {
+ char tmp = *pattend;
+ *pattend = 0;
+ if (x->p_atom.a_type == A_FLOAT)
+ {
+ t_float f = x->p_atom.a_w.w_float;
+ if (x->p_type == SPRINTF_INT)
+ /* CHECKME large/negative values */
+ result = sprintf(buf, x->p_pattern, (int)f);
+ else if (x->p_type == SPRINTF_FLOAT)
+ result = sprintf(buf, x->p_pattern, f);
+ else if (x->p_type == SPRINTF_CHAR)
+ /* CHECKED: if 0 is input into a %c-slot, the whole output
+ string is null-terminated */
+ /* CHECKED: float into a %c-slot is truncated,
+ but CHECKME large/negative values */
+ result = sprintf(buf, x->p_pattern, (unsigned char)f);
+ else if (x->p_type == SPRINTF_STRING)
+ {
+ /* CHECKED: any number input into a %s-slot is ok */
+ char tmp[64]; /* LATER rethink */
+ sprintf(tmp, "%g", f);
+ result = sprintf(buf, x->p_pattern, tmp);
+ }
+ else /* LATER consider calling it a bug(), rather than error? */
+ loud_error((t_pd *)x->p_master,
+ "can't convert float to type of argument %d",
+ x->p_id + 1);
+ }
+ else if (x->p_atom.a_type == A_SYMBOL)
+ {
+ t_symbol *s = x->p_atom.a_w.w_symbol;
+ if (x->p_type == SPRINTF_STRING)
+ {
+ if (strlen(s->s_name) > SPRINTF_MAXWIDTH)
+ {
+ strncpy(buf, s->s_name, SPRINTF_MAXWIDTH);
+ buf[SPRINTF_MAXWIDTH] = 0;
+ result = SPRINTF_MAXWIDTH;
+ }
+ else result = sprintf(buf, x->p_pattern, s->s_name);
+ }
+ else /* CHECKED */
+ loud_error((t_pd *)x->p_master,
+ "can't convert symbol to type of argument %d",
+ x->p_id + 1);
+ }
+ *pattend = tmp;
+ }
+ else bug("sprintf_proxy_checkit");
+ if (result > 0)
+ {
+#if SPRINTF_DEBUG
+ if (checkin) post("[%d in \"%s\"]", result, buf);
+#endif
+ x->p_size = result;
+ }
+ else
+ {
+#if SPRINTF_DEBUG
+ if (checkin) post("checkit failed");
+#endif
+ x->p_size = 0;
+ }
+}
+
+static void sprintf_dooutput(t_sprintf *x)
+{
+ int i, outsize;
+ char *outstring;
+ outsize = x->x_fsize; /* this is strlen() + 1 */
+ /* LATER consider subtracting format pattern sizes */
+ for (i = 0; i < x->x_nslots; i++)
+ {
+ t_sprintf_proxy *y = (t_sprintf_proxy *)x->x_proxies[i];
+ if (y->p_size)
+ outsize += y->p_size;
+ else
+ {
+ /* slot i has received an invalid input -- CHECKME if this
+ condition blocks all subsequent output requests? */
+ return;
+ }
+ }
+ if (outsize > 0 && (outstring = getbytes(outsize)))
+ {
+ char *inp = x->x_fstring;
+ char *outp = outstring;
+ for (i = 0; i < x->x_nslots; i++)
+ {
+ t_sprintf_proxy *y = (t_sprintf_proxy *)x->x_proxies[i];
+ int len = y->p_pattern - inp;
+ if (len > 0)
+ {
+ strncpy(outp, inp, len);
+ outp += len;
+ }
+ sprintf_proxy_checkit(y, outp, 0);
+ outp += y->p_size; /* p_size is never negative */
+ inp = y->p_pattend;
+ }
+ strcpy(outp, inp);
+
+ outp = outstring;
+ while (*outp == ' ' || *outp == '\t'
+ || *outp == '\n' || *outp == '\r') outp++;
+ if (*outp)
+ {
+ t_binbuf *bb = binbuf_new();
+ int ac;
+ t_atom *av;
+ binbuf_text(bb, outp, strlen(outp));
+ ac = binbuf_getnatom(bb);
+ av = binbuf_getvec(bb);
+ if (ac)
+ {
+ if (av->a_type == A_SYMBOL)
+ outlet_anything(((t_object *)x)->ob_outlet,
+ av->a_w.w_symbol, ac - 1, av + 1);
+ else if (av->a_type == A_FLOAT)
+ {
+ if (ac > 1)
+ outlet_list(((t_object *)x)->ob_outlet,
+ &s_list, ac, av);
+ else
+ outlet_float(((t_object *)x)->ob_outlet,
+ av->a_w.w_float);
+ }
+ }
+ binbuf_free(bb);
+ }
+ freebytes(outstring, outsize);
+ }
+}
+
+static void sprintf_proxy_bang(t_sprintf_proxy *x)
+{
+ sprintf_dooutput(x->p_master); /* CHECKED (in any inlet) */
+}
+
+static void sprintf_proxy_float(t_sprintf_proxy *x, t_float f)
+{
+ char buf[SPRINTF_MAXWIDTH + 1]; /* LATER rethink */
+ SETFLOAT(&x->p_atom, f);
+ sprintf_proxy_checkit(x, buf, 1);
+ if (x->p_id == 0 && x->p_size)
+ sprintf_dooutput(x->p_master); /* CHECKED: only first inlet */
+}
+
+static void sprintf_proxy_symbol(t_sprintf_proxy *x, t_symbol *s)
+{
+ char buf[SPRINTF_MAXWIDTH + 1]; /* LATER rethink */
+ if (s && *s->s_name)
+ SETSYMBOL(&x->p_atom, s);
+ else
+ SETFLOAT(&x->p_atom, 0);
+ sprintf_proxy_checkit(x, buf, 1);
+ if (x->p_id == 0 && x->p_size)
+ sprintf_dooutput(x->p_master); /* CHECKED: only first inlet */
+}
+
+static void sprintf_dolist(t_sprintf *x,
+ t_symbol *s, int ac, t_atom *av, int startid)
+{
+ int cnt = x->x_nslots - startid;
+ if (ac > cnt)
+ ac = cnt;
+ if (ac-- > 0)
+ {
+ int id;
+ for (id = startid + ac, av += ac; id >= startid; id--, av--)
+ {
+ if (av->a_type == A_FLOAT)
+ sprintf_proxy_float((t_sprintf_proxy *)x->x_proxies[id],
+ av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL)
+ sprintf_proxy_symbol((t_sprintf_proxy *)x->x_proxies[id],
+ av->a_w.w_symbol);
+ }
+ }
+}
+
+static void sprintf_doanything(t_sprintf *x,
+ t_symbol *s, int ac, t_atom *av, int startid)
+{
+ if (s && s != &s_)
+ {
+ sprintf_dolist(x, 0, ac, av, startid + 1);
+ sprintf_proxy_symbol((t_sprintf_proxy *)x->x_proxies[startid], s);
+ }
+ else sprintf_dolist(x, 0, ac, av, startid);
+}
+
+static void sprintf_proxy_list(t_sprintf_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ sprintf_dolist(x->p_master, s, ac, av, x->p_id);
+}
+
+static void sprintf_proxy_anything(t_sprintf_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ sprintf_doanything(x->p_master, s, ac, av, x->p_id);
+}
+
+static void sprintf_bang(t_sprintf *x)
+{
+ if (x->x_nslots)
+ sprintf_proxy_bang((t_sprintf_proxy *)x->x_proxies[0]);
+}
+
+static void sprintf_float(t_sprintf *x, t_float f)
+{
+ if (x->x_nslots)
+ sprintf_proxy_float((t_sprintf_proxy *)x->x_proxies[0], f);
+}
+
+static void sprintf_symbol(t_sprintf *x, t_symbol *s)
+{
+ if (x->x_nslots)
+ sprintf_proxy_symbol((t_sprintf_proxy *)x->x_proxies[0], s);
+}
+
+static void sprintf_list(t_sprintf *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (x->x_nslots)
+ sprintf_dolist(x, s, ac, av, 0);
+}
+
+static void sprintf_anything(t_sprintf *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (x->x_nslots)
+ sprintf_doanything(x, s, ac, av, 0);
+}
+
+/* adjusted binbuf_gettext(), LATER do it right */
+static char *hammer_gettext(int ac, t_atom *av, int *sizep)
+{
+ char *buf = getbytes(1);
+ int size = 1;
+ char atomtext[MAXPDSTRING];
+ while (ac--)
+ {
+ char *newbuf;
+ int newsize;
+ if (buf[size-1] == 0 || av->a_type == A_SEMI || av->a_type == A_COMMA)
+ size--;
+ atom_string(av, atomtext, MAXPDSTRING);
+ newsize = size + strlen(atomtext) + 1;
+ if (!(newbuf = resizebytes(buf, size, newsize)))
+ {
+ *sizep = 1;
+ return (getbytes(1));
+ }
+ buf = newbuf;
+ strcpy(buf + size, atomtext);
+ size = newsize;
+ buf[size-1] = ' ';
+ av++;
+ }
+ buf[size-1] = 0;
+ *sizep = size;
+ return (buf);
+}
+
+/* Called twice: 1st pass (with x == 0) is used for counting valid patterns;
+ 2nd pass (after object allocation) -- for initializing the proxies.
+ If there is a "%%" pattern, then the buffer is shrinked in the second pass
+ (LATER rethink). */
+static int sprintf_parsepattern(t_sprintf *x, char **patternp)
+{
+ int type = SPRINTF_UNSUPPORTED;
+ char errstring[MAXPDSTRING];
+ char *ptr;
+ char modifier = 0;
+ int width = 0;
+ int precision = 0;
+ int *numfield = &width;
+ int dotseen = 0;
+ *errstring = 0;
+ for (ptr = *patternp; *ptr; ptr++)
+ {
+ if (*ptr >= '0' && *ptr <= '9')
+ {
+ if (!numfield)
+ {
+ if (x) sprintf(errstring, "extra number field");
+ break;
+ }
+ *numfield = 10 * *numfield + *ptr - '0';
+ if (dotseen)
+ {
+ if (precision > SPRINTF_MAXPRECISION)
+ {
+ if (x) sprintf(errstring, "precision field too large");
+ break;
+ }
+ }
+ else
+ {
+ if (width > SPRINTF_MAXWIDTH)
+ {
+ if (x) sprintf(errstring, "width field too large");
+ break;
+ }
+ }
+ continue;
+ }
+ if (*numfield)
+ numfield = 0;
+
+ if (strchr("diouxX", *ptr))
+ {
+ type = SPRINTF_INT;
+ break;
+ }
+ else if (strchr("aAeEfgG", *ptr))
+ {
+ if (modifier)
+ {
+ if (x) sprintf(errstring,
+ "\'%c\' modifier not supported", modifier);
+ break;
+ }
+ type = SPRINTF_FLOAT;
+ break;
+ }
+ else if (strchr("c", *ptr))
+ {
+ if (modifier)
+ {
+ if (x) sprintf(errstring,
+ "\'%c\' modifier not supported", modifier);
+ break;
+ }
+ type = SPRINTF_CHAR;
+ break;
+ }
+ else if (strchr("s", *ptr))
+ {
+ if (modifier)
+ {
+ if (x) sprintf(errstring,
+ "\'%c\' modifier not supported", modifier);
+ break;
+ }
+ type = SPRINTF_STRING;
+ break;
+ }
+ else if (*ptr == '%')
+ {
+ type = SPRINTF_LITERAL;
+ if (x)
+ { /* buffer-shrinking hack, LATER rethink */
+ char *p1 = ptr, *p2 = ptr + 1;
+ do
+ *p1++ = *p2;
+ while (*p2++);
+ ptr--;
+ }
+ break;
+ }
+ else if (strchr("CSnm", *ptr))
+ {
+ if (x) sprintf(errstring, "\'%c\' type not supported", *ptr);
+ break;
+ }
+ else if (strchr("l", *ptr))
+ {
+ if (modifier)
+ {
+ if (x) sprintf(errstring, "only single modifier is supported");
+ break;
+ }
+ modifier = *ptr;
+ }
+ else if (strchr("hjLqtzZ", *ptr))
+ {
+ if (x) sprintf(errstring, "\'%c\' modifier not supported", *ptr);
+ break;
+ }
+ else if (*ptr == '.')
+ {
+ if (dotseen)
+ {
+ if (x) sprintf(errstring, "multiple dots");
+ break;
+ }
+ numfield = &precision;
+ dotseen = 1;
+ }
+ else if (*ptr == '$')
+ {
+ if (x) sprintf(errstring, "parameter number field not supported");
+ break;
+ }
+ else if (*ptr == '*')
+ {
+ if (x) sprintf(errstring, "%s parameter not supported",
+ (dotseen ? "precision" : "width"));
+ break;
+ }
+ else if (!strchr("-+ #\'", *ptr))
+ {
+ if (x) sprintf(errstring,
+ "\'%c\' format character not supported", *ptr);
+ break;
+ }
+ }
+ if (*ptr)
+ ptr++; /* LATER rethink */
+ else
+ if (x) sprintf(errstring, "type not specified");
+ if (x && type == SPRINTF_UNSUPPORTED)
+ {
+ if (*errstring)
+ loud_error((t_pd *)x, "slot skipped (%s %s)",
+ errstring, "in a format pattern");
+ else
+ loud_error((t_pd *)x, "slot skipped");
+ }
+ *patternp = ptr;
+ return (type);
+}
+
+static void sprintf_free(t_sprintf *x)
+{
+ if (x->x_proxies)
+ {
+ int i = x->x_nslots;
+ while (i--)
+ {
+ t_sprintf_proxy *y = (t_sprintf_proxy *)x->x_proxies[i];
+ pd_free((t_pd *)y);
+ }
+ freebytes(x->x_proxies, x->x_nproxies * sizeof(*x->x_proxies));
+ }
+ if (x->x_fstring)
+ freebytes(x->x_fstring, x->x_fsize);
+}
+
+static void *sprintf_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_sprintf *x;
+ int fsize;
+ char *fstring;
+ char *p1, *p2;
+ int i, nslots, nproxies = 0;
+ t_pd **proxies;
+ fstring = hammer_gettext(ac, av, &fsize);
+ p1 = fstring;
+ while (p2 = strchr(p1, '%'))
+ {
+ int type;
+ p1 = p2 + 1;
+ type = sprintf_parsepattern(0, &p1);
+ if (type >= SPRINTF_MINSLOTTYPE)
+ nproxies++;
+ }
+ if (!nproxies)
+ {
+ /* CHECKED: an object without arguments, if created in the editor,
+ has no inlets/outlets, but it would have one inlet (no outlets)
+ upon loading. Error message is printed in either case. */
+ x = (t_sprintf *)pd_new(sprintf_class);
+ x->x_nslots = 0;
+ x->x_nproxies = 0;
+ x->x_proxies = 0;
+ x->x_fsize = fsize;
+ x->x_fstring = fstring;
+ p1 = fstring;
+ while (p2 = strchr(p1, '%'))
+ {
+ p1 = p2 + 1;
+ sprintf_parsepattern(x, &p1);
+ }
+ loud_error((t_pd *)x,
+ "an object created without valid format patterns...");
+ return (x);
+ }
+#if SPRINTF_DEBUG
+ post("%d slots:", nproxies);
+#endif
+ /* CHECKED: max creates as many inlets, as there are %-signs, no matter
+ if they are valid, or not -- if not, it prints ``can't convert'' errors
+ for any input... */
+ if (!(proxies = (t_pd **)getbytes(nproxies * sizeof(*proxies))))
+ {
+ freebytes(fstring, fsize);
+ return (0);
+ }
+ for (nslots = 0; nslots < nproxies; nslots++)
+ if (!(proxies[nslots] = pd_new(sprintf_proxy_class))) break;
+ if (!nslots)
+ {
+ freebytes(fstring, fsize);
+ freebytes(proxies, nproxies * sizeof(*proxies));
+ return (0);
+ }
+ x = (t_sprintf *)pd_new(sprintf_class);
+ x->x_nslots = nslots;
+ x->x_nproxies = nproxies;
+ x->x_proxies = proxies;
+ x->x_fsize = fsize;
+ x->x_fstring = fstring;
+ p1 = fstring;
+ i = 0;
+ while (p2 = strchr(p1, '%'))
+ {
+ int type;
+ p1 = p2 + 1;
+ type = sprintf_parsepattern(x, &p1);
+ if (type >= SPRINTF_MINSLOTTYPE)
+ {
+#if SPRINTF_DEBUG
+ char tmp = *++p1;
+ *p1 = 0;
+ poststring(p2);
+ endpost();
+ *p1 = tmp;
+#endif
+ if (i < nslots)
+ {
+ char buf[SPRINTF_MAXWIDTH + 1]; /* LATER rethink */
+ t_sprintf_proxy *y = (t_sprintf_proxy *)proxies[i];
+ y->p_master = x;
+ y->p_id = i;
+ y->p_type = type;
+ y->p_pattern = p2;
+ y->p_pattend = p1;
+ SETFLOAT(&y->p_atom, 0);
+ y->p_size = 0;
+ if (i) inlet_new((t_object *)x, (t_pd *)y, 0, 0);
+ sprintf_proxy_checkit(y, buf, 1);
+ i++;
+ }
+ }
+ }
+#if SPRINTF_DEBUG
+ post("printf(\"%s\", ...)", fstring);
+#endif
+ outlet_new((t_object *)x, &s_anything);
+ return (x);
+}
+
+void sprintf_setup(void)
+{
+ sprintf_class = class_new(gensym("sprintf"),
+ (t_newmethod)sprintf_new,
+ (t_method)sprintf_free,
+ sizeof(t_sprintf), 0, A_GIMME, 0);
+ class_addbang(sprintf_class, sprintf_bang);
+ class_addfloat(sprintf_class, sprintf_float);
+ class_addsymbol(sprintf_class, sprintf_symbol);
+ class_addlist(sprintf_class, sprintf_list);
+ class_addanything(sprintf_class, sprintf_anything);
+ sprintf_proxy_class = class_new(gensym("_sprintf_proxy"), 0, 0,
+ sizeof(t_sprintf_proxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addbang(sprintf_proxy_class, sprintf_proxy_bang);
+ class_addfloat(sprintf_proxy_class, sprintf_proxy_float);
+ class_addsymbol(sprintf_proxy_class, sprintf_proxy_symbol);
+ class_addlist(sprintf_proxy_class, sprintf_proxy_list);
+ class_addanything(sprintf_proxy_class, sprintf_proxy_anything);
+}
diff --git a/cyclone/hammer/substitute.c b/cyclone/hammer/substitute.c
new file mode 100644
index 0000000..48a9b9d
--- /dev/null
+++ b/cyclone/hammer/substitute.c
@@ -0,0 +1,340 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+#define SUBSTITUTE_INISIZE 32 /* LATER rethink */
+#define SUBSTITUTE_MAXSIZE 256
+
+typedef struct _substitute
+{
+ t_object x_ob;
+ t_pd *x_proxy;
+ t_atom x_match;
+ t_atom x_repl;
+ int x_size; /* as allocated */
+ t_atom *x_message;
+ t_atom x_messini[SUBSTITUTE_INISIZE];
+ int x_entered;
+ t_atom x_auxmatch;
+ t_atom x_auxrepl;
+ t_outlet *x_passout;
+} t_substitute;
+
+typedef struct _substitute_proxy
+{
+ t_object p_ob;
+ t_atom *p_match; /* pointing to parent's (aux)match */
+ t_atom *p_repl;
+} t_substitute_proxy;
+
+static t_class *substitute_class;
+static t_class *substitute_proxy_class;
+
+/* LATER rethink */
+static void substitute_dooutput(t_substitute *x,
+ t_symbol *s, int ac, t_atom *av, int pass)
+{
+ t_outlet *out = (pass ? x->x_passout : ((t_object *)x)->ob_outlet);
+ if (s == &s_float)
+ {
+ if (ac > 1)
+ outlet_list(out, &s_list, ac, av);
+ else
+ outlet_float(out, av->a_w.w_float);
+ }
+ else if (s == &s_bang && !ac) /* CHECKED */
+ outlet_bang(out);
+ else if (s == &s_symbol && ac == 1 && av->a_type == A_SYMBOL)
+ outlet_symbol(out, av->a_w.w_symbol);
+ else if (s)
+ outlet_anything(out, s, ac, av);
+ else if (ac)
+ outlet_list(out, &s_list, ac, av);
+}
+
+static int substitute_check(t_substitute *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (x->x_repl.a_type == A_NULL)
+ return (-2);
+ /* see substitute_proxy_validate() for possible types and values */
+ if (x->x_match.a_type == A_FLOAT)
+ {
+ t_float f = x->x_match.a_w.w_float;
+ int i;
+ for (i = 0; i < ac; i++, av++)
+ if (av->a_type == A_FLOAT && av->a_w.w_float == f)
+ return (i);
+ }
+ else if (x->x_match.a_type == A_SYMBOL)
+ {
+ /* match symbol is validated -- never null */
+ t_symbol *match = x->x_match.a_w.w_symbol;
+ int i;
+ if (s == match)
+ return (-1);
+ for (i = 0; i < ac; i++, av++)
+ if (av->a_type == A_SYMBOL && av->a_w.w_symbol == match)
+ return (i);
+ }
+ return (-2);
+}
+
+static void substitute_doit(t_substitute *x,
+ t_symbol *s, int ac, t_atom *av, int startndx)
+{
+ int cnt = ac - startndx;
+ if (cnt > 0)
+ {
+ t_atom *ap = av + startndx;
+ if (x->x_match.a_type == A_FLOAT)
+ {
+ t_float f = x->x_match.a_w.w_float;
+ while (cnt--)
+ {
+ if (ap->a_type == A_FLOAT && ap->a_w.w_float == f)
+ *ap = x->x_repl;
+ ap++;
+ }
+ }
+ else if (x->x_match.a_type == A_SYMBOL)
+ {
+ t_symbol *match = x->x_match.a_w.w_symbol;
+ while (cnt--)
+ {
+ if (ap->a_type == A_SYMBOL && ap->a_w.w_symbol == match)
+ *ap = x->x_repl;
+ ap++;
+ }
+ }
+ }
+ substitute_dooutput(x, s, ac, av, 0);
+}
+
+static void substitute_anything(t_substitute *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ int matchndx = substitute_check(x, s, ac, av);
+ if (matchndx < -1)
+ substitute_dooutput(x, s, ac, av, 1);
+ else
+ {
+ int reentered = x->x_entered;
+ int prealloc = !reentered;
+ int ntotal = ac;
+ t_atom *buf;
+ t_substitute_proxy *proxy = (t_substitute_proxy *)x->x_proxy;
+ x->x_entered = 1;
+ proxy->p_match = &x->x_auxmatch;
+ proxy->p_repl = &x->x_auxrepl;
+ if (s == &s_) s = 0;
+ if (matchndx == -1)
+ {
+ if (x->x_repl.a_type == A_FLOAT)
+ {
+ ntotal++;
+ if (ac) s = &s_list;
+ else s = &s_float;
+ }
+ else if (x->x_repl.a_type == A_SYMBOL)
+ {
+ s = x->x_repl.a_w.w_symbol;
+ matchndx = 0;
+ }
+ }
+ else if (matchndx == 0
+ && (!s || s == &s_list || s == &s_float)
+ && av->a_type == A_FLOAT
+ && x->x_repl.a_type == A_SYMBOL)
+ {
+ s = x->x_repl.a_w.w_symbol;
+ ac--;
+ av++;
+ ntotal = ac;
+ }
+ if (prealloc && ac > x->x_size)
+ {
+ if (ntotal > SUBSTITUTE_MAXSIZE)
+ prealloc = 0;
+ else
+ x->x_message = grow_nodata(&ntotal, &x->x_size, x->x_message,
+ SUBSTITUTE_INISIZE, x->x_messini,
+ sizeof(*x->x_message));
+ }
+ if (prealloc) buf = x->x_message;
+ else
+ /* LATER consider using the stack if ntotal <= MAXSTACK */
+ buf = getbytes(ntotal * sizeof(*buf));
+ if (buf)
+ {
+ int ncopy = ntotal;
+ t_atom *bp = buf;
+ if (matchndx == -1)
+ {
+ SETFLOAT(bp++, x->x_repl.a_w.w_float);
+ ncopy--;
+ }
+ if (ncopy)
+ memcpy(bp, av, ncopy * sizeof(*buf));
+ substitute_doit(x, s, ntotal, buf, matchndx);
+ if (buf != x->x_message)
+ freebytes(buf, ntotal * sizeof(*buf));
+ }
+ if (!reentered)
+ {
+ x->x_entered = 0;
+ if (x->x_auxmatch.a_type != A_NULL)
+ {
+ x->x_match = x->x_auxmatch;
+ x->x_auxmatch.a_type = A_NULL;
+ }
+ if (x->x_auxrepl.a_type != A_NULL)
+ {
+ x->x_repl = x->x_auxrepl;
+ x->x_auxrepl.a_type = A_NULL;
+ }
+ proxy->p_match = &x->x_match;
+ proxy->p_repl = &x->x_repl;
+ }
+ }
+}
+
+static void substitute_bang(t_substitute *x)
+{
+ substitute_anything(x, &s_bang, 0, 0);
+}
+
+static void substitute_float(t_substitute *x, t_float f)
+{
+ t_atom at;
+ SETFLOAT(&at, f);
+ substitute_anything(x, 0, 1, &at);
+}
+
+/* CHECKED (but LATER rethink) */
+static void substitute_symbol(t_substitute *x, t_symbol *s)
+{
+ t_atom at;
+ SETSYMBOL(&at, s);
+ substitute_anything(x, &s_symbol, 1, &at);
+}
+
+/* LATER gpointer */
+
+static void substitute_list(t_substitute *x, t_symbol *s, int ac, t_atom *av)
+{
+ substitute_anything(x, 0, ac, av);
+}
+
+static int substitute_atomvalidate(t_atom *ap)
+{
+ return (ap->a_type == A_FLOAT
+ || (ap->a_type == A_SYMBOL
+ && ap->a_w.w_symbol && ap->a_w.w_symbol != &s_));
+}
+
+/* CHECKED: 'set' is ignored, single '<atom>' does not modify a replacement */
+static void substitute_proxy_anything(t_substitute_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ if (s == &s_) s = 0;
+ if (s)
+ {
+ SETSYMBOL(x->p_match, s);
+ if (ac && substitute_atomvalidate(av))
+ *x->p_repl = *av;
+ }
+ else if (ac && substitute_atomvalidate(av))
+ {
+ *x->p_match = *av++;
+ if (ac > 1 && substitute_atomvalidate(av))
+ *x->p_repl = *av;
+ }
+}
+
+static void substitute_proxy_bang(t_substitute_proxy *x)
+{
+ SETSYMBOL(x->p_match, &s_bang);
+}
+
+static void substitute_proxy_float(t_substitute_proxy *x, t_float f)
+{
+ SETFLOAT(x->p_match, f);
+}
+
+/* CHECKED (but LATER rethink) */
+static void substitute_proxy_symbol(t_substitute_proxy *x, t_symbol *s)
+{
+ SETSYMBOL(x->p_match, &s_symbol);
+ SETSYMBOL(x->p_repl, s);
+}
+
+/* LATER gpointer */
+
+static void substitute_proxy_list(t_substitute_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ substitute_proxy_anything(x, 0, ac, av);
+}
+
+static void substitute_free(t_substitute *x)
+{
+ if (x->x_proxy) pd_free(x->x_proxy);
+ if (x->x_message != x->x_messini)
+ freebytes(x->x_message, x->x_size * sizeof(*x->x_message));
+}
+
+static void *substitute_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_substitute *x = 0;
+ t_substitute_proxy *proxy =
+ (t_substitute_proxy *)pd_new(substitute_proxy_class);
+ if (proxy)
+ {
+ x = (t_substitute *)pd_new(substitute_class);
+ proxy->p_match = &x->x_match;
+ proxy->p_repl = &x->x_repl;
+ x->x_proxy = (t_pd *)proxy;
+ x->x_size = SUBSTITUTE_INISIZE;
+ x->x_message = x->x_messini;
+ x->x_entered = 0;
+ /* CHECKED: everything is to be passed unchanged, until both are set */
+ /* CHECKED: max crashes if a match has been set, but not a replacement,
+ and there is a match */
+ x->x_match.a_type = x->x_repl.a_type = A_NULL;
+ x->x_auxmatch.a_type = x->x_auxrepl.a_type = A_NULL;
+ inlet_new((t_object *)x, (t_pd *)proxy, 0, 0);
+ outlet_new((t_object *)x, &s_anything);
+ /* CHECKED (refman error: 'a bang is sent') */
+ x->x_passout = outlet_new((t_object *)x, &s_anything);
+ substitute_proxy_anything(proxy, 0, ac, av);
+ }
+ return (x);
+}
+
+void substitute_setup(void)
+{
+ substitute_class = class_new(gensym("substitute"),
+ (t_newmethod)substitute_new,
+ (t_method)substitute_free,
+ sizeof(t_substitute), 0,
+ A_GIMME, 0);
+ class_addbang(substitute_class, substitute_bang);
+ class_addfloat(substitute_class, substitute_float);
+ class_addsymbol(substitute_class, substitute_symbol);
+ class_addlist(substitute_class, substitute_list);
+ class_addanything(substitute_class, substitute_anything);
+ substitute_proxy_class = class_new(gensym("_substitute_proxy"), 0, 0,
+ sizeof(t_substitute_proxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addbang(substitute_proxy_class, substitute_proxy_bang);
+ class_addfloat(substitute_proxy_class, substitute_proxy_float);
+ class_addsymbol(substitute_proxy_class, substitute_proxy_symbol);
+ class_addlist(substitute_proxy_class, substitute_proxy_list);
+ class_addanything(substitute_proxy_class, substitute_proxy_anything);
+ class_addmethod(substitute_proxy_class, (t_method)substitute_proxy_list,
+ gensym("set"), A_GIMME, 0);
+}
diff --git a/cyclone/hammer/sustain.c b/cyclone/hammer/sustain.c
new file mode 100644
index 0000000..975e6aa
--- /dev/null
+++ b/cyclone/hammer/sustain.c
@@ -0,0 +1,85 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+
+#define SUSTAIN_NPITCHES 128
+
+typedef struct _sustain
+{
+ t_object x_ob;
+ t_float x_velocity;
+ int x_switch;
+ unsigned char x_pitches[SUSTAIN_NPITCHES];
+ t_outlet *x_voutlet;
+} t_sustain;
+
+static t_class *sustain_class;
+
+static void sustain_float(t_sustain *x, t_float f)
+{
+ int pitch = (int)f;
+ if (pitch >= 0 && pitch < SUSTAIN_NPITCHES)
+ {
+ if (x->x_velocity || !x->x_switch)
+ {
+ outlet_float(x->x_voutlet, x->x_velocity);
+ outlet_float(((t_object *)x)->ob_outlet, pitch);
+ }
+ else x->x_pitches[pitch]++;
+ }
+}
+
+static void sustain_bang(t_sustain *x)
+{
+ int i;
+ unsigned char *pp;
+ for (i = 0, pp = x->x_pitches; i < SUSTAIN_NPITCHES; i++, pp++)
+ {
+ while (*pp)
+ {
+ outlet_float(x->x_voutlet, 0);
+ outlet_float(((t_object *)x)->ob_outlet, i);
+ (*pp)--;
+ }
+ }
+}
+
+static void sustain_clear(t_sustain *x)
+{
+ memset(x->x_pitches, 0, sizeof(x->x_pitches));
+}
+
+static void sustain_ft2(t_sustain *x, t_floatarg f)
+{
+ int newstate = ((int)f != 0);
+ if (x->x_switch && !newstate) sustain_bang(x);
+ x->x_switch = newstate;
+}
+
+static void *sustain_new(void)
+{
+ t_sustain *x = (t_sustain *)pd_new(sustain_class);
+ x->x_velocity = 0;
+ x->x_switch = 0;
+ sustain_clear(x);
+ floatinlet_new((t_object *)x, &x->x_velocity);
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft2"));
+ outlet_new((t_object *)x, &s_float);
+ x->x_voutlet = outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void sustain_setup(void)
+{
+ sustain_class = class_new(gensym("sustain"),
+ (t_newmethod)sustain_new,
+ 0, /* CHECKED: no flushout */
+ sizeof(t_sustain), 0, 0);
+ class_addfloat(sustain_class, sustain_float);
+ class_addbang(sustain_class, sustain_bang);
+ class_addmethod(sustain_class, (t_method)sustain_ft2,
+ gensym("ft2"), A_FLOAT, 0);
+}
diff --git a/cyclone/hammer/switch.c b/cyclone/hammer/switch.c
new file mode 100644
index 0000000..69317a1
--- /dev/null
+++ b/cyclone/hammer/switch.c
@@ -0,0 +1,152 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+
+#define SWITCH_MININLETS 2 /* LATER consider using 1 (with a warning) */
+#define SWITCH_MAXINLETS 100
+#define SWITCH_DEFINLETS 2
+
+typedef struct _switch
+{
+ t_object x_ob;
+ int x_open;
+ int x_ninlets; /* not counting left one */
+ int x_nproxies; /* as requested (and allocated) */
+ t_pd **x_proxies;
+} t_switch;
+
+typedef struct _switch_proxy
+{
+ t_object p_ob;
+ t_switch *p_master;
+ int p_id;
+} t_switch_proxy;
+
+static t_class *switch_class;
+static t_class *switch_proxy_class;
+
+static void switch_proxy_bang(t_switch_proxy *x)
+{
+ t_switch *master = x->p_master;
+ if (master->x_open == x->p_id)
+ outlet_bang(((t_object *)master)->ob_outlet);
+}
+
+static void switch_proxy_float(t_switch_proxy *x, t_float f)
+{
+ t_switch *master = x->p_master;
+ if (master->x_open == x->p_id)
+ outlet_float(((t_object *)master)->ob_outlet, f);
+}
+
+static void switch_proxy_symbol(t_switch_proxy *x, t_symbol *s)
+{
+ t_switch *master = x->p_master;
+ if (master->x_open == x->p_id)
+ outlet_symbol(((t_object *)master)->ob_outlet, s);
+}
+
+static void switch_proxy_pointer(t_switch_proxy *x, t_gpointer *gp)
+{
+ t_switch *master = x->p_master;
+ if (master->x_open == x->p_id)
+ outlet_pointer(((t_object *)master)->ob_outlet, gp);
+}
+
+static void switch_proxy_list(t_switch_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ t_switch *master = x->p_master;
+ if (master->x_open == x->p_id)
+ outlet_list(((t_object *)master)->ob_outlet, s, ac, av);
+}
+
+static void switch_proxy_anything(t_switch_proxy *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ t_switch *master = x->p_master;
+ if (master->x_open == x->p_id)
+ outlet_anything(((t_object *)master)->ob_outlet, s, ac, av);
+}
+
+static void switch_float(t_switch *x, t_float f)
+{
+ int i = (int)f;
+ if (i < 0) i = -i;
+ if (i > x->x_ninlets) i = x->x_ninlets;
+ x->x_open = i;
+}
+
+static void switch_bang(t_switch *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_open);
+}
+
+static void switch_free(t_switch *x)
+{
+ if (x->x_proxies)
+ {
+ int i = x->x_ninlets;
+ while (i--) pd_free(x->x_proxies[i]);
+ freebytes(x->x_proxies, x->x_nproxies * sizeof(*x->x_proxies));
+ }
+}
+
+static void *switch_new(t_floatarg f1, t_floatarg f2)
+{
+ t_switch *x;
+ int i, ninlets, nproxies = (int)f1;
+ t_pd **proxies;
+ if (nproxies < SWITCH_MININLETS)
+ nproxies = SWITCH_DEFINLETS;
+ if (nproxies > SWITCH_MAXINLETS)
+ loud_incompatible_max(switch_class, SWITCH_MAXINLETS, "inlets");
+ if (!(proxies = (t_pd **)getbytes(nproxies * sizeof(*proxies))))
+ return (0);
+ for (ninlets = 0; ninlets < nproxies; ninlets++)
+ if (!(proxies[ninlets] = pd_new(switch_proxy_class))) break;
+ if (ninlets < SWITCH_MININLETS)
+ {
+ int i = ninlets;
+ while (i--) pd_free(proxies[i]);
+ freebytes(proxies, nproxies * sizeof(*proxies));
+ return (0);
+ }
+ x = (t_switch *)pd_new(switch_class);
+ x->x_ninlets = ninlets;
+ x->x_nproxies = nproxies;
+ x->x_proxies = proxies;
+ for (i = 0; i < ninlets; i++)
+ {
+ t_switch_proxy *y = (t_switch_proxy *)proxies[i];
+ y->p_master = x;
+ y->p_id = i + 1;
+ inlet_new((t_object *)x, (t_pd *)y, 0, 0);
+ }
+ outlet_new((t_object *)x, &s_anything);
+ switch_float(x, (f2 > 0 ? f2 : 0)); /* CHECKED */
+ return (x);
+}
+
+void switch_setup(void)
+{
+ switch_class = class_new(gensym("switch"),
+ (t_newmethod)switch_new,
+ (t_method)switch_free,
+ sizeof(t_switch), 0,
+ A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addfloat(switch_class, switch_float);
+ class_addbang(switch_class, switch_bang);
+ switch_proxy_class = class_new(gensym("_switch_proxy"), 0, 0,
+ sizeof(t_switch_proxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addfloat(switch_proxy_class, switch_proxy_float);
+ class_addbang(switch_proxy_class, switch_proxy_bang);
+ class_addsymbol(switch_proxy_class, switch_proxy_symbol);
+ class_addpointer(switch_proxy_class, switch_proxy_pointer);
+ class_addlist(switch_proxy_class, switch_proxy_list);
+ class_addanything(switch_proxy_class, switch_proxy_anything);
+}
diff --git a/cyclone/hammer/tanh.c b/cyclone/hammer/tanh.c
new file mode 100644
index 0000000..e124d4c
--- /dev/null
+++ b/cyclone/hammer/tanh.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define tanhf tanh
+#endif
+
+typedef struct _tanh
+{
+ t_object x_ob;
+ float x_value;
+} t_tanh;
+
+static t_class *tanh_class;
+
+static void tanh_bang(t_tanh *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+}
+
+static void tanh_float(t_tanh *x, t_float f)
+{
+ /* CHECKME large values */
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value = tanhf(f));
+}
+
+static void *tanh_new(t_floatarg f)
+{
+ t_tanh *x = (t_tanh *)pd_new(tanh_class);
+ /* CHECKME large values */
+ x->x_value = tanhf(f);
+ outlet_new((t_object *)x, &s_float);
+ return (x);
+}
+
+void tanh_setup(void)
+{
+ tanh_class = class_new(gensym("tanh"),
+ (t_newmethod)tanh_new, 0,
+ sizeof(t_tanh), 0, A_DEFFLOAT, 0);
+ class_addbang(tanh_class, tanh_bang);
+ class_addfloat(tanh_class, tanh_float);
+}
diff --git a/cyclone/hammer/testmess.c b/cyclone/hammer/testmess.c
new file mode 100644
index 0000000..a6e8fe4
--- /dev/null
+++ b/cyclone/hammer/testmess.c
@@ -0,0 +1,245 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+
+#define TESTMESS_INISIZE 4 /* LATER rethink */
+#define TESTMESS_STACKSIZE 256
+
+typedef struct _testmess
+{
+ t_object x_ob;
+ t_symbol *x_method;
+ void (*x_messfun)(struct _testmess *, t_symbol *s, int, t_atom *);
+ int x_appendmode;
+ int x_size; /* as allocated */
+ int x_natoms; /* as used */
+ int x_tailwise; /* data is moved to the end of a buffer */
+ t_atom *x_message;
+ t_atom *x_messbuf;
+ t_atom x_messini[TESTMESS_INISIZE];
+} t_testmess;
+
+static t_class *testmess_class;
+
+static void testmess_setnatoms(t_testmess *x, int natoms)
+{
+ if (x->x_tailwise)
+ x->x_message = x->x_messbuf + x->x_size - natoms;
+ else
+ x->x_message = x->x_messbuf;
+ x->x_natoms = natoms;
+}
+
+static int testmess_makeroom(t_testmess *x, int natoms, int preserve)
+{
+ if (x->x_size < natoms)
+ {
+ int newsize = x->x_size * 2;
+ while (newsize < natoms) newsize *= 2;
+ post("makeroom %s %d %d %d", x->x_method->s_name,
+ preserve, natoms, newsize);
+ if (x->x_messbuf == x->x_messini)
+ {
+ if (!(x->x_messbuf =
+ (t_atom *)getbytes(newsize * sizeof(*x->x_messbuf))))
+ {
+ x->x_messbuf = x->x_messini;
+ testmess_setnatoms(x, preserve ? x->x_natoms : 0);
+ return (0);
+ }
+ x->x_size = newsize;
+ testmess_setnatoms(x, preserve ? x->x_natoms : 0);
+ if (x->x_natoms)
+ {
+ if (x->x_tailwise)
+ memcpy(x->x_message,
+ x->x_messini + TESTMESS_INISIZE - x->x_natoms,
+ x->x_natoms * sizeof(*x->x_message));
+ else
+ memcpy(x->x_message,
+ x->x_messini, x->x_natoms * sizeof(*x->x_message));
+ }
+ }
+ else
+ {
+ int oldsize = x->x_size;
+ if (!(x->x_messbuf =
+ (t_atom *)resizebytes(x->x_messbuf,
+ x->x_size * sizeof(*x->x_messbuf),
+ newsize * sizeof(*x->x_messbuf))))
+ {
+ x->x_messbuf = x->x_messini;
+ x->x_size = TESTMESS_INISIZE;
+ testmess_setnatoms(x, 0);
+ return (0);
+ }
+ x->x_size = newsize;
+ testmess_setnatoms(x, preserve ? x->x_natoms : 0);
+ if (x->x_natoms && x->x_tailwise)
+ memmove(x->x_message, x->x_messbuf + oldsize - x->x_natoms,
+ x->x_natoms * sizeof(*x->x_message));
+ }
+ }
+ return (1);
+}
+
+static void testmess_stackmess(t_testmess *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_atom buf[TESTMESS_STACKSIZE];
+ int natoms = x->x_natoms;
+ if (x->x_appendmode)
+ {
+ int left = TESTMESS_STACKSIZE - ac;
+ if (left < 0) ac = TESTMESS_STACKSIZE, natoms = 0;
+ else if (natoms > left) natoms = left;
+ if (ac)
+ memcpy(buf, av, ac * sizeof(*buf));
+ if (natoms)
+ memcpy(buf + ac, x->x_message, natoms * sizeof(*buf));
+ }
+ else
+ {
+ int left = TESTMESS_STACKSIZE - natoms;
+ if (left < 0) natoms = TESTMESS_STACKSIZE, ac = 0;
+ else if (ac > left) ac = left;
+ if (natoms)
+ memcpy(buf, x->x_message, natoms * sizeof(*buf));
+ if (ac)
+ memcpy(buf + natoms, av, ac * sizeof(*buf));
+ }
+ outlet_anything(((t_object *)x)->ob_outlet, s, natoms + ac, buf);
+}
+
+static void testmess_heapmess(t_testmess *x, t_symbol *s, int ac, t_atom *av)
+{
+ int ntotal = x->x_natoms + ac;
+ t_atom *buf = getbytes(ntotal * sizeof(*buf));
+ if (buf)
+ {
+ if (x->x_appendmode)
+ {
+ if (ac)
+ memcpy(buf, av, ac * sizeof(*buf));
+ if (x->x_natoms)
+ memcpy(buf + ac, x->x_message, x->x_natoms * sizeof(*buf));
+ }
+ else
+ {
+ if (x->x_natoms)
+ memcpy(buf, x->x_message, x->x_natoms * sizeof(*buf));
+ if (ac)
+ memcpy(buf + x->x_natoms, av, ac * sizeof(*buf));
+ }
+ outlet_anything(((t_object *)x)->ob_outlet, s, ntotal, buf);
+ freebytes(buf, ntotal * sizeof(*buf));
+ }
+}
+
+static void testmess_premess(t_testmess *x, t_symbol *s, int ac, t_atom *av)
+{
+ int ntotal = x->x_natoms + ac;
+ if (testmess_makeroom(x, ntotal, 1))
+ {
+ t_atom *buf;
+ if (x->x_appendmode)
+ {
+ buf = x->x_messbuf + x->x_size - ntotal;
+ if (ac)
+ memcpy(buf, av, ac * sizeof(*buf));
+ }
+ else
+ {
+ buf = x->x_messbuf;
+ if (ac)
+ memcpy(buf + x->x_natoms, av, ac * sizeof(*buf));
+ }
+ outlet_anything(((t_object *)x)->ob_outlet, s, ntotal, buf);
+ }
+}
+
+static void testmess_bang(t_testmess *x)
+{
+ if (x->x_natoms)
+ x->x_messfun(x, &s_list, 0, 0);
+}
+
+static void testmess_float(t_testmess *x, t_float f)
+{
+ t_atom at;
+ SETFLOAT(&at, f);
+ x->x_messfun(x, (x->x_natoms ? &s_list : &s_float), 1, &at);
+}
+
+static void testmess_symbol(t_testmess *x, t_symbol *s)
+{
+ x->x_messfun(x, s, 0, 0);
+}
+
+static void testmess_anything(t_testmess *x, t_symbol *s, int ac, t_atom *av)
+{
+ x->x_messfun(x, s, ac, av);
+}
+
+static void testmess_set(t_testmess *x, t_floatarg f1, t_floatarg f2)
+{
+ int natoms = (int)f1;
+ if (natoms > 0 && testmess_makeroom(x, natoms * 2, 0))
+ {
+ t_atom *ap;
+ int i = (int)f2;;
+ testmess_setnatoms(x, natoms);
+ ap = x->x_message;
+ while (natoms--)
+ {
+ SETFLOAT(ap, i);
+ i++; ap++;
+ }
+ }
+}
+
+static void testmess_free(t_testmess *x)
+{
+ if (x->x_messbuf != x->x_messini)
+ freebytes(x->x_messbuf, x->x_size * sizeof(*x->x_messbuf));
+}
+
+static void *testmess_new(t_symbol *s, t_floatarg f)
+{
+ t_testmess *x = (t_testmess *)pd_new(testmess_class);
+ x->x_appendmode = 1;
+ x->x_tailwise = 0;
+ if (s == gensym("stack"))
+ x->x_method = s, x->x_messfun = testmess_stackmess;
+ else if (s == gensym("heap"))
+ x->x_method = s, x->x_messfun = testmess_heapmess;
+ else
+ {
+ x->x_method = gensym("prealloc");
+ x->x_messfun = testmess_premess;
+ x->x_tailwise = x->x_appendmode;
+ }
+ x->x_size = TESTMESS_INISIZE;
+ x->x_messbuf = x->x_messini;
+ outlet_new((t_object *)x, &s_anything);
+ testmess_setnatoms(x, 0);
+ testmess_set(x, f, 0);
+ return (x);
+}
+
+void testmess_setup(void)
+{
+ testmess_class = class_new(gensym("testmess"),
+ (t_newmethod)testmess_new,
+ (t_method)testmess_free,
+ sizeof(t_testmess), 0,
+ A_DEFFLOAT, A_DEFSYM, 0);
+ class_addbang(testmess_class, testmess_bang);
+ class_addfloat(testmess_class, testmess_float);
+ class_addsymbol(testmess_class, testmess_symbol);
+ class_addanything(testmess_class, testmess_anything);
+ class_addmethod(testmess_class, (t_method)testmess_set,
+ gensym("set"), A_FLOAT, A_DEFFLOAT, 0);
+}
diff --git a/cyclone/hammer/thresh.c b/cyclone/hammer/thresh.c
new file mode 100644
index 0000000..6890dcc
--- /dev/null
+++ b/cyclone/hammer/thresh.c
@@ -0,0 +1,134 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+#define THRESH_INISIZE 32 /* LATER rethink */
+#define THRESH_MAXSIZE 256
+#define THRESH_DEFTHRESH 10
+
+typedef struct _thresh
+{
+ t_object x_ob;
+ t_float x_thresh;
+ int x_size; /* as allocated */
+ int x_natoms; /* as used */
+ t_atom *x_message;
+ t_atom x_messini[THRESH_INISIZE];
+ t_clock *x_clock;
+} t_thresh;
+
+static t_class *thresh_class;
+
+static void thresh_tick(t_thresh *x)
+{
+ int ac = x->x_natoms;
+ if (ac)
+ {
+ t_atom *av = x->x_message;
+ if (av->a_type == A_FLOAT) /* redundant, but we might need it LATER */
+ {
+ if (ac > 1)
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av);
+ else
+ outlet_float(((t_object *)x)->ob_outlet, av->a_w.w_float);
+ }
+ x->x_natoms = 0;
+ }
+}
+
+static void thresh_anything(t_thresh *x, t_symbol *s, int ac, t_atom *av)
+{
+ int ntotal = x->x_natoms + ac;
+ t_atom *buf;
+ clock_unset(x->x_clock);
+ if (s == &s_) s = 0;
+ if (s)
+ ntotal++;
+ if (ntotal > x->x_size)
+ {
+ /* LATER if (ntotal > THRESH_MAXSIZE)... (cf prepend) */
+ int nrequested = ntotal;
+ x->x_message = grow_withdata(&nrequested, &x->x_natoms,
+ &x->x_size, x->x_message,
+ THRESH_INISIZE, x->x_messini,
+ sizeof(*x->x_message));
+ if (nrequested != ntotal)
+ {
+ x->x_natoms = 0;
+ if (ac >= x->x_size)
+ ac = (s ? x->x_size - 1 : x->x_size);
+ }
+ }
+ buf = x->x_message + x->x_natoms;
+ if (s)
+ {
+ SETSYMBOL(buf, s);
+ buf++;
+ x->x_natoms++;
+ }
+ if (ac)
+ {
+ memcpy(buf, av, ac * sizeof(*buf));
+ x->x_natoms += ac;
+ }
+ clock_delay(x->x_clock, x->x_thresh);
+}
+
+static void thresh_float(t_thresh *x, t_float f)
+{
+ t_atom at;
+ SETFLOAT(&at, f);
+ thresh_anything(x, 0, 1, &at);
+}
+
+static void thresh_list(t_thresh *x, t_symbol *s, int ac, t_atom *av)
+{
+ thresh_anything(x, 0, ac, av);
+}
+
+static void thresh_ft1(t_thresh *x, t_floatarg f)
+{
+ if (f < 0)
+ f = 0; /* CHECKED */
+ x->x_thresh = f;
+ /* CHECKED: no rearming */
+}
+
+static void thresh_free(t_thresh *x)
+{
+ if (x->x_message != x->x_messini)
+ freebytes(x->x_message, x->x_size * sizeof(*x->x_message));
+ if (x->x_clock)
+ clock_free(x->x_clock);
+}
+
+static void *thresh_new(t_floatarg f)
+{
+ t_thresh *x = (t_thresh *)pd_new(thresh_class);
+ x->x_thresh = (f > 0 ? f : THRESH_DEFTHRESH);
+ x->x_size = THRESH_INISIZE;
+ x->x_natoms = 0;
+ x->x_message = x->x_messini;
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_list); /* LATER rethink: list or float */
+ x->x_clock = clock_new(x, (t_method)thresh_tick);
+ return (x);
+}
+
+void thresh_setup(void)
+{
+ thresh_class = class_new(gensym("thresh"),
+ (t_newmethod)thresh_new,
+ (t_method)thresh_free,
+ sizeof(t_thresh), 0,
+ A_DEFFLOAT, 0);
+ class_addfloat(thresh_class, thresh_float);
+ class_addlist(thresh_class, thresh_list);
+ class_addmethod(thresh_class, (t_method)thresh_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ /* CHECKED: thresh: doesn't understand bang, symbol, anything */
+}
diff --git a/cyclone/hammer/tosymbol.c b/cyclone/hammer/tosymbol.c
new file mode 100644
index 0000000..8b45ad0
--- /dev/null
+++ b/cyclone/hammer/tosymbol.c
@@ -0,0 +1,184 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <stdio.h>
+#include <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+#define TOSYMBOL_INISTRING 128 /* LATER rethink */
+#define TOSYMBOL_MAXSTRING 2048 /* the refman says so, later CHECKME */
+static char tosymbol_defseparator[] = " ";
+
+typedef struct _tosymbol
+{
+ t_object x_ob;
+ t_symbol *x_separator;
+ int x_bufsize;
+ char *x_buffer;
+ char x_bufini[TOSYMBOL_INISTRING];
+ int x_entered;
+} t_tosymbol;
+
+static t_class *tosymbol_class;
+static char tosymbol_buffer[TOSYMBOL_MAXSTRING];
+static int tosymbol_bufferlocked = 0;
+/* The idea is to prevent two different tosymbol objects from using the static
+ buffer at the same time. In the current scenario this buffer is never used
+ for output, so this lock is unnecessary... but it does no harm either... */
+
+static void tosymbol_flushbuffer(t_tosymbol *x)
+{
+ if (*x->x_buffer)
+ {
+ x->x_entered = 1;
+ outlet_symbol(((t_object *)x)->ob_outlet, gensym(x->x_buffer));
+ x->x_entered = 0;
+ }
+}
+
+static void tosymbol_bang(t_tosymbol *x)
+{
+ outlet_bang(((t_object *)x)->ob_outlet); /* CHECKED */
+}
+
+static void tosymbol_float(t_tosymbol *x, t_float f)
+{
+ if (!x->x_entered)
+ {
+ sprintf(x->x_buffer, "%g", f);
+ tosymbol_flushbuffer(x);
+ }
+}
+
+static void tosymbol_symbol(t_tosymbol *x, t_symbol *s)
+{
+ outlet_symbol(((t_object *)x)->ob_outlet, s);
+}
+
+static void tosymbol_pointer(t_tosymbol *x, t_gpointer *gp)
+{
+ /* nop: otherwise gpointer would be converted to 'list <gp>' */
+}
+
+static int tosymbol_parse(t_symbol *s, int ac, t_atom *av, t_symbol *separator,
+ int bufsize, char *buffer)
+{
+ int nleft = bufsize - 1;
+ int len;
+ char *bp = buffer;
+ bp[0] = bp[nleft] = 0;
+ if (s)
+ strncpy(bp, s->s_name, nleft);
+ len = strlen(bp);
+ nleft -= len;
+ bp += len;
+ if (ac && nleft > 0)
+ {
+ char *sepstring = (separator ?
+ separator->s_name : tosymbol_defseparator);
+ while (ac--)
+ {
+ if (*sepstring && bp > buffer)
+ {
+ strncpy(bp, sepstring, nleft);
+ len = strlen(bp);
+ nleft -= len;
+ if (nleft <= 0) break;
+ bp += len;
+ }
+ /* LATER rethink: type-checking */
+ atom_string(av, bp, nleft);
+ len = strlen(bp);
+ nleft -= len;
+ bp += len;
+ if (nleft <= 0) break;
+ av++;
+ }
+ }
+ if (nleft < 0)
+ {
+ bug("tosymbol_parse");
+ return (bufsize);
+ }
+ return (bufsize - nleft);
+}
+
+static void tosymbol_anything(t_tosymbol *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (!x->x_entered)
+ {
+ if (tosymbol_bufferlocked)
+ {
+ bug("tosymbol_anything");
+ tosymbol_parse(s, ac, av, x->x_separator,
+ x->x_bufsize, x->x_buffer);
+ }
+ else
+ {
+ int ntotal;
+ tosymbol_bufferlocked = 1;
+ ntotal = tosymbol_parse(s, ac, av, x->x_separator,
+ TOSYMBOL_MAXSTRING, tosymbol_buffer);
+ if (ntotal > x->x_bufsize)
+ {
+ int newtotal = ntotal;
+ x->x_buffer = grow_nodata(&newtotal, &x->x_bufsize, x->x_buffer,
+ TOSYMBOL_INISTRING, x->x_bufini,
+ sizeof(*x->x_buffer));
+ if (newtotal < ntotal)
+ {
+ ntotal = newtotal - 1;
+ x->x_buffer[ntotal] = 0;
+ }
+ }
+ memcpy(x->x_buffer, tosymbol_buffer, ntotal);
+ tosymbol_bufferlocked = 0;
+ }
+ tosymbol_flushbuffer(x);
+ }
+}
+
+static void tosymbol_list(t_tosymbol *x, t_symbol *s, int ac, t_atom *av)
+{
+ tosymbol_anything(x, 0, ac, av);
+}
+
+static void tosymbol_separator(t_tosymbol *x, t_symbol *s)
+{
+ x->x_separator = (s ? s : &s_); /* default: empty string */
+}
+
+static void tosymbol_free(t_tosymbol *x)
+{
+ if (x->x_buffer != x->x_bufini)
+ freebytes(x->x_buffer, x->x_bufsize);
+}
+
+static void *tosymbol_new(void)
+{
+ t_tosymbol *x = (t_tosymbol *)pd_new(tosymbol_class);
+ x->x_separator = 0; /* default: a space */
+ x->x_bufsize = TOSYMBOL_INISTRING;
+ x->x_buffer = x->x_bufini;
+ x->x_entered = 0;
+ outlet_new((t_object *)x, &s_symbol);
+ return (x);
+}
+
+void tosymbol_setup(void)
+{
+ tosymbol_class = class_new(gensym("tosymbol"),
+ (t_newmethod)tosymbol_new,
+ (t_method)tosymbol_free,
+ sizeof(t_tosymbol), 0, 0);
+ class_addbang(tosymbol_class, tosymbol_bang);
+ class_addfloat(tosymbol_class, tosymbol_float);
+ class_addsymbol(tosymbol_class, tosymbol_symbol);
+ class_addpointer(tosymbol_class, tosymbol_pointer);
+ class_addlist(tosymbol_class, tosymbol_list);
+ class_addanything(tosymbol_class, tosymbol_anything);
+ class_addmethod(tosymbol_class, (t_method)tosymbol_separator,
+ gensym("separator"), A_DEFSYM, 0);
+}
diff --git a/cyclone/hammer/universal.c b/cyclone/hammer/universal.c
new file mode 100644
index 0000000..b1731d8
--- /dev/null
+++ b/cyclone/hammer/universal.c
@@ -0,0 +1,167 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "g_canvas.h"
+#include "unstable/pd_imp.h"
+#include "common/loud.h"
+
+/* LATER fragilize */
+
+typedef struct _universal
+{
+ t_object x_ob;
+ t_glist *x_glist;
+ t_int x_descend;
+} t_universal;
+
+static t_class *universal_class;
+
+static void universal_dobang(t_glist *glist, int descend, t_symbol *cname)
+{
+ t_gobj *g;
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd)->c_name == cname) /* LATER rethink */
+ pd_bang(&g->g_pd);
+ if (descend)
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd) == canvas_class) /* LATER rethink */
+ universal_dobang((t_glist *)g, descend, cname);
+}
+
+static void universal_dofloat(t_glist *glist, int descend, t_symbol *cname,
+ t_float f)
+{
+ t_gobj *g;
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd)->c_name == cname) /* LATER rethink */
+ pd_float(&g->g_pd, f);
+ if (descend)
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd) == canvas_class) /* LATER rethink */
+ universal_dofloat((t_glist *)g, descend, cname, f);
+}
+
+static void universal_dosymbol(t_glist *glist, int descend, t_symbol *cname,
+ t_symbol *s)
+{
+ t_gobj *g;
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd)->c_name == cname) /* LATER rethink */
+ pd_symbol(&g->g_pd, s);
+ if (descend)
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd) == canvas_class) /* LATER rethink */
+ universal_dosymbol((t_glist *)g, descend, cname, s);
+}
+
+static void universal_dopointer(t_glist *glist, int descend, t_symbol *cname,
+ t_gpointer *gp)
+{
+ t_gobj *g;
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd)->c_name == cname) /* LATER rethink */
+ pd_pointer(&g->g_pd, gp);
+ if (descend)
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd) == canvas_class) /* LATER rethink */
+ universal_dopointer((t_glist *)g, descend, cname, gp);
+}
+
+static void universal_dolist(t_glist *glist, int descend, t_symbol *cname,
+ int ac, t_atom *av)
+{
+ t_gobj *g;
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd)->c_name == cname) /* LATER rethink */
+ pd_list(&g->g_pd, &s_list, ac, av);
+ if (descend)
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd) == canvas_class) /* LATER rethink */
+ universal_dolist((t_glist *)g, descend, cname, ac, av);
+}
+
+static void universal_doanything(t_glist *glist, int descend, t_symbol *cname,
+ t_symbol *s, int ac, t_atom *av)
+{
+ t_gobj *g;
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd)->c_name == cname) /* LATER rethink */
+ typedmess(&g->g_pd, s, ac, av);
+ if (descend)
+ for (g = glist->gl_list; g; g = g->g_next)
+ if (pd_class(&g->g_pd) == canvas_class) /* LATER rethink */
+ universal_doanything((t_glist *)g, descend, cname, s, ac, av);
+}
+
+/* LATER rethink type-checking -- it is borrowed from typedmess().
+ Anyway, do it once, before traversal, bypassing the generic mechanism
+ performed for every object. */
+static void universal_anything(t_universal *x, t_symbol *s, int ac, t_atom *av)
+{
+ /* CHECKED selector without arguments ignored with no complaints */
+ if (x->x_glist && s && ac)
+ {
+ if (av->a_type == A_FLOAT)
+ {
+ if (ac > 1)
+ universal_dolist(x->x_glist, x->x_descend, s, ac, av);
+ else
+ universal_dofloat(x->x_glist, x->x_descend, s, av->a_w.w_float);
+ }
+ else if (av->a_type == A_SYMBOL)
+ {
+ if (av->a_w.w_symbol == &s_bang)
+ universal_dobang(x->x_glist, x->x_descend, s);
+ else if (av->a_w.w_symbol == &s_float)
+ {
+ if (ac == 1)
+ universal_dofloat(x->x_glist, x->x_descend, s, 0.);
+ else if (av[1].a_type == A_FLOAT)
+ universal_dofloat(x->x_glist, x->x_descend, s,
+ av[1].a_w.w_float);
+ else
+ loud_error((t_pd *)x, "Bad argument for message 'float'");
+ }
+ else if (av->a_w.w_symbol == &s_symbol)
+ universal_dosymbol(x->x_glist, x->x_descend, s,
+ (ac > 1 && av[1].a_type == A_SYMBOL ?
+ av[1].a_w.w_symbol : &s_));
+ else if (av->a_w.w_symbol == &s_list)
+ universal_dolist(x->x_glist, x->x_descend, s, ac - 1, av + 1);
+ else
+ universal_doanything(x->x_glist, x->x_descend, s,
+ av->a_w.w_symbol, ac - 1, av + 1);
+ }
+ if (av->a_type == A_POINTER)
+ universal_dopointer(x->x_glist, x->x_descend, s,
+ av->a_w.w_gpointer);
+ }
+}
+
+static void universal_send(t_universal *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac && av->a_type == A_SYMBOL)
+ universal_anything(x, av->a_w.w_symbol, ac - 1, av + 1);
+ /* CHECKED: else ignored without complaints */
+}
+
+static void *universal_new(t_floatarg f)
+{
+ t_universal *x = (t_universal *)pd_new(universal_class);
+ x->x_glist = canvas_getcurrent();
+ x->x_descend = ((int)f != 0); /* CHECKED */
+ return (x);
+}
+
+void universal_setup(void)
+{
+ universal_class = class_new(gensym("universal"),
+ (t_newmethod)universal_new, 0,
+ sizeof(t_universal), 0, A_DEFFLOAT, 0);
+ class_addanything(universal_class, universal_anything);
+ /* CHECKED: 'send', not 'sendmessage' */
+ class_addmethod(universal_class, (t_method)universal_send,
+ gensym("send"), A_GIMME, 0);
+}
diff --git a/cyclone/hammer/urn.c b/cyclone/hammer/urn.c
new file mode 100644
index 0000000..59b140e
--- /dev/null
+++ b/cyclone/hammer/urn.c
@@ -0,0 +1,148 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* LATER think again about avoiding memory allocation overhead in run-time.
+ One would need to use a creation argument greater than any future right
+ inlet value. But this is incompatible (max uses a `static', max-size
+ array), and should be put somewhere in the docs... */
+
+#include "m_pd.h"
+#include "common/loud.h"
+#include "common/rand.h"
+#include "common/grow.h"
+
+#define URN_INISIZE 128 /* LATER rethink */
+#define URN_MAXSIZE 4096 /* CHECKED */
+#define URN_MAXIMUMSIZE 65536 /* LATER use USHRT_MAX */
+
+typedef struct _urn
+{
+ t_object x_ob;
+ int x_count;
+ int x_size; /* as allocated (in bytes) */
+ int x_range; /* as used */
+ unsigned short *x_urn;
+ unsigned short x_urnini[URN_INISIZE];
+ unsigned int x_seed;
+ t_outlet *x_bangout;
+} t_urn;
+
+static t_class *urn_class;
+
+static int urn_resize(t_urn *x, t_float f, int init)
+{
+ int maxmax = URN_MAXSIZE;
+ int range = (int)f; /* CHECKED silent truncation */
+ if (init)
+ {
+ maxmax--; /* CHECKED: max 4095 here (a bug, sort of) */
+ /* CHECKED in the constructor this is silent
+ (also > maxmax clipped without complaining) */
+ if (range < 1)
+ range = 1;
+ }
+ else if (range < 1)
+ {
+ /* CHECKED (the same for > maxmax) */
+ loud_error((t_pd *)x, "illegal size %d", f);
+ return (0);
+ }
+ if (range > URN_MAXIMUMSIZE)
+ {
+ loud_warning((t_pd *)x,
+ "requested size (%d) clipped -- effective size is %d",
+ range, URN_MAXIMUMSIZE);
+ range = URN_MAXIMUMSIZE;
+ }
+ if (range > maxmax)
+ loud_incompatible_max(urn_class, maxmax, "elements");
+ x->x_range = range;
+ if (range > x->x_size)
+ x->x_urn = grow_nodata(&x->x_range, &x->x_size, x->x_urn,
+ URN_INISIZE, x->x_urnini,
+ sizeof(*x->x_urn));
+ return (1);
+}
+
+static void urn_bang(t_urn *x)
+{
+ if (x->x_count)
+ {
+ int ndx = rand_int(&x->x_seed, x->x_count);
+ unsigned short pick = x->x_urn[ndx];
+ x->x_urn[ndx] = x->x_urn[--x->x_count];
+ outlet_float(((t_object *)x)->ob_outlet, pick);
+ }
+ /* CHECKED: start banging when the first bang is input
+ into an empty urn (and not when the last value is output).
+ CHECKED: keep banging until cleared. */
+ else outlet_bang(x->x_bangout);
+}
+
+static void urn_clear(t_urn *x)
+{
+ int i;
+ x->x_count = x->x_range;
+ for (i = 0; i < x->x_count; i++) x->x_urn[i] = i;
+}
+
+static void urn_float(t_urn *x, t_float f)
+{
+ /* CHECKED: float loudly rejected, int (any value) same as bang */
+ int i;
+ if (loud_checkint((t_pd *)x, f, &i, &s_float))
+ urn_bang(x);
+}
+
+static void urn_ft1(t_urn *x, t_floatarg f)
+{
+ if (urn_resize(x, f, 0)) /* CHECKED cleared only if a legal resize */
+ urn_clear(x);
+}
+
+static void urn_seed(t_urn *x, t_floatarg f)
+{
+ int i = (int)f; /* CHECKED */
+ if (i < 0)
+ i = 1; /* CHECKED */
+ rand_seed(&x->x_seed, (unsigned int)i);
+}
+
+static void urn_free(t_urn *x)
+{
+ if (x->x_urn != x->x_urnini)
+ freebytes(x->x_urn, x->x_size * sizeof(*x->x_urn));
+}
+
+static void *urn_new(t_floatarg f1, t_floatarg f2)
+{
+ t_urn *x = (t_urn *)pd_new(urn_class);
+ x->x_size = URN_INISIZE;
+ x->x_urn = x->x_urnini;
+ urn_resize(x, f1, 1);
+ urn_seed(x, f2); /* CHECKME */
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_float);
+ x->x_bangout = outlet_new((t_object *)x, &s_bang);
+ urn_clear(x);
+ return (x);
+}
+
+void urn_setup(void)
+{
+ urn_class = class_new(gensym("urn"),
+ (t_newmethod)urn_new,
+ (t_method)urn_free,
+ sizeof(t_urn), 0,
+ A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addbang(urn_class, urn_bang);
+ class_addfloat(urn_class, urn_float);
+ class_addmethod(urn_class, (t_method)urn_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ /* CHECKED list is auto-unfolded */
+ class_addmethod(urn_class, (t_method)urn_seed,
+ gensym("seed"), A_FLOAT, 0); /* CHECKED arg obligatory */
+ class_addmethod(urn_class, (t_method)urn_clear,
+ gensym("clear"), 0);
+}
diff --git a/cyclone/hammer/xbendin.c b/cyclone/hammer/xbendin.c
new file mode 100644
index 0000000..54082b3
--- /dev/null
+++ b/cyclone/hammer/xbendin.c
@@ -0,0 +1,93 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+
+typedef struct _xbendin
+{
+ t_object x_ob;
+ int x_omni;
+ unsigned char x_ready;
+ unsigned char x_status;
+ unsigned char x_channel;
+ unsigned char x_lsb;
+ t_outlet *x_chanout;
+} t_xbendin;
+
+static t_class *xbendin_class;
+
+static void xbendin_clear(t_xbendin *x)
+{
+ x->x_status = 0;
+ x->x_ready = 0;
+}
+
+static void xbendin_float(t_xbendin *x, t_float f)
+{
+ int ival = (int)f; /* CHECKME */
+ if (ival < 0)
+ {
+ /* CHECKME */
+ return;
+ }
+ if (ival < 256) /* CHECKME */
+ {
+ unsigned char bval = ival;
+ if (bval & 0x80)
+ {
+ unsigned char status = bval & 0xF0;
+ if (status == 0xF0)
+ {
+ /* CHECKME */
+ if (bval < 0xF8)
+ xbendin_clear(x);
+ }
+ else if (status == 0xE0)
+ {
+ unsigned char channel = bval & 0x0F;
+ if (x->x_omni)
+ x->x_channel = channel;
+ x->x_status = (x->x_channel == channel);
+ x->x_ready = 0;
+ }
+ else xbendin_clear(x);
+ }
+ else if (x->x_ready)
+ {
+ if (x->x_omni)
+ outlet_float(x->x_chanout, x->x_channel + 1);
+ outlet_float(((t_object *)x)->ob_outlet, (bval << 7) + x->x_lsb);
+ x->x_ready = 0;
+ }
+ else if (x->x_status)
+ {
+ x->x_lsb = bval;
+ x->x_ready = 1;
+ }
+ }
+ else xbendin_clear(x);
+}
+
+static void *xbendin_new(t_floatarg f)
+{
+ int channel = (int)f; /* CHECKME */
+ t_xbendin *x = (t_xbendin *)pd_new(xbendin_class);
+ outlet_new((t_object *)x, &s_float);
+ if (x->x_omni = (channel == 0)) /* CHECKME */
+ x->x_chanout = outlet_new((t_object *)x, &s_float);
+ else
+ x->x_channel = (unsigned char)--channel; /* CHECKME */
+ xbendin_clear(x);
+ return (x);
+}
+
+void xbendin_setup(void)
+{
+ xbendin_class = class_new(gensym("xbendin"),
+ (t_newmethod)xbendin_new, 0,
+ sizeof(t_xbendin), 0,
+ A_DEFFLOAT, 0);
+ class_addfloat(xbendin_class, xbendin_float);
+ /* CHECKME autocasting lists to floats */
+}
diff --git a/cyclone/hammer/xbendin2.c b/cyclone/hammer/xbendin2.c
new file mode 100644
index 0000000..1336800
--- /dev/null
+++ b/cyclone/hammer/xbendin2.c
@@ -0,0 +1,99 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+
+/* LATER find a better way to synchronize with xbendin,
+ while avoiding the c74's bug... */
+
+typedef struct _xbendin2
+{
+ t_object x_ob;
+ int x_omni;
+ unsigned char x_ready;
+ unsigned char x_status;
+ unsigned char x_channel;
+ unsigned char x_lsb;
+ t_outlet *x_lsbout;
+ t_outlet *x_chanout;
+} t_xbendin2;
+
+static t_class *xbendin2_class;
+
+static void xbendin2_clear(t_xbendin2 *x)
+{
+ x->x_status = 0;
+ x->x_ready = 0;
+}
+
+static void xbendin2_float(t_xbendin2 *x, t_float f)
+{
+ int ival = (int)f; /* CHECKME */
+ if (ival < 0)
+ {
+ /* CHECKME */
+ return;
+ }
+ if (ival < 256) /* CHECKME */
+ {
+ unsigned char bval = ival;
+ if (bval & 0x80)
+ {
+ unsigned char status = bval & 0xF0;
+ if (status == 0xF0)
+ {
+ /* CHECKME */
+ if (bval < 0xF8)
+ xbendin2_clear(x);
+ }
+ else if (status == 0xE0)
+ {
+ unsigned char channel = bval & 0x0F;
+ if (x->x_omni)
+ x->x_channel = channel;
+ x->x_status = (x->x_channel == channel);
+ x->x_ready = 0;
+ }
+ else xbendin2_clear(x);
+ }
+ else if (x->x_ready)
+ {
+ if (x->x_omni)
+ outlet_float(x->x_chanout, x->x_channel + 1);
+ outlet_float(x->x_lsbout, x->x_lsb);
+ outlet_float(((t_object *)x)->ob_outlet, bval);
+ x->x_ready = 0;
+ }
+ else if (x->x_status)
+ {
+ x->x_lsb = bval;
+ x->x_ready = 1;
+ }
+ }
+ else xbendin2_clear(x);
+}
+
+static void *xbendin2_new(t_floatarg f)
+{
+ int channel = (int)f; /* CHECKME */
+ t_xbendin2 *x = (t_xbendin2 *)pd_new(xbendin2_class);
+ outlet_new((t_object *)x, &s_float);
+ x->x_lsbout = outlet_new((t_object *)x, &s_float);
+ if (x->x_omni = (channel == 0)) /* CHECKME */
+ x->x_chanout = outlet_new((t_object *)x, &s_float);
+ else
+ x->x_channel = (unsigned char)--channel; /* CHECKME */
+ xbendin2_clear(x);
+ return (x);
+}
+
+void xbendin2_setup(void)
+{
+ xbendin2_class = class_new(gensym("xbendin2"),
+ (t_newmethod)xbendin2_new, 0,
+ sizeof(t_xbendin2), 0,
+ A_DEFFLOAT, 0);
+ class_addfloat(xbendin2_class, xbendin2_float);
+ /* CHECKME autocasting lists to floats */
+}
diff --git a/cyclone/hammer/xbendout.c b/cyclone/hammer/xbendout.c
new file mode 100644
index 0000000..faa401e
--- /dev/null
+++ b/cyclone/hammer/xbendout.c
@@ -0,0 +1,54 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+
+typedef struct _xbendout
+{
+ t_object x_ob;
+ t_float x_channel;
+ int x_value;
+} t_xbendout;
+
+static t_class *xbendout_class;
+
+static void xbendout_dooutput(t_xbendout *x)
+{
+ int value = x->x_value;
+ int channel = (int)x->x_channel; /* CHECKME */
+ if (value >= 0 && /* CHECKME */
+ value <= 16383 && /* CHECKME */
+ channel > 0) /* CHECKME */
+ {
+ outlet_float(((t_object *)x)->ob_outlet, 224 + ((channel-1) & 0x0F));
+ outlet_float(((t_object *)x)->ob_outlet, value & 0x7F);
+ outlet_float(((t_object *)x)->ob_outlet, value >> 7);
+ }
+}
+
+static void xbendout_float(t_xbendout *x, t_float f)
+{
+ x->x_value = (int)f; /* CHECKME */
+ xbendout_dooutput(x);
+}
+
+static void *xbendout_new(t_floatarg f)
+{
+ t_xbendout *x = (t_xbendout *)pd_new(xbendout_class);
+ floatinlet_new((t_object *)x, &x->x_channel);
+ outlet_new((t_object *)x, &s_float);
+ x->x_channel = ((int)f > 0 ? f : 1); /* CHECKME */
+ x->x_value = 8192; /* CHECKME if not -1 */
+ return (x);
+}
+
+void xbendout_setup(void)
+{
+ xbendout_class = class_new(gensym("xbendout"),
+ (t_newmethod)xbendout_new, 0,
+ sizeof(t_xbendout), 0,
+ A_DEFFLOAT, 0);
+ class_addbang(xbendout_class, xbendout_dooutput);
+ class_addfloat(xbendout_class, xbendout_float);
+}
diff --git a/cyclone/hammer/xbendout2.c b/cyclone/hammer/xbendout2.c
new file mode 100644
index 0000000..a2f8817
--- /dev/null
+++ b/cyclone/hammer/xbendout2.c
@@ -0,0 +1,60 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+
+typedef struct _xbendout2
+{
+ t_object x_ob;
+ t_float x_channel;
+ t_float x_lsb;
+ int x_msb;
+} t_xbendout2;
+
+static t_class *xbendout2_class;
+
+static void xbendout2_dooutput(t_xbendout2 *x)
+{
+ int msb = x->x_msb;
+ int lsb = (int)x->x_lsb; /* CHECKME */
+ int channel = (int)x->x_channel; /* CHECKME */
+ if (msb >= 0 && /* CHECKME */
+ msb <= 127 && /* CHECKME */
+ lsb >= 0 && /* CHECKME */
+ lsb <= 127 && /* CHECKME */
+ channel > 0) /* CHECKME */
+ {
+ outlet_float(((t_object *)x)->ob_outlet, 224 + ((channel-1) & 0x0F));
+ outlet_float(((t_object *)x)->ob_outlet, lsb);
+ outlet_float(((t_object *)x)->ob_outlet, msb);
+ }
+}
+
+static void xbendout2_float(t_xbendout2 *x, t_float f)
+{
+ x->x_msb = (int)f; /* CHECKME */
+ xbendout2_dooutput(x);
+}
+
+static void *xbendout2_new(t_floatarg f)
+{
+ t_xbendout2 *x = (t_xbendout2 *)pd_new(xbendout2_class);
+ floatinlet_new((t_object *)x, &x->x_lsb);
+ floatinlet_new((t_object *)x, &x->x_channel);
+ outlet_new((t_object *)x, &s_float);
+ x->x_channel = ((int)f > 0 ? f : 1); /* CHECKME */
+ x->x_lsb = 0;
+ x->x_msb = 64; /* CHECKME if not -1 */
+ return (x);
+}
+
+void xbendout2_setup(void)
+{
+ xbendout2_class = class_new(gensym("xbendout2"),
+ (t_newmethod)xbendout2_new, 0,
+ sizeof(t_xbendout2), 0,
+ A_DEFFLOAT, 0);
+ class_addbang(xbendout2_class, xbendout2_dooutput);
+ class_addfloat(xbendout2_class, xbendout2_float);
+}
diff --git a/cyclone/hammer/xnotein.c b/cyclone/hammer/xnotein.c
new file mode 100644
index 0000000..73b271b
--- /dev/null
+++ b/cyclone/hammer/xnotein.c
@@ -0,0 +1,100 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+
+typedef struct _xnotein
+{
+ t_object x_ob;
+ int x_omni;
+ unsigned char x_ready;
+ unsigned char x_status;
+ unsigned char x_channel;
+ unsigned char x_pitch;
+ t_outlet *x_velout;
+ t_outlet *x_flagout;
+ t_outlet *x_chanout;
+} t_xnotein;
+
+static t_class *xnotein_class;
+
+static void xnotein_clear(t_xnotein *x)
+{
+ x->x_status = 0;
+ x->x_ready = 0;
+}
+
+static void xnotein_float(t_xnotein *x, t_float f)
+{
+ int ival = (int)f; /* CHECKME */
+ if (ival < 0)
+ {
+ /* CHECKME */
+ return;
+ }
+ if (ival < 256) /* CHECKME */
+ {
+ unsigned char bval = ival;
+ if (bval & 0x80)
+ {
+ unsigned char status = bval & 0xF0;
+ if (status == 0xF0)
+ {
+ /* CHECKME */
+ if (bval < 0xF8)
+ xnotein_clear(x);
+ }
+ else if (status == 0x80 || status == 0x90)
+ {
+ unsigned char channel = bval & 0x0F;
+ if (x->x_omni)
+ x->x_channel = channel;
+ x->x_status = (x->x_channel == channel ? status : 0);
+ x->x_ready = 0;
+ }
+ else xnotein_clear(x);
+ }
+ else if (x->x_ready)
+ {
+ int flag = (x->x_status == 0x90 && bval);
+ if (x->x_omni)
+ outlet_float(x->x_chanout, x->x_channel + 1);
+ outlet_float(x->x_flagout, flag);
+ outlet_float(x->x_velout, bval);
+ outlet_float(((t_object *)x)->ob_outlet, x->x_pitch);
+ x->x_ready = 0;
+ }
+ else if (x->x_status)
+ {
+ x->x_pitch = bval;
+ x->x_ready = 1;
+ }
+ }
+ else xnotein_clear(x);
+}
+
+static void *xnotein_new(t_floatarg f)
+{
+ int channel = (int)f; /* CHECKME */
+ t_xnotein *x = (t_xnotein *)pd_new(xnotein_class);
+ outlet_new((t_object *)x, &s_float);
+ x->x_velout = outlet_new((t_object *)x, &s_float);
+ x->x_flagout = outlet_new((t_object *)x, &s_float);
+ if (x->x_omni = (channel == 0)) /* CHECKME */
+ x->x_chanout = outlet_new((t_object *)x, &s_float);
+ else
+ x->x_channel = (unsigned char)--channel; /* CHECKME */
+ xnotein_clear(x);
+ return (x);
+}
+
+void xnotein_setup(void)
+{
+ xnotein_class = class_new(gensym("xnotein"),
+ (t_newmethod)xnotein_new, 0,
+ sizeof(t_xnotein), 0,
+ A_DEFFLOAT, 0);
+ class_addfloat(xnotein_class, xnotein_float);
+ /* CHECKME autocasting lists to floats */
+}
diff --git a/cyclone/hammer/xnoteout.c b/cyclone/hammer/xnoteout.c
new file mode 100644
index 0000000..058c7f9
--- /dev/null
+++ b/cyclone/hammer/xnoteout.c
@@ -0,0 +1,62 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+
+typedef struct _xnoteout
+{
+ t_object x_ob;
+ t_float x_channel;
+ t_float x_flag;
+ t_float x_velocity;
+ int x_pitch;
+} t_xnoteout;
+
+static t_class *xnoteout_class;
+
+static void xnoteout_dooutput(t_xnoteout *x)
+{
+ int status = ((int)x->x_flag ? 0x90 : 0x80); /* CHECKME */
+ int channel = (int)x->x_channel; /* CHECKME */
+ int pitch = x->x_pitch;
+ int velocity = (int)x->x_velocity & 0x7F; /* CHECKME */
+ if (pitch >= 0 && /* CHECKME */
+ pitch <= 127 && /* CHECKME */
+ channel > 0) /* CHECKME */
+ {
+ outlet_float(((t_object *)x)->ob_outlet, status + ((channel-1) & 0x0F));
+ outlet_float(((t_object *)x)->ob_outlet, pitch);
+ outlet_float(((t_object *)x)->ob_outlet, velocity);
+ }
+}
+
+static void xnoteout_float(t_xnoteout *x, t_float f)
+{
+ x->x_pitch = (int)f; /* CHECKME */
+ xnoteout_dooutput(x);
+}
+
+static void *xnoteout_new(t_floatarg f)
+{
+ t_xnoteout *x = (t_xnoteout *)pd_new(xnoteout_class);
+ floatinlet_new((t_object *)x, &x->x_velocity);
+ floatinlet_new((t_object *)x, &x->x_flag);
+ floatinlet_new((t_object *)x, &x->x_channel);
+ outlet_new((t_object *)x, &s_float);
+ x->x_channel = ((int)f > 0 ? f : 1); /* CHECKME */
+ x->x_flag = 0; /* CHECKME */
+ x->x_velocity = 0; /* CHECKME */
+ x->x_pitch = -1; /* CHECKME */
+ return (x);
+}
+
+void xnoteout_setup(void)
+{
+ xnoteout_class = class_new(gensym("xnoteout"),
+ (t_newmethod)xnoteout_new, 0,
+ sizeof(t_xnoteout), 0,
+ A_DEFFLOAT, 0);
+ class_addbang(xnoteout_class, xnoteout_dooutput);
+ class_addfloat(xnoteout_class, xnoteout_float);
+}
diff --git a/cyclone/hammer/zl.c b/cyclone/hammer/zl.c
new file mode 100644
index 0000000..566c18e
--- /dev/null
+++ b/cyclone/hammer/zl.c
@@ -0,0 +1,982 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/loud.h"
+#include "common/grow.h"
+
+/* LATER test reentrancy, tune speedwise */
+
+#define ZL_DEBUG
+
+#define ZL_INISIZE 32 /* LATER rethink */
+#define ZL_MAXSIZE 256
+#define ZL_MAXMODES 16
+#define ZL_DEFMODE 0
+
+struct _zl;
+typedef int (*t_zlintargfn)(struct _zl *, int);
+typedef void (*t_zlanyargfn)(struct _zl *, t_symbol *, int, t_atom *);
+typedef int (*t_zlnatomsfn)(struct _zl *);
+typedef void (*t_zldoitfn)(struct _zl *, int, t_atom *);
+
+static int zl_nmodes = 0;
+static t_symbol *zl_modesym[ZL_MAXMODES];
+static int zl_modeflags[ZL_MAXMODES];
+static t_zlintargfn zl_intargfn[ZL_MAXMODES];
+static t_zlanyargfn zl_anyargfn[ZL_MAXMODES];
+static t_zlnatomsfn zl_natomsfn[ZL_MAXMODES];
+static t_zldoitfn zl_doitfn[ZL_MAXMODES];
+
+typedef struct _zldata
+{
+ int d_size; /* as allocated */
+ int d_natoms; /* as used */
+ t_atom *d_buf;
+ t_atom d_bufini[ZL_INISIZE];
+} t_zldata;
+
+typedef struct _zl
+{
+ t_object x_ob;
+ struct _zlproxy *x_proxy;
+ int x_entered;
+ int x_locked; /* locking inbuf1 in modes: iter, reg, slice */
+ t_zldata x_inbuf1;
+ t_zldata x_inbuf2;
+ t_zldata x_outbuf;
+ int x_mode;
+ int x_modearg;
+ t_outlet *x_out2;
+} t_zl;
+
+typedef struct _zlproxy
+{
+ t_object p_ob;
+ t_zl *p_master;
+} t_zlproxy;
+
+static t_class *zl_class;
+static t_class *zlproxy_class;
+
+static void zldata_init(t_zldata *d)
+{
+ d->d_size = ZL_INISIZE;
+ d->d_natoms = 0;
+ d->d_buf = d->d_bufini;
+}
+
+static void zldata_free(t_zldata *d)
+{
+ if (d->d_buf != d->d_bufini)
+ freebytes(d->d_buf, d->d_size * sizeof(*d->d_buf));
+}
+
+static void zldata_setfloat(t_zldata *d, t_float f)
+{
+ SETFLOAT(d->d_buf, f);
+ d->d_natoms = 1;
+}
+
+static void zldata_addfloat(t_zldata *d, t_float f)
+{
+ int natoms = d->d_natoms;
+ int nrequested = natoms + 1;
+ if (nrequested > d->d_size)
+ {
+ d->d_buf = grow_withdata(&nrequested, &natoms, &d->d_size,
+ d->d_buf, ZL_INISIZE, d->d_bufini,
+ sizeof(*d->d_buf));
+ if (natoms >= nrequested)
+ natoms = nrequested - 1;
+ }
+ SETFLOAT(d->d_buf + natoms, f);
+ d->d_natoms = natoms + 1;
+}
+
+static void zldata_setsymbol(t_zldata *d, t_symbol *s)
+{
+ SETSYMBOL(d->d_buf, s);
+ d->d_natoms = 1;
+}
+
+static void zldata_addsymbol(t_zldata *d, t_symbol *s)
+{
+ int natoms = d->d_natoms;
+ int nrequested = natoms + 1;
+ if (nrequested > d->d_size)
+ {
+ d->d_buf = grow_withdata(&nrequested, &natoms, &d->d_size,
+ d->d_buf, ZL_INISIZE, d->d_bufini,
+ sizeof(*d->d_buf));
+ if (natoms >= nrequested)
+ natoms = nrequested - 1;
+ }
+ SETSYMBOL(d->d_buf + natoms, s);
+ d->d_natoms = natoms + 1;
+}
+
+static void zldata_setlist(t_zldata *d, int ac, t_atom *av)
+{
+ int nrequested = ac;
+ if (nrequested > d->d_size)
+ d->d_buf = grow_nodata(&nrequested, &d->d_size, d->d_buf,
+ ZL_INISIZE, d->d_bufini, sizeof(*d->d_buf));
+ if (d->d_natoms = nrequested)
+ memcpy(d->d_buf, av, nrequested * sizeof(*d->d_buf));
+}
+
+static void zldata_addlist(t_zldata *d, int ac, t_atom *av)
+{
+ int natoms = d->d_natoms;
+ int nrequested = natoms + ac;
+ if (nrequested > d->d_size)
+ {
+ d->d_buf = grow_withdata(&nrequested, &natoms, &d->d_size,
+ d->d_buf, ZL_INISIZE, d->d_bufini,
+ sizeof(*d->d_buf));
+ if (natoms + ac > nrequested)
+ {
+ natoms = nrequested - ac;
+ if (natoms < 0)
+ natoms = 0, ac = nrequested;
+ }
+ }
+ if (d->d_natoms = natoms + ac)
+ memcpy(d->d_buf + natoms, av, ac * sizeof(*d->d_buf));
+}
+
+static void zldata_set(t_zldata *d, t_symbol *s, int ac, t_atom *av)
+{
+ if (s && s != &s_)
+ {
+ int nrequested = ac + 1;
+ if (nrequested > d->d_size)
+ d->d_buf = grow_nodata(&nrequested, &d->d_size, d->d_buf,
+ ZL_INISIZE, d->d_bufini, sizeof(*d->d_buf));
+ if (d->d_natoms = nrequested)
+ {
+ SETSYMBOL(d->d_buf, s);
+ if (--nrequested)
+ memcpy(d->d_buf + 1, av, nrequested * sizeof(*d->d_buf));
+ }
+ }
+ else zldata_setlist(d, ac, av);
+}
+
+static void zldata_add(t_zldata *d, t_symbol *s, int ac, t_atom *av)
+{
+ if (s && s != &s_)
+ {
+ int natoms = d->d_natoms;
+ int nrequested = natoms + 1 + ac;
+ if (nrequested > d->d_size)
+ {
+ d->d_buf = grow_withdata(&nrequested, &natoms, &d->d_size,
+ d->d_buf, ZL_INISIZE, d->d_bufini,
+ sizeof(*d->d_buf));
+ if (natoms + 1 + ac > nrequested)
+ {
+ natoms = nrequested - 1 - ac;
+ if (natoms < 0)
+ natoms = 0, ac = nrequested - 1;
+ }
+ }
+ if (d->d_natoms = natoms + 1 + ac)
+ {
+ SETSYMBOL(d->d_buf + natoms, s);
+ if (ac > 0)
+ memcpy(d->d_buf + natoms + 1, av, ac * sizeof(*d->d_buf));
+ }
+ }
+ else zldata_addlist(d, ac, av);
+}
+
+/* LATER rethink */
+static void zl_dooutput(t_outlet *o, int ac, t_atom *av)
+{
+ if (ac > 1)
+ {
+ if (av->a_type == A_FLOAT)
+ outlet_list(o, &s_list, ac, av);
+ else if (av->a_type == A_SYMBOL)
+ outlet_anything(o, av->a_w.w_symbol, ac - 1, av + 1);
+ }
+ else if (ac)
+ {
+ if (av->a_type == A_FLOAT)
+ outlet_float(o, av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL)
+#if 1
+ outlet_anything(o, av->a_w.w_symbol, 0, 0); /* CHECKED */
+#else
+ outlet_symbol(o, av->a_w.w_symbol); /* LATER rethink */
+#endif
+ }
+}
+
+static void zl_output(t_zl *x, int ac, t_atom *av)
+{
+ zl_dooutput(((t_object *)x)->ob_outlet, ac, av);
+}
+
+static void zl_output2(t_zl *x, int ac, t_atom *av)
+{
+ zl_dooutput(x->x_out2, ac, av);
+}
+
+static int zl_equal(t_atom *ap1, t_atom *ap2)
+{
+ return (ap1->a_type == ap2->a_type
+ &&
+ ((ap1->a_type == A_FLOAT
+ && ap1->a_w.w_float == ap2->a_w.w_float)
+ ||
+ (ap1->a_type == A_SYMBOL
+ && ap1->a_w.w_symbol == ap2->a_w.w_symbol)));
+}
+
+/* Mode handlers:
+ If zl_<mode>_count's return value is positve, then the main routine
+ uses an output buffer 'buf' (outbuf, or a separately allocated one).
+ If zl_<mode>_count's return value is zero, then the main routine is
+ passed a null 'buf' (see below); if it is negative, then the main
+ routine is not being called.
+ zl_<mode> (main routine) arguments: if 'buf' is null, 'natoms'
+ is always zero -- in modes other than len (no buffer used), group,
+ iter, reg, slice/ecils (inbuf1 used), there should be no output.
+ If 'buf' is not null, then 'natoms' is guaranteed to be positive.
+*/
+
+static int zl_nop_count(t_zl *x)
+{
+ return (0);
+}
+
+static void zl_nop(t_zl *x, int natoms, t_atom *buf)
+{
+ loud_warning((t_pd *)x, "unknown mode");
+}
+
+static int zl_ecils_intarg(t_zl *x, int i)
+{
+ return (i > 0 ? i : 0); /* CHECKED */
+}
+
+static int zl_ecils_count(t_zl *x)
+{
+ return (x->x_entered ? -1 : 0);
+}
+
+static void zl_ecils(t_zl *x, int natoms, t_atom *buf)
+{
+ int cnt1, cnt2 = x->x_modearg;
+ natoms = x->x_inbuf1.d_natoms;
+ buf = x->x_inbuf1.d_buf;
+ if (cnt2 > natoms)
+ cnt2 = natoms, cnt1 = 0; /* CHECKED */
+ else
+ cnt1 = natoms - cnt2;
+ x->x_locked = 1;
+ if (cnt2)
+ zl_output2(x, cnt2, buf + cnt1);
+ if (cnt1)
+ zl_output(x, cnt1, buf);
+}
+
+static int zl_group_intarg(t_zl *x, int i)
+{
+ return (i > 0 ? i : 0); /* CHECKED */
+}
+
+static int zl_group_count(t_zl *x)
+{
+ return (x->x_entered ? -1 : 0);
+}
+
+static void zl_group(t_zl *x, int natoms, t_atom *buf)
+{
+ int cnt = x->x_modearg;
+ if (cnt > 0)
+ {
+ natoms = x->x_inbuf1.d_natoms;
+ buf = x->x_inbuf1.d_buf;
+ if (natoms >= cnt)
+ {
+ t_atom *from;
+ x->x_locked = 1;
+ for (from = buf; natoms >= cnt; natoms -= cnt, from += cnt)
+ zl_output(x, cnt, from);
+ x->x_inbuf1.d_natoms = natoms;
+ while (natoms--) *buf++ = *from++;
+ }
+ }
+ else x->x_inbuf1.d_natoms = 0; /* CHECKED */
+}
+
+static int zl_iter_intarg(t_zl *x, int i)
+{
+ return (i > 0 ? i : 0); /* CHECKED */
+}
+
+static int zl_iter_count(t_zl *x)
+{
+ return (x->x_entered ?
+ (x->x_modearg < x->x_inbuf1.d_natoms ?
+ x->x_modearg : x->x_inbuf1.d_natoms)
+ : 0);
+}
+
+static void zl_iter(t_zl *x, int natoms, t_atom *buf)
+{
+ int nremaining = x->x_inbuf1.d_natoms;
+ t_atom *ptr = x->x_inbuf1.d_buf;
+ if (!buf)
+ {
+ if (natoms = (x->x_modearg < nremaining ?
+ x->x_modearg : nremaining))
+ x->x_locked = 1;
+ else
+ return;
+ }
+ while (nremaining)
+ {
+ if (natoms > nremaining)
+ natoms = nremaining;
+ if (buf)
+ {
+ memcpy(buf, ptr, natoms * sizeof(*buf));
+ zl_output(x, natoms, buf);
+ }
+ else zl_output(x, natoms, ptr);
+ nremaining -= natoms;
+ ptr += natoms;
+ }
+}
+
+static int zl_join_count(t_zl *x)
+{
+ return (x->x_inbuf1.d_natoms + x->x_inbuf2.d_natoms);
+}
+
+static void zl_join(t_zl *x, int natoms, t_atom *buf)
+{
+ if (buf)
+ {
+ int ac1 = x->x_inbuf1.d_natoms, ac2 = x->x_inbuf2.d_natoms;
+ if (ac1)
+ memcpy(buf, x->x_inbuf1.d_buf, ac1 * sizeof(*buf));
+ if (ac2)
+ memcpy(buf + ac1, x->x_inbuf2.d_buf, ac2 * sizeof(*buf));
+ zl_output(x, natoms, buf);
+ }
+}
+
+static int zl_len_count(t_zl *x)
+{
+ return (0);
+}
+
+static void zl_len(t_zl *x, int natoms, t_atom *buf)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_inbuf1.d_natoms);
+}
+
+static int zl_nth_intarg(t_zl *x, int i)
+{
+ return (i > 0 ? i : 0); /* CHECKED */
+}
+
+static void zl_nth_anyarg(t_zl *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (!s && ac && av->a_type == A_FLOAT)
+ zldata_setlist(&x->x_inbuf2, ac - 1, av + 1);
+}
+
+static int zl_nth_count(t_zl *x)
+{
+ int ac1 = x->x_inbuf1.d_natoms;
+ if (ac1)
+ {
+ if (x->x_modearg > 0)
+ return (ac1 - 1 + x->x_inbuf2.d_natoms);
+ else
+ return (x->x_entered ? ac1 : 0);
+ }
+ else return (-1);
+}
+
+static void zl_nth(t_zl *x, int natoms, t_atom *buf)
+{
+ int ac1 = x->x_inbuf1.d_natoms,
+ ndx = x->x_modearg - 1; /* CHECKED one-based */
+ if (ac1 && ndx < ac1) /* CHECKED */
+ {
+ t_atom *av1 = x->x_inbuf1.d_buf;
+ if (ndx < 0)
+ {
+ if (buf) memcpy(buf, av1, ac1 * sizeof(*buf));
+ else
+ {
+ buf = av1;
+ x->x_locked = 1;
+ }
+ zl_output2(x, ac1, buf);
+ }
+ else
+ {
+ t_atom at = av1[ndx];
+ if (buf)
+ {
+ int ac2 = x->x_inbuf2.d_natoms, ntail = ac1 - ndx + 1;
+ t_atom *ptr = buf;
+ if (ndx)
+ {
+ memcpy(ptr, av1, ndx * sizeof(*buf));
+ ptr += ndx;
+ }
+ if (ac2)
+ {
+ memcpy(ptr, x->x_inbuf2.d_buf, ac2 * sizeof(*buf));
+ ptr += ac2;
+ }
+ if (ntail)
+ memcpy(ptr, av1 + ndx + 1, ntail * sizeof(*buf));
+ zl_output2(x, natoms, buf);
+ }
+ zl_output(x, 1, &at);
+ }
+ }
+}
+
+static void zl_reg_anyarg(t_zl *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (!x->x_locked)
+ zldata_set(&x->x_inbuf1, s, ac, av);
+}
+
+static int zl_reg_count(t_zl *x)
+{
+ return (x->x_entered ? x->x_inbuf1.d_natoms : 0);
+}
+
+static void zl_reg(t_zl *x, int natoms, t_atom *buf)
+{
+ if (buf) memcpy(buf, x->x_inbuf1.d_buf, natoms * sizeof(*buf));
+ else
+ {
+ natoms = x->x_inbuf1.d_natoms;
+ buf = x->x_inbuf1.d_buf;
+ x->x_locked = 1;
+ }
+ if (natoms)
+ zl_output(x, natoms, buf);
+}
+
+static int zl_rev_count(t_zl *x)
+{
+ return (x->x_inbuf1.d_natoms);
+}
+
+static void zl_rev(t_zl *x, int natoms, t_atom *buf)
+{
+ if (buf)
+ {
+ t_atom *from = x->x_inbuf1.d_buf, *to = buf + natoms;
+ while (to-- > buf)
+ *to = *from++;
+ zl_output(x, natoms, buf);
+ }
+}
+
+static int zl_rot_intarg(t_zl *x, int i)
+{
+ return (i); /* CHECKED anything goes (modulo) */
+}
+
+static int zl_rot_count(t_zl *x)
+{
+ return (x->x_inbuf1.d_natoms);
+}
+
+static void zl_rot(t_zl *x, int natoms, t_atom *buf)
+{
+ if (buf)
+ {
+ int cnt1 = x->x_modearg, cnt2;
+ if (cnt1)
+ {
+ if (cnt1 > 0)
+ {
+ cnt1 %= natoms;
+ cnt2 = natoms - cnt1;
+ }
+ else
+ {
+ cnt2 = -cnt1 % natoms;
+ cnt1 = natoms - cnt2;
+ }
+ /* CHECKED right rotation for positive args */
+ memcpy(buf, x->x_inbuf1.d_buf + cnt2, cnt1 * sizeof(*buf));
+ memcpy(buf + cnt1, x->x_inbuf1.d_buf, cnt2 * sizeof(*buf));
+ }
+ else memcpy(buf, x->x_inbuf1.d_buf, natoms * sizeof(*buf));
+ zl_output(x, natoms, buf);
+ }
+}
+
+/* LATER rethink */
+static int zl_sect_count(t_zl *x)
+{
+ int result = 0;
+ int ac1 = x->x_inbuf1.d_natoms, ac2 = x->x_inbuf2.d_natoms, i1;
+ t_atom *av1 = x->x_inbuf1.d_buf, *av2 = x->x_inbuf2.d_buf, *ap1;
+ for (i1 = 0, ap1 = av1; i1 < ac1; i1++, ap1++)
+ {
+ int i2;
+ t_atom *testp;
+ for (i2 = 0, testp = av1; i2 < i1; i2++, testp++)
+ if (zl_equal(ap1, testp))
+ goto skip;
+ for (i2 = 0, testp = av2; i2 < ac2; i2++, testp++)
+ {
+ if (zl_equal(ap1, testp))
+ {
+ result++;
+ break;
+ }
+ }
+ skip:;
+ }
+ return (result);
+}
+
+/* CHECKED in-buffer duplicates are skipped */
+static void zl_sect(t_zl *x, int natoms, t_atom *buf)
+{
+ if (buf)
+ {
+ int ac1 = x->x_inbuf1.d_natoms, ac2 = x->x_inbuf2.d_natoms, i1;
+ t_atom *ap1 = x->x_inbuf1.d_buf, *av2 = x->x_inbuf2.d_buf, *to = buf;
+ for (i1 = 0; i1 < ac1; i1++, ap1++)
+ {
+ int i2;
+ t_atom *testp;
+ for (testp = buf; testp < to; testp++)
+ if (zl_equal(ap1, testp))
+ goto skip;
+ for (i2 = 0, testp = av2; i2 < ac2; i2++, testp++)
+ {
+ if (zl_equal(ap1, testp))
+ {
+ *to++ = *ap1;
+ break;
+ }
+ }
+ skip:;
+ }
+ zl_output(x, natoms, buf);
+ }
+}
+
+static int zl_slice_intarg(t_zl *x, int i)
+{
+ return (i > 0 ? i : 0); /* CHECKED */
+}
+
+static int zl_slice_count(t_zl *x)
+{
+ return (x->x_entered ? -1 : 0);
+}
+
+static void zl_slice(t_zl *x, int natoms, t_atom *buf)
+{
+ int cnt1 = x->x_modearg, cnt2;
+ natoms = x->x_inbuf1.d_natoms;
+ buf = x->x_inbuf1.d_buf;
+ if (cnt1 > natoms)
+ cnt1 = natoms, cnt2 = 0; /* CHECKED */
+ else
+ cnt2 = natoms - cnt1;
+ x->x_locked = 1;
+ if (cnt2)
+ zl_output2(x, cnt2, buf + cnt1);
+ if (cnt1)
+ zl_output(x, cnt1, buf);
+}
+
+static int zl_sub_count(t_zl *x)
+{
+ return (0);
+}
+
+static void zl_sub(t_zl *x, int natoms, t_atom *buf)
+{
+ int natoms2 = x->x_inbuf2.d_natoms;
+ if (natoms2)
+ {
+ int ndx1, natoms1 = x->x_inbuf1.d_natoms;
+ t_atom *av1 = x->x_inbuf1.d_buf, *av2 = x->x_inbuf2.d_buf;
+ for (ndx1 = 0; ndx1 < natoms1; ndx1++, av1++)
+ {
+ int ndx2;
+ t_atom *ap1 = av1, *ap2 = av2;
+ for (ndx2 = 0; ndx2 < natoms2; ndx2++, ap1++, ap2++)
+ if (!zl_equal(ap1, ap2))
+ break;
+ if (ndx2 == natoms2)
+ /* CHECKED output position is zero-based */
+ outlet_float(((t_object *)x)->ob_outlet, ndx1);
+ }
+ }
+}
+
+/* LATER rethink */
+static int zl_union_count(t_zl *x)
+{
+ int result, ac1 = x->x_inbuf1.d_natoms, ac2 = x->x_inbuf2.d_natoms, i2;
+ t_atom *av1 = x->x_inbuf1.d_buf, *ap2 = x->x_inbuf2.d_buf;
+ result = ac1 + ac2;
+ for (i2 = 0; i2 < ac2; i2++, ap2++)
+ {
+ int i1;
+ t_atom *ap1;
+ for (i1 = 0, ap1 = av1; i1 < ac1; i1++, ap1++)
+ {
+ if (zl_equal(ap1, ap2))
+ {
+ result--;
+ break;
+ }
+ }
+ }
+ return (result);
+}
+
+/* CHECKED in-buffer duplicates not skipped */
+static void zl_union(t_zl *x, int natoms, t_atom *buf)
+{
+ if (buf)
+ {
+ int ac1 = x->x_inbuf1.d_natoms, ac2 = x->x_inbuf2.d_natoms, i2;
+ t_atom *av1 = x->x_inbuf1.d_buf, *ap2 = x->x_inbuf2.d_buf;
+ if (ac1)
+ {
+ t_atom *to = buf + ac1;
+ memcpy(buf, av1, ac1 * sizeof(*buf));
+ for (i2 = 0; i2 < ac2; i2++, ap2++)
+ {
+ int i1;
+ t_atom *ap1;
+ for (i1 = 0, ap1 = av1; i1 < ac1; i1++, ap1++)
+ if (zl_equal(ap1, ap2))
+ break;
+ if (i1 == ac1)
+ *to++ = *ap2;
+ }
+ }
+ else memcpy(buf, ap2, ac2 * sizeof(*buf));
+ zl_output(x, natoms, buf);
+ }
+}
+
+static void zl_doit(t_zl *x)
+{
+ int reentered = x->x_entered;
+ int prealloc = !reentered;
+ int natoms = (*zl_natomsfn[x->x_mode])(x);
+ if (natoms < 0)
+ return;
+ x->x_entered = 1;
+ if (natoms)
+ {
+ t_zldata *d = &x->x_outbuf;
+ t_atom *buf;
+ if (prealloc && natoms > d->d_size)
+ {
+ if (natoms > ZL_MAXSIZE)
+ prealloc = 0;
+ else
+ {
+ int nrequested = natoms;
+ d->d_buf = grow_nodata(&nrequested, &d->d_size, d->d_buf,
+ ZL_INISIZE, d->d_bufini,
+ sizeof(*d->d_buf));
+ if (nrequested != natoms)
+ prealloc = 0;
+ }
+ }
+ /* LATER consider using the stack if !prealloc && natoms <= MAXSTACK */
+ if (buf = (prealloc ? d->d_buf : getbytes(natoms * sizeof(*buf))))
+ {
+ (*zl_doitfn[x->x_mode])(x, natoms, buf);
+ if (buf != d->d_buf)
+ freebytes(buf, natoms * sizeof(*buf));
+ }
+ }
+ else (*zl_doitfn[x->x_mode])(x, 0, 0);
+ if (!reentered)
+ x->x_entered = x->x_locked = 0;
+}
+
+static void zl_bang(t_zl *x)
+{
+ /* CHECKED bang is a nop in len mode, LATER consider emulating this */
+ /* CHECKED 'mode len, bang'->[zl]->[print] crashes max 4.0.7... */
+ zl_doit(x);
+}
+
+static void zl_float(t_zl *x, t_float f)
+{
+ if (!x->x_locked)
+ {
+ if (zl_modeflags[x->x_mode])
+ zldata_addfloat(&x->x_inbuf1, f);
+ else
+ zldata_setfloat(&x->x_inbuf1, f);
+ }
+ zl_doit(x);
+}
+
+static void zl_symbol(t_zl *x, t_symbol *s)
+{
+ if (!x->x_locked)
+ {
+ if (zl_modeflags[x->x_mode])
+ zldata_addsymbol(&x->x_inbuf1, s);
+ else
+ zldata_setsymbol(&x->x_inbuf1, s);
+ }
+ zl_doit(x);
+}
+
+/* LATER gpointer */
+
+static void zl_list(t_zl *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (!x->x_locked)
+ {
+ if (zl_modeflags[x->x_mode])
+ zldata_addlist(&x->x_inbuf1, ac, av);
+ else
+ zldata_setlist(&x->x_inbuf1, ac, av);
+ }
+ zl_doit(x);
+}
+
+static void zl_anything(t_zl *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (!x->x_locked)
+ {
+ if (zl_modeflags[x->x_mode])
+ zldata_add(&x->x_inbuf1, s, ac, av);
+ else
+ zldata_set(&x->x_inbuf1, s, ac, av);
+ }
+ zl_doit(x);
+}
+
+static int zl_modeargfn(t_zl *x)
+{
+ return (zl_intargfn[x->x_mode] || zl_anyargfn[x->x_mode]);
+}
+
+static void zl_setmodearg(t_zl *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (zl_intargfn[x->x_mode])
+ {
+ int i = (!s && ac && av->a_type == A_FLOAT ?
+ (int)av->a_w.w_float : /* CHECKED silent truncation */
+ 0); /* CHECKED current x->x_modearg not kept */
+ x->x_modearg = (*zl_intargfn[x->x_mode])(x, i);
+ }
+ if (zl_anyargfn[x->x_mode])
+ (*zl_anyargfn[x->x_mode])(x, s, ac, av);
+}
+
+static void zl_mode(t_zl *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac && av->a_type == A_SYMBOL)
+ {
+ t_symbol *modesym = av->a_w.w_symbol;
+ int i;
+ for (i = 0; i < zl_nmodes; i++)
+ if (modesym == zl_modesym[i])
+ break;
+ /* LATER consider making this compatible:
+ CHECKED setting unknown mode makes a zl nop */
+ if (i && i < zl_nmodes)
+ {
+ x->x_mode = i;
+ zl_setmodearg(x, 0, ac - 1, av + 1);
+ }
+ }
+}
+
+static void zlproxy_bang(t_zlproxy *d)
+{
+ /* CHECKED a nop */
+}
+
+static void zlproxy_float(t_zlproxy *p, t_float f)
+{
+ t_zl *x = p->p_master;
+ if (zl_modeargfn(x))
+ {
+ t_atom at;
+ SETFLOAT(&at, f);
+ zl_setmodearg(x, 0, 1, &at);
+ }
+ else /* CHECKED inbuf2 filled only when used */
+ zldata_setfloat(&x->x_inbuf2, f);
+}
+
+static void zlproxy_symbol(t_zlproxy *p, t_symbol *s)
+{
+ t_zl *x = p->p_master;
+ if (zl_modeargfn(x))
+ {
+ t_atom at;
+ SETSYMBOL(&at, s);
+ zl_setmodearg(x, 0, 1, &at);
+ }
+ else /* CHECKED inbuf2 filled only when used */
+ zldata_setsymbol(&x->x_inbuf2, s);
+}
+
+/* LATER gpointer */
+
+static void zlproxy_list(t_zlproxy *p, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ t_zl *x = p->p_master;
+ if (zl_modeargfn(x))
+ zl_setmodearg(x, 0, ac, av);
+ else /* CHECKED inbuf2 filled only when used */
+ zldata_setlist(&x->x_inbuf2, ac, av);
+ }
+}
+
+static void zlproxy_anything(t_zlproxy *p, t_symbol *s, int ac, t_atom *av)
+{
+ t_zl *x = p->p_master;
+ if (zl_modeargfn(x))
+ zl_setmodearg(x, s, ac, av);
+ else /* CHECKED inbuf2 filled only when used */
+ zldata_set(&x->x_inbuf2, s, ac, av);
+}
+
+#ifdef ZL_DEBUG
+static void zl_debug(t_zl *x, t_floatarg f)
+{
+ startpost("mode %s", zl_modesym[x->x_mode]->s_name);
+ if (zl_intargfn[x->x_mode])
+ post(" %d", x->x_modearg);
+ else
+ endpost();
+ if ((int)f)
+ {
+ startpost("first:");
+ postatom(x->x_inbuf1.d_natoms, x->x_inbuf1.d_buf);
+ endpost();
+ startpost("second:");
+ postatom(x->x_inbuf2.d_natoms, x->x_inbuf2.d_buf);
+ endpost();
+ }
+}
+#endif
+
+static void zl_free(t_zl *x)
+{
+ zldata_free(&x->x_inbuf1);
+ zldata_free(&x->x_inbuf2);
+ zldata_free(&x->x_outbuf);
+ if (x->x_proxy) pd_free((t_pd *)x->x_proxy);
+}
+
+static void *zl_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_zl *x = (t_zl *)pd_new(zl_class);
+ t_zlproxy *y = (t_zlproxy *)pd_new(zlproxy_class);
+ x->x_proxy = y;
+ y->p_master = x;
+ x->x_entered = 0;
+ x->x_locked = 0;
+ zldata_init(&x->x_inbuf1);
+ zldata_init(&x->x_inbuf2);
+ zldata_init(&x->x_outbuf);
+ x->x_mode = ZL_DEFMODE;
+ zl_mode(x, s, ac, av);
+ inlet_new((t_object *)x, (t_pd *)y, 0, 0);
+ outlet_new((t_object *)x, &s_anything);
+ x->x_out2 = outlet_new((t_object *)x, &s_anything);
+ return (x);
+}
+
+static void zl_setupmode(char *id, int flags,
+ t_zlintargfn ifn, t_zlanyargfn afn,
+ t_zlnatomsfn nfn, t_zldoitfn dfn)
+{
+ if (zl_nmodes < ZL_MAXMODES)
+ {
+ zl_modesym[zl_nmodes] = gensym(id);
+ zl_modeflags[zl_nmodes] = flags;
+ zl_intargfn[zl_nmodes] = ifn;
+ zl_anyargfn[zl_nmodes] = afn;
+ zl_natomsfn[zl_nmodes] = nfn;
+ zl_doitfn[zl_nmodes] = dfn;
+ zl_nmodes++;
+ }
+ else bug("zl_setupmode");
+}
+
+static void zl_setupallmodes(void)
+{
+ zl_setupmode("unknown", 0, 0, 0, zl_nop_count, zl_nop);
+ zl_setupmode("ecils", 0, zl_ecils_intarg, 0, zl_ecils_count, zl_ecils);
+ zl_setupmode("group", 1, zl_group_intarg, 0, zl_group_count, zl_group);
+ zl_setupmode("iter", 0, zl_iter_intarg, 0, zl_iter_count, zl_iter);
+ zl_setupmode("join", 0, 0, 0, zl_join_count, zl_join);
+ zl_setupmode("len", 0, 0, 0, zl_len_count, zl_len);
+ zl_setupmode("nth", 0, zl_nth_intarg, zl_nth_anyarg, zl_nth_count, zl_nth);
+ zl_setupmode("reg", 0, 0, zl_reg_anyarg, zl_reg_count, zl_reg);
+ zl_setupmode("rev", 0, 0, 0, zl_rev_count, zl_rev);
+ zl_setupmode("rot", /* CHECKED (refman error) */
+ 0, zl_rot_intarg, 0, zl_rot_count, zl_rot);
+ zl_setupmode("sect", 0, 0, 0, zl_sect_count, zl_sect);
+ zl_setupmode("slice", 0, zl_slice_intarg, 0, zl_slice_count, zl_slice);
+ zl_setupmode("sub", 0, 0, 0, zl_sub_count, zl_sub);
+ zl_setupmode("union", 0, 0, 0, zl_union_count, zl_union);
+}
+
+void zl_setup(void)
+{
+ zl_class = class_new(gensym("zl"),
+ (t_newmethod)zl_new,
+ (t_method)zl_free,
+ sizeof(t_zl), 0,
+ A_GIMME, 0);
+ class_addbang(zl_class, zl_bang);
+ class_addfloat(zl_class, zl_float);
+ class_addsymbol(zl_class, zl_symbol);
+ class_addlist(zl_class, zl_list);
+ class_addanything(zl_class, zl_anything);
+ class_addmethod(zl_class, (t_method)zl_mode,
+ gensym("mode"), A_GIMME, 0);
+#ifdef ZL_DEBUG
+ class_addmethod(zl_class, (t_method)zl_debug,
+ gensym("debug"), A_DEFFLOAT, 0);
+#endif
+ zlproxy_class = class_new(gensym("_zlproxy"), 0, 0,
+ sizeof(t_zlproxy),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addbang(zlproxy_class, zlproxy_bang);
+ class_addfloat(zlproxy_class, zlproxy_float);
+ class_addsymbol(zlproxy_class, zlproxy_symbol);
+ class_addlist(zlproxy_class, zlproxy_list);
+ class_addanything(zlproxy_class, zlproxy_anything);
+ zl_setupallmodes();
+}
diff --git a/cyclone/shadow/Makefile b/cyclone/shadow/Makefile
new file mode 100644
index 0000000..b700e5e
--- /dev/null
+++ b/cyclone/shadow/Makefile
@@ -0,0 +1,7 @@
+ROOT_DIR = ../..
+redefault: default $(ROOT_DIR)/bin/cyclist
+include $(ROOT_DIR)/Makefile.common
+
+$(ROOT_DIR)/bin/cyclist: $(SHARED_DIR)/common/binport.c
+ $(CC) -DBINPORT_STANDALONE -o $@ $<
+
diff --git a/cyclone/shadow/Makefile.objects b/cyclone/shadow/Makefile.objects
new file mode 100644
index 0000000..f77675c
--- /dev/null
+++ b/cyclone/shadow/Makefile.objects
@@ -0,0 +1,9 @@
+SHARED_OBJECTS = \
+common/loud.o \
+common/grow.o \
+common/binport.o \
+common/port.o \
+hammer/file.o \
+sickle/sic.o \
+unstable/fragile.o \
+unstable/loader.o
diff --git a/cyclone/shadow/Makefile.sources b/cyclone/shadow/Makefile.sources
new file mode 100644
index 0000000..8ba4681
--- /dev/null
+++ b/cyclone/shadow/Makefile.sources
@@ -0,0 +1,6 @@
+CX_SOURCES = \
+cyclone.c
+
+OTHER_SOURCES = \
+nettles.c \
+dummies.c
diff --git a/cyclone/shadow/cyclone.c b/cyclone/shadow/cyclone.c
new file mode 100644
index 0000000..047d39d
--- /dev/null
+++ b/cyclone/shadow/cyclone.c
@@ -0,0 +1,159 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* Never use forked calls in shadow code... */
+
+#include <stdio.h>
+#include "m_pd.h"
+#include "common/loud.h"
+#include "common/port.h"
+#include "hammer/file.h"
+#include "unstable/fragile.h"
+#include "unstable/loader.h"
+#include "shadow.h"
+#include "../build_counter"
+
+typedef struct _cyclone
+{
+ t_object x_ob;
+ t_symbol *x_dir;
+ t_hammerfile *x_filehandle;
+} t_cyclone;
+
+static t_class *cyclone_class;
+static int cyclone_hammerndx;
+static int cyclone_sicklendx;
+static int cyclone_nettlesndx;
+static int cyclone_dummiesndx;
+static int cyclone_lastndx;
+
+static void cyclone_readhook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ import_max(fn->s_name, "");
+}
+
+static void cyclone_import(t_cyclone *x, t_symbol *fn, t_symbol *dir)
+{
+ if (fn && fn != &s_)
+ {
+ if (!dir || dir == &s_) dir = x->x_dir;
+ import_max(fn->s_name, (dir && dir != &s_) ? dir->s_name : "");
+ }
+ else
+ hammerpanel_open(x->x_filehandle);
+}
+
+static void cyclone_click(t_cyclone *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ cyclone_import(x, 0, 0);
+}
+
+static void cyclone_bang(t_cyclone *x)
+{
+ int i;
+ fragile_class_printnames("hammer classes are: ",
+ cyclone_hammerndx, cyclone_sicklendx - 1);
+ fragile_class_printnames("sickle classes are: ",
+ cyclone_sicklendx, cyclone_nettlesndx - 1);
+ fragile_class_printnames("nettles are: ",
+ cyclone_nettlesndx, cyclone_dummiesndx - 1);
+ if (i = dummy_nreplacements())
+ post("send 'reps' message to see the list of %d \
+replacement abstractions", i);
+ else
+ post("no replacement abstractions");
+ post("send 'dummies' message to see the list of %d dummy classes",
+ /* cyclone_lastndx points to the "_dummy" sentinel class */
+ cyclone_lastndx - cyclone_dummiesndx);
+}
+
+static void cyclone_reps(t_cyclone *x)
+{
+ if (dummy_nreplacements())
+ dummy_printreplacements("replacement abstractions are: ");
+ else
+ post("no replacement abstractions");
+}
+
+static void cyclone_dummies(t_cyclone *x)
+{
+ fragile_class_printnames("dummies are: ",
+ cyclone_dummiesndx, cyclone_lastndx);
+}
+
+static void cyclone_free(t_cyclone *x)
+{
+ hammerfile_free(x->x_filehandle);
+}
+
+static void *cyclone_new(t_symbol *s)
+{
+ t_cyclone *x = (t_cyclone *)pd_new(cyclone_class);
+ x->x_filehandle = hammerfile_new((t_pd *)x, 0, cyclone_readhook, 0, 0);
+ x->x_dir = (s && s != &s_ ? s : canvas_getdir(x->x_filehandle->f_canvas));
+ return (x);
+}
+
+void cyclone_setup(void)
+{
+ int hresult, sresult;
+ hresult = sresult = LOADER_OK;
+ if (canvas_getcurrent())
+ {
+ /* Loading the library by object creation is banned, because of a danger
+ of having some of the classes already loaded. LATER rethink. */
+ loud_error(0, "apparently an attempt to create a 'cyclone' object");
+ loud_errand(0, "without having cyclone library preloaded");
+ return;
+ }
+ post("this is cyclone %s, %s %s build",
+ CYCLONE_VERSION, loud_ordinal(CYCLONE_BUILD), CYCLONE_RELEASE);
+ cyclone_class = class_new(gensym("cyclone"),
+ (t_newmethod)cyclone_new,
+ (t_method)cyclone_free,
+ sizeof(t_cyclone), 0, A_DEFSYM, 0);
+ class_addbang(cyclone_class, cyclone_bang);
+ class_addmethod(cyclone_class, (t_method)cyclone_reps,
+ gensym("reps"), 0);
+ class_addmethod(cyclone_class, (t_method)cyclone_dummies,
+ gensym("dummies"), 0);
+ class_addmethod(cyclone_class, (t_method)cyclone_import,
+ gensym("import"), A_DEFSYM, A_DEFSYM, 0);
+ class_addmethod(cyclone_class, (t_method)cyclone_click,
+ gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ hammerfile_setup(cyclone_class, 0);
+
+ cyclone_hammerndx = fragile_class_count();
+ if (zgetfn(&pd_objectmaker, gensym("hammer")))
+ loud_warning(0, "hammer is already loaded");
+ else
+ hresult = unstable_load_lib("", "hammer");
+
+ cyclone_sicklendx = fragile_class_count();
+ if (zgetfn(&pd_objectmaker, gensym("sickle")))
+ loud_warning(0, "sickle is already loaded");
+ else
+ sresult = unstable_load_lib("", "sickle");
+
+ cyclone_nettlesndx = fragile_class_count();
+ allnettles_setup();
+
+ cyclone_dummiesndx = fragile_class_count();
+ alldummies_setup();
+ cyclone_lastndx = fragile_class_count() - 1;
+
+ if (hresult == LOADER_NOFILE)
+ loud_error(0, "hammer library is missing");
+ else if (sresult == LOADER_NOFILE)
+ loud_error(0, "sickle library is missing");
+ else if (!zgetfn(&pd_objectmaker, gensym("hammer")) ||
+ !zgetfn(&pd_objectmaker, gensym("sickle")))
+ {
+ loud_error(0, "version mismatch");
+ loud_errand(0,
+ "use a more recent Pd release (or recompile the cyclone).");
+ }
+}
diff --git a/cyclone/shadow/dummies.c b/cyclone/shadow/dummies.c
new file mode 100644
index 0000000..272fd45
--- /dev/null
+++ b/cyclone/shadow/dummies.c
@@ -0,0 +1,664 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#ifdef UNIX
+#include <unistd.h>
+#endif
+#ifdef NT
+#include <io.h>
+#endif
+#include "m_pd.h"
+#include "common/loud.h"
+#include "shadow.h"
+
+static int dummy_nclasses = 0;
+static t_class **dummy_classes;
+static int dummy_nreps = 0;
+
+typedef struct _dummy_slot
+{
+ char *s_name;
+ int s_nins;
+ int s_nouts;
+ int s_warned;
+ t_newmethod s_method; /* a specialized constructor */
+} t_dummy_slot;
+
+static t_object *dummy_newobject(t_symbol *s, t_dummy_slot **slotp);
+static void dummy_io(t_object *x, int nins, int nouts);
+
+static void *dummy_2dwave_tilde_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_dummy_slot *sl;
+ t_object *x = dummy_newobject(s, &sl);
+ int nouts = 0;
+ if (ac && av->a_type == A_SYMBOL)
+ {
+ if (ac > 3 && av[3].a_type == A_FLOAT)
+ nouts = (int)av[3].a_w.w_float;
+ }
+ else loud_classarg(*(t_pd *)x);
+ if (nouts < 1)
+ nouts = 1;
+ dummy_io(x, sl->s_nins, nouts);
+ return (x);
+}
+
+static void *dummy_adoutput_tilde_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_dummy_slot *sl;
+ t_object *x = dummy_newobject(s, &sl);
+ int nouts = 0;
+ while (ac--)
+ {
+ if (av++->a_type == A_FLOAT) nouts++;
+ else
+ {
+ loud_classarg(*(t_pd *)x);
+ break;
+ }
+ }
+ if (nouts < 1)
+ nouts = 2;
+ dummy_io(x, sl->s_nins, nouts);
+ return (x);
+}
+
+static void *dummy_fffb_tilde_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_dummy_slot *sl;
+ t_object *x = dummy_newobject(s, &sl);
+ int nouts = 0;
+ if (ac && av->a_type == A_FLOAT)
+ nouts = (int)av->a_w.w_float;
+ if (nouts < 1)
+ {
+ loud_classarg(*(t_pd *)x);
+ nouts = 1;
+ }
+ dummy_io(x, sl->s_nins, nouts);
+ return (x);
+}
+
+static void *dummy_gate_tilde_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_dummy_slot *sl;
+ t_object *x = dummy_newobject(s, &sl);
+ int nouts = 0;
+ if (ac && av->a_type == A_FLOAT)
+ nouts = (int)av->a_w.w_float;
+ if (nouts < 1)
+ nouts = 1;
+ dummy_io(x, sl->s_nins, nouts);
+ return (x);
+}
+
+static void *dummy_groove_tilde_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_dummy_slot *sl;
+ t_object *x = dummy_newobject(s, &sl);
+ int nouts = 0;
+ if (ac && av->a_type == A_SYMBOL)
+ {
+ if (ac > 1 && av[1].a_type == A_FLOAT)
+ nouts = (int)av[1].a_w.w_float;
+ }
+ else loud_classarg(*(t_pd *)x);
+ if (nouts < 1)
+ nouts = 1;
+ dummy_io(x, sl->s_nins, nouts + 1);
+ return (x);
+}
+
+/* FIXME */
+static void *dummy_if_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_object *x = dummy_newobject(s, 0);
+ int nins = 0;
+ int nouts = 1;
+ t_symbol *ps_out2 = gensym("out2");
+ while (ac--)
+ {
+ if (av->a_type == A_SYMBOL)
+ {
+ if (av->a_w.w_symbol == ps_out2)
+ nouts = 2;
+ else
+ {
+ char *name = av->a_w.w_symbol->s_name;
+ if (strlen(name) >= 3 && *name == '$')
+ {
+ char c = name[2];
+ if (c > '1' && c <= '9' && c > '0' + nins)
+ nins = c - '0';
+ }
+ }
+ }
+ av++;
+ }
+ dummy_io(x, nins, nouts);
+ return (x);
+}
+
+static void *dummy_matrix_tilde_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_dummy_slot *sl;
+ t_object *x = dummy_newobject(s, &sl);
+ int nins = 0, nouts = 0;
+ if (ac && av->a_type == A_FLOAT)
+ {
+ nins = (int)av->a_w.w_float;
+ if (ac > 1 && av[1].a_type == A_FLOAT)
+ nouts = (int)av[1].a_w.w_float;
+ }
+ if (nins < 1 || nouts < 1)
+ {
+ loud_classarg(*(t_pd *)x);
+ if (nins < 1) nins = 1;
+ if (nouts < 1) nouts = 1;
+ }
+ dummy_io(x, nins, nouts + 1); /* CHECKME */
+ return (x);
+}
+
+static void *dummy_mtr_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_dummy_slot *sl;
+ t_object *x = dummy_newobject(s, &sl);
+ int nios = 0;
+ if (ac && av->a_type == A_FLOAT)
+ nios = (int)av->a_w.w_float;
+ if (nios < 1)
+ nios = 1;
+ dummy_io(x, nios + 1, nios + 1);
+ return (x);
+}
+
+/* CHECKME */
+static void *dummy_pong_tilde_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_dummy_slot *sl;
+ t_object *x = dummy_newobject(s, &sl);
+ int nins = 0;
+ if (ac)
+ {
+ if (av->a_type == A_FLOAT)
+ {
+ ac--; av++;
+ if (ac)
+ {
+ if (av->a_type == A_FLOAT) nins = 3;
+ }
+ else nins = 2;
+ }
+ }
+ else nins = 2;
+ if (nins < 1)
+ {
+ loud_classarg(*(t_pd *)x);
+ nins = 2;
+ }
+ dummy_io(x, nins, sl->s_nouts);
+ return (x);
+}
+
+static void *dummy_rewire_tilde_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_dummy_slot *sl;
+ t_object *x = dummy_newobject(s, &sl);
+ int nouts = 0;
+ if (ac && av->a_type == A_FLOAT)
+ nouts = (int)av->a_w.w_float;
+ else if (ac > 1 && av[1].a_type == A_FLOAT)
+ nouts = (int)av[1].a_w.w_float;
+ if (nouts < 1)
+ nouts = 1; /* CHECKME */
+ dummy_io(x, sl->s_nins, nouts + 4);
+ return (x);
+}
+
+static void *dummy_selector_tilde_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_dummy_slot *sl;
+ t_object *x = dummy_newobject(s, &sl);
+ int nins = 0;
+ if (ac && av->a_type == A_FLOAT)
+ nins = (int)av->a_w.w_float;
+ if (nins < 1)
+ nins = 1;
+ dummy_io(x, nins + 1, sl->s_nouts);
+ return (x);
+}
+
+static void *dummy_sfplay_tilde_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_dummy_slot *sl;
+ t_object *x = dummy_newobject(s, &sl);
+ int nouts = 0;
+ if (ac)
+ {
+ if (av->a_type == A_FLOAT)
+ nouts = (int)av->a_w.w_float;
+ else if (ac > 1 && av[1].a_type == A_FLOAT)
+ nouts = (int)av[1].a_w.w_float;
+ }
+ if (nouts < 1)
+ nouts = 1;
+ dummy_io(x, sl->s_nins, nouts + 1);
+ return (x);
+}
+
+static void *dummy_sfrecord_tilde_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_dummy_slot *sl;
+ t_object *x = dummy_newobject(s, &sl);
+ int nins = 0;
+ if (ac && av->a_type == A_FLOAT)
+ nins = (int)av->a_w.w_float;
+ if (nins < 1)
+ nins = 1;
+ dummy_io(x, nins, sl->s_nouts);
+ return (x);
+}
+
+static void *dummy_stutter_tilde_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_dummy_slot *sl;
+ t_object *x = dummy_newobject(s, &sl);
+ int nios = 0;
+ if (ac > 4 && av[4].a_type == A_FLOAT)
+ nios = (int)av[4].a_w.w_float;
+ if (nios < 1)
+ nios = 1;
+ dummy_io(x, nios + 2, nios);
+ return (x);
+}
+
+static void *dummy_sxformat_new(t_symbol *s, int ac, t_atom *av)
+{
+ return (dummy_if_new(s, ac, av)); /* FIXME */
+}
+
+static void *dummy_tapout_tilde_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_dummy_slot *sl;
+ t_object *x = dummy_newobject(s, &sl);
+ int warned = 0, nios = 0;
+ while (ac--)
+ if (av++->a_type == A_FLOAT)
+ nios++;
+ else if (!warned++)
+ loud_classarg(*(t_pd *)x);
+ if (nios < 1)
+ nios = 1;
+ dummy_io(x, nios, nios);
+ return (x);
+}
+
+/* CHECKME */
+static void *dummy_tiCmd_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_dummy_slot *sl;
+ t_object *x = dummy_newobject(s, &sl);
+ int nouts = 0;
+ if (ac > 1)
+ {
+ ac--; av++;
+ while (ac--)
+ {
+ char c = 0;
+ if (av->a_type == A_SYMBOL)
+ {
+ c = *av->a_w.w_symbol->s_name;
+ if (c == 'i' || c == 'f' || c == 'l'
+ || c == 'b' || c == 's' || c == 'a')
+ nouts++;
+ else
+ c = 0;
+ }
+ if (c == 0)
+ {
+ loud_classarg(*(t_pd *)x);
+ break;
+ }
+ av++;
+ }
+ }
+ if (nouts < 1)
+ nouts = 0;
+ dummy_io(x, sl->s_nins, nouts + 2);
+ return (x);
+}
+
+/* CHECKME */
+static void *dummy_timeline_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_dummy_slot *sl;
+ t_object *x = dummy_newobject(s, &sl);
+ int nouts = 0;
+ if (ac)
+ {
+ if (av->a_type == A_FLOAT)
+ nouts = (int)av->a_w.w_float;
+ else if (ac > 1 && av[1].a_type == A_FLOAT)
+ nouts = (int)av[1].a_w.w_float;
+ }
+ if (nouts < 1)
+ nouts = 0;
+ dummy_io(x, sl->s_nins, nouts);
+ return (x);
+}
+
+static void *dummy_vexpr_new(t_symbol *s, int ac, t_atom *av)
+{
+ return (dummy_if_new(s, ac, av)); /* FIXME */
+}
+
+static void *dummy_vst_tilde_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_dummy_slot *sl;
+ t_object *x = dummy_newobject(s, &sl);
+ int nins = 0, nouts = 0;
+ if (ac > 1 && av[1].a_type == A_FLOAT)
+ {
+ if (av->a_type == A_FLOAT)
+ {
+ nins = (int)av->a_w.w_float;
+ nouts = (int)av[1].a_w.w_float;
+ }
+ }
+ else if (ac && av->a_type == A_FLOAT)
+ nouts = (int)av->a_w.w_float;
+ if (nins < 1)
+ nins = 2; /* CHECKME */
+ if (nouts < 1)
+ nouts = 2; /* CHECKME */
+ dummy_io(x, nins, nouts + 4); /* CHECKME */
+ return (x);
+}
+
+static t_dummy_slot dummy_slots[] =
+{
+ { "2d.wave~", 4, -1, 0, (t_newmethod)dummy_2dwave_tilde_new },
+ { "absolutepath", 1, 1, 0, 0 },
+ { "acosh", 1, 1, 0, 0 },
+ { "adoutput~", 1, -1, 0, (t_newmethod)dummy_adoutput_tilde_new },
+ { "adstatus", 2, 2, 0, 0 },
+ { "asinh", 1, 1, 0, 0 },
+ { "atanh", 1, 1, 0, 0 },
+ { "begin~", 0, 1, 0, 0 },
+ { "Biquad~", 6, 1, 0, 0 },
+ /* LATER try mapping bpatcher to a gop abstraction/subpatch */
+ { "buffer~", 1, 2, 0, 0 },
+ { "buffir~", 3, 1, 0, 0 },
+ { "cd", 1, 2, 0, 0 }, /* CHECKED (refman error?) */
+ { "cd~", 1, 6, 0, 0 }, /* CHECKED (refman error?) */
+ { "Change", 1, 3, 0, 0 },
+ { "clocker", 2, 1, 0, 0 },
+ { "closebang", 0, 1, 0, 0 },
+ { "colorpicker", 1, 1, 0, 0 },
+ { "curve~", 3, 2, 0, 0 },
+ { "date", 1, 3, 0, 0 },
+ { "defer", 1, 1, 0, 0 }, /* LATER pass anything through */
+ { "degrade~", 3, 1, 0, 0 },
+ { "detonate", 8, 8, 0, 0 },
+ { "dial", 1, 1, 0, 0 },
+ { "dialog", 2, 1, 0, 0 },
+ { "downsamp~", 2, 1, 0, 0 },
+ { "dropfile", 1, 2, 0, 0 },
+ { "dspstate~", 1, 3, 0, 0 },
+ { "dsptime~", 1, 1, 0, 0 },
+ { "env", 1, 1, 0, 0 },
+ { "envi", 1, 1, 0, 0 },
+ { "error", 1, 1, 0, 0 },
+ { "ezadc~", 1, 2, 0, 0 },
+ { "ezdac~", 2, 0, 0, 0 },
+ { "fffb~", 1, -1, 0, (t_newmethod)dummy_fffb_tilde_new },
+ /* LATER Fft~ */
+ /* LATER pfft~-specific classes: fftin~, fftinfo~, fftout~ */
+ { "filedate", 1, 1, 0, 0 },
+ { "filein", 3, 3, 0, 0 },
+ { "filepath", 1, 1, 0, 0 },
+ { "filtergraph~", 8, 6, 0, 0 },
+ { "folder", 1, 1, 0, 0 }, /* CHECKME 2nd outlet */
+ { "follow", 1, 2, 0, 0 },
+ { "fpic", 1, 0, 0, 0 },
+ { "frame", 6, 0, 0, 0 },
+ { "function", 1, 4, 0, 0 },
+ { "gain~", 2, 2, 0, 0 },
+ { "gate~", 2, -1, 0, (t_newmethod)dummy_gate_tilde_new },
+ { "gestalt", 1, 2, 0, 0 },
+ { "Ggate", 2, 2, 0, 0 },
+ /* LATER glove? */
+ { "graphic", 1, 0, 0, 0 },
+ { "groove~", 3, -1, 0, (t_newmethod)dummy_groove_tilde_new },
+ { "Gswitch", 3, 1, 0, 0 },
+ { "hint", 1, 1, 0, 0 },
+ { "if", -1, -1, 0, (t_newmethod)dummy_if_new },
+ /* LATER Ifft~ */
+ { "imovie", 1, 3, 0, 0 },
+ { "IncDec", 1, 1, 0, 0 },
+ { "info~", 1, 8, 0, 0 }, /* CHECKME nouts */
+ { "ioscbank~", 4, 1, 0, 0 },
+ { "Key", 0, 3, 0, 0 },
+ { "Keyup", 0, 3, 0, 0 },
+ { "kslider", 2, 2, 0, 0 },
+ { "lcd", 1, 4, 0, 0 }, /* CHECKME nouts */
+ { "led", 1, 1, 0, 0 },
+ { "Line", 3, 2, 0, 0 },
+ { "lores~", 3, 1, 0, 0 },
+ { "matrixctrl", 1, 1, 0, 0 }, /* CHECKME nins, nouts */
+ { "matrix~", -1, -1, 0, (t_newmethod)dummy_matrix_tilde_new },
+ { "maximum~", 2, 1, 0, 0 },
+ { "menubar", 1, 4, 0, 0 }, /* LATER parse #Xs (additional outs) */
+ { "meter~", 1, 1, 0, 0 }, /* LATER consider mapping to the vu */
+ { "minimum~", 2, 1, 0, 0 },
+ { "movie", 1, 3, 0, 0 },
+ /* CHECKME msd */
+ { "mstosamps~", 1, 2, 0, 0 },
+ { "mtr", -1, -1, 0, (t_newmethod)dummy_mtr_new },
+ { "multiSlider", 1, 1, 0, 0 },
+ { "mute~", 1, 1, 0, 0 },
+ { "normalize~", 2, 1, 0, 0 },
+ { "number~", 2, 2, 0, 0 },
+ { "numkey", 1, 2, 0, 0 },
+ { "omscontrollers", 4, 2, 0, 0 }, /* CHECKME osx */
+ { "omsinfo", 2, 1, 0, 0 }, /* LATER midiinfo? */
+ { "omsnotes", 4, 2, 0, 0 }, /* CHECKME osx */
+ { "omspatches", 3, 2, 0, 0 }, /* CHECKME osx */
+ { "onecopy", 0, 0, 0, 0 }, /* CHECKME */
+ { "onepole~", 2, 1, 0, 0 },
+ { "opendialog", 1, 2, 0, 0 },
+ { "oscbank~", 4, 1, 0, 0 },
+ { "oval", 6, 0, 0, 0 },
+ { "overdrive~", 2, 1, 0, 0 },
+ { "panel", 1, 0, 0, 0 },
+ { "pass~", 1, 1, 0, 0 },
+ { "pcontrol", 1, 1, 0, 0 },
+ /* LATER pfft~ */
+ { "phaseshift~", 3, 1, 0, 0 },
+ { "pics", 3, 0, 0, 0 }, /* CHECKME */
+ { "pics2", 3, 0, 0, 0 }, /* CHECKME */
+ { "pict", 3, 0, 0, 0 },
+ { "pictctrl", 1, 1, 0, 0 },
+ { "pictslider", 2, 2, 0, 0 }, /* CHECKME one-dimensional mode */
+ { "pink~", 1, 1, 0, 0 }, /* CHECKME inlet */
+ { "playbar", 1, 2, 0, 0 }, /* CHECKME */
+ { "plugconfig", 1, 0, 0, 0 },
+ { "plugin~", 2, 2, 0, 0 },
+ { "plugmidiin", 0, 1, 0, 0 },
+ { "plugmidiout", 1, 0, 0, 0 },
+ { "plugmod", 5, 3, 0, 0 },
+ { "plugmorph", 2, 3, 0, 0 },
+ { "plugmultiparam", 1, 2, 0, 0 },
+ { "plugout~", 2, 2, 0, 0 }, /* CHECKME nouts */
+ { "plugphasor~", 0, 1, 0, 0 }, /* CHECKME nouts */
+ { "plugreceive~", 1, 1, 0, 0 },
+ { "plugsend~", 1, 0, 0, 0 },
+ { "plugstore", 1, 1, 0, 0 }, /* CHECKME nouts */
+ { "plugsync~", 0, 9, 0, 0 }, /* CHECKME nouts */
+ { "poke~", 3, 0, 0, 0 },
+ { "Poly", 2, 4, 0, 0 },
+ { "polyin", 1, 3, 0, 0 }, /* LATER parse args for nouts */
+ { "polyout", 3, 0, 0, 0 }, /* CHECKME nins */
+ /* LATER poly~ */
+ { "pong~", -1, 1, 0, (t_newmethod)dummy_pong_tilde_new },
+ { "pp", 2, 2, 0, 0 }, /* CHECKME nins */
+ { "pptempo", 2, 2, 0, 0 },
+ { "pptime", 4, 4, 0, 0 },
+ { "preset", 1, 3, 0, 0 },
+ { "radiogroup", 1, 1, 0, 0 },
+ { "rate~", 2, 1, 0, 0 }, /* CHECKME */
+ /* LATER settable Receive? */
+ { "rect", 6, 0, 0, 0 },
+ { "relativepath", 1, 1, 0, 0 },
+ { "reson~", 4, 1, 0, 0 },
+ { "rewire~", 1, -1, 0, (t_newmethod)dummy_rewire_tilde_new },
+ { "ring", 6, 0, 0, 0 },
+ { "round~", 2, 1, 0, 0 },
+ { "rslider", 2, 2, 0, 0 },
+ { "rtin", 1, 1, 0, 0 },
+ { "sampstoms~", 1, 2, 0, 0 },
+ { "savedialog", 1, 3, 0, 0 },
+ { "screensize", 1, 2, 0, 0 },
+ { "selector~", -1, 1, 0, (t_newmethod)dummy_selector_tilde_new },
+ { "seq~", 1, 2, 0, 0 },
+ { "serial", 1, 2, 0, 0 },
+ { "setclock", 2, 1, 0, 0 },
+ { "sfinfo~", 1, 6, 0, 0 }, /* CHECKME nouts */
+ { "sflist~", 1, 0, 0, 0 },
+ { "sfplay~", 1, -1, 0, (t_newmethod)dummy_sfplay_tilde_new },
+ { "sfrecord~", -1, 0, 0, (t_newmethod)dummy_sfrecord_tilde_new },
+ { "sndmgrin~", 0, 2, 0, 0 }, /* CHECKME */
+ { "strippath", 1, 2, 0, 0 },
+ { "stutter~", -1, -1, 0, (t_newmethod)dummy_stutter_tilde_new },
+ { "suspend", 0, 1, 0, 0 },
+ { "svf~", 3, 4, 0, 0 },
+ { "swatch", 3, 2, 0, 0 },
+ { "sxformat", -1, 1, 0, (t_newmethod)dummy_sxformat_new },
+ { "sysexin", 1, 1, 0, 0 },
+ { "Table", 2, 2, 0, 0 },
+ { "tapin~", 1, 1, 0, 0 },
+ { "tapout~", -1, -1, 0, (t_newmethod)dummy_tapout_tilde_new },
+ { "teeth~", 6, 1, 0, 0 },
+ { "tempo", 4, 1, 0, 0 },
+ { "Text", 1, 1, 0, 0 },
+ { "textedit", 1, 3, 0, 0 },
+ { "thisobject", 1, 3, 0, 0 }, /* CHECKME */
+ { "thispatcher", 1, 2, 0, 0 },
+ { "thisTimeline", 1, 1, 0, 0 },
+ { "thisTrack", 1, 0, 0, 0 },
+ { "thispoly~", 1, 1, 0, 0 },
+ { "thresh~", 3, 1, 0, 0 },
+ { "tiCmd", 0, -1, 0, (t_newmethod)dummy_tiCmd_new },
+ { "timeline", 1, -1, 0, (t_newmethod)dummy_timeline_new },
+ { "tiOut", 1, 0, 0, 0 },
+ { "timein", 3, 4, 0, 0 },
+ { "timeout", 4, 0, 0, 0 },
+ /* LATER touchin's inlet (Touchin?) */
+ { "trunc~", 1, 1, 0, 0 }, /* CHECKME */
+ { "ubutton", 1, 4, 0, 0 },
+ { "umenu", 1, 2, 0, 0 },
+ { "vdp", 3, 4, 0, 0 },
+ { "vexpr", -1, 1, 0, (t_newmethod)dummy_vexpr_new },
+ { "vpicture", 0, 0, 0, 0 },
+ { "vst~", -1, -1, 0, (t_newmethod)dummy_vst_tilde_new },
+ { "waveform~", 5, 6, 0, 0 }, /* CHECKME */
+ { "zerox~", 1, 2, 0, 0 },
+ { "zigzag~", 2, 4, 0, 0 },
+ { "_dummy", 0, 0, 0, 0 }
+};
+
+static void *dummy_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_dummy_slot *sl;
+ t_object *x = dummy_newobject(s, &sl);
+ dummy_io(x, sl->s_nins, sl->s_nouts);
+ return (x);
+}
+
+static void dummy_io(t_object *x, int nins, int nouts)
+{
+ nins = (nins > 0 ? nins - 1 : 0);
+ while (nins--) inlet_new(x, (t_pd *)x, 0, 0);
+ while (nouts--) outlet_new(x, &s_anything);
+}
+
+static t_object *dummy_newobject(t_symbol *s, t_dummy_slot **slotp)
+{
+ t_object *x;
+ t_dummy_slot *sl;
+ int fnd;
+ for (fnd = 0; fnd < dummy_nclasses; fnd++)
+ /* LATER compare symbols, rather than strings */
+ if (dummy_classes[fnd] /* empty slot: abstraction replacement */
+ && !strcmp(class_getname(dummy_classes[fnd]), s->s_name))
+ break;
+ x = (t_object *)pd_new(dummy_classes[fnd]);
+ sl = &dummy_slots[fnd];
+ if (fnd == dummy_nclasses)
+ bug("dummy_newobject"); /* create a "_dummy" in this case */
+ else if (!sl->s_warned)
+ {
+ loud_warning((t_pd *)x, "dummy substitution");
+ sl->s_warned = 1;
+ }
+ if (slotp) *slotp = sl;
+ return (x);
+}
+
+int dummy_nreplacements(void)
+{
+ return (dummy_nreps);
+}
+
+void dummy_printreplacements(char *msg)
+{
+ int i, len = strlen(msg);
+ t_dummy_slot *sl;
+ startpost(msg);
+ for (i = 0, sl = dummy_slots; i < dummy_nclasses; i++, sl++)
+ {
+ if (!dummy_classes[i])
+ {
+ int l = 1 + strlen(sl->s_name);
+ if ((len += l) > 66)
+ {
+ endpost();
+ startpost(" ");
+ len = 3 + l;
+ }
+ poststring(sl->s_name);
+ }
+ }
+ endpost();
+}
+
+void alldummies_setup(void)
+{
+ t_dummy_slot *sl;
+ int i;
+ dummy_nclasses = sizeof(dummy_slots)/sizeof(*dummy_slots);
+ /* never freed: */
+ dummy_classes = getbytes(dummy_nclasses * sizeof(*dummy_classes));
+ for (i = 0, sl = dummy_slots; i < dummy_nclasses; i++, sl++)
+ {
+ int fd;
+ char dirbuf[MAXPDSTRING], *nameptr;
+ if ((fd = open_via_path("", sl->s_name, ".pd",
+ dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0)
+ {
+ close(fd);
+ dummy_nreps++;
+ }
+ else
+ dummy_classes[i] =
+ class_new(gensym(sl->s_name),
+ sl->s_method ? sl->s_method : (t_newmethod)dummy_new,
+ 0, sizeof(t_object),
+ (sl->s_nins ? 0 : CLASS_NOINLET), A_GIMME, 0);
+ }
+ dummy_nclasses--; /* use "_dummy" as a sentinel */
+}
diff --git a/cyclone/shadow/nettles.c b/cyclone/shadow/nettles.c
new file mode 100644
index 0000000..d7ccb87
--- /dev/null
+++ b/cyclone/shadow/nettles.c
@@ -0,0 +1,549 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+#include "shared.h"
+#include "sickle/sic.h"
+#include "shadow.h"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define fmodf fmod
+#endif
+
+/* Two remaining control binops have their inputs reversed.
+ LATER think about float-to-int conversion -- there is no point in making
+ the two below compatible, while all the others are not compatible... */
+
+/* CHECKED left inlet causes output (refman's error -- a total rubbish) */
+
+typedef struct _rbinop
+{
+ t_object x_ob;
+ t_float x_f1; /* left inlet value */
+ t_float x_f2;
+} t_rbinop;
+
+static t_class *rminus_class;
+
+static void rminus_bang(t_rbinop *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_f2 - x->x_f1);
+}
+
+static void rminus_float(t_rbinop *x, t_float f)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_f2 - (x->x_f1 = f));
+}
+
+static void *rminus_new(t_floatarg f)
+{
+ t_rbinop *x = (t_rbinop *)pd_new(rminus_class);
+ floatinlet_new((t_object *)x, &x->x_f2); /* CHECKED */
+ outlet_new((t_object *)x, &s_float);
+ x->x_f1 = 0;
+ x->x_f2 = f; /* CHECKED */
+ return (x);
+}
+
+static t_class *rdiv_class;
+
+static void rdiv_bang(t_rbinop *x)
+{
+ if (x->x_f1 != 0.)
+ outlet_float(((t_object *)x)->ob_outlet, x->x_f2 / x->x_f1);
+ else
+ /* CHECKED int mode: nonnegative/0 == 0, negative/0 == -1,
+ float mode: positive/0 == INT_MAX, nonpositive/0 == INT_MIN
+ LATER rethink -- why is it INT_MAX, not FLT_MAX? */
+ outlet_float(((t_object *)x)->ob_outlet,
+ (x->x_f2 > 0 ? SHARED_INT_MAX : SHARED_INT_MIN));
+}
+
+static void rdiv_float(t_rbinop *x, t_float f)
+{
+ x->x_f1 = f;
+ rdiv_bang(x);
+}
+
+static void *rdiv_new(t_floatarg f)
+{
+ t_rbinop *x = (t_rbinop *)pd_new(rdiv_class);
+ floatinlet_new((t_object *)x, &x->x_f2);
+ outlet_new((t_object *)x, &s_float);
+ x->x_f1 = 0;
+ x->x_f2 = f; /* CHECKED (refman's error) */
+ return (x);
+}
+
+/* The implementation of signal relational operators below has been tuned
+ somewhat, mostly in order to get rid of costly int->float conversions.
+ Loops are not hand-unrolled, because these have proven to be slower
+ in all the tests performed so far. LATER find a good soul willing to
+ make a serious profiling research... */
+
+typedef struct _sigeq
+{
+ t_sic x_sic;
+ int x_algo;
+} t_sigeq;
+
+static t_class *sigeq_class;
+
+static t_int *sigeq_perform0(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ t_shared_floatint fi;
+#ifdef NETTLES_SAFE
+ int32 truebits;
+ fi.fi_f = 1.;
+ truebits = fi.fi_i;
+#endif
+ while (nblock--)
+ {
+#ifdef NETTLES_SAFE
+ fi.fi_i = ~((*in1++ == *in2++) - 1) & truebits;
+#else
+ fi.fi_i = ~((*in1++ == *in2++) - 1) & SHARED_TRUEBITS;
+#endif
+ *out++ = fi.fi_f;
+ }
+ return (w + 5);
+}
+
+static t_int *sigeq_perform1(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ while (nblock--) *out++ = (*in1++ == *in2++);
+ return (w + 5);
+}
+
+static t_int *sigeq_perform2(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ for (; nblock; nblock -= 8, in1 += 8, in2 += 8, out += 8)
+ {
+ float f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ float f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+ float g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ float g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+ out[0] = f0 == g0; out[1] = f1 == g1;
+ out[2] = f2 == g2; out[3] = f3 == g3;
+ out[4] = f4 == g4; out[5] = f5 == g5;
+ out[6] = f6 == g6; out[7] = f7 == g7;
+ }
+ return (w + 5);
+}
+
+static void sigeq_dsp(t_sigeq *x, t_signal **sp)
+{
+ switch (x->x_algo)
+ {
+ case 1:
+ dsp_add(sigeq_perform1, 4, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+ break;
+ case 2:
+ dsp_add(sigeq_perform2, 4, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+ break;
+ default:
+ dsp_add(sigeq_perform0, 4, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+ }
+}
+
+static void sigeq__algo(t_sigeq *x, t_floatarg f)
+{
+ x->x_algo = f;
+}
+
+static void *sigeq_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_sigeq *x = (t_sigeq *)pd_new(sigeq_class);
+ if (s == gensym("_==1~"))
+ x->x_algo = 1;
+ else if (s == gensym("_==2~"))
+ x->x_algo = 2;
+ else
+ x->x_algo = 0;
+ sic_inlet((t_sic *)x, 1, 0, 0, ac, av);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+typedef t_sic t_signeq;
+static t_class *signeq_class;
+
+static t_int *signeq_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ t_shared_floatint fi;
+ while (nblock--)
+ {
+ fi.fi_i = ~((*in1++ != *in2++) - 1) & SHARED_TRUEBITS;
+ *out++ = fi.fi_f;
+ }
+ return (w + 5);
+}
+
+static void signeq_dsp(t_signeq *x, t_signal **sp)
+{
+ dsp_add(signeq_perform, 4, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+}
+
+static void *signeq_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_signeq *x = (t_signeq *)pd_new(signeq_class);
+ sic_inlet((t_sic *)x, 1, 0, 0, ac, av);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+typedef t_sic t_siglt;
+static t_class *siglt_class;
+
+static t_int *siglt_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ t_shared_floatint fi;
+ while (nblock--)
+ {
+ fi.fi_i = ~((*in1++ < *in2++) - 1) & SHARED_TRUEBITS;
+ *out++ = fi.fi_f;
+ }
+ return (w + 5);
+}
+
+static void siglt_dsp(t_siglt *x, t_signal **sp)
+{
+ dsp_add(siglt_perform, 4, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+}
+
+static void *siglt_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_siglt *x = (t_siglt *)pd_new(siglt_class);
+ sic_inlet((t_sic *)x, 1, 0, 0, ac, av);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+typedef t_sic t_siggt;
+static t_class *siggt_class;
+
+static t_int *siggt_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ t_shared_floatint fi;
+ while (nblock--)
+ {
+ fi.fi_i = ~((*in1++ > *in2++) - 1) & SHARED_TRUEBITS;
+ *out++ = fi.fi_f;
+ }
+ return (w + 5);
+}
+
+static void siggt_dsp(t_siggt *x, t_signal **sp)
+{
+ dsp_add(siggt_perform, 4, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+}
+
+static void *siggt_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_siggt *x = (t_siggt *)pd_new(siggt_class);
+ sic_inlet((t_sic *)x, 1, 0, 0, ac, av);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+typedef t_sic t_sigleq;
+static t_class *sigleq_class;
+
+static t_int *sigleq_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ t_shared_floatint fi;
+ while (nblock--)
+ {
+ fi.fi_i = ~((*in1++ <= *in2++) - 1) & SHARED_TRUEBITS;
+ *out++ = fi.fi_f;
+ }
+ return (w + 5);
+}
+
+static void sigleq_dsp(t_sigleq *x, t_signal **sp)
+{
+ dsp_add(sigleq_perform, 4, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+}
+
+static void *sigleq_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_sigleq *x = (t_sigleq *)pd_new(sigleq_class);
+ sic_inlet((t_sic *)x, 1, 0, 0, ac, av);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+typedef t_sic t_siggeq;
+static t_class *siggeq_class;
+
+static t_int *siggeq_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ t_shared_floatint fi;
+ while (nblock--)
+ {
+ fi.fi_i = ~((*in1++ >= *in2++) - 1) & SHARED_TRUEBITS;
+ *out++ = fi.fi_f;
+ }
+ return (w + 5);
+}
+
+static void siggeq_dsp(t_siggeq *x, t_signal **sp)
+{
+ dsp_add(siggeq_perform, 4, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+}
+
+static void *siggeq_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_siggeq *x = (t_siggeq *)pd_new(siggeq_class);
+ sic_inlet((t_sic *)x, 1, 0, 0, ac, av);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+typedef t_sic t_sigrminus;
+static t_class *sigrminus_class;
+
+static t_int *sigrminus_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ while (nblock--) *out++ = *in2++ - *in1++;
+ return (w + 5);
+}
+
+static void sigrminus_dsp(t_sigrminus *x, t_signal **sp)
+{
+ dsp_add(sigrminus_perform, 4, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+}
+
+static void *sigrminus_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_sigrminus *x = (t_sigrminus *)pd_new(sigrminus_class);
+ sic_inlet((t_sic *)x, 1, 0, 0, ac, av);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+typedef t_sic t_sigrover;
+static t_class *sigrover_class;
+
+static t_int *sigrover_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ while (nblock--)
+ {
+ t_float f1 = *in1++;
+ /* CHECKED incompatible: c74 outputs NaNs.
+ The line below is consistent with Pd's /~, LATER rethink. */
+ /* LATER multiply by reciprocal if in1 has no signal feeders */
+ *out++ = (f1 == 0. ? 0. : *in2++ / f1);
+ }
+ return (w + 5);
+}
+
+static void sigrover_dsp(t_sigrover *x, t_signal **sp)
+{
+ dsp_add(sigrover_perform, 4, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+}
+
+static void *sigrover_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_sigrover *x = (t_sigrover *)pd_new(sigrover_class);
+ /* CHECKED default 0 (refman's error), LATER rethink */
+ sic_inlet((t_sic *)x, 1, 0, 0, ac, av);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+typedef t_sic t_sigmod;
+static t_class *sigmod_class;
+
+static t_int *sigmod_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ while (nblock--)
+ {
+ t_float f1 = *in1++;
+ t_float f2 = *in2++;
+ /* LATER think about using ieee-754 normalization tricks */
+ *out++ = (f2 == 0. ? 0. /* CHECKED */
+ : fmod(f1, f2));
+ }
+ return (w + 5);
+}
+
+static void sigmod_dsp(t_sigmod *x, t_signal **sp)
+{
+ dsp_add(sigmod_perform, 4, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+}
+
+static void *sigmod_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_sigmod *x = (t_sigmod *)pd_new(sigmod_class);
+ /* CHECKED default 0 (refman's error), LATER rethink */
+ sic_inlet((t_sic *)x, 1, 0, 0, ac, av);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+typedef struct _sigaccum
+{
+ t_sic x_sic;
+ t_float x_sum;
+} t_sigaccum;
+
+static t_class *sigaccum_class;
+
+static t_int *sigaccum_perform(t_int *w)
+{
+ t_sigaccum *x = (t_sigaccum *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ t_float sum = x->x_sum;
+ while (nblock--) *out++ = (sum += *in++);
+ x->x_sum = sum;
+ return (w + 5);
+}
+
+static void sigaccum_dsp(t_sigaccum *x, t_signal **sp)
+{
+ dsp_add(sigaccum_perform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void sigaccum_bang(t_sigaccum *x)
+{
+ x->x_sum = 0;
+}
+
+static void sigaccum_set(t_sigaccum *x, t_floatarg f)
+{
+ x->x_sum = f;
+}
+
+static void *sigaccum_new(t_floatarg f)
+{
+ t_sigaccum *x = (t_sigaccum *)pd_new(sigaccum_class);
+ x->x_sum = f;
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void allnettles_setup(void)
+{
+ rminus_class = class_new(gensym("!-"),
+ (t_newmethod)rminus_new, 0,
+ sizeof(t_rbinop), 0, A_DEFFLOAT, 0);
+ class_addbang(rminus_class, rminus_bang);
+ class_addfloat(rminus_class, rminus_float);
+ rdiv_class = class_new(gensym("!/"),
+ (t_newmethod)rdiv_new, 0,
+ sizeof(t_rbinop), 0, A_DEFFLOAT, 0);
+ class_addbang(rdiv_class, rdiv_bang);
+ class_addfloat(rdiv_class, rdiv_float);
+
+ sigeq_class = class_new(gensym("==~"),
+ (t_newmethod)sigeq_new, 0,
+ sizeof(t_sigeq), 0, A_GIMME, 0);
+ class_addcreator((t_newmethod)sigeq_new,
+ gensym("_==1~"), A_GIMME, 0);
+ class_addcreator((t_newmethod)sigeq_new,
+ gensym("_==2~"), A_GIMME, 0);
+ sic_setup(sigeq_class, sigeq_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(sigeq_class, (t_method)sigeq__algo,
+ gensym("_algo"), A_FLOAT, 0);
+
+ signeq_class = class_new(gensym("!=~"),
+ (t_newmethod)signeq_new, 0,
+ sizeof(t_signeq), 0, A_GIMME, 0);
+ sic_setup(signeq_class, signeq_dsp, SIC_FLOATTOSIGNAL);
+ siglt_class = class_new(gensym("<~"),
+ (t_newmethod)siglt_new, 0,
+ sizeof(t_siglt), 0, A_GIMME, 0);
+ sic_setup(siglt_class, siglt_dsp, SIC_FLOATTOSIGNAL);
+ siggt_class = class_new(gensym(">~"),
+ (t_newmethod)siggt_new, 0,
+ sizeof(t_siggt), 0, A_GIMME, 0);
+ sic_setup(siggt_class, siggt_dsp, SIC_FLOATTOSIGNAL);
+ sigleq_class = class_new(gensym("<=~"),
+ (t_newmethod)sigleq_new, 0,
+ sizeof(t_sigleq), 0, A_GIMME, 0);
+ sic_setup(sigleq_class, sigleq_dsp, SIC_FLOATTOSIGNAL);
+ siggeq_class = class_new(gensym(">=~"),
+ (t_newmethod)siggeq_new, 0,
+ sizeof(t_siggeq), 0, A_GIMME, 0);
+ sic_setup(siggeq_class, siggeq_dsp, SIC_FLOATTOSIGNAL);
+ sigrminus_class = class_new(gensym("!-~"),
+ (t_newmethod)sigrminus_new, 0,
+ sizeof(t_sigrminus), 0, A_GIMME, 0);
+ sic_setup(sigrminus_class, sigrminus_dsp, SIC_FLOATTOSIGNAL);
+ sigrover_class = class_new(gensym("!/~"),
+ (t_newmethod)sigrover_new, 0,
+ sizeof(t_sigrover), 0, A_GIMME, 0);
+ sic_setup(sigrover_class, sigrover_dsp, SIC_FLOATTOSIGNAL);
+ sigmod_class = class_new(gensym("%~"),
+ (t_newmethod)sigmod_new, 0,
+ sizeof(t_sigmod), 0, A_GIMME, 0);
+ sic_setup(sigmod_class, sigmod_dsp, SIC_FLOATTOSIGNAL);
+ sigaccum_class = class_new(gensym("+=~"),
+ (t_newmethod)sigaccum_new, 0,
+ sizeof(t_sigaccum), 0, A_DEFFLOAT, 0);
+ sic_setup(sigaccum_class, sigaccum_dsp, SIC_FLOATTOSIGNAL);
+ class_addbang(sigaccum_class, sigaccum_bang);
+ class_addmethod(sigaccum_class, (t_method)sigaccum_set,
+ gensym("set"), A_FLOAT, 0);
+}
diff --git a/cyclone/shadow/shadow.h b/cyclone/shadow/shadow.h
new file mode 100644
index 0000000..aefc46e
--- /dev/null
+++ b/cyclone/shadow/shadow.h
@@ -0,0 +1,13 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __SHADOW_H__
+#define __SHADOW_H__
+
+void allnettles_setup(void);
+void alldummies_setup(void);
+int dummy_nreplacements(void);
+void dummy_printreplacements(char *msg);
+
+#endif
diff --git a/cyclone/sickle/Clip.c b/cyclone/sickle/Clip.c
new file mode 100644
index 0000000..2888be1
--- /dev/null
+++ b/cyclone/sickle/Clip.c
@@ -0,0 +1,59 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* Clip~ substitution is needed to handle signal input for lo and hi */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+#define CLIP_DEFLO 0.
+#define CLIP_DEFHI 0.
+
+typedef t_sic t_clip;
+static t_class *clip_class;
+
+static t_int *clip_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *in3 = (t_float *)(w[4]);
+ t_float *out = (t_float *)(w[5]);
+ while (nblock--)
+ {
+ float f = *in1++;
+ float lo = *in2++;
+ float hi = *in3++;
+ if (f < lo)
+ *out++ = lo;
+ else if (f > hi)
+ *out++ = hi;
+ else
+ *out++ = f;
+ }
+ return (w + 6);
+}
+
+static void clip_dsp(t_clip *x, t_signal **sp)
+{
+ dsp_add(clip_perform, 5, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec);
+}
+
+static void *clip_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_clip *x = (t_clip *)pd_new(clip_class);
+ sic_inlet((t_sic *)x, 1, CLIP_DEFLO, 0, ac, av);
+ sic_inlet((t_sic *)x, 2, CLIP_DEFHI, 1, ac, av);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void Clip_tilde_setup(void)
+{
+ clip_class = class_new(gensym("Clip~"),
+ (t_newmethod)clip_new, 0,
+ sizeof(t_clip), 0, A_GIMME, 0);
+ sic_setup(clip_class, clip_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/Line.c b/cyclone/sickle/Line.c
new file mode 100644
index 0000000..f1d2b18
--- /dev/null
+++ b/cyclone/sickle/Line.c
@@ -0,0 +1,299 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "common/grow.h"
+#include "common/loud.h"
+#include "sickle/sic.h"
+
+//#define LINE_DEBUG
+
+#ifndef PD_BADFLOAT
+#define PD_BADFLOAT(f) ((((*(unsigned int*)&(f))&0x7f800000)==0) || \
+ (((*(unsigned int*)&(f))&0x7f800000)==0x7f800000))
+#endif
+
+#define LINE_INISIZE 64 /* LATER rethink */
+#define LINE_MAXSIZE 64
+
+typedef struct _lineseg
+{
+ float s_target;
+ float s_delta;
+} t_lineseg;
+
+typedef struct _line
+{
+ t_sic x_sic;
+ float x_value;
+ float x_target;
+ float x_delta;
+ int x_deltaset;
+ float x_inc;
+ float x_biginc;
+ float x_ksr;
+ int x_nleft;
+ int x_retarget;
+ int x_size; /* as allocated */
+ int x_nsegs; /* as used */
+ t_lineseg *x_curseg;
+ t_lineseg *x_segs;
+ t_lineseg x_segini[LINE_INISIZE];
+ t_clock *x_clock;
+ t_outlet *x_bangout;
+#ifdef LINE_DEBUG
+ int dbg_nretargets;
+ int dbg_exitpoint;
+ int dbg_npoints;
+#endif
+} t_line;
+
+static t_class *line_class;
+
+static void line_tick(t_line *x)
+{
+ outlet_bang(x->x_bangout);
+#ifdef LINE_DEBUG
+ post("exit point %d, after %d retarget calls",
+ x->dbg_exitpoint, x->dbg_nretargets);
+ post("at value %g, after last %d npoints, with inc %g, biginc %g",
+ x->x_value, x->dbg_npoints, x->x_inc, x->x_biginc);
+ x->dbg_nretargets = x->dbg_exitpoint = x->dbg_npoints = 0;
+#endif
+}
+
+static t_int *line_perform(t_int *w)
+{
+ t_line *x = (t_line *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int nblock = (int)(w[3]);
+ int nxfer = x->x_nleft;
+ float curval = x->x_value;
+ float inc = x->x_inc;
+ float biginc = x->x_biginc;
+ if (PD_BADFLOAT(curval)) /* LATER rethink */
+ curval = x->x_value = 0;
+retarget:
+ if (x->x_retarget)
+ {
+ float target = x->x_curseg->s_target;
+ float delta = x->x_curseg->s_delta;
+ int npoints = delta * x->x_ksr + 0.5; /* LATER rethink */
+#ifdef LINE_DEBUG
+ x->dbg_nretargets++;
+#endif
+ x->x_nsegs--;
+ x->x_curseg++;
+ while (npoints <= 0)
+ {
+ curval = x->x_value = target;
+ if (x->x_nsegs)
+ {
+ target = x->x_curseg->s_target;
+ delta = x->x_curseg->s_delta;
+ npoints = delta * x->x_ksr + 0.5; /* LATER rethink */
+ x->x_nsegs--;
+ x->x_curseg++;
+ }
+ else
+ {
+ while (nblock--) *out++ = curval;
+ x->x_nleft = 0;
+#ifdef LINE_DEBUG
+ x->dbg_exitpoint = 1;
+#endif
+ clock_delay(x->x_clock, 0);
+ x->x_retarget = 0;
+ return (w + 4);
+ }
+ }
+ nxfer = x->x_nleft = npoints;
+ inc = x->x_inc = (target - x->x_value) / (float)npoints;
+ x->x_biginc = (int)(w[3]) * inc;
+ biginc = nblock * inc;
+ x->x_target = target;
+ x->x_retarget = 0;
+#ifdef LINE_DEBUG
+ x->dbg_npoints = npoints;
+#endif
+ }
+ if (nxfer >= nblock)
+ {
+ if ((x->x_nleft -= nblock) == 0)
+ {
+ if (x->x_nsegs) x->x_retarget = 1;
+ else
+ {
+#ifdef LINE_DEBUG
+ x->dbg_exitpoint = 2;
+#endif
+ clock_delay(x->x_clock, 0);
+ }
+ x->x_value = x->x_target;
+ }
+ else x->x_value += biginc;
+ while (nblock--)
+ *out++ = curval, curval += inc;
+ }
+ else if (nxfer > 0)
+ {
+ nblock -= nxfer;
+ do
+ *out++ = curval, curval += inc;
+ while (--nxfer);
+ curval = x->x_value = x->x_target;
+ if (x->x_nsegs)
+ {
+ x->x_retarget = 1;
+ goto retarget;
+ }
+ else
+ {
+ while (nblock--) *out++ = curval;
+ x->x_nleft = 0;
+#ifdef LINE_DEBUG
+ x->dbg_exitpoint = 3;
+#endif
+ clock_delay(x->x_clock, 0);
+ }
+ }
+ else while (nblock--) *out++ = curval;
+ return (w + 4);
+}
+
+static void line_float(t_line *x, t_float f)
+{
+ if (x->x_deltaset)
+ {
+ x->x_deltaset = 0;
+ x->x_target = f;
+ x->x_nsegs = 1;
+ x->x_curseg = x->x_segs;
+ x->x_curseg->s_target = f;
+ x->x_curseg->s_delta = x->x_delta;
+ x->x_retarget = 1;
+ }
+ else
+ {
+ x->x_value = x->x_target = f;
+ x->x_nsegs = 0;
+ x->x_curseg = 0;
+ x->x_nleft = 0;
+ x->x_retarget = 0;
+ }
+}
+
+static void line_ft1(t_line *x, t_floatarg f)
+{
+ x->x_delta = f;
+ x->x_deltaset = (f > 0);
+}
+
+static void line_list(t_line *x, t_symbol *s, int ac, t_atom *av)
+{
+ int natoms, nsegs, odd;
+ t_atom *ap;
+ t_lineseg *segp;
+ for (natoms = 0, ap = av; natoms < ac; natoms++, ap++)
+ if (ap->a_type != A_FLOAT) break; /* CHECKME */
+ if (!natoms)
+ return; /* CHECKME */
+ odd = natoms % 2;
+ nsegs = natoms / 2;
+ if (odd) nsegs++;
+ if (nsegs > x->x_size)
+ {
+ int ns = nsegs;
+ x->x_segs = grow_nodata(&ns, &x->x_size, x->x_segs,
+ LINE_INISIZE, x->x_segini,
+ sizeof(*x->x_segs));
+ if (ns < nsegs)
+ {
+ natoms = ns * 2;
+ nsegs = ns;
+ }
+ }
+ x->x_nsegs = nsegs;
+#ifdef LINE_DEBUG
+ post("%d segments:", x->x_nsegs);
+#endif
+ segp = x->x_segs;
+ if (odd) nsegs--;
+ while (nsegs--)
+ {
+ segp->s_target = av++->a_w.w_float;
+ segp->s_delta = av++->a_w.w_float;
+#ifdef LINE_DEBUG
+ post("%g %g", segp->s_target, segp->s_delta);
+#endif
+ segp++;
+ }
+ if (odd)
+ {
+ segp->s_target = av->a_w.w_float;
+ segp->s_delta = 0;
+#ifdef LINE_DEBUG
+ post("%g %g", segp->s_target, segp->s_delta);
+#endif
+ }
+ x->x_deltaset = 0;
+ x->x_target = x->x_segs->s_target;
+ x->x_curseg = x->x_segs;
+ x->x_retarget = 1;
+}
+
+/* CHECKED no stop, pity... */
+#if 0
+static void line_stop(t_line *x)
+{
+ x->x_target = x->x_value;
+ x->x_nleft = 0;
+ x->x_retarget = 0;
+ x->x_nsegs = 0;
+ x->x_curseg = 0;
+}
+#endif
+
+static void line_dsp(t_line *x, t_signal **sp)
+{
+ dsp_add(line_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+ x->x_ksr = sp[0]->s_sr * 0.001;
+}
+
+static void line_free(t_line *x)
+{
+ if (x->x_segs != x->x_segini)
+ freebytes(x->x_segs, x->x_size * sizeof(*x->x_segs));
+ if (x->x_clock) clock_free(x->x_clock);
+}
+
+static void *line_new(t_floatarg f)
+{
+ t_line *x = (t_line *)pd_new(line_class);
+ x->x_value = x->x_target = f;
+ x->x_deltaset = 0;
+ x->x_nleft = 0;
+ x->x_retarget = 0;
+ x->x_size = LINE_INISIZE;
+ x->x_nsegs = 0;
+ x->x_segs = x->x_segini;
+ x->x_curseg = 0;
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_signal);
+ x->x_bangout = outlet_new((t_object *)x, &s_bang);
+ x->x_clock = clock_new(x, (t_method)line_tick);
+ return (x);
+}
+
+void Line_tilde_setup(void)
+{
+ line_class = class_new(gensym("Line~"),
+ (t_newmethod)line_new, 0,
+ sizeof(t_line), 0, A_DEFFLOAT, 0);
+ sic_setup(line_class, line_dsp, SIC_NOMAINSIGNALIN);
+ class_addfloat(line_class, line_float);
+ class_addlist(line_class, line_list);
+ class_addmethod(line_class, (t_method)line_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
diff --git a/cyclone/sickle/Makefile b/cyclone/sickle/Makefile
new file mode 100644
index 0000000..61aa444
--- /dev/null
+++ b/cyclone/sickle/Makefile
@@ -0,0 +1,3 @@
+ROOT_DIR = ../..
+redefault: allsickles.c default
+include $(ROOT_DIR)/Makefile.common
diff --git a/cyclone/sickle/Makefile.objects b/cyclone/sickle/Makefile.objects
new file mode 100644
index 0000000..2edb12c
--- /dev/null
+++ b/cyclone/sickle/Makefile.objects
@@ -0,0 +1,11 @@
+SHARED_OBJECTS = \
+unstable/forky.o \
+unstable/fragile.o \
+common/loud.o \
+common/grow.o \
+common/vefl.o \
+common/binport.o \
+common/port.o \
+hammer/file.o \
+sickle/sic.o \
+sickle/arsic.o
diff --git a/cyclone/sickle/Makefile.sources b/cyclone/sickle/Makefile.sources
new file mode 100644
index 0000000..e807a06
--- /dev/null
+++ b/cyclone/sickle/Makefile.sources
@@ -0,0 +1,67 @@
+CX_SOURCES = \
+sickle.c
+
+OTHER_SOURCES = \
+allsickles.c \
+abs.c \
+acos.c \
+acosh.c \
+allpass.c \
+asin.c \
+asinh.c \
+atan.c \
+atan2.c \
+atanh.c \
+average.c \
+avg.c \
+bitand.c \
+bitnot.c \
+bitor.c \
+bitshift.c \
+bitxor.c \
+capture.c \
+cartopol.c \
+change.c \
+click.c \
+Clip.c \
+comb.c \
+cosh.c \
+cosx.c \
+count.c \
+cycle.c \
+delay.c \
+delta.c \
+deltaclip.c \
+edge.c \
+frameaccum.c \
+framedelta.c \
+index.c \
+kink.c \
+Line.c \
+linedrive.c \
+log.c \
+lookup.c \
+minmax.c \
+peakamp.c \
+peek.c \
+phasewrap.c \
+play.c \
+poltocar.c \
+pow.c \
+rand.c \
+rampsmooth.c \
+record.c \
+sah.c \
+Scope.c \
+sinh.c \
+sinx.c \
+slide.c \
+Snapshot.c \
+spike.c \
+tanh.c \
+tanx.c \
+train.c \
+trapezoid.c \
+triangle.c \
+vectral.c \
+wave.c
diff --git a/cyclone/sickle/Scope.c b/cyclone/sickle/Scope.c
new file mode 100644
index 0000000..75e825d
--- /dev/null
+++ b/cyclone/sickle/Scope.c
@@ -0,0 +1,1043 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* LATER cache gui commands */
+/* LATER think about resizing scheme. Currently mouse events are not bound
+ to any part of Scope~'s 'widget' as such, but to a special item, which is
+ created only for a selected Scope~. For the other scheme see the 'comment'
+ class (no indicator there, though -- neither a handle, nor a pointer change).
+ One way or the other, the traffic from the gui layer should be kept possibly
+ low, at least in run-mode. */
+
+#include <stdio.h>
+#include <string.h>
+#include "m_pd.h"
+#include "g_canvas.h"
+#include "common/loud.h"
+#include "common/grow.h"
+#include "unstable/forky.h"
+#include "sickle/sic.h"
+
+//#define SCOPE_DEBUG
+
+/* these are powers of 2 + margins */
+#define SCOPE_DEFWIDTH 130 /* CHECKED */
+#define SCOPE_MINWIDTH 66
+#define SCOPE_DEFHEIGHT 130 /* CHECKED */
+#define SCOPE_MINHEIGHT 34
+#define SCOPE_DEFPERIOD 256
+#define SCOPE_MINPERIOD 2
+#define SCOPE_MAXPERIOD 8092
+#define SCOPE_DEFBUFSIZE 128
+#define SCOPE_MINBUFSIZE 8
+#define SCOPE_MAXBUFSIZE 800 /* LATER rethink */
+#define SCOPE_WARNBUFSIZE 256
+#define SCOPE_DEFMINVAL -1.
+#define SCOPE_DEFMAXVAL 1.
+#define SCOPE_DEFDELAY 0
+#define SCOPE_MINDELAY 0
+#define SCOPE_TRIGLINEMODE 0
+#define SCOPE_TRIGUPMODE 1
+#define SCOPE_TRIGDOWNMODE 2
+#define SCOPE_DEFTRIGMODE SCOPE_TRIGLINEMODE
+#define SCOPE_MINTRIGMODE SCOPE_TRIGLINEMODE
+#define SCOPE_MAXTRIGMODE SCOPE_TRIGDOWNMODE
+#define SCOPE_DEFTRIGLEVEL 0.
+#define SCOPE_MINCOLOR 0
+#define SCOPE_MAXCOLOR 255
+#define SCOPE_DEFFGRED 102
+#define SCOPE_DEFFGGREEN 255
+#define SCOPE_DEFFGBLUE 51
+#define SCOPE_DEFBGRED 135
+#define SCOPE_DEFBGGREEN 135
+#define SCOPE_DEFBGBLUE 135
+#define SCOPE_SELCOLOR "#8080ff" /* a bit lighter shade of blue */
+#define SCOPE_FGWIDTH 0.7 /* line width is float */
+#define SCOPE_GRIDWIDTH 0.9
+#define SCOPE_SELBDWIDTH 3.0
+#define SCOPEHANDLE_WIDTH 10 /* item size is int */
+#define SCOPEHANDLE_HEIGHT 10
+/* these are performance-related hacks, LATER investigate */
+#define SCOPE_GUICHUNKMONO 16
+#define SCOPE_GUICHUNKXY 32
+
+typedef struct _scope
+{
+ t_sic x_sic;
+ t_glist *x_glist;
+ t_canvas *x_canvas; /* also an 'isvised' flag */
+ char x_tag[64];
+ char x_fgtag[64];
+ char x_bgtag[64];
+ char x_gridtag[64];
+ int x_width;
+ int x_height;
+ float x_minval;
+ float x_maxval;
+ int x_delay;
+ int x_trigmode;
+ float x_triglevel;
+ unsigned char x_fgred;
+ unsigned char x_fggreen;
+ unsigned char x_fgblue;
+ unsigned char x_bgred;
+ unsigned char x_bggreen;
+ unsigned char x_bgblue;
+ int x_xymode;
+ float *x_xbuffer;
+ float *x_ybuffer;
+ float x_xbufini[SCOPE_DEFBUFSIZE];
+ float x_ybufini[SCOPE_DEFBUFSIZE];
+ int x_allocsize;
+ int x_bufsize;
+ int x_bufphase;
+ int x_period;
+ int x_phase;
+ int x_precount;
+ int x_retrigger;
+ float x_ksr;
+ float x_currx;
+ float x_curry;
+ float x_trigx;
+ int x_frozen;
+ t_clock *x_clock;
+ t_pd *x_handle;
+} t_scope;
+
+typedef struct _scopehandle
+{
+ t_pd h_pd;
+ t_scope *h_master;
+ t_symbol *h_bindsym;
+ char h_pathname[64];
+ char h_outlinetag[64];
+ int h_dragon;
+ int h_dragx;
+ int h_dragy;
+} t_scopehandle;
+
+static t_class *scope_class;
+static t_class *scopehandle_class;
+
+static void scope_clear(t_scope *x, int withdelay)
+{
+ x->x_bufphase = 0;
+ x->x_phase = 0;
+ x->x_precount = (withdelay ? (int)(x->x_delay * x->x_ksr) : 0);
+ /* CHECKED delay does not matter (refman is wrong) */
+ x->x_retrigger = (x->x_trigmode != SCOPE_TRIGLINEMODE);
+ x->x_trigx = x->x_triglevel;
+}
+
+static t_int *scope_monoperform(t_int *w)
+{
+ t_scope *x = (t_scope *)(w[1]);
+ int bufphase = x->x_bufphase;
+ int bufsize = x->x_bufsize;
+ if (bufphase < bufsize)
+ {
+ int nblock = (int)(w[2]);
+ if (x->x_precount >= nblock)
+ x->x_precount -= nblock;
+ else
+ {
+ t_float *in = (t_float *)(w[3]);
+ int phase = x->x_phase;
+ int period = x->x_period;
+ float *bp1 = x->x_xbuffer + bufphase;
+ float *bp2 = x->x_ybuffer + bufphase;
+ float currx = x->x_currx;
+ if (x->x_precount > 0)
+ {
+ nblock -= x->x_precount;
+ in += x->x_precount;
+ x->x_precount = 0;
+ }
+ while (x->x_retrigger)
+ {
+ float triglevel = x->x_triglevel;
+ if (x->x_trigmode == SCOPE_TRIGUPMODE)
+ {
+ if (x->x_trigx < triglevel)
+ {
+ while (nblock--) if (*in++ >= triglevel)
+ {
+ x->x_retrigger = 0;
+ break;
+ }
+ }
+ else while (nblock--) if (*in++ < triglevel)
+ {
+ x->x_trigx = triglevel - 1.;
+ break;
+ }
+ }
+ else
+ {
+ if (x->x_trigx > triglevel)
+ {
+ while (nblock--) if (*in++ <= triglevel)
+ {
+ x->x_retrigger = 0;
+ break;
+ }
+ }
+ else while (nblock--) if (*in++ > triglevel)
+ {
+ x->x_trigx = triglevel + 1.;
+ break;
+ }
+ }
+ if (nblock <= 0)
+ return (w + 4);
+ }
+ while (nblock--)
+ {
+ if (phase)
+ {
+ float f = *in++;
+ /* CHECKED */
+ if ((currx < 0 && (f < currx || f > -currx)) ||
+ (currx > 0 && (f > currx || f < -currx)))
+ currx = f;
+ }
+ else currx = *in++;
+ if (currx != currx)
+ currx = 0.; /* CHECKED NaNs bashed to zeros */
+ if (++phase == period)
+ {
+ phase = 0;
+ if (++bufphase == bufsize)
+ {
+ *bp1 = *bp2 = currx;
+ clock_delay(x->x_clock, 0);
+ break;
+ }
+ else *bp1++ = *bp2++ = currx;
+ }
+ }
+ x->x_currx = currx;
+ x->x_bufphase = bufphase;
+ x->x_phase = phase;
+ }
+ }
+ return (w + 4);
+}
+
+static t_int *scope_xyperform(t_int *w)
+{
+ t_scope *x = (t_scope *)(w[1]);
+ int bufphase = x->x_bufphase;
+ int bufsize = x->x_bufsize;
+ if (bufphase < bufsize)
+ {
+ int nblock = (int)(w[2]);
+ if (x->x_precount >= nblock)
+ x->x_precount -= nblock;
+ else
+ {
+ t_float *in1 = (t_float *)(w[3]);
+ t_float *in2 = (t_float *)(w[4]);
+ int phase = x->x_phase;
+ int period = x->x_period;
+ float freq = 1. / period;
+ float *bp1 = x->x_xbuffer + bufphase;
+ float *bp2 = x->x_ybuffer + bufphase;
+ float currx = x->x_currx;
+ float curry = x->x_curry;
+ if (x->x_precount > 0)
+ {
+ nblock -= x->x_precount;
+ in1 += x->x_precount;
+ in2 += x->x_precount;
+ x->x_precount = 0;
+ }
+ if (x->x_retrigger)
+ {
+ /* CHECKME and FIXME */
+ x->x_retrigger = 0;
+ }
+ while (nblock--)
+ {
+ if (phase)
+ {
+ /* CHECKME */
+ currx += *in1++;
+ curry += *in2++;
+ }
+ else
+ {
+ currx = *in1++;
+ curry = *in2++;
+ }
+ if (currx != currx)
+ currx = 0.; /* CHECKME NaNs bashed to zeros */
+ if (curry != curry)
+ curry = 0.; /* CHECKME NaNs bashed to zeros */
+ if (++phase == period)
+ {
+ phase = 0;
+ if (++bufphase == bufsize)
+ {
+ *bp1 = currx * freq;
+ *bp2 = curry * freq;
+ clock_delay(x->x_clock, 0);
+ break;
+ }
+ else
+ {
+ *bp1++ = currx * freq;
+ *bp2++ = curry * freq;
+ }
+ }
+ }
+ x->x_currx = currx;
+ x->x_curry = curry;
+ x->x_bufphase = bufphase;
+ x->x_phase = phase;
+ }
+ }
+ return (w + 5);
+}
+
+static void scope_setxymode(t_scope *x, int xymode);
+
+static void scope_dsp(t_scope *x, t_signal **sp)
+{
+ x->x_ksr = sp[0]->s_sr * 0.001;
+ scope_setxymode(x,
+ forky_hasfeeders((t_object *)x, x->x_glist, 1, &s_signal));
+ if (x->x_xymode)
+ dsp_add(scope_xyperform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+ else
+ dsp_add(scope_monoperform, 3, x, sp[0]->s_n, sp[0]->s_vec);
+}
+
+static t_canvas *scope_getcanvas(t_scope *x, t_glist *glist)
+{
+ if (glist != x->x_glist)
+ {
+ bug("scope_getcanvas");
+ x->x_glist = glist;
+ }
+ return (x->x_canvas = glist_getcanvas(glist));
+}
+
+/* answers the question: ``can we draw and where to?'' */
+static t_canvas *scope_isvisible(t_scope *x)
+{
+ return (glist_isvisible(x->x_glist) ? x->x_canvas : 0);
+}
+
+static void scope_period(t_scope *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_float period = (s ? x->x_period : SCOPE_DEFPERIOD);
+ int result = loud_floatarg(*(t_pd *)x, (s ? 0 : 2), ac, av, &period,
+ SCOPE_MINPERIOD, SCOPE_MAXPERIOD,
+ /* LATER rethink warning rules */
+ (s ? LOUD_CLIP : LOUD_CLIP | LOUD_WARN),
+ (s ? 0 : LOUD_WARN), "samples per element");
+ if (!s || result == LOUD_ARGOK || result == LOUD_ARGOVER)
+ {
+ x->x_period = (int)period;
+ scope_clear(x, 0);
+ }
+}
+
+static void scope_float(t_scope *x, t_float f)
+{
+ t_atom at;
+ SETFLOAT(&at, f);
+ scope_period(x, &s_float, 1, &at);
+}
+
+static void scope_bufsize(t_scope *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_float bufsize = (s ? x->x_bufsize : SCOPE_DEFBUFSIZE);
+ int result = loud_floatarg(*(t_pd *)x, (s ? 0 : 4), ac, av, &bufsize,
+ SCOPE_MINBUFSIZE, SCOPE_WARNBUFSIZE,
+ /* LATER rethink warning rules */
+ (s ? LOUD_CLIP : LOUD_CLIP | LOUD_WARN),
+ (s ? 0 : LOUD_WARN), "display elements");
+ if (result == LOUD_ARGOVER)
+ {
+ bufsize = (s ? x->x_bufsize : SCOPE_DEFBUFSIZE);
+ result = loud_floatarg(*(t_pd *)x, (s ? 0 : 4), ac, av, &bufsize,
+ 0, SCOPE_MAXBUFSIZE, 0, LOUD_CLIP | LOUD_WARN,
+ "display elements");
+ }
+ if (!s)
+ {
+ x->x_allocsize = SCOPE_DEFBUFSIZE;
+ x->x_bufsize = 0;
+ x->x_xbuffer = x->x_xbufini;
+ x->x_ybuffer = x->x_ybufini;
+ }
+ if (!s || result == LOUD_ARGOK)
+ {
+ int newsize = (int)bufsize;
+ if (newsize > x->x_allocsize)
+ {
+ int nrequested = newsize;
+ int allocsize = x->x_allocsize;
+ int oldsize = x->x_bufsize;
+ x->x_xbuffer = grow_withdata(&nrequested, &oldsize,
+ &allocsize, x->x_xbuffer,
+ SCOPE_DEFBUFSIZE, x->x_xbufini,
+ sizeof(*x->x_xbuffer));
+ if (nrequested == newsize)
+ {
+ allocsize = x->x_allocsize;
+ oldsize = x->x_bufsize;
+ x->x_ybuffer = grow_withdata(&nrequested, &oldsize,
+ &allocsize, x->x_ybuffer,
+ SCOPE_DEFBUFSIZE, x->x_ybufini,
+ sizeof(*x->x_ybuffer));
+ }
+ if (nrequested == newsize)
+ {
+ x->x_allocsize = allocsize;
+ x->x_bufsize = newsize;
+ }
+ else
+ {
+ if (x->x_xbuffer != x->x_xbufini)
+ freebytes(x->x_xbuffer,
+ x->x_allocsize * sizeof(*x->x_xbuffer));
+ if (x->x_ybuffer != x->x_ybufini)
+ freebytes(x->x_ybuffer,
+ x->x_allocsize * sizeof(*x->x_ybuffer));
+ x->x_allocsize = SCOPE_DEFBUFSIZE;
+ x->x_bufsize = SCOPE_DEFBUFSIZE;
+ x->x_xbuffer = x->x_xbufini;
+ x->x_ybuffer = x->x_ybufini;
+ }
+ }
+ else x->x_bufsize = newsize;
+ scope_clear(x, 0);
+ }
+}
+
+static void scope_range(t_scope *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_float minval = (s ? x->x_minval : SCOPE_DEFMINVAL);
+ t_float maxval = (s ? x->x_maxval : SCOPE_DEFMAXVAL);
+ loud_floatarg(*(t_pd *)x, (s ? 0 : 5), ac, av, &minval, 0, 0, 0, 0, 0);
+ loud_floatarg(*(t_pd *)x, (s ? 1 : 6), ac, av, &maxval, 0, 0, 0, 0, 0);
+ /* CHECKME swapping, ignoring if equal */
+ if (minval < maxval)
+ {
+ x->x_minval = minval;
+ x->x_maxval = maxval;
+ }
+ else if (minval > maxval)
+ {
+ x->x_minval = maxval;
+ x->x_maxval = minval;
+ }
+ else if (!s)
+ {
+ x->x_minval = SCOPE_DEFMINVAL;
+ x->x_maxval = SCOPE_DEFMAXVAL;
+ }
+}
+
+static void scope_delay(t_scope *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_float delay = (s ? x->x_delay : SCOPE_DEFDELAY);
+ int result = loud_floatarg(*(t_pd *)x, (s ? 0 : 7), ac, av, &delay,
+ SCOPE_MINDELAY, 0,
+ LOUD_CLIP | LOUD_WARN, 0, "delay");
+ if (!s || result == LOUD_ARGOK)
+ x->x_delay = delay;
+}
+
+static void scope_trigger(t_scope *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_float trigmode = (s ? x->x_trigmode : SCOPE_DEFTRIGMODE);
+ loud_floatarg(*(t_pd *)x, (s ? 0 : 9), ac, av, &trigmode,
+ SCOPE_MINTRIGMODE, SCOPE_MAXTRIGMODE,
+ LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN,
+ "trigger mode");
+ x->x_trigmode = (int)trigmode;
+ if (x->x_trigmode == SCOPE_TRIGLINEMODE)
+ x->x_retrigger = 0;
+}
+
+static void scope_triglevel(t_scope *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_float triglevel = (s ? x->x_triglevel : SCOPE_DEFTRIGLEVEL);
+ loud_floatarg(*(t_pd *)x, (s ? 0 : 10), ac, av, &triglevel, 0, 0, 0, 0, 0);
+ x->x_triglevel = triglevel;
+}
+
+static void scope_frgb(t_scope *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_float fgred = (s ? x->x_fgred : SCOPE_DEFFGRED);
+ t_float fggreen = (s ? x->x_fggreen : SCOPE_DEFFGGREEN);
+ t_float fgblue = (s ? x->x_fgblue : SCOPE_DEFFGBLUE);
+ t_canvas *cv;
+ loud_floatarg(*(t_pd *)x, (s ? 0 : 11), ac, av, &fgred,
+ SCOPE_MINCOLOR, SCOPE_MAXCOLOR,
+ LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN, "color");
+ loud_floatarg(*(t_pd *)x, (s ? 1 : 12), ac, av, &fggreen,
+ SCOPE_MINCOLOR, SCOPE_MAXCOLOR,
+ LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN, "color");
+ loud_floatarg(*(t_pd *)x, (s ? 2 : 13), ac, av, &fgblue,
+ SCOPE_MINCOLOR, SCOPE_MAXCOLOR,
+ LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN, "color");
+ x->x_fgred = (int)fgred;
+ x->x_fggreen = (int)fggreen;
+ x->x_fgblue = (int)fgblue;
+ if (cv = scope_isvisible(x))
+ sys_vgui(".x%x.c itemconfigure %s -fill #%2.2x%2.2x%2.2x\n",
+ cv, x->x_fgtag, x->x_fgred, x->x_fggreen, x->x_fgblue);
+}
+
+static void scope_brgb(t_scope *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_float bgred = (s ? x->x_bgred : SCOPE_DEFBGRED);
+ t_float bggreen = (s ? x->x_bggreen : SCOPE_DEFBGGREEN);
+ t_float bgblue = (s ? x->x_bgblue : SCOPE_DEFBGBLUE);
+ t_canvas *cv;
+ loud_floatarg(*(t_pd *)x, (s ? 0 : 14), ac, av, &bgred,
+ SCOPE_MINCOLOR, SCOPE_MAXCOLOR,
+ LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN, "color");
+ loud_floatarg(*(t_pd *)x, (s ? 1 : 15), ac, av, &bggreen,
+ SCOPE_MINCOLOR, SCOPE_MAXCOLOR,
+ LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN, "color");
+ loud_floatarg(*(t_pd *)x, (s ? 2 : 16), ac, av, &bgblue,
+ SCOPE_MINCOLOR, SCOPE_MAXCOLOR,
+ LOUD_CLIP | LOUD_WARN, LOUD_CLIP | LOUD_WARN, "color");
+ x->x_bgred = (int)bgred;
+ x->x_bggreen = (int)bggreen;
+ x->x_bgblue = (int)bgblue;
+ if (cv = scope_isvisible(x))
+ sys_vgui(".x%x.c itemconfigure %s -fill #%2.2x%2.2x%2.2x\n",
+ cv, x->x_bgtag, x->x_bgred, x->x_bggreen, x->x_bgblue);
+}
+
+static void scope_getrect(t_gobj *z, t_glist *glist,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_scope *x = (t_scope *)z;
+ float x1, y1, x2, y2;
+ x1 = text_xpix((t_text *)x, glist);
+ y1 = text_ypix((t_text *)x, glist);
+ x2 = x1 + x->x_width;
+ y2 = y1 + x->x_height;
+ *xp1 = x1;
+ *yp1 = y1;
+ *xp2 = x2;
+ *yp2 = y2;
+}
+
+static void scope_displace(t_gobj *z, t_glist *glist, int dx, int dy)
+{
+ t_scope *x = (t_scope *)z;
+ t_text *t = (t_text *)z;
+ t->te_xpix += dx;
+ t->te_ypix += dy;
+ if (glist_isvisible(glist))
+ {
+ t_canvas *cv = scope_getcanvas(x, glist);
+ sys_vgui(".x%x.c move %s %d %d\n", cv, x->x_tag, dx, dy);
+ canvas_fixlinesfor(cv, t);
+ }
+}
+
+static void scope_select(t_gobj *z, t_glist *glist, int state)
+{
+ t_scope *x = (t_scope *)z;
+ t_canvas *cv = scope_getcanvas(x, glist);
+ t_scopehandle *sh = (t_scopehandle *)x->x_handle;
+ if (state)
+ {
+ int x1, y1, x2, y2;
+ scope_getrect(z, glist, &x1, &y1, &x2, &y2);
+
+ sys_vgui(".x%x.c itemconfigure %s -outline blue -width %f -fill %s\n",
+ cv, x->x_bgtag, SCOPE_SELBDWIDTH, SCOPE_SELCOLOR);
+
+ sys_vgui("canvas %s -width %d -height %d -bg #fedc00 -bd 0\n",
+ sh->h_pathname, SCOPEHANDLE_WIDTH, SCOPEHANDLE_HEIGHT);
+ sys_vgui(".x%x.c create window %f %f -anchor nw\
+ -width %d -height %d -window %s -tags %s\n",
+ cv, x2 - (SCOPEHANDLE_WIDTH - SCOPE_SELBDWIDTH),
+ y2 - (SCOPEHANDLE_HEIGHT - SCOPE_SELBDWIDTH),
+ SCOPEHANDLE_WIDTH, SCOPEHANDLE_HEIGHT,
+ sh->h_pathname, x->x_tag);
+ sys_vgui("bind %s <Button> {pd [concat %s _click 1 \\;]}\n",
+ sh->h_pathname, sh->h_bindsym->s_name);
+ sys_vgui("bind %s <ButtonRelease> {pd [concat %s _click 0 \\;]}\n",
+ sh->h_pathname, sh->h_bindsym->s_name);
+ sys_vgui("bind %s <Motion> {pd [concat %s _motion %%x %%y \\;]}\n",
+ sh->h_pathname, sh->h_bindsym->s_name);
+ }
+ else
+ {
+ sys_vgui(".x%x.c itemconfigure %s -outline black -width %f\
+ -fill #%2.2x%2.2x%2.2x\n", cv, x->x_bgtag, SCOPE_GRIDWIDTH,
+ x->x_bgred, x->x_bggreen, x->x_bgblue);
+ sys_vgui("destroy %s\n", sh->h_pathname);
+ }
+}
+
+static void scope_delete(t_gobj *z, t_glist *glist)
+{
+ canvas_deletelinesfor(glist, (t_text *)z);
+}
+
+static void scope_drawfgmono(t_scope *x, t_canvas *cv,
+ int x1, int y1, int x2, int y2)
+{
+ int i;
+ float dx, dy, xx, yy, sc;
+ float *bp;
+ dx = (float)(x2 - x1) / (float)x->x_bufsize;
+ sc = ((float)x->x_height - 2.) / (float)(x->x_maxval - x->x_minval);
+ sys_vgui(".x%x.c create line \\\n", cv);
+ for (i = 0, xx = x1, bp = x->x_xbuffer;
+ i < x->x_bufsize; i++, xx += dx, bp++)
+ {
+ yy = (y2 - 1) - sc * (*bp - x->x_minval);
+#ifndef SCOPE_DEBUG
+ if (yy > y2) yy = y2; else if (yy < y1) yy = y1;
+#endif
+ sys_vgui("%d %d \\\n", (int)xx, (int)yy);
+ }
+ sys_vgui("-fill #%2.2x%2.2x%2.2x -width %f -tags {%s %s}\n",
+ x->x_fgred, x->x_fggreen, x->x_fgblue,
+ SCOPE_FGWIDTH, x->x_fgtag, x->x_tag);
+
+ /* margin lines: masking overflows, so that they appear as gaps,
+ rather than clipped signal values, LATER rethink */
+ sys_vgui(".x%x.c create line %d %d %d %d\
+ -fill #%2.2x%2.2x%2.2x -width %f -tags {%s %s}\n",
+ cv, x1, y1, x2, y1, x->x_bgred, x->x_bggreen, x->x_bgblue,
+ 1., x->x_fgtag, x->x_tag);
+ sys_vgui(".x%x.c create line %d %d %d %d\
+ -fill #%2.2x%2.2x%2.2x -width %f -tags {%s %s}\n",
+ cv, x1, y2, x2, y2, x->x_bgred, x->x_bggreen, x->x_bgblue,
+ 1., x->x_fgtag, x->x_tag);
+}
+
+static void scope_drawfgxy(t_scope *x, t_canvas *cv,
+ int x1, int y1, int x2, int y2)
+{
+ int nleft = x->x_bufsize;
+ float *xbp = x->x_xbuffer, *ybp = x->x_ybuffer;
+ char chunk[200 * SCOPE_GUICHUNKXY]; /* LATER estimate */
+ char *chunkp = chunk;
+ char cmd1[64], cmd2[64];
+ float xx, yy, xsc, ysc;
+ xx = yy = 0;
+ /* subtract 1-pixel margins, see below */
+ xsc = ((float)x->x_width - 2.) / (float)(x->x_maxval - x->x_minval);
+ ysc = ((float)x->x_height - 2.) / (float)(x->x_maxval - x->x_minval);
+ sprintf(cmd1, ".x%x.c create line", (int)cv);
+ sprintf(cmd2, "-fill #%2.2x%2.2x%2.2x -width %f -tags {%s %s}\n ",
+ x->x_fgred, x->x_fggreen, x->x_fgblue,
+ SCOPE_FGWIDTH, x->x_fgtag, x->x_tag);
+ while (nleft > SCOPE_GUICHUNKXY)
+ {
+ int i = SCOPE_GUICHUNKXY;
+ while (i--)
+ {
+ float oldx = xx, oldy = yy, dx, dy;
+ xx = x1 + xsc * (*xbp++ - x->x_minval);
+ yy = y2 - ysc * (*ybp++ - x->x_minval);
+ /* using 1-pixel margins */
+ dx = (xx > oldx ? 1. : -1.);
+ dy = (yy > oldy ? 1. : -1.);
+#ifndef SCOPE_DEBUG
+ if (xx < x1 || xx > x2 || yy < y1 || yy > y2)
+ continue;
+#endif
+ sprintf(chunkp, "%s %d %d %d %d %s", cmd1,
+ (int)(xx - dx), (int)(yy - dy),
+ (int)(xx + dx), (int)(yy + dy), cmd2);
+ chunkp += strlen(chunkp);
+ }
+ if (chunkp > chunk)
+ sys_gui(chunk);
+ chunkp = chunk;
+ nleft -= SCOPE_GUICHUNKXY;
+ }
+ while (nleft--)
+ {
+ float oldx = xx, oldy = yy, dx, dy;
+ xx = x1 + xsc * (*xbp++ - x->x_minval);
+ yy = y2 - ysc * (*ybp++ - x->x_minval);
+ /* using 1-pixel margins */
+ dx = (xx > oldx ? 1. : -1.);
+ dy = (yy > oldy ? 1. : -1.);
+#ifndef SCOPE_DEBUG
+ if (xx < x1 || xx > x2 || yy < y1 || yy > y2)
+ continue;
+#endif
+ sprintf(chunkp, "%s %d %d %d %d %s", cmd1,
+ (int)(xx - dx), (int)(yy - dy),
+ (int)(xx + dx), (int)(yy + dy), cmd2);
+ chunkp += strlen(chunkp);
+ }
+ if (chunkp > chunk)
+ sys_gui(chunk);
+}
+
+static void scope_drawbg(t_scope *x, t_canvas *cv,
+ int x1, int y1, int x2, int y2)
+{
+ int i;
+ float dx, dy, xx, yy;
+ dx = (x2 - x1) * 0.125;
+ dy = (y2 - y1) * 0.25;
+ sys_vgui(".x%x.c create rectangle %d %d %d %d\
+ -fill #%2.2x%2.2x%2.2x -width %f -tags {%s %s}\n",
+ cv, x1, y1, x2, y2,
+ x->x_bgred, x->x_bggreen, x->x_bgblue,
+ SCOPE_GRIDWIDTH, x->x_bgtag, x->x_tag);
+ for (i = 0, xx = x1 + dx; i < 7; i++, xx += dx)
+ sys_vgui(".x%x.c create line %f %d %f %d\
+ -width %f -tags {%s %s}\n", cv, xx, y1, xx, y2,
+ SCOPE_GRIDWIDTH, x->x_gridtag, x->x_tag);
+ for (i = 0, yy = y1 + dy; i < 3; i++, yy += dy)
+ sys_vgui(".x%x.c create line %d %f %d %f\
+ -width %f -tags {%s %s}\n", cv, x1, yy, x2, yy,
+ SCOPE_GRIDWIDTH, x->x_gridtag, x->x_tag);
+}
+
+static void scope_drawmono(t_scope *x, t_canvas *cv)
+{
+ int x1, y1, x2, y2;
+ scope_getrect((t_gobj *)x, x->x_glist, &x1, &y1, &x2, &y2);
+ scope_drawbg(x, cv, x1, y1, x2, y2);
+ scope_drawfgmono(x, cv, x1, y1, x2, y2);
+}
+
+static void scope_redrawmono(t_scope *x, t_canvas *cv)
+{
+ int nleft = x->x_bufsize;
+ float *bp = x->x_xbuffer;
+ char chunk[32 * SCOPE_GUICHUNKMONO]; /* LATER estimate */
+ char *chunkp = chunk;
+ int x1, y1, x2, y2;
+ float dx, dy, xx, yy, sc;
+ scope_getrect((t_gobj *)x, x->x_glist, &x1, &y1, &x2, &y2);
+ dx = (float)(x2 - x1) / (float)x->x_bufsize;
+ sc = ((float)x->x_height - 2.) / (float)(x->x_maxval - x->x_minval);
+ xx = x1;
+ sys_vgui(".x%x.c coords %s \\\n", cv, x->x_fgtag);
+ while (nleft > SCOPE_GUICHUNKMONO)
+ {
+ int i = SCOPE_GUICHUNKMONO;
+ while (i--)
+ {
+ yy = (y2 - 1) - sc * (*bp++ - x->x_minval);
+#ifndef SCOPE_DEBUG
+ if (yy > y2) yy = y2; else if (yy < y1) yy = y1;
+#endif
+ sprintf(chunkp, "%d %d ", (int)xx, (int)yy);
+ chunkp += strlen(chunkp);
+ xx += dx;
+ }
+ strcpy(chunkp, "\\\n");
+ sys_gui(chunk);
+ chunkp = chunk;
+ nleft -= SCOPE_GUICHUNKMONO;
+ }
+ while (nleft--)
+ {
+ yy = (y2 - 1) - sc * (*bp++ - x->x_minval);
+#ifndef SCOPE_DEBUG
+ if (yy > y2) yy = y2; else if (yy < y1) yy = y1;
+#endif
+ sprintf(chunkp, "%d %d ", (int)xx, (int)yy);
+ chunkp += strlen(chunkp);
+ xx += dx;
+ }
+ strcpy(chunkp, "\n");
+ sys_gui(chunk);
+}
+
+static void scope_drawxy(t_scope *x, t_canvas *cv)
+{
+ int x1, y1, x2, y2;
+ scope_getrect((t_gobj *)x, x->x_glist, &x1, &y1, &x2, &y2);
+ scope_drawbg(x, cv, x1, y1, x2, y2);
+ scope_drawfgxy(x, cv, x1, y1, x2, y2);
+}
+
+static void scope_redrawxy(t_scope *x, t_canvas *cv)
+{
+ int x1, y1, x2, y2;
+ scope_getrect((t_gobj *)x, x->x_glist, &x1, &y1, &x2, &y2);
+ sys_vgui(".x%x.c delete %s\n", cv, x->x_fgtag);
+ scope_drawfgxy(x, cv, x1, y1, x2, y2);
+}
+
+static void scope_revis(t_scope *x, t_canvas *cv)
+{
+ sys_vgui(".x%x.c delete %s\n", cv, x->x_tag);
+ if (x->x_xymode)
+ scope_drawxy(x, cv);
+ else
+ scope_drawmono(x, cv);
+}
+
+static void scope_vis(t_gobj *z, t_glist *glist, int vis)
+{
+ t_scope *x = (t_scope *)z;
+ t_text *t = (t_text *)z;
+ t_canvas *cv = scope_getcanvas(x, glist);
+ if (vis)
+ {
+ t_scopehandle *sh = (t_scopehandle *)x->x_handle;
+#ifndef PD_MINOR_VERSION
+ rtext_new(glist, t, glist->gl_editor->e_rtext, 0);
+#endif
+ sprintf(sh->h_pathname, ".x%x.h%x", (int)cv, (int)sh);
+ if (x->x_xymode)
+ scope_drawxy(x, cv);
+ else
+ scope_drawmono(x, cv);
+ }
+ else
+ {
+#ifndef PD_MINOR_VERSION
+ t_rtext *rt = glist_findrtext(glist, t);
+ if (rt) rtext_free(rt);
+#endif
+ sys_vgui(".x%x.c delete %s\n", cv, x->x_tag);
+ x->x_canvas = 0;
+ }
+}
+
+static int scope_click(t_gobj *z, t_glist *glist,
+ int xpix, int ypix, int shift, int alt, int dbl,
+ int doit)
+{
+ t_scope *x = (t_scope *)z;
+ x->x_frozen = doit;
+ return (CURSOR_RUNMODE_CLICKME);
+}
+
+/* CHECKED there is only one copy of state variables,
+ the same, whether modified with messages, or in the inspector */
+static void scope_save(t_gobj *z, t_binbuf *b)
+{
+ t_scope *x = (t_scope *)z;
+ t_text *t = (t_text *)x;
+ binbuf_addv(b, "ssiisiiiiiffififiiiiiii;", gensym("#X"), gensym("obj"),
+ (int)t->te_xpix, (int)t->te_ypix,
+ gensym("Scope~"),
+ x->x_width, x->x_height, x->x_period, 3, x->x_bufsize,
+ x->x_minval, x->x_maxval, x->x_delay, 0.,
+ x->x_trigmode, x->x_triglevel,
+ x->x_fgred, x->x_fggreen, x->x_fgblue,
+ x->x_bgred, x->x_bggreen, x->x_bgblue, 0);
+}
+
+static t_widgetbehavior scope_widgetbehavior =
+{
+ scope_getrect,
+ scope_displace,
+ scope_select,
+ 0,
+ scope_delete,
+ scope_vis,
+ scope_click,
+ scope_save,
+ 0
+};
+
+static void scope_setxymode(t_scope *x, int xymode)
+{
+ if (xymode != x->x_xymode)
+ {
+ t_canvas *cv;
+ if (cv = scope_isvisible(x))
+ {
+ sys_vgui(".x%x.c delete %s\n", cv, x->x_fgtag);
+ if (!xymode)
+ {
+ int x1, y1, x2, y2;
+ scope_getrect((t_gobj *)x, x->x_glist, &x1, &y1, &x2, &y2);
+ scope_drawfgmono(x, cv, x1, y1, x2, y2);
+ }
+ }
+ x->x_xymode = xymode;
+ scope_clear(x, 0);
+ }
+}
+
+static void scope_tick(t_scope *x)
+{
+ t_canvas *cv;
+ if (!x->x_frozen && (cv = scope_isvisible(x)))
+ {
+ if (x->x_xymode)
+ scope_redrawxy(x, cv);
+ else
+ scope_redrawmono(x, cv);
+ }
+ scope_clear(x, 1);
+}
+
+static void scopehandle__clickhook(t_scopehandle *sh, t_floatarg f)
+{
+ int newstate = (int)f;
+ if (sh->h_dragon && newstate == 0)
+ {
+ t_scope *x = sh->h_master;
+ t_canvas *cv;
+ x->x_width += sh->h_dragx;
+ x->x_height += sh->h_dragy;
+ if (cv = scope_isvisible(x))
+ {
+ sys_vgui(".x%x.c delete %s\n", cv, sh->h_outlinetag);
+ scope_revis(x, cv);
+ sys_vgui("destroy %s\n", sh->h_pathname);
+ scope_select((t_gobj *)x, x->x_glist, 1);
+ canvas_fixlinesfor(x->x_glist, (t_text *)x); /* 2nd inlet */
+ }
+ }
+ else if (!sh->h_dragon && newstate)
+ {
+ t_scope *x = sh->h_master;
+ t_canvas *cv;
+ if (cv = scope_isvisible(x))
+ {
+ int x1, y1, x2, y2;
+ scope_getrect((t_gobj *)x, x->x_glist, &x1, &y1, &x2, &y2);
+ sys_vgui("lower %s\n", sh->h_pathname);
+ sys_vgui(".x%x.c create rectangle %d %d %d %d\
+ -outline blue -width %f -tags %s\n",
+ cv, x1, y1, x2, y2, SCOPE_SELBDWIDTH, sh->h_outlinetag);
+ }
+ sh->h_dragx = 0;
+ sh->h_dragy = 0;
+ }
+ sh->h_dragon = newstate;
+}
+
+static void scopehandle__motionhook(t_scopehandle *sh,
+ t_floatarg f1, t_floatarg f2)
+{
+ if (sh->h_dragon)
+ {
+ t_scope *x = sh->h_master;
+ int dx = (int)f1, dy = (int)f2;
+ int x1, y1, x2, y2, newx, newy;
+ scope_getrect((t_gobj *)x, x->x_glist, &x1, &y1, &x2, &y2);
+ newx = x2 + dx;
+ newy = y2 + dy;
+ if (newx > x1 + SCOPE_MINWIDTH && newy > y1 + SCOPE_MINHEIGHT)
+ {
+ t_canvas *cv;
+ if (cv = scope_isvisible(x))
+ sys_vgui(".x%x.c coords %s %d %d %d %d\n",
+ cv, sh->h_outlinetag, x1, y1, newx, newy);
+ sh->h_dragx = dx;
+ sh->h_dragy = dy;
+ }
+ }
+}
+
+static void scope_free(t_scope *x)
+{
+ if (x->x_clock) clock_free(x->x_clock);
+ if (x->x_xbuffer != x->x_xbufini)
+ freebytes(x->x_xbuffer, x->x_allocsize * sizeof(*x->x_xbuffer));
+ if (x->x_ybuffer != x->x_ybufini)
+ freebytes(x->x_ybuffer, x->x_allocsize * sizeof(*x->x_ybuffer));
+ if (x->x_handle)
+ {
+ pd_unbind(x->x_handle, ((t_scopehandle *)x->x_handle)->h_bindsym);
+ pd_free(x->x_handle);
+ }
+}
+
+static void *scope_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_scope *x = (t_scope *)pd_new(scope_class);
+ t_scopehandle *sh;
+ t_float width = SCOPE_DEFWIDTH;
+ t_float height = SCOPE_DEFHEIGHT;
+ char buf[64];
+ x->x_glist = canvas_getcurrent();
+ x->x_canvas = 0;
+ loud_floatarg(*(t_pd *)x, 0, ac, av, &width,
+ SCOPE_MINWIDTH, 0,
+ LOUD_CLIP | LOUD_WARN, 0, "width");
+ x->x_width = (int)width;
+ loud_floatarg(*(t_pd *)x, 1, ac, av, &height,
+ SCOPE_MINHEIGHT, 0,
+ LOUD_CLIP | LOUD_WARN, 0, "height");
+ x->x_height = (int)height;
+ scope_period(x, 0, ac, av);
+ /* CHECKME 6th argument (default 3 for mono, 1 for xy */
+ scope_bufsize(x, 0, ac, av);
+ scope_range(x, 0, ac, av);
+ scope_delay(x, 0, ac, av);
+ /* CHECKME 11th argument (default 0.) */
+ scope_trigger(x, 0, ac, av);
+ scope_triglevel(x, 0, ac, av);
+ scope_frgb(x, 0, ac, av);
+ scope_brgb(x, 0, ac, av);
+ /* CHECKME last argument (default 0) */
+
+ sprintf(x->x_tag, "all%x", (int)x);
+ sprintf(x->x_bgtag, "bg%x", (int)x);
+ sprintf(x->x_gridtag, "gr%x", (int)x);
+ sprintf(x->x_fgtag, "fg%x", (int)x);
+ x->x_xymode = 0;
+ x->x_ksr = sys_getsr() * 0.001; /* redundant */
+ x->x_frozen = 0;
+ inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal);
+ x->x_clock = clock_new(x, (t_method)scope_tick);
+ scope_clear(x, 0);
+
+ x->x_handle = pd_new(scopehandle_class);
+ sh = (t_scopehandle *)x->x_handle;
+ sh->h_master = x;
+ sprintf(buf, "_h%x", (int)sh);
+ pd_bind(x->x_handle, sh->h_bindsym = gensym(buf));
+ sprintf(sh->h_outlinetag, "h%x", (int)sh);
+ sh->h_dragon = 0;
+ return (x);
+}
+
+void Scope_tilde_setup(void)
+{
+ scope_class = class_new(gensym("Scope~"),
+ (t_newmethod)scope_new,
+ (t_method)scope_free,
+ sizeof(t_scope), 0, A_GIMME, 0);
+ sic_setup(scope_class, scope_dsp, scope_float);
+ class_addmethod(scope_class, (t_method)scope_bufsize,
+ gensym("bufsize"), A_GIMME, 0);
+ class_addmethod(scope_class, (t_method)scope_range,
+ gensym("range"), A_GIMME, 0);
+ class_addmethod(scope_class, (t_method)scope_delay,
+ gensym("delay"), A_GIMME, 0);
+ class_addmethod(scope_class, (t_method)scope_trigger,
+ gensym("trigger"), A_GIMME, 0);
+ class_addmethod(scope_class, (t_method)scope_triglevel,
+ gensym("triglevel"), A_GIMME, 0);
+ class_addmethod(scope_class, (t_method)scope_frgb,
+ gensym("frgb"), A_GIMME, 0);
+ class_addmethod(scope_class, (t_method)scope_brgb,
+ gensym("brgb"), A_GIMME, 0);
+ class_addmethod(scope_class, (t_method)scope_click,
+ gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_setwidget(scope_class, &scope_widgetbehavior);
+ scopehandle_class = class_new(gensym("_scopehandle"), 0, 0,
+ sizeof(t_scopehandle), CLASS_PD, 0);
+ class_addmethod(scopehandle_class, (t_method)scopehandle__clickhook,
+ gensym("_click"), A_FLOAT, 0);
+ class_addmethod(scopehandle_class, (t_method)scopehandle__motionhook,
+ gensym("_motion"), A_FLOAT, A_FLOAT, 0);
+}
diff --git a/cyclone/sickle/Snapshot.c b/cyclone/sickle/Snapshot.c
new file mode 100644
index 0000000..7c7e974
--- /dev/null
+++ b/cyclone/sickle/Snapshot.c
@@ -0,0 +1,161 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+/* CHECKME for a fixed minimum deltime, if any (5ms for c74's metro) */
+
+typedef struct _snapshot
+{
+ t_sic x_sic;
+ t_float x_value;
+ int x_rqoffset; /* requested */
+ int x_offset; /* effective (truncated) */
+ int x_stopped;
+ int x_on; /* !stopped && deltime > 0 */
+ float x_deltime;
+ int x_npoints;
+ int x_nleft;
+ int x_nblock;
+ float x_ksr;
+ t_clock *x_clock;
+} t_snapshot;
+
+static t_class *snapshot_class;
+
+static void snapshot_tick(t_snapshot *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+}
+
+static void snapshot_bang(t_snapshot *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+}
+
+static void snapshot_correct(t_snapshot *x)
+{
+ int wason = x->x_on;
+ x->x_offset =
+ (x->x_rqoffset < x->x_nblock ? x->x_rqoffset : x->x_nblock - 1);
+ x->x_npoints = x->x_deltime * x->x_ksr - x->x_nblock + x->x_offset;
+ if (x->x_on = (!x->x_stopped && x->x_deltime > 0.))
+ {
+ if (!wason) x->x_nleft = x->x_offset; /* CHECKME */
+ }
+ else if (wason) clock_unset(x->x_clock);
+}
+
+static void snapshot_start(t_snapshot *x)
+{
+ x->x_stopped = 0;
+ if (!x->x_on && x->x_deltime > 0.) /* CHECKED no default */
+ {
+ x->x_nleft = x->x_offset; /* CHECKME */
+ x->x_on = 1;
+ }
+}
+
+static void snapshot_stop(t_snapshot *x)
+{
+ x->x_stopped = 1;
+ if (x->x_on)
+ {
+ clock_unset(x->x_clock);
+ x->x_on = 0;
+ }
+}
+
+static void snapshot_float(t_snapshot *x, t_float f)
+{
+ /* CHECKED nonzero/zero, CHECKED incompatible: int only (float ignored) */
+ if (f != 0.)
+ snapshot_start(x);
+ else
+ snapshot_stop(x);
+}
+
+static void snapshot_ft1(t_snapshot *x, t_floatarg f)
+{
+ x->x_deltime = (f > 0. ? f : 0.); /* CHECKED */
+ /* CHECKED setting deltime to a positive value starts the clock
+ only if it was stopped by setting deltime to zero */
+ snapshot_correct(x);
+}
+
+static void snapshot_offset(t_snapshot *x, t_floatarg f)
+{
+ int i = (int)f; /* CHECKME */
+ x->x_rqoffset = (i >= 0 ? i : 0); /* CHECKME */
+ /* CHECKME if the change has an effect prior to next dsp_add call */
+ snapshot_correct(x);
+}
+
+static t_int *snapshot_perform(t_int *w)
+{
+ t_snapshot *x = (t_snapshot *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ x->x_value = in[x->x_offset];
+ if (x->x_on)
+ {
+ /* CHECKME nleft vs offset */
+ if (x->x_nleft < x->x_nblock)
+ {
+ clock_delay(x->x_clock, 0);
+ x->x_nleft = x->x_npoints;
+ }
+ else x->x_nleft -= x->x_nblock;
+ }
+ return (w + 3);
+}
+
+static void snapshot_dsp(t_snapshot *x, t_signal **sp)
+{
+ x->x_nblock = sp[0]->s_n;
+ x->x_ksr = sp[0]->s_sr * 0.001;
+ snapshot_correct(x);
+ x->x_nleft = x->x_offset; /* CHECKME */
+ dsp_add(snapshot_perform, 2, x, sp[0]->s_vec);
+}
+
+static void snapshot_free(t_snapshot *x)
+{
+ if (x->x_clock) clock_free(x->x_clock);
+}
+
+static void *snapshot_new(t_floatarg f1, t_floatarg f2)
+{
+ t_snapshot *x = (t_snapshot *)pd_new(snapshot_class);
+ x->x_stopped = 0; /* CHECKED */
+ x->x_on = 0;
+ x->x_value = 0;
+ x->x_nblock = 64; /* redundant */
+ x->x_ksr = 44.1; /* redundant */
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_float);
+ x->x_clock = clock_new(x, (t_method)snapshot_tick);
+ snapshot_offset(x, f2); /* CHECKME (this is fixed at nblock-1 in Pd) */
+ snapshot_ft1(x, f1);
+ return (x);
+}
+
+void Snapshot_tilde_setup(void)
+{
+ snapshot_class = class_new(gensym("Snapshot~"),
+ (t_newmethod)snapshot_new,
+ (t_method)snapshot_free,
+ sizeof(t_snapshot), 0,
+ A_DEFFLOAT, A_DEFFLOAT, 0);
+ sic_setup(snapshot_class, snapshot_dsp, snapshot_float);
+ class_addbang(snapshot_class, snapshot_bang);
+ class_addmethod(snapshot_class, (t_method)snapshot_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(snapshot_class, (t_method)snapshot_offset,
+ gensym("offset"), A_FLOAT, 0);
+ class_addmethod(snapshot_class, (t_method)snapshot_start,
+ gensym("start"), 0);
+ class_addmethod(snapshot_class, (t_method)snapshot_stop,
+ gensym("stop"), 0);
+}
diff --git a/cyclone/sickle/abs.c b/cyclone/sickle/abs.c
new file mode 100644
index 0000000..cde26a5
--- /dev/null
+++ b/cyclone/sickle/abs.c
@@ -0,0 +1,42 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+typedef t_sic t_abs;
+static t_class *abs_class;
+
+static t_int *abs_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ while (nblock--)
+ {
+ float f = *in++;
+ *out++ = (f >= 0 ? f : -f);
+ }
+ return (w + 4);
+}
+
+static void abs_dsp(t_abs *x, t_signal **sp)
+{
+ dsp_add(abs_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void *abs_new(void)
+{
+ t_abs *x = (t_abs *)pd_new(abs_class);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void abs_tilde_setup(void)
+{
+ abs_class = class_new(gensym("abs~"),
+ (t_newmethod)abs_new, 0,
+ sizeof(t_abs), 0, 0);
+ sic_setup(abs_class, abs_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/acos.c b/cyclone/sickle/acos.c
new file mode 100644
index 0000000..1dd5719
--- /dev/null
+++ b/cyclone/sickle/acos.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define acosf acos
+#endif
+
+typedef t_sic t_acos;
+static t_class *acos_class;
+
+static t_int *acos_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ while (nblock--)
+ {
+ float f = *in++;
+ *out++ = acosf(f); /* CHECKED no protection against NaNs */
+ }
+ return (w + 4);
+}
+
+static void acos_dsp(t_acos *x, t_signal **sp)
+{
+ dsp_add(acos_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void *acos_new(void)
+{
+ t_acos *x = (t_acos *)pd_new(acos_class);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void acos_tilde_setup(void)
+{
+ acos_class = class_new(gensym("acos~"),
+ (t_newmethod)acos_new, 0,
+ sizeof(t_acos), 0, 0);
+ sic_setup(acos_class, acos_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/acosh.c b/cyclone/sickle/acosh.c
new file mode 100644
index 0000000..392ad97
--- /dev/null
+++ b/cyclone/sickle/acosh.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+/* LATER ask about osx */
+#if defined(NT) || defined(MACOSX)
+#define acoshf(x) (log(x + sqrt(x * x - 1)))
+#endif
+
+typedef t_sic t_acosh;
+static t_class *acosh_class;
+
+static t_int *acosh_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ while (nblock--)
+ {
+ float f = *in++;
+ *out++ = acoshf(f); /* CHECKME no protection against NaNs */
+ }
+ return (w + 4);
+}
+
+static void acosh_dsp(t_acosh *x, t_signal **sp)
+{
+ dsp_add(acosh_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void *acosh_new(void)
+{
+ t_acosh *x = (t_acosh *)pd_new(acosh_class);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void acosh_tilde_setup(void)
+{
+ acosh_class = class_new(gensym("acosh~"),
+ (t_newmethod)acosh_new, 0,
+ sizeof(t_acosh), 0, 0);
+ sic_setup(acosh_class, acosh_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/allpass.c b/cyclone/sickle/allpass.c
new file mode 100644
index 0000000..761d0cc
--- /dev/null
+++ b/cyclone/sickle/allpass.c
@@ -0,0 +1,153 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+typedef struct _allpass
+{
+ t_sic x_sic;
+ float x_sr;
+ float x_ksr;
+ t_float *x_buf;
+ int x_bufsize; /* as allocated */
+ int x_maxsize; /* as used */
+ float x_maxdelay; /* same in ms */
+ int x_phase; /* writing head */
+} t_allpass;
+
+static t_class *allpass_class;
+
+/* maximum delay defaults to 50 ms (cycling has 10 ms here) */
+#define ALLPASS_DEFMAXDELAY 50.0
+
+/* LATER choose the best way (compare with comb~) */
+#define ALLPASS_MAXFEEDBACK 0.999
+
+static void allpass_clear(t_allpass *x)
+{
+ memset(x->x_buf, 0, x->x_maxsize * sizeof(*x->x_buf));
+ x->x_phase = 0;
+}
+
+static void allpass_resize(t_allpass *x, int newsize)
+{
+ if (newsize > 0 && newsize != x->x_maxsize)
+ {
+ if (newsize > x->x_bufsize)
+ {
+ x->x_buf = resizebytes(x->x_buf,
+ x->x_bufsize * sizeof(*x->x_buf),
+ newsize * sizeof(*x->x_buf));
+ /* LATER test for failure */
+ x->x_bufsize = newsize;
+ }
+ x->x_maxsize = newsize;
+ }
+ allpass_clear(x);
+}
+
+static t_int *allpass_perform(t_int *w)
+{
+ t_allpass *x = (t_allpass *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *xin = (t_float *)(w[3]);
+ t_float *din = (t_float *)(w[4]);
+ t_float *gin = (t_float *)(w[5]);
+ t_float *out = (t_float *)(w[6]);
+ t_float *buf = x->x_buf;
+ int maxsize = x->x_maxsize;
+ int guardpoint = maxsize - 1;
+ float ksr = x->x_ksr;
+ int wph = x->x_phase;
+ while (nblock--)
+ { /* TDFII scheme */
+ float xn = *xin++;
+ float delsize = ksr * *din++;
+ float gain = *gin++;
+ float yn;
+ float rph; /* reading head */
+ if (gain < -ALLPASS_MAXFEEDBACK) gain = -ALLPASS_MAXFEEDBACK;
+ else if (gain > ALLPASS_MAXFEEDBACK) gain = ALLPASS_MAXFEEDBACK;
+ yn = -gain * xn;
+ if (delsize > 0)
+ {
+ int ndx;
+ float val;
+ rph = wph - (delsize > guardpoint ? guardpoint : delsize);
+ if (rph < 0) rph += guardpoint;
+ ndx = (int)rph;
+ val = buf[ndx];
+ /* ``a cheezy linear interpolation'' ala msp,
+ (vd~ uses 4-point interpolation...) */
+ yn += val + (buf[ndx+1] - val) * (rph - ndx);
+ }
+ *out++ = yn;
+ if (wph == guardpoint)
+ {
+ buf[wph] = *buf = xn + gain * yn;
+ wph = 1;
+ }
+ else buf[wph++] = xn + gain * yn;
+ }
+ x->x_phase = wph;
+ return (w + 7);
+}
+
+static void allpass_dsp(t_allpass *x, t_signal **sp)
+{
+ float sr = sp[0]->s_sr;
+ if (sr != x->x_sr)
+ {
+ x->x_sr = sr;
+ x->x_ksr = sr * 0.001;
+ allpass_resize(x, x->x_ksr * x->x_maxdelay);
+ }
+ else allpass_clear(x);
+ dsp_add(allpass_perform, 6, x, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec);
+}
+
+static void *allpass_new(t_floatarg f1, t_floatarg f2, t_floatarg f3)
+{
+ t_allpass *x;
+ float maxdelay = (f1 > 0 ? f1 : ALLPASS_DEFMAXDELAY);
+ float sr = sys_getsr();
+ float ksr = sr * 0.001;
+ int bufsize = ksr * maxdelay;
+ t_float *buf = (t_float *)getbytes(bufsize * sizeof(*buf));
+ if (!buf)
+ return (0);
+ x = (t_allpass *)pd_new(allpass_class);
+ x->x_maxdelay = maxdelay;
+ x->x_sr = sr;
+ x->x_ksr = ksr;
+ x->x_bufsize = x->x_maxsize = bufsize;
+ x->x_buf = buf;
+ if (f2 < 0) f2 = 0;
+ if (f3 < -ALLPASS_MAXFEEDBACK) f3 = -ALLPASS_MAXFEEDBACK;
+ else if (f3 > ALLPASS_MAXFEEDBACK) f3 = ALLPASS_MAXFEEDBACK;
+ sic_newinlet((t_sic *)x, f2);
+ sic_newinlet((t_sic *)x, f3);
+ outlet_new((t_object *)x, &s_signal);
+ allpass_clear(x);
+ return (x);
+}
+
+static void allpass_free(t_allpass *x)
+{
+ if (x->x_buf) freebytes(x->x_buf, x->x_bufsize * sizeof(*x->x_buf));
+}
+
+void allpass_tilde_setup(void)
+{
+ allpass_class = class_new(gensym("allpass~"),
+ (t_newmethod)allpass_new,
+ (t_method)allpass_free,
+ sizeof(t_allpass), 0,
+ A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ sic_setup(allpass_class, allpass_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(allpass_class, (t_method)allpass_clear, gensym("clear"), 0);
+}
diff --git a/cyclone/sickle/allsickles.c b/cyclone/sickle/allsickles.c
new file mode 100644
index 0000000..624a48d
--- /dev/null
+++ b/cyclone/sickle/allsickles.c
@@ -0,0 +1,134 @@
+// Do not edit this file, run "make" instead.
+
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+void Clip_tilde_setup(void);
+void Line_tilde_setup(void);
+void Scope_tilde_setup(void);
+void Snapshot_tilde_setup(void);
+void abs_tilde_setup(void);
+void acos_tilde_setup(void);
+void acosh_tilde_setup(void);
+void allpass_tilde_setup(void);
+void asin_tilde_setup(void);
+void asinh_tilde_setup(void);
+void atan_tilde_setup(void);
+void atan2_tilde_setup(void);
+void atanh_tilde_setup(void);
+void average_tilde_setup(void);
+void avg_tilde_setup(void);
+void bitand_tilde_setup(void);
+void bitnot_tilde_setup(void);
+void bitor_tilde_setup(void);
+void bitshift_tilde_setup(void);
+void bitxor_tilde_setup(void);
+void capture_tilde_setup(void);
+void cartopol_tilde_setup(void);
+void change_tilde_setup(void);
+void click_tilde_setup(void);
+void comb_tilde_setup(void);
+void cosh_tilde_setup(void);
+void cosx_tilde_setup(void);
+void count_tilde_setup(void);
+void cycle_tilde_setup(void);
+void delay_tilde_setup(void);
+void delta_tilde_setup(void);
+void deltaclip_tilde_setup(void);
+void edge_tilde_setup(void);
+void frameaccum_tilde_setup(void);
+void framedelta_tilde_setup(void);
+void index_tilde_setup(void);
+void kink_tilde_setup(void);
+void linedrive_setup(void);
+void log_tilde_setup(void);
+void lookup_tilde_setup(void);
+void minmax_tilde_setup(void);
+void peakamp_tilde_setup(void);
+void peek_tilde_setup(void);
+void phasewrap_tilde_setup(void);
+void play_tilde_setup(void);
+void poltocar_tilde_setup(void);
+void pow_tilde_setup(void);
+void rampsmooth_tilde_setup(void);
+void rand_tilde_setup(void);
+void record_tilde_setup(void);
+void sah_tilde_setup(void);
+void sinh_tilde_setup(void);
+void sinx_tilde_setup(void);
+void slide_tilde_setup(void);
+void spike_tilde_setup(void);
+void tanh_tilde_setup(void);
+void tanx_tilde_setup(void);
+void train_tilde_setup(void);
+void trapezoid_tilde_setup(void);
+void triangle_tilde_setup(void);
+void vectral_tilde_setup(void);
+void wave_tilde_setup(void);
+
+void allsickles_setup(void)
+{
+ Clip_tilde_setup();
+ Line_tilde_setup();
+ Scope_tilde_setup();
+ Snapshot_tilde_setup();
+ abs_tilde_setup();
+ acos_tilde_setup();
+ acosh_tilde_setup();
+ allpass_tilde_setup();
+ asin_tilde_setup();
+ asinh_tilde_setup();
+ atan_tilde_setup();
+ atan2_tilde_setup();
+ atanh_tilde_setup();
+ average_tilde_setup();
+ avg_tilde_setup();
+ bitand_tilde_setup();
+ bitnot_tilde_setup();
+ bitor_tilde_setup();
+ bitshift_tilde_setup();
+ bitxor_tilde_setup();
+ capture_tilde_setup();
+ cartopol_tilde_setup();
+ change_tilde_setup();
+ click_tilde_setup();
+ comb_tilde_setup();
+ cosh_tilde_setup();
+ cosx_tilde_setup();
+ count_tilde_setup();
+ cycle_tilde_setup();
+ delay_tilde_setup();
+ delta_tilde_setup();
+ deltaclip_tilde_setup();
+ edge_tilde_setup();
+ frameaccum_tilde_setup();
+ framedelta_tilde_setup();
+ index_tilde_setup();
+ kink_tilde_setup();
+ linedrive_setup();
+ log_tilde_setup();
+ lookup_tilde_setup();
+ minmax_tilde_setup();
+ peakamp_tilde_setup();
+ peek_tilde_setup();
+ phasewrap_tilde_setup();
+ play_tilde_setup();
+ poltocar_tilde_setup();
+ pow_tilde_setup();
+ rampsmooth_tilde_setup();
+ rand_tilde_setup();
+ record_tilde_setup();
+ sah_tilde_setup();
+ sinh_tilde_setup();
+ sinx_tilde_setup();
+ slide_tilde_setup();
+ spike_tilde_setup();
+ tanh_tilde_setup();
+ tanx_tilde_setup();
+ train_tilde_setup();
+ trapezoid_tilde_setup();
+ triangle_tilde_setup();
+ vectral_tilde_setup();
+ wave_tilde_setup();
+}
diff --git a/cyclone/sickle/asin.c b/cyclone/sickle/asin.c
new file mode 100644
index 0000000..05e5c28
--- /dev/null
+++ b/cyclone/sickle/asin.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define asinf asin
+#endif
+
+typedef t_sic t_asin;
+static t_class *asin_class;
+
+static t_int *asin_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ while (nblock--)
+ {
+ float f = *in++;
+ *out++ = asinf(f); /* CHECKME no protection against NaNs */
+ }
+ return (w + 4);
+}
+
+static void asin_dsp(t_asin *x, t_signal **sp)
+{
+ dsp_add(asin_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void *asin_new(void)
+{
+ t_asin *x = (t_asin *)pd_new(asin_class);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void asin_tilde_setup(void)
+{
+ asin_class = class_new(gensym("asin~"),
+ (t_newmethod)asin_new, 0,
+ sizeof(t_asin), 0, 0);
+ sic_setup(asin_class, asin_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/asinh.c b/cyclone/sickle/asinh.c
new file mode 100644
index 0000000..931cb1f
--- /dev/null
+++ b/cyclone/sickle/asinh.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+/* LATER ask about osx */
+#if defined(NT) || defined(MACOSX)
+#define asinhf(x) (log(x + sqrt(x * x + 1)))
+#endif
+
+typedef t_sic t_asinh;
+static t_class *asinh_class;
+
+static t_int *asinh_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ while (nblock--)
+ {
+ float f = *in++;
+ *out++ = asinhf(f); /* CHECKME no protection against NaNs */
+ }
+ return (w + 4);
+}
+
+static void asinh_dsp(t_asinh *x, t_signal **sp)
+{
+ dsp_add(asinh_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void *asinh_new(void)
+{
+ t_asinh *x = (t_asinh *)pd_new(asinh_class);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void asinh_tilde_setup(void)
+{
+ asinh_class = class_new(gensym("asinh~"),
+ (t_newmethod)asinh_new, 0,
+ sizeof(t_asinh), 0, 0);
+ sic_setup(asinh_class, asinh_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/atan.c b/cyclone/sickle/atan.c
new file mode 100644
index 0000000..f541fa4
--- /dev/null
+++ b/cyclone/sickle/atan.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define atanf atan
+#endif
+
+typedef t_sic t_atan;
+static t_class *atan_class;
+
+static t_int *atan_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ while (nblock--)
+ {
+ float f = *in++;
+ *out++ = atanf(f); /* CHECKME no protection against NaNs */
+ }
+ return (w + 4);
+}
+
+static void atan_dsp(t_atan *x, t_signal **sp)
+{
+ dsp_add(atan_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void *atan_new(void)
+{
+ t_atan *x = (t_atan *)pd_new(atan_class);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void atan_tilde_setup(void)
+{
+ atan_class = class_new(gensym("atan~"),
+ (t_newmethod)atan_new, 0,
+ sizeof(t_atan), 0, 0);
+ sic_setup(atan_class, atan_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/atan2.c b/cyclone/sickle/atan2.c
new file mode 100644
index 0000000..171fc17
--- /dev/null
+++ b/cyclone/sickle/atan2.c
@@ -0,0 +1,53 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define atan2f atan2
+#endif
+
+typedef t_sic t_atan2;
+static t_class *atan2_class;
+
+static t_int *atan2_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ while (nblock--)
+ {
+ float f1 = *in1++;
+ float f2 = *in2++;
+ /* CHECKED arg order, range (radians) */
+ *out++ = atan2f(f1, f2);
+ }
+ return (w + 5);
+}
+
+static void atan2_dsp(t_atan2 *x, t_signal **sp)
+{
+ dsp_add(atan2_perform, 4, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+}
+
+static void *atan2_new(t_floatarg f)
+{
+ t_atan2 *x = (t_atan2 *)pd_new(atan2_class);
+ sic_newinlet((t_sic *)x, f); /* CHECKED x-value argument */
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void atan2_tilde_setup(void)
+{
+ atan2_class = class_new(gensym("atan2~"),
+ (t_newmethod)atan2_new, 0,
+ sizeof(t_atan2), 0, A_DEFFLOAT, 0);
+ sic_setup(atan2_class, atan2_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/atanh.c b/cyclone/sickle/atanh.c
new file mode 100644
index 0000000..464f955
--- /dev/null
+++ b/cyclone/sickle/atanh.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+/* LATER ask about osx */
+#if defined(NT) || defined(MACOSX)
+#define atanhf(x) (log((1 + x) / (1 - x)) * 0.5)
+#endif
+
+typedef t_sic t_atanh;
+static t_class *atanh_class;
+
+static t_int *atanh_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ while (nblock--)
+ {
+ float f = *in++;
+ *out++ = atanhf(f); /* CHECKME no protection against NaNs */
+ }
+ return (w + 4);
+}
+
+static void atanh_dsp(t_atanh *x, t_signal **sp)
+{
+ dsp_add(atanh_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void *atanh_new(void)
+{
+ t_atanh *x = (t_atanh *)pd_new(atanh_class);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void atanh_tilde_setup(void)
+{
+ atanh_class = class_new(gensym("atanh~"),
+ (t_newmethod)atanh_new, 0,
+ sizeof(t_atanh), 0, 0);
+ sic_setup(atanh_class, atanh_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/average.c b/cyclone/sickle/average.c
new file mode 100644
index 0000000..ea330c1
--- /dev/null
+++ b/cyclone/sickle/average.c
@@ -0,0 +1,194 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* CHECKME no reset after changing of a window size? */
+/* CHECKME overlap */
+
+#include <math.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define sqrtf sqrt
+#endif
+
+#define AVERAGE_DEFNPOINTS 100 /* CHECKME */
+#define AVERAGE_DEFMODE AVERAGE_BIPOLAR
+enum { AVERAGE_BIPOLAR, AVERAGE_ABSOLUTE, AVERAGE_RMS };
+
+typedef struct _average
+{
+ t_sic x_sic;
+ int x_mode;
+ float (*x_sumfn)(t_float*, int, float);
+ int x_phase;
+ int x_npoints;
+ float x_result;
+ float x_accum;
+ t_clock *x_clock;
+} t_average;
+
+static t_class *average_class;
+
+static void average_tick(t_average *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_result);
+}
+
+static float average_bipolarsum(t_float *in, int nxfer, float accum)
+{
+ while (nxfer--)
+ accum += *in++;
+ return (accum);
+}
+
+static float average_absolutesum(t_float *in, int nxfer, float accum)
+{
+ while (nxfer--)
+ {
+ float f = *in++;
+ accum += (f >= 0 ? f : -f);
+ }
+ return (accum);
+}
+
+static float average_rmssum(t_float *in, int nxfer, float accum)
+{
+ while (nxfer--)
+ {
+ float f = *in++;
+ accum += f * f;
+ }
+ return (accum);
+}
+
+static void average_setmode(t_average *x, int mode)
+{
+ if (mode == AVERAGE_BIPOLAR)
+ x->x_sumfn = average_bipolarsum;
+ else if (mode == AVERAGE_ABSOLUTE)
+ x->x_sumfn = average_absolutesum;
+ else if (mode == AVERAGE_RMS)
+ x->x_sumfn = average_rmssum;
+ else
+ {
+ bug("average_setmode");
+ return;
+ }
+ x->x_mode = mode;
+ x->x_phase = x->x_npoints;
+ x->x_accum = 0;
+}
+
+static void average_float(t_average *x, t_float f)
+{
+ int i = (int)f; /* CHECKME noninteger */
+ if (i > 0) /* CHECKME */
+ {
+ x->x_npoints = i;
+ x->x_phase = x->x_npoints;
+ x->x_accum = 0;
+ }
+}
+
+static void average_bipolar(t_average *x)
+{
+ average_setmode(x, AVERAGE_BIPOLAR);
+}
+
+static void average_absolute(t_average *x)
+{
+ average_setmode(x, AVERAGE_ABSOLUTE);
+}
+
+static void average_rms(t_average *x)
+{
+ average_setmode(x, AVERAGE_RMS);
+}
+
+static t_int *average_perform(t_int *w)
+{
+ t_average *x = (t_average *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ float (*sumfn)(t_float*, int, float) = x->x_sumfn;
+ int phase = x->x_phase;
+ if (phase <= nblock)
+ {
+ float accum = (*sumfn)(in, phase, x->x_accum);
+ nblock -= phase;
+ if (x->x_mode == AVERAGE_RMS)
+ /* CHECKME scaling and FIXME */
+ x->x_result = sqrtf(accum / x->x_npoints);
+ else
+ x->x_result = accum / x->x_npoints;
+ clock_delay(x->x_clock, 0);
+ x->x_accum = 0;
+ if (nblock < x->x_npoints)
+ x->x_phase = x->x_npoints - nblock;
+ else
+ {
+ x->x_phase = x->x_npoints;
+ return (w + 4);
+ }
+ }
+ else x->x_phase -= nblock;
+ x->x_accum = (*sumfn)(in, nblock, x->x_accum);
+ return (w + 4);
+}
+
+static void average_dsp(t_average *x, t_signal **sp)
+{
+ dsp_add(average_perform, 3, x, sp[0]->s_n, sp[0]->s_vec);
+}
+
+static void average_free(t_average *x)
+{
+ if (x->x_clock) clock_free(x->x_clock);
+}
+
+static void *average_new(t_symbol *s, t_floatarg f)
+{
+ t_average *x = (t_average *)pd_new(average_class);
+ int i = (int)f; /* CHECKME noninteger */
+ int mode;
+ /* CHECKED it looks like memory is allocated for the entire window,
+ in tune with the refman's note about ``maximum averaging interval'' --
+ needed for dynamic control over window size, or what? LATER rethink */
+ x->x_npoints = (i > 0 ? /* CHECKME */
+ i : AVERAGE_DEFNPOINTS);
+ if (s == gensym("bipolar"))
+ mode = AVERAGE_BIPOLAR;
+ else if (s == gensym("absolute"))
+ mode = AVERAGE_ABSOLUTE;
+ else if (s == gensym("rms"))
+ mode = AVERAGE_RMS;
+ else
+ {
+ mode = AVERAGE_DEFMODE;
+ /* CHECKME a warning if (s && s != &s_) */
+ }
+ average_setmode(x, mode);
+ /* CHECKME if not x->x_phase = 0 */
+ outlet_new((t_object *)x, &s_float);
+ x->x_clock = clock_new(x, (t_method)average_tick);
+ return (x);
+}
+
+void average_tilde_setup(void)
+{
+ average_class = class_new(gensym("average~"),
+ (t_newmethod)average_new,
+ (t_method)average_free,
+ sizeof(t_average), 0,
+ A_DEFFLOAT, A_DEFSYM, 0);
+ sic_setup(average_class, average_dsp, average_float);
+ class_addmethod(average_class, (t_method)average_bipolar,
+ gensym("bipolar"), 0);
+ class_addmethod(average_class, (t_method)average_absolute,
+ gensym("absolute"), 0);
+ class_addmethod(average_class, (t_method)average_rms,
+ gensym("rms"), 0);
+}
diff --git a/cyclone/sickle/avg.c b/cyclone/sickle/avg.c
new file mode 100644
index 0000000..2ad214a
--- /dev/null
+++ b/cyclone/sickle/avg.c
@@ -0,0 +1,62 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+typedef struct _avg
+{
+ t_sic x_sic;
+ float x_count;
+ float x_accum;
+} t_avg;
+
+static t_class *avg_class;
+
+static void avg_bang(t_avg *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet,
+ (x->x_count ? x->x_accum / x->x_count : 0));
+ x->x_count = 0;
+ x->x_accum = 0;
+}
+
+static t_int *avg_perform(t_int *w)
+{
+ t_avg *x = (t_avg *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ float accum = 0;
+ x->x_count += nblock; /* LATER consider blockcount++ */
+ while (nblock--)
+ {
+ float f = *in++;
+ accum += (f >= 0 ? f : -f);
+ }
+ x->x_accum += accum;
+ return (w + 4);
+}
+
+static void avg_dsp(t_avg *x, t_signal **sp)
+{
+ dsp_add(avg_perform, 3, x, sp[0]->s_n, sp[0]->s_vec);
+}
+
+static void *avg_new(void)
+{
+ t_avg *x = (t_avg *)pd_new(avg_class);
+ outlet_new((t_object *)x, &s_float);
+ x->x_count = 0;
+ x->x_accum = 0;
+ return (x);
+}
+
+void avg_tilde_setup(void)
+{
+ avg_class = class_new(gensym("avg~"),
+ (t_newmethod)avg_new, 0,
+ sizeof(t_avg), 0, 0);
+ sic_setup(avg_class, avg_dsp, SIC_FLOATTOSIGNAL);
+ class_addbang(avg_class, avg_bang);
+}
diff --git a/cyclone/sickle/bitand.c b/cyclone/sickle/bitand.c
new file mode 100644
index 0000000..a7cfeb7
--- /dev/null
+++ b/cyclone/sickle/bitand.c
@@ -0,0 +1,144 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* FIXME find a way of setting a 32-bit mask in an argument */
+
+#include "m_pd.h"
+#include "unstable/forky.h"
+#include "sickle/sic.h"
+
+typedef struct _bitand
+{
+ t_sic x_sic;
+ t_glist *x_glist;
+ t_int x_mask; /* set by a 'bits' message or a creation argument */
+ int x_mode;
+ int x_convert1;
+} t_bitand;
+
+static t_class *bitand_class;
+
+static t_int *bitand_perform(t_int *w)
+{
+ t_bitand *x = (t_bitand *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in1 = (t_float *)(w[3]);
+ t_float *in2 = (t_float *)(w[4]);
+ t_float *out = (t_float *)(w[5]);
+ t_int mask = x->x_mask;
+ switch (x->x_mode)
+ {
+ /* LATER think about performance */
+ case 0:
+ /* CHECKED */
+ while (nblock--)
+ {
+ t_int i = ((*(t_int *)(t_float *)in1++) &
+ (*(t_int *)(t_float *)in2++));
+ *out++ = *(t_float *)&i;
+ }
+ break;
+ case 1:
+ /* CHECKED */
+ while (nblock--)
+ {
+ t_int i = (((t_int)*in1++) &
+ ((t_int)*in2++));
+ *out++ = (t_float)i;
+ }
+ break;
+ case 2:
+ /* CHECKED */
+ while (nblock--)
+ {
+ t_int i = (*(t_int *)(t_float *)in1++) & ((t_int)*in2++);
+ *out++ = *(t_float *)&i;
+ }
+ break;
+ case 3:
+ /* CHECKED */
+ while (nblock--)
+ {
+ t_int i = ((t_int)*in1++) & (*(t_int *)(t_float *)in2++);
+ *out++ = (t_float)i;
+ }
+ break;
+ }
+ return (w + 6);
+}
+
+static t_int *bitand_perform_noin2(t_int *w)
+{
+ t_bitand *x = (t_bitand *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ t_int mask = x->x_mask;
+ /* LATER think about performance */
+ if (x->x_convert1) while (nblock--)
+ {
+ /* CHECKED */
+ t_int i = ((t_int)*in++) & mask;
+ *out++ = (t_float)i;
+ }
+ else while (nblock--)
+ {
+ /* CHECKED */
+ t_int i = (*(t_int *)(t_float *)in++) & mask;
+ *out++ = *(t_float *)&i;
+ }
+ return (w + 5);
+}
+
+static void bitand_dsp(t_bitand *x, t_signal **sp)
+{
+ if (forky_hasfeeders((t_object *)x, x->x_glist, 1, 0))
+ /* use the mask set by a second inlet's signal or float,
+ CHECKED (incompatible) second inlet's int is persistent */
+ dsp_add(bitand_perform, 5, x, sp[0]->s_n, sp[0]->s_vec,
+ sp[1]->s_vec, sp[2]->s_vec);
+ else /* use the mask set by a 'bits' message or a creation argument */
+ dsp_add(bitand_perform_noin2, 4, x, sp[0]->s_n, sp[0]->s_vec,
+ sp[1]->s_vec);
+}
+
+static void bitand_bits(t_bitand *x, t_symbol *s, int ac, t_atom *av)
+{
+ x->x_mask = forky_getbitmask(ac, av);
+}
+
+static void bitand_mode(t_bitand *x, t_floatarg f)
+{
+ int i = (int)f;
+ if (i < 0)
+ i = 0; /* CHECKED */
+ else if (i > 3)
+ i = 3; /* CHECKED */
+ x->x_mode = i;
+ x->x_convert1 = (x->x_mode == 1 || x->x_mode == 3);
+}
+
+static void *bitand_new(t_floatarg f1, t_floatarg f2)
+{
+ t_bitand *x = (t_bitand *)pd_new(bitand_class);
+ x->x_glist = canvas_getcurrent();
+ inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal);
+ outlet_new((t_object *)x, &s_signal);
+ x->x_mask = (t_int)f1; /* FIXME (how?) */
+ bitand_mode(x, f2);
+ return (x);
+}
+
+void bitand_tilde_setup(void)
+{
+ bitand_class = class_new(gensym("bitand~"),
+ (t_newmethod)bitand_new, 0,
+ sizeof(t_bitand), 0,
+ A_DEFFLOAT, A_DEFFLOAT, 0);
+ sic_setup(bitand_class, bitand_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(bitand_class, (t_method)bitand_bits,
+ gensym("bits"), A_GIMME, 0);
+ class_addmethod(bitand_class, (t_method)bitand_mode,
+ gensym("mode"), A_FLOAT, 0);
+}
diff --git a/cyclone/sickle/bitnot.c b/cyclone/sickle/bitnot.c
new file mode 100644
index 0000000..c2929e8
--- /dev/null
+++ b/cyclone/sickle/bitnot.c
@@ -0,0 +1,66 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+typedef struct _bitnot
+{
+ t_sic x_sic;
+ int x_convert1;
+} t_bitnot;
+
+static t_class *bitnot_class;
+
+static t_int *bitnot_perform(t_int *w)
+{
+ t_bitnot *x = (t_bitnot *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ /* LATER think about performance */
+ if (x->x_convert1) while (nblock--)
+ {
+ /* CHECKME */
+ t_int i = ~((t_int)*in++);
+ *out++ = (t_float)i;
+ }
+ else while (nblock--)
+ {
+ /* CHECKME */
+ t_int i = ~(*(t_int *)(t_float *)in++);
+ *out++ = *(t_float *)&i;
+ }
+ return (w + 5);
+}
+
+static void bitnot_dsp(t_bitnot *x, t_signal **sp)
+{
+ dsp_add(bitnot_perform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void bitnot_mode(t_bitnot *x, t_floatarg f)
+{
+ int i = (int)f;
+ x->x_convert1 = (i > 0); /* CHECKME */
+}
+
+static void *bitnot_new(t_floatarg f)
+{
+ t_bitnot *x = (t_bitnot *)pd_new(bitnot_class);
+ outlet_new((t_object *)x, &s_signal);
+ bitnot_mode(x, f);
+ return (x);
+}
+
+void bitnot_tilde_setup(void)
+{
+ bitnot_class = class_new(gensym("bitnot~"),
+ (t_newmethod)bitnot_new, 0,
+ sizeof(t_bitnot), 0,
+ A_DEFFLOAT, 0);
+ sic_setup(bitnot_class, bitnot_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(bitnot_class, (t_method)bitnot_mode,
+ gensym("mode"), A_FLOAT, 0);
+}
diff --git a/cyclone/sickle/bitor.c b/cyclone/sickle/bitor.c
new file mode 100644
index 0000000..e5c887b
--- /dev/null
+++ b/cyclone/sickle/bitor.c
@@ -0,0 +1,144 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* FIXME find a way of setting a 32-bit mask in an argument */
+
+#include "m_pd.h"
+#include "unstable/forky.h"
+#include "sickle/sic.h"
+
+typedef struct _bitor
+{
+ t_sic x_sic;
+ t_glist *x_glist;
+ t_int x_mask; /* set by a 'bits' message or a creation argument */
+ int x_mode;
+ int x_convert1;
+} t_bitor;
+
+static t_class *bitor_class;
+
+static t_int *bitor_perform(t_int *w)
+{
+ t_bitor *x = (t_bitor *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in1 = (t_float *)(w[3]);
+ t_float *in2 = (t_float *)(w[4]);
+ t_float *out = (t_float *)(w[5]);
+ t_int mask = x->x_mask;
+ switch (x->x_mode)
+ {
+ /* LATER think about performance */
+ case 0:
+ /* CHECKED */
+ while (nblock--)
+ {
+ t_int i = ((*(t_int *)(t_float *)in1++) |
+ (*(t_int *)(t_float *)in2++));
+ *out++ = *(t_float *)&i;
+ }
+ break;
+ case 1:
+ /* CHECKED */
+ while (nblock--)
+ {
+ t_int i = (((t_int)*in1++) |
+ ((t_int)*in2++));
+ *out++ = (t_float)i;
+ }
+ break;
+ case 2:
+ /* CHECKED */
+ while (nblock--)
+ {
+ t_int i = (*(t_int *)(t_float *)in1++) | ((t_int)*in2++);
+ *out++ = *(t_float *)&i;
+ }
+ break;
+ case 3:
+ /* CHECKED */
+ while (nblock--)
+ {
+ t_int i = ((t_int)*in1++) | (*(t_int *)(t_float *)in2++);
+ *out++ = (t_float)i;
+ }
+ break;
+ }
+ return (w + 6);
+}
+
+static t_int *bitor_perform_noin2(t_int *w)
+{
+ t_bitor *x = (t_bitor *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ t_int mask = x->x_mask;
+ /* LATER think about performance */
+ if (x->x_convert1) while (nblock--)
+ {
+ /* CHECKED */
+ t_int i = ((t_int)*in++) | mask;
+ *out++ = (t_float)i;
+ }
+ else while (nblock--)
+ {
+ /* CHECKED */
+ t_int i = (*(t_int *)(t_float *)in++) | mask;
+ *out++ = *(t_float *)&i;
+ }
+ return (w + 5);
+}
+
+static void bitor_dsp(t_bitor *x, t_signal **sp)
+{
+ if (forky_hasfeeders((t_object *)x, x->x_glist, 1, 0))
+ /* use the mask set by a second inlet's signal or float,
+ CHECKED (incompatible) second inlet's int is persistent */
+ dsp_add(bitor_perform, 5, x, sp[0]->s_n, sp[0]->s_vec,
+ sp[1]->s_vec, sp[2]->s_vec);
+ else /* use the mask set by a 'bits' message or a creation argument */
+ dsp_add(bitor_perform_noin2, 4, x, sp[0]->s_n, sp[0]->s_vec,
+ sp[1]->s_vec);
+}
+
+static void bitor_bits(t_bitor *x, t_symbol *s, int ac, t_atom *av)
+{
+ x->x_mask = forky_getbitmask(ac, av);
+}
+
+static void bitor_mode(t_bitor *x, t_floatarg f)
+{
+ int i = (int)f;
+ if (i < 0)
+ i = 0; /* CHECKED */
+ else if (i > 3)
+ i = 3; /* CHECKED */
+ x->x_mode = i;
+ x->x_convert1 = (x->x_mode == 1 || x->x_mode == 3);
+}
+
+static void *bitor_new(t_floatarg f1, t_floatarg f2)
+{
+ t_bitor *x = (t_bitor *)pd_new(bitor_class);
+ x->x_glist = canvas_getcurrent();
+ inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal);
+ outlet_new((t_object *)x, &s_signal);
+ x->x_mask = (t_int)f1; /* FIXME (how?) */
+ bitor_mode(x, f2);
+ return (x);
+}
+
+void bitor_tilde_setup(void)
+{
+ bitor_class = class_new(gensym("bitor~"),
+ (t_newmethod)bitor_new, 0,
+ sizeof(t_bitor), 0,
+ A_DEFFLOAT, A_DEFFLOAT, 0);
+ sic_setup(bitor_class, bitor_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(bitor_class, (t_method)bitor_bits,
+ gensym("bits"), A_GIMME, 0);
+ class_addmethod(bitor_class, (t_method)bitor_mode,
+ gensym("mode"), A_FLOAT, 0);
+}
diff --git a/cyclone/sickle/bitshift.c b/cyclone/sickle/bitshift.c
new file mode 100644
index 0000000..db30fcd
--- /dev/null
+++ b/cyclone/sickle/bitshift.c
@@ -0,0 +1,130 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* When bit-shifting 32-bit values, gcc (intel?) bashes the second operand
+ modulo 32. In msp x << 32 gives 0, x >> 32 gives a propagated sign bit
+ (as expected). Mimicking that is clumsy. LATER consider making the calcs
+ more generic (use long long values?) */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+//#define BITSHIFT_DEBUG
+
+typedef struct _bitshift
+{
+ t_sic x_sic;
+ int x_convert1;
+ int x_lshift;
+ int x_rshift;
+ int x_lover;
+} t_bitshift;
+
+static t_class *bitshift_class;
+
+static t_int *bitshift_perform(t_int *w)
+{
+ t_bitshift *x = (t_bitshift *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ /* LATER think about performance */
+ if (x->x_lshift)
+ {
+ unsigned int shift = x->x_lshift;
+ if (x->x_convert1) while (nblock--)
+ {
+ /* CHECKED */
+ t_int i = ((t_int)*in++ << shift);
+ *out++ = (t_float)i;
+ }
+ else while (nblock--)
+ {
+ /* CHECKED */
+ t_int i = (*(t_int *)(t_float *)in++ << shift);
+ *out++ = *(t_float *)&i;
+ }
+ }
+ else if (x->x_rshift)
+ {
+ unsigned int shift = x->x_rshift;
+ if (x->x_convert1) while (nblock--)
+ {
+ /* CHECKME */
+ t_int i = ((t_int)*in++ >> shift);
+ *out++ = (t_float)i;
+ }
+ else while (nblock--)
+ {
+ /* CHECKME */
+ t_int i = (*(t_int *)(t_float *)in++ >> shift);
+ *out++ = *(t_float *)&i;
+ }
+ }
+ else if (x->x_lover)
+ while (nblock--) *out++ = 0; /* CHECKED both modes */
+ else
+ while (nblock--) *out++ = *in++; /* CHECKED both modes */
+ return (w + 5);
+}
+
+static void bitshift_dsp(t_bitshift *x, t_signal **sp)
+{
+ dsp_add(bitshift_perform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void bitshift_mode(t_bitshift *x, t_floatarg f)
+{
+ int i = (int)f;
+ x->x_convert1 = (i > 0); /* CHECKED */
+}
+
+static void bitshift_shift(t_bitshift *x, t_floatarg f)
+{
+ int i = (int)f;
+ int nbits = sizeof(t_int) * 8;
+ x->x_lshift = x->x_rshift = 0;
+ x->x_lover = 0;
+ if (i > 0)
+ {
+#ifdef BITSHIFT_DEBUG
+ post("%.8x << %d == %.8x, %.8x << %d == %.8x",
+ 1, i, 1 << i, -1, i, -1 << i);
+#endif
+ if (i < nbits)
+ x->x_lshift = i;
+ else
+ x->x_lover = 1;
+ }
+ else if (i < 0)
+ {
+#ifdef BITSHIFT_DEBUG
+ post("%.8x >> %d == %.8x, %.8x >> %d == %.8x",
+ 0x7fffffff, -i, 0x7fffffff >> -i, -1, -i, -1 >> -i);
+#endif
+ x->x_rshift = (i <= -nbits ? nbits - 1 : -i);
+ }
+}
+
+static void *bitshift_new(t_floatarg f1, t_floatarg f2)
+{
+ t_bitshift *x = (t_bitshift *)pd_new(bitshift_class);
+ outlet_new((t_object *)x, &s_signal);
+ bitshift_shift(x, f1);
+ bitshift_mode(x, f2);
+ return (x);
+}
+
+void bitshift_tilde_setup(void)
+{
+ bitshift_class = class_new(gensym("bitshift~"),
+ (t_newmethod)bitshift_new, 0,
+ sizeof(t_bitshift), 0,
+ A_DEFFLOAT, A_DEFFLOAT, 0);
+ sic_setup(bitshift_class, bitshift_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(bitshift_class, (t_method)bitshift_mode,
+ gensym("mode"), A_FLOAT, 0);
+ class_addmethod(bitshift_class, (t_method)bitshift_shift,
+ gensym("shift"), A_FLOAT, 0);
+}
diff --git a/cyclone/sickle/bitxor.c b/cyclone/sickle/bitxor.c
new file mode 100644
index 0000000..ce54843
--- /dev/null
+++ b/cyclone/sickle/bitxor.c
@@ -0,0 +1,144 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* FIXME find a way of setting a 32-bit mask in an argument */
+
+#include "m_pd.h"
+#include "unstable/forky.h"
+#include "sickle/sic.h"
+
+typedef struct _bitxor
+{
+ t_sic x_sic;
+ t_glist *x_glist;
+ t_int x_mask; /* set by a 'bits' message or a creation argument */
+ int x_mode;
+ int x_convert1;
+} t_bitxor;
+
+static t_class *bitxor_class;
+
+static t_int *bitxor_perform(t_int *w)
+{
+ t_bitxor *x = (t_bitxor *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in1 = (t_float *)(w[3]);
+ t_float *in2 = (t_float *)(w[4]);
+ t_float *out = (t_float *)(w[5]);
+ t_int mask = x->x_mask;
+ switch (x->x_mode)
+ {
+ /* LATER think about performance */
+ case 0:
+ /* CHECKED */
+ while (nblock--)
+ {
+ t_int i = ((*(t_int *)(t_float *)in1++) ^
+ (*(t_int *)(t_float *)in2++));
+ *out++ = *(t_float *)&i;
+ }
+ break;
+ case 1:
+ /* CHECKED */
+ while (nblock--)
+ {
+ t_int i = (((t_int)*in1++) ^
+ ((t_int)*in2++));
+ *out++ = (t_float)i;
+ }
+ break;
+ case 2:
+ /* CHECKED */
+ while (nblock--)
+ {
+ t_int i = (*(t_int *)(t_float *)in1++) ^ ((t_int)*in2++);
+ *out++ = *(t_float *)&i;
+ }
+ break;
+ case 3:
+ /* CHECKED */
+ while (nblock--)
+ {
+ t_int i = ((t_int)*in1++) ^ (*(t_int *)(t_float *)in2++);
+ *out++ = (t_float)i;
+ }
+ break;
+ }
+ return (w + 6);
+}
+
+static t_int *bitxor_perform_noin2(t_int *w)
+{
+ t_bitxor *x = (t_bitxor *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ t_int mask = x->x_mask;
+ /* LATER think about performance */
+ if (x->x_convert1) while (nblock--)
+ {
+ /* CHECKED */
+ t_int i = ((t_int)*in++) ^ mask;
+ *out++ = (t_float)i;
+ }
+ else while (nblock--)
+ {
+ /* CHECKED */
+ t_int i = (*(t_int *)(t_float *)in++) ^ mask;
+ *out++ = *(t_float *)&i;
+ }
+ return (w + 5);
+}
+
+static void bitxor_dsp(t_bitxor *x, t_signal **sp)
+{
+ if (forky_hasfeeders((t_object *)x, x->x_glist, 1, 0))
+ /* use the mask set by a second inlet's signal or float,
+ CHECKED (incompatible) second inlet's int is persistent */
+ dsp_add(bitxor_perform, 5, x, sp[0]->s_n, sp[0]->s_vec,
+ sp[1]->s_vec, sp[2]->s_vec);
+ else /* use the mask set by a 'bits' message or a creation argument */
+ dsp_add(bitxor_perform_noin2, 4, x, sp[0]->s_n, sp[0]->s_vec,
+ sp[1]->s_vec);
+}
+
+static void bitxor_bits(t_bitxor *x, t_symbol *s, int ac, t_atom *av)
+{
+ x->x_mask = forky_getbitmask(ac, av);
+}
+
+static void bitxor_mode(t_bitxor *x, t_floatarg f)
+{
+ int i = (int)f;
+ if (i < 0)
+ i = 0; /* CHECKED */
+ else if (i > 3)
+ i = 3; /* CHECKED */
+ x->x_mode = i;
+ x->x_convert1 = (x->x_mode == 1 || x->x_mode == 3);
+}
+
+static void *bitxor_new(t_floatarg f1, t_floatarg f2)
+{
+ t_bitxor *x = (t_bitxor *)pd_new(bitxor_class);
+ x->x_glist = canvas_getcurrent();
+ inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal);
+ outlet_new((t_object *)x, &s_signal);
+ x->x_mask = (t_int)f1; /* FIXME (how?) */
+ bitxor_mode(x, f2);
+ return (x);
+}
+
+void bitxor_tilde_setup(void)
+{
+ bitxor_class = class_new(gensym("bitxor~"),
+ (t_newmethod)bitxor_new, 0,
+ sizeof(t_bitxor), 0,
+ A_DEFFLOAT, A_DEFFLOAT, 0);
+ sic_setup(bitxor_class, bitxor_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(bitxor_class, (t_method)bitxor_bits,
+ gensym("bits"), A_GIMME, 0);
+ class_addmethod(bitxor_class, (t_method)bitxor_mode,
+ gensym("mode"), A_FLOAT, 0);
+}
diff --git a/cyclone/sickle/capture.c b/cyclone/sickle/capture.c
new file mode 100644
index 0000000..089c21e
--- /dev/null
+++ b/cyclone/sickle/capture.c
@@ -0,0 +1,408 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* CHECKME list of indices */
+
+#include <stdio.h>
+#include "m_pd.h"
+#include "g_canvas.h"
+#include "common/loud.h"
+#include "hammer/file.h"
+#include "sickle/sic.h"
+
+#define CAPTURE_DEFSIZE 4096
+#define CAPTURE_DEFPRECISION 4
+#define CAPTURE_MAXPRECISION 99 /* format array protection */
+#define CAPTURE_MAXINDICES 4096 /* FIXME */
+
+typedef struct _capture
+{
+ t_sic x_sic;
+ t_glist *x_glist;
+ char x_mode; /* 'f' for first or 0 for last */
+ int x_precision;
+ char x_format[8];
+ char *x_indices;
+ int x_szindices; /* size of x_indices array */
+ int x_nindices; /* number of reported indices */
+ int x_nblock;
+ float *x_buffer;
+ int x_bufsize;
+ int x_count;
+ int x_head;
+ t_hammerfile *x_filehandle;
+} t_capture;
+
+static t_class *capture_class;
+
+static void capture_clear(t_capture *x)
+{
+ x->x_count = 0;
+ x->x_head = 0;
+}
+
+static int capture_formatfloat(t_capture *x, float f, char *buf, int col,
+ int maxcol)
+{
+ char *bp = buf;
+ int cnt = 0;
+ if (col > 0)
+ *bp++ = ' ', cnt++;
+ if (x->x_precision)
+ cnt += sprintf(bp, x->x_format, f);
+ else
+ cnt += sprintf(bp, "%d", (int)f);
+ if (col + cnt > maxcol)
+ buf[0] = '\n', col = cnt;
+ else
+ col += cnt;
+ return (col);
+}
+
+static int capture_writefloat(t_capture *x, float f, char *buf, int col,
+ FILE *fp)
+{
+ /* CHECKME linebreaks */
+ col = capture_formatfloat(x, f, buf, col, 80);
+ return (fputs(buf, fp) < 0 ? -1 : col);
+}
+
+static void capture_dowrite(t_capture *x, t_symbol *fn)
+{
+ FILE *fp = 0;
+ int count = x->x_count;
+ char buf[MAXPDSTRING];
+ canvas_makefilename(glist_getcanvas(x->x_glist),
+ fn->s_name, buf, MAXPDSTRING);
+ if (fp = fopen(buf, "w")) /* LATER ask if overwriting, CHECKME */
+ {
+ int col = 0;
+ if (x->x_mode == 'f' || count < x->x_bufsize)
+ {
+ float *bp = x->x_buffer;
+ while (count--)
+ if ((col = capture_writefloat(x, *bp++, buf, col, fp)) < 0)
+ goto fail;
+ }
+ else
+ {
+ float *bp = x->x_buffer + x->x_head;
+ count = x->x_bufsize - x->x_head;
+ while (count--)
+ if ((col = capture_writefloat(x, *bp++, buf, col, fp)) < 0)
+ goto fail;
+ bp = x->x_buffer;
+ count = x->x_head;
+ while (count--)
+ if ((col = capture_writefloat(x, *bp++, buf, col, fp)) < 0)
+ goto fail;
+ }
+ if (col) fputc('\n', fp);
+ fclose(fp);
+ return;
+ }
+fail:
+ if (fp) fclose(fp);
+ loud_syserror((t_pd *)x, 0);
+}
+
+static void capture_writehook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ capture_dowrite((t_capture *)z, fn);
+}
+
+static void capture_write(t_capture *x, t_symbol *s)
+{
+ if (s && s != &s_)
+ capture_dowrite(x, s);
+ else
+ hammerpanel_save(x->x_filehandle, 0, 0);
+}
+
+static int capture_appendfloat(t_capture *x, float f, char *buf,
+ int col, int linebreak)
+{
+ /* CHECKME 80 columns */
+ col = capture_formatfloat(x, f, buf, col, 80);
+ hammereditor_append(x->x_filehandle, buf);
+ if (linebreak)
+ {
+ if (col)
+ {
+ hammereditor_append(x->x_filehandle, "\n\n");
+ col = 0;
+ }
+ else hammereditor_append(x->x_filehandle, "\n");
+ }
+ return (col);
+}
+
+/* CHECKED blank line between blocks */
+static void capture_open(t_capture *x)
+{
+ int count = x->x_count;
+ char buf[MAXPDSTRING];
+ int nindices = (x->x_nindices > 0 ? x->x_nindices : x->x_nblock);
+ hammereditor_open(x->x_filehandle, "Signal Capture"); /* CHECKED */
+ if (x->x_mode == 'f' || count < x->x_bufsize)
+ {
+ float *bp = x->x_buffer;
+ int col = 0, i;
+ for (i = 1; i <= count; i++)
+ col = capture_appendfloat(x, *bp++, buf, col,
+ ((i % nindices) == 0));
+ }
+ else
+ {
+ float *bp = x->x_buffer + x->x_head;
+ int col = 0, i = x->x_bufsize;
+ count = x->x_bufsize - x->x_head;
+ while (count--)
+ col = capture_appendfloat(x, *bp++, buf, col,
+ ((--i % nindices) == 0));
+ bp = x->x_buffer;
+ count = x->x_head;
+ while (count--)
+ col = capture_appendfloat(x, *bp++, buf, col,
+ ((count % nindices) == 0));
+ }
+}
+
+static void capture_wclose(t_capture *x)
+{
+ hammereditor_close(x->x_filehandle, 0);
+}
+
+static void capture_click(t_capture *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ capture_open(x);
+}
+
+static t_int *capture_perform_first(t_int *w)
+{
+ t_capture *x = (t_capture *)(w[1]);
+ int count = x->x_count;
+ int bufsize = x->x_bufsize;
+ if (count < bufsize)
+ {
+ t_float *in = (t_float *)(w[2]);
+ int nblock = (int)(w[3]);
+ float *bp = x->x_buffer + count;
+ char *ndxp = x->x_indices;
+ if (nblock > x->x_szindices)
+ nblock = x->x_szindices;
+ while (nblock--)
+ {
+ if (*ndxp++)
+ {
+ *bp++ = *in++;
+ if (++count == bufsize)
+ break;
+ }
+ else in++;
+ }
+ x->x_count = count;
+ }
+ return (w + 4);
+}
+
+static t_int *capture_perform_allfirst(t_int *w)
+{
+ t_capture *x = (t_capture *)(w[1]);
+ int count = x->x_count;
+ int bufsize = x->x_bufsize;
+ if (count < bufsize)
+ {
+ t_float *in = (t_float *)(w[2]);
+ int nblock = (int)(w[3]);
+ float *bp = x->x_buffer + count;
+ while (nblock--)
+ {
+ *bp++ = *in++;
+ if (++count == bufsize)
+ break;
+ }
+ x->x_count = count;
+ }
+ return (w + 4);
+}
+
+static t_int *capture_perform_last(t_int *w)
+{
+ t_capture *x = (t_capture *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ int nblock = (int)(w[3]);
+ float *buffer = x->x_buffer;
+ int bufsize = x->x_bufsize;
+ int count = x->x_count;
+ int head = x->x_head;
+ char *ndxp = x->x_indices;
+ if (nblock > x->x_szindices)
+ nblock = x->x_szindices;
+ while (nblock--)
+ {
+ if (*ndxp++)
+ {
+ buffer[head++] = *in++;
+ if (head >= bufsize)
+ head = 0;
+ if (count < bufsize)
+ count++;
+ }
+ else in++;
+ }
+ x->x_count = count;
+ x->x_head = head;
+ return (w + 4);
+}
+
+static t_int *capture_perform_alllast(t_int *w)
+{
+ t_capture *x = (t_capture *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ int nblock = (int)(w[3]);
+ float *buffer = x->x_buffer;
+ int bufsize = x->x_bufsize;
+ int count = x->x_count;
+ int head = x->x_head;
+ while (nblock--)
+ {
+ buffer[head++] = *in++;
+ if (head >= bufsize)
+ head = 0;
+ if (count < bufsize)
+ count++;
+ }
+ x->x_count = count;
+ x->x_head = head;
+ return (w + 4);
+}
+
+static void capture_dsp(t_capture *x, t_signal **sp)
+{
+ x->x_nblock = sp[0]->s_n;
+ if (x->x_indices)
+ dsp_add((x->x_mode == 'f' ?
+ capture_perform_first : capture_perform_last),
+ 3, x, sp[0]->s_vec, sp[0]->s_n);
+ else
+ dsp_add((x->x_mode == 'f' ?
+ capture_perform_allfirst : capture_perform_alllast),
+ 3, x, sp[0]->s_vec, sp[0]->s_n);
+}
+
+static void capture_free(t_capture *x)
+{
+ hammerfile_free(x->x_filehandle);
+ if (x->x_indices)
+ freebytes(x->x_indices, x->x_szindices * sizeof(*x->x_indices));
+ if (x->x_buffer)
+ freebytes(x->x_buffer, x->x_bufsize * sizeof(*x->x_buffer));
+}
+
+static void *capture_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_capture *x = 0;
+ char mode = 0;
+ int precision = -1;
+ float *buffer;
+ int bufsize = 0;
+ char *indices = 0;
+ int szindices = 0, nindices = -1;
+ if (ac && av->a_type == A_SYMBOL)
+ {
+ t_symbol *s = av->a_w.w_symbol;
+ if (s && *s->s_name == 'f') /* CHECKME */
+ mode = 'f';
+ ac--; av++;
+ }
+ if (ac && av->a_type == A_FLOAT)
+ {
+ bufsize = (int)av->a_w.w_float; /* CHECKME */
+ ac--; av++;
+ if (ac && av->a_type == A_FLOAT)
+ {
+ int i;
+ t_atom *ap;
+ precision = (int)av->a_w.w_float; /* CHECKME */
+ ac--; av++;
+ for (i = 0, ap = av; i < ac; i++, ap++)
+ {
+ if (ap->a_type == A_FLOAT)
+ {
+ int ndx = (int)ap->a_w.w_float;
+ /* CHECKME noninteger, negative */
+ ndx++;
+ if (ndx >= CAPTURE_MAXINDICES)
+ {
+ /* CHECKME complaint */
+ szindices = CAPTURE_MAXINDICES;
+ break;
+ }
+ else if (ndx > szindices)
+ szindices = ndx;
+ }
+ else break; /* CHECKME */
+ }
+ if (szindices && (indices = getbytes(szindices * sizeof(*indices))))
+ {
+ nindices = 0;
+ while (i--)
+ {
+ int ndx = (int)av++->a_w.w_float;
+ /* CHECKME noninteger */
+ if (ndx >= 0 && ndx < szindices)
+ indices[ndx] = 1, nindices++;
+ }
+ }
+ }
+ }
+ if (bufsize <= 0) /* CHECKME */
+ bufsize = CAPTURE_DEFSIZE;
+ if (buffer = getbytes(bufsize * sizeof(*buffer)))
+ {
+ x = (t_capture *)pd_new(capture_class);
+ x->x_glist = canvas_getcurrent();
+ x->x_mode = mode;
+ if (precision < 0) /* CHECKME */
+ precision = CAPTURE_DEFPRECISION;
+ else if (precision > CAPTURE_MAXPRECISION) /* CHECKME */
+ precision = CAPTURE_MAXPRECISION;
+ if (x->x_precision = precision)
+ sprintf(x->x_format, "%%.%dg", precision);
+ x->x_indices = indices;
+ x->x_szindices = szindices;
+ x->x_nindices = nindices;
+ x->x_nblock = 64; /* redundant */
+ x->x_buffer = buffer;
+ x->x_bufsize = bufsize;
+ x->x_filehandle = hammerfile_new((t_pd *)x, 0, 0, capture_writehook, 0);
+ capture_clear(x);
+ }
+ else if (indices)
+ freebytes(indices, szindices * sizeof(*indices));
+ return (x);
+}
+
+void capture_tilde_setup(void)
+{
+ capture_class = class_new(gensym("capture~"),
+ (t_newmethod)capture_new,
+ (t_method)capture_free,
+ sizeof(t_capture), 0, A_GIMME, 0);
+ sic_setup(capture_class, capture_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(capture_class, (t_method)capture_clear,
+ gensym("clear"), 0);
+ class_addmethod(capture_class, (t_method)capture_write,
+ gensym("write"), A_DEFSYM, 0);
+ class_addmethod(capture_class, (t_method)capture_open,
+ gensym("open"), 0);
+ class_addmethod(capture_class, (t_method)capture_wclose,
+ gensym("wclose"), 0);
+ class_addmethod(capture_class, (t_method)capture_click,
+ gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ hammerfile_setup(capture_class, 0);
+}
diff --git a/cyclone/sickle/cartopol.c b/cyclone/sickle/cartopol.c
new file mode 100644
index 0000000..4c25797
--- /dev/null
+++ b/cyclone/sickle/cartopol.c
@@ -0,0 +1,79 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+#include "unstable/fragile.h"
+#include "sickle/sic.h"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define atan2f atan2
+#define hypotf hypot
+#endif
+
+typedef struct _cartopol
+{
+ t_sic x_sic;
+ t_outlet *x_out2;
+} t_cartopol;
+
+static t_class *cartopol_class;
+
+static t_int *cartopol_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out1 = (t_float *)(w[4]);
+ t_float *out2 = (t_float *)(w[5]);
+ while (nblock--)
+ {
+ float rl = *in1++, im = -*in2++; /* CHECKED */
+ *out1++ = hypotf(rl, im);
+ *out2++ = atan2f(im, rl);
+ }
+ return (w + 6);
+}
+
+static t_int *cartopol_perform_nophase(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out1 = (t_float *)(w[4]);
+ while (nblock--)
+ {
+ float rl = *in1++, im = -*in2++; /* CHECKED */
+ *out1++ = hypotf(rl, im);
+ }
+ return (w + 5);
+}
+
+static void cartopol_dsp(t_cartopol *x, t_signal **sp)
+{
+ if (fragile_outlet_connections(x->x_out2))
+ dsp_add(cartopol_perform, 5, sp[0]->s_n, sp[0]->s_vec,
+ sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec);
+ else
+ dsp_add(cartopol_perform_nophase, 4, sp[0]->s_n, sp[0]->s_vec,
+ sp[1]->s_vec, sp[2]->s_vec);
+}
+
+static void *cartopol_new(void)
+{
+ t_cartopol *x = (t_cartopol *)pd_new(cartopol_class);
+ inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal);
+ outlet_new((t_object *)x, &s_signal);
+ x->x_out2 = outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void cartopol_tilde_setup(void)
+{
+ cartopol_class = class_new(gensym("cartopol~"),
+ (t_newmethod)cartopol_new, 0,
+ sizeof(t_cartopol), 0, 0);
+ sic_setup(cartopol_class, cartopol_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/change.c b/cyclone/sickle/change.c
new file mode 100644
index 0000000..fffc43a
--- /dev/null
+++ b/cyclone/sickle/change.c
@@ -0,0 +1,52 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+typedef struct _change
+{
+ t_sic x_sic;
+ t_float x_last;
+} t_change;
+
+static t_class *change_class;
+
+static t_int *change_perform(t_int *w)
+{
+ t_change *x = (t_change *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ t_float last = x->x_last;
+ while (nblock--)
+ {
+ t_float f = *in++;
+ *out++ = (f > last ? 1. : (f < last ? -1. : 0.));
+ last = f;
+ }
+ x->x_last = last;
+ return (w + 5);
+}
+
+static void change_dsp(t_change *x, t_signal **sp)
+{
+ dsp_add(change_perform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void *change_new(void)
+{
+ t_change *x = (t_change *)pd_new(change_class);
+ outlet_new((t_object *)x, &s_signal);
+ x->x_last = 0; /* CHECKME startup conditions */
+ return (x);
+}
+
+void change_tilde_setup(void)
+{
+ change_class = class_new(gensym("change~"),
+ (t_newmethod)change_new, 0,
+ sizeof(t_change), 0, 0);
+ sic_setup(change_class, change_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/click.c b/cyclone/sickle/click.c
new file mode 100644
index 0000000..5734cfd
--- /dev/null
+++ b/cyclone/sickle/click.c
@@ -0,0 +1,119 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "common/grow.h"
+#include "sickle/sic.h"
+
+#define CLICK_INISIZE 16 /* LATER rethink */
+
+typedef struct _click
+{
+ t_sic x_sic;
+ int x_nsamples; /* as used */
+ int x_bufsize; /* as allocated */
+ t_float *x_buffer;
+ t_float x_bufini[CLICK_INISIZE];
+ int x_nleft;
+ t_float *x_head;
+} t_click;
+
+static t_class *click_class;
+
+static void click_bang(t_click *x)
+{
+ x->x_nleft = x->x_nsamples;
+ x->x_head = x->x_buffer;
+}
+
+static void click_set(t_click *x, t_symbol *s, int ac, t_atom *av)
+{
+ int i, nsamples = 0;
+ t_atom *ap;
+ t_float *bp;
+ for (i = 0, ap = av; i < ac; i++, ap++)
+ {
+ if (ap->a_type == A_FLOAT) nsamples++;
+ /* CHECKED no restrictions (refman's error about 0.0-1.0 range)
+ CHECKED nonnumeric atoms silently ignored */
+ }
+ if (nsamples > x->x_bufsize)
+ x->x_buffer = grow_nodata(&nsamples, &x->x_bufsize, x->x_buffer,
+ CLICK_INISIZE, x->x_bufini,
+ sizeof(*x->x_buffer));
+ if (nsamples)
+ {
+ x->x_nsamples = nsamples;
+ bp = x->x_buffer;
+ while (nsamples--) *bp++ = av++->a_w.w_float;
+ }
+ else x->x_nsamples = 0; /* CHECKED, need to 'set 1' explicitly */
+ x->x_nleft = 0;
+ x->x_head = x->x_buffer;
+}
+
+static t_int *click_perform(t_int *w)
+{
+ t_click *x = (t_click *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ if (x->x_nleft)
+ {
+ int nleft = x->x_nleft;
+ t_float *head = x->x_head;
+ if (nleft >= nblock)
+ {
+ x->x_nleft -= nblock;
+ while (nblock--) *out++ = *head++;
+ x->x_head = head;
+ }
+ else
+ {
+ nblock -= nleft;
+ while (nleft--) *out++ = *head++;
+ while (nblock--) *out++ = 0.;
+ x->x_nleft = 0;
+ x->x_head = x->x_buffer;
+ }
+ }
+ else while (nblock--) *out++ = 0.;
+ return (w + 4);
+}
+
+static void click_dsp(t_click *x, t_signal **sp)
+{
+ dsp_add(click_perform, 3, x, sp[0]->s_n, sp[0]->s_vec);
+}
+
+static void click_free(t_click *x)
+{
+ if (x->x_buffer != x->x_bufini)
+ freebytes(x->x_buffer, x->x_bufsize * sizeof(*x->x_buffer));
+}
+
+static void *click_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_click *x = (t_click *)pd_new(click_class);
+ x->x_nsamples = 1; /* CHECKED */
+ x->x_bufsize = CLICK_INISIZE;
+ x->x_buffer = x->x_bufini;
+ x->x_buffer[0] = 1.; /* CHECKED */
+ x->x_nleft = 0;
+ x->x_head = x->x_buffer;
+ outlet_new((t_object *)x, &s_signal);
+ if (ac) click_set(x, 0, ac, av);
+ return (x);
+}
+
+void click_tilde_setup(void)
+{
+ click_class = class_new(gensym("click~"),
+ (t_newmethod)click_new,
+ (t_method)click_free,
+ sizeof(t_click), 0, A_GIMME, 0);
+ sic_setup(click_class, click_dsp, SIC_NOMAINSIGNALIN);
+ class_addbang(click_class, click_bang);
+ class_addmethod(click_class, (t_method)click_set,
+ gensym("set"), A_GIMME, 0);
+}
diff --git a/cyclone/sickle/comb.c b/cyclone/sickle/comb.c
new file mode 100644
index 0000000..8d4c8b3
--- /dev/null
+++ b/cyclone/sickle/comb.c
@@ -0,0 +1,162 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+typedef struct _comb
+{
+ t_sic x_sic;
+ float x_sr;
+ float x_ksr;
+ t_float *x_buf;
+ int x_bufsize; /* as allocated */
+ int x_maxsize; /* as used */
+ float x_maxdelay; /* same in ms */
+ int x_phase; /* writing head */
+} t_comb;
+
+static t_class *comb_class;
+
+/* maximum delay defaults to 50 ms (cycling has 10 ms here) */
+#define COMB_DEFMAXDELAY 50.0
+
+/* LATER choose the best way. From msp help patch:
+ no clipping is done on a, b, or c coefficient input */
+#define COMB_MAXFEEDBACK 0.999
+
+static void comb_clear(t_comb *x)
+{
+ memset(x->x_buf, 0, x->x_maxsize * sizeof(*x->x_buf));
+ x->x_phase = 0;
+}
+
+static void comb_resize(t_comb *x, int newsize)
+{
+ if (newsize > 0 && newsize != x->x_maxsize)
+ {
+ if (newsize > x->x_bufsize)
+ {
+ x->x_buf = resizebytes(x->x_buf,
+ x->x_bufsize * sizeof(*x->x_buf),
+ newsize * sizeof(*x->x_buf));
+ /* LATER test for failure */
+ x->x_bufsize = newsize;
+ }
+ x->x_maxsize = newsize;
+ }
+ comb_clear(x);
+}
+
+static t_int *comb_perform(t_int *w)
+{
+ t_comb *x = (t_comb *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *xin = (t_float *)(w[3]);
+ t_float *din = (t_float *)(w[4]);
+ t_float *ain = (t_float *)(w[5]);
+ t_float *bin = (t_float *)(w[6]);
+ t_float *cin = (t_float *)(w[7]);
+ t_float *out = (t_float *)(w[8]);
+ t_float *buf = x->x_buf;
+ int maxsize = x->x_maxsize;
+ int guardpoint = maxsize - 1;
+ float ksr = x->x_ksr;
+ int wph = x->x_phase;
+ while (nblock--)
+ { /* TDFII scheme is used. Do not forget, that any signal value
+ read after writing to out has to be saved beforehand. */
+ float xn = *xin++;
+ float delsize = ksr * *din++;
+ float bgain = *bin++;
+ float cgain = *cin++;
+ float yn = *ain++ * xn;
+ float rph; /* reading head */
+ if (cgain < -COMB_MAXFEEDBACK) cgain = -COMB_MAXFEEDBACK;
+ else if (cgain > COMB_MAXFEEDBACK) cgain = COMB_MAXFEEDBACK;
+ if (delsize > 1.0)
+ {
+ int ndx;
+ float val;
+ rph = wph - (delsize > guardpoint ? guardpoint : delsize);
+ if (rph < 0) rph += guardpoint;
+ ndx = (int)rph;
+ val = buf[ndx];
+ /* ``a cheezy linear interpolation'' ala msp,
+ (vd~ uses 4-point interpolation...) */
+ yn += val + (buf[ndx+1] - val) * (rph - ndx);
+ }
+ *out++ = yn;
+ if (wph == guardpoint)
+ {
+ buf[wph] = *buf = bgain * xn + cgain * yn;
+ wph = 1;
+ }
+ else buf[wph++] = bgain * xn + cgain * yn;
+ }
+ x->x_phase = wph;
+ return (w + 9);
+}
+
+static void comb_dsp(t_comb *x, t_signal **sp)
+{
+ float sr = sp[0]->s_sr;
+ if (sr != x->x_sr)
+ {
+ x->x_sr = sr;
+ x->x_ksr = sr * 0.001;
+ comb_resize(x, x->x_ksr * x->x_maxdelay);
+ }
+ else comb_clear(x);
+ dsp_add(comb_perform, 8, x, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,
+ sp[3]->s_vec, sp[4]->s_vec, sp[5]->s_vec);
+}
+
+static void *comb_new(t_floatarg f1, t_floatarg f2,
+ t_floatarg f3, t_floatarg f4, t_floatarg f5)
+{
+ t_comb *x;
+ float maxdelay = (f1 > 0 ? f1 : COMB_DEFMAXDELAY);
+ float sr = sys_getsr();
+ float ksr = sr * 0.001;
+ int bufsize = ksr * maxdelay;
+ t_float *buf = (t_float *)getbytes(bufsize * sizeof(*buf));
+ if (!buf)
+ return (0);
+ x = (t_comb *)pd_new(comb_class);
+ x->x_maxdelay = maxdelay;
+ x->x_sr = sr;
+ x->x_ksr = ksr;
+ x->x_bufsize = x->x_maxsize = bufsize;
+ x->x_buf = buf;
+ if (f2 < 0) f2 = 0;
+ if (f5 < -COMB_MAXFEEDBACK) f5 = -COMB_MAXFEEDBACK;
+ else if (f5 > COMB_MAXFEEDBACK) f5 = COMB_MAXFEEDBACK;
+ sic_newinlet((t_sic *)x, f2);
+ sic_newinlet((t_sic *)x, f3);
+ sic_newinlet((t_sic *)x, f4);
+ sic_newinlet((t_sic *)x, f5);
+ outlet_new((t_object *)x, &s_signal);
+ comb_clear(x);
+ return (x);
+}
+
+static void comb_free(t_comb *x)
+{
+ if (x->x_buf) freebytes(x->x_buf, x->x_bufsize * sizeof(*x->x_buf));
+}
+
+void comb_tilde_setup(void)
+{
+ comb_class = class_new(gensym("comb~"),
+ (t_newmethod)comb_new,
+ (t_method)comb_free,
+ sizeof(t_comb), 0,
+ A_DEFFLOAT, A_DEFFLOAT,
+ A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ sic_setup(comb_class, comb_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(comb_class, (t_method)comb_clear, gensym("clear"), 0);
+}
diff --git a/cyclone/sickle/cosh.c b/cyclone/sickle/cosh.c
new file mode 100644
index 0000000..ae5f8cb
--- /dev/null
+++ b/cyclone/sickle/cosh.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define coshf cosh
+#endif
+
+typedef t_sic t_cosh;
+static t_class *cosh_class;
+
+static t_int *cosh_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ while (nblock--)
+ {
+ float f = *in++;
+ *out++ = coshf(f); /* CHECKME no protection against overflow */
+ }
+ return (w + 4);
+}
+
+static void cosh_dsp(t_cosh *x, t_signal **sp)
+{
+ dsp_add(cosh_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void *cosh_new(void)
+{
+ t_cosh *x = (t_cosh *)pd_new(cosh_class);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void cosh_tilde_setup(void)
+{
+ cosh_class = class_new(gensym("cosh~"),
+ (t_newmethod)cosh_new, 0,
+ sizeof(t_cosh), 0, 0);
+ sic_setup(cosh_class, cosh_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/cosx.c b/cyclone/sickle/cosx.c
new file mode 100644
index 0000000..b368559
--- /dev/null
+++ b/cyclone/sickle/cosx.c
@@ -0,0 +1,51 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+/* by definition, this is just an interface to the -lm call
+ (do not use costable) */
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define cosf cos
+#endif
+
+typedef t_sic t_cosx;
+static t_class *cosx_class;
+
+static t_int *cosx_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ while (nblock--)
+ {
+ float f = *in++;
+ *out++ = cosf(f);
+ }
+ return (w + 4);
+}
+
+static void cosx_dsp(t_cosx *x, t_signal **sp)
+{
+ dsp_add(cosx_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void *cosx_new(void)
+{
+ t_cosx *x = (t_cosx *)pd_new(cosx_class);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void cosx_tilde_setup(void)
+{
+ cosx_class = class_new(gensym("cosx~"),
+ (t_newmethod)cosx_new, 0,
+ sizeof(t_cosx), 0, 0);
+ sic_setup(cosx_class, cosx_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/count.c b/cyclone/sickle/count.c
new file mode 100644
index 0000000..b2ed2cd
--- /dev/null
+++ b/cyclone/sickle/count.c
@@ -0,0 +1,145 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+typedef struct _count
+{
+ t_sic x_sic;
+ int x_min;
+ int x_max;
+ int x_limit;
+ int x_on;
+ int x_autoreset;
+ int x_count; /* MAYBE use 64 bits (if 13.5 hours is not enough...) */
+} t_count;
+
+static t_class *count_class;
+
+static void count_min(t_count *x, t_floatarg f)
+{
+ x->x_min = (int)f;
+}
+
+static void count_max(t_count *x, t_floatarg f)
+{
+ x->x_max = (int)f;
+ /* MAYBE use 64 bits */
+ x->x_limit = (x->x_max == 0 ? 0x7fffffff
+ : x->x_max - 1); /* CHECKED */
+}
+
+static void count_autoreset(t_count *x, t_floatarg f)
+{
+ x->x_autoreset = (f != 0);
+}
+
+static void count_bang(t_count *x)
+{
+ x->x_count = x->x_min;
+ x->x_on = 1;
+}
+
+static void count_float(t_count *x, t_floatarg f)
+{
+ x->x_count = x->x_min = (int)f;
+ x->x_on = 1;
+}
+
+static void count_list(t_count *x, t_symbol *s, int ac, t_atom *av)
+{
+ int i;
+ if (ac > 4) ac = 4;
+ for (i = 0; i < ac; i++)
+ if (av[i].a_type != A_FLOAT) break;
+ switch (i)
+ {
+ case 4:
+ count_autoreset(x, av[3].a_w.w_float);
+ case 3:
+ x->x_on = (av[2].a_w.w_float != 0);
+ case 2:
+ count_max(x, av[1].a_w.w_float);
+ case 1:
+ count_min(x, av[0].a_w.w_float);
+ default:
+ x->x_count = x->x_min;
+ }
+}
+
+static void count_set(t_count *x, t_symbol s, int ac, t_atom *av)
+{
+ if (av[0].a_type == A_FLOAT) count_min(x, av[0].a_w.w_float);
+ if (av[1].a_type == A_FLOAT) count_max(x, av[1].a_w.w_float);
+}
+
+static void count_stop(t_count *x)
+{
+ x->x_count = x->x_min;
+ x->x_on = 0;
+}
+
+static t_int *count_perform(t_int *w)
+{
+ t_count *x = (t_count *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int count = x->x_count;
+ int limit = x->x_limit;
+ if (x->x_on)
+ {
+ while (nblock--)
+ {
+ if (count > limit) count = x->x_min;
+ *out++ = (t_float)count++;
+ }
+ }
+ else
+ while (nblock--) *out++ = count;
+ x->x_count = count;
+ return (w + 4);
+}
+
+static void count_dsp(t_count *x, t_signal **sp)
+{
+ if (x->x_autoreset) count_bang(x);
+ dsp_add(count_perform, 3, x, sp[0]->s_n, sp[0]->s_vec);
+}
+
+static void *count_new(t_floatarg minval, t_floatarg maxval,
+ t_floatarg onflag, t_floatarg autoflag)
+{
+ t_count *x = (t_count *)pd_new(count_class);
+ count_min(x, minval);
+ count_max(x, maxval);
+ x->x_on = (onflag != 0);
+ count_autoreset(x, autoflag);
+ x->x_count = x->x_min;
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void count_tilde_setup(void)
+{
+ count_class = class_new(gensym("count~"),
+ (t_newmethod)count_new, 0,
+ sizeof(t_count), 0,
+ A_DEFFLOAT, A_DEFFLOAT,
+ A_DEFFLOAT, A_DEFFLOAT, 0);
+ sic_setup(count_class, count_dsp, SIC_NOMAINSIGNALIN);
+ class_addbang(count_class, count_bang);
+ class_addfloat(count_class, count_float);
+ class_addlist(count_class, count_list);
+ class_addmethod(count_class, (t_method)count_max,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(count_class, (t_method)count_autoreset,
+ gensym("autoreset"), A_FLOAT, 0);
+ class_addmethod(count_class, (t_method)count_min,
+ gensym("min"), A_FLOAT, 0);
+ class_addmethod(count_class, (t_method)count_set,
+ gensym("set"), A_GIMME, 0);
+ class_addmethod(count_class, (t_method)count_stop, gensym("stop"), 0);
+}
diff --git a/cyclone/sickle/cycle.c b/cyclone/sickle/cycle.c
new file mode 100644
index 0000000..01500ba
--- /dev/null
+++ b/cyclone/sickle/cycle.c
@@ -0,0 +1,173 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "shared.h"
+#include "common/loud.h"
+#include "common/vefl.h"
+#include "sickle/sic.h"
+
+#define CYCLE_TABSIZE 512
+
+typedef struct _cycle
+{
+ t_sic x_sic;
+ double x_phase;
+ double x_conv;
+ t_symbol *x_name;
+ int x_offset;
+ t_float *x_table;
+ t_float *x_costable;
+ t_float x_usertable[CYCLE_TABSIZE + 1];
+} t_cycle;
+
+static t_class *cycle_class;
+
+static void cycle_gettable(t_cycle *x)
+{
+ x->x_table = 0;
+ if (x->x_name)
+ {
+ int tabsize = 0;
+ t_float *table = vefl_get(x->x_name, &tabsize, 1, (t_pd *)x);
+ /* CHECKED buffer is copied */
+ if (table)
+ {
+ int indx = x->x_offset + CYCLE_TABSIZE;
+ t_float *ptr = x->x_usertable + CYCLE_TABSIZE;
+ if (indx == tabsize)
+ {
+ *ptr-- = *table;
+ indx--;
+ }
+ if (indx < tabsize)
+ {
+ table += indx;
+ indx -= x->x_offset;
+ while (indx--) *ptr-- = *table--;
+ x->x_table = x->x_usertable;
+ }
+ /* CHECKED else no complaint */
+ }
+ }
+ else x->x_table = x->x_costable;
+ if (!x->x_table)
+ {
+ /* CHECKED (incompatible) cycle~ is disabled -- garbage is output */
+ x->x_table = x->x_usertable;
+ memset(x->x_table, 0, (CYCLE_TABSIZE + 1) * sizeof(*x->x_table));
+ }
+}
+
+static void cycle_set(t_cycle *x, t_symbol *s, t_floatarg f)
+{
+ if (s && s != &s_)
+ {
+ x->x_name = s;
+ if ((x->x_offset = (int)f) < 0)
+ x->x_offset = 0;
+ }
+ else x->x_name = 0;
+ cycle_gettable(x);
+}
+
+static t_int *cycle_perform(t_int *w)
+{
+ t_cycle *x = (t_cycle *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in1 = (t_float *)(w[3]);
+ t_float *in2 = (t_float *)(w[4]);
+ t_float *out = (t_float *)(w[5]);
+ t_float *tab = x->x_table;
+ t_float *addr, f1, f2, frac;
+ double dphase = x->x_phase + SHARED_UNITBIT32;
+ double conv = x->x_conv;
+ int32 normhipart;
+ t_shared_wrappy wrappy;
+
+ wrappy.w_d = SHARED_UNITBIT32;
+ normhipart = wrappy.w_i[SHARED_HIOFFSET];
+
+ wrappy.w_d = dphase + CYCLE_TABSIZE * *in2++; /* CHECKED */
+ dphase += *in1++ * conv;
+ addr = tab + (wrappy.w_i[SHARED_HIOFFSET] & (CYCLE_TABSIZE-1));
+ wrappy.w_i[SHARED_HIOFFSET] = normhipart;
+ frac = wrappy.w_d - SHARED_UNITBIT32;
+
+ while (--nblock)
+ {
+ wrappy.w_d = dphase + CYCLE_TABSIZE * *in2++; /* CHECKED */
+ dphase += *in1++ * conv;
+ f1 = addr[0];
+ f2 = addr[1];
+ addr = tab + (wrappy.w_i[SHARED_HIOFFSET] & (CYCLE_TABSIZE-1));
+ wrappy.w_i[SHARED_HIOFFSET] = normhipart;
+ *out++ = f1 + frac * (f2 - f1);
+ frac = wrappy.w_d - SHARED_UNITBIT32;
+ }
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+
+ wrappy.w_d = SHARED_UNITBIT32 * CYCLE_TABSIZE;
+ normhipart = wrappy.w_i[SHARED_HIOFFSET];
+ wrappy.w_d = dphase + (SHARED_UNITBIT32 * CYCLE_TABSIZE - SHARED_UNITBIT32);
+ wrappy.w_i[SHARED_HIOFFSET] = normhipart;
+ x->x_phase = wrappy.w_d - (SHARED_UNITBIT32 * CYCLE_TABSIZE);
+ return (w + 6);
+}
+
+static void cycle_dsp(t_cycle *x, t_signal **sp)
+{
+ cycle_gettable(x);
+ x->x_conv = CYCLE_TABSIZE / sp[0]->s_sr;
+ dsp_add(cycle_perform, 5, x, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+}
+
+static void *cycle_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_cycle *x = (t_cycle *)pd_new(cycle_class);
+ int i = (ac && av->a_type == A_FLOAT ? 1 : 0);
+ int tabsize = CYCLE_TABSIZE;
+ x->x_costable = sic_makecostable(&tabsize);
+ if (tabsize != CYCLE_TABSIZE)
+ {
+ bug("cycle_new");
+ pd_free((t_pd *)x);
+ return (0);
+ }
+ if (ac && av->a_type == A_FLOAT)
+ {
+ sic_inlet((t_sic *)x, 0, 0, 0, ac, av);
+ ac--, av++;
+ }
+ sic_newinlet((t_sic *)x, 0);
+ outlet_new((t_object *)x, &s_signal);
+ x->x_offset = 0;
+ if (ac && av->a_type == A_SYMBOL)
+ {
+ x->x_name = av->a_w.w_symbol;
+ ac--, av++;
+ if (ac && av->a_type == A_FLOAT)
+ if ((x->x_offset = (int)av->a_w.w_float) < 0)
+ x->x_offset = 0;
+ }
+ else x->x_name = 0;
+ x->x_table = 0;
+ x->x_phase = 0.;
+ x->x_conv = 0.;
+ return (x);
+}
+
+void cycle_tilde_setup(void)
+{
+ cycle_class = class_new(gensym("cycle~"),
+ (t_newmethod)cycle_new, 0,
+ sizeof(t_cycle), 0, A_GIMME, 0);
+ sic_setup(cycle_class, cycle_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(cycle_class, (t_method)cycle_set,
+ gensym("set"), A_DEFSYMBOL, A_DEFFLOAT, 0);
+}
diff --git a/cyclone/sickle/delay.c b/cyclone/sickle/delay.c
new file mode 100644
index 0000000..b0ddd9d
--- /dev/null
+++ b/cyclone/sickle/delay.c
@@ -0,0 +1,101 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+typedef struct _delay
+{
+ t_sic x_sic;
+ t_float *x_buf;
+ t_float *x_bufend;
+ t_float *x_whead;
+ int x_maxsize;
+ int x_delsize;
+} t_delay;
+
+static t_class *delay_class;
+
+#define DELAY_DEFMAXSIZE 512
+
+static void delay_ft1(t_delay *x, t_floatarg f)
+{
+ x->x_delsize = (f > 0 ? (int)f : 0);
+ if (x->x_delsize > x->x_maxsize)
+ x->x_delsize = x->x_maxsize; /* CHECKED */
+ /* CHECKED: all buffered values should be available */
+}
+
+static t_int *delay_perform(t_int *w)
+{
+ t_delay *x = (t_delay *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ t_float *buf = x->x_buf;
+ t_float *ep = x->x_bufend;
+ t_float *wp = x->x_whead;
+ if (x->x_delsize)
+ {
+ t_float *rp = wp - x->x_delsize;
+ if (rp < buf) rp += x->x_maxsize;
+ while (nblock--)
+ {
+ float f = *in++;
+ *out++ = *rp;
+ if (rp++ == ep) rp = buf;
+ *wp = f;
+ if (wp++ == ep) wp = buf;
+ }
+ }
+ else while (nblock--)
+ {
+ *out++ = *wp = *in++;
+ if (wp++ == ep) wp = buf;
+ }
+ x->x_whead = wp;
+ return (w + 5);
+}
+
+static void delay_dsp(t_delay *x, t_signal **sp)
+{
+ memset(x->x_buf, 0, x->x_maxsize * sizeof(*x->x_buf)); /* CHECKED */
+ x->x_whead = x->x_buf;
+ dsp_add(delay_perform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void *delay_new(t_floatarg f1, t_floatarg f2)
+{
+ t_delay *x;
+ int maxsize = (f1 > 0 ? (int)f1 : DELAY_DEFMAXSIZE);
+ t_float *buf = (t_float *)getbytes(maxsize * sizeof(*buf));
+ if (!buf)
+ return (0);
+ x = (t_delay *)pd_new(delay_class);
+ x->x_maxsize = maxsize;
+ x->x_buf = x->x_whead = buf;
+ x->x_bufend = buf + maxsize - 1;
+ x->x_delsize = (f2 > 0 ? (int)f2 : 0);
+ if (x->x_delsize > maxsize)
+ x->x_delsize = maxsize;
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+static void delay_free(t_delay *x)
+{
+ if (x->x_buf) freebytes(x->x_buf, x->x_maxsize * sizeof(*x->x_buf));
+}
+
+void delay_tilde_setup(void)
+{
+ delay_class = class_new(gensym("delay~"),
+ (t_newmethod)delay_new, (t_method)delay_free,
+ sizeof(t_delay), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ sic_setup(delay_class, delay_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(delay_class, (t_method)delay_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
diff --git a/cyclone/sickle/delta.c b/cyclone/sickle/delta.c
new file mode 100644
index 0000000..145d6b7
--- /dev/null
+++ b/cyclone/sickle/delta.c
@@ -0,0 +1,52 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+typedef struct _delta
+{
+ t_sic x_sic;
+ t_float x_last;
+} t_delta;
+
+static t_class *delta_class;
+
+static t_int *delta_perform(t_int *w)
+{
+ t_delta *x = (t_delta *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ t_float last = x->x_last;
+ while (nblock--)
+ {
+ t_float f = *in++;
+ *out++ = f - last;
+ last = f;
+ }
+ x->x_last = last;
+ return (w + 5);
+}
+
+static void delta_dsp(t_delta *x, t_signal **sp)
+{
+ dsp_add(delta_perform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void *delta_new(void)
+{
+ t_delta *x = (t_delta *)pd_new(delta_class);
+ outlet_new((t_object *)x, &s_signal);
+ x->x_last = 0;
+ return (x);
+}
+
+void delta_tilde_setup(void)
+{
+ delta_class = class_new(gensym("delta~"),
+ (t_newmethod)delta_new, 0,
+ sizeof(t_delta), 0, 0);
+ sic_setup(delta_class, delta_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/deltaclip.c b/cyclone/sickle/deltaclip.c
new file mode 100644
index 0000000..89c9321
--- /dev/null
+++ b/cyclone/sickle/deltaclip.c
@@ -0,0 +1,67 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "shared.h"
+#include "sickle/sic.h"
+
+#define DELTACLIP_DEFLO 0.
+#define DELTACLIP_DEFHI 0.
+
+typedef struct _deltaclip
+{
+ t_sic x_sic;
+ t_float x_last;
+} t_deltaclip;
+
+static t_class *deltaclip_class;
+
+static t_int *deltaclip_perform(t_int *w)
+{
+ t_deltaclip *x = (t_deltaclip *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in1 = (t_float *)(w[3]);
+ t_float *in2 = (t_float *)(w[4]);
+ t_float *in3 = (t_float *)(w[5]);
+ t_float *out = (t_float *)(w[6]);
+ t_float last = x->x_last;
+ while (nblock--)
+ {
+ float f = *in1++;
+ float delta = f - last;
+ float lo = *in2++;
+ float hi = *in3++;
+ if (delta < lo)
+ f = last + lo;
+ else if (delta > hi)
+ f = last + hi;
+ *out++ = last = f;
+ }
+ x->x_last = last;
+ return (w + 7);
+}
+
+static void deltaclip_dsp(t_deltaclip *x, t_signal **sp)
+{
+ dsp_add(deltaclip_perform, 6, x, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec);
+}
+
+static void *deltaclip_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_deltaclip *x = (t_deltaclip *)pd_new(deltaclip_class);
+ sic_inlet((t_sic *)x, 1, DELTACLIP_DEFLO, 0, ac, av);
+ sic_inlet((t_sic *)x, 2, DELTACLIP_DEFHI, 1, ac, av);
+ outlet_new((t_object *)x, &s_signal);
+ x->x_last = 0;
+ return (x);
+}
+
+void deltaclip_tilde_setup(void)
+{
+ deltaclip_class = class_new(gensym("deltaclip~"),
+ (t_newmethod)deltaclip_new, 0,
+ sizeof(t_deltaclip), 0, A_GIMME, 0);
+ sic_setup(deltaclip_class, deltaclip_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/edge.c b/cyclone/sickle/edge.c
new file mode 100644
index 0000000..b206f6b
--- /dev/null
+++ b/cyclone/sickle/edge.c
@@ -0,0 +1,106 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+typedef struct _edge
+{
+ t_sic x_sic;
+ t_float x_last;
+ int x_zeroleft;
+ int x_zerohit;
+ t_outlet *x_out2;
+ t_clock *x_clock;
+} t_edge;
+
+static t_class *edge_class;
+
+static void edge_tick(t_edge *x)
+{
+ /* CHECKED both may fire simultaneously */
+ if (x->x_zeroleft)
+ {
+ outlet_bang(((t_object *)x)->ob_outlet);
+ x->x_zeroleft = 0;
+ }
+ if (x->x_zerohit)
+ {
+ outlet_bang(x->x_out2);
+ x->x_zerohit = 0;
+ }
+}
+
+static t_int *edge_perform(t_int *w)
+{
+ t_edge *x = (t_edge *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ t_float last = x->x_last;
+ while (nblock--)
+ {
+ float f = *in++;
+ if (last == 0.)
+ {
+ if (f != 0.)
+ {
+ x->x_zeroleft = 1;
+ if (x->x_zerohit)
+ {
+ clock_delay(x->x_clock, 0);
+ x->x_last = in[nblock - 1];
+ return (w + 4);
+ }
+ }
+ }
+ else
+ {
+ if (f == 0.)
+ {
+ x->x_zerohit = 1;
+ if (x->x_zeroleft)
+ {
+ clock_delay(x->x_clock, 0);
+ x->x_last = in[nblock - 1];
+ return (w + 4);
+ }
+ }
+ }
+ last = f;
+ }
+ if (x->x_zeroleft || x->x_zerohit) clock_delay(x->x_clock, 0);
+ x->x_last = last;
+ return (w + 4);
+}
+
+static void edge_dsp(t_edge *x, t_signal **sp)
+{
+ dsp_add(edge_perform, 3, x, sp[0]->s_n, sp[0]->s_vec);
+}
+
+static void edge_free(t_edge *x)
+{
+ if (x->x_clock) clock_free(x->x_clock);
+}
+
+static void *edge_new(t_floatarg f)
+{
+ t_edge *x = (t_edge *)pd_new(edge_class);
+ x->x_last = 0.; /* CHECKED fires at startup */
+ x->x_zeroleft = x->x_zerohit = 0;
+ outlet_new((t_object *)x, &s_bang);
+ x->x_out2 = outlet_new((t_object *)x, &s_bang);
+ x->x_clock = clock_new(x, (t_method)edge_tick);
+ return (x);
+}
+
+void edge_tilde_setup(void)
+{
+ edge_class = class_new(gensym("edge~"),
+ (t_newmethod)edge_new,
+ (t_method)edge_free,
+ sizeof(t_edge), 0,
+ A_DEFFLOAT, 0);
+ sic_setup(edge_class, edge_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/frameaccum.c b/cyclone/sickle/frameaccum.c
new file mode 100644
index 0000000..6038ae5
--- /dev/null
+++ b/cyclone/sickle/frameaccum.c
@@ -0,0 +1,71 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+#include "sickle/sic.h"
+
+#define FRAMEACCUM_INISIZE 512
+
+typedef struct _frameaccum
+{
+ t_sic x_sic;
+ int x_size;
+ t_float *x_frame;
+ t_float x_frameini[FRAMEACCUM_INISIZE];
+} t_frameaccum;
+
+static t_class *frameaccum_class;
+
+static t_int *frameaccum_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *frame = (t_float *)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ while (nblock--) *out++ = (*frame++ += *in++);
+ return (w + 5);
+}
+
+static void frameaccum_dsp(t_frameaccum *x, t_signal **sp)
+{
+ int nblock = sp[0]->s_n;
+ if (nblock > x->x_size)
+ x->x_frame = grow_nodata(&nblock, &x->x_size, x->x_frame,
+ FRAMEACCUM_INISIZE, x->x_frameini,
+ sizeof(*x->x_frame));
+ memset(x->x_frame, 0, nblock * sizeof(*x->x_frame)); /* CHECKED */
+ dsp_add(frameaccum_perform, 4, nblock, x->x_frame,
+ sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void frameaccum_free(t_frameaccum *x)
+{
+ if (x->x_frame != x->x_frameini)
+ freebytes(x->x_frame, x->x_size * sizeof(*x->x_frame));
+}
+
+static void *frameaccum_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_frameaccum *x = (t_frameaccum *)pd_new(frameaccum_class);
+ int size;
+ x->x_size = FRAMEACCUM_INISIZE;
+ x->x_frame = x->x_frameini;
+ if ((size = sys_getblksize()) > FRAMEACCUM_INISIZE)
+ x->x_frame = grow_nodata(&size, &x->x_size, x->x_frame,
+ FRAMEACCUM_INISIZE, x->x_frameini,
+ sizeof(*x->x_frame));
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void frameaccum_tilde_setup(void)
+{
+ frameaccum_class = class_new(gensym("frameaccum~"),
+ (t_newmethod)frameaccum_new,
+ (t_method)frameaccum_free,
+ sizeof(t_frameaccum), 0, 0);
+ sic_setup(frameaccum_class, frameaccum_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/framedelta.c b/cyclone/sickle/framedelta.c
new file mode 100644
index 0000000..b898444
--- /dev/null
+++ b/cyclone/sickle/framedelta.c
@@ -0,0 +1,76 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+#include "sickle/sic.h"
+
+#define FRAMEDELTA_INISIZE 512
+
+typedef struct _framedelta
+{
+ t_sic x_sic;
+ int x_size;
+ t_float *x_frame;
+ t_float x_frameini[FRAMEDELTA_INISIZE];
+} t_framedelta;
+
+static t_class *framedelta_class;
+
+static t_int *framedelta_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *frame = (t_float *)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ while (nblock--)
+ {
+ float f = *in++;
+ *out++ = f - *frame; /* CHECKME */
+ *frame++ = f;
+ }
+ return (w + 5);
+}
+
+static void framedelta_dsp(t_framedelta *x, t_signal **sp)
+{
+ int nblock = sp[0]->s_n;
+ if (nblock > x->x_size)
+ x->x_frame = grow_nodata(&nblock, &x->x_size, x->x_frame,
+ FRAMEDELTA_INISIZE, x->x_frameini,
+ sizeof(*x->x_frame));
+ memset(x->x_frame, 0, nblock * sizeof(*x->x_frame)); /* CHECKME */
+ dsp_add(framedelta_perform, 4, nblock, x->x_frame,
+ sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void framedelta_free(t_framedelta *x)
+{
+ if (x->x_frame != x->x_frameini)
+ freebytes(x->x_frame, x->x_size * sizeof(*x->x_frame));
+}
+
+static void *framedelta_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_framedelta *x = (t_framedelta *)pd_new(framedelta_class);
+ int size;
+ x->x_size = FRAMEDELTA_INISIZE;
+ x->x_frame = x->x_frameini;
+ if ((size = sys_getblksize()) > FRAMEDELTA_INISIZE)
+ x->x_frame = grow_nodata(&size, &x->x_size, x->x_frame,
+ FRAMEDELTA_INISIZE, x->x_frameini,
+ sizeof(*x->x_frame));
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void framedelta_tilde_setup(void)
+{
+ framedelta_class = class_new(gensym("framedelta~"),
+ (t_newmethod)framedelta_new,
+ (t_method)framedelta_free,
+ sizeof(t_framedelta), 0, 0);
+ sic_setup(framedelta_class, framedelta_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/index.c b/cyclone/sickle/index.c
new file mode 100644
index 0000000..036e6fb
--- /dev/null
+++ b/cyclone/sickle/index.c
@@ -0,0 +1,107 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* LATER: 'click' method */
+
+#include <string.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+#include "sickle/arsic.h"
+
+#define INDEX_MAXCHANNELS 4 /* LATER implement arsic resizing feature */
+
+typedef struct _index
+{
+ t_arsic x_arsic;
+ int x_maxchannels;
+ int x_effchannel; /* effective channel (clipped reqchannel) */
+ int x_reqchannel; /* requested channel */
+} t_index;
+
+static t_class *index_class;
+
+static void index_set(t_index *x, t_symbol *s)
+{
+ arsic_setarray((t_arsic *)x, s, 1);
+}
+
+static t_int *index_perform(t_int *w)
+{
+ t_arsic *sic = (t_arsic *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *out = (t_float *)(w[4]);
+ if (sic->s_playable)
+ {
+ t_index *x = (t_index *)sic;
+ t_float *xin = (t_float *)(w[3]);
+ int index, maxindex = sic->s_vecsize - 1;
+ t_float *vp = sic->s_vectors[x->x_effchannel];
+ if (vp) /* handle array swapping on the fly via ft1 */
+ {
+ while (nblock--)
+ {
+ index = (int)(*xin++ + 0.5);
+ if (index < 0)
+ index = 0;
+ else if (index > maxindex)
+ index = maxindex;
+ *out++ = vp[index];
+ }
+ }
+ else while (nblock--) *out++ = 0;
+ }
+ else while (nblock--) *out++ = 0;
+ return (w + 5);
+}
+
+static void index_ft1(t_index *x, t_floatarg f)
+{
+ if ((x->x_reqchannel = (f > 1 ? (int)f - 1 : 0)) > x->x_maxchannels)
+ x->x_effchannel = x->x_maxchannels - 1;
+ else
+ x->x_effchannel = x->x_reqchannel;
+}
+
+static void index_dsp(t_index *x, t_signal **sp)
+{
+ t_arsic *sic = (t_arsic *)x;
+ arsic_dsp(sic, sp, index_perform, sic->s_mononame != 0);
+}
+
+static void index_free(t_index *x)
+{
+ arsic_free((t_arsic *)x);
+}
+
+static void *index_new(t_symbol *s, t_floatarg f)
+{
+ int ch = (f > 0 ? (int)f : 0);
+ /* two signals: index input, value output */
+ t_index *x = (t_index *)arsic_new(index_class, s,
+ (ch ? INDEX_MAXCHANNELS : 0), 2, 0);
+ if (x)
+ {
+ if (ch > INDEX_MAXCHANNELS)
+ ch = INDEX_MAXCHANNELS;
+ x->x_maxchannels = (ch ? INDEX_MAXCHANNELS : 1);
+ x->x_effchannel = x->x_reqchannel = (ch ? ch - 1 : 0);
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_signal);
+ }
+ return (x);
+}
+
+void index_tilde_setup(void)
+{
+ index_class = class_new(gensym("index~"),
+ (t_newmethod)index_new,
+ (t_method)index_free,
+ sizeof(t_index), 0,
+ A_DEFSYM, A_DEFFLOAT, 0);
+ arsic_setup(index_class, index_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(index_class, (t_method)index_set,
+ gensym("set"), A_SYMBOL, 0);
+ class_addmethod(index_class, (t_method)index_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
diff --git a/cyclone/sickle/kink.c b/cyclone/sickle/kink.c
new file mode 100644
index 0000000..86bc81d
--- /dev/null
+++ b/cyclone/sickle/kink.c
@@ -0,0 +1,62 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* CHECKED negative float in 2nd inlet: "illegal slope value %f",
+ but no complaints for signal input -- this is impossible in Pd.
+ The only thing we could do (and a bit stupid one) would be to
+ clock this exception out from the perf routine. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+#define KINK_DEFSLOPE 1.0
+
+typedef t_sic t_kink;
+static t_class *kink_class;
+
+static t_int *kink_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ while (nblock--)
+ {
+ float iph = *in1++;
+ float slope = *in2++;
+ float oph = iph * slope;
+ if (oph > .5)
+ {
+ slope = 1. / (slope + slope); /* x(y=.5) */
+ if (slope == 1.)
+ *out++ = 0; /* CHECKED */
+ else
+ *out++ = (iph - slope) / (2. - (slope + slope)) + .5;
+ }
+ else *out++ = oph;
+ }
+ return (w + 5);
+}
+
+static void kink_dsp(t_kink *x, t_signal **sp)
+{
+ dsp_add(kink_perform, 4, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+}
+
+static void *kink_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_kink *x = (t_kink *)pd_new(kink_class);
+ sic_inlet((t_sic *)x, 1, KINK_DEFSLOPE, 0, ac, av);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void kink_tilde_setup(void)
+{
+ kink_class = class_new(gensym("kink~"),
+ (t_newmethod)kink_new, 0,
+ sizeof(t_kink), 0, A_GIMME, 0);
+ sic_setup(kink_class, kink_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/linedrive.c b/cyclone/sickle/linedrive.c
new file mode 100644
index 0000000..8b133ab
--- /dev/null
+++ b/cyclone/sickle/linedrive.c
@@ -0,0 +1,73 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* CHECKME polarity */
+
+#include <math.h>
+#include "m_pd.h"
+
+#if defined(NT) || defined(MACOSX)
+#define logf log
+#define expf exp
+#endif
+
+static t_class *linedrive_class;
+
+typedef struct _linedrive
+{
+ t_object x_ob;
+ t_float x_maxin;
+ t_float x_maxout;
+ t_float x_expcoef;
+ t_float x_lincoef;
+ t_atom x_vec[2];
+ int x_linear;
+} t_linedrive;
+
+static void linedrive_float(t_linedrive *x, t_floatarg f)
+{
+ float outval = f - x->x_maxin;
+ if (outval >= 0)
+ outval = x->x_maxout; /* CHECKED */
+ else if (x->x_linear)
+ outval = x->x_maxout + outval * x->x_lincoef;
+ else
+ outval = expf(outval * x->x_expcoef) * x->x_maxout;
+ SETFLOAT(x->x_vec, outval);
+ outlet_list(((t_object *)x)->ob_outlet, 0, 2, x->x_vec);
+}
+
+static void *linedrive_new(t_floatarg maxin, t_floatarg maxout,
+ t_floatarg curve, t_floatarg deltime)
+{
+ t_linedrive *x = (t_linedrive *)pd_new(linedrive_class);
+ x->x_maxin = (maxin < 1.0e-20f && maxin > -1e-20f ? 0 : maxin);
+ x->x_maxout = maxout;
+ if (curve < 1.0e-20f) curve = 1.0; /* a bug in msp? */
+ if (curve == 1.0)
+ {
+ x->x_expcoef = 0;
+ x->x_lincoef = (x->x_maxin == 0 ? 0 : x->x_maxout / x->x_maxin);
+ x->x_linear = 1;
+ }
+ else {
+ x->x_expcoef = logf(curve);
+ x->x_lincoef = 0;
+ x->x_linear = 0;
+ }
+ SETFLOAT(&x->x_vec[1], deltime); /* CHECKED: any value accepted */
+ floatinlet_new((t_object *)x, &x->x_vec[1].a_w.w_float);
+ outlet_new((t_object *)x, &s_list);
+ return (x);
+}
+
+void linedrive_setup(void)
+{
+ linedrive_class = class_new(gensym("linedrive"),
+ (t_newmethod)linedrive_new, 0,
+ sizeof(t_linedrive), 0,
+ A_DEFFLOAT, A_DEFFLOAT,
+ A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addfloat(linedrive_class, linedrive_float);
+}
diff --git a/cyclone/sickle/log.c b/cyclone/sickle/log.c
new file mode 100644
index 0000000..74e3e40
--- /dev/null
+++ b/cyclone/sickle/log.c
@@ -0,0 +1,74 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define logf log
+#endif
+
+#define LOG_MININPUT 1e-10 /* CHECKED */
+
+typedef struct _log
+{
+ t_sic x_sic;
+ t_float x_rcplogbase; /* LATER consider using double (and log()) */
+} t_log;
+
+static t_class *log_class;
+
+static void log_ft1(t_log *x, t_floatarg f)
+{
+ x->x_rcplogbase = (f == 0. ? 1. : /* CHECKED no protection against NaNs */
+ (f == 1. ? 0. : /* CHECKED */
+ 1. / logf(f)));
+}
+
+static t_int *log_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ t_float rcplogbase = *(t_float *)(w[4]);
+ if (rcplogbase != 0.)
+ {
+ while (nblock--)
+ {
+ float f = *in++;
+ if (f < LOG_MININPUT)
+ f = LOG_MININPUT; /* CHECKED */
+ *out++ = logf(f) * rcplogbase;
+ }
+ }
+ else while (nblock--) *out++ = 0.;
+ return (w + 5);
+}
+
+static void log_dsp(t_log *x, t_signal **sp)
+{
+ dsp_add(log_perform, 4, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec,
+ &x->x_rcplogbase);
+}
+
+static void *log_new(t_floatarg f)
+{
+ t_log *x = (t_log *)pd_new(log_class);
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_signal);
+ log_ft1(x, f);
+ return (x);
+}
+
+void log_tilde_setup(void)
+{
+ log_class = class_new(gensym("log~"),
+ (t_newmethod)log_new, 0,
+ sizeof(t_log), 0, A_DEFFLOAT, 0);
+ sic_setup(log_class, log_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(log_class, (t_method)log_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
diff --git a/cyclone/sickle/lookup.c b/cyclone/sickle/lookup.c
new file mode 100644
index 0000000..1c6a8af
--- /dev/null
+++ b/cyclone/sickle/lookup.c
@@ -0,0 +1,94 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* LATER reconsider making float/int conversions
+ more compatible (and less useful). */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+#include "sickle/arsic.h"
+
+typedef t_arsic t_lookup;
+static t_class *lookup_class;
+
+#define LOOKUP_DEFSIZE 512
+
+static void lookup_set(t_lookup *x, t_symbol *s)
+{
+ arsic_setarray((t_arsic *)x, s, 1);
+}
+
+static t_int *lookup_perform(t_int *w)
+{
+ t_arsic *sic = (t_arsic *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *out = (t_float *)(w[6]);
+ if (sic->s_playable)
+ {
+ t_float *xin = (t_float *)(w[3]);
+ t_float *oin = (t_float *)(w[4]);
+ t_float *sin = (t_float *)(w[5]);
+ int vecsize = sic->s_vecsize;
+ t_float *vec = sic->s_vectors[0]; /* playable implies nonzero (mono) */
+ while (nblock--)
+ {
+ float off = *oin++; /* msp: converted to int (if not a signal) */
+ int siz = (int)*sin++ - 1; /* msp: converted to int (signal too) */
+ float pos = (siz > 0 ? off + siz * (*xin++ + 1.0) * 0.5 : off);
+ int ndx = (int)pos;
+ int ndx1 = ndx + 1;
+ if (ndx1 > 0 && ndx1 < vecsize)
+ {
+ float val = vec[ndx];
+ *out++ = val + (vec[ndx1] - val) * (pos - ndx);
+ }
+ /* CHECKED: */
+ else if (ndx1 == 0) *out++ = *vec * (pos + 1.0);
+ else if (ndx1 == vecsize) *out++ = vec[ndx] * (ndx1 - pos);
+ else *out++ = 0;
+ }
+ }
+ else while (nblock--) *out++ = 0;
+ return (w + 7);
+}
+
+static void lookup_dsp(t_lookup *x, t_signal **sp)
+{
+ arsic_dsp((t_arsic *)x, sp, lookup_perform, 1);
+}
+
+static void lookup_free(t_lookup *x)
+{
+ arsic_free((t_arsic *)x);
+}
+
+static void *lookup_new(t_symbol *s, t_floatarg f1, t_floatarg f2)
+{
+ /* CHECKED: lookup~ always uses the first channel in a multi-channel buffer~
+ (as the refman says). */
+ /* three auxiliary signals: amplitude, offset and size inputs */
+ t_lookup *x = (t_lookup *)arsic_new(lookup_class, s, 0, 0, 3);
+ if (x)
+ {
+ arsic_setminsize((t_arsic *)x, 2);
+ if (f1 < 0) f1 = 0;
+ if (f2 <= 0) f2 = LOOKUP_DEFSIZE;
+ sic_newinlet((t_sic *)x, f1);
+ sic_newinlet((t_sic *)x, f2);
+ outlet_new((t_object *)x, &s_signal);
+ }
+ return (x);
+}
+
+void lookup_tilde_setup(void)
+{
+ lookup_class = class_new(gensym("lookup~"),
+ (t_newmethod)lookup_new,
+ (t_method)lookup_free,
+ sizeof(t_lookup), 0,
+ A_DEFSYM, A_DEFFLOAT, A_DEFFLOAT, 0);
+ arsic_setup(lookup_class, lookup_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(lookup_class, (t_method)lookup_set,
+ gensym("set"), A_SYMBOL, 0);
+}
diff --git a/cyclone/sickle/minmax.c b/cyclone/sickle/minmax.c
new file mode 100644
index 0000000..5bd0e39
--- /dev/null
+++ b/cyclone/sickle/minmax.c
@@ -0,0 +1,78 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+typedef struct _minmax
+{
+ t_sic x_sic;
+ t_float x_min;
+ t_float x_max;
+ t_outlet *x_minout;
+ t_outlet *x_maxout;
+} t_minmax;
+
+static t_class *minmax_class;
+
+static void minmax_bang(t_minmax *x)
+{
+ outlet_float(x->x_maxout, x->x_max);
+ outlet_float(x->x_minout, x->x_min);
+}
+
+static void minmax_reset(t_minmax *x)
+{
+ x->x_min = x->x_max = 0; /* CHECKME */
+}
+
+static t_int *minmax_perform(t_int *w)
+{
+ t_minmax *x = (t_minmax *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ t_float *outmin = (t_float *)(w[4]);
+ t_float *outmax = (t_float *)(w[5]);
+ t_float fmin = x->x_min;
+ t_float fmax = x->x_max;
+ while (nblock--)
+ {
+ t_float f = *in++;
+ if (f < fmin) fmin = f;
+ else if (f > fmax) fmax = f;
+ *outmin++ = fmin;
+ *outmax++ = fmax;
+ }
+ x->x_min = fmin;
+ x->x_max = fmax;
+ return (w + 6);
+}
+
+static void minmax_dsp(t_minmax *x, t_signal **sp)
+{
+ dsp_add(minmax_perform, 5, x, sp[0]->s_n, sp[0]->s_vec,
+ sp[1]->s_vec, sp[2]->s_vec);
+}
+
+static void *minmax_new(void)
+{
+ t_minmax *x = (t_minmax *)pd_new(minmax_class);
+ outlet_new((t_object *)x, &s_signal);
+ outlet_new((t_object *)x, &s_signal);
+ x->x_minout = outlet_new((t_object *)x, &s_float);
+ x->x_maxout = outlet_new((t_object *)x, &s_float);
+ minmax_reset(x);
+ return (x);
+}
+
+void minmax_tilde_setup(void)
+{
+ minmax_class = class_new(gensym("minmax~"),
+ (t_newmethod)minmax_new, 0,
+ sizeof(t_minmax), 0, 0);
+ sic_setup(minmax_class, minmax_dsp, SIC_FLOATTOSIGNAL);
+ class_addbang(minmax_class, minmax_bang);
+ class_addmethod(minmax_class, (t_method)minmax_reset,
+ gensym("reset"), 0);
+}
diff --git a/cyclone/sickle/peakamp.c b/cyclone/sickle/peakamp.c
new file mode 100644
index 0000000..67d1093
--- /dev/null
+++ b/cyclone/sickle/peakamp.c
@@ -0,0 +1,107 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+typedef struct _peakamp
+{
+ t_sic x_sic;
+ t_float x_value;
+ int x_nwait;
+ int x_nleft;
+ int x_precount;
+ float x_waittime;
+ float x_ksr;
+ t_clock *x_clock;
+} t_peakamp;
+
+static t_class *peakamp_class;
+
+static void peakamp_tick(t_peakamp *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_value);
+ x->x_value = 0;
+ if ((x->x_nleft = x->x_nwait - x->x_precount) < 0) /* CHECKME */
+ x->x_nleft = 0;
+}
+
+static void peakamp_bang(t_peakamp *x)
+{
+ peakamp_tick(x); /* CHECKME */
+}
+
+static void peakamp_ft1(t_peakamp *x, t_floatarg f)
+{
+ if ((x->x_waittime = f) < 0.)
+ x->x_waittime = 0.;
+ if ((x->x_nwait = (int)(x->x_waittime * x->x_ksr)) < 0)
+ x->x_nwait = 0;
+}
+
+static t_int *peakamp_perform(t_int *w)
+{
+ t_peakamp *x = (t_peakamp *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ t_float value = x->x_value;
+ if (x->x_nwait)
+ {
+ if (x->x_nleft < nblock)
+ {
+ clock_delay(x->x_clock, 0);
+ x->x_precount = nblock - x->x_nleft;
+ x->x_nleft = 0; /* LATER rethink */
+ }
+ else x->x_nleft -= nblock;
+ }
+ while (nblock--)
+ {
+ t_float f = *in++;
+ if (f > value)
+ value = f;
+ else if (f < -value)
+ value = -f;
+ }
+ x->x_value = value;
+ return (w + 4);
+}
+
+static void peakamp_dsp(t_peakamp *x, t_signal **sp)
+{
+ x->x_ksr = sp[0]->s_sr * 0.001;
+ x->x_nwait = (int)(x->x_waittime * x->x_ksr);
+ dsp_add(peakamp_perform, 3, x, sp[0]->s_n, sp[0]->s_vec);
+}
+
+static void peakamp_free(t_peakamp *x)
+{
+ if (x->x_clock) clock_free(x->x_clock);
+}
+
+static void *peakamp_new(t_floatarg f)
+{
+ t_peakamp *x = (t_peakamp *)pd_new(peakamp_class);
+ x->x_value = 0.;
+ x->x_nleft = 0;
+ x->x_ksr = sys_getsr() * 0.001;
+ peakamp_ft1(x, f);
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_float);
+ x->x_clock = clock_new(x, (t_method)peakamp_tick);
+ return (x);
+}
+
+void peakamp_tilde_setup(void)
+{
+ peakamp_class = class_new(gensym("peakamp~"),
+ (t_newmethod)peakamp_new,
+ (t_method)peakamp_free,
+ sizeof(t_peakamp), 0,
+ A_DEFFLOAT, 0);
+ sic_setup(peakamp_class, peakamp_dsp, SIC_FLOATTOSIGNAL);
+ class_addbang(peakamp_class, peakamp_bang);
+ class_addmethod(peakamp_class, (t_method)peakamp_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
diff --git a/cyclone/sickle/peek.c b/cyclone/sickle/peek.c
new file mode 100644
index 0000000..7397577
--- /dev/null
+++ b/cyclone/sickle/peek.c
@@ -0,0 +1,147 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* LATER: 'click' method */
+
+#include <string.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+#include "sickle/arsic.h"
+
+#define PEEK_MAXCHANNELS 4 /* LATER implement arsic resizing feature */
+
+typedef struct _peek
+{
+ t_arsic x_arsic;
+ int x_maxchannels;
+ int x_effchannel; /* effective channel (clipped reqchannel) */
+ int x_reqchannel; /* requested channel */
+ int x_clipmode;
+ int x_pokemode;
+ t_float x_value;
+ t_clock *x_clock;
+ double x_clocklasttick;
+ int x_clockset;
+} t_peek;
+
+static t_class *peek_class;
+
+static void peek_tick(t_peek *x)
+{
+ arsic_redraw((t_arsic *)x); /* LATER redraw only dirty channel(s!) */
+ x->x_clockset = 0;
+ x->x_clocklasttick = clock_getsystime();
+}
+
+static void peek_set(t_peek *x, t_symbol *s)
+{
+ arsic_setarray((t_arsic *)x, s, 1);
+}
+
+#define peek_doclip(f) (f < -1. ? -1. : (f > 1. ? 1. : f))
+
+/* CHECKED refman error: ``if the number received in the left inlet
+ specifies a sample index that does not exist in the buffer~ object's
+ currently allocated memory, nothing happens.'' This is plainly wrong,
+ at least for max/msp 4.0.7 bundle: the index is clipped (just like
+ in tabread/tabwrite). As a kind of an experiment, lets make this
+ the refman's way... */
+static void peek_float(t_peek *x, t_float f)
+{
+ t_arsic *sic = (t_arsic *)x;
+ t_float *vp;
+ arsic_validate(sic, 0); /* LATER rethink (efficiency, and complaining) */
+ if (vp = sic->s_vectors[x->x_effchannel])
+ {
+ int ndx = (int)f;
+ if (vp && ndx >= 0 && ndx < sic->s_vecsize)
+ {
+ if (x->x_pokemode)
+ {
+ double timesince;
+ t_float f = x->x_value;
+ vp[ndx] = (x->x_clipmode ? peek_doclip(f) : f);
+ x->x_pokemode = 0;
+ timesince = clock_gettimesince(x->x_clocklasttick);
+ if (timesince > 1000) peek_tick(x);
+ else if (!x->x_clockset)
+ {
+ clock_delay(x->x_clock, 1000 - timesince);
+ x->x_clockset = 1;
+ }
+ }
+ /* CHECKED: output not clipped */
+ else outlet_float(((t_object *)x)->ob_outlet, vp[ndx]);
+ }
+ }
+}
+
+static void peek_ft1(t_peek *x, t_floatarg f)
+{
+ x->x_value = f;
+ x->x_pokemode = 1;
+ /* CHECKED: poke-mode is reset only after receiving left inlet input
+ -- it is kept across 'ft2', 'clip', and 'set' inputs. */
+}
+
+static void peek_ft2(t_peek *x, t_floatarg f)
+{
+ if ((x->x_reqchannel = (f > 1 ? (int)f - 1 : 0)) > x->x_maxchannels)
+ x->x_effchannel = x->x_maxchannels - 1;
+ else
+ x->x_effchannel = x->x_reqchannel;
+}
+
+static void peek_clip(t_peek *x, t_floatarg f)
+{
+ x->x_clipmode = ((int)f != 0);
+}
+
+static void peek_free(t_peek *x)
+{
+ if (x->x_clock) clock_free(x->x_clock);
+ arsic_free((t_arsic *)x);
+}
+
+static void *peek_new(t_symbol *s, t_floatarg f1, t_floatarg f2)
+{
+ int ch = (f1 > 0 ? (int)f1 : 0);
+ t_peek *x = (t_peek *)arsic_new(peek_class, s,
+ (ch ? PEEK_MAXCHANNELS : 0), 0, 0);
+ if (x)
+ {
+ if (ch > PEEK_MAXCHANNELS)
+ ch = PEEK_MAXCHANNELS;
+ x->x_maxchannels = (ch ? PEEK_MAXCHANNELS : 1);
+ x->x_effchannel = x->x_reqchannel = (ch ? ch - 1 : 0);
+ /* CHECKED (refman error) clipping is disabled by default */
+ x->x_clipmode = ((int)f2 != 0);
+ x->x_pokemode = 0;
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft2"));
+ outlet_new((t_object *)x, &s_float);
+ x->x_clock = clock_new(x, (t_method)peek_tick);
+ x->x_clocklasttick = clock_getsystime();
+ x->x_clockset = 0;
+ }
+ return (x);
+}
+
+void peek_tilde_setup(void)
+{
+ peek_class = class_new(gensym("peek~"),
+ (t_newmethod)peek_new,
+ (t_method)peek_free,
+ sizeof(t_peek), 0,
+ A_DEFSYM, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addfloat(peek_class, peek_float);
+ class_addmethod(peek_class, (t_method)peek_set,
+ gensym("set"), A_SYMBOL, 0);
+ class_addmethod(peek_class, (t_method)peek_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(peek_class, (t_method)peek_ft2,
+ gensym("ft2"), A_FLOAT, 0);
+ class_addmethod(peek_class, (t_method)peek_clip,
+ gensym("clip"), A_FLOAT, 0);
+}
diff --git a/cyclone/sickle/phasewrap.c b/cyclone/sickle/phasewrap.c
new file mode 100644
index 0000000..535d5e8
--- /dev/null
+++ b/cyclone/sickle/phasewrap.c
@@ -0,0 +1,131 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+#include "shared.h"
+#include "sickle/sic.h"
+
+typedef struct _phasewrap
+{
+ t_sic x_sic;
+ int x_algo;
+} t_phasewrap;
+
+static t_class *phasewrap_class;
+
+static t_int *phasewrap_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ t_shared_wrappy wrappy;
+ while (nblock--)
+ {
+ /* FIXME here we have pi -> pi, 3pi -> -pi, -pi -> -pi, -3pi -> pi,
+ while in msp it is pi -> -pi, 3pi -> -pi, -pi -> pi, -3pi -> pi */
+
+ double dnorm = *in++ * (1. / SHARED_2PI);
+ wrappy.w_d = dnorm + SHARED_UNITBIT0;
+ /* Speeding up the int-to-double conversion below would be nice,
+ but all attempts failed. Even this is slower (which works only
+ for nonnegative input):
+
+ wrappy.w_i[SHARED_HIOFFSET] = SHARED_UNITBIT0_HIPART;
+ *out++ = (dnorm - (wrappy.w_d - SHARED_UNITBIT0)) * SHARED_2PI;
+ */
+ dnorm -= wrappy.w_i[SHARED_LOWOFFSET];
+ *out++ = dnorm * SHARED_2PI;
+ }
+ return (w + 4);
+}
+
+/* This is the slowest algo. It is slower than fmod in all cases,
+ except for input being zero. */
+static t_int *phasewrap_perform1(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ while (nblock--)
+ {
+ float f = *in++;
+ double dnorm;
+ if (f < -SHARED_PI)
+ {
+ dnorm = (double)f * (1. / SHARED_2PI) + .5;
+ *out++ = (dnorm - (int)dnorm) * SHARED_2PI + SHARED_PI;
+ }
+ else if (f > SHARED_PI)
+ {
+ dnorm = (double)f * (1. / SHARED_2PI) + .5;
+ *out++ = (dnorm - (int)dnorm) * SHARED_2PI - SHARED_PI;
+ }
+ else *out++ = f;
+ }
+ return (w + 4);
+}
+
+static t_int *phasewrap_perform2(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ while (nblock--)
+ {
+ double dnorm = *in++ + SHARED_PI;
+ if (dnorm < 0)
+ *out++ = SHARED_PI - fmod(-dnorm, SHARED_2PI);
+ else
+ *out++ = fmod(dnorm, SHARED_2PI) - SHARED_PI;
+ }
+ return (w + 4);
+}
+
+static void phasewrap_dsp(t_phasewrap *x, t_signal **sp)
+{
+ switch (x->x_algo)
+ {
+ case 1:
+ dsp_add(phasewrap_perform1, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+ break;
+ case 2:
+ dsp_add(phasewrap_perform2, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+ break;
+ default:
+ dsp_add(phasewrap_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+ }
+}
+
+static void phasewrap__algo(t_phasewrap *x, t_floatarg f)
+{
+ x->x_algo = f;
+}
+
+static void *phasewrap_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_phasewrap *x = (t_phasewrap *)pd_new(phasewrap_class);
+ if (s == gensym("_phasewrap1~"))
+ x->x_algo = 1;
+ else if (s == gensym("_phasewrap2~"))
+ x->x_algo = 2;
+ else
+ x->x_algo = 0;
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void phasewrap_tilde_setup(void)
+{
+ phasewrap_class = class_new(gensym("phasewrap~"),
+ (t_newmethod)phasewrap_new, 0,
+ sizeof(t_phasewrap), 0, A_GIMME, 0);
+ class_addcreator((t_newmethod)phasewrap_new,
+ gensym("_phasewrap1~"), A_GIMME, 0);
+ class_addcreator((t_newmethod)phasewrap_new,
+ gensym("_phasewrap2~"), A_GIMME, 0);
+ sic_setup(phasewrap_class, phasewrap_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(phasewrap_class, (t_method)phasewrap__algo,
+ gensym("_algo"), A_FLOAT, 0);
+}
diff --git a/cyclone/sickle/play.c b/cyclone/sickle/play.c
new file mode 100644
index 0000000..9d2c303
--- /dev/null
+++ b/cyclone/sickle/play.c
@@ -0,0 +1,122 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+#include "sickle/arsic.h"
+
+/* CHECKME (the refman): if the buffer~ has more channels, channels are mixed */
+
+typedef t_arsic t_play;
+static t_class *play_class;
+
+static void play_set(t_play *x, t_symbol *s)
+{
+ arsic_setarray((t_arsic *)x, s, 1);
+}
+
+/* LATER optimize */
+static t_int *play_perform(t_int *w)
+{
+ t_arsic *sic = (t_arsic *)(w[1]);
+ int nblock = (int)(w[2]);
+ int nch = sic->s_nchannels;
+ t_int *outp = w + 4;
+ if (sic->s_playable)
+ {
+ t_play *x = (t_play *)sic;
+ t_float *xin = (t_float *)(w[3]);
+ int vecsize = sic->s_vecsize;
+ t_float **vectable = sic->s_vectors;
+ float ksr = sic->s_ksr;
+ int nointerp = 0;
+ int maxindex = (nointerp ? vecsize - 1 : vecsize - 3);
+ int iblock;
+
+ for (iblock = 0; iblock < nblock; iblock++)
+ {
+ float phase = *xin++ * ksr;
+ int ndx;
+ int ch = nch;
+ float frac, a, b, c, d, cminusb;
+ if (phase < 0 || phase > maxindex)
+ phase = 0; /* CHECKED: a value 0, not ndx 0 */
+ ndx = (int)phase;
+ /* CHECKME: what kind of interpolation? (CHECKED: multi-point) */
+ if (ndx < 1)
+ ndx = 1, frac = 0;
+ else if (ndx > maxindex)
+ ndx = maxindex, frac = 1;
+ else frac = phase - ndx;
+ while (ch--)
+ {
+ t_float *vp = vectable[ch];
+ t_float *out = (t_float *)(outp[ch]);
+ if (vp)
+ {
+ vp += ndx;
+ a = vp[-1];
+ b = vp[0];
+ c = vp[1];
+ d = vp[2];
+ cminusb = c-b;
+ out[iblock] = b + frac * (
+ cminusb - 0.1666667f * (1. - frac) * (
+ (d - a - 3.0f * cminusb) * frac
+ + (d + 2.0f * a - 3.0f * b)
+ )
+ );
+ }
+ else out[iblock] = 0;
+ }
+ }
+ }
+ else
+ {
+ int ch = nch;
+ while (ch--)
+ {
+ t_float *out = (t_float *)outp[ch];
+ int n = nblock;
+ while (n--) *out++ = 0;
+ }
+ }
+ return (w + sic->s_nperfargs + 1);
+}
+
+static void play_dsp(t_play *x, t_signal **sp)
+{
+ arsic_dsp((t_arsic *)x, sp, play_perform, 1);
+}
+
+static void play_free(t_play *x)
+{
+ arsic_free((t_arsic *)x);
+}
+
+static void *play_new(t_symbol *s, t_floatarg f)
+{
+ /* one auxiliary signal: position input */
+ t_play *x = (t_play *)arsic_new(play_class, s, (int)f, 0, 1);
+ if (x)
+ {
+ int nch = arsic_getnchannels((t_arsic *)x);
+ while (nch--)
+ outlet_new((t_object *)x, &s_signal);
+ }
+ return (x);
+}
+
+void play_tilde_setup(void)
+{
+ play_class = class_new(gensym("play~"),
+ (t_newmethod)play_new,
+ (t_method)play_free,
+ sizeof(t_play), 0,
+ A_DEFSYM, A_DEFFLOAT, 0);
+ arsic_setup(play_class, play_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(play_class, (t_method)play_set,
+ gensym("set"), A_SYMBOL, 0);
+}
diff --git a/cyclone/sickle/poltocar.c b/cyclone/sickle/poltocar.c
new file mode 100644
index 0000000..8d7f94c
--- /dev/null
+++ b/cyclone/sickle/poltocar.c
@@ -0,0 +1,79 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+#include "unstable/fragile.h"
+#include "sickle/sic.h"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define sinf sin
+#define cosf cos
+#endif
+
+typedef struct _poltocar
+{
+ t_sic x_sic;
+ t_outlet *x_out2;
+} t_poltocar;
+
+static t_class *poltocar_class;
+
+static t_int *poltocar_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out1 = (t_float *)(w[4]);
+ t_float *out2 = (t_float *)(w[5]);
+ while (nblock--)
+ {
+ float am = *in1++, ph = *in2++;
+ *out1++ = am * cosf(ph);
+ *out2++ = -am * sinf(ph); /* CHECKED */
+ }
+ return (w + 6);
+}
+
+static t_int *poltocar_perform_noimag(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out1 = (t_float *)(w[4]);
+ while (nblock--)
+ {
+ float am = *in1++, ph = *in2++;
+ *out1++ = am * cosf(ph);
+ }
+ return (w + 5);
+}
+
+static void poltocar_dsp(t_poltocar *x, t_signal **sp)
+{
+ if (fragile_outlet_connections(x->x_out2))
+ dsp_add(poltocar_perform, 5, sp[0]->s_n, sp[0]->s_vec,
+ sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec);
+ else
+ dsp_add(poltocar_perform_noimag, 4, sp[0]->s_n, sp[0]->s_vec,
+ sp[1]->s_vec, sp[2]->s_vec);
+}
+
+static void *poltocar_new(void)
+{
+ t_poltocar *x = (t_poltocar *)pd_new(poltocar_class);
+ inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal);
+ outlet_new((t_object *)x, &s_signal);
+ x->x_out2 = outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void poltocar_tilde_setup(void)
+{
+ poltocar_class = class_new(gensym("poltocar~"),
+ (t_newmethod)poltocar_new, 0,
+ sizeof(t_poltocar), 0, 0);
+ sic_setup(poltocar_class, poltocar_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/pow.c b/cyclone/sickle/pow.c
new file mode 100644
index 0000000..11cd508
--- /dev/null
+++ b/cyclone/sickle/pow.c
@@ -0,0 +1,54 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define powf pow
+#endif
+
+typedef t_sic t_pow;
+static t_class *pow_class;
+
+static t_int *pow_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ while (nblock--)
+ {
+ float f1 = *in1++;
+ float f2 = *in2++;
+ /* CHECKED arg order, no protection against NaNs (negative base),
+ under-, and overflows */
+ *out++ = powf(f2, f1);
+ }
+ return (w + 5);
+}
+
+static void pow_dsp(t_pow *x, t_signal **sp)
+{
+ dsp_add(pow_perform, 4, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+}
+
+static void *pow_new(t_floatarg f)
+{
+ t_pow *x = (t_pow *)pd_new(pow_class);
+ sic_newinlet((t_sic *)x, f); /* CHECKED default 0 */
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void pow_tilde_setup(void)
+{
+ pow_class = class_new(gensym("pow~"),
+ (t_newmethod)pow_new, 0,
+ sizeof(t_pow), 0, A_DEFFLOAT, 0);
+ sic_setup(pow_class, pow_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/rampsmooth.c b/cyclone/sickle/rampsmooth.c
new file mode 100644
index 0000000..c2023d8
--- /dev/null
+++ b/cyclone/sickle/rampsmooth.c
@@ -0,0 +1,206 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+#define RAMPSMOOTH_GEOMETRIC /* geometric series (same as slide~) CHECKED */
+#ifndef RAMPSMOOTH_GEOMETRIC
+#define RAMPSMOOTH_LINEAR
+#endif
+#define RAMPSMOOTH_DEFNUP 0.
+#define RAMPSMOOTH_DEFNDOWN 0.
+
+typedef struct _rampsmooth
+{
+ t_sic x_sic;
+ int x_nup;
+ int x_ndown;
+ double x_upcoef;
+ double x_downcoef;
+ t_float x_last;
+#ifdef RAMPSMOOTH_LINEAR
+ t_float x_target;
+ double x_incr;
+ int x_nleft;
+#endif
+} t_rampsmooth;
+
+static t_class *rampsmooth_class;
+
+#ifdef RAMPSMOOTH_LINEAR
+/* this is a true linear ramper */
+static t_int *rampsmooth_perform(t_int *w)
+{
+ t_rampsmooth *x = (t_rampsmooth *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ t_float last = x->x_last;
+ t_float target = x->x_target;
+ double incr = x->x_incr;
+ int nleft = x->x_nleft;
+ while (nblock--)
+ {
+ t_float f = *in++;
+ if (f != target)
+ {
+ target = f;
+ if (f > last)
+ {
+ if (x->x_nup > 1)
+ {
+ incr = (f - last) * x->x_upcoef;
+ nleft = x->x_nup;
+ *out++ = (last += incr);
+ continue;
+ }
+ }
+ else if (f < last)
+ {
+ if (x->x_ndown > 1)
+ {
+ incr = (f - last) * x->x_downcoef;
+ nleft = x->x_ndown;
+ *out++ = (last += incr);
+ continue;
+ }
+ }
+ incr = 0.;
+ nleft = 0;
+ *out++ = last = f;
+ }
+ else if (nleft > 0)
+ {
+ *out++ = (last += incr);
+ if (--nleft == 0)
+ {
+ incr = 0.;
+ last = target;
+ }
+ }
+ else *out++ = target;
+ }
+ x->x_last = last;
+ x->x_target = target;
+ x->x_incr = incr;
+ x->x_nleft = nleft;
+ return (w + 5);
+}
+
+#else
+
+/* this ramper generates a geometric series output for a single step input */
+static t_int *rampsmooth_perform(t_int *w)
+{
+ t_rampsmooth *x = (t_rampsmooth *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ t_float last = x->x_last;
+ while (nblock--)
+ {
+ t_float f = *in++;
+ if (f > last)
+ {
+ if (x->x_nup > 1)
+ {
+ *out++ = (last += (f - last) * x->x_upcoef);
+ continue;
+ }
+ }
+ else if (f < last)
+ {
+ if (x->x_ndown > 1)
+ {
+ *out++ = (last += (f - last) * x->x_downcoef);
+ continue;
+ }
+ }
+ *out++ = last = f;
+ }
+ x->x_last = last;
+ return (w + 5);
+}
+#endif
+
+static void rampsmooth_dsp(t_rampsmooth *x, t_signal **sp)
+{
+ dsp_add(rampsmooth_perform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void rampsmooth_rampup(t_rampsmooth *x, t_floatarg f)
+{
+ int i = (int)f;
+ if (i > 1) /* CHECKME if 1 and 0 differ in any way */
+ {
+ x->x_nup = i;
+ x->x_upcoef = 1. / (float)i;
+ }
+ else
+ {
+ x->x_nup = 0;
+ x->x_upcoef = 0.;
+ }
+}
+
+static void rampsmooth_rampdown(t_rampsmooth *x, t_floatarg f)
+{
+ int i = (int)f;
+ if (i > 1) /* CHECKME if 1 and 0 differ in any way */
+ {
+ x->x_ndown = i;
+ x->x_downcoef = 1. / (float)i;
+ }
+ else
+ {
+ x->x_ndown = 0;
+ x->x_downcoef = 0.;
+ }
+}
+
+/* CHECKED */
+static void rampsmooth_ramp(t_rampsmooth *x, t_floatarg f)
+{
+ rampsmooth_rampup(x, f);
+ rampsmooth_rampdown(x, f);
+}
+
+static void *rampsmooth_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_rampsmooth *x = (t_rampsmooth *)pd_new(rampsmooth_class);
+ float f1 = RAMPSMOOTH_DEFNUP;
+ float f2 = RAMPSMOOTH_DEFNDOWN;
+ if (ac && av->a_type == A_FLOAT)
+ {
+ f1 = av->a_w.w_float;
+ ac--; av++;
+ if (ac && av->a_type == A_FLOAT)
+ f2 = av->a_w.w_float;
+ }
+ rampsmooth_rampup(x, f1);
+ rampsmooth_rampdown(x, f2);
+ x->x_last = 0.;
+#ifdef RAMPSMOOTH_LINEAR
+ x->x_target = 0.;
+ x->x_incr = 0.;
+ x->x_nleft = 0;
+#endif
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void rampsmooth_tilde_setup(void)
+{
+ rampsmooth_class = class_new(gensym("rampsmooth~"),
+ (t_newmethod)rampsmooth_new, 0,
+ sizeof(t_rampsmooth), 0, A_GIMME, 0);
+ sic_setup(rampsmooth_class, rampsmooth_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(rampsmooth_class, (t_method)rampsmooth_rampup,
+ gensym("rampup"), A_FLOAT, 0);
+ class_addmethod(rampsmooth_class, (t_method)rampsmooth_rampdown,
+ gensym("rampdown"), A_FLOAT, 0);
+ class_addmethod(rampsmooth_class, (t_method)rampsmooth_ramp,
+ gensym("ramp"), A_FLOAT, 0);
+}
diff --git a/cyclone/sickle/rand.c b/cyclone/sickle/rand.c
new file mode 100644
index 0000000..146cbc9
--- /dev/null
+++ b/cyclone/sickle/rand.c
@@ -0,0 +1,95 @@
+/* Copyright (c) 1997-2003 Miller Puckette, krzYszcz, and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* This is a compilation of phasor~ and noise~ code from d_osc.c. */
+
+#include "m_pd.h"
+#include "shared.h"
+#include "sickle/sic.h"
+
+typedef struct _rand
+{
+ t_sic x_sic;
+ t_float x_rate;
+ double x_lastphase;
+ double x_nextphase;
+ float x_rcpsr;
+ int x_state;
+ float x_target;
+ float x_scaling; /* LATER use phase increment */
+} t_rand;
+
+static t_class *rand_class;
+
+static t_int *rand_perform(t_int *w)
+{
+ t_rand *x = (t_rand *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *rin = (t_float *)(w[3]);
+ t_float *out = (t_float *)(w[4]);
+ double lastph = x->x_lastphase;
+ double ph = x->x_nextphase;
+ double tfph = ph + SHARED_UNITBIT32;
+ t_shared_wrappy wrappy;
+ int32 normhipart;
+ float rcpsr = x->x_rcpsr;
+ float target = x->x_target;
+ float scaling = x->x_scaling;
+
+ wrappy.w_d = SHARED_UNITBIT32;
+ normhipart = wrappy.w_i[SHARED_HIOFFSET];
+
+ while (nblock--)
+ {
+ float rate = *rin++;
+ if (ph > lastph)
+ {
+ int state = x->x_state;
+ float newtarget = ((float)((state & 0x7fffffff) - 0x40000000))
+ * (float)(1.0 / 0x40000000);
+ x->x_state = state * 435898247 + 382842987;
+ x->x_scaling = scaling = target - newtarget;
+ x->x_target = target = newtarget;
+ }
+ *out++ = ph * scaling + target;
+ lastph = ph;
+ if (rate > 0) rate = -rate;
+ tfph += rate * rcpsr;
+ wrappy.w_d = tfph;
+ wrappy.w_i[SHARED_HIOFFSET] = normhipart;
+ ph = wrappy.w_d - SHARED_UNITBIT32;
+ }
+ x->x_lastphase = lastph;
+ x->x_nextphase = ph;
+ return (w + 5);
+}
+
+static void rand_dsp(t_rand *x, t_signal **sp)
+{
+ x->x_rcpsr = 1. / sp[0]->s_sr;
+ dsp_add(rand_perform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void *rand_new(t_floatarg inirate)
+{
+ t_rand *x = (t_rand *)pd_new(rand_class);
+ /* borrowed from d_osc.c, LATER rethink */
+ static int init = 307;
+ x->x_state = (init *= 1319);
+ x->x_lastphase = 0.;
+ x->x_nextphase = 1.; /* start from 0, force retargetting */
+ x->x_target = x->x_scaling = 0;
+ x->x_rate = (inirate > 0 ? -inirate : 0);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void rand_tilde_setup(void)
+{
+ rand_class = class_new(gensym("rand~"),
+ (t_newmethod)rand_new, 0,
+ sizeof(t_rand), 0,
+ A_DEFFLOAT, 0);
+ sic_setup(rand_class, rand_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/record.c b/cyclone/sickle/record.c
new file mode 100644
index 0000000..ba2e3b5
--- /dev/null
+++ b/cyclone/sickle/record.c
@@ -0,0 +1,242 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "shared.h"
+#include "sickle/sic.h"
+#include "sickle/arsic.h"
+
+typedef struct _record
+{
+ t_arsic x_arsic;
+ float x_startpoint; /* the inputs */
+ float x_endpoint;
+ int x_appendmode;
+ int x_loopmode;
+ int x_startindex;
+ int x_endindex; /* (one past last record position) */
+ int x_pauseindex;
+ int x_phase; /* writing head */
+ float x_sync;
+ float x_syncincr;
+ int x_isrunning; /* to know if sync should be 0.0 or 1.0 */
+ t_clock *x_clock;
+} t_record;
+
+static t_class *record_class;
+
+static void record_tick(t_record *x)
+{
+ arsic_redraw((t_arsic *)x);
+}
+
+static void record_setsync(t_record *x)
+{
+ /* CHECKED: clipped to array size -- using indices, not points */
+ float range = (float)(x->x_endindex - x->x_startindex);
+ int phase = x->x_phase;
+ if (phase == SHARED_INT_MAX || range < 1.0)
+ {
+ x->x_sync = (x->x_isrunning ? 1.0 : 0); /* CHECKED */
+ x->x_syncincr = 0;
+ }
+ else
+ {
+ x->x_sync = (float)(phase - x->x_startindex) / range;
+ x->x_syncincr = 1.0 / range;
+ }
+}
+
+static void record_mstoindex(t_record *x)
+{
+ t_arsic *sic = (t_arsic *)x;
+ x->x_startindex = (int)(x->x_startpoint * sic->s_ksr);
+ if (x->x_startindex < 0)
+ x->x_startindex = 0; /* CHECKED */
+ x->x_endindex = (int)(x->x_endpoint * sic->s_ksr);
+ if (x->x_endindex > sic->s_vecsize
+ || x->x_endindex <= 0)
+ x->x_endindex = sic->s_vecsize; /* CHECKED (both ways) */
+ record_setsync(x);
+}
+
+static void record_set(t_record *x, t_symbol *s)
+{
+ arsic_setarray((t_arsic *)x, s, 1);
+ record_mstoindex(x);
+}
+
+static void record_startpoint(t_record *x, t_floatarg f)
+{
+ x->x_startpoint = f;
+ record_mstoindex(x);
+}
+
+static void record_endpoint(t_record *x, t_floatarg f)
+{
+ x->x_endpoint = f;
+ record_mstoindex(x);
+}
+
+static void record_float(t_record *x, t_float f)
+{
+ if (x->x_isrunning = (f != 0))
+ {
+ /* CHECKED: no (re)start in append mode */
+ /* LATER consider restart if x->x_pauseindex == SHARED_INT_MAX */
+ x->x_phase = x->x_appendmode ? x->x_pauseindex : x->x_startindex;
+ if (x->x_phase >= x->x_endindex) x->x_phase = SHARED_INT_MAX;
+ }
+ else if (x->x_phase != SHARED_INT_MAX) /* CHECKED: no rewind */
+ {
+ record_tick(x);
+ x->x_pauseindex = x->x_phase;
+ x->x_phase = SHARED_INT_MAX;
+ }
+ record_setsync(x);
+}
+
+static void record_append(t_record *x, t_floatarg f)
+{
+ if (f != 0)
+ {
+ x->x_appendmode = 1; /* CHECKED: always allow appending */
+ }
+ else x->x_appendmode = 0;
+}
+
+static void record_loop(t_record *x, t_floatarg f)
+{
+ x->x_loopmode = (f != 0);
+}
+
+static t_int *record_perform(t_int *w)
+{
+ t_arsic *sic = (t_arsic *)(w[1]);
+ int nblock = (int)(w[2]);
+ int nch = sic->s_nchannels;
+ t_float *out = (t_float *)(w[3 + nch]);
+ t_record *x = (t_record *)sic;
+ int phase = x->x_phase;
+ int endphase = x->x_endindex;
+ float sync = x->x_sync;
+ if (sic->s_playable && endphase > phase)
+ {
+ int vecsize = sic->s_vecsize;
+ float syncincr = x->x_syncincr;
+ int ch, over, i, nxfer;
+loopover:
+ if ((nxfer = endphase - phase) > nblock)
+ {
+ nxfer = nblock;
+ over = 0;
+ }
+ else over = 1;
+ ch = nch;
+ while (ch--)
+ {
+ t_float *vp = sic->s_vectors[ch];
+ if (vp)
+ {
+ t_float *ip = (t_float *)(w[3 + ch]);
+ vp += phase;
+ i = nxfer;
+ /* LATER consider handling under and overflows */
+ while (i--) *vp++ = *ip++;
+ }
+ }
+ i = nxfer;
+ while (i--)
+ {
+ *out++ = sync;
+ sync += syncincr;
+ }
+ if (over)
+ {
+ nblock -= nxfer;
+ if (x->x_loopmode
+ && (phase = x->x_startindex) < endphase)
+ {
+ x->x_phase = phase;
+ x->x_sync = sync = 0;
+ if (nblock > 0) goto loopover;
+ goto done;
+ }
+ clock_delay(x->x_clock, 0);
+ /* CHECKED: no restart in append mode */
+ x->x_pauseindex = SHARED_INT_MAX;
+ x->x_phase = SHARED_INT_MAX;
+ x->x_sync = 1.0;
+ x->x_syncincr = 0;
+ }
+ else
+ {
+ x->x_phase += nxfer;
+ x->x_sync = sync;
+ goto done;
+ }
+ }
+ while (nblock--) *out++ = sync;
+done:
+ return (w + sic->s_nperfargs + 1);
+}
+
+static void record_dsp(t_record *x, t_signal **sp)
+{
+ arsic_dsp((t_arsic *)x, sp, record_perform, 1);
+ record_mstoindex(x);
+}
+
+static void record_free(t_record *x)
+{
+ arsic_free((t_arsic *)x);
+ if (x->x_clock) clock_free(x->x_clock);
+}
+
+static void *record_new(t_symbol *s, t_floatarg f)
+{
+ /* one auxiliary signal: sync output */
+ t_record *x = (t_record *)arsic_new(record_class, s, (int)f, 0, 1);
+ if (x)
+ {
+ int nch = arsic_getnchannels((t_arsic *)x);
+ arsic_setminsize((t_arsic *)x, 2);
+ x->x_startpoint = 0;
+ x->x_endpoint = 0;
+ x->x_appendmode = 0;
+ x->x_loopmode = 0;
+ x->x_pauseindex = SHARED_INT_MAX;
+ x->x_phase = SHARED_INT_MAX;
+ x->x_isrunning = 0;
+ record_mstoindex(x);
+ x->x_clock = clock_new(x, (t_method)record_tick);
+ while (--nch)
+ inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal);
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft-2"));
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft-1"));
+ outlet_new((t_object *)x, &s_signal);
+ }
+ return (x);
+}
+
+void record_tilde_setup(void)
+{
+ record_class = class_new(gensym("record~"),
+ (t_newmethod)record_new,
+ (t_method)record_free,
+ sizeof(t_record), 0,
+ A_DEFSYM, A_DEFFLOAT, 0);
+ arsic_setup(record_class, record_dsp, record_float);
+ class_addmethod(record_class, (t_method)record_startpoint,
+ gensym("ft-2"), A_FLOAT, 0);
+ class_addmethod(record_class, (t_method)record_endpoint,
+ gensym("ft-1"), A_FLOAT, 0);
+ class_addmethod(record_class, (t_method)record_append,
+ gensym("append"), A_FLOAT, 0);
+ class_addmethod(record_class, (t_method)record_loop,
+ gensym("loop"), A_FLOAT, 0);
+ class_addmethod(record_class, (t_method)record_set,
+ gensym("set"), A_SYMBOL, 0);
+}
diff --git a/cyclone/sickle/sah.c b/cyclone/sickle/sah.c
new file mode 100644
index 0000000..afac1e0
--- /dev/null
+++ b/cyclone/sickle/sah.c
@@ -0,0 +1,70 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+typedef struct _sah
+{
+ t_sic x_sic;
+ t_float x_threshold;
+ t_float x_lastin;
+ t_float x_lastout;
+} t_sah;
+
+static t_class *sah_class;
+
+static t_int *sah_perform(t_int *w)
+{
+ t_sah *x = (t_sah *)(w[1]);
+ int nblock = (t_int)(w[2]);
+ t_float *in1 = (t_float *)(w[3]);
+ t_float *in2 = (t_float *)(w[4]);
+ t_float *out = (t_float *)(w[5]);
+ t_float threshold = x->x_threshold;
+ t_float lastin = x->x_lastin;
+ t_float lastout = x->x_lastout;
+ while (nblock--)
+ {
+ float f = *in2++;
+ if (lastin <= threshold && f > threshold) /* CHECKME <=, > */
+ lastout = *in1;
+ in1++;
+ lastin = f;
+ *out++ = lastout;
+ }
+ x->x_lastin = lastin;
+ x->x_lastout = lastout;
+ return (w + 6);
+}
+
+static void sah_dsp(t_sah *x, t_signal **sp)
+{
+ dsp_add(sah_perform, 5, x, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+}
+
+static void sah_float(t_sah *x, t_float f)
+{
+ x->x_threshold = f;
+}
+
+static void *sah_new(t_floatarg f)
+{
+ t_sah *x = (t_sah *)pd_new(sah_class);
+ x->x_threshold = f;
+ x->x_lastin = 0;
+ x->x_lastout = 0;
+ inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void sah_tilde_setup(void)
+{
+ sah_class = class_new(gensym("sah~"),
+ (t_newmethod)sah_new, 0,
+ sizeof(t_sah), 0, A_DEFFLOAT, 0);
+ sic_setup(sah_class, sah_dsp, sah_float);
+}
diff --git a/cyclone/sickle/sickle.c b/cyclone/sickle/sickle.c
new file mode 100644
index 0000000..765209a
--- /dev/null
+++ b/cyclone/sickle/sickle.c
@@ -0,0 +1,93 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <stdio.h>
+#include "m_pd.h"
+#include "unstable/fragile.h"
+#include "common/loud.h"
+#include "common/port.h"
+#include "hammer/file.h"
+#include "../build_counter"
+void allsickles_setup(void);
+
+typedef struct _sickle
+{
+ t_object x_ob;
+ t_symbol *x_dir;
+ t_hammerfile *x_filehandle;
+} t_sickle;
+
+static t_class *sickle_class;
+static int sickle_firstndx;
+static int sickle_lastndx;
+
+static void sickle_readhook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ import_max(fn->s_name, "");
+}
+
+static void sickle_import(t_sickle *x, t_symbol *fn, t_symbol *dir)
+{
+ if (fn && fn != &s_)
+ {
+ if (!dir || dir == &s_) dir = x->x_dir;
+ import_max(fn->s_name, (dir && dir != &s_) ? dir->s_name : "");
+ }
+ else
+ hammerpanel_open(x->x_filehandle);
+}
+
+static void sickle_click(t_sickle *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ sickle_import(x, 0, 0);
+}
+
+static void sickle_bang(t_sickle *x)
+{
+ fragile_class_printnames("sickle classes are: ",
+ sickle_firstndx, sickle_lastndx);
+}
+
+static void sickle_free(t_sickle *x)
+{
+ hammerfile_free(x->x_filehandle);
+}
+
+static void *sickle_new(t_symbol *s)
+{
+ t_sickle *x = (t_sickle *)pd_new(sickle_class);
+ x->x_filehandle = hammerfile_new((t_pd *)x, 0, sickle_readhook, 0, 0);
+ x->x_dir = (s && s != &s_ ? s : canvas_getdir(x->x_filehandle->f_canvas));
+ return (x);
+}
+
+void sickle_setup(void)
+{
+ if (canvas_getcurrent())
+ {
+ /* Loading the library by object creation is banned, because of a danger
+ of having some of the classes already loaded. LATER rethink. */
+ loud_error(0, "apparently an attempt to create a 'sickle' object");
+ loud_errand(0, "without having sickle library preloaded");
+ return;
+ }
+ if (!zgetfn(&pd_objectmaker, gensym("cyclone")))
+ post("this is sickle %s, %s %s build",
+ CYCLONE_VERSION, loud_ordinal(CYCLONE_BUILD), CYCLONE_RELEASE);
+ sickle_class = class_new(gensym("sickle"),
+ (t_newmethod)sickle_new,
+ (t_method)sickle_free,
+ sizeof(t_sickle), 0, A_DEFSYM, 0);
+ class_addbang(sickle_class, sickle_bang);
+ class_addmethod(sickle_class, (t_method)sickle_import,
+ gensym("import"), A_DEFSYM, A_DEFSYM, 0);
+ class_addmethod(sickle_class, (t_method)sickle_click,
+ gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ hammerfile_setup(sickle_class, 0);
+ sickle_firstndx = fragile_class_count();
+ allsickles_setup();
+ sickle_lastndx = fragile_class_count() - 1;
+}
diff --git a/cyclone/sickle/sinh.c b/cyclone/sickle/sinh.c
new file mode 100644
index 0000000..523c28a
--- /dev/null
+++ b/cyclone/sickle/sinh.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define sinhf sinh
+#endif
+
+typedef t_sic t_sinh;
+static t_class *sinh_class;
+
+static t_int *sinh_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ while (nblock--)
+ {
+ float f = *in++;
+ *out++ = sinhf(f); /* CHECKME no protection against overflow */
+ }
+ return (w + 4);
+}
+
+static void sinh_dsp(t_sinh *x, t_signal **sp)
+{
+ dsp_add(sinh_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void *sinh_new(void)
+{
+ t_sinh *x = (t_sinh *)pd_new(sinh_class);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void sinh_tilde_setup(void)
+{
+ sinh_class = class_new(gensym("sinh~"),
+ (t_newmethod)sinh_new, 0,
+ sizeof(t_sinh), 0, 0);
+ sic_setup(sinh_class, sinh_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/sinx.c b/cyclone/sickle/sinx.c
new file mode 100644
index 0000000..b303024
--- /dev/null
+++ b/cyclone/sickle/sinx.c
@@ -0,0 +1,51 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+/* by definition, this is just an interface to the -lm call
+ (do not use costable) */
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define sinf sin
+#endif
+
+typedef t_sic t_sinx;
+static t_class *sinx_class;
+
+static t_int *sinx_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ while (nblock--)
+ {
+ float f = *in++;
+ *out++ = sinf(f);
+ }
+ return (w + 4);
+}
+
+static void sinx_dsp(t_sinx *x, t_signal **sp)
+{
+ dsp_add(sinx_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void *sinx_new(void)
+{
+ t_sinx *x = (t_sinx *)pd_new(sinx_class);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void sinx_tilde_setup(void)
+{
+ sinx_class = class_new(gensym("sinx~"),
+ (t_newmethod)sinx_new, 0,
+ sizeof(t_sinx), 0, 0);
+ sic_setup(sinx_class, sinx_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/slide.c b/cyclone/sickle/slide.c
new file mode 100644
index 0000000..92001b2
--- /dev/null
+++ b/cyclone/sickle/slide.c
@@ -0,0 +1,77 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+#define SLIDE_DEFUP 1.
+#define SLIDE_DEFDN 1.
+
+typedef struct _slide
+{
+ t_sic x_sic;
+ t_float x_last;
+} t_slide;
+
+static t_class *slide_class;
+
+static t_int *slide_perform(t_int *w)
+{
+ t_slide *x = (t_slide *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in1 = (t_float *)(w[3]);
+ t_float *in2 = (t_float *)(w[4]);
+ t_float *in3 = (t_float *)(w[5]);
+ t_float *out = (t_float *)(w[6]);
+ t_float last = x->x_last;
+ while (nblock--)
+ {
+ float f = *in1++;
+ if (f > last)
+ {
+ float up = *in2++;
+ if (up > 1.) /* CHECKED */
+ last += (f - last) / up;
+ else
+ last = f;
+ in3++;
+ }
+ else if (f < last)
+ {
+ float dn = *in3++;
+ if (dn > 1.) /* CHECKED */
+ last += (f - last) / dn;
+ else
+ last = f;
+ in2++;
+ }
+ *out++ = last;
+ }
+ x->x_last = last;
+ return (w + 7);
+}
+
+static void slide_dsp(t_slide *x, t_signal **sp)
+{
+ dsp_add(slide_perform, 6, x, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec);
+}
+
+static void *slide_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_slide *x = (t_slide *)pd_new(slide_class);
+ sic_inlet((t_sic *)x, 1, SLIDE_DEFUP, 0, ac, av);
+ sic_inlet((t_sic *)x, 2, SLIDE_DEFDN, 1, ac, av);
+ outlet_new((t_object *)x, &s_signal);
+ x->x_last = 0;
+ return (x);
+}
+
+void slide_tilde_setup(void)
+{
+ slide_class = class_new(gensym("slide~"),
+ (t_newmethod)slide_new, 0,
+ sizeof(t_slide), 0, A_GIMME, 0);
+ sic_setup(slide_class, slide_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/spike.c b/cyclone/sickle/spike.c
new file mode 100644
index 0000000..13f9361
--- /dev/null
+++ b/cyclone/sickle/spike.c
@@ -0,0 +1,109 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+typedef struct _spike
+{
+ t_sic x_sic;
+ t_float x_last;
+ int x_count;
+ int x_precount;
+ int x_nwait;
+ float x_waittime;
+ float x_ksr;
+ float x_rcpksr;
+ t_clock *x_clock;
+} t_spike;
+
+static t_class *spike_class;
+
+static void spike_tick(t_spike *x)
+{
+ outlet_float(((t_object *)x)->ob_outlet, x->x_count * x->x_rcpksr);
+ x->x_count = x->x_precount;
+}
+
+static void spike_ft1(t_spike *x, t_floatarg f)
+{
+ if ((x->x_waittime = f) < 0.)
+ x->x_waittime = 0.;
+ x->x_nwait = (int)(x->x_waittime * x->x_ksr);
+}
+
+static t_int *spike_perform(t_int *w)
+{
+ t_spike *x = (t_spike *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in = (t_float *)(w[3]);
+ t_float last = x->x_last;
+ int count = x->x_count;
+ int nwait = x->x_nwait;
+ if (count + nblock > nwait)
+ {
+ /* LATER efficiency tricks */
+ while (nblock--)
+ {
+ float f = *in++;
+ if (last == 0. && f != 0. /* CHECKED zero-to-nonzero */
+ && count /* CHECKED no firing at startup */
+ && count >= nwait)
+ {
+ clock_delay(x->x_clock, 0);
+ x->x_last = in[nblock - 1];
+ x->x_count = count;
+ x->x_precount = nblock;
+ return (w + 4);
+ }
+ count++;
+ last = f;
+ }
+ x->x_last = last;
+ x->x_count = count;
+ }
+ else
+ {
+ x->x_last = in[nblock - 1];
+ x->x_count += nblock;
+ }
+ return (w + 4);
+}
+
+static void spike_dsp(t_spike *x, t_signal **sp)
+{
+ x->x_ksr = sp[0]->s_sr * 0.001;
+ x->x_rcpksr = 1000.0 / sp[0]->s_sr;
+ x->x_nwait = (int)(x->x_waittime * x->x_ksr);
+ dsp_add(spike_perform, 3, x, sp[0]->s_n, sp[0]->s_vec);
+}
+
+static void spike_free(t_spike *x)
+{
+ if (x->x_clock) clock_free(x->x_clock);
+}
+
+static void *spike_new(t_floatarg f)
+{
+ t_spike *x = (t_spike *)pd_new(spike_class);
+ x->x_last = 0.;
+ x->x_ksr = sys_getsr() * 0.001;
+ spike_ft1(x, f);
+ inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1"));
+ outlet_new((t_object *)x, &s_float);
+ x->x_clock = clock_new(x, (t_method)spike_tick);
+ return (x);
+}
+
+void spike_tilde_setup(void)
+{
+ spike_class = class_new(gensym("spike~"),
+ (t_newmethod)spike_new,
+ (t_method)spike_free,
+ sizeof(t_spike), 0,
+ A_DEFFLOAT, 0);
+ sic_setup(spike_class, spike_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(spike_class, (t_method)spike_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
diff --git a/cyclone/sickle/tanh.c b/cyclone/sickle/tanh.c
new file mode 100644
index 0000000..7473dcf
--- /dev/null
+++ b/cyclone/sickle/tanh.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define tanhf tanh
+#endif
+
+typedef t_sic t_tanh;
+static t_class *tanh_class;
+
+static t_int *tanh_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ while (nblock--)
+ {
+ float f = *in++;
+ *out++ = tanhf(f); /* CHECKME no protection against overflow */
+ }
+ return (w + 4);
+}
+
+static void tanh_dsp(t_tanh *x, t_signal **sp)
+{
+ dsp_add(tanh_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void *tanh_new(void)
+{
+ t_tanh *x = (t_tanh *)pd_new(tanh_class);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void tanh_tilde_setup(void)
+{
+ tanh_class = class_new(gensym("tanh~"),
+ (t_newmethod)tanh_new, 0,
+ sizeof(t_tanh), 0, 0);
+ sic_setup(tanh_class, tanh_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/tanx.c b/cyclone/sickle/tanx.c
new file mode 100644
index 0000000..d2a1102
--- /dev/null
+++ b/cyclone/sickle/tanx.c
@@ -0,0 +1,51 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <math.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+/* by definition, this is just an interface to the -lm call
+ (do not use costable) */
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define tanf tan
+#endif
+
+typedef t_sic t_tanx;
+static t_class *tanx_class;
+
+static t_int *tanx_perform(t_int *w)
+{
+ int nblock = (int)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ while (nblock--)
+ {
+ float f = *in++;
+ *out++ = tanf(f);
+ }
+ return (w + 4);
+}
+
+static void tanx_dsp(t_tanx *x, t_signal **sp)
+{
+ dsp_add(tanx_perform, 3, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec);
+}
+
+static void *tanx_new(void)
+{
+ t_tanx *x = (t_tanx *)pd_new(tanx_class);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+}
+
+void tanx_tilde_setup(void)
+{
+ tanx_class = class_new(gensym("tanx~"),
+ (t_newmethod)tanx_new, 0,
+ sizeof(t_tanx), 0, 0);
+ sic_setup(tanx_class, tanx_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/train.c b/cyclone/sickle/train.c
new file mode 100644
index 0000000..b07ba9a
--- /dev/null
+++ b/cyclone/sickle/train.c
@@ -0,0 +1,117 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "shared.h"
+#include "sickle/sic.h"
+
+#define TRAIN_DEFPERIOD 1000
+#define TRAIN_DEFWIDTH 0.5
+#define TRAIN_DEFOFFSET 0
+
+typedef struct _train
+{
+ t_sic x_sic;
+ int x_on;
+ double x_phase;
+ float x_rcpksr;
+ t_outlet *x_bangout;
+ t_clock *x_clock;
+} t_train;
+
+static t_class *train_class;
+
+static void train_tick(t_train *x)
+{
+ outlet_bang(x->x_bangout);
+}
+
+static t_int *train_perform(t_int *w)
+{
+ t_train *x = (t_train *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in1 = (t_float *)(w[3]);
+ t_float *in2 = (t_float *)(w[4]);
+ t_float *in3 = (t_float *)(w[5]);
+ t_float *out = (t_float *)(w[6]);
+ float rcpksr = x->x_rcpksr;
+ double ph = x->x_phase;
+ double tfph = ph + SHARED_UNITBIT32;
+ t_shared_wrappy wrappy;
+ int32 normhipart;
+ int on = x->x_on;
+ int edge = 0;
+
+ wrappy.w_d = SHARED_UNITBIT32;
+ normhipart = wrappy.w_i[SHARED_HIOFFSET];
+
+ while (nblock--)
+ {
+ double onph, offph;
+ float period = *in1++;
+
+ wrappy.w_d = *in3++ + SHARED_UNITBIT32;
+ wrappy.w_i[SHARED_HIOFFSET] = normhipart;
+ onph = wrappy.w_d - SHARED_UNITBIT32;
+
+ wrappy.w_d = onph + *in2++ + SHARED_UNITBIT32;
+ wrappy.w_i[SHARED_HIOFFSET] = normhipart;
+ offph = wrappy.w_d - SHARED_UNITBIT32;
+
+ if (offph > onph ? ph < offph && ph >= onph : ph < offph || ph >= onph)
+ {
+ if (!on) on = edge = 1;
+ *out++ = 1.;
+ }
+ else
+ {
+ on = 0;
+ *out++ = 0.;
+ }
+ if (period > rcpksr) /* LATER rethink */
+ tfph += rcpksr / period; /* LATER revisit (profiling?) */
+ wrappy.w_d = tfph;
+ wrappy.w_i[SHARED_HIOFFSET] = normhipart;
+ ph = wrappy.w_d - SHARED_UNITBIT32;
+ }
+ x->x_phase = ph;
+ x->x_on = on;
+ if (edge) clock_delay(x->x_clock, 0);
+ return (w + 7);
+}
+
+static void train_dsp(t_train *x, t_signal **sp)
+{
+ x->x_rcpksr = 1000. / sp[0]->s_sr;
+ dsp_add(train_perform, 6, x, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec);
+}
+
+static void train_free(t_train *x)
+{
+ if (x->x_clock) clock_free(x->x_clock);
+}
+
+static void *train_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_train *x = (t_train *)pd_new(train_class);
+ x->x_on = 0;
+ x->x_phase = 0;
+ sic_inlet((t_sic *)x, 0, TRAIN_DEFPERIOD, 0, ac, av);
+ sic_inlet((t_sic *)x, 1, TRAIN_DEFWIDTH, 1, ac, av);
+ sic_inlet((t_sic *)x, 2, TRAIN_DEFOFFSET, 2, ac, av);
+ outlet_new((t_object *)x, &s_signal);
+ x->x_bangout = outlet_new((t_object *)x, &s_bang);
+ x->x_clock = clock_new(x, (t_method)train_tick);
+ return (x);
+}
+
+void train_tilde_setup(void)
+{
+ train_class = class_new(gensym("train~"),
+ (t_newmethod)train_new,
+ (t_method)train_free,
+ sizeof(t_train), 0, A_GIMME, 0);
+ sic_setup(train_class, train_dsp, SIC_FLOATTOSIGNAL);
+}
diff --git a/cyclone/sickle/trapezoid.c b/cyclone/sickle/trapezoid.c
new file mode 100644
index 0000000..b33cb02
--- /dev/null
+++ b/cyclone/sickle/trapezoid.c
@@ -0,0 +1,105 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+#define TRAPEZOID_DEFUP 0.1 /* a bug? */
+#define TRAPEZOID_DEFDN 0.9 /* a bug? */
+#define TRAPEZOID_DEFLO 0.0
+#define TRAPEZOID_DEFHI 1.0
+
+typedef struct _trapezoid
+{
+ t_sic x_sic;
+ float x_low;
+ float x_range;
+} t_trapezoid;
+
+static t_class *trapezoid_class;
+
+static void trapezoid_lo(t_trapezoid *x, t_floatarg f)
+{
+ float high = x->x_low + x->x_range;
+ x->x_low = f;
+ x->x_range = high - x->x_low;
+}
+
+static void trapezoid_hi(t_trapezoid *x, t_floatarg f)
+{
+ x->x_range = f - x->x_low;
+}
+
+/* LATER optimize */
+static t_int *trapezoid_perform(t_int *w)
+{
+ t_trapezoid *x = (t_trapezoid *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in1 = (t_float *)(w[3]);
+ t_float *in2 = (t_float *)(w[4]);
+ t_float *in3 = (t_float *)(w[5]);
+ t_float *out = (t_float *)(w[6]);
+ float low = x->x_low;
+ float range = x->x_range;
+ while (nblock--)
+ {
+ float ph = *in1++;
+ float upph = *in2++;
+ float dnph = *in3++;
+ /* CHECKED ph wrapped */
+ if (ph < 0.)
+ ph -= (int)ph - 1.;
+ else if (ph > 1.)
+ ph -= (int)ph;
+ /* CHECKED upph, dnph clipped */
+ if (upph < 0.)
+ upph = 0.;
+ else if (upph > 1.) /* CHECKME */
+ upph = 1.;
+ if (dnph < upph)
+ dnph = upph;
+ else if (dnph > 1.)
+ dnph = 1.;
+
+ if (ph < upph)
+ ph /= upph;
+ else if (ph < dnph)
+ ph = 1.;
+ else if (dnph < 1.)
+ ph = (1. - ph) / (1. - dnph);
+ else
+ ph = 0.;
+ *out++ = low + ph * range;
+ }
+ return (w + 7);
+}
+
+static void trapezoid_dsp(t_trapezoid *x, t_signal **sp)
+{
+ dsp_add(trapezoid_perform, 6, x, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec);
+}
+
+static void *trapezoid_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_trapezoid *x = (t_trapezoid *)pd_new(trapezoid_class);
+ sic_inlet((t_sic *)x, 1, TRAPEZOID_DEFUP, 0, ac, av);
+ sic_inlet((t_sic *)x, 2, TRAPEZOID_DEFDN, 1, ac, av);
+ outlet_new((t_object *)x, &s_signal);
+ x->x_low = TRAPEZOID_DEFLO;
+ x->x_range = (TRAPEZOID_DEFHI - TRAPEZOID_DEFLO);
+ return (x);
+}
+
+void trapezoid_tilde_setup(void)
+{
+ trapezoid_class = class_new(gensym("trapezoid~"),
+ (t_newmethod)trapezoid_new, 0,
+ sizeof(t_trapezoid), 0, A_GIMME, 0);
+ sic_setup(trapezoid_class, trapezoid_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(trapezoid_class, (t_method)trapezoid_lo,
+ gensym("lo"), A_DEFFLOAT, 0); /* CHECKME */
+ class_addmethod(trapezoid_class, (t_method)trapezoid_hi,
+ gensym("hi"), A_DEFFLOAT, 0); /* CHECKME */
+}
diff --git a/cyclone/sickle/triangle.c b/cyclone/sickle/triangle.c
new file mode 100644
index 0000000..703e5ba
--- /dev/null
+++ b/cyclone/sickle/triangle.c
@@ -0,0 +1,95 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+#define TRIANGLE_DEFPHASE 0.5
+#define TRIANGLE_DEFLO -1.0
+#define TRIANGLE_DEFHI 1.0
+
+typedef struct _triangle
+{
+ t_sic x_sic;
+ float x_low;
+ float x_range;
+} t_triangle;
+
+static t_class *triangle_class;
+
+static void triangle_lo(t_triangle *x, t_floatarg f)
+{
+ float high = x->x_low + x->x_range;
+ x->x_low = f;
+ x->x_range = high - x->x_low;
+}
+
+static void triangle_hi(t_triangle *x, t_floatarg f)
+{
+ x->x_range = f - x->x_low;
+}
+
+/* LATER optimize */
+static t_int *triangle_perform(t_int *w)
+{
+ t_triangle *x = (t_triangle *)(w[1]);
+ int nblock = (int)(w[2]);
+ t_float *in1 = (t_float *)(w[3]);
+ t_float *in2 = (t_float *)(w[4]);
+ t_float *out = (t_float *)(w[5]);
+ float low = x->x_low;
+ float range = x->x_range;
+ while (nblock--)
+ {
+ float ph = *in1++;
+ float peakph = *in2++;
+ /* CHECKED ph wrapped */
+ if (ph < 0.)
+ ph -= (int)ph - 1.;
+ else if (ph > 1.)
+ ph -= (int)ph;
+ /* CHECKED peakph clipped */
+ if (peakph < 0.)
+ peakph = 0.;
+ else if (peakph > 1.)
+ peakph = 1.;
+
+ if (ph < peakph)
+ ph /= peakph;
+ else if (peakph < 1.)
+ ph = (1. - ph) / (1. - peakph);
+ else
+ ph = 0.;
+ *out++ = low + ph * range;
+ }
+ return (w + 6);
+}
+
+static void triangle_dsp(t_triangle *x, t_signal **sp)
+{
+ dsp_add(triangle_perform, 5, x, sp[0]->s_n,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);
+}
+
+static void *triangle_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_triangle *x = (t_triangle *)pd_new(triangle_class);
+ sic_inlet((t_sic *)x, 1, TRIANGLE_DEFPHASE, 0, ac, av);
+ outlet_new((t_object *)x, &s_signal);
+ x->x_low = TRIANGLE_DEFLO;
+ x->x_range = (TRIANGLE_DEFHI - TRIANGLE_DEFLO);
+ return (x);
+}
+
+void triangle_tilde_setup(void)
+{
+ triangle_class = class_new(gensym("triangle~"),
+ (t_newmethod)triangle_new, 0,
+ sizeof(t_triangle), 0, A_GIMME, 0);
+ sic_setup(triangle_class, triangle_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(triangle_class, (t_method)triangle_lo,
+ gensym("lo"), A_DEFFLOAT, 0); /* CHECKED */
+ class_addmethod(triangle_class, (t_method)triangle_hi,
+ gensym("hi"), A_DEFFLOAT, 0); /* CHECKED */
+}
diff --git a/cyclone/sickle/vectral.c b/cyclone/sickle/vectral.c
new file mode 100644
index 0000000..b9cdf69
--- /dev/null
+++ b/cyclone/sickle/vectral.c
@@ -0,0 +1,235 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "sickle/sic.h"
+
+#define VECTRAL_DEFSIZE 512
+
+struct _vectral;
+typedef void (*t_vectral_perform)(struct _vectral *, int,
+ t_float *, t_float *, t_float *, t_float *);
+
+typedef struct _vectral
+{
+ t_sic x_sic;
+ t_vectral_perform x_perform;
+ int x_bufsize;
+ t_float *x_buffer;
+ t_float *x_lastframe;
+ /* rampsmooth and slide state */
+ double x_upcoef;
+ double x_downcoef;
+ /* deltaclip state */
+ float x_lo;
+ float x_hi;
+} t_vectral;
+
+static t_class *vectral_class;
+
+/* LATER after any modification make sure about syncing other variants
+ of perform routine to the bypassing version */
+/* this is: for i in [0..nblock) buf[in2[i]] = in3[i], out[i] = buf[in1[i]] */
+static void vectral_perform_bypass(t_vectral *x, int nblock,
+ t_float *in1, t_float *in2, t_float *in3,
+ t_float *out)
+{
+ t_float *buf = x->x_buffer;
+ int bufsize = x->x_bufsize;
+ t_float *last = x->x_lastframe;
+ int blocksize = nblock;
+ while (nblock--)
+ {
+ int indx = (int)*in2++;
+ /* CHECKED buffer not zeroed out (the buffer's garbage remains) */
+ if (indx >= 0 && indx < bufsize)
+ buf[indx] = *in3;
+ in3++;
+ }
+ while (blocksize--)
+ {
+ int ondx = (int)*in1++;
+ if (ondx >= 0 && ondx < bufsize)
+ *out++ = *last++ = buf[ondx];
+ else
+ /* CHECKED garbage in the output vector is cleared */
+ *out++ = *last++ = 0.;
+ }
+}
+
+/* this one is used for rampsmooth mode as well (see rampsmooth.c)
+ LATER recheck */
+static void vectral_perform_slide(t_vectral *x, int nblock,
+ t_float *in1, t_float *in2, t_float *in3,
+ t_float *out)
+{
+ t_float *buf = x->x_buffer;
+ int bufsize = x->x_bufsize;
+ double upcoef = x->x_upcoef;
+ double downcoef = x->x_downcoef;
+ t_float *last = x->x_lastframe;
+ int blocksize = nblock;
+ while (nblock--)
+ {
+ int indx = (int)*in2++;
+ if (indx >= 0 && indx < bufsize)
+ buf[indx] = *in3;
+ in3++;
+ }
+ while (blocksize--)
+ {
+ int ondx = (int)*in1++;
+ if (ondx >= 0 && ondx < bufsize)
+ {
+ /* CHECKME what is smoothed, and FIXME */
+ float delta = buf[ondx] - *last;
+ *out++ =
+ (*last++ += (delta > 0 ? delta * upcoef : delta * downcoef));
+ }
+ else *out++ = *last++ = 0.;
+ }
+}
+
+static void vectral_perform_clip(t_vectral *x, int nblock,
+ t_float *in1, t_float *in2, t_float *in3,
+ t_float *out)
+{
+ t_float *buf = x->x_buffer;
+ int bufsize = x->x_bufsize;
+ float lo = x->x_lo;
+ float hi = x->x_hi;
+ t_float *last = x->x_lastframe;
+ int blocksize = nblock;
+ while (nblock--)
+ {
+ int indx = (int)*in2++;
+ if (indx >= 0 && indx < bufsize)
+ buf[indx] = *in3;
+ in3++;
+ }
+ while (blocksize--)
+ {
+ int ondx = (int)*in1++;
+ if (ondx >= 0 && ondx < bufsize)
+ {
+ /* CHECKME what is smoothed, and FIXME */
+ float delta = buf[ondx] - *last;
+ if (delta < lo)
+ *out++ = (*last++ += lo);
+ else if (delta > hi)
+ *out++ = (*last++ += hi);
+ else
+ *out++ = *last++ = buf[ondx];
+ }
+ else *out++ = *last++ = 0.;
+ }
+}
+
+static t_int *vectral_perform(t_int *w)
+{
+ t_vectral *x = (t_vectral *)(w[1]);
+ (*x->x_perform)(x, (int)(w[2]), (t_float *)(w[3]), (t_float *)(w[4]),
+ (t_float *)(w[5]), (t_float *)(w[6]));
+ return (w + 7);
+}
+
+static void vectral_dsp(t_vectral *x, t_signal **sp)
+{
+ int nblock = sp[0]->s_n;
+ if (nblock > x->x_bufsize)
+ nblock = x->x_bufsize; /* CHECKME */
+ dsp_add(vectral_perform, 6, x, nblock,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec);
+}
+
+static void vectral_rampsmooth(t_vectral *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac && av->a_type == A_FLOAT)
+ {
+ int i;
+ x->x_upcoef = ((i = (int)av->a_w.w_float) > 1 ? 1. / (double)i : 1.);
+ ac--; av++;
+ if (ac && av->a_type == A_FLOAT)
+ x->x_downcoef =
+ ((i = (int)av->a_w.w_float) > 1 ? 1. / (double)i : 1.);
+ else
+ x->x_downcoef = 1.; /* CHECKED */
+ x->x_perform = vectral_perform_slide; /* see above */
+ }
+ else x->x_perform = vectral_perform_bypass; /* CHECKED */
+}
+
+static void vectral_slide(t_vectral *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac && av->a_type == A_FLOAT)
+ {
+ double d;
+ x->x_upcoef = ((d = av->a_w.w_float) > 1. ? 1. / d : 1.);
+ ac--; av++;
+ if (ac && av->a_type == A_FLOAT)
+ x->x_downcoef = ((d = av->a_w.w_float) > 1. ? 1. / d : 1.);
+ else
+ x->x_downcoef = 1.; /* CHECKED */
+ x->x_perform = vectral_perform_slide;
+ }
+ else x->x_perform = vectral_perform_bypass; /* CHECKED */
+}
+
+/* CHECKED 'deltaclip <hi> <lo>' (deltaclip~'s args are swapped) */
+static void vectral_deltaclip(t_vectral *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac && av->a_type == A_FLOAT)
+ {
+ x->x_hi = av->a_w.w_float;
+ ac--; av++;
+ if (ac && av->a_type == A_FLOAT)
+ x->x_lo = av->a_w.w_float;
+ else
+ x->x_lo = 0.; /* CHECKED */
+ }
+ else x->x_lo = x->x_hi = 0.; /* CHECKED */
+ x->x_perform = vectral_perform_clip;
+}
+
+static void vectral_free(t_vectral *x)
+{
+ if (x->x_buffer)
+ freebytes(x->x_buffer, x->x_bufsize * sizeof(*x->x_buffer));
+ if (x->x_lastframe)
+ freebytes(x->x_lastframe, x->x_bufsize * sizeof(*x->x_lastframe));
+}
+
+static void *vectral_new(t_floatarg f)
+{
+ t_vectral *x = (t_vectral *)pd_new(vectral_class);
+ int i = (int)f;
+ x->x_bufsize = (i > 0 ? i : VECTRAL_DEFSIZE);
+ if (!(x->x_buffer = getbytes(x->x_bufsize * sizeof(*x->x_buffer))))
+ goto failure;
+ if (!(x->x_lastframe = getbytes(x->x_bufsize * sizeof(*x->x_lastframe))))
+ goto failure;
+ x->x_perform = vectral_perform_bypass;
+ inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal);
+ inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal);
+ outlet_new((t_object *)x, &s_signal);
+ return (x);
+failure:
+ pd_free((t_pd *)x);
+ return (0);
+}
+
+void vectral_tilde_setup(void)
+{
+ vectral_class = class_new(gensym("vectral~"),
+ (t_newmethod)vectral_new,
+ (t_method)vectral_free,
+ sizeof(t_vectral), 0, A_DEFFLOAT, 0);
+ sic_setup(vectral_class, vectral_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(vectral_class, (t_method)vectral_rampsmooth,
+ gensym("rampsmooth"), A_GIMME, 0);
+ class_addmethod(vectral_class, (t_method)vectral_slide,
+ gensym("slide"), A_GIMME, 0);
+ class_addmethod(vectral_class, (t_method)vectral_deltaclip,
+ gensym("deltaclip"), A_GIMME, 0);
+}
diff --git a/cyclone/sickle/wave.c b/cyclone/sickle/wave.c
new file mode 100644
index 0000000..7804c88
--- /dev/null
+++ b/cyclone/sickle/wave.c
@@ -0,0 +1,161 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "sickle/sic.h"
+#include "sickle/arsic.h"
+
+/* CHECKME (the refman): the extra channels are not played */
+
+typedef struct _wave
+{
+ t_arsic x_arsic;
+ int x_nointerp;
+} t_wave;
+
+static t_class *wave_class;
+
+static void wave_interp(t_wave *x, t_floatarg f)
+{
+ x->x_nointerp = (f == 0);
+ arsic_setminsize((t_arsic *)x, (x->x_nointerp ? 1 : 4));
+ arsic_check((t_arsic *)x);
+}
+
+static void wave_set(t_wave *x, t_symbol *s)
+{
+ arsic_setarray((t_arsic *)x, s, 1);
+}
+
+static t_int *wave_perform(t_int *w)
+{
+ t_arsic *sic = (t_arsic *)(w[1]);
+ int nblock = (int)(w[2]);
+ int nch = sic->s_nchannels;
+ t_int *outp = w + 6;
+ if (sic->s_playable)
+ {
+ t_wave *x = (t_wave *)sic;
+ t_float *xin = (t_float *)(w[3]);
+ t_float *sin = (t_float *)(w[4]);
+ t_float *ein = (t_float *)(w[5]);
+ int vecsize = sic->s_vecsize;
+ t_float **vectable = sic->s_vectors;
+ float ksr = sic->s_ksr;
+ int nointerp = x->x_nointerp;
+ int maxindex = (nointerp ? vecsize - 1 : vecsize - 3);
+ int iblock;
+
+ for (iblock = 0; iblock < nblock; iblock++)
+ {
+ float spos = *sin++ * ksr;
+ float xpos = *ein++ * ksr;
+ /* msp seems to be buggy here, but CHECKME again */
+ int siz = (int)((xpos > 0 ? xpos : maxindex) - spos);
+ float phase = *xin++;
+ int ndx;
+ int ch = nch;
+ /* CHECKED: phase is clipped, not wrapped */
+ if (phase < 0) phase = 0;
+ else if (phase > 1.0) phase = 1.0;
+ xpos = (siz > 0 ? spos + siz * phase : spos);
+ ndx = (int)xpos;
+ if (nointerp)
+ {
+ if (ndx < 0) ndx = 0;
+ else if (ndx > maxindex) ndx = maxindex;
+ while (ch--)
+ {
+ t_float *vp = vectable[ch];
+ t_float *out = (t_float *)(outp[ch]);
+ out[iblock] = (vp ? vp[ndx] : 0);
+ }
+ }
+ else
+ {
+ float frac, a, b, c, d, cminusb;
+ if (ndx < 1)
+ ndx = 1, frac = 0;
+ else if (ndx > maxindex)
+ ndx = maxindex, frac = 1;
+ else frac = xpos - ndx;
+ while (ch--)
+ {
+ t_float *vp = vectable[ch];
+ t_float *out = (t_float *)(outp[ch]);
+ if (vp)
+ {
+ vp += ndx;
+ a = vp[-1];
+ b = vp[0];
+ c = vp[1];
+ d = vp[2];
+ cminusb = c-b;
+ out[iblock] = b + frac * (
+ cminusb - 0.1666667f * (1. - frac) * (
+ (d - a - 3.0f * cminusb) * frac
+ + (d + 2.0f * a - 3.0f * b)
+ )
+ );
+ }
+ else out[iblock] = 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ int ch = nch;
+ while (ch--)
+ {
+ t_float *out = (t_float *)outp[ch];
+ int n = nblock;
+ while (n--) *out++ = 0;
+ }
+ }
+ return (w + sic->s_nperfargs + 1);
+}
+
+static void wave_dsp(t_wave *x, t_signal **sp)
+{
+ arsic_dsp((t_arsic *)x, sp, wave_perform, 1);
+}
+
+static void wave_free(t_wave *x)
+{
+ arsic_free((t_arsic *)x);
+}
+
+static void *wave_new(t_symbol *s, t_floatarg f1, t_floatarg f2, t_floatarg f3)
+{
+ /* three auxiliary signals: phase, clipstart, and clipend inputs */
+ t_wave *x = (t_wave *)arsic_new(wave_class, s, (int)f3, 0, 3);
+ if (x)
+ {
+ int nch = arsic_getnchannels((t_arsic *)x);
+ if (f1 < 0) f1 = 0;
+ if (f2 < 0) f2 = 0;
+ sic_newinlet((t_sic *)x, f1);
+ sic_newinlet((t_sic *)x, f2);
+ while (nch--)
+ outlet_new((t_object *)x, &s_signal);
+ wave_interp(x, 1);
+ }
+ return (x);
+}
+
+void wave_tilde_setup(void)
+{
+ wave_class = class_new(gensym("wave~"),
+ (t_newmethod)wave_new,
+ (t_method)wave_free,
+ sizeof(t_wave), 0,
+ A_DEFSYM, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ arsic_setup(wave_class, wave_dsp, SIC_FLOATTOSIGNAL);
+ class_addmethod(wave_class, (t_method)wave_set,
+ gensym("set"), A_SYMBOL, 0);
+ class_addmethod(wave_class, (t_method)wave_interp,
+ gensym("interp"), A_FLOAT, 0);
+}
diff --git a/dumpsetups b/dumpsetups
new file mode 100755
index 0000000..e65b265
--- /dev/null
+++ b/dumpsetups
@@ -0,0 +1,15 @@
+#!/bin/sh
+# LATER make this into a regular awk script
+DIR=`pwd`
+LIB=`basename $DIR`
+echo '// Do not edit this file, run "make" instead.
+
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+'
+awk '/void .*_setup\(void\)$/&&!/'$LIB'/{print $0";"}' *.c
+echo -e '\nvoid all'$LIB's_setup(void)'
+echo '{'
+awk -F '[ (]' '/void .*_setup\(void\)$/&&!/'$LIB'/{print " "$2"();"}' *.c
+echo '}'
diff --git a/shared/Makefile b/shared/Makefile
new file mode 100644
index 0000000..fc022be
--- /dev/null
+++ b/shared/Makefile
@@ -0,0 +1,2 @@
+ROOT_DIR = ..
+include $(ROOT_DIR)/Makefile.common
diff --git a/shared/Makefile.dirs b/shared/Makefile.dirs
new file mode 100644
index 0000000..d9be5aa
--- /dev/null
+++ b/shared/Makefile.dirs
@@ -0,0 +1 @@
+MIXED_DIRS = common hammer sickle toys unstable
diff --git a/shared/Makefile.objects b/shared/Makefile.objects
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/shared/Makefile.objects
diff --git a/shared/Makefile.sources b/shared/Makefile.sources
new file mode 100644
index 0000000..6e792b8
--- /dev/null
+++ b/shared/Makefile.sources
@@ -0,0 +1,2 @@
+OTHER_SOURCES = \
+shared.c
diff --git a/shared/common/Makefile b/shared/common/Makefile
new file mode 100644
index 0000000..5dcb2c8
--- /dev/null
+++ b/shared/common/Makefile
@@ -0,0 +1,4 @@
+ROOT_DIR = ../..
+include $(ROOT_DIR)/Makefile.common
+
+all: $(OBJECTS)
diff --git a/shared/common/Makefile.objects b/shared/common/Makefile.objects
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/shared/common/Makefile.objects
diff --git a/shared/common/Makefile.sources b/shared/common/Makefile.sources
new file mode 100644
index 0000000..64da6f8
--- /dev/null
+++ b/shared/common/Makefile.sources
@@ -0,0 +1,16 @@
+OTHER_SOURCES = \
+bifi.c \
+binport.c \
+dict.c \
+grow.c \
+hyphen.c \
+loud.c \
+mfbb.c \
+mifi.c \
+port.c \
+props.c \
+rand.c \
+sofi.c \
+sq.c \
+squeal.c \
+vefl.c
diff --git a/shared/common/bifi.c b/shared/common/bifi.c
new file mode 100644
index 0000000..22f3df3
--- /dev/null
+++ b/shared/common/bifi.c
@@ -0,0 +1,217 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* generic helpers for binary file reading and writing */
+
+#ifdef NT
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "m_pd.h"
+#include "shared.h"
+#include "common/bifi.h"
+
+#if 1
+#define BIFI_VERBOSE
+#if 0
+#define BIFI_DEBUG
+#endif
+#endif
+
+static int bifi_swapping = 1; /* set in bifi_clear() */
+
+/* one helper from g_array.c (the original is global, but since
+ garray_ambigendian() lacks EXTERN specifier, .dll externs cannot see it;
+ btw. it has a comment: ``this should be renamed and moved...'')
+*/
+static int ambigendian(void)
+{
+ unsigned short s = 1;
+ unsigned char c = *(char *)(&s);
+ return (c==0);
+}
+
+/* two helpers from d_soundfile.c */
+uint32 bifi_swap4(uint32 n)
+{
+ if (bifi_swapping)
+ return (((n & 0xff) << 24) | ((n & 0xff00) << 8) |
+ ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24));
+ else return (n);
+}
+
+uint16 bifi_swap2(uint16 n)
+{
+ if (bifi_swapping)
+ return (((n & 0xff) << 8) | ((n & 0xff00) >> 8));
+ else return (n);
+}
+
+static void bifi_error_clear(t_bifi *x)
+{
+ x->b_err = BIFI_ERR_OK;
+ x->b_syserrno = 0;
+ errno = 0;
+}
+
+static void bifi_error_set(t_bifi *x, int errcode)
+{
+ x->b_err = errcode;
+ x->b_syserrno = errno;
+ if (errcode != BIFI_ERR_OK && x->b_fp)
+ {
+ fclose(x->b_fp);
+ x->b_fp = 0;
+ }
+#if 0 /* LATER use Pd's own error logging mechanism, maybe by calling this: */
+ sys_unixerror((char *)x); /* sys_logerror((char *)x, "...")? */
+#endif
+}
+
+void bifi_clear(t_bifi *x)
+{
+ bifi_swapping = !ambigendian();
+ x->b_fp = 0;
+ x->b_filename[0] = '\0';
+ bifi_error_clear(x);
+}
+
+t_bifi *bifi_new(t_bifi *x, char *hdr, size_t hdrsz)
+{
+ t_bifi *result = x;
+ if (result) result->b_selfalloc = 0;
+ else {
+ if (!(result = getbytes(sizeof(*result)))) return (0);
+ result->b_selfalloc = 1;
+ }
+ if (hdr || !hdrsz) result->b_hdralloc = 0;
+ else {
+ if (!(hdr = getbytes(hdrsz)))
+ {
+ if (result->b_selfalloc) freebytes(result, sizeof(*result));
+ return (0);
+ }
+ result->b_hdralloc = 1;
+ }
+ result->b_header = hdr;
+ result->b_headersize = hdrsz;
+ bifi_clear(result);
+ return (result);
+}
+
+void bifi_free(t_bifi *x)
+{
+ if (x->b_fp) fclose(x->b_fp);
+ if (x->b_hdralloc) freebytes(x->b_header, x->b_headersize);
+ if (x->b_selfalloc) freebytes(x, sizeof(*x));
+}
+
+void bifi_error_report(t_bifi *x)
+{
+ char *errmess = 0;
+ switch (x->b_err)
+ {
+ case BIFI_ERR_OK:
+ break;
+ case BIFI_ERR_OPEN:
+ errmess = "cannot open";
+ break;
+ case BIFI_ERR_READ:
+ errmess = "error reading";
+ break;
+ case BIFI_ERR_WRITE:
+ errmess = "error writing";
+ break;
+ case BIFI_ERR_BADHEADER:
+ errmess = "missing header of";
+ break;
+ default:
+ post("binary file i/o unknown error");
+ }
+ if (errmess)
+ post("%s binary file `%s\' (errno %d: %s)", errmess,
+ x->b_filename, x->b_syserrno, strerror(x->b_syserrno));
+ bifi_error_clear(x);
+}
+
+/* Open file and read in its header (x must be a valid t_bifi pointer,
+ no checks are being made...)
+*/
+int bifi_read_start(t_bifi *x, const char *filename, const char *dirname)
+{
+ int fd;
+ char dirbuf[MAXPDSTRING], *nameptr;
+
+ bifi_clear(x);
+ strcpy(x->b_filename, filename);
+ if ((fd = open_via_path(dirname, filename,
+ "", dirbuf, &nameptr, MAXPDSTRING, 1)) < 0)
+ {
+ bifi_error_set(x, BIFI_ERR_OPEN);
+ return (0);
+ }
+
+ /* Closing/reopening dance. This is unnecessary under linux, and we
+ could have tried to convert fd to fp (since we prefer using streams),
+ but under windows open_via_path() returns what seems to be an invalid
+ fd. LATER try to understand what is going on here... */
+ close(fd);
+ if (dirbuf != nameptr)
+ {
+ char *slashpos = dirbuf + strlen(dirbuf);
+ *slashpos++ = '/';
+ /* try not to be dependent on current open_via_path() implementation */
+ if (nameptr != slashpos)
+ strcpy(slashpos, nameptr);
+ }
+ sys_unbashfilename(dirbuf, dirbuf);
+ if (!(x->b_fp = fopen(dirbuf, "rb")))
+ {
+ bifi_error_set(x, BIFI_ERR_OPEN);
+ return (0);
+ }
+
+ if (x->b_headersize &&
+ fread(x->b_header, 1, x->b_headersize, x->b_fp) < x->b_headersize)
+ {
+ bifi_error_set(x, BIFI_ERR_BADHEADER);
+ return (0);
+ }
+ return (1);
+}
+
+/* Open file and write the supplied header (x must be a valid t_bifi pointer
+ with header data properly filled, no checks are being made...)
+*/
+int bifi_write_start(t_bifi *x, const char *filename, const char *dirname)
+{
+ char fnamebuf[MAXPDSTRING];
+
+ bifi_clear(x);
+ strcpy(x->b_filename, filename);
+
+ fnamebuf[0] = 0;
+ if (*dirname)
+ strcat(fnamebuf, dirname), strcat(fnamebuf, "/");
+ strcat(fnamebuf, filename);
+ sys_bashfilename(fnamebuf, fnamebuf);
+ if (!(x->b_fp = fopen(fnamebuf, "wb")))
+ {
+ bifi_error_set(x, BIFI_ERR_OPEN);
+ return (0);
+ }
+
+ if (x->b_headersize &&
+ fwrite(x->b_header, 1, x->b_headersize, x->b_fp) < x->b_headersize)
+ {
+ bifi_error_set(x, BIFI_ERR_WRITE);
+ return (0);
+ }
+ return (1);
+}
diff --git a/shared/common/bifi.h b/shared/common/bifi.h
new file mode 100644
index 0000000..29fe5ae
--- /dev/null
+++ b/shared/common/bifi.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* generic helpers for binary file reading and writing */
+
+#ifndef __BIFI_H__
+#define __BIFI_H__
+
+#define BIFI_ERR_OK 0
+#define BIFI_ERR_OPEN -1
+#define BIFI_ERR_READ -2 /* generic read failure */
+#define BIFI_ERR_WRITE -3 /* generic write failure */
+#define BIFI_ERR_BADHEADER -4 /* header missing or short */
+
+typedef struct _bifi
+{
+ int b_selfalloc:1;
+ int b_hdralloc:1;
+ char *b_header;
+ size_t b_headersize;
+ FILE *b_fp;
+ char b_filename[MAXPDSTRING];
+ int b_err; /* BIFI_ERR code */
+ int b_syserrno; /* system error code */
+} t_bifi;
+
+uint32 bifi_swap4(uint32 n);
+uint16 bifi_swap2(uint16 n);
+
+t_bifi *bifi_new(t_bifi *x, char *hdr, size_t hdrsz);
+void bifi_free(t_bifi *x);
+void bifi_clear(t_bifi *x);
+
+int bifi_read_start(t_bifi *x, const char *filename, const char *dirname);
+int bifi_write_start(t_bifi *x, const char *filename, const char *dirname);
+
+void bifi_error_report(t_bifi *x);
+
+#endif
diff --git a/shared/common/binport.c b/shared/common/binport.c
new file mode 100644
index 0000000..05cc5df
--- /dev/null
+++ b/shared/common/binport.c
@@ -0,0 +1,559 @@
+/* Copyright (c) 1997-2003 Miller Puckette, krzYszcz, and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#define BINPORT_MAXSTRING 256
+#define BINPORT_SYMGROW 64
+
+#ifndef BINPORT_STANDALONE
+/* load max binary file to a binbuf */
+
+#include "m_pd.h"
+
+#else
+/* make a max-textual listing from a max binary file */
+
+/* This is a standalone version of a ``max binary to binbuf'' module.
+ It uses certain Pd calls and structs, which are duplicated below.
+ LATER should be linked to the Pd API library. */
+
+#define BINPORT_VERBOSE
+//#define BINPORT_DEBUG
+
+#endif
+
+#include "binport.h"
+
+static void binport_error(char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "ERROR (binport): ");
+ vfprintf(stderr, fmt, ap);
+ putc('\n', stderr);
+ va_end(ap);
+}
+
+static void binport_warning(char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "warning (binport): ");
+ vfprintf(stderr, fmt, ap);
+ putc('\n', stderr);
+ va_end(ap);
+}
+
+static void binport_bug(char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "BUG (binport): ");
+ vfprintf(stderr, fmt, ap);
+ putc('\n', stderr);
+ va_end(ap);
+}
+
+#ifdef BINPORT_STANDALONE
+
+typedef int t_int;
+typedef float t_float;
+
+typedef struct _symbol
+{
+ char *s_name;
+ void *s_thing;
+ struct _symbol *s_next;
+} t_symbol;
+
+typedef union word
+{
+ t_float w_float;
+ t_symbol *w_symbol;
+ int w_index;
+} t_word;
+
+typedef enum
+{
+ A_NULL,
+ A_FLOAT,
+ A_SYMBOL,
+ A_POINTER,
+ A_SEMI,
+ A_COMMA,
+ A_DEFFLOAT,
+ A_DEFSYM,
+ A_DOLLAR,
+ A_DOLLSYM,
+ A_GIMME,
+ A_CANT
+} t_atomtype;
+
+typedef struct _atom
+{
+ t_atomtype a_type;
+ union word a_w;
+} t_atom;
+
+void *getbytes(size_t nbytes)
+{
+ void *ret;
+ if (nbytes < 1) nbytes = 1;
+ ret = (void *)calloc(nbytes, 1);
+ if (!ret)
+ binport_error("getbytes() failed -- out of memory");
+ return (ret);
+}
+
+void *resizebytes(void *old, size_t oldsize, size_t newsize)
+{
+ void *ret;
+ if (newsize < 1) newsize = 1;
+ if (oldsize < 1) oldsize = 1;
+ ret = (void *)realloc((char *)old, newsize);
+ if (newsize > oldsize && ret)
+ memset(((char *)ret) + oldsize, 0, newsize - oldsize);
+ if (!ret)
+ binport_error("resizebytes() failed -- out of memory");
+ return (ret);
+}
+
+void freebytes(void *fatso, size_t nbytes)
+{
+ free(fatso);
+}
+
+#define HASHSIZE 1024
+
+static t_symbol *symhash[HASHSIZE];
+
+t_symbol *dogensym(char *s, t_symbol *oldsym)
+{
+ t_symbol **sym1, *sym2;
+ unsigned int hash1 = 0, hash2 = 0;
+ int length = 0;
+ char *s2 = s;
+ while (*s2)
+ {
+ hash1 += *s2;
+ hash2 += hash1;
+ length++;
+ s2++;
+ }
+ sym1 = symhash + (hash2 & (HASHSIZE-1));
+ while (sym2 = *sym1)
+ {
+ if (!strcmp(sym2->s_name, s)) return(sym2);
+ sym1 = &sym2->s_next;
+ }
+ if (oldsym) sym2 = oldsym;
+ else
+ {
+ sym2 = (t_symbol *)getbytes(sizeof(*sym2));
+ sym2->s_name = getbytes(length+1);
+ sym2->s_next = 0;
+ sym2->s_thing = 0;
+ strcpy(sym2->s_name, s);
+ }
+ *sym1 = sym2;
+ return (sym2);
+}
+
+t_symbol *gensym(char *s)
+{
+ return(dogensym(s, 0));
+}
+
+#endif /* end of Pd API */
+
+/* clumsy... LATER find a better way */
+#ifdef BINPORT_STANDALONE
+#define A_INT (A_CANT + 1)
+#endif
+
+static int binport_getint(t_atom *ap)
+{
+#ifdef A_INT
+ return (*(int *)&ap->a_w);
+#else
+ return (ap->a_w.w_float);
+#endif
+}
+
+static void binport_setint(t_atom *ap, int i)
+{
+#ifdef A_INT
+ ap->a_type = A_INT;
+ *(int *)&ap->a_w = i;
+#else
+ SETFLOAT(ap, (float)i);
+#endif
+}
+
+static void binport_setfloat(t_atom *ap, float f)
+{
+ ap->a_type = A_FLOAT;
+ ap->a_w.w_float = f;
+}
+
+typedef struct _binport
+{
+ FILE *b_fp;
+ int b_nsymbols;
+ int b_symsize;
+ t_symbol **b_symtable;
+} t_binport;
+
+static int binport_getbuf(t_binport *bp, char *buf, size_t sz)
+{
+ return (fread(buf, 1, sz, bp->b_fp) == sz);
+}
+
+static int binport_getbyte(t_binport *bp, unsigned char *buf)
+{
+ int c;
+ if ((c = fgetc(bp->b_fp)) == EOF)
+ return (0);
+ *buf = (unsigned char)c;
+ return (1);
+}
+
+static int binport_getstring(t_binport *bp, char *buf)
+{
+ int c, i = 0;
+ while (c = fgetc(bp->b_fp))
+ {
+ if (c == EOF)
+ return (0);
+ if (++i < BINPORT_MAXSTRING)
+ *buf++ = (unsigned char)c;
+ }
+ *buf = '\0';
+ if (i >= BINPORT_MAXSTRING)
+ binport_warning("symbol string too long, skipped");
+ return (1);
+}
+
+static t_symbol *binport_makesymbol(t_binport *bp, int id)
+{
+ char s[BINPORT_MAXSTRING];
+ if (id < bp->b_nsymbols)
+ binport_bug("symbol id mismatch");
+ else if (id > bp->b_nsymbols)
+ binport_error("unexpected symbol id");
+ else if (binport_getstring(bp, s))
+ {
+ int reqsize = ++bp->b_nsymbols;
+ if (reqsize > bp->b_symsize)
+ {
+ reqsize += (BINPORT_SYMGROW - 1);
+#ifdef BINPORT_DEBUG
+ binport_warning("resizing symbol table to %d elements", reqsize);
+#endif
+ if (bp->b_symtable =
+ resizebytes(bp->b_symtable,
+ bp->b_symsize * sizeof(*bp->b_symtable),
+ reqsize * sizeof(*bp->b_symtable)))
+ bp->b_symsize = reqsize;
+ else
+ {
+ bp->b_nsymbols = bp->b_symsize = 0;
+ return (0);
+ }
+ }
+ return (bp->b_symtable[id] = gensym(s));
+ }
+ return (0);
+}
+
+static t_symbol *binport_getsymbol(t_binport *bp, int id)
+{
+ if (id < bp->b_nsymbols)
+ return (bp->b_symtable[id]);
+ else
+ return (binport_makesymbol(bp, id));
+}
+
+static int binport_setsymbol(t_binport *bp, t_atom *ap, int id)
+{
+ t_symbol *s = binport_getsymbol(bp, id);
+ if (s)
+ {
+ ap->a_type = A_SYMBOL;
+ ap->a_w.w_symbol = s;
+ }
+ return (s != 0);
+}
+
+static int binport_nextatom(t_binport *bp, t_atom *ap)
+{
+ unsigned char opcode;
+ int opval;
+ char buf[64];
+ if (!binport_getbyte(bp, &opcode))
+ goto bad;
+ opval = opcode & 0x0f;
+ switch (opcode >> 4)
+ {
+ case 1: /* variable length int,
+ opval: length (number of bytes that follow) */
+ if (!binport_getbuf(bp, buf, opval))
+ goto bad;
+ else
+ {
+ unsigned char *p = (unsigned char *)buf + opval;
+ int i = 0;
+ while (opval--) i = (i << 8) | *--p;
+ if (opcode == 0x12) /* FIXME */
+ i = (short)i;
+ binport_setint(ap, i);
+ }
+ break;
+ case 2: /* variable length float,
+ opval: length (number of bytes that follow) */
+ if (!binport_getbuf(bp, buf, opval))
+ goto bad;
+ else
+ {
+ unsigned char *p = (unsigned char *)buf + opval;
+ int i = 0;
+ while (opval--) i = (i << 8) | *--p;
+ binport_setfloat(ap, *(t_float *)&i);
+ }
+ break;
+ case 3: /* variable length symbol id,
+ opval: length (number of bytes that follow) */
+ if (!binport_getbuf(bp, buf, opval))
+ goto bad;
+ else
+ {
+ unsigned char *p = (unsigned char *)buf + opval;
+ int i = 0;
+ while (opval--) i = (i << 8) | *--p;
+ if (!binport_setsymbol(bp, ap, i))
+ goto bad;
+ }
+ break;
+ case 5: /* half-byte int */
+ binport_setint(ap, opval);
+ break;
+ case 7: /* half-byte symbol id */
+ if (!binport_setsymbol(bp, ap, opval))
+ goto bad;
+ break;
+ case 12: /* #number */
+ sprintf(buf, "#%d", opval);
+ ap->a_type = A_SYMBOL;
+ ap->a_w.w_symbol = gensym(buf);
+ break;
+ case 13: /* #symbol id,
+ opval: length (number of bytes that follow) */
+ if (!binport_getbuf(bp, buf, opval))
+ goto bad;
+ else
+ {
+ unsigned char *p = (unsigned char *)buf + opval;
+ int i = 0;
+ while (opval--) i = (i << 8) | *--p;
+ if (!binport_setsymbol(bp, ap, i))
+ goto bad;
+ }
+ sprintf(buf, "#%s", ap->a_w.w_symbol->s_name);
+#ifdef BINPORT_DEBUG
+ binport_warning(buf);
+#endif
+ ap->a_w.w_symbol = gensym(buf);
+ break;
+ default:
+ switch (opcode)
+ {
+ case 0xa0:
+ ap->a_type = A_SEMI;
+ break;
+ default:
+ goto unknown;
+ }
+ }
+ return (1);
+unknown:
+ binport_error("unknown opcode %x", (int)opcode);
+bad:
+ return (0);
+}
+
+static void binport_free(t_binport *bp)
+{
+ fclose(bp->b_fp);
+ freebytes(bp->b_symtable, bp->b_symsize * sizeof(*bp->b_symtable));
+ freebytes(bp, sizeof(*bp));
+}
+
+static t_binport *binport_new(FILE *fp, int *ftypep)
+{
+ static char binport_header[4] = { 2, 0, 0, 0 };
+ char header[4];
+ *ftypep = BINPORT_INVALID;
+ if (fread(header, 1, 4, fp) == 4)
+ {
+ if (memcmp(header, binport_header, 4))
+ {
+ if (memcmp(header, "max", 3))
+ {
+ if (header[0] == '#') /* LATER rethink */
+ *ftypep = BINPORT_PDFILE;
+#ifdef BINPORT_VERBOSE
+ else binport_warning("unknown header: %x %x %x %x",
+ (int)header[0], (int)header[1],
+ (int)header[2], (int)header[3]);
+#endif
+ }
+ else *ftypep = BINPORT_MAXTEXT;
+ }
+ else
+ {
+ t_binport *bp = getbytes(sizeof(*bp));
+ bp->b_fp = fp;
+ bp->b_nsymbols = 0;
+ bp->b_symsize = BINPORT_SYMGROW;
+ bp->b_symtable = getbytes(bp->b_symsize * sizeof(*bp->b_symtable));
+ *ftypep = BINPORT_OK;
+ return (bp);
+ }
+ }
+#ifdef BINPORT_VERBOSE
+ else binport_warning("file too short");
+#endif
+ fclose(fp);
+ return (0);
+}
+
+#ifndef BINPORT_STANDALONE
+
+/* LATER deal with corrupt binary files? */
+int binport_read(t_binbuf *bb, char *filename, char *dirname)
+{
+ FILE *fp;
+ char namebuf[MAXPDSTRING];
+ namebuf[0] = 0;
+ if (*dirname)
+ strcat(namebuf, dirname), strcat(namebuf, "/");
+ strcat(namebuf, filename);
+ sys_bashfilename(namebuf, namebuf);
+ if (fp = fopen(namebuf, "rb"))
+ {
+ int ftype;
+ t_binport *bp = binport_new(fp, &ftype);
+ if (bp)
+ {
+ t_atom at;
+ while (binport_nextatom(bp, &at))
+ binbuf_add(bb, 1, &at);
+ binport_free(bp);
+ return (BINPORT_OK);
+ }
+ else if (ftype == BINPORT_MAXTEXT || ftype == BINPORT_PDFILE)
+ return (ftype);
+ else
+ binport_error("\"%s\" doesn't look like a patch file", filename);
+ }
+ else binport_bug("cannot open file");
+ return (BINPORT_INVALID);
+}
+
+#else
+
+static void binport_atomstring(t_atom *ap, char *buf, int bufsize)
+{
+ char *sp, *bp, *ep;
+ switch(ap->a_type)
+ {
+ case A_SEMI:
+ strcpy(buf, ";"); break;
+ case A_COMMA:
+ strcpy(buf, ","); break;
+ case A_INT:
+ sprintf(buf, "%d", binport_getint(ap)); break;
+ case A_FLOAT:
+ sprintf(buf, "%#f", ap->a_w.w_float);
+ ep = buf + strlen(buf) - 1;
+ while (ep > buf && *ep == '0') *ep-- = 0;
+ break;
+ case A_SYMBOL:
+ sp = ap->a_w.w_symbol->s_name;
+ bp = buf;
+ ep = buf + (bufsize-5);
+ while (bp < ep && *sp)
+ {
+ if (*sp == ';' || *sp == ',' || *sp == '\\' ||
+ (*sp == '$' && bp == buf && sp[1] >= '0' && sp[1] <= '9'))
+ *bp++ = '\\';
+ if ((unsigned char)*sp < 127)
+ *bp++ = *sp++;
+ else
+ /* FIXME this is temporary -- codepage horror */
+ sprintf(bp, "\\%.3o", (unsigned char)*sp++), bp += 4;
+ }
+ if (*sp) *bp++ = '*';
+ *bp = 0;
+ break;
+ case A_DOLLAR:
+ sprintf(buf, "$%d", ap->a_w.w_index);
+ break;
+ case A_DOLLSYM:
+ sprintf(buf, "$%s", ap->a_w.w_symbol->s_name);
+ break;
+ default:
+ binport_bug("bad atom type");
+ strcpy(buf, "???");
+ }
+}
+
+int main(int ac, char **av)
+{
+ if (ac > 1)
+ {
+ FILE *fp = fopen(av[1], "rb");
+ if (fp)
+ {
+ int ftype;
+ t_binport *bp = binport_new(fp, &ftype);
+ if (bp)
+ {
+ char buf[BINPORT_MAXSTRING];
+ t_atom at;
+ int ac = 0;
+ while (binport_nextatom(bp, &at))
+ {
+ if (at.a_type == A_SEMI)
+ {
+ fputs(";\n", stdout);
+ ac = 0;
+ }
+ else
+ {
+ if (ac++) fputc(' ', stdout);
+ binport_atomstring(&at, buf, BINPORT_MAXSTRING);
+ fputs(buf, stdout);
+ }
+ }
+ binport_free(bp);
+ }
+ else if (ftype == BINPORT_MAXTEXT)
+ binport_warning("\"%s\" looks like a Max text file", av[1]);
+ else if (ftype == BINPORT_PDFILE)
+ binport_warning("\"%s\" looks like a Pd patch file", av[1]);
+ else
+ binport_error("\"%s\" doesn't look like a patch file", av[1]);
+ }
+ else binport_error("cannot open file \"%s\"", av[1]);
+ }
+ else binport_error("what file?");
+ return (0);
+}
+
+#endif
diff --git a/shared/common/binport.h b/shared/common/binport.h
new file mode 100644
index 0000000..0b6b607
--- /dev/null
+++ b/shared/common/binport.h
@@ -0,0 +1,15 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __BINPORT_H__
+#define __BINPORT_H__
+
+enum { BINPORT_OK, BINPORT_MAXTEXT, BINPORT_PDFILE,
+ BINPORT_INVALID, BINPORT_CORRUPT };
+
+#ifndef BINPORT_STANDALONE
+int binport_read(t_binbuf *bb, char *filename, char *dirname);
+#endif
+
+#endif
diff --git a/shared/common/grow.c b/shared/common/grow.c
new file mode 100644
index 0000000..f02509a
--- /dev/null
+++ b/shared/common/grow.c
@@ -0,0 +1,105 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* LATER generic handling of reentrant output request and self-invoked set */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/grow.h"
+
+/* Prior to this call a caller is supposed to check for *nrequested > *sizep.
+ Returns a reallocated buffer's pointer (success) or a given 'bufini'
+ default value (failure).
+ Upon return *nrequested contains the actual number of elements:
+ requested (success) or a given default value of 'inisize' (failure). */
+void *grow_nodata(int *nrequested, int *sizep, void *bufp,
+ int inisize, void *bufini, size_t typesize)
+{
+ int newsize = *sizep * 2;
+ while (newsize < *nrequested) newsize *= 2;
+ if (bufp == bufini)
+ bufp = getbytes(newsize * typesize);
+ else
+ bufp = resizebytes(bufp, *sizep * typesize, newsize * typesize);
+ if (bufp)
+ {
+ *sizep = newsize;
+ return (bufp);
+ }
+ else
+ {
+ *nrequested = *sizep = inisize;
+ return (bufini);
+ }
+}
+
+/* Like grow_nodata(), but preserving first *nexisting elements. */
+void *grow_withdata(int *nrequested, int *nexisting,
+ int *sizep, void *bufp,
+ int inisize, void *bufini, size_t typesize)
+{
+ int newsize = *sizep * 2;
+ while (newsize < *nrequested) newsize *= 2;
+ if (bufp == bufini)
+ {
+ if (!(bufp = getbytes(newsize * typesize)))
+ {
+ *nrequested = *sizep = inisize;
+ return (bufini);
+ }
+ *sizep = newsize;
+ memcpy(bufp, bufini, *nexisting * typesize);
+ }
+ else
+ {
+ int oldsize = *sizep;
+ if (!(bufp = resizebytes(bufp, *sizep * typesize, newsize * typesize)))
+ {
+ *nrequested = *sizep = inisize;
+ *nexisting = 0;
+ return (bufini);
+ }
+ *sizep = newsize;
+ }
+ return (bufp);
+}
+
+/* Like grow_nodata(), but preserving a 'tail' of *nexisting elements,
+ starting from *startp. */
+/* LATER rethink handling of a start pointer (clumsy now) */
+void *grow_withtail(int *nrequested, int *nexisting, char **startp,
+ int *sizep, void *bufp,
+ int inisize, void *bufini, size_t typesize)
+{
+ int newsize = *sizep * 2;
+ while (newsize < *nrequested) newsize *= 2;
+ if (bufp == bufini)
+ {
+ char *oldstart = *startp;
+ if (!(bufp = getbytes(newsize * typesize)))
+ {
+ *nrequested = *sizep = inisize;
+ return (bufini);
+ }
+ *startp = (char *)bufp + (newsize - *nexisting) * typesize;
+ *sizep = newsize;
+ memcpy(*startp, oldstart, *nexisting * typesize);
+ }
+ else
+ {
+ int oldsize = *sizep;
+ if (!(bufp = resizebytes(bufp, *sizep * typesize, newsize * typesize)))
+ {
+ *startp = (char *)bufini + inisize * typesize;
+ *nrequested = *sizep = inisize;
+ *nexisting = 0;
+ return (bufini);
+ }
+ *startp = (char *)bufp + (newsize - *nexisting) * typesize;
+ *sizep = newsize;
+ memmove(*startp, (char *)bufp + (oldsize - *nexisting) * typesize,
+ *nexisting * typesize);
+ }
+ return (bufp);
+}
diff --git a/shared/common/grow.h b/shared/common/grow.h
new file mode 100644
index 0000000..1749cfc
--- /dev/null
+++ b/shared/common/grow.h
@@ -0,0 +1,17 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __GROW_H__
+#define __GROW_H__
+
+void *grow_nodata(int *nrequested, int *sizep, void *bufp,
+ int inisize, void *bufini, size_t typesize);
+void *grow_withdata(int *nrequested, int *nexisting,
+ int *sizep, void *bufp,
+ int inisize, void *bufini, size_t typesize);
+void *grow_withtail(int *nrequested, int *nexisting, char **startp,
+ int *sizep, void *bufp,
+ int inisize, void *bufini, size_t typesize);
+
+#endif
diff --git a/shared/common/loud.c b/shared/common/loud.c
new file mode 100644
index 0000000..638f431
--- /dev/null
+++ b/shared/common/loud.c
@@ -0,0 +1,210 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include "m_pd.h"
+#include "common/loud.h"
+
+#define LOUD_ERROR_DEFAULT "error (miXed): "
+
+/* LATER move it somewhere else */
+t_symbol *loud_floatsym(void)
+{
+ static t_symbol *s = 0;
+ return (s ? s : (s = gensym("noninteger float")));
+}
+
+/* LATER move it somewhere else */
+char *loud_symbolname(t_symbol *s, char *nullname)
+{
+ return (s && s != &s_ ? s->s_name : nullname);
+}
+
+/* LATER move it somewhere else */
+char *loud_ordinal(int n)
+{
+ static char buf[16]; /* assuming 10-digit INT_MAX */
+ sprintf(buf, "%dth", n);
+ if (n < 0) n = -n;
+ n %= 100;
+ if (n > 20) n %= 10;
+ if (n && n <= 3)
+ {
+ char *ptr = buf + strlen(buf) - 2;
+ switch (n)
+ {
+ case 1: strcpy(ptr, "st"); break;
+ case 2: strcpy(ptr, "nd"); break;
+ case 3: strcpy(ptr, "rd"); break;
+ }
+ }
+ return (buf);
+}
+
+void loud_error(t_pd *x, char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ if (x)
+ {
+ char buf[MAXPDSTRING];
+ fprintf(stderr, "%s's ", class_getname(*x));
+ vsprintf(buf, fmt, ap);
+ pd_error(x, buf);
+ }
+ else
+ {
+ fputs(LOUD_ERROR_DEFAULT, stderr);
+ vfprintf(stderr, fmt, ap);
+ putc('\n', stderr);
+ }
+ va_end(ap);
+}
+
+void loud_errand(t_pd *x, char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "%*s", (int)(x ? strlen(class_getname(*x)) + 10
+ : strlen(LOUD_ERROR_DEFAULT)), "");
+ vfprintf(stderr, fmt, ap);
+ putc('\n', stderr);
+ va_end(ap);
+}
+
+void loud_syserror(t_pd *x, char *msg)
+{
+ if (msg)
+ loud_error(x, "%s (%s)", msg, strerror(errno));
+ else
+ loud_error(x, strerror(errno));
+}
+
+void loud_nomethod(t_pd *x, t_symbol *s)
+{
+ loud_error(x, "doesn't understand \"%s\"", s->s_name);
+}
+
+void loud_messarg(t_pd *x, t_symbol *s)
+{
+ loud_error(x, "bad arguments for message \"%s\"", s->s_name);
+}
+
+int loud_checkint(t_pd *x, t_float f, int *valuep, t_symbol *mess)
+{
+ if ((*valuep = (int)f) == f)
+ return (1);
+ else
+ {
+ if (mess == &s_float)
+ loud_nomethod(x, loud_floatsym());
+ else if (mess)
+ loud_error(x, "\"%s\" argument invalid for message \"%s\"",
+ loud_floatsym()->s_name, mess->s_name);
+ return (0);
+ }
+}
+
+void loud_classarg(t_class *c)
+{
+ loud_error(0, "missing or bad arguments in \"%s\"", class_getname(c));
+}
+
+void loud_warning(t_pd *x, char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "warning (%s): ", (x ? class_getname(*x) : "miXed"));
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ putc('\n', stderr);
+}
+
+void loud_notimplemented(t_pd *x, char *name)
+{
+ if (name)
+ loud_warning(x, "\"%s\" method not implemented (yet)", name);
+ else
+ loud_warning(x, "not implemented (yet)");
+}
+
+void loud_incompatible(t_class *c, char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "'%s' class incompatibility warning:\n\t",
+ class_getname(c));
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ putc('\n', stderr);
+}
+
+void loud_incompatible_max(t_class *c, int maxmax, char *what)
+{
+ loud_incompatible(c, "more than %d %s requested", maxmax, what);
+}
+
+int loud_floatarg(t_class *c, int which, int ac, t_atom *av,
+ t_float *vp, t_float minval, t_float maxval,
+ int underaction, int overaction, char *what)
+{
+ int result = LOUD_ARGOK;
+ if (which < ac)
+ {
+ av += which;
+ if (av->a_type == A_FLOAT)
+ {
+ t_float f = av->a_w.w_float;
+ if (f < minval)
+ {
+ *vp = (underaction & LOUD_CLIP ? minval : f);
+ if (underaction)
+ result = LOUD_ARGUNDER;
+ }
+ else if (f > maxval)
+ {
+ *vp = (overaction & LOUD_CLIP ? maxval : f);
+ if (overaction)
+ result = LOUD_ARGOVER;
+ }
+ else *vp = f;
+ }
+ else result = LOUD_ARGTYPE;
+ }
+ else result = LOUD_ARGMISSING;
+ if (what)
+ {
+ switch (result)
+ {
+ case LOUD_ARGUNDER:
+ if (underaction & LOUD_WARN)
+ {
+ if (underaction & LOUD_CLIP)
+ loud_warning(&c, "%s rounded up to %g", what, minval);
+ else
+ loud_incompatible(c, "less than %g %s requested",
+ minval, what);
+ }
+ break;
+ case LOUD_ARGOVER:
+ if (overaction & LOUD_WARN)
+ {
+ if (overaction & LOUD_CLIP)
+ loud_warning(&c, "%s truncated to %g", what, maxval);
+ else
+ loud_incompatible(c, "more than %g %s requested",
+ maxval, what);
+ }
+ break;
+ case LOUD_ARGTYPE:
+ loud_error(0, "bad argument %d (%s)", which, class_getname(c));
+ break;
+ default:;
+ }
+ }
+ return (result);
+}
diff --git a/shared/common/loud.h b/shared/common/loud.h
new file mode 100644
index 0000000..17c02bf
--- /dev/null
+++ b/shared/common/loud.h
@@ -0,0 +1,31 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __LOUD_H__
+#define __LOUD_H__
+
+#define LOUD_CLIP 1
+#define LOUD_WARN 2
+
+enum { LOUD_ARGOK, LOUD_ARGUNDER, LOUD_ARGOVER, LOUD_ARGTYPE, LOUD_ARGMISSING };
+
+t_symbol *loud_floatsym(void);
+char *loud_symbolname(t_symbol *s, char *nullname);
+char *loud_ordinal(int n);
+void loud_error(t_pd *x, char *fmt, ...);
+void loud_errand(t_pd *x, char *fmt, ...);
+void loud_syserror(t_pd *x, char *msg);
+void loud_nomethod(t_pd *x, t_symbol *s);
+void loud_messarg(t_pd *x, t_symbol *s);
+int loud_checkint(t_pd *x, t_float f, int *valuep, t_symbol *mess);
+void loud_classarg(t_class *c);
+void loud_warning(t_pd *x, char *fmt, ...);
+void loud_notimplemented(t_pd *x, char *name);
+void loud_incompatible(t_class *c, char *fmt, ...);
+void loud_incompatible_max(t_class *c, int maxmax, char *what);
+int loud_floatarg(t_class *c, int which, int ac, t_atom *av,
+ t_float *vp, t_float minval, t_float maxval,
+ int underaction, int overaction, char *what);
+
+#endif
diff --git a/shared/common/mifi.c b/shared/common/mifi.c
new file mode 100644
index 0000000..ad16b3b
--- /dev/null
+++ b/shared/common/mifi.c
@@ -0,0 +1,867 @@
+/* Copyright (c) 2001-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* reading/writing midifiles, a prototype version */
+
+#ifdef NT
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "m_pd.h"
+#include "shared.h"
+#include "common/sq.h"
+#include "common/bifi.h"
+#include "common/mifi.h"
+
+#if 1
+#define MIFI_VERBOSE
+#if 0
+#define MIFI_DEBUG
+#endif
+#endif
+
+#define MIFI_SHORTEST_EVENT 2 /* singlebyte delta and one databyte */
+#define MIFI_EVENT_NALLOC 32 /* LATER do some research (average max?) */
+#define MIFI_HEADER_SIZE 14 /* in case t_mifi_header is padded to 16 */
+#define MIFI_HEADERDATA_SIZE 6
+#define MIFI_TRACKHEADER_SIZE 8
+
+/* header structures for midifile and track */
+
+typedef struct _mifi_header
+{
+ char h_type[4];
+ uint32 h_length;
+ uint16 h_format;
+ uint16 h_ntracks;
+ uint16 h_division;
+} t_mifi_header;
+
+typedef struct _mifi_trackheader
+{
+ char h_type[4];
+ uint32 h_length;
+} t_mifi_trackheader;
+
+/* reading helpers */
+
+static void mifi_earlyeof(t_mifi_stream *x)
+{
+ x->s_bytesleft = 0;
+ x->s_eof = 1;
+}
+
+/* Get next byte from track data.
+ On error: return 0 (which is a valid result) and set x->s_eof.
+*/
+static uchar mifi_getbyte(t_mifi_stream *x)
+{
+ if (x->s_bytesleft)
+ {
+ int c;
+ if ((c = fgetc(x->s_fp)) == EOF)
+ {
+ mifi_earlyeof(x);
+ return (0);
+ }
+ else {
+ x->s_bytesleft--;
+ return ((uchar)c);
+ }
+ }
+ else return (0);
+}
+
+static uint32 mifi_readbytes(t_mifi_stream *x, uchar *buf, uint32 size)
+{
+ size_t res;
+ if (size > x->s_bytesleft)
+ size = x->s_bytesleft;
+ if ((res = fread(buf, 1, (size_t)size, x->s_fp)) == size)
+ x->s_bytesleft -= res;
+ else
+ mifi_earlyeof(x);
+ return (res);
+}
+
+static int mifi_skipbytes(t_mifi_stream *x, uint32 size)
+{
+ if (size > x->s_bytesleft)
+ size = x->s_bytesleft;
+ if (size)
+ {
+ int res = fseek(x->s_fp, size, SEEK_CUR);
+ if (res < 0)
+ mifi_earlyeof(x);
+ else
+ x->s_bytesleft -= size;
+ return res;
+ }
+ else return (0);
+}
+
+/* helpers handling variable-length quantities */
+
+static size_t mifi_writevarlen(t_mifi_stream *x, uint32 n)
+{
+ uint32 buf = n & 0x7f;
+ size_t length = 1;
+ while ((n >>= 7) > 0)
+ {
+ buf <<= 8;
+ buf |= 0x80;
+ buf += n & 0x7f;
+ length++;
+ }
+ return ((fwrite(&buf, 1, length, x->s_fp) == length) ? length : 0);
+}
+
+static uint32 mifi_readvarlen(t_mifi_stream *x)
+{
+ uint32 n = 0;
+ uchar c;
+ uint32 count = x->s_bytesleft;
+ if (count > 4) count = 4;
+ while (count--)
+ {
+ n = (n << 7) + ((c = mifi_getbyte(x)) & 0x7f);
+ if ((c & 0x80) == 0)
+ break;
+ }
+ return (n);
+}
+
+/* other helpers */
+
+static int mifi_read_start_track(t_mifi_stream *x)
+{
+ t_mifi_trackheader header;
+ long skip;
+ int notyet = 1;
+ do {
+ if (fread(&header, 1,
+ MIFI_TRACKHEADER_SIZE, x->s_fp) < MIFI_TRACKHEADER_SIZE)
+ goto nomoretracks;
+ header.h_length = bifi_swap4(header.h_length);
+ if (strncmp(header.h_type, "MTrk", 4))
+ {
+ char buf[5];
+ strncpy(buf, header.h_type, 4);
+ buf[5] = '\0';
+ if (x->s_anapass)
+ post("unknown chunk %s in midifile -- skipped", buf);
+ }
+ else if (header.h_length < MIFI_SHORTEST_EVENT)
+ {
+ if (x->s_anapass) post("empty track in midifile -- skipped");
+ }
+ else notyet = 0;
+ if (notyet && (skip = header.h_length) &&
+ fseek(x->s_fp, skip, SEEK_CUR) < 0)
+ goto nomoretracks;
+ } while (notyet);
+
+ x->s_track++;
+ x->s_newtrack = 1;
+ x->s_status = x->s_channel = 0;
+ x->s_bytesleft = header.h_length;
+ x->s_time = 0;
+
+ return (1);
+nomoretracks:
+ if (x->s_track == 0)
+ if (x->s_anapass) post("no valid miditracks");
+ return (0);
+}
+
+/* public interface */
+
+t_mifi_event *mifi_event_new(void)
+{
+ t_mifi_event *e = getbytes(sizeof(*e));
+ if (e && !(e->e_data = getbytes(e->e_bufsize = MIFI_EVENT_NALLOC)))
+ {
+ freebytes(e, sizeof(*e));
+ return (0);
+ }
+ return (e);
+}
+
+void mifi_event_free(t_mifi_event *e)
+{
+ freebytes(e->e_data, e->e_bufsize);
+ freebytes(e, sizeof(*e));
+}
+
+int mifi_event_settext(t_mifi_event *e, int type, char *text)
+{
+ e->e_delay = 0;
+ e->e_status = MIFI_EVENT_META;
+ e->e_meta = type;
+ e->e_length = strlen(text);
+ if (squb_checksize(e, e->e_length + 1, 1) <= e->e_length)
+ {
+ e->e_length = 0;
+ return (0);
+ }
+ strcpy(e->e_data, text);
+ return (1);
+}
+
+void mifi_event_printmeta(t_mifi_event *e)
+{
+ static int isprintable[MIFI_META_MAXPRINTABLE+1] =
+ {
+#ifdef MIFI_DEBUG
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+#elif defined MIFI_VERBOSE
+ 0, 0, 1, 1, 1, 1, 1, 1
+#endif
+ };
+ static char *printformat[MIFI_META_MAXPRINTABLE+1] =
+ {
+ "", "text: %s", "copyright: %s", "track name: %s",
+ "instrument name: %s", "lyric: %s", "marker: %s", "cue point: %s"
+ };
+ if (e->e_meta <= MIFI_META_MAXPRINTABLE)
+ {
+ if (isprintable[e->e_meta] && printformat[e->e_meta])
+ post(printformat[e->e_meta], e->e_data);
+ }
+#ifdef MIFI_DEBUG /* in verbose mode tempo printout done only after sorting */
+ else if (e->e_meta == MIFI_META_TEMPO)
+ {
+ int tempo = bifi_swap4(*(uint32*)e->e_data);
+ post("tempo %d after %d", tempo, e->e_delay);
+ }
+#endif
+}
+
+void mifi_stream_reset(t_mifi_stream *x)
+{
+ sq_reset(x);
+ x->s_status = x->s_channel = 0;
+ x->s_timecoef = sq_msecs2ticks(x, 0);
+ x->s_bytesleft = 0;
+}
+
+t_mifi_stream *mifi_stream_new(void)
+{
+ t_mifi_stream *x = sq_new();
+ if (x)
+ {
+ if (x->s_auxeve = mifi_event_new())
+ {
+ x->s_hdtracks = 1;
+ x->s_alltracks = 0;
+ mifi_stream_reset(x); /* LATER avoid calling sq_reset() twice */
+ }
+ else
+ {
+ mifi_stream_free(x);
+ return (0);
+ }
+ }
+ return (x);
+}
+
+void mifi_stream_free(t_mifi_stream *x)
+{
+ if (x->s_auxeve)
+ mifi_event_free(x->s_auxeve);
+ sq_free(x);
+}
+
+/* Open midifile for reading, parse the header. May be used as t_mifi_stream
+ allocator (if x is a null pointer), to be freed by mifi_read_end() or
+ explicitly.
+
+ Return value: null on error, else x if passed a valid pointer, else pointer
+ to an allocated structure.
+*/
+t_mifi_stream *mifi_read_start(t_mifi_stream *x,
+ const char *filename, const char *dirname,
+ int complain)
+{
+ t_mifi_stream *result = x;
+ t_bifi bifi;
+ t_bifi *bp = &bifi;
+ t_mifi_header header;
+ long skip;
+
+ bifi_new(bp, (char *)&header, MIFI_HEADER_SIZE);
+ if (!bifi_read_start(bp, filename, dirname))
+ {
+ bifi_error_report(bp);
+ bifi_free(bp);
+ return (0);
+ }
+ if (strncmp(header.h_type, "MThd", 4))
+ goto badheader;
+ header.h_length = bifi_swap4(header.h_length);
+ if (header.h_length < MIFI_HEADERDATA_SIZE)
+ goto badheader;
+ if (skip = header.h_length - MIFI_HEADERDATA_SIZE)
+ {
+ post("%ld extra bytes of midifile header -- skipped", skip);
+ if (fseek(bp->b_fp, skip, SEEK_CUR) < 0)
+ goto badstart;
+ }
+
+ /* since we will tolerate other incompatibilities, now we can allocate */
+ if (x) mifi_stream_reset(x);
+ else
+ {
+ if (!(result = mifi_stream_new()))
+ goto badstart;
+ result->s_autoalloc = 1;
+ }
+ result->s_fp = bp->b_fp;
+ result->s_format = bifi_swap2(header.h_format);
+ result->s_hdtracks = bifi_swap2(header.h_ntracks);
+ result->s_nticks = bifi_swap2(header.h_division);
+ if (result->s_nticks & 0x8000)
+ {
+ result->s_nframes = (result->s_nticks >> 8);
+ result->s_nticks &= 0xff;
+ }
+ else result->s_nframes = 0;
+ if (result->s_nticks == 0)
+ goto badheader;
+
+ return (result);
+badheader:
+ if (complain)
+ post("`%s\' is not a valid midifile", filename);
+badstart:
+ if (result && !x) mifi_stream_free(result);
+ bifi_free(bp);
+ return (0);
+}
+
+int mifi_read_restart(t_mifi_stream *x)
+{
+ FILE *fp = x->s_fp;
+ mifi_stream_reset(x);
+ x->s_anapass = 0;
+ x->s_fp = fp;
+ return (fseek(fp, 0, SEEK_SET) ? 0 : 1);
+}
+
+/* Close midifile and free t_mifi_stream if it was allocated
+ by mifi_read_start() */
+void mifi_read_end(t_mifi_stream *x)
+{
+ if (x->s_fp) fclose(x->s_fp);
+ if (x->s_autoalloc) mifi_stream_free(x);
+}
+
+/* Read next event from midifile.
+ Return value: see #defines in mifi.h.
+*/
+int mifi_read_event(t_mifi_stream *x, t_mifi_event *e)
+{
+ uchar status, channel;
+ uint32 length;
+
+ x->s_newtrack = 0;
+nextattempt:
+ if (x->s_bytesleft < MIFI_SHORTEST_EVENT && !mifi_read_start_track(x))
+ return (MIFI_READ_EOF);
+
+ x->s_time += (e->e_delay = mifi_readvarlen(x));
+
+ if ((status = mifi_getbyte(x)) < 0x80)
+ {
+ if (MIFI_IS_CHANNEL(x->s_status))
+ {
+ e->e_data[0] = status;
+ e->e_length = 1;
+ status = x->s_status;
+ e->e_channel = x->s_channel;
+ }
+ else {
+ if (x->s_anapass)
+ post("missing running status in midifile -- skip to end of track");
+ goto endoftrack;
+ }
+ }
+ else e->e_length = 0;
+
+ /* channel message */
+ if (status < 0xf0)
+ {
+ if (e->e_length == 0)
+ {
+ e->e_data[0] = mifi_getbyte(x);
+ e->e_length = 1;
+ x->s_status = status & 0xf0;
+ x->s_channel = e->e_channel = status & 0x0f;
+ status = x->s_status;
+ }
+ if (!MIFI_ONE_DATABYTE(status))
+ {
+ e->e_data[1] = mifi_getbyte(x);
+ e->e_length = 2;
+ }
+ }
+
+ /* system exclusive */
+ else if (status == MIFI_SYSEX_FIRST || status == MIFI_SYSEX_NEXT)
+ {
+ /* LATER choose the right way --
+ do we really need all those huge bulk dumps? */
+ length = mifi_readvarlen(x);
+ if (squb_checksize(e, length, 1) < length)
+ {
+ if (mifi_skipbytes(x, length) < 0)
+ return (MIFI_READ_FATAL);
+ goto nextattempt;
+ }
+ if (mifi_readbytes(x, e->e_data, length) != length)
+ return (MIFI_READ_FATAL);
+ e->e_length = length;
+#ifdef MIFI_VERBOSE
+ if (x->s_anapass) post("got %d bytes of sysex", length);
+#endif
+ }
+
+ /* meta-event */
+ else if (status == MIFI_EVENT_META)
+ {
+ e->e_meta = mifi_getbyte(x);
+ length = mifi_readvarlen(x);
+ if (e->e_meta > 127)
+ {
+ /* try to skip corrupted meta-event (quietly) */
+#ifdef MIFI_VERBOSE
+ if (x->s_anapass) post("bad meta: %d > 127", e->e_meta);
+#endif
+ if (mifi_skipbytes(x, length) < 0)
+ return (MIFI_READ_FATAL);
+ goto nextattempt;
+ }
+ switch (e->e_meta)
+ {
+ case MIFI_META_EOT:
+ if (length)
+ {
+ /* corrupted eot: ignore and skip to the real end of track */
+#ifdef MIFI_VERBOSE
+ if (x->s_anapass) post("corrupted eot, length %d", length);
+#endif
+ goto endoftrack;
+ }
+ break;
+ case MIFI_META_TEMPO:
+ if (length != 3)
+ {
+ if (x->s_anapass)
+ post("corrupted event in midifile -- skip to end of track");
+ goto endoftrack;
+ }
+ if (mifi_readbytes(x, e->e_data+1, 3) != 3)
+ return (MIFI_READ_FATAL);
+ e->e_data[0] = 0;
+ x->s_tempo = bifi_swap4(*(uint32*)e->e_data);
+ break;
+ default:
+ if (squb_checksize(e, length + 1, 1) <= length)
+ {
+ if (mifi_skipbytes(x, length) < 0)
+ return (MIFI_READ_FATAL);
+ goto nextattempt;
+ }
+ if (mifi_readbytes(x, e->e_data, length) != length)
+ return (MIFI_READ_FATAL);
+ e->e_length = length;
+ if (e->e_meta && e->e_meta <= MIFI_META_MAXPRINTABLE)
+ e->e_data[length] = '\0'; /* text meta-event nultermination */
+ }
+ }
+ else {
+ if (x->s_anapass)
+ post("unknown event type in midifile -- skip to end of track");
+ goto endoftrack;
+ }
+
+ return ((e->e_status = status) == MIFI_EVENT_META ? e->e_meta : status);
+
+endoftrack:
+ if (mifi_skipbytes(x, x->s_bytesleft) < 0)
+ return (MIFI_READ_FATAL);
+ return (MIFI_READ_SKIP);
+}
+
+/* Gather statistics (nevents, ntracks, ntempi), pick track names, and
+ allocate the maps. To be called in the first pass of reading.
+*/
+/* LATER consider optional reading of nonchannel events */
+int mifi_read_analyse(t_mifi_stream *x)
+{
+ t_mifi_event *evp = x->s_auxeve;
+ int evtype, result = MIFI_READ_FATAL;
+ int isnewtrack = 0;
+ int i;
+ char tnamebuf[MAXPDSTRING];
+ t_symbol *tnamesym = 0;
+ t_squack *trp = 0;
+
+ *tnamebuf = '\0';
+ x->s_alltracks = x->s_ntracks = 0;
+ x->s_nevents = 0;
+ x->s_ntempi = 0;
+
+ while ((evtype = mifi_read_event(x, evp)) >= MIFI_READ_SKIP)
+ {
+ if (evtype == MIFI_READ_SKIP)
+ continue;
+ if (x->s_newtrack)
+ {
+#ifdef MIFI_VERBOSE
+ post("track %d", x->s_track);
+#endif
+ isnewtrack = 1;
+ *tnamebuf = '\0';
+ tnamesym = 0; /* set to nonzero for nonempty tracks only */
+ }
+ if (MIFI_IS_CHANNEL(evtype))
+ {
+ if (isnewtrack)
+ {
+ isnewtrack = 0;
+ x->s_alltracks++;
+ if (!(trp = squax_add(x)))
+ goto anafail;
+ if (*tnamebuf)
+ {
+ tnamesym = trp->tr_name = gensym(tnamebuf);
+#ifdef MIFI_DEBUG
+ post("nonempty track name %s", tnamesym->s_name);
+#endif
+ }
+ else tnamesym = trp->tr_name = &s_;
+ }
+ x->s_nevents++;
+ }
+ else if (evtype < 0x80)
+ {
+ mifi_event_printmeta(evp);
+ if (evtype == MIFI_META_TEMPO)
+ x->s_ntempi++;
+ else if (evtype == MIFI_META_TRACKNAME)
+ {
+ char *p1 = evp->e_data;
+ if (*p1 &&
+ !*tnamebuf) /* take the first one */
+ {
+ while (*p1 == ' ') p1++;
+ if (*p1)
+ {
+ char *p2 = evp->e_data + evp->e_length - 1;
+ while (p2 > p1 && *p2 == ' ') *p2-- = '\0';
+ p2 = p1;
+ do if (*p2 == ' ' || *p2 == ',' || *p2 == ';')
+ *p2 = '-';
+ while (*++p2);
+ if (tnamesym == &s_)
+ { /* trackname after channel-event */
+ if (trp) /* redundant check */
+ tnamesym = trp->tr_name = gensym(p1);
+ }
+ else strcpy(tnamebuf, p1);
+ }
+ }
+ }
+ }
+ }
+ if (evtype != MIFI_READ_EOF)
+ goto anafail;
+
+ i = x->s_ntracks;
+ while (--i >= 0)
+ {
+ if (!x->s_track_name(i) || x->s_track_name(i) == &s_)
+ {
+ sprintf(tnamebuf, "%d-track", i);
+ x->s_track_name(i) = gensym(tnamebuf);
+ }
+ }
+
+ /* now (re)allocate the buffers */
+ if (squb_checksize(x->s_mytempi,
+ x->s_ntempi, sizeof(t_squmpo)) < x->s_ntempi)
+ goto anafail;
+ x->s_track_nevents(0) = 0;
+ x->s_track_nevents(x->s_ntracks) = x->s_nevents; /* guard point */
+
+ result = evtype;
+anafail:
+ return (result);
+}
+
+/* To be called in second pass of reading */
+/* LATER do not trust analysis: in case of inconsistency give up or checksize */
+int mifi_read_doit(t_mifi_stream *x)
+{
+ t_mifi_event *evp = x->s_auxeve;
+ t_squiter *it = x->s_myiter;
+ t_squiter_seekhook seekhook = squiter_seekhook(it);
+ t_squiter_incrhook incrhook = squiter_incrhook(it);
+ t_squiter_setevehook evehook = squiter_setevehook(it);
+ t_squiter_settimhook timhook = squiter_settimhook(it);
+ t_squiter_settarhook tarhook = squiter_settarhook(it);
+ int evtype, result = MIFI_READ_FATAL;
+ int nevents = x->s_nevents; /* three proxies... */
+ int ntracks = x->s_ntracks;
+ int ntempi = x->s_ntempi;
+ int trackno = 0;
+ t_symbol *trackname = 0;
+ int isnewtrack = 0;
+ t_squmpo *tp = x->s_tempomap;
+
+ if (!it || !seekhook(it, 0))
+ goto readfailed;
+
+ while ((evtype = mifi_read_event(x, evp)) >= MIFI_READ_SKIP)
+ {
+ if (evtype == MIFI_READ_SKIP)
+ continue;
+ if (x->s_newtrack)
+ isnewtrack = 1;
+ if (MIFI_IS_CHANNEL(evtype))
+ {
+ int ret;
+ if (isnewtrack)
+ {
+ isnewtrack = 0;
+ trackname = x->s_track_name(trackno);
+ trackno++;
+ if (!trackname || trackname == &s_)
+ {
+ bug("mifi_read_doit: empty track name");
+ trackname = gensym("bug-track");
+ }
+ }
+ x->s_track_nevents(trackno)++;
+ if (ret = squiter_inrange(it))
+ {
+ evehook(it, (t_squeve *)evp, &ret);
+ /* We store onset times instead of delta times, because:
+ 1) some deltas may represent delays since nonchannel events;
+ 2) we'll need onsets while merging the tracks. */
+ if (ret) timhook(it, (t_float)x->s_time, &ret);
+ if (ret) tarhook(it, trackname, &ret);
+ }
+ if (ret) incrhook(it);
+ else
+ goto readfailed;
+ }
+ else if (evtype < 0x80)
+ {
+ if (evtype == MIFI_META_TEMPO)
+ {
+ tp->te_onset = x->s_time;
+ tp->te_value = x->s_tempo;
+ tp++;
+ }
+ }
+ }
+ if (evtype != MIFI_READ_EOF)
+ goto readfailed;
+
+ result = evtype;
+readfailed:
+ return (result);
+}
+
+/* Open midifile for saving, write the header. May be used as t_mifi_stream
+ allocator (if x is a null pointer), to be freed by mifi_write_end() or
+ explicitly.
+
+ Return value: null on error, else x if passed a valid pointer, else pointer
+ to allocated structure.
+*/
+t_mifi_stream *mifi_write_start(t_mifi_stream *x,
+ const char *filename, const char *dirname)
+{
+ t_mifi_stream *result = x;
+ t_bifi bifi;
+ t_bifi *bp = &bifi;
+ t_mifi_header header;
+
+ /* this must precede bifi_swap() calls */
+ bifi_new(bp, (char *)&header, MIFI_HEADER_SIZE);
+
+ if (x->s_format == 0)
+ {
+ if (x->s_ntracks != 1)
+ goto startfailure; /* LATER replace with a warning only? */
+#ifdef MIFI_VERBOSE
+ post("writing singletrack midifile %s", filename);
+#endif
+ }
+#ifdef MIFI_VERBOSE
+ else post("writing midifile %s (%d tracks)", filename, x->s_ntracks);
+#endif
+
+ strncpy(header.h_type, "MThd", 4);
+ header.h_length = bifi_swap4(MIFI_HEADERDATA_SIZE);
+ if (x)
+ {
+ if (!x->s_hdtracks || !x->s_nticks)
+ goto startfailure;
+ header.h_format = bifi_swap2(x->s_format);
+ header.h_ntracks = bifi_swap2(x->s_hdtracks);
+ if (x->s_nframes)
+ header.h_division = ((x->s_nframes << 8) | x->s_nticks) | 0x8000;
+ else
+ header.h_division = x->s_nticks & 0x7fff;
+ header.h_division = bifi_swap2(header.h_division);
+ }
+ else {
+ header.h_format = 0;
+ header.h_ntracks = bifi_swap2(1);
+ header.h_division = bifi_swap2(192); /* LATER parametrize this somehow */
+ }
+
+ if (!bifi_write_start(bp, filename, dirname))
+ {
+ bifi_error_report(bp);
+ bifi_free(bp);
+ return (0);
+ }
+
+ if (x) mifi_stream_reset(x);
+ else
+ {
+ if (!(result = mifi_stream_new()))
+ goto startfailure;
+ result->s_autoalloc = 1;
+ }
+ result->s_fp = bp->b_fp;
+ result->s_track = 0;
+
+ return (result);
+startfailure:
+ if (result && !x) mifi_stream_free(result);
+ bifi_free(bp);
+ return (0);
+}
+
+/* Close midifile, free t_mifi_stream if it was allocated
+ by mifi_write_start(). */
+void mifi_write_end(t_mifi_stream *x)
+{
+ if (x->s_autoalloc)
+ {
+ /* LATER adjust ntracks field in a file header, but do so only if
+ a stream was autoallocated -- number of tracks must be known
+ before calling mifi_write_start() for a preexisting stream. */
+ }
+ if (x->s_fp) fclose(x->s_fp);
+ if (x->s_autoalloc) mifi_stream_free(x);
+}
+
+int mifi_write_start_track(t_mifi_stream *x)
+{
+ t_mifi_trackheader header;
+ /* LATER check if (x->s_track < x->s_hdtracks)... after some thinking */
+ strncpy(header.h_type, "MTrk", 4);
+ header.h_length = 0;
+ x->s_trackid = x->s_track_id(x->s_track);
+ x->s_track++;
+ x->s_newtrack = 1;
+ x->s_status = x->s_channel = 0;
+ x->s_bytesleft = 0;
+ x->s_time = 0;
+ if (fwrite(&header, 1,
+ MIFI_TRACKHEADER_SIZE, x->s_fp) != MIFI_TRACKHEADER_SIZE)
+ {
+ post("unable to write midifile header");
+ return (0);
+ }
+ return (1);
+}
+
+/* append eot meta and update length field in a track header */
+int mifi_write_adjust_track(t_mifi_stream *x, uint32 eotdelay)
+{
+ t_mifi_event *evp = x->s_auxeve;
+ long skip;
+ uint32 length;
+ evp->e_delay = eotdelay;
+ evp->e_status = MIFI_EVENT_META;
+ evp->e_meta = MIFI_META_EOT;
+ evp->e_length = 0;
+ if (!mifi_write_event(x, evp))
+ return (0);
+ skip = x->s_bytesleft + 4;
+ length = bifi_swap4(x->s_bytesleft);
+#ifdef MIFI_DEBUG
+ post("adjusting track size to %d", x->s_bytesleft);
+#endif
+ /* LATER add sanity check (compare to saved filepos) */
+ if (skip > 4 &&
+ fseek(x->s_fp, -skip, SEEK_CUR) < 0 ||
+ fwrite(&length, 1, 4, x->s_fp) != 4 ||
+ fseek(x->s_fp, 0, SEEK_END) < 0)
+ {
+ post("unable to adjust length field in midifile track header (length %d)",
+ x->s_bytesleft);
+ return (0);
+ }
+ return (1);
+}
+
+/* LATER analyse shrinking effect caused by truncation */
+int mifi_write_event(t_mifi_stream *x, t_mifi_event *e)
+{
+ uchar buf[3], *ptr = buf;
+ size_t size = mifi_writevarlen(x, e->e_delay);
+ if (!size)
+ return (0);
+ x->s_bytesleft += size;
+ if (MIFI_IS_CHANNEL(e->e_status))
+ {
+ if ((*ptr = e->e_status | e->e_channel) == x->s_status)
+ size = 1;
+ else {
+ x->s_status = *ptr++;
+ size = 2;
+ }
+ *ptr++ = e->e_data[0];
+ if (!MIFI_ONE_DATABYTE(e->e_status))
+ {
+ *ptr = e->e_data[1];
+ size++;
+ }
+ ptr = buf;
+ }
+ else if (e->e_status == MIFI_EVENT_META)
+ {
+ x->s_status = 0; /* sysex and meta-events cancel any running status */
+ buf[0] = e->e_status;
+ buf[1] = e->e_meta;
+ if (fwrite(buf, 1, 2, x->s_fp) != 2)
+ return (0);
+ x->s_bytesleft += 2;
+ size = mifi_writevarlen(x, (uint32)(e->e_length));
+ if (!size)
+ return (0);
+ x->s_bytesleft += size;
+ size = e->e_length;
+ ptr = e->e_data;
+ }
+ else return (0);
+ if (fwrite(ptr, 1, size, x->s_fp) != size)
+ return (0);
+ x->s_bytesleft += size;
+ return (1);
+}
diff --git a/shared/common/mifi.h b/shared/common/mifi.h
new file mode 100644
index 0000000..3893616
--- /dev/null
+++ b/shared/common/mifi.h
@@ -0,0 +1,84 @@
+/* Copyright (c) 2001-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* reading/writing midifiles, a prototype version */
+
+#ifndef __MIFI_H__
+#define __MIFI_H__
+
+/* event types, as returned by mifi_read_event() */
+#define MIFI_READ_FATAL -3 /* unexpected eof, error in last track, or file error */
+#define MIFI_READ_EOF -2 /* regular eof */
+#define MIFI_READ_SKIP -1 /* error and successful skip to the next track */
+#define MIFI_META_SEQNUM 0
+#define MIFI_META_TEXT 1
+#define MIFI_META_COPYRIGHT 2
+#define MIFI_META_TRACKNAME 3
+#define MIFI_META_INSTRUMENT 4
+#define MIFI_META_LYRIC 5
+#define MIFI_META_MARKER 6
+#define MIFI_META_CUE 7
+#define MIFI_META_MAXPRINTABLE 15 /* 1..15 are various text meta-events */
+#define MIFI_META_CHANNEL 0x20 /* channel prefix */
+#define MIFI_META_EOT 0x2f /* end of track */
+#define MIFI_META_TEMPO 0x51
+#define MIFI_META_SMPTE 0x54 /* SMPTE offset */
+#define MIFI_META_TIMESIG 0x58 /* time signature */
+#define MIFI_META_KEYSIG 0x59 /* key signature */
+/* ...channel status codes go here, too obvious to #define... */
+#define MIFI_SYSEX_FIRST 0xf0
+#define MIFI_SYSEX_NEXT 0xf7
+/* this code is not returned as an event type, but in e_status of t_mifi_event */
+#define MIFI_EVENT_META 0xff
+
+/* true if one of channel messages */
+#define MIFI_IS_CHANNEL(status) (((status) & 0x80) && (status) < 0xf0)
+/* true if one of the two shorter channel messages */
+#define MIFI_ONE_DATABYTE(status) (((status) & 0xe0) == 0xc0)
+
+/* derived from t_squeve */
+typedef struct _mifi_event
+{
+ uint32 e_length;
+ uchar *e_data;
+ size_t e_bufsize;
+ uint32 e_delay;
+ uchar e_status;
+ uchar e_channel;
+ uchar e_meta; /* meta-event type */
+} t_mifi_event;
+
+/* This structure holds midi data stream properties, i.e. both the info stored
+ in midifile header, and the current state according to position in a stream. */
+/* LATER clean up t_sq and derive t_mifi_stream */
+typedef struct _sq t_mifi_stream;
+
+/* prototypes of public interface routines */
+
+t_mifi_event *mifi_event_new(void);
+void mifi_event_free(t_mifi_event *e);
+int mifi_event_settext(t_mifi_event *e, int type, char *text);
+void mifi_event_printmeta(t_mifi_event *e);
+
+t_mifi_stream *mifi_stream_new(void);
+void mifi_stream_reset(t_mifi_stream *x);
+void mifi_stream_free(t_mifi_stream *x);
+
+t_mifi_stream *mifi_read_start(t_mifi_stream *x,
+ const char *filename, const char *dirname,
+ int complain);
+int mifi_read_restart(t_mifi_stream *x);
+void mifi_read_end(t_mifi_stream *x);
+int mifi_read_event(t_mifi_stream *x, t_mifi_event *e);
+int mifi_read_analyse(t_mifi_stream *stp);
+int mifi_read_doit(t_mifi_stream *stp);
+
+t_mifi_stream *mifi_write_start(t_mifi_stream *x,
+ const char *filename, const char *dirname);
+void mifi_write_end(t_mifi_stream *x);
+int mifi_write_start_track(t_mifi_stream *x);
+int mifi_write_adjust_track(t_mifi_stream *x, uint32 eotdelay);
+int mifi_write_event(t_mifi_stream *x, t_mifi_event *e);
+
+#endif
diff --git a/shared/common/port.c b/shared/common/port.c
new file mode 100644
index 0000000..f1471bf
--- /dev/null
+++ b/shared/common/port.c
@@ -0,0 +1,612 @@
+/* Copyright (c) 1997-2003 Miller Puckette, krzYszcz, and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* CHECKME inlet/outlet vs inlet~/outlet~ */
+/* LATER think about abstractions */
+/* LATER sort out escaping rules (also revisit binport.c) */
+/* LATER quoting */
+/* LATER resolve object names (preserve connections of unknown dummies?) */
+
+#ifdef UNIX
+#include <unistd.h>
+#endif
+#ifdef NT
+#include <io.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include "m_pd.h"
+#include "common/loud.h"
+#include "common/grow.h"
+#include "common/binport.h"
+#include "common/port.h"
+
+#define PORT_INISTACK 256 /* LATER rethink */
+#define PORT_INISIZE 512 /* LATER rethink */
+
+enum { PORT_OK,
+ PORT_NEXT, /* next line, please */
+ PORT_UNKNOWN, PORT_CORRUPT, PORT_FATAL };
+
+#define PORT_DEFFONTSIZE 10.
+#define PORT_XSTRETCH 1.25
+#define PORT_YSTRETCH 1.1
+#define PORT_WSTRETCH 1.25
+
+typedef struct _port
+{
+ t_binbuf *x_oldbb;
+ t_binbuf *x_newbb;
+ int x_nobj;
+ int x_inatoms;
+ t_atom *x_inmess;
+ int x_outsize;
+ int x_outatoms;
+ t_atom *x_outmess;
+ t_atom x_outini[PORT_INISIZE];
+ int x_stacksize;
+ int x_stackdepth;
+ int *x_stack;
+ int x_stackini[PORT_INISTACK];
+} t_port;
+
+static t_float port_floatarg(t_port *x, int ndx)
+{
+ if (ndx < x->x_inatoms)
+ {
+ t_atom *av = &x->x_inmess[ndx];
+ return (av->a_type == A_FLOAT ? av->a_w.w_float : 0);
+ }
+ else return (0);
+}
+
+static t_symbol *port_symbolarg(t_port *x, int ndx)
+{
+ if (ndx < x->x_inatoms)
+ {
+ t_atom *av = &x->x_inmess[ndx];
+ return (av->a_type == A_SYMBOL ? av->a_w.w_symbol : &s_);
+ }
+ else return (&s_);
+}
+
+static int port_xstretch(float f)
+{
+ return ((int)(f * PORT_XSTRETCH + 0.5));
+}
+
+static int port_ystretch(float f)
+{
+ return ((int)(f * PORT_YSTRETCH + 0.5));
+}
+
+static int port_wstretch(float f)
+{
+ return ((int)(f * PORT_WSTRETCH + 0.5));
+}
+
+static t_float port_xarg(t_port *x, int ndx)
+{
+ return ((t_float)port_xstretch(port_floatarg(x, ndx)));
+}
+
+static t_float port_yarg(t_port *x, int ndx)
+{
+ return ((t_float)port_ystretch(port_floatarg(x, ndx)));
+}
+
+static t_float port_widtharg(t_port *x, int ndx)
+{
+ return ((t_float)port_wstretch(port_floatarg(x, ndx)));
+}
+
+static void port_setxy(t_port *x, int ndx, t_atom *ap)
+{
+ float f = port_xarg(x, ndx);
+ SETFLOAT(ap, f);
+ ndx++; ap++;
+ f = port_yarg(x, ndx);
+ SETFLOAT(ap, f);
+}
+
+static int import_obj(t_port *x, char *name)
+{
+ int ndx = (x->x_inmess[1].a_w.w_symbol == gensym("user") ? 3 : 2);
+ binbuf_addv(x->x_newbb, "ssffs;",
+ gensym("#X"), gensym("obj"),
+ port_xarg(x, ndx), port_yarg(x, ndx + 1),
+ (name ? gensym(name) :
+ x->x_inmess[ndx == 2 ? 6 : 2].a_w.w_symbol));
+ x->x_nobj++;
+ return (PORT_NEXT);
+}
+
+static int import_objarg(t_port *x, char *name)
+{
+ int ndx = (x->x_inmess[1].a_w.w_symbol == gensym("user") ? 3 : 2);
+ if (x->x_inatoms > 6)
+ {
+ t_atom *in = x->x_inmess + ndx + 4;
+ t_atom *out = x->x_outmess;
+ SETSYMBOL(out, gensym("#X")); out++;
+ SETSYMBOL(out, gensym("obj")); out++;
+ port_setxy(x, ndx, out); out++; out++;
+ if (name)
+ {
+ SETSYMBOL(out, gensym(name)); out++;
+ if (ndx == 2) in++;
+ }
+ else *out++ = (ndx == 2 ? *in++ : x->x_inmess[2]);
+ for (ndx = 7; ndx < x->x_inatoms; ndx++)
+ *out++ = *in++;
+ SETSEMI(out);
+ binbuf_add(x->x_newbb, x->x_inatoms - 1, x->x_outmess);
+ x->x_nobj++;
+ return (PORT_NEXT);
+ }
+ else return (PORT_CORRUPT);
+}
+
+static int imaction_vpatcher(t_port *x, char *arg)
+{
+ if (x->x_stackdepth >= x->x_stacksize)
+ {
+ int rqsz = x->x_stackdepth + 1;
+ int sz = rqsz;
+ x->x_stack = grow_withdata(&rqsz, &x->x_stackdepth,
+ &x->x_stacksize, x->x_stack,
+ PORT_INISTACK, x->x_stackini,
+ sizeof(*x->x_stack));
+ if (rqsz != sz)
+ {
+ post("too many embedded patches");
+ return (PORT_FATAL);
+ }
+ }
+ x->x_stack[x->x_stackdepth++] = x->x_nobj;
+ x->x_nobj = 0;
+ binbuf_addv(x->x_newbb, "ssfffff;",
+ gensym("#N"), gensym("canvas"),
+ port_xarg(x, 2), port_yarg(x, 3),
+ (float)port_xstretch(port_floatarg(x, 4) - port_floatarg(x, 2)),
+ (float)port_ystretch(port_floatarg(x, 5) - port_floatarg(x, 3)),
+ PORT_DEFFONTSIZE);
+ return (PORT_NEXT);
+}
+
+static int imaction_patcher(t_port *x, char *arg)
+{
+ binbuf_addv(x->x_newbb, "ssffss;",
+ gensym("#X"), gensym("restore"),
+ port_xarg(x, 2), port_yarg(x, 3),
+ gensym("pd"), port_symbolarg(x, 7));
+ if (x->x_stackdepth) /* LATER consider returning PORT_FATAL otherwise */
+ x->x_stackdepth--;
+ x->x_nobj = x->x_stack[x->x_stackdepth];
+ x->x_nobj++;
+ return (PORT_NEXT);
+}
+
+static int imaction_trigger(t_port *x, char *arg)
+{
+ int i;
+ for (i = 7; i < x->x_inatoms; i++)
+ if (x->x_inmess[i].a_type == A_SYMBOL &&
+ x->x_inmess[i].a_w.w_symbol == gensym("i"))
+ x->x_inmess[i].a_w.w_symbol = gensym("f");
+ return (PORT_OK);
+}
+
+static int imaction_scope(t_port *x, char *name)
+{
+ if (x->x_inatoms > 6)
+ {
+ t_atom *in = x->x_inmess + 7;
+ t_atom *out = x->x_outmess;
+ int i, xpix, ypix;
+ SETSYMBOL(out, gensym("#X")); out++;
+ SETSYMBOL(out, gensym("obj")); out++;
+ port_setxy(x, 3, out);
+ xpix = (int)out++->a_w.w_float;
+ ypix = (int)out++->a_w.w_float;
+ if (name)
+ {
+ SETSYMBOL(out, gensym(name)); out++;
+ }
+ else *out++ = x->x_inmess[2];
+ port_setxy(x, 5, out);
+ out++->a_w.w_float -= xpix;
+ out++->a_w.w_float -= ypix;
+ for (i = 7; i < x->x_inatoms; i++)
+ *out++ = *in++;
+ SETSEMI(out);
+ binbuf_add(x->x_newbb, x->x_inatoms + 1, x->x_outmess);
+ x->x_nobj++;
+ return (PORT_NEXT);
+ }
+ else return (PORT_CORRUPT);
+}
+
+/* width fontsize fontfamily encoding fontprops red green blue text... */
+static int imaction_comment(t_port *x, char *arg)
+{
+ int outatoms;
+ SETSYMBOL(x->x_outmess, gensym("#X"));
+ SETSYMBOL(x->x_outmess + 1, gensym("obj"));
+ port_setxy(x, 2, x->x_outmess + 2);
+ SETSYMBOL(x->x_outmess + 4, gensym("comment"));
+ if (x->x_inatoms > 5)
+ {
+ int i, fontsize, fontprops;
+ float width = port_widtharg(x, 4);
+ t_atom *ap = x->x_inmess + 5;
+ SETFLOAT(x->x_outmess + 5, width);
+ if (ap->a_type == A_FLOAT)
+ {
+ fontsize = ((int)ap->a_w.w_float) & 0x0ff;
+ fontprops = ((int)ap->a_w.w_float) >> 8;
+ }
+ else fontsize = 10, fontprops = 0;
+ SETFLOAT(x->x_outmess + 6, fontsize);
+ SETSYMBOL(x->x_outmess + 7, gensym("helvetica"));
+ SETSYMBOL(x->x_outmess + 8, gensym("?"));
+ SETFLOAT(x->x_outmess + 9, fontprops);
+ SETFLOAT(x->x_outmess + 10, 0);
+ SETFLOAT(x->x_outmess + 11, 0);
+ SETFLOAT(x->x_outmess + 12, 0);
+ outatoms = x->x_inatoms + 7;
+ for (i = 13; i < outatoms ; i++)
+ x->x_outmess[i] = x->x_inmess[i - 7];
+ }
+ else outatoms = 5;
+ SETSEMI(x->x_outmess + outatoms);
+ binbuf_add(x->x_newbb, outatoms + 1, x->x_outmess);
+ x->x_nobj++;
+ return (PORT_NEXT);
+}
+
+static int imaction_message(t_port *x, char *arg)
+{
+ int i;
+ SETSYMBOL(x->x_outmess, gensym("#X"));
+ SETSYMBOL(x->x_outmess + 1, gensym("msg"));
+ port_setxy(x, 2, x->x_outmess + 2);
+ for (i = 6; i < x->x_inatoms; i++)
+ x->x_outmess[i-2] = x->x_inmess[i];
+ SETSEMI(x->x_outmess + x->x_inatoms - 2);
+ binbuf_add(x->x_newbb, x->x_inatoms - 1, x->x_outmess);
+ x->x_nobj++;
+ return (PORT_NEXT);
+}
+
+/* FIXME this is no longer true */
+static int imaction_inlet(t_port *x, char *arg)
+{
+ return (import_obj(x, (port_floatarg(x, 5) ? "inlet~" : "inlet")));
+}
+
+/* FIXME this is no longer true */
+static int imaction_outlet(t_port *x, char *arg)
+{
+ return (import_obj(x, (port_floatarg(x, 5) ? "outlet~" : "outlet")));
+}
+
+static int imaction_number(t_port *x, char *arg)
+{
+ binbuf_addv(x->x_newbb, "ssff;",
+ gensym("#X"), gensym("floatatom"),
+ port_xarg(x, 2), port_yarg(x, 3));
+ x->x_nobj++;
+ return (PORT_NEXT);
+}
+
+static int imaction_connect(t_port *x, char *arg)
+{
+ binbuf_addv(x->x_newbb, "ssffff;",
+ gensym("#X"), gensym("connect"),
+ x->x_nobj - port_floatarg(x, 2) - 1,
+ port_floatarg(x, 3),
+ x->x_nobj - port_floatarg(x, 4) - 1,
+ port_floatarg(x, 5));
+ return (PORT_NEXT);
+}
+
+typedef int (*t_portaction)(t_port *, char *arg);
+
+typedef struct _portslot
+{
+ char *s_name;
+ int s_index;
+ t_portaction s_action;
+ char *s_actionarg;
+ struct _portnode *s_subtree;
+ t_symbol *s_symbol;
+} t_portslot;
+
+typedef struct _portnode /* a parser's symbol definition, sort of... */
+{
+ t_portslot *n_table;
+ int n_nslots;
+} t_portnode;
+
+#define PORT_NSLOTS(slots) (sizeof(slots)/sizeof(*(slots)))
+
+static t_portslot imslots__N[] =
+{
+ { "vpatcher", 1, imaction_vpatcher, 0, 0, 0 }
+};
+static t_portnode imnode__N = { imslots__N, PORT_NSLOTS(imslots__N) };
+
+static t_portslot imslots_newobj[] =
+{
+ { "patcher", 6, imaction_patcher, 0, 0, 0 },
+ { "p", 6, imaction_patcher, 0, 0, 0 },
+ /* state is embedded in #N vtable...; #T set...; */
+ { "table", 6, import_obj, "Table", 0, 0 }
+};
+static t_portnode imnode_newobj = { imslots_newobj,
+ PORT_NSLOTS(imslots_newobj) };
+
+/* LATER consider merging newobj and newex */
+static t_portslot imslots_newex[] =
+{
+ { "append", 6, import_objarg, "Append", 0, 0 },
+ { "biquad~", 6, import_objarg, "Biquad~", 0, 0 },
+ { "change", 6, import_objarg, "Change", 0, 0 },
+ { "clip", 6, import_objarg, "Clip", 0, 0 },
+ { "clip~", 6, import_objarg, "Clip~", 0, 0 },
+ { "key", 6, import_obj, "Key", 0, 0 },
+ { "keyup", 6, import_obj, "Keyup", 0, 0 },
+ { "line", 6, import_objarg, "Line", 0, 0 },
+ { "line~", 6, import_objarg, "Line~", 0, 0 },
+ { "poly", 6, import_objarg, "Poly", 0, 0 },
+ { "snapshot~", 6, import_objarg, "Snapshot~", 0, 0 },
+ { "trigger", 6, imaction_trigger, 0, 0, 0 },
+ { "t", 6, imaction_trigger, 0, 0, 0 }
+};
+static t_portnode imnode_newex = { imslots_newex,
+ PORT_NSLOTS(imslots_newex) };
+
+static t_portslot imslots_user[] =
+{
+ { "GSwitch", 2, import_objarg, "Gswitch", 0, 0 },
+ { "GSwitch2", 2, import_objarg, "Ggate", 0, 0 },
+ { "number~", 2, import_obj, 0, 0, 0 },
+ { "scope~", 2, imaction_scope, "Scope~", 0, 0 },
+ { "uslider", 2, import_obj, "vsl", 0, 0 } /* LATER range and offset */
+};
+static t_portnode imnode_user = { imslots_user,
+ PORT_NSLOTS(imslots_user) };
+
+static t_portslot imslots__P[] =
+{
+ { "comment", 1, imaction_comment, 0, 0, 0 },
+ { "message", 1, imaction_message, 0, 0, 0 },
+ { "newobj", 1, import_objarg, 0, &imnode_newobj, 0 },
+ { "newex", 1, import_objarg, 0, &imnode_newex, 0 },
+ { "inlet", 1, imaction_inlet, 0, 0, 0 },
+ { "inlet~", 1, imaction_inlet, 0, 0, 0 },
+ { "outlet", 1, imaction_outlet, 0, 0, 0 },
+ { "outlet~", 1, imaction_outlet, 0, 0, 0 },
+ { "number", 1, imaction_number, 0, 0, 0 },
+ { "flonum", 1, imaction_number, 0, 0, 0 },
+ { "button", 1, import_obj, "bng", 0, 0 },
+ { "slider" , 1, import_obj, "vsl", 0, 0 }, /* LATER range and offset */
+ { "hslider", 1, import_obj, "hsl", 0, 0 }, /* LATER range and offset */
+ { "toggle", 1, import_obj, "tgl", 0, 0 },
+ { "user", 1, import_objarg, 0, &imnode_user, 0 },
+ /* state is embedded in #N vpreset <nslots>; #X append... */
+ { "preset", 1, import_obj, "preset", 0, 0 },
+ /* an object created from the "Paste Picture" menu,
+ state is embedded in #N picture; #K...; */
+ { "vpicture", 1, import_obj, "vpicture", 0, 0 },
+ { "connect", 1, imaction_connect, 0, 0, 0 },
+ { "fasten", 1, imaction_connect, 0, 0, 0 }
+};
+static t_portnode imnode__P = { imslots__P, PORT_NSLOTS(imslots__P) };
+
+static t_portslot imslots_[] =
+{
+ { "#N", 0, 0, 0, &imnode__N, 0 },
+ { "#P", 0, 0, 0, &imnode__P, 0 }
+};
+static t_portnode imnode_ = { imslots_, PORT_NSLOTS(imslots_) };
+
+static int port_doit(t_port *x, t_portnode *node)
+{
+ int nslots = node->n_nslots;
+ if (nslots > 0)
+ {
+ t_portslot *slot = node->n_table;
+ t_symbol *s = port_symbolarg(x, slot->s_index);
+ while (nslots--)
+ {
+ if (slot->s_symbol == s)
+ {
+ if (slot->s_subtree)
+ {
+ int nobj = x->x_nobj;
+ int result = port_doit(x, slot->s_subtree);
+ if (result == PORT_FATAL || result == PORT_CORRUPT ||
+ result == PORT_NEXT)
+ return (result);
+ }
+ if (slot->s_action)
+ return (slot->s_action(x, slot->s_actionarg));
+ else
+ return (PORT_OK); /* LATER rethink */
+ }
+ slot++;
+ }
+ }
+ else bug("port_doit");
+ return (PORT_UNKNOWN);
+}
+
+static void port_dochecksetup(t_portnode *node)
+{
+ t_portslot *slots = node->n_table;
+ int i, nslots = node->n_nslots;
+ for (i = 0; i < nslots; i++)
+ {
+ t_portnode *subtree = slots[i].s_subtree;
+ slots[i].s_symbol = gensym(slots[i].s_name);
+ if (subtree)
+ port_dochecksetup(subtree);
+ }
+}
+
+static void port_checksetup(void)
+{
+ static int done = 0;
+ if (!done)
+ {
+ port_dochecksetup(&imnode_);
+ done = 1;
+ }
+}
+
+static t_port *port_new(void)
+{
+ t_port *x = (t_port *)getbytes(sizeof(*x));
+ x->x_oldbb = binbuf_new();
+ x->x_outsize = PORT_INISIZE;
+ x->x_outatoms = 0;
+ x->x_outmess = x->x_outini;
+ x->x_stacksize = PORT_INISTACK;
+ x->x_stackdepth = 0;
+ x->x_stack = x->x_stackini;
+ return (x);
+}
+
+static void port_free(t_port *x)
+{
+ if (x->x_outmess != x->x_outini)
+ freebytes(x->x_outmess, x->x_outsize * sizeof(*x->x_outmess));
+ if (x->x_stack != x->x_stackini)
+ freebytes(x->x_stack, x->x_stacksize * sizeof(*x->x_stack));
+ freebytes(x, sizeof(*x));
+}
+
+static int import_binbuf(t_port *x)
+{
+ t_atom *av = binbuf_getvec(x->x_oldbb);
+ int ac = binbuf_getnatom(x->x_oldbb);
+ int startmess, endmess;
+ x->x_newbb = binbuf_new();
+ for (startmess = 0; startmess < ac; startmess = endmess + 1)
+ {
+ t_atom *mess = av + startmess, *ap;
+ int i;
+ for (endmess = startmess, ap = mess;
+ ap->a_type != A_SEMI; endmess++, ap++)
+ if (endmess == ac)
+ return (PORT_CORRUPT); /* no final semi */
+ if (endmess == startmess || endmess == startmess + 1
+ || mess->a_type != A_SYMBOL || mess[1].a_type != A_SYMBOL)
+ {
+ startmess = endmess + 1;
+ continue;
+ }
+ if (mess[1].a_w.w_symbol == gensym("hidden"))
+ {
+ t_symbol *sel = mess[1].a_w.w_symbol;
+ mess[1].a_w.w_symbol = mess->a_w.w_symbol;
+ startmess++;
+ mess++;
+ if (endmess == startmess + 1 || mess[1].a_type != A_SYMBOL)
+ {
+ startmess = endmess + 1;
+ continue;
+ }
+ }
+ x->x_inatoms = endmess - startmess;
+ x->x_inmess = mess;
+ if ((i = x->x_inatoms + 16) > x->x_outsize) /* LATER rethink */
+ {
+ int sz = i;
+ x->x_outmess = grow_nodata(&sz, &x->x_outsize, x->x_outmess,
+ PORT_INISIZE, x->x_outini,
+ sizeof(*x->x_outmess));
+ if (sz != i)
+ {
+ startmess = endmess + 1;
+ continue; /* LATER rethink */
+ }
+ }
+
+ /* dollar signs in file translate to symbols,
+ LATER rethink, also #-signs */
+ for (i = 0, ap = x->x_inmess; i < x->x_inatoms; i++, ap++)
+ {
+ if (ap->a_type == A_DOLLAR)
+ {
+ char buf[100];
+ sprintf(buf, "$%d", ap->a_w.w_index);
+ SETSYMBOL(ap, gensym(buf));
+ }
+ else if (ap->a_type == A_DOLLSYM)
+ {
+ char buf[100];
+ sprintf(buf, "$%s", ap->a_w.w_symbol->s_name);
+ SETSYMBOL(ap, gensym(buf));
+ }
+ }
+ if (port_doit(x, &imnode_) == PORT_FATAL)
+ return (PORT_FATAL);
+ }
+ return (PORT_OK);
+}
+
+void import_max(char *fn, char *dir)
+{
+ t_port *x;
+ int failure, fd, ftype;
+ char buf[MAXPDSTRING], *bufp;
+ t_pd *stackp = 0;
+ int dspstate = canvas_suspend_dsp();
+ port_checksetup();
+ if ((fd = open_via_path(dir, fn, "", buf, &bufp, MAXPDSTRING, 0)) < 0)
+ {
+ loud_error(0, "%s: can't open", fn);
+ return;
+ }
+ else close (fd);
+
+ x = port_new();
+ glob_setfilename(0, gensym(bufp), gensym(buf));
+ ftype = binport_read(x->x_oldbb, bufp, buf);
+ if (ftype == BINPORT_MAXTEXT || ftype == BINPORT_PDFILE)
+ failure = binbuf_read(x->x_oldbb, bufp, buf, 0);
+ else
+ failure = (ftype != BINPORT_OK); /* LATER rethink */
+ if (failure)
+ {
+ perror(fn); /* FIXME */
+ binbuf_free(x->x_oldbb);
+ }
+ else
+ {
+ if (ftype == BINPORT_PDFILE) x->x_newbb = x->x_oldbb;
+ else
+ {
+ import_binbuf(x);
+ binbuf_free(x->x_oldbb);
+#if 1
+ binbuf_write(x->x_newbb, "import-result.pd", "", 0);
+#endif
+ }
+ binbuf_eval(x->x_newbb, 0, 0, 0);
+ binbuf_free(x->x_newbb);
+ }
+ port_free(x);
+
+ glob_setfilename(0, &s_, &s_);
+ canvas_resume_dsp(dspstate);
+ while ((stackp != s__X.s_thing) && (stackp = s__X.s_thing))
+ vmess(stackp, gensym("pop"), "i", 1);
+#if 0 /* LATER */
+ pd_doloadbang();
+#endif
+}
diff --git a/shared/common/port.h b/shared/common/port.h
new file mode 100644
index 0000000..5d2c118
--- /dev/null
+++ b/shared/common/port.h
@@ -0,0 +1,10 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __PORT_H__
+#define __PORT_H__
+
+void import_max(char *fn, char *dir);
+
+#endif
diff --git a/shared/common/rand.c b/shared/common/rand.c
new file mode 100644
index 0000000..37dcf62
--- /dev/null
+++ b/shared/common/rand.c
@@ -0,0 +1,61 @@
+/* Copyright (c) 1997-2003 Miller Puckette, krzYszcz, and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <time.h>
+#include "m_pd.h"
+EXTERN double sys_getrealtime(void); /* used to be in m_imp.h */
+#include "common/rand.h"
+
+/* borrowed from x_misc.c, LATER rethink */
+void rand_seed(unsigned int *statep, unsigned int seed)
+{
+ if (seed) *statep = (seed & 0x7fffffff);
+ else
+ {
+ /* LATER consider using time elapsed from system startup,
+ (or login -- in linux we might call getutent) */
+ static unsigned int failsafe = 1489853723;
+ static int shift = 0;
+ static unsigned int lastticks = 0;
+ /* LATER rethink -- it might fail on faster machine than mine
+ (but does it matter?) */
+ unsigned int newticks = (unsigned int)(sys_getrealtime() * 1000000.);
+ if (newticks == lastticks)
+ {
+ failsafe = failsafe * 435898247 + 938284287;
+ *statep = (failsafe & 0x7fffffff);
+#ifdef RAND_DEBUG
+ post("rand_seed failed (newticks %d)", newticks);
+#endif
+ }
+ else
+ {
+ if (!shift)
+ shift = (int)time(0); /* LATER deal with error return (-1) */
+ *statep = ((newticks + shift) & 0x7fffffff);
+#if 0
+ post("rand_seed: newticks %d, shift %d", newticks, shift);
+#endif
+ }
+ lastticks = newticks;
+ }
+}
+
+/* borrowed from x_misc.c, LATER rethink */
+int rand_int(unsigned int *statep, int range)
+{
+ int result;
+ *statep = *statep * 472940017 + 832416023;
+ result = ((double)range) * ((double)*statep) * (1./4294967296.);
+ return (result < range ? result : range - 1);
+}
+
+/* borrowed from d_osc.c, LATER rethink */
+float rand_float(unsigned int *statep)
+{
+ float result = ((float)((*statep & 0x7fffffff) - 0x40000000))
+ * (float)(1.0 / 0x40000000);
+ *statep = *statep * 435898247 + 382842987;
+ return (result);
+}
diff --git a/shared/common/rand.h b/shared/common/rand.h
new file mode 100644
index 0000000..75350d2
--- /dev/null
+++ b/shared/common/rand.h
@@ -0,0 +1,14 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __RAND_H__
+#define __RAND_H__
+
+#define RAND_DEBUG
+
+void rand_seed(unsigned int *statep, unsigned int seed);
+int rand_int(unsigned int *statep, int range);
+float rand_float(unsigned int *statep);
+
+#endif
diff --git a/shared/common/sq.c b/shared/common/sq.c
new file mode 100644
index 0000000..d7b1ea5
--- /dev/null
+++ b/shared/common/sq.c
@@ -0,0 +1,371 @@
+/* Copyright (c) 2001-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* squeak and squeal: sequencing utilities, a prototype version
+ (the main, 'sq' part of the library) */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "m_pd.h"
+#include "shared.h"
+#include "common/sq.h"
+
+#if 1
+#define SQ_VERBOSE
+#if 0
+#define SQ_DEBUG
+#endif
+#endif
+
+/* #define SQUMPI_IGNORE */
+
+#define SQUB_NALLOC 32
+#define SQUMPI_NALLOC (32 * sizeof(t_squmpo))
+#define SQUAX_NALLOC (32 * sizeof(t_squack))
+
+#define SQUMPI_DEFAULT 500000 /* 120 bpm in microseconds per beat */
+
+/* Arguments reqcount and elsize as in calloc, returns count */
+size_t squb_checksize(void *buf, size_t reqcount, size_t elsize)
+{
+ t_squb *x = buf;
+ size_t reqsize = reqcount * elsize;
+ size_t newsize = x->b_bufsize;
+ while (newsize < reqsize) newsize *= 2;
+ if (newsize == x->b_bufsize)
+ return (newsize);
+#ifdef SQ_DEBUG
+ post("need to resize buffer %x from %d to %d (requested size %d)",
+ (int)x, x->b_bufsize, newsize, reqsize);
+#endif
+ if (!(x->b_data = resizebytes(x->b_data, x->b_bufsize, newsize)) &&
+ /* rather hopeless... */
+ !(x->b_data = getbytes(newsize = SQUB_NALLOC * elsize)))
+ newsize = 0;
+ return ((x->b_bufsize = newsize) / elsize); /* LATER do it right */
+}
+
+/* generic event */
+
+/* tempo map */
+
+/* comparison function used by qsort */
+static int squmpi_compare(const void *tp1, const void *tp2)
+{
+ return (((t_squmpo *)tp1)->te_onset > ((t_squmpo *)tp2)->te_onset ? 1 : -1);
+}
+
+void squmpi_sort(t_sq *x)
+{
+ int i;
+ t_squmpo *tp;
+ qsort(x->s_tempomap, x->s_ntempi, sizeof(t_squmpo), squmpi_compare);
+#if defined SQ_VERBOSE && ! defined SQ_DEBUG
+ for (i = x->s_ntempi, tp = x->s_tempomap; i > 0 ; i--, tp++)
+ post("tempo %d at %d", tp->te_value, (int)tp->te_onset);
+#endif
+}
+
+t_squmpo *squmpi_add(t_sq *x)
+{
+ size_t count = x->s_ntempi + 1;
+ t_squmpo *tep;
+ if (squb_checksize(x->s_mytempi, count, sizeof(t_squmpo)) < count)
+ return (0);
+ tep = x->s_tempomap + x->s_ntempi++;
+ squmpo_reset(tep);
+ return (tep);
+}
+
+void squmpo_reset(t_squmpo *x)
+{
+ x->te_onset = 0;
+ x->te_value = SQUMPI_DEFAULT;
+}
+
+/* track map */
+
+t_squack *squax_add(t_sq *x)
+{
+ size_t count = x->s_ntracks + 2; /* guard point */
+ t_squack *trp;
+ if (squb_checksize(x->s_mytracks, count, sizeof(t_squack)) < count)
+ return (0);
+ trp = x->s_trackmap + x->s_ntracks++;
+ squack_reset(trp);
+ return (trp);
+}
+
+void squack_reset(t_squack *x)
+{
+ x->tr_id = 0; /* this is no-id */
+ x->tr_nevents = 0;
+ x->tr_name = 0;
+ x->tr_head = 0;
+}
+
+/* generic iterator */
+
+void *squiter_new(t_sq *x)
+{
+ if (x->s_myiter = getbytes(sizeof(*x->s_myiter)))
+ {
+ }
+ return (x->s_myiter);
+}
+
+/* routines to access iterator hooks (setting hooks is explicit only) */
+t_squiter_seekhook squiter_seekhook(t_squiter *x)
+{
+ return (x ? (t_squiter_seekhook)x->i_hooks[SQUITER_SEEKHOOK] : 0);
+}
+
+t_squiter_incrhook squiter_incrhook(t_squiter *x)
+{
+ return (x ? (t_squiter_incrhook)x->i_hooks[SQUITER_INCRHOOK] : 0);
+}
+
+t_squiter_getevehook squiter_getevehook(t_squiter *x)
+{
+ return (x ? (t_squiter_getevehook)x->i_hooks[SQUITER_GETEVEHOOK] : 0);
+}
+
+t_squiter_setevehook squiter_setevehook(t_squiter *x)
+{
+ return (x ? (t_squiter_setevehook)x->i_hooks[SQUITER_SETEVEHOOK] : 0);
+}
+
+t_squiter_gettimhook squiter_gettimhook(t_squiter *x)
+{
+ return (x ? (t_squiter_gettimhook)x->i_hooks[SQUITER_GETTIMHOOK] : 0);
+}
+
+t_squiter_settimhook squiter_settimhook(t_squiter *x)
+{
+ return (x ? (t_squiter_settimhook)x->i_hooks[SQUITER_SETTIMHOOK] : 0);
+}
+
+t_squiter_gettarhook squiter_gettarhook(t_squiter *x)
+{
+ return (x ? (t_squiter_gettarhook)x->i_hooks[SQUITER_GETTARHOOK] : 0);
+}
+
+t_squiter_settarhook squiter_settarhook(t_squiter *x)
+{
+ return (x ? (t_squiter_settarhook)x->i_hooks[SQUITER_SETTARHOOK] : 0);
+}
+
+/* time conversion */
+
+/* Compute reusable coefficient, rather then repeatedly apply the formula.
+ For smpte time:
+ d msecs == (d / 1000.) secs == ((d * nframes * nticks) / 1000.) ticks
+ or for metrical time:
+ d msecs == (d * 1000.) usecs == ((d * 1000.) / tempo) beats
+ == ((d * nticks * 1000.) / tempo) ticks
+*/
+/* LATER ntsc */
+float sq_ticks2msecs(t_sq *x, uint32 tempo)
+{
+ if (x->s_nframes)
+ return (1000. / (x->s_nframes * x->s_nticks));
+ if (tempo <= 0)
+ tempo = x->s_tempo;
+ if (tempo <= 0)
+ tempo = SQUMPI_DEFAULT;
+ return (tempo / (x->s_nticks * 1000.));
+}
+
+float sq_msecs2ticks(t_sq *x, uint32 tempo)
+{
+ if (x->s_nframes)
+ return (((x->s_nframes * x->s_nticks) / 1000.));
+ if (!tempo)
+ tempo = x->s_tempo;
+ if (!tempo)
+ tempo = SQUMPI_DEFAULT;
+ return ((x->s_nticks * 1000.) / tempo);
+}
+
+/* transform onset ticks into delta msecs */
+void sq_fold_time(t_sq *x)
+{
+ t_squiter *it = x->s_myiter;
+ t_squiter_seekhook seekhook = squiter_seekhook(it);
+ t_squiter_incrhook incrhook = squiter_incrhook(it);
+ t_squiter_gettimhook gethook = squiter_gettimhook(it);
+ t_squiter_settimhook sethook = squiter_settimhook(it);
+ int i, ret, nevents = x->s_nevents;
+
+ if (!it || !seekhook(it, 0))
+ return;
+ if (x->s_nframes)
+ {
+ float coef = sq_ticks2msecs(x, 0);
+ t_float lasttime = 0;
+ for (i = 0; i < nevents; i++)
+ {
+ if (ret = squiter_inrange(it))
+ {
+ t_float thistime = gethook(it, &ret) * coef;
+ /* back to delta time */
+ if (ret) sethook(it, thistime - lasttime, &ret);
+ lasttime = thistime;
+ }
+ if (ret) incrhook(it);
+ else
+ {
+ post("sequence folding error: bad iterator");
+ break;
+ }
+ }
+ }
+ else /* apply tempomap */
+ {
+ float coef = sq_ticks2msecs(x, SQUMPI_DEFAULT);
+ int ntempi = x->s_ntempi;
+ t_float lasttime = 0, thistime = 0;
+ t_float temposince = 0;
+ t_float tempoonset = 0;
+ int tempondx = 0;
+ for (i = 0; i < nevents; i++)
+ {
+ if (ret = squiter_inrange(it))
+ {
+ t_float thisonset = gethook(it, &ret);
+ t_float nexttempoonset;
+#ifdef SQUMPI_IGNORE
+ thistime = thisonset * coef;
+#else
+ while (tempondx < ntempi /* LATER consider using guard point */
+ && (nexttempoonset = x->s_tempo_onset(tempondx))
+ < thisonset)
+ {
+ temposince += (nexttempoonset - tempoonset) * coef;
+ tempoonset = nexttempoonset;
+ coef = sq_ticks2msecs(x, x->s_tempo_value(tempondx));
+ tempondx++;
+ }
+ thistime = temposince + (thisonset - tempoonset) * coef;
+#endif
+ if (thistime < lasttime)
+ {
+#ifdef SQ_DEBUG
+ /* FIXME under msvc -- horror! */
+ if (thistime != lasttime)
+ post("ndx %d, this-last (%x-%x) %.15f, \
+tix %.9f, tsince %.9f, ttix %.9f, coef %.9f",
+ tempondx, (int)thistime, (int)lasttime,
+ thistime - lasttime,
+ thisonset, temposince, tempoonset, coef);
+#endif
+ thistime = lasttime;
+ }
+ /* back to delta time */
+ if (ret) sethook(it, thistime - lasttime, &ret);
+ lasttime = thistime;
+ }
+ if (ret) incrhook(it);
+ else
+ {
+ post("sequence folding error: bad iterator");
+ break;
+ }
+ }
+ }
+}
+
+/* transform delta msecs into onset msecs */
+/* LATER add an option (or a separate function) for obtaining ticks
+ (according to tempomap) */
+void sq_unfold_time(t_sq *x)
+{
+ t_squiter *it = x->s_myiter;
+ t_squiter_seekhook seekhook = squiter_seekhook(it);
+ t_squiter_incrhook incrhook = squiter_incrhook(it);
+ t_squiter_gettimhook gethook = squiter_gettimhook(it);
+ t_squiter_settimhook sethook = squiter_settimhook(it);
+ int i, ret, nevents = x->s_nevents;
+ t_float thisonset = 0;
+
+ if (!it || !seekhook(it, 0))
+ return;
+ for (i = 0; i < nevents; i++)
+ {
+ if (ret = squiter_inrange(it))
+ {
+ thisonset += gethook(it, &ret);
+ if (ret) sethook(it, thisonset, &ret);
+ }
+ if (ret) incrhook(it);
+ else
+ {
+ post("sequence unfolding error: bad iterator");
+ break;
+ }
+ }
+}
+
+void sq_reset(t_sq *x)
+{
+ x->s_eof = 0;
+ x->s_newtrack = 0;
+ x->s_anapass = 1;
+ x->s_fp = 0;
+ x->s_time = 0;
+ x->s_tempo = SQUMPI_DEFAULT;
+ x->s_track = 0;
+}
+
+t_sq *sq_new(void)
+{
+ t_sq *x = (t_sq *)getbytes(sizeof(*x));
+ if (!x)
+ goto constructorfailure;
+
+ /* these two are allocated in derived structure constructor */
+ x->s_myiter = 0;
+ x->s_auxeve = 0;
+
+ if (!(x->s_mytempi = getbytes(sizeof(t_squmpi))))
+ goto constructorfailure;
+ if (!(x->s_tempomap = getbytes(x->s_mytempi->m_bufsize = SQUMPI_NALLOC)))
+ goto constructorfailure;
+ x->s_ntempi = 0;
+ if (!(x->s_mytracks = getbytes(sizeof(t_squax))))
+ goto constructorfailure;
+ if (!(x->s_trackmap = getbytes(x->s_mytracks->m_bufsize = SQUAX_NALLOC)))
+ goto constructorfailure;
+ x->s_ntracks = 0;
+
+ x->s_autoalloc = 0;
+ x->s_format = 0;
+ x->s_nticks = 192; /* LATER parametrize this somehow */
+ x->s_nframes = 0;
+
+ sq_reset(x);
+ return (x);
+constructorfailure:
+ if (x) sq_free(x);
+ return (0);
+}
+
+void sq_free(t_sq *x)
+{
+ if (x->s_mytempi)
+ {
+ if (x->s_tempomap)
+ freebytes(x->s_tempomap, x->s_mytempi->m_bufsize);
+ freebytes(x->s_mytempi, sizeof(t_squmpi));
+ }
+ if (x->s_mytracks)
+ {
+ if (x->s_trackmap)
+ freebytes(x->s_trackmap, x->s_mytracks->m_bufsize);
+ freebytes(x->s_mytracks, sizeof(t_squax));
+ }
+ if (x->s_myiter)
+ freebytes(x->s_myiter, sizeof(*x->s_myiter));
+ freebytes(x, sizeof(*x));
+}
diff --git a/shared/common/sq.h b/shared/common/sq.h
new file mode 100644
index 0000000..6b7586e
--- /dev/null
+++ b/shared/common/sq.h
@@ -0,0 +1,169 @@
+/* Copyright (c) 2001-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* squeak and squeal: sequencing utilities, a prototype version
+ (the main, 'sq' part of the library) */
+/* LATER move everything not needed in mifi to squeal */
+
+#ifndef __SQ_H__
+#define __SQ_H__
+
+/* Generic buffer structure, the `base' for t_squeve, t_squmpi and t_squax */
+typedef struct _squb
+{
+ uint32 b_length; /* length of data currently used (in items) */
+ uchar *b_data; /* data buffer */
+ size_t b_bufsize; /* allocated size of data buffer (in bytes) */
+} t_squb;
+
+/* Generic event structure. Designed as an interface to squeak routines,
+ and not to be kept in arrays or lists (use sequence containers instead).
+ Data buffer is automatically allocated and resized by those routines. */
+typedef struct _squeve
+{
+ uint32 e_length; /* set for any event type! */
+ uchar *e_data;
+ size_t e_bufsize;
+ uint32 e_delay;
+} t_squeve;
+
+/* tempo map element */
+typedef struct _squmpo
+{
+ t_float te_onset; /* ticks or microseconds from start of sequence */
+ uint32 te_value; /* microseconds per beat */
+} t_squmpo;
+
+typedef struct _squmpi
+{
+ uint32 m_ntempi;
+ t_squmpo *m_map;
+ size_t m_bufsize; /* allocated size of m_map array in bytes */
+} t_squmpi;
+
+/* track/subtrack map element */
+typedef struct _squack
+{
+ int tr_id; /* according to target template */
+ uint32 tr_nevents; /* number of events (in this track or pre-total) */
+ t_symbol *tr_name; /* track name */
+ void *tr_head; /* pointer to first event */
+} t_squack;
+
+typedef struct _squax
+{
+ uint32 m_ntracks;
+ t_squack *m_map;
+ size_t m_bufsize; /* allocated size of m_map array in bytes */
+} t_squax;
+
+/* generic type of callback routines used to read/write
+ sequence containers through t_squiter */
+typedef int (*t_squiterhook)(void *it);
+
+#define SQUITER_SEEKHOOK 0
+#define SQUITER_INCRHOOK 1
+#define SQUITER_GETEVEHOOK 2
+#define SQUITER_SETEVEHOOK 3
+#define SQUITER_GETTIMHOOK 4
+#define SQUITER_SETTIMHOOK 5
+#define SQUITER_GETTARHOOK 6
+#define SQUITER_SETTARHOOK 7
+#define SQUITER_NHOOKS 8
+/* LATER move these typedefs to sq.c, if still not used globally */
+typedef int (*t_squiter_seekhook)(void *it, int offset);
+typedef void (*t_squiter_incrhook)(void *it);
+typedef void (*t_squiter_getevehook)(void *it, t_squeve *evp, int *ret);
+typedef void (*t_squiter_setevehook)(void *it, t_squeve *evp, int *ret);
+typedef t_float (*t_squiter_gettimhook)(void *it, int *ret);
+typedef void (*t_squiter_settimhook)(void *it, t_float v, int *ret);
+typedef t_symbol (*t_squiter_gettarhook)(void *it, int *ret);
+typedef void (*t_squiter_settarhook)(void *it, t_symbol *s, int *ret);
+
+/* elements might be 'atoms' or whole events, whatever suits better */
+typedef struct _squiter
+{
+ void *i_owner;
+ int i_nelems;
+ void *i_sequence; /* first element pointer */
+ void *i_element; /* current element pointer */
+ int i_index; /* current element index */
+ t_squiterhook i_hooks[SQUITER_NHOOKS];
+} t_squiter;
+
+/* This is a good candidate for a derivation hierarchy. */
+typedef struct _sq
+{
+ t_squiter *s_myiter;
+ t_squax *s_mytracks;
+ t_squmpi *s_mytempi; /* use shortcuts #defined below */
+ void *s_auxeve; /* auxiliary event */
+ uint32 s_nevents; /* total number of events */
+ FILE *s_fp; /* hmm... */
+ int s_autoalloc:1; /* set if auto-allocated */
+ int s_eof:1; /* reading: set in case of early eof (error) */
+ int s_newtrack:1; /* reading: set if first event in a track */
+ int s_anapass:1; /* read/write: set during analysis (pass #1) */
+ uchar s_nframes; /* fps if nonzero, else use metrical time */
+ uint16 s_nticks; /* number of ticks per beat or per frame */
+ uint16 s_format; /* `ismultitrack' flag, LATER add other formats */
+ uint32 s_time; /* current time in ticks */
+ uint32 s_tempo; /* current tempo, or last one encountered in a file */
+ int s_trackid; /* LATER remove? */
+ uint16 s_track; /* current track number */
+
+ /* fields below are specific to midifile streams */
+ uchar s_status; /* current running status, | channel in writing */
+ uchar s_channel; /* current channel, not used in writing */
+ uint16 s_hdtracks; /* number of tracks declared in a midifile header */
+ uint32 s_alltracks; /* total number of nonempty tracks */
+ /* (s_ntracks counts `in range' nonempty tracks) */
+ float s_timecoef; /* msecs->ticks, used in writing only */
+ uint32 s_bytesleft; /* nbytes remaining to be read from current track,
+ or number of bytes written to a track so far */
+} t_sq;
+
+#define s_ntempi s_mytempi->m_ntempi
+#define s_tempomap s_mytempi->m_map
+#define s_tempo_onset(ndx) s_mytempi->m_map[ndx].te_onset
+#define s_tempo_value(ndx) s_mytempi->m_map[ndx].te_value
+#define s_ntracks s_mytracks->m_ntracks
+#define s_trackmap s_mytracks->m_map
+#define s_track_id(ndx) s_mytracks->m_map[ndx].tr_id
+#define s_track_nevents(ndx) s_mytracks->m_map[ndx].tr_nevents
+#define s_track_name(ndx) s_mytracks->m_map[ndx].tr_name
+#define s_track_head(ndx) s_mytracks->m_map[ndx].tr_head
+
+/* prototypes of public interface routines */
+
+size_t squb_checksize(void *buf, size_t reqcount, size_t elsize);
+
+#define squiter_inrange(it) ((it)->i_index < (it)->i_nelems)
+void *squiter_new(t_sq *x);
+t_squiter_seekhook squiter_seekhook(t_squiter *x);
+t_squiter_incrhook squiter_incrhook(t_squiter *x);
+t_squiter_getevehook squiter_getevehook(t_squiter *x);
+t_squiter_setevehook squiter_setevehook(t_squiter *x);
+t_squiter_gettimhook squiter_gettimhook(t_squiter *x);
+t_squiter_settimhook squiter_settimhook(t_squiter *x);
+t_squiter_gettarhook squiter_gettarhook(t_squiter *x);
+t_squiter_settarhook squiter_settarhook(t_squiter *x);
+
+void squmpi_sort(t_sq *x);
+t_squmpo *squmpi_add(t_sq *x);
+void squmpo_reset(t_squmpo *x);
+t_squack *squax_add(t_sq *x);
+void squack_reset(t_squack *x);
+
+float sq_ticks2msecs(t_sq *x, uint32 tempo);
+float sq_msecs2ticks(t_sq *x, uint32 tempo);
+
+void sq_fold_time(t_sq *x);
+void sq_unfold_time(t_sq *x);
+
+t_sq *sq_new(void);
+void sq_reset(t_sq *x);
+void sq_free(t_sq *x);
+
+#endif
diff --git a/shared/common/vefl.c b/shared/common/vefl.c
new file mode 100644
index 0000000..19f37a2
--- /dev/null
+++ b/shared/common/vefl.c
@@ -0,0 +1,233 @@
+/* Copyright (c) 1997-2003 Miller Puckette, krzYszcz, and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* The simplest of garrays: vector of floats */
+
+/* Array checking is done in three points:
+ 1. vefl_new(): never complains
+ 2. vefl_renew(): this should be called once per every message
+ 3. vefl_tick(): no template checking (only redraw is involved)
+*/
+
+/* LATER rethink indsp flag */
+
+#include "m_pd.h"
+#include "g_canvas.h"
+#include "shared.h"
+#include "unstable/fragile.h"
+#include "common/loud.h"
+#include "common/vefl.h"
+
+#if 1
+#define VEFL_VERBOSE
+#if 0
+#define VEFL_DEBUG
+#endif
+#endif
+
+/* on failure *vszp is not modified */
+t_float *vefl_get(t_symbol *name, int *vszp, int indsp, t_pd *complain)
+{
+ if (name && name != &s_)
+ {
+ t_garray *ap = (t_garray *)pd_findbyclass(name, garray_class);
+ if (ap)
+ {
+ int vsz;
+ t_float *vec;
+ if (garray_getfloatarray(ap, &vsz, &vec))
+ {
+ if (indsp) garray_usedindsp(ap);
+ if (vszp) *vszp = vsz;
+ return (vec);
+ }
+ else loud_error(complain, /* always complain */
+ "bad template of array '%s'", name->s_name);
+ }
+ else if (complain)
+ loud_error(complain, "no such array '%s'", name->s_name);
+ }
+ return (0);
+}
+
+static void vefl_tick(t_vefl *vp)
+{
+ if (vp->v_name && vp->v_name != &s_
+ /* Check if an array has not been deleted
+ (e.g. during patch closing sequence). */
+ && (vp->v_garray =
+ (t_garray *)pd_findbyclass(vp->v_name, garray_class)))
+ {
+ vp->v_glist = fragile_garray_glist(vp->v_garray);
+ garray_redraw(vp->v_garray);
+ }
+ vp->v_clockset = 0;
+ vp->v_updtime = clock_getsystime();
+}
+
+t_vefl *vefl_placement_new(t_vefl *vp, t_symbol *name,
+ int writable, t_glist *gl, t_garray *arr)
+{
+ if (sizeof(t_word) != sizeof(t_float))
+ {
+ bug("vefl_new: sizeof(t_word) != sizeof(t_float)");
+ return (0);
+ }
+ if (!vp)
+ {
+ if (!(vp = getbytes(sizeof(*vp))))
+ return (0);
+ vp->v_autoalloc = 1;
+ }
+ else vp->v_autoalloc = 0;
+ vp->v_name = name;
+ if (writable)
+ {
+ vp->v_updtime = clock_getsystime();
+ vp->v_clock = clock_new(vp, (t_method)vefl_tick);
+ vp->v_clockset = 0;
+ }
+ else vp->v_clock = 0;
+ vp->v_glist = gl;
+ vp->v_garray = arr;
+ vp->v_size = 0;
+ vp->v_data = 0;
+ vp->v_type = &s_float;
+ if (!arr && name && name != &s_)
+ {
+ vp->v_garray = (t_garray *)pd_findbyclass(name, garray_class);
+ vp->v_glist = vp->v_garray ? fragile_garray_glist(vp->v_garray) : 0;
+ }
+ if (vp->v_garray
+ && !garray_getfloatarray(vp->v_garray, &vp->v_size, &vp->v_data))
+ {
+ vp->v_glist = 0;
+ vp->v_garray = 0;
+ vp->v_type = 0; /* template mismatch */
+ }
+ return (vp);
+}
+
+t_vefl *vefl_new(t_symbol *name, int writable, t_glist *gl, t_garray *arr)
+{
+ return (vefl_placement_new(0, name, writable, gl, arr));
+}
+
+void vefl_free(t_vefl *vp)
+{
+ if (vp->v_clock) clock_free(vp->v_clock);
+ if (vp->v_autoalloc) freebytes(vp, sizeof(*vp));
+}
+
+/* LATER handle yonset */
+int vefl_renew(t_vefl *vp, t_symbol *name, t_pd *complain)
+{
+ if (!name || name == &s_) name = vp->v_name;
+ if (name && name != &s_)
+ {
+ vp->v_glist = 0;
+ /* There are three possible ways: */
+#if 0
+ vp->v_name = 0;
+#elif 1 /* , do nothing, and */
+ vp->v_name = name;
+#endif /* LATER check all the cases and decide... */
+ if (!(vp->v_garray = (t_garray *)pd_findbyclass(name, garray_class)))
+ {
+ if (complain)
+ loud_error(complain, "no such array '%s'", name->s_name);
+ }
+ else if (!garray_getfloatarray(vp->v_garray, &vp->v_size, &vp->v_data))
+ {
+ vp->v_garray = 0;
+ loud_error(complain, /* always complain */
+ "bad template of array '%s'", name->s_name);
+ }
+ else
+ {
+ vp->v_glist = fragile_garray_glist(vp->v_garray);
+ vp->v_name = name;
+ return (1);
+ }
+ }
+ return (0);
+}
+
+void vefl_redraw(t_vefl *vp, float suppresstime)
+{
+ if (vp->v_clock) /* requests from readers are ignored */
+ {
+ if (suppresstime > 0)
+ {
+ double timesince = clock_gettimesince(vp->v_updtime);
+ if (timesince > suppresstime)
+ {
+ clock_unset(vp->v_clock);
+ vefl_tick(vp);
+ }
+ else if (!vp->v_clockset)
+ {
+ clock_delay(vp->v_clock, suppresstime - timesince);
+ vp->v_clockset = 1;
+ }
+ }
+ else {
+ clock_unset(vp->v_clock);
+ vefl_tick(vp);
+ }
+ }
+}
+
+void vefl_redraw_stop(t_vefl *vp)
+{
+ if (vp->v_clock) /* requests from readers are ignored */
+ {
+ clock_unset(vp->v_clock);
+ vp->v_clockset = 0;
+ }
+}
+
+/* Y-bounds flipped here */
+void vefl_getbounds(t_vefl *vp, t_float *xminp, t_float *yminp,
+ t_float *xmaxp, t_float *ymaxp)
+{
+ t_glist *gl = vp->v_glist;
+ if (gl)
+ {
+ *xminp = gl->gl_x1;
+ *xmaxp = gl->gl_x2;
+ *yminp = gl->gl_y2;
+ *ymaxp = gl->gl_y1;
+ }
+}
+
+/* Y-bounds flipped here */
+void vefl_setbounds(t_vefl *vp, t_float xmin, t_float ymin,
+ t_float xmax, t_float ymax)
+{
+ vmess((t_pd *)vp->v_glist, gensym("bounds"), "ffff",
+ xmin, ymax, xmax, ymin);
+}
+
+void vefl_getrange(t_vefl *vp, t_float *yminp, t_float *ymaxp)
+{
+ int vsz = vp->v_size;
+ t_float *vec = vp->v_data;
+ if (vec && vsz)
+ {
+ t_float ymin = SHARED_FLT_MAX, ymax = -SHARED_FLT_MAX;
+ while (vsz--)
+ {
+ if (*vec > ymax)
+ {
+ ymax = *vec;
+ if (ymax < ymin) ymin = ymax;
+ }
+ else if (*vec < ymin) ymin = *vec;
+ vec++;
+ }
+ *yminp = ymin;
+ *ymaxp = ymax;
+ }
+}
diff --git a/shared/common/vefl.h b/shared/common/vefl.h
new file mode 100644
index 0000000..e470a80
--- /dev/null
+++ b/shared/common/vefl.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 2001-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __VEFL_H__
+#define __VEFL_H__
+
+typedef struct _vefl
+{
+ int v_autoalloc;
+ t_symbol *v_name;
+ t_glist *v_glist;
+ t_garray *v_garray;
+ int v_size;
+ t_float *v_data;
+ t_symbol *v_type;
+ t_clock *v_clock;
+ int v_clockset;
+ double v_updtime;
+} t_vefl;
+
+t_float *vefl_get(t_symbol *name, int *vszp, int indsp, t_pd *complain);
+t_vefl *vefl_new(t_symbol *name, int writable, t_glist *gl, t_garray *arr);
+t_vefl *vefl_placement_new(t_vefl *vp, t_symbol *name,
+ int writable, t_glist *gl, t_garray *arr);
+void vefl_free(t_vefl *vp);
+int vefl_renew(t_vefl *vp, t_symbol *name, t_pd *complain);
+void vefl_redraw(t_vefl *vp, float suppresstime);
+void vefl_redraw_stop(t_vefl *vp);
+void vefl_getbounds(t_vefl *vp, t_float *xminp, t_float *yminp,
+ t_float *xmaxp, t_float *ymaxp);
+void vefl_setbounds(t_vefl *vp, t_float xmin, t_float ymin,
+ t_float xmax, t_float ymax);
+void vefl_getrange(t_vefl *vp, t_float *yminp, t_float *ymaxp);
+
+#endif
diff --git a/shared/hammer/Makefile b/shared/hammer/Makefile
new file mode 100644
index 0000000..5dcb2c8
--- /dev/null
+++ b/shared/hammer/Makefile
@@ -0,0 +1,4 @@
+ROOT_DIR = ../..
+include $(ROOT_DIR)/Makefile.common
+
+all: $(OBJECTS)
diff --git a/shared/hammer/Makefile.objects b/shared/hammer/Makefile.objects
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/shared/hammer/Makefile.objects
diff --git a/shared/hammer/Makefile.sources b/shared/hammer/Makefile.sources
new file mode 100644
index 0000000..5a6d99a
--- /dev/null
+++ b/shared/hammer/Makefile.sources
@@ -0,0 +1,4 @@
+OTHER_SOURCES = \
+file.c \
+gui.c \
+tree.c
diff --git a/shared/hammer/file.c b/shared/hammer/file.c
new file mode 100644
index 0000000..6a94c92
--- /dev/null
+++ b/shared/hammer/file.c
@@ -0,0 +1,402 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* The three uses of the 'hammerfile' proxy class are:
+ 1. providing `embedding' facility -- storing master object's state
+ in a .pd file,
+ 2. encapsulating openpanel/savepanel management,
+ 3. extending the gui of Pd with a simple text editor window.
+
+ A master class which needs embedding feature (like coll), passes
+ a nonzero flag to the hammerfile setup routine, and a nonzero embedfn
+ function pointer to the hammerfile constructor. If a master needs
+ access to the panels (like collcommon), then it passes nonzero readfn
+ and/or writefn callback pointers to the constructor. A master which has
+ an associated text editor, AND wants to update object's state after
+ edits, passes a nonzero updatefn callback in a call to the constructor. */
+
+#include <stdio.h>
+#include <string.h>
+#include "m_pd.h"
+#include "g_canvas.h"
+/* need this for t_class::c_wb field access, LATER find a better way... */
+#include "unstable/pd_imp.h"
+#include "hammer/file.h"
+
+static t_class *hammerfile_class = 0;
+static t_hammerfile *hammerfile_proxies;
+static t_symbol *ps__C;
+
+static t_hammerfile *hammerfile_getproxy(t_pd *master)
+{
+ t_hammerfile *f;
+ for (f = hammerfile_proxies; f; f = f->f_next)
+ if (f->f_master == master)
+ return (f);
+ return (0);
+}
+
+/* FIXME somehow plug the "save changes" dialog into close-by-wm */
+/* FIXME dirty condition */
+static void hammereditor_guidefs(void)
+{
+ sys_gui("proc hammereditor_open {name geometry title} {\n");
+ sys_gui(" if {[winfo exists $name]} {\n");
+ sys_gui(" $name.text delete 1.0 end\n");
+ sys_gui(" } else {\n");
+ sys_gui(" toplevel $name\n");
+ sys_gui(" wm title $name $title\n");
+ sys_gui(" wm geometry $name $geometry\n");
+ sys_gui(" text $name.text -relief raised -bd 2 \\\n");
+ sys_gui(" -font -*-courier-medium--normal--12-* \\\n");
+ sys_gui(" -yscrollcommand \"$name.scroll set\" -background lightgrey\n");
+ sys_gui(" scrollbar $name.scroll -command \"$name.text yview\"\n");
+ sys_gui(" pack $name.scroll -side right -fill y\n");
+ sys_gui(" pack $name.text -side left -fill both -expand 1\n");
+ sys_gui(" }\n");
+ sys_gui("}\n");
+
+ sys_gui("proc hammereditor_doclose {name} {\n");
+ sys_gui(" destroy $name\n");
+ sys_gui("}\n");
+
+ sys_gui("proc hammereditor_append {name contents} {\n");
+ sys_gui(" if {[winfo exists $name]} {\n");
+ sys_gui(" $name.text insert end $contents\n");
+ sys_gui(" }\n");
+ sys_gui("}\n");
+
+ /* FIXME make it more reliable */
+ sys_gui("proc hammereditor_send {name} {\n");
+ sys_gui(" if {[winfo exists $name]} {\n");
+ sys_gui(" set ii [$name.text index [concat end - 1 lines]]\n");
+ sys_gui(" pd [concat miXed$name clear \\;]\n");
+ sys_gui(" for {set i 1} \\\n");
+ sys_gui(" {[$name.text compare $i.end < $ii]} \\\n");
+ sys_gui(" {incr i 1} {\n");
+ sys_gui(" set lin [$name.text get $i.0 $i.end]\n");
+ sys_gui(" if {$lin != \"\"} {\n");
+ /* LATER rethink semi/comma mapping */
+ sys_gui(" regsub -all \\; $lin \" _semi_ \" tmplin\n");
+ sys_gui(" regsub -all \\, $tmplin \" _comma_ \" lin\n");
+ sys_gui(" pd [concat miXed$name addline $lin \\;]\n");
+ sys_gui(" }\n");
+ sys_gui(" }\n");
+ sys_gui(" pd [concat miXed$name end \\;]\n");
+ sys_gui(" }\n");
+ sys_gui("}\n");
+
+ sys_gui("proc hammereditor_close {name ask} {\n");
+ sys_gui(" if {[winfo exists $name]} {\n");
+ sys_gui(" set dirty $ask\n"); /* FIXME */
+ sys_gui(" if {$dirty == 0} {hammereditor_doclose $name} else {\n");
+ sys_gui(" set title [wm title $name]\n");
+ sys_gui(" set answer [tk_messageBox \\-type yesnocancel \\\n");
+ sys_gui(" \\-icon question \\\n");
+ sys_gui(" \\-message [concat Save changes to $title?]]\n");
+ sys_gui(" if {$answer == \"yes\"} {hammereditor_send $name}\n");
+ sys_gui(" if {$answer != \"cancel\"} {hammereditor_doclose $name}\n");
+ sys_gui(" }\n");
+ sys_gui(" }\n");
+ sys_gui("}\n");
+}
+
+void hammereditor_open(t_hammerfile *f, char *title)
+{
+ if (!title) title = class_getname(*f->f_master);
+ sys_vgui("hammereditor_open .%x %dx%d {%s}\n", (int)f, 600, 340, title);
+}
+
+static void hammereditor_tick(t_hammerfile *f)
+{
+ sys_vgui("hammereditor_close .%x %d\n", (int)f, 1);
+}
+
+void hammereditor_close(t_hammerfile *f, int ask)
+{
+ if (ask)
+ /* hack: deferring modal dialog creation in order to allow for
+ a message box redraw to happen -- LATER investigate */
+ clock_delay(f->f_editorclock, 0);
+ else
+ sys_vgui("hammereditor_close .%x %d\n", (int)f, 0);
+}
+
+void hammereditor_append(t_hammerfile *f, char *contents)
+{
+ if (!contents) contents = "";
+ sys_vgui("hammereditor_append .%x {%s}\n", (int)f, contents);
+}
+
+static void hammereditor_clear(t_hammerfile *f)
+{
+ if (f->f_editorfn)
+ {
+ if (f->f_binbuf)
+ binbuf_clear(f->f_binbuf);
+ else
+ f->f_binbuf = binbuf_new();
+ }
+}
+
+static void hammereditor_addline(t_hammerfile *f,
+ t_symbol *s, int ac, t_atom *av)
+{
+ if (f->f_editorfn)
+ {
+ int i;
+ t_atom *ap;
+ for (i = 0, ap = av; i < ac; i++, ap++)
+ {
+ if (ap->a_type == A_SYMBOL)
+ {
+ /* LATER rethink semi/comma mapping */
+ if (!strcmp(ap->a_w.w_symbol->s_name, "_semi_"))
+ SETSEMI(ap);
+ else if (!strcmp(ap->a_w.w_symbol->s_name, "_comma_"))
+ SETCOMMA(ap);
+ }
+ }
+ binbuf_add(f->f_binbuf, ac, av);
+ }
+}
+
+static void hammereditor_end(t_hammerfile *f)
+{
+ if (f->f_editorfn)
+ {
+ (*f->f_editorfn)(f->f_master, 0, binbuf_getnatom(f->f_binbuf),
+ binbuf_getvec(f->f_binbuf));
+ binbuf_clear(f->f_binbuf);
+ }
+}
+
+static void hammerpanel_guidefs(void)
+{
+ sys_gui("proc hammerpanel_save {target inidir inifile} {\n");
+ sys_gui(" if {$inifile != \"\"} {\n");
+ sys_gui(" set filename [tk_getSaveFile \\\n");
+ sys_gui(" -initialdir $inidir -initialfile $inifile]\n");
+ sys_gui(" } else {\n");
+ sys_gui(" set filename [tk_getSaveFile]\n");
+ sys_gui(" }\n");
+ sys_gui(" if {$filename != \"\"} {\n");
+ sys_gui(" pd [concat $target symbol [pdtk_enquote $filename] \\;]\n");
+ sys_gui(" }\n");
+ sys_gui("}\n");
+}
+
+static void hammerpanel_symbol(t_hammerfile *f, t_symbol *s)
+{
+ if (s && s != &s_ && f->f_panelfn)
+ (*f->f_panelfn)(f->f_master, s, 0, 0);
+}
+
+static void hammerpanel_tick(t_hammerfile *f)
+{
+ if (f->f_savepanel)
+ sys_vgui("pdtk_openpanel %s\n", f->f_bindname->s_name);
+ else
+ sys_vgui("hammerpanel_save %s {%s} {%s}\n", f->f_bindname->s_name,
+ f->f_inidir->s_name, f->f_inifile->s_name);
+}
+
+/* these are hacks: deferring modal dialog creation in order to allow for
+ a message box redraw to happen -- LATER investigate */
+void hammerpanel_open(t_hammerfile *f)
+{
+ clock_delay(f->f_panelclock, 0);
+}
+
+void hammerpanel_save(t_hammerfile *f, t_symbol *inidir, t_symbol *inifile)
+{
+ /* LATER ask if we can rely on s_ pointing to "" */
+ f->f_savepanel->f_inidir = (inidir ? inidir : &s_);
+ f->f_savepanel->f_inifile = (inifile ? inifile : &s_);
+ clock_delay(f->f_savepanel->f_panelclock, 0);
+}
+
+/* Currently embeddable hammer classes do not use the 'saveto' method.
+ In order to use it, any embeddable class would have to add a creation
+ method to pd_canvasmaker -- then saving could be done with a 'proper'
+ sequence: #N <master> <args>; #X <whatever>; ...; #X restore <x> <y>;
+ However, this works only for -lib externals. So, we choose a sequence:
+ #X obj <x> <y> <master> <args>; #C <whatever>; ...; #C restore;
+ Since the first message in this sequence is a valid creation message
+ on its own, we have to distinguish loading from a .pd file, and other
+ cases (editing). */
+
+static void hammerembed_gc(t_pd *x, t_symbol *s, int expected)
+{
+ t_pd *garbage;
+ int count = 0;
+ while (garbage = pd_findbyclass(s, *x)) pd_unbind(garbage, s), count++;
+ if (count != expected)
+ bug("hammerembed_gc (%d garbage bindings)", count);
+}
+
+static void hammerembed_restore(t_pd *master)
+{
+ hammerembed_gc(master, ps__C, 1);
+}
+
+void hammerembed_save(t_gobj *master, t_binbuf *bb)
+{
+ t_hammerfile *f = hammerfile_getproxy((t_pd *)master);
+ t_text *t = (t_text *)master;
+ binbuf_addv(bb, "ssii", &s__X, gensym("obj"),
+ (int)t->te_xpix, (int)t->te_ypix);
+ binbuf_addbinbuf(bb, t->te_binbuf);
+ binbuf_addsemi(bb);
+ if (f && f->f_embedfn)
+ (*f->f_embedfn)(f->f_master, bb, ps__C);
+ binbuf_addv(bb, "ss;", ps__C, gensym("restore"));
+}
+
+int hammerfile_ismapped(t_hammerfile *f)
+{
+ return (f->f_canvas->gl_mapped);
+}
+
+int hammerfile_isloading(t_hammerfile *f)
+{
+ return (f->f_canvas->gl_loading);
+}
+
+/* LATER find a better way */
+int hammerfile_ispasting(t_hammerfile *f)
+{
+ int result = 0;
+ t_canvas *cv = f->f_canvas;
+ if (!cv->gl_loading)
+ {
+ t_pd *z = s__X.s_thing;
+ if (z == (t_pd *)cv)
+ {
+ pd_popsym(z);
+ if (s__X.s_thing == (t_pd *)cv) result = 1;
+ pd_pushsym(z);
+ }
+ else if (z) result = 1;
+ }
+#if 0
+ if (result) post("pasting");
+#endif
+ return (result);
+}
+
+void hammerfile_free(t_hammerfile *f)
+{
+ t_hammerfile *prev, *next;
+ hammereditor_close(f, 0);
+ if (f->f_embedfn)
+ /* just in case of missing 'restore' */
+ hammerembed_gc(f->f_master, ps__C, 0);
+ if (f->f_savepanel)
+ {
+ pd_unbind((t_pd *)f->f_savepanel, f->f_savepanel->f_bindname);
+ pd_free((t_pd *)f->f_savepanel);
+ }
+ if (f->f_bindname) pd_unbind((t_pd *)f, f->f_bindname);
+ if (f->f_panelclock) clock_free(f->f_panelclock);
+ if (f->f_editorclock) clock_free(f->f_editorclock);
+ for (prev = 0, next = hammerfile_proxies;
+ next; prev = next, next = next->f_next)
+ if (next == f)
+ break;
+ if (prev)
+ prev->f_next = f->f_next;
+ else if (f == hammerfile_proxies)
+ hammerfile_proxies = f->f_next;
+ pd_free((t_pd *)f);
+}
+
+t_hammerfile *hammerfile_new(t_pd *master, t_hammerembedfn embedfn,
+ t_hammerfilefn readfn, t_hammerfilefn writefn,
+ t_hammerfilefn updatefn)
+{
+ t_hammerfile *result = (t_hammerfile *)pd_new(hammerfile_class);
+ result->f_master = master;
+ result->f_next = hammerfile_proxies;
+ hammerfile_proxies = result;
+ if (!(result->f_canvas = canvas_getcurrent()))
+ {
+ bug("hammerfile_new: out of context");
+ return (result);
+ }
+
+ /* 1. embedding */
+ if (result->f_embedfn = embedfn)
+ {
+ /* just in case of missing 'restore' */
+ hammerembed_gc(master, ps__C, 0);
+ if (hammerfile_isloading(result) || hammerfile_ispasting(result))
+ pd_bind(master, ps__C);
+ }
+
+ /* 2. the panels */
+ if (readfn || writefn)
+ {
+ t_hammerfile *f;
+ char buf[64];
+ sprintf(buf, "miXed.%x", (int)result);
+ result->f_bindname = gensym(buf);
+ pd_bind((t_pd *)result, result->f_bindname);
+ result->f_panelfn = readfn;
+ result->f_panelclock = clock_new(result, (t_method)hammerpanel_tick);
+ f = (t_hammerfile *)pd_new(hammerfile_class);
+ f->f_master = master;
+ sprintf(buf, "miXed.%x", (int)f);
+ f->f_bindname = gensym(buf);
+ pd_bind((t_pd *)f, f->f_bindname);
+ f->f_panelfn = writefn;
+ f->f_panelclock = clock_new(f, (t_method)hammerpanel_tick);
+ result->f_savepanel = f;
+ }
+ else result->f_savepanel = 0;
+
+ /* 3. editor */
+ if (result->f_editorfn = updatefn)
+ {
+ result->f_editorclock = clock_new(result, (t_method)hammereditor_tick);
+ if (!result->f_bindname)
+ {
+ char buf[64];
+ sprintf(buf, "miXed.%x", (int)result);
+ result->f_bindname = gensym(buf);
+ pd_bind((t_pd *)result, result->f_bindname);
+ }
+ }
+ return (result);
+}
+
+void hammerfile_setup(t_class *c, int embeddable)
+{
+ if (embeddable)
+ {
+ t_widgetbehavior *newwb = getbytes(sizeof(*newwb)); /* never freed */
+ *newwb = *c->c_wb;
+ newwb->w_savefn = hammerembed_save;
+ class_setwidget(c, newwb);
+ class_addmethod(c, (t_method)hammerembed_restore,
+ gensym("restore"), 0);
+ }
+ if (!hammerfile_class)
+ {
+ ps__C = gensym("#C");
+ hammerfile_class = class_new(gensym("_hammerfile"), 0, 0,
+ sizeof(t_hammerfile),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addsymbol(hammerfile_class, hammerpanel_symbol);
+ class_addmethod(hammerfile_class, (t_method)hammereditor_clear,
+ gensym("clear"), 0);
+ class_addmethod(hammerfile_class, (t_method)hammereditor_addline,
+ gensym("addline"), A_GIMME, 0);
+ class_addmethod(hammerfile_class, (t_method)hammereditor_end,
+ gensym("end"), 0);
+ /* LATER find a way of ensuring that these are not defined yet... */
+ hammereditor_guidefs();
+ hammerpanel_guidefs();
+ }
+}
diff --git a/shared/hammer/file.h b/shared/hammer/file.h
new file mode 100644
index 0000000..d0f6526
--- /dev/null
+++ b/shared/hammer/file.h
@@ -0,0 +1,43 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __HAMMERFILE_H__
+#define __HAMMERFILE_H__
+
+typedef void (*t_hammerfilefn)(t_pd *, t_symbol *, int, t_atom *);
+typedef void (*t_hammerembedfn)(t_pd *, t_binbuf *, t_symbol *);
+
+typedef struct _hammerfile
+{
+ t_pd f_pd;
+ t_pd *f_master;
+ t_canvas *f_canvas;
+ t_symbol *f_bindname;
+ t_symbol *f_inidir;
+ t_symbol *f_inifile;
+ t_hammerfilefn f_panelfn;
+ t_hammerfilefn f_editorfn;
+ t_hammerembedfn f_embedfn;
+ t_binbuf *f_binbuf;
+ t_clock *f_panelclock;
+ t_clock *f_editorclock;
+ struct _hammerfile *f_savepanel;
+ struct _hammerfile *f_next;
+} t_hammerfile;
+
+void hammereditor_open(t_hammerfile *f, char *title);
+void hammereditor_close(t_hammerfile *f, int ask);
+void hammereditor_append(t_hammerfile *f, char *contents);
+void hammerpanel_open(t_hammerfile *f);
+void hammerpanel_save(t_hammerfile *f, t_symbol *inidir, t_symbol *inifile);
+int hammerfile_ismapped(t_hammerfile *f);
+int hammerfile_isloading(t_hammerfile *f);
+int hammerfile_ispasting(t_hammerfile *f);
+void hammerfile_free(t_hammerfile *f);
+t_hammerfile *hammerfile_new(t_pd *master, t_hammerembedfn embedfn,
+ t_hammerfilefn readfn, t_hammerfilefn writefn,
+ t_hammerfilefn updatefn);
+void hammerfile_setup(t_class *c, int embeddable);
+
+#endif
diff --git a/shared/hammer/gui.c b/shared/hammer/gui.c
new file mode 100644
index 0000000..5e98ff8
--- /dev/null
+++ b/shared/hammer/gui.c
@@ -0,0 +1,438 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* FIXME use guiconnect */
+
+#include <stdio.h>
+#include "m_pd.h"
+#include "g_canvas.h"
+#include "hammer/gui.h"
+
+//#define HAMMERGUI_DEBUG
+
+static t_class *hammergui_class = 0;
+static t_hammergui *sink = 0;
+static t_symbol *ps__up;
+static t_symbol *ps__focus;
+static t_symbol *ps__vised;
+
+static void hammergui_anything(t_hammergui *snk,
+ t_symbol *s, int ac, t_atom *av)
+{
+ /* Dummy method, filtering out messages from gui to the masters. This is
+ needed in order to keep Pd's message system happy in a ``gray period''
+ -- after last master is unbound, and before gui bindings are cleared. */
+#ifdef HAMMERGUI_DEBUG
+ startpost("%s", s->s_name);
+ postatom(ac, av);
+ endpost();
+#endif
+}
+
+/* filtering out redundant "_up" messages */
+static void hammergui__up(t_hammergui *snk, t_floatarg f)
+{
+#ifdef HAMMERGUI_DEBUG
+ post("_up %g", f);
+#endif
+ if ((int)f)
+ {
+ if (!snk->g_up)
+ {
+ snk->g_up = 1;
+ if (snk->g_mouse->s_thing)
+ {
+ t_atom at;
+ SETFLOAT(&at, 1);
+ pd_typedmess(snk->g_mouse->s_thing, ps__up, 1, &at);
+ }
+ }
+ }
+ else
+ {
+ if (snk->g_up)
+ {
+ snk->g_up = 0;
+ if (snk->g_mouse->s_thing)
+ {
+ t_atom at;
+ SETFLOAT(&at, 0);
+ pd_typedmess(snk->g_mouse->s_thing, ps__up, 1, &at);
+ }
+ }
+ }
+}
+
+static void hammergui__focus(t_hammergui *snk, t_symbol *s, t_floatarg f)
+{
+#ifdef HAMMERGUI_DEBUG
+ if (s) post("_focus %s %g", s->s_name, f);
+#endif
+ if (snk->g_focus->s_thing)
+ {
+ t_atom at[2];
+ SETSYMBOL(&at[0], s);
+ SETFLOAT(&at[1], f);
+ pd_typedmess(snk->g_focus->s_thing, ps__focus, 2, at);
+ }
+}
+
+static void hammergui__vised(t_hammergui *snk, t_symbol *s, t_floatarg f)
+{
+#ifdef HAMMERGUI_DEBUG
+ if (s) post("_vised %s %g", s->s_name, f);
+#endif
+ if (snk->g_vised->s_thing)
+ {
+ t_atom at[2];
+ SETSYMBOL(&at[0], s);
+ SETFLOAT(&at[1], f);
+ pd_typedmess(snk->g_vised->s_thing, ps__vised, 2, at);
+ }
+#if 0
+ /* How to be notified about changes of button state, prior to gui objects
+ in a canvas? LATER find a reliable way -- delete if failed */
+ sys_vgui("bindtags %s {hammertag %s Canvas . all}\n",
+ s->s_name, s->s_name);
+#endif
+}
+
+
+static void hammergui_dobindmouse(t_hammergui *snk)
+{
+#if 0
+ /* How to be notified about changes of button state, prior to gui objects
+ in a canvas? LATER find a reliable way -- delete if failed */
+ sys_vgui("bind hammertag <<hammerdown>> {pd [concat %s _up 0 \\;]}\n",
+ snk->g_gui->s_name);
+ sys_vgui("bind hammertag <<hammerup>> {pd [concat %s _up 1 \\;]}\n",
+ snk->g_gui->s_name);
+#endif
+ sys_vgui("bind all <<hammerdown>> {pd [concat %s _up 0 \\;]}\n",
+ snk->g_gui->s_name);
+ sys_vgui("bind all <<hammerup>> {pd [concat %s _up 1 \\;]}\n",
+ snk->g_gui->s_name);
+}
+
+static void hammergui__remouse(t_hammergui *snk)
+{
+ if (snk->g_mouse->s_thing)
+ {
+ /* if a new master was bound in a gray period, we need to
+ restore gui bindings */
+#if 1
+ post("rebinding mouse...");
+#endif
+ hammergui_dobindmouse(snk);
+ }
+}
+
+static void hammergui_dobindfocus(t_hammergui *snk)
+{
+ sys_vgui("bind Canvas <<hammerfocusin>> \
+ {pd [concat %s _focus %%W 1 \\;]}\n", snk->g_gui->s_name);
+ sys_vgui("bind Canvas <<hammerfocusout>> \
+ {pd [concat %s _focus %%W 0 \\;]}\n", snk->g_gui->s_name);
+}
+
+static void hammergui__refocus(t_hammergui *snk)
+{
+ if (snk->g_focus->s_thing)
+ {
+ /* if a new master was bound in a gray period, we need to
+ restore gui bindings */
+#if 1
+ post("rebinding focus...");
+#endif
+ hammergui_dobindfocus(snk);
+ }
+}
+
+static void hammergui_dobindvised(t_hammergui *snk)
+{
+ sys_vgui("bind Canvas <<hammervised>> \
+ {pd [concat %s _vised %%W 1 \\;]}\n", snk->g_gui->s_name);
+ sys_vgui("bind Canvas <<hammerunvised>> \
+ {pd [concat %s _vised %%W 0 \\;]}\n", snk->g_gui->s_name);
+}
+
+static void hammergui__revised(t_hammergui *snk)
+{
+ if (snk->g_vised->s_thing)
+ {
+ /* if a new master was bound in a gray period, we need to
+ restore gui bindings */
+#if 1
+ post("rebinding vised events...");
+#endif
+ hammergui_dobindvised(snk);
+ }
+}
+
+static void hammergui_setup(void)
+{
+ hammergui_class = class_new(gensym("_hammergui"), 0, 0,
+ sizeof(t_hammergui),
+ CLASS_PD | CLASS_NOINLET, 0);
+ class_addanything(hammergui_class, hammergui_anything);
+ class_addmethod(hammergui_class, (t_method)hammergui__remouse,
+ gensym("_remouse"), 0);
+ class_addmethod(hammergui_class, (t_method)hammergui__refocus,
+ gensym("_refocus"), 0);
+ class_addmethod(hammergui_class, (t_method)hammergui__revised,
+ gensym("_revised"), 0);
+ ps__up = gensym("_up");
+ class_addmethod(hammergui_class, (t_method)hammergui__up,
+ ps__up, A_FLOAT, 0);
+ ps__focus = gensym("_focus");
+ class_addmethod(hammergui_class, (t_method)hammergui__focus,
+ ps__focus, A_SYMBOL, A_FLOAT, 0);
+ ps__vised = gensym("_vised");
+ class_addmethod(hammergui_class, (t_method)hammergui__vised,
+ ps__vised, A_SYMBOL, A_FLOAT, 0);
+
+ sys_gui("proc hammergui_remouse {} {\n");
+ sys_gui(" bind all <<hammerdown>> {}\n");
+ sys_gui(" bind all <<hammerup>> {}\n");
+ sys_gui(" pd [concat #hammergui _remouse \\;]\n");
+ sys_gui("}\n");
+
+ sys_gui("proc hammergui_mousexy {target} {\n");
+ sys_gui(" set x [winfo pointerx .]\n");
+ sys_gui(" set y [winfo pointery .]\n");
+ sys_gui(" pd [concat #hammermouse $target $x $y \\;]\n");
+ sys_gui("}\n");
+
+ /* visibility hack for msw, LATER rethink */
+ sys_gui("global hammergui_ispolling\n");
+ sys_gui("global hammergui_x\n");
+ sys_gui("global hammergui_y\n");
+ sys_gui("set hammergui_ispolling 0\n");
+ sys_gui("set hammergui_x 0\n");
+ sys_gui("set hammergui_y 0\n");
+
+ sys_gui("proc hammergui_poll {} {\n");
+ sys_gui(" global hammergui_ispolling\n");
+ sys_gui(" global hammergui_x\n");
+ sys_gui(" global hammergui_y\n");
+ sys_gui(" if {$hammergui_ispolling == 1} {\n");
+ sys_gui(" set x [winfo pointerx .]\n");
+ sys_gui(" set y [winfo pointery .]\n");
+ sys_gui(" if {$hammergui_x != $x || $hammergui_y != $y} {\n");
+ sys_gui(" pd [concat #hammermouse _poll $x $y \\;]\n");
+ sys_gui(" set hammergui_x $x\n");
+ sys_gui(" set hammergui_y $y\n");
+ sys_gui(" }\n");
+ sys_gui(" after 50 hammergui_poll\n");
+ sys_gui(" }\n");
+ sys_gui("}\n");
+
+ sys_gui("proc hammergui_refocus {} {\n");
+ sys_gui(" bind Canvas <<hammerfocusin>> {}\n");
+ sys_gui(" bind Canvas <<hammerfocusout>> {}\n");
+ sys_gui(" pd [concat #hammergui _refocus \\;]\n");
+ sys_gui("}\n");
+
+ sys_gui("proc hammergui_revised {} {\n");
+ sys_gui(" bind Canvas <<hammervised>> {}\n");
+ sys_gui(" bind Canvas <<hammerunvised>> {}\n");
+ sys_gui(" pd [concat #hammergui _revised \\;]\n");
+ sys_gui("}\n");
+}
+
+static int hammergui_validate(int dosetup)
+{
+ if (dosetup)
+ {
+ if (!hammergui_class) hammergui_setup();
+ if (!sink)
+ {
+ sink = (t_hammergui *)pd_new(hammergui_class);
+ sink->g_gui = gensym("#hammergui");
+ pd_bind((t_pd *)sink, sink->g_gui);
+ }
+ }
+ if (hammergui_class && sink)
+ return (1);
+ else
+ {
+ bug("hammergui_validate");
+ return (0);
+ }
+}
+
+static int hammergui_mousevalidate(int dosetup)
+{
+ if (dosetup && !sink->g_mouse)
+ {
+ sink->g_mouse = gensym("#hammermouse");
+ sys_gui("event add <<hammerdown>> <ButtonPress>\n");
+ sys_gui("event add <<hammerup>> <ButtonRelease>\n");
+ }
+ if (sink->g_mouse)
+ return (1);
+ else
+ {
+ bug("hammergui_mousevalidate");
+ return (0);
+ }
+}
+
+static int hammergui_pollvalidate(int dosetup)
+{
+ if (dosetup && !sink->g_poll)
+ {
+ sink->g_poll = gensym("#hammerpoll");
+ pd_bind((t_pd *)sink, sink->g_poll); /* never unbound */
+ }
+ if (sink->g_poll)
+ return (1);
+ else
+ {
+ bug("hammergui_pollvalidate");
+ return (0);
+ }
+}
+
+static int hammergui_focusvalidate(int dosetup)
+{
+ if (dosetup && !sink->g_focus)
+ {
+ sink->g_focus = gensym("#hammerfocus");
+ sys_gui("event add <<hammerfocusin>> <FocusIn>\n");
+ sys_gui("event add <<hammerfocusout>> <FocusOut>\n");
+ }
+ if (sink->g_focus)
+ return (1);
+ else
+ {
+ bug("hammergui_focusvalidate");
+ return (0);
+ }
+}
+
+static int hammergui_visedvalidate(int dosetup)
+{
+ if (dosetup && !sink->g_vised)
+ {
+ sink->g_vised = gensym("#hammervised");
+ /* subsequent map events have to be filtered out at the caller's side,
+ LATER investigate */
+ sys_gui("event add <<hammervised>> <Map>\n");
+ sys_gui("event add <<hammerunvised>> <Destroy>\n");
+ }
+ if (sink->g_vised)
+ return (1);
+ else
+ {
+ bug("hammergui_visedvalidate");
+ return (0);
+ }
+}
+
+void hammergui_bindmouse(t_pd *master)
+{
+ hammergui_validate(1);
+ hammergui_mousevalidate(1);
+ if (!sink->g_mouse->s_thing)
+ hammergui_dobindmouse(sink);
+ pd_bind(master, sink->g_mouse);
+}
+
+void hammergui_unbindmouse(t_pd *master)
+{
+ if (hammergui_validate(0) && hammergui_mousevalidate(0)
+ && sink->g_mouse->s_thing)
+ {
+ pd_unbind(master, sink->g_mouse);
+ if (!sink->g_mouse->s_thing)
+ sys_gui("hammergui_remouse\n");
+ }
+ else bug("hammergui_unbindmouse");
+}
+
+void hammergui_mousexy(t_symbol *s)
+{
+ if (hammergui_validate(0))
+ sys_vgui("hammergui_mousexy %s\n", s->s_name);
+}
+
+void hammergui_willpoll(void)
+{
+ hammergui_validate(1);
+ hammergui_pollvalidate(1);
+}
+
+void hammergui_startpolling(t_pd *master)
+{
+ if (hammergui_validate(0) && hammergui_pollvalidate(0))
+ {
+ int doinit = (sink->g_poll->s_thing == (t_pd *)sink);
+ pd_bind(master, sink->g_poll);
+ if (doinit)
+ {
+ /* visibility hack for msw, LATER rethink */
+ sys_gui("global hammergui_ispolling\n");
+ sys_gui("set hammergui_ispolling 1\n");
+ sys_gui("hammergui_poll\n");
+ }
+ }
+}
+
+void hammergui_stoppolling(t_pd *master)
+{
+ if (hammergui_validate(0) && hammergui_pollvalidate(0))
+ {
+ pd_unbind(master, sink->g_poll);
+ if (sink->g_poll->s_thing == (t_pd *)sink)
+ {
+ sys_gui("after cancel hammergui_poll\n");
+ /* visibility hack for msw, LATER rethink */
+ sys_gui("global hammergui_ispolling\n");
+ sys_gui("set hammergui_ispolling 0\n");
+ }
+ }
+}
+
+void hammergui_bindfocus(t_pd *master)
+{
+ hammergui_validate(1);
+ hammergui_focusvalidate(1);
+ if (!sink->g_focus->s_thing)
+ hammergui_dobindfocus(sink);
+ pd_bind(master, sink->g_focus);
+}
+
+void hammergui_unbindfocus(t_pd *master)
+{
+ if (hammergui_validate(0) && hammergui_focusvalidate(0)
+ && sink->g_focus->s_thing)
+ {
+ pd_unbind(master, sink->g_focus);
+ if (!sink->g_focus->s_thing)
+ sys_gui("hammergui_refocus\n");
+ }
+ else bug("hammergui_unbindfocus");
+}
+
+void hammergui_bindvised(t_pd *master)
+{
+ hammergui_validate(1);
+ hammergui_visedvalidate(1);
+ if (!sink->g_vised->s_thing)
+ hammergui_dobindvised(sink);
+ pd_bind(master, sink->g_vised);
+}
+
+void hammergui_unbindvised(t_pd *master)
+{
+ if (hammergui_validate(0) && hammergui_visedvalidate(0)
+ && sink->g_vised->s_thing)
+ {
+ pd_unbind(master, sink->g_vised);
+ if (!sink->g_vised->s_thing)
+ sys_gui("hammergui_revised\n");
+ }
+ else bug("hammergui_unbindvised");
+}
diff --git a/shared/hammer/gui.h b/shared/hammer/gui.h
new file mode 100644
index 0000000..13afd0a
--- /dev/null
+++ b/shared/hammer/gui.h
@@ -0,0 +1,30 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __HAMMERGUI_H__
+#define __HAMMERGUI_H__
+
+typedef struct _hammergui
+{
+ t_pd g_pd;
+ t_symbol *g_gui;
+ t_symbol *g_mouse;
+ t_symbol *g_poll;
+ t_symbol *g_focus;
+ t_symbol *g_vised;
+ int g_up;
+} t_hammergui;
+
+void hammergui_bindmouse(t_pd *master);
+void hammergui_unbindmouse(t_pd *master);
+void hammergui_mousexy(t_symbol *s);
+void hammergui_willpoll(void);
+void hammergui_startpolling(t_pd *master);
+void hammergui_stoppolling(t_pd *master);
+void hammergui_bindfocus(t_pd *master);
+void hammergui_unbindfocus(t_pd *master);
+void hammergui_bindvised(t_pd *master);
+void hammergui_unbindvised(t_pd *master);
+
+#endif
diff --git a/shared/hammer/tree.c b/shared/hammer/tree.c
new file mode 100644
index 0000000..549dd09
--- /dev/null
+++ b/shared/hammer/tree.c
@@ -0,0 +1,482 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "hammer/tree.h"
+
+/* Since there is no sentinel node, the deletion routine has to have
+ a few extra checks. LATER rethink. */
+
+/* LATER freelist */
+
+#ifdef HAMMERTREE_DEBUG
+/* returns bh or 0 if failed */
+static int hammernode_verify(t_hammernode *np)
+{
+ if (np)
+ {
+ int bhl, bhr;
+ if (((bhl = hammernode_verify(np->n_left)) == 0) ||
+ ((bhr = hammernode_verify(np->n_right)) == 0))
+ return (0);
+ if (bhl != bhr)
+ {
+ /* failure: two paths rooted in the same node
+ contain different number of black nodes */
+ bug("hammernode_verify: not balanced");
+ return (0);
+ }
+ if (np->n_black)
+ return (bhl + 1);
+ else
+ {
+ if ((np->n_left && !np->n_left->n_black) ||
+ (np->n_right && !np->n_right->n_black))
+ {
+ bug("hammernode_verify: adjacent red nodes");
+ return (0);
+ }
+ return (bhl);
+ }
+ }
+ else return (1);
+}
+
+/* returns bh or 0 if failed */
+static int hammertree_verify(t_hammertree *tree)
+{
+ return (hammernode_verify(tree->t_root));
+}
+
+static void hammernode_post(t_hammernode *np)
+{
+ startpost("%d %g %d (", np->n_index, np->n_value, np->n_black);
+ if (np->n_left)
+ startpost("%d, ", np->n_left->n_index);
+ else
+ startpost("nul, ");
+ if (np->n_right)
+ post("%d)", np->n_right->n_index);
+ else
+ post("nul)");
+}
+
+/* this is a standard stackless traversal, not the best one, obviously...
+ (used only for debugging) */
+static int hammertree_traverse(t_hammertree *tree, int postit)
+{
+ t_hammernode *np = tree->t_root;
+ int count = 0;
+ while (np)
+ {
+ t_hammernode *prev = np->n_left;
+ if (prev)
+ {
+ while (prev->n_right && prev->n_right != np) prev = prev->n_right;
+ if (prev->n_right)
+ {
+ prev->n_right = 0;
+ if (postit) hammernode_post(np);
+ count++;
+ np = np->n_right;
+ }
+ else
+ {
+ prev->n_right = np;
+ np = np->n_left;
+ }
+ }
+ else
+ {
+ if (postit) hammernode_post(np);
+ count++;
+ np = np->n_right;
+ }
+ }
+ return (count);
+}
+
+static int hammernode_height(t_hammernode *np)
+{
+ if (np)
+ {
+ int lh = hammernode_height(np->n_left);
+ int rh = hammernode_height(np->n_right);
+ return (lh > rh ? lh + 1 : rh + 1);
+ }
+ else return (0);
+}
+
+void hammertree_debug(t_hammertree *tree, int level)
+{
+ t_hammernode *np;
+ int count;
+ post("------------------------");
+ count = hammertree_traverse(tree, level);
+ if (level > 1)
+ {
+ post("***");
+ for (np = tree->t_last; np; np = np->n_prev)
+ startpost("%d ", np->n_index);
+ endpost();
+ }
+ post("count %d, height %d, root %d:",
+ count, hammernode_height(tree->t_root),
+ (tree->t_root ? tree->t_root->n_index : 0));
+ post("...verified (black-height is %d)", hammertree_verify(tree));
+ post("------------------------");
+}
+#endif
+
+/* assuming that target node (np->n_right) exists */
+static void hammertree_lrotate(t_hammertree *tree, t_hammernode *np)
+{
+ t_hammernode *target = np->n_right;
+ if (np->n_right = target->n_left)
+ np->n_right->n_parent = np;
+ if (!(target->n_parent = np->n_parent))
+ tree->t_root = target;
+ else if (np == np->n_parent->n_left)
+ np->n_parent->n_left = target;
+ else
+ np->n_parent->n_right = target;
+ target->n_left = np;
+ np->n_parent = target;
+}
+
+/* assuming that target node (np->n_left) exists */
+static void hammertree_rrotate(t_hammertree *tree, t_hammernode *np)
+{
+ t_hammernode *target = np->n_left;
+ if (np->n_left = target->n_right)
+ np->n_left->n_parent = np;
+ if (!(target->n_parent = np->n_parent))
+ tree->t_root = target;
+ else if (np == np->n_parent->n_left)
+ np->n_parent->n_left = target;
+ else
+ np->n_parent->n_right = target;
+ target->n_right = np;
+ np->n_parent = target;
+}
+
+/* returns a newly inserted or already existing node
+ (or 0 if allocation failed) */
+t_hammernode *hammertree_insert(t_hammertree *tree, int ndx)
+{
+ t_hammernode *np, *parent, *result;
+ if (!(np = tree->t_root))
+ {
+ if (!(np = getbytes(sizeof(*np))))
+ return (0);
+ np->n_index = ndx;
+ np->n_black = 1;
+ tree->t_root = tree->t_first = tree->t_last = np;
+ return (np);
+ }
+
+ do
+ if (np->n_index == ndx)
+ return (np);
+ else
+ parent = np;
+ while (np = (ndx < np->n_index ? np->n_left : np->n_right));
+
+ if (!(np = getbytes(sizeof(*np))))
+ return (0);
+ np->n_index = ndx;
+ np->n_parent = parent;
+ if (ndx < parent->n_index)
+ {
+ parent->n_left = np;
+ /* update the auxiliary linked list structure */
+ np->n_next = parent;
+ if (np->n_prev = parent->n_prev)
+ np->n_prev->n_next = np;
+ else
+ tree->t_first = np;
+ parent->n_prev = np;
+ }
+ else
+ {
+ parent->n_right = np;
+ /* update the auxiliary linked list structure */
+ np->n_prev = parent;
+ if (np->n_next = parent->n_next)
+ np->n_next->n_prev = np;
+ else
+ tree->t_last = np;
+ parent->n_next = np;
+ }
+ result = np;
+
+ /* balance the tree -- LATER clean this if possible... */
+ np->n_black = 0;
+ while (np != tree->t_root && !np->n_parent->n_black)
+ {
+ t_hammernode *uncle;
+ /* np->n_parent->n_parent exists (we always paint root node in black) */
+ if (np->n_parent == np->n_parent->n_parent->n_left)
+ {
+ uncle = np->n_parent->n_parent->n_right;
+ if (!uncle /* (sentinel not used) */
+ || uncle->n_black)
+ {
+ if (np == np->n_parent->n_right)
+ {
+ np = np->n_parent;
+ hammertree_lrotate(tree, np);
+ }
+ np->n_parent->n_black = 1;
+ np->n_parent->n_parent->n_black = 0;
+ hammertree_rrotate(tree, np->n_parent->n_parent);
+ }
+ else
+ {
+ np->n_parent->n_black = 1;
+ uncle->n_black = 1;
+ np = np->n_parent->n_parent;
+ np->n_black = 0;
+ }
+ }
+ else
+ {
+ uncle = np->n_parent->n_parent->n_left;
+ if (!uncle /* (sentinel not used) */
+ || uncle->n_black)
+ {
+ if (np == np->n_parent->n_left)
+ {
+ np = np->n_parent;
+ hammertree_rrotate(tree, np);
+ }
+ np->n_parent->n_black = 1;
+ np->n_parent->n_parent->n_black = 0;
+ hammertree_lrotate(tree, np->n_parent->n_parent);
+ }
+ else
+ {
+ np->n_parent->n_black = 1;
+ uncle->n_black = 1;
+ np = np->n_parent->n_parent;
+ np->n_black = 0;
+ }
+ }
+ }
+ tree->t_root->n_black = 1;
+ return (result);
+}
+
+/* assuming that requested node exists */
+void hammertree_delete(t_hammertree *tree, t_hammernode *np)
+{
+ t_hammernode *gone, *parent, *child;
+ /* gone is the actual node to be deleted
+ -- it has to be the parent of no more than one child: */
+ if (np->n_left && np->n_right)
+ {
+ gone = np->n_next; /* gone always exists */
+ child = gone->n_right; /* there is no left child of gone */
+ /* gone is not a requested node, so we replace fields to be
+ deleted with gone's fields: */
+ np->n_index = gone->n_index;
+ np->n_value = gone->n_value;
+ /* update the auxiliary linked list structure */
+ /* np->n_prev is up-to-date */
+ if (np->n_prev)
+ np->n_prev->n_next = np;
+ else tree->t_first = np;
+ if (np->n_next = gone->n_next)
+ np->n_next->n_prev = np;
+ else tree->t_last = np;
+ }
+ else
+ {
+ gone = np;
+ if (gone->n_left)
+ child = gone->n_left;
+ else
+ child = gone->n_right;
+ /* update the auxiliary linked list structure */
+ if (gone->n_prev)
+ gone->n_prev->n_next = gone->n_next;
+ else
+ tree->t_first = gone->n_next;
+ if (gone->n_next)
+ gone->n_next->n_prev = gone->n_prev;
+ else
+ tree->t_last = gone->n_prev;
+ }
+ /* connect gone's child with gone's parent */
+ if (!(parent = gone->n_parent))
+ {
+ if (tree->t_root = child)
+ {
+ child->n_parent = 0;
+ child->n_black = 1; /* LATER rethink */
+ }
+ goto done;
+ }
+ else
+ {
+ if (child) /* (sentinel not used) */
+ child->n_parent = parent;
+ if (gone == parent->n_left)
+ parent->n_left = child;
+ else
+ parent->n_right = child;
+ }
+
+ if (gone->n_black)
+ {
+ /* balance the tree -- LATER clean this if possible... */
+ /* on entry: tree is not empty, parent always exists, child
+ not necessarily... */
+ while (child != tree->t_root &&
+ (!child || /* (sentinel not used) */
+ child->n_black))
+ {
+ t_hammernode *other; /* another child of the same parent */
+ if (child == parent->n_left)
+ {
+ other = parent->n_right;
+ if (other && /* (sentinel not used) */
+ !other->n_black)
+ {
+ other->n_black = 1;
+ parent->n_black = 0;
+ hammertree_lrotate(tree, parent);
+ other = parent->n_right;
+ }
+ if (!other || /* (sentinel not used) */
+ (!other->n_left || other->n_left->n_black) &&
+ (!other->n_right || other->n_right->n_black))
+ {
+ if (other) /* (sentinel not used) */
+ other->n_black = 0;
+ child = parent;
+ parent = parent->n_parent;
+ }
+ else
+ {
+ if (!other || /* (sentinel not used) */
+ !other->n_right || other->n_right->n_black)
+ {
+ if (other) /* (sentinel not used) */
+ {
+ if (other->n_left) other->n_left->n_black = 1;
+ other->n_black = 0;
+ hammertree_rrotate(tree, other);
+ other = parent->n_right;
+ }
+ }
+ if (other) /* (sentinel not used) */
+ {
+ if (other->n_right) other->n_right->n_black = 1;
+ other->n_black = parent->n_black;
+ }
+ parent->n_black = 1;
+ hammertree_lrotate(tree, parent);
+ tree->t_root->n_black = 1; /* LATER rethink */
+ goto done;
+ }
+ }
+ else /* right child */
+ {
+ other = parent->n_left;
+ if (other && /* (sentinel not used) */
+ !other->n_black)
+ {
+ other->n_black = 1;
+ parent->n_black = 0;
+ hammertree_rrotate(tree, parent);
+ other = parent->n_left;
+ }
+ if (!other || /* (sentinel not used) */
+ (!other->n_left || other->n_left->n_black) &&
+ (!other->n_right || other->n_right->n_black))
+ {
+ if (other) /* (sentinel not used) */
+ other->n_black = 0;
+ child = parent;
+ parent = parent->n_parent;
+ }
+ else
+ {
+ if (!other || /* (sentinel not used) */
+ !other->n_left || other->n_left->n_black)
+ {
+ if (other) /* (sentinel not used) */
+ {
+ if (other->n_right) other->n_right->n_black = 1;
+ other->n_black = 0;
+ hammertree_lrotate(tree, other);
+ other = parent->n_left;
+ }
+ }
+ if (other) /* (sentinel not used) */
+ {
+ if (other->n_left) other->n_left->n_black = 1;
+ other->n_black = parent->n_black;
+ }
+ parent->n_black = 1;
+ hammertree_rrotate(tree, parent);
+ tree->t_root->n_black = 1; /* LATER rethink */
+ goto done;
+ }
+ }
+ }
+ if (child) /* (sentinel not used) */
+ child->n_black = 1;
+ }
+done:
+ freebytes(gone, sizeof(*gone));
+#ifdef HAMMERTREE_DEBUG
+ hammertree_verify(tree);
+#endif
+}
+
+t_hammernode *hammertree_search(t_hammertree *tree, int ndx)
+{
+ t_hammernode *np = tree->t_root;
+ while (np && np->n_index != ndx)
+ np = (ndx < np->n_index ? np->n_left : np->n_right);
+ return (np);
+}
+
+t_hammernode *hammertree_closest(t_hammertree *tree, int ndx, int geqflag)
+{
+ t_hammernode *np, *parent;
+ if (!(np = tree->t_root))
+ return (0);
+ do
+ if (np->n_index == ndx)
+ return (np);
+ else
+ parent = np;
+ while (np = (ndx < np->n_index ? np->n_left : np->n_right));
+ if (geqflag)
+ return (ndx > parent->n_index ? parent->n_next : parent);
+ else
+ return (ndx < parent->n_index ? parent->n_prev : parent);
+}
+
+/* LATER preallocate 'freecount' nodes */
+void hammertree_init(t_hammertree *tree, int freecount)
+{
+ tree->t_root = tree->t_first = tree->t_last = 0;
+}
+
+/* LATER keep and/or preallocate 'freecount' nodes (if negative, keep all) */
+void hammertree_clear(t_hammertree *tree, int freecount)
+{
+ t_hammernode *np, *next = tree->t_first;
+ while (next)
+ {
+ np = next;
+ next = next->n_next;
+ freebytes(np, sizeof(*np));
+ }
+ hammertree_init(tree, 0);
+}
diff --git a/shared/hammer/tree.h b/shared/hammer/tree.h
new file mode 100644
index 0000000..fcbc036
--- /dev/null
+++ b/shared/hammer/tree.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __HAMMERTREE_H__
+#define __HAMMERTREE_H__
+
+#define HAMMERTREE_DEBUG
+
+typedef struct _hammernode
+{
+ int n_index;
+ float n_value;
+ int n_black;
+ struct _hammernode *n_left;
+ struct _hammernode *n_right;
+ struct _hammernode *n_parent;
+ struct _hammernode *n_prev;
+ struct _hammernode *n_next;
+} t_hammernode;
+
+typedef struct _hammertree
+{
+ t_hammernode *t_root;
+ t_hammernode *t_first;
+ t_hammernode *t_last;
+} t_hammertree;
+
+t_hammernode *hammertree_insert(t_hammertree *tree, int ndx);
+void hammertree_delete(t_hammertree *tree, t_hammernode *np);
+t_hammernode *hammertree_search(t_hammertree *tree, int ndx);
+t_hammernode *hammertree_closest(t_hammertree *tree, int ndx, int geqflag);
+void hammertree_init(t_hammertree *tree, int freecount);
+void hammertree_clear(t_hammertree *tree, int freecount);
+void hammertree_debug(t_hammertree *tree, int level);
+
+#endif
diff --git a/shared/shared.c b/shared/shared.c
new file mode 100644
index 0000000..d6d2c98
--- /dev/null
+++ b/shared/shared.c
@@ -0,0 +1,11 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "shared.h"
+
+void shared_debug(void)
+{
+ /* LATER */
+}
diff --git a/shared/shared.h b/shared/shared.h
new file mode 100644
index 0000000..a0bd0e6
--- /dev/null
+++ b/shared/shared.h
@@ -0,0 +1,166 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __SHARED_H__
+#define __SHARED_H__
+
+/* LATER find a proper place for #include <limits.h> */
+#ifdef INT_MAX
+#define SHARED_INT_MAX INT_MAX
+#else
+#define SHARED_INT_MAX 0x7FFFFFFF
+#endif
+#ifdef INT_MIN
+#define SHARED_INT_MIN INT_MIN
+#else
+#define SHARED_INT_MIN ((int)0x80000000)
+#endif
+/* LATER find a proper place for #include <float.h> */
+#ifdef FLT_MAX
+#define SHARED_FLT_MAX FLT_MAX
+#else
+#define SHARED_FLT_MAX 1E+36
+#endif
+
+typedef unsigned long shared_t_bitmask;
+
+#ifdef __linux__
+#include <sys/types.h>
+#ifndef int32
+typedef int32_t int32;
+#endif
+#ifndef uint32
+typedef u_int32_t uint32;
+#endif
+#ifndef int16
+typedef int16_t int16;
+#endif
+#ifndef uint16
+typedef u_int16_t uint16;
+#endif
+#ifndef uchar
+typedef u_int8_t uchar;
+#endif
+#include <endian.h>
+#if !defined(__BYTE_ORDER) || !defined(__LITTLE_ENDIAN)
+#error No byte order defined
+#endif
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define SHARED_HIOFFSET 1
+#define SHARED_LOWOFFSET 0
+#else
+#define SHARED_HIOFFSET 0
+#define SHARED_LOWOFFSET 1
+#endif
+#endif
+
+#ifdef NT
+#ifndef int32
+typedef long int32;
+#endif
+#ifndef uint32
+typedef unsigned long uint32;
+#endif
+#ifndef int16
+typedef short int16;
+#endif
+#ifndef uint16
+typedef unsigned short uint16;
+#endif
+#ifndef uchar
+typedef unsigned char uchar;
+#endif
+#define SHARED_HIOFFSET 1
+#define SHARED_LOWOFFSET 0
+#endif
+
+#ifdef MACOSX
+#ifndef int32
+typedef int int32;
+#endif
+#ifndef uint32
+typedef unsigned int uint32;
+#endif
+#ifndef int16
+typedef short int16;
+#endif
+#ifndef uint16
+typedef unsigned short uint16;
+#endif
+#ifndef uchar
+typedef unsigned char uchar;
+#endif
+#define SHARED_HIOFFSET 0
+#define SHARED_LOWOFFSET 1
+#endif
+
+#ifdef IRIX
+#ifndef int32
+typedef long int32;
+#endif
+#ifndef uint32
+typedef unsigned long uint32;
+#endif
+#ifndef int16
+typedef short int16;
+#endif
+#ifndef uint16
+typedef unsigned short uint16;
+#endif
+#ifndef uchar
+typedef unsigned char uchar;
+#endif
+#define SHARED_HIOFFSET 0
+#define SHARED_LOWOFFSET 1
+#endif
+
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#ifndef int32
+typedef int32_t int32;
+#endif
+#ifndef uint32
+typedef u_int32_t uint32;
+#endif
+#ifndef int16
+typedef int16_t int16;
+#endif
+#ifndef uint16
+typedef u_int16_t uint16;
+#endif
+#ifndef uchar
+typedef u_int8_t uchar;
+#endif
+#include <machine/endian.h>
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define SHARED_HIOFFSET 1
+#define SHARED_LOWOFFSET 0
+#else
+#define SHARED_HIOFFSET 0
+#define SHARED_LOWOFFSET 1
+#endif
+#endif
+
+#define SHARED_UNITBIT32 1572864. /* 3*(2^19) gives 32 fractional bits */
+#define SHARED_UNITBIT0 6755399441055744. /* 3*(2^51), no fractional bits */
+#define SHARED_UNITBIT0_HIPART 0x43380000
+
+typedef union _shared_wrappy
+{
+ double w_d;
+ int32 w_i[2];
+} t_shared_wrappy;
+
+typedef union _shared_floatint
+{
+ t_float fi_f;
+ int32 fi_i;
+} t_shared_floatint;
+
+#define SHARED_TRUEBITS 0x3f800000 /* t_float f = 1; *(int32 *)&f */
+
+#define SHARED_PI 3.14159265359
+#define SHARED_2PI 6.28318530718
+
+#endif
diff --git a/shared/sickle/Makefile b/shared/sickle/Makefile
new file mode 100644
index 0000000..5dcb2c8
--- /dev/null
+++ b/shared/sickle/Makefile
@@ -0,0 +1,4 @@
+ROOT_DIR = ../..
+include $(ROOT_DIR)/Makefile.common
+
+all: $(OBJECTS)
diff --git a/shared/sickle/Makefile.objects b/shared/sickle/Makefile.objects
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/shared/sickle/Makefile.objects
diff --git a/shared/sickle/Makefile.sources b/shared/sickle/Makefile.sources
new file mode 100644
index 0000000..5575605
--- /dev/null
+++ b/shared/sickle/Makefile.sources
@@ -0,0 +1,3 @@
+OTHER_SOURCES = \
+sic.c \
+arsic.c
diff --git a/shared/sickle/arsic.c b/shared/sickle/arsic.c
new file mode 100644
index 0000000..8f0e309
--- /dev/null
+++ b/shared/sickle/arsic.c
@@ -0,0 +1,221 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* generic array-based signal class */
+
+#include <stdio.h>
+#include <string.h>
+#include "m_pd.h"
+#include "shared.h"
+#include "common/vefl.h"
+#include "sickle/sic.h"
+#include "sickle/arsic.h"
+
+void arsic_clear(t_arsic *x)
+{
+ x->s_vecsize = 0;
+ memset(x->s_vectors, 0, x->s_nchannels * sizeof(*x->s_vectors));
+}
+
+void arsic_redraw(t_arsic *x)
+{
+ if (x->s_mononame)
+ {
+ t_garray *ap =
+ (t_garray *)pd_findbyclass(x->s_mononame, garray_class);
+ if (ap) garray_redraw(ap);
+ else if (x->s_vectors[0]) bug("arsic_redraw 1");
+ }
+ else if (*x->s_stub)
+ {
+ int ch = x->s_nchannels;
+ while (ch--)
+ {
+ t_garray *ap =
+ (t_garray *)pd_findbyclass(x->s_channames[ch], garray_class);
+ if (ap) garray_redraw(ap);
+ else if (x->s_vectors[ch]) bug("arsic_redraw 2");
+ }
+ }
+}
+
+void arsic_validate(t_arsic *x, int complain)
+{
+ arsic_clear(x);
+ x->s_vecsize = SHARED_INT_MAX;
+ if (x->s_mononame)
+ {
+ x->s_vectors[0] =
+ vefl_get(x->s_mononame, &x->s_vecsize, 1,
+ (complain ? (t_pd *)x : 0));
+ }
+ else if (*x->s_stub)
+ {
+ int ch;
+ for (ch = 0; ch < x->s_nchannels ; ch++)
+ {
+ int vsz = x->s_vecsize; /* ignore missing arrays */
+ x->s_vectors[ch] =
+ vefl_get(x->s_channames[ch], &vsz, 1,
+ (complain ? (t_pd *)x : 0));
+ if (vsz < x->s_vecsize) x->s_vecsize = vsz;
+ }
+ }
+ if (x->s_vecsize == SHARED_INT_MAX) x->s_vecsize = 0;
+}
+
+void arsic_check(t_arsic *x)
+{
+ x->s_playable = (!((t_sic *)x)->s_disabled && x->s_vecsize >= x->s_minsize);
+}
+
+int arsic_getnchannels(t_arsic *x)
+{
+ return (x->s_nchannels);
+}
+
+void arsic_setarray(t_arsic *x, t_symbol *s, int complain)
+{
+ if (s)
+ {
+ if (x->s_mononame) x->s_mononame = s;
+ else
+ {
+ x->s_stub = s->s_name;
+ if (*x->s_stub)
+ {
+ char buf[MAXPDSTRING];
+ int ch;
+ for (ch = 0; ch < x->s_nchannels; ch++)
+ {
+ sprintf(buf, "%d-%s", ch, x->s_stub);
+ x->s_channames[ch] = gensym(buf);
+ }
+ }
+ }
+ arsic_validate(x, complain);
+ }
+ arsic_check(x);
+}
+
+void arsic_setminsize(t_arsic *x, int i)
+{
+ x->s_minsize = i;
+}
+
+void arsic_dsp(t_arsic *x, t_signal **sp, t_perfroutine perf, int complain)
+{
+ t_int *ap = x->s_perfargs;
+ if (ap)
+ {
+ int i, nsigs = x->s_nperfargs - 2;
+ x->s_ksr = sp[0]->s_sr * 0.001;
+ arsic_validate(x, complain);
+ arsic_check(x);
+
+ /* LATER consider glist traversing, and, if we have no feeders,
+ choosing an optimized version of perform routine */
+
+ *ap++ = (t_int)x;
+ *ap++ = (t_int)sp[0]->s_n;
+ for (i = 0; i < nsigs; i++) *ap++ = (t_int)sp[i]->s_vec;
+ dsp_addv(perf, x->s_nperfargs, x->s_perfargs);
+ }
+ else bug("arsic_dsp");
+}
+
+void arsic_free(t_arsic *x)
+{
+ if (x->s_vectors)
+ freebytes(x->s_vectors, x->s_nchannels * sizeof(*x->s_vectors));
+ if (x->s_channames)
+ freebytes(x->s_channames,
+ x->s_nchannels * sizeof(*x->s_channames));
+ if (x->s_perfargs)
+ freebytes(x->s_perfargs, x->s_nperfargs * sizeof(*x->s_perfargs));
+}
+
+/* If nauxsigs is positive, then the number of signals is nchannels + nauxsigs;
+ otherwise the channels are not used as signals, and the number of signals is
+ nsigs -- provided that nsigs is positive -- or, if it is not, then an arsic
+ is not used in dsp (peek~). */
+void *arsic_new(t_class *c, t_symbol *s,
+ int nchannels, int nsigs, int nauxsigs)
+{
+ t_arsic *x;
+ t_symbol *mononame;
+ char *stub;
+ t_float **vectors;
+ int nperfargs = 0;
+ t_int *perfargs = 0;
+ t_symbol **channames = 0;
+ if (!s) s = &s_;
+ if (nchannels < 1)
+ {
+ nchannels = 1;
+ mononame = s;
+ stub = 0;
+ }
+ else
+ {
+ mononame = 0;
+ stub = s->s_name;
+ }
+ if (!(vectors = (t_float **)getbytes(nchannels * sizeof(*vectors))))
+ return (0);
+ if (nauxsigs > 0)
+ nperfargs = nchannels + nauxsigs + 2;
+ else if (nsigs > 0)
+ nperfargs = nsigs + 2;
+ if (nperfargs
+ && !(perfargs = (t_int *)getbytes(nperfargs * sizeof(*perfargs))))
+ {
+ freebytes(vectors, nchannels * sizeof(*vectors));
+ return (0);
+ }
+ if (stub &&
+ !(channames = (t_symbol **)getbytes(nchannels * sizeof(*channames))))
+ {
+ freebytes(vectors, nchannels * sizeof(*vectors));
+ if (perfargs) freebytes(perfargs, nperfargs * sizeof(*perfargs));
+ return (0);
+ }
+ x = (t_arsic *)pd_new(c);
+ x->s_vecsize = 0;
+ x->s_nchannels = nchannels;
+ x->s_vectors = vectors;
+ x->s_channames = channames;
+ x->s_nperfargs = nperfargs;
+ x->s_perfargs = perfargs;
+ x->s_mononame = mononame;
+ x->s_stub = stub;
+ x->s_ksr = sys_getsr() * 0.001;
+ ((t_sic *)x)->s_disabled = 0;
+ x->s_playable = 0;
+ x->s_minsize = 1;
+ arsic_setarray(x, s, 0);
+ return (x);
+}
+
+static void arsic_enable(t_arsic *x, t_floatarg f)
+{
+ ((t_sic *)x)->s_disabled = (f == 0);
+ arsic_check(x);
+}
+
+/* LATER somehow link this to sic_setup() */
+void arsic_setup(t_class *c, void *dspfn, void *floatfn)
+{
+ if (floatfn != SIC_NOMAINSIGNALIN)
+ {
+ if (floatfn)
+ {
+ class_domainsignalin(c, -1);
+ class_addfloat(c, floatfn);
+ }
+ else CLASS_MAINSIGNALIN(c, t_sic, s_f);
+ }
+ class_addmethod(c, (t_method)dspfn, gensym("dsp"), 0);
+ class_addmethod(c, (t_method)arsic_enable, gensym("enable"), 0);
+}
diff --git a/shared/sickle/arsic.h b/shared/sickle/arsic.h
new file mode 100644
index 0000000..a941279
--- /dev/null
+++ b/shared/sickle/arsic.h
@@ -0,0 +1,38 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __ARSIC_H__
+#define __ARSIC_H__
+
+typedef struct _arsic
+{
+ t_sic s_sic;
+ int s_vecsize; /* used also as a validation flag */
+ int s_nchannels;
+ t_float **s_vectors;
+ t_symbol **s_channames;
+ int s_nperfargs;
+ t_int *s_perfargs;
+ t_symbol *s_mononame; /* used also as an 'ismono' flag */
+ char *s_stub;
+ float s_ksr;
+ int s_playable;
+ int s_minsize;
+} t_arsic;
+
+void arsic_clear(t_arsic *x);
+void arsic_redraw(t_arsic *x);
+void arsic_validate(t_arsic *x, int complain);
+void arsic_check(t_arsic *x);
+int arsic_getnchannels(t_arsic *x);
+void arsic_setarray(t_arsic *x, t_symbol *s, int complain);
+void arsic_setminsize(t_arsic *x, int i);
+
+void arsic_dsp(t_arsic *x, t_signal **sp, t_perfroutine perf, int complain);
+void *arsic_new(t_class *c, t_symbol *s,
+ int nchannels, int nsigs, int nauxsigs);
+void arsic_free(t_arsic *x);
+void arsic_setup(t_class *c, void *dspfn, void *floatfn);
+
+#endif
diff --git a/shared/sickle/sic.c b/shared/sickle/sic.c
new file mode 100644
index 0000000..003120e
--- /dev/null
+++ b/shared/sickle/sic.c
@@ -0,0 +1,119 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* generic signal class */
+
+#include <math.h>
+#include "m_pd.h"
+#include "shared.h"
+#include "common/loud.h"
+#include "sickle/sic.h"
+
+//#define SIC_DEBUG
+
+#if defined(NT) || defined(MACOSX)
+/* cf pd/src/x_arithmetic.c */
+#define cosf cos
+#endif
+
+t_inlet *sic_inlet(t_sic *x, int ix, t_float df, int ax, int ac, t_atom *av)
+{
+ t_inlet *in = 0;
+ if (ax < ac)
+ {
+ if (av[ax].a_type == A_FLOAT)
+ df = av[ax].a_w.w_float;
+ else
+ loud_error((t_pd *)x, "bad argument %d (float expected)", ax + 1);
+ }
+ if (ix)
+ {
+ in = inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal);
+ /* this is persistent (in->i_un.iu_floatsignalvalue = df) */
+ pd_float((t_pd *)in, df);
+ }
+ else
+ {
+ in = ((t_object *)x)->ob_inlet;
+ pd_float((t_pd *)x, df);
+ }
+ return (in);
+}
+
+t_inlet *sic_newinlet(t_sic *x, t_float f)
+{
+ return (sic_inlet(x, 1, f, 0, 0, 0));
+}
+
+t_float *sic_makecostable(int *sizep)
+{
+ /* permanent cache (tables are never freed); LATER rethink */
+ static t_float *sic_costables[SIC_NCOSTABLES];
+ int ndx, sz;
+ /* round upwards -- always return at least requested number of elements,
+ unless the maximum of 2^SIC_NCOSTABLES is exceeded; LATER rethink */
+ /* (the minimum, at ndx 0, is 2^1) */
+ for (ndx = 0, sz = 2; ndx < (SIC_NCOSTABLES - 1); ndx++, sz <<= 1)
+ if (sz >= *sizep)
+ break;
+#ifdef SIC_DEBUG
+ post("request for a costable of %d points (effective %d, ndx %d)",
+ *sizep, sz, ndx);
+#endif
+ *sizep = sz;
+ if (sic_costables[ndx])
+ return (sic_costables[ndx]);
+ else if (sz == COSTABSIZE && cos_table)
+ return (sic_costables[ndx] = cos_table);
+ else
+ {
+ int cnt = sz + 1;
+ float phase = 0, phsinc = SHARED_2PI / sz;
+ t_float *table = (t_float *)getbytes(cnt * sizeof(*table)), *tp = table;
+ if (table)
+ {
+#ifdef SIC_DEBUG
+ post("got %d points of a costable", cnt);
+#endif
+ while (cnt--)
+ {
+ *tp++ = cosf(phase);
+ phase += phsinc;
+ }
+ }
+ return (sic_costables[ndx] = table);
+ }
+}
+
+static void sic_enable(t_sic *x, t_floatarg f)
+{
+ x->s_disabled = (f == 0);
+}
+
+void sic_setup(t_class *c, void *dspfn, void *floatfn)
+{
+ static int checked = 0;
+ if (!checked)
+ {
+ /* MSP: here we check at startup whether the byte alignment
+ is as we declared it. If not, the code has to be
+ recompiled the other way. */
+ t_shared_wrappy wrappy;
+ wrappy.w_d = SHARED_UNITBIT32 + 0.5;
+ if ((unsigned)wrappy.w_i[SHARED_LOWOFFSET] != 0x80000000)
+ bug("sic_setup: unexpected machine alignment");
+ checked = 1;
+ }
+ if (floatfn != SIC_NOMAINSIGNALIN)
+ {
+ if (floatfn)
+ {
+ class_domainsignalin(c, -1);
+ class_addfloat(c, floatfn);
+ }
+ else CLASS_MAINSIGNALIN(c, t_sic, s_f);
+ }
+ class_addmethod(c, (t_method)dspfn, gensym("dsp"), 0);
+ class_addmethod(c, (t_method)sic_enable, gensym("enable"), 0);
+}
diff --git a/shared/sickle/sic.h b/shared/sickle/sic.h
new file mode 100644
index 0000000..9dce95f
--- /dev/null
+++ b/shared/sickle/sic.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __SIC_H__
+#define __SIC_H__
+
+typedef struct _sic
+{
+ t_object s_ob;
+ t_float s_f;
+ int s_disabled;
+} t_sic;
+
+#define SIC_FLOATTOSIGNAL ((void *)0)
+#define SIC_NOMAINSIGNALIN ((void *)-1)
+
+#define SIC_NCOSTABLES 16 /* this is oscbank~'s max, LATER rethink */
+
+t_inlet *sic_inlet(t_sic *x, int ix, t_float df, int ax, int ac, t_atom *av);
+t_inlet *sic_newinlet(t_sic *x, t_float f);
+t_float *sic_makecostable(int *sizep);
+void sic_setup(t_class *c, void *dspfn, void *floatfn);
+
+#endif
diff --git a/shared/unstable/Makefile b/shared/unstable/Makefile
new file mode 100644
index 0000000..5dcb2c8
--- /dev/null
+++ b/shared/unstable/Makefile
@@ -0,0 +1,4 @@
+ROOT_DIR = ../..
+include $(ROOT_DIR)/Makefile.common
+
+all: $(OBJECTS)
diff --git a/shared/unstable/Makefile.objects b/shared/unstable/Makefile.objects
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/shared/unstable/Makefile.objects
diff --git a/shared/unstable/Makefile.sources b/shared/unstable/Makefile.sources
new file mode 100644
index 0000000..4636701
--- /dev/null
+++ b/shared/unstable/Makefile.sources
@@ -0,0 +1,4 @@
+OTHER_SOURCES = \
+fragile.c \
+forky.c \
+loader.c
diff --git a/shared/unstable/forky.c b/shared/unstable/forky.c
new file mode 100644
index 0000000..7fb6b08
--- /dev/null
+++ b/shared/unstable/forky.c
@@ -0,0 +1,56 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "g_canvas.h"
+#include "shared.h"
+#include "unstable/forky.h"
+
+//#define FORKY_DEBUG
+
+/* To be called in a 'dsp' method -- e.g. if there are no feeders, the caller
+ might use an optimized version of a 'perform' routine.
+ LATER think about replacing 'linetraverser' calls with something faster. */
+int forky_hasfeeders(t_object *x, t_glist *glist, int inno, t_symbol *outsym)
+{
+ t_linetraverser t;
+ linetraverser_start(&t, glist);
+ while (linetraverser_next(&t))
+ if (t.tr_ob2 == x && t.tr_inno == inno
+#ifdef PD_VERSION /* FIXME ask Miller */
+ && (!outsym || outsym == outlet_getsymbol(t.tr_outlet))
+#endif
+ )
+ return (1);
+ return (0);
+}
+
+/* Not really a forky, just found no better place to put it in.
+ Used in bitwise signal binops (sickle). Checked against msp2. */
+t_int forky_getbitmask(int ac, t_atom *av)
+{
+ t_int result = 0;
+ if (sizeof(shared_t_bitmask) >= sizeof(t_int))
+ {
+ int nbits = sizeof(t_int) * 8;
+ shared_t_bitmask bitmask = 1 << (nbits - 1);
+ if (ac > nbits)
+ ac = nbits;
+ while (ac--)
+ {
+ if (av->a_type == A_FLOAT &&
+ (int)av->a_w.w_float) /* CHECKED */
+ result |= bitmask;
+ /* CHECKED symbols are zero */
+ bitmask >>= 1;
+ av++;
+ }
+ /* CHECKED missing are zero */
+#ifdef FORKY_DEBUG
+ post("mask set to %.8x", result);
+#endif
+ }
+ else bug("sizeof(shared_t_bitmask)");
+ return (result);
+}
diff --git a/shared/unstable/forky.h b/shared/unstable/forky.h
new file mode 100644
index 0000000..0d27080
--- /dev/null
+++ b/shared/unstable/forky.h
@@ -0,0 +1,11 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __FORKY_H__
+#define __FORKY_H__
+
+int forky_hasfeeders(t_object *x, t_glist *glist, int inno, t_symbol *outsym);
+t_int forky_getbitmask(int ac, t_atom *av);
+
+#endif
diff --git a/shared/unstable/fragile.c b/shared/unstable/fragile.c
new file mode 100644
index 0000000..3267721
--- /dev/null
+++ b/shared/unstable/fragile.c
@@ -0,0 +1,67 @@
+/* Copyright (c) 1997-2003 Miller Puckette, krzYszcz, and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "unstable/pd_imp.h"
+#include "unstable/fragile.h"
+
+int fragile_class_count(void)
+{
+ return (pd_objectmaker->c_nmethod);
+}
+
+void fragile_class_printnames(char *msg, int firstndx, int lastndx)
+{
+ t_methodentry *mp = pd_objectmaker->c_methods;
+ int ndx, len = strlen(msg);
+ startpost(msg);
+ for (ndx = firstndx, mp += ndx; ndx <= lastndx; ndx++, mp++)
+ {
+ t_symbol *s = mp->me_name;
+ if (s && s->s_name[0] != '_')
+ {
+ int l = 1 + strlen(s->s_name);
+ if ((len += l) > 66)
+ {
+ endpost();
+ startpost(" ");
+ len = 3 + l;
+ }
+ poststring(s->s_name);
+ }
+ }
+ endpost();
+}
+
+/* This structure is local to g_array.c. We need it,
+ because there is no other way to get into array's graph. */
+struct _garray
+{
+ t_gobj x_gobj;
+ t_glist *x_glist;
+ /* ... */
+};
+
+t_glist *fragile_garray_glist(void *arr)
+{
+ return (((struct _garray *)arr)->x_glist);
+}
+
+/* This is local to m_obj.c.
+ LATER export write access to o_connections field ('grab' class).
+ LATER encapsulate 'traverseoutlet' routines (not in the stable API yet). */
+struct _outlet
+{
+ t_object *o_owner;
+ struct _outlet *o_next;
+ t_outconnect *o_connections;
+ t_symbol *o_sym;
+};
+
+/* obj_starttraverseoutlet() replacement */
+t_outconnect *fragile_outlet_connections(t_outlet *o)
+{
+ return (o ? o->o_connections : 0);
+}
diff --git a/shared/unstable/fragile.h b/shared/unstable/fragile.h
new file mode 100644
index 0000000..c1ba8e3
--- /dev/null
+++ b/shared/unstable/fragile.h
@@ -0,0 +1,13 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __FRAGILE_H__
+#define __FRAGILE_H__
+
+int fragile_class_count(void);
+void fragile_class_printnames(char *msg, int firstndx, int lastndx);
+t_glist *fragile_garray_glist(void *arr);
+t_outconnect *fragile_outlet_connections(t_outlet *o);
+
+#endif
diff --git a/shared/unstable/loader.c b/shared/unstable/loader.c
new file mode 100644
index 0000000..91b7ff3
--- /dev/null
+++ b/shared/unstable/loader.c
@@ -0,0 +1,139 @@
+/* Copyright (c) 1997-2003 Miller Puckette, krzYszcz, and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* This is just a not-yet-in-the-API-sys_load_lib() duplication
+ (modulo differentiating the error return codes). LATER use the original. */
+
+#include "loader.h"
+
+#ifdef __linux__
+#include <dlfcn.h>
+#endif
+#ifdef UNIX
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+#ifdef NT
+#include <io.h>
+#include <windows.h>
+#endif
+#ifdef MACOSX
+#include <mach-o/dyld.h>
+#endif
+#include <string.h>
+#include "m_pd.h"
+#include <stdio.h>
+
+typedef void (*t_xxx)(void);
+
+static char sys_dllextent[] =
+#ifdef __FreeBSD__
+ ".pd_freebsd";
+#endif
+#ifdef IRIX
+#ifdef N32
+ ".pd_irix6";
+#else
+ ".pd_irix5";
+#endif
+#endif
+#ifdef __linux__
+ ".pd_linux";
+#endif
+#ifdef MACOSX
+ ".pd_darwin";
+#endif
+#ifdef NT
+ ".dll";
+#endif
+
+int unstable_load_lib(char *dirname, char *classname)
+{
+ char symname[MAXPDSTRING], filename[MAXPDSTRING], dirbuf[MAXPDSTRING],
+ *nameptr, *lastdot;
+ void *dlobj;
+ t_xxx makeout;
+ int fd;
+#ifdef NT
+ HINSTANCE ntdll;
+#endif
+#if 0
+ fprintf(stderr, "lib %s %s\n", dirname, classname);
+#endif
+ if ((fd = open_via_path(dirname, classname, sys_dllextent,
+ dirbuf, &nameptr, MAXPDSTRING, 1)) < 0)
+ {
+ return (LOADER_NOFILE);
+ }
+ else
+ {
+ close(fd);
+ /* refabricate the pathname */
+ strcpy(filename, dirbuf);
+ strcat(filename, "/");
+ strcat(filename, nameptr);
+ /* extract the setup function name */
+ if (lastdot = strrchr(nameptr, '.'))
+ *lastdot = 0;
+
+#ifdef MACOSX
+ strcpy(symname, "_");
+ strcat(symname, nameptr);
+#else
+ strcpy(symname, nameptr);
+#endif
+ /* if the last character is a tilde, replace with "_tilde" */
+ if (symname[strlen(symname) - 1] == '~')
+ strcpy(symname + (strlen(symname) - 1), "_tilde");
+ /* and append _setup to form the C setup function name */
+ strcat(symname, "_setup");
+#ifdef __linux__
+ dlobj = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
+ if (!dlobj)
+ {
+ post("%s: %s", filename, dlerror());
+ return (LOADER_BADFILE);
+ }
+ makeout = (t_xxx)dlsym(dlobj, symname);
+#endif
+#ifdef NT
+ sys_bashfilename(filename, filename);
+ ntdll = LoadLibrary(filename);
+ if (!ntdll)
+ {
+ post("%s: couldn't load", filename);
+ return (LOADER_BADFILE);
+ }
+ makeout = (t_xxx)GetProcAddress(ntdll, symname);
+#endif
+#ifdef MACOSX
+ {
+ NSObjectFileImage image;
+ void *ret;
+ NSSymbol s;
+ if ( NSCreateObjectFileImageFromFile( filename, &image) != NSObjectFileImageSuccess )
+ {
+ post("%s: couldn't load", filename);
+ return (LOADER_BADFILE);
+ }
+ ret = NSLinkModule( image, filename,
+ NSLINKMODULE_OPTION_BINDNOW
+ + NSLINKMODULE_OPTION_PRIVATE);
+
+ s = NSLookupSymbolInModule(ret, symname);
+
+ if (s)
+ makeout = (t_xxx)NSAddressOfSymbol( s);
+ else makeout = 0;
+ }
+#endif
+ }
+ if (!makeout)
+ {
+ post("load_object: Symbol \"%s\" not found", symname);
+ return (LOADER_NOENTRY);
+ }
+ (*makeout)();
+ return (LOADER_OK);
+}
diff --git a/shared/unstable/loader.h b/shared/unstable/loader.h
new file mode 100644
index 0000000..e9766ac
--- /dev/null
+++ b/shared/unstable/loader.h
@@ -0,0 +1,12 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __LOADER_H__
+#define __LOADER_H__
+
+enum { LOADER_OK, LOADER_NOFILE, LOADER_BADFILE, LOADER_NOENTRY };
+
+int unstable_load_lib(char *dirname, char *classname);
+
+#endif
diff --git a/shared/unstable/pd_imp.h b/shared/unstable/pd_imp.h
new file mode 100644
index 0000000..bf659ed
--- /dev/null
+++ b/shared/unstable/pd_imp.h
@@ -0,0 +1,60 @@
+/* Copyright (c) 1997-2003 Miller Puckette and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __PD_IMP_H__
+#define __PD_IMP_H__
+
+#ifdef PD_MINOR_VERSION
+#include "m_imp.h"
+#else
+
+typedef struct _methodentry
+{
+ t_symbol *me_name;
+ t_gotfn me_fun;
+ t_atomtype me_arg[MAXPDARG+1];
+} t_methodentry;
+
+EXTERN_STRUCT _widgetbehavior;
+
+typedef void (*t_bangmethod)(t_pd *x);
+typedef void (*t_pointermethod)(t_pd *x, t_gpointer *gp);
+typedef void (*t_floatmethod)(t_pd *x, t_float f);
+typedef void (*t_symbolmethod)(t_pd *x, t_symbol *s);
+typedef void (*t_listmethod)(t_pd *x, t_symbol *s, int argc, t_atom *argv);
+typedef void (*t_anymethod)(t_pd *x, t_symbol *s, int argc, t_atom *argv);
+
+struct _class
+{
+ t_symbol *c_name; /* name (mostly for error reporting) */
+ t_symbol *c_helpname; /* name of help file */
+ size_t c_size; /* size of an instance */
+ t_methodentry *c_methods; /* methods other than bang, etc below */
+ int c_nmethod; /* number of methods */
+ t_method c_freemethod; /* function to call before freeing */
+ t_bangmethod c_bangmethod; /* common methods */
+ t_pointermethod c_pointermethod;
+ t_floatmethod c_floatmethod;
+ t_symbolmethod c_symbolmethod;
+ t_listmethod c_listmethod;
+ t_anymethod c_anymethod;
+ struct _widgetbehavior *c_wb; /* "gobjs" only */
+ struct _parentwidgetbehavior *c_pwb;/* widget behavior in parent */
+ int c_floatsignalin; /* onset to float for signal input */
+ char c_gobj; /* true if is a gobj */
+ char c_patchable; /* true if we have a t_object header */
+ char c_firstin; /* if patchable, true if draw first inlet */
+ char c_drawcommand; /* a drawing command for a template */
+};
+
+EXTERN int obj_noutlets(t_object *x);
+EXTERN int obj_ninlets(t_object *x);
+EXTERN t_outconnect *obj_starttraverseoutlet(t_object *x, t_outlet **op,
+ int nout);
+EXTERN t_outconnect *obj_nexttraverseoutlet(t_outconnect *lastconnect,
+ t_object **destp, t_inlet **inletp, int *whichp);
+
+#endif
+
+#endif
diff --git a/test/cyclone/Borax-test.pd b/test/cyclone/Borax-test.pd
new file mode 100644
index 0000000..aa2970b
--- /dev/null
+++ b/test/cyclone/Borax-test.pd
@@ -0,0 +1,120 @@
+#N canvas 137 29 642 442 12;
+#X obj 24 185 Borax dummy;
+#X floatatom 24 220 5 0 0;
+#X floatatom 24 124 5 0 0;
+#X msg 24 86 1;
+#X msg 80 86 0;
+#X msg 118 152 bang;
+#X obj 129 86 counter;
+#X msg 57 51 set 0;
+#X msg 129 18 128;
+#X obj 129 51 Uzi;
+#X obj 326 220 Borax dummy;
+#X obj 469 324 funbuff;
+#C restore;
+#X obj 230 324 funbuff;
+#C restore;
+#X obj 356 324 funbuff;
+#C restore;
+#X obj 326 185 makenote;
+#X obj 326 86 random 128;
+#X obj 393 152 random 1000;
+#X obj 326 51 t b b b;
+#X msg 326 18 bang;
+#X msg 209 220 dump;
+#X obj 230 359 pack;
+#X obj 230 392 print pitch;
+#X obj 469 359 pack;
+#X obj 469 392 print delta;
+#X obj 356 359 pack;
+#X obj 356 392 print dur;
+#X msg 260 220 dump;
+#X msg 486 220 dump;
+#X msg 230 263 clear;
+#X obj 356 288 spigot;
+#X msg 405 263 1;
+#X msg 419 288 0;
+#X obj 469 288 spigot;
+#X msg 518 263 1;
+#X msg 532 288 0;
+#X obj 92 220 print voice;
+#X obj 210 86 urn 128;
+#X msg 210 18 128;
+#X obj 210 51 Uzi;
+#X msg 258 51 clear;
+#X msg 536 18 128;
+#X obj 411 51 Uzi;
+#X msg 420 185 bang;
+#X obj 456 51 t b b b;
+#X obj 456 86 urn 128;
+#X obj 514 152 random 1000;
+#X msg 536 51 clear;
+#X obj 456 18 t 0 b;
+#X msg 485 119 64;
+#X msg 355 119 64;
+#X connect 0 0 1 0;
+#X connect 0 1 35 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 1;
+#X connect 4 0 0 1;
+#X connect 5 0 0 2;
+#X connect 6 0 0 0;
+#X connect 7 0 6 0;
+#X connect 8 0 9 0;
+#X connect 9 0 6 0;
+#X connect 10 0 12 0;
+#X connect 10 0 32 0;
+#X connect 10 0 29 0;
+#X connect 10 3 12 1;
+#X connect 10 6 13 1;
+#X connect 10 6 30 0;
+#X connect 10 8 11 1;
+#X connect 10 8 33 0;
+#X connect 11 0 22 0;
+#X connect 11 1 22 1;
+#X connect 12 0 20 0;
+#X connect 12 1 20 1;
+#X connect 13 0 24 0;
+#X connect 13 1 24 1;
+#X connect 14 0 10 0;
+#X connect 14 1 10 1;
+#X connect 15 0 14 0;
+#X connect 16 0 14 2;
+#X connect 17 0 15 0;
+#X connect 17 1 49 0;
+#X connect 17 2 16 0;
+#X connect 18 0 17 0;
+#X connect 19 0 12 0;
+#X connect 20 0 21 0;
+#X connect 22 0 23 0;
+#X connect 24 0 25 0;
+#X connect 26 0 13 0;
+#X connect 27 0 11 0;
+#X connect 28 0 12 0;
+#X connect 28 0 13 0;
+#X connect 28 0 11 0;
+#X connect 29 0 31 0;
+#X connect 29 0 13 0;
+#X connect 30 0 29 1;
+#X connect 31 0 29 1;
+#X connect 32 0 34 0;
+#X connect 32 0 11 0;
+#X connect 33 0 32 1;
+#X connect 34 0 32 1;
+#X connect 36 0 0 0;
+#X connect 37 0 38 0;
+#X connect 38 0 36 0;
+#X connect 39 0 36 0;
+#X connect 40 0 47 0;
+#X connect 41 0 43 0;
+#X connect 42 0 10 2;
+#X connect 43 0 44 0;
+#X connect 43 1 48 0;
+#X connect 43 2 45 0;
+#X connect 44 0 14 0;
+#X connect 45 0 14 2;
+#X connect 46 0 44 0;
+#X connect 47 0 41 0;
+#X connect 47 1 46 0;
+#X connect 48 0 14 1;
+#X connect 49 0 14 1;
diff --git a/test/cyclone/Bucket-test.pd b/test/cyclone/Bucket-test.pd
new file mode 100644
index 0000000..c43b0ed
--- /dev/null
+++ b/test/cyclone/Bucket-test.pd
@@ -0,0 +1,40 @@
+#N canvas 306 219 459 482 12;
+#X obj 134 126 Bucket 10 padding;
+#X floatatom 134 433 5 0 0;
+#X floatatom 150 403 5 0 0;
+#X floatatom 166 374 5 0 0;
+#X floatatom 183 343 5 0 0;
+#X floatatom 199 313 5 0 0;
+#X floatatom 216 282 5 0 0;
+#X floatatom 232 255 5 0 0;
+#X floatatom 249 224 5 0 0;
+#X floatatom 265 192 5 0 0;
+#X floatatom 282 162 5 0 0;
+#X msg 233 21 roll;
+#X floatatom 232 56 5 0 0;
+#X msg 232 88 set \$1;
+#X floatatom 81 56 5 0 0;
+#X msg 156 21 l2r;
+#X msg 156 56 r2l;
+#X msg 332 56 freeze;
+#X msg 332 88 thaw;
+#X msg 21 56 bang;
+#X connect 0 0 1 0;
+#X connect 0 1 2 0;
+#X connect 0 2 3 0;
+#X connect 0 3 4 0;
+#X connect 0 4 5 0;
+#X connect 0 5 6 0;
+#X connect 0 6 7 0;
+#X connect 0 7 8 0;
+#X connect 0 8 9 0;
+#X connect 0 9 10 0;
+#X connect 11 0 0 0;
+#X connect 12 0 13 0;
+#X connect 13 0 0 0;
+#X connect 14 0 0 0;
+#X connect 15 0 0 0;
+#X connect 16 0 0 0;
+#X connect 17 0 0 0;
+#X connect 18 0 0 0;
+#X connect 19 0 0 0;
diff --git a/test/cyclone/Decode-test.pd b/test/cyclone/Decode-test.pd
new file mode 100644
index 0000000..bd35b61
--- /dev/null
+++ b/test/cyclone/Decode-test.pd
@@ -0,0 +1,18 @@
+#N canvas 314 293 450 300 12;
+#X obj 151 134 Decode 4;
+#X obj 151 256 print a;
+#X obj 173 230 print b;
+#X obj 195 200 print c;
+#X obj 218 172 print d;
+#X floatatom 68 81 5 0 0;
+#X obj 184 81 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 218 81 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X connect 0 0 1 0;
+#X connect 0 1 2 0;
+#X connect 0 2 3 0;
+#X connect 0 3 4 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 1;
+#X connect 7 0 0 2;
diff --git a/test/cyclone/Histo-test.pd b/test/cyclone/Histo-test.pd
new file mode 100644
index 0000000..cd22730
--- /dev/null
+++ b/test/cyclone/Histo-test.pd
@@ -0,0 +1,20 @@
+#N canvas 386 259 450 300 12;
+#X obj 158 150 Histo 1000;
+#X obj 158 226 print a;
+#X obj 243 226 print b;
+#X msg 51 93 bang;
+#X msg 158 93 700;
+#X msg 111 93 -1;
+#X msg 243 44 1000;
+#X msg 263 93 700.5;
+#X msg 178 121 clear;
+#X msg 139 44 1 1;
+#X connect 0 0 1 0;
+#X connect 0 1 2 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 1;
+#X connect 7 0 0 1;
+#X connect 8 0 0 0;
+#X connect 9 0 0 0;
diff --git a/test/cyclone/MouseState-test.pd b/test/cyclone/MouseState-test.pd
new file mode 100644
index 0000000..12b13ff
--- /dev/null
+++ b/test/cyclone/MouseState-test.pd
@@ -0,0 +1,54 @@
+#N canvas 228 259 751 304 12;
+#X obj 179 129 MouseState;
+#X obj 179 264 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X floatatom 200 238 5 0 0 0 - - -;
+#X floatatom 221 213 5 0 0 0 - - -;
+#X floatatom 242 185 5 0 0 0 - - -;
+#X floatatom 264 159 5 0 0 0 - - -;
+#X obj 179 19 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 179 54 metro 50;
+#X msg 272 54 zero;
+#X msg 272 86 reset;
+#X msg 35 87 poll;
+#X msg 99 87 nopoll;
+#X obj 523 129 MouseState;
+#X obj 523 264 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X floatatom 544 238 5 0 0 0 - - -;
+#X floatatom 565 213 5 0 0 0 - - -;
+#X floatatom 586 185 5 0 0 0 - - -;
+#X floatatom 608 159 5 0 0 0 - - -;
+#X obj 523 19 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 523 54 metro 50;
+#X msg 616 54 zero;
+#X msg 616 86 reset;
+#X msg 379 87 poll;
+#X msg 443 87 nopoll;
+#X obj 53 213 capture;
+#X connect 0 0 1 0;
+#X connect 0 1 2 0;
+#X connect 0 1 24 0;
+#X connect 0 2 3 0;
+#X connect 0 2 24 0;
+#X connect 0 3 4 0;
+#X connect 0 4 5 0;
+#X connect 6 0 7 0;
+#X connect 7 0 0 0;
+#X connect 8 0 0 0;
+#X connect 9 0 0 0;
+#X connect 10 0 0 0;
+#X connect 11 0 0 0;
+#X connect 12 0 13 0;
+#X connect 12 1 14 0;
+#X connect 12 2 15 0;
+#X connect 12 3 16 0;
+#X connect 12 4 17 0;
+#X connect 18 0 19 0;
+#X connect 19 0 12 0;
+#X connect 20 0 12 0;
+#X connect 21 0 12 0;
+#X connect 22 0 12 0;
+#X connect 23 0 12 0;
diff --git a/test/cyclone/TogEdge-test.pd b/test/cyclone/TogEdge-test.pd
new file mode 100644
index 0000000..9198075
--- /dev/null
+++ b/test/cyclone/TogEdge-test.pd
@@ -0,0 +1,16 @@
+#N canvas 516 361 368 289 12;
+#X obj 109 129 TogEdge;
+#X obj 109 184 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 167 184 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 168 74 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 109 74 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X msg 36 74 1.5;
+#X connect 0 0 1 0;
+#X connect 0 1 2 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
diff --git a/test/cyclone/Uzi-test.pd b/test/cyclone/Uzi-test.pd
new file mode 100644
index 0000000..c01ad33
--- /dev/null
+++ b/test/cyclone/Uzi-test.pd
@@ -0,0 +1,27 @@
+#N canvas 407 221 414 285 12;
+#X obj 153 97 Uzi;
+#X obj 153 194 counter;
+#X floatatom 153 225 5 0 0;
+#X msg 153 35 bang;
+#X msg 212 35 99;
+#X msg 212 66 11;
+#X floatatom 336 171 5 0 0;
+#X msg 62 225 pause;
+#X msg 55 35 resume;
+#X obj 296 136 t 0 0;
+#X obj 62 194 sel 10;
+#X floatatom 267 77 5 0 0;
+#X obj 164 136 print carry;
+#X connect 0 0 1 0;
+#X connect 0 1 12 0;
+#X connect 0 2 9 0;
+#X connect 1 0 2 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 1;
+#X connect 7 0 0 0;
+#X connect 8 0 0 0;
+#X connect 9 0 10 0;
+#X connect 9 1 6 0;
+#X connect 10 0 7 0;
+#X connect 11 0 0 1;
diff --git a/test/cyclone/active-test.pd b/test/cyclone/active-test.pd
new file mode 100644
index 0000000..6f40f96
--- /dev/null
+++ b/test/cyclone/active-test.pd
@@ -0,0 +1,19 @@
+#N canvas 52 81 262 185 12;
+#X obj 27 29 active;
+#X obj 27 74 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X obj 129 29 active;
+#X obj 129 74 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#N canvas 376 80 255 181 test 1;
+#X obj 27 29 active;
+#X obj 27 74 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 129 29 active;
+#X obj 129 74 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X connect 0 0 1 0;
+#X connect 2 0 3 0;
+#X restore 31 138 pd test;
+#X connect 0 0 1 0;
+#X connect 2 0 3 0;
diff --git a/test/cyclone/anal-test.pd b/test/cyclone/anal-test.pd
new file mode 100644
index 0000000..a4ec7ab
--- /dev/null
+++ b/test/cyclone/anal-test.pd
@@ -0,0 +1,17 @@
+#N canvas 466 161 450 300 12;
+#X obj 62 215 print;
+#X msg 62 67 1;
+#X floatatom 119 67 5 0 0;
+#X msg 189 67 reset;
+#X msg 189 108 clear;
+#X obj 198 215 anal 1025;
+#X obj 62 167 anal;
+#X msg 118 27 128 \, -1;
+#X msg 203 27 1.1;
+#X connect 1 0 6 0;
+#X connect 2 0 6 0;
+#X connect 3 0 6 0;
+#X connect 4 0 6 0;
+#X connect 6 0 0 0;
+#X connect 7 0 6 0;
+#X connect 8 0 6 0;
diff --git a/test/cyclone/append-test.pd b/test/cyclone/append-test.pd
new file mode 100644
index 0000000..821c22e
--- /dev/null
+++ b/test/cyclone/append-test.pd
@@ -0,0 +1,78 @@
+#N canvas 516 251 510 466 12;
+#X obj 25 416 print;
+#X msg 25 298 1 2 3;
+#X msg 102 298 set test;
+#X obj 25 241 print;
+#X msg 25 51 1 2 3;
+#X obj 25 169 t a b;
+#X msg 111 241 4 5 6;
+#X obj 190 206 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 347 50 testmess 1000;
+#X msg 347 19 mess;
+#X msg 101 19 mess;
+#X obj 101 50 testmess 100;
+#X msg 155 128 set changed;
+#X obj 111 169 gate;
+#X obj 111 206 t b b;
+#X obj 25 377 t a b b;
+#X msg 220 416 set mess1;
+#X msg 108 416 set mess2;
+#X msg 285 241 bang;
+#X msg 347 241 99;
+#X obj 285 377 print list;
+#X obj 285 339 route list;
+#X obj 408 377 print;
+#X msg 227 241 mess;
+#X msg 398 241 set bang;
+#X msg 400 278 set 0;
+#X obj 101 81 prepend check;
+#X msg 160 19 set set;
+#X msg 244 19 set check;
+#X obj 25 128 Append test;
+#X obj 25 339 Append test;
+#X obj 285 298 Append;
+#X obj 347 81 prepend check;
+#X msg 398 206 set test;
+#X obj 301 159 Append test it;
+#X obj 301 190 print;
+#X msg 301 128 symbol mess;
+#X connect 1 0 30 0;
+#X connect 2 0 30 0;
+#X connect 4 0 29 0;
+#X connect 5 0 3 0;
+#X connect 5 1 13 1;
+#X connect 6 0 29 0;
+#X connect 7 0 13 0;
+#X connect 8 0 32 0;
+#X connect 9 0 8 0;
+#X connect 10 0 11 0;
+#X connect 11 0 26 0;
+#X connect 12 0 29 0;
+#X connect 13 0 14 0;
+#X connect 14 0 6 0;
+#X connect 14 1 7 0;
+#X connect 15 0 0 0;
+#X connect 15 1 17 0;
+#X connect 15 2 16 0;
+#X connect 16 0 30 0;
+#X connect 17 0 30 0;
+#X connect 18 0 31 0;
+#X connect 19 0 31 0;
+#X connect 21 0 20 0;
+#X connect 21 1 22 0;
+#X connect 23 0 31 0;
+#X connect 24 0 31 0;
+#X connect 25 0 31 0;
+#X connect 26 0 29 0;
+#X connect 27 0 26 0;
+#X connect 27 0 32 0;
+#X connect 28 0 26 0;
+#X connect 28 0 32 0;
+#X connect 29 0 5 0;
+#X connect 30 0 15 0;
+#X connect 31 0 21 0;
+#X connect 32 0 29 0;
+#X connect 33 0 31 0;
+#X connect 34 0 35 0;
+#X connect 36 0 34 0;
diff --git a/test/cyclone/bad.coll b/test/cyclone/bad.coll
new file mode 100644
index 0000000..bb76cf7
--- /dev/null
+++ b/test/cyclone/bad.coll
@@ -0,0 +1,4 @@
+11, testing coll;
+12, missing semi
+13 extra key, with data;
+14 empty,;
diff --git a/test/cyclone/bondo-test.pd b/test/cyclone/bondo-test.pd
new file mode 100644
index 0000000..38a43ba
--- /dev/null
+++ b/test/cyclone/bondo-test.pd
@@ -0,0 +1,73 @@
+#N canvas 289 274 747 476 12;
+#X obj 78 164 print first;
+#X obj 199 165 print last;
+#X msg 78 22 any message;
+#X msg 199 21 other message;
+#X msg 94 62 11;
+#X msg 211 62 55;
+#X obj 78 108 bondo 5 1000 n;
+#X obj 412 203 print first;
+#X obj 530 169 print last;
+#X msg 412 22 any message;
+#X msg 533 57 other message;
+#X msg 437 92 11;
+#X msg 545 92 55;
+#X obj 412 133 bondo 5 1000;
+#X obj 437 169 print 2nd;
+#X msg 429 57 1 2 3;
+#X msg 21 62 test;
+#X msg 356 92 test;
+#X obj 78 390 print first;
+#X obj 199 391 print last;
+#X msg 78 248 any message;
+#X msg 199 247 other message;
+#X msg 94 288 11;
+#X msg 211 288 55;
+#X obj 412 429 print first;
+#X obj 530 395 print last;
+#X msg 412 248 any message;
+#X msg 533 283 other message;
+#X msg 437 318 11;
+#X msg 528 318 55;
+#X obj 437 395 print 2nd;
+#X msg 429 283 1 2 3;
+#X msg 21 288 test;
+#X msg 356 318 test;
+#X obj 78 334 bondo 5 n;
+#X obj 412 359 bondo 5;
+#X msg 583 319 -1 -2 \, -2 -3;
+#X msg 600 92 -1 -2 \, -2 -3;
+#X connect 2 0 6 0;
+#X connect 3 0 6 4;
+#X connect 4 0 6 0;
+#X connect 5 0 6 4;
+#X connect 6 0 0 0;
+#X connect 6 4 1 0;
+#X connect 9 0 13 0;
+#X connect 10 0 13 4;
+#X connect 11 0 13 0;
+#X connect 12 0 13 4;
+#X connect 13 0 7 0;
+#X connect 13 1 14 0;
+#X connect 13 4 8 0;
+#X connect 15 0 13 0;
+#X connect 16 0 6 0;
+#X connect 17 0 13 0;
+#X connect 20 0 34 0;
+#X connect 21 0 34 4;
+#X connect 22 0 34 0;
+#X connect 23 0 34 4;
+#X connect 26 0 35 0;
+#X connect 27 0 35 4;
+#X connect 28 0 35 0;
+#X connect 29 0 35 4;
+#X connect 31 0 35 0;
+#X connect 32 0 34 0;
+#X connect 33 0 35 0;
+#X connect 34 0 18 0;
+#X connect 34 4 19 0;
+#X connect 35 0 24 0;
+#X connect 35 1 30 0;
+#X connect 35 4 25 0;
+#X connect 36 0 35 3;
+#X connect 37 0 13 3;
diff --git a/test/cyclone/buddy-test.pd b/test/cyclone/buddy-test.pd
new file mode 100644
index 0000000..3c072b1
--- /dev/null
+++ b/test/cyclone/buddy-test.pd
@@ -0,0 +1,28 @@
+#N canvas 242 401 623 363 12;
+#X obj 66 268 print a;
+#X obj 168 268 print b;
+#X floatatom 107 83 5 0 0;
+#X floatatom 264 184 5 0 0;
+#X msg 136 116 symbol test1;
+#X msg 264 152 symbol test2;
+#X msg 264 77 one two three;
+#X msg 264 116 1 2 3 4 5 6 7 8 9;
+#X msg 38 25 a long message with floats 1 2 3 4 5 6 7 8 9 (lets make
+it even longer);
+#X obj 260 268 print c;
+#X obj 139 212 buddy 3;
+#X msg 40 156 clear;
+#X connect 2 0 10 0;
+#X connect 2 0 10 1;
+#X connect 3 0 10 2;
+#X connect 4 0 10 0;
+#X connect 4 0 10 1;
+#X connect 5 0 10 2;
+#X connect 6 0 10 2;
+#X connect 7 0 10 2;
+#X connect 8 0 10 0;
+#X connect 8 0 10 1;
+#X connect 10 0 0 0;
+#X connect 10 1 1 0;
+#X connect 10 2 9 0;
+#X connect 11 0 10 0;
diff --git a/test/cyclone/capture-test.pd b/test/cyclone/capture-test.pd
new file mode 100644
index 0000000..0ebc045
--- /dev/null
+++ b/test/cyclone/capture-test.pd
@@ -0,0 +1,48 @@
+#N canvas 548 272 562 363 12;
+#X obj 81 169 capture;
+#X obj 169 169 capture 100000;
+#X obj 169 216 print;
+#X floatatom 81 96 5 0 0 0 - - -;
+#X floatatom 169 96 5 0 0 0 - - -;
+#X obj 323 169 capture 2;
+#X obj 431 169 capture 1;
+#X floatatom 323 96 5 0 0 0 - - -;
+#X floatatom 431 96 5 0 0 0 - - -;
+#X msg 242 96 wclose;
+#X msg 59 59 write;
+#X msg 266 59 write test.capture;
+#X msg 16 96 dump;
+#X msg 147 24 1 2 3 4 5 6 7 8 9;
+#X msg 133 59 clear;
+#X msg 500 96 dump;
+#X msg 500 128 count;
+#X msg 376 134 count;
+#X obj 265 297 capture 10 x;
+#X obj 402 297 capture 10 m;
+#X floatatom 347 243 5 0 0 0 - - -;
+#X msg 226 134 count;
+#X msg 250 243 write;
+#X connect 0 0 2 0;
+#X connect 1 0 2 0;
+#X connect 3 0 0 0;
+#X connect 4 0 1 0;
+#X connect 5 0 2 0;
+#X connect 6 0 2 0;
+#X connect 7 0 5 0;
+#X connect 8 0 6 0;
+#X connect 9 0 0 0;
+#X connect 9 0 1 0;
+#X connect 9 0 5 0;
+#X connect 9 0 6 0;
+#X connect 10 0 0 0;
+#X connect 11 0 1 0;
+#X connect 12 0 0 0;
+#X connect 13 0 1 0;
+#X connect 14 0 1 0;
+#X connect 15 0 6 0;
+#X connect 16 0 6 0;
+#X connect 17 0 5 0;
+#X connect 20 0 18 0;
+#X connect 20 0 19 0;
+#X connect 21 0 1 0;
+#X connect 22 0 18 0;
diff --git a/test/cyclone/click-test.pd b/test/cyclone/click-test.pd
new file mode 100644
index 0000000..3a16ae6
--- /dev/null
+++ b/test/cyclone/click-test.pd
@@ -0,0 +1,26 @@
+#N canvas 480 212 450 300 12;
+#X obj 45 136 click~;
+#X obj 247 136 click~ -1;
+#X obj 45 59 testmess 100;
+#X msg 45 24 bang;
+#X obj 45 98 prepend set;
+#X obj 68 237 capture~ f;
+#X msg 68 207 clear;
+#X obj 212 237 capture~ f;
+#X msg 212 207 clear;
+#X msg 176 98 bang;
+#X msg 182 24 bang;
+#X obj 182 59 testmess 1000;
+#X connect 0 0 5 0;
+#X connect 1 0 7 0;
+#X connect 2 0 4 0;
+#X connect 3 0 2 0;
+#X connect 4 0 0 0;
+#X connect 6 0 5 0;
+#X connect 8 0 7 0;
+#X connect 9 0 0 0;
+#X connect 9 0 1 0;
+#X connect 9 0 6 0;
+#X connect 9 0 8 0;
+#X connect 10 0 11 0;
+#X connect 11 0 4 0;
diff --git a/test/cyclone/clip-test.pd b/test/cyclone/clip-test.pd
new file mode 100644
index 0000000..9bc83ef
--- /dev/null
+++ b/test/cyclone/clip-test.pd
@@ -0,0 +1,41 @@
+#N canvas 282 194 586 335 12;
+#X obj 32 223 Clip -5;
+#X obj 32 255 print;
+#X msg 32 176 set test;
+#X msg 122 175 set test -5;
+#X floatatom 46 103 5 0 0;
+#X msg 122 143 set test 3;
+#X msg 58 143 set;
+#X obj 406 234 Clip -5 0;
+#X obj 406 266 print;
+#X msg 427 207 set;
+#X msg 406 176 set -5;
+#X floatatom 314 207 5 0 0;
+#X msg 129 30 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7;
+#X msg 129 62 -7 -6 -5 -4 -3 test -1 0 1 2 3 4 5 6 7;
+#X msg 132 103 test;
+#X msg 252 175 set -5 test -4;
+#X msg 312 103 bang;
+#X msg 198 103 set 11 333;
+#X obj 252 143 testmess 350;
+#X msg 444 103 bang;
+#X obj 384 143 testmess 200;
+#X connect 0 0 1 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 0;
+#X connect 7 0 8 0;
+#X connect 9 0 7 0;
+#X connect 10 0 7 0;
+#X connect 11 0 7 0;
+#X connect 12 0 0 0;
+#X connect 13 0 0 0;
+#X connect 14 0 0 0;
+#X connect 15 0 0 0;
+#X connect 16 0 18 0;
+#X connect 17 0 0 0;
+#X connect 18 0 0 0;
+#X connect 19 0 20 0;
+#X connect 20 0 0 0;
diff --git a/test/cyclone/coll-print.pd b/test/cyclone/coll-print.pd
new file mode 100644
index 0000000..8ef57dc
--- /dev/null
+++ b/test/cyclone/coll-print.pd
@@ -0,0 +1,12 @@
+#N canvas 24 90 450 300 12;
+#X obj 169 170 print;
+#X obj 169 129 prepend dummy;
+#X msg 169 83 set \$1;
+#X obj 66 83 prepend :;
+#X obj 66 40 inlet;
+#X obj 169 40 inlet;
+#X connect 1 0 0 0;
+#X connect 2 0 1 0;
+#X connect 3 0 1 0;
+#X connect 4 0 3 0;
+#X connect 5 0 2 0;
diff --git a/test/cyclone/coll-test.pd b/test/cyclone/coll-test.pd
new file mode 100644
index 0000000..d955ce1
--- /dev/null
+++ b/test/cyclone/coll-test.pd
@@ -0,0 +1,117 @@
+#N canvas 392 153 614 512 12;
+#X obj 40 57 coll;
+#C restore;
+#X msg 40 20 debug;
+#X obj 106 57 coll;
+#C restore;
+#X msg 106 20 debug;
+#X msg 42 136 debug;
+#X msg 184 136 debug;
+#X obj 42 172 coll good.coll;
+#C restore;
+#X obj 184 205 coll good.coll;
+#C restore;
+#X msg 42 218 debug;
+#X obj 42 280 coll good.coll;
+#C restore;
+#X msg 41 366 debug;
+#X obj 41 406 coll bad.coll;
+#C restore;
+#X msg 113 218 dump;
+#X msg 25 103 store one first element;
+#X msg 260 103 store 2 2nd element;
+#X obj 321 451 coll good.coll;
+#C restore;
+#X msg 265 136 store 3 3rd;
+#X msg 248 172 store 4 4;
+#X floatatom 113 248 5 0 0 0 - - -;
+#X msg 205 248 renumber 11;
+#X msg 246 280 swap 11 one;
+#X msg 308 376 read good.coll;
+#X msg 246 406 read;
+#X msg 191 406 open;
+#X obj 42 322 coll-print;
+#X obj 41 444 coll-print;
+#X msg 111 366 dump;
+#X obj 167 57 coll missing;
+#C restore;
+#X msg 285 344 refer bad.coll;
+#X msg 440 344 refer good.coll;
+#X msg 443 415 write test.coll;
+#X msg 379 415 write;
+#X msg 349 172 flags 1 0;
+#X msg 380 224 sort -1;
+#X msg 394 248 sort -1 -1;
+#X msg 409 280 sort 1;
+#X msg 423 309 sort 1 -1;
+#X msg 191 376 wclose;
+#N canvas 502 158 450 423 large 0;
+#X obj 241 341 coll big.coll;
+#C restore;
+#X msg 33 205 store \$1;
+#X obj 33 277 testmess 10;
+#X obj 33 92 Uzi;
+#X msg 99 92 clear;
+#X obj 33 57 t 0 b;
+#X obj 33 169 t 0 b;
+#X msg 167 277 wclose;
+#X obj 241 380 print;
+#X floatatom 164 341 5 0 0 0 - - -;
+#X msg 261 277 sort -1 -1;
+#X obj 129 205 random 10000;
+#X msg 129 241 set 10 \$1;
+#X msg 241 241 clear;
+#X msg 33 21 5000;
+#X obj 33 131 urn 50000;
+#X msg 283 308 sort 1;
+#X connect 0 0 8 0;
+#X connect 1 0 2 0;
+#X connect 2 0 0 0;
+#X connect 3 0 15 0;
+#X connect 4 0 15 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 6 0 1 0;
+#X connect 6 1 11 0;
+#X connect 7 0 0 0;
+#X connect 9 0 0 0;
+#X connect 10 0 0 0;
+#X connect 11 0 12 0;
+#X connect 12 0 2 0;
+#X connect 13 0 0 0;
+#X connect 14 0 5 0;
+#X connect 15 0 6 0;
+#X connect 16 0 0 0;
+#X restore 320 20 pd large;
+#X connect 1 0 0 0;
+#X connect 3 0 2 0;
+#X connect 4 0 6 0;
+#X connect 5 0 7 0;
+#X connect 8 0 9 0;
+#X connect 9 0 24 0;
+#X connect 9 1 24 1;
+#X connect 10 0 11 0;
+#X connect 11 0 25 0;
+#X connect 11 1 25 1;
+#X connect 12 0 9 0;
+#X connect 13 0 6 0;
+#X connect 14 0 7 0;
+#X connect 16 0 7 0;
+#X connect 17 0 7 0;
+#X connect 18 0 9 0;
+#X connect 19 0 15 0;
+#X connect 20 0 15 0;
+#X connect 21 0 15 0;
+#X connect 22 0 15 0;
+#X connect 23 0 15 0;
+#X connect 26 0 11 0;
+#X connect 28 0 15 0;
+#X connect 29 0 15 0;
+#X connect 30 0 15 0;
+#X connect 31 0 15 0;
+#X connect 32 0 7 0;
+#X connect 33 0 15 0;
+#X connect 34 0 15 0;
+#X connect 35 0 15 0;
+#X connect 36 0 15 0;
+#X connect 37 0 15 0;
diff --git a/test/cyclone/comb-test.pd b/test/cyclone/comb-test.pd
new file mode 100644
index 0000000..dc2e599
--- /dev/null
+++ b/test/cyclone/comb-test.pd
@@ -0,0 +1,80 @@
+#N canvas 134 225 749 475 12;
+#X floatatom 137 89 5 0 0;
+#X floatatom 534 89 5 0 0;
+#X msg 68 154 clear;
+#X obj 36 427 dac~;
+#X floatatom 376 89 5 0 0;
+#X obj 220 119 osc~;
+#X floatatom 220 89 5 0 0;
+#X obj 137 154 line~;
+#X msg 137 119 \$1 5;
+#X obj 220 154 *~ 1;
+#X floatatom 303 89 5 0 0;
+#X floatatom 458 89 5 0 0;
+#N canvas 80 0 592 295 graph1 0;
+#X array test 1000 float 0;
+#X coords 0 1 999 -1 200 140 1;
+#X restore 522 282 graph;
+#X obj 65 282 tabwrite~ test;
+#X msg 65 246 bang;
+#X obj 36 59 adc~;
+#X obj 267 282 int;
+#X msg 267 246 0;
+#X msg 313 246 1;
+#X obj 347 18 loadbang;
+#X msg 220 59 0.33;
+#X msg 137 59 2;
+#X msg 303 59 1;
+#X obj 534 154 line~;
+#X msg 534 119 \$1 5;
+#X obj 93 354 dbtorms;
+#X obj 93 427 line~;
+#X obj 36 390 *~;
+#X msg 93 390 \$1 10;
+#X obj 96 312 hsl 128 25 0 100 0 0 empty empty empty -2 -6 0 8 -24198
+-1 -1 0 0;
+#X obj 267 312 vex_pool~ pool test.pool;
+#X msg 458 59 0.4;
+#X msg 376 59 0.7;
+#X msg 534 59 0.66;
+#X obj 36 209 comb~ 100 2 0.7 0.4 0.66;
+#X connect 0 0 8 0;
+#X connect 1 0 24 0;
+#X connect 2 0 34 0;
+#X connect 4 0 34 2;
+#X connect 5 0 9 0;
+#X connect 6 0 5 0;
+#X connect 7 0 34 1;
+#X connect 8 0 7 0;
+#X connect 9 0 34 1;
+#X connect 10 0 9 1;
+#X connect 11 0 34 3;
+#X connect 14 0 13 0;
+#X connect 15 0 34 0;
+#X connect 16 0 30 0;
+#X connect 17 0 16 0;
+#X connect 18 0 16 0;
+#X connect 19 0 33 0;
+#X connect 19 0 31 0;
+#X connect 19 0 32 0;
+#X connect 19 0 22 0;
+#X connect 19 0 20 0;
+#X connect 19 0 21 0;
+#X connect 20 0 6 0;
+#X connect 21 0 0 0;
+#X connect 22 0 10 0;
+#X connect 23 0 34 4;
+#X connect 24 0 23 0;
+#X connect 25 0 28 0;
+#X connect 26 0 27 1;
+#X connect 27 0 3 0;
+#X connect 27 0 3 1;
+#X connect 28 0 26 0;
+#X connect 29 0 25 0;
+#X connect 30 0 34 0;
+#X connect 30 1 16 0;
+#X connect 31 0 11 0;
+#X connect 32 0 4 0;
+#X connect 33 0 1 0;
+#X connect 34 0 13 0;
+#X connect 34 0 27 0;
diff --git a/test/cyclone/comment-dotest.pd b/test/cyclone/comment-dotest.pd
new file mode 100644
index 0000000..7a78080
--- /dev/null
+++ b/test/cyclone/comment-dotest.pd
@@ -0,0 +1,37 @@
+#N canvas 286 325 415 463 12;
+#N canvas 454 204 548 368 doit 0;
+#X obj 27 120 counter;
+#X obj 27 254 pack 0 0 0;
+#X obj 27 188 * 10;
+#X obj 27 21 inlet;
+#X obj 27 85 Uzi;
+#X obj 27 53 t 0 b;
+#X msg 73 85 set 0;
+#X obj 27 220 + 10;
+#X obj 81 220 + 10;
+#X obj 138 220 + 7;
+#X obj 27 154 t 0 0 0 0;
+#X obj 81 188 *;
+#X obj 138 188 * 3;
+#X msg 27 289 \; pd-comment-dotest.pd obj \$1 \$2 comment 0 \$3 . test
+;
+#X connect 0 0 10 0;
+#X connect 1 0 13 0;
+#X connect 2 0 7 0;
+#X connect 3 0 5 0;
+#X connect 4 0 0 0;
+#X connect 5 0 4 0;
+#X connect 5 1 6 0;
+#X connect 6 0 0 0;
+#X connect 7 0 1 0;
+#X connect 8 0 1 1;
+#X connect 9 0 1 2;
+#X connect 10 0 2 0;
+#X connect 10 1 11 0;
+#X connect 10 2 11 1;
+#X connect 10 3 12 0;
+#X connect 11 0 8 0;
+#X connect 12 0 9 0;
+#X restore 283 92 pd doit;
+#X msg 283 60 20;
+#X connect 1 0 0 0;
diff --git a/test/cyclone/comment-ogonki.pd b/test/cyclone/comment-ogonki.pd
new file mode 100644
index 0000000..1e0902e
--- /dev/null
+++ b/test/cyclone/comment-ogonki.pd
@@ -0,0 +1,9 @@
+#N canvas 232 153 767 466 12;
+#X obj 41 14 comment 550 72 helvetica iso8859-2 0 255 0 0 ê󱶳¿¼æñ
+ÊÓ¡¦£¯¬ÆÑ;
+#X obj 48 321 comment 200 24 courier iso8859-2 0 0 255 0 ê󱶳¿¼æñ
+ÊÓ¡¦£¯¬ÆÑ;
+#X obj 275 316 comment 200 24 times iso8859-2 0 0 255 255 ê󱶳¿¼æñ
+ÊÓ¡¦£¯¬ÆÑ;
+#X obj 500 316 comment 200 24 helvetica iso8859-2 0 255 255 0 ê󱶳¿¼æñ
+ÊÓ¡¦£¯¬ÆÑ;
diff --git a/test/cyclone/comment-test.pd b/test/cyclone/comment-test.pd
new file mode 100644
index 0000000..03edff6
--- /dev/null
+++ b/test/cyclone/comment-test.pd
@@ -0,0 +1,21 @@
+#N canvas 85 23 415 463 12;
+#X obj 10 10 comment 0 7 courier ? 0 0 0 0 test;
+#X obj 20 10 comment 0 10 courier ? 0 0 0 0 test;
+#X obj 30 14 comment 0 13 courier ? 0 0 0 0 test;
+#X obj 40 19 comment 0 16 courier ? 0 0 0 0 test;
+#X obj 50 26 comment 0 19 courier ? 0 0 0 0 test;
+#X obj 60 35 comment 0 22 courier ? 0 0 0 0 test;
+#X obj 70 46 comment 0 25 courier ? 0 0 0 0 test;
+#X obj 80 59 comment 0 28 courier ? 0 0 0 0 test;
+#X obj 90 74 comment 0 31 courier ? 0 0 0 0 test;
+#X obj 100 91 comment 0 34 courier ? 0 0 0 0 test;
+#X obj 110 110 comment 0 37 courier ? 0 0 0 0 test;
+#X obj 120 131 comment 0 40 courier ? 0 0 0 0 test;
+#X obj 130 154 comment 0 43 courier ? 0 0 0 0 test;
+#X obj 140 179 comment 0 46 courier ? 0 0 0 0 test;
+#X obj 150 206 comment 0 49 courier ? 0 0 0 0 test;
+#X obj 160 235 comment 0 52 courier ? 0 0 0 0 test;
+#X obj 170 266 comment 0 55 courier ? 0 0 0 0 test;
+#X obj 180 299 comment 0 58 courier ? 0 0 0 0 test;
+#X obj 190 334 comment 0 61 courier ? 0 0 0 0 test;
+#X obj 200 371 comment 0 64 courier ? 0 0 0 0 test;
diff --git a/test/cyclone/count-test.pd b/test/cyclone/count-test.pd
new file mode 100644
index 0000000..27fe454
--- /dev/null
+++ b/test/cyclone/count-test.pd
@@ -0,0 +1,19 @@
+#N canvas 229 256 450 300 12;
+#X obj 121 167 snapshot~;
+#X obj 294 122 metro 30;
+#X obj 294 88 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X floatatom 121 215 0 0 0;
+#X msg 121 60 bang;
+#X msg 59 60 stop;
+#X obj 121 118 count~;
+#X msg 177 60 3;
+#X msg 232 60 100;
+#X connect 0 0 3 0;
+#X connect 1 0 0 0;
+#X connect 2 0 1 0;
+#X connect 4 0 6 0;
+#X connect 5 0 6 0;
+#X connect 6 0 0 0;
+#X connect 7 0 6 0;
+#X connect 8 0 6 1;
diff --git a/test/cyclone/counter-test.pd b/test/cyclone/counter-test.pd
new file mode 100644
index 0000000..5716b52
--- /dev/null
+++ b/test/cyclone/counter-test.pd
@@ -0,0 +1,46 @@
+#N canvas 476 253 450 390 12;
+#X obj 68 234 counter;
+#X floatatom 68 344 0 0 0;
+#X msg 16 173 bang;
+#X msg 68 35 up;
+#X msg 80 61 down;
+#X msg 89 87 updown;
+#X msg 96 117 bang;
+#X msg 106 145 bang;
+#X msg 116 173 bang;
+#X msg 126 203 bang;
+#X floatatom 152 117 5 0 0;
+#X floatatom 161 145 5 0 0;
+#X floatatom 167 173 5 0 0;
+#X floatatom 177 203 5 0 0;
+#X floatatom 126 259 5 0 0;
+#X obj 87 315 print second;
+#X obj 106 286 print third;
+#X msg 319 203 max \$1;
+#X msg 243 203 min \$1;
+#X floatatom 243 177 5 0 0;
+#X floatatom 319 177 5 0 0;
+#X msg 16 117 inc;
+#X msg 16 145 dec;
+#X connect 0 0 1 0;
+#X connect 0 1 15 0;
+#X connect 0 2 16 0;
+#X connect 0 3 14 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 1;
+#X connect 7 0 0 2;
+#X connect 8 0 0 3;
+#X connect 9 0 0 4;
+#X connect 10 0 0 1;
+#X connect 11 0 0 2;
+#X connect 12 0 0 3;
+#X connect 13 0 0 4;
+#X connect 17 0 0 0;
+#X connect 18 0 0 0;
+#X connect 19 0 18 0;
+#X connect 20 0 17 0;
+#X connect 21 0 0 0;
+#X connect 22 0 0 0;
diff --git a/test/cyclone/cycle-test.pd b/test/cyclone/cycle-test.pd
new file mode 100644
index 0000000..97d008e
--- /dev/null
+++ b/test/cyclone/cycle-test.pd
@@ -0,0 +1,30 @@
+#N canvas 257 195 450 300 12;
+#X msg 77 196 bang;
+#X obj 131 235 print a;
+#X obj 218 235 print b;
+#X msg 131 153 test;
+#X msg 192 152 symbol test;
+#X msg 72 86 1 2 3 \, 4 5;
+#X msg 204 86 1 2 3;
+#X msg 230 115 4 5;
+#X obj 131 195 cycle 2 1;
+#X msg 242 18 bang;
+#X obj 204 59 del 100;
+#X obj 293 59 del 100;
+#X obj 312 205 cycle;
+#X obj 312 237 print;
+#X msg 312 151 test 1 2 3;
+#X connect 0 0 8 0;
+#X connect 3 0 8 0;
+#X connect 4 0 8 0;
+#X connect 5 0 8 0;
+#X connect 6 0 8 0;
+#X connect 7 0 8 0;
+#X connect 8 0 1 0;
+#X connect 8 1 2 0;
+#X connect 9 0 10 0;
+#X connect 9 0 11 0;
+#X connect 10 0 6 0;
+#X connect 11 0 7 0;
+#X connect 12 0 13 0;
+#X connect 14 0 12 0;
diff --git a/test/cyclone/cyclone-test.pd b/test/cyclone/cyclone-test.pd
new file mode 100644
index 0000000..d2919c0
--- /dev/null
+++ b/test/cyclone/cyclone-test.pd
@@ -0,0 +1,54 @@
+#N canvas 430 63 531 442 12;
+#X obj 39 399 cyclone;
+#X msg 39 19 bang;
+#X msg 244 19 import;
+#X obj 42 212 forward texthelp;
+#X obj 63 278 r texthelp;
+#X msg 56 245 send binhelp;
+#X msg 182 245 send texthelp;
+#X obj 90 309 r binhelp;
+#X msg 148 112 pv;
+#X msg 64 112 coll;
+#X msg 207 83 triangle~;
+#X msg 148 83 comb~;
+#X msg 64 83 allpass~;
+#X msg 207 112 message;
+#X msg 207 141 line~;
+#X obj 90 338 sprintf import ../../../ref/c74help/bin/%s.help;
+#X obj 63 369 sprintf import ../../../ref/c74help/text/%s.help;
+#X msg 92 19 dummies;
+#X obj 39 48 cyclone;
+#X msg 274 141 groove~;
+#X msg 207 170 scope~;
+#X msg 306 83 trapezoid~;
+#X msg 306 112 kink~;
+#X msg 290 170 rate~;
+#X msg 360 170 pong~;
+#X msg 360 141 vectral~;
+#X msg 170 19 reps;
+#X msg 378 112 bitand~;
+#X connect 1 0 18 0;
+#X connect 2 0 18 0;
+#X connect 4 0 16 0;
+#X connect 5 0 3 0;
+#X connect 6 0 3 0;
+#X connect 7 0 15 0;
+#X connect 8 0 3 0;
+#X connect 9 0 3 0;
+#X connect 10 0 3 0;
+#X connect 11 0 3 0;
+#X connect 12 0 3 0;
+#X connect 13 0 3 0;
+#X connect 14 0 3 0;
+#X connect 15 0 0 0;
+#X connect 16 0 0 0;
+#X connect 17 0 18 0;
+#X connect 19 0 3 0;
+#X connect 20 0 3 0;
+#X connect 21 0 3 0;
+#X connect 22 0 3 0;
+#X connect 23 0 3 0;
+#X connect 24 0 3 0;
+#X connect 25 0 3 0;
+#X connect 26 0 18 0;
+#X connect 27 0 3 0;
diff --git a/test/cyclone/decide-test.pd b/test/cyclone/decide-test.pd
new file mode 100644
index 0000000..27c534c
--- /dev/null
+++ b/test/cyclone/decide-test.pd
@@ -0,0 +1,27 @@
+#N canvas 242 258 450 300 12;
+#X obj 116 111 decide;
+#X msg 47 68 bang;
+#X obj 116 68 Uzi;
+#X obj 116 198 counter;
+#X obj 200 198 counter;
+#X obj 116 151 sel 0 1;
+#X floatatom 116 249 0 0 0;
+#X floatatom 200 249 0 0 0;
+#X msg 116 29 10000;
+#X obj 276 73 decide;
+#X msg 237 29 bang;
+#X msg 325 29 1;
+#X msg 382 29 -1;
+#X obj 276 111 print;
+#X connect 0 0 5 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 6 0;
+#X connect 4 0 7 0;
+#X connect 5 0 3 0;
+#X connect 5 1 4 0;
+#X connect 8 0 2 0;
+#X connect 9 0 13 0;
+#X connect 10 0 9 0;
+#X connect 11 0 9 1;
+#X connect 12 0 9 1;
diff --git a/test/cyclone/drunk-test.pd b/test/cyclone/drunk-test.pd
new file mode 100644
index 0000000..fdd6087
--- /dev/null
+++ b/test/cyclone/drunk-test.pd
@@ -0,0 +1,45 @@
+#N canvas 366 150 514 397 12;
+#X obj 43 265 drunk;
+#X obj 43 305 print;
+#X msg 43 112 bang;
+#X msg 53 142 seed 123;
+#X floatatom 147 172 5 0 0;
+#X floatatom 171 196 5 0 0;
+#X floatatom 189 219 5 0 0;
+#X msg 147 142 11 22 33;
+#X obj 282 305 print;
+#X msg 282 112 bang;
+#X msg 292 142 seed 123;
+#X floatatom 386 172 5 0 0;
+#X floatatom 410 196 5 0 0;
+#X floatatom 428 219 5 0 0;
+#X msg 386 142 11 22 33;
+#X obj 282 265 drunk 100 -2;
+#X msg 124 265 -----;
+#X msg 62 177 set 50;
+#X msg 301 177 set 50;
+#X msg 43 28 1000;
+#X obj 43 66 Uzi;
+#X msg 282 28 1000;
+#X obj 282 66 Uzi;
+#X connect 0 0 1 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 1;
+#X connect 6 0 0 2;
+#X connect 7 0 0 0;
+#X connect 9 0 15 0;
+#X connect 10 0 15 0;
+#X connect 11 0 15 0;
+#X connect 12 0 15 1;
+#X connect 13 0 15 2;
+#X connect 14 0 15 0;
+#X connect 15 0 8 0;
+#X connect 16 0 1 0;
+#X connect 17 0 0 0;
+#X connect 18 0 15 0;
+#X connect 19 0 20 0;
+#X connect 20 0 0 0;
+#X connect 21 0 22 0;
+#X connect 22 0 15 0;
diff --git a/test/cyclone/forward-test.pd b/test/cyclone/forward-test.pd
new file mode 100644
index 0000000..af4b299
--- /dev/null
+++ b/test/cyclone/forward-test.pd
@@ -0,0 +1,27 @@
+#N canvas 489 306 462 351 12;
+#X msg 197 169 send there;
+#X msg 197 205 send elsewhere;
+#X msg 197 240 send;
+#X obj 62 45 r there;
+#X obj 167 45 r elsewhere;
+#X obj 62 83 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 167 83 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 67 195 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 207 83 print;
+#X msg 100 124 any message;
+#X obj 100 279 forward here;
+#X obj 266 240 r here;
+#X obj 266 279 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X connect 0 0 10 0;
+#X connect 1 0 10 0;
+#X connect 2 0 10 0;
+#X connect 3 0 5 0;
+#X connect 4 0 6 0;
+#X connect 4 0 8 0;
+#X connect 7 0 10 0;
+#X connect 9 0 10 0;
+#X connect 11 0 12 0;
diff --git a/test/cyclone/frameaccum-test.pd b/test/cyclone/frameaccum-test.pd
new file mode 100644
index 0000000..61e4ffd
--- /dev/null
+++ b/test/cyclone/frameaccum-test.pd
@@ -0,0 +1,15 @@
+#N canvas 0 0 450 300 12;
+#X obj 31 52 frameaccum~;
+#X obj 31 93 capture~;
+#X obj 177 183 Scope~ 234 106 8 3 256 0 1 0 0 0 0 102 255 51 135 135
+135 0;
+#X obj 325 93 capture~;
+#X obj 325 52 framedelta~;
+#X msg 33 143 range 0 1 \, bufsize 256 \, 8;
+#X obj 177 13 train~ 46.4399;
+#X connect 0 0 1 0;
+#X connect 4 0 3 0;
+#X connect 5 0 2 0;
+#X connect 6 0 2 0;
+#X connect 6 0 0 0;
+#X connect 6 0 4 0;
diff --git a/test/cyclone/fromsymbol-test.pd b/test/cyclone/fromsymbol-test.pd
new file mode 100644
index 0000000..cacbc83
--- /dev/null
+++ b/test/cyclone/fromsymbol-test.pd
@@ -0,0 +1,64 @@
+#N canvas 352 169 704 560 12;
+#X obj 81 108 tosymbol;
+#X msg 81 62 one two three;
+#X obj 81 147 fromsymbol;
+#X msg 29 62 one;
+#X obj 243 62 testmess 100;
+#X msg 243 31 test;
+#X msg 385 31 test;
+#X obj 385 62 testmess 300;
+#X obj 81 190 route one test;
+#X obj 81 229 print one;
+#X obj 184 229 print test;
+#X obj 293 229 print unknown;
+#X obj 42 316 tosymbol;
+#X obj 42 359 fromsymbol;
+#X floatatom 106 416 5 0 0;
+#X floatatom 158 390 5 0 0;
+#X floatatom 42 282 5 0 0;
+#X obj 158 359 f;
+#X obj 268 322 tosymbol;
+#X obj 268 359 fromsymbol;
+#X msg 133 316 99;
+#X msg 178 316 0.99;
+#X msg 133 282 1 2 3;
+#X obj 42 416 print;
+#X msg 268 397 test2;
+#X msg 364 282 set test2;
+#X msg 268 282 set test1;
+#X msg 476 246 1 2 3 4;
+#X obj 476 282 tosymbol;
+#X obj 476 322 fromsymbol;
+#X obj 476 359 unpack 0 0 0 0;
+#X obj 476 397 print;
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 2 0 8 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 4 0;
+#X connect 6 0 7 0;
+#X connect 7 0 0 0;
+#X connect 8 0 9 0;
+#X connect 8 1 10 0;
+#X connect 8 2 11 0;
+#X connect 12 0 13 0;
+#X connect 12 0 17 0;
+#X connect 13 0 14 0;
+#X connect 13 0 23 0;
+#X connect 16 0 12 0;
+#X connect 17 0 15 0;
+#X connect 18 0 19 0;
+#X connect 19 0 24 0;
+#X connect 20 0 13 0;
+#X connect 21 0 13 0;
+#X connect 22 0 13 0;
+#X connect 25 0 18 0;
+#X connect 26 0 18 0;
+#X connect 27 0 28 0;
+#X connect 28 0 29 0;
+#X connect 29 0 30 0;
+#X connect 30 0 31 0;
+#X connect 30 1 31 0;
+#X connect 30 2 31 0;
+#X connect 30 3 31 0;
diff --git a/test/cyclone/funbuff-etest.pd b/test/cyclone/funbuff-etest.pd
new file mode 100644
index 0000000..5d6a1a3
--- /dev/null
+++ b/test/cyclone/funbuff-etest.pd
@@ -0,0 +1,164 @@
+#N canvas 116 34 735 514 12;
+#X msg 49 113 clear;
+#X floatatom 172 181 5 0 0;
+#X obj 212 243 * -1;
+#X obj 172 213 t 0 0;
+#X floatatom 172 147 5 0 0;
+#X obj 279 113 Uzi;
+#X msg 49 181 debug \$1;
+#X msg 71 147 1;
+#X obj 279 71 t 0 0;
+#X msg 224 34 1000;
+#X msg 279 34 10000;
+#X msg 173 34 100;
+#X obj 530 147 counter;
+#X obj 530 113 Uzi;
+#X msg 595 34 100000;
+#X msg 475 34 1000;
+#X msg 530 34 10000;
+#X msg 424 34 100;
+#X msg 578 113 set 0;
+#X obj 530 71 t 0 b;
+#X msg 114 147 2;
+#X obj 279 147 urn;
+#X msg 344 34 100000;
+#X obj 531 306 counter;
+#X obj 531 271 Uzi;
+#X msg 579 271 set 0;
+#X obj 531 235 t 0 b;
+#X msg 531 196 50;
+#X msg 582 196 100;
+#X obj 429 235 Uzi;
+#X msg 429 196 50;
+#X msg 480 196 100;
+#X obj 429 271 urn 100;
+#X obj 49 355 funbuff;
+#C embed 1;
+#C set 1 -1 2 -2 3 -3 5 -5 6 -6 7 -7 8 -8 9 -9 10 -10 11 -11 12 -12
+13 -13 14 -14 15 -15 16 -16 18 -18 19 -19 20 -20 21 -21 22 -22 23 -23
+25 -25 26 -26 27 -27 28 -28 30 -30 31 -31 33 -33 34 -34;
+#C restore;
+#X obj 49 426 print;
+#X msg 60 213 bang;
+#X msg 69 243 dump;
+#X obj 49 389 pack;
+#X msg 126 288 set;
+#X msg 194 288 set 1 2 3;
+#X msg 171 83 goto 15;
+#X msg 171 112 next;
+#X msg 148 426 write test.funbuff;
+#X msg 157 461 read test.funbuff;
+#X msg 184 364 read;
+#X msg 184 393 write;
+#X obj 398 389 funbuff test.funbuff;
+#C embed 1;
+#C set 0 -0 1 -1 2 -2 3 -3 4 -4 5 -5 6 -6 7 -7 8 -8 9 -9 10 -10 11
+-11 12 -12 13 -13 14 -14 15 -15 16 -16 17 -17 18 -18 19 -19 20 -20
+21 -21 22 -22 23 -23 24 -24 25 -25 26 -26 27 -27 28 -28 29 -29 30 -30
+31 -31 32 -32 33 -33 34 -34 35 -35 36 -36 37 -37 38 -38 39 -39 40 -40
+41 -41 42 -42 43 -43 44 -44 45 -45 46 -46 47 -47 48 -48 49 -49 50 -50
+51 -51 52 -52 53 -53 54 -54 55 -55 56 -56 57 -57 58 -58 59 -59 60 -60
+61 -61 62 -62 63 -63 64 -64 65 -65 66 -66 67 -67 68 -68 69 -69 70 -70
+71 -71 72 -72 73 -73 74 -74 75 -75 76 -76 77 -77 78 -78 79 -79 80 -80
+81 -81 82 -82 83 -83 84 -84 85 -85 86 -86 87 -87 88 -88 89 -89 90 -90
+91 -91 92 -92 93 -93 94 -94 95 -95 96 -96 97 -97 98 -98 99 -99;
+#C restore;
+#X obj 398 461 print;
+#X obj 398 426 pack;
+#X msg 398 355 bang;
+#X msg 456 355 next;
+#X msg 514 355 goto 0;
+#N canvas 478 69 552 396 interp 0;
+#X obj 52 124 funbuff test.funbuff;
+#C restore;
+#X msg 52 85 interp \$1;
+#X floatatom 52 53 5 0 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array t 100 float 1;
+#A 0 0 -0.0285716 -0.0548876 -0.0812036 -0.10752 -0.133836 -0.160152
+-0.186468 -0.212784 -0.2391 -0.265416 -0.291732 -0.318048 -0.344364
+-0.37068 -0.396996 -0.423312 -0.449628 -0.475944 -0.50226 -0.528575
+-0.55429 -0.580004 -0.605719 -0.631433 -0.657148 -0.682863 -0.708577
+-0.734292 -0.760006 -0.785721 -0.811435 -0.83715 -0.862864 -0.888579
+-0.914293 -0.939293 -0.964293 -0.989294 -1.01429 -1.04287 -1.07144
+-1.10001 -1.12382 -1.14763 -1.17144 -1.18572 -1.20001 -1.22858 -1.25715
+-1.28096 -1.30477 -1.32858 -1.35715 -1.40715 -1.45715 -1.40001 -1.38573
+-1.15715 -0.942865 -0.0285715 0.242859 0.343812 0.444765 0.545719 0.646672
+0.747625 0.848578 0.949531 1.05048 1.15144 1.25239 1.35334 1.4543 1.55525
+1.6562 1.77144 1.84922 1.927 2.68574 2.67145 2.65716 2.64288 2.62859
+2.61431 2.6041 2.5939 2.58369 2.57349 2.56329 2.55308 2.54288 2.54288
+2.54696 2.55104 2.55512 2.5592 2.56329 2.56737 2.62859;
+#X coords 0 1 99 -1 200 140 1;
+#X restore 290 173 graph;
+#X floatatom 184 53 5 0 0;
+#X msg 184 85 interptab \$1 t;
+#X floatatom 52 168 0 0 0;
+#X connect 0 0 6 0;
+#X connect 1 0 0 0;
+#X connect 2 0 1 0;
+#X connect 4 0 5 0;
+#X connect 5 0 0 0;
+#X restore 49 34 pd interp;
+#X msg 306 235 embed 1;
+#X msg 332 355 dump;
+#X connect 0 0 33 0;
+#X connect 1 0 3 0;
+#X connect 2 0 33 1;
+#X connect 3 0 33 0;
+#X connect 3 1 2 0;
+#X connect 4 0 33 0;
+#X connect 5 0 21 0;
+#X connect 6 0 33 0;
+#X connect 7 0 6 0;
+#X connect 8 0 5 0;
+#X connect 8 1 21 1;
+#X connect 9 0 8 0;
+#X connect 10 0 8 0;
+#X connect 11 0 8 0;
+#X connect 12 0 3 0;
+#X connect 13 0 12 0;
+#X connect 14 0 19 0;
+#X connect 15 0 19 0;
+#X connect 16 0 19 0;
+#X connect 17 0 19 0;
+#X connect 18 0 12 0;
+#X connect 19 0 13 0;
+#X connect 19 1 18 0;
+#X connect 20 0 6 0;
+#X connect 21 0 3 0;
+#X connect 22 0 8 0;
+#X connect 23 0 33 0;
+#X connect 24 0 23 0;
+#X connect 25 0 23 0;
+#X connect 26 0 24 0;
+#X connect 26 1 25 0;
+#X connect 27 0 26 0;
+#X connect 28 0 26 0;
+#X connect 29 0 32 0;
+#X connect 30 0 29 0;
+#X connect 31 0 29 0;
+#X connect 32 0 33 0;
+#X connect 33 0 37 0;
+#X connect 33 1 37 1;
+#X connect 33 2 34 0;
+#X connect 35 0 33 0;
+#X connect 36 0 33 0;
+#X connect 37 0 34 0;
+#X connect 38 0 33 0;
+#X connect 39 0 33 0;
+#X connect 40 0 33 0;
+#X connect 41 0 33 0;
+#X connect 42 0 33 0;
+#X connect 43 0 33 0;
+#X connect 44 0 33 0;
+#X connect 45 0 33 0;
+#X connect 46 0 48 0;
+#X connect 46 1 48 1;
+#X connect 46 2 47 0;
+#X connect 48 0 47 0;
+#X connect 49 0 46 0;
+#X connect 50 0 46 0;
+#X connect 51 0 46 0;
+#X connect 53 0 46 0;
+#X connect 53 0 33 0;
+#X connect 54 0 46 0;
diff --git a/test/cyclone/funbuff-test.pd b/test/cyclone/funbuff-test.pd
new file mode 100644
index 0000000..230368e
--- /dev/null
+++ b/test/cyclone/funbuff-test.pd
@@ -0,0 +1,149 @@
+#N canvas 116 34 735 514 12;
+#X msg 49 113 clear;
+#X floatatom 172 181 5 0 0;
+#X obj 212 243 * -1;
+#X obj 172 213 t 0 0;
+#X floatatom 172 147 5 0 0;
+#X obj 279 113 Uzi;
+#X msg 49 181 debug \$1;
+#X msg 71 147 1;
+#X obj 279 71 t 0 0;
+#X msg 224 34 1000;
+#X msg 279 34 10000;
+#X msg 173 34 100;
+#X obj 530 147 counter;
+#X obj 530 113 Uzi;
+#X msg 595 34 100000;
+#X msg 475 34 1000;
+#X msg 530 34 10000;
+#X msg 424 34 100;
+#X msg 578 113 set 0;
+#X obj 530 71 t 0 b;
+#X msg 114 147 2;
+#X obj 279 147 urn;
+#X msg 344 34 100000;
+#X obj 531 306 counter;
+#X obj 531 271 Uzi;
+#X msg 579 271 set 0;
+#X obj 531 235 t 0 b;
+#X msg 531 196 50;
+#X msg 582 196 100;
+#X obj 429 235 Uzi;
+#X msg 429 196 50;
+#X msg 480 196 100;
+#X obj 429 271 urn 100;
+#X obj 49 355 funbuff;
+#C restore;
+#X obj 49 426 print;
+#X msg 60 213 bang;
+#X msg 69 243 dump;
+#X obj 49 389 pack;
+#X msg 126 288 set;
+#X msg 194 288 set 1 2 3;
+#X msg 171 83 goto 15;
+#X msg 171 112 next;
+#X msg 148 426 write test.funbuff;
+#X msg 157 461 read test.funbuff;
+#X msg 184 364 read;
+#X msg 184 393 write;
+#X obj 398 389 funbuff test.funbuff;
+#C restore;
+#X obj 398 461 print;
+#X obj 398 426 pack;
+#X msg 398 355 bang;
+#X msg 456 355 next;
+#X msg 514 355 goto 0;
+#N canvas 478 69 552 396 interp 0;
+#X obj 52 124 funbuff test.funbuff;
+#C restore;
+#X msg 52 85 interp \$1;
+#X floatatom 52 53 5 0 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array t 100 float 1;
+#A 0 0 -0.0285716 -0.0548876 -0.0812036 -0.10752 -0.133836 -0.160152
+-0.186468 -0.212784 -0.2391 -0.265416 -0.291732 -0.318048 -0.344364
+-0.37068 -0.396996 -0.423312 -0.449628 -0.475944 -0.50226 -0.528575
+-0.55429 -0.580004 -0.605719 -0.631433 -0.657148 -0.682863 -0.708577
+-0.734292 -0.760006 -0.785721 -0.811435 -0.83715 -0.862864 -0.888579
+-0.914293 -0.939293 -0.964293 -0.989294 -1.01429 -1.04287 -1.07144
+-1.10001 -1.12382 -1.14763 -1.17144 -1.18572 -1.20001 -1.22858 -1.25715
+-1.28096 -1.30477 -1.32858 -1.35715 -1.40715 -1.45715 -1.40001 -1.38573
+-1.15715 -0.942865 -0.0285715 0.242859 0.343812 0.444765 0.545719 0.646672
+0.747625 0.848578 0.949531 1.05048 1.15144 1.25239 1.35334 1.4543 1.55525
+1.6562 1.77144 1.84922 1.927 2.68574 2.67145 2.65716 2.64288 2.62859
+2.61431 2.6041 2.5939 2.58369 2.57349 2.56329 2.55308 2.54288 2.54288
+2.54696 2.55104 2.55512 2.5592 2.56329 2.56737 2.62859;
+#X coords 0 1 99 -1 200 140 1;
+#X restore 290 173 graph;
+#X floatatom 184 53 5 0 0;
+#X msg 184 85 interptab \$1 t;
+#X floatatom 52 168 0 0 0;
+#X connect 0 0 6 0;
+#X connect 1 0 0 0;
+#X connect 2 0 1 0;
+#X connect 4 0 5 0;
+#X connect 5 0 0 0;
+#X restore 49 34 pd interp;
+#X msg 306 235 embed 1;
+#X msg 332 355 dump;
+#X connect 0 0 33 0;
+#X connect 1 0 3 0;
+#X connect 2 0 33 1;
+#X connect 3 0 33 0;
+#X connect 3 1 2 0;
+#X connect 4 0 33 0;
+#X connect 5 0 21 0;
+#X connect 6 0 33 0;
+#X connect 7 0 6 0;
+#X connect 8 0 5 0;
+#X connect 8 1 21 1;
+#X connect 9 0 8 0;
+#X connect 10 0 8 0;
+#X connect 11 0 8 0;
+#X connect 12 0 3 0;
+#X connect 13 0 12 0;
+#X connect 14 0 19 0;
+#X connect 15 0 19 0;
+#X connect 16 0 19 0;
+#X connect 17 0 19 0;
+#X connect 18 0 12 0;
+#X connect 19 0 13 0;
+#X connect 19 1 18 0;
+#X connect 20 0 6 0;
+#X connect 21 0 3 0;
+#X connect 22 0 8 0;
+#X connect 23 0 33 0;
+#X connect 24 0 23 0;
+#X connect 25 0 23 0;
+#X connect 26 0 24 0;
+#X connect 26 1 25 0;
+#X connect 27 0 26 0;
+#X connect 28 0 26 0;
+#X connect 29 0 32 0;
+#X connect 30 0 29 0;
+#X connect 31 0 29 0;
+#X connect 32 0 33 0;
+#X connect 33 0 37 0;
+#X connect 33 1 37 1;
+#X connect 33 2 34 0;
+#X connect 35 0 33 0;
+#X connect 36 0 33 0;
+#X connect 37 0 34 0;
+#X connect 38 0 33 0;
+#X connect 39 0 33 0;
+#X connect 40 0 33 0;
+#X connect 41 0 33 0;
+#X connect 42 0 33 0;
+#X connect 43 0 33 0;
+#X connect 44 0 33 0;
+#X connect 45 0 33 0;
+#X connect 46 0 48 0;
+#X connect 46 1 48 1;
+#X connect 46 2 47 0;
+#X connect 48 0 47 0;
+#X connect 49 0 46 0;
+#X connect 50 0 46 0;
+#X connect 51 0 46 0;
+#X connect 53 0 46 0;
+#X connect 53 0 33 0;
+#X connect 54 0 46 0;
diff --git a/test/cyclone/funnel-test.pd b/test/cyclone/funnel-test.pd
new file mode 100644
index 0000000..3580e5d
--- /dev/null
+++ b/test/cyclone/funnel-test.pd
@@ -0,0 +1,33 @@
+#N canvas 557 414 450 300 12;
+#X obj 93 108 funnel 5;
+#X obj 93 147 spray 5;
+#X obj 58 200 print a;
+#X obj 174 200 print e;
+#X msg 116 64 bang;
+#X msg 49 64 2 3 4;
+#X msg 172 64 5 6 7;
+#X msg 172 26 -7;
+#X msg 49 26 -4;
+#X obj 245 64 testmess 50;
+#X msg 245 26 11 test;
+#X obj 187 147 print;
+#X obj 283 147 funnel 1 7;
+#X msg 283 108 99;
+#X msg 331 108 list test;
+#X msg 222 108 bang;
+#X connect 0 0 1 0;
+#X connect 0 0 11 0;
+#X connect 1 0 2 0;
+#X connect 1 4 3 0;
+#X connect 4 0 0 0;
+#X connect 4 0 0 4;
+#X connect 5 0 0 0;
+#X connect 6 0 0 4;
+#X connect 7 0 0 4;
+#X connect 8 0 0 0;
+#X connect 9 0 0 4;
+#X connect 10 0 9 0;
+#X connect 12 0 11 0;
+#X connect 13 0 12 0;
+#X connect 14 0 12 0;
+#X connect 15 0 12 0;
diff --git a/test/cyclone/gate-test.pd b/test/cyclone/gate-test.pd
new file mode 100644
index 0000000..80cdb61
--- /dev/null
+++ b/test/cyclone/gate-test.pd
@@ -0,0 +1,48 @@
+#N canvas 250 108 629 425 12;
+#X obj 209 222 switch 11 0 padding;
+#X msg 90 37 bang;
+#X msg 141 37 2;
+#X msg 184 37 symbol three;
+#X msg 264 67 1 2 3 4;
+#X msg 318 94 five is anything;
+#X msg 34 37 bang;
+#X obj 34 67 grab;
+#X floatatom 34 182 5 0 0;
+#X floatatom 54 113 5 0 0;
+#X obj 209 274 route bang float symbol list;
+#X obj 209 314 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 270 310 5 0 0;
+#X symbolatom 332 310 10 0 0;
+#X obj 394 347 print list;
+#X obj 456 310 print anything;
+#X msg 357 123 last is anything too;
+#X obj 227 165 gate 11 0 padding;
+#X connect 0 0 10 0;
+#X connect 1 0 17 1;
+#X connect 2 0 17 1;
+#X connect 3 0 17 1;
+#X connect 4 0 17 1;
+#X connect 5 0 17 1;
+#X connect 6 0 7 0;
+#X connect 7 0 8 0;
+#X connect 7 1 17 0;
+#X connect 9 0 0 0;
+#X connect 9 0 17 0;
+#X connect 10 0 11 0;
+#X connect 10 1 12 0;
+#X connect 10 2 13 0;
+#X connect 10 3 14 0;
+#X connect 10 4 15 0;
+#X connect 16 0 17 1;
+#X connect 17 0 0 1;
+#X connect 17 1 0 2;
+#X connect 17 2 0 3;
+#X connect 17 3 0 4;
+#X connect 17 4 0 5;
+#X connect 17 5 0 6;
+#X connect 17 6 0 7;
+#X connect 17 7 0 8;
+#X connect 17 8 0 9;
+#X connect 17 9 0 10;
+#X connect 17 10 0 11;
diff --git a/test/cyclone/good.coll b/test/cyclone/good.coll
new file mode 100644
index 0000000..fcbd428
--- /dev/null
+++ b/test/cyclone/good.coll
@@ -0,0 +1,4 @@
+11, testing coll;
+12, who is going to do that?;
+13 !, not;
+me 14, and you?;
diff --git a/test/cyclone/grab-test.pd b/test/cyclone/grab-test.pd
new file mode 100644
index 0000000..7d1b31b
--- /dev/null
+++ b/test/cyclone/grab-test.pd
@@ -0,0 +1,42 @@
+#N canvas 402 375 591 368 12;
+#X obj 252 43 r t1;
+#X msg 121 43 set t2;
+#X obj 495 129 r t2;
+#X obj 27 175 print 1st;
+#X obj 103 129 print 2nd;
+#X obj 252 253 print pass1;
+#X obj 292 214 print pass2;
+#X obj 27 89 grab 2 t1;
+#X obj 419 43 r t1;
+#X obj 419 253 print pass3;
+#X floatatom 27 43 5 0 0;
+#X floatatom 286 129 5 0 0;
+#X obj 252 175 t 0 b;
+#X obj 419 175 + 100;
+#X obj 495 175 print t2;
+#X obj 271 83 print t1-a;
+#X obj 445 83 print t1-b;
+#X obj 142 214 grab;
+#X obj 204 294 +;
+#X floatatom 142 293 5 0 0;
+#X msg 142 175 \$1 1;
+#X obj 173 255 grab;
+#X connect 0 0 12 0;
+#X connect 0 0 15 0;
+#X connect 1 0 7 0;
+#X connect 2 0 12 0;
+#X connect 2 0 14 0;
+#X connect 7 0 3 0;
+#X connect 7 1 4 0;
+#X connect 8 0 13 0;
+#X connect 8 0 16 0;
+#X connect 10 0 7 0;
+#X connect 10 0 20 0;
+#X connect 11 0 12 0;
+#X connect 12 0 5 0;
+#X connect 12 1 6 0;
+#X connect 13 0 9 0;
+#X connect 17 0 19 0;
+#X connect 17 1 21 0;
+#X connect 20 0 17 0;
+#X connect 21 1 18 0;
diff --git a/test/cyclone/index-test.pd b/test/cyclone/index-test.pd
new file mode 100644
index 0000000..ea925fd
--- /dev/null
+++ b/test/cyclone/index-test.pd
@@ -0,0 +1,51 @@
+#N canvas 391 378 743 455 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array 0-t 100 float 0;
+#X coords 0 1 99 -1 200 140 1;
+#X restore 279 34 graph;
+#X obj 43 280 index~ t;
+#X obj 43 321 snapshot~;
+#X floatatom 43 359 5 0 0;
+#X floatatom 43 245 5 0 0;
+#X obj 155 280 metro 10;
+#X obj 155 245 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#N canvas 0 0 450 300 graph1 0;
+#X array t 100 float 0;
+#X coords 0 1 99 -1 200 140 1;
+#X restore 37 34 graph;
+#X obj 273 321 snapshot~;
+#X floatatom 273 359 5 0 0;
+#X floatatom 273 245 5 0 0;
+#X obj 385 280 metro 10;
+#X obj 385 245 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 273 280 index~ t 1;
+#N canvas 0 0 450 300 graph1 0;
+#X array 1-t 100 float 0;
+#X coords 0 1 99 -1 200 140 1;
+#X restore 518 34 graph;
+#X msg 121 202 1;
+#X msg 161 202 2;
+#X msg 80 202 0;
+#X msg 324 202 1;
+#X msg 364 202 2;
+#X msg 283 202 0;
+#X msg 408 202 3;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 4 0 1 0;
+#X connect 5 0 2 0;
+#X connect 6 0 5 0;
+#X connect 8 0 9 0;
+#X connect 10 0 13 0;
+#X connect 11 0 8 0;
+#X connect 12 0 11 0;
+#X connect 13 0 8 0;
+#X connect 15 0 1 1;
+#X connect 16 0 1 1;
+#X connect 17 0 1 1;
+#X connect 18 0 13 1;
+#X connect 19 0 13 1;
+#X connect 20 0 13 1;
+#X connect 21 0 13 1;
diff --git a/test/cyclone/kanon.mid b/test/cyclone/kanon.mid
new file mode 100644
index 0000000..a07f5ec
--- /dev/null
+++ b/test/cyclone/kanon.mid
Binary files differ
diff --git a/test/cyclone/kink-test.pd b/test/cyclone/kink-test.pd
new file mode 100644
index 0000000..44bade7
--- /dev/null
+++ b/test/cyclone/kink-test.pd
@@ -0,0 +1,22 @@
+#N canvas 289 161 465 369 12;
+#X obj 31 88 kink~;
+#X floatatom 99 88 0 0 0 0 - - -;
+#X obj 32 156 Scope~ 400 200 256 3 128 -1 1 0 0 0 0 102 255 51 135
+135 135 0;
+#X obj 30 16 phasor~ 3;
+#X obj 30 53 *~ 1;
+#X floatatom 100 53 0 0 0 0 - - -;
+#X obj 242 53 kink~;
+#X floatatom 242 120 5 0 0 0 - - -;
+#X floatatom 242 16 5 0 0 0 - - -;
+#X floatatom 315 16 5 0 0 0 - - -;
+#X obj 242 88 Snapshot~ 10;
+#X connect 0 0 2 0;
+#X connect 1 0 0 1;
+#X connect 3 0 4 0;
+#X connect 4 0 0 0;
+#X connect 5 0 4 1;
+#X connect 6 0 10 0;
+#X connect 8 0 6 0;
+#X connect 9 0 6 1;
+#X connect 10 0 7 0;
diff --git a/test/cyclone/line-test.pd b/test/cyclone/line-test.pd
new file mode 100644
index 0000000..76df2da
--- /dev/null
+++ b/test/cyclone/line-test.pd
@@ -0,0 +1,54 @@
+#N canvas 95 168 608 427 12;
+#X obj 37 222 Line~;
+#N canvas 0 0 450 300 graph1 0;
+#X array t 133000 float 0;
+#X coords 0 1000 132999 -1000 200 140 1;
+#X restore 390 37 graph;
+#X obj 38 303 tabwrite~ t;
+#X obj 37 53 t b b;
+#X obj 37 16 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 106 53 t b b;
+#X obj 106 16 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 296 380 capture~ f;
+#X msg 296 341 clear;
+#X obj 61 380 capture~ f;
+#X msg 231 341 clear;
+#X obj 354 241 Snapshot~ 150;
+#X floatatom 354 279 5 0 0 0 - - -;
+#X obj 77 268 print;
+#X obj 61 341 delay~ 4096 4096;
+#X obj 175 53 t b b;
+#X obj 175 16 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 37 89 0 \, 1000 1000 0 1000 1000 1000;
+#X msg 103 187 0 \, 1000 1;
+#X msg 56 120 0 \, 1000 1 0 640 -1000 0 1000 640 0;
+#X msg 77 152 0 \, 1000 640;
+#X connect 0 0 2 0;
+#X connect 0 0 7 0;
+#X connect 0 0 11 0;
+#X connect 0 0 14 0;
+#X connect 0 1 13 0;
+#X connect 0 1 10 0;
+#X connect 3 0 17 0;
+#X connect 3 1 2 0;
+#X connect 3 1 8 0;
+#X connect 4 0 3 0;
+#X connect 5 0 19 0;
+#X connect 5 1 2 0;
+#X connect 5 1 8 0;
+#X connect 6 0 5 0;
+#X connect 8 0 7 0;
+#X connect 10 0 9 0;
+#X connect 11 0 12 0;
+#X connect 14 0 9 0;
+#X connect 15 0 20 0;
+#X connect 15 1 8 0;
+#X connect 15 1 2 0;
+#X connect 16 0 15 0;
+#X connect 17 0 0 0;
+#X connect 18 0 0 0;
+#X connect 19 0 0 0;
+#X connect 20 0 0 0;
diff --git a/test/cyclone/match-reentrant.pd b/test/cyclone/match-reentrant.pd
new file mode 100644
index 0000000..495cfad
--- /dev/null
+++ b/test/cyclone/match-reentrant.pd
@@ -0,0 +1,20 @@
+#N canvas 496 270 520 430 12;
+#X obj 38 135 t a b;
+#X obj 38 244 print;
+#X obj 38 88 match -1 -2 -3 -4 -5 -6 -7 -8 -9;
+#X msg 38 38 -1 -2 -3 -4 -5 -6 -7 -8 -9;
+#X msg 78 195 set 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17;
+#X obj 228 330 t a b;
+#X msg 268 373 4 5 6;
+#X obj 228 289 match 1 nn 3;
+#X msg 228 244 1 2 3;
+#X connect 0 0 1 0;
+#X connect 0 1 4 0;
+#X connect 2 0 0 0;
+#X connect 3 0 2 0;
+#X connect 4 0 2 0;
+#X connect 5 0 1 0;
+#X connect 5 1 6 0;
+#X connect 6 0 7 0;
+#X connect 7 0 5 0;
+#X connect 8 0 7 0;
diff --git a/test/cyclone/match-test.pd b/test/cyclone/match-test.pd
new file mode 100644
index 0000000..e02a909
--- /dev/null
+++ b/test/cyclone/match-test.pd
@@ -0,0 +1,33 @@
+#N canvas 79 190 867 561 12;
+#X obj 490 63 match;
+#X obj 27 182 match one two nn one;
+#X obj 29 451 match 0 one two nn one 0;
+#X msg 27 26 one two 99 one;
+#X msg 47 63 list one two 99 one;
+#X msg 66 101 one \, two \, and \, one \, two \, or \, one;
+#X msg 82 141 one \, two \, and \, one \, one \, two \, or \, one;
+#X msg 29 308 0 \, one \, two \, and \, one \, 0 \, one \, two \, or
+\, one \, 0;
+#X msg 46 350 0 \, one \, two \, set two three \, three \, set 0 one
+two nn one 0;
+#X msg 61 392 0 \, one \, two \, set two three \, two \, three \, set
+0 one two nn one 0;
+#X msg 490 26 test;
+#X obj 593 63 match test;
+#X msg 593 26 test \, set \, test \, set test;
+#X obj 490 101 print;
+#X obj 27 226 print;
+#X obj 29 494 print;
+#X connect 0 0 13 0;
+#X connect 1 0 14 0;
+#X connect 2 0 15 0;
+#X connect 3 0 1 0;
+#X connect 4 0 1 0;
+#X connect 5 0 1 0;
+#X connect 6 0 1 0;
+#X connect 7 0 2 0;
+#X connect 8 0 2 0;
+#X connect 9 0 2 0;
+#X connect 10 0 0 0;
+#X connect 11 0 13 0;
+#X connect 12 0 11 0;
diff --git a/test/cyclone/maxmin-test.pd b/test/cyclone/maxmin-test.pd
new file mode 100644
index 0000000..278aa8e
--- /dev/null
+++ b/test/cyclone/maxmin-test.pd
@@ -0,0 +1,65 @@
+#N canvas 212 65 529 484 12;
+#X obj 82 209 maximum;
+#X msg 57 54 1 2 3 4 5 4 3 2 1;
+#X floatatom 140 175 5 0 0;
+#X floatatom 140 149 5 0 0;
+#X floatatom 82 251 5 0 0;
+#X msg 21 175 bang;
+#X msg 36 23 1 2 3 4 5 5 4 3 2 1;
+#X msg 292 54 1 2 3 4 5 4 3 2 1;
+#X floatatom 401 175 5 0 0;
+#X floatatom 401 149 5 0 0;
+#X floatatom 316 251 5 0 0;
+#X msg 255 175 bang;
+#X msg 270 23 1 2 3 4 5 4 3 2;
+#X obj 316 209 minimum -1;
+#X msg 82 84 list a b c 4;
+#X msg 316 84 list a 2 c 4;
+#X msg 103 115 1 b c d;
+#X msg 334 115 1 b 3 d;
+#X obj 78 365 Peak;
+#X floatatom 109 330 5 0 0;
+#X floatatom 78 453 5 0 0;
+#X obj 93 426 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 109 399 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
+1;
+#X msg 42 330 bang;
+#X floatatom 109 297 5 0 0;
+#X floatatom 306 330 5 0 0;
+#X floatatom 257 453 5 0 0;
+#X obj 281 426 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 306 399 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
+1;
+#X msg 221 330 bang;
+#X floatatom 308 297 5 0 0;
+#X obj 257 365 Trough;
+#X connect 0 0 4 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 1;
+#X connect 3 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 0;
+#X connect 7 0 13 0;
+#X connect 8 0 13 1;
+#X connect 9 0 13 0;
+#X connect 11 0 13 0;
+#X connect 12 0 13 0;
+#X connect 13 0 10 0;
+#X connect 14 0 0 0;
+#X connect 15 0 13 0;
+#X connect 16 0 0 0;
+#X connect 17 0 13 0;
+#X connect 18 0 20 0;
+#X connect 18 1 21 0;
+#X connect 18 2 22 0;
+#X connect 19 0 18 1;
+#X connect 23 0 18 0;
+#X connect 24 0 18 0;
+#X connect 25 0 31 1;
+#X connect 29 0 31 0;
+#X connect 30 0 31 0;
+#X connect 31 0 26 0;
+#X connect 31 1 27 0;
+#X connect 31 2 28 0;
diff --git a/test/cyclone/mean-test.pd b/test/cyclone/mean-test.pd
new file mode 100644
index 0000000..29fb8a6
--- /dev/null
+++ b/test/cyclone/mean-test.pd
@@ -0,0 +1,16 @@
+#N canvas 368 260 327 204 12;
+#X obj 84 84 mean;
+#X msg 141 34 1 2 3 4;
+#X msg 233 34 99;
+#X floatatom 84 123 5 0 0;
+#X floatatom 156 123 5 0 0;
+#X msg 21 34 clear;
+#X msg 84 34 bang;
+#X floatatom 233 64 5 0 0;
+#X connect 0 0 3 0;
+#X connect 0 1 4 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 0;
+#X connect 7 0 0 0;
diff --git a/test/cyclone/midi-test.pd b/test/cyclone/midi-test.pd
new file mode 100644
index 0000000..8846f70
--- /dev/null
+++ b/test/cyclone/midi-test.pd
@@ -0,0 +1,33 @@
+#N canvas 236 201 400 408 12;
+#X obj 207 181 flush;
+#X msg 46 29 bang;
+#X obj 207 76 midiparse;
+#X obj 207 29 midiin;
+#X obj 207 283 midiformat;
+#X obj 207 234 pack;
+#X obj 207 336 midiout;
+#X obj 46 181 midiflush;
+#X obj 46 128 spigot;
+#X obj 207 128 spigot;
+#X obj 134 25 tgl 25 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X obj 134 76 == 0;
+#X floatatom 46 222 5 0 0;
+#X floatatom 294 336 5 0 0;
+#X connect 0 0 5 0;
+#X connect 0 1 5 1;
+#X connect 1 0 9 0;
+#X connect 1 0 8 0;
+#X connect 2 0 9 0;
+#X connect 3 0 8 0;
+#X connect 3 0 2 0;
+#X connect 4 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 4 0;
+#X connect 7 0 6 0;
+#X connect 7 0 12 0;
+#X connect 8 0 7 0;
+#X connect 9 0 0 0;
+#X connect 10 0 8 1;
+#X connect 10 0 11 0;
+#X connect 11 0 9 1;
diff --git a/test/cyclone/midiparse-test.pd b/test/cyclone/midiparse-test.pd
new file mode 100644
index 0000000..b006c94
--- /dev/null
+++ b/test/cyclone/midiparse-test.pd
@@ -0,0 +1,28 @@
+#N canvas 445 218 450 300 12;
+#X obj 124 189 midiparse;
+#X obj 124 225 funnel 7;
+#X obj 124 262 print;
+#X msg 124 18 145 \, 0 \, 64;
+#X msg 137 44 145 \, 1 \, 0;
+#X floatatom 39 18 5 0 0;
+#X msg 152 71 128 \, 2 \, 0;
+#X msg 44 148 bang;
+#X msg 42 71 1 2 3;
+#X msg 207 103 248;
+#X msg 160 103 240;
+#X connect 0 0 1 0;
+#X connect 0 1 1 1;
+#X connect 0 2 1 2;
+#X connect 0 3 1 3;
+#X connect 0 4 1 4;
+#X connect 0 5 1 5;
+#X connect 0 6 1 6;
+#X connect 1 0 2 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 0;
+#X connect 7 0 0 0;
+#X connect 8 0 0 0;
+#X connect 9 0 0 0;
+#X connect 10 0 0 0;
diff --git a/test/cyclone/mousefilter-test.pd b/test/cyclone/mousefilter-test.pd
new file mode 100644
index 0000000..084086f
--- /dev/null
+++ b/test/cyclone/mousefilter-test.pd
@@ -0,0 +1,28 @@
+#N canvas 199 54 444 300 12;
+#X obj 50 198 mousefilter;
+#X floatatom 50 158 5 0 0;
+#X obj 50 239 print;
+#X obj 50 38 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 50 116 random 1000;
+#X obj 214 198 mousefilter;
+#X floatatom 214 158 5 0 0;
+#X obj 214 239 print;
+#X obj 214 38 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 214 116 random 1000;
+#X obj 50 74 metro 500;
+#X obj 214 74 metro 500;
+#X obj 341 26 vsl 15 128 0 127 0 0 empty empty empty 0 -8 0 8 -262144
+-1 -1 6800 0;
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 3 0 10 0;
+#X connect 4 0 1 0;
+#X connect 5 0 7 0;
+#X connect 6 0 5 0;
+#X connect 8 0 11 0;
+#X connect 9 0 6 0;
+#X connect 10 0 4 0;
+#X connect 11 0 9 0;
+#X connect 12 0 5 0;
diff --git a/test/cyclone/next-test.pd b/test/cyclone/next-test.pd
new file mode 100644
index 0000000..50d78d1
--- /dev/null
+++ b/test/cyclone/next-test.pd
@@ -0,0 +1,16 @@
+#N canvas 225 213 485 258 12;
+#X obj 91 143 next;
+#X msg 91 26 bang \, bang;
+#X msg 118 78 bang;
+#X obj 236 105 delay 0;
+#X msg 236 55 bang;
+#X obj 122 177 print same;
+#X obj 91 208 print new;
+#X text 286 49 this fails without geteventno;
+#X connect 0 0 6 0;
+#X connect 0 1 5 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 3 0;
+#X connect 4 0 0 0;
diff --git a/test/cyclone/offer-test.pd b/test/cyclone/offer-test.pd
new file mode 100644
index 0000000..537a3b9
--- /dev/null
+++ b/test/cyclone/offer-test.pd
@@ -0,0 +1,76 @@
+#N canvas 299 297 735 363 12;
+#X obj 49 244 offer;
+#X floatatom 49 279 5 0 0;
+#X msg 50 114 clear;
+#X floatatom 172 181 5 0 0;
+#X obj 212 244 * -1;
+#X obj 172 209 t 0 0;
+#X floatatom 172 147 5 0 0;
+#X obj 279 110 Uzi;
+#X msg 49 181 debug \$1;
+#X msg 71 147 1;
+#X obj 279 71 t 0 0;
+#X msg 224 31 1000;
+#X msg 279 31 10000;
+#X msg 173 31 100;
+#X obj 530 147 counter;
+#X obj 530 110 Uzi;
+#X msg 595 31 100000;
+#X msg 475 31 1000;
+#X msg 530 31 10000;
+#X msg 424 31 100;
+#X msg 578 110 set 0;
+#X obj 530 71 t 0 b;
+#X msg 114 147 2;
+#X obj 279 147 urn;
+#X msg 344 31 100000;
+#X obj 531 306 counter;
+#X obj 531 271 Uzi;
+#X msg 579 271 set 0;
+#X obj 531 234 t 0 b;
+#X msg 531 196 50;
+#X msg 582 196 100;
+#X obj 429 234 Uzi;
+#X msg 429 196 50;
+#X msg 480 196 100;
+#X obj 429 271 urn 100;
+#X msg 117 209 1.5;
+#X connect 0 0 1 0;
+#X connect 2 0 0 0;
+#X connect 3 0 5 0;
+#X connect 4 0 0 1;
+#X connect 5 0 0 0;
+#X connect 5 1 4 0;
+#X connect 6 0 0 0;
+#X connect 7 0 23 0;
+#X connect 8 0 0 0;
+#X connect 9 0 8 0;
+#X connect 10 0 7 0;
+#X connect 10 1 23 1;
+#X connect 11 0 10 0;
+#X connect 12 0 10 0;
+#X connect 13 0 10 0;
+#X connect 14 0 5 0;
+#X connect 15 0 14 0;
+#X connect 16 0 21 0;
+#X connect 17 0 21 0;
+#X connect 18 0 21 0;
+#X connect 19 0 21 0;
+#X connect 20 0 14 0;
+#X connect 21 0 15 0;
+#X connect 21 1 20 0;
+#X connect 22 0 8 0;
+#X connect 23 0 5 0;
+#X connect 24 0 10 0;
+#X connect 25 0 0 0;
+#X connect 26 0 25 0;
+#X connect 27 0 25 0;
+#X connect 28 0 26 0;
+#X connect 28 1 27 0;
+#X connect 29 0 28 0;
+#X connect 30 0 28 0;
+#X connect 31 0 34 0;
+#X connect 32 0 31 0;
+#X connect 33 0 31 0;
+#X connect 34 0 0 0;
+#X connect 35 0 0 0;
diff --git a/test/cyclone/onebang-test.pd b/test/cyclone/onebang-test.pd
new file mode 100644
index 0000000..56f0440
--- /dev/null
+++ b/test/cyclone/onebang-test.pd
@@ -0,0 +1,26 @@
+#N canvas 516 361 450 300 12;
+#X obj 65 144 onebang;
+#X obj 65 89 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 65 200 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 221 89 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 221 200 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 221 144 onebang 1;
+#X obj 123 109 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 297 109 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 297 62 metro 500;
+#X obj 297 24 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 3 0 5 0;
+#X connect 5 0 4 0;
+#X connect 6 0 0 1;
+#X connect 7 0 5 1;
+#X connect 8 0 5 0;
+#X connect 9 0 8 0;
diff --git a/test/cyclone/past-test.pd b/test/cyclone/past-test.pd
new file mode 100644
index 0000000..3c1b1c5
--- /dev/null
+++ b/test/cyclone/past-test.pd
@@ -0,0 +1,38 @@
+#N canvas 280 124 570 391 12;
+#X obj 56 244 print;
+#X floatatom 56 109 5 0 0;
+#X obj 185 244 print;
+#X floatatom 185 109 5 0 0;
+#X obj 185 198 past 1 2 3;
+#X obj 296 244 print;
+#X obj 296 198 past 1 2 3;
+#X msg 317 128 2 3 4;
+#X msg 309 93 1 2 3;
+#X msg 296 53 0 1 2;
+#X msg 121 109 clear;
+#X msg 121 138 set 3;
+#X obj 56 198 past 7;
+#X msg 245 53 0;
+#X msg 121 167 set 7;
+#X msg 402 157 2 0 0 \, 1 2 3;
+#X msg 402 128 0 3 4 \, 1 2 3;
+#X msg 401 93 2 3 0;
+#X msg 461 93 1 1 4;
+#X msg 283 13 set 1 2 3 4 5 6 7 8 9;
+#X connect 1 0 12 0;
+#X connect 3 0 4 0;
+#X connect 4 0 2 0;
+#X connect 6 0 5 0;
+#X connect 7 0 6 0;
+#X connect 8 0 6 0;
+#X connect 9 0 6 0;
+#X connect 10 0 12 0;
+#X connect 11 0 12 0;
+#X connect 12 0 0 0;
+#X connect 13 0 6 0;
+#X connect 14 0 12 0;
+#X connect 15 0 6 0;
+#X connect 16 0 6 0;
+#X connect 17 0 6 0;
+#X connect 18 0 6 0;
+#X connect 19 0 6 0;
diff --git a/test/cyclone/peakamp-test.pd b/test/cyclone/peakamp-test.pd
new file mode 100644
index 0000000..c0c3121
--- /dev/null
+++ b/test/cyclone/peakamp-test.pd
@@ -0,0 +1,25 @@
+#N canvas 354 192 367 254 12;
+#X obj 190 160 peakamp~ 1;
+#X obj 31 82 count~ 0 64 1 1;
+#X obj 31 225 capture~;
+#X msg 190 124 bang;
+#X floatatom 126 225 5 0 0 0 - - -;
+#X obj 190 221 capture 1000;
+#X msg 31 47 min \$1;
+#X floatatom 31 16 5 0 0 0 - - -;
+#X floatatom 161 16 5 0 0 0 - - -;
+#X msg 59 192 open;
+#X obj 59 160 delay 0;
+#X msg 59 124 bang;
+#X connect 0 0 4 0;
+#X connect 0 0 5 0;
+#X connect 1 0 0 0;
+#X connect 1 0 2 0;
+#X connect 3 0 0 0;
+#X connect 6 0 1 0;
+#X connect 7 0 6 0;
+#X connect 8 0 1 1;
+#X connect 9 0 2 0;
+#X connect 9 0 5 0;
+#X connect 10 0 9 0;
+#X connect 11 0 10 0;
diff --git a/test/cyclone/peek-test.pd b/test/cyclone/peek-test.pd
new file mode 100644
index 0000000..ef0db24
--- /dev/null
+++ b/test/cyclone/peek-test.pd
@@ -0,0 +1,51 @@
+#N canvas 326 171 584 586 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array 0-t 20000 float 0;
+#X coords 0 1 19999 -1 200 140 1;
+#X restore 59 17 graph;
+#N canvas 0 0 450 300 graph1 0;
+#X array 1-t 20000 float 0;
+#X coords 0 1 19999 -1 200 140 1;
+#X restore 326 17 graph;
+#X obj 122 511 peek~ t 1;
+#X floatatom 122 548 5 0 0;
+#X msg 286 362 1;
+#X msg 286 394 2;
+#X msg 286 430 3;
+#X msg 286 326 0;
+#X floatatom 390 548 5 0 0;
+#X floatatom 390 438 5 0 0;
+#X floatatom 428 469 5 0 0;
+#X obj 390 511 peek~ 0-t;
+#X floatatom 122 438 5 0 0;
+#X floatatom 160 474 5 0 0;
+#X floatatom 41 253 5 0 0;
+#X obj 41 400 pack 0 0 0;
+#X floatatom 171 362 5 0 0;
+#X obj 41 287 t 0 b;
+#X obj 81 326 random 1000;
+#X obj 41 438 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X msg 41 474 clip \$1;
+#X obj 81 362 / -500;
+#X floatatom 150 400 5 0 0;
+#X connect 2 0 3 0;
+#X connect 4 0 2 2;
+#X connect 5 0 2 2;
+#X connect 6 0 2 2;
+#X connect 7 0 2 2;
+#X connect 9 0 11 0;
+#X connect 10 0 11 1;
+#X connect 11 0 8 0;
+#X connect 12 0 2 0;
+#X connect 13 0 2 1;
+#X connect 14 0 17 0;
+#X connect 15 0 2 0;
+#X connect 16 0 15 2;
+#X connect 17 0 15 0;
+#X connect 17 1 18 0;
+#X connect 18 0 21 0;
+#X connect 19 0 20 0;
+#X connect 20 0 2 0;
+#X connect 21 0 15 1;
+#X connect 21 0 22 0;
diff --git a/test/cyclone/prepend-test.pd b/test/cyclone/prepend-test.pd
new file mode 100644
index 0000000..d43b8c1
--- /dev/null
+++ b/test/cyclone/prepend-test.pd
@@ -0,0 +1,73 @@
+#N canvas 479 230 524 465 12;
+#X obj 25 416 print;
+#X msg 25 298 1 2 3;
+#X msg 102 298 set test;
+#X obj 25 241 print;
+#X msg 25 55 1 2 3;
+#X obj 25 169 t a b;
+#X msg 111 241 4 5 6;
+#X obj 190 206 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 347 55 testmess 1000;
+#X msg 347 19 mess;
+#X msg 101 19 mess;
+#X obj 101 55 testmess 100;
+#X msg 155 128 set changed;
+#X obj 111 169 gate;
+#X obj 111 206 t b b;
+#X obj 25 377 t a b b;
+#X msg 220 416 set mess1;
+#X msg 108 416 set mess2;
+#X msg 285 241 bang;
+#X msg 347 241 99;
+#X obj 285 377 print list;
+#X obj 285 339 route list;
+#X obj 408 377 print;
+#X msg 227 241 mess;
+#X obj 25 128 prepend test;
+#X obj 25 339 prepend test;
+#X msg 398 241 set bang;
+#X msg 400 278 set 0;
+#X obj 285 298 prepend;
+#X obj 101 88 prepend check;
+#X obj 347 88 prepend check;
+#X msg 160 19 set set;
+#X msg 244 19 set check;
+#X msg 348 211 list;
+#X connect 1 0 25 0;
+#X connect 2 0 25 0;
+#X connect 4 0 24 0;
+#X connect 5 0 3 0;
+#X connect 5 1 13 1;
+#X connect 6 0 24 0;
+#X connect 7 0 13 0;
+#X connect 8 0 30 0;
+#X connect 9 0 8 0;
+#X connect 10 0 11 0;
+#X connect 11 0 29 0;
+#X connect 12 0 24 0;
+#X connect 13 0 14 0;
+#X connect 14 0 6 0;
+#X connect 14 1 7 0;
+#X connect 15 0 0 0;
+#X connect 15 1 17 0;
+#X connect 15 2 16 0;
+#X connect 16 0 25 0;
+#X connect 17 0 25 0;
+#X connect 18 0 28 0;
+#X connect 19 0 28 0;
+#X connect 21 0 20 0;
+#X connect 21 1 22 0;
+#X connect 23 0 28 0;
+#X connect 24 0 5 0;
+#X connect 25 0 15 0;
+#X connect 26 0 28 0;
+#X connect 27 0 28 0;
+#X connect 28 0 21 0;
+#X connect 29 0 24 0;
+#X connect 30 0 24 0;
+#X connect 31 0 30 0;
+#X connect 31 0 29 0;
+#X connect 32 0 30 0;
+#X connect 32 0 29 0;
+#X connect 33 0 28 0;
diff --git a/test/cyclone/prob-test.pd b/test/cyclone/prob-test.pd
new file mode 100644
index 0000000..e21a3c5
--- /dev/null
+++ b/test/cyclone/prob-test.pd
@@ -0,0 +1,33 @@
+#N canvas 482 332 476 300 12;
+#X obj 146 119 anal;
+#X obj 146 174 prob;
+#X floatatom 114 221 5 0 0;
+#X obj 213 221 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 146 84 5 0 0;
+#X msg 52 139 dump;
+#X msg 125 48 bang;
+#X floatatom 222 84 5 0 0;
+#X msg 297 84 2 -1 1;
+#X msg 359 119 reset 2;
+#X msg 51 84 embed 1;
+#X msg 221 48 clear;
+#X msg 298 48 -1;
+#X msg 375 84 1 1 1;
+#X msg 344 48 1;
+#X msg 47 14 clear \, 2 -1 1 \, -1 \, bang \, reset 2;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 1 1 3 0;
+#X connect 4 0 0 0;
+#X connect 5 0 1 0;
+#X connect 6 0 1 0;
+#X connect 7 0 1 0;
+#X connect 8 0 1 0;
+#X connect 9 0 1 0;
+#X connect 10 0 1 0;
+#X connect 11 0 1 0;
+#X connect 12 0 1 0;
+#X connect 13 0 1 0;
+#X connect 14 0 1 0;
+#X connect 15 0 1 0;
diff --git a/test/cyclone/pv-test.pd b/test/cyclone/pv-test.pd
new file mode 100644
index 0000000..c1252b5
--- /dev/null
+++ b/test/cyclone/pv-test.pd
@@ -0,0 +1,83 @@
+#N canvas 400 284 560 390 12;
+#X obj 53 112 pv x;
+#X floatatom 53 77 5 0 0;
+#X msg 132 40 bang;
+#X floatatom 132 112 5 0 0;
+#X msg 197 40 status;
+#X msg 29 40 status;
+#X floatatom 57 238 5 0 0;
+#X msg 286 238 bang;
+#X msg 351 238 status;
+#X msg 32 190 status;
+#X obj 286 280 pv common;
+#N canvas 556 81 496 259 sub-a 0;
+#X floatatom 59 88 5 0 0;
+#X msg 317 88 bang;
+#X msg 382 88 status;
+#X msg 35 51 status;
+#X obj 317 123 pv common;
+#X msg 133 88 bang;
+#X floatatom 250 88 5 0 0;
+#X obj 59 161 print private-a;
+#X obj 317 161 print common-a;
+#X obj 59 123 pv private symbol test;
+#X connect 0 0 9 0;
+#X connect 1 0 4 0;
+#X connect 2 0 4 0;
+#X connect 3 0 9 0;
+#X connect 4 0 8 0;
+#X connect 5 0 9 0;
+#X connect 6 0 4 0;
+#X connect 9 0 7 0;
+#X restore 454 280 pd sub-a;
+#X msg 455 64 \; x bang;
+#X obj 455 148 r x;
+#X obj 455 190 print;
+#N canvas 556 81 496 259 sub-b 0;
+#X floatatom 91 87 5 0 0;
+#X msg 317 87 bang;
+#X msg 382 87 status;
+#X msg 67 50 status;
+#X obj 317 122 pv common;
+#X msg 165 87 bang;
+#X floatatom 250 87 5 0 0;
+#X obj 91 160 print private-b;
+#X obj 317 160 print common-b;
+#X obj 91 122 pv private 1 2 3;
+#X connect 0 0 9 0;
+#X connect 1 0 4 0;
+#X connect 2 0 4 0;
+#X connect 3 0 9 0;
+#X connect 4 0 8 0;
+#X connect 5 0 9 0;
+#X connect 6 0 4 0;
+#X connect 9 0 7 0;
+#X restore 453 318 pd sub-b;
+#X obj 286 318 print common;
+#X msg 116 190 symbol test;
+#X obj 288 195 testmess 100;
+#X msg 288 159 bang;
+#X msg 344 159 test;
+#X msg 288 88 bang;
+#X msg 344 88 test;
+#X obj 288 124 testmess 300;
+#X obj 57 280 pv common test message;
+#X obj 132 77 pv x 99;
+#X connect 1 0 0 0;
+#X connect 2 0 25 0;
+#X connect 4 0 25 0;
+#X connect 5 0 0 0;
+#X connect 6 0 24 0;
+#X connect 7 0 10 0;
+#X connect 8 0 10 0;
+#X connect 9 0 24 0;
+#X connect 10 0 16 0;
+#X connect 13 0 14 0;
+#X connect 17 0 24 0;
+#X connect 18 0 24 0;
+#X connect 19 0 18 0;
+#X connect 20 0 18 0;
+#X connect 21 0 23 0;
+#X connect 22 0 23 0;
+#X connect 23 0 24 0;
+#X connect 25 0 3 0;
diff --git a/test/cyclone/rand-test.pd b/test/cyclone/rand-test.pd
new file mode 100644
index 0000000..2a438d6
--- /dev/null
+++ b/test/cyclone/rand-test.pd
@@ -0,0 +1,37 @@
+#N canvas 224 159 762 415 12;
+#X obj 33 348 tabwrite~ t;
+#N canvas 0 0 450 300 graph1 0;
+#X array t 400 float 0;
+#X coords 0 1 399 -1 400 300 1;
+#X restore 330 44 graph;
+#X obj 35 54 osc~ 10;
+#X obj 35 89 *~ 1000;
+#X floatatom 35 19 5 0 0 0 - - -;
+#X obj 256 174 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X floatatom 114 54 5 0 0 0 - - -;
+#X msg 64 189 \$1 \; pd dsp \$1;
+#X obj 45 244 metro 300;
+#X obj 33 151 rand~ 1000;
+#X floatatom 168 114 5 0 0 0 - - -;
+#X obj 171 315 hsl 128 15 -1 1 0 0 empty empty empty -2 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 168 151 rand~;
+#X obj 64 315 capture~ f;
+#X msg 64 278 clear;
+#X obj 177 204 sel 1;
+#X obj 168 278 Snapshot~ 20;
+#X connect 2 0 3 0;
+#X connect 4 0 2 0;
+#X connect 5 0 7 0;
+#X connect 5 0 15 0;
+#X connect 6 0 3 1;
+#X connect 7 0 8 0;
+#X connect 8 0 0 0;
+#X connect 9 0 0 0;
+#X connect 9 0 13 0;
+#X connect 10 0 12 0;
+#X connect 12 0 16 0;
+#X connect 14 0 13 0;
+#X connect 15 0 14 0;
+#X connect 16 0 11 0;
diff --git a/test/cyclone/record-sync-test.pd b/test/cyclone/record-sync-test.pd
new file mode 100644
index 0000000..368bf06
--- /dev/null
+++ b/test/cyclone/record-sync-test.pd
@@ -0,0 +1,64 @@
+#N canvas 380 162 635 531 12;
+#X obj 56 320 record~ t;
+#N canvas 0 0 450 300 graph1 0;
+#X array t 100000 float 0;
+#X coords 0 1 99999 -1 200 140 1;
+#X restore 46 20 graph;
+#X floatatom 77 241 5 0 0;
+#X floatatom 149 241 5 0 0;
+#X obj 345 279 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1
+1;
+#X obj 56 437 threshold~ 0;
+#X obj 56 401 -~;
+#X obj 56 365 delay~ 1 1;
+#N canvas 0 0 450 300 graph1 0;
+#X array sync 100000 float 0;
+#X coords 0 1 99999 -1 200 140 1;
+#X restore 299 20 graph;
+#X floatatom 400 324 5 0 0;
+#X floatatom 400 246 5 0 0;
+#X msg 56 205 loop \$1;
+#X msg 161 205 append \$1;
+#X obj 56 179 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 1
+;
+#X obj 161 179 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0
+1;
+#X obj 56 476 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 149 279 / 44.1;
+#X obj 77 279 / 44.1;
+#X obj 345 365 record~ sync;
+#X obj 400 286 tabread sync;
+#X msg 303 189 \; sync const 0;
+#X obj 240 437 snapshot~;
+#X obj 240 401 metro 10;
+#X floatatom 240 476 5 0 0;
+#X obj 240 369 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 1
+1;
+#X obj 345 437 snapshot~;
+#X floatatom 345 476 5 0 0;
+#X connect 0 0 6 1;
+#X connect 0 0 7 0;
+#X connect 0 0 18 0;
+#X connect 0 0 21 0;
+#X connect 2 0 17 0;
+#X connect 3 0 16 0;
+#X connect 4 0 0 0;
+#X connect 4 0 18 0;
+#X connect 5 0 15 0;
+#X connect 6 0 5 0;
+#X connect 7 0 6 0;
+#X connect 10 0 19 0;
+#X connect 11 0 0 0;
+#X connect 12 0 0 0;
+#X connect 13 0 11 0;
+#X connect 14 0 12 0;
+#X connect 16 0 0 2;
+#X connect 17 0 0 1;
+#X connect 18 0 25 0;
+#X connect 19 0 9 0;
+#X connect 21 0 23 0;
+#X connect 22 0 21 0;
+#X connect 22 0 25 0;
+#X connect 24 0 22 0;
+#X connect 25 0 26 0;
diff --git a/test/cyclone/record-test.pd b/test/cyclone/record-test.pd
new file mode 100644
index 0000000..8896aec
--- /dev/null
+++ b/test/cyclone/record-test.pd
@@ -0,0 +1,60 @@
+#N canvas 106 146 768 968 12;
+#X obj 254 110 record~ bulk 8;
+#X obj 53 36 osc~ 1;
+#X obj 124 36 osc~ 2;
+#X obj 193 36 osc~ 3;
+#X obj 263 36 osc~ 4;
+#X obj 335 36 osc~ 5;
+#X obj 403 36 osc~ 6;
+#X obj 479 36 osc~ 7;
+#X obj 549 36 osc~ 8;
+#X obj 154 95 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#N canvas 0 0 450 300 graph65 0;
+#X array 0-bulk 10000 float 0;
+#X coords 0 1 9999 -1 600 60 1;
+#X restore 84 192 graph;
+#N canvas 0 0 450 300 graph65 0;
+#X array 1-bulk 10000 float 0;
+#X coords 0 1 9999 -1 600 60 1;
+#X restore 84 269 graph;
+#N canvas 0 0 450 300 graph65 0;
+#X array 2-bulk 10000 float 0;
+#X coords 0 1 9999 -1 600 60 1;
+#X restore 83 345 graph;
+#N canvas 0 0 450 300 graph65 0;
+#X array 3-bulk 10000 float 0;
+#X coords 0 1 9999 -1 600 60 1;
+#X restore 83 422 graph;
+#N canvas 0 0 450 300 graph65 0;
+#X array 4-bulk 10000 float 0;
+#X coords 0 1 9999 -1 600 60 1;
+#X restore 83 501 graph;
+#N canvas 0 0 450 300 graph65 0;
+#X array 5-bulk 10000 float 0;
+#X coords 0 1 9999 -1 600 60 1;
+#X restore 83 578 graph;
+#N canvas 0 0 450 300 graph65 0;
+#X array 6-bulk 10000 float 0;
+#X coords 0 1 9999 -1 600 60 1;
+#X restore 82 654 graph;
+#N canvas 0 0 450 300 graph65 0;
+#X array 7-bulk 10000 float 0;
+#X coords 0 1 9999 -1 600 60 1;
+#X restore 82 731 graph;
+#X obj 254 146 record~ sync;
+#N canvas 0 0 450 300 graph65 0;
+#X array sync 10000 float 0;
+#X coords 0 1 9999 -1 600 60 1;
+#X restore 80 839 graph;
+#X connect 0 0 18 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 1;
+#X connect 3 0 0 2;
+#X connect 4 0 0 3;
+#X connect 5 0 0 4;
+#X connect 6 0 0 5;
+#X connect 7 0 0 6;
+#X connect 8 0 0 7;
+#X connect 9 0 0 0;
+#X connect 9 0 18 0;
diff --git a/test/cyclone/scope-gop.pd b/test/cyclone/scope-gop.pd
new file mode 100644
index 0000000..a5980d0
--- /dev/null
+++ b/test/cyclone/scope-gop.pd
@@ -0,0 +1,2 @@
+#N canvas 315 186 464 344 12;
+#X obj 186 108 scope-test;
diff --git a/test/cyclone/scope-test.pd b/test/cyclone/scope-test.pd
new file mode 100644
index 0000000..8a69d6b
--- /dev/null
+++ b/test/cyclone/scope-test.pd
@@ -0,0 +1,125 @@
+#N canvas 188 168 778 363 12;
+#X obj 19 207 Scope~ 130 130 150 3 200 -1 1 100 0 0 0 50 255 0 202
+32 49 0;
+#X floatatom 18 18 5 0 0 0 - - -;
+#X floatatom 132 18 5 0 0 0 - - -;
+#X obj 18 73 *~;
+#X msg 100 161 bufsize \$1;
+#X floatatom 100 135 5 0 0 0 - - -;
+#X floatatom 247 80 5 0 0 0 - - -;
+#X floatatom 276 106 5 0 0 0 - - -;
+#X floatatom 305 130 5 0 0 0 - - -;
+#X floatatom 36 136 5 0 0 0 - - -;
+#X floatatom 364 80 5 0 0 0 - - -;
+#X floatatom 393 106 5 0 0 0 - - -;
+#X floatatom 422 130 5 0 0 0 - - -;
+#N canvas 0 0 262 195 frgb 0;
+#X obj 17 25 inlet;
+#X obj 94 25 inlet;
+#X obj 173 25 inlet;
+#X obj 17 148 outlet;
+#X obj 17 56 bondo 3;
+#X obj 17 86 pack 0 0 0;
+#X msg 17 116 frgb \$1 \$2 \$3;
+#X connect 0 0 4 0;
+#X connect 1 0 4 1;
+#X connect 2 0 4 2;
+#X connect 4 0 5 0;
+#X connect 4 1 5 1;
+#X connect 4 2 5 2;
+#X connect 5 0 6 0;
+#X connect 6 0 3 0;
+#X restore 247 161 pd frgb;
+#N canvas 0 0 250 195 brgb 0;
+#X obj 17 25 inlet;
+#X obj 94 25 inlet;
+#X obj 173 25 inlet;
+#X obj 17 148 outlet;
+#X msg 17 116 brgb \$1 \$2 \$3;
+#X obj 17 56 bondo 3;
+#X obj 17 86 pack 0 0 0;
+#X connect 0 0 5 0;
+#X connect 1 0 5 1;
+#X connect 2 0 5 2;
+#X connect 4 0 3 0;
+#X connect 5 0 6 0;
+#X connect 5 1 6 1;
+#X connect 5 2 6 2;
+#X connect 6 0 4 0;
+#X restore 364 161 pd brgb;
+#X obj 18 44 osc~ 5;
+#X obj 132 44 osc~ 11;
+#X floatatom 100 80 5 0 0 0 - - -;
+#X floatatom 167 80 5 0 0 0 - - -;
+#N canvas 0 0 262 195 range 0;
+#X obj 17 25 inlet;
+#X obj 94 25 inlet;
+#X obj 17 145 outlet;
+#X msg 17 115 range \$1 \$2;
+#X obj 17 85 pack;
+#X obj 17 55 bondo;
+#X connect 0 0 5 0;
+#X connect 1 0 5 1;
+#X connect 3 0 2 0;
+#X connect 4 0 3 0;
+#X connect 5 0 4 0;
+#X connect 5 1 4 1;
+#X restore 100 106 pd range;
+#X floatatom 240 18 5 0 0 0 - - -;
+#X msg 240 44 delay \$1;
+#X floatatom 171 207 5 0 0 0 - - -;
+#X obj 171 233 osc~ 5;
+#X obj 243 207 Scope~ 130 130 256 3 128 -1 1 0 0 0 0 102 255 51 135
+135 135 0;
+#X floatatom 73 18 5 0 0 0 - - -;
+#X floatatom 386 207 5 0 0 0 - - -;
+#X obj 386 233 osc~ 5;
+#X floatatom 441 207 5 0 0 0 - - -;
+#X floatatom 512 18 5 0 0 0 - - -;
+#X obj 512 44 pack;
+#X floatatom 575 18 5 0 0 0 - - -;
+#X msg 512 73 triglevel \$1 \, trigger \$2;
+#X obj 512 207 Scope~ 130 130 256 3 128 -1 1 300 0 1 0 253 86 245 17
+40 152 0;
+#X floatatom 655 136 5 0 0 0 - - -;
+#X floatatom 731 136 5 0 0 0 - - -;
+#X floatatom 530 136 5 0 0 0 - - -;
+#X msg 530 162 delay \$1;
+#X obj 655 162 osc~ 1.35;
+#X connect 1 0 15 0;
+#X connect 2 0 16 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 4 0;
+#X connect 6 0 13 0;
+#X connect 7 0 13 1;
+#X connect 8 0 13 2;
+#X connect 9 0 0 0;
+#X connect 10 0 14 0;
+#X connect 11 0 14 1;
+#X connect 12 0 14 2;
+#X connect 13 0 0 0;
+#X connect 14 0 0 0;
+#X connect 15 0 3 0;
+#X connect 16 0 3 1;
+#X connect 17 0 19 0;
+#X connect 18 0 19 1;
+#X connect 19 0 0 0;
+#X connect 20 0 21 0;
+#X connect 21 0 0 0;
+#X connect 22 0 23 0;
+#X connect 23 0 24 0;
+#X connect 25 0 15 1;
+#X connect 26 0 27 0;
+#X connect 27 0 24 1;
+#X connect 28 0 27 1;
+#X connect 29 0 30 0;
+#X connect 30 0 32 0;
+#X connect 31 0 30 1;
+#X connect 32 0 33 0;
+#X connect 34 0 38 0;
+#X connect 35 0 38 1;
+#X connect 36 0 37 0;
+#X connect 37 0 33 0;
+#X connect 38 0 33 0;
+#X coords 0 0 1 1 200 140 1;
diff --git a/test/cyclone/scope-test1.pd b/test/cyclone/scope-test1.pd
new file mode 100644
index 0000000..60af46d
--- /dev/null
+++ b/test/cyclone/scope-test1.pd
@@ -0,0 +1,28 @@
+#N canvas 236 201 450 300 12;
+#X obj 17 27 osc~ 440;
+#X obj 15 250 dac~;
+#X obj 16 190 *~ 0.1;
+#X obj 177 135 Scope~ 252 152 10 3 100 -1 1 0 0 0 0 102 255 51 135
+135 135 0;
+#X floatatom 177 96 5 0 0 0 - - -;
+#X msg 270 96 bufsize \$1;
+#X floatatom 270 60 5 0 0 0 - - -;
+#X msg 177 21 10;
+#X msg 270 21 100;
+#X obj 38 96 triangle~;
+#X obj 17 141 *~;
+#X floatatom 107 27 5 0 0 0 - - -;
+#X obj 38 60 phasor~ 4;
+#X connect 0 0 10 0;
+#X connect 2 0 1 0;
+#X connect 2 0 1 1;
+#X connect 4 0 3 0;
+#X connect 5 0 3 0;
+#X connect 6 0 5 0;
+#X connect 7 0 4 0;
+#X connect 8 0 6 0;
+#X connect 9 0 10 1;
+#X connect 10 0 2 0;
+#X connect 10 0 3 0;
+#X connect 11 0 12 0;
+#X connect 12 0 9 0;
diff --git a/test/cyclone/scope-test2.pd b/test/cyclone/scope-test2.pd
new file mode 100644
index 0000000..47ad604
--- /dev/null
+++ b/test/cyclone/scope-test2.pd
@@ -0,0 +1,31 @@
+#N canvas 495 177 450 300 12;
+#X obj 15 250 dac~;
+#X obj 16 190 *~ 0.1;
+#X obj 177 135 Scope~ 252 152 30 3 250 -1 1 0 0 0 0 102 255 51 135
+135 135 0;
+#X floatatom 177 96 5 0 0 0 - - -;
+#X msg 270 96 bufsize \$1;
+#X floatatom 270 60 5 0 0 0 - - -;
+#X obj 38 96 triangle~;
+#X obj 17 141 *~;
+#X floatatom 107 27 5 0 0 0 - - -;
+#X obj 17 27 osc~ 110;
+#X obj 38 60 phasor~ 111;
+#X msg 177 21 30;
+#X msg 270 21 250;
+#X msg 195 60 4;
+#X connect 1 0 0 0;
+#X connect 1 0 0 1;
+#X connect 3 0 2 0;
+#X connect 4 0 2 0;
+#X connect 5 0 4 0;
+#X connect 6 0 7 1;
+#X connect 6 0 2 1;
+#X connect 7 0 1 0;
+#X connect 7 0 2 0;
+#X connect 8 0 10 0;
+#X connect 9 0 7 0;
+#X connect 10 0 6 0;
+#X connect 11 0 3 0;
+#X connect 12 0 5 0;
+#X connect 13 0 3 0;
diff --git a/test/cyclone/seq-test.pd b/test/cyclone/seq-test.pd
new file mode 100644
index 0000000..baa645d
--- /dev/null
+++ b/test/cyclone/seq-test.pd
@@ -0,0 +1,58 @@
+#N canvas 349 176 601 359 12;
+#X obj 125 191 seq;
+#X msg 61 249 print;
+#X floatatom 63 83 5 0 0 0 - - -;
+#X msg 160 74 record;
+#X msg 144 48 stop;
+#X msg 217 180 read nosuchfile;
+#X obj 125 249 print;
+#X obj 125 24 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 217 206 write;
+#X msg 379 215 write;
+#X msg 168 102 144;
+#X msg 217 102 240;
+#X obj 61 147 midiin;
+#X obj 379 249 seq test.seq;
+#X obj 242 319 midiout;
+#X msg 217 128 read test.seq;
+#X msg 445 215 start \$1;
+#X msg 445 147 512;
+#X floatatom 445 183 5 0 0 0 - - -;
+#X msg 379 147 stop;
+#X msg 217 232 write test.seq;
+#X obj 242 293 midiflush;
+#X msg 189 293 bang;
+#X msg 264 102 read kanon.mid;
+#X msg 231 74 append;
+#X msg 217 258 write test.mid;
+#X msg 217 154 read test.mid;
+#X connect 0 0 6 0;
+#X connect 0 0 21 0;
+#X connect 0 1 6 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 4 0 22 0;
+#X connect 5 0 0 0;
+#X connect 7 0 0 0;
+#X connect 8 0 0 0;
+#X connect 9 0 13 0;
+#X connect 10 0 0 0;
+#X connect 11 0 0 0;
+#X connect 12 0 0 0;
+#X connect 12 0 14 0;
+#X connect 13 0 21 0;
+#X connect 15 0 0 0;
+#X connect 16 0 13 0;
+#X connect 17 0 18 0;
+#X connect 18 0 16 0;
+#X connect 19 0 13 0;
+#X connect 20 0 0 0;
+#X connect 21 0 14 0;
+#X connect 22 0 21 0;
+#X connect 23 0 0 0;
+#X connect 24 0 0 0;
+#X connect 25 0 0 0;
+#X connect 26 0 0 0;
diff --git a/test/cyclone/sigbits-test.pd b/test/cyclone/sigbits-test.pd
new file mode 100644
index 0000000..9fcb65d
--- /dev/null
+++ b/test/cyclone/sigbits-test.pd
@@ -0,0 +1,157 @@
+#N canvas 138 178 832 338 12;
+#X floatatom 208 168 5 0 0 0 - - -;
+#X floatatom 266 155 5 0 0 0 - - -;
+#X obj 208 250 Snapshot~ 50;
+#X floatatom 208 290 0 0 0 0 - - -;
+#X msg 332 168 mode \$1;
+#X floatatom 332 134 5 0 0 0 - - -;
+#X obj 62 207 bitand~;
+#X floatatom 62 168 5 0 0 0 - - -;
+#X obj 62 250 Snapshot~ 50;
+#X floatatom 62 290 0 0 0 0 - - -;
+#X msg 126 168 mode \$1;
+#X floatatom 126 134 5 0 0 0 - - -;
+#X obj 62 104 prepend bits;
+#X obj 62 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 83 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 103 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 123 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 143 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 163 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 183 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 203 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 223 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 243 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 263 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 283 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 303 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 323 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 343 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 363 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 385 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 405 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 425 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 445 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 465 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 485 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 505 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 525 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 545 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 565 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 585 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 605 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 625 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 645 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 665 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 685 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 62 57 pack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0;
+#X obj 26 57 int;
+#X obj 26 29 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 419 168 5 0 0 0 - - -;
+#X obj 419 250 Snapshot~ 50;
+#X floatatom 419 290 0 0 0 0 - - -;
+#X msg 489 168 mode \$1;
+#X floatatom 489 134 5 0 0 0 - - -;
+#X obj 419 214 bitnot~;
+#X obj 208 214 bitxor~;
+#X floatatom 577 168 5 0 0 0 - - -;
+#X obj 577 250 Snapshot~ 50;
+#X floatatom 577 290 0 0 0 0 - - -;
+#X msg 647 168 mode \$1;
+#X floatatom 647 134 5 0 0 0 - - -;
+#X msg 683 214 shift \$1;
+#X obj 577 214 bitshift~;
+#X floatatom 731 168 5 0 0 0 - - -;
+#X connect 0 0 54 0;
+#X connect 1 0 54 1;
+#X connect 2 0 3 0;
+#X connect 4 0 54 0;
+#X connect 5 0 4 0;
+#X connect 6 0 8 0;
+#X connect 7 0 6 0;
+#X connect 8 0 9 0;
+#X connect 10 0 6 0;
+#X connect 11 0 10 0;
+#X connect 12 0 6 0;
+#X connect 13 0 46 1;
+#X connect 14 0 45 1;
+#X connect 15 0 45 2;
+#X connect 16 0 45 3;
+#X connect 17 0 45 4;
+#X connect 18 0 45 5;
+#X connect 19 0 45 6;
+#X connect 20 0 45 7;
+#X connect 21 0 45 8;
+#X connect 22 0 45 9;
+#X connect 23 0 45 10;
+#X connect 24 0 45 11;
+#X connect 25 0 45 12;
+#X connect 26 0 45 13;
+#X connect 27 0 45 14;
+#X connect 28 0 45 15;
+#X connect 29 0 45 16;
+#X connect 30 0 45 17;
+#X connect 31 0 45 18;
+#X connect 32 0 45 19;
+#X connect 33 0 45 20;
+#X connect 34 0 45 21;
+#X connect 35 0 45 22;
+#X connect 36 0 45 23;
+#X connect 37 0 45 24;
+#X connect 38 0 45 25;
+#X connect 39 0 45 26;
+#X connect 40 0 45 27;
+#X connect 41 0 45 28;
+#X connect 42 0 45 29;
+#X connect 43 0 45 30;
+#X connect 44 0 45 31;
+#X connect 45 0 12 0;
+#X connect 46 0 45 0;
+#X connect 47 0 46 0;
+#X connect 48 0 53 0;
+#X connect 49 0 50 0;
+#X connect 51 0 53 0;
+#X connect 52 0 51 0;
+#X connect 53 0 49 0;
+#X connect 54 0 2 0;
+#X connect 55 0 61 0;
+#X connect 56 0 57 0;
+#X connect 58 0 61 0;
+#X connect 59 0 58 0;
+#X connect 60 0 61 0;
+#X connect 61 0 56 0;
+#X connect 62 0 60 0;
diff --git a/test/cyclone/sigcapture-test.pd b/test/cyclone/sigcapture-test.pd
new file mode 100644
index 0000000..2225e61
--- /dev/null
+++ b/test/cyclone/sigcapture-test.pd
@@ -0,0 +1,25 @@
+#N canvas 249 232 527 300 12;
+#X obj 200 34 phasor~ 1;
+#X floatatom 45 34 5 0 0 0 - - -;
+#X msg 306 34 clear;
+#X msg 306 69 write;
+#X obj 199 107 capture~ 1000 7;
+#X obj 47 215 *~ 100;
+#X obj 47 256 capture~ 1000 0;
+#X obj 47 174 osc~ 100;
+#X msg 76 69 clear;
+#X obj 45 107 capture~ f;
+#X obj 225 215 count~;
+#X obj 225 174 bang~;
+#X obj 225 256 capture~ 100 0 3 5 7 11 999 13;
+#X obj 328 234 capture~ 1000;
+#X connect 0 0 4 0;
+#X connect 1 0 9 0;
+#X connect 2 0 4 0;
+#X connect 3 0 4 0;
+#X connect 5 0 6 0;
+#X connect 7 0 5 0;
+#X connect 8 0 9 0;
+#X connect 10 0 12 0;
+#X connect 10 0 13 0;
+#X connect 11 0 10 0;
diff --git a/test/cyclone/sigcycle-test.pd b/test/cyclone/sigcycle-test.pd
new file mode 100644
index 0000000..9903487
--- /dev/null
+++ b/test/cyclone/sigcycle-test.pd
@@ -0,0 +1,156 @@
+#N canvas 442 270 466 287 12;
+#N canvas 179 250 728 409 test1 0;
+#X obj 27 146 cycle~;
+#X obj 28 225 Scope~ 301 138 126 3 128 -1 1 0 0 0 0 102 255 51 135
+135 135 0;
+#X obj 368 225 Scope~ 301 138 126 3 128 -1 1 0 0 0 0 102 255 51 135
+135 135 0;
+#X floatatom 239 58 5 0 0 0 - - -;
+#X floatatom 150 146 5 0 0 0 - - -;
+#X msg 233 146 trigger \$1;
+#X obj 233 118 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 76 102 phasor~ 3;
+#X obj 367 146 cycle~ 3;
+#N canvas 0 0 450 300 graph1 0;
+#X array t1 1000 float 0;
+#X coords 0 1 999 -1 200 140 1;
+#X restore 481 34 graph;
+#X msg 137 58 set;
+#X msg 27 58 set t1 \$1;
+#X floatatom 27 23 5 0 0 0 - - -;
+#X connect 0 0 1 0;
+#X connect 3 0 7 0;
+#X connect 3 0 8 0;
+#X connect 4 0 1 0;
+#X connect 4 0 2 0;
+#X connect 5 0 1 0;
+#X connect 5 0 2 0;
+#X connect 6 0 5 0;
+#X connect 7 0 0 1;
+#X connect 8 0 2 0;
+#X connect 10 0 0 0;
+#X connect 10 0 8 0;
+#X connect 11 0 0 0;
+#X connect 11 0 8 0;
+#X connect 12 0 11 0;
+#X restore 42 39 pd test1;
+#N canvas 125 182 742 644 test2 0;
+#X obj 29 255 Scope~ 301 138 72 3 128 -1 1 0 0 0 0 102 255 51 135 135
+135 0;
+#X obj 382 255 Scope~ 301 138 72 3 128 -1 1 0 0 0 0 102 255 51 135
+135 135 0;
+#X floatatom 29 19 5 0 0 0 - - -;
+#X floatatom 152 211 5 0 0 0 - - -;
+#X msg 235 211 trigger \$1;
+#X obj 235 181 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 382 211 cycle~ 3;
+#X obj 29 211 cycle~ 3;
+#X obj 96 143 cycle~ 3;
+#X obj 384 105 cycle~ 3;
+#X obj 383 177 +~ 3;
+#X obj 384 143 *~ 1;
+#X obj 95 177 *~ 1;
+#X floatatom 96 19 5 0 0 0 - - -;
+#X floatatom 168 19 5 0 0 0 - - -;
+#X obj 508 112 *;
+#X obj 508 63 bondo;
+#X obj 548 90 * 6.28;
+#X obj 188 435 Scope~ 301 138 72 3 128 -1 1 0 0 0 0 102 255 51 135
+135 135 0;
+#X obj 30 513 phasor~ 3;
+#X obj 107 435 osc~ 3;
+#X obj 107 474 *~ 1;
+#X obj 30 575 cos~;
+#X obj 30 544 +~;
+#X connect 2 0 10 1;
+#X connect 2 0 7 0;
+#X connect 2 0 19 0;
+#X connect 3 0 0 0;
+#X connect 3 0 1 0;
+#X connect 3 0 18 0;
+#X connect 4 0 0 0;
+#X connect 4 0 1 0;
+#X connect 4 0 18 0;
+#X connect 5 0 4 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 8 0 12 0;
+#X connect 9 0 11 0;
+#X connect 10 0 6 0;
+#X connect 11 0 10 0;
+#X connect 12 0 7 1;
+#X connect 13 0 9 0;
+#X connect 13 0 8 0;
+#X connect 13 0 16 0;
+#X connect 13 0 20 0;
+#X connect 14 0 12 1;
+#X connect 14 0 16 1;
+#X connect 14 0 21 1;
+#X connect 15 0 11 1;
+#X connect 16 0 15 0;
+#X connect 16 1 17 0;
+#X connect 17 0 15 1;
+#X connect 19 0 23 0;
+#X connect 20 0 21 0;
+#X connect 21 0 23 1;
+#X connect 22 0 18 0;
+#X connect 23 0 22 0;
+#X restore 164 39 pd test2;
+#N canvas 180 253 749 421 test3 0;
+#X obj 29 255 Scope~ 301 138 118 3 128 -1 1 0 0 0 0 102 255 51 135
+135 135 0;
+#X obj 382 255 Scope~ 301 138 118 3 128 -1 1 0 0 0 0 102 255 51 135
+135 135 0;
+#X floatatom 29 19 5 0 0 0 - - -;
+#X floatatom 152 211 5 0 0 0 - - -;
+#X msg 235 211 trigger \$1;
+#X obj 235 181 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 382 211 cycle~ 3;
+#X obj 29 211 cycle~ 3;
+#X obj 383 177 +~ 3;
+#X obj 444 140 *~ 1;
+#X obj 95 177 *~ 1;
+#X floatatom 126 20 5 0 0 0 - - -;
+#X obj 508 112 *;
+#X obj 508 63 bondo;
+#X obj 548 90 * 6.28;
+#X obj 47 138 delwrite~ d1;
+#X obj 174 138 delread~ d1;
+#X obj 258 90 delwrite~ d2;
+#X obj 385 90 delread~ d2;
+#X connect 2 0 8 1;
+#X connect 2 0 7 0;
+#X connect 2 0 13 0;
+#X connect 3 0 0 0;
+#X connect 3 0 1 0;
+#X connect 4 0 0 0;
+#X connect 4 0 1 0;
+#X connect 5 0 4 0;
+#X connect 6 0 1 0;
+#X connect 6 0 17 0;
+#X connect 7 0 0 0;
+#X connect 7 0 15 0;
+#X connect 8 0 6 0;
+#X connect 9 0 8 0;
+#X connect 10 0 7 1;
+#X connect 11 0 10 1;
+#X connect 11 0 13 1;
+#X connect 12 0 9 1;
+#X connect 13 0 12 0;
+#X connect 13 1 14 0;
+#X connect 14 0 12 1;
+#X connect 16 0 10 0;
+#X connect 18 0 9 0;
+#X restore 293 39 pd test3;
+#X floatatom 120 99 5 0 0 0 - - -;
+#X floatatom 44 216 0 0 0 0 - - -;
+#X msg 44 99 set;
+#X obj 44 137 cycle~ t2;
+#X obj 44 177 Snapshot~ 20;
+#X connect 3 0 6 1;
+#X connect 5 0 6 0;
+#X connect 6 0 7 0;
+#X connect 7 0 4 0;
diff --git a/test/cyclone/sigmeters-test.pd b/test/cyclone/sigmeters-test.pd
new file mode 100644
index 0000000..edf97e8
--- /dev/null
+++ b/test/cyclone/sigmeters-test.pd
@@ -0,0 +1,45 @@
+#N canvas 296 215 621 370 12;
+#X obj 146 187 minmax~;
+#X floatatom 146 29 5 0 0 0 - - -;
+#X obj 117 29 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 57 29 reset;
+#X obj 204 221 print;
+#X obj 174 71 abs~;
+#X obj 365 92 avg~;
+#X floatatom 365 124 5 0 0 0 - - -;
+#X obj 365 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 287 60 osc~ 1;
+#X obj 365 60 metro 250;
+#X obj 164 255 Snapshot~ 150;
+#X floatatom 164 287 5 0 0 0 - - -;
+#X obj 29 255 Snapshot~ 150;
+#X floatatom 29 287 5 0 0 0 - - -;
+#X obj 174 106 Snapshot~ 150;
+#X floatatom 174 138 5 0 0 0 - - -;
+#X floatatom 287 29 5 0 0 0 - - -;
+#X obj 367 187 osc~ 100;
+#X floatatom 367 257 5 0 0 0 - - -;
+#X obj 367 221 average~ 10000 rms;
+#X msg 459 187 absolute;
+#X connect 0 0 13 0;
+#X connect 0 1 11 0;
+#X connect 0 2 4 0;
+#X connect 0 3 4 0;
+#X connect 1 0 0 0;
+#X connect 1 0 5 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 5 0 15 0;
+#X connect 6 0 7 0;
+#X connect 8 0 10 0;
+#X connect 9 0 6 0;
+#X connect 10 0 6 0;
+#X connect 11 0 12 0;
+#X connect 13 0 14 0;
+#X connect 15 0 16 0;
+#X connect 17 0 9 0;
+#X connect 18 0 20 0;
+#X connect 20 0 19 0;
+#X connect 21 0 20 0;
diff --git a/test/cyclone/sigops-test.pd b/test/cyclone/sigops-test.pd
new file mode 100644
index 0000000..d2eb9a1
--- /dev/null
+++ b/test/cyclone/sigops-test.pd
@@ -0,0 +1,64 @@
+#N canvas 281 205 642 407 12;
+#X obj 25 108 %~;
+#X floatatom 25 181 10 0 0 0 - - -;
+#X floatatom 25 40 5 0 0 0 - - -;
+#X floatatom 96 71 5 0 0 0 - - -;
+#X obj 25 71 * 0.01;
+#X floatatom 277 40 5 0 0 0 - - -;
+#X obj 277 71 +=~;
+#X floatatom 277 144 10 0 0 0 - - -;
+#X msg 337 40 set 999;
+#X msg 222 40 bang;
+#X floatatom 442 144 10 0 0 0 - - -;
+#X floatatom 442 40 5 0 0 0 - - -;
+#X floatatom 513 40 5 0 0 0 - - -;
+#X obj 442 71 !/~;
+#X obj 277 108 Snapshot~ 50;
+#X obj 442 108 Snapshot~ 50;
+#X obj 25 144 Snapshot~ 50;
+#X floatatom 26 340 10 0 0 0 - - -;
+#X floatatom 26 236 10 0 0 0 - - -;
+#X floatatom 152 236 5 0 0 0 - - -;
+#X obj 26 304 Snapshot~ 50;
+#X obj 26 267 log~;
+#X obj 183 108 >~ 10000;
+#X obj 183 144 edge~;
+#X floatatom 234 342 10 0 0 0 - - -;
+#X floatatom 234 238 10 0 0 0 - - -;
+#X floatatom 360 238 5 0 0 0 - - -;
+#X obj 234 306 Snapshot~ 50;
+#X obj 234 269 pow~;
+#X floatatom 439 341 10 0 0 0 - - -;
+#X floatatom 439 237 10 0 0 0 - - -;
+#X floatatom 565 237 5 0 0 0 - - -;
+#X obj 439 305 Snapshot~ 50;
+#X obj 439 268 atan2~;
+#X connect 0 0 16 0;
+#X connect 2 0 4 0;
+#X connect 3 0 0 1;
+#X connect 4 0 0 0;
+#X connect 5 0 6 0;
+#X connect 6 0 14 0;
+#X connect 6 0 22 0;
+#X connect 8 0 6 0;
+#X connect 9 0 6 0;
+#X connect 11 0 13 0;
+#X connect 12 0 13 1;
+#X connect 13 0 15 0;
+#X connect 14 0 7 0;
+#X connect 15 0 10 0;
+#X connect 16 0 1 0;
+#X connect 18 0 21 0;
+#X connect 19 0 21 1;
+#X connect 20 0 17 0;
+#X connect 21 0 20 0;
+#X connect 22 0 23 0;
+#X connect 23 0 6 0;
+#X connect 25 0 28 0;
+#X connect 26 0 28 1;
+#X connect 27 0 24 0;
+#X connect 28 0 27 0;
+#X connect 30 0 33 0;
+#X connect 31 0 33 1;
+#X connect 32 0 29 0;
+#X connect 33 0 32 0;
diff --git a/test/cyclone/sigsmoothers-test.pd b/test/cyclone/sigsmoothers-test.pd
new file mode 100644
index 0000000..803d950
--- /dev/null
+++ b/test/cyclone/sigsmoothers-test.pd
@@ -0,0 +1,34 @@
+#N canvas 304 91 587 409 12;
+#X obj 51 371 cyclone;
+#X obj 51 340 sprintf import ../../../ref/c74help/text/%s.help;
+#X msg 62 281 slide~;
+#X msg 51 253 deltaclip~;
+#X msg 72 309 rampsmooth~;
+#X msg 114 48 1;
+#X msg 65 48 0;
+#X floatatom 65 79 0 0 0 0 - - -;
+#X msg 165 85 ramp \$1;
+#X floatatom 165 48 0 0 0 0 - - -;
+#X obj 27 149 capture~ f;
+#X msg 95 17 clear;
+#X msg 27 17 clear;
+#X obj 65 117 rampsmooth~;
+#X obj 244 148 Scope~ 130 130 256 3 128 0 1 0 0 0 0 102 255 51 135
+135 135 0;
+#X msg 244 117 range 0 1;
+#X connect 1 0 0 0;
+#X connect 2 0 1 0;
+#X connect 3 0 1 0;
+#X connect 4 0 1 0;
+#X connect 5 0 7 0;
+#X connect 6 0 7 0;
+#X connect 7 0 13 0;
+#X connect 8 0 13 0;
+#X connect 9 0 8 0;
+#X connect 11 0 10 0;
+#X connect 11 0 5 0;
+#X connect 12 0 6 0;
+#X connect 12 0 10 0;
+#X connect 13 0 10 0;
+#X connect 13 0 14 0;
+#X connect 15 0 14 0;
diff --git a/test/cyclone/sigtrig-test.pd b/test/cyclone/sigtrig-test.pd
new file mode 100644
index 0000000..01d88e5
--- /dev/null
+++ b/test/cyclone/sigtrig-test.pd
@@ -0,0 +1,80 @@
+#N canvas 210 153 573 323 12;
+#N canvas 0 0 749 559 coords 0;
+#X obj 199 114 cartopol~;
+#X floatatom 199 21 5 0 0 0 - - -;
+#X floatatom 275 58 5 0 0 0 - - -;
+#X floatatom 199 287 0 0 0 0 - - -;
+#X floatatom 275 205 0 0 0 0 - - -;
+#X obj 199 257 snapshot~;
+#X obj 275 175 snapshot~;
+#X obj 66 114 metro 50;
+#X obj 66 84 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 66 458 0 0 0 0 - - -;
+#X floatatom 142 376 0 0 0 0 - - -;
+#X obj 66 428 snapshot~;
+#X obj 66 286 poltocar~;
+#X obj 142 346 snapshot~;
+#X floatatom 571 21 5 0 0 0 - - -;
+#X floatatom 647 58 5 0 0 0 - - -;
+#X floatatom 571 287 0 0 0 0 - - -;
+#X floatatom 647 205 0 0 0 0 - - -;
+#X obj 571 257 snapshot~;
+#X obj 647 175 snapshot~;
+#X obj 438 114 metro 50;
+#X obj 438 84 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 438 458 0 0 0 0 - - -;
+#X floatatom 514 376 0 0 0 0 - - -;
+#X obj 438 428 snapshot~;
+#X obj 514 346 snapshot~;
+#X obj 571 114 poltocar~;
+#X obj 438 286 cartopol~;
+#X obj 346 21 loadbang;
+#X connect 0 0 5 0;
+#X connect 0 0 12 0;
+#X connect 0 1 6 0;
+#X connect 0 1 12 1;
+#X connect 1 0 0 0;
+#X connect 2 0 0 1;
+#X connect 5 0 3 0;
+#X connect 6 0 4 0;
+#X connect 7 0 6 0;
+#X connect 7 0 5 0;
+#X connect 7 0 13 0;
+#X connect 7 0 11 0;
+#X connect 8 0 7 0;
+#X connect 11 0 9 0;
+#X connect 12 0 11 0;
+#X connect 12 1 13 0;
+#X connect 13 0 10 0;
+#X connect 14 0 26 0;
+#X connect 15 0 26 1;
+#X connect 18 0 16 0;
+#X connect 19 0 17 0;
+#X connect 20 0 19 0;
+#X connect 20 0 18 0;
+#X connect 20 0 25 0;
+#X connect 20 0 24 0;
+#X connect 21 0 20 0;
+#X connect 24 0 22 0;
+#X connect 25 0 23 0;
+#X connect 26 0 18 0;
+#X connect 26 0 27 0;
+#X connect 26 1 19 0;
+#X connect 26 1 27 1;
+#X connect 27 0 24 0;
+#X connect 27 1 25 0;
+#X connect 28 0 8 0;
+#X connect 28 0 21 0;
+#X restore 42 41 pd coords;
+#N canvas 135 57 659 466 -lm 0;
+#X obj 31 70 acos~;
+#X obj 30 120 Scope~ 229 132 256 3 128 0 3.15 0 0 0 0 102 255 51 135
+135 135 0;
+#X msg 122 70 range 0 3.15;
+#X obj 31 25 cycle~ 1;
+#X connect 0 0 1 0;
+#X connect 2 0 1 0;
+#X connect 3 0 0 0;
+#X restore 177 41 pd -lm;
diff --git a/test/cyclone/sigwrappers-speed.pd b/test/cyclone/sigwrappers-speed.pd
new file mode 100644
index 0000000..f680971
--- /dev/null
+++ b/test/cyclone/sigwrappers-speed.pd
@@ -0,0 +1,101 @@
+#N canvas 220 91 570 539 12;
+#X obj 65 200 phasewrap~;
+#X msg 20 19 0;
+#X msg 71 19 1;
+#X msg 122 19 2;
+#X floatatom 71 53 5 0 0 0 - - -;
+#X obj 168 200 phasewrap~;
+#X obj 272 200 phasewrap~;
+#X obj 376 200 phasewrap~;
+#X obj 71 229 phasewrap~;
+#X obj 174 229 phasewrap~;
+#X obj 278 229 phasewrap~;
+#X obj 382 229 phasewrap~;
+#X obj 71 261 phasewrap~;
+#X obj 174 261 phasewrap~;
+#X obj 278 261 phasewrap~;
+#X obj 382 261 phasewrap~;
+#X obj 77 291 phasewrap~;
+#X obj 180 291 phasewrap~;
+#X obj 284 291 phasewrap~;
+#X obj 388 291 phasewrap~;
+#X obj 83 323 phasewrap~;
+#X obj 186 323 phasewrap~;
+#X obj 290 323 phasewrap~;
+#X obj 394 323 phasewrap~;
+#X obj 59 354 phasewrap~;
+#X obj 162 354 phasewrap~;
+#X obj 266 354 phasewrap~;
+#X obj 370 354 phasewrap~;
+#X obj 65 383 phasewrap~;
+#X obj 168 383 phasewrap~;
+#X obj 272 383 phasewrap~;
+#X obj 376 383 phasewrap~;
+#X obj 65 415 phasewrap~;
+#X obj 168 415 phasewrap~;
+#X obj 272 415 phasewrap~;
+#X obj 376 415 phasewrap~;
+#X obj 71 445 phasewrap~;
+#X obj 174 445 phasewrap~;
+#X obj 278 445 phasewrap~;
+#X obj 382 445 phasewrap~;
+#X obj 77 477 phasewrap~;
+#X obj 180 477 phasewrap~;
+#X obj 284 477 phasewrap~;
+#X obj 388 477 phasewrap~;
+#X msg 197 124 \$2 \, _algo \$1 \; pd dsp 0 \; pd dsp 1;
+#X obj 197 92 pack;
+#X floatatom 237 19 5 0 0 0 - - -;
+#X obj 164 19 inlet;
+#X obj 305 19 inlet;
+#X obj 197 58 bondo;
+#X connect 1 0 4 0;
+#X connect 2 0 4 0;
+#X connect 3 0 4 0;
+#X connect 4 0 49 0;
+#X connect 44 0 0 0;
+#X connect 44 0 5 0;
+#X connect 44 0 6 0;
+#X connect 44 0 7 0;
+#X connect 44 0 8 0;
+#X connect 44 0 9 0;
+#X connect 44 0 10 0;
+#X connect 44 0 11 0;
+#X connect 44 0 12 0;
+#X connect 44 0 14 0;
+#X connect 44 0 13 0;
+#X connect 44 0 15 0;
+#X connect 44 0 16 0;
+#X connect 44 0 17 0;
+#X connect 44 0 18 0;
+#X connect 44 0 19 0;
+#X connect 44 0 20 0;
+#X connect 44 0 21 0;
+#X connect 44 0 22 0;
+#X connect 44 0 23 0;
+#X connect 44 0 24 0;
+#X connect 44 0 25 0;
+#X connect 44 0 26 0;
+#X connect 44 0 27 0;
+#X connect 44 0 28 0;
+#X connect 44 0 29 0;
+#X connect 44 0 30 0;
+#X connect 44 0 31 0;
+#X connect 44 0 32 0;
+#X connect 44 0 33 0;
+#X connect 44 0 34 0;
+#X connect 44 0 35 0;
+#X connect 44 0 36 0;
+#X connect 44 0 37 0;
+#X connect 44 0 38 0;
+#X connect 44 0 39 0;
+#X connect 44 0 40 0;
+#X connect 44 0 41 0;
+#X connect 44 0 42 0;
+#X connect 44 0 43 0;
+#X connect 45 0 44 0;
+#X connect 46 0 49 1;
+#X connect 47 0 4 0;
+#X connect 48 0 46 0;
+#X connect 49 0 45 0;
+#X connect 49 1 45 1;
diff --git a/test/cyclone/sigwrappers-speed20.pd b/test/cyclone/sigwrappers-speed20.pd
new file mode 100644
index 0000000..98143ec
--- /dev/null
+++ b/test/cyclone/sigwrappers-speed20.pd
@@ -0,0 +1,63 @@
+#N canvas 441 249 467 396 12;
+#X obj 46 77 sigwrappers-speed;
+#X floatatom 123 29 5 0 0 0 - - -;
+#X floatatom 293 29 5 0 0 0 - - -;
+#X obj 46 107 sigwrappers-speed;
+#X obj 46 137 sigwrappers-speed;
+#X obj 46 167 sigwrappers-speed;
+#X obj 46 197 sigwrappers-speed;
+#X obj 46 227 sigwrappers-speed;
+#X obj 46 257 sigwrappers-speed;
+#X obj 228 77 sigwrappers-speed;
+#X obj 228 107 sigwrappers-speed;
+#X obj 228 137 sigwrappers-speed;
+#X obj 228 167 sigwrappers-speed;
+#X obj 228 197 sigwrappers-speed;
+#X obj 228 227 sigwrappers-speed;
+#X obj 228 257 sigwrappers-speed;
+#X obj 46 287 sigwrappers-speed;
+#X obj 46 317 sigwrappers-speed;
+#X obj 46 347 sigwrappers-speed;
+#X obj 228 287 sigwrappers-speed;
+#X obj 228 317 sigwrappers-speed;
+#X obj 228 347 sigwrappers-speed;
+#X connect 1 0 0 0;
+#X connect 1 0 3 0;
+#X connect 1 0 4 0;
+#X connect 1 0 5 0;
+#X connect 1 0 6 0;
+#X connect 1 0 7 0;
+#X connect 1 0 8 0;
+#X connect 1 0 9 0;
+#X connect 1 0 10 0;
+#X connect 1 0 11 0;
+#X connect 1 0 12 0;
+#X connect 1 0 13 0;
+#X connect 1 0 14 0;
+#X connect 1 0 15 0;
+#X connect 1 0 16 0;
+#X connect 1 0 17 0;
+#X connect 1 0 18 0;
+#X connect 1 0 19 0;
+#X connect 1 0 20 0;
+#X connect 1 0 21 0;
+#X connect 2 0 0 1;
+#X connect 2 0 3 1;
+#X connect 2 0 4 1;
+#X connect 2 0 5 1;
+#X connect 2 0 6 1;
+#X connect 2 0 7 1;
+#X connect 2 0 8 1;
+#X connect 2 0 16 1;
+#X connect 2 0 17 1;
+#X connect 2 0 18 1;
+#X connect 2 0 9 1;
+#X connect 2 0 10 1;
+#X connect 2 0 11 1;
+#X connect 2 0 12 1;
+#X connect 2 0 13 1;
+#X connect 2 0 14 1;
+#X connect 2 0 15 1;
+#X connect 2 0 19 1;
+#X connect 2 0 20 1;
+#X connect 2 0 21 1;
diff --git a/test/cyclone/sigwrappers-test.pd b/test/cyclone/sigwrappers-test.pd
new file mode 100644
index 0000000..c675fb4
--- /dev/null
+++ b/test/cyclone/sigwrappers-test.pd
@@ -0,0 +1,34 @@
+#N canvas 468 231 530 478 12;
+#X obj 38 200 phasewrap~;
+#X floatatom 234 68 0 0 0 0 - - -;
+#X obj 175 200 _phasewrap1~;
+#X obj 336 200 _phasewrap2~;
+#X obj 234 102 * 0.01;
+#X floatatom 38 273 0 0 0 0 - - -;
+#X floatatom 175 273 0 0 0 0 - - -;
+#X floatatom 336 273 0 0 0 0 - - -;
+#X floatatom 175 154 0 0 0 0 - - -;
+#X floatatom 49 68 5 0 0 0 - - -;
+#X obj 129 102 acos;
+#X obj 107 135 *;
+#X msg 129 68 -1;
+#X obj 129 33 loadbang;
+#X obj 38 237 Snapshot~ 20;
+#X obj 175 237 Snapshot~ 20;
+#X obj 336 237 Snapshot~ 20;
+#X connect 0 0 14 0;
+#X connect 1 0 4 0;
+#X connect 2 0 15 0;
+#X connect 3 0 16 0;
+#X connect 4 0 8 0;
+#X connect 8 0 0 0;
+#X connect 8 0 2 0;
+#X connect 8 0 3 0;
+#X connect 9 0 11 0;
+#X connect 10 0 11 1;
+#X connect 11 0 8 0;
+#X connect 12 0 10 0;
+#X connect 13 0 12 0;
+#X connect 14 0 5 0;
+#X connect 15 0 6 0;
+#X connect 16 0 7 0;
diff --git a/test/cyclone/spectrum-pm.pd b/test/cyclone/spectrum-pm.pd
new file mode 100644
index 0000000..db35ca8
--- /dev/null
+++ b/test/cyclone/spectrum-pm.pd
@@ -0,0 +1,34 @@
+#N canvas 189 215 712 594 12;
+#X obj 62 350 Scope~ 562 220 2 3 512 0 512 0 0 0 0 102 255 51 135 135
+135 0;
+#X obj 174 234 cartopol~;
+#X obj 174 190 rfft~;
+#X obj 23 25 block~ 1024;
+#X obj 62 276 vectral~ 1024;
+#X obj 62 142 count~ 0 1024 1 1;
+#X floatatom 284 100 5 0 0 0 - - -;
+#X floatatom 378 25 5 0 0 0 - - -;
+#X floatatom 111 190 5 0 0 0 - - -;
+#X obj 378 100 *~ 1;
+#X floatatom 440 100 5 0 0 0 - - -;
+#X obj 62 234 *~ 0.3;
+#X obj 284 142 cycle~ 3000;
+#X obj 378 62 cycle~ 1000;
+#X msg 210 276 slide 10 10;
+#X msg 130 310 range 0 512 \, 2 \, bufsize 512;
+#X connect 1 0 4 2;
+#X connect 2 0 1 0;
+#X connect 2 1 1 1;
+#X connect 4 0 0 0;
+#X connect 5 0 4 1;
+#X connect 5 0 11 0;
+#X connect 6 0 12 0;
+#X connect 7 0 13 0;
+#X connect 8 0 11 1;
+#X connect 9 0 12 1;
+#X connect 10 0 9 1;
+#X connect 11 0 4 0;
+#X connect 12 0 2 0;
+#X connect 13 0 9 0;
+#X connect 14 0 4 0;
+#X connect 15 0 0 0;
diff --git a/test/cyclone/speedlim-test.pd b/test/cyclone/speedlim-test.pd
new file mode 100644
index 0000000..04b6edf
--- /dev/null
+++ b/test/cyclone/speedlim-test.pd
@@ -0,0 +1,63 @@
+#N canvas 385 195 511 382 12;
+#X obj 191 306 speedlim;
+#X msg 191 31 bang;
+#X obj 191 331 print;
+#X msg 258 266 0;
+#X msg 301 266 10;
+#X msg 342 266 500;
+#X msg 263 66 1;
+#X msg 306 66 2;
+#X msg 349 66 3;
+#X msg 393 66 4;
+#X obj 279 92 pipe 490;
+#X obj 279 117 pipe 510;
+#X obj 279 142 pipe 990;
+#X obj 279 167 pipe 1600;
+#X obj 279 192 pipe 2010;
+#X obj 279 217 pipe 2020;
+#X msg 393 91 5;
+#X msg 393 116 6;
+#X msg 393 141 7;
+#X msg 263 31 bang;
+#X msg 384 266 3000;
+#X msg 106 235 one;
+#X msg 80 203 symbol two;
+#X msg 55 175 perhaps three;
+#X obj 30 143 testmess 300;
+#X msg 30 66 test;
+#X obj 30 104 t a b b b;
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 3 0 0 1;
+#X connect 4 0 0 1;
+#X connect 5 0 0 1;
+#X connect 6 0 0 0;
+#X connect 7 0 10 0;
+#X connect 8 0 11 0;
+#X connect 9 0 12 0;
+#X connect 10 0 0 0;
+#X connect 11 0 0 0;
+#X connect 12 0 0 0;
+#X connect 13 0 0 0;
+#X connect 14 0 0 0;
+#X connect 15 0 0 0;
+#X connect 16 0 13 0;
+#X connect 17 0 14 0;
+#X connect 18 0 15 0;
+#X connect 19 0 6 0;
+#X connect 19 0 7 0;
+#X connect 19 0 8 0;
+#X connect 19 0 9 0;
+#X connect 19 0 16 0;
+#X connect 19 0 17 0;
+#X connect 19 0 18 0;
+#X connect 20 0 0 1;
+#X connect 21 0 0 0;
+#X connect 22 0 0 0;
+#X connect 23 0 0 0;
+#X connect 24 0 0 0;
+#X connect 25 0 26 0;
+#X connect 26 0 24 0;
+#X connect 26 1 23 0;
+#X connect 26 2 22 0;
+#X connect 26 3 21 0;
diff --git a/test/cyclone/spell-test.pd b/test/cyclone/spell-test.pd
new file mode 100644
index 0000000..dd56e0c
--- /dev/null
+++ b/test/cyclone/spell-test.pd
@@ -0,0 +1,26 @@
+#N canvas 469 262 450 300 12;
+#X obj 130 233 spell 7 -0.5;
+#X msg 311 140 symbol test;
+#X obj 130 261 print;
+#X msg 311 168 another test;
+#X msg 40 191 bang;
+#X msg 130 106 99;
+#X msg 177 106 99.99;
+#X msg 79 106 -99;
+#X msg 243 106 1 2 3;
+#X msg 311 106 1 2.5 3;
+#X msg 311 78 1 test 3;
+#X obj 35 58 sprintf %c;
+#X msg 35 30 129;
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 0;
+#X connect 7 0 0 0;
+#X connect 8 0 0 0;
+#X connect 9 0 0 0;
+#X connect 10 0 0 0;
+#X connect 11 0 0 0;
+#X connect 12 0 11 0;
diff --git a/test/cyclone/spike-test.pd b/test/cyclone/spike-test.pd
new file mode 100644
index 0000000..4fb168c
--- /dev/null
+++ b/test/cyclone/spike-test.pd
@@ -0,0 +1,23 @@
+#N canvas 442 260 450 300 12;
+#X obj 59 186 spike~;
+#X obj 59 225 print;
+#X obj 59 75 phasor~ 1;
+#X floatatom 59 38 5 0 0 0 - - -;
+#X floatatom 131 149 5 0 0 0 - - -;
+#X floatatom 133 225 10 0 0 0 - - -;
+#X obj 59 112 change~;
+#X obj 59 149 +~ 1;
+#X obj 239 186 spike~;
+#X floatatom 311 149 5 0 0 0 - - -;
+#X floatatom 313 225 10 0 0 0 - - -;
+#X obj 239 149 -~ 1;
+#X connect 0 0 5 0;
+#X connect 2 0 6 0;
+#X connect 3 0 2 0;
+#X connect 4 0 0 1;
+#X connect 6 0 7 0;
+#X connect 6 0 11 0;
+#X connect 7 0 0 0;
+#X connect 8 0 10 0;
+#X connect 9 0 8 1;
+#X connect 11 0 8 0;
diff --git a/test/cyclone/split-test.pd b/test/cyclone/split-test.pd
new file mode 100644
index 0000000..860faa8
--- /dev/null
+++ b/test/cyclone/split-test.pd
@@ -0,0 +1,48 @@
+#N canvas 300 45 610 348 12;
+#X obj 176 212 split;
+#X msg 99 95 1.5 1 2;
+#X floatatom 176 252 5 0 0;
+#X floatatom 279 252 5 0 0;
+#X obj 176 295 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 279 295 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 176 36 5 0 0;
+#X floatatom 196 68 5 0 0;
+#X floatatom 216 101 5 0 0;
+#X msg 313 89 test;
+#X msg 313 121 list test;
+#X msg 313 57 1.5 test;
+#X msg 36 68 1.5 1.5 2;
+#X msg 36 142 2.5 1.5 2.4;
+#X floatatom 433 222 5 0 0;
+#X floatatom 536 222 5 0 0;
+#X obj 433 265 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 536 265 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 433 142 5 0 0;
+#X obj 433 101 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 313 153 3.5;
+#X obj 433 182 split 3.5;
+#X connect 0 0 2 0;
+#X connect 0 1 3 0;
+#X connect 1 0 0 0;
+#X connect 2 0 4 0;
+#X connect 3 0 5 0;
+#X connect 6 0 0 0;
+#X connect 7 0 0 1;
+#X connect 8 0 0 2;
+#X connect 9 0 0 0;
+#X connect 10 0 0 0;
+#X connect 11 0 0 0;
+#X connect 12 0 0 0;
+#X connect 13 0 0 0;
+#X connect 14 0 16 0;
+#X connect 15 0 17 0;
+#X connect 18 0 21 0;
+#X connect 19 0 18 0;
+#X connect 20 0 0 1;
+#X connect 21 0 14 0;
+#X connect 21 1 15 0;
diff --git a/test/cyclone/spray-test.pd b/test/cyclone/spray-test.pd
new file mode 100644
index 0000000..5c2cbd1
--- /dev/null
+++ b/test/cyclone/spray-test.pd
@@ -0,0 +1,82 @@
+#N canvas 210 202 708 466 12;
+#X obj 75 243 spray;
+#X obj 75 324 print a;
+#X obj 115 284 print b;
+#X obj 221 332 spray 5;
+#X obj 235 374 print;
+#X obj 221 405 print first;
+#X obj 465 370 print;
+#X obj 451 401 print first;
+#X obj 451 328 spray 5 -3;
+#X msg 451 110 \$1 1 2 3 4 5;
+#X msg 470 136 \$1 1 2 3 4;
+#X msg 484 163 \$1 1 2 3;
+#X msg 497 190 \$1 1 2;
+#X msg 504 216 \$1 1;
+#X msg 513 240 \$1 test 2 3 4 5;
+#X msg 517 269 \$1 1 test 3 4 5;
+#X msg 221 114 \$1 1 2 3 4 5;
+#X msg 240 141 \$1 1 2 3 4;
+#X msg 254 167 \$1 1 2 3;
+#X msg 266 194 \$1 1 2;
+#X msg 274 220 \$1 1;
+#X msg 283 244 \$1 test 2 3 4 5;
+#X msg 287 273 \$1 1 test 3 4 5;
+#X msg 75 110 \$1 1 2 3 4 5;
+#X msg 94 136 \$1 1 2 3 4;
+#X msg 108 163 \$1 1 2 3;
+#X msg 120 190 \$1 1 2;
+#X msg 128 216 \$1 1;
+#X floatatom 130 61 5 0 0;
+#X floatatom 250 62 5 0 0;
+#X floatatom 487 58 5 0 0;
+#X connect 0 0 1 0;
+#X connect 0 1 2 0;
+#X connect 3 0 5 0;
+#X connect 3 1 4 0;
+#X connect 3 2 4 0;
+#X connect 3 3 4 0;
+#X connect 3 4 4 0;
+#X connect 8 0 7 0;
+#X connect 8 1 6 0;
+#X connect 8 2 6 0;
+#X connect 8 3 6 0;
+#X connect 8 4 6 0;
+#X connect 9 0 8 0;
+#X connect 10 0 8 0;
+#X connect 11 0 8 0;
+#X connect 12 0 8 0;
+#X connect 13 0 8 0;
+#X connect 14 0 8 0;
+#X connect 15 0 8 0;
+#X connect 16 0 3 0;
+#X connect 17 0 3 0;
+#X connect 18 0 3 0;
+#X connect 19 0 3 0;
+#X connect 20 0 3 0;
+#X connect 21 0 3 0;
+#X connect 22 0 3 0;
+#X connect 23 0 0 0;
+#X connect 24 0 0 0;
+#X connect 25 0 0 0;
+#X connect 26 0 0 0;
+#X connect 27 0 0 0;
+#X connect 28 0 23 0;
+#X connect 28 0 24 0;
+#X connect 28 0 25 0;
+#X connect 28 0 26 0;
+#X connect 28 0 27 0;
+#X connect 29 0 16 0;
+#X connect 29 0 17 0;
+#X connect 29 0 18 0;
+#X connect 29 0 19 0;
+#X connect 29 0 20 0;
+#X connect 29 0 21 0;
+#X connect 29 0 22 0;
+#X connect 30 0 9 0;
+#X connect 30 0 10 0;
+#X connect 30 0 11 0;
+#X connect 30 0 12 0;
+#X connect 30 0 13 0;
+#X connect 30 0 14 0;
+#X connect 30 0 15 0;
diff --git a/test/cyclone/substitute-test.pd b/test/cyclone/substitute-test.pd
new file mode 100644
index 0000000..37e1a95
--- /dev/null
+++ b/test/cyclone/substitute-test.pd
@@ -0,0 +1,56 @@
+#N canvas 179 48 593 501 12;
+#X obj 281 458 substitute;
+#X msg 281 418 1 2 3;
+#X obj 180 342 print replaced;
+#X obj 398 347 print unchanged;
+#X obj 180 314 substitute foo bar;
+#X msg 28 73 bang;
+#X msg 61 102 set bang;
+#X msg 180 30 hello foo boo;
+#X msg 147 102 set bang;
+#X msg 252 102 one;
+#X msg 148 149 foo 34;
+#X msg 253 137 1 2 3 4;
+#X msg 302 102 one two three;
+#X msg 334 137 1 2 foo 4;
+#X msg 438 102 foo foo foo 77;
+#X msg 337 172 foo fum;
+#X msg 427 172 1 otherhit;
+#X msg 427 200 set 1 hithere;
+#X msg 428 236 set;
+#X msg 218 73 bang;
+#X msg 39 259 symbol sym;
+#X msg 428 264 symbol test;
+#X msg 255 381 bang;
+#X msg 341 381 bang;
+#X msg 256 172 1;
+#X msg 366 418 1 2;
+#X msg 426 418 2 3;
+#X connect 0 0 2 0;
+#X connect 0 0 26 0;
+#X connect 0 1 3 0;
+#X connect 1 0 0 0;
+#X connect 4 0 2 0;
+#X connect 4 1 3 0;
+#X connect 5 0 4 0;
+#X connect 6 0 4 0;
+#X connect 7 0 4 0;
+#X connect 8 0 4 1;
+#X connect 9 0 4 0;
+#X connect 10 0 4 0;
+#X connect 11 0 4 0;
+#X connect 12 0 4 1;
+#X connect 13 0 4 0;
+#X connect 14 0 4 0;
+#X connect 15 0 4 1;
+#X connect 16 0 4 1;
+#X connect 17 0 4 1;
+#X connect 18 0 4 1;
+#X connect 19 0 4 1;
+#X connect 20 0 4 0;
+#X connect 21 0 4 1;
+#X connect 22 0 0 0;
+#X connect 23 0 0 1;
+#X connect 24 0 4 0;
+#X connect 25 0 0 1;
+#X connect 26 0 0 1;
diff --git a/test/cyclone/switch-test.pd b/test/cyclone/switch-test.pd
new file mode 100644
index 0000000..ec7fe2f
--- /dev/null
+++ b/test/cyclone/switch-test.pd
@@ -0,0 +1,35 @@
+#N canvas 333 279 593 442 12;
+#X obj 123 227 switch 11 1 padding;
+#X msg 138 50 bang;
+#X msg 153 87 2;
+#X msg 168 122 symbol three;
+#X msg 183 155 1 2 3 4;
+#X msg 198 190 five is anything;
+#X msg 72 155 bang;
+#X obj 72 190 grab;
+#X floatatom 72 318 5 0 0;
+#X floatatom 68 50 5 0 0;
+#X obj 167 282 route bang float symbol list;
+#X obj 167 322 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 228 318 5 0 0;
+#X symbolatom 290 318 10 0 0;
+#X obj 352 355 print list;
+#X obj 414 318 print anything;
+#X msg 289 50 last is anything too;
+#X connect 0 0 10 0;
+#X connect 1 0 0 1;
+#X connect 2 0 0 2;
+#X connect 3 0 0 3;
+#X connect 4 0 0 4;
+#X connect 5 0 0 5;
+#X connect 6 0 7 0;
+#X connect 7 0 8 0;
+#X connect 7 1 0 0;
+#X connect 9 0 0 0;
+#X connect 10 0 11 0;
+#X connect 10 1 12 0;
+#X connect 10 2 13 0;
+#X connect 10 3 14 0;
+#X connect 10 4 15 0;
+#X connect 16 0 0 11;
diff --git a/test/cyclone/test.capture b/test/cyclone/test.capture
new file mode 100644
index 0000000..238343a
--- /dev/null
+++ b/test/cyclone/test.capture
@@ -0,0 +1,2 @@
+ffffffff fffffffe fffffffd fffffffc fffffffb fffffffa fffffff9 fffffff8 fffffff7
+fffffff6
diff --git a/test/cyclone/test.funbuff b/test/cyclone/test.funbuff
new file mode 100644
index 0000000..2c89038
--- /dev/null
+++ b/test/cyclone/test.funbuff
@@ -0,0 +1,10 @@
+funbuff 0 -0 1 -1 2 -2 3 -3 4 -4 5 -5 6 -6 7 -7 8 -8 9 -9 10 -10 11
+-11 12 -12 13 -13 14 -14 15 -15 16 -16 17 -17 18 -18 19 -19 20 -20
+21 -21 22 -22 23 -23 24 -24 25 -25 26 -26 27 -27 28 -28 29 -29 30 -30
+31 -31 32 -32 33 -33 34 -34 35 -35 36 -36 37 -37 38 -38 39 -39 40 -40
+41 -41 42 -42 43 -43 44 -44 45 -45 46 -46 47 -47 48 -48 49 -49 50 -50
+51 -51 52 -52 53 -53 54 -54 55 -55 56 -56 57 -57 58 -58 59 -59 60 -60
+61 -61 62 -62 63 -63 64 -64 65 -65 66 -66 67 -67 68 -68 69 -69 70 -70
+71 -71 72 -72 73 -73 74 -74 75 -75 76 -76 77 -77 78 -78 79 -79 80 -80
+81 -81 82 -82 83 -83 84 -84 85 -85 86 -86 87 -87 88 -88 89 -89 90 -90
+91 -91 92 -92 93 -93 94 -94 95 -95 96 -96 97 -97 98 -98 99 -99 \ No newline at end of file
diff --git a/test/cyclone/test.mid b/test/cyclone/test.mid
new file mode 100644
index 0000000..9547e79
--- /dev/null
+++ b/test/cyclone/test.mid
Binary files differ
diff --git a/test/cyclone/test.pool b/test/cyclone/test.pool
new file mode 100644
index 0000000..22c43be
--- /dev/null
+++ b/test/cyclone/test.pool
@@ -0,0 +1,2 @@
+sample /mnt/win_d/III_rok/Janek/krotkie/niskie_smyki.wav
+sample /mnt/win_d/III_rok/Janek/krotkie/wysokie_smyki.wav
diff --git a/test/cyclone/test.seq b/test/cyclone/test.seq
new file mode 100644
index 0000000..88b1657
--- /dev/null
+++ b/test/cyclone/test.seq
@@ -0,0 +1,1208 @@
+0 193 107;
+10 145 71 79;
+455 145 73 88;
+475 129 71 0;
+739 145 74 88;
+748 129 73 0;
+1138 145 76 94;
+1154 129 74 0;
+1255 145 74 92;
+1270 129 76 0;
+1486 145 73 79;
+1508 129 74 0;
+1574 145 74 80;
+1589 129 73 0;
+1660 145 73 79;
+1673 129 74 0;
+1762 145 69 80;
+1784 129 73 0;
+1984 145 66 76;
+2002 129 69 0;
+2231 145 71 79;
+2257 129 66 0;
+2496 145 64 88;
+2525 129 71 0;
+2739 145 66 76;
+2763 129 64 0;
+2976 145 67 80;
+2985 129 66 0;
+3108 129 67 0;
+3243 145 67 76;
+3381 129 67 0;
+3494 145 67 77;
+3694 129 67 0;
+3734 145 66 69;
+3994 145 71 80;
+4004 129 66 0;
+4242 145 59 79;
+4256 129 71 0;
+4483 194 98;
+4493 146 76 79;
+4494 145 60 80;
+4509 129 59 0;
+4611 145 59 79;
+4635 129 60 0;
+4727 145 60 80;
+4746 129 59 0;
+4846 145 57 79;
+4868 129 60 0;
+4934 146 78 88;
+4954 130 76 0;
+4961 145 62 80;
+4981 129 57 0;
+5074 145 59 80;
+5085 129 62 0;
+5204 145 64 80;
+5214 146 79 88;
+5219 129 59 0;
+5222 130 78 0;
+5612 146 81 94;
+5628 130 79 0;
+5650 129 64 0;
+5729 146 79 92;
+5735 145 64 88;
+5744 130 81 0;
+5943 129 64 0;
+5959 146 78 79;
+5981 145 62 88;
+5981 130 79 0;
+6047 146 79 80;
+6062 130 78 0;
+6133 146 78 79;
+6146 130 79 0;
+6235 146 74 80;
+6257 130 78 0;
+6345 145 59 80;
+6373 129 62 0;
+6456 146 71 76;
+6462 145 55 88;
+6465 129 59 0;
+6472 130 74 0;
+6570 145 54 80;
+6592 129 55 0;
+6700 146 76 79;
+6702 145 52 88;
+6716 129 54 0;
+6725 130 71 0;
+6825 145 50 88;
+6847 129 52 0;
+6955 145 48 80;
+6964 146 69 88;
+6967 129 50 0;
+6993 130 76 0;
+7207 146 71 76;
+7231 130 69 0;
+7444 146 72 80;
+7453 130 71 0;
+7462 145 53 88;
+7485 129 48 0;
+7576 130 72 0;
+7711 146 72 76;
+7849 130 72 0;
+7957 145 52 92;
+7962 146 72 77;
+7978 129 53 0;
+8161 130 72 0;
+8170 129 52 0;
+8201 146 71 69;
+8220 145 52 88;
+8460 146 76 80;
+8470 130 71 0;
+8580 145 50 80;
+8593 129 52 0;
+8701 145 48 88;
+8707 146 64 79;
+8712 129 50 0;
+8721 130 76 0;
+8819 145 50 79;
+8829 129 48 0;
+8946 145 38 80;
+8947 195 74;
+8957 147 81 79;
+8958 146 65 80;
+8963 129 50 0;
+8973 130 64 0;
+9075 146 64 79;
+9099 130 65 0;
+9191 146 65 80;
+9210 130 64 0;
+9303 145 41 80;
+9309 146 62 79;
+9319 129 38 0;
+9330 130 65 0;
+9396 147 83 88;
+9416 131 81 0;
+9423 146 67 80;
+9425 145 40 80;
+9428 129 41 0;
+9442 130 62 0;
+9535 146 64 80;
+9546 130 67 0;
+9665 146 69 80;
+9675 147 84 88;
+9680 130 64 0;
+9681 145 45 80;
+9683 131 83 0;
+9702 129 40 0;
+10026 129 45 0;
+10057 145 45 88;
+10072 147 86 94;
+10088 131 84 0;
+10110 130 69 0;
+10138 129 45 0;
+10169 145 45 80;
+10188 147 84 92;
+10194 146 69 88;
+10203 131 86 0;
+10283 145 48 84;
+10293 129 45 0;
+10401 130 69 0;
+10417 147 83 79;
+10420 145 47 88;
+10436 129 48 0;
+10437 146 67 88;
+10437 131 84 0;
+10503 147 84 80;
+10518 131 83 0;
+10589 147 83 79;
+10602 131 84 0;
+10680 145 40 80;
+10689 129 47 0;
+10691 147 79 80;
+10713 131 83 0;
+10801 146 64 80;
+10829 130 67 0;
+10912 147 76 76;
+10918 146 60 88;
+10921 130 64 0;
+10928 131 79 0;
+11026 146 59 80;
+11048 130 60 0;
+11156 147 81 79;
+11158 146 57 88;
+11163 145 38 88;
+11172 130 59 0;
+11174 129 40 0;
+11180 131 76 0;
+11280 146 55 88;
+11302 130 57 0;
+11410 146 53 80;
+11419 147 74 88;
+11422 130 55 0;
+11448 131 81 0;
+11662 145 36 80;
+11662 147 76 76;
+11673 129 38 0;
+11686 131 74 0;
+11899 147 77 80;
+11908 131 76 0;
+11917 145 34 76;
+11917 146 58 88;
+11940 130 53 0;
+11945 129 36 0;
+12030 131 77 0;
+12032 145 36 79;
+12045 129 34 0;
+12164 145 38 88;
+12164 147 77 76;
+12188 129 36 0;
+12301 131 77 0;
+12409 146 57 92;
+12414 147 77 77;
+12430 130 58 0;
+12613 131 77 0;
+12622 130 57 0;
+12653 147 76 69;
+12660 145 36 78;
+12671 146 57 88;
+12678 129 38 0;
+12782 145 35 80;
+12804 129 36 0;
+12900 129 35 0;
+12900 145 33 72;
+12910 147 81 80;
+12920 131 76 0;
+13030 146 55 80;
+13043 130 57 0;
+13151 146 53 88;
+13157 147 69 79;
+13160 145 45 88;
+13161 130 55 0;
+13170 131 81 0;
+13183 129 33 0;
+13268 146 55 79;
+13278 130 53 0;
+13395 146 43 80;
+13396 196 38;
+13406 148 74 79;
+13407 145 43 88;
+13407 147 70 80;
+13412 130 55 0;
+13422 131 69 0;
+13424 129 45 0;
+13524 147 69 79;
+13548 131 70 0;
+13640 147 70 80;
+13659 131 69 0;
+13752 146 46 80;
+13758 147 67 79;
+13763 145 46 80;
+13768 130 43 0;
+13779 131 70 0;
+13780 129 43 0;
+13845 148 76 88;
+13865 132 74 0;
+13872 147 72 80;
+13874 146 45 80;
+13877 130 46 0;
+13886 145 45 84;
+13891 131 67 0;
+13893 129 46 0;
+13984 147 69 80;
+13995 131 72 0;
+14114 147 74 80;
+14124 148 77 88;
+14129 131 69 0;
+14130 146 50 80;
+14132 132 76 0;
+14134 145 50 94;
+14150 129 45 0;
+14150 130 45 0;
+14472 129 50 0;
+14473 130 50 0;
+14497 145 50 80;
+14503 146 50 88;
+14518 148 79 94;
+14534 132 77 0;
+14556 131 74 0;
+14580 129 50 0;
+14583 130 50 0;
+14607 145 50 79;
+14613 146 50 80;
+14632 148 77 92;
+14638 147 74 88;
+14647 132 79 0;
+14727 146 53 84;
+14729 145 53 84;
+14736 130 50 0;
+14741 129 50 0;
+14843 131 74 0;
+14859 148 76 79;
+14860 145 52 92;
+14862 146 52 88;
+14878 130 53 0;
+14879 147 72 88;
+14879 132 77 0;
+14880 129 53 0;
+14945 148 77 80;
+14960 132 76 0;
+15031 148 76 79;
+15044 132 77 0;
+15115 145 45 88;
+15117 129 52 0;
+15120 146 45 80;
+15129 130 52 0;
+15131 148 72 80;
+15153 132 76 0;
+15241 147 69 80;
+15269 131 72 0;
+15352 148 69 76;
+15358 147 65 88;
+15361 131 69 0;
+15368 132 72 0;
+15466 147 64 80;
+15488 131 65 0;
+15596 148 74 79;
+15598 147 62 88;
+15603 146 43 88;
+15605 145 43 88;
+15611 131 64 0;
+15613 130 45 0;
+15615 129 45 0;
+15618 132 69 0;
+15718 147 60 88;
+15740 131 62 0;
+15848 147 58 80;
+15857 148 67 88;
+15860 131 60 0;
+15886 132 74 0;
+16100 146 41 80;
+16100 148 69 76;
+16111 145 41 92;
+16111 130 43 0;
+16124 132 67 0;
+16129 129 43 0;
+16337 148 70 80;
+16346 132 69 0;
+16347 145 39 80;
+16354 146 39 76;
+16354 147 63 88;
+16365 129 41 0;
+16376 131 58 0;
+16381 130 41 0;
+16465 145 41 92;
+16466 132 70 0;
+16468 146 41 79;
+16481 129 39 0;
+16481 130 39 0;
+16589 145 43 80;
+16600 146 43 88;
+16600 148 70 76;
+16606 129 41 0;
+16624 130 41 0;
+16737 132 70 0;
+16835 145 41 88;
+16844 147 62 92;
+16849 148 70 77;
+16862 129 43 0;
+16865 131 63 0;
+16956 145 40 88;
+16976 129 41 0;
+17047 132 70 0;
+17056 131 62 0;
+17087 148 69 69;
+17088 145 38 80;
+17094 146 41 78;
+17097 129 40 0;
+17104 147 62 88;
+17111 130 43 0;
+17215 146 40 80;
+17237 130 41 0;
+17333 130 40 0;
+17333 146 38 72;
+17343 148 74 80;
+17353 132 69 0;
+17463 147 60 80;
+17476 131 62 0;
+17569 129 38 0;
+17583 147 58 88;
+17589 148 62 79;
+17592 146 50 88;
+17593 131 60 0;
+17602 132 74 0;
+17615 130 38 0;
+17700 147 60 79;
+17710 131 58 0;
+17827 147 48 80;
+17828 193 44;
+17838 145 67 79;
+17839 146 48 88;
+17839 148 63 80;
+17844 131 60 0;
+17854 132 62 0;
+17856 130 50 0;
+17956 148 62 79;
+17980 132 63 0;
+18072 148 63 80;
+18091 132 62 0;
+18184 147 51 80;
+18190 148 60 79;
+18195 146 51 80;
+18200 131 48 0;
+18211 132 63 0;
+18212 130 48 0;
+18277 145 69 88;
+18297 129 67 0;
+18304 148 65 80;
+18306 147 50 80;
+18309 131 51 0;
+18318 146 50 84;
+18323 132 60 0;
+18325 130 51 0;
+18416 148 62 80;
+18427 132 65 0;
+18546 148 67 80;
+18556 145 70 88;
+18561 132 62 0;
+18562 147 55 80;
+18564 129 69 0;
+18566 146 55 94;
+18582 130 50 0;
+18582 131 50 0;
+18904 130 55 0;
+18905 131 55 0;
+18929 146 55 80;
+18935 147 55 88;
+18950 145 72 94;
+18966 129 70 0;
+18988 132 67 0;
+19012 130 55 0;
+19015 131 55 0;
+19039 146 55 79;
+19045 147 55 80;
+19064 145 70 92;
+19070 148 67 88;
+19079 129 72 0;
+19159 147 58 84;
+19161 146 58 84;
+19168 131 55 0;
+19173 130 55 0;
+19275 132 67 0;
+19291 145 69 79;
+19292 146 57 92;
+19294 147 57 88;
+19310 131 58 0;
+19311 129 70 0;
+19311 148 65 88;
+19312 130 58 0;
+19377 145 70 80;
+19392 129 69 0;
+19463 145 69 79;
+19476 129 70 0;
+19547 146 50 88;
+19549 130 57 0;
+19552 147 50 80;
+19561 131 57 0;
+19563 145 65 80;
+19585 129 69 0;
+19673 148 62 80;
+19701 132 65 0;
+19784 145 62 76;
+19790 148 58 88;
+19793 132 62 0;
+19800 129 65 0;
+19898 148 57 80;
+19920 132 58 0;
+20028 145 67 79;
+20030 148 55 88;
+20035 147 48 88;
+20037 146 48 88;
+20043 132 57 0;
+20045 131 50 0;
+20047 130 50 0;
+20050 129 62 0;
+20150 148 53 88;
+20172 132 55 0;
+20280 148 51 80;
+20289 145 60 88;
+20292 132 53 0;
+20318 129 67 0;
+20532 145 62 76;
+20532 147 46 80;
+20543 146 46 92;
+20543 131 48 0;
+20556 129 60 0;
+20561 130 48 0;
+20769 145 63 80;
+20778 129 62 0;
+20779 146 44 80;
+20786 147 44 76;
+20786 148 56 88;
+20797 130 46 0;
+20808 132 51 0;
+20813 131 46 0;
+20897 146 46 92;
+20898 129 63 0;
+20900 147 46 79;
+20913 130 44 0;
+20913 131 44 0;
+21021 146 48 80;
+21032 145 63 76;
+21032 147 48 88;
+21038 130 46 0;
+21056 131 46 0;
+21169 129 63 0;
+21267 146 46 88;
+21276 148 55 92;
+21281 145 63 77;
+21294 130 48 0;
+21297 132 56 0;
+21388 146 45 88;
+21408 130 46 0;
+21479 129 63 0;
+21488 132 55 0;
+21519 145 62 69;
+21520 146 43 80;
+21526 147 46 78;
+21529 130 45 0;
+21536 148 55 88;
+21543 131 48 0;
+21647 147 45 80;
+21669 131 46 0;
+21765 131 45 0;
+21765 147 43 72;
+21775 145 67 80;
+21785 129 62 0;
+21895 148 53 80;
+21908 132 55 0;
+22001 130 43 0;
+22015 148 51 88;
+22021 145 55 79;
+22024 147 55 88;
+22025 132 53 0;
+22034 129 67 0;
+22047 131 43 0;
+22132 148 53 79;
+22142 132 51 0;
+22259 148 41 80;
+22260 194 66;
+22270 146 72 79;
+22271 145 56 80;
+22271 147 53 88;
+22276 132 53 0;
+22286 129 55 0;
+22288 131 55 0;
+22388 145 55 79;
+22412 129 56 0;
+22504 145 56 80;
+22523 129 55 0;
+22616 148 44 80;
+22622 145 53 79;
+22627 147 56 80;
+22632 132 41 0;
+22643 129 56 0;
+22644 131 53 0;
+22709 146 74 88;
+22729 130 72 0;
+22736 145 58 80;
+22738 148 43 80;
+22741 132 44 0;
+22750 147 55 84;
+22755 129 53 0;
+22757 131 56 0;
+22848 145 55 80;
+22859 129 58 0;
+22978 145 60 80;
+22988 146 75 88;
+22993 129 55 0;
+22994 148 48 80;
+22996 130 74 0;
+22998 147 60 94;
+23014 131 55 0;
+23014 132 43 0;
+23336 131 60 0;
+23337 132 48 0;
+23361 147 60 80;
+23367 148 48 88;
+23382 146 77 94;
+23398 130 75 0;
+23420 129 60 0;
+23444 131 60 0;
+23447 132 48 0;
+23471 147 60 79;
+23477 148 48 80;
+23496 146 75 92;
+23502 145 60 88;
+23511 130 77 0;
+23591 148 51 84;
+23593 147 63 84;
+23600 132 48 0;
+23605 131 60 0;
+23707 129 60 0;
+23723 146 74 79;
+23724 147 62 92;
+23726 148 50 88;
+23742 132 51 0;
+23743 145 58 88;
+23743 130 75 0;
+23744 131 63 0;
+23809 146 75 80;
+23824 130 74 0;
+23895 146 74 79;
+23908 130 75 0;
+23979 147 55 88;
+23981 131 62 0;
+23984 148 43 80;
+23993 132 50 0;
+23995 146 70 80;
+24017 130 74 0;
+24105 145 55 80;
+24133 129 58 0;
+24216 146 67 76;
+24222 145 51 88;
+24225 129 55 0;
+24232 130 70 0;
+24330 145 50 80;
+24352 129 51 0;
+24460 146 72 79;
+24462 145 48 88;
+24467 148 41 88;
+24469 147 53 88;
+24475 129 50 0;
+24477 132 43 0;
+24479 131 55 0;
+24482 130 67 0;
+24582 145 46 88;
+24604 129 48 0;
+24712 145 44 80;
+24721 146 65 88;
+24724 129 46 0;
+24750 130 72 0;
+24964 146 67 76;
+24964 148 39 80;
+24975 147 51 92;
+24975 132 41 0;
+24988 130 65 0;
+24993 131 53 0;
+25201 146 68 80;
+25210 130 67 0;
+25211 147 49 80;
+25218 145 49 88;
+25218 148 37 76;
+25229 131 51 0;
+25240 129 44 0;
+25245 132 39 0;
+25329 147 51 92;
+25330 130 68 0;
+25332 148 39 79;
+25345 131 49 0;
+25345 132 37 0;
+25453 147 53 80;
+25464 146 68 76;
+25464 148 41 88;
+25470 131 51 0;
+25488 132 39 0;
+25601 130 68 0;
+25699 147 51 88;
+25708 145 48 92;
+25713 146 68 77;
+25726 131 53 0;
+25729 129 49 0;
+25820 147 50 88;
+25840 131 51 0;
+25911 130 68 0;
+25920 129 48 0;
+25951 146 67 69;
+25952 147 48 80;
+25958 148 39 78;
+25961 131 50 0;
+25968 145 48 88;
+25975 132 41 0;
+26079 148 38 80;
+26101 132 39 0;
+26197 132 38 0;
+26197 148 36 72;
+26207 146 72 80;
+26217 130 67 0;
+26327 145 46 80;
+26340 129 48 0;
+26433 131 48 0;
+26447 145 44 88;
+26453 146 60 79;
+26456 148 48 88;
+26457 129 46 0;
+26466 130 72 0;
+26479 132 36 0;
+26564 145 46 79;
+26574 129 44 0;
+26691 145 34 80;
+26692 195 99;
+26702 147 77 79;
+26703 146 61 80;
+26703 148 46 88;
+26708 129 46 0;
+26718 130 60 0;
+26720 132 48 0;
+26820 146 60 79;
+26844 130 61 0;
+26936 146 61 80;
+26955 130 60 0;
+27048 145 37 80;
+27054 146 58 79;
+27059 148 49 80;
+27064 129 34 0;
+27075 130 61 0;
+27076 132 46 0;
+27141 147 79 88;
+27161 131 77 0;
+27168 146 63 80;
+27170 145 36 80;
+27173 129 37 0;
+27182 148 48 84;
+27187 130 58 0;
+27189 132 49 0;
+27280 146 60 80;
+27291 130 63 0;
+27410 146 65 80;
+27420 147 80 88;
+27425 130 60 0;
+27426 145 41 80;
+27428 131 79 0;
+27430 148 53 94;
+27446 129 36 0;
+27446 132 48 0;
+27768 132 53 0;
+27769 129 41 0;
+27793 148 53 80;
+27799 145 41 88;
+27814 147 82 94;
+27830 131 80 0;
+27852 130 65 0;
+27876 132 53 0;
+27879 129 41 0;
+27903 148 53 79;
+27909 145 41 80;
+27928 147 80 92;
+27934 146 65 88;
+27943 131 82 0;
+28023 145 44 84;
+28025 148 56 84;
+28032 129 41 0;
+28037 132 53 0;
+28139 130 65 0;
+28155 147 79 79;
+28156 148 55 92;
+28158 145 43 88;
+28174 129 44 0;
+28175 146 63 88;
+28175 131 80 0;
+28176 132 56 0;
+28241 147 80 80;
+28256 131 79 0;
+28327 147 79 79;
+28340 131 80 0;
+28411 148 48 88;
+28413 132 55 0;
+28416 145 36 80;
+28425 129 43 0;
+28427 147 75 80;
+28449 131 79 0;
+28537 146 60 80;
+28565 130 63 0;
+28648 147 72 76;
+28654 146 56 88;
+28657 130 60 0;
+28664 131 75 0;
+28762 146 55 80;
+28784 130 56 0;
+28892 147 77 79;
+28894 146 53 88;
+28899 145 34 88;
+28901 148 46 88;
+28907 130 55 0;
+28909 129 36 0;
+28911 132 48 0;
+28914 131 72 0;
+29014 146 51 88;
+29036 130 53 0;
+29144 146 49 80;
+29153 147 70 88;
+29156 130 51 0;
+29182 131 77 0;
+29396 145 32 80;
+29396 147 72 76;
+29407 129 34 0;
+29407 148 44 92;
+29420 131 70 0;
+29425 132 46 0;
+29633 147 73 80;
+29642 131 72 0;
+29643 148 42 80;
+29650 145 30 76;
+29650 146 54 88;
+29661 132 44 0;
+29672 130 49 0;
+29677 129 32 0;
+29761 148 44 92;
+29762 131 73 0;
+29764 145 32 79;
+29777 129 30 0;
+29777 132 42 0;
+29885 148 46 80;
+29896 145 34 88;
+29896 147 73 76;
+29902 132 44 0;
+29920 129 32 0;
+30033 131 73 0;
+30131 148 44 88;
+30140 146 53 92;
+30145 147 73 77;
+30158 132 46 0;
+30161 130 54 0;
+30252 148 43 88;
+30272 132 44 0;
+30343 131 73 0;
+30352 130 53 0;
+30383 147 72 69;
+30384 148 41 80;
+30390 145 32 78;
+30393 132 43 0;
+30400 146 53 88;
+30407 129 34 0;
+30511 145 31 80;
+30533 129 32 0;
+30629 129 31 0;
+30629 145 29 72;
+30639 147 77 80;
+30649 131 72 0;
+30759 146 51 80;
+30772 130 53 0;
+30865 132 41 0;
+30879 146 49 88;
+30885 147 65 79;
+30888 145 41 88;
+30889 130 51 0;
+30898 131 77 0;
+30911 129 29 0;
+30996 146 51 79;
+31006 130 49 0;
+31123 146 39 80;
+31124 196 47;
+31134 148 70 79;
+31135 145 39 88;
+31135 147 66 80;
+31140 130 51 0;
+31150 131 65 0;
+31152 129 41 0;
+31252 147 65 79;
+31276 131 66 0;
+31368 147 66 80;
+31387 131 65 0;
+31480 146 42 80;
+31486 147 63 79;
+31491 145 42 80;
+31496 130 39 0;
+31507 131 66 0;
+31508 129 39 0;
+31573 148 72 88;
+31593 132 70 0;
+31600 147 68 80;
+31602 146 41 80;
+31605 130 42 0;
+31614 145 41 84;
+31619 131 63 0;
+31621 129 42 0;
+31712 147 65 80;
+31723 131 68 0;
+31842 147 70 80;
+31852 148 73 88;
+31857 131 65 0;
+31858 146 46 80;
+31860 132 72 0;
+31862 145 46 94;
+31878 129 41 0;
+31878 130 41 0;
+32200 129 46 0;
+32201 130 46 0;
+32225 145 46 80;
+32231 146 46 88;
+32246 148 75 94;
+32262 132 73 0;
+32284 131 70 0;
+32308 129 46 0;
+32311 130 46 0;
+32335 145 46 79;
+32341 146 46 80;
+32360 148 73 92;
+32366 147 70 88;
+32375 132 75 0;
+32455 146 49 84;
+32457 145 49 84;
+32464 130 46 0;
+32469 129 46 0;
+32571 131 70 0;
+32587 148 72 79;
+32588 145 48 92;
+32590 146 48 88;
+32606 130 49 0;
+32607 147 68 88;
+32607 132 73 0;
+32608 129 49 0;
+32673 148 73 80;
+32688 132 72 0;
+32759 148 72 79;
+32772 132 73 0;
+32843 145 41 88;
+32845 129 48 0;
+32848 146 41 80;
+32857 130 48 0;
+32859 148 68 80;
+32881 132 72 0;
+32969 147 65 80;
+32997 131 68 0;
+33080 148 65 76;
+33086 147 61 88;
+33089 131 65 0;
+33096 132 68 0;
+33194 147 60 80;
+33216 131 61 0;
+33324 148 70 79;
+33326 147 58 88;
+33331 146 39 88;
+33333 145 39 88;
+33339 131 60 0;
+33341 130 41 0;
+33343 129 41 0;
+33346 132 65 0;
+33446 147 56 88;
+33468 131 58 0;
+33576 147 54 80;
+33585 148 63 88;
+33588 131 56 0;
+33614 132 70 0;
+33828 146 37 80;
+33828 148 65 76;
+33839 145 37 92;
+33839 130 39 0;
+33852 132 63 0;
+33857 129 39 0;
+34065 148 66 80;
+34074 132 65 0;
+34075 145 35 80;
+34082 146 35 76;
+34082 147 59 88;
+34093 129 37 0;
+34104 131 54 0;
+34109 130 37 0;
+34193 145 37 92;
+34194 132 66 0;
+34196 146 37 79;
+34209 129 35 0;
+34209 130 35 0;
+34317 145 39 80;
+34328 146 39 88;
+34328 148 66 76;
+34334 129 37 0;
+34352 130 37 0;
+34465 132 66 0;
+34563 145 37 88;
+34572 147 58 92;
+34577 148 66 77;
+34590 129 39 0;
+34593 131 59 0;
+34684 145 36 88;
+34704 129 37 0;
+34775 132 66 0;
+34784 131 58 0;
+34815 148 65 69;
+34816 145 34 80;
+34822 146 37 78;
+34825 129 36 0;
+34832 147 58 88;
+34839 130 39 0;
+34943 146 36 80;
+34965 130 37 0;
+35061 130 36 0;
+35061 146 34 72;
+35071 148 70 80;
+35081 132 65 0;
+35191 147 56 80;
+35204 131 58 0;
+35297 129 34 0;
+35311 147 54 88;
+35317 148 58 79;
+35320 146 46 88;
+35321 131 56 0;
+35330 132 70 0;
+35343 130 34 0;
+35428 147 56 79;
+35438 131 54 0;
+35555 147 44 80;
+35568 146 44 88;
+35568 148 59 80;
+35573 131 56 0;
+35583 132 58 0;
+35585 130 46 0;
+35685 148 58 79;
+35709 132 59 0;
+35801 148 59 80;
+35820 132 58 0;
+35913 147 47 80;
+35919 148 56 79;
+35924 146 47 80;
+35929 131 44 0;
+35940 132 59 0;
+35941 130 44 0;
+36034 148 61 80;
+36036 147 46 80;
+36039 131 47 0;
+36048 146 46 84;
+36053 132 56 0;
+36055 130 47 0;
+36146 148 58 80;
+36157 132 61 0;
+36276 148 63 80;
+36291 132 58 0;
+36292 147 51 80;
+36297 146 51 94;
+36313 130 46 0;
+36313 131 46 0;
+36635 130 51 0;
+36636 131 51 0;
+36660 146 51 80;
+36666 147 51 88;
+36720 132 63 0;
+36744 130 51 0;
+36747 131 51 0;
+36771 146 51 79;
+36777 147 51 80;
+36803 148 63 88;
+36892 147 54 84;
+36894 146 54 84;
+36901 131 51 0;
+36906 130 51 0;
+37008 132 63 0;
+37026 146 53 92;
+37028 147 53 88;
+37044 131 54 0;
+37045 148 61 88;
+37046 130 54 0;
+37282 146 46 88;
+37284 130 53 0;
+37287 147 46 80;
+37296 131 53 0;
+37409 148 58 80;
+37437 132 61 0;
+37526 148 54 88;
+37529 132 58 0;
+37635 148 53 80;
+37657 132 54 0;
+37767 148 51 88;
+37772 147 44 88;
+37774 146 44 88;
+37780 132 53 0;
+37782 131 46 0;
+37784 130 46 0;
+37888 148 49 88;
+37910 132 51 0;
+38018 148 47 80;
+38031 132 49 0;
+38271 147 42 80;
+38282 146 42 92;
+38282 131 44 0;
+38300 130 44 0;
+38518 146 40 80;
+38525 147 40 76;
+38525 148 52 88;
+38536 130 42 0;
+38547 132 47 0;
+38552 131 42 0;
+38636 146 42 92;
+38639 147 42 79;
+38652 130 40 0;
+38652 131 40 0;
+38760 146 44 80;
+38771 147 44 88;
+38777 130 42 0;
+38795 131 42 0;
+39007 146 42 88;
+39016 148 51 92;
+39034 130 44 0;
+39037 132 52 0;
+39128 146 41 88;
+39148 130 42 0;
+39228 132 51 0;
+39260 146 39 80;
+39266 147 42 78;
+39269 130 41 0;
+39276 148 51 88;
+39283 131 44 0;
+39387 147 41 80;
+39409 131 42 0;
+39505 131 41 0;
+39505 147 39 72;
+39636 148 49 80;
+39649 132 51 0;
+39742 130 39 0;
+39756 148 47 88;
+39766 147 51 88;
+39767 132 49 0;
+39789 131 39 0;
+39874 148 49 79;
+39884 132 47 0;
+40001 148 37 80;
+40014 147 49 88;
+40019 132 49 0;
+40032 131 51 0;
+40362 148 40 80;
+40373 147 52 80;
+40378 132 37 0;
+40391 131 49 0;
+40487 148 39 80;
+40490 132 40 0;
+40499 147 51 84;
+40506 131 52 0;
+40745 148 44 80;
+40750 147 56 94;
+40766 131 51 0;
+40766 132 39 0;
+41088 131 56 0;
+41089 132 44 0;
+41113 147 56 80;
+41119 148 44 88;
+41198 131 56 0;
+41201 132 44 0;
+41225 147 56 79;
+41231 148 44 80;
+41346 148 47 84;
+41348 147 59 84;
+41355 132 44 0;
+41360 131 56 0;
+41481 147 58 92;
+41483 148 46 88;
+41499 132 47 0;
+41501 131 59 0;
+41737 147 51 88;
+41739 131 58 0;
+41742 148 39 80;
+41751 132 46 0;
+42231 148 37 88;
+42233 147 49 88;
+42242 132 39 0;
+42244 131 51 0;
+42732 148 35 80;
+42743 147 47 92;
+42743 132 37 0;
+42761 131 49 0;
+42979 147 45 80;
+42986 148 33 76;
+42997 131 47 0;
+43013 132 35 0;
+43097 147 47 92;
+43100 148 35 79;
+43113 131 45 0;
+43113 132 33 0;
+43221 147 49 80;
+43232 148 37 88;
+43238 131 47 0;
+43256 132 35 0;
+43468 147 47 88;
+43495 131 49 0;
+43590 147 46 88;
+43610 131 47 0;
+43723 147 44 80;
+43729 148 35 78;
+43732 131 46 0;
+43747 132 37 0;
+43851 148 34 80;
+43873 132 35 0;
+43969 132 34 0;
+43969 148 32 72;
+44207 131 44 0;
+44231 148 44 88;
+44254 132 32 0;
+44480 148 42 88;
+44498 132 44 0;
+44840 148 45 80;
+44858 132 42 0;
+44967 148 44 84;
+44974 132 45 0;
+45218 148 49 94;
+45234 132 44 0;
+45556 132 49 0;
+45582 148 49 80;
+45667 132 49 0;
+45695 148 49 79;
+45820 148 52 84;
+45833 132 49 0;
+45954 148 51 92;
+45976 132 52 0;
+46212 148 44 88;
+46214 132 51 0;
+46710 148 42 88;
+46721 132 44 0;
+47221 148 40 92;
+47239 132 42 0;
+47457 148 38 80;
+47476 132 40 0;
+47577 148 40 92;
+47593 132 38 0;
+47701 148 42 80;
+47719 132 40 0;
+47949 148 40 88;
+47976 132 42 0;
+48071 148 39 88;
+48091 132 40 0;
+48204 148 37 80;
+48214 132 39 0;
+48690 132 37 0;
diff --git a/test/cyclone/test1.seq b/test/cyclone/test1.seq
new file mode 100644
index 0000000..5b695dc
--- /dev/null
+++ b/test/cyclone/test1.seq
@@ -0,0 +1,1208 @@
+0 193 107;
+7 145 71 79;
+449 145 73 88;
+467 129 71 0;
+730 145 74 88;
+737 129 73 0;
+1125 145 76 94;
+1140 129 74 0;
+1238 145 74 92;
+1251 129 76 0;
+1464 145 73 79;
+1484 129 74 0;
+1549 145 74 80;
+1562 129 73 0;
+1632 145 73 79;
+1642 129 74 0;
+1730 145 69 80;
+1750 129 73 0;
+1947 145 66 76;
+1962 129 69 0;
+2188 145 71 79;
+2211 129 66 0;
+2447 145 64 88;
+2475 129 71 0;
+2688 145 66 76;
+2711 129 64 0;
+2921 145 67 80;
+2928 129 66 0;
+3050 129 67 0;
+3182 145 67 76;
+3317 129 67 0;
+3428 145 67 77;
+3625 129 67 0;
+3664 145 66 69;
+3921 145 71 80;
+3928 129 66 0;
+4164 145 59 79;
+4177 129 71 0;
+4403 194 98;
+4410 146 76 79;
+4410 145 60 80;
+4423 129 59 0;
+4524 145 59 79;
+4547 129 60 0;
+4638 145 60 80;
+4656 129 59 0;
+4754 145 57 79;
+4774 129 60 0;
+4839 146 78 88;
+4857 130 76 0;
+4862 145 62 80;
+4880 129 57 0;
+4971 145 59 80;
+4981 129 62 0;
+5098 145 64 80;
+5105 146 79 88;
+5107 129 59 0;
+5109 130 78 0;
+5497 146 81 94;
+5512 130 79 0;
+5532 129 64 0;
+5610 146 79 92;
+5615 145 64 88;
+5622 130 81 0;
+5819 129 64 0;
+5834 146 78 79;
+5854 145 62 88;
+5854 130 79 0;
+5919 146 79 80;
+5932 130 78 0;
+6002 146 78 79;
+6012 130 79 0;
+6100 146 74 80;
+6120 130 78 0;
+6205 145 59 80;
+6231 129 62 0;
+6311 146 71 76;
+6316 145 55 88;
+6318 129 59 0;
+6323 130 74 0;
+6419 145 54 80;
+6439 129 55 0;
+6545 146 76 79;
+6545 145 52 88;
+6558 129 54 0;
+6565 130 71 0;
+6663 145 50 88;
+6683 129 52 0;
+6789 145 48 80;
+6796 146 69 88;
+6798 129 50 0;
+6821 130 76 0;
+7034 146 71 76;
+7057 130 69 0;
+7267 146 72 80;
+7274 130 71 0;
+7281 145 53 88;
+7301 129 48 0;
+7389 130 72 0;
+7521 146 72 76;
+7656 130 72 0;
+7762 145 52 92;
+7764 146 72 77;
+7779 129 53 0;
+7961 130 72 0;
+7968 129 52 0;
+7996 146 71 69;
+8014 145 52 88;
+8253 146 76 80;
+8260 130 71 0;
+8369 145 50 80;
+8379 129 52 0;
+8485 145 48 88;
+8490 146 64 79;
+8492 129 50 0;
+8499 130 76 0;
+8595 145 50 79;
+8602 129 48 0;
+8716 145 38 80;
+8716 195 74;
+8723 147 81 79;
+8723 146 65 80;
+8725 129 50 0;
+8732 130 64 0;
+8833 146 64 79;
+8856 130 65 0;
+8947 146 65 80;
+8965 130 64 0;
+9056 145 41 80;
+9061 146 62 79;
+9068 129 38 0;
+9078 130 65 0;
+9143 147 83 88;
+9161 131 81 0;
+9166 146 67 80;
+9166 145 40 80;
+9168 129 41 0;
+9181 130 62 0;
+9272 146 64 80;
+9282 130 67 0;
+9399 146 69 80;
+9406 147 84 88;
+9408 130 64 0;
+9408 145 45 80;
+9408 131 83 0;
+9426 129 40 0;
+9748 129 45 0;
+9776 145 45 88;
+9789 147 86 94;
+9804 131 84 0;
+9824 130 69 0;
+9850 129 45 0;
+9878 145 45 80;
+9896 147 84 92;
+9901 146 69 88;
+9908 131 86 0;
+9986 145 48 84;
+9993 129 45 0;
+10099 130 69 0;
+10114 147 83 79;
+10116 145 47 88;
+10131 129 48 0;
+10131 146 67 88;
+10131 131 84 0;
+10196 147 84 80;
+10209 131 83 0;
+10279 147 83 79;
+10289 131 84 0;
+10364 145 40 80;
+10371 129 47 0;
+10371 147 79 80;
+10391 131 83 0;
+10476 146 64 80;
+10502 130 67 0;
+10582 147 76 76;
+10587 146 60 88;
+10589 130 64 0;
+10594 131 79 0;
+10690 146 59 80;
+10710 130 60 0;
+10816 147 81 79;
+10816 146 57 88;
+10818 145 38 88;
+10825 130 59 0;
+10825 129 40 0;
+10830 131 76 0;
+10928 146 55 88;
+10948 130 57 0;
+11054 146 53 80;
+11061 147 74 88;
+11063 130 55 0;
+11086 131 81 0;
+11299 145 36 80;
+11299 147 76 76;
+11309 129 38 0;
+11319 131 74 0;
+11529 147 77 80;
+11536 131 76 0;
+11543 145 34 76;
+11543 146 58 88;
+11563 130 53 0;
+11565 129 36 0;
+11648 131 77 0;
+11648 145 36 79;
+11658 129 34 0;
+11775 145 38 88;
+11775 147 77 76;
+11798 129 36 0;
+11909 131 77 0;
+12015 146 57 92;
+12017 147 77 77;
+12032 130 58 0;
+12214 131 77 0;
+12221 130 57 0;
+12249 147 76 69;
+12254 145 36 78;
+12264 146 57 88;
+12269 129 38 0;
+12370 145 35 80;
+12390 129 36 0;
+12483 129 35 0;
+12483 145 33 72;
+12490 147 81 80;
+12497 131 76 0;
+12606 146 55 80;
+12616 130 57 0;
+12722 146 53 88;
+12727 147 69 79;
+12729 145 45 88;
+12729 130 55 0;
+12736 131 81 0;
+12746 129 33 0;
+12829 146 55 79;
+12836 130 53 0;
+12950 146 43 80;
+12950 196 38;
+12957 148 74 79;
+12957 145 43 88;
+12957 147 70 80;
+12959 130 55 0;
+12966 131 69 0;
+12966 129 45 0;
+13064 147 69 79;
+13087 131 70 0;
+13178 147 70 80;
+13196 131 69 0;
+13287 146 46 80;
+13292 147 67 79;
+13294 145 46 80;
+13296 130 43 0;
+13306 131 70 0;
+13306 129 43 0;
+13368 148 76 88;
+13386 132 74 0;
+13391 147 72 80;
+13391 146 45 80;
+13393 130 46 0;
+13400 145 45 84;
+13402 131 67 0;
+13402 129 46 0;
+13490 147 69 80;
+13500 131 72 0;
+13617 147 74 80;
+13624 148 77 88;
+13626 131 69 0;
+13626 146 50 80;
+13626 132 76 0;
+13626 145 50 94;
+13641 129 45 0;
+13641 130 45 0;
+13961 129 50 0;
+13961 130 50 0;
+13984 145 50 80;
+13989 146 50 88;
+14002 148 79 94;
+14017 132 77 0;
+14037 131 74 0;
+14060 129 50 0;
+14062 130 50 0;
+14085 145 50 79;
+14090 146 50 80;
+14108 148 77 92;
+14113 147 74 88;
+14120 132 79 0;
+14198 146 53 84;
+14198 145 53 84;
+14203 130 50 0;
+14205 129 50 0;
+14306 131 74 0;
+14321 148 76 79;
+14321 145 52 92;
+14321 146 52 88;
+14336 130 53 0;
+14336 147 72 88;
+14336 132 77 0;
+14336 129 53 0;
+14398 148 77 80;
+14411 132 76 0;
+14481 148 76 79;
+14491 132 77 0;
+14561 145 45 88;
+14561 129 52 0;
+14563 146 45 80;
+14570 130 52 0;
+14570 148 72 80;
+14590 132 76 0;
+14675 147 69 80;
+14701 131 72 0;
+14781 148 69 76;
+14786 147 65 88;
+14788 131 69 0;
+14793 132 72 0;
+14889 147 64 80;
+14909 131 65 0;
+15015 148 74 79;
+15015 147 62 88;
+15017 146 43 88;
+15017 145 43 88;
+15022 131 64 0;
+15022 130 45 0;
+15022 129 45 0;
+15024 132 69 0;
+15122 147 60 88;
+15142 131 62 0;
+15248 147 58 80;
+15255 148 67 88;
+15257 131 60 0;
+15280 132 74 0;
+15493 146 41 80;
+15493 148 69 76;
+15503 145 41 92;
+15503 130 43 0;
+15513 132 67 0;
+15515 129 43 0;
+15720 148 70 80;
+15727 132 69 0;
+15727 145 39 80;
+15732 146 39 76;
+15732 147 63 88;
+15742 129 41 0;
+15752 131 58 0;
+15754 130 41 0;
+15837 145 41 92;
+15837 132 70 0;
+15837 146 41 79;
+15847 129 39 0;
+15847 130 39 0;
+15953 145 43 80;
+15963 146 43 88;
+15963 148 70 76;
+15968 129 41 0;
+15983 130 41 0;
+16094 132 70 0;
+16190 145 41 88;
+16197 147 62 92;
+16199 148 70 77;
+16209 129 43 0;
+16211 131 63 0;
+16299 145 40 88;
+16317 129 41 0;
+16387 132 70 0;
+16394 131 62 0;
+16422 148 69 69;
+16422 145 38 80;
+16427 146 41 78;
+16429 129 40 0;
+16434 147 62 88;
+16439 130 43 0;
+16540 146 40 80;
+16560 130 41 0;
+16653 130 40 0;
+16653 146 38 72;
+16660 148 74 80;
+16667 132 69 0;
+16776 147 60 80;
+16786 131 62 0;
+16877 129 38 0;
+16890 147 58 88;
+16895 148 62 79;
+16897 146 50 88;
+16897 131 60 0;
+16904 132 74 0;
+16914 130 38 0;
+16997 147 60 79;
+17004 131 58 0;
+17118 147 48 80;
+17118 193 44;
+17125 145 67 79;
+17125 146 48 88;
+17125 148 63 80;
+17127 131 60 0;
+17134 132 62 0;
+17134 130 50 0;
+17232 148 62 79;
+17255 132 63 0;
+17346 148 63 80;
+17364 132 62 0;
+17455 147 51 80;
+17460 148 60 79;
+17462 146 51 80;
+17464 131 48 0;
+17474 132 63 0;
+17474 130 48 0;
+17536 145 69 88;
+17554 129 67 0;
+17559 148 65 80;
+17559 147 50 80;
+17561 131 51 0;
+17568 146 50 84;
+17570 132 60 0;
+17570 130 51 0;
+17658 148 62 80;
+17668 132 65 0;
+17785 148 67 80;
+17792 145 70 88;
+17794 132 62 0;
+17794 147 55 80;
+17794 129 69 0;
+17794 146 55 94;
+17809 130 50 0;
+17809 131 50 0;
+18129 130 55 0;
+18129 131 55 0;
+18152 146 55 80;
+18157 147 55 88;
+18170 145 72 94;
+18185 129 70 0;
+18205 132 67 0;
+18228 130 55 0;
+18230 131 55 0;
+18253 146 55 79;
+18258 147 55 80;
+18276 145 70 92;
+18281 148 67 88;
+18288 129 72 0;
+18366 147 58 84;
+18366 146 58 84;
+18371 131 55 0;
+18373 130 55 0;
+18474 132 67 0;
+18489 145 69 79;
+18489 146 57 92;
+18489 147 57 88;
+18504 131 58 0;
+18504 129 70 0;
+18504 148 65 88;
+18504 130 58 0;
+18566 145 70 80;
+18579 129 69 0;
+18649 145 69 79;
+18659 129 70 0;
+18729 146 50 88;
+18729 130 57 0;
+18731 147 50 80;
+18738 131 57 0;
+18738 145 65 80;
+18758 129 69 0;
+18843 148 62 80;
+18869 132 65 0;
+18949 145 62 76;
+18954 148 58 88;
+18956 132 62 0;
+18961 129 65 0;
+19057 148 57 80;
+19077 132 58 0;
+19183 145 67 79;
+19183 148 55 88;
+19185 147 48 88;
+19185 146 48 88;
+19190 132 57 0;
+19190 131 50 0;
+19190 130 50 0;
+19192 129 62 0;
+19290 148 53 88;
+19310 132 55 0;
+19416 148 51 80;
+19423 145 60 88;
+19425 132 53 0;
+19448 129 67 0;
+19661 145 62 76;
+19661 147 46 80;
+19671 146 46 92;
+19671 131 48 0;
+19681 129 60 0;
+19683 130 48 0;
+19888 145 63 80;
+19895 129 62 0;
+19895 146 44 80;
+19900 147 44 76;
+19900 148 56 88;
+19910 130 46 0;
+19920 132 51 0;
+19922 131 46 0;
+20005 146 46 92;
+20005 129 63 0;
+20005 147 46 79;
+20015 130 44 0;
+20015 131 44 0;
+20121 146 48 80;
+20131 145 63 76;
+20131 147 48 88;
+20136 130 46 0;
+20151 131 46 0;
+20262 129 63 0;
+20358 146 46 88;
+20365 148 55 92;
+20367 145 63 77;
+20377 130 48 0;
+20379 132 56 0;
+20467 146 45 88;
+20485 130 46 0;
+20555 129 63 0;
+20562 132 55 0;
+20590 145 62 69;
+20590 146 43 80;
+20595 147 46 78;
+20597 130 45 0;
+20602 148 55 88;
+20607 131 48 0;
+20708 147 45 80;
+20728 131 46 0;
+20821 131 45 0;
+20821 147 43 72;
+20828 145 67 80;
+20835 129 62 0;
+20944 148 53 80;
+20954 132 55 0;
+21045 130 43 0;
+21058 148 51 88;
+21063 145 55 79;
+21065 147 55 88;
+21065 132 53 0;
+21072 129 67 0;
+21082 131 43 0;
+21165 148 53 79;
+21172 132 51 0;
+21286 148 41 80;
+21286 194 66;
+21293 146 72 79;
+21293 145 56 80;
+21293 147 53 88;
+21295 132 53 0;
+21302 129 55 0;
+21302 131 55 0;
+21400 145 55 79;
+21423 129 56 0;
+21514 145 56 80;
+21532 129 55 0;
+21623 148 44 80;
+21628 145 53 79;
+21630 147 56 80;
+21632 132 41 0;
+21642 129 56 0;
+21642 131 53 0;
+21704 146 74 88;
+21722 130 72 0;
+21727 145 58 80;
+21727 148 43 80;
+21729 132 44 0;
+21736 147 55 84;
+21738 129 53 0;
+21738 131 56 0;
+21826 145 55 80;
+21836 129 58 0;
+21953 145 60 80;
+21960 146 75 88;
+21962 129 55 0;
+21962 148 48 80;
+21962 130 74 0;
+21962 147 60 94;
+21977 131 55 0;
+21977 132 43 0;
+22297 131 60 0;
+22297 132 48 0;
+22320 147 60 80;
+22325 148 48 88;
+22338 146 77 94;
+22353 130 75 0;
+22373 129 60 0;
+22396 131 60 0;
+22398 132 48 0;
+22421 147 60 79;
+22426 148 48 80;
+22444 146 75 92;
+22449 145 60 88;
+22456 130 77 0;
+22534 148 51 84;
+22534 147 63 84;
+22539 132 48 0;
+22541 131 60 0;
+22642 129 60 0;
+22657 146 74 79;
+22657 147 62 92;
+22657 148 50 88;
+22672 132 51 0;
+22672 145 58 88;
+22672 130 75 0;
+22672 131 63 0;
+22734 146 75 80;
+22747 130 74 0;
+22817 146 74 79;
+22827 130 75 0;
+22897 147 55 88;
+22897 131 62 0;
+22899 148 43 80;
+22906 132 50 0;
+22906 146 70 80;
+22926 130 74 0;
+23011 145 55 80;
+23037 129 58 0;
+23117 146 67 76;
+23122 145 51 88;
+23124 129 55 0;
+23129 130 70 0;
+23225 145 50 80;
+23245 129 51 0;
+23351 146 72 79;
+23351 145 48 88;
+23353 148 41 88;
+23353 147 53 88;
+23358 129 50 0;
+23358 132 43 0;
+23358 131 55 0;
+23360 130 67 0;
+23458 145 46 88;
+23478 129 48 0;
+23584 145 44 80;
+23591 146 65 88;
+23593 129 46 0;
+23616 130 72 0;
+23829 146 67 76;
+23829 148 39 80;
+23839 147 51 92;
+23839 132 41 0;
+23849 130 65 0;
+23851 131 53 0;
+24056 146 68 80;
+24063 130 67 0;
+24063 147 49 80;
+24068 145 49 88;
+24068 148 37 76;
+24078 131 51 0;
+24088 129 44 0;
+24090 132 39 0;
+24173 147 51 92;
+24173 130 68 0;
+24173 148 39 79;
+24183 131 49 0;
+24183 132 37 0;
+24289 147 53 80;
+24299 146 68 76;
+24299 148 41 88;
+24304 131 51 0;
+24319 132 39 0;
+24430 130 68 0;
+24526 147 51 88;
+24533 145 48 92;
+24535 146 68 77;
+24545 131 53 0;
+24547 129 49 0;
+24635 147 50 88;
+24653 131 51 0;
+24723 130 68 0;
+24730 129 48 0;
+24758 146 67 69;
+24758 147 48 80;
+24763 148 39 78;
+24765 131 50 0;
+24770 145 48 88;
+24775 132 41 0;
+24876 148 38 80;
+24896 132 39 0;
+24989 132 38 0;
+24989 148 36 72;
+24996 146 72 80;
+25003 130 67 0;
+25112 145 46 80;
+25122 129 48 0;
+25213 131 48 0;
+25226 145 44 88;
+25231 146 60 79;
+25233 148 48 88;
+25233 129 46 0;
+25240 130 72 0;
+25250 132 36 0;
+25333 145 46 79;
+25340 129 44 0;
+25454 145 34 80;
+25454 195 99;
+25461 147 77 79;
+25461 146 61 80;
+25461 148 46 88;
+25463 129 46 0;
+25470 130 60 0;
+25470 132 48 0;
+25568 146 60 79;
+25591 130 61 0;
+25682 146 61 80;
+25700 130 60 0;
+25791 145 37 80;
+25796 146 58 79;
+25798 148 49 80;
+25800 129 34 0;
+25810 130 61 0;
+25810 132 46 0;
+25872 147 79 88;
+25890 131 77 0;
+25895 146 63 80;
+25895 145 36 80;
+25897 129 37 0;
+25904 148 48 84;
+25906 130 58 0;
+25906 132 49 0;
+25994 146 60 80;
+26004 130 63 0;
+26121 146 65 80;
+26128 147 80 88;
+26130 130 60 0;
+26130 145 41 80;
+26130 131 79 0;
+26130 148 53 94;
+26145 129 36 0;
+26145 132 48 0;
+26465 132 53 0;
+26465 129 41 0;
+26488 148 53 80;
+26493 145 41 88;
+26506 147 82 94;
+26521 131 80 0;
+26541 130 65 0;
+26564 132 53 0;
+26566 129 41 0;
+26589 148 53 79;
+26594 145 41 80;
+26612 147 80 92;
+26617 146 65 88;
+26624 131 82 0;
+26702 145 44 84;
+26702 148 56 84;
+26707 129 41 0;
+26709 132 53 0;
+26810 130 65 0;
+26825 147 79 79;
+26825 148 55 92;
+26825 145 43 88;
+26840 129 44 0;
+26840 146 63 88;
+26840 131 80 0;
+26840 132 56 0;
+26902 147 80 80;
+26915 131 79 0;
+26985 147 79 79;
+26995 131 80 0;
+27065 148 48 88;
+27065 132 55 0;
+27067 145 36 80;
+27074 129 43 0;
+27074 147 75 80;
+27094 131 79 0;
+27179 146 60 80;
+27205 130 63 0;
+27285 147 72 76;
+27290 146 56 88;
+27292 130 60 0;
+27297 131 75 0;
+27393 146 55 80;
+27413 130 56 0;
+27519 147 77 79;
+27519 146 53 88;
+27521 145 34 88;
+27521 148 46 88;
+27526 130 55 0;
+27526 129 36 0;
+27526 132 48 0;
+27528 131 72 0;
+27626 146 51 88;
+27646 130 53 0;
+27752 146 49 80;
+27759 147 70 88;
+27761 130 51 0;
+27784 131 77 0;
+27997 145 32 80;
+27997 147 72 76;
+28007 129 34 0;
+28007 148 44 92;
+28017 131 70 0;
+28019 132 46 0;
+28224 147 73 80;
+28231 131 72 0;
+28231 148 42 80;
+28236 145 30 76;
+28236 146 54 88;
+28246 132 44 0;
+28256 130 49 0;
+28258 129 32 0;
+28341 148 44 92;
+28341 131 73 0;
+28341 145 32 79;
+28351 129 30 0;
+28351 132 42 0;
+28457 148 46 80;
+28467 145 34 88;
+28467 147 73 76;
+28472 132 44 0;
+28487 129 32 0;
+28598 131 73 0;
+28694 148 44 88;
+28701 146 53 92;
+28703 147 73 77;
+28713 132 46 0;
+28715 130 54 0;
+28803 148 43 88;
+28821 132 44 0;
+28891 131 73 0;
+28898 130 53 0;
+28926 147 72 69;
+28926 148 41 80;
+28931 145 32 78;
+28933 132 43 0;
+28938 146 53 88;
+28943 129 34 0;
+29044 145 31 80;
+29064 129 32 0;
+29157 129 31 0;
+29157 145 29 72;
+29164 147 77 80;
+29171 131 72 0;
+29280 146 51 80;
+29290 130 53 0;
+29381 132 41 0;
+29394 146 49 88;
+29399 147 65 79;
+29401 145 41 88;
+29401 130 51 0;
+29408 131 77 0;
+29418 129 29 0;
+29501 146 51 79;
+29508 130 49 0;
+29622 146 39 80;
+29622 196 47;
+29629 148 70 79;
+29629 145 39 88;
+29629 147 66 80;
+29631 130 51 0;
+29638 131 65 0;
+29638 129 41 0;
+29736 147 65 79;
+29759 131 66 0;
+29850 147 66 80;
+29868 131 65 0;
+29959 146 42 80;
+29964 147 63 79;
+29966 145 42 80;
+29968 130 39 0;
+29978 131 66 0;
+29978 129 39 0;
+30040 148 72 88;
+30058 132 70 0;
+30063 147 68 80;
+30063 146 41 80;
+30065 130 42 0;
+30072 145 41 84;
+30074 131 63 0;
+30074 129 42 0;
+30162 147 65 80;
+30172 131 68 0;
+30289 147 70 80;
+30296 148 73 88;
+30298 131 65 0;
+30298 146 46 80;
+30298 132 72 0;
+30298 145 46 94;
+30313 129 41 0;
+30313 130 41 0;
+30633 129 46 0;
+30633 130 46 0;
+30656 145 46 80;
+30661 146 46 88;
+30674 148 75 94;
+30689 132 73 0;
+30709 131 70 0;
+30732 129 46 0;
+30734 130 46 0;
+30757 145 46 79;
+30762 146 46 80;
+30780 148 73 92;
+30785 147 70 88;
+30792 132 75 0;
+30870 146 49 84;
+30870 145 49 84;
+30875 130 46 0;
+30877 129 46 0;
+30978 131 70 0;
+30993 148 72 79;
+30993 145 48 92;
+30993 146 48 88;
+31008 130 49 0;
+31008 147 68 88;
+31008 132 73 0;
+31008 129 49 0;
+31070 148 73 80;
+31083 132 72 0;
+31153 148 72 79;
+31163 132 73 0;
+31233 145 41 88;
+31233 129 48 0;
+31235 146 41 80;
+31242 130 48 0;
+31242 148 68 80;
+31262 132 72 0;
+31347 147 65 80;
+31373 131 68 0;
+31453 148 65 76;
+31458 147 61 88;
+31460 131 65 0;
+31465 132 68 0;
+31561 147 60 80;
+31581 131 61 0;
+31687 148 70 79;
+31687 147 58 88;
+31689 146 39 88;
+31689 145 39 88;
+31694 131 60 0;
+31694 130 41 0;
+31694 129 41 0;
+31696 132 65 0;
+31794 147 56 88;
+31814 131 58 0;
+31920 147 54 80;
+31927 148 63 88;
+31929 131 56 0;
+31952 132 70 0;
+32165 146 37 80;
+32165 148 65 76;
+32175 145 37 92;
+32175 130 39 0;
+32185 132 63 0;
+32187 129 39 0;
+32392 148 66 80;
+32399 132 65 0;
+32399 145 35 80;
+32404 146 35 76;
+32404 147 59 88;
+32414 129 37 0;
+32424 131 54 0;
+32426 130 37 0;
+32509 145 37 92;
+32509 132 66 0;
+32509 146 37 79;
+32519 129 35 0;
+32519 130 35 0;
+32625 145 39 80;
+32635 146 39 88;
+32635 148 66 76;
+32640 129 37 0;
+32655 130 37 0;
+32766 132 66 0;
+32862 145 37 88;
+32869 147 58 92;
+32871 148 66 77;
+32881 129 39 0;
+32883 131 59 0;
+32971 145 36 88;
+32989 129 37 0;
+33059 132 66 0;
+33066 131 58 0;
+33094 148 65 69;
+33094 145 34 80;
+33099 146 37 78;
+33101 129 36 0;
+33106 147 58 88;
+33111 130 39 0;
+33212 146 36 80;
+33232 130 37 0;
+33325 130 36 0;
+33325 146 34 72;
+33332 148 70 80;
+33339 132 65 0;
+33448 147 56 80;
+33458 131 58 0;
+33549 129 34 0;
+33562 147 54 88;
+33567 148 58 79;
+33569 146 46 88;
+33569 131 56 0;
+33576 132 70 0;
+33586 130 34 0;
+33669 147 56 79;
+33676 131 54 0;
+33790 147 44 80;
+33800 146 44 88;
+33800 148 59 80;
+33802 131 56 0;
+33809 132 58 0;
+33809 130 46 0;
+33907 148 58 79;
+33930 132 59 0;
+34021 148 59 80;
+34039 132 58 0;
+34130 147 47 80;
+34135 148 56 79;
+34137 146 47 80;
+34139 131 44 0;
+34149 132 59 0;
+34149 130 44 0;
+34240 148 61 80;
+34240 147 46 80;
+34242 131 47 0;
+34249 146 46 84;
+34251 132 56 0;
+34251 130 47 0;
+34339 148 58 80;
+34349 132 61 0;
+34466 148 63 80;
+34479 132 58 0;
+34479 147 51 80;
+34481 146 51 94;
+34496 130 46 0;
+34496 131 46 0;
+34816 130 51 0;
+34816 131 51 0;
+34839 146 51 80;
+34844 147 51 88;
+34896 132 63 0;
+34919 130 51 0;
+34921 131 51 0;
+34944 146 51 79;
+34949 147 51 80;
+34972 148 63 88;
+35060 147 54 84;
+35060 146 54 84;
+35065 131 51 0;
+35067 130 51 0;
+35168 132 63 0;
+35183 146 53 92;
+35183 147 53 88;
+35198 131 54 0;
+35198 148 61 88;
+35198 130 54 0;
+35432 146 46 88;
+35432 130 53 0;
+35434 147 46 80;
+35441 131 53 0;
+35552 148 58 80;
+35578 132 61 0;
+35666 148 54 88;
+35668 132 58 0;
+35772 148 53 80;
+35792 132 54 0;
+35901 148 51 88;
+35903 147 44 88;
+35903 146 44 88;
+35908 132 53 0;
+35908 131 46 0;
+35908 130 46 0;
+36009 148 49 88;
+36029 132 51 0;
+36135 148 47 80;
+36145 132 49 0;
+36384 147 42 80;
+36394 146 42 92;
+36394 131 44 0;
+36409 130 44 0;
+36625 146 40 80;
+36630 147 40 76;
+36630 148 52 88;
+36640 130 42 0;
+36650 132 47 0;
+36652 131 42 0;
+36735 146 42 92;
+36737 147 42 79;
+36747 130 40 0;
+36747 131 40 0;
+36853 146 44 80;
+36863 147 44 88;
+36868 130 42 0;
+36883 131 42 0;
+37093 146 42 88;
+37100 148 51 92;
+37115 130 44 0;
+37117 132 52 0;
+37205 146 41 88;
+37223 130 42 0;
+37301 132 51 0;
+37332 146 39 80;
+37337 147 42 78;
+37339 130 41 0;
+37344 148 51 88;
+37349 131 44 0;
+37450 147 41 80;
+37470 131 42 0;
+37563 131 41 0;
+37563 147 39 72;
+37693 148 49 80;
+37703 132 51 0;
+37794 130 39 0;
+37807 148 47 88;
+37814 147 51 88;
+37814 132 49 0;
+37834 131 39 0;
+37917 148 49 79;
+37924 132 47 0;
+38038 148 37 80;
+38048 147 49 88;
+38050 132 49 0;
+38060 131 51 0;
+38388 148 40 80;
+38398 147 52 80;
+38400 132 37 0;
+38410 131 49 0;
+38503 148 39 80;
+38505 132 40 0;
+38512 147 51 84;
+38517 131 52 0;
+38753 148 44 80;
+38755 147 56 94;
+38770 131 51 0;
+38770 132 39 0;
+39090 131 56 0;
+39090 132 44 0;
+39113 147 56 80;
+39118 148 44 88;
+39196 131 56 0;
+39198 132 44 0;
+39221 147 56 79;
+39226 148 44 80;
+39340 148 47 84;
+39340 147 59 84;
+39345 132 44 0;
+39347 131 56 0;
+39466 147 58 92;
+39466 148 46 88;
+39481 132 47 0;
+39481 131 59 0;
+39715 147 51 88;
+39715 131 58 0;
+39717 148 39 80;
+39724 132 46 0;
+40203 148 37 88;
+40203 147 49 88;
+40210 132 39 0;
+40210 131 51 0;
+40696 148 35 80;
+40706 147 47 92;
+40706 132 37 0;
+40721 131 49 0;
+40937 147 45 80;
+40942 148 33 76;
+40952 131 47 0;
+40967 132 35 0;
+41050 147 47 92;
+41052 148 35 79;
+41062 131 45 0;
+41062 132 33 0;
+41168 147 49 80;
+41178 148 37 88;
+41183 131 47 0;
+41198 132 35 0;
+41408 147 47 88;
+41434 131 49 0;
+41527 147 46 88;
+41545 131 47 0;
+41656 147 44 80;
+41661 148 35 78;
+41663 131 46 0;
+41676 132 37 0;
+41777 148 34 80;
+41797 132 35 0;
+41890 132 34 0;
+41890 148 32 72;
+42126 131 44 0;
+42149 148 44 88;
+42169 132 32 0;
+42392 148 42 88;
+42407 132 44 0;
+42748 148 45 80;
+42763 132 42 0;
+42869 148 44 84;
+42874 132 45 0;
+43116 148 49 94;
+43131 132 44 0;
+43451 132 49 0;
+43474 148 49 80;
+43557 132 49 0;
+43583 148 49 79;
+43708 148 52 84;
+43718 132 49 0;
+43837 148 51 92;
+43857 132 52 0;
+44091 148 44 88;
+44091 132 51 0;
+44585 148 42 88;
+44595 132 44 0;
+45095 148 40 92;
+45110 132 42 0;
+45326 148 38 80;
+45344 132 40 0;
+45442 148 40 92;
+45457 132 38 0;
+45563 148 42 80;
+45578 132 40 0;
+45807 148 40 88;
+45833 132 42 0;
+45926 148 39 88;
+45944 132 40 0;
+46055 148 37 80;
+46062 132 39 0;
+46535 132 37 0;
diff --git a/test/cyclone/testmess-reentrant.pd b/test/cyclone/testmess-reentrant.pd
new file mode 100644
index 0000000..afac922
--- /dev/null
+++ b/test/cyclone/testmess-reentrant.pd
@@ -0,0 +1,25 @@
+#N canvas 326 112 405 388 12;
+#X obj 67 328 print;
+#X obj 67 57 t a b;
+#X obj 67 136 spigot;
+#X msg 193 95 1;
+#X msg 194 136 0;
+#X msg 117 220 -9 -8 -7 -6 -5 -4 -3 -2 -1;
+#X msg 67 19 test this mess;
+#X msg 92 254 test;
+#X obj 92 290 testmess 16 heap;
+#X obj 67 95 testmess 8;
+#X obj 67 181 t a b b b;
+#X connect 1 0 9 0;
+#X connect 1 1 3 0;
+#X connect 2 0 10 0;
+#X connect 3 0 2 1;
+#X connect 4 0 2 1;
+#X connect 5 0 9 0;
+#X connect 6 0 1 0;
+#X connect 7 0 8 0;
+#X connect 9 0 2 0;
+#X connect 10 0 0 0;
+#X connect 10 1 7 0;
+#X connect 10 2 5 0;
+#X connect 10 3 4 0;
diff --git a/test/cyclone/testmess-test.pd b/test/cyclone/testmess-test.pd
new file mode 100644
index 0000000..442ffc3
--- /dev/null
+++ b/test/cyclone/testmess-test.pd
@@ -0,0 +1,69 @@
+#N canvas 319 97 771 509 12;
+#X obj 97 235 until;
+#X msg 97 266 test;
+#X obj 68 202 t b 0 b;
+#X obj 62 371 realtime;
+#X floatatom 62 411 0 0 0;
+#X obj 346 235 until;
+#X msg 346 266 test;
+#X obj 317 202 t b 0 b;
+#X obj 311 371 realtime;
+#X floatatom 311 411 0 0 0;
+#X obj 614 235 until;
+#X msg 614 266 test;
+#X obj 579 371 realtime;
+#X floatatom 579 411 0 0 0;
+#X obj 317 49 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X obj 317 18 loadbang;
+#X obj 346 299 testmess 1 heap;
+#X obj 346 332 testmess 1 heap;
+#X obj 614 332 testmess 1;
+#X obj 614 299 testmess 1;
+#X obj 97 299 testmess 1 stack;
+#X obj 97 332 testmess 1 stack;
+#X msg 585 166 1000;
+#X msg 317 166 1000;
+#X msg 68 166 1000;
+#X msg 416 239 set \$1;
+#X obj 317 112 t b b;
+#X obj 585 202 t b 0 b;
+#X obj 317 79 metro 500;
+#X floatatom 501 112 5 0 0;
+#X obj 416 202 random 120;
+#X connect 0 0 1 0;
+#X connect 1 0 20 0;
+#X connect 2 0 3 1;
+#X connect 2 1 0 0;
+#X connect 2 2 3 0;
+#X connect 3 0 4 0;
+#X connect 5 0 6 0;
+#X connect 6 0 16 0;
+#X connect 7 0 8 1;
+#X connect 7 1 5 0;
+#X connect 7 2 8 0;
+#X connect 8 0 9 0;
+#X connect 10 0 11 0;
+#X connect 11 0 19 0;
+#X connect 12 0 13 0;
+#X connect 14 0 28 0;
+#X connect 15 0 14 0;
+#X connect 16 0 17 0;
+#X connect 19 0 18 0;
+#X connect 20 0 21 0;
+#X connect 22 0 27 0;
+#X connect 23 0 7 0;
+#X connect 24 0 2 0;
+#X connect 25 0 16 0;
+#X connect 25 0 19 0;
+#X connect 25 0 20 0;
+#X connect 26 0 24 0;
+#X connect 26 0 22 0;
+#X connect 26 0 23 0;
+#X connect 26 1 30 0;
+#X connect 27 0 12 1;
+#X connect 27 1 10 0;
+#X connect 27 2 12 0;
+#X connect 28 0 26 0;
+#X connect 29 0 30 1;
+#X connect 30 0 25 0;
diff --git a/test/cyclone/thresh-test.pd b/test/cyclone/thresh-test.pd
new file mode 100644
index 0000000..35e8ab7
--- /dev/null
+++ b/test/cyclone/thresh-test.pd
@@ -0,0 +1,41 @@
+#N canvas 415 237 602 431 12;
+#X obj 339 290 print;
+#X msg 339 173 1 test \, 2 test \, 3 test;
+#X obj 339 256 thresh;
+#X msg 472 218 300;
+#X msg 516 218 1000;
+#X msg 388 218 0;
+#X msg 430 218 10;
+#X msg 276 173 99;
+#X msg 315 55 33;
+#X obj 315 129 pipe 1;
+#X obj 315 89 t 0 0;
+#X obj 87 206 pipe 900;
+#X msg 154 173 900;
+#X msg 199 173 1000;
+#X obj 87 89 t b b b;
+#X msg 87 129 12;
+#X msg 175 129 11;
+#X msg 130 129 0;
+#X msg 87 55 bang;
+#X connect 1 0 2 0;
+#X connect 2 0 0 0;
+#X connect 3 0 2 1;
+#X connect 4 0 2 1;
+#X connect 5 0 2 1;
+#X connect 6 0 2 1;
+#X connect 7 0 2 0;
+#X connect 8 0 10 0;
+#X connect 9 0 2 0;
+#X connect 10 0 9 0;
+#X connect 10 1 2 0;
+#X connect 11 0 2 0;
+#X connect 12 0 11 1;
+#X connect 13 0 11 1;
+#X connect 14 0 15 0;
+#X connect 14 1 17 0;
+#X connect 14 2 16 0;
+#X connect 15 0 11 0;
+#X connect 16 0 2 0;
+#X connect 17 0 2 1;
+#X connect 18 0 14 0;
diff --git a/test/cyclone/tosymbol-test.pd b/test/cyclone/tosymbol-test.pd
new file mode 100644
index 0000000..f207831
--- /dev/null
+++ b/test/cyclone/tosymbol-test.pd
@@ -0,0 +1,44 @@
+#N canvas 200 14 639 535 12;
+#X obj 190 190 tosymbol;
+#X msg 201 84 test;
+#X obj 190 221 print;
+#X msg 190 51 symbol test;
+#X msg 259 84 bang;
+#X msg 265 150 1 2 3;
+#X msg 132 84 -0.99;
+#X msg 265 119 one two three;
+#X obj 28 221 prepend set;
+#X msg 28 257 test;
+#X msg 26 84 separator;
+#X msg 26 115 separator /;
+#X msg 405 119 one 2 3;
+#X msg 341 150 1 two three;
+#X msg 26 146 separator ----;
+#X obj 329 51 testmess 300;
+#X msg 414 20 test;
+#X msg 329 20 7e+10;
+#X msg 264 20 bang;
+#X obj 478 51 testmess 3000;
+#X msg 478 20 huge mess;
+#X obj 478 82 print;
+#X connect 0 0 2 0;
+#X connect 0 0 8 0;
+#X connect 1 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 0;
+#X connect 7 0 0 0;
+#X connect 8 0 9 0;
+#X connect 10 0 0 0;
+#X connect 11 0 0 0;
+#X connect 12 0 0 0;
+#X connect 13 0 0 0;
+#X connect 14 0 0 0;
+#X connect 15 0 0 0;
+#X connect 16 0 15 0;
+#X connect 17 0 15 0;
+#X connect 18 0 15 0;
+#X connect 19 0 0 0;
+#X connect 19 0 21 0;
+#X connect 20 0 19 0;
diff --git a/test/cyclone/train-test.pd b/test/cyclone/train-test.pd
new file mode 100644
index 0000000..cbf6c4a
--- /dev/null
+++ b/test/cyclone/train-test.pd
@@ -0,0 +1,17 @@
+#N canvas 450 299 450 300 12;
+#X floatatom 71 50 5 0 0 0 - - -;
+#X floatatom 95 77 5 0 0 0 - - -;
+#X floatatom 120 108 5 0 0 0 - - -;
+#X floatatom 71 229 5 0 0 0 - - -;
+#X obj 158 229 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 201 187 capture~;
+#X obj 71 144 train~;
+#X obj 71 187 Snapshot~ 20;
+#X connect 0 0 6 0;
+#X connect 1 0 6 1;
+#X connect 2 0 6 2;
+#X connect 6 0 5 0;
+#X connect 6 0 7 0;
+#X connect 6 1 4 0;
+#X connect 7 0 3 0;
diff --git a/test/cyclone/trig-test.pd b/test/cyclone/trig-test.pd
new file mode 100644
index 0000000..b4888f8
--- /dev/null
+++ b/test/cyclone/trig-test.pd
@@ -0,0 +1,66 @@
+#N canvas 337 140 550 476 12;
+#X obj 171 59 acos;
+#X floatatom 171 33 5 0 0 0 - - -;
+#X floatatom 171 88 0 0 0 0 - - -;
+#X msg 236 33 bang;
+#X floatatom 297 33 5 0 0 0 - - -;
+#X floatatom 297 88 0 0 0 0 - - -;
+#X obj 297 59 asin;
+#X floatatom 101 139 5 0 0 0 - - -;
+#X floatatom 101 194 0 0 0 0 - - -;
+#X obj 101 165 cosh;
+#X floatatom 230 139 5 0 0 0 - - -;
+#X floatatom 230 194 0 0 0 0 - - -;
+#X obj 230 165 sinh;
+#X floatatom 366 139 5 0 0 0 - - -;
+#X floatatom 366 194 0 0 0 0 - - -;
+#X obj 366 165 tanh;
+#X floatatom 40 320 5 0 0 0 - - -;
+#X floatatom 40 405 0 0 0 0 - - -;
+#X obj 40 346 cartopol;
+#X floatatom 107 376 0 0 0 0 - - -;
+#X floatatom 107 320 5 0 0 0 - - -;
+#X floatatom 196 320 5 0 0 0 - - -;
+#X floatatom 196 405 0 0 0 0 - - -;
+#X floatatom 263 376 0 0 0 0 - - -;
+#X floatatom 263 320 5 0 0 0 - - -;
+#X obj 196 346 poltocar;
+#X floatatom 346 320 5 0 0 0 - - -;
+#X floatatom 346 405 0 0 0 0 - - -;
+#X obj 346 346 cartopol;
+#X floatatom 413 376 0 0 0 0 - - -;
+#X floatatom 413 320 5 0 0 0 - - -;
+#X obj 40 282 MouseState;
+#X msg 40 253 poll;
+#X msg 95 253 nopoll;
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 6 0;
+#X connect 6 0 5 0;
+#X connect 7 0 9 0;
+#X connect 9 0 8 0;
+#X connect 10 0 12 0;
+#X connect 12 0 11 0;
+#X connect 13 0 15 0;
+#X connect 15 0 14 0;
+#X connect 16 0 18 0;
+#X connect 18 0 17 0;
+#X connect 18 0 25 0;
+#X connect 18 1 19 0;
+#X connect 18 1 25 1;
+#X connect 20 0 18 1;
+#X connect 21 0 25 0;
+#X connect 24 0 25 1;
+#X connect 25 0 22 0;
+#X connect 25 0 28 0;
+#X connect 25 1 23 0;
+#X connect 25 1 28 1;
+#X connect 26 0 28 0;
+#X connect 28 0 27 0;
+#X connect 28 1 29 0;
+#X connect 30 0 28 1;
+#X connect 31 1 16 0;
+#X connect 31 2 20 0;
+#X connect 32 0 31 0;
+#X connect 33 0 31 0;
diff --git a/test/cyclone/universal-test.pd b/test/cyclone/universal-test.pd
new file mode 100644
index 0000000..a1b083d
--- /dev/null
+++ b/test/cyclone/universal-test.pd
@@ -0,0 +1,55 @@
+#N canvas 329 126 483 198 12;
+#X obj 25 60 universal;
+#X msg 25 25 print bang;
+#X obj 26 112 print one;
+#X obj 27 152 print two;
+#N canvas 0 0 384 238 sub 0;
+#X obj 25 60 universal;
+#X msg 25 25 print bang;
+#X msg 159 25 print bang;
+#X obj 159 60 universal 1;
+#X obj 26 112 print sub-one;
+#X obj 27 152 print sub-two;
+#N canvas 0 0 390 231 sub-sub 0;
+#X obj 25 60 universal;
+#X msg 25 25 print bang;
+#X msg 159 25 print bang;
+#X obj 159 60 universal 1;
+#X obj 26 112 print sub-sub-one;
+#X obj 27 152 print sub-sub-two;
+#X connect 1 0 0 0;
+#X connect 2 0 3 0;
+#X restore 212 151 pd sub-sub;
+#X connect 1 0 0 0;
+#X connect 2 0 3 0;
+#X restore 163 152 pd sub;
+#X msg 327 25 print bang;
+#N canvas 0 0 384 238 zub 0;
+#X obj 25 60 universal;
+#X msg 25 25 print bang;
+#X msg 159 25 print bang;
+#X obj 159 60 universal 1;
+#X obj 26 112 print zub-one;
+#X obj 27 152 print zub-two;
+#N canvas 0 0 390 231 zub-zub 0;
+#X obj 25 60 universal;
+#X msg 25 25 print bang;
+#X msg 159 25 print bang;
+#X obj 159 60 universal 1;
+#X obj 26 112 print zub-zub-one;
+#X obj 27 152 print zub-zub-two;
+#X connect 1 0 0 0;
+#X connect 2 0 3 0;
+#X restore 212 151 pd zub-zub;
+#X connect 1 0 0 0;
+#X connect 2 0 3 0;
+#X restore 262 152 pd zub;
+#X obj 327 60 universal 1;
+#X msg 138 25 print;
+#X msg 206 25 print list;
+#X msg 137 74 list;
+#X connect 1 0 0 0;
+#X connect 5 0 7 0;
+#X connect 8 0 0 0;
+#X connect 9 0 0 0;
+#X connect 10 0 2 0;
diff --git a/test/cyclone/urn-test.pd b/test/cyclone/urn-test.pd
new file mode 100644
index 0000000..ab2787d
--- /dev/null
+++ b/test/cyclone/urn-test.pd
@@ -0,0 +1,15 @@
+#N canvas 433 476 450 300 12;
+#X obj 152 131 urn 10;
+#X obj 152 190 print;
+#X msg 152 73 bang;
+#X msg 220 73 clear;
+#X msg 94 73 99;
+#X msg 28 73 99.9;
+#X msg 295 72 10000;
+#X connect 0 0 1 0;
+#X connect 0 1 1 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 1;
diff --git a/test/cyclone/vectral-test.pd b/test/cyclone/vectral-test.pd
new file mode 100644
index 0000000..dad2343
--- /dev/null
+++ b/test/cyclone/vectral-test.pd
@@ -0,0 +1,56 @@
+#N canvas 368 287 673 449 12;
+#X obj 268 277 Scope~ 307 152 2 3 128 0 1 0 0 0 0 102 255 51 135 135
+135 0;
+#X floatatom 303 111 5 0 0 0 - - -;
+#X msg 404 171 2;
+#X floatatom 404 200 5 0 0 0 - - -;
+#X msg 503 226 bufsize \$1;
+#X floatatom 503 200 5 0 0 0 - - -;
+#X floatatom 18 80 5 0 0 0 - - -;
+#X floatatom 80 80 5 0 0 0 - - -;
+#X floatatom 370 111 5 0 0 0 - - -;
+#X obj 303 137 sig~;
+#X obj 18 106 sig~;
+#X obj 80 106 sig~;
+#X obj 370 137 phasor~ 0.5;
+#X obj 267 227 vectral~ 256;
+#X obj 9 15 block~ 256;
+#X msg 503 171 128;
+#X msg 404 226 range 0 1;
+#X msg 23 180 slide \$1;
+#X floatatom 23 154 5 0 0 0 - - -;
+#X obj 267 54 count~ 0 256 1 1;
+#X floatatom 27 221 5 0 0 0 - - -;
+#X msg 27 345 deltaclip \$1 \$2;
+#X obj 27 253 t 0 0;
+#X obj 67 286 * -1;
+#X obj 27 316 pack;
+#X obj 303 86 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 24 406 capture~ 256;
+#X connect 1 0 9 0;
+#X connect 2 0 3 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 4 0;
+#X connect 6 0 10 0;
+#X connect 7 0 11 0;
+#X connect 8 0 12 0;
+#X connect 9 0 13 2;
+#X connect 10 0 13 0;
+#X connect 11 0 13 1;
+#X connect 13 0 0 0;
+#X connect 13 0 26 0;
+#X connect 15 0 5 0;
+#X connect 16 0 0 0;
+#X connect 17 0 13 0;
+#X connect 18 0 17 0;
+#X connect 19 0 13 0;
+#X connect 19 0 13 1;
+#X connect 20 0 22 0;
+#X connect 21 0 13 0;
+#X connect 22 0 24 0;
+#X connect 22 1 23 0;
+#X connect 23 0 24 1;
+#X connect 24 0 21 0;
+#X connect 25 0 1 0;
diff --git a/test/cyclone/xbend-test.pd b/test/cyclone/xbend-test.pd
new file mode 100644
index 0000000..c7dcaa8
--- /dev/null
+++ b/test/cyclone/xbend-test.pd
@@ -0,0 +1,89 @@
+#N canvas 220 178 814 503 12;
+#X msg 124 18 145 \, 0 \, 64;
+#X msg 137 44 145 \, 1 \, 0;
+#X floatatom 39 18 5 0 0;
+#X msg 152 71 128 \, 2 \, 0;
+#X msg 42 71 1 2 3;
+#X msg 207 103 248;
+#X msg 160 103 240;
+#X obj 124 189 xbendin;
+#X obj 124 225 funnel 2;
+#X msg 198 143 224 \, 1 \, 2;
+#X obj 247 189 xbendin 1;
+#X obj 247 263 print single;
+#X obj 124 263 print omni;
+#X msg 311 143 225 \, 1 \, 2;
+#X msg 499 18 145 \, 0 \, 64;
+#X msg 512 44 145 \, 1 \, 0;
+#X floatatom 414 18 5 0 0;
+#X msg 527 71 128 \, 2 \, 0;
+#X msg 417 71 1 2 3;
+#X msg 582 103 248;
+#X msg 535 103 240;
+#X msg 573 143 224 \, 1 \, 2;
+#X obj 622 263 print single;
+#X obj 499 263 print omni;
+#X msg 686 143 225 \, 1 \, 2;
+#X obj 499 189 xbendin2;
+#X obj 499 225 funnel 3;
+#X obj 622 189 xbendin2 1;
+#X obj 622 225 funnel 2;
+#X obj 125 396 xbendout;
+#X obj 125 442 print;
+#X floatatom 125 327 5 0 0;
+#X floatatom 192 358 5 0 0;
+#X msg 50 358 bang;
+#X obj 424 438 print;
+#X floatatom 424 297 5 0 0;
+#X floatatom 462 327 5 0 0;
+#X msg 324 358 bang;
+#X obj 424 392 xbendout2;
+#X floatatom 500 358 5 0 0;
+#X msg 360 327 1 2 3;
+#X connect 0 0 7 0;
+#X connect 1 0 7 0;
+#X connect 2 0 7 0;
+#X connect 2 0 10 0;
+#X connect 3 0 7 0;
+#X connect 4 0 7 0;
+#X connect 4 0 10 0;
+#X connect 5 0 7 0;
+#X connect 6 0 7 0;
+#X connect 7 0 8 0;
+#X connect 7 1 8 1;
+#X connect 8 0 12 0;
+#X connect 9 0 7 0;
+#X connect 9 0 10 0;
+#X connect 10 0 11 0;
+#X connect 13 0 7 0;
+#X connect 13 0 10 0;
+#X connect 14 0 25 0;
+#X connect 15 0 25 0;
+#X connect 16 0 25 0;
+#X connect 16 0 27 0;
+#X connect 17 0 25 0;
+#X connect 18 0 25 0;
+#X connect 18 0 27 0;
+#X connect 19 0 25 0;
+#X connect 20 0 25 0;
+#X connect 21 0 25 0;
+#X connect 21 0 27 0;
+#X connect 24 0 25 0;
+#X connect 24 0 27 0;
+#X connect 25 0 26 0;
+#X connect 25 1 26 1;
+#X connect 25 2 26 2;
+#X connect 26 0 23 0;
+#X connect 27 0 28 0;
+#X connect 27 1 28 1;
+#X connect 28 0 22 0;
+#X connect 29 0 30 0;
+#X connect 31 0 29 0;
+#X connect 32 0 29 1;
+#X connect 33 0 29 0;
+#X connect 35 0 38 0;
+#X connect 36 0 38 1;
+#X connect 37 0 38 0;
+#X connect 38 0 34 0;
+#X connect 39 0 38 2;
+#X connect 40 0 38 0;
diff --git a/test/cyclone/xnote-test.pd b/test/cyclone/xnote-test.pd
new file mode 100644
index 0000000..8f9ac44
--- /dev/null
+++ b/test/cyclone/xnote-test.pd
@@ -0,0 +1,50 @@
+#N canvas 372 121 442 534 12;
+#X msg 124 18 145 \, 0 \, 64;
+#X msg 137 44 145 \, 1 \, 0;
+#X floatatom 39 18 5 0 0;
+#X msg 42 72 1 2 3;
+#X msg 207 103 248;
+#X msg 160 103 240;
+#X msg 198 143 224 \, 1 \, 2;
+#X obj 247 263 print single;
+#X obj 124 263 print omni;
+#X obj 116 482 print;
+#X floatatom 116 317 5 0 0;
+#X floatatom 138 341 5 0 0;
+#X msg 41 367 bang;
+#X obj 124 190 xnotein;
+#X obj 124 225 funnel 4;
+#X obj 247 225 funnel 3;
+#X obj 247 190 xnotein 2;
+#X msg 152 72 129 \, 2 \, 0;
+#X obj 116 436 xnoteout;
+#X floatatom 160 367 5 0 0;
+#X floatatom 183 392 5 0 0;
+#X connect 0 0 13 0;
+#X connect 0 0 16 0;
+#X connect 1 0 13 0;
+#X connect 1 0 16 0;
+#X connect 2 0 13 0;
+#X connect 2 0 16 0;
+#X connect 3 0 13 0;
+#X connect 3 0 16 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 13 0;
+#X connect 10 0 18 0;
+#X connect 11 0 18 1;
+#X connect 12 0 18 0;
+#X connect 13 0 14 0;
+#X connect 13 1 14 1;
+#X connect 13 2 14 2;
+#X connect 13 3 14 3;
+#X connect 14 0 8 0;
+#X connect 15 0 7 0;
+#X connect 16 0 15 0;
+#X connect 16 1 15 1;
+#X connect 16 2 15 2;
+#X connect 17 0 13 0;
+#X connect 17 0 16 0;
+#X connect 18 0 9 0;
+#X connect 19 0 18 2;
+#X connect 20 0 18 3;
diff --git a/test/cyclone/zl-test.pd b/test/cyclone/zl-test.pd
new file mode 100644
index 0000000..64900d0
--- /dev/null
+++ b/test/cyclone/zl-test.pd
@@ -0,0 +1,148 @@
+#N canvas 442 94 629 579 12;
+#X msg 196 21 bang;
+#X obj 196 161 zl group 3;
+#X msg 296 21 a b c;
+#X msg 62 133 symbol test;
+#X floatatom 54 171 5 0 0 0 - - -;
+#X msg 307 171 bang;
+#X msg 308 105 symbol test;
+#X floatatom 308 133 5 0 0 0 - - -;
+#X msg 29 21 b c d e f;
+#X msg 69 489 mode len \, debug \, bang \, mode previous \, debug;
+#X msg 433 77 2nd;
+#X msg 433 21 1st;
+#X obj 433 105 testmess 150;
+#X obj 433 49 testmess 150;
+#X msg 69 517 mode reg \, debug \, bang \, mode previous \, debug;
+#X msg 111 171 debug 1;
+#X msg 54 77 -1 -2 -3 -4 -5;
+#X msg 308 77 -4 -5 -6;
+#X obj 524 237 zl;
+#X msg 524 209 bang;
+#X msg 462 209 debug;
+#X msg 406 297 mode rev \, bang;
+#X msg 487 21 set 1000;
+#X msg 488 77 set 1000;
+#X msg 406 353 mode union \, bang;
+#X msg 406 325 mode sect \, bang;
+#X floatatom 49 301 5 0 0 0 - - -;
+#X msg 172 271 mode group \$1 \, bang;
+#X floatatom 49 276 5 0 0 0 - - -;
+#X msg 172 327 mode slice \$1 \, bang;
+#X msg 406 381 mode join \, bang;
+#X msg 172 243 mode iter \$1 \, bang;
+#X floatatom 49 326 5 0 0 0 - - -;
+#X floatatom 49 251 5 0 0 0 - - -;
+#X msg 172 299 mode rot \$1 \, bang;
+#X msg 172 355 mode ecils \$1 \, bang;
+#X floatatom 49 351 5 0 0 0 - - -;
+#X obj 196 189 print left;
+#X obj 307 199 print right;
+#X msg 172 383 mode nth \$1 \, bang;
+#N canvas 0 0 450 300 prev 0;
+#X obj 45 39 r doit;
+#X obj 173 246 outlet;
+#X obj 45 75 route mode;
+#X obj 173 211 prepend mode;
+#X obj 173 177 zl reg;
+#X msg 173 143 bang;
+#X obj 45 109 route len reg previous;
+#X msg 92 177 debug 1;
+#X connect 0 0 2 0;
+#X connect 2 0 6 0;
+#X connect 3 0 1 0;
+#X connect 4 0 3 0;
+#X connect 5 0 4 0;
+#X connect 6 2 5 0;
+#X connect 6 3 4 1;
+#X connect 7 0 4 0;
+#X restore 206 105 pd prev;
+#X obj 41 549 s doit;
+#X obj 359 458 s doit;
+#X obj 196 133 r doit;
+#X obj 409 133 s doit;
+#X obj 104 458 s doit;
+#X floatatom 49 382 5 0 0 0 - - -;
+#X floatatom 49 407 5 0 0 0 - - -;
+#X msg 172 411 mode nth \$1 x \, bang;
+#X msg 406 409 mode sub \, bang;
+#X obj 29 199 s doit;
+#X msg 62 105 1 1 2 2 1 2;
+#X msg 45 49 1 a b c test;
+#X msg 259 49 1 2;
+#X msg 308 49 148 149;
+#X msg 487 133 bang;
+#N canvas 419 256 450 300 more 0;
+#X obj 118 117 zl sub;
+#X obj 78 78 t a a;
+#X obj 51 185 print upto;
+#X obj 170 185 print downfrom;
+#X msg 78 42 a list with a pattern to split upon;
+#X msg 167 78 a pattern;
+#X obj 51 150 zl slice;
+#X msg 271 78 a list;
+#X msg 351 78 upon;
+#X msg 23 42 bang;
+#X obj 23 78 t b b;
+#X connect 0 0 6 1;
+#X connect 1 0 6 0;
+#X connect 1 1 0 0;
+#X connect 4 0 1 0;
+#X connect 5 0 0 1;
+#X connect 6 0 2 0;
+#X connect 6 1 3 0;
+#X connect 7 0 0 1;
+#X connect 8 0 0 1;
+#X connect 9 0 10 0;
+#X connect 10 0 6 0;
+#X connect 10 1 0 0;
+#X restore 396 251 pd more;
+#X connect 0 0 1 0;
+#X connect 1 0 37 0;
+#X connect 1 1 38 0;
+#X connect 2 0 1 1;
+#X connect 3 0 50 0;
+#X connect 4 0 50 0;
+#X connect 5 0 1 1;
+#X connect 6 0 1 1;
+#X connect 7 0 1 1;
+#X connect 8 0 50 0;
+#X connect 9 0 41 0;
+#X connect 10 0 12 0;
+#X connect 11 0 13 0;
+#X connect 12 0 1 1;
+#X connect 13 0 44 0;
+#X connect 14 0 41 0;
+#X connect 15 0 1 0;
+#X connect 16 0 50 0;
+#X connect 17 0 1 1;
+#X connect 19 0 18 0;
+#X connect 20 0 18 0;
+#X connect 21 0 42 0;
+#X connect 22 0 13 0;
+#X connect 23 0 12 0;
+#X connect 24 0 42 0;
+#X connect 25 0 42 0;
+#X connect 26 0 34 0;
+#X connect 27 0 45 0;
+#X connect 28 0 27 0;
+#X connect 29 0 45 0;
+#X connect 30 0 42 0;
+#X connect 31 0 45 0;
+#X connect 32 0 29 0;
+#X connect 33 0 31 0;
+#X connect 34 0 45 0;
+#X connect 35 0 45 0;
+#X connect 36 0 35 0;
+#X connect 39 0 45 0;
+#X connect 40 0 1 0;
+#X connect 43 0 1 0;
+#X connect 46 0 39 0;
+#X connect 47 0 48 0;
+#X connect 48 0 45 0;
+#X connect 49 0 42 0;
+#X connect 51 0 50 0;
+#X connect 52 0 50 0;
+#X connect 53 0 1 1;
+#X connect 54 0 1 1;
+#X connect 55 0 12 0;