[SCM] pd-iemutils/master: New upstream version 0.0.20161027

umlaeute at users.alioth.debian.org umlaeute at users.alioth.debian.org
Thu Oct 27 16:35:09 UTC 2016


The following commit has been merged in the master branch:
commit b8288d9be2dccbab2a1471b4e80fc52b006eec10
Author: IOhannes m zmölnig <zmoelnig at umlautQ.umlaeute.mur.at>
Date:   Thu Oct 27 16:42:33 2016 +0200

    New upstream version 0.0.20161027

diff --git a/DEVELOPER.md b/DEVELOPER.md
index d77736c..f0ab4cb 100644
--- a/DEVELOPER.md
+++ b/DEVELOPER.md
@@ -13,7 +13,7 @@ git-submodules.
 ~~~sh
 git clone https://git.iem.at/pd/iem_utils
 cd iem_utils
-git submodule update
+git submodule update --init
 ~~~
 
 ## Building
diff --git a/Makefile b/Makefile
index a5b2f4b..aaa5b18 100644
--- a/Makefile
+++ b/Makefile
@@ -1,13 +1,17 @@
-all: iem_adaptfilt iem_dp iem_roomsim iem_spec2 iem_tab
+subprojects = iem_adaptfilt iem_dp iem_roomsim iem_spec2 iem_tab punish
+all: $(subprojects)
 
 .PHONY: all clean archive release dummy
-.PHONY: iem_adaptfilt iem_dp iem_roomsim iem_spec2 iem_tab
+.PHONY: $(subprojects)
 
 
 library=iem_utils
 version=0.0.$(shell date +%Y%m%d)
 archivefile=$(library)-v$(version).tgz
 
+IEM_CFLAGS=-DPD $(CPPFLAGS) -fPIC $(CFLAGS)
+IEM_LDFLAGS=--export-dynamic -fPIC -shared $(LDFLAGS)
+
 clean:
 	-find . -name "*.o" -delete
 	-find . -name "*.pd_*" -delete
@@ -26,9 +30,9 @@ release: $(archivefile)
 	-rm -f $@
 	tar --transform "s|^|$(@:.tgz=)/|" --exclude-vcs --exclude='.gitmodules' --exclude $@ -czf $@ *
 
-iem_adaptfilt:
-	make -C iem_adaptfilt/src -f makefile_lin \
-		CFLAGS="-DPD -fPIC" \
-		LDFLAGS="--export-dynamic -fPIC -shared"
+iem_adaptfilt punish:
+	$(MAKE) -C $@ \
+		$(empty)
 iem_dp iem_roomsim iem_spec2 iem_tab:
-	make -C $@/src -f makefile_linux
+	$(MAKE) -C $@/src -f makefile_linux \
+		CFLAGS="$(IEM_CFLAGS)" LDFLAGS="$(IEM_LDFLAGS)"
diff --git a/README.md b/README.md
index 8541331..50e20ce 100644
--- a/README.md
+++ b/README.md
@@ -54,3 +54,13 @@ https://git.iem.at/pd-gui/patch2svg-plugin
 pd-gui plugin that (re)adds a wee tcl-prompt to the Pd-console
 
 https://git.iem.at/pd-gui/tclprompt-plugin
