[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