From 71b83fc040b848c98c5065d95ecbc72b0b4f8943 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 17 Jan 2013 22:54:00 +0000 Subject: merging maxlib v1.5.5 from branches/pd-extended/0.43 svn path=/trunk/externals/maxlib/; revision=16897 --- HISTORY | 100 -- Makefile | 122 +- allow.c | 224 ++-- arbran.c | 378 +++--- arraycopy.c | 50 +- automata.txt | 178 --- average.c | 404 +++--- beat.c | 806 ++++++------ beta.c | 214 +-- bilex.c | 174 +-- borax.c | 476 +++---- cauchy.c | 170 +-- chord.c | 3644 +++++++++++++++++++++++++-------------------------- delta.c | 278 ++-- deny.c | 228 ++-- dist.c | 558 ++++---- divide.c | 220 ++-- divmod.c | 200 +-- edge.c | 164 +-- examples/score.txt | 25 + examplescore.txt | 25 - expo.c | 172 +-- fifo.c | 192 +-- gauss.c | 168 +-- gestalt.c | 246 ++-- history.c | 542 ++++---- ignore.c | 238 ++-- iso.c | 438 +++---- lifo.c | 202 +-- limit.c | 250 ++-- linear.c | 162 +-- listfifo.c | 218 +-- listfunnel.c | 184 +-- manual/HISTORY.txt | 100 ++ manual/automata.txt | 178 +++ match.c | 548 ++++---- maxlib-meta.pd | 2 +- maxlib.c | 384 +++--- minus.c | 222 ++-- mlife.c | 1030 +++++++-------- multi.c | 220 ++-- nchange.c | 410 +++--- netclient.c | 764 +++++------ netdist.c | 626 ++++----- netrec.c | 894 ++++++------- netserver.c | 1340 +++++++++---------- nroute.c | 358 ++--- pitch.c | 228 ++-- plus.c | 220 ++-- poisson.c | 182 +-- pong.c | 664 +++++----- pulse.c | 602 ++++----- remote.c | 216 +-- rewrap.c | 310 ++--- rhythm.c | 686 +++++----- scale.c | 276 ++-- score-help.pd | 2 +- score.c | 618 ++++----- speedlim.c | 470 +++---- split.c | 190 +-- step.c | 358 ++--- subst.c | 848 ++++++------ sync.c | 588 ++++----- temperature.c | 240 ++-- tilt.c | 378 +++--- timebang.c | 348 ++--- triang.c | 160 +-- unroute.c | 350 ++--- urn.c | 304 ++--- velocity.c | 224 ++-- weibull.c | 182 +-- wrap.c | 284 ++-- 72 files changed, 13866 insertions(+), 13788 deletions(-) delete mode 100644 HISTORY delete mode 100644 automata.txt create mode 100644 examples/score.txt delete mode 100644 examplescore.txt create mode 100644 manual/HISTORY.txt create mode 100644 manual/automata.txt diff --git a/HISTORY b/HISTORY deleted file mode 100644 index c90963f..0000000 --- a/HISTORY +++ /dev/null @@ -1,100 +0,0 @@ -version history of maxlib library for pure-data - -v 1.5.2 (17. december 2003): -- modified netclient for not to drop received data: use of syspollfn - instead of clock to poll for incoming data, circular recv buffer - -v 1.5 (18. october 2003): -- added some usefull features to arraycopy (i.e. copying just parts of - an array and copying to specified position in destination array) -- new object: nchange -- IRIX 6.5 port (for GCC 3.3) -- OS X binary (Jaguar 10.2.6) - -v 1.4 (22. may 2003): -- updated sources to compile with Pd0.37-test4 -- new object: arraycopy - -v 1.3 (12. april 2003): -- new objects: sync listfifo -- all setup routines renamed to maxlib__setup() to avoid name - clashes, old names still work via class_addcreator() -- some improvements for the help files - -v 1.2 (30. january 2003): -- new objects: unroute urn split wrap rewrap timebang -- another fix for the makefile -- fixed a bug in netserver (sockets remained open when netserver closed) -- added a 'prepend' option (with additional creation argument) to remote, - patch was supplied by Maurizio Umberto Puxeddu - -v 1.1b2 (23. oktober 2002): -- corrected two small bugs in the makefile (linux only!), thanks to - Hans-Christoph Steiner - -v 1.1b (12. september 2002): -- new object: limit -- match and speedlim have been replaced with the objects from cyclone library -- deleted the (unwanted) debugging printout from nroute - -v 1.1 (26. august 2002): -- new objects: nroute, pong, edge -- arbran 0.1b now allows to (re-)set the arrays dynamically -- match 0.3 now matches any type of data (floats, lists, symbols, anything) -- scale 0.2 allows to dynamically change the creation arguments and to choose - between linear (default) and exponential scale -- MSVC++ workspace contains configuration for Intel Compiler with Pentium 4 - optimizations ("maxlib - Win32 Intel") -- makefile and binary release for Mac OS X (10.1.5) -- BUG FIX: corrected path to helpfiles in rand objects -- BUG FIX: corrected makefile to work under Linux again - -v 1.0 (9th august 2002): -- new objects: netserver, netclient, arbran, beta, bilex, cauchy, expo, - gauss, linear, poisson, triang, weibull -- the help patches now live in doc/5.reference/maxlib, thanks to - Frank Barknecht for suggesting that and for modifying the sources - -v 0.9 (25th july 2002): -- new objects: tilt gestalt temperature - -v 0.8b (21st july 2002): -- now compiles on Linux, thanks to Martin Pi -- new objects: listfunnel - -v 0.8 (4th july 2002): -- new objects: history netrec scale delta velocity -- some small changes to speedlim - -v 0.7 (24th june 2002): -- fixed a bug in average, thanks to João Miguel Pais -- new chord algorhythm: supports up to 67 chord types now - -v 0.6 (7th june 2002): -- added objects: beat rhythm - -v 0.5 (28th mai 2002): -- added objects: netdist mlife subst -- netdist uses the pthreads-win32 library for POSIX multithreading - under NT, thus at least pd0.35-test17 is needed under NT -- made a MSVC++ 6.0 project file - -v 0.4 (16th mai 2002): -- match now also takes lists of floats -- added objects: dist remote step - -v 0.3b (14th mai 2002): -- fixed a zero-division bug in pulse, thanks to Frank Barknecht - -v 0.3 (13th mai 2002): -- added objects: divmod, fifo, iso, lifo, pulse -- made divide, minus, multi & plus 'multi-inlet-ready' - -v 0.2 (7th mai 2002): -- added objects: average, chord, score - -v 0.1b (24th apr. 2002): -- added objects: divide, minus, multi, plus - -v 0.1a (15th apr. 2002, first public release): -- included objects: borax, ignore, match, pitch, speedlim diff --git a/Makefile b/Makefile index 254ceff..7f8a16e 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -## Pd library template version 1.0.11 +## Pd library template version 1.0.14 # For instructions on how to use this template, see: # http://puredata.info/docs/developer/MakefileTemplate LIBRARY_NAME = maxlib @@ -12,16 +12,19 @@ SOURCES = allow.c arbran.c arraycopy.c average.c beat.c beta.c bilex.c borax.c c PDOBJECTS = # example patches and related files, in the 'examples' subfolder -EXAMPLES = +EXAMPLES = score.txt # manuals and related files, in the 'manual' subfolder -MANUAL = +MANUAL = automata.txt HISTORY.txt # if you want to include any other files in the source and binary tarballs, # list them here. This can be anything from header files, test patches, # documentation, etc. README.txt and LICENSE.txt are required and therefore # automatically included -EXTRA_DIST = HISTORY automata.txt examplescore.txt maxlib-help.pd maxlib.c maxlib.dsp maxlib.dsw +EXTRA_DIST = maxlib-help.pd maxlib.c maxlib.dsp maxlib.dsw + +# unit tests and related files here, in the 'unittests' subfolder +UNITTESTS = @@ -105,13 +108,19 @@ ifeq ($(UNAME),Darwin) ifeq ($(shell uname -r | sed 's|\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*|\1|'), 8) FAT_FLAGS = -arch ppc -arch i386 -mmacosx-version-min=10.4 else - FAT_FLAGS = -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=10.4 SOURCES += $(SOURCES_iphoneos) +# Starting with Xcode 4.0, the PowerPC compiler is not installed by default + ifeq ($(wildcard /usr/llvm-gcc-4.2/libexec/gcc/powerpc*), ) + FAT_FLAGS = -arch i386 -arch x86_64 -mmacosx-version-min=10.5 + else + FAT_FLAGS = -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=10.4 + endif endif ALL_CFLAGS += $(FAT_FLAGS) -fPIC -I/sw/include # if the 'pd' binary exists, check the linking against it to aid with stripping BUNDLE_LOADER = $(shell test ! -e $(PD_PATH)/bin/pd || echo -bundle_loader $(PD_PATH)/bin/pd) - ALL_LDFLAGS += $(FAT_FLAGS) -bundle $(BUNDLE_LOADER) -undefined dynamic_lookup -L/sw/lib + ALL_LDFLAGS += $(FAT_FLAGS) -headerpad_max_install_names -bundle $(BUNDLE_LOADER) \ + -undefined dynamic_lookup -L/sw/lib SHARED_LDFLAGS += $(FAT_FLAGS) -dynamiclib -undefined dynamic_lookup \ -install_name @loader_path/$(SHARED_LIB) -compatibility_version 1 -current_version 1.0 ALL_LIBS += -lc $(LIBS_macosx) @@ -126,35 +135,61 @@ endif ifeq ($(UNAME),ANDROID) CPU := arm SOURCES += $(SOURCES_android) - EXTENSION = pd_linux + EXTENSION = so SHARED_EXTENSION = so OS = android PD_PATH = /usr NDK_BASE := /usr/local/android-ndk - NDK_PLATFORM_VERSION := 5 - NDK_SYSROOT=$(NDK_BASE)/platforms/android-$(NDK_PLATFORM_VERSION)/arch-arm + NDK_PLATFORM_LEVEL ?= 5 + NDK_ABI=arm + NDK_SYSROOT=$(NDK_BASE)/platforms/android-$(NDK_PLATFORM_LEVEL)/arch-$(NDK_ABI) NDK_UNAME := $(shell uname -s | tr '[A-Z]' '[a-z]') - NDK_TOOLCHAIN_BASE=$(NDK_BASE)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/$(NDK_UNAME)-x86 - CC := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-gcc --sysroot=$(NDK_SYSROOT) + NDK_COMPILER_VERSION=4.6 + NDK_TOOLCHAIN=$(wildcard \ + $(NDK_BASE)/toolchains/$(NDK_ABI)*-$(NDK_COMPILER_VERSION)/prebuilt/$(NDK_UNAME)-x86) + CC := $(wildcard $(NDK_TOOLCHAIN)/bin/*-linux-android*-gcc) --sysroot=$(NDK_SYSROOT) OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer CFLAGS += LDFLAGS += -rdynamic -shared SHARED_LDFLAGS += -Wl,-soname,$(SHARED_LIB) -shared LIBS += -lc $(LIBS_android) - STRIP := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-strip \ + STRIP := $(wildcard $(NDK_TOOLCHAIN)/bin/$(NDK_ABI)-linux-android*-strip) \ --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m) endif ifeq ($(UNAME),Linux) CPU := $(shell uname -m) - SOURCES += $(SOURCES_linux) EXTENSION = pd_linux + ifeq ($(findstring arm,$(CPU)),arm) + EXTENSION = l_arm + endif + ifeq ($(CPU),i386) + EXTENSION = l_i386 + endif + ifeq ($(CPU),i486) + EXTENSION = l_i386 + endif + ifeq ($(CPU),i586) + EXTENSION = l_i386 + endif + ifeq ($(CPU),i686) + EXTENSION = l_i386 + endif + ifeq ($(CPU),amd64) + # amd64 and ia64 aren't the same thing, but that's how its done in pd... + EXTENSION = l_ia64 + endif + ifeq ($(CPU),x86_64) + # x86_64 and ia64 aren't the same thing, but that's how its done in pd... + EXTENSION = l_ia64 + endif + SOURCES += $(SOURCES_linux) SHARED_EXTENSION = so OS = linux PD_PATH = /usr OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -fPIC - ALL_LDFLAGS += -rdynamic -shared -fPIC + ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags SHARED_LDFLAGS += -Wl,-soname,$(SHARED_LIB) -shared ALL_LIBS += -lc $(LIBS_linux) STRIP = strip --strip-unneeded -R .note -R .comment @@ -170,7 +205,7 @@ ifeq ($(UNAME),GNU) PD_PATH = /usr OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -fPIC - ALL_LDFLAGS += -rdynamic -shared -fPIC + ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB) ALL_LIBS += -lc $(LIBS_linux) STRIP = strip --strip-unneeded -R .note -R .comment @@ -186,7 +221,7 @@ ifeq ($(UNAME),GNU/kFreeBSD) PD_PATH = /usr OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -fPIC - ALL_LDFLAGS += -rdynamic -shared -fPIC + ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB) ALL_LIBS += -lc $(LIBS_linux) STRIP = strip --strip-unneeded -R .note -R .comment @@ -218,9 +253,10 @@ ifeq (MINGW,$(findstring MINGW,$(UNAME))) CC=gcc OPT_CFLAGS = -O3 -funroll-loops -fomit-frame-pointer ALL_CFLAGS += -mms-bitfields - ALL_LDFLAGS += -s -shared -Wl,--enable-auto-import -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" -L"$(PD_PATH)/obj" + ALL_LDFLAGS += -s -shared -Wl,--enable-auto-import SHARED_LDFLAGS += -shared - ALL_LIBS += -lpd -lwsock32 -lkernel32 -luser32 -lgdi32 $(LIBS_windows) + ALL_LIBS += -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" -L"$(PD_PATH)/obj" \ + -lpd -lwsock32 -lkernel32 -luser32 -lgdi32 -liberty $(LIBS_windows) STRIP = strip --strip-unneeded -R .note -R .comment DISTBINDIR=$(DISTDIR)-$(OS) endif @@ -232,12 +268,12 @@ ALL_CFLAGS := $(ALL_CFLAGS) $(CFLAGS) $(OPT_CFLAGS) ALL_LDFLAGS := $(LDFLAGS) $(ALL_LDFLAGS) ALL_LIBS := $(LIBS) $(ALL_LIBS) -SHARED_SOURCE ?= $(shell test ! -e lib$(LIBRARY_NAME).c || \ - echo lib$(LIBRARY_NAME).c ) +SHARED_SOURCE ?= $(wildcard lib$(LIBRARY_NAME).c) SHARED_HEADER ?= $(shell test ! -e $(LIBRARY_NAME).h || echo $(LIBRARY_NAME).h) -SHARED_LIB = $(SHARED_SOURCE:.c=.$(SHARED_EXTENSION)) +SHARED_LIB ?= $(SHARED_SOURCE:.c=.$(SHARED_EXTENSION)) +SHARED_TCL_LIB = $(wildcard lib$(LIBRARY_NAME).tcl) -.PHONY = install libdir_install single_install install-doc install-examples install-manual clean distclean dist etags $(LIBRARY_NAME) +.PHONY = install libdir_install single_install install-doc install-examples install-manual install-unittests clean distclean dist etags $(LIBRARY_NAME) all: $(SOURCES:.c=.$(EXTENSION)) $(SHARED_LIB) @@ -249,18 +285,19 @@ all: $(SOURCES:.c=.$(EXTENSION)) $(SHARED_LIB) chmod a-x "$*.$(EXTENSION)" # this links everything into a single binary file -$(LIBRARY_NAME): $(SOURCES:.c=.o) $(LIBRARY_NAME).o - $(CC) $(ALL_LDFLAGS) -o $(LIBRARY_NAME).$(EXTENSION) $(SOURCES:.c=.o) $(LIBRARY_NAME).o $(ALL_LIBS) +$(LIBRARY_NAME): $(SOURCES:.c=.o) $(LIBRARY_NAME).o lib$(LIBRARY_NAME).o + $(CC) $(ALL_LDFLAGS) -o $(LIBRARY_NAME).$(EXTENSION) $(SOURCES:.c=.o) \ + $(LIBRARY_NAME).o lib$(LIBRARY_NAME).o $(ALL_LIBS) chmod a-x $(LIBRARY_NAME).$(EXTENSION) $(SHARED_LIB): $(SHARED_SOURCE:.c=.o) - $(CC) $(SHARED_LDFLAGS) -o $(SHARED_LIB) $(SHARED_SOURCE:.c=.o) $(LIBS) + $(CC) $(SHARED_LDFLAGS) -o $(SHARED_LIB) $(SHARED_SOURCE:.c=.o) $(ALL_LIBS) install: libdir_install # The meta and help files are explicitly installed to make sure they are # actually there. Those files are not optional, then need to be there. -libdir_install: $(SOURCES:.c=.$(EXTENSION)) $(SHARED_LIB) install-doc install-examples install-manual +libdir_install: $(SOURCES:.c=.$(EXTENSION)) $(SHARED_LIB) install-doc install-examples install-manual install-unittests $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) @@ -276,9 +313,12 @@ libdir_install: $(SOURCES:.c=.$(EXTENSION)) $(SHARED_LIB) install-doc install-ex test -z "$(strip $(PDOBJECTS))" || \ $(INSTALL_DATA) $(PDOBJECTS) \ $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) + test -z "$(strip $(SHARED_TCL_LIB))" || \ + $(INSTALL_DATA) $(SHARED_TCL_LIB) \ + $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) # install library linked as single binary -single_install: $(LIBRARY_NAME) install-doc install-examples install-manual +single_install: $(LIBRARY_NAME) install-doc install-examples install-manual install-unittests $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(INSTALL_PROGRAM) $(LIBRARY_NAME).$(EXTENSION) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) $(STRIP) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/$(LIBRARY_NAME).$(EXTENSION) @@ -305,6 +345,12 @@ install-manual: $(INSTALL_DATA) manual/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual; \ done +install-unittests: + test -z "$(strip $(UNITTESTS))" || \ + $(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/unittests && \ + for file in $(UNITTESTS); do \ + $(INSTALL_DATA) unittests/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/unittests; \ + done clean: -rm -f -- $(SOURCES:.c=.o) $(SOURCES_LIB:.c=.o) $(SHARED_SOURCE:.c=.o) @@ -348,10 +394,14 @@ dist: $(DISTDIR) $(INSTALL_DATA) $(ALLSOURCES) $(DISTDIR) test -z "$(strip $(wildcard $(ALLSOURCES:.c=.tcl)))" || \ $(INSTALL_DATA) $(wildcard $(ALLSOURCES:.c=.tcl)) $(DISTDIR) + test -z "$(strip $(wildcard $(LIBRARY_NAME).c))" || \ + $(INSTALL_DATA) $(LIBRARY_NAME).c $(DISTDIR) test -z "$(strip $(SHARED_HEADER))" || \ $(INSTALL_DATA) $(SHARED_HEADER) $(DISTDIR) test -z "$(strip $(SHARED_SOURCE))" || \ $(INSTALL_DATA) $(SHARED_SOURCE) $(DISTDIR) + test -z "$(strip $(SHARED_TCL_LIB))" || \ + $(INSTALL_DATA) $(SHARED_TCL_LIB) $(DISTDIR) test -z "$(strip $(PDOBJECTS))" || \ $(INSTALL_DATA) $(PDOBJECTS) $(DISTDIR) test -z "$(strip $(HELPPATCHES))" || \ @@ -368,6 +418,11 @@ dist: $(DISTDIR) for file in $(MANUAL); do \ $(INSTALL_DATA) manual/$$file $(DISTDIR)/manual; \ done + test -z "$(strip $(UNITTESTS))" || \ + $(INSTALL_DIR) $(DISTDIR)/unittests && \ + for file in $(UNITTESTS); do \ + $(INSTALL_DATA) unittests/$$file $(DISTDIR)/unittests; \ + done tar --exclude-vcs -czpf $(DISTDIR).tar.gz $(DISTDIR) # make a Debian source package @@ -380,8 +435,12 @@ dpkg-source: rm -rf -- $(DISTDIR) $(ORIGDIR) cd .. && dpkg-source -b $(LIBRARY_NAME) -etags: - etags *.h $(SOURCES) ../../pd/src/*.[ch] /usr/include/*.h /usr/include/*/*.h +etags: TAGS + +TAGS: $(wildcard $(PD_INCLUDE)/*.h) $(SOURCES) $(SHARED_SOURCE) $(SHARED_HEADER) + etags $(wildcard $(PD_INCLUDE)/*.h) + etags -a *.h $(SOURCES) $(SHARED_SOURCE) $(SHARED_HEADER) + etags -a --language=none --regex="/proc[ \t]+\([^ \t]+\)/\1/" *.tcl showsetup: @echo "CC: $(CC)" @@ -397,9 +456,11 @@ showsetup: @echo "LIBRARY_NAME: $(LIBRARY_NAME)" @echo "LIBRARY_VERSION: $(LIBRARY_VERSION)" @echo "SOURCES: $(SOURCES)" + @echo "EXTENSION: $(EXTENSION)" @echo "SHARED_HEADER: $(SHARED_HEADER)" @echo "SHARED_SOURCE: $(SHARED_SOURCE)" @echo "SHARED_LIB: $(SHARED_LIB)" + @echo "SHARED_TCL_LIB: $(SHARED_TCL_LIB)" @echo "PDOBJECTS: $(PDOBJECTS)" @echo "ALLSOURCES: $(ALLSOURCES)" @echo "ALLSOURCES TCL: $(wildcard $(ALLSOURCES:.c=.tcl))" @@ -408,3 +469,6 @@ showsetup: @echo "pkglibdir: $(pkglibdir)" @echo "DISTDIR: $(DISTDIR)" @echo "ORIGDIR: $(ORIGDIR)" + @echo "NDK_TOOLCHAIN: $(NDK_TOOLCHAIN)" + @echo "NDK_BASE: $(NDK_BASE)" + @echo "NDK_SYSROOT: $(NDK_SYSROOT)" diff --git a/allow.c b/allow.c index a8a6238..15b3803 100644 --- a/allow.c +++ b/allow.c @@ -1,112 +1,112 @@ -/* ---------------------------- allow --------------------------------------- */ -/* */ -/* Lets only floats/symbols through that are allowed to do so. */ -/* Written by Olaf Matthes */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include - -static char *version = "allow v0.1, written by Olaf Matthes "; - -typedef struct allow -{ - t_object x_obj; - t_outlet *x_out; - t_atom *x_elem; // list of elemets that are allowed to pass - t_int x_numelem; // the number of elemetns in our allow-list -} t_allow; - - /* we got a symbol... */ -static void allow_symbol(t_allow *x, t_symbol *s) -{ - int i; - for(i = 0; i < x->x_numelem; i++) - { - if(x->x_elem[i].a_type == A_SYMBOL) // compare with all symbols in our list - if(atom_getsymbolarg(i, x->x_numelem, x->x_elem) == s) - { - outlet_symbol(x->x_out, s); - return; - } - } -} - - /* we got a float... */ -static void allow_float(t_allow *x, t_floatarg f) -{ - int i; - for(i = 0; i < x->x_numelem; i++) - { - if(x->x_elem[i].a_type == A_FLOAT) // compare with all floats in our list - if(atom_getfloatarg(i, x->x_numelem, x->x_elem) == f) - { - outlet_float(x->x_out, f); - return; - } - } -} - -static t_class *allow_class; - -static void allow_free(t_allow *x) -{ - freebytes(x->x_elem, x->x_numelem*sizeof(t_atom)); -} - -static void *allow_new(t_symbol *s, int argc, t_atom *argv) -{ - t_allow *x = (t_allow *)pd_new(allow_class); - - x->x_numelem = argc; // get the number of elements - x->x_elem = getbytes(argc*sizeof(t_atom)); - memcpy(x->x_elem, argv, argc*sizeof(t_atom)); - - x->x_out = outlet_new(&x->x_obj, gensym("anything")); - - // post("allow: got %d elements", x->x_numelem); - - return (x); -} - -#ifndef MAXLIB -void allow_setup(void) -{ - /* the object's class: */ - allow_class = class_new(gensym("allow"), (t_newmethod)allow_new, - (t_method)allow_free, sizeof(t_allow), 0, A_GIMME, 0); -#else -void maxlib_allow_setup(void) -{ - /* the object's class: */ - allow_class = class_new(gensym("maxlib_allow"), (t_newmethod)allow_new, - (t_method)allow_free, sizeof(t_allow), 0, A_GIMME, 0); - class_addcreator((t_newmethod)allow_new, gensym("allow"), A_GIMME, 0); -#endif - class_addsymbol(allow_class, allow_symbol); - class_addfloat(allow_class, allow_float); -#ifndef MAXLIB - - post(version); -#else - class_sethelpsymbol(allow_class, gensym("maxlib/allow-help.pd")); -#endif -} +/* ---------------------------- allow --------------------------------------- */ +/* */ +/* Lets only floats/symbols through that are allowed to do so. */ +/* Written by Olaf Matthes */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include + +static char *version = "allow v0.1, written by Olaf Matthes "; + +typedef struct allow +{ + t_object x_obj; + t_outlet *x_out; + t_atom *x_elem; // list of elemets that are allowed to pass + t_int x_numelem; // the number of elemetns in our allow-list +} t_allow; + + /* we got a symbol... */ +static void allow_symbol(t_allow *x, t_symbol *s) +{ + int i; + for(i = 0; i < x->x_numelem; i++) + { + if(x->x_elem[i].a_type == A_SYMBOL) // compare with all symbols in our list + if(atom_getsymbolarg(i, x->x_numelem, x->x_elem) == s) + { + outlet_symbol(x->x_out, s); + return; + } + } +} + + /* we got a float... */ +static void allow_float(t_allow *x, t_floatarg f) +{ + int i; + for(i = 0; i < x->x_numelem; i++) + { + if(x->x_elem[i].a_type == A_FLOAT) // compare with all floats in our list + if(atom_getfloatarg(i, x->x_numelem, x->x_elem) == f) + { + outlet_float(x->x_out, f); + return; + } + } +} + +static t_class *allow_class; + +static void allow_free(t_allow *x) +{ + freebytes(x->x_elem, x->x_numelem*sizeof(t_atom)); +} + +static void *allow_new(t_symbol *s, int argc, t_atom *argv) +{ + t_allow *x = (t_allow *)pd_new(allow_class); + + x->x_numelem = argc; // get the number of elements + x->x_elem = getbytes(argc*sizeof(t_atom)); + memcpy(x->x_elem, argv, argc*sizeof(t_atom)); + + x->x_out = outlet_new(&x->x_obj, gensym("anything")); + + // post("allow: got %d elements", x->x_numelem); + + return (x); +} + +#ifndef MAXLIB +void allow_setup(void) +{ + /* the object's class: */ + allow_class = class_new(gensym("allow"), (t_newmethod)allow_new, + (t_method)allow_free, sizeof(t_allow), 0, A_GIMME, 0); +#else +void maxlib_allow_setup(void) +{ + /* the object's class: */ + allow_class = class_new(gensym("maxlib_allow"), (t_newmethod)allow_new, + (t_method)allow_free, sizeof(t_allow), 0, A_GIMME, 0); + class_addcreator((t_newmethod)allow_new, gensym("allow"), A_GIMME, 0); +#endif + class_addsymbol(allow_class, allow_symbol); + class_addfloat(allow_class, allow_float); +#ifndef MAXLIB + + logpost(NULL, 4, version); +#else + class_sethelpsymbol(allow_class, gensym("maxlib/allow-help.pd")); +#endif +} diff --git a/arbran.c b/arbran.c index d708e11..7dc68ac 100644 --- a/arbran.c +++ b/arbran.c @@ -1,189 +1,189 @@ -/* ---------------------------- rand_arbran ----------------------------------- */ -/* */ -/* rand_arbran generates a random variable that conforms to the */ -/* piecewise probability density in two arrays */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Based on code found in Dodge/Jerse "Computer Music" */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include -#include -#include - -#define fran() (t_float)rand()/(t_float)RAND_MAX -#ifndef M_PI -#define M_PI 3.1415927 -#endif - -static char *version = "arbran v0.1b, generates a random variable that conforms to the\n" - " piecewise probability density in two arrays\n" - " written by Olaf Matthes "; - -/* -------------------------- rand_arbran ------------------------------ */ - -static t_class *rand_arbran_class; - -typedef struct _rand_arbran -{ - t_object x_obj; - t_symbol *x_x; - t_symbol *x_p; - t_garray *x_bufx; - t_garray *x_bufp; -} t_rand_arbran; - -static void rand_arbran_pdfscale(t_rand_arbran *x) -{ - t_garray *bx = x->x_bufx, *bp = x->x_bufp; - t_float a = 0; - t_int k = 0; - t_float *tx, *tp; - int ix, ip; - if (!garray_getfloatarray(bx, &ix, &tx)) - { - post("arbran: couldn't read from array!"); - return; - } - if (!garray_getfloatarray(bp, &ip, &tp)) - { - post("arbran: couldn't read from array!"); - return; - } - - for(k = 1; k < ix; k++) - { - a += (tx[k]-tx[k-1])*(tp[k]+tp[k-1])/2.0; - } - for(k = 0; k < ix; k++) - { - tp[k] = tp[k]/a; - } - garray_redraw(x->x_bufp); -} - -static void rand_arbran_bang(t_rand_arbran *x) -{ - t_garray *bx = x->x_bufx, *bp = x->x_bufp; - t_float a, u, a0, slope, b, d, r; - t_int k = 0; - t_float *tx, *tp; - int ix, ip; - if (!garray_getfloatarray(bx, &ix, &tx)) - { - post("arbran: couldn't read from array!"); - return; - } - if (!garray_getfloatarray(bp, &ip, &tp)) - { - post("arbran: couldn't read from array!"); - return; - } - - a = 0; - a0 = 0; - u = fran(); - while(u > a) - { - a0 = (tx[k+1]-tx[k])*(tp[k+1]+tp[k])/2.0; - a += a0; - k++; - } - k--; - slope = (tp[k+1]-tp[k])/(tx[k+1]-tx[k]); - if(slope == 0) - { - r = (u-a+a0)/tp[k]+tx[k]; - } - else - { - b=tp[k]/slope-tx[k]; - d=b*b+tx[k]*tx[k]+2*b*tx[k]+2*(u-a+a0)/slope; - if(slope > 0) - r=-b+sqrt(d); - else - r=-b-sqrt(d); - } - outlet_float(x->x_obj.ob_outlet, r); -} - -static void rand_arbran_set(t_rand_arbran *x) -{ - t_garray *b, *b2; - - if ((b = (t_garray *)pd_findbyclass(x->x_x, garray_class))) - { - post("arbran: array set to \"%s\"", x->x_x->s_name); - x->x_bufx = b; - } else { - post("arbran: no array \"%s\" (error %d)", x->x_x->s_name, b); - x->x_bufx = 0; - } - if ((b2 = (t_garray *)pd_findbyclass(x->x_p, garray_class))) - { - post("arbran: array set to \"%s\"", x->x_p->s_name); - x->x_bufp = b2; - } else { - post("arbran: no array \"%s\" (error %d)", x->x_p->s_name, b); - x->x_bufp = 0; - } -} - -static void rand_arbran_setarrays(t_rand_arbran *x, t_symbol *s1, t_symbol *s2) -{ - x->x_x = s1; - x->x_p = s2; - rand_arbran_set(x); -} - -static void *rand_arbran_new(t_symbol *s1, t_symbol *s2) -{ - t_rand_arbran *x = (t_rand_arbran *)pd_new(rand_arbran_class); - srand( (unsigned)time( NULL ) ); - outlet_new(&x->x_obj, &s_float); - x->x_x = s1; - x->x_p = s2; - rand_arbran_set(x); - return (x); -} - -#ifndef MAXLIB -void arbran_setup(void) -{ - rand_arbran_class = class_new(gensym("arbran"), (t_newmethod)rand_arbran_new, 0, - sizeof(t_rand_arbran), 0, A_SYMBOL, A_SYMBOL, 0); -#else -void maxlib_arbran_setup(void) -{ - rand_arbran_class = class_new(gensym("maxlib_arbran"), (t_newmethod)rand_arbran_new, 0, - sizeof(t_rand_arbran), 0, A_SYMBOL, A_SYMBOL, 0); -#endif - class_addbang(rand_arbran_class, rand_arbran_bang); - class_addmethod(rand_arbran_class, (t_method)rand_arbran_pdfscale, gensym("pdfscale"), 0); - class_addmethod(rand_arbran_class, (t_method)rand_arbran_setarrays, gensym("set"), A_SYMBOL, A_SYMBOL, 0); -#ifndef MAXLIB - class_sethelpsymbol(rand_arbran_class, gensym("arbran-help.pd")); - post(version); -#else - class_addcreator((t_newmethod)rand_arbran_new, gensym("arbran"), A_SYMBOL, A_SYMBOL, 0); - class_sethelpsymbol(rand_arbran_class, gensym("maxlib/arbran-help.pd")); -#endif -} +/* ---------------------------- rand_arbran ----------------------------------- */ +/* */ +/* rand_arbran generates a random variable that conforms to the */ +/* piecewise probability density in two arrays */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Based on code found in Dodge/Jerse "Computer Music" */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include +#include +#include + +#define fran() (t_float)rand()/(t_float)RAND_MAX +#ifndef M_PI +#define M_PI 3.1415927 +#endif + +static char *version = "arbran v0.1b, generates a random variable that conforms to the\n" + " piecewise probability density in two arrays\n" + " written by Olaf Matthes "; + +/* -------------------------- rand_arbran ------------------------------ */ + +static t_class *rand_arbran_class; + +typedef struct _rand_arbran +{ + t_object x_obj; + t_symbol *x_x; + t_symbol *x_p; + t_garray *x_bufx; + t_garray *x_bufp; +} t_rand_arbran; + +static void rand_arbran_pdfscale(t_rand_arbran *x) +{ + t_garray *bx = x->x_bufx, *bp = x->x_bufp; + t_float a = 0; + t_int k = 0; + t_float *tx, *tp; + int ix, ip; + if (!garray_getfloatarray(bx, &ix, &tx)) + { + post("arbran: couldn't read from array!"); + return; + } + if (!garray_getfloatarray(bp, &ip, &tp)) + { + post("arbran: couldn't read from array!"); + return; + } + + for(k = 1; k < ix; k++) + { + a += (tx[k]-tx[k-1])*(tp[k]+tp[k-1])/2.0; + } + for(k = 0; k < ix; k++) + { + tp[k] = tp[k]/a; + } + garray_redraw(x->x_bufp); +} + +static void rand_arbran_bang(t_rand_arbran *x) +{ + t_garray *bx = x->x_bufx, *bp = x->x_bufp; + t_float a, u, a0, slope, b, d, r; + t_int k = 0; + t_float *tx, *tp; + int ix, ip; + if (!garray_getfloatarray(bx, &ix, &tx)) + { + post("arbran: couldn't read from array!"); + return; + } + if (!garray_getfloatarray(bp, &ip, &tp)) + { + post("arbran: couldn't read from array!"); + return; + } + + a = 0; + a0 = 0; + u = fran(); + while(u > a) + { + a0 = (tx[k+1]-tx[k])*(tp[k+1]+tp[k])/2.0; + a += a0; + k++; + } + k--; + slope = (tp[k+1]-tp[k])/(tx[k+1]-tx[k]); + if(slope == 0) + { + r = (u-a+a0)/tp[k]+tx[k]; + } + else + { + b=tp[k]/slope-tx[k]; + d=b*b+tx[k]*tx[k]+2*b*tx[k]+2*(u-a+a0)/slope; + if(slope > 0) + r=-b+sqrt(d); + else + r=-b-sqrt(d); + } + outlet_float(x->x_obj.ob_outlet, r); +} + +static void rand_arbran_set(t_rand_arbran *x) +{ + t_garray *b, *b2; + + if ((b = (t_garray *)pd_findbyclass(x->x_x, garray_class))) + { + post("arbran: array set to \"%s\"", x->x_x->s_name); + x->x_bufx = b; + } else { + post("arbran: no array \"%s\" (error %d)", x->x_x->s_name, b); + x->x_bufx = 0; + } + if ((b2 = (t_garray *)pd_findbyclass(x->x_p, garray_class))) + { + post("arbran: array set to \"%s\"", x->x_p->s_name); + x->x_bufp = b2; + } else { + post("arbran: no array \"%s\" (error %d)", x->x_p->s_name, b); + x->x_bufp = 0; + } +} + +static void rand_arbran_setarrays(t_rand_arbran *x, t_symbol *s1, t_symbol *s2) +{ + x->x_x = s1; + x->x_p = s2; + rand_arbran_set(x); +} + +static void *rand_arbran_new(t_symbol *s1, t_symbol *s2) +{ + t_rand_arbran *x = (t_rand_arbran *)pd_new(rand_arbran_class); + srand( (unsigned)time( NULL ) ); + outlet_new(&x->x_obj, &s_float); + x->x_x = s1; + x->x_p = s2; + rand_arbran_set(x); + return (x); +} + +#ifndef MAXLIB +void arbran_setup(void) +{ + rand_arbran_class = class_new(gensym("arbran"), (t_newmethod)rand_arbran_new, 0, + sizeof(t_rand_arbran), 0, A_SYMBOL, A_SYMBOL, 0); +#else +void maxlib_arbran_setup(void) +{ + rand_arbran_class = class_new(gensym("maxlib_arbran"), (t_newmethod)rand_arbran_new, 0, + sizeof(t_rand_arbran), 0, A_SYMBOL, A_SYMBOL, 0); +#endif + class_addbang(rand_arbran_class, rand_arbran_bang); + class_addmethod(rand_arbran_class, (t_method)rand_arbran_pdfscale, gensym("pdfscale"), 0); + class_addmethod(rand_arbran_class, (t_method)rand_arbran_setarrays, gensym("set"), A_SYMBOL, A_SYMBOL, 0); +#ifndef MAXLIB + class_sethelpsymbol(rand_arbran_class, gensym("arbran-help.pd")); + logpost(NULL, 4, version); +#else + class_addcreator((t_newmethod)rand_arbran_new, gensym("arbran"), A_SYMBOL, A_SYMBOL, 0); + class_sethelpsymbol(rand_arbran_class, gensym("maxlib/arbran-help.pd")); +#endif +} diff --git a/arraycopy.c b/arraycopy.c index 50d4dd8..c5e2eb0 100644 --- a/arraycopy.c +++ b/arraycopy.c @@ -25,7 +25,7 @@ #include "m_pd.h" #include -static char *version = "arraycopy v0.2, written by Olaf Matthes "; +static char *version = "arraycopy v0.2.1, written by Olaf Matthes "; typedef struct arraycopy { @@ -80,7 +80,7 @@ static void arraycopy_setsourcearray(t_arraycopy *x, t_symbol *s) /* get's called directly when we get a 'bang' */ static void arraycopy_docopy(t_arraycopy *x) { - + /* use new 64-bit compatible array API if available */ #if (defined PD_MAJOR_VERSION && defined PD_MINOR_VERSION) && (PD_MAJOR_VERSION > 0 || PD_MINOR_VERSION >= 41) # define arraynumber_t t_word # define array_getarray garray_getfloatwords @@ -94,11 +94,10 @@ static void arraycopy_docopy(t_arraycopy *x) #endif t_garray *b; /* make local copy of array */ - arraynumber_t *tab; /* the content itselfe */ - int items; + arraynumber_t *tab; /* the content itself */ + int sourcesize, destsize; t_int i; t_garray *A; - int npoints; arraynumber_t *vec; if(!x->x_destarray) @@ -123,40 +122,55 @@ static void arraycopy_docopy(t_arraycopy *x) } // read from our array - if (!array_getarray(b, &items, &tab)) + if (!array_getarray(b, &sourcesize, &tab)) { - post("arraycopy: couldn't read from source array!"); + pd_error(x, "arraycopy: couldn't read from source array '%s'!", + x->x_sourcearray->s_name); return; } if (!(A = (t_garray *)pd_findbyclass(x->x_destarray, garray_class))) error("arraycopy: %s: no such array", x->x_destarray->s_name); - else if (!array_getarray(A, &npoints, &vec)) + else if (!array_getarray(A, &destsize, &vec)) error("arraycopy: %s: bad template ", x->x_destarray->s_name); else { - if(x->x_start > items) // check start point + if(x->x_start > sourcesize) + { + pd_error(x, "arraycopy: start point %i out of range for source '%s'", + (int)x->x_start, x->x_sourcearray->s_name); + return; + } + if(x->x_start > destsize) { - post("arraycopy: source start point out of range for the array given"); + pd_error(x, "arraycopy: start point %i out of range for destination '%s'", + (int)x->x_start, x->x_destarray->s_name); return; } if(x->x_end) // end point is specified { - if(x->x_end > items) // check start point - { - post("arraycopy: source end point out of range for the array given"); - x->x_end = items; + if(x->x_end > sourcesize) + { + logpost(x, 2, "arraycopy: end point %i out of range for source '%s', using %i", + (int)x->x_end, x->x_sourcearray->s_name, sourcesize); + x->x_end = sourcesize; + } + if(x->x_end > destsize) + { + logpost(x, 2, "arraycopy: end point %i out of range for destination '%s', using %i", + (int)x->x_end, x->x_destarray->s_name, destsize); + x->x_end = destsize; } } - else x->x_end = items; + else + x->x_end = (sourcesize < destsize ? sourcesize : destsize); if(x->x_pos) vec += x->x_pos; - for(i = x->x_start; i < x->x_end; i++) { - array_set(vec, 0, array_get(tab, i)); + array_set(vec, 0, array_get(tab, i)); vec++; } garray_redraw(A); @@ -292,7 +306,7 @@ void maxlib_arraycopy_setup(void) // class_addlist(arraycopy_class, arraycopy_list); #ifndef MAXLIB - post(version); + logpost(NULL, 4, version); #else class_sethelpsymbol(arraycopy_class, gensym("maxlib/arraycopy-help.pd")); #endif diff --git a/automata.txt b/automata.txt deleted file mode 100644 index 3f5ff21..0000000 --- a/automata.txt +++ /dev/null @@ -1,178 +0,0 @@ -[The following note originally appeared on the emusic-l mailing list. It is -reprinted here with the author's permission] - -From xrjdm@FARSIDE.GSFC.NASA.GOV Wed Nov 23 11:26:39 1994 -Date: Tue, 4 Oct 1994 15:09:23 -0500 -From: Joe McMahon -Reply to: Electronic Music Discussion List -To: Multiple recipients of list EMUSIC-L -Subject: Automata: the long-awaited summary - -Back in August, I think, I promised to post a quick intro to cellular -automata and how they can be used as a sound-generation tool. Since I'm -going to take a couple of different sources and sum them up with little or -no direct attribution, combined with my own opinions, I'll give everybody -my references *first* so they can delete the article and draw their own -conclusions if they so prefer. - -The primary reference that got me started on all this is one in the CMJ: -Vol 14, No. 4, Winter 1990: "Digital Synthesis of Self-modifying Waveforms -by Means of Cellular Automata" (Jacques Chareyon). Those who are already -familiar with automata may just skip to that article and forget about the -rest of this one. -Note: the article gives a mail address for M. Chareyon, but he did not -answer an inquiry about any available recordings using this technique in -1990. - -So. Anyone still here? Good. - -Cellular automata are a mathematical concept first introduced in the late -1940's. Generally speaking, a cellular automaton consists of a grid of -cells. Each cell may take on any of a number of values - binary automata -(cell on or cell off) are the most commonly studied. Each cell has a -neighborhood, defined more simply as other cells which influence its state. -The exact nature of this influence is defined by what are called transition -rules. The cellular automaton starts off with some cells in any of the -allowable states. for each "step" in the automaton's history, the -neighborhood of every cell is checked, and the state of the cell is -updated. All updates occur simultaneously. - -The transition rule must describe the resulting state of a cell for every -possible configuration of other cells in the neighborhood. For large -numbers of states, the amount of memory required to hold the transition -rule becomes increasingly large, Therefore, some automata use what is known -as a "totalistic" rule. These rules simply sum the values of the cells in -the neighborhood and then assign a result on this basis. The resulting -tables are far smaller. - -Many readers may already be familiar with John Horton Conway's game of -"Life". This is a two-dimensional binary automaton with a totalistic rule. -This makes for a very small rule set: - - i) If fewer than two filled cells (cells with value 1) surround a cell, - it becomes empty next generation. - ii) If more than three filled cells surround a cell, it becomes empty - next generation. -iii) If exactly three cells filled cells surround a cell, it becomes - filled on the next generation. - -This corresponds to a totalistic rule set with a total of 8(2-1)+1 or 9 -rules (one each for the sum values of 0 (no cells with a value) through 9 -(all cells with a value) ).If the transition rule were represented as a -non-totalistic one, the rule set would need 2**8 or 256 entries. There are -many interesting totalistic automata, so giving up detailed description of -every nuance of the transitions to save memory space isn't a big sacrifice. - -Interesting as two dimensional automata are, they really aren't terribly -useful for music making. There have been some experiments which have -attempted to use a two-dimensional automaton to generate MIDI events - -synthesis at the note level, using : - -Battista, T. and M. Giri, 1988. "Composizione Tramite Automi Cellulari." -Atti del VII Cooloquio di Informatica Musicale. Rome, Italy: Edizione Arti -Grafiche Ambrosini, pp. 181-182. - -Edgar, R. and J. Ryan, 1986. "LINA" Exhibition of the 1986 International -Computer Music Conference, San Francisco: Computer Music Association. - -I have not heard any of the music from these efforts, so I certainly can't -pass any judgement on them. For the purposes of this summary, we'll just -look at one-dimensional automata. These use a linear array of cells, with -the neighborhood generally being one or two cells on either side of each -cell. -(This is the type of automaton dealt with in M. Chareyon's article, which I -will be paraphrasing broadly hereafter). - -M. Chareyon's automata are wavetables. A digitized signal is stored as a -linear array of numbers in memory. A totalistic rule is used to determine a -lookup value which indexes into an array containing the resulting value; -this is saved into a second array. After the first array is completely -processed, the roles of the two are swapped and the process is repeated. - -The limiting factor in this process is the number of bits of resolution -being used to generate the sound. For a totalistic rule using a two-cell -neighborhood and 12-bit individual samples, we have 3*(2*12) = 12288 -entries in the rule table. At 2 bytes each, this is 24K of storage. If we -go to 16-bit sample resolution, we have 196608 entries at 2 bytes each for -a total of 393216 bytes, or 384K. - -The key point of M. Charyeon's method is the use of small neighborhoods -with large numbers of cellular states. Since the computation of the new -wavetable is all table lookup, very complex transition rules can be -precomputed and loaded into the tables, allowing the synthesis to -essentially be a fast sum-and-lookup loop to calculate each new wavesample. ->From the article, it appears that M. Chareyon was able to produce 2 or 3 -voices in realtime on a Mac II with a Digidesign Sound Accelerator board. -It seems that it would probably be possible to use an AV Mac to do it -without the board. - -This LASy (Linear Automaton Synthesis) method is closely related to the -Karplus-Strong plucked-string algorithm, in that a wavesample is run -through an algorithm which recirculates the samples to "self-modify" the -wave. In fact, a judicious choice of table entries allows one to very -simply simulate the K-S algoritm directly. - -So what are the sounds like? Some automata produce waveforms which quickly -"ramp-up" to complex spectra and then drop off quickly. Others move to a -steady state and then remain there. Yet others produce never-ending and -unpredictable waveforms, whose harmonic content is constantly changing. - -Obviously enough, the original wavesample can be obtained mathematically, -or by actual sampling and using LASy as a waveshaper. As M. Chareyon notes, -a quick estimate of the number of possible automata for a 2-neighbor -totalistic rule using a 256-entry wavetable with 12-bit entries is -(2**12)**256 * (2**12)**(3*2**12) or about 10**4500 possible automata. Of -course, many, many of these would not be suitable for music (e.g., the 4096 -automata in which all values go to one vlaue in one step, etc.); however, -the number of musically useful automata is still likely to be an immense -number. - -M. Chareyon provides a number of examples of ways to fill out the rule -tables and a number of hints on creating wave tables - generally speaking, -one can create a function which is used to compute the values to be placed -into the table and then fill it so it can simply be loaded and used by the -basic algorithm. His experience in using LASy is that he manages -approximately 50% of the time to produce sounds with the desired -characteristics, and that about 10% of the remaining time he gets -unexpected but useful results which can be used as starting points for -further exploration. - -Again, the important point is that the basic automaton uses wavesamples at -full resolution, calculating a new wavesample for each step of the -automaton; the next wavesample can be played while the new one is being -calculated. Because of the large number of states, mathematical tools for -the analysis of automata and the construction of automata with specifically -desired qualities require too much storage and compute time to make them -useful for LASy purposes. - -Again, much of this article is paraphrased from M. Chareyon's article; I -take no credit for any of the work in this note. I'm just summarizing. - -The following other articles were referenced by M. Chareyon's article: - -Burks, A., ed. 1970. Essays on Cellular Automata. Champaign/Urbana, IL: -University of Illinois Press. - -Chareyon, J. 1988a. "Sound Synthesis and Processing by Means of Linear -Cellular Automata." Proceedings of the 1988 Internation Computer Music -Conference. San Francisco: Computer Music Association. - -Chareyon, J. 1988b. "Wavetable come Automa Cellulare: una Nuova Tecnica di -Sintesi." Atti del VII Colloquio di Informatica Musicale, Rome, Italy: -Edizioni Arti Grafiche Ambrosini, pp. 174-177. - -Farmer, D., T. Toffoli, and S. Wolfram, eds. 1984. Cellular Automata. -North-Holland Physics Publishing. [One of the definitive works on cellular -automata - fairly heavy math, not a popular presentation - JM] - -Gardner, M. 1970. "The Fantastic Combinations of John Conway's New Solitare -Game 'Life'". Scientific American 223(4) 120-123. [A good introduction to -cellular automata, focusing on 'life' in specific. Useful intro if my -1-paragraph summary of automata was confusing :) - JM] - - --- Joe M. - --- -"At the end of the hour, we'll have information on the sedatives used by -the artists,,," (MST3K) - diff --git a/average.c b/average.c index 2ce99ad..4e0f2d0 100644 --- a/average.c +++ b/average.c @@ -1,202 +1,202 @@ -/* -------------------------- average ----------------------------------------- */ -/* */ -/* Calculates the average value of the last N elements. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include - -#define MAX_ARG 128 /* maximum number of items to average */ - -static char *version = "average v0.1, written by Olaf Matthes "; - -typedef struct average -{ - t_object x_ob; - t_clock *x_clock; - t_inlet *x_inindex; - t_outlet *x_outfloat; /* output the average */ - t_outlet *x_outtendency; /* outputs the tendency of the average */ - t_int x_limit; /* indicates if input is 'blocked' (1) */ - t_int x_index; /* the number of elements to average */ - t_float x_input[MAX_ARG]; /* stores the input values we need for averaging */ - t_int x_inpointer; /* actual position in above array */ - t_float x_average; /* what do you guess ? */ - t_float x_lastaverage; - t_int x_mode; /* how to average: linear or geometric */ - -} t_average; - - /* there must be a function for this in math.h but how is the - german 'Fakultät' called in english ???? */ -static int normalise(int i) -{ - int ret = i; - while(i--) - { - if(i == 0)break; - ret += i; - } - return (ret); -} - -static void average_float(t_average *x, t_floatarg f) -{ - int i, j = 0; - t_float tendency; - t_float geo = 1.0; - - x->x_average = 0; - /* put value into array */ - x->x_input[x->x_inpointer] = f; - /* calulate average */ - for(i = 0; i < x->x_index; i++) - { - if(x->x_mode == 0) /* linear */ - { - x->x_average += x->x_input[i] * (1.0 / (float)x->x_index); - } - else if(x->x_mode == 1) /* geometric */ - { - if(x->x_input[i] == 0)x->x_input[i] = 0.001; /* need to cheat a bit... */ - geo *= x->x_input[i]; - if(i == x->x_index - 1) - x->x_average = pow(geo, (1.0/(float)x->x_index)); - } - else if(x->x_mode == 2) /* weighted */ - { - x->x_average += x->x_input[(j + x->x_inpointer + x->x_index) % x->x_index] * (float)(x->x_index - (i + 1)); - j--; /* go back in array */ - /* normalise output */ - if(i == x->x_index - 1) - x->x_average = x->x_average / (float)normalise(x->x_index - 1); - } else post("average: internal error!"); - } - if(++x->x_inpointer > x->x_index) - { - x->x_inpointer = 0; - if(x->x_lastaverage < x->x_average) - { - tendency = 1; /* getting more */ - } - else if(x->x_lastaverage > x->x_average) - { - tendency = -1; /* getting less */ - } - else tendency = 0; /* nothing has changed */ - outlet_float(x->x_outtendency, tendency); - x->x_lastaverage = x->x_average; - } - outlet_float(x->x_outfloat, x->x_average); -} - -static void average_index(t_average *x, t_floatarg f) -{ - x->x_index = (t_int)f; - if(x->x_index > MAX_ARG)x->x_index = MAX_ARG; -} - -static void average_reset(t_average *x) -{ - int i; - /* zeroe out the array */ - for(i = 0; i < MAX_ARG; i++)x->x_input[i] = 0.0; - x->x_inpointer = 0; - x->x_average = 0; - x->x_lastaverage = 0; - post("average: reset"); -} - -static void average_linear(t_average *x) -{ - x->x_mode = 0; - post("average: linear"); -} - -static void average_geometric(t_average *x) -{ - x->x_mode = 1; - post("average: geometric"); -} - -static void average_weight(t_average *x) -{ - x->x_mode = 2; - post("average: weighted"); -} - -static void average_free(t_average *x) -{ - /* nothing to do */ -} - -static t_class *average_class; - -static void *average_new(t_floatarg f) -{ - int i; - - t_average *x = (t_average *)pd_new(average_class); - x->x_inindex = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("index")); - x->x_outfloat = outlet_new(&x->x_ob, gensym("float")); - x->x_outtendency = outlet_new(&x->x_ob, gensym("float")); - - /* zeroe out the array */ - for(i = 0; i < MAX_ARG; i++)x->x_input[i] = 0.0; - x->x_index = (t_int)f; - if(x->x_index > MAX_ARG) - { - x->x_index = MAX_ARG; - post("average: set number of items to %d", x->x_index); - } - x->x_inpointer = 0; - x->x_average = 0; - x->x_mode = 0; - return (void *)x; -} - -#ifndef MAXLIB -void average_setup(void) -{ - average_class = class_new(gensym("average"), (t_newmethod)average_new, - (t_method)average_free, sizeof(t_average), 0, A_DEFFLOAT, 0); -#else -void maxlib_average_setup(void) -{ - average_class = class_new(gensym("maxlib_average"), (t_newmethod)average_new, - (t_method)average_free, sizeof(t_average), 0, A_DEFFLOAT, 0); -#endif - class_addmethod(average_class, (t_method)average_reset, gensym("reset"), 0); - class_addmethod(average_class, (t_method)average_linear, gensym("linear"), 0); - class_addmethod(average_class, (t_method)average_geometric, gensym("geometric"), 0); - class_addmethod(average_class, (t_method)average_weight, gensym("weight"), 0); - class_addfloat(average_class, average_float); - class_addmethod(average_class, (t_method)average_index, gensym("index"), A_FLOAT, 0); -#ifndef MAXLIB - post(version); - -#else - class_addcreator((t_newmethod)average_new, gensym("average"), A_DEFFLOAT, 0); - class_sethelpsymbol(average_class, gensym("maxlib/average-help.pd")); -#endif -} - +/* -------------------------- average ----------------------------------------- */ +/* */ +/* Calculates the average value of the last N elements. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include + +#define MAX_ARG 128 /* maximum number of items to average */ + +static char *version = "average v0.1, written by Olaf Matthes "; + +typedef struct average +{ + t_object x_ob; + t_clock *x_clock; + t_inlet *x_inindex; + t_outlet *x_outfloat; /* output the average */ + t_outlet *x_outtendency; /* outputs the tendency of the average */ + t_int x_limit; /* indicates if input is 'blocked' (1) */ + t_int x_index; /* the number of elements to average */ + t_float x_input[MAX_ARG]; /* stores the input values we need for averaging */ + t_int x_inpointer; /* actual position in above array */ + t_float x_average; /* what do you guess ? */ + t_float x_lastaverage; + t_int x_mode; /* how to average: linear or geometric */ + +} t_average; + + /* there must be a function for this in math.h but how is the + german 'Fakultät' called in english ???? */ +static int normalise(int i) +{ + int ret = i; + while(i--) + { + if(i == 0)break; + ret += i; + } + return (ret); +} + +static void average_float(t_average *x, t_floatarg f) +{ + int i, j = 0; + t_float tendency; + t_float geo = 1.0; + + x->x_average = 0; + /* put value into array */ + x->x_input[x->x_inpointer] = f; + /* calulate average */ + for(i = 0; i < x->x_index; i++) + { + if(x->x_mode == 0) /* linear */ + { + x->x_average += x->x_input[i] * (1.0 / (float)x->x_index); + } + else if(x->x_mode == 1) /* geometric */ + { + if(x->x_input[i] == 0)x->x_input[i] = 0.001; /* need to cheat a bit... */ + geo *= x->x_input[i]; + if(i == x->x_index - 1) + x->x_average = pow(geo, (1.0/(float)x->x_index)); + } + else if(x->x_mode == 2) /* weighted */ + { + x->x_average += x->x_input[(j + x->x_inpointer + x->x_index) % x->x_index] * (float)(x->x_index - (i + 1)); + j--; /* go back in array */ + /* normalise output */ + if(i == x->x_index - 1) + x->x_average = x->x_average / (float)normalise(x->x_index - 1); + } else post("average: internal error!"); + } + if(++x->x_inpointer > x->x_index) + { + x->x_inpointer = 0; + if(x->x_lastaverage < x->x_average) + { + tendency = 1; /* getting more */ + } + else if(x->x_lastaverage > x->x_average) + { + tendency = -1; /* getting less */ + } + else tendency = 0; /* nothing has changed */ + outlet_float(x->x_outtendency, tendency); + x->x_lastaverage = x->x_average; + } + outlet_float(x->x_outfloat, x->x_average); +} + +static void average_index(t_average *x, t_floatarg f) +{ + x->x_index = (t_int)f; + if(x->x_index > MAX_ARG)x->x_index = MAX_ARG; +} + +static void average_reset(t_average *x) +{ + int i; + /* zeroe out the array */ + for(i = 0; i < MAX_ARG; i++)x->x_input[i] = 0.0; + x->x_inpointer = 0; + x->x_average = 0; + x->x_lastaverage = 0; + post("average: reset"); +} + +static void average_linear(t_average *x) +{ + x->x_mode = 0; + post("average: linear"); +} + +static void average_geometric(t_average *x) +{ + x->x_mode = 1; + post("average: geometric"); +} + +static void average_weight(t_average *x) +{ + x->x_mode = 2; + post("average: weighted"); +} + +static void average_free(t_average *x) +{ + /* nothing to do */ +} + +static t_class *average_class; + +static void *average_new(t_floatarg f) +{ + int i; + + t_average *x = (t_average *)pd_new(average_class); + x->x_inindex = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("index")); + x->x_outfloat = outlet_new(&x->x_ob, gensym("float")); + x->x_outtendency = outlet_new(&x->x_ob, gensym("float")); + + /* zeroe out the array */ + for(i = 0; i < MAX_ARG; i++)x->x_input[i] = 0.0; + x->x_index = (t_int)f; + if(x->x_index > MAX_ARG) + { + x->x_index = MAX_ARG; + post("average: set number of items to %d", x->x_index); + } + x->x_inpointer = 0; + x->x_average = 0; + x->x_mode = 0; + return (void *)x; +} + +#ifndef MAXLIB +void average_setup(void) +{ + average_class = class_new(gensym("average"), (t_newmethod)average_new, + (t_method)average_free, sizeof(t_average), 0, A_DEFFLOAT, 0); +#else +void maxlib_average_setup(void) +{ + average_class = class_new(gensym("maxlib_average"), (t_newmethod)average_new, + (t_method)average_free, sizeof(t_average), 0, A_DEFFLOAT, 0); +#endif + class_addmethod(average_class, (t_method)average_reset, gensym("reset"), 0); + class_addmethod(average_class, (t_method)average_linear, gensym("linear"), 0); + class_addmethod(average_class, (t_method)average_geometric, gensym("geometric"), 0); + class_addmethod(average_class, (t_method)average_weight, gensym("weight"), 0); + class_addfloat(average_class, average_float); + class_addmethod(average_class, (t_method)average_index, gensym("index"), A_FLOAT, 0); +#ifndef MAXLIB + logpost(NULL, 4, version); + +#else + class_addcreator((t_newmethod)average_new, gensym("average"), A_DEFFLOAT, 0); + class_sethelpsymbol(average_class, gensym("maxlib/average-help.pd")); +#endif +} + diff --git a/beat.c b/beat.c index a2f565e..1bf5a76 100644 --- a/beat.c +++ b/beat.c @@ -1,403 +1,403 @@ -/* --------------------------- beat ------------------------------------------ */ -/* */ -/* Detect the beats per minute of a MIDI stream. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Based on code written by Robert Rowe. */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include -#include -#include - -#define BEAT_LONG 1500 /* longest time we take into concideration (40 bpm) */ -#define BEAT_SHORT 300 /* shortest time we take into concideration (200 bpm) */ - -static char *version = "beat v0.1, written by Olaf Matthes "; - -typedef struct -{ - t_int points; /* number of points assigned to this theory */ - double expect; /* time of next expected hit */ - t_int onbeat; /* whether (1) or not (0) it was on the beat */ -} beat_theory; - -typedef struct /* used for sorting theories */ -{ - t_int points; - t_int theory; -} beat_sort_record; - - -typedef struct beat -{ - t_object x_ob; - t_clock *x_clock; - t_outlet *x_outbpm; /* beat as MIDI note number */ - t_outlet *x_outms; /* beat in milliseconds */ - t_outlet *x_outbeat; /* send a bang whenever beat is 'on beat' */ - t_int x_print; /* switch printing to console window on / off */ - - t_int x_num_beats; /* number of beats we've received */ - double x_beat_period; /* time in ms until next expected beat / beat pulse */ - beat_theory x_beats[BEAT_LONG]; - double x_beatexpect; /* expected time for next beat */ - t_int x_on_beat; /* indicate if last event was on beat */ - t_int x_band_percent; - - t_int x_pitch; - t_int x_velo; - /* helpers needed to do the time calculations */ - double x_this_input; - double x_last_input; - double x_lasttime; - double x_lastlasttime; -} t_beat; - -/* ---------------- mathematical functions to work with doubles -------------- */ -static double double_abs(double value) -{ - if(value < 0) - return (value * -1); - else - return (value); -} - -/* --------------- beat stuff ------------------------------------------------ */ - /* evaluate results: find theory that is the most likely one and - print out internal data to console window if print is enabled */ -static int beat_evaluate(t_beat *x) -{ - int i, j, K; - char string[256]; - char info[40]; - beat_sort_record theories[BEAT_LONG], *sortp, R; - int value; /* the result of the sorting */ - - for (i = 0; i < BEAT_LONG; i++) - { /* prepare sort records */ - sortp = &(theories[i]); - sortp->points = x->x_beats[i].points; - sortp->theory = i; - } - for (j = 2; j < BEAT_LONG; j++) - { /* sort */ - i = j - 1; - K = theories[j].points; - R = theories[j]; - while (i > 0) - { - if (K >= theories[i].points) - { - theories[i+1] = R; - break; - } - else - { - theories[i+1] = theories[i]; - i -= 1; - } - } - if (i==0) theories[i+1] = R; - } - /* get leading result */ - sortp = &(theories[BEAT_LONG - 1]); - value = sortp->theory; /* get our resulting theory */ - - if(x->x_print) - { - post(" 0 1 2 3 4 R E"); - *string = '\0'; /* print out five leading theories */ - sprintf(info, "%4g", x->x_this_input); - strcat(string, info); - for(i = 1; i < 6; i++) - { - sortp = &(theories[BEAT_LONG - i]); - sprintf(info, " %4d[%3d]", (int) sortp->theory, (int) sortp->points); - strcat(string, info); - } - sprintf(info, " %g %g", clock_getlogicaltime(), x->x_beatexpect); - strcat(string, info); - post(string); - } - - return value; -} - - /* reduce duration to fit into our processing window */ - /* some sort of 'double modulo'... */ -static double beat_reduce_offset(double duration) -{ - double temp = duration; - int divisor = 2; /* first try dividing by two */ - while (temp > BEAT_LONG) /* while duration is too long */ - temp = duration / divisor++; /* divide by progressively higher divisors */ - return temp; /* return a value in bounds */ -} - -/* - * beat_eligible: determine whether an event is eligible for consideration - * as a beat theory - */ -static int beat_eligible(double candidate, int* offsets, int num_offsets) -{ - double diff; - int i; - - if (candidate >= BEAT_LONG) /* if too long try subharmonics */ - candidate = beat_reduce_offset(candidate); - - /* if candidate is close to one already found */ - for(i = 0; i < num_offsets; i++) - { - diff = double_abs((candidate - offsets[i])); - if (diff < offsets[i]/20) { - if (candidate > offsets[i]) - ++offsets[i]; else /* pull existing one */ - if (candidate < offsets[i]) /* toward new candidate */ - --offsets[i]; - return 0; /* declare candidate ineligible */ - } - } - return candidate; /* otherwise return legal candidate */ -} - -static void beat_float(t_beat *x, t_floatarg f) -{ - t_int velo = x->x_velo; - int i, j, indx; - int num_offsets, candidate; - int low_limit, high_limit, width, deviation; - int points, band, center_offset, period; - beat_theory* t; - int offsets[7]; - static int factors[10] = - { 200, 50, 300, 150, 66, 400, 600, 133, 33, 75 }; - double now = clock_getlogicaltime(); - t_float outvalue; - - x->x_pitch = (t_int)f; - x->x_this_input = clock_gettimesince(x->x_last_input); - - if(velo != 0) /* note-on received */ - { - if(++x->x_num_beats == 1) - { - goto time; /* only one event, no beats yet */ - } - - num_offsets = 0; - candidate = beat_eligible(x->x_this_input, offsets, num_offsets); - if(candidate) - offsets[num_offsets++] = candidate; /* offset[0] set to incoming offset */ - - if(x->x_num_beats > 2) - { /* if three events */ - /* check previous for eligibility */ - candidate = beat_eligible(x->x_lasttime, offsets, num_offsets); - if (candidate) - offsets[num_offsets++] = candidate; - candidate = x->x_this_input + x->x_lasttime; /* add current and previous offsets */ - candidate = beat_eligible(candidate, offsets, num_offsets); - if (candidate) /* add to list if eligible */ - offsets[num_offsets++] = candidate; - } - - if(x->x_num_beats > 3) - { - candidate = beat_eligible(x->x_lastlasttime, offsets, num_offsets); - if (candidate) - offsets[num_offsets++] = candidate; - candidate += x->x_lasttime; - candidate = beat_eligible(candidate, offsets, num_offsets); - if (candidate) - offsets[num_offsets++] = candidate; - } - - indx = 0; - for(i = num_offsets; i < 7; i++) - { - offsets[i] = 0; - if (indx >= 10) break; - candidate = 0; - while ((indx < 10) && (!candidate)) - candidate = beat_eligible((x->x_this_input * factors[indx++])/100, offsets, num_offsets); - if (candidate) - offsets[num_offsets++] = candidate; - } - - for(i = 0; i < num_offsets; i++) - { - band = offsets[i] * x->x_band_percent / 100; - if ((low_limit = offsets[i] - band) < 0) /* add points in a critical band */ - low_limit = 0; /* around calculated offset */ - if ((high_limit = offsets[i] + band) > BEAT_LONG) - high_limit = BEAT_LONG; - center_offset = offsets[i]; /* midpoint of increment */ - points = 0; - for (j = low_limit; j < high_limit; j++) - { - if ((points = x->x_beats[j].points) > 0) - { /* if there is already activation */ - deviation = j - center_offset; /* record deviation from midpoint */ - x->x_beats[j].points = 0; - if (deviation < 0) { /* if there is activation below midpoint */ - t = &(x->x_beats[j+1]); /* take theory one above prior */ - } else - if (deviation > 0) { /* if there is activation above midpoint */ - t = &(x->x_beats[j-1]); /* take theory one below prior */ - } else - t = &(x->x_beats[j]); /* landed right on it */ - t->points = points + (num_offsets-i); - break; - } - } - if (!points) - x->x_beats[center_offset].points = num_offsets - i; - } - - /* boost hits, and suppress theories with missed beats */ - period = 0; - points = 0; - for (i = BEAT_SHORT; i < BEAT_LONG; i++) - { - t = &(x->x_beats[i]); - width = 5 > (t->expect / 7) ? 5 : (t->expect / 7); - t->expect -= x->x_this_input; - t->onbeat = 0; - if(double_abs(t->expect) <= width) /* lies within range */ - { - t->expect = i; - t->onbeat = 1; - if (t->points > 0) - t->points += 4; /* add 4 points */ - } - else if(t->expect < 0) - { - t->points -= 8; - t->expect = i; - } - if (t->points < 0) t->points = 0; else - if (t->points > 200) t->points = 200; - if (t->points > points) - { - points = t->points; - period = i; - } - } - - - - x->x_beat_period = (double)period; - t = &(x->x_beats[period]); - x->x_beatexpect = now + (double)t->expect; - x->x_on_beat = t->onbeat; - -time: - x->x_lastlasttime = x->x_lasttime; - x->x_lasttime = x->x_this_input; //now; - x->x_last_input = now; - - if(x->x_on_beat)outlet_bang(x->x_outbeat); - outvalue = (t_float)beat_evaluate(x); - outlet_float(x->x_outms, outvalue); - if(x->x_beat_period)outlet_float(x->x_outbpm, (t_float)(60000.0 / outvalue)); - } - return; -} - -static void beat_ft1(t_beat *x, t_floatarg f) -{ - x->x_velo = (t_int)f; -} - - /* toggle printing on/off */ -static void beat_print(t_beat *x) -{ - if(x->x_print)x->x_print = 0; - else x->x_print = 1; -} - -static void beat_reset(t_beat *x) -{ - int i; - - for(i = 0; i < BEAT_LONG; i++) - { - x->x_beats[i].points = 0; - x->x_beats[i].expect = i; - x->x_beats[i].onbeat = 0; - } - x->x_lastlasttime = 0; - x->x_lasttime = 0; - x->x_num_beats = 0; - x->x_beat_period = 0; - x->x_on_beat = 0; -} - -static t_class *beat_class; - -static void beat_free(t_beat *x) -{ - /* nothing to do */ -} - -static void *beat_new(t_floatarg f) -{ - t_beat *x = (t_beat *)pd_new(beat_class); - inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); - x->x_outbpm = outlet_new(&x->x_ob, gensym("float")); - x->x_outms = outlet_new(&x->x_ob, gensym("float")); - x->x_outbeat = outlet_new(&x->x_ob, gensym("bang")); - - beat_reset(x); - x->x_band_percent = 4; /* allow 4% 'jitter' by default */ - if(f)x->x_band_percent = (t_int)f; - - post("beat: band percentage set to %d", x->x_band_percent); - - return (void *)x; -} - -#ifndef MAXLIB -void beat_setup(void) -{ - beat_class = class_new(gensym("beat"), (t_newmethod)beat_new, - (t_method)beat_free, sizeof(t_beat), 0, A_DEFFLOAT, 0); -#else -void maxlib_beat_setup(void) -{ - beat_class = class_new(gensym("maxlib_beat"), (t_newmethod)beat_new, - (t_method)beat_free, sizeof(t_beat), 0, A_DEFFLOAT, 0); -#endif - class_addfloat(beat_class, beat_float); - class_addmethod(beat_class, (t_method)beat_ft1, gensym("ft1"), A_FLOAT, 0); - class_addmethod(beat_class, (t_method)beat_reset, gensym("reset"), 0); - class_addmethod(beat_class, (t_method)beat_print, gensym("print"), 0); -#ifndef MAXLIB - - post(version); -#else - class_addcreator((t_newmethod)beat_new, gensym("beat"), A_DEFFLOAT, 0); - class_sethelpsymbol(beat_class, gensym("maxlib/beat-help.pd")); -#endif -} - +/* --------------------------- beat ------------------------------------------ */ +/* */ +/* Detect the beats per minute of a MIDI stream. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Based on code written by Robert Rowe. */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include +#include +#include + +#define BEAT_LONG 1500 /* longest time we take into concideration (40 bpm) */ +#define BEAT_SHORT 300 /* shortest time we take into concideration (200 bpm) */ + +static char *version = "beat v0.1, written by Olaf Matthes "; + +typedef struct +{ + t_int points; /* number of points assigned to this theory */ + double expect; /* time of next expected hit */ + t_int onbeat; /* whether (1) or not (0) it was on the beat */ +} beat_theory; + +typedef struct /* used for sorting theories */ +{ + t_int points; + t_int theory; +} beat_sort_record; + + +typedef struct beat +{ + t_object x_ob; + t_clock *x_clock; + t_outlet *x_outbpm; /* beat as MIDI note number */ + t_outlet *x_outms; /* beat in milliseconds */ + t_outlet *x_outbeat; /* send a bang whenever beat is 'on beat' */ + t_int x_print; /* switch printing to console window on / off */ + + t_int x_num_beats; /* number of beats we've received */ + double x_beat_period; /* time in ms until next expected beat / beat pulse */ + beat_theory x_beats[BEAT_LONG]; + double x_beatexpect; /* expected time for next beat */ + t_int x_on_beat; /* indicate if last event was on beat */ + t_int x_band_percent; + + t_int x_pitch; + t_int x_velo; + /* helpers needed to do the time calculations */ + double x_this_input; + double x_last_input; + double x_lasttime; + double x_lastlasttime; +} t_beat; + +/* ---------------- mathematical functions to work with doubles -------------- */ +static double double_abs(double value) +{ + if(value < 0) + return (value * -1); + else + return (value); +} + +/* --------------- beat stuff ------------------------------------------------ */ + /* evaluate results: find theory that is the most likely one and + print out internal data to console window if print is enabled */ +static int beat_evaluate(t_beat *x) +{ + int i, j, K; + char string[256]; + char info[40]; + beat_sort_record theories[BEAT_LONG], *sortp, R; + int value; /* the result of the sorting */ + + for (i = 0; i < BEAT_LONG; i++) + { /* prepare sort records */ + sortp = &(theories[i]); + sortp->points = x->x_beats[i].points; + sortp->theory = i; + } + for (j = 2; j < BEAT_LONG; j++) + { /* sort */ + i = j - 1; + K = theories[j].points; + R = theories[j]; + while (i > 0) + { + if (K >= theories[i].points) + { + theories[i+1] = R; + break; + } + else + { + theories[i+1] = theories[i]; + i -= 1; + } + } + if (i==0) theories[i+1] = R; + } + /* get leading result */ + sortp = &(theories[BEAT_LONG - 1]); + value = sortp->theory; /* get our resulting theory */ + + if(x->x_print) + { + post(" 0 1 2 3 4 R E"); + *string = '\0'; /* print out five leading theories */ + sprintf(info, "%4g", x->x_this_input); + strcat(string, info); + for(i = 1; i < 6; i++) + { + sortp = &(theories[BEAT_LONG - i]); + sprintf(info, " %4d[%3d]", (int) sortp->theory, (int) sortp->points); + strcat(string, info); + } + sprintf(info, " %g %g", clock_getlogicaltime(), x->x_beatexpect); + strcat(string, info); + post(string); + } + + return value; +} + + /* reduce duration to fit into our processing window */ + /* some sort of 'double modulo'... */ +static double beat_reduce_offset(double duration) +{ + double temp = duration; + int divisor = 2; /* first try dividing by two */ + while (temp > BEAT_LONG) /* while duration is too long */ + temp = duration / divisor++; /* divide by progressively higher divisors */ + return temp; /* return a value in bounds */ +} + +/* + * beat_eligible: determine whether an event is eligible for consideration + * as a beat theory + */ +static int beat_eligible(double candidate, int* offsets, int num_offsets) +{ + double diff; + int i; + + if (candidate >= BEAT_LONG) /* if too long try subharmonics */ + candidate = beat_reduce_offset(candidate); + + /* if candidate is close to one already found */ + for(i = 0; i < num_offsets; i++) + { + diff = double_abs((candidate - offsets[i])); + if (diff < offsets[i]/20) { + if (candidate > offsets[i]) + ++offsets[i]; else /* pull existing one */ + if (candidate < offsets[i]) /* toward new candidate */ + --offsets[i]; + return 0; /* declare candidate ineligible */ + } + } + return candidate; /* otherwise return legal candidate */ +} + +static void beat_float(t_beat *x, t_floatarg f) +{ + t_int velo = x->x_velo; + int i, j, indx; + int num_offsets, candidate; + int low_limit, high_limit, width, deviation; + int points, band, center_offset, period; + beat_theory* t; + int offsets[7]; + static int factors[10] = + { 200, 50, 300, 150, 66, 400, 600, 133, 33, 75 }; + double now = clock_getlogicaltime(); + t_float outvalue; + + x->x_pitch = (t_int)f; + x->x_this_input = clock_gettimesince(x->x_last_input); + + if(velo != 0) /* note-on received */ + { + if(++x->x_num_beats == 1) + { + goto time; /* only one event, no beats yet */ + } + + num_offsets = 0; + candidate = beat_eligible(x->x_this_input, offsets, num_offsets); + if(candidate) + offsets[num_offsets++] = candidate; /* offset[0] set to incoming offset */ + + if(x->x_num_beats > 2) + { /* if three events */ + /* check previous for eligibility */ + candidate = beat_eligible(x->x_lasttime, offsets, num_offsets); + if (candidate) + offsets[num_offsets++] = candidate; + candidate = x->x_this_input + x->x_lasttime; /* add current and previous offsets */ + candidate = beat_eligible(candidate, offsets, num_offsets); + if (candidate) /* add to list if eligible */ + offsets[num_offsets++] = candidate; + } + + if(x->x_num_beats > 3) + { + candidate = beat_eligible(x->x_lastlasttime, offsets, num_offsets); + if (candidate) + offsets[num_offsets++] = candidate; + candidate += x->x_lasttime; + candidate = beat_eligible(candidate, offsets, num_offsets); + if (candidate) + offsets[num_offsets++] = candidate; + } + + indx = 0; + for(i = num_offsets; i < 7; i++) + { + offsets[i] = 0; + if (indx >= 10) break; + candidate = 0; + while ((indx < 10) && (!candidate)) + candidate = beat_eligible((x->x_this_input * factors[indx++])/100, offsets, num_offsets); + if (candidate) + offsets[num_offsets++] = candidate; + } + + for(i = 0; i < num_offsets; i++) + { + band = offsets[i] * x->x_band_percent / 100; + if ((low_limit = offsets[i] - band) < 0) /* add points in a critical band */ + low_limit = 0; /* around calculated offset */ + if ((high_limit = offsets[i] + band) > BEAT_LONG) + high_limit = BEAT_LONG; + center_offset = offsets[i]; /* midpoint of increment */ + points = 0; + for (j = low_limit; j < high_limit; j++) + { + if ((points = x->x_beats[j].points) > 0) + { /* if there is already activation */ + deviation = j - center_offset; /* record deviation from midpoint */ + x->x_beats[j].points = 0; + if (deviation < 0) { /* if there is activation below midpoint */ + t = &(x->x_beats[j+1]); /* take theory one above prior */ + } else + if (deviation > 0) { /* if there is activation above midpoint */ + t = &(x->x_beats[j-1]); /* take theory one below prior */ + } else + t = &(x->x_beats[j]); /* landed right on it */ + t->points = points + (num_offsets-i); + break; + } + } + if (!points) + x->x_beats[center_offset].points = num_offsets - i; + } + + /* boost hits, and suppress theories with missed beats */ + period = 0; + points = 0; + for (i = BEAT_SHORT; i < BEAT_LONG; i++) + { + t = &(x->x_beats[i]); + width = 5 > (t->expect / 7) ? 5 : (t->expect / 7); + t->expect -= x->x_this_input; + t->onbeat = 0; + if(double_abs(t->expect) <= width) /* lies within range */ + { + t->expect = i; + t->onbeat = 1; + if (t->points > 0) + t->points += 4; /* add 4 points */ + } + else if(t->expect < 0) + { + t->points -= 8; + t->expect = i; + } + if (t->points < 0) t->points = 0; else + if (t->points > 200) t->points = 200; + if (t->points > points) + { + points = t->points; + period = i; + } + } + + + + x->x_beat_period = (double)period; + t = &(x->x_beats[period]); + x->x_beatexpect = now + (double)t->expect; + x->x_on_beat = t->onbeat; + +time: + x->x_lastlasttime = x->x_lasttime; + x->x_lasttime = x->x_this_input; //now; + x->x_last_input = now; + + if(x->x_on_beat)outlet_bang(x->x_outbeat); + outvalue = (t_float)beat_evaluate(x); + outlet_float(x->x_outms, outvalue); + if(x->x_beat_period)outlet_float(x->x_outbpm, (t_float)(60000.0 / outvalue)); + } + return; +} + +static void beat_ft1(t_beat *x, t_floatarg f) +{ + x->x_velo = (t_int)f; +} + + /* toggle printing on/off */ +static void beat_print(t_beat *x) +{ + if(x->x_print)x->x_print = 0; + else x->x_print = 1; +} + +static void beat_reset(t_beat *x) +{ + int i; + + for(i = 0; i < BEAT_LONG; i++) + { + x->x_beats[i].points = 0; + x->x_beats[i].expect = i; + x->x_beats[i].onbeat = 0; + } + x->x_lastlasttime = 0; + x->x_lasttime = 0; + x->x_num_beats = 0; + x->x_beat_period = 0; + x->x_on_beat = 0; +} + +static t_class *beat_class; + +static void beat_free(t_beat *x) +{ + /* nothing to do */ +} + +static void *beat_new(t_floatarg f) +{ + t_beat *x = (t_beat *)pd_new(beat_class); + inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); + x->x_outbpm = outlet_new(&x->x_ob, gensym("float")); + x->x_outms = outlet_new(&x->x_ob, gensym("float")); + x->x_outbeat = outlet_new(&x->x_ob, gensym("bang")); + + beat_reset(x); + x->x_band_percent = 4; /* allow 4% 'jitter' by default */ + if(f)x->x_band_percent = (t_int)f; + + post("beat: band percentage set to %d", x->x_band_percent); + + return (void *)x; +} + +#ifndef MAXLIB +void beat_setup(void) +{ + beat_class = class_new(gensym("beat"), (t_newmethod)beat_new, + (t_method)beat_free, sizeof(t_beat), 0, A_DEFFLOAT, 0); +#else +void maxlib_beat_setup(void) +{ + beat_class = class_new(gensym("maxlib_beat"), (t_newmethod)beat_new, + (t_method)beat_free, sizeof(t_beat), 0, A_DEFFLOAT, 0); +#endif + class_addfloat(beat_class, beat_float); + class_addmethod(beat_class, (t_method)beat_ft1, gensym("ft1"), A_FLOAT, 0); + class_addmethod(beat_class, (t_method)beat_reset, gensym("reset"), 0); + class_addmethod(beat_class, (t_method)beat_print, gensym("print"), 0); +#ifndef MAXLIB + + logpost(NULL, 4, version); +#else + class_addcreator((t_newmethod)beat_new, gensym("beat"), A_DEFFLOAT, 0); + class_sethelpsymbol(beat_class, gensym("maxlib/beat-help.pd")); +#endif +} + diff --git a/beta.c b/beta.c index c99b538..2d7f3b3 100644 --- a/beta.c +++ b/beta.c @@ -1,107 +1,107 @@ -/* ---------------------------- rand_beta ------------------------------------- */ -/* */ -/* rand_beta generates a beta distributed random variable. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Based on code found in Dodge/Jerse "Computer Music" */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include -#include -#include - -#define fran() (t_float)rand()/(t_float)RAND_MAX -#ifndef M_PI -#define M_PI 3.1415927 -#endif - -static char *version = "beta v0.1, generates a beta distributed random variable\n" - " written by Olaf Matthes "; - -/* -------------------------- rand_beta ------------------------------ */ - -static t_class *rand_beta_class; - -typedef struct _rand_beta -{ - t_object x_obj; - t_float x_a; - t_float x_b; -} t_rand_beta; - -static void *rand_beta_new(t_floatarg a, t_floatarg b) -{ - t_rand_beta *x = (t_rand_beta *)pd_new(rand_beta_class); - srand( (unsigned)time( NULL ) ); - floatinlet_new(&x->x_obj, &x->x_a); - floatinlet_new(&x->x_obj, &x->x_b); - outlet_new(&x->x_obj, &s_float); - x->x_a = a; - x->x_b = b; - return (x); -} - -static void rand_beta_bang(t_rand_beta *x) -{ - t_float u1, u2, y01, y2, sum, a, b, ainv, binv; - a = (x->x_a <= 0 ? 0.0001 : x->x_a); - b = (x->x_b <= 0 ? 0.0001 : x->x_b); - ainv = 1/a; - binv = 1/b; - do - { - do - { - u1 = fran(); - } - while(u1 == 0); - do - { - u2 = fran(); - } - while(u2 == 0); - y01 = pow(u1, ainv); - y2 = pow(u2, binv); - sum = y01 + y2; - } - while(sum > 1); - outlet_float(x->x_obj.ob_outlet, y01/sum); -} - -#ifndef MAXLIB -void beta_setup(void) -{ - rand_beta_class = class_new(gensym("beta"), (t_newmethod)rand_beta_new, 0, - sizeof(t_rand_beta), 0, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addbang(rand_beta_class, rand_beta_bang); - class_sethelpsymbol(rand_beta_class, gensym("beta-help.pd")); - post(version); -} -#else -void maxlib_beta_setup(void) -{ - rand_beta_class = class_new(gensym("maxlib_beta"), (t_newmethod)rand_beta_new, 0, - sizeof(t_rand_beta), 0, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addbang(rand_beta_class, rand_beta_bang); - class_addcreator((t_newmethod)rand_beta_new, gensym("beta"), A_DEFFLOAT, A_DEFFLOAT, 0); - class_sethelpsymbol(rand_beta_class, gensym("maxlib/beta-help.pd")); -} -#endif +/* ---------------------------- rand_beta ------------------------------------- */ +/* */ +/* rand_beta generates a beta distributed random variable. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Based on code found in Dodge/Jerse "Computer Music" */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include +#include +#include + +#define fran() (t_float)rand()/(t_float)RAND_MAX +#ifndef M_PI +#define M_PI 3.1415927 +#endif + +static char *version = "beta v0.1, generates a beta distributed random variable\n" + " written by Olaf Matthes "; + +/* -------------------------- rand_beta ------------------------------ */ + +static t_class *rand_beta_class; + +typedef struct _rand_beta +{ + t_object x_obj; + t_float x_a; + t_float x_b; +} t_rand_beta; + +static void *rand_beta_new(t_floatarg a, t_floatarg b) +{ + t_rand_beta *x = (t_rand_beta *)pd_new(rand_beta_class); + srand( (unsigned)time( NULL ) ); + floatinlet_new(&x->x_obj, &x->x_a); + floatinlet_new(&x->x_obj, &x->x_b); + outlet_new(&x->x_obj, &s_float); + x->x_a = a; + x->x_b = b; + return (x); +} + +static void rand_beta_bang(t_rand_beta *x) +{ + t_float u1, u2, y01, y2, sum, a, b, ainv, binv; + a = (x->x_a <= 0 ? 0.0001 : x->x_a); + b = (x->x_b <= 0 ? 0.0001 : x->x_b); + ainv = 1/a; + binv = 1/b; + do + { + do + { + u1 = fran(); + } + while(u1 == 0); + do + { + u2 = fran(); + } + while(u2 == 0); + y01 = pow(u1, ainv); + y2 = pow(u2, binv); + sum = y01 + y2; + } + while(sum > 1); + outlet_float(x->x_obj.ob_outlet, y01/sum); +} + +#ifndef MAXLIB +void beta_setup(void) +{ + rand_beta_class = class_new(gensym("beta"), (t_newmethod)rand_beta_new, 0, + sizeof(t_rand_beta), 0, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addbang(rand_beta_class, rand_beta_bang); + class_sethelpsymbol(rand_beta_class, gensym("beta-help.pd")); + logpost(NULL, 4, version); +} +#else +void maxlib_beta_setup(void) +{ + rand_beta_class = class_new(gensym("maxlib_beta"), (t_newmethod)rand_beta_new, 0, + sizeof(t_rand_beta), 0, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addbang(rand_beta_class, rand_beta_bang); + class_addcreator((t_newmethod)rand_beta_new, gensym("beta"), A_DEFFLOAT, A_DEFFLOAT, 0); + class_sethelpsymbol(rand_beta_class, gensym("maxlib/beta-help.pd")); +} +#endif diff --git a/bilex.c b/bilex.c index eb54aa4..6bd432e 100644 --- a/bilex.c +++ b/bilex.c @@ -1,91 +1,91 @@ -/* ---------------------------- rand_bilex ------------------------------------ */ -/* */ -/* rand_bilex generates a bilinear exponentially distributed random variable. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Based on code found in Dodge/Jerse "Computer Music" */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ +/* ---------------------------- rand_bilex ------------------------------------ */ +/* */ +/* rand_bilex generates a bilinear exponentially distributed random variable. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Based on code found in Dodge/Jerse "Computer Music" */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ #include "m_pd.h" -#include -#include -#include - -#define fran() (t_float)rand()/(t_float)RAND_MAX +#include +#include +#include -static char *version = "bilex v0.1, generates bilinear exponentially distributed random\n" - " variable, written by Olaf Matthes "; +#define fran() (t_float)rand()/(t_float)RAND_MAX -/* -------------------------- rand_bilex ------------------------------ */ - -static t_class *rand_bilex_class; - -typedef struct _rand_bilex -{ - t_object x_obj; - t_float x_lambda; -} t_rand_bilex; - -static void *rand_bilex_new(t_floatarg f) -{ - t_rand_bilex *x = (t_rand_bilex *)pd_new(rand_bilex_class); - srand( (unsigned)time( NULL ) ); - floatinlet_new(&x->x_obj, &x->x_lambda); - outlet_new(&x->x_obj, &s_float); - x->x_lambda = f; - return (x); -} - -static void rand_bilex_bang(t_rand_bilex *x) -{ - t_float u, s = 1, l; - l = (x->x_lambda <= 0 ? 0.0001 : x->x_lambda); - do - { - u = 2*fran(); - } - while(u == 0 || u == 2); - if(u > 1) - { - u = 2-u; - s=-1; - } - outlet_float(x->x_obj.ob_outlet, s*log(u)/l); -} - -#ifndef MAXLIB -void bilex_setup(void) -{ - rand_bilex_class = class_new(gensym("bilex"), (t_newmethod)rand_bilex_new, 0, - sizeof(t_rand_bilex), 0, A_DEFFLOAT, 0); - class_addbang(rand_bilex_class, rand_bilex_bang); - class_sethelpsymbol(rand_bilex_class, gensym("bilex-help.pd")); - post(version); -} -#else -void maxlib_bilex_setup(void) -{ - rand_bilex_class = class_new(gensym("maxlib_bilex"), (t_newmethod)rand_bilex_new, 0, - sizeof(t_rand_bilex), 0, A_DEFFLOAT, 0); - class_addbang(rand_bilex_class, rand_bilex_bang); - class_addcreator((t_newmethod)rand_bilex_new, gensym("bilex"), A_DEFFLOAT, 0); - class_sethelpsymbol(rand_bilex_class, gensym("maxlib/bilex-help.pd")); -} -#endif +static char *version = "bilex v0.1, generates bilinear exponentially distributed random\n" + " variable, written by Olaf Matthes "; + +/* -------------------------- rand_bilex ------------------------------ */ + +static t_class *rand_bilex_class; + +typedef struct _rand_bilex +{ + t_object x_obj; + t_float x_lambda; +} t_rand_bilex; + +static void *rand_bilex_new(t_floatarg f) +{ + t_rand_bilex *x = (t_rand_bilex *)pd_new(rand_bilex_class); + srand( (unsigned)time( NULL ) ); + floatinlet_new(&x->x_obj, &x->x_lambda); + outlet_new(&x->x_obj, &s_float); + x->x_lambda = f; + return (x); +} + +static void rand_bilex_bang(t_rand_bilex *x) +{ + t_float u, s = 1, l; + l = (x->x_lambda <= 0 ? 0.0001 : x->x_lambda); + do + { + u = 2*fran(); + } + while(u == 0 || u == 2); + if(u > 1) + { + u = 2-u; + s=-1; + } + outlet_float(x->x_obj.ob_outlet, s*log(u)/l); +} + +#ifndef MAXLIB +void bilex_setup(void) +{ + rand_bilex_class = class_new(gensym("bilex"), (t_newmethod)rand_bilex_new, 0, + sizeof(t_rand_bilex), 0, A_DEFFLOAT, 0); + class_addbang(rand_bilex_class, rand_bilex_bang); + class_sethelpsymbol(rand_bilex_class, gensym("bilex-help.pd")); + logpost(NULL, 4, version); +} +#else +void maxlib_bilex_setup(void) +{ + rand_bilex_class = class_new(gensym("maxlib_bilex"), (t_newmethod)rand_bilex_new, 0, + sizeof(t_rand_bilex), 0, A_DEFFLOAT, 0); + class_addbang(rand_bilex_class, rand_bilex_bang); + class_addcreator((t_newmethod)rand_bilex_new, gensym("bilex"), A_DEFFLOAT, 0); + class_sethelpsymbol(rand_bilex_class, gensym("maxlib/bilex-help.pd")); +} +#endif diff --git a/borax.c b/borax.c index 32979b7..fc271bf 100644 --- a/borax.c +++ b/borax.c @@ -1,238 +1,238 @@ -/* ------------------------- borax ------------------------------------------ */ -/* */ -/* "swiss army knife" for music analysis. Inspired by 'borax' for Max. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" - -#define MAX_POLY 128 /* maximum number of notes played at a time */ - -static char *version = "borax v0.1, written by Olaf Matthes "; - -typedef struct borax -{ - t_object x_ob; - t_inlet *x_invelo; /* inlet for velocity */ - t_inlet *x_inreset; /* inlet to reset the object */ - t_outlet *x_outnotecount; /* counts notes */ - t_outlet *x_outvoicealloc; /* assigns every note a unique number */ - t_outlet *x_outpoly; /* number of notes playing (polyphony) */ - t_outlet *x_outpitch; /* pitch of current note */ - t_outlet *x_outvelo; /* velocity of current note */ - t_outlet *x_outdurcount; /* number assigned to duration value */ - t_outlet *x_outdurval; /* duration value */ - t_outlet *x_outtimecount; /* number assigned to delta time value */ - t_outlet *x_outtimeval; /* delta time value */ - - - t_float x_notecount; - t_int x_pitch; - t_int x_velo; - t_float x_voicecount; - t_int x_voicealloc; - t_int x_poly; - t_float x_durcount; - t_float x_durval; - t_float x_timecount; - t_float x_timeval; - /* helpers needed to do the calculations */ - double x_starttime[MAX_POLY]; - double x_laststarttime; - t_int x_alloctable[MAX_POLY]; - -} t_borax; - -static void borax_float(t_borax *x, t_floatarg f) -{ - t_int velo = x->x_velo; - t_int allloc = 0; - int i; - - x->x_pitch = (t_int)f; - - if(velo == 0) - { - /* note off received... */ - if(x->x_poly > 0)x->x_poly--; /* polyphony has decreased by one */ - x->x_durcount++; /* we can calculate the duration */ - for(i = 0; i < MAX_POLY; i++) /* search for voice allocation number */ - { - /* search for corresponding alloc number */ - if(x->x_alloctable[i] == x->x_pitch) - { - x->x_voicealloc = i; - x->x_alloctable[i] = 0; /* free the alloc number */ - break; - } - /* couldn't find it ? */ - if(i == MAX_POLY - 1) - { - post("borax: no corresponding note-on found (ignored)"); - return; - } - } - x->x_durval = clock_gettimesince(x->x_starttime[x->x_voicealloc]); - } - else if(velo != 0) - { - /* note on received... */ - x->x_poly++; /* number of currently playing notes has increased */ - x->x_notecount++; /* total number of notes has increased */ - /* assign a voice allocation number */ - for(i = 0; i < MAX_POLY; i++) - { - /* search for free alloc number */ - if(x->x_alloctable[i] == 0) - { - x->x_voicealloc = i; /* take the number */ - x->x_alloctable[i] = x->x_pitch; /* ... and store pitch */ - break; - } - /* couldn't find any ? */ - if(i == MAX_POLY - 1) - { - post("borax: too many note-on messages (ignored)"); - return; - } - } - /* calculate time in case it's not the first note */ - if(x->x_notecount > 1) - { - x->x_timecount++; - x->x_timeval = clock_gettimesince(x->x_laststarttime); - } - /* save the new start time */ - x->x_laststarttime = x->x_starttime[x->x_voicealloc] = clock_getlogicaltime(); - } - /* output values from right to left */ - outlet_float(x->x_outtimeval, x->x_timeval); - outlet_float(x->x_outtimecount, x->x_timecount); - outlet_float(x->x_outdurval, x->x_durval); - outlet_float(x->x_outdurcount, x->x_durcount); - outlet_float(x->x_outvelo, velo); - outlet_float(x->x_outpitch, x->x_pitch); - outlet_float(x->x_outpoly, x->x_poly); - outlet_float(x->x_outvoicealloc, x->x_voicealloc); - outlet_float(x->x_outnotecount, x->x_notecount); -} - -static void borax_ft1(t_borax *x, t_floatarg f) -{ - x->x_velo = (t_int)f; -} - -static void borax_reset(t_borax *x) -{ - int i; - post("borax: reset"); - x->x_notecount = 0; - x->x_pitch = 0; - x->x_velo = 0; - x->x_voicecount = 0; - x->x_voicealloc = 0; - x->x_poly = 0; - x->x_durcount = 0; - x->x_durval = 0; - x->x_timecount = 0; - x->x_timeval = 0; - outlet_float(x->x_outtimeval, x->x_timeval); - outlet_float(x->x_outtimecount, x->x_timecount); - outlet_float(x->x_outdurval, x->x_durval); - outlet_float(x->x_outdurcount, x->x_durcount); - for(i = 0; i < MAX_POLY; i++) - { - if(x->x_alloctable[i] != 0) - { - x->x_poly--; - /* send note-off */ - outlet_float(x->x_outvelo, 0); - outlet_float(x->x_outpitch, x->x_alloctable[i]); - outlet_float(x->x_outpoly, x->x_poly); - outlet_float(x->x_outvoicealloc, i); - } - x->x_alloctable[i] = 0; - } - outlet_float(x->x_outvelo, x->x_velo); - outlet_float(x->x_outpitch, x->x_pitch); - outlet_float(x->x_outpoly, x->x_poly); - outlet_float(x->x_outvoicealloc, x->x_voicealloc); - outlet_float(x->x_outnotecount, x->x_notecount); -} - -static t_class *borax_class; - -static void *borax_new(void) -{ - int i; - - t_borax *x = (t_borax *)pd_new(borax_class); - x->x_invelo = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); - x->x_inreset = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("bang"), gensym("ft2")); - x->x_outnotecount = outlet_new(&x->x_ob, gensym("float")); - x->x_outvoicealloc = outlet_new(&x->x_ob, gensym("float")); - x->x_outpoly = outlet_new(&x->x_ob, gensym("float")); - x->x_outpitch = outlet_new(&x->x_ob, gensym("float")); - x->x_outvelo = outlet_new(&x->x_ob, gensym("float")); - x->x_outdurcount = outlet_new(&x->x_ob, gensym("float")); - x->x_outdurval = outlet_new(&x->x_ob, gensym("float")); - x->x_outtimecount = outlet_new(&x->x_ob, gensym("float")); - x->x_outtimeval = outlet_new(&x->x_ob, gensym("float")); - - for(i = 0; i < MAX_POLY; i++)x->x_alloctable[i] = 0; - x->x_notecount = 0; - x->x_pitch = 0; - x->x_velo = 0; - x->x_voicecount = 0; - x->x_voicealloc = 0; - x->x_poly = 0; - x->x_durcount = 0; - x->x_durval = 0; - x->x_timecount = 0; - x->x_timeval = 0; - - return (void *)x; -} - -#ifndef MAXLIB -void borax_setup(void) -{ - borax_class = class_new(gensym("borax"), (t_newmethod)borax_new, - 0, sizeof(t_borax), 0, 0); -#else -void maxlib_borax_setup(void) -{ - borax_class = class_new(gensym("maxlib_borax"), (t_newmethod)borax_new, - 0, sizeof(t_borax), 0, 0); -#endif - class_addmethod(borax_class, (t_method)borax_reset, gensym("reset"), 0); - class_addmethod(borax_class, (t_method)borax_ft1, gensym("ft1"), A_FLOAT, 0); - class_addmethod(borax_class, (t_method)borax_reset, gensym("ft2"), A_GIMME, 0); - class_addfloat(borax_class, borax_float); -#ifndef MAXLIB - - post(version); -#else - class_addcreator((t_newmethod)borax_new, gensym("borax"), 0); - class_sethelpsymbol(borax_class, gensym("maxlib/borax-help.pd")); -#endif -} - +/* ------------------------- borax ------------------------------------------ */ +/* */ +/* "swiss army knife" for music analysis. Inspired by 'borax' for Max. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" + +#define MAX_POLY 128 /* maximum number of notes played at a time */ + +static char *version = "borax v0.1, written by Olaf Matthes "; + +typedef struct borax +{ + t_object x_ob; + t_inlet *x_invelo; /* inlet for velocity */ + t_inlet *x_inreset; /* inlet to reset the object */ + t_outlet *x_outnotecount; /* counts notes */ + t_outlet *x_outvoicealloc; /* assigns every note a unique number */ + t_outlet *x_outpoly; /* number of notes playing (polyphony) */ + t_outlet *x_outpitch; /* pitch of current note */ + t_outlet *x_outvelo; /* velocity of current note */ + t_outlet *x_outdurcount; /* number assigned to duration value */ + t_outlet *x_outdurval; /* duration value */ + t_outlet *x_outtimecount; /* number assigned to delta time value */ + t_outlet *x_outtimeval; /* delta time value */ + + + t_float x_notecount; + t_int x_pitch; + t_int x_velo; + t_float x_voicecount; + t_int x_voicealloc; + t_int x_poly; + t_float x_durcount; + t_float x_durval; + t_float x_timecount; + t_float x_timeval; + /* helpers needed to do the calculations */ + double x_starttime[MAX_POLY]; + double x_laststarttime; + t_int x_alloctable[MAX_POLY]; + +} t_borax; + +static void borax_float(t_borax *x, t_floatarg f) +{ + t_int velo = x->x_velo; + t_int allloc = 0; + int i; + + x->x_pitch = (t_int)f; + + if(velo == 0) + { + /* note off received... */ + if(x->x_poly > 0)x->x_poly--; /* polyphony has decreased by one */ + x->x_durcount++; /* we can calculate the duration */ + for(i = 0; i < MAX_POLY; i++) /* search for voice allocation number */ + { + /* search for corresponding alloc number */ + if(x->x_alloctable[i] == x->x_pitch) + { + x->x_voicealloc = i; + x->x_alloctable[i] = 0; /* free the alloc number */ + break; + } + /* couldn't find it ? */ + if(i == MAX_POLY - 1) + { + post("borax: no corresponding note-on found (ignored)"); + return; + } + } + x->x_durval = clock_gettimesince(x->x_starttime[x->x_voicealloc]); + } + else if(velo != 0) + { + /* note on received... */ + x->x_poly++; /* number of currently playing notes has increased */ + x->x_notecount++; /* total number of notes has increased */ + /* assign a voice allocation number */ + for(i = 0; i < MAX_POLY; i++) + { + /* search for free alloc number */ + if(x->x_alloctable[i] == 0) + { + x->x_voicealloc = i; /* take the number */ + x->x_alloctable[i] = x->x_pitch; /* ... and store pitch */ + break; + } + /* couldn't find any ? */ + if(i == MAX_POLY - 1) + { + post("borax: too many note-on messages (ignored)"); + return; + } + } + /* calculate time in case it's not the first note */ + if(x->x_notecount > 1) + { + x->x_timecount++; + x->x_timeval = clock_gettimesince(x->x_laststarttime); + } + /* save the new start time */ + x->x_laststarttime = x->x_starttime[x->x_voicealloc] = clock_getlogicaltime(); + } + /* output values from right to left */ + outlet_float(x->x_outtimeval, x->x_timeval); + outlet_float(x->x_outtimecount, x->x_timecount); + outlet_float(x->x_outdurval, x->x_durval); + outlet_float(x->x_outdurcount, x->x_durcount); + outlet_float(x->x_outvelo, velo); + outlet_float(x->x_outpitch, x->x_pitch); + outlet_float(x->x_outpoly, x->x_poly); + outlet_float(x->x_outvoicealloc, x->x_voicealloc); + outlet_float(x->x_outnotecount, x->x_notecount); +} + +static void borax_ft1(t_borax *x, t_floatarg f) +{ + x->x_velo = (t_int)f; +} + +static void borax_reset(t_borax *x) +{ + int i; + post("borax: reset"); + x->x_notecount = 0; + x->x_pitch = 0; + x->x_velo = 0; + x->x_voicecount = 0; + x->x_voicealloc = 0; + x->x_poly = 0; + x->x_durcount = 0; + x->x_durval = 0; + x->x_timecount = 0; + x->x_timeval = 0; + outlet_float(x->x_outtimeval, x->x_timeval); + outlet_float(x->x_outtimecount, x->x_timecount); + outlet_float(x->x_outdurval, x->x_durval); + outlet_float(x->x_outdurcount, x->x_durcount); + for(i = 0; i < MAX_POLY; i++) + { + if(x->x_alloctable[i] != 0) + { + x->x_poly--; + /* send note-off */ + outlet_float(x->x_outvelo, 0); + outlet_float(x->x_outpitch, x->x_alloctable[i]); + outlet_float(x->x_outpoly, x->x_poly); + outlet_float(x->x_outvoicealloc, i); + } + x->x_alloctable[i] = 0; + } + outlet_float(x->x_outvelo, x->x_velo); + outlet_float(x->x_outpitch, x->x_pitch); + outlet_float(x->x_outpoly, x->x_poly); + outlet_float(x->x_outvoicealloc, x->x_voicealloc); + outlet_float(x->x_outnotecount, x->x_notecount); +} + +static t_class *borax_class; + +static void *borax_new(void) +{ + int i; + + t_borax *x = (t_borax *)pd_new(borax_class); + x->x_invelo = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); + x->x_inreset = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("bang"), gensym("ft2")); + x->x_outnotecount = outlet_new(&x->x_ob, gensym("float")); + x->x_outvoicealloc = outlet_new(&x->x_ob, gensym("float")); + x->x_outpoly = outlet_new(&x->x_ob, gensym("float")); + x->x_outpitch = outlet_new(&x->x_ob, gensym("float")); + x->x_outvelo = outlet_new(&x->x_ob, gensym("float")); + x->x_outdurcount = outlet_new(&x->x_ob, gensym("float")); + x->x_outdurval = outlet_new(&x->x_ob, gensym("float")); + x->x_outtimecount = outlet_new(&x->x_ob, gensym("float")); + x->x_outtimeval = outlet_new(&x->x_ob, gensym("float")); + + for(i = 0; i < MAX_POLY; i++)x->x_alloctable[i] = 0; + x->x_notecount = 0; + x->x_pitch = 0; + x->x_velo = 0; + x->x_voicecount = 0; + x->x_voicealloc = 0; + x->x_poly = 0; + x->x_durcount = 0; + x->x_durval = 0; + x->x_timecount = 0; + x->x_timeval = 0; + + return (void *)x; +} + +#ifndef MAXLIB +void borax_setup(void) +{ + borax_class = class_new(gensym("borax"), (t_newmethod)borax_new, + 0, sizeof(t_borax), 0, 0); +#else +void maxlib_borax_setup(void) +{ + borax_class = class_new(gensym("maxlib_borax"), (t_newmethod)borax_new, + 0, sizeof(t_borax), 0, 0); +#endif + class_addmethod(borax_class, (t_method)borax_reset, gensym("reset"), 0); + class_addmethod(borax_class, (t_method)borax_ft1, gensym("ft1"), A_FLOAT, 0); + class_addmethod(borax_class, (t_method)borax_reset, gensym("ft2"), A_GIMME, 0); + class_addfloat(borax_class, borax_float); +#ifndef MAXLIB + + logpost(NULL, 4, version); +#else + class_addcreator((t_newmethod)borax_new, gensym("borax"), 0); + class_sethelpsymbol(borax_class, gensym("maxlib/borax-help.pd")); +#endif +} + diff --git a/cauchy.c b/cauchy.c index ee64296..73fcfef 100644 --- a/cauchy.c +++ b/cauchy.c @@ -1,89 +1,89 @@ -/* ---------------------------- rand_cauchy ----------------------------------- */ -/* */ -/* rand_cauchy generates a Cauchy distributed random variable. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Based on code found in Dodge/Jerse "Computer Music" */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ +/* ---------------------------- rand_cauchy ----------------------------------- */ +/* */ +/* rand_cauchy generates a Cauchy distributed random variable. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Based on code found in Dodge/Jerse "Computer Music" */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ #include "m_pd.h" -#include -#include -#include - -#define fran() (t_float)rand()/(t_float)RAND_MAX -#ifndef M_PI -#define M_PI 3.1415927 -#endif +#include +#include +#include -static char *version = "cauchy v0.1, generates a Cauchy distributed random variable\n" - " with a spread governed by to parameter 'aplha',\n" - " written by Olaf Matthes "; +#define fran() (t_float)rand()/(t_float)RAND_MAX +#ifndef M_PI +#define M_PI 3.1415927 +#endif -/* -------------------------- rand_cauchy ------------------------------ */ - -static t_class *rand_cauchy_class; - -typedef struct _rand_cauchy -{ - t_object x_obj; - t_float x_alpha; -} t_rand_cauchy; - -static void *rand_cauchy_new(t_floatarg f) -{ - t_rand_cauchy *x = (t_rand_cauchy *)pd_new(rand_cauchy_class); - srand( (unsigned)time( NULL ) ); - floatinlet_new(&x->x_obj, &x->x_alpha); - outlet_new(&x->x_obj, &s_float); - x->x_alpha = f; - return (x); -} - -static void rand_cauchy_bang(t_rand_cauchy *x) -{ - t_float u; - do - { - u = fran(); - } - while(u == 0.5); - u *= M_PI; - outlet_float(x->x_obj.ob_outlet, x->x_alpha*tan(u)); -} - -#ifndef MAXLIB -void cauchy_setup(void) -{ - rand_cauchy_class = class_new(gensym("cauchy"), (t_newmethod)rand_cauchy_new, 0, - sizeof(t_rand_cauchy), 0, A_DEFFLOAT, 0); - class_addbang(rand_cauchy_class, rand_cauchy_bang); - class_sethelpsymbol(rand_cauchy_class, gensym("cauchy-help.pd")); - post(version); -#else -void maxlib_cauchy_setup(void) -{ - rand_cauchy_class = class_new(gensym("maxlib_cauchy"), (t_newmethod)rand_cauchy_new, 0, - sizeof(t_rand_cauchy), 0, A_DEFFLOAT, 0); - class_addbang(rand_cauchy_class, rand_cauchy_bang); - class_addcreator((t_newmethod)rand_cauchy_new, gensym("cauchy"), A_DEFFLOAT, 0); - class_sethelpsymbol(rand_cauchy_class, gensym("maxlib/cauchy-help.pd")); -#endif -} +static char *version = "cauchy v0.1, generates a Cauchy distributed random variable\n" + " with a spread governed by to parameter 'aplha',\n" + " written by Olaf Matthes "; + +/* -------------------------- rand_cauchy ------------------------------ */ + +static t_class *rand_cauchy_class; + +typedef struct _rand_cauchy +{ + t_object x_obj; + t_float x_alpha; +} t_rand_cauchy; + +static void *rand_cauchy_new(t_floatarg f) +{ + t_rand_cauchy *x = (t_rand_cauchy *)pd_new(rand_cauchy_class); + srand( (unsigned)time( NULL ) ); + floatinlet_new(&x->x_obj, &x->x_alpha); + outlet_new(&x->x_obj, &s_float); + x->x_alpha = f; + return (x); +} + +static void rand_cauchy_bang(t_rand_cauchy *x) +{ + t_float u; + do + { + u = fran(); + } + while(u == 0.5); + u *= M_PI; + outlet_float(x->x_obj.ob_outlet, x->x_alpha*tan(u)); +} + +#ifndef MAXLIB +void cauchy_setup(void) +{ + rand_cauchy_class = class_new(gensym("cauchy"), (t_newmethod)rand_cauchy_new, 0, + sizeof(t_rand_cauchy), 0, A_DEFFLOAT, 0); + class_addbang(rand_cauchy_class, rand_cauchy_bang); + class_sethelpsymbol(rand_cauchy_class, gensym("cauchy-help.pd")); + logpost(NULL, 4, version); +#else +void maxlib_cauchy_setup(void) +{ + rand_cauchy_class = class_new(gensym("maxlib_cauchy"), (t_newmethod)rand_cauchy_new, 0, + sizeof(t_rand_cauchy), 0, A_DEFFLOAT, 0); + class_addbang(rand_cauchy_class, rand_cauchy_bang); + class_addcreator((t_newmethod)rand_cauchy_new, gensym("cauchy"), A_DEFFLOAT, 0); + class_sethelpsymbol(rand_cauchy_class, gensym("maxlib/cauchy-help.pd")); +#endif +} diff --git a/chord.c b/chord.c index a1839d3..ad3f6eb 100644 --- a/chord.c +++ b/chord.c @@ -1,1822 +1,1822 @@ -/* ------------------------- chord ------------------------------------------ */ -/* */ -/* Tries to detect a chord (or any harmonic relations) of incoming notes. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include -#include -#ifndef _WIN32 -#include -#endif - - -#define MAX_POLY 32 /* maximum number of notes played at a time */ - -#define kUnison 0 -#define kMaj 1 -#define kMin 2 -#define kDim 3 -#define kAug 4 -#define kMaj7 5 -#define kDom7 6 -#define kMin7 7 -#define kHalfDim7 8 -#define kDim7 9 -#define kMinMaj7 10 -#define kMaj7s5 11 -#define kMaj7b5 12 -#define kDom7s5 13 -#define kDom7b5 14 -#define kDomb9 15 -#define kMaj9 16 -#define kDom9 17 -#define kMin9 18 -#define kHalfDim9 19 -#define kMinMaj9 20 -#define kDimMaj9 21 -#define kMaj9b5 22 -#define kDom9b5 23 -#define kDom9b13 24 -#define kMin9s11 25 -#define kmM9b11 26 -#define kMaj7b9 27 -#define kMaj7s5b9 28 -#define kDom7b9 29 -#define kMin7b9 30 -#define kMinb9s11 31 -#define kHalfDimb9 32 -#define kDim7b9 33 -#define kMinMajb9 34 -#define kDimMajb9 35 -#define kMaj7s9 36 -#define kDom7s9 37 -#define kMaj7s11 38 -#define kMs9s11 39 -#define kHDimb11 40 -#define kMaj11 41 -#define kDom11 42 -#define kMin11 43 -#define kHalfDim11 44 -#define kDim11 45 -#define kMinMaj11 46 -#define kDimMaj11 47 -#define kMaj11b5 48 -#define kMaj11s5 49 -#define kMaj11b9 50 -#define kMaj11s9 51 -#define kMaj11b13 52 -#define kMaj11s13 53 -#define kM11b5b9 54 -#define kDom11b5 55 -#define kDom11b9 56 -#define kDom11s9 57 -#define kHalfDim11b9 58 -#define kDom7s11 59 -#define kMin7s11 60 -#define kDom13s11 61 -#define kM7b913 62 -#define kMaj7s13 63 -#define kMaj9s13 64 -#define kM7b9s13 65 -#define kDom7b13 66 -#define kChrom 67 -#define kNone 68 - -#define kXX -1 - - -static char *version = "chord v0.2, written by Olaf Matthes "; - -static char* pitch_class[13] = {"C ", "Db ", "D ", "Eb ", "E ", "F ", "Gb ", "G ", "Ab ", "A ", "Bb ", "B ", "no root "}; -static char name_class[7] = {'C', 'D', 'E', 'F', 'G', 'A', 'B'}; - -typedef struct { - int type; - int rootMember; -} t_type_root; - -typedef struct chord -{ - t_object x_ob; - t_outlet *x_outchordval; /* chord as MIDI note number of base note */ - t_outlet *x_outchordclass; /* class of chord's bass note */ - t_outlet *x_outchordname; /* chord name, e.g. "Cmajor7" */ - t_outlet *x_outchordinversion; /* inversion of the chord (root = 0, 1st = 1, 2nd = 2) */ - t_outlet *x_outchordnotes; /* list with note numbers belonging to the chord */ - - t_int x_pitch; - t_int x_pc[12]; /* pitch class array */ - t_int x_abs_pc[12]; /* pitch class array: absolute MIDI note numbers */ - t_int x_velo; - t_int x_alloctable[MAX_POLY]; /* a table used to store all playing notes */ - t_int x_poly; /* number of notes currently playing */ - t_atom x_chordlist[12]; /* list that stores the note numbers for output */ - t_int x_split; /* highes note number to process */ - - t_int x_chord_type; /* chord's type (number between 0 and 68) */ - t_int x_chord_root; /* chord's root (pitch class) */ - t_int x_chord_bass; /* chord's bass note (MIDI note number) */ - t_int x_chord_inversion; /* chord's state of inversion (root, 1st, 2nd) */ - -} t_chord; - -/* functions */ -static void chord_kick_out_member(t_chord *x, t_int number, t_int *members); -static void chord_chord_finder(t_chord *x, t_int num_pcs); -static void chord_draw_chord_type(t_chord *x, t_int num_pcs); - - -static void chord_unison(t_chord *x) -{ - int i; - int member = 0; - for(i = 0; i < 12; i++) - if(x->x_pc[i]) - { - member = i; // find pitch class - break; - } - x->x_chord_type = 0; - x->x_chord_root = member; - chord_draw_chord_type(x, 1); // output onto the screen -} - -static void chord_dyad(t_chord *x) -{ - static t_type_root dyads[11] = - {{ kMaj7, 1 }, { kDom7, 1 }, { kMin, 0 }, { kMaj, 0 }, { kMaj, 1 }, - { kDom7 , 0 }, { kMaj, 0 }, { kMaj, 1 }, { kMin, 1 }, { kDom7, 0 }, { kMaj7, 0 }}; - register t_type_root* t; - - int members[2]; - int i, j = 0; - int interval1; - - for(i = 0; i < 12; i++) - if(x->x_pc[i]) members[j++] = i; /* load members array with chord pitch classes */ - interval1 = members[1] - members[0]; /* calculate interval between first two members */ - interval1 = interval1 - 1; /* reduce interval1 to start at zero */ - t = &(dyads[interval1]); /* find TypeRoot struct for this interval */ - x->x_chord_type = t->type; - if (interval1 == 5) - x->x_chord_root = (members[0]+8)%12; - else - x->x_chord_root = members[t->rootMember]; - x->x_chord_inversion = t->rootMember; /* get state of inversion */ - chord_draw_chord_type(x, 2); /* output results */ -} - -static void chord_triad(t_chord *x) -{ - static t_type_root triads[10][10] = - {/* interval1 is a half step */ - {{ kMaj7b9, 1 }, { kMaj9, 1 }, { kMinMaj7, 1 }, { kMaj7, 1 }, { kDom7s11,2 }, - { kDomb9 , 0 }, { kMaj7, 1 }, { kMaj7s5, 1 }, { kMin9, 2 }, { kMaj7b9, 0 }}, - /* interval1 is a whole step */ - {{ kMin9, 0 }, { kDom9, 0 }, { kMin7, 1 }, { kDom7, 1 }, { kDom9, 0 }, - { kHalfDim7, 1 }, { kDom7, 1 }, { kDom9, 0 }, { kMaj9, 0 }}, - /* interval1 is a minor third */ - {{ kMaj7s5, 2 }, { kDom7, 2 }, { kDim, 0 }, { kMin, 0 }, { kMaj, 2 }, - { kDim, 2 }, { kMin7, 0 }, { kMinMaj7, 0 }}, - /* interval1 is a major third */ - {{ kMaj7, 2 }, { kHalfDim7, 2 }, { kMaj, 0 }, { kAug, 0 }, { kMin, 2 }, - { kDom7, 0 }, { kMaj7, 0 }}, - /* interval1 is a perfect fourth */ - {{ kDomb9, 1 }, { kDom9, 1 }, { kMin, 1 }, { kMaj, 1 }, { kDom9, 2 }, - { kDom7s11, 1 }}, - /* interval1 is an augmented fourth */ - {{ kDom7s11, 0 }, { kDom7, 2 }, { kDim, 1 }, { kHalfDim7, 0 }, { kDomb9, 2 }}, - /* interval1 is a perfect fifth */ - {{ kMaj7, 2 }, { kMin7, 2 }, { kDom7, 0 }, { kMaj7, 0 }}, - /* interval1 is a minor sixth */ - {{ kMinMaj7, 2 }, { kDom9, 1 }, { kMaj7s5, 0 }}, - /* interval1 is a major sixth */ - {{ kMaj9, 2 }, { kMin9, 1 }}, - /* interval1 is a minor seventh */ - {{ kMaj7b9, 2 }} - }; - register t_type_root* t; - - int members[3]; - int i, j = 0; - int interval1, interval2; - - for(i = 0; i < 12; i++) - if(x->x_pc[i]) members[j++] = i; /* load members array with chord pitch classes */ - interval1 = members[1] - members[0]; /* calculate interval between first two members */ - interval2 = members[2] - members[0]; /* calculate interval between first and third */ - interval2 = interval2 - interval1 - 1; /* reduce interval2 to start at zero */ - interval1 = interval1 - 1; /* reduce interval1 to start at zero */ - t = &(triads[interval1][interval2]); /* find TypeRoot struct for this interval vector */ - x->x_chord_type = t->type; - x->x_chord_root = members[t->rootMember]; - switch(t->rootMember) { /* get state of inversion */ - case 0: - x->x_chord_inversion = 0; - break; - case 1: - x->x_chord_inversion = 2; - break; - case 2: - x->x_chord_inversion = 1; - } - chord_draw_chord_type(x, 3); /* output onto the screen */ -} - -static void chord_quartad(t_chord *x) -{ - static t_type_root quartads[9][9][9] = - { - {/* interval1 is a half step */ - {/* interval2 is a whole step */ - { kM7b9s13, 2 }, { kMinMajb9,1 }, { kMaj7b9, 1 }, { kMaj7s13, 2 }, { kDimMajb9, 1 }, - { kMaj7b9, 1 }, { kMaj7s13, 2 }, { kM7b913, 1 }, { kM7b9s13, 1 }}, - {/* interval2 is a minor third */ - { kMinMaj9, 1 }, { kMaj9, 1 }, { kHalfDimb9,0 }, { kMin7b9, 0 }, { kMaj9, 1 }, - { kDim7b9, 0 }, { kMin7b9, 0 }, { kMinMajb9, 0 }}, - {/* interval2 is a major third */ - { kMaj7s9, 1 }, { kDom7s11, 3 }, { kDomb9, 0 }, { kMinMaj7, 1 }, { kDom7s9, 3 }, - { kDomb9, 0 }, { kMaj7b9, 0 }}, - {/* interval2 is a perfect fourth */ - { kMaj11, 1 }, { kMaj7b5, 1 }, { kMaj7, 1 }, { kMaj7s5, 1 }, { kMin9, 3 }, - { kMaj7s13, 1 }}, - {/* interval2 is a tritone */ - { kDimMaj9, 3 }, { kDom11, 3 }, { kDim7b9, 0 }, { kHalfDimb9,0 }, { kDimMajb9, 0 }}, - {/* interval2 is a perfect fifth */ - { kMaj11, 3 }, { kDom7s9, 3 }, { kDomb9, 0 }, { kMaj7b9, 0 }}, - {/* interval2 is a minor sixth */ - { kMaj7s9, 3 }, { kMin9, 3 }, { kMaj7s13, 1 }}, - {/* interval2 is a major sixth */ - { kMinMaj9, 3 }, { kM7b913, 0 }}, - {/* interval2 is a minor seventh */ - { kM7b9s13, 0 }} - }, - {/* interval1 is a whole step */ - {/* interval2 is a minor third */ - { kM7b913, 2 }, { kMin7b9, 1 }, { kDomb9, 1 }, { kMin9, 0 }, { kHalfDimb9,1 }, - { kDomb9, 1 }, { kMin9, 0 }, { kMinMaj9, 0 }}, - {/* interval2 is a major third */ - { kMin9, 1 }, { kDom9, 1 }, { kDom9, 0 }, { kDom7s5, 2 }, { kDom9, 1 }, - { kDom9, 0 }, { kMaj9, 0 }}, - {/* interval2 is a perfect fourth */ - { kDom7s9, 1 }, { kDom11, 3 }, { kHalfDim7, 1 }, { kMin7, 1 }, { kDom9, 3 }, - { kHalfDimb9,3 }}, - {/* interval2 is a tritone */ - { kDom11, 1 }, { kDom7b5, 3 }, { kDom7, 1 }, { kDom7s5, 1 }, { kMin7b9, 3 }}, - {/* interval2 is a perfect fifth */ - { kMaj7b5, 3 }, { kDom11, 1 }, { kDom9, 0 }, { kMaj9, 0 }}, - {/* interval2 is a minor sixth */ - { kDom7s11, 1 }, { kDom9, 3 }, { kDim7b9, 3 }}, - {/* interval2 is a major sixth */ - { kMaj9, 3 }, { kMin7b9, 3 }}, - {/* interval2 is a minor seventh */ - { kMinMajb9, 3 }} - }, - {/* interval1 is a minor third */ - {/* interval2 is a major third */ - { kMaj7s13, 3 }, { kDim7b9, 1 }, { kDom7s9, 0 }, { kMaj7s5, 2 }, { kDim7b9, 1 }, - { kDom7s9, 0 }, { kMaj7s9, 0 }}, - {/* interval2 is a perfect fourth */ - { kDomb9, 2 }, { kDom9, 2 }, { kMin7, 2 }, { kDom7, 2 }, { kDom11, 2 }, - { kDom7s11, 2 }}, - {/* interval2 is a tritone */ - { kDim7b9, 2 }, { kDom7, 3 }, { kDim7, 0 }, { kHalfDim7, 0 }, { kDomb9, 3 }}, - {/* interval2 is a perfect fifth */ - { kMaj7, 3 }, { kHalfDim7,3 }, { kMin7, 0 }, { kMinMaj7, 0 }}, - {/* interval2 is a minor sixth */ - { kDomb9, 2 }, { kDom9, 2 }, { kDom7s9, 2 }}, - {/* interval2 is a major sixth */ - { kHalfDimb9,2 }, { kDomb9, 3 }}, - {/* interval2 is a minor seventh */ - { kMaj7b9, 3 }} - }, - {/* interval1 is a major third */ - {/* interval2 is a perfect fourth */ - { kMaj7b9, 2 }, { kMaj9, 2 }, { kMinMaj7, 2 }, { kMaj7, 2 }, { kDom11, 0 }, - { kMaj11, 0 }}, - {/* interval2 is a tritone */ - { kHalfDimb9,2 }, { kDom7s5, 3 }, { kHalfDim7, 2 }, { kDom7b5, 0 }, { kMaj7b5, 0 }}, - {/* interval2 is a perfect fifth */ - { kMaj7s5, 3 }, { kMin7, 3 }, { kDom7, 0 }, { kMaj7, 0 }}, - {/* interval2 is a minor sixth */ - { kMinMaj7, 3 }, { kDom7s5, 0 }, { kMaj7s5, 0 }}, - {/* interval2 is a major sixth */ - { kMin7b9, 2 }, { kMin9, 2 }}, - {/* interval2 is a minor seventh */ - { kMaj7s13, 0 }} - }, - {/* interval1 is a perfect fourth */ - {/* interval2 is a tritone */ - { kDimMajb9, 2 }, { kMin7b9, 1 }, { kDomb9, 1 }, { kMaj7b5, 2 }, { kDimMaj9, 0 }}, - {/* interval2 is a perfect fifth */ - { kMin9, 1 }, { kDom9, 1 }, { kDom11, 0 }, { kDom11, 2 }}, - {/* interval2 is a minor sixth */ - { kDom7s9, 1 }, { kDom9, 3 }, { kDim7b9, 3 }}, - {/* interval2 is a major sixth */ - { kMaj9, 3 }, { kHalfDimb9,3 }}, - {/* interval2 is a minor seventh */ - { kDimMajb9, 3 }} - }, - {/* interval1 is a tritone */ - {/* interval2 is a perfect fifth */ - { kMaj7s13, 3 }, { kHalfDimb9,1 }, { kDom7s11, 0 }, { kMaj11, 2 }}, - {/* interval2 is a minor sixth */ - { kDomb9, 2 }, { kDom9, 2 }, { kDom7s9, 2 }}, - {/* interval2 is a major sixth */ - { kDim7b9, 2 }, { kDomb9, 3 }}, - {/* interval2 is a minor seventh */ - { kMaj7b9, 3 }} - }, - {/* interval1 is a perfect fifth */ - {/* interval2 is a minor sixth */ - { kMaj7b9, 2 }, { kMaj9, 2 }, { kMaj7s9, 2 }}, - {/* interval2 is a major sixth */ - { kMin7b9, 2 }, { kMin9, 2 }}, - {/* interval2 is a minor seventh */ - { kMaj7s13, 0 }} - }, - {/* interval1 is a minor sixth */ - {/* interval2 is a major sixth */ - { kMinMajb9, 2 }, { kMinMaj9, 2 }}, - {/* interval2 is a minor seventh */ - { kM7b913, 3 }} - }, - {/* interval1 is a major sixth */ - {/* interval2 is a minor seventh */ - { kM7b9s13, 2 }} - } - }; - - register t_type_root* t; - - int members[4]; - int interval1, interval2, interval3; - int i, j = 0; - for (i=0; i<12; i++) - if (x->x_pc[i]) members[j++] = i; /* load members array with chord pitch classes */ - interval1 = members[1] - members[0]; /* calculate interval between first two members */ - interval2 = members[2] - members[0]; /* calculate interval between first and third */ - interval3 = members[3] - members[0]; /* calculate interval between first and third */ - interval3 = interval3 - interval2 - 1; /* reduce interval3 to start at zero */ - interval2 = interval2 - interval1 - 1; /* reduce interval2 to start at zero */ - interval1 = interval1 - 1; /* reduce interval1 to start at zero */ - - /* find TypeRoot struct for this interval set */ - t = &(quartads[interval1][interval2][interval3]); - x->x_chord_type = t->type; - x->x_chord_root = members[t->rootMember]; - switch(t->rootMember) { /* get state of inversion */ - case 0: - x->x_chord_inversion = 0; - break; - case 1: - x->x_chord_inversion = 2; - break; - case 2: - x->x_chord_inversion = 2; - break; - case 3: - x->x_chord_inversion = 1; - } - chord_draw_chord_type(x, 4); /* output results */ -} - -static void chord_fatal_error(char* s1, char* s2) -{ - post("chord: error: %s : %s", s1, s2); -} - -static void chord_quintad(t_chord *x) -{ - static int initialized = 0; - static t_type_root quintads[8][8][8][8]; - register int i, j, k, l; - register t_type_root *t; - t_int members[5]; - int interval1, interval2, interval3, interval4; - int *st; - int maj9[5][4] = {{1,1,2,3}, {0,1,1,2}, {3,0,1,1}, {2,3,0,1}, {1,2,3,0}}; - int dom9[5][4] = {{1,1,2,2}, {1,1,1,2}, {2,1,1,1}, {2,2,1,1}, {1,2,2,1}}; - int min9[5][4] = {{1,0,3,2}, {1,1,0,3}, {2,1,1,0}, {3,2,1,1}, {0,3,2,1}}; - int had9[5][4] = {{1,0,2,3}, {1,1,0,2}, {3,1,1,0}, {2,3,1,1}, {0,2,3,1}}; - int miM9[5][4] = {{1,0,3,3}, {0,1,0,3}, {3,0,1,0}, {3,3,0,1}, {0,3,3,0}}; - int diM9[5][4] = {{1,0,2,4}, {0,1,0,2}, {4,0,1,0}, {2,4,0,1}, {0,2,4,0}}; - int M9b5[5][4] = {{1,1,1,4}, {0,1,1,1}, {4,0,1,1}, {1,4,0,1}, {1,1,4,0}}; - int D9b5[5][4] = {{1,1,1,3}, {1,1,1,1}, {3,1,1,1}, {1,3,1,1}, {1,1,3,1}}; - int mM91[5][4] = {{1,0,0,6}, {0,1,0,0}, {6,0,1,0}, {0,6,0,1}, {0,0,6,0}}; - int M7b9[5][4] = {{0,2,2,3}, {0,0,2,2}, {3,0,0,2}, {2,3,0,0}, {2,2,3,0}}; - int M5b9[5][4] = {{0,2,3,2}, {0,0,2,3}, {2,0,0,2}, {3,2,0,0}, {2,3,2,0}}; - int D7b9[5][4] = {{0,2,2,2}, {1,0,2,2}, {2,1,0,2}, {2,2,1,0}, {2,2,2,1}}; - int m7b9[5][4] = {{0,1,3,2}, {1,0,1,3}, {2,1,0,1}, {3,2,1,0}, {1,3,2,1}}; - int mb51[5][4] = {{0,1,2,0}, {4,0,1,2}, {0,4,0,1}, {2,0,4,0}, {1,2,0,4}}; - int d7b9[5][4] = {{0,1,2,3}, {1,0,1,2}, {3,1,0,1}, {2,3,1,0}, {1,2,3,1}}; - int mMb9[5][4] = {{0,1,3,3}, {0,0,1,3}, {3,0,0,1}, {3,3,0,0}, {1,3,3,0}}; - int dMb9[5][4] = {{0,1,2,4}, {0,0,1,2}, {4,0,0,1}, {2,4,0,0}, {1,2,4,0}}; - int dib9[5][4] = {{0,1,2,2}, {2,0,1,2}, {2,2,0,1}, {2,2,2,0}, {1,2,2,2}}; - int M7s9[5][4] = {{2,0,2,3}, {0,2,0,2}, {3,0,2,0}, {2,3,0,2}, {0,2,3,0}}; - int D7s9[5][4] = {{2,0,2,2}, {1,2,0,2}, {2,1,2,0}, {2,2,1,2}, {0,2,2,1}}; - int M7s1[5][4] = {{3,1,0,3}, {0,3,1,0}, {3,0,3,1}, {0,3,0,3}, {1,0,3,0}}; - int d9b3[5][4] = {{1,1,2,0}, {3,1,1,2}, {0,3,1,1}, {2,0,3,1}, {1,2,0,3}}; - int M9s3[5][4] = {{1,4,2,0}, {0,1,4,2}, {0,0,1,4}, {2,0,0,1}, {4,2,0,0}}; - int M9st[5][4] = {{1,1,5,0}, {0,1,1,5}, {0,0,1,1}, {5,0,0,1}, {1,5,0,0}}; - int s9s1[5][4] = {{2,0,1,0}, {4,2,0,1}, {0,4,2,0}, {1,0,4,2}, {0,1,0,4}}; - int h7b1[5][4] = {{2,0,1,3}, {1,2,0,1}, {3,1,2,0}, {1,3,1,2}, {0,1,3,1}}; - int M711[5][4] = {{3,0,1,3}, {0,3,0,1}, {3,0,3,0}, {1,3,0,3}, {0,1,3,0}}; - int M115[5][4] = {{1,1,0,5}, {0,1,1,0}, {5,0,1,1}, {0,5,0,1}, {1,0,5,0}}; - int d711[5][4] = {{3,0,1,2}, {1,3,0,1}, {2,1,3,0}, {1,2,1,3}, {0,1,2,1}}; - int d712[5][4] = {{1,1,0,1}, {4,1,1,0}, {1,4,1,1}, {0,1,4,1}, {1,0,1,4}}; - int d713[5][4] = {{1,1,0,4}, {1,1,1,0}, {4,1,1,1}, {0,4,1,1}, {1,0,4,1}}; - int m711[5][4] = {{2,1,1,2}, {1,2,1,1}, {2,1,2,1}, {1,2,1,2}, {1,1,2,1}}; - int m712[5][4] = {{1,0,1,1}, {4,1,0,1}, {1,4,1,0}, {1,1,4,1}, {0,1,1,4}}; - int di11[5][4] = {{1,0,1,0}, {5,1,0,1}, {0,5,1,0}, {1,0,5,1}, {0,1,0,5}}; - int mM11[5][4] = {{2,1,1,3}, {0,2,1,1}, {3,0,2,1}, {1,3,0,2}, {1,1,3,0}}; - int dM11[5][4] = {{2,1,0,4}, {0,2,1,0}, {4,0,2,1}, {0,4,0,2}, {1,0,4,0}}; - int Meb5[5][4] = {{3,0,0,4}, {0,3,0,0}, {4,0,3,0}, {0,4,0,3}, {0,0,4,0}}; - int Mes5[5][4] = {{3,0,2,2}, {0,3,0,2}, {2,0,3,0}, {2,2,0,3}, {0,2,2,0}}; - int Meb9[5][4] = {{0,2,0,5}, {0,0,2,0}, {5,0,0,2}, {0,5,0,0}, {2,0,5,0}}; - int Mes9[5][4] = {{2,0,0,5}, {0,2,0,0}, {5,0,2,0}, {0,5,0,2}, {0,0,5,0}}; - int Deb5[5][4] = {{3,0,0,3}, {1,3,0,0}, {3,1,3,0}, {0,3,1,3}, {0,0,3,1}}; - int Mes3[5][4] = {{3,0,4,0}, {0,3,0,4}, {0,0,3,0}, {4,0,0,3}, {0,4,0,0}}; - int Deb9[5][4] = {{0,2,0,4}, {1,0,2,0}, {4,1,0,2}, {0,4,1,0}, {2,0,4,1}}; - int De91[5][4] = {{0,2,0,1}, {4,0,2,0}, {1,4,0,2}, {0,1,4,0}, {2,0,1,4}}; - int Des9[5][4] = {{2,0,0,4}, {1,2,0,0}, {4,1,2,0}, {0,4,1,2}, {0,0,4,1}}; - int Ds11[5][4] = {{3,1,0,2}, {1,3,1,0}, {2,1,3,1}, {0,2,1,3}, {1,0,2,1}}; - int m7s1[5][4] = {{2,2,0,2}, {1,2,2,0}, {2,1,2,2}, {0,2,1,2}, {2,0,2,1}}; - int D3s1[5][4] = {{5,0,1,0}, {1,5,0,1}, {0,1,5,0}, {1,0,1,5}, {0,1,0,1}}; - int Mb9s[5][4] = {{0,2,5,0}, {0,0,2,5}, {0,0,0,2}, {5,0,0,0}, {2,5,0,0}}; - int D7b3[5][4] = {{3,2,0,1}, {1,3,2,0}, {1,1,3,2}, {0,1,1,3}, {2,0,1,1}}; - - if (!initialized) { - for (i=0; i<8; i++) - for (j=0; j<8; j++) - for (k=0; k<8; k++) - for (l=0; l<8; l++) { - quintads[i][j][k][l].type = kNone; - quintads[i][j][k][l].rootMember = kXX; - } - - - // major ninths - for (i=0; i<5; i++) { - st = maj9[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - t->type = kMaj9; - t->rootMember = i; - } - - // dominant ninths - for (i=0; i<5; i++) { - st = dom9[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "dom9"); - t->type = kDom9; - t->rootMember = i; - } - - // minor ninths - for (i=0; i<5; i++) { - st = min9[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "min9"); - t->type = kMin9; - t->rootMember = i; - } - - // half diminished ninths - for (i=0; i<5; i++) { - st = had9[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "had9"); - t->type = kHalfDim9; - t->rootMember = i; - } - - // minor/major ninths - for (i=0; i<5; i++) { - st = miM9[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "miM9"); - t->type = kMinMaj9; - t->rootMember = i; - } - - // diminished/major ninths - for (i=0; i<5; i++) { - st = diM9[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "diM9"); - t->type = kDimMaj9; - t->rootMember = i; - } - - // major ninth flat 5 - for (i=0; i<5; i++) { - st = M9b5[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "M9b5"); - t->type = kMaj9b5; - t->rootMember = i; - } - - // dominant ninth flat 5 - for (i=0; i<5; i++) { - st = D9b5[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "D9b5"); - t->type = kDom9b5; - t->rootMember = i; - } - - // minor/major ninth flat 11 - for (i=0; i<5; i++) { - st = mM91[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "mM91"); - t->type = kmM9b11; - t->rootMember = i; - } - - // major seventh flat nine - for (i=0; i<5; i++) { - st = M7b9[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "M7b9"); - t->type = kMaj7b9; - t->rootMember = i; - } - - // major seventh sharp five flat nine - for (i=0; i<5; i++) { - st = M5b9[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "M5b9"); - t->type = kMaj7s5b9; - t->rootMember = i; - } - - // dominant seventh flat nine - for (i=0; i<5; i++) { - st = D7b9[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "D7b9"); - t->type = kDom7b9; - t->rootMember = i; - } - - // minor seventh flat nine - for (i=0; i<5; i++) { - t = &(quintads[m7b9[i][0]][m7b9[i][1]][m7b9[i][2]][m7b9[i][3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "m7b9"); - t->type = kMin7b9; - t->rootMember = i; - } - - // minor flat nine sharp eleventh - for (i=0; i<5; i++) { - st = mb51[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "mb51"); - t->type = kMinb9s11; - t->rootMember = i; - } - - // half diminished seventh flat nine - for (i=0; i<5; i++) { - st = d7b9[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "d7b9"); - t->type = kHalfDimb9; - t->rootMember = i; - } - - // minor/major seventh flat nine - for (i=0; i<5; i++) { - st = mMb9[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "mMb9"); - t->type = kMinMajb9; - t->rootMember = i; - } - - // diminished major seventh flat nine - for (i=0; i<5; i++) { - st = dMb9[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "dMb9"); - t->type = kDimMajb9; - t->rootMember = i; - } - - // diminished seventh flat nine - for (i=0; i<5; i++) { - t = &(quintads[dib9[i][0]][dib9[i][1]][dib9[i][2]][dib9[i][3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "dib9"); - t->type = kDim7b9; - t->rootMember = i; - } - - // major seventh sharp nine - for (i=0; i<5; i++) { - t = &(quintads[M7s9[i][0]][M7s9[i][1]][M7s9[i][2]][M7s9[i][3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "M7s9"); - t->type = kMaj7s9; - t->rootMember = i; - } - - // dominant seventh sharp nine - for (i=0; i<5; i++) { - t = &(quintads[D7s9[i][0]][D7s9[i][1]][D7s9[i][2]][D7s9[i][3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "D7s9"); - t->type = kDom7s9; - t->rootMember = i; - } - - // major seventh sharp eleventh - for (i=0; i<5; i++) { - t = &(quintads[M7s1[i][0]][M7s1[i][1]][M7s1[i][2]][M7s1[i][3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "M7s1"); - t->type = kMaj7s11; - t->rootMember = i; - } - - // dominant ninth flat thirteenth - for (i=0; i<5; i++) { - st = d9b3[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "d9b3"); - t->type = kDom9b13; - t->rootMember = i; - } - - // major ninth sharp thirteenth - for (i=0; i<5; i++) { - st = M9s3[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "M9s3"); - t->type = kMaj9s13; - t->rootMember = i; - } - - // major ninth sharp thirteenth - for (i=0; i<5; i++) { - t = &(quintads[M9st[i][0]][M9st[i][1]][M9st[i][2]][M9st[i][3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "M9st"); - t->type = kMaj9s13; - t->rootMember = i; - } - - // major chord sharp ninth sharp eleventh - for (i=0; i<5; i++) { - st = s9s1[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "s9s1"); - t->type = kMs9s11; - t->rootMember = i; - } - - // half diminished seven flat 11 - for (i=0; i<5; i++) { - st = h7b1[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "h7b1"); - t->type = kHDimb11; - t->rootMember = i; - } - - // major eleventh - for (i=0; i<5; i++) { - t = &(quintads[M711[i][0]][M711[i][1]][M711[i][2]][M711[i][3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "M711"); - t->type = kMaj11; - t->rootMember = i; - } - - // major eleventh - for (i=0; i<5; i++) { - t = &(quintads[M115[i][0]][M115[i][1]][M115[i][2]][M115[i][3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "M711"); - t->type = kMaj11; - t->rootMember = i; - } - - // dominant eleventh - for (i=0; i<5; i++) { - t = &(quintads[d711[i][0]][d711[i][1]][d711[i][2]][d711[i][3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "d711"); - t->type = kDom11; - t->rootMember = i; - } - - // dominant eleventh - for (i=0; i<5; i++) { - t = &(quintads[d712[i][0]][d712[i][1]][d712[i][2]][d712[i][3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "d712"); - t->type = kDom11; - t->rootMember = i; - } - - // dominant eleventh - for (i=0; i<5; i++) { - st = d713[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "d713"); - t->type = kDom11; - t->rootMember = i; - } - - // minor eleventh - for (i=0; i<5; i++) { - t = &(quintads[m711[i][0]][m711[i][1]][m711[i][2]][m711[i][3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "m711"); - t->type = kMin11; - t->rootMember = i; - } - - // minor eleventh - for (i=0; i<5; i++) { - t = &(quintads[m712[i][0]][m712[i][1]][m712[i][2]][m712[i][3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "m712"); - t->type = kMin11; - t->rootMember = i; - } - - // diminished eleventh - for (i=0; i<5; i++) { - st = di11[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "di11"); - t->type = kDim11; - t->rootMember = i; - } - - // minor/major eleventh - for (i=0; i<5; i++) { - st = mM11[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "mM11"); - t->type = kMinMaj11; - t->rootMember = i; - } - - // diminished major eleventh - for (i=0; i<5; i++) { - st = dM11[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "dM11"); - t->type = kDimMaj11; - t->rootMember = i; - } - - // major eleventh flat fifth - for (i=0; i<5; i++) { - st = Meb5[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "Meb5"); - t->type = kMaj11b5; - t->rootMember = i; - } - - // major eleventh sharp fifth - for (i=0; i<5; i++) { - st = Mes5[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "Mes5"); - t->type = kMaj11s5; - t->rootMember = i; - } - - // major eleventh flat ninth - for (i=0; i<5; i++) { - st = Meb9[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "Meb9"); - t->type = kMaj11b9; - t->rootMember = i; - } - - // major eleventh sharp ninth - for (i=0; i<5; i++) { - st = Mes9[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "Mes9"); - t->type = kMaj11s9; - t->rootMember = i; - } - - // major eleventh sharp thirteenth - for (i=0; i<5; i++) { - st = Mes3[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "Mes3"); - t->type = kMaj11s13; - t->rootMember = i; - } - - // dominant eleventh flat fifth - for (i=0; i<5; i++) { - st = Deb5[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "Deb5"); - t->type = kDom11b5; - t->rootMember = i; - } - - // dominant eleventh flat ninth - for (i=0; i<5; i++) { - st = Deb9[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "Deb9"); - t->type = kDom11b9; - t->rootMember = i; - } - - // dominant eleventh flat ninth - for (i=0; i<5; i++) { - st = De91[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "De91"); - t->type = kDom11b9; - t->rootMember = i; - } - - // dominant eleventh sharp ninth - for (i=0; i<5; i++) { - st = Des9[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "Des9"); - t->type = kDom11s9; - t->rootMember = i; - } - - // dominant seventh sharp eleventh - for (i=0; i<5; i++) { - st = Ds11[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "Ds11"); - t->type = kDom7s11; - t->rootMember = i; - } - - // minor seventh sharp eleventh - for (i=0; i<5; i++) { - st = m7s1[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "m7s1"); - t->type = kMin7s11; - t->rootMember = i; - } - - // dominant thirteenth sharp eleventh - for (i=0; i<5; i++) { - st = D3s1[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "D3s1"); - t->type = kDom13s11; - t->rootMember = i; - } - - // major seventh flat ninth sharp thirteenth - for (i=0; i<5; i++) { - st = Mb9s[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "Mb9s"); - t->type = kM7b9s13; - t->rootMember = i; - } - - // dominant seventh flat thirteenth - for (i=0; i<5; i++) { - st = D7b3[i]; - t = &(quintads[st[0]][st[1]][st[2]][st[3]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "D7b3"); - t->type = kDom7b13; - t->rootMember = i; - } - - initialized = 1; - return; - } - - j = 0; - for (i=0; i<12; i++) - if (x->x_pc[i]) members[j++] = i; /* load members array with chord pitch classes */ - interval1 = members[1] - members[0]; /* calculate interval between first two members */ - interval2 = members[2] - members[0]; /* calculate interval between first and third */ - interval3 = members[3] - members[0]; /* calculate interval between first and third */ - interval4 = members[4] - members[0]; /* calculate interval between first and fourth */ - interval4 = interval4 - interval3 - 1; /* reduce interval4 to start at zero */ - interval3 = interval3 - interval2 - 1; /* reduce interval3 to start at zero */ - interval2 = interval2 - interval1 - 1; /* reduce interval2 to start at zero */ - interval1 = interval1 - 1; /* reduce interval1 to start at zero */ - - // find TypeRoot struct for this interval set - t = &(quintads[interval1][interval2][interval3][interval4]); - if (t->rootMember != kXX) - { - x->x_chord_type = t->type; - x->x_chord_root = members[t->rootMember]; - switch(t->rootMember) { /* get state of inversion */ - case 0: - x->x_chord_inversion = 0; - break; - case 1: - x->x_chord_inversion = 2; - break; - case 2: - x->x_chord_inversion = 2; - break; - case 3: - x->x_chord_inversion = 2; - break; - case 4: - x->x_chord_inversion = 1; - } - chord_draw_chord_type(x, 5); /* output result */ - } else - chord_kick_out_member(x, 5, members); -} - -static void chord_sextad(t_chord *x) -{ - static int initialized = 0; - static t_type_root sextads[7][7][7][7][7]; - register int i, j, k, l, m; - register t_type_root *t; - register int* st; - t_int members[6]; - int interval1, interval2, interval3, interval4, interval5; - - int D9b3[6][5] = - {{1,1,2,0,1}, {1,1,1,2,0}, {1,1,1,1,2}, {0,1,1,1,1}, {2,0,1,1,1}, {1,2,0,1,1}}; - int m9s1[6][5] = - {{1,0,2,0,2}, {1,1,0,2,0}, {2,1,1,0,2}, {0,2,1,1,0}, {2,0,2,1,1}, {0,2,0,2,1}}; - int M711[6][5] = - {{1,1,0,1,3}, {0,1,1,0,1}, {3,0,1,1,0}, {1,3,0,1,1}, {0,1,3,0,1}, {1,0,1,3,0}}; - int D711[6][5] = - {{1,1,0,1,2}, {1,1,1,0,1}, {2,1,1,1,0}, {1,2,1,1,1}, {0,1,2,1,1}, {1,0,1,2,1}}; - int hd11[6][5] = - {{1,0,1,0,3}, {1,1,0,1,0}, {3,1,1,0,1}, {0,3,1,1,0}, {1,0,3,1,1}, {0,1,0,3,1}}; - int M1b5[6][5] = - {{1,1,0,0,4}, {0,1,1,0,0}, {4,0,1,1,0}, {0,4,0,1,1}, {0,0,4,0,1}, {1,0,0,4,0}}; - int M159[6][5] = - {{0,2,0,0,4}, {0,0,2,0,0}, {4,0,0,2,0}, {0,4,0,0,2}, {0,0,4,0,0}, {2,0,0,4,0}}; - int M1s3[6][5] = - {{1,1,0,4,0}, {0,1,1,0,4}, {0,0,1,1,0}, {4,0,0,1,1}, {0,4,0,0,1}, {1,0,4,0,0}}; - int hd19[6][5] = - {{0,1,1,0,3}, {1,0,1,1,0}, {3,1,0,1,1}, {0,3,1,0,1}, {1,0,3,1,0}, {1,1,0,3,1}}; - int M1b3[6][5] = - {{3,0,1,0,2}, {0,3,0,1,0}, {2,0,3,0,1}, {0,2,0,3,0}, {1,0,2,0,3}, {0,1,0,2,0}}; - int D1b5[6][5] = - {{1,1,0,0,3}, {1,1,1,0,0}, {3,1,1,1,0}, {0,3,1,1,1}, {0,0,3,1,1}, {1,0,0,3,1}}; - int D1s9[6][5] = - {{2,0,0,1,2}, {1,2,0,0,1}, {2,1,2,0,0}, {1,2,1,2,0}, {0,1,2,1,2}, {0,0,1,2,1}}; - int m791[6][5] = - {{0,1,2,0,2}, {1,0,1,2,0}, {2,1,0,1,2}, {0,2,1,0,1}, {2,0,2,1,0}, {1,2,0,2,1}}; - int d7s1[6][5] = - {{1,1,1,0,2}, {1,1,1,1,0}, {2,1,1,1,1}, {0,2,1,1,1}, {1,0,2,1,1}, {1,1,0,2,1}}; - int d3s1[6][5] = - {{3,1,0,1,0}, {1,3,1,0,1}, {0,1,3,1,0}, {1,0,1,3,1}, {0,1,0,1,3}, {1,0,1,0,1}}; - - - if (!initialized) { - for (i=0; i<7; i++) - for (j=0; j<7; j++) - for (k=0; k<7; k++) - for (l=0; l<7; l++) - for (m=0; m<7; m++) { - sextads[i][j][k][l][m].type = kNone; - sextads[i][j][k][l][m].rootMember = kXX; - } - - // dominant ninth flat thirteen - for (i=0; i<6; i++) { - st = D9b3[i]; - t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "D9b3"); - t->type = kDom9b13; - t->rootMember = i; - } - - // minor ninth sharp eleventh - for (i=0; i<6; i++) { - st = m9s1[i]; - t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "m9s1"); - t->type = kMin9s11; - t->rootMember = i; - } - - // major eleventh - for (i=0; i<6; i++) { - st = M711[i]; - t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "M711"); - t->type = kMaj11; - t->rootMember = i; - } - - // dominant eleventh - for (i=0; i<6; i++) { - st = D711[i]; - t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "D711"); - t->type = kDom11; - t->rootMember = i; - } - - // half diminished eleventh - for (i=0; i<6; i++) { - st = hd11[i]; - t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "hd11"); - t->type = kHalfDim11; - t->rootMember = i; - } - - // major eleventh flat 5 - for (i=0; i<6; i++) { - st = M1b5[i]; - t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "M1b5"); - t->type = kMaj11b5; - t->rootMember = i; - } - - // major eleventh flat 5 flat 9 - for (i=0; i<6; i++) { - st = M159[i]; - t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "M159"); - t->type = kM11b5b9; - t->rootMember = i; - } - - // major eleventh sharp 13 - for (i=0; i<6; i++) { - st = M1s3[i]; - t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "M1s3"); - t->type = kMaj11s13; - t->rootMember = i; - } - - // half diminished eleventh flat 9 - for (i=0; i<6; i++) { - st = hd19[i]; - t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "hd19"); - t->type = kHalfDim11b9; - t->rootMember = i; - } - - // major eleventh flat 13 - for (i=0; i<6; i++) { - st = M1b3[i]; - t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "M1b3"); - t->type = kMaj11b13; - t->rootMember = i; - } - - // dominant eleventh flat five - for (i=0; i<6; i++) { - st = D1b5[i]; - t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "D1b5"); - t->type = kDom11b5; - t->rootMember = i; - } - - // dominant eleventh sharp nine - for (i=0; i<6; i++) { - st = D1s9[i]; - t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "D1s9"); - t->type = kDom11s9; - t->rootMember = i; - } - - // minor seventh flat 9 sharp 11 - for (i=0; i<6; i++) { - st = m791[i]; - t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "m791"); - t->type = kMinb9s11; - t->rootMember = i; - } - - // dominant seventh sharp 11 - for (i=0; i<6; i++) { - st = d7s1[i]; - t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "d7s1"); - t->type = kDom7s11; - t->rootMember = i; - } - - // dominant thirteenth sharp 11 - for (i=0; i<6; i++) { - st = d3s1[i]; - t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); - if (t->type != kNone) chord_fatal_error("redefining chord", "d3s1"); - t->type = kDom13s11; - t->rootMember = i; - } - - initialized = 1; - return; - } - - j = 0; - for (i=0; i<12; i++) - if (x->x_pc[i]) members[j++] = i; // load members array with chord pitch classes - interval1 = members[1] - members[0]; // calculate interval between first two members - interval2 = members[2] - members[0]; // calculate interval between first and third - interval3 = members[3] - members[0]; // calculate interval between first and third - interval4 = members[4] - members[0]; // calculate interval between first and fourth - interval5 = members[5] - members[0]; // calculate interval between first and fifth - interval5 = interval5 - interval4 - 1; // reduce interval5 to start at zero - interval4 = interval4 - interval3 - 1; // reduce interval4 to start at zero - interval3 = interval3 - interval2 - 1; // reduce interval3 to start at zero - interval2 = interval2 - interval1 - 1; // reduce interval2 to start at zero - interval1 = interval1 - 1; // reduce interval1 to start at zero - - // find TypeRoot struct for this interval set - t = &(sextads[interval1][interval2][interval3][interval4][interval5]); - if (t->rootMember != kXX) { - x->x_chord_type = t->type; - x->x_chord_root = members[t->rootMember]; - switch(t->rootMember) { /* get state of inversion */ - case 0: - x->x_chord_inversion = 0; - break; - case 1: - x->x_chord_inversion = 2; - break; - case 2: - x->x_chord_inversion = 2; - break; - case 3: - x->x_chord_inversion = 2; - break; - case 4: - x->x_chord_inversion = 2; - break; - case 5: x->x_chord_inversion = 1; - } - chord_draw_chord_type(x, 6); // output onto the screen - } else - chord_kick_out_member(x, 6, members); -} - -static int chord_accidental(t_int pc) -{ - switch (pc) { - case 0: - case 2: - case 4: - case 5: - case 7: - case 9: - case 11: return 0; - case 1: - case 3: - case 6: - case 8: - case 10: - default: return 1; - } -} - -static int chord_name_third(t_chord *x, char* chord, int c, int rootName) -{ - int third = (x->x_chord_root+4)%12; // look for major third - if (x->x_pc[third]) { // if one is there - x->x_pc[third] = 0; // erase from pcs array - chord[c++] = name_class[(rootName+2)%7]; - if (chord_accidental(third)) { // if it has an chord_accidental - // make it a flat if the root also has an chord_accidental - if (chord_accidental(x->x_chord_root)) - chord[c++] = 'b'; - // otherwise make it a sharp - else - chord[c++] = '#'; - } - chord[c++] = ' '; - return c; // return if major third found - } - - third = (x->x_chord_root+3)%12; // no major, look for minor third - if (x->x_pc[third]) { // if one is there - x->x_pc[third] = 0; // erase from pcs array - chord[c++] = name_class[(rootName+2)%7]; - if (chord_accidental(third)) // if it has an chord_accidental - chord[c++] = 'b'; else // make it a flat - if (chord_accidental(x->x_chord_root)) { // if the root has an chord_accidental - chord[c++] = 'b'; // make the third a flat - if (chord[0] == 'G') // if the root is Gb - chord[c++] = 'b'; // this must be Bbb - } - chord[c++] = ' '; - return c; - } - - return c; // if we get here there was no third -} - -static int chord_name_fifth(t_chord *x, char* chord, int c, int rootName) -{ - int fifth = (x->x_chord_root+7)%12; - if (x->x_pc[fifth]) { - x->x_pc[fifth] = 0; - chord[c++] = name_class[(rootName+4)%7]; - if (chord_accidental(fifth)) { - if (chord_accidental(x->x_chord_root)) chord[c++] = 'b'; - else chord[c++] = '#'; - } - chord[c++] = ' '; - return c; - } - - fifth = (x->x_chord_root+6)%12; - if (x->x_pc[fifth]) { - x->x_pc[fifth] = 0; - chord[c++] = name_class[(rootName+4)%7]; - if (chord[0] != 'B') chord[c++] = 'b'; - if (chord_accidental(x->x_chord_root)) chord[c++] = 'b'; - chord[c++] = ' '; - return c; - } - - fifth = (x->x_chord_root+8)%12; - if (x->x_pc[fifth]) { - x->x_pc[fifth] = 0; - chord[c++] = name_class[(rootName+4)%7]; - if (chord_accidental(fifth)) chord[c++] = '#'; else - if (!chord_accidental(x->x_chord_root)) { - chord[c++] = '#'; - if (chord[0] == 'B') - chord[c++] = '#'; - } - chord[c++] = ' '; - return c; - } - - return c; -} - -static int chord_name_seventh(t_chord *x, char* chord, int c, int rootName) -{ - int seventh = (x->x_chord_root+11)%12; - if (x->x_pc[seventh]) { - x->x_pc[seventh] = 0; - chord[c++] = name_class[(rootName+6)%7]; - if (chord_accidental(seventh)) chord[c++] = '#'; - chord[c++] = ' '; - return c; - } - seventh = (x->x_chord_root+10)%12; - if (x->x_pc[seventh]) { - x->x_pc[seventh] = 0; - chord[c++] = name_class[(rootName+6)%7]; - if (chord_accidental(seventh) || chord_accidental(x->x_chord_root)) - chord[c++] = 'b'; - chord[c++] = ' '; - return c; - } - seventh = (x->x_chord_root+9)%12; - if (x->x_pc[seventh]) { - x->x_pc[seventh] = 0; - chord[c++] = name_class[(rootName+6)%7]; - chord[c++] = 'b'; - if (chord_accidental(x->x_chord_root)) chord[c++] = 'b'; else - if (chord_accidental((seventh+1)%12)) chord[c++] = 'b'; - chord[c++] = ' '; - return c; - } - return c; -} - -static int chord_name_ninth(t_chord *x, char* chord, int c, int rootName) -{ - int ninth = (x->x_chord_root+2)%12; - if (x->x_pc[ninth]) { - x->x_pc[ninth] = 0; - chord[c++] = name_class[(rootName+1)%7]; - if (chord_accidental(ninth)) { - if (chord_accidental(x->x_chord_root)) chord[c++] = 'b'; - else chord[c++] = '#'; - } - chord[c++] = ' '; - return c; - } - - ninth = (x->x_chord_root+1)%12; - if (x->x_pc[ninth]) { - x->x_pc[ninth] = 0; - chord[c++] = name_class[(rootName+1)%7]; - if (chord_accidental(ninth)) chord[c++] = 'b'; - else { - if (chord_accidental(x->x_chord_root)) { - chord[c++] = 'b'; - if ((x->x_chord_root == 1) || (x->x_chord_root == 6) || (x->x_chord_root == 8)) - chord[c++] = 'b'; - } - } - chord[c++] = ' '; - return c; - } - - ninth = (x->x_chord_root+3)%12; - if (x->x_pc[ninth]) { - x->x_pc[ninth] = 0; - chord[c++] = name_class[(rootName+1)%7]; - if (chord_accidental(ninth)) chord[c++] = '#'; else - if (!chord_accidental(x->x_chord_root)) { - chord[c++] = '#'; - if (chord_accidental((x->x_chord_root+2)%12)) - chord[c++] = '#'; - } - chord[c++] = ' '; - return c; - } - - return c; -} - -static int chord_name_eleventh(t_chord *x, char* chord, int c, int rootName) -{ - int eleventh = (x->x_chord_root+5)%12; - if (x->x_pc[eleventh]) { - x->x_pc[eleventh] = 0; - chord[c++] = name_class[(rootName+3)%7]; - if (chord_accidental(eleventh)) chord[c++] = 'b'; else - if (chord_accidental(x->x_chord_root)) chord[c++] = 'b'; - chord[c++] = ' '; - return c; - } - - eleventh = (x->x_chord_root+6)%12; - if (x->x_pc[eleventh]) { - x->x_pc[eleventh] = 0; - chord[c++] = name_class[(rootName+3)%7]; - if (chord_accidental(eleventh)) chord[c++] = '#'; else - if ((!chord_accidental(x->x_chord_root)) && (x->x_chord_root == 11)) - chord[c++] = '#'; - chord[c++] = ' '; - return c; - } - - return c; -} - -static int chord_name_thirteenth(t_chord *x, char* chord, int c, int rootName) -{ - int thirteenth = (x->x_chord_root+9)%12; - if (x->x_pc[thirteenth]) { - x->x_pc[thirteenth] = 0; - chord[c++] = name_class[(rootName+5)%7]; - if (chord_accidental(thirteenth)) { - if (chord_accidental(x->x_chord_root)) - chord[c++] = 'b'; - else - chord[c++] = '#'; - } - - chord[c++] = ' '; - return c; - } - - thirteenth = (x->x_chord_root+10)%12; - if (x->x_pc[thirteenth]) { - x->x_pc[thirteenth] = 0; - chord[c++] = name_class[(rootName+5)%7]; - if (chord_accidental(thirteenth)) chord[c++] = '#'; else - if (!chord_accidental(x->x_chord_root)) { - chord[c++] = '#'; - if (chord_accidental((x->x_chord_root+9)%12)) - chord[c++] = '#'; - } - chord[c++] = ' '; - return c; - } - - thirteenth = (x->x_chord_root+8)%12; - if (x->x_pc[thirteenth]) { - x->x_pc[thirteenth] = 0; - chord[c++] = name_class[(rootName+5)%7]; - if (chord_accidental(thirteenth)) chord[c++] = 'b'; else - if (chord_accidental(x->x_chord_root)) { - chord[c++] = 'b'; - if (chord_accidental(x->x_chord_root+9)%12) - chord[c++] = 'b'; - } - chord[c++] = ' '; - return c; - } - - return c; -} - - - -static void chord_spell_chord(t_chord *x, char *chord, t_int num_pcs) -{ - int rootName = 0; // keep index of root name class - int c = 0; // pointer to current character - int named = 0; // how many members have been named - int mark; - int i; - - // use chordRoot to set rootName index and store characters for name - switch (x->x_chord_root) - { - case 0: chord[c++] = name_class[rootName=0]; break; - case 1: chord[c++] = name_class[rootName=1]; - chord[c++] = 'b'; break; - case 2: chord[c++] = name_class[rootName=1]; break; - case 3: chord[c++] = name_class[rootName=2]; - chord[c++] = 'b'; break; - case 4: chord[c++] = name_class[rootName=2]; break; - case 5: chord[c++] = name_class[rootName=3]; break; - case 6: chord[c++] = name_class[rootName=4]; - chord[c++] = 'b'; break; - case 7: chord[c++] = name_class[rootName=4]; break; - case 8: chord[c++] = name_class[rootName=5]; - chord[c++] = 'b'; break; - case 9: chord[c++] = name_class[rootName=5]; break; - case 10: chord[c++] = name_class[rootName=6]; - chord[c++] = 'b'; break; - case 11: chord[c++] = name_class[rootName=6]; break; - default: break; - } - x->x_pc[x->x_chord_root] = 0; /* set this member to zero */ - - chord[c++] = ' '; // insert space - if (++named == num_pcs) { // if everything is named - chord[c] = '\0'; // terminate the string - return; // and return - } - - mark = c; // use mark to see if new names are added - for (i=0; i<6; i++) { - // advance search by thirds - switch (i) { - case 0: mark = chord_name_third (x, chord, c, rootName); break; - case 1: mark = chord_name_fifth (x, chord, c, rootName); break; - case 2: mark = chord_name_seventh (x, chord, c, rootName); break; - case 3: mark = chord_name_ninth (x, chord, c, rootName); break; - case 4: mark = chord_name_eleventh (x, chord, c, rootName); break; - case 5: mark = chord_name_thirteenth(x, chord, c, rootName); break; - } - if (mark != c) { // if new name is added - ++named; // increment count of named members - c = mark; // update character pointer - } - if (named == num_pcs) { // if everything is named - chord[c] = '\0'; // terminate the string - return; // and return - } - } - - chord[c] = '\0'; -} - - -static void chord_draw_chord_type(t_chord *x, t_int num_pcs) -{ - char chord[255]; /* output string */ - int i, j; - - /* get members of chord */ - j = 0; - for(i = 0; i < 12; i++) - { - if(x->x_pc[i]) - { - SETFLOAT(x->x_chordlist+j, x->x_abs_pc[i]); - j++; - } - } - - if (x->x_chord_type != kNone) - { - chord_spell_chord(x, chord, num_pcs); /* spell chord members */ - } - else - { - post("going..."); - chord[0] = '\0'; - for(i = 0; i < 12; i++) - if (x->x_pc[i]) - strcat(chord, pitch_class[i]); /* output single notes */ - post("did it"); - } - - strcat(chord, ": "); - strcat(chord, pitch_class[x->x_chord_root]); - - /* append name of chord type */ - switch (x->x_chord_type) { - case kUnison: strcat(chord, "unison"); break; - case kMaj: strcat(chord, "major"); break; - case kMin: strcat(chord, "minor"); break; - case kDim: strcat(chord, "diminished"); break; - case kAug: strcat(chord, "augmented"); break; - - case kMaj7: strcat(chord, "major 7th"); break; - case kDom7: strcat(chord, "dominant 7th"); break; - case kMin7: strcat(chord, "minor 7th"); break; - case kHalfDim7: strcat(chord, "half diminished 7th"); break; - case kDim7: strcat(chord, "diminished 7th"); break; - case kMinMaj7: strcat(chord, "minor/major 7th"); break; - - case kMaj7s5: strcat(chord, "major 7th #5"); break; - case kMaj7b5: strcat(chord, "major 7th b5"); break; - case kDom7s5: strcat(chord, "dominant 7th #5"); break; - case kDom7b5: strcat(chord, "dominant 7th b5"); break; - case kDomb9: strcat(chord, "dominant b9"); break; - - case kMaj9: strcat(chord, "major 9th"); break; - case kDom9: strcat(chord, "dominant 9th"); break; - case kMin9: strcat(chord, "minor 9th"); break; - case kHalfDim9: strcat(chord, "half diminished 9th"); break; - case kMinMaj9: strcat(chord, "minor major 9th"); break; - case kDimMaj9: strcat(chord, "diminished major 9th");break; - case kMaj9b5: strcat(chord, "major 9th b5"); break; - case kDom9b5: strcat(chord, "dominant 9th b5"); break; - case kDom9b13: strcat(chord, "dominant 9th b13"); break; - case kMin9s11: strcat(chord, "minor 9th #11"); break; - case kmM9b11: strcat(chord, "minor/maj 9th b11"); break; - - case kMaj7b9: strcat(chord, "major 7th b9"); break; - case kMaj7s5b9: strcat(chord, "major 7th #5 b9"); break; - case kDom7b9: strcat(chord, "dominant 7th b9"); break; - case kMin7b9: strcat(chord, "minor 7th b9"); break; - case kMinb9s11: strcat(chord, "minor b9 #11"); break; - case kHalfDimb9:strcat(chord, "half diminished b9"); break; - case kDim7b9: strcat(chord, "diminished b9"); break; - case kMinMajb9: strcat(chord, "minor/major b9"); break; - case kDimMajb9: strcat(chord, "diminished M7 b9"); break; - - case kMaj7s9: strcat(chord, "major 7th #9"); break; - case kDom7s9: strcat(chord, "dominant #9"); break; - case kMaj7s11: strcat(chord, "major 7th #11"); break; - case kMaj9s13: strcat(chord, "major 9th #13"); break; - case kMs9s11: strcat(chord, "major #9 #11"); break; - case kHDimb11: strcat(chord, "half diminished b11"); break; - - case kMaj11: strcat(chord, "major 11th"); break; - case kDom11: strcat(chord, "dominant 11th"); break; - case kMin11: strcat(chord, "minor 11th"); break; - case kHalfDim11:strcat(chord, "half diminished 11th");break; - case kDim11: strcat(chord, "diminished 11th"); break; - case kMinMaj11: strcat(chord, "minor/major 11th"); break; - case kDimMaj11: strcat(chord, "diminished maj 11th"); break; - - case kMaj11b5: strcat(chord, "major 11th b5"); break; - case kMaj11s5: strcat(chord, "major 11th #5"); break; - case kMaj11b9: strcat(chord, "major 11th b9"); break; - case kMaj11s9: strcat(chord, "major 11th #9"); break; - case kMaj11b13: strcat(chord, "major 11th b13"); break; - case kMaj11s13: strcat(chord, "major 11th #13"); break; - case kM11b5b9: strcat(chord, "major 11th b5 b9"); break; - case kDom11b5: strcat(chord, "dominant 11th b5"); break; - case kDom11b9: strcat(chord, "dominant 11th b9"); break; - case kDom11s9: strcat(chord, "dominant 11th #9"); break; - case kHalfDim11b9:strcat(chord, "half dim 11th b9"); break; - case kDom7s11: strcat(chord, "dominant #11"); break; - case kMin7s11: strcat(chord, "minor 7th #11"); break; - - case kDom13s11: strcat(chord, "dominant 13th #11"); break; - case kM7b913: strcat(chord, "major 7 b9 13"); break; - case kMaj7s13: strcat(chord, "major 7th #13"); break; - case kM7b9s13: strcat(chord, "major 7 b9 #13"); break; - case kDom7b13: strcat(chord, "dominant 7th b13"); break; - case kChrom: strcat(chord, "chromatic"); break; - case kNone: - default: strcat(chord, "unknown"); break; - } - - x->x_chord_bass = x->x_abs_pc[x->x_chord_root]; /* get MIDI note number of bass */ - - /* output results */ - outlet_list(x->x_outchordnotes, NULL, j, x->x_chordlist); - outlet_float(x->x_outchordinversion, x->x_chord_inversion); - outlet_symbol(x->x_outchordname, gensym(chord)); - outlet_float(x->x_outchordclass, x->x_chord_root); - outlet_float(x->x_outchordval, x->x_chord_bass); -} - -static void chord_kick_out_member(t_chord *x, t_int number, t_int *members) -{ - int *distances; - int minDistance = 1000; - int badMember = 0; - int i, j, interval; - - distances = getbytes(number*sizeof(int)); - - for (i=0; i 6) interval = 12 - interval; - // add absolute interval size to total - distances[i] += interval; - } - - // if this is the smallest total distance - if (distances[i] < minDistance) { - // remember it - minDistance = distances[i]; - badMember = i; - } - } - freebytes(distances, number * sizeof(int)); - x->x_pc[members[badMember]] = 0; // cancel out most dissonant member - chord_chord_finder(x, number-1); // call chord finder again without it - x->x_pc[members[badMember]] = 1; // replace most dissonant member -} - -static void chord_chord_finder(t_chord *x, t_int num_pcs) -{ - int i; - x->x_chord_type = kNone; - x->x_chord_root = kXX; /* none */ - switch (num_pcs) { - case 1: chord_unison(x); break; - case 2: chord_dyad(x); break; - case 3: chord_triad(x); break; - case 4: chord_quartad(x); break; - case 5: chord_quintad(x); break; - case 6: chord_sextad(x); break; - default: x->x_chord_type = kChrom; - for(i = 0; i < 12; i++) // 12 was num_pcs !? - { - if(x->x_pc[i]) - { - x->x_chord_root = i; - break; - } - } - } -} - -static void chord_float(t_chord *x, t_floatarg f) -{ - t_int velo = x->x_velo; - t_int allloc = 0; - t_int num_pc = 0; /* number of pitch classes present */ - int i, j, k, l; - - x->x_pitch = (t_int)f; - - if(x->x_pitch <= x->x_split) - { - /* first we need to put the note into the allocation table */ - if(velo == 0) /* got note-off: remove from allocation table */ - { - if(x->x_poly > 0)x->x_poly--; /* polyphony has decreased by one */ - for(i = 0; i < MAX_POLY; i++) /* search for voice allocation number */ - { - /* search for corresponding alloc number */ - if(x->x_alloctable[i] == x->x_pitch) - { - x->x_alloctable[i] = -1; /* free the alloc number */ - break; - } - /* couldn't find it ? */ - if(i == MAX_POLY - 1) - { - post("chord: no corresponding note-on found (ignored)"); - return; - } - } - return; /* no need to look for chord */ - } - else /* we got a note-on message */ - { - if(x->x_poly == MAX_POLY) - { - post("chord: too many note-on messages (ignored)"); - return; - } - - x->x_poly++; /* number of currently playing notes has increased */ - /* assign a voice allocation number */ - for(i = 0; i < MAX_POLY; i++) - { - /* search for free alloc number */ - if(x->x_alloctable[i] == -1) - { - x->x_alloctable[i] = x->x_pitch; /* ... and store pitch */ - break; - } - } - /* copy all notes into the pitch class array */ - for(i = 0; i < 12; i++) - { - x->x_pc[i] = 0; /* empty pitch class */ - x->x_abs_pc[i] = -1; /* empty absolute values */ - } - for(i = 0; i < MAX_POLY; i++) - { - /* check for presence of pitch class */ - if(x->x_alloctable[i] != -1) - { - if(!x->x_pc[x->x_alloctable[i]%12]) /* a new pitch class */ - { - x->x_abs_pc[x->x_alloctable[i]%12] = x->x_alloctable[i]; - } - else if(x->x_abs_pc[x->x_alloctable[i]%12] > x->x_alloctable[i]) /* remember lowest pitch */ - { - x->x_abs_pc[x->x_alloctable[i]%12] = x->x_alloctable[i]; - } - - x->x_pc[x->x_alloctable[i]%12] = 1; /* indicate presence of pc */ - } - } - /* count number of pitch classes */ - for(i = 0; i < 12; i++) - { - num_pc += x->x_pc[i]; - } - // post("%d pitch classes", num_pc); - } - } - - chord_chord_finder(x, num_pc); -} - -static void chord_ft1(t_chord *x, t_floatarg f) -{ - x->x_velo = (t_int)f; -} - -static t_class *chord_class; - -static void *chord_new(t_floatarg f) -{ - int i; - t_chord *x = (t_chord *)pd_new(chord_class); - inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); - x->x_outchordval = outlet_new(&x->x_ob, gensym("float")); - x->x_outchordclass = outlet_new(&x->x_ob, gensym("float")); - x->x_outchordname = outlet_new(&x->x_ob, gensym("symbol")); - x->x_outchordinversion = outlet_new(&x->x_ob, gensym("float")); - x->x_outchordnotes = outlet_new(&x->x_ob, gensym("float")); - - x->x_split = (t_int)f; - if(x->x_split == 0)x->x_split = 128; - for(i = 0; i < MAX_POLY; i++)x->x_alloctable[i] = -1; - - return (void *)x; -} - -#ifndef MAXLIB -void chord_setup(void) -{ - chord_class = class_new(gensym("chord"), (t_newmethod)chord_new, - 0, sizeof(t_chord), 0, A_DEFFLOAT, 0); -#else -void maxlib_chord_setup(void) -{ - chord_class = class_new(gensym("maxlib_chord"), (t_newmethod)chord_new, - 0, sizeof(t_chord), 0, A_DEFFLOAT, 0); -#endif - class_addfloat(chord_class, chord_float); - class_addmethod(chord_class, (t_method)chord_ft1, gensym("ft1"), A_FLOAT, 0); -#ifndef MAXLIB - - post(version); -#else - class_addcreator((t_newmethod)chord_new, gensym("chord"), A_DEFFLOAT, 0); - class_sethelpsymbol(chord_class, gensym("maxlib/chord-help.pd")); -#endif -} - +/* ------------------------- chord ------------------------------------------ */ +/* */ +/* Tries to detect a chord (or any harmonic relations) of incoming notes. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include +#include +#ifndef _WIN32 +#include +#endif + + +#define MAX_POLY 32 /* maximum number of notes played at a time */ + +#define kUnison 0 +#define kMaj 1 +#define kMin 2 +#define kDim 3 +#define kAug 4 +#define kMaj7 5 +#define kDom7 6 +#define kMin7 7 +#define kHalfDim7 8 +#define kDim7 9 +#define kMinMaj7 10 +#define kMaj7s5 11 +#define kMaj7b5 12 +#define kDom7s5 13 +#define kDom7b5 14 +#define kDomb9 15 +#define kMaj9 16 +#define kDom9 17 +#define kMin9 18 +#define kHalfDim9 19 +#define kMinMaj9 20 +#define kDimMaj9 21 +#define kMaj9b5 22 +#define kDom9b5 23 +#define kDom9b13 24 +#define kMin9s11 25 +#define kmM9b11 26 +#define kMaj7b9 27 +#define kMaj7s5b9 28 +#define kDom7b9 29 +#define kMin7b9 30 +#define kMinb9s11 31 +#define kHalfDimb9 32 +#define kDim7b9 33 +#define kMinMajb9 34 +#define kDimMajb9 35 +#define kMaj7s9 36 +#define kDom7s9 37 +#define kMaj7s11 38 +#define kMs9s11 39 +#define kHDimb11 40 +#define kMaj11 41 +#define kDom11 42 +#define kMin11 43 +#define kHalfDim11 44 +#define kDim11 45 +#define kMinMaj11 46 +#define kDimMaj11 47 +#define kMaj11b5 48 +#define kMaj11s5 49 +#define kMaj11b9 50 +#define kMaj11s9 51 +#define kMaj11b13 52 +#define kMaj11s13 53 +#define kM11b5b9 54 +#define kDom11b5 55 +#define kDom11b9 56 +#define kDom11s9 57 +#define kHalfDim11b9 58 +#define kDom7s11 59 +#define kMin7s11 60 +#define kDom13s11 61 +#define kM7b913 62 +#define kMaj7s13 63 +#define kMaj9s13 64 +#define kM7b9s13 65 +#define kDom7b13 66 +#define kChrom 67 +#define kNone 68 + +#define kXX -1 + + +static char *version = "chord v0.2, written by Olaf Matthes "; + +static char* pitch_class[13] = {"C ", "Db ", "D ", "Eb ", "E ", "F ", "Gb ", "G ", "Ab ", "A ", "Bb ", "B ", "no root "}; +static char name_class[7] = {'C', 'D', 'E', 'F', 'G', 'A', 'B'}; + +typedef struct { + int type; + int rootMember; +} t_type_root; + +typedef struct chord +{ + t_object x_ob; + t_outlet *x_outchordval; /* chord as MIDI note number of base note */ + t_outlet *x_outchordclass; /* class of chord's bass note */ + t_outlet *x_outchordname; /* chord name, e.g. "Cmajor7" */ + t_outlet *x_outchordinversion; /* inversion of the chord (root = 0, 1st = 1, 2nd = 2) */ + t_outlet *x_outchordnotes; /* list with note numbers belonging to the chord */ + + t_int x_pitch; + t_int x_pc[12]; /* pitch class array */ + t_int x_abs_pc[12]; /* pitch class array: absolute MIDI note numbers */ + t_int x_velo; + t_int x_alloctable[MAX_POLY]; /* a table used to store all playing notes */ + t_int x_poly; /* number of notes currently playing */ + t_atom x_chordlist[12]; /* list that stores the note numbers for output */ + t_int x_split; /* highes note number to process */ + + t_int x_chord_type; /* chord's type (number between 0 and 68) */ + t_int x_chord_root; /* chord's root (pitch class) */ + t_int x_chord_bass; /* chord's bass note (MIDI note number) */ + t_int x_chord_inversion; /* chord's state of inversion (root, 1st, 2nd) */ + +} t_chord; + +/* functions */ +static void chord_kick_out_member(t_chord *x, t_int number, t_int *members); +static void chord_chord_finder(t_chord *x, t_int num_pcs); +static void chord_draw_chord_type(t_chord *x, t_int num_pcs); + + +static void chord_unison(t_chord *x) +{ + int i; + int member = 0; + for(i = 0; i < 12; i++) + if(x->x_pc[i]) + { + member = i; // find pitch class + break; + } + x->x_chord_type = 0; + x->x_chord_root = member; + chord_draw_chord_type(x, 1); // output onto the screen +} + +static void chord_dyad(t_chord *x) +{ + static t_type_root dyads[11] = + {{ kMaj7, 1 }, { kDom7, 1 }, { kMin, 0 }, { kMaj, 0 }, { kMaj, 1 }, + { kDom7 , 0 }, { kMaj, 0 }, { kMaj, 1 }, { kMin, 1 }, { kDom7, 0 }, { kMaj7, 0 }}; + register t_type_root* t; + + int members[2]; + int i, j = 0; + int interval1; + + for(i = 0; i < 12; i++) + if(x->x_pc[i]) members[j++] = i; /* load members array with chord pitch classes */ + interval1 = members[1] - members[0]; /* calculate interval between first two members */ + interval1 = interval1 - 1; /* reduce interval1 to start at zero */ + t = &(dyads[interval1]); /* find TypeRoot struct for this interval */ + x->x_chord_type = t->type; + if (interval1 == 5) + x->x_chord_root = (members[0]+8)%12; + else + x->x_chord_root = members[t->rootMember]; + x->x_chord_inversion = t->rootMember; /* get state of inversion */ + chord_draw_chord_type(x, 2); /* output results */ +} + +static void chord_triad(t_chord *x) +{ + static t_type_root triads[10][10] = + {/* interval1 is a half step */ + {{ kMaj7b9, 1 }, { kMaj9, 1 }, { kMinMaj7, 1 }, { kMaj7, 1 }, { kDom7s11,2 }, + { kDomb9 , 0 }, { kMaj7, 1 }, { kMaj7s5, 1 }, { kMin9, 2 }, { kMaj7b9, 0 }}, + /* interval1 is a whole step */ + {{ kMin9, 0 }, { kDom9, 0 }, { kMin7, 1 }, { kDom7, 1 }, { kDom9, 0 }, + { kHalfDim7, 1 }, { kDom7, 1 }, { kDom9, 0 }, { kMaj9, 0 }}, + /* interval1 is a minor third */ + {{ kMaj7s5, 2 }, { kDom7, 2 }, { kDim, 0 }, { kMin, 0 }, { kMaj, 2 }, + { kDim, 2 }, { kMin7, 0 }, { kMinMaj7, 0 }}, + /* interval1 is a major third */ + {{ kMaj7, 2 }, { kHalfDim7, 2 }, { kMaj, 0 }, { kAug, 0 }, { kMin, 2 }, + { kDom7, 0 }, { kMaj7, 0 }}, + /* interval1 is a perfect fourth */ + {{ kDomb9, 1 }, { kDom9, 1 }, { kMin, 1 }, { kMaj, 1 }, { kDom9, 2 }, + { kDom7s11, 1 }}, + /* interval1 is an augmented fourth */ + {{ kDom7s11, 0 }, { kDom7, 2 }, { kDim, 1 }, { kHalfDim7, 0 }, { kDomb9, 2 }}, + /* interval1 is a perfect fifth */ + {{ kMaj7, 2 }, { kMin7, 2 }, { kDom7, 0 }, { kMaj7, 0 }}, + /* interval1 is a minor sixth */ + {{ kMinMaj7, 2 }, { kDom9, 1 }, { kMaj7s5, 0 }}, + /* interval1 is a major sixth */ + {{ kMaj9, 2 }, { kMin9, 1 }}, + /* interval1 is a minor seventh */ + {{ kMaj7b9, 2 }} + }; + register t_type_root* t; + + int members[3]; + int i, j = 0; + int interval1, interval2; + + for(i = 0; i < 12; i++) + if(x->x_pc[i]) members[j++] = i; /* load members array with chord pitch classes */ + interval1 = members[1] - members[0]; /* calculate interval between first two members */ + interval2 = members[2] - members[0]; /* calculate interval between first and third */ + interval2 = interval2 - interval1 - 1; /* reduce interval2 to start at zero */ + interval1 = interval1 - 1; /* reduce interval1 to start at zero */ + t = &(triads[interval1][interval2]); /* find TypeRoot struct for this interval vector */ + x->x_chord_type = t->type; + x->x_chord_root = members[t->rootMember]; + switch(t->rootMember) { /* get state of inversion */ + case 0: + x->x_chord_inversion = 0; + break; + case 1: + x->x_chord_inversion = 2; + break; + case 2: + x->x_chord_inversion = 1; + } + chord_draw_chord_type(x, 3); /* output onto the screen */ +} + +static void chord_quartad(t_chord *x) +{ + static t_type_root quartads[9][9][9] = + { + {/* interval1 is a half step */ + {/* interval2 is a whole step */ + { kM7b9s13, 2 }, { kMinMajb9,1 }, { kMaj7b9, 1 }, { kMaj7s13, 2 }, { kDimMajb9, 1 }, + { kMaj7b9, 1 }, { kMaj7s13, 2 }, { kM7b913, 1 }, { kM7b9s13, 1 }}, + {/* interval2 is a minor third */ + { kMinMaj9, 1 }, { kMaj9, 1 }, { kHalfDimb9,0 }, { kMin7b9, 0 }, { kMaj9, 1 }, + { kDim7b9, 0 }, { kMin7b9, 0 }, { kMinMajb9, 0 }}, + {/* interval2 is a major third */ + { kMaj7s9, 1 }, { kDom7s11, 3 }, { kDomb9, 0 }, { kMinMaj7, 1 }, { kDom7s9, 3 }, + { kDomb9, 0 }, { kMaj7b9, 0 }}, + {/* interval2 is a perfect fourth */ + { kMaj11, 1 }, { kMaj7b5, 1 }, { kMaj7, 1 }, { kMaj7s5, 1 }, { kMin9, 3 }, + { kMaj7s13, 1 }}, + {/* interval2 is a tritone */ + { kDimMaj9, 3 }, { kDom11, 3 }, { kDim7b9, 0 }, { kHalfDimb9,0 }, { kDimMajb9, 0 }}, + {/* interval2 is a perfect fifth */ + { kMaj11, 3 }, { kDom7s9, 3 }, { kDomb9, 0 }, { kMaj7b9, 0 }}, + {/* interval2 is a minor sixth */ + { kMaj7s9, 3 }, { kMin9, 3 }, { kMaj7s13, 1 }}, + {/* interval2 is a major sixth */ + { kMinMaj9, 3 }, { kM7b913, 0 }}, + {/* interval2 is a minor seventh */ + { kM7b9s13, 0 }} + }, + {/* interval1 is a whole step */ + {/* interval2 is a minor third */ + { kM7b913, 2 }, { kMin7b9, 1 }, { kDomb9, 1 }, { kMin9, 0 }, { kHalfDimb9,1 }, + { kDomb9, 1 }, { kMin9, 0 }, { kMinMaj9, 0 }}, + {/* interval2 is a major third */ + { kMin9, 1 }, { kDom9, 1 }, { kDom9, 0 }, { kDom7s5, 2 }, { kDom9, 1 }, + { kDom9, 0 }, { kMaj9, 0 }}, + {/* interval2 is a perfect fourth */ + { kDom7s9, 1 }, { kDom11, 3 }, { kHalfDim7, 1 }, { kMin7, 1 }, { kDom9, 3 }, + { kHalfDimb9,3 }}, + {/* interval2 is a tritone */ + { kDom11, 1 }, { kDom7b5, 3 }, { kDom7, 1 }, { kDom7s5, 1 }, { kMin7b9, 3 }}, + {/* interval2 is a perfect fifth */ + { kMaj7b5, 3 }, { kDom11, 1 }, { kDom9, 0 }, { kMaj9, 0 }}, + {/* interval2 is a minor sixth */ + { kDom7s11, 1 }, { kDom9, 3 }, { kDim7b9, 3 }}, + {/* interval2 is a major sixth */ + { kMaj9, 3 }, { kMin7b9, 3 }}, + {/* interval2 is a minor seventh */ + { kMinMajb9, 3 }} + }, + {/* interval1 is a minor third */ + {/* interval2 is a major third */ + { kMaj7s13, 3 }, { kDim7b9, 1 }, { kDom7s9, 0 }, { kMaj7s5, 2 }, { kDim7b9, 1 }, + { kDom7s9, 0 }, { kMaj7s9, 0 }}, + {/* interval2 is a perfect fourth */ + { kDomb9, 2 }, { kDom9, 2 }, { kMin7, 2 }, { kDom7, 2 }, { kDom11, 2 }, + { kDom7s11, 2 }}, + {/* interval2 is a tritone */ + { kDim7b9, 2 }, { kDom7, 3 }, { kDim7, 0 }, { kHalfDim7, 0 }, { kDomb9, 3 }}, + {/* interval2 is a perfect fifth */ + { kMaj7, 3 }, { kHalfDim7,3 }, { kMin7, 0 }, { kMinMaj7, 0 }}, + {/* interval2 is a minor sixth */ + { kDomb9, 2 }, { kDom9, 2 }, { kDom7s9, 2 }}, + {/* interval2 is a major sixth */ + { kHalfDimb9,2 }, { kDomb9, 3 }}, + {/* interval2 is a minor seventh */ + { kMaj7b9, 3 }} + }, + {/* interval1 is a major third */ + {/* interval2 is a perfect fourth */ + { kMaj7b9, 2 }, { kMaj9, 2 }, { kMinMaj7, 2 }, { kMaj7, 2 }, { kDom11, 0 }, + { kMaj11, 0 }}, + {/* interval2 is a tritone */ + { kHalfDimb9,2 }, { kDom7s5, 3 }, { kHalfDim7, 2 }, { kDom7b5, 0 }, { kMaj7b5, 0 }}, + {/* interval2 is a perfect fifth */ + { kMaj7s5, 3 }, { kMin7, 3 }, { kDom7, 0 }, { kMaj7, 0 }}, + {/* interval2 is a minor sixth */ + { kMinMaj7, 3 }, { kDom7s5, 0 }, { kMaj7s5, 0 }}, + {/* interval2 is a major sixth */ + { kMin7b9, 2 }, { kMin9, 2 }}, + {/* interval2 is a minor seventh */ + { kMaj7s13, 0 }} + }, + {/* interval1 is a perfect fourth */ + {/* interval2 is a tritone */ + { kDimMajb9, 2 }, { kMin7b9, 1 }, { kDomb9, 1 }, { kMaj7b5, 2 }, { kDimMaj9, 0 }}, + {/* interval2 is a perfect fifth */ + { kMin9, 1 }, { kDom9, 1 }, { kDom11, 0 }, { kDom11, 2 }}, + {/* interval2 is a minor sixth */ + { kDom7s9, 1 }, { kDom9, 3 }, { kDim7b9, 3 }}, + {/* interval2 is a major sixth */ + { kMaj9, 3 }, { kHalfDimb9,3 }}, + {/* interval2 is a minor seventh */ + { kDimMajb9, 3 }} + }, + {/* interval1 is a tritone */ + {/* interval2 is a perfect fifth */ + { kMaj7s13, 3 }, { kHalfDimb9,1 }, { kDom7s11, 0 }, { kMaj11, 2 }}, + {/* interval2 is a minor sixth */ + { kDomb9, 2 }, { kDom9, 2 }, { kDom7s9, 2 }}, + {/* interval2 is a major sixth */ + { kDim7b9, 2 }, { kDomb9, 3 }}, + {/* interval2 is a minor seventh */ + { kMaj7b9, 3 }} + }, + {/* interval1 is a perfect fifth */ + {/* interval2 is a minor sixth */ + { kMaj7b9, 2 }, { kMaj9, 2 }, { kMaj7s9, 2 }}, + {/* interval2 is a major sixth */ + { kMin7b9, 2 }, { kMin9, 2 }}, + {/* interval2 is a minor seventh */ + { kMaj7s13, 0 }} + }, + {/* interval1 is a minor sixth */ + {/* interval2 is a major sixth */ + { kMinMajb9, 2 }, { kMinMaj9, 2 }}, + {/* interval2 is a minor seventh */ + { kM7b913, 3 }} + }, + {/* interval1 is a major sixth */ + {/* interval2 is a minor seventh */ + { kM7b9s13, 2 }} + } + }; + + register t_type_root* t; + + int members[4]; + int interval1, interval2, interval3; + int i, j = 0; + for (i=0; i<12; i++) + if (x->x_pc[i]) members[j++] = i; /* load members array with chord pitch classes */ + interval1 = members[1] - members[0]; /* calculate interval between first two members */ + interval2 = members[2] - members[0]; /* calculate interval between first and third */ + interval3 = members[3] - members[0]; /* calculate interval between first and third */ + interval3 = interval3 - interval2 - 1; /* reduce interval3 to start at zero */ + interval2 = interval2 - interval1 - 1; /* reduce interval2 to start at zero */ + interval1 = interval1 - 1; /* reduce interval1 to start at zero */ + + /* find TypeRoot struct for this interval set */ + t = &(quartads[interval1][interval2][interval3]); + x->x_chord_type = t->type; + x->x_chord_root = members[t->rootMember]; + switch(t->rootMember) { /* get state of inversion */ + case 0: + x->x_chord_inversion = 0; + break; + case 1: + x->x_chord_inversion = 2; + break; + case 2: + x->x_chord_inversion = 2; + break; + case 3: + x->x_chord_inversion = 1; + } + chord_draw_chord_type(x, 4); /* output results */ +} + +static void chord_fatal_error(char* s1, char* s2) +{ + post("chord: error: %s : %s", s1, s2); +} + +static void chord_quintad(t_chord *x) +{ + static int initialized = 0; + static t_type_root quintads[8][8][8][8]; + register int i, j, k, l; + register t_type_root *t; + t_int members[5]; + int interval1, interval2, interval3, interval4; + int *st; + int maj9[5][4] = {{1,1,2,3}, {0,1,1,2}, {3,0,1,1}, {2,3,0,1}, {1,2,3,0}}; + int dom9[5][4] = {{1,1,2,2}, {1,1,1,2}, {2,1,1,1}, {2,2,1,1}, {1,2,2,1}}; + int min9[5][4] = {{1,0,3,2}, {1,1,0,3}, {2,1,1,0}, {3,2,1,1}, {0,3,2,1}}; + int had9[5][4] = {{1,0,2,3}, {1,1,0,2}, {3,1,1,0}, {2,3,1,1}, {0,2,3,1}}; + int miM9[5][4] = {{1,0,3,3}, {0,1,0,3}, {3,0,1,0}, {3,3,0,1}, {0,3,3,0}}; + int diM9[5][4] = {{1,0,2,4}, {0,1,0,2}, {4,0,1,0}, {2,4,0,1}, {0,2,4,0}}; + int M9b5[5][4] = {{1,1,1,4}, {0,1,1,1}, {4,0,1,1}, {1,4,0,1}, {1,1,4,0}}; + int D9b5[5][4] = {{1,1,1,3}, {1,1,1,1}, {3,1,1,1}, {1,3,1,1}, {1,1,3,1}}; + int mM91[5][4] = {{1,0,0,6}, {0,1,0,0}, {6,0,1,0}, {0,6,0,1}, {0,0,6,0}}; + int M7b9[5][4] = {{0,2,2,3}, {0,0,2,2}, {3,0,0,2}, {2,3,0,0}, {2,2,3,0}}; + int M5b9[5][4] = {{0,2,3,2}, {0,0,2,3}, {2,0,0,2}, {3,2,0,0}, {2,3,2,0}}; + int D7b9[5][4] = {{0,2,2,2}, {1,0,2,2}, {2,1,0,2}, {2,2,1,0}, {2,2,2,1}}; + int m7b9[5][4] = {{0,1,3,2}, {1,0,1,3}, {2,1,0,1}, {3,2,1,0}, {1,3,2,1}}; + int mb51[5][4] = {{0,1,2,0}, {4,0,1,2}, {0,4,0,1}, {2,0,4,0}, {1,2,0,4}}; + int d7b9[5][4] = {{0,1,2,3}, {1,0,1,2}, {3,1,0,1}, {2,3,1,0}, {1,2,3,1}}; + int mMb9[5][4] = {{0,1,3,3}, {0,0,1,3}, {3,0,0,1}, {3,3,0,0}, {1,3,3,0}}; + int dMb9[5][4] = {{0,1,2,4}, {0,0,1,2}, {4,0,0,1}, {2,4,0,0}, {1,2,4,0}}; + int dib9[5][4] = {{0,1,2,2}, {2,0,1,2}, {2,2,0,1}, {2,2,2,0}, {1,2,2,2}}; + int M7s9[5][4] = {{2,0,2,3}, {0,2,0,2}, {3,0,2,0}, {2,3,0,2}, {0,2,3,0}}; + int D7s9[5][4] = {{2,0,2,2}, {1,2,0,2}, {2,1,2,0}, {2,2,1,2}, {0,2,2,1}}; + int M7s1[5][4] = {{3,1,0,3}, {0,3,1,0}, {3,0,3,1}, {0,3,0,3}, {1,0,3,0}}; + int d9b3[5][4] = {{1,1,2,0}, {3,1,1,2}, {0,3,1,1}, {2,0,3,1}, {1,2,0,3}}; + int M9s3[5][4] = {{1,4,2,0}, {0,1,4,2}, {0,0,1,4}, {2,0,0,1}, {4,2,0,0}}; + int M9st[5][4] = {{1,1,5,0}, {0,1,1,5}, {0,0,1,1}, {5,0,0,1}, {1,5,0,0}}; + int s9s1[5][4] = {{2,0,1,0}, {4,2,0,1}, {0,4,2,0}, {1,0,4,2}, {0,1,0,4}}; + int h7b1[5][4] = {{2,0,1,3}, {1,2,0,1}, {3,1,2,0}, {1,3,1,2}, {0,1,3,1}}; + int M711[5][4] = {{3,0,1,3}, {0,3,0,1}, {3,0,3,0}, {1,3,0,3}, {0,1,3,0}}; + int M115[5][4] = {{1,1,0,5}, {0,1,1,0}, {5,0,1,1}, {0,5,0,1}, {1,0,5,0}}; + int d711[5][4] = {{3,0,1,2}, {1,3,0,1}, {2,1,3,0}, {1,2,1,3}, {0,1,2,1}}; + int d712[5][4] = {{1,1,0,1}, {4,1,1,0}, {1,4,1,1}, {0,1,4,1}, {1,0,1,4}}; + int d713[5][4] = {{1,1,0,4}, {1,1,1,0}, {4,1,1,1}, {0,4,1,1}, {1,0,4,1}}; + int m711[5][4] = {{2,1,1,2}, {1,2,1,1}, {2,1,2,1}, {1,2,1,2}, {1,1,2,1}}; + int m712[5][4] = {{1,0,1,1}, {4,1,0,1}, {1,4,1,0}, {1,1,4,1}, {0,1,1,4}}; + int di11[5][4] = {{1,0,1,0}, {5,1,0,1}, {0,5,1,0}, {1,0,5,1}, {0,1,0,5}}; + int mM11[5][4] = {{2,1,1,3}, {0,2,1,1}, {3,0,2,1}, {1,3,0,2}, {1,1,3,0}}; + int dM11[5][4] = {{2,1,0,4}, {0,2,1,0}, {4,0,2,1}, {0,4,0,2}, {1,0,4,0}}; + int Meb5[5][4] = {{3,0,0,4}, {0,3,0,0}, {4,0,3,0}, {0,4,0,3}, {0,0,4,0}}; + int Mes5[5][4] = {{3,0,2,2}, {0,3,0,2}, {2,0,3,0}, {2,2,0,3}, {0,2,2,0}}; + int Meb9[5][4] = {{0,2,0,5}, {0,0,2,0}, {5,0,0,2}, {0,5,0,0}, {2,0,5,0}}; + int Mes9[5][4] = {{2,0,0,5}, {0,2,0,0}, {5,0,2,0}, {0,5,0,2}, {0,0,5,0}}; + int Deb5[5][4] = {{3,0,0,3}, {1,3,0,0}, {3,1,3,0}, {0,3,1,3}, {0,0,3,1}}; + int Mes3[5][4] = {{3,0,4,0}, {0,3,0,4}, {0,0,3,0}, {4,0,0,3}, {0,4,0,0}}; + int Deb9[5][4] = {{0,2,0,4}, {1,0,2,0}, {4,1,0,2}, {0,4,1,0}, {2,0,4,1}}; + int De91[5][4] = {{0,2,0,1}, {4,0,2,0}, {1,4,0,2}, {0,1,4,0}, {2,0,1,4}}; + int Des9[5][4] = {{2,0,0,4}, {1,2,0,0}, {4,1,2,0}, {0,4,1,2}, {0,0,4,1}}; + int Ds11[5][4] = {{3,1,0,2}, {1,3,1,0}, {2,1,3,1}, {0,2,1,3}, {1,0,2,1}}; + int m7s1[5][4] = {{2,2,0,2}, {1,2,2,0}, {2,1,2,2}, {0,2,1,2}, {2,0,2,1}}; + int D3s1[5][4] = {{5,0,1,0}, {1,5,0,1}, {0,1,5,0}, {1,0,1,5}, {0,1,0,1}}; + int Mb9s[5][4] = {{0,2,5,0}, {0,0,2,5}, {0,0,0,2}, {5,0,0,0}, {2,5,0,0}}; + int D7b3[5][4] = {{3,2,0,1}, {1,3,2,0}, {1,1,3,2}, {0,1,1,3}, {2,0,1,1}}; + + if (!initialized) { + for (i=0; i<8; i++) + for (j=0; j<8; j++) + for (k=0; k<8; k++) + for (l=0; l<8; l++) { + quintads[i][j][k][l].type = kNone; + quintads[i][j][k][l].rootMember = kXX; + } + + + // major ninths + for (i=0; i<5; i++) { + st = maj9[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + t->type = kMaj9; + t->rootMember = i; + } + + // dominant ninths + for (i=0; i<5; i++) { + st = dom9[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "dom9"); + t->type = kDom9; + t->rootMember = i; + } + + // minor ninths + for (i=0; i<5; i++) { + st = min9[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "min9"); + t->type = kMin9; + t->rootMember = i; + } + + // half diminished ninths + for (i=0; i<5; i++) { + st = had9[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "had9"); + t->type = kHalfDim9; + t->rootMember = i; + } + + // minor/major ninths + for (i=0; i<5; i++) { + st = miM9[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "miM9"); + t->type = kMinMaj9; + t->rootMember = i; + } + + // diminished/major ninths + for (i=0; i<5; i++) { + st = diM9[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "diM9"); + t->type = kDimMaj9; + t->rootMember = i; + } + + // major ninth flat 5 + for (i=0; i<5; i++) { + st = M9b5[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "M9b5"); + t->type = kMaj9b5; + t->rootMember = i; + } + + // dominant ninth flat 5 + for (i=0; i<5; i++) { + st = D9b5[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "D9b5"); + t->type = kDom9b5; + t->rootMember = i; + } + + // minor/major ninth flat 11 + for (i=0; i<5; i++) { + st = mM91[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "mM91"); + t->type = kmM9b11; + t->rootMember = i; + } + + // major seventh flat nine + for (i=0; i<5; i++) { + st = M7b9[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "M7b9"); + t->type = kMaj7b9; + t->rootMember = i; + } + + // major seventh sharp five flat nine + for (i=0; i<5; i++) { + st = M5b9[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "M5b9"); + t->type = kMaj7s5b9; + t->rootMember = i; + } + + // dominant seventh flat nine + for (i=0; i<5; i++) { + st = D7b9[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "D7b9"); + t->type = kDom7b9; + t->rootMember = i; + } + + // minor seventh flat nine + for (i=0; i<5; i++) { + t = &(quintads[m7b9[i][0]][m7b9[i][1]][m7b9[i][2]][m7b9[i][3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "m7b9"); + t->type = kMin7b9; + t->rootMember = i; + } + + // minor flat nine sharp eleventh + for (i=0; i<5; i++) { + st = mb51[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "mb51"); + t->type = kMinb9s11; + t->rootMember = i; + } + + // half diminished seventh flat nine + for (i=0; i<5; i++) { + st = d7b9[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "d7b9"); + t->type = kHalfDimb9; + t->rootMember = i; + } + + // minor/major seventh flat nine + for (i=0; i<5; i++) { + st = mMb9[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "mMb9"); + t->type = kMinMajb9; + t->rootMember = i; + } + + // diminished major seventh flat nine + for (i=0; i<5; i++) { + st = dMb9[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "dMb9"); + t->type = kDimMajb9; + t->rootMember = i; + } + + // diminished seventh flat nine + for (i=0; i<5; i++) { + t = &(quintads[dib9[i][0]][dib9[i][1]][dib9[i][2]][dib9[i][3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "dib9"); + t->type = kDim7b9; + t->rootMember = i; + } + + // major seventh sharp nine + for (i=0; i<5; i++) { + t = &(quintads[M7s9[i][0]][M7s9[i][1]][M7s9[i][2]][M7s9[i][3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "M7s9"); + t->type = kMaj7s9; + t->rootMember = i; + } + + // dominant seventh sharp nine + for (i=0; i<5; i++) { + t = &(quintads[D7s9[i][0]][D7s9[i][1]][D7s9[i][2]][D7s9[i][3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "D7s9"); + t->type = kDom7s9; + t->rootMember = i; + } + + // major seventh sharp eleventh + for (i=0; i<5; i++) { + t = &(quintads[M7s1[i][0]][M7s1[i][1]][M7s1[i][2]][M7s1[i][3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "M7s1"); + t->type = kMaj7s11; + t->rootMember = i; + } + + // dominant ninth flat thirteenth + for (i=0; i<5; i++) { + st = d9b3[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "d9b3"); + t->type = kDom9b13; + t->rootMember = i; + } + + // major ninth sharp thirteenth + for (i=0; i<5; i++) { + st = M9s3[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "M9s3"); + t->type = kMaj9s13; + t->rootMember = i; + } + + // major ninth sharp thirteenth + for (i=0; i<5; i++) { + t = &(quintads[M9st[i][0]][M9st[i][1]][M9st[i][2]][M9st[i][3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "M9st"); + t->type = kMaj9s13; + t->rootMember = i; + } + + // major chord sharp ninth sharp eleventh + for (i=0; i<5; i++) { + st = s9s1[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "s9s1"); + t->type = kMs9s11; + t->rootMember = i; + } + + // half diminished seven flat 11 + for (i=0; i<5; i++) { + st = h7b1[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "h7b1"); + t->type = kHDimb11; + t->rootMember = i; + } + + // major eleventh + for (i=0; i<5; i++) { + t = &(quintads[M711[i][0]][M711[i][1]][M711[i][2]][M711[i][3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "M711"); + t->type = kMaj11; + t->rootMember = i; + } + + // major eleventh + for (i=0; i<5; i++) { + t = &(quintads[M115[i][0]][M115[i][1]][M115[i][2]][M115[i][3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "M711"); + t->type = kMaj11; + t->rootMember = i; + } + + // dominant eleventh + for (i=0; i<5; i++) { + t = &(quintads[d711[i][0]][d711[i][1]][d711[i][2]][d711[i][3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "d711"); + t->type = kDom11; + t->rootMember = i; + } + + // dominant eleventh + for (i=0; i<5; i++) { + t = &(quintads[d712[i][0]][d712[i][1]][d712[i][2]][d712[i][3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "d712"); + t->type = kDom11; + t->rootMember = i; + } + + // dominant eleventh + for (i=0; i<5; i++) { + st = d713[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "d713"); + t->type = kDom11; + t->rootMember = i; + } + + // minor eleventh + for (i=0; i<5; i++) { + t = &(quintads[m711[i][0]][m711[i][1]][m711[i][2]][m711[i][3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "m711"); + t->type = kMin11; + t->rootMember = i; + } + + // minor eleventh + for (i=0; i<5; i++) { + t = &(quintads[m712[i][0]][m712[i][1]][m712[i][2]][m712[i][3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "m712"); + t->type = kMin11; + t->rootMember = i; + } + + // diminished eleventh + for (i=0; i<5; i++) { + st = di11[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "di11"); + t->type = kDim11; + t->rootMember = i; + } + + // minor/major eleventh + for (i=0; i<5; i++) { + st = mM11[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "mM11"); + t->type = kMinMaj11; + t->rootMember = i; + } + + // diminished major eleventh + for (i=0; i<5; i++) { + st = dM11[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "dM11"); + t->type = kDimMaj11; + t->rootMember = i; + } + + // major eleventh flat fifth + for (i=0; i<5; i++) { + st = Meb5[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "Meb5"); + t->type = kMaj11b5; + t->rootMember = i; + } + + // major eleventh sharp fifth + for (i=0; i<5; i++) { + st = Mes5[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "Mes5"); + t->type = kMaj11s5; + t->rootMember = i; + } + + // major eleventh flat ninth + for (i=0; i<5; i++) { + st = Meb9[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "Meb9"); + t->type = kMaj11b9; + t->rootMember = i; + } + + // major eleventh sharp ninth + for (i=0; i<5; i++) { + st = Mes9[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "Mes9"); + t->type = kMaj11s9; + t->rootMember = i; + } + + // major eleventh sharp thirteenth + for (i=0; i<5; i++) { + st = Mes3[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "Mes3"); + t->type = kMaj11s13; + t->rootMember = i; + } + + // dominant eleventh flat fifth + for (i=0; i<5; i++) { + st = Deb5[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "Deb5"); + t->type = kDom11b5; + t->rootMember = i; + } + + // dominant eleventh flat ninth + for (i=0; i<5; i++) { + st = Deb9[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "Deb9"); + t->type = kDom11b9; + t->rootMember = i; + } + + // dominant eleventh flat ninth + for (i=0; i<5; i++) { + st = De91[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "De91"); + t->type = kDom11b9; + t->rootMember = i; + } + + // dominant eleventh sharp ninth + for (i=0; i<5; i++) { + st = Des9[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "Des9"); + t->type = kDom11s9; + t->rootMember = i; + } + + // dominant seventh sharp eleventh + for (i=0; i<5; i++) { + st = Ds11[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "Ds11"); + t->type = kDom7s11; + t->rootMember = i; + } + + // minor seventh sharp eleventh + for (i=0; i<5; i++) { + st = m7s1[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "m7s1"); + t->type = kMin7s11; + t->rootMember = i; + } + + // dominant thirteenth sharp eleventh + for (i=0; i<5; i++) { + st = D3s1[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "D3s1"); + t->type = kDom13s11; + t->rootMember = i; + } + + // major seventh flat ninth sharp thirteenth + for (i=0; i<5; i++) { + st = Mb9s[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "Mb9s"); + t->type = kM7b9s13; + t->rootMember = i; + } + + // dominant seventh flat thirteenth + for (i=0; i<5; i++) { + st = D7b3[i]; + t = &(quintads[st[0]][st[1]][st[2]][st[3]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "D7b3"); + t->type = kDom7b13; + t->rootMember = i; + } + + initialized = 1; + return; + } + + j = 0; + for (i=0; i<12; i++) + if (x->x_pc[i]) members[j++] = i; /* load members array with chord pitch classes */ + interval1 = members[1] - members[0]; /* calculate interval between first two members */ + interval2 = members[2] - members[0]; /* calculate interval between first and third */ + interval3 = members[3] - members[0]; /* calculate interval between first and third */ + interval4 = members[4] - members[0]; /* calculate interval between first and fourth */ + interval4 = interval4 - interval3 - 1; /* reduce interval4 to start at zero */ + interval3 = interval3 - interval2 - 1; /* reduce interval3 to start at zero */ + interval2 = interval2 - interval1 - 1; /* reduce interval2 to start at zero */ + interval1 = interval1 - 1; /* reduce interval1 to start at zero */ + + // find TypeRoot struct for this interval set + t = &(quintads[interval1][interval2][interval3][interval4]); + if (t->rootMember != kXX) + { + x->x_chord_type = t->type; + x->x_chord_root = members[t->rootMember]; + switch(t->rootMember) { /* get state of inversion */ + case 0: + x->x_chord_inversion = 0; + break; + case 1: + x->x_chord_inversion = 2; + break; + case 2: + x->x_chord_inversion = 2; + break; + case 3: + x->x_chord_inversion = 2; + break; + case 4: + x->x_chord_inversion = 1; + } + chord_draw_chord_type(x, 5); /* output result */ + } else + chord_kick_out_member(x, 5, members); +} + +static void chord_sextad(t_chord *x) +{ + static int initialized = 0; + static t_type_root sextads[7][7][7][7][7]; + register int i, j, k, l, m; + register t_type_root *t; + register int* st; + t_int members[6]; + int interval1, interval2, interval3, interval4, interval5; + + int D9b3[6][5] = + {{1,1,2,0,1}, {1,1,1,2,0}, {1,1,1,1,2}, {0,1,1,1,1}, {2,0,1,1,1}, {1,2,0,1,1}}; + int m9s1[6][5] = + {{1,0,2,0,2}, {1,1,0,2,0}, {2,1,1,0,2}, {0,2,1,1,0}, {2,0,2,1,1}, {0,2,0,2,1}}; + int M711[6][5] = + {{1,1,0,1,3}, {0,1,1,0,1}, {3,0,1,1,0}, {1,3,0,1,1}, {0,1,3,0,1}, {1,0,1,3,0}}; + int D711[6][5] = + {{1,1,0,1,2}, {1,1,1,0,1}, {2,1,1,1,0}, {1,2,1,1,1}, {0,1,2,1,1}, {1,0,1,2,1}}; + int hd11[6][5] = + {{1,0,1,0,3}, {1,1,0,1,0}, {3,1,1,0,1}, {0,3,1,1,0}, {1,0,3,1,1}, {0,1,0,3,1}}; + int M1b5[6][5] = + {{1,1,0,0,4}, {0,1,1,0,0}, {4,0,1,1,0}, {0,4,0,1,1}, {0,0,4,0,1}, {1,0,0,4,0}}; + int M159[6][5] = + {{0,2,0,0,4}, {0,0,2,0,0}, {4,0,0,2,0}, {0,4,0,0,2}, {0,0,4,0,0}, {2,0,0,4,0}}; + int M1s3[6][5] = + {{1,1,0,4,0}, {0,1,1,0,4}, {0,0,1,1,0}, {4,0,0,1,1}, {0,4,0,0,1}, {1,0,4,0,0}}; + int hd19[6][5] = + {{0,1,1,0,3}, {1,0,1,1,0}, {3,1,0,1,1}, {0,3,1,0,1}, {1,0,3,1,0}, {1,1,0,3,1}}; + int M1b3[6][5] = + {{3,0,1,0,2}, {0,3,0,1,0}, {2,0,3,0,1}, {0,2,0,3,0}, {1,0,2,0,3}, {0,1,0,2,0}}; + int D1b5[6][5] = + {{1,1,0,0,3}, {1,1,1,0,0}, {3,1,1,1,0}, {0,3,1,1,1}, {0,0,3,1,1}, {1,0,0,3,1}}; + int D1s9[6][5] = + {{2,0,0,1,2}, {1,2,0,0,1}, {2,1,2,0,0}, {1,2,1,2,0}, {0,1,2,1,2}, {0,0,1,2,1}}; + int m791[6][5] = + {{0,1,2,0,2}, {1,0,1,2,0}, {2,1,0,1,2}, {0,2,1,0,1}, {2,0,2,1,0}, {1,2,0,2,1}}; + int d7s1[6][5] = + {{1,1,1,0,2}, {1,1,1,1,0}, {2,1,1,1,1}, {0,2,1,1,1}, {1,0,2,1,1}, {1,1,0,2,1}}; + int d3s1[6][5] = + {{3,1,0,1,0}, {1,3,1,0,1}, {0,1,3,1,0}, {1,0,1,3,1}, {0,1,0,1,3}, {1,0,1,0,1}}; + + + if (!initialized) { + for (i=0; i<7; i++) + for (j=0; j<7; j++) + for (k=0; k<7; k++) + for (l=0; l<7; l++) + for (m=0; m<7; m++) { + sextads[i][j][k][l][m].type = kNone; + sextads[i][j][k][l][m].rootMember = kXX; + } + + // dominant ninth flat thirteen + for (i=0; i<6; i++) { + st = D9b3[i]; + t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "D9b3"); + t->type = kDom9b13; + t->rootMember = i; + } + + // minor ninth sharp eleventh + for (i=0; i<6; i++) { + st = m9s1[i]; + t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "m9s1"); + t->type = kMin9s11; + t->rootMember = i; + } + + // major eleventh + for (i=0; i<6; i++) { + st = M711[i]; + t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "M711"); + t->type = kMaj11; + t->rootMember = i; + } + + // dominant eleventh + for (i=0; i<6; i++) { + st = D711[i]; + t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "D711"); + t->type = kDom11; + t->rootMember = i; + } + + // half diminished eleventh + for (i=0; i<6; i++) { + st = hd11[i]; + t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "hd11"); + t->type = kHalfDim11; + t->rootMember = i; + } + + // major eleventh flat 5 + for (i=0; i<6; i++) { + st = M1b5[i]; + t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "M1b5"); + t->type = kMaj11b5; + t->rootMember = i; + } + + // major eleventh flat 5 flat 9 + for (i=0; i<6; i++) { + st = M159[i]; + t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "M159"); + t->type = kM11b5b9; + t->rootMember = i; + } + + // major eleventh sharp 13 + for (i=0; i<6; i++) { + st = M1s3[i]; + t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "M1s3"); + t->type = kMaj11s13; + t->rootMember = i; + } + + // half diminished eleventh flat 9 + for (i=0; i<6; i++) { + st = hd19[i]; + t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "hd19"); + t->type = kHalfDim11b9; + t->rootMember = i; + } + + // major eleventh flat 13 + for (i=0; i<6; i++) { + st = M1b3[i]; + t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "M1b3"); + t->type = kMaj11b13; + t->rootMember = i; + } + + // dominant eleventh flat five + for (i=0; i<6; i++) { + st = D1b5[i]; + t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "D1b5"); + t->type = kDom11b5; + t->rootMember = i; + } + + // dominant eleventh sharp nine + for (i=0; i<6; i++) { + st = D1s9[i]; + t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "D1s9"); + t->type = kDom11s9; + t->rootMember = i; + } + + // minor seventh flat 9 sharp 11 + for (i=0; i<6; i++) { + st = m791[i]; + t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "m791"); + t->type = kMinb9s11; + t->rootMember = i; + } + + // dominant seventh sharp 11 + for (i=0; i<6; i++) { + st = d7s1[i]; + t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "d7s1"); + t->type = kDom7s11; + t->rootMember = i; + } + + // dominant thirteenth sharp 11 + for (i=0; i<6; i++) { + st = d3s1[i]; + t = &(sextads[st[0]][st[1]][st[2]][st[3]][st[4]]); + if (t->type != kNone) chord_fatal_error("redefining chord", "d3s1"); + t->type = kDom13s11; + t->rootMember = i; + } + + initialized = 1; + return; + } + + j = 0; + for (i=0; i<12; i++) + if (x->x_pc[i]) members[j++] = i; // load members array with chord pitch classes + interval1 = members[1] - members[0]; // calculate interval between first two members + interval2 = members[2] - members[0]; // calculate interval between first and third + interval3 = members[3] - members[0]; // calculate interval between first and third + interval4 = members[4] - members[0]; // calculate interval between first and fourth + interval5 = members[5] - members[0]; // calculate interval between first and fifth + interval5 = interval5 - interval4 - 1; // reduce interval5 to start at zero + interval4 = interval4 - interval3 - 1; // reduce interval4 to start at zero + interval3 = interval3 - interval2 - 1; // reduce interval3 to start at zero + interval2 = interval2 - interval1 - 1; // reduce interval2 to start at zero + interval1 = interval1 - 1; // reduce interval1 to start at zero + + // find TypeRoot struct for this interval set + t = &(sextads[interval1][interval2][interval3][interval4][interval5]); + if (t->rootMember != kXX) { + x->x_chord_type = t->type; + x->x_chord_root = members[t->rootMember]; + switch(t->rootMember) { /* get state of inversion */ + case 0: + x->x_chord_inversion = 0; + break; + case 1: + x->x_chord_inversion = 2; + break; + case 2: + x->x_chord_inversion = 2; + break; + case 3: + x->x_chord_inversion = 2; + break; + case 4: + x->x_chord_inversion = 2; + break; + case 5: x->x_chord_inversion = 1; + } + chord_draw_chord_type(x, 6); // output onto the screen + } else + chord_kick_out_member(x, 6, members); +} + +static int chord_accidental(t_int pc) +{ + switch (pc) { + case 0: + case 2: + case 4: + case 5: + case 7: + case 9: + case 11: return 0; + case 1: + case 3: + case 6: + case 8: + case 10: + default: return 1; + } +} + +static int chord_name_third(t_chord *x, char* chord, int c, int rootName) +{ + int third = (x->x_chord_root+4)%12; // look for major third + if (x->x_pc[third]) { // if one is there + x->x_pc[third] = 0; // erase from pcs array + chord[c++] = name_class[(rootName+2)%7]; + if (chord_accidental(third)) { // if it has an chord_accidental + // make it a flat if the root also has an chord_accidental + if (chord_accidental(x->x_chord_root)) + chord[c++] = 'b'; + // otherwise make it a sharp + else + chord[c++] = '#'; + } + chord[c++] = ' '; + return c; // return if major third found + } + + third = (x->x_chord_root+3)%12; // no major, look for minor third + if (x->x_pc[third]) { // if one is there + x->x_pc[third] = 0; // erase from pcs array + chord[c++] = name_class[(rootName+2)%7]; + if (chord_accidental(third)) // if it has an chord_accidental + chord[c++] = 'b'; else // make it a flat + if (chord_accidental(x->x_chord_root)) { // if the root has an chord_accidental + chord[c++] = 'b'; // make the third a flat + if (chord[0] == 'G') // if the root is Gb + chord[c++] = 'b'; // this must be Bbb + } + chord[c++] = ' '; + return c; + } + + return c; // if we get here there was no third +} + +static int chord_name_fifth(t_chord *x, char* chord, int c, int rootName) +{ + int fifth = (x->x_chord_root+7)%12; + if (x->x_pc[fifth]) { + x->x_pc[fifth] = 0; + chord[c++] = name_class[(rootName+4)%7]; + if (chord_accidental(fifth)) { + if (chord_accidental(x->x_chord_root)) chord[c++] = 'b'; + else chord[c++] = '#'; + } + chord[c++] = ' '; + return c; + } + + fifth = (x->x_chord_root+6)%12; + if (x->x_pc[fifth]) { + x->x_pc[fifth] = 0; + chord[c++] = name_class[(rootName+4)%7]; + if (chord[0] != 'B') chord[c++] = 'b'; + if (chord_accidental(x->x_chord_root)) chord[c++] = 'b'; + chord[c++] = ' '; + return c; + } + + fifth = (x->x_chord_root+8)%12; + if (x->x_pc[fifth]) { + x->x_pc[fifth] = 0; + chord[c++] = name_class[(rootName+4)%7]; + if (chord_accidental(fifth)) chord[c++] = '#'; else + if (!chord_accidental(x->x_chord_root)) { + chord[c++] = '#'; + if (chord[0] == 'B') + chord[c++] = '#'; + } + chord[c++] = ' '; + return c; + } + + return c; +} + +static int chord_name_seventh(t_chord *x, char* chord, int c, int rootName) +{ + int seventh = (x->x_chord_root+11)%12; + if (x->x_pc[seventh]) { + x->x_pc[seventh] = 0; + chord[c++] = name_class[(rootName+6)%7]; + if (chord_accidental(seventh)) chord[c++] = '#'; + chord[c++] = ' '; + return c; + } + seventh = (x->x_chord_root+10)%12; + if (x->x_pc[seventh]) { + x->x_pc[seventh] = 0; + chord[c++] = name_class[(rootName+6)%7]; + if (chord_accidental(seventh) || chord_accidental(x->x_chord_root)) + chord[c++] = 'b'; + chord[c++] = ' '; + return c; + } + seventh = (x->x_chord_root+9)%12; + if (x->x_pc[seventh]) { + x->x_pc[seventh] = 0; + chord[c++] = name_class[(rootName+6)%7]; + chord[c++] = 'b'; + if (chord_accidental(x->x_chord_root)) chord[c++] = 'b'; else + if (chord_accidental((seventh+1)%12)) chord[c++] = 'b'; + chord[c++] = ' '; + return c; + } + return c; +} + +static int chord_name_ninth(t_chord *x, char* chord, int c, int rootName) +{ + int ninth = (x->x_chord_root+2)%12; + if (x->x_pc[ninth]) { + x->x_pc[ninth] = 0; + chord[c++] = name_class[(rootName+1)%7]; + if (chord_accidental(ninth)) { + if (chord_accidental(x->x_chord_root)) chord[c++] = 'b'; + else chord[c++] = '#'; + } + chord[c++] = ' '; + return c; + } + + ninth = (x->x_chord_root+1)%12; + if (x->x_pc[ninth]) { + x->x_pc[ninth] = 0; + chord[c++] = name_class[(rootName+1)%7]; + if (chord_accidental(ninth)) chord[c++] = 'b'; + else { + if (chord_accidental(x->x_chord_root)) { + chord[c++] = 'b'; + if ((x->x_chord_root == 1) || (x->x_chord_root == 6) || (x->x_chord_root == 8)) + chord[c++] = 'b'; + } + } + chord[c++] = ' '; + return c; + } + + ninth = (x->x_chord_root+3)%12; + if (x->x_pc[ninth]) { + x->x_pc[ninth] = 0; + chord[c++] = name_class[(rootName+1)%7]; + if (chord_accidental(ninth)) chord[c++] = '#'; else + if (!chord_accidental(x->x_chord_root)) { + chord[c++] = '#'; + if (chord_accidental((x->x_chord_root+2)%12)) + chord[c++] = '#'; + } + chord[c++] = ' '; + return c; + } + + return c; +} + +static int chord_name_eleventh(t_chord *x, char* chord, int c, int rootName) +{ + int eleventh = (x->x_chord_root+5)%12; + if (x->x_pc[eleventh]) { + x->x_pc[eleventh] = 0; + chord[c++] = name_class[(rootName+3)%7]; + if (chord_accidental(eleventh)) chord[c++] = 'b'; else + if (chord_accidental(x->x_chord_root)) chord[c++] = 'b'; + chord[c++] = ' '; + return c; + } + + eleventh = (x->x_chord_root+6)%12; + if (x->x_pc[eleventh]) { + x->x_pc[eleventh] = 0; + chord[c++] = name_class[(rootName+3)%7]; + if (chord_accidental(eleventh)) chord[c++] = '#'; else + if ((!chord_accidental(x->x_chord_root)) && (x->x_chord_root == 11)) + chord[c++] = '#'; + chord[c++] = ' '; + return c; + } + + return c; +} + +static int chord_name_thirteenth(t_chord *x, char* chord, int c, int rootName) +{ + int thirteenth = (x->x_chord_root+9)%12; + if (x->x_pc[thirteenth]) { + x->x_pc[thirteenth] = 0; + chord[c++] = name_class[(rootName+5)%7]; + if (chord_accidental(thirteenth)) { + if (chord_accidental(x->x_chord_root)) + chord[c++] = 'b'; + else + chord[c++] = '#'; + } + + chord[c++] = ' '; + return c; + } + + thirteenth = (x->x_chord_root+10)%12; + if (x->x_pc[thirteenth]) { + x->x_pc[thirteenth] = 0; + chord[c++] = name_class[(rootName+5)%7]; + if (chord_accidental(thirteenth)) chord[c++] = '#'; else + if (!chord_accidental(x->x_chord_root)) { + chord[c++] = '#'; + if (chord_accidental((x->x_chord_root+9)%12)) + chord[c++] = '#'; + } + chord[c++] = ' '; + return c; + } + + thirteenth = (x->x_chord_root+8)%12; + if (x->x_pc[thirteenth]) { + x->x_pc[thirteenth] = 0; + chord[c++] = name_class[(rootName+5)%7]; + if (chord_accidental(thirteenth)) chord[c++] = 'b'; else + if (chord_accidental(x->x_chord_root)) { + chord[c++] = 'b'; + if (chord_accidental(x->x_chord_root+9)%12) + chord[c++] = 'b'; + } + chord[c++] = ' '; + return c; + } + + return c; +} + + + +static void chord_spell_chord(t_chord *x, char *chord, t_int num_pcs) +{ + int rootName = 0; // keep index of root name class + int c = 0; // pointer to current character + int named = 0; // how many members have been named + int mark; + int i; + + // use chordRoot to set rootName index and store characters for name + switch (x->x_chord_root) + { + case 0: chord[c++] = name_class[rootName=0]; break; + case 1: chord[c++] = name_class[rootName=1]; + chord[c++] = 'b'; break; + case 2: chord[c++] = name_class[rootName=1]; break; + case 3: chord[c++] = name_class[rootName=2]; + chord[c++] = 'b'; break; + case 4: chord[c++] = name_class[rootName=2]; break; + case 5: chord[c++] = name_class[rootName=3]; break; + case 6: chord[c++] = name_class[rootName=4]; + chord[c++] = 'b'; break; + case 7: chord[c++] = name_class[rootName=4]; break; + case 8: chord[c++] = name_class[rootName=5]; + chord[c++] = 'b'; break; + case 9: chord[c++] = name_class[rootName=5]; break; + case 10: chord[c++] = name_class[rootName=6]; + chord[c++] = 'b'; break; + case 11: chord[c++] = name_class[rootName=6]; break; + default: break; + } + x->x_pc[x->x_chord_root] = 0; /* set this member to zero */ + + chord[c++] = ' '; // insert space + if (++named == num_pcs) { // if everything is named + chord[c] = '\0'; // terminate the string + return; // and return + } + + mark = c; // use mark to see if new names are added + for (i=0; i<6; i++) { + // advance search by thirds + switch (i) { + case 0: mark = chord_name_third (x, chord, c, rootName); break; + case 1: mark = chord_name_fifth (x, chord, c, rootName); break; + case 2: mark = chord_name_seventh (x, chord, c, rootName); break; + case 3: mark = chord_name_ninth (x, chord, c, rootName); break; + case 4: mark = chord_name_eleventh (x, chord, c, rootName); break; + case 5: mark = chord_name_thirteenth(x, chord, c, rootName); break; + } + if (mark != c) { // if new name is added + ++named; // increment count of named members + c = mark; // update character pointer + } + if (named == num_pcs) { // if everything is named + chord[c] = '\0'; // terminate the string + return; // and return + } + } + + chord[c] = '\0'; +} + + +static void chord_draw_chord_type(t_chord *x, t_int num_pcs) +{ + char chord[255]; /* output string */ + int i, j; + + /* get members of chord */ + j = 0; + for(i = 0; i < 12; i++) + { + if(x->x_pc[i]) + { + SETFLOAT(x->x_chordlist+j, x->x_abs_pc[i]); + j++; + } + } + + if (x->x_chord_type != kNone) + { + chord_spell_chord(x, chord, num_pcs); /* spell chord members */ + } + else + { + post("going..."); + chord[0] = '\0'; + for(i = 0; i < 12; i++) + if (x->x_pc[i]) + strcat(chord, pitch_class[i]); /* output single notes */ + post("did it"); + } + + strcat(chord, ": "); + strcat(chord, pitch_class[x->x_chord_root]); + + /* append name of chord type */ + switch (x->x_chord_type) { + case kUnison: strcat(chord, "unison"); break; + case kMaj: strcat(chord, "major"); break; + case kMin: strcat(chord, "minor"); break; + case kDim: strcat(chord, "diminished"); break; + case kAug: strcat(chord, "augmented"); break; + + case kMaj7: strcat(chord, "major 7th"); break; + case kDom7: strcat(chord, "dominant 7th"); break; + case kMin7: strcat(chord, "minor 7th"); break; + case kHalfDim7: strcat(chord, "half diminished 7th"); break; + case kDim7: strcat(chord, "diminished 7th"); break; + case kMinMaj7: strcat(chord, "minor/major 7th"); break; + + case kMaj7s5: strcat(chord, "major 7th #5"); break; + case kMaj7b5: strcat(chord, "major 7th b5"); break; + case kDom7s5: strcat(chord, "dominant 7th #5"); break; + case kDom7b5: strcat(chord, "dominant 7th b5"); break; + case kDomb9: strcat(chord, "dominant b9"); break; + + case kMaj9: strcat(chord, "major 9th"); break; + case kDom9: strcat(chord, "dominant 9th"); break; + case kMin9: strcat(chord, "minor 9th"); break; + case kHalfDim9: strcat(chord, "half diminished 9th"); break; + case kMinMaj9: strcat(chord, "minor major 9th"); break; + case kDimMaj9: strcat(chord, "diminished major 9th");break; + case kMaj9b5: strcat(chord, "major 9th b5"); break; + case kDom9b5: strcat(chord, "dominant 9th b5"); break; + case kDom9b13: strcat(chord, "dominant 9th b13"); break; + case kMin9s11: strcat(chord, "minor 9th #11"); break; + case kmM9b11: strcat(chord, "minor/maj 9th b11"); break; + + case kMaj7b9: strcat(chord, "major 7th b9"); break; + case kMaj7s5b9: strcat(chord, "major 7th #5 b9"); break; + case kDom7b9: strcat(chord, "dominant 7th b9"); break; + case kMin7b9: strcat(chord, "minor 7th b9"); break; + case kMinb9s11: strcat(chord, "minor b9 #11"); break; + case kHalfDimb9:strcat(chord, "half diminished b9"); break; + case kDim7b9: strcat(chord, "diminished b9"); break; + case kMinMajb9: strcat(chord, "minor/major b9"); break; + case kDimMajb9: strcat(chord, "diminished M7 b9"); break; + + case kMaj7s9: strcat(chord, "major 7th #9"); break; + case kDom7s9: strcat(chord, "dominant #9"); break; + case kMaj7s11: strcat(chord, "major 7th #11"); break; + case kMaj9s13: strcat(chord, "major 9th #13"); break; + case kMs9s11: strcat(chord, "major #9 #11"); break; + case kHDimb11: strcat(chord, "half diminished b11"); break; + + case kMaj11: strcat(chord, "major 11th"); break; + case kDom11: strcat(chord, "dominant 11th"); break; + case kMin11: strcat(chord, "minor 11th"); break; + case kHalfDim11:strcat(chord, "half diminished 11th");break; + case kDim11: strcat(chord, "diminished 11th"); break; + case kMinMaj11: strcat(chord, "minor/major 11th"); break; + case kDimMaj11: strcat(chord, "diminished maj 11th"); break; + + case kMaj11b5: strcat(chord, "major 11th b5"); break; + case kMaj11s5: strcat(chord, "major 11th #5"); break; + case kMaj11b9: strcat(chord, "major 11th b9"); break; + case kMaj11s9: strcat(chord, "major 11th #9"); break; + case kMaj11b13: strcat(chord, "major 11th b13"); break; + case kMaj11s13: strcat(chord, "major 11th #13"); break; + case kM11b5b9: strcat(chord, "major 11th b5 b9"); break; + case kDom11b5: strcat(chord, "dominant 11th b5"); break; + case kDom11b9: strcat(chord, "dominant 11th b9"); break; + case kDom11s9: strcat(chord, "dominant 11th #9"); break; + case kHalfDim11b9:strcat(chord, "half dim 11th b9"); break; + case kDom7s11: strcat(chord, "dominant #11"); break; + case kMin7s11: strcat(chord, "minor 7th #11"); break; + + case kDom13s11: strcat(chord, "dominant 13th #11"); break; + case kM7b913: strcat(chord, "major 7 b9 13"); break; + case kMaj7s13: strcat(chord, "major 7th #13"); break; + case kM7b9s13: strcat(chord, "major 7 b9 #13"); break; + case kDom7b13: strcat(chord, "dominant 7th b13"); break; + case kChrom: strcat(chord, "chromatic"); break; + case kNone: + default: strcat(chord, "unknown"); break; + } + + x->x_chord_bass = x->x_abs_pc[x->x_chord_root]; /* get MIDI note number of bass */ + + /* output results */ + outlet_list(x->x_outchordnotes, NULL, j, x->x_chordlist); + outlet_float(x->x_outchordinversion, x->x_chord_inversion); + outlet_symbol(x->x_outchordname, gensym(chord)); + outlet_float(x->x_outchordclass, x->x_chord_root); + outlet_float(x->x_outchordval, x->x_chord_bass); +} + +static void chord_kick_out_member(t_chord *x, t_int number, t_int *members) +{ + int *distances; + int minDistance = 1000; + int badMember = 0; + int i, j, interval; + + distances = getbytes(number*sizeof(int)); + + for (i=0; i 6) interval = 12 - interval; + // add absolute interval size to total + distances[i] += interval; + } + + // if this is the smallest total distance + if (distances[i] < minDistance) { + // remember it + minDistance = distances[i]; + badMember = i; + } + } + freebytes(distances, number * sizeof(int)); + x->x_pc[members[badMember]] = 0; // cancel out most dissonant member + chord_chord_finder(x, number-1); // call chord finder again without it + x->x_pc[members[badMember]] = 1; // replace most dissonant member +} + +static void chord_chord_finder(t_chord *x, t_int num_pcs) +{ + int i; + x->x_chord_type = kNone; + x->x_chord_root = kXX; /* none */ + switch (num_pcs) { + case 1: chord_unison(x); break; + case 2: chord_dyad(x); break; + case 3: chord_triad(x); break; + case 4: chord_quartad(x); break; + case 5: chord_quintad(x); break; + case 6: chord_sextad(x); break; + default: x->x_chord_type = kChrom; + for(i = 0; i < 12; i++) // 12 was num_pcs !? + { + if(x->x_pc[i]) + { + x->x_chord_root = i; + break; + } + } + } +} + +static void chord_float(t_chord *x, t_floatarg f) +{ + t_int velo = x->x_velo; + t_int allloc = 0; + t_int num_pc = 0; /* number of pitch classes present */ + int i, j, k, l; + + x->x_pitch = (t_int)f; + + if(x->x_pitch <= x->x_split) + { + /* first we need to put the note into the allocation table */ + if(velo == 0) /* got note-off: remove from allocation table */ + { + if(x->x_poly > 0)x->x_poly--; /* polyphony has decreased by one */ + for(i = 0; i < MAX_POLY; i++) /* search for voice allocation number */ + { + /* search for corresponding alloc number */ + if(x->x_alloctable[i] == x->x_pitch) + { + x->x_alloctable[i] = -1; /* free the alloc number */ + break; + } + /* couldn't find it ? */ + if(i == MAX_POLY - 1) + { + post("chord: no corresponding note-on found (ignored)"); + return; + } + } + return; /* no need to look for chord */ + } + else /* we got a note-on message */ + { + if(x->x_poly == MAX_POLY) + { + post("chord: too many note-on messages (ignored)"); + return; + } + + x->x_poly++; /* number of currently playing notes has increased */ + /* assign a voice allocation number */ + for(i = 0; i < MAX_POLY; i++) + { + /* search for free alloc number */ + if(x->x_alloctable[i] == -1) + { + x->x_alloctable[i] = x->x_pitch; /* ... and store pitch */ + break; + } + } + /* copy all notes into the pitch class array */ + for(i = 0; i < 12; i++) + { + x->x_pc[i] = 0; /* empty pitch class */ + x->x_abs_pc[i] = -1; /* empty absolute values */ + } + for(i = 0; i < MAX_POLY; i++) + { + /* check for presence of pitch class */ + if(x->x_alloctable[i] != -1) + { + if(!x->x_pc[x->x_alloctable[i]%12]) /* a new pitch class */ + { + x->x_abs_pc[x->x_alloctable[i]%12] = x->x_alloctable[i]; + } + else if(x->x_abs_pc[x->x_alloctable[i]%12] > x->x_alloctable[i]) /* remember lowest pitch */ + { + x->x_abs_pc[x->x_alloctable[i]%12] = x->x_alloctable[i]; + } + + x->x_pc[x->x_alloctable[i]%12] = 1; /* indicate presence of pc */ + } + } + /* count number of pitch classes */ + for(i = 0; i < 12; i++) + { + num_pc += x->x_pc[i]; + } + // post("%d pitch classes", num_pc); + } + } + + chord_chord_finder(x, num_pc); +} + +static void chord_ft1(t_chord *x, t_floatarg f) +{ + x->x_velo = (t_int)f; +} + +static t_class *chord_class; + +static void *chord_new(t_floatarg f) +{ + int i; + t_chord *x = (t_chord *)pd_new(chord_class); + inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); + x->x_outchordval = outlet_new(&x->x_ob, gensym("float")); + x->x_outchordclass = outlet_new(&x->x_ob, gensym("float")); + x->x_outchordname = outlet_new(&x->x_ob, gensym("symbol")); + x->x_outchordinversion = outlet_new(&x->x_ob, gensym("float")); + x->x_outchordnotes = outlet_new(&x->x_ob, gensym("float")); + + x->x_split = (t_int)f; + if(x->x_split == 0)x->x_split = 128; + for(i = 0; i < MAX_POLY; i++)x->x_alloctable[i] = -1; + + return (void *)x; +} + +#ifndef MAXLIB +void chord_setup(void) +{ + chord_class = class_new(gensym("chord"), (t_newmethod)chord_new, + 0, sizeof(t_chord), 0, A_DEFFLOAT, 0); +#else +void maxlib_chord_setup(void) +{ + chord_class = class_new(gensym("maxlib_chord"), (t_newmethod)chord_new, + 0, sizeof(t_chord), 0, A_DEFFLOAT, 0); +#endif + class_addfloat(chord_class, chord_float); + class_addmethod(chord_class, (t_method)chord_ft1, gensym("ft1"), A_FLOAT, 0); +#ifndef MAXLIB + + logpost(NULL, 4, version); +#else + class_addcreator((t_newmethod)chord_new, gensym("chord"), A_DEFFLOAT, 0); + class_sethelpsymbol(chord_class, gensym("maxlib/chord-help.pd")); +#endif +} + diff --git a/delta.c b/delta.c index 41e9b6e..f47e6a9 100644 --- a/delta.c +++ b/delta.c @@ -1,139 +1,139 @@ -/* ------------------------- delta ------------------------------------------ */ -/* */ -/* Claculate 1st or 2nd order difference. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Inspired by code written by Trond Lossius. */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include - -#define MAXSIZE 32 - -static char *version = "delta v0.1, written by Olaf Matthes "; - -typedef struct delta -{ - t_object x_ob; - t_outlet *x_out; /* result */ - t_int x_order; /* 1st or second order */ - t_int x_clearflag; - t_float x_delta; /* the result */ - - t_float x_prev; /* previous value */ - t_float x_prev2; /* value previous to previous value */ -} t_delta; - -static void delta_clear(t_delta *x) -{ - if(x->x_order == 2) - x->x_clearflag = 2; - else - x->x_clearflag = 1; - x->x_delta = 0; -} - -static void delta_bang(t_delta *x) -{ - outlet_float(x->x_out, x->x_delta); -} - -static void delta_float(t_delta *x, t_floatarg f) -{ - if(x->x_order != 2) /* first order */ - { - if(x->x_clearflag) - { - x->x_prev = f; - x->x_delta = 0; - x->x_clearflag = 0; - } - else - { - x->x_delta = f - x->x_prev; - x->x_prev = f; - } - } - else - { - switch(x->x_clearflag) - { - case 0: - x->x_delta = f - 2*x->x_prev + x->x_prev2; - x->x_prev2 = x->x_prev; - x->x_prev = f; - break; - case 1: - x->x_prev = f; - x->x_clearflag--; - break; - case 2: - x->x_prev2 = f; - x->x_clearflag--; - break; - } - } - delta_bang(x); -} - -static t_class *delta_class; - -static void *delta_new(t_floatarg f) -{ - int i; - - t_delta *x = (t_delta *)pd_new(delta_class); - x->x_out = outlet_new(&x->x_ob, gensym("float")); - - x->x_order = (int)f; - if(x->x_order == 2) - x->x_clearflag = 2; - else - x->x_clearflag = 1; - x->x_delta = 0; - - return (void *)x; -} - -#ifndef MAXLIB -void delta_setup(void) -{ - delta_class = class_new(gensym("delta"), (t_newmethod)delta_new, - 0, sizeof(t_delta), 0, A_DEFFLOAT, 0); -#else -void maxlib_delta_setup(void) -{ - delta_class = class_new(gensym("maxlib_delta"), (t_newmethod)delta_new, - 0, sizeof(t_delta), 0, A_DEFFLOAT, 0); -#endif - class_addfloat(delta_class, delta_float); - class_addbang(delta_class, (t_method)delta_bang); - class_addmethod(delta_class, (t_method)delta_clear, gensym("clear"), 0); - class_sethelpsymbol(delta_class, gensym("maxlib/delta-help.pd")); -#ifndef MAXLIB - - post(version); -#else - class_addcreator((t_newmethod)delta_new, gensym("delta"), A_DEFFLOAT, 0); - class_sethelpsymbol(delta_class, gensym("maxlib/delta-help.pd")); -#endif -} - +/* ------------------------- delta ------------------------------------------ */ +/* */ +/* Claculate 1st or 2nd order difference. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Inspired by code written by Trond Lossius. */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include + +#define MAXSIZE 32 + +static char *version = "delta v0.1, written by Olaf Matthes "; + +typedef struct delta +{ + t_object x_ob; + t_outlet *x_out; /* result */ + t_int x_order; /* 1st or second order */ + t_int x_clearflag; + t_float x_delta; /* the result */ + + t_float x_prev; /* previous value */ + t_float x_prev2; /* value previous to previous value */ +} t_delta; + +static void delta_clear(t_delta *x) +{ + if(x->x_order == 2) + x->x_clearflag = 2; + else + x->x_clearflag = 1; + x->x_delta = 0; +} + +static void delta_bang(t_delta *x) +{ + outlet_float(x->x_out, x->x_delta); +} + +static void delta_float(t_delta *x, t_floatarg f) +{ + if(x->x_order != 2) /* first order */ + { + if(x->x_clearflag) + { + x->x_prev = f; + x->x_delta = 0; + x->x_clearflag = 0; + } + else + { + x->x_delta = f - x->x_prev; + x->x_prev = f; + } + } + else + { + switch(x->x_clearflag) + { + case 0: + x->x_delta = f - 2*x->x_prev + x->x_prev2; + x->x_prev2 = x->x_prev; + x->x_prev = f; + break; + case 1: + x->x_prev = f; + x->x_clearflag--; + break; + case 2: + x->x_prev2 = f; + x->x_clearflag--; + break; + } + } + delta_bang(x); +} + +static t_class *delta_class; + +static void *delta_new(t_floatarg f) +{ + int i; + + t_delta *x = (t_delta *)pd_new(delta_class); + x->x_out = outlet_new(&x->x_ob, gensym("float")); + + x->x_order = (int)f; + if(x->x_order == 2) + x->x_clearflag = 2; + else + x->x_clearflag = 1; + x->x_delta = 0; + + return (void *)x; +} + +#ifndef MAXLIB +void delta_setup(void) +{ + delta_class = class_new(gensym("delta"), (t_newmethod)delta_new, + 0, sizeof(t_delta), 0, A_DEFFLOAT, 0); +#else +void maxlib_delta_setup(void) +{ + delta_class = class_new(gensym("maxlib_delta"), (t_newmethod)delta_new, + 0, sizeof(t_delta), 0, A_DEFFLOAT, 0); +#endif + class_addfloat(delta_class, delta_float); + class_addbang(delta_class, (t_method)delta_bang); + class_addmethod(delta_class, (t_method)delta_clear, gensym("clear"), 0); + class_sethelpsymbol(delta_class, gensym("maxlib/delta-help.pd")); +#ifndef MAXLIB + + logpost(NULL, 4, version); +#else + class_addcreator((t_newmethod)delta_new, gensym("delta"), A_DEFFLOAT, 0); + class_sethelpsymbol(delta_class, gensym("maxlib/delta-help.pd")); +#endif +} + diff --git a/deny.c b/deny.c index 1ab4de8..5525cc2 100644 --- a/deny.c +++ b/deny.c @@ -1,114 +1,114 @@ -/* ---------------------------- deny --------------------------------------- */ -/* */ -/* Lets only floats/symbols through that are denyed to do so. */ -/* Written by Olaf Matthes */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include - -static char *version = "deny v0.1, written by Olaf Matthes "; - -typedef struct deny -{ - t_object x_obj; - t_outlet *x_out; - t_atom *x_elem; // list of elemets that are denyed to pass - t_int x_numelem; // the number of elemetns in our deny-list -} t_deny; - - /* we got a symbol... */ -static void deny_symbol(t_deny *x, t_symbol *s) -{ - int i, deny = 0; - for(i = 0; i < x->x_numelem; i++) - { - if(x->x_elem[i].a_type == A_SYMBOL) // compare with all symbols in our list - if(atom_getsymbolarg(i, x->x_numelem, x->x_elem) == s) - { - deny = 1; - return; - } - } - if(!deny)outlet_symbol(x->x_out, s); -} - - /* we got a float... */ -static void deny_float(t_deny *x, t_floatarg f) -{ - int i, deny = 0; - for(i = 0; i < x->x_numelem; i++) - { - if(x->x_elem[i].a_type == A_FLOAT) // compare with all floats in our list - if(atom_getfloatarg(i, x->x_numelem, x->x_elem) == f) - { - deny = 1; // input is in deny-list - return; - } - } - if(!deny)outlet_float(x->x_out, f); -} - -static t_class *deny_class; - -static void deny_free(t_deny *x) -{ - freebytes(x->x_elem, x->x_numelem*sizeof(t_atom)); -} - -static void *deny_new(t_symbol *s, int argc, t_atom *argv) -{ - t_deny *x = (t_deny *)pd_new(deny_class); - - x->x_numelem = argc; // get the number of elements - x->x_elem = getbytes(argc*sizeof(t_atom)); - memcpy(x->x_elem, argv, argc*sizeof(t_atom)); - - x->x_out = outlet_new(&x->x_obj, gensym("anything")); - - // post("deny: got %d elements", x->x_numelem); - - return (x); -} - -#ifndef MAXLIB -void deny_setup(void) -{ - /* the object's class: */ - deny_class = class_new(gensym("deny"), (t_newmethod)deny_new, - (t_method)deny_free, sizeof(t_deny), 0, A_GIMME, 0); -#else -void maxlib_deny_setup(void) -{ - /* the object's class: */ - deny_class = class_new(gensym("maxlib_deny"), (t_newmethod)deny_new, - (t_method)deny_free, sizeof(t_deny), 0, A_GIMME, 0); - class_addcreator((t_newmethod)deny_new, gensym("deny"), A_GIMME, 0); -#endif - class_addsymbol(deny_class, deny_symbol); - class_addfloat(deny_class, deny_float); -#ifndef MAXLIB - - post(version); -#else - class_sethelpsymbol(deny_class, gensym("maxlib/deny-help.pd")); -#endif -} +/* ---------------------------- deny --------------------------------------- */ +/* */ +/* Lets only floats/symbols through that are denyed to do so. */ +/* Written by Olaf Matthes */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include + +static char *version = "deny v0.1, written by Olaf Matthes "; + +typedef struct deny +{ + t_object x_obj; + t_outlet *x_out; + t_atom *x_elem; // list of elemets that are denyed to pass + t_int x_numelem; // the number of elemetns in our deny-list +} t_deny; + + /* we got a symbol... */ +static void deny_symbol(t_deny *x, t_symbol *s) +{ + int i, deny = 0; + for(i = 0; i < x->x_numelem; i++) + { + if(x->x_elem[i].a_type == A_SYMBOL) // compare with all symbols in our list + if(atom_getsymbolarg(i, x->x_numelem, x->x_elem) == s) + { + deny = 1; + return; + } + } + if(!deny)outlet_symbol(x->x_out, s); +} + + /* we got a float... */ +static void deny_float(t_deny *x, t_floatarg f) +{ + int i, deny = 0; + for(i = 0; i < x->x_numelem; i++) + { + if(x->x_elem[i].a_type == A_FLOAT) // compare with all floats in our list + if(atom_getfloatarg(i, x->x_numelem, x->x_elem) == f) + { + deny = 1; // input is in deny-list + return; + } + } + if(!deny)outlet_float(x->x_out, f); +} + +static t_class *deny_class; + +static void deny_free(t_deny *x) +{ + freebytes(x->x_elem, x->x_numelem*sizeof(t_atom)); +} + +static void *deny_new(t_symbol *s, int argc, t_atom *argv) +{ + t_deny *x = (t_deny *)pd_new(deny_class); + + x->x_numelem = argc; // get the number of elements + x->x_elem = getbytes(argc*sizeof(t_atom)); + memcpy(x->x_elem, argv, argc*sizeof(t_atom)); + + x->x_out = outlet_new(&x->x_obj, gensym("anything")); + + // post("deny: got %d elements", x->x_numelem); + + return (x); +} + +#ifndef MAXLIB +void deny_setup(void) +{ + /* the object's class: */ + deny_class = class_new(gensym("deny"), (t_newmethod)deny_new, + (t_method)deny_free, sizeof(t_deny), 0, A_GIMME, 0); +#else +void maxlib_deny_setup(void) +{ + /* the object's class: */ + deny_class = class_new(gensym("maxlib_deny"), (t_newmethod)deny_new, + (t_method)deny_free, sizeof(t_deny), 0, A_GIMME, 0); + class_addcreator((t_newmethod)deny_new, gensym("deny"), A_GIMME, 0); +#endif + class_addsymbol(deny_class, deny_symbol); + class_addfloat(deny_class, deny_float); +#ifndef MAXLIB + + logpost(NULL, 4, version); +#else + class_sethelpsymbol(deny_class, gensym("maxlib/deny-help.pd")); +#endif +} diff --git a/dist.c b/dist.c index 38544d5..e98eebb 100644 --- a/dist.c +++ b/dist.c @@ -1,279 +1,279 @@ -/* -------------------------- dist ------------------------------------------ */ -/* */ -/* Distributes incoming data to a changeable list of receive objects. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ -/* - connect : store receive objects in list of receivers - disconnect : remove objects from list of receivers - clear: clear list of receivers - send : send anything to all receives named in the list of receivers */ - -#include "m_pd.h" - -#include -#include - -#define MAX_REC 64 /* maximum number of receive objects */ -#define MAX_ARG 32 /* maximum number of arguments to pass on */ - -static char *version = "dist v0.1, written by Olaf Matthes "; - -static t_class *dist_class; - -typedef struct _dist -{ - t_object x_obj; - t_symbol *x_sym[MAX_REC]; /* names of receiving objects */ - t_int x_rec; /* current number of receiving objects */ - t_int x_verbose; /* set to 0 to turn off detailed output in Pd window */ -} t_dist; - -static void dist_bang(t_dist *x) -{ - int i; - - for(i = 0; i <= x->x_rec; i++) - { - if (x->x_sym[i]->s_thing) pd_bang(x->x_sym[i]->s_thing); - } -} - -static void dist_float(t_dist *x, t_float f) -{ - int i; - - for(i = 0; i <= x->x_rec; i++) - { - if (x->x_sym[i]->s_thing) pd_float(x->x_sym[i]->s_thing, f); - } -} - -static void dist_symbol(t_dist *x, t_symbol *s) -{ - int i; - - for(i = 0; i <= x->x_rec; i++) - { - if (x->x_sym[i]->s_thing) pd_symbol(x->x_sym[i]->s_thing, s); - } -} - -static void dist_pointer(t_dist *x, t_gpointer *gp) -{ - int i; - - for(i = 0; i <= x->x_rec; i++) - { - if (x->x_sym[i]->s_thing) pd_pointer(x->x_sym[i]->s_thing, gp); - } -} - -static void dist_list(t_dist *x, t_symbol *s, int argc, t_atom *argv) -{ - int i; - - for(i = 0; i <= x->x_rec; i++) - { - if (x->x_sym[i]->s_thing) pd_list(x->x_sym[i]->s_thing, s, argc, argv); - } -} - -static void dist_anything(t_dist *x, t_symbol *s, int argc, t_atom *argv) -{ - int i; - - for(i = 0; i <= x->x_rec; i++) - { - if (x->x_sym[i]->s_thing) typedmess(x->x_sym[i]->s_thing, s, argc, argv); - } -} - - /* send 'anything' to receiver */ -static void dist_send(t_dist *x, t_symbol *s, int argc, t_atom *argv) -{ - int i; - t_atom av[MAX_ARG]; /* the 'new' t_atom without first element */ - t_int ac = argc - 1; /* the 'new' number of arguments */ - - if(ac > MAX_ARG) - { - post("dist: too many arguments!"); - return; - } - - for(i = 1; i < argc; i++) - { - av[i - 1] = argv[i]; /* just copy, don't care about types */ - } - /* send only argument-part to receivers */ - for(i = 0; i <= x->x_rec; i++) - { - if (x->x_sym[i]->s_thing) pd_forwardmess(x->x_sym[i]->s_thing, argc, argv); - } -} - -static void dist_connect(t_dist *x, t_symbol *s, int argc, t_atom *argv) -{ - int i, j; - int exist; - t_symbol *name; - /* just append every new receive-name to end of list */ - for(i = 0; i < argc; i++) - { - exist = 0; - if(x->x_rec == MAX_REC - 1) - { - post("dist: too many connections in use!"); - return; - } - name = atom_getsymbolarg(i, argc, argv); - for(j = 0; j <= x->x_rec; j++) - { - /* check if the name already exists */ - if(x->x_sym[j] == name) - { - post("dist: \"%s\" already exists in list of receivers", name->s_name); - exist = 1; /* indicate that it _does_ exist */ - } - } - /* add it in case it's a new one */ - if(!exist) - { - x->x_rec++; - x->x_sym[x->x_rec] = name; - if(x->x_verbose)post("dist: \"%s\" added to list of receivers", x->x_sym[x->x_rec]->s_name); - } - } -} - -static void dist_disconnect(t_dist *x, t_symbol *s, int argc, t_atom *argv) -{ - /* need to rearrange list in order to get rid of empty entries */ - int i, j, k; - int done; - t_symbol *name; - - for(i = 0; i < argc; i++) - { - name = atom_getsymbolarg(i, argc, argv); /* the one we're going to remove */ - done = 0; /* not yet removed */ - for(j = 0; j <= x->x_rec; j++) /* search for it... */ - { - if(x->x_sym[j] == name) - { - x->x_rec--; - if(x->x_verbose)post("dist: \"%s\" removed from list of receivers", x->x_sym[j]->s_name); - x->x_sym[j] = NULL; /* delete entry */ - /* rearrange list now: move entries to close the gap */ - for(k = j; k <= x->x_rec; k++) - { - x->x_sym[k] = x->x_sym[k + 1]; - } - done = 1; /* removed successfully */ - } - } - if(!done)post("dist: \"%s\" not in list of receivers, ignored", name->s_name); - } -} - -static void dist_clear(t_dist *x) -{ - int i; - - for(i = 0; i < MAX_REC; i++) - { - x->x_sym[i] = NULL; - } - x->x_rec = -1; -} - -static void dist_print(t_dist *x) -{ - int i; - - if(x->x_rec == 0) - { - post("dist: there is one object in receiver list:"); - } - else if(x->x_rec > 0) - { - post("dist: there are %d objects in receiver list:", x->x_rec + 1); - } - else - { - post("dist: there are no objects in receiver list"); - return; - } - - for(i = 0; i <= x->x_rec; i++) - { - post(" \"%s\"", x->x_sym[i]->s_name); - } -} - -static void *dist_new(t_symbol *s, int argc, t_atom *argv) -{ - int i; - - t_dist *x = (t_dist *)pd_new(dist_class); - - x->x_rec = -1; - x->x_verbose = 1; /* display info on connect/disconnect */ - for(i = 0; i < argc; i++) - { - x->x_sym[i] = atom_getsymbolarg(i, argc, argv); - x->x_rec++; - } - return (x); -} - -#ifndef MAXLIB -void dist_setup(void) -{ - dist_class = class_new(gensym("dist"), (t_newmethod)dist_new, 0, - sizeof(t_dist), 0, A_GIMME, 0); -#else -void maxlib_dist_setup(void) -{ - dist_class = class_new(gensym("maxlib_dist"), (t_newmethod)dist_new, 0, - sizeof(t_dist), 0, A_GIMME, 0); -#endif - class_addcreator((t_newmethod)dist_new, gensym("d"), A_GIMME, 0); - class_addbang(dist_class, dist_bang); - class_addfloat(dist_class, dist_float); - class_addsymbol(dist_class, dist_symbol); - class_addpointer(dist_class, dist_pointer); - class_addlist(dist_class, dist_list); - class_addmethod(dist_class, (t_method)dist_connect, gensym("connect"), A_GIMME, 0); - class_addmethod(dist_class, (t_method)dist_disconnect, gensym("disconnect"), A_GIMME, 0); - class_addmethod(dist_class, (t_method)dist_clear, gensym("clear"), 0); - class_addmethod(dist_class, (t_method)dist_print, gensym("print"), 0); - class_addmethod(dist_class, (t_method)dist_send, gensym("send"), A_GIMME, 0); - class_addanything(dist_class, dist_anything); -#ifndef MAXLIB - - post(version); -#else - class_addcreator((t_newmethod)dist_new, gensym("dist"), A_GIMME, 0); - class_sethelpsymbol(dist_class, gensym("maxlib/dist-help.pd")); -#endif -} +/* -------------------------- dist ------------------------------------------ */ +/* */ +/* Distributes incoming data to a changeable list of receive objects. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ +/* + connect : store receive objects in list of receivers + disconnect : remove objects from list of receivers + clear: clear list of receivers + send : send anything to all receives named in the list of receivers */ + +#include "m_pd.h" + +#include +#include + +#define MAX_REC 64 /* maximum number of receive objects */ +#define MAX_ARG 32 /* maximum number of arguments to pass on */ + +static char *version = "dist v0.1, written by Olaf Matthes "; + +static t_class *dist_class; + +typedef struct _dist +{ + t_object x_obj; + t_symbol *x_sym[MAX_REC]; /* names of receiving objects */ + t_int x_rec; /* current number of receiving objects */ + t_int x_verbose; /* set to 0 to turn off detailed output in Pd window */ +} t_dist; + +static void dist_bang(t_dist *x) +{ + int i; + + for(i = 0; i <= x->x_rec; i++) + { + if (x->x_sym[i]->s_thing) pd_bang(x->x_sym[i]->s_thing); + } +} + +static void dist_float(t_dist *x, t_float f) +{ + int i; + + for(i = 0; i <= x->x_rec; i++) + { + if (x->x_sym[i]->s_thing) pd_float(x->x_sym[i]->s_thing, f); + } +} + +static void dist_symbol(t_dist *x, t_symbol *s) +{ + int i; + + for(i = 0; i <= x->x_rec; i++) + { + if (x->x_sym[i]->s_thing) pd_symbol(x->x_sym[i]->s_thing, s); + } +} + +static void dist_pointer(t_dist *x, t_gpointer *gp) +{ + int i; + + for(i = 0; i <= x->x_rec; i++) + { + if (x->x_sym[i]->s_thing) pd_pointer(x->x_sym[i]->s_thing, gp); + } +} + +static void dist_list(t_dist *x, t_symbol *s, int argc, t_atom *argv) +{ + int i; + + for(i = 0; i <= x->x_rec; i++) + { + if (x->x_sym[i]->s_thing) pd_list(x->x_sym[i]->s_thing, s, argc, argv); + } +} + +static void dist_anything(t_dist *x, t_symbol *s, int argc, t_atom *argv) +{ + int i; + + for(i = 0; i <= x->x_rec; i++) + { + if (x->x_sym[i]->s_thing) typedmess(x->x_sym[i]->s_thing, s, argc, argv); + } +} + + /* send 'anything' to receiver */ +static void dist_send(t_dist *x, t_symbol *s, int argc, t_atom *argv) +{ + int i; + t_atom av[MAX_ARG]; /* the 'new' t_atom without first element */ + t_int ac = argc - 1; /* the 'new' number of arguments */ + + if(ac > MAX_ARG) + { + post("dist: too many arguments!"); + return; + } + + for(i = 1; i < argc; i++) + { + av[i - 1] = argv[i]; /* just copy, don't care about types */ + } + /* send only argument-part to receivers */ + for(i = 0; i <= x->x_rec; i++) + { + if (x->x_sym[i]->s_thing) pd_forwardmess(x->x_sym[i]->s_thing, argc, argv); + } +} + +static void dist_connect(t_dist *x, t_symbol *s, int argc, t_atom *argv) +{ + int i, j; + int exist; + t_symbol *name; + /* just append every new receive-name to end of list */ + for(i = 0; i < argc; i++) + { + exist = 0; + if(x->x_rec == MAX_REC - 1) + { + post("dist: too many connections in use!"); + return; + } + name = atom_getsymbolarg(i, argc, argv); + for(j = 0; j <= x->x_rec; j++) + { + /* check if the name already exists */ + if(x->x_sym[j] == name) + { + post("dist: \"%s\" already exists in list of receivers", name->s_name); + exist = 1; /* indicate that it _does_ exist */ + } + } + /* add it in case it's a new one */ + if(!exist) + { + x->x_rec++; + x->x_sym[x->x_rec] = name; + if(x->x_verbose)post("dist: \"%s\" added to list of receivers", x->x_sym[x->x_rec]->s_name); + } + } +} + +static void dist_disconnect(t_dist *x, t_symbol *s, int argc, t_atom *argv) +{ + /* need to rearrange list in order to get rid of empty entries */ + int i, j, k; + int done; + t_symbol *name; + + for(i = 0; i < argc; i++) + { + name = atom_getsymbolarg(i, argc, argv); /* the one we're going to remove */ + done = 0; /* not yet removed */ + for(j = 0; j <= x->x_rec; j++) /* search for it... */ + { + if(x->x_sym[j] == name) + { + x->x_rec--; + if(x->x_verbose)post("dist: \"%s\" removed from list of receivers", x->x_sym[j]->s_name); + x->x_sym[j] = NULL; /* delete entry */ + /* rearrange list now: move entries to close the gap */ + for(k = j; k <= x->x_rec; k++) + { + x->x_sym[k] = x->x_sym[k + 1]; + } + done = 1; /* removed successfully */ + } + } + if(!done)post("dist: \"%s\" not in list of receivers, ignored", name->s_name); + } +} + +static void dist_clear(t_dist *x) +{ + int i; + + for(i = 0; i < MAX_REC; i++) + { + x->x_sym[i] = NULL; + } + x->x_rec = -1; +} + +static void dist_print(t_dist *x) +{ + int i; + + if(x->x_rec == 0) + { + post("dist: there is one object in receiver list:"); + } + else if(x->x_rec > 0) + { + post("dist: there are %d objects in receiver list:", x->x_rec + 1); + } + else + { + post("dist: there are no objects in receiver list"); + return; + } + + for(i = 0; i <= x->x_rec; i++) + { + post(" \"%s\"", x->x_sym[i]->s_name); + } +} + +static void *dist_new(t_symbol *s, int argc, t_atom *argv) +{ + int i; + + t_dist *x = (t_dist *)pd_new(dist_class); + + x->x_rec = -1; + x->x_verbose = 1; /* display info on connect/disconnect */ + for(i = 0; i < argc; i++) + { + x->x_sym[i] = atom_getsymbolarg(i, argc, argv); + x->x_rec++; + } + return (x); +} + +#ifndef MAXLIB +void dist_setup(void) +{ + dist_class = class_new(gensym("dist"), (t_newmethod)dist_new, 0, + sizeof(t_dist), 0, A_GIMME, 0); +#else +void maxlib_dist_setup(void) +{ + dist_class = class_new(gensym("maxlib_dist"), (t_newmethod)dist_new, 0, + sizeof(t_dist), 0, A_GIMME, 0); +#endif + class_addcreator((t_newmethod)dist_new, gensym("d"), A_GIMME, 0); + class_addbang(dist_class, dist_bang); + class_addfloat(dist_class, dist_float); + class_addsymbol(dist_class, dist_symbol); + class_addpointer(dist_class, dist_pointer); + class_addlist(dist_class, dist_list); + class_addmethod(dist_class, (t_method)dist_connect, gensym("connect"), A_GIMME, 0); + class_addmethod(dist_class, (t_method)dist_disconnect, gensym("disconnect"), A_GIMME, 0); + class_addmethod(dist_class, (t_method)dist_clear, gensym("clear"), 0); + class_addmethod(dist_class, (t_method)dist_print, gensym("print"), 0); + class_addmethod(dist_class, (t_method)dist_send, gensym("send"), A_GIMME, 0); + class_addanything(dist_class, dist_anything); +#ifndef MAXLIB + + logpost(NULL, 4, version); +#else + class_addcreator((t_newmethod)dist_new, gensym("dist"), A_GIMME, 0); + class_sethelpsymbol(dist_class, gensym("maxlib/dist-help.pd")); +#endif +} diff --git a/divide.c b/divide.c index b13fefe..be825e8 100644 --- a/divide.c +++ b/divide.c @@ -1,110 +1,110 @@ -/* ------------------------- divide ------------------------------------------ */ -/* */ -/* Like '/', but calculates output whenever _any_ of the inlets changes. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include - -#define MAXSIZE 32 - -static char *version = "divide v0.2, written by Olaf Matthes "; - -typedef struct divide -{ - t_object x_ob; - t_inlet *x_inleft; /* leftmost inlet */ - t_inlet *x_inright; /* right inlet */ - t_outlet *x_outlet; /* result */ - t_int x_numvalues; /* number of values / inlets */ - - t_float x_dividevalue[MAXSIZE]; - -} t_divide; - -static void divide_bang(t_divide *x) -{ - int i; - t_float result = x->x_dividevalue[0]; - for(i = 1; i < x->x_numvalues; i++) - result /= x->x_dividevalue[i]; - outlet_float(x->x_outlet, result); -} - -static void divide_float(t_divide *x, t_floatarg f) -{ - x->x_dividevalue[0] = f; - divide_bang(x); /* calculate result */ -} - -static void divide_ft1(t_divide *x, t_floatarg f) -{ - x->x_dividevalue[1] = f; - divide_bang(x); /* calculate result */ -} - -static t_class *divide_class; - -static void *divide_new(t_symbol *s, t_int argc, t_atom* argv) -{ - int i; - - t_divide *x = (t_divide *)pd_new(divide_class); - x->x_inright = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); - for(i = 2; i < argc; i++) /* create additional inlets, if any */ - { - floatinlet_new(&x->x_ob, &x->x_dividevalue[i]); - } - x->x_outlet = outlet_new(&x->x_ob, gensym("float")); - - for(i = 0; i < argc; i++) - { - x->x_dividevalue[i] = atom_getfloatarg(i, argc, argv); - } - x->x_numvalues = i; - - return (void *)x; -} - -#ifndef MAXLIB -void divide_setup(void) -{ - divide_class = class_new(gensym("divide"), (t_newmethod)divide_new, - 0, sizeof(t_divide), 0, A_GIMME, 0); -#else -void maxlib_divide_setup(void) -{ - divide_class = class_new(gensym("maxlib_divide"), (t_newmethod)divide_new, - 0, sizeof(t_divide), 0, A_GIMME, 0); -#endif - class_addfloat(divide_class, divide_float); - class_addmethod(divide_class, (t_method)divide_ft1, gensym("ft1"), A_FLOAT, 0); - class_addbang(divide_class, (t_method)divide_bang); -#ifndef MAXLIB - - post(version); -#else - class_addcreator((t_newmethod)divide_new, gensym("divide"), A_GIMME, 0); - class_sethelpsymbol(divide_class, gensym("maxlib/divide-help.pd")); -#endif -} - +/* ------------------------- divide ------------------------------------------ */ +/* */ +/* Like '/', but calculates output whenever _any_ of the inlets changes. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include + +#define MAXSIZE 32 + +static char *version = "divide v0.2, written by Olaf Matthes "; + +typedef struct divide +{ + t_object x_ob; + t_inlet *x_inleft; /* leftmost inlet */ + t_inlet *x_inright; /* right inlet */ + t_outlet *x_outlet; /* result */ + t_int x_numvalues; /* number of values / inlets */ + + t_float x_dividevalue[MAXSIZE]; + +} t_divide; + +static void divide_bang(t_divide *x) +{ + int i; + t_float result = x->x_dividevalue[0]; + for(i = 1; i < x->x_numvalues; i++) + result /= x->x_dividevalue[i]; + outlet_float(x->x_outlet, result); +} + +static void divide_float(t_divide *x, t_floatarg f) +{ + x->x_dividevalue[0] = f; + divide_bang(x); /* calculate result */ +} + +static void divide_ft1(t_divide *x, t_floatarg f) +{ + x->x_dividevalue[1] = f; + divide_bang(x); /* calculate result */ +} + +static t_class *divide_class; + +static void *divide_new(t_symbol *s, t_int argc, t_atom* argv) +{ + int i; + + t_divide *x = (t_divide *)pd_new(divide_class); + x->x_inright = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); + for(i = 2; i < argc; i++) /* create additional inlets, if any */ + { + floatinlet_new(&x->x_ob, &x->x_dividevalue[i]); + } + x->x_outlet = outlet_new(&x->x_ob, gensym("float")); + + for(i = 0; i < argc; i++) + { + x->x_dividevalue[i] = atom_getfloatarg(i, argc, argv); + } + x->x_numvalues = i; + + return (void *)x; +} + +#ifndef MAXLIB +void divide_setup(void) +{ + divide_class = class_new(gensym("divide"), (t_newmethod)divide_new, + 0, sizeof(t_divide), 0, A_GIMME, 0); +#else +void maxlib_divide_setup(void) +{ + divide_class = class_new(gensym("maxlib_divide"), (t_newmethod)divide_new, + 0, sizeof(t_divide), 0, A_GIMME, 0); +#endif + class_addfloat(divide_class, divide_float); + class_addmethod(divide_class, (t_method)divide_ft1, gensym("ft1"), A_FLOAT, 0); + class_addbang(divide_class, (t_method)divide_bang); +#ifndef MAXLIB + + logpost(NULL, 4, version); +#else + class_addcreator((t_newmethod)divide_new, gensym("divide"), A_GIMME, 0); + class_sethelpsymbol(divide_class, gensym("maxlib/divide-help.pd")); +#endif +} + diff --git a/divmod.c b/divmod.c index 07f265e..7151baf 100644 --- a/divmod.c +++ b/divmod.c @@ -1,100 +1,100 @@ -/* ------------------------- divmod ----------------------------------------- */ -/* */ -/* Calculates / and % together. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include - -static char *version = "divmod v0.1, written by Olaf Matthes "; - -typedef struct divmod -{ - t_object x_ob; - t_inlet *x_inleft; /* leftmost inlet */ - t_inlet *x_inright; /* right inlet */ - t_outlet *x_outlet1; /* result of division */ - t_outlet *x_outlet2; /* result of modulo */ - - t_int x_leftvalue; - t_int x_rightvalue; - -} t_divmod; - -static void divmod_float(t_divmod *x, t_floatarg f) -{ - x->x_leftvalue = (t_int)f; - outlet_float(x->x_outlet1, x->x_leftvalue / x->x_rightvalue); - outlet_float(x->x_outlet2, x->x_leftvalue % x->x_rightvalue); -} - -static void divmod_ft1(t_divmod *x, t_floatarg f) -{ - x->x_rightvalue = (t_int)f; - outlet_float(x->x_outlet1, x->x_leftvalue / x->x_rightvalue); - outlet_float(x->x_outlet2, x->x_leftvalue % x->x_rightvalue); -} - -static void divmod_bang(t_divmod *x) -{ - outlet_float(x->x_outlet1, x->x_leftvalue / x->x_rightvalue); - outlet_float(x->x_outlet2, x->x_leftvalue % x->x_rightvalue); -} - -static t_class *divmod_class; - -static void *divmod_new(t_floatarg fl, t_floatarg fr) -{ - t_divmod *x = (t_divmod *)pd_new(divmod_class); - x->x_inright = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); - x->x_outlet1 = outlet_new(&x->x_ob, gensym("float")); - x->x_outlet2 = outlet_new(&x->x_ob, gensym("float")); - - x->x_rightvalue = fr; - x->x_leftvalue = fl; - - return (void *)x; -} - -#ifndef MAXLIB -void divmod_setup(void) -{ - divmod_class = class_new(gensym("divmod"), (t_newmethod)divmod_new, - 0, sizeof(t_divmod), 0, A_DEFFLOAT, A_DEFFLOAT, 0); -#else -void maxlib_divmod_setup(void) -{ - divmod_class = class_new(gensym("maxlib_divmod"), (t_newmethod)divmod_new, - 0, sizeof(t_divmod), 0, A_DEFFLOAT, A_DEFFLOAT, 0); -#endif - class_addfloat(divmod_class, divmod_float); - class_addmethod(divmod_class, (t_method)divmod_ft1, gensym("ft1"), A_FLOAT, 0); - class_addbang(divmod_class, (t_method)divmod_bang); -#ifndef MAXLIB - - post(version); -#else - class_addcreator((t_newmethod)divmod_new, gensym("divmod"), A_DEFFLOAT, A_DEFFLOAT, 0); - class_sethelpsymbol(divmod_class, gensym("maxlib/divmod-help.pd")); -#endif -} - +/* ------------------------- divmod ----------------------------------------- */ +/* */ +/* Calculates / and % together. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include + +static char *version = "divmod v0.1, written by Olaf Matthes "; + +typedef struct divmod +{ + t_object x_ob; + t_inlet *x_inleft; /* leftmost inlet */ + t_inlet *x_inright; /* right inlet */ + t_outlet *x_outlet1; /* result of division */ + t_outlet *x_outlet2; /* result of modulo */ + + t_int x_leftvalue; + t_int x_rightvalue; + +} t_divmod; + +static void divmod_float(t_divmod *x, t_floatarg f) +{ + x->x_leftvalue = (t_int)f; + outlet_float(x->x_outlet1, x->x_leftvalue / x->x_rightvalue); + outlet_float(x->x_outlet2, x->x_leftvalue % x->x_rightvalue); +} + +static void divmod_ft1(t_divmod *x, t_floatarg f) +{ + x->x_rightvalue = (t_int)f; + outlet_float(x->x_outlet1, x->x_leftvalue / x->x_rightvalue); + outlet_float(x->x_outlet2, x->x_leftvalue % x->x_rightvalue); +} + +static void divmod_bang(t_divmod *x) +{ + outlet_float(x->x_outlet1, x->x_leftvalue / x->x_rightvalue); + outlet_float(x->x_outlet2, x->x_leftvalue % x->x_rightvalue); +} + +static t_class *divmod_class; + +static void *divmod_new(t_floatarg fl, t_floatarg fr) +{ + t_divmod *x = (t_divmod *)pd_new(divmod_class); + x->x_inright = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); + x->x_outlet1 = outlet_new(&x->x_ob, gensym("float")); + x->x_outlet2 = outlet_new(&x->x_ob, gensym("float")); + + x->x_rightvalue = fr; + x->x_leftvalue = fl; + + return (void *)x; +} + +#ifndef MAXLIB +void divmod_setup(void) +{ + divmod_class = class_new(gensym("divmod"), (t_newmethod)divmod_new, + 0, sizeof(t_divmod), 0, A_DEFFLOAT, A_DEFFLOAT, 0); +#else +void maxlib_divmod_setup(void) +{ + divmod_class = class_new(gensym("maxlib_divmod"), (t_newmethod)divmod_new, + 0, sizeof(t_divmod), 0, A_DEFFLOAT, A_DEFFLOAT, 0); +#endif + class_addfloat(divmod_class, divmod_float); + class_addmethod(divmod_class, (t_method)divmod_ft1, gensym("ft1"), A_FLOAT, 0); + class_addbang(divmod_class, (t_method)divmod_bang); +#ifndef MAXLIB + + logpost(NULL, 4, version); +#else + class_addcreator((t_newmethod)divmod_new, gensym("divmod"), A_DEFFLOAT, A_DEFFLOAT, 0); + class_sethelpsymbol(divmod_class, gensym("maxlib/divmod-help.pd")); +#endif +} + diff --git a/edge.c b/edge.c index 4f32e8a..8d94c71 100644 --- a/edge.c +++ b/edge.c @@ -1,82 +1,82 @@ -/* --------------------------- edge ----------------------------------------- */ -/* */ -/* Detect rising or falling edge of float input. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include - -static char *version = "edge v0.1, written by Olaf Matthes "; - -typedef struct edge -{ - t_object x_ob; - t_outlet *x_out1; /* bang on rising edge */ - t_outlet *x_out2; /* bang on falling edge */ - t_float x_lastval; /* last input value */ -} t_edge; - -static void edge_float(t_edge *x, t_floatarg f) -{ - if((x->x_lastval <= 0) && (f >= 1)) /* rising edge */ - outlet_bang(x->x_out1); - else if((x->x_lastval >= 1) && (f <= 0)) /* falling edge */ - outlet_bang(x->x_out2); - - x->x_lastval = f; /* save last value */ -} - -static t_class *edge_class; - -static void *edge_new(t_floatarg f) -{ - int i; - - t_edge *x = (t_edge *)pd_new(edge_class); - x->x_out1 = outlet_new(&x->x_ob, gensym("bang")); - x->x_out2 = outlet_new(&x->x_ob, gensym("bang")); - - x->x_lastval = f; - - return (void *)x; -} - -#ifndef MAXLIB -void edge_setup(void) -{ - edge_class = class_new(gensym("edge"), (t_newmethod)edge_new, - 0, sizeof(t_edge), 0, A_DEFFLOAT, 0); - class_addfloat(edge_class, edge_float); - - post(version); -} -#else -void maxlib_edge_setup(void) -{ - edge_class = class_new(gensym("maxlib_edge"), (t_newmethod)edge_new, - 0, sizeof(t_edge), 0, A_DEFFLOAT, 0); - class_addfloat(edge_class, edge_float); - class_addcreator((t_newmethod)edge_new, gensym("edge"), A_DEFFLOAT, 0); - class_sethelpsymbol(edge_class, gensym("maxlib/edge-help.pd")); -} -#endif - +/* --------------------------- edge ----------------------------------------- */ +/* */ +/* Detect rising or falling edge of float input. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include + +static char *version = "edge v0.1, written by Olaf Matthes "; + +typedef struct edge +{ + t_object x_ob; + t_outlet *x_out1; /* bang on rising edge */ + t_outlet *x_out2; /* bang on falling edge */ + t_float x_lastval; /* last input value */ +} t_edge; + +static void edge_float(t_edge *x, t_floatarg f) +{ + if((x->x_lastval <= 0) && (f >= 1)) /* rising edge */ + outlet_bang(x->x_out1); + else if((x->x_lastval >= 1) && (f <= 0)) /* falling edge */ + outlet_bang(x->x_out2); + + x->x_lastval = f; /* save last value */ +} + +static t_class *edge_class; + +static void *edge_new(t_floatarg f) +{ + int i; + + t_edge *x = (t_edge *)pd_new(edge_class); + x->x_out1 = outlet_new(&x->x_ob, gensym("bang")); + x->x_out2 = outlet_new(&x->x_ob, gensym("bang")); + + x->x_lastval = f; + + return (void *)x; +} + +#ifndef MAXLIB +void edge_setup(void) +{ + edge_class = class_new(gensym("edge"), (t_newmethod)edge_new, + 0, sizeof(t_edge), 0, A_DEFFLOAT, 0); + class_addfloat(edge_class, edge_float); + + logpost(NULL, 4, version); +} +#else +void maxlib_edge_setup(void) +{ + edge_class = class_new(gensym("maxlib_edge"), (t_newmethod)edge_new, + 0, sizeof(t_edge), 0, A_DEFFLOAT, 0); + class_addfloat(edge_class, edge_float); + class_addcreator((t_newmethod)edge_new, gensym("edge"), A_DEFFLOAT, 0); + class_sethelpsymbol(edge_class, gensym("maxlib/edge-help.pd")); +} +#endif + diff --git a/examples/score.txt b/examples/score.txt new file mode 100644 index 0000000..27002f1 --- /dev/null +++ b/examples/score.txt @@ -0,0 +1,25 @@ +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +71 +70 +69 +68 +67 +66 +65 +64 +63 +62 +61 +60 \ No newline at end of file diff --git a/examplescore.txt b/examplescore.txt deleted file mode 100644 index 27002f1..0000000 --- a/examplescore.txt +++ /dev/null @@ -1,25 +0,0 @@ -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -71 -70 -69 -68 -67 -66 -65 -64 -63 -62 -61 -60 \ No newline at end of file diff --git a/expo.c b/expo.c index 231a923..4b65731 100644 --- a/expo.c +++ b/expo.c @@ -1,86 +1,86 @@ -/* ---------------------------- rand_expo ------------------------------------- */ -/* */ -/* rand_expo generates a exponentially distributed random variable. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Based on code found in Dodge/Jerse "Computer Music" */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include -#include -#include - -#define fran() (t_float)rand()/(t_float)RAND_MAX - -static char *version = "expo v0.1, generates exponentially distributed random variable\n" - " written by Olaf Matthes "; - -/* -------------------------- rand_expo ------------------------------ */ - -static t_class *rand_expo_class; - -typedef struct _rand_expo -{ - t_object x_obj; - t_float x_lambda; -} t_rand_expo; - -static void *rand_expo_new(t_floatarg f) -{ - t_rand_expo *x = (t_rand_expo *)pd_new(rand_expo_class); - srand( (unsigned)time( NULL ) ); - floatinlet_new(&x->x_obj, &x->x_lambda); - outlet_new(&x->x_obj, &s_float); - x->x_lambda = f; - return (x); -} - -static void rand_expo_bang(t_rand_expo *x) -{ - t_float u, l; - l = (x->x_lambda <= 0 ? 0.0001 : x->x_lambda); - do - { - u = fran(); - } - while(u == 0); - outlet_float(x->x_obj.ob_outlet, -log(u)/l); -} - -#ifndef MAXLIB -void expo_setup(void) -{ - rand_expo_class = class_new(gensym("expo"), (t_newmethod)rand_expo_new, 0, - sizeof(t_rand_expo), 0, A_DEFFLOAT, 0); - class_addbang(rand_expo_class, rand_expo_bang); - class_sethelpsymbol(rand_expo_class, gensym("expo-help.pd")); - post(version); -} -#else -void maxlib_expo_setup(void) -{ - rand_expo_class = class_new(gensym("maxlib_expo"), (t_newmethod)rand_expo_new, 0, - sizeof(t_rand_expo), 0, A_DEFFLOAT, 0); - class_addbang(rand_expo_class, rand_expo_bang); - class_addcreator((t_newmethod)rand_expo_new, gensym("expo"), A_DEFFLOAT, 0); - class_sethelpsymbol(rand_expo_class, gensym("maxlib/expo-help.pd")); -} -#endif +/* ---------------------------- rand_expo ------------------------------------- */ +/* */ +/* rand_expo generates a exponentially distributed random variable. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Based on code found in Dodge/Jerse "Computer Music" */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include +#include +#include + +#define fran() (t_float)rand()/(t_float)RAND_MAX + +static char *version = "expo v0.1, generates exponentially distributed random variable\n" + " written by Olaf Matthes "; + +/* -------------------------- rand_expo ------------------------------ */ + +static t_class *rand_expo_class; + +typedef struct _rand_expo +{ + t_object x_obj; + t_float x_lambda; +} t_rand_expo; + +static void *rand_expo_new(t_floatarg f) +{ + t_rand_expo *x = (t_rand_expo *)pd_new(rand_expo_class); + srand( (unsigned)time( NULL ) ); + floatinlet_new(&x->x_obj, &x->x_lambda); + outlet_new(&x->x_obj, &s_float); + x->x_lambda = f; + return (x); +} + +static void rand_expo_bang(t_rand_expo *x) +{ + t_float u, l; + l = (x->x_lambda <= 0 ? 0.0001 : x->x_lambda); + do + { + u = fran(); + } + while(u == 0); + outlet_float(x->x_obj.ob_outlet, -log(u)/l); +} + +#ifndef MAXLIB +void expo_setup(void) +{ + rand_expo_class = class_new(gensym("expo"), (t_newmethod)rand_expo_new, 0, + sizeof(t_rand_expo), 0, A_DEFFLOAT, 0); + class_addbang(rand_expo_class, rand_expo_bang); + class_sethelpsymbol(rand_expo_class, gensym("expo-help.pd")); + logpost(NULL, 4, version); +} +#else +void maxlib_expo_setup(void) +{ + rand_expo_class = class_new(gensym("maxlib_expo"), (t_newmethod)rand_expo_new, 0, + sizeof(t_rand_expo), 0, A_DEFFLOAT, 0); + class_addbang(rand_expo_class, rand_expo_bang); + class_addcreator((t_newmethod)rand_expo_new, gensym("expo"), A_DEFFLOAT, 0); + class_sethelpsymbol(rand_expo_class, gensym("maxlib/expo-help.pd")); +} +#endif diff --git a/fifo.c b/fifo.c index c932c07..b747b70 100644 --- a/fifo.c +++ b/fifo.c @@ -1,96 +1,96 @@ -/* ---------------------------- fifo ------------------------------------------ */ -/* */ -/* Fifo buffer of floats, empties itselfe on every bang (in order of coming in) */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* Fifi-code based St. Rainstick fifi.c for Max, */ -/* copyright St. Rainstick, Amsterdam 1995 */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" - -static char *version = "fifo v0.1, written by Olaf Matthes "; - -typedef struct fifo -{ - t_object d_ob; - t_float *getal; - t_int count, end, size; - t_outlet *out; - -}t_fifo; - -static t_class *fifo_class; - -static void fifo_int(t_fifo *x, t_floatarg n) -{ - x->getal[x->count] = n; - x->count = (x->count + 1) % x->size; -} - -static void fifo_bang(t_fifo *x) -{ - if (x->end != x->count){ - outlet_float(x->out,x->getal[x->end]); - x->end = (x->end + 1) % x->size; - } -} - -static void fifo_free(t_fifo *x) -{ - freebytes(x->getal, x->size * sizeof(t_float)); -} - -static void *fifo_new(t_floatarg n) -{ - - t_fifo *x = (t_fifo *)pd_new(fifo_class); - if (n<10) n = 10; - x->size = (t_int)n; - x->end = 0; - x->count = 0; - x->getal = (t_float *)getbytes(x->size * sizeof(t_float)); - x->out = outlet_new(&x->d_ob, gensym("float")); - - return (x); -} - -#ifndef MAXLIB -void fifo_setup(void) -{ - fifo_class = class_new(gensym("fifo"), (t_newmethod)fifo_new, - (t_method)fifo_free, sizeof(t_fifo), 0, A_DEFFLOAT, 0); - class_addfloat(fifo_class, fifo_int); - class_addbang(fifo_class, fifo_bang); - - post(version); -} -#else -void maxlib_fifo_setup(void) -{ - fifo_class = class_new(gensym("maxlib_fifo"), (t_newmethod)fifo_new, - (t_method)fifo_free, sizeof(t_fifo), 0, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)fifo_new, gensym("fifo"), A_DEFFLOAT, 0); - class_addfloat(fifo_class, fifo_int); - class_addbang(fifo_class, fifo_bang); - class_sethelpsymbol(fifo_class, gensym("maxlib/fifo-help.pd")); -} -#endif +/* ---------------------------- fifo ------------------------------------------ */ +/* */ +/* Fifo buffer of floats, empties itselfe on every bang (in order of coming in) */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* Fifi-code based St. Rainstick fifi.c for Max, */ +/* copyright St. Rainstick, Amsterdam 1995 */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" + +static char *version = "fifo v0.1, written by Olaf Matthes "; + +typedef struct fifo +{ + t_object d_ob; + t_float *getal; + t_int count, end, size; + t_outlet *out; + +}t_fifo; + +static t_class *fifo_class; + +static void fifo_int(t_fifo *x, t_floatarg n) +{ + x->getal[x->count] = n; + x->count = (x->count + 1) % x->size; +} + +static void fifo_bang(t_fifo *x) +{ + if (x->end != x->count){ + outlet_float(x->out,x->getal[x->end]); + x->end = (x->end + 1) % x->size; + } +} + +static void fifo_free(t_fifo *x) +{ + freebytes(x->getal, x->size * sizeof(t_float)); +} + +static void *fifo_new(t_floatarg n) +{ + + t_fifo *x = (t_fifo *)pd_new(fifo_class); + if (n<10) n = 10; + x->size = (t_int)n; + x->end = 0; + x->count = 0; + x->getal = (t_float *)getbytes(x->size * sizeof(t_float)); + x->out = outlet_new(&x->d_ob, gensym("float")); + + return (x); +} + +#ifndef MAXLIB +void fifo_setup(void) +{ + fifo_class = class_new(gensym("fifo"), (t_newmethod)fifo_new, + (t_method)fifo_free, sizeof(t_fifo), 0, A_DEFFLOAT, 0); + class_addfloat(fifo_class, fifo_int); + class_addbang(fifo_class, fifo_bang); + + logpost(NULL, 4, version); +} +#else +void maxlib_fifo_setup(void) +{ + fifo_class = class_new(gensym("maxlib_fifo"), (t_newmethod)fifo_new, + (t_method)fifo_free, sizeof(t_fifo), 0, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)fifo_new, gensym("fifo"), A_DEFFLOAT, 0); + class_addfloat(fifo_class, fifo_int); + class_addbang(fifo_class, fifo_bang); + class_sethelpsymbol(fifo_class, gensym("maxlib/fifo-help.pd")); +} +#endif diff --git a/gauss.c b/gauss.c index c1f32bf..3f2270c 100644 --- a/gauss.c +++ b/gauss.c @@ -1,88 +1,88 @@ -/* ---------------------------- rand_gauss ----------------------------------- */ -/* */ -/* rand_gauss generates a gauss distributed random variable. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Based on code found in Dodge/Jerse "Computer Music" */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ +/* ---------------------------- rand_gauss ----------------------------------- */ +/* */ +/* rand_gauss generates a gauss distributed random variable. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Based on code found in Dodge/Jerse "Computer Music" */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ #include "m_pd.h" -#include -#include -#include - -#define fran() (t_float)rand()/(t_float)RAND_MAX +#include +#include +#include -static char *version = "gauss v0.1, generates a Gaussian distributed random variable\n" - " with mean 'mu' and standard deviation 'sigma',\n" - " written by Olaf Matthes "; +#define fran() (t_float)rand()/(t_float)RAND_MAX + +static char *version = "gauss v0.1, generates a Gaussian distributed random variable\n" + " with mean 'mu' and standard deviation 'sigma',\n" + " written by Olaf Matthes "; + +/* -------------------------- rand_gauss ------------------------------ */ + +static t_class *rand_gauss_class; + +typedef struct _rand_gauss +{ + t_object x_obj; + t_float x_sigma; + t_float x_mu; +} t_rand_gauss; + +static void *rand_gauss_new(t_floatarg fs, t_floatarg fm) +{ + t_rand_gauss *x = (t_rand_gauss *)pd_new(rand_gauss_class); + srand( (unsigned)time( NULL ) ); + floatinlet_new(&x->x_obj, &x->x_sigma); + floatinlet_new(&x->x_obj, &x->x_mu); + outlet_new(&x->x_obj, &s_float); + x->x_sigma = fs; + return (x); +} + +static void rand_gauss_bang(t_rand_gauss *x) +{ + t_float u, halfN = 6.0, sum = 0, scale; + t_int k, N = 12; + scale = 1/sqrt(N/12); + for(k = 1; k <= N; k++) + sum += fran(); + outlet_float(x->x_obj.ob_outlet, x->x_sigma*scale*(sum-halfN)+x->x_mu); +} + +#ifndef MAXLIB +void gauss_setup(void) +{ + rand_gauss_class = class_new(gensym("gauss"), (t_newmethod)rand_gauss_new, 0, + sizeof(t_rand_gauss), 0, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addbang(rand_gauss_class, rand_gauss_bang); + class_sethelpsymbol(rand_gauss_class, gensym("gauss-help.pd")); + logpost(NULL, 4, version); +} +#else +void maxlib_gauss_setup(void) +{ + rand_gauss_class = class_new(gensym("maxlib_gauss"), (t_newmethod)rand_gauss_new, 0, + sizeof(t_rand_gauss), 0, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)rand_gauss_new, gensym("gauss"), A_DEFFLOAT, 0); + class_addbang(rand_gauss_class, rand_gauss_bang); + class_sethelpsymbol(rand_gauss_class, gensym("maxlib/gauss-help.pd")); +} +#endif -/* -------------------------- rand_gauss ------------------------------ */ - -static t_class *rand_gauss_class; - -typedef struct _rand_gauss -{ - t_object x_obj; - t_float x_sigma; - t_float x_mu; -} t_rand_gauss; - -static void *rand_gauss_new(t_floatarg fs, t_floatarg fm) -{ - t_rand_gauss *x = (t_rand_gauss *)pd_new(rand_gauss_class); - srand( (unsigned)time( NULL ) ); - floatinlet_new(&x->x_obj, &x->x_sigma); - floatinlet_new(&x->x_obj, &x->x_mu); - outlet_new(&x->x_obj, &s_float); - x->x_sigma = fs; - return (x); -} - -static void rand_gauss_bang(t_rand_gauss *x) -{ - t_float u, halfN = 6.0, sum = 0, scale; - t_int k, N = 12; - scale = 1/sqrt(N/12); - for(k = 1; k <= N; k++) - sum += fran(); - outlet_float(x->x_obj.ob_outlet, x->x_sigma*scale*(sum-halfN)+x->x_mu); -} - -#ifndef MAXLIB -void gauss_setup(void) -{ - rand_gauss_class = class_new(gensym("gauss"), (t_newmethod)rand_gauss_new, 0, - sizeof(t_rand_gauss), 0, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addbang(rand_gauss_class, rand_gauss_bang); - class_sethelpsymbol(rand_gauss_class, gensym("gauss-help.pd")); - post(version); -} -#else -void maxlib_gauss_setup(void) -{ - rand_gauss_class = class_new(gensym("maxlib_gauss"), (t_newmethod)rand_gauss_new, 0, - sizeof(t_rand_gauss), 0, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)rand_gauss_new, gensym("gauss"), A_DEFFLOAT, 0); - class_addbang(rand_gauss_class, rand_gauss_bang); - class_sethelpsymbol(rand_gauss_class, gensym("maxlib/gauss-help.pd")); -} -#endif - diff --git a/gestalt.c b/gestalt.c index 3155206..a929e0d 100644 --- a/gestalt.c +++ b/gestalt.c @@ -1,123 +1,123 @@ -/* ------------------------- gestalt ---------------------------------------- */ -/* */ -/* Find the 'gestalt' of the MIDI input. */ -/* Written by Olaf Matthes */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include -#include -#ifndef _WIN32 -#include -#endif - -static char *version = "gestalt v0.1, written by Olaf Matthes "; - -typedef struct gestalt -{ - t_object x_ob; - t_inlet *x_invelocity; /* inlet for velocity */ - t_outlet *x_outgestalt; /* calculated 'gestalt'-value */ - - t_float x_lastpitch; - t_float x_velocity; - - t_float x_reftime; - - double x_lastontime; - -} t_gestalt; - -static void gestalt_ft1(t_gestalt *x, t_floatarg f) -{ - x->x_velocity = f; -} - -static void gestalt_ft2(t_gestalt *x, t_floatarg f) -{ - if(f > 0.0) x->x_reftime = f; -} - -static void gestalt_float(t_gestalt *x, t_floatarg f) -{ - - int interval, pitch, gestalt; - double ontime = clock_getlogicaltime(); - - if(x->x_velocity) /* only process note-ons */ - { - - pitch = (t_int)f; - if(pitch < 1) pitch = 0; - if(pitch > 127) pitch = 127; - - interval = abs(pitch - x->x_lastpitch); - gestalt = (clock_gettimesince(x->x_lastontime)/x->x_reftime) + interval; - - x->x_lastpitch = pitch; - x->x_lastontime = ontime; - - /* output values from right to left */ - outlet_float(x->x_outgestalt, gestalt); - } -} - -static t_class *gestalt_class; - -static void *gestalt_new(t_floatarg f) -{ - t_gestalt *x = (t_gestalt *)pd_new(gestalt_class); - inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); - inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft2")); - x->x_outgestalt = outlet_new(&x->x_ob, gensym("float")); - - x->x_lastontime = clock_getlogicaltime(); - - x->x_reftime = f; - if(x->x_reftime < 1) x->x_reftime = 1; - - return (void *)x; -} - -#ifndef MAXLIB -void gestalt_setup(void) -{ - gestalt_class = class_new(gensym("gestalt"), (t_newmethod)gestalt_new, - 0, sizeof(t_gestalt), 0, A_DEFFLOAT, 0); - class_addfloat(gestalt_class, gestalt_float); - class_addmethod(gestalt_class, (t_method)gestalt_ft1, gensym("ft1"), A_FLOAT, 0); - class_addmethod(gestalt_class, (t_method)gestalt_ft2, gensym("ft2"), A_FLOAT, 0); - - post(version); -} -#else -void maxlib_gestalt_setup(void) -{ - gestalt_class = class_new(gensym("maxlib_gestalt"), (t_newmethod)gestalt_new, - 0, sizeof(t_gestalt), 0, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)gestalt_new, gensym("gestalt"), A_DEFFLOAT, 0); - class_addfloat(gestalt_class, gestalt_float); - class_addmethod(gestalt_class, (t_method)gestalt_ft1, gensym("ft1"), A_FLOAT, 0); - class_addmethod(gestalt_class, (t_method)gestalt_ft2, gensym("ft2"), A_FLOAT, 0); - class_sethelpsymbol(gestalt_class, gensym("maxlib/gestalt-help.pd")); -} -#endif - +/* ------------------------- gestalt ---------------------------------------- */ +/* */ +/* Find the 'gestalt' of the MIDI input. */ +/* Written by Olaf Matthes */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include +#include +#ifndef _WIN32 +#include +#endif + +static char *version = "gestalt v0.1, written by Olaf Matthes "; + +typedef struct gestalt +{ + t_object x_ob; + t_inlet *x_invelocity; /* inlet for velocity */ + t_outlet *x_outgestalt; /* calculated 'gestalt'-value */ + + t_float x_lastpitch; + t_float x_velocity; + + t_float x_reftime; + + double x_lastontime; + +} t_gestalt; + +static void gestalt_ft1(t_gestalt *x, t_floatarg f) +{ + x->x_velocity = f; +} + +static void gestalt_ft2(t_gestalt *x, t_floatarg f) +{ + if(f > 0.0) x->x_reftime = f; +} + +static void gestalt_float(t_gestalt *x, t_floatarg f) +{ + + int interval, pitch, gestalt; + double ontime = clock_getlogicaltime(); + + if(x->x_velocity) /* only process note-ons */ + { + + pitch = (t_int)f; + if(pitch < 1) pitch = 0; + if(pitch > 127) pitch = 127; + + interval = abs(pitch - x->x_lastpitch); + gestalt = (clock_gettimesince(x->x_lastontime)/x->x_reftime) + interval; + + x->x_lastpitch = pitch; + x->x_lastontime = ontime; + + /* output values from right to left */ + outlet_float(x->x_outgestalt, gestalt); + } +} + +static t_class *gestalt_class; + +static void *gestalt_new(t_floatarg f) +{ + t_gestalt *x = (t_gestalt *)pd_new(gestalt_class); + inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); + inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft2")); + x->x_outgestalt = outlet_new(&x->x_ob, gensym("float")); + + x->x_lastontime = clock_getlogicaltime(); + + x->x_reftime = f; + if(x->x_reftime < 1) x->x_reftime = 1; + + return (void *)x; +} + +#ifndef MAXLIB +void gestalt_setup(void) +{ + gestalt_class = class_new(gensym("gestalt"), (t_newmethod)gestalt_new, + 0, sizeof(t_gestalt), 0, A_DEFFLOAT, 0); + class_addfloat(gestalt_class, gestalt_float); + class_addmethod(gestalt_class, (t_method)gestalt_ft1, gensym("ft1"), A_FLOAT, 0); + class_addmethod(gestalt_class, (t_method)gestalt_ft2, gensym("ft2"), A_FLOAT, 0); + + logpost(NULL, 4, version); +} +#else +void maxlib_gestalt_setup(void) +{ + gestalt_class = class_new(gensym("maxlib_gestalt"), (t_newmethod)gestalt_new, + 0, sizeof(t_gestalt), 0, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)gestalt_new, gensym("gestalt"), A_DEFFLOAT, 0); + class_addfloat(gestalt_class, gestalt_float); + class_addmethod(gestalt_class, (t_method)gestalt_ft1, gensym("ft1"), A_FLOAT, 0); + class_addmethod(gestalt_class, (t_method)gestalt_ft2, gensym("ft2"), A_FLOAT, 0); + class_sethelpsymbol(gestalt_class, gensym("maxlib/gestalt-help.pd")); +} +#endif + diff --git a/history.c b/history.c index 97ff0e7..4c94927 100644 --- a/history.c +++ b/history.c @@ -1,271 +1,271 @@ -/* -------------------------- history ----------------------------------------- */ -/* */ -/* Calculates the average value of the elements within the last N seconds. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include - -#define MAX_ARG 1024 /* maximum number of items to average */ -#define MAX_TIME 60000 /* maximum time to look back */ - -static char *version = "history v0.1, written by Olaf Matthes "; - -typedef struct history -{ - t_object x_ob; - t_clock *x_clock; - t_inlet *x_inindex; - t_outlet *x_outfloat; /* output the history */ - t_outlet *x_outtendency; /* outputs the tendency of the average */ - t_int x_limit; /* indicates if input is 'blocked' (1) */ - t_int x_index; /* the number of elements to average */ - t_float x_input[MAX_ARG]; /* stores the input values we need for averaging */ - double x_intime[MAX_ARG]; /* stores the time of arrival of an element */ - t_int x_inpointer; /* actual position in above array */ - t_float x_average; /* what do you guess ? */ - t_float x_lastaverage; - t_int x_mode; /* how to history: linear or geometric */ - t_int x_time; - -} t_history; - - /* there must be a function for this in math.h but how is the - german 'Fakultät' called in english ???? */ -static int normalise(int i) -{ - int ret = i; - while(i--) - { - if(i == 0)break; - ret += i; - } - return (ret); -} - -static void history_tick(t_history *x) -{ - t_float tendency = 0.0; - if(x->x_lastaverage < x->x_average) - { - tendency = 1.0; /* getting more */ - } - else if(x->x_lastaverage > x->x_average) - { - tendency = -1.0; /* getting less */ - } - else tendency = 0.0; /* nothing has changed */ - outlet_float(x->x_outtendency, tendency); - x->x_lastaverage = x->x_average; - clock_delay(x->x_clock, x->x_time); -} - -static void history_float(t_history *x, t_floatarg f) -{ - int i, j = 0, k = 0, l; - t_float geo = 1.0; - - x->x_average = 0; - /* put value into array */ - x->x_input[x->x_inpointer] = f; - x->x_intime[x->x_inpointer] = clock_getlogicaltime(); - /* look for elements that are too old */ - x->x_index = 0; - for(i = 0; i < MAX_ARG; i++) /* check all valid elements */ - { - if(x->x_intime[i] != 0) - { - if(clock_gettimesince(x->x_intime[i]) <= x->x_time) /* it's in our time window */ - { - x->x_index++; /* count valid entries */ - } - else /* too old, delete entry */ - { - x->x_intime[i] = 0; - } - } - } - if(x->x_index > 1) - { - /* calulate history */ - for(i = 0; i < MAX_ARG; i++) /* check all valid elements */ - { - if(x->x_intime[i] != 0) /* it's a valid entry */ - { - k++; - l = MAX_ARG; - - if(x->x_mode == 0) /* linear */ - { - x->x_average += x->x_input[i] * (1.0 / (float)x->x_index); - } - else if(x->x_mode == 1) /* geometric */ - { - if(x->x_input[i] == 0)x->x_input[i] = 0.001; /* need to cheat a bit... */ - geo *= x->x_input[i]; - if(k == x->x_index) - x->x_average = pow(geo, (1.0/(float)x->x_index)); - } - else if(x->x_mode == 2) /* weighted */ - { - /* normalise output */ - if(k == x->x_index) - { - x->x_average += x->x_input[(j + x->x_inpointer + MAX_ARG) % MAX_ARG] * (float)(x->x_index - k); - x->x_average = x->x_average / (float)normalise(x->x_index - 1); - } - else - { - x->x_average += x->x_input[(j + x->x_inpointer + MAX_ARG) % MAX_ARG] * (float)(x->x_index - k); - j--; /* go back in array */ - while(l--) /* check if this will result in a valid value */ - { - if(x->x_intime[(j + x->x_inpointer + MAX_ARG) % MAX_ARG] == 0) - { - j--; /* go back more if necessary */ - } - else break; /* finished on first non-zero */ - } - } - } else post("history: internal error!"); - } - } - } - else x->x_average = x->x_input[x->x_inpointer]; - - if(++x->x_inpointer > MAX_ARG) - { - x->x_inpointer = 0; - } - outlet_float(x->x_outfloat, x->x_average); -} - -static void history_time(t_history *x, t_floatarg f) -{ - x->x_time = (t_int)f; - if(x->x_time < 1) x->x_time = 1; - if(x->x_time > MAX_TIME)x->x_time = MAX_TIME; - clock_unset(x->x_clock); - clock_delay(x->x_clock, 0); -} - -static void history_reset(t_history *x) -{ - int i; - /* zeroe out the array */ - for(i = 0; i < MAX_ARG; i++) - { - x->x_input[i] = 0.0; - x->x_intime[i] = 0.0; - } - x->x_index = 0; - x->x_inpointer = 0; - x->x_average = 0; - x->x_lastaverage = 0; - post("history: reset"); -} - -static void history_linear(t_history *x) -{ - x->x_mode = 0; - post("history: linear"); -} - -static void history_geometric(t_history *x) -{ - x->x_mode = 1; - post("history: geometric"); -} - -static void history_weight(t_history *x) -{ - x->x_mode = 2; - post("history: weighted"); -} - -static void history_free(t_history *x) -{ - clock_free(x->x_clock); -} - -static t_class *history_class; - -static void *history_new(t_floatarg f) -{ - int i; - - t_history *x = (t_history *)pd_new(history_class); - x->x_inindex = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("time")); - x->x_outfloat = outlet_new(&x->x_ob, gensym("float")); - x->x_outtendency = outlet_new(&x->x_ob, gensym("float")); - x->x_clock = clock_new(x, (t_method)history_tick); - /* zeroe out the array */ - for(i = 0; i < MAX_ARG; i++) - { - x->x_input[i] = 0.0; - x->x_intime[i] = 0.0; - } - x->x_time = (t_int)f; - if(x->x_time < 1) x->x_time = 1; - if(x->x_time > MAX_TIME) - { - x->x_time = MAX_TIME; - post("history: set number time to %d", x->x_time); - } - x->x_index = 0; - x->x_inpointer = 0; - x->x_average = 0; - x->x_mode = 0; - clock_delay(x->x_clock, 0); - - return (void *)x; -} - -#ifndef MAXLIB -void history_setup(void) -{ - history_class = class_new(gensym("history"), (t_newmethod)history_new, - (t_method)history_free, sizeof(t_history), 0, A_DEFFLOAT, 0); - class_addmethod(history_class, (t_method)history_reset, gensym("reset"), 0); - class_addmethod(history_class, (t_method)history_linear, gensym("linear"), 0); - class_addmethod(history_class, (t_method)history_geometric, gensym("geometric"), 0); - class_addmethod(history_class, (t_method)history_weight, gensym("weight"), 0); - class_addfloat(history_class, history_float); - class_addmethod(history_class, (t_method)history_time, gensym("time"), A_FLOAT, 0); - - post(version); -} -#else -void maxlib_history_setup(void) -{ - history_class = class_new(gensym("maxlib_history"), (t_newmethod)history_new, - (t_method)history_free, sizeof(t_history), 0, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)history_new, gensym("history"), A_DEFFLOAT, 0); - class_addmethod(history_class, (t_method)history_reset, gensym("reset"), 0); - class_addmethod(history_class, (t_method)history_linear, gensym("linear"), 0); - class_addmethod(history_class, (t_method)history_geometric, gensym("geometric"), 0); - class_addmethod(history_class, (t_method)history_weight, gensym("weight"), 0); - class_addfloat(history_class, history_float); - class_addmethod(history_class, (t_method)history_time, gensym("time"), A_FLOAT, 0); - class_sethelpsymbol(history_class, gensym("maxlib/history-help.pd")); -} -#endif +/* -------------------------- history ----------------------------------------- */ +/* */ +/* Calculates the average value of the elements within the last N seconds. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include + +#define MAX_ARG 1024 /* maximum number of items to average */ +#define MAX_TIME 60000 /* maximum time to look back */ + +static char *version = "history v0.1, written by Olaf Matthes "; + +typedef struct history +{ + t_object x_ob; + t_clock *x_clock; + t_inlet *x_inindex; + t_outlet *x_outfloat; /* output the history */ + t_outlet *x_outtendency; /* outputs the tendency of the average */ + t_int x_limit; /* indicates if input is 'blocked' (1) */ + t_int x_index; /* the number of elements to average */ + t_float x_input[MAX_ARG]; /* stores the input values we need for averaging */ + double x_intime[MAX_ARG]; /* stores the time of arrival of an element */ + t_int x_inpointer; /* actual position in above array */ + t_float x_average; /* what do you guess ? */ + t_float x_lastaverage; + t_int x_mode; /* how to history: linear or geometric */ + t_int x_time; + +} t_history; + + /* there must be a function for this in math.h but how is the + german 'Fakultät' called in english ???? */ +static int normalise(int i) +{ + int ret = i; + while(i--) + { + if(i == 0)break; + ret += i; + } + return (ret); +} + +static void history_tick(t_history *x) +{ + t_float tendency = 0.0; + if(x->x_lastaverage < x->x_average) + { + tendency = 1.0; /* getting more */ + } + else if(x->x_lastaverage > x->x_average) + { + tendency = -1.0; /* getting less */ + } + else tendency = 0.0; /* nothing has changed */ + outlet_float(x->x_outtendency, tendency); + x->x_lastaverage = x->x_average; + clock_delay(x->x_clock, x->x_time); +} + +static void history_float(t_history *x, t_floatarg f) +{ + int i, j = 0, k = 0, l; + t_float geo = 1.0; + + x->x_average = 0; + /* put value into array */ + x->x_input[x->x_inpointer] = f; + x->x_intime[x->x_inpointer] = clock_getlogicaltime(); + /* look for elements that are too old */ + x->x_index = 0; + for(i = 0; i < MAX_ARG; i++) /* check all valid elements */ + { + if(x->x_intime[i] != 0) + { + if(clock_gettimesince(x->x_intime[i]) <= x->x_time) /* it's in our time window */ + { + x->x_index++; /* count valid entries */ + } + else /* too old, delete entry */ + { + x->x_intime[i] = 0; + } + } + } + if(x->x_index > 1) + { + /* calulate history */ + for(i = 0; i < MAX_ARG; i++) /* check all valid elements */ + { + if(x->x_intime[i] != 0) /* it's a valid entry */ + { + k++; + l = MAX_ARG; + + if(x->x_mode == 0) /* linear */ + { + x->x_average += x->x_input[i] * (1.0 / (float)x->x_index); + } + else if(x->x_mode == 1) /* geometric */ + { + if(x->x_input[i] == 0)x->x_input[i] = 0.001; /* need to cheat a bit... */ + geo *= x->x_input[i]; + if(k == x->x_index) + x->x_average = pow(geo, (1.0/(float)x->x_index)); + } + else if(x->x_mode == 2) /* weighted */ + { + /* normalise output */ + if(k == x->x_index) + { + x->x_average += x->x_input[(j + x->x_inpointer + MAX_ARG) % MAX_ARG] * (float)(x->x_index - k); + x->x_average = x->x_average / (float)normalise(x->x_index - 1); + } + else + { + x->x_average += x->x_input[(j + x->x_inpointer + MAX_ARG) % MAX_ARG] * (float)(x->x_index - k); + j--; /* go back in array */ + while(l--) /* check if this will result in a valid value */ + { + if(x->x_intime[(j + x->x_inpointer + MAX_ARG) % MAX_ARG] == 0) + { + j--; /* go back more if necessary */ + } + else break; /* finished on first non-zero */ + } + } + } else post("history: internal error!"); + } + } + } + else x->x_average = x->x_input[x->x_inpointer]; + + if(++x->x_inpointer > MAX_ARG) + { + x->x_inpointer = 0; + } + outlet_float(x->x_outfloat, x->x_average); +} + +static void history_time(t_history *x, t_floatarg f) +{ + x->x_time = (t_int)f; + if(x->x_time < 1) x->x_time = 1; + if(x->x_time > MAX_TIME)x->x_time = MAX_TIME; + clock_unset(x->x_clock); + clock_delay(x->x_clock, 0); +} + +static void history_reset(t_history *x) +{ + int i; + /* zeroe out the array */ + for(i = 0; i < MAX_ARG; i++) + { + x->x_input[i] = 0.0; + x->x_intime[i] = 0.0; + } + x->x_index = 0; + x->x_inpointer = 0; + x->x_average = 0; + x->x_lastaverage = 0; + post("history: reset"); +} + +static void history_linear(t_history *x) +{ + x->x_mode = 0; + post("history: linear"); +} + +static void history_geometric(t_history *x) +{ + x->x_mode = 1; + post("history: geometric"); +} + +static void history_weight(t_history *x) +{ + x->x_mode = 2; + post("history: weighted"); +} + +static void history_free(t_history *x) +{ + clock_free(x->x_clock); +} + +static t_class *history_class; + +static void *history_new(t_floatarg f) +{ + int i; + + t_history *x = (t_history *)pd_new(history_class); + x->x_inindex = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("time")); + x->x_outfloat = outlet_new(&x->x_ob, gensym("float")); + x->x_outtendency = outlet_new(&x->x_ob, gensym("float")); + x->x_clock = clock_new(x, (t_method)history_tick); + /* zeroe out the array */ + for(i = 0; i < MAX_ARG; i++) + { + x->x_input[i] = 0.0; + x->x_intime[i] = 0.0; + } + x->x_time = (t_int)f; + if(x->x_time < 1) x->x_time = 1; + if(x->x_time > MAX_TIME) + { + x->x_time = MAX_TIME; + post("history: set number time to %d", x->x_time); + } + x->x_index = 0; + x->x_inpointer = 0; + x->x_average = 0; + x->x_mode = 0; + clock_delay(x->x_clock, 0); + + return (void *)x; +} + +#ifndef MAXLIB +void history_setup(void) +{ + history_class = class_new(gensym("history"), (t_newmethod)history_new, + (t_method)history_free, sizeof(t_history), 0, A_DEFFLOAT, 0); + class_addmethod(history_class, (t_method)history_reset, gensym("reset"), 0); + class_addmethod(history_class, (t_method)history_linear, gensym("linear"), 0); + class_addmethod(history_class, (t_method)history_geometric, gensym("geometric"), 0); + class_addmethod(history_class, (t_method)history_weight, gensym("weight"), 0); + class_addfloat(history_class, history_float); + class_addmethod(history_class, (t_method)history_time, gensym("time"), A_FLOAT, 0); + + logpost(NULL, 4, version); +} +#else +void maxlib_history_setup(void) +{ + history_class = class_new(gensym("maxlib_history"), (t_newmethod)history_new, + (t_method)history_free, sizeof(t_history), 0, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)history_new, gensym("history"), A_DEFFLOAT, 0); + class_addmethod(history_class, (t_method)history_reset, gensym("reset"), 0); + class_addmethod(history_class, (t_method)history_linear, gensym("linear"), 0); + class_addmethod(history_class, (t_method)history_geometric, gensym("geometric"), 0); + class_addmethod(history_class, (t_method)history_weight, gensym("weight"), 0); + class_addfloat(history_class, history_float); + class_addmethod(history_class, (t_method)history_time, gensym("time"), A_FLOAT, 0); + class_sethelpsymbol(history_class, gensym("maxlib/history-help.pd")); +} +#endif diff --git a/ignore.c b/ignore.c index 4dda16d..098751d 100644 --- a/ignore.c +++ b/ignore.c @@ -1,119 +1,119 @@ -/* ------------------------- ignore ------------------------------------------- */ -/* */ -/* Ignores input that is followed by next value faster than N ms. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" - -static char *version = "ignore v0.1, written by Olaf Matthes "; - -typedef struct ignore -{ - t_object x_ob; - t_clock *x_clock; - t_inlet *x_intime; - t_outlet *x_outfloat; - t_float x_input; - t_float x_lastinput; - t_int x_limit; /* indicates if input is 'blocked' (1) */ - t_int x_time; /* the time in ms */ -} t_ignore; - -static void ignore_tick(t_ignore *x) -{ - x->x_limit = 0; - /* output in case nothing has changed */ - if(x->x_lastinput == x->x_input) - outlet_float(x->x_outfloat, x->x_lastinput); -} - -static void ignore_float(t_ignore *x, t_floatarg f) -{ - x->x_input = f; - if(!x->x_limit) - { - x->x_limit = 1; /* ignore input within next N ms */ - clock_delay(x->x_clock, x->x_time); /* start clock */ - } - else /* ignore / start clock again */ - { - x->x_lastinput = x->x_input; /* save current as last valid value */ - clock_unset(x->x_clock); /* throw out last clock */ - clock_delay(x->x_clock, x->x_time); /* start new clock */ - } -} - -static void ignore_time(t_ignore *x, t_floatarg f) -{ - x->x_time = (t_int)f; -} - -static void ignore_reset(t_ignore *x) -{ - x->x_limit = 0; - post("ignore: reset"); -} - -static void ignore_free(t_ignore *x) -{ - clock_free(x->x_clock); -} - -static t_class *ignore_class; - -static void *ignore_new(t_floatarg f) -{ - t_ignore *x = (t_ignore *)pd_new(ignore_class); - x->x_intime = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("time")); - x->x_outfloat = outlet_new(&x->x_ob, gensym("float")); - x->x_clock = clock_new(x, (t_method)ignore_tick); - - x->x_time = (t_int)f; - x->x_lastinput = 0; - - return (void *)x; -} - -#ifndef MAXLIB -void ignore_setup(void) -{ - ignore_class = class_new(gensym("ignore"), (t_newmethod)ignore_new, - (t_method)ignore_free, sizeof(t_ignore), 0, A_DEFFLOAT, 0); - class_addmethod(ignore_class, (t_method)ignore_reset, gensym("reset"), 0); - class_addmethod(ignore_class, (t_method)ignore_time, gensym("time"), A_FLOAT, 0); - class_addfloat(ignore_class, ignore_float); - - post(version); -} -#else -void maxlib_ignore_setup(void) -{ - ignore_class = class_new(gensym("maxlib_ignore"), (t_newmethod)ignore_new, - (t_method)ignore_free, sizeof(t_ignore), 0, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)ignore_new, gensym("ignore"), A_DEFFLOAT, 0); - class_addmethod(ignore_class, (t_method)ignore_reset, gensym("reset"), 0); - class_addmethod(ignore_class, (t_method)ignore_time, gensym("time"), A_FLOAT, 0); - class_addfloat(ignore_class, ignore_float); - class_sethelpsymbol(ignore_class, gensym("maxlib/ignore-help.pd")); -} -#endif - +/* ------------------------- ignore ------------------------------------------- */ +/* */ +/* Ignores input that is followed by next value faster than N ms. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" + +static char *version = "ignore v0.1, written by Olaf Matthes "; + +typedef struct ignore +{ + t_object x_ob; + t_clock *x_clock; + t_inlet *x_intime; + t_outlet *x_outfloat; + t_float x_input; + t_float x_lastinput; + t_int x_limit; /* indicates if input is 'blocked' (1) */ + t_int x_time; /* the time in ms */ +} t_ignore; + +static void ignore_tick(t_ignore *x) +{ + x->x_limit = 0; + /* output in case nothing has changed */ + if(x->x_lastinput == x->x_input) + outlet_float(x->x_outfloat, x->x_lastinput); +} + +static void ignore_float(t_ignore *x, t_floatarg f) +{ + x->x_input = f; + if(!x->x_limit) + { + x->x_limit = 1; /* ignore input within next N ms */ + clock_delay(x->x_clock, x->x_time); /* start clock */ + } + else /* ignore / start clock again */ + { + x->x_lastinput = x->x_input; /* save current as last valid value */ + clock_unset(x->x_clock); /* throw out last clock */ + clock_delay(x->x_clock, x->x_time); /* start new clock */ + } +} + +static void ignore_time(t_ignore *x, t_floatarg f) +{ + x->x_time = (t_int)f; +} + +static void ignore_reset(t_ignore *x) +{ + x->x_limit = 0; + post("ignore: reset"); +} + +static void ignore_free(t_ignore *x) +{ + clock_free(x->x_clock); +} + +static t_class *ignore_class; + +static void *ignore_new(t_floatarg f) +{ + t_ignore *x = (t_ignore *)pd_new(ignore_class); + x->x_intime = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("time")); + x->x_outfloat = outlet_new(&x->x_ob, gensym("float")); + x->x_clock = clock_new(x, (t_method)ignore_tick); + + x->x_time = (t_int)f; + x->x_lastinput = 0; + + return (void *)x; +} + +#ifndef MAXLIB +void ignore_setup(void) +{ + ignore_class = class_new(gensym("ignore"), (t_newmethod)ignore_new, + (t_method)ignore_free, sizeof(t_ignore), 0, A_DEFFLOAT, 0); + class_addmethod(ignore_class, (t_method)ignore_reset, gensym("reset"), 0); + class_addmethod(ignore_class, (t_method)ignore_time, gensym("time"), A_FLOAT, 0); + class_addfloat(ignore_class, ignore_float); + + logpost(NULL, 4, version); +} +#else +void maxlib_ignore_setup(void) +{ + ignore_class = class_new(gensym("maxlib_ignore"), (t_newmethod)ignore_new, + (t_method)ignore_free, sizeof(t_ignore), 0, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)ignore_new, gensym("ignore"), A_DEFFLOAT, 0); + class_addmethod(ignore_class, (t_method)ignore_reset, gensym("reset"), 0); + class_addmethod(ignore_class, (t_method)ignore_time, gensym("time"), A_FLOAT, 0); + class_addfloat(ignore_class, ignore_float); + class_sethelpsymbol(ignore_class, gensym("maxlib/ignore-help.pd")); +} +#endif + diff --git a/iso.c b/iso.c index 43af2b1..69a13ec 100644 --- a/iso.c +++ b/iso.c @@ -1,219 +1,219 @@ -/* ---------------------------- iso ------------------------------------------- */ -/* */ -/* Queue up pitch and attack point series. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Based on iso for Max by Charlie Baker (baker@foxtrot.ccmrc.ucsb.edu). */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include - -#define MAXPOLY 32 - -static char *version = "iso v0.1, written for Max by Charlie Baker \n" - " ported to Pd by Olaf Matthes "; - -/* Iso object data structure */ - -typedef struct iso -{ - t_object iso_ob; - t_outlet *iso_out1; /* outlet 1*/ - t_outlet *iso_out2; /* outlet 2*/ - t_inlet *iso_in2; /* inlet 2 (attack list) */ - t_clock *iso_clock; - t_int ptchlength,atklength,curptch,curatk; - t_float pitches[MAXPOLY]; - t_float atks[MAXPOLY]; - t_int loop,stop; - t_float hook,duty; -} t_iso; - -static t_class *iso_class; - -/* take list and create matrix */ - -static void iso_bang(t_iso *x) -{ - x->stop = 0; - x->curptch = 0; - x->curatk = 0; - clock_delay(x->iso_clock, 0); -} - - -static void iso_clock_fun(t_iso *x) -{ - if (!x->stop) { - clock_delay(x->iso_clock, (double)(x->atks[x->curatk] * x->hook)); - outlet_float(x->iso_out2,(t_float)(x->atks[x->curatk] * x->hook * x->duty)); - outlet_float(x->iso_out1,x->pitches[x->curptch] ); - if (x->loop) { - x->curatk = ((x->curatk + 1) % x->atklength); - x->curptch = ((x->curptch + 1) % x->ptchlength); - } - else { - if (((x->curatk + 1) >= x->atklength) || ((x->curptch + 1) >= x->ptchlength)) - x->stop = 1; - else { - x->curptch += 1; - x->curatk += 1; - } - } - } -} - -static void iso_hook(t_iso *x, t_floatarg hook) -{ - if (hook < 1.0) hook = 1.0; - x->hook = (t_float)hook; -} - -static void iso_duty(t_iso *x, t_floatarg duty) -{ - if (duty < 1.0) duty = 1.0; - x->duty = (t_float)duty; -} - -static void iso_list(t_iso *x, t_symbol *s, t_int argc, t_atom* argv) -{ - int i; - if (argc > MAXPOLY) post("iso: only %d values max. allowed in list!", MAXPOLY); - for (i = 0; i < argc; i++) x->atks[i] = argv[i].a_w.w_float; - x->atklength = argc; -} - -static void iso_pitch(t_iso *x, t_symbol *s, t_int argc, t_atom* argv) -{ - int i; - if (argc > MAXPOLY) post("iso: only %d values max. allowed in list!", MAXPOLY); - for (i = 0; i < argc; i++) x->pitches[i] = argv[i].a_w.w_float; - x->ptchlength = argc; -} - -static void iso_start(t_iso *x, t_symbol *s, t_int argc, t_atom* argv) -{ - t_int start = atom_getfloatarg(0, argc, argv); - x->stop = 0; - if (start) { - x->curptch = (t_int)((start - 1) % x->ptchlength); - x->curatk = (t_int)((start - 1) % x->atklength); - } - else { - x->curptch = 0; - x->curatk = 0; - } - clock_delay(x->iso_clock, 0); -} - -static void iso_stop(t_iso *x) -{ - x->stop = 1; - x->curatk = 0; - x->curptch = 0; -} - -static void iso_pause(t_iso *x) -{ - x->stop = 1; -} - -static void iso_loop(t_iso *x) -{ - x->loop = 1; -} - -static void iso_resume(t_iso *x) -{ - x->stop = 0; - clock_delay(x->iso_clock, 0); -} - -static void iso_unloop(t_iso *x) -{ - x->loop = 0; -} - - -static void *iso_new(void) { - t_iso *x = (t_iso *)pd_new(iso_class); /* allocates memory and sticks in an inlet */ - x->iso_clock = clock_new(x, (t_method)iso_clock_fun); - x->iso_out1 = outlet_new(&x->iso_ob, gensym("float")); - x->iso_out2 = outlet_new(&x->iso_ob, gensym("float")); - x->iso_in2 = inlet_new(&x->iso_ob, &x->iso_ob.ob_pd, gensym("list"), gensym("attack")); - x->stop = 0; - x->loop = 1; - x->hook = 1.0; - x->curptch = 0; - x->curatk = 0; - x->ptchlength = 1; - x->atklength = 1; - x->pitches[0] = 60; - x->atks[0] = 500; - x->duty = 1.0; - - return (x); /* always return a copy of the created object */ -} - -static void iso_free(t_iso *x) { - - clock_free(x->iso_clock); -} - -#ifndef MAXLIB -void iso_setup(void) { - - iso_class = class_new(gensym("iso"), (t_newmethod)iso_new, - (t_method)iso_free, sizeof(t_iso), 0, 0); - class_addmethod(iso_class, (t_method)iso_duty, gensym("duty"), A_FLOAT, 0); - class_addmethod(iso_class, (t_method)iso_list, gensym("attack"), A_GIMME, 0); - class_addmethod(iso_class, (t_method)iso_start, gensym("start"), A_GIMME, 0); - class_addmethod(iso_class, (t_method)iso_stop, gensym("stop"), 0); - class_addmethod(iso_class, (t_method)iso_pause, gensym("pause"), 0); - class_addmethod(iso_class, (t_method)iso_loop, gensym("loop"), 0); - class_addmethod(iso_class, (t_method)iso_unloop, gensym("unloop"), 0); - class_addmethod(iso_class, (t_method)iso_resume, gensym("resume"), 0); - class_addmethod(iso_class, (t_method)iso_hook, gensym("hook"), A_FLOAT, 0); - class_addbang(iso_class, iso_bang); - class_addlist(iso_class, iso_pitch); - - post(version); -} -#else -void maxlib_iso_setup(void) { - - iso_class = class_new(gensym("maxlib_iso"), (t_newmethod)iso_new, - (t_method)iso_free, sizeof(t_iso), 0, 0); - class_addcreator((t_newmethod)iso_new, gensym("iso"), 0); - class_addmethod(iso_class, (t_method)iso_duty, gensym("duty"), A_FLOAT, 0); - class_addmethod(iso_class, (t_method)iso_list, gensym("attack"), A_GIMME, 0); - class_addmethod(iso_class, (t_method)iso_start, gensym("start"), A_GIMME, 0); - class_addmethod(iso_class, (t_method)iso_stop, gensym("stop"), 0); - class_addmethod(iso_class, (t_method)iso_pause, gensym("pause"), 0); - class_addmethod(iso_class, (t_method)iso_loop, gensym("loop"), 0); - class_addmethod(iso_class, (t_method)iso_unloop, gensym("unloop"), 0); - class_addmethod(iso_class, (t_method)iso_resume, gensym("resume"), 0); - class_addmethod(iso_class, (t_method)iso_hook, gensym("hook"), A_FLOAT, 0); - class_addbang(iso_class, iso_bang); - class_addlist(iso_class, iso_pitch); - class_sethelpsymbol(iso_class, gensym("maxlib/iso-help.pd")); -} -#endif +/* ---------------------------- iso ------------------------------------------- */ +/* */ +/* Queue up pitch and attack point series. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Based on iso for Max by Charlie Baker (baker@foxtrot.ccmrc.ucsb.edu). */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include + +#define MAXPOLY 32 + +static char *version = "iso v0.1, written for Max by Charlie Baker \n" + " ported to Pd by Olaf Matthes "; + +/* Iso object data structure */ + +typedef struct iso +{ + t_object iso_ob; + t_outlet *iso_out1; /* outlet 1*/ + t_outlet *iso_out2; /* outlet 2*/ + t_inlet *iso_in2; /* inlet 2 (attack list) */ + t_clock *iso_clock; + t_int ptchlength,atklength,curptch,curatk; + t_float pitches[MAXPOLY]; + t_float atks[MAXPOLY]; + t_int loop,stop; + t_float hook,duty; +} t_iso; + +static t_class *iso_class; + +/* take list and create matrix */ + +static void iso_bang(t_iso *x) +{ + x->stop = 0; + x->curptch = 0; + x->curatk = 0; + clock_delay(x->iso_clock, 0); +} + + +static void iso_clock_fun(t_iso *x) +{ + if (!x->stop) { + clock_delay(x->iso_clock, (double)(x->atks[x->curatk] * x->hook)); + outlet_float(x->iso_out2,(t_float)(x->atks[x->curatk] * x->hook * x->duty)); + outlet_float(x->iso_out1,x->pitches[x->curptch] ); + if (x->loop) { + x->curatk = ((x->curatk + 1) % x->atklength); + x->curptch = ((x->curptch + 1) % x->ptchlength); + } + else { + if (((x->curatk + 1) >= x->atklength) || ((x->curptch + 1) >= x->ptchlength)) + x->stop = 1; + else { + x->curptch += 1; + x->curatk += 1; + } + } + } +} + +static void iso_hook(t_iso *x, t_floatarg hook) +{ + if (hook < 1.0) hook = 1.0; + x->hook = (t_float)hook; +} + +static void iso_duty(t_iso *x, t_floatarg duty) +{ + if (duty < 1.0) duty = 1.0; + x->duty = (t_float)duty; +} + +static void iso_list(t_iso *x, t_symbol *s, t_int argc, t_atom* argv) +{ + int i; + if (argc > MAXPOLY) post("iso: only %d values max. allowed in list!", MAXPOLY); + for (i = 0; i < argc; i++) x->atks[i] = argv[i].a_w.w_float; + x->atklength = argc; +} + +static void iso_pitch(t_iso *x, t_symbol *s, t_int argc, t_atom* argv) +{ + int i; + if (argc > MAXPOLY) post("iso: only %d values max. allowed in list!", MAXPOLY); + for (i = 0; i < argc; i++) x->pitches[i] = argv[i].a_w.w_float; + x->ptchlength = argc; +} + +static void iso_start(t_iso *x, t_symbol *s, t_int argc, t_atom* argv) +{ + t_int start = atom_getfloatarg(0, argc, argv); + x->stop = 0; + if (start) { + x->curptch = (t_int)((start - 1) % x->ptchlength); + x->curatk = (t_int)((start - 1) % x->atklength); + } + else { + x->curptch = 0; + x->curatk = 0; + } + clock_delay(x->iso_clock, 0); +} + +static void iso_stop(t_iso *x) +{ + x->stop = 1; + x->curatk = 0; + x->curptch = 0; +} + +static void iso_pause(t_iso *x) +{ + x->stop = 1; +} + +static void iso_loop(t_iso *x) +{ + x->loop = 1; +} + +static void iso_resume(t_iso *x) +{ + x->stop = 0; + clock_delay(x->iso_clock, 0); +} + +static void iso_unloop(t_iso *x) +{ + x->loop = 0; +} + + +static void *iso_new(void) { + t_iso *x = (t_iso *)pd_new(iso_class); /* allocates memory and sticks in an inlet */ + x->iso_clock = clock_new(x, (t_method)iso_clock_fun); + x->iso_out1 = outlet_new(&x->iso_ob, gensym("float")); + x->iso_out2 = outlet_new(&x->iso_ob, gensym("float")); + x->iso_in2 = inlet_new(&x->iso_ob, &x->iso_ob.ob_pd, gensym("list"), gensym("attack")); + x->stop = 0; + x->loop = 1; + x->hook = 1.0; + x->curptch = 0; + x->curatk = 0; + x->ptchlength = 1; + x->atklength = 1; + x->pitches[0] = 60; + x->atks[0] = 500; + x->duty = 1.0; + + return (x); /* always return a copy of the created object */ +} + +static void iso_free(t_iso *x) { + + clock_free(x->iso_clock); +} + +#ifndef MAXLIB +void iso_setup(void) { + + iso_class = class_new(gensym("iso"), (t_newmethod)iso_new, + (t_method)iso_free, sizeof(t_iso), 0, 0); + class_addmethod(iso_class, (t_method)iso_duty, gensym("duty"), A_FLOAT, 0); + class_addmethod(iso_class, (t_method)iso_list, gensym("attack"), A_GIMME, 0); + class_addmethod(iso_class, (t_method)iso_start, gensym("start"), A_GIMME, 0); + class_addmethod(iso_class, (t_method)iso_stop, gensym("stop"), 0); + class_addmethod(iso_class, (t_method)iso_pause, gensym("pause"), 0); + class_addmethod(iso_class, (t_method)iso_loop, gensym("loop"), 0); + class_addmethod(iso_class, (t_method)iso_unloop, gensym("unloop"), 0); + class_addmethod(iso_class, (t_method)iso_resume, gensym("resume"), 0); + class_addmethod(iso_class, (t_method)iso_hook, gensym("hook"), A_FLOAT, 0); + class_addbang(iso_class, iso_bang); + class_addlist(iso_class, iso_pitch); + + logpost(NULL, 4, version); +} +#else +void maxlib_iso_setup(void) { + + iso_class = class_new(gensym("maxlib_iso"), (t_newmethod)iso_new, + (t_method)iso_free, sizeof(t_iso), 0, 0); + class_addcreator((t_newmethod)iso_new, gensym("iso"), 0); + class_addmethod(iso_class, (t_method)iso_duty, gensym("duty"), A_FLOAT, 0); + class_addmethod(iso_class, (t_method)iso_list, gensym("attack"), A_GIMME, 0); + class_addmethod(iso_class, (t_method)iso_start, gensym("start"), A_GIMME, 0); + class_addmethod(iso_class, (t_method)iso_stop, gensym("stop"), 0); + class_addmethod(iso_class, (t_method)iso_pause, gensym("pause"), 0); + class_addmethod(iso_class, (t_method)iso_loop, gensym("loop"), 0); + class_addmethod(iso_class, (t_method)iso_unloop, gensym("unloop"), 0); + class_addmethod(iso_class, (t_method)iso_resume, gensym("resume"), 0); + class_addmethod(iso_class, (t_method)iso_hook, gensym("hook"), A_FLOAT, 0); + class_addbang(iso_class, iso_bang); + class_addlist(iso_class, iso_pitch); + class_sethelpsymbol(iso_class, gensym("maxlib/iso-help.pd")); +} +#endif diff --git a/lifo.c b/lifo.c index 81e2dc0..3f062ae 100644 --- a/lifo.c +++ b/lifo.c @@ -1,109 +1,109 @@ -/* ---------------------------- lifo ------------------------------------------ */ -/* */ -/* lifo buffer of floats, empties itselfe on every bang (in order of coming in) */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* Fifi-code based St. Rainstick fifo.c for Max, */ -/* copyright St. Rainstick, Amsterdam 1995 */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" - -static char *version = "lifo v0.1, written by Olaf Matthes "; - -typedef struct lifo -{ - t_object d_ob; - t_float *getal; - t_int size, teller; - t_outlet *out; - -}t_lifo; - -static t_class *lifo_class; - -static void lifo_int(t_lifo *x, t_floatarg n) +/* ---------------------------- lifo ------------------------------------------ */ +/* */ +/* lifo buffer of floats, empties itselfe on every bang (in order of coming in) */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* Fifi-code based St. Rainstick fifo.c for Max, */ +/* copyright St. Rainstick, Amsterdam 1995 */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" + +static char *version = "lifo v0.1, written by Olaf Matthes "; + +typedef struct lifo +{ + t_object d_ob; + t_float *getal; + t_int size, teller; + t_outlet *out; + +}t_lifo; + +static t_class *lifo_class; + +static void lifo_int(t_lifo *x, t_floatarg n) { if(x->teller < x->size ) { - x->getal[x->teller] = n; + x->getal[x->teller] = n; x->teller++; } else post("no more lifo memory"); - -} - -static void lifo_bang(t_lifo *x) -{ + +} + +static void lifo_bang(t_lifo *x) +{ if (x->teller > 0) - { - outlet_float(x->out,x->getal[x->teller-1]); - x->teller--; - } -} - -static void lifo_clear(t_lifo *x) -{ - x->teller = 0; -} - -static void lifo_free(t_lifo *x) -{ - freebytes(x->getal, x->size * sizeof(t_float)); -} - -static void *lifo_new(t_floatarg n) -{ - - t_lifo *x = (t_lifo *)pd_new(lifo_class); - if (n<10) n = 10; - x->size = (t_int)n; - x->teller = 0; - x->getal = (t_float *)getbytes(x->size * sizeof(t_float)); - x->out = outlet_new(&x->d_ob, gensym("float")); - - return (x); -} - -#ifndef MAXLIB -void lifo_setup(void) -{ - lifo_class = class_new(gensym("lifo"), (t_newmethod)lifo_new, - (t_method)lifo_free, sizeof(t_lifo), 0, A_DEFFLOAT, 0); - class_addfloat(lifo_class, lifo_int); - class_addbang(lifo_class, lifo_bang); - class_addmethod(lifo_class, (t_method)lifo_clear, gensym("clear"), 0); - - post(version); -} -#else -void maxlib_lifo_setup(void) -{ - lifo_class = class_new(gensym("maxlib_lifo"), (t_newmethod)lifo_new, - (t_method)lifo_free, sizeof(t_lifo), 0, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)lifo_new, gensym("lifo"), A_DEFFLOAT, 0); - class_addfloat(lifo_class, lifo_int); - class_addbang(lifo_class, lifo_bang); - class_addmethod(lifo_class, (t_method)lifo_clear, gensym("clear"), 0); - class_sethelpsymbol(lifo_class, gensym("maxlib/lifo-help.pd")); -} -#endif + { + outlet_float(x->out,x->getal[x->teller-1]); + x->teller--; + } +} + +static void lifo_clear(t_lifo *x) +{ + x->teller = 0; +} + +static void lifo_free(t_lifo *x) +{ + freebytes(x->getal, x->size * sizeof(t_float)); +} + +static void *lifo_new(t_floatarg n) +{ + + t_lifo *x = (t_lifo *)pd_new(lifo_class); + if (n<10) n = 10; + x->size = (t_int)n; + x->teller = 0; + x->getal = (t_float *)getbytes(x->size * sizeof(t_float)); + x->out = outlet_new(&x->d_ob, gensym("float")); + + return (x); +} + +#ifndef MAXLIB +void lifo_setup(void) +{ + lifo_class = class_new(gensym("lifo"), (t_newmethod)lifo_new, + (t_method)lifo_free, sizeof(t_lifo), 0, A_DEFFLOAT, 0); + class_addfloat(lifo_class, lifo_int); + class_addbang(lifo_class, lifo_bang); + class_addmethod(lifo_class, (t_method)lifo_clear, gensym("clear"), 0); + + logpost(NULL, 4, version); +} +#else +void maxlib_lifo_setup(void) +{ + lifo_class = class_new(gensym("maxlib_lifo"), (t_newmethod)lifo_new, + (t_method)lifo_free, sizeof(t_lifo), 0, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)lifo_new, gensym("lifo"), A_DEFFLOAT, 0); + class_addfloat(lifo_class, lifo_int); + class_addbang(lifo_class, lifo_bang); + class_addmethod(lifo_class, (t_method)lifo_clear, gensym("clear"), 0); + class_sethelpsymbol(lifo_class, gensym("maxlib/lifo-help.pd")); +} +#endif diff --git a/limit.c b/limit.c index cf3d97a..cfd79ea 100644 --- a/limit.c +++ b/limit.c @@ -1,125 +1,125 @@ -/* ------------------------- limit ------------------------------------------ */ -/* */ -/* limits input to lie within an output range. */ -/* Written by Olaf Matthes */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include -#include - -static char *version = "limit v0.1, written by Olaf Matthes "; - -typedef struct limit -{ - t_object x_ob; - t_float x_ol; /* low border of output range */ - t_float x_oh; /* high border of output range */ - t_float x_ratio; /* 'compression ratio' */ - t_outlet *x_outlet1; /* result */ - t_float x_f; -} t_limit; - -static void limit_float(t_limit *x, t_floatarg f) -{ - if(x->x_oh < x->x_ol) /* swap values */ - { - int i = x->x_oh; - x->x_oh = x->x_ol; - x->x_ol = i; - } - if(x->x_ratio == 0) /* 'clip' mode */ - { - if(f > x->x_oh)f = x->x_oh; - else if(f < x->x_ol)f = x->x_ol; - } - else /* 'compress' mode */ - { - int diff; - if(f > x->x_oh) - { - diff = f - x->x_oh; - f = x->x_oh + (diff / x->x_ratio); - } - else if(f < x->x_ol) - { - diff = x->x_ol - f; - f = x->x_ol - (diff / x->x_ratio); - } - } - outlet_float(x->x_outlet1, f); - x->x_f = f; -} - -static void limit_bang(t_limit *x) -{ - limit_float(x, x->x_f); /* recalculate result */ -} - -static t_class *limit_class; - -static void *limit_new(t_floatarg fol, t_floatarg foh, t_floatarg fr) -{ - t_limit *x = (t_limit *)pd_new(limit_class); - - floatinlet_new(&x->x_ob, &x->x_ol); - floatinlet_new(&x->x_ob, &x->x_oh); - floatinlet_new(&x->x_ob, &x->x_ratio); - - x->x_outlet1 = outlet_new(&x->x_ob, gensym("float")); - - /* default values taken from Max's limit */ - x->x_ol = fol; - x->x_oh = foh; - if(x->x_oh < x->x_ol) /* swap values */ - { - int i = x->x_oh; - x->x_oh = x->x_ol; - x->x_ol = i; - } - x->x_ratio = fr; - x->x_f = 0; - - return (void *)x; -} - -#ifndef MAXLIB -void limit_setup(void) -{ - limit_class = class_new(gensym("limit"), (t_newmethod)limit_new, - 0, sizeof(t_limit), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); -#else -void maxlib_limit_setup(void) -{ - limit_class = class_new(gensym("maxlib_limit"), (t_newmethod)limit_new, - 0, sizeof(t_limit), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)limit_new, gensym("limit"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); -#endif - class_addfloat(limit_class, limit_float); - class_addbang(limit_class, limit_bang); -#ifndef MAXLIB - - post(version); -#else - class_sethelpsymbol(limit_class, gensym("maxlib/limit-help.pd")); -#endif -} - +/* ------------------------- limit ------------------------------------------ */ +/* */ +/* limits input to lie within an output range. */ +/* Written by Olaf Matthes */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include +#include + +static char *version = "limit v0.1, written by Olaf Matthes "; + +typedef struct limit +{ + t_object x_ob; + t_float x_ol; /* low border of output range */ + t_float x_oh; /* high border of output range */ + t_float x_ratio; /* 'compression ratio' */ + t_outlet *x_outlet1; /* result */ + t_float x_f; +} t_limit; + +static void limit_float(t_limit *x, t_floatarg f) +{ + if(x->x_oh < x->x_ol) /* swap values */ + { + int i = x->x_oh; + x->x_oh = x->x_ol; + x->x_ol = i; + } + if(x->x_ratio == 0) /* 'clip' mode */ + { + if(f > x->x_oh)f = x->x_oh; + else if(f < x->x_ol)f = x->x_ol; + } + else /* 'compress' mode */ + { + int diff; + if(f > x->x_oh) + { + diff = f - x->x_oh; + f = x->x_oh + (diff / x->x_ratio); + } + else if(f < x->x_ol) + { + diff = x->x_ol - f; + f = x->x_ol - (diff / x->x_ratio); + } + } + outlet_float(x->x_outlet1, f); + x->x_f = f; +} + +static void limit_bang(t_limit *x) +{ + limit_float(x, x->x_f); /* recalculate result */ +} + +static t_class *limit_class; + +static void *limit_new(t_floatarg fol, t_floatarg foh, t_floatarg fr) +{ + t_limit *x = (t_limit *)pd_new(limit_class); + + floatinlet_new(&x->x_ob, &x->x_ol); + floatinlet_new(&x->x_ob, &x->x_oh); + floatinlet_new(&x->x_ob, &x->x_ratio); + + x->x_outlet1 = outlet_new(&x->x_ob, gensym("float")); + + /* default values taken from Max's limit */ + x->x_ol = fol; + x->x_oh = foh; + if(x->x_oh < x->x_ol) /* swap values */ + { + int i = x->x_oh; + x->x_oh = x->x_ol; + x->x_ol = i; + } + x->x_ratio = fr; + x->x_f = 0; + + return (void *)x; +} + +#ifndef MAXLIB +void limit_setup(void) +{ + limit_class = class_new(gensym("limit"), (t_newmethod)limit_new, + 0, sizeof(t_limit), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); +#else +void maxlib_limit_setup(void) +{ + limit_class = class_new(gensym("maxlib_limit"), (t_newmethod)limit_new, + 0, sizeof(t_limit), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)limit_new, gensym("limit"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); +#endif + class_addfloat(limit_class, limit_float); + class_addbang(limit_class, limit_bang); +#ifndef MAXLIB + + logpost(NULL, 4, version); +#else + class_sethelpsymbol(limit_class, gensym("maxlib/limit-help.pd")); +#endif +} + diff --git a/linear.c b/linear.c index 492b961..a12881d 100644 --- a/linear.c +++ b/linear.c @@ -1,81 +1,81 @@ -/* ---------------------------- rand_linear ----------------------------------- */ -/* */ -/* rand_linear generates a linearly distributed random variable. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Based on code found in Dodge/Jerse "Computer Music" */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include -#include -#include - -#define fran() (t_float)rand()/(t_float)RAND_MAX - -static char *version = "linear v0.1, generates linearly distributed random variable\n" - " written by Olaf Matthes "; - -/* -------------------------- rand_linear ------------------------------ */ - -static t_class *rand_linear_class; - -typedef struct _rand_linear -{ - t_object x_obj; -} t_rand_linear; - -static void *rand_linear_new(t_floatarg f) -{ - t_rand_linear *x = (t_rand_linear *)pd_new(rand_linear_class); - srand( (unsigned)time( NULL ) ); - outlet_new(&x->x_obj, &s_float); - return (x); -} - -static void rand_linear_bang(t_rand_linear *x) -{ - t_float u1, u2; - u1 = fran(); - u2 = fran(); - if(u2 < u1) - u1 = u2; - outlet_float(x->x_obj.ob_outlet, u1); -} - -#ifndef MAXLIB -void linear_setup(void) -{ - rand_linear_class = class_new(gensym("linear"), (t_newmethod)rand_linear_new, 0, - sizeof(t_rand_linear), 0, A_DEFFLOAT, 0); - class_addbang(rand_linear_class, rand_linear_bang); - class_sethelpsymbol(rand_linear_class, gensym("linear-help.pd")); - post(version); -} -#else -void maxlib_linear_setup(void) -{ - rand_linear_class = class_new(gensym("maxlib_linear"), (t_newmethod)rand_linear_new, 0, - sizeof(t_rand_linear), 0, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)rand_linear_new, gensym("linear"), A_DEFFLOAT, 0); - class_addbang(rand_linear_class, rand_linear_bang); - class_sethelpsymbol(rand_linear_class, gensym("maxlib/linear-help.pd")); -} -#endif +/* ---------------------------- rand_linear ----------------------------------- */ +/* */ +/* rand_linear generates a linearly distributed random variable. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Based on code found in Dodge/Jerse "Computer Music" */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include +#include +#include + +#define fran() (t_float)rand()/(t_float)RAND_MAX + +static char *version = "linear v0.1, generates linearly distributed random variable\n" + " written by Olaf Matthes "; + +/* -------------------------- rand_linear ------------------------------ */ + +static t_class *rand_linear_class; + +typedef struct _rand_linear +{ + t_object x_obj; +} t_rand_linear; + +static void *rand_linear_new(t_floatarg f) +{ + t_rand_linear *x = (t_rand_linear *)pd_new(rand_linear_class); + srand( (unsigned)time( NULL ) ); + outlet_new(&x->x_obj, &s_float); + return (x); +} + +static void rand_linear_bang(t_rand_linear *x) +{ + t_float u1, u2; + u1 = fran(); + u2 = fran(); + if(u2 < u1) + u1 = u2; + outlet_float(x->x_obj.ob_outlet, u1); +} + +#ifndef MAXLIB +void linear_setup(void) +{ + rand_linear_class = class_new(gensym("linear"), (t_newmethod)rand_linear_new, 0, + sizeof(t_rand_linear), 0, A_DEFFLOAT, 0); + class_addbang(rand_linear_class, rand_linear_bang); + class_sethelpsymbol(rand_linear_class, gensym("linear-help.pd")); + logpost(NULL, 4, version); +} +#else +void maxlib_linear_setup(void) +{ + rand_linear_class = class_new(gensym("maxlib_linear"), (t_newmethod)rand_linear_new, 0, + sizeof(t_rand_linear), 0, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)rand_linear_new, gensym("linear"), A_DEFFLOAT, 0); + class_addbang(rand_linear_class, rand_linear_bang); + class_sethelpsymbol(rand_linear_class, gensym("maxlib/linear-help.pd")); +} +#endif diff --git a/listfifo.c b/listfifo.c index 4c6e93d..9433a79 100644 --- a/listfifo.c +++ b/listfifo.c @@ -1,109 +1,109 @@ -/* ---------------------------- listfifo -------------------------------------- */ -/* */ -/* Fifo buffer of lists, empties itselfe on every bang (in order of coming in) */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" - -#define MAX_ELEM 256 /* maximum number of list elements to pass on */ - -static char *version = "listfifo v0.1, written by Olaf Matthes "; - -typedef struct listfifo -{ - t_object d_ob; - t_atom *getal; /* stores the list values */ - t_int *getsize; /* stores the number of elements in list */ - t_int count, end, size; - t_outlet *out; - -}t_listfifo; - -static t_class *listfifo_class; - -static void listfifo_list(t_listfifo *x, t_symbol *s, int argc, t_atom *argv) -{ - int i; - if(argc > MAX_ELEM) - { - post("listfifo: to many arguments in list, ignored"); - return; - } - for(i = 0; i < argc; i++) - x->getal[(x->count * MAX_ELEM) + i] = argv[i]; - x->getsize[x->count] = argc; - x->count = (x->count + 1) % x->size; - // post("got %d elements", argc); -} - -static void listfifo_bang(t_listfifo *x) -{ - // post("count = %d, end = %d", x->count, x->end); - if (x->end != x->count){ - outlet_list(x->out, NULL, x->getsize[x->end], x->getal+(x->end * MAX_ELEM)); - x->end = (x->end + 1) % x->size; - } -} - -static void listfifo_free(t_listfifo *x) -{ - freebytes(x->getsize, x->size * sizeof(t_int)); - freebytes(x->getal, x->size * sizeof(t_float) * MAX_ELEM); -} - -static void *listfifo_new(t_floatarg n) -{ - int i; - - t_listfifo *x = (t_listfifo *)pd_new(listfifo_class); - if (n<10) n = 10; - x->size = (t_int)n; - x->end = 0; - x->count = 0; - x->getsize = (t_int *)getbytes(x->size * sizeof(t_int)); - x->getal = (t_atom *)getbytes(x->size * sizeof(t_atom) * MAX_ELEM); - x->out = outlet_new(&x->d_ob, gensym("list")); - - return (x); -} - -#ifndef MAXLIB -void listfifo_setup(void) -{ - listfifo_class = class_new(gensym("listfifo"), (t_newmethod)listfifo_new, - (t_method)listfifo_free, sizeof(t_listfifo), 0, A_DEFFLOAT, 0); - class_addbang(listfifo_class, listfifo_bang); - class_addlist(listfifo_class, listfifo_list); - - post(version); -} -#else -void maxlib_listfifo_setup(void) -{ - listfifo_class = class_new(gensym("maxlib_listfifo"), (t_newmethod)listfifo_new, - (t_method)listfifo_free, sizeof(t_listfifo), 0, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)listfifo_new, gensym("listfifo"), A_DEFFLOAT, 0); - class_addbang(listfifo_class, listfifo_bang); - class_addlist(listfifo_class, listfifo_list); - class_sethelpsymbol(listfifo_class, gensym("maxlib/listfifo-help.pd")); -} -#endif +/* ---------------------------- listfifo -------------------------------------- */ +/* */ +/* Fifo buffer of lists, empties itselfe on every bang (in order of coming in) */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" + +#define MAX_ELEM 256 /* maximum number of list elements to pass on */ + +static char *version = "listfifo v0.1, written by Olaf Matthes "; + +typedef struct listfifo +{ + t_object d_ob; + t_atom *getal; /* stores the list values */ + t_int *getsize; /* stores the number of elements in list */ + t_int count, end, size; + t_outlet *out; + +}t_listfifo; + +static t_class *listfifo_class; + +static void listfifo_list(t_listfifo *x, t_symbol *s, int argc, t_atom *argv) +{ + int i; + if(argc > MAX_ELEM) + { + post("listfifo: to many arguments in list, ignored"); + return; + } + for(i = 0; i < argc; i++) + x->getal[(x->count * MAX_ELEM) + i] = argv[i]; + x->getsize[x->count] = argc; + x->count = (x->count + 1) % x->size; + // post("got %d elements", argc); +} + +static void listfifo_bang(t_listfifo *x) +{ + // post("count = %d, end = %d", x->count, x->end); + if (x->end != x->count){ + outlet_list(x->out, NULL, x->getsize[x->end], x->getal+(x->end * MAX_ELEM)); + x->end = (x->end + 1) % x->size; + } +} + +static void listfifo_free(t_listfifo *x) +{ + freebytes(x->getsize, x->size * sizeof(t_int)); + freebytes(x->getal, x->size * sizeof(t_float) * MAX_ELEM); +} + +static void *listfifo_new(t_floatarg n) +{ + int i; + + t_listfifo *x = (t_listfifo *)pd_new(listfifo_class); + if (n<10) n = 10; + x->size = (t_int)n; + x->end = 0; + x->count = 0; + x->getsize = (t_int *)getbytes(x->size * sizeof(t_int)); + x->getal = (t_atom *)getbytes(x->size * sizeof(t_atom) * MAX_ELEM); + x->out = outlet_new(&x->d_ob, gensym("list")); + + return (x); +} + +#ifndef MAXLIB +void listfifo_setup(void) +{ + listfifo_class = class_new(gensym("listfifo"), (t_newmethod)listfifo_new, + (t_method)listfifo_free, sizeof(t_listfifo), 0, A_DEFFLOAT, 0); + class_addbang(listfifo_class, listfifo_bang); + class_addlist(listfifo_class, listfifo_list); + + logpost(NULL, 4, version); +} +#else +void maxlib_listfifo_setup(void) +{ + listfifo_class = class_new(gensym("maxlib_listfifo"), (t_newmethod)listfifo_new, + (t_method)listfifo_free, sizeof(t_listfifo), 0, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)listfifo_new, gensym("listfifo"), A_DEFFLOAT, 0); + class_addbang(listfifo_class, listfifo_bang); + class_addlist(listfifo_class, listfifo_list); + class_sethelpsymbol(listfifo_class, gensym("maxlib/listfifo-help.pd")); +} +#endif diff --git a/listfunnel.c b/listfunnel.c index 0626057..83f3927 100644 --- a/listfunnel.c +++ b/listfunnel.c @@ -1,92 +1,92 @@ -/* ------------------------- listfunnel ------------------------------------- */ -/* */ -/* Convert list into two-element lists with source index. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include -#include - -static char *version = "listfunnel v0.1, written by Olaf Matthes "; - -typedef struct listfunnel -{ - t_object x_ob; - t_outlet *x_outlet; /* result */ -} t_listfunnel; - -static void listfunnel_list(t_listfunnel *x, t_symbol *s, int argc, t_atom *argv) -{ - int i; - t_atom list[2]; - - for(i = 0; i < argc; i++) - { - SETFLOAT(list, i); - list[1] = argv[i]; // SETFLOAT(list+1, atom_getfloatarg(i, argc, argv)); - outlet_list(x->x_outlet, NULL, 2, list); - } -} - -static void listfunnel_float(t_listfunnel *x, t_floatarg f) -{ - t_atom list[2]; - - SETFLOAT(list, 0); - SETFLOAT(list+1, f); - outlet_list(x->x_outlet, NULL, 2, list); -} - -static t_class *listfunnel_class; - -static void *listfunnel_new(void) -{ - int i; - - t_listfunnel *x = (t_listfunnel *)pd_new(listfunnel_class); - x->x_outlet = outlet_new(&x->x_ob, gensym("float")); - - return (void *)x; -} - -#ifndef MAXLIB -void listfunnel_setup(void) -{ - listfunnel_class = class_new(gensym("listfunnel"), (t_newmethod)listfunnel_new, - 0, sizeof(t_listfunnel), 0, 0, 0); - class_addfloat(listfunnel_class, listfunnel_float); - class_addlist(listfunnel_class, listfunnel_list); - - post(version); -} -#else -void maxlib_listfunnel_setup(void) -{ - listfunnel_class = class_new(gensym("maxlib_listfunnel"), (t_newmethod)listfunnel_new, - 0, sizeof(t_listfunnel), 0, 0, 0); - class_addcreator((t_newmethod)listfunnel_new, gensym("listfunnel"), 0); - class_addfloat(listfunnel_class, listfunnel_float); - class_addlist(listfunnel_class, listfunnel_list); - class_sethelpsymbol(listfunnel_class, gensym("maxlib/listfunnel-help.pd")); -} -#endif - +/* ------------------------- listfunnel ------------------------------------- */ +/* */ +/* Convert list into two-element lists with source index. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include +#include + +static char *version = "listfunnel v0.1, written by Olaf Matthes "; + +typedef struct listfunnel +{ + t_object x_ob; + t_outlet *x_outlet; /* result */ +} t_listfunnel; + +static void listfunnel_list(t_listfunnel *x, t_symbol *s, int argc, t_atom *argv) +{ + int i; + t_atom list[2]; + + for(i = 0; i < argc; i++) + { + SETFLOAT(list, i); + list[1] = argv[i]; // SETFLOAT(list+1, atom_getfloatarg(i, argc, argv)); + outlet_list(x->x_outlet, NULL, 2, list); + } +} + +static void listfunnel_float(t_listfunnel *x, t_floatarg f) +{ + t_atom list[2]; + + SETFLOAT(list, 0); + SETFLOAT(list+1, f); + outlet_list(x->x_outlet, NULL, 2, list); +} + +static t_class *listfunnel_class; + +static void *listfunnel_new(void) +{ + int i; + + t_listfunnel *x = (t_listfunnel *)pd_new(listfunnel_class); + x->x_outlet = outlet_new(&x->x_ob, gensym("float")); + + return (void *)x; +} + +#ifndef MAXLIB +void listfunnel_setup(void) +{ + listfunnel_class = class_new(gensym("listfunnel"), (t_newmethod)listfunnel_new, + 0, sizeof(t_listfunnel), 0, 0, 0); + class_addfloat(listfunnel_class, listfunnel_float); + class_addlist(listfunnel_class, listfunnel_list); + + logpost(NULL, 4, version); +} +#else +void maxlib_listfunnel_setup(void) +{ + listfunnel_class = class_new(gensym("maxlib_listfunnel"), (t_newmethod)listfunnel_new, + 0, sizeof(t_listfunnel), 0, 0, 0); + class_addcreator((t_newmethod)listfunnel_new, gensym("listfunnel"), 0); + class_addfloat(listfunnel_class, listfunnel_float); + class_addlist(listfunnel_class, listfunnel_list); + class_sethelpsymbol(listfunnel_class, gensym("maxlib/listfunnel-help.pd")); +} +#endif + diff --git a/manual/HISTORY.txt b/manual/HISTORY.txt new file mode 100644 index 0000000..c90963f --- /dev/null +++ b/manual/HISTORY.txt @@ -0,0 +1,100 @@ +version history of maxlib library for pure-data + +v 1.5.2 (17. december 2003): +- modified netclient for not to drop received data: use of syspollfn + instead of clock to poll for incoming data, circular recv buffer + +v 1.5 (18. october 2003): +- added some usefull features to arraycopy (i.e. copying just parts of + an array and copying to specified position in destination array) +- new object: nchange +- IRIX 6.5 port (for GCC 3.3) +- OS X binary (Jaguar 10.2.6) + +v 1.4 (22. may 2003): +- updated sources to compile with Pd0.37-test4 +- new object: arraycopy + +v 1.3 (12. april 2003): +- new objects: sync listfifo +- all setup routines renamed to maxlib__setup() to avoid name + clashes, old names still work via class_addcreator() +- some improvements for the help files + +v 1.2 (30. january 2003): +- new objects: unroute urn split wrap rewrap timebang +- another fix for the makefile +- fixed a bug in netserver (sockets remained open when netserver closed) +- added a 'prepend' option (with additional creation argument) to remote, + patch was supplied by Maurizio Umberto Puxeddu + +v 1.1b2 (23. oktober 2002): +- corrected two small bugs in the makefile (linux only!), thanks to + Hans-Christoph Steiner + +v 1.1b (12. september 2002): +- new object: limit +- match and speedlim have been replaced with the objects from cyclone library +- deleted the (unwanted) debugging printout from nroute + +v 1.1 (26. august 2002): +- new objects: nroute, pong, edge +- arbran 0.1b now allows to (re-)set the arrays dynamically +- match 0.3 now matches any type of data (floats, lists, symbols, anything) +- scale 0.2 allows to dynamically change the creation arguments and to choose + between linear (default) and exponential scale +- MSVC++ workspace contains configuration for Intel Compiler with Pentium 4 + optimizations ("maxlib - Win32 Intel") +- makefile and binary release for Mac OS X (10.1.5) +- BUG FIX: corrected path to helpfiles in rand objects +- BUG FIX: corrected makefile to work under Linux again + +v 1.0 (9th august 2002): +- new objects: netserver, netclient, arbran, beta, bilex, cauchy, expo, + gauss, linear, poisson, triang, weibull +- the help patches now live in doc/5.reference/maxlib, thanks to + Frank Barknecht for suggesting that and for modifying the sources + +v 0.9 (25th july 2002): +- new objects: tilt gestalt temperature + +v 0.8b (21st july 2002): +- now compiles on Linux, thanks to Martin Pi +- new objects: listfunnel + +v 0.8 (4th july 2002): +- new objects: history netrec scale delta velocity +- some small changes to speedlim + +v 0.7 (24th june 2002): +- fixed a bug in average, thanks to João Miguel Pais +- new chord algorhythm: supports up to 67 chord types now + +v 0.6 (7th june 2002): +- added objects: beat rhythm + +v 0.5 (28th mai 2002): +- added objects: netdist mlife subst +- netdist uses the pthreads-win32 library for POSIX multithreading + under NT, thus at least pd0.35-test17 is needed under NT +- made a MSVC++ 6.0 project file + +v 0.4 (16th mai 2002): +- match now also takes lists of floats +- added objects: dist remote step + +v 0.3b (14th mai 2002): +- fixed a zero-division bug in pulse, thanks to Frank Barknecht + +v 0.3 (13th mai 2002): +- added objects: divmod, fifo, iso, lifo, pulse +- made divide, minus, multi & plus 'multi-inlet-ready' + +v 0.2 (7th mai 2002): +- added objects: average, chord, score + +v 0.1b (24th apr. 2002): +- added objects: divide, minus, multi, plus + +v 0.1a (15th apr. 2002, first public release): +- included objects: borax, ignore, match, pitch, speedlim diff --git a/manual/automata.txt b/manual/automata.txt new file mode 100644 index 0000000..3f5ff21 --- /dev/null +++ b/manual/automata.txt @@ -0,0 +1,178 @@ +[The following note originally appeared on the emusic-l mailing list. It is +reprinted here with the author's permission] + +From xrjdm@FARSIDE.GSFC.NASA.GOV Wed Nov 23 11:26:39 1994 +Date: Tue, 4 Oct 1994 15:09:23 -0500 +From: Joe McMahon +Reply to: Electronic Music Discussion List +To: Multiple recipients of list EMUSIC-L +Subject: Automata: the long-awaited summary + +Back in August, I think, I promised to post a quick intro to cellular +automata and how they can be used as a sound-generation tool. Since I'm +going to take a couple of different sources and sum them up with little or +no direct attribution, combined with my own opinions, I'll give everybody +my references *first* so they can delete the article and draw their own +conclusions if they so prefer. + +The primary reference that got me started on all this is one in the CMJ: +Vol 14, No. 4, Winter 1990: "Digital Synthesis of Self-modifying Waveforms +by Means of Cellular Automata" (Jacques Chareyon). Those who are already +familiar with automata may just skip to that article and forget about the +rest of this one. +Note: the article gives a mail address for M. Chareyon, but he did not +answer an inquiry about any available recordings using this technique in +1990. + +So. Anyone still here? Good. + +Cellular automata are a mathematical concept first introduced in the late +1940's. Generally speaking, a cellular automaton consists of a grid of +cells. Each cell may take on any of a number of values - binary automata +(cell on or cell off) are the most commonly studied. Each cell has a +neighborhood, defined more simply as other cells which influence its state. +The exact nature of this influence is defined by what are called transition +rules. The cellular automaton starts off with some cells in any of the +allowable states. for each "step" in the automaton's history, the +neighborhood of every cell is checked, and the state of the cell is +updated. All updates occur simultaneously. + +The transition rule must describe the resulting state of a cell for every +possible configuration of other cells in the neighborhood. For large +numbers of states, the amount of memory required to hold the transition +rule becomes increasingly large, Therefore, some automata use what is known +as a "totalistic" rule. These rules simply sum the values of the cells in +the neighborhood and then assign a result on this basis. The resulting +tables are far smaller. + +Many readers may already be familiar with John Horton Conway's game of +"Life". This is a two-dimensional binary automaton with a totalistic rule. +This makes for a very small rule set: + + i) If fewer than two filled cells (cells with value 1) surround a cell, + it becomes empty next generation. + ii) If more than three filled cells surround a cell, it becomes empty + next generation. +iii) If exactly three cells filled cells surround a cell, it becomes + filled on the next generation. + +This corresponds to a totalistic rule set with a total of 8(2-1)+1 or 9 +rules (one each for the sum values of 0 (no cells with a value) through 9 +(all cells with a value) ).If the transition rule were represented as a +non-totalistic one, the rule set would need 2**8 or 256 entries. There are +many interesting totalistic automata, so giving up detailed description of +every nuance of the transitions to save memory space isn't a big sacrifice. + +Interesting as two dimensional automata are, they really aren't terribly +useful for music making. There have been some experiments which have +attempted to use a two-dimensional automaton to generate MIDI events - +synthesis at the note level, using : + +Battista, T. and M. Giri, 1988. "Composizione Tramite Automi Cellulari." +Atti del VII Cooloquio di Informatica Musicale. Rome, Italy: Edizione Arti +Grafiche Ambrosini, pp. 181-182. + +Edgar, R. and J. Ryan, 1986. "LINA" Exhibition of the 1986 International +Computer Music Conference, San Francisco: Computer Music Association. + +I have not heard any of the music from these efforts, so I certainly can't +pass any judgement on them. For the purposes of this summary, we'll just +look at one-dimensional automata. These use a linear array of cells, with +the neighborhood generally being one or two cells on either side of each +cell. +(This is the type of automaton dealt with in M. Chareyon's article, which I +will be paraphrasing broadly hereafter). + +M. Chareyon's automata are wavetables. A digitized signal is stored as a +linear array of numbers in memory. A totalistic rule is used to determine a +lookup value which indexes into an array containing the resulting value; +this is saved into a second array. After the first array is completely +processed, the roles of the two are swapped and the process is repeated. + +The limiting factor in this process is the number of bits of resolution +being used to generate the sound. For a totalistic rule using a two-cell +neighborhood and 12-bit individual samples, we have 3*(2*12) = 12288 +entries in the rule table. At 2 bytes each, this is 24K of storage. If we +go to 16-bit sample resolution, we have 196608 entries at 2 bytes each for +a total of 393216 bytes, or 384K. + +The key point of M. Charyeon's method is the use of small neighborhoods +with large numbers of cellular states. Since the computation of the new +wavetable is all table lookup, very complex transition rules can be +precomputed and loaded into the tables, allowing the synthesis to +essentially be a fast sum-and-lookup loop to calculate each new wavesample. +>From the article, it appears that M. Chareyon was able to produce 2 or 3 +voices in realtime on a Mac II with a Digidesign Sound Accelerator board. +It seems that it would probably be possible to use an AV Mac to do it +without the board. + +This LASy (Linear Automaton Synthesis) method is closely related to the +Karplus-Strong plucked-string algorithm, in that a wavesample is run +through an algorithm which recirculates the samples to "self-modify" the +wave. In fact, a judicious choice of table entries allows one to very +simply simulate the K-S algoritm directly. + +So what are the sounds like? Some automata produce waveforms which quickly +"ramp-up" to complex spectra and then drop off quickly. Others move to a +steady state and then remain there. Yet others produce never-ending and +unpredictable waveforms, whose harmonic content is constantly changing. + +Obviously enough, the original wavesample can be obtained mathematically, +or by actual sampling and using LASy as a waveshaper. As M. Chareyon notes, +a quick estimate of the number of possible automata for a 2-neighbor +totalistic rule using a 256-entry wavetable with 12-bit entries is +(2**12)**256 * (2**12)**(3*2**12) or about 10**4500 possible automata. Of +course, many, many of these would not be suitable for music (e.g., the 4096 +automata in which all values go to one vlaue in one step, etc.); however, +the number of musically useful automata is still likely to be an immense +number. + +M. Chareyon provides a number of examples of ways to fill out the rule +tables and a number of hints on creating wave tables - generally speaking, +one can create a function which is used to compute the values to be placed +into the table and then fill it so it can simply be loaded and used by the +basic algorithm. His experience in using LASy is that he manages +approximately 50% of the time to produce sounds with the desired +characteristics, and that about 10% of the remaining time he gets +unexpected but useful results which can be used as starting points for +further exploration. + +Again, the important point is that the basic automaton uses wavesamples at +full resolution, calculating a new wavesample for each step of the +automaton; the next wavesample can be played while the new one is being +calculated. Because of the large number of states, mathematical tools for +the analysis of automata and the construction of automata with specifically +desired qualities require too much storage and compute time to make them +useful for LASy purposes. + +Again, much of this article is paraphrased from M. Chareyon's article; I +take no credit for any of the work in this note. I'm just summarizing. + +The following other articles were referenced by M. Chareyon's article: + +Burks, A., ed. 1970. Essays on Cellular Automata. Champaign/Urbana, IL: +University of Illinois Press. + +Chareyon, J. 1988a. "Sound Synthesis and Processing by Means of Linear +Cellular Automata." Proceedings of the 1988 Internation Computer Music +Conference. San Francisco: Computer Music Association. + +Chareyon, J. 1988b. "Wavetable come Automa Cellulare: una Nuova Tecnica di +Sintesi." Atti del VII Colloquio di Informatica Musicale, Rome, Italy: +Edizioni Arti Grafiche Ambrosini, pp. 174-177. + +Farmer, D., T. Toffoli, and S. Wolfram, eds. 1984. Cellular Automata. +North-Holland Physics Publishing. [One of the definitive works on cellular +automata - fairly heavy math, not a popular presentation - JM] + +Gardner, M. 1970. "The Fantastic Combinations of John Conway's New Solitare +Game 'Life'". Scientific American 223(4) 120-123. [A good introduction to +cellular automata, focusing on 'life' in specific. Useful intro if my +1-paragraph summary of automata was confusing :) - JM] + + --- Joe M. + +-- +"At the end of the hour, we'll have information on the sedatives used by +the artists,,," (MST3K) + diff --git a/match.c b/match.c index 48eca45..53ad633 100644 --- a/match.c +++ b/match.c @@ -1,274 +1,274 @@ -/* ------------------------- match ------------------------------------------ */ -/* */ -/* Outputs a list when a list of input values matches the creation args. */ -/* Written by Krzysztof Czaja for his cyclone library. */ -/* Modified to fit into maxlib by Olaf Matthes . */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -/* this is the original copyright notice: */ - -/* Copyright (c) 1997-2002 Miller Puckette and others. - * For information on usage and redistribution, and for a DISCLAIMER OF ALL - * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ - - -#include -#include "m_pd.h" - -#define MATCH_INISIZE 16 /* LATER rethink */ - -typedef struct _match -{ - t_object x_ob; - int x_size; /* as allocated */ - int x_patlen; /* as used */ - t_atom *x_pattern; - t_atom x_patini[MATCH_INISIZE]; - int x_quelen; - t_atom *x_queue; - t_atom x_queini[MATCH_INISIZE]; - t_atom *x_queend; - t_atom *x_queptr; /* writing head, post-incremented (oldest-pointing) */ - int x_; -} t_match; - -static t_class *match_class; - -/* a caller must check for nrequested > *sizep */ -/* returns actual number of atoms: requested (success) - or a default value of initial size (failure) */ -/* the result is guaranteed to be >= min(nrequested, inisize) */ -static int match_grow(int nrequested, int *sizep, t_atom **bufp, - int inisize, t_atom *bufini) -{ - int newsize = *sizep * 2; - while (newsize < nrequested) newsize *= 2; - if (*bufp == bufini) - *bufp = (t_atom *)getbytes(newsize * sizeof(**bufp)); - else - *bufp = (t_atom *)resizebytes(*bufp, *sizep * sizeof(**bufp), - newsize * sizeof(**bufp)); - if (*bufp) - *sizep = newsize; - else - { - *bufp = bufini; - nrequested = *sizep = inisize; - } - return (nrequested); -} - -static void match_clear(t_match *x) -{ - x->x_quelen = 0; - x->x_queptr = x->x_queue; -} - -/* x->x_patlen > 0 is assumed */ -/* LATER use a lock to disable reentrant calls. I do not see any - purpose of reentering match, but lets CHECKME first... */ -static void match_checkin(t_match *x) -{ - int i, patlen = x->x_patlen; - t_atom *queptr, *pp, *qp; - if (x->x_queptr >= x->x_queend) - x->x_queptr = x->x_queue; - else x->x_queptr++; - if (x->x_quelen < patlen && ++(x->x_quelen) < patlen) - return; - - qp = queptr = x->x_queptr; - for (i = 0, pp = x->x_pattern; i < patlen; i++, pp++) - { - if (pp->a_type == A_FLOAT) - { - if (qp->a_type != A_FLOAT || qp->a_w.w_float != pp->a_w.w_float) - break; - } - else if (pp->a_type == A_SYMBOL) - { - if (qp->a_type != A_SYMBOL || qp->a_w.w_symbol != pp->a_w.w_symbol) - break; - } - else if (pp->a_type == A_NULL) - { - if (qp->a_type == A_FLOAT || qp->a_type == A_SYMBOL) - { - /* instantiating a pattern */ - *pp = *qp; - qp->a_type = A_NULL; - } - else break; /* LATER rethink */ - } - else break; /* LATER rethink */ - if (qp >= x->x_queend) - qp = x->x_queue; - else qp++; - } - if (i == patlen) - { - pp = x->x_pattern; - if (pp->a_type == A_FLOAT) - { - if (patlen == 1) - outlet_float(((t_object *)x)->ob_outlet, pp->a_w.w_float); - else - outlet_list(((t_object *)x)->ob_outlet, &s_list, patlen, pp); - } - else /* assuming A_SYMBOL (see above) */ - { - if (pp->a_w.w_symbol == &s_symbol /* bypassing typedmess() */ - && patlen == 2 && pp[1].a_type == A_SYMBOL) - outlet_symbol(((t_object *)x)->ob_outlet, pp[1].a_w.w_symbol); - else - outlet_anything(((t_object *)x)->ob_outlet, pp->a_w.w_symbol, - patlen - 1, pp + 1); - } - /* CHECKED: no implicit clear (resolving overlapping patterns) */ - } - /* restoring a pattern */ - for (i = 0, pp = x->x_pattern; i < patlen; i++, pp++) - { - if (queptr->a_type == A_NULL) - { - queptr->a_type = pp->a_type; - pp->a_type = A_NULL; - } - if (queptr >= x->x_queend) - queptr = x->x_queue; - else queptr++; - } -} - -static void match_float(t_match *x, t_float f) -{ - if (x->x_patlen) - { - SETFLOAT(x->x_queptr, f); - match_checkin(x); - } -} - -static void match_symbol(t_match *x, t_symbol *s) -{ - if (s && s != &s_ && x->x_patlen) - { - SETSYMBOL(x->x_queptr, s); - match_checkin(x); - } -} - -/* LATER gpointer */ - -static void match_list(t_match *x, t_symbol *s, int ac, t_atom *av) -{ - while (ac--) - { - if (av->a_type == A_FLOAT) match_float(x, av->a_w.w_float); - else if (av->a_type == A_SYMBOL) match_symbol(x, av->a_w.w_symbol); - av++; - } -} - -static void match_anything(t_match *x, t_symbol *s, int ac, t_atom *av) -{ - match_symbol(x, s); - match_list(x, 0, ac, av); -} - -static void match_set(t_match *x, t_symbol *s, int ac, t_atom *av) -{ - if (ac) /* CHECKED */ - { - t_atom *pp; - t_symbol *ps_nn; - int newlen = ac * 2; - if (newlen > x->x_size) - { - newlen = match_grow(newlen, &x->x_size, &x->x_pattern, - MATCH_INISIZE * 2, x->x_patini); - if (newlen == MATCH_INISIZE * 2) - { - x->x_queue = x->x_queini; - ac = MATCH_INISIZE; - } - else x->x_queue = x->x_pattern + x->x_size / 2; - } - x->x_patlen = ac; - x->x_queend = x->x_queue + ac - 1; - match_clear(x); /* CHECKED */ - memcpy(x->x_pattern, av, ac * sizeof(*x->x_pattern)); - pp = x->x_pattern; - ps_nn = gensym("nn"); - while (ac--) - { - if (pp->a_type == A_SYMBOL && pp->a_w.w_symbol == ps_nn) - pp->a_type = A_NULL; - pp++; - } - } -} - -static void match_free(t_match *x) -{ - if (x->x_pattern != x->x_patini) - freebytes(x->x_pattern, 2 * x->x_size * sizeof(*x->x_pattern)); -} - -static void *match_new(t_symbol *s, int ac, t_atom *av) -{ - t_match *x = (t_match *)pd_new(match_class); - x->x_size = MATCH_INISIZE * 2; - x->x_patlen = 0; - x->x_pattern = x->x_patini; - x->x_queue = x->x_queini; - /* x->x_queend is not used unless x->x_patlen > 0, - LATER consider chosing a more defensive way... */ - outlet_new((t_object *)x, &s_anything); - match_clear(x); - match_set(x, 0, ac, av); - return (x); -} - -#ifndef MAXLIB -void match_setup(void) -{ - match_class = class_new(gensym("match"), (t_newmethod)match_new, - (t_method)match_free, sizeof(t_match), 0, A_GIMME, 0); -#else -void maxlib_match_setup(void) -{ - match_class = class_new(gensym("maxlib_match"), (t_newmethod)match_new, - (t_method)match_free, sizeof(t_match), 0, A_GIMME, 0); - class_addcreator((t_newmethod)match_new, gensym("match"), A_GIMME, 0); -#endif - class_addfloat(match_class, match_float); - class_addsymbol(match_class, match_symbol); - class_addlist(match_class, match_list); - class_addanything(match_class, match_anything); - class_addmethod(match_class, (t_method)match_set, gensym("set"), A_GIMME, 0); - class_addmethod(match_class, (t_method)match_clear, gensym("clear"), 0); -#ifndef MAXLIB - -#else - class_sethelpsymbol(match_class, gensym("maxlib/match-help.pd")); -#endif -} +/* ------------------------- match ------------------------------------------ */ +/* */ +/* Outputs a list when a list of input values matches the creation args. */ +/* Written by Krzysztof Czaja for his cyclone library. */ +/* Modified to fit into maxlib by Olaf Matthes . */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +/* this is the original copyright notice: */ + +/* Copyright (c) 1997-2002 Miller Puckette and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + + +#include +#include "m_pd.h" + +#define MATCH_INISIZE 16 /* LATER rethink */ + +typedef struct _match +{ + t_object x_ob; + int x_size; /* as allocated */ + int x_patlen; /* as used */ + t_atom *x_pattern; + t_atom x_patini[MATCH_INISIZE]; + int x_quelen; + t_atom *x_queue; + t_atom x_queini[MATCH_INISIZE]; + t_atom *x_queend; + t_atom *x_queptr; /* writing head, post-incremented (oldest-pointing) */ + int x_; +} t_match; + +static t_class *match_class; + +/* a caller must check for nrequested > *sizep */ +/* returns actual number of atoms: requested (success) + or a default value of initial size (failure) */ +/* the result is guaranteed to be >= min(nrequested, inisize) */ +static int match_grow(int nrequested, int *sizep, t_atom **bufp, + int inisize, t_atom *bufini) +{ + int newsize = *sizep * 2; + while (newsize < nrequested) newsize *= 2; + if (*bufp == bufini) + *bufp = (t_atom *)getbytes(newsize * sizeof(**bufp)); + else + *bufp = (t_atom *)resizebytes(*bufp, *sizep * sizeof(**bufp), + newsize * sizeof(**bufp)); + if (*bufp) + *sizep = newsize; + else + { + *bufp = bufini; + nrequested = *sizep = inisize; + } + return (nrequested); +} + +static void match_clear(t_match *x) +{ + x->x_quelen = 0; + x->x_queptr = x->x_queue; +} + +/* x->x_patlen > 0 is assumed */ +/* LATER use a lock to disable reentrant calls. I do not see any + purpose of reentering match, but lets CHECKME first... */ +static void match_checkin(t_match *x) +{ + int i, patlen = x->x_patlen; + t_atom *queptr, *pp, *qp; + if (x->x_queptr >= x->x_queend) + x->x_queptr = x->x_queue; + else x->x_queptr++; + if (x->x_quelen < patlen && ++(x->x_quelen) < patlen) + return; + + qp = queptr = x->x_queptr; + for (i = 0, pp = x->x_pattern; i < patlen; i++, pp++) + { + if (pp->a_type == A_FLOAT) + { + if (qp->a_type != A_FLOAT || qp->a_w.w_float != pp->a_w.w_float) + break; + } + else if (pp->a_type == A_SYMBOL) + { + if (qp->a_type != A_SYMBOL || qp->a_w.w_symbol != pp->a_w.w_symbol) + break; + } + else if (pp->a_type == A_NULL) + { + if (qp->a_type == A_FLOAT || qp->a_type == A_SYMBOL) + { + /* instantiating a pattern */ + *pp = *qp; + qp->a_type = A_NULL; + } + else break; /* LATER rethink */ + } + else break; /* LATER rethink */ + if (qp >= x->x_queend) + qp = x->x_queue; + else qp++; + } + if (i == patlen) + { + pp = x->x_pattern; + if (pp->a_type == A_FLOAT) + { + if (patlen == 1) + outlet_float(((t_object *)x)->ob_outlet, pp->a_w.w_float); + else + outlet_list(((t_object *)x)->ob_outlet, &s_list, patlen, pp); + } + else /* assuming A_SYMBOL (see above) */ + { + if (pp->a_w.w_symbol == &s_symbol /* bypassing typedmess() */ + && patlen == 2 && pp[1].a_type == A_SYMBOL) + outlet_symbol(((t_object *)x)->ob_outlet, pp[1].a_w.w_symbol); + else + outlet_anything(((t_object *)x)->ob_outlet, pp->a_w.w_symbol, + patlen - 1, pp + 1); + } + /* CHECKED: no implicit clear (resolving overlapping patterns) */ + } + /* restoring a pattern */ + for (i = 0, pp = x->x_pattern; i < patlen; i++, pp++) + { + if (queptr->a_type == A_NULL) + { + queptr->a_type = pp->a_type; + pp->a_type = A_NULL; + } + if (queptr >= x->x_queend) + queptr = x->x_queue; + else queptr++; + } +} + +static void match_float(t_match *x, t_float f) +{ + if (x->x_patlen) + { + SETFLOAT(x->x_queptr, f); + match_checkin(x); + } +} + +static void match_symbol(t_match *x, t_symbol *s) +{ + if (s && s != &s_ && x->x_patlen) + { + SETSYMBOL(x->x_queptr, s); + match_checkin(x); + } +} + +/* LATER gpointer */ + +static void match_list(t_match *x, t_symbol *s, int ac, t_atom *av) +{ + while (ac--) + { + if (av->a_type == A_FLOAT) match_float(x, av->a_w.w_float); + else if (av->a_type == A_SYMBOL) match_symbol(x, av->a_w.w_symbol); + av++; + } +} + +static void match_anything(t_match *x, t_symbol *s, int ac, t_atom *av) +{ + match_symbol(x, s); + match_list(x, 0, ac, av); +} + +static void match_set(t_match *x, t_symbol *s, int ac, t_atom *av) +{ + if (ac) /* CHECKED */ + { + t_atom *pp; + t_symbol *ps_nn; + int newlen = ac * 2; + if (newlen > x->x_size) + { + newlen = match_grow(newlen, &x->x_size, &x->x_pattern, + MATCH_INISIZE * 2, x->x_patini); + if (newlen == MATCH_INISIZE * 2) + { + x->x_queue = x->x_queini; + ac = MATCH_INISIZE; + } + else x->x_queue = x->x_pattern + x->x_size / 2; + } + x->x_patlen = ac; + x->x_queend = x->x_queue + ac - 1; + match_clear(x); /* CHECKED */ + memcpy(x->x_pattern, av, ac * sizeof(*x->x_pattern)); + pp = x->x_pattern; + ps_nn = gensym("nn"); + while (ac--) + { + if (pp->a_type == A_SYMBOL && pp->a_w.w_symbol == ps_nn) + pp->a_type = A_NULL; + pp++; + } + } +} + +static void match_free(t_match *x) +{ + if (x->x_pattern != x->x_patini) + freebytes(x->x_pattern, 2 * x->x_size * sizeof(*x->x_pattern)); +} + +static void *match_new(t_symbol *s, int ac, t_atom *av) +{ + t_match *x = (t_match *)pd_new(match_class); + x->x_size = MATCH_INISIZE * 2; + x->x_patlen = 0; + x->x_pattern = x->x_patini; + x->x_queue = x->x_queini; + /* x->x_queend is not used unless x->x_patlen > 0, + LATER consider chosing a more defensive way... */ + outlet_new((t_object *)x, &s_anything); + match_clear(x); + match_set(x, 0, ac, av); + return (x); +} + +#ifndef MAXLIB +void match_setup(void) +{ + match_class = class_new(gensym("match"), (t_newmethod)match_new, + (t_method)match_free, sizeof(t_match), 0, A_GIMME, 0); +#else +void maxlib_match_setup(void) +{ + match_class = class_new(gensym("maxlib_match"), (t_newmethod)match_new, + (t_method)match_free, sizeof(t_match), 0, A_GIMME, 0); + class_addcreator((t_newmethod)match_new, gensym("match"), A_GIMME, 0); +#endif + class_addfloat(match_class, match_float); + class_addsymbol(match_class, match_symbol); + class_addlist(match_class, match_list); + class_addanything(match_class, match_anything); + class_addmethod(match_class, (t_method)match_set, gensym("set"), A_GIMME, 0); + class_addmethod(match_class, (t_method)match_clear, gensym("clear"), 0); +#ifndef MAXLIB + +#else + class_sethelpsymbol(match_class, gensym("maxlib/match-help.pd")); +#endif +} diff --git a/maxlib-meta.pd b/maxlib-meta.pd index 2602b0f..9d6d387 100644 --- a/maxlib-meta.pd +++ b/maxlib-meta.pd @@ -4,5 +4,5 @@ #X text 10 30 NAME maxlib; #X text 10 50 AUTHOR Olaf Matthes ; #X text 10 70 LICENSE GNU GPL; -#X text 10 90 VERSION 1.5.4; +#X text 10 90 VERSION 1.5.5; #X restore 10 10 pd META; diff --git a/maxlib.c b/maxlib.c index f470693..160503e 100644 --- a/maxlib.c +++ b/maxlib.c @@ -1,192 +1,192 @@ -/* -------------------------- maxlib ---------------------------------------- */ -/* */ -/* maxlib :: music analysis extensions library. */ -/* Written by Olaf Matthes */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ -#ifndef VERSION -#define VERSION "1.5.4" -#endif - -#include "m_pd.h" - - -#ifndef __DATE__ -#define __DATE__ "without using a gnu compiler" -#endif - -typedef struct _maxlib -{ - t_object x_obj; -} t_maxlib; - -static t_class* maxlib_class; - - /* objects */ -void maxlib_allow_setup(); -void maxlib_arbran_setup(); -void maxlib_arraycopy_setup(); -void maxlib_average_setup(); -void maxlib_beat_setup(); -void maxlib_beta_setup(); -void maxlib_bilex_setup(); -void maxlib_borax_setup(); -void maxlib_cauchy_setup(); -void maxlib_chord_setup(); -void maxlib_delta_setup(); -void maxlib_deny_setup(); -void maxlib_dist_setup(); -void maxlib_divide_setup(); -void maxlib_divmod_setup(); -void maxlib_edge_setup(); -void maxlib_expo_setup(); -void maxlib_fifo_setup(); -void maxlib_gauss_setup(); -void maxlib_gestalt_setup(); -void maxlib_history_setup(); -void maxlib_ignore_setup(); -void maxlib_iso_setup(); -void maxlib_lifo_setup(); -void maxlib_limit_setup(); -void maxlib_linear_setup(); -void maxlib_listfifo_setup(); -void maxlib_listfunnel_setup(); -void maxlib_match_setup(); -void maxlib_minus_setup(); -void maxlib_mlife_setup(); -void maxlib_multi_setup(); -void maxlib_nchange_setup(); -void maxlib_netclient_setup(); -void maxlib_netdist_setup(); -void maxlib_netrec_setup(); -void maxlib_netserver_setup(); -void maxlib_nroute_setup(); -void maxlib_pitch_setup(); -void maxlib_plus_setup(); -void maxlib_poisson_setup(); -void maxlib_pong_setup(); -void maxlib_pulse_setup(); -void maxlib_remote_setup(); -void maxlib_rewrap_setup(); -void maxlib_rhythm_setup(); -void maxlib_scale_setup(); -void maxlib_score_setup(); -void maxlib_speedlim_setup(); -void maxlib_split_setup(); -void maxlib_step_setup(); -void maxlib_subst_setup(); -void maxlib_sync_setup(); -void maxlib_temperature_setup(); -void maxlib_tilt_setup(); -void maxlib_timebang_setup(); -void maxlib_triang_setup(); -void maxlib_unroute_setup(); -void maxlib_urn_setup(); -void maxlib_velocity_setup(); -void maxlib_weibull_setup(); -void maxlib_wrap_setup(); - -static void* maxlib_new(t_symbol* s) -{ - t_maxlib *x = (t_maxlib *)pd_new(maxlib_class); - return (x); -} - -void maxlib_setup(void) -{ - maxlib_class = class_new(gensym("maxlib"), (t_newmethod)maxlib_new, 0, - sizeof(t_maxlib), 0,0); - - maxlib_allow_setup(); - maxlib_arbran_setup(); - maxlib_arraycopy_setup(); - maxlib_average_setup(); - maxlib_beat_setup(); - maxlib_beta_setup(); - maxlib_bilex_setup(); - maxlib_borax_setup(); - maxlib_cauchy_setup(); - maxlib_chord_setup(); - maxlib_delta_setup(); - maxlib_deny_setup(); - maxlib_dist_setup(); - maxlib_divide_setup(); - maxlib_divmod_setup(); - maxlib_edge_setup(); - maxlib_expo_setup(); - maxlib_fifo_setup(); - maxlib_gauss_setup(); - maxlib_gestalt_setup(); - maxlib_history_setup(); - maxlib_ignore_setup(); - maxlib_iso_setup(); - maxlib_lifo_setup(); - maxlib_limit_setup(); - maxlib_linear_setup(); - maxlib_listfifo_setup(); - maxlib_listfunnel_setup(); - maxlib_match_setup(); - maxlib_minus_setup(); - maxlib_mlife_setup(); - maxlib_multi_setup(); - maxlib_nchange_setup(); - maxlib_netclient_setup(); - maxlib_netdist_setup(); - maxlib_netrec_setup(); - maxlib_netserver_setup(); - maxlib_nroute_setup(); - maxlib_pitch_setup(); - maxlib_plus_setup(); - maxlib_poisson_setup(); - maxlib_pong_setup(); - maxlib_pulse_setup(); - maxlib_remote_setup(); - maxlib_rewrap_setup(); - maxlib_rhythm_setup(); - maxlib_scale_setup(); - maxlib_score_setup(); - maxlib_speedlim_setup(); - maxlib_split_setup(); - maxlib_step_setup(); - maxlib_subst_setup(); - maxlib_sync_setup(); - maxlib_temperature_setup(); - maxlib_tilt_setup(); - maxlib_timebang_setup(); - maxlib_triang_setup(); - maxlib_unroute_setup(); - maxlib_urn_setup(); - maxlib_velocity_setup(); - maxlib_weibull_setup(); - maxlib_wrap_setup(); - - post("\n maxlib :: Music Analysis eXtensions LIBrary"); - post(" written by Olaf Matthes "); - post(" version "VERSION); - post(" compiled "__DATE__); - post(" latest version at http://www.akustische-kunst.org/puredata/maxlib/"); - post(" objects: allow arbran arraycopy average beat beta bilex borax cauchy "); - post(" chord delta deny dist divide divmod edge expo fifo gauss "); - post(" gestalt history ignore iso lifo linear listfifo listfunnel "); - post(" match minus mlife multi nchange netclient netdist netrec "); - post(" netserver nroute pitch plus poisson pong pulse remote rewrap "); - post(" rhythm scale score speedlim split step subst sync temperature "); - post(" tilt timebang triang unroute urn velocity weibull wrap\n"); -} +/* -------------------------- maxlib ---------------------------------------- */ +/* */ +/* maxlib :: music analysis extensions library. */ +/* Written by Olaf Matthes */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ +#ifndef VERSION +#define VERSION "1.5.4" +#endif + +#include "m_pd.h" + + +#ifndef __DATE__ +#define __DATE__ "without using a gnu compiler" +#endif + +typedef struct _maxlib +{ + t_object x_obj; +} t_maxlib; + +static t_class* maxlib_class; + + /* objects */ +void maxlib_allow_setup(); +void maxlib_arbran_setup(); +void maxlib_arraycopy_setup(); +void maxlib_average_setup(); +void maxlib_beat_setup(); +void maxlib_beta_setup(); +void maxlib_bilex_setup(); +void maxlib_borax_setup(); +void maxlib_cauchy_setup(); +void maxlib_chord_setup(); +void maxlib_delta_setup(); +void maxlib_deny_setup(); +void maxlib_dist_setup(); +void maxlib_divide_setup(); +void maxlib_divmod_setup(); +void maxlib_edge_setup(); +void maxlib_expo_setup(); +void maxlib_fifo_setup(); +void maxlib_gauss_setup(); +void maxlib_gestalt_setup(); +void maxlib_history_setup(); +void maxlib_ignore_setup(); +void maxlib_iso_setup(); +void maxlib_lifo_setup(); +void maxlib_limit_setup(); +void maxlib_linear_setup(); +void maxlib_listfifo_setup(); +void maxlib_listfunnel_setup(); +void maxlib_match_setup(); +void maxlib_minus_setup(); +void maxlib_mlife_setup(); +void maxlib_multi_setup(); +void maxlib_nchange_setup(); +void maxlib_netclient_setup(); +void maxlib_netdist_setup(); +void maxlib_netrec_setup(); +void maxlib_netserver_setup(); +void maxlib_nroute_setup(); +void maxlib_pitch_setup(); +void maxlib_plus_setup(); +void maxlib_poisson_setup(); +void maxlib_pong_setup(); +void maxlib_pulse_setup(); +void maxlib_remote_setup(); +void maxlib_rewrap_setup(); +void maxlib_rhythm_setup(); +void maxlib_scale_setup(); +void maxlib_score_setup(); +void maxlib_speedlim_setup(); +void maxlib_split_setup(); +void maxlib_step_setup(); +void maxlib_subst_setup(); +void maxlib_sync_setup(); +void maxlib_temperature_setup(); +void maxlib_tilt_setup(); +void maxlib_timebang_setup(); +void maxlib_triang_setup(); +void maxlib_unroute_setup(); +void maxlib_urn_setup(); +void maxlib_velocity_setup(); +void maxlib_weibull_setup(); +void maxlib_wrap_setup(); + +static void* maxlib_new(t_symbol* s) +{ + t_maxlib *x = (t_maxlib *)pd_new(maxlib_class); + return (x); +} + +void maxlib_setup(void) +{ + maxlib_class = class_new(gensym("maxlib"), (t_newmethod)maxlib_new, 0, + sizeof(t_maxlib), 0,0); + + maxlib_allow_setup(); + maxlib_arbran_setup(); + maxlib_arraycopy_setup(); + maxlib_average_setup(); + maxlib_beat_setup(); + maxlib_beta_setup(); + maxlib_bilex_setup(); + maxlib_borax_setup(); + maxlib_cauchy_setup(); + maxlib_chord_setup(); + maxlib_delta_setup(); + maxlib_deny_setup(); + maxlib_dist_setup(); + maxlib_divide_setup(); + maxlib_divmod_setup(); + maxlib_edge_setup(); + maxlib_expo_setup(); + maxlib_fifo_setup(); + maxlib_gauss_setup(); + maxlib_gestalt_setup(); + maxlib_history_setup(); + maxlib_ignore_setup(); + maxlib_iso_setup(); + maxlib_lifo_setup(); + maxlib_limit_setup(); + maxlib_linear_setup(); + maxlib_listfifo_setup(); + maxlib_listfunnel_setup(); + maxlib_match_setup(); + maxlib_minus_setup(); + maxlib_mlife_setup(); + maxlib_multi_setup(); + maxlib_nchange_setup(); + maxlib_netclient_setup(); + maxlib_netdist_setup(); + maxlib_netrec_setup(); + maxlib_netserver_setup(); + maxlib_nroute_setup(); + maxlib_pitch_setup(); + maxlib_plus_setup(); + maxlib_poisson_setup(); + maxlib_pong_setup(); + maxlib_pulse_setup(); + maxlib_remote_setup(); + maxlib_rewrap_setup(); + maxlib_rhythm_setup(); + maxlib_scale_setup(); + maxlib_score_setup(); + maxlib_speedlim_setup(); + maxlib_split_setup(); + maxlib_step_setup(); + maxlib_subst_setup(); + maxlib_sync_setup(); + maxlib_temperature_setup(); + maxlib_tilt_setup(); + maxlib_timebang_setup(); + maxlib_triang_setup(); + maxlib_unroute_setup(); + maxlib_urn_setup(); + maxlib_velocity_setup(); + maxlib_weibull_setup(); + maxlib_wrap_setup(); + + post("\n maxlib :: Music Analysis eXtensions LIBrary"); + post(" written by Olaf Matthes "); + logpost(NULL, 4, " version "VERSION); + post(" compiled "__DATE__); + logpost(NULL, 4, " latest version at http://www.akustische-kunst.org/puredata/maxlib/"); + post(" objects: allow arbran arraycopy average beat beta bilex borax cauchy "); + post(" chord delta deny dist divide divmod edge expo fifo gauss "); + post(" gestalt history ignore iso lifo linear listfifo listfunnel "); + post(" match minus mlife multi nchange netclient netdist netrec "); + post(" netserver nroute pitch plus poisson pong pulse remote rewrap "); + post(" rhythm scale score speedlim split step subst sync temperature "); + post(" tilt timebang triang unroute urn velocity weibull wrap\n"); +} diff --git a/minus.c b/minus.c index c1de401..6c88583 100644 --- a/minus.c +++ b/minus.c @@ -1,111 +1,111 @@ -/* ------------------------- minus ------------------------------------------ */ -/* */ -/* Like '-', but calculates output whenever _any_ of the inlets changes. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include - -#define MAXSIZE 32 - -static char *version = "minus v0.2, written by Olaf Matthes "; - -typedef struct minus -{ - t_object x_ob; - t_inlet *x_inleft; /* leftmost inlet */ - t_inlet *x_inright; /* right inlet */ - t_outlet *x_outlet; /* result */ - t_int x_numvalues; /* number of values / inlets */ - - t_float x_minusvalue[MAXSIZE]; - -} t_minus; - -static void minus_bang(t_minus *x) -{ - int i; - t_float result = x->x_minusvalue[0]; - for(i = 1; i < x->x_numvalues; i++) - result -= x->x_minusvalue[i]; - outlet_float(x->x_outlet, result); -} - -static void minus_float(t_minus *x, t_floatarg f) -{ - x->x_minusvalue[0] = f; - minus_bang(x); /* calculate result */ -} - -static void minus_ft1(t_minus *x, t_floatarg f) -{ - x->x_minusvalue[1] = f; - minus_bang(x); /* calculate result */ -} - -static t_class *minus_class; - -static void *minus_new(t_symbol *s, t_int argc, t_atom* argv) -{ - int i; - - t_minus *x = (t_minus *)pd_new(minus_class); - x->x_inright = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); - for(i = 2; i < argc; i++) /* create additional inlets, if any */ - { - // inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); - floatinlet_new(&x->x_ob, &x->x_minusvalue[i]); - } - x->x_outlet = outlet_new(&x->x_ob, gensym("float")); - - for(i = 0; i < argc; i++) - { - x->x_minusvalue[i] = atom_getfloatarg(i, argc, argv); - } - x->x_numvalues = i; - - return (void *)x; -} - -#ifndef MAXLIB -void minus_setup(void) -{ - minus_class = class_new(gensym("minus"), (t_newmethod)minus_new, - 0, sizeof(t_minus), 0, A_GIMME, 0); - class_addfloat(minus_class, minus_float); - class_addmethod(minus_class, (t_method)minus_ft1, gensym("ft1"), A_FLOAT, 0); - class_addbang(minus_class, (t_method)minus_bang); - - post(version); -} -#else -void maxlib_minus_setup(void) -{ - minus_class = class_new(gensym("maxlib_minus"), (t_newmethod)minus_new, - 0, sizeof(t_minus), 0, A_GIMME, 0); - class_addcreator((t_newmethod)minus_new, gensym("minus"), A_GIMME, 0); - class_addfloat(minus_class, minus_float); - class_addmethod(minus_class, (t_method)minus_ft1, gensym("ft1"), A_FLOAT, 0); - class_addbang(minus_class, (t_method)minus_bang); - class_sethelpsymbol(minus_class, gensym("maxlib/minus-help.pd")); -} -#endif +/* ------------------------- minus ------------------------------------------ */ +/* */ +/* Like '-', but calculates output whenever _any_ of the inlets changes. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include + +#define MAXSIZE 32 + +static char *version = "minus v0.2, written by Olaf Matthes "; + +typedef struct minus +{ + t_object x_ob; + t_inlet *x_inleft; /* leftmost inlet */ + t_inlet *x_inright; /* right inlet */ + t_outlet *x_outlet; /* result */ + t_int x_numvalues; /* number of values / inlets */ + + t_float x_minusvalue[MAXSIZE]; + +} t_minus; + +static void minus_bang(t_minus *x) +{ + int i; + t_float result = x->x_minusvalue[0]; + for(i = 1; i < x->x_numvalues; i++) + result -= x->x_minusvalue[i]; + outlet_float(x->x_outlet, result); +} + +static void minus_float(t_minus *x, t_floatarg f) +{ + x->x_minusvalue[0] = f; + minus_bang(x); /* calculate result */ +} + +static void minus_ft1(t_minus *x, t_floatarg f) +{ + x->x_minusvalue[1] = f; + minus_bang(x); /* calculate result */ +} + +static t_class *minus_class; + +static void *minus_new(t_symbol *s, t_int argc, t_atom* argv) +{ + int i; + + t_minus *x = (t_minus *)pd_new(minus_class); + x->x_inright = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); + for(i = 2; i < argc; i++) /* create additional inlets, if any */ + { + // inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); + floatinlet_new(&x->x_ob, &x->x_minusvalue[i]); + } + x->x_outlet = outlet_new(&x->x_ob, gensym("float")); + + for(i = 0; i < argc; i++) + { + x->x_minusvalue[i] = atom_getfloatarg(i, argc, argv); + } + x->x_numvalues = i; + + return (void *)x; +} + +#ifndef MAXLIB +void minus_setup(void) +{ + minus_class = class_new(gensym("minus"), (t_newmethod)minus_new, + 0, sizeof(t_minus), 0, A_GIMME, 0); + class_addfloat(minus_class, minus_float); + class_addmethod(minus_class, (t_method)minus_ft1, gensym("ft1"), A_FLOAT, 0); + class_addbang(minus_class, (t_method)minus_bang); + + logpost(NULL, 4, version); +} +#else +void maxlib_minus_setup(void) +{ + minus_class = class_new(gensym("maxlib_minus"), (t_newmethod)minus_new, + 0, sizeof(t_minus), 0, A_GIMME, 0); + class_addcreator((t_newmethod)minus_new, gensym("minus"), A_GIMME, 0); + class_addfloat(minus_class, minus_float); + class_addmethod(minus_class, (t_method)minus_ft1, gensym("ft1"), A_FLOAT, 0); + class_addbang(minus_class, (t_method)minus_bang); + class_sethelpsymbol(minus_class, gensym("maxlib/minus-help.pd")); +} +#endif diff --git a/mlife.c b/mlife.c index 4b77e09..0768f16 100644 --- a/mlife.c +++ b/mlife.c @@ -1,515 +1,515 @@ -/* ------------------------- mlife ------------------------------------------ */ -/* */ -/* A linear cellular automata object for PureData. */ -/* Based on 'mlife' by pauld@koncon.nl */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ -#include "m_pd.h" - - -static char *version = "mlife v0.1, a linear cellular automata object for Pd\n" - " written by Olaf Matthes "; - -#undef DEBUG -//#define DEBUG - - -#define INTSIZE sizeof(unsigned int) * 8 -#define LONGSIZE sizeof(unsigned long) * 8 -#define DEFAULT_DIE_LO 2 -#define DEFAULT_DIE_HI 3 -#define DEFAULT_N_SIZE 3 - -#define MAXSIZE 1024 - -#include -#include - -/* -------------------- random stuff -------------------- */ -static union { - unsigned long next; - struct { - unsigned short : 1; - unsigned short n : 15; - } bits; -} seed = { 1 }; - - -/* - * rand - pseudo-random number generator - * - */ - -static int my_rand(void) -{ - seed.next = seed.next * 1103515245 + 12345; - return(seed.bits.n); -} - - -/* - * srand - seed pseudo-random number generator - * - */ - -static void my_srand(unsigned n) -{ - seed.next = n; -} -/* --------------------------------------------------------- */ - -// -// Maxlife object data structure -// -typedef struct maxlife -{ - t_object ml_ob; // must begin every object - t_int universe[MAXSIZE]; // array of cells - alive and dead - t_outlet *out[MAXSIZE]; // outlets - t_int size; // size of the CA field/world - t_int view_start; // Start of viewport - t_int view_size; // length of viewport and number of outlets - t_int rule_die_lo; // death if less than this - t_int rule_die_hi; // death if greater then this - t_int neighbourhood_size; // # of cells either side to check - t_int closed; // closed universe if true -} t_maxlife; - -// -// Function prototypes for our methods and functions -// -static t_class *mlife_class; // global variable that points to the Maxlife class - -// -// ml_nextgeneration -// Step through the array, applying the rules and reset each cell -// accordingly. For each cell: -// - Check the number of neighbours (watch for "closed") -// using neighbourhood_size -// -// - If neighbours < rule_die_lo the cell is cleared (0) -// -// - If neighbours > rule_die_hi the cell is cleared (0) -// -// - Else the cell is filled (1) -// -// not called by Pd itself -// -static void ml_nextgeneration(t_maxlife *mlp) -{ - register long i, j, k; - register long size, neighbourhood_size, max_neighbours, min_neighbours, neighbours; - register int closed, out_of_bounds; - - // get the important info a little closer to hand - size = mlp->size; - closed = mlp->closed; - neighbourhood_size = mlp->neighbourhood_size; - max_neighbours = mlp->rule_die_hi; - min_neighbours = mlp->rule_die_lo; - -#ifdef DEBUG - post("mlife:next_generation called, vars n_size=%ld, n_max=%ld, n_min=%ld", - neighbourhood_size, max_neighbours, min_neighbours); -#endif - // for each cell... - for(i=0; i size-1L) - k = j - size - 1L; // not size-1 ??? - - if(j != i) // skip our own location in this roundup - if(mlp->universe[k]) // if there's a neighbour inc count - neighbours++; - } - else // not closed - { - out_of_bounds = 0; - if(k < 0L) // start of array - { - out_of_bounds = 1; - k = 0L; - } - if(k > size-1L) - { - out_of_bounds = 1; - k = size-1L; // end of array - } - - if((j != i) && !out_of_bounds) // skip our own location in this roundup - if(mlp->universe[k]) // if there's a neighbour inc count - neighbours++; - } - - } // end of neighbour search - - // based on number of neighbours, fill or clear this cell (i) - if((neighbours < min_neighbours) || (neighbours > max_neighbours)) - mlp->universe[i] = 0; - else - mlp->universe[i] = 1; - } -} - -// -// method to set the die_lo number -// -static void ml_set_die_lo(t_maxlife *mlp, t_floatarg die_lo) -{ - mlp->rule_die_lo = (t_int)die_lo; -} - -// -// method to set the die_hi number -// -static void ml_set_die_hi(t_maxlife *mlp, t_floatarg die_hi) -{ - mlp->rule_die_hi = (t_int)die_hi; -} - -// -// method to set the die_lo number -// -static void ml_set_neighbourhood(t_maxlife *mlp, t_floatarg n_size) -{ - mlp->neighbourhood_size = (t_int)n_size; -} - -// -// bang method outputs bangs for filled cells within the view port -// -static void ml_bang(t_maxlife *mlp) // argument is a pointer to an instance -{ - register long i, view_start; - -#ifdef DEBUG - post("mlife:ml_bang called, sending bangs"); -#endif - - view_start = mlp->view_start; - - // loop through the outlets right->left sending bangs if alive - for(i=view_start+mlp->view_size-2; i>=view_start-1; i--) - { - // send a bang out the appropriate outlet - if(mlp->universe[i]) - outlet_bang(mlp->out[i-view_start+1]); - } - - ml_nextgeneration(mlp); -} - -// -// int method outputs ints for ALL cells in the view port (1=filled, 0=not) -// -static void ml_int(t_maxlife *mlp, t_floatarg dummy) -{ - t_int i, view_start; - -#ifdef DEBUG - post("mlife:ml_int method called"); -#endif - - view_start = mlp->view_start; - - // loop through the outlets right -> left sending ints - for(i = view_start + mlp->view_size - 2; i >= view_start - 1; i--) - { - //outlet_int(mlp->out[i-view_start+1], mlp->universe[i]); - if(mlp->universe[i] == 1) - outlet_float(mlp->out[i-view_start+1], 1); - else if(mlp->universe[i] == 0) - outlet_float(mlp->out[i-view_start+1], 0); - else - error("mlife: corrupted data in universe[] array!"); - } - - ml_nextgeneration(mlp); -} - - -// -// method to print out the array -// -static void ml_display(t_maxlife *mlp) -{ - register long i; - char s[MAXSIZE]; - -#ifdef DEBUG - post("mlife: display method called"); -#endif - - for(i = 0; i < mlp->size; i++) // print the universe array - { - //s[i] = itoa(mlp->universe[i]); // my very primitive itoa() - if(mlp->universe[i]) - s[i] = '1'; - else - s[i] = '0'; - } - s[mlp->size] = '\0'; // null terminate the string - post("%s", s); -} - -// -// method to fill the array with a number -// -static void ml_fill(t_maxlife *mlp, t_floatarg fill_no) -{ - t_int n; - register long i, j; - - for(i=mlp->size-1; i >= 0; i--) // fill the universe array from the back - { - n = (t_int)fill_no; - - for(j=(long)INTSIZE; j>0; j--, i--, n>>=1) - { - if(i < 0L) - { - return; - } - if(n & 01) - mlp->universe[i] = 1; - else - mlp->universe[i] = 0; - } - } -} - -// -// method to fill the array with a random number -// -static void ml_randfill(t_maxlife *mlp) -{ - unsigned int s, rnum; - register unsigned int n; - register long i, j; - -#ifdef DEBUG - post("mlife: randfill method called"); -#endif - - s = (unsigned int)clock_getlogicaltime(); // set seed to a new number - my_srand(s); // reseed the 'random' generator - rnum = (unsigned int)my_rand(); - - for(i=mlp->size - 1; i>=0; i--) // fill the universe array from the back - { - n = rnum; - - for(j=(long)INTSIZE; j>0; j--, i--, n>>=1) - { - if(i < 0L) - { - return; - } - if(n & 01) - mlp->universe[i] = 1; - else - mlp->universe[i] = 0; - } - } -} - -// -// method to seed the array with a number -// -static void ml_seed(t_maxlife *mlp, t_floatarg start, t_floatarg fill_no) -{ - t_int n; - register long i, st, end; - -#ifdef DEBUG - post("mlife: seed method called"); -#endif - - st = (t_int)start; - n = (t_int)fill_no; - - if(st+(t_int)INTSIZE > mlp->size) - i = mlp->size - 1; - else - i = st+(long)INTSIZE - 1; - - // init the universe array from the back i>=start? - for(; i >= start - 1; i--, n>>=1) - { - if(n & 01) - mlp->universe[i] = 1; - else - mlp->universe[i] = 0; - } -} - -// -// method to seed the array with a random number -// -static void ml_randseed(t_maxlife *mlp, t_floatarg start) -{ - unsigned long s, rnum; - register unsigned long n; - register long i, st; - -#ifdef DEBUG - post("mlife: randseed method called, INTSIZE=%ld", (long)INTSIZE); -#endif - //if((start < 1) || (start > mlp->size-(long)INTSIZE)) - if(start < 1) - { - error("Randseed start parameter must be between 1 and %ld", mlp->size); - return; - } - - s = (unsigned long)clock_getlogicaltime(); // set seed to a new number - my_srand(s); // reseed the 'random' generator - rnum = (unsigned long)my_rand(); - n = (unsigned int)rnum; - st = start; - - if(st+(t_int)INTSIZE > mlp->size) - i = mlp->size - 1; - else - i = st+(t_int)INTSIZE - 1; - - // init the universe array from the back - for(; i>=st-1; i--, n>>=1) - { - if(n & 01) - mlp->universe[i] = 1; - else - mlp->universe[i] = 0; - - } -} - - -// -// function to create an instance of the mlife class -// -static void *ml_new(t_floatarg size, t_floatarg view_start, t_floatarg view_size, t_floatarg closed) -{ - long i; - t_maxlife *mlp = (t_maxlife *)pd_new(mlife_class); - - // check all args... - if((size>MAXSIZE) || (size<1)) - { - post("mlife: size argument must be between 1 and %ld", MAXSIZE); - size = 1.0; - } - if(view_start < 1) - { - post("mlife: view_start argument must be between 1 and %ld", size); - view_start = 1.0; - } - if((view_size < 1) || (view_size+view_start > size+1)) - { - post("mlife: viewsize argument must be between 1 and %ld", size-view_start); - view_size = 1.0; - } - - - // set up our structure - mlp->size = (t_int)size; - mlp->view_start = (t_int)view_start; - mlp->view_size = (t_int)view_size; - mlp->rule_die_lo = DEFAULT_DIE_LO; // 2 - mlp->rule_die_hi = DEFAULT_DIE_HI; // 3 - mlp->neighbourhood_size = DEFAULT_N_SIZE; // 3 - mlp->closed = (t_int)closed; - for(i=0; iuniverse[i] = 0; - - // create outlets - last first! - for(i = 0; i < mlp->view_size; i++) - mlp->out[i] = outlet_new(&mlp->ml_ob, gensym("float")); - -#ifdef DEBUG - post("mlife: finished building object"); - post("mlife: INTSIZE=%ld, LONGSIZE=%ld", (long)INTSIZE, (long)LONGSIZE); -#endif - - post("mlife: defaults are: lo=%ld, hi=%ld, nset=%ld", (long)DEFAULT_DIE_LO, (long)DEFAULT_DIE_HI, DEFAULT_N_SIZE); - - return(mlp); // always return a copy of the created object -} - -static void ml_free(t_maxlife *mlp) -{ - long i; - -#ifdef DEBUG - post("mlife:freeing outlet memory"); -#endif -/* for(i=mlp->view_size-1; i>=0; i--) - freeobject(mlp->out[i]); */ -} - -#ifndef MAXLIB -void mlife_setup(void) -{ - mlife_class = class_new(gensym("mlife"), (t_newmethod)ml_new, - (t_method)ml_free, sizeof(t_maxlife), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addmethod(mlife_class, (t_method)ml_randfill, gensym("randfill"), 0); - class_addmethod(mlife_class, (t_method)ml_fill, gensym("fill"), A_FLOAT, 0); - class_addmethod(mlife_class, (t_method)ml_set_die_lo, gensym("lo"), A_FLOAT, 0); - class_addmethod(mlife_class, (t_method)ml_set_die_hi, gensym("hi"), A_FLOAT, 0); - class_addmethod(mlife_class, (t_method)ml_set_neighbourhood, gensym("nset"), A_FLOAT, 0); - class_addmethod(mlife_class, (t_method)ml_randseed, gensym("randseed"), A_FLOAT, 0); - class_addmethod(mlife_class, (t_method)ml_seed, gensym("seed"), A_FLOAT, A_FLOAT, 0); - class_addmethod(mlife_class, (t_method)ml_display, gensym("display"), 0); - class_addfloat(mlife_class, ml_int); - class_addbang(mlife_class, ml_bang); - - post(version); -} -#else -void maxlib_mlife_setup(void) -{ - mlife_class = class_new(gensym("maxlib_mlife"), (t_newmethod)ml_new, - (t_method)ml_free, sizeof(t_maxlife), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)ml_new, gensym("mlife"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addmethod(mlife_class, (t_method)ml_randfill, gensym("randfill"), 0); - class_addmethod(mlife_class, (t_method)ml_fill, gensym("fill"), A_FLOAT, 0); - class_addmethod(mlife_class, (t_method)ml_set_die_lo, gensym("lo"), A_FLOAT, 0); - class_addmethod(mlife_class, (t_method)ml_set_die_hi, gensym("hi"), A_FLOAT, 0); - class_addmethod(mlife_class, (t_method)ml_set_neighbourhood, gensym("nset"), A_FLOAT, 0); - class_addmethod(mlife_class, (t_method)ml_randseed, gensym("randseed"), A_FLOAT, 0); - class_addmethod(mlife_class, (t_method)ml_seed, gensym("seed"), A_FLOAT, A_FLOAT, 0); - class_addmethod(mlife_class, (t_method)ml_display, gensym("display"), 0); - class_addfloat(mlife_class, ml_int); - class_addbang(mlife_class, ml_bang); - class_sethelpsymbol(mlife_class, gensym("maxlib/mlife-help.pd")); -} -#endif +/* ------------------------- mlife ------------------------------------------ */ +/* */ +/* A linear cellular automata object for PureData. */ +/* Based on 'mlife' by pauld@koncon.nl */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ +#include "m_pd.h" + + +static char *version = "mlife v0.1, a linear cellular automata object for Pd\n" + " written by Olaf Matthes "; + +#undef DEBUG +//#define DEBUG + + +#define INTSIZE sizeof(unsigned int) * 8 +#define LONGSIZE sizeof(unsigned long) * 8 +#define DEFAULT_DIE_LO 2 +#define DEFAULT_DIE_HI 3 +#define DEFAULT_N_SIZE 3 + +#define MAXSIZE 1024 + +#include +#include + +/* -------------------- random stuff -------------------- */ +static union { + unsigned long next; + struct { + unsigned short : 1; + unsigned short n : 15; + } bits; +} seed = { 1 }; + + +/* + * rand - pseudo-random number generator + * + */ + +static int my_rand(void) +{ + seed.next = seed.next * 1103515245 + 12345; + return(seed.bits.n); +} + + +/* + * srand - seed pseudo-random number generator + * + */ + +static void my_srand(unsigned n) +{ + seed.next = n; +} +/* --------------------------------------------------------- */ + +// +// Maxlife object data structure +// +typedef struct maxlife +{ + t_object ml_ob; // must begin every object + t_int universe[MAXSIZE]; // array of cells - alive and dead + t_outlet *out[MAXSIZE]; // outlets + t_int size; // size of the CA field/world + t_int view_start; // Start of viewport + t_int view_size; // length of viewport and number of outlets + t_int rule_die_lo; // death if less than this + t_int rule_die_hi; // death if greater then this + t_int neighbourhood_size; // # of cells either side to check + t_int closed; // closed universe if true +} t_maxlife; + +// +// Function prototypes for our methods and functions +// +static t_class *mlife_class; // global variable that points to the Maxlife class + +// +// ml_nextgeneration +// Step through the array, applying the rules and reset each cell +// accordingly. For each cell: +// - Check the number of neighbours (watch for "closed") +// using neighbourhood_size +// +// - If neighbours < rule_die_lo the cell is cleared (0) +// +// - If neighbours > rule_die_hi the cell is cleared (0) +// +// - Else the cell is filled (1) +// +// not called by Pd itself +// +static void ml_nextgeneration(t_maxlife *mlp) +{ + register long i, j, k; + register long size, neighbourhood_size, max_neighbours, min_neighbours, neighbours; + register int closed, out_of_bounds; + + // get the important info a little closer to hand + size = mlp->size; + closed = mlp->closed; + neighbourhood_size = mlp->neighbourhood_size; + max_neighbours = mlp->rule_die_hi; + min_neighbours = mlp->rule_die_lo; + +#ifdef DEBUG + post("mlife:next_generation called, vars n_size=%ld, n_max=%ld, n_min=%ld", + neighbourhood_size, max_neighbours, min_neighbours); +#endif + // for each cell... + for(i=0; i size-1L) + k = j - size - 1L; // not size-1 ??? + + if(j != i) // skip our own location in this roundup + if(mlp->universe[k]) // if there's a neighbour inc count + neighbours++; + } + else // not closed + { + out_of_bounds = 0; + if(k < 0L) // start of array + { + out_of_bounds = 1; + k = 0L; + } + if(k > size-1L) + { + out_of_bounds = 1; + k = size-1L; // end of array + } + + if((j != i) && !out_of_bounds) // skip our own location in this roundup + if(mlp->universe[k]) // if there's a neighbour inc count + neighbours++; + } + + } // end of neighbour search + + // based on number of neighbours, fill or clear this cell (i) + if((neighbours < min_neighbours) || (neighbours > max_neighbours)) + mlp->universe[i] = 0; + else + mlp->universe[i] = 1; + } +} + +// +// method to set the die_lo number +// +static void ml_set_die_lo(t_maxlife *mlp, t_floatarg die_lo) +{ + mlp->rule_die_lo = (t_int)die_lo; +} + +// +// method to set the die_hi number +// +static void ml_set_die_hi(t_maxlife *mlp, t_floatarg die_hi) +{ + mlp->rule_die_hi = (t_int)die_hi; +} + +// +// method to set the die_lo number +// +static void ml_set_neighbourhood(t_maxlife *mlp, t_floatarg n_size) +{ + mlp->neighbourhood_size = (t_int)n_size; +} + +// +// bang method outputs bangs for filled cells within the view port +// +static void ml_bang(t_maxlife *mlp) // argument is a pointer to an instance +{ + register long i, view_start; + +#ifdef DEBUG + post("mlife:ml_bang called, sending bangs"); +#endif + + view_start = mlp->view_start; + + // loop through the outlets right->left sending bangs if alive + for(i=view_start+mlp->view_size-2; i>=view_start-1; i--) + { + // send a bang out the appropriate outlet + if(mlp->universe[i]) + outlet_bang(mlp->out[i-view_start+1]); + } + + ml_nextgeneration(mlp); +} + +// +// int method outputs ints for ALL cells in the view port (1=filled, 0=not) +// +static void ml_int(t_maxlife *mlp, t_floatarg dummy) +{ + t_int i, view_start; + +#ifdef DEBUG + post("mlife:ml_int method called"); +#endif + + view_start = mlp->view_start; + + // loop through the outlets right -> left sending ints + for(i = view_start + mlp->view_size - 2; i >= view_start - 1; i--) + { + //outlet_int(mlp->out[i-view_start+1], mlp->universe[i]); + if(mlp->universe[i] == 1) + outlet_float(mlp->out[i-view_start+1], 1); + else if(mlp->universe[i] == 0) + outlet_float(mlp->out[i-view_start+1], 0); + else + error("mlife: corrupted data in universe[] array!"); + } + + ml_nextgeneration(mlp); +} + + +// +// method to print out the array +// +static void ml_display(t_maxlife *mlp) +{ + register long i; + char s[MAXSIZE]; + +#ifdef DEBUG + post("mlife: display method called"); +#endif + + for(i = 0; i < mlp->size; i++) // print the universe array + { + //s[i] = itoa(mlp->universe[i]); // my very primitive itoa() + if(mlp->universe[i]) + s[i] = '1'; + else + s[i] = '0'; + } + s[mlp->size] = '\0'; // null terminate the string + post("%s", s); +} + +// +// method to fill the array with a number +// +static void ml_fill(t_maxlife *mlp, t_floatarg fill_no) +{ + t_int n; + register long i, j; + + for(i=mlp->size-1; i >= 0; i--) // fill the universe array from the back + { + n = (t_int)fill_no; + + for(j=(long)INTSIZE; j>0; j--, i--, n>>=1) + { + if(i < 0L) + { + return; + } + if(n & 01) + mlp->universe[i] = 1; + else + mlp->universe[i] = 0; + } + } +} + +// +// method to fill the array with a random number +// +static void ml_randfill(t_maxlife *mlp) +{ + unsigned int s, rnum; + register unsigned int n; + register long i, j; + +#ifdef DEBUG + post("mlife: randfill method called"); +#endif + + s = (unsigned int)clock_getlogicaltime(); // set seed to a new number + my_srand(s); // reseed the 'random' generator + rnum = (unsigned int)my_rand(); + + for(i=mlp->size - 1; i>=0; i--) // fill the universe array from the back + { + n = rnum; + + for(j=(long)INTSIZE; j>0; j--, i--, n>>=1) + { + if(i < 0L) + { + return; + } + if(n & 01) + mlp->universe[i] = 1; + else + mlp->universe[i] = 0; + } + } +} + +// +// method to seed the array with a number +// +static void ml_seed(t_maxlife *mlp, t_floatarg start, t_floatarg fill_no) +{ + t_int n; + register long i, st, end; + +#ifdef DEBUG + post("mlife: seed method called"); +#endif + + st = (t_int)start; + n = (t_int)fill_no; + + if(st+(t_int)INTSIZE > mlp->size) + i = mlp->size - 1; + else + i = st+(long)INTSIZE - 1; + + // init the universe array from the back i>=start? + for(; i >= start - 1; i--, n>>=1) + { + if(n & 01) + mlp->universe[i] = 1; + else + mlp->universe[i] = 0; + } +} + +// +// method to seed the array with a random number +// +static void ml_randseed(t_maxlife *mlp, t_floatarg start) +{ + unsigned long s, rnum; + register unsigned long n; + register long i, st; + +#ifdef DEBUG + post("mlife: randseed method called, INTSIZE=%ld", (long)INTSIZE); +#endif + //if((start < 1) || (start > mlp->size-(long)INTSIZE)) + if(start < 1) + { + error("Randseed start parameter must be between 1 and %ld", mlp->size); + return; + } + + s = (unsigned long)clock_getlogicaltime(); // set seed to a new number + my_srand(s); // reseed the 'random' generator + rnum = (unsigned long)my_rand(); + n = (unsigned int)rnum; + st = start; + + if(st+(t_int)INTSIZE > mlp->size) + i = mlp->size - 1; + else + i = st+(t_int)INTSIZE - 1; + + // init the universe array from the back + for(; i>=st-1; i--, n>>=1) + { + if(n & 01) + mlp->universe[i] = 1; + else + mlp->universe[i] = 0; + + } +} + + +// +// function to create an instance of the mlife class +// +static void *ml_new(t_floatarg size, t_floatarg view_start, t_floatarg view_size, t_floatarg closed) +{ + long i; + t_maxlife *mlp = (t_maxlife *)pd_new(mlife_class); + + // check all args... + if((size>MAXSIZE) || (size<1)) + { + post("mlife: size argument must be between 1 and %ld", MAXSIZE); + size = 1.0; + } + if(view_start < 1) + { + post("mlife: view_start argument must be between 1 and %ld", size); + view_start = 1.0; + } + if((view_size < 1) || (view_size+view_start > size+1)) + { + post("mlife: viewsize argument must be between 1 and %ld", size-view_start); + view_size = 1.0; + } + + + // set up our structure + mlp->size = (t_int)size; + mlp->view_start = (t_int)view_start; + mlp->view_size = (t_int)view_size; + mlp->rule_die_lo = DEFAULT_DIE_LO; // 2 + mlp->rule_die_hi = DEFAULT_DIE_HI; // 3 + mlp->neighbourhood_size = DEFAULT_N_SIZE; // 3 + mlp->closed = (t_int)closed; + for(i=0; iuniverse[i] = 0; + + // create outlets - last first! + for(i = 0; i < mlp->view_size; i++) + mlp->out[i] = outlet_new(&mlp->ml_ob, gensym("float")); + +#ifdef DEBUG + post("mlife: finished building object"); + post("mlife: INTSIZE=%ld, LONGSIZE=%ld", (long)INTSIZE, (long)LONGSIZE); +#endif + + post("mlife: defaults are: lo=%ld, hi=%ld, nset=%ld", (long)DEFAULT_DIE_LO, (long)DEFAULT_DIE_HI, DEFAULT_N_SIZE); + + return(mlp); // always return a copy of the created object +} + +static void ml_free(t_maxlife *mlp) +{ + long i; + +#ifdef DEBUG + post("mlife:freeing outlet memory"); +#endif +/* for(i=mlp->view_size-1; i>=0; i--) + freeobject(mlp->out[i]); */ +} + +#ifndef MAXLIB +void mlife_setup(void) +{ + mlife_class = class_new(gensym("mlife"), (t_newmethod)ml_new, + (t_method)ml_free, sizeof(t_maxlife), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addmethod(mlife_class, (t_method)ml_randfill, gensym("randfill"), 0); + class_addmethod(mlife_class, (t_method)ml_fill, gensym("fill"), A_FLOAT, 0); + class_addmethod(mlife_class, (t_method)ml_set_die_lo, gensym("lo"), A_FLOAT, 0); + class_addmethod(mlife_class, (t_method)ml_set_die_hi, gensym("hi"), A_FLOAT, 0); + class_addmethod(mlife_class, (t_method)ml_set_neighbourhood, gensym("nset"), A_FLOAT, 0); + class_addmethod(mlife_class, (t_method)ml_randseed, gensym("randseed"), A_FLOAT, 0); + class_addmethod(mlife_class, (t_method)ml_seed, gensym("seed"), A_FLOAT, A_FLOAT, 0); + class_addmethod(mlife_class, (t_method)ml_display, gensym("display"), 0); + class_addfloat(mlife_class, ml_int); + class_addbang(mlife_class, ml_bang); + + logpost(NULL, 4, version); +} +#else +void maxlib_mlife_setup(void) +{ + mlife_class = class_new(gensym("maxlib_mlife"), (t_newmethod)ml_new, + (t_method)ml_free, sizeof(t_maxlife), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)ml_new, gensym("mlife"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addmethod(mlife_class, (t_method)ml_randfill, gensym("randfill"), 0); + class_addmethod(mlife_class, (t_method)ml_fill, gensym("fill"), A_FLOAT, 0); + class_addmethod(mlife_class, (t_method)ml_set_die_lo, gensym("lo"), A_FLOAT, 0); + class_addmethod(mlife_class, (t_method)ml_set_die_hi, gensym("hi"), A_FLOAT, 0); + class_addmethod(mlife_class, (t_method)ml_set_neighbourhood, gensym("nset"), A_FLOAT, 0); + class_addmethod(mlife_class, (t_method)ml_randseed, gensym("randseed"), A_FLOAT, 0); + class_addmethod(mlife_class, (t_method)ml_seed, gensym("seed"), A_FLOAT, A_FLOAT, 0); + class_addmethod(mlife_class, (t_method)ml_display, gensym("display"), 0); + class_addfloat(mlife_class, ml_int); + class_addbang(mlife_class, ml_bang); + class_sethelpsymbol(mlife_class, gensym("maxlib/mlife-help.pd")); +} +#endif diff --git a/multi.c b/multi.c index a29e80f..6cfbadf 100644 --- a/multi.c +++ b/multi.c @@ -1,110 +1,110 @@ -/* -------------------------- multi ------------------------------------------ */ -/* */ -/* Like '*', but calculates output whenever _any_ of the inlets changes. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include - -#define MAXSIZE 32 - -static char *version = "multi v0.2, written by Olaf Matthes "; - -typedef struct multi -{ - t_object x_ob; - t_inlet *x_inleft; /* leftmost inlet */ - t_inlet *x_inright; /* right inlet */ - t_outlet *x_outlet; /* result */ - t_int x_numvalues; /* number of values / inlets */ - - t_float x_multivalue[MAXSIZE]; - -} t_multi; - -static void multi_bang(t_multi *x) -{ - int i; - t_float result = x->x_multivalue[0]; - for(i = 1; i < x->x_numvalues; i++) - result *= x->x_multivalue[i]; - outlet_float(x->x_outlet, result); -} - -static void multi_float(t_multi *x, t_floatarg f) -{ - x->x_multivalue[0] = f; - multi_bang(x); /* calculate result */ -} - -static void multi_ft1(t_multi *x, t_floatarg f) -{ - x->x_multivalue[1] = f; - multi_bang(x); /* calculate result */ -} - -static t_class *multi_class; - -static void *multi_new(t_symbol *s, t_int argc, t_atom* argv) -{ - int i; - - t_multi *x = (t_multi *)pd_new(multi_class); - x->x_inright = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); - for(i = 2; i < argc; i++) /* create additional inlets, if any */ - { - floatinlet_new(&x->x_ob, &x->x_multivalue[i]); - } - x->x_outlet = outlet_new(&x->x_ob, gensym("float")); - - for(i = 0; i < argc; i++) - { - x->x_multivalue[i] = atom_getfloatarg(i, argc, argv);; - } - x->x_numvalues = i; - - return (void *)x; -} - -#ifndef MAXLIB -void multi_setup(void) -{ - multi_class = class_new(gensym("multi"), (t_newmethod)multi_new, - 0, sizeof(t_multi), 0, A_GIMME, 0); - class_addfloat(multi_class, multi_float); - class_addmethod(multi_class, (t_method)multi_ft1, gensym("ft1"), A_FLOAT, 0); - class_addbang(multi_class, (t_method)multi_bang); - - post(version); -} -#else -void maxlib_multi_setup(void) -{ - multi_class = class_new(gensym("maxlib_multi"), (t_newmethod)multi_new, - 0, sizeof(t_multi), 0, A_GIMME, 0); - class_addcreator((t_newmethod)multi_new, gensym("multi"), A_GIMME, 0); - class_addfloat(multi_class, multi_float); - class_addmethod(multi_class, (t_method)multi_ft1, gensym("ft1"), A_FLOAT, 0); - class_addbang(multi_class, (t_method)multi_bang); - class_sethelpsymbol(multi_class, gensym("maxlib/multi-help.pd")); -} -#endif +/* -------------------------- multi ------------------------------------------ */ +/* */ +/* Like '*', but calculates output whenever _any_ of the inlets changes. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include + +#define MAXSIZE 32 + +static char *version = "multi v0.2, written by Olaf Matthes "; + +typedef struct multi +{ + t_object x_ob; + t_inlet *x_inleft; /* leftmost inlet */ + t_inlet *x_inright; /* right inlet */ + t_outlet *x_outlet; /* result */ + t_int x_numvalues; /* number of values / inlets */ + + t_float x_multivalue[MAXSIZE]; + +} t_multi; + +static void multi_bang(t_multi *x) +{ + int i; + t_float result = x->x_multivalue[0]; + for(i = 1; i < x->x_numvalues; i++) + result *= x->x_multivalue[i]; + outlet_float(x->x_outlet, result); +} + +static void multi_float(t_multi *x, t_floatarg f) +{ + x->x_multivalue[0] = f; + multi_bang(x); /* calculate result */ +} + +static void multi_ft1(t_multi *x, t_floatarg f) +{ + x->x_multivalue[1] = f; + multi_bang(x); /* calculate result */ +} + +static t_class *multi_class; + +static void *multi_new(t_symbol *s, t_int argc, t_atom* argv) +{ + int i; + + t_multi *x = (t_multi *)pd_new(multi_class); + x->x_inright = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); + for(i = 2; i < argc; i++) /* create additional inlets, if any */ + { + floatinlet_new(&x->x_ob, &x->x_multivalue[i]); + } + x->x_outlet = outlet_new(&x->x_ob, gensym("float")); + + for(i = 0; i < argc; i++) + { + x->x_multivalue[i] = atom_getfloatarg(i, argc, argv);; + } + x->x_numvalues = i; + + return (void *)x; +} + +#ifndef MAXLIB +void multi_setup(void) +{ + multi_class = class_new(gensym("multi"), (t_newmethod)multi_new, + 0, sizeof(t_multi), 0, A_GIMME, 0); + class_addfloat(multi_class, multi_float); + class_addmethod(multi_class, (t_method)multi_ft1, gensym("ft1"), A_FLOAT, 0); + class_addbang(multi_class, (t_method)multi_bang); + + logpost(NULL, 4, version); +} +#else +void maxlib_multi_setup(void) +{ + multi_class = class_new(gensym("maxlib_multi"), (t_newmethod)multi_new, + 0, sizeof(t_multi), 0, A_GIMME, 0); + class_addcreator((t_newmethod)multi_new, gensym("multi"), A_GIMME, 0); + class_addfloat(multi_class, multi_float); + class_addmethod(multi_class, (t_method)multi_ft1, gensym("ft1"), A_FLOAT, 0); + class_addbang(multi_class, (t_method)multi_bang); + class_sethelpsymbol(multi_class, gensym("maxlib/multi-help.pd")); +} +#endif diff --git a/nchange.c b/nchange.c index 57945b1..5ede0c0 100644 --- a/nchange.c +++ b/nchange.c @@ -1,205 +1,205 @@ -/* ------------------------- ignore ------------------------------------------- */ -/* */ -/* A 'new' change object for more than just floats. */ -/* Written by Olaf Matthes */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#define A_LIST 254; -#define A_ANYTHING 255; - -#include "m_pd.h" - -// #include -// #include - -/* -------------------------- nchange ------------------------------ */ -static char *version = "nchange v0.1, written by Olaf Matthes "; - -static t_class *nchange_class; - -typedef struct _nchange -{ - t_object x_obj; - t_atom x_a[256]; - int x_c; - int x_type; -} t_nchange; - -static void *nchange_new(t_symbol *s) -{ - int i; - - t_nchange *x = (t_nchange *)pd_new(nchange_class); - - if(s == gensym("s")) - { - x->x_type = A_SYMBOL; - outlet_new(&x->x_obj, &s_symbol); - } - else if(s == gensym("f")) - { - x->x_type = A_FLOAT; - outlet_new(&x->x_obj, &s_float); - } - else if(s == gensym("l")) - { - x->x_type = A_LIST; - outlet_new(&x->x_obj, &s_list); - } - else - { - x->x_type = A_ANYTHING; - outlet_new(&x->x_obj, &s_anything); - } - - return (x); -} - -static void nchange_bang(t_nchange *x) -{ - if (x->x_type == A_FLOAT) - outlet_float(x->x_obj.ob_outlet, x->x_a->a_w.w_float); - else if (x->x_type == A_SYMBOL) - outlet_symbol(x->x_obj.ob_outlet, x->x_a->a_w.w_symbol); - else - outlet_list(x->x_obj.ob_outlet, NULL, x->x_c, x->x_a); -} - -static void nchange_float(t_nchange *x, t_float f) -{ - if (x->x_type == A_FLOAT) - { - if (f != x->x_a->a_w.w_float) - { - // x->x_f = f; - SETFLOAT(x->x_a, f); - outlet_float(x->x_obj.ob_outlet, x->x_a->a_w.w_float); - } - } -} - -static void nchange_symbol(t_nchange *x, t_symbol *s) -{ - if (x->x_type == A_SYMBOL) - { - if (s != x->x_a->a_w.w_symbol) - { - // x->x_s = s; - SETSYMBOL(x->x_a, s); - outlet_symbol(x->x_obj.ob_outlet, x->x_a->a_w.w_symbol); - } - } -} - -static void nchange_list(t_nchange *x, t_symbol *s, int argc, t_atom *argv) -{ - int i, change = 0; - int c = argc; - - if(c == x->x_c) // same number of elements - for (i = 0; i < c; i++) - { - /* if(x->x_a[i].a_type != argv[i].a_type) - { - change = 1; - break; - } */ - if (x->x_a[i].a_type == A_FLOAT) - { - if (argv[i].a_type != A_FLOAT || x->x_a[i].a_w.w_float != argv[i].a_w.w_float) - { - change = 1; - break; - } - } - else if (x->x_a[i].a_type == A_SYMBOL) - { - if (argv[i].a_type != A_SYMBOL || x->x_a[i].a_w.w_symbol != argv[i].a_w.w_symbol) - { - change = 1; - break; - } - } - } - else change = 1; // different number of elems. - - if (change) - { - x->x_c = c; - for (i = 0; i < c; i++) // same new list - { - x->x_a[i] = argv[i]; - } - outlet_list(x->x_obj.ob_outlet, s, argc, argv); - } -} - -static void nchange_set(t_nchange *x, t_symbol *s, int argc, t_atom *argv) -{ - int i; - - if (x->x_type == A_SYMBOL) - { - SETSYMBOL(x->x_a, argv->a_w.w_symbol); - } - else if (x->x_type == A_FLOAT) - { - SETFLOAT(x->x_a, argv->a_w.w_float); - } - else // list or anything - { - x->x_c = argc; - for (i = 0; i < argc; i++) - { - x->x_a[i] = argv[i]; - } - } -} - -#ifndef MAXLIB -void nchange_setup(void) -{ - nchange_class = class_new(gensym("nchange"), (t_newmethod)nchange_new, 0, - sizeof(t_nchange), 0, A_SYMBOL, 0); - class_addbang(nchange_class, nchange_bang); - class_addfloat(nchange_class, nchange_float); - class_addsymbol(nchange_class, nchange_symbol); - class_addlist(nchange_class, nchange_list); - class_addanything(nchange_class, nchange_list); - class_addmethod(nchange_class, (t_method)nchange_set, gensym("set"), A_GIMME, 0); - - post(version); -} -#else -void maxlib_nchange_setup(void) -{ - nchange_class = class_new(gensym("maxlib_nchange"), (t_newmethod)nchange_new, 0, - sizeof(t_nchange), 0, A_SYMBOL, 0); - class_addcreator((t_newmethod)nchange_new, gensym("nchange"), A_SYMBOL, 0); - class_addbang(nchange_class, nchange_bang); - class_addfloat(nchange_class, nchange_float); - class_addsymbol(nchange_class, nchange_symbol); - class_addlist(nchange_class, nchange_list); - class_addanything(nchange_class, nchange_list); - class_addmethod(nchange_class, (t_method)nchange_set, gensym("set"), A_GIMME, 0); - class_sethelpsymbol(nchange_class, gensym("maxlib/nchange-help.pd")); -} -#endif +/* ------------------------- ignore ------------------------------------------- */ +/* */ +/* A 'new' change object for more than just floats. */ +/* Written by Olaf Matthes */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#define A_LIST 254; +#define A_ANYTHING 255; + +#include "m_pd.h" + +// #include +// #include + +/* -------------------------- nchange ------------------------------ */ +static char *version = "nchange v0.1, written by Olaf Matthes "; + +static t_class *nchange_class; + +typedef struct _nchange +{ + t_object x_obj; + t_atom x_a[256]; + int x_c; + int x_type; +} t_nchange; + +static void *nchange_new(t_symbol *s) +{ + int i; + + t_nchange *x = (t_nchange *)pd_new(nchange_class); + + if(s == gensym("s")) + { + x->x_type = A_SYMBOL; + outlet_new(&x->x_obj, &s_symbol); + } + else if(s == gensym("f")) + { + x->x_type = A_FLOAT; + outlet_new(&x->x_obj, &s_float); + } + else if(s == gensym("l")) + { + x->x_type = A_LIST; + outlet_new(&x->x_obj, &s_list); + } + else + { + x->x_type = A_ANYTHING; + outlet_new(&x->x_obj, &s_anything); + } + + return (x); +} + +static void nchange_bang(t_nchange *x) +{ + if (x->x_type == A_FLOAT) + outlet_float(x->x_obj.ob_outlet, x->x_a->a_w.w_float); + else if (x->x_type == A_SYMBOL) + outlet_symbol(x->x_obj.ob_outlet, x->x_a->a_w.w_symbol); + else + outlet_list(x->x_obj.ob_outlet, NULL, x->x_c, x->x_a); +} + +static void nchange_float(t_nchange *x, t_float f) +{ + if (x->x_type == A_FLOAT) + { + if (f != x->x_a->a_w.w_float) + { + // x->x_f = f; + SETFLOAT(x->x_a, f); + outlet_float(x->x_obj.ob_outlet, x->x_a->a_w.w_float); + } + } +} + +static void nchange_symbol(t_nchange *x, t_symbol *s) +{ + if (x->x_type == A_SYMBOL) + { + if (s != x->x_a->a_w.w_symbol) + { + // x->x_s = s; + SETSYMBOL(x->x_a, s); + outlet_symbol(x->x_obj.ob_outlet, x->x_a->a_w.w_symbol); + } + } +} + +static void nchange_list(t_nchange *x, t_symbol *s, int argc, t_atom *argv) +{ + int i, change = 0; + int c = argc; + + if(c == x->x_c) // same number of elements + for (i = 0; i < c; i++) + { + /* if(x->x_a[i].a_type != argv[i].a_type) + { + change = 1; + break; + } */ + if (x->x_a[i].a_type == A_FLOAT) + { + if (argv[i].a_type != A_FLOAT || x->x_a[i].a_w.w_float != argv[i].a_w.w_float) + { + change = 1; + break; + } + } + else if (x->x_a[i].a_type == A_SYMBOL) + { + if (argv[i].a_type != A_SYMBOL || x->x_a[i].a_w.w_symbol != argv[i].a_w.w_symbol) + { + change = 1; + break; + } + } + } + else change = 1; // different number of elems. + + if (change) + { + x->x_c = c; + for (i = 0; i < c; i++) // same new list + { + x->x_a[i] = argv[i]; + } + outlet_list(x->x_obj.ob_outlet, s, argc, argv); + } +} + +static void nchange_set(t_nchange *x, t_symbol *s, int argc, t_atom *argv) +{ + int i; + + if (x->x_type == A_SYMBOL) + { + SETSYMBOL(x->x_a, argv->a_w.w_symbol); + } + else if (x->x_type == A_FLOAT) + { + SETFLOAT(x->x_a, argv->a_w.w_float); + } + else // list or anything + { + x->x_c = argc; + for (i = 0; i < argc; i++) + { + x->x_a[i] = argv[i]; + } + } +} + +#ifndef MAXLIB +void nchange_setup(void) +{ + nchange_class = class_new(gensym("nchange"), (t_newmethod)nchange_new, 0, + sizeof(t_nchange), 0, A_SYMBOL, 0); + class_addbang(nchange_class, nchange_bang); + class_addfloat(nchange_class, nchange_float); + class_addsymbol(nchange_class, nchange_symbol); + class_addlist(nchange_class, nchange_list); + class_addanything(nchange_class, nchange_list); + class_addmethod(nchange_class, (t_method)nchange_set, gensym("set"), A_GIMME, 0); + + logpost(NULL, 4, version); +} +#else +void maxlib_nchange_setup(void) +{ + nchange_class = class_new(gensym("maxlib_nchange"), (t_newmethod)nchange_new, 0, + sizeof(t_nchange), 0, A_SYMBOL, 0); + class_addcreator((t_newmethod)nchange_new, gensym("nchange"), A_SYMBOL, 0); + class_addbang(nchange_class, nchange_bang); + class_addfloat(nchange_class, nchange_float); + class_addsymbol(nchange_class, nchange_symbol); + class_addlist(nchange_class, nchange_list); + class_addanything(nchange_class, nchange_list); + class_addmethod(nchange_class, (t_method)nchange_set, gensym("set"), A_GIMME, 0); + class_sethelpsymbol(nchange_class, gensym("maxlib/nchange-help.pd")); +} +#endif diff --git a/netclient.c b/netclient.c index 3a024cd..7436aed 100644 --- a/netclient.c +++ b/netclient.c @@ -1,396 +1,396 @@ -/* -------------------------- netclient ------------------------------------- */ -/* */ -/* Extended 'netsend', connects to 'netserver'. */ -/* Uses child thread to connect to server. Thus needs pd0.35-test17 or later. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* -------------------------- netclient ------------------------------------- */ +/* */ +/* Extended 'netsend', connects to 'netserver'. */ +/* Uses child thread to connect to server. Thus needs pd0.35-test17 or later. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ /* Get source at */ /* http://pure-data.svn.sourceforge.net/viewvc/pure-data/trunk/externals/maxlib/src/netclient.c */ /* March 26 2010 */ /* Additional fixes and improvements by Ivica Ico Bukvic */ /* for the purpose of L2Ork http://l2ork.music.vt.edu */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ -/* Changes: use circular message buffer for receive */ -/* using pollfunction instead of clock (suggested by HCS) */ - -#include "m_pd.h" -#include "s_stuff.h" -#include "m_imp.h" - -#include -#include -#include -#ifdef WIN32 -#include -#else -#include -#include -#include -#include -#include -#include -#include -#define SOCKET_ERROR -1 -#endif - -#define INBUFSIZE 4096 /* maximum numbers of characters to read */ - -static char *version = "netclient v0.3.1, written by Olaf Matthes "; - -static t_class *netclient_class; -static t_binbuf *inbinbuf; -static int netclient_instance_count; - -typedef struct _netclient -{ - t_object x_obj; - t_clock *x_clock; - t_outlet *x_outdata; - t_outlet *x_outconnect; - int x_fd; - char *x_hostname; - int x_connectstate; - int x_port; - int x_protocol; - char x_inbuf[INBUFSIZE]; /* circular message buffer for received data */ - int x_intail; - int x_inhead; - /* multithread stuff */ - pthread_t x_threadid; /* id of child thread */ - pthread_attr_t x_threadattr; /* attributes of child thread */ -} t_netclient; - - /* one lonely prototype */ -static void netclient_rcv(t_netclient *x); - - - /* gets called when connection status has changed */ -static void netclient_tick(t_netclient *x) -{ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ +/* Changes: use circular message buffer for receive */ +/* using pollfunction instead of clock (suggested by HCS) */ + +#include "m_pd.h" +#include "s_stuff.h" +#include "m_imp.h" + +#include +#include +#include +#ifdef WIN32 +#include +#else +#include +#include +#include +#include +#include +#include +#include +#define SOCKET_ERROR -1 +#endif + +#define INBUFSIZE 4096 /* maximum numbers of characters to read */ + +static char *version = "netclient v0.3.1, written by Olaf Matthes "; + +static t_class *netclient_class; +static t_binbuf *inbinbuf; +static int netclient_instance_count; + +typedef struct _netclient +{ + t_object x_obj; + t_clock *x_clock; + t_outlet *x_outdata; + t_outlet *x_outconnect; + int x_fd; + char *x_hostname; + int x_connectstate; + int x_port; + int x_protocol; + char x_inbuf[INBUFSIZE]; /* circular message buffer for received data */ + int x_intail; + int x_inhead; + /* multithread stuff */ + pthread_t x_threadid; /* id of child thread */ + pthread_attr_t x_threadattr; /* attributes of child thread */ +} t_netclient; + + /* one lonely prototype */ +static void netclient_rcv(t_netclient *x); + + + /* gets called when connection status has changed */ +static void netclient_tick(t_netclient *x) +{ outlet_float(x->x_outconnect, x->x_connectstate); /* add pollfunction for checking for input */ if (x->x_connectstate == 1) { sys_addpollfn(x->x_fd, (t_fdpollfn)netclient_rcv, x); } -} - -static void *netclient_child_connect(void *w) -{ - t_netclient *x = (t_netclient*) w; - struct sockaddr_in server; - struct hostent *hp; - int sockfd; - int portno = x->x_port; - if (x->x_fd >= 0) - { - error("netclient_connect: already connected"); - return (x); - } - - /* create a socket */ - sockfd = socket(AF_INET, x->x_protocol, 0); -#if 0 - fprintf(stderr, "send socket %d\n", sockfd); -#endif - if (sockfd < 0) - { - sys_sockerror("socket"); - return (x); - } - /* connect socket using hostname provided in command line */ - server.sin_family = AF_INET; - hp = gethostbyname(x->x_hostname); - if (hp == 0) - { - post("bad host?\n"); - return (x); - } - memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); - - /* assign client port number */ - server.sin_port = htons((u_short)portno); - - post("connecting to port %d", portno); - /* try to connect */ - if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) - { - sys_sockerror("connecting stream socket"); - sys_closesocket(sockfd); - return (x); - } - x->x_fd = sockfd; - /* outlet_float is not threadsafe ! */ - // outlet_float(x->x_obj.ob_outlet, 1); - x->x_connectstate = 1; - /* use callback instead to set outlet */ - clock_delay(x->x_clock, 0); - return (x); -} - -static void netclient_connect(t_netclient *x, t_symbol *hostname, - t_floatarg fportno) -{ - /* we get hostname and port and pass them on - to the child thread that establishes the connection */ - x->x_hostname = hostname->s_name; - x->x_port = fportno; - x->x_connectstate = 0; - /* start child thread */ - if(pthread_create( &x->x_threadid, &x->x_threadattr, netclient_child_connect, x) < 0) - post("netclient: could not create new thread"); -} - -static void netclient_disconnect(t_netclient *x) -{ - if (x->x_fd >= 0) - { - sys_rmpollfn(x->x_fd); - sys_closesocket(x->x_fd); - x->x_fd = -1; - x->x_connectstate = 0; - //outlet_float(x->x_outconnect, 0); +} + +static void *netclient_child_connect(void *w) +{ + t_netclient *x = (t_netclient*) w; + struct sockaddr_in server; + struct hostent *hp; + int sockfd; + int portno = x->x_port; + if (x->x_fd >= 0) + { + error("netclient_connect: already connected"); + return (x); + } + + /* create a socket */ + sockfd = socket(AF_INET, x->x_protocol, 0); +#if 0 + fprintf(stderr, "send socket %d\n", sockfd); +#endif + if (sockfd < 0) + { + sys_sockerror("socket"); + return (x); + } + /* connect socket using hostname provided in command line */ + server.sin_family = AF_INET; + hp = gethostbyname(x->x_hostname); + if (hp == 0) + { + post("bad host?\n"); + return (x); + } + memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); + + /* assign client port number */ + server.sin_port = htons((u_short)portno); + + post("connecting to port %d", portno); + /* try to connect */ + if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) + { + sys_sockerror("connecting stream socket"); + sys_closesocket(sockfd); + return (x); + } + x->x_fd = sockfd; + /* outlet_float is not threadsafe ! */ + // outlet_float(x->x_obj.ob_outlet, 1); + x->x_connectstate = 1; + /* use callback instead to set outlet */ + clock_delay(x->x_clock, 0); + return (x); +} + +static void netclient_connect(t_netclient *x, t_symbol *hostname, + t_floatarg fportno) +{ + /* we get hostname and port and pass them on + to the child thread that establishes the connection */ + x->x_hostname = hostname->s_name; + x->x_port = fportno; + x->x_connectstate = 0; + /* start child thread */ + if(pthread_create( &x->x_threadid, &x->x_threadattr, netclient_child_connect, x) < 0) + post("netclient: could not create new thread"); +} + +static void netclient_disconnect(t_netclient *x) +{ + if (x->x_fd >= 0) + { + sys_rmpollfn(x->x_fd); + sys_closesocket(x->x_fd); + x->x_fd = -1; + x->x_connectstate = 0; + //outlet_float(x->x_outconnect, 0); clock_delay(x->x_clock, 0); /* output connect state later */ - } -} - -static void netclient_send(t_netclient *x, t_symbol *s, int argc, t_atom *argv) -{ - if (x->x_fd >= 0) - { - t_binbuf *b = binbuf_new(); - char *buf, *bp; - int length, sent; - t_atom at; - binbuf_add(b, argc, argv); - SETSEMI(&at); - binbuf_add(b, 1, &at); - binbuf_gettext(b, &buf, &length); - for (bp = buf, sent = 0; sent < length;) - { - static double lastwarntime; - static double pleasewarn; - double timebefore = sys_getrealtime(); - int res = send(x->x_fd, buf, length-sent, 0); - double timeafter = sys_getrealtime(); - int late = (timeafter - timebefore > 0.005); - if (late || pleasewarn) - { - if (timeafter > lastwarntime + 2) - { - post("netclient blocked %d msec", - (int)(1000 * ((timeafter - timebefore) + pleasewarn))); - pleasewarn = 0; - lastwarntime = timeafter; - } - else if (late) pleasewarn += timeafter - timebefore; - } - if (res <= 0) - { - sys_sockerror("netclient"); - netclient_disconnect(x); - break; - } - else - { - sent += res; - bp += res; - } - } - t_freebytes(buf, length); - binbuf_free(b); - } - else error("netclient: not connected"); -} - - /* this is in a separately called subroutine so that the buffer isn't - sitting on the stack while the messages are getting passed. */ -static int netclient_doread(t_netclient *x) -{ - char messbuf[INBUFSIZE], *bp = messbuf; - int indx; - int inhead = x->x_inhead; - int intail = x->x_intail; - char *inbuf = x->x_inbuf; - if (intail == inhead) return (0); - for (indx = intail; indx != inhead; indx = (indx+1)&(INBUFSIZE-1)) - { - char c = *bp++ = inbuf[indx]; - if (c == ';' && (!indx || inbuf[indx-1] != '\\')) - { - intail = (indx+1)&(INBUFSIZE-1); - binbuf_text(inbinbuf, messbuf, bp - messbuf); - x->x_inhead = inhead; - x->x_intail = intail; - return (1); - } - } - return (0); -} - -static void netclient_rcv(t_netclient *x) -{ - int fd = x->x_fd; - int ret; - fd_set readset; - fd_set exceptset; - struct timeval ztout; - /* output data */ - int msg, natom; - t_atom *at; - - if(x->x_connectstate) - { - /* check if we can read/write from/to the socket */ - FD_ZERO(&readset); - FD_ZERO(&exceptset); - FD_SET(fd, &readset ); - FD_SET(fd, &exceptset ); - - ztout.tv_sec = 0; - ztout.tv_usec = 0; - ret = select(fd+1, &readset, NULL, &exceptset, &ztout); - if(ret < 0) - { - error("netclient: can not read from socket"); + } +} + +static void netclient_send(t_netclient *x, t_symbol *s, int argc, t_atom *argv) +{ + if (x->x_fd >= 0) + { + t_binbuf *b = binbuf_new(); + char *buf, *bp; + int length, sent; + t_atom at; + binbuf_add(b, argc, argv); + SETSEMI(&at); + binbuf_add(b, 1, &at); + binbuf_gettext(b, &buf, &length); + for (bp = buf, sent = 0; sent < length;) + { + static double lastwarntime; + static double pleasewarn; + double timebefore = sys_getrealtime(); + int res = send(x->x_fd, buf, length-sent, 0); + double timeafter = sys_getrealtime(); + int late = (timeafter - timebefore > 0.005); + if (late || pleasewarn) + { + if (timeafter > lastwarntime + 2) + { + post("netclient blocked %d msec", + (int)(1000 * ((timeafter - timebefore) + pleasewarn))); + pleasewarn = 0; + lastwarntime = timeafter; + } + else if (late) pleasewarn += timeafter - timebefore; + } + if (res <= 0) + { + sys_sockerror("netclient"); + netclient_disconnect(x); + break; + } + else + { + sent += res; + bp += res; + } + } + t_freebytes(buf, length); + binbuf_free(b); + } + else error("netclient: not connected"); +} + + /* this is in a separately called subroutine so that the buffer isn't + sitting on the stack while the messages are getting passed. */ +static int netclient_doread(t_netclient *x) +{ + char messbuf[INBUFSIZE], *bp = messbuf; + int indx; + int inhead = x->x_inhead; + int intail = x->x_intail; + char *inbuf = x->x_inbuf; + if (intail == inhead) return (0); + for (indx = intail; indx != inhead; indx = (indx+1)&(INBUFSIZE-1)) + { + char c = *bp++ = inbuf[indx]; + if (c == ';' && (!indx || inbuf[indx-1] != '\\')) + { + intail = (indx+1)&(INBUFSIZE-1); + binbuf_text(inbinbuf, messbuf, bp - messbuf); + x->x_inhead = inhead; + x->x_intail = intail; + return (1); + } + } + return (0); +} + +static void netclient_rcv(t_netclient *x) +{ + int fd = x->x_fd; + int ret; + fd_set readset; + fd_set exceptset; + struct timeval ztout; + /* output data */ + int msg, natom; + t_atom *at; + + if(x->x_connectstate) + { + /* check if we can read/write from/to the socket */ + FD_ZERO(&readset); + FD_ZERO(&exceptset); + FD_SET(fd, &readset ); + FD_SET(fd, &exceptset ); + + ztout.tv_sec = 0; + ztout.tv_usec = 0; + ret = select(fd+1, &readset, NULL, &exceptset, &ztout); + if(ret < 0) + { + error("netclient: can not read from socket"); //sys_closesocket(fd); - netclient_disconnect(x); - return; - } - if(FD_ISSET(fd, &readset) || FD_ISSET(fd, &exceptset)) - { - int readto = (x->x_inhead >= x->x_intail ? INBUFSIZE : x->x_intail-1); - - ret = recv(fd, x->x_inbuf + x->x_inhead, readto - x->x_inhead, 0); - if (ret < 0) - { - sys_sockerror("recv"); - //sys_rmpollfn(fd); + netclient_disconnect(x); + return; + } + if(FD_ISSET(fd, &readset) || FD_ISSET(fd, &exceptset)) + { + int readto = (x->x_inhead >= x->x_intail ? INBUFSIZE : x->x_intail-1); + + ret = recv(fd, x->x_inbuf + x->x_inhead, readto - x->x_inhead, 0); + if (ret < 0) + { + sys_sockerror("recv"); + //sys_rmpollfn(fd); //sys_closesocket(fd); - netclient_disconnect(x); - } - else if (ret == 0) - { - post("netclient: connection closed on socket %d", fd); - //sys_rmpollfn(fd); - //sys_closesocket(fd); - netclient_disconnect(x); - } - else - { - x->x_inhead += ret; - if (x->x_inhead >= INBUFSIZE) x->x_inhead = 0; - while (netclient_doread(x)) - { - /* output binbuf */ - natom = binbuf_getnatom(inbinbuf); /* get number of atoms */ - at = binbuf_getvec(inbinbuf); /* get the atoms */ - /* now split it into several parts at every A_SEMI because - we probably received more than one message at a time */ - for (msg = 0; msg < natom;) - { - int emsg; - for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA - && at[emsg].a_type != A_SEMI; emsg++); - - if (emsg > msg) - { - int ii; - for (ii = msg; ii < emsg; ii++) - if (at[ii].a_type == A_DOLLAR || at[ii].a_type == A_DOLLSYM) - { - pd_error(x, "netserver: -- got dollar sign in message"); - goto nodice; - } - if (at[msg].a_type == A_FLOAT) - { - if (emsg > msg + 1) - outlet_list(x->x_outdata, 0, emsg-msg, at + msg); - else outlet_float(x->x_outdata, at[msg].a_w.w_float); - } - else if (at[msg].a_type == A_SYMBOL) - outlet_anything(x->x_outdata, at[msg].a_w.w_symbol, - emsg-msg-1, at + msg + 1); - } - nodice: - msg = emsg + 1; - } - } - } - } - } - else post("netclient: not connected"); -} - -static void *netclient_new(t_floatarg udpflag) -{ - t_netclient *x = (t_netclient *)pd_new(netclient_class); - x->x_outdata = outlet_new(&x->x_obj, &s_anything); /* received data */ - x->x_outconnect = outlet_new(&x->x_obj, &s_float); /* connection state */ - x->x_clock = clock_new(x, (t_method)netclient_tick); - if(netclient_instance_count == 0) - inbinbuf = binbuf_new(); - x->x_fd = -1; - x->x_protocol = (udpflag != 0 ? SOCK_DGRAM : SOCK_STREAM); - /* prepare child thread */ - if(pthread_attr_init(&x->x_threadattr) < 0) - post("netclient: warning: could not prepare child thread" ); - if(pthread_attr_setdetachstate(&x->x_threadattr, PTHREAD_CREATE_DETACHED) < 0) - post("netclient: warning: could not prepare child thread" ); - netclient_instance_count++; - return (x); -} - -static void netclient_free(t_netclient *x) -{ - netclient_disconnect(x); - clock_free(x->x_clock); - netclient_instance_count--; - if(netclient_instance_count == 0) - binbuf_free(inbinbuf); -} - -#ifndef MAXLIB -void netclient_setup(void) -{ - netclient_class = class_new(gensym("netclient"), (t_newmethod)netclient_new, - (t_method)netclient_free, - sizeof(t_netclient), 0, A_DEFFLOAT, 0); - class_addmethod(netclient_class, (t_method)netclient_connect, gensym("connect"), A_SYMBOL, A_FLOAT, 0); - class_addmethod(netclient_class, (t_method)netclient_disconnect, gensym("disconnect"), 0); - class_addmethod(netclient_class, (t_method)netclient_send, gensym("send"), A_GIMME, 0); - class_addmethod(netclient_class, (t_method)netclient_rcv, gensym("receive"), 0); - class_addmethod(netclient_class, (t_method)netclient_rcv, gensym("rcv"), 0); - - post(version); -} -#else -void maxlib_netclient_setup(void) -{ - netclient_class = class_new(gensym("maxlib_netclient"), (t_newmethod)netclient_new, - (t_method)netclient_free, - sizeof(t_netclient), 0, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)netclient_new, gensym("netclient"), A_DEFFLOAT, 0); - class_addmethod(netclient_class, (t_method)netclient_connect, gensym("connect"), A_SYMBOL, A_FLOAT, 0); - class_addmethod(netclient_class, (t_method)netclient_disconnect, gensym("disconnect"), 0); - class_addmethod(netclient_class, (t_method)netclient_send, gensym("send"), A_GIMME, 0); - class_addmethod(netclient_class, (t_method)netclient_rcv, gensym("receive"), 0); - class_addmethod(netclient_class, (t_method)netclient_rcv, gensym("rcv"), 0); - class_sethelpsymbol(netclient_class, gensym("maxlib/netclient-help.pd")); -} -#endif + netclient_disconnect(x); + } + else if (ret == 0) + { + post("netclient: connection closed on socket %d", fd); + //sys_rmpollfn(fd); + //sys_closesocket(fd); + netclient_disconnect(x); + } + else + { + x->x_inhead += ret; + if (x->x_inhead >= INBUFSIZE) x->x_inhead = 0; + while (netclient_doread(x)) + { + /* output binbuf */ + natom = binbuf_getnatom(inbinbuf); /* get number of atoms */ + at = binbuf_getvec(inbinbuf); /* get the atoms */ + /* now split it into several parts at every A_SEMI because + we probably received more than one message at a time */ + for (msg = 0; msg < natom;) + { + int emsg; + for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA + && at[emsg].a_type != A_SEMI; emsg++); + + if (emsg > msg) + { + int ii; + for (ii = msg; ii < emsg; ii++) + if (at[ii].a_type == A_DOLLAR || at[ii].a_type == A_DOLLSYM) + { + pd_error(x, "netserver: -- got dollar sign in message"); + goto nodice; + } + if (at[msg].a_type == A_FLOAT) + { + if (emsg > msg + 1) + outlet_list(x->x_outdata, 0, emsg-msg, at + msg); + else outlet_float(x->x_outdata, at[msg].a_w.w_float); + } + else if (at[msg].a_type == A_SYMBOL) + outlet_anything(x->x_outdata, at[msg].a_w.w_symbol, + emsg-msg-1, at + msg + 1); + } + nodice: + msg = emsg + 1; + } + } + } + } + } + else post("netclient: not connected"); +} + +static void *netclient_new(t_floatarg udpflag) +{ + t_netclient *x = (t_netclient *)pd_new(netclient_class); + x->x_outdata = outlet_new(&x->x_obj, &s_anything); /* received data */ + x->x_outconnect = outlet_new(&x->x_obj, &s_float); /* connection state */ + x->x_clock = clock_new(x, (t_method)netclient_tick); + if(netclient_instance_count == 0) + inbinbuf = binbuf_new(); + x->x_fd = -1; + x->x_protocol = (udpflag != 0 ? SOCK_DGRAM : SOCK_STREAM); + /* prepare child thread */ + if(pthread_attr_init(&x->x_threadattr) < 0) + post("netclient: warning: could not prepare child thread" ); + if(pthread_attr_setdetachstate(&x->x_threadattr, PTHREAD_CREATE_DETACHED) < 0) + post("netclient: warning: could not prepare child thread" ); + netclient_instance_count++; + return (x); +} + +static void netclient_free(t_netclient *x) +{ + netclient_disconnect(x); + clock_free(x->x_clock); + netclient_instance_count--; + if(netclient_instance_count == 0) + binbuf_free(inbinbuf); +} + +#ifndef MAXLIB +void netclient_setup(void) +{ + netclient_class = class_new(gensym("netclient"), (t_newmethod)netclient_new, + (t_method)netclient_free, + sizeof(t_netclient), 0, A_DEFFLOAT, 0); + class_addmethod(netclient_class, (t_method)netclient_connect, gensym("connect"), A_SYMBOL, A_FLOAT, 0); + class_addmethod(netclient_class, (t_method)netclient_disconnect, gensym("disconnect"), 0); + class_addmethod(netclient_class, (t_method)netclient_send, gensym("send"), A_GIMME, 0); + class_addmethod(netclient_class, (t_method)netclient_rcv, gensym("receive"), 0); + class_addmethod(netclient_class, (t_method)netclient_rcv, gensym("rcv"), 0); + + logpost(NULL, 4, version); +} +#else +void maxlib_netclient_setup(void) +{ + netclient_class = class_new(gensym("maxlib_netclient"), (t_newmethod)netclient_new, + (t_method)netclient_free, + sizeof(t_netclient), 0, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)netclient_new, gensym("netclient"), A_DEFFLOAT, 0); + class_addmethod(netclient_class, (t_method)netclient_connect, gensym("connect"), A_SYMBOL, A_FLOAT, 0); + class_addmethod(netclient_class, (t_method)netclient_disconnect, gensym("disconnect"), 0); + class_addmethod(netclient_class, (t_method)netclient_send, gensym("send"), A_GIMME, 0); + class_addmethod(netclient_class, (t_method)netclient_rcv, gensym("receive"), 0); + class_addmethod(netclient_class, (t_method)netclient_rcv, gensym("rcv"), 0); + class_sethelpsymbol(netclient_class, gensym("maxlib/netclient-help.pd")); +} +#endif diff --git a/netdist.c b/netdist.c index 866dc36..2f2bf50 100644 --- a/netdist.c +++ b/netdist.c @@ -1,313 +1,313 @@ -/* -------------------------- netdist --------------------------------------- */ -/* */ -/* Distributes incoming data to a changeable list of netreceive objects. */ -/* Uses child thread to connect to clients. Thus needs pd0.35-test17 or later. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - - -#include "m_pd.h" - -#include -#include -#include -#ifdef WIN32 -#include -#else -#include -#include -#include -#include -#include -#include -#define SOCKET_ERROR -1 -#endif - -#define MAX_REC 32 - -static char *version = "netdist v0.1, written by Olaf Matthes "; - -static t_class *netdist_class; - -typedef struct _netdist -{ - t_object x_obj; - t_clock *x_clock; - int x_fd[MAX_REC]; - char *x_hostname[MAX_REC]; - int x_numconnect; - int x_port[MAX_REC]; - int x_protocol; - /* multithread stuff */ - pthread_t x_threadid; /* id of child thread */ - pthread_attr_t x_threadattr; /* attributes of child thread */ -} t_netdist; - -static void sys_sockerror(char *s) -{ -#ifdef WIN32 - int err = WSAGetLastError(); - if (err == 10054) return; -#else - int err = errno; -#endif - post("%s: %s (%d)\n", s, strerror(err), err); -} - -static void sys_closesocket(int fd) { - -#ifdef WIN32 - closesocket(fd); -#else - close(fd); -#endif -} - - -static void netdist_tick(t_netdist *x) -{ - outlet_float(x->x_obj.ob_outlet, x->x_numconnect + 1); -} - -static void *netdist_new(t_floatarg udpflag) -{ - int i; - t_netdist *x = (t_netdist *)pd_new(netdist_class); - outlet_new(&x->x_obj, &s_float); - x->x_clock = clock_new(x, (t_method)netdist_tick); - for(i = 0; i < MAX_REC; i++)x->x_fd[i] = -1; - x->x_numconnect = -1; - x->x_protocol = (udpflag != 0 ? SOCK_DGRAM : SOCK_STREAM); - - /* prepare child thread */ - if(pthread_attr_init(&x->x_threadattr) < 0) - post("netdist: warning: could not prepare child thread" ); - if(pthread_attr_setdetachstate(&x->x_threadattr, PTHREAD_CREATE_DETACHED) < 0) - post("netdist: warning: could not prepare child thread" ); - return (x); -} - -static void *netdist_child_connect(void *w) -{ - int i; - - t_netdist *x = (t_netdist*) w; - struct sockaddr_in server; - struct hostent *hp; - int sockfd; - int portno; - i = x->x_numconnect + 1; - portno = x->x_port[i]; - /* create a socket */ - sockfd = socket(AF_INET, x->x_protocol, 0); -#if 0 - fprintf(stderr, "send socket %d\n", sockfd); -#endif - if (sockfd < 0) - { - sys_sockerror("socket"); - return (x); - } - /* connect socket using hostname provided in command line */ - server.sin_family = AF_INET; - hp = gethostbyname(x->x_hostname[i]); - if (hp == 0) - { - post("bad host?\n"); - return (x); - } - memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); - - /* assign client port number */ - server.sin_port = htons((u_short)portno); - - post("connecting to port %d", portno); - /* try to connect */ - if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) - { - sys_sockerror("connecting stream socket"); - sys_closesocket(sockfd); - return (x); - } - x->x_fd[i] = sockfd; - /* outlet_float is not threadsafe ! */ - // outlet_float(x->x_obj.ob_outlet, 1); - x->x_numconnect++; /* count connection */ - /* use callback instead to set outlet */ - clock_delay(x->x_clock, 0); - return (x); -} - -static void netdist_connect(t_netdist *x, t_symbol *hostname, - t_floatarg fportno) -{ - int i; - /* we get hostname and port and pass them on - to the child thread that establishes the connection */ - for(i = 0; i <= x->x_numconnect; i++) - { /* check if we are already connected */ - if (hostname->s_name == x->x_hostname[i] && fportno == x->x_port[i]) - { - error("netdist_connect: already connected"); - return; - } - } - x->x_hostname[x->x_numconnect + 1] = hostname->s_name; - x->x_port[x->x_numconnect + 1] = fportno; - - /* start child thread */ - if(pthread_create( &x->x_threadid, &x->x_threadattr, netdist_child_connect, x) < 0) - post("netdist: could not create new thread"); -} - -static void netdist_disconnect(t_netdist *x, t_symbol *hostname, t_floatarg port) -{ - int i, j; - for(i = 0; i <= x->x_numconnect; i++) - { - if((hostname->s_name == x->x_hostname[i]) && ((int)port == x->x_port[i])) - { - /* search for connection */ - if (x->x_fd[i] >= 0) - { - sys_closesocket(x->x_fd[i]); - x->x_fd[i] = -1; - x->x_numconnect--; - outlet_float(x->x_obj.ob_outlet, x->x_numconnect + 1); - for(j = i; j <= x->x_numconnect; j++) - { - x->x_hostname[j] = x->x_hostname[j + 1]; - x->x_port[j] = x->x_port[j + 1]; - x->x_fd[j] = x->x_fd[j + 1]; - } - } - } - } -} - -static void netdist_send(t_netdist *x, t_symbol *s, int argc, t_atom *argv) -{ - int i = 0; - - for(i = 0; i <= x->x_numconnect; i++) - { - if (x->x_fd[i] >= 0) - { - t_binbuf *b = binbuf_new(); - char *buf, *bp; - int length, sent; - t_atom at; - binbuf_add(b, argc, argv); - SETSEMI(&at); - binbuf_add(b, 1, &at); - binbuf_gettext(b, &buf, &length); - for (bp = buf, sent = 0; sent < length;) - { - static double lastwarntime; - static double pleasewarn; - double timebefore = clock_getlogicaltime(); - int res = send(x->x_fd[i], buf, length-sent, 0); - double timeafter = clock_getlogicaltime(); - int late = (timeafter - timebefore > 0.005); - if (late || pleasewarn) - { - if (timeafter > lastwarntime + 2) - { - post("netdist blocked %d msec", - (int)(1000 * ((timeafter - timebefore) + pleasewarn))); - pleasewarn = 0; - lastwarntime = timeafter; - } - else if (late) pleasewarn += timeafter - timebefore; - } - if (res <= 0) - { - sys_sockerror("netdist"); - netdist_disconnect(x, gensym(x->x_hostname[i]), x->x_port[i]); - break; - } - else - { - sent += res; - bp += res; - } - } - t_freebytes(buf, length); - binbuf_free(b); - } - } - if(x->x_numconnect == -1) error("netdist: not connected"); -} - - /* disconnect all */ -static void netdist_clear(t_netdist *x) -{ - int i, j, n; - n = x->x_numconnect; - for (i = n; i >= 0; i--) - { - netdist_disconnect(x, gensym(x->x_hostname[i]), x->x_port[i]); - } -} - -static void netdist_print(t_netdist *x) -{ - int i; - post("netdist: %d connection(s) established:", x->x_numconnect + 1); - for (i = x->x_numconnect; i >= 0; i--) - { - post(" \"%s\", port %d",x->x_hostname[i], x->x_port[i]); - } -} - -static void netdist_free(t_netdist *x) -{ - netdist_clear(x); - clock_free(x->x_clock); -} - -#ifndef MAXLIB -void netdist_setup(void) -{ - netdist_class = class_new(gensym("netdist"), (t_newmethod)netdist_new, - (t_method)netdist_free, sizeof(t_netdist), 0, A_DEFFLOAT, 0); - class_addmethod(netdist_class, (t_method)netdist_connect, gensym("connect"), A_SYMBOL, A_FLOAT, 0); - class_addmethod(netdist_class, (t_method)netdist_disconnect, gensym("disconnect"), A_SYMBOL, A_FLOAT, 0); - class_addmethod(netdist_class, (t_method)netdist_send, gensym("send"), A_GIMME, 0); - class_addmethod(netdist_class, (t_method)netdist_clear, gensym("clear"), 0); - class_addmethod(netdist_class, (t_method)netdist_print, gensym("print"), 0); - - post(version); -} -#else -void maxlib_netdist_setup(void) -{ - netdist_class = class_new(gensym("maxlib_netdist"), (t_newmethod)netdist_new, - (t_method)netdist_free, sizeof(t_netdist), 0, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)netdist_new, gensym("netdist"), A_DEFFLOAT, 0); - class_addmethod(netdist_class, (t_method)netdist_connect, gensym("connect"), A_SYMBOL, A_FLOAT, 0); - class_addmethod(netdist_class, (t_method)netdist_disconnect, gensym("disconnect"), A_SYMBOL, A_FLOAT, 0); - class_addmethod(netdist_class, (t_method)netdist_send, gensym("send"), A_GIMME, 0); - class_addmethod(netdist_class, (t_method)netdist_clear, gensym("clear"), 0); - class_addmethod(netdist_class, (t_method)netdist_print, gensym("print"), 0); - class_sethelpsymbol(netdist_class, gensym("maxlib/netdist-help.pd")); -} -#endif +/* -------------------------- netdist --------------------------------------- */ +/* */ +/* Distributes incoming data to a changeable list of netreceive objects. */ +/* Uses child thread to connect to clients. Thus needs pd0.35-test17 or later. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + + +#include "m_pd.h" + +#include +#include +#include +#ifdef WIN32 +#include +#else +#include +#include +#include +#include +#include +#include +#define SOCKET_ERROR -1 +#endif + +#define MAX_REC 32 + +static char *version = "netdist v0.1, written by Olaf Matthes "; + +static t_class *netdist_class; + +typedef struct _netdist +{ + t_object x_obj; + t_clock *x_clock; + int x_fd[MAX_REC]; + char *x_hostname[MAX_REC]; + int x_numconnect; + int x_port[MAX_REC]; + int x_protocol; + /* multithread stuff */ + pthread_t x_threadid; /* id of child thread */ + pthread_attr_t x_threadattr; /* attributes of child thread */ +} t_netdist; + +static void sys_sockerror(char *s) +{ +#ifdef WIN32 + int err = WSAGetLastError(); + if (err == 10054) return; +#else + int err = errno; +#endif + post("%s: %s (%d)\n", s, strerror(err), err); +} + +static void sys_closesocket(int fd) { + +#ifdef WIN32 + closesocket(fd); +#else + close(fd); +#endif +} + + +static void netdist_tick(t_netdist *x) +{ + outlet_float(x->x_obj.ob_outlet, x->x_numconnect + 1); +} + +static void *netdist_new(t_floatarg udpflag) +{ + int i; + t_netdist *x = (t_netdist *)pd_new(netdist_class); + outlet_new(&x->x_obj, &s_float); + x->x_clock = clock_new(x, (t_method)netdist_tick); + for(i = 0; i < MAX_REC; i++)x->x_fd[i] = -1; + x->x_numconnect = -1; + x->x_protocol = (udpflag != 0 ? SOCK_DGRAM : SOCK_STREAM); + + /* prepare child thread */ + if(pthread_attr_init(&x->x_threadattr) < 0) + post("netdist: warning: could not prepare child thread" ); + if(pthread_attr_setdetachstate(&x->x_threadattr, PTHREAD_CREATE_DETACHED) < 0) + post("netdist: warning: could not prepare child thread" ); + return (x); +} + +static void *netdist_child_connect(void *w) +{ + int i; + + t_netdist *x = (t_netdist*) w; + struct sockaddr_in server; + struct hostent *hp; + int sockfd; + int portno; + i = x->x_numconnect + 1; + portno = x->x_port[i]; + /* create a socket */ + sockfd = socket(AF_INET, x->x_protocol, 0); +#if 0 + fprintf(stderr, "send socket %d\n", sockfd); +#endif + if (sockfd < 0) + { + sys_sockerror("socket"); + return (x); + } + /* connect socket using hostname provided in command line */ + server.sin_family = AF_INET; + hp = gethostbyname(x->x_hostname[i]); + if (hp == 0) + { + post("bad host?\n"); + return (x); + } + memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); + + /* assign client port number */ + server.sin_port = htons((u_short)portno); + + post("connecting to port %d", portno); + /* try to connect */ + if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) + { + sys_sockerror("connecting stream socket"); + sys_closesocket(sockfd); + return (x); + } + x->x_fd[i] = sockfd; + /* outlet_float is not threadsafe ! */ + // outlet_float(x->x_obj.ob_outlet, 1); + x->x_numconnect++; /* count connection */ + /* use callback instead to set outlet */ + clock_delay(x->x_clock, 0); + return (x); +} + +static void netdist_connect(t_netdist *x, t_symbol *hostname, + t_floatarg fportno) +{ + int i; + /* we get hostname and port and pass them on + to the child thread that establishes the connection */ + for(i = 0; i <= x->x_numconnect; i++) + { /* check if we are already connected */ + if (hostname->s_name == x->x_hostname[i] && fportno == x->x_port[i]) + { + error("netdist_connect: already connected"); + return; + } + } + x->x_hostname[x->x_numconnect + 1] = hostname->s_name; + x->x_port[x->x_numconnect + 1] = fportno; + + /* start child thread */ + if(pthread_create( &x->x_threadid, &x->x_threadattr, netdist_child_connect, x) < 0) + post("netdist: could not create new thread"); +} + +static void netdist_disconnect(t_netdist *x, t_symbol *hostname, t_floatarg port) +{ + int i, j; + for(i = 0; i <= x->x_numconnect; i++) + { + if((hostname->s_name == x->x_hostname[i]) && ((int)port == x->x_port[i])) + { + /* search for connection */ + if (x->x_fd[i] >= 0) + { + sys_closesocket(x->x_fd[i]); + x->x_fd[i] = -1; + x->x_numconnect--; + outlet_float(x->x_obj.ob_outlet, x->x_numconnect + 1); + for(j = i; j <= x->x_numconnect; j++) + { + x->x_hostname[j] = x->x_hostname[j + 1]; + x->x_port[j] = x->x_port[j + 1]; + x->x_fd[j] = x->x_fd[j + 1]; + } + } + } + } +} + +static void netdist_send(t_netdist *x, t_symbol *s, int argc, t_atom *argv) +{ + int i = 0; + + for(i = 0; i <= x->x_numconnect; i++) + { + if (x->x_fd[i] >= 0) + { + t_binbuf *b = binbuf_new(); + char *buf, *bp; + int length, sent; + t_atom at; + binbuf_add(b, argc, argv); + SETSEMI(&at); + binbuf_add(b, 1, &at); + binbuf_gettext(b, &buf, &length); + for (bp = buf, sent = 0; sent < length;) + { + static double lastwarntime; + static double pleasewarn; + double timebefore = clock_getlogicaltime(); + int res = send(x->x_fd[i], buf, length-sent, 0); + double timeafter = clock_getlogicaltime(); + int late = (timeafter - timebefore > 0.005); + if (late || pleasewarn) + { + if (timeafter > lastwarntime + 2) + { + post("netdist blocked %d msec", + (int)(1000 * ((timeafter - timebefore) + pleasewarn))); + pleasewarn = 0; + lastwarntime = timeafter; + } + else if (late) pleasewarn += timeafter - timebefore; + } + if (res <= 0) + { + sys_sockerror("netdist"); + netdist_disconnect(x, gensym(x->x_hostname[i]), x->x_port[i]); + break; + } + else + { + sent += res; + bp += res; + } + } + t_freebytes(buf, length); + binbuf_free(b); + } + } + if(x->x_numconnect == -1) error("netdist: not connected"); +} + + /* disconnect all */ +static void netdist_clear(t_netdist *x) +{ + int i, j, n; + n = x->x_numconnect; + for (i = n; i >= 0; i--) + { + netdist_disconnect(x, gensym(x->x_hostname[i]), x->x_port[i]); + } +} + +static void netdist_print(t_netdist *x) +{ + int i; + post("netdist: %d connection(s) established:", x->x_numconnect + 1); + for (i = x->x_numconnect; i >= 0; i--) + { + post(" \"%s\", port %d",x->x_hostname[i], x->x_port[i]); + } +} + +static void netdist_free(t_netdist *x) +{ + netdist_clear(x); + clock_free(x->x_clock); +} + +#ifndef MAXLIB +void netdist_setup(void) +{ + netdist_class = class_new(gensym("netdist"), (t_newmethod)netdist_new, + (t_method)netdist_free, sizeof(t_netdist), 0, A_DEFFLOAT, 0); + class_addmethod(netdist_class, (t_method)netdist_connect, gensym("connect"), A_SYMBOL, A_FLOAT, 0); + class_addmethod(netdist_class, (t_method)netdist_disconnect, gensym("disconnect"), A_SYMBOL, A_FLOAT, 0); + class_addmethod(netdist_class, (t_method)netdist_send, gensym("send"), A_GIMME, 0); + class_addmethod(netdist_class, (t_method)netdist_clear, gensym("clear"), 0); + class_addmethod(netdist_class, (t_method)netdist_print, gensym("print"), 0); + + logpost(NULL, 4, version); +} +#else +void maxlib_netdist_setup(void) +{ + netdist_class = class_new(gensym("maxlib_netdist"), (t_newmethod)netdist_new, + (t_method)netdist_free, sizeof(t_netdist), 0, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)netdist_new, gensym("netdist"), A_DEFFLOAT, 0); + class_addmethod(netdist_class, (t_method)netdist_connect, gensym("connect"), A_SYMBOL, A_FLOAT, 0); + class_addmethod(netdist_class, (t_method)netdist_disconnect, gensym("disconnect"), A_SYMBOL, A_FLOAT, 0); + class_addmethod(netdist_class, (t_method)netdist_send, gensym("send"), A_GIMME, 0); + class_addmethod(netdist_class, (t_method)netdist_clear, gensym("clear"), 0); + class_addmethod(netdist_class, (t_method)netdist_print, gensym("print"), 0); + class_sethelpsymbol(netdist_class, gensym("maxlib/netdist-help.pd")); +} +#endif diff --git a/netrec.c b/netrec.c index 9e89521..91f8dd7 100644 --- a/netrec.c +++ b/netrec.c @@ -1,447 +1,447 @@ -/* -------------------------- netrec ---------------------------------------- */ -/* */ -/* A 'netreceive' that tells the IP of the connecting netsend. */ -/* Written by Olaf Matthes */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include "s_stuff.h" -#include "m_imp.h" - -#include -#include -#include -#include -#include -#include -#include -#ifdef WIN32 -#include -#include -#include -#else -#include -#include -#include -#include -#include -#include -#include -#include -#define SOCKET_ERROR -1 -#endif - -#define MAX_CONNECT 32 /* maximum number of connections */ -#define INBUFSIZE 4096 /* size of receiving data buffer */ - -static char *version = "netrec v0.1, written by Olaf Matthes "; - -/* ----------------------------- netrec ------------------------- */ - -static t_class *netrec_class; -static t_binbuf *inbinbuf; - -typedef void (*t_netrec_socketnotifier)(void *x); -typedef void (*t_netrec_socketreceivefn)(void *x, t_binbuf *b); - -typedef struct _netrec -{ - t_object x_obj; - t_outlet *x_msgout; - t_outlet *x_connectout; - t_outlet *x_clientno; - t_outlet *x_connectionip; - t_symbol *x_host[MAX_CONNECT]; - t_int x_fd[MAX_CONNECT]; - t_int x_sock_fd; - int x_connectsocket; - int x_nconnections; - int x_udp; -} t_netrec; - -typedef struct _netrec_socketreceiver -{ - char *sr_inbuf; - int sr_inhead; - int sr_intail; - void *sr_owner; - int sr_udp; - t_netrec_socketnotifier sr_notifier; - t_netrec_socketreceivefn sr_socketreceivefn; -} t_netrec_socketreceiver; - -static t_netrec_socketreceiver *netrec_socketreceiver_new(void *owner, t_netrec_socketnotifier notifier, - t_netrec_socketreceivefn socketreceivefn, int udp) -{ - t_netrec_socketreceiver *x = (t_netrec_socketreceiver *)getbytes(sizeof(*x)); - x->sr_inhead = x->sr_intail = 0; - x->sr_owner = owner; - x->sr_notifier = notifier; - x->sr_socketreceivefn = socketreceivefn; - x->sr_udp = udp; - if (!(x->sr_inbuf = malloc(INBUFSIZE))) bug("t_netrec_socketreceiver"); - return (x); -} - - /* this is in a separately called subroutine so that the buffer isn't - sitting on the stack while the messages are getting passed. */ -static int netrec_socketreceiver_doread(t_netrec_socketreceiver *x) -{ - char messbuf[INBUFSIZE], *bp = messbuf; - int indx; - int inhead = x->sr_inhead; - int intail = x->sr_intail; - char *inbuf = x->sr_inbuf; - if (intail == inhead) return (0); - for (indx = intail; indx != inhead; indx = (indx+1)&(INBUFSIZE-1)) - { - char c = *bp++ = inbuf[indx]; - if (c == ';' && (!indx || inbuf[indx-1] != '\\')) - { - intail = (indx+1)&(INBUFSIZE-1); - binbuf_text(inbinbuf, messbuf, bp - messbuf); - x->sr_inhead = inhead; - x->sr_intail = intail; - return (1); - } - } - return (0); -} - -static void netrec_socketreceiver_getudp(t_netrec_socketreceiver *x, int fd) -{ - char buf[INBUFSIZE+1]; - int ret = recv(fd, buf, INBUFSIZE, 0); - if (ret < 0) - { - sys_sockerror("recv"); - sys_rmpollfn(fd); - sys_closesocket(fd); - } - else if (ret > 0) - { - buf[ret] = 0; -#if 0 - post("%s", buf); -#endif - if (buf[ret-1] != '\n') - { -#if 0 - buf[ret] = 0; - error("dropped bad buffer %s\n", buf); -#endif - } - else - { - char *semi = strchr(buf, ';'); - if (semi) - *semi = 0; - binbuf_text(inbinbuf, buf, strlen(buf)); - outlet_setstacklim(); - if (x->sr_socketreceivefn) - (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf); - else bug("netrec_socketreceiver_getudp"); - } - } -} - -static void netrec_socketreceiver_read(t_netrec_socketreceiver *x, int fd) -{ - if (x->sr_udp) /* UDP ("datagram") socket protocol */ - netrec_socketreceiver_getudp(x, fd); - else /* TCP ("streaming") socket protocol */ - { - char *semi; - int readto = - (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1); - int ret; - - t_netrec *y = x->sr_owner; - - y->x_sock_fd = fd; - - /* the input buffer might be full. If so, drop the whole thing */ - if (readto == x->sr_inhead) - { - fprintf(stderr, "netrec: dropped message"); - x->sr_inhead = x->sr_intail = 0; - readto = INBUFSIZE; - } - else - { - ret = recv(fd, x->sr_inbuf + x->sr_inhead, - readto - x->sr_inhead, 0); - if (ret < 0) - { - sys_sockerror("recv"); - if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); - sys_rmpollfn(fd); - sys_closesocket(fd); - } - else if (ret == 0) - { - post("netrec: connection closed on socket %d", fd); - if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); - sys_rmpollfn(fd); - sys_closesocket(fd); - } - else - { - x->sr_inhead += ret; - if (x->sr_inhead >= INBUFSIZE) x->sr_inhead = 0; - while (netrec_socketreceiver_doread(x)) - { - outlet_setstacklim(); - if (x->sr_socketreceivefn) - (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf); - else binbuf_eval(inbinbuf, 0, 0, 0); - } - } - } - } -} - -static void netrec_socketreceiver_free(t_netrec_socketreceiver *x) -{ - free(x->sr_inbuf); - freebytes(x, sizeof(*x)); -} - -/* ---------------- main netrec stuff --------------------- */ - -static void netrec_notify(t_netrec *x) -{ - int i, k; - /* remove connection from list */ - for(i = 0; i < x->x_nconnections; i++) - { - if(x->x_fd[i] == x->x_sock_fd) - { - x->x_nconnections--; - post("netrec: \"%s\" removed from list of clients", x->x_host[i]->s_name); - x->x_host[i] = NULL; /* delete entry */ - x->x_fd[i] = -1; - /* rearrange list now: move entries to close the gap */ - for(k = i; k < x->x_nconnections; k++) - { - x->x_host[k] = x->x_host[k + 1]; - x->x_fd[k] = x->x_fd[k + 1]; - } - } - } - outlet_float(x->x_connectout, x->x_nconnections); -} - -static void netrec_doit(void *z, t_binbuf *b) -{ - t_atom messbuf[1024]; - t_netrec *x = (t_netrec *)z; - int msg, natom = binbuf_getnatom(b); - t_atom *at = binbuf_getvec(b); - int i; - /* output clients IP and socket no */ - for(i = 0; i < x->x_nconnections; i++) - { - if(x->x_fd[i] == x->x_sock_fd) - { - outlet_symbol(x->x_connectionip, x->x_host[i]); - break; - } - } - outlet_float(x->x_clientno, x->x_sock_fd); - /* process data */ - for (msg = 0; msg < natom;) - { - int emsg; - for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA - && at[emsg].a_type != A_SEMI; emsg++); - - if (emsg > msg) - { - int ii; - for (ii = msg; ii < emsg; ii++) - if (at[ii].a_type == A_DOLLAR || at[ii].a_type == A_DOLLSYM) - { - pd_error(x, "netrec: got dollar sign in message"); - goto nodice; - } - if (at[msg].a_type == A_FLOAT) - { - if (emsg > msg + 1) - outlet_list(x->x_msgout, 0, emsg-msg, at + msg); - else outlet_float(x->x_msgout, at[msg].a_w.w_float); - } - else if (at[msg].a_type == A_SYMBOL) - outlet_anything(x->x_msgout, at[msg].a_w.w_symbol, - emsg-msg-1, at + msg + 1); - } - nodice: - msg = emsg + 1; - } -} - -static void netrec_connectpoll(t_netrec *x) -{ - struct sockaddr_in incomer_address; - int sockaddrl = (int) sizeof( struct sockaddr ); - int fd = accept(x->x_connectsocket, (struct sockaddr*)&incomer_address, &sockaddrl); - if (fd < 0) post("netrec: accept failed"); - else - { - t_netrec_socketreceiver *y = netrec_socketreceiver_new((void *)x, - (t_netrec_socketnotifier)netrec_notify, - (x->x_msgout ? netrec_doit : 0), 0); - sys_addpollfn(fd, (t_fdpollfn)netrec_socketreceiver_read, y); - x->x_nconnections++; - x->x_host[x->x_nconnections - 1] = gensym(inet_ntoa(incomer_address.sin_addr)); - x->x_fd[x->x_nconnections - 1] = fd; - - // outlet_symbol( x->x_connectionip, x->x_host[x->x_nconnections - 1]); - post("netrec: accepted connection from %s on socket %d", - x->x_host[x->x_nconnections - 1]->s_name, x->x_fd[x->x_nconnections - 1]); - outlet_float(x->x_connectout, x->x_nconnections); - } -} - -static void netrec_print(t_netrec *x) -{ - int i; - if(x->x_nconnections > 0) - { - post("netrec: %d open connections:", x->x_nconnections); - - for(i = 0; i < x->x_nconnections; i++) - { - post(" \"%s\" on socket %d", - x->x_host[i]->s_name, x->x_fd[i]); - } - } else post("netrec: no open connections"); -} - -static void *netrec_new(t_symbol *compatflag, - t_floatarg fportno, t_floatarg udpflag) -{ - t_netrec *x; - int i; - struct sockaddr_in server; - int sockfd, portno = fportno, udp = (udpflag != 0); - int old = !strcmp(compatflag->s_name , "old"); - /* create a socket */ - sockfd = socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0); -#if 1 - post("netrec: receive socket %d\n", sockfd); -#endif - if (sockfd < 0) - { - sys_sockerror("socket"); - return (0); - } - server.sin_family = AF_INET; - server.sin_addr.s_addr = INADDR_ANY; - -#ifdef IRIX - /* this seems to work only in IRIX but is unnecessary in - Linux. Not sure what NT needs in place of this. */ - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0) - post("setsockopt failed\n"); -#endif - - /* assign server port number */ - server.sin_port = htons((u_short)portno); - - /* name the socket */ - if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) - { - sys_sockerror("bind"); - sys_closesocket(sockfd); - return (0); - } - x = (t_netrec *)pd_new(netrec_class); - if (old) - { - /* old style, nonsecure version */ - x->x_msgout = 0; - } - else x->x_msgout = outlet_new(&x->x_obj, &s_anything); - - if (udp) /* datagram protocol */ - { - t_netrec_socketreceiver *y = netrec_socketreceiver_new((void *)x, - (t_netrec_socketnotifier)netrec_notify, - (x->x_msgout ? netrec_doit : 0), 1); - sys_addpollfn(sockfd, (t_fdpollfn)netrec_socketreceiver_read, y); - x->x_connectout = 0; - } - else /* streaming protocol */ - { - if (listen(sockfd, 5) < 0) - { - sys_sockerror("listen"); - sys_closesocket(sockfd); - sockfd = -1; - } - else - { - sys_addpollfn(sockfd, (t_fdpollfn)netrec_connectpoll, x); - x->x_connectout = outlet_new(&x->x_obj, &s_float); - x->x_clientno = outlet_new(&x->x_obj, &s_float); - x->x_connectionip = outlet_new(&x->x_obj, &s_symbol); - inbinbuf = binbuf_new(); - } - } - x->x_connectsocket = sockfd; - x->x_nconnections = 0; - x->x_udp = udp; - for(i = 0; i < MAX_CONNECT; i++)x->x_fd[i] = -1; - - return (x); -} - -static void netrec_free(t_netrec *x) -{ - /* LATER make me clean up open connections */ - if (x->x_connectsocket >= 0) - { - sys_rmpollfn(x->x_connectsocket); - sys_closesocket(x->x_connectsocket); - } - binbuf_free(inbinbuf); -} - -#ifndef MAXLIB -void netrec_setup(void) -{ - netrec_class = class_new(gensym("netrec"),(t_newmethod)netrec_new, (t_method)netrec_free, - sizeof(t_netrec), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFSYM, 0); - class_addmethod(netrec_class, (t_method)netrec_print, gensym("print"), 0); - - post(version); -} -#else -void maxlib_netrec_setup(void) -{ - netrec_class = class_new(gensym("maxlib_netrec"),(t_newmethod)netrec_new, (t_method)netrec_free, - sizeof(t_netrec), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFSYM, 0); - class_addcreator((t_newmethod)netrec_new, gensym("netrec"), A_DEFFLOAT, A_DEFFLOAT, A_DEFSYM, 0); - class_addmethod(netrec_class, (t_method)netrec_print, gensym("print"), 0); - class_sethelpsymbol(netrec_class, gensym("maxlib/netrec-help.pd")); -} -#endif +/* -------------------------- netrec ---------------------------------------- */ +/* */ +/* A 'netreceive' that tells the IP of the connecting netsend. */ +/* Written by Olaf Matthes */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include "s_stuff.h" +#include "m_imp.h" + +#include +#include +#include +#include +#include +#include +#include +#ifdef WIN32 +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#define SOCKET_ERROR -1 +#endif + +#define MAX_CONNECT 32 /* maximum number of connections */ +#define INBUFSIZE 4096 /* size of receiving data buffer */ + +static char *version = "netrec v0.1, written by Olaf Matthes "; + +/* ----------------------------- netrec ------------------------- */ + +static t_class *netrec_class; +static t_binbuf *inbinbuf; + +typedef void (*t_netrec_socketnotifier)(void *x); +typedef void (*t_netrec_socketreceivefn)(void *x, t_binbuf *b); + +typedef struct _netrec +{ + t_object x_obj; + t_outlet *x_msgout; + t_outlet *x_connectout; + t_outlet *x_clientno; + t_outlet *x_connectionip; + t_symbol *x_host[MAX_CONNECT]; + t_int x_fd[MAX_CONNECT]; + t_int x_sock_fd; + int x_connectsocket; + int x_nconnections; + int x_udp; +} t_netrec; + +typedef struct _netrec_socketreceiver +{ + char *sr_inbuf; + int sr_inhead; + int sr_intail; + void *sr_owner; + int sr_udp; + t_netrec_socketnotifier sr_notifier; + t_netrec_socketreceivefn sr_socketreceivefn; +} t_netrec_socketreceiver; + +static t_netrec_socketreceiver *netrec_socketreceiver_new(void *owner, t_netrec_socketnotifier notifier, + t_netrec_socketreceivefn socketreceivefn, int udp) +{ + t_netrec_socketreceiver *x = (t_netrec_socketreceiver *)getbytes(sizeof(*x)); + x->sr_inhead = x->sr_intail = 0; + x->sr_owner = owner; + x->sr_notifier = notifier; + x->sr_socketreceivefn = socketreceivefn; + x->sr_udp = udp; + if (!(x->sr_inbuf = malloc(INBUFSIZE))) bug("t_netrec_socketreceiver"); + return (x); +} + + /* this is in a separately called subroutine so that the buffer isn't + sitting on the stack while the messages are getting passed. */ +static int netrec_socketreceiver_doread(t_netrec_socketreceiver *x) +{ + char messbuf[INBUFSIZE], *bp = messbuf; + int indx; + int inhead = x->sr_inhead; + int intail = x->sr_intail; + char *inbuf = x->sr_inbuf; + if (intail == inhead) return (0); + for (indx = intail; indx != inhead; indx = (indx+1)&(INBUFSIZE-1)) + { + char c = *bp++ = inbuf[indx]; + if (c == ';' && (!indx || inbuf[indx-1] != '\\')) + { + intail = (indx+1)&(INBUFSIZE-1); + binbuf_text(inbinbuf, messbuf, bp - messbuf); + x->sr_inhead = inhead; + x->sr_intail = intail; + return (1); + } + } + return (0); +} + +static void netrec_socketreceiver_getudp(t_netrec_socketreceiver *x, int fd) +{ + char buf[INBUFSIZE+1]; + int ret = recv(fd, buf, INBUFSIZE, 0); + if (ret < 0) + { + sys_sockerror("recv"); + sys_rmpollfn(fd); + sys_closesocket(fd); + } + else if (ret > 0) + { + buf[ret] = 0; +#if 0 + post("%s", buf); +#endif + if (buf[ret-1] != '\n') + { +#if 0 + buf[ret] = 0; + error("dropped bad buffer %s\n", buf); +#endif + } + else + { + char *semi = strchr(buf, ';'); + if (semi) + *semi = 0; + binbuf_text(inbinbuf, buf, strlen(buf)); + outlet_setstacklim(); + if (x->sr_socketreceivefn) + (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf); + else bug("netrec_socketreceiver_getudp"); + } + } +} + +static void netrec_socketreceiver_read(t_netrec_socketreceiver *x, int fd) +{ + if (x->sr_udp) /* UDP ("datagram") socket protocol */ + netrec_socketreceiver_getudp(x, fd); + else /* TCP ("streaming") socket protocol */ + { + char *semi; + int readto = + (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1); + int ret; + + t_netrec *y = x->sr_owner; + + y->x_sock_fd = fd; + + /* the input buffer might be full. If so, drop the whole thing */ + if (readto == x->sr_inhead) + { + fprintf(stderr, "netrec: dropped message"); + x->sr_inhead = x->sr_intail = 0; + readto = INBUFSIZE; + } + else + { + ret = recv(fd, x->sr_inbuf + x->sr_inhead, + readto - x->sr_inhead, 0); + if (ret < 0) + { + sys_sockerror("recv"); + if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); + sys_rmpollfn(fd); + sys_closesocket(fd); + } + else if (ret == 0) + { + post("netrec: connection closed on socket %d", fd); + if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); + sys_rmpollfn(fd); + sys_closesocket(fd); + } + else + { + x->sr_inhead += ret; + if (x->sr_inhead >= INBUFSIZE) x->sr_inhead = 0; + while (netrec_socketreceiver_doread(x)) + { + outlet_setstacklim(); + if (x->sr_socketreceivefn) + (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf); + else binbuf_eval(inbinbuf, 0, 0, 0); + } + } + } + } +} + +static void netrec_socketreceiver_free(t_netrec_socketreceiver *x) +{ + free(x->sr_inbuf); + freebytes(x, sizeof(*x)); +} + +/* ---------------- main netrec stuff --------------------- */ + +static void netrec_notify(t_netrec *x) +{ + int i, k; + /* remove connection from list */ + for(i = 0; i < x->x_nconnections; i++) + { + if(x->x_fd[i] == x->x_sock_fd) + { + x->x_nconnections--; + post("netrec: \"%s\" removed from list of clients", x->x_host[i]->s_name); + x->x_host[i] = NULL; /* delete entry */ + x->x_fd[i] = -1; + /* rearrange list now: move entries to close the gap */ + for(k = i; k < x->x_nconnections; k++) + { + x->x_host[k] = x->x_host[k + 1]; + x->x_fd[k] = x->x_fd[k + 1]; + } + } + } + outlet_float(x->x_connectout, x->x_nconnections); +} + +static void netrec_doit(void *z, t_binbuf *b) +{ + t_atom messbuf[1024]; + t_netrec *x = (t_netrec *)z; + int msg, natom = binbuf_getnatom(b); + t_atom *at = binbuf_getvec(b); + int i; + /* output clients IP and socket no */ + for(i = 0; i < x->x_nconnections; i++) + { + if(x->x_fd[i] == x->x_sock_fd) + { + outlet_symbol(x->x_connectionip, x->x_host[i]); + break; + } + } + outlet_float(x->x_clientno, x->x_sock_fd); + /* process data */ + for (msg = 0; msg < natom;) + { + int emsg; + for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA + && at[emsg].a_type != A_SEMI; emsg++); + + if (emsg > msg) + { + int ii; + for (ii = msg; ii < emsg; ii++) + if (at[ii].a_type == A_DOLLAR || at[ii].a_type == A_DOLLSYM) + { + pd_error(x, "netrec: got dollar sign in message"); + goto nodice; + } + if (at[msg].a_type == A_FLOAT) + { + if (emsg > msg + 1) + outlet_list(x->x_msgout, 0, emsg-msg, at + msg); + else outlet_float(x->x_msgout, at[msg].a_w.w_float); + } + else if (at[msg].a_type == A_SYMBOL) + outlet_anything(x->x_msgout, at[msg].a_w.w_symbol, + emsg-msg-1, at + msg + 1); + } + nodice: + msg = emsg + 1; + } +} + +static void netrec_connectpoll(t_netrec *x) +{ + struct sockaddr_in incomer_address; + int sockaddrl = (int) sizeof( struct sockaddr ); + int fd = accept(x->x_connectsocket, (struct sockaddr*)&incomer_address, &sockaddrl); + if (fd < 0) post("netrec: accept failed"); + else + { + t_netrec_socketreceiver *y = netrec_socketreceiver_new((void *)x, + (t_netrec_socketnotifier)netrec_notify, + (x->x_msgout ? netrec_doit : 0), 0); + sys_addpollfn(fd, (t_fdpollfn)netrec_socketreceiver_read, y); + x->x_nconnections++; + x->x_host[x->x_nconnections - 1] = gensym(inet_ntoa(incomer_address.sin_addr)); + x->x_fd[x->x_nconnections - 1] = fd; + + // outlet_symbol( x->x_connectionip, x->x_host[x->x_nconnections - 1]); + post("netrec: accepted connection from %s on socket %d", + x->x_host[x->x_nconnections - 1]->s_name, x->x_fd[x->x_nconnections - 1]); + outlet_float(x->x_connectout, x->x_nconnections); + } +} + +static void netrec_print(t_netrec *x) +{ + int i; + if(x->x_nconnections > 0) + { + post("netrec: %d open connections:", x->x_nconnections); + + for(i = 0; i < x->x_nconnections; i++) + { + post(" \"%s\" on socket %d", + x->x_host[i]->s_name, x->x_fd[i]); + } + } else post("netrec: no open connections"); +} + +static void *netrec_new(t_symbol *compatflag, + t_floatarg fportno, t_floatarg udpflag) +{ + t_netrec *x; + int i; + struct sockaddr_in server; + int sockfd, portno = fportno, udp = (udpflag != 0); + int old = !strcmp(compatflag->s_name , "old"); + /* create a socket */ + sockfd = socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0); +#if 1 + post("netrec: receive socket %d\n", sockfd); +#endif + if (sockfd < 0) + { + sys_sockerror("socket"); + return (0); + } + server.sin_family = AF_INET; + server.sin_addr.s_addr = INADDR_ANY; + +#ifdef IRIX + /* this seems to work only in IRIX but is unnecessary in + Linux. Not sure what NT needs in place of this. */ + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0) + post("setsockopt failed\n"); +#endif + + /* assign server port number */ + server.sin_port = htons((u_short)portno); + + /* name the socket */ + if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) + { + sys_sockerror("bind"); + sys_closesocket(sockfd); + return (0); + } + x = (t_netrec *)pd_new(netrec_class); + if (old) + { + /* old style, nonsecure version */ + x->x_msgout = 0; + } + else x->x_msgout = outlet_new(&x->x_obj, &s_anything); + + if (udp) /* datagram protocol */ + { + t_netrec_socketreceiver *y = netrec_socketreceiver_new((void *)x, + (t_netrec_socketnotifier)netrec_notify, + (x->x_msgout ? netrec_doit : 0), 1); + sys_addpollfn(sockfd, (t_fdpollfn)netrec_socketreceiver_read, y); + x->x_connectout = 0; + } + else /* streaming protocol */ + { + if (listen(sockfd, 5) < 0) + { + sys_sockerror("listen"); + sys_closesocket(sockfd); + sockfd = -1; + } + else + { + sys_addpollfn(sockfd, (t_fdpollfn)netrec_connectpoll, x); + x->x_connectout = outlet_new(&x->x_obj, &s_float); + x->x_clientno = outlet_new(&x->x_obj, &s_float); + x->x_connectionip = outlet_new(&x->x_obj, &s_symbol); + inbinbuf = binbuf_new(); + } + } + x->x_connectsocket = sockfd; + x->x_nconnections = 0; + x->x_udp = udp; + for(i = 0; i < MAX_CONNECT; i++)x->x_fd[i] = -1; + + return (x); +} + +static void netrec_free(t_netrec *x) +{ + /* LATER make me clean up open connections */ + if (x->x_connectsocket >= 0) + { + sys_rmpollfn(x->x_connectsocket); + sys_closesocket(x->x_connectsocket); + } + binbuf_free(inbinbuf); +} + +#ifndef MAXLIB +void netrec_setup(void) +{ + netrec_class = class_new(gensym("netrec"),(t_newmethod)netrec_new, (t_method)netrec_free, + sizeof(t_netrec), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFSYM, 0); + class_addmethod(netrec_class, (t_method)netrec_print, gensym("print"), 0); + + logpost(NULL, 4, version); +} +#else +void maxlib_netrec_setup(void) +{ + netrec_class = class_new(gensym("maxlib_netrec"),(t_newmethod)netrec_new, (t_method)netrec_free, + sizeof(t_netrec), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFSYM, 0); + class_addcreator((t_newmethod)netrec_new, gensym("netrec"), A_DEFFLOAT, A_DEFFLOAT, A_DEFSYM, 0); + class_addmethod(netrec_class, (t_method)netrec_print, gensym("print"), 0); + class_sethelpsymbol(netrec_class, gensym("maxlib/netrec-help.pd")); +} +#endif diff --git a/netserver.c b/netserver.c index 196d29f..4fca399 100644 --- a/netserver.c +++ b/netserver.c @@ -1,670 +1,670 @@ -/* -------------------------- netserver ------------------------------------- */ -/* */ -/* A server for bidirectional communication from within Pd. */ -/* Allows to send back data to specific clients connected to the server. */ -/* Written by Olaf Matthes */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include "s_stuff.h" -#include "m_imp.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef WIN32 -#include -#include -#include -#else -#include -#include -#include -#include -#include -#include -#include -#include -#define SOCKET_ERROR -1 -#endif - -#define MAX_CONNECT 32 /* maximum number of connections */ -#define INBUFSIZE 4096 /* size of receiving data buffer */ - -/* message levels from syslog.h */ -#define LOG_EMERG 0 /* system is unusable */ -#define LOG_ALERT 1 /* action must be taken immediately */ -#define LOG_CRIT 2 /* critical conditions */ -#define LOG_ERR 3 /* error conditions */ -#define LOG_WARNING 4 /* warning conditions */ -#define LOG_NOTICE 5 /* normal but significant condition */ -#define LOG_INFO 6 /* informational */ -#define LOG_DEBUG 7 /* debug-level messages */ - -static char *version = - "netserver v0.2.hcs1 :: bidirectional communication for Pd\n" - " written by Olaf Matthes \n" - " syslogging by Hans-Christoph Steiner "; - -/* ----------------------------- netserver ------------------------- */ - -static t_class *netserver_class; -static t_binbuf *inbinbuf; - -typedef void (*t_netserver_socketnotifier)(void *x); -typedef void (*t_netserver_socketreceivefn)(void *x, t_binbuf *b); - -typedef struct _netserver -{ - t_object x_obj; - t_outlet *x_msgout; - t_outlet *x_connectout; - t_outlet *x_clientno; - t_outlet *x_connectionip; - t_symbol *x_host[MAX_CONNECT]; - t_int x_fd[MAX_CONNECT]; - t_int x_sock_fd; - t_int x_connectsocket; - t_int x_nconnections; -/* for syslog style logging priorities */ - t_int x_log_pri; -} t_netserver; - -typedef struct _netserver_socketreceiver -{ - char *sr_inbuf; - int sr_inhead; - int sr_intail; - void *sr_owner; - t_netserver_socketnotifier sr_notifier; - t_netserver_socketreceivefn sr_socketreceivefn; -} t_netserver_socketreceiver; - -static t_netserver_socketreceiver *netserver_socketreceiver_new(void *owner, t_netserver_socketnotifier notifier, - t_netserver_socketreceivefn socketreceivefn) -{ - t_netserver_socketreceiver *x = (t_netserver_socketreceiver *)getbytes(sizeof(*x)); - x->sr_inhead = x->sr_intail = 0; - x->sr_owner = owner; - x->sr_notifier = notifier; - x->sr_socketreceivefn = socketreceivefn; - if (!(x->sr_inbuf = malloc(INBUFSIZE))) bug("t_netserver_socketreceiver"); - return (x); -} - -/* this is in a separately called subroutine so that the buffer isn't - sitting on the stack while the messages are getting passed. */ -static int netserver_socketreceiver_doread(t_netserver_socketreceiver *x) -{ - char messbuf[INBUFSIZE], *bp = messbuf; - int indx; - int inhead = x->sr_inhead; - int intail = x->sr_intail; - char *inbuf = x->sr_inbuf; - if (intail == inhead) return (0); - for (indx = intail; indx != inhead; indx = (indx+1)&(INBUFSIZE-1)) - { - char c = *bp++ = inbuf[indx]; - if (c == ';' && (!indx || inbuf[indx-1] != '\\')) - { - intail = (indx+1)&(INBUFSIZE-1); - binbuf_text(inbinbuf, messbuf, bp - messbuf); - x->sr_inhead = inhead; - x->sr_intail = intail; - return (1); - } - } - return (0); -} - -static void netserver_socketreceiver_read(t_netserver_socketreceiver *x, int fd) -{ - char *semi; - int readto = (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1); - int ret; - - t_netserver *y = x->sr_owner; - - y->x_sock_fd = fd; - - /* the input buffer might be full. If so, drop the whole thing */ - if (readto == x->sr_inhead) - { - if (y->x_log_pri >= LOG_ERR) - post("netserver: dropped message"); - x->sr_inhead = x->sr_intail = 0; - readto = INBUFSIZE; - } - else - { - ret = recv(fd, x->sr_inbuf + x->sr_inhead, - readto - x->sr_inhead, 0); - if (ret < 0) - { - sys_sockerror("recv"); - if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); - sys_rmpollfn(fd); - sys_closesocket(fd); - } - else if (ret == 0) - { - if (y->x_log_pri >= LOG_NOTICE) - post("netserver: << connection closed on socket %d", fd); - if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); - sys_rmpollfn(fd); - sys_closesocket(fd); - } - else - { - x->sr_inhead += ret; - if (x->sr_inhead >= INBUFSIZE) x->sr_inhead = 0; - while (netserver_socketreceiver_doread(x)) - { - outlet_setstacklim(); - if (x->sr_socketreceivefn) - (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf); - else binbuf_eval(inbinbuf, 0, 0, 0); - } - } - } -} - -static void netserver_socketreceiver_free(t_netserver_socketreceiver *x) -{ - free(x->sr_inbuf); - freebytes(x, sizeof(*x)); -} - -/* ---------------- main netserver (send) stuff --------------------- */ - -/* send message to client using socket number */ -static void netserver_send(t_netserver *x, t_symbol *s, int argc, t_atom *argv) -{ - int sockfd, client = -1, i; - if(x->x_nconnections < 0) - { - if (x->x_log_pri >= LOG_WARNING) - post("netserver: no clients connected"); - return; - } - if(argc < 2) - { - if (x->x_log_pri >= LOG_WARNING) - post("netserver: nothing to send"); - return; - } - /* get socket number of connection (first element in list) */ - if(argv[0].a_type == A_FLOAT) - { - sockfd = atom_getfloatarg(0, argc, argv); - for(i = 0; i < x->x_nconnections; i++) /* check if connection exists */ - { - if(x->x_fd[i] == sockfd) - { - client = i; /* the client we're sending to */ - break; - } - } - if(client == -1) - { - if (x->x_log_pri >= LOG_CRIT) - post("netserver: no connection on socket %d", sockfd); - return; - } - } - else - { - if (x->x_log_pri >= LOG_CRIT) - post("netserver: no socket specified"); - return; - } - /* process & send data */ - if(sockfd > 0) - { - t_binbuf *b = binbuf_new(); - char *buf, *bp; - int length, sent; - t_atom at; - binbuf_add(b, argc - 1, argv + 1); /* skip first element */ - SETSEMI(&at); - binbuf_add(b, 1, &at); - binbuf_gettext(b, &buf, &length); - - if (x->x_log_pri >= LOG_DEBUG) - { - post("netserver: sending data to client %d on socket %d", client + 1, sockfd); - post("netserver: sending \"%s\"", buf); - } - - for (bp = buf, sent = 0; sent < length;) - { - static double lastwarntime; - static double pleasewarn; - double timebefore = clock_getlogicaltime(); - int res = send(sockfd, buf, length-sent, 0); - double timeafter = clock_getlogicaltime(); - int late = (timeafter - timebefore > 0.005); - if (late || pleasewarn) - { - if (timeafter > lastwarntime + 2) - { - if (x->x_log_pri >= LOG_WARNING) - post("netserver blocked %d msec", - (int)(1000 * ((timeafter - timebefore) + pleasewarn))); - pleasewarn = 0; - lastwarntime = timeafter; - } - else if (late) pleasewarn += timeafter - timebefore; - } - if (res <= 0) - { - sys_sockerror("netserver"); - if (x->x_log_pri >= LOG_ERR) - post("netserver: could not send data to client"); - break; - } - else - { - sent += res; - bp += res; - } - } - t_freebytes(buf, length); - binbuf_free(b); - } - else if (x->x_log_pri >= LOG_CRIT) - post("netserver: not a valid socket number (%d)", sockfd); -} - -/* send message to client using client number - note that the client numbers might change in case a client disconnects! */ -static void netserver_client_send(t_netserver *x, t_symbol *s, int argc, t_atom *argv) -{ - int sockfd, client; - if(x->x_nconnections < 0) - { - if (x->x_log_pri >= LOG_WARNING) - post("netserver: no clients connected"); - return; - } - if(argc < 2) - { - if (x->x_log_pri >= LOG_WARNING) - post("netserver: nothing to send"); - return; - } - /* get number of client (first element in list) */ - if(argv[0].a_type == A_FLOAT) - client = atom_getfloatarg(0, argc, argv); - else - { - if (x->x_log_pri >= LOG_WARNING) - post("netserver: no client specified"); - return; - } - sockfd = x->x_fd[client - 1]; /* get socket number for that client */ - - /* process & send data */ - if(sockfd > 0) - { - t_binbuf *b = binbuf_new(); - char *buf, *bp; - int length, sent; - t_atom at; - binbuf_add(b, argc - 1, argv + 1); /* skip first element */ - SETSEMI(&at); - binbuf_add(b, 1, &at); - binbuf_gettext(b, &buf, &length); - - if (x->x_log_pri >= LOG_DEBUG) - { - post("netserver: sending data to client %d on socket %d", client, sockfd); - post("netserver: >> sending \"%s\"", buf); - } - - for (bp = buf, sent = 0; sent < length;) - { - static double lastwarntime; - static double pleasewarn; - double timebefore = clock_getlogicaltime(); - int res = send(sockfd, buf, length-sent, 0); - double timeafter = clock_getlogicaltime(); - int late = (timeafter - timebefore > 0.005); - if (late || pleasewarn) - { - if (timeafter > lastwarntime + 2) - { - if (x->x_log_pri >= LOG_WARNING) - post("netserver blocked %d msec", - (int)(1000 * ((timeafter - timebefore) + pleasewarn))); - pleasewarn = 0; - lastwarntime = timeafter; - } - else if (late) pleasewarn += timeafter - timebefore; - } - if (res <= 0) - { - sys_sockerror("netserver"); - if (x->x_log_pri >= LOG_ERR) - post("netserver: could not send data to cient"); - break; - } - else - { - sent += res; - bp += res; - } - } - t_freebytes(buf, length); - binbuf_free(b); - } - else if (x->x_log_pri >= LOG_CRIT) - post("netserver: not a valid socket number (%d)", sockfd); -} - -/* broadcasts a message to all connected clients */ -static void netserver_broadcast(t_netserver *x, t_symbol *s, int argc, t_atom *argv) -{ - int i, client = x->x_nconnections; /* number of clients to send to */ - t_atom at[256]; - for(i = 0; i < argc; i++) - { - at[i + 1] = argv[i]; - } - argc++; - /* enumerate through the clients and send each the message */ - while(client--) - { - SETFLOAT(at, client + 1); /* prepend number of client */ - netserver_client_send(x, s, argc, at); - } -} - - -/* ---------------- main netserver (receive) stuff --------------------- */ - -static void netserver_notify(t_netserver *x) -{ - int i, k; - /* remove connection from list */ - for(i = 0; i < x->x_nconnections; i++) - { - if(x->x_fd[i] == x->x_sock_fd) - { - x->x_nconnections--; - if (x->x_log_pri >= LOG_NOTICE) - post("netserver: \"%s\" removed from list of clients", x->x_host[i]->s_name); - x->x_host[i] = NULL; /* delete entry */ - x->x_fd[i] = -1; - /* rearrange list now: move entries to close the gap */ - for(k = i; k < x->x_nconnections; k++) - { - x->x_host[k] = x->x_host[k + 1]; - x->x_fd[k] = x->x_fd[k + 1]; - } - } - } - outlet_float(x->x_connectout, x->x_nconnections); -} - -static void netserver_doit(void *z, t_binbuf *b) -{ - t_atom messbuf[1024]; - t_netserver *x = (t_netserver *)z; - int msg, natom = binbuf_getnatom(b); - t_atom *at = binbuf_getvec(b); - int i; - /* output clients IP and socket no. */ - for(i = 0; i < x->x_nconnections; i++) /* search for corresponding IP */ - { - if(x->x_fd[i] == x->x_sock_fd) - { - outlet_symbol(x->x_connectionip, x->x_host[i]); - break; - } - } - outlet_float(x->x_clientno, x->x_sock_fd); /* the socket number */ - /* process data */ - for (msg = 0; msg < natom;) - { - int emsg; - for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA - && at[emsg].a_type != A_SEMI; emsg++); - - if (emsg > msg) - { - int ii; - for (ii = msg; ii < emsg; ii++) - if (at[ii].a_type == A_DOLLAR || at[ii].a_type == A_DOLLSYM) - { - pd_error(x, "netserver: got dollar sign in message"); - goto nodice; - } - if (at[msg].a_type == A_FLOAT) - { - if (emsg > msg + 1) - outlet_list(x->x_msgout, 0, emsg-msg, at + msg); - else outlet_float(x->x_msgout, at[msg].a_w.w_float); - } - else if (at[msg].a_type == A_SYMBOL) - outlet_anything(x->x_msgout, at[msg].a_w.w_symbol, - emsg-msg-1, at + msg + 1); - } - nodice: - msg = emsg + 1; - } -} - -static void netserver_connectpoll(t_netserver *x) -{ - struct sockaddr_in incomer_address; - int sockaddrl = (int) sizeof( struct sockaddr ); - int fd = accept(x->x_connectsocket, (struct sockaddr*)&incomer_address, &sockaddrl); - if (fd < 0) post("netserver: accept failed"); - else - { - t_netserver_socketreceiver *y = netserver_socketreceiver_new((void *)x, - (t_netserver_socketnotifier)netserver_notify, - (x->x_msgout ? netserver_doit : 0)); - sys_addpollfn(fd, (t_fdpollfn)netserver_socketreceiver_read, y); - x->x_nconnections++; - x->x_host[x->x_nconnections - 1] = gensym(inet_ntoa(incomer_address.sin_addr)); - x->x_fd[x->x_nconnections - 1] = fd; - - if (x->x_log_pri >= LOG_NOTICE) - post("netserver: ** accepted connection from %s on socket %d", - x->x_host[x->x_nconnections - 1]->s_name, x->x_fd[x->x_nconnections - 1]); - outlet_float(x->x_connectout, x->x_nconnections); - } -} - -static void netserver_print(t_netserver *x) -{ - int i; - if(x->x_nconnections > 0) - { - post("netserver: %d open connections:", x->x_nconnections); - - for(i = 0; i < x->x_nconnections; i++) - { - post(" \"%s\" on socket %d", - x->x_host[i]->s_name, x->x_fd[i]); - } - } else post("netserver: no open connections"); -} - -static void netserver_emerg(t_netserver *x) -{ - x->x_log_pri = LOG_EMERG; -} -static void netserver_alert(t_netserver *x) -{ - x->x_log_pri = LOG_ALERT; -} -static void netserver_crit(t_netserver *x) -{ - x->x_log_pri = LOG_CRIT; -} -static void netserver_err(t_netserver *x) -{ - x->x_log_pri = LOG_ERR; -} -static void netserver_warning(t_netserver *x) -{ - x->x_log_pri = LOG_WARNING; -} -static void netserver_notice(t_netserver *x) -{ - x->x_log_pri = LOG_NOTICE; -} -static void netserver_info(t_netserver *x) -{ - x->x_log_pri = LOG_INFO; -} -static void netserver_debug(t_netserver *x) -{ - x->x_log_pri = LOG_DEBUG; -} - -static void *netserver_new(t_floatarg fportno) -{ - t_netserver *x; - int i; - struct sockaddr_in server; - int sockfd, portno = fportno; - - x = (t_netserver *)pd_new(netserver_class); -/* set default debug message level */ - x->x_log_pri = LOG_ERR; -/* create a socket */ - sockfd = socket(AF_INET, SOCK_STREAM, 0); - if (x->x_log_pri >= LOG_NOTICE) - post("netserver: receive socket %d", sockfd); - if (sockfd < 0) - { - sys_sockerror("socket"); - return (0); - } - server.sin_family = AF_INET; - server.sin_addr.s_addr = INADDR_ANY; - -#ifdef IRIX - /* this seems to work only in IRIX but is unnecessary in - Linux. Not sure what NT needs in place of this. */ - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0) - post("setsockopt failed\n"); -#endif - - /* assign server port number */ - server.sin_port = htons((u_short)portno); - - /* name the socket */ - if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) - { - sys_sockerror("bind"); - sys_closesocket(sockfd); - return (0); - } - x->x_msgout = outlet_new(&x->x_obj, &s_anything); - - /* streaming protocol */ - if (listen(sockfd, 5) < 0) - { - sys_sockerror("listen"); - sys_closesocket(sockfd); - sockfd = -1; - } - else - { - sys_addpollfn(sockfd, (t_fdpollfn)netserver_connectpoll, x); - x->x_connectout = outlet_new(&x->x_obj, &s_float); - x->x_clientno = outlet_new(&x->x_obj, &s_float); - x->x_connectionip = outlet_new(&x->x_obj, &s_symbol); - inbinbuf = binbuf_new(); - } - x->x_connectsocket = sockfd; - x->x_nconnections = 0; - for(i = 0; i < MAX_CONNECT; i++)x->x_fd[i] = -1; - - return (x); -} - -static void netserver_free(t_netserver *x) -{ - int i; - for(i = 0; i < x->x_nconnections; i++) - { - sys_rmpollfn(x->x_fd[i]); - sys_closesocket(x->x_fd[i]); - } - if (x->x_connectsocket >= 0) - { - sys_rmpollfn(x->x_connectsocket); - sys_closesocket(x->x_connectsocket); - } - binbuf_free(inbinbuf); -} - -#ifndef MAXLIB -void netserver_setup(void) -{ - netserver_class = class_new(gensym("netserver"),(t_newmethod)netserver_new, (t_method)netserver_free, - sizeof(t_netserver), 0, A_DEFFLOAT, 0); - class_addmethod(netserver_class, (t_method)netserver_print, gensym("print"), 0); - class_addmethod(netserver_class, (t_method)netserver_send, gensym("send"), A_GIMME, 0); - class_addmethod(netserver_class, (t_method)netserver_client_send, gensym("client"), A_GIMME, 0); - class_addmethod(netserver_class, (t_method)netserver_broadcast, gensym("broadcast"), A_GIMME, 0); -/* syslog log level messages */ - class_addmethod(netserver_class, (t_method)netserver_emerg, gensym("emerg"), 0); - class_addmethod(netserver_class, (t_method)netserver_emerg, gensym("emergency"), 0); - class_addmethod(netserver_class, (t_method)netserver_alert, gensym("alert"), 0); - class_addmethod(netserver_class, (t_method)netserver_crit, gensym("crit"), 0); - class_addmethod(netserver_class, (t_method)netserver_crit, gensym("critical"), 0); - class_addmethod(netserver_class, (t_method)netserver_err, gensym("err"), 0); - class_addmethod(netserver_class, (t_method)netserver_err, gensym("error"), 0); - class_addmethod(netserver_class, (t_method)netserver_err, gensym("quiet"), 0); - class_addmethod(netserver_class, (t_method)netserver_warning, gensym("warning"), 0); - class_addmethod(netserver_class, (t_method)netserver_notice, gensym("notice"), 0); - class_addmethod(netserver_class, (t_method)netserver_info, gensym("info"), 0); - class_addmethod(netserver_class, (t_method)netserver_info, gensym("verbose"), 0); - class_addmethod(netserver_class, (t_method)netserver_debug, gensym("debug"), 0); - - - post(version); -} -#else -void maxlib_netserver_setup(void) -{ - netserver_class = class_new(gensym("maxlib_netserver"),(t_newmethod)netserver_new, (t_method)netserver_free, - sizeof(t_netserver), 0, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)netserver_new, gensym("netserver"), A_DEFFLOAT, 0); - class_addmethod(netserver_class, (t_method)netserver_print, gensym("print"), 0); - class_addmethod(netserver_class, (t_method)netserver_send, gensym("send"), A_GIMME, 0); - class_addmethod(netserver_class, (t_method)netserver_client_send, gensym("client"), A_GIMME, 0); - class_addmethod(netserver_class, (t_method)netserver_broadcast, gensym("broadcast"), A_GIMME, 0); - class_sethelpsymbol(netserver_class, gensym("maxlib/netserver-help.pd")); -} -#endif +/* -------------------------- netserver ------------------------------------- */ +/* */ +/* A server for bidirectional communication from within Pd. */ +/* Allows to send back data to specific clients connected to the server. */ +/* Written by Olaf Matthes */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include "s_stuff.h" +#include "m_imp.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef WIN32 +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#define SOCKET_ERROR -1 +#endif + +#define MAX_CONNECT 32 /* maximum number of connections */ +#define INBUFSIZE 4096 /* size of receiving data buffer */ + +/* message levels from syslog.h */ +#define LOG_EMERG 0 /* system is unusable */ +#define LOG_ALERT 1 /* action must be taken immediately */ +#define LOG_CRIT 2 /* critical conditions */ +#define LOG_ERR 3 /* error conditions */ +#define LOG_WARNING 4 /* warning conditions */ +#define LOG_NOTICE 5 /* normal but significant condition */ +#define LOG_INFO 6 /* informational */ +#define LOG_DEBUG 7 /* debug-level messages */ + +static char *version = + "netserver v0.2.hcs1 :: bidirectional communication for Pd\n" + " written by Olaf Matthes \n" + " syslogging by Hans-Christoph Steiner "; + +/* ----------------------------- netserver ------------------------- */ + +static t_class *netserver_class; +static t_binbuf *inbinbuf; + +typedef void (*t_netserver_socketnotifier)(void *x); +typedef void (*t_netserver_socketreceivefn)(void *x, t_binbuf *b); + +typedef struct _netserver +{ + t_object x_obj; + t_outlet *x_msgout; + t_outlet *x_connectout; + t_outlet *x_clientno; + t_outlet *x_connectionip; + t_symbol *x_host[MAX_CONNECT]; + t_int x_fd[MAX_CONNECT]; + t_int x_sock_fd; + t_int x_connectsocket; + t_int x_nconnections; +/* for syslog style logging priorities */ + t_int x_log_pri; +} t_netserver; + +typedef struct _netserver_socketreceiver +{ + char *sr_inbuf; + int sr_inhead; + int sr_intail; + void *sr_owner; + t_netserver_socketnotifier sr_notifier; + t_netserver_socketreceivefn sr_socketreceivefn; +} t_netserver_socketreceiver; + +static t_netserver_socketreceiver *netserver_socketreceiver_new(void *owner, t_netserver_socketnotifier notifier, + t_netserver_socketreceivefn socketreceivefn) +{ + t_netserver_socketreceiver *x = (t_netserver_socketreceiver *)getbytes(sizeof(*x)); + x->sr_inhead = x->sr_intail = 0; + x->sr_owner = owner; + x->sr_notifier = notifier; + x->sr_socketreceivefn = socketreceivefn; + if (!(x->sr_inbuf = malloc(INBUFSIZE))) bug("t_netserver_socketreceiver"); + return (x); +} + +/* this is in a separately called subroutine so that the buffer isn't + sitting on the stack while the messages are getting passed. */ +static int netserver_socketreceiver_doread(t_netserver_socketreceiver *x) +{ + char messbuf[INBUFSIZE], *bp = messbuf; + int indx; + int inhead = x->sr_inhead; + int intail = x->sr_intail; + char *inbuf = x->sr_inbuf; + if (intail == inhead) return (0); + for (indx = intail; indx != inhead; indx = (indx+1)&(INBUFSIZE-1)) + { + char c = *bp++ = inbuf[indx]; + if (c == ';' && (!indx || inbuf[indx-1] != '\\')) + { + intail = (indx+1)&(INBUFSIZE-1); + binbuf_text(inbinbuf, messbuf, bp - messbuf); + x->sr_inhead = inhead; + x->sr_intail = intail; + return (1); + } + } + return (0); +} + +static void netserver_socketreceiver_read(t_netserver_socketreceiver *x, int fd) +{ + char *semi; + int readto = (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1); + int ret; + + t_netserver *y = x->sr_owner; + + y->x_sock_fd = fd; + + /* the input buffer might be full. If so, drop the whole thing */ + if (readto == x->sr_inhead) + { + if (y->x_log_pri >= LOG_ERR) + post("netserver: dropped message"); + x->sr_inhead = x->sr_intail = 0; + readto = INBUFSIZE; + } + else + { + ret = recv(fd, x->sr_inbuf + x->sr_inhead, + readto - x->sr_inhead, 0); + if (ret < 0) + { + sys_sockerror("recv"); + if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); + sys_rmpollfn(fd); + sys_closesocket(fd); + } + else if (ret == 0) + { + if (y->x_log_pri >= LOG_NOTICE) + post("netserver: << connection closed on socket %d", fd); + if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner); + sys_rmpollfn(fd); + sys_closesocket(fd); + } + else + { + x->sr_inhead += ret; + if (x->sr_inhead >= INBUFSIZE) x->sr_inhead = 0; + while (netserver_socketreceiver_doread(x)) + { + outlet_setstacklim(); + if (x->sr_socketreceivefn) + (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf); + else binbuf_eval(inbinbuf, 0, 0, 0); + } + } + } +} + +static void netserver_socketreceiver_free(t_netserver_socketreceiver *x) +{ + free(x->sr_inbuf); + freebytes(x, sizeof(*x)); +} + +/* ---------------- main netserver (send) stuff --------------------- */ + +/* send message to client using socket number */ +static void netserver_send(t_netserver *x, t_symbol *s, int argc, t_atom *argv) +{ + int sockfd, client = -1, i; + if(x->x_nconnections < 0) + { + if (x->x_log_pri >= LOG_WARNING) + post("netserver: no clients connected"); + return; + } + if(argc < 2) + { + if (x->x_log_pri >= LOG_WARNING) + post("netserver: nothing to send"); + return; + } + /* get socket number of connection (first element in list) */ + if(argv[0].a_type == A_FLOAT) + { + sockfd = atom_getfloatarg(0, argc, argv); + for(i = 0; i < x->x_nconnections; i++) /* check if connection exists */ + { + if(x->x_fd[i] == sockfd) + { + client = i; /* the client we're sending to */ + break; + } + } + if(client == -1) + { + if (x->x_log_pri >= LOG_CRIT) + post("netserver: no connection on socket %d", sockfd); + return; + } + } + else + { + if (x->x_log_pri >= LOG_CRIT) + post("netserver: no socket specified"); + return; + } + /* process & send data */ + if(sockfd > 0) + { + t_binbuf *b = binbuf_new(); + char *buf, *bp; + int length, sent; + t_atom at; + binbuf_add(b, argc - 1, argv + 1); /* skip first element */ + SETSEMI(&at); + binbuf_add(b, 1, &at); + binbuf_gettext(b, &buf, &length); + + if (x->x_log_pri >= LOG_DEBUG) + { + post("netserver: sending data to client %d on socket %d", client + 1, sockfd); + post("netserver: sending \"%s\"", buf); + } + + for (bp = buf, sent = 0; sent < length;) + { + static double lastwarntime; + static double pleasewarn; + double timebefore = clock_getlogicaltime(); + int res = send(sockfd, buf, length-sent, 0); + double timeafter = clock_getlogicaltime(); + int late = (timeafter - timebefore > 0.005); + if (late || pleasewarn) + { + if (timeafter > lastwarntime + 2) + { + if (x->x_log_pri >= LOG_WARNING) + post("netserver blocked %d msec", + (int)(1000 * ((timeafter - timebefore) + pleasewarn))); + pleasewarn = 0; + lastwarntime = timeafter; + } + else if (late) pleasewarn += timeafter - timebefore; + } + if (res <= 0) + { + sys_sockerror("netserver"); + if (x->x_log_pri >= LOG_ERR) + post("netserver: could not send data to client"); + break; + } + else + { + sent += res; + bp += res; + } + } + t_freebytes(buf, length); + binbuf_free(b); + } + else if (x->x_log_pri >= LOG_CRIT) + post("netserver: not a valid socket number (%d)", sockfd); +} + +/* send message to client using client number + note that the client numbers might change in case a client disconnects! */ +static void netserver_client_send(t_netserver *x, t_symbol *s, int argc, t_atom *argv) +{ + int sockfd, client; + if(x->x_nconnections < 0) + { + if (x->x_log_pri >= LOG_WARNING) + post("netserver: no clients connected"); + return; + } + if(argc < 2) + { + if (x->x_log_pri >= LOG_WARNING) + post("netserver: nothing to send"); + return; + } + /* get number of client (first element in list) */ + if(argv[0].a_type == A_FLOAT) + client = atom_getfloatarg(0, argc, argv); + else + { + if (x->x_log_pri >= LOG_WARNING) + post("netserver: no client specified"); + return; + } + sockfd = x->x_fd[client - 1]; /* get socket number for that client */ + + /* process & send data */ + if(sockfd > 0) + { + t_binbuf *b = binbuf_new(); + char *buf, *bp; + int length, sent; + t_atom at; + binbuf_add(b, argc - 1, argv + 1); /* skip first element */ + SETSEMI(&at); + binbuf_add(b, 1, &at); + binbuf_gettext(b, &buf, &length); + + if (x->x_log_pri >= LOG_DEBUG) + { + post("netserver: sending data to client %d on socket %d", client, sockfd); + post("netserver: >> sending \"%s\"", buf); + } + + for (bp = buf, sent = 0; sent < length;) + { + static double lastwarntime; + static double pleasewarn; + double timebefore = clock_getlogicaltime(); + int res = send(sockfd, buf, length-sent, 0); + double timeafter = clock_getlogicaltime(); + int late = (timeafter - timebefore > 0.005); + if (late || pleasewarn) + { + if (timeafter > lastwarntime + 2) + { + if (x->x_log_pri >= LOG_WARNING) + post("netserver blocked %d msec", + (int)(1000 * ((timeafter - timebefore) + pleasewarn))); + pleasewarn = 0; + lastwarntime = timeafter; + } + else if (late) pleasewarn += timeafter - timebefore; + } + if (res <= 0) + { + sys_sockerror("netserver"); + if (x->x_log_pri >= LOG_ERR) + post("netserver: could not send data to cient"); + break; + } + else + { + sent += res; + bp += res; + } + } + t_freebytes(buf, length); + binbuf_free(b); + } + else if (x->x_log_pri >= LOG_CRIT) + post("netserver: not a valid socket number (%d)", sockfd); +} + +/* broadcasts a message to all connected clients */ +static void netserver_broadcast(t_netserver *x, t_symbol *s, int argc, t_atom *argv) +{ + int i, client = x->x_nconnections; /* number of clients to send to */ + t_atom at[256]; + for(i = 0; i < argc; i++) + { + at[i + 1] = argv[i]; + } + argc++; + /* enumerate through the clients and send each the message */ + while(client--) + { + SETFLOAT(at, client + 1); /* prepend number of client */ + netserver_client_send(x, s, argc, at); + } +} + + +/* ---------------- main netserver (receive) stuff --------------------- */ + +static void netserver_notify(t_netserver *x) +{ + int i, k; + /* remove connection from list */ + for(i = 0; i < x->x_nconnections; i++) + { + if(x->x_fd[i] == x->x_sock_fd) + { + x->x_nconnections--; + if (x->x_log_pri >= LOG_NOTICE) + post("netserver: \"%s\" removed from list of clients", x->x_host[i]->s_name); + x->x_host[i] = NULL; /* delete entry */ + x->x_fd[i] = -1; + /* rearrange list now: move entries to close the gap */ + for(k = i; k < x->x_nconnections; k++) + { + x->x_host[k] = x->x_host[k + 1]; + x->x_fd[k] = x->x_fd[k + 1]; + } + } + } + outlet_float(x->x_connectout, x->x_nconnections); +} + +static void netserver_doit(void *z, t_binbuf *b) +{ + t_atom messbuf[1024]; + t_netserver *x = (t_netserver *)z; + int msg, natom = binbuf_getnatom(b); + t_atom *at = binbuf_getvec(b); + int i; + /* output clients IP and socket no. */ + for(i = 0; i < x->x_nconnections; i++) /* search for corresponding IP */ + { + if(x->x_fd[i] == x->x_sock_fd) + { + outlet_symbol(x->x_connectionip, x->x_host[i]); + break; + } + } + outlet_float(x->x_clientno, x->x_sock_fd); /* the socket number */ + /* process data */ + for (msg = 0; msg < natom;) + { + int emsg; + for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA + && at[emsg].a_type != A_SEMI; emsg++); + + if (emsg > msg) + { + int ii; + for (ii = msg; ii < emsg; ii++) + if (at[ii].a_type == A_DOLLAR || at[ii].a_type == A_DOLLSYM) + { + pd_error(x, "netserver: got dollar sign in message"); + goto nodice; + } + if (at[msg].a_type == A_FLOAT) + { + if (emsg > msg + 1) + outlet_list(x->x_msgout, 0, emsg-msg, at + msg); + else outlet_float(x->x_msgout, at[msg].a_w.w_float); + } + else if (at[msg].a_type == A_SYMBOL) + outlet_anything(x->x_msgout, at[msg].a_w.w_symbol, + emsg-msg-1, at + msg + 1); + } + nodice: + msg = emsg + 1; + } +} + +static void netserver_connectpoll(t_netserver *x) +{ + struct sockaddr_in incomer_address; + int sockaddrl = (int) sizeof( struct sockaddr ); + int fd = accept(x->x_connectsocket, (struct sockaddr*)&incomer_address, &sockaddrl); + if (fd < 0) post("netserver: accept failed"); + else + { + t_netserver_socketreceiver *y = netserver_socketreceiver_new((void *)x, + (t_netserver_socketnotifier)netserver_notify, + (x->x_msgout ? netserver_doit : 0)); + sys_addpollfn(fd, (t_fdpollfn)netserver_socketreceiver_read, y); + x->x_nconnections++; + x->x_host[x->x_nconnections - 1] = gensym(inet_ntoa(incomer_address.sin_addr)); + x->x_fd[x->x_nconnections - 1] = fd; + + if (x->x_log_pri >= LOG_NOTICE) + post("netserver: ** accepted connection from %s on socket %d", + x->x_host[x->x_nconnections - 1]->s_name, x->x_fd[x->x_nconnections - 1]); + outlet_float(x->x_connectout, x->x_nconnections); + } +} + +static void netserver_print(t_netserver *x) +{ + int i; + if(x->x_nconnections > 0) + { + post("netserver: %d open connections:", x->x_nconnections); + + for(i = 0; i < x->x_nconnections; i++) + { + post(" \"%s\" on socket %d", + x->x_host[i]->s_name, x->x_fd[i]); + } + } else post("netserver: no open connections"); +} + +static void netserver_emerg(t_netserver *x) +{ + x->x_log_pri = LOG_EMERG; +} +static void netserver_alert(t_netserver *x) +{ + x->x_log_pri = LOG_ALERT; +} +static void netserver_crit(t_netserver *x) +{ + x->x_log_pri = LOG_CRIT; +} +static void netserver_err(t_netserver *x) +{ + x->x_log_pri = LOG_ERR; +} +static void netserver_warning(t_netserver *x) +{ + x->x_log_pri = LOG_WARNING; +} +static void netserver_notice(t_netserver *x) +{ + x->x_log_pri = LOG_NOTICE; +} +static void netserver_info(t_netserver *x) +{ + x->x_log_pri = LOG_INFO; +} +static void netserver_debug(t_netserver *x) +{ + x->x_log_pri = LOG_DEBUG; +} + +static void *netserver_new(t_floatarg fportno) +{ + t_netserver *x; + int i; + struct sockaddr_in server; + int sockfd, portno = fportno; + + x = (t_netserver *)pd_new(netserver_class); +/* set default debug message level */ + x->x_log_pri = LOG_ERR; +/* create a socket */ + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (x->x_log_pri >= LOG_NOTICE) + post("netserver: receive socket %d", sockfd); + if (sockfd < 0) + { + sys_sockerror("socket"); + return (0); + } + server.sin_family = AF_INET; + server.sin_addr.s_addr = INADDR_ANY; + +#ifdef IRIX + /* this seems to work only in IRIX but is unnecessary in + Linux. Not sure what NT needs in place of this. */ + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0) + post("setsockopt failed\n"); +#endif + + /* assign server port number */ + server.sin_port = htons((u_short)portno); + + /* name the socket */ + if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) + { + sys_sockerror("bind"); + sys_closesocket(sockfd); + return (0); + } + x->x_msgout = outlet_new(&x->x_obj, &s_anything); + + /* streaming protocol */ + if (listen(sockfd, 5) < 0) + { + sys_sockerror("listen"); + sys_closesocket(sockfd); + sockfd = -1; + } + else + { + sys_addpollfn(sockfd, (t_fdpollfn)netserver_connectpoll, x); + x->x_connectout = outlet_new(&x->x_obj, &s_float); + x->x_clientno = outlet_new(&x->x_obj, &s_float); + x->x_connectionip = outlet_new(&x->x_obj, &s_symbol); + inbinbuf = binbuf_new(); + } + x->x_connectsocket = sockfd; + x->x_nconnections = 0; + for(i = 0; i < MAX_CONNECT; i++)x->x_fd[i] = -1; + + return (x); +} + +static void netserver_free(t_netserver *x) +{ + int i; + for(i = 0; i < x->x_nconnections; i++) + { + sys_rmpollfn(x->x_fd[i]); + sys_closesocket(x->x_fd[i]); + } + if (x->x_connectsocket >= 0) + { + sys_rmpollfn(x->x_connectsocket); + sys_closesocket(x->x_connectsocket); + } + binbuf_free(inbinbuf); +} + +#ifndef MAXLIB +void netserver_setup(void) +{ + netserver_class = class_new(gensym("netserver"),(t_newmethod)netserver_new, (t_method)netserver_free, + sizeof(t_netserver), 0, A_DEFFLOAT, 0); + class_addmethod(netserver_class, (t_method)netserver_print, gensym("print"), 0); + class_addmethod(netserver_class, (t_method)netserver_send, gensym("send"), A_GIMME, 0); + class_addmethod(netserver_class, (t_method)netserver_client_send, gensym("client"), A_GIMME, 0); + class_addmethod(netserver_class, (t_method)netserver_broadcast, gensym("broadcast"), A_GIMME, 0); +/* syslog log level messages */ + class_addmethod(netserver_class, (t_method)netserver_emerg, gensym("emerg"), 0); + class_addmethod(netserver_class, (t_method)netserver_emerg, gensym("emergency"), 0); + class_addmethod(netserver_class, (t_method)netserver_alert, gensym("alert"), 0); + class_addmethod(netserver_class, (t_method)netserver_crit, gensym("crit"), 0); + class_addmethod(netserver_class, (t_method)netserver_crit, gensym("critical"), 0); + class_addmethod(netserver_class, (t_method)netserver_err, gensym("err"), 0); + class_addmethod(netserver_class, (t_method)netserver_err, gensym("error"), 0); + class_addmethod(netserver_class, (t_method)netserver_err, gensym("quiet"), 0); + class_addmethod(netserver_class, (t_method)netserver_warning, gensym("warning"), 0); + class_addmethod(netserver_class, (t_method)netserver_notice, gensym("notice"), 0); + class_addmethod(netserver_class, (t_method)netserver_info, gensym("info"), 0); + class_addmethod(netserver_class, (t_method)netserver_info, gensym("verbose"), 0); + class_addmethod(netserver_class, (t_method)netserver_debug, gensym("debug"), 0); + + + logpost(NULL, 4, version); +} +#else +void maxlib_netserver_setup(void) +{ + netserver_class = class_new(gensym("maxlib_netserver"),(t_newmethod)netserver_new, (t_method)netserver_free, + sizeof(t_netserver), 0, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)netserver_new, gensym("netserver"), A_DEFFLOAT, 0); + class_addmethod(netserver_class, (t_method)netserver_print, gensym("print"), 0); + class_addmethod(netserver_class, (t_method)netserver_send, gensym("send"), A_GIMME, 0); + class_addmethod(netserver_class, (t_method)netserver_client_send, gensym("client"), A_GIMME, 0); + class_addmethod(netserver_class, (t_method)netserver_broadcast, gensym("broadcast"), A_GIMME, 0); + class_sethelpsymbol(netserver_class, gensym("maxlib/netserver-help.pd")); +} +#endif diff --git a/nroute.c b/nroute.c index 5c85f6c..60bcea8 100644 --- a/nroute.c +++ b/nroute.c @@ -1,179 +1,179 @@ -/* ------------------------- nroute ------------------------------------------ */ -/* */ -/* Route input according to Nth element. */ -/* Written by Olaf Matthes */ -/* Based on code found on the web. */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -/* - inlet 1: anything to be routed - inlet 2: anything to be matched to - inlet 3: position to match - out 1: input if match found - out 2: input if match not found -*/ - -#include "m_pd.h" - -static char *version = "nroute v0.1, written by Olaf Matthes "; - -typedef struct nroute -{ - t_object x_obj; - t_outlet *out1; - t_outlet *out2; - t_int pos; - t_atom match; -} t_nroute; - -typedef struct proxy -{ - t_object obj; - t_int index; /* number of proxy inlet(s) */ - t_nroute *x; /* we'll put the other struct in here */ -} t_proxy; - - - /* this is the routine that actually does the routing / matching */ - /* it get's called by all other routines that get any input and */ - /* even handles the second (proxy) inlet ! */ -static void nroute_any(t_nroute *x, t_symbol *s, int argc, t_atom *argv) -{ - if(s) - { - if (x->pos == 1 && x->match.a_type == A_SYMBOL && x->match.a_w.w_symbol == s) - outlet_anything (x->out1,s,argc,argv); - else if (x->pos > 1 && x->pos <= argc + 1 && - argv[x->pos-2].a_type == x->match.a_type && - argv[x->pos-2].a_w.w_float == x->match.a_w.w_float) - outlet_anything (x->out1,s,argc,argv); - else outlet_anything (x->out2,s,argc,argv); - } - else - { - if (x->pos > 0 && x->pos <= argc && - argv[x->pos-1].a_type == x->match.a_type && - argv[x->pos-1].a_w.w_float == x->match.a_w.w_float) - outlet_list (x->out1,0,argc,argv); - else outlet_list (x->out2,0,argc,argv); - } -} - -static void nroute_float(t_nroute *x, float f) -{ - t_atom a; - - SETFLOAT (&a,f); - nroute_any(x,0,1,&a); -} - -static void nroute_list(t_nroute *x, t_symbol *s, int argc, t_atom *argv) -{ - nroute_any(x,0,argc,argv); -} - -static void nroute_setmatch(t_proxy *p, t_symbol *s, int argc, t_atom *argv) -{ - t_nroute *x = (t_nroute *)(p->x); - - if(argc == 0) /* have to match a symbol */ - { - x->match.a_type = A_SYMBOL; - x->match.a_w.w_symbol = s; - } - else /* got a float */ - { - if(argc > 1) - { - post("nroute: middle inlet accepts only (float,symbol) for match"); - return; - } - x->match.a_type = A_FLOAT; - x->match.a_w.w_float = argv[0].a_w.w_float; - } -} - -static void nroute_setpos(t_nroute *x, t_floatarg f) -{ - x->pos = (t_int)f; -} - -static t_class *nroute_class; -static t_class *proxy_class; - -static void *nroute_new(t_symbol *s, int argc, t_atom *argv) -{ - t_nroute *x = (t_nroute *)pd_new(nroute_class); - t_proxy *inlet = (t_proxy *)pd_new(proxy_class); /* for the proxy inlet */ - - inlet->x = x; /* make x visible to the proxy inlets */ - - x->pos = 1; - x->match.a_type = A_NULL; - if (argc > 2) { error ("nroute: extra arguments"); return 0; } - if (argc > 1) { - if (argv[1].a_type == A_FLOAT) x->pos = argv[1].a_w.w_float; - else { post ("nroute: second argument must be (int) position"); return 0; } - } - if (argc > 0) { - x->match.a_type = argv[0].a_type; - x->match.a_w.w_float = argv[0].a_w.w_float; - } - inlet->index = 0; /* we are going to create a proxy inlet no. 0 */ - /* it belongs to the object t_nroute but the destination is t_proxy */ - inlet_new(&x->x_obj, &inlet->obj.ob_pd, 0,0); - /* and now a 'normal' third inlet */ - inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("right")); - x->out1 = outlet_new(&x->x_obj, gensym("list")); - x->out2 = outlet_new(&x->x_obj, gensym("list")); - return (x); -} - -#ifndef MAXLIB -void nroute_setup(void) -{ - /* the object's class: */ - nroute_class = class_new(gensym("nroute"), (t_newmethod)nroute_new, - 0, sizeof(t_nroute), 0, A_GIMME, 0); -#else -void maxlib_nroute_setup(void) -{ - /* the object's class: */ - nroute_class = class_new(gensym("maxlib_nroute"), (t_newmethod)nroute_new, - 0, sizeof(t_nroute), 0, A_GIMME, 0); - class_addcreator((t_newmethod)nroute_new, gensym("nroute"), A_GIMME, 0); -#endif - /* a class for the proxy inlet: */ - proxy_class = class_new(gensym("maxlib_nroute_proxy"), NULL, NULL, sizeof(t_proxy), - CLASS_PD|CLASS_NOINLET, A_NULL); - - class_addmethod(nroute_class, (t_method)nroute_setpos, gensym("right"), A_FLOAT, 0); - class_addfloat(nroute_class, nroute_float); - class_addlist(nroute_class, nroute_list); - class_addanything(nroute_class, nroute_any); - class_addanything(proxy_class, nroute_setmatch); -#ifndef MAXLIB - - post(version); -#else - class_sethelpsymbol(nroute_class, gensym("maxlib/nroute-help.pd")); -#endif -} +/* ------------------------- nroute ------------------------------------------ */ +/* */ +/* Route input according to Nth element. */ +/* Written by Olaf Matthes */ +/* Based on code found on the web. */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +/* + inlet 1: anything to be routed + inlet 2: anything to be matched to + inlet 3: position to match + out 1: input if match found + out 2: input if match not found +*/ + +#include "m_pd.h" + +static char *version = "nroute v0.1, written by Olaf Matthes "; + +typedef struct nroute +{ + t_object x_obj; + t_outlet *out1; + t_outlet *out2; + t_int pos; + t_atom match; +} t_nroute; + +typedef struct proxy +{ + t_object obj; + t_int index; /* number of proxy inlet(s) */ + t_nroute *x; /* we'll put the other struct in here */ +} t_proxy; + + + /* this is the routine that actually does the routing / matching */ + /* it get's called by all other routines that get any input and */ + /* even handles the second (proxy) inlet ! */ +static void nroute_any(t_nroute *x, t_symbol *s, int argc, t_atom *argv) +{ + if(s) + { + if (x->pos == 1 && x->match.a_type == A_SYMBOL && x->match.a_w.w_symbol == s) + outlet_anything (x->out1,s,argc,argv); + else if (x->pos > 1 && x->pos <= argc + 1 && + argv[x->pos-2].a_type == x->match.a_type && + argv[x->pos-2].a_w.w_float == x->match.a_w.w_float) + outlet_anything (x->out1,s,argc,argv); + else outlet_anything (x->out2,s,argc,argv); + } + else + { + if (x->pos > 0 && x->pos <= argc && + argv[x->pos-1].a_type == x->match.a_type && + argv[x->pos-1].a_w.w_float == x->match.a_w.w_float) + outlet_list (x->out1,0,argc,argv); + else outlet_list (x->out2,0,argc,argv); + } +} + +static void nroute_float(t_nroute *x, float f) +{ + t_atom a; + + SETFLOAT (&a,f); + nroute_any(x,0,1,&a); +} + +static void nroute_list(t_nroute *x, t_symbol *s, int argc, t_atom *argv) +{ + nroute_any(x,0,argc,argv); +} + +static void nroute_setmatch(t_proxy *p, t_symbol *s, int argc, t_atom *argv) +{ + t_nroute *x = (t_nroute *)(p->x); + + if(argc == 0) /* have to match a symbol */ + { + x->match.a_type = A_SYMBOL; + x->match.a_w.w_symbol = s; + } + else /* got a float */ + { + if(argc > 1) + { + post("nroute: middle inlet accepts only (float,symbol) for match"); + return; + } + x->match.a_type = A_FLOAT; + x->match.a_w.w_float = argv[0].a_w.w_float; + } +} + +static void nroute_setpos(t_nroute *x, t_floatarg f) +{ + x->pos = (t_int)f; +} + +static t_class *nroute_class; +static t_class *proxy_class; + +static void *nroute_new(t_symbol *s, int argc, t_atom *argv) +{ + t_nroute *x = (t_nroute *)pd_new(nroute_class); + t_proxy *inlet = (t_proxy *)pd_new(proxy_class); /* for the proxy inlet */ + + inlet->x = x; /* make x visible to the proxy inlets */ + + x->pos = 1; + x->match.a_type = A_NULL; + if (argc > 2) { error ("nroute: extra arguments"); return 0; } + if (argc > 1) { + if (argv[1].a_type == A_FLOAT) x->pos = argv[1].a_w.w_float; + else { post ("nroute: second argument must be (int) position"); return 0; } + } + if (argc > 0) { + x->match.a_type = argv[0].a_type; + x->match.a_w.w_float = argv[0].a_w.w_float; + } + inlet->index = 0; /* we are going to create a proxy inlet no. 0 */ + /* it belongs to the object t_nroute but the destination is t_proxy */ + inlet_new(&x->x_obj, &inlet->obj.ob_pd, 0,0); + /* and now a 'normal' third inlet */ + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("right")); + x->out1 = outlet_new(&x->x_obj, gensym("list")); + x->out2 = outlet_new(&x->x_obj, gensym("list")); + return (x); +} + +#ifndef MAXLIB +void nroute_setup(void) +{ + /* the object's class: */ + nroute_class = class_new(gensym("nroute"), (t_newmethod)nroute_new, + 0, sizeof(t_nroute), 0, A_GIMME, 0); +#else +void maxlib_nroute_setup(void) +{ + /* the object's class: */ + nroute_class = class_new(gensym("maxlib_nroute"), (t_newmethod)nroute_new, + 0, sizeof(t_nroute), 0, A_GIMME, 0); + class_addcreator((t_newmethod)nroute_new, gensym("nroute"), A_GIMME, 0); +#endif + /* a class for the proxy inlet: */ + proxy_class = class_new(gensym("maxlib_nroute_proxy"), NULL, NULL, sizeof(t_proxy), + CLASS_PD|CLASS_NOINLET, A_NULL); + + class_addmethod(nroute_class, (t_method)nroute_setpos, gensym("right"), A_FLOAT, 0); + class_addfloat(nroute_class, nroute_float); + class_addlist(nroute_class, nroute_list); + class_addanything(nroute_class, nroute_any); + class_addanything(proxy_class, nroute_setmatch); +#ifndef MAXLIB + + logpost(NULL, 4, version); +#else + class_sethelpsymbol(nroute_class, gensym("maxlib/nroute-help.pd")); +#endif +} diff --git a/pitch.c b/pitch.c index c584f7b..2eed248 100644 --- a/pitch.c +++ b/pitch.c @@ -1,114 +1,114 @@ -/* ------------------------- pitch ------------------------------------------ */ -/* */ -/* Get a lot of info about an incoming pitch (class, register, interval...). */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include - -static char *version = "pitch v0.1b, written by Olaf Matthes "; - -typedef struct pitch -{ - t_object x_ob; - t_inlet *x_inpitch; /* inlet for pitch */ - t_outlet *x_outpitchval; /* pitch as MIDI note number */ - t_outlet *x_outpitchname; /* pitch name, e.g. "C1" */ - t_outlet *x_outpitchclass; /* pitch class */ - t_outlet *x_outintv; /* interval */ - t_outlet *x_outregister; /* register */ - - t_int x_lastpitch; - -} t_pitch; - -static void pitch_float(t_pitch *x, t_floatarg f) { - - char buf[8]; - int r, c, interval = 0, pitch; - - char* notes_up[12] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"}; - char* notes_down[12] = {"C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"}; - - pitch = (t_int)f; - if(pitch < 1) pitch = 0; - if(pitch > 127) pitch = 127; - - if(x->x_lastpitch != 0)interval = pitch - x->x_lastpitch; - x->x_lastpitch = pitch; - - r = (pitch / 12) - 1; - c = pitch % 12; - if(interval >= 0) - { - sprintf(buf, "%s%d", notes_up[c], r); - } - else - { - sprintf(buf, "%s%d", notes_down[c], r); - } - // post("note: %s %d", notes[c], r); - - /* output values from right to left */ - outlet_float(x->x_outregister, r); - outlet_float(x->x_outintv, interval); - outlet_float(x->x_outpitchclass, c); - outlet_symbol(x->x_outpitchname, gensym(buf)); - outlet_float(x->x_outpitchval, pitch); -} - -static t_class *pitch_class; - -static void *pitch_new(t_floatarg f) -{ - t_pitch *x = (t_pitch *)pd_new(pitch_class); - x->x_inpitch = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); - x->x_outpitchval = outlet_new(&x->x_ob, gensym("float")); - x->x_outpitchname = outlet_new(&x->x_ob, gensym("symbol")); - x->x_outpitchclass = outlet_new(&x->x_ob, gensym("float")); - x->x_outintv = outlet_new(&x->x_ob, gensym("float")); - x->x_outregister = outlet_new(&x->x_ob, gensym("float")); - - x->x_lastpitch = f; - - return (void *)x; -} - -#ifndef MAXLIB -void pitch_setup(void) -{ - pitch_class = class_new(gensym("pitch"), (t_newmethod)pitch_new, - 0, sizeof(t_pitch), 0, A_DEFFLOAT, 0); - class_addfloat(pitch_class, pitch_float); - - post(version); -} -#else -void maxlib_pitch_setup(void) -{ - pitch_class = class_new(gensym("maxlib_pitch"), (t_newmethod)pitch_new, - 0, sizeof(t_pitch), 0, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)pitch_new, gensym("pitch"), A_DEFFLOAT, 0); - class_addfloat(pitch_class, pitch_float); - class_sethelpsymbol(pitch_class, gensym("maxlib/pitch-help.pd")); -} -#endif +/* ------------------------- pitch ------------------------------------------ */ +/* */ +/* Get a lot of info about an incoming pitch (class, register, interval...). */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include + +static char *version = "pitch v0.1b, written by Olaf Matthes "; + +typedef struct pitch +{ + t_object x_ob; + t_inlet *x_inpitch; /* inlet for pitch */ + t_outlet *x_outpitchval; /* pitch as MIDI note number */ + t_outlet *x_outpitchname; /* pitch name, e.g. "C1" */ + t_outlet *x_outpitchclass; /* pitch class */ + t_outlet *x_outintv; /* interval */ + t_outlet *x_outregister; /* register */ + + t_int x_lastpitch; + +} t_pitch; + +static void pitch_float(t_pitch *x, t_floatarg f) { + + char buf[8]; + int r, c, interval = 0, pitch; + + char* notes_up[12] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"}; + char* notes_down[12] = {"C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"}; + + pitch = (t_int)f; + if(pitch < 1) pitch = 0; + if(pitch > 127) pitch = 127; + + if(x->x_lastpitch != 0)interval = pitch - x->x_lastpitch; + x->x_lastpitch = pitch; + + r = (pitch / 12) - 1; + c = pitch % 12; + if(interval >= 0) + { + sprintf(buf, "%s%d", notes_up[c], r); + } + else + { + sprintf(buf, "%s%d", notes_down[c], r); + } + // post("note: %s %d", notes[c], r); + + /* output values from right to left */ + outlet_float(x->x_outregister, r); + outlet_float(x->x_outintv, interval); + outlet_float(x->x_outpitchclass, c); + outlet_symbol(x->x_outpitchname, gensym(buf)); + outlet_float(x->x_outpitchval, pitch); +} + +static t_class *pitch_class; + +static void *pitch_new(t_floatarg f) +{ + t_pitch *x = (t_pitch *)pd_new(pitch_class); + x->x_inpitch = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); + x->x_outpitchval = outlet_new(&x->x_ob, gensym("float")); + x->x_outpitchname = outlet_new(&x->x_ob, gensym("symbol")); + x->x_outpitchclass = outlet_new(&x->x_ob, gensym("float")); + x->x_outintv = outlet_new(&x->x_ob, gensym("float")); + x->x_outregister = outlet_new(&x->x_ob, gensym("float")); + + x->x_lastpitch = f; + + return (void *)x; +} + +#ifndef MAXLIB +void pitch_setup(void) +{ + pitch_class = class_new(gensym("pitch"), (t_newmethod)pitch_new, + 0, sizeof(t_pitch), 0, A_DEFFLOAT, 0); + class_addfloat(pitch_class, pitch_float); + + logpost(NULL, 4, version); +} +#else +void maxlib_pitch_setup(void) +{ + pitch_class = class_new(gensym("maxlib_pitch"), (t_newmethod)pitch_new, + 0, sizeof(t_pitch), 0, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)pitch_new, gensym("pitch"), A_DEFFLOAT, 0); + class_addfloat(pitch_class, pitch_float); + class_sethelpsymbol(pitch_class, gensym("maxlib/pitch-help.pd")); +} +#endif diff --git a/plus.c b/plus.c index 1a03171..5095d89 100644 --- a/plus.c +++ b/plus.c @@ -1,110 +1,110 @@ -/* --------------------------- plus ------------------------------------------ */ -/* */ -/* Like '+', but calculates output whenever _any_ of the inlets changes. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include - -#define MAXSIZE 32 - -static char *version = "plus v0.2, written by Olaf Matthes "; - -typedef struct plus -{ - t_object x_ob; - t_inlet *x_inleft; /* leftmost inlet */ - t_inlet *x_inright; /* right inlet */ - t_outlet *x_outlet; /* result */ - t_int x_numvalues; /* number of values / inlets */ - - t_float x_plusvalue[MAXSIZE]; - -} t_plus; - -static void plus_bang(t_plus *x) -{ - int i; - t_float result = x->x_plusvalue[0]; - for(i = 1; i < x->x_numvalues; i++) - result += x->x_plusvalue[i]; - outlet_float(x->x_outlet, result); -} - -static void plus_float(t_plus *x, t_floatarg f) -{ - x->x_plusvalue[0] = f; - plus_bang(x); /* calculate result */ -} - -static void plus_ft1(t_plus *x, t_floatarg f) -{ - x->x_plusvalue[1] = f; - plus_bang(x); /* calculate result */ -} - -static t_class *plus_class; - -static void *plus_new(t_symbol *s, t_int argc, t_atom* argv) -{ - int i; - - t_plus *x = (t_plus *)pd_new(plus_class); - x->x_inright = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); - for(i = 2; i < argc; i++) /* create additional inlets, if any */ - { - floatinlet_new(&x->x_ob, &x->x_plusvalue[i]); - } - x->x_outlet = outlet_new(&x->x_ob, gensym("float")); - - for(i = 0; i < argc; i++) - { - x->x_plusvalue[i] = atom_getfloatarg(i, argc, argv);; - } - x->x_numvalues = i; - - return (void *)x; -} - -#ifndef MAXLIB -void plus_setup(void) -{ - plus_class = class_new(gensym("plus"), (t_newmethod)plus_new, - 0, sizeof(t_plus), 0, A_GIMME, 0); - class_addfloat(plus_class, plus_float); - class_addmethod(plus_class, (t_method)plus_ft1, gensym("ft1"), A_FLOAT, 0); - class_addbang(plus_class, (t_method)plus_bang); - - post(version); -} -#else -void maxlib_plus_setup(void) -{ - plus_class = class_new(gensym("maxlib_plus"), (t_newmethod)plus_new, - 0, sizeof(t_plus), 0, A_GIMME, 0); - class_addcreator((t_newmethod)plus_new, gensym("plus"), A_GIMME, 0); - class_addfloat(plus_class, plus_float); - class_addmethod(plus_class, (t_method)plus_ft1, gensym("ft1"), A_FLOAT, 0); - class_addbang(plus_class, (t_method)plus_bang); - class_sethelpsymbol(plus_class, gensym("maxlib/plus-help.pd")); -} -#endif +/* --------------------------- plus ------------------------------------------ */ +/* */ +/* Like '+', but calculates output whenever _any_ of the inlets changes. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include + +#define MAXSIZE 32 + +static char *version = "plus v0.2, written by Olaf Matthes "; + +typedef struct plus +{ + t_object x_ob; + t_inlet *x_inleft; /* leftmost inlet */ + t_inlet *x_inright; /* right inlet */ + t_outlet *x_outlet; /* result */ + t_int x_numvalues; /* number of values / inlets */ + + t_float x_plusvalue[MAXSIZE]; + +} t_plus; + +static void plus_bang(t_plus *x) +{ + int i; + t_float result = x->x_plusvalue[0]; + for(i = 1; i < x->x_numvalues; i++) + result += x->x_plusvalue[i]; + outlet_float(x->x_outlet, result); +} + +static void plus_float(t_plus *x, t_floatarg f) +{ + x->x_plusvalue[0] = f; + plus_bang(x); /* calculate result */ +} + +static void plus_ft1(t_plus *x, t_floatarg f) +{ + x->x_plusvalue[1] = f; + plus_bang(x); /* calculate result */ +} + +static t_class *plus_class; + +static void *plus_new(t_symbol *s, t_int argc, t_atom* argv) +{ + int i; + + t_plus *x = (t_plus *)pd_new(plus_class); + x->x_inright = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); + for(i = 2; i < argc; i++) /* create additional inlets, if any */ + { + floatinlet_new(&x->x_ob, &x->x_plusvalue[i]); + } + x->x_outlet = outlet_new(&x->x_ob, gensym("float")); + + for(i = 0; i < argc; i++) + { + x->x_plusvalue[i] = atom_getfloatarg(i, argc, argv);; + } + x->x_numvalues = i; + + return (void *)x; +} + +#ifndef MAXLIB +void plus_setup(void) +{ + plus_class = class_new(gensym("plus"), (t_newmethod)plus_new, + 0, sizeof(t_plus), 0, A_GIMME, 0); + class_addfloat(plus_class, plus_float); + class_addmethod(plus_class, (t_method)plus_ft1, gensym("ft1"), A_FLOAT, 0); + class_addbang(plus_class, (t_method)plus_bang); + + logpost(NULL, 4, version); +} +#else +void maxlib_plus_setup(void) +{ + plus_class = class_new(gensym("maxlib_plus"), (t_newmethod)plus_new, + 0, sizeof(t_plus), 0, A_GIMME, 0); + class_addcreator((t_newmethod)plus_new, gensym("plus"), A_GIMME, 0); + class_addfloat(plus_class, plus_float); + class_addmethod(plus_class, (t_method)plus_ft1, gensym("ft1"), A_FLOAT, 0); + class_addbang(plus_class, (t_method)plus_bang); + class_sethelpsymbol(plus_class, gensym("maxlib/plus-help.pd")); +} +#endif diff --git a/poisson.c b/poisson.c index ce2e33b..499886c 100644 --- a/poisson.c +++ b/poisson.c @@ -1,91 +1,91 @@ -/* ---------------------------- rand_poisson ---------------------------------- */ -/* */ -/* rand_poisson generates a poisson distributed random variable. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Based on code found in Dodge/Jerse "Computer Music" */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include -#include -#include - -#define fran() (t_float)rand()/(t_float)RAND_MAX -#ifndef M_PI -#define M_PI 3.1415927 -#endif - -static char *version = "poisson v0.1, generates a poisson distributed random variable\n" - " written by Olaf Matthes "; - -/* -------------------------- rand_poisson ------------------------------ */ - -static t_class *rand_poisson_class; - -typedef struct _rand_poisson -{ - t_object x_obj; - t_float x_lambda; -} t_rand_poisson; - -static void *rand_poisson_new(t_floatarg f) -{ - t_rand_poisson *x = (t_rand_poisson *)pd_new(rand_poisson_class); - srand( (unsigned)time( NULL ) ); - floatinlet_new(&x->x_obj, &x->x_lambda); - outlet_new(&x->x_obj, &s_float); - x->x_lambda = f; - return (x); -} - -static void rand_poisson_bang(t_rand_poisson *x) -{ - t_float u, v; - t_int n = 0; - v = exp(-x->x_lambda); - u = fran(); - while(u > v) - { - u *= fran(); - n++; - } - outlet_float(x->x_obj.ob_outlet, n); -} - -#ifndef MAXLIB -void poisson_setup(void) -{ - rand_poisson_class = class_new(gensym("poisson"), (t_newmethod)rand_poisson_new, 0, - sizeof(t_rand_poisson), 0, A_DEFFLOAT, 0); - class_addbang(rand_poisson_class, rand_poisson_bang); - class_sethelpsymbol(rand_poisson_class, gensym("poisson-help.pd")); - post(version); -} -#else -void maxlib_poisson_setup(void) -{ - rand_poisson_class = class_new(gensym("maxlib_poisson"), (t_newmethod)rand_poisson_new, 0, - sizeof(t_rand_poisson), 0, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)rand_poisson_new, gensym("poisson"), A_DEFFLOAT, 0); - class_addbang(rand_poisson_class, rand_poisson_bang); - class_sethelpsymbol(rand_poisson_class, gensym("maxlib/poisson-help.pd")); -} -#endif +/* ---------------------------- rand_poisson ---------------------------------- */ +/* */ +/* rand_poisson generates a poisson distributed random variable. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Based on code found in Dodge/Jerse "Computer Music" */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include +#include +#include + +#define fran() (t_float)rand()/(t_float)RAND_MAX +#ifndef M_PI +#define M_PI 3.1415927 +#endif + +static char *version = "poisson v0.1, generates a poisson distributed random variable\n" + " written by Olaf Matthes "; + +/* -------------------------- rand_poisson ------------------------------ */ + +static t_class *rand_poisson_class; + +typedef struct _rand_poisson +{ + t_object x_obj; + t_float x_lambda; +} t_rand_poisson; + +static void *rand_poisson_new(t_floatarg f) +{ + t_rand_poisson *x = (t_rand_poisson *)pd_new(rand_poisson_class); + srand( (unsigned)time( NULL ) ); + floatinlet_new(&x->x_obj, &x->x_lambda); + outlet_new(&x->x_obj, &s_float); + x->x_lambda = f; + return (x); +} + +static void rand_poisson_bang(t_rand_poisson *x) +{ + t_float u, v; + t_int n = 0; + v = exp(-x->x_lambda); + u = fran(); + while(u > v) + { + u *= fran(); + n++; + } + outlet_float(x->x_obj.ob_outlet, n); +} + +#ifndef MAXLIB +void poisson_setup(void) +{ + rand_poisson_class = class_new(gensym("poisson"), (t_newmethod)rand_poisson_new, 0, + sizeof(t_rand_poisson), 0, A_DEFFLOAT, 0); + class_addbang(rand_poisson_class, rand_poisson_bang); + class_sethelpsymbol(rand_poisson_class, gensym("poisson-help.pd")); + logpost(NULL, 4, version); +} +#else +void maxlib_poisson_setup(void) +{ + rand_poisson_class = class_new(gensym("maxlib_poisson"), (t_newmethod)rand_poisson_new, 0, + sizeof(t_rand_poisson), 0, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)rand_poisson_new, gensym("poisson"), A_DEFFLOAT, 0); + class_addbang(rand_poisson_class, rand_poisson_bang); + class_sethelpsymbol(rand_poisson_class, gensym("maxlib/poisson-help.pd")); +} +#endif diff --git a/pong.c b/pong.c index a30e892..6ee6a24 100644 --- a/pong.c +++ b/pong.c @@ -1,332 +1,332 @@ -/* --------------------------- pong ------------------------------------------ */ -/* */ -/* A virtual bouncing ball. */ -/* Written by Olaf Matthes */ -/* Based on pong (for Max) version 1.5 written by Richard Dudas. */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" - -static char *version = "pong v0.1, ported by Olaf Matthes \n" - " written for Max by Richard Dudas"; - -typedef struct pong -{ - t_object x_obj; - t_outlet *p_bounceout; - t_outlet *p_handout; - t_outlet *p_velout; - t_outlet *p_heightout; - t_clock *p_klok; - - t_int p_ms; // ms count - t_float p_time; // current time div by warp - t_float p_timegrain; // timegrain in seconds - t_float p_timegrainin; // timegrain in ms - t_float p_warp; // timewarp in ms - - t_float p_dinit; // init distance - t_float p_vinit; // init velocity - t_float p_ainit; // base acceleration def -100 - t_float p_damping; // realtime multiplicative damping - t_float p_dhand; // virtual hand distance - t_float p_force; // force of hand 1.0 = no force - - t_float p_accel; // current accel value - t_float p_vi; // current velocity - t_float p_di; // current distance - t_float p_dt; // distance out - t_float p_dtprev; // previous distance out for accel computation - t_float p_vt; // velocity out - t_int p_prevchg; // for logical transition -} t_pong; - -/* ---------------------------------------------------------- */ -/* ---- this stuff is mainly for the timer, on off etc... --- */ -/* ---------------------------------------------------------- */ - -static void pong_reset(t_pong *x) -{ - x->p_di = x->p_dinit; - x->p_dt = x->p_dinit; // added - x->p_dtprev = x->p_dinit; // added - x->p_vi = x->p_vinit; - x->p_vt = x->p_vinit; // added - x->p_ms = 0; - x->p_time = 0.; - x->p_ainit = -100.; // added, but currently disabled - x->p_accel = -100.; // reactivated (?) - x->p_damping = 1.; // i.e. no initial damping - x->p_prevchg = 0; // added - -/* x->p_ms = 0; - x->p_time = 0.; - x->p_timegrain = 0.05; // if ms grain = 50 - x->p_timegrainin = 50; - - x->p_vinit = 0.; - x->p_dinit = 100.; - x->p_ainit = -100.; - x->p_damping = 1.; // i.e. no initial damping - x->p_dhand = 100.; - x->p_force = 1.; // i.e. hand does nothing initially - - x->p_accel = -100.; - x->p_vi = 0.; - x->p_di = 100.; - - x->p_dt = 100.; // changed from 0 to 100 - x->p_dtprev = 100.; // changed from 0 to 100 - x->p_vt = 0.; - x->p_prevchg = 0; -*/ -} - -/* ---------------------------------------------------------- */ - -static void pong_timein(t_pong *x, t_floatarg n) -{ - int thischg; - - x->p_time = n / x->p_warp; - - x->p_dt = ((x->p_accel * (x->p_time*x->p_time)) + (x->p_time * x->p_vi) + x->p_di); - x->p_vt = ((x->p_dt - x->p_dtprev) / x->p_timegrain); - - if (x->p_dt < 0.) - { - x->p_dt *= -1.; - - x->p_di = 0.; - x->p_vi = x->p_vt * (-1. * x->p_damping); // -1 will eventually be a damping variable - //post("vel at bounce %f", x->p_vi); - outlet_bang(x->p_bounceout); - x->p_ms = 0; - //x->p_dtprev= 0.; - } - //else - x->p_dtprev = x->p_dt; - - /* ---------------------------------- virtual hand below ------------ */ - - if (x->p_dt > x->p_dhand) // presuming the hand is initially equal to the dinit - thischg = 1; - else - thischg = 0; - - if (thischg != x->p_prevchg) - { - x->p_ms = 0; - x->p_vi = x->p_vt; - x->p_di = x->p_dhand; - - if (thischg == 0) - { - x->p_accel = -100.; // x->p_ainit in lieu of -100. - outlet_float(x->p_handout, 0); - } - else - { - x->p_accel = (x->p_force * -100.); // x->p_ainit in lieu of -100. - outlet_float(x->p_handout, 1); - } - } - - x->p_prevchg = thischg; - outlet_float(x->p_velout, x->p_vt); - outlet_float(x->p_heightout, x->p_dt); -} - -static void pong_onoff(t_pong *x, t_floatarg n) -{ - if (n != 0) - clock_delay(x->p_klok, 0); - else - clock_unset(x->p_klok); -} - -/* ---------------------------------------------------------- */ - -static void pong_bang(t_pong *x) -{ - x->p_ms = 0; - clock_delay(x->p_klok, 0); -} - -static void pong_stop(t_pong *x) -{ - clock_unset(x->p_klok); -} - -/* ---------------------------------------------------------- */ - -static void pong_tick(t_pong *x) -{ - clock_delay(x->p_klok, (t_int)x->p_timegrainin); - pong_timein(x, x->p_ms); - //outlet_float(x->p_heightout, (float)x->p_ms); - x->p_ms = x->p_ms + x->p_timegrainin; -} - -/* ---------------------------------------------------------- */ - -static void pong_tgrain(t_pong *x, t_floatarg n) -{ - x->p_timegrain = n / x->p_warp; - x->p_timegrainin = n; - post("timegrain %f", x->p_timegrain); -} - -/* ---------------------------------------------------------- */ - -static void pong_warpin(t_pong *x, t_floatarg n) -{ - x->p_warp = n; - x->p_timegrain = x->p_timegrainin / x->p_warp; - post("timewarp %f ms = one sec", x->p_warp); -} - -/* ---------------------------------------------------------- */ -/* ----- these are to receive and store the init values ----- */ -/* ---------------------------------------------------------- */ - -static void pong_initdist(t_pong *x, t_floatarg n) -{ - x->p_dinit = n; -} - -static void pong_initvel(t_pong *x, t_floatarg n) -{ - x->p_vinit = n; -} - -static void pong_damp(t_pong *x, t_floatarg n) -{ - x->p_damping = n; -} - -/* ---------------------------------------------------------- */ - -static void pong_baseacc(t_pong *x, t_floatarg n) -{ - //post ("baseaccel currently disabled", 0); - x->p_ainit = n; - x->p_accel = x->p_ainit; -} - -/* ---------------------------------------------------------- */ - -static void pong_hand(t_pong *x, t_floatarg n) -{ - x->p_dhand = n; -} - -static void pong_force(t_pong *x, t_floatarg n) -{ - x->p_force = n; -} - -/* ---------------------------------------------------------- */ - - -static t_class *pong_class; - -static void *pong_new(t_floatarg n) -{ - t_pong *x = (t_pong *)pd_new(pong_class); - - x->p_klok = clock_new(x, (t_method)pong_tick); - - inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("dist")); // distance - inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("velo")); // velocity - inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("damp")); // damping - inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("force")); // hand force 1.0 = no force - inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("hand")); // virtual hand (distance) - - - if (n > 0) - x->p_warp = n; - else - x->p_warp = 1000.; - - x->p_ms = 0; - x->p_time = 0.; - x->p_timegrain = 0.05; // if ms grain = 50 - x->p_timegrainin = 50.0; - - x->p_vinit = 0.; - x->p_dinit = 100.; - x->p_ainit = -100.; - x->p_damping = 1.; // i.e. no initial damping - x->p_dhand = 100.; - x->p_force = 1.; // i.e. hand does nothing initially - - x->p_accel = -100.; - x->p_vi = 0.; - x->p_di = 100.; - - x->p_dt = 100.; // changed from 0 to 100 - x->p_dtprev = 100.; // changed from 0 to 100 - x->p_vt = 0.; - x->p_prevchg = 0; - - x->p_bounceout = outlet_new(&x->x_obj, gensym("bang")); - x->p_handout = outlet_new(&x->x_obj, gensym("float")); - x->p_velout = outlet_new(&x->x_obj, gensym("float")); - x->p_heightout = outlet_new(&x->x_obj, gensym("float")); - - return (x); -} - -#ifndef MAXLIB -void pong_setup(void) -{ - pong_class = class_new(gensym("pong"), (t_newmethod)pong_new, - 0, sizeof(t_pong), 0, A_DEFFLOAT, 0); -#else -void maxlib_pong_setup(void) -{ - pong_class = class_new(gensym("maxlib_pong"), (t_newmethod)pong_new, - 0, sizeof(t_pong), 0, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)pong_new, gensym("pong"), A_DEFFLOAT, 0); -#endif - /* method handlers for inlets */ - class_addmethod(pong_class, (t_method)pong_initdist, gensym("dist"), A_FLOAT, 0); - class_addmethod(pong_class, (t_method)pong_initvel, gensym("velo"), A_FLOAT, 0); - class_addmethod(pong_class, (t_method)pong_damp, gensym("damp"), A_FLOAT, 0); - class_addmethod(pong_class, (t_method)pong_force, gensym("force"), A_FLOAT, 0); - class_addmethod(pong_class, (t_method)pong_hand, gensym("hand"), A_FLOAT, 0); - /* method handlers for other messages to first inlet */ - class_addmethod(pong_class, (t_method)pong_tgrain, gensym("timegrain"), A_FLOAT, 0); - class_addmethod(pong_class, (t_method)pong_warpin, gensym("timewarp"), A_FLOAT, 0); - class_addmethod(pong_class, (t_method)pong_baseacc, gensym("baseaccel"), A_FLOAT, 0); - class_addmethod(pong_class, (t_method)pong_reset, gensym("reset"), 0); - class_addmethod(pong_class, (t_method)pong_stop, gensym("stop"), 0); - - class_addfloat(pong_class, pong_onoff); - class_addbang(pong_class, pong_bang); -#ifndef MAXLIB - - post(version); -#else - class_sethelpsymbol(pong_class, gensym("maxlib/pong-help.pd")); -#endif -} +/* --------------------------- pong ------------------------------------------ */ +/* */ +/* A virtual bouncing ball. */ +/* Written by Olaf Matthes */ +/* Based on pong (for Max) version 1.5 written by Richard Dudas. */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" + +static char *version = "pong v0.1, ported by Olaf Matthes \n" + " written for Max by Richard Dudas"; + +typedef struct pong +{ + t_object x_obj; + t_outlet *p_bounceout; + t_outlet *p_handout; + t_outlet *p_velout; + t_outlet *p_heightout; + t_clock *p_klok; + + t_int p_ms; // ms count + t_float p_time; // current time div by warp + t_float p_timegrain; // timegrain in seconds + t_float p_timegrainin; // timegrain in ms + t_float p_warp; // timewarp in ms + + t_float p_dinit; // init distance + t_float p_vinit; // init velocity + t_float p_ainit; // base acceleration def -100 + t_float p_damping; // realtime multiplicative damping + t_float p_dhand; // virtual hand distance + t_float p_force; // force of hand 1.0 = no force + + t_float p_accel; // current accel value + t_float p_vi; // current velocity + t_float p_di; // current distance + t_float p_dt; // distance out + t_float p_dtprev; // previous distance out for accel computation + t_float p_vt; // velocity out + t_int p_prevchg; // for logical transition +} t_pong; + +/* ---------------------------------------------------------- */ +/* ---- this stuff is mainly for the timer, on off etc... --- */ +/* ---------------------------------------------------------- */ + +static void pong_reset(t_pong *x) +{ + x->p_di = x->p_dinit; + x->p_dt = x->p_dinit; // added + x->p_dtprev = x->p_dinit; // added + x->p_vi = x->p_vinit; + x->p_vt = x->p_vinit; // added + x->p_ms = 0; + x->p_time = 0.; + x->p_ainit = -100.; // added, but currently disabled + x->p_accel = -100.; // reactivated (?) + x->p_damping = 1.; // i.e. no initial damping + x->p_prevchg = 0; // added + +/* x->p_ms = 0; + x->p_time = 0.; + x->p_timegrain = 0.05; // if ms grain = 50 + x->p_timegrainin = 50; + + x->p_vinit = 0.; + x->p_dinit = 100.; + x->p_ainit = -100.; + x->p_damping = 1.; // i.e. no initial damping + x->p_dhand = 100.; + x->p_force = 1.; // i.e. hand does nothing initially + + x->p_accel = -100.; + x->p_vi = 0.; + x->p_di = 100.; + + x->p_dt = 100.; // changed from 0 to 100 + x->p_dtprev = 100.; // changed from 0 to 100 + x->p_vt = 0.; + x->p_prevchg = 0; +*/ +} + +/* ---------------------------------------------------------- */ + +static void pong_timein(t_pong *x, t_floatarg n) +{ + int thischg; + + x->p_time = n / x->p_warp; + + x->p_dt = ((x->p_accel * (x->p_time*x->p_time)) + (x->p_time * x->p_vi) + x->p_di); + x->p_vt = ((x->p_dt - x->p_dtprev) / x->p_timegrain); + + if (x->p_dt < 0.) + { + x->p_dt *= -1.; + + x->p_di = 0.; + x->p_vi = x->p_vt * (-1. * x->p_damping); // -1 will eventually be a damping variable + //post("vel at bounce %f", x->p_vi); + outlet_bang(x->p_bounceout); + x->p_ms = 0; + //x->p_dtprev= 0.; + } + //else + x->p_dtprev = x->p_dt; + + /* ---------------------------------- virtual hand below ------------ */ + + if (x->p_dt > x->p_dhand) // presuming the hand is initially equal to the dinit + thischg = 1; + else + thischg = 0; + + if (thischg != x->p_prevchg) + { + x->p_ms = 0; + x->p_vi = x->p_vt; + x->p_di = x->p_dhand; + + if (thischg == 0) + { + x->p_accel = -100.; // x->p_ainit in lieu of -100. + outlet_float(x->p_handout, 0); + } + else + { + x->p_accel = (x->p_force * -100.); // x->p_ainit in lieu of -100. + outlet_float(x->p_handout, 1); + } + } + + x->p_prevchg = thischg; + outlet_float(x->p_velout, x->p_vt); + outlet_float(x->p_heightout, x->p_dt); +} + +static void pong_onoff(t_pong *x, t_floatarg n) +{ + if (n != 0) + clock_delay(x->p_klok, 0); + else + clock_unset(x->p_klok); +} + +/* ---------------------------------------------------------- */ + +static void pong_bang(t_pong *x) +{ + x->p_ms = 0; + clock_delay(x->p_klok, 0); +} + +static void pong_stop(t_pong *x) +{ + clock_unset(x->p_klok); +} + +/* ---------------------------------------------------------- */ + +static void pong_tick(t_pong *x) +{ + clock_delay(x->p_klok, (t_int)x->p_timegrainin); + pong_timein(x, x->p_ms); + //outlet_float(x->p_heightout, (float)x->p_ms); + x->p_ms = x->p_ms + x->p_timegrainin; +} + +/* ---------------------------------------------------------- */ + +static void pong_tgrain(t_pong *x, t_floatarg n) +{ + x->p_timegrain = n / x->p_warp; + x->p_timegrainin = n; + post("timegrain %f", x->p_timegrain); +} + +/* ---------------------------------------------------------- */ + +static void pong_warpin(t_pong *x, t_floatarg n) +{ + x->p_warp = n; + x->p_timegrain = x->p_timegrainin / x->p_warp; + post("timewarp %f ms = one sec", x->p_warp); +} + +/* ---------------------------------------------------------- */ +/* ----- these are to receive and store the init values ----- */ +/* ---------------------------------------------------------- */ + +static void pong_initdist(t_pong *x, t_floatarg n) +{ + x->p_dinit = n; +} + +static void pong_initvel(t_pong *x, t_floatarg n) +{ + x->p_vinit = n; +} + +static void pong_damp(t_pong *x, t_floatarg n) +{ + x->p_damping = n; +} + +/* ---------------------------------------------------------- */ + +static void pong_baseacc(t_pong *x, t_floatarg n) +{ + //post ("baseaccel currently disabled", 0); + x->p_ainit = n; + x->p_accel = x->p_ainit; +} + +/* ---------------------------------------------------------- */ + +static void pong_hand(t_pong *x, t_floatarg n) +{ + x->p_dhand = n; +} + +static void pong_force(t_pong *x, t_floatarg n) +{ + x->p_force = n; +} + +/* ---------------------------------------------------------- */ + + +static t_class *pong_class; + +static void *pong_new(t_floatarg n) +{ + t_pong *x = (t_pong *)pd_new(pong_class); + + x->p_klok = clock_new(x, (t_method)pong_tick); + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("dist")); // distance + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("velo")); // velocity + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("damp")); // damping + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("force")); // hand force 1.0 = no force + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("hand")); // virtual hand (distance) + + + if (n > 0) + x->p_warp = n; + else + x->p_warp = 1000.; + + x->p_ms = 0; + x->p_time = 0.; + x->p_timegrain = 0.05; // if ms grain = 50 + x->p_timegrainin = 50.0; + + x->p_vinit = 0.; + x->p_dinit = 100.; + x->p_ainit = -100.; + x->p_damping = 1.; // i.e. no initial damping + x->p_dhand = 100.; + x->p_force = 1.; // i.e. hand does nothing initially + + x->p_accel = -100.; + x->p_vi = 0.; + x->p_di = 100.; + + x->p_dt = 100.; // changed from 0 to 100 + x->p_dtprev = 100.; // changed from 0 to 100 + x->p_vt = 0.; + x->p_prevchg = 0; + + x->p_bounceout = outlet_new(&x->x_obj, gensym("bang")); + x->p_handout = outlet_new(&x->x_obj, gensym("float")); + x->p_velout = outlet_new(&x->x_obj, gensym("float")); + x->p_heightout = outlet_new(&x->x_obj, gensym("float")); + + return (x); +} + +#ifndef MAXLIB +void pong_setup(void) +{ + pong_class = class_new(gensym("pong"), (t_newmethod)pong_new, + 0, sizeof(t_pong), 0, A_DEFFLOAT, 0); +#else +void maxlib_pong_setup(void) +{ + pong_class = class_new(gensym("maxlib_pong"), (t_newmethod)pong_new, + 0, sizeof(t_pong), 0, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)pong_new, gensym("pong"), A_DEFFLOAT, 0); +#endif + /* method handlers for inlets */ + class_addmethod(pong_class, (t_method)pong_initdist, gensym("dist"), A_FLOAT, 0); + class_addmethod(pong_class, (t_method)pong_initvel, gensym("velo"), A_FLOAT, 0); + class_addmethod(pong_class, (t_method)pong_damp, gensym("damp"), A_FLOAT, 0); + class_addmethod(pong_class, (t_method)pong_force, gensym("force"), A_FLOAT, 0); + class_addmethod(pong_class, (t_method)pong_hand, gensym("hand"), A_FLOAT, 0); + /* method handlers for other messages to first inlet */ + class_addmethod(pong_class, (t_method)pong_tgrain, gensym("timegrain"), A_FLOAT, 0); + class_addmethod(pong_class, (t_method)pong_warpin, gensym("timewarp"), A_FLOAT, 0); + class_addmethod(pong_class, (t_method)pong_baseacc, gensym("baseaccel"), A_FLOAT, 0); + class_addmethod(pong_class, (t_method)pong_reset, gensym("reset"), 0); + class_addmethod(pong_class, (t_method)pong_stop, gensym("stop"), 0); + + class_addfloat(pong_class, pong_onoff); + class_addbang(pong_class, pong_bang); +#ifndef MAXLIB + + logpost(NULL, 4, version); +#else + class_sethelpsymbol(pong_class, gensym("maxlib/pong-help.pd")); +#endif +} diff --git a/pulse.c b/pulse.c index 4205315..6b7ca62 100644 --- a/pulse.c +++ b/pulse.c @@ -1,301 +1,301 @@ -/* --------------------------- pong ------------------------------------------ */ -/* */ -/* A more accurate replacement for the tempo object. */ -/* Written by Olaf Matthes */ -/* Based on pulse for Max written by James McCartney. */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -/* pulse.c ---- a more accurate replacement for the tempo object */ -/* updated for CW 68K / PPC summer 96 -RD */ -/* written for Max by James McCartney */ - -#include "m_pd.h" -#include - -static char *version = "pulse v0.1b, written by James McCartney for Max \n" - " ported to Pd by Olaf Matthes "; - -/* Pulse object data structure */ -typedef struct pulse -{ - t_object p_ob; - t_clock *p_clock; - t_outlet *p_out1; /* outlet */ - t_outlet *p_out2; /* outlet */ - t_int p_onoff, p_changenumer, p_changedenom; - t_int p_tempo, p_durnumer, p_durdenom, p_maxbeats, p_count; - double p_starttime, p_endtime, p_startremain, p_endremain, p_mspbquotient; - t_int p_newdurnumer, p_newdurdenom; - t_int p_mspbnumer, p_mspbdenom, p_mspbremainder; -} Pulse; - -static t_class *pulse_class; - -static void durcalc(Pulse *x) -{ - /* recalc duration */ - x->p_mspbnumer = 240000 * x->p_durnumer; - if (x->p_tempo * x->p_durdenom != 0) /* bug fix by Frank Barknecht */ - x->p_mspbdenom = x->p_tempo * x->p_durdenom; - x->p_mspbquotient = x->p_mspbnumer / x->p_mspbdenom; - x->p_mspbremainder = x->p_mspbnumer % x->p_mspbdenom; - if (x->p_mspbquotient < 5) { - x->p_mspbquotient = 5; - x->p_mspbremainder = 0; - } -} - -static void pulse_onoff(Pulse *x, t_floatarg f) -{ - int i = (int)f; - if (i && !x->p_onoff) { - x->p_onoff = 1; - x->p_count = 0; - outlet_float(x->p_out1, x->p_count); - if (x->p_changedenom) { - x->p_durdenom = x->p_newdurdenom; - x->p_changedenom = 0; - } - if (x->p_changenumer) { - x->p_durnumer = x->p_newdurnumer; - x->p_changenumer = 0; - } - durcalc(x); - x->p_startremain = 0; - x->p_endremain = x->p_mspbremainder; - x->p_starttime = clock_getlogicaltime(); - x->p_endtime = x->p_starttime + x->p_mspbquotient; - // clock_set(x->p_clock, x->p_endtime); - clock_delay(x->p_clock, x->p_mspbquotient); - } else if (i==0 && x->p_onoff) { - x->p_onoff = 0; - clock_unset(x->p_clock); - } -} - -static void pulse_bang(Pulse *x) -{ - if (!x->p_onoff) { - x->p_onoff = 1; - x->p_count = 0; - outlet_float(x->p_out1, x->p_count); - if (x->p_changedenom) { - x->p_durdenom = x->p_newdurdenom; - x->p_changedenom = 0; - } - if (x->p_changenumer) { - x->p_durnumer = x->p_newdurnumer; - x->p_changenumer = 0; - } - durcalc(x); - x->p_startremain = 0; - x->p_endremain = x->p_mspbremainder; - x->p_starttime = clock_getlogicaltime(); - x->p_endtime = x->p_starttime + x->p_mspbquotient; - clock_set(x->p_clock, x->p_endtime); - } else { - x->p_onoff = 0; - clock_unset(x->p_clock); - } -} - -/* clock tick routine */ -static void pulse_tick(Pulse *x) -{ - x->p_count ++; - if ((x->p_maxbeats > 0) && (x->p_count >= x->p_maxbeats)) { /* turn off time */ - x->p_onoff = 0; - outlet_bang(x->p_out2); - } else { - outlet_float(x->p_out1, x->p_count); - x->p_startremain = x->p_endremain; /* save in case we have to re do it */ - if (x->p_changenumer || x->p_changedenom) { /* duration changed */ - if (x->p_changedenom) { - /* this statement may cause a slight drift of (1/(tempo*denom) msecs) */ - x->p_startremain = (x->p_startremain * x->p_newdurdenom + (x->p_durdenom>>1)) - /x->p_durdenom; - x->p_durdenom = x->p_newdurdenom; - x->p_changedenom = 0; - } - if (x->p_changenumer) { - x->p_durnumer = x->p_newdurnumer; - x->p_changenumer = 0; - } - durcalc(x); - } - x->p_endremain = x->p_startremain + x->p_mspbremainder; - x->p_starttime = x->p_endtime; - x->p_endtime = x->p_starttime + x->p_mspbquotient; - if (x->p_endremain >= x->p_mspbdenom) { - x->p_endremain -= x->p_mspbdenom; - x->p_endtime ++; - } - // clock_set(x->p_clock, x->p_endtime); - clock_delay(x->p_clock, x->p_mspbquotient); - } -} - -/* deal with tempo change */ -static void pulse_tempo(Pulse *x, t_floatarg t) -{ - double time, msecdur, tickdur, fracremain; - t_int fracnumer, fracquotient, oldtempo; - oldtempo = x->p_tempo; - x->p_tempo = (t<5) ? 5 : ((t>500) ? 500 : t); - if (x->p_onoff) { - /* calculate fraction of the beat we have done */ - time = clock_getlogicaltime(); - if (time != x->p_endtime) { - /* if pulse_tempo is called as a result of a call from pulse_tick - (call chain from outlet_float()) - then this stuff doesn't need to be done (time will == x->p_endtime) - */ - msecdur = time - x->p_starttime; - tickdur = msecdur * x->p_mspbdenom - x->p_startremain; - fracnumer = (t_int)(x->p_mspbnumer - tickdur); - - durcalc(x); - - /* calculate end time */ - fracquotient = fracnumer / x->p_mspbdenom; - fracremain = fracnumer % x->p_mspbdenom; - - x->p_endtime = time + fracquotient; - x->p_endremain = fracremain; - - /* recalculate starttime so future tempo changes work */ - x->p_starttime = x->p_endtime - x->p_mspbquotient; - x->p_startremain = x->p_mspbdenom - x->p_mspbremainder + fracremain; - if (x->p_mspbremainder > fracremain) { - x->p_startremain = x->p_mspbdenom - x->p_mspbremainder + fracremain; - x->p_starttime --; - } else { - x->p_startremain = fracremain - x->p_mspbremainder; - } - clock_unset(x->p_clock); - clock_set(x->p_clock, x->p_endtime); - // clock_delay(x->p_clock, fracquotient); - } - } -} - -static void pulse_numer(Pulse *x, t_floatarg n) -{ - int i = (t_int)n; - if(i >= 0) - { - if (x->p_onoff) { - if (x->p_durnumer != i) { - x->p_changenumer = 1; - x->p_newdurnumer = i; - } - } else { - x->p_durnumer = i; - } - } -} - -static void pulse_denom(Pulse *x, t_floatarg n) -{ - int i = (t_int)n; - if(i >= 0) - { - if (x->p_onoff) { - if (x->p_durdenom != i) { - x->p_changedenom = 1; - x->p_newdurdenom = i; - } - } else { - x->p_durdenom = i; - } - } -} - -static void pulse_beat(Pulse *x, t_floatarg n) -{ - int i = (t_int)n; - if(i >= 0) - { - x->p_maxbeats = i; - } -} - - -static void pulse_free(Pulse *x) -{ - clock_free(x->p_clock); -} - - -/* function run to create a new instance of the Pulse class */ -static void *pulse_new(t_floatarg t, t_floatarg n, t_floatarg d, t_floatarg b) -{ - Pulse *x; - - x = (Pulse *)pd_new(pulse_class); /* allocates memory and sticks in an inlet */ - - inlet_new(&x->p_ob, &x->p_ob.ob_pd, gensym("float"), gensym("tempo")); - inlet_new(&x->p_ob, &x->p_ob.ob_pd, gensym("float"), gensym("numer")); - inlet_new(&x->p_ob, &x->p_ob.ob_pd, gensym("float"), gensym("denom")); - inlet_new(&x->p_ob, &x->p_ob.ob_pd, gensym("float"), gensym("beat")); - x->p_out1 = outlet_new(&x->p_ob, gensym("float")); - x->p_out2 = outlet_new(&x->p_ob, gensym("float")); - x->p_clock = clock_new(x, (t_method)pulse_tick); - x->p_tempo = (t==0) ? 120 : ((t<5) ? 5 : ((t>500) ? 500 : t)); - x->p_durnumer = (n<=0) ? 1 : n; - x->p_durdenom = (d<=0) ? 4 : d; - x->p_maxbeats = (b<=0) ? 0 : b; - x->p_changenumer = 0; - x->p_changedenom = 0; - x->p_onoff = 0; - - return (x); /* always return a copy of the created object */ -} - -#ifndef MAXLIB -void pulse_setup(void) -{ - pulse_class = class_new(gensym("pulse"), (t_newmethod)pulse_new, - (t_method)pulse_free, sizeof(Pulse), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addmethod(pulse_class, (t_method)pulse_beat, gensym("beat"), A_FLOAT, 0); - class_addmethod(pulse_class, (t_method)pulse_denom, gensym("denom"), A_FLOAT, 0); - class_addmethod(pulse_class, (t_method)pulse_numer, gensym("numer"), A_FLOAT, 0); - class_addmethod(pulse_class, (t_method)pulse_tempo, gensym("tempo"), A_FLOAT, 0); - class_addfloat(pulse_class, pulse_onoff); - class_addbang(pulse_class, pulse_bang); - - post(version); -} -#else -void maxlib_pulse_setup(void) -{ - pulse_class = class_new(gensym("maxlib_pulse"), (t_newmethod)pulse_new, - (t_method)pulse_free, sizeof(Pulse), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)pulse_new, gensym("pulse"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addmethod(pulse_class, (t_method)pulse_beat, gensym("beat"), A_FLOAT, 0); - class_addmethod(pulse_class, (t_method)pulse_denom, gensym("denom"), A_FLOAT, 0); - class_addmethod(pulse_class, (t_method)pulse_numer, gensym("numer"), A_FLOAT, 0); - class_addmethod(pulse_class, (t_method)pulse_tempo, gensym("tempo"), A_FLOAT, 0); - class_addfloat(pulse_class, pulse_onoff); - class_addbang(pulse_class, pulse_bang); - class_sethelpsymbol(pulse_class, gensym("maxlib/pulse-help.pd")); -} -#endif +/* --------------------------- pong ------------------------------------------ */ +/* */ +/* A more accurate replacement for the tempo object. */ +/* Written by Olaf Matthes */ +/* Based on pulse for Max written by James McCartney. */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +/* pulse.c ---- a more accurate replacement for the tempo object */ +/* updated for CW 68K / PPC summer 96 -RD */ +/* written for Max by James McCartney */ + +#include "m_pd.h" +#include + +static char *version = "pulse v0.1b, written by James McCartney for Max \n" + " ported to Pd by Olaf Matthes "; + +/* Pulse object data structure */ +typedef struct pulse +{ + t_object p_ob; + t_clock *p_clock; + t_outlet *p_out1; /* outlet */ + t_outlet *p_out2; /* outlet */ + t_int p_onoff, p_changenumer, p_changedenom; + t_int p_tempo, p_durnumer, p_durdenom, p_maxbeats, p_count; + double p_starttime, p_endtime, p_startremain, p_endremain, p_mspbquotient; + t_int p_newdurnumer, p_newdurdenom; + t_int p_mspbnumer, p_mspbdenom, p_mspbremainder; +} Pulse; + +static t_class *pulse_class; + +static void durcalc(Pulse *x) +{ + /* recalc duration */ + x->p_mspbnumer = 240000 * x->p_durnumer; + if (x->p_tempo * x->p_durdenom != 0) /* bug fix by Frank Barknecht */ + x->p_mspbdenom = x->p_tempo * x->p_durdenom; + x->p_mspbquotient = x->p_mspbnumer / x->p_mspbdenom; + x->p_mspbremainder = x->p_mspbnumer % x->p_mspbdenom; + if (x->p_mspbquotient < 5) { + x->p_mspbquotient = 5; + x->p_mspbremainder = 0; + } +} + +static void pulse_onoff(Pulse *x, t_floatarg f) +{ + int i = (int)f; + if (i && !x->p_onoff) { + x->p_onoff = 1; + x->p_count = 0; + outlet_float(x->p_out1, x->p_count); + if (x->p_changedenom) { + x->p_durdenom = x->p_newdurdenom; + x->p_changedenom = 0; + } + if (x->p_changenumer) { + x->p_durnumer = x->p_newdurnumer; + x->p_changenumer = 0; + } + durcalc(x); + x->p_startremain = 0; + x->p_endremain = x->p_mspbremainder; + x->p_starttime = clock_getlogicaltime(); + x->p_endtime = x->p_starttime + x->p_mspbquotient; + // clock_set(x->p_clock, x->p_endtime); + clock_delay(x->p_clock, x->p_mspbquotient); + } else if (i==0 && x->p_onoff) { + x->p_onoff = 0; + clock_unset(x->p_clock); + } +} + +static void pulse_bang(Pulse *x) +{ + if (!x->p_onoff) { + x->p_onoff = 1; + x->p_count = 0; + outlet_float(x->p_out1, x->p_count); + if (x->p_changedenom) { + x->p_durdenom = x->p_newdurdenom; + x->p_changedenom = 0; + } + if (x->p_changenumer) { + x->p_durnumer = x->p_newdurnumer; + x->p_changenumer = 0; + } + durcalc(x); + x->p_startremain = 0; + x->p_endremain = x->p_mspbremainder; + x->p_starttime = clock_getlogicaltime(); + x->p_endtime = x->p_starttime + x->p_mspbquotient; + clock_set(x->p_clock, x->p_endtime); + } else { + x->p_onoff = 0; + clock_unset(x->p_clock); + } +} + +/* clock tick routine */ +static void pulse_tick(Pulse *x) +{ + x->p_count ++; + if ((x->p_maxbeats > 0) && (x->p_count >= x->p_maxbeats)) { /* turn off time */ + x->p_onoff = 0; + outlet_bang(x->p_out2); + } else { + outlet_float(x->p_out1, x->p_count); + x->p_startremain = x->p_endremain; /* save in case we have to re do it */ + if (x->p_changenumer || x->p_changedenom) { /* duration changed */ + if (x->p_changedenom) { + /* this statement may cause a slight drift of (1/(tempo*denom) msecs) */ + x->p_startremain = (x->p_startremain * x->p_newdurdenom + (x->p_durdenom>>1)) + /x->p_durdenom; + x->p_durdenom = x->p_newdurdenom; + x->p_changedenom = 0; + } + if (x->p_changenumer) { + x->p_durnumer = x->p_newdurnumer; + x->p_changenumer = 0; + } + durcalc(x); + } + x->p_endremain = x->p_startremain + x->p_mspbremainder; + x->p_starttime = x->p_endtime; + x->p_endtime = x->p_starttime + x->p_mspbquotient; + if (x->p_endremain >= x->p_mspbdenom) { + x->p_endremain -= x->p_mspbdenom; + x->p_endtime ++; + } + // clock_set(x->p_clock, x->p_endtime); + clock_delay(x->p_clock, x->p_mspbquotient); + } +} + +/* deal with tempo change */ +static void pulse_tempo(Pulse *x, t_floatarg t) +{ + double time, msecdur, tickdur, fracremain; + t_int fracnumer, fracquotient, oldtempo; + oldtempo = x->p_tempo; + x->p_tempo = (t<5) ? 5 : ((t>500) ? 500 : t); + if (x->p_onoff) { + /* calculate fraction of the beat we have done */ + time = clock_getlogicaltime(); + if (time != x->p_endtime) { + /* if pulse_tempo is called as a result of a call from pulse_tick + (call chain from outlet_float()) + then this stuff doesn't need to be done (time will == x->p_endtime) + */ + msecdur = time - x->p_starttime; + tickdur = msecdur * x->p_mspbdenom - x->p_startremain; + fracnumer = (t_int)(x->p_mspbnumer - tickdur); + + durcalc(x); + + /* calculate end time */ + fracquotient = fracnumer / x->p_mspbdenom; + fracremain = fracnumer % x->p_mspbdenom; + + x->p_endtime = time + fracquotient; + x->p_endremain = fracremain; + + /* recalculate starttime so future tempo changes work */ + x->p_starttime = x->p_endtime - x->p_mspbquotient; + x->p_startremain = x->p_mspbdenom - x->p_mspbremainder + fracremain; + if (x->p_mspbremainder > fracremain) { + x->p_startremain = x->p_mspbdenom - x->p_mspbremainder + fracremain; + x->p_starttime --; + } else { + x->p_startremain = fracremain - x->p_mspbremainder; + } + clock_unset(x->p_clock); + clock_set(x->p_clock, x->p_endtime); + // clock_delay(x->p_clock, fracquotient); + } + } +} + +static void pulse_numer(Pulse *x, t_floatarg n) +{ + int i = (t_int)n; + if(i >= 0) + { + if (x->p_onoff) { + if (x->p_durnumer != i) { + x->p_changenumer = 1; + x->p_newdurnumer = i; + } + } else { + x->p_durnumer = i; + } + } +} + +static void pulse_denom(Pulse *x, t_floatarg n) +{ + int i = (t_int)n; + if(i >= 0) + { + if (x->p_onoff) { + if (x->p_durdenom != i) { + x->p_changedenom = 1; + x->p_newdurdenom = i; + } + } else { + x->p_durdenom = i; + } + } +} + +static void pulse_beat(Pulse *x, t_floatarg n) +{ + int i = (t_int)n; + if(i >= 0) + { + x->p_maxbeats = i; + } +} + + +static void pulse_free(Pulse *x) +{ + clock_free(x->p_clock); +} + + +/* function run to create a new instance of the Pulse class */ +static void *pulse_new(t_floatarg t, t_floatarg n, t_floatarg d, t_floatarg b) +{ + Pulse *x; + + x = (Pulse *)pd_new(pulse_class); /* allocates memory and sticks in an inlet */ + + inlet_new(&x->p_ob, &x->p_ob.ob_pd, gensym("float"), gensym("tempo")); + inlet_new(&x->p_ob, &x->p_ob.ob_pd, gensym("float"), gensym("numer")); + inlet_new(&x->p_ob, &x->p_ob.ob_pd, gensym("float"), gensym("denom")); + inlet_new(&x->p_ob, &x->p_ob.ob_pd, gensym("float"), gensym("beat")); + x->p_out1 = outlet_new(&x->p_ob, gensym("float")); + x->p_out2 = outlet_new(&x->p_ob, gensym("float")); + x->p_clock = clock_new(x, (t_method)pulse_tick); + x->p_tempo = (t==0) ? 120 : ((t<5) ? 5 : ((t>500) ? 500 : t)); + x->p_durnumer = (n<=0) ? 1 : n; + x->p_durdenom = (d<=0) ? 4 : d; + x->p_maxbeats = (b<=0) ? 0 : b; + x->p_changenumer = 0; + x->p_changedenom = 0; + x->p_onoff = 0; + + return (x); /* always return a copy of the created object */ +} + +#ifndef MAXLIB +void pulse_setup(void) +{ + pulse_class = class_new(gensym("pulse"), (t_newmethod)pulse_new, + (t_method)pulse_free, sizeof(Pulse), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addmethod(pulse_class, (t_method)pulse_beat, gensym("beat"), A_FLOAT, 0); + class_addmethod(pulse_class, (t_method)pulse_denom, gensym("denom"), A_FLOAT, 0); + class_addmethod(pulse_class, (t_method)pulse_numer, gensym("numer"), A_FLOAT, 0); + class_addmethod(pulse_class, (t_method)pulse_tempo, gensym("tempo"), A_FLOAT, 0); + class_addfloat(pulse_class, pulse_onoff); + class_addbang(pulse_class, pulse_bang); + + logpost(NULL, 4, version); +} +#else +void maxlib_pulse_setup(void) +{ + pulse_class = class_new(gensym("maxlib_pulse"), (t_newmethod)pulse_new, + (t_method)pulse_free, sizeof(Pulse), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)pulse_new, gensym("pulse"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addmethod(pulse_class, (t_method)pulse_beat, gensym("beat"), A_FLOAT, 0); + class_addmethod(pulse_class, (t_method)pulse_denom, gensym("denom"), A_FLOAT, 0); + class_addmethod(pulse_class, (t_method)pulse_numer, gensym("numer"), A_FLOAT, 0); + class_addmethod(pulse_class, (t_method)pulse_tempo, gensym("tempo"), A_FLOAT, 0); + class_addfloat(pulse_class, pulse_onoff); + class_addbang(pulse_class, pulse_bang); + class_sethelpsymbol(pulse_class, gensym("maxlib/pulse-help.pd")); +} +#endif diff --git a/remote.c b/remote.c index 4cdcff5..a407d9c 100644 --- a/remote.c +++ b/remote.c @@ -1,108 +1,108 @@ -/* ------------------------ remote ------------------------------------------ */ -/* */ -/* Send data to receive obejct . */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.de/puredata/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" - -#include -#include - -#define MAX_REC 64 /* maximum number of receive objects */ -#define MAX_ARG 64 /* maximum number of arguments to pass on */ - -static char *version = "remote v0.2, written by Olaf Matthes "; - -static t_class *remote_class; - -typedef struct _remote -{ - t_object x_obj; - t_symbol *x_prefix; - t_int x_prepend; -} t_remote; - - /* send 'anything' to receiver */ -static void remote_anything(t_remote *x, t_symbol *s, int argc, t_atom *argv) -{ - int i; - t_atom av[MAX_ARG]; /* the 'new' t_atom without first element */ - t_int ac = argc - 1; /* the 'new' number of arguments */ - char mysym[MAXPDSTRING]; - t_symbol *target; - - if(argc < 1) /* need */ - { - post("remote: too few arguments!"); - return; - } - if(ac > MAX_ARG) - { - post("remote: too many arguments!"); - return; - } - - for(i = 1; i < argc; i++) - { - av[i - 1] = argv[i]; /* just copy, don't care about types */ - } - /* send only argument-part to receivers */ - if(x->x_prepend) - { - sprintf(mysym,"%s%s", x->x_prefix->s_name, s->s_name); - target = gensym(mysym); - if (target->s_thing) pd_forwardmess(target->s_thing, argc, argv); - } - else - if (s->s_thing) pd_forwardmess(s->s_thing, argc, argv); -} - -static void *remote_new(t_symbol *s) -{ - t_remote *x = (t_remote *)pd_new(remote_class); - - x->x_prefix = s; - if(x->x_prefix) x->x_prepend = 1; - else x->x_prepend = 0; - - return (x); -} - -#ifndef MAXLIB -void remote_setup(void) -{ - remote_class = class_new(gensym("remote"), (t_newmethod)remote_new, 0, - sizeof(t_remote), 0, A_DEFSYM, 0); - class_addanything(remote_class, remote_anything); - - post(version); -} -#else -void maxlib_remote_setup(void) -{ - remote_class = class_new(gensym("maxlib_remote"), (t_newmethod)remote_new, 0, - sizeof(t_remote), 0, A_DEFSYM, 0); - class_addcreator((t_newmethod)remote_new, gensym("remote"), A_DEFSYM, 0); - class_addanything(remote_class, remote_anything); - class_sethelpsymbol(remote_class, gensym("maxlib/remote-help.pd")); -} -#endif +/* ------------------------ remote ------------------------------------------ */ +/* */ +/* Send data to receive obejct . */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.de/puredata/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" + +#include +#include + +#define MAX_REC 64 /* maximum number of receive objects */ +#define MAX_ARG 64 /* maximum number of arguments to pass on */ + +static char *version = "remote v0.2, written by Olaf Matthes "; + +static t_class *remote_class; + +typedef struct _remote +{ + t_object x_obj; + t_symbol *x_prefix; + t_int x_prepend; +} t_remote; + + /* send 'anything' to receiver */ +static void remote_anything(t_remote *x, t_symbol *s, int argc, t_atom *argv) +{ + int i; + t_atom av[MAX_ARG]; /* the 'new' t_atom without first element */ + t_int ac = argc - 1; /* the 'new' number of arguments */ + char mysym[MAXPDSTRING]; + t_symbol *target; + + if(argc < 1) /* need */ + { + post("remote: too few arguments!"); + return; + } + if(ac > MAX_ARG) + { + post("remote: too many arguments!"); + return; + } + + for(i = 1; i < argc; i++) + { + av[i - 1] = argv[i]; /* just copy, don't care about types */ + } + /* send only argument-part to receivers */ + if(x->x_prepend) + { + sprintf(mysym,"%s%s", x->x_prefix->s_name, s->s_name); + target = gensym(mysym); + if (target->s_thing) pd_forwardmess(target->s_thing, argc, argv); + } + else + if (s->s_thing) pd_forwardmess(s->s_thing, argc, argv); +} + +static void *remote_new(t_symbol *s) +{ + t_remote *x = (t_remote *)pd_new(remote_class); + + x->x_prefix = s; + if(x->x_prefix) x->x_prepend = 1; + else x->x_prepend = 0; + + return (x); +} + +#ifndef MAXLIB +void remote_setup(void) +{ + remote_class = class_new(gensym("remote"), (t_newmethod)remote_new, 0, + sizeof(t_remote), 0, A_DEFSYM, 0); + class_addanything(remote_class, remote_anything); + + logpost(NULL, 4, version); +} +#else +void maxlib_remote_setup(void) +{ + remote_class = class_new(gensym("maxlib_remote"), (t_newmethod)remote_new, 0, + sizeof(t_remote), 0, A_DEFSYM, 0); + class_addcreator((t_newmethod)remote_new, gensym("remote"), A_DEFSYM, 0); + class_addanything(remote_class, remote_anything); + class_sethelpsymbol(remote_class, gensym("maxlib/remote-help.pd")); +} +#endif diff --git a/rewrap.c b/rewrap.c index e429dc0..40b7df5 100644 --- a/rewrap.c +++ b/rewrap.c @@ -1,155 +1,155 @@ -/* ------------------------- rewrap ------------------------------------------ */ -/* */ -/* rewraps input to lie within an output range. */ -/* Written by Olaf Matthes */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include -#include - -static char *version = "rewrap v0.1, written by Olaf Matthes "; - -typedef struct rewrap -{ - t_object x_ob; - t_float x_min; /* low border of input range */ - t_float x_max; /* high border of input range */ - t_outlet *x_outlet1; /* path-through outlet */ - t_outlet *x_outlet2; /* rewrap outlet */ -} t_rewrap; - -static void rewrap_float(t_rewrap *x, t_floatarg f) -{ - t_float min = x->x_min; - t_float max = x->x_max; - t_float range = 2.0f * (max - min); - t_int i; - - if(range == 0.0f) - { - f = min; - outlet_float(x->x_outlet2, 0); - } - else if(f < min) - { - float diff = min - f; - float n = ceil(diff / range); - - f += n * range; - - if(f >= max) - { - f = 2 * max - f; - n -= 0.5; - } - - outlet_float(x->x_outlet2, (t_int)(-2.0f * n)); - } - else if (f >= max) - { - float diff = f - max; - float n = floor(diff / range) + 1.0f; - - f -= n * range; - - if(f < min) - { - f = 2 * min - f; - n -= 0.5; - } - - outlet_float(x->x_outlet2, (t_int)(2.0f * n)); - } - else - outlet_float(x->x_outlet2, 0.0f); - - - outlet_float(x->x_outlet1, f); -} - -static void rewrap_a(t_rewrap *x, t_floatarg a) -{ - t_float max = x->x_max; - - if(a <= max) - x->x_min = a; - else - { - x->x_min = max; - x->x_max = a; - } -} - -static void rewrap_b(t_rewrap *x, t_floatarg b) -{ - t_float min = x->x_min; - - if(b >= min) - x->x_max = b; - else - { - x->x_max = min; - x->x_min = b; - } -} - -static t_class *rewrap_class; - -static void *rewrap_new(t_floatarg fmin, t_floatarg fmax) -{ - t_rewrap *x = (t_rewrap *)pd_new(rewrap_class); - - inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("a")); - inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("b")); - - x->x_outlet1 = outlet_new(&x->x_ob, gensym("float")); - x->x_outlet2 = outlet_new(&x->x_ob, gensym("float")); - - x->x_min = fmin; - rewrap_b(x, fmax); - - return (void *)x; -} - -#ifndef MAXLIB -void rewrap_setup(void) -{ - rewrap_class = class_new(gensym("rewrap"), (t_newmethod)rewrap_new, - 0, sizeof(t_rewrap), 0, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addfloat(rewrap_class, rewrap_float); - class_addmethod(rewrap_class, (t_method)rewrap_a, gensym("a"), A_FLOAT, 0); - class_addmethod(rewrap_class, (t_method)rewrap_b, gensym("b"), A_FLOAT, 0); - - post(version); -} -#else -void maxlib_rewrap_setup(void) -{ - rewrap_class = class_new(gensym("maxlib_rewrap"), (t_newmethod)rewrap_new, - 0, sizeof(t_rewrap), 0, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)rewrap_new, gensym("rewrap"), A_DEFFLOAT, A_DEFFLOAT, 0); - class_addfloat(rewrap_class, rewrap_float); - class_addmethod(rewrap_class, (t_method)rewrap_a, gensym("a"), A_FLOAT, 0); - class_addmethod(rewrap_class, (t_method)rewrap_b, gensym("b"), A_FLOAT, 0); - class_sethelpsymbol(rewrap_class, gensym("maxlib/rewrap-help.pd")); -} -#endif +/* ------------------------- rewrap ------------------------------------------ */ +/* */ +/* rewraps input to lie within an output range. */ +/* Written by Olaf Matthes */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include +#include + +static char *version = "rewrap v0.1, written by Olaf Matthes "; + +typedef struct rewrap +{ + t_object x_ob; + t_float x_min; /* low border of input range */ + t_float x_max; /* high border of input range */ + t_outlet *x_outlet1; /* path-through outlet */ + t_outlet *x_outlet2; /* rewrap outlet */ +} t_rewrap; + +static void rewrap_float(t_rewrap *x, t_floatarg f) +{ + t_float min = x->x_min; + t_float max = x->x_max; + t_float range = 2.0f * (max - min); + t_int i; + + if(range == 0.0f) + { + f = min; + outlet_float(x->x_outlet2, 0); + } + else if(f < min) + { + float diff = min - f; + float n = ceil(diff / range); + + f += n * range; + + if(f >= max) + { + f = 2 * max - f; + n -= 0.5; + } + + outlet_float(x->x_outlet2, (t_int)(-2.0f * n)); + } + else if (f >= max) + { + float diff = f - max; + float n = floor(diff / range) + 1.0f; + + f -= n * range; + + if(f < min) + { + f = 2 * min - f; + n -= 0.5; + } + + outlet_float(x->x_outlet2, (t_int)(2.0f * n)); + } + else + outlet_float(x->x_outlet2, 0.0f); + + + outlet_float(x->x_outlet1, f); +} + +static void rewrap_a(t_rewrap *x, t_floatarg a) +{ + t_float max = x->x_max; + + if(a <= max) + x->x_min = a; + else + { + x->x_min = max; + x->x_max = a; + } +} + +static void rewrap_b(t_rewrap *x, t_floatarg b) +{ + t_float min = x->x_min; + + if(b >= min) + x->x_max = b; + else + { + x->x_max = min; + x->x_min = b; + } +} + +static t_class *rewrap_class; + +static void *rewrap_new(t_floatarg fmin, t_floatarg fmax) +{ + t_rewrap *x = (t_rewrap *)pd_new(rewrap_class); + + inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("a")); + inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("b")); + + x->x_outlet1 = outlet_new(&x->x_ob, gensym("float")); + x->x_outlet2 = outlet_new(&x->x_ob, gensym("float")); + + x->x_min = fmin; + rewrap_b(x, fmax); + + return (void *)x; +} + +#ifndef MAXLIB +void rewrap_setup(void) +{ + rewrap_class = class_new(gensym("rewrap"), (t_newmethod)rewrap_new, + 0, sizeof(t_rewrap), 0, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addfloat(rewrap_class, rewrap_float); + class_addmethod(rewrap_class, (t_method)rewrap_a, gensym("a"), A_FLOAT, 0); + class_addmethod(rewrap_class, (t_method)rewrap_b, gensym("b"), A_FLOAT, 0); + + logpost(NULL, 4, version); +} +#else +void maxlib_rewrap_setup(void) +{ + rewrap_class = class_new(gensym("maxlib_rewrap"), (t_newmethod)rewrap_new, + 0, sizeof(t_rewrap), 0, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)rewrap_new, gensym("rewrap"), A_DEFFLOAT, A_DEFFLOAT, 0); + class_addfloat(rewrap_class, rewrap_float); + class_addmethod(rewrap_class, (t_method)rewrap_a, gensym("a"), A_FLOAT, 0); + class_addmethod(rewrap_class, (t_method)rewrap_b, gensym("b"), A_FLOAT, 0); + class_sethelpsymbol(rewrap_class, gensym("maxlib/rewrap-help.pd")); +} +#endif diff --git a/rhythm.c b/rhythm.c index 197a143..774f07d 100644 --- a/rhythm.c +++ b/rhythm.c @@ -1,343 +1,343 @@ -/* --------------------------- rhythm ---------------------------------------- */ -/* */ -/* Detect the beats per minute of a MIDI stream. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Based on code written by Robert Rowe. */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include -#include -#ifndef _WIN32 -#include -#endif - -#define ALPHA 10 -#define ADAPT_ARRAY_SIZE 1000 - -#ifndef M_PI -#define M_PI 3.14159265358979 -#endif -#ifndef TWO_PI -#define TWO_PI 2.0*M_PI -#endif - -static char *version = "rhythm v0.1, written by Olaf Matthes "; - -typedef struct rhythm -{ - t_object x_ob; - t_clock *x_tick; - t_outlet *x_out_bpm; /* beats per minute */ - t_outlet *x_out_period; /* beats in milliseconds */ - t_outlet *x_out_pulse; - t_int x_print; /* switch printing to console window on / off */ - t_int x_ticking; /* indicates if clock is ticking or not */ - - t_int x_model; /* algorhythm to use: 0 - Large & Kolen, 1 - Toiviainen */ - t_float x_long_term[ADAPT_ARRAY_SIZE]; - t_float x_short_term[ADAPT_ARRAY_SIZE]; - t_float x_phi_at_pulse; /* phase at latest pulse */ - t_float x_phiVel_at_pulse; /* phase velocity */ - - t_float x_adapt; - t_float x_errFunc; /* error function */ - t_float x_etaLong; /* strength of long-term adaptation */ - t_float x_etaShort; /* strength of short-term adaptation */ - t_float x_gamma; /* gain parameter */ - double x_lastIoi; /* last inter-onset interval */ - double x_lastPulseTime; /* time of last pulse */ - t_float x_output; /* current output value of the oscillator */ - t_float x_phi; /* phase */ - double x_expected; /* estimated time of arrival */ - t_float x_period; - t_float x_periodStrength; - t_float x_phaseStrength; - double x_startTime; - - t_int x_pitch; - t_int x_velo; - /* helpers needed to do the time calculations */ - double x_last_input; -} t_rhythm; - -/* --------------- rhythm stuff ------------------------------------------------ */ - /* bang at the rhythm's pulse */ -static void rhythm_tick(t_rhythm *x) -{ - outlet_bang(x->x_out_pulse); - clock_delay(x->x_tick, x->x_period); -} - -static t_float rhythm_get_adapt_long(t_rhythm *x, t_float arg) -{ - int address; - if (arg > 1.0) - address = ADAPT_ARRAY_SIZE - 1; - else if (arg < -1.0) - address = ADAPT_ARRAY_SIZE - 1; - else - address = abs((int)(arg*1000.0)); - return x->x_long_term[address]; -} - -static t_float rhythm_get_adapt_short(t_rhythm *x, t_float arg) -{ - int address; - if (arg > 1.0) - address = ADAPT_ARRAY_SIZE - 1; - else if (arg < -1.0) - address = ADAPT_ARRAY_SIZE - 1; - else - address = abs((int)(arg*1000.0)); - return x->x_short_term[address]; -} - - - /* Large & Kolen adaptation model */ -static void rhythm_large(t_rhythm *x, t_int pulse, double time) -{ - while (time > (x->x_expected+(x->x_period/2))) // move the expectation point - x->x_expected += x->x_period; // to be within one period of onset - x->x_phi = (t_float)(time - x->x_expected) / x->x_period; // calculate phi - - if (pulse) { // if this was an onset - x->x_adapt = x->x_gamma * (cos(TWO_PI*x->x_phi)-1.0); - x->x_adapt = 1.0 / cosh(x->x_adapt); - x->x_adapt *= x->x_adapt; - x->x_adapt *= sin(TWO_PI*x->x_phi); - x->x_adapt *= (x->x_period / TWO_PI); - x->x_period += (x->x_periodStrength*x->x_adapt); // update period - x->x_expected += (x->x_phaseStrength *x->x_adapt); // and phase - x->x_phi = (t_float)(time - x->x_expected) / x->x_period; - } - - x->x_output = 1+tanh(x->x_gamma*(cos(TWO_PI*x->x_phi)-1.0)); // oscillator output -} - /* Toiviainen adaptation model */ -static void rhythm_toiviainen(t_rhythm *x, t_int pulse, double time) -{ - t_float deltaTime, varPhi, adaptLong, adaptShort; - - /* if just starting, initialize phi */ - if(x->x_lastPulseTime < 0) - { - x->x_phi = x->x_phi_at_pulse + x->x_phiVel_at_pulse * ((t_float)(time-x->x_startTime) / 1000.0); - } - else - { - deltaTime = time - x->x_lastPulseTime; - varPhi = (deltaTime/1000.0) * x->x_phiVel_at_pulse; - adaptLong = rhythm_get_adapt_long(x, varPhi); // get long adaptation from table - adaptShort = rhythm_get_adapt_short(x, varPhi); // get short adaptation from table - x->x_phi = x->x_phi_at_pulse + varPhi + x->x_errFunc * (x->x_etaLong*adaptLong + x->x_etaShort*adaptShort); - if (pulse) // change tempo if on pulse - x->x_phiVel_at_pulse = x->x_phiVel_at_pulse * (1 + x->x_etaLong * x->x_errFunc * adaptShort); - } - - if (pulse) { - x->x_output = 1+tanh(x->x_gamma*(cos(TWO_PI*x->x_phi)-1.0)); - x->x_errFunc = x->x_output * (x->x_output - 2.0) * sin(TWO_PI * x->x_phi); - x->x_phi_at_pulse = x->x_phi; - } - - x->x_period = 1000.0 / x->x_phiVel_at_pulse; // update period -} - -static void rhythm_move(t_rhythm *x, t_int pulse, double time) -{ - switch (x->x_model) /* choose adaptation model */ - { - case 0: - rhythm_large(x, pulse, time); - break; - - case 1: - rhythm_toiviainen(x, pulse, time); - break; - } - - if(x->x_ticking == 0) - { - x->x_ticking = 1; /* prevent us from further calls */ - clock_delay(x->x_tick, 0); /* start pulse bangs */ - } -} - - /* main processing function */ -static void rhythm_float(t_rhythm *x, t_floatarg f) -{ - t_int velo = x->x_velo; - double time = clock_gettimesince(x->x_last_input); - x->x_pitch = (t_int)f; - - if(velo != 0) /* note-on received */ - { - if (x->x_startTime == 0) { - x->x_startTime = time; - return; - } - - if (x->x_period < 2.0) { - x->x_period = (t_float)(time - x->x_startTime); - x->x_phiVel_at_pulse = 1000.0 / x->x_period; - } - - rhythm_move(x, 1, time); - - if (x->x_lastPulseTime >= 0) - { - x->x_lastIoi = time - x->x_lastPulseTime; - } - x->x_lastPulseTime = time; - x->x_last_input = clock_getlogicaltime(); - - outlet_float(x->x_out_period, x->x_period); - outlet_float(x->x_out_bpm, 60000.0/x->x_period); - } - return; -} - /* get velocity */ -static void rhythm_ft1(t_rhythm *x, t_floatarg f) -{ - x->x_velo = (t_int)f; -} - - /* toggle printing on/off (not used right now!) */ -static void rhythm_print(t_rhythm *x) -{ - if(x->x_print)x->x_print = 0; - else x->x_print = 1; -} - /* initialise array for Toiviainen adaptation model */ -static void rhythm_calculate_adaptations(t_rhythm *x) -{ - int i; - t_float f; - - for(i = 0; i < ADAPT_ARRAY_SIZE; i++) - { - f = (t_float)i/(t_float)ADAPT_ARRAY_SIZE; - x->x_long_term[i] = f+(ALPHA*f*f/2.0+2.0*f+3.0/ALPHA)*exp(-ALPHA*f)-3.0/ALPHA; - x->x_short_term[i] = 1.0-(ALPHA*ALPHA*f*f/2.0+ALPHA*f+1.0)*exp(-ALPHA*f); - } -} - -static void rhythm_reset(t_rhythm *x) -{ - if(x->x_ticking)clock_unset(x->x_tick); - x->x_ticking = 0; - - x->x_gamma = 1.0; /* default value for gain parameter */ - x->x_phi = 0.0; - x->x_output = 1+tanh(x->x_gamma*(cos(TWO_PI*x->x_phi)-1.0)); - x->x_expected = 0; - x->x_lastIoi = 0; - x->x_lastPulseTime = -1; - x->x_period = 1.0; - x->x_periodStrength = 0.2; - x->x_phaseStrength = 0.2; - - x->x_errFunc = 0.0; - x->x_etaLong = 0.2; - x->x_etaShort = 0.2; - x->x_phi_at_pulse = 0.0; - x->x_phiVel_at_pulse = 0.9; - x->x_startTime = 0; - - rhythm_calculate_adaptations(x); -} - -static void rhythm_model(t_rhythm *x, t_floatarg f) -{ - if(f == 1) - { - x->x_model = 1; /* Toiviainen model */ - rhythm_reset(x); - post("rhythm: using \"Toiviainen\" adaptation model"); - } - else - { - x->x_model = 0; /* Large and Kolen model */ - rhythm_reset(x); - post("rhythm: using \"Large and Kolen\" adaptation model"); - } -} - -static t_class *rhythm_class; - -static void rhythm_free(t_rhythm *x) -{ - clock_free(x->x_tick); -} - -static void *rhythm_new(t_floatarg f) -{ - t_rhythm *x = (t_rhythm *)pd_new(rhythm_class); - inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); - x->x_out_bpm = outlet_new(&x->x_ob, gensym("float")); - x->x_out_period = outlet_new(&x->x_ob, gensym("float")); - x->x_out_pulse = outlet_new(&x->x_ob, gensym("bang")); - x->x_tick = clock_new(x, (t_method)rhythm_tick); - - rhythm_reset(x); - - if(f == 1) - { - x->x_model = 1; /* Toiviainen model */ - post("rhythm: using \"Toiviainen\" adaptation model"); - } - else - { - x->x_model = 0; /* Large and Kolen model */ - post("rhythm: using \"Large and Kolen\" adaptation model"); - } - - return (void *)x; -} - -#ifndef MAXLIB -void rhythm_setup(void) -{ - rhythm_class = class_new(gensym("rhythm"), (t_newmethod)rhythm_new, - (t_method)rhythm_free, sizeof(t_rhythm), 0, A_DEFFLOAT, 0); - class_addfloat(rhythm_class, rhythm_float); - class_addmethod(rhythm_class, (t_method)rhythm_ft1, gensym("ft1"), A_FLOAT, 0); - class_addmethod(rhythm_class, (t_method)rhythm_model, gensym("model"), A_FLOAT, 0); - class_addmethod(rhythm_class, (t_method)rhythm_reset, gensym("reset"), 0); - class_addmethod(rhythm_class, (t_method)rhythm_print, gensym("print"), 0); - - post(version); -} -#else -void maxlib_rhythm_setup(void) -{ - rhythm_class = class_new(gensym("maxlib_rhythm"), (t_newmethod)rhythm_new, - (t_method)rhythm_free, sizeof(t_rhythm), 0, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)rhythm_new, gensym("rhythm"), A_DEFFLOAT, 0); - class_addfloat(rhythm_class, rhythm_float); - class_addmethod(rhythm_class, (t_method)rhythm_ft1, gensym("ft1"), A_FLOAT, 0); - class_addmethod(rhythm_class, (t_method)rhythm_model, gensym("model"), A_FLOAT, 0); - class_addmethod(rhythm_class, (t_method)rhythm_reset, gensym("reset"), 0); - class_addmethod(rhythm_class, (t_method)rhythm_print, gensym("print"), 0); - class_sethelpsymbol(rhythm_class, gensym("maxlib/rhythm-help.pd")); -} -#endif +/* --------------------------- rhythm ---------------------------------------- */ +/* */ +/* Detect the beats per minute of a MIDI stream. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Based on code written by Robert Rowe. */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include +#include +#ifndef _WIN32 +#include +#endif + +#define ALPHA 10 +#define ADAPT_ARRAY_SIZE 1000 + +#ifndef M_PI +#define M_PI 3.14159265358979 +#endif +#ifndef TWO_PI +#define TWO_PI 2.0*M_PI +#endif + +static char *version = "rhythm v0.1, written by Olaf Matthes "; + +typedef struct rhythm +{ + t_object x_ob; + t_clock *x_tick; + t_outlet *x_out_bpm; /* beats per minute */ + t_outlet *x_out_period; /* beats in milliseconds */ + t_outlet *x_out_pulse; + t_int x_print; /* switch printing to console window on / off */ + t_int x_ticking; /* indicates if clock is ticking or not */ + + t_int x_model; /* algorhythm to use: 0 - Large & Kolen, 1 - Toiviainen */ + t_float x_long_term[ADAPT_ARRAY_SIZE]; + t_float x_short_term[ADAPT_ARRAY_SIZE]; + t_float x_phi_at_pulse; /* phase at latest pulse */ + t_float x_phiVel_at_pulse; /* phase velocity */ + + t_float x_adapt; + t_float x_errFunc; /* error function */ + t_float x_etaLong; /* strength of long-term adaptation */ + t_float x_etaShort; /* strength of short-term adaptation */ + t_float x_gamma; /* gain parameter */ + double x_lastIoi; /* last inter-onset interval */ + double x_lastPulseTime; /* time of last pulse */ + t_float x_output; /* current output value of the oscillator */ + t_float x_phi; /* phase */ + double x_expected; /* estimated time of arrival */ + t_float x_period; + t_float x_periodStrength; + t_float x_phaseStrength; + double x_startTime; + + t_int x_pitch; + t_int x_velo; + /* helpers needed to do the time calculations */ + double x_last_input; +} t_rhythm; + +/* --------------- rhythm stuff ------------------------------------------------ */ + /* bang at the rhythm's pulse */ +static void rhythm_tick(t_rhythm *x) +{ + outlet_bang(x->x_out_pulse); + clock_delay(x->x_tick, x->x_period); +} + +static t_float rhythm_get_adapt_long(t_rhythm *x, t_float arg) +{ + int address; + if (arg > 1.0) + address = ADAPT_ARRAY_SIZE - 1; + else if (arg < -1.0) + address = ADAPT_ARRAY_SIZE - 1; + else + address = abs((int)(arg*1000.0)); + return x->x_long_term[address]; +} + +static t_float rhythm_get_adapt_short(t_rhythm *x, t_float arg) +{ + int address; + if (arg > 1.0) + address = ADAPT_ARRAY_SIZE - 1; + else if (arg < -1.0) + address = ADAPT_ARRAY_SIZE - 1; + else + address = abs((int)(arg*1000.0)); + return x->x_short_term[address]; +} + + + /* Large & Kolen adaptation model */ +static void rhythm_large(t_rhythm *x, t_int pulse, double time) +{ + while (time > (x->x_expected+(x->x_period/2))) // move the expectation point + x->x_expected += x->x_period; // to be within one period of onset + x->x_phi = (t_float)(time - x->x_expected) / x->x_period; // calculate phi + + if (pulse) { // if this was an onset + x->x_adapt = x->x_gamma * (cos(TWO_PI*x->x_phi)-1.0); + x->x_adapt = 1.0 / cosh(x->x_adapt); + x->x_adapt *= x->x_adapt; + x->x_adapt *= sin(TWO_PI*x->x_phi); + x->x_adapt *= (x->x_period / TWO_PI); + x->x_period += (x->x_periodStrength*x->x_adapt); // update period + x->x_expected += (x->x_phaseStrength *x->x_adapt); // and phase + x->x_phi = (t_float)(time - x->x_expected) / x->x_period; + } + + x->x_output = 1+tanh(x->x_gamma*(cos(TWO_PI*x->x_phi)-1.0)); // oscillator output +} + /* Toiviainen adaptation model */ +static void rhythm_toiviainen(t_rhythm *x, t_int pulse, double time) +{ + t_float deltaTime, varPhi, adaptLong, adaptShort; + + /* if just starting, initialize phi */ + if(x->x_lastPulseTime < 0) + { + x->x_phi = x->x_phi_at_pulse + x->x_phiVel_at_pulse * ((t_float)(time-x->x_startTime) / 1000.0); + } + else + { + deltaTime = time - x->x_lastPulseTime; + varPhi = (deltaTime/1000.0) * x->x_phiVel_at_pulse; + adaptLong = rhythm_get_adapt_long(x, varPhi); // get long adaptation from table + adaptShort = rhythm_get_adapt_short(x, varPhi); // get short adaptation from table + x->x_phi = x->x_phi_at_pulse + varPhi + x->x_errFunc * (x->x_etaLong*adaptLong + x->x_etaShort*adaptShort); + if (pulse) // change tempo if on pulse + x->x_phiVel_at_pulse = x->x_phiVel_at_pulse * (1 + x->x_etaLong * x->x_errFunc * adaptShort); + } + + if (pulse) { + x->x_output = 1+tanh(x->x_gamma*(cos(TWO_PI*x->x_phi)-1.0)); + x->x_errFunc = x->x_output * (x->x_output - 2.0) * sin(TWO_PI * x->x_phi); + x->x_phi_at_pulse = x->x_phi; + } + + x->x_period = 1000.0 / x->x_phiVel_at_pulse; // update period +} + +static void rhythm_move(t_rhythm *x, t_int pulse, double time) +{ + switch (x->x_model) /* choose adaptation model */ + { + case 0: + rhythm_large(x, pulse, time); + break; + + case 1: + rhythm_toiviainen(x, pulse, time); + break; + } + + if(x->x_ticking == 0) + { + x->x_ticking = 1; /* prevent us from further calls */ + clock_delay(x->x_tick, 0); /* start pulse bangs */ + } +} + + /* main processing function */ +static void rhythm_float(t_rhythm *x, t_floatarg f) +{ + t_int velo = x->x_velo; + double time = clock_gettimesince(x->x_last_input); + x->x_pitch = (t_int)f; + + if(velo != 0) /* note-on received */ + { + if (x->x_startTime == 0) { + x->x_startTime = time; + return; + } + + if (x->x_period < 2.0) { + x->x_period = (t_float)(time - x->x_startTime); + x->x_phiVel_at_pulse = 1000.0 / x->x_period; + } + + rhythm_move(x, 1, time); + + if (x->x_lastPulseTime >= 0) + { + x->x_lastIoi = time - x->x_lastPulseTime; + } + x->x_lastPulseTime = time; + x->x_last_input = clock_getlogicaltime(); + + outlet_float(x->x_out_period, x->x_period); + outlet_float(x->x_out_bpm, 60000.0/x->x_period); + } + return; +} + /* get velocity */ +static void rhythm_ft1(t_rhythm *x, t_floatarg f) +{ + x->x_velo = (t_int)f; +} + + /* toggle printing on/off (not used right now!) */ +static void rhythm_print(t_rhythm *x) +{ + if(x->x_print)x->x_print = 0; + else x->x_print = 1; +} + /* initialise array for Toiviainen adaptation model */ +static void rhythm_calculate_adaptations(t_rhythm *x) +{ + int i; + t_float f; + + for(i = 0; i < ADAPT_ARRAY_SIZE; i++) + { + f = (t_float)i/(t_float)ADAPT_ARRAY_SIZE; + x->x_long_term[i] = f+(ALPHA*f*f/2.0+2.0*f+3.0/ALPHA)*exp(-ALPHA*f)-3.0/ALPHA; + x->x_short_term[i] = 1.0-(ALPHA*ALPHA*f*f/2.0+ALPHA*f+1.0)*exp(-ALPHA*f); + } +} + +static void rhythm_reset(t_rhythm *x) +{ + if(x->x_ticking)clock_unset(x->x_tick); + x->x_ticking = 0; + + x->x_gamma = 1.0; /* default value for gain parameter */ + x->x_phi = 0.0; + x->x_output = 1+tanh(x->x_gamma*(cos(TWO_PI*x->x_phi)-1.0)); + x->x_expected = 0; + x->x_lastIoi = 0; + x->x_lastPulseTime = -1; + x->x_period = 1.0; + x->x_periodStrength = 0.2; + x->x_phaseStrength = 0.2; + + x->x_errFunc = 0.0; + x->x_etaLong = 0.2; + x->x_etaShort = 0.2; + x->x_phi_at_pulse = 0.0; + x->x_phiVel_at_pulse = 0.9; + x->x_startTime = 0; + + rhythm_calculate_adaptations(x); +} + +static void rhythm_model(t_rhythm *x, t_floatarg f) +{ + if(f == 1) + { + x->x_model = 1; /* Toiviainen model */ + rhythm_reset(x); + post("rhythm: using \"Toiviainen\" adaptation model"); + } + else + { + x->x_model = 0; /* Large and Kolen model */ + rhythm_reset(x); + post("rhythm: using \"Large and Kolen\" adaptation model"); + } +} + +static t_class *rhythm_class; + +static void rhythm_free(t_rhythm *x) +{ + clock_free(x->x_tick); +} + +static void *rhythm_new(t_floatarg f) +{ + t_rhythm *x = (t_rhythm *)pd_new(rhythm_class); + inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); + x->x_out_bpm = outlet_new(&x->x_ob, gensym("float")); + x->x_out_period = outlet_new(&x->x_ob, gensym("float")); + x->x_out_pulse = outlet_new(&x->x_ob, gensym("bang")); + x->x_tick = clock_new(x, (t_method)rhythm_tick); + + rhythm_reset(x); + + if(f == 1) + { + x->x_model = 1; /* Toiviainen model */ + post("rhythm: using \"Toiviainen\" adaptation model"); + } + else + { + x->x_model = 0; /* Large and Kolen model */ + post("rhythm: using \"Large and Kolen\" adaptation model"); + } + + return (void *)x; +} + +#ifndef MAXLIB +void rhythm_setup(void) +{ + rhythm_class = class_new(gensym("rhythm"), (t_newmethod)rhythm_new, + (t_method)rhythm_free, sizeof(t_rhythm), 0, A_DEFFLOAT, 0); + class_addfloat(rhythm_class, rhythm_float); + class_addmethod(rhythm_class, (t_method)rhythm_ft1, gensym("ft1"), A_FLOAT, 0); + class_addmethod(rhythm_class, (t_method)rhythm_model, gensym("model"), A_FLOAT, 0); + class_addmethod(rhythm_class, (t_method)rhythm_reset, gensym("reset"), 0); + class_addmethod(rhythm_class, (t_method)rhythm_print, gensym("print"), 0); + + logpost(NULL, 4, version); +} +#else +void maxlib_rhythm_setup(void) +{ + rhythm_class = class_new(gensym("maxlib_rhythm"), (t_newmethod)rhythm_new, + (t_method)rhythm_free, sizeof(t_rhythm), 0, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)rhythm_new, gensym("rhythm"), A_DEFFLOAT, 0); + class_addfloat(rhythm_class, rhythm_float); + class_addmethod(rhythm_class, (t_method)rhythm_ft1, gensym("ft1"), A_FLOAT, 0); + class_addmethod(rhythm_class, (t_method)rhythm_model, gensym("model"), A_FLOAT, 0); + class_addmethod(rhythm_class, (t_method)rhythm_reset, gensym("reset"), 0); + class_addmethod(rhythm_class, (t_method)rhythm_print, gensym("print"), 0); + class_sethelpsymbol(rhythm_class, gensym("maxlib/rhythm-help.pd")); +} +#endif diff --git a/scale.c b/scale.c index 890b38d..3654249 100644 --- a/scale.c +++ b/scale.c @@ -1,138 +1,138 @@ -/* ------------------------- scale ------------------------------------------ */ -/* */ -/* Scales input to lie within an output range. */ -/* Written by Olaf Matthes */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include -#include - -static char *version = "scale v0.2, written by Olaf Matthes "; - -typedef struct scale -{ - t_object x_ob; - t_float x_f; /* current input value */ - t_float x_il; /* low border of input range */ - t_float x_ih; /* high border of input range */ - t_float x_ol; /* low border of output range */ - t_float x_oh; /* high border of output range */ - t_float x_logcoeff; /* log-coefficient */ - t_outlet *x_outlet1; /* result */ -} t_scale; - -static void scale_float(t_scale *x, t_floatarg f) -{ - t_float ir = x->x_ih - x->x_il; - t_float or = x->x_oh - x->x_ol; - double oq; - double result; - double k; - if(ir == 0) - { - post("scale: input range must not be 0"); - return; - } - /* we accept an output range of 0 in case someone really wants this */ - if(!x->x_logcoeff) /* linear */ - { - k = (or / ir); - result = ((f - x->x_il) * k) + x->x_ol; - } - else /* logarythmical scale */ - { - oq = x->x_oh / x->x_ol; - // k = (log((double)oq)/log(x->x_logcoeff))/((double)ir); - k = log((double)oq)/((double)ir); - - if(x->x_ol) - { - // result = (double)x->x_ol*exp(k*(double)(f - x->x_il)*log(x->x_logcoeff)); - result = (double)x->x_ol*exp(k*(double)(f - x->x_il)); - } - else - { - /* in case the low output is 0 we have to cheat... */ - /* okay, here's the chating: we calculate for a lower out limit - of 1 and remove this shift after the calculation */ - result = ((double)(x->x_ol+1)*exp(k*(double)(f - x->x_il)))-1.0; - } - } - - x->x_f = f; /* save current input value */ - - outlet_float(x->x_outlet1, result); -} - -static void scale_bang(t_scale *x) -{ - scale_float(x, x->x_f); /* recalculate result */ -} - -static t_class *scale_class; - -static void *scale_new(t_floatarg fil, t_floatarg fih, t_floatarg fol, t_floatarg foh, t_floatarg flc) -{ - t_scale *x = (t_scale *)pd_new(scale_class); - - floatinlet_new(&x->x_ob, &x->x_il); - floatinlet_new(&x->x_ob, &x->x_ih); - floatinlet_new(&x->x_ob, &x->x_ol); - floatinlet_new(&x->x_ob, &x->x_oh); - floatinlet_new(&x->x_ob, &x->x_logcoeff); - - x->x_outlet1 = outlet_new(&x->x_ob, gensym("float")); - - /* default values taken from Max's scale */ - x->x_il = fil; - x->x_ih = fih; - if(!x->x_ih)x->x_ih = 127.0; - x->x_ol = fol; - x->x_oh = foh; - if(!x->x_oh)x->x_oh = 1.0; - x->x_logcoeff = flc; - x->x_f = 0; - - return (void *)x; -} - -#ifndef MAXLIB -void scale_setup(void) -{ - scale_class = class_new(gensym("scale"), (t_newmethod)scale_new, - 0, sizeof(t_scale), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addfloat(scale_class, scale_float); - class_addbang(scale_class, scale_bang); - - post(version); -#else -void maxlib_scale_setup(void) -{ - scale_class = class_new(gensym("maxlib_scale"), (t_newmethod)scale_new, - 0, sizeof(t_scale), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)scale_new, gensym("scale"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addfloat(scale_class, scale_float); - class_addbang(scale_class, scale_bang); - class_sethelpsymbol(scale_class, gensym("maxlib/scale-help.pd")); -#endif -} - +/* ------------------------- scale ------------------------------------------ */ +/* */ +/* Scales input to lie within an output range. */ +/* Written by Olaf Matthes */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include +#include + +static char *version = "scale v0.2, written by Olaf Matthes "; + +typedef struct scale +{ + t_object x_ob; + t_float x_f; /* current input value */ + t_float x_il; /* low border of input range */ + t_float x_ih; /* high border of input range */ + t_float x_ol; /* low border of output range */ + t_float x_oh; /* high border of output range */ + t_float x_logcoeff; /* log-coefficient */ + t_outlet *x_outlet1; /* result */ +} t_scale; + +static void scale_float(t_scale *x, t_floatarg f) +{ + t_float ir = x->x_ih - x->x_il; + t_float or = x->x_oh - x->x_ol; + double oq; + double result; + double k; + if(ir == 0) + { + post("scale: input range must not be 0"); + return; + } + /* we accept an output range of 0 in case someone really wants this */ + if(!x->x_logcoeff) /* linear */ + { + k = (or / ir); + result = ((f - x->x_il) * k) + x->x_ol; + } + else /* logarythmical scale */ + { + oq = x->x_oh / x->x_ol; + // k = (log((double)oq)/log(x->x_logcoeff))/((double)ir); + k = log((double)oq)/((double)ir); + + if(x->x_ol) + { + // result = (double)x->x_ol*exp(k*(double)(f - x->x_il)*log(x->x_logcoeff)); + result = (double)x->x_ol*exp(k*(double)(f - x->x_il)); + } + else + { + /* in case the low output is 0 we have to cheat... */ + /* okay, here's the chating: we calculate for a lower out limit + of 1 and remove this shift after the calculation */ + result = ((double)(x->x_ol+1)*exp(k*(double)(f - x->x_il)))-1.0; + } + } + + x->x_f = f; /* save current input value */ + + outlet_float(x->x_outlet1, result); +} + +static void scale_bang(t_scale *x) +{ + scale_float(x, x->x_f); /* recalculate result */ +} + +static t_class *scale_class; + +static void *scale_new(t_floatarg fil, t_floatarg fih, t_floatarg fol, t_floatarg foh, t_floatarg flc) +{ + t_scale *x = (t_scale *)pd_new(scale_class); + + floatinlet_new(&x->x_ob, &x->x_il); + floatinlet_new(&x->x_ob, &x->x_ih); + floatinlet_new(&x->x_ob, &x->x_ol); + floatinlet_new(&x->x_ob, &x->x_oh); + floatinlet_new(&x->x_ob, &x->x_logcoeff); + + x->x_outlet1 = outlet_new(&x->x_ob, gensym("float")); + + /* default values taken from Max's scale */ + x->x_il = fil; + x->x_ih = fih; + if(!x->x_ih)x->x_ih = 127.0; + x->x_ol = fol; + x->x_oh = foh; + if(!x->x_oh)x->x_oh = 1.0; + x->x_logcoeff = flc; + x->x_f = 0; + + return (void *)x; +} + +#ifndef MAXLIB +void scale_setup(void) +{ + scale_class = class_new(gensym("scale"), (t_newmethod)scale_new, + 0, sizeof(t_scale), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addfloat(scale_class, scale_float); + class_addbang(scale_class, scale_bang); + + logpost(NULL, 4, version); +#else +void maxlib_scale_setup(void) +{ + scale_class = class_new(gensym("maxlib_scale"), (t_newmethod)scale_new, + 0, sizeof(t_scale), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)scale_new, gensym("scale"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addfloat(scale_class, scale_float); + class_addbang(scale_class, scale_bang); + class_sethelpsymbol(scale_class, gensym("maxlib/scale-help.pd")); +#endif +} + diff --git a/score-help.pd b/score-help.pd index 7c981f7..0a799a9 100644 --- a/score-help.pd +++ b/score-help.pd @@ -25,7 +25,7 @@ #X restore 402 361 graph; #X obj 30 235 score sco_array 2 300; #X msg 130 173 set sco_array; -#X msg 23 449 \; sco_array resize 25 \; sco_array read examplescore.txt +#X msg 23 449 \; sco_array resize 25 \; sco_array read examples/score.txt \;; #X text 250 174 set to array that contains the score; #X text 88 303 position on score; diff --git a/score.c b/score.c index 153b65a..04ef1ff 100644 --- a/score.c +++ b/score.c @@ -1,309 +1,309 @@ -/* ------------------------- score ------------------------------------------ */ -/* */ -/* Simple score following / orientation. Incoming data gets compared to a */ -/* score stored in an array or table. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" - -#define MAX_NOTES 32 /* maximum number of notes that can be stored */ - -static char *version = "score v0.1, score follower written by Olaf Matthes "; - -typedef struct score -{ - t_object x_ob; - t_inlet *x_invelo; /* inlet for velocity */ - t_inlet *x_inreset; /* inlet to reset the object */ - t_outlet *x_outindex; /* index :: position in given score */ - t_outlet *x_outerror; /* indicates lost orientation */ - t_symbol *x_sym; /* name of array that contains the score */ - t_garray *x_buf; /* the above array itselfe */ - - t_int x_state; /* indicates state of score following: */ - /* running = 1, record = -1, stop = 0 */ - t_int x_skipindex; /* max. number of notes to skip */ - t_float x_skiptime; /* max time in ms to skip */ - t_int x_index; /* position in array / score */ - t_int x_lastpitch; - t_int x_error; - - t_int x_notecount; - t_int x_pitch; - t_int x_velo; - /* helpers needed to do the calculations */ - double x_starttime[MAX_NOTES]; - double x_laststarttime; - t_int x_alloctable[MAX_NOTES]; - -} t_score; - -static void score_float(t_score *x, t_floatarg f) -{ - /* This is the score following algorhythm: - - first, we check if the note we got is in the score. In case - it's not the next note, we'll search 'skipnotes' in advance. - In case that fails we go back 'skipnotes' and check them. As - extra these notes have to be 'younger' than 'skiptime' (to - avoid going back too far in case of slow melodies) - As last resort we check if we probably just got the same not - again (double trigger from keyboard or the like) - */ - - t_int velo = x->x_velo; /* get the velocity */ - t_garray *b = x->x_buf; /* make local copy of array */ - float *tab; /* we'll store notes in here */ - int items; - int i, j, n, check; - - x->x_pitch = (t_int)f; - x->x_error = 0; - - /* check our array */ - if (!b) - { - post("score: no array selected!"); - x->x_error = 1; - goto output; - } - if (!garray_getfloatarray(b, &items, &tab)) - { - post("score: couldn't read from array!"); - x->x_error = 1; - goto output; - } - - if (x->x_state) /* score follower is running */ - { - n = check = x->x_notecount; /* make local copys */ - - if (x->x_velo != 0) /* store note-on in alloctable */ - { - /* store note in alloctable */ - x->x_alloctable[n] = (t_int)x->x_pitch; - /* store note-on time */ - x->x_starttime[n] = clock_getlogicaltime(); - if(++x->x_notecount >= MAX_NOTES)x->x_notecount = 0; /* total number of notes has increased */ - } else return; /* we don't care about note-off's */ - - /* first we try to find a match within the skip area */ - /* ( probably looking ahead in the score ) */ - for (i = x->x_index + 1; i < (x->x_index + x->x_skipindex + 1); i++) - { - // post("%d: %d -> %d", i, x->x_alloctable[n], (t_int)tab[i]); - if(x->x_alloctable[n] == (t_int)tab[i]) - { - if(i - x->x_index != 1) post("score: skipped %d notes!", i - x->x_index - 1); - x->x_alloctable[n] = -1; /* delete note, we've matched it! */ - x->x_index = i; - goto output; - } - } - - /* then we look back within the boudaries of skiptime */ - for (i = x->x_index - 1; i > (x->x_index - x->x_skipindex) - 1; i--) - { - check = n; /* get current notecount */ - - for (j = 0; j < MAX_NOTES; j++) /* check with every note from our alloctable */ - { - if (x->x_alloctable[check] == (t_int)tab[i]) /* this one would fit */ - { - /* check the time restrictions */ - if (clock_gettimesince(x->x_starttime[check]) < x->x_skiptime) - { - if (i != x->x_index) post("score: skipped %d notes in score!", x->x_index - i); - if (j != 0) post("score: skipped %d notes from input!", j); - post("score: going back by %g milliseconds!", clock_gettimesince(x->x_starttime[check])); - x->x_index = i; - /* new notecount: we assume the notes we skipped are errors made by the */ - /* performer. new notes will be added right behind the last valid one */ - x->x_notecount = (check++) % MAX_NOTES; - x->x_alloctable[x->x_notecount - 1] = -1; /* delete note since we've matched it */ - goto output; - } - else /* ough, too old ! */ - { - post("score: matching note is too old! (ignored)"); - x->x_alloctable[check] = 0; /* delete note since it's too old */ - x->x_error = 1; - goto output; /* stop with first match as all others would be far older */ - } - } - if(--check < 0) check = MAX_NOTES - 1; /* decrease counter */ - /* as we want to go back in time */ - } - } - /* or is it just the same note again ??? (double trigger...) */ - if(x->x_pitch == x->x_lastpitch) - { - post("score: repetition! (ignored)"); - x->x_alloctable[x->x_notecount - 1] = -1; /* forget this one */ - return; - } - - /* in case we found nothing: indicate that! */ - x->x_error = 1; - post("score: couldn't find any matches !"); - x->x_lastpitch = x->x_pitch; - goto output; - } - else return; - -output: - /* output index */ - outlet_float(x->x_outindex, x->x_index); - /* bang in case of error */ - if(x->x_error) outlet_bang(x->x_outerror); -} - -static void score_ft1(t_score *x, t_floatarg f) -{ - x->x_velo = (t_int)f; -} - - /* start following the previoisly recorded score */ -static void score_start(t_score *x, t_symbol *s, t_int argc, t_atom* argv) -{ - x->x_index = (t_int)atom_getfloatarg(0, argc, argv); - if(x->x_index > 0) - { - post("score: starting at note %d", x->x_index); - } - else post("score: start following"); - x->x_index--; /* because our array starts with 0 */ - x->x_state = 1; -} - /* resume following the previoisly recorded score */ -static void score_resume(t_score *x) -{ - x->x_state = 1; - post("score: resume following"); -} - - /* stop following the previoisly recorded score */ -static void score_stop(t_score *x) -{ - x->x_state = 0; - post("score: stop following"); -} - - /* choose the array that holds the score */ -void score_set(t_score *x, t_symbol *s) -{ - t_garray *b; - - x->x_sym = s; - - if ((b = (t_garray *)pd_findbyclass(s, garray_class))) - { - post("score: array set to \"%s\"", s->s_name); - x->x_buf = b; - } else { - post("score: no array \"%s\" (error %d)", s->s_name, b); - x->x_buf = 0; - } -} - -static void score_reset(t_score *x) -{ - int i; - - x->x_state = 0; /* don't follow */ - x->x_error = 0; - x->x_index = -1; - x->x_notecount = 0; - x->x_lastpitch = 0; - for(i = 0; i < MAX_NOTES; i++)x->x_alloctable[i] = -1; - - post("score: reset"); -} - -static void score_free(t_score *x) -{ - // nothing to do -} - -static t_class *score_class; - -static void *score_new(t_symbol *s, t_floatarg fskipindex, t_floatarg fskiptime) -{ - int i; - - t_score *x = (t_score *)pd_new(score_class); - x->x_invelo = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); - x->x_inreset = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("bang"), gensym("reset")); - x->x_outindex = outlet_new(&x->x_ob, gensym("float")); - x->x_outerror = outlet_new(&x->x_ob, gensym("float")); - - x->x_sym = s; /* get name of array */ - score_set(x,x->x_sym); /* set array */ - if(!fskipindex)fskipindex = 2; - if(!fskiptime)fskiptime = 300.0; - x->x_skipindex = (t_int)fskipindex; - x->x_skiptime = (t_float)fskiptime; - post("score: skipindex set to %d, skiptime set to %g milliseconds", x->x_skipindex, x->x_skiptime); - - x->x_state = 0; /* don't follow */ - x->x_error = 0; - x->x_index = -1; - x->x_notecount = 0; - x->x_pitch = x->x_lastpitch = -1; - for(i = 0; i < MAX_NOTES; i++)x->x_alloctable[i] = -1; - - return (void *)x; -} - -#ifndef MAXLIB -void score_setup(void) -{ - score_class = class_new(gensym("score"), (t_newmethod)score_new, - (t_method)score_free, sizeof(t_score), 0, A_SYMBOL, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addmethod(score_class, (t_method)score_reset, gensym("reset"), 0); - class_addmethod(score_class, (t_method)score_resume, gensym("resume"), 0); - class_addmethod(score_class, (t_method)score_start, gensym("start"), A_GIMME, 0); - class_addmethod(score_class, (t_method)score_stop, gensym("stop"), 0); - class_addmethod(score_class, (t_method)score_ft1, gensym("ft1"), A_FLOAT, 0); - class_addmethod(score_class, (t_method)score_reset, gensym("reset"), A_GIMME, 0); - class_addmethod(score_class, (t_method)score_set, gensym("set"), A_SYMBOL, 0); - class_addfloat(score_class, score_float); - - post(version); -} -#else -void maxlib_score_setup(void) -{ - score_class = class_new(gensym("maxlib_score"), (t_newmethod)score_new, - (t_method)score_free, sizeof(t_score), 0, A_SYMBOL, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)score_new, gensym("score"), A_SYMBOL, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addmethod(score_class, (t_method)score_reset, gensym("reset"), 0); - class_addmethod(score_class, (t_method)score_resume, gensym("resume"), 0); - class_addmethod(score_class, (t_method)score_start, gensym("start"), A_GIMME, 0); - class_addmethod(score_class, (t_method)score_stop, gensym("stop"), 0); - class_addmethod(score_class, (t_method)score_ft1, gensym("ft1"), A_FLOAT, 0); - class_addmethod(score_class, (t_method)score_reset, gensym("reset"), A_GIMME, 0); - class_addmethod(score_class, (t_method)score_set, gensym("set"), A_SYMBOL, 0); - class_addfloat(score_class, score_float); - class_sethelpsymbol(score_class, gensym("maxlib/score-help.pd")); -} -#endif +/* ------------------------- score ------------------------------------------ */ +/* */ +/* Simple score following / orientation. Incoming data gets compared to a */ +/* score stored in an array or table. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" + +#define MAX_NOTES 32 /* maximum number of notes that can be stored */ + +static char *version = "score v0.1, score follower written by Olaf Matthes "; + +typedef struct score +{ + t_object x_ob; + t_inlet *x_invelo; /* inlet for velocity */ + t_inlet *x_inreset; /* inlet to reset the object */ + t_outlet *x_outindex; /* index :: position in given score */ + t_outlet *x_outerror; /* indicates lost orientation */ + t_symbol *x_sym; /* name of array that contains the score */ + t_garray *x_buf; /* the above array itselfe */ + + t_int x_state; /* indicates state of score following: */ + /* running = 1, record = -1, stop = 0 */ + t_int x_skipindex; /* max. number of notes to skip */ + t_float x_skiptime; /* max time in ms to skip */ + t_int x_index; /* position in array / score */ + t_int x_lastpitch; + t_int x_error; + + t_int x_notecount; + t_int x_pitch; + t_int x_velo; + /* helpers needed to do the calculations */ + double x_starttime[MAX_NOTES]; + double x_laststarttime; + t_int x_alloctable[MAX_NOTES]; + +} t_score; + +static void score_float(t_score *x, t_floatarg f) +{ + /* This is the score following algorhythm: + + first, we check if the note we got is in the score. In case + it's not the next note, we'll search 'skipnotes' in advance. + In case that fails we go back 'skipnotes' and check them. As + extra these notes have to be 'younger' than 'skiptime' (to + avoid going back too far in case of slow melodies) + As last resort we check if we probably just got the same not + again (double trigger from keyboard or the like) + */ + + t_int velo = x->x_velo; /* get the velocity */ + t_garray *b = x->x_buf; /* make local copy of array */ + float *tab; /* we'll store notes in here */ + int items; + int i, j, n, check; + + x->x_pitch = (t_int)f; + x->x_error = 0; + + /* check our array */ + if (!b) + { + post("score: no array selected!"); + x->x_error = 1; + goto output; + } + if (!garray_getfloatarray(b, &items, &tab)) + { + post("score: couldn't read from array!"); + x->x_error = 1; + goto output; + } + + if (x->x_state) /* score follower is running */ + { + n = check = x->x_notecount; /* make local copys */ + + if (x->x_velo != 0) /* store note-on in alloctable */ + { + /* store note in alloctable */ + x->x_alloctable[n] = (t_int)x->x_pitch; + /* store note-on time */ + x->x_starttime[n] = clock_getlogicaltime(); + if(++x->x_notecount >= MAX_NOTES)x->x_notecount = 0; /* total number of notes has increased */ + } else return; /* we don't care about note-off's */ + + /* first we try to find a match within the skip area */ + /* ( probably looking ahead in the score ) */ + for (i = x->x_index + 1; i < (x->x_index + x->x_skipindex + 1); i++) + { + // post("%d: %d -> %d", i, x->x_alloctable[n], (t_int)tab[i]); + if(x->x_alloctable[n] == (t_int)tab[i]) + { + if(i - x->x_index != 1) post("score: skipped %d notes!", i - x->x_index - 1); + x->x_alloctable[n] = -1; /* delete note, we've matched it! */ + x->x_index = i; + goto output; + } + } + + /* then we look back within the boudaries of skiptime */ + for (i = x->x_index - 1; i > (x->x_index - x->x_skipindex) - 1; i--) + { + check = n; /* get current notecount */ + + for (j = 0; j < MAX_NOTES; j++) /* check with every note from our alloctable */ + { + if (x->x_alloctable[check] == (t_int)tab[i]) /* this one would fit */ + { + /* check the time restrictions */ + if (clock_gettimesince(x->x_starttime[check]) < x->x_skiptime) + { + if (i != x->x_index) post("score: skipped %d notes in score!", x->x_index - i); + if (j != 0) post("score: skipped %d notes from input!", j); + post("score: going back by %g milliseconds!", clock_gettimesince(x->x_starttime[check])); + x->x_index = i; + /* new notecount: we assume the notes we skipped are errors made by the */ + /* performer. new notes will be added right behind the last valid one */ + x->x_notecount = (check++) % MAX_NOTES; + x->x_alloctable[x->x_notecount - 1] = -1; /* delete note since we've matched it */ + goto output; + } + else /* ough, too old ! */ + { + post("score: matching note is too old! (ignored)"); + x->x_alloctable[check] = 0; /* delete note since it's too old */ + x->x_error = 1; + goto output; /* stop with first match as all others would be far older */ + } + } + if(--check < 0) check = MAX_NOTES - 1; /* decrease counter */ + /* as we want to go back in time */ + } + } + /* or is it just the same note again ??? (double trigger...) */ + if(x->x_pitch == x->x_lastpitch) + { + post("score: repetition! (ignored)"); + x->x_alloctable[x->x_notecount - 1] = -1; /* forget this one */ + return; + } + + /* in case we found nothing: indicate that! */ + x->x_error = 1; + post("score: couldn't find any matches !"); + x->x_lastpitch = x->x_pitch; + goto output; + } + else return; + +output: + /* output index */ + outlet_float(x->x_outindex, x->x_index); + /* bang in case of error */ + if(x->x_error) outlet_bang(x->x_outerror); +} + +static void score_ft1(t_score *x, t_floatarg f) +{ + x->x_velo = (t_int)f; +} + + /* start following the previoisly recorded score */ +static void score_start(t_score *x, t_symbol *s, t_int argc, t_atom* argv) +{ + x->x_index = (t_int)atom_getfloatarg(0, argc, argv); + if(x->x_index > 0) + { + post("score: starting at note %d", x->x_index); + } + else post("score: start following"); + x->x_index--; /* because our array starts with 0 */ + x->x_state = 1; +} + /* resume following the previoisly recorded score */ +static void score_resume(t_score *x) +{ + x->x_state = 1; + post("score: resume following"); +} + + /* stop following the previoisly recorded score */ +static void score_stop(t_score *x) +{ + x->x_state = 0; + post("score: stop following"); +} + + /* choose the array that holds the score */ +void score_set(t_score *x, t_symbol *s) +{ + t_garray *b; + + x->x_sym = s; + + if ((b = (t_garray *)pd_findbyclass(s, garray_class))) + { + post("score: array set to \"%s\"", s->s_name); + x->x_buf = b; + } else { + post("score: no array \"%s\" (error %d)", s->s_name, b); + x->x_buf = 0; + } +} + +static void score_reset(t_score *x) +{ + int i; + + x->x_state = 0; /* don't follow */ + x->x_error = 0; + x->x_index = -1; + x->x_notecount = 0; + x->x_lastpitch = 0; + for(i = 0; i < MAX_NOTES; i++)x->x_alloctable[i] = -1; + + post("score: reset"); +} + +static void score_free(t_score *x) +{ + // nothing to do +} + +static t_class *score_class; + +static void *score_new(t_symbol *s, t_floatarg fskipindex, t_floatarg fskiptime) +{ + int i; + + t_score *x = (t_score *)pd_new(score_class); + x->x_invelo = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1")); + x->x_inreset = inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("bang"), gensym("reset")); + x->x_outindex = outlet_new(&x->x_ob, gensym("float")); + x->x_outerror = outlet_new(&x->x_ob, gensym("float")); + + x->x_sym = s; /* get name of array */ + score_set(x,x->x_sym); /* set array */ + if(!fskipindex)fskipindex = 2; + if(!fskiptime)fskiptime = 300.0; + x->x_skipindex = (t_int)fskipindex; + x->x_skiptime = (t_float)fskiptime; + post("score: skipindex set to %d, skiptime set to %g milliseconds", x->x_skipindex, x->x_skiptime); + + x->x_state = 0; /* don't follow */ + x->x_error = 0; + x->x_index = -1; + x->x_notecount = 0; + x->x_pitch = x->x_lastpitch = -1; + for(i = 0; i < MAX_NOTES; i++)x->x_alloctable[i] = -1; + + return (void *)x; +} + +#ifndef MAXLIB +void score_setup(void) +{ + score_class = class_new(gensym("score"), (t_newmethod)score_new, + (t_method)score_free, sizeof(t_score), 0, A_SYMBOL, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addmethod(score_class, (t_method)score_reset, gensym("reset"), 0); + class_addmethod(score_class, (t_method)score_resume, gensym("resume"), 0); + class_addmethod(score_class, (t_method)score_start, gensym("start"), A_GIMME, 0); + class_addmethod(score_class, (t_method)score_stop, gensym("stop"), 0); + class_addmethod(score_class, (t_method)score_ft1, gensym("ft1"), A_FLOAT, 0); + class_addmethod(score_class, (t_method)score_reset, gensym("reset"), A_GIMME, 0); + class_addmethod(score_class, (t_method)score_set, gensym("set"), A_SYMBOL, 0); + class_addfloat(score_class, score_float); + + logpost(NULL, 4, version); +} +#else +void maxlib_score_setup(void) +{ + score_class = class_new(gensym("maxlib_score"), (t_newmethod)score_new, + (t_method)score_free, sizeof(t_score), 0, A_SYMBOL, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)score_new, gensym("score"), A_SYMBOL, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addmethod(score_class, (t_method)score_reset, gensym("reset"), 0); + class_addmethod(score_class, (t_method)score_resume, gensym("resume"), 0); + class_addmethod(score_class, (t_method)score_start, gensym("start"), A_GIMME, 0); + class_addmethod(score_class, (t_method)score_stop, gensym("stop"), 0); + class_addmethod(score_class, (t_method)score_ft1, gensym("ft1"), A_FLOAT, 0); + class_addmethod(score_class, (t_method)score_reset, gensym("reset"), A_GIMME, 0); + class_addmethod(score_class, (t_method)score_set, gensym("set"), A_SYMBOL, 0); + class_addfloat(score_class, score_float); + class_sethelpsymbol(score_class, gensym("maxlib/score-help.pd")); +} +#endif diff --git a/speedlim.c b/speedlim.c index 72ad34c..4b917c0 100644 --- a/speedlim.c +++ b/speedlim.c @@ -1,235 +1,235 @@ -/* ------------------------- speedlim ----------------------------------------- */ -/* */ -/* Lets information through only every N milliseconds. */ -/* Written by Krzysztof Czaja for his cyclone library. */ -/* Modified to fit into maxlib by Olaf Matthes . */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* You should have received a copy of the GNU Lesser General Public */ -/* License along with this library; if not, write to the */ -/* Free Software Foundation, Inc., 59 Temple Place - Suite 330, */ -/* Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -/* this is the original copyright notice: */ - -/* Copyright (c) 1997-2002 Miller Puckette and others. - * For information on usage and redistribution, and for a DISCLAIMER OF ALL - * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ - - -#include -#include "m_pd.h" - -#define SPEEDLIM_INISIZE 32 /* LATER rethink */ -#define SPEEDLIM_MAXSIZE 256 /* not used */ - -typedef struct _speedlim -{ - t_object x_ob; - int x_open; - t_float x_delta; - t_symbol *x_selector; - t_float x_float; - t_symbol *x_symbol; - t_gpointer *x_pointer; - int x_size; /* as allocated */ - int x_natoms; /* as used */ - t_atom *x_message; - t_atom x_messini[SPEEDLIM_INISIZE]; - int x_entered; - t_clock *x_clock; -} t_speedlim; - -static t_class *speedlim_class; - -/* a caller must check for nrequested > *sizep */ -/* returns actual number of atoms: requested (success) - or a default value of initial size (failure) */ -/* the result is guaranteed to be >= min(nrequested, inisize) */ -static int speedlim_grow(int nrequested, int *sizep, t_atom **bufp, - int inisize, t_atom *bufini) -{ - int newsize = *sizep * 2; - while (newsize < nrequested) newsize *= 2; - if (*bufp == bufini) - *bufp = (t_atom *)getbytes(newsize * sizeof(**bufp)); - else - *bufp = (t_atom *)resizebytes(*bufp, *sizep * sizeof(**bufp), - newsize * sizeof(**bufp)); - if (*bufp) - *sizep = newsize; - else - { - *bufp = bufini; - nrequested = *sizep = inisize; - } - return (nrequested); -} - -static void speedlim_dooutput(t_speedlim *x, t_symbol *s, int ac, t_atom *av) -{ - x->x_open = 0; /* so there will be no reentrant calls of dooutput */ - x->x_entered = 1; /* this prevents a message from being overridden */ - clock_unset(x->x_clock); - if (s == &s_bang) - outlet_bang(((t_object *)x)->ob_outlet); - else if (s == &s_float) - outlet_float(((t_object *)x)->ob_outlet, x->x_float); - else if (s == &s_symbol && x->x_symbol) - { - /* if x_symbol is null, then symbol &s_ is passed - by outlet_anything() -> typedmess() */ - outlet_symbol(((t_object *)x)->ob_outlet, x->x_symbol); - x->x_symbol = 0; - } - else if (s == &s_pointer && x->x_pointer) - { - /* LATER */ - x->x_pointer = 0; - } - else if (s == &s_list) - outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av); - else if (s) - outlet_anything(((t_object *)x)->ob_outlet, s, ac, av); - x->x_selector = 0; - x->x_natoms = 0; - if (x->x_delta > 0) - clock_delay(x->x_clock, x->x_delta); - else - x->x_open = 1; - x->x_entered = 0; -} - -static void speedlim_tick(t_speedlim *x) -{ - if (x->x_selector) - speedlim_dooutput(x, x->x_selector, x->x_natoms, x->x_message); - else - x->x_open = 1; -} - -static void speedlim_anything(t_speedlim *x, t_symbol *s, int ac, t_atom *av) -{ - if (x->x_open) - speedlim_dooutput(x, s, ac, av); - else if (s && s != &s_ && !x->x_entered) - { - if (ac > x->x_size) - /* MAXSIZE not used, not even a warning... - LATER consider clipping */ - ac = speedlim_grow(ac, &x->x_size, &x->x_message, - SPEEDLIM_INISIZE, x->x_messini); - x->x_selector = s; - x->x_natoms = ac; - if (ac) - memcpy(x->x_message, av, ac * sizeof(*x->x_message)); - } -} - -static void speedlim_bang(t_speedlim *x) -{ - x->x_selector = &s_bang; - speedlim_anything(x, x->x_selector, 0, 0); -} - -static void speedlim_float(t_speedlim *x, t_float f) -{ - x->x_selector = &s_float; - x->x_float = f; - speedlim_anything(x, x->x_selector, 0, 0); -} - -static void speedlim_symbol(t_speedlim *x, t_symbol *s) -{ - x->x_selector = &s_symbol; - x->x_symbol = s; - speedlim_anything(x, x->x_selector, 0, 0); -} - -/* LATER gpointer */ - -static void speedlim_list(t_speedlim *x, t_symbol *s, int ac, t_atom *av) -{ - x->x_selector = &s_list; - speedlim_anything(x, x->x_selector, ac, av); -} - -static void speedlim_ft1(t_speedlim *x, t_floatarg f) -{ - if (f < 0) - f = 0; /* redundant (and CHECKED) */ - x->x_delta = f; - /* CHECKED: no rearming -- - if clock is set, then new delta value is not used until next tick */ -} - -static void speedlim_free(t_speedlim *x) -{ - if (x->x_message != x->x_messini) - freebytes(x->x_message, x->x_size * sizeof(*x->x_message)); - if (x->x_clock) - clock_free(x->x_clock); -} - -static void *speedlim_new(t_floatarg f) -{ - t_speedlim *x = (t_speedlim *)pd_new(speedlim_class); - x->x_open = 1; /* CHECKED */ - x->x_delta = 0; - x->x_selector = 0; - x->x_float = 0; - x->x_symbol = 0; - x->x_pointer = 0; - x->x_size = SPEEDLIM_INISIZE; - x->x_natoms = 0; - x->x_message = x->x_messini; - x->x_entered = 0; - inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1")); - outlet_new((t_object *)x, &s_anything); - x->x_clock = clock_new(x, (t_method)speedlim_tick); - speedlim_ft1(x, f); - return (x); -} - -#ifndef MAXLIB -void speedlim_setup(void) -{ - speedlim_class = class_new(gensym("speedlim"), (t_newmethod)speedlim_new, - (t_method)speedlim_free, sizeof(t_speedlim), 0, A_DEFFLOAT, 0); -#else -void maxlib_speedlim_setup(void) -{ - speedlim_class = class_new(gensym("maxlib_speedlim"), (t_newmethod)speedlim_new, - (t_method)speedlim_free, sizeof(t_speedlim), 0, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)speedlim_new, gensym("speedlim"), A_DEFFLOAT, 0); -#endif - class_addbang(speedlim_class, speedlim_bang); - class_addfloat(speedlim_class, speedlim_float); - class_addsymbol(speedlim_class, speedlim_symbol); - class_addlist(speedlim_class, speedlim_list); - class_addanything(speedlim_class, speedlim_anything); - class_addmethod(speedlim_class, (t_method)speedlim_ft1, gensym("ft1"), A_FLOAT, 0); -#ifndef MAXLIB - -#else - class_sethelpsymbol(speedlim_class, gensym("maxlib/speedlim-help.pd")); -#endif -} +/* ------------------------- speedlim ----------------------------------------- */ +/* */ +/* Lets information through only every N milliseconds. */ +/* Written by Krzysztof Czaja for his cyclone library. */ +/* Modified to fit into maxlib by Olaf Matthes . */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* You should have received a copy of the GNU Lesser General Public */ +/* License along with this library; if not, write to the */ +/* Free Software Foundation, Inc., 59 Temple Place - Suite 330, */ +/* Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +/* this is the original copyright notice: */ + +/* Copyright (c) 1997-2002 Miller Puckette and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + + +#include +#include "m_pd.h" + +#define SPEEDLIM_INISIZE 32 /* LATER rethink */ +#define SPEEDLIM_MAXSIZE 256 /* not used */ + +typedef struct _speedlim +{ + t_object x_ob; + int x_open; + t_float x_delta; + t_symbol *x_selector; + t_float x_float; + t_symbol *x_symbol; + t_gpointer *x_pointer; + int x_size; /* as allocated */ + int x_natoms; /* as used */ + t_atom *x_message; + t_atom x_messini[SPEEDLIM_INISIZE]; + int x_entered; + t_clock *x_clock; +} t_speedlim; + +static t_class *speedlim_class; + +/* a caller must check for nrequested > *sizep */ +/* returns actual number of atoms: requested (success) + or a default value of initial size (failure) */ +/* the result is guaranteed to be >= min(nrequested, inisize) */ +static int speedlim_grow(int nrequested, int *sizep, t_atom **bufp, + int inisize, t_atom *bufini) +{ + int newsize = *sizep * 2; + while (newsize < nrequested) newsize *= 2; + if (*bufp == bufini) + *bufp = (t_atom *)getbytes(newsize * sizeof(**bufp)); + else + *bufp = (t_atom *)resizebytes(*bufp, *sizep * sizeof(**bufp), + newsize * sizeof(**bufp)); + if (*bufp) + *sizep = newsize; + else + { + *bufp = bufini; + nrequested = *sizep = inisize; + } + return (nrequested); +} + +static void speedlim_dooutput(t_speedlim *x, t_symbol *s, int ac, t_atom *av) +{ + x->x_open = 0; /* so there will be no reentrant calls of dooutput */ + x->x_entered = 1; /* this prevents a message from being overridden */ + clock_unset(x->x_clock); + if (s == &s_bang) + outlet_bang(((t_object *)x)->ob_outlet); + else if (s == &s_float) + outlet_float(((t_object *)x)->ob_outlet, x->x_float); + else if (s == &s_symbol && x->x_symbol) + { + /* if x_symbol is null, then symbol &s_ is passed + by outlet_anything() -> typedmess() */ + outlet_symbol(((t_object *)x)->ob_outlet, x->x_symbol); + x->x_symbol = 0; + } + else if (s == &s_pointer && x->x_pointer) + { + /* LATER */ + x->x_pointer = 0; + } + else if (s == &s_list) + outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av); + else if (s) + outlet_anything(((t_object *)x)->ob_outlet, s, ac, av); + x->x_selector = 0; + x->x_natoms = 0; + if (x->x_delta > 0) + clock_delay(x->x_clock, x->x_delta); + else + x->x_open = 1; + x->x_entered = 0; +} + +static void speedlim_tick(t_speedlim *x) +{ + if (x->x_selector) + speedlim_dooutput(x, x->x_selector, x->x_natoms, x->x_message); + else + x->x_open = 1; +} + +static void speedlim_anything(t_speedlim *x, t_symbol *s, int ac, t_atom *av) +{ + if (x->x_open) + speedlim_dooutput(x, s, ac, av); + else if (s && s != &s_ && !x->x_entered) + { + if (ac > x->x_size) + /* MAXSIZE not used, not even a warning... + LATER consider clipping */ + ac = speedlim_grow(ac, &x->x_size, &x->x_message, + SPEEDLIM_INISIZE, x->x_messini); + x->x_selector = s; + x->x_natoms = ac; + if (ac) + memcpy(x->x_message, av, ac * sizeof(*x->x_message)); + } +} + +static void speedlim_bang(t_speedlim *x) +{ + x->x_selector = &s_bang; + speedlim_anything(x, x->x_selector, 0, 0); +} + +static void speedlim_float(t_speedlim *x, t_float f) +{ + x->x_selector = &s_float; + x->x_float = f; + speedlim_anything(x, x->x_selector, 0, 0); +} + +static void speedlim_symbol(t_speedlim *x, t_symbol *s) +{ + x->x_selector = &s_symbol; + x->x_symbol = s; + speedlim_anything(x, x->x_selector, 0, 0); +} + +/* LATER gpointer */ + +static void speedlim_list(t_speedlim *x, t_symbol *s, int ac, t_atom *av) +{ + x->x_selector = &s_list; + speedlim_anything(x, x->x_selector, ac, av); +} + +static void speedlim_ft1(t_speedlim *x, t_floatarg f) +{ + if (f < 0) + f = 0; /* redundant (and CHECKED) */ + x->x_delta = f; + /* CHECKED: no rearming -- + if clock is set, then new delta value is not used until next tick */ +} + +static void speedlim_free(t_speedlim *x) +{ + if (x->x_message != x->x_messini) + freebytes(x->x_message, x->x_size * sizeof(*x->x_message)); + if (x->x_clock) + clock_free(x->x_clock); +} + +static void *speedlim_new(t_floatarg f) +{ + t_speedlim *x = (t_speedlim *)pd_new(speedlim_class); + x->x_open = 1; /* CHECKED */ + x->x_delta = 0; + x->x_selector = 0; + x->x_float = 0; + x->x_symbol = 0; + x->x_pointer = 0; + x->x_size = SPEEDLIM_INISIZE; + x->x_natoms = 0; + x->x_message = x->x_messini; + x->x_entered = 0; + inlet_new((t_object *)x, (t_pd *)x, &s_float, gensym("ft1")); + outlet_new((t_object *)x, &s_anything); + x->x_clock = clock_new(x, (t_method)speedlim_tick); + speedlim_ft1(x, f); + return (x); +} + +#ifndef MAXLIB +void speedlim_setup(void) +{ + speedlim_class = class_new(gensym("speedlim"), (t_newmethod)speedlim_new, + (t_method)speedlim_free, sizeof(t_speedlim), 0, A_DEFFLOAT, 0); +#else +void maxlib_speedlim_setup(void) +{ + speedlim_class = class_new(gensym("maxlib_speedlim"), (t_newmethod)speedlim_new, + (t_method)speedlim_free, sizeof(t_speedlim), 0, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)speedlim_new, gensym("speedlim"), A_DEFFLOAT, 0); +#endif + class_addbang(speedlim_class, speedlim_bang); + class_addfloat(speedlim_class, speedlim_float); + class_addsymbol(speedlim_class, speedlim_symbol); + class_addlist(speedlim_class, speedlim_list); + class_addanything(speedlim_class, speedlim_anything); + class_addmethod(speedlim_class, (t_method)speedlim_ft1, gensym("ft1"), A_FLOAT, 0); +#ifndef MAXLIB + +#else + class_sethelpsymbol(speedlim_class, gensym("maxlib/speedlim-help.pd")); +#endif +} diff --git a/split.c b/split.c index 6b1b13a..de3f662 100644 --- a/split.c +++ b/split.c @@ -1,95 +1,95 @@ -/* ------------------------- split ------------------------------------------ */ -/* */ -/* splits input to lie within an output range. */ -/* Written by Olaf Matthes */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include -#include - -static char *version = "split v0.1, written by Olaf Matthes "; - -typedef struct split -{ - t_object x_ob; - t_float x_min; /* low border of input range */ - t_float x_max; /* high border of input range */ - t_int x_revert; /* range is inverted */ - t_outlet *x_outlet1; /* path-through outlet */ - t_outlet *x_outlet2; /* split outlet */ -} t_split; - -static void split_float(t_split *x, t_floatarg f) -{ - if(x->x_max >= x->x_min) - { - if(f <= x->x_max && f >= x->x_min) - outlet_float(x->x_outlet1, f); - else - outlet_float(x->x_outlet2, f); - } - else - { - if(f >= x->x_max && f <= x->x_min) - outlet_float(x->x_outlet1, f); - else - outlet_float(x->x_outlet2, f); - } -} - -static t_class *split_class; - -static void *split_new(t_floatarg fmin, t_floatarg fmax) -{ - t_split *x = (t_split *)pd_new(split_class); - - floatinlet_new(&x->x_ob, &x->x_min); - floatinlet_new(&x->x_ob, &x->x_max); - - x->x_outlet1 = outlet_new(&x->x_ob, gensym("float")); - x->x_outlet2 = outlet_new(&x->x_ob, gensym("float")); - - x->x_min = fmin; - x->x_max = fmax; - - return (void *)x; -} - -#ifndef MAXLIB -void split_setup(void) -{ - split_class = class_new(gensym("split"), (t_newmethod)split_new, - 0, sizeof(t_split), 0, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addfloat(split_class, split_float); - - post(version); -} -#else -void maxlib_split_setup(void) -{ - split_class = class_new(gensym("maxlib_split"), (t_newmethod)split_new, - 0, sizeof(t_split), 0, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)split_new, gensym("split"), A_DEFFLOAT, A_DEFFLOAT, 0); - class_addfloat(split_class, split_float); - class_sethelpsymbol(split_class, gensym("maxlib/split-help.pd")); -} -#endif +/* ------------------------- split ------------------------------------------ */ +/* */ +/* splits input to lie within an output range. */ +/* Written by Olaf Matthes */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include +#include + +static char *version = "split v0.1, written by Olaf Matthes "; + +typedef struct split +{ + t_object x_ob; + t_float x_min; /* low border of input range */ + t_float x_max; /* high border of input range */ + t_int x_revert; /* range is inverted */ + t_outlet *x_outlet1; /* path-through outlet */ + t_outlet *x_outlet2; /* split outlet */ +} t_split; + +static void split_float(t_split *x, t_floatarg f) +{ + if(x->x_max >= x->x_min) + { + if(f <= x->x_max && f >= x->x_min) + outlet_float(x->x_outlet1, f); + else + outlet_float(x->x_outlet2, f); + } + else + { + if(f >= x->x_max && f <= x->x_min) + outlet_float(x->x_outlet1, f); + else + outlet_float(x->x_outlet2, f); + } +} + +static t_class *split_class; + +static void *split_new(t_floatarg fmin, t_floatarg fmax) +{ + t_split *x = (t_split *)pd_new(split_class); + + floatinlet_new(&x->x_ob, &x->x_min); + floatinlet_new(&x->x_ob, &x->x_max); + + x->x_outlet1 = outlet_new(&x->x_ob, gensym("float")); + x->x_outlet2 = outlet_new(&x->x_ob, gensym("float")); + + x->x_min = fmin; + x->x_max = fmax; + + return (void *)x; +} + +#ifndef MAXLIB +void split_setup(void) +{ + split_class = class_new(gensym("split"), (t_newmethod)split_new, + 0, sizeof(t_split), 0, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addfloat(split_class, split_float); + + logpost(NULL, 4, version); +} +#else +void maxlib_split_setup(void) +{ + split_class = class_new(gensym("maxlib_split"), (t_newmethod)split_new, + 0, sizeof(t_split), 0, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)split_new, gensym("split"), A_DEFFLOAT, A_DEFFLOAT, 0); + class_addfloat(split_class, split_float); + class_sethelpsymbol(split_class, gensym("maxlib/split-help.pd")); +} +#endif diff --git a/step.c b/step.c index 3057347..cc44f7b 100644 --- a/step.c +++ b/step.c @@ -1,179 +1,179 @@ -/* -------------------------- step ------------------------------------------ */ -/* */ -/* Step to a new value in N milliseconds (similar to line). */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" - -/* -------------------------- step ------------------------------ */ -static char *version = "step v0.1, written by Olaf Matthes "; - -static t_class *step_class; - -typedef struct _step -{ - t_object x_obj; - t_clock *x_clock; - double x_targettime; - t_float x_targetval; - double x_prevtime; - t_float x_setval; - int x_gotinlet; - t_float x_grain; /* time interval for output */ - t_float x_step; /* step size for output */ - t_float x_steptime; /* length for one step */ - t_int x_stepcall; - double x_1overtimediff; - double x_in1val; -} t_step; - -static void step_tick(t_step *x) -{ - t_float outvalue; - double timenow = clock_getsystime(); - double msectogo = - clock_gettimesince(x->x_targettime); - if (msectogo < 1E-9) - { - outlet_float(x->x_obj.ob_outlet, x->x_targetval); - } - else - { - if(x->x_setval < x->x_targetval) - { /* count upwards */ - outvalue = x->x_setval + x->x_stepcall * x->x_step; - } - else - { /* count downwards */ - outvalue = x->x_setval - x->x_stepcall * x->x_step; - } - outlet_float(x->x_obj.ob_outlet, outvalue); - clock_delay(x->x_clock, (x->x_steptime > msectogo ? msectogo : x->x_steptime)); - } - x->x_stepcall++; -} - -static void step_float(t_step *x, t_float f) -{ - double timenow = clock_getsystime(); - if (x->x_gotinlet && x->x_in1val > 0 && x->x_step != 0 && f != x->x_setval) - { - if (timenow > x->x_targettime) x->x_setval = x->x_targetval; - else x->x_setval = x->x_setval + x->x_1overtimediff * - (timenow - x->x_prevtime) - * (x->x_targetval - x->x_setval); - x->x_prevtime = timenow; - x->x_targetval = f; /* where to end */ - x->x_stepcall = 0; - /* how long does it take ? */ - x->x_targettime = clock_getsystimeafter(x->x_in1val); - if(x->x_setval < x->x_targetval) - { - x->x_steptime = x->x_in1val / (int)((x->x_targetval - x->x_setval) / x->x_step); - } - else - { - x->x_steptime = x->x_in1val / (int)((x->x_setval - x->x_targetval) / x->x_step); - } - // post("steptime %g", x->x_steptime); - step_tick(x); - x->x_gotinlet = 0; - x->x_1overtimediff = 1./ (x->x_targettime - timenow); - /* call tick function */ - clock_delay(x->x_clock, x->x_steptime); - - } - else - { - clock_unset(x->x_clock); - x->x_targetval = x->x_setval = f; - outlet_float(x->x_obj.ob_outlet, f); - } - x->x_gotinlet = 0; -} - -static void step_ft1(t_step *x, t_floatarg g) -{ - x->x_in1val = g; - x->x_gotinlet = 1; -} - -static void step_ft2(t_step *x, t_floatarg g) -{ - if (g <= 0) g = 1; - x->x_step = g; - x->x_gotinlet = 1; -} - -static void step_stop(t_step *x) -{ - x->x_targetval = x->x_setval; - clock_unset(x->x_clock); -} - -static void step_free(t_step *x) -{ - clock_free(x->x_clock); -} - -static void *step_new(t_floatarg f, t_floatarg step, t_floatarg grain) -{ - t_step *x = (t_step *)pd_new(step_class); - x->x_targetval = x->x_setval = f; - x->x_gotinlet = 0; - x->x_1overtimediff = 1; - x->x_clock = clock_new(x, (t_method)step_tick); - x->x_targettime = x->x_prevtime = clock_getsystime(); - if (grain <= 0) grain = 20; - x->x_grain = grain; - if (step <= 0) step = 1; - x->x_step = step; - outlet_new(&x->x_obj, gensym("float")); - inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1")); - inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft2")); - return (x); -} - -#ifndef MAXLIB -void step_setup(void) -{ - step_class = class_new(gensym("step"), (t_newmethod)step_new, - (t_method)step_free, sizeof(t_step), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addmethod(step_class, (t_method)step_ft1, gensym("ft1"), A_FLOAT, 0); - class_addmethod(step_class, (t_method)step_ft2, gensym("ft2"), A_FLOAT, 0); - class_addmethod(step_class, (t_method)step_stop, gensym("stop"), 0); - class_addfloat(step_class, (t_method)step_float); - - post(version); -} -#else -void maxlib_step_setup(void) -{ - step_class = class_new(gensym("maxlib_step"), (t_newmethod)step_new, - (t_method)step_free, sizeof(t_step), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)step_new, gensym("step"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addmethod(step_class, (t_method)step_ft1, gensym("ft1"), A_FLOAT, 0); - class_addmethod(step_class, (t_method)step_ft2, gensym("ft2"), A_FLOAT, 0); - class_addmethod(step_class, (t_method)step_stop, gensym("stop"), 0); - class_addfloat(step_class, (t_method)step_float); - class_sethelpsymbol(step_class, gensym("maxlib/step-help.pd")); -} -#endif +/* -------------------------- step ------------------------------------------ */ +/* */ +/* Step to a new value in N milliseconds (similar to line). */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" + +/* -------------------------- step ------------------------------ */ +static char *version = "step v0.1, written by Olaf Matthes "; + +static t_class *step_class; + +typedef struct _step +{ + t_object x_obj; + t_clock *x_clock; + double x_targettime; + t_float x_targetval; + double x_prevtime; + t_float x_setval; + int x_gotinlet; + t_float x_grain; /* time interval for output */ + t_float x_step; /* step size for output */ + t_float x_steptime; /* length for one step */ + t_int x_stepcall; + double x_1overtimediff; + double x_in1val; +} t_step; + +static void step_tick(t_step *x) +{ + t_float outvalue; + double timenow = clock_getsystime(); + double msectogo = - clock_gettimesince(x->x_targettime); + if (msectogo < 1E-9) + { + outlet_float(x->x_obj.ob_outlet, x->x_targetval); + } + else + { + if(x->x_setval < x->x_targetval) + { /* count upwards */ + outvalue = x->x_setval + x->x_stepcall * x->x_step; + } + else + { /* count downwards */ + outvalue = x->x_setval - x->x_stepcall * x->x_step; + } + outlet_float(x->x_obj.ob_outlet, outvalue); + clock_delay(x->x_clock, (x->x_steptime > msectogo ? msectogo : x->x_steptime)); + } + x->x_stepcall++; +} + +static void step_float(t_step *x, t_float f) +{ + double timenow = clock_getsystime(); + if (x->x_gotinlet && x->x_in1val > 0 && x->x_step != 0 && f != x->x_setval) + { + if (timenow > x->x_targettime) x->x_setval = x->x_targetval; + else x->x_setval = x->x_setval + x->x_1overtimediff * + (timenow - x->x_prevtime) + * (x->x_targetval - x->x_setval); + x->x_prevtime = timenow; + x->x_targetval = f; /* where to end */ + x->x_stepcall = 0; + /* how long does it take ? */ + x->x_targettime = clock_getsystimeafter(x->x_in1val); + if(x->x_setval < x->x_targetval) + { + x->x_steptime = x->x_in1val / (int)((x->x_targetval - x->x_setval) / x->x_step); + } + else + { + x->x_steptime = x->x_in1val / (int)((x->x_setval - x->x_targetval) / x->x_step); + } + // post("steptime %g", x->x_steptime); + step_tick(x); + x->x_gotinlet = 0; + x->x_1overtimediff = 1./ (x->x_targettime - timenow); + /* call tick function */ + clock_delay(x->x_clock, x->x_steptime); + + } + else + { + clock_unset(x->x_clock); + x->x_targetval = x->x_setval = f; + outlet_float(x->x_obj.ob_outlet, f); + } + x->x_gotinlet = 0; +} + +static void step_ft1(t_step *x, t_floatarg g) +{ + x->x_in1val = g; + x->x_gotinlet = 1; +} + +static void step_ft2(t_step *x, t_floatarg g) +{ + if (g <= 0) g = 1; + x->x_step = g; + x->x_gotinlet = 1; +} + +static void step_stop(t_step *x) +{ + x->x_targetval = x->x_setval; + clock_unset(x->x_clock); +} + +static void step_free(t_step *x) +{ + clock_free(x->x_clock); +} + +static void *step_new(t_floatarg f, t_floatarg step, t_floatarg grain) +{ + t_step *x = (t_step *)pd_new(step_class); + x->x_targetval = x->x_setval = f; + x->x_gotinlet = 0; + x->x_1overtimediff = 1; + x->x_clock = clock_new(x, (t_method)step_tick); + x->x_targettime = x->x_prevtime = clock_getsystime(); + if (grain <= 0) grain = 20; + x->x_grain = grain; + if (step <= 0) step = 1; + x->x_step = step; + outlet_new(&x->x_obj, gensym("float")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1")); + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft2")); + return (x); +} + +#ifndef MAXLIB +void step_setup(void) +{ + step_class = class_new(gensym("step"), (t_newmethod)step_new, + (t_method)step_free, sizeof(t_step), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addmethod(step_class, (t_method)step_ft1, gensym("ft1"), A_FLOAT, 0); + class_addmethod(step_class, (t_method)step_ft2, gensym("ft2"), A_FLOAT, 0); + class_addmethod(step_class, (t_method)step_stop, gensym("stop"), 0); + class_addfloat(step_class, (t_method)step_float); + + logpost(NULL, 4, version); +} +#else +void maxlib_step_setup(void) +{ + step_class = class_new(gensym("maxlib_step"), (t_newmethod)step_new, + (t_method)step_free, sizeof(t_step), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)step_new, gensym("step"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addmethod(step_class, (t_method)step_ft1, gensym("ft1"), A_FLOAT, 0); + class_addmethod(step_class, (t_method)step_ft2, gensym("ft2"), A_FLOAT, 0); + class_addmethod(step_class, (t_method)step_stop, gensym("stop"), 0); + class_addfloat(step_class, (t_method)step_float); + class_sethelpsymbol(step_class, gensym("maxlib/step-help.pd")); +} +#endif diff --git a/subst.c b/subst.c index 00fa9db..1bb4d45 100644 --- a/subst.c +++ b/subst.c @@ -1,424 +1,424 @@ -/* ------------------------- subst ------------------------------------------ */ -/* */ -/* Performs 'self-similar' substitution of a given list of values. */ -/* Written by Olaf Matthes */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ -#include "m_pd.h" - - -static char *version = "subst v0.1, self-similar substitution of rows (list or array)\n" - " written by Olaf Matthes "; - -#undef DEBUG -//#define DEBUG - -#define MAXSIZE 1024 - -#include -#include - - -// -// Maxlife object data structure -// -typedef struct subst -{ - t_object x_obj; // must begin every object - t_outlet *x_outlist; // outlet for the processed list - t_outlet *x_outlength; - t_atom x_row[MAXSIZE]; // row of values to get processed - t_int x_length; // length of row - t_int x_order; // size of the CA field/world - t_symbol *x_array; // name of array that holds the data - t_garray *x_buf; // content of that array -} t_subst; - -// -// Function prototypes for our methods and functions -// -static t_class *subst_class; // global variable that points to the Maxlife class - -// -// get the sum of intervals from no a to no b -// Parameters: the row, it's length, intv a, intev b -// -static int sum_intv(t_atom *argv, int argc, int a, int b) -{ - int i; - int summe = 0; // sum of intervals - - if(a==b) - return(0); // same index - if(atom_getintarg(a, argc, argv) == atom_getintarg(b, argc, argv)) - return(0); // same value - - for(i=a;i atom_getintarg(i, argc, argv)) // positive intv. - { - summe += ((atom_getintarg(i + 1, argc, argv) - atom_getintarg(i, argc, argv)) % 12); - } - else // negative interval - { - summe -= ((atom_getintarg(i + 1, argc, argv) - atom_getintarg(i, argc, argv)) % 12); - } - } - return(summe); -} -//----- Anzahl Partialreihen mit Interval d ------------------------------- -static int no_part(t_atom *argv, int argc, int a, int b, int d) // nn -{ - int i,j,r = 0; - - if(a = b)return(0); - - for(i = a; i < b; i++) - { - for(j=a+1;j no_part(argv, argc, a, b, d)) - return(-1); - for(i = 1; i = (b - a); i++) - { - for(j = 1; j = b; j++) - { - if(sum_intv(argv, argc, i, j) == d) - r++; - } - } - return(r); -} -//----- Test, ob Partialreihe der Ordnung o mit Interval d existiert ---------- -static int check_part_intv(t_atom *argv, int argc, int o, int d) -{ - int z; - - for(z = 0; z < argc - o; z++) - { - if(sum_intv(argv, argc, z, z + o) == d) - return(z); // Abstand von Reihenanfang - } - - return(-1); -} - -static int my_random(int range) { - int ret = rand(); - ret = ret % range; // limit to desired output range - return(ret); -} - -// -// the substitution algorhythm -// -static int subst_calc(t_subst *x, int n) -{ - int i,j,k,l,o = x->x_order; - int s = -1; - int intv; - t_atom newrow[MAXSIZE]; - t_garray *A = x->x_buf; - int npoints; - t_float *vec; - - if(x->x_length <= 1) - { - post("subst: need some data first!"); - return(-1); - } - srand((unsigned int)clock_getlogicaltime()); - - if(n == -1) // no interval given: choose one by chance - { - do - { - n = my_random(x->x_length - 1); // choose interval - intv = sum_intv(x->x_row, x->x_length, n, n + 1); // size of this interval - } - while(intv == 0); // ...until we found one that is not 0! - } - else intv = sum_intv(x->x_row, x->x_length, n, n + 1); - -#ifdef DEBUG - post("subst: substitution of %dth interval (%d halftones)", n+1, intv); -#endif - - /* for-Schleife für möglichst lange Substitutionen - for(j=anzahlReihe(alteReihe);j>2;j--) */ - for(j = x->x_order; j < x->x_length; j++) // prefer lower orders (min. 2) - { // search for possible order... - s = check_part_intv(x->x_row, x->x_length, j, intv); - if(s != -1) // check if there is a partial row with the interval we want - { - o = j; // save actual order, might be larger then x->x_order - break; // ... do it! - } - if(o == j)break; // found one - } - - for(i = 0; i < x->x_length; i++) - { - if(i <= n) // just copy values before substitution - { - newrow[i] = x->x_row[i]; - } - if((i == n) && (s != -1)) // now substitute - { - for(k=1;kx_row, x->x_length, s+k-1, s+k))); -#ifdef DEBUG - post("subst: new interval[%d]: %d ", k, sum_intv(x->x_row, x->x_length, s+k-1, s+k)); -#endif - } - post("subst: replaced interval %d (%d halftones) with %d new intervals", n, intv, o); - } - else if((i == n) && (s == -1)) // not partial row found - { - o = 1; // order is 1 -> now substitution - newrow[i] = x->x_row[i]; // copy the next value of the row - post("subst: coundn't find any partial rows to fit in!"); - } - - if(i>n) // behind substitution - { - newrow[i+(o-1)] = x->x_row[i]; // copy rest or row - } - } - - // copy stuff back... - x->x_length = l = x->x_length + o - 1; - for(i = 0; i < x->x_length; i++) - x->x_row[i] = newrow[i]; - - // write to array - if(x->x_array)if (!(A = (t_garray *)pd_findbyclass(x->x_array, garray_class))) - error("subst: %s: no such array", x->x_array->s_name); - else if (!garray_getfloatarray(A, &npoints, &vec)) - error("subst: %s: bad template ", x->x_array->s_name); - else - { - i = 0; - - if (l >= npoints) // keep end of array - { - while(npoints--) - { - *vec++ = atom_getfloat(x->x_row + i); - i++; - } - } - else // update - { - npoints -= l; - while (l--) - { - *vec++ = atom_getfloat(x->x_row + i); - i++; - } - while (npoints--) *vec++ = 0; - } - garray_redraw(A); - } - - // output stuff - outlet_float(x->x_outlength, x->x_length); - outlet_list(x->x_outlist, NULL, x->x_length, x->x_row); - - return(0); -} - -static void subst_list(t_subst *x, t_symbol *s, int argc, t_atom *argv) -{ - t_garray *b = x->x_buf; /* make local copy of array */ - float *tab; /* we'll store notes in here */ - int items; - int i; - - for(i = 0; i < argc; i++) - { - x->x_row[i] = argv[i]; // just copy input - } - x->x_length = argc; - -} - -// -// choose the array that holds the processed row (output!!) -// -void subst_set(t_subst *x, t_symbol *s) -{ - t_garray *b; - - x->x_array = s; - - if ((b = (t_garray *)pd_findbyclass(s, garray_class))) - { - post("subst: array set to \"%s\"", s->s_name); - x->x_buf = b; - } else { - post("subst: no array \"%s\" (error %d)", s->s_name, b); - x->x_buf = 0; - } -} - -// -// load row from array (input!!) -// -static void subst_load(t_subst *x, t_symbol *s) -{ - t_garray *b; /* make local copy of array */ - t_float *tab; /* the content itselfe */ - int items, i; - - if ((b = (t_garray *)pd_findbyclass(s, garray_class))) - { - post("subst: array set to \"%s\"", s->s_name); - } else { - post("subst: no array \"%s\" (error %d)", s->s_name, b); - return; - } - - // read from our array - if (!garray_getfloatarray(b, &items, &tab)) - { - post("subst: couldn't read from array!"); - return; - } - for(i = 0; i < items; i++) - { - SETFLOAT(x->x_row + i, tab[i]); // copy array into x->x_row - } - x->x_length = items; - post("subst: loaded %d values from array \"%s\"", items, s->s_name); -} - -// -// substitute an interval choosen by chance -// -static void subst_bang(t_subst *x) -{ - subst_calc(x, -1); -} - -// -// substitute the Nth interval -// -static void subst_intv(t_subst *x, t_floatarg f) -{ - int i = (int)f; - if(i > x->x_length) i = x->x_length; - subst_calc(x, i); -} - -// -// set the minimum order of substitution -// -static void subst_set_order(t_subst *x, t_floatarg f) -{ - x->x_order = (t_int)f; - if(x->x_order < 2)x->x_order = 2; - post("subst: set order to %d", x->x_order); -} - -// -// method to print out: but what? -// -static void subst_display(t_subst *x) -{ -} - -// -// function to create an instance of the subst class -// -static void *subst_new(t_symbol *s, int argc, t_atom *argv) -{ - long i; - t_symbol *sym; - t_subst *x = (t_subst *)pd_new(subst_class); - // read in order... - x->x_order = 3; - if(argc == 1) - { - x->x_order = atom_getintarg(0, argc, argv); - } - else if(argc == 2) - { - sym = atom_getsymbolarg(0, argc, argv); - x->x_order = atom_getintarg(1, argc, argv); - subst_set(x, sym); - } - - // create outlets - x->x_outlist = outlet_new(&x->x_obj, gensym("list")); - x->x_outlength = outlet_new(&x->x_obj, gensym("float")); - - return(x); // always return a copy of the created object -} - -static void subst_free(t_subst *x) -{ - /* nothing to do */ -} - -#ifndef MAXLIB -void subst_setup(void) -{ - subst_class = class_new(gensym("subst"), (t_newmethod)subst_new, - (t_method)subst_free, sizeof(t_subst), 0, A_GIMME, 0); - class_addmethod(subst_class, (t_method)subst_set_order, gensym("order"), A_FLOAT, 0); - class_addmethod(subst_class, (t_method)subst_intv, gensym("interval"), A_FLOAT, 0); - class_addmethod(subst_class, (t_method)subst_set, gensym("set"), A_SYMBOL, 0); - class_addmethod(subst_class, (t_method)subst_load, gensym("load"), A_SYMBOL, 0); - class_addmethod(subst_class, (t_method)subst_display, gensym("display"), 0); - class_addlist(subst_class, subst_list); - class_addbang(subst_class, subst_bang); - - post(version); -} -#else -void maxlib_subst_setup(void) -{ - subst_class = class_new(gensym("maxlib_subst"), (t_newmethod)subst_new, - (t_method)subst_free, sizeof(t_subst), 0, A_GIMME, 0); - class_addcreator((t_newmethod)subst_new, gensym("subst"), A_GIMME, 0); - class_addmethod(subst_class, (t_method)subst_set_order, gensym("order"), A_FLOAT, 0); - class_addmethod(subst_class, (t_method)subst_intv, gensym("interval"), A_FLOAT, 0); - class_addmethod(subst_class, (t_method)subst_set, gensym("set"), A_SYMBOL, 0); - class_addmethod(subst_class, (t_method)subst_load, gensym("load"), A_SYMBOL, 0); - class_addmethod(subst_class, (t_method)subst_display, gensym("display"), 0); - class_addlist(subst_class, subst_list); - class_addbang(subst_class, subst_bang); - class_sethelpsymbol(subst_class, gensym("maxlib/subst-help.pd")); -} -#endif +/* ------------------------- subst ------------------------------------------ */ +/* */ +/* Performs 'self-similar' substitution of a given list of values. */ +/* Written by Olaf Matthes */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ +#include "m_pd.h" + + +static char *version = "subst v0.1, self-similar substitution of rows (list or array)\n" + " written by Olaf Matthes "; + +#undef DEBUG +//#define DEBUG + +#define MAXSIZE 1024 + +#include +#include + + +// +// Maxlife object data structure +// +typedef struct subst +{ + t_object x_obj; // must begin every object + t_outlet *x_outlist; // outlet for the processed list + t_outlet *x_outlength; + t_atom x_row[MAXSIZE]; // row of values to get processed + t_int x_length; // length of row + t_int x_order; // size of the CA field/world + t_symbol *x_array; // name of array that holds the data + t_garray *x_buf; // content of that array +} t_subst; + +// +// Function prototypes for our methods and functions +// +static t_class *subst_class; // global variable that points to the Maxlife class + +// +// get the sum of intervals from no a to no b +// Parameters: the row, it's length, intv a, intev b +// +static int sum_intv(t_atom *argv, int argc, int a, int b) +{ + int i; + int summe = 0; // sum of intervals + + if(a==b) + return(0); // same index + if(atom_getintarg(a, argc, argv) == atom_getintarg(b, argc, argv)) + return(0); // same value + + for(i=a;i atom_getintarg(i, argc, argv)) // positive intv. + { + summe += ((atom_getintarg(i + 1, argc, argv) - atom_getintarg(i, argc, argv)) % 12); + } + else // negative interval + { + summe -= ((atom_getintarg(i + 1, argc, argv) - atom_getintarg(i, argc, argv)) % 12); + } + } + return(summe); +} +//----- Anzahl Partialreihen mit Interval d ------------------------------- +static int no_part(t_atom *argv, int argc, int a, int b, int d) // nn +{ + int i,j,r = 0; + + if(a = b)return(0); + + for(i = a; i < b; i++) + { + for(j=a+1;j no_part(argv, argc, a, b, d)) + return(-1); + for(i = 1; i = (b - a); i++) + { + for(j = 1; j = b; j++) + { + if(sum_intv(argv, argc, i, j) == d) + r++; + } + } + return(r); +} +//----- Test, ob Partialreihe der Ordnung o mit Interval d existiert ---------- +static int check_part_intv(t_atom *argv, int argc, int o, int d) +{ + int z; + + for(z = 0; z < argc - o; z++) + { + if(sum_intv(argv, argc, z, z + o) == d) + return(z); // Abstand von Reihenanfang + } + + return(-1); +} + +static int my_random(int range) { + int ret = rand(); + ret = ret % range; // limit to desired output range + return(ret); +} + +// +// the substitution algorhythm +// +static int subst_calc(t_subst *x, int n) +{ + int i,j,k,l,o = x->x_order; + int s = -1; + int intv; + t_atom newrow[MAXSIZE]; + t_garray *A = x->x_buf; + int npoints; + t_float *vec; + + if(x->x_length <= 1) + { + post("subst: need some data first!"); + return(-1); + } + srand((unsigned int)clock_getlogicaltime()); + + if(n == -1) // no interval given: choose one by chance + { + do + { + n = my_random(x->x_length - 1); // choose interval + intv = sum_intv(x->x_row, x->x_length, n, n + 1); // size of this interval + } + while(intv == 0); // ...until we found one that is not 0! + } + else intv = sum_intv(x->x_row, x->x_length, n, n + 1); + +#ifdef DEBUG + post("subst: substitution of %dth interval (%d halftones)", n+1, intv); +#endif + + /* for-Schleife für möglichst lange Substitutionen + for(j=anzahlReihe(alteReihe);j>2;j--) */ + for(j = x->x_order; j < x->x_length; j++) // prefer lower orders (min. 2) + { // search for possible order... + s = check_part_intv(x->x_row, x->x_length, j, intv); + if(s != -1) // check if there is a partial row with the interval we want + { + o = j; // save actual order, might be larger then x->x_order + break; // ... do it! + } + if(o == j)break; // found one + } + + for(i = 0; i < x->x_length; i++) + { + if(i <= n) // just copy values before substitution + { + newrow[i] = x->x_row[i]; + } + if((i == n) && (s != -1)) // now substitute + { + for(k=1;kx_row, x->x_length, s+k-1, s+k))); +#ifdef DEBUG + post("subst: new interval[%d]: %d ", k, sum_intv(x->x_row, x->x_length, s+k-1, s+k)); +#endif + } + post("subst: replaced interval %d (%d halftones) with %d new intervals", n, intv, o); + } + else if((i == n) && (s == -1)) // not partial row found + { + o = 1; // order is 1 -> now substitution + newrow[i] = x->x_row[i]; // copy the next value of the row + post("subst: coundn't find any partial rows to fit in!"); + } + + if(i>n) // behind substitution + { + newrow[i+(o-1)] = x->x_row[i]; // copy rest or row + } + } + + // copy stuff back... + x->x_length = l = x->x_length + o - 1; + for(i = 0; i < x->x_length; i++) + x->x_row[i] = newrow[i]; + + // write to array + if(x->x_array)if (!(A = (t_garray *)pd_findbyclass(x->x_array, garray_class))) + error("subst: %s: no such array", x->x_array->s_name); + else if (!garray_getfloatarray(A, &npoints, &vec)) + error("subst: %s: bad template ", x->x_array->s_name); + else + { + i = 0; + + if (l >= npoints) // keep end of array + { + while(npoints--) + { + *vec++ = atom_getfloat(x->x_row + i); + i++; + } + } + else // update + { + npoints -= l; + while (l--) + { + *vec++ = atom_getfloat(x->x_row + i); + i++; + } + while (npoints--) *vec++ = 0; + } + garray_redraw(A); + } + + // output stuff + outlet_float(x->x_outlength, x->x_length); + outlet_list(x->x_outlist, NULL, x->x_length, x->x_row); + + return(0); +} + +static void subst_list(t_subst *x, t_symbol *s, int argc, t_atom *argv) +{ + t_garray *b = x->x_buf; /* make local copy of array */ + float *tab; /* we'll store notes in here */ + int items; + int i; + + for(i = 0; i < argc; i++) + { + x->x_row[i] = argv[i]; // just copy input + } + x->x_length = argc; + +} + +// +// choose the array that holds the processed row (output!!) +// +void subst_set(t_subst *x, t_symbol *s) +{ + t_garray *b; + + x->x_array = s; + + if ((b = (t_garray *)pd_findbyclass(s, garray_class))) + { + post("subst: array set to \"%s\"", s->s_name); + x->x_buf = b; + } else { + post("subst: no array \"%s\" (error %d)", s->s_name, b); + x->x_buf = 0; + } +} + +// +// load row from array (input!!) +// +static void subst_load(t_subst *x, t_symbol *s) +{ + t_garray *b; /* make local copy of array */ + t_float *tab; /* the content itselfe */ + int items, i; + + if ((b = (t_garray *)pd_findbyclass(s, garray_class))) + { + post("subst: array set to \"%s\"", s->s_name); + } else { + post("subst: no array \"%s\" (error %d)", s->s_name, b); + return; + } + + // read from our array + if (!garray_getfloatarray(b, &items, &tab)) + { + post("subst: couldn't read from array!"); + return; + } + for(i = 0; i < items; i++) + { + SETFLOAT(x->x_row + i, tab[i]); // copy array into x->x_row + } + x->x_length = items; + post("subst: loaded %d values from array \"%s\"", items, s->s_name); +} + +// +// substitute an interval choosen by chance +// +static void subst_bang(t_subst *x) +{ + subst_calc(x, -1); +} + +// +// substitute the Nth interval +// +static void subst_intv(t_subst *x, t_floatarg f) +{ + int i = (int)f; + if(i > x->x_length) i = x->x_length; + subst_calc(x, i); +} + +// +// set the minimum order of substitution +// +static void subst_set_order(t_subst *x, t_floatarg f) +{ + x->x_order = (t_int)f; + if(x->x_order < 2)x->x_order = 2; + post("subst: set order to %d", x->x_order); +} + +// +// method to print out: but what? +// +static void subst_display(t_subst *x) +{ +} + +// +// function to create an instance of the subst class +// +static void *subst_new(t_symbol *s, int argc, t_atom *argv) +{ + long i; + t_symbol *sym; + t_subst *x = (t_subst *)pd_new(subst_class); + // read in order... + x->x_order = 3; + if(argc == 1) + { + x->x_order = atom_getintarg(0, argc, argv); + } + else if(argc == 2) + { + sym = atom_getsymbolarg(0, argc, argv); + x->x_order = atom_getintarg(1, argc, argv); + subst_set(x, sym); + } + + // create outlets + x->x_outlist = outlet_new(&x->x_obj, gensym("list")); + x->x_outlength = outlet_new(&x->x_obj, gensym("float")); + + return(x); // always return a copy of the created object +} + +static void subst_free(t_subst *x) +{ + /* nothing to do */ +} + +#ifndef MAXLIB +void subst_setup(void) +{ + subst_class = class_new(gensym("subst"), (t_newmethod)subst_new, + (t_method)subst_free, sizeof(t_subst), 0, A_GIMME, 0); + class_addmethod(subst_class, (t_method)subst_set_order, gensym("order"), A_FLOAT, 0); + class_addmethod(subst_class, (t_method)subst_intv, gensym("interval"), A_FLOAT, 0); + class_addmethod(subst_class, (t_method)subst_set, gensym("set"), A_SYMBOL, 0); + class_addmethod(subst_class, (t_method)subst_load, gensym("load"), A_SYMBOL, 0); + class_addmethod(subst_class, (t_method)subst_display, gensym("display"), 0); + class_addlist(subst_class, subst_list); + class_addbang(subst_class, subst_bang); + + logpost(NULL, 4, version); +} +#else +void maxlib_subst_setup(void) +{ + subst_class = class_new(gensym("maxlib_subst"), (t_newmethod)subst_new, + (t_method)subst_free, sizeof(t_subst), 0, A_GIMME, 0); + class_addcreator((t_newmethod)subst_new, gensym("subst"), A_GIMME, 0); + class_addmethod(subst_class, (t_method)subst_set_order, gensym("order"), A_FLOAT, 0); + class_addmethod(subst_class, (t_method)subst_intv, gensym("interval"), A_FLOAT, 0); + class_addmethod(subst_class, (t_method)subst_set, gensym("set"), A_SYMBOL, 0); + class_addmethod(subst_class, (t_method)subst_load, gensym("load"), A_SYMBOL, 0); + class_addmethod(subst_class, (t_method)subst_display, gensym("display"), 0); + class_addlist(subst_class, subst_list); + class_addbang(subst_class, subst_bang); + class_sethelpsymbol(subst_class, gensym("maxlib/subst-help.pd")); +} +#endif diff --git a/sync.c b/sync.c index ccfb172..7024a95 100644 --- a/sync.c +++ b/sync.c @@ -1,294 +1,294 @@ -/* ------------------------- sync ------------------------------------------- */ -/* */ -/* syncronises outputs depending on inputs. */ -/* Written by Olaf Matthes */ -/* Based on 'sync' from jMax. */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include -#include - -#define SYNC_MAX_SIZE (int)(sizeof(unsigned int) * 8) - -static char *version = "sync v0.1, written by Olaf Matthes \n" - " based on sync from jMax"; - -typedef struct sync -{ - t_object x_ob; - t_float x_min; /* low border of input range */ - t_float x_max; /* high border of input range */ - t_outlet *x_outlet[SYNC_MAX_SIZE]; - - t_int x_n; - unsigned int x_trigger; /* control bits: trigger on input at given inlets */ - unsigned int x_require; /* control bits: require input on given inlets */ - unsigned int x_reset; /* control bits: reset memory of given inputs after on each input */ - unsigned int x_wait; /* status bits: wait for input at given inlet before output */ - t_atom x_a[SYNC_MAX_SIZE]; - enum {mode_all, mode_select} mode; -} t_sync; - -typedef struct proxy -{ - t_object obj; - t_int index; /* number of proxy inlet(s) */ - t_sync *x; /* we'll put the other struct in here */ -} t_proxy; - -static void sync_output(t_sync *x) -{ - int i; - - for(i=x->x_n-1; i>=0; i--) - if(x->x_a[i].a_type != A_SEMI) - outlet_list(x->x_outlet[i], NULL, 1, x->x_a + i); -} - -static void sync_input(t_proxy *p, t_symbol *s, int ac, t_atom *at) -{ - t_sync *x = (t_sync *)(p->x); - int winlet = p->index; - - if(ac) - { - unsigned int bit = 1 << winlet; - - x->x_a[winlet] = at[0]; - - x->x_wait &= ~bit; - - if(!x->x_wait && (x->x_trigger & bit)) - { - sync_output(x); - x->x_wait |= x->x_reset & x->x_require; - } - } -} - -static void sync_float_input(t_proxy *p, t_floatarg f) -{ - t_sync *x = (t_sync *)(p->x); - int winlet = p->index; - - { - unsigned int bit = 1 << winlet; - - SETFLOAT(x->x_a + winlet, f); - - x->x_wait &= ~bit; - - if(!x->x_wait && (x->x_trigger & bit)) - { - sync_output(x); - x->x_wait |= x->x_reset & x->x_require; - } - } -} - -static void sync_set_bits(unsigned int *bits, int n, t_atom *at, int sign) -{ - if(at->a_type == A_SYMBOL) - { - t_symbol *mode = atom_getsymbol(at); - - if(mode == gensym("all")) - *bits = (1 << n) - 1; - else if(mode == gensym("none")) - *bits = 0; - } - else if(at->a_type == A_FLOAT) - { - int in = (int)atom_getfloat(at) * sign; - - if(in >= 0 && in < n) - *bits = 1 << in; - } - else if(at->a_type == A_GIMME) - { - int size = n; - int i; - - *bits = 0; - - for(i=0; i= 0 && in < n) - *bits |= 1 << in; - } - } - } -} - -static void sync_set_trigger(t_sync *x, t_symbol *s, int ac, t_atom *at) -{ - sync_set_bits(&x->x_trigger, x->x_n, at, 1); -} - -static void sync_set_require(t_sync *x, t_symbol *s, int ac, t_atom *at) -{ - unsigned int once = 0; - - sync_set_bits(&x->x_require, x->x_n, at, 1); - sync_set_bits(&once, x->x_n, at, -1); - - x->x_reset = ~once; - x->x_wait = x->x_require | once; -} - -static void sync_set_mode(t_sync *x, t_symbol *mode) -{ - if(mode == gensym("any")) - { - x->x_trigger = (1 << x->x_n) - 1; - x->x_reset = 0; - x->x_require = 0; - } - else if(mode == gensym("all")) - x->x_trigger = x->x_require = x->x_reset = x->x_wait = (1 << x->x_n) - 1; - else if(mode == gensym("left")) - { - x->x_trigger = 1; - x->x_reset = 0; - x->x_require = 0; - } - else if(mode == gensym("right")) - { - x->x_trigger = (1 << (x->x_n - 1)); - x->x_reset = 0; - x->x_require = 0; - } - - x->x_wait = x->x_require; -} - -static void sync_float(t_sync *x, t_floatarg f) -{ - unsigned int bit = 1 << 0; - - SETFLOAT(x->x_a, f); - - x->x_wait &= ~bit; - - if(!x->x_wait && (x->x_trigger & bit)) - { - sync_output(x); - x->x_wait |= x->x_reset & x->x_require; - } -} - -static t_class *sync_class; -static t_class *proxy_class; - -static void *sync_new(t_symbol *s, int ac, t_atom *at) -{ - int n = 0; - int i; - t_sync *x = (t_sync *)pd_new(sync_class); - t_proxy *inlet[SYNC_MAX_SIZE]; - - /* void state - we fill with SEMI and treat this as 'void' */ - for(i=0; ix_a + i); - - if(ac == 1) - { - if(at->a_type == A_FLOAT) - { - n = atom_getfloat(at); - - if(n < 2) - n = 2; - else if(n > SYNC_MAX_SIZE) - n = SYNC_MAX_SIZE; - } - else - { - post("sync: wrong argument"); - return (0); - } - } - else if(ac > 1) - { - if(ac > SYNC_MAX_SIZE) - ac = SYNC_MAX_SIZE; - - n = ac; - - for(i=0; ix_a[i] = at[i]; - } - - x->x_n = n; - x->x_trigger = x->x_require = x->x_reset = x->x_wait = (1 << n) - 1; - - x->x_outlet[0] = outlet_new(&x->x_ob, gensym("list")); - - for(i=1; ix = x; /* make t_sync *x visible to the proxy inlets */ - inlet[i]->index = i; /* remember it's number */ - /* it belongs to the object t_sync but the destination is t_proxy */ - inlet_new(&x->x_ob, &inlet[i]->obj.ob_pd, 0,0); - - x->x_outlet[i] = outlet_new(&x->x_ob, gensym("list")); - } - - return (void *)x; -} - -#ifndef MAXLIB -void sync_setup(void) -{ - sync_class = class_new(gensym("sync"), (t_newmethod)sync_new, - 0, sizeof(t_sync), 0, A_GIMME, 0); -#else -void maxlib_sync_setup(void) -{ - sync_class = class_new(gensym("maxlib_sync"), (t_newmethod)sync_new, - 0, sizeof(t_sync), 0, A_GIMME, 0); -#endif - /* a class for the proxy inlet: */ - proxy_class = class_new(gensym("maxlib_sync_proxy"), NULL, NULL, sizeof(t_proxy), - CLASS_PD|CLASS_NOINLET, A_NULL); - - class_addfloat(proxy_class, sync_float_input); - class_addanything(proxy_class, sync_input); - - class_addfloat(sync_class, sync_float); - class_addmethod(sync_class, (t_method)sync_set_trigger, gensym("trigger"), A_GIMME, 0); - class_addmethod(sync_class, (t_method)sync_set_require, gensym("require"), A_GIMME, 0); - class_addmethod(sync_class, (t_method)sync_set_mode, gensym("mode"), A_SYMBOL, 0); -#ifndef MAXLIB - - post(version); -#else - class_addcreator((t_newmethod)sync_new, gensym("sync"), A_GIMME, 0); - class_sethelpsymbol(sync_class, gensym("maxlib/sync-help.pd")); -#endif -} - +/* ------------------------- sync ------------------------------------------- */ +/* */ +/* syncronises outputs depending on inputs. */ +/* Written by Olaf Matthes */ +/* Based on 'sync' from jMax. */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include +#include + +#define SYNC_MAX_SIZE (int)(sizeof(unsigned int) * 8) + +static char *version = "sync v0.1, written by Olaf Matthes \n" + " based on sync from jMax"; + +typedef struct sync +{ + t_object x_ob; + t_float x_min; /* low border of input range */ + t_float x_max; /* high border of input range */ + t_outlet *x_outlet[SYNC_MAX_SIZE]; + + t_int x_n; + unsigned int x_trigger; /* control bits: trigger on input at given inlets */ + unsigned int x_require; /* control bits: require input on given inlets */ + unsigned int x_reset; /* control bits: reset memory of given inputs after on each input */ + unsigned int x_wait; /* status bits: wait for input at given inlet before output */ + t_atom x_a[SYNC_MAX_SIZE]; + enum {mode_all, mode_select} mode; +} t_sync; + +typedef struct proxy +{ + t_object obj; + t_int index; /* number of proxy inlet(s) */ + t_sync *x; /* we'll put the other struct in here */ +} t_proxy; + +static void sync_output(t_sync *x) +{ + int i; + + for(i=x->x_n-1; i>=0; i--) + if(x->x_a[i].a_type != A_SEMI) + outlet_list(x->x_outlet[i], NULL, 1, x->x_a + i); +} + +static void sync_input(t_proxy *p, t_symbol *s, int ac, t_atom *at) +{ + t_sync *x = (t_sync *)(p->x); + int winlet = p->index; + + if(ac) + { + unsigned int bit = 1 << winlet; + + x->x_a[winlet] = at[0]; + + x->x_wait &= ~bit; + + if(!x->x_wait && (x->x_trigger & bit)) + { + sync_output(x); + x->x_wait |= x->x_reset & x->x_require; + } + } +} + +static void sync_float_input(t_proxy *p, t_floatarg f) +{ + t_sync *x = (t_sync *)(p->x); + int winlet = p->index; + + { + unsigned int bit = 1 << winlet; + + SETFLOAT(x->x_a + winlet, f); + + x->x_wait &= ~bit; + + if(!x->x_wait && (x->x_trigger & bit)) + { + sync_output(x); + x->x_wait |= x->x_reset & x->x_require; + } + } +} + +static void sync_set_bits(unsigned int *bits, int n, t_atom *at, int sign) +{ + if(at->a_type == A_SYMBOL) + { + t_symbol *mode = atom_getsymbol(at); + + if(mode == gensym("all")) + *bits = (1 << n) - 1; + else if(mode == gensym("none")) + *bits = 0; + } + else if(at->a_type == A_FLOAT) + { + int in = (int)atom_getfloat(at) * sign; + + if(in >= 0 && in < n) + *bits = 1 << in; + } + else if(at->a_type == A_GIMME) + { + int size = n; + int i; + + *bits = 0; + + for(i=0; i= 0 && in < n) + *bits |= 1 << in; + } + } + } +} + +static void sync_set_trigger(t_sync *x, t_symbol *s, int ac, t_atom *at) +{ + sync_set_bits(&x->x_trigger, x->x_n, at, 1); +} + +static void sync_set_require(t_sync *x, t_symbol *s, int ac, t_atom *at) +{ + unsigned int once = 0; + + sync_set_bits(&x->x_require, x->x_n, at, 1); + sync_set_bits(&once, x->x_n, at, -1); + + x->x_reset = ~once; + x->x_wait = x->x_require | once; +} + +static void sync_set_mode(t_sync *x, t_symbol *mode) +{ + if(mode == gensym("any")) + { + x->x_trigger = (1 << x->x_n) - 1; + x->x_reset = 0; + x->x_require = 0; + } + else if(mode == gensym("all")) + x->x_trigger = x->x_require = x->x_reset = x->x_wait = (1 << x->x_n) - 1; + else if(mode == gensym("left")) + { + x->x_trigger = 1; + x->x_reset = 0; + x->x_require = 0; + } + else if(mode == gensym("right")) + { + x->x_trigger = (1 << (x->x_n - 1)); + x->x_reset = 0; + x->x_require = 0; + } + + x->x_wait = x->x_require; +} + +static void sync_float(t_sync *x, t_floatarg f) +{ + unsigned int bit = 1 << 0; + + SETFLOAT(x->x_a, f); + + x->x_wait &= ~bit; + + if(!x->x_wait && (x->x_trigger & bit)) + { + sync_output(x); + x->x_wait |= x->x_reset & x->x_require; + } +} + +static t_class *sync_class; +static t_class *proxy_class; + +static void *sync_new(t_symbol *s, int ac, t_atom *at) +{ + int n = 0; + int i; + t_sync *x = (t_sync *)pd_new(sync_class); + t_proxy *inlet[SYNC_MAX_SIZE]; + + /* void state - we fill with SEMI and treat this as 'void' */ + for(i=0; ix_a + i); + + if(ac == 1) + { + if(at->a_type == A_FLOAT) + { + n = atom_getfloat(at); + + if(n < 2) + n = 2; + else if(n > SYNC_MAX_SIZE) + n = SYNC_MAX_SIZE; + } + else + { + post("sync: wrong argument"); + return (0); + } + } + else if(ac > 1) + { + if(ac > SYNC_MAX_SIZE) + ac = SYNC_MAX_SIZE; + + n = ac; + + for(i=0; ix_a[i] = at[i]; + } + + x->x_n = n; + x->x_trigger = x->x_require = x->x_reset = x->x_wait = (1 << n) - 1; + + x->x_outlet[0] = outlet_new(&x->x_ob, gensym("list")); + + for(i=1; ix = x; /* make t_sync *x visible to the proxy inlets */ + inlet[i]->index = i; /* remember it's number */ + /* it belongs to the object t_sync but the destination is t_proxy */ + inlet_new(&x->x_ob, &inlet[i]->obj.ob_pd, 0,0); + + x->x_outlet[i] = outlet_new(&x->x_ob, gensym("list")); + } + + return (void *)x; +} + +#ifndef MAXLIB +void sync_setup(void) +{ + sync_class = class_new(gensym("sync"), (t_newmethod)sync_new, + 0, sizeof(t_sync), 0, A_GIMME, 0); +#else +void maxlib_sync_setup(void) +{ + sync_class = class_new(gensym("maxlib_sync"), (t_newmethod)sync_new, + 0, sizeof(t_sync), 0, A_GIMME, 0); +#endif + /* a class for the proxy inlet: */ + proxy_class = class_new(gensym("maxlib_sync_proxy"), NULL, NULL, sizeof(t_proxy), + CLASS_PD|CLASS_NOINLET, A_NULL); + + class_addfloat(proxy_class, sync_float_input); + class_addanything(proxy_class, sync_input); + + class_addfloat(sync_class, sync_float); + class_addmethod(sync_class, (t_method)sync_set_trigger, gensym("trigger"), A_GIMME, 0); + class_addmethod(sync_class, (t_method)sync_set_require, gensym("require"), A_GIMME, 0); + class_addmethod(sync_class, (t_method)sync_set_mode, gensym("mode"), A_SYMBOL, 0); +#ifndef MAXLIB + + logpost(NULL, 4, version); +#else + class_addcreator((t_newmethod)sync_new, gensym("sync"), A_GIMME, 0); + class_sethelpsymbol(sync_class, gensym("maxlib/sync-help.pd")); +#endif +} + diff --git a/temperature.c b/temperature.c index 78b7fe7..ac9287e 100644 --- a/temperature.c +++ b/temperature.c @@ -1,120 +1,120 @@ -/* -------------------------- temperature ------------------------------------- */ -/* */ -/* Calculates temperature: number of 'events' within N milliseconds. */ -/* Written by Olaf Matthes */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include - -static char *version = "temperature v0.1, written by Olaf Matthes "; - -typedef struct temperature -{ - t_object x_ob; - t_clock *x_clock; - t_outlet *x_outfloat; /* output the temperature */ - t_int x_index; /* the number of elements to average */ - t_int x_time; - -} t_temperature; - -static void temperature_tick(t_temperature *x) -{ - outlet_float(x->x_outfloat, x->x_index); - x->x_index = 0; - clock_delay(x->x_clock, x->x_time); -} - -static void temperature_float(t_temperature *x, t_floatarg f) -{ - x->x_index++; /* just count number of 'events' */ -} - -static void temperature_anything(t_temperature *x, t_symbol *s, int argc, t_atom *argv) -{ - x->x_index++; /* just count number of 'events' */ -} - -static void temperature_time(t_temperature *x, t_floatarg f) -{ - x->x_time = (t_int)f; - if(x->x_time < 1) x->x_time = 1; - clock_unset(x->x_clock); - clock_delay(x->x_clock, x->x_time); -} - -static void temperature_reset(t_temperature *x) -{ - x->x_index = 0; - post("temperature: reset"); -} - -static void temperature_free(t_temperature *x) -{ - clock_free(x->x_clock); -} - -static t_class *temperature_class; - -static void *temperature_new(t_floatarg f) -{ - t_temperature *x = (t_temperature *)pd_new(temperature_class); - inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("time")); - x->x_outfloat = outlet_new(&x->x_ob, gensym("float")); - x->x_clock = clock_new(x, (t_method)temperature_tick); - - x->x_time = (t_int)f; - if(x->x_time < 1) - { - x->x_time = 1; - post("temperature: set time to %d ms", x->x_time); - } - x->x_index = 0; - clock_delay(x->x_clock, x->x_time); - return (void *)x; -} - -#ifndef MAXLIB -void temperature_setup(void) -{ - temperature_class = class_new(gensym("temperature"), (t_newmethod)temperature_new, - (t_method)temperature_free, sizeof(t_temperature), 0, A_DEFFLOAT, 0); - class_addmethod(temperature_class, (t_method)temperature_reset, gensym("reset"), 0); - class_addfloat(temperature_class, temperature_float); - class_addmethod(temperature_class, (t_method)temperature_time, gensym("time"), A_FLOAT, 0); - class_addanything(temperature_class, temperature_anything); - - post(version); -} -#else -void maxlib_temperature_setup(void) -{ - temperature_class = class_new(gensym("maxlib_temperature"), (t_newmethod)temperature_new, - (t_method)temperature_free, sizeof(t_temperature), 0, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)temperature_new, gensym("temperature"), A_DEFFLOAT, 0); - class_addmethod(temperature_class, (t_method)temperature_reset, gensym("reset"), 0); - class_addfloat(temperature_class, temperature_float); - class_addmethod(temperature_class, (t_method)temperature_time, gensym("time"), A_FLOAT, 0); - class_addanything(temperature_class, temperature_anything); - class_sethelpsymbol(temperature_class, gensym("maxlib/temperature-help.pd")); -} -#endif +/* -------------------------- temperature ------------------------------------- */ +/* */ +/* Calculates temperature: number of 'events' within N milliseconds. */ +/* Written by Olaf Matthes */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include + +static char *version = "temperature v0.1, written by Olaf Matthes "; + +typedef struct temperature +{ + t_object x_ob; + t_clock *x_clock; + t_outlet *x_outfloat; /* output the temperature */ + t_int x_index; /* the number of elements to average */ + t_int x_time; + +} t_temperature; + +static void temperature_tick(t_temperature *x) +{ + outlet_float(x->x_outfloat, x->x_index); + x->x_index = 0; + clock_delay(x->x_clock, x->x_time); +} + +static void temperature_float(t_temperature *x, t_floatarg f) +{ + x->x_index++; /* just count number of 'events' */ +} + +static void temperature_anything(t_temperature *x, t_symbol *s, int argc, t_atom *argv) +{ + x->x_index++; /* just count number of 'events' */ +} + +static void temperature_time(t_temperature *x, t_floatarg f) +{ + x->x_time = (t_int)f; + if(x->x_time < 1) x->x_time = 1; + clock_unset(x->x_clock); + clock_delay(x->x_clock, x->x_time); +} + +static void temperature_reset(t_temperature *x) +{ + x->x_index = 0; + post("temperature: reset"); +} + +static void temperature_free(t_temperature *x) +{ + clock_free(x->x_clock); +} + +static t_class *temperature_class; + +static void *temperature_new(t_floatarg f) +{ + t_temperature *x = (t_temperature *)pd_new(temperature_class); + inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("time")); + x->x_outfloat = outlet_new(&x->x_ob, gensym("float")); + x->x_clock = clock_new(x, (t_method)temperature_tick); + + x->x_time = (t_int)f; + if(x->x_time < 1) + { + x->x_time = 1; + post("temperature: set time to %d ms", x->x_time); + } + x->x_index = 0; + clock_delay(x->x_clock, x->x_time); + return (void *)x; +} + +#ifndef MAXLIB +void temperature_setup(void) +{ + temperature_class = class_new(gensym("temperature"), (t_newmethod)temperature_new, + (t_method)temperature_free, sizeof(t_temperature), 0, A_DEFFLOAT, 0); + class_addmethod(temperature_class, (t_method)temperature_reset, gensym("reset"), 0); + class_addfloat(temperature_class, temperature_float); + class_addmethod(temperature_class, (t_method)temperature_time, gensym("time"), A_FLOAT, 0); + class_addanything(temperature_class, temperature_anything); + + logpost(NULL, 4, version); +} +#else +void maxlib_temperature_setup(void) +{ + temperature_class = class_new(gensym("maxlib_temperature"), (t_newmethod)temperature_new, + (t_method)temperature_free, sizeof(t_temperature), 0, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)temperature_new, gensym("temperature"), A_DEFFLOAT, 0); + class_addmethod(temperature_class, (t_method)temperature_reset, gensym("reset"), 0); + class_addfloat(temperature_class, temperature_float); + class_addmethod(temperature_class, (t_method)temperature_time, gensym("time"), A_FLOAT, 0); + class_addanything(temperature_class, temperature_anything); + class_sethelpsymbol(temperature_class, gensym("maxlib/temperature-help.pd")); +} +#endif diff --git a/tilt.c b/tilt.c index dde587d..a3a3ef5 100644 --- a/tilt.c +++ b/tilt.c @@ -1,189 +1,189 @@ -/* ------------------------- tilt --------------------------------------------- */ -/* */ -/* Monitor input for changes. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Inspired by code written by Trond Lossius. */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include -#include - -#define MAXSIZE 32 - -static char *version = "tilt v0.1, written by Olaf Matthes "; - -typedef struct tilt -{ - t_object x_ob; - t_outlet *x_out; /* result */ - t_clock *x_clock; - - t_float x_tilt; /* the result */ - t_float x_start_tilt; - t_float x_t; - t_float x_sa; - t_float x_sb; - t_float x_offset; - t_float x_time; - t_float x_wait; - t_float x_hi_limit; - t_float x_low_limit; - t_float x_trip_point; -} t_tilt; - -static void tilt_tick(t_tilt *x) -{ - x->x_sb = x->x_t - x->x_offset; - if((x->x_sb - x->x_sa) > x->x_hi_limit) - { - x->x_sa = x->x_sb; - clock_delay(x->x_clock, x->x_wait); - return; - } - else - { - if((x->x_sb - x->x_sa) > x->x_trip_point) - { - outlet_bang(x->x_out); - clock_delay(x->x_clock, x->x_wait); - return; - } - if((x->x_sb - x->x_sa) < x->x_low_limit) - { - x->x_time++; - if(x->x_time > 15) - { - x->x_start_tilt = x->x_sa; - x->x_time = 0; - } - } - if((x->x_sb - x->x_start_tilt) > x->x_tilt) - { - outlet_bang(x->x_out); - clock_delay(x->x_clock, x->x_wait); - } - else - { - x->x_sa = x->x_sb; - clock_delay(x->x_clock, x->x_wait); - return; - } - } -} - -static void tilt_float(t_tilt *x, t_floatarg f) -{ - x->x_t = f; -} - -static void tilt_intv(t_tilt *x, t_floatarg f) -{ - x->x_wait = f; -} - -static void tilt_tilt(t_tilt *x, t_floatarg f) -{ - x->x_tilt = f; - post("tilt: set tilt to %g", x->x_tilt); -} - -static void tilt_hi_limit(t_tilt *x, t_floatarg f) -{ - x->x_hi_limit = f; - post("tilt: set high limit to %g", x->x_hi_limit); -} - -static void tilt_low_limit(t_tilt *x, t_floatarg f) -{ - x->x_low_limit = f; - post("tilt: set low limit to %g", x->x_low_limit); -} - -static void tilt_trip_point(t_tilt *x, t_floatarg f) -{ - x->x_trip_point = f; - post("tilt: set trip point to %g", x->x_trip_point); -} - -static void tilt_free(t_tilt *x) -{ - clock_free(x->x_clock); -} - -static t_class *tilt_class; - -static void *tilt_new(t_floatarg f, t_floatarg f2) -{ - int i; - - t_tilt *x = (t_tilt *)pd_new(tilt_class); - inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("intv")); - x->x_out = outlet_new(&x->x_ob, gensym("float")); - x->x_clock = clock_new(x, (t_method)tilt_tick); - - x->x_t = f; /* set initial value */ - if(f2 > 4) - x->x_wait = f2; - else - x->x_wait = 4000; - x->x_offset = 0; - x->x_sa = 0; - x->x_sb = 0; - x->x_time = 0; - x->x_tilt = 0; - x->x_start_tilt = x->x_sa = x->x_t - x->x_offset; - x->x_hi_limit = x->x_low_limit = x->x_trip_point = 0; - clock_delay(x->x_clock, x->x_wait); /* wait 4 sec and start calculation */ - - post("tilt: set interval to %g msec", x->x_wait); - return (void *)x; -} - -#ifndef MAXLIB -void tilt_setup(void) -{ - tilt_class = class_new(gensym("tilt"), (t_newmethod)tilt_new, - (t_method)tilt_free, sizeof(t_tilt), 0, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addfloat(tilt_class, tilt_float); - class_addmethod(tilt_class, (t_method)tilt_intv, gensym("intv"), A_FLOAT, 0); - class_addmethod(tilt_class, (t_method)tilt_tilt, gensym("tilt"), A_FLOAT, 0); - class_addmethod(tilt_class, (t_method)tilt_hi_limit, gensym("hi"), A_FLOAT, 0); - class_addmethod(tilt_class, (t_method)tilt_low_limit, gensym("low"), A_FLOAT, 0); - class_addmethod(tilt_class, (t_method)tilt_trip_point, gensym("trip"), A_FLOAT, 0); - - post(version); -} -#else -void maxlib_tilt_setup(void) -{ - tilt_class = class_new(gensym("maxlib_tilt"), (t_newmethod)tilt_new, - (t_method)tilt_free, sizeof(t_tilt), 0, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)tilt_new, gensym("tilt"), A_DEFFLOAT, A_DEFFLOAT, 0); - class_addfloat(tilt_class, tilt_float); - class_addmethod(tilt_class, (t_method)tilt_intv, gensym("intv"), A_FLOAT, 0); - class_addmethod(tilt_class, (t_method)tilt_tilt, gensym("tilt"), A_FLOAT, 0); - class_addmethod(tilt_class, (t_method)tilt_hi_limit, gensym("hi"), A_FLOAT, 0); - class_addmethod(tilt_class, (t_method)tilt_low_limit, gensym("low"), A_FLOAT, 0); - class_addmethod(tilt_class, (t_method)tilt_trip_point, gensym("trip"), A_FLOAT, 0); - class_sethelpsymbol(tilt_class, gensym("maxlib/tilt-help.pd")); -} -#endif +/* ------------------------- tilt --------------------------------------------- */ +/* */ +/* Monitor input for changes. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Inspired by code written by Trond Lossius. */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include +#include + +#define MAXSIZE 32 + +static char *version = "tilt v0.1, written by Olaf Matthes "; + +typedef struct tilt +{ + t_object x_ob; + t_outlet *x_out; /* result */ + t_clock *x_clock; + + t_float x_tilt; /* the result */ + t_float x_start_tilt; + t_float x_t; + t_float x_sa; + t_float x_sb; + t_float x_offset; + t_float x_time; + t_float x_wait; + t_float x_hi_limit; + t_float x_low_limit; + t_float x_trip_point; +} t_tilt; + +static void tilt_tick(t_tilt *x) +{ + x->x_sb = x->x_t - x->x_offset; + if((x->x_sb - x->x_sa) > x->x_hi_limit) + { + x->x_sa = x->x_sb; + clock_delay(x->x_clock, x->x_wait); + return; + } + else + { + if((x->x_sb - x->x_sa) > x->x_trip_point) + { + outlet_bang(x->x_out); + clock_delay(x->x_clock, x->x_wait); + return; + } + if((x->x_sb - x->x_sa) < x->x_low_limit) + { + x->x_time++; + if(x->x_time > 15) + { + x->x_start_tilt = x->x_sa; + x->x_time = 0; + } + } + if((x->x_sb - x->x_start_tilt) > x->x_tilt) + { + outlet_bang(x->x_out); + clock_delay(x->x_clock, x->x_wait); + } + else + { + x->x_sa = x->x_sb; + clock_delay(x->x_clock, x->x_wait); + return; + } + } +} + +static void tilt_float(t_tilt *x, t_floatarg f) +{ + x->x_t = f; +} + +static void tilt_intv(t_tilt *x, t_floatarg f) +{ + x->x_wait = f; +} + +static void tilt_tilt(t_tilt *x, t_floatarg f) +{ + x->x_tilt = f; + post("tilt: set tilt to %g", x->x_tilt); +} + +static void tilt_hi_limit(t_tilt *x, t_floatarg f) +{ + x->x_hi_limit = f; + post("tilt: set high limit to %g", x->x_hi_limit); +} + +static void tilt_low_limit(t_tilt *x, t_floatarg f) +{ + x->x_low_limit = f; + post("tilt: set low limit to %g", x->x_low_limit); +} + +static void tilt_trip_point(t_tilt *x, t_floatarg f) +{ + x->x_trip_point = f; + post("tilt: set trip point to %g", x->x_trip_point); +} + +static void tilt_free(t_tilt *x) +{ + clock_free(x->x_clock); +} + +static t_class *tilt_class; + +static void *tilt_new(t_floatarg f, t_floatarg f2) +{ + int i; + + t_tilt *x = (t_tilt *)pd_new(tilt_class); + inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("intv")); + x->x_out = outlet_new(&x->x_ob, gensym("float")); + x->x_clock = clock_new(x, (t_method)tilt_tick); + + x->x_t = f; /* set initial value */ + if(f2 > 4) + x->x_wait = f2; + else + x->x_wait = 4000; + x->x_offset = 0; + x->x_sa = 0; + x->x_sb = 0; + x->x_time = 0; + x->x_tilt = 0; + x->x_start_tilt = x->x_sa = x->x_t - x->x_offset; + x->x_hi_limit = x->x_low_limit = x->x_trip_point = 0; + clock_delay(x->x_clock, x->x_wait); /* wait 4 sec and start calculation */ + + post("tilt: set interval to %g msec", x->x_wait); + return (void *)x; +} + +#ifndef MAXLIB +void tilt_setup(void) +{ + tilt_class = class_new(gensym("tilt"), (t_newmethod)tilt_new, + (t_method)tilt_free, sizeof(t_tilt), 0, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addfloat(tilt_class, tilt_float); + class_addmethod(tilt_class, (t_method)tilt_intv, gensym("intv"), A_FLOAT, 0); + class_addmethod(tilt_class, (t_method)tilt_tilt, gensym("tilt"), A_FLOAT, 0); + class_addmethod(tilt_class, (t_method)tilt_hi_limit, gensym("hi"), A_FLOAT, 0); + class_addmethod(tilt_class, (t_method)tilt_low_limit, gensym("low"), A_FLOAT, 0); + class_addmethod(tilt_class, (t_method)tilt_trip_point, gensym("trip"), A_FLOAT, 0); + + logpost(NULL, 4, version); +} +#else +void maxlib_tilt_setup(void) +{ + tilt_class = class_new(gensym("maxlib_tilt"), (t_newmethod)tilt_new, + (t_method)tilt_free, sizeof(t_tilt), 0, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)tilt_new, gensym("tilt"), A_DEFFLOAT, A_DEFFLOAT, 0); + class_addfloat(tilt_class, tilt_float); + class_addmethod(tilt_class, (t_method)tilt_intv, gensym("intv"), A_FLOAT, 0); + class_addmethod(tilt_class, (t_method)tilt_tilt, gensym("tilt"), A_FLOAT, 0); + class_addmethod(tilt_class, (t_method)tilt_hi_limit, gensym("hi"), A_FLOAT, 0); + class_addmethod(tilt_class, (t_method)tilt_low_limit, gensym("low"), A_FLOAT, 0); + class_addmethod(tilt_class, (t_method)tilt_trip_point, gensym("trip"), A_FLOAT, 0); + class_sethelpsymbol(tilt_class, gensym("maxlib/tilt-help.pd")); +} +#endif diff --git a/timebang.c b/timebang.c index d70744a..2960ce9 100644 --- a/timebang.c +++ b/timebang.c @@ -1,174 +1,174 @@ -/* ------------------------- timebang --------------------------------------- */ -/* */ -/* Send out bangs at given times (time of day!). */ -/* Written by Olaf Matthes */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include -#include -#include - -#define MAX_TIMES 256 /* maximum number of times to process */ - -static char *version = "timebang v0.2, written by Olaf Matthes "; - -typedef struct timebang -{ - t_object x_ob; - t_clock *x_clock; - t_outlet *x_outlet[MAX_TIMES]; /* the bang outlets */ - t_int x_sec[MAX_TIMES]; /* seconds (0 - 59) */ - t_int x_min[MAX_TIMES]; /* minutes (0 - 59) */ - t_int x_hour[MAX_TIMES]; /* hours (0 - 11) */ - t_int x_mday[MAX_TIMES]; /* day of month (1 - 31) */ - t_int x_mon[MAX_TIMES]; /* month (0 - 11) */ - t_int x_year[MAX_TIMES]; /* year (current year minus 1900) */ - t_int x_wday[MAX_TIMES]; /* day of week (0 - 6, Sunday = 0, -1 = all days) */ - t_int x_over[MAX_TIMES]; /* indicate that time is over */ - t_int x_notimes; /* number of times to bang */ -} t_timebang; - - -static void timebang_tick(t_timebang *x) -{ - time_t now = time(NULL); - struct tm *newtime; - int i; - - newtime = localtime(&now); /* convert to local time. */ - for(i = 0; i < x->x_notimes; i++) - { - if(!x->x_over[i]) - { - if(newtime->tm_hour == x->x_hour[i] && - newtime->tm_min == x->x_min[i] && - newtime->tm_sec >= x->x_sec[i]) - { - x->x_over[i] = 1; /* mark as 'time is over' */ - outlet_bang(x->x_outlet[i]); /* send corresponding bang */ - } - } - else if(newtime->tm_hour != x->x_hour[i]) - x->x_over[i] = 0; /* reactivate time one hour later */ - } - - clock_delay(x->x_clock, 1000); /* come back in one second */ -} - -static void timebang_set(t_timebang *x, t_symbol *s, int ac, t_atom *av) -{ - int i, j; - - if(ac == x->x_notimes * 3) - { - for(i = 0, j = 0; i < ac; i += 3, j++) - { - if (av[i].a_type == A_FLOAT) x->x_hour[j] = av[i].a_w.w_float; - else { post ("timebang: first argument must be (int) hours"); return; } - if (av[i+1].a_type == A_FLOAT) x->x_min[j] = av[i+1].a_w.w_float; - else { post ("timebang: second argument must be (int) minutes"); return; } - if (av[i+2].a_type == A_FLOAT) x->x_sec[j] = av[i+2].a_w.w_float; - else { post ("timebang: third argument must be (int) seconds"); return; } - x->x_over[i] = 0; - } - post("timebang: read in %d times of day:", x->x_notimes); - for(i = 0; i < x->x_notimes; i++) - { - post(" %02d:%02d:%02d", x->x_hour[i], x->x_min[i], x->x_sec[i]); - } - } - else post("timebang: wrong number of parameter"); -} - -static void timebang_bang(t_timebang *x) -{ - time_t now = time(NULL); - struct tm *newtime = localtime(&now); /* convert to local time. */ - post("timebang: local time is %02d:%02d:%02d", newtime->tm_hour, newtime->tm_min, newtime->tm_sec); -} - -static t_class *timebang_class; - -static void *timebang_new(t_symbol *s, int ac, t_atom *av) -{ - int i; - t_timebang *x = (t_timebang *)pd_new(timebang_class); - - x->x_clock = clock_new(x, (t_method)timebang_tick); - - if(ac > MAX_TIMES * 3) - { - post("timebang: too many creation arguments"); - ac = MAX_TIMES * 3; - } - - x->x_notimes = 0; - for(i = 0; i < ac; i += 3) - { - if (av[i].a_type == A_FLOAT) x->x_hour[x->x_notimes] = av[i].a_w.w_float; - else { post ("timebang: first argument must be (int) hours"); return 0; } - if (av[i+1].a_type == A_FLOAT) x->x_min[x->x_notimes] = av[i+1].a_w.w_float; - else { post ("timebang: second argument must be (int) minutes"); return 0; } - if (av[i+2].a_type == A_FLOAT) x->x_sec[x->x_notimes] = av[i+2].a_w.w_float; - else { post ("timebang: third argument must be (int) seconds"); return 0; } - x->x_over[x->x_notimes] = 0; - x->x_notimes++; - } - post("timebang: read in %d times of day:", x->x_notimes); - for(i = 0; i < x->x_notimes; i++) - { - x->x_outlet[i] = outlet_new(&x->x_ob, gensym("bang")); /* create specific bang outlet for time */ - post(" %02d:%02d:%02d", x->x_hour[i], x->x_min[i], x->x_sec[i]); - } - - clock_set(x->x_clock, 0); - - return (void *)x; -} - -static void timebang_free(t_timebang *x) -{ - clock_free(x->x_clock); -} - -#ifndef MAXLIB -void timebang_setup(void) -{ - timebang_class = class_new(gensym("timebang"), (t_newmethod)timebang_new, - (t_method)timebang_free, sizeof(t_timebang), 0, A_GIMME, 0); -#else -void maxlib_timebang_setup(void) -{ - timebang_class = class_new(gensym("maxlib_timebang"), (t_newmethod)timebang_new, - (t_method)timebang_free, sizeof(t_timebang), 0, A_GIMME, 0); - class_addcreator((t_newmethod)timebang_new, gensym("timebang"), A_GIMME, 0); -#endif - class_addmethod(timebang_class, (t_method)timebang_set, gensym("set"), A_GIMME, 0); - class_addbang(timebang_class, (t_method)timebang_bang); -#ifndef MAXLIB - - post(version); -#else - class_sethelpsymbol(timebang_class, gensym("maxlib/timebang-help.pd")); -#endif -} - +/* ------------------------- timebang --------------------------------------- */ +/* */ +/* Send out bangs at given times (time of day!). */ +/* Written by Olaf Matthes */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include +#include +#include + +#define MAX_TIMES 256 /* maximum number of times to process */ + +static char *version = "timebang v0.2, written by Olaf Matthes "; + +typedef struct timebang +{ + t_object x_ob; + t_clock *x_clock; + t_outlet *x_outlet[MAX_TIMES]; /* the bang outlets */ + t_int x_sec[MAX_TIMES]; /* seconds (0 - 59) */ + t_int x_min[MAX_TIMES]; /* minutes (0 - 59) */ + t_int x_hour[MAX_TIMES]; /* hours (0 - 11) */ + t_int x_mday[MAX_TIMES]; /* day of month (1 - 31) */ + t_int x_mon[MAX_TIMES]; /* month (0 - 11) */ + t_int x_year[MAX_TIMES]; /* year (current year minus 1900) */ + t_int x_wday[MAX_TIMES]; /* day of week (0 - 6, Sunday = 0, -1 = all days) */ + t_int x_over[MAX_TIMES]; /* indicate that time is over */ + t_int x_notimes; /* number of times to bang */ +} t_timebang; + + +static void timebang_tick(t_timebang *x) +{ + time_t now = time(NULL); + struct tm *newtime; + int i; + + newtime = localtime(&now); /* convert to local time. */ + for(i = 0; i < x->x_notimes; i++) + { + if(!x->x_over[i]) + { + if(newtime->tm_hour == x->x_hour[i] && + newtime->tm_min == x->x_min[i] && + newtime->tm_sec >= x->x_sec[i]) + { + x->x_over[i] = 1; /* mark as 'time is over' */ + outlet_bang(x->x_outlet[i]); /* send corresponding bang */ + } + } + else if(newtime->tm_hour != x->x_hour[i]) + x->x_over[i] = 0; /* reactivate time one hour later */ + } + + clock_delay(x->x_clock, 1000); /* come back in one second */ +} + +static void timebang_set(t_timebang *x, t_symbol *s, int ac, t_atom *av) +{ + int i, j; + + if(ac == x->x_notimes * 3) + { + for(i = 0, j = 0; i < ac; i += 3, j++) + { + if (av[i].a_type == A_FLOAT) x->x_hour[j] = av[i].a_w.w_float; + else { post ("timebang: first argument must be (int) hours"); return; } + if (av[i+1].a_type == A_FLOAT) x->x_min[j] = av[i+1].a_w.w_float; + else { post ("timebang: second argument must be (int) minutes"); return; } + if (av[i+2].a_type == A_FLOAT) x->x_sec[j] = av[i+2].a_w.w_float; + else { post ("timebang: third argument must be (int) seconds"); return; } + x->x_over[i] = 0; + } + post("timebang: read in %d times of day:", x->x_notimes); + for(i = 0; i < x->x_notimes; i++) + { + post(" %02d:%02d:%02d", x->x_hour[i], x->x_min[i], x->x_sec[i]); + } + } + else post("timebang: wrong number of parameter"); +} + +static void timebang_bang(t_timebang *x) +{ + time_t now = time(NULL); + struct tm *newtime = localtime(&now); /* convert to local time. */ + post("timebang: local time is %02d:%02d:%02d", newtime->tm_hour, newtime->tm_min, newtime->tm_sec); +} + +static t_class *timebang_class; + +static void *timebang_new(t_symbol *s, int ac, t_atom *av) +{ + int i; + t_timebang *x = (t_timebang *)pd_new(timebang_class); + + x->x_clock = clock_new(x, (t_method)timebang_tick); + + if(ac > MAX_TIMES * 3) + { + post("timebang: too many creation arguments"); + ac = MAX_TIMES * 3; + } + + x->x_notimes = 0; + for(i = 0; i < ac; i += 3) + { + if (av[i].a_type == A_FLOAT) x->x_hour[x->x_notimes] = av[i].a_w.w_float; + else { post ("timebang: first argument must be (int) hours"); return 0; } + if (av[i+1].a_type == A_FLOAT) x->x_min[x->x_notimes] = av[i+1].a_w.w_float; + else { post ("timebang: second argument must be (int) minutes"); return 0; } + if (av[i+2].a_type == A_FLOAT) x->x_sec[x->x_notimes] = av[i+2].a_w.w_float; + else { post ("timebang: third argument must be (int) seconds"); return 0; } + x->x_over[x->x_notimes] = 0; + x->x_notimes++; + } + post("timebang: read in %d times of day:", x->x_notimes); + for(i = 0; i < x->x_notimes; i++) + { + x->x_outlet[i] = outlet_new(&x->x_ob, gensym("bang")); /* create specific bang outlet for time */ + post(" %02d:%02d:%02d", x->x_hour[i], x->x_min[i], x->x_sec[i]); + } + + clock_set(x->x_clock, 0); + + return (void *)x; +} + +static void timebang_free(t_timebang *x) +{ + clock_free(x->x_clock); +} + +#ifndef MAXLIB +void timebang_setup(void) +{ + timebang_class = class_new(gensym("timebang"), (t_newmethod)timebang_new, + (t_method)timebang_free, sizeof(t_timebang), 0, A_GIMME, 0); +#else +void maxlib_timebang_setup(void) +{ + timebang_class = class_new(gensym("maxlib_timebang"), (t_newmethod)timebang_new, + (t_method)timebang_free, sizeof(t_timebang), 0, A_GIMME, 0); + class_addcreator((t_newmethod)timebang_new, gensym("timebang"), A_GIMME, 0); +#endif + class_addmethod(timebang_class, (t_method)timebang_set, gensym("set"), A_GIMME, 0); + class_addbang(timebang_class, (t_method)timebang_bang); +#ifndef MAXLIB + + logpost(NULL, 4, version); +#else + class_sethelpsymbol(timebang_class, gensym("maxlib/timebang-help.pd")); +#endif +} + diff --git a/triang.c b/triang.c index 42e0766..77ec5e9 100644 --- a/triang.c +++ b/triang.c @@ -1,80 +1,80 @@ -/* ---------------------------- rand_triang ----------------------------------- */ -/* */ -/* rand_triang generates a triangularly distributed random variable. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Based on code found in Dodge/Jerse "Computer Music" */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include -#include -#include - -#define fran() (t_float)rand()/(t_float)RAND_MAX - -static char *version = "triang v0.1, generates triangularly distributed random variable\n" - " written by Olaf Matthes "; - -/* -------------------------- rand_triang ------------------------------ */ - -static t_class *rand_triang_class; - -typedef struct _rand_triang -{ - t_object x_obj; -} t_rand_triang; - -static void *rand_triang_new(t_floatarg f) -{ - t_rand_triang *x = (t_rand_triang *)pd_new(rand_triang_class); - srand( (unsigned)time( NULL ) ); - outlet_new(&x->x_obj, &s_float); - return (x); -} - -static void rand_triang_bang(t_rand_triang *x) -{ - t_float u1, u2; - u1 = fran(); - u2 = fran(); - outlet_float(x->x_obj.ob_outlet, 0.5*(u1+u2)); -} - -#ifndef MAXLIB -void triang_setup(void) -{ - rand_triang_class = class_new(gensym("triang"), (t_newmethod)rand_triang_new, 0, - sizeof(t_rand_triang), 0, A_DEFFLOAT, 0); -#else -void maxlib_triang_setup(void) -{ - rand_triang_class = class_new(gensym("maxlib_triang"), (t_newmethod)rand_triang_new, 0, - sizeof(t_rand_triang), 0, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)rand_triang_new, gensym("triang"), A_DEFFLOAT, 0); -#endif - class_addbang(rand_triang_class, rand_triang_bang); -#ifndef MAXLIB - class_sethelpsymbol(rand_triang_class, gensym("triang-help.pd")); - post(version); -#else - class_sethelpsymbol(rand_triang_class, gensym("maxlib/triang-help.pd")); -#endif -} +/* ---------------------------- rand_triang ----------------------------------- */ +/* */ +/* rand_triang generates a triangularly distributed random variable. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Based on code found in Dodge/Jerse "Computer Music" */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include +#include +#include + +#define fran() (t_float)rand()/(t_float)RAND_MAX + +static char *version = "triang v0.1, generates triangularly distributed random variable\n" + " written by Olaf Matthes "; + +/* -------------------------- rand_triang ------------------------------ */ + +static t_class *rand_triang_class; + +typedef struct _rand_triang +{ + t_object x_obj; +} t_rand_triang; + +static void *rand_triang_new(t_floatarg f) +{ + t_rand_triang *x = (t_rand_triang *)pd_new(rand_triang_class); + srand( (unsigned)time( NULL ) ); + outlet_new(&x->x_obj, &s_float); + return (x); +} + +static void rand_triang_bang(t_rand_triang *x) +{ + t_float u1, u2; + u1 = fran(); + u2 = fran(); + outlet_float(x->x_obj.ob_outlet, 0.5*(u1+u2)); +} + +#ifndef MAXLIB +void triang_setup(void) +{ + rand_triang_class = class_new(gensym("triang"), (t_newmethod)rand_triang_new, 0, + sizeof(t_rand_triang), 0, A_DEFFLOAT, 0); +#else +void maxlib_triang_setup(void) +{ + rand_triang_class = class_new(gensym("maxlib_triang"), (t_newmethod)rand_triang_new, 0, + sizeof(t_rand_triang), 0, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)rand_triang_new, gensym("triang"), A_DEFFLOAT, 0); +#endif + class_addbang(rand_triang_class, rand_triang_bang); +#ifndef MAXLIB + class_sethelpsymbol(rand_triang_class, gensym("triang-help.pd")); + logpost(NULL, 4, version); +#else + class_sethelpsymbol(rand_triang_class, gensym("maxlib/triang-help.pd")); +#endif +} diff --git a/unroute.c b/unroute.c index 96331a4..bc31c39 100644 --- a/unroute.c +++ b/unroute.c @@ -1,175 +1,175 @@ -/* -------------------------- unroute ------------------------------------- */ -/* */ -/* Opposit to croute. */ -/* Written by Olaf Matthes */ -/* Get source at http://www.akustische-kunst.org/puredata/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" - -#define MAX_INLET 256 - -static char *version = "unroute v0.1, written by Olaf Matthes "; - -typedef struct unroute -{ - t_object x_obj; - t_outlet *x_outlet; - t_int x_ninstance; - t_atom x_id; -} t_unroute; - -typedef struct proxy -{ - t_object obj; - t_int index; /* number of proxy inlet(s) */ - t_atom id; - t_unroute *x; /* we'll put the other struct in here */ -} t_proxy; - -static void unroute_any(t_unroute *x, t_symbol *s, int argc, t_atom *argv) -{ - int i; - t_atom at[MAXPDSTRING]; - - for(i = 0; i < argc; i++) - { - at[i + 2] = argv[i]; - } - argc += 2; - SETSYMBOL(at+1, s); - - at[0] = x->x_id; /* prepend id of that inlet */ - - outlet_list(x->x_outlet, NULL, argc, at); -} - -static void unroute_list(t_unroute *x, t_symbol *s, int argc, t_atom *argv) -{ - int i; - t_atom at[MAXPDSTRING]; - - for(i = 0; i < argc; i++) - { - at[i + 1] = argv[i]; - } - argc++; - - at[0] = x->x_id; /* prepend id of that inlet */ - - outlet_list(x->x_outlet, NULL, argc, at); -} - -static void unroute_float(t_unroute *x, t_floatarg f) -{ - t_atom list[2]; - - list[0] = x->x_id; /* prepend id of that inlet */ - SETFLOAT(list+1, f); - outlet_list(x->x_outlet, NULL, 2, list); -} - -static void unroute_input(t_proxy *p, t_symbol *s, int argc, t_atom *argv) -{ - t_unroute *x = (t_unroute *)(p->x); - int i; - t_atom at[MAXPDSTRING]; - - if(s == gensym("list")) - { - for(i = 0; i < argc; i++) - { - at[i + 1] = argv[i]; - } - argc++; - } - else - { - for(i = 0; i < argc; i++) - { - at[i + 2] = argv[i]; - } - argc += 2; - SETSYMBOL(at+1, s); - } - - at[0] = p->id; /* prepend id for that inlet */ - - outlet_list(x->x_outlet, NULL, argc, at); -} - - -static t_class *unroute_class; -static t_class *proxy_class; - -static void *unroute_new(t_symbol *s, int argc, t_atom *argv) -{ - int i; - - t_unroute *x = (t_unroute *)pd_new(unroute_class); - t_proxy *inlet[MAX_INLET]; - - x->x_ninstance = argc; - x->x_id = argv[0]; - - for(i = 0; i < x->x_ninstance - 1; i++) - { - inlet[i] = (t_proxy *)pd_new(proxy_class); - inlet[i]->x = x; /* make x visible to the proxy inlets */ - inlet[i]->index = i; /* remember our number */ - inlet[i]->id = argv[i+1]; - /* the inlet we're going to create belongs to the object - 't_unroute' but the destination is the instance 'i' - of the proxy class 't_proxy' */ - inlet_new(&x->x_obj, &inlet[i]->obj.ob_pd, 0,0); - } - x->x_outlet = outlet_new(&x->x_obj, gensym("float")); - - return (void *)x; -} - -#ifndef MAXLIB -void unroute_setup(void) -{ - unroute_class = class_new(gensym("unroute"), (t_newmethod)unroute_new, - 0, sizeof(t_unroute), 0, A_GIMME, 0); -#else -void maxlib_unroute_setup(void) -{ - unroute_class = class_new(gensym("maxlib_unroute"), (t_newmethod)unroute_new, - 0, sizeof(t_unroute), 0, A_GIMME, 0); -#endif - /* a class for the proxy inlet: */ - proxy_class = class_new(gensym("maxlib_unroute_proxy"), NULL, NULL, sizeof(t_proxy), - CLASS_PD|CLASS_NOINLET, A_NULL); - - class_addanything(proxy_class, unroute_input); - - class_addfloat(unroute_class, unroute_float); - class_addlist(unroute_class, unroute_list); - class_addanything(unroute_class, unroute_any); -#ifndef MAXLIB - - post(version); -#else - class_addcreator((t_newmethod)unroute_new, gensym("unroute"), A_GIMME, 0); - class_sethelpsymbol(unroute_class, gensym("maxlib/unroute-help.pd")); -#endif -} +/* -------------------------- unroute ------------------------------------- */ +/* */ +/* Opposit to croute. */ +/* Written by Olaf Matthes */ +/* Get source at http://www.akustische-kunst.org/puredata/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" + +#define MAX_INLET 256 + +static char *version = "unroute v0.1, written by Olaf Matthes "; + +typedef struct unroute +{ + t_object x_obj; + t_outlet *x_outlet; + t_int x_ninstance; + t_atom x_id; +} t_unroute; + +typedef struct proxy +{ + t_object obj; + t_int index; /* number of proxy inlet(s) */ + t_atom id; + t_unroute *x; /* we'll put the other struct in here */ +} t_proxy; + +static void unroute_any(t_unroute *x, t_symbol *s, int argc, t_atom *argv) +{ + int i; + t_atom at[MAXPDSTRING]; + + for(i = 0; i < argc; i++) + { + at[i + 2] = argv[i]; + } + argc += 2; + SETSYMBOL(at+1, s); + + at[0] = x->x_id; /* prepend id of that inlet */ + + outlet_list(x->x_outlet, NULL, argc, at); +} + +static void unroute_list(t_unroute *x, t_symbol *s, int argc, t_atom *argv) +{ + int i; + t_atom at[MAXPDSTRING]; + + for(i = 0; i < argc; i++) + { + at[i + 1] = argv[i]; + } + argc++; + + at[0] = x->x_id; /* prepend id of that inlet */ + + outlet_list(x->x_outlet, NULL, argc, at); +} + +static void unroute_float(t_unroute *x, t_floatarg f) +{ + t_atom list[2]; + + list[0] = x->x_id; /* prepend id of that inlet */ + SETFLOAT(list+1, f); + outlet_list(x->x_outlet, NULL, 2, list); +} + +static void unroute_input(t_proxy *p, t_symbol *s, int argc, t_atom *argv) +{ + t_unroute *x = (t_unroute *)(p->x); + int i; + t_atom at[MAXPDSTRING]; + + if(s == gensym("list")) + { + for(i = 0; i < argc; i++) + { + at[i + 1] = argv[i]; + } + argc++; + } + else + { + for(i = 0; i < argc; i++) + { + at[i + 2] = argv[i]; + } + argc += 2; + SETSYMBOL(at+1, s); + } + + at[0] = p->id; /* prepend id for that inlet */ + + outlet_list(x->x_outlet, NULL, argc, at); +} + + +static t_class *unroute_class; +static t_class *proxy_class; + +static void *unroute_new(t_symbol *s, int argc, t_atom *argv) +{ + int i; + + t_unroute *x = (t_unroute *)pd_new(unroute_class); + t_proxy *inlet[MAX_INLET]; + + x->x_ninstance = argc; + x->x_id = argv[0]; + + for(i = 0; i < x->x_ninstance - 1; i++) + { + inlet[i] = (t_proxy *)pd_new(proxy_class); + inlet[i]->x = x; /* make x visible to the proxy inlets */ + inlet[i]->index = i; /* remember our number */ + inlet[i]->id = argv[i+1]; + /* the inlet we're going to create belongs to the object + 't_unroute' but the destination is the instance 'i' + of the proxy class 't_proxy' */ + inlet_new(&x->x_obj, &inlet[i]->obj.ob_pd, 0,0); + } + x->x_outlet = outlet_new(&x->x_obj, gensym("float")); + + return (void *)x; +} + +#ifndef MAXLIB +void unroute_setup(void) +{ + unroute_class = class_new(gensym("unroute"), (t_newmethod)unroute_new, + 0, sizeof(t_unroute), 0, A_GIMME, 0); +#else +void maxlib_unroute_setup(void) +{ + unroute_class = class_new(gensym("maxlib_unroute"), (t_newmethod)unroute_new, + 0, sizeof(t_unroute), 0, A_GIMME, 0); +#endif + /* a class for the proxy inlet: */ + proxy_class = class_new(gensym("maxlib_unroute_proxy"), NULL, NULL, sizeof(t_proxy), + CLASS_PD|CLASS_NOINLET, A_NULL); + + class_addanything(proxy_class, unroute_input); + + class_addfloat(unroute_class, unroute_float); + class_addlist(unroute_class, unroute_list); + class_addanything(unroute_class, unroute_any); +#ifndef MAXLIB + + logpost(NULL, 4, version); +#else + class_addcreator((t_newmethod)unroute_new, gensym("unroute"), A_GIMME, 0); + class_sethelpsymbol(unroute_class, gensym("maxlib/unroute-help.pd")); +#endif +} diff --git a/urn.c b/urn.c index 5522244..10a7651 100644 --- a/urn.c +++ b/urn.c @@ -1,152 +1,152 @@ -/* ------------------------------- urn -------------------------------------- */ -/* */ -/* urn - urn selection model (random numbers without repetition). */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Based on code found in Dodge/Jerse "Computer Music" */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include -#include -#include - -static char *version = "urn v0.1, urn selection model\n" - " written by Olaf Matthes "; - -/* -------------------------- urn ------------------------------ */ - -static t_class *urn_class; - -typedef struct _urn -{ - t_object x_obj; - t_outlet *x_numberout; - t_outlet *x_notify; - - t_float x_f; /* number of numbers in urn */ - t_int x_numbers; /* numbers left in urn */ - t_int *x_selected; - unsigned int x_state; -} t_urn; - -static int makeseed(void) -{ - static unsigned int random_nextseed = 1489853723; - random_nextseed = random_nextseed * 435898247 + 938284287; - return (random_nextseed & 0x7fffffff); -} - -static void *urn_new(t_floatarg f) -{ - t_urn *x = (t_urn *)pd_new(urn_class); - srand( (unsigned)time( NULL ) ); - x->x_numbers = x->x_f = f; - if(x->x_f < 0)x->x_f = 0; - x->x_selected = getbytes(((t_int)x->x_f+1)*sizeof(t_int)); - - x->x_state = makeseed(); - - inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("f")); - - x->x_numberout = outlet_new(&x->x_obj, &s_float); - x->x_notify = outlet_new(&x->x_obj, &s_bang); - return (x); -} - - /* set new size of urn */ -static void urn_f(t_urn *x, t_floatarg f) -{ - int i; - if(f < 0) - f = 0; - freebytes(x->x_selected, ((t_int)x->x_f+1)*sizeof(t_int)); - x->x_numbers = x->x_f = f; - x->x_selected = getbytes(((t_int)x->x_f+1)*sizeof(t_int)); - for(i = 0; i <= x->x_f; i++) - x->x_selected[i] = 0; -} - - /* clear (refill) urn */ -static void urn_clear(t_urn *x) -{ - int i; - x->x_numbers = x->x_f; - for(i = 0; i <= x->x_f; i++) - x->x_selected[i] = 0; -} - -static void urn_seed(t_urn *x, float f, float glob) -{ - x->x_state = f; -} - - /* choose from urn */ -static void urn_bang(t_urn *x) -{ - int n = x->x_f, nval; - int range = (n < 1 ? 1 : n); - unsigned int randval = x->x_state; - if(x->x_numbers == 0) - goto notify; - do - { - x->x_state = randval = randval * 472940017 + 832416023; - nval = ((double)range) * ((double)randval) - * (1./4294967296.); - if (nval >= range) nval = range-1; - } - while(x->x_selected[nval]); - - x->x_selected[nval] = 1; - - outlet_float(x->x_numberout, nval); - - if(--x->x_numbers == 0) /* urn is now empty */ - goto notify; - return; - -notify: - outlet_bang(x->x_notify); -} - -#ifndef MAXLIB -void urn_setup(void) -{ - urn_class = class_new(gensym("urn"), (t_newmethod)urn_new, 0, - sizeof(t_urn), 0, A_DEFFLOAT, 0); -#else -void maxlib_urn_setup(void) -{ - urn_class = class_new(gensym("maxlib_urn"), (t_newmethod)urn_new, 0, - sizeof(t_urn), 0, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)urn_new, gensym("urn"), A_DEFFLOAT, 0); -#endif - class_addbang(urn_class, urn_bang); - class_addmethod(urn_class, (t_method)urn_f, gensym("f"), A_FLOAT, 0); - class_addmethod(urn_class, (t_method)urn_clear, gensym("clear"), 0); - class_addmethod(urn_class, (t_method)urn_seed, gensym("seed"), A_FLOAT, 0); -#ifndef MAXLIB - - post(version); -#else - class_sethelpsymbol(urn_class, gensym("maxlib/urn-help.pd")); -#endif -} +/* ------------------------------- urn -------------------------------------- */ +/* */ +/* urn - urn selection model (random numbers without repetition). */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Based on code found in Dodge/Jerse "Computer Music" */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include +#include +#include + +static char *version = "urn v0.1, urn selection model\n" + " written by Olaf Matthes "; + +/* -------------------------- urn ------------------------------ */ + +static t_class *urn_class; + +typedef struct _urn +{ + t_object x_obj; + t_outlet *x_numberout; + t_outlet *x_notify; + + t_float x_f; /* number of numbers in urn */ + t_int x_numbers; /* numbers left in urn */ + t_int *x_selected; + unsigned int x_state; +} t_urn; + +static int makeseed(void) +{ + static unsigned int random_nextseed = 1489853723; + random_nextseed = random_nextseed * 435898247 + 938284287; + return (random_nextseed & 0x7fffffff); +} + +static void *urn_new(t_floatarg f) +{ + t_urn *x = (t_urn *)pd_new(urn_class); + srand( (unsigned)time( NULL ) ); + x->x_numbers = x->x_f = f; + if(x->x_f < 0)x->x_f = 0; + x->x_selected = getbytes(((t_int)x->x_f+1)*sizeof(t_int)); + + x->x_state = makeseed(); + + inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("f")); + + x->x_numberout = outlet_new(&x->x_obj, &s_float); + x->x_notify = outlet_new(&x->x_obj, &s_bang); + return (x); +} + + /* set new size of urn */ +static void urn_f(t_urn *x, t_floatarg f) +{ + int i; + if(f < 0) + f = 0; + freebytes(x->x_selected, ((t_int)x->x_f+1)*sizeof(t_int)); + x->x_numbers = x->x_f = f; + x->x_selected = getbytes(((t_int)x->x_f+1)*sizeof(t_int)); + for(i = 0; i <= x->x_f; i++) + x->x_selected[i] = 0; +} + + /* clear (refill) urn */ +static void urn_clear(t_urn *x) +{ + int i; + x->x_numbers = x->x_f; + for(i = 0; i <= x->x_f; i++) + x->x_selected[i] = 0; +} + +static void urn_seed(t_urn *x, float f, float glob) +{ + x->x_state = f; +} + + /* choose from urn */ +static void urn_bang(t_urn *x) +{ + int n = x->x_f, nval; + int range = (n < 1 ? 1 : n); + unsigned int randval = x->x_state; + if(x->x_numbers == 0) + goto notify; + do + { + x->x_state = randval = randval * 472940017 + 832416023; + nval = ((double)range) * ((double)randval) + * (1./4294967296.); + if (nval >= range) nval = range-1; + } + while(x->x_selected[nval]); + + x->x_selected[nval] = 1; + + outlet_float(x->x_numberout, nval); + + if(--x->x_numbers == 0) /* urn is now empty */ + goto notify; + return; + +notify: + outlet_bang(x->x_notify); +} + +#ifndef MAXLIB +void urn_setup(void) +{ + urn_class = class_new(gensym("urn"), (t_newmethod)urn_new, 0, + sizeof(t_urn), 0, A_DEFFLOAT, 0); +#else +void maxlib_urn_setup(void) +{ + urn_class = class_new(gensym("maxlib_urn"), (t_newmethod)urn_new, 0, + sizeof(t_urn), 0, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)urn_new, gensym("urn"), A_DEFFLOAT, 0); +#endif + class_addbang(urn_class, urn_bang); + class_addmethod(urn_class, (t_method)urn_f, gensym("f"), A_FLOAT, 0); + class_addmethod(urn_class, (t_method)urn_clear, gensym("clear"), 0); + class_addmethod(urn_class, (t_method)urn_seed, gensym("seed"), A_FLOAT, 0); +#ifndef MAXLIB + + logpost(NULL, 4, version); +#else + class_sethelpsymbol(urn_class, gensym("maxlib/urn-help.pd")); +#endif +} diff --git a/velocity.c b/velocity.c index c04fab9..50163fa 100644 --- a/velocity.c +++ b/velocity.c @@ -1,112 +1,112 @@ -/* ------------------------- velocity ----------------------------------------- */ -/* */ -/* Get velocity of input in digits per second. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Originally written for Max by Trond Lossius. */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* You should have received a copy of the GNU Lesser General Public */ -/* License along with this library; if not, write to the */ -/* Free Software Foundation, Inc., 59 Temple Place - Suite 330, */ -/* Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -// velocity.c: (1000*(x[n]-x[n-1]))/Æt -// (C) Trond Lossius/BEK 2000 -// Last revision: 4/7 2000 -// -// Input: -// float -// int (converted to float) -// set (set new value but no output) -// Argument (optional, defaults to 0): -// Initial stored value -// Output: -// float: Velocity as change per second (not ms) - -#include "m_pd.h" - -static char *version = "velocity v0.1, written by Olaf Matthes "; - -typedef struct velocity -{ - t_object x_ob; - t_outlet *x_out; - t_float x_xn1; /* input (floats) */ - t_float x_xn; - double x_lasttime; -} t_velocity; - -static void velocity_bang(t_velocity *x) -{ - double thistime; - t_float vel; - - thistime = clock_getlogicaltime(); - vel = (1000 * (x->x_xn - x->x_xn1) ) / (clock_gettimesince(x->x_lasttime)); - x->x_lasttime = thistime; - outlet_float(x->x_out, vel); -} - -static void velocity_float(t_velocity *x, t_floatarg f) -{ - x->x_xn1 = x->x_xn; - x->x_xn = f; - velocity_bang(x); -} - -static void velocity_free(t_velocity *x) -{ - // nothing to do -} - -static t_class *velocity_class; - -static void *velocity_new(t_floatarg f) -{ - t_velocity *x = (t_velocity *)pd_new(velocity_class); - x->x_out = outlet_new(&x->x_ob, gensym("float")); - x->x_lasttime = clock_getlogicaltime(); - - return (void *)x; -} - -#ifndef MAXLIB -void velocity_setup(void) -{ - velocity_class = class_new(gensym("velocity"), (t_newmethod)velocity_new, - (t_method)velocity_free, sizeof(t_velocity), 0, A_DEFFLOAT, 0); -#else -void maxlib_velocity_setup(void) -{ - velocity_class = class_new(gensym("maxlib_velocity"), (t_newmethod)velocity_new, - (t_method)velocity_free, sizeof(t_velocity), 0, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)velocity_new, gensym("velocity"), A_DEFFLOAT, 0); -#endif - class_addfloat(velocity_class, velocity_float); - class_addbang(velocity_class, velocity_bang); -#ifndef MAXLIB - - post(version); -#else - class_sethelpsymbol(velocity_class, gensym("maxlib/velocity-help.pd")); -#endif -} - +/* ------------------------- velocity ----------------------------------------- */ +/* */ +/* Get velocity of input in digits per second. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Originally written for Max by Trond Lossius. */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* You should have received a copy of the GNU Lesser General Public */ +/* License along with this library; if not, write to the */ +/* Free Software Foundation, Inc., 59 Temple Place - Suite 330, */ +/* Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +// velocity.c: (1000*(x[n]-x[n-1]))/Æt +// (C) Trond Lossius/BEK 2000 +// Last revision: 4/7 2000 +// +// Input: +// float +// int (converted to float) +// set (set new value but no output) +// Argument (optional, defaults to 0): +// Initial stored value +// Output: +// float: Velocity as change per second (not ms) + +#include "m_pd.h" + +static char *version = "velocity v0.1, written by Olaf Matthes "; + +typedef struct velocity +{ + t_object x_ob; + t_outlet *x_out; + t_float x_xn1; /* input (floats) */ + t_float x_xn; + double x_lasttime; +} t_velocity; + +static void velocity_bang(t_velocity *x) +{ + double thistime; + t_float vel; + + thistime = clock_getlogicaltime(); + vel = (1000 * (x->x_xn - x->x_xn1) ) / (clock_gettimesince(x->x_lasttime)); + x->x_lasttime = thistime; + outlet_float(x->x_out, vel); +} + +static void velocity_float(t_velocity *x, t_floatarg f) +{ + x->x_xn1 = x->x_xn; + x->x_xn = f; + velocity_bang(x); +} + +static void velocity_free(t_velocity *x) +{ + // nothing to do +} + +static t_class *velocity_class; + +static void *velocity_new(t_floatarg f) +{ + t_velocity *x = (t_velocity *)pd_new(velocity_class); + x->x_out = outlet_new(&x->x_ob, gensym("float")); + x->x_lasttime = clock_getlogicaltime(); + + return (void *)x; +} + +#ifndef MAXLIB +void velocity_setup(void) +{ + velocity_class = class_new(gensym("velocity"), (t_newmethod)velocity_new, + (t_method)velocity_free, sizeof(t_velocity), 0, A_DEFFLOAT, 0); +#else +void maxlib_velocity_setup(void) +{ + velocity_class = class_new(gensym("maxlib_velocity"), (t_newmethod)velocity_new, + (t_method)velocity_free, sizeof(t_velocity), 0, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)velocity_new, gensym("velocity"), A_DEFFLOAT, 0); +#endif + class_addfloat(velocity_class, velocity_float); + class_addbang(velocity_class, velocity_bang); +#ifndef MAXLIB + + logpost(NULL, 4, version); +#else + class_sethelpsymbol(velocity_class, gensym("maxlib/velocity-help.pd")); +#endif +} + diff --git a/weibull.c b/weibull.c index a6e8564..b3ff821 100644 --- a/weibull.c +++ b/weibull.c @@ -1,95 +1,95 @@ -/* ---------------------------- rand_weibull ---------------------------------- */ -/* */ -/* rand_weibull generates a weibull distributed random variable. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Based on code found in Dodge/Jerse "Computer Music" */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ +/* ---------------------------- rand_weibull ---------------------------------- */ +/* */ +/* rand_weibull generates a weibull distributed random variable. */ +/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ +/* Based on code found in Dodge/Jerse "Computer Music" */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ #include "m_pd.h" -#include -#include -#include - -#define fran() (t_float)rand()/(t_float)RAND_MAX -#ifndef M_PI -#define M_PI 3.1415927 -#endif +#include +#include +#include -static char *version = "weibull v0.1, generates a weibull distributed random variable\n" - " written by Olaf Matthes "; +#define fran() (t_float)rand()/(t_float)RAND_MAX +#ifndef M_PI +#define M_PI 3.1415927 +#endif -/* -------------------------- rand_weibull ------------------------------ */ - -static t_class *rand_weibull_class; - -typedef struct _rand_weibull -{ - t_object x_obj; - t_float x_s; - t_float x_t; -} t_rand_weibull; - -static void *rand_weibull_new(t_floatarg s, t_floatarg t) -{ - t_rand_weibull *x = (t_rand_weibull *)pd_new(rand_weibull_class); - srand( (unsigned)time( NULL ) ); - floatinlet_new(&x->x_obj, &x->x_s); - floatinlet_new(&x->x_obj, &x->x_t); - outlet_new(&x->x_obj, &s_float); - x->x_s = s; - x->x_t = t; - return (x); -} - -static void rand_weibull_bang(t_rand_weibull *x) -{ - t_float u, a, t, tinv; - t = (x->x_t <= 0 ? 0.0001 : x->x_t); - tinv = 1/t; - do - { - u = fran(); - } - while(u == 0 || u == 1); - a = 1/(1 - u); - outlet_float(x->x_obj.ob_outlet, x->x_s*pow(log(a), tinv)); -} - -#ifndef MAXLIB -void weibull_setup(void) -{ - rand_weibull_class = class_new(gensym("weibull"), (t_newmethod)rand_weibull_new, 0, - sizeof(t_rand_weibull), 0, A_DEFFLOAT, A_DEFFLOAT, 0); -#else -void maxlib_weibull_setup(void) -{ - rand_weibull_class = class_new(gensym("maxlib_weibull"), (t_newmethod)rand_weibull_new, 0, - sizeof(t_rand_weibull), 0, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)rand_weibull_new, gensym("weibull"), A_DEFFLOAT, A_DEFFLOAT, 0); -#endif - class_addbang(rand_weibull_class, rand_weibull_bang); -#ifndef MAXLIB - class_sethelpsymbol(rand_weibull_class, gensym("weibull-help.pd")); - post(version); -#else - class_sethelpsymbol(rand_weibull_class, gensym("maxlib/weibull-help.pd")); -#endif -} +static char *version = "weibull v0.1, generates a weibull distributed random variable\n" + " written by Olaf Matthes "; + +/* -------------------------- rand_weibull ------------------------------ */ + +static t_class *rand_weibull_class; + +typedef struct _rand_weibull +{ + t_object x_obj; + t_float x_s; + t_float x_t; +} t_rand_weibull; + +static void *rand_weibull_new(t_floatarg s, t_floatarg t) +{ + t_rand_weibull *x = (t_rand_weibull *)pd_new(rand_weibull_class); + srand( (unsigned)time( NULL ) ); + floatinlet_new(&x->x_obj, &x->x_s); + floatinlet_new(&x->x_obj, &x->x_t); + outlet_new(&x->x_obj, &s_float); + x->x_s = s; + x->x_t = t; + return (x); +} + +static void rand_weibull_bang(t_rand_weibull *x) +{ + t_float u, a, t, tinv; + t = (x->x_t <= 0 ? 0.0001 : x->x_t); + tinv = 1/t; + do + { + u = fran(); + } + while(u == 0 || u == 1); + a = 1/(1 - u); + outlet_float(x->x_obj.ob_outlet, x->x_s*pow(log(a), tinv)); +} + +#ifndef MAXLIB +void weibull_setup(void) +{ + rand_weibull_class = class_new(gensym("weibull"), (t_newmethod)rand_weibull_new, 0, + sizeof(t_rand_weibull), 0, A_DEFFLOAT, A_DEFFLOAT, 0); +#else +void maxlib_weibull_setup(void) +{ + rand_weibull_class = class_new(gensym("maxlib_weibull"), (t_newmethod)rand_weibull_new, 0, + sizeof(t_rand_weibull), 0, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)rand_weibull_new, gensym("weibull"), A_DEFFLOAT, A_DEFFLOAT, 0); +#endif + class_addbang(rand_weibull_class, rand_weibull_bang); +#ifndef MAXLIB + class_sethelpsymbol(rand_weibull_class, gensym("weibull-help.pd")); + logpost(NULL, 4, version); +#else + class_sethelpsymbol(rand_weibull_class, gensym("maxlib/weibull-help.pd")); +#endif +} diff --git a/wrap.c b/wrap.c index 2272045..b7a63c4 100644 --- a/wrap.c +++ b/wrap.c @@ -1,142 +1,142 @@ -/* ------------------------- wrap ------------------------------------------ */ -/* */ -/* wraps input to lie within an output range. */ -/* Written by Olaf Matthes */ -/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ -/* */ -/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" -#include -#include - -static char *version = "wrap v0.1, written by Olaf Matthes "; - -typedef struct wrap -{ - t_object x_ob; - t_float x_min; /* low border of input range */ - t_float x_max; /* high border of input range */ - t_outlet *x_outlet1; /* path-through outlet */ - t_outlet *x_outlet2; /* wrap outlet */ -} t_wrap; - -static void wrap_float(t_wrap *x, t_floatarg f) -{ - t_float min = x->x_min; - t_float max = x->x_max; - t_float range = max - min; - t_int i; - - if(range == 0.0f) - { - f = min; - outlet_float(x->x_outlet2, 0); - } - else if(f < min) - { - t_float diff = min - f; - t_float n = ceil(diff / range); - - f += n * range; - - outlet_float(x->x_outlet2, -(t_int)n); - } - else if (f >= max) - { - t_float diff = f - max; - t_float n = floor(diff / range) + 1.0f; - - f -= n * range; - - outlet_float(x->x_outlet2, (t_int)n); - } - else - outlet_float(x->x_outlet2, 0.0f); - - outlet_float(x->x_outlet1, f); -} - -static void wrap_a(t_wrap *x, t_floatarg a) -{ - t_float max = x->x_max; - - if(a <= max) - x->x_min = a; - else - { - x->x_min = max; - x->x_max = a; - } -} - -static void wrap_b(t_wrap *x, t_floatarg b) -{ - t_float min = x->x_min; - - if(b >= min) - x->x_max = b; - else - { - x->x_max = min; - x->x_min = b; - } -} - -static t_class *wrap_class; - -static void *wrap_new(t_floatarg fmin, t_floatarg fmax) -{ - t_wrap *x = (t_wrap *)pd_new(wrap_class); - - inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("a")); - inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("b")); - - x->x_outlet1 = outlet_new(&x->x_ob, gensym("float")); - x->x_outlet2 = outlet_new(&x->x_ob, gensym("float")); - - x->x_min = fmin; - wrap_b(x, fmax); - - return (void *)x; -} - -#ifndef MAXLIB -void wrap_setup(void) -{ - wrap_class = class_new(gensym("wrap"), (t_newmethod)wrap_new, - 0, sizeof(t_wrap), 0, A_DEFFLOAT, A_DEFFLOAT, 0); -#else -void maxlib_wrap_setup(void) -{ - wrap_class = class_new(gensym("maxlib_wrap"), (t_newmethod)wrap_new, - 0, sizeof(t_wrap), 0, A_DEFFLOAT, A_DEFFLOAT, 0); - class_addcreator((t_newmethod)wrap_new, gensym("wrap"), A_DEFFLOAT, A_DEFFLOAT, 0); -#endif - class_addfloat(wrap_class, wrap_float); - class_addmethod(wrap_class, (t_method)wrap_a, gensym("a"), A_FLOAT, 0); - class_addmethod(wrap_class, (t_method)wrap_b, gensym("b"), A_FLOAT, 0); -#ifndef MAXLIB - - post(version); -#else - class_sethelpsymbol(wrap_class, gensym("maxlib/wrap-help.pd")); -#endif -} - +/* ------------------------- wrap ------------------------------------------ */ +/* */ +/* wraps input to lie within an output range. */ +/* Written by Olaf Matthes */ +/* Get source at http://www.akustische-kunst.org/puredata/maxlib/ */ +/* */ +/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* */ +/* Based on PureData by Miller Puckette and others. */ +/* */ +/* ---------------------------------------------------------------------------- */ + +#include "m_pd.h" +#include +#include + +static char *version = "wrap v0.1, written by Olaf Matthes "; + +typedef struct wrap +{ + t_object x_ob; + t_float x_min; /* low border of input range */ + t_float x_max; /* high border of input range */ + t_outlet *x_outlet1; /* path-through outlet */ + t_outlet *x_outlet2; /* wrap outlet */ +} t_wrap; + +static void wrap_float(t_wrap *x, t_floatarg f) +{ + t_float min = x->x_min; + t_float max = x->x_max; + t_float range = max - min; + t_int i; + + if(range == 0.0f) + { + f = min; + outlet_float(x->x_outlet2, 0); + } + else if(f < min) + { + t_float diff = min - f; + t_float n = ceil(diff / range); + + f += n * range; + + outlet_float(x->x_outlet2, -(t_int)n); + } + else if (f >= max) + { + t_float diff = f - max; + t_float n = floor(diff / range) + 1.0f; + + f -= n * range; + + outlet_float(x->x_outlet2, (t_int)n); + } + else + outlet_float(x->x_outlet2, 0.0f); + + outlet_float(x->x_outlet1, f); +} + +static void wrap_a(t_wrap *x, t_floatarg a) +{ + t_float max = x->x_max; + + if(a <= max) + x->x_min = a; + else + { + x->x_min = max; + x->x_max = a; + } +} + +static void wrap_b(t_wrap *x, t_floatarg b) +{ + t_float min = x->x_min; + + if(b >= min) + x->x_max = b; + else + { + x->x_max = min; + x->x_min = b; + } +} + +static t_class *wrap_class; + +static void *wrap_new(t_floatarg fmin, t_floatarg fmax) +{ + t_wrap *x = (t_wrap *)pd_new(wrap_class); + + inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("a")); + inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("b")); + + x->x_outlet1 = outlet_new(&x->x_ob, gensym("float")); + x->x_outlet2 = outlet_new(&x->x_ob, gensym("float")); + + x->x_min = fmin; + wrap_b(x, fmax); + + return (void *)x; +} + +#ifndef MAXLIB +void wrap_setup(void) +{ + wrap_class = class_new(gensym("wrap"), (t_newmethod)wrap_new, + 0, sizeof(t_wrap), 0, A_DEFFLOAT, A_DEFFLOAT, 0); +#else +void maxlib_wrap_setup(void) +{ + wrap_class = class_new(gensym("maxlib_wrap"), (t_newmethod)wrap_new, + 0, sizeof(t_wrap), 0, A_DEFFLOAT, A_DEFFLOAT, 0); + class_addcreator((t_newmethod)wrap_new, gensym("wrap"), A_DEFFLOAT, A_DEFFLOAT, 0); +#endif + class_addfloat(wrap_class, wrap_float); + class_addmethod(wrap_class, (t_method)wrap_a, gensym("a"), A_FLOAT, 0); + class_addmethod(wrap_class, (t_method)wrap_b, gensym("b"), A_FLOAT, 0); +#ifndef MAXLIB + + logpost(NULL, 4, version); +#else + class_sethelpsymbol(wrap_class, gensym("maxlib/wrap-help.pd")); +#endif +} + -- cgit v1.2.1