+
+### punish/triggerize-plugin
+pd-gui plugin that helps avoiding fan-outs by inserting [trigger] as appropriate.
+
+https://git.iem.at/pd-gui/punish
+
+### punish/patcherize-plugin
+pd-gui plugin that helps refactoring code into abstraction/subpatches.
+
+https://git.iem.at/pd-gui/punish
diff --git a/iem_adaptfilt/Makefile b/iem_adaptfilt/Makefile
new file mode 100644
index 0000000..e5db989
--- /dev/null
+++ b/iem_adaptfilt/Makefile
@@ -0,0 +1,33 @@
+#!/usr/bin/make -f
+# Makefile to the 'iemguts' library for Pure Data.
+# Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build
+# settings and rules (https://github.com/pure-data/pd-lib-builder).
+
+lib.name = iem_adaptfilt
+
+# special file that does not provide a class
+lib.setup.sources = src/iem_adaptfilt.c
+
+# all other C and C++ files in subdirs are source files per class
+# (alternatively, enumerate them by hand)
+class.sources = $(filter-out $(lib.setup.sources),$(wildcard src/*.c))
+
+datafiles = \
+$(wildcard help/*.pd) \
+AUTHORS.txt \
+GnuGPL.txt \
+VERSION.txt
+
+datadirs =  doc
+
+cflags = -DVERSION=$(shell cat VERSION.txt)
+
+################################################################################
+### pdlibbuilder ###############################################################
+################################################################################
+
+# This Makefile is based on the Makefile from pd-lib-builder written by
+# Katja Vetter. You can get it from:
+# https://github.com/pure-data/pd-lib-builder
+PDLIBBUILDER_DIR=pd-lib-builder/
+include $(firstword $(wildcard $(PDLIBBUILDER_DIR)/Makefile.pdlibbuilder Makefile.pdlibbuilder))
diff --git a/iem_adaptfilt/Makefile.pdlibbuilder b/iem_adaptfilt/Makefile.pdlibbuilder
new file mode 100644
index 0000000..8be6339
--- /dev/null
+++ b/iem_adaptfilt/Makefile.pdlibbuilder
@@ -0,0 +1,1212 @@
+# Makefile.pdlibbuilder dated 2016-10-27
+version = 0.4.1
+
+# Helper makefile for Pure Data external libraries.
+# Written by Katja Vetter March-June 2015 for the public domain. No warranties.
+# Inspired by Hans Christoph Steiner's Makefile Template and Stephan Beal's
+# ShakeNMake.
+#
+# GNU make version >= 3.81 required.
+#
+#
+#=== characteristics ===========================================================
+#
+#
+# - defines build settings based on autodetected OS and architecture
+# - defines rules to build Pd class- or lib executables from C or C++ sources
+# - defines rules for libdir installation
+# - defines convenience targets for developer and user
+# - evaluates implicit dependencies for non-clean builds
+#
+#
+#=== basic usage ===============================================================
+#
+#
+# In your Makefile, define your Pd lib name and class files, and include
+# Makefile.pdlibbuilder at the end of the Makefile. Like so:
+#
+#    ________________________________________________________________________
+#
+#     # Makefile for mylib
+#
+#     lib.name = mylib
+#
+#     class.sources = myclass1.c myclass2.c
+#
+#     datafiles = myclass1-help.pd myclass2-help.pd README.txt LICENSE.txt
+#
+#     include Makefile.pdlibbuilder
+#    ________________________________________________________________________
+#
+#
+# For files in class.sources it is assumed that class basename == source file
+# basename. The default target builds all classes as individual executables
+# with Pd's default extension for the platform. For anything more than the
+# most basic usage, continue reading.
+#
+#
+#=== list of Makefile.pdlibbuilder API variables ===============================
+#
+#
+# Variables available for definition in your library Makefile:
+#
+# - lib.name
+# - lib.setup.sources
+# - class.sources
+# - common.sources
+# - shared.sources
+# - <classname>.class.sources
+# - <classname>.class.ldflags
+# - <classname>.class.ldlibs
+# - cflags
+# - ldflags
+# - ldlibs
+# - datafiles
+# - datadirs
+# - makefiles
+# - makefiledirs
+# - externalsdir
+#
+# Optional multiline defines evaluated per operating system:
+#
+# - forLinux
+# - forDarwin
+# - forWindows
+#
+# Variables available for your makefile or make command line:
+#
+# - make-lib-executable
+# - suppress-wunused
+#
+# Path variables for make command line or environment:
+#
+# - PDDIR
+# - PDINCLUDEDIR
+# - PDBINDIR
+# - PDLIBDIR
+#
+# Standard make variables for make command line or environment:
+#
+# - CPPFLAGS
+# - CFLAGS
+# - LDFLAGS
+# - CC
+# - CXX
+# - INSTALL
+# - DESTDIR
+#
+# Deprecated path variables:
+#
+# - PD_PATH
+# - pdincludepath
+# - pdbinpath
+# - objectsdir
+#
+#
+#=== descriptions of Makefile.pdlibbuilder API variables =======================
+#
+#
+# lib.name: 
+# Name of the library directory as it will be installed / distributed. Also the
+# name of the lib executable in the case where all classes are linked into
+# a single binary.
+#
+# lib.setup.sources:
+# Source file(s) (C or C++) which must be compiled only when linking all classes
+# into a single lib binary.
+#
+# class.sources:
+# All sources files (C or C++) for which the condition holds that 
+# class name == source file basename.
+#
+# <classname>.class.sources:
+# Source file(s) (C or C++) specific to class <classname>. Use this for
+# multiple-source classes or when class name != source file basename.
+#
+# common.sources:
+# Source file(s) which must be statically linked to each class in the library.
+#
+# shared.sources:
+# Source file(s) (C or C++) to build a shared dynamic link lib, to be linked
+# with all class executables.
+#
+# cflags, ldflags, ldlibs:
+# Define cflags (preprocessor&compiler), ldflags (linker) and ldlibs (dynamic
+# link libs) for the whole library. These flags are added to platform-specific
+# flags defined by Makefile.pdlibbuilder.
+#
+# <classname>.class.ldflags and <classname>.class.ldlibs: 
+# Define ldflags resp. ldlibs specific to class <classname>. These flags are
+# added to platform-specific flags defined by Makefile.pdlibbuilder, and flags
+# defined in your Makefile for the whole library. Note: cflags can not be
+# defined per class in the current implementation.
+#
+# datafiles and datadirs: 
+# All extra files you want to include in binary distributions of the
+# library: abstractions and help patches, example patches, meta patch, readme
+# and license texts, manuals, sound files, etcetera. Use 'datafiles' for all
+# files that should go into your lib rootdir and 'datadirs' for complete
+# directories you want to copy from source to distribution.
+#
+# forLinux, forDarwin, forWindows:
+# Shorthand for 'variable definitions for Linux only' etc. Use like:
+#    define forLinux
+#      cflags += -DLINUX
+#      class.sources += linuxthing.c
+#    endef
+#
+# makefiles and makefiledirs: 
+# Extra makefiles or directories with makefiles that should be made in sub-make
+# processes.
+#
+# make-lib-executable:
+# When this variable is defined 'yes' in your makefile or as command argument,
+# Makefile.pdlibbuilder will try to build all classes into a single library
+# executable (but it will force exit if lib.setup.sources is undefined).
+# If your makefile defines 'make-lib-executable=yes' as the library default,
+# this can still be overriden with 'make-lib-executable=no' as command argument 
+# to build individual class executables (the Makefile.pdlibbuilder default.)
+#
+# suppress-wunused:
+# When this variable is defined ('yes' or any other value), -Wunused-variable,
+# -Wunused-parameter, -Wunused-value and -Wunused-function are suppressed,
+# but the other warnings from -Wall are retained.
+#
+# PDDIR:
+# Root directory of 'portable' pd package. When defined, PDINCLUDEDIR and 
+# PDBINDIR will be evaluated as $(PDDIR)/src and $(PDDIR)/bin.
+#
+# PDINCLUDEDIR:
+# Directory where Pd API m_pd.h should be found, and other Pd header files.
+# Overrides the default search path.
+#
+# PDBINDIR:
+# Directory where pd.dll should be found for linking (Windows only). Overrides
+# the default search path.
+#
+# PDLIBDIR:
+# Root directory for installation of Pd library directories. Overrides the
+# default install location.
+#
+# DESTDIR:
+# Prepended path component for staged install.
+#
+# CPPFLAGS:
+# Preprocessor flags which are not strictly required for building.
+#
+# CFLAGS:
+# Compiler flags which are not strictly required for building. Compiler flags
+# defined by Makefile.pdlibbuilder for warning, optimization and architecture
+# specification are overriden by CFLAGS.
+#
+# LDFLAGS:
+# Linker flags which are not strictly required for building. Linker flags
+# defined by Makefile.pdlibbuilder for architecture specification are overriden
+# by LDFLAGS.
+#
+# CC and CXX:
+# C and C++ compiler programs as defined in your build environment.
+#
+# INSTALL
+# Definition of install program.
+#
+# PD_PATH:
+# Equivalent to PDDIR. Supported for compatibility with pd-extended central
+# makefile, but deprecated otherwise.
+#
+# objectsdir:
+# Root directory for installation of Pd library directories, like PDLIBDIR but
+# not overridable by environment. Supported for compatibility with pd-extended
+# central makefile, but deprecated otherwise.
+#
+# pdincludepath, pdbinpath:
+# As PDINCLUDEDIR and PDBINDIR but not overridable by environment. Deprecated
+# as user variables.
+#
+#
+#=== paths =====================================================================
+#
+#
+# Source files in directories other than current working directory must be
+# prefixed with their relative path. Do not rely on VPATH or vpath.
+# Object (.o) files are built in the directory of their source files.
+# Executables are built in current working directory. 
+#
+# Default search path for m_pd.h and other API header files is platform 
+# dependent, and overridable by PDINCLUDEDIR:
+#
+# Linux:    /usr/include/pd
+#
+# OSX:      /Applications/Pd*.app/Contents/Resources/src
+#
+# Windows:  %PROGRAMFILES%/pd/src
+#
+# Default location to install pd libraries is platform dependent, and
+# overridable by PDLIBDIR:
+#
+# Linux:    /usr/local/lib/pd-externals
+# OSX:      ~/Library/Pd
+# Windows:  %APPDATA%/Pd
+#
+# https://puredata.info/docs/faq/how-do-i-install-externals-and-help-files
+# The rationale for not installing to ~/pd-externals by default on Linux
+# is that some people share the home dir between 32 and 64 bit installations.
+#
+#
+#=== targets ===================================================================
+#
+#
+# all: build $(executables) plus optional post target
+# post: target to build after $(executables)
+# alldebug: build all with -g option turned on for debug symbols
+# <classname>: force clean build of an individual class
+# <sourcefile>.pre: make preprocessor output file in current working directory
+# <sourcefile>.lst: make asm/source output file in current working directory
+#
+# install: install executables and data files
+# clean: remove build products from source tree
+#
+# help: print help text
+# vars: print makefile variables
+# allvars: print all variables
+# depend: print generated prerequisites
+# coffee: dummy target
+#
+# Variable $(executables) expands to class executables plus optional shared lib,
+# or alternatively to single lib executable when make-lib-executable=true.
+# Targets pre and post can be defined by library makefile. Make sure to include
+# Makefile.pdlibbuilder first so default target all will not be redefined.
+#
+#
+#=== Pd-extended libdir concept ================================================
+#
+#
+# For libdir layout as conceived by Hans-Christoph Steiner, see:
+#
+# https://puredata.info/docs/developer/Libdir
+#
+# Files README.txt, LICENSE.txt and <lib.name>-meta.pd are part of the libdir
+# convention. Help patches for each class and abstraction are supposed to be
+# available. Makefile.pdlibbuilder does not force the presence of these files
+# however. It does not automatically include such files in libdir installations.
+# Data files you want to include in distributions must be defined explicitly in
+# your Makefile.
+#
+#
+#=== Makefile.pdlibbuilder syntax conventions ==================================
+#
+#
+# Makefile.pdlibbuilder variable names are lower case. Default make variables,
+# environment variables, and standard user variables (CC, CXX, CFLAGS, DESTDIR)
+# are upper case. Use target 'allvars' to print all variables and their values.
+#
+# 'Fields' in data variables are separated by dots, like in 'foo.class.sources'.
+# Words in variables expressing a function or command are separated by dashes, 
+# like in 'make-lib-executable'.
+#
+#
+#=== useful make options =======================================================
+#
+#
+# Use 'make -d <target>' to print debug details of the make process.
+# Use 'make -p <target>' to print make's database.
+#
+#
+#=== TODO ======================================================================
+#
+#
+# - decide whether to use -static-libgcc or shared dll in MinGW
+# - cygwin support
+# - android support
+# - Windows 64 bit support
+# - figure out how to handle '$' in filenames
+# - add makefile template targets dpkg-source dist libdir distclean tags?
+#
+#
+#=== end of documentation sections =============================================
+#
+# 
+################################################################################
+################################################################################
+################################################################################
+
+
+# GNU make version 3.81 (2006) or higher is required because of the following:
+# - function 'info'
+# - variable '.DEFAULT_GOAL'
+
+# force exit when make version is < 3.81
+ifneq ($(firstword $(sort 3.81 $(MAKE_VERSION))), 3.81)
+  $(error GNU make version 3.81 or higher is required)
+endif
+
+# Relative path to externals root dir in multi-lib source tree like 
+# pd-extended SVN. Default is parent of current working directory. May be
+# defined differently in including makefile.
+externalsdir ?= ..
+
+# variable you can use to check if Makefile.pdlibbuilder is already included
+Makefile.pdlibbuilder = true
+
+
+################################################################################
+### variables: library name and version ########################################
+################################################################################
+
+
+# strip possibles spaces from lib.name, they mess up calculated file names
+lib.name := $(strip $(lib.name))
+
+# if meta file exists, check library version 
+metafile := $(wildcard $(lib.name)-meta.pd)
+
+ifdef metafile
+  lib.version := $(shell sed -n \
+    's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' \
+    $(metafile))
+endif
+
+
+################################################################################
+### variables: files ###########################################################
+################################################################################
+
+
+#=== sources ===================================================================
+
+
+# (re)define <classname>.class.sources using file names in class.sources
+
+define add-class-source
+$(notdir $(basename $v)).class.sources += $v
+endef
+
+$(foreach v, $(class.sources), $(eval $(add-class-source)))
+
+# derive class names from <classname>.class.sources variables
+sourcevariables := $(filter %.class.sources, $(.VARIABLES))
+classes := $(basename $(basename $(sourcevariables)))
+
+# accumulate all source files specified in makefile
+classes.sources := $(sort $(foreach v, $(sourcevariables), $($v)))
+all.sources := $(classes.sources) $(lib.setup.sources) \
+  $(shared.sources) $(common.sources)
+
+
+#=== object files ==============================================================
+
+
+# construct object filenames from all C and C++ source file names
+classes.objects := $(addsuffix .o, $(basename $(classes.sources)))
+common.objects := $(addsuffix .o, $(basename $(common.sources)))
+shared.objects := $(addsuffix .o, $(basename $(shared.sources)))
+lib.setup.objects := $(addsuffix .o, $(basename $(lib.setup.sources)))
+all.objects = $(classes.objects) $(common.objects) $(shared.objects) \
+  $(lib.setup.objects)
+
+
+#=== executables ===============================================================
+
+
+# use recursive variables here because executable extension is not yet known
+
+# construct class executable names from class names
+classes.executables = $(addsuffix .$(extension), $(classes))
+
+# construct shared lib executable name if shared sources are defined
+ifdef shared.sources
+  shared.lib = lib$(lib.name).$(shared.extension)
+else
+  shared.lib =
+endif
+
+
+################################################################################
+### variables per platform #####################################################
+################################################################################
+
+
+#=== flags per architecture ====================================================
+
+
+# Set architecture-dependent cflags, mainly for Linux. For Mac and Windows, 
+# arch.c.flags are overriden below.
+
+machine := $(shell uname -m)
+
+# Raspberry Pi 1st generation
+ifeq ($(machine), armv6l)
+  arch.c.flags = -march=armv6 -mfpu=vfp -mfloat-abi=hard
+endif
+
+# Beagle, Udoo, RPi2 etc.
+ifeq ($(machine), armv7l)
+  arch.c.flags = -march=armv7-a -mfpu=vfpv3 -mfloat-abi=hard
+endif
+
+# Intel 32 bit, build with SSE and SSE2 instructions
+ifeq ($(findstring $(machine), i386 i686), $(machine))
+  arch.c.flags = -march=pentium4 -mfpmath=sse -msse -msse2
+endif
+
+# Intel/AMD 64 bit, build with SSE, SSE2 and SSE3 instructions
+ifeq ($(findstring $(machine), ia64 x86_64), $(machine))
+  arch.c.flags = -march=core2 -mfpmath=sse -msse -msse2 -msse3 
+endif
+
+
+#=== operating system ==========================================================
+
+
+# The following systems are defined: Linux, Darwin, Windows. GNU and
+# GNU/kFreeBSD are treated as Linux to get the same options. System-specific
+# multiline defines (optionally set in library makefile) are conditionally
+# evaluated here.
+
+uname := $(shell uname)
+
+ifeq ($(findstring $(uname), Linux GNU GNU/kFreeBSD), $(uname))
+  system = Linux
+  $(eval $(forLinux))
+endif
+
+ifeq ($(uname), Darwin)
+  system = Darwin
+  $(eval $(forDarwin))
+endif
+
+ifeq ($(findstring MINGW, $(uname)), MINGW)
+  system = Windows
+  $(eval $(forWindows))
+endif
+
+# TODO: Cygwin, Android
+
+
+#=== flags and paths for Linux =================================================
+
+
+ifeq ($(system), Linux)
+  prefix = /usr/local
+  libdir := $(prefix)/lib
+  pkglibdir = $(libdir)/pd-externals
+  pdincludepath := $(wildcard /usr/include/pd)
+  extension = pd_linux
+  cpp.flags := -DUNIX
+  c.flags := -fpic
+  c.ldflags := -rdynamic -shared -fpic -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags
+  c.ldlibs := -lc -lm
+  cxx.flags := -fpic -fcheck-new
+  cxx.ldflags := -rdynamic -shared -fpic -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags
+  cxx.ldlibs := -lc -lm -lstdc++
+  shared.extension = so
+  shared.ldflags := -rdynamic -fpic -shared -Wl,-soname,$(shared.lib)
+  stripflags = --strip-unneeded -R .note -R .comment
+endif
+
+
+#=== flags and paths for Darwin ================================================
+
+
+# On OSX we try to build fat binaries by default. It is assumed that OSX i386
+# can build for ppc and OSX x86_64 can't. TODO: try to refine this condition.
+# LLVM-clang doesn't support -fcheck-new, therefore this flag is omitted for
+# OSX x86_64.
+
+
+ifeq ($(system), Darwin)
+  pkglibdir = $(HOME)/Library/Pd
+  pdincludepath := $(firstword $(wildcard \
+    /Applications/Pd*.app/Contents/Resources/src))
+  extension = pd_darwin
+  cpp.flags := -DUNIX -DMACOSX -I /sw/include
+  c.flags := 
+  c.ldflags := -undefined suppress -flat_namespace -bundle
+  c.ldlibs := -lc
+  cxx.ldflags := -undefined suppress -flat_namespace -bundle
+  cxx.ldlibs := -lc
+  shared.extension = dylib
+  shared.ldflags = -dynamiclib -undefined dynamic_lookup \
+    -install_name @loader_path/$(shared.lib) \
+    -compatibility_version 1 -current_version 1.0
+  stripflags = -x
+  version.flag := $(filter $(cflags), -mmacosx-version-min=%)
+  ifeq ($(machine), i386)
+    cxx.flags := -fcheck-new
+    arch := ppc i386 x86_64
+    version.flag ?= -mmacosx-version-min=10.4
+  endif
+  ifeq ($(machine), x86_64)
+    arch := i386 x86_64
+    version.flag ?= -mmacosx-version-min=10.5
+  endif
+  arch.c.flags := $(addprefix -arch , $(arch)) $(version.flag)
+  arch.ld.flags := $(arch.c.flags)
+endif
+
+
+#=== flags and paths for Windows ===============================================
+
+
+# Standard paths on Windows contain spaces, and GNU make functions treat such
+# paths as lists, with unintended effects. Therefore we must use shell function
+# ls instead of make's wildcard, and probe for each standard path individually.
+# Using double quotes around paths with spaces is obligatory. Since some path
+# variables are assembled or re-expanded later, great care must be taken to put
+# quotes at appropriate points throughout the makefile. Thanks, Bill.
+
+# paths for 32-bit executables on 64-bit Windows aren't yet defined here (TODO)
+ifeq ($(system), Windows)
+  pkglibdir := $(APPDATA)/Pd
+  ifndef pdbinpath
+    pdbinpath := $(shell ls -d "$(PROGRAMFILES)/pd/bin")
+  endif
+  ifndef pdincludepath
+    pdincludepath := $(shell ls -d "$(PROGRAMFILES)/pd/src")
+  endif
+endif
+
+# On Windows we build 32 bit by default to match Pd(-extended) binary 
+# distributions. This may change in the future.
+# TODO: decide whether -mms-bitfields should be specified.
+ifeq ($(system), Windows)
+  extension = dll
+  CC = gcc
+  CXX = g++
+  arch.c.flags := -march=pentium4 -msse -msse2 -mfpmath=sse
+  cpp.flags := -DMSW -DNT
+  c.flags :=
+  c.ldflags = -static-libgcc -shared \
+    -Wl,--enable-auto-import "$(pdbinpath)/pd.dll"
+  c.ldlibs :=
+  cxx.flags := -fcheck-new
+  cxx.ldflags = -static-libstdc++ -shared \
+    -Wl,--enable-auto-import "$(pdbinpath)/pd.dll"
+  cxx.ldlibs :=
+  shared.extension = dll
+  shared.ldflags = -static-libgcc -shared "$(pdbinpath)/pd.dll"
+  stripflags = --strip-unneeded -R .note -R .comment
+endif
+
+
+#=== paths =====================================================================
+
+
+# Platform-dependent default paths are specified above, but overridable.
+# Path variables in upper case can be defined as make command argument or in the
+# environment. 'PD_PATH' and 'objectsdir' are supported for compatibility with
+# the build system that pd-l2ork has inherited from pd-extended.
+
+PDDIR ?= $(PD_PATH)
+PDINCLUDEDIR ?= $(pdincludepath)
+PDBINDIR ?= $(pdbinpath)
+PDLIBDIR ?= $(firstword $(objectsdir) $(pkglibdir))
+
+ifneq ($(PDDIR),)
+  PDINCLUDEDIR := $(wildcard $(PDDIR)/src)
+  PDBINDIR := $(wildcard $(PDDIR)/bin)
+endif
+
+# base path where all components of the lib will be installed by default
+installpath := $(DESTDIR)$(PDLIBDIR)/$(lib.name)
+
+# check if include path contains spaces (as is often the case on Windows)
+# if so, store the path so we can later do checks with it
+pdincludepathwithspaces := $(if $(word 2, $(PDINCLUDEDIR)), $(PDINCLUDEDIR))
+
+
+#=== accumulated build flags ===================================================
+
+
+# From GNU make docs: 'Users expect to be able to specify CFLAGS freely
+# themselves.' So we use CFLAGS to define options which  are not strictly
+# required for compilation: optimizations, architecture specifications, and 
+# warnings. CFLAGS can be safely overriden using a make command argument.
+# Variables cflags, ldflags and ldlibs may be defined in including makefile.
+
+optimization.flags = -O3 -ffast-math -funroll-loops -fomit-frame-pointer
+warn.flags = -Wall -Wextra -Wshadow -Winline -Wstrict-aliasing
+
+# suppress -Wunused-variable & Co if you don't want to clutter a build log
+ifdef suppress-wunused
+  warn.flags += $(addprefix -Wno-unused-, function parameter value variable)
+endif
+
+CFLAGS = $(warn.flags) $(optimization.flags) $(arch.c.flags)
+
+# preprocessor flags
+cpp.flags := -DPD -I "$(PDINCLUDEDIR)" $(cpp.flags) $(CPPFLAGS)
+
+# flags for dependency checking (cflags from makefile may define -I options)
+depcheck.flags := $(cpp.flags) $(cflags)
+
+# architecture specifications for linker are overridable by LDFLAGS
+LDFLAGS := $(arch.ld.flags)
+
+# now add the same ld flags to shared dynamic lib
+shared.ldflags := $(shared.ldflags) $(LDFLAGS)
+
+# accumulated flags for C compiler / linker
+c.flags := $(cpp.flags) $(c.flags) $(cflags) $(CFLAGS)
+c.ldflags := $(c.ldflags) $(ldflags) $(LDFLAGS)
+c.ldlibs := $(c.ldlibs) $(ldlibs)
+
+# accumulated flags for C++ compiler / linker
+cxx.flags := $(cpp.flags) $(cxx.flags) $(cflags) $(CFLAGS)
+cxx.ldflags := $(cxx.ldflags) $(ldflags) $(LDFLAGS)
+cxx.ldlibs := $(cxx.ldlibs) $(ldlibs)
+
+
+################################################################################
+### variables: tools ###########################################################
+################################################################################
+
+
+# aliases so we can later define 'compile-$1' and set 'c' or 'cxx' as argument
+compile-c := $(CC)
+compile-cxx := $(CXX)
+
+
+################################################################################
+### checks #####################################################################
+################################################################################
+
+
+# At this point most variables are defined. Now do some checks and info's
+# before rules begin.
+
+# 'forward declaration' of default target, needed to do checks
+all:
+
+# To avoid unpredictable results, make sure the default target is not redefined
+# by including makefile. 
+ifneq ($(.DEFAULT_GOAL), all)
+  $(error Default target must be 'all'.)
+endif
+
+# find out which target(s) will be made
+ifdef MAKECMDGOALS
+  goals := $(MAKECMDGOALS)
+else
+  goals := all
+endif
+
+# store path to Pd API m_pd.h if it is found
+ifdef pdincludepath
+  mpdh := $(shell ls "$(PDINCLUDEDIR)/m_pd.h")
+endif
+
+# print Makefile.pdlibbuilder version
+$(info ++++ info: using Makefile.pdlibbuilder version $(version))
+
+# when making target all, check if m_pd.h is found and print info about it
+ifeq ($(goals), all)
+  $(if $(mpdh), \
+    $(info ++++ info: using Pd API $(mpdh)), \
+    $(warning Where is Pd API m_pd.h? Do 'make help' for info.))
+endif
+
+# print target info
+$(info ++++ info: making target $(goals) $(if $(lib.name),in lib $(lib.name)))
+
+# when installing, print installpath info
+$(if $(filter install install-lib, $(goals)), $(info ++++ info: \
+  installpath is '$(installpath)'))
+
+
+#=== define executables ========================================================
+
+
+# By default we build class executables, and optionally a shared dynamic link
+# lib. When make-lib-executable=yes we build all classes into a single lib
+# executable, on the condition that variable lib.setup.sources is defined.
+
+ifeq ($(make-lib-executable),yes)
+  $(if $(lib.setup.sources), ,\
+    $(error Can not build library blob because lib.setup.sources is undefined))
+  executables := $(lib.name).$(extension)
+else
+  executables := $(classes.executables) $(shared.lib)
+endif
+
+
+################################################################################
+### rules: special targets #####################################################
+################################################################################
+
+
+# Disable built-in rules. If some target can't be built with the specified
+# rules, it should not be built at all.
+MAKEFLAGS += --no-builtin-rules
+
+.PRECIOUS:
+.SUFFIXES:
+.PHONY: all post build-lib \
+        $(classes) $(makefiledirs) $(makefiles) \
+        install install-executables install-datafiles install-datadirs \
+        force clean vars allvars depend help
+
+
+################################################################################
+### rules: build targets #######################################################
+################################################################################
+
+
+# Target all forces the build of targets [$(executables) post] in
+# deterministic order. Target $(executables) builds class executables plus 
+# optional shared lib or alternatively a single lib executable when 
+# make-lib-executable=true. Target post is optionally defined by
+# library makefile.
+
+all: post
+post: $(executables)
+
+all:
+	$(info ++++info: target all in lib $(lib.name) completed)
+
+# build all with -g option turned on for debug symbols
+alldebug: c.flags += -g
+alldebug: cxx.flags += -g
+alldebug: all
+
+
+#=== class executable ==========================================================
+
+
+# recipe for linking objects in class executable
+# argument $1 = compiler type (c or cxx)
+# argument $2 = class basename
+define link-class
+  $(compile-$1) \
+  $($1.ldflags) $($2.class.ldflags) \
+  -o $2.$(extension) \
+  $(addsuffix .o, $(basename $($2.class.sources))) \
+  $(addsuffix .o, $(basename $(common.sources))) \
+  $($1.ldlibs) $($2.class.ldlibs) $(shared.lib)
+endef
+
+# general rule for linking object files in class executable
+%.$(extension): $(shared.lib)
+	$(info ++++ info: linking objects in $@ for lib $(lib.name))
+	$(if $(filter %.cc %.cpp, $($*.class.sources)), \
+        $(call link-class,cxx,$*), \
+        $(call link-class,c,$*))
+
+
+#=== library blob ==============================================================
+
+
+# build all classes into single executable
+build-lib: $(lib.name).$(extension)
+	$(info ++++ info: library blob $(lib.name).$(extension) completed)
+
+# recipe for linking objects in lib executable
+# argument $1 = compiler type (c or cxx)
+define link-lib
+  $(compile-$1) \
+  $($1.ldflags) $(lib.ldflags) \
+  -o $(lib.name).$(extension) $(all.objects) \
+  $($1.ldlibs) $(lib.ldlibs)
+endef
+
+# rule for linking objects in lib executable
+# declared conditionally to avoid name clashes
+ifeq ($(make-lib-executable),yes)
+$(lib.name).$(extension): $(all.objects)
+	$(if $(filter %.cc %.cpp, $(all.sources)), \
+        $(call link-lib,cxx), \
+        $(call link-lib,c))
+endif
+
+
+#=== shared dynamic lib ========================================================
+
+
+# recipe for linking objects in shared executable
+# argument $1 = compiler type (c or cxx)
+define link-shared
+  $(compile-$1) \
+  $(shared.ldflags) \
+  -o lib$(lib.name).$(shared.extension) $(shared.objects) \
+  $($1.ldlibs) $(shared.ldlibs)
+endef
+
+# rule for linking objects in shared executable
+# build recipe is in macro 'link-shared'
+lib$(lib.name).$(shared.extension): $(shared.objects)
+	$(info ++++ info: linking objects in shared lib $@)
+	$(if $(filter %.cc %.cpp, $(shared.sources)), \
+        $(call link-shared,cxx), \
+        $(call link-shared,c))
+
+
+#=== object files ==============================================================
+
+
+# recipe to make .o file from source
+# argument $1 is compiler type (c or cxx)
+define make-object-file
+  $(info ++++ info: making $@ in lib $(lib.name))
+  $(compile-$1) \
+  $($1.flags) \
+  -o $@ -c $<
+endef
+
+# Three rules to create .o files. These are double colon 'terminal' rules,
+# meaning they are the last in a rules chain.
+
+%.o:: %.c
+	$(call make-object-file,c)
+
+%.o:: %.cc
+	$(call make-object-file,cxx)
+
+%.o:: %.cpp
+	$(call make-object-file,cxx)
+
+
+#=== explicit prerequisites for class executables ==============================
+
+
+# For class executables, prerequisite rules are declared in run time. Target
+# 'depend' prints these rules for debugging purposes.
+
+# declare explicit prerequisites rule like 'class: class.extension'
+# argument $v is class basename
+define declare-class-target
+$v: $v.$(extension)
+endef
+
+# declare explicit prerequisites rule like 'class.extension: object1.o object2.o'
+# argument $v is class basename
+define declare-class-executable-target
+$v.$(extension): $(addsuffix .o, $(basename $($v.class.sources))) \
+  $(addsuffix .o, $(basename $(common.sources)))
+endef
+
+# evaluate explicit prerequisite rules for all classes
+$(foreach v, $(classes), $(eval $(declare-class-target)))
+$(foreach v, $(classes), $(eval $(declare-class-executable-target)))
+
+
+#=== implicit prerequisites for class executables ==============================
+
+
+# Evaluating implicit prerequisites (header files) with help from the
+# preprocessor is 'expensive' so this is done conditionally and selectively.
+# Note that it is also possible to trigger a build via install targets, in
+# which case implicit prerequisites are not checked.
+
+# When the Pd include path contains spaces it will mess up the implicit
+# prerequisites rules.
+disable-dependency-tracking := $(strip $(pdincludepathwithspaces))
+
+ifndef disable-dependency-tracking
+  must-build-everything := $(filter all, $(goals))
+  must-build-class := $(filter $(classes), $(goals))
+  must-build-sources := $(foreach v, $(must-build-class), $($v.class.sources))
+endif
+
+# declare implicit prerequisites rule like 'object.o: header1.h header2.h ...'
+# argument $1 is input source file(s)
+# dir is explicitly added because option -MM strips it by default
+define declare-object-target
+$(dir $1)$(filter %.o: %.h, $(shell $(CPP) $(depcheck.flags) -MM $1)) $(MAKEFILE_LIST)
+endef
+
+# evaluate implicit prerequisite rules when rebuilding everything
+ifdef must-build-everything
+  $(if $(wildcard $(all.objects)), \
+  $(info ++++ info: evaluating implicit prerequisites in lib $(lib.name).....) \
+  $(foreach v, $(all.sources), $(eval $(call declare-object-target, $v))))
+endif
+
+# evaluate implicit prerequisite rules when selectively building classes
+ifdef must-build-class
+  $(foreach v, $(must-build-sources), \
+  $(eval $(call declare-object-target, $v)))
+  $(foreach v, $(shared.sources), \
+  $(eval $(call declare-object-target, $v)))
+endif
+
+
+################################################################################
+### rules: preprocessor and assembly files #####################################
+################################################################################
+
+
+# Preprocessor and assembly output files for bug tracing etc. They are not part
+# of the build processes for executables. By default these files are created in
+# the current working directory. Dependency tracking is not performed, the build
+# is forced instead to make sure it's up to date.
+
+force:
+
+
+#=== preprocessor file =========================================================
+
+
+# make preprocessor output file with extension .pre
+# argument $1 = compiler type (c or cxx)
+define make-preprocessor-file
+  $(info ++++ info: making preprocessor output file $(notdir $*.pre) \
+  in current working directory)
+  $(compile-$1) -E $< $(c.flags) $($1.flags) -o $(notdir $*.pre)
+endef
+
+%.pre:: %.c force
+	$(call make-preprocessor-file,c)
+
+%.pre:: %.cc force
+	$(call make-preprocessor-file,cxx)
+
+%.pre:: %.cpp force 
+	$(call make-preprocessor-file,cxx)
+
+
+#=== assembly file =============================================================
+
+
+# make C / assembly interleaved output file with extension .lst
+# argument $1 = compiler type (c or cxx)
+define make-assembly-file
+  $(info ++++ info: making assembly output file $(notdir $*.lst) \
+  in current working directory)
+  $(compile-$1) \
+  -c -Wa,-a,-ad -fverbose-asm \
+  $($1.flags) \
+  $< > $(notdir $*.lst)
+endef
+
+%.lst:: %.c force
+	$(call make-assembly-file,c)
+
+%.lst:: %.cc force
+	$(call make-assembly-file,cxx)
+
+%.lst:: %.cpp force
+	$(call make-assembly-file,cxx)
+
+
+################################################################################
+### rules: installation targets ################################################
+################################################################################
+
+
+# Install targets depend on successful exit status of target all because nothing
+# must be installed in case of a build error.
+
+
+# -p = preserve time stamps
+# -m = set permission mode (as in chmod)
+# -d = create all components of specified directories
+INSTALL = install
+INSTALL_PROGRAM := $(INSTALL) -p -m 644
+INSTALL_DATA := $(INSTALL) -p -m 644
+INSTALL_DIR := $(INSTALL) -m 755 -d
+
+# strip spaces from file names
+executables := $(strip $(executables))
+datafiles := $(strip $(datafiles))
+datadirs := $(strip $(datadirs))
+
+# Do not make any install sub-target with empty variable definition because the
+# install program would exit with an error.
+install: $(if $(executables), install-executables)
+install: $(if $(datafiles), install-datafiles)
+install: $(if $(datadirs), install-datadirs)
+
+install-executables: all
+	$(INSTALL_DIR) -v "$(installpath)"
+	$(foreach v, $(executables), \
+	$(INSTALL_PROGRAM) '$v' "$(installpath)";)
+	$(info ++++ info: executables of lib $(lib.name) installed \
+        from $(CURDIR) to $(installpath))
+
+install-datafiles: all
+	$(INSTALL_DIR) -v "$(installpath)"
+	$(foreach v, $(datafiles), \
+	$(INSTALL_DATA) '$(v)' "$(installpath)";)
+	$(info ++++ info: data files of lib $(lib.name) installed \
+        from $(CURDIR) to $(installpath))
+
+install-datadirs: all
+	$(foreach v, $(datadirs), $(INSTALL_DIR) "$(installpath)/$v";)
+	$(foreach v, $(datadirs), \
+        $(INSTALL_DATA) $(wildcard $v/*) "$(installpath)/$v";)
+	$(info ++++ info: data directories of lib $(lib.name) installed \
+        from $(CURDIR) to $(installpath))
+
+
+################################################################################
+### rules: distribution targets ################################################
+################################################################################
+
+
+# TODO
+# These targets are implemented in Makefile Template, but I have to figure out
+# how to do it under the not-so-strict conditions of Makefile.pdlibbuilder.
+
+# make source package
+dist:
+	@echo "target dist not yet implemented"
+
+# make Debian source package
+dpkg-source:
+	@echo "target dpkg-source not yet implemented"
+
+$(ORIGDIR):
+
+$(DISTDIR):
+
+
+################################################################################
+### rules: clean targets #######################################################
+################################################################################
+
+
+# delete build products from build tree
+clean:
+	rm -f $(all.objects)
+	rm -f $(classes.executables) $(lib.name).$(extension) $(shared.lib)
+	rm -f *.pre *.lst
+
+# remove distribution directories and tarballs from build tree
+distclean: clean
+	@echo "target distclean not yet implemented"
+
+
+################################################################################
+### rules: submake targets #####################################################
+################################################################################
+
+
+# Iterate over sub-makefiles or makefiles in other directories.
+
+# When 'continue-make=yes' is set, sub-makes will report 'true' to the parent
+# process regardless of their real exit status. This prevents the parent make
+# from being aborted by a sub-make error. Useful when you want to quickly find
+# out which sub-makes from a large set will succeed.
+ifeq ($(continue-make),yes)
+  continue = || true
+endif
+
+# These targets will trigger sub-make processes for entries in 'makefiledirs'
+# and 'makefiles'.
+all alldebug install clean distclean dist dkpg-source: \
+        $(makefiledirs) $(makefiles)
+
+# this expands to identical rules for each entry in 'makefiledirs'
+$(makefiledirs):
+	$(MAKE) --directory=$@ $(MAKECMDGOALS) $(continue)
+
+# this expands to identical rules for each entry in 'makefiles'
+$(makefiles):
+	$(MAKE) --directory=$(dir $@) --makefile=$(notdir $@) $(MAKECMDGOALS) $(continue)
+
+
+################################################################################
+### rules: convenience targets #################################################
+################################################################################
+
+
+#=== show variables ============================================================
+
+
+# Several 'function' macro's cause errors when expanded within a rule or without
+# proper arguments. Variables which are set with the define directive are only
+# shown by name for that reason.
+functions = \
+add-class-source \
+declare-class-target \
+declare-class-executable-target \
+declare-object-target \
+link-class \
+link-lib \
+link-shared \
+make-object-file \
+make-preprocessor-file \
+make-assembly-file
+
+
+# show variables from makefiles
+vars:
+	$(info ++++ info: showing makefile variables:)
+	$(foreach v,\
+        $(sort $(filter-out $(functions) functions, $(.VARIABLES))),\
+        $(if $(filter file, $(origin $v)),\
+        $(info variable $v = $($v))))
+	$(foreach v, $(functions), $(info 'function' name: $v))
+	@echo
+
+# show all variables
+allvars:
+	$(info ++++ info: showing default, automatic and makefile variables:)
+	$(foreach v, \
+        $(sort $(filter-out $(functions) functions, $(.VARIABLES))), \
+        $(info variable ($(origin $v)) $v = $($v)))
+	$(foreach v, $(functions), $(info 'function' name: $v))
+	@echo
+
+
+#=== show dependencies =========================================================
+
+
+# show generated prerequisites rules
+depend:
+	$(info ++++ info: generated prerequisite rules)
+	$(foreach v, $(classes), $(info $(declare-class-target)))
+	$(foreach v, $(classes), $(info $(declare-class-executable-target)))
+	$(foreach v, $(all.sources), $(info $(call declare-object-target, $v)))
+	@echo
+
+
+#=== show help text ============================================================
+
+
+# brief info about targets and paths
+
+ifdef mpdh
+  mpdhinfo := $(mpdh)
+else
+  mpdhinfo := m_pd.h was not found. Is Pd installed?
+endif
+
+help:
+	@echo
+	@echo "  Main targets:"
+	@echo "    all:     build executables (default target)"
+	@echo "    install: install all components of the library"
+	@echo "    vars:    print makefile variables for troubleshooting"
+	@echo "    allvars: print all variables for troubleshooting"
+	@echo "    help:    print this help text"
+	@echo
+	@echo "  Pd API m_pd.h:"
+	@echo "    $(mpdhinfo)"
+	@echo "  You may specify your preferred Pd include directory as argument"
+	@echo "  to the make command, like 'PDINCLUDEDIR=path/to/pd/src'."
+	@echo
+	@echo "  Path for installation of your libdir(s):"
+	@echo "    $(PDLIBDIR)"
+	@echo "  Alternatively you may specify your path for installation as argument"
+	@echo "  to the make command, like 'PDLIBDIR=path/to/pd-externals'."
+	@echo
+	@echo "  Default paths are listed in the doc sections in Makefile.pdlibbuilder."
+	@echo
+
+
+#=== dummy target ==============================================================
+
+
+coffee:
+	@echo "Makefile.pdlibbuilder: Can not make coffee. Sorry."
+
+
+################################################################################
+### end of rules sections ######################################################
+################################################################################
+
+
+# for syntax highlighting in vim and github
+# vim: set filetype=make:
+
diff --git a/patch2svg-plugin/README.md b/patch2svg-plugin/README.md
index 4153467..448c95a 100644
--- a/patch2svg-plugin/README.md
+++ b/patch2svg-plugin/README.md
@@ -1,12 +1,34 @@
 Save Pd patches as SVG
-===
+======================
 
-This adds a new menu-item to the "File" menu: "Save patch as image..."
+This adds a new menu-item to the "File" menu: "Save patch as SVG..."
 
 It allows you to save the current Pd patch as an SVG graphics.
 
 ## Installing
-simply copy the [patch2svg-plugin.tcl](https://git.iem.at/pd-gui/patch2svg-plugin/raw/master/patch2svg-plugin.tcl) into your Pd searchpath.
+Simply copy the [patch2svg-plugin.tcl](https://git.iem.at/pd-gui/patch2svg-plugin/raw/master/patch2svg-plugin.tcl) into your Pd searchpath.
+
+## Repository
+
+The official repository is
+
+   https://git.iem.at/pd-gui/patch2svg-plugin/
+
+There is also a mirror on github:
+
+   https://github.com/iem-projects/patch2svg-plugin
+
+## Reporting Issues
+If you have discovered a bug or are missing some functionality, please do not
+hestitate to let me know.
+We are currently accepting bug-reports (and pull-requests) on our github mirror:
+
+  https://github.com/iem-projects/patch2svg-plugin/issues
+
+### Translating
+If you want the "Save patch as SVG..." menu-entry to be displayed in another
+language, please send me a translation (you can use the patch-tracker for this).
+
 
 ## AUTHORS
 
diff --git a/patch2svg-plugin/patch2svg-plugin.tcl b/patch2svg-plugin/patch2svg-plugin.tcl
index 4f8e411..e86205e 100644
--- a/patch2svg-plugin/patch2svg-plugin.tcl
+++ b/patch2svg-plugin/patch2svg-plugin.tcl
@@ -4,6 +4,10 @@
 # META VERSION 0.1
 
 package require pdwindow 0.1
+if [catch {
+    package require msgcat
+    ::msgcat::mcload po
+}] { puts "patch2svg: i18n failed" }
 
 #package require uriencode
 #package require tinyfileutils
@@ -1673,7 +1677,7 @@ proc focus {winid state} {
 
 proc register {} {
     # create an entry for our "print2svg" in the "file" menu
-    set ::patch2svg::label [_ "Export patch as image..."]
+    set ::patch2svg::label [_ "Export patch as SVG..."]
     set mymenu .menubar.file
     if {$::windowingsystem eq "aqua"} {
         set inserthere 8
@@ -1683,20 +1687,24 @@ proc register {} {
     #$mymenu insert $inserthere separator
     $mymenu insert $inserthere command \
         -label $::patch2svg::label \
+        -state disabled \
         -command {::patch2svg::menu_export $::focused_window}
     # bind all <$::modifier-Key-s> {::deken::open_helpbrowser .helpbrowser2}
     bind PatchWindow <FocusIn> "+::patch2svg::focus %W 1"
     bind PdWindow    <FocusIn> "+::patch2svg::focus %W 0"
 
-    ::pd_connect::register_plugin_dispatch_receiver ::patch2svg::exportall ::patch2svg::exportall
+    set rpdr ::pd_connect::register_plugin_dispatch_receiver
+    if {[info procs $rpdr] == $rpdr} {
+	${rpdr} ::patch2svg::exportall ::patch2svg::exportall
+    }
 
     pdtk_post "loaded patch2svg-plugin\n"
-}
 
-}
 
 
-::patch2svg::register
+}
 
+}
 
 
+::patch2svg::register
diff --git a/patch2svg-plugin/po/Makefile b/patch2svg-plugin/po/Makefile
new file mode 100644
index 0000000..18ae3e8
--- /dev/null
+++ b/patch2svg-plugin/po/Makefile
@@ -0,0 +1,49 @@
+
+PACKAGE_NAME = patch to SVG
+PACKAGE_VERSION = 1.0
+TCLFILES = patch2svg-plugin.tcl
+
+# we use all language files found here
+POFILES=$(wildcard *.po)
+MSGFILES=$(POFILES:.po=.msg)
+
+TEMPLATE = patch2svg.pot
+FILES = $(addprefix ../, $(TCLFILES))
+
+# generate .msg files from the .po files
+all: $(TEMPLATE) $(MSGFILES)
+
+# refresh .po files from the template
+clean:
+	-rm -f -- $(MSGFILES)
+	-rm -f -- $(POFILES:=~)
+	-rm -f -- $(TEMPLATE)
+distclean: clean
+
+po: $(TEMPLATE) $(POFILES)
+
+$(TEMPLATE): $(FILES)
+	touch $(TEMPLATE)
+	xgettext --join-existing \
+		--from-code=UTF-8 --language=Tcl --keyword=_ \
+		--sort-output --no-location --output=$(TEMPLATE) \
+		--package-name="$(PACKAGE_NAME)" \
+		--package-version=$(PACKAGE_VERSION) \
+		--copyright-holder='This file is put in the public domain' \
+		--foreign-user \
+		--msgid-bugs-address=http://bugs.puredata.info \
+		$(FILES)
+
+$(POFILES): $(TEMPLATE)
+	touch $@
+	msgmerge --sort-output --no-fuzzy-matching --no-location --update $@ $(TEMPLATE)
+
+%.msg: %.po
+	msgfmt --check --tcl --locale=$* -d . $<
+
+
+#install: $(MSGFILES)
+#	install -d $(DESTDIR)
+#	install $(MSGFILES) $(DESTDIR)
+install:
+	@echo "nothing to install"
diff --git a/patch2svg-plugin/po/de.po b/patch2svg-plugin/po/de.po
new file mode 100644
index 0000000..e7fd4dd
--- /dev/null
+++ b/patch2svg-plugin/po/de.po
@@ -0,0 +1,21 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: http://bugs.puredata.info\n"
+"POT-Creation-Date: 2016-02-17 22:39+0100\n"
+"PO-Revision-Date: \n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.8.7\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+# SOME DESCRIPTIVE TITLE.
+# This file is put in the public domain.
+# FIRST AUTHOR <EMAIL at ADDRESS>, YEAR.
+#
+msgid "Export patch as SVG..."
+msgstr "Patch als SVG exportieren..."
diff --git a/punish/.travis.yml b/punish/.travis.yml
new file mode 100644
index 0000000..2cebe99
--- /dev/null
+++ b/punish/.travis.yml
@@ -0,0 +1,29 @@
+language: c
+sudo: required
+dist: trusty
+
+env:
+  global:
+        - secure: "VtjMps4NzAMe2I3/CClJ6r8XJeXZ+4dtQR2EIul+IgPNhCexLA96Y9MLjXaE90+frOYZvuQUN/WXjqRrc5M3PgsaRnSRqlpqQSQX47AII/qoY8xf/mEJ2fn/QhF63XDRe+91cVFNG5MHUKLPDcl3QhiPBUmkN8eJtFDPrtXZiU+2zGs+sbyqB/E5BCvQAq1QCqSNbI/JUTQpcafbQf11rrzfsJBo9e/C/VK6rK+LB8Xch1ajiKPlud/VL8RXef8DfReOSsQ0LP0VI1Aj4tQs17zqKXOaUiMQUav3s7qTcIuLVaYf6w0bY3a6URV59Lj5F9+B7gkbwuAJLNPO8Dv87WeIZE8NreszPRLsTUoLrsq8OgDKiYEi4dfZH1vPpF8YhkQy+eaWImi7l7E5NNzi/k8oa6Ej/1P3aRvMuivpX8c0GRJDF5LOowG8WfGF8IkW1KeoRvYM/N7ZnIzppeMgEhKx6V+cXY1RZDUjgCO5hjUUhi9Yj1JRuInPoc5pycG0HbaMwVaZe+zyiTWRX7takuh0gQrsq1r6jg7PkcU+V8+U7QiXfwfp8KzMSr0TZxiw7DDO/Fzckg0wTsFb6Ya7RTvQPx7hM84RJ6eXzt0a+ixkKEntKaljTaW2pKvqFuTjHYq7ybisf6dnR6mjk02uqigvoVaZclDR/stLeWTqf5Q="
+        - COVERITY_SCAN_BRANCH_PATTERN="(master|coverity-.*)"
+        - COVERITY_SCAN_NOTIFICATION_EMAIL="dev at umlaeute.mur.at"
+        - COVERITY_SCAN_BUILD_COMMAND="make"
+
+matrix:
+  include:
+    - compiler: clang
+    - compiler: gcc
+      env:
+        - COVERITY_SCAN_PROJECT_NAME="$TRAVIS_REPO_SLUG"
+
+before_install:
+- sudo apt-get update -qq
+- sudo apt-get install -qq puredata-dev
+
+before_script:
+  # implement Coverity Scan with before_script instead of addons.coverity_scan
+  # to work around too-early quota check by the coverity_scan addon
+  - if [[ -n $COVERITY_SCAN_PROJECT_NAME ]] ; then curl -s 'https://scan.coverity.com/scripts/travisci_build_coverity_scan.sh' | bash || true ; fi
+
+script:
+- make
diff --git a/punish/Makefile b/punish/Makefile
new file mode 100644
index 0000000..be58ae7
--- /dev/null
+++ b/punish/Makefile
@@ -0,0 +1,12 @@
+subprojects=patcherize triggerize
+
+.PHONY: all $(subprojects)
+all: $(subprojects)
+$(subprojects):
+	$(MAKE) -C $@-plugin
+
+.PHONY: clean $(subprojects%=%-clean)
+clean: $(subprojects:%=%-clean)
+$(subprojects:%=%-clean):
+	$(MAKE) -C $(@:%-clean=%-plugin) clean
+
diff --git a/punish/README.md b/punish/README.md
new file mode 100644
index 0000000..6bb5f52
--- /dev/null
+++ b/punish/README.md
@@ -0,0 +1,29 @@
+punish - IEM's Pure Data User Interface Hacks
+=============================================
+
+a collection of hacks for the Pd User Interface
+
+# BIG FAT WARNING
+
+This collection is intended to explore ideas on how to improve Pd's user
+interface (from a library perspective).
+
+There are known crasher bugs.
+
+# Contents
+
+## [patcherize](patcherize-plugin)
+turn selected objects into a subpatch (or abstraction)
+
+## [triggerize](triggerize-plugin)
+- replace fan-outs with [trigger]s
+- expand [trigger] to the *left*
+- insert [trigger] into wires
+
+# LICENSE
+
+each hack comes with its own license
+
+# AUTHORS
+
+- IOhannes m zmölnig
diff --git a/punish/patcherize-plugin/LICENSE.md b/punish/patcherize-plugin/LICENSE.md
new file mode 100644
index 0000000..74d573e
--- /dev/null
+++ b/punish/patcherize-plugin/LICENSE.md
@@ -0,0 +1,344 @@
+GNU GENERAL PUBLIC LICENSE
+==========================
+Version 2, June 1991
+
+> Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA  
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+# Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+
+#                     GNU GENERAL PUBLIC LICENSE                    #
+## TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ##
+
+- *0\.* This License applies to any program or other work which contains
+	a notice placed by the copyright holder saying it may be distributed
+	under the terms of this General Public License.  The "Program", below,
+	refers to any such program or work, and a "work based on the Program"
+	means either the Program or any derivative work under copyright law:
+	that is to say, a work containing the Program or a portion of it,
+	either verbatim or with modifications and/or translated into another
+	language.  (Hereinafter, translation is included without limitation in
+	the term "modification".)  Each licensee is addressed as "you".
+	
+	Activities other than copying, distribution and modification are not
+	covered by this License; they are outside its scope.  The act of
+	running the Program is not restricted, and the output from the Program
+	is covered only if its contents constitute a work based on the
+	Program (independent of having been made by running the Program).
+	Whether that is true depends on what the Program does.
+
+- 1\. You may copy and distribute verbatim copies of the Program's
+	source code as you receive it, in any medium, provided that you
+	conspicuously and appropriately publish on each copy an appropriate
+	copyright notice and disclaimer of warranty; keep intact all the
+	notices that refer to this License and to the absence of any warranty;
+	and give any other recipients of the Program a copy of this License
+	along with the Program.
+
+	You may charge a fee for the physical act of transferring a copy, and
+	you may at your option offer warranty protection in exchange for a fee.
+
+- 2\. You may modify your copy or copies of the Program or any portion
+	of it, thus forming a work based on the Program, and copy and
+	distribute such modifications or work under the terms of Section 1
+	above, provided that you also meet all of these conditions:
+
+		a) You must cause the modified files to carry prominent notices
+		stating that you changed the files and the date of any change.
+		
+		b) You must cause any work that you distribute or publish, that in
+		whole or in part contains or is derived from the Program or any
+		part thereof, to be licensed as a whole at no charge to all third
+		parties under the terms of this License.
+		
+		c) If the modified program normally reads commands interactively
+		when run, you must cause it, when started running for such
+		interactive use in the most ordinary way, to print or display an
+		announcement including an appropriate copyright notice and a
+		notice that there is no warranty (or else, saying that you provide
+		a warranty) and that users may redistribute the program under
+		these conditions, and telling the user how to view a copy of this
+		License.  (Exception: if the Program itself is interactive but
+		does not normally print such an announcement, your work based on
+		the Program is not required to print an announcement.)
+
+	These requirements apply to the modified work as a whole.  If
+	identifiable sections of that work are not derived from the Program,
+	and can be reasonably considered independent and separate works in
+	themselves, then this License, and its terms, do not apply to those
+	sections when you distribute them as separate works.  But when you
+	distribute the same sections as part of a whole which is a work based
+	on the Program, the distribution of the whole must be on the terms of
+	this License, whose permissions for other licensees extend to the
+	entire whole, and thus to each and every part regardless of who wrote it.
+	
+	Thus, it is not the intent of this section to claim rights or contest
+	your rights to work written entirely by you; rather, the intent is to
+	exercise the right to control the distribution of derivative or
+	collective works based on the Program.
+	
+	In addition, mere aggregation of another work not based on the Program
+	with the Program (or with a work based on the Program) on a volume of
+	a storage or distribution medium does not bring the other work under
+	the scope of this License.
+
+- 3\. You may copy and distribute the Program (or a work based on it,
+	under Section 2) in object code or executable form under the terms of
+	Sections 1 and 2 above provided that you also do one of the following:
+
+    	a) Accompany it with the complete corresponding machine-readable
+    	source code, which must be distributed under the terms of Sections
+    	1 and 2 above on a medium customarily used for software interchange; or,
+
+    	b) Accompany it with a written offer, valid for at least three
+    	years, to give any third party, for a charge no more than your
+    	cost of physically performing source distribution, a complete
+    	machine-readable copy of the corresponding source code, to be
+    	distributed under the terms of Sections 1 and 2 above on a medium
+    	customarily used for software interchange; or,
+
+    	c) Accompany it with the information you received as to the offer
+    	to distribute corresponding source code.  (This alternative is
+    	allowed only for noncommercial distribution and only if you
+    	received the program in object code or executable form with such
+    	an offer, in accord with Subsection b above.)
+
+	The source code for a work means the preferred form of the work for
+	making modifications to it.  For an executable work, complete source
+	code means all the source code for all modules it contains, plus any
+	associated interface definition files, plus the scripts used to
+	control compilation and installation of the executable.  However, as a
+	special exception, the source code distributed need not include
+	anything that is normally distributed (in either source or binary
+	form) with the major components (compiler, kernel, and so on) of the
+	operating system on which the executable runs, unless that component
+	itself accompanies the executable.
+	
+	If distribution of executable or object code is made by offering
+	access to copy from a designated place, then offering equivalent
+	access to copy the source code from the same place counts as
+	distribution of the source code, even though third parties are not
+	compelled to copy the source along with the object code.
+
+- 4\. You may not copy, modify, sublicense, or distribute the Program
+	except as expressly provided under this License.  Any attempt
+	otherwise to copy, modify, sublicense or distribute the Program is
+	void, and will automatically terminate your rights under this License.
+	However, parties who have received copies, or rights, from you under
+	this License will not have their licenses terminated so long as such
+	parties remain in full compliance.
+
+- 5\. You are not required to accept this License, since you have not
+	signed it.  However, nothing else grants you permission to modify or
+	distribute the Program or its derivative works.  These actions are
+	prohibited by law if you do not accept this License.  Therefore, by
+	modifying or distributing the Program (or any work based on the
+	Program), you indicate your acceptance of this License to do so, and
+	all its terms and conditions for copying, distributing or modifying
+	the Program or works based on it.
+
+- 6\. Each time you redistribute the Program (or any work based on the
+	Program), the recipient automatically receives a license from the
+	original licensor to copy, distribute or modify the Program subject to
+	these terms and conditions.  You may not impose any further
+	restrictions on the recipients' exercise of the rights granted herein.
+	You are not responsible for enforcing compliance by third parties to
+	this License.
+
+- 7\. If, as a consequence of a court judgment or allegation of patent
+	infringement or for any other reason (not limited to patent issues),
+	conditions are imposed on you (whether by court order, agreement or
+	otherwise) that contradict the conditions of this License, they do not
+	excuse you from the conditions of this License.  If you cannot
+	distribute so as to satisfy simultaneously your obligations under this
+	License and any other pertinent obligations, then as a consequence you
+	may not distribute the Program at all.  For example, if a patent
+	license would not permit royalty-free redistribution of the Program by
+	all those who receive copies directly or indirectly through you, then
+	the only way you could satisfy both it and this License would be to
+	refrain entirely from distribution of the Program.
+	
+	If any portion of this section is held invalid or unenforceable under
+	any particular circumstance, the balance of the section is intended to
+	apply and the section as a whole is intended to apply in other
+	circumstances.
+	
+	It is not the purpose of this section to induce you to infringe any
+	patents or other property right claims or to contest validity of any
+	such claims; this section has the sole purpose of protecting the
+	integrity of the free software distribution system, which is
+	implemented by public license practices.  Many people have made
+	generous contributions to the wide range of software distributed
+	through that system in reliance on consistent application of that
+	system; it is up to the author/donor to decide if he or she is willing
+	to distribute software through any other system and a licensee cannot
+	impose that choice.
+	
+	This section is intended to make thoroughly clear what is believed to
+	be a consequence of the rest of this License.
+
+- 8\. If the distribution and/or use of the Program is restricted in
+	certain countries either by patents or by copyrighted interfaces, the
+	original copyright holder who places the Program under this License
+	may add an explicit geographical distribution limitation excluding
+	those countries, so that distribution is permitted only in or among
+	countries not thus excluded.  In such case, this License incorporates
+	the limitation as if written in the body of this License.
+	
+- 9\. The Free Software Foundation may publish revised and/or new versions
+	of the General Public License from time to time.  Such new versions will
+	be similar in spirit to the present version, but may differ in detail to
+	address new problems or concerns.
+	
+	Each version is given a distinguishing version number.  If the Program
+	specifies a version number of this License which applies to it and "any
+	later version", you have the option of following the terms and conditions
+	either of that version or of any later version published by the Free
+	Software Foundation.  If the Program does not specify a version number of
+	this License, you may choose any version ever published by the Free Software
+	Foundation.
+	
+- 10\. If you wish to incorporate parts of the Program into other free
+	programs whose distribution conditions are different, write to the author
+	to ask for permission.  For software which is copyrighted by the Free
+	Software Foundation, write to the Free Software Foundation; we sometimes
+	make exceptions for this.  Our decision will be guided by the two goals
+	of preserving the free status of all derivatives of our free software and
+	of promoting the sharing and reuse of software generally.
+
+
+## NO WARRANTY
+
+- 11\. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+	FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+	OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+	PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+	OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+	MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+	TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+	PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+	REPAIR OR CORRECTION.
+	
+- 12\. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+	WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+	REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+	INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+	OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+	TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+	YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+	PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+	POSSIBILITY OF SUCH DAMAGES.
+
+##                      END OF TERMS AND CONDITIONS                      ##
+
+---------------------------------------------------------------------------
+
+###            How to Apply These Terms to Your New Programs            ###
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+  Also add information on how to contact you by electronic and paper mail.
+
+  If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+  The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+  You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+	Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+	`Gnomovision' (which makes passes at compilers) written by James Hacker.
+	
+	<signature of Ty Coon>, 1 April 1989
+	Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/punish/patcherize-plugin/Makefile b/punish/patcherize-plugin/Makefile
new file mode 100755
index 0000000..226a9bb
--- /dev/null
+++ b/punish/patcherize-plugin/Makefile
@@ -0,0 +1,30 @@
+#!/usr/bin/make -f
+# Makefile for pure data externals in lib creb.
+# Needs Makefile.pdlibbuilder to work (https://github.com/pure-data/pd-lib-builder)
+
+lib.name = patcherize-plugin
+
+# special file that does not provide a class
+lib.setup.sources = 
+
+# all other C and C++ files in subdirs are source files per class
+# (alternatively, enumerate them by hand)
+class.sources = patcherize.c
+
+datafiles = \
+$(wildcard *-help.pd) \
+patcherize-plugin.tcl \
+README.md LICENSE.md
+
+datadirs =  
+
+################################################################################
+### pdlibbuilder ###############################################################
+################################################################################
+
+
+# Include Makefile.pdlibbuilder from this directory, or else from the general
+# 'punish' folder
+
+include $(firstword $(wildcard ../Makefile.pdlibbuilder Makefile.pdlibbuilder))
+
diff --git a/punish/patcherize-plugin/Makefile.pdlibbuilder b/punish/patcherize-plugin/Makefile.pdlibbuilder
new file mode 100644
index 0000000..a91bb39
--- /dev/null
+++ b/punish/patcherize-plugin/Makefile.pdlibbuilder
@@ -0,0 +1,1201 @@
+# Makefile.pdlibbuilder version 0.2.3, dated 2016-03-29
+#
+# Helper makefile for Pure Data external libraries.
+# Written by Katja Vetter March-June 2015 for the public domain. No warranties.
+# Inspired by Hans Christoph Steiner's Makefile Template and Stephan Beal's
+# ShakeNMake.
+#
+# GNU make version >= 3.81 required.
+#
+#
+#=== characteristics ===========================================================
+#
+#
+# - defines build settings based on autodetected OS and architecture
+# - defines rules to build Pd class- or lib executables from C or C++ sources
+# - defines rules for libdir installation
+# - defines convenience targets for developer and user
+# - evaluates implicit dependencies for non-clean builds
+#
+#
+#=== basic usage ===============================================================
+#
+#
+# In your Makefile, define your Pd lib name and class files, and include
+# Makefile.pdlibbuilder at the end of the Makefile. Like so:
+#
+#    ________________________________________________________________________
+#
+#     # Makefile for mylib
+#
+#     lib.name = mylib
+#
+#     class.sources = myclass1.c myclass2.c
+#
+#     datafiles = myclass1-help.pd myclass2-help.pd README.txt LICENSE.txt
+#
+#     include Makefile.pdlibbuilder
+#    ________________________________________________________________________
+#
+#
+# For files in class.sources it is assumed that class basename == source file
+# basename. The default target builds all classes as individual executables
+# with Pd's default extension for the platform. For anything more than the
+# most basic usage, continue reading.
+#
+#
+#=== list of Makefile.pdlibbuilder API variables ===============================
+#
+#
+# Variables available for definition in your library Makefile:
+#
+# - lib.name
+# - lib.setup.sources
+# - class.sources
+# - common.sources
+# - shared.sources
+# - <classname>.class.sources
+# - <classname>.class.ldflags
+# - <classname>.class.ldlibs
+# - cflags
+# - ldflags
+# - ldlibs
+# - datafiles
+# - datadirs
+# - makefiles
+# - makefiledirs
+# - externalsdir
+#
+# Optional multiline defines evaluated per operating system:
+#
+# - forLinux
+# - forDarwin
+# - forWindows
+#
+#
+# Variables avaialable for (re)definition via command arguments:
+#
+# - pdbinpath (Windows only)
+# - pdincludepath
+# - DESTDIR
+# - prefix
+# - libdir
+# - pkglibdir
+# - CPPFLAGS
+# - CFLAGS
+# - LDFLAGS
+# - CC
+# - CXX
+# - INSTALL
+# - INSTALL_PROGRAM
+# - INSTALL_DATA
+# - INSTALL_DIR
+#
+# Variables available for your makefile or as command argument:
+#
+# - objectsdir
+# - make-lib-executable
+# - suppress-wunused
+#
+#
+#=== descriptions of Makefile.pdlibbuilder API variables =======================
+#
+#
+# lib.name: 
+# Name of the library directory as it will be installed / distributed. Also the
+# name of the lib executable in the case where all classes are linked into
+# a single binary.
+#
+# lib.setup.sources:
+# Source file(s) (C or C++) which must be compiled only when linking all classes
+# into a single lib binary.
+#
+# class.sources:
+# All sources files (C or C++) for which the condition holds that 
+# class name == source file basename.
+#
+# <classname>.class.sources:
+# Source file(s) (C or C++) specific to class <classname>. Use this for
+# multiple-source classes or when class name != source file basename.
+#
+# common.sources:
+# Source file(s) which must be statically linked to each class in the library.
+#
+# shared.sources:
+# Source file(s) (C or C++) to build a shared dynamic link lib, to be linked
+# with all class executables.
+#
+# cflags, ldflags, ldlibs:
+# Define cflags (preprocessor&compiler), ldflags (linker) and ldlibs (dynamic
+# link libs) for the whole library. These flags are added to platform-specific
+# flags defined by Makefile.pdlibbuilder.
+#
+# <classname>.class.ldflags and <classname>.class.ldlibs: 
+# Define ldflags resp. ldlibs specific to class <classname>. These flags are
+# added to platform-specific flags defined by Makefile.pdlibbuilder, and flags
+# defined in your Makefile for the whole library. Note: cflags can not be
+# defined per class in the current implementation.
+#
+# datafiles and datadirs: 
+# All extra files you want to include in binary distributions of the
+# library: abstractions and help patches, example patches, meta patch, readme
+# and license texts, manuals, sound files, etcetera. Use 'datafiles' for all
+# files that should go into your lib rootdir and 'datadirs' for complete
+# directories you want to copy from source to distribution.
+#
+# externalsdir: 
+# Relative path to directory 'externals' in the context of pd-extended SVN, or
+# any other centralized build layout for multiple libraries. Default value
+# is '..', meaning the direct parent. The value is used in search paths for 
+# pd core components (header files, and executable in the case of Windows).
+#
+# forLinux, forDarwin, forWindows:
+# Shorthand for 'variable definitions for Linux only' etc. Use like:
+#    define forLinux
+#      cflags += -DLINUX
+#      class.sources += linuxthing.c
+#    endef
+#
+# makefiles and makefiledirs: 
+# Extra makefiles or directories with makefiles that should be made in sub-make
+# processes.
+#
+# pdbinpath:
+# For Windows only. Directory where pd.dll can be found for linking.
+#
+# pdincludepath:
+# Directory where Pd API m_pd.h can be found, and other Pd header files.
+#
+# DESTDIR, prefix, libdir:
+# Components of the path for installation as conventionally used on Linux.
+#
+# pkglibdir:
+# Base path for installation of Pd library directories. Default is specified
+# per OS, see section about paths below.
+#
+# objectsdir:
+# Alias of pkglibdir. Can be defined in your makefile to enable project-
+# dependent relative install locations.
+#
+# CPPFLAGS:
+# Preprocessor flags which are not strictly required for building.
+#
+# CFLAGS:
+# Compiler flags which are not strictly required for building. Compiler flags
+# defined by Makefile.pdlibbuilder for warning, optimization and architecture
+# specification are overriden by CFLAGS.
+#
+# LDFLAGS:
+# Linker flags which are not strictly required for building. Linker flags
+# defined by Makefile.pdlibbuilder for architecture specification are overriden
+# by LDFLAGS.
+#
+# CC and CXX:
+# C and C++ compiler programs as defined in your build environment.
+#
+# INSTALL, INSTALL_PROGRAM, INSTALL_DATA, INSTALL_DIR:
+# Definitions of install program, may be overriden via command argument.
+#
+# make-lib-executable:
+# When this variable is defined 'yes' in your makefile or as command argument,
+# Makefile.pdlibbuilder will try to build all classes into a single library
+# executable (but it will force exit if lib.setup.sources is undefined).
+# If your makefile defines 'make-lib-executable=yes' as the library default,
+# this can still be overriden with 'make-lib-executable=no' as command argument 
+# to build individual class executables (the Makefile.pdlibbuilder default.)
+#
+# suppress-wunused:
+# When this variable is defined ('yes' or any other value), -Wunused-variable,
+# -Wunused-parameter, -Wunused-value and -Wunused-function are suppressed,
+# but the other warnings from -Wall are retained.
+#
+#
+#=== paths =====================================================================
+#
+#
+# Source files in directories other than current working directory must be
+# prefixed with their relative path. Do not rely on VPATH or vpath.
+# Object (.o) files are built in the directory of their source files.
+# Executables are built in current working directory. 
+#
+# Variable 'pdincludepath' stores a location where m_pd.h is expected to reside.
+# Locations where Makefile.pdlibbuilder tries to find it, in order of priority:
+#
+# any OS:   $(externalsdir)../pd/src
+#
+# Linux:    /usr/include/pdextended
+#           /usr/include/pd
+#
+# OSX:      /Applications/Pd-extended.app/Contents/Resources/include/pdextended
+#           /Applications/Pd.app/Contents/Resources/src
+#
+# Windows:  %PROGRAMFILES%/pd/include/pdextended
+#           %PROGRAMFILES%/pd/src
+#
+# The path for installation of all library components is constructed as:
+#
+# installpath := $(DESTDIR)$(objectsdir)/$(lib.name)
+#
+# Default for 'objectsdir' is defined per platform and follows this convention:
+# https://puredata.info/docs/faq/how-do-i-install-externals-and-help-files
+#
+# Linux:    /usr/local/lib/pd-externals
+# OSX:      ~/Library/Pd
+# Windows:  %APPDATA%/Pd
+#
+# The rationale for not installing to ~/pd-externals by default on Linux
+# is that some people share the home dir between 32 and 64 bit installations.
+#
+#
+#=== targets ===================================================================
+#
+#
+# all: build $(executables) plus optional post target
+# post: target to build after $(executables)
+# alldebug: build all with -g option turned on for debug symbols
+# <classname>: force clean build of an individual class
+# <sourcefile>.pre: make preprocessor output file in current working directory
+# <sourcefile>.lst: make asm/source output file in current working directory
+#
+# install: install executables and data files
+# clean: remove build products from source tree
+#
+# help: print help text
+# vars: print makefile variables
+# allvars: print all variables
+# depend: print generated prerequisites
+# coffee: dummy target
+#
+# Variable $(executables) expands to class executables plus optional shared lib,
+# or alternatively to single lib executable when make-lib-executable=true.
+# Targets pre and post can be defined by library makefile. Make sure to include
+# Makefile.pdlibbuilder first so default target all will not be redefined.
+#
+#
+#=== Pd-extended libdir concept ================================================
+#
+#
+# For libdir layout as conceived by Hans-Christoph Steiner, see:
+#
+# https://puredata.info/docs/developer/Libdir
+#
+# Files README.txt, LICENSE.txt and <lib.name>-meta.pd are part of the libdir
+# convention. Help patches for each class and abstraction are supposed to be
+# available. Makefile.pdlibbuilder does not force the presence of these files
+# however. It does not automatically include such files in libdir installations.
+# Data files you want to include in distributions must be defined explicitly in
+# your Makefile.
+#
+#
+#=== Makefile.pdlibbuilder syntax conventions ==================================
+#
+#
+# Makefile.pdlibbuilder variable names are lower case. Default make variables,
+# environment variables, and standard user variables (CC, CXX, CFLAGS, DESTDIR)
+# are upper case. Use target 'allvars' to print all variables and their values.
+#
+# 'Fields' in data variables are separated by dots, like in 'foo.class.sources'.
+# Words in variables expressing a function or command are separated by dashes, 
+# like in 'make-lib-executable'.
+#
+#
+#=== useful make options =======================================================
+#
+#
+# Use 'make -d <target>' to print debug details of the make process.
+# Use 'make -p <target>' to print make's database.
+#
+#
+#=== TODO ======================================================================
+#
+#
+# - decide whether to use -static-libgcc or shared dll in MinGW
+# - cygwin support
+# - android support
+# - Windows 64 bit support
+# - figure out how to handle '$' in filenames
+# - add makefile template targets dpkg-source dist libdir distclean tags?
+#
+#
+#=== end of documentation sections =============================================
+#
+# 
+################################################################################
+################################################################################
+################################################################################
+
+
+# GNU make version 3.81 (2006) or higher is required because of the following:
+# - function 'info'
+# - variable '.DEFAULT_GOAL'
+
+# force exit when make version is < 3.81
+ifneq ($(firstword $(sort 3.81 $(MAKE_VERSION))), 3.81)
+  $(error GNU make version 3.81 or higher is required)
+endif
+
+# Relative path to externals root dir in multi-lib source tree like 
+# pd-extended SVN. Default is parent of current working directory. May be
+# defined differently in including makefile. This variable is used to probe for
+# paths.
+externalsdir ?= ..
+
+# variable you can use to check if Makefile.pdlibbuilder is already included
+Makefile.pdlibbuilder = true
+
+
+################################################################################
+### variables: library name and version ########################################
+################################################################################
+
+
+# strip possibles spaces from lib.name, they mess up calculated file names
+lib.name := $(strip $(lib.name))
+
+# if meta file exists, check library version 
+metafile := $(wildcard $(lib.name)-meta.pd)
+
+ifdef metafile
+  lib.version := $(shell sed -n \
+    's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' \
+    $(metafile))
+endif
+
+
+################################################################################
+### variables: files ###########################################################
+################################################################################
+
+
+#=== sources ===================================================================
+
+
+# (re)define <classname>.class.sources using file names in class.sources
+
+define add-class-source
+$(notdir $(basename $v)).class.sources += $v
+endef
+
+$(foreach v, $(class.sources), $(eval $(add-class-source)))
+
+# derive class names from <classname>.class.sources variables
+sourcevariables := $(filter %.class.sources, $(.VARIABLES))
+classes := $(basename $(basename $(sourcevariables)))
+
+# accumulate all source files specified in makefile
+classes.sources := $(sort $(foreach v, $(sourcevariables), $($v)))
+all.sources := $(classes.sources) $(lib.setup.sources) \
+  $(shared.sources) $(common.sources)
+
+
+#=== object files ==============================================================
+
+
+# construct object filenames from all C and C++ source file names
+classes.objects := $(addsuffix .o, $(basename $(classes.sources)))
+common.objects := $(addsuffix .o, $(basename $(common.sources)))
+shared.objects := $(addsuffix .o, $(basename $(shared.sources)))
+lib.setup.objects := $(addsuffix .o, $(basename $(lib.setup.sources)))
+all.objects = $(classes.objects) $(common.objects) $(shared.objects) \
+  $(lib.setup.objects)
+
+
+#=== executables ===============================================================
+
+
+# use recursive variables here because executable extension is not yet known
+
+# construct class executable names from class names
+classes.executables = $(addsuffix .$(extension), $(classes))
+
+# construct shared lib executable name if shared sources are defined
+ifdef shared.sources
+  shared.lib = lib$(lib.name).$(shared.extension)
+else
+  shared.lib =
+endif
+
+
+################################################################################
+### variables per platform #####################################################
+################################################################################
+
+
+#=== flags per architecture ====================================================
+
+
+# Set architecture-dependent cflags, mainly for Linux. For Mac and Windows, 
+# arch.c.flags are overriden below.
+
+machine := $(shell uname -m)
+
+# Raspberry Pi 1st generation
+ifeq ($(machine), armv6l)
+  arch.c.flags = -march=armv6 -mfpu=vfp -mfloat-abi=hard
+endif
+
+# Beagle, Udoo, RPi2 etc.
+ifeq ($(machine), armv7l)
+  arch.c.flags = -march=armv7-a -mfpu=vfpv3 -mfloat-abi=hard
+endif
+
+# Intel 32 bit, build with SSE and SSE2 instructions
+ifeq ($(findstring $(machine), i386 i686), $(machine))
+  arch.c.flags = -march=pentium4 -mfpmath=sse -msse -msse2
+endif
+
+# Intel/AMD 64 bit, build with SSE, SSE2 and SSE3 instructions
+ifeq ($(findstring $(machine), ia64 x86_64), $(machine))
+  arch.c.flags = -march=core2 -mfpmath=sse -msse -msse2 -msse3 
+endif
+
+
+#=== operating system ==========================================================
+
+
+# The following systems are defined: Linux, Darwin, Windows. GNU and
+# GNU/kFreeBSD are treated as Linux to get the same options. System-specific
+# multiline defines (optionally set in library makefile) are conditionally
+# evaluated here.
+
+uname := $(shell uname)
+
+ifeq ($(findstring $(uname), Linux GNU GNU/kFreeBSD), $(uname))
+  system = Linux
+  $(eval $(forLinux))
+endif
+
+ifeq ($(uname), Darwin)
+  system = Darwin
+  $(eval $(forDarwin))
+endif
+
+ifeq ($(findstring MINGW, $(uname)), MINGW)
+  system = Windows
+  $(eval $(forWindows))
+endif
+
+# TODO: Cygwin, Android
+
+
+#=== flags and paths for Linux =================================================
+
+
+ifeq ($(system), Linux)
+  prefix = /usr/local
+  libdir := $(prefix)/lib
+  pkglibdir = $(libdir)/pd-externals
+  pdincludepath := $(firstword $(wildcard \
+    $(externalsdir)/../pd/src \
+    /usr/include/pdextended \
+    /usr/include/pd))
+  extension = pd_linux
+  cpp.flags := -DUNIX
+  c.flags := -fpic
+  c.ldflags := -rdynamic -shared -fpic -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags
+  c.ldlibs := -lc -lm
+  cxx.flags := -fpic -fcheck-new
+  cxx.ldflags := -rdynamic -shared -fpic -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags
+  cxx.ldlibs := -lc -lm -lstdc++
+  shared.extension = so
+  shared.ldflags := -rdynamic -fpic -shared -Wl,-soname,$(shared.lib)
+  stripflags = --strip-unneeded -R .note -R .comment
+endif
+
+
+#=== flags and paths for Darwin ================================================
+
+
+# On OSX we try to build fat binaries by default. It is assumed that OSX i386
+# can build for ppc and OSX x86_64 can't. TODO: try to refine this condition.
+# LLVM-clang doesn't support -fcheck-new, therefore this flag is omitted for
+# OSX x86_64.
+
+ifeq ($(system), Darwin)
+  pkglibdir = $(HOME)/Library/Pd
+  pdincludepath := $(firstword $(wildcard \
+    $(externalsdir)/../pd/src \
+    /Applications/Pd-extended*.app/Contents/Resources/include/pdextended \
+    /Applications/Pd*.app/Contents/Resources/src))
+  extension = pd_darwin
+  cpp.flags := -DUNIX -DMACOSX -I /sw/include
+  c.flags := 
+  c.ldflags := -undefined suppress -flat_namespace -bundle
+  c.ldlibs := -lc
+  cxx.ldflags := -undefined suppress -flat_namespace -bundle
+  cxx.ldlibs := -lc
+  shared.extension = dylib
+  shared.ldflags = -dynamiclib -undefined dynamic_lookup \
+    -install_name @loader_path/$(shared.lib) \
+    -compatibility_version 1 -current_version 1.0
+  stripflags = -x
+  ifeq ($(machine), i386)
+    cxx.flags := -fcheck-new
+    arch.c.flags := -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=10.4
+    arch.ld.flags := -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=10.4
+  endif
+  ifeq ($(machine), x86_64)
+    arch.c.flags := -arch i386 -arch x86_64 -mmacosx-version-min=10.5
+    arch.ld.flags := -arch i386 -arch x86_64 -mmacosx-version-min=10.5
+  endif
+endif
+
+
+#=== flags and paths for Windows ===============================================
+
+
+# Standard paths on Windows contain spaces, and GNU make functions treat such
+# paths as lists, with unintended effects. Therefore we must use shell function
+# ls instead of make's wildcard, and probe for each standard path individually.
+# Using double quotes around paths with spaces is obligatory. Since some path
+# variables are assembled or re-expanded later, great care must be taken to put
+# quotes at appropriate points throughout the makefile. Thanks, Bill.
+
+# paths for 32-bit executables on 64-bit Windows aren't yet defined here (TODO)
+ifeq ($(system), Windows)
+  pkglibdir := $(APPDATA)/Pd
+  pdbinpath := $(wildcard $(externalsdir)/../pd/bin)
+  pdincludepath := $(wildcard $(externalsdir)/../pd/src)
+  ifndef pdbinpath
+    pdbinpath := $(shell ls -d "$(PROGRAMFILES)/pd/bin")
+  endif
+  ifndef pdincludepath
+    pdincludepath := $(shell ls -d "$(PROGRAMFILES)/pd/include/pdextended")
+  endif
+  ifndef pdincludepath
+    pdincludepath := $(shell ls -d "$(PROGRAMFILES)/pd/src")
+  endif
+endif
+
+# On Windows we build 32 bit by default to match Pd(-extended) binary 
+# distributions. This may change in the future.
+# TODO: decide whether -mms-bitfields should be specified.
+ifeq ($(system), Windows)
+  extension = dll
+  CC = gcc
+  CXX = g++
+  arch.c.flags := -march=pentium4 -msse -msse2 -mfpmath=sse
+  cpp.flags := -DMSW -DNT
+  c.flags :=
+  c.ldflags := -static-libgcc -shared \
+    -Wl,--enable-auto-import "$(pdbinpath)/pd.dll"
+  c.ldlibs :=
+  cxx.flags := -fcheck-new
+  cxx.ldflags := -static-libstdc++ -shared \
+    -Wl,--enable-auto-import "$(pdbinpath)/pd.dll"
+  cxx.ldlibs :=
+  shared.extension = dll
+  shared.ldflags := -static-libgcc -shared "$(pdbinpath)/pd.dll"
+  stripflags = --strip-unneeded -R .note -R .comment
+endif
+
+
+#=== paths =====================================================================
+
+
+# Default pkglibdir is specified above per operating system. It is aliased as 
+# 'objectsdir' to retain compatibility with pd-extended template. Assignment
+# operator '?=' is used to enable a project-relative path definition in the
+# including makefile.
+objectsdir ?= $(pkglibdir)
+
+# base path where all components of the lib will be installed by default
+installpath := $(DESTDIR)$(objectsdir)/$(lib.name)
+
+# check if pdincludepath contains spaces (as is often the case on Windows)
+# if so, store the path so we can later do checks with it
+pdincludepathwithspaces := $(if $(word 2, $(pdincludepath)), $(pdincludepath))
+
+
+#=== accumulated build flags ===================================================
+
+
+# From GNU make docs: 'Users expect to be able to specify CFLAGS freely
+# themselves.' So we use CFLAGS to define options which  are not strictly
+# required for compilation: optimizations, architecture specifications, and 
+# warnings. CFLAGS can be safely overriden using a make command argument.
+# Variables cflags, ldflags and ldlibs may be defined in including makefile.
+
+optimization.flags = -O3 -ffast-math -funroll-loops -fomit-frame-pointer
+warn.flags = -Wall -Wextra -Wshadow -Winline -Wstrict-aliasing
+
+# suppress -Wunused-variable & Co if you don't want to clutter a build log
+ifdef suppress-wunused
+  warn.flags += $(addprefix -Wno-unused-, function parameter value variable)
+endif
+
+CFLAGS = $(warn.flags) $(optimization.flags) $(arch.c.flags)
+
+# preprocessor flags
+cpp.flags += -DPD -I "$(pdincludepath)" $(CPPFLAGS)
+
+# architecture specifications for linker are overridable by LDFLAGS
+LDFLAGS := $(arch.ld.flags)
+
+# now add the same ld flags to shared dynamic lib
+shared.ldflags := $(shared.ldflags) $(LDFLAGS)
+
+# accumulated flags for C compiler / linker
+c.flags := $(cpp.flags) $(c.flags) $(cflags) $(CFLAGS)
+c.ldflags := $(c.ldflags) $(ldflags) $(LDFLAGS)
+c.ldlibs := $(c.ldlibs) $(ldlibs)
+
+# accumulated flags for C++ compiler / linker
+cxx.flags := $(cpp.flags) $(cxx.flags) $(cflags) $(CFLAGS)
+cxx.ldflags := $(cxx.ldflags) $(ldflags) $(LDFLAGS)
+cxx.ldlibs := $(cxx.ldlibs) $(ldlibs)
+
+
+################################################################################
+### variables: tools ###########################################################
+################################################################################
+
+
+# aliases so we can later define 'compile-$1' and set 'c' or 'cxx' as argument
+compile-c := $(CC)
+compile-cxx := $(CXX)
+
+
+################################################################################
+### checks #####################################################################
+################################################################################
+
+
+# At this point most variables are defined. Now do some checks and info's
+# before rules begin.
+
+# 'forward declaration' of default target, needed to do checks
+all:
+
+# To avoid unpredictable results, make sure the default target is not redefined
+# by including makefile. 
+ifneq ($(.DEFAULT_GOAL), all)
+  $(error Default target must be 'all'.)
+endif
+
+# find out which target(s) will be made
+ifdef MAKECMDGOALS
+  goals := $(MAKECMDGOALS)
+else
+  goals := all
+endif
+
+# store path to Pd API m_pd.h if it is found
+ifdef pdincludepath
+  mpdh := $(shell ls "$(pdincludepath)/m_pd.h")
+endif
+
+# when making target all, check if m_pd.h is found and print info about it
+ifeq ($(goals), all)
+  $(if $(mpdh), \
+    $(info ++++ info: using Pd API $(mpdh)), \
+    $(warning Where is Pd API m_pd.h? Do 'make help' for info.))
+endif
+
+# print target info
+$(info ++++ info: making target $(goals) $(if $(lib.name),in lib $(lib.name)))
+
+# when installing, print installpath info
+$(if $(filter install install-lib, $(goals)), $(info ++++ info: \
+  installpath is '$(installpath)'))
+
+
+#=== define executables ========================================================
+
+
+# By default we build class executables, and optionally a shared dynamic link
+# lib. When make-lib-executable=yes we build all classes into a single lib
+# executable, on the condition that variable lib.setup.sources is defined.
+
+ifeq ($(make-lib-executable),yes)
+  $(if $(lib.setup.sources), ,\
+    $(error Can not build library blob because lib.setup.sources is undefined))
+  executables := $(lib.name).$(extension)
+else
+  executables := $(classes.executables) $(shared.lib)
+endif
+
+
+################################################################################
+### rules: special targets #####################################################
+################################################################################
+
+
+# Disable built-in rules. If some target can't be built with the specified
+# rules, it should not be built at all.
+MAKEFLAGS += --no-builtin-rules
+
+.PRECIOUS:
+.SUFFIXES:
+.PHONY: all post build-lib \
+        $(classes) $(makefiledirs) $(makefiles) \
+        install install-executables install-datafiles install-datadirs \
+        force clean vars allvars depend help
+
+
+################################################################################
+### rules: build targets #######################################################
+################################################################################
+
+
+# Target all forces the build of targets [$(executables) post] in
+# deterministic order. Target $(executables) builds class executables plus 
+# optional shared lib or alternatively a single lib executable when 
+# make-lib-executable=true. Target post is optionally defined by
+# library makefile.
+
+all: post
+post: $(executables)
+
+all:
+	$(info ++++info: target all in lib $(lib.name) completed)
+
+# build all with -g option turned on for debug symbols
+alldebug: c.flags += -g
+alldebug: cxx.flags += -g
+alldebug: all
+
+
+#=== class executable ==========================================================
+
+
+# recipe for linking objects in class executable
+# argument $1 = compiler type (c or cxx)
+# argument $2 = class basename
+define link-class
+  $(compile-$1) \
+  $($1.ldflags) $($2.class.ldflags) \
+  -o $2.$(extension) \
+  $(addsuffix .o, $(basename $($2.class.sources))) \
+  $(addsuffix .o, $(basename $(common.sources))) \
+  $($1.ldlibs) $($2.class.ldlibs) $(shared.lib)
+endef
+
+# general rule for linking object files in class executable
+%.$(extension): $(shared.lib)
+	$(info ++++ info: linking objects in $@ for lib $(lib.name))
+	$(if $(filter %.cc %.cpp, $($*.class.sources)), \
+        $(call link-class,cxx,$*), \
+        $(call link-class,c,$*))
+
+
+#=== library blob ==============================================================
+
+
+# build all classes into single executable
+build-lib: $(lib.name).$(extension)
+	$(info ++++ info: library blob $(lib.name).$(extension) completed)
+
+# recipe for linking objects in lib executable
+# argument $1 = compiler type (c or cxx)
+define link-lib
+  $(compile-$1) \
+  $($1.ldflags) $(lib.ldflags) \
+  -o $(lib.name).$(extension) $(all.objects) \
+  $($1.ldlibs) $(lib.ldlibs)
+endef
+
+# rule for linking objects in lib executable
+# declared conditionally to avoid name clashes
+ifeq ($(make-lib-executable),yes)
+$(lib.name).$(extension): $(all.objects)
+	$(if $(filter %.cc %.cpp, $(all.sources)), \
+        $(call link-lib,cxx), \
+        $(call link-lib,c))
+endif
+
+
+#=== shared dynamic lib ========================================================
+
+
+# recipe for linking objects in shared executable
+# argument $1 = compiler type (c or cxx)
+define link-shared
+  $(compile-$1) \
+  $(shared.ldflags) \
+  -o lib$(lib.name).$(shared.extension) $(shared.objects) \
+  $($1.ldlibs) $(shared.ldlibs)
+endef
+
+# rule for linking objects in shared executable
+# build recipe is in macro 'link-shared'
+lib$(lib.name).$(shared.extension): $(shared.objects)
+	$(info ++++ info: linking objects in shared lib $@)
+	$(if $(filter %.cc %.cpp, $(shared.sources)), \
+        $(call link-shared,cxx), \
+        $(call link-shared,c))
+
+
+#=== object files ==============================================================
+
+
+# recipe to make .o file from source
+# argument $1 is compiler type (c or cxx)
+define make-object-file
+  $(info ++++ info: making $@ in lib $(lib.name))
+  $(compile-$1) \
+  $($1.flags) \
+  -o $@ -c $<
+endef
+
+# Three rules to create .o files. These are double colon 'terminal' rules,
+# meaning they are the last in a rules chain.
+
+%.o:: %.c
+	$(call make-object-file,c)
+
+%.o:: %.cc
+	$(call make-object-file,cxx)
+
+%.o:: %.cpp
+	$(call make-object-file,cxx)
+
+
+#=== explicit prerequisites for class executables ==============================
+
+
+# For class executables, prerequisite rules are declared in run time. Target
+# 'depend' prints these rules for debugging purposes.
+
+# declare explicit prerequisites rule like 'class: class.extension'
+# argument $v is class basename
+define declare-class-target
+$v: $v.$(extension)
+endef
+
+# declare explicit prerequisites rule like 'class.extension: object1.o object2.o'
+# argument $v is class basename
+define declare-class-executable-target
+$v.$(extension): $(addsuffix .o, $(basename $($v.class.sources))) \
+  $(addsuffix .o, $(basename $(common.sources)))
+endef
+
+# evaluate explicit prerequisite rules for all classes
+$(foreach v, $(classes), $(eval $(declare-class-target)))
+$(foreach v, $(classes), $(eval $(declare-class-executable-target)))
+
+
+#=== implicit prerequisites for class executables ==============================
+
+
+# Evaluating implicit prerequisites (header files) with help from the
+# preprocessor is 'expensive' so this is done conditionally and selectively.
+# Note that it is also possible to trigger a build via install targets, in
+# which case implicit prerequisites are not checked.
+
+# When the Pd include path contains spaces it will mess up the implicit
+# prerequisites rules. Also it is known that multiple arch flags are
+# incompatible with preprocessor option -MM on OSX <= 10.5. Dependency
+# tracking must be disabled in those cases.
+
+oldfat := $(and $(filter ppc i386, $(machine)), \
+          $(filter-out 0 1, $(words $(filter -arch, $(c.flags)))))
+
+disable-dependency-tracking := pdincludepathwithspaces oldfat
+
+ifndef disable-dependency-tracking
+  must-build-everything := $(filter all, $(goals))
+  must-build-class := $(filter $(classes), $(goals))
+  must-build-sources := $(foreach v, $(must-build-class), $($v.class.sources))
+endif
+
+# declare implicit prerequisites rule like 'object.o: header1.h header2.h ...'
+# argument $1 is input source file(s)
+define declare-object-target
+$(filter %.o: %.h, $(shell $(CPP) $(c.flags) -MM $1)) $(MAKEFILE_LIST)
+endef
+
+# evaluate implicit prerequisite rules when rebuilding everything
+ifdef must-build-everything
+  $(if $(wildcard $(all.objects)), \
+  $(info ++++ info: evaluating implicit prerequisites in lib $(lib.name).....) \
+  $(foreach v, $(all.sources), $(eval $(call declare-object-target, $v))))
+endif
+
+# evaluate implicit prerequisite rules when selectively building classes
+ifdef must-build-class
+  $(foreach v, $(must-build-sources), \
+  $(eval $(call declare-object-target, $v)))
+  $(foreach v, $(shared.sources), \
+  $(eval $(call declare-object-target, $v)))
+endif
+
+
+################################################################################
+### rules: preprocessor and assembly files #####################################
+################################################################################
+
+
+# Preprocessor and assembly output files for bug tracing etc. They are not part
+# of the build processes for executables. By default these files are created in
+# the current working directory. Dependency tracking is not performed, the build
+# is forced instead to make sure it's up to date.
+
+force:
+
+
+#=== preprocessor file =========================================================
+
+
+# make preprocessor output file with extension .pre
+# argument $1 = compiler type (c or cxx)
+define make-preprocessor-file
+  $(info ++++ info: making preprocessor output file $(notdir $*.pre) \
+  in current working directory)
+  $(compile-$1) -E $< $(c.flags) $($1.flags) -o $(notdir $*.pre)
+endef
+
+%.pre:: %.c force
+	$(call make-preprocessor-file,c)
+
+%.pre:: %.cc force
+	$(call make-preprocessor-file,cxx)
+
+%.pre:: %.cpp force 
+	$(call make-preprocessor-file,cxx)
+
+
+#=== assembly file =============================================================
+
+
+# make C / assembly interleaved output file with extension .lst
+# argument $1 = compiler type (c or cxx)
+define make-assembly-file
+  $(info ++++ info: making assembly output file $(notdir $*.lst) \
+  in current working directory)
+  $(compile-$1) \
+  -c -Wa,-a,-ad -fverbose-asm \
+  $($1.flags) \
+  $< > $(notdir $*.lst)
+endef
+
+%.lst:: %.c force
+	$(call make-assembly-file,c)
+
+%.lst:: %.cc force
+	$(call make-assembly-file,cxx)
+
+%.lst:: %.cpp force
+	$(call make-assembly-file,cxx)
+
+
+################################################################################
+### rules: installation targets ################################################
+################################################################################
+
+
+# Install targets depend on successful exit status of target all because nothing
+# must be installed in case of a build error.
+
+
+# -p = preserve time stamps
+# -m = set permission mode (as in chmod)
+# -d = create all components of specified directories
+INSTALL = install
+INSTALL_PROGRAM := $(INSTALL) -p -m 644
+INSTALL_DATA := $(INSTALL) -p -m 644
+INSTALL_DIR := $(INSTALL) -m 755 -d
+
+# strip spaces from file names
+executables := $(strip $(executables))
+datafiles := $(strip $(datafiles))
+datadirs := $(strip $(datadirs))
+
+# Do not make any install sub-target with empty variable definition because the
+# install program would exit with an error.
+install: $(if $(executables), install-executables)
+install: $(if $(datafiles), install-datafiles)
+install: $(if $(datadirs), install-datadirs)
+
+install-executables: all
+	$(INSTALL_DIR) -v "$(installpath)"
+	$(INSTALL_PROGRAM) $(executables) "$(installpath)"
+	$(info ++++ info: executables of lib $(lib.name) installed \
+        from $(CURDIR) to $(installpath))
+
+install-datafiles: all
+	$(INSTALL_DIR) -v "$(installpath)"
+	$(INSTALL_DATA) $(datafiles) "$(installpath)"
+	$(info ++++ info: data files of lib $(lib.name) installed \
+        from $(CURDIR) to $(installpath))
+
+install-datadirs: all
+	$(foreach v, $(datadirs), $(INSTALL_DIR) "$(installpath)/$v";)
+	$(foreach v, $(datadirs), \
+        $(INSTALL_DATA) $(wildcard $v/*) "$(installpath)/$v";)
+	$(info ++++ info: data directories of lib $(lib.name) installed \
+        from $(CURDIR) to $(installpath))
+
+
+################################################################################
+### rules: distribution targets ################################################
+################################################################################
+
+
+# TODO
+# These targets are implemented in Makefile Template, but I have to figure out
+# how to do it under the not-so-strict conditions of Makefile.pdlibbuilder.
+
+# make source package
+dist:
+	@echo "target dist not yet implemented"
+
+# make Debian source package
+dpkg-source:
+	@echo "target dpkg-source not yet implemented"
+
+$(ORIGDIR):
+
+$(DISTDIR):
+
+
+################################################################################
+### rules: clean targets #######################################################
+################################################################################
+
+
+# delete build products from build tree
+clean:
+	rm -f $(all.objects)
+	rm -f $(classes.executables) $(lib.name).$(extension) $(shared.lib)
+	rm -f *.pre *.lst
+
+# remove distribution directories and tarballs from build tree
+distclean: clean
+	@echo "target distclean not yet implemented"
+
+
+################################################################################
+### rules: submake targets #####################################################
+################################################################################
+
+
+# Iterate over sub-makefiles or makefiles in other directories.
+
+# When 'continue-make=yes' is set, sub-makes will report 'true' to the parent
+# process regardless of their real exit status. This prevents the parent make
+# from being aborted by a sub-make error. Useful when you want to quickly find
+# out which sub-makes from a large set will succeed.
+ifeq ($(continue-make),yes)
+  continue = || true
+endif
+
+# These targets will trigger sub-make processes for entries in 'makefiledirs'
+# and 'makefiles'.
+all alldebug install clean distclean dist dkpg-source: \
+        $(makefiledirs) $(makefiles)
+
+# this expands to identical rules for each entry in 'makefiledirs'
+$(makefiledirs):
+	$(MAKE) --directory=$@ $(MAKECMDGOALS) $(continue)
+
+# this expands to identical rules for each entry in 'makefiles'
+$(makefiles):
+	$(MAKE) --directory=$(dir $@) --makefile=$(notdir $@) $(MAKECMDGOALS) $(continue)
+
+
+################################################################################
+### rules: convenience targets #################################################
+################################################################################
+
+
+#=== show variables ============================================================
+
+
+# Several 'function' macro's cause errors when expanded within a rule or without
+# proper arguments. Variables which are set with the define directive are only
+# shown by name for that reason.
+functions = \
+add-class-source \
+declare-class-target \
+declare-class-executable-target \
+declare-object-target \
+link-class \
+link-lib \
+link-shared \
+make-object-file \
+make-preprocessor-file \
+make-assembly-file
+
+
+# show variables from makefiles
+vars:
+	$(info ++++ info: showing makefile variables:)
+	$(foreach v,\
+        $(sort $(filter-out $(functions) functions, $(.VARIABLES))),\
+        $(if $(filter file, $(origin $v)),\
+        $(info variable $v = $($v))))
+	$(foreach v, $(functions), $(info 'function' name: $v))
+	@echo
+
+# show all variables
+allvars:
+	$(info ++++ info: showing default, automatic and makefile variables:)
+	$(foreach v, \
+        $(sort $(filter-out $(functions) functions, $(.VARIABLES))), \
+        $(info variable ($(origin $v)) $v = $($v)))
+	$(foreach v, $(functions), $(info 'function' name: $v))
+	@echo
+
+
+#=== show dependencies =========================================================
+
+
+# show generated prerequisites rules
+depend:
+	$(info ++++ info: generated prerequisite rules)
+	$(foreach v, $(classes), $(info $(declare-class-target)))
+	$(foreach v, $(classes), $(info $(declare-class-executable-target)))
+	$(foreach v, $(all.sources), $(info $(call declare-object-target, $v)))
+	@echo
+
+
+#=== show help text ============================================================
+
+
+# brief info about targets and paths
+
+ifdef mpdh
+  mpdhinfo := $(mpdh)
+else
+  mpdhinfo := m_pd.h was not found. Is Pd(-extended) installed?
+endif
+
+help:
+	@echo
+	@echo "  Main targets:"
+	@echo "    all:     build executables (default target)"
+	@echo "    install: install all components of the library"
+	@echo "    vars:    print makefile variables for troubleshooting"
+	@echo "    allvars: print all variables for troubleshooting"
+	@echo "    help:    print this help text"
+	@echo
+	@echo "  Pd API m_pd.h:"
+	@echo "    $(mpdhinfo)"
+	@echo "  You may specify your preferred Pd include path as argument to"
+	@echo "  the make command, like 'pdincludepath=path/to/pd/src'."
+	@echo
+	@echo "  Path for installation of your libdir(s):"
+	@echo "    $(objectsdir)"
+	@echo "  Alternatively you may specify your path for installation as argument"
+	@echo "  to the make command, like 'objectsdir=path/to/pd-externals'."
+	@echo
+	@echo "  Default paths are listed in the doc sections in Makefile.pdlibbuilder."
+	@echo
+
+
+#=== dummy target ==============================================================
+
+
+coffee:
+	@echo "Makefile.pdlibbuilder: Can not make coffee. Sorry."
+
+
+################################################################################
+### end of rules sections ######################################################
+################################################################################
+
+
+# for syntax highlighting in vim and github
+# vim: set filetype=make:
+
diff --git a/punish/patcherize-plugin/README.md b/punish/patcherize-plugin/README.md
new file mode 100644
index 0000000..a051970
--- /dev/null
+++ b/punish/patcherize-plugin/README.md
@@ -0,0 +1,87 @@
+patcherize
+==========
+
+
+  - connections to the containing patch will be kept (via inlets/outlets)
+  - objects will keep their internal state
+
+# Usage
+- Select the objects you want to turn into a subpatch
+- Press <kbd>Control</kbd>+<kbd>Shift</kbd>+<kbd>p</kbd> to turn the selected
+  objects into a subpatch.
+- the selection will be replaced by a subpatch `[pd /*patcherized*/]`
+- Alternatively, you can do this via the Menu: `Edit` -> `(Sub)patcherize Selection`
+
+You can also create an abstraction from the selection:
+- Select the objects you want to turn into a subpatch
+- Use the menu: `Edit` -> `Patcherize selection...`
+- a "Save As..." menu will appear, asking you where you want to save the
+  patcherized selection (e.g. pick "foo.pd")
+- The selection will be replaced by an abstraction for the said name (e.g.
+  `[foo]`).
+- If you saved the abstraction outside Pd's search path, the abstraction will be
+  instantiated with its full name (e.g. `[/home/frodel/foo]`)
+
+# Installation
+
+## Building
+Build the external:
+
+    make
+
+If you have an unusual setup (and/or your Pd installation is at a place not
+found by the compiler), you can parameterize the build. Try this first:
+
+    make help
+
+
+## Installing
+Put both the externals (`patcherize.pd_linux` or similar) an dthe GUI plugin
+(`patcherize-plugin.tcl`) into a directory `patcherize-plugin`, and put that
+into a place where Pd can find it.
+
+     make install
+
+E.g.
+
+    $ ~/.local/lib/pd/extra/patcherize-plugin/
+    ~/.local/lib/pd/extra/patcherize-plugin/patcherize.pd_linux
+    ~/.local/lib/pd/extra/patcherize-plugin/patcherize-plugin.tcl
+
+# BUGS
+
+## Pd crashes when clicking on a patcherized msgbox
+Yes.
+Patcherization does not re-instantiate any object (or msgbox).
+Instead it just "moves" the selection to the new window, basically leaving
+the object unaware that it's context has changed.
+
+When clicking on the 'msgbox', the "flashing effect" will try to talk to the
+wrong window, resulting in a crash.
+
+This could be fixed by doing a Cut-n-Paste instead of sleekily migrating the
+objects, but this would result in objects losing their inner state (not a
+problem for a msgbox, that doesn't have any hidden inner state)
+
+## GUI objects do not respond after being patcherized
+See above: the reason for this behaviour is the same (albeit less drastic) than
+the crashing msgbox.
+Unfortunately, generic GUI objects might (and most probably) will have a hidden
+inner state - which is the reason why i would rather not go the safe Cut-n-Paste
+route.
+
+# AUTHORS
+
+IOhannes m zmölnig
+
+# LICENSE
+`patcherize` is released under the Gnu GPL version 2 (or later).
+See LICENSE.md for the full text of the GPLv2.
+
+## Special license grant to Miller Puckette
+I hereby grant Miller S. Puckette the exclusive right to include
+`patcherize` into Pure Data (Pd) under the BSD 3-clause license under
+which Pd is currently released.
+
+Once it has been included into Pd it is of course re-distributable under
+that license. Until then, the Gnu GPL v2 (or later) applies.
diff --git a/punish/patcherize-plugin/patcherize-help.pd b/punish/patcherize-plugin/patcherize-help.pd
new file mode 100644
index 0000000..6daa999
--- /dev/null
+++ b/punish/patcherize-plugin/patcherize-help.pd
@@ -0,0 +1,55 @@
+#N canvas 241 361 446 325 10;
+#X declare -lib patcherize -path iemguts -stdpath iemguts;
+#N canvas 504 133 594 498 guts 0;
+#X obj 136 176 inlet;
+#X obj 207 262 sendcanvas 1;
+#X msg 207 242 patcherize;
+#X obj 207 222 t b;
+#X obj 136 380 canvasselect 1;
+#X msg 136 360 select \$1;
+#X obj 136 282 t b b;
+#X msg 215 356 deselect;
+#X obj 149 105 declare -lib patcherize -path iemguts -stdpath iemguts
+;
+#X obj 425 321 s \$0-on;
+#X msg 425 300 1;
+#X obj 425 231 t b;
+#X msg 188 176 init;
+#X obj 136 198 route select patcherize init;
+#X obj 188 154 loadbang;
+#X msg 136 308 0 \, 1 \, 2;
+#X obj 136 330 + 8;
+#X connect 0 0 13 0;
+#X connect 2 0 1 0;
+#X connect 3 0 2 0;
+#X connect 5 0 4 0;
+#X connect 6 0 15 0;
+#X connect 6 1 7 0;
+#X connect 7 0 4 0;
+#X connect 10 0 9 0;
+#X connect 11 0 10 0;
+#X connect 12 0 13 0;
+#X connect 13 0 6 0;
+#X connect 13 1 3 0;
+#X connect 13 2 11 0;
+#X connect 14 0 12 0;
+#X connect 15 0 16 0;
+#X connect 16 0 5 0;
+#X restore 57 116 pd guts;
+#X obj 37 274 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
+-1;
+#X obj 37 252 r \$0-beat;
+#X msg 57 50 select;
+#X msg 70 74 patcherize;
+#X text 114 263 objects will continue to work...;
+#X text 163 45 1st \, select a few objects;
+#X text 163 69 then turn selected objects into subpatch;
+#X obj 125 152 tgl 15 0 empty \$0-on empty 17 7 0 10 -262144 -1 -1
+0 1;
+#X obj 125 196 s \$0-beat;
+#X obj 125 174 metro 500;
+#X connect 2 0 1 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 8 0 10 0;
+#X connect 10 0 9 0;
diff --git a/punish/patcherize-plugin/patcherize-plugin.tcl b/punish/patcherize-plugin/patcherize-plugin.tcl
new file mode 100644
index 0000000..4d8ed04
--- /dev/null
+++ b/punish/patcherize-plugin/patcherize-plugin.tcl
@@ -0,0 +1,80 @@
+# META helper plugin for patcherize-selection
+# META DESCRIPTION adds menu to tell the 'patcherize' library to doit
+# META AUTHOR IOhannes m zmölnig <zmoelnig at umlaeute.mur.at>
+# META VERSION 0.1
+
+package require pdwindow 0.1
+if [catch {
+    package require msgcat
+    ::msgcat::mcload po
+}] { puts "iem::punish::patcherize: i18n failed" }
+
+namespace eval ::iem::punish::patcherize:: {
+    variable label_sub
+    variable label_abs
+    proc focus {winid state} {
+        set menustate [expr $state?"normal":"disabled"]
+        .menubar.edit entryconfigure "$::iem::punish::patcherize::label_sub" -state $menustate
+        .menubar.edit entryconfigure "$::iem::punish::patcherize::label_abs" -state $menustate
+    }
+    ## helper function to pick a filename for saving
+    # (why isn't there something like this in Pd-GUI?)
+    proc savepanel {initialdir {initialfile ""} {defaultextension ".pd"} {filetypes $::filetypes} } {
+	if { "$filetypes" == {$::filetypes} } {
+	    set filetypes $::filetypes
+	}
+        if { ! [file isdirectory $initialdir]} {set initialdir $::env(HOME)}
+        set filename [tk_getSaveFile \
+			  -defaultextension $defaultextension \
+                          -filetypes $filetypes \
+                          -initialfile $initialfile \
+			  -initialdir $initialdir]
+	return $filename
+    }
+
+    proc patcherize2file {winid} {
+	set filename [::iem::punish::patcherize::savepanel "" "" ".pd" [list [list [_ "Pd Files"]          {.pd}  ]]]
+	if { $filename != "" } {
+	    menu_send $::focused_window "patcherize [enquote_path $filename]"
+	}
+    }
+    proc register {} {
+        # create an entry for our "print2svg" in the "file" menu
+        set ::iem::punish::patcherize::label_sub [_ "SubPatcherize Selection"]
+        set ::iem::punish::patcherize::label_abs [_ "Patcherize Selection..."]
+        set accelerator $::pd_menus::accelerator
+        set mymenu .menubar.edit
+        if {$::windowingsystem eq "aqua"} {
+            set inserthere 8
+            set accelerator "$accelerator+Shift"
+        } else {
+            set inserthere 8
+            set accelerator "Shift+$accelerator"
+        }
+        set accelerator "$accelerator+P"
+
+        $mymenu insert $inserthere command \
+            -label $::iem::punish::patcherize::label_sub \
+            -state disabled \
+            -accelerator "$accelerator" \
+            -command { menu_send $::focused_window patcherize }
+        $mymenu insert [incr inserthere] command \
+            -label $::iem::punish::patcherize::label_abs \
+            -state disabled \
+            -command { ::iem::punish::patcherize::patcherize2file $::focused_window }
+
+        bind all <$::modifier-Key-P> {menu_send %W patcherize}
+        bind PatchWindow <FocusIn> "+::iem::punish::patcherize::focus %W 1"
+        bind PdWindow    <FocusIn> "+::iem::punish::patcherize::focus %W 0"
+
+        # attempt to load the 'patcherize' library from iem::punish
+        # (that does all the work)
+        set lib [string map {" " "\\ "} [file join $::current_plugin_loadpath patcherize]]
+        pdsend "pd-_float_template declare -lib $lib"
+
+        pdtk_post "loaded iem::punish::patcherize-plugin\n"
+    }
+}
+
+
+::iem::punish::patcherize::register
diff --git a/punish/patcherize-plugin/patcherize.c b/punish/patcherize-plugin/patcherize.c
new file mode 100644
index 0000000..0763eaf
--- /dev/null
+++ b/punish/patcherize-plugin/patcherize.c
@@ -0,0 +1,702 @@
+/******************************************************
+ *
+ * patcherize - implementation file
+ *
+ * copyleft (c) IOhannes m zmölnig
+ *
+ *   2016:forum::für::umläute:2016
+ *
+ *   institute of electronic music and acoustics (iem)
+ *
+ ******************************************************
+ *
+ * license: GNU General Public License v.2 (or later)
+ *
+ ******************************************************/
+
+
+/*
+ *
+ *  - patcherize selection
+ *
+ * send a 'patcherize' message to the canvas, and all currently selected objects will
+ *  be moved into a newly created subpatch
+ *
+ * TODO:
+ * - subpatch label
+ *   + if the containing canvas is visible, go into edit-mode and let the user type a canvas-name immediately
+ *
+ * LATER:
+ *  - save selection to file
+ *
+ */
+
+#include "m_pd.h"
+
+#include "g_canvas.h"
+#include "m_imp.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+/* ------------------------- patcherize ---------------------------- */
+/* ------------ utilities ---------- */
+
+static t_gobj*o2g(t_object*obj) {
+  return &(obj->te_g);
+}
+static t_object*g2o(t_gobj*gobj) {
+  return pd_checkobject(&gobj->g_pd);
+}
+
+static void print_glist(t_glist*glist) {
+  t_gobj*obj = NULL;
+  if(NULL == glist)return;
+  post("\tglist=%p", glist);
+  for(obj=glist->gl_list; obj; obj=obj->g_next) { post ("\t%p [%p]", obj, obj->g_next); }
+}
+static int glist_suspend_editor(t_glist*glist) {
+  int wanteditor = (NULL != glist->gl_editor);
+  canvas_destroy_editor(glist);
+  return wanteditor;
+}
+
+static void glist_resume_editor(t_glist*glist, int wanteditor) {
+  if(wanteditor) {
+    canvas_create_editor(glist);
+  }
+  glist_redraw(glist);
+}
+
+static int object_isabstraction(t_object*obj) {
+  if(!obj || !obj->te_g.g_pd)return 0;
+  return (gensym("canvas") == obj->te_g.g_pd->c_name
+          && canvas_isabstraction((t_canvas*)obj));
+}
+static int object_issubpatch(t_object*obj) {
+  if(!obj || !obj->te_g.g_pd)return 0;
+  return (gensym("canvas") == obj->te_g.g_pd->c_name
+          && !canvas_isabstraction((t_canvas*)obj));
+}
+static void object_typedmess(t_object *x, t_symbol *s, int argc, t_atom *argv) {
+  pd_typedmess(&x->te_g.g_pd, s, argc, argv);
+}
+
+/* returns 0 if the object is to be excluded from patcherization */
+static t_symbol**s_excluded_classnames = 0;
+static void build_exclude_list(void) {
+  int i=0;
+  s_excluded_classnames=getbytes(5 * sizeof(*s_excluded_classnames));
+
+  s_excluded_classnames[i++]=gensym("inlet");
+  s_excluded_classnames[i++]=gensym("outlet");
+  s_excluded_classnames[i++]=gensym("inlet~");
+  s_excluded_classnames[i++]=gensym("outlet~");
+  s_excluded_classnames[i++]=0;
+}
+static int include_in_patcherization(const t_object*obj) {
+  const t_symbol*c_name=obj->te_g.g_pd->c_name;
+  t_symbol**excluded;
+  if(!s_excluded_classnames)build_exclude_list();
+  for(excluded=s_excluded_classnames;*excluded; excluded++) {
+    if(c_name == *excluded)return 0;
+  }
+
+  return 1;
+}
+
+
+struct _patcherize_connectto
+{
+  t_object *object;   /* object that we connect to */
+  unsigned int index; /* which inlet of the given object is this? */
+  struct _patcherize_connectto *next;
+};
+
+/* connection between subpatch and surrounding environment */
+typedef struct _patcherize_connection {
+  int is_signal;      /* is this a signal outlet? */
+  t_object*object;    /* object that we connect from */
+  unsigned int index; /* which outlet of the given object is this? */
+  struct _patcherize_connectto*to; /* list of connections */
+  struct _patcherize_connection*next;
+} t_patcherize_connection;
+typedef struct _patcherize_connections {
+  t_patcherize_connection*inlets;
+  t_patcherize_connection*outlets;
+} t_patcherize_connections;
+static int patcherize_conn_leftof_ref(t_object*ref_obj, unsigned int ref_idx, t_object*obj, unsigned int idx) {
+  if(obj->te_xpix < ref_obj->te_xpix) return 1;
+  if(obj->te_xpix > ref_obj->te_xpix) return 0;
+  if(idx < ref_idx) return 1;
+  if(idx > ref_idx) return 0;
+  if(obj->te_ypix < ref_obj->te_ypix) return 1;
+  if(obj->te_ypix > ref_obj->te_ypix) return 0;
+  return 0;
+}
+static void insert_connection_to(t_patcherize_connection*iolets,t_object*to_obj, unsigned int to_index) {
+  struct _patcherize_connectto*dest=iolets->to, *last=NULL;
+  while(dest) {
+    if((dest->object == to_obj) && (dest->index == to_index)) /* already inserted */
+      return;
+    last=dest;
+    dest=dest->next;
+  }
+  dest=calloc(1, sizeof(*dest));
+  dest->object=to_obj;
+  dest->index=to_index;
+  if(last)
+    last->next=dest;
+  else
+    iolets->to=dest;
+}
+static t_patcherize_connection*create_connection(t_object*from_obj, int from_index, t_object*to_obj, int to_index) {
+  t_patcherize_connection*conn=calloc(1, sizeof(*conn));
+  conn->is_signal=obj_issignaloutlet(from_obj, from_index);
+  conn->object=from_obj;
+  conn->index=from_index;
+  insert_connection_to(conn, to_obj, to_index);
+  return conn;
+}
+static t_patcherize_connection*insert_connection(t_patcherize_connection*iolets,
+						 t_object*from_obj, unsigned int from_index,
+						 t_object*to_obj, unsigned int to_index) {
+  /* check whether iolets already contains from_obj/from_index */
+  t_patcherize_connection*cur=iolets, *last=NULL, *conn=NULL;
+  if(!cur) {
+    return create_connection(from_obj, from_index, to_obj, to_index);
+  }
+  while(cur) {
+    if((cur->object == from_obj) && (cur->index == from_index)) {
+      /* found it; insert new 'to' */
+      insert_connection_to(cur, to_obj, to_index);
+      return iolets;
+    }
+    cur=cur->next;
+  }
+  /* if we reach this, then we didn't find the output in our list; so create it */
+  /* LATER: insert the new connection at a sorted location */
+  conn=create_connection(from_obj, from_index, to_obj, to_index);
+
+  /* inserted into sorted list */
+  cur=iolets; last=NULL;
+  while(cur) {
+    if(patcherize_conn_leftof_ref(cur->object, cur->index, from_obj, from_index)) {
+      /* we sort before current element, so insert! */
+      conn->next=cur;
+      if(last) {
+	last->next=conn;
+      } else {
+	/* insert beginning */
+	iolets=conn;
+      }
+      return iolets;
+    }
+    last=cur;
+    cur=cur->next;
+  }
+  /* if we reached this, then the new outlet sorts last */
+  last->next=conn;
+  return iolets;
+}
+static void print_conns(const char*name, t_patcherize_connection*conn) {
+  post("%s: %p", name, conn);
+  while(conn) {
+    struct _patcherize_connectto *to=conn->to;
+    while(to) {
+      post("%s%p[%d] -> %p[%d]", name, conn->object, conn->index, to->object, to->index);
+      to=to->next;
+    }
+    conn=conn->next;
+  }
+}
+static t_patcherize_connection*get_object_connections(t_patcherize_connection*iolets, t_glist*cnv, t_object*obj) {
+  int sel=glist_isselected(cnv,&obj->te_g);
+  int obj_nout=obj_noutlets(obj);
+  int nout=0;
+  for(nout=0; nout<obj_nout; nout++) { /* traverse all outlets of the object */
+    t_outlet*out=0;
+    t_outconnect*conn=obj_starttraverseoutlet(obj, &out, nout);
+    while(conn) {
+      int which;
+      t_object*dest=0;
+      t_inlet *in =0;
+      conn=obj_nexttraverseoutlet(conn, &dest, &in, &which);
+      if (glist_isselected(cnv, &(dest->te_g)) != sel) {
+	/* this is a connection crossing the selection boundary; insert it */
+	iolets=insert_connection(iolets, obj, nout, dest, which);
+      }
+    }
+  }
+  return iolets;
+}
+
+static t_patcherize_connections*get_connections(t_glist*cnv) {
+  t_patcherize_connections*connections=calloc(1, sizeof(*connections));
+  /* 1. iterate over all the objects in the canvas, and store any connecting objects */
+  t_gobj*gobj=NULL;
+  for(gobj=cnv->gl_list; gobj; gobj=gobj->g_next) {
+    t_object*obj=pd_checkobject(&gobj->g_pd);
+    if(!obj)continue;
+    if(glist_isselected(cnv, gobj)) {
+      connections->outlets=get_object_connections(connections->outlets, cnv, obj);
+    } else {
+      connections->inlets=get_object_connections(connections->inlets, cnv, obj);
+    }
+  }
+  return connections;
+}
+static unsigned int object_getmaxdollar(t_object*obj, unsigned int intermediate) {
+  t_binbuf*b=obj->te_binbuf;
+  int argc=binbuf_getnatom(b);
+  t_atom*argv=binbuf_getvec(b);
+  while(argc--) {
+    t_atom*a=argv++;
+    unsigned int dollarg=0;
+    if(A_DOLLAR == a->a_type)
+      dollarg=a->a_w.w_index;
+    else if(A_DOLLSYM == a->a_type) {
+      const char*s=a->a_w.w_symbol->s_name;
+      while(*s){
+	if('$' == *s) {
+	  char*endptr=0;
+	  long int v=strtol(s+1, &endptr, 10);
+	  s=endptr;
+	  if(v>dollarg)dollarg=v;
+	} else
+	  s++;
+      }
+    }
+    if(dollarg>intermediate)intermediate=dollarg;
+  }
+  return intermediate;
+}
+static unsigned int get_maxdollarg(t_object*obj) {
+  unsigned int result=0;
+  if(object_issubpatch(obj)) {
+    // a subpatch! recurse
+    t_gobj*gobj;
+    for(gobj=((t_glist*)obj)->gl_list; gobj; gobj=gobj->g_next) {
+      unsigned int subdollar=get_maxdollarg(g2o(gobj));
+      if(subdollar>result)result=subdollar;
+    }
+  }
+  return(object_getmaxdollar(obj, result));
+}
+
+
+static void free_connectto(struct _patcherize_connectto*conn) {
+  struct _patcherize_connectto*next=0;
+  while(conn) {
+    next=conn->next;
+    conn->object=NULL;
+    conn->index=0;
+    conn->next=NULL;
+    free(conn);
+    conn=next;
+  }
+}
+static void free_connection(t_patcherize_connection*conn) {
+  t_patcherize_connection*next=0;
+  while(conn) {
+    next=conn->next;
+    free_connectto(conn->to);
+    conn->object=NULL;
+    conn->index=0;
+    conn->to=NULL;
+    conn->next=NULL;
+    free(conn);
+    conn=next;
+  }
+}
+static void free_connections(t_patcherize_connections*conns) {
+  free_connection(conns->inlets);
+  free_connection(conns->outlets);
+  conns->inlets=conns->outlets=NULL;
+  free(conns);
+}
+
+static void patcherize_boundary_disconnect(t_patcherize_connection*from) {
+  while(from) {
+    struct _patcherize_connectto*to=from->to;
+    while(to) {
+      obj_disconnect(from->object, from->index, to->object, to->index);
+      to=to->next;
+    }
+    from=from->next;
+  }
+}
+static void patcherize_boundary_reconnect(t_canvas*cnv,t_patcherize_connections*connections) {
+  unsigned int index=0;
+  t_gobj*gobj=cnv->gl_list;
+  t_patcherize_connection*conns=connections->inlets;
+  while(conns) {
+    struct _patcherize_connectto*to=conns->to;
+    /* connect outside objects with new subpatch */
+    obj_connect(conns->object, conns->index, (t_object*)cnv, index);
+    while(to) {
+      /* connect [inlet]s with inside objects */
+      obj_connect((t_object*)gobj, 0, to->object, to->index);
+      to=to->next;
+    }
+    index++;
+    gobj=gobj->g_next;
+    conns=conns->next;
+  }
+  conns=connections->outlets;
+  index=0;
+  while(conns) {
+    struct _patcherize_connectto*to=conns->to;
+    /* connect inside objects with [outlet]s */
+    obj_connect(conns->object, conns->index, (t_object*)gobj, 0);
+    while(to) {
+      /* connect subpatch with outside objects */
+      obj_connect((t_object*)cnv, index, to->object, to->index);
+      to=to->next;
+    }
+    index++;
+    conns=conns->next;
+    gobj=gobj->g_next;
+  }
+}
+
+static void patcherize_fixcoordinates(unsigned int argc, t_gobj**argv, int xmin, int ymin) {
+  unsigned int i;
+  for(i=0; i<argc; i++) {
+    t_object*obj=pd_checkobject(&argv[i]->g_pd);
+    if(obj) {
+      int x = obj->te_xpix;
+      int y = obj->te_ypix;
+      obj->te_xpix = x - xmin + 30;
+      obj->te_ypix = y - ymin + 60;
+    }
+  }
+}
+
+static int patcherize_single_canvas(t_gobj*gobj, const char*name, int save2file) {
+  /* sub-patcherizing abstraction: turn abstraction into subpatch
+   * filepatcherizing sub-patch  : turn sub-patch into abstraction
+   */
+  t_object*obj=g2o(gobj);
+  if(save2file && object_issubpatch(obj)) {
+    post("patcherizing subpatch");
+  } else if(!save2file && object_isabstraction(obj)) {
+    if (!name) {
+      t_atom*argv=binbuf_getvec(obj->te_binbuf);
+      name=atom_getsymbol(argv)->s_name;
+    }
+    post("sub-patcherizing abstraction: %s", name);
+  }
+
+  return 0;
+}
+
+static t_glist*patcherize_makesub(t_canvas*cnv,
+				  const char* name, /* subpatch name of filename */
+				  int*save2file_,
+				  int X, int Y,
+				  int xmin, int ymin, int xmax, int ymax,
+				  int xwin, int ywin,
+				  t_patcherize_connections*connections,
+				  unsigned int maxdollarg);
+static t_glist*
+patcherize_makesub_tryagain(t_canvas*cnv,
+			   const char*name, int*save2file,
+			   int X, int Y,
+			   int xmin, int ymin, int xmax, int ymax,
+			   int xwin, int ywin,
+			   t_patcherize_connections*connections,
+			   unsigned int maxdollarg,
+			   t_binbuf*b, t_pd *boundx, t_pd *boundn) {
+  /* things went wrong, try again as subpatch */
+  t_glist*res=patcherize_makesub(cnv, name, 0,
+				 X, Y, xmin, ymin, xmax, ymax, xwin, ywin,
+				 connections, maxdollarg);
+  if(save2file)*save2file=0;
+  s__X.s_thing = boundx;
+  s__N.s_thing = boundn;
+  binbuf_free(b);
+  return res;
+}
+static t_glist*patcherize_makesub(t_canvas*cnv,
+				  const char* name, /* subpatch name of filename */
+				  int*save2file_,
+				  int X, int Y,
+				  int xmin, int ymin, int xmax, int ymax,
+				  int xwin, int ywin,
+				  t_patcherize_connections*connections,
+				  unsigned int maxdollarg) {
+  t_binbuf*b=NULL;
+  t_gobj*result=NULL;
+  t_patcherize_connection*iolets=NULL;
+  int x, y;
+  int width=xmax-xmin;
+  int height=ymax-ymin;
+  int save2file=(save2file_)?*save2file_:0;
+
+  /* save and clear bindings to symbols #a, $N, $X; restore when done */
+  t_pd *boundx = s__X.s_thing, *boundn = s__N.s_thing;
+  s__X.s_thing = &cnv->gl_pd;
+  s__N.s_thing = &pd_canvasmaker;
+
+  if(width<200) width=200;
+  if(height<100)height=100;
+
+  if (!name || !*name)save2file=0;
+  if(save2file && strcmp(name + strlen(name) - 3, ".pd")) {
+    /* not a Pd patch */
+    save2file=0;
+  }
+
+  b=binbuf_new();
+  if (save2file) {
+    // #N canvas 4 49 450 300 10;
+    binbuf_addv(b, "ssiiiii;", gensym("#N"), gensym("canvas"), xwin+xmin, ywin+ymin, width, height, 10);
+  } else {
+    binbuf_addv(b, "ssiiiisi;", gensym("#N"), gensym("canvas"), xwin+xmin, ywin+ymin, width, height, gensym(name), 0);
+  }
+
+  iolets=connections->inlets;
+  x=20;  y=20;
+  while(iolets) {
+    binbuf_addv(b, "ssiis;", gensym("#X"), gensym("obj"), x, y,
+		obj_issignaloutlet(iolets->object, iolets->index)?gensym("inlet~"):gensym("inlet"));
+    x+=50;
+    iolets=iolets->next;
+  }
+  iolets=connections->outlets;
+  x=20; y=height-30;
+  while(iolets) {
+    binbuf_addv(b, "ssiis;", gensym("#X"), gensym("obj"), x, y,
+		obj_issignaloutlet(iolets->object, iolets->index)?gensym("outlet~"):gensym("outlet"));
+    x+=50;
+    iolets=iolets->next;
+  }
+  if(save2file) {
+  } else {
+    binbuf_addv(b, "ssiiss;", gensym("#X"), gensym("restore"), X, Y, gensym("pd"), gensym(name));
+  }
+
+  if(save2file) {
+    /* save the binbuf to file */
+    char dirbuf[MAXPDSTRING];
+    const char*nameptr;
+    char*nameptr_res;
+    char objname[MAXPDSTRING];
+    int fd;
+    int len=strlen(name) -3 ;
+    unsigned int i;
+    strncpy(objname, name, MAXPDSTRING-1);
+    objname[MAXPDSTRING-1]=0;
+    if(len>0 && len<MAXPDSTRING)objname[len]=0;
+    nameptr=strrchr(name, '/');
+    nameptr=nameptr?(nameptr+1):name;
+
+    if(binbuf_write(b, name, "", 0)) {
+      /* things went wrong, try again as subpatch */
+      return patcherize_makesub_tryagain(cnv, objname, save2file_,
+					 X, Y, xmin, ymin, xmax, ymax, xwin, ywin,
+					 connections, maxdollarg,
+					 b, boundx, boundn);
+    }
+    /* and instantiate the file as an abstraction*/
+    if ((fd = canvas_open(cnv, nameptr, "",
+			  dirbuf, &nameptr_res, MAXPDSTRING, 0)) >= 0) {
+      sys_close(fd);
+      nameptr_res[-1]='/';
+      if(!strcmp(dirbuf, name)) {
+	strncpy(objname, nameptr_res, MAXPDSTRING-2);
+	objname[strlen(nameptr_res)-3]=0; // strip away ".pd".extension
+      }
+    }
+    binbuf_clear(b);
+    binbuf_addv(b, "ssiis", gensym("#X"), gensym("obj"), X, Y, gensym(objname));
+    for(i=1; i<=maxdollarg; i++) {
+      t_atom a;
+      char dollstring[MAXPDSTRING];
+      snprintf(dollstring, MAXPDSTRING-1, "$%d", i);
+      dollstring[MAXPDSTRING-1]=0;
+      SETSYMBOL(&a, gensym(dollstring));
+      binbuf_add(b, 1, &a);
+    }
+    binbuf_addsemi(b);
+  }
+  binbuf_eval(b, 0,0,0);
+  binbuf_free(b);
+
+  s__X.s_thing = boundx;
+  s__N.s_thing = boundn;
+
+  /* the new object is the last in the parent's glist */
+  for(result=cnv->gl_list; result->g_next;) result=result->g_next;
+
+  if(save2file_)*save2file_=save2file;
+  return pd_checkglist(&(result->g_pd));
+}
+
+static void canvas_patcherize(t_glist*cnv, t_symbol*s) {
+  /* migrate selected objects from one canvas to another without re-instantiating them */
+  int dspstate = 0;
+  int editFrom = 0;
+  t_gobj*gobj = NULL, *last=NULL;
+  int objcount=0;
+  t_gobj**gobjs=0;
+  t_glist*to;
+  int i=0;
+  int xpos=0, ypos=0;
+  int xmin, ymin, xmax, ymax;
+  int numins=0, numouts=0;
+  t_patcherize_connections*connections;
+  const char*name = 0;
+  int save2file=0;
+  int maxdollarg=0;
+
+  if(NULL == cnv)return;
+  xmin=ymin=INT_MAX;
+  xmax=ymax=INT_MIN;
+
+  if (s && s->s_name && *s->s_name) {
+    name=s->s_name;
+    save2file=1;
+  }
+
+  /* store all the selected objects.
+   * this needs to be done because the GUI-cleanup in glist_suspend_editor()
+   * will undo any selection...
+   */
+  gobjs=getbytes(0*sizeof(*gobjs));
+  for(gobj=cnv->gl_list; gobj; gobj=gobj->g_next) {
+    if(glist_isselected(cnv, gobj)) {
+      t_object*obj=pd_checkobject(&gobj->g_pd);
+      if(!include_in_patcherization(obj)){
+	/* deselect excluded objects */
+	glist_deselect(cnv, gobj);
+	continue;
+      }
+      if(obj) {
+	int dollarg=get_maxdollarg(obj);
+	int x=obj->te_xpix;
+	int y=obj->te_ypix;
+	xpos+=x;
+	ypos+=y;
+	if(xmin>x)xmin=x;if(xmax<x)xmax=x;
+	if(ymin>y)ymin=y;if(ymax<y)ymax=y;
+	if(dollarg>maxdollarg)maxdollarg=dollarg;
+      }
+      gobjs=resizebytes(gobjs, (objcount)*sizeof(*gobjs), (objcount+1)*sizeof(*gobjs));
+      gobjs[objcount]=gobj;
+      objcount++;
+    }
+  }
+
+  /* if nothing is selected, we are done... */
+  if(!objcount) {
+    freebytes(gobjs,objcount * sizeof(*gobjs));
+    return;
+  }
+
+  if(1==objcount && patcherize_single_canvas(gobjs[0], name, save2file)) {
+    post("single canvas patcherization");
+  } else {
+    t_patcherize_connection*iolets;
+    connections=get_connections(cnv);
+    iolets=connections->inlets;
+    if(!name)name="/*patcherized*/";
+
+    numins=0;
+    while(iolets) {
+      iolets=iolets->next;
+      numins++;
+    }
+
+    iolets=connections->outlets;
+    numouts=0;
+    while(iolets) {
+      iolets=iolets->next;
+      numouts++;
+    }
+    dspstate=canvas_suspend_dsp();
+
+    /* disconnect the boundary connections */
+    patcherize_boundary_disconnect(connections->inlets);
+    patcherize_boundary_disconnect(connections->outlets);
+
+    /* create a new sub-patch to patcherize into */
+    to=patcherize_makesub(cnv, name, &save2file,
+                          xpos/objcount, ypos/objcount,
+                          xmin, ymin, xmax+50, ymax+150,
+                          cnv->gl_screenx1,cnv->gl_screeny1,
+                          connections, maxdollarg);
+    if(!to)
+      goto cleanup;
+
+    editFrom=glist_suspend_editor(cnv);
+
+    /* move the objects to the new subcanvas */
+    for(i=0; i<objcount; i++) {
+      t_gobj*gobj2 = NULL;
+      int doit=0;
+      gobj=gobjs[i];
+
+      /* find the gobj that points to the current one (stored in 'last') */
+      for(gobj2=cnv->gl_list; gobj2; last=gobj2, gobj2=gobj2->g_next) {
+        if (gobj == gobj2) {
+          doit=1;
+          break;
+        }
+      }
+      if (!doit)continue;
+
+      /* remove the object from the 'from'-canvas */
+      if (last)
+        last->g_next = gobj->g_next;
+      else
+        cnv->gl_list = gobj->g_next;
+
+      /* append it to the 'to'-canvas */
+      if(to->gl_list) {
+        for(gobj2=to->gl_list; gobj2 && gobj2->g_next;) gobj2=gobj2->g_next;
+        gobj2->g_next = gobj;
+      } else {
+        to->gl_list = gobj;
+      }
+      gobj->g_next = 0;
+    }
+
+    patcherize_fixcoordinates(objcount, gobjs, xmin, ymin);
+
+    /* reconnect the boundary connections */
+    //print_conns("inlets :",connections->inlets);
+    //print_conns("outlets:",connections->outlets);
+    patcherize_boundary_reconnect(to, connections);
+  }
+  if(save2file) {
+    object_typedmess(&to->gl_obj, gensym("menusave"), 0, 0);
+  }
+  canvas_dirty(cnv, 1);
+ cleanup:
+  /* cleanup */
+  free_connections(connections);
+  freebytes(gobjs,objcount * sizeof(*gobjs));
+
+  /* restore state */
+  glist_resume_editor(cnv, editFrom);
+  canvas_redraw(cnv);
+  canvas_resume_dsp(dspstate);
+}
+
+void patcherize_setup(void)
+{
+  if(NULL==canvas_class)return;
+  //iemguts_boilerplate("patcherize - turn objects into a subpatch", 0);
+  post("patcherize - turn objects into a subpatch");
+
+  if(NULL==zgetfn(&canvas_class, gensym("patcherize")))
+    class_addmethod(canvas_class, (t_method)canvas_patcherize, gensym("patcherize"), A_DEFSYM, 0);
+
+  if(0) {
+    print_glist(NULL);
+    print_conns("", NULL);
+    o2g(NULL);
+  }
+}
diff --git a/punish/triggerize-plugin/LICENSE.md b/punish/triggerize-plugin/LICENSE.md
new file mode 100644
index 0000000..74d573e
--- /dev/null
+++ b/punish/triggerize-plugin/LICENSE.md
@@ -0,0 +1,344 @@
+GNU GENERAL PUBLIC LICENSE
+==========================
+Version 2, June 1991
+
+> Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA  
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+# Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+
+#                     GNU GENERAL PUBLIC LICENSE                    #
+## TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ##
+
+- *0\.* This License applies to any program or other work which contains
+	a notice placed by the copyright holder saying it may be distributed
+	under the terms of this General Public License.  The "Program", below,
+	refers to any such program or work, and a "work based on the Program"
+	means either the Program or any derivative work under copyright law:
+	that is to say, a work containing the Program or a portion of it,
+	either verbatim or with modifications and/or translated into another
+	language.  (Hereinafter, translation is included without limitation in
+	the term "modification".)  Each licensee is addressed as "you".
+	
+	Activities other than copying, distribution and modification are not
+	covered by this License; they are outside its scope.  The act of
+	running the Program is not restricted, and the output from the Program
+	is covered only if its contents constitute a work based on the
+	Program (independent of having been made by running the Program).
+	Whether that is true depends on what the Program does.
+
+- 1\. You may copy and distribute verbatim copies of the Program's
+	source code as you receive it, in any medium, provided that you
+	conspicuously and appropriately publish on each copy an appropriate
+	copyright notice and disclaimer of warranty; keep intact all the
+	notices that refer to this License and to the absence of any warranty;
+	and give any other recipients of the Program a copy of this License
+	along with the Program.
+
+	You may charge a fee for the physical act of transferring a copy, and
+	you may at your option offer warranty protection in exchange for a fee.
+
+- 2\. You may modify your copy or copies of the Program or any portion
+	of it, thus forming a work based on the Program, and copy and
+	distribute such modifications or work under the terms of Section 1
+	above, provided that you also meet all of these conditions:
+
+		a) You must cause the modified files to carry prominent notices
+		stating that you changed the files and the date of any change.
+		
+		b) You must cause any work that you distribute or publish, that in
+		whole or in part contains or is derived from the Program or any
+		part thereof, to be licensed as a whole at no charge to all third
+		parties under the terms of this License.
+		
+		c) If the modified program normally reads commands interactively
+		when run, you must cause it, when started running for such
+		interactive use in the most ordinary way, to print or display an
+		announcement including an appropriate copyright notice and a
+		notice that there is no warranty (or else, saying that you provide
+		a warranty) and that users may redistribute the program under
+		these conditions, and telling the user how to view a copy of this
+		License.  (Exception: if the Program itself is interactive but
+		does not normally print such an announcement, your work based on
+		the Program is not required to print an announcement.)
+
+	These requirements apply to the modified work as a whole.  If
+	identifiable sections of that work are not derived from the Program,
+	and can be reasonably considered independent and separate works in
+	themselves, then this License, and its terms, do not apply to those
+	sections when you distribute them as separate works.  But when you
+	distribute the same sections as part of a whole which is a work based
+	on the Program, the distribution of the whole must be on the terms of
+	this License, whose permissions for other licensees extend to the
+	entire whole, and thus to each and every part regardless of who wrote it.
+	
+	Thus, it is not the intent of this section to claim rights or contest
+	your rights to work written entirely by you; rather, the intent is to
+	exercise the right to control the distribution of derivative or
+	collective works based on the Program.
+	
+	In addition, mere aggregation of another work not based on the Program
+	with the Program (or with a work based on the Program) on a volume of
+	a storage or distribution medium does not bring the other work under
+	the scope of this License.
+
+- 3\. You may copy and distribute the Program (or a work based on it,
+	under Section 2) in object code or executable form under the terms of
+	Sections 1 and 2 above provided that you also do one of the following:
+
+    	a) Accompany it with the complete corresponding machine-readable
+    	source code, which must be distributed under the terms of Sections
+    	1 and 2 above on a medium customarily used for software interchange; or,
+
+    	b) Accompany it with a written offer, valid for at least three
+    	years, to give any third party, for a charge no more than your
+    	cost of physically performing source distribution, a complete
+    	machine-readable copy of the corresponding source code, to be
+    	distributed under the terms of Sections 1 and 2 above on a medium
+    	customarily used for software interchange; or,
+
+    	c) Accompany it with the information you received as to the offer
+    	to distribute corresponding source code.  (This alternative is
+    	allowed only for noncommercial distribution and only if you
+    	received the program in object code or executable form with such
+    	an offer, in accord with Subsection b above.)
+
+	The source code for a work means the preferred form of the work for
+	making modifications to it.  For an executable work, complete source
+	code means all the source code for all modules it contains, plus any
+	associated interface definition files, plus the scripts used to
+	control compilation and installation of the executable.  However, as a
+	special exception, the source code distributed need not include
+	anything that is normally distributed (in either source or binary
+	form) with the major components (compiler, kernel, and so on) of the
+	operating system on which the executable runs, unless that component
+	itself accompanies the executable.
+	
+	If distribution of executable or object code is made by offering
+	access to copy from a designated place, then offering equivalent
+	access to copy the source code from the same place counts as
+	distribution of the source code, even though third parties are not
+	compelled to copy the source along with the object code.
+
+- 4\. You may not copy, modify, sublicense, or distribute the Program
+	except as expressly provided under this License.  Any attempt
+	otherwise to copy, modify, sublicense or distribute the Program is
+	void, and will automatically terminate your rights under this License.
+	However, parties who have received copies, or rights, from you under
+	this License will not have their licenses terminated so long as such
+	parties remain in full compliance.
+
+- 5\. You are not required to accept this License, since you have not
+	signed it.  However, nothing else grants you permission to modify or
+	distribute the Program or its derivative works.  These actions are
+	prohibited by law if you do not accept this License.  Therefore, by
+	modifying or distributing the Program (or any work based on the
+	Program), you indicate your acceptance of this License to do so, and
+	all its terms and conditions for copying, distributing or modifying
+	the Program or works based on it.
+
+- 6\. Each time you redistribute the Program (or any work based on the
+	Program), the recipient automatically receives a license from the
+	original licensor to copy, distribute or modify the Program subject to
+	these terms and conditions.  You may not impose any further
+	restrictions on the recipients' exercise of the rights granted herein.
+	You are not responsible for enforcing compliance by third parties to
+	this License.
+
+- 7\. If, as a consequence of a court judgment or allegation of patent
+	infringement or for any other reason (not limited to patent issues),
+	conditions are imposed on you (whether by court order, agreement or
+	otherwise) that contradict the conditions of this License, they do not
+	excuse you from the conditions of this License.  If you cannot
+	distribute so as to satisfy simultaneously your obligations under this
+	License and any other pertinent obligations, then as a consequence you
+	may not distribute the Program at all.  For example, if a patent
+	license would not permit royalty-free redistribution of the Program by
+	all those who receive copies directly or indirectly through you, then
+	the only way you could satisfy both it and this License would be to
+	refrain entirely from distribution of the Program.
+	
+	If any portion of this section is held invalid or unenforceable under
+	any particular circumstance, the balance of the section is intended to
+	apply and the section as a whole is intended to apply in other
+	circumstances.
+	
+	It is not the purpose of this section to induce you to infringe any
+	patents or other property right claims or to contest validity of any
+	such claims; this section has the sole purpose of protecting the
+	integrity of the free software distribution system, which is
+	implemented by public license practices.  Many people have made
+	generous contributions to the wide range of software distributed
+	through that system in reliance on consistent application of that
+	system; it is up to the author/donor to decide if he or she is willing
+	to distribute software through any other system and a licensee cannot
+	impose that choice.
+	
+	This section is intended to make thoroughly clear what is believed to
+	be a consequence of the rest of this License.
+
+- 8\. If the distribution and/or use of the Program is restricted in
+	certain countries either by patents or by copyrighted interfaces, the
+	original copyright holder who places the Program under this License
+	may add an explicit geographical distribution limitation excluding
+	those countries, so that distribution is permitted only in or among
+	countries not thus excluded.  In such case, this License incorporates
+	the limitation as if written in the body of this License.
+	
+- 9\. The Free Software Foundation may publish revised and/or new versions
+	of the General Public License from time to time.  Such new versions will
+	be similar in spirit to the present version, but may differ in detail to
+	address new problems or concerns.
+	
+	Each version is given a distinguishing version number.  If the Program
+	specifies a version number of this License which applies to it and "any
+	later version", you have the option of following the terms and conditions
+	either of that version or of any later version published by the Free
+	Software Foundation.  If the Program does not specify a version number of
+	this License, you may choose any version ever published by the Free Software
+	Foundation.
+	
+- 10\. If you wish to incorporate parts of the Program into other free
+	programs whose distribution conditions are different, write to the author
+	to ask for permission.  For software which is copyrighted by the Free
+	Software Foundation, write to the Free Software Foundation; we sometimes
+	make exceptions for this.  Our decision will be guided by the two goals
+	of preserving the free status of all derivatives of our free software and
+	of promoting the sharing and reuse of software generally.
+
+
+## NO WARRANTY
+
+- 11\. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+	FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+	OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+	PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+	OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+	MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+	TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+	PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+	REPAIR OR CORRECTION.
+	
+- 12\. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+	WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+	REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+	INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+	OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+	TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+	YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+	PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+	POSSIBILITY OF SUCH DAMAGES.
+
+##                      END OF TERMS AND CONDITIONS                      ##
+
+---------------------------------------------------------------------------
+
+###            How to Apply These Terms to Your New Programs            ###
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+  Also add information on how to contact you by electronic and paper mail.
+
+  If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+  The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+  You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+	Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+	`Gnomovision' (which makes passes at compilers) written by James Hacker.
+	
+	<signature of Ty Coon>, 1 April 1989
+	Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/punish/triggerize-plugin/Makefile b/punish/triggerize-plugin/Makefile
new file mode 100755
index 0000000..3b6be7d
--- /dev/null
+++ b/punish/triggerize-plugin/Makefile
@@ -0,0 +1,30 @@
+#!/usr/bin/make -f
+# Makefile for pure data externals in lib creb.
+# Needs Makefile.pdlibbuilder to work (https://github.com/pure-data/pd-lib-builder)
+
+lib.name = triggerize-plugin
+
+# special file that does not provide a class
+lib.setup.sources = 
+
+# all other C and C++ files in subdirs are source files per class
+# (alternatively, enumerate them by hand)
+class.sources = triggerize.c
+
+datafiles = \
+$(wildcard *-help.pd) \
+triggerize-plugin.tcl \
+README.md LICENSE.md
+
+datadirs =  
+
+################################################################################
+### pdlibbuilder ###############################################################
+################################################################################
+
+
+# Include Makefile.pdlibbuilder from this directory, or else from the general
+# 'punish' folder
+
+include $(firstword $(wildcard ../Makefile.pdlibbuilder Makefile.pdlibbuilder))
+
diff --git a/punish/triggerize-plugin/Makefile.pdlibbuilder b/punish/triggerize-plugin/Makefile.pdlibbuilder
new file mode 100644
index 0000000..a91bb39
--- /dev/null
+++ b/punish/triggerize-plugin/Makefile.pdlibbuilder
@@ -0,0 +1,1201 @@
+# Makefile.pdlibbuilder version 0.2.3, dated 2016-03-29
+#
+# Helper makefile for Pure Data external libraries.
+# Written by Katja Vetter March-June 2015 for the public domain. No warranties.
+# Inspired by Hans Christoph Steiner's Makefile Template and Stephan Beal's
+# ShakeNMake.
+#
+# GNU make version >= 3.81 required.
+#
+#
+#=== characteristics ===========================================================
+#
+#
+# - defines build settings based on autodetected OS and architecture
+# - defines rules to build Pd class- or lib executables from C or C++ sources
+# - defines rules for libdir installation
+# - defines convenience targets for developer and user
+# - evaluates implicit dependencies for non-clean builds
+#
+#
+#=== basic usage ===============================================================
+#
+#
+# In your Makefile, define your Pd lib name and class files, and include
+# Makefile.pdlibbuilder at the end of the Makefile. Like so:
+#
+#    ________________________________________________________________________
+#
+#     # Makefile for mylib
+#
+#     lib.name = mylib
+#
+#     class.sources = myclass1.c myclass2.c
+#
+#     datafiles = myclass1-help.pd myclass2-help.pd README.txt LICENSE.txt
+#
+#     include Makefile.pdlibbuilder
+#    ________________________________________________________________________
+#
+#
+# For files in class.sources it is assumed that class basename == source file
+# basename. The default target builds all classes as individual executables
+# with Pd's default extension for the platform. For anything more than the
+# most basic usage, continue reading.
+#
+#
+#=== list of Makefile.pdlibbuilder API variables ===============================
+#
+#
+# Variables available for definition in your library Makefile:
+#
+# - lib.name
+# - lib.setup.sources
+# - class.sources
+# - common.sources
+# - shared.sources
+# - <classname>.class.sources
+# - <classname>.class.ldflags
+# - <classname>.class.ldlibs
+# - cflags
+# - ldflags
+# - ldlibs
+# - datafiles
+# - datadirs
+# - makefiles
+# - makefiledirs
+# - externalsdir
+#
+# Optional multiline defines evaluated per operating system:
+#
+# - forLinux
+# - forDarwin
+# - forWindows
+#
+#
+# Variables avaialable for (re)definition via command arguments:
+#
+# - pdbinpath (Windows only)
+# - pdincludepath
+# - DESTDIR
+# - prefix
+# - libdir
+# - pkglibdir
+# - CPPFLAGS
+# - CFLAGS
+# - LDFLAGS
+# - CC
+# - CXX
+# - INSTALL
+# - INSTALL_PROGRAM
+# - INSTALL_DATA
+# - INSTALL_DIR
+#
+# Variables available for your makefile or as command argument:
+#
+# - objectsdir
+# - make-lib-executable
+# - suppress-wunused
+#
+#
+#=== descriptions of Makefile.pdlibbuilder API variables =======================
+#
+#
+# lib.name: 
+# Name of the library directory as it will be installed / distributed. Also the
+# name of the lib executable in the case where all classes are linked into
+# a single binary.
+#
+# lib.setup.sources:
+# Source file(s) (C or C++) which must be compiled only when linking all classes
+# into a single lib binary.
+#
+# class.sources:
+# All sources files (C or C++) for which the condition holds that 
+# class name == source file basename.
+#
+# <classname>.class.sources:
+# Source file(s) (C or C++) specific to class <classname>. Use this for
+# multiple-source classes or when class name != source file basename.
+#
+# common.sources:
+# Source file(s) which must be statically linked to each class in the library.
+#
+# shared.sources:
+# Source file(s) (C or C++) to build a shared dynamic link lib, to be linked
+# with all class executables.
+#
+# cflags, ldflags, ldlibs:
+# Define cflags (preprocessor&compiler), ldflags (linker) and ldlibs (dynamic
+# link libs) for the whole library. These flags are added to platform-specific
+# flags defined by Makefile.pdlibbuilder.
+#
+# <classname>.class.ldflags and <classname>.class.ldlibs: 
+# Define ldflags resp. ldlibs specific to class <classname>. These flags are
+# added to platform-specific flags defined by Makefile.pdlibbuilder, and flags
+# defined in your Makefile for the whole library. Note: cflags can not be
+# defined per class in the current implementation.
+#
+# datafiles and datadirs: 
+# All extra files you want to include in binary distributions of the
+# library: abstractions and help patches, example patches, meta patch, readme
+# and license texts, manuals, sound files, etcetera. Use 'datafiles' for all
+# files that should go into your lib rootdir and 'datadirs' for complete
+# directories you want to copy from source to distribution.
+#
+# externalsdir: 
+# Relative path to directory 'externals' in the context of pd-extended SVN, or
+# any other centralized build layout for multiple libraries. Default value
+# is '..', meaning the direct parent. The value is used in search paths for 
+# pd core components (header files, and executable in the case of Windows).
+#
+# forLinux, forDarwin, forWindows:
+# Shorthand for 'variable definitions for Linux only' etc. Use like:
+#    define forLinux
+#      cflags += -DLINUX
+#      class.sources += linuxthing.c
+#    endef
+#
+# makefiles and makefiledirs: 
+# Extra makefiles or directories with makefiles that should be made in sub-make
+# processes.
+#
+# pdbinpath:
+# For Windows only. Directory where pd.dll can be found for linking.
+#
+# pdincludepath:
+# Directory where Pd API m_pd.h can be found, and other Pd header files.
+#
+# DESTDIR, prefix, libdir:
+# Components of the path for installation as conventionally used on Linux.
+#
+# pkglibdir:
+# Base path for installation of Pd library directories. Default is specified
+# per OS, see section about paths below.
+#
+# objectsdir:
+# Alias of pkglibdir. Can be defined in your makefile to enable project-
+# dependent relative install locations.
+#
+# CPPFLAGS:
+# Preprocessor flags which are not strictly required for building.
+#
+# CFLAGS:
+# Compiler flags which are not strictly required for building. Compiler flags
+# defined by Makefile.pdlibbuilder for warning, optimization and architecture
+# specification are overriden by CFLAGS.
+#
+# LDFLAGS:
+# Linker flags which are not strictly required for building. Linker flags
+# defined by Makefile.pdlibbuilder for architecture specification are overriden
+# by LDFLAGS.
+#
+# CC and CXX:
+# C and C++ compiler programs as defined in your build environment.
+#
+# INSTALL, INSTALL_PROGRAM, INSTALL_DATA, INSTALL_DIR:
+# Definitions of install program, may be overriden via command argument.
+#
+# make-lib-executable:
+# When this variable is defined 'yes' in your makefile or as command argument,
+# Makefile.pdlibbuilder will try to build all classes into a single library
+# executable (but it will force exit if lib.setup.sources is undefined).
+# If your makefile defines 'make-lib-executable=yes' as the library default,
+# this can still be overriden with 'make-lib-executable=no' as command argument 
+# to build individual class executables (the Makefile.pdlibbuilder default.)
+#
+# suppress-wunused:
+# When this variable is defined ('yes' or any other value), -Wunused-variable,
+# -Wunused-parameter, -Wunused-value and -Wunused-function are suppressed,
+# but the other warnings from -Wall are retained.
+#
+#
+#=== paths =====================================================================
+#
+#
+# Source files in directories other than current working directory must be
+# prefixed with their relative path. Do not rely on VPATH or vpath.
+# Object (.o) files are built in the directory of their source files.
+# Executables are built in current working directory. 
+#
+# Variable 'pdincludepath' stores a location where m_pd.h is expected to reside.
+# Locations where Makefile.pdlibbuilder tries to find it, in order of priority:
+#
+# any OS:   $(externalsdir)../pd/src
+#
+# Linux:    /usr/include/pdextended
+#           /usr/include/pd
+#
+# OSX:      /Applications/Pd-extended.app/Contents/Resources/include/pdextended
+#           /Applications/Pd.app/Contents/Resources/src
+#
+# Windows:  %PROGRAMFILES%/pd/include/pdextended
+#           %PROGRAMFILES%/pd/src
+#
+# The path for installation of all library components is constructed as:
+#
+# installpath := $(DESTDIR)$(objectsdir)/$(lib.name)
+#
+# Default for 'objectsdir' is defined per platform and follows this convention:
+# https://puredata.info/docs/faq/how-do-i-install-externals-and-help-files
+#
+# Linux:    /usr/local/lib/pd-externals
+# OSX:      ~/Library/Pd
+# Windows:  %APPDATA%/Pd
+#
+# The rationale for not installing to ~/pd-externals by default on Linux
+# is that some people share the home dir between 32 and 64 bit installations.
+#
+#
+#=== targets ===================================================================
+#
+#
+# all: build $(executables) plus optional post target
+# post: target to build after $(executables)
+# alldebug: build all with -g option turned on for debug symbols
+# <classname>: force clean build of an individual class
+# <sourcefile>.pre: make preprocessor output file in current working directory
+# <sourcefile>.lst: make asm/source output file in current working directory
+#
+# install: install executables and data files
+# clean: remove build products from source tree
+#
+# help: print help text
+# vars: print makefile variables
+# allvars: print all variables
+# depend: print generated prerequisites
+# coffee: dummy target
+#
+# Variable $(executables) expands to class executables plus optional shared lib,
+# or alternatively to single lib executable when make-lib-executable=true.
+# Targets pre and post can be defined by library makefile. Make sure to include
+# Makefile.pdlibbuilder first so default target all will not be redefined.
+#
+#
+#=== Pd-extended libdir concept ================================================
+#
+#
+# For libdir layout as conceived by Hans-Christoph Steiner, see:
+#
+# https://puredata.info/docs/developer/Libdir
+#
+# Files README.txt, LICENSE.txt and <lib.name>-meta.pd are part of the libdir
+# convention. Help patches for each class and abstraction are supposed to be
+# available. Makefile.pdlibbuilder does not force the presence of these files
+# however. It does not automatically include such files in libdir installations.
+# Data files you want to include in distributions must be defined explicitly in
+# your Makefile.
+#
+#
+#=== Makefile.pdlibbuilder syntax conventions ==================================
+#
+#
+# Makefile.pdlibbuilder variable names are lower case. Default make variables,
+# environment variables, and standard user variables (CC, CXX, CFLAGS, DESTDIR)
+# are upper case. Use target 'allvars' to print all variables and their values.
+#
+# 'Fields' in data variables are separated by dots, like in 'foo.class.sources'.
+# Words in variables expressing a function or command are separated by dashes, 
+# like in 'make-lib-executable'.
+#
+#
+#=== useful make options =======================================================
+#
+#
+# Use 'make -d <target>' to print debug details of the make process.
+# Use 'make -p <target>' to print make's database.
+#
+#
+#=== TODO ======================================================================
+#
+#
+# - decide whether to use -static-libgcc or shared dll in MinGW
+# - cygwin support
+# - android support
+# - Windows 64 bit support
+# - figure out how to handle '$' in filenames
+# - add makefile template targets dpkg-source dist libdir distclean tags?
+#
+#
+#=== end of documentation sections =============================================
+#
+# 
+################################################################################
+################################################################################
+################################################################################
+
+
+# GNU make version 3.81 (2006) or higher is required because of the following:
+# - function 'info'
+# - variable '.DEFAULT_GOAL'
+
+# force exit when make version is < 3.81
+ifneq ($(firstword $(sort 3.81 $(MAKE_VERSION))), 3.81)
+  $(error GNU make version 3.81 or higher is required)
+endif
+
+# Relative path to externals root dir in multi-lib source tree like 
+# pd-extended SVN. Default is parent of current working directory. May be
+# defined differently in including makefile. This variable is used to probe for
+# paths.
+externalsdir ?= ..
+
+# variable you can use to check if Makefile.pdlibbuilder is already included
+Makefile.pdlibbuilder = true
+
+
+################################################################################
+### variables: library name and version ########################################
+################################################################################
+
+
+# strip possibles spaces from lib.name, they mess up calculated file names
+lib.name := $(strip $(lib.name))
+
+# if meta file exists, check library version 
+metafile := $(wildcard $(lib.name)-meta.pd)
+
+ifdef metafile
+  lib.version := $(shell sed -n \
+    's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' \
+    $(metafile))
+endif
+
+
+################################################################################
+### variables: files ###########################################################
+################################################################################
+
+
+#=== sources ===================================================================
+
+
+# (re)define <classname>.class.sources using file names in class.sources
+
+define add-class-source
+$(notdir $(basename $v)).class.sources += $v
+endef
+
+$(foreach v, $(class.sources), $(eval $(add-class-source)))
+
+# derive class names from <classname>.class.sources variables
+sourcevariables := $(filter %.class.sources, $(.VARIABLES))
+classes := $(basename $(basename $(sourcevariables)))
+
+# accumulate all source files specified in makefile
+classes.sources := $(sort $(foreach v, $(sourcevariables), $($v)))
+all.sources := $(classes.sources) $(lib.setup.sources) \
+  $(shared.sources) $(common.sources)
+
+
+#=== object files ==============================================================
+
+
+# construct object filenames from all C and C++ source file names
+classes.objects := $(addsuffix .o, $(basename $(classes.sources)))
+common.objects := $(addsuffix .o, $(basename $(common.sources)))
+shared.objects := $(addsuffix .o, $(basename $(shared.sources)))
+lib.setup.objects := $(addsuffix .o, $(basename $(lib.setup.sources)))
+all.objects = $(classes.objects) $(common.objects) $(shared.objects) \
+  $(lib.setup.objects)
+
+
+#=== executables ===============================================================
+
+
+# use recursive variables here because executable extension is not yet known
+
+# construct class executable names from class names
+classes.executables = $(addsuffix .$(extension), $(classes))
+
+# construct shared lib executable name if shared sources are defined
+ifdef shared.sources
+  shared.lib = lib$(lib.name).$(shared.extension)
+else
+  shared.lib =
+endif
+
+
+################################################################################
+### variables per platform #####################################################
+################################################################################
+
+
+#=== flags per architecture ====================================================
+
+
+# Set architecture-dependent cflags, mainly for Linux. For Mac and Windows, 
+# arch.c.flags are overriden below.
+
+machine := $(shell uname -m)
+
+# Raspberry Pi 1st generation
+ifeq ($(machine), armv6l)
+  arch.c.flags = -march=armv6 -mfpu=vfp -mfloat-abi=hard
+endif
+
+# Beagle, Udoo, RPi2 etc.
+ifeq ($(machine), armv7l)
+  arch.c.flags = -march=armv7-a -mfpu=vfpv3 -mfloat-abi=hard
+endif
+
+# Intel 32 bit, build with SSE and SSE2 instructions
+ifeq ($(findstring $(machine), i386 i686), $(machine))
+  arch.c.flags = -march=pentium4 -mfpmath=sse -msse -msse2
+endif
+
+# Intel/AMD 64 bit, build with SSE, SSE2 and SSE3 instructions
+ifeq ($(findstring $(machine), ia64 x86_64), $(machine))
+  arch.c.flags = -march=core2 -mfpmath=sse -msse -msse2 -msse3 
+endif
+
+
+#=== operating system ==========================================================
+
+
+# The following systems are defined: Linux, Darwin, Windows. GNU and
+# GNU/kFreeBSD are treated as Linux to get the same options. System-specific
+# multiline defines (optionally set in library makefile) are conditionally
+# evaluated here.
+
+uname := $(shell uname)
+
+ifeq ($(findstring $(uname), Linux GNU GNU/kFreeBSD), $(uname))
+  system = Linux
+  $(eval $(forLinux))
+endif
+
+ifeq ($(uname), Darwin)
+  system = Darwin
+  $(eval $(forDarwin))
+endif
+
+ifeq ($(findstring MINGW, $(uname)), MINGW)
+  system = Windows
+  $(eval $(forWindows))
+endif
+
+# TODO: Cygwin, Android
+
+
+#=== flags and paths for Linux =================================================
+
+
+ifeq ($(system), Linux)
+  prefix = /usr/local
+  libdir := $(prefix)/lib
+  pkglibdir = $(libdir)/pd-externals
+  pdincludepath := $(firstword $(wildcard \
+    $(externalsdir)/../pd/src \
+    /usr/include/pdextended \
+    /usr/include/pd))
+  extension = pd_linux
+  cpp.flags := -DUNIX
+  c.flags := -fpic
+  c.ldflags := -rdynamic -shared -fpic -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags
+  c.ldlibs := -lc -lm
+  cxx.flags := -fpic -fcheck-new
+  cxx.ldflags := -rdynamic -shared -fpic -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags
+  cxx.ldlibs := -lc -lm -lstdc++
+  shared.extension = so
+  shared.ldflags := -rdynamic -fpic -shared -Wl,-soname,$(shared.lib)
+  stripflags = --strip-unneeded -R .note -R .comment
+endif
+
+
+#=== flags and paths for Darwin ================================================
+
+
+# On OSX we try to build fat binaries by default. It is assumed that OSX i386
+# can build for ppc and OSX x86_64 can't. TODO: try to refine this condition.
+# LLVM-clang doesn't support -fcheck-new, therefore this flag is omitted for
+# OSX x86_64.
+
+ifeq ($(system), Darwin)
+  pkglibdir = $(HOME)/Library/Pd
+  pdincludepath := $(firstword $(wildcard \
+    $(externalsdir)/../pd/src \
+    /Applications/Pd-extended*.app/Contents/Resources/include/pdextended \
+    /Applications/Pd*.app/Contents/Resources/src))
+  extension = pd_darwin
+  cpp.flags := -DUNIX -DMACOSX -I /sw/include
+  c.flags := 
+  c.ldflags := -undefined suppress -flat_namespace -bundle
+  c.ldlibs := -lc
+  cxx.ldflags := -undefined suppress -flat_namespace -bundle
+  cxx.ldlibs := -lc
+  shared.extension = dylib
+  shared.ldflags = -dynamiclib -undefined dynamic_lookup \
+    -install_name @loader_path/$(shared.lib) \
+    -compatibility_version 1 -current_version 1.0
+  stripflags = -x
+  ifeq ($(machine), i386)
+    cxx.flags := -fcheck-new
+    arch.c.flags := -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=10.4
+    arch.ld.flags := -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=10.4
+  endif
+  ifeq ($(machine), x86_64)
+    arch.c.flags := -arch i386 -arch x86_64 -mmacosx-version-min=10.5
+    arch.ld.flags := -arch i386 -arch x86_64 -mmacosx-version-min=10.5
+  endif
+endif
+
+
+#=== flags and paths for Windows ===============================================
+
+
+# Standard paths on Windows contain spaces, and GNU make functions treat such
+# paths as lists, with unintended effects. Therefore we must use shell function
+# ls instead of make's wildcard, and probe for each standard path individually.
+# Using double quotes around paths with spaces is obligatory. Since some path
+# variables are assembled or re-expanded later, great care must be taken to put
+# quotes at appropriate points throughout the makefile. Thanks, Bill.
+
+# paths for 32-bit executables on 64-bit Windows aren't yet defined here (TODO)
+ifeq ($(system), Windows)
+  pkglibdir := $(APPDATA)/Pd
+  pdbinpath := $(wildcard $(externalsdir)/../pd/bin)
+  pdincludepath := $(wildcard $(externalsdir)/../pd/src)
+  ifndef pdbinpath
+    pdbinpath := $(shell ls -d "$(PROGRAMFILES)/pd/bin")
+  endif
+  ifndef pdincludepath
+    pdincludepath := $(shell ls -d "$(PROGRAMFILES)/pd/include/pdextended")
+  endif
+  ifndef pdincludepath
+    pdincludepath := $(shell ls -d "$(PROGRAMFILES)/pd/src")
+  endif
+endif
+
+# On Windows we build 32 bit by default to match Pd(-extended) binary 
+# distributions. This may change in the future.
+# TODO: decide whether -mms-bitfields should be specified.
+ifeq ($(system), Windows)
+  extension = dll
+  CC = gcc
+  CXX = g++
+  arch.c.flags := -march=pentium4 -msse -msse2 -mfpmath=sse
+  cpp.flags := -DMSW -DNT
+  c.flags :=
+  c.ldflags := -static-libgcc -shared \
+    -Wl,--enable-auto-import "$(pdbinpath)/pd.dll"
+  c.ldlibs :=
+  cxx.flags := -fcheck-new
+  cxx.ldflags := -static-libstdc++ -shared \
+    -Wl,--enable-auto-import "$(pdbinpath)/pd.dll"
+  cxx.ldlibs :=
+  shared.extension = dll
+  shared.ldflags := -static-libgcc -shared "$(pdbinpath)/pd.dll"
+  stripflags = --strip-unneeded -R .note -R .comment
+endif
+
+
+#=== paths =====================================================================
+
+
+# Default pkglibdir is specified above per operating system. It is aliased as 
+# 'objectsdir' to retain compatibility with pd-extended template. Assignment
+# operator '?=' is used to enable a project-relative path definition in the
+# including makefile.
+objectsdir ?= $(pkglibdir)
+
+# base path where all components of the lib will be installed by default
+installpath := $(DESTDIR)$(objectsdir)/$(lib.name)
+
+# check if pdincludepath contains spaces (as is often the case on Windows)
+# if so, store the path so we can later do checks with it
+pdincludepathwithspaces := $(if $(word 2, $(pdincludepath)), $(pdincludepath))
+
+
+#=== accumulated build flags ===================================================
+
+
+# From GNU make docs: 'Users expect to be able to specify CFLAGS freely
+# themselves.' So we use CFLAGS to define options which  are not strictly
+# required for compilation: optimizations, architecture specifications, and 
+# warnings. CFLAGS can be safely overriden using a make command argument.
+# Variables cflags, ldflags and ldlibs may be defined in including makefile.
+
+optimization.flags = -O3 -ffast-math -funroll-loops -fomit-frame-pointer
+warn.flags = -Wall -Wextra -Wshadow -Winline -Wstrict-aliasing
+
+# suppress -Wunused-variable & Co if you don't want to clutter a build log
+ifdef suppress-wunused
+  warn.flags += $(addprefix -Wno-unused-, function parameter value variable)
+endif
+
+CFLAGS = $(warn.flags) $(optimization.flags) $(arch.c.flags)
+
+# preprocessor flags
+cpp.flags += -DPD -I "$(pdincludepath)" $(CPPFLAGS)
+
+# architecture specifications for linker are overridable by LDFLAGS
+LDFLAGS := $(arch.ld.flags)
+
+# now add the same ld flags to shared dynamic lib
+shared.ldflags := $(shared.ldflags) $(LDFLAGS)
+
+# accumulated flags for C compiler / linker
+c.flags := $(cpp.flags) $(c.flags) $(cflags) $(CFLAGS)
+c.ldflags := $(c.ldflags) $(ldflags) $(LDFLAGS)
+c.ldlibs := $(c.ldlibs) $(ldlibs)
+
+# accumulated flags for C++ compiler / linker
+cxx.flags := $(cpp.flags) $(cxx.flags) $(cflags) $(CFLAGS)
+cxx.ldflags := $(cxx.ldflags) $(ldflags) $(LDFLAGS)
+cxx.ldlibs := $(cxx.ldlibs) $(ldlibs)
+
+
+################################################################################
+### variables: tools ###########################################################
+################################################################################
+
+
+# aliases so we can later define 'compile-$1' and set 'c' or 'cxx' as argument
+compile-c := $(CC)
+compile-cxx := $(CXX)
+
+
+################################################################################
+### checks #####################################################################
+################################################################################
+
+
+# At this point most variables are defined. Now do some checks and info's
+# before rules begin.
+
+# 'forward declaration' of default target, needed to do checks
+all:
+
+# To avoid unpredictable results, make sure the default target is not redefined
+# by including makefile. 
+ifneq ($(.DEFAULT_GOAL), all)
+  $(error Default target must be 'all'.)
+endif
+
+# find out which target(s) will be made
+ifdef MAKECMDGOALS
+  goals := $(MAKECMDGOALS)
+else
+  goals := all
+endif
+
+# store path to Pd API m_pd.h if it is found
+ifdef pdincludepath
+  mpdh := $(shell ls "$(pdincludepath)/m_pd.h")
+endif
+
+# when making target all, check if m_pd.h is found and print info about it
+ifeq ($(goals), all)
+  $(if $(mpdh), \
+    $(info ++++ info: using Pd API $(mpdh)), \
+    $(warning Where is Pd API m_pd.h? Do 'make help' for info.))
+endif
+
+# print target info
+$(info ++++ info: making target $(goals) $(if $(lib.name),in lib $(lib.name)))
+
+# when installing, print installpath info
+$(if $(filter install install-lib, $(goals)), $(info ++++ info: \
+  installpath is '$(installpath)'))
+
+
+#=== define executables ========================================================
+
+
+# By default we build class executables, and optionally a shared dynamic link
+# lib. When make-lib-executable=yes we build all classes into a single lib
+# executable, on the condition that variable lib.setup.sources is defined.
+
+ifeq ($(make-lib-executable),yes)
+  $(if $(lib.setup.sources), ,\
+    $(error Can not build library blob because lib.setup.sources is undefined))
+  executables := $(lib.name).$(extension)
+else
+  executables := $(classes.executables) $(shared.lib)
+endif
+
+
+################################################################################
+### rules: special targets #####################################################
+################################################################################
+
+
+# Disable built-in rules. If some target can't be built with the specified
+# rules, it should not be built at all.
+MAKEFLAGS += --no-builtin-rules
+
+.PRECIOUS:
+.SUFFIXES:
+.PHONY: all post build-lib \
+        $(classes) $(makefiledirs) $(makefiles) \
+        install install-executables install-datafiles install-datadirs \
+        force clean vars allvars depend help
+
+
+################################################################################
+### rules: build targets #######################################################
+################################################################################
+
+
+# Target all forces the build of targets [$(executables) post] in
+# deterministic order. Target $(executables) builds class executables plus 
+# optional shared lib or alternatively a single lib executable when 
+# make-lib-executable=true. Target post is optionally defined by
+# library makefile.
+
+all: post
+post: $(executables)
+
+all:
+	$(info ++++info: target all in lib $(lib.name) completed)
+
+# build all with -g option turned on for debug symbols
+alldebug: c.flags += -g
+alldebug: cxx.flags += -g
+alldebug: all
+
+
+#=== class executable ==========================================================
+
+
+# recipe for linking objects in class executable
+# argument $1 = compiler type (c or cxx)
+# argument $2 = class basename
+define link-class
+  $(compile-$1) \
+  $($1.ldflags) $($2.class.ldflags) \
+  -o $2.$(extension) \
+  $(addsuffix .o, $(basename $($2.class.sources))) \
+  $(addsuffix .o, $(basename $(common.sources))) \
+  $($1.ldlibs) $($2.class.ldlibs) $(shared.lib)
+endef
+
+# general rule for linking object files in class executable
+%.$(extension): $(shared.lib)
+	$(info ++++ info: linking objects in $@ for lib $(lib.name))
+	$(if $(filter %.cc %.cpp, $($*.class.sources)), \
+        $(call link-class,cxx,$*), \
+        $(call link-class,c,$*))
+
+
+#=== library blob ==============================================================
+
+
+# build all classes into single executable
+build-lib: $(lib.name).$(extension)
+	$(info ++++ info: library blob $(lib.name).$(extension) completed)
+
+# recipe for linking objects in lib executable
+# argument $1 = compiler type (c or cxx)
+define link-lib
+  $(compile-$1) \
+  $($1.ldflags) $(lib.ldflags) \
+  -o $(lib.name).$(extension) $(all.objects) \
+  $($1.ldlibs) $(lib.ldlibs)
+endef
+
+# rule for linking objects in lib executable
+# declared conditionally to avoid name clashes
+ifeq ($(make-lib-executable),yes)
+$(lib.name).$(extension): $(all.objects)
+	$(if $(filter %.cc %.cpp, $(all.sources)), \
+        $(call link-lib,cxx), \
+        $(call link-lib,c))
+endif
+
+
+#=== shared dynamic lib ========================================================
+
+
+# recipe for linking objects in shared executable
+# argument $1 = compiler type (c or cxx)
+define link-shared
+  $(compile-$1) \
+  $(shared.ldflags) \
+  -o lib$(lib.name).$(shared.extension) $(shared.objects) \
+  $($1.ldlibs) $(shared.ldlibs)
+endef
+
+# rule for linking objects in shared executable
+# build recipe is in macro 'link-shared'
+lib$(lib.name).$(shared.extension): $(shared.objects)
+	$(info ++++ info: linking objects in shared lib $@)
+	$(if $(filter %.cc %.cpp, $(shared.sources)), \
+        $(call link-shared,cxx), \
+        $(call link-shared,c))
+
+
+#=== object files ==============================================================
+
+
+# recipe to make .o file from source
+# argument $1 is compiler type (c or cxx)
+define make-object-file
+  $(info ++++ info: making $@ in lib $(lib.name))
+  $(compile-$1) \
+  $($1.flags) \
+  -o $@ -c $<
+endef
+
+# Three rules to create .o files. These are double colon 'terminal' rules,
+# meaning they are the last in a rules chain.
+
+%.o:: %.c
+	$(call make-object-file,c)
+
+%.o:: %.cc
+	$(call make-object-file,cxx)
+
+%.o:: %.cpp
+	$(call make-object-file,cxx)
+
+
+#=== explicit prerequisites for class executables ==============================
+
+
+# For class executables, prerequisite rules are declared in run time. Target
+# 'depend' prints these rules for debugging purposes.
+
+# declare explicit prerequisites rule like 'class: class.extension'
+# argument $v is class basename
+define declare-class-target
+$v: $v.$(extension)
+endef
+
+# declare explicit prerequisites rule like 'class.extension: object1.o object2.o'
+# argument $v is class basename
+define declare-class-executable-target
+$v.$(extension): $(addsuffix .o, $(basename $($v.class.sources))) \
+  $(addsuffix .o, $(basename $(common.sources)))
+endef
+
+# evaluate explicit prerequisite rules for all classes
+$(foreach v, $(classes), $(eval $(declare-class-target)))
+$(foreach v, $(classes), $(eval $(declare-class-executable-target)))
+
+
+#=== implicit prerequisites for class executables ==============================
+
+
+# Evaluating implicit prerequisites (header files) with help from the
+# preprocessor is 'expensive' so this is done conditionally and selectively.
+# Note that it is also possible to trigger a build via install targets, in
+# which case implicit prerequisites are not checked.
+
+# When the Pd include path contains spaces it will mess up the implicit
+# prerequisites rules. Also it is known that multiple arch flags are
+# incompatible with preprocessor option -MM on OSX <= 10.5. Dependency
+# tracking must be disabled in those cases.
+
+oldfat := $(and $(filter ppc i386, $(machine)), \
+          $(filter-out 0 1, $(words $(filter -arch, $(c.flags)))))
+
+disable-dependency-tracking := pdincludepathwithspaces oldfat
+
+ifndef disable-dependency-tracking
+  must-build-everything := $(filter all, $(goals))
+  must-build-class := $(filter $(classes), $(goals))
+  must-build-sources := $(foreach v, $(must-build-class), $($v.class.sources))
+endif
+
+# declare implicit prerequisites rule like 'object.o: header1.h header2.h ...'
+# argument $1 is input source file(s)
+define declare-object-target
+$(filter %.o: %.h, $(shell $(CPP) $(c.flags) -MM $1)) $(MAKEFILE_LIST)
+endef
+
+# evaluate implicit prerequisite rules when rebuilding everything
+ifdef must-build-everything
+  $(if $(wildcard $(all.objects)), \
+  $(info ++++ info: evaluating implicit prerequisites in lib $(lib.name).....) \
+  $(foreach v, $(all.sources), $(eval $(call declare-object-target, $v))))
+endif
+
+# evaluate implicit prerequisite rules when selectively building classes
+ifdef must-build-class
+  $(foreach v, $(must-build-sources), \
+  $(eval $(call declare-object-target, $v)))
+  $(foreach v, $(shared.sources), \
+  $(eval $(call declare-object-target, $v)))
+endif
+
+
+################################################################################
+### rules: preprocessor and assembly files #####################################
+################################################################################
+
+
+# Preprocessor and assembly output files for bug tracing etc. They are not part
+# of the build processes for executables. By default these files are created in
+# the current working directory. Dependency tracking is not performed, the build
+# is forced instead to make sure it's up to date.
+
+force:
+
+
+#=== preprocessor file =========================================================
+
+
+# make preprocessor output file with extension .pre
+# argument $1 = compiler type (c or cxx)
+define make-preprocessor-file
+  $(info ++++ info: making preprocessor output file $(notdir $*.pre) \
+  in current working directory)
+  $(compile-$1) -E $< $(c.flags) $($1.flags) -o $(notdir $*.pre)
+endef
+
+%.pre:: %.c force
+	$(call make-preprocessor-file,c)
+
+%.pre:: %.cc force
+	$(call make-preprocessor-file,cxx)
+
+%.pre:: %.cpp force 
+	$(call make-preprocessor-file,cxx)
+
+
+#=== assembly file =============================================================
+
+
+# make C / assembly interleaved output file with extension .lst
+# argument $1 = compiler type (c or cxx)
+define make-assembly-file
+  $(info ++++ info: making assembly output file $(notdir $*.lst) \
+  in current working directory)
+  $(compile-$1) \
+  -c -Wa,-a,-ad -fverbose-asm \
+  $($1.flags) \
+  $< > $(notdir $*.lst)
+endef
+
+%.lst:: %.c force
+	$(call make-assembly-file,c)
+
+%.lst:: %.cc force
+	$(call make-assembly-file,cxx)
+
+%.lst:: %.cpp force
+	$(call make-assembly-file,cxx)
+
+
+################################################################################
+### rules: installation targets ################################################
+################################################################################
+
+
+# Install targets depend on successful exit status of target all because nothing
+# must be installed in case of a build error.
+
+
+# -p = preserve time stamps
+# -m = set permission mode (as in chmod)
+# -d = create all components of specified directories
+INSTALL = install
+INSTALL_PROGRAM := $(INSTALL) -p -m 644
+INSTALL_DATA := $(INSTALL) -p -m 644
+INSTALL_DIR := $(INSTALL) -m 755 -d
+
+# strip spaces from file names
+executables := $(strip $(executables))
+datafiles := $(strip $(datafiles))
+datadirs := $(strip $(datadirs))
+
+# Do not make any install sub-target with empty variable definition because the
+# install program would exit with an error.
+install: $(if $(executables), install-executables)
+install: $(if $(datafiles), install-datafiles)
+install: $(if $(datadirs), install-datadirs)
+
+install-executables: all
+	$(INSTALL_DIR) -v "$(installpath)"
+	$(INSTALL_PROGRAM) $(executables) "$(installpath)"
+	$(info ++++ info: executables of lib $(lib.name) installed \
+        from $(CURDIR) to $(installpath))
+
+install-datafiles: all
+	$(INSTALL_DIR) -v "$(installpath)"
+	$(INSTALL_DATA) $(datafiles) "$(installpath)"
+	$(info ++++ info: data files of lib $(lib.name) installed \
+        from $(CURDIR) to $(installpath))
+
+install-datadirs: all
+	$(foreach v, $(datadirs), $(INSTALL_DIR) "$(installpath)/$v";)
+	$(foreach v, $(datadirs), \
+        $(INSTALL_DATA) $(wildcard $v/*) "$(installpath)/$v";)
+	$(info ++++ info: data directories of lib $(lib.name) installed \
+        from $(CURDIR) to $(installpath))
+
+
+################################################################################
+### rules: distribution targets ################################################
+################################################################################
+
+
+# TODO
+# These targets are implemented in Makefile Template, but I have to figure out
+# how to do it under the not-so-strict conditions of Makefile.pdlibbuilder.
+
+# make source package
+dist:
+	@echo "target dist not yet implemented"
+
+# make Debian source package
+dpkg-source:
+	@echo "target dpkg-source not yet implemented"
+
+$(ORIGDIR):
+
+$(DISTDIR):
+
+
+################################################################################
+### rules: clean targets #######################################################
+################################################################################
+
+
+# delete build products from build tree
+clean:
+	rm -f $(all.objects)
+	rm -f $(classes.executables) $(lib.name).$(extension) $(shared.lib)
+	rm -f *.pre *.lst
+
+# remove distribution directories and tarballs from build tree
+distclean: clean
+	@echo "target distclean not yet implemented"
+
+
+################################################################################
+### rules: submake targets #####################################################
+################################################################################
+
+
+# Iterate over sub-makefiles or makefiles in other directories.
+
+# When 'continue-make=yes' is set, sub-makes will report 'true' to the parent
+# process regardless of their real exit status. This prevents the parent make
+# from being aborted by a sub-make error. Useful when you want to quickly find
+# out which sub-makes from a large set will succeed.
+ifeq ($(continue-make),yes)
+  continue = || true
+endif
+
+# These targets will trigger sub-make processes for entries in 'makefiledirs'
+# and 'makefiles'.
+all alldebug install clean distclean dist dkpg-source: \
+        $(makefiledirs) $(makefiles)
+
+# this expands to identical rules for each entry in 'makefiledirs'
+$(makefiledirs):
+	$(MAKE) --directory=$@ $(MAKECMDGOALS) $(continue)
+
+# this expands to identical rules for each entry in 'makefiles'
+$(makefiles):
+	$(MAKE) --directory=$(dir $@) --makefile=$(notdir $@) $(MAKECMDGOALS) $(continue)
+
+
+################################################################################
+### rules: convenience targets #################################################
+################################################################################
+
+
+#=== show variables ============================================================
+
+
+# Several 'function' macro's cause errors when expanded within a rule or without
+# proper arguments. Variables which are set with the define directive are only
+# shown by name for that reason.
+functions = \
+add-class-source \
+declare-class-target \
+declare-class-executable-target \
+declare-object-target \
+link-class \
+link-lib \
+link-shared \
+make-object-file \
+make-preprocessor-file \
+make-assembly-file
+
+
+# show variables from makefiles
+vars:
+	$(info ++++ info: showing makefile variables:)
+	$(foreach v,\
+        $(sort $(filter-out $(functions) functions, $(.VARIABLES))),\
+        $(if $(filter file, $(origin $v)),\
+        $(info variable $v = $($v))))
+	$(foreach v, $(functions), $(info 'function' name: $v))
+	@echo
+
+# show all variables
+allvars:
+	$(info ++++ info: showing default, automatic and makefile variables:)
+	$(foreach v, \
+        $(sort $(filter-out $(functions) functions, $(.VARIABLES))), \
+        $(info variable ($(origin $v)) $v = $($v)))
+	$(foreach v, $(functions), $(info 'function' name: $v))
+	@echo
+
+
+#=== show dependencies =========================================================
+
+
+# show generated prerequisites rules
+depend:
+	$(info ++++ info: generated prerequisite rules)
+	$(foreach v, $(classes), $(info $(declare-class-target)))
+	$(foreach v, $(classes), $(info $(declare-class-executable-target)))
+	$(foreach v, $(all.sources), $(info $(call declare-object-target, $v)))
+	@echo
+
+
+#=== show help text ============================================================
+
+
+# brief info about targets and paths
+
+ifdef mpdh
+  mpdhinfo := $(mpdh)
+else
+  mpdhinfo := m_pd.h was not found. Is Pd(-extended) installed?
+endif
+
+help:
+	@echo
+	@echo "  Main targets:"
+	@echo "    all:     build executables (default target)"
+	@echo "    install: install all components of the library"
+	@echo "    vars:    print makefile variables for troubleshooting"
+	@echo "    allvars: print all variables for troubleshooting"
+	@echo "    help:    print this help text"
+	@echo
+	@echo "  Pd API m_pd.h:"
+	@echo "    $(mpdhinfo)"
+	@echo "  You may specify your preferred Pd include path as argument to"
+	@echo "  the make command, like 'pdincludepath=path/to/pd/src'."
+	@echo
+	@echo "  Path for installation of your libdir(s):"
+	@echo "    $(objectsdir)"
+	@echo "  Alternatively you may specify your path for installation as argument"
+	@echo "  to the make command, like 'objectsdir=path/to/pd-externals'."
+	@echo
+	@echo "  Default paths are listed in the doc sections in Makefile.pdlibbuilder."
+	@echo
+
+
+#=== dummy target ==============================================================
+
+
+coffee:
+	@echo "Makefile.pdlibbuilder: Can not make coffee. Sorry."
+
+
+################################################################################
+### end of rules sections ######################################################
+################################################################################
+
+
+# for syntax highlighting in vim and github
+# vim: set filetype=make:
+
diff --git a/punish/triggerize-plugin/README.md b/punish/triggerize-plugin/README.md
new file mode 100644
index 0000000..3f5f052
--- /dev/null
+++ b/punish/triggerize-plugin/README.md
@@ -0,0 +1,85 @@
+triggerize
+==========
+
+  - replace fan-outs with [t a a ...]
+  - when selecting a single line: insert [t a]
+  - when selecting a [trigger]: insert "a" at the beginning
+
+# Usage
+
+### removing fan-outs
+- Select objects with fan-outs
+- Press <kbd>Control</kbd>+<kbd>t</kbd>
+- the (msg) fan-outs will be replaced by (connected) [t a a] objects
+
+### removing all fan-outs
+- Select All objects (<kbd>Control</kbd>-<kbd>a</kbd>)
+- Press <kbd>Control</kbd>+<kbd>t</kbd>
+- all fan-outs will be replaced by (connected) [t a a] objects
+
+### adding new left-hand outlet to [trigger]
+- Select a [trigger] object
+- Press <kbd>Control</kbd>+<kbd>t</kbd>
+- a new (unconnected) left-most outlet of type "a" will be created.
+
+### inserting triggers
+- Select a single (msg) connection
+- Press <kbd>Control</kbd>+<kbd>t</kbd>
+- the connection will be replaced by a (connected) `[t a]` object
+
+### inserting nop~ for signals
+- Select a single signal connection
+- Press <kbd>Control</kbd>+<kbd>t</kbd>
+- the connection will be replaced by a (connected) `[pd nop~]` object
+
+You can also use the menu:
+- `Edit` -> `Triggerize`
+
+OSX users should use <kbd>Cmd</kbd> instead of <kbd>Control</kbd>
+
+# Installation
+
+## Building
+Build the external:
+
+    make
+
+If you have an unusual setup (and/or your Pd installation is at a place not
+found by the compiler), you can parameterize the build. Try this first:
+
+    make help
+
+
+## Installing
+Put both the externals (`triggerize.pd_linux` or similar) an dthe GUI plugin
+(`triggerize-plugin.tcl`) into a directory `triggerize-plugin`, and put that
+into a place where Pd can find it.
+
+     make install
+
+E.g.
+
+    $ ~/.local/lib/pd/extra/triggerize-plugin/
+    ~/.local/lib/pd/extra/triggerize-plugin/triggerize.pd_linux
+    ~/.local/lib/pd/extra/triggerize-plugin/triggerize-plugin.tcl
+
+# BUGS
+
+## none known
+TODO
+
+# AUTHORS
+
+IOhannes m zmölnig
+
+# LICENSE
+`triggerize` is released under the Gnu GPL version 2 (or later).
+See LICENSE.md for the full text of the GPLv2.
+
+## Special license grant to Miller Puckette
+I hereby grant Miller S. Puckette the exclusive right to include
+`triggerize` into Pure Data (Pd) under the BSD 3-clause license under
+which Pd is currently released.
+
+Once it has been included into Pd it is of course re-distributable under
+that license. Until then, the Gnu GPL v2 (or later) applies.
diff --git a/punish/triggerize-plugin/triggerize-help.pd b/punish/triggerize-plugin/triggerize-help.pd
new file mode 100644
index 0000000..2a7a5de
--- /dev/null
+++ b/punish/triggerize-plugin/triggerize-help.pd
@@ -0,0 +1,46 @@
+#N canvas 165 134 692 566 10;
+#X text 53 45 1st \, select a few objects;
+#X floatatom 45 189 5 0 0 0 - - -, f 5;
+#X obj 45 238 *;
+#X floatatom 45 260 5 0 0 0 - - -, f 5;
+#X floatatom 95 189 5 0 0 0 - - -, f 5;
+#X obj 95 238 *;
+#X floatatom 95 260 5 0 0 0 - - -, f 5;
+#X floatatom 391 411 5 0 0 0 - - -, f 5;
+#X floatatom 391 467 5 0 0 0 - - -, f 5;
+#X text 35 166 select numbox;
+#X text 369 372 select coord;
+#X floatatom 105 393 5 0 0 0 - - -, f 5;
+#X obj 105 412 t b f;
+#X obj 119 448 i;
+#X floatatom 119 470 5 0 0 0 - - -, f 5;
+#X text 90 369 select [trigger];
+#X obj 488 411 sig~ 3;
+#X obj 488 466 osc~;
+#X text 469 371 select coord;
+#X floatatom 249 210 5 0 0 0 - - -, f 5;
+#X obj 253 251 + 1;
+#X obj 249 229 t b f;
+#X floatatom 284 254 5 0 0 0 - - -, f 5;
+#X text 239 178 select [trigger];
+#X text 48 71 then press <Ctrl>+<t> (<Cmd>+<t> on OSX) to add [trigger]
+objects ad lib., f 75;
+#X text 33 336 expand [t] to the left::;
+#X text 37 137 getting rid of fan-out::;
+#X text 342 337 insert objects into coord::;
+#X connect 1 0 2 0;
+#X connect 1 0 2 1;
+#X connect 2 0 3 0;
+#X connect 4 0 5 1;
+#X connect 4 0 5 0;
+#X connect 5 0 6 0;
+#X connect 7 0 8 0;
+#X connect 11 0 12 0;
+#X connect 12 0 13 0;
+#X connect 12 1 13 1;
+#X connect 13 0 14 0;
+#X connect 16 0 17 0;
+#X connect 19 0 21 0;
+#X connect 21 0 20 0;
+#X connect 21 1 20 1;
+#X connect 21 1 22 0;
diff --git a/punish/triggerize-plugin/triggerize-plugin.tcl b/punish/triggerize-plugin/triggerize-plugin.tcl
new file mode 100644
index 0000000..a4b4f68
--- /dev/null
+++ b/punish/triggerize-plugin/triggerize-plugin.tcl
@@ -0,0 +1,52 @@
+# META helper plugin for triggerize-selection
+# META DESCRIPTION adds menu to tell the 'triggerize' library to doit
+# META AUTHOR IOhannes m zmölnig <zmoelnig at umlaeute.mur.at>
+# META VERSION 0.1
+
+package require pdwindow 0.1
+if [catch {
+    package require msgcat
+    ::msgcat::mcload po
+}] { puts "iem::punish::triggerize: i18n failed" }
+
+namespace eval ::iem::punish::triggerize:: {
+    variable label
+    proc focus {winid state} {
+        set menustate [expr $state?"normal":"disabled"]
+        .menubar.edit entryconfigure "$::iem::punish::triggerize::label" -state $menustate
+    }
+    proc register {} {
+        # create an entry for our "triggerize" in the "edit" menu
+        set ::iem::punish::triggerize::label [_ "Triggerize Selection"]
+        set accelerator $::pd_menus::accelerator
+        set mymenu .menubar.edit
+        if {$::windowingsystem eq "aqua"} {
+            set inserthere 8
+            set accelerator "$accelerator"
+        } else {
+            set inserthere 8
+            set accelerator "$accelerator"
+        }
+        set accelerator "$accelerator+T"
+
+        $mymenu insert $inserthere command \
+            -label $::iem::punish::triggerize::label \
+            -state disabled \
+            -accelerator "$accelerator" \
+            -command { menu_send $::focused_window triggerize }
+
+        bind all <$::modifier-Key-t> {menu_send %W triggerize}
+        bind PatchWindow <FocusIn> "+::iem::punish::triggerize::focus %W 1"
+        bind PdWindow    <FocusIn> "+::iem::punish::triggerize::focus %W 0"
+
+        # attempt to load the 'triggerize' library from iem::punish
+        # (that does all the work)
+        set lib [string map {" " "\\ "} [file join $::current_plugin_loadpath triggerize]]
+        pdsend "pd-_float_template declare -lib $lib"
+
+        pdtk_post "loaded iem::punish::triggerize-plugin\n"
+    }
+}
+
+
+::iem::punish::triggerize::register
diff --git a/punish/triggerize-plugin/triggerize.c b/punish/triggerize-plugin/triggerize.c
new file mode 100644
index 0000000..b20ca36
--- /dev/null
+++ b/punish/triggerize-plugin/triggerize.c
@@ -0,0 +1,369 @@
+/******************************************************
+ *
+ * triggerize - implementation file
+ *
+ * copyleft (c) IOhannes m zmölnig
+ *
+ *   2016:forum::für::umläute:2016
+ *
+ *   institute of electronic music and acoustics (iem)
+ *
+ ******************************************************
+ *
+ * license: GNU General Public License v.2 (or later)
+ *
+ ******************************************************/
+
+#include "m_pd.h"
+
+#include "g_canvas.h"
+#include "m_imp.h"
+
+#define MARK() post("%s:%d\t%s", __FILE__, __LINE__, __FUNCTION__)
+
+/* ------------ utilities ---------- */
+static t_gobj*o2g(t_object*obj) {
+  return &(obj->te_g);
+}
+static t_object*g2o(t_gobj*gobj) {
+  return pd_checkobject(&gobj->g_pd);
+}
+t_gobj*glist_getlast(t_glist*cnv) {
+  t_gobj*result=NULL;
+  for(result=cnv->gl_list; result->g_next;) result=result->g_next;
+  return result;
+}
+static void dereconnect(t_glist*cnv, t_object*org, t_object*replace) {
+  t_gobj*gobj;
+  for(gobj=cnv->gl_list; gobj; gobj=gobj->g_next) {
+    t_object*obj=g2o(gobj);
+    int obj_nout=0;
+    int nout;
+    if(!obj)continue;
+    obj_nout=obj_noutlets(obj);
+    for(nout=0; nout<obj_nout; nout++) {
+      t_outlet*out=0;
+      t_outconnect*conn=obj_starttraverseoutlet(obj, &out, nout);
+      while(conn) {
+        int which;
+        t_object*dest=0;
+        t_inlet *in =0;
+        conn=obj_nexttraverseoutlet(conn, &dest, &in, &which);
+        if(dest!=org)
+          continue;
+        obj_disconnect(obj, nout, dest, which);
+        obj_connect(obj, nout, replace, which);
+      }
+    }
+  }
+}
+static t_object*triggerize_createobj(t_glist*x, t_binbuf*b) {
+  t_pd *boundx = s__X.s_thing, *boundn = s__N.s_thing;
+  s__X.s_thing = &x->gl_pd;
+  s__N.s_thing = &pd_canvasmaker;
+
+  binbuf_eval(b, 0, 0, 0);
+
+  s__X.s_thing = boundx;
+  s__N.s_thing = boundn;
+  return g2o(glist_getlast(x));
+}
+static void stack_conn(t_object*new, int*newoutlet, t_object*org, int orgoutlet, t_outconnect*conn){
+  t_object*dest=0;
+  t_inlet *in =0;
+  int which;
+
+  conn=obj_nexttraverseoutlet(conn, &dest, &in, &which);
+  if(conn)
+    stack_conn(new, newoutlet, org, orgoutlet, conn);
+  obj_disconnect(org, orgoutlet, dest, which);
+  obj_connect(new, *newoutlet, dest, which);
+  (*newoutlet)++;
+}
+static int has_fanout(t_object*obj) {
+  int obj_nout=obj_noutlets(obj);
+  int nout;
+  /* check if we actually do have a fan out */
+  for(nout=0; nout<obj_nout; nout++) {
+    t_outlet*out=0;
+    t_outconnect*conn=obj_starttraverseoutlet(obj, &out, nout);
+    int count=0;
+    if(obj_issignaloutlet(obj, nout))
+      continue;
+    while(conn) {
+      int which;
+      t_object*dest=0;
+      t_inlet *in =0;
+      if(count)return 1;
+      conn=obj_nexttraverseoutlet(conn, &dest, &in, &which);
+      count++;
+    }
+  }
+  return 0;
+}
+/* ------------------------- triggerize ---------------------------- */
+static int triggerize_fanout_inplace(t_glist*x, t_object*obj) {
+  int posX=obj->te_xpix;
+  int posY=obj->te_ypix;
+  t_atom*argv=binbuf_getvec(obj->te_binbuf);
+  int    argc=binbuf_getnatom(obj->te_binbuf);
+  int obj_nout=obj_noutlets(obj);
+  int nout, newout;
+  t_binbuf*b=0;
+  t_object*stub=0;
+
+  /* avoid fanouts in [t] objects by adding additional outlets */
+
+  /* check if we actually do have a fan out */
+  if(!has_fanout(obj))return 0;
+
+  /* create a new trigger object, that hsa outlets for the fans */
+  b=binbuf_new();
+  binbuf_addv(b, "ssii", gensym("#X"), gensym("obj"), posX, posY);
+  binbuf_add(b, 1, argv);
+  argc--; argv++;
+  for(nout=0; nout<obj_nout; nout++) {
+    t_outlet*out=0;
+    t_outconnect*conn=obj_starttraverseoutlet(obj, &out, nout);
+    while(conn) {
+      int which;
+      t_object*dest=0;
+      t_inlet *in =0;
+      conn=obj_nexttraverseoutlet(conn, &dest, &in, &which);
+      binbuf_add(b, 1, argv);
+    }
+    argv++; argc--;
+  }
+  binbuf_addsemi(b);
+  stub=triggerize_createobj(x, b);
+  binbuf_free(b);
+
+  /* connect */
+  newout=0;
+  dereconnect(x, obj, stub);
+  for(nout=0; nout<obj_nout; nout++) {
+    t_outlet*out=0;
+    t_outconnect*conn=obj_starttraverseoutlet(obj, &out, nout);
+    stack_conn(stub, &newout, obj, nout, conn);
+  }
+
+  /* free old object */
+  glist_delete(x, o2g(obj));
+  return 1;
+}
+static int triggerize_fanout(t_glist*x, t_object*obj, int fanout_trigger_inplace) {
+  const t_symbol*s_trigger=gensym("trigger");
+  int obj_nout=obj_noutlets(obj);
+  int nout;
+  int posX=obj->te_xpix-10;
+  int posY=obj->te_ypix+20;
+  t_binbuf*b=binbuf_new();
+  int didit=0;
+  if(fanout_trigger_inplace && (s_trigger == obj->te_g.g_pd->c_name)) {
+    return triggerize_fanout_inplace(x, obj);
+  }
+
+  for(nout=0; nout<obj_nout; nout++) {
+    t_outlet*out=0;
+    t_outconnect*conn=obj_starttraverseoutlet(obj, &out, nout);
+    int count=0;
+    if(obj_issignaloutlet(obj, nout))
+      continue;
+    while(conn) {
+      int which;
+      t_object*dest=0;
+      t_inlet *in =0;
+      conn=obj_nexttraverseoutlet(conn, &dest, &in, &which);
+      count++;
+    }
+    if(count>1) {
+      /* fan out */
+      int i;
+      t_object*stub=0;
+      binbuf_clear(b);
+      binbuf_addv(b, "ssiis", gensym("#X"), gensym("obj"), posX, posY, gensym("t"));
+      for(i=0; i<count; i++) {
+        binbuf_addv(b, "s", gensym("a"));
+      }
+      binbuf_addsemi(b);
+      stub=triggerize_createobj(x, b);
+      conn=obj_starttraverseoutlet(obj, &out, nout);
+      i=0;
+      while(conn) {
+        int which;
+        t_object*dest=0;
+        t_inlet *in =0;
+        conn=obj_nexttraverseoutlet(conn, &dest, &in, &which);
+        obj_disconnect(obj, nout, dest, which);
+        obj_connect(stub, count-i-1, dest, which);
+        i++;
+      }
+      obj_connect(obj, nout, stub, 0);
+      glist_select(x, o2g(stub));
+    }
+    didit++;
+  }
+  binbuf_free(b);
+  return didit;
+}
+static int triggerize_fanouts(t_glist*cnv, int fanout_trigger_inplace) {
+  t_gobj*gobj = NULL;
+  int count=0;
+  for(gobj=cnv->gl_list; gobj; gobj=gobj->g_next) {
+    t_object*obj=g2o(gobj);
+    if(obj && glist_isselected(cnv, gobj) && triggerize_fanout(cnv, obj, fanout_trigger_inplace))
+      count++;
+  }
+  return count;
+}
+
+static int triggerize_line(t_glist*x) {
+  t_editor*ed=x->gl_editor;
+  int src_obj, src_out, dst_obj ,dst_in;
+  t_gobj *src = 0, *dst = 0;
+  t_binbuf*b=0;
+  int posx=100, posy=100;
+  t_object*stub=0;
+
+  if(!ed->e_selectedline)
+    return 0;
+  src_obj=ed->e_selectline_index1;
+  src_out=ed->e_selectline_outno;
+  dst_obj=ed->e_selectline_index2;
+  dst_in =ed->e_selectline_inno;
+  for (src = x->gl_list; src_obj; src = src->g_next, src_obj--)
+    if (!src->g_next) goto bad;
+  for (dst = x->gl_list; dst_obj; dst = dst->g_next, dst_obj--)
+    if (!dst->g_next) goto bad;
+  src_obj=ed->e_selectline_index1;
+  dst_obj=ed->e_selectline_index2;
+
+  if(1) {
+    t_object*obj1=g2o(src);
+    t_object*obj2=g2o(dst);
+    if(obj1 && obj2) {
+      posx=(obj1->te_xpix+obj2->te_xpix)>>1;
+      posy=(obj1->te_ypix+obj2->te_ypix)>>1;
+    }
+  }
+
+  b=binbuf_new();
+  if(obj_issignaloutlet(g2o(src), src_out)) {
+    //binbuf_addv(b,"ssii", gensym("#X"), gensym("obj"), posx, posy);
+    //binbuf_addv(b,"s", gensym("+~"));235 124 189 224
+    binbuf_addv(b, "ssiiiisi;", gensym("#N"), gensym("canvas"), 200, 100, 190, 200, gensym("nop~"), 0);
+    binbuf_addv(b, "ssiis;", gensym("#X"), gensym("obj"), 50, 70, gensym("inlet~"));
+    binbuf_addv(b, "ssiis;", gensym("#X"), gensym("obj"), 50,140, gensym("outlet~"));
+    binbuf_addv(b, "ssiiii;", gensym("#X"), gensym("connect"), 0,0,1,0);
+    binbuf_addv(b, "ssiiss", gensym("#X"), gensym("restore"), posx, posy, gensym("pd"), gensym("nop~"));
+  } else {
+    binbuf_addv(b,"ssii", gensym("#X"), gensym("obj"), posx, posy);
+    binbuf_addv(b,"ss", gensym("t"), gensym("a"));
+  }
+  binbuf_addsemi(b);
+  stub=triggerize_createobj(x, b);
+  binbuf_free(b);b=0;
+
+  obj_disconnect(g2o(src), src_out, g2o(dst), dst_in);
+  obj_connect(g2o(src), src_out, stub, 0);
+  obj_connect(stub, 0, g2o(dst), dst_in);
+  glist_select(x, o2g(stub));
+
+  return 1;
+ bad:
+  return 0;
+}
+static int triggerize_trigger(t_glist*cnv, t_object*obj) {
+  /* insert a first "a" outlet into the trigger */
+  t_binbuf*b=binbuf_new();
+  int argc=binbuf_getnatom(obj->te_binbuf);
+  t_atom*argv=binbuf_getvec(obj->te_binbuf);
+  t_object*stub=0;
+  int obj_nout=obj_noutlets(obj);
+  int nout;
+
+  binbuf_addv(b, "ssii", gensym("#X"), gensym("obj"), obj->te_xpix, obj->te_ypix);
+  binbuf_add(b, 1, argv);
+  binbuf_addv(b, "s", gensym("a"));
+  binbuf_add(b, argc-1, argv+1);
+  stub=triggerize_createobj(cnv, b);
+  for(nout=0; nout<obj_nout; nout++) {
+    t_outlet*out=0;
+    t_outconnect*conn=obj_starttraverseoutlet(obj, &out, nout);
+    while(conn) {
+      int which;
+      t_object*dest=0;
+      t_inlet *in =0;
+      conn=obj_nexttraverseoutlet(conn, &dest, &in, &which);
+      obj_disconnect(obj, nout, dest, which);
+      obj_connect(stub, nout+1, dest, which);
+    }
+  }
+  binbuf_free(b);
+  dereconnect(cnv, obj, stub);
+  glist_delete(cnv,o2g(obj));
+  //glist_select(cnv, o2g(stub));
+  return 1;
+}
+static int triggerize_triggers(t_glist*cnv, int skip_if_nontriggers) {
+  t_gobj*gobj = NULL;
+  const t_symbol*s_trigger=gensym("trigger");
+  int count=0;
+
+  if(skip_if_nontriggers) {
+    /* if this is enabled, we refuse to do anything if the selection is not
+     * exclusively [trigger] objects
+     */
+    for(gobj=cnv->gl_list; gobj; gobj=gobj->g_next) {
+      t_object*obj=g2o(gobj);
+      if(obj && glist_isselected(cnv, gobj) && (s_trigger != obj->te_g.g_pd->c_name)) {
+        return 0;
+      }
+    }
+  }
+  for(gobj=cnv->gl_list; gobj; gobj=gobj->g_next) {
+    t_object*obj=g2o(gobj);
+    if(obj && glist_isselected(cnv, gobj)) {
+      const t_symbol*c_name=obj->te_g.g_pd->c_name;
+      if((s_trigger == c_name)&&triggerize_trigger(cnv, obj))
+        count++;
+    }
+  }
+  return count;
+}
+
+static void canvas_do_triggerize(t_glist*cnv) {
+  /*
+   * selected msg-connection: insert [t a]
+   * selected sig-connection: insert [pd nop~]
+   * selected [trigger]: if fan-outs, remove them
+   * selected [trigger]: if no fan-outs, add left-most "a" outlet
+   * selected objects: remove fan-outs
+   */
+  if(triggerize_line(cnv))return;
+  if(triggerize_fanouts(cnv, 1))return;
+  if(triggerize_triggers(cnv, 1))return;
+}
+static void canvas_triggerize(t_glist*cnv) {
+  int dspstate;
+  if(NULL == cnv)return;
+
+  /* suspend system */
+  dspstate = canvas_suspend_dsp();
+
+  canvas_do_triggerize(cnv);
+
+  /* restore state */
+  canvas_redraw(cnv);
+  glist_redraw(cnv);
+  canvas_resume_dsp(dspstate);
+}
+
+void triggerize_setup(void)
+{
+  if(NULL==canvas_class)return;
+  post("triggerize - insert [trigger] ad lib.");
+
+  if(NULL==zgetfn(&canvas_class, gensym("triggerize")))
+    class_addmethod(canvas_class, (t_method)canvas_triggerize, gensym("triggerize"), 0);
+}

-- 
pd-iemutils packaging



More information about the pkg-multimedia-commits mailing list