aboutsummaryrefslogtreecommitdiff
path: root/pd/src
diff options
context:
space:
mode:
Diffstat (limited to 'pd/src')
-rwxr-xr-xpd/src/configure3021
-rw-r--r--pd/src/configure.in192
-rw-r--r--pd/src/d_arithmetic.c842
-rw-r--r--pd/src/d_array.c1075
-rw-r--r--pd/src/d_ctl.c496
-rw-r--r--pd/src/d_dac.c183
-rw-r--r--pd/src/d_delay.c314
-rw-r--r--pd/src/d_fft.c342
-rw-r--r--pd/src/d_fftroutine.c1001
-rw-r--r--pd/src/d_filter.c534
-rw-r--r--pd/src/d_global.c312
-rw-r--r--pd/src/d_math.c573
-rw-r--r--pd/src/d_mayer_fft.c419
-rw-r--r--pd/src/d_misc.c260
-rw-r--r--pd/src/d_osc.c531
-rw-r--r--pd/src/d_resample.c225
-rw-r--r--pd/src/d_soundfile.c2200
-rw-r--r--pd/src/d_ugen.c1078
-rw-r--r--pd/src/g_all_guis.c937
-rw-r--r--pd/src/g_all_guis.h320
-rw-r--r--pd/src/g_array.c1358
-rw-r--r--pd/src/g_bang.c600
-rw-r--r--pd/src/g_canvas.c1482
-rw-r--r--pd/src/g_canvas.h564
-rw-r--r--pd/src/g_editor.c1658
-rw-r--r--pd/src/g_graph.c1119
-rw-r--r--pd/src/g_guiconnect.c94
-rw-r--r--pd/src/g_hdial.c675
-rw-r--r--pd/src/g_hslider.c708
-rw-r--r--pd/src/g_io.c612
-rw-r--r--pd/src/g_mycanvas.c439
-rw-r--r--pd/src/g_numbox.c979
-rw-r--r--pd/src/g_readwrite.c722
-rw-r--r--pd/src/g_rtext.c478
-rw-r--r--pd/src/g_scalar.c373
-rw-r--r--pd/src/g_template.c1673
-rw-r--r--pd/src/g_text.c1070
-rw-r--r--pd/src/g_toggle.c528
-rw-r--r--pd/src/g_traversal.c1084
-rw-r--r--pd/src/g_vdial.c672
-rw-r--r--pd/src/g_vslider.c688
-rw-r--r--pd/src/g_vumeter.c762
-rw-r--r--pd/src/install-sh251
-rw-r--r--pd/src/m_atom.c129
-rw-r--r--pd/src/m_binbuf.c1138
-rw-r--r--pd/src/m_class.c772
-rw-r--r--pd/src/m_conf.c100
-rw-r--r--pd/src/m_glob.c121
-rw-r--r--pd/src/m_imp.h223
-rw-r--r--pd/src/m_memory.c88
-rw-r--r--pd/src/m_obj.c676
-rw-r--r--pd/src/m_pd.c296
-rw-r--r--pd/src/m_pd.h594
-rw-r--r--pd/src/m_sched.c462
-rw-r--r--pd/src/makefile3
-rw-r--r--pd/src/makefile.clean3
-rw-r--r--pd/src/makefile.dependencies0
-rw-r--r--pd/src/makefile.in233
-rw-r--r--pd/src/makefile.irix65
-rw-r--r--pd/src/makefile.nt95
-rw-r--r--pd/src/notes.txt264
-rw-r--r--pd/src/s_entry.c10
-rw-r--r--pd/src/s_file.c54
-rw-r--r--pd/src/s_freebsd.c3072
-rw-r--r--pd/src/s_inter.c794
-rw-r--r--pd/src/s_linux.c3087
-rw-r--r--pd/src/s_loader.c142
-rw-r--r--pd/src/s_mac.c356
-rw-r--r--pd/src/s_main.c803
-rw-r--r--pd/src/s_nt.c1586
-rw-r--r--pd/src/s_path.c279
-rw-r--r--pd/src/s_portaudio.c197
-rw-r--r--pd/src/s_print.c150
-rw-r--r--pd/src/s_sgi.c433
-rw-r--r--pd/src/s_unix.c445
-rw-r--r--pd/src/s_watchdog.c47
-rw-r--r--pd/src/t_main.c123
-rw-r--r--pd/src/t_tk.h10
-rw-r--r--pd/src/t_tkcmd.c367
-rw-r--r--pd/src/u_main.tk2570
-rw-r--r--pd/src/u_pdreceive.c305
-rw-r--r--pd/src/u_pdsend.c150
-rw-r--r--pd/src/x_acoustics.c193
-rw-r--r--pd/src/x_arithmetic.c898
-rw-r--r--pd/src/x_connective.c1452
-rw-r--r--pd/src/x_gui.c377
-rw-r--r--pd/src/x_interface.c78
-rw-r--r--pd/src/x_midi.c1314
-rw-r--r--pd/src/x_misc.c319
-rw-r--r--pd/src/x_net.c362
-rw-r--r--pd/src/x_qlist.c345
-rw-r--r--pd/src/x_time.c519
-rw-r--r--pd/src/z.pd41
-rw-r--r--pd/src/z2.pd12
-rw-r--r--pd/src/z3.pd3
-rw-r--r--pd/src/z4.pd2
-rw-r--r--pd/src/z5.pd8
-rw-r--r--pd/src/z6.pd4
98 files changed, 59613 insertions, 0 deletions
diff --git a/pd/src/configure b/pd/src/configure
new file mode 100755
index 00000000..88e26a18
--- /dev/null
+++ b/pd/src/configure
@@ -0,0 +1,3021 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+ --enable-alsa compile ALSA support"
+ac_help="$ac_help
+ --enable-old-alsa ALSA 0.5x support"
+ac_help="$ac_help
+ --enable-rme compile RME support"
+ac_help="$ac_help
+ --enable-debug debugging support"
+ac_help="$ac_help
+ --with-x use the X Window System"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.13"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=d_arithmetic.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --enable-alsa or --disable-alsa was given.
+if test "${enable_alsa+set}" = set; then
+ enableval="$enable_alsa"
+ alsa="yes"
+fi
+
+# Check whether --enable-old-alsa or --disable-old-alsa was given.
+if test "${enable_old_alsa+set}" = set; then
+ enableval="$enable_old_alsa"
+ alsa="old"
+fi
+
+# Check whether --enable-rme or --disable-rme was given.
+if test "${enable_rme+set}" = set; then
+ enableval="$enable_rme"
+ rme="yes"
+fi
+
+# Check whether --enable-debug or --disable-debug was given.
+if test "${enable_debug+set}" = set; then
+ enableval="$enable_debug"
+ USE_OPT_CFLAGS="NO"
+else
+ USE_OPT_CFLAGS="YES"
+fi
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:583: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:613: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_prog_rejected=no
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test -z "$CC"; then
+ case "`uname -s`" in
+ *win32* | *WIN32*)
+ # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:664: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="cl"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
+ esac
+ fi
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:696: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 707 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:712: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cc_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cc_cross=no
+ else
+ ac_cv_prog_cc_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+ { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:738: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:743: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:752: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:771: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_g=yes
+else
+ ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:833: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:886: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftestmake <<\EOF
+all:
+ @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ SET_MAKE=
+else
+ echo "$ac_t""no" 1>&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:913: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 928 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:934: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 945 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:951: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -nologo -E"
+ cat > conftest.$ac_ext <<EOF
+#line 962 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:968: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:994: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 999 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this. */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this. */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this. */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in an arm
+ of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:1048: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_c_const=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+ cat >> confdefs.h <<\EOF
+#define const
+EOF
+
+fi
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1069: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1074 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1082: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1099 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1117 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1138 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1149: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking for pid_t""... $ac_c" 1>&6
+echo "configure:1173: checking for pid_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1178 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_pid_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_pid_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_pid_t" 1>&6
+if test $ac_cv_type_pid_t = no; then
+ cat >> confdefs.h <<\EOF
+#define pid_t int
+EOF
+
+fi
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+echo "configure:1206: checking for size_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1211 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_size_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&6
+if test $ac_cv_type_size_t = no; then
+ cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1239: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1244 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1253: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_time=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+ cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1275: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1280 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1288: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1305 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1323 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1344 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1355: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+for ac_hdr in fcntl.h limits.h malloc.h sys/ioctl.h sys/time.h unistd.h bstring.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1382: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1387 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1392: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+if test $ac_cv_prog_gcc = yes; then
+ echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
+echo "configure:1421: checking whether ${CC-cc} needs -traditional" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_pattern="Autoconf.*'x'"
+ cat > conftest.$ac_ext <<EOF
+#line 1427 "configure"
+#include "confdefs.h"
+#include <sgtty.h>
+Autoconf TIOCGETP
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "$ac_pattern" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_prog_gcc_traditional=yes
+else
+ rm -rf conftest*
+ ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+ if test $ac_cv_prog_gcc_traditional = no; then
+ cat > conftest.$ac_ext <<EOF
+#line 1445 "configure"
+#include "confdefs.h"
+#include <termio.h>
+Autoconf TCGETA
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "$ac_pattern" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+ fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
+ if test $ac_cv_prog_gcc_traditional = yes; then
+ CC="$CC -traditional"
+ fi
+fi
+
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:1467: checking return type of signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1472 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:1489: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_type_signal=void
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <<EOF
+#define RETSIGTYPE $ac_cv_type_signal
+EOF
+
+
+echo $ac_n "checking for vprintf""... $ac_c" 1>&6
+echo "configure:1508: checking for vprintf" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1513 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char vprintf(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char vprintf();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_vprintf) || defined (__stub___vprintf)
+choke me
+#else
+vprintf();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1536: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_vprintf=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_vprintf=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_VPRINTF 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test "$ac_cv_func_vprintf" != yes; then
+echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
+echo "configure:1560: checking for _doprnt" >&5
+if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1565 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char _doprnt(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char _doprnt();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub__doprnt) || defined (__stub____doprnt)
+choke me
+#else
+_doprnt();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1588: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func__doprnt=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func__doprnt=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_DOPRNT 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+for ac_func in gettimeofday select socket strerror
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1615: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1620 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1643: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+
+echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6
+echo "configure:1670: checking for dlopen in -ldl" >&5
+ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldl $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1678 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen();
+
+int main() {
+dlopen()
+; return 0; }
+EOF
+if { (eval echo configure:1689: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ PDLIB="$PDLIB -ldl"
+else
+ echo "$ac_t""no" 1>&6
+echo "dynamic link support required" || exit 1
+fi
+
+
+echo $ac_n "checking for sin in -lffm""... $ac_c" 1>&6
+echo "configure:1712: checking for sin in -lffm" >&5
+ac_lib_var=`echo ffm'_'sin | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lffm $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1720 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char sin();
+
+int main() {
+sin()
+; return 0; }
+EOF
+if { (eval echo configure:1731: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ PDLIB="$PDLIB -lffm"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking for sin in -lm""... $ac_c" 1>&6
+echo "configure:1753: checking for sin in -lm" >&5
+ac_lib_var=`echo m'_'sin | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lm $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1761 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char sin();
+
+int main() {
+sin()
+; return 0; }
+EOF
+if { (eval echo configure:1772: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ PDLIB="$PDLIB -lm"
+else
+ echo "$ac_t""no" 1>&6
+echo "math library required" || exit 1
+fi
+
+
+echo $ac_n "checking for pthread_create in -lpthread""... $ac_c" 1>&6
+echo "configure:1795: checking for pthread_create in -lpthread" >&5
+ac_lib_var=`echo pthread'_'pthread_create | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lpthread $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1803 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pthread_create();
+
+int main() {
+pthread_create()
+; return 0; }
+EOF
+if { (eval echo configure:1814: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ PDLIB="$PDLIB -lpthread"
+else
+ echo "$ac_t""no" 1>&6
+echo "pthreads required" || exit 1
+fi
+
+
+if test "$alsa" = yes; then
+ echo $ac_n "checking for snd_pcm_info in -lasound""... $ac_c" 1>&6
+echo "configure:1838: checking for snd_pcm_info in -lasound" >&5
+ac_lib_var=`echo asound'_'snd_pcm_info | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lasound $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1846 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char snd_pcm_info();
+
+int main() {
+snd_pcm_info()
+; return 0; }
+EOF
+if { (eval echo configure:1857: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ PDLIB="$PDLIB -lasound"
+else
+ echo "$ac_t""no" 1>&6
+alsa=""
+fi
+
+elif test "$alsa" = old; then
+ echo $ac_n "checking for snd_pcm_info in -lasound""... $ac_c" 1>&6
+echo "configure:1880: checking for snd_pcm_info in -lasound" >&5
+ac_lib_var=`echo asound'_'snd_pcm_info | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lasound $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1888 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char snd_pcm_info();
+
+int main() {
+snd_pcm_info()
+; return 0; }
+EOF
+if { (eval echo configure:1899: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ PDLIB="$PDLIB -lasound"
+else
+ echo "$ac_t""no" 1>&6
+alsa=""
+fi
+
+fi
+
+# If we find X, set shell vars x_includes and x_libraries to the
+# paths, otherwise set no_x=yes.
+# Uses ac_ vars as temps to allow command line to override cache and checks.
+# --without-x overrides everything else, but does not touch the cache.
+echo $ac_n "checking for X""... $ac_c" 1>&6
+echo "configure:1927: checking for X" >&5
+
+# Check whether --with-x or --without-x was given.
+if test "${with_x+set}" = set; then
+ withval="$with_x"
+ :
+fi
+
+# $have_x is `yes', `no', `disabled', or empty when we do not yet know.
+if test "x$with_x" = xno; then
+ # The user explicitly disabled X.
+ have_x=disabled
+else
+ if test "x$x_includes" != xNONE && test "x$x_libraries" != xNONE; then
+ # Both variables are already set.
+ have_x=yes
+ else
+if eval "test \"`echo '$''{'ac_cv_have_x'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # One or both of the vars are not set, and there is no cached value.
+ac_x_includes=NO ac_x_libraries=NO
+rm -fr conftestdir
+if mkdir conftestdir; then
+ cd conftestdir
+ # Make sure to not put "make" in the Imakefile rules, since we grep it out.
+ cat > Imakefile <<'EOF'
+acfindx:
+ @echo 'ac_im_incroot="${INCROOT}"; ac_im_usrlibdir="${USRLIBDIR}"; ac_im_libdir="${LIBDIR}"'
+EOF
+ if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then
+ # GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+ eval `${MAKE-make} acfindx 2>/dev/null | grep -v make`
+ # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR.
+ for ac_extension in a so sl; do
+ if test ! -f $ac_im_usrlibdir/libX11.$ac_extension &&
+ test -f $ac_im_libdir/libX11.$ac_extension; then
+ ac_im_usrlibdir=$ac_im_libdir; break
+ fi
+ done
+ # Screen out bogus values from the imake configuration. They are
+ # bogus both because they are the default anyway, and because
+ # using them would break gcc on systems where it needs fixed includes.
+ case "$ac_im_incroot" in
+ /usr/include) ;;
+ *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes="$ac_im_incroot" ;;
+ esac
+ case "$ac_im_usrlibdir" in
+ /usr/lib | /lib) ;;
+ *) test -d "$ac_im_usrlibdir" && ac_x_libraries="$ac_im_usrlibdir" ;;
+ esac
+ fi
+ cd ..
+ rm -fr conftestdir
+fi
+
+if test "$ac_x_includes" = NO; then
+ # Guess where to find include files, by looking for this one X11 .h file.
+ test -z "$x_direct_test_include" && x_direct_test_include=X11/Intrinsic.h
+
+ # First, try using that file with no special directory specified.
+cat > conftest.$ac_ext <<EOF
+#line 1989 "configure"
+#include "confdefs.h"
+#include <$x_direct_test_include>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1994: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ # We can compile using X headers with no special include directory.
+ac_x_includes=
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ # Look for the header file in a standard set of common directories.
+# Check X11 before X11Rn because it is often a symlink to the current release.
+ for ac_dir in \
+ /usr/X11/include \
+ /usr/X11R6/include \
+ /usr/X11R5/include \
+ /usr/X11R4/include \
+ \
+ /usr/include/X11 \
+ /usr/include/X11R6 \
+ /usr/include/X11R5 \
+ /usr/include/X11R4 \
+ \
+ /usr/local/X11/include \
+ /usr/local/X11R6/include \
+ /usr/local/X11R5/include \
+ /usr/local/X11R4/include \
+ \
+ /usr/local/include/X11 \
+ /usr/local/include/X11R6 \
+ /usr/local/include/X11R5 \
+ /usr/local/include/X11R4 \
+ \
+ /usr/X386/include \
+ /usr/x386/include \
+ /usr/XFree86/include/X11 \
+ \
+ /usr/include \
+ /usr/local/include \
+ /usr/unsupported/include \
+ /usr/athena/include \
+ /usr/local/x11r5/include \
+ /usr/lpp/Xamples/include \
+ \
+ /usr/openwin/include \
+ /usr/openwin/share/include \
+ ; \
+ do
+ if test -r "$ac_dir/$x_direct_test_include"; then
+ ac_x_includes=$ac_dir
+ break
+ fi
+ done
+fi
+rm -f conftest*
+fi # $ac_x_includes = NO
+
+if test "$ac_x_libraries" = NO; then
+ # Check for the libraries.
+
+ test -z "$x_direct_test_library" && x_direct_test_library=Xt
+ test -z "$x_direct_test_function" && x_direct_test_function=XtMalloc
+
+ # See if we find them without any special options.
+ # Don't add to $LIBS permanently.
+ ac_save_LIBS="$LIBS"
+ LIBS="-l$x_direct_test_library $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2063 "configure"
+#include "confdefs.h"
+
+int main() {
+${x_direct_test_function}()
+; return 0; }
+EOF
+if { (eval echo configure:2070: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ LIBS="$ac_save_LIBS"
+# We can link X programs with no special library path.
+ac_x_libraries=
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ LIBS="$ac_save_LIBS"
+# First see if replacing the include by lib works.
+# Check X11 before X11Rn because it is often a symlink to the current release.
+for ac_dir in `echo "$ac_x_includes" | sed s/include/lib/` \
+ /usr/X11/lib \
+ /usr/X11R6/lib \
+ /usr/X11R5/lib \
+ /usr/X11R4/lib \
+ \
+ /usr/lib/X11 \
+ /usr/lib/X11R6 \
+ /usr/lib/X11R5 \
+ /usr/lib/X11R4 \
+ \
+ /usr/local/X11/lib \
+ /usr/local/X11R6/lib \
+ /usr/local/X11R5/lib \
+ /usr/local/X11R4/lib \
+ \
+ /usr/local/lib/X11 \
+ /usr/local/lib/X11R6 \
+ /usr/local/lib/X11R5 \
+ /usr/local/lib/X11R4 \
+ \
+ /usr/X386/lib \
+ /usr/x386/lib \
+ /usr/XFree86/lib/X11 \
+ \
+ /usr/lib \
+ /usr/local/lib \
+ /usr/unsupported/lib \
+ /usr/athena/lib \
+ /usr/local/x11r5/lib \
+ /usr/lpp/Xamples/lib \
+ /lib/usr/lib/X11 \
+ \
+ /usr/openwin/lib \
+ /usr/openwin/share/lib \
+ ; \
+do
+ for ac_extension in a so sl; do
+ if test -r $ac_dir/lib${x_direct_test_library}.$ac_extension; then
+ ac_x_libraries=$ac_dir
+ break 2
+ fi
+ done
+done
+fi
+rm -f conftest*
+fi # $ac_x_libraries = NO
+
+if test "$ac_x_includes" = NO || test "$ac_x_libraries" = NO; then
+ # Didn't find X anywhere. Cache the known absence of X.
+ ac_cv_have_x="have_x=no"
+else
+ # Record where we found X for the cache.
+ ac_cv_have_x="have_x=yes \
+ ac_x_includes=$ac_x_includes ac_x_libraries=$ac_x_libraries"
+fi
+fi
+ fi
+ eval "$ac_cv_have_x"
+fi # $with_x != no
+
+if test "$have_x" != yes; then
+ echo "$ac_t""$have_x" 1>&6
+ no_x=yes
+else
+ # If each of the values was on the command line, it overrides each guess.
+ test "x$x_includes" = xNONE && x_includes=$ac_x_includes
+ test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries
+ # Update the cache value to reflect the command line values.
+ ac_cv_have_x="have_x=yes \
+ ac_x_includes=$x_includes ac_x_libraries=$x_libraries"
+ echo "$ac_t""libraries $x_libraries, headers $x_includes" 1>&6
+fi
+
+echo $ac_n "checking for XCreateWindow in -lX11""... $ac_c" 1>&6
+echo "configure:2157: checking for XCreateWindow in -lX11" >&5
+ac_lib_var=`echo X11'_'XCreateWindow | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lX11 -L$x_libraries $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2165 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char XCreateWindow();
+
+int main() {
+XCreateWindow()
+; return 0; }
+EOF
+if { (eval echo configure:2176: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lX11 -L$x_libraries"
+else
+ echo "$ac_t""no" 1>&6
+echo "no X11 found" || exit 1
+fi
+
+
+ac_safe=`echo "tcl.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for tcl.h""... $ac_c" 1>&6
+echo "configure:2200: checking for tcl.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2205 "configure"
+#include "confdefs.h"
+#include <tcl.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2210: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ :
+else
+ echo "$ac_t""no" 1>&6
+ac_safe=`echo "tcl8.1/tcl.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for tcl8.1/tcl.h""... $ac_c" 1>&6
+echo "configure:2231: checking for tcl8.1/tcl.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2236 "configure"
+#include "confdefs.h"
+#include <tcl8.1/tcl.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2241: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.1"
+else
+ echo "$ac_t""no" 1>&6
+ac_safe=`echo "tcl8.2/tcl.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for tcl8.2/tcl.h""... $ac_c" 1>&6
+echo "configure:2262: checking for tcl8.2/tcl.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2267 "configure"
+#include "confdefs.h"
+#include <tcl8.2/tcl.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2272: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.2"
+else
+ echo "$ac_t""no" 1>&6
+ac_safe=`echo "tcl8.3/tcl.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for tcl8.3/tcl.h""... $ac_c" 1>&6
+echo "configure:2293: checking for tcl8.3/tcl.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2298 "configure"
+#include "confdefs.h"
+#include <tcl8.3/tcl.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2303: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.3"
+else
+ echo "$ac_t""no" 1>&6
+ac_safe=`echo "tcl8.4/tcl.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for tcl8.4/tcl.h""... $ac_c" 1>&6
+echo "configure:2324: checking for tcl8.4/tcl.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2329 "configure"
+#include "confdefs.h"
+#include <tcl8.4/tcl.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2334: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.4"
+else
+ echo "$ac_t""no" 1>&6
+ac_safe=`echo "tcl8.5/tcl.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for tcl8.5/tcl.h""... $ac_c" 1>&6
+echo "configure:2355: checking for tcl8.5/tcl.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2360 "configure"
+#include "confdefs.h"
+#include <tcl8.5/tcl.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2365: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.5"
+else
+ echo "$ac_t""no" 1>&6
+echo "no tcl/tk header found" || exit 1
+fi
+
+fi
+
+fi
+
+fi
+
+fi
+
+fi
+
+
+echo $ac_n "checking for main in -ltcl8.3""... $ac_c" 1>&6
+echo "configure:2399: checking for main in -ltcl8.3" >&5
+ac_lib_var=`echo tcl8.3'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ltcl8.3 $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2407 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:2414: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo tcl8.3 | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-ltcl8.3 $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for main in -ltcl8.2""... $ac_c" 1>&6
+echo "configure:2440: checking for main in -ltcl8.2" >&5
+ac_lib_var=`echo tcl8.2'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ltcl8.2 $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2448 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:2455: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo tcl8.2 | sed -e 's/^a-zA-Z0-9_/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-ltcl8.2 $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for main in -ltcl8.0""... $ac_c" 1>&6
+echo "configure:2481: checking for main in -ltcl8.0" >&5
+ac_lib_var=`echo tcl8.0'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ltcl8.0 $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2489 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:2496: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo tcl8.0 | sed -e 's/^a-zA-Z0-9_/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-ltcl8.0 $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+fi
+
+
+echo $ac_n "checking for main in -ltk8.3""... $ac_c" 1>&6
+echo "configure:2529: checking for main in -ltk8.3" >&5
+ac_lib_var=`echo tk8.3'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ltk8.3 $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2537 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:2544: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo tk8.3 | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-ltk8.3 $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for main in -ltk8.2""... $ac_c" 1>&6
+echo "configure:2570: checking for main in -ltk8.2" >&5
+ac_lib_var=`echo tk8.2'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ltk8.2 $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2578 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:2585: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo tk8.2 | sed -e 's/^a-zA-Z0-9_/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-ltk8.2 $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for main in -ltk8.0""... $ac_c" 1>&6
+echo "configure:2611: checking for main in -ltk8.0" >&5
+ac_lib_var=`echo tk8.0'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ltk8.0 $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2619 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:2626: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo tk8.0 | sed -e 's/^a-zA-Z0-9_/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-ltk8.0 $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+fi
+
+
+
+
+if test `uname -s` = FreeBSD;
+then
+ LDFLAGS="-Wl,-export-dynamic"
+ EXT=pd_freebsd
+ MORECFLAGS=-DDL_OPEN
+ SYSSRC=s_freebsd.c
+ STRIPFLAG=-s
+ GUINAME="pd-gui"
+ OSNUMBER=0
+fi
+
+if test `uname -s` = Linux;
+then
+ LDFLAGS="-Wl,-export-dynamic"
+ EXT=pd_linux
+ MORECFLAGS=-DDL_OPEN
+ SYSSRC=s_linux.c
+ STRIPFLAG=-s
+ GUINAME="pd-gui"
+ if test $USE_OPT_CFLAGS == "YES";
+ then
+ OPT_CFLAGS="-O6 -funroll-loops -fomit-frame-pointer"
+ else
+ OPT_CFLAGS="-g"
+ fi
+ OSNUMBER=0
+fi
+
+if test `uname -s` = IRIX64;
+then
+ LDFLAGS="-n32 -DUNIX -DIRIX -DN32 -woff 1080,1064,1185 \
+ -OPT:roundoff=3 -OPT:IEEE_arithmetic=3 -OPT:cray_ivdep=true \
+ -shared -rdata_shared"
+ EXT=pd_irix6
+ MORECFLAGS=-DDL_OPEN
+ SYSSRC=s_sgi.c
+ STRIPFLAG=-s
+ GUINAME="pd-gui"
+ OSNUMBER=0
+fi
+
+if test `uname -s` = IRIX32;
+then
+ LDFLAGS="-o32 -DUNIX -DIRIX -O2 -shared -rdata_shared"
+ EXT=pd_irix5
+ MORECFLAGS=-DDL_OPEN
+ SYSSRC=s_sgi.c
+ STRIPFLAG=-s
+ GUINAME="pd-gui"
+ OSNUMBER=0
+fi
+
+if test `uname -s` = Darwin;
+then
+ LDFLAGS="-Wl -framework Tcl -framework Tk -framework CoreAudio -framework Carbon -framework CoreMIDI"
+ EXT=pd_darwin
+ MORECFLAGS="-DMACOSX -I/usr/X11R6/include -I../portaudio/pa_common \
+ -I../portaudio/pablio -I../portaudio/portmidi-macosx -Wno-error"
+ SYSSRC="s_mac.c s_portaudio.c ../portaudio/pa_common/pa_lib.c \
+ ../portaudio/pa_common/pa_trace.c \
+ ../portaudio/pa_common/pa_convert.c \
+ ../portaudio/pablio/pablio_pd.c \
+ ../portaudio/pablio/ringbuffer_pd.c \
+ ../portaudio/pa_mac_core/pa_mac_core.c \
+ ../portaudio/portmidi-macosx/pmdarwin.c \
+ ../portaudio/portmidi-macosx/pmmacosx.c \
+ ../portaudio/portmidi-macosx/pmutil.c \
+ ../portaudio/portmidi-macosx/portmidi.c \
+ ../portaudio/portmidi-macosx/ptdarwin.c "
+ STRIPFLAG=""
+ GUINAME="pdtcl"
+ GUIFLAGS="-framework Tcl -framework Tk \
+ -I/Library/Frameworks/Tk.framework/Versions/Current/Headers \
+ -I/Library/Frameworks/Tcl.framework/Versions/Current/Headers \
+ -I/Library/Frameworks/Tcl.framework/Versions/8.4/PrivateHeaders"
+ if test $USE_OPT_CFLAGS == "YES";
+ then
+ OPT_CFLAGS="-O2"
+ else
+ OPT_CFLAGS="-g"
+ fi
+ OSNUMBER=2
+ EXTERNTARGET=pd_darwin
+fi
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+cat > conftest.defs <<\EOF
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g
+s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g
+s%\[%\\&%g
+s%\]%\\&%g
+s%\$%$$%g
+EOF
+DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`
+rm -f conftest.defs
+
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@alsa@%$alsa%g
+s%@rme@%$rme%g
+s%@PDLIB@%$PDLIB%g
+s%@DEFINES@%$DEFINES%g
+s%@MORECFLAGS@%$MORECFLAGS%g
+s%@EXT@%$EXT%g
+s%@OPT_CFLAGS@%$OPT_CFLAGS%g
+s%@USE_OPT_CFLAGS@%$USE_OPT_CFLAGS%g
+s%@SYSSRC@%$SYSSRC%g
+s%@STRIPFLAG@%$STRIPFLAG%g
+s%@GUINAME@%$GUINAME%g
+s%@GUIFLAGS@%$GUIFLAGS%g
+s%@OSNUMBER@%$OSNUMBER%g
+s%@EXTERNTARGET@%$EXTERNTARGET%g
+s%@CC@%$CC%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@CPP@%$CPP%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ case "$ac_given_INSTALL" in
+ [/$]*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
+
diff --git a/pd/src/configure.in b/pd/src/configure.in
new file mode 100644
index 00000000..ad1eba66
--- /dev/null
+++ b/pd/src/configure.in
@@ -0,0 +1,192 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(d_arithmetic.c)
+
+AC_SUBST(alsa)
+AC_SUBST(rme)
+AC_SUBST(PDLIB)
+AC_SUBST(DEFINES)
+AC_SUBST(MORECFLAGS)
+AC_SUBST(EXT)
+AC_SUBST(OPT_CFLAGS)
+AC_SUBST(USE_OPT_CFLAGS)
+AC_SUBST(SYSSRC)
+AC_SUBST(STRIPFLAG)
+AC_SUBST(GUINAME)
+AC_SUBST(GUIFLAGS)
+AC_SUBST(OSNUMBER)
+AC_SUBST(EXTERNTARGET)
+
+dnl other defaults
+
+dnl check for features
+
+AC_ARG_ENABLE(alsa, [ --enable-alsa compile ALSA support],
+ alsa="yes")
+AC_ARG_ENABLE(old-alsa,[ --enable-old-alsa ALSA 0.5x support],
+ alsa="old")
+AC_ARG_ENABLE(rme, [ --enable-rme compile RME support],
+ rme="yes")
+AC_ARG_ENABLE(debug, [ --enable-debug debugging support],
+ USE_OPT_CFLAGS="NO", USE_OPT_CFLAGS="YES")
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+AC_PROG_CPP
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h limits.h malloc.h sys/ioctl.h sys/time.h unistd.h bstring.h)
+
+dnl Checks for library functions.
+AC_PROG_GCC_TRADITIONAL
+AC_TYPE_SIGNAL
+AC_FUNC_VPRINTF
+AC_CHECK_FUNCS(gettimeofday select socket strerror)
+
+
+dnl Checks for libraries.
+dnl Checking for `dlopen' function in -ldl:
+AC_CHECK_LIB(dl, dlopen,PDLIB="$PDLIB -ldl",
+ echo "dynamic link support required" || exit 1)
+
+dnl Checking for `sin' function in -lffm:
+dnl ffm is the fast math library on the alpha
+AC_CHECK_LIB(ffm, sin,PDLIB="$PDLIB -lffm")
+
+dnl Checking for `sin' function in -lm:
+AC_CHECK_LIB(m, sin,PDLIB="$PDLIB -lm",
+ echo "math library required" || exit 1)
+
+dnl Checking for `pthread_create' function in -pthread
+AC_CHECK_LIB(pthread, pthread_create,PDLIB="$PDLIB -lpthread",
+ echo "pthreads required" || exit 1)
+
+dnl This should be fixed so Pd can use ALSA shared libraries where appropriate.
+if test "$alsa" = yes; then
+ AC_CHECK_LIB(asound,snd_pcm_info,PDLIB="$PDLIB -lasound",alsa="")
+elif test "$alsa" = old; then
+ AC_CHECK_LIB(asound,snd_pcm_info,PDLIB="$PDLIB -lasound",alsa="")
+fi
+
+dnl Find paths to includes and libraries for X11
+AC_PATH_X
+dnl Checking for `XCreateWindow' function in -lX11:
+AC_CHECK_LIB(X11, XCreateWindow, LIBS="$LIBS -lX11 -L$x_libraries",
+ echo "no X11 found" || exit 1, -L$x_libraries)
+
+AC_CHECK_HEADER(tcl.h,,
+ AC_CHECK_HEADER(tcl8.1/tcl.h,GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.1",
+ AC_CHECK_HEADER(tcl8.2/tcl.h,GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.2",
+ AC_CHECK_HEADER(tcl8.3/tcl.h,GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.3",
+ AC_CHECK_HEADER(tcl8.4/tcl.h,GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.4",
+ AC_CHECK_HEADER(tcl8.5/tcl.h,GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.5",
+ echo "no tcl/tk header found" || exit 1))))))
+
+AC_CHECK_LIB(tcl8.3, main,,
+ AC_CHECK_LIB(tcl8.2, main,,
+ AC_CHECK_LIB(tcl8.0, main)))
+
+AC_CHECK_LIB(tk8.3, main,,
+ AC_CHECK_LIB(tk8.2, main,,
+ AC_CHECK_LIB(tk8.0, main)))
+
+dnl Checking for tk.h or tkstep.h - not used at the moment
+dnl AC_CHECK_HEADER(tk.h,DEFINES="$DEFINES -DTKINC=\\\"tk.h\\\"")
+dnl AC_CHECK_HEADER(tkstep.h,DEFINES="$DEFINES -DTKINC=\\\"tkstep.h\\\"")
+
+
+if test `uname -s` = FreeBSD;
+then
+ LDFLAGS="-Wl,-export-dynamic"
+ EXT=pd_freebsd
+ MORECFLAGS=-DDL_OPEN
+ SYSSRC=s_freebsd.c
+ STRIPFLAG=-s
+ GUINAME="pd-gui"
+ OSNUMBER=0
+fi
+
+if test `uname -s` = Linux;
+then
+ LDFLAGS="-Wl,-export-dynamic"
+ EXT=pd_linux
+ MORECFLAGS=-DDL_OPEN
+ SYSSRC=s_linux.c
+ STRIPFLAG=-s
+ GUINAME="pd-gui"
+ if test $USE_OPT_CFLAGS == "YES";
+ then
+ OPT_CFLAGS="-O6 -funroll-loops -fomit-frame-pointer"
+ else
+ OPT_CFLAGS="-g"
+ fi
+ OSNUMBER=0
+fi
+
+if test `uname -s` = IRIX64;
+then
+ LDFLAGS="-n32 -DUNIX -DIRIX -DN32 -woff 1080,1064,1185 \
+ -OPT:roundoff=3 -OPT:IEEE_arithmetic=3 -OPT:cray_ivdep=true \
+ -shared -rdata_shared"
+ EXT=pd_irix6
+ MORECFLAGS=-DDL_OPEN
+ SYSSRC=s_sgi.c
+ STRIPFLAG=-s
+ GUINAME="pd-gui"
+ OSNUMBER=0
+fi
+
+if test `uname -s` = IRIX32;
+then
+ LDFLAGS="-o32 -DUNIX -DIRIX -O2 -shared -rdata_shared"
+ EXT=pd_irix5
+ MORECFLAGS=-DDL_OPEN
+ SYSSRC=s_sgi.c
+ STRIPFLAG=-s
+ GUINAME="pd-gui"
+ OSNUMBER=0
+fi
+
+if test `uname -s` = Darwin;
+then
+ LDFLAGS="-Wl -framework Tcl -framework Tk -framework CoreAudio -framework Carbon -framework CoreMIDI"
+ EXT=pd_darwin
+ MORECFLAGS="-DMACOSX -I/usr/X11R6/include -I../portaudio/pa_common \
+ -I../portaudio/pablio -I../portaudio/portmidi-macosx -Wno-error"
+ SYSSRC="s_mac.c s_portaudio.c ../portaudio/pa_common/pa_lib.c \
+ ../portaudio/pa_common/pa_trace.c \
+ ../portaudio/pa_common/pa_convert.c \
+ ../portaudio/pablio/pablio_pd.c \
+ ../portaudio/pablio/ringbuffer_pd.c \
+ ../portaudio/pa_mac_core/pa_mac_core.c \
+ ../portaudio/portmidi-macosx/pmdarwin.c \
+ ../portaudio/portmidi-macosx/pmmacosx.c \
+ ../portaudio/portmidi-macosx/pmutil.c \
+ ../portaudio/portmidi-macosx/portmidi.c \
+ ../portaudio/portmidi-macosx/ptdarwin.c "
+ STRIPFLAG=""
+ GUINAME="pdtcl"
+ GUIFLAGS="-framework Tcl -framework Tk \
+ -I/Library/Frameworks/Tk.framework/Versions/Current/Headers \
+ -I/Library/Frameworks/Tcl.framework/Versions/Current/Headers \
+ -I/Library/Frameworks/Tcl.framework/Versions/8.4/PrivateHeaders"
+ if test $USE_OPT_CFLAGS == "YES";
+ then
+ OPT_CFLAGS="-O2"
+ else
+ OPT_CFLAGS="-g"
+ fi
+ OSNUMBER=2
+ EXTERNTARGET=pd_darwin
+fi
+
+AC_OUTPUT(makefile)
+
diff --git a/pd/src/d_arithmetic.c b/pd/src/d_arithmetic.c
new file mode 100644
index 00000000..0ca4e846
--- /dev/null
+++ b/pd/src/d_arithmetic.c
@@ -0,0 +1,842 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* arithmetic binops (+, -, *, /).
+If no creation argument is given, there are two signal inlets for vector/vector
+operation; otherwise it's vector/scalar and the second inlet takes a float
+to reset the value.
+*/
+
+#include "m_pd.h"
+
+/* ----------------------------- plus ----------------------------- */
+static t_class *plus_class, *scalarplus_class;
+
+typedef struct _plus
+{
+ t_object x_obj;
+ float x_f;
+} t_plus;
+
+typedef struct _scalarplus
+{
+ t_object x_obj;
+ float x_f;
+ t_float x_g; /* inlet value */
+} t_scalarplus;
+
+static void *plus_new(t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc > 1) post("+~: extra arguments ignored");
+ if (argc)
+ {
+ t_scalarplus *x = (t_scalarplus *)pd_new(scalarplus_class);
+ floatinlet_new(&x->x_obj, &x->x_g);
+ x->x_g = atom_getfloatarg(0, argc, argv);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+ else
+ {
+ t_plus *x = (t_plus *)pd_new(plus_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+}
+
+t_int *plus_perform(t_int *w)
+{
+ t_float *in1 = (t_float *)(w[1]);
+ t_float *in2 = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--) *out++ = *in1++ + *in2++;
+ return (w+5);
+}
+
+t_int *plus_perf8(t_int *w)
+{
+ t_float *in1 = (t_float *)(w[1]);
+ t_float *in2 = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
+ {
+ float f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ float f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+
+ float g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ float g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+
+ out[0] = f0 + g0; out[1] = f1 + g1; out[2] = f2 + g2; out[3] = f3 + g3;
+ out[4] = f4 + g4; out[5] = f5 + g5; out[6] = f6 + g6; out[7] = f7 + g7;
+ }
+ return (w+5);
+}
+
+t_int *scalarplus_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float f = *(t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--) *out++ = *in++ + f;
+ return (w+5);
+}
+
+t_int *scalarplus_perf8(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float g = *(t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in += 8, out += 8)
+ {
+ float f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
+ float f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
+
+ out[0] = f0 + g; out[1] = f1 + g; out[2] = f2 + g; out[3] = f3 + g;
+ out[4] = f4 + g; out[5] = f5 + g; out[6] = f6 + g; out[7] = f7 + g;
+ }
+ return (w+5);
+}
+
+void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n)
+{
+ if (n&7)
+ dsp_add(plus_perform, 4, in1, in2, out, n);
+ else
+ dsp_add(plus_perf8, 4, in1, in2, out, n);
+}
+
+static void plus_dsp(t_plus *x, t_signal **sp)
+{
+ dsp_add_plus(sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+static void scalarplus_dsp(t_scalarplus *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(scalarplus_perform, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(scalarplus_perf8, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void plus_setup(void)
+{
+ plus_class = class_new(gensym("+~"), (t_newmethod)plus_new, 0,
+ sizeof(t_plus), 0, A_GIMME, 0);
+ class_addmethod(plus_class, (t_method)plus_dsp, gensym("dsp"), 0);
+ CLASS_MAINSIGNALIN(plus_class, t_plus, x_f);
+ class_sethelpsymbol(plus_class, gensym("sigbinops"));
+ scalarplus_class = class_new(gensym("+~"), 0, 0,
+ sizeof(t_scalarplus), 0, 0);
+ CLASS_MAINSIGNALIN(scalarplus_class, t_scalarplus, x_f);
+ class_addmethod(scalarplus_class, (t_method)scalarplus_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(scalarplus_class, gensym("sigbinops"));
+}
+
+/* ----------------------------- minus ----------------------------- */
+static t_class *minus_class, *scalarminus_class;
+
+typedef struct _minus
+{
+ t_object x_obj;
+ float x_f;
+} t_minus;
+
+typedef struct _scalarminus
+{
+ t_object x_obj;
+ float x_f;
+ t_float x_g;
+} t_scalarminus;
+
+static void *minus_new(t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc > 1) post("-~: extra arguments ignored");
+ if (argc)
+ {
+ t_scalarminus *x = (t_scalarminus *)pd_new(scalarminus_class);
+ floatinlet_new(&x->x_obj, &x->x_g);
+ x->x_g = atom_getfloatarg(0, argc, argv);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+ else
+ {
+ t_minus *x = (t_minus *)pd_new(minus_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+}
+
+t_int *minus_perform(t_int *w)
+{
+ t_float *in1 = (t_float *)(w[1]);
+ t_float *in2 = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--) *out++ = *in1++ - *in2++;
+ return (w+5);
+}
+
+t_int *minus_perf8(t_int *w)
+{
+ t_float *in1 = (t_float *)(w[1]);
+ t_float *in2 = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
+ {
+ float f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ float f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+
+ float g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ float g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+
+ out[0] = f0 - g0; out[1] = f1 - g1; out[2] = f2 - g2; out[3] = f3 - g3;
+ out[4] = f4 - g4; out[5] = f5 - g5; out[6] = f6 - g6; out[7] = f7 - g7;
+ }
+ return (w+5);
+}
+
+t_int *scalarminus_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float f = *(t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--) *out++ = *in++ - f;
+ return (w+5);
+}
+
+t_int *scalarminus_perf8(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float g = *(t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in += 8, out += 8)
+ {
+ float f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
+ float f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
+
+ out[0] = f0 - g; out[1] = f1 - g; out[2] = f2 - g; out[3] = f3 - g;
+ out[4] = f4 - g; out[5] = f5 - g; out[6] = f6 - g; out[7] = f7 - g;
+ }
+ return (w+5);
+}
+
+static void minus_dsp(t_minus *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(minus_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(minus_perf8, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+static void scalarminus_dsp(t_scalarminus *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(scalarminus_perform, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(scalarminus_perf8, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void minus_setup(void)
+{
+ minus_class = class_new(gensym("-~"), (t_newmethod)minus_new, 0,
+ sizeof(t_minus), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(minus_class, t_minus, x_f);
+ class_addmethod(minus_class, (t_method)minus_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(minus_class, gensym("sigbinops"));
+ scalarminus_class = class_new(gensym("-~"), 0, 0,
+ sizeof(t_scalarminus), 0, 0);
+ CLASS_MAINSIGNALIN(scalarminus_class, t_scalarminus, x_f);
+ class_addmethod(scalarminus_class, (t_method)scalarminus_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(scalarminus_class, gensym("sigbinops"));
+}
+
+/* ----------------------------- times ----------------------------- */
+
+static t_class *times_class, *scalartimes_class;
+
+typedef struct _times
+{
+ t_object x_obj;
+ float x_f;
+} t_times;
+
+typedef struct _scalartimes
+{
+ t_object x_obj;
+ float x_f;
+ t_float x_g;
+} t_scalartimes;
+
+static void *times_new(t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc > 1) post("*~: extra arguments ignored");
+ if (argc)
+ {
+ t_scalartimes *x = (t_scalartimes *)pd_new(scalartimes_class);
+ floatinlet_new(&x->x_obj, &x->x_g);
+ x->x_g = atom_getfloatarg(0, argc, argv);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+ else
+ {
+ t_times *x = (t_times *)pd_new(times_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+}
+
+t_int *times_perform(t_int *w)
+{
+ t_float *in1 = (t_float *)(w[1]);
+ t_float *in2 = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--) *out++ = *in1++ * *in2++;
+ return (w+5);
+}
+
+t_int *times_perf8(t_int *w)
+{
+ t_float *in1 = (t_float *)(w[1]);
+ t_float *in2 = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
+ {
+ float f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ float f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+
+ float g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ float g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+
+ out[0] = f0 * g0; out[1] = f1 * g1; out[2] = f2 * g2; out[3] = f3 * g3;
+ out[4] = f4 * g4; out[5] = f5 * g5; out[6] = f6 * g6; out[7] = f7 * g7;
+ }
+ return (w+5);
+}
+
+t_int *scalartimes_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float f = *(t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--) *out++ = *in++ * f;
+ return (w+5);
+}
+
+t_int *scalartimes_perf8(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float g = *(t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in += 8, out += 8)
+ {
+ float f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
+ float f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
+
+ out[0] = f0 * g; out[1] = f1 * g; out[2] = f2 * g; out[3] = f3 * g;
+ out[4] = f4 * g; out[5] = f5 * g; out[6] = f6 * g; out[7] = f7 * g;
+ }
+ return (w+5);
+}
+
+static void times_dsp(t_times *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(times_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(times_perf8, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+static void scalartimes_dsp(t_scalartimes *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(scalartimes_perform, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(scalartimes_perf8, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void times_setup(void)
+{
+ times_class = class_new(gensym("*~"), (t_newmethod)times_new, 0,
+ sizeof(t_times), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(times_class, t_times, x_f);
+ class_addmethod(times_class, (t_method)times_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(times_class, gensym("sigbinops"));
+ scalartimes_class = class_new(gensym("*~"), 0, 0,
+ sizeof(t_scalartimes), 0, 0);
+ CLASS_MAINSIGNALIN(scalartimes_class, t_scalartimes, x_f);
+ class_addmethod(scalartimes_class, (t_method)scalartimes_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(scalartimes_class, gensym("sigbinops"));
+}
+
+/* ----------------------------- over ----------------------------- */
+static t_class *over_class, *scalarover_class;
+
+typedef struct _over
+{
+ t_object x_obj;
+ float x_f;
+} t_over;
+
+typedef struct _scalarover
+{
+ t_object x_obj;
+ float x_f;
+ t_float x_g;
+} t_scalarover;
+
+static void *over_new(t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc > 1) post("/~: extra arguments ignored");
+ if (argc)
+ {
+ t_scalarover *x = (t_scalarover *)pd_new(scalarover_class);
+ floatinlet_new(&x->x_obj, &x->x_g);
+ x->x_g = atom_getfloatarg(0, argc, argv);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+ else
+ {
+ t_over *x = (t_over *)pd_new(over_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+}
+
+t_int *over_perform(t_int *w)
+{
+ t_float *in1 = (t_float *)(w[1]);
+ t_float *in2 = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--)
+ {
+ float g = *in2++;
+ *out++ = (g ? *in1++ / g : 0);
+ }
+ return (w+5);
+}
+
+t_int *over_perf8(t_int *w)
+{
+ t_float *in1 = (t_float *)(w[1]);
+ t_float *in2 = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
+ {
+ float f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ float f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+
+ float g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ float g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+
+ out[0] = (g0? f0 / g0 : 0);
+ out[1] = (g1? f1 / g1 : 0);
+ out[2] = (g2? f2 / g2 : 0);
+ out[3] = (g3? f3 / g3 : 0);
+ out[4] = (g4? f4 / g4 : 0);
+ out[5] = (g5? f5 / g5 : 0);
+ out[6] = (g6? f6 / g6 : 0);
+ out[7] = (g7? f7 / g7 : 0);
+ }
+ return (w+5);
+}
+
+t_int *scalarover_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float f = 1. / *(t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--) *out++ = *in++ * f;
+ return (w+5);
+}
+
+t_int *scalarover_perf8(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float g = *(t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ if (g) g = 1.f / g;
+ for (; n; n -= 8, in += 8, out += 8)
+ {
+ float f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
+ float f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
+
+ out[0] = f0 * g; out[1] = f1 * g; out[2] = f2 * g; out[3] = f3 * g;
+ out[4] = f4 * g; out[5] = f5 * g; out[6] = f6 * g; out[7] = f7 * g;
+ }
+ return (w+5);
+}
+
+static void over_dsp(t_over *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(over_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(over_perf8, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+static void scalarover_dsp(t_scalarover *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(scalarover_perform, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(scalarover_perf8, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void over_setup(void)
+{
+ over_class = class_new(gensym("/~"), (t_newmethod)over_new, 0,
+ sizeof(t_over), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(over_class, t_over, x_f);
+ class_addmethod(over_class, (t_method)over_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(over_class, gensym("sigbinops"));
+ scalarover_class = class_new(gensym("/~"), 0, 0,
+ sizeof(t_scalarover), 0, 0);
+ CLASS_MAINSIGNALIN(scalarover_class, t_scalarover, x_f);
+ class_addmethod(scalarover_class, (t_method)scalarover_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(scalarover_class, gensym("sigbinops"));
+}
+
+/* ----------------------------- max ----------------------------- */
+static t_class *max_class, *scalarmax_class;
+
+typedef struct _max
+{
+ t_object x_obj;
+ float x_f;
+} t_max;
+
+typedef struct _scalarmax
+{
+ t_object x_obj;
+ float x_f;
+ t_float x_g;
+} t_scalarmax;
+
+static void *max_new(t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc > 1) post("max~: extra arguments ignored");
+ if (argc)
+ {
+ t_scalarmax *x = (t_scalarmax *)pd_new(scalarmax_class);
+ floatinlet_new(&x->x_obj, &x->x_g);
+ x->x_g = atom_getfloatarg(0, argc, argv);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+ else
+ {
+ t_max *x = (t_max *)pd_new(max_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+}
+
+t_int *max_perform(t_int *w)
+{
+ t_float *in1 = (t_float *)(w[1]);
+ t_float *in2 = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--)
+ {
+ float f = *in1++, g = *in2++;
+ *out++ = (f > g ? f : g);
+ }
+ return (w+5);
+}
+
+t_int *max_perf8(t_int *w)
+{
+ t_float *in1 = (t_float *)(w[1]);
+ t_float *in2 = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
+ {
+ float f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ float f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+
+ float g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ float g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+
+ out[0] = (f0 > g0 ? f0 : g0); out[1] = (f1 > g1 ? f1 : g1);
+ out[2] = (f2 > g2 ? f2 : g2); out[3] = (f3 > g3 ? f3 : g3);
+ out[4] = (f4 > g4 ? f4 : g4); out[5] = (f5 > g5 ? f5 : g5);
+ out[6] = (f6 > g6 ? f6 : g6); out[7] = (f7 > g7 ? f7 : g7);
+ }
+ return (w+5);
+}
+
+t_int *scalarmax_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float f = *(t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--)
+ {
+ t_float g = *in++;
+ *out++ = (f > g ? f : g);
+ }
+ return (w+5);
+}
+
+t_int *scalarmax_perf8(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float g = *(t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in += 8, out += 8)
+ {
+ float f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
+ float f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
+
+ out[0] = (f0 > g ? f0 : g); out[1] = (f1 > g ? f1 : g);
+ out[2] = (f2 > g ? f2 : g); out[3] = (f3 > g ? f3 : g);
+ out[4] = (f4 > g ? f4 : g); out[5] = (f5 > g ? f5 : g);
+ out[6] = (f6 > g ? f6 : g); out[7] = (f7 > g ? f7 : g);
+ }
+ return (w+5);
+}
+
+static void max_dsp(t_max *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(max_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(max_perf8, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+static void scalarmax_dsp(t_scalarmax *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(scalarmax_perform, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(scalarmax_perf8, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void max_setup(void)
+{
+ max_class = class_new(gensym("max~"), (t_newmethod)max_new, 0,
+ sizeof(t_max), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(max_class, t_max, x_f);
+ class_addmethod(max_class, (t_method)max_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(max_class, gensym("sigbinops"));
+ scalarmax_class = class_new(gensym("max~"), 0, 0,
+ sizeof(t_scalarmax), 0, 0);
+ CLASS_MAINSIGNALIN(scalarmax_class, t_scalarmax, x_f);
+ class_addmethod(scalarmax_class, (t_method)scalarmax_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(scalarmax_class, gensym("sigbinops"));
+}
+
+/* ----------------------------- min ----------------------------- */
+static t_class *min_class, *scalarmin_class;
+
+typedef struct _min
+{
+ t_object x_obj;
+ float x_f;
+} t_min;
+
+typedef struct _scalarmin
+{
+ t_object x_obj;
+ t_float x_g;
+ float x_f;
+} t_scalarmin;
+
+static void *min_new(t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc > 1) post("min~: extra arguments ignored");
+ if (argc)
+ {
+ t_scalarmin *x = (t_scalarmin *)pd_new(scalarmin_class);
+ floatinlet_new(&x->x_obj, &x->x_g);
+ x->x_g = atom_getfloatarg(0, argc, argv);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+ else
+ {
+ t_min *x = (t_min *)pd_new(min_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+ }
+}
+
+t_int *min_perform(t_int *w)
+{
+ t_float *in1 = (t_float *)(w[1]);
+ t_float *in2 = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--)
+ {
+ float f = *in1++, g = *in2++;
+ *out++ = (f < g ? f : g);
+ }
+ return (w+5);
+}
+
+t_int *min_perf8(t_int *w)
+{
+ t_float *in1 = (t_float *)(w[1]);
+ t_float *in2 = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8)
+ {
+ float f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ float f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+
+ float g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ float g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+
+ out[0] = (f0 < g0 ? f0 : g0); out[1] = (f1 < g1 ? f1 : g1);
+ out[2] = (f2 < g2 ? f2 : g2); out[3] = (f3 < g3 ? f3 : g3);
+ out[4] = (f4 < g4 ? f4 : g4); out[5] = (f5 < g5 ? f5 : g5);
+ out[6] = (f6 < g6 ? f6 : g6); out[7] = (f7 < g7 ? f7 : g7);
+ }
+ return (w+5);
+}
+
+t_int *scalarmin_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float f = *(t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--)
+ {
+ t_float g = *in++;
+ *out++ = (f < g ? f : g);
+ }
+ return (w+5);
+}
+
+t_int *scalarmin_perf8(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float g = *(t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ for (; n; n -= 8, in += 8, out += 8)
+ {
+ float f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
+ float f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
+
+ out[0] = (f0 < g ? f0 : g); out[1] = (f1 < g ? f1 : g);
+ out[2] = (f2 < g ? f2 : g); out[3] = (f3 < g ? f3 : g);
+ out[4] = (f4 < g ? f4 : g); out[5] = (f5 < g ? f5 : g);
+ out[6] = (f6 < g ? f6 : g); out[7] = (f7 < g ? f7 : g);
+ }
+ return (w+5);
+}
+
+static void min_dsp(t_min *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(min_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(min_perf8, 4,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[0]->s_n);
+}
+
+static void scalarmin_dsp(t_scalarmin *x, t_signal **sp)
+{
+ if (sp[0]->s_n&7)
+ dsp_add(scalarmin_perform, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+ else
+ dsp_add(scalarmin_perf8, 4, sp[0]->s_vec, &x->x_g,
+ sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void min_setup(void)
+{
+ min_class = class_new(gensym("min~"), (t_newmethod)min_new, 0,
+ sizeof(t_min), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(min_class, t_min, x_f);
+ class_addmethod(min_class, (t_method)min_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(min_class, gensym("sigbinops"));
+ scalarmin_class = class_new(gensym("min~"), 0, 0,
+ sizeof(t_scalarmin), 0, 0);
+ CLASS_MAINSIGNALIN(scalarmin_class, t_scalarmin, x_f);
+ class_addmethod(scalarmin_class, (t_method)scalarmin_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(scalarmin_class, gensym("sigbinops"));
+}
+
+/* ----------------------- global setup routine ---------------- */
+void d_arithmetic_setup(void)
+{
+ plus_setup();
+ minus_setup();
+ times_setup();
+ over_setup();
+ max_setup();
+ min_setup();
+}
+
diff --git a/pd/src/d_array.c b/pd/src/d_array.c
new file mode 100644
index 00000000..3491ad35
--- /dev/null
+++ b/pd/src/d_array.c
@@ -0,0 +1,1075 @@
+/* Copyright (c) 1997-1999 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. */
+
+/* sampling */
+
+/* LATER make tabread4 and tabread~ */
+
+#include "m_imp.h"
+
+
+/* ------------------------- tabwrite~ -------------------------- */
+
+static t_class *tabwrite_tilde_class;
+
+typedef struct _tabwrite_tilde
+{
+ t_object x_obj;
+ int x_phase;
+ int x_nsampsintab;
+ float *x_vec;
+ t_symbol *x_arrayname;
+ t_clock *x_clock;
+ float x_f;
+} t_tabwrite_tilde;
+
+static void tabwrite_tilde_tick(t_tabwrite_tilde *x);
+
+static void *tabwrite_tilde_new(t_symbol *s)
+{
+ t_tabwrite_tilde *x = (t_tabwrite_tilde *)pd_new(tabwrite_tilde_class);
+ x->x_clock = clock_new(x, (t_method)tabwrite_tilde_tick);
+ x->x_phase = 0x7fffffff;
+ x->x_arrayname = s;
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *tabwrite_tilde_perform(t_int *w)
+{
+ t_tabwrite_tilde *x = (t_tabwrite_tilde *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ int n = (int)(w[3]), phase = x->x_phase, endphase = x->x_nsampsintab;
+ if (!x->x_vec) goto bad;
+
+ if (endphase > phase)
+ {
+ int nxfer = endphase - phase;
+ float *fp = x->x_vec + phase;
+ if (nxfer > n) nxfer = n;
+ phase += nxfer;
+ while (nxfer--)
+ {
+ float f = *in++;
+ /* bash NANs and underflow/overflow hazards to zero */
+ if (!((f > 1.0e-20f && f < 1.0e20f) || (f < -1e-20f && f > -1e20)))
+ f = 0;
+ *fp++ = f;
+ }
+ if (phase >= endphase)
+ {
+ clock_delay(x->x_clock, 0);
+ phase = 0x7fffffff;
+ }
+ x->x_phase = phase;
+ }
+bad:
+ return (w+4);
+}
+
+void tabwrite_tilde_set(t_tabwrite_tilde *x, t_symbol *s)
+{
+ t_garray *a;
+
+ x->x_arrayname = s;
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*s->s_name) pd_error(x, "tabwrite~: %s: no such array",
+ x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if (!garray_getfloatarray(a, &x->x_nsampsintab, &x->x_vec))
+ {
+ error("%s: bad template for tabwrite~", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else garray_usedindsp(a);
+}
+
+static void tabwrite_tilde_dsp(t_tabwrite_tilde *x, t_signal **sp)
+{
+ tabwrite_tilde_set(x, x->x_arrayname);
+ dsp_add(tabwrite_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+}
+
+static void tabwrite_tilde_bang(t_tabwrite_tilde *x)
+{
+ x->x_phase = 0;
+}
+
+static void tabwrite_tilde_stop(t_tabwrite_tilde *x)
+{
+ if (x->x_phase != 0x7fffffff)
+ {
+ tabwrite_tilde_tick(x);
+ x->x_phase = 0x7fffffff;
+ }
+}
+
+static void tabwrite_tilde_tick(t_tabwrite_tilde *x)
+{
+ t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
+ if (!a) bug("tabwrite_tilde_tick");
+ else garray_redraw(a);
+}
+
+static void tabwrite_tilde_free(t_tabwrite_tilde *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void tabwrite_tilde_setup(void)
+{
+ tabwrite_tilde_class = class_new(gensym("tabwrite~"),
+ (t_newmethod)tabwrite_tilde_new, (t_method)tabwrite_tilde_free,
+ sizeof(t_tabwrite_tilde), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(tabwrite_tilde_class, t_tabwrite_tilde, x_f);
+ class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_set,
+ gensym("set"), A_SYMBOL, 0);
+ class_addmethod(tabwrite_tilde_class, (t_method)tabwrite_tilde_stop,
+ gensym("stop"), 0);
+ class_addbang(tabwrite_tilde_class, tabwrite_tilde_bang);
+}
+
+/* ------------ tabplay~ - non-transposing sample playback --------------- */
+
+static t_class *tabplay_tilde_class;
+
+typedef struct _tabplay_tilde
+{
+ t_object x_obj;
+ t_outlet *x_bangout;
+ int x_phase;
+ int x_nsampsintab;
+ int x_limit;
+ float *x_vec;
+ t_symbol *x_arrayname;
+ t_clock *x_clock;
+} t_tabplay_tilde;
+
+static void tabplay_tilde_tick(t_tabplay_tilde *x);
+
+static void *tabplay_tilde_new(t_symbol *s)
+{
+ t_tabplay_tilde *x = (t_tabplay_tilde *)pd_new(tabplay_tilde_class);
+ x->x_clock = clock_new(x, (t_method)tabplay_tilde_tick);
+ x->x_phase = 0x7fffffff;
+ x->x_limit = 0;
+ x->x_arrayname = s;
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_bangout = outlet_new(&x->x_obj, &s_bang);
+ return (x);
+}
+
+static t_int *tabplay_tilde_perform(t_int *w)
+{
+ t_tabplay_tilde *x = (t_tabplay_tilde *)(w[1]);
+ t_float *out = (t_float *)(w[2]), *fp;
+ int n = (int)(w[3]), phase = x->x_phase,
+ endphase = (x->x_nsampsintab < x->x_limit ?
+ x->x_nsampsintab : x->x_limit), nxfer, n3;
+ if (!x->x_vec || phase >= endphase)
+ goto zero;
+
+ nxfer = endphase - phase;
+ fp = x->x_vec + phase;
+ if (nxfer > n)
+ nxfer = n;
+ n3 = n - nxfer;
+ phase += nxfer;
+ while (nxfer--)
+ *out++ = *fp++;
+ if (phase >= endphase)
+ {
+ clock_delay(x->x_clock, 0);
+ x->x_phase = 0x7fffffff;
+ while (n3--)
+ *out++ = 0;
+ }
+ else x->x_phase = phase;
+
+ return (w+4);
+zero:
+ while (n--) *out++ = 0;
+ return (w+4);
+}
+
+void tabplay_tilde_set(t_tabplay_tilde *x, t_symbol *s)
+{
+ t_garray *a;
+
+ x->x_arrayname = s;
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*s->s_name) pd_error(x, "tabplay~: %s: no such array",
+ x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if (!garray_getfloatarray(a, &x->x_nsampsintab, &x->x_vec))
+ {
+ error("%s: bad template for tabplay~", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else garray_usedindsp(a);
+}
+
+static void tabplay_tilde_dsp(t_tabplay_tilde *x, t_signal **sp)
+{
+ tabplay_tilde_set(x, x->x_arrayname);
+ dsp_add(tabplay_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+}
+
+static void tabplay_tilde_list(t_tabplay_tilde *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ long start = atom_getfloatarg(0, argc, argv);
+ long length = atom_getfloatarg(1, argc, argv);
+ if (start < 0) start = 0;
+ if (length <= 0)
+ x->x_limit = 0x7fffffff;
+ else
+ x->x_limit = start + length;
+ x->x_phase = start;
+}
+
+static void tabplay_tilde_stop(t_tabplay_tilde *x)
+{
+ x->x_phase = 0x7fffffff;
+}
+
+static void tabplay_tilde_tick(t_tabplay_tilde *x)
+{
+ outlet_bang(x->x_bangout);
+}
+
+static void tabplay_tilde_free(t_tabplay_tilde *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void tabplay_tilde_setup(void)
+{
+ tabplay_tilde_class = class_new(gensym("tabplay~"),
+ (t_newmethod)tabplay_tilde_new, (t_method)tabplay_tilde_free,
+ sizeof(t_tabplay_tilde), 0, A_DEFSYM, 0);
+ class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_stop,
+ gensym("stop"), 0);
+ class_addmethod(tabplay_tilde_class, (t_method)tabplay_tilde_set,
+ gensym("set"), A_DEFSYM, 0);
+ class_addlist(tabplay_tilde_class, tabplay_tilde_list);
+}
+
+/******************** tabread~ ***********************/
+
+static t_class *tabread_tilde_class;
+
+typedef struct _tabread_tilde
+{
+ t_object x_obj;
+ int x_npoints;
+ float *x_vec;
+ t_symbol *x_arrayname;
+ float x_f;
+} t_tabread_tilde;
+
+static void *tabread_tilde_new(t_symbol *s)
+{
+ t_tabread_tilde *x = (t_tabread_tilde *)pd_new(tabread_tilde_class);
+ x->x_arrayname = s;
+ x->x_vec = 0;
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *tabread_tilde_perform(t_int *w)
+{
+ t_tabread_tilde *x = (t_tabread_tilde *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ int maxindex;
+ float *buf = x->x_vec, *fp;
+ int i;
+
+ maxindex = x->x_npoints - 1;
+ if (!buf) goto zero;
+
+ for (i = 0; i < n; i++)
+ {
+ int index = *in++;
+ if (index < 0)
+ index = 0;
+ else if (index > maxindex)
+ index = maxindex;
+ *out++ = buf[index];
+ }
+ return (w+5);
+ zero:
+ while (n--) *out++ = 0;
+
+ return (w+5);
+}
+
+void tabread_tilde_set(t_tabread_tilde *x, t_symbol *s)
+{
+ t_garray *a;
+
+ x->x_arrayname = s;
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*s->s_name)
+ error("tabread~: %s: no such array", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if (!garray_getfloatarray(a, &x->x_npoints, &x->x_vec))
+ {
+ error("%s: bad template for tabread~", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else garray_usedindsp(a);
+}
+
+static void tabread_tilde_dsp(t_tabread_tilde *x, t_signal **sp)
+{
+ tabread_tilde_set(x, x->x_arrayname);
+
+ dsp_add(tabread_tilde_perform, 4, x,
+ sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+
+}
+
+static void tabread_tilde_free(t_tabread_tilde *x)
+{
+}
+
+static void tabread_tilde_setup(void)
+{
+ tabread_tilde_class = class_new(gensym("tabread~"),
+ (t_newmethod)tabread_tilde_new, (t_method)tabread_tilde_free,
+ sizeof(t_tabread_tilde), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(tabread_tilde_class, t_tabread_tilde, x_f);
+ class_addmethod(tabread_tilde_class, (t_method)tabread_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(tabread_tilde_class, (t_method)tabread_tilde_set,
+ gensym("set"), A_SYMBOL, 0);
+}
+
+/******************** tabread4~ ***********************/
+
+static t_class *tabread4_tilde_class;
+
+typedef struct _tabread4_tilde
+{
+ t_object x_obj;
+ int x_npoints;
+ float *x_vec;
+ t_symbol *x_arrayname;
+ float x_f;
+} t_tabread4_tilde;
+
+static void *tabread4_tilde_new(t_symbol *s)
+{
+ t_tabread4_tilde *x = (t_tabread4_tilde *)pd_new(tabread4_tilde_class);
+ x->x_arrayname = s;
+ x->x_vec = 0;
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *tabread4_tilde_perform(t_int *w)
+{
+ t_tabread4_tilde *x = (t_tabread4_tilde *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ int maxindex;
+ float *buf = x->x_vec, *fp;
+ int i;
+
+ maxindex = x->x_npoints - 3;
+
+ if (!buf) goto zero;
+
+#if 0 /* test for spam -- I'm not ready to deal with this */
+ for (i = 0, xmax = 0, xmin = maxindex, fp = in1; i < n; i++, fp++)
+ {
+ float f = *in1;
+ if (f < xmin) xmin = f;
+ else if (f > xmax) xmax = f;
+ }
+ if (xmax < xmin + x->c_maxextent) xmax = xmin + x->c_maxextent;
+ for (i = 0, splitlo = xmin+ x->c_maxextent, splithi = xmax - x->c_maxextent,
+ fp = in1; i < n; i++, fp++)
+ {
+ float f = *in1;
+ if (f > splitlo && f < splithi) goto zero;
+ }
+#endif
+
+ for (i = 0; i < n; i++)
+ {
+ float findex = *in++;
+ int index = findex;
+ float frac, a, b, c, d, cminusb;
+ static int count;
+ if (index < 1)
+ index = 1, frac = 0;
+ else if (index > maxindex)
+ index = maxindex, frac = 1;
+ else frac = findex - index;
+ fp = buf + index;
+ a = fp[-1];
+ b = fp[0];
+ c = fp[1];
+ d = fp[2];
+ /* if (!i && !(count++ & 1023))
+ post("fp = %lx, shit = %lx, b = %f", fp, buf->b_shit, b); */
+ cminusb = c-b;
+ *out++ = b + frac * (
+ cminusb - 0.5f * (frac-1.) * (
+ (a - d + 3.0f * cminusb) * frac + (b - a - cminusb)
+ )
+ );
+ }
+ return (w+5);
+ zero:
+ while (n--) *out++ = 0;
+
+ return (w+5);
+}
+
+void tabread4_tilde_set(t_tabread4_tilde *x, t_symbol *s)
+{
+ t_garray *a;
+
+ x->x_arrayname = s;
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*s->s_name)
+ error("tabread4~: %s: no such array", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if (!garray_getfloatarray(a, &x->x_npoints, &x->x_vec))
+ {
+ error("%s: bad template for tabread4~", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else garray_usedindsp(a);
+}
+
+static void tabread4_tilde_dsp(t_tabread4_tilde *x, t_signal **sp)
+{
+ tabread4_tilde_set(x, x->x_arrayname);
+
+ dsp_add(tabread4_tilde_perform, 4, x,
+ sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+
+}
+
+static void tabread4_tilde_free(t_tabread4_tilde *x)
+{
+}
+
+static void tabread4_tilde_setup(void)
+{
+ tabread4_tilde_class = class_new(gensym("tabread4~"),
+ (t_newmethod)tabread4_tilde_new, (t_method)tabread4_tilde_free,
+ sizeof(t_tabread4_tilde), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(tabread4_tilde_class, t_tabread4_tilde, x_f);
+ class_addmethod(tabread4_tilde_class, (t_method)tabread4_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(tabread4_tilde_class, (t_method)tabread4_tilde_set,
+ gensym("set"), A_SYMBOL, 0);
+}
+
+/******************** tabosc4~ ***********************/
+
+/* this is all copied from d_osc.c... what include file could this go in? */
+#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */
+
+ /* machine-dependent definitions. These ifdefs really
+ should have been by CPU type and not by operating system! */
+#ifdef IRIX
+ /* big-endian. Most significant byte is at low address in memory */
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#define int32 long /* a data type that has 32 bits */
+#else
+#ifdef NT
+ /* little-endian; most significant byte is at highest address */
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#define int32 long
+#else
+#ifdef __FreeBSD__
+#include <machine/endian.h>
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#else
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#endif /* BYTE_ORDER */
+#include <sys/types.h>
+#define int32 int32_t
+#endif
+
+#ifdef __linux__
+#include <endian.h>
+#if !defined(__BYTE_ORDER) || !defined(__LITTLE_ENDIAN)
+#error No byte order defined
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#else
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#endif /* __BYTE_ORDER */
+
+#include <sys/types.h>
+#define int32 int32_t
+
+#else
+#ifdef MACOSX
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#define int32 int /* a data type that has 32 bits */
+
+#endif /* MACOSX */
+#endif /* __linux__ */
+#endif /* NT */
+#endif /* SGI */
+
+union tabfudge
+{
+ double tf_d;
+ int32 tf_i[2];
+};
+
+static t_class *tabosc4_tilde_class;
+
+typedef struct _tabosc4_tilde
+{
+ t_object x_obj;
+ float x_fnpoints;
+ float x_finvnpoints;
+ float *x_vec;
+ t_symbol *x_arrayname;
+ float x_f;
+ double x_phase;
+ float x_conv;
+} t_tabosc4_tilde;
+
+static void *tabosc4_tilde_new(t_symbol *s)
+{
+ t_tabosc4_tilde *x = (t_tabosc4_tilde *)pd_new(tabosc4_tilde_class);
+ x->x_arrayname = s;
+ x->x_vec = 0;
+ x->x_fnpoints = 512.;
+ x->x_finvnpoints = (1./512.);
+ outlet_new(&x->x_obj, gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *tabosc4_tilde_perform(t_int *w)
+{
+ t_tabosc4_tilde *x = (t_tabosc4_tilde *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ int normhipart;
+ union tabfudge tf;
+ float fnpoints = x->x_fnpoints;
+ int mask = fnpoints - 1;
+ float conv = fnpoints * x->x_conv;
+ int maxindex;
+ float *tab = x->x_vec, *addr;
+ int i;
+ double dphase = fnpoints * x->x_phase + UNITBIT32;
+
+ if (!tab) goto zero;
+ tf.tf_d = UNITBIT32;
+ normhipart = tf.tf_i[HIOFFSET];
+
+#if 1
+ while (n--)
+ {
+ float frac, a, b, c, d, cminusb;
+ tf.tf_d = dphase;
+ dphase += *in++ * conv;
+ addr = tab + (tf.tf_i[HIOFFSET] & mask);
+ tf.tf_i[HIOFFSET] = normhipart;
+ frac = tf.tf_d - UNITBIT32;
+ a = addr[0];
+ b = addr[1];
+ c = addr[2];
+ d = addr[3];
+ cminusb = c-b;
+ *out++ = b + frac * (
+ cminusb - 0.5f * (frac-1.) * (
+ (a - d + 3.0f * cminusb) * frac + (b - a - cminusb)
+ )
+ );
+ }
+#endif
+
+ tf.tf_d = UNITBIT32 * fnpoints;
+ normhipart = tf.tf_i[HIOFFSET];
+ tf.tf_d = dphase + (UNITBIT32 * fnpoints - UNITBIT32);
+ tf.tf_i[HIOFFSET] = normhipart;
+ x->x_phase = (tf.tf_d - UNITBIT32 * fnpoints) * x->x_finvnpoints;
+ return (w+5);
+ zero:
+ while (n--) *out++ = 0;
+
+ return (w+5);
+}
+
+void tabosc4_tilde_set(t_tabosc4_tilde *x, t_symbol *s)
+{
+ t_garray *a;
+ int npoints, pointsinarray;
+
+ x->x_arrayname = s;
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*s->s_name)
+ pd_error(x, "tabosc4~: %s: no such array", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if (!garray_getfloatarray(a, &pointsinarray, &x->x_vec))
+ {
+ pd_error(x, "%s: bad template for tabosc4~", x->x_arrayname->s_name);
+ x->x_vec = 0;
+ }
+ else if ((npoints = pointsinarray - 3) != (1 << ilog2(pointsinarray - 3)))
+ {
+ pd_error(x, "%s: number of points (%d) not a power of 2 plus three",
+ x->x_arrayname->s_name, pointsinarray);
+ x->x_vec = 0;
+ garray_usedindsp(a);
+ }
+ else
+ {
+ x->x_fnpoints = npoints;
+ x->x_finvnpoints = 1./npoints;
+ garray_usedindsp(a);
+ }
+}
+
+static void tabosc4_tilde_ft1(t_tabosc4_tilde *x, t_float f)
+{
+ x->x_phase = f;
+}
+
+static void tabosc4_tilde_dsp(t_tabosc4_tilde *x, t_signal **sp)
+{
+ x->x_conv = 1. / sp[0]->s_sr;
+ tabosc4_tilde_set(x, x->x_arrayname);
+
+ dsp_add(tabosc4_tilde_perform, 4, x,
+ sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void tabosc4_tilde_setup(void)
+{
+ tabosc4_tilde_class = class_new(gensym("tabosc4~"),
+ (t_newmethod)tabosc4_tilde_new, 0,
+ sizeof(t_tabosc4_tilde), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(tabosc4_tilde_class, t_tabosc4_tilde, x_f);
+ class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_set,
+ gensym("set"), A_SYMBOL, 0);
+ class_addmethod(tabosc4_tilde_class, (t_method)tabosc4_tilde_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
+
+/* ------------------------ tabsend~ ------------------------- */
+
+static t_class *tabsend_class;
+
+typedef struct _tabsend
+{
+ t_object x_obj;
+ float *x_vec;
+ int x_graphperiod;
+ int x_graphcount;
+ t_symbol *x_arrayname;
+ t_clock *x_clock;
+ float x_f;
+} t_tabsend;
+
+static void tabsend_tick(t_tabsend *x);
+
+static void *tabsend_new(t_symbol *s)
+{
+ t_tabsend *x = (t_tabsend *)pd_new(tabsend_class);
+ x->x_graphcount = 0;
+ x->x_arrayname = s;
+ x->x_clock = clock_new(x, (t_method)tabsend_tick);
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *tabsend_perform(t_int *w)
+{
+ t_tabsend *x = (t_tabsend *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ int n = w[3];
+ t_float *dest = x->x_vec;
+ int i = x->x_graphcount;
+ if (!x->x_vec) goto bad;
+
+ while (n--)
+ {
+ float f = *in++;
+ /* bash NANs and underflow/overflow hazards to zero */
+ if (!((f > 1.0e-20f && f < 1.0e20f) || (f < -1e-20f && f > -1e20)))
+ f = 0;
+ *dest++ = f;
+ }
+ if (!i--)
+ {
+ clock_delay(x->x_clock, 0);
+ i = x->x_graphperiod;
+ }
+ x->x_graphcount = i;
+bad:
+ return (w+4);
+}
+
+static void tabsend_dsp(t_tabsend *x, t_signal **sp)
+{
+ int i, vecsize;
+ t_garray *a;
+
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*x->x_arrayname->s_name)
+ error("tabsend~: %s: no such array", x->x_arrayname->s_name);
+ }
+ else if (!garray_getfloatarray(a, &vecsize, &x->x_vec))
+ error("%s: bad template for tabsend~", x->x_arrayname->s_name);
+ else
+ {
+ int n = sp[0]->s_n;
+ int ticksper = sp[0]->s_sr/n;
+ if (ticksper < 1) ticksper = 1;
+ x->x_graphperiod = ticksper;
+ if (x->x_graphcount > ticksper) x->x_graphcount = ticksper;
+ if (n < vecsize) vecsize = n;
+ garray_usedindsp(a);
+ dsp_add(tabsend_perform, 3, x, sp[0]->s_vec, vecsize);
+ }
+}
+
+static void tabsend_tick(t_tabsend *x)
+{
+ t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
+ if (!a) bug("tabsend_tick");
+ else garray_redraw(a);
+}
+
+static void tabsend_free(t_tabsend *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void tabsend_setup(void)
+{
+ tabsend_class = class_new(gensym("tabsend~"), (t_newmethod)tabsend_new,
+ (t_method)tabsend_free, sizeof(t_tabsend), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(tabsend_class, t_tabsend, x_f);
+ class_addmethod(tabsend_class, (t_method)tabsend_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------ tabreceive~ ------------------------- */
+
+static t_class *tabreceive_class;
+
+typedef struct _tabreceive
+{
+ t_object x_obj;
+ float *x_vec;
+ t_symbol *x_arrayname;
+} t_tabreceive;
+
+static t_int *tabreceive_perform(t_int *w)
+{
+ t_tabreceive *x = (t_tabreceive *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = w[3];
+ t_float *from = x->x_vec;
+ if (from) while (n--) *out++ = *from++;
+ else while (n--) *out++ = 0;
+ return (w+4);
+}
+
+static void tabreceive_dsp(t_tabreceive *x, t_signal **sp)
+{
+ t_garray *a;
+ int vecsize;
+
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ {
+ if (*x->x_arrayname->s_name)
+ error("tabsend~: %s: no such array", x->x_arrayname->s_name);
+ }
+ else if (!garray_getfloatarray(a, &vecsize, &x->x_vec))
+ error("%s: bad template for tabreceive~", x->x_arrayname->s_name);
+ else
+ {
+ int n = sp[0]->s_n;
+ if (n < vecsize) vecsize = n;
+ garray_usedindsp(a);
+ dsp_add(tabreceive_perform, 3, x, sp[0]->s_vec, vecsize);
+ }
+}
+
+static void *tabreceive_new(t_symbol *s)
+{
+ t_tabreceive *x = (t_tabreceive *)pd_new(tabreceive_class);
+ x->x_arrayname = s;
+ outlet_new(&x->x_obj, &s_signal);
+ return (x);
+}
+
+static void tabreceive_setup(void)
+{
+ tabreceive_class = class_new(gensym("tabreceive~"),
+ (t_newmethod)tabreceive_new, 0,
+ sizeof(t_tabreceive), 0, A_DEFSYM, 0);
+ class_addmethod(tabreceive_class, (t_method)tabreceive_dsp,
+ gensym("dsp"), 0);
+}
+
+/* ---------- tabread: control, non-interpolating ------------------------ */
+
+static t_class *tabread_class;
+
+typedef struct _tabread
+{
+ t_object x_obj;
+ t_symbol *x_arrayname;
+} t_tabread;
+
+static void tabread_float(t_tabread *x, t_float f)
+{
+ t_garray *a;
+ int npoints;
+ t_float *vec;
+
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ error("%s: no such array", x->x_arrayname->s_name);
+ else if (!garray_getfloatarray(a, &npoints, &vec))
+ error("%s: bad template for tabread", x->x_arrayname->s_name);
+ else
+ {
+ int n = f;
+ if (n < 0) n = 0;
+ else if (n >= npoints) n = npoints - 1;
+ outlet_float(x->x_obj.ob_outlet, (npoints ? vec[n] : 0));
+ }
+}
+
+static void tabread_set(t_tabread *x, t_symbol *s)
+{
+ x->x_arrayname = s;
+}
+
+static void *tabread_new(t_symbol *s)
+{
+ t_tabread *x = (t_tabread *)pd_new(tabread_class);
+ x->x_arrayname = s;
+ outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+static void tabread_setup(void)
+{
+ tabread_class = class_new(gensym("tabread"), (t_newmethod)tabread_new,
+ 0, sizeof(t_tabread), 0, A_DEFSYM, 0);
+ class_addfloat(tabread_class, (t_method)tabread_float);
+ class_addmethod(tabread_class, (t_method)tabread_set, gensym("set"),
+ A_SYMBOL, 0);
+}
+
+/* ---------- tabread4: control, non-interpolating ------------------------ */
+
+static t_class *tabread4_class;
+
+typedef struct _tabread4
+{
+ t_object x_obj;
+ t_symbol *x_arrayname;
+} t_tabread4;
+
+static void tabread4_float(t_tabread4 *x, t_float f)
+{
+ t_garray *a;
+ int npoints;
+ t_float *vec;
+
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ error("%s: no such array", x->x_arrayname->s_name);
+ else if (!garray_getfloatarray(a, &npoints, &vec))
+ error("%s: bad template for tabread4", x->x_arrayname->s_name);
+ else if (npoints < 4)
+ outlet_float(x->x_obj.ob_outlet, 0);
+ else if (f <= 1)
+ outlet_float(x->x_obj.ob_outlet, vec[1]);
+ else if (f >= npoints - 2)
+ outlet_float(x->x_obj.ob_outlet, vec[npoints - 2]);
+ else
+ {
+ int n = f;
+ float a, b, c, d, cminusb, frac, *fp;
+ if (n >= npoints - 2)
+ n = npoints - 3;
+ fp = vec + n;
+ frac = f - n;
+ a = fp[-1];
+ b = fp[0];
+ c = fp[1];
+ d = fp[2];
+ cminusb = c-b;
+ outlet_float(x->x_obj.ob_outlet, b + frac * (
+ cminusb - 0.5f * (frac-1.) * (
+ (a - d + 3.0f * cminusb) * frac + (b - a - cminusb))));
+ }
+}
+
+static void tabread4_set(t_tabread4 *x, t_symbol *s)
+{
+ x->x_arrayname = s;
+}
+
+static void *tabread4_new(t_symbol *s)
+{
+ t_tabread4 *x = (t_tabread4 *)pd_new(tabread4_class);
+ x->x_arrayname = s;
+ outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+static void tabread4_setup(void)
+{
+ tabread4_class = class_new(gensym("tabread4"), (t_newmethod)tabread4_new,
+ 0, sizeof(t_tabread4), 0, A_DEFSYM, 0);
+ class_addfloat(tabread4_class, (t_method)tabread4_float);
+ class_addmethod(tabread4_class, (t_method)tabread4_set, gensym("set"),
+ A_SYMBOL, 0);
+}
+
+/* ------------------ tabwrite: control ------------------------ */
+
+static t_class *tabwrite_class;
+
+typedef struct _tabwrite
+{
+ t_object x_obj;
+ t_symbol *x_arrayname;
+ t_clock *x_clock;
+ float x_ft1;
+ double x_updtime;
+ int x_set;
+} t_tabwrite;
+
+static void tabwrite_tick(t_tabwrite *x)
+{
+ t_garray *a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class);
+ if (!a) bug("tabwrite_tick");
+ else garray_redraw(a);
+ x->x_set = 0;
+ x->x_updtime = clock_getsystime();
+}
+
+static void tabwrite_float(t_tabwrite *x, t_float f)
+{
+ int i, vecsize;
+ t_garray *a;
+ t_float *vec;
+
+ if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class)))
+ error("%s: no such array", x->x_arrayname->s_name);
+ else if (!garray_getfloatarray(a, &vecsize, &vec))
+ error("%s: bad template for tabwrite", x->x_arrayname->s_name);
+ else
+ {
+ int n = x->x_ft1;
+ double timesince = clock_gettimesince(x->x_updtime);
+ if (n < 0) n = 0;
+ else if (n >= vecsize) n = vecsize-1;
+ vec[n] = f;
+ if (timesince > 1000)
+ {
+ tabwrite_tick(x);
+ }
+ else
+ {
+ if (x->x_set == 0)
+ {
+ clock_delay(x->x_clock, 1000 - timesince);
+ x->x_set = 1;
+ }
+ }
+ }
+}
+
+static void tabwrite_set(t_tabwrite *x, t_symbol *s)
+{
+ x->x_arrayname = s;
+}
+
+static void tabwrite_free(t_tabwrite *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void *tabwrite_new(t_symbol *s)
+{
+ t_tabwrite *x = (t_tabwrite *)pd_new(tabwrite_class);
+ x->x_ft1 = 0;
+ x->x_arrayname = s;
+ x->x_updtime = clock_getsystime();
+ x->x_clock = clock_new(x, (t_method)tabwrite_tick);
+ floatinlet_new(&x->x_obj, &x->x_ft1);
+ return (x);
+}
+
+void tabwrite_setup(void)
+{
+ tabwrite_class = class_new(gensym("tabwrite"), (t_newmethod)tabwrite_new,
+ (t_method)tabwrite_free, sizeof(t_tabwrite), 0, A_DEFSYM, 0);
+ class_addfloat(tabwrite_class, (t_method)tabwrite_float);
+ class_addmethod(tabwrite_class, (t_method)tabwrite_set, gensym("set"), A_SYMBOL, 0);
+}
+
+/* ------------------------ global setup routine ------------------------- */
+
+void d_array_setup(void)
+{
+ tabwrite_tilde_setup();
+ tabplay_tilde_setup();
+ tabread_tilde_setup();
+ tabread4_tilde_setup();
+ tabosc4_tilde_setup();
+ tabsend_setup();
+ tabreceive_setup();
+ tabread_setup();
+ tabread4_setup();
+ tabwrite_setup();
+}
+
diff --git a/pd/src/d_ctl.c b/pd/src/d_ctl.c
new file mode 100644
index 00000000..e143a067
--- /dev/null
+++ b/pd/src/d_ctl.c
@@ -0,0 +1,496 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* The sig~ and line~ routines; possibly fancier envelope generators to
+ come later.
+*/
+
+#include "m_pd.h"
+#include "math.h"
+
+/* -------------------------- sig~ ------------------------------ */
+static t_class *sig_class;
+
+typedef struct _sig
+{
+ t_object x_obj;
+ float x_f;
+} t_sig;
+
+static t_int *sig_perform(t_int *w)
+{
+ t_float f = *(t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ while (n--) *out++ = f;
+ return (w+4);
+}
+
+static t_int *sig_perf8(t_int *w)
+{
+ t_float f = *(t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+
+ for (; n; n -= 8, out += 8)
+ {
+ out[0] = f;
+ out[1] = f;
+ out[2] = f;
+ out[3] = f;
+ out[4] = f;
+ out[5] = f;
+ out[6] = f;
+ out[7] = f;
+ }
+ return (w+4);
+}
+
+void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n)
+{
+ if (n&7)
+ dsp_add(sig_perform, 3, in, out, n);
+ else
+ dsp_add(sig_perf8, 3, in, out, n);
+}
+
+static void sig_float(t_sig *x, t_float f)
+{
+ x->x_f = f;
+}
+
+static void sig_dsp(t_sig *x, t_signal **sp)
+{
+ dsp_add(sig_perform, 3, &x->x_f, sp[0]->s_vec, sp[0]->s_n);
+}
+
+static void *sig_new(t_floatarg f)
+{
+ t_sig *x = (t_sig *)pd_new(sig_class);
+ x->x_f = f;
+ outlet_new(&x->x_obj, gensym("signal"));
+ return (x);
+}
+
+static void sig_setup(void)
+{
+ sig_class = class_new(gensym("sig~"), (t_newmethod)sig_new, 0,
+ sizeof(t_sig), 0, A_DEFFLOAT, 0);
+ class_addfloat(sig_class, (t_method)sig_float);
+ class_addmethod(sig_class, (t_method)sig_dsp, gensym("dsp"), 0);
+}
+
+/* -------------------------- line~ ------------------------------ */
+static t_class *line_class;
+
+typedef struct _line
+{
+ t_object x_obj;
+ float x_target;
+ float x_value;
+ float x_biginc;
+ float x_inc;
+ float x_1overn;
+ float x_msectodsptick;
+ float x_inletvalue;
+ float x_inletwas;
+ int x_ticksleft;
+ int x_retarget;
+} t_line;
+
+static t_int *line_perform(t_int *w)
+{
+ t_line *x = (t_line *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ float f = x->x_value;
+ /* bash NANs and underflow/overflow hazards to zero */
+ if (!((f > 1.0e-20f && f < 1.0e20f) || (f < -1e-20f && f > -1e20)))
+ x->x_value = f = 0;
+ if (x->x_retarget)
+ {
+ int nticks = x->x_inletwas * x->x_msectodsptick;
+ if (!nticks) nticks = 1;
+ x->x_ticksleft = nticks;
+ x->x_biginc = (x->x_target - x->x_value)/(float)nticks;
+ x->x_inc = x->x_1overn * x->x_biginc;
+ x->x_retarget = 0;
+ }
+ if (x->x_ticksleft)
+ {
+ float f = x->x_value;
+ while (n--) *out++ = f, f += x->x_inc;
+ x->x_value += x->x_biginc;
+ x->x_ticksleft--;
+ }
+ else
+ {
+ x->x_value = x->x_target;
+ while (n--) *out++ = x->x_value;
+ }
+ return (w+4);
+}
+
+static void line_float(t_line *x, t_float f)
+{
+ if (x->x_inletvalue <= 0)
+ {
+ x->x_target = x->x_value = f;
+ x->x_ticksleft = x->x_retarget = 0;
+ }
+ else
+ {
+ x->x_target = f;
+ x->x_retarget = 1;
+ x->x_inletwas = x->x_inletvalue;
+ x->x_inletvalue = 0;
+ }
+}
+
+static void line_stop(t_line *x)
+{
+ x->x_target = x->x_value;
+ x->x_ticksleft = x->x_retarget = 0;
+}
+
+static void line_dsp(t_line *x, t_signal **sp)
+{
+ dsp_add(line_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+ x->x_1overn = 1./sp[0]->s_n;
+ x->x_msectodsptick = sp[0]->s_sr / (1000 * sp[0]->s_n);
+}
+
+static void *line_new(void)
+{
+ t_line *x = (t_line *)pd_new(line_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ floatinlet_new(&x->x_obj, &x->x_inletvalue);
+ x->x_ticksleft = x->x_retarget = 0;
+ x->x_value = x->x_target = x->x_inletvalue = x->x_inletwas = 0;
+ return (x);
+}
+
+static void line_setup(void)
+{
+ line_class = class_new(gensym("line~"), line_new, 0,
+ sizeof(t_line), 0, 0);
+ class_addfloat(line_class, (t_method)line_float);
+ class_addmethod(line_class, (t_method)line_dsp, gensym("dsp"), 0);
+ class_addmethod(line_class, (t_method)line_stop, gensym("stop"), 0);
+}
+
+/* -------------------------- snapshot~ ------------------------------ */
+static t_class *snapshot_class;
+
+typedef struct _snapshot
+{
+ t_object x_obj;
+ t_sample x_value;
+ float x_f;
+} t_snapshot;
+
+static void *snapshot_new(void)
+{
+ t_snapshot *x = (t_snapshot *)pd_new(snapshot_class);
+ x->x_value = 0;
+ outlet_new(&x->x_obj, &s_float);
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *snapshot_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ *out = *in;
+ return (w+3);
+}
+
+static void snapshot_dsp(t_snapshot *x, t_signal **sp)
+{
+ dsp_add(snapshot_perform, 2, sp[0]->s_vec + (sp[0]->s_n-1), &x->x_value);
+}
+
+static void snapshot_bang(t_snapshot *x)
+{
+ outlet_float(x->x_obj.ob_outlet, x->x_value);
+}
+
+static void snapshot_setup(void)
+{
+ snapshot_class = class_new(gensym("snapshot~"), snapshot_new, 0,
+ sizeof(t_snapshot), 0, 0);
+ CLASS_MAINSIGNALIN(snapshot_class, t_snapshot, x_f);
+ class_addmethod(snapshot_class, (t_method)snapshot_dsp, gensym("dsp"), 0);
+ class_addbang(snapshot_class, snapshot_bang);
+}
+
+/* ---------------- env~ - simple envelope follower. ----------------- */
+
+#define MAXOVERLAP 10
+#define MAXVSTAKEN 64
+
+typedef struct sigenv
+{
+ t_object x_obj; /* header */
+ void *x_outlet; /* a "float" outlet */
+ void *x_clock; /* a "clock" object */
+ float *x_buf; /* a Hanning window */
+ int x_phase; /* number of points since last output */
+ int x_period; /* requested period of output */
+ int x_realperiod; /* period rounded up to vecsize multiple */
+ int x_npoints; /* analysis window size in samples */
+ float x_result; /* result to output */
+ float x_sumbuf[MAXOVERLAP]; /* summing buffer */
+ float x_f;
+} t_sigenv;
+
+t_class *sigenv_class;
+static void sigenv_tick(t_sigenv *x);
+
+static void *sigenv_new(t_floatarg fnpoints, t_floatarg fperiod)
+{
+ int npoints = fnpoints;
+ int period = fperiod;
+ t_sigenv *x;
+ float *buf;
+ int i;
+
+ if (npoints < 1) npoints = 1024;
+ if (period < 1) period = npoints/2;
+ if (period < npoints / MAXOVERLAP + 1)
+ period = npoints / MAXOVERLAP + 1;
+ if (!(buf = getbytes(sizeof(float) * (npoints + MAXVSTAKEN))))
+ {
+ error("env: couldn't allocate buffer");
+ return (0);
+ }
+ x = (t_sigenv *)pd_new(sigenv_class);
+ x->x_buf = buf;
+ x->x_npoints = npoints;
+ x->x_phase = 0;
+ x->x_period = period;
+ for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0;
+ for (i = 0; i < npoints; i++)
+ buf[i] = (1. - cos((2 * 3.14159 * i) / npoints))/npoints;
+ for (; i < npoints+MAXVSTAKEN; i++) buf[i] = 0;
+ x->x_clock = clock_new(x, (t_method)sigenv_tick);
+ x->x_outlet = outlet_new(&x->x_obj, gensym("float"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigenv_perform(t_int *w)
+{
+ t_sigenv *x = (t_sigenv *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ int count;
+ float *sump;
+ in += n;
+ for (count = x->x_phase, sump = x->x_sumbuf;
+ count < x->x_npoints; count += x->x_realperiod, sump++)
+ {
+ float *hp = x->x_buf + count;
+ float *fp = in;
+ float sum = *sump;
+ int i;
+
+ for (i = 0; i < n; i++)
+ {
+ fp--;
+ sum += *hp++ * (*fp * *fp);
+ }
+ *sump = sum;
+ }
+ sump[0] = 0;
+ x->x_phase -= n;
+ if (x->x_phase < 0)
+ {
+ x->x_result = x->x_sumbuf[0];
+ for (count = x->x_realperiod, sump = x->x_sumbuf;
+ count < x->x_npoints; count += x->x_realperiod, sump++)
+ sump[0] = sump[1];
+ sump[0] = 0;
+ x->x_phase = x->x_realperiod - n;
+ clock_delay(x->x_clock, 0L);
+ }
+ return (w+4);
+}
+
+static void sigenv_dsp(t_sigenv *x, t_signal **sp)
+{
+ if (x->x_period % sp[0]->s_n) x->x_realperiod =
+ x->x_period + sp[0]->s_n - (x->x_period % sp[0]->s_n);
+ else x->x_realperiod = x->x_period;
+ dsp_add(sigenv_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+ if (sp[0]->s_n > MAXVSTAKEN) bug("sigenv_dsp");
+}
+
+static void sigenv_tick(t_sigenv *x) /* callback function for the clock */
+{
+ outlet_float(x->x_outlet, powtodb(x->x_result));
+}
+
+static void sigenv_ff(t_sigenv *x) /* cleanup on free */
+{
+ clock_free(x->x_clock);
+ freebytes(x->x_buf, (x->x_npoints + MAXVSTAKEN) * sizeof(float));
+}
+
+
+void sigenv_setup(void )
+{
+ sigenv_class = class_new(gensym("env~"), (t_newmethod)sigenv_new,
+ (t_method)sigenv_ff, sizeof(t_sigenv), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(sigenv_class, t_sigenv, x_f);
+ class_addmethod(sigenv_class, (t_method)sigenv_dsp, gensym("dsp"), 0);
+}
+
+/* --------------------- threshold~ ----------------------------- */
+
+static t_class *threshold_tilde_class;
+
+typedef struct _threshold_tilde
+{
+ t_object x_obj;
+ t_outlet *x_outlet1; /* bang out for high thresh */
+ t_outlet *x_outlet2; /* bang out for low thresh */
+ t_clock *x_clock; /* wakeup for message output */
+ float x_f; /* scalar inlet */
+ int x_state; /* 1 = high, 0 = low */
+ float x_hithresh; /* value of high threshold */
+ float x_lothresh; /* value of low threshold */
+ float x_deadwait; /* msec remaining in dead period */
+ float x_msecpertick; /* msec per DSP tick */
+ float x_hideadtime; /* hi dead time in msec */
+ float x_lodeadtime; /* lo dead time in msec */
+} t_threshold_tilde;
+
+static void threshold_tilde_tick(t_threshold_tilde *x);
+static void threshold_tilde_set(t_threshold_tilde *x,
+ t_floatarg hithresh, t_floatarg hideadtime,
+ t_floatarg lothresh, t_floatarg lodeadtime);
+
+static t_threshold_tilde *threshold_tilde_new(t_floatarg hithresh,
+ t_floatarg hideadtime, t_floatarg lothresh, t_floatarg lodeadtime)
+{
+ t_threshold_tilde *x = (t_threshold_tilde *)
+ pd_new(threshold_tilde_class);
+ x->x_state = 0; /* low state */
+ x->x_deadwait = 0; /* no dead time */
+ x->x_clock = clock_new(x, (t_method)threshold_tilde_tick);
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_bang);
+ x->x_outlet2 = outlet_new(&x->x_obj, &s_bang);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
+ x->x_msecpertick = 0.;
+ x->x_f = 0;
+ threshold_tilde_set(x, hithresh, hideadtime, lothresh, lodeadtime);
+ return (x);
+}
+
+ /* "set" message to specify thresholds and dead times */
+static void threshold_tilde_set(t_threshold_tilde *x,
+ t_floatarg hithresh, t_floatarg hideadtime,
+ t_floatarg lothresh, t_floatarg lodeadtime)
+{
+ if (lothresh > hithresh)
+ lothresh = hithresh;
+ x->x_hithresh = hithresh;
+ x->x_hideadtime = hideadtime;
+ x->x_lothresh = lothresh;
+ x->x_lodeadtime = lodeadtime;
+}
+
+ /* number in inlet sets state -- note incompatible with JMAX which used
+ "int" message for this, impossible here because of auto signal conversion */
+static void threshold_tilde_ft1(t_threshold_tilde *x, t_floatarg f)
+{
+ x->x_state = (f != 0);
+ x->x_deadwait = 0;
+}
+
+static void threshold_tilde_tick(t_threshold_tilde *x)
+{
+ if (x->x_state)
+ outlet_bang(x->x_outlet1);
+ else outlet_bang(x->x_outlet2);
+}
+
+static t_int *threshold_tilde_perform(t_int *w)
+{
+ float *in1 = (float *)(w[1]);
+ t_threshold_tilde *x = (t_threshold_tilde *)(w[2]);
+ int n = (t_int)(w[3]);
+ if (x->x_deadwait > 0)
+ x->x_deadwait -= x->x_msecpertick;
+ else if (x->x_state)
+ {
+ /* we're high; look for low sample */
+ for (; n--; in1++)
+ {
+ if (*in1 < x->x_lothresh)
+ {
+ clock_delay(x->x_clock, 0L);
+ x->x_state = 0;
+ x->x_deadwait = x->x_lodeadtime;
+ goto done;
+ }
+ }
+ }
+ else
+ {
+ /* we're low; look for high sample */
+ for (; n--; in1++)
+ {
+ if (*in1 >= x->x_hithresh)
+ {
+ clock_delay(x->x_clock, 0L);
+ x->x_state = 1;
+ x->x_deadwait = x->x_hideadtime;
+ goto done;
+ }
+ }
+ }
+done:
+ return (w+4);
+}
+
+void threshold_tilde_dsp(t_threshold_tilde *x, t_signal **sp)
+{
+ x->x_msecpertick = 1000. * sp[0]->s_n / sp[0]->s_sr;
+ dsp_add(threshold_tilde_perform, 3, sp[0]->s_vec, x, sp[0]->s_n);
+}
+
+static void threshold_tilde_ff(t_threshold_tilde *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void threshold_tilde_setup( void)
+{
+ threshold_tilde_class = class_new(gensym("threshold~"),
+ (t_newmethod)threshold_tilde_new, (t_method)threshold_tilde_ff,
+ sizeof(t_threshold_tilde), 0,
+ A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(threshold_tilde_class, t_threshold_tilde, x_f);
+ class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_set,
+ gensym("set"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_dsp,
+ gensym("dsp"), 0);
+}
+
+/* ------------------------ global setup routine ------------------------- */
+
+void d_ctl_setup(void)
+{
+ sig_setup();
+ line_setup();
+ snapshot_setup();
+ sigenv_setup();
+ threshold_tilde_setup();
+}
+
diff --git a/pd/src/d_dac.c b/pd/src/d_dac.c
new file mode 100644
index 00000000..620adba5
--- /dev/null
+++ b/pd/src/d_dac.c
@@ -0,0 +1,183 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* The dac~ and adc~ routines.
+*/
+
+#include "m_imp.h"
+
+/* ----------------------------- dac~ --------------------------- */
+static t_class *dac_class;
+
+typedef struct _dac
+{
+ t_object x_obj;
+ t_int x_n;
+ t_int *x_vec;
+ float x_f;
+} t_dac;
+
+static void *dac_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_dac *x = (t_dac *)pd_new(dac_class);
+ t_atom defarg[2], *ap;
+ int i;
+ if (!argc)
+ {
+ argv = defarg;
+ argc = 2;
+ SETFLOAT(&defarg[0], 1);
+ SETFLOAT(&defarg[1], 2);
+ }
+ x->x_n = argc;
+ x->x_vec = (t_int *)getbytes(argc * sizeof(*x->x_vec));
+ for (i = 0; i < argc; i++)
+ x->x_vec[i] = atom_getintarg(i, argc, argv);
+ for (i = 1; i < argc; i++)
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ x->x_f = 0;
+ return (x);
+}
+
+static void dac_dsp(t_dac *x, t_signal **sp)
+{
+ t_int i, *ip;
+ t_signal **sp2;
+ for (i = x->x_n, ip = x->x_vec, sp2 = sp; i--; ip++, sp2++)
+ {
+ int ch = *ip - 1;
+ if ((*sp2)->s_n != DACBLKSIZE)
+ error("dac~: bad vector size");
+ else if (ch >= 0 && ch < sys_get_outchannels())
+ dsp_add(plus_perform, 4, sys_soundout + DACBLKSIZE*ch,
+ (*sp2)->s_vec, sys_soundout + DACBLKSIZE*ch, DACBLKSIZE);
+ }
+}
+
+static void dac_free(t_dac *x)
+{
+ freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec));
+}
+
+static void dac_setup(void)
+{
+ dac_class = class_new(gensym("dac~"), (t_newmethod)dac_new,
+ (t_method)dac_free, sizeof(t_dac), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(dac_class, t_dac, x_f);
+ class_addmethod(dac_class, (t_method)dac_dsp, gensym("dsp"), A_CANT, 0);
+ class_sethelpsymbol(dac_class, gensym("adc~_dac~"));
+}
+
+/* ----------------------------- adc~ --------------------------- */
+static t_class *adc_class;
+
+typedef struct _adc
+{
+ t_object x_obj;
+ t_int x_n;
+ t_int *x_vec;
+} t_adc;
+
+static void *adc_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_adc *x = (t_adc *)pd_new(adc_class);
+ t_atom defarg[2], *ap;
+ int i;
+ if (!argc)
+ {
+ argv = defarg;
+ argc = 2;
+ SETFLOAT(&defarg[0], 1);
+ SETFLOAT(&defarg[1], 2);
+ }
+ x->x_n = argc;
+ x->x_vec = (t_int *)getbytes(argc * sizeof(*x->x_vec));
+ for (i = 0; i < argc; i++)
+ x->x_vec[i] = atom_getintarg(i, argc, argv);
+ for (i = 0; i < argc; i++)
+ outlet_new(&x->x_obj, &s_signal);
+ return (x);
+}
+
+t_int *copy_perform(t_int *w)
+{
+ t_float *in1 = (t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ while (n--) *out++ = *in1++;
+ return (w+4);
+}
+
+t_int *copy_perf8(t_int *w)
+{
+ t_float *in1 = (t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+
+ for (; n; n -= 8, in1 += 8, out += 8)
+ {
+ float f0 = in1[0];
+ float f1 = in1[1];
+ float f2 = in1[2];
+ float f3 = in1[3];
+ float f4 = in1[4];
+ float f5 = in1[5];
+ float f6 = in1[6];
+ float f7 = in1[7];
+
+ out[0] = f0;
+ out[1] = f1;
+ out[2] = f2;
+ out[3] = f3;
+ out[4] = f4;
+ out[5] = f5;
+ out[6] = f6;
+ out[7] = f7;
+ }
+ return (w+4);
+}
+
+void dsp_add_copy(t_sample *in, t_sample *out, int n)
+{
+ if (n&7)
+ dsp_add(copy_perform, 3, in, out, n);
+ else
+ dsp_add(copy_perf8, 3, in, out, n);
+}
+
+static void adc_dsp(t_adc *x, t_signal **sp)
+{
+ t_int i, *ip;
+ t_signal **sp2;
+ for (i = x->x_n, ip = x->x_vec, sp2 = sp; i--; ip++, sp2++)
+ {
+ int ch = *ip - 1;
+ if ((*sp2)->s_n != DACBLKSIZE)
+ error("adc~: bad vector size");
+ else if (ch >= 0 && ch < sys_get_inchannels())
+ dsp_add_copy(sys_soundin + DACBLKSIZE*ch,
+ (*sp2)->s_vec, DACBLKSIZE);
+ else dsp_add_zero((*sp2)->s_vec, DACBLKSIZE);
+ }
+}
+
+static void adc_free(t_adc *x)
+{
+ freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec));
+}
+
+static void adc_setup(void)
+{
+ adc_class = class_new(gensym("adc~"), (t_newmethod)adc_new,
+ (t_method)adc_free, sizeof(t_adc), 0, A_GIMME, 0);
+ class_addmethod(adc_class, (t_method)adc_dsp, gensym("dsp"), A_CANT, 0);
+ class_sethelpsymbol(adc_class, gensym("adc~_dac~"));
+}
+
+void d_dac_setup(void)
+{
+ dac_setup();
+ adc_setup();
+}
+
diff --git a/pd/src/d_delay.c b/pd/src/d_delay.c
new file mode 100644
index 00000000..f14bb112
--- /dev/null
+++ b/pd/src/d_delay.c
@@ -0,0 +1,314 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* send~, delread~, throw~, catch~ */
+
+#include "m_pd.h"
+extern int ugen_getsortno(void);
+
+#define DEFDELVS 64 /* LATER get this from canvas at DSP time */
+static int delread_zero = 0; /* four bytes of zero for delread~, vd~ */
+
+/* ----------------------------- delwrite~ ----------------------------- */
+static t_class *sigdelwrite_class;
+
+typedef struct delwritectl
+{
+ int c_n;
+ float *c_vec;
+ int c_phase;
+} t_delwritectl;
+
+typedef struct _sigdelwrite
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+ t_delwritectl x_cspace;
+ int x_sortno; /* DSP sort number at which this was last put on chain */
+ int x_rsortno; /* DSP sort # for first delread or write in chain */
+ int x_vecsize; /* vector size for delread~ to use */
+ float x_f;
+} t_sigdelwrite;
+
+#define XTRASAMPS 4
+#define SAMPBLK 4
+
+ /* routine to check that all delwrites/delreads/vds have same vecsize */
+static void sigdelwrite_checkvecsize(t_sigdelwrite *x, int vecsize)
+{
+ if (x->x_rsortno != ugen_getsortno())
+ {
+ x->x_vecsize = vecsize;
+ x->x_rsortno = ugen_getsortno();
+ }
+ else if (vecsize != x->x_vecsize)
+ pd_error(x, "delread/delwrite/vd vector size mismatch");
+}
+
+static void *sigdelwrite_new(t_symbol *s, t_floatarg msec)
+{
+ int nsamps;
+ t_sigdelwrite *x = (t_sigdelwrite *)pd_new(sigdelwrite_class);
+ if (!*s->s_name) s = gensym("delwrite~");
+ pd_bind(&x->x_obj.ob_pd, s);
+ x->x_sym = s;
+ nsamps = msec * sys_getsr() * (float)(0.001f);
+ if (nsamps < 1) nsamps = 1;
+ nsamps += ((- nsamps) & (SAMPBLK - 1));
+ nsamps += DEFDELVS;
+ x->x_cspace.c_n = nsamps;
+ x->x_cspace.c_vec =
+ (float *)getbytes((nsamps + XTRASAMPS) * sizeof(float));
+ x->x_cspace.c_phase = XTRASAMPS;
+ x->x_sortno = 0;
+ x->x_vecsize = 0;
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigdelwrite_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_delwritectl *c = (t_delwritectl *)(w[2]);
+ int n = (int)(w[3]);
+ int phase = c->c_phase, nsamps = c->c_n;
+ float *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS);
+ phase += n;
+ while (n--)
+ {
+ float f = *in++;
+ /* bash NANs and underflow/overflow hazards to zero */
+ if (!((f > 1.0e-20f && f < 1.0e20f) || (f < -1e-20f && f > -1e20)))
+ f = 0;
+ *bp++ = f;
+ if (bp == ep)
+ {
+ vp[0] = ep[-4];
+ vp[1] = ep[-3];
+ vp[2] = ep[-2];
+ vp[3] = ep[-1];
+ bp = vp + XTRASAMPS;
+ phase -= nsamps;
+ }
+ }
+ c->c_phase = phase;
+ return (w+4);
+}
+
+static void sigdelwrite_dsp(t_sigdelwrite *x, t_signal **sp)
+{
+ dsp_add(sigdelwrite_perform, 3, sp[0]->s_vec, &x->x_cspace, sp[0]->s_n);
+ x->x_sortno = ugen_getsortno();
+ sigdelwrite_checkvecsize(x, sp[0]->s_n);
+}
+
+static void sigdelwrite_free(t_sigdelwrite *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, x->x_sym);
+ freebytes(x->x_cspace.c_vec,
+ (x->x_cspace.c_n + XTRASAMPS) * sizeof(float));
+}
+
+static void sigdelwrite_setup(void)
+{
+ sigdelwrite_class = class_new(gensym("delwrite~"),
+ (t_newmethod)sigdelwrite_new, (t_method)sigdelwrite_free,
+ sizeof(t_sigdelwrite), 0, A_DEFSYM, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(sigdelwrite_class, t_sigdelwrite, x_f);
+ class_addmethod(sigdelwrite_class, (t_method)sigdelwrite_dsp,
+ gensym("dsp"), 0);
+}
+
+/* ----------------------------- delread~ ----------------------------- */
+static t_class *sigdelread_class;
+
+typedef struct _sigdelread
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+ t_float x_deltime; /* delay in msec */
+ int x_delsamps; /* delay in samples */
+ t_float x_sr; /* samples per msec */
+ t_float x_n; /* vector size */
+ int x_zerodel; /* 0 or vecsize depending on read/write order */
+} t_sigdelread;
+
+static void sigdelread_float(t_sigdelread *x, t_float f);
+
+static void *sigdelread_new(t_symbol *s, t_floatarg f)
+{
+ t_sigdelread *x = (t_sigdelread *)pd_new(sigdelread_class);
+ x->x_sym = s;
+ x->x_sr = 1;
+ x->x_n = 1;
+ x->x_zerodel = 0;
+ sigdelread_float(x, f);
+ outlet_new(&x->x_obj, &s_signal);
+ return (x);
+}
+
+static void sigdelread_float(t_sigdelread *x, t_float f)
+{
+ int samps;
+ t_sigdelwrite *delwriter =
+ (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
+ x->x_deltime = f;
+ if (delwriter)
+ {
+ int delsize = delwriter->x_cspace.c_n;
+ x->x_delsamps = (int)(0.5 + x->x_sr * x->x_deltime)
+ + x->x_n - x->x_zerodel;
+ if (x->x_delsamps < x->x_n) x->x_delsamps = x->x_n;
+ else if (x->x_delsamps > delwriter->x_cspace.c_n - DEFDELVS)
+ x->x_delsamps = delwriter->x_cspace.c_n - DEFDELVS;
+ }
+}
+
+static t_int *sigdelread_perform(t_int *w)
+{
+ t_float *out = (t_float *)(w[1]);
+ t_delwritectl *c = (t_delwritectl *)(w[2]);
+ int delsamps = *(int *)(w[3]);
+ int n = (int)(w[4]);
+ int phase = c->c_phase - delsamps, nsamps = c->c_n;
+ float *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS);
+
+ if (phase < 0) phase += nsamps;
+ bp = vp + phase;
+ while (n--)
+ {
+ *out++ = *bp++;
+ if (bp == ep) bp -= nsamps;
+ }
+ return (w+5);
+}
+
+static void sigdelread_dsp(t_sigdelread *x, t_signal **sp)
+{
+ t_sigdelwrite *delwriter =
+ (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
+ x->x_sr = sp[0]->s_sr * 0.001;
+ x->x_n = sp[0]->s_n;
+ if (delwriter)
+ {
+ sigdelwrite_checkvecsize(delwriter, sp[0]->s_n);
+ x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ?
+ 0 : delwriter->x_vecsize);
+ sigdelread_float(x, x->x_deltime);
+ dsp_add(sigdelread_perform, 4,
+ sp[0]->s_vec, &delwriter->x_cspace, &x->x_delsamps, sp[0]->s_n);
+ }
+ else if (*x->x_sym->s_name)
+ error("delread~: %s: no such delwrite~",x->x_sym->s_name);
+}
+
+static void sigdelread_setup(void)
+{
+ sigdelread_class = class_new(gensym("delread~"),
+ (t_newmethod)sigdelread_new, 0,
+ sizeof(t_sigdelread), 0, A_DEFSYM, A_DEFFLOAT, 0);
+ class_addmethod(sigdelread_class, (t_method)sigdelread_dsp,
+ gensym("dsp"), 0);
+ class_addfloat(sigdelread_class, (t_method)sigdelread_float);
+}
+
+
+/* ----------------------------- vd~ ----------------------------- */
+static t_class *sigvd_class;
+
+typedef struct _sigvd
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+ t_float x_sr; /* samples per msec */
+ int x_zerodel; /* 0 or vecsize depending on read/write order */
+ float x_f;
+} t_sigvd;
+
+static void *sigvd_new(t_symbol *s)
+{
+ t_sigvd *x = (t_sigvd *)pd_new(sigvd_class);
+ if (!*s->s_name) s = gensym("vd~");
+ x->x_sym = s;
+ x->x_sr = 1;
+ x->x_zerodel = 0;
+ outlet_new(&x->x_obj, &s_signal);
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigvd_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ t_delwritectl *ctl = (t_delwritectl *)(w[3]);
+ t_sigvd *x = (t_sigvd *)(w[4]);
+ int n = (int)(w[5]);
+
+ int nsamps = ctl->c_n;
+ float limit = nsamps - n - 1;
+ float fn = n-4;
+ float *vp = ctl->c_vec, *bp, *wp = vp + ctl->c_phase;
+ float zerodel = x->x_zerodel;
+ while (n--)
+ {
+ float delsamps = x->x_sr * *in++ - zerodel, frac;
+ int idelsamps;
+ float a, b, c, d, cminusb;
+ if (delsamps < 1.00001f) delsamps = 1.00001f;
+ if (delsamps > limit) delsamps = limit;
+ delsamps += fn;
+ fn = fn - 1.0f;
+ idelsamps = delsamps;
+ frac = delsamps - (float)idelsamps;
+ bp = wp - (idelsamps + 3);
+ if (bp < vp + 4) bp += nsamps;
+ d = bp[-3];
+ c = bp[-2];
+ b = bp[-1];
+ a = bp[0];
+ cminusb = c-b;
+ *out++ = b + frac * (
+ cminusb - 0.5f * (frac-1.) * (
+ (a - d + 3.0f * cminusb) * frac + (b - a - cminusb)
+ )
+ );
+ }
+ return (w+6);
+}
+
+static void sigvd_dsp(t_sigvd *x, t_signal **sp)
+{
+ t_sigdelwrite *delwriter =
+ (t_sigdelwrite *)pd_findbyclass(x->x_sym, sigdelwrite_class);
+ x->x_sr = sp[0]->s_sr * 0.001;
+ if (delwriter)
+ {
+ sigdelwrite_checkvecsize(delwriter, sp[0]->s_n);
+ x->x_zerodel = (delwriter->x_sortno == ugen_getsortno() ?
+ 0 : delwriter->x_vecsize);
+ dsp_add(sigvd_perform, 5,
+ sp[0]->s_vec, sp[1]->s_vec,
+ &delwriter->x_cspace, x, sp[0]->s_n);
+ }
+ else error("vd~: %s: no such delwrite~",x->x_sym->s_name);
+}
+
+static void sigvd_setup(void)
+{
+ sigvd_class = class_new(gensym("vd~"), (t_newmethod)sigvd_new, 0,
+ sizeof(t_sigvd), 0, A_DEFSYM, 0);
+ class_addmethod(sigvd_class, (t_method)sigvd_dsp, gensym("dsp"), 0);
+ CLASS_MAINSIGNALIN(sigvd_class, t_sigvd, x_f);
+}
+
+/* ----------------------- global setup routine ---------------- */
+
+void d_delay_setup(void)
+{
+ sigdelwrite_setup();
+ sigdelread_setup();
+ sigvd_setup();
+}
+
diff --git a/pd/src/d_fft.c b/pd/src/d_fft.c
new file mode 100644
index 00000000..7e5a95a3
--- /dev/null
+++ b/pd/src/d_fft.c
@@ -0,0 +1,342 @@
+/* Copyright (c) 1997-1999 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 "m_pd.h"
+
+/* ------------------------ fft~ and ifft~ -------------------------------- */
+static t_class *sigfft_class, *sigifft_class;
+
+typedef struct fft
+{
+ t_object x_obj;
+ float x_f;
+} t_sigfft;
+
+static void *sigfft_new(void)
+{
+ t_sigfft *x = (t_sigfft *)pd_new(sigfft_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ x->x_f = 0;
+ return (x);
+}
+
+static void *sigifft_new(void)
+{
+ t_sigfft *x = (t_sigfft *)pd_new(sigifft_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigfft_swap(t_int *w)
+{
+ float *in1 = (t_float *)(w[1]);
+ float *in2 = (t_float *)(w[2]);
+ int n = w[3];
+ for (;n--; in1++, in2++)
+ {
+ float f = *in1;
+ *in1 = *in2;
+ *in2 = f;
+ }
+ return (w+4);
+}
+
+static t_int *sigfft_perform(t_int *w)
+{
+ float *in1 = (t_float *)(w[1]);
+ float *in2 = (t_float *)(w[2]);
+ int n = w[3];
+ mayer_fft(n, in1, in2);
+ return (w+4);
+}
+
+static t_int *sigifft_perform(t_int *w)
+{
+ float *in1 = (t_float *)(w[1]);
+ float *in2 = (t_float *)(w[2]);
+ int n = w[3];
+ mayer_ifft(n, in1, in2);
+ return (w+4);
+}
+
+static void sigfft_dspx(t_sigfft *x, t_signal **sp, t_int *(*f)(t_int *w))
+{
+ int n = sp[0]->s_n;
+ float *in1 = sp[0]->s_vec;
+ float *in2 = sp[1]->s_vec;
+ float *out1 = sp[2]->s_vec;
+ float *out2 = sp[3]->s_vec;
+ if (out1 == in2 && out2 == in1)
+ dsp_add(sigfft_swap, 3, out1, out2, n);
+ else if (out1 == in2)
+ {
+ dsp_add(copy_perform, 3, in2, out2, n);
+ dsp_add(copy_perform, 3, in1, out1, n);
+ }
+ else
+ {
+ if (out1 != in1) dsp_add(copy_perform, 3, in1, out1, n);
+ if (out2 != in2) dsp_add(copy_perform, 3, in2, out2, n);
+ }
+ dsp_add(f, 3, sp[2]->s_vec, sp[3]->s_vec, n);
+}
+
+static void sigfft_dsp(t_sigfft *x, t_signal **sp)
+{
+ sigfft_dspx(x, sp, sigfft_perform);
+}
+
+static void sigifft_dsp(t_sigfft *x, t_signal **sp)
+{
+ sigfft_dspx(x, sp, sigifft_perform);
+}
+
+static void sigfft_setup(void)
+{
+ sigfft_class = class_new(gensym("fft~"), sigfft_new, 0,
+ sizeof(t_sigfft), 0, 0);
+ CLASS_MAINSIGNALIN(sigfft_class, t_sigfft, x_f);
+ class_addmethod(sigfft_class, (t_method)sigfft_dsp, gensym("dsp"), 0);
+
+ sigifft_class = class_new(gensym("ifft~"), sigifft_new, 0,
+ sizeof(t_sigfft), 0, 0);
+ CLASS_MAINSIGNALIN(sigifft_class, t_sigfft, x_f);
+ class_addmethod(sigifft_class, (t_method)sigifft_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(sigifft_class, gensym("fft~"));
+}
+
+/* ----------------------- rfft~ -------------------------------- */
+
+static t_class *sigrfft_class;
+
+typedef struct rfft
+{
+ t_object x_obj;
+ float x_f;
+} t_sigrfft;
+
+static void *sigrfft_new(void)
+{
+ t_sigrfft *x = (t_sigrfft *)pd_new(sigrfft_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigrfft_flip(t_int *w)
+{
+ float *in = (t_float *)(w[1]);
+ float *out = (t_float *)(w[2]);
+ int n = w[3];
+ while (n--) *(--out) = *in++;
+ *(--out) = 0; /* to hell with it */
+ return (w+4);
+}
+
+static t_int *sigrfft_perform(t_int *w)
+{
+ float *in = (t_float *)(w[1]);
+ int n = w[2];
+ mayer_realfft(n, in);
+ return (w+3);
+}
+
+static void sigrfft_dsp(t_sigrfft *x, t_signal **sp)
+{
+ int n = sp[0]->s_n, n2 = (n>>1);
+ float *in1 = sp[0]->s_vec;
+ float *out1 = sp[1]->s_vec;
+ float *out2 = sp[2]->s_vec;
+ if (n < 4)
+ {
+ error("fft: minimum 4 points");
+ return;
+ }
+ if (in1 == out2) /* this probably never happens */
+ {
+ dsp_add(sigrfft_perform, 2, out2, n);
+ dsp_add(copy_perform, 3, out2, out1, n2);
+ dsp_add(sigrfft_flip, 3, out2 + (n2+1), out2 + n2, n2-1);
+ }
+ else
+ {
+ if (in1 != out1) dsp_add(copy_perform, 3, in1, out1, n);
+ dsp_add(sigrfft_perform, 2, out1, n);
+ dsp_add(sigrfft_flip, 3, out1 + (n2+1), out2 + n2, n2-1);
+ }
+ dsp_add_zero(out1 + n2, n2);
+ dsp_add_zero(out2 + n2, n2);
+}
+
+static void sigrfft_setup(void)
+{
+ sigrfft_class = class_new(gensym("rfft~"), sigrfft_new, 0,
+ sizeof(t_sigrfft), 0, 0);
+ CLASS_MAINSIGNALIN(sigrfft_class, t_sigrfft, x_f);
+ class_addmethod(sigrfft_class, (t_method)sigrfft_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(sigrfft_class, gensym("fft~"));
+}
+
+/* ----------------------- rifft~ -------------------------------- */
+
+static t_class *sigrifft_class;
+
+typedef struct rifft
+{
+ t_object x_obj;
+ float x_f;
+} t_sigrifft;
+
+static void *sigrifft_new(void)
+{
+ t_sigrifft *x = (t_sigrifft *)pd_new(sigrifft_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigrifft_perform(t_int *w)
+{
+ float *in = (t_float *)(w[1]);
+ int n = w[2];
+ mayer_realifft(n, in);
+ return (w+3);
+}
+
+static void sigrifft_dsp(t_sigrifft *x, t_signal **sp)
+{
+ int n = sp[0]->s_n, n2 = (n>>1);
+ float *in1 = sp[0]->s_vec;
+ float *in2 = sp[1]->s_vec;
+ float *out1 = sp[2]->s_vec;
+ if (n < 4)
+ {
+ error("fft: minimum 4 points");
+ return;
+ }
+ if (in2 == out1)
+ {
+ dsp_add(sigrfft_flip, 3, out1+1, out1 + n, (n2-1));
+ dsp_add(copy_perform, 3, in1, out1, n2);
+ }
+ else
+ {
+ if (in1 != out1) dsp_add(copy_perform, 3, in1, out1, n2);
+ dsp_add(sigrfft_flip, 3, in2+1, out1 + n, n2-1);
+ }
+ dsp_add(sigrifft_perform, 2, out1, n);
+}
+
+static void sigrifft_setup(void)
+{
+ sigrifft_class = class_new(gensym("rifft~"), sigrifft_new, 0,
+ sizeof(t_sigrifft), 0, 0);
+ CLASS_MAINSIGNALIN(sigrifft_class, t_sigrifft, x_f);
+ class_addmethod(sigrifft_class, (t_method)sigrifft_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(sigrifft_class, gensym("fft~"));
+}
+
+/* ----------------------- framp~ -------------------------------- */
+
+static t_class *sigframp_class;
+
+typedef struct framp
+{
+ t_object x_obj;
+ float x_f;
+} t_sigframp;
+
+static void *sigframp_new(void)
+{
+ t_sigframp *x = (t_sigframp *)pd_new(sigframp_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigframp_perform(t_int *w)
+{
+ float *inreal = (t_float *)(w[1]);
+ float *inimag = (t_float *)(w[2]);
+ float *outfreq = (t_float *)(w[3]);
+ float *outamp = (t_float *)(w[4]);
+ float lastreal = 0, currentreal = inreal[0], nextreal = inreal[1];
+ float lastimag = 0, currentimag = inimag[0], nextimag = inimag[1];
+ int n = w[5];
+ int m = n + 1;
+ float fbin = 1, oneovern2 = 1.f/((float)n * (float)n);
+
+ inreal += 2;
+ inimag += 2;
+ *outamp++ = *outfreq++ = 0;
+ n -= 2;
+ while (n--)
+ {
+ float re, im, pow, freq;
+ lastreal = currentreal;
+ currentreal = nextreal;
+ nextreal = *inreal++;
+ lastimag = currentimag;
+ currentimag = nextimag;
+ nextimag = *inimag++;
+ re = currentreal - 0.5f * (lastreal + nextreal);
+ im = currentimag - 0.5f * (lastimag + nextimag);
+ pow = re * re + im * im;
+ if (pow > 1e-19)
+ {
+ float detune = ((lastreal - nextreal) * re +
+ (lastimag - nextimag) * im) / (2.0f * pow);
+ if (detune > 2 || detune < -2) freq = pow = 0;
+ else freq = fbin + detune;
+ }
+ else freq = pow = 0;
+ *outfreq++ = freq;
+ *outamp++ = oneovern2 * pow;
+ fbin += 1.0f;
+ }
+ while (m--) *outamp++ = *outfreq++ = 0;
+ return (w+6);
+}
+
+t_int *sigsqrt_perform(t_int *w);
+
+static void sigframp_dsp(t_sigframp *x, t_signal **sp)
+{
+ int n = sp[0]->s_n, n2 = (n>>1);
+ if (n < 4)
+ {
+ error("framp: minimum 4 points");
+ return;
+ }
+ dsp_add(sigframp_perform, 5, sp[0]->s_vec, sp[1]->s_vec,
+ sp[2]->s_vec, sp[3]->s_vec, n2);
+ dsp_add(sigsqrt_perform, 3, sp[3]->s_vec, sp[3]->s_vec, n2);
+}
+
+static void sigframp_setup(void)
+{
+ sigframp_class = class_new(gensym("framp~"), sigframp_new, 0,
+ sizeof(t_sigframp), 0, 0);
+ CLASS_MAINSIGNALIN(sigframp_class, t_sigframp, x_f);
+ class_addmethod(sigframp_class, (t_method)sigframp_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------ global setup routine ------------------------- */
+
+void d_fft_setup(void)
+{
+ sigfft_setup();
+ sigrfft_setup();
+ sigrifft_setup();
+ sigframp_setup();
+}
diff --git a/pd/src/d_fftroutine.c b/pd/src/d_fftroutine.c
new file mode 100644
index 00000000..7f0d2523
--- /dev/null
+++ b/pd/src/d_fftroutine.c
@@ -0,0 +1,1001 @@
+/*****************************************************************************/
+/* */
+/* Fast Fourier Transform */
+/* Network Abstraction, Definitions */
+/* Kevin Peterson, MIT Media Lab, EMS */
+/* UROP - Fall '86 */
+/* REV: 6/12/87(KHP) - To incorporate link list of different sized networks */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* added debug option 5/91 brown@nadia */
+/* change sign at AAA */
+/* */
+/* Fast Fourier Transform */
+/* FFT Network Interaction and Support Modules */
+/* Kevin Peterson, MIT Media Lab, EMS */
+/* UROP - Fall '86 */
+/* REV: 6/12/87(KHP) - Generalized to one procedure call with typed I/O */
+/* */
+/*****************************************************************************/
+
+/* Overview:
+
+ My realization of the FFT involves a representation of a network of
+ "butterfly" elements that takes a set of 'N' sound samples as input and
+ computes the discrete Fourier transform. This network consists of a
+ series of stages (log2 N), each stage consisting of N/2 parallel butterfly
+ elements. Consecutive stages are connected by specific, predetermined flow
+ paths, (see Oppenheim, Schafer for details) and each butterfly element has
+ an associated multiplicative coefficient.
+
+ FFT NETWORK:
+ -----------
+ ____ _ ____ _ ____ _ ____ _ ____
+ o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
+ |reg1| | | |W^r1| | | |reg1| | | |W^r1| | | |reg1|
+ | | | | | | | | | | | | | | | | | | .....
+ | | | | | | | | | | | | | | | | | |
+ o--|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|--o
+ | | | | | | | |
+ | | | | | | | |
+ ____ | | ____ | | ____ | | ____ | | ____
+ o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
+ |reg2| | | |W^r2| | | |reg2| | | |W^r2| | | |reg2|
+ | | | | | | | | | | | | | | | | | | .....
+ | | | | | | | | | | | | | | | | | |
+ o--|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|--o
+ | | | | | | | |
+ | | | | | | | |
+ : : : : : : : : :
+ : : : : : : : : :
+ : : : : : : : : :
+ : : : : : : : : :
+ : : : : : : : : :
+
+ ____ | | ____ | | ____ | | ____ | | ____
+ o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
+ |reg | | | |W^r | | | |reg | | | |W^r | | | |reg |
+ | N/2| | | | N/2| | | | N/2| | | | N/2| | | | N/2| .....
+ | | | | | | | | | | | | | | | | | |
+ o--|____|o-|_|-o|____|o-|_|-o|____|o-|_|-o|____|o-|_|-o|____|--o
+
+ ^ ^ ^ ^
+ Initial | Bttrfly | Rd/Wrt | Bttrfly | Rd/Wrt
+ Buffer | | Register | | Register
+ |____________|____________|____________|
+ |
+ |
+ Interconnect
+ Paths
+
+ The use of "in-place" computation permits one to use only one set of
+ registers realized by an array of complex number structures. To describe
+ the coefficients for each butterfly I am using a two dimensional array
+ (stage, butterfly) of complex numbers. The predetermined stage connections
+ will be described in a two dimensional array of indicies. These indicies
+ will be used to determine the order of reading at each stage of the
+ computation.
+*/
+
+
+/*****************************************************************************/
+/* INCLUDE FILES */
+/*****************************************************************************/
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+
+ /* the following is needed only to declare pd_fft() as exportable in NT */
+#include "m_pd.h"
+
+/* some basic definitions */
+#ifndef BOOL
+#define BOOL int
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define SAMPLE float /* data type used in calculation */
+
+#define SHORT_SIZE sizeof(short)
+#define INT_SIZE sizeof(int)
+#define FLOAT_SIZE sizeof(float)
+#define SAMPLE_SIZE sizeof(SAMPLE)
+#define PNTR_SIZE sizeof(char *)
+
+#define PI 3.1415927
+#define TWO_PI 6.2831854
+
+/* type definitions for I/O buffers */
+#define REAL 0 /* real only */
+#define IMAG 2 /* imaginary only */
+#define RECT 8 /* real and imaginary */
+#define MAG 16 /* magnitude only */
+#define PHASE 32 /* phase only */
+#define POLAR 64 /* magnitude and phase*/
+
+/* scale definitions for I/O buffers */
+#define LINEAR 0
+#define DB 1 /* 20log10 */
+
+/* transform direction definition */
+#define FORWARD 1 /* Forward FFT */
+#define INVERSE 2 /* Inverse FFT */
+
+/* window type definitions */
+#define HANNING 1
+#define RECTANGULAR 0
+
+
+
+/* network structure definition */
+
+typedef struct Tfft_net {
+ int n;
+ int stages;
+ int bps;
+ int direction;
+ int window_type;
+ int *load_index;
+ SAMPLE *window, *inv_window;
+ SAMPLE *regr;
+ SAMPLE *regi;
+ SAMPLE **indexpr;
+ SAMPLE **indexpi;
+ SAMPLE **indexqr;
+ SAMPLE **indexqi;
+ SAMPLE *coeffr, *inv_coeffr;
+ SAMPLE *coeffi, *inv_coeffi;
+ struct Tfft_net *next;
+} FFT_NET;
+
+
+void cfft(int trnsfrm_dir, int npnt, int window,
+ float *source_buf, int source_form, int source_scale,
+ float *result_buf, int result_form, int result_scale, int debug);
+
+
+/*****************************************************************************/
+/* GLOBAL DECLARATIONS */
+/*****************************************************************************/
+
+static FFT_NET *firstnet;
+
+/* prototypes */
+
+void net_alloc(FFT_NET *fft_net);
+void net_dealloc(FFT_NET *fft_net);
+int power_of_two(int n);
+void create_hanning(SAMPLE *window, int n, SAMPLE scale);
+void create_rectangular(SAMPLE *window, int n, SAMPLE scale);
+void short_to_float(short *short_buf, float *float_buf, int n);
+void load_registers(FFT_NET *fft_net, float *buf, int buf_form,
+ int buf_scale, int trnsfrm_dir);
+void compute_fft(FFT_NET *fft_net);
+void store_registers(FFT_NET *fft_net, float *buf, int buf_form,
+ int buf_scale, int debug);
+void build_fft_network(FFT_NET *fft_net, int n, int window_type);
+
+/*****************************************************************************/
+/* GENERALIZED FAST FOURIER TRANSFORM MODULE */
+/*****************************************************************************/
+
+void cfft(int trnsfrm_dir, int npnt, int window,
+ float *source_buf, int source_form, int source_scale,
+ float *result_buf, int result_form, int result_scale, int debug)
+
+/* modifies: result_buf
+ effects: Computes npnt FFT specified by form, scale, and dir parameters.
+ Source samples (single precision float) are taken from soure_buf and
+ the transfrmd representation is stored in result_buf (single precision
+ float). The parameters are defined as follows:
+
+ trnsfrm_dir = FORWARD | INVERSE
+ npnt = 2^k for some any positive integer k
+ window = HANNING | RECTANGULAR
+ (RECT = real and imag parts, POLAR = magnitude and phase)
+ source_form = REAL | IMAG | RECT | POLAR
+ result_form = REAL | IMAG | RECT | MAG | PHASE | POLAR
+ xxxxxx_scale= LINEAR | DB ( 20log10 |mag| )
+
+ The input/output buffers are stored in a form appropriate to the type.
+ For example: REAL => {real, real, real ...},
+ MAG => {mag, mag, mag, ... },
+ RECT => {real, imag, real, imag, ... },
+ POLAR => {mag, phase, mag, phase, ... }.
+
+ To look at the magnitude (in db) of a 1024 point FFT of a real time
+ signal we have:
+
+ fft(FORWARD, 1024, RECTANGULAR, input, REAL, LINEAR, output, MAG, DB)
+
+ All possible input and output combinations are possible given the
+ choice of type and scale parameters.
+*/
+
+{
+ FFT_NET *thisnet = (FFT_NET *)0;
+ FFT_NET *lastnet = (FFT_NET *)0;
+
+ /* A linked list of fft networks of different sizes is maintained to
+ avoid building with every call. The network is built on the first
+ call but reused for subsequent calls requesting the same size
+ transformation.
+ */
+
+ thisnet=firstnet;
+ while (thisnet) {
+ if (!(thisnet->n == npnt) || !(thisnet->window_type == window)) {
+ /* current net doesn't match size or window type */
+ lastnet=thisnet;
+ thisnet=thisnet->next;
+ continue; /* keep looking */
+ }
+
+ else { /* network matches desired size */
+ load_registers(thisnet, source_buf, source_form, source_scale,
+ trnsfrm_dir);
+ compute_fft(thisnet); /* do transformation */
+ store_registers(thisnet, result_buf, result_form, result_scale,debug);
+ return;
+ }
+ }
+
+ /* none of existing networks match required size*/
+
+ if (lastnet) { /* add new network to end of list */
+ thisnet = (FFT_NET *)malloc(sizeof(FFT_NET)); /* allocate */
+ thisnet->next = 0;
+ lastnet->next = thisnet; /* add to end of list */
+ }
+ else { /* first network to be created */
+ thisnet=firstnet=(FFT_NET *)malloc(sizeof(FFT_NET)); /* alloc. */
+ thisnet->next = 0;
+ }
+
+ /* build new network and compute transformation */
+ build_fft_network(thisnet, npnt, window);
+ load_registers(thisnet, source_buf, source_form, source_scale,
+ trnsfrm_dir);
+ compute_fft(thisnet);
+ store_registers(thisnet, result_buf, result_form, result_scale,debug);
+ return;
+}
+
+void fft_clear(void)
+
+/* effects: Deallocates all preserved FFT networks. Should be used when
+ finished with all computations.
+*/
+
+{
+ FFT_NET *thisnet, *nextnet;
+
+ if (firstnet) {
+ thisnet=firstnet;
+ do {
+ nextnet = thisnet->next;
+ net_dealloc(thisnet);
+ free((char *)thisnet);
+ } while (thisnet = nextnet);
+ }
+}
+
+
+/*****************************************************************************/
+/* NETWORK CONSTRUCTION */
+/*****************************************************************************/
+
+void build_fft_network(FFT_NET *fft_net, int n, int window_type)
+
+
+/* modifies:fft_net
+ effects: Constructs the fft network as described in fft.h. Butterfly
+ coefficients, read/write indicies, bit reversed load indicies,
+ and array allocations are computed.
+*/
+
+{
+ int cntr, i, j, s;
+ int stages, bps;
+ int **p, **q, *pp, *qp;
+ SAMPLE two_pi_div_n = TWO_PI / n;
+
+
+ /* network definition */
+ fft_net->n = n;
+ fft_net->bps = bps = n/2;
+ for (i = 0, j = n; j > 1; j >>= 1, i++);
+ fft_net->stages = stages = i;
+ fft_net->direction = FORWARD;
+ fft_net->window_type = window_type;
+ fft_net->next = (FFT_NET *)0;
+
+ /* allocate registers, index, coefficient arrays */
+ net_alloc(fft_net);
+
+
+ /* create appropriate windows */
+ if (window_type==HANNING) {
+ create_hanning(fft_net->window, n, 1.);
+ create_hanning(fft_net->inv_window, n, 1./n);
+ }
+ else {
+ create_rectangular(fft_net->window, n, 1.);
+ create_rectangular(fft_net->inv_window, n, 1./n);
+ }
+
+
+ /* calculate butterfly coefficients */ {
+
+ int num_diff_coeffs, power_inc, power;
+ SAMPLE *coeffpr = fft_net->coeffr;
+ SAMPLE *coeffpi = fft_net->coeffi;
+ SAMPLE *inv_coeffpr = fft_net->inv_coeffr;
+ SAMPLE *inv_coeffpi = fft_net->inv_coeffi;
+
+ /* stage one coeffs are 1 + 0j */
+ for (i = 0; i < bps; i++) {
+ *coeffpr = *inv_coeffpr = 1.;
+ *coeffpi = *inv_coeffpi = 0.;
+ coeffpr++; inv_coeffpr++;
+ coeffpi++; inv_coeffpi++;
+ }
+
+ /* stage 2 to last stage coeffs need calculation */
+ /* (1<<r <=> 2^r */
+ for (s = 2; s <= stages; s++) {
+
+ num_diff_coeffs = n / (1 << (stages - s + 1));
+ power_inc = 1 << (stages -s);
+ cntr = 0;
+
+ for (i = bps/num_diff_coeffs; i > 0; i--) {
+
+ power = 0;
+
+ for (j = num_diff_coeffs; j > 0; j--) {
+ *coeffpr = cos(two_pi_div_n*power);
+ *inv_coeffpr = cos(two_pi_div_n*power);
+/* AAA change these signs */ *coeffpi = -sin(two_pi_div_n*power);
+/* change back */ *inv_coeffpi = sin(two_pi_div_n*power);
+ power += power_inc;
+ coeffpr++; inv_coeffpr++;
+ coeffpi++; inv_coeffpi++;
+ }
+ }
+ }
+ }
+
+ /* calculate network indicies: stage exchange indicies are
+ calculated and then used as offset values from the base
+ register locations. The final addresses are then stored in
+ fft_net.
+ */ {
+
+ int index, inc;
+ SAMPLE **indexpr = fft_net->indexpr;
+ SAMPLE **indexpi = fft_net->indexpi;
+ SAMPLE **indexqr = fft_net->indexqr;
+ SAMPLE **indexqi = fft_net->indexqi;
+ SAMPLE *regr = fft_net->regr;
+ SAMPLE *regi = fft_net->regi;
+
+
+ /* allocate temporary 2d stage exchange index, 1d temp
+ load index */
+ p = (int **)malloc(stages * PNTR_SIZE);
+ q = (int **)malloc(stages * PNTR_SIZE);
+
+ for (s = 0; s < stages; s++) {
+ p[s] = (int *)malloc(bps * INT_SIZE);
+ q[s] = (int *)malloc(bps * INT_SIZE);
+ }
+
+ /* calculate stage exchange indicies: */
+ for (s = 0; s < stages; s++) {
+ pp = p[s];
+ qp = q[s];
+ inc = 1 << s;
+ cntr = 1 << (stages-s-1);
+ i = j = index = 0;
+
+ do {
+ do {
+ qp[i] = index + inc;
+ pp[i++] = index++;
+ } while (++j < inc);
+ index = qp[i-1] + 1;
+ j = 0;
+ } while (--cntr);
+ }
+
+ /* compute actual address values using indicies as offsets */
+ for (s = 0; s < stages; s++) {
+ for (i = 0; i < bps; i++) {
+ *indexpr++ = regr + p[s][i];
+ *indexpi++ = regi + p[s][i];
+ *indexqr++ = regr + q[s][i];
+ *indexqi++ = regi + q[s][i];
+ }
+ }
+ }
+
+
+ /* calculate load indicies (bit reverse ordering) */
+ /* bit reverse ordering achieved by passing normal
+ order indicies backwards through the network */
+
+ /* init to normal order indicies */ {
+ int *load_index,*load_indexp;
+ int *temp_indexp, *temp_index;
+ temp_index=temp_indexp=(int *)malloc(n * INT_SIZE);
+
+ i = 0; j = n;
+ load_index = load_indexp = fft_net->load_index;
+
+ while (j--)
+ *load_indexp++ = i++;
+
+ /* pass indicies backwards through net */
+ for (s = stages - 1; s > 0; s--) {
+ pp = p[s];
+ qp = q[s];
+
+ for (i = 0; i < bps; i++) {
+ temp_index[pp[i]]=load_index[2*i];
+ temp_index[qp[i]]=load_index[2*i+1];
+ }
+ j = n;
+ load_indexp = load_index;
+ temp_indexp = temp_index;
+ while (j--)
+ *load_indexp++ = *temp_indexp++;
+ }
+
+ /* free all temporary arrays */
+ free((char *)temp_index);
+ for (s = 0; s < stages; s++) {
+ free((char *)p[s]);free((char *)q[s]);
+ }
+ free((char *)p);free((char *)q);
+ }
+}
+
+
+
+/*****************************************************************************/
+/* REGISTER LOAD AND STORE */
+/*****************************************************************************/
+
+void load_registers(FFT_NET *fft_net, float *buf, int buf_form,
+ int buf_scale, int trnsfrm_dir)
+
+/* effects: Multiplies the input buffer with the appropriate window and
+ stores the resulting values in the initial registers of the
+ network. Input buffer must contain values appropriate to form.
+ For RECT, the buffer contains real num. followed by imag num,
+ and for POLAR, it contains magnitude followed by phase. Pure
+ inputs are listed normally. Both LINEAR and DB scales are
+ interpreted.
+*/
+
+{
+ int *load_index = fft_net->load_index;
+ SAMPLE *window;
+ int index, i = 0, n = fft_net->n;
+
+ if (trnsfrm_dir==FORWARD) window = fft_net->window;
+ else if (trnsfrm_dir==INVERSE) window = fft_net->inv_window;
+ else {
+ fprintf(stderr, "load_registers:illegal transform direction\n");
+ exit(0);
+ }
+ fft_net->direction = trnsfrm_dir;
+
+ switch(buf_scale) {
+ case LINEAR: {
+
+ switch (buf_form) {
+ case REAL: { /* pure REAL */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)buf[index] * window[index];
+ fft_net->regi[i]=0.;
+ i++;
+ }
+ } break;
+
+ case IMAG: { /* pure IMAGinary */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=0;
+ fft_net->regi[i]=(SAMPLE)buf[index] * window[index];
+ i++;
+ }
+ } break;
+
+ case RECT: { /* both REAL and IMAGinary */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)buf[index*2] * window[index];
+ fft_net->regi[i]=(SAMPLE)buf[index*2+1] * window[index];
+ i++;
+ }
+ } break;
+
+ case POLAR: { /* magnitude followed by phase */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)(buf[index*2] * cos(buf[index*2+1]))
+ * window[index];
+ fft_net->regi[i]=(SAMPLE)(buf[index*2] * sin(buf[index*2+1]))
+ * window[index];
+ i++;
+ }
+ } break;
+
+ default: {
+ fprintf(stderr, "load_registers:illegal input form\n");
+ exit(0);
+ } break;
+ }
+ } break;
+
+ case DB: {
+
+ switch (buf_form) {
+ case REAL: { /* log pure REAL */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)pow(10., (1./20.)*buf[index])
+ * window[index]; /* window scaling after linearization */
+ fft_net->regi[i]=0.;
+ i++;
+ }
+ } break;
+
+ case IMAG: { /* log pure IMAGinary */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=0.;
+ fft_net->regi[i]=(SAMPLE)pow(10., (1./20.)*buf[index])
+ * window[index];
+ i++;
+ }
+ } break;
+
+ case RECT: { /* log REAL and log IMAGinary */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)pow(10., (1./20.)*buf[index*2])
+ * window[index];
+ fft_net->regi[i]=(SAMPLE)pow(10., (1./20.)*buf[index*2+1])
+ * window[index];
+ i++;
+ }
+ } break;
+
+ case POLAR: { /* log mag followed by phase */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)(pow(10., (1./20.)*buf[index*2])
+ * cos(buf[index*2+1])) * window[index];
+ fft_net->regi[i]=(SAMPLE)(pow(10., (1./20.)*buf[index*2])
+ * sin(buf[index*2+1])) * window[index];
+ i++;
+ }
+ } break;
+
+ default: {
+ fprintf(stderr, "load_registers:illegal input form\n");
+ exit(0);
+ } break;
+ }
+ } break;
+
+ default: {
+ fprintf(stderr, "load_registers:illegal input scale\n");
+ exit(0);
+ } break;
+ }
+}
+
+
+void store_registers(FFT_NET *fft_net, float *buf, int buf_form,
+ int buf_scale, int debug)
+
+/* modifies: buf
+ effects: Writes the final contents of the network registers into buf in
+ either linear or db scale, polar or rectangular form. If any of
+ the pure forms(REAL, IMAG, MAG, or PHASE) are used then only the
+ corresponding part of the registers is stored in buf.
+*/
+
+{
+ int i;
+ SAMPLE real, imag, mag, phase;
+ int n;
+
+ i = 0;
+ n = fft_net->n;
+
+ switch (buf_scale) {
+ case LINEAR: {
+
+ switch (buf_form) {
+ case REAL: { /* pure REAL */
+ do {
+ *buf++ = (float)fft_net->regr[i];
+ } while (++i < n);
+ } break;
+
+ case IMAG: { /* pure IMAGinary */
+ do {
+ *buf++ = (float)fft_net->regi[i];
+ } while (++i < n);
+ } break;
+
+ case RECT: { /* both REAL and IMAGinary */
+ do {
+ *buf++ = (float)fft_net->regr[i];
+ *buf++ = (float)fft_net->regi[i];
+ } while (++i < n);
+ } break;
+
+ case MAG: { /* magnitude only */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ *buf++ = (float)sqrt(real*real+imag*imag);
+ } while (++i < n);
+ } break;
+
+ case PHASE: { /* phase only */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ if (real > .00001)
+ *buf++ = (float)atan2(imag, real);
+ else { /* deal with bad case */
+ if (imag > 0){ *buf++ = PI / 2.;
+ if(debug) fprintf(stderr,"real=0 and imag > 0\n");}
+ else if (imag < 0){ *buf++ = -PI / 2.;
+ if(debug) fprintf(stderr,"real=0 and imag < 0\n");}
+ else { *buf++ = 0;
+ if(debug) fprintf(stderr,"real=0 and imag=0\n");}
+ }
+ } while (++i < n);
+ } break;
+
+ case POLAR: { /* magnitude and phase */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ *buf++ = (float)sqrt(real*real+imag*imag);
+ if (real) /* a hack to avoid div by zero */
+ *buf++ = (float)atan2(imag, real);
+ else { /* deal with bad case */
+ if (imag > 0) *buf++ = PI / 2.;
+ else if (imag < 0) *buf++ = -PI / 2.;
+ else *buf++ = 0;
+ }
+ } while (++i < n);
+ } break;
+
+ default: {
+ fprintf(stderr, "store_registers:illegal output form\n");
+ exit(0);
+ } break;
+ }
+ } break;
+
+ case DB: {
+
+ switch (buf_form) {
+ case REAL: { /* real only */
+ do {
+ *buf++ = (float)20.*log10(fft_net->regr[i]);
+ } while (++i < n);
+ } break;
+
+ case IMAG: { /* imag only */
+ do {
+ *buf++ = (float)20.*log10(fft_net->regi[i]);
+ } while (++i < n);
+ } break;
+
+ case RECT: { /* real and imag */
+ do {
+ *buf++ = (float)20.*log10(fft_net->regr[i]);
+ *buf++ = (float)20.*log10(fft_net->regi[i]);
+ } while (++i < n);
+ } break;
+
+ case MAG: { /* magnitude only */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ *buf++ = (float)20.*log10(sqrt(real*real+imag*imag));
+ } while (++i < n);
+ } break;
+
+ case PHASE: { /* phase only */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ if (real)
+ *buf++ = (float)atan2(imag, real);
+ else { /* deal with bad case */
+ if (imag > 0) *buf++ = PI / 2.;
+ else if (imag < 0) *buf++ = -PI / 2.;
+ else *buf++ = 0;
+ }
+ } while (++i < n);
+ } break;
+
+ case POLAR: { /* magnitude and phase */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ *buf++ = (float)20.*log10(sqrt(real*real+imag*imag));
+ if (real)
+ *buf++ = (float)atan2(imag, real);
+ else { /* deal with bad case */
+ if (imag > 0) *buf++ = PI / 2.;
+ else if (imag < 0) *buf++ = -PI / 2.;
+ else *buf++ = 0;
+ }
+ } while (++i < n);
+ } break;
+
+ default: {
+ fprintf(stderr, "store_registers:illegal output form\n");
+ exit(0);
+ } break;
+ }
+ } break;
+
+ default: {
+ fprintf(stderr, "store_registers:illegal output scale\n");
+ exit(0);
+ } break;
+ }
+}
+
+
+
+/*****************************************************************************/
+/* COMPUTE TRANSFORMATION */
+/*****************************************************************************/
+
+void compute_fft(FFT_NET *fft_net)
+
+
+/* modifies: fft_net
+ effects: Passes the values (already loaded) in the registers through
+ the network, multiplying with appropriate coefficients at each
+ stage. The fft result will be in the registers at the end of
+ the computation. The direction of the transformation is indicated
+ by the network flag 'direction'. The form of the computation is:
+
+ X(pn) = X(p) + C*X(q)
+ X(qn) = X(p) - C*X(q)
+
+ where X(pn,qn) represents the output of the registers at each stage.
+ The calculations are actually done in place. Register pointers are
+ used to speed up the calculations.
+
+ Register and coefficient addresses involved in the calculations
+ are stored sequentially and are accessed as such. fft_net->indexp,
+ indexq contain pointers to the relevant addresses, and fft_net->coeffs,
+ inv_coeffs points to the appropriate coefficients at each stage of the
+ computation.
+*/
+
+{
+ SAMPLE **xpr, **xpi, **xqr, **xqi, *cr, *ci;
+ int i;
+ SAMPLE tpr, tpi, tqr, tqi;
+ int bps = fft_net->bps;
+ int cnt = bps * (fft_net->stages - 1);
+
+ /* predetermined register addresses and coefficients */
+ xpr = fft_net->indexpr;
+ xpi = fft_net->indexpi;
+ xqr = fft_net->indexqr;
+ xqi = fft_net->indexqi;
+
+ if (fft_net->direction==FORWARD) { /* FORWARD FFT coefficients */
+ cr = fft_net->coeffr;
+ ci = fft_net->coeffi;
+ }
+ else { /* INVERSE FFT coefficients */
+ cr = fft_net->inv_coeffr;
+ ci = fft_net->inv_coeffi;
+ }
+
+ /* stage one coefficients are 1 + 0j so C*X(q)=X(q) */
+ /* bps mults can be avoided */
+
+ for (i = 0; i < bps; i++) {
+
+ /* add X(p) and X(q) */
+ tpr = **xpr + **xqr;
+ tpi = **xpi + **xqi;
+ tqr = **xpr - **xqr;
+ tqi = **xpi - **xqi;
+
+ /* exchange register with temp */
+ **xpr = tpr;
+ **xpi = tpi;
+ **xqr = tqr;
+ **xqi = tqi;
+
+ /* next set of register for calculations: */
+ xpr++; xpi++; xqr++; xqi++; cr++; ci++;
+
+ }
+
+ for (i = 0; i < cnt; i++) {
+
+ /* mult X(q) by coeff C */
+ tqr = **xqr * *cr - **xqi * *ci;
+ tqi = **xqr * *ci + **xqi * *cr;
+
+ /* exchange register with temp */
+ **xqr = tqr;
+ **xqi = tqi;
+
+ /* add X(p) and X(q) */
+ tpr = **xpr + **xqr;
+ tpi = **xpi + **xqi;
+ tqr = **xpr - **xqr;
+ tqi = **xpi - **xqi;
+
+ /* exchange register with temp */
+ **xpr = tpr;
+ **xpi = tpi;
+ **xqr = tqr;
+ **xqi = tqi;
+ /* next set of register for calculations: */
+ xpr++; xpi++; xqr++; xqi++; cr++; ci++;
+ }
+}
+
+
+/****************************************************************************/
+/* SUPPORT MODULES */
+/****************************************************************************/
+
+void net_alloc(FFT_NET *fft_net)
+
+
+/* effects: Allocates appropriate two dimensional arrays and assigns
+ correct internal pointers.
+*/
+
+{
+
+ int stages, bps, n;
+
+ n = fft_net->n;
+ stages = fft_net->stages;
+ bps = fft_net->bps;
+
+
+ /* two dimensional arrays with elements stored sequentially */
+
+ fft_net->load_index = (int *)malloc(n * INT_SIZE);
+ fft_net->regr = (SAMPLE *)malloc(n * SAMPLE_SIZE);
+ fft_net->regi = (SAMPLE *)malloc(n * SAMPLE_SIZE);
+ fft_net->coeffr = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
+ fft_net->coeffi = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
+ fft_net->inv_coeffr = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
+ fft_net->inv_coeffi = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
+ fft_net->indexpr = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
+ fft_net->indexpi = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
+ fft_net->indexqr = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
+ fft_net->indexqi = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
+
+ /* one dimensional load window */
+ fft_net->window = (SAMPLE *)malloc(n * SAMPLE_SIZE);
+ fft_net->inv_window = (SAMPLE *)malloc(n * SAMPLE_SIZE);
+}
+
+void net_dealloc(FFT_NET *fft_net)
+
+
+/* effects: Deallocates given FFT network.
+*/
+
+{
+
+ free((char *)fft_net->load_index);
+ free((char *)fft_net->regr);
+ free((char *)fft_net->regi);
+ free((char *)fft_net->coeffr);
+ free((char *)fft_net->coeffi);
+ free((char *)fft_net->inv_coeffr);
+ free((char *)fft_net->inv_coeffi);
+ free((char *)fft_net->indexpr);
+ free((char *)fft_net->indexpi);
+ free((char *)fft_net->indexqr);
+ free((char *)fft_net->indexqi);
+ free((char *)fft_net->window);
+ free((char *)fft_net->inv_window);
+}
+
+
+BOOL power_of_two(n)
+
+int n;
+
+/* effects: Returns TRUE if n is a power of two, otherwise FALSE.
+*/
+
+{
+ int i;
+
+ for (i = n; i > 1; i >>= 1)
+ if (i & 1) return FALSE; /* more than one bit high */
+ return TRUE;
+}
+
+
+void create_hanning(SAMPLE *window, int n, SAMPLE scale)
+
+/* effects: Fills the buffer window with a hanning window of the appropriate
+ size scaled by scale.
+*/
+
+{
+ SAMPLE a, pi_div_n = PI/n;
+ int k;
+
+ for (k=1; k <= n; k++) {
+ a = sin(k * pi_div_n);
+ *window++ = scale * a * a;
+ }
+}
+
+
+void create_rectangular(SAMPLE *window, int n, SAMPLE scale)
+
+/* effects: Fills the buffer window with a rectangular window of the
+ appropriate size of height scale.
+*/
+
+{
+ while (n--)
+ *window++ = scale;
+}
+
+
+void short_to_float(short *short_buf, float *float_buf, int n)
+
+/* effects; Converts short_buf to floats and stores them in float_buf.
+*/
+
+{
+ while (n--) {
+ *float_buf++ = (float)*short_buf++;
+ }
+}
+
+
+/* here's the meat: */
+
+void pd_fft(float *buf, int npoints, int inverse)
+{
+ double renorm;
+ float *fp, *fp2;
+ int i;
+ renorm = (inverse ? npoints : 1.);
+ cfft((inverse ? INVERSE : FORWARD), npoints, RECTANGULAR,
+ buf, RECT, LINEAR, buf, RECT, LINEAR, 0);
+ for (i = npoints << 1, fp = buf; i--; fp++) *fp *= renorm;
+}
diff --git a/pd/src/d_filter.c b/pd/src/d_filter.c
new file mode 100644
index 00000000..1693cd85
--- /dev/null
+++ b/pd/src/d_filter.c
@@ -0,0 +1,534 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* "filters", both linear and nonlinear.
+*/
+
+#include "m_pd.h"
+#include <math.h>
+
+/* ---------------- hip~ - 1-pole 1-zero hipass filter. ----------------- */
+
+typedef struct hipctl
+{
+ float c_x;
+ float c_coef;
+} t_hipctl;
+
+typedef struct sighip
+{
+ t_object x_obj;
+ float x_sr;
+ float x_hz;
+ t_hipctl x_cspace;
+ t_hipctl *x_ctl;
+ float x_f;
+} t_sighip;
+
+t_class *sighip_class;
+static void sighip_ft1(t_sighip *x, t_floatarg f);
+
+static void *sighip_new(t_floatarg f)
+{
+ t_sighip *x = (t_sighip *)pd_new(sighip_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_sr = 44100;
+ x->x_ctl = &x->x_cspace;
+ x->x_cspace.c_x = 0;
+ sighip_ft1(x, f);
+ x->x_f = 0;
+ return (x);
+}
+
+static void sighip_ft1(t_sighip *x, t_floatarg f)
+{
+ if (f < 0.001) f = 10;
+ x->x_hz = f;
+ x->x_ctl->c_coef = 1 - f * (2 * 3.14159) / x->x_sr;
+ if (x->x_ctl->c_coef < 0) x->x_ctl->c_coef = 0;
+}
+
+static t_int *sighip_perform(t_int *w)
+{
+ float *in = (float *)(w[1]);
+ float *out = (float *)(w[2]);
+ t_hipctl *c = (t_hipctl *)(w[3]);
+ int n = (t_int)(w[4]);
+ int i;
+ float last = c->c_x;
+ float coef = c->c_coef;
+ for (i = 0; i < n; i++)
+ {
+ float new = *in++ + coef * last;
+ *out++ = new - last;
+ last = new;
+ }
+ /* NAN protect */
+ if (!((last <= 0) || (last >= 0)))
+ last = 0;
+ c->c_x = last;
+ return (w+5);
+}
+
+static void sighip_dsp(t_sighip *x, t_signal **sp)
+{
+ x->x_sr = sp[0]->s_sr;
+ sighip_ft1(x, x->x_hz);
+ dsp_add(sighip_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec,
+ x->x_ctl, sp[0]->s_n);
+
+}
+
+static void sighip_clear(t_sighip *x, t_floatarg q)
+{
+ x->x_cspace.c_x = 0;
+}
+
+void sighip_setup(void)
+{
+ sighip_class = class_new(gensym("hip~"), (t_newmethod)sighip_new, 0,
+ sizeof(t_sighip), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(sighip_class, t_sighip, x_f);
+ class_addmethod(sighip_class, (t_method)sighip_dsp, gensym("dsp"), 0);
+ class_addmethod(sighip_class, (t_method)sighip_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(sighip_class, (t_method)sighip_clear, gensym("clear"), 0);
+}
+
+/* ---------------- lop~ - 1-pole lopass filter. ----------------- */
+
+typedef struct lopctl
+{
+ float c_x;
+ float c_coef;
+} t_lopctl;
+
+typedef struct siglop
+{
+ t_object x_obj;
+ float x_sr;
+ float x_hz;
+ t_lopctl x_cspace;
+ t_lopctl *x_ctl;
+ float x_f;
+} t_siglop;
+
+t_class *siglop_class;
+
+static void siglop_ft1(t_siglop *x, t_floatarg f);
+
+static void *siglop_new(t_floatarg f)
+{
+ t_siglop *x = (t_siglop *)pd_new(siglop_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_sr = 44100;
+ x->x_ctl = &x->x_cspace;
+ x->x_cspace.c_x = 0;
+ siglop_ft1(x, f);
+ x->x_f = 0;
+ return (x);
+}
+
+static void siglop_ft1(t_siglop *x, t_floatarg f)
+{
+ if (f < 0.001) f = 10;
+ x->x_hz = f;
+ x->x_ctl->c_coef = f * (2 * 3.14159) / x->x_sr;
+ if (x->x_ctl->c_coef > 1) x->x_ctl->c_coef = 1;
+}
+
+static void siglop_clear(t_siglop *x, t_floatarg q)
+{
+ x->x_cspace.c_x = 0;
+}
+
+static t_int *siglop_perform(t_int *w)
+{
+ float *in = (float *)(w[1]);
+ float *out = (float *)(w[2]);
+ t_lopctl *c = (t_lopctl *)(w[3]);
+ int n = (t_int)(w[4]);
+ int i;
+ float last = c->c_x;
+ float coef = c->c_coef;
+ float feedback = 1 - coef;
+ for (i = 0; i < n; i++)
+ last = *out++ = coef * *in++ + feedback * last;
+ /* NAN protect */
+ if (!((last <= 0) || (last >= 0)))
+ last = 0;
+ c->c_x = last;
+ return (w+5);
+}
+
+static void siglop_dsp(t_siglop *x, t_signal **sp)
+{
+ x->x_sr = sp[0]->s_sr;
+ siglop_ft1(x, x->x_hz);
+ dsp_add(siglop_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec,
+ x->x_ctl, sp[0]->s_n);
+
+}
+
+void siglop_setup(void)
+{
+ siglop_class = class_new(gensym("lop~"), (t_newmethod)siglop_new, 0,
+ sizeof(t_siglop), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(siglop_class, t_siglop, x_f);
+ class_addmethod(siglop_class, (t_method)siglop_dsp, gensym("dsp"), 0);
+ class_addmethod(siglop_class, (t_method)siglop_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(siglop_class, (t_method)siglop_clear, gensym("clear"), 0);
+}
+
+/* ---------------- bp~ - 2-pole bandpass filter. ----------------- */
+
+typedef struct bpctl
+{
+ float c_x1;
+ float c_x2;
+ float c_coef1;
+ float c_coef2;
+ float c_gain;
+} t_bpctl;
+
+typedef struct sigbp
+{
+ t_object x_obj;
+ float x_sr;
+ float x_freq;
+ float x_q;
+ t_bpctl x_cspace;
+ t_bpctl *x_ctl;
+ float x_f;
+} t_sigbp;
+
+t_class *sigbp_class;
+
+static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q);
+
+static void *sigbp_new(t_floatarg f, t_floatarg q)
+{
+ t_sigbp *x = (t_sigbp *)pd_new(sigbp_class);
+ 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"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_sr = 44100;
+ x->x_ctl = &x->x_cspace;
+ x->x_cspace.c_x1 = 0;
+ x->x_cspace.c_x2 = 0;
+ sigbp_docoef(x, f, q);
+ x->x_f = 0;
+ return (x);
+}
+
+static float sigbp_qcos(float f)
+{
+ if (f >= -(0.5f*3.14159f) && f <= 0.5f*3.14159f)
+ {
+ float g = f*f;
+ return (((g*g*g * (-1.0f/720.0f) + g*g*(1.0f/24.0f)) - g*0.5) + 1);
+ }
+ else return (0);
+}
+
+static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q)
+{
+ float r, oneminusr, omega;
+ if (f < 0.001) f = 10;
+ if (q < 0) q = 0;
+ x->x_freq = f;
+ x->x_q = q;
+ omega = f * (2.0f * 3.14159f) / x->x_sr;
+ if (q < 0.001) oneminusr = 1.0f;
+ else oneminusr = omega/q;
+ if (oneminusr > 1.0f) oneminusr = 1.0f;
+ r = 1.0f - oneminusr;
+ x->x_ctl->c_coef1 = 2.0f * sigbp_qcos(omega) * r;
+ x->x_ctl->c_coef2 = - r * r;
+ x->x_ctl->c_gain = 2 * oneminusr * (oneminusr + r * omega);
+ /* post("r %f, omega %f, coef1 %f, coef2 %f",
+ r, omega, x->x_ctl->c_coef1, x->x_ctl->c_coef2); */
+}
+
+static void sigbp_ft1(t_sigbp *x, t_floatarg f)
+{
+ sigbp_docoef(x, f, x->x_q);
+}
+
+static void sigbp_ft2(t_sigbp *x, t_floatarg q)
+{
+ sigbp_docoef(x, x->x_freq, q);
+}
+
+static void sigbp_clear(t_sigbp *x, t_floatarg q)
+{
+ x->x_ctl->c_x1 = x->x_ctl->c_x2 = 0;
+}
+
+static t_int *sigbp_perform(t_int *w)
+{
+ float *in = (float *)(w[1]);
+ float *out = (float *)(w[2]);
+ t_bpctl *c = (t_bpctl *)(w[3]);
+ int n = (t_int)(w[4]);
+ int i;
+ float last = c->c_x1;
+ float prev = c->c_x2;
+ float coef1 = c->c_coef1;
+ float coef2 = c->c_coef2;
+ float gain = c->c_gain;
+ for (i = 0; i < n; i++)
+ {
+ float output = *in++ + coef1 * last + coef2 * prev;
+ *out++ = gain * output;
+ prev = last;
+ last = output;
+ }
+ /* NAN protect */
+ if (!((last <= 0) || (last >= 0)))
+ last = 0;
+ if (!((prev <= 0) || (prev >= 0)))
+ prev = 0;
+ c->c_x1 = last;
+ c->c_x2 = prev;
+ return (w+5);
+}
+
+static void sigbp_dsp(t_sigbp *x, t_signal **sp)
+{
+ x->x_sr = sp[0]->s_sr;
+ sigbp_docoef(x, x->x_freq, x->x_q);
+ dsp_add(sigbp_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec,
+ x->x_ctl, sp[0]->s_n);
+
+}
+
+void sigbp_setup(void)
+{
+ sigbp_class = class_new(gensym("bp~"), (t_newmethod)sigbp_new, 0,
+ sizeof(t_sigbp), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(sigbp_class, t_sigbp, x_f);
+ class_addmethod(sigbp_class, (t_method)sigbp_dsp, gensym("dsp"), 0);
+ class_addmethod(sigbp_class, (t_method)sigbp_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(sigbp_class, (t_method)sigbp_ft2,
+ gensym("ft2"), A_FLOAT, 0);
+ class_addmethod(sigbp_class, (t_method)sigbp_clear, gensym("clear"), 0);
+}
+
+/* ---------------- biquad~ - raw biquad filter ----------------- */
+
+typedef struct biquadctl
+{
+ float c_x1;
+ float c_x2;
+ float c_fb1;
+ float c_fb2;
+ float c_ff1;
+ float c_ff2;
+ float c_ff3;
+} t_biquadctl;
+
+typedef struct sigbiquad
+{
+ t_object x_obj;
+ float x_f;
+ t_biquadctl x_cspace;
+ t_biquadctl *x_ctl;
+} t_sigbiquad;
+
+t_class *sigbiquad_class;
+
+static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv);
+
+static void *sigbiquad_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_sigbiquad *x = (t_sigbiquad *)pd_new(sigbiquad_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_ctl = &x->x_cspace;
+ x->x_cspace.c_x1 = x->x_cspace.c_x2 = 0;
+ sigbiquad_list(x, s, argc, argv);
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigbiquad_perform(t_int *w)
+{
+ float *in = (float *)(w[1]);
+ float *out = (float *)(w[2]);
+ t_biquadctl *c = (t_biquadctl *)(w[3]);
+ int n = (t_int)(w[4]);
+ int i;
+ float last = c->c_x1;
+ float prev = c->c_x2;
+ float fb1 = c->c_fb1;
+ float fb2 = c->c_fb2;
+ float ff1 = c->c_ff1;
+ float ff2 = c->c_ff2;
+ float ff3 = c->c_ff3;
+ for (i = 0; i < n; i++)
+ {
+ float output = *in++ + fb1 * last + fb2 * prev;
+ *out++ = ff1 * output + ff2 * last + ff3 * prev;
+ prev = last;
+ last = output;
+ }
+ c->c_x1 = last;
+ c->c_x2 = prev;
+ return (w+5);
+}
+
+static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv)
+{
+ float fb1 = atom_getfloatarg(0, argc, argv);
+ float fb2 = atom_getfloatarg(1, argc, argv);
+ float ff1 = atom_getfloatarg(2, argc, argv);
+ float ff2 = atom_getfloatarg(3, argc, argv);
+ float ff3 = atom_getfloatarg(4, argc, argv);
+ float discriminant = fb1 * fb1 + 4 * fb2;
+ t_biquadctl *c = x->x_ctl;
+ if (discriminant < 0) /* imaginary roots -- resonant filter */
+ {
+ /* they're conjugates so we just check that the product
+ is less than one */
+ if (fb2 >= -1.0f) goto stable;
+ }
+ else /* real roots */
+ {
+ /* check that the parabola 1 - fb1 x - fb2 x^2 has a
+ vertex between -1 and 1, and that it's nonnegative
+ at both ends, which implies both roots are in [1-,1]. */
+ if (fb1 <= 2.0f && fb1 >= -2.0f &&
+ 1.0f - fb1 -fb2 >= 0 && 1.0f + fb1 - fb2 >= 0)
+ goto stable;
+ }
+ /* if unstable, just bash to zero */
+ fb1 = fb2 = ff1 = ff2 = ff3 = 0;
+stable:
+ c->c_fb1 = fb1;
+ c->c_fb2 = fb2;
+ c->c_ff1 = ff1;
+ c->c_ff2 = ff2;
+ c->c_ff3 = ff3;
+}
+
+static void sigbiquad_set(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_biquadctl *c = x->x_ctl;
+ c->c_x1 = atom_getfloatarg(0, argc, argv);
+ c->c_x2 = atom_getfloatarg(1, argc, argv);
+}
+
+static void sigbiquad_dsp(t_sigbiquad *x, t_signal **sp)
+{
+ dsp_add(sigbiquad_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec,
+ x->x_ctl, sp[0]->s_n);
+
+}
+
+void sigbiquad_setup(void)
+{
+ sigbiquad_class = class_new(gensym("biquad~"), (t_newmethod)sigbiquad_new,
+ 0, sizeof(t_sigbiquad), 0, A_GIMME, 0);
+ CLASS_MAINSIGNALIN(sigbiquad_class, t_sigbiquad, x_f);
+ class_addmethod(sigbiquad_class, (t_method)sigbiquad_dsp, gensym("dsp"), 0);
+ class_addlist(sigbiquad_class, sigbiquad_list);
+ class_addmethod(sigbiquad_class, (t_method)sigbiquad_set, gensym("set"),
+ A_GIMME, 0);
+ class_addmethod(sigbiquad_class, (t_method)sigbiquad_set, gensym("clear"),
+ A_GIMME, 0);
+}
+
+/* ---------------- samphold~ - sample and hold ----------------- */
+
+typedef struct sigsamphold
+{
+ t_object x_obj;
+ float x_f;
+ float x_lastin;
+ float x_lastout;
+} t_sigsamphold;
+
+t_class *sigsamphold_class;
+
+static void *sigsamphold_new(void)
+{
+ t_sigsamphold *x = (t_sigsamphold *)pd_new(sigsamphold_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_lastin = 0;
+ x->x_lastout = 0;
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigsamphold_perform(t_int *w)
+{
+ float *in1 = (float *)(w[1]);
+ float *in2 = (float *)(w[2]);
+ float *out = (float *)(w[3]);
+ t_sigsamphold *x = (t_sigsamphold *)(w[4]);
+ int n = (t_int)(w[5]);
+ int i;
+ float lastin = x->x_lastin;
+ float lastout = x->x_lastout;
+ for (i = 0; i < n; i++, *in1++)
+ {
+ float next = *in2++;
+ if (next < lastin) lastout = *in1;
+ *out++ = lastout;
+ lastin = next;
+ }
+ x->x_lastin = lastin;
+ x->x_lastout = lastout;
+ return (w+6);
+}
+
+static void sigsamphold_dsp(t_sigsamphold *x, t_signal **sp)
+{
+ dsp_add(sigsamphold_perform, 5,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,
+ x, sp[0]->s_n);
+}
+
+static void sigsamphold_reset(t_sigsamphold *x)
+{
+ x->x_lastin = 1e20;
+}
+
+static void sigsamphold_set(t_sigsamphold *x, t_float f)
+{
+ x->x_lastout = f;
+}
+
+void sigsamphold_setup(void)
+{
+ sigsamphold_class = class_new(gensym("samphold~"),
+ (t_newmethod)sigsamphold_new, 0, sizeof(t_sigsamphold), 0, 0);
+ CLASS_MAINSIGNALIN(sigsamphold_class, t_sigsamphold, x_f);
+ class_addmethod(sigsamphold_class, (t_method)sigsamphold_set,
+ gensym("set"), A_FLOAT, 0);
+ class_addmethod(sigsamphold_class, (t_method)sigsamphold_reset,
+ gensym("reset"), 0);
+ class_addmethod(sigsamphold_class, (t_method)sigsamphold_dsp,
+ gensym("dsp"), 0);
+}
+
+/* ------------------------ setup routine ------------------------- */
+
+void d_filter_setup(void)
+{
+ sighip_setup();
+ siglop_setup();
+ sigbp_setup();
+ sigbiquad_setup();
+ sigsamphold_setup();
+}
diff --git a/pd/src/d_global.c b/pd/src/d_global.c
new file mode 100644
index 00000000..633eba1c
--- /dev/null
+++ b/pd/src/d_global.c
@@ -0,0 +1,312 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* send~, receive~, throw~, catch~ */
+
+#include "m_pd.h"
+#include <string.h>
+
+#define DEFSENDVS 64 /* LATER get send to get this from canvas */
+
+/* ----------------------------- send~ ----------------------------- */
+static t_class *sigsend_class;
+
+typedef struct _sigsend
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+ int x_n;
+ float *x_vec;
+ float x_f;
+} t_sigsend;
+
+static void *sigsend_new(t_symbol *s)
+{
+ t_sigsend *x = (t_sigsend *)pd_new(sigsend_class);
+ pd_bind(&x->x_obj.ob_pd, s);
+ x->x_sym = s;
+ x->x_n = DEFSENDVS;
+ x->x_vec = (float *)getbytes(DEFSENDVS * sizeof(float));
+ memset((char *)(x->x_vec), 0, DEFSENDVS * sizeof(float));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigsend_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ while (n--)
+ {
+ float f = *in++;
+ /* bash NANs and underflow/overflow hazards to zero */
+ if (!((f > 1.0e-20f && f < 1.0e20f) || (f < -1e-20f && f > -1e20)))
+ f = 0;
+ *out++ = f;
+ }
+ return (w+4);
+}
+
+static void sigsend_dsp(t_sigsend *x, t_signal **sp)
+{
+ if (x->x_n == sp[0]->s_n)
+ dsp_add(sigsend_perform, 3, sp[0]->s_vec, x->x_vec, sp[0]->s_n);
+ else error("sigsend %s: unexpected vector size", x->x_sym->s_name);
+}
+
+static void sigsend_free(t_sigsend *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, x->x_sym);
+ freebytes(x->x_vec, x->x_n * sizeof(float));
+}
+
+static void sigsend_setup(void)
+{
+ sigsend_class = class_new(gensym("send~"), (t_newmethod)sigsend_new,
+ (t_method)sigsend_free, sizeof(t_sigsend), 0, A_DEFSYM, 0);
+ class_addcreator((t_newmethod)sigsend_new, gensym("s~"), A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(sigsend_class, t_sigsend, x_f);
+ class_addmethod(sigsend_class, (t_method)sigsend_dsp, gensym("dsp"), 0);
+}
+
+/* ----------------------------- receive~ ----------------------------- */
+static t_class *sigreceive_class;
+
+typedef struct _sigreceive
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+ t_float *x_wherefrom;
+ int x_n;
+} t_sigreceive;
+
+static void *sigreceive_new(t_symbol *s)
+{
+ t_sigreceive *x = (t_sigreceive *)pd_new(sigreceive_class);
+ x->x_n = DEFSENDVS; /* LATER find our vector size correctly */
+ x->x_sym = s;
+ x->x_wherefrom = 0;
+ outlet_new(&x->x_obj, &s_signal);
+ return (x);
+}
+
+static t_int *sigreceive_perform(t_int *w)
+{
+ t_sigreceive *x = (t_sigreceive *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ t_float *in = x->x_wherefrom;
+ if (in)
+ {
+ while (n--)
+ *out++ = *in++;
+ }
+ else
+ {
+ while (n--)
+ *out++ = 0;
+ }
+ return (w+4);
+}
+
+static void sigreceive_set(t_sigreceive *x, t_symbol *s)
+{
+ t_sigsend *sender = (t_sigsend *)pd_findbyclass((x->x_sym = s),
+ sigsend_class);
+ if (sender)
+ {
+ if (sender->x_n == x->x_n)
+ x->x_wherefrom = sender->x_vec;
+ else
+ {
+ pd_error(x, "receive~ %s: vector size mismatch", x->x_sym->s_name);
+ x->x_wherefrom = 0;
+ }
+ }
+ else
+ {
+ pd_error(x, "receive~ %s: no matching send", x->x_sym->s_name);
+ x->x_wherefrom = 0;
+ }
+}
+
+static void sigreceive_dsp(t_sigreceive *x, t_signal **sp)
+{
+ if (sp[0]->s_n != x->x_n)
+ {
+ pd_error(x, "receive~ %s: vector size mismatch", x->x_sym->s_name);
+ }
+ else
+ {
+ sigreceive_set(x, x->x_sym);
+ dsp_add(sigreceive_perform, 3,
+ x, sp[0]->s_vec, sp[0]->s_n);
+ }
+}
+
+static void sigreceive_setup(void)
+{
+ sigreceive_class = class_new(gensym("receive~"),
+ (t_newmethod)sigreceive_new, 0,
+ sizeof(t_sigreceive), 0, A_DEFSYM, 0);
+ class_addcreator((t_newmethod)sigreceive_new, gensym("r~"), A_DEFSYM, 0);
+ class_addmethod(sigreceive_class, (t_method)sigreceive_set, gensym("set"),
+ A_SYMBOL, 0);
+ class_addmethod(sigreceive_class, (t_method)sigreceive_dsp, gensym("dsp"),
+ 0);
+ class_sethelpsymbol(sigreceive_class, gensym("send~"));
+}
+
+/* ----------------------------- catch~ ----------------------------- */
+static t_class *sigcatch_class;
+
+typedef struct _sigcatch
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+ int x_n;
+ float *x_vec;
+} t_sigcatch;
+
+static void *sigcatch_new(t_symbol *s)
+{
+ t_sigcatch *x = (t_sigcatch *)pd_new(sigcatch_class);
+ pd_bind(&x->x_obj.ob_pd, s);
+ x->x_sym = s;
+ x->x_n = DEFSENDVS;
+ x->x_vec = (float *)getbytes(DEFSENDVS * sizeof(float));
+ memset((char *)(x->x_vec), 0, DEFSENDVS * sizeof(float));
+ outlet_new(&x->x_obj, &s_signal);
+ return (x);
+}
+
+static t_int *sigcatch_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ while (n--) *out++ = *in, *in++ = 0;
+ return (w+4);
+}
+
+static void sigcatch_dsp(t_sigcatch *x, t_signal **sp)
+{
+ if (x->x_n == sp[0]->s_n)
+ dsp_add(sigcatch_perform, 3, x->x_vec, sp[0]->s_vec, sp[0]->s_n);
+ else error("sigcatch %s: unexpected vector size", x->x_sym->s_name);
+}
+
+static void sigcatch_free(t_sigcatch *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, x->x_sym);
+ freebytes(x->x_vec, x->x_n * sizeof(float));
+}
+
+static void sigcatch_setup(void)
+{
+ sigcatch_class = class_new(gensym("catch~"), (t_newmethod)sigcatch_new,
+ (t_method)sigcatch_free, sizeof(t_sigcatch), CLASS_NOINLET, A_DEFSYM, 0);
+ class_addmethod(sigcatch_class, (t_method)sigcatch_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(sigcatch_class, gensym("throw~"));
+}
+
+/* ----------------------------- throw~ ----------------------------- */
+static t_class *sigthrow_class;
+
+typedef struct _sigthrow
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+ t_float *x_whereto;
+ int x_n;
+ t_float x_f;
+} t_sigthrow;
+
+static void *sigthrow_new(t_symbol *s)
+{
+ t_sigthrow *x = (t_sigthrow *)pd_new(sigthrow_class);
+ x->x_sym = s;
+ x->x_whereto = 0;
+ x->x_n = DEFSENDVS;
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigthrow_perform(t_int *w)
+{
+ t_sigthrow *x = (t_sigthrow *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ t_float *out = x->x_whereto;
+ if (out)
+ {
+ while (n--)
+ {
+ float f = *in++;
+ /* bash NANs and underflow/overflow hazards to zero */
+ if (!((f > 1.0e-20f && f < 1.0e20f) || (f < -1e-20f && f > -1e20)))
+ f = 0;
+ *out++ += f;
+ }
+ }
+ return (w+4);
+}
+
+static void sigthrow_set(t_sigthrow *x, t_symbol *s)
+{
+ t_sigcatch *catcher = (t_sigcatch *)pd_findbyclass((x->x_sym = s),
+ sigcatch_class);
+ if (catcher)
+ {
+ if (catcher->x_n == x->x_n)
+ x->x_whereto = catcher->x_vec;
+ else
+ {
+ pd_error(x, "throw~ %s: vector size mismatch", x->x_sym->s_name);
+ x->x_whereto = 0;
+ }
+ }
+ else
+ {
+ pd_error(x, "throw~ %s: no matching catch", x->x_sym->s_name);
+ x->x_whereto = 0;
+ }
+}
+
+static void sigthrow_dsp(t_sigthrow *x, t_signal **sp)
+{
+ if (sp[0]->s_n != x->x_n)
+ {
+ pd_error(x, "throw~ %s: vector size mismatch", x->x_sym->s_name);
+ }
+ else
+ {
+ sigthrow_set(x, x->x_sym);
+ dsp_add(sigthrow_perform, 3,
+ x, sp[0]->s_vec, sp[0]->s_n);
+ }
+}
+
+static void sigthrow_setup(void)
+{
+ sigthrow_class = class_new(gensym("throw~"), (t_newmethod)sigthrow_new, 0,
+ sizeof(t_sigthrow), 0, A_DEFSYM, 0);
+ class_addcreator((t_newmethod)sigthrow_new, gensym("r~"), A_DEFSYM, 0);
+ class_addmethod(sigthrow_class, (t_method)sigthrow_set, gensym("set"),
+ A_SYMBOL, 0);
+ CLASS_MAINSIGNALIN(sigthrow_class, t_sigthrow, x_f);
+ class_addmethod(sigthrow_class, (t_method)sigthrow_dsp, gensym("dsp"), 0);
+}
+
+/* ----------------------- global setup routine ---------------- */
+
+void d_global_setup(void)
+{
+ sigsend_setup();
+ sigreceive_setup();
+ sigcatch_setup();
+ sigthrow_setup();
+}
+
diff --git a/pd/src/d_math.c b/pd/src/d_math.c
new file mode 100644
index 00000000..d64e2e34
--- /dev/null
+++ b/pd/src/d_math.c
@@ -0,0 +1,573 @@
+/* Copyright (c) 1997-2001 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. */
+
+/* mathematical functions and other transfer functions, including tilde
+ versions of stuff from x_acoustics.c.
+*/
+
+#include "m_pd.h"
+#include <math.h>
+#define LOGTEN 2.302585092994
+
+/* ------------------------- clip~ -------------------------- */
+static t_class *clip_class;
+
+typedef struct _clip
+{
+ t_object x_obj;
+ float x_f;
+ t_sample x_lo;
+ t_sample x_hi;
+} t_clip;
+
+static void *clip_new(t_floatarg lo, t_floatarg hi)
+{
+ t_clip *x = (t_clip *)pd_new(clip_class);
+ x->x_lo = lo;
+ x->x_hi = hi;
+ outlet_new(&x->x_obj, gensym("signal"));
+ floatinlet_new(&x->x_obj, &x->x_lo);
+ floatinlet_new(&x->x_obj, &x->x_hi);
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *clip_perform(t_int *w)
+{
+ t_clip *x = (t_clip *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ while (n--)
+ {
+ float f = *in++;
+ if (f < x->x_lo) f = x->x_lo;
+ if (f > x->x_hi) f = x->x_hi;
+ *out++ = f;
+ }
+ return (w+5);
+}
+
+static void clip_dsp(t_clip *x, t_signal **sp)
+{
+ dsp_add(clip_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void clip_setup(void)
+{
+ clip_class = class_new(gensym("clip~"), (t_newmethod)clip_new, 0,
+ sizeof(t_clip), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(clip_class, t_clip, x_f);
+ class_addmethod(clip_class, (t_method)clip_dsp, gensym("dsp"), 0);
+}
+
+/* sigrsqrt - reciprocal square root good to 8 mantissa bits */
+
+#define DUMTAB1SIZE 256
+#define DUMTAB2SIZE 1024
+
+static float rsqrt_exptab[DUMTAB1SIZE], rsqrt_mantissatab[DUMTAB2SIZE];
+
+static void init_rsqrt(void)
+{
+ int i;
+ for (i = 0; i < DUMTAB1SIZE; i++)
+ {
+ float f;
+ long l = (i ? (i == DUMTAB1SIZE-1 ? DUMTAB1SIZE-2 : i) : 1)<< 23;
+ *(long *)(&f) = l;
+ rsqrt_exptab[i] = 1./sqrt(f);
+ }
+ for (i = 0; i < DUMTAB2SIZE; i++)
+ {
+ float f = 1 + (1./DUMTAB2SIZE) * i;
+ rsqrt_mantissatab[i] = 1./sqrt(f);
+ }
+}
+
+ /* these are used in externs like "bonk" */
+
+float q8_rsqrt(float f)
+{
+ long l = *(long *)(&f);
+ if (f < 0) return (0);
+ else return (rsqrt_exptab[(l >> 23) & 0xff] *
+ rsqrt_mantissatab[(l >> 13) & 0x3ff]);
+}
+
+float q8_sqrt(float f)
+{
+ long l = *(long *)(&f);
+ if (f < 0) return (0);
+ else return (f * rsqrt_exptab[(l >> 23) & 0xff] *
+ rsqrt_mantissatab[(l >> 13) & 0x3ff]);
+}
+
+ /* the old names are OK unless we're in IRIX N32 */
+
+#ifndef N32
+float qsqrt(float f) {return (q8_sqrt(f)); }
+float qrsqrt(float f) {return (q8_rsqrt(f)); }
+#endif
+
+
+
+typedef struct sigrsqrt
+{
+ t_object x_obj;
+ float x_f;
+} t_sigrsqrt;
+
+static t_class *sigrsqrt_class;
+
+static void *sigrsqrt_new(void)
+{
+ t_sigrsqrt *x = (t_sigrsqrt *)pd_new(sigrsqrt_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigrsqrt_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ while (n--)
+ {
+ float f = *in;
+ long l = *(long *)(in++);
+ if (f < 0) *out++ = 0;
+ else
+ {
+ float g = rsqrt_exptab[(l >> 23) & 0xff] *
+ rsqrt_mantissatab[(l >> 13) & 0x3ff];
+ *out++ = 1.5 * g - 0.5 * g * g * g * f;
+ }
+ }
+ return (w + 4);
+}
+
+static void sigrsqrt_dsp(t_sigrsqrt *x, t_signal **sp)
+{
+ dsp_add(sigrsqrt_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void sigrsqrt_setup(void)
+{
+ init_rsqrt();
+ sigrsqrt_class = class_new(gensym("rsqrt~"), (t_newmethod)sigrsqrt_new, 0,
+ sizeof(t_sigrsqrt), 0, 0);
+ /* an old name for it: */
+ class_addcreator(sigrsqrt_new, gensym("q8_rsqrt~"), 0);
+ CLASS_MAINSIGNALIN(sigrsqrt_class, t_sigrsqrt, x_f);
+ class_addmethod(sigrsqrt_class, (t_method)sigrsqrt_dsp, gensym("dsp"), 0);
+}
+
+
+/* sigsqrt - square root good to 8 mantissa bits */
+
+typedef struct sigsqrt
+{
+ t_object x_obj;
+ float x_f;
+} t_sigsqrt;
+
+static t_class *sigsqrt_class;
+
+static void *sigsqrt_new(void)
+{
+ t_sigsqrt *x = (t_sigsqrt *)pd_new(sigsqrt_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+t_int *sigsqrt_perform(t_int *w) /* not static; also used in d_fft.c */
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ while (n--)
+ {
+ float f = *in;
+ long l = *(long *)(in++);
+ if (f < 0) *out++ = 0;
+ else
+ {
+ float g = rsqrt_exptab[(l >> 23) & 0xff] *
+ rsqrt_mantissatab[(l >> 13) & 0x3ff];
+ *out++ = f * (1.5 * g - 0.5 * g * g * g * f);
+ }
+ }
+ return (w + 4);
+}
+
+static void sigsqrt_dsp(t_sigsqrt *x, t_signal **sp)
+{
+ dsp_add(sigsqrt_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void sigsqrt_setup(void)
+{
+ sigsqrt_class = class_new(gensym("sqrt~"), (t_newmethod)sigsqrt_new, 0,
+ sizeof(t_sigsqrt), 0, 0);
+ class_addcreator(sigsqrt_new, gensym("q8_sqrt~"), 0); /* old name */
+ CLASS_MAINSIGNALIN(sigsqrt_class, t_sigsqrt, x_f);
+ class_addmethod(sigsqrt_class, (t_method)sigsqrt_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ wrap~ -------------------------- */
+
+typedef struct wrap
+{
+ t_object x_obj;
+ float x_f;
+} t_sigwrap;
+
+t_class *sigwrap_class;
+
+static void *sigwrap_new(void)
+{
+ t_sigwrap *x = (t_sigwrap *)pd_new(sigwrap_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *sigwrap_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ while (n--)
+ {
+ float f = *in++;
+ int k = f;
+ if (f > 0) *out++ = f-k;
+ else *out++ = f - (k-1);
+ }
+ return (w + 4);
+}
+
+static void sigwrap_dsp(t_sigwrap *x, t_signal **sp)
+{
+ dsp_add(sigwrap_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void sigwrap_setup(void)
+{
+ sigwrap_class = class_new(gensym("wrap~"), (t_newmethod)sigwrap_new, 0,
+ sizeof(t_sigwrap), 0, 0);
+ CLASS_MAINSIGNALIN(sigwrap_class, t_sigwrap, x_f);
+ class_addmethod(sigwrap_class, (t_method)sigwrap_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ mtof_tilde~ -------------------------- */
+
+typedef struct mtof_tilde
+{
+ t_object x_obj;
+ float x_f;
+} t_mtof_tilde;
+
+t_class *mtof_tilde_class;
+
+static void *mtof_tilde_new(void)
+{
+ t_mtof_tilde *x = (t_mtof_tilde *)pd_new(mtof_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *mtof_tilde_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ for (; n--; in++, out++)
+ {
+ float f = *in;
+ if (f <= -1500) *out = 0;
+ else
+ {
+ if (f > 1499) f = 1499;
+ *out = 8.17579891564 * exp(.0577622650 * f);
+ }
+ }
+ return (w + 4);
+}
+
+static void mtof_tilde_dsp(t_mtof_tilde *x, t_signal **sp)
+{
+ dsp_add(mtof_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void mtof_tilde_setup(void)
+{
+ mtof_tilde_class = class_new(gensym("mtof~"), (t_newmethod)mtof_tilde_new, 0,
+ sizeof(t_mtof_tilde), 0, 0);
+ CLASS_MAINSIGNALIN(mtof_tilde_class, t_mtof_tilde, x_f);
+ class_addmethod(mtof_tilde_class, (t_method)mtof_tilde_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ ftom_tilde~ -------------------------- */
+
+typedef struct ftom_tilde
+{
+ t_object x_obj;
+ float x_f;
+} t_ftom_tilde;
+
+t_class *ftom_tilde_class;
+
+static void *ftom_tilde_new(void)
+{
+ t_ftom_tilde *x = (t_ftom_tilde *)pd_new(ftom_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *ftom_tilde_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ for (; n--; *in++, out++)
+ {
+ float f = *in;
+ *out = (f > 0 ? 17.3123405046 * log(.12231220585 * f) : -1500);
+ }
+ return (w + 4);
+}
+
+static void ftom_tilde_dsp(t_ftom_tilde *x, t_signal **sp)
+{
+ dsp_add(ftom_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void ftom_tilde_setup(void)
+{
+ ftom_tilde_class = class_new(gensym("ftom~"), (t_newmethod)ftom_tilde_new, 0,
+ sizeof(t_ftom_tilde), 0, 0);
+ CLASS_MAINSIGNALIN(ftom_tilde_class, t_ftom_tilde, x_f);
+ class_addmethod(ftom_tilde_class, (t_method)ftom_tilde_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ dbtorms~ -------------------------- */
+
+typedef struct dbtorms_tilde
+{
+ t_object x_obj;
+ float x_f;
+} t_dbtorms_tilde;
+
+t_class *dbtorms_tilde_class;
+
+static void *dbtorms_tilde_new(void)
+{
+ t_dbtorms_tilde *x = (t_dbtorms_tilde *)pd_new(dbtorms_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *dbtorms_tilde_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ for (; n--; in++, out++)
+ {
+ float f = *in;
+ if (f <= 0) *out = 0;
+ else
+ {
+ if (f > 485)
+ f = 485;
+ *out = exp((LOGTEN * 0.05) * (f-100.));
+ }
+ }
+ return (w + 4);
+}
+
+static void dbtorms_tilde_dsp(t_dbtorms_tilde *x, t_signal **sp)
+{
+ dsp_add(dbtorms_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void dbtorms_tilde_setup(void)
+{
+ dbtorms_tilde_class = class_new(gensym("dbtorms~"), (t_newmethod)dbtorms_tilde_new, 0,
+ sizeof(t_dbtorms_tilde), 0, 0);
+ CLASS_MAINSIGNALIN(dbtorms_tilde_class, t_dbtorms_tilde, x_f);
+ class_addmethod(dbtorms_tilde_class, (t_method)dbtorms_tilde_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ rmstodb~ -------------------------- */
+
+typedef struct rmstodb_tilde
+{
+ t_object x_obj;
+ float x_f;
+} t_rmstodb_tilde;
+
+t_class *rmstodb_tilde_class;
+
+static void *rmstodb_tilde_new(void)
+{
+ t_rmstodb_tilde *x = (t_rmstodb_tilde *)pd_new(rmstodb_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *rmstodb_tilde_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ for (; n--; in++, out++)
+ {
+ float f = *in;
+ if (f <= 0) *out = 0;
+ else
+ {
+ float g = 100 + 20./LOGTEN * log(f);
+ *out = (g < 0 ? 0 : g);
+ }
+ }
+ return (w + 4);
+}
+
+static void rmstodb_tilde_dsp(t_rmstodb_tilde *x, t_signal **sp)
+{
+ dsp_add(rmstodb_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void rmstodb_tilde_setup(void)
+{
+ rmstodb_tilde_class = class_new(gensym("rmstodb~"), (t_newmethod)rmstodb_tilde_new, 0,
+ sizeof(t_rmstodb_tilde), 0, 0);
+ CLASS_MAINSIGNALIN(rmstodb_tilde_class, t_rmstodb_tilde, x_f);
+ class_addmethod(rmstodb_tilde_class, (t_method)rmstodb_tilde_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ dbtopow~ -------------------------- */
+
+typedef struct dbtopow_tilde
+{
+ t_object x_obj;
+ float x_f;
+} t_dbtopow_tilde;
+
+t_class *dbtopow_tilde_class;
+
+static void *dbtopow_tilde_new(void)
+{
+ t_dbtopow_tilde *x = (t_dbtopow_tilde *)pd_new(dbtopow_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *dbtopow_tilde_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ for (; n--; in++, out++)
+ {
+ float f = *in;
+ if (f <= 0) *out = 0;
+ else
+ {
+ if (f > 870)
+ f = 870;
+ *out = exp((LOGTEN * 0.1) * (f-100.));
+ }
+ }
+ return (w + 4);
+}
+
+static void dbtopow_tilde_dsp(t_dbtopow_tilde *x, t_signal **sp)
+{
+ dsp_add(dbtopow_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void dbtopow_tilde_setup(void)
+{
+ dbtopow_tilde_class = class_new(gensym("dbtopow~"), (t_newmethod)dbtopow_tilde_new, 0,
+ sizeof(t_dbtopow_tilde), 0, 0);
+ CLASS_MAINSIGNALIN(dbtopow_tilde_class, t_dbtopow_tilde, x_f);
+ class_addmethod(dbtopow_tilde_class, (t_method)dbtopow_tilde_dsp, gensym("dsp"), 0);
+}
+
+/* ------------------------------ powtodb~ -------------------------- */
+
+typedef struct powtodb_tilde
+{
+ t_object x_obj;
+ float x_f;
+} t_powtodb_tilde;
+
+t_class *powtodb_tilde_class;
+
+static void *powtodb_tilde_new(void)
+{
+ t_powtodb_tilde *x = (t_powtodb_tilde *)pd_new(powtodb_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *powtodb_tilde_perform(t_int *w)
+{
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ for (; n--; in++, out++)
+ {
+ float f = *in;
+ if (f <= 0) *out = 0;
+ else
+ {
+ float g = 100 + 10./LOGTEN * log(f);
+ *out = (g < 0 ? 0 : g);
+ }
+ }
+ return (w + 4);
+}
+
+static void powtodb_tilde_dsp(t_powtodb_tilde *x, t_signal **sp)
+{
+ dsp_add(powtodb_tilde_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+void powtodb_tilde_setup(void)
+{
+ powtodb_tilde_class = class_new(gensym("powtodb~"), (t_newmethod)powtodb_tilde_new, 0,
+ sizeof(t_powtodb_tilde), 0, 0);
+ CLASS_MAINSIGNALIN(powtodb_tilde_class, t_powtodb_tilde, x_f);
+ class_addmethod(powtodb_tilde_class, (t_method)powtodb_tilde_dsp, gensym("dsp"), 0);
+}
+
+
+/* ------------------------ global setup routine ------------------------- */
+
+void d_math_setup(void)
+{
+ t_symbol *s = gensym("acoustics~.pd");
+ clip_setup();
+ sigrsqrt_setup();
+ sigsqrt_setup();
+ sigwrap_setup();
+ mtof_tilde_setup();
+ ftom_tilde_setup();
+ dbtorms_tilde_setup();
+ rmstodb_tilde_setup();
+ dbtopow_tilde_setup();
+ powtodb_tilde_setup();
+
+ class_sethelpsymbol(mtof_tilde_class, s);
+ class_sethelpsymbol(ftom_tilde_class, s);
+ class_sethelpsymbol(dbtorms_tilde_class, s);
+ class_sethelpsymbol(rmstodb_tilde_class, s);
+ class_sethelpsymbol(dbtopow_tilde_class, s);
+ class_sethelpsymbol(powtodb_tilde_class, s);
+}
+
diff --git a/pd/src/d_mayer_fft.c b/pd/src/d_mayer_fft.c
new file mode 100644
index 00000000..c221e33e
--- /dev/null
+++ b/pd/src/d_mayer_fft.c
@@ -0,0 +1,419 @@
+/*
+** FFT and FHT routines
+** Copyright 1988, 1993; Ron Mayer
+**
+** mayer_fht(fz,n);
+** Does a hartley transform of "n" points in the array "fz".
+** mayer_fft(n,real,imag)
+** Does a fourier transform of "n" points of the "real" and
+** "imag" arrays.
+** mayer_ifft(n,real,imag)
+** Does an inverse fourier transform of "n" points of the "real"
+** and "imag" arrays.
+** mayer_realfft(n,real)
+** Does a real-valued fourier transform of "n" points of the
+** "real" array. The real part of the transform ends
+** up in the first half of the array and the imaginary part of the
+** transform ends up in the second half of the array.
+** mayer_realifft(n,real)
+** The inverse of the realfft() routine above.
+**
+**
+** NOTE: This routine uses at least 2 patented algorithms, and may be
+** under the restrictions of a bunch of different organizations.
+** Although I wrote it completely myself, it is kind of a derivative
+** of a routine I once authored and released under the GPL, so it
+** may fall under the free software foundation's restrictions;
+** it was worked on as a Stanford Univ project, so they claim
+** some rights to it; it was further optimized at work here, so
+** I think this company claims parts of it. The patents are
+** held by R. Bracewell (the FHT algorithm) and O. Buneman (the
+** trig generator), both at Stanford Univ.
+** If it were up to me, I'd say go do whatever you want with it;
+** but it would be polite to give credit to the following people
+** if you use this anywhere:
+** Euler - probable inventor of the fourier transform.
+** Gauss - probable inventor of the FFT.
+** Hartley - probable inventor of the hartley transform.
+** Buneman - for a really cool trig generator
+** Mayer(me) - for authoring this particular version and
+** including all the optimizations in one package.
+** Thanks,
+** Ron Mayer; mayer@acuson.com
+**
+*/
+
+/* This is a slightly modified version of Mayer's contribution; write
+* msp@ucsd.edu for the original code. Kudos to Mayer for a fine piece
+* of work. -msp
+*/
+
+#ifdef NT
+#pragma warning( disable : 4305 ) /* uncast const double to float */
+#pragma warning( disable : 4244 ) /* uncast double to float */
+#pragma warning( disable : 4101 ) /* unused local variables */
+#endif
+
+#define REAL float
+#define GOOD_TRIG
+
+#ifdef GOOD_TRIG
+#else
+#define FAST_TRIG
+#endif
+
+#if defined(GOOD_TRIG)
+#define FHT_SWAP(a,b,t) {(t)=(a);(a)=(b);(b)=(t);}
+#define TRIG_VARS \
+ int t_lam=0;
+#define TRIG_INIT(k,c,s) \
+ { \
+ int i; \
+ for (i=2 ; i<=k ; i++) \
+ {coswrk[i]=costab[i];sinwrk[i]=sintab[i];} \
+ t_lam = 0; \
+ c = 1; \
+ s = 0; \
+ }
+#define TRIG_NEXT(k,c,s) \
+ { \
+ int i,j; \
+ (t_lam)++; \
+ for (i=0 ; !((1<<i)&t_lam) ; i++); \
+ i = k-i; \
+ s = sinwrk[i]; \
+ c = coswrk[i]; \
+ if (i>1) \
+ { \
+ for (j=k-i+2 ; (1<<j)&t_lam ; j++); \
+ j = k - j; \
+ sinwrk[i] = halsec[i] * (sinwrk[i-1] + sinwrk[j]); \
+ coswrk[i] = halsec[i] * (coswrk[i-1] + coswrk[j]); \
+ } \
+ }
+#define TRIG_RESET(k,c,s)
+#endif
+
+#if defined(FAST_TRIG)
+#define TRIG_VARS \
+ REAL t_c,t_s;
+#define TRIG_INIT(k,c,s) \
+ { \
+ t_c = costab[k]; \
+ t_s = sintab[k]; \
+ c = 1; \
+ s = 0; \
+ }
+#define TRIG_NEXT(k,c,s) \
+ { \
+ REAL t = c; \
+ c = t*t_c - s*t_s; \
+ s = t*t_s + s*t_c; \
+ }
+#define TRIG_RESET(k,c,s)
+#endif
+
+static REAL halsec[20]=
+ {
+ 0,
+ 0,
+ .54119610014619698439972320536638942006107206337801,
+ .50979557910415916894193980398784391368261849190893,
+ .50241928618815570551167011928012092247859337193963,
+ .50060299823519630134550410676638239611758632599591,
+ .50015063602065098821477101271097658495974913010340,
+ .50003765191554772296778139077905492847503165398345,
+ .50000941253588775676512870469186533538523133757983,
+ .50000235310628608051401267171204408939326297376426,
+ .50000058827484117879868526730916804925780637276181,
+ .50000014706860214875463798283871198206179118093251,
+ .50000003676714377807315864400643020315103490883972,
+ .50000000919178552207366560348853455333939112569380,
+ .50000000229794635411562887767906868558991922348920,
+ .50000000057448658687873302235147272458812263401372
+ };
+static REAL costab[20]=
+ {
+ .00000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768847,
+ .92387953251128675612818318939678828682241662586364,
+ .98078528040323044912618223613423903697393373089333,
+ .99518472667219688624483695310947992157547486872985,
+ .99879545620517239271477160475910069444320361470461,
+ .99969881869620422011576564966617219685006108125772,
+ .99992470183914454092164649119638322435060646880221,
+ .99998117528260114265699043772856771617391725094433,
+ .99999529380957617151158012570011989955298763362218,
+ .99999882345170190992902571017152601904826792288976,
+ .99999970586288221916022821773876567711626389934930,
+ .99999992646571785114473148070738785694820115568892,
+ .99999998161642929380834691540290971450507605124278,
+ .99999999540410731289097193313960614895889430318945,
+ .99999999885102682756267330779455410840053741619428
+ };
+static REAL sintab[20]=
+ {
+ 1.0000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768846,
+ .38268343236508977172845998403039886676134456248561,
+ .19509032201612826784828486847702224092769161775195,
+ .09801714032956060199419556388864184586113667316749,
+ .04906767432741801425495497694268265831474536302574,
+ .02454122852291228803173452945928292506546611923944,
+ .01227153828571992607940826195100321214037231959176,
+ .00613588464915447535964023459037258091705788631738,
+ .00306795676296597627014536549091984251894461021344,
+ .00153398018628476561230369715026407907995486457522,
+ .00076699031874270452693856835794857664314091945205,
+ .00038349518757139558907246168118138126339502603495,
+ .00019174759731070330743990956198900093346887403385,
+ .00009587379909597734587051721097647635118706561284,
+ .00004793689960306688454900399049465887274686668768
+ };
+static REAL coswrk[20]=
+ {
+ .00000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768847,
+ .92387953251128675612818318939678828682241662586364,
+ .98078528040323044912618223613423903697393373089333,
+ .99518472667219688624483695310947992157547486872985,
+ .99879545620517239271477160475910069444320361470461,
+ .99969881869620422011576564966617219685006108125772,
+ .99992470183914454092164649119638322435060646880221,
+ .99998117528260114265699043772856771617391725094433,
+ .99999529380957617151158012570011989955298763362218,
+ .99999882345170190992902571017152601904826792288976,
+ .99999970586288221916022821773876567711626389934930,
+ .99999992646571785114473148070738785694820115568892,
+ .99999998161642929380834691540290971450507605124278,
+ .99999999540410731289097193313960614895889430318945,
+ .99999999885102682756267330779455410840053741619428
+ };
+static REAL sinwrk[20]=
+ {
+ 1.0000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768846,
+ .38268343236508977172845998403039886676134456248561,
+ .19509032201612826784828486847702224092769161775195,
+ .09801714032956060199419556388864184586113667316749,
+ .04906767432741801425495497694268265831474536302574,
+ .02454122852291228803173452945928292506546611923944,
+ .01227153828571992607940826195100321214037231959176,
+ .00613588464915447535964023459037258091705788631738,
+ .00306795676296597627014536549091984251894461021344,
+ .00153398018628476561230369715026407907995486457522,
+ .00076699031874270452693856835794857664314091945205,
+ .00038349518757139558907246168118138126339502603495,
+ .00019174759731070330743990956198900093346887403385,
+ .00009587379909597734587051721097647635118706561284,
+ .00004793689960306688454900399049465887274686668768
+ };
+
+
+#define SQRT2_2 0.70710678118654752440084436210484
+#define SQRT2 2*0.70710678118654752440084436210484
+
+void mayer_fht(REAL *fz, int n)
+{
+/* REAL a,b;
+REAL c1,s1,s2,c2,s3,c3,s4,c4;
+ REAL f0,g0,f1,g1,f2,g2,f3,g3; */
+ int k,k1,k2,k3,k4,kx;
+ REAL *fi,*fn,*gi;
+ TRIG_VARS;
+
+ for (k1=1,k2=0;k1<n;k1++)
+ {
+ REAL aa;
+ for (k=n>>1; (!((k2^=k)&k)); k>>=1);
+ if (k1>k2)
+ {
+ aa=fz[k1];fz[k1]=fz[k2];fz[k2]=aa;
+ }
+ }
+ for ( k=0 ; (1<<k)<n ; k++ );
+ k &= 1;
+ if (k==0)
+ {
+ for (fi=fz,fn=fz+n;fi<fn;fi+=4)
+ {
+ REAL f0,f1,f2,f3;
+ f1 = fi[0 ]-fi[1 ];
+ f0 = fi[0 ]+fi[1 ];
+ f3 = fi[2 ]-fi[3 ];
+ f2 = fi[2 ]+fi[3 ];
+ fi[2 ] = (f0-f2);
+ fi[0 ] = (f0+f2);
+ fi[3 ] = (f1-f3);
+ fi[1 ] = (f1+f3);
+ }
+ }
+ else
+ {
+ for (fi=fz,fn=fz+n,gi=fi+1;fi<fn;fi+=8,gi+=8)
+ {
+ REAL bs1,bc1,bs2,bc2,bs3,bc3,bs4,bc4,
+ bg0,bf0,bf1,bg1,bf2,bg2,bf3,bg3;
+ bc1 = fi[0 ] - gi[0 ];
+ bs1 = fi[0 ] + gi[0 ];
+ bc2 = fi[2 ] - gi[2 ];
+ bs2 = fi[2 ] + gi[2 ];
+ bc3 = fi[4 ] - gi[4 ];
+ bs3 = fi[4 ] + gi[4 ];
+ bc4 = fi[6 ] - gi[6 ];
+ bs4 = fi[6 ] + gi[6 ];
+ bf1 = (bs1 - bs2);
+ bf0 = (bs1 + bs2);
+ bg1 = (bc1 - bc2);
+ bg0 = (bc1 + bc2);
+ bf3 = (bs3 - bs4);
+ bf2 = (bs3 + bs4);
+ bg3 = SQRT2*bc4;
+ bg2 = SQRT2*bc3;
+ fi[4 ] = bf0 - bf2;
+ fi[0 ] = bf0 + bf2;
+ fi[6 ] = bf1 - bf3;
+ fi[2 ] = bf1 + bf3;
+ gi[4 ] = bg0 - bg2;
+ gi[0 ] = bg0 + bg2;
+ gi[6 ] = bg1 - bg3;
+ gi[2 ] = bg1 + bg3;
+ }
+ }
+ if (n<16) return;
+
+ do
+ {
+ REAL s1,c1;
+ int ii;
+ k += 2;
+ k1 = 1 << k;
+ k2 = k1 << 1;
+ k4 = k2 << 1;
+ k3 = k2 + k1;
+ kx = k1 >> 1;
+ fi = fz;
+ gi = fi + kx;
+ fn = fz + n;
+ do
+ {
+ REAL g0,f0,f1,g1,f2,g2,f3,g3;
+ f1 = fi[0 ] - fi[k1];
+ f0 = fi[0 ] + fi[k1];
+ f3 = fi[k2] - fi[k3];
+ f2 = fi[k2] + fi[k3];
+ fi[k2] = f0 - f2;
+ fi[0 ] = f0 + f2;
+ fi[k3] = f1 - f3;
+ fi[k1] = f1 + f3;
+ g1 = gi[0 ] - gi[k1];
+ g0 = gi[0 ] + gi[k1];
+ g3 = SQRT2 * gi[k3];
+ g2 = SQRT2 * gi[k2];
+ gi[k2] = g0 - g2;
+ gi[0 ] = g0 + g2;
+ gi[k3] = g1 - g3;
+ gi[k1] = g1 + g3;
+ gi += k4;
+ fi += k4;
+ } while (fi<fn);
+ TRIG_INIT(k,c1,s1);
+ for (ii=1;ii<kx;ii++)
+ {
+ REAL c2,s2;
+ TRIG_NEXT(k,c1,s1);
+ c2 = c1*c1 - s1*s1;
+ s2 = 2*(c1*s1);
+ fn = fz + n;
+ fi = fz +ii;
+ gi = fz +k1-ii;
+ do
+ {
+ REAL a,b,g0,f0,f1,g1,f2,g2,f3,g3;
+ b = s2*fi[k1] - c2*gi[k1];
+ a = c2*fi[k1] + s2*gi[k1];
+ f1 = fi[0 ] - a;
+ f0 = fi[0 ] + a;
+ g1 = gi[0 ] - b;
+ g0 = gi[0 ] + b;
+ b = s2*fi[k3] - c2*gi[k3];
+ a = c2*fi[k3] + s2*gi[k3];
+ f3 = fi[k2] - a;
+ f2 = fi[k2] + a;
+ g3 = gi[k2] - b;
+ g2 = gi[k2] + b;
+ b = s1*f2 - c1*g3;
+ a = c1*f2 + s1*g3;
+ fi[k2] = f0 - a;
+ fi[0 ] = f0 + a;
+ gi[k3] = g1 - b;
+ gi[k1] = g1 + b;
+ b = c1*g2 - s1*f3;
+ a = s1*g2 + c1*f3;
+ gi[k2] = g0 - a;
+ gi[0 ] = g0 + a;
+ fi[k3] = f1 - b;
+ fi[k1] = f1 + b;
+ gi += k4;
+ fi += k4;
+ } while (fi<fn);
+ }
+ TRIG_RESET(k,c1,s1);
+ } while (k4<n);
+}
+
+void mayer_fft(int n, REAL *real, REAL *imag)
+{
+ REAL a,b,c,d;
+ REAL q,r,s,t;
+ int i,j,k;
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i]; b = real[j]; q=a+b; r=a-b;
+ c = imag[i]; d = imag[j]; s=c+d; t=c-d;
+ real[i] = (q+t)*.5; real[j] = (q-t)*.5;
+ imag[i] = (s-r)*.5; imag[j] = (s+r)*.5;
+ }
+ mayer_fht(real,n);
+ mayer_fht(imag,n);
+}
+
+void mayer_ifft(int n, REAL *real, REAL *imag)
+{
+ REAL a,b,c,d;
+ REAL q,r,s,t;
+ int i,j,k;
+ mayer_fht(real,n);
+ mayer_fht(imag,n);
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i]; b = real[j]; q=a+b; r=a-b;
+ c = imag[i]; d = imag[j]; s=c+d; t=c-d;
+ imag[i] = (s+r)*0.5; imag[j] = (s-r)*0.5;
+ real[i] = (q-t)*0.5; real[j] = (q+t)*0.5;
+ }
+}
+
+void mayer_realfft(int n, REAL *real)
+{
+ REAL a,b,c,d;
+ int i,j,k;
+ mayer_fht(real,n);
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i];
+ b = real[j];
+ real[j] = (a-b)*0.5;
+ real[i] = (a+b)*0.5;
+ }
+}
+
+void mayer_realifft(int n, REAL *real)
+{
+ REAL a,b,c,d;
+ int i,j,k;
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i];
+ b = real[j];
+ real[j] = (a-b);
+ real[i] = (a+b);
+ }
+ mayer_fht(real,n);
+}
diff --git a/pd/src/d_misc.c b/pd/src/d_misc.c
new file mode 100644
index 00000000..35f4af0b
--- /dev/null
+++ b/pd/src/d_misc.c
@@ -0,0 +1,260 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* miscellaneous: print~; more to come.
+*/
+
+#include "m_pd.h"
+#include <stdio.h>
+#include <string.h>
+
+/* ------------------------- print~ -------------------------- */
+static t_class *print_class;
+
+typedef struct _print
+{
+ t_object x_obj;
+ float x_f;
+ t_symbol *x_sym;
+ int x_count;
+} t_print;
+
+static t_int *print_perform(t_int *w)
+{
+ t_print *x = (t_print *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ if (x->x_count)
+ {
+ post("%s:", x->x_sym->s_name);
+ if (n == 1) post("%8g", in[0]);
+ else if (n == 2) post("%8g %8g", in[0], in[1]);
+ else if (n == 4) post("%8g %8g %8g %8g",
+ in[0], in[1], in[2], in[3]);
+ else while (n > 0)
+ {
+ post("%-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g",
+ in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7]);
+ n -= 8;
+ in += 8;
+ }
+ x->x_count--;
+ }
+ return (w+4);
+}
+
+static void print_dsp(t_print *x, t_signal **sp)
+{
+ dsp_add(print_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+}
+
+static void print_float(t_print *x, t_float f)
+{
+ if (f < 0) f = 0;
+ x->x_count = f;
+}
+
+static void print_bang(t_print *x)
+{
+ x->x_count = 1;
+}
+
+static void *print_new(t_symbol *s)
+{
+ t_print *x = (t_print *)pd_new(print_class);
+ x->x_sym = (s->s_name[0]? s : gensym("print~"));
+ x->x_count = 0;
+ x->x_f = 0;
+ return (x);
+}
+
+static void print_setup(void)
+{
+ print_class = class_new(gensym("print~"), (t_newmethod)print_new, 0,
+ sizeof(t_print), 0, A_DEFSYM, 0);
+ CLASS_MAINSIGNALIN(print_class, t_print, x_f);
+ class_addmethod(print_class, (t_method)print_dsp, gensym("dsp"), 0);
+ class_addbang(print_class, print_bang);
+ class_addfloat(print_class, print_float);
+}
+
+/* ------------------------- scope~ -------------------------- */
+/* this has been replaced by arrays; to be deleted later */
+
+#include "g_canvas.h"
+
+static t_class *scope_class;
+
+#define SCOPESIZE 256
+
+typedef struct _scope
+{
+ t_object x_obj;
+ t_sample x_samps[SCOPESIZE];
+ int x_phase;
+ int x_drawn;
+ void *x_canvas;
+} t_scope;
+
+static t_int *scope_perform(t_int *w)
+{
+ t_scope *x = (t_scope *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ int n = (int)(w[3]), phase = x->x_phase;
+ while (n--)
+ {
+ x->x_samps[phase] = *in++;
+ phase = (phase + 1) & (SCOPESIZE-1);
+ }
+ x->x_phase = phase;
+ return (w+4);
+}
+
+static void scope_dsp(t_scope *x, t_signal **sp)
+{
+ dsp_add(scope_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+}
+
+static void scope_erase(t_scope *x)
+{
+ if (x->x_drawn) sys_vgui(".x%x.c delete gumbo\n", x->x_canvas);
+}
+
+#define X1 10.
+#define X2 20.
+#define YC 5.
+static void scope_bang(t_scope *x)
+{
+ int n, phase;
+ char hugebuf[10000], *s = hugebuf;
+ scope_erase(x);
+ sys_vgui(".x%x.c create line 10c 5c 20c 5c -tags gumbo\n", x->x_canvas);
+ sprintf(s, ".x%x.c create line ", (t_int)x->x_canvas);
+ s += strlen(s);
+ for (n = 0, phase = x->x_phase;
+ n < SCOPESIZE; phase = ((phase+1) & (SCOPESIZE-1)), n++)
+ {
+ sprintf(s, "%fc %fc ", X1 + (X2 - X1) * (float)n * (1./SCOPESIZE),
+ YC - 5 * x->x_samps[phase]);
+ s += strlen(s);
+ /* post("phase %d", phase); */
+ }
+ sprintf(s, "-tags gumbo\n");
+ sys_gui(hugebuf);
+ x->x_drawn = 1;
+}
+
+static void scope_free(t_scope *x)
+{
+ scope_erase(x);
+}
+
+static void *scope_new(t_symbol *s)
+{
+ t_scope *x = (t_scope *)pd_new(scope_class);
+ error("scope: this is now obsolete; use arrays and tabwrite~ instead");
+ x->x_phase = 0;
+ x->x_drawn = 0;
+ x->x_canvas = canvas_getcurrent();
+ return (x);
+}
+
+static void scope_setup(void)
+{
+ scope_class = class_new(gensym("scope~"), (t_newmethod)scope_new,
+ (t_method)scope_free, sizeof(t_scope), 0, A_DEFSYM, 0);
+ class_addmethod(scope_class, nullfn, gensym("signal"), 0);
+ class_addmethod(scope_class, (t_method)scope_dsp, gensym("dsp"), 0);
+ class_addbang(scope_class, scope_bang);
+}
+
+/* ------------------------ bang~ -------------------------- */
+
+static t_class *bang_tilde_class;
+
+typedef struct _bang
+{
+ t_object x_obj;
+ t_clock *x_clock;
+} t_bang;
+
+static t_int *bang_tilde_perform(t_int *w)
+{
+ t_bang *x = (t_bang *)(w[1]);
+ clock_delay(x->x_clock, 0);
+ return (w+2);
+}
+
+static void bang_tilde_dsp(t_bang *x, t_signal **sp)
+{
+ dsp_add(bang_tilde_perform, 1, x);
+}
+
+static void bang_tilde_tick(t_bang *x)
+{
+ outlet_bang(x->x_obj.ob_outlet);
+}
+
+static void bang_tilde_free(t_bang *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void *bang_tilde_new(t_symbol *s)
+{
+ t_bang *x = (t_bang *)pd_new(bang_tilde_class);
+ x->x_clock = clock_new(x, (t_method)bang_tilde_tick);
+ outlet_new(&x->x_obj, &s_bang);
+ return (x);
+}
+
+static void bang_tilde_setup(void)
+{
+ bang_tilde_class = class_new(gensym("bang~"), (t_newmethod)bang_tilde_new,
+ (t_method)bang_tilde_free, sizeof(t_bang), 0, 0);
+ class_addmethod(bang_tilde_class, (t_method)bang_tilde_dsp,
+ gensym("dsp"), 0);
+}
+
+/* ------------------------ samplerate~~ -------------------------- */
+
+static t_class *samplerate_tilde_class;
+
+typedef struct _samplerate
+{
+ t_object x_obj;
+} t_samplerate;
+
+static void samplerate_tilde_bang(t_samplerate *x)
+{
+ outlet_float(x->x_obj.ob_outlet, sys_getsr());
+}
+
+static void *samplerate_tilde_new(t_symbol *s)
+{
+ t_samplerate *x = (t_samplerate *)pd_new(samplerate_tilde_class);
+ outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+static void samplerate_tilde_setup(void)
+{
+ samplerate_tilde_class = class_new(gensym("samplerate~"),
+ (t_newmethod)samplerate_tilde_new, 0, sizeof(t_samplerate), 0, 0);
+ class_addbang(samplerate_tilde_class, samplerate_tilde_bang);
+}
+
+/* ------------------------ global setup routine ------------------------- */
+
+void d_misc_setup(void)
+{
+ print_setup();
+ scope_setup();
+ bang_tilde_setup();
+ samplerate_tilde_setup();
+}
+
+
+
+
diff --git a/pd/src/d_osc.c b/pd/src/d_osc.c
new file mode 100644
index 00000000..27dceae9
--- /dev/null
+++ b/pd/src/d_osc.c
@@ -0,0 +1,531 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* sinusoidal oscillator and table lookup; see also tabosc4~ in d_array.c.
+*/
+
+#include "m_pd.h"
+#include "math.h"
+
+#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */
+
+ /* machine-dependent definitions. These ifdefs really
+ should have been by CPU type and not by operating system! */
+#ifdef IRIX
+ /* big-endian. Most significant byte is at low address in memory */
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#define int32 long /* a data type that has 32 bits */
+#else
+#ifdef NT
+ /* little-endian; most significant byte is at highest address */
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#define int32 long
+#else
+#ifdef __FreeBSD__
+#include <machine/endian.h>
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#else
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#endif /* BYTE_ORDER */
+#include <sys/types.h>
+#define int32 int32_t
+#endif
+#ifdef __linux__
+
+#include <endian.h>
+
+#if !defined(__BYTE_ORDER) || !defined(__LITTLE_ENDIAN)
+#error No byte order defined
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#else
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#endif /* __BYTE_ORDER */
+
+#include <sys/types.h>
+#define int32 int32_t
+
+#else
+#ifdef MACOSX
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#define int32 int /* a data type that has 32 bits */
+
+#endif /* MACOSX */
+#endif /* __linux__ */
+#endif /* NT */
+#endif /* SGI */
+
+union tabfudge
+{
+ double tf_d;
+ int32 tf_i[2];
+};
+
+
+/* -------------------------- phasor~ ------------------------------ */
+static t_class *phasor_class, *scalarphasor_class;
+
+#if 1 /* in the style of R. Hoeldrich (ICMC 1995 Banff) */
+
+typedef struct _phasor
+{
+ t_object x_obj;
+ double x_phase;
+ float x_conv;
+ float x_f; /* scalar frequency */
+} t_phasor;
+
+static void *phasor_new(t_floatarg f)
+{
+ t_phasor *x = (t_phasor *)pd_new(phasor_class);
+ x->x_f = f;
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
+ x->x_phase = 0;
+ x->x_conv = 0;
+ outlet_new(&x->x_obj, gensym("signal"));
+ return (x);
+}
+
+static t_int *phasor_perform(t_int *w)
+{
+ t_phasor *x = (t_phasor *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ double dphase = x->x_phase + UNITBIT32;
+ union tabfudge tf;
+ int normhipart;
+ float conv = x->x_conv;
+
+ tf.tf_d = UNITBIT32;
+ normhipart = tf.tf_i[HIOFFSET];
+ tf.tf_d = dphase;
+
+ while (n--)
+ {
+ tf.tf_i[HIOFFSET] = normhipart;
+ dphase += *in++ * conv;
+ *out++ = tf.tf_d - UNITBIT32;
+ tf.tf_d = dphase;
+ }
+ tf.tf_i[HIOFFSET] = normhipart;
+ x->x_phase = tf.tf_d - UNITBIT32;
+ return (w+5);
+}
+
+static void phasor_dsp(t_phasor *x, t_signal **sp)
+{
+ x->x_conv = 1./sp[0]->s_sr;
+ dsp_add(phasor_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void phasor_ft1(t_phasor *x, t_float f)
+{
+ x->x_phase = f;
+}
+
+static void phasor_setup(void)
+{
+ phasor_class = class_new(gensym("phasor~"), (t_newmethod)phasor_new, 0,
+ sizeof(t_phasor), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(phasor_class, t_phasor, x_f);
+ class_addmethod(phasor_class, (t_method)phasor_dsp, gensym("dsp"), 0);
+ class_addmethod(phasor_class, (t_method)phasor_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
+
+#endif /* Hoeldrich version */
+
+/* ------------------------ cos~ ----------------------------- */
+
+float *cos_table;
+
+static t_class *cos_class;
+
+typedef struct _cos
+{
+ t_object x_obj;
+ float x_f;
+} t_cos;
+
+static void *cos_new(void)
+{
+ t_cos *x = (t_cos *)pd_new(cos_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+static t_int *cos_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ float *tab = cos_table, *addr, f1, f2, frac;
+ double dphase;
+ int normhipart;
+ union tabfudge tf;
+
+ tf.tf_d = UNITBIT32;
+ normhipart = tf.tf_i[HIOFFSET];
+
+#if 0 /* this is the readable version of the code. */
+ while (n--)
+ {
+ dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
+ tf.tf_d = dphase;
+ addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
+ tf.tf_i[HIOFFSET] = normhipart;
+ frac = tf.tf_d - UNITBIT32;
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+ }
+#endif
+#if 1 /* this is the same, unwrapped by hand. */
+ dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
+ tf.tf_d = dphase;
+ addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
+ tf.tf_i[HIOFFSET] = normhipart;
+ while (--n)
+ {
+ dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
+ frac = tf.tf_d - UNITBIT32;
+ tf.tf_d = dphase;
+ f1 = addr[0];
+ f2 = addr[1];
+ addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
+ *out++ = f1 + frac * (f2 - f1);
+ tf.tf_i[HIOFFSET] = normhipart;
+ }
+ frac = tf.tf_d - UNITBIT32;
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+#endif
+ return (w+4);
+}
+
+static void cos_dsp(t_cos *x, t_signal **sp)
+{
+ dsp_add(cos_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void cos_maketable(void)
+{
+ int i;
+ float *fp, phase, phsinc = (2. * 3.14159) / COSTABSIZE;
+ union tabfudge tf;
+
+ if (cos_table) return;
+ cos_table = (float *)getbytes(sizeof(float) * (COSTABSIZE+1));
+ for (i = COSTABSIZE + 1, fp = cos_table, phase = 0; i--;
+ fp++, phase += phsinc)
+ *fp = cos(phase);
+
+ /* here we check at startup whether the byte alignment
+ is as we declared it. If not, the code has to be
+ recompiled the other way. */
+ tf.tf_d = UNITBIT32 + 0.5;
+ if ((unsigned)tf.tf_i[LOWOFFSET] != 0x80000000)
+ bug("cos~: unexpected machine alignment");
+}
+
+static void cos_setup(void)
+{
+ cos_class = class_new(gensym("cos~"), (t_newmethod)cos_new, 0,
+ sizeof(t_cos), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(cos_class, t_cos, x_f);
+ class_addmethod(cos_class, (t_method)cos_dsp, gensym("dsp"), 0);
+ cos_maketable();
+}
+
+/* ------------------------ osc~ ----------------------------- */
+
+static t_class *osc_class, *scalarosc_class;
+
+typedef struct _osc
+{
+ t_object x_obj;
+ double x_phase;
+ float x_conv;
+ float x_f; /* frequency if scalar */
+} t_osc;
+
+static void *osc_new(t_floatarg f)
+{
+ t_osc *x = (t_osc *)pd_new(osc_class);
+ x->x_f = f;
+ outlet_new(&x->x_obj, gensym("signal"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
+ x->x_phase = 0;
+ x->x_conv = 0;
+ return (x);
+}
+
+static t_int *osc_perform(t_int *w)
+{
+ t_osc *x = (t_osc *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ t_float *out = (t_float *)(w[3]);
+ int n = (int)(w[4]);
+ float *tab = cos_table, *addr, f1, f2, frac;
+ double dphase = x->x_phase + UNITBIT32;
+ int normhipart;
+ union tabfudge tf;
+ float conv = x->x_conv;
+
+ tf.tf_d = UNITBIT32;
+ normhipart = tf.tf_i[HIOFFSET];
+#if 0
+ while (n--)
+ {
+ tf.tf_d = dphase;
+ dphase += *in++ * conv;
+ addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
+ tf.tf_i[HIOFFSET] = normhipart;
+ frac = tf.tf_d - UNITBIT32;
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+ }
+#endif
+#if 1
+ tf.tf_d = dphase;
+ dphase += *in++ * conv;
+ addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
+ tf.tf_i[HIOFFSET] = normhipart;
+ frac = tf.tf_d - UNITBIT32;
+ while (--n)
+ {
+ tf.tf_d = dphase;
+ f1 = addr[0];
+ dphase += *in++ * conv;
+ f2 = addr[1];
+ addr = tab + (tf.tf_i[HIOFFSET] & (COSTABSIZE-1));
+ tf.tf_i[HIOFFSET] = normhipart;
+ *out++ = f1 + frac * (f2 - f1);
+ frac = tf.tf_d - UNITBIT32;
+ }
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+#endif
+
+ tf.tf_d = UNITBIT32 * COSTABSIZE;
+ normhipart = tf.tf_i[HIOFFSET];
+ tf.tf_d = dphase + (UNITBIT32 * COSTABSIZE - UNITBIT32);
+ tf.tf_i[HIOFFSET] = normhipart;
+ x->x_phase = tf.tf_d - UNITBIT32 * COSTABSIZE;
+ return (w+5);
+}
+
+static void osc_dsp(t_osc *x, t_signal **sp)
+{
+ x->x_conv = COSTABSIZE/sp[0]->s_sr;
+ dsp_add(osc_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void osc_ft1(t_osc *x, t_float f)
+{
+ x->x_phase = COSTABSIZE * f;
+}
+
+static void osc_setup(void)
+{
+ osc_class = class_new(gensym("osc~"), (t_newmethod)osc_new, 0,
+ sizeof(t_osc), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(osc_class, t_osc, x_f);
+ class_addmethod(osc_class, (t_method)osc_dsp, gensym("dsp"), 0);
+ class_addmethod(osc_class, (t_method)osc_ft1, gensym("ft1"), A_FLOAT, 0);
+
+ cos_maketable();
+}
+
+/* ---------------- vcf~ - 2-pole bandpass filter. ----------------- */
+
+typedef struct vcfctl
+{
+ float c_re;
+ float c_im;
+ float c_q;
+ float c_isr;
+} t_vcfctl;
+
+typedef struct sigvcf
+{
+ t_object x_obj;
+ t_vcfctl x_cspace;
+ t_vcfctl *x_ctl;
+ float x_f;
+} t_sigvcf;
+
+t_class *sigvcf_class;
+
+static void *sigvcf_new(t_floatarg q)
+{
+ t_sigvcf *x = (t_sigvcf *)pd_new(sigvcf_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_ctl = &x->x_cspace;
+ x->x_cspace.c_re = 0;
+ x->x_cspace.c_im = 0;
+ x->x_cspace.c_q = q;
+ x->x_cspace.c_isr = 0;
+ x->x_f = 0;
+ return (x);
+}
+
+static void sigvcf_ft1(t_sigvcf *x, t_floatarg f)
+{
+ x->x_ctl->c_q = (f > 0 ? f : 0.f);
+}
+
+static t_int *sigvcf_perform(t_int *w)
+{
+ float *in1 = (float *)(w[1]);
+ float *in2 = (float *)(w[2]);
+ float *out1 = (float *)(w[3]);
+ float *out2 = (float *)(w[4]);
+ t_vcfctl *c = (t_vcfctl *)(w[5]);
+ int n = (t_int)(w[6]);
+ int i;
+ float re = c->c_re, re2;
+ float im = c->c_im;
+ float q = c->c_q;
+ float qinv = (q > 0? 1.0f/q : 0);
+ float ampcorrect = 2.0f - 2.0f / (q + 2.0f);
+ float isr = c->c_isr;
+ float coefr, coefi;
+ float *tab = cos_table, *addr, f1, f2, frac;
+ double dphase;
+ int normhipart, tabindex;
+ union tabfudge tf;
+
+ tf.tf_d = UNITBIT32;
+ normhipart = tf.tf_i[HIOFFSET];
+
+ for (i = 0; i < n; i++)
+ {
+ float cf, cfindx, r, oneminusr;
+ cf = *in2++ * isr;
+ if (cf < 0) cf = 0;
+ cfindx = cf * (float)(COSTABSIZE/6.28318f);
+ r = (qinv > 0 ? 1 - cf * qinv : 0);
+ if (r < 0) r = 0;
+ oneminusr = 1.0f - r;
+ dphase = ((double)(cfindx)) + UNITBIT32;
+ tf.tf_d = dphase;
+ tabindex = tf.tf_i[HIOFFSET] & (COSTABSIZE-1);
+ addr = tab + tabindex;
+ tf.tf_i[HIOFFSET] = normhipart;
+ frac = tf.tf_d - UNITBIT32;
+ f1 = addr[0];
+ f2 = addr[1];
+ coefr = r * (f1 + frac * (f2 - f1));
+
+ addr = tab + ((tabindex - (COSTABSIZE/4)) & (COSTABSIZE-1));
+ f1 = addr[0];
+ f2 = addr[1];
+ coefi = r * (f1 + frac * (f2 - f1));
+
+ f1 = *in1++;
+ re2 = re;
+ *out1++ = re = ampcorrect * oneminusr * f1
+ + coefr * re2 - coefi * im;
+ *out2++ = im = coefi * re2 + coefr * im;
+ }
+ c->c_re = re;
+ c->c_im = im;
+ return (w+7);
+}
+
+static void sigvcf_dsp(t_sigvcf *x, t_signal **sp)
+{
+ x->x_ctl->c_isr = 6.28318f/sp[0]->s_sr;
+ dsp_add(sigvcf_perform, 6,
+ sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec,
+ x->x_ctl, sp[0]->s_n);
+
+}
+
+void sigvcf_setup(void)
+{
+ sigvcf_class = class_new(gensym("vcf~"), (t_newmethod)sigvcf_new, 0,
+ sizeof(t_sigvcf), 0, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(sigvcf_class, t_sigvcf, x_f);
+ class_addmethod(sigvcf_class, (t_method)sigvcf_dsp, gensym("dsp"), 0);
+ class_addmethod(sigvcf_class, (t_method)sigvcf_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+}
+
+/* -------------------------- noise~ ------------------------------ */
+static t_class *noise_class;
+
+typedef struct _noise
+{
+ t_object x_obj;
+ int x_val;
+} t_noise;
+
+static void *noise_new(void)
+{
+ t_noise *x = (t_noise *)pd_new(noise_class);
+ static int init = 307;
+ x->x_val = (init *= 1319);
+ outlet_new(&x->x_obj, gensym("signal"));
+ return (x);
+}
+
+static t_int *noise_perform(t_int *w)
+{
+ t_float *out = (t_float *)(w[1]);
+ int *vp = (int *)(w[2]);
+ int n = (int)(w[3]);
+ int val = *vp;
+ while (n--)
+ {
+ *out++ = ((float)((val & 0x7fffffff) - 0x40000000)) *
+ (float)(1.0 / 0x40000000);
+ val = val * 435898247 + 382842987;
+ }
+ *vp = val;
+ return (w+4);
+}
+
+static void noise_dsp(t_noise *x, t_signal **sp)
+{
+ dsp_add(noise_perform, 3, sp[0]->s_vec, &x->x_val, sp[0]->s_n);
+}
+
+static void noise_setup(void)
+{
+ noise_class = class_new(gensym("noise~"), (t_newmethod)noise_new, 0,
+ sizeof(t_noise), 0, 0);
+ class_addmethod(noise_class, (t_method)noise_dsp, gensym("dsp"), 0);
+}
+
+
+/* ----------------------- global setup routine ---------------- */
+void d_osc_setup(void)
+{
+ phasor_setup();
+ cos_setup();
+ osc_setup();
+ sigvcf_setup();
+ noise_setup();
+}
+
diff --git a/pd/src/d_resample.c b/pd/src/d_resample.c
new file mode 100644
index 00000000..83ed7498
--- /dev/null
+++ b/pd/src/d_resample.c
@@ -0,0 +1,225 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* upsampling/downsampling methods for inlet~/outlet~
+ *
+ * mfg.gfd.uil
+ * IOhannes
+ *
+ * 2509:forum::für::umläute:2001
+ */
+
+
+
+#include "m_pd.h"
+
+/* --------------------- up/down-sampling --------------------- */
+t_int *downsampling_perform_0(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]); /* original signal */
+ t_float *out = (t_float *)(w[2]); /* downsampled signal */
+ int down = (int)(w[3]); /* downsampling factor */
+ int parent = (int)(w[4]); /* original vectorsize */
+
+ int n=parent/down;
+
+ while(n--){
+ *out++=*in;
+ in+=down;
+ }
+
+ return (w+5);
+}
+
+t_int *upsampling_perform_0(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]); /* original signal */
+ t_float *out = (t_float *)(w[2]); /* upsampled signal */
+ int up = (int)(w[3]); /* upsampling factor */
+ int parent = (int)(w[4]); /* original vectorsize */
+
+ int n=parent*up;
+ t_float *dummy = out;
+
+ while(n--)*out++=0;
+
+ n = parent;
+ out = dummy;
+ while(n--){
+ *out=*in++;
+ out+=up;
+ }
+
+ return (w+5);
+}
+
+t_int *upsampling_perform_hold(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]); /* original signal */
+ t_float *out = (t_float *)(w[2]); /* upsampled signal */
+ int up = (int)(w[3]); /* upsampling factor */
+ int parent = (int)(w[4]); /* original vectorsize */
+ int i=up;
+
+ int n=parent;
+ t_float *dum_out = out;
+ t_float *dum_in = in;
+
+ while (i--) {
+ n = parent;
+ out = dum_out+i;
+ in = dum_in;
+ while(n--){
+ *out=*in++;
+ out+=up;
+ }
+ }
+ return (w+5);
+}
+
+t_int *upsampling_perform_linear(t_int *w)
+{
+ t_resample *x= (t_resample *)(w[1]);
+ t_float *in = (t_float *)(w[2]); /* original signal */
+ t_float *out = (t_float *)(w[3]); /* upsampled signal */
+ int up = (int)(w[4]); /* upsampling factor */
+ int parent = (int)(w[5]); /* original vectorsize */
+ int length = parent*up;
+ int n;
+ t_float *fp;
+ t_float a=*x->buffer, b=*in;
+
+
+ for (n=0; n<length; n++) {
+ t_float findex = (t_float)(n+1)/up;
+ int index = findex;
+ t_float frac=findex - index;
+ if (frac==0.)frac=1.;
+ *out++ = frac * b + (1.-frac) * a;
+ fp = in+index;
+ b=*fp;
+ a=(index)?*(fp-1):a;
+ }
+
+ *x->buffer = a;
+ return (w+6);
+}
+
+/* ----------------------- public -------------------------------- */
+
+/* utils */
+
+void resample_init(t_resample *x)
+{
+ x->method=0;
+
+ x->downsample=x->upsample=1;
+
+ x->s_n = x->coefsize = x->bufsize = 0;
+ x->s_vec = x->coeffs = x->buffer = 0;
+}
+
+void resample_free(t_resample *x)
+{
+ if (x->s_n) t_freebytes(x->s_vec, x->s_n*sizeof(*x->s_vec));
+ if (x->coefsize) t_freebytes(x->coeffs, x->coefsize*sizeof(*x->coeffs));
+ if (x->bufsize) t_freebytes(x->buffer, x->bufsize*sizeof(*x->buffer));
+
+ x->s_n = x->coefsize = x->bufsize = 0;
+ x->s_vec = x->coeffs = x->buffer = 0;
+}
+
+
+/* dsp-adding */
+
+void resample_dsp(t_resample *x,
+ t_sample* in, int insize,
+ t_sample* out, int outsize,
+ int method)
+{
+ if (insize == outsize){
+ bug("nothing to be done");
+ return;
+ }
+
+ if (insize > outsize) { /* downsampling */
+ if (insize % outsize) {
+ error("bad downsampling factor");
+ return;
+ }
+ switch (method) {
+ default:
+ dsp_add(downsampling_perform_0, 4, in, out, insize/outsize, insize);
+ }
+
+
+ } else { /* upsampling */
+ if (outsize % insize) {
+ error("bad upsampling factor");
+ return;
+ }
+ switch (method) {
+ case 1:
+ dsp_add(upsampling_perform_hold, 4, in, out, outsize/insize, insize);
+ break;
+ case 2:
+ if (x->bufsize != 1) {
+ t_freebytes(x->buffer, x->bufsize*sizeof(*x->buffer));
+ x->bufsize = 1;
+ x->buffer = t_getbytes(x->bufsize*sizeof(*x->buffer));
+ }
+ dsp_add(upsampling_perform_linear, 5, x, in, out, outsize/insize, insize);
+ break;
+ default:
+ dsp_add(upsampling_perform_0, 4, in, out, outsize/insize, insize);
+ }
+ }
+}
+
+void resamplefrom_dsp(t_resample *x,
+ t_sample *in,
+ int insize, int outsize, int method)
+{
+ if (insize==outsize) {
+ t_freebytes(x->s_vec, x->s_n * sizeof(*x->s_vec));
+ x->s_n = 0;
+ x->s_vec = in;
+ return;
+ }
+
+ if (x->s_n != outsize) {
+ t_float *buf=x->s_vec;
+ t_freebytes(buf, x->s_n * sizeof(*buf));
+ buf = (t_float *)t_getbytes(outsize * sizeof(*buf));
+ x->s_vec = buf;
+ x->s_n = outsize;
+ }
+
+ resample_dsp(x, in, insize, x->s_vec, x->s_n, method);
+ return;
+}
+
+void resampleto_dsp(t_resample *x,
+ t_sample *out,
+ int insize, int outsize, int method)
+{
+ if (insize==outsize) {
+ if (x->s_n)t_freebytes(x->s_vec, x->s_n * sizeof(*x->s_vec));
+ x->s_n = 0;
+ x->s_vec = out;
+ return;
+ }
+
+ if (x->s_n != insize) {
+ t_float *buf=x->s_vec;
+ t_freebytes(buf, x->s_n * sizeof(*buf));
+ buf = (t_float *)t_getbytes(insize * sizeof(*buf));
+ x->s_vec = buf;
+ x->s_n = insize;
+ }
+
+ resample_dsp(x, x->s_vec, x->s_n, out, outsize, method);
+
+ return;
+}
diff --git a/pd/src/d_soundfile.c b/pd/src/d_soundfile.c
new file mode 100644
index 00000000..33de90b7
--- /dev/null
+++ b/pd/src/d_soundfile.c
@@ -0,0 +1,2200 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* this file contains, first, a collection of soundfile access routines, a
+sort of soundfile library. Second, the "soundfiler" object is defined which
+uses the routines to read or write soundfiles, synchronously, from garrays.
+These operations are not to be done in "real time" as they may have to wait
+for disk accesses (even the write routine.) Finally, the realtime objects
+readsf~ and writesf~ are defined which confine disk operations to a separate
+thread so that they can be used in real time. The real-time disk access
+objects are available for linux only so far, although they could be compiled
+for Windows if someone were willing to find a Pthreads package for it. */
+
+#ifdef UNIX
+#include <unistd.h>
+#include <fcntl.h>
+#endif
+#include <pthread.h>
+#ifdef NT
+#include <io.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "m_pd.h"
+
+#define MAXSFCHANS 64
+
+/***************** soundfile header structures ************************/
+
+typedef unsigned short uint16;
+typedef unsigned long uint32;
+
+#define FORMAT_WAVE 0
+#define FORMAT_AIFF 1
+#define FORMAT_NEXT 2
+
+/* the NeXTStep sound header structure; can be big or little endian */
+
+typedef struct _nextstep
+{
+ char ns_fileid[4]; /* magic number '.snd' if file is big-endian */
+ uint32 ns_onset; /* byte offset of first sample */
+ uint32 ns_length; /* length of sound in bytes */
+ uint32 ns_format; /* format; see below */
+ uint32 ns_sr; /* sample rate */
+ uint32 ns_nchans; /* number of channels */
+ char ns_info[4]; /* comment */
+} t_nextstep;
+
+#define NS_FORMAT_LINEAR_16 3
+#define NS_FORMAT_LINEAR_24 4
+#define NS_FORMAT_FLOAT 6
+#define SCALE (1./(1024. * 1024. * 1024. * 2.))
+
+/* the WAVE header. All Wave files are little endian. We assume
+ the "fmt" chunk comes first which is usually the case but perhaps not
+ always; same for AIFF and the "COMM" chunk. */
+
+typedef unsigned word;
+typedef unsigned long dword;
+
+typedef struct _wave
+{
+ char w_fileid[4]; /* chunk id 'RIFF' */
+ uint32 w_chunksize; /* chunk size */
+ char w_waveid[4]; /* wave chunk id 'WAVE' */
+ char w_fmtid[4]; /* format chunk id 'fmt ' */
+ uint32 w_fmtchunksize; /* format chunk size */
+ uint16 w_fmttag; /* format tag, 1 for PCM */
+ uint16 w_nchannels; /* number of channels */
+ uint32 w_samplespersec; /* sample rate in hz */
+ uint32 w_navgbytespersec; /* average bytes per second */
+ uint16 w_nblockalign; /* number of bytes per frame */
+ uint16 w_nbitspersample; /* number of bits in a sample */
+ char w_datachunkid[4]; /* data chunk id 'data' */
+ uint32 w_datachunksize; /* length of data chunk */
+} t_wave;
+
+typedef struct _fmt /* format chunk */
+{
+ uint16 f_fmttag; /* format tag, 1 for PCM */
+ uint16 f_nchannels; /* number of channels */
+ uint32 f_samplespersec; /* sample rate in hz */
+ uint32 f_navgbytespersec; /* average bytes per second */
+ uint16 f_nblockalign; /* number of bytes per frame */
+ uint16 f_nbitspersample; /* number of bits in a sample */
+} t_fmt;
+
+typedef struct _wavechunk /* ... and the last two items */
+{
+ char wc_id[4]; /* data chunk id, e.g., 'data' or 'fmt ' */
+ uint32 wc_size; /* length of data chunk */
+} t_wavechunk;
+
+/* the AIFF header. I'm assuming AIFC is compatible but don't really know
+ that. */
+
+typedef struct _datachunk
+{
+ char dc_id[4]; /* data chunk id 'SSND' */
+ uint32 dc_size; /* length of data chunk */
+} t_datachunk;
+
+typedef struct _comm
+{
+ uint16 c_nchannels; /* number of channels */
+ uint16 c_nframeshi; /* # of sample frames (hi) */
+ uint16 c_nframeslo; /* # of sample frames (lo) */
+ uint16 c_bitspersamp; /* bits per sample */
+ unsigned char c_samprate[10]; /* sample rate, 80-bit float! */
+} t_comm;
+
+ /* this version is more convenient for writing them out: */
+typedef struct _aiff
+{
+ char a_fileid[4]; /* chunk id 'FORM' */
+ uint32 a_chunksize; /* chunk size */
+ char a_aiffid[4]; /* aiff chunk id 'AIFF' */
+ char a_fmtid[4]; /* format chunk id 'COMM' */
+ uint32 a_fmtchunksize; /* format chunk size, 18 */
+ uint16 a_nchannels; /* number of channels */
+ uint16 a_nframeshi; /* # of sample frames (hi) */
+ uint16 a_nframeslo; /* # of sample frames (lo) */
+ uint16 a_bitspersamp; /* bits per sample */
+ unsigned char a_samprate[10]; /* sample rate, 80-bit float! */
+} t_aiff;
+
+#define AIFFHDRSIZE 38 /* probably not what sizeof() gives */
+
+
+#define AIFFPLUS (AIFFHDRSIZE + 8) /* header size including first chunk hdr */
+
+#define WHDR1 sizeof(t_nextstep)
+#define WHDR2 (sizeof(t_wave) > WHDR1 ? sizeof (t_wave) : WHDR1)
+#define WRITEHDRSIZE (AIFFPLUS > WHDR2 ? AIFFPLUS : WHDR2)
+
+#define READHDRSIZE (16 > WHDR2 + 2 ? 16 : WHDR2 + 2)
+
+#define OBUFSIZE MAXPDSTRING /* assume MAXPDSTRING is bigger than headers */
+
+#ifdef NT
+#include <fcntl.h>
+#define BINCREATE _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY
+#else
+#define BINCREATE O_WRONLY | O_CREAT | O_TRUNC
+#endif
+
+/* this routine returns 1 if the high order byte comes at the lower
+address on our architecture (big-endianness.). It's 1 for Motorola,
+0 for Intel: */
+
+extern int garray_ambigendian(void);
+
+/* byte swappers */
+
+static uint32 swap4(uint32 n, int doit)
+{
+ if (doit)
+ return (((n & 0xff) << 24) | ((n & 0xff00) << 8) |
+ ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24));
+ else return (n);
+}
+
+static uint16 swap2(uint32 n, int doit)
+{
+ if (doit)
+ return (((n & 0xff) << 8) | ((n & 0xff00) >> 8));
+ else return (n);
+}
+
+static void swapstring(char *foo, int doit)
+{
+ if (doit)
+ {
+ char a = foo[0], b = foo[1], c = foo[2], d = foo[3];
+ foo[0] = d; foo[1] = c; foo[2] = b; foo[3] = a;
+ }
+}
+
+/******************** soundfile access routines **********************/
+
+void readsf_banana( void); /* debugging */
+
+/* This routine opens a file, looks for either a nextstep or "wave" header,
+* seeks to end of it, and fills in bytes per sample and number of channels.
+* Only 2- and 3-byte fixed-point samples and 4-byte floating point samples
+* are supported. If "headersize" is nonzero, the
+* caller should supply the number of channels, endinanness, and bytes per
+* sample; the header is ignored. Otherwise, the routine tries to read the
+* header and fill in the properties.
+*/
+
+int open_soundfile(const char *dirname, const char *filename, int headersize,
+ int *p_bytespersamp, int *p_bigendian, int *p_nchannels, long *p_bytelimit,
+ long skipframes)
+{
+ char buf[OBUFSIZE], *bufptr;
+ int fd, format, nchannels, bigendian, bytespersamp, swap, sysrtn;
+ long bytelimit = 0x7fffffff;
+ errno = 0;
+ fd = open_via_path(dirname, filename,
+ "", buf, &bufptr, MAXPDSTRING, 1);
+ if (fd < 0)
+ return (-1);
+ if (headersize >= 0) /* header detection overridden */
+ {
+ bigendian = *p_bigendian;
+ nchannels = *p_nchannels;
+ bytespersamp = *p_bytespersamp;
+ bytelimit = *p_bytelimit;
+ }
+ else
+ {
+ int bytesread = read(fd, buf, READHDRSIZE);
+ int format;
+ if (bytesread < 4)
+ goto badheader;
+ if (!strncmp(buf, ".snd", 4))
+ format = FORMAT_NEXT, bigendian = 1;
+ else if (!strncmp(buf, "dns.", 4))
+ format = FORMAT_NEXT, bigendian = 0;
+ else if (!strncmp(buf, "RIFF", 4))
+ {
+ if (bytesread < 12 || strncmp(buf + 8, "WAVE", 4))
+ goto badheader;
+ format = FORMAT_WAVE, bigendian = 0;
+ }
+ else if (!strncmp(buf, "FORM", 4))
+ {
+ if (bytesread < 12 || strncmp(buf + 8, "AIFF", 4))
+ goto badheader;
+ format = FORMAT_AIFF, bigendian = 1;
+ }
+ else
+ goto badheader;
+ swap = (bigendian != garray_ambigendian());
+ if (format == FORMAT_NEXT) /* nextstep header */
+ {
+ uint32 param;
+ if (bytesread < (int)sizeof(t_nextstep))
+ goto badheader;
+ nchannels = swap4(((t_nextstep *)buf)->ns_nchans, swap);
+ format = swap4(((t_nextstep *)buf)->ns_format, swap);
+ headersize = swap4(((t_nextstep *)buf)->ns_onset, swap);
+ if (format == NS_FORMAT_LINEAR_16)
+ bytespersamp = 2;
+ else if (format == NS_FORMAT_LINEAR_24)
+ bytespersamp = 3;
+ else if (format == NS_FORMAT_FLOAT)
+ bytespersamp = 4;
+ else goto badheader;
+ bytelimit = 0x7fffffff;
+ }
+ else if (format == FORMAT_WAVE) /* wave header */
+ {
+ /* This is awful. You have to skip over chunks,
+ except that if one happens to be a "fmt" chunk, you want to
+ find out the format from that one. The case where the
+ "fmt" chunk comes after the audio isn't handled. */
+ headersize = 12;
+ if (bytesread < 20)
+ goto badheader;
+ /* First we guess a number of channels, etc., in case there's
+ no "fmt" chunk to follow. */
+ nchannels = 1;
+ bytespersamp = 2;
+ /* copy the first chunk header to beginnning of buffer. */
+ memcpy(buf, buf + headersize, sizeof(t_wavechunk));
+ /* post("chunk %c %c %c %c",
+ ((t_wavechunk *)buf)->wc_id[0],
+ ((t_wavechunk *)buf)->wc_id[1],
+ ((t_wavechunk *)buf)->wc_id[2],
+ ((t_wavechunk *)buf)->wc_id[3]); */
+ /* read chunks in loop until we get to the data chunk */
+ while (strncmp(((t_wavechunk *)buf)->wc_id, "data", 4))
+ {
+ long chunksize = swap4(((t_wavechunk *)buf)->wc_size,
+ swap), seekto = headersize + chunksize + 8, seekout;
+
+ if (!strncmp(((t_wavechunk *)buf)->wc_id, "fmt ", 4))
+ {
+ long commblockonset = headersize + 8;
+ seekout = lseek(fd, commblockonset, SEEK_SET);
+ if (seekout != commblockonset)
+ goto badheader;
+ if (read(fd, buf, sizeof(t_fmt)) < (int) sizeof(t_fmt))
+ goto badheader;
+ nchannels = swap2(((t_fmt *)buf)->f_nchannels, swap);
+ format = swap2(((t_fmt *)buf)->f_nbitspersample, swap);
+ if (format == 16)
+ bytespersamp = 2;
+ else if (format == 24)
+ bytespersamp = 3;
+ else if (format == 32)
+ bytespersamp = 4;
+ else goto badheader;
+ }
+ seekout = lseek(fd, seekto, SEEK_SET);
+ if (seekout != seekto)
+ goto badheader;
+ if (read(fd, buf, sizeof(t_wavechunk)) <
+ (int) sizeof(t_wavechunk))
+ goto badheader;
+ /* post("new chunk %c %c %c %c at %d",
+ ((t_wavechunk *)buf)->wc_id[0],
+ ((t_wavechunk *)buf)->wc_id[1],
+ ((t_wavechunk *)buf)->wc_id[2],
+ ((t_wavechunk *)buf)->wc_id[3], seekto); */
+ headersize = seekto;
+ }
+ bytelimit = swap4(((t_wavechunk *)buf)->wc_size, swap);
+ headersize += 8;
+ }
+ else
+ {
+ /* AIFF. same as WAVE; actually predates it. Disgusting. */
+ headersize = 12;
+ if (bytesread < 20)
+ goto badheader;
+ /* First we guess a number of channels, etc., in case there's
+ no COMM block to follow. */
+ nchannels = 1;
+ bytespersamp = 2;
+ /* copy the first chunk header to beginnning of buffer. */
+ memcpy(buf, buf + headersize, sizeof(t_datachunk));
+ /* read chunks in loop until we get to the data chunk */
+ while (strncmp(((t_datachunk *)buf)->dc_id, "SSND", 4))
+ {
+ long chunksize = swap4(((t_datachunk *)buf)->dc_size,
+ swap), seekto = headersize + chunksize + 8, seekout;
+ /* post("chunk %c %c %c %c seek %d",
+ ((t_datachunk *)buf)->dc_id[0],
+ ((t_datachunk *)buf)->dc_id[1],
+ ((t_datachunk *)buf)->dc_id[2],
+ ((t_datachunk *)buf)->dc_id[3], seekto); */
+ if (!strncmp(((t_datachunk *)buf)->dc_id, "COMM", 4))
+ {
+ long commblockonset = headersize + 8;
+ seekout = lseek(fd, commblockonset, SEEK_SET);
+ if (seekout != commblockonset)
+ goto badheader;
+ if (read(fd, buf, sizeof(t_comm)) <
+ (int) sizeof(t_comm))
+ goto badheader;
+ nchannels = swap2(((t_comm *)buf)->c_nchannels, swap);
+ format = swap2(((t_comm *)buf)->c_bitspersamp, swap);
+ if (format == 16)
+ bytespersamp = 2;
+ else if (format == 24)
+ bytespersamp = 3;
+ else goto badheader;
+ }
+ seekout = lseek(fd, seekto, SEEK_SET);
+ if (seekout != seekto)
+ goto badheader;
+ if (read(fd, buf, sizeof(t_datachunk)) <
+ (int) sizeof(t_datachunk))
+ goto badheader;
+ headersize = seekto;
+ }
+ bytelimit = swap4(((t_datachunk *)buf)->dc_size, swap);
+ headersize += 8;
+ }
+ }
+ /* seek past header and any sample frames to skip */
+ sysrtn = lseek(fd, nchannels * bytespersamp * skipframes + headersize, 0);
+ if (sysrtn != nchannels * bytespersamp * skipframes + headersize)
+ return (-1);
+ /* copy sample format back to caller */
+ *p_bigendian = bigendian;
+ *p_nchannels = nchannels;
+ *p_bytespersamp = bytespersamp;
+ *p_bytelimit = bytelimit;
+ return (fd);
+badheader:
+ /* the header wasn't recognized. We're threadable here so let's not
+ print out the error... */
+ errno = EIO;
+ return (-1);
+}
+
+static void soundfile_xferin(int sfchannels, int nvecs, float **vecs,
+ long itemsread, unsigned char *buf, int nitems, int bytespersamp,
+ int bigendian)
+{
+ int i, j;
+ unsigned char *sp, *sp2;
+ float *fp;
+ int nchannels = (sfchannels < nvecs ? sfchannels : nvecs);
+ int bytesperframe = bytespersamp * sfchannels;
+ for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp)
+ {
+ if (bytespersamp == 2)
+ {
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16));
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *fp = SCALE * ((sp2[1] << 24) | (sp2[0] << 16));
+ }
+ }
+ else if (bytespersamp == 3)
+ {
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *fp = SCALE * ((sp2[0] << 24) | (sp2[1] << 16)
+ | (sp2[2] << 8));
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *fp = SCALE * ((sp2[2] << 24) | (sp2[1] << 16)
+ | (sp2[0] << 8));
+ }
+ }
+ else if (bytespersamp == 4)
+ {
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *(long *)fp = ((sp2[0] << 24) | (sp2[1] << 16)
+ | (sp2[2] << 8) | sp2[3]);
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ *(long *)fp = ((sp2[3] << 24) | (sp2[2] << 16)
+ | (sp2[1] << 8) | sp2[0]);
+ }
+ }
+ }
+ /* zero out other outputs */
+ for (i = sfchannels; i < nvecs; i++)
+ for (j = nitems, fp = vecs[i]; j--; )
+ *fp++ = 0;
+
+}
+
+ /* soundfiler_write ...
+
+ usage: write [flags] filename table ...
+ flags:
+ -nframes <frames>
+ -skip <frames>
+ -bytes <bytes per sample>
+ -normalize
+ -nextstep
+ -wave
+ -big
+ -little
+ */
+
+ /* the routine which actually does the work should LATER also be called
+ from garray_write16. */
+
+
+ /* Parse arguments for writing. The "obj" argument is only for flagging
+ errors. For streaming to a file the "normalize", "onset" and "nframes"
+ arguments shouldn't be set but the calling routine flags this. */
+
+static int soundfiler_writeargparse(void *obj, int *p_argc, t_atom **p_argv,
+ t_symbol **p_filesym,
+ int *p_filetype, int *p_bytespersamp, int *p_swap, int *p_bigendian,
+ int *p_normalize, long *p_onset, long *p_nframes)
+{
+ int argc = *p_argc;
+ t_atom *argv = *p_argv;
+ int bytespersamp = 2, bigendian = 0,
+ endianness = -1, swap, filetype = FORMAT_WAVE, normalize = 0;
+ long onset = 0, nframes = 0x7fffffff;
+ t_symbol *filesym;
+ while (argc > 0 && argv->a_type == A_SYMBOL &&
+ *argv->a_w.w_symbol->s_name == '-')
+ {
+ char *flag = argv->a_w.w_symbol->s_name + 1;
+ if (!strcmp(flag, "skip"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((onset = argv[1].a_w.w_float) < 0))
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(flag, "nframes"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((nframes = argv[1].a_w.w_float) < 0))
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(flag, "bytes"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((bytespersamp = argv[1].a_w.w_float) < 2) ||
+ bytespersamp > 4)
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(flag, "normalize"))
+ {
+ normalize = 1;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "wave"))
+ {
+ filetype = FORMAT_WAVE;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "nextstep"))
+ {
+ filetype = FORMAT_NEXT;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "aiff"))
+ {
+ filetype = FORMAT_AIFF;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "big"))
+ {
+ endianness = 1;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "little"))
+ {
+ endianness = 1;
+ argc -= 1; argv += 1;
+ }
+ else goto usage;
+ }
+ /* only NextStep handles floating point samples */
+ if (bytespersamp == 4)
+ filetype = FORMAT_NEXT;
+
+ /* for WAVE force little endian; for nextstep use machine native */
+ if (filetype == FORMAT_WAVE)
+ {
+ bigendian = 0;
+ if (endianness == 1)
+ pd_error(obj, "WAVE file forced to little endian");
+ }
+ else if (filetype == FORMAT_AIFF)
+ {
+ bigendian = 1;
+ if (endianness == 0)
+ pd_error(obj, "AIFF file forced to big endian");
+ }
+ else if (endianness == -1)
+ {
+ bigendian = garray_ambigendian();
+ }
+ swap = (bigendian != garray_ambigendian());
+ if (!argc || argv->a_type != A_SYMBOL)
+ goto usage;
+ filesym = argv->a_w.w_symbol;
+ argc--; argv++;
+
+ *p_argc = argc;
+ *p_argv = argv;
+ *p_filesym = filesym;
+ *p_filetype = filetype;
+ *p_bytespersamp = bytespersamp;
+ *p_swap = swap;
+ *p_normalize = normalize;
+ *p_onset = onset;
+ *p_nframes = nframes;
+ *p_bigendian = bigendian;
+ return (0);
+usage:
+ return (-1);
+}
+
+static int create_soundfile(t_canvas *canvas, const char *filename,
+ int filetype, int nframes, int bytespersamp,
+ int bigendian, int nchannels, int swap)
+{
+ char filenamebuf[MAXPDSTRING], buf2[MAXPDSTRING];
+ char headerbuf[WRITEHDRSIZE];
+ t_wave *wavehdr = (t_wave *)headerbuf;
+ t_nextstep *nexthdr = (t_nextstep *)headerbuf;
+ t_aiff *aiffhdr = (t_aiff *)headerbuf;
+ int fd, headersize = 0;
+
+ strncpy(filenamebuf, filename, MAXPDSTRING-10);
+ filenamebuf[MAXPDSTRING-10] = 0;
+
+ if (filetype == FORMAT_NEXT)
+ {
+ if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".snd"))
+ strcat(filenamebuf, ".snd");
+ if (bigendian)
+ strncpy(nexthdr->ns_fileid, ".snd", 4);
+ else strncpy(nexthdr->ns_fileid, "dns.", 4);
+ nexthdr->ns_onset = swap4(sizeof(*nexthdr), swap);
+ nexthdr->ns_length = 0;
+ nexthdr->ns_format = swap4((bytespersamp == 3 ? NS_FORMAT_LINEAR_24 :
+ (bytespersamp == 4 ? NS_FORMAT_FLOAT : NS_FORMAT_LINEAR_16)), swap);;
+ nexthdr->ns_sr = swap4(44100, swap); /* lie */
+ nexthdr->ns_nchans = swap4(nchannels, swap);
+ strcpy(nexthdr->ns_info, "Pd ");
+ swapstring(nexthdr->ns_info, swap);
+ headersize = sizeof(t_nextstep);
+ }
+ else if (filetype == FORMAT_AIFF)
+ {
+ long datasize = nframes * nchannels * bytespersamp;
+ long longtmp;
+ static unsigned char dogdoo[] =
+ {0x40, 0x0e, 0xac, 0x44, 0, 0, 0, 0, 0, 0, 'S', 'S', 'N', 'D'};
+ if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".aif") &&
+ strcmp(filenamebuf + strlen(filenamebuf)-5, ".aiff"))
+ strcat(filenamebuf, ".aif");
+ strncpy(aiffhdr->a_fileid, "FORM", 4);
+ aiffhdr->a_chunksize = swap4(datasize + sizeof(*aiffhdr) + 4, swap);
+ strncpy(aiffhdr->a_aiffid, "AIFF", 4);
+ strncpy(aiffhdr->a_fmtid, "COMM", 4);
+ aiffhdr->a_fmtchunksize = swap4(18, swap);
+ aiffhdr->a_nchannels = swap2(nchannels, swap);
+ longtmp = swap4(nframes, swap);
+ memcpy(&aiffhdr->a_nframeshi, &longtmp, 4);
+ aiffhdr->a_bitspersamp = swap2(8 * bytespersamp, swap);
+ memcpy(aiffhdr->a_samprate, dogdoo, sizeof(dogdoo));
+ longtmp = swap4(datasize, swap);
+ memcpy(aiffhdr->a_samprate + sizeof(dogdoo), &longtmp, 4);
+ headersize = AIFFPLUS;
+ }
+ else /* WAVE format */
+ {
+ long datasize = nframes * nchannels * bytespersamp;
+ if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".wav"))
+ strcat(filenamebuf, ".wav");
+ strncpy(wavehdr->w_fileid, "RIFF", 4);
+ wavehdr->w_chunksize = swap4(datasize + sizeof(*wavehdr) - 8, swap);
+ strncpy(wavehdr->w_waveid, "WAVE", 4);
+ strncpy(wavehdr->w_fmtid, "fmt ", 4);
+ wavehdr->w_fmtchunksize = swap4(16, swap);
+ wavehdr->w_fmttag = swap2(1, swap);
+ wavehdr->w_nchannels = swap2(nchannels, swap);
+ wavehdr->w_samplespersec = swap4(44100, swap);
+ wavehdr->w_navgbytespersec = swap4(44100 * nchannels * bytespersamp, swap);
+ wavehdr->w_nblockalign = swap2(bytespersamp, swap);
+ wavehdr->w_nbitspersample = swap2(8 * bytespersamp, swap);
+ strncpy(wavehdr->w_datachunkid, "data", 4);
+ wavehdr->w_datachunksize = swap4(datasize, swap);
+ headersize = sizeof(t_wave);
+ }
+
+ canvas_makefilename(canvas, filenamebuf, buf2, MAXPDSTRING);
+ sys_bashfilename(buf2, buf2);
+ if ((fd = open(buf2, BINCREATE, 0666)) < 0)
+ return (-1);
+
+ if (write(fd, headerbuf, headersize) < headersize)
+ {
+ close (fd);
+ return (-1);
+ }
+ return (fd);
+}
+
+static void soundfile_finishwrite(void *obj, char *filename, int fd,
+ int filetype, long nframes, long itemswritten, int bytesperframe, int swap)
+{
+ if (itemswritten < nframes)
+ {
+ if (nframes < 0x7fffffff)
+ pd_error(obj, "soundfiler_write: %d out of %d bytes written",
+ itemswritten, nframes);
+ /* try to fix size fields in header */
+ if (filetype == FORMAT_WAVE)
+ {
+ long datasize = itemswritten * bytesperframe, mofo;
+
+ if (lseek(fd,
+ ((char *)(&((t_wave *)0)->w_chunksize)) - (char *)0,
+ SEEK_SET) == 0)
+ goto baddonewrite;
+ mofo = swap4(datasize + sizeof(t_wave) - 8, swap);
+ if (write(fd, (char *)(&mofo), 4) < 4)
+ goto baddonewrite;
+ if (lseek(fd,
+ ((char *)(&((t_wave *)0)->w_datachunksize)) - (char *)0,
+ SEEK_SET) == 0)
+ goto baddonewrite;
+ mofo = swap4(datasize, swap);
+ if (write(fd, (char *)(&mofo), 4) < 4)
+ goto baddonewrite;
+ }
+ if (filetype == FORMAT_AIFF)
+ {
+ long mofo;
+ if (lseek(fd,
+ ((char *)(&((t_aiff *)0)->a_nframeshi)) - (char *)0,
+ SEEK_SET) == 0)
+ goto baddonewrite;
+ mofo = swap4(nframes, swap);
+ if (write(fd, (char *)(&mofo), 4) < 4)
+ goto baddonewrite;
+ }
+ }
+ return;
+baddonewrite:
+ post("%s: %s", filename, strerror(errno));
+}
+
+static void soundfile_xferout(int nchannels, float **vecs,
+ unsigned char *buf, int nitems, long onset, int bytespersamp,
+ int bigendian, float normalfactor)
+{
+ int i, j;
+ unsigned char *sp, *sp2;
+ float *fp;
+ int bytesperframe = bytespersamp * nchannels;
+ long xx;
+ for (i = 0, sp = buf; i < nchannels; i++, sp += bytespersamp)
+ {
+ if (bytespersamp == 2)
+ {
+ float ff = normalfactor * 32768.;
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp = vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ int xx = 32768. + (*fp * ff);
+ xx -= 32768;
+ if (xx < -32767)
+ xx = -32767;
+ if (xx > 32767)
+ xx = 32767;
+ sp2[0] = (xx >> 8);
+ sp2[1] = xx;
+ }
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ int xx = 32768. + (*fp * ff);
+ xx -= 32768;
+ if (xx < -32767)
+ xx = -32767;
+ if (xx > 32767)
+ xx = 32767;
+ sp2[1] = (xx >> 8);
+ sp2[0] = xx;
+ }
+ }
+ }
+ else if (bytespersamp == 3)
+ {
+ float ff = normalfactor * 8388608.;
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ int xx = 8388608. + (*fp * ff);
+ xx -= 8388608;
+ if (xx < -8388607)
+ xx = -8388607;
+ if (xx > 8388607)
+ xx = 8388607;
+ sp2[0] = (xx >> 16);
+ sp2[1] = (xx >> 8);
+ sp2[2] = xx;
+ }
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ int xx = 8388608. + (*fp * ff);
+ xx -= 8388608;
+ if (xx < -8388607)
+ xx = -8388607;
+ if (xx > 8388607)
+ xx = 8388607;
+ sp2[2] = (xx >> 16);
+ sp2[1] = (xx >> 8);
+ sp2[0] = xx;
+ }
+ }
+ }
+ else if (bytespersamp == 4)
+ {
+ if (bigendian)
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ float f2 = *fp * normalfactor;
+ xx = *(long *)&f2;
+ sp2[0] = (xx >> 24); sp2[1] = (xx >> 24);
+ sp2[2] = (xx >> 24); sp2[3] = xx;
+ }
+ }
+ else
+ {
+ for (j = 0, sp2 = sp, fp=vecs[i] + onset;
+ j < nitems; j++, sp2 += bytesperframe, fp++)
+ {
+ float f2 = *fp * normalfactor;
+ xx = *(long *)&f2;
+ sp2[3] = (xx >> 24); sp2[2] = (xx >> 24);
+ sp2[1] = (xx >> 24); sp2[0] = xx;
+ }
+ }
+ }
+ }
+}
+
+
+/* ------- soundfiler - reads and writes soundfiles to/from "garrays" ---- */
+#define DEFMAXSIZE 4000000 /* default maximum 16 MB per channel */
+#define SAMPBUFSIZE 1024
+
+
+static t_class *soundfiler_class;
+
+typedef struct _soundfiler
+{
+ t_object x_obj;
+ t_canvas *x_canvas;
+} t_soundfiler;
+
+static t_soundfiler *soundfiler_new(void)
+{
+ t_soundfiler *x = (t_soundfiler *)pd_new(soundfiler_class);
+ x->x_canvas = canvas_getcurrent();
+ outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+ /* soundfiler_read ...
+
+ usage: read [flags] filename table ...
+ flags:
+ -skip <frames> ... frames to skip in file
+ -nframes <frames>
+ -onset <frames> ... onset in table to read into (NOT DONE YET)
+ -raw <headersize channels bytes endian>
+ -resize
+ -maxsize <max-size>
+ */
+
+static void soundfiler_read(t_soundfiler *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ int headersize = -1, channels = 0, bytespersamp = 0, bigendian = 0,
+ resize = 0, i, j;
+ long skipframes = 0, nframes = 0, finalsize = 0, itemsleft,
+ maxsize = DEFMAXSIZE, itemsread = 0, bytelimit = 0x7fffffff;
+ int fd = -1;
+ char endianness, *filename;
+ t_garray *garrays[MAXSFCHANS];
+ t_float *vecs[MAXSFCHANS];
+ char sampbuf[SAMPBUFSIZE];
+ int bufframes, nitems;
+ FILE *fp;
+ while (argc > 0 && argv->a_type == A_SYMBOL &&
+ *argv->a_w.w_symbol->s_name == '-')
+ {
+ char *flag = argv->a_w.w_symbol->s_name + 1;
+ if (!strcmp(flag, "skip"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((skipframes = argv[1].a_w.w_float) < 0))
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(flag, "nframes"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((nframes = argv[1].a_w.w_float) < 0))
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(flag, "raw"))
+ {
+ if (argc < 5 ||
+ argv[1].a_type != A_FLOAT ||
+ ((headersize = argv[1].a_w.w_float) < 0) ||
+ argv[2].a_type != A_FLOAT ||
+ ((channels = argv[2].a_w.w_float) < 1) ||
+ (channels > MAXSFCHANS) ||
+ argv[3].a_type != A_FLOAT ||
+ ((bytespersamp = argv[3].a_w.w_float) < 2) ||
+ (bytespersamp > 4) ||
+ argv[4].a_type != A_SYMBOL ||
+ ((endianness = argv[4].a_w.w_symbol->s_name[0]) != 'b'
+ && endianness != 'l' && endianness != 'n'))
+ goto usage;
+ if (endianness == 'b')
+ bigendian = 1;
+ else if (endianness == 'l')
+ bigendian = 0;
+ else
+ bigendian = garray_ambigendian();
+ argc -= 5; argv += 5;
+ }
+ else if (!strcmp(flag, "resize"))
+ {
+ resize = 1;
+ argc -= 1; argv += 1;
+ }
+ else if (!strcmp(flag, "maxsize"))
+ {
+ if (argc < 2 || argv[1].a_type != A_FLOAT ||
+ ((maxsize = argv[1].a_w.w_float) < 0))
+ goto usage;
+ resize = 1; /* maxsize implies resize. */
+ argc -= 2; argv += 2;
+ }
+ else goto usage;
+ }
+ if (argc < 2 || argc > MAXSFCHANS + 1 || argv[0].a_type != A_SYMBOL)
+ goto usage;
+ filename = argv[0].a_w.w_symbol->s_name;
+ argc--; argv++;
+
+ for (i = 0; i < argc; i++)
+ {
+ int vecsize;
+ if (argv[i].a_type != A_SYMBOL)
+ goto usage;
+ if (!(garrays[i] =
+ (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class)))
+ {
+ pd_error(x, "%s: no such table", argv[i].a_w.w_symbol->s_name);
+ goto done;
+ }
+ else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
+ error("%s: bad template for tabwrite",
+ argv[i].a_w.w_symbol->s_name);
+ if (finalsize && finalsize != vecsize && !resize)
+ {
+ post("soundfiler_read: arrays have different lengths; resizing...");
+ resize = 1;
+ }
+ finalsize = vecsize;
+ }
+ fd = open_soundfile(canvas_getdir(x->x_canvas)->s_name, filename,
+ headersize, &bytespersamp, &bigendian, &channels, &bytelimit,
+ skipframes);
+
+ if (fd < 0)
+ {
+ pd_error(x, "soundfiler_read: %s: %s", filename, (errno == EIO ?
+ "unknown or bad header format" : strerror(errno)));
+ goto done;
+ }
+
+ if (resize)
+ {
+ /* figure out what to resize to */
+ long poswas, eofis, framesinfile;
+
+ poswas = lseek(fd, 0, SEEK_CUR);
+ eofis = lseek(fd, 0, SEEK_END);
+ if (poswas < 0 || eofis < 0)
+ {
+ pd_error(x, "lseek failed");
+ goto done;
+ }
+ lseek(fd, poswas, SEEK_SET);
+ framesinfile = (eofis - poswas) / (channels * bytespersamp);
+ if (framesinfile > maxsize)
+ {
+ pd_error(x, "soundfiler_read: truncated to %d elements", maxsize);
+ framesinfile = maxsize;
+ }
+ if (framesinfile > bytelimit / bytespersamp)
+ framesinfile = bytelimit / bytespersamp;
+ finalsize = framesinfile;
+ for (i = 0; i < argc; i++)
+ {
+ int vecsize;
+
+ garray_resize(garrays[i], finalsize);
+ /* for sanity's sake let's clear the save-in-patch flag here */
+ garray_setsaveit(garrays[i], 0);
+ garray_getfloatarray(garrays[i], &vecsize, &vecs[i]);
+ /* if the resize failed, garray_resize reported the error */
+ if (vecsize != framesinfile)
+ {
+ pd_error(x, "resize failed");
+ goto done;
+ }
+ }
+ }
+ if (!finalsize) finalsize = 0x7fffffff;
+ if (finalsize > bytelimit / bytespersamp)
+ finalsize = bytelimit / bytespersamp;
+ fp = fdopen(fd, "rb");
+ bufframes = SAMPBUFSIZE / (channels * bytespersamp);
+
+ for (itemsread = 0; itemsread < finalsize; )
+ {
+ int thisread = finalsize - itemsread;
+ thisread = (thisread > bufframes ? bufframes : thisread);
+ nitems = fread(sampbuf, channels * bytespersamp, thisread, fp);
+ if (nitems <= 0) break;
+ soundfile_xferin(channels, argc, vecs, itemsread,
+ (unsigned char *)sampbuf, nitems, bytespersamp, bigendian);
+ itemsread += nitems;
+ }
+ /* zero out remaining elements of vectors */
+
+ for (i = 0; i < argc; i++)
+ {
+ int nzero, vecsize;
+ garray_getfloatarray(garrays[i], &vecsize, &vecs[i]);
+ for (j = itemsread; j < vecsize; j++)
+ vecs[i][j] = 0;
+ }
+ /* zero out vectors in excess of number of channels */
+ for (i = channels; i < argc; i++)
+ {
+ int vecsize;
+ float *foo;
+ garray_getfloatarray(garrays[i], &vecsize, &foo);
+ for (j = 0; j < vecsize; j++)
+ foo[j] = 0;
+ }
+ /* do all graphics updates */
+ for (i = 0; i < argc; i++)
+ garray_redraw(garrays[i]);
+ fclose(fp);
+ fd = -1;
+ goto done;
+usage:
+ pd_error(x, "usage: read [flags] filename tablename...");
+ post("flags: -skip <n> -nframes <n> -resize -maxsize <n> ...");
+ post("-raw <headerbytes> <channels> <bytespersamp> <endian (b, l, or n)>.");
+done:
+ if (fd >= 0)
+ close (fd);
+ outlet_float(x->x_obj.ob_outlet, (float)itemsread);
+}
+
+ /* this is broken out from soundfiler_write below so garray_write can
+ call it too... not done yet though. */
+
+long soundfiler_dowrite(void *obj, t_canvas *canvas,
+ int argc, t_atom *argv)
+{
+ int headersize, bytespersamp, bigendian,
+ endianness, swap, filetype, normalize, i, j, nchannels;
+ long onset, nframes, itemsleft,
+ maxsize = DEFMAXSIZE, itemswritten = 0;
+ t_garray *garrays[MAXSFCHANS];
+ t_float *vecs[MAXSFCHANS];
+ char sampbuf[SAMPBUFSIZE];
+ int bufframes, nitems;
+ int fd = -1;
+ float normfactor, biggest = 0;
+ t_symbol *filesym;
+
+ if (soundfiler_writeargparse(obj, &argc, &argv, &filesym, &filetype,
+ &bytespersamp, &swap, &bigendian, &normalize, &onset, &nframes))
+ goto usage;
+ nchannels = argc;
+ if (nchannels < 1 || nchannels > MAXSFCHANS)
+ goto usage;
+
+ for (i = 0; i < nchannels; i++)
+ {
+ int vecsize;
+ if (argv[i].a_type != A_SYMBOL)
+ goto usage;
+ if (!(garrays[i] =
+ (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class)))
+ {
+ pd_error(obj, "%s: no such table", argv[i].a_w.w_symbol->s_name);
+ goto fail;
+ }
+ else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
+ error("%s: bad template for tabwrite",
+ argv[i].a_w.w_symbol->s_name);
+ if (nframes > vecsize - onset)
+ nframes = vecsize - onset;
+
+ for (j = 0; j < vecsize; j++)
+ {
+ if (vecs[i][j] > biggest)
+ biggest = vecs[i][j];
+ else if (-vecs[i][j] > biggest)
+ biggest = -vecs[i][j];
+ }
+ }
+ if (nframes <= 0)
+ {
+ pd_error(obj, "soundfiler_write: no samples at onset %ld", onset);
+ goto fail;
+ }
+
+ if ((fd = create_soundfile(canvas, filesym->s_name, filetype,
+ nframes, bytespersamp, bigendian, nchannels,
+ swap)) < 0)
+ {
+ post("%s: %s\n", filesym->s_name, strerror(errno));
+ goto fail;
+ }
+ if (!normalize)
+ {
+ if ((bytespersamp != 4) && (biggest > 1))
+ {
+ post("%s: normalizing max amplitude %f to 1", filesym->s_name, biggest);
+ normalize = 1;
+ }
+ else post("%s: biggest amplitude = %f", filesym->s_name, biggest);
+ }
+ if (normalize)
+ normfactor = (biggest > 0 ? 32767./(32768. * biggest) : 1);
+ else normfactor = 1;
+
+ bufframes = SAMPBUFSIZE / (nchannels * bytespersamp);
+
+ for (itemswritten = 0; itemswritten < nframes; )
+ {
+ int thiswrite = nframes - itemswritten, nitems, nbytes;
+ thiswrite = (thiswrite > bufframes ? bufframes : thiswrite);
+ soundfile_xferout(argc, vecs, (unsigned char *)sampbuf, thiswrite,
+ onset, bytespersamp, bigendian, normfactor);
+ nbytes = write(fd, sampbuf, nchannels * bytespersamp * thiswrite);
+ if (nbytes < nchannels * bytespersamp * thiswrite)
+ {
+ post("%s: %s", filesym->s_name, strerror(errno));
+ if (nbytes > 0)
+ itemswritten += nbytes / (nchannels * bytespersamp);
+ break;
+ }
+ itemswritten += thiswrite;
+ onset += thiswrite;
+ }
+ if (fd >= 0)
+ {
+ soundfile_finishwrite(obj, filesym->s_name, fd,
+ filetype, nframes, itemswritten, nchannels * bytespersamp, swap);
+ close (fd);
+ }
+ return ((float)itemswritten);
+usage:
+ pd_error(obj, "usage: write [flags] filename tablename...");
+ post("flags: -skip <n> -nframes <n> -bytes <n> -wave -aiff -nextstep ...");
+ post("-big -little -normalize");
+ post("(defaults to a 16-bit wave file).");
+fail:
+ if (fd >= 0)
+ close (fd);
+ return (0);
+}
+
+static void soundfiler_write(t_soundfiler *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ long bozo = soundfiler_dowrite(x, x->x_canvas,
+ argc, argv);
+ outlet_float(x->x_obj.ob_outlet, (float)bozo);
+}
+
+static void soundfiler_setup(void)
+{
+ soundfiler_class = class_new(gensym("soundfiler"), (t_newmethod)soundfiler_new,
+ 0, sizeof(t_soundfiler), 0, 0);
+ class_addmethod(soundfiler_class, (t_method)soundfiler_read, gensym("read"),
+ A_GIMME, 0);
+ class_addmethod(soundfiler_class, (t_method)soundfiler_write,
+ gensym("write"), A_GIMME, 0);
+}
+
+
+/************************* readsf object ******************************/
+
+/* READSF uses the Posix threads package; for the moment we're Linux
+only although this should be portable to the other platforms.
+
+Each instance of readsf~ owns a "child" thread for doing the UNIX (NT?) file
+reading. The parent thread signals the child each time:
+ (1) a file wants opening or closing;
+ (2) we've eaten another 1/16 of the shared buffer (so that the
+ child thread should check if it's time to read some more.)
+The child signals the parent whenever a read has completed. Signalling
+is done by setting "conditions" and putting data in mutex-controlled common
+areas.
+*/
+
+#define MAXBYTESPERSAMPLE 4
+#define MAXVECSIZE 128
+
+#define READSIZE 65536
+#define WRITESIZE 65536
+#define DEFBUFPERCHAN 262144
+#define MINBUFSIZE (4 * READSIZE)
+#define MAXBUFSIZE 16777216 /* arbitrary; just don't want to hang malloc */
+
+#define REQUEST_NOTHING 0
+#define REQUEST_OPEN 1
+#define REQUEST_CLOSE 2
+#define REQUEST_QUIT 3
+#define REQUEST_BUSY 4
+
+#define STATE_IDLE 0
+#define STATE_STARTUP 1
+#define STATE_STREAM 2
+
+static t_class *readsf_class;
+
+typedef struct _readsf
+{
+ t_object x_obj;
+ t_canvas *x_canvas;
+ t_clock *x_clock;
+ char *x_buf; /* soundfile buffer */
+ int x_bufsize; /* buffer size in bytes */
+ int x_noutlets; /* number of audio outlets */
+ t_sample *(x_outvec[MAXSFCHANS]); /* audio vectors */
+ int x_vecsize; /* vector size for transfers */
+ t_outlet *x_bangout; /* bang-on-done outlet */
+ int x_state; /* opened, running, or idle */
+ /* parameters to communicate with subthread */
+ int x_requestcode; /* pending request from parent to I/O thread */
+ char *x_filename; /* file to open (string is permanently allocated) */
+ int x_fileerror; /* slot for "errno" return */
+ int x_skipheaderbytes; /* size of header we'll skip */
+ int x_bytespersample; /* bytes per sample (2 or 3) */
+ int x_bigendian; /* true if file is big-endian */
+ int x_sfchannels; /* number of channels in soundfile */
+ long x_onsetframes; /* number of sample frames to skip */
+ long x_bytelimit; /* max number of data bytes to read */
+ int x_fd; /* filedesc */
+ int x_fifosize; /* buffer size appropriately rounded down */
+ int x_fifohead; /* index of next byte to get from file */
+ int x_fifotail; /* index of next byte the ugen will read */
+ int x_eof; /* true if fifohead has stopped changing */
+ int x_sigcountdown; /* counter for signalling child for more data */
+ int x_sigperiod; /* number of ticks per signal */
+ int x_filetype; /* writesf~ only; type of file to create */
+ int x_itemswritten; /* writesf~ only; items writen */
+ int x_swap; /* writesf~ only; true if byte swapping */
+ float x_f; /* writesf~ only; scalar for signal inlet */
+ pthread_mutex_t x_mutex;
+ pthread_cond_t x_requestcondition;
+ pthread_cond_t x_answercondition;
+ pthread_t x_childthread;
+} t_readsf;
+
+
+/************** the child thread which performs file I/O ***********/
+
+#if 0
+static void pute(char *s) /* debug routine */
+{
+ write(2, s, strlen(s));
+}
+#else
+#define pute(x)
+#endif
+
+#if 1
+#define sfread_cond_wait pthread_cond_wait
+#define sfread_cond_signal pthread_cond_signal
+#else
+#include <sys/time.h> /* debugging version... */
+#include <sys/types.h>
+static void readsf_fakewait(pthread_mutex_t *b)
+{
+ struct timeval timout;
+ timout.tv_sec = 0;
+ timout.tv_usec = 1000000;
+ pthread_mutex_unlock(b);
+ select(0, 0, 0, 0, &timout);
+ pthread_mutex_lock(b);
+}
+
+void readsf_banana( void)
+{
+ struct timeval timout;
+ timout.tv_sec = 0;
+ timout.tv_usec = 200000;
+ pute("banana1\n");
+ select(0, 0, 0, 0, &timout);
+ pute("banana2\n");
+}
+
+
+#define sfread_cond_wait(a,b) readsf_fakewait(b)
+#define sfread_cond_signal(a)
+#endif
+
+static void *readsf_child_main(void *zz)
+{
+ t_readsf *x = zz;
+ pute("1\n");
+ pthread_mutex_lock(&x->x_mutex);
+ while (1)
+ {
+ int fd, fifohead;
+ char *buf;
+ pute("0\n");
+ if (x->x_requestcode == REQUEST_NOTHING)
+ {
+ pute("wait 2\n");
+ sfread_cond_signal(&x->x_answercondition);
+ sfread_cond_wait(&x->x_requestcondition, &x->x_mutex);
+ pute("3\n");
+ }
+ else if (x->x_requestcode == REQUEST_OPEN)
+ {
+ char boo[80];
+ int sysrtn, wantbytes;
+
+ /* copy file stuff out of the data structure so we can
+ relinquish the mutex while we're in open_soundfile(). */
+ long onsetframes = x->x_onsetframes;
+ long bytelimit = 0x7fffffff;
+ int skipheaderbytes = x->x_skipheaderbytes;
+ int bytespersample = x->x_bytespersample;
+ int sfchannels = x->x_sfchannels;
+ int bigendian = x->x_bigendian;
+ char *filename = x->x_filename;
+ char *dirname = canvas_getdir(x->x_canvas)->s_name;
+ /* alter the request code so that an ensuing "open" will get
+ noticed. */
+ pute("4\n");
+ x->x_requestcode = REQUEST_BUSY;
+ x->x_fileerror = 0;
+
+ /* if there's already a file open, close it */
+ if (x->x_fd >= 0)
+ {
+ fd = x->x_fd;
+ pthread_mutex_unlock(&x->x_mutex);
+ close (fd);
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_fd = -1;
+ if (x->x_requestcode != REQUEST_BUSY)
+ goto lost;
+ }
+ /* open the soundfile with the mutex unlocked */
+ pthread_mutex_unlock(&x->x_mutex);
+ fd = open_soundfile(dirname, filename,
+ skipheaderbytes, &bytespersample, &bigendian,
+ &sfchannels, &bytelimit, onsetframes);
+ pthread_mutex_lock(&x->x_mutex);
+
+ pute("5\n");
+ /* copy back into the instance structure. */
+ x->x_bytespersample = bytespersample;
+ x->x_sfchannels = sfchannels;
+ x->x_bigendian = bigendian;
+ x->x_fd = fd;
+ x->x_bytelimit = bytelimit;
+ if (fd < 0)
+ {
+ x->x_fileerror = errno;
+ x->x_eof = 1;
+ pute("open failed\n");
+ pute(filename);
+ pute(dirname);
+ goto lost;
+ }
+ /* check if another request has been made; if so, field it */
+ if (x->x_requestcode != REQUEST_BUSY)
+ goto lost;
+ pute("6\n");
+ x->x_fifohead = 0;
+ /* set fifosize from bufsize. fifosize must be a
+ multiple of the number of bytes eaten for each DSP
+ tick. We pessimistically assume MAXVECSIZE samples
+ per tick since that could change. There could be a
+ problem here if the vector size increases while a
+ soundfile is being played... */
+ x->x_fifosize = x->x_bufsize - (x->x_bufsize %
+ (x->x_bytespersample * x->x_sfchannels * MAXVECSIZE));
+ /* arrange for the "request" condition to be signalled 16
+ times per buffer */
+ sprintf(boo, "fifosize %d\n",
+ x->x_fifosize);
+ pute(boo);
+ x->x_sigcountdown = x->x_sigperiod =
+ (x->x_fifosize /
+ (16 * x->x_bytespersample * x->x_sfchannels *
+ x->x_vecsize));
+ /* in a loop, wait for the fifo to get hungry and feed it */
+
+ while (x->x_requestcode == REQUEST_BUSY)
+ {
+ int fifosize = x->x_fifosize;
+ pute("77\n");
+ if (x->x_eof)
+ break;
+ if (x->x_fifohead >= x->x_fifotail)
+ {
+ /* if the head is >= the tail, we can immediately read
+ to the end of the fifo. Unless, that is, we would
+ read all the way to the end of the buffer and the
+ "tail" is zero; this would fill the buffer completely
+ which isn't allowed because you can't tell a completely
+ full buffer from an empty one. */
+ if (x->x_fifotail || (fifosize - x->x_fifohead > READSIZE))
+ {
+ wantbytes = fifosize - x->x_fifohead;
+ if (wantbytes > READSIZE)
+ wantbytes = READSIZE;
+ if (wantbytes > x->x_bytelimit)
+ wantbytes = x->x_bytelimit;
+ sprintf(boo, "head %d, tail %d, size %d\n",
+ x->x_fifohead, x->x_fifotail, wantbytes);
+ pute(boo);
+ }
+ else
+ {
+ pute("wait 7a ...\n");
+ sfread_cond_signal(&x->x_answercondition);
+ pute("signalled\n");
+ sfread_cond_wait(&x->x_requestcondition,
+ &x->x_mutex);
+ pute("7a done\n");
+ continue;
+ }
+ }
+ else
+ {
+ /* otherwise check if there are at least READSIZE
+ bytes to read. If not, wait and loop back. */
+ wantbytes = x->x_fifotail - x->x_fifohead - 1;
+ if (wantbytes < READSIZE)
+ {
+ pute("wait 7...\n");
+ sfread_cond_signal(&x->x_answercondition);
+ sfread_cond_wait(&x->x_requestcondition,
+ &x->x_mutex);
+ pute("7 done\n");
+ continue;
+ }
+ else wantbytes = READSIZE;
+ }
+ pute("8\n");
+ fd = x->x_fd;
+ buf = x->x_buf;
+ fifohead = x->x_fifohead;
+ pthread_mutex_unlock(&x->x_mutex);
+ sysrtn = read(fd, buf + fifohead, wantbytes);
+ pthread_mutex_lock(&x->x_mutex);
+ if (x->x_requestcode != REQUEST_BUSY)
+ break;
+ if (sysrtn < 0)
+ {
+ pute("fileerror\n");
+ x->x_fileerror = errno;
+ break;
+ }
+ else if (sysrtn == 0)
+ {
+ x->x_eof = 1;
+ break;
+ }
+ else
+ {
+ x->x_fifohead += sysrtn;
+ x->x_bytelimit -= sysrtn;
+ if (x->x_bytelimit <= 0)
+ {
+ x->x_eof = 1;
+ break;
+ }
+ if (x->x_fifohead == fifosize)
+ x->x_fifohead = 0;
+ }
+ sprintf(boo, "after: head %d, tail %d\n",
+ x->x_fifohead, x->x_fifotail);
+ pute(boo);
+ /* signal parent in case it's waiting for data */
+ sfread_cond_signal(&x->x_answercondition);
+ }
+ lost:
+
+ if (x->x_requestcode == REQUEST_BUSY)
+ x->x_requestcode = REQUEST_NOTHING;
+ /* fell out of read loop: close file if necessary,
+ set EOF and signal once more */
+ if (x->x_fd >= 0)
+ {
+ fd = x->x_fd;
+ pthread_mutex_unlock(&x->x_mutex);
+ close (fd);
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_fd = -1;
+ }
+ sfread_cond_signal(&x->x_answercondition);
+
+ }
+ else if (x->x_requestcode == REQUEST_CLOSE)
+ {
+ if (x->x_fd >= 0)
+ {
+ fd = x->x_fd;
+ pthread_mutex_unlock(&x->x_mutex);
+ close (fd);
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_fd = -1;
+ }
+ if (x->x_requestcode == REQUEST_CLOSE)
+ x->x_requestcode = REQUEST_NOTHING;
+ sfread_cond_signal(&x->x_answercondition);
+ }
+ else if (x->x_requestcode == REQUEST_QUIT)
+ {
+ if (x->x_fd >= 0)
+ {
+ fd = x->x_fd;
+ pthread_mutex_unlock(&x->x_mutex);
+ close (fd);
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_fd = -1;
+ }
+ x->x_requestcode = REQUEST_NOTHING;
+ sfread_cond_signal(&x->x_answercondition);
+ break;
+ }
+ else
+ {
+ pute("13\n");
+ }
+ }
+ pute("thread exit\n");
+ pthread_mutex_unlock(&x->x_mutex);
+ return (0);
+}
+
+/******** the object proper runs in the calling (parent) thread ****/
+
+static void readsf_tick(t_readsf *x);
+
+static void *readsf_new(t_floatarg fnchannels, t_floatarg fbufsize)
+{
+ t_readsf *x;
+ int nchannels = fnchannels, bufsize = fbufsize, i;
+ char *buf;
+
+ if (nchannels < 1)
+ nchannels = 1;
+ else if (nchannels > MAXSFCHANS)
+ nchannels = MAXSFCHANS;
+ if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels;
+ else if (bufsize < MINBUFSIZE)
+ bufsize = MINBUFSIZE;
+ else if (bufsize > MAXBUFSIZE)
+ bufsize = MAXBUFSIZE;
+ buf = getbytes(bufsize);
+ if (!buf) return (0);
+
+ x = (t_readsf *)pd_new(readsf_class);
+
+ for (i = 0; i < nchannels; i++)
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_noutlets = nchannels;
+ x->x_bangout = outlet_new(&x->x_obj, &s_bang);
+ pthread_mutex_init(&x->x_mutex, 0);
+ pthread_cond_init(&x->x_requestcondition, 0);
+ pthread_cond_init(&x->x_answercondition, 0);
+ x->x_vecsize = MAXVECSIZE;
+ x->x_state = STATE_IDLE;
+ x->x_clock = clock_new(x, (t_method)readsf_tick);
+ x->x_canvas = canvas_getcurrent();
+ x->x_bytespersample = 2;
+ x->x_sfchannels = 1;
+ x->x_fd = -1;
+ x->x_buf = buf;
+ x->x_bufsize = bufsize;
+ x->x_fifosize = x->x_fifohead = x->x_fifotail = x->x_requestcode = 0;
+ pthread_create(&x->x_childthread, 0, readsf_child_main, x);
+ return (x);
+}
+
+static void readsf_tick(t_readsf *x)
+{
+ outlet_bang(x->x_bangout);
+}
+
+static t_int *readsf_perform(t_int *w)
+{
+ t_readsf *x = (t_readsf *)(w[1]);
+ int vecsize = x->x_vecsize, noutlets = x->x_noutlets, i, j,
+ bytespersample = x->x_bytespersample,
+ bigendian = x->x_bigendian;
+ float *fp;
+ if (x->x_state == STATE_STREAM)
+ {
+ int wantbytes, nchannels, sfchannels = x->x_sfchannels;
+ pthread_mutex_lock(&x->x_mutex);
+ wantbytes = sfchannels * vecsize * bytespersample;
+ while (
+ !x->x_eof && x->x_fifohead >= x->x_fifotail &&
+ x->x_fifohead < x->x_fifotail + wantbytes-1)
+ {
+ pute("wait...\n");
+ sfread_cond_signal(&x->x_requestcondition);
+ sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
+ pute("done\n");
+ }
+ if (x->x_eof && x->x_fifohead >= x->x_fifotail &&
+ x->x_fifohead < x->x_fifotail + wantbytes-1)
+ {
+ if (x->x_fileerror)
+ {
+ pd_error(x, "dsp: %s: %s", x->x_filename,
+ (x->x_fileerror == EIO ?
+ "unknown or bad header format" :
+ strerror(x->x_fileerror)));
+ }
+ clock_delay(x->x_clock, 0);
+ x->x_state = STATE_IDLE;
+ sfread_cond_signal(&x->x_requestcondition);
+ pthread_mutex_unlock(&x->x_mutex);
+ goto idle;
+ }
+
+ soundfile_xferin(sfchannels, noutlets, x->x_outvec, 0,
+ (unsigned char *)(x->x_buf + x->x_fifotail), vecsize,
+ bytespersample, bigendian);
+
+ x->x_fifotail += wantbytes;
+ if (x->x_fifotail >= x->x_fifosize)
+ x->x_fifotail = 0;
+ if ((--x->x_sigcountdown) <= 0)
+ {
+ sfread_cond_signal(&x->x_requestcondition);
+ x->x_sigcountdown = x->x_sigperiod;
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+ }
+ else
+ {
+ idle:
+ for (i = 0; i < noutlets; i++)
+ for (j = vecsize, fp = x->x_outvec[i]; j--; )
+ *fp++ = 0;
+ }
+ return (w+2);
+}
+
+static void readsf_start(t_readsf *x)
+{
+ /* start making output. If we're in the "startup" state change
+ to the "running" state. */
+ if (x->x_state == STATE_STARTUP)
+ x->x_state = STATE_STREAM;
+ else pd_error(x, "readsf: start requested with no prior 'open'");
+}
+
+static void readsf_stop(t_readsf *x)
+{
+ /* LATER rethink whether you need the mutex just to set a variable? */
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_state = STATE_IDLE;
+ x->x_requestcode = REQUEST_CLOSE;
+ sfread_cond_signal(&x->x_requestcondition);
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+static void readsf_float(t_readsf *x, t_floatarg f)
+{
+ if (f != 0)
+ readsf_start(x);
+ else readsf_stop(x);
+}
+
+ /* open method. Called as:
+ open filename [skipframes headersize channels bytespersamp endianness]
+ (if headersize is zero, header is taken to be automatically
+ detected; thus, use the special "-1" to mean a truly headerless file.)
+ */
+
+static void readsf_open(t_readsf *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_symbol *filesym = atom_getsymbolarg(0, argc, argv);
+ t_float onsetframes = atom_getfloatarg(1, argc, argv);
+ t_float headerbytes = atom_getfloatarg(2, argc, argv);
+ t_float channels = atom_getfloatarg(3, argc, argv);
+ t_float bytespersamp = atom_getfloatarg(4, argc, argv);
+ t_symbol *endian = atom_getsymbolarg(5, argc, argv);
+ if (!*filesym->s_name)
+ return;
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_requestcode = REQUEST_OPEN;
+ x->x_filename = filesym->s_name;
+ x->x_fifotail = 0;
+ x->x_fifohead = 0;
+ if (*endian->s_name == 'b')
+ x->x_bigendian = 1;
+ else if (*endian->s_name == 'l')
+ x->x_bigendian = 0;
+ else if (*endian->s_name)
+ pd_error(x, "endianness neither 'b' nor 'l'");
+ else x->x_bigendian = garray_ambigendian();
+ x->x_onsetframes = (onsetframes > 0 ? onsetframes : 0);
+ x->x_skipheaderbytes = (headerbytes > 0 ? headerbytes :
+ (headerbytes == 0 ? -1 : 0));
+ x->x_sfchannels = (channels >= 1 ? channels : 1);
+ x->x_bytespersample = (bytespersamp > 2 ? bytespersamp : 2);
+ x->x_eof = 0;
+ x->x_fileerror = 0;
+ x->x_state = STATE_STARTUP;
+ sfread_cond_signal(&x->x_requestcondition);
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+static void readsf_dsp(t_readsf *x, t_signal **sp)
+{
+ int i, noutlets = x->x_noutlets;
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_vecsize = sp[0]->s_n;
+
+ x->x_sigperiod = (x->x_fifosize /
+ (x->x_bytespersample * x->x_sfchannels * x->x_vecsize));
+ for (i = 0; i < noutlets; i++)
+ x->x_outvec[i] = sp[i]->s_vec;
+ pthread_mutex_unlock(&x->x_mutex);
+ dsp_add(readsf_perform, 1, x);
+}
+
+static void readsf_print(t_readsf *x)
+{
+ post("state %d", x->x_state);
+ post("fifo head %d", x->x_fifohead);
+ post("fifo tail %d", x->x_fifotail);
+ post("fifo size %d", x->x_fifosize);
+ post("fd %d", x->x_fd);
+ post("eof %d", x->x_eof);
+}
+
+static void readsf_free(t_readsf *x)
+{
+ /* request QUIT and wait for acknowledge */
+ void *threadrtn;
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_requestcode = REQUEST_QUIT;
+ post("stopping readsf thread...");
+ sfread_cond_signal(&x->x_requestcondition);
+ while (x->x_requestcode != REQUEST_NOTHING)
+ {
+ post("signalling...");
+ sfread_cond_signal(&x->x_requestcondition);
+ sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+ if (pthread_join(x->x_childthread, &threadrtn))
+ error("readsf_free: join failed");
+ post("... done.");
+
+ pthread_cond_destroy(&x->x_requestcondition);
+ pthread_cond_destroy(&x->x_answercondition);
+ pthread_mutex_destroy(&x->x_mutex);
+ freebytes(x->x_buf, x->x_bufsize);
+ clock_free(x->x_clock);
+}
+
+static void readsf_setup(void)
+{
+ readsf_class = class_new(gensym("readsf~"), (t_newmethod)readsf_new,
+ (t_method)readsf_free, sizeof(t_readsf), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addfloat(readsf_class, (t_method)readsf_float);
+ class_addmethod(readsf_class, (t_method)readsf_start, gensym("start"), 0);
+ class_addmethod(readsf_class, (t_method)readsf_stop, gensym("stop"), 0);
+ class_addmethod(readsf_class, (t_method)readsf_dsp, gensym("dsp"), 0);
+ class_addmethod(readsf_class, (t_method)readsf_open, gensym("open"),
+ A_GIMME, 0);
+ class_addmethod(readsf_class, (t_method)readsf_print, gensym("print"), 0);
+}
+
+/******************************* writesf *******************/
+
+static t_class *writesf_class;
+
+#define t_writesf t_readsf /* just re-use the structure */
+
+/************** the child thread which performs file I/O ***********/
+
+static void *writesf_child_main(void *zz)
+{
+ t_writesf *x = zz;
+ pute("1\n");
+ pthread_mutex_lock(&x->x_mutex);
+ while (1)
+ {
+ pute("0\n");
+ if (x->x_requestcode == REQUEST_NOTHING)
+ {
+ pute("wait 2\n");
+ sfread_cond_signal(&x->x_answercondition);
+ sfread_cond_wait(&x->x_requestcondition, &x->x_mutex);
+ pute("3\n");
+ }
+ else if (x->x_requestcode == REQUEST_OPEN)
+ {
+ char boo[80];
+ int fd, sysrtn, writebytes;
+
+ /* copy file stuff out of the data structure so we can
+ relinquish the mutex while we're in open_soundfile(). */
+ long onsetframes = x->x_onsetframes;
+ long bytelimit = 0x7fffffff;
+ int skipheaderbytes = x->x_skipheaderbytes;
+ int bytespersample = x->x_bytespersample;
+ int sfchannels = x->x_sfchannels;
+ int bigendian = x->x_bigendian;
+ int filetype = x->x_filetype;
+ char *filename = x->x_filename;
+ t_canvas *canvas = x->x_canvas;
+
+ /* alter the request code so that an ensuing "open" will get
+ noticed. */
+ pute("4\n");
+ x->x_requestcode = REQUEST_BUSY;
+ x->x_fileerror = 0;
+
+ /* if there's already a file open, close it */
+ if (x->x_fd >= 0)
+ {
+ pthread_mutex_unlock(&x->x_mutex);
+ close (x->x_fd);
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_fd = -1;
+ if (x->x_requestcode != REQUEST_BUSY)
+ continue;
+ }
+ /* open the soundfile with the mutex unlocked */
+ pthread_mutex_unlock(&x->x_mutex);
+ fd = create_soundfile(canvas, filename, filetype, 0,
+ bytespersample, bigendian, sfchannels,
+ garray_ambigendian() != bigendian);
+ pthread_mutex_lock(&x->x_mutex);
+
+ pute("5\n");
+
+ if (fd < 0)
+ {
+ x->x_fd = -1;
+ x->x_eof = 1;
+ x->x_fileerror = errno;
+ pute("open failed\n");
+ pute(filename);
+ x->x_requestcode = REQUEST_NOTHING;
+ continue;
+ }
+ /* check if another request has been made; if so, field it */
+ if (x->x_requestcode != REQUEST_BUSY)
+ continue;
+ pute("6\n");
+ x->x_fd = fd;
+ x->x_fifotail = 0;
+ x->x_itemswritten = 0;
+ x->x_swap = garray_ambigendian() != bigendian;
+ /* in a loop, wait for the fifo to have data and write it
+ to disk */
+ while (x->x_requestcode == REQUEST_BUSY ||
+ (x->x_requestcode == REQUEST_CLOSE &&
+ x->x_fifohead != x->x_fifotail))
+ {
+ int fifosize = x->x_fifosize, fifotail;
+ char *buf = x->x_buf;
+ pute("77\n");
+
+ /* if the head is < the tail, we can immediately write
+ from tail to end of fifo to disk; otherwise we hold off
+ writing until there are at least WRITESIZE bytes in the
+ buffer */
+ if (x->x_fifohead < x->x_fifotail ||
+ x->x_fifohead >= x->x_fifotail + WRITESIZE
+ || (x->x_requestcode == REQUEST_CLOSE &&
+ x->x_fifohead != x->x_fifotail))
+ {
+ writebytes = (x->x_fifohead < x->x_fifotail ?
+ fifosize : x->x_fifohead) - x->x_fifotail;
+ if (writebytes > READSIZE)
+ writebytes = READSIZE;
+ }
+ else
+ {
+ pute("wait 7a ...\n");
+ sfread_cond_signal(&x->x_answercondition);
+ pute("signalled\n");
+ sfread_cond_wait(&x->x_requestcondition,
+ &x->x_mutex);
+ pute("7a done\n");
+ continue;
+ }
+ pute("8\n");
+ fifotail = x->x_fifotail;
+ fd = x->x_fd;
+ pthread_mutex_unlock(&x->x_mutex);
+ sysrtn = write(fd, buf + fifotail, writebytes);
+ pthread_mutex_lock(&x->x_mutex);
+ if (x->x_requestcode != REQUEST_BUSY &&
+ x->x_requestcode != REQUEST_CLOSE)
+ break;
+ if (sysrtn < writebytes)
+ {
+ pute("fileerror\n");
+ x->x_fileerror = errno;
+ break;
+ }
+ else
+ {
+ x->x_fifotail += sysrtn;
+ if (x->x_fifotail == fifosize)
+ x->x_fifotail = 0;
+ }
+ x->x_itemswritten +=
+ sysrtn / (x->x_bytespersample * x->x_sfchannels);
+ sprintf(boo, "after: head %d, tail %d\n",
+ x->x_fifohead, x->x_fifotail);
+ pute(boo);
+ /* signal parent in case it's waiting for data */
+ sfread_cond_signal(&x->x_answercondition);
+ }
+ }
+ else if (x->x_requestcode == REQUEST_CLOSE ||
+ x->x_requestcode == REQUEST_QUIT)
+ {
+ int quit = (x->x_requestcode == REQUEST_QUIT);
+ if (x->x_fd >= 0)
+ {
+ int bytesperframe = x->x_bytespersample * x->x_sfchannels;
+ int bigendian = x->x_bigendian;
+ char *filename = x->x_filename;
+ int fd = x->x_fd;
+ int filetype = x->x_filetype;
+ int itemswritten = x->x_itemswritten;
+ int swap = x->x_swap;
+ pthread_mutex_unlock(&x->x_mutex);
+
+ soundfile_finishwrite(x, filename, fd,
+ filetype, 0x7fffffff, itemswritten,
+ bytesperframe, swap);
+ close (fd);
+
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_fd = -1;
+ }
+ x->x_requestcode = REQUEST_NOTHING;
+ sfread_cond_signal(&x->x_answercondition);
+ if (quit)
+ break;
+ }
+ else
+ {
+ pute("13\n");
+ }
+ }
+ pute("thread exit\n");
+ pthread_mutex_unlock(&x->x_mutex);
+ return (0);
+}
+
+/******** the object proper runs in the calling (parent) thread ****/
+
+static void writesf_tick(t_writesf *x);
+
+static void *writesf_new(t_floatarg fnchannels, t_floatarg fbufsize)
+{
+ t_writesf *x;
+ int nchannels = fnchannels, bufsize = fbufsize, i;
+ char *buf;
+
+ if (nchannels < 1)
+ nchannels = 1;
+ else if (nchannels > MAXSFCHANS)
+ nchannels = MAXSFCHANS;
+ if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels;
+ else if (bufsize < MINBUFSIZE)
+ bufsize = MINBUFSIZE;
+ else if (bufsize > MAXBUFSIZE)
+ bufsize = MAXBUFSIZE;
+ buf = getbytes(bufsize);
+ if (!buf) return (0);
+
+ x = (t_writesf *)pd_new(writesf_class);
+
+ for (i = 1; i < nchannels; i++)
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+
+ x->x_f = 0;
+ x->x_sfchannels = nchannels;
+ pthread_mutex_init(&x->x_mutex, 0);
+ pthread_cond_init(&x->x_requestcondition, 0);
+ pthread_cond_init(&x->x_answercondition, 0);
+ x->x_vecsize = MAXVECSIZE;
+ x->x_state = STATE_IDLE;
+ x->x_clock = 0; /* no callback needed here */
+ x->x_canvas = canvas_getcurrent();
+ x->x_bytespersample = 2;
+ x->x_fd = -1;
+ x->x_buf = buf;
+ x->x_bufsize = bufsize;
+ x->x_fifosize = x->x_fifohead = x->x_fifotail = x->x_requestcode = 0;
+ pthread_create(&x->x_childthread, 0, writesf_child_main, x);
+ return (x);
+}
+
+static t_int *writesf_perform(t_int *w)
+{
+ t_writesf *x = (t_writesf *)(w[1]);
+ int vecsize = x->x_vecsize, sfchannels = x->x_sfchannels, i, j,
+ bytespersample = x->x_bytespersample,
+ bigendian = x->x_bigendian;
+ float *fp;
+ if (x->x_state == STATE_STREAM)
+ {
+ int wantbytes;
+ pthread_mutex_lock(&x->x_mutex);
+ wantbytes = sfchannels * vecsize * bytespersample;
+ while (x->x_fifotail > x->x_fifohead &&
+ x->x_fifotail < x->x_fifohead + wantbytes + 1)
+ {
+ pute("wait...\n");
+ sfread_cond_signal(&x->x_requestcondition);
+ sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
+ pute("done\n");
+ }
+
+ soundfile_xferout(sfchannels, x->x_outvec,
+ (unsigned char *)(x->x_buf + x->x_fifohead), vecsize, 0,
+ bytespersample, bigendian, 1.);
+
+ x->x_fifohead += wantbytes;
+ if (x->x_fifohead >= x->x_fifosize)
+ x->x_fifohead = 0;
+ if ((--x->x_sigcountdown) <= 0)
+ {
+ pute("signal 1\n");
+ sfread_cond_signal(&x->x_requestcondition);
+ x->x_sigcountdown = x->x_sigperiod;
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+ }
+ return (w+2);
+}
+
+static void writesf_start(t_writesf *x)
+{
+ /* start making output. If we're in the "startup" state change
+ to the "running" state. */
+ if (x->x_state == STATE_STARTUP)
+ x->x_state = STATE_STREAM;
+ else
+ pd_error(x, "writesf: start requested with no prior 'open'");
+}
+
+static void writesf_stop(t_writesf *x)
+{
+ /* LATER rethink whether you need the mutex just to set a Svariable? */
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_state = STATE_IDLE;
+ x->x_requestcode = REQUEST_CLOSE;
+ pute("signal 2\n");
+ sfread_cond_signal(&x->x_requestcondition);
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+
+ /* open method. Called as: open [args] filename with args as in
+ soundfiler_writeargparse().
+ */
+
+static void writesf_open(t_writesf *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_symbol *filesym;
+ int filetype, bytespersamp, swap, bigendian, normalize;
+ long onset, nframes;
+ if (soundfiler_writeargparse(x, &argc,
+ &argv, &filesym, &filetype, &bytespersamp, &swap, &bigendian,
+ &normalize, &onset, &nframes))
+ {
+ pd_error(x,
+ "writesf~: usage: open [-bytes [234]] [-wave,-nextstep,-aiff] ...");
+ post("... [-big,-little] filename");
+ }
+ if (normalize || onset || (nframes != 0x7fffffff))
+ pd_error(x, "normalize/onset/nframes argument to writesf~: ignored");
+ if (argc)
+ pd_error(x, "extra argument(s) to writesf~: ignored");
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_bytespersample = bytespersamp;
+ x->x_swap = swap;
+ x->x_bigendian = bigendian;
+ x->x_filename = filesym->s_name;
+ x->x_filetype = filetype;
+ x->x_itemswritten = 0;
+ x->x_requestcode = REQUEST_OPEN;
+ x->x_fifotail = 0;
+ x->x_fifohead = 0;
+ x->x_eof = 0;
+ x->x_fileerror = 0;
+ x->x_state = STATE_STARTUP;
+ x->x_bytespersample = (bytespersamp > 2 ? bytespersamp : 2);
+ /* set fifosize from bufsize. fifosize must be a
+ multiple of the number of bytes eaten for each DSP
+ tick. */
+ x->x_fifosize = x->x_bufsize - (x->x_bufsize %
+ (x->x_bytespersample * x->x_sfchannels * MAXVECSIZE));
+ /* arrange for the "request" condition to be signalled 16
+ times per buffer */
+ x->x_sigcountdown = x->x_sigperiod =
+ (x->x_fifosize /
+ (16 * x->x_bytespersample * x->x_sfchannels *
+ x->x_vecsize));
+ sfread_cond_signal(&x->x_requestcondition);
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+static void writesf_dsp(t_writesf *x, t_signal **sp)
+{
+ int i, ninlets = x->x_sfchannels;
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_vecsize = sp[0]->s_n;
+
+ x->x_sigperiod = (x->x_fifosize /
+ (x->x_bytespersample * ninlets * x->x_vecsize));
+ for (i = 0; i < ninlets; i++)
+ x->x_outvec[i] = sp[i]->s_vec;
+ pthread_mutex_unlock(&x->x_mutex);
+ dsp_add(writesf_perform, 1, x);
+}
+
+static void writesf_print(t_writesf *x)
+{
+ post("state %d", x->x_state);
+ post("fifo head %d", x->x_fifohead);
+ post("fifo tail %d", x->x_fifotail);
+ post("fifo size %d", x->x_fifosize);
+ post("fd %d", x->x_fd);
+ post("eof %d", x->x_eof);
+}
+
+static void writesf_free(t_writesf *x)
+{
+ /* request QUIT and wait for acknowledge */
+ void *threadrtn;
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_requestcode = REQUEST_QUIT;
+ /* post("stopping writesf thread..."); */
+ sfread_cond_signal(&x->x_requestcondition);
+ while (x->x_requestcode != REQUEST_NOTHING)
+ {
+ /* post("signalling..."); */
+ sfread_cond_signal(&x->x_requestcondition);
+ sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+ if (pthread_join(x->x_childthread, &threadrtn))
+ error("writesf_free: join failed");
+ /* post("... done."); */
+
+ pthread_cond_destroy(&x->x_requestcondition);
+ pthread_cond_destroy(&x->x_answercondition);
+ pthread_mutex_destroy(&x->x_mutex);
+ freebytes(x->x_buf, x->x_bufsize);
+}
+
+static void writesf_setup(void)
+{
+ writesf_class = class_new(gensym("writesf~"), (t_newmethod)writesf_new,
+ (t_method)writesf_free, sizeof(t_writesf), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(writesf_class, (t_method)writesf_start, gensym("start"), 0);
+ class_addmethod(writesf_class, (t_method)writesf_stop, gensym("stop"), 0);
+ class_addmethod(writesf_class, (t_method)writesf_dsp, gensym("dsp"), 0);
+ class_addmethod(writesf_class, (t_method)writesf_open, gensym("open"),
+ A_GIMME, 0);
+ class_addmethod(writesf_class, (t_method)writesf_print, gensym("print"), 0);
+ CLASS_MAINSIGNALIN(writesf_class, t_writesf, x_f);
+}
+
+/* ------------------------ global setup routine ------------------------- */
+
+void d_soundfile_setup(void)
+{
+ soundfiler_setup();
+ readsf_setup();
+ writesf_setup();
+}
+
diff --git a/pd/src/d_ugen.c b/pd/src/d_ugen.c
new file mode 100644
index 00000000..68e931e6
--- /dev/null
+++ b/pd/src/d_ugen.c
@@ -0,0 +1,1078 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* These routines build a copy of the DSP portion of a graph, which is
+ then sorted into a linear list of DSP operations which are added to
+ the DSP duty cycle called by the scheduler. Once that's been done,
+ we delete the copy. The DSP objects are represented by "ugenbox"
+ structures which are parallel to the DSP objects in the graph and
+ have vectors of siginlets and sigoutlets which record their
+ interconnections.
+*/
+
+/* hacked to run subpatches with different samplerates
+ * only samplerates that are a power_of_2-multiple of the
+ *
+ * mfg.gfd.uil
+ * IOhannes
+ *
+ * edited lines are marked with "IOhannes"
+ *
+ */
+
+
+#include "m_pd.h"
+#include <stdlib.h>
+#include <stdarg.h>
+
+extern t_class *vinlet_class, *voutlet_class, *canvas_class;
+int obj_nsiginlets(t_object *x);
+int obj_siginletindex(t_object *x, int m);
+int obj_nsigoutlets(t_object *x);
+int obj_sigoutletindex(t_object *x, int m);
+t_sample *obj_findsignalscalar(t_object *x, int m);
+static int ugen_loud;
+EXTERN_STRUCT _vinlet;
+EXTERN_STRUCT _voutlet;
+
+void vinlet_dspprolog(struct _vinlet *x, t_signal **parentsigs,
+ int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
+ int switched);
+void voutlet_dspprolog(struct _voutlet *x, t_signal **parentsigs,
+ int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
+ int switched);
+void voutlet_dspepilog(struct _voutlet *x, t_signal **parentsigs,
+ int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
+ int switched);
+
+t_int *zero_perform(t_int *w) /* zero out a vector */
+{
+ t_float *out = (t_float *)(w[1]);
+ int n = (int)(w[2]);
+ while (n--) *out++ = 0;
+ return (w+3);
+}
+
+t_int *zero_perf8(t_int *w)
+{
+ t_float *out = (t_float *)(w[1]);
+ int n = (int)(w[2]);
+
+ for (; n; n -= 8, out += 8)
+ {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ }
+ return (w+3);
+}
+
+void dsp_add_zero(t_sample *out, int n)
+{
+ if (n&7)
+ dsp_add(zero_perform, 2, out, n);
+ else
+ dsp_add(zero_perf8, 2, out, n);
+}
+
+/* ---------------------------- block~ ----------------------------- */
+
+/* The "block~ object maintains the containing canvas's DSP computation,
+calling it at a super- or sub-multiple of the containing canvas's
+calling frequency. The block~'s creation arguments specify block size
+and overlap. Block~ does no "dsp" computation in its own right, but it
+adds prolog and epilog code before and after the canvas's unit generators.
+
+A subcanvas need not have a block~ at all; if there's none, its
+ugens are simply put on the list without any prolog or epilog code.
+
+Block~ may be invoked as switch~, in which case it also acts to switch the
+subcanvas on and off. The overall order of scheduling for a subcanvas
+is thus,
+
+ inlet and outlet prologue code (1)
+ block prologue (2)
+ the objects in the subcanvas, including inlets and outlets
+ block epilogue (2)
+ outlet epilogue code (2)
+
+where (1) means, "if reblocked" and (2) means, "if reblocked or switched".
+
+If we're reblocked, the inlet prolog and outlet epilog code takes care of
+overlapping and buffering to deal with vector size changes. If we're switched
+but not reblocked, the inlet prolog is not needed, and the output epilog is
+ONLY run when the block is switched off; in this case the epilog code simply
+copies zeros to all signal outlets.
+*/
+
+static int dsp_phase;
+static t_class *block_class;
+
+typedef struct _block
+{
+ t_object x_obj;
+ int x_vecsize;
+ int x_overlap;
+ int x_phase; /* from 0 to period-1; when zero we run the block */
+ int x_period; /* submultiple of containing canvas */
+ int x_frequency; /* supermultiple of comtaining canvas */
+ int x_count;
+ int x_blocklength; /* length of dspchain for this block */
+ int x_epiloglength; /* length of epilog */
+ char x_switched; /* true if we're acting as a a switch */
+ char x_switchon; /* true if we're switched on */
+ char x_reblock; /* true if inlets and outlets are reblocking */
+
+ int x_upsample; /* IOhannes: upsampling-factor */
+ int x_downsample; /* IOhannes: downsampling-factor */
+
+} t_block;
+
+static void *block_new(t_floatarg fvecsize, t_floatarg foverlap,
+ t_floatarg fupsample) /* IOhannes */
+{
+ int vecsize = fvecsize;
+ int overlap = foverlap;
+ int upsample, downsample; /* IOhannes */
+ t_block *x = (t_block *)pd_new(block_class);
+ if (overlap < 1)
+ overlap = 1;
+ if (vecsize < 0)
+ vecsize = 0; /* this means we'll get it from parent later. */
+
+ /* IOhannes { */
+ if (fupsample <= 0) upsample = downsample = 1;
+ else if (fupsample >= 1) {
+ upsample = fupsample;
+ downsample = 1;
+ } else {
+ downsample = 1.0 / fupsample;
+ upsample = 1;
+ }
+ /* } IOhannes */
+
+ if (vecsize && (vecsize != (1 << ilog2(vecsize))))
+ {
+ pd_error(x, "block~: vector size not a power of 2");
+ vecsize = 64;
+ }
+ if (overlap != (1 << ilog2(overlap)))
+ {
+ pd_error(x, "block~: overlap not a power of 2");
+ overlap = 1;
+ }
+ /* IOhannes { */
+ if (downsample != (1 << ilog2(downsample)))
+ {
+ pd_error(x, "block~: downsampling not a power of 2");
+ downsample = 1;
+ }
+ if (upsample != (1 << ilog2(upsample)))
+ {
+ pd_error(x, "block~: upsampling not a power of 2");
+ upsample = 1;
+ }
+ /* } IOhannes */
+
+
+ x->x_vecsize = vecsize;
+ x->x_overlap = overlap;
+ x->x_phase = 0;
+ x->x_period = 1;
+ x->x_frequency = 1;
+ x->x_switched = 0;
+ x->x_switchon = 1;
+ /* IOhannes { */
+ x->x_upsample = upsample;
+ x->x_downsample = downsample;
+ /* } IOhannes */
+ return (x);
+}
+
+static void *switch_new(t_floatarg fvecsize, t_floatarg foverlap,
+ t_floatarg fupsample) /* IOhannes */
+{
+ t_block *x = (t_block *)(block_new(fvecsize, foverlap, fupsample)); /* IOhannes */
+ x->x_switched = 1;
+ x->x_switchon = 0;
+ return (x);
+}
+
+static void block_float(t_block *x, t_floatarg f)
+{
+ if (x->x_switched)
+ x->x_switchon = (f != 0);
+}
+#define PROLOGCALL 2
+#define EPILOGCALL 2
+
+static t_int *block_prolog(t_int *w)
+{
+ t_block *x = (t_block *)w[1];
+ int phase = x->x_phase;
+ /* if we're switched off, jump past the epilog code */
+ if (!x->x_switchon)
+ return (w + x->x_blocklength);
+ if (phase)
+ {
+ phase++;
+ if (phase == x->x_period) phase = 0;
+ x->x_phase = phase;
+ return (w + x->x_blocklength); /* skip block; jump past epilog */
+ }
+ else
+ {
+ x->x_count = x->x_frequency;
+ x->x_phase = (x->x_period > 1 ? 1 : 0);
+ return (w + PROLOGCALL); /* beginning of block is next ugen */
+ }
+}
+
+static t_int *block_epilog(t_int *w)
+{
+ t_block *x = (t_block *)w[1];
+ int count = x->x_count - 1;
+ if (!x->x_reblock)
+ return (w + x->x_epiloglength + EPILOGCALL);
+ if (count)
+ {
+ x->x_count = count;
+ return (w - (x->x_blocklength -
+ (PROLOGCALL + EPILOGCALL))); /* go to ugen after prolog */
+ }
+ else return (w + EPILOGCALL);
+}
+
+static void block_dsp(t_block *x, t_signal **sp)
+{
+ /* do nothing here */
+}
+
+/* ------------------ DSP call list ----------------------- */
+
+static t_int *dsp_chain;
+static int dsp_chainsize;
+
+void dsp_add(t_perfroutine f, int n, ...)
+{
+ int newsize = dsp_chainsize + n+1, i;
+ va_list ap;
+
+ dsp_chain = t_resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int),
+ newsize * sizeof (t_int));
+ dsp_chain[dsp_chainsize-1] = (t_int)f;
+ va_start(ap, n);
+ for (i = 0; i < n; i++)
+ dsp_chain[dsp_chainsize + i] = va_arg(ap, t_int);
+ va_end(ap);
+ dsp_chain[newsize-1] = 0;
+ dsp_chainsize = newsize;
+}
+
+ /* at Guenter's suggestion, here's a vectorized version */
+void dsp_addv(t_perfroutine f, int n, t_int *vec)
+{
+ int newsize = dsp_chainsize + n+1, i;
+
+ dsp_chain = t_resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int),
+ newsize * sizeof (t_int));
+ dsp_chain[dsp_chainsize-1] = (t_int)f;
+ for (i = 0; i < n; i++)
+ dsp_chain[dsp_chainsize + i] = vec[i];
+ dsp_chain[newsize-1] = 0;
+ dsp_chainsize = newsize;
+}
+
+void dsp_tick(void)
+{
+ if (dsp_chain)
+ {
+ t_int *ip;
+ for (ip = dsp_chain; *ip; ) ip = (*(t_perfroutine)(*ip))(ip);
+ dsp_phase++;
+ }
+}
+
+/* ---------------- signals ---------------------------- */
+
+int ilog2(int n)
+{
+ int r = -1;
+ if (n <= 0) return(0);
+ while (n)
+ {
+ r++;
+ n >>= 1;
+ }
+ return (r);
+}
+
+ /* list of signals which can be reused, sorted by buffer size */
+static t_signal *signal_freelist[MAXLOGSIG+1];
+ /* list of reusable "borrowed" signals */
+static t_signal *signal_freeborrowed;
+ /* list of all signals allocated (not including "borrowed" ones) */
+static t_signal *signal_usedlist;
+
+ /* call this when DSP is stopped to free all the signals */
+void signal_cleanup(void)
+{
+ t_signal **svec, *sig, *sig2;
+ int i;
+ while (sig = signal_usedlist)
+ {
+ signal_usedlist = sig->s_nextused;
+ if (!sig->s_isborrowed)
+ t_freebytes(sig->s_vec, sig->s_n * sizeof (*sig->s_vec));
+ t_freebytes(sig, sizeof *sig);
+ }
+ for (i = 0; i <= MAXLOGSIG; i++)
+ signal_freelist[i] = 0;
+ signal_freeborrowed = 0;
+}
+
+ /* mark the signal "reusable." */
+void signal_makereusable(t_signal *sig)
+{
+ int logn = ilog2(sig->s_n);
+#if 1
+ t_signal *s5;
+ for (s5 = signal_freeborrowed; s5; s5 = s5->s_nextfree)
+ {
+ if (s5 == sig)
+ {
+ bug("signal_free 3");
+ return;
+ }
+ }
+ for (s5 = signal_freelist[logn]; s5; s5 = s5->s_nextfree)
+ {
+ if (s5 == sig)
+ {
+ bug("signal_free 4");
+ return;
+ }
+ }
+#endif
+ if (ugen_loud) post("free %x: %d", sig, sig->s_isborrowed);
+ if (sig->s_isborrowed)
+ {
+ /* if the signal is borrowed, decrement the borowee's reference
+ count, possibly marking it reusable too */
+ t_signal *s2 = sig->s_borrowedfrom;
+ if ((s2 == sig) || !s2)
+ bug("signal_free");
+ s2->s_refcount--;
+ if (!s2->s_refcount)
+ signal_makereusable(s2);
+ sig->s_nextfree = signal_freeborrowed;
+ signal_freeborrowed = sig;
+ }
+ else
+ {
+ /* if it's a real signal, put it on the free list so we can
+ reuse it. */
+ if (signal_freelist[logn] == sig) bug("signal_free 2");
+ sig->s_nextfree = signal_freelist[logn];
+ signal_freelist[logn] = sig;
+ }
+}
+
+ /* reclaim or make an audio signal. If n is zero, return a "borrowed"
+ signal whose buffer and size will be obtained later via
+ signal_setborrowed(). */
+
+t_signal *signal_new(int n, float sr)
+{
+ int logn, n2;
+ t_signal *ret, **whichlist;
+ t_sample *fp;
+ logn = ilog2(n);
+ if (n)
+ {
+ if (n != (1 << logn))
+ bug("signal buffer not a power of 2");
+ if (logn > MAXLOGSIG)
+ bug("signal buffer too large");
+ whichlist = signal_freelist + logn;
+ }
+ else
+ whichlist = &signal_freeborrowed;
+
+ /* first try to reclaim one from the free list */
+ if (ret = *whichlist)
+ *whichlist = ret->s_nextfree;
+ else
+ {
+ /* LATER figure out what to do for out-of-space here! */
+ ret = (t_signal *)t_getbytes(sizeof *ret);
+ if (n)
+ {
+ ret->s_vec = (t_sample *)getbytes(n * sizeof (*ret->s_vec));
+ ret->s_isborrowed = 0;
+ }
+ else
+ {
+ ret->s_vec = 0;
+ ret->s_isborrowed = 1;
+ }
+ ret->s_nextused = signal_usedlist;
+ signal_usedlist = ret;
+ }
+ ret->s_n = n;
+ ret->s_sr = sr;
+ ret->s_refcount = 0;
+ ret->s_borrowedfrom = 0;
+ if (ugen_loud) post("new %x: %d", ret, ret->s_isborrowed);
+ return (ret);
+}
+
+static t_signal *signal_newlike(const t_signal *sig)
+{
+ return (signal_new(sig->s_n, sig->s_sr));
+}
+
+void signal_setborrowed(t_signal *sig, t_signal *sig2)
+{
+ if (!sig->s_isborrowed || sig->s_borrowedfrom)
+ bug("signal_setborrowed");
+ sig->s_borrowedfrom = sig2;
+ sig->s_vec = sig2->s_vec;
+ sig->s_n = sig2->s_n;
+}
+
+int signal_compatible(t_signal *s1, t_signal *s2)
+{
+ return (s1->s_n == s2->s_n && s1->s_sr == s2->s_sr);
+}
+
+/* ------------------ ugen ("unit generator") sorting ----------------- */
+
+typedef struct _ugenbox
+{
+ struct _siginlet *u_in;
+ int u_nin;
+ struct _sigoutlet *u_out;
+ int u_nout;
+ int u_phase;
+ struct _ugenbox *u_next;
+ t_object *u_obj;
+ int u_done;
+} t_ugenbox;
+
+typedef struct _siginlet
+{
+ int i_nconnect;
+ int i_ngot;
+ t_signal *i_signal;
+} t_siginlet;
+
+typedef struct _sigoutconnect
+{
+ t_ugenbox *oc_who;
+ int oc_inno;
+ struct _sigoutconnect *oc_next;
+} t_sigoutconnect;
+
+typedef struct _sigoutlet
+{
+ int o_nconnect;
+ int o_nsent;
+ t_signal *o_signal;
+ t_sigoutconnect *o_connections;
+} t_sigoutlet;
+
+
+struct _dspcontext
+{
+ struct _ugenbox *dc_ugenlist;
+ struct _dspcontext *dc_parentcontext;
+ int dc_ninlets;
+ int dc_noutlets;
+ t_signal **dc_iosigs;
+ float dc_srate;
+ int dc_vecsize;
+ char dc_toplevel; /* true if "iosigs" is invalid. */
+ char dc_reblock; /* true if we have to reblock inlets/outlets */
+ char dc_switched; /* true if we're switched */
+
+};
+
+#define t_dspcontext struct _dspcontext
+
+static int ugen_sortno = 0;
+static t_dspcontext *ugen_currentcontext;
+
+void ugen_stop(void)
+{
+ t_signal *s;
+ int i;
+ if (dsp_chain)
+ {
+ freebytes(dsp_chain, dsp_chainsize * sizeof (t_int));
+ dsp_chain = 0;
+ }
+ signal_cleanup();
+
+}
+
+void ugen_start(void)
+{
+ ugen_stop();
+ ugen_sortno++;
+ dsp_chain = (t_int *)getbytes(sizeof(*dsp_chain));
+ dsp_chain[0] = 0;
+ dsp_chainsize = 1;
+ if (ugen_currentcontext) bug("ugen_start");
+}
+
+int ugen_getsortno(void)
+{
+ return (ugen_sortno);
+}
+
+#if 0
+void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
+{
+ int i, count;
+ t_signal *sig;
+ for (count = 0, sig = signal_usedlist; sig;
+ count++, sig = sig->s_nextused)
+ ;
+ post("used signals %d", count);
+ for (i = 0; i < MAXLOGSIG; i++)
+ {
+ for (count = 0, sig = signal_freelist[i]; sig;
+ count++, sig = sig->s_nextfree)
+ ;
+ if (count)
+ post("size %d: free %d", (1 << i), count);
+ }
+ for (count = 0, sig = signal_freeborrowed; sig;
+ count++, sig = sig->s_nextfree)
+ ;
+ post("free borrowed %d", count);
+
+ ugen_loud = argc;
+}
+#endif
+
+ /* start building the graph for a canvas */
+t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp,
+ int ninlets, int noutlets)
+{
+ t_dspcontext *dc = (t_dspcontext *)getbytes(sizeof(*dc));
+ float parent_srate, srate;
+ int parent_vecsize, vecsize;
+
+ if (ugen_loud) post("ugen_start_graph...");
+
+ dc->dc_ugenlist = 0;
+ dc->dc_toplevel = toplevel;
+ dc->dc_iosigs = sp;
+ dc->dc_ninlets = ninlets;
+ dc->dc_noutlets = noutlets;
+ dc->dc_parentcontext = ugen_currentcontext;
+ ugen_currentcontext = dc;
+ return (dc);
+}
+
+ /* first the canvas calls this to create all the boxes... */
+void ugen_add(t_dspcontext *dc, t_object *obj, int nextjump)
+{
+ t_ugenbox *x = (t_ugenbox *)getbytes(sizeof *x);
+ int i;
+ t_sigoutlet *uout;
+ t_siginlet *uin;
+
+ x->u_next = dc->dc_ugenlist;
+ dc->dc_ugenlist = x;
+ x->u_obj = obj;
+ x->u_nin = obj_nsiginlets(obj);
+ x->u_in = getbytes(x->u_nin * sizeof (*x->u_in));
+ for (uin = x->u_in, i = x->u_nin; i--; uin++)
+ uin->i_nconnect = 0;
+ x->u_nout = obj_nsigoutlets(obj);
+ x->u_out = getbytes(x->u_nout * sizeof (*x->u_out));
+ for (uout = x->u_out, i = x->u_nout; i--; uout++)
+ uout->o_connections = 0, uout->o_nconnect = 0;
+}
+
+ /* and then this to make all the connections. */
+void ugen_connect(t_dspcontext *dc, t_object *x1, int outno, t_object *x2,
+ int inno)
+{
+ t_ugenbox *u1, *u2;
+ t_sigoutlet *uout;
+ t_siginlet *uin;
+ t_sigoutconnect *oc;
+ int sigoutno = obj_sigoutletindex(x1, outno);
+ int siginno = obj_siginletindex(x2, inno);
+ if (ugen_loud)
+ post("%s -> %s: %d->%d",
+ class_getname(x1->ob_pd),
+ class_getname(x2->ob_pd), outno, inno);
+ for (u1 = dc->dc_ugenlist; u1 && u1->u_obj != x1; u1 = u1->u_next);
+ for (u2 = dc->dc_ugenlist; u2 && u2->u_obj != x2; u2 = u2->u_next);
+ if (!u1 || !u2 || siginno < 0)
+ {
+ pd_error(u1->u_obj, "signal outlet connect to nonsignal inlet (ignored)");
+ return;
+ }
+ if (sigoutno < 0 || sigoutno >= u1->u_nout || siginno >= u2->u_nin)
+ {
+ bug("ugen_connect %s %s %d %d (%d %d)",
+ class_getname(x1->ob_pd),
+ class_getname(x2->ob_pd), sigoutno, siginno, u1->u_nout,
+ u2->u_nin);
+ }
+ uout = u1->u_out + sigoutno;
+ uin = u2->u_in + siginno;
+
+ /* add a new connection to the outlet's list */
+ oc = (t_sigoutconnect *)getbytes(sizeof *oc);
+ oc->oc_next = uout->o_connections;
+ uout->o_connections = oc;
+ oc->oc_who = u2;
+ oc->oc_inno = siginno;
+ /* update inlet and outlet counts */
+ uout->o_nconnect++;
+ uin->i_nconnect++;
+}
+
+ /* get the index of a ugenbox or -1 if it's not on the list */
+static int ugen_index(t_dspcontext *dc, t_ugenbox *x)
+{
+ int ret;
+ t_ugenbox *u;
+ for (u = dc->dc_ugenlist, ret = 0; u; u = u->u_next, ret++)
+ if (u == x) return (ret);
+ return (-1);
+}
+
+ /* put a ugenbox on the chain, recursively putting any others on that
+ this one might uncover. */
+static void ugen_doit(t_dspcontext *dc, t_ugenbox *u)
+{
+ t_sigoutlet *uout;
+ t_siginlet *uin;
+ t_sigoutconnect *oc, *oc2;
+ t_class *class = pd_class(&u->u_obj->ob_pd);
+ int i, n;
+ /* suppress creating new signals for the outputs of signal
+ inlets and subpatchs; except in the case we're an inlet and "blocking"
+ is set. We don't yet know if a subcanvas will be "blocking" so there
+ we delay new signal creation, which will be handled by calling
+ signal_setborrowed in the ugen_done_graph routine below. */
+ int nonewsigs = (class == canvas_class ||
+ (class == vinlet_class) && !(dc->dc_reblock));
+ /* when we encounter a subcanvas or a signal outlet, suppress freeing
+ the input signals as they may be "borrowed" for the super or sub
+ patch; same exception as above, but also if we're "switched" we
+ have to do a copy rather than a borrow. */
+ int nofreesigs = (class == canvas_class ||
+ (class == voutlet_class) && !(dc->dc_reblock || dc->dc_switched));
+ t_signal **insig, **outsig, **sig, *s1, *s2, *s3;
+ t_ugenbox *u2;
+
+ if (ugen_loud) post("doit %s %d %d", class_getname(class), nofreesigs,
+ nonewsigs);
+ for (i = 0, uin = u->u_in; i < u->u_nin; i++, uin++)
+ {
+ if (!uin->i_nconnect)
+ {
+ t_sample *scalar;
+ s3 = signal_new(dc->dc_vecsize, dc->dc_srate);
+ /* post("%s: unconnected signal inlet set to zero",
+ class_getname(u->u_obj->ob_pd)); */
+ if (scalar = obj_findsignalscalar(u->u_obj, i))
+ dsp_add_scalarcopy(scalar, s3->s_vec, s3->s_n);
+ else
+ dsp_add_zero(s3->s_vec, s3->s_n);
+ uin->i_signal = s3;
+ s3->s_refcount = 1;
+ }
+ }
+ insig = (t_signal **)getbytes((u->u_nin + u->u_nout) * sizeof(t_signal *));
+ outsig = insig + u->u_nin;
+ for (sig = insig, uin = u->u_in, i = u->u_nin; i--; sig++, uin++)
+ {
+ int newrefcount;
+ *sig = uin->i_signal;
+ newrefcount = --(*sig)->s_refcount;
+ /* if the reference count went to zero, we free the signal now,
+ unless it's a subcanvas or outlet; these might keep the
+ signal around to send to objects connected to them. In this
+ case we increment the reference count; the corresponding decrement
+ is in sig_makereusable(). */
+ if (nofreesigs)
+ (*sig)->s_refcount++;
+ else if (!newrefcount)
+ signal_makereusable(*sig);
+ }
+ for (sig = outsig, uout = u->u_out, i = u->u_nout; i--; sig++, uout++)
+ {
+ /* similarly, for outlets of subcanvases we delay creating
+ them; instead we create "borrowed" ones so that the refcount
+ is known. The subcanvas replaces the fake signal with one showing
+ where the output data actually is, to avoid having to copy it.
+ For any other object, we just allocate a new output vector;
+ since we've already freed the inputs the objects might get called
+ "in place." */
+ if (nonewsigs)
+ {
+ *sig = uout->o_signal =
+ signal_new(0, dc->dc_srate);
+ }
+ else
+ *sig = uout->o_signal = signal_new(dc->dc_vecsize, dc->dc_srate);
+ (*sig)->s_refcount = uout->o_nconnect;
+ }
+ /* now call the DSP scheduling routine for the ugen. This
+ routine must fill in "borrowed" signal outputs in case it's either
+ a subcanvas or a signal inlet. */
+ mess1(&u->u_obj->ob_pd, gensym("dsp"), insig);
+
+ /* if any output signals aren't connected to anyone, free them
+ now; otherwise they'll either get freed when the reference count
+ goes back to zero, or even later as explained above. */
+
+ for (sig = outsig, uout = u->u_out, i = u->u_nout; i--; sig++, uout++)
+ {
+ if (!(*sig)->s_refcount)
+ signal_makereusable(*sig);
+ }
+ if (ugen_loud)
+ {
+ if (u->u_nin + u->u_nout == 0) post("put %s %d",
+ class_getname(u->u_obj->ob_pd), ugen_index(dc, u));
+ else if (u->u_nin + u->u_nout == 1) post("put %s %d (%x)",
+ class_getname(u->u_obj->ob_pd), ugen_index(dc, u), sig[0]);
+ else if (u->u_nin + u->u_nout == 2) post("put %s %d (%x %x)",
+ class_getname(u->u_obj->ob_pd), ugen_index(dc, u),
+ sig[0], sig[1]);
+ else post("put %s %d (%x %x %x ...)",
+ class_getname(u->u_obj->ob_pd), ugen_index(dc, u),
+ sig[0], sig[1], sig[2]);
+ }
+
+ /* pass it on and trip anyone whose last inlet was filled */
+ for (uout = u->u_out, i = u->u_nout; i--; uout++)
+ {
+ s1 = uout->o_signal;
+ for (oc = uout->o_connections; oc; oc = oc->oc_next)
+ {
+ u2 = oc->oc_who;
+ uin = &u2->u_in[oc->oc_inno];
+ /* if there's already someone here, sum the two */
+ if (s2 = uin->i_signal)
+ {
+ s1->s_refcount--;
+ s2->s_refcount--;
+ if (!signal_compatible(s1, s2))
+ {
+ pd_error(u->u_obj, "%s: incompatible signal inputs",
+ class_getname(u->u_obj->ob_pd));
+ return;
+ }
+ s3 = signal_newlike(s1);
+ dsp_add_plus(s1->s_vec, s2->s_vec, s3->s_vec, s1->s_n);
+ uin->i_signal = s3;
+ s3->s_refcount = 1;
+ if (!s1->s_refcount) signal_makereusable(s1);
+ if (!s2->s_refcount) signal_makereusable(s2);
+ }
+ else uin->i_signal = s1;
+ uin->i_ngot++;
+ /* if we didn't fill this inlet don't bother yet */
+ if (uin->i_ngot < uin->i_nconnect)
+ goto notyet;
+ /* if there's more than one, check them all */
+ if (u2->u_nin > 1)
+ {
+ for (uin = u2->u_in, n = u2->u_nin; n--; uin++)
+ if (uin->i_ngot < uin->i_nconnect) goto notyet;
+ }
+ /* so now we can schedule the ugen. */
+ ugen_doit(dc, u2);
+ notyet: ;
+ }
+ }
+ t_freebytes(insig,(u->u_nin + u->u_nout) * sizeof(t_signal *));
+}
+
+ /* once the DSP graph is built, we call this routine to sort it.
+ This routine also deletes the graph; later we might want to leave the
+ graph around, in case the user is editing the DSP network, to save having
+ to recreate it all the time. But not today. */
+
+void ugen_done_graph(t_dspcontext *dc)
+{
+ t_ugenbox *u, *u2;
+ t_sigoutlet *uout;
+ t_siginlet *uin;
+ t_sigoutconnect *oc, *oc2;
+ int i, n;
+ t_block *blk;
+ t_dspcontext *parent_context = dc->dc_parentcontext;
+ float parent_srate;
+ int parent_vecsize;
+ int period, frequency, phase, vecsize;
+ float srate;
+ int chainblockbegin; /* DSP chain onset before block prolog code */
+ int chainblockend; /* and after block epilog code */
+ int chainafterall; /* and after signal outlet epilog */
+ int reblock = 0, switched;
+ int downsample = 1, upsample = 1; /* IOhannes */
+ /* debugging printout */
+
+ if (ugen_loud)
+ {
+ post("ugen_done_graph...");
+ for (u = dc->dc_ugenlist; u; u = u->u_next)
+ {
+ post("ugen: %s", class_getname(u->u_obj->ob_pd));
+ for (uout = u->u_out, i = 0; i < u->u_nout; uout++, i++)
+ for (oc = uout->o_connections; oc; oc = oc->oc_next)
+ {
+ post("... out %d to %s, index %d, inlet %d", i,
+ class_getname(oc->oc_who->u_obj->ob_pd),
+ ugen_index(dc, oc->oc_who), oc->oc_inno);
+ }
+ }
+ }
+
+ /* search for an object of class "block~" */
+ for (u = dc->dc_ugenlist, blk = 0; u; u = u->u_next)
+ {
+ t_pd *zz = &u->u_obj->ob_pd;
+ if (pd_class(zz) == block_class)
+ {
+ if (blk) pd_error(blk, "conflicting block~ objects in same page");
+ else blk = (t_block *)zz;
+ }
+ }
+
+ /* figure out block size, calling frequency, sample rate */
+ if (parent_context)
+ {
+ parent_srate = parent_context->dc_srate;
+ parent_vecsize = parent_context->dc_vecsize;
+ }
+ else
+ {
+ parent_srate = sys_getsr();
+ parent_vecsize = sys_getblksize();
+ }
+ if (blk)
+ {
+ int realoverlap;
+ vecsize = blk->x_vecsize;
+ if (vecsize == 0)
+ vecsize = parent_vecsize;
+ realoverlap = blk->x_overlap;
+ if (realoverlap > vecsize) realoverlap = vecsize;
+ /* IOhannes { */
+ downsample = blk->x_downsample;
+ upsample = blk->x_upsample;
+ if (downsample > parent_vecsize) downsample=parent_vecsize;
+ period = (vecsize * downsample)/(parent_vecsize * realoverlap * upsample);
+ frequency = (parent_vecsize * realoverlap * upsample)/(vecsize * downsample);
+ /* } IOhannes*/
+ phase = blk->x_phase;
+ srate = parent_srate * realoverlap * upsample / downsample;
+ /* IOhannes */
+ if (period < 1) period = 1;
+ if (frequency < 1) frequency = 1;
+ blk->x_frequency = frequency;
+ blk->x_period = period;
+ blk->x_phase = dsp_phase & (period - 1);
+ if (! parent_context || (realoverlap != 1) || (vecsize != parent_vecsize) ||
+ (downsample != 1) || (upsample != 1)) /* IOhannes */
+ reblock = 1;
+ switched = blk->x_switched;
+ }
+ else
+ {
+ srate = parent_srate;
+ vecsize = parent_vecsize;
+ downsample = upsample = 1;/* IOhannes */
+ period = frequency = 1;
+ phase = 0;
+ if (!parent_context) reblock = 1;
+ switched = 0;
+ }
+ dc->dc_reblock = reblock;
+ dc->dc_switched = switched;
+ dc->dc_srate = srate;
+ dc->dc_vecsize = vecsize;
+
+ /* if we're reblocking or switched, we now have to create output
+ signals to fill in for the "borrowed" ones we have now. The
+ output signals will be filled by the outlet epilog code. */
+
+ if (reblock || switched)
+ {
+ t_signal **iosigs = dc->dc_iosigs;
+ if (iosigs)
+ {
+ t_signal **sigp;
+ int noutlets = dc->dc_noutlets;
+ for (i = 0, sigp = iosigs + dc->dc_ninlets; i < noutlets;
+ i++, sigp++)
+ {
+ signal_setborrowed(*sigp,
+ signal_new(parent_vecsize, parent_srate));
+ (*sigp)->s_refcount++;
+ if (ugen_loud) post("set %x->%x", *sigp, (*sigp)->s_borrowedfrom);
+ }
+ }
+ }
+ if (ugen_loud)
+ post("reblock %d, switched %d", reblock, switched);
+
+ /* schedule prologs for inlets and outlets. If the "reblock" flag
+ is set, an inlet will put code on the DSP chain to copy its input
+ into an internal buffer here, before any unit generators' DSP code
+ gets scheduled. If we don't "reblock", inlets will need to get
+ pointers to their corresponding inlets/outlets on the box we're inside,
+ if any. Outlets will also need pointers, unless we're switched, in
+ which case outlet epilog code will kick in. */
+
+ for (u = dc->dc_ugenlist; u; u = u->u_next)
+ {
+ t_pd *zz = &u->u_obj->ob_pd;
+ t_signal **insigs = dc->dc_iosigs, **outsigs = dc->dc_iosigs;
+ if (outsigs) outsigs += dc->dc_ninlets;
+
+ if (pd_class(zz) == vinlet_class)
+ vinlet_dspprolog((struct _vinlet *)zz,
+ dc->dc_iosigs, vecsize, dsp_phase, period, frequency,
+ downsample, upsample, /* IOhannes */
+ reblock, switched);
+ else if (pd_class(zz) == voutlet_class)
+ voutlet_dspprolog((struct _voutlet *)zz,
+ outsigs, vecsize, dsp_phase, period, frequency,
+ downsample, upsample, /* IOhannes */
+ reblock, switched);
+ }
+ chainblockbegin = dsp_chainsize;
+
+ if (blk && (reblock || switched)) /* add the block DSP prolog */
+ dsp_add(block_prolog, 1, blk);
+
+ /* Initialize for sorting */
+ for (u = dc->dc_ugenlist; u; u = u->u_next)
+ {
+ u->u_done = 0;
+ for (uout = u->u_out, i = u->u_nout; i--; uout++)
+ uout->o_nsent = 0;
+ for (uin = u->u_in, i = u->u_nin; i--; uin++)
+ uin->i_ngot = 0, uin->i_signal = 0;
+ }
+
+ /* Do the sort */
+
+ for (u = dc->dc_ugenlist; u; u = u->u_next)
+ {
+ /* check that we have no connected signal inlets */
+ if (u->u_done) continue;
+ for (uin = u->u_in, i = u->u_nin; i--; uin++)
+ if (uin->i_nconnect) goto next;
+
+ ugen_doit(dc, u);
+ next: ;
+ }
+
+ if (blk && (reblock || switched)) /* add block DSP epilog */
+ dsp_add(block_epilog, 1, blk);
+ chainblockend = dsp_chainsize;
+
+ /* add epilogs for outlets. */
+
+ for (u = dc->dc_ugenlist; u; u = u->u_next)
+ {
+ t_pd *zz = &u->u_obj->ob_pd;
+ if (pd_class(zz) == voutlet_class)
+ {
+ t_signal **iosigs = dc->dc_iosigs;
+ if (iosigs) iosigs += dc->dc_ninlets;
+ voutlet_dspepilog((struct _voutlet *)zz,
+ iosigs, vecsize, dsp_phase, period, frequency,
+ downsample, upsample, /* IOhannes */
+ reblock, switched);
+ }
+ }
+
+ chainafterall = dsp_chainsize;
+ if (blk)
+ {
+ blk->x_blocklength = chainblockend - chainblockbegin;
+ blk->x_epiloglength = chainafterall - chainblockend;
+ blk->x_reblock = reblock;
+ }
+
+ if (ugen_loud)
+ {
+ t_int *ip;
+ if (!dc->dc_parentcontext)
+ for (i = dsp_chainsize, ip = dsp_chain; i--; ip++)
+ post("chain %x", *ip);
+ post("... ugen_done_graph done.");
+ }
+ /* now delete everything. */
+ while (dc->dc_ugenlist)
+ {
+ for (uout = dc->dc_ugenlist->u_out, n = dc->dc_ugenlist->u_nout;
+ n--; uout++)
+ {
+ oc = uout->o_connections;
+ while (oc)
+ {
+ oc2 = oc->oc_next;
+ freebytes(oc, sizeof *oc);
+ oc = oc2;
+ }
+ }
+ freebytes(dc->dc_ugenlist->u_out, dc->dc_ugenlist->u_nout *
+ sizeof (*dc->dc_ugenlist->u_out));
+ freebytes(dc->dc_ugenlist->u_in, dc->dc_ugenlist->u_nin *
+ sizeof(*dc->dc_ugenlist->u_in));
+ u = dc->dc_ugenlist;
+ dc->dc_ugenlist = u->u_next;
+ freebytes(u, sizeof *u);
+ }
+ if (ugen_currentcontext == dc)
+ ugen_currentcontext = dc->dc_parentcontext;
+ else bug("ugen_currentcontext");
+ freebytes(dc, sizeof(*dc));
+
+}
+
+t_signal *ugen_getiosig(int index, int inout)
+{
+ if (!ugen_currentcontext) bug("ugen_getiosig");
+ if (ugen_currentcontext->dc_toplevel) return (0);
+ if (inout) index += ugen_currentcontext->dc_ninlets;
+ return (ugen_currentcontext->dc_iosigs[index]);
+}
+
+
+/* -------------------- setup routine -------------------------- */
+
+void d_ugen_setup(void) /* really just block_setup */
+{
+ block_class = class_new(gensym("block~"), (t_newmethod)block_new, 0,
+ sizeof(t_block), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT/*IOhannes*/, 0);
+ class_addcreator((t_newmethod)switch_new, gensym("switch~"),
+ A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT/*IOhannes*/, 0);
+ class_addmethod(block_class, (t_method)block_dsp, gensym("dsp"), 0);
+ class_addfloat(block_class, block_float);
+}
+
diff --git a/pd/src/g_all_guis.c b/pd/src/g_all_guis.c
new file mode 100644
index 00000000..5bbf2f4a
--- /dev/null
+++ b/pd/src/g_all_guis.c
@@ -0,0 +1,937 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
+/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "m_imp.h"
+#include "g_canvas.h"
+#include "t_tk.h"
+#include "g_all_guis.h"
+#include <math.h>
+
+#ifdef NT
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+/* #define GGEE_HSLIDER_COMPATIBLE */
+
+/*------------------ global varaibles -------------------------*/
+
+t_symbol *iemgui_key_sym=0;
+
+int iemgui_color_hex[]=
+{
+ 16579836, 10526880, 4210752, 16572640, 16572608,
+ 16579784, 14220504, 14220540, 14476540, 16308476,
+ 14737632, 8158332, 2105376, 16525352, 16559172,
+ 15263784, 1370132, 2684148, 3952892, 16003312,
+ 12369084, 6316128, 0, 9177096, 5779456,
+ 7874580, 2641940, 17488, 5256, 5767248
+};
+
+int iemgui_vu_db2i[]=
+{
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 9, 9, 9, 9, 9,10,10,10,10,10,
+ 11,11,11,11,11,12,12,12,12,12,
+ 13,13,13,13,14,14,14,14,15,15,
+ 15,15,16,16,16,16,17,17,17,18,
+ 18,18,19,19,19,20,20,20,21,21,
+ 22,22,23,23,24,24,25,26,27,28,
+ 29,30,31,32,33,33,34,34,35,35,
+ 36,36,37,37,37,38,38,38,39,39,
+ 39,39,39,39,40,40
+};
+
+int iemgui_vu_col[]=
+{
+ 0,17,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
+ 15,15,15,15,15,15,15,15,15,15,14,14,13,13,13,13,13,13,13,13,13,13,13,19,19,19
+};
+
+char *iemgui_vu_scale_str[]=
+{
+ "",
+ "<-99",
+ "",
+ "",
+ "",
+ "-50",
+ "",
+ "",
+ "",
+ "-30",
+ "",
+ "",
+ "",
+ "-20",
+ "",
+ "",
+ "",
+ "-12",
+ "",
+ "",
+ "",
+ "-6",
+ "",
+ "",
+ "",
+ "-2",
+ "",
+ "",
+ "",
+ "-0dB",
+ "",
+ "",
+ "",
+ "+2",
+ "",
+ "",
+ "",
+ "+6",
+ "",
+ "",
+ "",
+ ">+12",
+ "",
+ "",
+ "",
+ "",
+ "",
+};
+
+
+/*------------------ global functions -------------------------*/
+
+
+int iemgui_clip_size(int size)
+{
+ if(size < IEM_GUI_MINSIZE)
+ size = IEM_GUI_MINSIZE;
+ return(size);
+}
+
+int iemgui_clip_font(int size)
+{
+ if(size < IEM_FONT_MINSIZE)
+ size = IEM_FONT_MINSIZE;
+ return(size);
+}
+
+int iemgui_modulo_color(int col)
+{
+ while(col >= IEM_GUI_MAX_COLOR)
+ col -= IEM_GUI_MAX_COLOR;
+ while(col < 0)
+ col += IEM_GUI_MAX_COLOR;
+ return(col);
+}
+
+void iemgui_raute2dollar(t_symbol *s)
+{
+ if(s->s_name[0] == '#')
+ s->s_name[0] = '$';
+}
+
+void iemgui_dollar2raute(t_symbol *s)
+{
+ if(s->s_name[0] == '$')
+ s->s_name[0] = '#';
+}
+
+t_symbol *iemgui_unique2dollarzero(t_symbol *s, int unique_num, int and_unique_flag)
+{
+ if(and_unique_flag)
+ {
+ int l=0;
+ char *b, str[144];
+
+ sprintf(str, "%d", unique_num);
+ while(str[l])
+ {
+ if(s->s_name[l] != str[l])
+ return(s);
+ else
+ l++;
+ }
+ str[0] = '$';
+ str[1] = '0';
+ str[2] = 0;
+ b = s->s_name + l;
+ if(strlen(b) >= IEM_MAX_SYM_LEN)
+ strncat(str, b, IEM_MAX_SYM_LEN-1);
+ else
+ strcat(str, b);
+ return(gensym(str));
+ }
+ else
+ return(s);
+}
+
+t_symbol *iemgui_sym2dollararg(t_symbol *s, int nth_arg, int tail_len)
+{
+ if(nth_arg)
+ {
+ char *b, str[144];
+ int i=(int)strlen(s->s_name) - tail_len;
+
+ sprintf(str, "_%d", nth_arg);
+ str[0] = '$';
+ if(i < 0) i = 0;
+ b = s->s_name + i;
+ strcat(str, b);
+ return(gensym(str));
+ }
+ else
+ return(s);
+}
+
+t_symbol *iemgui_dollarzero2unique(t_symbol *s, int unique_num)
+{
+ int l;
+ char *b, str[144];
+
+ sprintf(str, "%d", unique_num);
+ l = (int)strlen(s->s_name);
+ b = s->s_name + 2;
+ if(l < 2)
+ strcat(str, "shorty");
+ else if(l >= IEM_MAX_SYM_LEN)
+ strncat(str, b, IEM_MAX_SYM_LEN-1);
+ else
+ strcat(str, b);
+ return(gensym(str));
+}
+
+t_symbol *iemgui_dollararg2sym(t_symbol *s, int nth_arg, int tail_len, int pargc, t_atom *pargv)
+{
+ int l=(int)strlen(s->s_name);
+ char *b, str[288]="0";
+ t_symbol *s2;
+
+ if(pargc <= 0){}
+ else if(nth_arg < 1){}
+ else if(nth_arg > pargc){}
+ else if(IS_A_FLOAT(pargv, nth_arg-1))
+ sprintf(str, "%d", atom_getintarg(nth_arg-1, pargc, pargv));
+ else if(IS_A_SYMBOL(pargv, nth_arg-1))
+ {
+ s2 = atom_getsymbolarg(nth_arg-1, pargc, pargv);
+ strcpy(str, s2->s_name);
+ }
+ b = s->s_name + (l - tail_len);
+ if(l <= tail_len)
+ strcat(str, "shorty");
+ else if(l >= IEM_MAX_SYM_LEN)
+ strncat(str, b, IEM_MAX_SYM_LEN-1);
+ else
+ strcat(str, b);
+ return(gensym(str));
+}
+
+int iemgui_is_dollarzero(t_symbol *s)
+{
+ char *name=s->s_name;
+
+ if((int)strlen(name) >= 2)
+ {
+ if((name[0] == '$') && (name[1] == '0') && ((name[2] < '0') || (name[2] > '9')))
+ return(1);
+ }
+ return(0);
+}
+
+int iemgui_is_dollararg(t_symbol *s, int *tail_len)
+{
+ char *name=s->s_name;
+
+ *tail_len = (int)strlen(name);
+ if(*tail_len >= 2)
+ {
+ if((name[0] == '$') && (name[1] >= '1') && (name[1] <= '9'))
+ {
+ int i=2, arg=(int)(name[1]-'0');
+
+ (*tail_len) -= 2;
+ while(name[i] && (name[i] >= '0') && (name[i] <= '9'))
+ {
+ arg *= 10;
+ arg += (int)(name[i]-'0');
+ i++;
+ (*tail_len)--;
+ }
+ return(arg);
+ }
+ }
+ return(0);
+}
+
+void iemgui_fetch_unique(t_iemgui *iemgui)
+{
+ if(!iemgui->x_unique_num)
+ {
+ pd_bind(&iemgui->x_glist->gl_gobj.g_pd, gensym("#X"));
+ iemgui->x_unique_num = canvas_getdollarzero();
+ pd_unbind(&iemgui->x_glist->gl_gobj.g_pd, gensym("#X"));
+ }
+}
+
+void iemgui_fetch_parent_args(t_iemgui *iemgui, int *pargc, t_atom **pargv)
+{
+ t_canvas *canvas=glist_getcanvas(iemgui->x_glist);
+
+ canvas_setcurrent(canvas);
+ canvas_getargs(pargc, pargv);
+ canvas_unsetcurrent(canvas);
+}
+
+void iemgui_verify_snd_ne_rcv(t_iemgui *iemgui)
+{
+ iemgui->x_fsf.x_put_in2out = 1;
+ if(iemgui->x_fsf.x_snd_able && iemgui->x_fsf.x_rcv_able)
+ {
+ if(!strcmp(iemgui->x_snd->s_name, iemgui->x_rcv->s_name))
+ iemgui->x_fsf.x_put_in2out = 0;
+ }
+}
+
+void iemgui_all_unique2dollarzero(t_iemgui *iemgui, t_symbol **srlsym)
+{
+ iemgui_fetch_unique(iemgui);
+ srlsym[0] = iemgui_unique2dollarzero(srlsym[0], iemgui->x_unique_num,
+ iemgui->x_fsf.x_snd_is_unique);
+ srlsym[1] = iemgui_unique2dollarzero(srlsym[1], iemgui->x_unique_num,
+ iemgui->x_fsf.x_rcv_is_unique);
+ srlsym[2] = iemgui_unique2dollarzero(srlsym[2], iemgui->x_unique_num,
+ iemgui->x_fsf.x_lab_is_unique);
+}
+
+void iemgui_all_sym2dollararg(t_iemgui *iemgui, t_symbol **srlsym)
+{
+ srlsym[0] = iemgui_sym2dollararg(srlsym[0], iemgui->x_isa.x_snd_is_arg_num,
+ iemgui->x_isa.x_snd_arg_tail_len);
+ srlsym[1] = iemgui_sym2dollararg(srlsym[1], iemgui->x_isa.x_rcv_is_arg_num,
+ iemgui->x_isa.x_rcv_arg_tail_len);
+ srlsym[2] = iemgui_sym2dollararg(srlsym[2], iemgui->x_fsf.x_lab_is_arg_num,
+ iemgui->x_fsf.x_lab_arg_tail_len);
+}
+
+void iemgui_all_dollarzero2unique(t_iemgui *iemgui, t_symbol **srlsym)
+{
+ iemgui_fetch_unique(iemgui);
+ if(iemgui_is_dollarzero(srlsym[0]))
+ {
+ iemgui->x_fsf.x_snd_is_unique = 1;
+ iemgui->x_isa.x_snd_is_arg_num = 0;
+ iemgui->x_isa.x_snd_arg_tail_len = 0;
+ srlsym[0] = iemgui_dollarzero2unique(srlsym[0], iemgui->x_unique_num);
+ }
+ else
+ iemgui->x_fsf.x_snd_is_unique = 0;
+ if(iemgui_is_dollarzero(srlsym[1]))
+ {
+ iemgui->x_fsf.x_rcv_is_unique = 1;
+ iemgui->x_isa.x_rcv_is_arg_num = 0;
+ iemgui->x_isa.x_rcv_arg_tail_len = 0;
+ srlsym[1] = iemgui_dollarzero2unique(srlsym[1], iemgui->x_unique_num);
+ }
+ else
+ iemgui->x_fsf.x_rcv_is_unique = 0;
+ if(iemgui_is_dollarzero(srlsym[2]))
+ {
+ iemgui->x_fsf.x_lab_is_unique = 1;
+ iemgui->x_fsf.x_lab_is_arg_num = 0;
+ iemgui->x_fsf.x_lab_arg_tail_len = 0;
+ srlsym[2] = iemgui_dollarzero2unique(srlsym[2], iemgui->x_unique_num);
+ }
+ else
+ iemgui->x_fsf.x_lab_is_unique = 0;
+}
+
+void iemgui_all_dollararg2sym(t_iemgui *iemgui, t_symbol **srlsym)
+{
+ int pargc, tail_len, nth_arg;
+ t_atom *pargv;
+
+ iemgui_fetch_parent_args(iemgui, &pargc, &pargv);
+ if(nth_arg = iemgui_is_dollararg(srlsym[0], &tail_len))
+ {
+ iemgui->x_isa.x_snd_is_arg_num = nth_arg;
+ iemgui->x_isa.x_snd_arg_tail_len = tail_len;
+ iemgui->x_fsf.x_snd_is_unique = 0;
+ srlsym[0] = iemgui_dollararg2sym(srlsym[0], nth_arg, tail_len, pargc, pargv);
+ }
+ else
+ {
+ iemgui->x_isa.x_snd_is_arg_num = 0;
+ iemgui->x_isa.x_snd_arg_tail_len = 0;
+ }
+ if(nth_arg = iemgui_is_dollararg(srlsym[1], &tail_len))
+ {
+ iemgui->x_isa.x_rcv_is_arg_num = nth_arg;
+ iemgui->x_isa.x_rcv_arg_tail_len = tail_len;
+ iemgui->x_fsf.x_rcv_is_unique = 0;
+ srlsym[1] = iemgui_dollararg2sym(srlsym[1], nth_arg, tail_len, pargc, pargv);
+ }
+ else
+ {
+ iemgui->x_isa.x_rcv_is_arg_num = 0;
+ iemgui->x_isa.x_rcv_arg_tail_len = 0;
+ }
+ if(nth_arg = iemgui_is_dollararg(srlsym[2], &tail_len))
+ {
+ iemgui->x_fsf.x_lab_is_arg_num = nth_arg;
+ iemgui->x_fsf.x_lab_arg_tail_len = tail_len;
+ iemgui->x_fsf.x_lab_is_unique = 0;
+ srlsym[2] = iemgui_dollararg2sym(srlsym[2], nth_arg, tail_len, pargc, pargv);
+ }
+ else
+ {
+ iemgui->x_fsf.x_lab_is_arg_num = 0;
+ iemgui->x_fsf.x_lab_arg_tail_len = 0;
+ }
+}
+
+void iemgui_first_dollararg2sym(t_iemgui *iemgui, t_symbol **srlsym)
+{
+ int pargc=0, tail_len, nth_arg;
+ t_atom pargv;
+ char *name;
+
+ SETFLOAT(&pargv, 0.0);
+ name = srlsym[0]->s_name;
+ if(iemgui->x_isa.x_snd_is_arg_num && (name[0] == '$')
+ && (name[1] >= '1') && (name[1] <= '9'))
+ {
+ srlsym[0] = iemgui_dollararg2sym(srlsym[0], iemgui->x_isa.x_snd_is_arg_num,
+ iemgui->x_isa.x_snd_arg_tail_len, pargc, &pargv);
+ }
+ name = srlsym[1]->s_name;
+ if(iemgui->x_isa.x_rcv_is_arg_num && (name[0] == '$')
+ && (name[1] >= '1') && (name[1] <= '9'))
+ {
+ srlsym[1] = iemgui_dollararg2sym(srlsym[1], iemgui->x_isa.x_rcv_is_arg_num,
+ iemgui->x_isa.x_rcv_arg_tail_len, pargc, &pargv);
+ }
+ name = srlsym[2]->s_name;
+ if(iemgui->x_fsf.x_lab_is_arg_num && (name[0] == '$')
+ && (name[1] >= '1') && (name[1] <= '9'))
+ {
+ srlsym[2] = iemgui_dollararg2sym(srlsym[2], iemgui->x_fsf.x_lab_is_arg_num,
+ iemgui->x_fsf.x_lab_arg_tail_len, pargc, &pargv);
+ }
+}
+
+void iemgui_all_col2save(t_iemgui *iemgui, int *bflcol)
+{
+ bflcol[0] = -1 - (((0xfc0000 & iemgui->x_bcol) >> 6)|
+ ((0xfc00 & iemgui->x_bcol) >> 4)|((0xfc & iemgui->x_bcol) >> 2));
+ bflcol[1] = -1 - (((0xfc0000 & iemgui->x_fcol) >> 6)|
+ ((0xfc00 & iemgui->x_fcol) >> 4)|((0xfc & iemgui->x_fcol) >> 2));
+ bflcol[2] = -1 - (((0xfc0000 & iemgui->x_lcol) >> 6)|
+ ((0xfc00 & iemgui->x_lcol) >> 4)|((0xfc & iemgui->x_lcol) >> 2));
+}
+
+void iemgui_all_colfromload(t_iemgui *iemgui, int *bflcol)
+{
+ if(bflcol[0] < 0)
+ {
+ bflcol[0] = -1 - bflcol[0];
+ iemgui->x_bcol = ((bflcol[0] & 0x3f000) << 6)|((bflcol[0] & 0xfc0) << 4)|
+ ((bflcol[0] & 0x3f) << 2);
+ }
+ else
+ {
+ bflcol[0] = iemgui_modulo_color(bflcol[0]);
+ iemgui->x_bcol = iemgui_color_hex[bflcol[0]];
+ }
+ if(bflcol[1] < 0)
+ {
+ bflcol[1] = -1 - bflcol[1];
+ iemgui->x_fcol = ((bflcol[1] & 0x3f000) << 6)|((bflcol[1] & 0xfc0) << 4)|
+ ((bflcol[1] & 0x3f) << 2);
+ }
+ else
+ {
+ bflcol[1] = iemgui_modulo_color(bflcol[1]);
+ iemgui->x_fcol = iemgui_color_hex[bflcol[1]];
+ }
+ if(bflcol[2] < 0)
+ {
+ bflcol[2] = -1 - bflcol[2];
+ iemgui->x_lcol = ((bflcol[2] & 0x3f000) << 6)|((bflcol[2] & 0xfc0) << 4)|
+ ((bflcol[2] & 0x3f) << 2);
+ }
+ else
+ {
+ bflcol[2] = iemgui_modulo_color(bflcol[2]);
+ iemgui->x_lcol = iemgui_color_hex[bflcol[2]];
+ }
+}
+
+int iemgui_compatible_col(int i)
+{
+ int j;
+
+ if(i >= 0)
+ {
+ j = iemgui_modulo_color(i);
+ return(iemgui_color_hex[(j)]);
+ }
+ else
+ return((-1 -i)&0xffffff);
+}
+
+void iemgui_all_dollar2raute(t_symbol **srlsym)
+{
+ if(srlsym[0]->s_name[0] == '$')
+ srlsym[0]->s_name[0] = '#';
+ if(srlsym[1]->s_name[0] == '$')
+ srlsym[1]->s_name[0] = '#';
+ if(srlsym[2]->s_name[0] == '$')
+ srlsym[2]->s_name[0] = '#';
+}
+
+void iemgui_all_raute2dollar(t_symbol **srlsym)
+{
+ if(srlsym[0]->s_name[0] == '#')
+ srlsym[0]->s_name[0] = '$';
+ if(srlsym[1]->s_name[0] == '#')
+ srlsym[1]->s_name[0] = '$';
+ if(srlsym[2]->s_name[0] == '#')
+ srlsym[2]->s_name[0] = '$';
+}
+
+void iemgui_send(void *x, t_iemgui *iemgui, t_symbol *s)
+{
+ t_symbol *snd;
+ int pargc, tail_len, nth_arg, sndable=1, oldsndrcvable=0;
+ t_atom *pargv;
+
+ if(iemgui->x_fsf.x_rcv_able)
+ oldsndrcvable += IEM_GUI_OLD_RCV_FLAG;
+ if(iemgui->x_fsf.x_snd_able)
+ oldsndrcvable += IEM_GUI_OLD_SND_FLAG;
+
+ if(!strcmp(s->s_name, "empty")) sndable = 0;
+ iemgui_raute2dollar(s);
+ iemgui_fetch_unique(iemgui);
+ snd = s;
+ if(iemgui_is_dollarzero(snd))
+ {
+ iemgui->x_fsf.x_snd_is_unique = 1;
+ iemgui->x_isa.x_snd_is_arg_num = 0;
+ iemgui->x_isa.x_snd_arg_tail_len = 0;
+ snd = iemgui_dollarzero2unique(snd, iemgui->x_unique_num);
+ }
+ else
+ iemgui->x_fsf.x_snd_is_unique = 0;
+ iemgui_fetch_parent_args(iemgui, &pargc, &pargv);
+ if(nth_arg = iemgui_is_dollararg(snd, &tail_len))
+ {
+ iemgui->x_isa.x_snd_is_arg_num = nth_arg;
+ iemgui->x_isa.x_snd_arg_tail_len = tail_len;
+ iemgui->x_fsf.x_snd_is_unique = 0;
+ snd = iemgui_dollararg2sym(snd, nth_arg, tail_len, pargc, pargv);
+ }
+ else
+ {
+ iemgui->x_isa.x_snd_is_arg_num = 0;
+ iemgui->x_isa.x_snd_arg_tail_len = 0;
+ }
+ iemgui->x_snd = snd;
+ iemgui->x_fsf.x_snd_able = sndable;
+ iemgui_verify_snd_ne_rcv(iemgui);
+ (*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_IO + oldsndrcvable);
+}
+
+void iemgui_receive(void *x, t_iemgui *iemgui, t_symbol *s)
+{
+ t_symbol *rcv;
+ int pargc, tail_len, nth_arg, rcvable=1, oldsndrcvable=0;
+ t_atom *pargv;
+
+ if(iemgui->x_fsf.x_rcv_able)
+ oldsndrcvable += IEM_GUI_OLD_RCV_FLAG;
+ if(iemgui->x_fsf.x_snd_able)
+ oldsndrcvable += IEM_GUI_OLD_SND_FLAG;
+
+ if(!strcmp(s->s_name, "empty")) rcvable = 0;
+ iemgui_raute2dollar(s);
+ rcv = s;
+ iemgui_fetch_unique(iemgui);
+ if(iemgui_is_dollarzero(rcv))
+ {
+ iemgui->x_fsf.x_rcv_is_unique = 1;
+ iemgui->x_isa.x_rcv_is_arg_num = 0;
+ iemgui->x_isa.x_rcv_arg_tail_len = 0;
+ rcv = iemgui_dollarzero2unique(rcv, iemgui->x_unique_num);
+ }
+ else
+ iemgui->x_fsf.x_rcv_is_unique = 0;
+ iemgui_fetch_parent_args(iemgui, &pargc, &pargv);
+ if(nth_arg = iemgui_is_dollararg(rcv, &tail_len))
+ {
+ iemgui->x_isa.x_rcv_is_arg_num = nth_arg;
+ iemgui->x_isa.x_rcv_arg_tail_len = tail_len;
+ iemgui->x_fsf.x_rcv_is_unique = 0;
+ rcv = iemgui_dollararg2sym(rcv, nth_arg, tail_len, pargc, pargv);
+ }
+ else
+ {
+ iemgui->x_isa.x_rcv_is_arg_num = 0;
+ iemgui->x_isa.x_rcv_arg_tail_len = 0;
+ }
+ if(rcvable)
+ {
+ if(strcmp(rcv->s_name, iemgui->x_rcv->s_name))
+ {
+ if(iemgui->x_fsf.x_rcv_able)
+ pd_unbind(&iemgui->x_obj.ob_pd, iemgui->x_rcv);
+ iemgui->x_rcv = rcv;
+ pd_bind(&iemgui->x_obj.ob_pd, iemgui->x_rcv);
+ }
+ }
+ else if(!rcvable && iemgui->x_fsf.x_rcv_able)
+ {
+ pd_unbind(&iemgui->x_obj.ob_pd, iemgui->x_rcv);
+ iemgui->x_rcv = rcv;
+ }
+ iemgui->x_fsf.x_rcv_able = rcvable;
+ iemgui_verify_snd_ne_rcv(iemgui);
+ (*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_IO + oldsndrcvable);
+}
+
+void iemgui_label(void *x, t_iemgui *iemgui, t_symbol *s)
+{
+ t_symbol *lab;
+ int pargc, tail_len, nth_arg;
+ t_atom *pargv;
+
+ iemgui_raute2dollar(s);
+ lab = s;
+ iemgui_fetch_unique(iemgui);
+
+ if(iemgui_is_dollarzero(lab))
+ {
+ iemgui->x_fsf.x_lab_is_unique = 1;
+ iemgui->x_fsf.x_lab_is_arg_num = 0;
+ iemgui->x_fsf.x_lab_arg_tail_len = 0;
+ lab = iemgui_dollarzero2unique(lab, iemgui->x_unique_num);
+ }
+ else
+ iemgui->x_fsf.x_lab_is_unique = 0;
+
+ iemgui_fetch_parent_args(iemgui, &pargc, &pargv);
+ if(nth_arg = iemgui_is_dollararg(lab, &tail_len))
+ {
+ iemgui->x_fsf.x_lab_is_arg_num = nth_arg;
+ iemgui->x_fsf.x_lab_arg_tail_len = tail_len;
+ iemgui->x_fsf.x_lab_is_unique = 0;
+ lab = iemgui_dollararg2sym(lab, nth_arg, tail_len, pargc, pargv);
+ }
+ else
+ {
+ iemgui->x_fsf.x_lab_is_arg_num = 0;
+ iemgui->x_fsf.x_lab_arg_tail_len = 0;
+ }
+ iemgui->x_lab = lab;
+ if(glist_isvisible(iemgui->x_glist))
+ sys_vgui(".x%x.c itemconfigure %xLABEL -text {%s} \n",
+ glist_getcanvas(iemgui->x_glist), x,
+ strcmp(s->s_name, "empty")?iemgui->x_lab->s_name:"");
+}
+
+void iemgui_label_pos(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av)
+{
+ iemgui->x_ldx = (int)atom_getintarg(0, ac, av);
+ iemgui->x_ldy = (int)atom_getintarg(1, ac, av);
+ if(glist_isvisible(iemgui->x_glist))
+ sys_vgui(".x%x.c coords %xLABEL %d %d\n",
+ glist_getcanvas(iemgui->x_glist), x,
+ iemgui->x_obj.te_xpix+iemgui->x_ldx,
+ iemgui->x_obj.te_ypix+iemgui->x_ldy);
+}
+
+void iemgui_label_font(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av)
+{
+ int f = (int)atom_getintarg(0, ac, av);
+
+ if(f == 1) strcpy(iemgui->x_font, "helvetica");
+ else if(f == 2) strcpy(iemgui->x_font, "times");
+ else
+ {
+ f = 0;
+ strcpy(iemgui->x_font, "courier");
+ }
+ iemgui->x_fsf.x_font_style = f;
+ f = (int)atom_getintarg(1, ac, av);
+ if(f < 4)
+ f = 4;
+ iemgui->x_fontsize = f;
+ if(glist_isvisible(iemgui->x_glist))
+ sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold}\n",
+ glist_getcanvas(iemgui->x_glist), x, iemgui->x_font, iemgui->x_fontsize);
+}
+
+void iemgui_size(void *x, t_iemgui *iemgui)
+{
+ if(glist_isvisible(iemgui->x_glist))
+ {
+ (*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(iemgui->x_glist), (t_text*)x);
+ }
+}
+
+void iemgui_delta(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av)
+{
+ iemgui->x_obj.te_xpix += (int)atom_getintarg(0, ac, av);
+ iemgui->x_obj.te_ypix += (int)atom_getintarg(1, ac, av);
+ if(glist_isvisible(iemgui->x_glist))
+ {
+ (*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(iemgui->x_glist), (t_text*)x);
+ }
+}
+
+void iemgui_pos(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av)
+{
+ iemgui->x_obj.te_xpix = (int)atom_getintarg(0, ac, av);
+ iemgui->x_obj.te_ypix = (int)atom_getintarg(1, ac, av);
+ if(glist_isvisible(iemgui->x_glist))
+ {
+ (*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(iemgui->x_glist), (t_text*)x);
+ }
+}
+
+void iemgui_color(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av)
+{
+ iemgui->x_bcol = iemgui_compatible_col(atom_getintarg(0, ac, av));
+ if(ac > 2)
+ {
+ iemgui->x_fcol = iemgui_compatible_col(atom_getintarg(1, ac, av));
+ iemgui->x_lcol = iemgui_compatible_col(atom_getintarg(2, ac, av));
+ }
+ else
+ iemgui->x_lcol = iemgui_compatible_col(atom_getintarg(1, ac, av));
+ if(glist_isvisible(iemgui->x_glist))
+ (*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_CONFIG);
+}
+
+int iemgui_list(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av)
+{
+ if(iemgui->x_fsf.x_selected)
+ {
+ if((ac == 2)&&IS_A_FLOAT(av,0)&&IS_A_SYMBOL(av,1))
+ {
+ t_symbol *key = atom_getsymbolarg(1, ac, av);
+ int keydown = atom_getintarg(0, ac, av);
+
+ if(keydown)
+ {
+ int refresh = 1,i,d=1;
+ static char buf[20];
+
+ buf[0] = 0;
+ if(!strcmp(key->s_name, "Shift_L")||!strcmp(key->s_name, "Shift_R"))
+ iemgui->x_fsf.x_shiftdown = 1;
+ else
+ {
+ if(iemgui->x_fsf.x_shiftdown)
+ d = 10;
+ if(!strcmp(key->s_name, "Up"))
+ iemgui->x_obj.te_ypix -= d;
+ else if(!strcmp(key->s_name, "Down"))
+ iemgui->x_obj.te_ypix += d;
+ else if(!strcmp(key->s_name, "Left"))
+ iemgui->x_obj.te_xpix -= d;
+ else if(!strcmp(key->s_name, "Right"))
+ iemgui->x_obj.te_xpix += d;
+ else
+ refresh = 0;
+ if(refresh)
+ return(1);
+ }
+ return(0);
+ }
+ else
+ {
+ if(!strcmp(key->s_name, "Shift_L")||!strcmp(key->s_name, "Shift_R"))
+ iemgui->x_fsf.x_shiftdown = 0;
+ return(0);
+ }
+ }
+ else
+ return(-1);
+ }
+ else
+ return(-1);
+}
+
+void iemgui_displace(t_gobj *z, t_glist *glist, int dx, int dy)
+{
+ t_iemguidummy *x = (t_iemguidummy *)z;
+
+ x->x_gui.x_obj.te_xpix += dx;
+ x->x_gui.x_obj.te_ypix += dy;
+ (*x->x_gui.x_draw)((void *)z, glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(glist), (t_text *)z);
+}
+
+void iemgui_select(t_gobj *z, t_glist *glist, int selected)
+{
+ t_iemguidummy *x = (t_iemguidummy *)z;
+
+ x->x_gui.x_fsf.x_selected = selected;
+ (*x->x_gui.x_draw)((void *)z, glist, IEM_GUI_DRAW_MODE_SELECT);
+}
+
+void iemgui_delete(t_gobj *z, t_glist *glist)
+{
+ canvas_deletelinesfor(glist, (t_text *)z);
+}
+
+void iemgui_vis(t_gobj *z, t_glist *glist, int vis)
+{
+ t_iemguidummy *x = (t_iemguidummy *)z;
+ t_rtext *y;
+
+ if(vis)
+ {
+ y = rtext_new_without_senditup(glist, (t_text *)z, glist->gl_editor->e_rtext);
+ (*x->x_gui.x_draw)((void *)z, glist, IEM_GUI_DRAW_MODE_NEW);
+ }
+ else
+ {
+ y = glist_findrtext(glist, (t_text *)z);
+ (*x->x_gui.x_draw)((void *)z, glist, IEM_GUI_DRAW_MODE_ERASE);
+ rtext_free(y);
+ }
+}
+
+void iemgui_save(t_iemgui *iemgui, t_symbol **srl, int *bflcol)
+{
+ srl[0] = iemgui->x_snd;
+ srl[1] = iemgui->x_rcv;
+ srl[2] = iemgui->x_lab;
+ iemgui_all_unique2dollarzero(iemgui, srl);
+ iemgui_all_sym2dollararg(iemgui, srl);
+ iemgui_all_col2save(iemgui, bflcol);
+}
+
+void iemgui_properties(t_iemgui *iemgui, t_symbol **srl)
+{
+ srl[0] = iemgui->x_snd;
+ srl[1] = iemgui->x_rcv;
+ srl[2] = iemgui->x_lab;
+ iemgui_all_unique2dollarzero(iemgui, srl);
+ iemgui_all_sym2dollararg(iemgui, srl);
+ iemgui_all_dollar2raute(srl);
+}
+
+int iemgui_dialog(t_iemgui *iemgui, t_symbol **srl, int argc, t_atom *argv)
+{
+ char str[144];
+ int init = (int)atom_getintarg(5, argc, argv);
+ int ldx = (int)atom_getintarg(10, argc, argv);
+ int ldy = (int)atom_getintarg(11, argc, argv);
+ int f = (int)atom_getintarg(12, argc, argv);
+ int fs = (int)atom_getintarg(13, argc, argv);
+ int bcol = (int)atom_getintarg(14, argc, argv);
+ int fcol = (int)atom_getintarg(15, argc, argv);
+ int lcol = (int)atom_getintarg(16, argc, argv);
+ int sndable=1, rcvable=1, oldsndrcvable=0;
+
+ if(iemgui->x_fsf.x_rcv_able)
+ oldsndrcvable += IEM_GUI_OLD_RCV_FLAG;
+ if(iemgui->x_fsf.x_snd_able)
+ oldsndrcvable += IEM_GUI_OLD_SND_FLAG;
+ if(IS_A_SYMBOL(argv,7))
+ srl[0] = atom_getsymbolarg(7, argc, argv);
+ else if(IS_A_FLOAT(argv,7))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(7, argc, argv));
+ srl[0] = gensym(str);
+ }
+ if(IS_A_SYMBOL(argv,8))
+ srl[1] = atom_getsymbolarg(8, argc, argv);
+ else if(IS_A_FLOAT(argv,8))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(8, argc, argv));
+ srl[1] = gensym(str);
+ }
+ if(IS_A_SYMBOL(argv,9))
+ srl[2] = atom_getsymbolarg(9, argc, argv);
+ else if(IS_A_FLOAT(argv,9))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(9, argc, argv));
+ srl[2] = gensym(str);
+ }
+ if(init != 0) init = 1;
+ iemgui->x_isa.x_loadinit = init;
+ if(!strcmp(srl[0]->s_name, "empty")) sndable = 0;
+ if(!strcmp(srl[1]->s_name, "empty")) rcvable = 0;
+ iemgui_all_raute2dollar(srl);
+ iemgui_all_dollarzero2unique(iemgui, srl);
+ iemgui_all_dollararg2sym(iemgui, srl);
+ if(rcvable)
+ {
+ if(strcmp(srl[1]->s_name, iemgui->x_rcv->s_name))
+ {
+ if(iemgui->x_fsf.x_rcv_able)
+ pd_unbind(&iemgui->x_obj.ob_pd, iemgui->x_rcv);
+ iemgui->x_rcv = srl[1];
+ pd_bind(&iemgui->x_obj.ob_pd, iemgui->x_rcv);
+ }
+ }
+ else if(!rcvable && iemgui->x_fsf.x_rcv_able)
+ {
+ pd_unbind(&iemgui->x_obj.ob_pd, iemgui->x_rcv);
+ iemgui->x_rcv = srl[1];
+ }
+ iemgui->x_snd = srl[0];
+ iemgui->x_fsf.x_snd_able = sndable;
+ iemgui->x_fsf.x_rcv_able = rcvable;
+ iemgui->x_lcol = lcol & 0xffffff;
+ iemgui->x_fcol = fcol & 0xffffff;
+ iemgui->x_bcol = bcol & 0xffffff;
+ iemgui->x_lab = srl[2];
+ iemgui->x_ldx = ldx;
+ iemgui->x_ldy = ldy;
+ if(f == 1) strcpy(iemgui->x_font, "helvetica");
+ else if(f == 2) strcpy(iemgui->x_font, "times");
+ else
+ {
+ f = 0;
+ strcpy(iemgui->x_font, "courier");
+ }
+ iemgui->x_fsf.x_font_style = f;
+ if(fs < 4)
+ fs = 4;
+ iemgui->x_fontsize = fs;
+ iemgui_verify_snd_ne_rcv(iemgui);
+ return(oldsndrcvable);
+}
diff --git a/pd/src/g_all_guis.h b/pd/src/g_all_guis.h
new file mode 100644
index 00000000..54f9cef4
--- /dev/null
+++ b/pd/src/g_all_guis.h
@@ -0,0 +1,320 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+/* g_7_guis.h written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
+
+
+#define IEM_GUI_COLNR_WHITE 0
+#define IEM_GUI_COLNR_ML_GREY 1
+#define IEM_GUI_COLNR_D_GREY 2
+#define IEM_GUI_COLNR_L_RED 3
+#define IEM_GUI_COLNR_L_ORANGE 4
+#define IEM_GUI_COLNR_L_YELLOW 5
+#define IEM_GUI_COLNR_L_GREEN 6
+#define IEM_GUI_COLNR_L_CYAN 7
+#define IEM_GUI_COLNR_L_BLUE 8
+#define IEM_GUI_COLNR_L_MAGENTA 9
+
+#define IEM_GUI_COLNR_LL_GREY 10
+#define IEM_GUI_COLNR_M_GREY 11
+#define IEM_GUI_COLNR_DD_GREY 12
+#define IEM_GUI_COLNR_RED 13
+#define IEM_GUI_COLNR_ORANGE 14
+#define IEM_GUI_COLNR_YELLOW 15
+#define IEM_GUI_COLNR_GREEN 16
+#define IEM_GUI_COLNR_CYAN 17
+#define IEM_GUI_COLNR_BLUE 18
+#define IEM_GUI_COLNR_MAGENTA 19
+
+#define IEM_GUI_COLNR_L_GREY 20
+#define IEM_GUI_COLNR_MD_GREY 21
+#define IEM_GUI_COLNR_BLACK 22
+#define IEM_GUI_COLNR_D_RED 23
+#define IEM_GUI_COLNR_D_ORANGE 24
+#define IEM_GUI_COLNR_D_YELLOW 25
+#define IEM_GUI_COLNR_D_GREEN 26
+#define IEM_GUI_COLNR_D_CYAN 27
+#define IEM_GUI_COLNR_D_BLUE 28
+#define IEM_GUI_COLNR_D_MAGENTA 29
+
+#define IEM_GUI_COLOR_SELECTED 255
+#define IEM_GUI_COLOR_NORMAL 0
+
+#define IEM_GUI_MAX_COLOR 30
+
+#define IEM_GUI_DEFAULTSIZE 15
+#define IEM_GUI_MINSIZE 8
+#define IEM_GUI_MAXSIZE 1000
+#define IEM_SL_DEFAULTSIZE 128
+#define IEM_SL_MINSIZE 20
+#define IEM_FONT_MINSIZE 4
+
+#define IEM_BNG_DEFAULTHOLDFLASHTIME 250
+#define IEM_BNG_DEFAULTBREAKFLASHTIME 50
+#define IEM_BNG_MINHOLDFLASHTIME 50
+#define IEM_BNG_MINBREAKFLASHTIME 10
+
+#define IEM_VU_DEFAULTSIZE 3
+#define IEM_VU_LARGESMALL 2
+#define IEM_VU_MINSIZE 2
+#define IEM_VU_MAXSIZE 25
+#define IEM_VU_STEPS 40
+
+#define IEM_VU_MINDB -99.9
+#define IEM_VU_MAXDB 12.0
+#define IEM_VU_OFFSET 100.0
+
+#define IEM_RADIO_MAX 128
+
+#define IEM_SYM_UNIQUE_SND 256
+#define IEM_SYM_UNIQUE_RCV 512
+#define IEM_SYM_UNIQUE_LAB 1024
+#define IEM_SYM_UNIQUE_ALL 1792
+#define IEM_FONT_STYLE_ALL 255
+
+#define IEM_MAX_SYM_LEN 127
+
+#define IEM_GUI_DRAW_MODE_UPDATE 0
+#define IEM_GUI_DRAW_MODE_MOVE 1
+#define IEM_GUI_DRAW_MODE_NEW 2
+#define IEM_GUI_DRAW_MODE_SELECT 3
+#define IEM_GUI_DRAW_MODE_ERASE 4
+#define IEM_GUI_DRAW_MODE_CONFIG 5
+#define IEM_GUI_DRAW_MODE_IO 6
+
+
+#define IS_A_POINTER(atom,index) ((atom+index)->a_type == A_POINTER)
+#define IS_A_FLOAT(atom,index) ((atom+index)->a_type == A_FLOAT)
+#define IS_A_SYMBOL(atom,index) ((atom+index)->a_type == A_SYMBOL)
+#define IS_A_DOLLAR(atom,index) ((atom+index)->a_type == A_DOLLAR)
+#define IS_A_DOLLSYM(atom,index) ((atom+index)->a_type == A_DOLLSYM)
+
+#define IEM_FSTYLE_FLAGS_ALL 0x007fffff
+#define IEM_INIT_ARGS_ALL 0x01ffffff
+
+#define IEM_GUI_OLD_SND_FLAG 1
+#define IEM_GUI_OLD_RCV_FLAG 2
+
+#define IEM_GUI_COLOR_EDITED 16711680
+#define IEMGUI_MAX_NUM_LEN 32
+
+typedef struct _iem_fstyle_flags
+{
+ unsigned int x_font_style:6;
+ unsigned int x_rcv_able:1;
+ unsigned int x_snd_able:1;
+ unsigned int x_lab_is_unique:1;
+ unsigned int x_rcv_is_unique:1;
+ unsigned int x_snd_is_unique:1;
+ unsigned int x_lab_arg_tail_len:6;
+ unsigned int x_lab_is_arg_num:6;
+ unsigned int x_shiftdown:1;
+ unsigned int x_selected:1;
+ unsigned int x_finemoved:1;
+ unsigned int x_put_in2out:1;
+ unsigned int x_change:1;
+ unsigned int x_thick:1;
+ unsigned int x_lin0_log1:1;
+ unsigned int x_steady:1;
+ unsigned int dummy:1;
+} t_iem_fstyle_flags;
+
+typedef struct _iem_init_symargs
+{
+ unsigned int x_loadinit:1;
+ unsigned int x_rcv_arg_tail_len:6;
+ unsigned int x_snd_arg_tail_len:6;
+ unsigned int x_rcv_is_arg_num:6;
+ unsigned int x_snd_is_arg_num:6;
+ unsigned int x_scale:1;
+ unsigned int x_flashed:1;
+ unsigned int x_locked:1;
+ unsigned int x_reverse:1; /* bugfix */
+ unsigned int dummy:3;
+} t_iem_init_symargs;
+
+typedef void (*t_iemfunptr)(void *x, t_glist *glist, int mode);
+
+typedef struct _iemgui
+{
+ t_object x_obj;
+ t_glist *x_glist;
+ t_iemfunptr x_draw;
+ int x_h;
+ int x_w;
+ int x_ldx;
+ int x_ldy;
+ char x_font[16];
+ t_iem_fstyle_flags x_fsf;
+ int x_fontsize;
+ t_iem_init_symargs x_isa;
+ int x_fcol;
+ int x_bcol;
+ int x_lcol;
+ int x_unique_num;
+ t_symbol *x_snd;
+ t_symbol *x_rcv;
+ t_symbol *x_lab;
+} t_iemgui;
+
+typedef struct _iemguidummy
+{
+ t_iemgui x_gui;
+ int x_dum1;
+ int x_dum2;
+ int x_dum3;
+} t_iemguidummy;
+
+typedef struct _bng
+{
+ t_iemgui x_gui;
+ int x_flashed;
+ int x_flashtime_break;
+ int x_flashtime_hold;
+ t_clock *x_clock_hld;
+ t_clock *x_clock_brk;
+ t_clock *x_clock_lck;
+} t_bng;
+
+typedef struct _hslider
+{
+ t_iemgui x_gui;
+ int x_pos;
+ int x_val;
+ int x_center;
+ int x_thick;
+ int x_lin0_log1;
+ int x_steady;
+ double x_min;
+ double x_max;
+ double x_k;
+} t_hslider;
+
+typedef struct _hdial
+{
+ t_iemgui x_gui;
+ int x_on;
+ int x_on_old;
+ int x_change;
+ int x_number;
+ t_atom x_at[2];
+} t_hdial;
+
+typedef struct _toggle
+{
+ t_iemgui x_gui;
+ float x_on;
+ float x_nonzero;
+} t_toggle;
+
+typedef struct _my_canvas
+{
+ t_iemgui x_gui;
+ t_atom x_at[3];
+ int x_vis_w;
+ int x_vis_h;
+} t_my_canvas;
+
+typedef struct _vslider
+{
+ t_iemgui x_gui;
+ int x_pos;
+ int x_val;
+ int x_lin0_log1;
+ int x_steady;
+ double x_min;
+ double x_max;
+ double x_k;
+} t_vslider;
+
+typedef struct _vu
+{
+ t_iemgui x_gui;
+ int x_led_size;
+ int x_peak;
+ int x_rms;
+ float x_fp;
+ float x_fr;
+ int x_scale;
+ void *x_out_rms;
+ void *x_out_peak;
+} t_vu;
+
+typedef struct _my_numbox
+{
+ t_iemgui x_gui;
+ t_clock *x_clock_reset;
+ t_clock *x_clock_wait;
+ double x_val;
+ double x_min;
+ double x_max;
+ double x_k;
+ int x_lin0_log1;
+ char x_buf[IEMGUI_MAX_NUM_LEN];
+ int x_numwidth;
+ int x_log_height;
+} t_my_numbox;
+
+typedef struct _vdial
+{
+ t_iemgui x_gui;
+ int x_on;
+ int x_on_old;
+ int x_change;
+ int x_number;
+ t_atom x_at[2];
+} t_vdial;
+
+extern int sys_noloadbang;
+extern t_symbol *iemgui_key_sym;
+extern int iemgui_color_hex[];
+extern int iemgui_vu_db2i[];
+extern int iemgui_vu_col[];
+extern char *iemgui_vu_scale_str[];
+
+EXTERN int iemgui_clip_size(int size);
+EXTERN int iemgui_clip_font(int size);
+EXTERN int iemgui_modulo_color(int col);
+EXTERN void iemgui_raute2dollar(t_symbol *s);
+EXTERN void iemgui_dollar2raute(t_symbol *s);
+EXTERN t_symbol *iemgui_unique2dollarzero(t_symbol *s, int unique_num, int and_unique_flag);
+EXTERN t_symbol *iemgui_sym2dollararg(t_symbol *s, int nth_arg, int tail_len);
+EXTERN t_symbol *iemgui_dollarzero2unique(t_symbol *s, int unique_num);
+EXTERN t_symbol *iemgui_dollararg2sym(t_symbol *s, int nth_arg, int tail_len, int pargc, t_atom *pargv);
+EXTERN int iemgui_is_dollarzero(t_symbol *s);
+EXTERN int iemgui_is_dollararg(t_symbol *s, int *tail_len);
+EXTERN void iemgui_fetch_unique(t_iemgui *iemgui);
+EXTERN void iemgui_fetch_parent_args(t_iemgui *iemgui, int *pargc, t_atom **pargv);
+EXTERN void iemgui_verify_snd_ne_rcv(t_iemgui *iemgui);
+EXTERN void iemgui_all_unique2dollarzero(t_iemgui *iemgui, t_symbol **srlsym);
+EXTERN void iemgui_all_sym2dollararg(t_iemgui *iemgui, t_symbol **srlsym);
+EXTERN void iemgui_all_dollarzero2unique(t_iemgui *iemgui, t_symbol **srlsym);
+EXTERN void iemgui_all_dollararg2sym(t_iemgui *iemgui, t_symbol **srlsym);
+EXTERN void iemgui_first_dollararg2sym(t_iemgui *iemgui, t_symbol **srlsym);
+EXTERN void iemgui_all_col2save(t_iemgui *iemgui, int *bflcol);
+EXTERN void iemgui_all_colfromload(t_iemgui *iemgui, int *bflcol);
+EXTERN int iemgui_compatible_col(int i);
+EXTERN void iemgui_all_dollar2raute(t_symbol **srlsym);
+EXTERN void iemgui_all_raute2dollar(t_symbol **srlsym);
+EXTERN void iemgui_send(void *x, t_iemgui *iemgui, t_symbol *s);
+EXTERN void iemgui_receive(void *x, t_iemgui *iemgui, t_symbol *s);
+EXTERN void iemgui_label(void *x, t_iemgui *iemgui, t_symbol *s);
+EXTERN void iemgui_label_pos(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av);
+EXTERN void iemgui_label_font(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av);
+EXTERN void iemgui_size(void *x, t_iemgui *iemgui);
+EXTERN void iemgui_delta(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av);
+EXTERN void iemgui_pos(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av);
+EXTERN void iemgui_color(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av);
+EXTERN int iemgui_list(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av);
+EXTERN void iemgui_displace(t_gobj *z, t_glist *glist, int dx, int dy);
+EXTERN void iemgui_select(t_gobj *z, t_glist *glist, int selected);
+EXTERN void iemgui_delete(t_gobj *z, t_glist *glist);
+EXTERN void iemgui_vis(t_gobj *z, t_glist *glist, int vis);
+EXTERN void iemgui_save(t_iemgui *iemgui, t_symbol **srl, int *bflcol);
+EXTERN void iemgui_properties(t_iemgui *iemgui, t_symbol **srl);
+EXTERN int iemgui_dialog(t_iemgui *iemgui, t_symbol **srl, int argc, t_atom *argv);
+
+EXTERN t_rtext *rtext_new_without_senditup(t_glist *glist, t_text *who, t_rtext *next);
+EXTERN int canvas_getdollarzero(void);
+EXTERN void canvas_getargs(int *argcp, t_atom **argvp);
+
diff --git a/pd/src/g_array.c b/pd/src/g_array.c
new file mode 100644
index 00000000..2cdb3d8e
--- /dev/null
+++ b/pd/src/g_array.c
@@ -0,0 +1,1358 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h> /* for read/write to files */
+#include "m_pd.h"
+#include "g_canvas.h"
+#include <math.h>
+
+/* see also the "plot" object in g_scalar.c which deals with graphing
+arrays which are fields in scalars. Someday we should unify the
+two, but how? */
+
+ /* aux routine to bash leading '#' to '$' for dialogs in u_main.tk
+ which can't send symbols starting with '$' (because the Pd message
+ interpreter would change them!) */
+
+static t_symbol *sharptodollar(t_symbol *s)
+{
+ if (*s->s_name == '#')
+ {
+ char buf[MAXPDSTRING];
+ strncpy(buf, s->s_name, MAXPDSTRING);
+ buf[MAXPDSTRING-1] = 0;
+ buf[0] = '$';
+ return (gensym(buf));
+ }
+ else return (s);
+}
+
+/* --------- "pure" arrays with scalars for elements. --------------- */
+
+/* Pure arrays have no a priori graphical capabilities.
+They are instantiated by "garrays" below or can be elements of other
+scalars (g_scalar.c); their graphical behavior is defined accordingly. */
+
+t_array *array_new(t_symbol *templatesym, t_gpointer *parent)
+{
+ t_array *x = (t_array *)getbytes(sizeof (*x));
+ t_template *template;
+ t_gpointer *gp;
+ template = template_findbyname(templatesym);
+ x->a_templatesym = templatesym;
+ x->a_n = 1;
+ x->a_elemsize = sizeof(t_word) * template->t_n;
+ x->a_vec = (char *)getbytes(x->a_elemsize);
+ /* note here we blithely copy a gpointer instead of "setting" a
+ new one; this gpointer isn't accounted for and needn't be since
+ we'll be deleted before the thing pointed to gets deleted anyway;
+ see array_free. */
+ x->a_gp = *parent;
+ x->a_stub = gstub_new(0, x);
+ word_init((t_word *)(x->a_vec), template, parent);
+ return (x);
+}
+
+void array_resize(t_array *x, t_template *template, int n)
+{
+ int elemsize, oldn;
+ t_gpointer *gp;
+
+ if (n < 1)
+ n = 1;
+ oldn = x->a_n;
+ elemsize = sizeof(t_word) * template->t_n;
+
+ x->a_vec = (char *)resizebytes(x->a_vec, oldn * elemsize,
+ n * elemsize);
+ x->a_n = n;
+ if (n > oldn)
+ {
+ char *cp = x->a_vec + elemsize * oldn;
+ int i = n - oldn;
+ for (; i--; cp += elemsize)
+ {
+ t_word *wp = (t_word *)cp;
+ word_init(wp, template, &x->a_gp);
+ }
+ }
+}
+
+void array_free(t_array *x)
+{
+ /* we don't unset our gpointer here since it was never "set." */
+ /* gpointer_unset(&x->a_gp); */
+ gstub_cutoff(x->a_stub);
+ freebytes(x->a_vec, x->a_elemsize * x->a_n);
+ freebytes(x, sizeof *x);
+}
+
+/* --------------------- graphical arrays (garrays) ------------------- */
+
+t_class *garray_class;
+static int gcount = 0;
+
+struct _garray
+{
+ t_gobj x_gobj;
+ t_glist *x_glist;
+ t_array x_array; /* actual array; note only 4 fields used as below */
+ t_symbol *x_name;
+ t_symbol *x_realname; /* name with "$" expanded */
+ t_float x_firstx; /* X value of first item */
+ t_float x_xinc; /* X increment */
+ char x_usedindsp; /* true if some DSP routine is using this */
+ char x_saveit; /* true if we should save this with parent */
+};
+
+ /* macros to get into the "array" structure */
+#define x_n x_array.a_n
+#define x_elemsize x_array.a_elemsize
+#define x_vec x_array.a_vec
+#define x_templatesym x_array.a_templatesym
+
+t_garray *graph_array(t_glist *gl, t_symbol *s, t_symbol *templatesym,
+ t_floatarg f, t_floatarg saveit)
+{
+ int n = f, i;
+ int zz, nwords;
+ t_garray *x;
+ t_pd *x2;
+ t_template *template;
+ char *str;
+ if (s == &s_)
+ {
+ char buf[40];
+ sprintf(buf, "array%d", ++gcount);
+ s = gensym(buf);
+ templatesym = &s_float;
+ n = 100;
+ }
+ else if (!strncmp((str = s->s_name), "array", 5)
+ && (zz = atoi(str + 5)) > gcount) gcount = zz;
+ template = template_findbyname(templatesym);
+ if (!template)
+ {
+ error("array: couldn't find template %s", templatesym->s_name);
+ return (0);
+ }
+ nwords = template->t_n;
+ for (i = 0; i < nwords; i++)
+ {
+ /* we can't have array or list elements yet because what scalar
+ can act as their "parent"??? */
+ if (template->t_vec[i].ds_type == DT_ARRAY
+ || template->t_vec[i].ds_type == DT_LIST)
+ {
+ error("array: template %s can't have sublists or arrays",
+ templatesym->s_name);
+ return (0);
+ }
+ }
+ x = (t_garray *)pd_new(garray_class);
+
+ if (n <= 0) n = 100;
+ x->x_n = n;
+ x->x_elemsize = nwords * sizeof(t_word);
+ x->x_vec = getbytes(x->x_n * x->x_elemsize);
+ memset(x->x_vec, 0, x->x_n * x->x_elemsize);
+ /* LATER should check that malloc */
+ x->x_name = s;
+ x->x_realname = canvas_realizedollar(gl, s);
+ pd_bind(&x->x_gobj.g_pd, x->x_realname);
+ x->x_templatesym = templatesym;
+ x->x_firstx = 0;
+ x->x_xinc = 1; /* LATER make methods to set this... */
+ glist_add(gl, &x->x_gobj);
+ x->x_glist = gl;
+ x->x_usedindsp = 0;
+ x->x_saveit = (saveit != 0);
+ if (x2 = pd_findbyclass(gensym("#A"), garray_class))
+ pd_unbind(x2, gensym("#A"));
+
+ pd_bind(&x->x_gobj.g_pd, gensym("#A"));
+
+ return (x);
+}
+
+ /* called from array menu item to create a new one */
+void canvas_menuarray(t_glist *canvas)
+{
+ t_glist *x = (t_glist *)canvas;
+ char cmdbuf[200];
+ sprintf(cmdbuf, "pdtk_array_dialog %%s array%d 100 1 1\n",
+ ++gcount);
+ gfxstub_new(&x->gl_pd, x, cmdbuf);
+}
+
+ /* called from graph_dialog to set properties */
+void garray_properties(t_garray *x)
+{
+ char cmdbuf[200];
+ gfxstub_deleteforkey(x);
+ /* create dialog window. LATER fix this to escape '$'
+ properly; right now we just detect a leading '$' and escape
+ it. There should be a systematic way of doing this. */
+ if (x->x_name->s_name[0] == '$')
+ sprintf(cmdbuf, "pdtk_array_dialog %%s \\%s %d %d 0\n",
+ x->x_name->s_name, x->x_n, x->x_saveit);
+ else sprintf(cmdbuf, "pdtk_array_dialog %%s %s %d %d 0\n",
+ x->x_name->s_name, x->x_n, x->x_saveit);
+ gfxstub_new(&x->x_gobj.g_pd, x, cmdbuf);
+}
+
+ /* this is called back from the dialog window to create a garray.
+ The otherflag requests that we find an existing graph to put it in. */
+void glist_arraydialog(t_glist *parent, t_symbol *name, t_floatarg size,
+ t_floatarg saveit, t_floatarg otherflag)
+{
+ t_glist *gl;
+ t_garray *a;
+ if (size < 1)
+ size = 1;
+ if (otherflag == 0 || (!(gl = glist_findgraph(parent))))
+ gl = glist_addglist(parent, &s_, 0, 1,
+ (size > 1 ? size-1 : size), -1, 0, 0, 0, 0);
+ a = graph_array(gl, sharptodollar(name), &s_float, size, saveit);
+}
+
+ /* this is called from the properties dialog window for an existing array */
+void garray_arraydialog(t_garray *x, t_symbol *name, t_floatarg fsize,
+ t_floatarg saveit, t_floatarg deleteit)
+{
+ if (deleteit != 0)
+ {
+ glist_delete(x->x_glist, &x->x_gobj);
+ }
+ else
+ {
+ int size;
+ t_symbol *argname = sharptodollar(name);
+ if (argname != x->x_name)
+ {
+ x->x_name = argname;
+ pd_unbind(&x->x_gobj.g_pd, x->x_realname);
+ x->x_realname = canvas_realizedollar(x->x_glist, argname);
+ pd_bind(&x->x_gobj.g_pd, x->x_realname);
+ }
+ size = fsize;
+ if (size < 1)
+ size = 1;
+ if (size != x->x_n)
+ garray_resize(x, size);
+ garray_setsaveit(x, (saveit != 0));
+ garray_redraw(x);
+ }
+}
+
+static void garray_free(t_garray *x)
+{
+ t_pd *x2;
+ gfxstub_deleteforkey(x);
+ pd_unbind(&x->x_gobj.g_pd, x->x_realname);
+ /* LATER find a way to get #A unbound earlier (at end of load?) */
+ while (x2 = pd_findbyclass(gensym("#A"), garray_class))
+ pd_unbind(x2, gensym("#A"));
+ freebytes(x->x_vec, x->x_n * x->x_elemsize);
+}
+
+/* ------------- code used by both array and plot widget functions ---- */
+
+ /* routine to get screen coordinates of a point in an array */
+void array_getcoordinate(t_glist *glist,
+ char *elem, int xonset, int yonset, int wonset, int indx,
+ float basex, float basey, float xinc,
+ float *xp, float *yp, float *wp)
+{
+ float xval, yval, ypix, wpix;
+ if (xonset >= 0)
+ xval = *(float *)(elem + xonset);
+ else xval = indx * xinc;
+ if (yonset >= 0)
+ yval = *(float *)(elem + yonset);
+ else yval = 0;
+ ypix = glist_ytopixels(glist, basey + yval);
+ if (wonset >= 0)
+ {
+ /* found "w" field which controls linewidth. */
+ float wval = *(float *)(elem + wonset);
+ wpix = glist_ytopixels(glist, basey + yval + wval) - ypix;
+ if (wpix < 0)
+ wpix = -wpix;
+ }
+ else wpix = 1;
+ *xp = glist_xtopixels(glist, basex + xval);
+ *yp = ypix;
+ *wp = wpix;
+}
+
+static float array_motion_xcumulative;
+static float array_motion_ycumulative;
+static t_symbol *array_motion_xfield;
+static t_symbol *array_motion_yfield;
+static t_glist *array_motion_glist;
+static t_gobj *array_motion_gobj;
+static t_word *array_motion_wp;
+static t_template *array_motion_template;
+static int array_motion_npoints;
+static int array_motion_elemsize;
+static int array_motion_altkey;
+static float array_motion_initx;
+static float array_motion_xperpix;
+static float array_motion_yperpix;
+static int array_motion_lastx;
+static int array_motion_fatten;
+
+ /* LATER protect against the template changing or the scalar disappearing
+ probably by attaching a gpointer here ... */
+
+static void array_motion(void *z, t_floatarg dx, t_floatarg dy)
+{
+ array_motion_xcumulative += dx * array_motion_xperpix;
+ array_motion_ycumulative += dy * array_motion_yperpix;
+ if (*array_motion_xfield->s_name)
+ {
+ /* it's an x, y plot; can drag many points at once */
+ int i;
+ char *charword = (char *)array_motion_wp;
+ for (i = 0; i < array_motion_npoints; i++)
+ {
+ t_word *thisword = (t_word *)(charword + i * array_motion_elemsize);
+ if (*array_motion_xfield->s_name)
+ {
+ float xwas = template_getfloat(array_motion_template,
+ array_motion_xfield, thisword, 1);
+ template_setfloat(array_motion_template,
+ array_motion_xfield, thisword, xwas + dx, 1);
+ }
+ if (*array_motion_yfield->s_name)
+ {
+ float ywas = template_getfloat(array_motion_template,
+ array_motion_yfield, thisword, 1);
+ if (array_motion_fatten)
+ {
+ if (i == 0)
+ {
+ float newy = ywas + dy;
+ if (newy < 0)
+ newy = 0;
+ template_setfloat(array_motion_template,
+ array_motion_yfield, thisword, newy, 1);
+ }
+ }
+ else
+ {
+ template_setfloat(array_motion_template,
+ array_motion_yfield, thisword, ywas + dy, 1);
+ }
+ }
+ }
+ }
+ else
+ {
+ /* a y-only plot. */
+ int thisx = array_motion_initx +
+ array_motion_xcumulative, x2;
+ int increment, i, nchange;
+ char *charword = (char *)array_motion_wp;
+ float newy = array_motion_ycumulative,
+ oldy = template_getfloat(
+ array_motion_template, array_motion_yfield,
+ (t_word *)(charword + array_motion_elemsize * array_motion_lastx), 1);
+ float ydiff = newy - oldy;
+ if (thisx < 0) thisx = 0;
+ else if (thisx >= array_motion_npoints)
+ thisx = array_motion_npoints - 1;
+ increment = (thisx > array_motion_lastx ? -1 : 1);
+ nchange = 1 + increment * (array_motion_lastx - thisx);
+
+ for (i = 0, x2 = thisx; i < nchange; i++, x2 += increment)
+ {
+ template_setfloat(array_motion_template,
+ array_motion_yfield,
+ (t_word *)(charword + array_motion_elemsize * x2),
+ newy, 1);
+ if (nchange > 1)
+ newy -= ydiff * (1./(nchange - 1));
+ }
+ array_motion_lastx = thisx;
+ }
+ glist_redrawitem(array_motion_glist, array_motion_gobj);
+}
+
+int array_doclick(t_array *array, t_glist *glist, t_gobj *gobj,
+ t_symbol *elemtemplatesym,
+ float linewidth, float xloc, float xinc, float yloc,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ t_canvas *elemtemplatecanvas;
+ t_template *elemtemplate;
+ int elemsize, yonset, wonset, xonset, i;
+
+ if (!array_getfields(elemtemplatesym, &elemtemplatecanvas,
+ &elemtemplate, &elemsize, &xonset, &yonset, &wonset))
+ {
+ float best = 100;
+ int incr;
+ /* if it has more than 2000 points, just check 300 of them. */
+ if (array->a_n < 2000)
+ incr = 1;
+ else incr = array->a_n / 300;
+ for (i = 0; i < array->a_n; i += incr)
+ {
+ float pxpix, pypix, pwpix, dx, dy;
+ array_getcoordinate(glist, (char *)(array->a_vec) + i * elemsize,
+ xonset, yonset, wonset, i, xloc, yloc, xinc,
+ &pxpix, &pypix, &pwpix);
+ if (pwpix < 4)
+ pwpix = 4;
+ dx = pxpix - xpix;
+ if (dx < 0) dx = -dx;
+ if (dx > 8)
+ continue;
+ dy = pypix - ypix;
+ if (dy < 0) dy = -dy;
+ if (dx + dy < best)
+ best = dx + dy;
+ if (wonset >= 0)
+ {
+ dy = (pypix + pwpix) - ypix;
+ if (dy < 0) dy = -dy;
+ if (dx + dy < best)
+ best = dx + dy;
+ dy = (pypix - pwpix) - ypix;
+ if (dy < 0) dy = -dy;
+ if (dx + dy < best)
+ best = dx + dy;
+ }
+ }
+ if (best > 8)
+ return (0);
+ best += 0.001; /* add truncation error margin */
+ for (i = 0; i < array->a_n; i += incr)
+ {
+ float pxpix, pypix, pwpix, dx, dy, dy2, dy3;
+ array_getcoordinate(glist, (char *)(array->a_vec) + i * elemsize,
+ xonset, yonset, wonset, i, xloc, yloc, xinc,
+ &pxpix, &pypix, &pwpix);
+ if (pwpix < 4)
+ pwpix = 4;
+ dx = pxpix - xpix;
+ if (dx < 0) dx = -dx;
+ dy = pypix - ypix;
+ if (dy < 0) dy = -dy;
+ if (wonset >= 0)
+ {
+ dy2 = (pypix + pwpix) - ypix;
+ if (dy2 < 0) dy2 = -dy2;
+ dy3 = (pypix - pwpix) - ypix;
+ if (dy3 < 0) dy3 = -dy3;
+ if (yonset <= 0)
+ dy = 100;
+ }
+ else dy2 = dy3 = 100;
+ if (dx + dy <= best || dx + dy2 <= best || dx + dy3 <= best)
+ {
+ if (dy < dy2 && dy < dy3)
+ array_motion_fatten = 0;
+ else if (dy2 < dy3)
+ array_motion_fatten = -1;
+ else array_motion_fatten = 1;
+ if (doit)
+ {
+ char *elem = (char *)array->a_vec;
+ array_motion_elemsize = elemsize;
+ array_motion_glist = glist;
+ array_motion_gobj = gobj;
+ array_motion_template = elemtemplate;
+ array_motion_xperpix = glist_dpixtodx(glist, 1);
+ array_motion_yperpix = glist_dpixtody(glist, 1);
+ if (alt && xpix < pxpix) /* delete a point */
+ {
+ if (array->a_n <= 1)
+ return (0);
+ memmove((char *)(array->a_vec) + elemsize * i,
+ (char *)(array->a_vec) + elemsize * (i+1),
+ (array->a_n - 1 - i) * elemsize);
+ array_resize(array, elemtemplate, array->a_n - 1);
+ glist_redrawitem(array_motion_glist, array_motion_gobj);
+ return (0);
+ }
+ else if (alt)
+ {
+ /* add a point (after the clicked-on one) */
+ array_resize(array, elemtemplate, array->a_n + 1);
+ elem = (char *)array->a_vec;
+ memmove(elem + elemsize * (i+1),
+ elem + elemsize * i,
+ (array->a_n - i) * elemsize);
+ i++;
+ (array->a_n)++;
+ }
+ if (xonset >= 0)
+ {
+ array_motion_xfield = gensym("x");
+ array_motion_xcumulative =
+ *(float *)((elem + elemsize * i) + xonset);
+ array_motion_wp = (t_word *)(elem + i * elemsize);
+ array_motion_npoints = array->a_n - i;
+ }
+ else
+ {
+ array_motion_xfield = &s_;
+ array_motion_xcumulative = 0;
+ array_motion_wp = (t_word *)elem;
+ array_motion_npoints = array->a_n;
+
+ array_motion_initx = i;
+ array_motion_lastx = i;
+ array_motion_xperpix *= (xinc == 0 ? 1 : 1./xinc);
+ }
+ if (array_motion_fatten)
+ {
+ array_motion_yfield = gensym("w");
+ array_motion_ycumulative =
+ *(float *)((elem + elemsize * i) + wonset);
+ array_motion_xperpix *= array_motion_fatten;
+ }
+ else if (yonset >= 0)
+ {
+ array_motion_yfield = gensym("y");
+ array_motion_ycumulative =
+ *(float *)((elem + elemsize * i) + yonset);
+ }
+ else
+ {
+ array_motion_yfield = &s_;
+ array_motion_ycumulative = 0;
+ }
+ glist_grab(glist, 0, array_motion, 0, xpix, ypix);
+ }
+ if (alt)
+ {
+ if (xpix < pxpix)
+ return (CURSOR_EDITMODE_DISCONNECT);
+ else return (CURSOR_RUNMODE_ADDPOINT);
+ }
+ else return (array_motion_fatten ?
+ CURSOR_RUNMODE_THICKEN : CURSOR_RUNMODE_CLICKME);
+ }
+ }
+ }
+ return (0);
+}
+
+/* -------------------- widget behavior for garray ------------ */
+
+static void garray_getrect(t_gobj *z, t_glist *glist,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_garray *x = (t_garray *)z;
+ float x1 = 0x7fffffff, y1 = 0x7fffffff, x2 = -0x7fffffff, y2 = -0x7fffffff;
+ t_canvas *elemtemplatecanvas;
+ t_template *elemtemplate;
+ int elemsize, yonset, wonset, xonset, i;
+
+ if (!array_getfields(x->x_templatesym, &elemtemplatecanvas,
+ &elemtemplate, &elemsize, &xonset, &yonset, &wonset))
+ {
+ int incr;
+ /* if it has more than 2000 points, just check 300 of them. */
+ if (x->x_array.a_n < 2000)
+ incr = 1;
+ else incr = x->x_array.a_n / 300;
+ for (i = 0; i < x->x_array.a_n; i += incr)
+ {
+ float pxpix, pypix, pwpix, dx, dy;
+ array_getcoordinate(glist, (char *)(x->x_array.a_vec) +
+ i * elemsize,
+ xonset, yonset, wonset, i, 0, 0, 1,
+ &pxpix, &pypix, &pwpix);
+ if (pwpix < 2)
+ pwpix = 2;
+ if (pxpix < x1)
+ x1 = pxpix;
+ if (pxpix > x2)
+ x2 = pxpix;
+ if (pypix - pwpix < y1)
+ y1 = pypix - pwpix;
+ if (pypix + pwpix > y2)
+ y2 = pypix + pwpix;
+ }
+ }
+ *xp1 = x1;
+ *yp1 = y1;
+ *xp2 = x2;
+ *yp2 = y2;
+}
+
+static void garray_displace(t_gobj *z, t_glist *glist, int dx, int dy)
+{
+ /* refuse */
+}
+
+static void garray_select(t_gobj *z, t_glist *glist, int state)
+{
+ t_garray *x = (t_garray *)z;
+ /* fill in later */
+}
+
+static void garray_activate(t_gobj *z, t_glist *glist, int state)
+{
+}
+
+static void garray_delete(t_gobj *z, t_glist *glist)
+{
+ /* nothing to do */
+}
+
+static void garray_vis(t_gobj *z, t_glist *glist, int vis)
+{
+ t_garray *x = (t_garray *)z;
+ if (vis)
+ {
+ int i, xonset, yonset, type;
+ t_symbol *arraytype;
+ t_template *template = template_findbyname(x->x_templatesym);
+ if (!template)
+ return;
+ if (!template_find_field(template, gensym("y"), &yonset, &type,
+ &arraytype) || type != DT_FLOAT)
+ {
+ error("%s: needs floating-point 'y' field",
+ x->x_templatesym->s_name);
+ sys_vgui(".x%x.c create text 50 50 -text foo\
+ -tags .x%x.a%x\n",
+ glist_getcanvas(glist), glist_getcanvas(glist), x);
+ }
+ else if (!template_find_field(template, gensym("x"), &xonset, &type,
+ &arraytype) || type != DT_FLOAT)
+ {
+ float firsty, xcum = x->x_firstx;
+ int lastpixel = -1, ndrawn = 0;
+ float yval = 0, xpix;
+ int ixpix = 0;
+ sys_vgui(".x%x.c create line \\\n", glist_getcanvas(glist));
+ for (i = 0; i < x->x_n; i++)
+ {
+ yval = *(float *)(x->x_vec +
+ template->t_n * i * sizeof (t_word) + yonset);
+ xpix = glist_xtopixels(glist, xcum);
+ ixpix = xpix + 0.5;
+ if (ixpix != lastpixel)
+ {
+ sys_vgui("%d %f \\\n", ixpix,
+ glist_ytopixels(glist, yval));
+ ndrawn++;
+ }
+ lastpixel = ixpix;
+ if (ndrawn >= 1000) break;
+ xcum += x->x_xinc;
+ }
+ /* TK will complain if there aren't at least 2 points... */
+ if (ndrawn == 0) sys_vgui("0 0 0 0 \\\n");
+ else if (ndrawn == 1) sys_vgui("%d %f \\\n", ixpix,
+ glist_ytopixels(glist, yval));
+ sys_vgui("-tags .x%x.a%x\n", glist_getcanvas(glist), x);
+ firsty = *(float *)(x->x_vec + yonset);
+ sys_vgui(".x%x.c create text %f %f -text {%s} -anchor e\
+ -font -*-courier-bold--normal--%d-* -tags .x%x.a%x\n",
+ glist_getcanvas(glist),
+ glist_xtopixels(glist, x->x_firstx) - 5.,
+ glist_ytopixels(glist, firsty),
+ x->x_name->s_name, glist_getfont(glist),
+ glist_getcanvas(glist), x);
+ }
+ else
+ {
+ post("x, y arrays not yet supported");
+ }
+ }
+ else
+ {
+ sys_vgui(".x%x.c delete .x%x.a%x\n",
+ glist_getcanvas(glist), glist_getcanvas(glist), x);
+ }
+}
+
+static int garray_click(t_gobj *z, struct _glist *glist,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ t_garray *x = (t_garray *)z;
+ return (array_doclick(&x->x_array, glist, z, x->x_templatesym, 1, 0, 1, 0,
+ xpix, ypix, shift, alt, dbl, doit));
+}
+
+#define ARRAYWRITECHUNKSIZE 1000
+
+static void garray_save(t_gobj *z, t_binbuf *b)
+{
+ t_garray *x = (t_garray *)z;
+ binbuf_addv(b, "sssisi;", gensym("#X"), gensym("array"),
+ x->x_name, x->x_n, x->x_templatesym, x->x_saveit);
+ if (x->x_saveit)
+ {
+ int n = x->x_n, n2 = 0;
+ if (x->x_templatesym != &s_float)
+ {
+ pd_error(x, "sorry, you can only save 'float' arrays now");
+ return;
+ }
+ if (n > 200000)
+ post("warning: I'm saving an array with %d points!\n", n);
+ while (n2 < n)
+ {
+ int chunk = n - n2, i;
+ if (chunk > ARRAYWRITECHUNKSIZE)
+ chunk = ARRAYWRITECHUNKSIZE;
+ binbuf_addv(b, "si", gensym("#A"), n2);
+ for (i = 0; i < chunk; i++)
+ binbuf_addv(b, "f", ((float *)(x->x_vec))[n2+i]);
+ binbuf_addv(b, ";");
+ n2 += chunk;
+ }
+ }
+}
+
+t_widgetbehavior garray_widgetbehavior =
+{
+ garray_getrect,
+ garray_displace,
+ garray_select,
+ garray_activate,
+ garray_delete,
+ garray_vis,
+ garray_click,
+ garray_save,
+ 0
+};
+
+/* ----------------------- public functions -------------------- */
+
+void garray_usedindsp(t_garray *x)
+{
+ x->x_usedindsp = 1;
+}
+
+void garray_redraw(t_garray *x)
+{
+ if (glist_isvisible(x->x_glist))
+ {
+ garray_vis(&x->x_gobj, x->x_glist, 0);
+ garray_vis(&x->x_gobj, x->x_glist, 1);
+ }
+}
+
+ /* This functiopn gets the template of an array; if we can't figure
+ out what template an array's elements belong to we're in grave trouble
+ when it's time to free or resize it. */
+t_template *garray_template(t_garray *x)
+{
+ t_template *template = template_findbyname(x->x_templatesym);
+ if (!template)
+ bug("garray_template");
+ return (template);
+}
+
+int garray_npoints(t_garray *x) /* get the length */
+{
+ return (x->x_n);
+}
+
+char *garray_vec(t_garray *x) /* get the contents */
+{
+ return ((char *)(x->x_vec));
+}
+
+ /* routine that checks if we're just an array of floats and if
+ so returns the goods */
+
+int garray_getfloatarray(t_garray *x, int *size, t_float **vec)
+{
+ t_template *template = garray_template(x);
+ int yonset, type;
+ t_symbol *arraytype;
+ if (!template_find_field(template, gensym("y"), &yonset,
+ &type, &arraytype) || type != DT_FLOAT)
+ error("%s: needs floating-point 'y' field",
+ x->x_templatesym->s_name);
+ else if (template->t_n != 1)
+ error("%s: has more than one field", x->x_templatesym->s_name);
+ else
+ {
+ *size = garray_npoints(x);
+ *vec = (float *)garray_vec(x);
+ return (1);
+ }
+ return (0);
+}
+
+ /* get any floating-point field of any element of an array */
+float garray_get(t_garray *x, t_symbol *s, t_int indx)
+{
+ t_template *template = garray_template(x);
+ int yonset, type;
+ t_symbol *arraytype;
+ if (!template_find_field(template, gensym("y"), &yonset,
+ &type, &arraytype) || type != DT_FLOAT)
+ {
+ error("%s: needs floating-point '%s' field", x->x_templatesym->s_name,
+ s->s_name);
+ return (0);
+ }
+ if (indx < 0) indx = 0;
+ else if (indx >= x->x_n) indx = x->x_n - 1;
+ return (*(float *)((x->x_vec + sizeof(t_word) * indx) + yonset));
+}
+
+ /* set the "saveit" flag */
+void garray_setsaveit(t_garray *x, int saveit)
+{
+ if (x->x_saveit && !saveit)
+ post("warning: array %s: clearing save-in-patch flag",
+ x->x_name->s_name);
+ x->x_saveit = saveit;
+}
+
+/*------------------- Pd messages ------------------------ */
+static void garray_const(t_garray *x, t_floatarg g)
+{
+ t_template *template = garray_template(x);
+ int yonset, type, i;
+ t_symbol *arraytype;
+ if (!template_find_field(template, gensym("y"), &yonset,
+ &type, &arraytype) || type != DT_FLOAT)
+ error("%s: needs floating-point 'y' field",
+ x->x_templatesym->s_name);
+ else for (i = 0; i < x->x_n; i++)
+ *(float *)(((char *)x->x_vec + sizeof(t_word) * i) + yonset) = g;
+ garray_redraw(x);
+}
+
+ /* sum of Fourier components; called from routines below */
+static void garray_dofo(t_garray *x, int npoints, float dcval,
+ int nsin, t_float *vsin, int sineflag)
+{
+ t_template *template = garray_template(x);
+ int yonset, type, i, j;
+ t_symbol *arraytype;
+ double phase, phaseincr, fj;
+ if (npoints == 0)
+ npoints = 512; /* dunno what a good default would be... */
+ if (npoints != (1 << ilog2(npoints)))
+ post("%s: rounnding to %d points", x->x_templatesym->s_name,
+ (npoints = (1<<ilog2(npoints))));
+ garray_resize(x, npoints + 3);
+ phaseincr = 2. * 3.14159 / npoints;
+ if (!template_find_field(template, gensym("y"), &yonset,
+ &type, &arraytype) || type != DT_FLOAT)
+ {
+ error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
+ return;
+ }
+ for (i = 0, phase = -phaseincr; i < x->x_n; i++, phase += phaseincr )
+ {
+ double sum = dcval;
+ if (sineflag)
+ for (j = 0, fj = phase; j < nsin; j++, fj += phase)
+ sum += vsin[j] * sin(fj);
+ else
+ for (j = 0, fj = 0; j < nsin; j++, fj += phase)
+ sum += vsin[j] * cos(fj);
+ *(float *)((x->x_vec + sizeof(t_word) * i) + yonset) = sum;
+ }
+ garray_redraw(x);
+}
+
+static void garray_sinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_template *template = garray_template(x);
+
+ t_float *svec = (t_float *)t_getbytes(sizeof(t_float) * argc);
+ int npoints, i;
+ if (argc < 2)
+ {
+ error("sinesum: %s: need number of points and partial strengths",
+ x->x_templatesym->s_name);
+ return;
+ }
+
+ npoints = atom_getfloatarg(0, argc, argv);
+ argv++, argc--;
+
+ svec = (t_float *)t_getbytes(sizeof(t_float) * argc);
+ if (!svec) return;
+
+ for (i = 0; i < argc; i++)
+ svec[i] = atom_getfloatarg(i, argc, argv);
+ garray_dofo(x, npoints, 0, argc, svec, 1);
+ t_freebytes(svec, sizeof(t_float) * argc);
+}
+
+static void garray_cosinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_template *template = garray_template(x);
+
+ t_float *svec = (t_float *)t_getbytes(sizeof(t_float) * argc);
+ int npoints, i;
+ if (argc < 2)
+ {
+ error("sinesum: %s: need number of points and partial strengths",
+ x->x_templatesym->s_name);
+ return;
+ }
+
+ npoints = atom_getfloatarg(0, argc, argv);
+ argv++, argc--;
+
+ svec = (t_float *)t_getbytes(sizeof(t_float) * argc);
+ if (!svec) return;
+
+ for (i = 0; i < argc; i++)
+ svec[i] = atom_getfloatarg(i, argc, argv);
+ garray_dofo(x, npoints, 0, argc, svec, 0);
+ t_freebytes(svec, sizeof(t_float) * argc);
+}
+
+static void garray_normalize(t_garray *x, t_float f)
+{
+ t_template *template = garray_template(x);
+ int yonset, type, npoints, i;
+ double maxv, renormer;
+ t_symbol *arraytype;
+
+ if (f <= 0)
+ f = 1;
+
+ if (!template_find_field(template, gensym("y"), &yonset,
+ &type, &arraytype) || type != DT_FLOAT)
+ {
+ error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
+ return;
+ }
+ for (i = 0, maxv = 0; i < x->x_n; i++)
+ {
+ double v = *(float *)((x->x_vec + sizeof(t_word) * i) + yonset);
+ if (v > maxv)
+ maxv = v;
+ if (-v > maxv)
+ maxv = -v;
+ }
+ if (maxv >= 0)
+ {
+ renormer = f / maxv;
+ for (i = 0; i < x->x_n; i++)
+ {
+ *(float *)((x->x_vec + sizeof(t_word) * i) + yonset)
+ *= renormer;
+ }
+ }
+ garray_redraw(x);
+}
+
+ /* list -- the first value is an index; subsequent values are put in
+ the "y" slot of the array. This generalizes Max's "table", sort of. */
+static void garray_list(t_garray *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_template *template = garray_template(x);
+ int yonset, type, i;
+ t_symbol *arraytype;
+ if (!template_find_field(template, gensym("y"), &yonset,
+ &type, &arraytype) || type != DT_FLOAT)
+ error("%s: needs floating-point 'y' field",
+ x->x_templatesym->s_name);
+ else if (argc < 2) return;
+ else
+ {
+ int firstindex = atom_getfloat(argv);
+ argc--;
+ argv++;
+ /* drop negative x values */
+ if (firstindex < 0)
+ {
+ argc += firstindex;
+ argv -= firstindex;
+ firstindex = 0;
+ if (argc <= 0) return;
+ }
+ if (argc + firstindex > x->x_n)
+ {
+ argc = x->x_n - firstindex;
+ if (argc <= 0) return;
+ }
+ for (i = 0; i < argc; i++)
+ *(float *)((x->x_vec + sizeof(t_word) * (i + firstindex)) + yonset) =
+ atom_getfloat(argv + i);
+ }
+ garray_redraw(x);
+}
+
+ /* forward a "bounds" message to the owning graph */
+static void garray_bounds(t_garray *x, t_floatarg x1, t_floatarg y1,
+ t_floatarg x2, t_floatarg y2)
+{
+ vmess(&x->x_glist->gl_pd, gensym("bounds"), "ffff", x1, y1, x2, y2);
+}
+
+ /* same for "xticks", etc */
+static void garray_xticks(t_garray *x,
+ t_floatarg point, t_floatarg inc, t_floatarg f)
+{
+ vmess(&x->x_glist->gl_pd, gensym("xticks"), "fff", point, inc, f);
+}
+
+static void garray_yticks(t_garray *x,
+ t_floatarg point, t_floatarg inc, t_floatarg f)
+{
+ vmess(&x->x_glist->gl_pd, gensym("yticks"), "fff", point, inc, f);
+}
+
+static void garray_xlabel(t_garray *x, t_symbol *s, int argc, t_atom *argv)
+{
+ typedmess(&x->x_glist->gl_pd, s, argc, argv);
+}
+
+static void garray_ylabel(t_garray *x, t_symbol *s, int argc, t_atom *argv)
+{
+ typedmess(&x->x_glist->gl_pd, s, argc, argv);
+}
+ /* change the name of a garray. */
+static void garray_rename(t_garray *x, t_symbol *s)
+{
+ pd_unbind(&x->x_gobj.g_pd, x->x_realname);
+ pd_bind(&x->x_gobj.g_pd, x->x_realname = x->x_name = s);
+ garray_redraw(x);
+}
+
+static void garray_read(t_garray *x, t_symbol *filename)
+{
+ int nelem = x->x_n, filedesc;
+ FILE *fd;
+ char buf[MAXPDSTRING], *bufptr;
+ t_template *template = garray_template(x);
+ int yonset, type, i;
+ t_symbol *arraytype;
+ if (!template_find_field(template, gensym("y"), &yonset,
+ &type, &arraytype) || type != DT_FLOAT)
+ {
+ error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
+ return;
+ }
+ if ((filedesc = open_via_path(
+ canvas_getdir(glist_getcanvas(x->x_glist))->s_name,
+ filename->s_name, "", buf, &bufptr, MAXPDSTRING, 0)) < 0
+ || !(fd = fdopen(filedesc, "r")))
+ {
+ error("%s: can't open", filename->s_name);
+ return;
+ }
+ for (i = 0; i < nelem; i++)
+ {
+ if (!fscanf(fd, "%f", (float *)((x->x_vec + sizeof(t_word) * i) +
+ yonset)))
+ {
+ post("%s: read %d elements into table of size %d",
+ filename->s_name, i, nelem);
+ break;
+ }
+ }
+ while (i < nelem)
+ *(float *)((x->x_vec + sizeof(t_word) * i) + yonset) = 0, i++;
+ fclose(fd);
+ garray_redraw(x);
+}
+
+ /* this should be renamed and moved... */
+int garray_ambigendian(void)
+{
+ unsigned short s = 1;
+ unsigned char c = *(char *)(&s);
+ return (c==0);
+}
+
+#define BINREADMODE "rb"
+#define BINWRITEMODE "wb"
+
+static void garray_read16(t_garray *x, t_symbol *filename,
+ t_symbol *endian, t_floatarg fskip)
+{
+ int skip = fskip, filedesc;
+ int i, nelem;
+ float *vec;
+ FILE *fd;
+ char buf[MAXPDSTRING], *bufptr;
+ short s;
+ int cpubig = garray_ambigendian(), swap = 0;
+ char c = endian->s_name[0];
+ if (c == 'b')
+ {
+ if (!cpubig) swap = 1;
+ }
+ else if (c == 'l')
+ {
+ if (cpubig) swap = 1;
+ }
+ else if (c)
+ {
+ error("array_read16: endianness is 'l' (low byte first ala INTEL)");
+ post("... or 'b' (high byte first ala MIPS,DEC,PPC)");
+ }
+ if (!garray_getfloatarray(x, &nelem, &vec))
+ {
+ error("%s: not a float array", x->x_templatesym->s_name);
+ return;
+ }
+ if ((filedesc = open_via_path(
+ canvas_getdir(glist_getcanvas(x->x_glist))->s_name,
+ filename->s_name, "", buf, &bufptr, MAXPDSTRING, 1)) < 0
+ || !(fd = fdopen(filedesc, BINREADMODE)))
+ {
+ error("%s: can't open", filename->s_name);
+ return;
+ }
+ if (skip)
+ {
+ long pos = fseek(fd, (long)skip, SEEK_SET);
+ if (pos < 0)
+ {
+ error("%s: can't seek to byte %d", buf, skip);
+ fclose(fd);
+ return;
+ }
+ }
+
+ for (i = 0; i < nelem; i++)
+ {
+ if (fread(&s, sizeof(s), 1, fd) < 1)
+ {
+ post("%s: read %d elements into table of size %d",
+ filename->s_name, i, nelem);
+ break;
+ }
+ if (swap) s = ((s & 0xff) << 8) | ((s & 0xff00) >> 8);
+ vec[i] = s * (1./32768.);
+ }
+ while (i < nelem) vec[i++] = 0;
+ fclose(fd);
+ garray_redraw(x);
+}
+
+static void garray_write(t_garray *x, t_symbol *filename)
+{
+ FILE *fd;
+ char buf[MAXPDSTRING];
+ t_template *template = garray_template(x);
+ int yonset, type, i;
+ t_symbol *arraytype;
+ if (!template_find_field(template, gensym("y"), &yonset,
+ &type, &arraytype) || type != DT_FLOAT)
+ {
+ error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
+ return;
+ }
+ canvas_makefilename(glist_getcanvas(x->x_glist), filename->s_name,
+ buf, MAXPDSTRING);
+ sys_bashfilename(buf, buf);
+ if (!(fd = fopen(buf, "w")))
+ {
+ error("%s: can't create", buf);
+ return;
+ }
+ for (i = 0; i < x->x_n; i++)
+ {
+ if (fprintf(fd, "%g\n",
+ *(float *)((x->x_vec + sizeof(t_word) * i) + yonset)) < 1)
+ {
+ post("%s: write error", filename->s_name);
+ break;
+ }
+ }
+ fclose(fd);
+}
+
+static unsigned char waveheader[] = {
+0x52, 0x49, 0x46, 0x46,
+0x00, 0x00, 0x00, 0x00,
+0x57, 0x41, 0x56, 0x45,
+0x66, 0x6d, 0x74, 0x20,
+
+0x10, 0x00, 0x00, 0x00,
+0x01, 0x00, 0x01, 0x00,
+0x44, 0xac, 0x00, 0x00,
+0x88, 0x58, 0x01, 0x00,
+
+0x02, 0x00, 0x10, 0x00,
+0x64, 0x61, 0x74, 0x61,
+0x00, 0x00, 0x00, 0x00,
+};
+
+ /* wave format only so far */
+static void garray_write16(t_garray *x, t_symbol *filename, t_symbol *format)
+{
+ t_template *template = garray_template(x);
+ int yonset, type, i;
+ t_symbol *arraytype;
+ FILE *fd;
+ int aiff = (format == gensym("aiff"));
+ char filenamebuf[MAXPDSTRING], buf2[MAXPDSTRING];
+ int swap = garray_ambigendian(); /* wave is only little endian */
+ int intbuf;
+ strncpy(filenamebuf, filename->s_name, MAXPDSTRING-10);
+ filenamebuf[MAXPDSTRING-10] = 0;
+ if (sizeof(int) != 4) post("write16: only works on 32-bit machines");
+ if (aiff)
+ {
+ if (strcmp(filenamebuf + strlen(filenamebuf)-5, ".aiff"))
+ strcat(filenamebuf, ".aiff");
+ }
+ else
+ {
+ if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".wav"))
+ strcat(filenamebuf, ".wav");
+ }
+ if (!template_find_field(template, gensym("y"), &yonset,
+ &type, &arraytype) || type != DT_FLOAT)
+ {
+ error("%s: needs floating-point 'y' field", x->x_templatesym->s_name);
+ return;
+ }
+ canvas_makefilename(glist_getcanvas(x->x_glist), filenamebuf,
+ buf2, MAXPDSTRING);
+ sys_bashfilename(buf2, buf2);
+ if (!(fd = fopen(buf2, BINWRITEMODE)))
+ {
+ error("%s: can't create", buf2);
+ return;
+ }
+ intbuf = 2 * x->x_n + 36;
+ if (swap)
+ {
+ unsigned char *foo = (unsigned char *)&intbuf, xxx;
+ xxx = foo[0]; foo[0] = foo[3]; foo[3] = xxx;
+ xxx = foo[1]; foo[1] = foo[2]; foo[2] = xxx;
+ }
+ memcpy((void *)(waveheader + 4), (void *)(&intbuf), 4);
+ intbuf = 2 * x->x_n;
+ if (swap)
+ {
+ unsigned char *foo = (unsigned char *)&intbuf, xxx;
+ xxx = foo[0]; foo[0] = foo[3]; foo[3] = xxx;
+ xxx = foo[1]; foo[1] = foo[2]; foo[2] = xxx;
+ }
+ memcpy((void *)(waveheader + 40), (void *)(&intbuf), 4);
+ if (fwrite(waveheader, sizeof(waveheader), 1, fd) < 1)
+ {
+ post("%s: write error", buf2);
+ goto closeit;
+ }
+ for (i = 0; i < x->x_n; i++)
+ {
+ float f = 32767. * *(float *)((x->x_vec + sizeof(t_word) * i) + yonset);
+ short sh;
+ if (f < -32768) f = -32768;
+ else if (f > 32767) f = 32767;
+ sh = f;
+ if (swap)
+ {
+ unsigned char *foo = (unsigned char *)&sh, xxx;
+ xxx = foo[0]; foo[0] = foo[1]; foo[1] = xxx;
+ }
+ if (fwrite(&sh, sizeof(sh), 1, fd) < 1)
+ {
+ post("%s: write error", buf2);
+ goto closeit;
+ }
+ }
+closeit:
+ fclose(fd);
+}
+
+void garray_resize(t_garray *x, t_floatarg f)
+{
+ int was = x->x_n, elemsize;
+ t_glist *gl;
+ int dspwas;
+ int n = f;
+ char *nvec;
+
+ if (n < 1) n = 1;
+ elemsize = template_findbyname(x->x_templatesym)->t_n * sizeof(t_word);
+ nvec = t_resizebytes(x->x_vec, was * elemsize, n * elemsize);
+ if (!nvec)
+ {
+ pd_error(x, "array resize failed: out of memory");
+ return;
+ }
+ x->x_vec = nvec;
+ /* LATER should check t_resizebytes result */
+ if (n > was)
+ memset(x->x_vec + was*elemsize,
+ 0, (n - was) * elemsize);
+ x->x_n = n;
+
+ /* if this is the only array in the graph,
+ reset the graph's coordinates */
+ gl = x->x_glist;
+ if (gl->gl_list == &x->x_gobj && !x->x_gobj.g_next)
+ {
+ vmess(&gl->gl_pd, gensym("bounds"), "ffff",
+ 0., gl->gl_y1, (double)(n > 1 ? n-1 : 1), gl->gl_y2);
+ /* close any dialogs that might have the wrong info now... */
+ gfxstub_deleteforkey(gl);
+ }
+ else garray_redraw(x);
+ if (x->x_usedindsp) canvas_update_dsp();
+}
+
+static void garray_print(t_garray *x)
+{
+ post("garray %s: template %s, length %d",
+ x->x_name->s_name, x->x_templatesym->s_name, x->x_n);
+}
+
+void g_array_setup(void)
+{
+ garray_class = class_new(gensym("array"), 0, (t_method)garray_free,
+ sizeof(t_garray), CLASS_GOBJ, 0);
+ class_setwidget(garray_class, &garray_widgetbehavior);
+ class_addmethod(garray_class, (t_method)garray_const, gensym("const"),
+ A_DEFFLOAT, A_NULL);
+ class_addlist(garray_class, garray_list);
+ class_addmethod(garray_class, (t_method)garray_bounds, gensym("bounds"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(garray_class, (t_method)garray_xticks, gensym("xticks"),
+ A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(garray_class, (t_method)garray_xlabel, gensym("xlabel"),
+ A_GIMME, 0);
+ class_addmethod(garray_class, (t_method)garray_yticks, gensym("yticks"),
+ A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(garray_class, (t_method)garray_ylabel, gensym("ylabel"),
+ A_GIMME, 0);
+ class_addmethod(garray_class, (t_method)garray_rename, gensym("rename"),
+ A_SYMBOL, 0);
+ class_addmethod(garray_class, (t_method)garray_read, gensym("read"),
+ A_SYMBOL, A_NULL);
+ class_addmethod(garray_class, (t_method)garray_read16, gensym("read16"),
+ A_SYMBOL, A_DEFFLOAT, A_DEFSYM, A_NULL);
+ class_addmethod(garray_class, (t_method)garray_write, gensym("write"),
+ A_SYMBOL, A_NULL);
+ class_addmethod(garray_class, (t_method)garray_write16, gensym("write16"),
+ A_SYMBOL, A_DEFSYM, A_NULL);
+ class_addmethod(garray_class, (t_method)garray_resize, gensym("resize"),
+ A_FLOAT, A_NULL);
+ class_addmethod(garray_class, (t_method)garray_print, gensym("print"),
+ A_NULL);
+ class_addmethod(garray_class, (t_method)garray_sinesum, gensym("sinesum"),
+ A_GIMME, 0);
+ class_addmethod(garray_class, (t_method)garray_cosinesum,
+ gensym("cosinesum"), A_GIMME, 0);
+ class_addmethod(garray_class, (t_method)garray_normalize,
+ gensym("normalize"), A_DEFFLOAT, 0);
+ class_addmethod(garray_class, (t_method)garray_arraydialog,
+ gensym("arraydialog"), A_SYMBOL, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+}
+
+
diff --git a/pd/src/g_bang.c b/pd/src/g_bang.c
new file mode 100644
index 00000000..cb92c685
--- /dev/null
+++ b/pd/src/g_bang.c
@@ -0,0 +1,600 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
+/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "m_imp.h"
+#include "g_canvas.h"
+#include "t_tk.h"
+#include "g_all_guis.h"
+#include <math.h>
+
+#ifdef NT
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+
+/* --------------- bng gui-bang ------------------------- */
+
+t_widgetbehavior bng_widgetbehavior;
+static t_class *bng_class;
+
+/* widget helper functions */
+
+
+void bng_draw_update(t_bng *x, t_glist *glist)
+{
+ if(glist_isvisible(glist))
+ {
+ sys_vgui(".x%x.c itemconfigure %xBUT -fill #%6.6x\n", glist_getcanvas(glist), x,
+ x->x_flashed?x->x_gui.x_fcol:x->x_gui.x_bcol);
+ }
+}
+
+void bng_draw_new(t_bng *x, t_glist *glist)
+{
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE\n",
+ canvas, xpos, ypos,
+ xpos + x->x_gui.x_w, ypos + x->x_gui.x_h,
+ x->x_gui.x_bcol, x);
+ sys_vgui(".x%x.c create oval %d %d %d %d -fill #%6.6x -tags %xBUT\n",
+ canvas, xpos+1, ypos+1,
+ xpos + x->x_gui.x_w-1, ypos + x->x_gui.x_h-1,
+ x->x_flashed?x->x_gui.x_fcol:x->x_gui.x_bcol, x);
+ sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
+ -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
+ canvas, xpos+x->x_gui.x_ldx,
+ ypos+x->x_gui.x_ldy,
+ strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
+ x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+ canvas, xpos,
+ ypos + x->x_gui.x_h-1, xpos + IOWIDTH,
+ ypos + x->x_gui.x_h, x, 0);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
+ canvas, xpos, ypos,
+ xpos + IOWIDTH, ypos+1, x, 0);
+}
+
+void bng_draw_move(t_bng *x, t_glist *glist)
+{
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c coords %xBASE %d %d %d %d\n",
+ canvas, x, xpos, ypos,
+ xpos + x->x_gui.x_w, ypos + x->x_gui.x_h);
+ sys_vgui(".x%x.c coords %xBUT %d %d %d %d\n",
+ canvas, x, xpos+1,ypos+1,
+ xpos + x->x_gui.x_w-1, ypos + x->x_gui.x_h-1);
+ sys_vgui(".x%x.c itemconfigure %xBUT -fill #%6.6x\n", canvas, x,
+ x->x_flashed?x->x_gui.x_fcol:x->x_gui.x_bcol);
+ sys_vgui(".x%x.c coords %xLABEL %d %d\n",
+ canvas, x, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
+ canvas, x, 0, xpos,
+ ypos + x->x_gui.x_h-1, xpos + IOWIDTH,
+ ypos + x->x_gui.x_h);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
+ canvas, x, 0, xpos, ypos,
+ xpos + IOWIDTH, ypos+1);
+}
+
+void bng_draw_erase(t_bng* x, t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c delete %xBASE\n", canvas, x);
+ sys_vgui(".x%x.c delete %xBUT\n", canvas, x);
+ sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
+}
+
+void bng_draw_config(t_bng* x, t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
+ canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
+ x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
+ strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
+ sys_vgui(".x%x.c itemconfigure %xBASE -fill #%6.6x\n", canvas, x, x->x_gui.x_bcol);
+ sys_vgui(".x%x.c itemconfigure %xBUT -fill #%6.6x\n", canvas, x,
+ x->x_flashed?x->x_gui.x_fcol:x->x_gui.x_bcol);
+}
+
+void bng_draw_io(t_bng* x, t_glist* glist, int old_snd_rcv_flags)
+{
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+ canvas, xpos,
+ ypos + x->x_gui.x_h-1, xpos + IOWIDTH,
+ ypos + x->x_gui.x_h, x, 0);
+ if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
+ if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
+ canvas, xpos, ypos,
+ xpos + IOWIDTH, ypos+1, x, 0);
+ if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
+}
+
+void bng_draw_select(t_bng* x, t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if(x->x_gui.x_fsf.x_selected)
+ {
+ pd_bind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+ sys_vgui(".x%x.c itemconfigure %xBUT -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+ sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+ }
+ else
+ {
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
+ sys_vgui(".x%x.c itemconfigure %xBUT -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
+ sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol);
+ }
+}
+
+void bng_draw(t_bng *x, t_glist *glist, int mode)
+{
+ if(mode == IEM_GUI_DRAW_MODE_UPDATE)
+ bng_draw_update(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_MOVE)
+ bng_draw_move(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_NEW)
+ bng_draw_new(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_SELECT)
+ bng_draw_select(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_ERASE)
+ bng_draw_erase(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
+ bng_draw_config(x, glist);
+ else if(mode >= IEM_GUI_DRAW_MODE_IO)
+ bng_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
+}
+
+/* ------------------------ bng widgetbehaviour----------------------------- */
+
+static void bng_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_bng *x = (t_bng *)z;
+
+ *xp1 = text_xpix(&x->x_gui.x_obj, glist);
+ *yp1 = text_ypix(&x->x_gui.x_obj, glist);
+ *xp2 = *xp1 + x->x_gui.x_w;
+ *yp2 = *yp1 + x->x_gui.x_h;
+}
+
+static void bng_save(t_gobj *z, t_binbuf *b)
+{
+ t_bng *x = (t_bng *)z;
+ int bflcol[3], *ip1, *ip2;
+ t_symbol *srl[3];
+
+ iemgui_save(&x->x_gui, srl, bflcol);
+ ip1 = (int *)(&x->x_gui.x_isa);
+ ip2 = (int *)(&x->x_gui.x_fsf);
+ binbuf_addv(b, "ssiisiiiisssiiiiiii", gensym("#X"),gensym("obj"),
+ (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
+ gensym("bng"), x->x_gui.x_w,
+ x->x_flashtime_hold, x->x_flashtime_break,
+ (*ip1)&IEM_INIT_ARGS_ALL,
+ srl[0], srl[1], srl[2],
+ x->x_gui.x_ldx, x->x_gui.x_ldy,
+ (*ip2)&IEM_FSTYLE_FLAGS_ALL, x->x_gui.x_fontsize,
+ bflcol[0], bflcol[1], bflcol[2]);
+ binbuf_addv(b, ";");
+}
+
+void bng_check_minmax(t_bng *x, int ftbreak, int fthold)
+{
+ if(ftbreak > fthold)
+ {
+ int h;
+
+ h = ftbreak;
+ ftbreak = fthold;
+ fthold = h;
+ }
+ if(ftbreak < IEM_BNG_MINBREAKFLASHTIME)
+ ftbreak = IEM_BNG_MINBREAKFLASHTIME;
+ if(fthold < IEM_BNG_MINHOLDFLASHTIME)
+ fthold = IEM_BNG_MINHOLDFLASHTIME;
+ x->x_flashtime_break = ftbreak;
+ x->x_flashtime_hold = fthold;
+}
+
+static void bng_properties(t_gobj *z, t_glist *owner)
+{
+ t_bng *x = (t_bng *)z;
+ char buf[800];
+ t_symbol *srl[3];
+
+ iemgui_properties(&x->x_gui, srl);
+ sprintf(buf, "pdtk_iemgui_dialog %%s BANG \
+ ----------dimensions(pix):----------- %d %d size: 0 0 empty \
+ --------flash-time(ms)(ms):--------- %d intrrpt: %d hold: %d \
+ %d empty empty %d %d empty %d \
+ %s %s \
+ %s %d %d \
+ %d %d \
+ %d %d %d\n",
+ x->x_gui.x_w, IEM_GUI_MINSIZE,
+ x->x_flashtime_break, x->x_flashtime_hold, 2,/*min_max_schedule+clip*/
+ -1, x->x_gui.x_isa.x_loadinit, -1, -1,/*no linlog, no multi*/
+ srl[0]->s_name, srl[1]->s_name,
+ srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
+ x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
+ 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
+ gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
+}
+
+static void bng_set(t_bng *x)
+{
+ if(x->x_flashed)
+ {
+ x->x_flashed = 0;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ clock_delay(x->x_clock_brk, x->x_flashtime_break);
+ x->x_flashed = 1;
+ }
+ else
+ {
+ x->x_flashed = 1;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ }
+ clock_delay(x->x_clock_hld, x->x_flashtime_hold);
+}
+
+static void bng_bout1(t_bng *x)/*wird nur mehr gesendet, wenn snd != rcv*/
+{
+ if(!x->x_gui.x_fsf.x_put_in2out)
+ {
+ x->x_gui.x_isa.x_locked = 1;
+ clock_delay(x->x_clock_lck, 2);
+ }
+ outlet_bang(x->x_gui.x_obj.ob_outlet);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing && x->x_gui.x_fsf.x_put_in2out)
+ pd_bang(x->x_gui.x_snd->s_thing);
+}
+
+static void bng_bout2(t_bng *x)/*wird immer gesendet, wenn moeglich*/
+{
+ if(!x->x_gui.x_fsf.x_put_in2out)
+ {
+ x->x_gui.x_isa.x_locked = 1;
+ clock_delay(x->x_clock_lck, 2);
+ }
+ outlet_bang(x->x_gui.x_obj.ob_outlet);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_bang(x->x_gui.x_snd->s_thing);
+}
+
+static void bng_bang(t_bng *x)/*wird nur mehr gesendet, wenn snd != rcv*/
+{
+ if(!x->x_gui.x_isa.x_locked)
+ {
+ bng_set(x);
+ bng_bout1(x);
+ }
+}
+
+static void bng_bang2(t_bng *x)/*wird immer gesendet, wenn moeglich*/
+{
+ if(!x->x_gui.x_isa.x_locked)
+ {
+ bng_set(x);
+ bng_bout2(x);
+ }
+}
+
+static void bng_dialog(t_bng *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_symbol *srl[3];
+ int a = (int)atom_getintarg(0, argc, argv);
+ int fthold = (int)atom_getintarg(2, argc, argv);
+ int ftbreak = (int)atom_getintarg(3, argc, argv);
+ int sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
+
+ x->x_gui.x_w = iemgui_clip_size(a);
+ x->x_gui.x_h = x->x_gui.x_w;
+ bng_check_minmax(x, ftbreak, fthold);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
+}
+
+static void bng_click(t_bng *x, t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ bng_set(x);
+ bng_bout2(x);
+}
+
+static int bng_newclick(t_gobj *z, struct _glist *glist, int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ if(doit)
+ bng_click((t_bng *)z, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift, 0, (t_floatarg)alt);
+ return (1);
+}
+
+static void bng_float(t_bng *x, t_floatarg f)
+{bng_bang2(x);}
+
+static void bng_symbol(t_bng *x, t_symbol *s)
+{bng_bang2(x);}
+
+static void bng_pointer(t_bng *x, t_gpointer *gp)
+{bng_bang2(x);}
+
+static void bng_list(t_bng *x, t_symbol *s, int ac, t_atom *av)
+{
+ int l=iemgui_list((void *)x, &x->x_gui, s, ac, av);
+
+ if(l < 0)
+ {
+ bng_bang2(x);
+ }
+ else if(l > 0)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
+ }
+}
+
+static void bng_anything(t_bng *x, t_symbol *s, int argc, t_atom *argv)
+{bng_bang2(x);}
+
+static void bng_loadbang(t_bng *x)
+{
+ if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
+ {
+ bng_set(x);
+ bng_bout2(x);
+ }
+}
+
+static void bng_size(t_bng *x, t_symbol *s, int ac, t_atom *av)
+{
+ x->x_gui.x_w = iemgui_clip_size((int)atom_getintarg(0, ac, av));
+ x->x_gui.x_h = x->x_gui.x_w;
+ iemgui_size((void *)x, &x->x_gui);
+}
+
+static void bng_delta(t_bng *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
+
+static void bng_pos(t_bng *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
+
+static void bng_flashtime(t_bng *x, t_symbol *s, int ac, t_atom *av)
+{
+ bng_check_minmax(x, (int)atom_getintarg(0, ac, av),
+ (int)atom_getintarg(1, ac, av));
+}
+
+static void bng_color(t_bng *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
+
+static void bng_send(t_bng *x, t_symbol *s)
+{iemgui_send(x, &x->x_gui, s);}
+
+static void bng_receive(t_bng *x, t_symbol *s)
+{iemgui_receive(x, &x->x_gui, s);}
+
+static void bng_label(t_bng *x, t_symbol *s)
+{iemgui_label((void *)x, &x->x_gui, s);}
+
+static void bng_label_pos(t_bng *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
+
+static void bng_label_font(t_bng *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
+
+static void bng_init(t_bng *x, t_floatarg f)
+{
+ x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
+}
+
+static void bng_tick_hld(t_bng *x)
+{
+ x->x_flashed = 0;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+}
+
+static void bng_tick_brk(t_bng *x)
+{
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+}
+
+static void bng_tick_lck(t_bng *x)
+{
+ x->x_gui.x_isa.x_locked = 0;
+}
+
+static void *bng_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_bng *x = (t_bng *)pd_new(bng_class);
+ int bflcol[]={-262144, -1, -1};
+ t_symbol *srl[3];
+ int a=IEM_GUI_DEFAULTSIZE;
+ int ldx=0, ldy=-6;
+ int fs=8, iinit=0, ifstyle=0;
+ int ftbreak=IEM_BNG_DEFAULTBREAKFLASHTIME, fthold=IEM_BNG_DEFAULTHOLDFLASHTIME;
+ t_iem_init_symargs *init=(t_iem_init_symargs *)(&iinit);
+ t_iem_fstyle_flags *fstyle=(t_iem_fstyle_flags *)(&ifstyle);
+ char str[144];
+
+ srl[0] = gensym("empty");
+ srl[1] = gensym("empty");
+ srl[2] = gensym("empty");
+
+ if((argc == 14)&&IS_A_FLOAT(argv,0)
+ &&IS_A_FLOAT(argv,1)&&IS_A_FLOAT(argv,2)
+ &&IS_A_FLOAT(argv,3)
+ &&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4))
+ &&(IS_A_SYMBOL(argv,5)||IS_A_FLOAT(argv,5))
+ &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
+ &&IS_A_FLOAT(argv,7)&&IS_A_FLOAT(argv,8)
+ &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)&&IS_A_FLOAT(argv,11)
+ &&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13))
+ {
+
+ a = (int)atom_getintarg(0, argc, argv);
+ fthold = (int)atom_getintarg(1, argc, argv);
+ ftbreak = (int)atom_getintarg(2, argc, argv);
+ iinit = (int)(atom_getintarg(3, argc, argv));
+ if(IS_A_SYMBOL(argv,4))
+ srl[0] = atom_getsymbolarg(4, argc, argv);
+ else if(IS_A_FLOAT(argv,4))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(4, argc, argv));
+ srl[0] = gensym(str);
+ }
+ if(IS_A_SYMBOL(argv,5))
+ srl[1] = atom_getsymbolarg(5, argc, argv);
+ else if(IS_A_FLOAT(argv,5))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(5, argc, argv));
+ srl[1] = gensym(str);
+ }
+ if(IS_A_SYMBOL(argv,6))
+ srl[2] = atom_getsymbolarg(6, argc, argv);
+ else if(IS_A_FLOAT(argv,6))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(6, argc, argv));
+ srl[2] = gensym(str);
+ }
+ ldx = (int)atom_getintarg(7, argc, argv);
+ ldy = (int)atom_getintarg(8, argc, argv);
+ ifstyle = (int)(atom_getintarg(9, argc, argv));
+ fs = (int)atom_getintarg(10, argc, argv);
+ bflcol[0] = (int)atom_getintarg(11, argc, argv);
+ bflcol[1] = (int)atom_getintarg(12, argc, argv);
+ bflcol[2] = (int)atom_getintarg(13, argc, argv);
+ }
+
+ x->x_gui.x_draw = (t_iemfunptr)bng_draw;
+ iinit &= IEM_INIT_ARGS_ALL;
+ ifstyle &= IEM_FSTYLE_FLAGS_ALL;
+
+ fstyle->x_snd_able = 1;
+ fstyle->x_rcv_able = 1;
+ x->x_flashed = 0;
+ x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
+ x->x_gui.x_isa = *init;
+ if(!strcmp(srl[0]->s_name, "empty")) fstyle->x_snd_able = 0;
+ if(!strcmp(srl[1]->s_name, "empty")) fstyle->x_rcv_able = 0;
+ x->x_gui.x_unique_num = 0;
+ if(fstyle->x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
+ else if(fstyle->x_font_style == 2) strcpy(x->x_gui.x_font, "times");
+ else { fstyle->x_font_style = 0;
+ strcpy(x->x_gui.x_font, "courier"); }
+ x->x_gui.x_fsf = *fstyle;
+ iemgui_first_dollararg2sym(&x->x_gui, srl);
+
+ if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, srl[1]);
+ x->x_gui.x_snd = srl[0];
+ x->x_gui.x_rcv = srl[1];
+ x->x_gui.x_lab = srl[2];
+ x->x_gui.x_ldx = ldx;
+ x->x_gui.x_ldy = ldy;
+
+ if(fs < 4)
+ fs = 4;
+ x->x_gui.x_fontsize = fs;
+ x->x_gui.x_w = iemgui_clip_size(a);
+ x->x_gui.x_h = x->x_gui.x_w;
+ bng_check_minmax(x, ftbreak, fthold);
+ iemgui_all_colfromload(&x->x_gui, bflcol);
+ x->x_gui.x_isa.x_locked = 0;
+ iemgui_verify_snd_ne_rcv(&x->x_gui);
+ x->x_clock_hld = clock_new(x, (t_method)bng_tick_hld);
+ x->x_clock_brk = clock_new(x, (t_method)bng_tick_brk);
+ x->x_clock_lck = clock_new(x, (t_method)bng_tick_lck);
+ outlet_new(&x->x_gui.x_obj, &s_bang);
+ return (x);
+}
+
+static void bng_ff(t_bng *x)
+{
+ if(x->x_gui.x_fsf.x_selected)
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ if(x->x_gui.x_fsf.x_rcv_able)
+ pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
+ clock_free(x->x_clock_lck);
+ clock_free(x->x_clock_brk);
+ clock_free(x->x_clock_hld);
+ gfxstub_deleteforkey(x);
+}
+
+void g_bang_setup(void)
+{
+ bng_class = class_new(gensym("bng"), (t_newmethod)bng_new,
+ (t_method)bng_ff, sizeof(t_bng), 0, A_GIMME, 0);
+ class_addbang(bng_class, bng_bang);
+ class_addfloat(bng_class, bng_float);
+ class_addsymbol(bng_class, bng_symbol);
+ class_addpointer(bng_class, bng_pointer);
+ class_addlist(bng_class, bng_list);
+ class_addanything(bng_class, bng_anything);
+ class_addmethod(bng_class, (t_method)bng_click, gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(bng_class, (t_method)bng_dialog, gensym("dialog"),
+ A_GIMME, 0);
+ class_addmethod(bng_class, (t_method)bng_loadbang, gensym("loadbang"), 0);
+ class_addmethod(bng_class, (t_method)bng_size, gensym("size"), A_GIMME, 0);
+ class_addmethod(bng_class, (t_method)bng_delta, gensym("delta"), A_GIMME, 0);
+ class_addmethod(bng_class, (t_method)bng_pos, gensym("pos"), A_GIMME, 0);
+ class_addmethod(bng_class, (t_method)bng_flashtime, gensym("flashtime"), A_GIMME, 0);
+ class_addmethod(bng_class, (t_method)bng_color, gensym("color"), A_GIMME, 0);
+ class_addmethod(bng_class, (t_method)bng_send, gensym("send"), A_DEFSYM, 0);
+ class_addmethod(bng_class, (t_method)bng_receive, gensym("receive"), A_DEFSYM, 0);
+ class_addmethod(bng_class, (t_method)bng_label, gensym("label"), A_DEFSYM, 0);
+ class_addmethod(bng_class, (t_method)bng_label_pos, gensym("label_pos"), A_GIMME, 0);
+ class_addmethod(bng_class, (t_method)bng_label_font, gensym("label_font"), A_GIMME, 0);
+ class_addmethod(bng_class, (t_method)bng_init, gensym("init"), A_FLOAT, 0);
+ if(!iemgui_key_sym)
+ iemgui_key_sym = gensym("#keyname");
+ bng_widgetbehavior.w_getrectfn = bng_getrect;
+ bng_widgetbehavior.w_displacefn = iemgui_displace;
+ bng_widgetbehavior.w_selectfn = iemgui_select;
+ bng_widgetbehavior.w_activatefn = NULL;
+ bng_widgetbehavior.w_deletefn = iemgui_delete;
+ bng_widgetbehavior.w_visfn = iemgui_vis;
+ bng_widgetbehavior.w_clickfn = bng_newclick;
+ bng_widgetbehavior.w_propertiesfn = bng_properties;
+ bng_widgetbehavior.w_savefn = bng_save;
+ class_setwidget(bng_class, &bng_widgetbehavior);
+ class_sethelpsymbol(bng_class, gensym("bng"));
+}
diff --git a/pd/src/g_canvas.c b/pd/src/g_canvas.c
new file mode 100644
index 00000000..c63b2c0b
--- /dev/null
+++ b/pd/src/g_canvas.c
@@ -0,0 +1,1482 @@
+/* Copyright (c) 1997-2001 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. */
+
+/* this file defines the "glist" class, also known as "canvas" (the two used
+to be different but are now unified except for some fossilized names.) */
+
+/* changes by Thomas Musil IEM KUG Graz Austria 2001 */
+
+/* improvement: line-delete-protection, look for "protect" */
+/* bug-fix: canvas_menuclose(): by Krzysztof Czaja */
+/* bug-fix: table_new(): I reversed the y-bounds */
+
+/* IOhannes :
+ * changed the canvas_restore, so that it might accept $args as well
+ * (like "pd $0_test")
+ * so you can make multiple & distinguishable templates
+ * 1511:forum::für::umläute:2001
+ * changes marked with IOhannes
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "m_imp.h"
+#include "g_canvas.h"
+#include <string.h>
+#include "g_all_guis.h"
+
+struct _canvasenvironment
+{
+ t_symbol *ce_dir; /* directory patch lives in */
+ int ce_argc; /* number of "$" arguments */
+ t_atom *ce_argv; /* array of "$" arguments */
+ int ce_dollarzero; /* value of "$0" */
+};
+
+#define GLIST_DEFCANVASWIDTH 450
+#define GLIST_DEFCANVASHEIGHT 300
+
+#ifdef MACOSX
+#define GLIST_DEFCANVASYLOC 20
+#else
+#define GLIST_DEFCANVASYLOC 0
+#endif
+
+/* ---------------------- variables --------------------------- */
+
+extern t_pd *newest;
+t_class *canvas_class;
+static int canvas_dspstate; /* whether DSP is on or off */
+t_canvas *canvas_editing; /* last canvas to start text edting */
+t_canvas *canvas_whichfind; /* last canvas we did a find in */
+t_canvas *canvas_list; /* list of all root canvases */
+
+/* ------------------ forward function declarations --------------- */
+static void canvas_start_dsp(void);
+static void canvas_stop_dsp(void);
+static void canvas_drawlines(t_canvas *x);
+static void canvas_setbounds(t_canvas *x, int x1, int y1, int x2, int y2);
+static void canvas_reflecttitle(t_canvas *x);
+static void canvas_addtolist(t_canvas *x);
+static void canvas_takeofflist(t_canvas *x);
+static void canvas_pop(t_canvas *x, t_floatarg fvis);
+void canvas_create_editor(t_glist *x, int createit);
+
+/* --------- functions to handle the canvas environment ----------- */
+
+static t_symbol *canvas_newfilename = &s_;
+static t_symbol *canvas_newdirectory = &s_;
+static int canvas_newargc;
+static t_atom *canvas_newargv;
+
+static void glist_doupdatewindowlist(t_glist *gl, char *sbuf)
+{
+ t_gobj *g;
+ if (!gl->gl_owner)
+ {
+ /* this is a canvas; if we have a window, put on "windows" list */
+ t_canvas *canvas = (t_canvas *)gl;
+ if (canvas->gl_havewindow)
+ {
+ if (strlen(sbuf) + strlen(gl->gl_name->s_name) + 100 <= 1024)
+ {
+ char tbuf[1024];
+ sprintf(tbuf, "{%s .x%x} ", gl->gl_name->s_name, (t_int)canvas);
+ strcat(sbuf, tbuf);
+ }
+ }
+ }
+ for (g = gl->gl_list; g; g = g->g_next)
+ {
+ if (pd_class(&g->g_pd) == canvas_class)
+ glist_doupdatewindowlist((t_glist *)g, sbuf);
+ }
+ return;
+}
+
+ /* maintain the list of visible toplevels for the GUI's "windows" menu */
+void canvas_updatewindowlist( void)
+{
+ t_canvas *x;
+ char sbuf[1024];
+ strcpy(sbuf, "set menu_windowlist {");
+ /* find all root canvases */
+ for (x = canvas_list; x; x = x->gl_next)
+ glist_doupdatewindowlist(x, sbuf);
+ strcat(sbuf, "}\n");
+ sys_gui(sbuf);
+}
+
+ /* add a glist the list of "root" canvases (toplevels without parents.) */
+static void canvas_addtolist(t_canvas *x)
+{
+ x->gl_next = canvas_list;
+ canvas_list = x;
+}
+
+static void canvas_takeofflist(t_canvas *x)
+{
+ /* take it off the window list */
+ if (x == canvas_list) canvas_list = x->gl_next;
+ else
+ {
+ t_canvas *z;
+ for (z = canvas_list; z->gl_next != x; z = z->gl_next)
+ ;
+ z->gl_next = x->gl_next;
+ }
+}
+
+
+void canvas_setargs(int argc, t_atom *argv)
+{
+ /* if there's an old one lying around free it here. This
+ happens if an abstraction is loaded but never gets as far
+ as calling canvas_new(). */
+ if (canvas_newargv)
+ freebytes(canvas_newargv, canvas_newargc * sizeof(t_atom));
+ canvas_newargc = argc;
+ canvas_newargv = copybytes(argv, argc * sizeof(t_atom));
+}
+
+void glob_setfilename(void *dummy, t_symbol *filesym, t_symbol *dirsym)
+{
+ canvas_newfilename = filesym;
+ canvas_newdirectory = dirsym;
+}
+
+t_canvas *canvas_getcurrent(void)
+{
+ return ((t_canvas *)pd_findbyclass(&s__X, canvas_class));
+}
+
+void canvas_setcurrent(t_canvas *x)
+{
+ pd_pushsym(&x->gl_pd);
+}
+
+void canvas_unsetcurrent(t_canvas *x)
+{
+ pd_popsym(&x->gl_pd);
+}
+
+t_canvasenvironment *canvas_getenv(t_canvas *x)
+{
+ if (!x) bug("canvas_getenv");
+ while (!x->gl_env)
+ if (!(x = x->gl_owner))
+ bug("t_canvasenvironment", x);
+ return (x->gl_env);
+}
+
+int canvas_getdollarzero( void)
+{
+ t_canvas *x = canvas_getcurrent();
+ t_canvasenvironment *env = (x ? canvas_getenv(x) : 0);
+ if (env)
+ return (env->ce_dollarzero);
+ else return (0);
+}
+
+void canvas_getargs(int *argcp, t_atom **argvp)
+{
+ t_canvasenvironment *e = canvas_getenv(canvas_getcurrent());
+ *argcp = e->ce_argc;
+ *argvp = e->ce_argv;
+}
+
+t_symbol *realizedollsym(t_symbol *s, int ac, t_atom *av, int tonew);
+
+t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s)
+{
+ t_symbol *ret;
+ char *name = s->s_name;
+ if (*name == '$' && name[1] >= '0' && name[1] <= '9')
+ {
+ t_canvasenvironment *env = canvas_getenv(x);
+ canvas_setcurrent(x);
+ ret = realizedollsym(gensym(name+1), env->ce_argc, env->ce_argv, 1);
+ canvas_unsetcurrent(x);
+ }
+ else ret = s;
+ return (ret);
+}
+
+t_symbol *canvas_getcurrentdir(void)
+{
+ t_canvasenvironment *e = canvas_getenv(canvas_getcurrent());
+ return (e->ce_dir);
+}
+
+t_symbol *canvas_getdir(t_canvas *x)
+{
+ t_canvasenvironment *e = canvas_getenv(x);
+ return (e->ce_dir);
+}
+
+void canvas_makefilename(t_canvas *x, char *file, char *result, int resultsize)
+{
+ char *dir = canvas_getenv(x)->ce_dir->s_name;
+ if (file[0] == '/' || (file[0] && file[1] == ':') || !*dir)
+ {
+ strncpy(result, file, resultsize);
+ result[resultsize-1] = 0;
+ }
+ else
+ {
+ int nleft;
+ strncpy(result, dir, resultsize);
+ result[resultsize-1] = 0;
+ nleft = resultsize - strlen(result) - 1;
+ if (nleft <= 0) return;
+ strcat(result, "/");
+ strncat(result, file, nleft);
+ result[resultsize-1] = 0;
+ }
+}
+
+void canvas_rename(t_canvas *x, t_symbol *s, t_symbol *dir)
+{
+ if (strcmp(x->gl_name->s_name, "Pd"))
+ pd_unbind(&x->gl_pd, canvas_makebindsym(x->gl_name));
+ x->gl_name = s;
+ if (strcmp(x->gl_name->s_name, "Pd"))
+ pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name));
+ if (glist_isvisible(x))
+ canvas_reflecttitle(x);
+ if (dir && dir != &s_)
+ {
+ t_canvasenvironment *e = canvas_getenv(x);
+ e->ce_dir = dir;
+ }
+}
+
+/* --------------- traversing the set of lines in a canvas ----------- */
+
+void linetraverser_start(t_linetraverser *t, t_canvas *x)
+{
+ t->tr_ob = 0;
+ t->tr_x = x;
+ t->tr_nextoc = 0;
+ t->tr_nextoutno = t->tr_nout = 0;
+}
+
+t_outconnect *linetraverser_next(t_linetraverser *t)
+{
+ t_outconnect *rval = t->tr_nextoc;
+ int outno;
+ while (!rval)
+ {
+ outno = t->tr_nextoutno;
+ while (outno == t->tr_nout)
+ {
+ t_gobj *y;
+ t_object *ob = 0;
+ if (!t->tr_ob) y = t->tr_x->gl_list;
+ else y = t->tr_ob->ob_g.g_next;
+ for (; y; y = y->g_next)
+ if (ob = pd_checkobject(&y->g_pd)) break;
+ if (!ob) return (0);
+ t->tr_ob = ob;
+ t->tr_nout = obj_noutlets(ob);
+ outno = 0;
+ if (glist_isvisible(t->tr_x))
+ gobj_getrect(y, t->tr_x,
+ &t->tr_x11, &t->tr_y11, &t->tr_x12, &t->tr_y12);
+ else t->tr_x11 = t->tr_y11 = t->tr_x12 = t->tr_y12 = 0;
+ }
+ t->tr_nextoutno = outno + 1;
+ rval = obj_starttraverseoutlet(t->tr_ob, &t->tr_outlet, outno);
+ t->tr_outno = outno;
+ }
+ t->tr_nextoc = obj_nexttraverseoutlet(rval, &t->tr_ob2,
+ &t->tr_inlet, &t->tr_inno);
+ t->tr_nin = obj_ninlets(t->tr_ob2);
+ if (!t->tr_nin) bug("drawline");
+ if (glist_isvisible(t->tr_x))
+ {
+ int inplus = (t->tr_nin == 1 ? 1 : t->tr_nin - 1);
+ int outplus = (t->tr_nout == 1 ? 1 : t->tr_nout - 1);
+ gobj_getrect(&t->tr_ob2->ob_g, t->tr_x,
+ &t->tr_x21, &t->tr_y21, &t->tr_x22, &t->tr_y22);
+ t->tr_lx1 = t->tr_x11 +
+ ((t->tr_x12 - t->tr_x11 - IOWIDTH) * t->tr_outno) /
+ outplus + IOMIDDLE;
+ t->tr_ly1 = t->tr_y12;
+ t->tr_lx2 = t->tr_x21 +
+ ((t->tr_x22 - t->tr_x21 - IOWIDTH) * t->tr_inno)/inplus +
+ IOMIDDLE;
+ t->tr_ly2 = t->tr_y21;
+ }
+ else
+ {
+ t->tr_x21 = t->tr_y21 = t->tr_x22 = t->tr_y22 = 0;
+ t->tr_lx1 = t->tr_ly1 = t->tr_lx2 = t->tr_ly2 = 0;
+ }
+
+ return (rval);
+}
+
+void linetraverser_skipobject(t_linetraverser *t)
+{
+ t->tr_nextoc = 0;
+ t->tr_nextoutno = t->tr_nout;
+}
+
+/* -------------------- the canvas object -------------------------- */
+int glist_valid = 10000;
+
+void glist_init(t_glist *x)
+{
+ /* zero out everyone except "pd" field */
+ memset(((char *)x) + sizeof(x->gl_pd), 0, sizeof(*x) - sizeof(x->gl_pd));
+ x->gl_stub = gstub_new(x, 0);
+ x->gl_valid = ++glist_valid;
+ x->gl_xlabel = (t_symbol **)t_getbytes(0);
+ x->gl_ylabel = (t_symbol **)t_getbytes(0);
+}
+
+ /* make a new glist. It will either be a "root" canvas or else
+ its parent will be a "text" object in another window... we don't
+ know which yet. */
+t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv)
+{
+ t_canvas *x = (t_canvas *)pd_new(canvas_class);
+ t_canvas *owner = canvas_getcurrent();
+ t_symbol *s = &s_;
+ int vis = 0, width = GLIST_DEFCANVASWIDTH, height = GLIST_DEFCANVASHEIGHT;
+ int xloc = 0, yloc = GLIST_DEFCANVASYLOC;
+ int font = (owner ? owner->gl_font : sys_defaultfont);
+ glist_init(x);
+ x->gl_obj.te_type = T_OBJECT;
+ if (!owner)
+ canvas_addtolist(x);
+ /* post("canvas %x, owner %x", x, owner); */
+
+ if (argc == 5) /* toplevel: x, y, w, h, font */
+ {
+ xloc = atom_getintarg(0, argc, argv);
+ yloc = atom_getintarg(1, argc, argv);
+ width = atom_getintarg(2, argc, argv);
+ height = atom_getintarg(3, argc, argv);
+ font = atom_getintarg(4, argc, argv);
+ }
+ else if (argc == 6) /* subwindow: x, y, w, h, name, vis */
+ {
+ xloc = atom_getintarg(0, argc, argv);
+ yloc = atom_getintarg(1, argc, argv);
+ width = atom_getintarg(2, argc, argv);
+ height = atom_getintarg(3, argc, argv);
+ s = atom_getsymbolarg(4, argc, argv);
+ vis = atom_getintarg(5, argc, argv);
+ }
+ /* (otherwise assume we're being created from the menu.) */
+
+ if (canvas_newdirectory->s_name[0])
+ {
+ static int dollarzero = 1000;
+ t_canvasenvironment *env = x->gl_env =
+ (t_canvasenvironment *)getbytes(sizeof(*x->gl_env));
+ env->ce_dir = canvas_newdirectory;
+ env->ce_argc = canvas_newargc;
+ env->ce_argv = canvas_newargv;
+ env->ce_dollarzero = dollarzero++;
+ canvas_newdirectory = &s_;
+ canvas_newargc = 0;
+ canvas_newargv = 0;
+ }
+ else x->gl_env = 0;
+
+ x->gl_x1 = 0;
+ x->gl_y1 = 0;
+ x->gl_x2 = 1;
+ x->gl_y2 = 1;
+ canvas_setbounds(x, xloc, yloc, xloc + width, yloc + height);
+ x->gl_owner = owner;
+ x->gl_name = (*s->s_name ? s :
+ (canvas_newfilename ? canvas_newfilename : gensym("Pd")));
+ if (strcmp(x->gl_name->s_name, "Pd"))
+ pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name));
+ x->gl_loading = 1;
+ x->gl_willvis = vis;
+ x->gl_edit = !strncmp(x->gl_name->s_name, "Untitled", 8);
+ x->gl_font = sys_nearestfontsize(font);
+ pd_pushsym(&x->gl_pd);
+ return(x);
+}
+
+void canvas_setgraph(t_glist *x, int flag);
+
+static void canvas_coords(t_glist *x, t_symbol *s, int argc, t_atom *argv)
+{
+ x->gl_x1 = atom_getfloatarg(0, argc, argv);
+ x->gl_y1 = atom_getfloatarg(1, argc, argv);
+ x->gl_x2 = atom_getfloatarg(2, argc, argv);
+ x->gl_y2 = atom_getfloatarg(3, argc, argv);
+ x->gl_pixwidth = atom_getintarg(4, argc, argv);
+ x->gl_pixheight = atom_getintarg(5, argc, argv);
+ canvas_setgraph(x, atom_getintarg(6, argc, argv));
+}
+
+ /* make a new glist and add it to this glist. It will appear as
+ a "graph", not a text object. */
+t_glist *glist_addglist(t_glist *g, t_symbol *sym,
+ float x1, float y1, float x2, float y2,
+ float px1, float py1, float px2, float py2)
+{
+ static int gcount = 0;
+ int zz;
+ int menu = 0;
+ char *str;
+ t_glist *x = (t_glist *)pd_new(canvas_class);
+ glist_init(x);
+ x->gl_obj.te_type = T_OBJECT;
+ if (!*sym->s_name)
+ {
+ char buf[40];
+ sprintf(buf, "graph%d", ++gcount);
+ sym = gensym(buf);
+ menu = 1;
+ }
+ else if (!strncmp((str = sym->s_name), "graph", 5)
+ && (zz = atoi(str + 5)) > gcount)
+ gcount = zz;
+ /* in 0.34 and earlier, the pixel rectangle and the y bounds were
+ reversed; this would behave the same, except that the dialog window
+ would be confusing. The "correct" way is to have "py1" be the value
+ that is higher on the screen. */
+ if (py2 < py1)
+ {
+ float zz;
+ zz = y2;
+ y2 = y1;
+ y1 = zz;
+ zz = py2;
+ py2 = py1;
+ py1 = zz;
+ }
+ if (x1 == x2 || y1 == y2)
+ x1 = 0, x2 = 100, y1 = 1, y2 = -1;
+ if (px1 >= px2 || py1 >= py2)
+ px1 = 100, py1 = 20, px2 = 100 + GLIST_DEFGRAPHWIDTH,
+ py2 = 20 + GLIST_DEFGRAPHHEIGHT;
+ x->gl_name = sym;
+ x->gl_x1 = x1;
+ x->gl_x2 = x2;
+ x->gl_y1 = y1;
+ x->gl_y2 = y2;
+ x->gl_obj.te_xpix = px1;
+ x->gl_obj.te_ypix = py1;
+ x->gl_pixwidth = px2 - px1;
+ x->gl_pixheight = py2 - py1;
+ x->gl_font = (canvas_getcurrent() ?
+ canvas_getcurrent()->gl_font : sys_defaultfont);
+ x->gl_screenx1 = x->gl_screeny1 = 0;
+ x->gl_screenx2 = 450;
+ x->gl_screeny2 = 300;
+ if (strcmp(x->gl_name->s_name, "Pd"))
+ pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name));
+ x->gl_owner = g;
+ x->gl_stretch = 1;
+ x->gl_isgraph = 1;
+ x->gl_obj.te_binbuf = binbuf_new();
+ binbuf_addv(x->gl_obj.te_binbuf, "s", gensym("graph"));
+ if (!menu)
+ pd_pushsym(&x->gl_pd);
+ glist_add(g, &x->gl_gobj);
+ if (glist_isvisible(g))
+ canvas_create_editor(x, 1);
+ return (x);
+}
+
+ /* call glist_addglist from a Pd message */
+void glist_glist(t_glist *g, t_symbol *s, int argc, t_atom *argv)
+{
+ t_symbol *sym = atom_getsymbolarg(0, argc, argv);
+ float x1 = atom_getfloatarg(1, argc, argv);
+ float y1 = atom_getfloatarg(2, argc, argv);
+ float x2 = atom_getfloatarg(3, argc, argv);
+ float y2 = atom_getfloatarg(4, argc, argv);
+ float px1 = atom_getfloatarg(5, argc, argv);
+ float py1 = atom_getfloatarg(6, argc, argv);
+ float px2 = atom_getfloatarg(7, argc, argv);
+ float py2 = atom_getfloatarg(8, argc, argv);
+ glist_addglist(g, sym, x1, y1, x2, y2, px1, py1, px2, py2);
+}
+
+ /* return true if the glist should appear as a graph on parent;
+ otherwise it appears as a text box. */
+int glist_isgraph(t_glist *x)
+{
+ return (x->gl_isgraph);
+}
+
+ /* This is sent from the GUI to inform a toplevel that its window has been
+ moved or resized. */
+static void canvas_setbounds(t_canvas *x, int x1, int y1, int x2, int y2)
+{
+ x->gl_screenx1 = x1;
+ x->gl_screeny1 = y1;
+ x->gl_screenx2 = x2;
+ x->gl_screeny2 = y2;
+ if (!glist_isgraph(x) && (x->gl_y2 < x->gl_y1))
+ {
+ /* if it's flipped so that y grows upward,
+ fix so that zero is bottom edge and redraw. This is
+ only appropriate if we're a regular "text" object on the
+ parent. */
+ float diff = x->gl_y1 - x->gl_y2;
+ x->gl_y1 = x->gl_screeny2 * diff;
+ x->gl_y2 = x->gl_y1 - diff;
+ canvas_redraw(x);
+ }
+}
+
+t_symbol *canvas_makebindsym(t_symbol *s)
+{
+ char buf[MAXPDSTRING];
+ strcpy(buf, "pd-");
+ strcat(buf, s->s_name);
+ return (gensym(buf));
+}
+
+void canvas_reflecttitle(t_canvas *x)
+{
+ char namebuf[MAXPDSTRING];
+ t_canvasenvironment *env = canvas_getenv(x);
+ if (env->ce_argc)
+ {
+ int i;
+ strcpy(namebuf, " (");
+ for (i = 0; i < env->ce_argc; i++)
+ {
+ if (strlen(namebuf) > MAXPDSTRING/2 - 5)
+ break;
+ if (i != 0)
+ strcat(namebuf, " ");
+ atom_string(&env->ce_argv[i], namebuf + strlen(namebuf),
+ MAXPDSTRING/2);
+ }
+ strcat(namebuf, ")");
+ }
+ else namebuf[0] = 0;
+ sys_vgui("wm title .x%x {%s%c%s - %s}\n",
+ x, x->gl_name->s_name, (x->gl_dirty? '*' : ' '), namebuf,
+ canvas_getdir(x)->s_name);
+}
+
+void canvas_dirty(t_canvas *x, t_int n)
+{
+ t_canvas *x2 = canvas_getrootfor(x);
+ if ((unsigned)n != x2->gl_dirty)
+ {
+ x2->gl_dirty = n;
+ canvas_reflecttitle(x2);
+ }
+}
+
+extern t_gobj *canvas_selectme; /* HACK */
+
+ /* the window becomes "mapped" (visible and not miniaturized) or
+ "unmapped" (either miniaturized or just plain gone.) This should be
+ called from the GUI after the fact to "notify" us that we're mapped. */
+void canvas_map(t_canvas *x, t_floatarg f)
+{
+ int flag = (f != 0);
+ t_gobj *y;
+ if (flag)
+ {
+ if (!glist_isvisible(x))
+ {
+ t_selection *sel;
+ if (!x->gl_havewindow)
+ {
+ bug("canvas_map");
+ canvas_vis(x, 1);
+ }
+ for (y = x->gl_list; y; y = y->g_next)
+ gobj_vis(y, x, 1);
+ for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next)
+ gobj_select(sel->sel_what, x, 1);
+ x->gl_mapped = 1;
+ if (canvas_selectme)
+ {
+ glist_noselect(x);
+ glist_select(x, canvas_selectme);
+ canvas_selectme = 0;
+ }
+ canvas_drawlines(x);
+ }
+ }
+ else
+ {
+ if (glist_isvisible(x))
+ {
+ for (y = x->gl_list; y; y = y->g_next)
+ gobj_vis(y, x, 0);
+ x->gl_mapped = 0;
+ }
+ }
+}
+
+void canvas_redraw(t_canvas *x)
+{
+ if (glist_isvisible(x))
+ {
+ canvas_map(x, 0);
+ canvas_map(x, 1);
+ }
+}
+
+/* ---- editors -- perhaps this and "vis" should go to g_editor.c ------- */
+
+static t_editor *editor_new(t_glist *owner)
+{
+ char buf[40];
+ t_editor *x = (t_editor *)getbytes(sizeof(*x));
+ x->e_connectbuf = binbuf_new();
+ x->e_deleted = binbuf_new();
+ x->e_glist = owner;
+ sprintf(buf, ".x%x", (t_int)owner);
+ x->e_guiconnect = guiconnect_new(&owner->gl_pd, gensym(buf));
+ return (x);
+}
+
+static void editor_free(t_editor *x, t_glist *y)
+{
+ glist_noselect(y);
+ guiconnect_notarget(x->e_guiconnect, 1000);
+ binbuf_free(x->e_connectbuf);
+ binbuf_free(x->e_deleted);
+ freebytes((void *)x, sizeof(*x));
+}
+
+ /* recursively create or destroy all editors of a glist and its
+ sub-glists, as long as they aren't toplevels. */
+void canvas_create_editor(t_glist *x, int createit)
+{
+ t_gobj *y;
+ if (createit)
+ {
+ if (x->gl_editor)
+ bug("canvas_create_editor");
+ else x->gl_editor = editor_new(x);
+ }
+ else
+ {
+ if (!x->gl_editor)
+ bug("canvas_create_editor");
+ else editor_free(x->gl_editor, x);
+ x->gl_editor = 0;
+ }
+ for (y = x->gl_list; y; y = y->g_next)
+ if (pd_class(&y->g_pd) == canvas_class &&
+ ((t_canvas *)y)->gl_isgraph)
+ canvas_create_editor((t_canvas *)y, createit);
+}
+
+ /* we call this when we want the window to become visible, mapped, and
+ in front of all windows; or with "f" zero, when we want to get rid of
+ the window. */
+void canvas_vis(t_canvas *x, t_floatarg f)
+{
+ char buf[30];
+ int flag = (f != 0);
+ if (flag)
+ {
+ /* test if we're already visible and toplevel */
+ if (glist_isvisible(x) && !x->gl_isgraph)
+ { /* just put us in front */
+#ifdef NT
+ canvas_vis(x, 0);
+ canvas_vis(x, 1);
+#else
+ sys_vgui("raise .x%x\n", x);
+ sys_vgui("focus .x%x.c\n", x);
+ sys_vgui("wm deiconify .x%x\n", x);
+#endif
+ }
+ else
+ {
+ canvas_create_editor(x, 1);
+ sys_vgui("pdtk_canvas_new .x%x %d %d +%d+%d\n", x,
+ (int)(x->gl_screenx2 - x->gl_screenx1),
+ (int)(x->gl_screeny2 - x->gl_screeny1),
+ (int)(x->gl_screenx1), (int)(x->gl_screeny1)
+ );
+ canvas_reflecttitle(x);
+ /* simulate a mouse up so u_main will calculate scrollbars...
+ ugly! */
+ sys_vgui("pdtk_canvas_mouseup .x%x.c 0 0 0\n", x);
+ x->gl_havewindow = 1;
+ canvas_updatewindowlist();
+ }
+ }
+ else /* make invisible */
+ {
+ int i;
+ t_canvas *x2;
+ if (!x->gl_havewindow)
+ {
+ /* bug workaround -- a graph in a visible patch gets "invised"
+ when the patch is closed, and must lost the editor here. It's
+ probably not the natural place to do this. Other cases like
+ subpatches fall here too but don'd need the editor freed, so
+ we check if it exists. */
+ if (x->gl_editor)
+ canvas_create_editor(x, 0);
+ return;
+ }
+ glist_noselect(x);
+ if (glist_isvisible(x))
+ canvas_map(x, 0);
+ canvas_create_editor(x, 0);
+ sys_vgui("destroy .x%x\n", x);
+ for (i = 1, x2 = x; x2; x2 = x2->gl_next, i++)
+ ;
+ sys_vgui(".mbar.find.menu delete %d\n", i);
+ /* if we're a graph on our parent, and if the parent exists
+ and is visible, show ourselves on parent. */
+ if (glist_isgraph(x) && x->gl_owner)
+ {
+ t_glist *gl2 = x->gl_owner;
+ canvas_create_editor(x, 1);
+ if (glist_isvisible(gl2))
+ gobj_vis(&x->gl_gobj, gl2, 0);
+ x->gl_havewindow = 0;
+ if (glist_isvisible(gl2))
+ gobj_vis(&x->gl_gobj, gl2, 1);
+ }
+ else x->gl_havewindow = 0;
+ canvas_updatewindowlist();
+ }
+}
+
+ /* we call this on a non-toplevel glist to "open" it into its
+ own window. */
+void glist_menu_open(t_glist *x)
+{
+ if (glist_isvisible(x) && !glist_istoplevel(x))
+ {
+ t_glist *gl2 = x->gl_owner;
+ if (!gl2)
+ bug("canvas_vis"); /* shouldn't happen but don't get too upset. */
+ else
+ {
+ /* erase ourself in parent window */
+ gobj_vis(&x->gl_gobj, gl2, 0);
+ /* get rid of our editor (and subeditors) */
+ canvas_create_editor(x, 0);
+ x->gl_havewindow = 1;
+ /* redraw ourself in parent window (blanked out this time) */
+ gobj_vis(&x->gl_gobj, gl2, 1);
+ }
+ }
+ canvas_vis(x, 1);
+}
+
+int glist_isvisible(t_glist *x)
+{
+ return ((!x->gl_loading) && glist_getcanvas(x)->gl_mapped);
+}
+
+int glist_istoplevel(t_glist *x)
+{
+ /* we consider a graph "toplevel" if it has its own window
+ or if it appears as a box in its parent window so that we
+ don't draw the actual contents there. */
+ return (x->gl_havewindow || !x->gl_isgraph);
+}
+
+int glist_getfont(t_glist *x)
+{
+ return (glist_getcanvas(x)->gl_font);
+}
+
+void canvas_free(t_canvas *x)
+{
+ t_gobj *y;
+ int dspstate = canvas_suspend_dsp();
+
+ if (canvas_editing == x)
+ canvas_editing = 0;
+ if (canvas_whichfind == x)
+ canvas_whichfind = 0;
+ glist_noselect(x);
+ while (y = x->gl_list)
+ glist_delete(x, y);
+ canvas_vis(x, 0);
+
+ if (strcmp(x->gl_name->s_name, "Pd"))
+ pd_unbind(&x->gl_pd, canvas_makebindsym(x->gl_name));
+ if (x->gl_env)
+ {
+ freebytes(x->gl_env->ce_argv, x->gl_env->ce_argc * sizeof(t_atom));
+ freebytes(x->gl_env, sizeof(*x->gl_env));
+ }
+ canvas_resume_dsp(dspstate);
+ glist_cleanup(x);
+ gfxstub_deleteforkey(x); /* probably unnecessary */
+ if (!x->gl_owner)
+ canvas_takeofflist(x);
+}
+
+/* ----------------- lines ---------- */
+
+static void canvas_drawlines(t_canvas *x)
+{
+ t_linetraverser t;
+ t_outconnect *oc;
+ {
+ linetraverser_start(&t, x);
+ while (oc = linetraverser_next(&t))
+ sys_vgui(".x%x.c create line %d %d %d %d -tags l%x\n",
+ glist_getcanvas(x),
+ t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2, oc);
+ }
+}
+
+void canvas_fixlinesfor(t_canvas *x, t_text *text)
+{
+ t_linetraverser t;
+ t_outconnect *oc;
+
+ linetraverser_start(&t, x);
+ while (oc = linetraverser_next(&t))
+ {
+ if (t.tr_ob == text || t.tr_ob2 == text)
+ {
+ sys_vgui(".x%x.c coords l%x %d %d %d %d\n",
+ glist_getcanvas(x), oc,
+ t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2);
+ }
+ }
+}
+
+ /* kill all lines for the object */
+void canvas_deletelinesfor(t_canvas *x, t_text *text)
+{
+ t_linetraverser t;
+ t_outconnect *oc;
+ linetraverser_start(&t, x);
+ while (oc = linetraverser_next(&t))
+ {
+ if (t.tr_ob == text || t.tr_ob2 == text)
+ {
+ if (x->gl_editor)
+ {
+ sys_vgui(".x%x.c delete l%x\n",
+ glist_getcanvas(x), oc);
+ }
+ obj_disconnect(t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno);
+ }
+ }
+}
+
+ /* kill all lines for one inlet or outlet */
+void canvas_deletelinesforio(t_canvas *x, t_text *text,
+ t_inlet *inp, t_outlet *outp)
+{
+ t_linetraverser t;
+ t_outconnect *oc;
+ linetraverser_start(&t, x);
+ while (oc = linetraverser_next(&t))
+ {
+ if ((t.tr_ob == text && t.tr_outlet == outp) ||
+ (t.tr_ob2 == text && t.tr_inlet == inp))
+ {
+ if (x->gl_editor)
+ {
+ sys_vgui(".x%x.c delete l%x\n",
+ glist_getcanvas(x), oc);
+ }
+ obj_disconnect(t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno);
+ }
+ }
+}
+
+static void canvas_pop(t_canvas *x, t_floatarg fvis)
+{
+ if (fvis != 0)
+ canvas_vis(x, 1);
+ pd_popsym(&x->gl_pd);
+ canvas_resortinlets(x);
+ canvas_resortoutlets(x);
+ x->gl_loading = 0;
+}
+
+void canvas_objfor(t_glist *gl, t_text *x, int argc, t_atom *argv);
+
+
+void canvas_restore(t_canvas *x, t_symbol *s, int argc, t_atom *argv)
+{ /* IOhannes */
+ t_pd *z;
+ /* this should be unnecessary, but sometimes the canvas's name gets
+ out of sync with the owning box's argument; this fixes that */
+ if (argc > 3)
+ {
+ t_atom *ap=argv+3;
+ if (ap->a_type == A_SYMBOL)
+ {
+ char *buf=ap->a_w.w_symbol->s_name, *bufp;
+ if (*buf == '$' && buf[1] >= '0' && buf[1] <= '9')
+ {
+ for (bufp = buf+2; *bufp; bufp++)
+ if (*bufp < '0' || *bufp > '9')
+ {
+ SETDOLLSYM(ap, gensym(buf+1));
+ goto didit;
+ }
+ SETDOLLAR(ap, atoi(buf+1));
+ didit: ;
+ }
+ }
+
+ if (ap->a_type == A_DOLLSYM)
+ {
+ t_canvasenvironment *e = canvas_getenv(canvas_getcurrent());
+ canvas_rename(x, realizedollsym(ap->a_w.w_symbol,
+ e->ce_argc, e->ce_argv, 1), 0);
+ }
+ else if (ap->a_type == A_SYMBOL)
+ canvas_rename(x, argv[3].a_w.w_symbol, 0);
+ }
+ canvas_pop(x, x->gl_willvis);
+
+ if (!(z = gensym("#X")->s_thing)) error("canvas_restore: out of context");
+ else if (*z != canvas_class) error("canvas_restore: wasn't a canvas");
+ else
+ {
+ t_canvas *x2 = (t_canvas *)z;
+ x->gl_owner = x2;
+ canvas_objfor(x2, &x->gl_obj, argc, argv);
+ }
+}
+
+static void canvas_loadbangabstractions(t_canvas *x)
+{
+ t_gobj *y;
+ t_symbol *s = gensym("loadbang");
+ for (y = x->gl_list; y; y = y->g_next)
+ if (pd_class(&y->g_pd) == canvas_class)
+ {
+ if (canvas_isabstraction((t_canvas *)y))
+ canvas_loadbang((t_canvas *)y);
+ else
+ canvas_loadbangabstractions((t_canvas *)y);
+ }
+}
+
+void canvas_loadbangsubpatches(t_canvas *x)
+{
+ t_gobj *y;
+ t_symbol *s = gensym("loadbang");
+ for (y = x->gl_list; y; y = y->g_next)
+ if (pd_class(&y->g_pd) == canvas_class)
+ {
+ if (!canvas_isabstraction((t_canvas *)y))
+ canvas_loadbangsubpatches((t_canvas *)y);
+ }
+ for (y = x->gl_list; y; y = y->g_next)
+ if ((pd_class(&y->g_pd) != canvas_class) &&
+ zgetfn(&y->g_pd, s))
+ pd_vmess(&y->g_pd, s, "");
+}
+
+void canvas_loadbang(t_canvas *x)
+{
+ t_gobj *y;
+ canvas_loadbangabstractions(x);
+ canvas_loadbangsubpatches(x);
+}
+
+ /* When you ask a canvas its size the result is 2 pixels more than what
+ you gave it to open it; perhaps there's a 1-pixel border all around it
+ or something. Anyway, we just add the 2 pixels back here: */
+
+#ifdef NT
+#define HORIZBORDER 2
+#define VERTBORDER 2
+#else
+#define HORIZBORDER 2
+#define VERTBORDER 2
+#endif
+
+static void canvas_relocate(t_canvas *x, t_symbol *canvasgeom,
+ t_symbol *topgeom)
+{
+ int cxpix, cypix, cw, ch, txpix, typix, tw, th;
+ if (sscanf(canvasgeom->s_name, "%dx%d+%d+%d", &cw, &ch, &cxpix, &cypix)
+ < 4 ||
+ sscanf(topgeom->s_name, "%dx%d+%d+%d", &tw, &th, &txpix, &typix) < 4)
+ bug("canvas_relocate");
+ /* for some reason this is initially called with cw=ch=1 so
+ we just suppress that here. */
+ if (cw > 5 && ch > 5)
+ canvas_setbounds(x, txpix, typix,
+ txpix + cw - HORIZBORDER, typix + ch - VERTBORDER);
+}
+
+void canvas_popabstraction(t_canvas *x)
+{
+ newest = &x->gl_pd;
+ pd_popsym(&x->gl_pd);
+ x->gl_loading = 0;
+ canvas_resortinlets(x);
+ canvas_resortoutlets(x);
+}
+
+void canvas_logerror(t_object *y)
+{
+#ifdef LATER
+ canvas_vis(x, 1);
+ if (!glist_isselected(x, &y->ob_g))
+ glist_select(x, &y->ob_g);
+#endif
+}
+
+/* -------------------------- subcanvases ---------------------- */
+
+static void *subcanvas_new(t_symbol *s)
+{
+ t_atom a[6];
+ t_canvas *x, *z = canvas_getcurrent();
+ if (!*s->s_name) s = gensym("/SUBPATCH/");
+ SETFLOAT(a, 0);
+ SETFLOAT(a+1, GLIST_DEFCANVASYLOC);
+ SETFLOAT(a+2, GLIST_DEFCANVASWIDTH);
+ SETFLOAT(a+3, GLIST_DEFCANVASHEIGHT);
+ SETSYMBOL(a+4, s);
+ SETFLOAT(a+5, 1);
+ x = canvas_new(0, 0, 6, a);
+ x->gl_owner = z;
+ canvas_pop(x, 1);
+ return (x);
+}
+
+static void canvas_click(t_canvas *x,
+ t_floatarg xpos, t_floatarg ypos,
+ t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ canvas_vis(x, 1);
+}
+
+
+ /* find out from subcanvas contents how much to fatten the box */
+void canvas_fattensub(t_canvas *x,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_gobj *y;
+ *xp2 += 50; /* fake for now */
+ *yp2 += 50;
+}
+
+static void canvas_rename_method(t_canvas *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac && av->a_type == A_SYMBOL)
+ canvas_rename(x, av->a_w.w_symbol, 0);
+ else canvas_rename(x, gensym("Pd"), 0);
+}
+
+/* ------------------ table ---------------------------*/
+
+static int tabcount = 0;
+
+static void *table_new(t_symbol *s, t_floatarg f)
+{
+ t_atom a[9];
+ t_glist *gl;
+ t_canvas *x, *z = canvas_getcurrent();
+ if (s == &s_)
+ {
+ char tabname[255];
+ t_symbol *t = gensym("table");
+ sprintf(tabname, "%s%d", t->s_name, tabcount++);
+ s = gensym(tabname);
+ }
+ if (f <= 1)
+ f = 100;
+ SETFLOAT(a, 0);
+ SETFLOAT(a+1, GLIST_DEFCANVASYLOC);
+ SETFLOAT(a+2, 600);
+ SETFLOAT(a+3, 400);
+ SETSYMBOL(a+4, s);
+ SETFLOAT(a+5, 0);
+ x = canvas_new(0, 0, 6, a);
+
+ x->gl_owner = z;
+
+ /* create a graph for the table */
+ gl = glist_addglist((t_glist*)x, &s_, 0, -1, (f > 1 ? f-1 : 1), 1,
+ 50, 350, 550, 50);
+
+ graph_array(gl, s, &s_float, f, 0);
+
+ canvas_pop(x, 0);
+
+ return (x);
+}
+
+ /* return true if the "canvas" object is an abstraction (so we don't
+ save its contents, fogr example.) */
+int canvas_isabstraction(t_canvas *x)
+{
+ return (x->gl_env != 0);
+}
+
+ /* return true if the "canvas" object is a "table". */
+int canvas_istable(t_canvas *x)
+{
+ t_atom *argv = (x->gl_obj.te_binbuf? binbuf_getvec(x->gl_obj.te_binbuf):0);
+ int argc = (x->gl_obj.te_binbuf? binbuf_getnatom(x->gl_obj.te_binbuf) : 0);
+ int istable = (argc && argv[0].a_type == A_SYMBOL &&
+ argv[0].a_w.w_symbol == gensym("table"));
+ return (istable);
+}
+
+ /* return true if the "canvas" object should be treated as a text
+ object. This is true for abstractions but also for "table"s... */
+int canvas_showtext(t_canvas *x)
+{
+ t_atom *argv = (x->gl_obj.te_binbuf? binbuf_getvec(x->gl_obj.te_binbuf):0);
+ int argc = (x->gl_obj.te_binbuf? binbuf_getnatom(x->gl_obj.te_binbuf) : 0);
+ int isarray = (argc && argv[0].a_type == A_SYMBOL &&
+ argv[0].a_w.w_symbol == gensym("graph"));
+ return (!isarray);
+}
+
+static void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp);
+static void canvas_dsp(t_canvas *x, t_signal **sp)
+{
+ canvas_dodsp(x, 0, sp);
+}
+
+ /* get the document containing this canvas */
+t_canvas *canvas_getrootfor(t_canvas *x)
+{
+ if ((!x->gl_owner) || canvas_isabstraction(x))
+ return (x);
+ else return (canvas_getrootfor(x->gl_owner));
+}
+
+/* ------------------------- DSP chain handling ------------------------- */
+
+EXTERN_STRUCT _dspcontext;
+#define t_dspcontext struct _dspcontext
+
+void ugen_start(void);
+void ugen_stop(void);
+
+t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp,
+ int ninlets, int noutlets);
+void ugen_add(t_dspcontext *dc, t_object *x);
+void ugen_connect(t_dspcontext *dc, t_object *x1, int outno,
+ t_object *x2, int inno);
+void ugen_done_graph(t_dspcontext *dc);
+
+int obj_issignaloutlet(t_object *x, int outno);
+int obj_nsiginlets(t_object *x);
+int obj_nsigoutlets(t_object *x);
+
+ /* schedule one canvas for DSP. This is called below for all "root"
+ canvases, but is also called from the "dsp" method for sub-
+ canvases, which are treated almost like any other tilde object. */
+
+static void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp)
+{
+ t_linetraverser t;
+ t_outconnect *oc;
+ t_gobj *y;
+ t_object *ob;
+ t_symbol *dspsym = gensym("dsp");
+ t_dspcontext *dc;
+
+ /* create a new "DSP graph" object to use in sorting this canvas.
+ If we aren't toplevel, there are already other dspcontexts around. */
+
+ dc = ugen_start_graph(toplevel, sp,
+ obj_nsiginlets(&x->gl_obj),
+ obj_nsigoutlets(&x->gl_obj));
+
+ /* find all the "dsp" boxes and add them to the graph */
+
+ for (y = x->gl_list; y; y = y->g_next)
+ if ((ob = pd_checkobject(&y->g_pd)) && zgetfn(&y->g_pd, dspsym))
+ ugen_add(dc, ob);
+
+ /* ... and all dsp interconnections */
+ linetraverser_start(&t, x);
+ while (oc = linetraverser_next(&t))
+ if (obj_issignaloutlet(t.tr_ob, t.tr_outno))
+ ugen_connect(dc, t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno);
+
+ /* finally, sort them and add them to the DSP chain */
+ ugen_done_graph(dc);
+}
+
+ /* this routine starts DSP for all root canvases. */
+static void canvas_start_dsp(void)
+{
+ t_canvas *x;
+ if (canvas_dspstate) ugen_stop();
+ else sys_gui("pdtk_pd_dsp ON\n");
+ ugen_start();
+
+ for (x = canvas_list; x; x = x->gl_next)
+ canvas_dodsp(x, 1, 0);
+
+ canvas_dspstate = 1;
+}
+
+static void canvas_stop_dsp(void)
+{
+ if (canvas_dspstate)
+ {
+ ugen_stop();
+ sys_gui("pdtk_pd_dsp OFF\n");
+ canvas_dspstate = 0;
+ }
+}
+
+ /* DSP can be suspended before, and resumed after, operations which
+ might affect the DSP chain. For example, we suspend before loading and
+ resume afterward, so that DSP doesn't get resorted for every DSP object
+ int the patch. */
+
+int canvas_suspend_dsp(void)
+{
+ int rval = canvas_dspstate;
+ if (rval) canvas_stop_dsp();
+ return (rval);
+}
+
+void canvas_resume_dsp(int oldstate)
+{
+ if (oldstate) canvas_start_dsp();
+}
+
+ /* this is equivalent to suspending and resuming in one step. */
+void canvas_update_dsp(void)
+{
+ if (canvas_dspstate) canvas_start_dsp();
+}
+
+void glob_dsp(void *dummy, t_symbol *s, int argc, t_atom *argv)
+{
+ int newstate;
+ if (argc)
+ {
+ newstate = atom_getintarg(0, argc, argv);
+ if (newstate && !canvas_dspstate)
+ canvas_start_dsp();
+ else if (!newstate && canvas_dspstate)
+ canvas_stop_dsp();
+ }
+ else post("dsp state %d", canvas_dspstate);
+}
+
+ /* LATER replace this with a queueing scheme */
+void glist_redrawitem(t_glist *owner, t_gobj *gobj)
+{
+ if (glist_isvisible(owner))
+ {
+ gobj_vis(gobj, owner, 0);
+ gobj_vis(gobj, owner, 1);
+ }
+}
+
+ /* redraw all "scalars" (do this if a drawing command is changed.)
+ LATER we'll use the "template" information to select which ones we
+ redraw. */
+static void glist_redrawall(t_glist *gl)
+{
+ t_gobj *g;
+ int vis = glist_isvisible(gl);
+ for (g = gl->gl_list; g; g = g->g_next)
+ {
+ t_class *cl;
+ if (vis && g->g_pd == scalar_class)
+ glist_redrawitem(gl, g);
+ else if (g->g_pd == canvas_class)
+ glist_redrawall((t_glist *)g);
+ }
+}
+
+ /* public interface for above */
+void canvas_redrawallfortemplate(t_canvas *template)
+{
+ t_canvas *x;
+ if (!template->gl_imatemplate) return;
+ /* find all root canvases */
+ for (x = canvas_list; x; x = x->gl_next)
+ glist_redrawall(x);
+}
+
+ /* Same as above but just zap them. Call this if a template
+ is changed by adding or removing a field. LATER we'll just
+ modify all the items appropriately. */
+static void glist_zapall(t_glist *gl)
+{
+ t_gobj *g;
+ for (g = gl->gl_list; g; g = g->g_next)
+ {
+ t_class *cl;
+ if (g->g_pd == canvas_class)
+ glist_zapall((t_glist *)g);
+ }
+ /* do we have any scalars? */
+ for (g = gl->gl_list; g; g = g->g_next)
+ {
+ if (g->g_pd == scalar_class)
+ break;
+ }
+ if (!g) return;
+ /* delete all the scalars. This is inefficient if for some reason
+ you've mixed scalars with other items in a single glist. */
+ while (1)
+ {
+ for (g = gl->gl_list; g; g = g->g_next)
+ {
+ if (g->g_pd == scalar_class)
+ {
+ glist_delete(gl, g);
+ break;
+ }
+ }
+ if (!g) break;
+ }
+}
+
+ /* public interface for above */
+void canvas_zapallfortemplate(t_canvas *template)
+{
+ t_canvas *x;
+ if (!template->gl_imatemplate) return;
+ /* find all root canvases */
+ for (x = canvas_list; x; x = x->gl_next)
+ glist_zapall(x);
+}
+
+ /* warn a canvas that some datum has used it as a template. If a
+ canvas has no data associated with it (at load time, for instance)
+ we don't have to search through the world for instances as it changes. */
+void canvas_setusedastemplate(t_canvas *x)
+{
+ x->gl_imatemplate = 1;
+}
+
+/* ------------------------------- setup routine ------------------------ */
+
+ /* why are some of these "glist" and others "canvas"? */
+extern void glist_text(t_glist *x, t_symbol *s, int argc, t_atom *argv);
+extern void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
+extern void canvas_bng(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
+extern void canvas_toggle(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
+extern void canvas_vslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
+extern void canvas_hslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
+extern void canvas_vdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
+extern void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
+extern void canvas_vumeter(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
+extern void canvas_mycnv(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
+extern void canvas_numbox(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
+extern void canvas_msg(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
+extern void canvas_floatatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
+extern void canvas_symbolatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
+extern void glist_scalar(t_glist *canvas, t_symbol *s, int argc, t_atom *argv);
+
+void g_graph_setup(void);
+void g_editor_setup(void);
+void g_readwrite_setup(void);
+
+void g_canvas_setup(void)
+{
+ /* we prevent the user from typing "canvas" in an object box
+ by sending 0 for a creator function. */
+ canvas_class = class_new(gensym("canvas"), 0,
+ (t_method)canvas_free, sizeof(t_canvas), CLASS_NOINLET, 0);
+ /* here is the real creator function, invoked in patch files
+ by sending the "canvas" message to #N, which is bound
+ to pd_camvasmaker. */
+ class_addmethod(pd_canvasmaker, (t_method)canvas_new, gensym("canvas"),
+ A_GIMME, 0);
+ class_addmethod(canvas_class, (t_method)canvas_restore,
+ gensym("restore"), A_GIMME, 0);
+ class_addmethod(canvas_class, (t_method)canvas_coords,
+ gensym("coords"), A_GIMME, 0);
+
+/* -------------------------- objects ----------------------------- */
+ class_addmethod(canvas_class, (t_method)canvas_obj,
+ gensym("obj"), A_GIMME, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_msg,
+ gensym("msg"), A_GIMME, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_floatatom,
+ gensym("floatatom"), A_GIMME, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_symbolatom,
+ gensym("symbolatom"), A_GIMME, A_NULL);
+ class_addmethod(canvas_class, (t_method)glist_text,
+ gensym("text"), A_GIMME, A_NULL);
+ class_addmethod(canvas_class, (t_method)glist_glist, gensym("graph"),
+ A_GIMME, A_NULL);
+ class_addmethod(canvas_class, (t_method)glist_scalar,
+ gensym("scalar"), A_GIMME, A_NULL);
+
+ /* -------------- Thomas Musil's GUI objects ------------ */
+ class_addmethod(canvas_class, (t_method)canvas_bng, gensym("bng"),
+ A_GIMME, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_toggle, gensym("toggle"),
+ A_GIMME, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_vslider, gensym("vslider"),
+ A_GIMME, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_hslider, gensym("hslider"),
+ A_GIMME, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_hdial, gensym("hdial"),
+ A_GIMME, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_vdial, gensym("vdial"),
+ A_GIMME, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_vumeter, gensym("vumeter"),
+ A_GIMME, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_mycnv, gensym("mycnv"),
+ A_GIMME, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_numbox, gensym("numbox"),
+ A_GIMME, A_NULL);
+
+/* ------------------------ gui stuff --------------------------- */
+ class_addmethod(canvas_class, (t_method)canvas_pop, gensym("pop"),
+ A_DEFFLOAT, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_loadbang,
+ gensym("loadbang"), A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_relocate,
+ gensym("relocate"), A_SYMBOL, A_SYMBOL, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_vis,
+ gensym("vis"), A_FLOAT, A_NULL);
+ class_addmethod(canvas_class, (t_method)glist_menu_open,
+ gensym("menu-open"), A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_map,
+ gensym("map"), A_FLOAT, A_NULL);
+
+/* ---------------------- list handling ------------------------ */
+ class_addmethod(canvas_class, (t_method)glist_clear, gensym("clear"),
+ A_NULL);
+
+/* ----- subcanvases, which you get by typing "pd" in a box ---- */
+ class_addcreator((t_newmethod)subcanvas_new, gensym("pd"), A_DEFSYMBOL, 0);
+ class_addcreator((t_newmethod)subcanvas_new, gensym("page"), A_DEFSYMBOL, 0);
+
+ class_addmethod(canvas_class, (t_method)canvas_click,
+ gensym("click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(canvas_class, (t_method)canvas_dsp, gensym("dsp"), 0);
+ class_addmethod(canvas_class, (t_method)canvas_rename_method,
+ gensym("rename"), A_GIMME, 0);
+
+/*---------------------------- tables -- GG ------------------- */
+
+ class_addcreator((t_newmethod)table_new, gensym("table"),
+ A_DEFSYM, A_DEFFLOAT, 0);
+
+/* -------------- setups from other files for canvas_class ---------------- */
+ g_graph_setup();
+ g_editor_setup();
+ g_readwrite_setup();
+
+}
diff --git a/pd/src/g_canvas.h b/pd/src/g_canvas.h
new file mode 100644
index 00000000..fb567ea5
--- /dev/null
+++ b/pd/src/g_canvas.h
@@ -0,0 +1,564 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* this file defines the structure for "glists" and related structures and
+functions. "Glists" and "canvases" and "graphs" used to be different
+structures until being unified in version 0.35.
+
+A glist occupies its own window if the "gl_havewindow" flag is set. Its
+appearance on its "parent" or "owner" (if it has one) is as a graph if
+"gl_isgraph" is set, and otherwise as a text box.
+
+A glist is "root" if it has no owner, i.e., a document window. In this
+case "gl_havewindow" is always set.
+
+We maintain a list of root windows, so that we can traverse the whole
+collection of everything in a Pd process.
+
+If a glist has a window it may still not be "mapped." Miniaturized
+windows aren't mapped, for example, but a window is also not mapped
+immediately upon creation. In either case gl_havewindow is true but
+gl_mapped is false.
+
+Closing a non-root window makes it invisible; closing a root destroys it.
+
+A glist that's just a text object on its parent is always "toplevel." An
+embedded glist can switch back and forth to appear as a toplevel by double-
+clicking on it. Single-clicking a text box makes the toplevel become visible
+and raises the window it's in.
+
+If a glist shows up as a graph on its parent, the graph is blanked while the
+glist has its own window, even if miniaturized.
+
+*/
+
+/* --------------------- geometry ---------------------------- */
+#define IOWIDTH 7 /* width of an inlet/outlet in pixels */
+#define IOMIDDLE ((IOWIDTH-1)/2)
+#define GLIST_DEFGRAPHWIDTH 200
+#define GLIST_DEFGRAPHHEIGHT 140
+/* ----------------------- data ------------------------------- */
+
+typedef struct _updateheader
+{
+ struct _updateheader *upd_next;
+ unsigned int upd_array:1; /* true if array, false if glist */
+ unsigned int upd_queued:1; /* true if we're queued */
+} t_updateheader;
+
+ /* types to support glists grabbing mouse motion or keys from parent */
+typedef void (*t_glistmotionfn)(void *z, t_floatarg dx, t_floatarg dy);
+typedef void (*t_glistkeyfn)(void *z, t_floatarg key);
+
+EXTERN_STRUCT _rtext;
+#define t_rtext struct _rtext
+
+EXTERN_STRUCT _gtemplate;
+#define t_gtemplate struct _gtemplate
+
+EXTERN_STRUCT _guiconnect;
+#define t_guiconnect struct _guiconnect
+
+EXTERN_STRUCT _tscalar;
+#define t_tscalar struct _tscalar
+
+EXTERN_STRUCT _canvasenvironment;
+#define t_canvasenvironment struct _canvasenvironment
+
+EXTERN_STRUCT _linetraverser;
+#define t_linetraverser struct _linetraverser
+
+typedef struct _selection
+{
+ t_gobj *sel_what;
+ struct _selection *sel_next;
+} t_selection;
+
+ /* this structure is instantiated whenever a glist becomes visible. */
+typedef struct _editor
+{
+ t_updateheader e_upd; /* update header structure */
+ t_selection *e_updlist; /* list of objects to update */
+ t_rtext *e_rtext; /* text responder linked list */
+ t_selection *e_selection; /* head of the selection list */
+ t_rtext *e_textedfor; /* the rtext if any that we are editing */
+ t_gobj *e_grab; /* object being "dragged" */
+ t_glistmotionfn e_motionfn; /* ... motion callback */
+ t_glistkeyfn e_keyfn; /* ... keypress callback */
+ t_binbuf *e_connectbuf; /* connections to deleted objects */
+ t_binbuf *e_deleted; /* last stuff we deleted */
+ t_guiconnect *e_guiconnect; /* GUI connection for filtering messages */
+ struct _glist *e_glist; /* glist which owns this */
+ int e_xwas; /* xpos on last mousedown or motion event */
+ int e_ywas; /* ypos, similarly */
+ unsigned int e_onmotion: 3; /* action to take on motion */
+ unsigned int e_lastmoved: 1; /* one if mouse has moved since click */
+ unsigned int e_textdirty: 1; /* one if e_textedfor has changed */
+} t_editor;
+
+#define MA_NONE 0 /* e_onmotion: do nothing on mouse motion */
+#define MA_MOVE 1 /* drag the selection around */
+#define MA_CONNECT 2 /* make a connection */
+#define MA_REGION 3 /* selection region */
+#define MA_PASSOUT 4 /* send on to e_grab */
+#define MA_DRAGTEXT 5 /* drag in text editor to alter selection */
+
+/* editor structure for "garrays". We don't bother to delete and regenerate
+this structure when the "garray" becomes invisible or visible, although we
+could do so if the structure gets big (like the "editor" above.) */
+
+typedef struct _arrayvis
+{
+ t_updateheader av_upd; /* update header structure */
+ t_garray *av_garray; /* owning structure */
+} t_arrayvis;
+
+/* the t_tick structure describes where to draw x and y "ticks" for a glist */
+
+typedef struct _tick /* where to put ticks on x or y axes */
+{
+ float k_point; /* one point to draw a big tick at */
+ float k_inc; /* x or y increment per little tick */
+ int k_lperb; /* little ticks per big; 0 if no ticks to draw */
+} t_tick;
+
+/* the t_glist structure, which describes a list of elements that live on an
+area of a window.
+
+*/
+
+struct _glist
+{
+ t_object gl_obj; /* header in case we're a glist */
+ t_gobj *gl_list; /* the actual data */
+ struct _gstub *gl_stub; /* safe pointer handler */
+ int gl_valid; /* incremented when pointers might be stale */
+ struct _glist *gl_owner; /* parent glist, supercanvas, or 0 if none */
+ int gl_pixwidth; /* width in pixels (on parent, if a graph) */
+ int gl_pixheight;
+ float gl_x1; /* bounding rectangle in our own coordinates */
+ float gl_y1;
+ float gl_x2;
+ float gl_y2;
+ int gl_screenx1; /* screen coordinates when toplevel */
+ int gl_screeny1;
+ int gl_screenx2;
+ int gl_screeny2;
+ t_tick gl_xtick; /* ticks marking X values */
+ int gl_nxlabels; /* number of X coordinate labels */
+ t_symbol **gl_xlabel; /* ... an array to hold them */
+ float gl_xlabely; /* ... and their Y coordinates */
+ t_tick gl_ytick; /* same as above for Y ticks and labels */
+ int gl_nylabels;
+ t_symbol **gl_ylabel;
+ float gl_ylabelx;
+ t_editor *gl_editor; /* editor structure when visible */
+ t_symbol *gl_name; /* symbol bound here */
+ int gl_font; /* nominal font size in points, e.g., 10 */
+ struct _glist *gl_next; /* link in list of toplevels */
+ t_canvasenvironment *gl_env; /* root canvases and abstractions only */
+ unsigned int gl_havewindow:1; /* true if we own a window */
+ unsigned int gl_mapped:1; /* true if, moreover, it's "mapped" */
+ unsigned int gl_dirty:1; /* (root canvas only:) patch has changed */
+ unsigned int gl_loading:1; /* am now loading from file */
+ unsigned int gl_willvis:1; /* make me visible after loading */
+ unsigned int gl_edit:1; /* edit mode */
+ unsigned int gl_imatemplate:1; /* someone needs me as template */
+ unsigned int gl_isdeleting:1; /* we're inside glist_delete -- hack! */
+ unsigned int gl_protect:1; /* don't delete connections on click */
+ unsigned int gl_stretch:1; /* stretch contents on resize */
+ unsigned int gl_isgraph:1; /* show as graph on parent */
+};
+
+#define gl_gobj gl_obj.te_g
+#define gl_pd gl_gobj.g_pd
+
+/* a data structure to describe a field in a pure datum */
+
+#define DT_FLOAT 0
+#define DT_SYMBOL 1
+#define DT_LIST 2
+#define DT_ARRAY 3
+
+typedef struct _dataslot
+{
+ int ds_type;
+ t_symbol *ds_name;
+ t_symbol *ds_arraytemplate; /* filled in for arrays only */
+} t_dataslot;
+
+typedef struct _template
+{
+ t_pd t_pd; /* header */
+ struct _gtemplate *t_list; /* list of "struct"/gtemplate objects */
+ t_symbol *t_sym; /* name */
+ int t_n; /* number of dataslots (fields) */
+ t_dataslot *t_vec; /* array of dataslots */
+} t_template;
+
+struct _array
+{
+ int a_n; /* number of elements */
+ int a_elemsize; /* size in bytes; LATER get this from template */
+ char *a_vec; /* array of elements */
+ t_symbol *a_templatesym; /* template for elements */
+ int a_valid; /* protection against stale pointers into array */
+ t_gpointer a_gp; /* pointer to scalar or array element we're in */
+ t_gstub *a_stub;
+};
+
+ /* structure for traversing all the connections in a glist */
+struct _linetraverser
+{
+ t_canvas *tr_x;
+ t_object *tr_ob;
+ int tr_nout;
+ int tr_outno;
+ t_object *tr_ob2;
+ t_outlet *tr_outlet;
+ t_inlet *tr_inlet;
+ int tr_nin;
+ int tr_inno;
+ int tr_x11, tr_y11, tr_x12, tr_y12;
+ int tr_x21, tr_y21, tr_x22, tr_y22;
+ int tr_lx1, tr_ly1, tr_lx2, tr_ly2;
+ t_outconnect *tr_nextoc;
+ int tr_nextoutno;
+};
+
+/* function types used to define graphical behavior for gobjs, a bit like X
+widgets. We don't use Pd methods because Pd's typechecking can't specify the
+types of pointer arguments. Also it's more convenient this way, since
+every "patchable" object can just get the "text" behaviors. */
+
+ /* Call this to get a gobj's bounding rectangle in pixels */
+typedef void (*t_getrectfn)(t_gobj *x, struct _glist *glist,
+ int *x1, int *y1, int *x2, int *y2);
+ /* and this to displace a gobj: */
+typedef void (*t_displacefn)(t_gobj *x, struct _glist *glist, int dx, int dy);
+ /* change color to show selection: */
+typedef void (*t_selectfn)(t_gobj *x, struct _glist *glist, int state);
+ /* change appearance to show activation/deactivation: */
+typedef void (*t_activatefn)(t_gobj *x, struct _glist *glist, int state);
+ /* warn a gobj it's about to be deleted */
+typedef void (*t_deletefn)(t_gobj *x, struct _glist *glist);
+ /* making visible or invisible */
+typedef void (*t_visfn)(t_gobj *x, struct _glist *glist, int flag);
+ /* field a mouse click (when not in "edit" mode) */
+typedef int (*t_clickfn)(t_gobj *x, struct _glist *glist,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit);
+ /* save to a binbuf */
+typedef void (*t_savefn)(t_gobj *x, t_binbuf *b);
+ /* open properties dialog */
+typedef void (*t_propertiesfn)(t_gobj *x, struct _glist *glist);
+ /* ... and later, resizing; getting/setting font or color... */
+
+struct _widgetbehavior
+{
+ t_getrectfn w_getrectfn;
+ t_displacefn w_displacefn;
+ t_selectfn w_selectfn;
+ t_activatefn w_activatefn;
+ t_deletefn w_deletefn;
+ t_visfn w_visfn;
+ t_clickfn w_clickfn;
+ t_savefn w_savefn;
+ t_propertiesfn w_propertiesfn;
+};
+
+/* -------- behaviors for scalars defined by objects in template --------- */
+/* these are set by "drawing commands" in g_template.c which add appearance to
+scalars, which live in some other window. If the scalar is just included
+in a canvas the "parent" is a misnomer. There is also a text scalar object
+which really does draw the scalar on the parent window; see g_scalar.c. */
+
+/* note how the click function wants the whole scalar, not the "data", so
+doesn't work on array elements... LATER reconsider this */
+
+ /* bounding rectangle: */
+typedef void (*t_parentgetrectfn)(t_gobj *x, struct _glist *glist,
+ t_word *data, t_template *template, float basex, float basey,
+ int *x1, int *y1, int *x2, int *y2);
+ /* displace it */
+typedef void (*t_parentdisplacefn)(t_gobj *x, struct _glist *glist,
+ t_word *data, t_template *template, float basex, float basey,
+ int dx, int dy);
+ /* change color to show selection */
+typedef void (*t_parentselectfn)(t_gobj *x, struct _glist *glist,
+ t_word *data, t_template *template, float basex, float basey,
+ int state);
+ /* change appearance to show activation/deactivation: */
+typedef void (*t_parentactivatefn)(t_gobj *x, struct _glist *glist,
+ t_word *data, t_template *template, float basex, float basey,
+ int state);
+ /* making visible or invisible */
+typedef void (*t_parentvisfn)(t_gobj *x, struct _glist *glist,
+ t_word *data, t_template *template, float basex, float basey,
+ int flag);
+ /* field a mouse click */
+typedef int (*t_parentclickfn)(t_gobj *x, struct _glist *glist,
+ t_scalar *sc, t_template *template, float basex, float basey,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit);
+
+struct _parentwidgetbehavior
+{
+ t_parentgetrectfn w_parentgetrectfn;
+ t_parentdisplacefn w_parentdisplacefn;
+ t_parentselectfn w_parentselectfn;
+ t_parentactivatefn w_parentactivatefn;
+ t_parentvisfn w_parentvisfn;
+ t_parentclickfn w_parentclickfn;
+};
+
+ /* cursor definitions; used as return value for t_parentclickfn */
+#define CURSOR_RUNMODE_NOTHING 0
+#define CURSOR_RUNMODE_CLICKME 1
+#define CURSOR_RUNMODE_THICKEN 2
+#define CURSOR_RUNMODE_ADDPOINT 3
+#define CURSOR_EDITMODE_NOTHING 4
+#define CURSOR_EDITMODE_CONNECT 5
+#define CURSOR_EDITMODE_DISCONNECT 6
+EXTERN void canvas_setcursor(t_glist *x, unsigned int cursornum);
+
+extern t_canvas *canvas_editing; /* last canvas to start text edting */
+extern t_canvas *canvas_whichfind; /* last canvas we did a find in */
+extern t_canvas *canvas_list; /* list of all root canvases */
+extern t_class *vinlet_class, *voutlet_class;
+extern int glist_valid; /* incremented when pointers might be stale */
+
+/* ------------------- functions on any gobj ----------------------------- */
+EXTERN void gobj_getrect(t_gobj *x, t_glist *owner, int *x1, int *y1,
+ int *x2, int *y2);
+EXTERN void gobj_displace(t_gobj *x, t_glist *owner, int dx, int dy);
+EXTERN void gobj_select(t_gobj *x, t_glist *owner, int state);
+EXTERN void gobj_activate(t_gobj *x, t_glist *owner, int state);
+EXTERN void gobj_delete(t_gobj *x, t_glist *owner);
+EXTERN void gobj_vis(t_gobj *x, t_glist *glist, int flag);
+EXTERN int gobj_click(t_gobj *x, struct _glist *glist,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit);
+EXTERN void gobj_save(t_gobj *x, t_binbuf *b);
+EXTERN void gobj_properties(t_gobj *x, struct _glist *glist);
+
+/* -------------------- functions on glists --------------------- */
+EXTERN t_glist *glist_new( void);
+EXTERN void glist_init(t_glist *x);
+EXTERN void glist_add(t_glist *x, t_gobj *g);
+EXTERN void glist_cleanup(t_glist *x);
+EXTERN void glist_free(t_glist *x);
+
+EXTERN void glist_clear(t_glist *x);
+EXTERN t_canvas *glist_getcanvas(t_glist *x);
+EXTERN int glist_isselected(t_glist *x, t_gobj *y);
+EXTERN void glist_select(t_glist *x, t_gobj *y);
+EXTERN void glist_deselect(t_glist *x, t_gobj *y);
+EXTERN void glist_noselect(t_glist *x);
+EXTERN void glist_selectall(t_glist *x);
+EXTERN void glist_delete(t_glist *x, t_gobj *y);
+EXTERN void glist_retext(t_glist *x, t_text *y);
+EXTERN void glist_grab(t_glist *x, t_gobj *y, t_glistmotionfn motionfn,
+ t_glistkeyfn keyfn, int xpos, int ypos);
+EXTERN int glist_isvisible(t_glist *x);
+EXTERN int glist_istoplevel(t_glist *x);
+EXTERN t_glist *glist_findgraph(t_glist *x);
+EXTERN int glist_getfont(t_glist *x);
+EXTERN void glist_sort(t_glist *canvas);
+EXTERN void glist_read(t_glist *x, t_symbol *filename, t_symbol *format);
+EXTERN void glist_mergefile(t_glist *x, t_symbol *filename, t_symbol *format);
+
+EXTERN float glist_pixelstox(t_glist *x, float xpix);
+EXTERN float glist_pixelstoy(t_glist *x, float ypix);
+EXTERN float glist_xtopixels(t_glist *x, float xval);
+EXTERN float glist_ytopixels(t_glist *x, float yval);
+EXTERN float glist_dpixtodx(t_glist *x, float dxpix);
+EXTERN float glist_dpixtody(t_glist *x, float dypix);
+
+EXTERN void glist_redrawitem(t_glist *owner, t_gobj *gobj);
+EXTERN void glist_getnextxy(t_glist *gl, int *xval, int *yval);
+EXTERN void glist_glist(t_glist *g, t_symbol *s, int argc, t_atom *argv);
+EXTERN t_glist *glist_addglist(t_glist *g, t_symbol *sym,
+ float x1, float y1, float x2, float y2,
+ float px1, float py1, float px2, float py2);
+EXTERN void glist_arraydialog(t_glist *parent, t_symbol *name,
+ t_floatarg size, t_floatarg saveit, t_floatarg newgraph);
+EXTERN t_binbuf *glist_writetobinbuf(t_glist *x, int wholething);
+EXTERN int glist_isgraph(t_glist *x);
+EXTERN void glist_redraw(t_glist *x);
+EXTERN void glist_drawiofor(t_glist *glist, t_object *ob, int firsttime,
+ char *tag, int x1, int y1, int x2, int y2);
+EXTERN void glist_eraseiofor(t_glist *glist, t_object *ob, char *tag);
+EXTERN void canvas_create_editor(t_glist *x, int createit);
+
+/* -------------------- functions on texts ------------------------- */
+EXTERN void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize);
+EXTERN void text_drawborder(t_text *x, t_glist *glist, char *tag,
+ int width, int height, int firsttime);
+EXTERN void text_eraseborder(t_text *x, t_glist *glist, char *tag);
+EXTERN int text_xcoord(t_text *x, t_glist *glist);
+EXTERN int text_ycoord(t_text *x, t_glist *glist);
+EXTERN int text_xpix(t_text *x, t_glist *glist);
+EXTERN int text_ypix(t_text *x, t_glist *glist);
+EXTERN int text_shouldvis(t_text *x, t_glist *glist);
+
+/* -------------------- functions on rtexts ------------------------- */
+#define RTEXT_DOWN 1
+#define RTEXT_DRAG 2
+#define RTEXT_DBL 3
+#define RTEXT_SHIFT 4
+
+EXTERN t_rtext *rtext_new(t_glist *glist, t_text *who, t_rtext *next,
+ int sendipup);
+EXTERN t_rtext *rtext_remove(t_rtext *first, t_rtext *x);
+EXTERN t_rtext *glist_findrtext(t_glist *gl, t_text *who);
+EXTERN int rtext_height(t_rtext *x);
+EXTERN void rtext_displace(t_rtext *x, int dx, int dy);
+EXTERN void rtext_select(t_rtext *x, int state);
+EXTERN void rtext_activate(t_rtext *x, int state);
+EXTERN void rtext_free(t_rtext *x);
+EXTERN void rtext_key(t_rtext *x, int n, t_symbol *s);
+EXTERN void rtext_mouse(t_rtext *x, int xval, int yval, int flag);
+EXTERN void rtext_retext(t_rtext *x);
+EXTERN int rtext_width(t_rtext *x);
+EXTERN int rtext_height(t_rtext *x);
+EXTERN char *rtext_gettag(t_rtext *x);
+EXTERN void rtext_gettext(t_rtext *x, char **buf, int *bufsize);
+
+/* -------------------- functions on canvases ------------------------ */
+EXTERN t_class *canvas_class;
+
+EXTERN t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv);
+EXTERN t_symbol *canvas_makebindsym(t_symbol *s);
+EXTERN void canvas_vistext(t_canvas *x, t_text *y);
+EXTERN void canvas_fixlinesfor(t_canvas *x, t_text *text);
+EXTERN void canvas_deletelinesfor(t_canvas *x, t_text *text);
+EXTERN void canvas_stowconnections(t_canvas *x);
+EXTERN void canvas_restoreconnections(t_canvas *x);
+EXTERN void canvas_redraw(t_canvas *x);
+
+EXTERN t_inlet *canvas_addinlet(t_canvas *x, t_pd *who, t_symbol *sym);
+EXTERN void canvas_rminlet(t_canvas *x, t_inlet *ip);
+EXTERN t_outlet *canvas_addoutlet(t_canvas *x, t_pd *who, t_symbol *sym);
+EXTERN void canvas_rmoutlet(t_canvas *x, t_outlet *op);
+EXTERN void canvas_redrawallfortemplate(t_canvas *template);
+EXTERN void canvas_zapallfortemplate(t_canvas *template);
+EXTERN void canvas_setusedastemplate(t_canvas *x);
+EXTERN t_canvas *canvas_getcurrent(void);
+EXTERN void canvas_setcurrent(t_canvas *x);
+EXTERN void canvas_unsetcurrent(t_canvas *x);
+EXTERN t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s);
+EXTERN t_canvas *canvas_getrootfor(t_canvas *x);
+EXTERN void canvas_dirty(t_canvas *x, t_int n);
+EXTERN int canvas_getfont(t_canvas *x);
+typedef int (*t_canvasapply)(t_canvas *x, t_int x1, t_int x2, t_int x3);
+
+EXTERN t_int *canvas_recurapply(t_canvas *x, t_canvasapply *fn,
+ t_int x1, t_int x2, t_int x3);
+
+EXTERN void canvas_resortinlets(t_canvas *x);
+EXTERN void canvas_resortoutlets(t_canvas *x);
+EXTERN void canvas_free(t_canvas *x);
+EXTERN void canvas_updatewindowlist( void);
+EXTERN void canvas_editmode(t_canvas *x, t_floatarg yesplease);
+EXTERN int canvas_isabstraction(t_canvas *x);
+EXTERN int canvas_istable(t_canvas *x);
+EXTERN int canvas_showtext(t_canvas *x);
+EXTERN void canvas_vis(t_canvas *x, t_floatarg f);
+EXTERN t_canvasenvironment *canvas_getenv(t_canvas *x);
+EXTERN void canvas_rename(t_canvas *x, t_symbol *s, t_symbol *dir);
+EXTERN void canvas_loadbang(t_canvas *x);
+EXTERN int canvas_hitbox(t_canvas *x, t_gobj *y, int xpos, int ypos,
+ int *x1p, int *y1p, int *x2p, int *y2p);
+EXTERN int canvas_setdeleting(t_canvas *x, int flag);
+
+/* ---- functions on canvasses as objects --------------------- */
+
+EXTERN void canvas_fattenforscalars(t_canvas *x,
+ int *x1, int *y1, int *x2, int *y2);
+EXTERN void canvas_visforscalars(t_canvas *x, t_glist *glist, int vis);
+EXTERN int canvas_clicksub(t_canvas *x, int xpix, int ypix, int shift,
+ int alt, int dbl, int doit);
+EXTERN t_glist *canvas_getglistonsuper(void);
+
+EXTERN void linetraverser_start(t_linetraverser *t, t_canvas *x);
+EXTERN t_outconnect *linetraverser_next(t_linetraverser *t);
+EXTERN void linetraverser_skipobject(t_linetraverser *t);
+
+/* --------------------- functions on tscalars --------------------- */
+
+EXTERN void tscalar_getrect(t_tscalar *x, t_glist *owner,
+ int *xp1, int *yp1, int *xp2, int *yp2);
+EXTERN void tscalar_vis(t_tscalar *x, t_glist *owner, int flag);
+EXTERN int tscalar_click(t_tscalar *x, int xpix, int ypix, int shift,
+ int alt, int dbl, int doit);
+
+/* --------- functions on garrays (graphical arrays) -------------------- */
+
+EXTERN t_template *garray_template(t_garray *x);
+
+/* -------------------- arrays --------------------- */
+EXTERN t_garray *graph_array(t_glist *gl, t_symbol *s, t_symbol *template,
+ t_floatarg f, t_floatarg saveit);
+EXTERN t_array *array_new(t_symbol *templatesym, t_gpointer *parent);
+EXTERN void array_resize(t_array *x, t_template *template, int n);
+EXTERN void array_free(t_array *x);
+
+/* --------------------- gpointers and stubs ---------------- */
+EXTERN t_gstub *gstub_new(t_glist *gl, t_array *a);
+EXTERN void gstub_cutoff(t_gstub *gs);
+EXTERN void gpointer_setglist(t_gpointer *gp, t_glist *glist, t_scalar *x);
+
+/* --------------------- scalars ------------------------- */
+EXTERN void word_init(t_word *wp, t_template *template, t_gpointer *gp);
+EXTERN void word_restore(t_word *wp, t_template *template,
+ int argc, t_atom *argv);
+EXTERN t_scalar *scalar_new(t_glist *owner,
+ t_symbol *templatesym);
+EXTERN void scalar_getbasexy(t_scalar *x, float *basex, float *basey);
+
+/* ------helper routines for "garrays" and "plots" -------------- */
+EXTERN int array_doclick(t_array *array, t_glist *glist, t_gobj *gobj,
+ t_symbol *elemtemplatesym,
+ float linewidth, float xloc, float xinc, float yloc,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit);
+
+EXTERN void array_getcoordinate(t_glist *glist,
+ char *elem, int xonset, int yonset, int wonset, int indx,
+ float basex, float basey, float xinc,
+ float *xp, float *yp, float *wp);
+
+EXTERN int array_getfields(t_symbol *elemtemplatesym,
+ t_canvas **elemtemplatecanvasp,
+ t_template **elemtemplatep, int *elemsizep,
+ int *xonsetp, int *yonsetp, int *wonsetp);
+
+/* --------------------- templates ------------------------- */
+EXTERN t_template *template_new(t_symbol *sym, int argc, t_atom *argv);
+EXTERN void template_free(t_template *x);
+EXTERN int template_match(t_template *x1, t_template *x2);
+EXTERN int template_find_field(t_template *x, t_symbol *name, int *p_onset,
+ int *p_type, t_symbol **p_arraytype);
+EXTERN t_float template_getfloat(t_template *x, t_symbol *fieldname, t_word *wp,
+ int loud);
+EXTERN void template_setfloat(t_template *x, t_symbol *fieldname, t_word *wp,
+ t_float f, int loud);
+EXTERN t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname,
+ t_word *wp, int loud);
+EXTERN void template_setsymbol(t_template *x, t_symbol *fieldname,
+ t_word *wp, t_symbol *s, int loud);
+
+EXTERN t_template *gtemplate_get(t_gtemplate *x);
+EXTERN t_template *template_findbyname(t_symbol *s);
+EXTERN t_canvas *template_findcanvas(t_template *template);
+
+EXTERN t_float template_getfloat(t_template *x, t_symbol *fieldname,
+ t_word *wp, int loud);
+EXTERN void template_setfloat(t_template *x, t_symbol *fieldname,
+ t_word *wp, t_float f, int loud);
+EXTERN t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname,
+ t_word *wp, int loud);
+EXTERN void template_setsymbol(t_template *x, t_symbol *fieldname,
+ t_word *wp, t_symbol *s, int loud);
+
+/* ----------------------- guiconnects, g_guiconnect.c --------- */
+EXTERN t_guiconnect *guiconnect_new(t_pd *who, t_symbol *sym);
+EXTERN void guiconnect_notarget(t_guiconnect *x, double timedelay);
diff --git a/pd/src/g_editor.c b/pd/src/g_editor.c
new file mode 100644
index 00000000..4e6783ff
--- /dev/null
+++ b/pd/src/g_editor.c
@@ -0,0 +1,1658 @@
+/* Copyright (c) 1997-2001 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 <stdlib.h>
+#include <stdio.h>
+#include "m_imp.h"
+#include "g_canvas.h"
+#include <string.h>
+
+void glist_readfrombinbuf(t_glist *x, t_binbuf *b, char *filename,
+ int selectem);
+
+/* ------------------ forward function declarations --------------- */
+static void canvas_doclear(t_canvas *x);
+static void glist_setlastxy(t_glist *gl, int xval, int yval);
+static void glist_donewloadbangs(t_glist *x);
+
+/* ---------------- generic widget behavior ------------------------- */
+
+void gobj_getrect(t_gobj *x, t_glist *glist, int *x1, int *y1,
+ int *x2, int *y2)
+{
+ if (x->g_pd->c_wb && x->g_pd->c_wb->w_getrectfn)
+ (*x->g_pd->c_wb->w_getrectfn)(x, glist, x1, y1, x2, y2);
+}
+
+void gobj_displace(t_gobj *x, t_glist *glist, int dx, int dy)
+{
+ if (x->g_pd->c_wb && x->g_pd->c_wb->w_displacefn)
+ (*x->g_pd->c_wb->w_displacefn)(x, glist, dx, dy);
+}
+
+void gobj_select(t_gobj *x, t_glist *glist, int state)
+{
+ if (x->g_pd->c_wb && x->g_pd->c_wb->w_selectfn)
+ (*x->g_pd->c_wb->w_selectfn)(x, glist, state);
+}
+
+void gobj_activate(t_gobj *x, t_glist *glist, int state)
+{
+ if (x->g_pd->c_wb && x->g_pd->c_wb->w_activatefn)
+ (*x->g_pd->c_wb->w_activatefn)(x, glist, state);
+}
+
+void gobj_delete(t_gobj *x, t_glist *glist)
+{
+ if (x->g_pd->c_wb && x->g_pd->c_wb->w_deletefn)
+ (*x->g_pd->c_wb->w_deletefn)(x, glist);
+}
+
+void gobj_vis(t_gobj *x, struct _glist *glist, int flag)
+{
+ if (x->g_pd->c_wb && x->g_pd->c_wb->w_visfn)
+ (*x->g_pd->c_wb->w_visfn)(x, glist, flag);
+}
+
+int gobj_click(t_gobj *x, struct _glist *glist,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ if (x->g_pd->c_wb && x->g_pd->c_wb->w_clickfn)
+ return ((*x->g_pd->c_wb->w_clickfn)(x,
+ glist, xpix, ypix, shift, alt, dbl, doit));
+ else return (0);
+}
+
+void gobj_save(t_gobj *x, t_binbuf *b)
+{
+ if (x->g_pd->c_wb && x->g_pd->c_wb->w_savefn)
+ (*x->g_pd->c_wb->w_savefn)(x, b);
+}
+
+void gobj_properties(t_gobj *x, struct _glist *glist)
+{
+ if (x->g_pd->c_wb && x->g_pd->c_wb->w_propertiesfn)
+ (*x->g_pd->c_wb->w_propertiesfn)(x, glist);
+}
+
+/* ------------------------ managing the selection ----------------- */
+
+int glist_isselected(t_glist *x, t_gobj *y)
+{
+ if (x->gl_editor)
+ {
+ t_selection *sel;
+ for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next)
+ if (sel->sel_what == y) return (1);
+ }
+ return (0);
+}
+
+ /* call this for unselected objects only */
+void glist_select(t_glist *x, t_gobj *y)
+{
+ if (x->gl_editor)
+ {
+ t_selection *sel = (t_selection *)getbytes(sizeof(*sel));
+ /* LATER #ifdef out the following check */
+ if (glist_isselected(x, y)) bug("glist_select");
+ sel->sel_next = x->gl_editor->e_selection;
+ sel->sel_what = y;
+ x->gl_editor->e_selection = sel;
+ gobj_select(y, x, 1);
+ }
+}
+
+ /* call this for selected objects only */
+void glist_deselect(t_glist *x, t_gobj *y)
+{
+ int fixdsp = 0;
+ static int reenter = 0;
+ if (reenter) return;
+ reenter = 1;
+ if (x->gl_editor)
+ {
+ t_selection *sel, *sel2;
+ t_rtext *z = 0;
+ if (!glist_isselected(x, y)) bug("glist_deselect");
+ if (x->gl_editor->e_textedfor)
+ {
+ t_rtext *fuddy = glist_findrtext(x, (t_text *)y);
+ if (x->gl_editor->e_textedfor == fuddy)
+ {
+ if (x->gl_editor->e_textdirty)
+ {
+ z = fuddy;
+ canvas_stowconnections(glist_getcanvas(x));
+ }
+ gobj_activate(y, x, 0);
+ }
+ if (zgetfn(&y->g_pd, gensym("dsp")))
+ fixdsp = 1;
+ }
+ if ((sel = x->gl_editor->e_selection)->sel_what == y)
+ {
+ x->gl_editor->e_selection = x->gl_editor->e_selection->sel_next;
+ gobj_select(sel->sel_what, x, 0);
+ freebytes(sel, sizeof(*sel));
+ }
+ else
+ {
+ for (sel = x->gl_editor->e_selection; sel2 = sel->sel_next;
+ sel = sel2)
+ {
+ if (sel2->sel_what == y)
+ {
+ sel->sel_next = sel2->sel_next;
+ gobj_select(sel2->sel_what, x, 0);
+ freebytes(sel2, sizeof(*sel2));
+ break;
+ }
+ }
+ }
+ if (z)
+ {
+ char *buf;
+ int bufsize;
+
+ rtext_gettext(z, &buf, &bufsize);
+ text_setto((t_text *)y, x, buf, bufsize);
+ canvas_fixlinesfor(glist_getcanvas(x), (t_text *)y);
+ x->gl_editor->e_textedfor = 0;
+ }
+ if (fixdsp)
+ canvas_update_dsp();
+ }
+ reenter = 0;
+}
+
+void glist_noselect(t_glist *x)
+{
+ if (x->gl_editor) while (x->gl_editor->e_selection)
+ glist_deselect(x, x->gl_editor->e_selection->sel_what);
+}
+
+void glist_selectall(t_glist *x)
+{
+ if (x->gl_editor)
+ {
+ glist_noselect(x);
+ if (x->gl_list)
+ {
+ t_selection *sel = (t_selection *)getbytes(sizeof(*sel));
+ t_gobj *y = x->gl_list;
+ x->gl_editor->e_selection = sel;
+ sel->sel_what = y;
+ gobj_select(y, x, 1);
+ while (y = y->g_next)
+ {
+ t_selection *sel2 = (t_selection *)getbytes(sizeof(*sel2));
+ sel->sel_next = sel2;
+ sel = sel2;
+ sel->sel_what = y;
+ gobj_select(y, x, 1);
+ }
+ sel->sel_next = 0;
+ }
+ }
+}
+
+
+/* ------------------------ event handling ------------------------ */
+
+#define CURSOR_RUNMODE_NOTHING 0
+#define CURSOR_RUNMODE_CLICKME 1
+#define CURSOR_RUNMODE_THICKEN 2
+#define CURSOR_RUNMODE_ADDPOINT 3
+#define CURSOR_EDITMODE_NOTHING 4
+#define CURSOR_EDITMODE_CONNECT 5
+#define CURSOR_EDITMODE_DISCONNECT 6
+
+static char *cursorlist[] = {
+#ifdef NT
+ "right_ptr", /* CURSOR_RUNMODE_NOTHING */
+#else
+ "left_ptr", /* CURSOR_RUNMODE_NOTHING */
+#endif
+ "arrow", /* CURSOR_RUNMODE_CLICKME */
+ "sb_v_double_arrow", /* CURSOR_RUNMODE_THICKEN */
+ "plus", /* CURSOR_RUNMODE_ADDPOINT */
+ "hand2", /* CURSOR_EDITMODE_NOTHING */
+ "circle", /* CURSOR_EDITMODE_CONNECT */
+ "X_cursor" /* CURSOR_EDITMODE_DISCONNECT */
+};
+
+void canvas_setcursor(t_canvas *x, unsigned int cursornum)
+{
+ static t_canvas *xwas;
+ static unsigned int cursorwas;
+ if (cursornum >= sizeof(cursorlist)/sizeof *cursorlist)
+ {
+ bug("canvas_setcursor");
+ return;
+ }
+ if (xwas != x || cursorwas != cursornum)
+ {
+ sys_vgui(".x%x configure -cursor %s\n", x, cursorlist[cursornum]);
+ xwas = x;
+ cursorwas = cursornum;
+ }
+}
+
+ /* check if a point lies in a gobj. */
+int canvas_hitbox(t_canvas *x, t_gobj *y, int xpos, int ypos,
+ int *x1p, int *y1p, int *x2p, int *y2p)
+{
+ int x1, y1, x2, y2;
+ t_text *ob;
+ if ((ob = pd_checkobject(&y->g_pd)) &&
+ !text_shouldvis(ob, x))
+ return (0);
+ gobj_getrect(y, x, &x1, &y1, &x2, &y2);
+ if (xpos >= x1 && xpos <= x2 && ypos >= y1 && ypos <= y2)
+ {
+ *x1p = x1;
+ *y1p = y1;
+ *x2p = x2;
+ *y2p = y2;
+ return (1);
+ }
+ else return (0);
+}
+
+ /* find the last gobj, if any, containing the point. */
+static t_gobj *canvas_findhitbox(t_canvas *x, int xpos, int ypos,
+ int *x1p, int *y1p, int *x2p, int *y2p)
+{
+ t_gobj *y, *rval = 0;
+ for (y = x->gl_list; y; y = y->g_next)
+ {
+ if (canvas_hitbox(x, y, xpos, ypos, x1p, y1p, x2p, y2p))
+ rval = y;
+ }
+ return (rval);
+}
+
+ /* right-clicking on a canvas object pops up a menu. */
+static void canvas_rightclick(t_canvas *x, int xpos, int ypos, t_gobj *y)
+{
+ int canprop, canopen;
+ canprop = (!y || (y && y->g_pd->c_wb && y->g_pd->c_wb->w_propertiesfn));
+ canopen = (y && zgetfn(&y->g_pd, gensym("menu-open")));
+ sys_vgui("pdtk_canvas_popup .x%x %d %d %d %d\n",
+ x, xpos, ypos, canprop, canopen);
+}
+
+ /* tell GUI to create a properties dialog on the canvas. We tell
+ the user the negative of the "pixel" y scale to make it appear to grow
+ naturally upward, whereas pixels grow downward. */
+static void canvas_properties(t_glist *x)
+{
+ char graphbuf[200];
+ sprintf(graphbuf, "pdtk_canvas_dialog %%s %g %g %g %g \n",
+ glist_dpixtodx(x, 1), -glist_dpixtody(x, 1),
+ (float)glist_isgraph(x), (float)x->gl_stretch);
+ gfxstub_new(&x->gl_pd, x, graphbuf);
+}
+
+
+void canvas_setgraph(t_glist *x, int flag)
+{
+ if (!flag && glist_isgraph(x))
+ {
+ if (x->gl_owner && !x->gl_loading && glist_isvisible(x->gl_owner))
+ gobj_vis(&x->gl_gobj, x->gl_owner, 0);
+ x->gl_isgraph = 0;
+ if (x->gl_owner && !x->gl_loading && glist_isvisible(x->gl_owner))
+ {
+ gobj_vis(&x->gl_gobj, x->gl_owner, 1);
+ canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
+ }
+ }
+ else if (flag && !glist_isgraph(x))
+ {
+ if (x->gl_pixwidth <= 0)
+ x->gl_pixwidth = GLIST_DEFGRAPHWIDTH;
+
+ if (x->gl_pixheight <= 0)
+ x->gl_pixheight = GLIST_DEFGRAPHHEIGHT;
+
+ if (x->gl_owner && !x->gl_loading && glist_isvisible(x->gl_owner))
+ gobj_vis(&x->gl_gobj, x->gl_owner, 0);
+ x->gl_isgraph = 1;
+ /* if (x->gl_owner && glist_isvisible(x->gl_owner))
+ canvas_vis(x, 1); */
+ if (x->gl_loading && x->gl_owner && glist_isvisible(x->gl_owner))
+ canvas_create_editor(x, 1);
+ if (x->gl_owner && !x->gl_loading && glist_isvisible(x->gl_owner))
+ {
+ gobj_vis(&x->gl_gobj, x->gl_owner, 1);
+ canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
+ }
+ }
+}
+
+ /* called from the gui when "OK" is selected on the canvas properties
+ dialog. Again we negate "y" scale. */
+static void canvas_donecanvasdialog(t_glist *x, t_floatarg xperpix,
+ t_floatarg yperpix, t_floatarg fgraphme)
+{
+ int graphme = (fgraphme != 0), redraw = 0;
+ yperpix = -yperpix;
+ if (xperpix == 0)
+ xperpix = 1;
+ if (yperpix == 0)
+ yperpix = 1;
+ canvas_setgraph(x, graphme);
+ if (!x->gl_isgraph && (xperpix != glist_dpixtodx(x, 1)))
+ {
+ if (xperpix > 0)
+ {
+ x->gl_x1 = 0;
+ x->gl_x2 = xperpix;
+ }
+ else
+ {
+ x->gl_x1 = -xperpix * (x->gl_screenx2 - x->gl_screenx1);
+ x->gl_x2 = x->gl_x1 + xperpix;
+ }
+ redraw = 1;
+ }
+ if (!x->gl_isgraph && (yperpix != glist_dpixtody(x, 1)))
+ {
+ if (yperpix > 0)
+ {
+ x->gl_y1 = 0;
+ x->gl_y2 = yperpix;
+ }
+ else
+ {
+ x->gl_y1 = -yperpix * (x->gl_screeny2 - x->gl_screeny1);
+ x->gl_y2 = x->gl_y1 + yperpix;
+ }
+ redraw = 1;
+ }
+ if (redraw)
+ canvas_redraw(x);
+}
+
+ /* called from the gui when a popup menu comes back with "properties,"
+ "open," or "help." */
+static void canvas_done_popup(t_canvas *x, float which, float xpos, float ypos)
+{
+ char pathbuf[MAXPDSTRING], namebuf[MAXPDSTRING];
+ t_gobj *y;
+ for (y = x->gl_list; y; y = y->g_next)
+ {
+ int x1, y1, x2, y2;
+ if (canvas_hitbox(x, y, xpos, ypos, &x1, &y1, &x2, &y2))
+ {
+ if (which == 0) /* properties */
+ {
+ if (!y->g_pd->c_wb || !y->g_pd->c_wb->w_propertiesfn)
+ continue;
+ gobj_properties(y, x);
+ return;
+ }
+ else if (which == 1) /* open */
+ {
+ if (!zgetfn(&y->g_pd, gensym("menu-open")))
+ continue;
+ vmess(&y->g_pd, gensym("menu-open"), "");
+ return;
+ }
+ else /* help */
+ {
+ char *s = class_gethelpname(pd_class(&y->g_pd));
+ strcpy(pathbuf, sys_libdir->s_name);
+ strcat(pathbuf, "/doc/5.reference");
+ strcpy(namebuf, s);
+ if (strcmp(namebuf + strlen(namebuf) - 3, ".pd"))
+ strcat(namebuf, ".pd");
+ glob_evalfile(0, gensym(namebuf), gensym(pathbuf));
+ return;
+ }
+ }
+ }
+ if (which == 0)
+ canvas_properties(x);
+ else if (which == 2)
+ {
+ strcpy(pathbuf, sys_libdir->s_name);
+ strcat(pathbuf, "/doc/5.reference/0.INTRO.txt");
+ sys_vgui("menu_opentext %s\n", pathbuf);
+ }
+}
+
+#define NOMOD 0
+#define SHIFTMOD 1
+#define CTRLMOD 2
+#define ALTMOD 4
+#define RIGHTCLICK 8
+
+/* on one-button-mouse machines, you can use double click to
+ mean right click (which gets the popup menu.) Do this for Mac. */
+#ifdef MACOSX
+#define SIMULATERIGHTCLICK
+#endif
+
+#ifdef SIMULATERIGHTCLICK
+static double canvas_upclicktime;
+static int canvas_upx, canvas_upy;
+#define DCLICKINTERVAL 0.25
+#endif
+
+ /* mouse click */
+void canvas_doclick(t_canvas *x, int xpos, int ypos, int which,
+ int mod, int doit)
+{
+ t_gobj *y;
+ int shiftmod, runmode, altmod, rightclick, protectmod;
+ int x1, y1, x2, y2, clickreturned = 0;
+
+ if (!x->gl_editor)
+ {
+ bug("editor");
+ return;
+ }
+
+ shiftmod = (mod & SHIFTMOD);
+ runmode = ((mod & CTRLMOD) || (!x->gl_edit));
+ altmod = (mod & ALTMOD);
+ rightclick = (mod & RIGHTCLICK);
+ protectmod = x->gl_protect;
+
+#ifdef SIMULATERIGHTCLICK
+ if (doit && !runmode && xpos == canvas_upx && ypos == canvas_upy &&
+ sys_getrealtime() - canvas_upclicktime < DCLICKINTERVAL)
+ rightclick = 1;
+#endif
+
+ x->gl_editor->e_lastmoved = 0;
+ if (doit)
+ {
+ x->gl_editor->e_grab = 0;
+ x->gl_editor->e_onmotion = MA_NONE;
+ }
+ /* post("click %d %d %d %d", xpos, ypos, which, mod); */
+
+ if (x->gl_editor->e_onmotion != MA_NONE)
+ return;
+
+ x->gl_editor->e_xwas = xpos;
+ x->gl_editor->e_ywas = ypos;
+
+ if (runmode && !rightclick)
+ {
+ for (y = x->gl_list; y; y = y->g_next)
+ {
+ /* check if the object wants to be clicked */
+ if (canvas_hitbox(x, y, xpos, ypos, &x1, &y1, &x2, &y2)
+ && (clickreturned = gobj_click(y, x, xpos, ypos,
+ shiftmod, altmod, 0, doit)))
+ break;
+ }
+ if (!doit)
+ {
+ if (y)
+ canvas_setcursor(x, clickreturned);
+ else canvas_setcursor(x, CURSOR_RUNMODE_NOTHING);
+ }
+ return;
+ }
+ /* if not a runmode left click, fall here. */
+ if (y = canvas_findhitbox(x, xpos, ypos, &x1, &y1, &x2, &y2))
+ {
+ t_object *ob = pd_checkobject(&y->g_pd);
+ /* check you're in the rectangle */
+ ob = pd_checkobject(&y->g_pd);
+ if (rightclick)
+ canvas_rightclick(x, xpos, ypos, y);
+ else if (shiftmod)
+ {
+ if (doit)
+ {
+ t_rtext *rt;
+ if (ob && (rt = x->gl_editor->e_textedfor) &&
+ rt == glist_findrtext(x, ob))
+ {
+ rtext_mouse(rt, xpos - x1, ypos - y1, RTEXT_SHIFT);
+ x->gl_editor->e_onmotion = MA_DRAGTEXT;
+ x->gl_editor->e_xwas = x1;
+ x->gl_editor->e_ywas = y1;
+ }
+ else
+ {
+ if (glist_isselected(x, y))
+ glist_deselect(x, y);
+ else glist_select(x, y);
+ }
+ }
+ }
+ else
+ {
+ /* look for an outlet */
+ int noutlet;
+ if (ob && (noutlet = obj_noutlets(ob)) && ypos >= y2-4)
+ {
+ int width = x2 - x1;
+ int nout1 = (noutlet > 1 ? noutlet - 1 : 1);
+ int closest = ((xpos-x1) * (nout1) + width/2)/width;
+ int hotspot = x1 +
+ (width - IOWIDTH) * closest / (nout1);
+ if (closest < noutlet &&
+ xpos >= (hotspot-1) && xpos <= hotspot + (IOWIDTH+1))
+ {
+ if (doit)
+ {
+ x->gl_editor->e_onmotion = MA_CONNECT;
+ x->gl_editor->e_xwas = xpos;
+ x->gl_editor->e_ywas = ypos;
+ sys_vgui(
+ ".x%x.c create line %d %d %d %d -tags x\n",
+ x, xpos, ypos, xpos, ypos);
+ }
+ else canvas_setcursor(x, CURSOR_EDITMODE_CONNECT);
+ }
+ else if (doit)
+ goto nooutletafterall;
+ }
+ /* not in an outlet; select and move */
+ else if (doit)
+ {
+ t_rtext *rt;
+ /* check if the box is being text edited */
+ nooutletafterall:
+ if (ob && (rt = x->gl_editor->e_textedfor) &&
+ rt == glist_findrtext(x, ob))
+ {
+ rtext_mouse(rt, xpos - x1, ypos - y1, RTEXT_DOWN);
+ x->gl_editor->e_onmotion = MA_DRAGTEXT;
+ x->gl_editor->e_xwas = x1;
+ x->gl_editor->e_ywas = y1;
+ }
+ else
+ {
+ /* otherwise select and drag to displace */
+ if (!glist_isselected(x, y))
+ {
+ glist_noselect(x);
+ glist_select(x, y);
+ }
+ x->gl_editor->e_onmotion = MA_MOVE;
+ }
+ }
+ else canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
+ }
+ return;
+ }
+ /* if right click doesn't hit any boxes, call rightclick
+ routine anyway */
+ if (rightclick)
+ canvas_rightclick(x, xpos, ypos, 0);
+
+ /* if not an editing action, and if we didn't hit a
+ box, set cursor and return */
+ if (runmode || rightclick)
+ {
+ canvas_setcursor(x, CURSOR_RUNMODE_NOTHING);
+ return;
+ }
+ /* having failed to find a box, we try lines now. */
+ if (!runmode && !altmod && !shiftmod && !protectmod)
+ {
+ t_linetraverser t;
+ t_outconnect *oc;
+ float fx = xpos, fy = ypos;
+ linetraverser_start(&t, glist_getcanvas(x));
+ while (oc = linetraverser_next(&t))
+ {
+ float lx1 = t.tr_lx1, ly1 = t.tr_ly1,
+ lx2 = t.tr_lx2, ly2 = t.tr_ly2;
+ float area = (lx2 - lx1) * (fy - ly1) -
+ (ly2 - ly1) * (fx - lx1);
+ float dsquare = (lx2-lx1) * (lx2-lx1) + (ly2-ly1) * (ly2-ly1);
+ if (area * area >= 50 * dsquare) continue;
+ if ((lx2-lx1) * (fx-lx1) + (ly2-ly1) * (fy-ly1) < 0) continue;
+ if ((lx2-lx1) * (lx2-fx) + (ly2-ly1) * (ly2-fy) < 0) continue;
+ if (doit)
+ {
+ sys_vgui(".x%x.c delete l%x\n",
+ glist_getcanvas(x), oc);
+ obj_disconnect(t.tr_ob, t.tr_outno, t.tr_ob2, t.tr_inno);
+ }
+ else canvas_setcursor(x, CURSOR_EDITMODE_DISCONNECT);
+ return;
+ }
+ }
+ canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
+ if (doit)
+ {
+ if (!shiftmod) glist_noselect(x);
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags x\n",
+ x, xpos, ypos, xpos, ypos);
+ x->gl_editor->e_onmotion = MA_REGION;
+ }
+}
+
+void canvas_mousedown(t_canvas *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg which, t_floatarg mod)
+{
+ canvas_doclick(x, xpos, ypos, which, mod, 1);
+}
+
+static int canvas_isconnected (t_canvas *x, t_text *ob1, int n1,
+ t_text *ob2, int n2)
+{
+ t_linetraverser t;
+ t_outconnect *oc;
+ linetraverser_start(&t, x);
+ while (oc = linetraverser_next(&t))
+ if (t.tr_ob == ob1 && t.tr_outno == n1 &&
+ t.tr_ob2 == ob2 && t.tr_inno == n2)
+ return (1);
+ return (0);
+}
+
+void canvas_doconnect(t_canvas *x, int xpos, int ypos, int which, int doit)
+{
+ int x11, y11, x12, y12;
+ t_gobj *y1;
+ int x21, y21, x22, y22;
+ t_gobj *y2;
+ int xwas = x->gl_editor->e_xwas,
+ ywas = x->gl_editor->e_ywas;
+ if (doit) sys_vgui(".x%x.c delete x\n", x);
+ else sys_vgui(".x%x.c coords x %d %d %d %d\n",
+ x, x->gl_editor->e_xwas,
+ x->gl_editor->e_ywas, xpos, ypos);
+
+ if ((y1 = canvas_findhitbox(x, xwas, ywas, &x11, &y11, &x12, &y12))
+ && (y2 = canvas_findhitbox(x, xpos, ypos, &x21, &y21, &x22, &y22)))
+ {
+ t_object *ob1 = pd_checkobject(&y1->g_pd);
+ t_object *ob2 = pd_checkobject(&y2->g_pd);
+ int noutlet1, ninlet2;
+ if (ob1 && ob2 && ob1 != ob2 &&
+ (noutlet1 = obj_noutlets(ob1))
+ && (ninlet2 = obj_ninlets(ob2)))
+ {
+ int width1 = x12 - x11, closest1, hotspot1;
+ int width2 = x22 - x21, closest2, hotspot2;
+ int lx1, lx2, ly1, ly2;
+ t_outconnect *oc;
+
+ if (noutlet1 > 1)
+ {
+ closest1 = ((xwas-x11) * (noutlet1-1) + width1/2)/width1;
+ hotspot1 = x11 +
+ (width1 - IOWIDTH) * closest1 / (noutlet1-1);
+ }
+ else closest1 = 0, hotspot1 = x11;
+
+ if (ninlet2 > 1)
+ {
+ closest2 = ((xpos-x21) * (ninlet2-1) + width2/2)/width2;
+ hotspot2 = x21 +
+ (width2 - IOWIDTH) * closest2 / (ninlet2-1);
+ }
+ else closest2 = 0, hotspot2 = x21;
+
+ if (closest1 >= noutlet1)
+ closest1 = noutlet1 - 1;
+ if (closest2 >= ninlet2)
+ closest2 = ninlet2 - 1;
+
+ if (canvas_isconnected (x, ob1, closest1, ob2, closest2))
+ {
+ canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
+ return;
+ }
+ if (doit)
+ {
+ oc = obj_connect(ob1, closest1, ob2, closest2);
+ lx1 = x11 + (noutlet1 > 1 ?
+ ((x12-x11-IOWIDTH) * closest1)/(noutlet1-1) : 0)
+ + IOMIDDLE;
+ ly1 = y12;
+ lx2 = x21 + (ninlet2 > 1 ?
+ ((x22-x21-IOWIDTH) * closest2)/(ninlet2-1) : 0)
+ + IOMIDDLE;
+ ly2 = y21;
+ sys_vgui(".x%x.c create line %d %d %d %d -tags l%x\n",
+ glist_getcanvas(x),
+ lx1, ly1, lx2, ly2, oc);
+ }
+ else canvas_setcursor(x, CURSOR_EDITMODE_CONNECT);
+ return;
+ }
+ }
+ canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
+}
+
+void canvas_doregion(t_canvas *x, int xpos, int ypos, int doit)
+{
+ if (doit)
+ {
+ t_gobj *y;
+ int lox, loy, hix, hiy;
+ if (x->gl_editor->e_xwas < xpos)
+ lox = x->gl_editor->e_xwas, hix = xpos;
+ else hix = x->gl_editor->e_xwas, lox = xpos;
+ if (x->gl_editor->e_ywas < ypos)
+ loy = x->gl_editor->e_ywas, hiy = ypos;
+ else hiy = x->gl_editor->e_ywas, loy = ypos;
+ for (y = x->gl_list; y; y = y->g_next)
+ {
+ int x1, y1, x2, y2;
+ gobj_getrect(y, x, &x1, &y1, &x2, &y2);
+ if (hix >= x1 && lox <= x2 && hiy >= y1 && loy <= y2
+ && !glist_isselected(x, y))
+ glist_select(x, y);
+ }
+ sys_vgui(".x%x.c delete x\n", x);
+ x->gl_editor->e_onmotion = 0;
+ }
+ else sys_vgui(".x%x.c coords x %d %d %d %d\n",
+ x, x->gl_editor->e_xwas,
+ x->gl_editor->e_ywas, xpos, ypos);
+}
+
+void canvas_mouseup(t_canvas *x,
+ t_floatarg fxpos, t_floatarg fypos, t_floatarg fwhich)
+{
+ int xpos = fxpos, ypos = fypos, which = fwhich;
+ /* post("mouseup %d %d %d", xpos, ypos, which); */
+ if (!x->gl_editor)
+ {
+ bug("editor");
+ return;
+ }
+#ifdef SIMULATERIGHTCLICK
+ canvas_upclicktime = sys_getrealtime();
+ canvas_upx = xpos;
+ canvas_upy = ypos;
+#endif
+
+ if (x->gl_editor->e_onmotion == MA_CONNECT)
+ canvas_doconnect(x, xpos, ypos, which, 1);
+ else if (x->gl_editor->e_onmotion == MA_REGION)
+ canvas_doregion(x, xpos, ypos, 1);
+ else if (x->gl_editor->e_onmotion == MA_MOVE)
+ {
+ /* after motion, if there's only one item selected, activate it */
+ if (x->gl_editor->e_selection &&
+ !(x->gl_editor->e_selection->sel_next))
+ gobj_activate(x->gl_editor->e_selection->sel_what,
+ x, 1);
+ }
+ else if (x->gl_editor->e_onmotion == MA_PASSOUT)
+ x->gl_editor->e_onmotion = 0;
+ x->gl_editor->e_onmotion = MA_NONE;
+}
+
+ /* this routine is called whenever a key is pressed or released. "x"
+ may be zero if there's no current canvas. The first argument is true or
+ fals for down/up; the second one is either a symbolic key name (e.g.,
+ "Right" or an Ascii key number. */
+void canvas_key(t_canvas *x, t_symbol *s, int ac, t_atom *av)
+{
+ static t_symbol *keynumsym, *keyupsym, *keynamesym;
+ float keynum, fflag;
+ if (ac < 2)
+ return;
+ fflag = (av[0].a_type == A_FLOAT ? av[0].a_w.w_float : 0);
+ keynum = (av[1].a_type == A_FLOAT ? av[1].a_w.w_float : 0);
+ if (keynum == '\\' || keynum == '{' || keynum == '}')
+ {
+ post("%c: dropped", (int)keynum);
+ return;
+ }
+ if (keynum == '\r') keynum = '\n';
+ /* post("key %c", keynum); */
+ if (av[1].a_type == A_SYMBOL &&
+ !strcmp(av[1].a_w.w_symbol->s_name, "Return"))
+ keynum = '\n';
+ if (!keynumsym)
+ {
+ keynumsym = gensym("#key");
+ keyupsym = gensym("#keyup");
+ keynamesym = gensym("#keyname");
+ }
+ if (keynumsym->s_thing && (fflag != 0))
+ pd_float(keynumsym->s_thing, keynum);
+ if (keyupsym->s_thing && (fflag == 0))
+ pd_float(keyupsym->s_thing, keynum);
+ if (keynamesym->s_thing)
+ {
+ t_atom at[2];
+ at[0] = av[0];
+ if (av[1].a_type == A_SYMBOL)
+ at[1] = av[1];
+ else
+ {
+ char buf[3];
+ sprintf(buf, "%c", (int)(av[1].a_w.w_float));
+ SETSYMBOL(at+1, gensym(buf));
+ }
+ pd_list(keynamesym->s_thing, 0, 2, at);
+ }
+ if (x && (fflag != 0))
+ {
+ if (!x->gl_editor)
+ {
+ bug("editor");
+ return;
+ }
+ /* if an object has "grabbed" keys just send them on */
+ if (x->gl_editor->e_grab && (keynum != 0)
+ && x->gl_editor->e_keyfn)
+ (* x->gl_editor->e_keyfn)
+ (x->gl_editor->e_grab, keynum);
+ /* if a text editor is open send it on */
+ else if (x->gl_editor->e_textedfor)
+ {
+ rtext_key(x->gl_editor->e_textedfor,
+ (int)keynum,
+ (av[1].a_type == A_SYMBOL ? av[1].a_w.w_symbol : &s_));
+ if (x->gl_editor->e_textdirty)
+ canvas_dirty(x, 1);
+ }
+ /* otherwise check for backspace or clear and do so */
+ else if (keynum == 8 || keynum == 127)
+ canvas_doclear(x);
+ }
+}
+
+void canvas_motion(t_canvas *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg fmod)
+{
+ /* post("motion %d %d", xpos, ypos); */
+ int mod = fmod;
+ if (!x->gl_editor)
+ {
+ bug("editor");
+ return;
+ }
+ glist_setlastxy(x, xpos, ypos);
+ if (x->gl_editor->e_onmotion == MA_MOVE)
+ {
+ t_selection *y;
+ int resortin = 0, resortout = 0;
+ for (y = x->gl_editor->e_selection; y; y = y->sel_next)
+ {
+ t_class *cl = pd_class(&y->sel_what->g_pd);
+ gobj_displace(y->sel_what, x,
+ xpos - x->gl_editor->e_xwas,
+ ypos - x->gl_editor->e_ywas);
+ if (cl == vinlet_class) resortin = 1;
+ else if (cl == voutlet_class) resortout = 1;
+ }
+ x->gl_editor->e_xwas = xpos;
+ x->gl_editor->e_ywas = ypos;
+ if (resortin) canvas_resortinlets(x);
+ if (resortout) canvas_resortoutlets(x);
+ canvas_dirty(x, 1);
+ }
+ else if (x->gl_editor->e_onmotion == MA_REGION)
+ canvas_doregion(x, xpos, ypos, 0);
+ else if (x->gl_editor->e_onmotion == MA_CONNECT)
+ canvas_doconnect(x, xpos, ypos, 0, 0);
+ else if (x->gl_editor->e_onmotion == MA_PASSOUT)
+ {
+ (*x->gl_editor->e_motionfn)(&x->gl_editor->e_grab->g_pd,
+ xpos - x->gl_editor->e_xwas,
+ ypos - x->gl_editor->e_ywas);
+ x->gl_editor->e_xwas = xpos;
+ x->gl_editor->e_ywas = ypos;
+ }
+ else if (x->gl_editor->e_onmotion == MA_DRAGTEXT)
+ {
+ t_rtext *rt = x->gl_editor->e_textedfor;
+ if (rt)
+ rtext_mouse(rt, xpos - x->gl_editor->e_xwas,
+ ypos - x->gl_editor->e_ywas, RTEXT_DRAG);
+ }
+ else canvas_doclick(x, xpos, ypos, 0, mod, 0);
+
+ x->gl_editor->e_lastmoved = 1;
+}
+
+void canvas_startmotion(t_canvas *x)
+{
+ int xval, yval;
+ if (!x->gl_editor) return;
+ glist_getnextxy(x, &xval, &yval);
+ if (xval == 0 && yval == 0) return;
+ x->gl_editor->e_onmotion = MA_MOVE;
+ x->gl_editor->e_xwas = xval;
+ x->gl_editor->e_ywas = yval;
+}
+
+/* ----------------------------- window stuff ----------------------- */
+
+void canvas_print(t_canvas *x, t_symbol *s)
+{
+ if (*s->s_name) sys_vgui(".x%x.c postscript -file %s\n", x, s->s_name);
+ else sys_vgui(".x%x.c postscript -file x.ps\n", x);
+}
+
+
+#if 0 /* LATER fix this to re-load abstractions when the patch changes.
+ The best way to do this is probably to rewrite "stowconnections"
+ so that it can operate either on the selection as now or on
+ another replacement criterion. Could do the same trick for
+ externs if we wish. */
+ /* recursively check for abstractions to reload as result of a save. */
+static void glist_doreload(t_glist *gl, t_symbol *name, t_symbol *dir)
+{
+ t_gobj *g;
+ for (g = gl->gl_list; g; g = g->g_next)
+ {
+ if (pd_class(&g->g_pd) == canvas_class &&
+ canvas_isabstraction(&g->g_pd) &&
+ ((t_canvas *)g)->gl_name == name &&
+ ((t_canvas *)g)->gl_env->ce_dir == dir)
+ {
+ .....
+ glist_noselect(gl);
+ canvas_vis(glist_getcanvas(gl), 1);
+ canvas_editmode(glist_getcanvas(gl), 1.);
+ glist_select(gl, g);
+ return (1);
+ }
+ else if (pd_class(&g->g_pd) == graph_class)
+ glist_doreload((t_glist *)g, name, dir);
+ else if (pd_class(&g->g_pd) == canvas_class)
+ glist_doreload(&((t_canvas *)g),
+ name, dir);
+ }
+ }
+ return (0);
+}
+
+static void canvas_reload(t_symbol *name, t_symbol *dir)
+{
+ t_canvas *x;
+ /* find all root canvases */
+ for (x = canvas_list; x; x = x->gl_next)
+ glist_doreload(x, name, dir);
+}
+
+#endif /* 0 -- also uncomment call to canvas_reload below */
+
+void canvas_menuclose(t_canvas *x, t_floatarg force)
+{
+ if (x->gl_owner)
+ canvas_vis(x, 0);
+ else if ((force != 0) || (!x->gl_dirty))
+ pd_free(&x->gl_pd);
+ else sys_vgui("pdtk_check {This window has been modified. Close anyway?}\
+ {.x%x menuclose 1;\n}\n", x);
+}
+
+ /* put up a dialog which may call canvas_font back to do the work */
+static void canvas_menufont(t_canvas *x)
+{
+ char buf[80];
+ t_canvas *x2 = canvas_getrootfor(x);
+ gfxstub_deleteforkey(x2);
+ sprintf(buf, "pdtk_canvas_dofont %%s %d\n", x2->gl_font);
+ gfxstub_new(&x2->gl_pd, &x2->gl_pd, buf);
+}
+
+static int canvas_find_index1, canvas_find_index2;
+static t_binbuf *canvas_findbuf;
+int binbuf_match(t_binbuf *inbuf, t_binbuf *searchbuf);
+t_gobj *canvas_selectme; /* HACK */
+
+ /* find an atom or string of atoms */
+static int canvas_dofind(t_canvas *x, int *myindex1p)
+{
+ t_gobj *y;
+ int myindex1 = *myindex1p, myindex2;
+ if (myindex1 >= canvas_find_index1)
+ {
+ for (y = x->gl_list, myindex2 = 0; y;
+ y = y->g_next, myindex2++)
+ {
+ t_object *ob = 0;
+ if (ob = pd_checkobject(&y->g_pd))
+ {
+ if (binbuf_match(ob->ob_binbuf, canvas_findbuf))
+ {
+ if (myindex1 > canvas_find_index1 ||
+ myindex1 == canvas_find_index1 &&
+ myindex2 > canvas_find_index2)
+ {
+ canvas_find_index1 = myindex1;
+ canvas_find_index2 = myindex2;
+ glist_noselect(x);
+ if (glist_isvisible(x))
+ {
+ canvas_vis(x, 1);
+ canvas_editmode(x, 1.);
+ glist_select(x, y);
+ }
+ else
+ {
+ /* LATER fix so we can select it right here.
+ ERight now, HACK it so that canvas_map selects it.
+ We can't select earlier because the rtexts aren't
+ created in time. Should create the rtexts in
+ canvas_vis() but we don't so that yet. */
+
+ canvas_selectme = y;
+ canvas_vis(x, 1);
+ }
+ return (1);
+ }
+ }
+ }
+ }
+ }
+ for (y = x->gl_list, myindex2 = 0; y; y = y->g_next, myindex2++)
+ {
+ if (pd_class(&y->g_pd) == canvas_class)
+ {
+ (*myindex1p)++;
+ if (canvas_dofind((t_canvas *)y, myindex1p))
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static void canvas_find(t_canvas *x, t_symbol *s, int ac, t_atom *av)
+{
+ int myindex1 = 0, i;
+ for (i = 0; i < ac; i++)
+ {
+ if (av[i].a_type == A_SYMBOL)
+ {
+ if (!strcmp(av[i].a_w.w_symbol->s_name, "_semi_"))
+ SETSEMI(&av[i]);
+ else if (!strcmp(av[i].a_w.w_symbol->s_name, "_comma_"))
+ SETCOMMA(&av[i]);
+ }
+ }
+ if (!canvas_findbuf)
+ canvas_findbuf = binbuf_new();
+ binbuf_clear(canvas_findbuf);
+ binbuf_add(canvas_findbuf, ac, av);
+ canvas_find_index1 = 0;
+ canvas_find_index2 = -1;
+ canvas_whichfind = x;
+ if (!canvas_dofind(x, &myindex1))
+ {
+ binbuf_print(canvas_findbuf);
+ post("... couldn't find");
+ }
+}
+
+static void canvas_find_again(t_canvas *x)
+{
+ int myindex1 = 0;
+ if (!canvas_findbuf || !canvas_whichfind)
+ return;
+ if (!canvas_dofind(canvas_whichfind, &myindex1))
+ {
+ binbuf_print(canvas_findbuf);
+ post("... couldn't find");
+ }
+}
+
+static void canvas_find_parent(t_canvas *x)
+{
+ if (x->gl_owner)
+ canvas_vis(glist_getcanvas(x->gl_owner), 1);
+}
+
+static int glist_dofinderror(t_glist *gl, void *error_object)
+{
+ t_gobj *g;
+ for (g = gl->gl_list; g; g = g->g_next)
+ {
+ if ((void *)g == error_object)
+ {
+ /* got it... now show it. */
+ glist_noselect(gl);
+ canvas_vis(glist_getcanvas(gl), 1);
+ canvas_editmode(glist_getcanvas(gl), 1.);
+ /* we can't just select here ala glist_select(gl, g); instead,
+ as in "find", set "selectme" for when "map" function is called. */
+ canvas_selectme = g;
+ return (1);
+ }
+ else if (g->g_pd == canvas_class)
+ {
+ if (glist_dofinderror((t_canvas *)g, error_object))
+ return (1);
+ }
+ }
+ return (0);
+}
+
+void canvas_finderror(void *error_object)
+{
+ t_canvas *x;
+ /* find all root canvases */
+ for (x = canvas_list; x; x = x->gl_next)
+ {
+ if (glist_dofinderror(x, error_object))
+ return;
+ }
+ post("... sorry, I couldn't find the source of that error.");
+}
+
+void canvas_stowconnections(t_canvas *x)
+{
+ t_gobj *selhead = 0, *seltail = 0, *nonhead = 0, *nontail = 0, *y, *y2;
+ t_linetraverser t;
+ t_outconnect *oc;
+ if (!x->gl_editor) return;
+ /* split list to "selected" and "unselected" parts */
+ for (y = x->gl_list; y; y = y2)
+ {
+ y2 = y->g_next;
+ if (glist_isselected(x, y))
+ {
+ if (seltail)
+ {
+ seltail->g_next = y;
+ seltail = y;
+ y->g_next = 0;
+ }
+ else
+ {
+ selhead = seltail = y;
+ seltail->g_next = 0;
+ }
+ }
+ else
+ {
+ if (nontail)
+ {
+ nontail->g_next = y;
+ nontail = y;
+ y->g_next = 0;
+ }
+ else
+ {
+ nonhead = nontail = y;
+ nontail->g_next = 0;
+ }
+ }
+ }
+ /* move the selected part to the end */
+ if (!nonhead) x->gl_list = selhead;
+ else x->gl_list = nonhead, nontail->g_next = selhead;
+
+ /* add connections to binbuf */
+ binbuf_clear(x->gl_editor->e_connectbuf);
+ linetraverser_start(&t, x);
+ while (oc = linetraverser_next(&t))
+ {
+ int srcno = 0, sinkno = 0;
+ int s1 = glist_isselected(x, &t.tr_ob->ob_g);
+ int s2 = glist_isselected(x, &t.tr_ob2->ob_g);
+ if (s1 != s2)
+ {
+ for (y = x->gl_list; y && y != &t.tr_ob->ob_g; y = y->g_next)
+ srcno++;
+ for (y = x->gl_list; y && y != &t.tr_ob2->ob_g; y = y->g_next)
+ sinkno++;
+ binbuf_addv(x->gl_editor->e_connectbuf, "ssiiii;",
+ gensym("#X"), gensym("connect"),
+ srcno, t.tr_outno, sinkno, t.tr_inno);
+ }
+ }
+}
+
+void canvas_restoreconnections(t_canvas *x)
+{
+ pd_bind(&x->gl_pd, gensym("#X"));
+ binbuf_eval(x->gl_editor->e_connectbuf, 0, 0, 0);
+ pd_unbind(&x->gl_pd, gensym("#X"));
+}
+
+
+static t_binbuf *copy_binbuf;
+
+static void canvas_copy(t_canvas *x)
+{
+ t_gobj *y;
+ t_linetraverser t;
+ t_outconnect *oc;
+ if (!x->gl_editor || !x->gl_editor->e_selection)
+ return;
+ binbuf_clear(copy_binbuf);
+ for (y = x->gl_list; y; y = y->g_next)
+ {
+ if (glist_isselected(x, y))
+ gobj_save(y, copy_binbuf);
+ }
+ linetraverser_start(&t, x);
+ while (oc = linetraverser_next(&t))
+ {
+ int srcno = 0, sinkno = 0;
+ if (glist_isselected(x, &t.tr_ob->ob_g)
+ && glist_isselected(x, &t.tr_ob2->ob_g))
+ {
+ for (y = x->gl_list; y && y != &t.tr_ob->ob_g; y = y->g_next)
+ if (glist_isselected(x, y)) srcno++;
+ for (y = x->gl_list; y && y != &t.tr_ob2->ob_g; y = y->g_next)
+ if (glist_isselected(x, y)) sinkno++;
+ binbuf_addv(copy_binbuf, "ssiiii;", gensym("#X"),
+ gensym("connect"), srcno, t.tr_outno, sinkno, t.tr_inno);
+ }
+ }
+}
+
+extern t_pd *newest;
+static void canvas_doclear(t_canvas *x)
+{
+ t_gobj *y, *y2;
+ int dspstate;
+
+ dspstate = canvas_suspend_dsp();
+ /* if text is selected, deselecting it might remake the
+ object. So we deselect it and hunt for a "new" object on
+ the glist to reselect. */
+ if (x->gl_editor->e_textedfor)
+ {
+ newest = 0;
+ glist_noselect(x);
+ if (newest)
+ {
+ for (y = x->gl_list; y; y = y->g_next)
+ if (&y->g_pd == newest) glist_select(x, y);
+ }
+ }
+ while (1) /* this is pretty wierd... should rewrite it */
+ {
+ for (y = x->gl_list; y; y = y2)
+ {
+ y2 = y->g_next;
+ if (glist_isselected(x, y))
+ {
+ glist_delete(x, y);
+#if 0
+ if (y2) post("cut 5 %x %x", y2, y2->g_next);
+ else post("cut 6");
+#endif
+ goto next;
+ }
+ }
+ goto restore;
+ next: ;
+ }
+restore:
+ canvas_resume_dsp(dspstate);
+ canvas_dirty(x, 1);
+}
+
+static void canvas_cut(t_canvas *x)
+{
+ canvas_copy(x);
+ canvas_doclear(x);
+}
+
+static int paste_onset;
+static t_canvas *paste_canvas;
+
+static void glist_donewloadbangs(t_glist *x)
+{
+ if (x->gl_editor)
+ {
+ t_selection *sel;
+ for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next)
+ if (pd_class(&sel->sel_what->g_pd) == canvas_class)
+ canvas_loadbang((t_canvas *)(&sel->sel_what->g_pd));
+ }
+}
+
+static void canvas_paste(t_canvas *x)
+{
+ t_gobj *newgobj, *last, *g2;
+ int dspstate = canvas_suspend_dsp(), nbox, count;
+
+ canvas_editmode(x, 1.);
+ glist_noselect(x);
+ for (g2 = x->gl_list, nbox = 0; g2; g2 = g2->g_next) nbox++;
+
+ paste_onset = nbox;
+ paste_canvas = x;
+
+ pd_bind(&x->gl_pd, gensym("#X"));
+ binbuf_eval(copy_binbuf, 0, 0, 0);
+ pd_unbind(&x->gl_pd, gensym("#X"));
+ for (g2 = x->gl_list, count = 0; g2; g2 = g2->g_next, count++)
+ if (count >= nbox)
+ glist_select(x, g2);
+ paste_canvas = 0;
+ canvas_resume_dsp(dspstate);
+ canvas_dirty(x, 1);
+ glist_donewloadbangs(x);
+}
+
+static void canvas_duplicate(t_canvas *x)
+{
+ if (x->gl_editor->e_onmotion == MA_NONE)
+ {
+ t_selection *y;
+ canvas_copy(x);
+ canvas_paste(x);
+ for (y = x->gl_editor->e_selection; y; y = y->sel_next)
+ gobj_displace(y->sel_what, x,
+ 10, 10);
+ canvas_dirty(x, 1);
+ }
+}
+
+static void canvas_selectall(t_canvas *x)
+{
+ t_gobj *y;
+ if (!x->gl_edit)
+ canvas_editmode(x, 1);
+ for (y = x->gl_list; y; y = y->g_next)
+ {
+ if (!glist_isselected(x, y))
+ glist_select(x, y);
+ }
+}
+
+static void canvas_connect(t_canvas *x, t_floatarg fwhoout, t_floatarg foutno,
+ t_floatarg fwhoin, t_floatarg finno)
+{
+ int whoout = fwhoout, outno = foutno, whoin = fwhoin, inno = finno;
+ t_gobj *src = 0, *sink = 0;
+ t_object *objsrc, *objsink;
+ t_outconnect *oc;
+ int nin = whoin, nout = whoout;
+ if (paste_canvas == x) whoout += paste_onset, whoin += paste_onset;
+ for (src = x->gl_list; whoout; src = src->g_next, whoout--)
+ if (!src->g_next) goto bad; /* bug fix thanks to Hannes */
+ for (sink = x->gl_list; whoin; sink = sink->g_next, whoin--)
+ if (!sink->g_next) goto bad;
+ if (!(objsrc = pd_checkobject(&src->g_pd)) ||
+ !(objsink = pd_checkobject(&sink->g_pd)))
+ goto bad;
+ if (!(oc = obj_connect(objsrc, outno, objsink, inno))) goto bad;
+ if (glist_isvisible(x))
+ {
+ sys_vgui(".x%x.c create line %d %d %d %d -tags l%x\n",
+ glist_getcanvas(x), 0, 0, 0, 0, oc);
+ canvas_fixlinesfor(x, objsrc);
+ }
+ return;
+
+bad:
+ post("%s %d %d %d %d (%s->%s) connection failed",
+ x->gl_name->s_name, nout, outno, nin, inno,
+ (src? class_getname(pd_class(&src->g_pd)) : "???"),
+ (sink? class_getname(pd_class(&sink->g_pd)) : "???"));
+}
+
+#define XTOLERANCE 4
+#define YTOLERANCE 3
+#define NHIST 15
+
+ /* LATER might have to speed this up */
+static void canvas_tidy(t_canvas *x)
+{
+ t_gobj *y, *y2, *y3;
+ int ax1, ay1, ax2, ay2, bx1, by1, bx2, by2;
+ int histogram[NHIST], *ip, i, besthist, bestdist;
+ /* tidy horizontally */
+ for (y = x->gl_list; y; y = y->g_next)
+ {
+ gobj_getrect(y, x, &ax1, &ay1, &ax2, &ay2);
+
+ for (y2 = x->gl_list; y2; y2 = y2->g_next)
+ {
+ gobj_getrect(y2, x, &bx1, &by1, &bx2, &by2);
+ if (by1 <= ay1 + YTOLERANCE && by1 >= ay1 - YTOLERANCE &&
+ bx1 < ax1)
+ goto nothorizhead;
+ }
+
+ for (y2 = x->gl_list; y2; y2 = y2->g_next)
+ {
+ gobj_getrect(y2, x, &bx1, &by1, &bx2, &by2);
+ if (by1 <= ay1 + YTOLERANCE && by1 >= ay1 - YTOLERANCE
+ && by1 != ay1)
+ gobj_displace(y2, x, 0, ay1-by1);
+ }
+ nothorizhead: ;
+ }
+ /* tidy vertically. First guess the user's favorite vertical spacing */
+ for (i = NHIST, ip = histogram; i--; ip++) *ip = 0;
+ for (y = x->gl_list; y; y = y->g_next)
+ {
+ gobj_getrect(y, x, &ax1, &ay1, &ax2, &ay2);
+ for (y2 = x->gl_list; y2; y2 = y2->g_next)
+ {
+ gobj_getrect(y2, x, &bx1, &by1, &bx2, &by2);
+ if (bx1 <= ax1 + XTOLERANCE && bx1 >= ax1 - XTOLERANCE)
+ {
+ int distance = by1-ay2;
+ if (distance >= 0 && distance < NHIST)
+ histogram[distance]++;
+ }
+ }
+ }
+ for (i = 1, besthist = 0, bestdist = 4, ip = histogram + 1;
+ i < (NHIST-1); i++, ip++)
+ {
+ int hit = ip[-1] + 2 * ip[0] + ip[1];
+ if (hit > besthist)
+ {
+ besthist = hit;
+ bestdist = i;
+ }
+ }
+ post("best vertical distance %d", bestdist);
+ for (y = x->gl_list; y; y = y->g_next)
+ {
+ int keep = 1;
+ gobj_getrect(y, x, &ax1, &ay1, &ax2, &ay2);
+ for (y2 = x->gl_list; y2; y2 = y2->g_next)
+ {
+ gobj_getrect(y2, x, &bx1, &by1, &bx2, &by2);
+ if (bx1 <= ax1 + XTOLERANCE && bx1 >= ax1 - XTOLERANCE &&
+ ay1 >= by2 - 10 && ay1 < by2 + NHIST)
+ goto nothead;
+ }
+ while (keep)
+ {
+ keep = 0;
+ for (y2 = x->gl_list; y2; y2 = y2->g_next)
+ {
+ gobj_getrect(y2, x, &bx1, &by1, &bx2, &by2);
+ if (bx1 <= ax1 + XTOLERANCE && bx1 >= ax1 - XTOLERANCE &&
+ by1 > ay1 && by1 < ay2 + NHIST)
+ {
+ int vmove = ay2 + bestdist - by1;
+ gobj_displace(y2, x, ax1-bx1, vmove);
+ ay1 = by1 + vmove;
+ ay2 = by2 + vmove;
+ keep = 1;
+ break;
+ }
+ }
+ }
+ nothead: ;
+ }
+ canvas_dirty(x, 1);
+}
+
+static void canvas_texteditor(t_canvas *x)
+{
+ t_rtext *foo;
+ char *buf;
+ int bufsize;
+ if (foo = x->gl_editor->e_textedfor)
+ rtext_gettext(foo, &buf, &bufsize);
+ else buf = "", bufsize = 0;
+ sys_vgui("pdtk_pd_texteditor {%.*s}\n", bufsize, buf);
+
+}
+
+
+void glob_key(void *dummy, t_symbol *s, int ac, t_atom *av)
+{
+ /* canvas_editing can be zero; canvas_key checks for that */
+ canvas_key(canvas_editing, s, ac, av);
+}
+
+void canvas_editmode(t_canvas *x, t_floatarg fyesplease)
+{
+ int yesplease = fyesplease;
+ if (yesplease && x->gl_edit)
+ return;
+ if (x->gl_edit = !x->gl_edit)
+ canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
+ else
+ {
+ glist_noselect(x);
+ canvas_setcursor(x, CURSOR_RUNMODE_NOTHING);
+ }
+ sys_vgui("pdtk_canvas_editval .x%x %d\n",
+ glist_getcanvas(x), x->gl_edit);
+ if (yesplease) canvas_dirty(x, 1);
+}
+
+static void canvas_protectmode(t_canvas *x, t_floatarg fyesplease)
+{
+ int yesplease = fyesplease;
+
+ if (yesplease && x->gl_protect)
+ return;
+ x->gl_protect = !x->gl_protect;
+ sys_vgui("pdtk_canvas_protectval .x%x %d\n",
+ glist_getcanvas(x), x->gl_protect);
+}
+
+ /* called by canvas_font below */
+static void canvas_dofont(t_canvas *x, t_floatarg font, t_floatarg xresize,
+ t_floatarg yresize)
+{
+ t_gobj *y;
+ x->gl_font = font;
+ if (xresize != 1 || yresize != 1)
+ {
+ for (y = x->gl_list; y; y = y->g_next)
+ {
+ int x1, x2, y1, y2, nx1, ny1;
+ gobj_getrect(y, x, &x1, &y1, &x2, &y2);
+ nx1 = x1 * xresize + 0.5;
+ ny1 = y1 * yresize + 0.5;
+ gobj_displace(y, x, nx1-x1, ny1-y1);
+ }
+ }
+ if (glist_isvisible(x))
+ glist_redraw(x);
+ for (y = x->gl_list; y; y = y->g_next)
+ if (pd_class(&y->g_pd) == canvas_class
+ && !canvas_isabstraction((t_canvas *)y))
+ canvas_dofont((t_canvas *)y, font, xresize, yresize);
+}
+
+ /* canvas_menufont calls up a TK dialog which calls this back */
+static void canvas_font(t_canvas *x, t_floatarg font, t_floatarg resize,
+ t_floatarg whichresize)
+{
+ float realresize, realresx = 1, realresy = 1;
+ t_canvas *x2 = canvas_getrootfor(x);
+ if (!resize) realresize = 1;
+ else
+ {
+ if (resize < 20) resize = 20;
+ if (resize > 500) resize = 500;
+ realresize = resize * 0.01;
+ }
+ if (whichresize != 3) realresx = realresize;
+ if (whichresize != 2) realresy = realresize;
+ canvas_dofont(x2, font, realresx, realresy);
+ sys_defaultfont = font;
+}
+
+static t_glist *canvas_last_glist;
+static int canvas_last_glist_x, canvas_last_glist_y;
+
+void glist_getnextxy(t_glist *gl, int *xpix, int *ypix)
+{
+ if (canvas_last_glist == gl)
+ *xpix = canvas_last_glist_x, *ypix = canvas_last_glist_y;
+ else *xpix = *ypix = 40;
+}
+
+static void glist_setlastxy(t_glist *gl, int xval, int yval)
+{
+ canvas_last_glist = gl;
+ canvas_last_glist_x = xval;
+ canvas_last_glist_y = yval;
+}
+
+
+void g_editor_setup(void)
+{
+/* ------------------------ events ---------------------------------- */
+ class_addmethod(canvas_class, (t_method)canvas_mousedown, gensym("mouse"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_mouseup, gensym("mouseup"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_key, gensym("key"),
+ A_GIMME, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_motion, gensym("motion"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+
+/* ------------------------ menu actions ---------------------------- */
+ class_addmethod(canvas_class, (t_method)canvas_menuclose,
+ gensym("menuclose"), A_DEFFLOAT, 0);
+ class_addmethod(canvas_class, (t_method)canvas_cut,
+ gensym("cut"), A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_copy,
+ gensym("copy"), A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_paste,
+ gensym("paste"), A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_duplicate,
+ gensym("duplicate"), A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_selectall,
+ gensym("selectall"), A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_tidy,
+ gensym("tidy"), A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_texteditor,
+ gensym("texteditor"), A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_editmode,
+ gensym("editmode"), A_DEFFLOAT, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_protectmode,
+ gensym("protectmode"), A_DEFFLOAT, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_print,
+ gensym("print"), A_SYMBOL, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_menufont,
+ gensym("menufont"), A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_font,
+ gensym("font"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_find,
+ gensym("find"), A_GIMME, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_find_again,
+ gensym("findagain"), A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_find_parent,
+ gensym("findparent"), A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_done_popup,
+ gensym("done-popup"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_donecanvasdialog,
+ gensym("donecanvasdialog"), A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(canvas_class, (t_method)glist_arraydialog,
+ gensym("arraydialog"), A_SYMBOL, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+
+/* -------------- connect method used in reading files ------------------ */
+ class_addmethod(canvas_class, (t_method)canvas_connect,
+ gensym("connect"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+
+/* -------------- copy buffer ------------------ */
+ copy_binbuf = binbuf_new();
+}
diff --git a/pd/src/g_graph.c b/pd/src/g_graph.c
new file mode 100644
index 00000000..65a5d056
--- /dev/null
+++ b/pd/src/g_graph.c
@@ -0,0 +1,1119 @@
+/* Copyright (c) 1997-2001 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. */
+
+/* This file deals with the behavior of glists as either "text objects" or
+"graphs" inside another glist. LATER move the inlet/outlet code of g_canvas.c
+to this file... */
+
+#include <stdlib.h>
+#include "m_pd.h"
+#include "t_tk.h"
+#include "g_canvas.h"
+#include <stdio.h>
+#include <string.h>
+
+/* ---------------------- forward definitions ----------------- */
+
+static void graph_vis(t_gobj *gr, t_glist *unused_glist, int vis);
+static void graph_graphrect(t_gobj *z, t_glist *glist,
+ int *xp1, int *yp1, int *xp2, int *yp2);
+static void graph_getrect(t_gobj *z, t_glist *glist,
+ int *xp1, int *yp1, int *xp2, int *yp2);
+
+/* -------------------- maintaining the list -------------------- */
+
+void glist_add(t_glist *x, t_gobj *y)
+{
+ y->g_next = 0;
+ if (!x->gl_list) x->gl_list = y;
+ else
+ {
+ t_gobj *y2;
+ for (y2 = x->gl_list; y2->g_next; y2 = y2->g_next);
+ y2->g_next = y;
+ }
+ if (glist_isvisible(x))
+ gobj_vis(y, x, 1);
+ if (class_isdrawcommand(y->g_pd))
+ canvas_redrawallfortemplate(glist_getcanvas(x));
+}
+
+ /* this is to protect against a hairy problem in which deleting
+ a sub-canvas might delete an inlet on a box, after the box had
+ been invisible-ized, so that we have to protect against redrawing it! */
+int canvas_setdeleting(t_canvas *x, int flag)
+{
+ int ret = x->gl_isdeleting;
+ x->gl_isdeleting = flag;
+ return (ret);
+}
+
+ /* delete an object from a glist and free it */
+void glist_delete(t_glist *x, t_gobj *y)
+{
+ t_gobj *g;
+ t_gotfn chkdsp = zgetfn(&y->g_pd, gensym("dsp"));
+ t_canvas *canvas = glist_getcanvas(x);
+ int drawcommand = class_isdrawcommand(y->g_pd);
+ int wasdeleting;
+
+ wasdeleting = canvas_setdeleting(canvas, 1);
+ /* LATER decide whether all visible glists must have an editor? */
+ if (glist_isvisible(canvas) && x->gl_editor)
+ {
+ if (x->gl_editor->e_grab == y) x->gl_editor->e_grab = 0;
+ if (glist_isselected(x, y)) glist_deselect(x, y);
+
+ /* HACK -- we had phantom outlets not getting erased on the
+ screen because the canvas_setdeleting() mechanism is too
+ crude. LATER carefully set up rules for when the rtexts
+ should exist, so that they stay around until all the
+ steps of becoming invisible are done. In the meantime, just
+ zap the inlets and outlets here... */
+ if (pd_class(&y->g_pd) == canvas_class)
+ {
+ t_glist *gl = (t_glist *)y;
+ if (gl->gl_isgraph)
+ {
+ char tag[80];
+ sprintf(tag, "graph%x", (int)gl);
+ glist_eraseiofor(x, &gl->gl_obj, tag);
+ }
+ else
+ {
+ text_eraseborder(&gl->gl_obj, x,
+ rtext_gettag(glist_findrtext(x, &gl->gl_obj)));
+ }
+ }
+ }
+ gobj_delete(y, x);
+ if (glist_isvisible(canvas)) gobj_vis(y, x, 0);
+ if (x->gl_list == y) x->gl_list = y->g_next;
+ else for (g = x->gl_list; g; g = g->g_next)
+ if (g->g_next == y)
+ {
+ g->g_next = y->g_next;
+ break;
+ }
+ pd_free(&y->g_pd);
+ if (chkdsp) canvas_update_dsp();
+ if (drawcommand) canvas_redrawallfortemplate(canvas);
+ canvas_setdeleting(canvas, wasdeleting);
+ x->gl_valid = ++glist_valid;
+}
+
+ /* remove every object from a glist. Experimental. */
+void glist_clear(t_glist *x)
+{
+ t_gobj *y, *y2;
+ int dspstate = canvas_suspend_dsp();
+ while (y = x->gl_list)
+ glist_delete(x, y);
+ canvas_resume_dsp(dspstate);
+}
+
+void glist_retext(t_glist *glist, t_text *y)
+{
+ t_canvas *c = glist_getcanvas(glist);
+ /* check that we have built rtexts yet. LATER need a better test. */
+ if (glist->gl_editor && glist->gl_editor->e_rtext)
+ {
+ t_rtext *rt = glist_findrtext(glist, y);
+ if (rt)
+ rtext_retext(rt);
+ }
+}
+
+void glist_grab(t_glist *x, t_gobj *y, t_glistmotionfn motionfn,
+ t_glistkeyfn keyfn, int xpos, int ypos)
+{
+ t_glist *x2 = glist_getcanvas(x);
+ x2->gl_editor->e_onmotion = MA_PASSOUT;
+ x2->gl_editor->e_grab = y;
+ x2->gl_editor->e_motionfn = motionfn;
+ x2->gl_editor->e_keyfn = keyfn;
+ x2->gl_editor->e_xwas = xpos;
+ x2->gl_editor->e_ywas = ypos;
+}
+
+t_canvas *glist_getcanvas(t_glist *x)
+{
+ while (x->gl_owner && !x->gl_havewindow && x->gl_isgraph)
+ x = x->gl_owner;
+ return((t_canvas *)x);
+}
+
+static float gobj_getxforsort(t_gobj *g)
+{
+ if (pd_class(&g->g_pd) == scalar_class)
+ {
+ float x1, y1;
+ scalar_getbasexy((t_scalar *)g, &x1, &y1);
+ return(x1);
+ }
+ else return (0);
+}
+
+static t_gobj *glist_merge(t_glist *x, t_gobj *g1, t_gobj *g2)
+{
+ t_gobj *g = 0, *g9 = 0;
+ float f1 = 0, f2 = 0;
+ if (g1)
+ f1 = gobj_getxforsort(g1);
+ if (g2)
+ f2 = gobj_getxforsort(g2);
+ while (1)
+ {
+ if (g1)
+ {
+ if (g2)
+ {
+ if (f1 <= f2)
+ goto put1;
+ else goto put2;
+ }
+ else goto put1;
+ }
+ else if (g2)
+ goto put2;
+ else break;
+ put1:
+ if (g9)
+ g9->g_next = g1, g9 = g1;
+ else g9 = g = g1;
+ if (g1 = g1->g_next)
+ f1 = gobj_getxforsort(g1);
+ g9->g_next = 0;
+ continue;
+ put2:
+ if (g9)
+ g9->g_next = g2, g9 = g2;
+ else g9 = g = g2;
+ if (g2 = g2->g_next)
+ f2 = gobj_getxforsort(g2);
+ g9->g_next = 0;
+ continue;
+ }
+ return (g);
+}
+
+static t_gobj *glist_dosort(t_glist *x,
+ t_gobj *g, int nitems)
+{
+ if (nitems < 2)
+ return (g);
+ else
+ {
+ int n1 = nitems/2, n2 = nitems - n1, i;
+ t_gobj *g2, *g3;
+ for (g2 = g, i = n1-1; i--; g2 = g2->g_next)
+ ;
+ g3 = g2->g_next;
+ g2->g_next = 0;
+ g = glist_dosort(x, g, n1);
+ g3 = glist_dosort(x, g3, n2);
+ return (glist_merge(x, g, g3));
+ }
+}
+
+void glist_sort(t_glist *x)
+{
+ int nitems = 0, foo = 0;
+ float lastx = -1e37;
+ t_gobj *g;
+ for (g = x->gl_list; g; g = g->g_next)
+ {
+ float x1 = gobj_getxforsort(g);
+ if (x1 < lastx)
+ foo = 1;
+ lastx = x1;
+ nitems++;
+ }
+ if (foo)
+ x->gl_list = glist_dosort(x, x->gl_list, nitems);
+}
+
+void glist_cleanup(t_glist *x)
+{
+ freebytes(x->gl_xlabel, x->gl_nxlabels * sizeof(*(x->gl_xlabel)));
+ freebytes(x->gl_ylabel, x->gl_nylabels * sizeof(*(x->gl_ylabel)));
+ gstub_cutoff(x->gl_stub);
+}
+
+void glist_free(t_glist *x)
+{
+ glist_cleanup(x);
+ freebytes(x, sizeof(*x));
+}
+
+/* --------------- inlets and outlets ----------- */
+
+
+t_inlet *canvas_addinlet(t_canvas *x, t_pd *who, t_symbol *s)
+{
+ t_inlet *ip = inlet_new(&x->gl_obj, who, s, 0);
+ if (!x->gl_loading && x->gl_owner && glist_isvisible(x->gl_owner))
+ {
+ gobj_vis(&x->gl_gobj, x->gl_owner, 0);
+ gobj_vis(&x->gl_gobj, x->gl_owner, 1);
+ canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
+ }
+ if (!x->gl_loading) canvas_resortinlets(x);
+ return (ip);
+}
+
+void canvas_deletelinesforio(t_canvas *x, t_text *text,
+ t_inlet *inp, t_outlet *outp);
+
+void canvas_rminlet(t_canvas *x, t_inlet *ip)
+{
+ t_canvas *owner = x->gl_owner;
+ int redraw = (owner && glist_isvisible(owner) && (!owner->gl_isdeleting)
+ && glist_istoplevel(owner));
+
+ if (owner) canvas_deletelinesforio(owner, &x->gl_obj, ip, 0);
+ if (redraw)
+ gobj_vis(&x->gl_gobj, x->gl_owner, 0);
+ inlet_free(ip);
+ if (redraw)
+ {
+ gobj_vis(&x->gl_gobj, x->gl_owner, 1);
+ canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
+ }
+}
+
+extern t_inlet *vinlet_getit(t_pd *x);
+extern void obj_moveinletfirst(t_object *x, t_inlet *i);
+
+void canvas_resortinlets(t_canvas *x)
+{
+ int ninlets = 0, i, j, xmax;
+ t_gobj *y, **vec, **vp, **maxp;
+
+ for (ninlets = 0, y = x->gl_list; y; y = y->g_next)
+ if (pd_class(&y->g_pd) == vinlet_class) ninlets++;
+
+ if (ninlets < 2) return;
+
+ vec = (t_gobj **)getbytes(ninlets * sizeof(*vec));
+
+ for (y = x->gl_list, vp = vec; y; y = y->g_next)
+ if (pd_class(&y->g_pd) == vinlet_class) *vp++ = y;
+
+ for (i = ninlets; i--;)
+ {
+ t_inlet *ip;
+ for (vp = vec, xmax = -0x7fffffff, maxp = 0, j = ninlets;
+ j--; vp++)
+ {
+ int x1, y1, x2, y2;
+ t_gobj *g = *vp;
+ if (!g) continue;
+ gobj_getrect(g, x, &x1, &y1, &x2, &y2);
+ if (x1 > xmax) xmax = x1, maxp = vp;
+ }
+ if (!maxp) break;
+ y = *maxp;
+ *maxp = 0;
+ ip = vinlet_getit(&y->g_pd);
+
+ obj_moveinletfirst(&x->gl_obj, ip);
+ }
+ freebytes(vec, ninlets * sizeof(*vec));
+ if (x->gl_owner && glist_isvisible(x->gl_owner))
+ canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
+}
+
+t_outlet *canvas_addoutlet(t_canvas *x, t_pd *who, t_symbol *s)
+{
+ t_outlet *op = outlet_new(&x->gl_obj, s);
+ if (!x->gl_loading && x->gl_owner && glist_isvisible(x->gl_owner))
+ {
+ gobj_vis(&x->gl_gobj, x->gl_owner, 0);
+ gobj_vis(&x->gl_gobj, x->gl_owner, 1);
+ canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
+ }
+ if (!x->gl_loading) canvas_resortoutlets(x);
+ return (op);
+}
+
+void canvas_rmoutlet(t_canvas *x, t_outlet *op)
+{
+ t_canvas *owner = x->gl_owner;
+ int redraw = (owner && glist_isvisible(owner) && (!owner->gl_isdeleting)
+ && glist_istoplevel(owner));
+
+ if (owner) canvas_deletelinesforio(owner, &x->gl_obj, 0, op);
+ if (redraw)
+ gobj_vis(&x->gl_gobj, x->gl_owner, 0);
+
+ outlet_free(op);
+ if (redraw)
+ {
+ gobj_vis(&x->gl_gobj, x->gl_owner, 1);
+ canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
+ }
+}
+
+extern t_outlet *voutlet_getit(t_pd *x);
+extern void obj_moveoutletfirst(t_object *x, t_outlet *i);
+
+void canvas_resortoutlets(t_canvas *x)
+{
+ int noutlets = 0, i, j, xmax;
+ t_gobj *y, **vec, **vp, **maxp;
+
+ for (noutlets = 0, y = x->gl_list; y; y = y->g_next)
+ if (pd_class(&y->g_pd) == voutlet_class) noutlets++;
+
+ if (noutlets < 2) return;
+
+ vec = (t_gobj **)getbytes(noutlets * sizeof(*vec));
+
+ for (y = x->gl_list, vp = vec; y; y = y->g_next)
+ if (pd_class(&y->g_pd) == voutlet_class) *vp++ = y;
+
+ for (i = noutlets; i--;)
+ {
+ t_outlet *ip;
+ for (vp = vec, xmax = -0x7fffffff, maxp = 0, j = noutlets;
+ j--; vp++)
+ {
+ int x1, y1, x2, y2;
+ t_gobj *g = *vp;
+ if (!g) continue;
+ gobj_getrect(g, x, &x1, &y1, &x2, &y2);
+ if (x1 > xmax) xmax = x1, maxp = vp;
+ }
+ if (!maxp) break;
+ y = *maxp;
+ *maxp = 0;
+ ip = voutlet_getit(&y->g_pd);
+
+ obj_moveoutletfirst(&x->gl_obj, ip);
+ }
+ freebytes(vec, noutlets * sizeof(*vec));
+ if (x->gl_owner && glist_isvisible(x->gl_owner))
+ canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
+}
+
+/* ----------calculating coordinates and controlling appearance --------- */
+
+
+static void graph_bounds(t_glist *x, t_floatarg x1, t_floatarg y1,
+ t_floatarg x2, t_floatarg y2)
+{
+ x->gl_x1 = x1;
+ x->gl_x2 = x2;
+ x->gl_y1 = y1;
+ x->gl_y2 = y2;
+ if (x->gl_x2 == x->gl_x1 ||
+ x->gl_y2 == x->gl_y1)
+ {
+ error("graph: empty bounds rectangle");
+ x1 = y1 = 0;
+ x2 = y2 = 1;
+ }
+ glist_redraw(x);
+}
+
+static void graph_xticks(t_glist *x,
+ t_floatarg point, t_floatarg inc, t_floatarg f)
+{
+ x->gl_xtick.k_point = point;
+ x->gl_xtick.k_inc = inc;
+ x->gl_xtick.k_lperb = f;
+ glist_redraw(x);
+}
+
+static void graph_yticks(t_glist *x,
+ t_floatarg point, t_floatarg inc, t_floatarg f)
+{
+ x->gl_ytick.k_point = point;
+ x->gl_ytick.k_inc = inc;
+ x->gl_ytick.k_lperb = f;
+ glist_redraw(x);
+}
+
+static void graph_xlabel(t_glist *x, t_symbol *s, int argc, t_atom *argv)
+{
+ int i;
+ if (argc < 1) error("graph_xlabel: no y value given");
+ else
+ {
+ x->gl_xlabely = atom_getfloat(argv);
+ argv++; argc--;
+ x->gl_xlabel = (t_symbol **)t_resizebytes(x->gl_xlabel,
+ x->gl_nxlabels * sizeof (t_symbol *), argc * sizeof (t_symbol *));
+ x->gl_nxlabels = argc;
+ for (i = 0; i < argc; i++) x->gl_xlabel[i] = atom_gensym(&argv[i]);
+ }
+ glist_redraw(x);
+}
+
+static void graph_ylabel(t_glist *x, t_symbol *s, int argc, t_atom *argv)
+{
+ int i;
+ if (argc < 1) error("graph_ylabel: no x value given");
+ else
+ {
+ x->gl_ylabelx = atom_getfloat(argv);
+ argv++; argc--;
+ x->gl_ylabel = (t_symbol **)t_resizebytes(x->gl_ylabel,
+ x->gl_nylabels * sizeof (t_symbol *), argc * sizeof (t_symbol *));
+ x->gl_nylabels = argc;
+ for (i = 0; i < argc; i++) x->gl_ylabel[i] = atom_gensym(&argv[i]);
+ }
+ glist_redraw(x);
+}
+
+/****** routines to convert pixels to X or Y value and vice versa ******/
+
+ /* convert an x pixel value to an x coordinate value */
+float glist_pixelstox(t_glist *x, float xpix)
+{
+ /* if we appear as a text box on parent, our range in our
+ coordinates (x1, etc.) specifies the coordinate range
+ of a one-pixel square at top left of the window. */
+ if (!x->gl_isgraph)
+ return (x->gl_x1 + (x->gl_x2 - x->gl_x1) * xpix);
+
+ /* if we're a graph when shown on parent, but own our own
+ window right now, our range in our coordinates (x1, etc.) is spread
+ over the visible window size, given by screenx1, etc. */
+ else if (x->gl_isgraph && x->gl_havewindow)
+ return (x->gl_x1 + (x->gl_x2 - x->gl_x1) *
+ (xpix) / (x->gl_screenx2 - x->gl_screenx1));
+
+ /* otherwise, we appear in a graph within a parent glist,
+ so get our screen rectangle on parent and transform. */
+ else
+ {
+ int x1, y1, x2, y2;
+ if (!x->gl_owner)
+ bug("glist_pixelstox");
+ graph_graphrect(&x->gl_gobj, x->gl_owner, &x1, &y1, &x2, &y2);
+ return (x->gl_x1 + (x->gl_x2 - x->gl_x1) *
+ (xpix - x1) / (x2 - x1));
+ }
+}
+
+float glist_pixelstoy(t_glist *x, float ypix)
+{
+ if (!x->gl_isgraph)
+ return (x->gl_y1 + (x->gl_y2 - x->gl_y1) * ypix);
+ else if (x->gl_isgraph && x->gl_havewindow)
+ return (x->gl_y1 + (x->gl_y2 - x->gl_y1) *
+ (ypix) / (x->gl_screeny2 - x->gl_screeny1));
+ else
+ {
+ int x1, y1, x2, y2;
+ if (!x->gl_owner)
+ bug("glist_pixelstox");
+ graph_graphrect(&x->gl_gobj, x->gl_owner, &x1, &y1, &x2, &y2);
+ return (x->gl_y1 + (x->gl_y2 - x->gl_y1) *
+ (ypix - y1) / (y2 - y1));
+ }
+}
+
+ /* convert an x coordinate value to an x pixel location in window */
+float glist_xtopixels(t_glist *x, float xval)
+{
+ if (!x->gl_isgraph)
+ return ((xval - x->gl_x1) / (x->gl_x2 - x->gl_x1));
+ else if (x->gl_isgraph && x->gl_havewindow)
+ return (x->gl_screenx2 - x->gl_screenx1) *
+ (xval - x->gl_x1) / (x->gl_x2 - x->gl_x1);
+ else
+ {
+ int x1, y1, x2, y2;
+ if (!x->gl_owner)
+ bug("glist_pixelstox");
+ graph_graphrect(&x->gl_gobj, x->gl_owner, &x1, &y1, &x2, &y2);
+ return (x1 + (x2 - x1) * (xval - x->gl_x1) / (x->gl_x2 - x->gl_x1));
+ }
+}
+
+float glist_ytopixels(t_glist *x, float yval)
+{
+ if (!x->gl_isgraph)
+ return ((yval - x->gl_y1) / (x->gl_y2 - x->gl_y1));
+ else if (x->gl_isgraph && x->gl_havewindow)
+ return (x->gl_screeny2 - x->gl_screeny1) *
+ (yval - x->gl_y1) / (x->gl_y2 - x->gl_y1);
+ else
+ {
+ int x1, y1, x2, y2;
+ if (!x->gl_owner)
+ bug("glist_pixelstox");
+ graph_graphrect(&x->gl_gobj, x->gl_owner, &x1, &y1, &x2, &y2);
+ return (y1 + (y2 - y1) * (yval - x->gl_y1) / (x->gl_y2 - x->gl_y1));
+ }
+}
+
+ /* convert an X screen distance to an X coordinate increment.
+ This is terribly inefficient;
+ but probably not a big enough CPU hog to warrant optimizing. */
+float glist_dpixtodx(t_glist *x, float dxpix)
+{
+ return (dxpix * (glist_pixelstox(x, 1) - glist_pixelstox(x, 0)));
+}
+
+float glist_dpixtody(t_glist *x, float dypix)
+{
+ return (dypix * (glist_pixelstoy(x, 1) - glist_pixelstoy(x, 0)));
+}
+
+ /* get the window location in pixels of a "text" object. The
+ object's x and y positions are in pixels when the glist they're
+ in is toplevel. If it's not, we convert to pixels on the parent
+ window. */
+int text_xpix(t_text *x, t_glist *glist)
+{
+ if (glist->gl_havewindow || !glist->gl_isgraph)
+ return (x->te_xpix);
+ else return (glist_xtopixels(glist,
+ glist->gl_x1 + (glist->gl_x2 - glist->gl_x1) *
+ x->te_xpix / (glist->gl_screenx2 - glist->gl_screenx1)));
+}
+
+int text_ypix(t_text *x, t_glist *glist)
+{
+ if (glist->gl_havewindow || !glist->gl_isgraph)
+ return (x->te_ypix);
+ else return (glist_ytopixels(glist,
+ glist->gl_y1 + (glist->gl_y2 - glist->gl_y1) *
+ x->te_ypix / (glist->gl_screeny2 - glist->gl_screeny1)));
+}
+
+ /* redraw all the items in a glist. We construe this to mean
+ redrawing in its own window and on parent, as needed in each case.
+ This is too conservative -- for instance, when you draw an "open"
+ rectangle on the parent, you shouldn't have to redraw the window! */
+void glist_redraw(t_glist *x)
+{
+ if (glist_isvisible(x))
+ {
+ /* LATER fix the graph_vis() code to handle both cases */
+ if (glist_istoplevel(x))
+ {
+ t_gobj *g;
+ t_linetraverser t;
+ t_outconnect *oc;
+ for (g = x->gl_list; g; g = g->g_next)
+ {
+ gobj_vis(g, x, 0);
+ gobj_vis(g, x, 1);
+ }
+ /* redraw all the lines */
+ linetraverser_start(&t, x);
+ while (oc = linetraverser_next(&t))
+ sys_vgui(".x%x.c coords l%x %d %d %d %d\n",
+ glist_getcanvas(x), oc,
+ t.tr_lx1, t.tr_ly1, t.tr_lx2, t.tr_ly2);
+ }
+ if (x->gl_owner)
+ {
+ graph_vis(&x->gl_gobj, x->gl_owner, 0);
+ graph_vis(&x->gl_gobj, x->gl_owner, 1);
+ }
+ }
+}
+
+t_class *graph_class;
+
+/* --------------------------- widget behavior ------------------- */
+
+extern t_widgetbehavior text_widgetbehavior;
+
+ /* Note that some code in here would also be useful for drawing
+ graph decorations in toplevels... */
+static void graph_vis(t_gobj *gr, t_glist *parent_glist, int vis)
+{
+ t_glist *x = (t_glist *)gr;
+ char tag[50];
+ t_gobj *g;
+ int x1, y1, x2, y2;
+ /* ordinary subpatches: just act like a text object */
+ if (!x->gl_isgraph)
+ {
+ text_widgetbehavior.w_visfn(gr, parent_glist, vis);
+ return;
+ }
+
+ if (vis)
+ rtext_new(parent_glist, &x->gl_obj,
+ parent_glist->gl_editor->e_rtext,
+ canvas_showtext(x));
+ graph_getrect(gr, parent_glist, &x1, &y1, &x2, &y2);
+ if (!vis)
+ rtext_free(glist_findrtext(parent_glist, &x->gl_obj));
+
+ sprintf(tag, "graph%x", (int)x);
+ if (vis)
+ glist_drawiofor(parent_glist, &x->gl_obj, 1,
+ tag, x1, y1, x2, y2);
+ else glist_eraseiofor(parent_glist, &x->gl_obj, tag);
+ /* if we look like a graph but have been moved to a toplevel,
+ just show the bounding rectangle */
+ if (x->gl_havewindow)
+ {
+ if (vis)
+ {
+ sys_vgui(".x%x.c create polygon\
+ %d %d %d %d %d %d %d %d %d %d -tags %s -fill #c0c0c0\n",
+ glist_getcanvas(x->gl_owner),
+ x1, y1, x1, y2, x2, y2, x2, y1, x1, y1, tag);
+ }
+ else
+ {
+ sys_vgui(".x%x.c delete %s\n",
+ glist_getcanvas(x->gl_owner), tag);
+ }
+ return;
+ }
+ /* otherwise draw (or erase) us as a graph inside another glist. */
+ if (vis)
+ {
+ int i;
+ float f;
+
+ /* draw a rectangle around the graph */
+ sys_vgui(".x%x.c create line\
+ %d %d %d %d %d %d %d %d %d %d -tags %s\n",
+ glist_getcanvas(x->gl_owner),
+ x1, y1, x1, y2, x2, y2, x2, y1, x1, y1, tag);
+
+ /* draw ticks on horizontal borders. If lperb field is
+ zero, this is disabled. */
+ if (x->gl_xtick.k_lperb)
+ {
+ float upix, lpix;
+ if (y2 < y1)
+ upix = y1, lpix = y2;
+ else upix = y2, lpix = y1;
+ for (i = 0, f = x->gl_xtick.k_point;
+ f < 0.99 * x->gl_x2 + 0.01*x->gl_x1; i++,
+ f += x->gl_xtick.k_inc)
+ {
+ int tickpix = (i % x->gl_xtick.k_lperb ? 2 : 4);
+ sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
+ glist_getcanvas(x->gl_owner),
+ (int)glist_xtopixels(x, f), (int)upix,
+ (int)glist_xtopixels(x, f), (int)upix - tickpix, tag);
+ sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
+ glist_getcanvas(x->gl_owner),
+ (int)glist_xtopixels(x, f), (int)lpix,
+ (int)glist_xtopixels(x, f), (int)lpix + tickpix, tag);
+ }
+ for (i = 1, f = x->gl_xtick.k_point - x->gl_xtick.k_inc;
+ f > 0.99 * x->gl_x1 + 0.01*x->gl_x2;
+ i++, f -= x->gl_xtick.k_inc)
+ {
+ int tickpix = (i % x->gl_xtick.k_lperb ? 2 : 4);
+ sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
+ glist_getcanvas(x->gl_owner),
+ (int)glist_xtopixels(x, f), (int)upix,
+ (int)glist_xtopixels(x, f), (int)upix - tickpix, tag);
+ sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
+ glist_getcanvas(x->gl_owner),
+ (int)glist_xtopixels(x, f), (int)lpix,
+ (int)glist_xtopixels(x, f), (int)lpix + tickpix, tag);
+ }
+ }
+
+ /* draw ticks in vertical borders*/
+ if (x->gl_ytick.k_lperb)
+ {
+ float ubound, lbound;
+ if (x->gl_y2 < x->gl_y1)
+ ubound = x->gl_y1, lbound = x->gl_y2;
+ else ubound = x->gl_y2, lbound = x->gl_y1;
+ for (i = 0, f = x->gl_ytick.k_point;
+ f < 0.99 * ubound + 0.01 * lbound;
+ i++, f += x->gl_ytick.k_inc)
+ {
+ int tickpix = (i % x->gl_ytick.k_lperb ? 2 : 4);
+ sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
+ glist_getcanvas(x->gl_owner),
+ x1, (int)glist_ytopixels(x, f),
+ x1 + tickpix, (int)glist_ytopixels(x, f), tag);
+ sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
+ glist_getcanvas(x->gl_owner),
+ x2, (int)glist_ytopixels(x, f),
+ x2 - tickpix, (int)glist_ytopixels(x, f), tag);
+ }
+ for (i = 1, f = x->gl_ytick.k_point - x->gl_ytick.k_inc;
+ f > 0.99 * lbound + 0.01 * ubound;
+ i++, f -= x->gl_ytick.k_inc)
+ {
+ int tickpix = (i % x->gl_ytick.k_lperb ? 2 : 4);
+ sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
+ glist_getcanvas(x->gl_owner),
+ x1, (int)glist_ytopixels(x, f),
+ x1 + tickpix, (int)glist_ytopixels(x, f), tag);
+ sys_vgui(".x%x.c create line %d %d %d %d -tags %s\n",
+ glist_getcanvas(x->gl_owner),
+ x2, (int)glist_ytopixels(x, f),
+ x2 - tickpix, (int)glist_ytopixels(x, f), tag);
+ }
+ }
+ /* draw x labels */
+ for (i = 0; i < x->gl_nxlabels; i++)
+ sys_vgui(".x%x.c create text\
+ %d %d -text {%s} -font -*-courier-bold--normal--%d-* -tags %s\n",
+ glist_getcanvas(x),
+ (int)glist_xtopixels(x, atof(x->gl_xlabel[i]->s_name)),
+ (int)glist_ytopixels(x, x->gl_xlabely), x->gl_xlabel[i]->s_name,
+ glist_getfont(x), tag);
+
+ /* draw y labels */
+ for (i = 0; i < x->gl_nylabels; i++)
+ sys_vgui(".x%x.c create text\
+ %d %d -text {%s} -font -*-courier-bold--normal--%d-* -tags %s\n",
+ glist_getcanvas(x),
+ (int)glist_xtopixels(x, x->gl_ylabelx),
+ (int)glist_ytopixels(x, atof(x->gl_ylabel[i]->s_name)),
+ x->gl_ylabel[i]->s_name,
+ glist_getfont(x), tag);
+
+ /* draw contents of graph as glist */
+ for (g = x->gl_list; g; g = g->g_next)
+ gobj_vis(g, x, 1);
+ }
+ else
+ {
+ sys_vgui(".x%x.c delete %s\n",
+ glist_getcanvas(x->gl_owner), tag);
+ for (g = x->gl_list; g; g = g->g_next)
+ gobj_vis(g, x, 0);
+ }
+}
+
+ /* get the graph's rectangle, not counting extra swelling for controls
+ to keep them inside the graph. This is the "logical" pixel size. */
+
+static void graph_graphrect(t_gobj *z, t_glist *glist,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_glist *x = (t_glist *)z;
+ int x1 = text_xpix(&x->gl_obj, glist);
+ int y1 = text_ypix(&x->gl_obj, glist);
+ int x2, y2;
+#if 0 /* this used to adjust graph size when it was in another graph;
+ now we just preserve the size. */
+ /* same logic here as in text_xpix(): */
+ if (glist->gl_havewindow)
+ {
+ x2 = x1 + x->gl_pixwidth;
+ y2 = y1 + x->gl_pixheight;
+ }
+ else
+ {
+ x2 = glist_xtopixels(glist,
+ glist->gl_x1 + (glist->gl_x2 - glist->gl_x1) *
+ (x->gl_obj.te_xpix + x->gl_pixwidth) /
+ (glist->gl_screenx2 - glist->gl_screenx1));
+ y2 = glist_ytopixels(glist,
+ glist->gl_y1 + (glist->gl_y2 - glist->gl_y1) *
+ (x->gl_obj.te_ypix + x->gl_pixheight) /
+ (glist->gl_screeny2 - glist->gl_screeny1));
+ }
+#endif
+ x2 = x1 + x->gl_pixwidth;
+ y2 = y1 + x->gl_pixheight;
+
+ *xp1 = x1;
+ *yp1 = y1;
+ *xp2 = x2;
+ *yp2 = y2;
+}
+
+ /* get the rectangle, enlarged to contain all the "contents" --
+ meaning their formal bounds rectangles. */
+static void graph_getrect(t_gobj *z, t_glist *glist,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ int x1 = 0x7fffffff, y1 = 0x7fffffff, x2 = -0x7fffffff, y2 = -0x7fffffff;
+ t_glist *x = (t_glist *)z;
+ if (x->gl_isgraph)
+ {
+ int hadwindow;
+ t_gobj *g;
+ t_text *ob;
+ int x21, y21, x22, y22;
+
+ graph_graphrect(z, glist, &x1, &y1, &x2, &y2);
+ if (canvas_showtext(x))
+ {
+ text_widgetbehavior.w_getrectfn(z, glist, &x21, &y21, &x22, &y22);
+ if (x22 > x2)
+ x2 = x22;
+ if (y22 > y2)
+ y2 = y22;
+ }
+ /* lie about whether we have our own window to affect gobj_getrect
+ calls below. (LATER add argument to gobj_getrect()?) */
+ hadwindow = x->gl_havewindow;
+ x->gl_havewindow = 0;
+ for (g = x->gl_list; g; g = g->g_next)
+ if ((!(ob = pd_checkobject(&g->g_pd))) || text_shouldvis(ob, x))
+ {
+ /* don't do this for arrays, just let them hang outsize the
+ box. */
+ if (pd_class(&g->g_pd) == garray_class)
+ continue;
+ gobj_getrect(g, x, &x21, &y21, &x22, &y22);
+ if (x22 > x2)
+ x2 = x22;
+ if (y22 > y2)
+ y2 = y22;
+ }
+ x->gl_havewindow = hadwindow;
+ }
+ else text_widgetbehavior.w_getrectfn(z, glist, &x1, &y1, &x2, &y2);
+ *xp1 = x1;
+ *yp1 = y1;
+ *xp2 = x2;
+ *yp2 = y2;
+}
+
+static void graph_displace(t_gobj *z, t_glist *glist, int dx, int dy)
+{
+ t_glist *x = (t_glist *)z;
+ if (!x->gl_isgraph)
+ text_widgetbehavior.w_displacefn(z, glist, dx, dy);
+ else
+ {
+ x->gl_obj.te_xpix += dx;
+ x->gl_obj.te_ypix += dy;
+ glist_redraw(x);
+ canvas_fixlinesfor(glist_getcanvas(glist), &x->gl_obj);
+ }
+}
+
+static void graph_select(t_gobj *z, t_glist *glist, int state)
+{
+ t_glist *x = (t_glist *)z;
+ if (!x->gl_isgraph)
+ text_widgetbehavior.w_selectfn(z, glist, state);
+ else
+ {
+ t_rtext *y = glist_findrtext(glist, &x->gl_obj);
+ if (canvas_showtext(x))
+ rtext_select(y, state);
+ sys_vgui(".x%x.c itemconfigure %sR -fill %s\n", glist,
+ rtext_gettag(y), (state? "blue" : "black"));
+ sys_vgui(".x%x.c itemconfigure graph%x -fill %s\n",
+ glist_getcanvas(glist), z, (state? "blue" : "black"));
+ }
+}
+
+static void graph_activate(t_gobj *z, t_glist *glist, int state)
+{
+ t_glist *x = (t_glist *)z;
+ if (canvas_showtext(x))
+ text_widgetbehavior.w_activatefn(z, glist, state);
+}
+
+#if 0
+static void graph_delete(t_gobj *z, t_glist *glist)
+{
+ t_glist *x = (t_glist *)z;
+ if (!x->gl_isgraph)
+ text_widgetbehavior.w_deletefn(z, glist);
+ else
+ {
+ t_gobj *y;
+ while (y = x->gl_list) glist_delete(x, y);
+#if 0 /* I think this was just wrong. */
+ if (glist_isvisible(x))
+ sys_vgui(".x%x.c delete graph%x\n", glist_getcanvas(glist), x);
+#endif
+ }
+}
+#endif
+
+static void graph_delete(t_gobj *z, t_glist *glist)
+{
+ t_glist *x = (t_glist *)z;
+ t_gobj *y;
+ text_widgetbehavior.w_deletefn(z, glist);
+ while (y = x->gl_list)
+ glist_delete(x, y);
+}
+
+static float graph_lastxpix, graph_lastypix;
+
+static void graph_motion(void *z, t_floatarg dx, t_floatarg dy)
+{
+ t_glist *x = (t_glist *)z;
+ float newxpix = graph_lastxpix + dx, newypix = graph_lastypix + dy;
+ t_garray *a = (t_garray *)(x->gl_list);
+ int oldx = 0.5 + glist_pixelstox(x, graph_lastxpix);
+ int newx = 0.5 + glist_pixelstox(x, newxpix);
+ t_float *vec;
+ int nelem, i;
+ float oldy = glist_pixelstoy(x, graph_lastypix);
+ float newy = glist_pixelstoy(x, newypix);
+ graph_lastxpix = newxpix;
+ graph_lastypix = newypix;
+ /* verify that the array is OK */
+ if (!a || pd_class((t_pd *)a) != garray_class)
+ return;
+ if (!garray_getfloatarray(a, &nelem, &vec))
+ return;
+ if (oldx < 0) oldx = 0;
+ if (oldx >= nelem)
+ oldx = nelem - 1;
+ if (newx < 0) newx = 0;
+ if (newx >= nelem)
+ newx = nelem - 1;
+ if (oldx < newx - 1)
+ {
+ for (i = oldx + 1; i <= newx; i++)
+ vec[i] = newy + (oldy - newy) *
+ ((float)(newx - i))/(float)(newx - oldx);
+ }
+ else if (oldx > newx + 1)
+ {
+ for (i = oldx - 1; i >= newx; i--)
+ vec[i] = newy + (oldy - newy) *
+ ((float)(newx - i))/(float)(newx - oldx);
+ }
+ else vec[newx] = newy;
+ garray_redraw(a);
+}
+
+static int graph_click(t_gobj *z, struct _glist *glist,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ t_glist *x = (t_glist *)z;
+ t_gobj *y;
+ int clickreturned = 0;
+ if (!x->gl_isgraph)
+ return (text_widgetbehavior.w_clickfn(z, glist,
+ xpix, ypix, shift, alt, dbl, doit));
+ else if (x->gl_havewindow)
+ return (0);
+ else
+ {
+ for (y = x->gl_list; y; y = y->g_next)
+ {
+ int x1, y1, x2, y2;
+ /* check if the object wants to be clicked */
+ if (canvas_hitbox(x, y, xpix, ypix, &x1, &y1, &x2, &y2)
+ && (clickreturned = gobj_click(y, x, xpix, ypix,
+ shift, alt, 0, doit)))
+ break;
+ }
+ if (!doit)
+ {
+ if (y)
+ canvas_setcursor(glist_getcanvas(x), clickreturned);
+ else canvas_setcursor(glist_getcanvas(x), CURSOR_RUNMODE_NOTHING);
+ }
+ return (clickreturned);
+ }
+}
+
+static void graph_save(t_gobj *z, t_binbuf *b)
+{
+ t_glist *x = (t_glist *)z;
+ text_widgetbehavior.w_savefn(z, b);
+}
+
+void garray_properties(t_garray *x);
+
+static void graph_properties(t_gobj *z, t_glist *owner)
+{
+ t_glist *x = (t_glist *)z;
+ {
+ t_gobj *y;
+ char graphbuf[200];
+ sprintf(graphbuf, "pdtk_graph_dialog %%s %g %g %g %g %d %d\n",
+ x->gl_x1, x->gl_y1, x->gl_x2, x->gl_y2,
+ x->gl_pixwidth, x->gl_pixheight);
+ gfxstub_new(&x->gl_pd, x, graphbuf);
+
+ for (y = x->gl_list; y; y = y->g_next)
+ if (pd_class(&y->g_pd) == garray_class)
+ garray_properties((t_garray *)y);
+ }
+}
+
+t_widgetbehavior graph_widgetbehavior =
+{
+ graph_getrect,
+ graph_displace,
+ graph_select,
+ graph_activate,
+ graph_delete,
+ graph_vis,
+ graph_click,
+ graph_save,
+ graph_properties,
+};
+
+ /* find the graph most recently added to this glist;
+ if none exists, return 0. */
+
+t_glist *glist_findgraph(t_glist *x)
+{
+ t_gobj *y = 0, *z;
+ for (z = x->gl_list; z; z = z->g_next)
+ if (pd_class(&z->g_pd) == canvas_class && ((t_glist *)z)->gl_isgraph)
+ y = z;
+ return ((t_glist *)y);
+}
+
+ /* message back from dialog GUI to set parameters. Args are:
+ 1-4: bounds in our coordinates; 5-6: size in parent */
+static void graph_dialog(t_glist *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_float x1 = atom_getfloatarg(0, argc, argv);
+ t_float y1 = atom_getfloatarg(1, argc, argv);
+ t_float x2 = atom_getfloatarg(2, argc, argv);
+ t_float y2 = atom_getfloatarg(3, argc, argv);
+ t_float xpix = atom_getfloatarg(4, argc, argv);
+ t_float ypix = atom_getfloatarg(5, argc, argv);
+ if (x1 != x->gl_x1 || x2 != x->gl_x2 ||
+ y1 != x->gl_y1 || y2 != x->gl_y2)
+ graph_bounds(x, x1, y1, x2, y2);
+ if (xpix != x->gl_pixwidth || ypix != x->gl_pixheight)
+ {
+ x->gl_pixwidth = xpix;
+ x->gl_pixheight = ypix;
+ glist_redraw(x);
+ if (x->gl_owner)
+ canvas_fixlinesfor(x->gl_owner, &x->gl_obj);
+ }
+}
+
+extern void canvas_menuarray(t_glist *canvas);
+
+void g_graph_setup(void)
+{
+ class_setwidget(canvas_class, &graph_widgetbehavior);
+ class_addmethod(canvas_class, (t_method)graph_bounds, gensym("bounds"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(canvas_class, (t_method)graph_xticks, gensym("xticks"),
+ A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(canvas_class, (t_method)graph_xlabel, gensym("xlabel"),
+ A_GIMME, 0);
+ class_addmethod(canvas_class, (t_method)graph_yticks, gensym("yticks"),
+ A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(canvas_class, (t_method)graph_ylabel, gensym("ylabel"),
+ A_GIMME, 0);
+ class_addmethod(canvas_class, (t_method)graph_array, gensym("array"),
+ A_SYMBOL, A_FLOAT, A_SYMBOL, A_DEFFLOAT, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_menuarray,
+ gensym("menuarray"), A_NULL);
+ class_addmethod(canvas_class, (t_method)graph_dialog, gensym("dialog"),
+ A_GIMME, 0);
+ class_addmethod(canvas_class, (t_method)glist_arraydialog,
+ gensym("arraydialog"), A_SYMBOL, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(canvas_class, (t_method)glist_sort,
+ gensym("sort"), A_NULL);
+}
diff --git a/pd/src/g_guiconnect.c b/pd/src/g_guiconnect.c
new file mode 100644
index 00000000..aef8acb6
--- /dev/null
+++ b/pd/src/g_guiconnect.c
@@ -0,0 +1,94 @@
+/* Copyright (c) 1997-2000 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* a thing to forward messages from the GUI, dealing with race conditions
+in which the "target" gets deleted while the GUI is sending it something.
+*/
+
+#include "m_pd.h"
+#include "g_canvas.h"
+
+struct _guiconnect
+{
+ t_object x_obj;
+ t_pd *x_who;
+ t_symbol *x_sym;
+ t_clock *x_clock;
+};
+
+static t_class *guiconnect_class;
+
+t_guiconnect *guiconnect_new(t_pd *who, t_symbol *sym)
+{
+ t_guiconnect *x = (t_guiconnect *)pd_new(guiconnect_class);
+ x->x_who = who;
+ x->x_sym = sym;
+ pd_bind(&x->x_obj.ob_pd, sym);
+ return (x);
+}
+
+ /* cleanup routine; delete any resources we have */
+static void guiconnect_free(t_guiconnect *x)
+{
+ if (x->x_sym)
+ pd_unbind(&x->x_obj.ob_pd, x->x_sym);
+ if (x->x_clock)
+ clock_free(x->x_clock);
+}
+
+ /* this is called when the clock times out to indicate the GUI should
+ be gone by now. */
+static void guiconnect_tick(t_guiconnect *x)
+{
+ pd_free(&x->x_obj.ob_pd);
+}
+
+ /* the target calls this to disconnect. If the gui has "signed off"
+ we're ready to delete the object; otherwise we wait either for signoff
+ or for a timeout. */
+void guiconnect_notarget(t_guiconnect *x, double timedelay)
+{
+ if (!x->x_sym)
+ pd_free(&x->x_obj.ob_pd);
+ else
+ {
+ x->x_who = 0;
+ if (timedelay > 0)
+ {
+ x->x_clock = clock_new(x, (t_method)guiconnect_tick);
+ clock_delay(x->x_clock, timedelay);
+ }
+ }
+}
+
+ /* the GUI calls this to send messages to the target. */
+static void guiconnect_anything(t_guiconnect *x,
+ t_symbol *s, int ac, t_atom *av)
+{
+ if (x->x_who)
+ typedmess(x->x_who, s, ac, av);
+}
+
+ /* the GUI calls this when it disappears. (If there's any chance the
+ GUI will fail to do this, the "target", when it signs off, should specify
+ a timeout after which the guiconnect will disappear.) */
+static void guiconnect_signoff(t_guiconnect *x)
+{
+ if (!x->x_who)
+ pd_free(&x->x_obj.ob_pd);
+ else
+ {
+ pd_unbind(&x->x_obj.ob_pd, x->x_sym);
+ x->x_sym = 0;
+ }
+}
+
+void g_guiconnect_setup(void)
+{
+ guiconnect_class = class_new(gensym("guiconnect"), 0,
+ (t_method)guiconnect_free, sizeof(t_guiconnect), CLASS_PD, 0);
+ class_addanything(guiconnect_class, guiconnect_anything);
+ class_addmethod(guiconnect_class, (t_method)guiconnect_signoff,
+ gensym("signoff"), 0);
+}
diff --git a/pd/src/g_hdial.c b/pd/src/g_hdial.c
new file mode 100644
index 00000000..6e9f08a7
--- /dev/null
+++ b/pd/src/g_hdial.c
@@ -0,0 +1,675 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
+/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "m_imp.h"
+#include "g_canvas.h"
+#include "t_tk.h"
+#include "g_all_guis.h"
+#include <math.h>
+
+#ifdef NT
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+/* ------------- hdl gui-horicontal dial ---------------------- */
+
+t_widgetbehavior hdial_widgetbehavior;
+static t_class *hdial_class;
+
+/* widget helper functions */
+
+void hdial_draw_update(t_hdial *x, t_glist *glist)
+{
+ if(glist_isvisible(glist))
+ {
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c itemconfigure %xBUT%d -fill #%6.6x -outline #%6.6x\n",
+ canvas, x, x->x_on_old,
+ x->x_gui.x_bcol, x->x_gui.x_bcol);
+ sys_vgui(".x%x.c itemconfigure %xBUT%d -fill #%6.6x -outline #%6.6x\n",
+ canvas, x, x->x_on,
+ x->x_gui.x_fcol, x->x_gui.x_fcol);
+ }
+}
+
+void hdial_draw_new(t_hdial *x, t_glist *glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ int n=x->x_number, i, dx=x->x_gui.x_w, s4=dx/4;
+ int yy11=text_ypix(&x->x_gui.x_obj, glist), yy12=yy11+dx;
+ int yy21=yy11+s4, yy22=yy12-s4;
+ int xx11b=text_xpix(&x->x_gui.x_obj, glist), xx11=xx11b, xx21=xx11b+s4;
+ int xx22=xx11b+dx-s4;
+
+
+ for(i=0; i<n; i++)
+ {
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE%d\n",
+ canvas, xx11, yy11, xx11+dx, yy12,
+ x->x_gui.x_bcol, x, i);
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -outline #%6.6x -tags %xBUT%d\n",
+ canvas, xx21, yy21, xx22, yy22,
+ (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol,
+ (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol, x, i);
+ xx11 += dx;
+ xx21 += dx;
+ xx22 += dx;
+ }
+ sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
+ -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
+ canvas, xx11b+x->x_gui.x_ldx, yy11+x->x_gui.x_ldy,
+ strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
+ x->x_gui.x_font, x->x_gui.x_fontsize,
+ x->x_gui.x_lcol, x);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+ canvas, xx11b, yy12-1, xx11b + IOWIDTH, yy12, x, 0);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
+ canvas, xx11b, yy11, xx11b + IOWIDTH, yy11+1, x, 0);
+
+}
+
+void hdial_draw_move(t_hdial *x, t_glist *glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ int n=x->x_number, i, dx=x->x_gui.x_w, s4=dx/4;
+ int yy11=text_ypix(&x->x_gui.x_obj, glist), yy12=yy11+dx;
+ int yy21=yy11+s4, yy22=yy12-s4;
+ int xx11b=text_xpix(&x->x_gui.x_obj, glist), xx11=xx11b, xx21=xx11b+s4;
+ int xx22=xx11b+dx-s4;
+
+ xx11 = xx11b;
+ xx21=xx11b+s4;
+ xx22=xx11b+dx-s4;
+ for(i=0; i<n; i++)
+ {
+ sys_vgui(".x%x.c coords %xBASE%d %d %d %d %d\n",
+ canvas, x, i, xx11, yy11, xx11+dx, yy12);
+ sys_vgui(".x%x.c coords %xBUT%d %d %d %d %d\n",
+ canvas, x, i, xx21, yy21, xx22, yy22);
+ xx11 += dx;
+ xx21 += dx;
+ xx22 += dx;
+ }
+ sys_vgui(".x%x.c coords %xLABEL %d %d\n",
+ canvas, x, xx11b+x->x_gui.x_ldx, yy11+x->x_gui.x_ldy);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
+ canvas, x, 0, xx11b, yy12-1, xx11b + IOWIDTH, yy12);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
+ canvas, x, 0, xx11b, yy11, xx11b + IOWIDTH, yy11+1);
+}
+
+void hdial_draw_erase(t_hdial* x, t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ int n=x->x_number, i;
+
+ for(i=0; i<n; i++)
+ {
+ sys_vgui(".x%x.c delete %xBASE%d\n", canvas, x, i);
+ sys_vgui(".x%x.c delete %xBUT%d\n", canvas, x, i);
+ }
+ sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
+}
+
+void hdial_draw_config(t_hdial* x, t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ int n=x->x_number, i;
+
+ sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
+ canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
+ x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
+ strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
+ for(i=0; i<n; i++)
+ {
+ sys_vgui(".x%x.c itemconfigure %xBASE%d -fill #%6.6x\n", canvas, x, i,
+ x->x_gui.x_bcol);
+ sys_vgui(".x%x.c itemconfigure %xBUT%d -fill #%6.6x -outline #%6.6x\n", canvas, x, i,
+ (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol,
+ (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol);
+ }
+}
+
+void hdial_draw_io(t_hdial* x, t_glist* glist, int old_snd_rcv_flags)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+
+ if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+ canvas,
+ xpos, ypos + x->x_gui.x_w-1,
+ xpos + IOWIDTH, ypos + x->x_gui.x_w,
+ x, 0);
+ if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
+ if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
+ canvas,
+ xpos, ypos,
+ xpos + IOWIDTH, ypos+1, x, 0);
+ if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
+}
+
+void hdial_draw_select(t_hdial* x, t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ int n=x->x_number, i;
+
+ if(x->x_gui.x_fsf.x_selected)
+ {
+ pd_bind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ for(i=0; i<n; i++)
+ {
+ sys_vgui(".x%x.c itemconfigure %xBASE%d -outline #%6.6x\n", canvas, x, i,
+ IEM_GUI_COLOR_SELECTED);
+ }
+ sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+ }
+ else
+ {
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ for(i=0; i<n; i++)
+ {
+ sys_vgui(".x%x.c itemconfigure %xBASE%d -outline #%6.6x\n", canvas, x, i,
+ IEM_GUI_COLOR_NORMAL);
+ }
+ sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x,
+ x->x_gui.x_lcol);
+ }
+}
+
+void hdial_draw(t_hdial *x, t_glist *glist, int mode)
+{
+ if(mode == IEM_GUI_DRAW_MODE_UPDATE)
+ hdial_draw_update(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_MOVE)
+ hdial_draw_move(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_NEW)
+ hdial_draw_new(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_SELECT)
+ hdial_draw_select(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_ERASE)
+ hdial_draw_erase(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
+ hdial_draw_config(x, glist);
+ else if(mode >= IEM_GUI_DRAW_MODE_IO)
+ hdial_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
+}
+
+/* ------------------------ hdl widgetbehaviour----------------------------- */
+
+static void hdial_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_hdial *x = (t_hdial *)z;
+
+ *xp1 = text_xpix(&x->x_gui.x_obj, glist);
+ *yp1 = text_ypix(&x->x_gui.x_obj, glist);
+ *xp2 = *xp1 + x->x_gui.x_w*x->x_number;
+ *yp2 = *yp1 + x->x_gui.x_h;
+}
+
+static void hdial_save(t_gobj *z, t_binbuf *b)
+{
+ t_hdial *x = (t_hdial *)z;
+ int bflcol[3], *ip1, *ip2;
+ t_symbol *srl[3];
+
+ iemgui_save(&x->x_gui, srl, bflcol);
+ ip1 = (int *)(&x->x_gui.x_isa);
+ ip2 = (int *)(&x->x_gui.x_fsf);
+ binbuf_addv(b, "ssiisiiiisssiiiiiiii", gensym("#X"),gensym("obj"),
+ (t_int)text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist), (t_int)text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist),
+ gensym("hdl"), x->x_gui.x_w,
+ x->x_change, (*ip1)&IEM_INIT_ARGS_ALL, x->x_number,
+ srl[0], srl[1], srl[2],
+ x->x_gui.x_ldx, x->x_gui.x_ldy,
+ (*ip2)&IEM_FSTYLE_FLAGS_ALL, x->x_gui.x_fontsize,
+ bflcol[0], bflcol[1], bflcol[2], x->x_on);
+ binbuf_addv(b, ";");
+}
+
+static void hdial_properties(t_gobj *z, t_glist *owner)
+{
+ t_hdial *x = (t_hdial *)z;
+ char buf[800];
+ t_symbol *srl[3];
+
+ iemgui_properties(&x->x_gui, srl);
+ sprintf(buf, "pdtk_iemgui_dialog %%s HDIAL \
+ ----------dimensions(pix):----------- %d %d size: 0 0 empty \
+ empty 0.0 empty 0.0 empty %d \
+ %d new-only new&old %d %d number: %d \
+ %s %s \
+ %s %d %d \
+ %d %d \
+ %d %d %d\n",
+ x->x_gui.x_w, IEM_GUI_MINSIZE,
+ 0,/*no_schedule*/
+ x->x_change, x->x_gui.x_isa.x_loadinit, -1, x->x_number,
+ srl[0]->s_name, srl[1]->s_name,
+ srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
+ x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
+ 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
+ gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
+}
+
+static void hdial_dialog(t_hdial *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_symbol *srl[3];
+ int a = (int)atom_getintarg(0, argc, argv);
+ int chg = (int)atom_getintarg(4, argc, argv);
+ int num = (int)atom_getintarg(6, argc, argv);
+ int sr_flags;
+
+ if(chg != 0) chg = 1;
+ x->x_change = chg;
+ sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
+ x->x_gui.x_w = iemgui_clip_size(a);
+ x->x_gui.x_h = x->x_gui.x_w;
+ if(x->x_number != num)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_ERASE);
+ x->x_number = num;
+ if(x->x_on >= x->x_number)
+ {
+ x->x_on = x->x_number - 1;
+ x->x_on_old = x->x_on;
+ }
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_NEW);
+ }
+ else
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
+ }
+
+}
+
+static void hdial_set(t_hdial *x, t_floatarg f)
+{
+ int i=(int)f;
+ int old=x->x_on_old;
+
+ if(i < 0)
+ i = 0;
+ if(i >= x->x_number)
+ i = x->x_number-1;
+ if(x->x_on != x->x_on_old)
+ {
+ old = x->x_on_old;
+ x->x_on_old = x->x_on;
+ x->x_on = i;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ x->x_on_old = old;
+ }
+ else
+ {
+ x->x_on = i;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ }
+}
+
+static void hdial_bang(t_hdial *x)
+{
+ if((x->x_change)&&(x->x_on != x->x_on_old))
+ {
+ SETFLOAT(x->x_at, (float)x->x_on_old);
+ SETFLOAT(x->x_at+1, 0.0);
+ outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
+ }
+ x->x_on_old = x->x_on;
+ SETFLOAT(x->x_at, (float)x->x_on);
+ SETFLOAT(x->x_at+1, 1.0);
+ outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
+}
+
+static void hdial_fout(t_hdial *x, t_floatarg f)
+{
+ int i=(int)f;
+
+ if(i < 0)
+ i = 0;
+ if(i >= x->x_number)
+ i = x->x_number-1;
+
+ if((x->x_change)&&(i != x->x_on_old))
+ {
+ SETFLOAT(x->x_at, (float)x->x_on_old);
+ SETFLOAT(x->x_at+1, 0.0);
+ outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
+ }
+ if(x->x_on != x->x_on_old)
+ x->x_on_old = x->x_on;
+ x->x_on = i;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ x->x_on_old = x->x_on;
+ SETFLOAT(x->x_at, (float)x->x_on);
+ SETFLOAT(x->x_at+1, 1.0);
+ outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
+}
+
+static void hdial_float(t_hdial *x, t_floatarg f)
+{
+ int i=(int)f;
+
+ if(i < 0)
+ i = 0;
+ if(i >= x->x_number)
+ i = x->x_number-1;
+
+ if((x->x_change)&&(i != x->x_on_old))
+ {
+ if(x->x_gui.x_fsf.x_put_in2out)
+ {
+ SETFLOAT(x->x_at, (float)x->x_on_old);
+ SETFLOAT(x->x_at+1, 0.0);
+ outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
+ }
+ }
+ if(x->x_on != x->x_on_old)
+ x->x_on_old = x->x_on;
+ x->x_on = i;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ x->x_on_old = x->x_on;
+ if(x->x_gui.x_fsf.x_put_in2out)
+ {
+ SETFLOAT(x->x_at, (float)x->x_on);
+ SETFLOAT(x->x_at+1, 1.0);
+ outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
+ }
+}
+
+static void hdial_click(t_hdial *x, t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ int xx = (int)xpos - (int)text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist);
+
+ hdial_fout(x, (float)(xx / x->x_gui.x_w));
+}
+
+static int hdial_newclick(t_gobj *z, struct _glist *glist, int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ if(doit)
+ hdial_click((t_hdial *)z, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift, 0, (t_floatarg)alt);
+ return (1);
+}
+
+static void hdial_loadbang(t_hdial *x)
+{
+ if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
+ hdial_bang(x);
+}
+
+static void hdial_number(t_hdial *x, t_floatarg num)
+{
+ int n=(int)num;
+
+ if(n < 1)
+ n = 1;
+ if(n > IEM_RADIO_MAX)
+ n = IEM_RADIO_MAX;
+ if(n != x->x_number)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_ERASE);
+ x->x_number = n;
+ if(x->x_on >= x->x_number)
+ x->x_on = x->x_number - 1;
+ x->x_on_old = x->x_on;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_NEW);
+ }
+}
+
+static void hdial_size(t_hdial *x, t_symbol *s, int ac, t_atom *av)
+{
+ x->x_gui.x_w = iemgui_clip_size((int)atom_getintarg(0, ac, av));
+ x->x_gui.x_h = x->x_gui.x_w;
+ iemgui_size((void *)x, &x->x_gui);
+}
+
+static void hdial_delta(t_hdial *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
+
+static void hdial_pos(t_hdial *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
+
+static void hdial_color(t_hdial *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
+
+static void hdial_send(t_hdial *x, t_symbol *s)
+{iemgui_send(x, &x->x_gui, s);}
+
+static void hdial_receive(t_hdial *x, t_symbol *s)
+{iemgui_receive(x, &x->x_gui, s);}
+
+static void hdial_label(t_hdial *x, t_symbol *s)
+{iemgui_label((void *)x, &x->x_gui, s);}
+
+static void hdial_label_pos(t_hdial *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
+
+static void hdial_label_font(t_hdial *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
+
+static void hdial_init(t_hdial *x, t_floatarg f)
+{
+ x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
+}
+
+static void hdial_double_change(t_hdial *x)
+{x->x_change = 1;}
+
+static void hdial_single_change(t_hdial *x)
+{x->x_change = 0;}
+
+static void hdial_list(t_hdial *x, t_symbol *s, int ac, t_atom *av)
+{
+ int l=iemgui_list((void *)x, &x->x_gui, s, ac, av);
+
+ if(l < 0)
+ {
+ if(IS_A_FLOAT(av,0))
+ hdial_float(x, atom_getfloatarg(0, ac, av));
+ }
+ else if(l > 0)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
+ }
+}
+
+static void *hdial_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_hdial *x = (t_hdial *)pd_new(hdial_class);
+ int bflcol[]={-262144, -1, -1};
+ t_symbol *srl[3];
+ int a=IEM_GUI_DEFAULTSIZE, on=0, f=0;
+ int ldx=0, ldy=-6, chg=1, num=8;
+ int fs=8, iinit=0, ifstyle=0;
+ int ftbreak=IEM_BNG_DEFAULTBREAKFLASHTIME, fthold=IEM_BNG_DEFAULTHOLDFLASHTIME;
+ t_iem_init_symargs *init=(t_iem_init_symargs *)(&iinit);
+ t_iem_fstyle_flags *fstyle=(t_iem_fstyle_flags *)(&ifstyle);
+ char str[144];
+
+ srl[0] = gensym("empty");
+ srl[1] = gensym("empty");
+ srl[2] = gensym("empty");
+
+ if((argc == 15)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)&&IS_A_FLOAT(argv,2)
+ &&IS_A_FLOAT(argv,3)
+ &&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4))
+ &&(IS_A_SYMBOL(argv,5)||IS_A_FLOAT(argv,5))
+ &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
+ &&IS_A_FLOAT(argv,7)&&IS_A_FLOAT(argv,8)
+ &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)&&IS_A_FLOAT(argv,11)
+ &&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)&&IS_A_FLOAT(argv,14))
+ {
+ a = (int)atom_getintarg(0, argc, argv);
+ chg = (int)atom_getintarg(1, argc, argv);
+ iinit = (int)atom_getintarg(2, argc, argv);
+ num = (int)atom_getintarg(3, argc, argv);
+ if(IS_A_SYMBOL(argv,4))
+ srl[0] = atom_getsymbolarg(4, argc, argv);
+ else if(IS_A_FLOAT(argv,4))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(4, argc, argv));
+ srl[0] = gensym(str);
+ }
+ if(IS_A_SYMBOL(argv,5))
+ srl[1] = atom_getsymbolarg(5, argc, argv);
+ else if(IS_A_FLOAT(argv,5))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(5, argc, argv));
+ srl[1] = gensym(str);
+ }
+ if(IS_A_SYMBOL(argv,6))
+ srl[2] = atom_getsymbolarg(6, argc, argv);
+ else if(IS_A_FLOAT(argv,6))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(6, argc, argv));
+ srl[2] = gensym(str);
+ }
+ ldx = (int)atom_getintarg(7, argc, argv);
+ ldy = (int)atom_getintarg(8, argc, argv);
+ ifstyle = (int)atom_getintarg(9, argc, argv);
+ fs = (int)atom_getintarg(10, argc, argv);
+ bflcol[0] = (int)atom_getintarg(11, argc, argv);
+ bflcol[1] = (int)atom_getintarg(12, argc, argv);
+ bflcol[2] = (int)atom_getintarg(13, argc, argv);
+ on = (int)atom_getintarg(14, argc, argv);
+ }
+ x->x_gui.x_draw = (t_iemfunptr)hdial_draw;
+ iinit &= IEM_INIT_ARGS_ALL;
+ ifstyle &= IEM_FSTYLE_FLAGS_ALL;
+ fstyle->x_snd_able = 1;
+ fstyle->x_rcv_able = 1;
+ x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
+ x->x_gui.x_isa = *init;
+ if(!strcmp(srl[0]->s_name, "empty")) fstyle->x_snd_able = 0;
+ if(!strcmp(srl[1]->s_name, "empty")) fstyle->x_rcv_able = 0;
+ if(fstyle->x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
+ else if(fstyle->x_font_style == 2) strcpy(x->x_gui.x_font, "times");
+ else { fstyle->x_font_style = 0;
+ strcpy(x->x_gui.x_font, "courier"); }
+ x->x_gui.x_fsf = *fstyle;
+ x->x_gui.x_unique_num = 0;
+ if(num < 1)
+ num = 1;
+ if(num > IEM_RADIO_MAX)
+ num = IEM_RADIO_MAX;
+ x->x_number = num;
+ if(on < 0)
+ on = 0;
+ if(on >= x->x_number)
+ on = x->x_number - 1;
+ if(x->x_gui.x_isa.x_loadinit)
+ x->x_on = on;
+ else
+ x->x_on = 0;
+ x->x_on_old = x->x_on;
+ x->x_change = (chg==0)?0:1;
+ iemgui_first_dollararg2sym(&x->x_gui, srl);
+ if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, srl[1]);
+ x->x_gui.x_snd = srl[0];
+ x->x_gui.x_rcv = srl[1];
+ x->x_gui.x_lab = srl[2];
+ x->x_gui.x_ldx = ldx;
+ x->x_gui.x_ldy = ldy;
+ if(fs < 4)
+ fs = 4;
+ x->x_gui.x_fontsize = fs;
+ x->x_gui.x_w = iemgui_clip_size(a);
+ x->x_gui.x_h = x->x_gui.x_w;
+ iemgui_verify_snd_ne_rcv(&x->x_gui);
+ iemgui_all_colfromload(&x->x_gui, bflcol);
+ outlet_new(&x->x_gui.x_obj, &s_list);
+ return (x);
+}
+
+static void hdial_ff(t_hdial *x)
+{
+ if(x->x_gui.x_fsf.x_selected)
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ if(x->x_gui.x_fsf.x_rcv_able)
+ pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
+ gfxstub_deleteforkey(x);
+}
+
+void g_hdial_setup(void)
+{
+ hdial_class = class_new(gensym("hdl"), (t_newmethod)hdial_new,
+ (t_method)hdial_ff, sizeof(t_hdial), 0, A_GIMME, 0);
+ class_addcreator((t_newmethod)hdial_new, gensym("rdb"), A_GIMME, 0);
+ class_addcreator((t_newmethod)hdial_new, gensym("radiobut"), A_GIMME, 0);
+ class_addcreator((t_newmethod)hdial_new, gensym("radiobutton"), A_GIMME, 0);
+ class_addbang(hdial_class, hdial_bang);
+ class_addfloat(hdial_class, hdial_float);
+ class_addlist(hdial_class, hdial_list);
+ class_addmethod(hdial_class, (t_method)hdial_click, gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(hdial_class, (t_method)hdial_dialog, gensym("dialog"),
+ A_GIMME, 0);
+ class_addmethod(hdial_class, (t_method)hdial_loadbang, gensym("loadbang"), 0);
+ class_addmethod(hdial_class, (t_method)hdial_set, gensym("set"), A_FLOAT, 0);
+ class_addmethod(hdial_class, (t_method)hdial_size, gensym("size"), A_GIMME, 0);
+ class_addmethod(hdial_class, (t_method)hdial_delta, gensym("delta"), A_GIMME, 0);
+ class_addmethod(hdial_class, (t_method)hdial_pos, gensym("pos"), A_GIMME, 0);
+ class_addmethod(hdial_class, (t_method)hdial_color, gensym("color"), A_GIMME, 0);
+ class_addmethod(hdial_class, (t_method)hdial_send, gensym("send"), A_DEFSYM, 0);
+ class_addmethod(hdial_class, (t_method)hdial_receive, gensym("receive"), A_DEFSYM, 0);
+ class_addmethod(hdial_class, (t_method)hdial_label, gensym("label"), A_DEFSYM, 0);
+ class_addmethod(hdial_class, (t_method)hdial_label_pos, gensym("label_pos"), A_GIMME, 0);
+ class_addmethod(hdial_class, (t_method)hdial_label_font, gensym("label_font"), A_GIMME, 0);
+ class_addmethod(hdial_class, (t_method)hdial_init, gensym("init"), A_FLOAT, 0);
+ class_addmethod(hdial_class, (t_method)hdial_number, gensym("number"), A_FLOAT, 0);
+ class_addmethod(hdial_class, (t_method)hdial_single_change, gensym("single_change"), 0);
+ class_addmethod(hdial_class, (t_method)hdial_double_change, gensym("double_change"), 0);
+ if(!iemgui_key_sym)
+ iemgui_key_sym = gensym("#keyname");
+ hdial_widgetbehavior.w_getrectfn = hdial_getrect;
+ hdial_widgetbehavior.w_displacefn = iemgui_displace;
+ hdial_widgetbehavior.w_selectfn = iemgui_select;
+ hdial_widgetbehavior.w_activatefn = NULL;
+ hdial_widgetbehavior.w_deletefn = iemgui_delete;
+ hdial_widgetbehavior.w_visfn = iemgui_vis;
+ hdial_widgetbehavior.w_clickfn = hdial_newclick;
+ hdial_widgetbehavior.w_propertiesfn = hdial_properties;
+ hdial_widgetbehavior.w_savefn = hdial_save;
+ class_setwidget(hdial_class, &hdial_widgetbehavior);
+ class_sethelpsymbol(hdial_class, gensym("hdial"));
+}
diff --git a/pd/src/g_hslider.c b/pd/src/g_hslider.c
new file mode 100644
index 00000000..0e5415a9
--- /dev/null
+++ b/pd/src/g_hslider.c
@@ -0,0 +1,708 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
+/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "m_imp.h"
+#include "g_canvas.h"
+#include "t_tk.h"
+#include "g_all_guis.h"
+#include <math.h>
+
+#ifdef NT
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+
+/* ------------ hsl gui-horicontal slider ----------------------- */
+
+t_widgetbehavior hslider_widgetbehavior;
+static t_class *hslider_class;
+
+/* widget helper functions */
+
+static void hslider_draw_update(t_hslider *x, t_glist *glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+
+ if (glist_isvisible(glist))
+ {
+ int r = text_xpix(&x->x_gui.x_obj, glist) + (x->x_val + 50)/100;
+ sys_vgui(".x%x.c coords %xKNOB %d %d %d %d\n",
+ canvas, x, r, ypos+1,
+ r, ypos + x->x_gui.x_h);
+ if(x->x_val == x->x_center)
+ {
+ if(!x->x_thick)
+ {
+ sys_vgui(".x%x.c itemconfigure %xKNOB -width 7\n", canvas, x);
+ x->x_thick = 1;
+ }
+ }
+ else
+ {
+ if(x->x_thick)
+ {
+ sys_vgui(".x%x.c itemconfigure %xKNOB -width 3\n", canvas, x);
+ x->x_thick = 0;
+ }
+ }
+ }
+}
+
+static void hslider_draw_new(t_hslider *x, t_glist *glist)
+{
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ int r = xpos + (x->x_val + 50)/100;
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE\n",
+ canvas, xpos-3, ypos,
+ xpos + x->x_gui.x_w+2, ypos + x->x_gui.x_h,
+ x->x_gui.x_bcol, x);
+ sys_vgui(".x%x.c create line %d %d %d %d -width 3 -fill #%6.6x -tags %xKNOB\n",
+ canvas, r, ypos+1, r,
+ ypos + x->x_gui.x_h, x->x_gui.x_fcol, x);
+ sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
+ -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
+ canvas, xpos+x->x_gui.x_ldx,
+ ypos+x->x_gui.x_ldy,
+ strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
+ x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+ canvas, xpos-3, ypos + x->x_gui.x_h-1,
+ xpos+4, ypos + x->x_gui.x_h, x, 0);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
+ canvas, xpos-3, ypos,
+ xpos+4, ypos+1, x, 0);
+}
+
+static void hslider_draw_move(t_hslider *x, t_glist *glist)
+{
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ int r = xpos + (x->x_val + 50)/100;
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c coords %xBASE %d %d %d %d\n",
+ canvas, x,
+ xpos-3, ypos,
+ xpos + x->x_gui.x_w+2, ypos + x->x_gui.x_h);
+ sys_vgui(".x%x.c coords %xKNOB %d %d %d %d\n",
+ canvas, x, r, ypos+1,
+ r, ypos + x->x_gui.x_h);
+ sys_vgui(".x%x.c coords %xLABEL %d %d\n",
+ canvas, x, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
+ canvas, x, 0,
+ xpos-3, ypos + x->x_gui.x_h-1,
+ xpos+4, ypos + x->x_gui.x_h);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
+ canvas, x, 0,
+ xpos-3, ypos,
+ xpos+4, ypos+1);
+}
+
+static void hslider_draw_erase(t_hslider* x,t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c delete %xBASE\n", canvas, x);
+ sys_vgui(".x%x.c delete %xKNOB\n", canvas, x);
+ sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
+}
+
+static void hslider_draw_config(t_hslider* x,t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
+ canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
+ x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
+ strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
+ sys_vgui(".x%x.c itemconfigure %xKNOB -fill #%6.6x\n", canvas, x, x->x_gui.x_fcol);
+ sys_vgui(".x%x.c itemconfigure %xBASE -fill #%6.6x\n", canvas, x, x->x_gui.x_bcol);
+}
+
+static void hslider_draw_io(t_hslider* x,t_glist* glist, int old_snd_rcv_flags)
+{
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+ canvas, xpos-3, ypos + x->x_gui.x_h-1,
+ xpos+4, ypos + x->x_gui.x_h, x, 0);
+ if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
+ if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
+ canvas, xpos-3, ypos,
+ xpos+4, ypos+1, x, 0);
+ if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
+}
+
+static void hslider_draw_select(t_hslider* x,t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if(x->x_gui.x_fsf.x_selected)
+ {
+ pd_bind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+ sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+ }
+ else
+ {
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
+ sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol);
+ }
+}
+
+void hslider_draw(t_hslider *x, t_glist *glist, int mode)
+{
+ if(mode == IEM_GUI_DRAW_MODE_UPDATE)
+ hslider_draw_update(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_MOVE)
+ hslider_draw_move(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_NEW)
+ hslider_draw_new(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_SELECT)
+ hslider_draw_select(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_ERASE)
+ hslider_draw_erase(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
+ hslider_draw_config(x, glist);
+ else if(mode >= IEM_GUI_DRAW_MODE_IO)
+ hslider_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
+}
+
+/* ------------------------ hsl widgetbehaviour----------------------------- */
+
+
+static void hslider_getrect(t_gobj *z, t_glist *glist,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_hslider* x = (t_hslider*)z;
+
+ *xp1 = text_xpix(&x->x_gui.x_obj, glist) - 3;
+ *yp1 = text_ypix(&x->x_gui.x_obj, glist);
+ *xp2 = *xp1 + x->x_gui.x_w + 5;
+ *yp2 = *yp1 + x->x_gui.x_h;
+}
+
+static void hslider_save(t_gobj *z, t_binbuf *b)
+{
+ t_hslider *x = (t_hslider *)z;
+ int bflcol[3], *ip1, *ip2;
+ t_symbol *srl[3];
+
+ iemgui_save(&x->x_gui, srl, bflcol);
+ ip1 = (int *)(&x->x_gui.x_isa);
+ ip2 = (int *)(&x->x_gui.x_fsf);
+ binbuf_addv(b, "ssiisiiffiisssiiiiiiiii", gensym("#X"),gensym("obj"),
+ (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
+ gensym("hsl"), x->x_gui.x_w, x->x_gui.x_h,
+ (float)x->x_min, (float)x->x_max,
+ x->x_lin0_log1, (*ip1)&IEM_INIT_ARGS_ALL,
+ srl[0], srl[1], srl[2],
+ x->x_gui.x_ldx, x->x_gui.x_ldy,
+ (*ip2)&IEM_FSTYLE_FLAGS_ALL, x->x_gui.x_fontsize,
+ bflcol[0], bflcol[1], bflcol[2],
+ x->x_val, x->x_steady);
+ binbuf_addv(b, ";");
+}
+
+void hslider_check_width(t_hslider *x, int w)
+{
+ if(w < IEM_SL_MINSIZE)
+ w = IEM_SL_MINSIZE;
+ x->x_gui.x_w = w;
+ x->x_center = (x->x_gui.x_w-1)*50;
+ if(x->x_val > (x->x_gui.x_w*100 - 100))
+ {
+ x->x_pos = x->x_gui.x_w*100 - 100;
+ x->x_val = x->x_pos;
+ }
+ if(x->x_lin0_log1)
+ x->x_k = log(x->x_max/x->x_min)/(double)(x->x_gui.x_w - 1);
+ else
+ x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_w - 1);
+}
+
+void hslider_check_minmax(t_hslider *x, double min, double max)
+{
+ if(x->x_lin0_log1)
+ {
+ if((min == 0.0)&&(max == 0.0))
+ max = 1.0;
+ if(max > 0.0)
+ {
+ if(min <= 0.0)
+ min = 0.01*max;
+ }
+ else
+ {
+ if(min > 0.0)
+ max = 0.01*min;
+ }
+ }
+ x->x_min = min;
+ x->x_max = max;
+ if(x->x_min > x->x_max) /* bugfix */
+ x->x_gui.x_isa.x_reverse = 1;
+ else
+ x->x_gui.x_isa.x_reverse = 0;
+ if(x->x_lin0_log1)
+ x->x_k = log(x->x_max/x->x_min)/(double)(x->x_gui.x_w - 1);
+ else
+ x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_w - 1);
+}
+
+static void hslider_properties(t_gobj *z, t_glist *owner)
+{
+ t_hslider *x = (t_hslider *)z;
+ char buf[800];
+ t_symbol *srl[3];
+
+ iemgui_properties(&x->x_gui, srl);
+ sprintf(buf, "pdtk_iemgui_dialog %%s HSLIDER \
+ --------dimensions(pix)(pix):-------- %d %d width: %d %d height: \
+ -----------output-range:----------- %g left: %g right: %g \
+ %d lin log %d %d empty %d \
+ %s %s \
+ %s %d %d \
+ %d %d \
+ %d %d %d\n",
+ x->x_gui.x_w, IEM_SL_MINSIZE, x->x_gui.x_h, IEM_GUI_MINSIZE,
+ x->x_min, x->x_max, 0.0,/*no_schedule*/
+ x->x_lin0_log1, x->x_gui.x_isa.x_loadinit, x->x_steady, -1,/*no multi, but iem-characteristic*/
+ srl[0]->s_name, srl[1]->s_name,
+ srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
+ x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
+ 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
+ gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
+}
+
+static void hslider_set(t_hslider *x, t_floatarg f) /* bugfix */
+{
+ double g;
+
+ if(x->x_gui.x_isa.x_reverse) /* bugfix */
+ {
+ if(f > x->x_min)
+ f = x->x_min;
+ if(f < x->x_max)
+ f = x->x_max;
+ }
+ else
+ {
+ if(f > x->x_max)
+ f = x->x_max;
+ if(f < x->x_min)
+ f = x->x_min;
+ }
+ if(x->x_lin0_log1)
+ g = log(f/x->x_min)/x->x_k;
+ else
+ g = (f - x->x_min) / x->x_k;
+ x->x_val = (int)(100.0*g + 0.49999);
+ x->x_pos = x->x_val;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+}
+
+static void hslider_bang(t_hslider *x)
+{
+ double out;
+
+ if(x->x_lin0_log1)
+ out = x->x_min*exp(x->x_k*(double)(x->x_val)*0.01);
+ else
+ out = (double)(x->x_val)*0.01*x->x_k + x->x_min;
+ if((out < 1.0e-10)&&(out > -1.0e-10))
+ out = 0.0;
+ outlet_float(x->x_gui.x_obj.ob_outlet, out);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_float(x->x_gui.x_snd->s_thing, out);
+}
+
+static void hslider_dialog(t_hslider *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_symbol *srl[3];
+ int w = (int)atom_getintarg(0, argc, argv);
+ int h = (int)atom_getintarg(1, argc, argv);
+ double min = (double)atom_getfloatarg(2, argc, argv);
+ double max = (double)atom_getfloatarg(3, argc, argv);
+ int lilo = (int)atom_getintarg(4, argc, argv);
+ int steady = (int)atom_getintarg(17, argc, argv);
+ int sr_flags;
+
+ if(lilo != 0) lilo = 1;
+ x->x_lin0_log1 = lilo;
+ if(steady)
+ x->x_steady = 1;
+ else
+ x->x_steady = 0;
+ sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
+ x->x_gui.x_h = iemgui_clip_size(h);
+ hslider_check_width(x, w);
+ hslider_check_minmax(x, min, max);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
+}
+
+static void hslider_motion(t_hslider *x, t_floatarg dx, t_floatarg dy)
+{
+ int old = x->x_val;
+
+ if(x->x_gui.x_fsf.x_finemoved)
+ x->x_pos += (int)dx;
+ else
+ x->x_pos += 100*(int)dx;
+ x->x_val = x->x_pos;
+ if(x->x_val > (100*x->x_gui.x_w - 100))
+ {
+ x->x_val = 100*x->x_gui.x_w - 100;
+ x->x_pos += 50;
+ x->x_pos -= x->x_pos%100;
+ }
+ if(x->x_val < 0)
+ {
+ x->x_val = 0;
+ x->x_pos -= 50;
+ x->x_pos -= x->x_pos%100;
+ }
+ if(old != x->x_val)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ hslider_bang(x);
+ }
+}
+
+static void hslider_click(t_hslider *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ if(!x->x_steady)
+ x->x_val = (int)(100.0 * (xpos - text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist)));
+ if(x->x_val > (100*x->x_gui.x_w - 100))
+ x->x_val = 100*x->x_gui.x_w - 100;
+ if(x->x_val < 0)
+ x->x_val = 0;
+ x->x_pos = x->x_val;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ hslider_bang(x);
+ glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g, (t_glistmotionfn)hslider_motion,
+ 0, xpos, ypos);
+}
+
+static int hslider_newclick(t_gobj *z, struct _glist *glist,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ t_hslider* x = (t_hslider *)z;
+
+ if(doit)
+ {
+ hslider_click( x, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift,
+ 0, (t_floatarg)alt);
+ if(shift)
+ x->x_gui.x_fsf.x_finemoved = 1;
+ else
+ x->x_gui.x_fsf.x_finemoved = 0;
+ }
+ return (1);
+}
+
+static void hslider_size(t_hslider *x, t_symbol *s, int ac, t_atom *av)
+{
+ hslider_check_width(x, (int)atom_getintarg(0, ac, av));
+ if(ac > 1)
+ x->x_gui.x_h = iemgui_clip_size((int)atom_getintarg(1, ac, av));
+ iemgui_size((void *)x, &x->x_gui);
+}
+
+static void hslider_delta(t_hslider *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
+
+static void hslider_pos(t_hslider *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
+
+static void hslider_range(t_hslider *x, t_symbol *s, int ac, t_atom *av)
+{
+ hslider_check_minmax(x, (double)atom_getfloatarg(0, ac, av),
+ (double)atom_getfloatarg(1, ac, av));
+}
+
+static void hslider_color(t_hslider *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
+
+static void hslider_send(t_hslider *x, t_symbol *s)
+{iemgui_send(x, &x->x_gui, s);}
+
+static void hslider_receive(t_hslider *x, t_symbol *s)
+{iemgui_receive(x, &x->x_gui, s);}
+
+static void hslider_label(t_hslider *x, t_symbol *s)
+{iemgui_label((void *)x, &x->x_gui, s);}
+
+static void hslider_label_pos(t_hslider *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
+
+static void hslider_label_font(t_hslider *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
+
+static void hslider_log(t_hslider *x)
+{
+ x->x_lin0_log1 = 1;
+ hslider_check_minmax(x, x->x_min, x->x_max);
+}
+
+static void hslider_lin(t_hslider *x)
+{
+ x->x_lin0_log1 = 0;
+ x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_w - 1);
+}
+
+static void hslider_init(t_hslider *x, t_floatarg f)
+{
+ x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
+}
+
+static void hslider_steady(t_hslider *x, t_floatarg f)
+{
+ x->x_steady = (f==0.0)?0:1;
+}
+
+static void hslider_float(t_hslider *x, t_floatarg f)
+{
+ double out;
+
+ hslider_set(x, f);
+ if(x->x_lin0_log1)
+ out = x->x_min*exp(x->x_k*(double)(x->x_val)*0.01);
+ else
+ out = (double)(x->x_val)*0.01*x->x_k + x->x_min;
+ if((out < 1.0e-10)&&(out > -1.0e-10))
+ out = 0.0;
+ if(x->x_gui.x_fsf.x_put_in2out)
+ {
+ outlet_float(x->x_gui.x_obj.ob_outlet, out);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_float(x->x_gui.x_snd->s_thing, out);
+ }
+}
+
+static void hslider_loadbang(t_hslider *x)
+{
+ if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ hslider_bang(x);
+ }
+}
+
+static void hslider_list(t_hslider *x, t_symbol *s, int ac, t_atom *av)
+{
+ int l=iemgui_list((void *)x, &x->x_gui, s, ac, av);
+
+ if(l < 0)
+ {
+ if(IS_A_FLOAT(av,0))
+ hslider_float(x, atom_getfloatarg(0, ac, av));
+ }
+ else if(l > 0)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
+ }
+}
+
+static void *hslider_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_hslider *x = (t_hslider *)pd_new(hslider_class);
+ int bflcol[]={-262144, -1, -1};
+ t_symbol *srl[3];
+ int w=IEM_SL_DEFAULTSIZE, h=IEM_GUI_DEFAULTSIZE;
+ int lilo=0, ldx=-2, ldy=-6, f=0, v=0, steady=1;
+ int fs=8, iinit=0, ifstyle=0;
+ double min=0.0, max=(double)(IEM_SL_DEFAULTSIZE-1);
+ t_iem_init_symargs *init=(t_iem_init_symargs *)(&iinit);
+ t_iem_fstyle_flags *fstyle=(t_iem_fstyle_flags *)(&ifstyle);
+ char str[144];
+
+ srl[0] = gensym("empty");
+ srl[1] = gensym("empty");
+ srl[2] = gensym("empty");
+
+ if(((argc == 17)||(argc == 18))&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)
+ &&IS_A_FLOAT(argv,2)&&IS_A_FLOAT(argv,3)
+ &&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5)
+ &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
+ &&(IS_A_SYMBOL(argv,7)||IS_A_FLOAT(argv,7))
+ &&(IS_A_SYMBOL(argv,8)||IS_A_FLOAT(argv,8))
+ &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)
+ &&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)
+ &&IS_A_FLOAT(argv,14)&&IS_A_FLOAT(argv,15)&&IS_A_FLOAT(argv,16))
+ {
+ w = (int)atom_getintarg(0, argc, argv);
+ h = (int)atom_getintarg(1, argc, argv);
+ min = (double)atom_getfloatarg(2, argc, argv);
+ max = (double)atom_getfloatarg(3, argc, argv);
+ lilo = (int)atom_getintarg(4, argc, argv);
+ iinit = (int)atom_getintarg(5, argc, argv);
+ if(IS_A_SYMBOL(argv,6))
+ srl[0] = atom_getsymbolarg(6, argc, argv);
+ else if(IS_A_FLOAT(argv,6))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(6, argc, argv));
+ srl[0] = gensym(str);
+ }
+ if(IS_A_SYMBOL(argv,7))
+ srl[1] = atom_getsymbolarg(7, argc, argv);
+ else if(IS_A_FLOAT(argv,7))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(7, argc, argv));
+ srl[1] = gensym(str);
+ }
+ if(IS_A_SYMBOL(argv,8))
+ srl[2] = atom_getsymbolarg(8, argc, argv);
+ else if(IS_A_FLOAT(argv,8))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(8, argc, argv));
+ srl[2] = gensym(str);
+ }
+ ldx = (int)atom_getintarg(9, argc, argv);
+ ldy = (int)atom_getintarg(10, argc, argv);
+ ifstyle = (int)atom_getintarg(11, argc, argv);
+ fs = (int)atom_getintarg(12, argc, argv);
+ bflcol[0] = (int)atom_getintarg(13, argc, argv);
+ bflcol[1] = (int)atom_getintarg(14, argc, argv);
+ bflcol[2] = (int)atom_getintarg(15, argc, argv);
+ v = (int)atom_getintarg(16, argc, argv);
+ }
+ if((argc == 18)&&IS_A_FLOAT(argv,17))
+ steady = (int)atom_getintarg(17, argc, argv);
+
+ x->x_gui.x_draw = (t_iemfunptr)hslider_draw;
+ iinit &= IEM_INIT_ARGS_ALL;
+ ifstyle &= IEM_FSTYLE_FLAGS_ALL;
+
+ fstyle->x_snd_able = 1;
+ fstyle->x_rcv_able = 1;
+
+ x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
+ x->x_gui.x_isa = *init;
+ if(x->x_gui.x_isa.x_loadinit)
+ x->x_val = v;
+ else
+ x->x_val = 0;
+ x->x_pos = x->x_val;
+ if(lilo != 0) lilo = 1;
+ x->x_lin0_log1 = lilo;
+ if(steady != 0) steady = 1;
+ x->x_steady = steady;
+ if(!strcmp(srl[0]->s_name, "empty")) fstyle->x_snd_able = 0;
+ if(!strcmp(srl[1]->s_name, "empty")) fstyle->x_rcv_able = 0;
+ x->x_gui.x_unique_num = 0;
+ if(fstyle->x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
+ else if(fstyle->x_font_style == 2) strcpy(x->x_gui.x_font, "times");
+ else { fstyle->x_font_style = 0;
+ strcpy(x->x_gui.x_font, "courier"); }
+ x->x_gui.x_fsf = *fstyle;
+ iemgui_first_dollararg2sym(&x->x_gui, srl);
+ if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, srl[1]);
+ x->x_gui.x_snd = srl[0];
+ x->x_gui.x_rcv = srl[1];
+ x->x_gui.x_lab = srl[2];
+ x->x_gui.x_ldx = ldx;
+ x->x_gui.x_ldy = ldy;
+ if(fs < 4)
+ fs = 4;
+ x->x_gui.x_fontsize = fs;
+ x->x_gui.x_h = iemgui_clip_size(h);
+ hslider_check_width(x, w);
+ hslider_check_minmax(x, min, max);
+ iemgui_all_colfromload(&x->x_gui, bflcol);
+ x->x_thick = 0;
+ iemgui_verify_snd_ne_rcv(&x->x_gui);
+ outlet_new(&x->x_gui.x_obj, &s_float);
+ return (x);
+}
+
+static void hslider_free(t_hslider *x)
+{
+ if(x->x_gui.x_fsf.x_selected)
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ if(x->x_gui.x_fsf.x_rcv_able)
+ pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
+ gfxstub_deleteforkey(x);
+}
+
+void g_hslider_setup(void)
+{
+ hslider_class = class_new(gensym("hsl"), (t_newmethod)hslider_new,
+ (t_method)hslider_free, sizeof(t_hslider), 0, A_GIMME, 0);
+#ifndef GGEE_HSLIDER_COMPATIBLE
+ class_addcreator((t_newmethod)hslider_new, gensym("hslider"), A_GIMME, 0);
+#endif
+ class_addbang(hslider_class,hslider_bang);
+ class_addfloat(hslider_class,hslider_float);
+ class_addlist(hslider_class, hslider_list);
+ class_addmethod(hslider_class, (t_method)hslider_click, gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(hslider_class, (t_method)hslider_motion, gensym("motion"),
+ A_FLOAT, A_FLOAT, 0);
+ class_addmethod(hslider_class, (t_method)hslider_dialog, gensym("dialog"), A_GIMME, 0);
+ class_addmethod(hslider_class, (t_method)hslider_loadbang, gensym("loadbang"), 0);
+ class_addmethod(hslider_class, (t_method)hslider_set, gensym("set"), A_FLOAT, 0);
+ class_addmethod(hslider_class, (t_method)hslider_size, gensym("size"), A_GIMME, 0);
+ class_addmethod(hslider_class, (t_method)hslider_delta, gensym("delta"), A_GIMME, 0);
+ class_addmethod(hslider_class, (t_method)hslider_pos, gensym("pos"), A_GIMME, 0);
+ class_addmethod(hslider_class, (t_method)hslider_range, gensym("range"), A_GIMME, 0);
+ class_addmethod(hslider_class, (t_method)hslider_color, gensym("color"), A_GIMME, 0);
+ class_addmethod(hslider_class, (t_method)hslider_send, gensym("send"), A_DEFSYM, 0);
+ class_addmethod(hslider_class, (t_method)hslider_receive, gensym("receive"), A_DEFSYM, 0);
+ class_addmethod(hslider_class, (t_method)hslider_label, gensym("label"), A_DEFSYM, 0);
+ class_addmethod(hslider_class, (t_method)hslider_label_pos, gensym("label_pos"), A_GIMME, 0);
+ class_addmethod(hslider_class, (t_method)hslider_label_font, gensym("label_font"), A_GIMME, 0);
+ class_addmethod(hslider_class, (t_method)hslider_log, gensym("log"), 0);
+ class_addmethod(hslider_class, (t_method)hslider_lin, gensym("lin"), 0);
+ class_addmethod(hslider_class, (t_method)hslider_init, gensym("init"), A_FLOAT, 0);
+ class_addmethod(hslider_class, (t_method)hslider_steady, gensym("steady"), A_FLOAT, 0);
+ if(!iemgui_key_sym)
+ iemgui_key_sym = gensym("#keyname");
+ hslider_widgetbehavior.w_getrectfn = hslider_getrect;
+ hslider_widgetbehavior.w_displacefn = iemgui_displace;
+ hslider_widgetbehavior.w_selectfn = iemgui_select;
+ hslider_widgetbehavior.w_activatefn = NULL;
+ hslider_widgetbehavior.w_deletefn = iemgui_delete;
+ hslider_widgetbehavior.w_visfn = iemgui_vis;
+ hslider_widgetbehavior.w_clickfn = hslider_newclick;
+ hslider_widgetbehavior.w_propertiesfn = hslider_properties;
+ hslider_widgetbehavior.w_savefn = hslider_save;
+ class_setwidget(hslider_class, &hslider_widgetbehavior);
+ class_sethelpsymbol(hslider_class, gensym("hslider"));
+}
diff --git a/pd/src/g_io.c b/pd/src/g_io.c
new file mode 100644
index 00000000..487be350
--- /dev/null
+++ b/pd/src/g_io.c
@@ -0,0 +1,612 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* graphical inlets and outlets, both for control and signals. */
+
+/* This code is highly inefficient; messages actually have to be forwarded
+by inlets and outlets. The outlet is in even worse shape than the inlet;
+in order to avoid having a "signal" method in the class, the oulet actually
+sprouts an inlet, which forwards the message to the "outlet" object, which
+sends it on to the outlet proper. Another way to do it would be to have
+separate classes for "signal" and "control" outlets, but this would complicate
+life elsewhere. */
+
+
+/* hacked to run subpatches with different samplerates
+ *
+ * mfg.gfd.uil
+ * IOhannes
+ *
+ * edited lines are marked with "IOhannes"
+ *
+ */
+
+#include "m_pd.h"
+#include "g_canvas.h"
+#include <string.h>
+void signal_setborrowed(t_signal *sig, t_signal *sig2);
+void signal_makereusable(t_signal *sig);
+
+/* ------------------------- vinlet -------------------------- */
+t_class *vinlet_class;
+
+typedef struct _vinlet
+{
+ t_object x_obj;
+ t_canvas *x_canvas;
+ t_inlet *x_inlet;
+ int x_bufsize;
+ t_float *x_buf; /* signal buffer; zero if not a signal */
+ t_float *x_endbuf;
+ t_float *x_fill;
+ t_float *x_read;
+ int x_hop;
+ /* if not reblocking, the next slot communicates the parent's inlet
+ signal from the prolog to the DSP routine: */
+ t_signal *x_directsignal;
+
+ t_resample x_updown; /* IOhannes */
+} t_vinlet;
+
+static void *vinlet_new(t_symbol *s)
+{
+ t_vinlet *x = (t_vinlet *)pd_new(vinlet_class);
+ x->x_canvas = canvas_getcurrent();
+ x->x_inlet = canvas_addinlet(x->x_canvas, &x->x_obj.ob_pd, 0);
+ x->x_bufsize = 0;
+ x->x_buf = 0;
+ outlet_new(&x->x_obj, 0);
+ return (x);
+}
+
+static void vinlet_bang(t_vinlet *x)
+{
+ outlet_bang(x->x_obj.ob_outlet);
+}
+
+static void vinlet_pointer(t_vinlet *x, t_gpointer *gp)
+{
+ outlet_pointer(x->x_obj.ob_outlet, gp);
+}
+
+static void vinlet_float(t_vinlet *x, t_float f)
+{
+ outlet_float(x->x_obj.ob_outlet, f);
+}
+
+static void vinlet_symbol(t_vinlet *x, t_symbol *s)
+{
+ outlet_symbol(x->x_obj.ob_outlet, s);
+}
+
+static void vinlet_list(t_vinlet *x, t_symbol *s, int argc, t_atom *argv)
+{
+ outlet_list(x->x_obj.ob_outlet, s, argc, argv);
+}
+
+static void vinlet_anything(t_vinlet *x, t_symbol *s, int argc, t_atom *argv)
+{
+ outlet_anything(x->x_obj.ob_outlet, s, argc, argv);
+}
+
+static void vinlet_free(t_vinlet *x)
+{
+ canvas_rminlet(x->x_canvas, x->x_inlet);
+ resample_free(&x->x_updown);
+}
+
+t_inlet *vinlet_getit(t_pd *x)
+{
+ if (pd_class(x) != vinlet_class) bug("vinlet_getit");
+ return (((t_vinlet *)x)->x_inlet);
+}
+
+/* ------------------------- signal inlet -------------------------- */
+int vinlet_issignal(t_vinlet *x)
+{
+ return (x->x_buf != 0);
+}
+
+static int tot;
+
+t_int *vinlet_perform(t_int *w)
+{
+ t_vinlet *x = (t_vinlet *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ t_float *in = x->x_read;
+#if 0
+ if (tot < 5) post("-in %x out %x n %d", in, out, n);
+ if (tot < 5) post("-buf %x endbuf %x", x->x_buf, x->x_endbuf);
+ if (tot < 5) post("in[0] %f in[1] %f in[2] %f", in[0], in[1], in[2]);
+#endif
+ while (n--) *out++ = *in++;
+ if (in == x->x_endbuf) in = x->x_buf;
+ x->x_read = in;
+ return (w+4);
+}
+
+static void vinlet_dsp(t_vinlet *x, t_signal **sp)
+{
+ t_signal *outsig;
+ /* no buffer means we're not a signal inlet */
+ if (!x->x_buf)
+ return;
+ outsig = sp[0];
+ if (x->x_directsignal)
+ {
+ signal_setborrowed(sp[0], x->x_directsignal);
+ }
+ else
+ {
+ dsp_add(vinlet_perform, 3, x, outsig->s_vec, outsig->s_n);
+ x->x_read = x->x_buf;
+ }
+}
+
+ /* prolog code: loads buffer from parent patch */
+t_int *vinlet_doprolog(t_int *w)
+{
+ t_vinlet *x = (t_vinlet *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ t_float *out = x->x_fill;
+ if (out == x->x_endbuf)
+ {
+ t_float *f1 = x->x_buf, *f2 = x->x_buf + x->x_hop;
+ int nshift = x->x_bufsize - x->x_hop;
+ out -= x->x_hop;
+ while (nshift--) *f1++ = *f2++;
+ }
+#if 0
+ if (tot < 5) post("in %x out %x n %x", in, out, n), tot++;
+ if (tot < 5) post("in[0] %f in[1] %f in[2] %f", in[0], in[1], in[2]);
+#endif
+
+ while (n--) *out++ = *in++;
+ x->x_fill = out;
+ return (w+4);
+}
+
+int inlet_getsignalindex(t_inlet *x);
+
+ /* set up prolog DSP code */
+void vinlet_dspprolog(t_vinlet *x, t_signal **parentsigs,
+ int myvecsize, int phase, int period, int frequency, int downsample, int upsample/* IOhannes */, int reblock,
+ int switched)
+{
+ t_signal *insig, *outsig;
+ x->x_updown.downsample = downsample;
+ x->x_updown.upsample = upsample;
+
+ /* if the "reblock" flag is set, arrange to copy data in from the
+ parent. */
+ if (reblock)
+ {
+ int parentvecsize, bufsize, oldbufsize, prologphase;
+ int re_parentvecsize; /* resampled parentvectorsize: IOhannes */
+ /* this should never happen: */
+ if (!x->x_buf) return;
+
+ /* the prolog code counts from 0 to period-1; the
+ phase is backed up by one so that AFTER the prolog code
+ runs, the "x_fill" phase is in sync with the "x_read" phase. */
+ prologphase = (phase - 1) & (period - 1);
+ if (parentsigs)
+ {
+ insig = parentsigs[inlet_getsignalindex(x->x_inlet)];
+ parentvecsize = insig->s_n;
+ re_parentvecsize = parentvecsize * upsample / downsample;
+ }
+ else
+ {
+ insig = 0;
+ parentvecsize = 1;
+ re_parentvecsize = 1;
+ }
+
+ bufsize = re_parentvecsize;
+ if (bufsize < myvecsize) bufsize = myvecsize;
+ if (bufsize != (oldbufsize = x->x_bufsize))
+ {
+ t_float *buf = x->x_buf;
+ t_freebytes(buf, oldbufsize * sizeof(*buf));
+ buf = (t_float *)t_getbytes(bufsize * sizeof(*buf));
+ memset((char *)buf, 0, bufsize * sizeof(*buf));
+ x->x_bufsize = bufsize;
+ x->x_endbuf = buf + bufsize;
+ x->x_buf = buf;
+ }
+ if (parentsigs)
+ {
+ /* IOhannes { */
+ x->x_hop = period * re_parentvecsize;
+
+ x->x_fill = x->x_endbuf -
+ (x->x_hop - prologphase * re_parentvecsize);
+
+ if (upsample * downsample == 1)
+ dsp_add(vinlet_doprolog, 3, x, insig->s_vec, re_parentvecsize);
+ else {
+ resamplefrom_dsp(&x->x_updown, insig->s_vec, parentvecsize, re_parentvecsize, x->x_updown.method);
+ dsp_add(vinlet_doprolog, 3, x, x->x_updown.s_vec, re_parentvecsize);
+ }
+
+ /* } IOhannes */
+ /* if the input signal's reference count is zero, we have
+ to free it here because we didn't in ugen_doit(). */
+ if (!insig->s_refcount)
+ signal_makereusable(insig);
+ }
+ else memset((char *)(x->x_buf), 0, bufsize * sizeof(*x->x_buf));
+ x->x_directsignal = 0;
+ }
+ else
+ {
+ /* no reblocking; in this case our output signal is "borrowed"
+ and merely needs to be pointed to the real one. */
+ x->x_directsignal = parentsigs[inlet_getsignalindex(x->x_inlet)];
+ }
+}
+
+//static void *vinlet_newsig(void)
+static void *vinlet_newsig(t_symbol *s)
+{
+ t_vinlet *x = (t_vinlet *)pd_new(vinlet_class);
+ x->x_canvas = canvas_getcurrent();
+ x->x_inlet = canvas_addinlet(x->x_canvas, &x->x_obj.ob_pd, &s_signal);
+ x->x_endbuf = x->x_buf = (t_float *)getbytes(0);
+ x->x_bufsize = 0;
+ x->x_directsignal = 0;
+ outlet_new(&x->x_obj, &s_signal);
+
+ resample_init(&x->x_updown);
+
+ /* this should be though over:
+ * it might prove hard to provide consistency between labeled up- & downsampling methods
+ * maybe indeces would be better...
+ *
+ * up till now we provide several upsampling methods and 1 single downsampling method (no filtering !)
+ */
+ if (s == gensym("hold"))x->x_updown.method=1; /* up: sample and hold */
+ else if (s == gensym("lin"))x->x_updown.method=2; /* up: linear interpolation */
+ else x->x_updown.method=0; /* up: zero-padding */
+
+ return (x);
+}
+
+static void vinlet_setup(void)
+{
+ vinlet_class = class_new(gensym("inlet"), (t_newmethod)vinlet_new,
+ (t_method)vinlet_free, sizeof(t_vinlet), CLASS_NOINLET, A_DEFSYM, 0);
+ class_addcreator((t_newmethod)vinlet_newsig, gensym("inlet~"), A_DEFSYM, 0);
+ class_addbang(vinlet_class, vinlet_bang);
+ class_addpointer(vinlet_class, vinlet_pointer);
+ class_addfloat(vinlet_class, vinlet_float);
+ class_addsymbol(vinlet_class, vinlet_symbol);
+ class_addlist(vinlet_class, vinlet_list);
+ class_addanything(vinlet_class, vinlet_anything);
+ class_addmethod(vinlet_class, (t_method)vinlet_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(vinlet_class, gensym("pd"));
+}
+
+/* ------------------------- voutlet -------------------------- */
+
+t_class *voutlet_class;
+
+typedef struct _voutlet
+{
+ t_object x_obj;
+ t_canvas *x_canvas;
+ t_outlet *x_parentoutlet;
+ int x_bufsize;
+ t_float *x_buf; /* signal buffer; zero if not a signal */
+ t_float *x_endbuf;
+ t_float *x_empty; /* next to read out of buffer in epilog code */
+ t_float *x_write; /* next to write in to buffer */
+ int x_hop; /* hopsize */
+ /* vice versa from the inlet, if we don't block, this holds the
+ parent's outlet signal, valid between the prolog and the dsp setup
+ routines. */
+ t_signal *x_directsignal;
+ /* and here's a flag indicating that we aren't blocked but have to
+ do a copy (because we're switched). */
+ char x_justcopyout;
+ t_resample x_updown; /* IOhannes */
+} t_voutlet;
+
+static void *voutlet_new(t_symbol *s)
+{
+ t_voutlet *x = (t_voutlet *)pd_new(voutlet_class);
+ x->x_canvas = canvas_getcurrent();
+ x->x_parentoutlet = canvas_addoutlet(x->x_canvas, &x->x_obj.ob_pd, 0);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, 0, 0);
+ x->x_bufsize = 0;
+ x->x_buf = 0;
+ return (x);
+}
+
+static void voutlet_bang(t_voutlet *x)
+{
+ outlet_bang(x->x_parentoutlet);
+}
+
+static void voutlet_pointer(t_voutlet *x, t_gpointer *gp)
+{
+ outlet_pointer(x->x_parentoutlet, gp);
+}
+
+static void voutlet_float(t_voutlet *x, t_float f)
+{
+ outlet_float(x->x_parentoutlet, f);
+}
+
+static void voutlet_symbol(t_voutlet *x, t_symbol *s)
+{
+ outlet_symbol(x->x_parentoutlet, s);
+}
+
+static void voutlet_list(t_voutlet *x, t_symbol *s, int argc, t_atom *argv)
+{
+ outlet_list(x->x_parentoutlet, s, argc, argv);
+}
+
+static void voutlet_anything(t_voutlet *x, t_symbol *s, int argc, t_atom *argv)
+{
+ outlet_anything(x->x_parentoutlet, s, argc, argv);
+}
+
+static void voutlet_free(t_voutlet *x)
+{
+ canvas_rmoutlet(x->x_canvas, x->x_parentoutlet);
+ resample_free(&x->x_updown);
+}
+
+t_outlet *voutlet_getit(t_pd *x)
+{
+ if (pd_class(x) != voutlet_class) bug("voutlet_getit");
+ return (((t_voutlet *)x)->x_parentoutlet);
+}
+
+/* ------------------------- signal outlet -------------------------- */
+
+int voutlet_issignal(t_voutlet *x)
+{
+ return (x->x_buf != 0);
+}
+
+ /* LATER optimize for non-overlapped case where the "+=" isn't needed */
+t_int *voutlet_perform(t_int *w)
+{
+ t_voutlet *x = (t_voutlet *)(w[1]);
+ t_float *in = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ t_float *out = x->x_write, *outwas = out;
+#if 0
+ if (tot < 5) post("-in %x out %x n %d", in, out, n);
+ if (tot < 5) post("-buf %x endbuf %x", x->x_buf, x->x_endbuf);
+#endif
+ while (n--)
+ {
+ *out++ += *in++;
+ if (out == x->x_endbuf) out = x->x_buf;
+ }
+ outwas += x->x_hop;
+ if (outwas >= x->x_endbuf) outwas = x->x_buf;
+ x->x_write = outwas;
+ return (w+4);
+}
+
+ /* epilog code for blocking: write buffer to parent patch */
+static t_int *voutlet_doepilog(t_int *w)
+{
+ t_voutlet *x = (t_voutlet *)(w[1]);
+ t_float *out = (t_float *)(w[2]); /* IOhannes */
+
+ int n = (int)(w[3]);
+ t_float *in = x->x_empty;
+ if (x->x_updown.downsample != x->x_updown.upsample) out = x->x_updown.s_vec; /* IOhannes */
+
+#if 0
+ if (tot < 5) post("outlet in %x out %x n %x", in, out, n), tot++;
+#endif
+ for (; n--; in++) *out++ = *in, *in = 0;
+ if (in == x->x_endbuf) in = x->x_buf;
+ x->x_empty = in;
+ return (w+4);
+}
+
+/* IOhannes { */
+static t_int *voutlet_doepilog_resampling(t_int *w)
+{
+ t_voutlet *x = (t_voutlet *)(w[1]);
+ // t_float *dummy = (t_float *)(w[2]);
+ int n = (int)(w[2]);
+ t_float *in = x->x_empty;
+ t_float *out = x->x_updown.s_vec; /* IOhannes */
+
+#if 0
+ if (tot < 5) post("outlet in %x out %x n %x", in, out, n), tot++;
+#endif
+ for (; n--; in++) *out++ = *in, *in = 0;
+ if (in == x->x_endbuf) in = x->x_buf;
+ x->x_empty = in;
+ return (w+3);
+}
+/* } IOhannes */
+int outlet_getsignalindex(t_outlet *x);
+
+ /* prolog for outlets -- store pointer to the outlet on the
+ parent, which, if "reblock" is false, will want to refer
+ back to whatever we see on our input during the "dsp" method
+ called later. */
+void voutlet_dspprolog(t_voutlet *x, t_signal **parentsigs,
+ int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
+ int switched)
+{
+ x->x_updown.downsample=downsample; x->x_updown.upsample=upsample; /* IOhannes */
+ x->x_justcopyout = (switched && !reblock);
+ if (reblock)
+ {
+ x->x_directsignal = 0;
+ }
+ else
+ {
+ if (!parentsigs) bug("voutlet_dspprolog");
+ x->x_directsignal =
+ parentsigs[outlet_getsignalindex(x->x_parentoutlet)];
+ }
+}
+
+static void voutlet_dsp(t_voutlet *x, t_signal **sp)
+{
+ t_signal *insig;
+ if (!x->x_buf) return;
+ insig = sp[0];
+ if (x->x_justcopyout)
+ dsp_add_copy(insig->s_vec, x->x_directsignal->s_vec, insig->s_n);
+ else if (x->x_directsignal)
+ {
+ /* if we're just going to make the signal available on the
+ parent patch, hand it off to the parent signal. */
+ /* this is done elsewhere--> sp[0]->s_refcount++; */
+ signal_setborrowed(x->x_directsignal, sp[0]);
+ }
+ else
+ dsp_add(voutlet_perform, 3, x, insig->s_vec, insig->s_n);
+}
+
+ /* set up epilog DSP code. If we're reblocking, this is the
+ time to copy the samples out to the containing object's outlets.
+ If we aren't reblocking, there's nothing to do here. */
+void voutlet_dspepilog(t_voutlet *x, t_signal **parentsigs,
+ int myvecsize, int phase, int period, int frequency, int downsample, int upsample /* IOhannes */, int reblock,
+ int switched)
+{
+ if (!x->x_buf) return; /* this shouldn't be necesssary... */
+ x->x_updown.downsample=downsample; x->x_updown.upsample=upsample; /* IOhannes */
+ if (reblock)
+ {
+ t_signal *insig, *outsig;
+ int parentvecsize, bufsize, oldbufsize;
+ int re_parentvecsize; /* IOhannes */
+ int bigperiod, epilogphase, blockphase;
+ if (parentsigs)
+ {
+ outsig = parentsigs[outlet_getsignalindex(x->x_parentoutlet)];
+ parentvecsize = outsig->s_n;
+ re_parentvecsize = parentvecsize * upsample / downsample;
+ }
+ else
+ {
+ outsig = 0;
+ parentvecsize = 1;
+ re_parentvecsize = 1;
+ }
+ // bigperiod = (downsample * myvecsize)/(upsample * parentvecsize); /* IOhannes */
+ bigperiod = myvecsize/re_parentvecsize; /* IOhannes */
+ if (!bigperiod) bigperiod = 1;
+ epilogphase = phase & (bigperiod - 1);
+ blockphase = (phase + period - 1) & (bigperiod - 1) & (- period);
+ // bufsize = parentvecsize * upsample; /* IOhannes */
+ bufsize = re_parentvecsize; /* IOhannes */
+ if (bufsize < myvecsize) bufsize = myvecsize;
+ if (bufsize != (oldbufsize = x->x_bufsize))
+ {
+ t_float *buf = x->x_buf;
+ t_freebytes(buf, oldbufsize * sizeof(*buf));
+ buf = (t_float *)t_getbytes(bufsize * sizeof(*buf));
+ memset((char *)buf, 0, bufsize * sizeof(*buf));
+ x->x_bufsize = bufsize;
+ x->x_endbuf = buf + bufsize;
+ x->x_buf = buf;
+ }
+ /* IOhannes: { */
+ if (re_parentvecsize * period > bufsize) bug("voutlet_dspepilog");
+ x->x_write = x->x_buf + re_parentvecsize * blockphase;
+ if (x->x_write == x->x_endbuf) x->x_write = x->x_buf;
+ if (period == 1 && frequency > 1)
+ x->x_hop = re_parentvecsize / frequency;
+ else x->x_hop = period * re_parentvecsize;
+ /* } IOhannes */
+ /* post("phase %d, block %d, parent %d", phase & 63,
+ parentvecsize * blockphase, parentvecsize * epilogphase); */
+ if (parentsigs)
+ {
+ /* set epilog pointer and schedule it */
+ /* IOhannes { */
+ x->x_empty = x->x_buf + re_parentvecsize * epilogphase;
+ if (upsample * downsample == 1)
+ dsp_add(voutlet_doepilog, 3, x, outsig->s_vec, re_parentvecsize);
+ else {
+ dsp_add(voutlet_doepilog_resampling, 2, x, re_parentvecsize);
+ resampleto_dsp(&x->x_updown, outsig->s_vec, re_parentvecsize, parentvecsize, x->x_updown.method);
+ }
+ /* } IOhannes */
+ }
+ }
+ /* if we aren't blocked but we are switched, the epilog code just
+ copies zeros to the output. In this case the blocking code actually
+ jumps over the epilog if the block is running. */
+ else if (switched)
+ {
+ if (parentsigs)
+ {
+ t_signal *outsig =
+ parentsigs[outlet_getsignalindex(x->x_parentoutlet)];
+ dsp_add_zero(outsig->s_vec, outsig->s_n);
+ }
+ }
+}
+
+static void *voutlet_newsig(t_symbol *s)
+{
+ t_voutlet *x = (t_voutlet *)pd_new(voutlet_class);
+ x->x_canvas = canvas_getcurrent();
+ x->x_parentoutlet = canvas_addoutlet(x->x_canvas,
+ &x->x_obj.ob_pd, &s_signal);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ x->x_endbuf = x->x_buf = (t_float *)getbytes(0);
+ x->x_bufsize = 0;
+
+ resample_init(&x->x_updown);
+
+ /* this should be though over:
+ * it might prove hard to provide consistency between labeled up- & downsampling methods
+ * maybe indeces would be better...
+ *
+ * up till now we provide several upsampling methods and 1 single downsampling method (no filtering !)
+ */
+ if (s == gensym("hold"))x->x_updown.method=1; /* up: sample and hold */
+ else if (s == gensym("lin"))x->x_updown.method=2; /* up: linear interpolation */
+ else if (s == gensym("linear"))x->x_updown.method=2; /* up: linear interpolation */
+ else x->x_updown.method=0; /* up: zero-padding; down: ignore samples inbetween */
+
+ return (x);
+}
+
+
+static void voutlet_setup(void)
+{
+ voutlet_class = class_new(gensym("outlet"), (t_newmethod)voutlet_new,
+ (t_method)voutlet_free, sizeof(t_voutlet), CLASS_NOINLET, A_DEFSYM, 0);
+ class_addcreator((t_newmethod)voutlet_newsig, gensym("outlet~"), A_DEFSYM, 0);
+ class_addbang(voutlet_class, voutlet_bang);
+ class_addpointer(voutlet_class, voutlet_pointer);
+ class_addfloat(voutlet_class, (t_method)voutlet_float);
+ class_addsymbol(voutlet_class, voutlet_symbol);
+ class_addlist(voutlet_class, voutlet_list);
+ class_addanything(voutlet_class, voutlet_anything);
+ class_addmethod(voutlet_class, (t_method)voutlet_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(voutlet_class, gensym("pd"));
+}
+
+
+/* ---------------------------- overall setup ----------------------------- */
+
+void g_io_setup(void)
+{
+ vinlet_setup();
+ voutlet_setup();
+}
diff --git a/pd/src/g_mycanvas.c b/pd/src/g_mycanvas.c
new file mode 100644
index 00000000..edddb568
--- /dev/null
+++ b/pd/src/g_mycanvas.c
@@ -0,0 +1,439 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
+/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "m_imp.h"
+#include "g_canvas.h"
+#include "t_tk.h"
+#include "g_all_guis.h"
+#include <math.h>
+
+#ifdef NT
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+/* ---------- cnv my gui-canvas for a window ---------------- */
+
+t_widgetbehavior my_canvas_widgetbehavior;
+static t_class *my_canvas_class;
+
+/* widget helper functions */
+
+void my_canvas_draw_new(t_my_canvas *x, t_glist *glist)
+{
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -outline #%6.6x -tags %xRECT\n",
+ canvas, xpos, ypos,
+ xpos + x->x_vis_w, ypos + x->x_vis_h,
+ x->x_gui.x_bcol, x->x_gui.x_bcol, x);
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -outline #%6.6x -tags %xBASE\n",
+ canvas, xpos, ypos,
+ xpos + x->x_gui.x_w, ypos + x->x_gui.x_h,
+ x->x_gui.x_bcol, x);
+ sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
+ -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
+ canvas, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy,
+ strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
+ x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
+}
+
+void my_canvas_draw_move(t_my_canvas *x, t_glist *glist)
+{
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c coords %xRECT %d %d %d %d\n",
+ canvas, x, xpos, ypos, xpos + x->x_vis_w,
+ ypos + x->x_vis_h);
+ sys_vgui(".x%x.c coords %xBASE %d %d %d %d\n",
+ canvas, x, xpos, ypos,
+ xpos + x->x_gui.x_w, ypos + x->x_gui.x_h);
+ sys_vgui(".x%x.c coords %xLABEL %d %d\n",
+ canvas, x, xpos+x->x_gui.x_ldx,
+ ypos+x->x_gui.x_ldy);
+}
+
+void my_canvas_draw_erase(t_my_canvas* x, t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c delete %xBASE\n", canvas, x);
+ sys_vgui(".x%x.c delete %xRECT\n", canvas, x);
+ sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
+}
+
+void my_canvas_draw_config(t_my_canvas* x, t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c itemconfigure %xRECT -fill #%6.6x -outline #%6.6x\n", canvas, x,
+ x->x_gui.x_bcol, x->x_gui.x_bcol);
+ sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x,
+ x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_bcol);
+ sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
+ canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol,
+ strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
+}
+
+void my_canvas_draw_select(t_my_canvas* x, t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if(x->x_gui.x_fsf.x_selected)
+ {
+ pd_bind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+ }
+ else
+ {
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, x->x_gui.x_bcol);
+ }
+}
+
+void my_canvas_draw(t_my_canvas *x, t_glist *glist, int mode)
+{
+ if(mode == IEM_GUI_DRAW_MODE_MOVE)
+ my_canvas_draw_move(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_NEW)
+ my_canvas_draw_new(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_SELECT)
+ my_canvas_draw_select(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_ERASE)
+ my_canvas_draw_erase(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
+ my_canvas_draw_config(x, glist);
+}
+
+/* ------------------------ cnv widgetbehaviour----------------------------- */
+
+static void my_canvas_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_my_canvas *x = (t_my_canvas *)z;
+
+ *xp1 = text_xpix(&x->x_gui.x_obj, glist);
+ *yp1 = text_ypix(&x->x_gui.x_obj, glist);
+ *xp2 = *xp1 + x->x_gui.x_w;
+ *yp2 = *yp1 + x->x_gui.x_h;
+}
+
+static void my_canvas_save(t_gobj *z, t_binbuf *b)
+{
+ t_my_canvas *x = (t_my_canvas *)z;
+ int bflcol[3], *ip1, *ip2;
+ t_symbol *srl[3];
+
+ iemgui_save(&x->x_gui, srl, bflcol);
+ ip1 = (int *)(&x->x_gui.x_isa);
+ ip2 = (int *)(&x->x_gui.x_fsf);
+ binbuf_addv(b, "ssiisiiisssiiiiiii", gensym("#X"),gensym("obj"),
+ (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
+ gensym("cnv"), x->x_gui.x_w, x->x_vis_w, x->x_vis_h,
+ srl[0], srl[1], srl[2], x->x_gui.x_ldx, x->x_gui.x_ldy,
+ (*ip2)&IEM_FSTYLE_FLAGS_ALL, x->x_gui.x_fontsize,
+ bflcol[0], bflcol[2], (*ip1)&IEM_INIT_ARGS_ALL);
+ binbuf_addv(b, ";");
+}
+
+static void my_canvas_properties(t_gobj *z, t_glist *owner)
+{
+ t_my_canvas *x = (t_my_canvas *)z;
+ char buf[800];
+ t_symbol *srl[3];
+
+ iemgui_properties(&x->x_gui, srl);
+ sprintf(buf, "pdtk_iemgui_dialog %%s MY_CANVAS \
+ ------selectable_dimensions(pix):------ %d %d size: 0.0 0.0 empty \
+ ------visible_rectangle(pix)(pix):------ %d width: %d height: %d \
+ %d empty empty %d %d empty %d \
+ %s %s \
+ %s %d %d \
+ %d %d \
+ %d %d %d\n",
+ x->x_gui.x_w, 1,
+ x->x_vis_w, x->x_vis_h, 0,/*no_schedule*/
+ -1, -1, -1, -1,/*no linlog, no init, no multi*/
+ srl[0]->s_name, srl[1]->s_name,
+ srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
+ x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
+ 0xffffff & x->x_gui.x_bcol, -1/*no frontcolor*/, 0xffffff & x->x_gui.x_lcol);
+ gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
+}
+
+static void my_canvas_get_pos(t_my_canvas *x)
+{
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ {
+ x->x_at[0].a_w.w_float = text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist);
+ x->x_at[1].a_w.w_float = text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist);
+ pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
+ }
+}
+
+static void my_canvas_dialog(t_my_canvas *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_symbol *srl[3];
+ int a = (int)atom_getintarg(0, argc, argv);
+ int w = (int)atom_getintarg(2, argc, argv);
+ int h = (int)atom_getintarg(3, argc, argv);
+ int sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
+
+ x->x_gui.x_isa.x_loadinit = 0;
+ if(a < 1)
+ a = 1;
+ x->x_gui.x_w = a;
+ x->x_gui.x_h = x->x_gui.x_w;
+ if(w < 1)
+ w = 1;
+ x->x_vis_w = w;
+ if(h < 1)
+ h = 1;
+ x->x_vis_h = h;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+}
+
+static void my_canvas_size(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
+{
+ int i = (int)atom_getintarg(0, ac, av);
+
+ if(i < 1)
+ i = 1;
+ x->x_gui.x_w = i;
+ x->x_gui.x_h = i;
+ iemgui_size((void *)x, &x->x_gui);
+}
+
+static void my_canvas_delta(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
+
+static void my_canvas_pos(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
+
+static void my_canvas_vis_size(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
+{
+ int i;
+
+ i = (int)atom_getintarg(0, ac, av);
+ if(i < 1)
+ i = 1;
+ x->x_vis_w = i;
+ if(ac > 1)
+ {
+ i = (int)atom_getintarg(1, ac, av);
+ if(i < 1)
+ i = 1;
+ }
+ x->x_vis_h = i;
+ if(glist_isvisible(x->x_gui.x_glist))
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+}
+
+static void my_canvas_color(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
+
+static void my_canvas_send(t_my_canvas *x, t_symbol *s)
+{iemgui_send(x, &x->x_gui, s);}
+
+static void my_canvas_receive(t_my_canvas *x, t_symbol *s)
+{iemgui_receive(x, &x->x_gui, s);}
+
+static void my_canvas_label(t_my_canvas *x, t_symbol *s)
+{iemgui_label((void *)x, &x->x_gui, s);}
+
+static void my_canvas_label_pos(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
+
+static void my_canvas_label_font(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
+
+static void my_canvas_list(t_my_canvas *x, t_symbol *s, int ac, t_atom *av)
+{
+ int l=iemgui_list((void *)x, &x->x_gui, s, ac, av);
+
+ /*if(l < 0)
+ {
+ post("error: my_canvas: no method for 'list'");
+ }
+ else */if(l > 0)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
+ }
+}
+
+static void *my_canvas_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_my_canvas *x = (t_my_canvas *)pd_new(my_canvas_class);
+ int bflcol[]={-233017, -1, -66577};
+ t_symbol *srl[3];
+ int a=IEM_GUI_DEFAULTSIZE, w=100, h=60;
+ int ldx=20, ldy=12, f=2, i=0;
+ int fs=14, iinit=0, ifstyle=0;
+ t_iem_init_symargs *init=(t_iem_init_symargs *)(&iinit);
+ t_iem_fstyle_flags *fstyle=(t_iem_fstyle_flags *)(&ifstyle);
+ char str[144];
+
+ srl[0] = gensym("empty");
+ srl[1] = gensym("empty");
+ srl[2] = gensym("empty");
+
+ if(((argc >= 10)&&(argc <= 13))
+ &&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)&&IS_A_FLOAT(argv,2))
+ {
+ a = (int)atom_getintarg(0, argc, argv);
+ w = (int)atom_getintarg(1, argc, argv);
+ h = (int)atom_getintarg(2, argc, argv);
+ }
+ if((argc >= 12)&&(IS_A_SYMBOL(argv,3)||IS_A_FLOAT(argv,3))&&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4)))
+ {
+ i = 2;
+ if(IS_A_SYMBOL(argv,3))
+ srl[0] = atom_getsymbolarg(3, argc, argv);
+ else if(IS_A_FLOAT(argv,3))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(3, argc, argv));
+ srl[0] = gensym(str);
+ }
+ if(IS_A_SYMBOL(argv,4))
+ srl[1] = atom_getsymbolarg(4, argc, argv);
+ else if(IS_A_FLOAT(argv,4))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(4, argc, argv));
+ srl[1] = gensym(str);
+ }
+ }
+ else if((argc == 11)&&(IS_A_SYMBOL(argv,3)||IS_A_FLOAT(argv,3)))
+ {
+ i = 1;
+ if(IS_A_SYMBOL(argv,3))
+ srl[1] = atom_getsymbolarg(3, argc, argv);
+ else if(IS_A_FLOAT(argv,3))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(3, argc, argv));
+ srl[1] = gensym(str);
+ }
+ }
+
+ if(((argc >= 10)&&(argc <= 13))
+ &&(IS_A_SYMBOL(argv,i+3)||IS_A_FLOAT(argv,i+3))&&IS_A_FLOAT(argv,i+4)
+ &&IS_A_FLOAT(argv,i+5)&&IS_A_FLOAT(argv,i+6)
+ &&IS_A_FLOAT(argv,i+7)&&IS_A_FLOAT(argv,i+8)
+ &&IS_A_FLOAT(argv,i+9))
+ {
+ if(IS_A_SYMBOL(argv,i+3))
+ srl[2] = atom_getsymbolarg(i+3, argc, argv);
+ else if(IS_A_FLOAT(argv,i+3))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(i+3, argc, argv));
+ srl[2] = gensym(str);
+ }
+ ldx = (int)atom_getintarg(i+4, argc, argv);
+ ldy = (int)atom_getintarg(i+5, argc, argv);
+ ifstyle = (int)atom_getintarg(i+6, argc, argv);
+ fs = (int)atom_getintarg(i+7, argc, argv);
+ bflcol[0] = (int)atom_getintarg(i+8, argc, argv);
+ bflcol[2] = (int)atom_getintarg(i+9, argc, argv);
+ }
+ if((argc == 13)&&IS_A_FLOAT(argv,i+10))
+ {
+ iinit = (int)(atom_getintarg(i+10, argc, argv));
+ }
+ x->x_gui.x_draw = (t_iemfunptr)my_canvas_draw;
+ iinit &= IEM_INIT_ARGS_ALL;
+ ifstyle &= IEM_FSTYLE_FLAGS_ALL;
+ fstyle->x_snd_able = 1;
+ fstyle->x_rcv_able = 1;
+ x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
+ x->x_gui.x_isa = *init;
+ if(!strcmp(srl[0]->s_name, "empty")) fstyle->x_snd_able = 0;
+ if(!strcmp(srl[1]->s_name, "empty")) fstyle->x_rcv_able = 0;
+ x->x_gui.x_unique_num = 0;
+ if(a < 1)
+ a = 1;
+ x->x_gui.x_w = a;
+ x->x_gui.x_h = x->x_gui.x_w;
+ if(w < 1)
+ w = 1;
+ x->x_vis_w = w;
+ if(h < 1)
+ h = 1;
+ x->x_vis_h = h;
+ if(fstyle->x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
+ else if(fstyle->x_font_style == 2) strcpy(x->x_gui.x_font, "times");
+ else { fstyle->x_font_style = 0;
+ strcpy(x->x_gui.x_font, "courier"); }
+ x->x_gui.x_fsf = *fstyle;
+ iemgui_first_dollararg2sym(&x->x_gui, srl);
+ if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, srl[1]);
+ x->x_gui.x_snd = srl[0];
+ x->x_gui.x_rcv = srl[1];
+ x->x_gui.x_lab = srl[2];
+ x->x_gui.x_ldx = ldx;
+ x->x_gui.x_ldy = ldy;
+ if(fs < 4)
+ fs = 4;
+ x->x_gui.x_fontsize = fs;
+ iemgui_all_colfromload(&x->x_gui, bflcol);
+ x->x_at[0].a_type = A_FLOAT;
+ x->x_at[1].a_type = A_FLOAT;
+ iemgui_verify_snd_ne_rcv(&x->x_gui);
+ return (x);
+}
+
+static void my_canvas_ff(t_my_canvas *x)
+{
+ if(x->x_gui.x_fsf.x_selected)
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ if(x->x_gui.x_fsf.x_rcv_able)
+ pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
+ gfxstub_deleteforkey(x);
+}
+
+void g_mycanvas_setup(void)
+{
+ my_canvas_class = class_new(gensym("cnv"), (t_newmethod)my_canvas_new,
+ (t_method)my_canvas_ff, sizeof(t_my_canvas), CLASS_NOINLET, A_GIMME, 0);
+ class_addcreator((t_newmethod)my_canvas_new, gensym("my_canvas"), A_GIMME, 0);
+ class_addlist(my_canvas_class, my_canvas_list);
+ class_addmethod(my_canvas_class, (t_method)my_canvas_dialog, gensym("dialog"), A_GIMME, 0);
+ class_addmethod(my_canvas_class, (t_method)my_canvas_size, gensym("size"), A_GIMME, 0);
+ class_addmethod(my_canvas_class, (t_method)my_canvas_delta, gensym("delta"), A_GIMME, 0);
+ class_addmethod(my_canvas_class, (t_method)my_canvas_pos, gensym("pos"), A_GIMME, 0);
+ class_addmethod(my_canvas_class, (t_method)my_canvas_vis_size, gensym("vis_size"), A_GIMME, 0);
+ class_addmethod(my_canvas_class, (t_method)my_canvas_color, gensym("color"), A_GIMME, 0);
+ class_addmethod(my_canvas_class, (t_method)my_canvas_send, gensym("send"), A_DEFSYM, 0);
+ class_addmethod(my_canvas_class, (t_method)my_canvas_receive, gensym("receive"), A_DEFSYM, 0);
+ class_addmethod(my_canvas_class, (t_method)my_canvas_label, gensym("label"), A_DEFSYM, 0);
+ class_addmethod(my_canvas_class, (t_method)my_canvas_label_pos, gensym("label_pos"), A_GIMME, 0);
+ class_addmethod(my_canvas_class, (t_method)my_canvas_label_font, gensym("label_font"), A_GIMME, 0);
+ class_addmethod(my_canvas_class, (t_method)my_canvas_get_pos, gensym("get_pos"), 0);
+
+ if(!iemgui_key_sym)
+ iemgui_key_sym = gensym("#keyname");
+ my_canvas_widgetbehavior.w_getrectfn = my_canvas_getrect;
+ my_canvas_widgetbehavior.w_displacefn = iemgui_displace;
+ my_canvas_widgetbehavior.w_selectfn = iemgui_select;
+ my_canvas_widgetbehavior.w_activatefn = NULL;
+ my_canvas_widgetbehavior.w_deletefn = iemgui_delete;
+ my_canvas_widgetbehavior.w_visfn = iemgui_vis;
+ my_canvas_widgetbehavior.w_clickfn = NULL;
+ my_canvas_widgetbehavior.w_propertiesfn = my_canvas_properties;
+ my_canvas_widgetbehavior.w_savefn = my_canvas_save;
+ class_setwidget(my_canvas_class, &my_canvas_widgetbehavior);
+ class_sethelpsymbol(my_canvas_class, gensym("my_canvas"));
+}
diff --git a/pd/src/g_numbox.c b/pd/src/g_numbox.c
new file mode 100644
index 00000000..e0967b5b
--- /dev/null
+++ b/pd/src/g_numbox.c
@@ -0,0 +1,979 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* my_numbox.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "m_imp.h"
+#include "g_canvas.h"
+#include "t_tk.h"
+#include "g_all_guis.h"
+#include <math.h>
+
+#ifdef NT
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+/*------------------ global varaibles -------------------------*/
+
+
+/*------------------ global functions -------------------------*/
+
+
+/* ------------ nmx gui-my number box ----------------------- */
+
+t_widgetbehavior my_numbox_widgetbehavior;
+static t_class *my_numbox_class;
+
+/* widget helper functions */
+
+static void my_numbox_tick_reset(t_my_numbox *x)
+{
+ if(x->x_gui.x_fsf.x_change)
+ {
+ x->x_gui.x_fsf.x_change = 0;
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ }
+}
+
+static void my_numbox_tick_wait(t_my_numbox *x)
+{
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+}
+
+void my_numbox_clip(t_my_numbox *x)
+{
+ if(x->x_val < x->x_min)
+ x->x_val = x->x_min;
+ if(x->x_val > x->x_max)
+ x->x_val = x->x_max;
+}
+
+void my_numbox_calc_fontwidth(t_my_numbox *x)
+{
+ int w, f=31;
+
+ if(x->x_gui.x_fsf.x_font_style == 1)
+ f = 27;
+ else if(x->x_gui.x_fsf.x_font_style == 2)
+ f = 25;
+
+ w = x->x_gui.x_fontsize * f * x->x_gui.x_w;
+ w /= 36;
+ x->x_numwidth = w + (x->x_gui.x_h / 2) + 4;
+}
+
+void my_numbox_ftoa(t_my_numbox *x)
+{
+ double f=x->x_val;
+ int bufsize, is_exp=0, i, idecimal;
+
+ sprintf(x->x_buf, "%g", f);
+ bufsize = strlen(x->x_buf);
+ if(bufsize >= 5)/* if it is in exponential mode */
+ {
+ i = bufsize - 4;
+ if((x->x_buf[i] == 'e') || (x->x_buf[i] == 'E'))
+ is_exp = 1;
+ }
+ if(bufsize > x->x_gui.x_w)/* if to reduce */
+ {
+ if(is_exp)
+ {
+ if(x->x_gui.x_w <= 5)
+ {
+ x->x_buf[0] = (f < 0.0 ? '-' : '+');
+ x->x_buf[1] = 0;
+ }
+ i = bufsize - 4;
+ for(idecimal=0; idecimal < i; idecimal++)
+ if(x->x_buf[idecimal] == '.')
+ break;
+ if(idecimal > (x->x_gui.x_w - 4))
+ {
+ x->x_buf[0] = (f < 0.0 ? '-' : '+');
+ x->x_buf[1] = 0;
+ }
+ else
+ {
+ int new_exp_index=x->x_gui.x_w-4, old_exp_index=bufsize-4;
+
+ for(i=0; i < 4; i++, new_exp_index++, old_exp_index++)
+ x->x_buf[new_exp_index] = x->x_buf[old_exp_index];
+ x->x_buf[x->x_gui.x_w] = 0;
+ }
+
+ }
+ else
+ {
+ for(idecimal=0; idecimal < bufsize; idecimal++)
+ if(x->x_buf[idecimal] == '.')
+ break;
+ if(idecimal > x->x_gui.x_w)
+ {
+ x->x_buf[0] = (f < 0.0 ? '-' : '+');
+ x->x_buf[1] = 0;
+ }
+ else
+ x->x_buf[x->x_gui.x_w] = 0;
+ }
+ }
+}
+
+static void my_numbox_draw_update(t_my_numbox *x, t_glist *glist)
+{
+ if (glist_isvisible(glist))
+ {
+ if(x->x_gui.x_fsf.x_change)
+ {
+ if(x->x_buf[0])
+ {
+ char *cp=x->x_buf;
+ int sl = strlen(x->x_buf);
+
+ x->x_buf[sl] = '>';
+ x->x_buf[sl+1] = 0;
+ if(sl >= x->x_gui.x_w)
+ cp += sl - x->x_gui.x_w + 1;
+ sys_vgui(".x%x.c itemconfigure %xNUMBER -fill #%6.6x -text {%s} \n",
+ glist_getcanvas(glist), x, IEM_GUI_COLOR_EDITED, cp);
+ x->x_buf[sl] = 0;
+ }
+ else
+ {
+ my_numbox_ftoa(x);
+ sys_vgui(".x%x.c itemconfigure %xNUMBER -fill #%6.6x -text {%s} \n",
+ glist_getcanvas(glist), x, IEM_GUI_COLOR_EDITED, x->x_buf);
+ x->x_buf[0] = 0;
+ }
+ }
+ else
+ {
+ my_numbox_ftoa(x);
+ sys_vgui(".x%x.c itemconfigure %xNUMBER -fill #%6.6x -text {%s} \n",
+ glist_getcanvas(glist), x,
+ x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_fcol,
+ x->x_buf);
+ x->x_buf[0] = 0;
+ }
+ }
+}
+
+static void my_numbox_draw_new(t_my_numbox *x, t_glist *glist)
+{
+ int half=x->x_gui.x_h/2, d=1+x->x_gui.x_h/34;
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c create polygon %d %d %d %d %d %d %d %d %d %d -outline #%6.6x -fill #%6.6x -tags %xBASE1\n",
+ canvas, xpos, ypos,
+ xpos + x->x_numwidth-4, ypos,
+ xpos + x->x_numwidth, ypos+4,
+ xpos + x->x_numwidth, ypos + x->x_gui.x_h,
+ xpos, ypos + x->x_gui.x_h,
+ IEM_GUI_COLOR_NORMAL, x->x_gui.x_bcol, x);
+ sys_vgui(".x%x.c create line %d %d %d %d %d %d -fill #%6.6x -tags %xBASE2\n",
+ canvas, xpos, ypos,
+ xpos + half, ypos + half,
+ xpos, ypos + x->x_gui.x_h,
+ x->x_gui.x_fcol, x);
+ sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
+ -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
+ canvas, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy,
+ strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
+ x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
+ my_numbox_ftoa(x);
+ sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
+ -font {%s %d bold} -fill #%6.6x -tags %xNUMBER\n",
+ canvas, xpos+half+2, ypos+half+d,
+ x->x_buf, x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_fcol, x);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+ canvas,
+ xpos, ypos + x->x_gui.x_h-1,
+ xpos+IOWIDTH, ypos + x->x_gui.x_h,
+ x, 0);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
+ canvas,
+ xpos, ypos,
+ xpos+IOWIDTH, ypos+1,
+ x, 0);
+}
+
+static void my_numbox_draw_move(t_my_numbox *x, t_glist *glist)
+{
+ int half = x->x_gui.x_h/2, d=1+x->x_gui.x_h/34;
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c coords %xBASE1 %d %d %d %d %d %d %d %d %d %d\n",
+ canvas, x, xpos, ypos,
+ xpos + x->x_numwidth-4, ypos,
+ xpos + x->x_numwidth, ypos+4,
+ xpos + x->x_numwidth, ypos + x->x_gui.x_h,
+ xpos, ypos + x->x_gui.x_h);
+ sys_vgui(".x%x.c coords %xBASE2 %d %d %d %d %d %d\n",
+ canvas, x, xpos, ypos,
+ xpos + half, ypos + half,
+ xpos, ypos + x->x_gui.x_h);
+ sys_vgui(".x%x.c coords %xLABEL %d %d\n",
+ canvas, x, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy);
+ sys_vgui(".x%x.c coords %xNUMBER %d %d\n",
+ canvas, x, xpos+half+2, ypos+half+d);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
+ canvas, x, 0,
+ xpos, ypos + x->x_gui.x_h-1,
+ xpos+IOWIDTH, ypos + x->x_gui.x_h);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
+ canvas, x, 0,
+ xpos, ypos,
+ xpos+IOWIDTH, ypos+1);
+}
+
+static void my_numbox_draw_erase(t_my_numbox* x,t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c delete %xBASE1\n", canvas, x);
+ sys_vgui(".x%x.c delete %xBASE2\n", canvas, x);
+ sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
+ sys_vgui(".x%x.c delete %xNUMBER\n", canvas, x);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
+}
+
+static void my_numbox_draw_config(t_my_numbox* x,t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
+ canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
+ x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
+ strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
+ sys_vgui(".x%x.c itemconfigure %xNUMBER -font {%s %d bold} -fill #%6.6x \n",
+ canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
+ x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_fcol);
+ sys_vgui(".x%x.c itemconfigure %xBASE1 -fill #%6.6x\n", canvas,
+ x, x->x_gui.x_bcol);
+ sys_vgui(".x%x.c itemconfigure %xBASE2 -fill #%6.6x\n", canvas,
+ x, x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_fcol);
+}
+
+static void my_numbox_draw_io(t_my_numbox* x,t_glist* glist, int old_snd_rcv_flags)
+{
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+ canvas,
+ xpos, ypos + x->x_gui.x_h-1,
+ xpos+IOWIDTH, ypos + x->x_gui.x_h,
+ x, 0);
+ if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
+ if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
+ canvas,
+ xpos, ypos,
+ xpos+IOWIDTH, ypos+1,
+ x, 0);
+ if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
+}
+
+static void my_numbox_draw_select(t_my_numbox *x, t_glist *glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if(x->x_gui.x_fsf.x_selected)
+ {
+ if(x->x_gui.x_fsf.x_change)
+ {
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ x->x_gui.x_fsf.x_change = 0;
+ clock_unset(x->x_clock_reset);
+ x->x_buf[0] = 0;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ }
+ pd_bind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ sys_vgui(".x%x.c itemconfigure %xBASE1 -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+ sys_vgui(".x%x.c itemconfigure %xBASE2 -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+ sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+ sys_vgui(".x%x.c itemconfigure %xNUMBER -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+ }
+ else
+ {
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ sys_vgui(".x%x.c itemconfigure %xBASE1 -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
+ sys_vgui(".x%x.c itemconfigure %xBASE2 -fill #%6.6x\n", canvas, x, x->x_gui.x_fcol);
+ sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol);
+ sys_vgui(".x%x.c itemconfigure %xNUMBER -fill #%6.6x\n", canvas, x, x->x_gui.x_fcol);
+ }
+}
+
+void my_numbox_draw(t_my_numbox *x, t_glist *glist, int mode)
+{
+ if(mode == IEM_GUI_DRAW_MODE_UPDATE)
+ my_numbox_draw_update(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_MOVE)
+ my_numbox_draw_move(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_NEW)
+ my_numbox_draw_new(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_SELECT)
+ my_numbox_draw_select(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_ERASE)
+ my_numbox_draw_erase(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
+ my_numbox_draw_config(x, glist);
+ else if(mode >= IEM_GUI_DRAW_MODE_IO)
+ my_numbox_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
+}
+
+/* ------------------------ nbx widgetbehaviour----------------------------- */
+
+
+static void my_numbox_getrect(t_gobj *z, t_glist *glist,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_my_numbox* x = (t_my_numbox*)z;
+
+ *xp1 = text_xpix(&x->x_gui.x_obj, glist);
+ *yp1 = text_ypix(&x->x_gui.x_obj, glist);
+ *xp2 = *xp1 + x->x_numwidth;
+ *yp2 = *yp1 + x->x_gui.x_h;
+}
+
+static void my_numbox_save(t_gobj *z, t_binbuf *b)
+{
+ t_my_numbox *x = (t_my_numbox *)z;
+ int bflcol[3], *ip1, *ip2;
+ t_symbol *srl[3];
+
+ iemgui_save(&x->x_gui, srl, bflcol);
+ if(x->x_gui.x_fsf.x_change)
+ {
+ x->x_gui.x_fsf.x_change = 0;
+ clock_unset(x->x_clock_reset);
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+
+ }
+ ip1 = (int *)(&x->x_gui.x_isa);
+ ip2 = (int *)(&x->x_gui.x_fsf);
+ binbuf_addv(b, "ssiisiiffiisssiiiiiiifi", gensym("#X"),gensym("obj"),
+ (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
+ gensym("nbx"), x->x_gui.x_w, x->x_gui.x_h,
+ (float)x->x_min, (float)x->x_max,
+ x->x_lin0_log1, (*ip1)&IEM_INIT_ARGS_ALL,
+ srl[0], srl[1], srl[2],
+ x->x_gui.x_ldx, x->x_gui.x_ldy,
+ (*ip2)&IEM_FSTYLE_FLAGS_ALL, x->x_gui.x_fontsize,
+ bflcol[0], bflcol[1], bflcol[2],
+ x->x_val, x->x_log_height);
+ binbuf_addv(b, ";");
+}
+
+int my_numbox_check_minmax(t_my_numbox *x, double min, double max)
+{
+ int ret=0;
+
+ if(x->x_lin0_log1)
+ {
+ if((min == 0.0)&&(max == 0.0))
+ max = 1.0;
+ if(max > 0.0)
+ {
+ if(min <= 0.0)
+ min = 0.01*max;
+ }
+ else
+ {
+ if(min > 0.0)
+ max = 0.01*min;
+ }
+ }
+ x->x_min = min;
+ x->x_max = max;
+ if(x->x_val < x->x_min)
+ {
+ x->x_val = x->x_min;
+ ret = 1;
+ }
+ if(x->x_val > x->x_max)
+ {
+ x->x_val = x->x_max;
+ ret = 1;
+ }
+ if(x->x_lin0_log1)
+ x->x_k = exp(log(x->x_max/x->x_min)/(double)(x->x_log_height));
+ else
+ x->x_k = 1.0;
+ return(ret);
+}
+
+static void my_numbox_properties(t_gobj *z, t_glist *owner)
+{
+ t_my_numbox *x = (t_my_numbox *)z;
+ char buf[800];
+ t_symbol *srl[3];
+
+ iemgui_properties(&x->x_gui, srl);
+ if(x->x_gui.x_fsf.x_change)
+ {
+ x->x_gui.x_fsf.x_change = 0;
+ clock_unset(x->x_clock_reset);
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+
+ }
+ sprintf(buf, "pdtk_iemgui_dialog %%s NUMBERBOX \
+ -------dimensions(digits)(pix):------- %d %d width: %d %d height: \
+ -----------output-range:----------- %g min: %g max: %d \
+ %d lin log %d %d log-height: %d \
+ %s %s \
+ %s %d %d \
+ %d %d \
+ %d %d %d\n",
+ x->x_gui.x_w, 1, x->x_gui.x_h, 8,
+ x->x_min, x->x_max, 0,/*no_schedule*/
+ x->x_lin0_log1, x->x_gui.x_isa.x_loadinit, -1, x->x_log_height,/*no multi, but iem-characteristic*/
+ srl[0]->s_name, srl[1]->s_name,
+ srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
+ x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
+ 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
+ gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
+}
+
+static void my_numbox_bang(t_my_numbox *x)
+{
+ outlet_float(x->x_gui.x_obj.ob_outlet, x->x_val);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_float(x->x_gui.x_snd->s_thing, x->x_val);
+}
+
+static void my_numbox_dialog(t_my_numbox *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_symbol *srl[3];
+ int w = (int)atom_getintarg(0, argc, argv);
+ int h = (int)atom_getintarg(1, argc, argv);
+ double min = (double)atom_getfloatarg(2, argc, argv);
+ double max = (double)atom_getfloatarg(3, argc, argv);
+ int lilo = (int)atom_getintarg(4, argc, argv);
+ int log_height = (int)atom_getintarg(6, argc, argv);
+ int sr_flags;
+
+ if(lilo != 0) lilo = 1;
+ x->x_lin0_log1 = lilo;
+ sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
+ if(w < 1)
+ w = 1;
+ x->x_gui.x_w = w;
+ if(h < 8)
+ h = 8;
+ x->x_gui.x_h = h;
+ if(log_height < 10)
+ log_height = 10;
+ x->x_log_height = log_height;
+ my_numbox_calc_fontwidth(x);
+ /*if(my_numbox_check_minmax(x, min, max))
+ my_numbox_bang(x);*/
+ my_numbox_check_minmax(x, min, max);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
+}
+
+static void my_numbox_motion(t_my_numbox *x, t_floatarg dx, t_floatarg dy)
+{
+ double k2=1.0;
+
+ if(x->x_gui.x_fsf.x_finemoved)
+ k2 = 0.01;
+ if(x->x_lin0_log1)
+ x->x_val *= pow(x->x_k, -k2*dy);
+ else
+ x->x_val -= k2*dy;
+ my_numbox_clip(x);
+ if(x->x_gui.x_fsf.x_change)
+ {
+ x->x_gui.x_fsf.x_change = 0;
+ clock_unset(x->x_clock_reset);
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+
+ }
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ my_numbox_bang(x);
+}
+
+static void my_numbox_click(t_my_numbox *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g, (t_glistmotionfn)my_numbox_motion,
+ 0, xpos, ypos);
+}
+
+static int my_numbox_newclick(t_gobj *z, struct _glist *glist,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ t_my_numbox* x = (t_my_numbox *)z;
+
+ if(doit)
+ {
+ my_numbox_click( x, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift,
+ 0, (t_floatarg)alt);
+ if(shift)
+ x->x_gui.x_fsf.x_finemoved = 1;
+ else
+ x->x_gui.x_fsf.x_finemoved = 0;
+ if(!x->x_gui.x_fsf.x_change)
+ {
+ clock_delay(x->x_clock_wait, 50);
+ x->x_gui.x_fsf.x_change = 1;
+ clock_delay(x->x_clock_reset, 3000);
+ pd_bind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ x->x_buf[0] = 0;
+ }
+ else
+ {
+ x->x_gui.x_fsf.x_change = 0;
+ clock_unset(x->x_clock_reset);
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ x->x_buf[0] = 0;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ }
+ }
+ return (1);
+}
+
+static void my_numbox_set(t_my_numbox *x, t_floatarg f)
+{
+ x->x_val = f;
+ my_numbox_clip(x);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+}
+
+static void my_numbox_log_height(t_my_numbox *x, t_floatarg lh)
+{
+ if(lh < 10.0)
+ lh = 10.0;
+ x->x_log_height = (int)lh;
+ if(x->x_lin0_log1)
+ x->x_k = exp(log(x->x_max/x->x_min)/(double)(x->x_log_height));
+ else
+ x->x_k = 1.0;
+
+}
+
+static void my_numbox_float(t_my_numbox *x, t_floatarg f)
+{
+ my_numbox_set(x, f);
+ if(x->x_gui.x_fsf.x_put_in2out)
+ my_numbox_bang(x);
+}
+
+static void my_numbox_size(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
+{
+ int h, w;
+
+ w = (int)atom_getintarg(0, ac, av);
+ if(w < 1)
+ w = 1;
+ x->x_gui.x_w = w;
+ if(ac > 1)
+ {
+ h = (int)atom_getintarg(1, ac, av);
+ if(h < 8)
+ h = 8;
+ x->x_gui.x_h = h;
+ }
+ my_numbox_calc_fontwidth(x);
+ iemgui_size((void *)x, &x->x_gui);
+}
+
+static void my_numbox_delta(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
+
+static void my_numbox_pos(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
+
+static void my_numbox_range(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
+{
+ if(my_numbox_check_minmax(x, (double)atom_getfloatarg(0, ac, av),
+ (double)atom_getfloatarg(1, ac, av)))
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ /*my_numbox_bang(x);*/
+ }
+}
+
+static void my_numbox_color(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
+
+static void my_numbox_send(t_my_numbox *x, t_symbol *s)
+{iemgui_send(x, &x->x_gui, s);}
+
+static void my_numbox_receive(t_my_numbox *x, t_symbol *s)
+{iemgui_receive(x, &x->x_gui, s);}
+
+static void my_numbox_label(t_my_numbox *x, t_symbol *s)
+{iemgui_label((void *)x, &x->x_gui, s);}
+
+static void my_numbox_label_pos(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
+
+static void my_numbox_label_font(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
+{
+ int f = (int)atom_getintarg(1, ac, av);
+
+ if(f < 4)
+ f = 4;
+ x->x_gui.x_fontsize = f;
+ f = (int)atom_getintarg(0, ac, av);
+ if((f < 0) || (f > 2))
+ f = 0;
+ x->x_gui.x_fsf.x_font_style = f;
+ my_numbox_calc_fontwidth(x);
+ iemgui_label_font((void *)x, &x->x_gui, s, ac, av);
+}
+
+static void my_numbox_log(t_my_numbox *x)
+{
+ x->x_lin0_log1 = 1;
+ if(my_numbox_check_minmax(x, x->x_min, x->x_max))
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ /*my_numbox_bang(x);*/
+ }
+}
+
+static void my_numbox_lin(t_my_numbox *x)
+{
+ x->x_lin0_log1 = 0;
+}
+
+static void my_numbox_init(t_my_numbox *x, t_floatarg f)
+{
+ x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
+}
+
+static void my_numbox_loadbang(t_my_numbox *x)
+{
+ if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ my_numbox_bang(x);
+ }
+}
+
+static void my_numbox_list(t_my_numbox *x, t_symbol *s, int ac, t_atom *av)
+{
+ int l=-1;
+
+ if(x->x_gui.x_fsf.x_selected)
+ {
+ if((ac == 2)&&IS_A_FLOAT(av,0)&&IS_A_SYMBOL(av,1))
+ {
+ t_symbol *key = atom_getsymbolarg(1, ac, av);
+ int keydown = atom_getintarg(0, ac, av);
+
+ if(keydown)
+ {
+ int refresh = 1,i,d=1;
+ static char buf[20];
+
+ buf[0] = 0;
+ if(!strcmp(key->s_name, "Shift_L")||!strcmp(key->s_name, "Shift_R"))
+ x->x_gui.x_fsf.x_shiftdown = 1;
+ else
+ {
+ if(x->x_gui.x_fsf.x_shiftdown)
+ d = 10;
+ if(!strcmp(key->s_name, "Up"))
+ x->x_gui.x_obj.te_ypix -= d;
+ else if(!strcmp(key->s_name, "Down"))
+ x->x_gui.x_obj.te_ypix += d;
+ else if(!strcmp(key->s_name, "Left"))
+ x->x_gui.x_obj.te_xpix -= d;
+ else if(!strcmp(key->s_name, "Right"))
+ x->x_gui.x_obj.te_xpix += d;
+ else
+ refresh = 0;
+ if(refresh)
+ l = 1;
+ }
+ l = 0;
+ }
+ else
+ {
+ if(!strcmp(key->s_name, "Shift_L")||!strcmp(key->s_name, "Shift_R"))
+ x->x_gui.x_fsf.x_shiftdown = 0;
+ l = 0;
+ }
+ }
+ }
+ else
+ {
+ if(x->x_gui.x_fsf.x_change)
+ {
+ if((ac == 2)&&IS_A_FLOAT(av,0)&&IS_A_SYMBOL(av,1))
+ {
+ t_symbol *key = atom_getsymbolarg(1, ac, av);
+ int keydown = atom_getintarg(0, ac, av);
+ char buf[3];
+
+ buf[1] = 0;
+ if(keydown)
+ {
+ char *c=key->s_name;
+
+ l = 0;
+ if(((*c>='0')&&(*c<='9'))||(*c=='.')||(*c=='-')||(*c=='e')||(*c=='+')||(*c=='E'))
+ {
+ if(strlen(x->x_buf) < (IEMGUI_MAX_NUM_LEN-2))
+ {
+ buf[0] = *c;
+ strcat(x->x_buf, buf);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ }
+ }
+ else if((*c=='\b')||(*c==127))
+ {
+ int sl=strlen(x->x_buf)-1;
+
+ if(sl < 0)
+ sl = 0;
+ x->x_buf[sl] = 0;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ }
+ else if((*c=='\n')||(*c==13))
+ {
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ x->x_val = atof(x->x_buf);
+ x->x_buf[0] = 0;
+ x->x_gui.x_fsf.x_change = 0;
+ clock_unset(x->x_clock_reset);
+ my_numbox_clip(x);
+ my_numbox_bang(x);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ }
+ clock_delay(x->x_clock_reset, 3000);
+ }
+ else
+ {
+ l = 0;
+ }
+ }
+ }
+ }
+ if(l < 0)
+ {
+ if(IS_A_FLOAT(av,0))
+ {
+ my_numbox_set(x, atom_getfloatarg(0, ac, av));
+ my_numbox_bang(x);
+ }
+ }
+ else if(l > 0)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
+ }
+}
+
+static void *my_numbox_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_my_numbox *x = (t_my_numbox *)pd_new(my_numbox_class);
+ int bflcol[]={-262144, -1, -1};
+ t_symbol *srl[3];
+ int w=5, h=14;
+ int lilo=0, f=0, ldx=0, ldy=-6;
+ int fs=10, iinit=0, ifstyle=0;
+ int log_height=256;
+ double min=-1.0e+37, max=1.0e+37,v=0.0;
+ t_iem_init_symargs *init=(t_iem_init_symargs *)(&iinit);
+ t_iem_fstyle_flags *fstyle=(t_iem_fstyle_flags *)(&ifstyle);
+ char str[144];
+
+ srl[0] = gensym("empty");
+ srl[1] = gensym("empty");
+ srl[2] = gensym("empty");
+
+
+ if((argc >= 17)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)
+ &&IS_A_FLOAT(argv,2)&&IS_A_FLOAT(argv,3)
+ &&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5)
+ &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
+ &&(IS_A_SYMBOL(argv,7)||IS_A_FLOAT(argv,7))
+ &&(IS_A_SYMBOL(argv,8)||IS_A_FLOAT(argv,8))
+ &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)
+ &&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)
+ &&IS_A_FLOAT(argv,14)&&IS_A_FLOAT(argv,15)&&IS_A_FLOAT(argv,16))
+ {
+ w = (int)atom_getintarg(0, argc, argv);
+ h = (int)atom_getintarg(1, argc, argv);
+ min = (double)atom_getfloatarg(2, argc, argv);
+ max = (double)atom_getfloatarg(3, argc, argv);
+ lilo = (int)atom_getintarg(4, argc, argv);
+ iinit = (int)atom_getintarg(5, argc, argv);
+ srl[0] = atom_getsymbolarg(6, argc, argv);
+ srl[1] = atom_getsymbolarg(7, argc, argv);
+ srl[2] = atom_getsymbolarg(8, argc, argv);
+ if(IS_A_SYMBOL(argv,6))
+ srl[0] = atom_getsymbolarg(6, argc, argv);
+ else if(IS_A_FLOAT(argv,6))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(6, argc, argv));
+ srl[0] = gensym(str);
+ }
+ if(IS_A_SYMBOL(argv,7))
+ srl[1] = atom_getsymbolarg(7, argc, argv);
+ else if(IS_A_FLOAT(argv,7))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(7, argc, argv));
+ srl[1] = gensym(str);
+ }
+ if(IS_A_SYMBOL(argv,8))
+ srl[2] = atom_getsymbolarg(8, argc, argv);
+ else if(IS_A_FLOAT(argv,8))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(8, argc, argv));
+ srl[2] = gensym(str);
+ }
+ ldx = (int)atom_getintarg(9, argc, argv);
+ ldy = (int)atom_getintarg(10, argc, argv);
+ ifstyle = (int)atom_getintarg(11, argc, argv);
+ fs = (int)atom_getintarg(12, argc, argv);
+ bflcol[0] = (int)atom_getintarg(13, argc, argv);
+ bflcol[1] = (int)atom_getintarg(14, argc, argv);
+ bflcol[2] = (int)atom_getintarg(15, argc, argv);
+ v = atom_getfloatarg(16, argc, argv);
+ }
+ if((argc == 18)&&IS_A_FLOAT(argv,17))
+ {
+ log_height = (int)atom_getintarg(17, argc, argv);
+ }
+ x->x_gui.x_draw = (t_iemfunptr)my_numbox_draw;
+ iinit &= IEM_INIT_ARGS_ALL;
+ ifstyle &= IEM_FSTYLE_FLAGS_ALL;
+ fstyle->x_snd_able = 1;
+ fstyle->x_rcv_able = 1;
+ x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
+ x->x_gui.x_isa = *init;
+ if(x->x_gui.x_isa.x_loadinit)
+ x->x_val = v;
+ else
+ x->x_val = 0.0;
+ if(lilo != 0) lilo = 1;
+ x->x_lin0_log1 = lilo;
+ if(log_height < 10)
+ log_height = 10;
+ x->x_log_height = log_height;
+ if(!strcmp(srl[0]->s_name, "empty")) fstyle->x_snd_able = 0;
+ if(!strcmp(srl[1]->s_name, "empty")) fstyle->x_rcv_able = 0;
+ x->x_gui.x_unique_num = 0;
+ if(fstyle->x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
+ else if(fstyle->x_font_style == 2) strcpy(x->x_gui.x_font, "times");
+ else { fstyle->x_font_style = 0;
+ strcpy(x->x_gui.x_font, "courier"); }
+ x->x_gui.x_fsf = *fstyle;
+ iemgui_first_dollararg2sym(&x->x_gui, srl);
+ if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, srl[1]);
+ x->x_gui.x_snd = srl[0];
+ x->x_gui.x_rcv = srl[1];
+ x->x_gui.x_lab = srl[2];
+ x->x_gui.x_ldx = ldx;
+ x->x_gui.x_ldy = ldy;
+ if(fs < 4)
+ fs = 4;
+ x->x_gui.x_fontsize = fs;
+ if(w < 1)
+ w = 1;
+ x->x_gui.x_w = w;
+ if(h < 8)
+ h = 8;
+ x->x_gui.x_h = h;
+ x->x_buf[0] = 0;
+ my_numbox_calc_fontwidth(x);
+ my_numbox_check_minmax(x, min, max);
+ iemgui_all_colfromload(&x->x_gui, bflcol);
+ iemgui_verify_snd_ne_rcv(&x->x_gui);
+ x->x_clock_reset = clock_new(x, (t_method)my_numbox_tick_reset);
+ x->x_clock_wait = clock_new(x, (t_method)my_numbox_tick_wait);
+ x->x_gui.x_fsf.x_change = 0;
+ outlet_new(&x->x_gui.x_obj, &s_float);
+ return (x);
+}
+
+static void my_numbox_free(t_my_numbox *x)
+{
+ if(x->x_gui.x_fsf.x_selected)
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ if(x->x_gui.x_fsf.x_rcv_able)
+ pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
+ clock_free(x->x_clock_reset);
+ clock_free(x->x_clock_wait);
+ gfxstub_deleteforkey(x);
+}
+
+void g_numbox_setup(void)
+{
+ my_numbox_class = class_new(gensym("nbx"), (t_newmethod)my_numbox_new,
+ (t_method)my_numbox_free, sizeof(t_my_numbox), 0, A_GIMME, 0);
+ class_addcreator((t_newmethod)my_numbox_new, gensym("my_numbox"), A_GIMME, 0);
+ class_addbang(my_numbox_class,my_numbox_bang);
+ class_addfloat(my_numbox_class,my_numbox_float);
+ class_addlist(my_numbox_class, my_numbox_list);
+ class_addmethod(my_numbox_class, (t_method)my_numbox_click, gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(my_numbox_class, (t_method)my_numbox_motion, gensym("motion"),
+ A_FLOAT, A_FLOAT, 0);
+ class_addmethod(my_numbox_class, (t_method)my_numbox_dialog, gensym("dialog"),
+ A_GIMME, 0);
+ class_addmethod(my_numbox_class, (t_method)my_numbox_loadbang, gensym("loadbang"), 0);
+ class_addmethod(my_numbox_class, (t_method)my_numbox_set, gensym("set"), A_FLOAT, 0);
+ class_addmethod(my_numbox_class, (t_method)my_numbox_size, gensym("size"), A_GIMME, 0);
+ class_addmethod(my_numbox_class, (t_method)my_numbox_delta, gensym("delta"), A_GIMME, 0);
+ class_addmethod(my_numbox_class, (t_method)my_numbox_pos, gensym("pos"), A_GIMME, 0);
+ class_addmethod(my_numbox_class, (t_method)my_numbox_range, gensym("range"), A_GIMME, 0);
+ class_addmethod(my_numbox_class, (t_method)my_numbox_color, gensym("color"), A_GIMME, 0);
+ class_addmethod(my_numbox_class, (t_method)my_numbox_send, gensym("send"), A_DEFSYM, 0);
+ class_addmethod(my_numbox_class, (t_method)my_numbox_receive, gensym("receive"), A_DEFSYM, 0);
+ class_addmethod(my_numbox_class, (t_method)my_numbox_label, gensym("label"), A_DEFSYM, 0);
+ class_addmethod(my_numbox_class, (t_method)my_numbox_label_pos, gensym("label_pos"), A_GIMME, 0);
+ class_addmethod(my_numbox_class, (t_method)my_numbox_label_font, gensym("label_font"), A_GIMME, 0);
+ class_addmethod(my_numbox_class, (t_method)my_numbox_log, gensym("log"), 0);
+ class_addmethod(my_numbox_class, (t_method)my_numbox_lin, gensym("lin"), 0);
+ class_addmethod(my_numbox_class, (t_method)my_numbox_init, gensym("init"), A_FLOAT, 0);
+ class_addmethod(my_numbox_class, (t_method)my_numbox_log_height, gensym("log_height"), A_FLOAT, 0);
+ if(!iemgui_key_sym)
+ iemgui_key_sym = gensym("#keyname");
+ my_numbox_widgetbehavior.w_getrectfn = my_numbox_getrect;
+ my_numbox_widgetbehavior.w_displacefn = iemgui_displace;
+ my_numbox_widgetbehavior.w_selectfn = iemgui_select;
+ my_numbox_widgetbehavior.w_activatefn = NULL;
+ my_numbox_widgetbehavior.w_deletefn = iemgui_delete;
+ my_numbox_widgetbehavior.w_visfn = iemgui_vis;
+ my_numbox_widgetbehavior.w_clickfn = my_numbox_newclick;
+ my_numbox_widgetbehavior.w_propertiesfn = my_numbox_properties;;
+ my_numbox_widgetbehavior.w_savefn = my_numbox_save;
+ class_setwidget(my_numbox_class, &my_numbox_widgetbehavior);
+ class_sethelpsymbol(my_numbox_class, gensym("numbox2"));
+}
diff --git a/pd/src/g_readwrite.c b/pd/src/g_readwrite.c
new file mode 100644
index 00000000..ab380971
--- /dev/null
+++ b/pd/src/g_readwrite.c
@@ -0,0 +1,722 @@
+/* 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. */
+
+/* this file reads and writes the "data" portions of a canvas to a file.
+See also canvas_saveto(), etc., in g_editor.c. The data portion is a
+collection of "scalar" objects. Routines here can save collections of
+scalars into a file and reload them; also, support is included here for
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "m_imp.h"
+#include "g_canvas.h"
+#include <string.h>
+
+ /* the following routines read "scalars" from a file into a canvas. */
+
+static int canvas_scanbinbuf(int natoms, t_atom *vec, int *p_indexout,
+ int *p_next)
+{
+ int i, j;
+ int indexwas = *p_next;
+ *p_indexout = indexwas;
+ if (indexwas >= natoms)
+ return (0);
+ for (i = indexwas; i < natoms && vec[i].a_type != A_SEMI; i++)
+ ;
+ if (i >= natoms)
+ *p_next = i;
+ else *p_next = i + 1;
+ return (i - indexwas);
+}
+
+int glist_readscalar(t_glist *x, int natoms, t_atom *vec,
+ int *p_nextmsg, int selectit);
+
+static void canvas_readerror(int natoms, t_atom *vec, int message,
+ int nline, char *s)
+{
+ error(s);
+ startpost("line was:");
+ postatom(nline, vec + message);
+ endpost();
+}
+
+ /* fill in the contents of the scalar into the vector w. */
+
+static void glist_readatoms(t_glist *x, int natoms, t_atom *vec,
+ int *p_nextmsg, t_symbol *templatesym, t_word *w, int argc, t_atom *argv)
+{
+ int message, nline, n, i;
+
+ t_template *template = template_findbyname(templatesym);
+ if (!template)
+ {
+ error("%s: no such template", templatesym->s_name);
+ *p_nextmsg = natoms;
+ return;
+ }
+ word_restore(w, template, argc, argv);
+ n = template->t_n;
+ for (i = 0; i < n; i++)
+ {
+ if (template->t_vec[i].ds_type == DT_ARRAY)
+ {
+ int j;
+ t_array *a = w[i].w_array;
+ int elemsize = a->a_elemsize, nitems = 0;
+ t_symbol *arraytemplatesym = template->t_vec[i].ds_arraytemplate;
+ t_template *arraytemplate =
+ template_findbyname(arraytemplatesym);
+ if (!arraytemplate)
+ {
+ error("%s: no such template", arraytemplatesym->s_name);
+ }
+ else while (1)
+ {
+ t_word *element;
+ int nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg);
+ /* empty line terminates array */
+ if (!nline)
+ break;
+ array_resize(a, arraytemplate, nitems + 1);
+ element = (t_word *)(((char *)a->a_vec) +
+ nitems * elemsize);
+ glist_readatoms(x, natoms, vec, p_nextmsg, arraytemplatesym,
+ element, nline, vec + message);
+ nitems++;
+ }
+ }
+ else if (template->t_vec[i].ds_type == DT_LIST)
+ {
+ while (1)
+ {
+ if (!glist_readscalar(w->w_list, natoms, vec,
+ p_nextmsg, 0))
+ break;
+ }
+ }
+ }
+}
+
+int glist_readscalar(t_glist *x, int natoms, t_atom *vec,
+ int *p_nextmsg, int selectit)
+{
+ int message, i, j, nline;
+ t_template *template;
+ t_symbol *templatesym;
+ t_scalar *sc;
+ int nextmsg = *p_nextmsg;
+ int wasvis = glist_isvisible(x);
+
+ if (nextmsg >= natoms || vec[nextmsg].a_type != A_SYMBOL)
+ {
+ if (nextmsg < natoms)
+ post("stopping early: type %d", vec[nextmsg].a_type);
+ *p_nextmsg = natoms;
+ return (0);
+ }
+ templatesym = canvas_makebindsym(vec[nextmsg].a_w.w_symbol);
+ *p_nextmsg = nextmsg + 1;
+
+ if (!(template = template_findbyname(templatesym)))
+ {
+ error("canvas_read: %s: no such template", templatesym->s_name);
+ *p_nextmsg = natoms;
+ return (0);
+ }
+ sc = scalar_new(x, templatesym);
+ if (!sc)
+ {
+ error("couldn't create scalar \"%s\"", templatesym->s_name);
+ *p_nextmsg = natoms;
+ return (0);
+ }
+ if (wasvis)
+ {
+ /* temporarily lie about vis flag while this is built */
+ glist_getcanvas(x)->gl_mapped = 0;
+ }
+ glist_add(x, &sc->sc_gobj);
+
+ nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg);
+ glist_readatoms(x, natoms, vec, p_nextmsg, templatesym, sc->sc_vec,
+ nline, vec + message);
+ if (wasvis)
+ {
+ /* reset vis flag as before */
+ glist_getcanvas(x)->gl_mapped = 1;
+ gobj_vis(&sc->sc_gobj, x, 1);
+ }
+ if (selectit)
+ {
+ glist_select(x, &sc->sc_gobj);
+ }
+ return (1);
+}
+
+void glist_readfrombinbuf(t_glist *x, t_binbuf *b, char *filename, int selectem)
+{
+ t_canvas *canvas = glist_getcanvas(x);
+ int cr = 0, natoms, nline, message, nextmsg = 0, i, j, nitems;
+ t_atom *vec;
+ t_gobj *gobj;
+
+ natoms = binbuf_getnatom(b);
+ vec = binbuf_getvec(b);
+
+
+ /* check for file type */
+ nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg);
+ if (nline != 1 && vec[message].a_type != A_SYMBOL &&
+ strcmp(vec[message].a_w.w_symbol->s_name, "data"))
+ {
+ pd_error(x, "%s: file apparently of wrong type", filename);
+ binbuf_free(b);
+ return;
+ }
+ /* read in templates and check for consistency */
+ while (1)
+ {
+ t_template *newtemplate, *existtemplate;
+ t_symbol *templatesym;
+ t_atom *templateargs = getbytes(0);
+ int ntemplateargs = 0, newnargs;
+ nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg);
+ if (nline < 2)
+ break;
+ else if (nline > 2)
+ canvas_readerror(natoms, vec, message, nline,
+ "extra items ignored");
+ else if (vec[message].a_type != A_SYMBOL ||
+ strcmp(vec[message].a_w.w_symbol->s_name, "template") ||
+ vec[message + 1].a_type != A_SYMBOL)
+ {
+ canvas_readerror(natoms, vec, message, nline,
+ "bad template header");
+ continue;
+ }
+ templatesym = canvas_makebindsym(vec[message + 1].a_w.w_symbol);
+ while (1)
+ {
+ nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg);
+ if (nline != 2 && nline != 3)
+ break;
+ newnargs = ntemplateargs + nline;
+ templateargs = (t_atom *)t_resizebytes(templateargs,
+ sizeof(*templateargs) * ntemplateargs,
+ sizeof(*templateargs) * newnargs);
+ templateargs[ntemplateargs] = vec[message];
+ templateargs[ntemplateargs + 1] = vec[message + 1];
+ if (nline == 3)
+ templateargs[ntemplateargs + 2] = vec[message + 2];
+ ntemplateargs = newnargs;
+ }
+ newtemplate = template_new(templatesym, ntemplateargs, templateargs);
+ t_freebytes(templateargs, sizeof (*templateargs) * ntemplateargs);
+ if (!(existtemplate = template_findbyname(templatesym)))
+ {
+ error("%s: template not found in current patch",
+ templatesym->s_name);
+ template_free(newtemplate);
+ return;
+ }
+ if (!template_match(existtemplate, newtemplate))
+ {
+ error("%s: template doesn't match current one",
+ templatesym->s_name);
+ template_free(newtemplate);
+ return;
+ }
+ template_free(newtemplate);
+ }
+ while (nextmsg < natoms)
+ {
+ glist_readscalar(x, natoms, vec, &nextmsg, selectem);
+ }
+}
+
+static void glist_doread(t_glist *x, t_symbol *filename, t_symbol *format,
+ int clearme)
+{
+ t_binbuf *b = binbuf_new();
+ t_canvas *canvas = glist_getcanvas(x);
+ int wasvis = glist_isvisible(canvas);
+ int cr = 0, natoms, nline, message, nextmsg = 0, i, j;
+ t_atom *vec;
+
+ if (!strcmp(format->s_name, "cr"))
+ cr = 1;
+ else if (*format->s_name)
+ error("qlist_read: unknown flag: %s", format->s_name);
+
+ if (binbuf_read_via_path(b, filename->s_name,
+ canvas_getdir(canvas)->s_name, cr))
+ {
+ pd_error(x, "read failed");
+ binbuf_free(b);
+ return;
+ }
+ if (wasvis)
+ canvas_vis(canvas, 0);
+ if (clearme)
+ glist_clear(x);
+ glist_readfrombinbuf(x, b, filename->s_name, 0);
+ if (wasvis)
+ canvas_vis(canvas, 1);
+ binbuf_free(b);
+}
+
+void glist_read(t_glist *x, t_symbol *filename, t_symbol *format)
+{
+ glist_doread(x, filename, format, 1);
+}
+
+void glist_mergefile(t_glist *x, t_symbol *filename, t_symbol *format)
+{
+ glist_doread(x, filename, format, 0);
+}
+
+ /* read text from a "properties" window, called from a gfxstub set
+ up in scalar_properties(). We try to restore the object; if successful
+ we delete the scalar and put the new thing in its place on the list. */
+void canvas_dataproperties(t_canvas *x, t_scalar *sc, t_binbuf *b)
+{
+ int ntotal, nnew, scindex;
+ t_gobj *y, *y2 = 0, *newone, *oldone = 0;
+ for (y = x->gl_list, ntotal = 0, scindex = -1; y; y = y->g_next)
+ {
+ if (y == &sc->sc_gobj)
+ scindex = ntotal, oldone = y;
+ ntotal++;
+ }
+
+ if (scindex == -1)
+ bug("data_properties: scalar disappeared");
+ glist_readfrombinbuf(x, b, "properties dialog", 0);
+ newone = 0;
+ if (scindex >= 0)
+ {
+ /* take the new object off the list */
+ if (ntotal)
+ {
+ for (y = x->gl_list, nnew = 1; y2 = y->g_next;
+ y = y2, nnew++)
+ if (nnew == ntotal)
+ {
+ newone = y2;
+ y->g_next = y2->g_next;
+ break;
+ }
+ }
+ else newone = x->gl_list, x->gl_list = newone->g_next;
+ }
+ if (!newone)
+ error("couldn't update properties (perhaps a format problem?)");
+ else if (!oldone)
+ bug("data_properties: couldn't find old element");
+ else
+ {
+ glist_delete(x, oldone);
+ if (scindex > 0)
+ {
+ for (y = x->gl_list, nnew = 1; y;
+ y = y->g_next, nnew++)
+ if (nnew == scindex || !y->g_next)
+ {
+ newone->g_next = y->g_next;
+ y->g_next = newone;
+ goto didit;
+ }
+ bug("data_properties: can't reinsert");
+ }
+ else newone->g_next = x->gl_list, x->gl_list = newone;
+ }
+didit:
+ ;
+}
+
+ /* ----------- routines to write data to a binbuf ----------- */
+
+void canvas_doaddtemplate(t_symbol *templatesym,
+ int *p_ntemplates, t_symbol ***p_templatevec)
+{
+ int n = *p_ntemplates, i;
+ t_symbol **templatevec = *p_templatevec;
+ for (i = 0; i < n; i++)
+ if (templatevec[i] == templatesym)
+ return;
+ templatevec = (t_symbol **)t_resizebytes(templatevec,
+ n * sizeof(*templatevec), (n+1) * sizeof(*templatevec));
+ templatevec[n] = templatesym;
+ *p_templatevec = templatevec;
+ *p_ntemplates = n+1;
+}
+
+static void glist_writelist(t_gobj *y, t_binbuf *b);
+
+void canvas_writescalar(t_symbol *templatesym, t_word *w, t_binbuf *b,
+ int amarrayelement)
+{
+ t_dataslot *ds;
+ t_template *template = template_findbyname(templatesym);
+ t_atom *a = (t_atom *)t_getbytes(0);
+ int i, n = template->t_n, natom = 0;
+ if (!amarrayelement)
+ {
+ t_atom templatename;
+ SETSYMBOL(&templatename, gensym(templatesym->s_name + 3));
+ binbuf_add(b, 1, &templatename);
+ }
+ if (!template)
+ bug("canvas_writescalar");
+ /* write the atoms (floats and symbols) */
+ for (i = 0; i < n; i++)
+ {
+ if (template->t_vec[i].ds_type == DT_FLOAT ||
+ template->t_vec[i].ds_type == DT_SYMBOL)
+ {
+ a = (t_atom *)t_resizebytes(a,
+ natom * sizeof(*a), (natom + 1) * sizeof (*a));
+ if (template->t_vec[i].ds_type == DT_FLOAT)
+ SETFLOAT(a + natom, w[i].w_float);
+ else SETSYMBOL(a + natom, w[i].w_symbol);
+ natom++;
+ }
+ }
+ /* array elements have to have at least something */
+ if (natom == 0 && amarrayelement)
+ SETSYMBOL(a + natom, &s_bang), natom++;
+ binbuf_add(b, natom, a);
+ binbuf_addsemi(b);
+ t_freebytes(a, natom * sizeof(*a));
+ for (i = 0; i < n; i++)
+ {
+ if (template->t_vec[i].ds_type == DT_ARRAY)
+ {
+ int j;
+ t_array *a = w[i].w_array;
+ int elemsize = a->a_elemsize, nitems = a->a_n;
+ t_symbol *arraytemplatesym = template->t_vec[i].ds_arraytemplate;
+ for (j = 0; j < nitems; j++)
+ canvas_writescalar(arraytemplatesym,
+ (t_word *)(((char *)a->a_vec) + elemsize * j), b, 1);
+ binbuf_addsemi(b);
+ }
+ else if (template->t_vec[i].ds_type == DT_LIST)
+ {
+ glist_writelist(w->w_list->gl_list, b);
+ binbuf_addsemi(b);
+ }
+ }
+}
+
+static void glist_writelist(t_gobj *y, t_binbuf *b)
+{
+ for (; y; y = y->g_next)
+ {
+ if (pd_class(&y->g_pd) == scalar_class)
+ {
+ canvas_writescalar(((t_scalar *)y)->sc_template,
+ ((t_scalar *)y)->sc_vec, b, 0);
+ }
+ }
+}
+
+ /* ------------ routines to write out templates for data ------- */
+
+static void canvas_addtemplatesforlist(t_gobj *y,
+ int *p_ntemplates, t_symbol ***p_templatevec);
+
+static void canvas_addtemplatesforscalar(t_symbol *templatesym,
+ t_word *w, int *p_ntemplates, t_symbol ***p_templatevec)
+{
+ t_dataslot *ds;
+ int i;
+ t_template *template = template_findbyname(templatesym);
+ canvas_doaddtemplate(templatesym, p_ntemplates, p_templatevec);
+ if (!template)
+ bug("canvas_addtemplatesforscalar");
+ else for (ds = template->t_vec, i = template->t_n; i--; ds++, w++)
+ {
+ if (ds->ds_type == DT_ARRAY)
+ {
+ int j;
+ t_array *a = w->w_array;
+ int elemsize = a->a_elemsize, nitems = a->a_n;
+ t_symbol *arraytemplatesym = ds->ds_arraytemplate;
+ canvas_doaddtemplate(arraytemplatesym, p_ntemplates, p_templatevec);
+ for (j = 0; j < nitems; j++)
+ canvas_addtemplatesforscalar(arraytemplatesym,
+ (t_word *)(((char *)a->a_vec) + elemsize * j),
+ p_ntemplates, p_templatevec);
+ }
+ else if (ds->ds_type == DT_LIST)
+ canvas_addtemplatesforlist(w->w_list->gl_list,
+ p_ntemplates, p_templatevec);
+ }
+}
+
+static void canvas_addtemplatesforlist(t_gobj *y,
+ int *p_ntemplates, t_symbol ***p_templatevec)
+{
+ for (; y; y = y->g_next)
+ {
+ if (pd_class(&y->g_pd) == scalar_class)
+ {
+ canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template,
+ ((t_scalar *)y)->sc_vec, p_ntemplates, p_templatevec);
+ }
+ }
+}
+
+ /* write all "scalars" in a glist to a binbuf. */
+t_binbuf *glist_writetobinbuf(t_glist *x, int wholething)
+{
+ int i;
+ t_symbol **templatevec = getbytes(0);
+ int ntemplates = 0;
+ t_gobj *y;
+ t_binbuf *b = binbuf_new();
+
+ for (y = x->gl_list; y; y = y->g_next)
+ {
+ if ((pd_class(&y->g_pd) == scalar_class) &&
+ (wholething || glist_isselected(x, y)))
+ {
+ canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template,
+ ((t_scalar *)y)->sc_vec, &ntemplates, &templatevec);
+ }
+ }
+ binbuf_addv(b, "s;", gensym("data"));
+ for (i = 0; i < ntemplates; i++)
+ {
+ t_template *template = template_findbyname(templatevec[i]);
+ int j, m = template->t_n;
+ /* drop "pd-" prefix from template symbol to print it: */
+ binbuf_addv(b, "ss;", gensym("template"),
+ gensym(templatevec[i]->s_name + 3));
+ for (j = 0; j < m; j++)
+ {
+ t_symbol *type;
+ switch (template->t_vec[j].ds_type)
+ {
+ case DT_FLOAT: type = &s_float; break;
+ case DT_SYMBOL: type = &s_symbol; break;
+ case DT_ARRAY: type = gensym("array"); break;
+ case DT_LIST: type = &s_list; break;
+ default: type = &s_float; bug("canvas_write");
+ }
+ if (template->t_vec[j].ds_type == DT_ARRAY)
+ binbuf_addv(b, "sss;", type, template->t_vec[j].ds_name,
+ gensym(template->t_vec[j].ds_arraytemplate->s_name + 3));
+ else binbuf_addv(b, "ss;", type, template->t_vec[j].ds_name);
+ }
+ binbuf_addsemi(b);
+ }
+ binbuf_addsemi(b);
+ /* now write out the objects themselves */
+ for (y = x->gl_list; y; y = y->g_next)
+ {
+ if ((pd_class(&y->g_pd) == scalar_class) &&
+ (wholething || glist_isselected(x, y)))
+ {
+ canvas_writescalar(((t_scalar *)y)->sc_template,
+ ((t_scalar *)y)->sc_vec, b, 0);
+ }
+ }
+ return (b);
+}
+
+static void glist_write(t_glist *x, t_symbol *filename, t_symbol *format)
+{
+ int cr = 0, i;
+ t_binbuf *b;
+ char buf[MAXPDSTRING];
+ t_symbol **templatevec = getbytes(0);
+ int ntemplates = 0;
+ t_gobj *y;
+ t_canvas *canvas = glist_getcanvas(x);
+ canvas_makefilename(canvas, filename->s_name, buf, MAXPDSTRING);
+ if (!strcmp(format->s_name, "cr"))
+ cr = 1;
+ else if (*format->s_name)
+ error("qlist_read: unknown flag: %s", format->s_name);
+
+ b = glist_writetobinbuf(x, 1);
+ if (b)
+ {
+ if (binbuf_write(b, buf, "", cr))
+ error("%s: write failed", filename->s_name);
+ binbuf_free(b);
+ }
+}
+
+/* ------ routines to save and restore canvases (patches) recursively. ----*/
+
+ /* save to a binbuf, called recursively; cf. canvas_savetofile() which
+ saves the document, and is only called on root canvases. */
+static void canvas_saveto(t_canvas *x, t_binbuf *b)
+{
+ t_gobj *y;
+ t_linetraverser t;
+ t_outconnect *oc;
+ /* subpatch */
+ if (x->gl_owner && !x->gl_env)
+ {
+ binbuf_addv(b, "ssiiiisi;", gensym("#N"), gensym("canvas"),
+ (t_int)(x->gl_screenx1),
+ (t_int)(x->gl_screeny1),
+ (t_int)(x->gl_screenx2 - x->gl_screenx1),
+ (t_int)(x->gl_screeny2 - x->gl_screeny1),
+ x->gl_name, x->gl_mapped);
+ }
+ /* root or abstraction */
+ else binbuf_addv(b, "ssiiiii;", gensym("#N"), gensym("canvas"),
+ (t_int)(x->gl_screenx1),
+ (t_int)(x->gl_screeny1),
+ (t_int)(x->gl_screenx2 - x->gl_screenx1),
+ (t_int)(x->gl_screeny2 - x->gl_screeny1),
+ x->gl_font);
+
+ for (y = x->gl_list; y; y = y->g_next)
+ gobj_save(y, b);
+
+ linetraverser_start(&t, x);
+ while (oc = linetraverser_next(&t))
+ {
+ int srcno, sinkno;
+ for (srcno = 0, y = x->gl_list; y && y != &t.tr_ob->ob_g; y = y->g_next)
+ srcno++;
+ for (sinkno = 0, y = x->gl_list; y && y != &t.tr_ob2->ob_g; y = y->g_next)
+ sinkno++;
+ binbuf_addv(b, "ssiiii;", gensym("#X"), gensym("connect"),
+ srcno, t.tr_outno, sinkno, t.tr_inno);
+ }
+ if (x->gl_isgraph)
+ binbuf_addv(b, "ssfffffff;", gensym("#X"), gensym("coords"),
+ x->gl_x1, x->gl_y1,
+ x->gl_x2, x->gl_y2,
+ (float)x->gl_pixwidth, (float)x->gl_pixheight,
+ (float)x->gl_isgraph);
+}
+
+ /* call this recursively to collect all the template names for
+ a canvas or for the selection. */
+static void canvas_collecttemplatesfor(t_canvas *x, int *ntemplatesp,
+ t_symbol ***templatevecp, int wholething)
+{
+ t_gobj *y;
+
+ for (y = x->gl_list; y; y = y->g_next)
+ {
+ if ((pd_class(&y->g_pd) == scalar_class) &&
+ (wholething || glist_isselected(x, y)))
+ canvas_addtemplatesforscalar(((t_scalar *)y)->sc_template,
+ ((t_scalar *)y)->sc_vec, ntemplatesp, templatevecp);
+ else if ((pd_class(&y->g_pd) == canvas_class) &&
+ (wholething || glist_isselected(x, y)))
+ canvas_collecttemplatesfor((t_canvas *)y,
+ ntemplatesp, templatevecp, 1);
+ }
+}
+
+ /* save the templates needed by a canvas to a binbuf. */
+static void canvas_savetemplatesto(t_canvas *x, t_binbuf *b, int wholething)
+{
+ t_symbol **templatevec = getbytes(0);
+ int i, ntemplates = 0;
+ t_gobj *y;
+ canvas_collecttemplatesfor(x, &ntemplates, &templatevec, wholething);
+ for (i = 0; i < ntemplates; i++)
+ {
+ t_template *template = template_findbyname(templatevec[i]);
+ int j, m = template->t_n;
+ if (!template)
+ {
+ bug("canvas_savetemplatesto");
+ continue;
+ }
+ /* drop "pd-" prefix from template symbol to print */
+ binbuf_addv(b, "sss", &s__N, gensym("struct"),
+ gensym(templatevec[i]->s_name + 3));
+ for (j = 0; j < m; j++)
+ {
+ t_symbol *type;
+ switch (template->t_vec[j].ds_type)
+ {
+ case DT_FLOAT: type = &s_float; break;
+ case DT_SYMBOL: type = &s_symbol; break;
+ case DT_ARRAY: type = gensym("array"); break;
+ case DT_LIST: type = &s_list; break;
+ default: type = &s_float; bug("canvas_write");
+ }
+ if (template->t_vec[j].ds_type == DT_ARRAY)
+ binbuf_addv(b, "sss", type, template->t_vec[j].ds_name,
+ gensym(template->t_vec[j].ds_arraytemplate->s_name + 3));
+ else binbuf_addv(b, "ss", type, template->t_vec[j].ds_name);
+ }
+ binbuf_addsemi(b);
+ }
+}
+
+ /* save a "root" canvas to a file; cf. canvas_saveto() which saves the
+ body (and which is called recursively.) */
+static void canvas_savetofile(t_canvas *x, t_symbol *filename, t_symbol *dir)
+{
+ t_binbuf *b = binbuf_new();
+ canvas_savetemplatesto(x, b, 1);
+ canvas_saveto(x, b);
+ if (binbuf_write(b, filename->s_name, dir->s_name, 0)) sys_ouch();
+ else
+ {
+ /* if not an abstraction, reset title bar and directory */
+ if (!x->gl_owner)
+ canvas_rename(x, filename, dir);
+ post("saved to: %s/%s", dir->s_name, filename->s_name);
+ canvas_dirty(x, 0);
+#if 0 /* not yet written */
+ canvas_reload(filename, dir);
+#endif
+ }
+ binbuf_free(b);
+}
+
+static void canvas_menusaveas(t_canvas *x)
+{
+ t_canvas *x2 = canvas_getrootfor(x);
+ sys_vgui("pdtk_canvas_saveas .x%x \"%s\" \"%s\"\n", x2,
+ x2->gl_name->s_name, canvas_getdir(x2)->s_name);
+}
+
+static void canvas_menusave(t_canvas *x)
+{
+ t_canvas *x2 = canvas_getrootfor(x);
+ char *name = x2->gl_name->s_name;
+ if (*name && strncmp(name, "Untitled", 8)
+ && (strlen(name) < 4 || strcmp(name + strlen(name)-4, ".pat")))
+ canvas_savetofile(x2, x2->gl_name, canvas_getdir(x2));
+ else canvas_menusaveas(x2);
+}
+
+
+void g_readwrite_setup(void)
+{
+ class_addmethod(canvas_class, (t_method)glist_write,
+ gensym("write"), A_SYMBOL, A_DEFSYM, A_NULL);
+ class_addmethod(canvas_class, (t_method)glist_read,
+ gensym("read"), A_SYMBOL, A_DEFSYM, A_NULL);
+ class_addmethod(canvas_class, (t_method)glist_mergefile,
+ gensym("mergefile"), A_SYMBOL, A_DEFSYM, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_savetofile,
+ gensym("savetofile"), A_SYMBOL, A_SYMBOL, 0);
+ class_addmethod(canvas_class, (t_method)canvas_saveto,
+ gensym("saveto"), A_CANT, 0);
+/* ------------------ from the menu ------------------------- */
+ class_addmethod(canvas_class, (t_method)canvas_menusave,
+ gensym("menusave"), 0);
+ class_addmethod(canvas_class, (t_method)canvas_menusaveas,
+ gensym("menusaveas"), 0);
+}
diff --git a/pd/src/g_rtext.c b/pd/src/g_rtext.c
new file mode 100644
index 00000000..4b48dcc0
--- /dev/null
+++ b/pd/src/g_rtext.c
@@ -0,0 +1,478 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* changes by Thomas Musil IEM KUG Graz Austria 2001 */
+/* have to insert gui-objects into editor-list */
+/* all changes are labeled with iemlib */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "m_imp.h"
+#include "g_canvas.h"
+#include "t_tk.h"
+
+#define LMARGIN 1
+#define RMARGIN 1
+#define TMARGIN 2
+#define BMARGIN 2
+
+#define SEND_FIRST 1
+#define SEND_UPDATE 2
+#define SEND_CHECK 0
+
+static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp,
+ int *indexp);
+
+struct _rtext
+{
+ char *x_buf;
+ int x_bufsize;
+ int x_selstart;
+ int x_selend;
+ int x_active;
+ int x_dragfrom;
+ int x_height;
+ int x_drawnwidth;
+ int x_drawnheight;
+ t_text *x_text;
+ t_glist *x_glist;
+ char x_tag[50];
+ struct _rtext *x_next;
+};
+
+t_rtext *rtext_new(t_glist *glist, t_text *who, t_rtext *next, int senditup)
+{
+ t_rtext *x = (t_rtext *)getbytes(sizeof *x);
+ int w = 0, h = 0, indx;
+ x->x_height = -1;
+ x->x_text = who;
+ x->x_glist = glist;
+ x->x_next = glist->gl_editor->e_rtext;
+ x->x_selstart = x->x_selend = x->x_active =
+ x->x_drawnwidth = x->x_drawnheight = 0;
+ binbuf_gettext(who->te_binbuf, &x->x_buf, &x->x_bufsize);
+ glist->gl_editor->e_rtext = x;
+ sprintf(x->x_tag, ".x%x.t%x", (t_int)glist_getcanvas(x->x_glist),
+ (t_int)x);
+ if (senditup)
+ rtext_senditup(x, SEND_FIRST, &w, &h, &indx);
+ return (x);
+}
+
+/* iemlib version (now incorporated into rtext_new() via the "senditup" arg) */
+
+t_rtext *rtext_new_without_senditup(t_glist *glist, t_text *who, t_rtext *next)
+{
+ return (rtext_new(glist, who, next, 0));
+}
+
+static t_rtext *rtext_entered;
+
+void rtext_free(t_rtext *x)
+{
+ sys_vgui(".x%x.c delete %s\n", glist_getcanvas(x->x_glist),
+ x->x_tag);
+ if (x->x_glist->gl_editor->e_textedfor == x)
+ x->x_glist->gl_editor->e_textedfor = 0;
+ if (x->x_glist->gl_editor->e_rtext == x)
+ x->x_glist->gl_editor->e_rtext = x->x_next;
+ else
+ {
+ t_rtext *e2;
+ for (e2 = x->x_glist->gl_editor->e_rtext; e2; e2 = e2->x_next)
+ if (e2->x_next == x)
+ {
+ e2->x_next = x->x_next;
+ break;
+ }
+ }
+ if (rtext_entered == x) rtext_entered = 0;
+ freebytes(x->x_buf, x->x_bufsize);
+ freebytes(x, sizeof *x);
+}
+
+char *rtext_gettag(t_rtext *x)
+{
+ return (x->x_tag);
+}
+
+void rtext_gettext(t_rtext *x, char **buf, int *bufsize)
+{
+ *buf = x->x_buf;
+ *bufsize = x->x_bufsize;
+}
+
+
+/* LATER deal with tcl-significant characters */
+
+static int firstone(char *s, int c, int n)
+{
+ char *s2 = s + n;
+ int i = 0;
+ while (s != s2)
+ {
+ if (*s == c) return (i);
+ i++;
+ s++;
+ }
+ return (-1);
+}
+
+static int lastone(char *s, int c, int n)
+{
+ char *s2 = s + n;
+ while (s2 != s)
+ {
+ s2--;
+ n--;
+ if (*s2 == c) return (n);
+ }
+ return (-1);
+}
+
+ /* the following routine computes line breaks and carries out
+ some action which could be:
+ SEND_FIRST - draw the box for the first time
+ SEND_UPDATE - redraw the updated box
+ otherwise - don't draw, just calculate.
+ Called with *widthp and *heightpas coordinates of
+ a test point, the routine reports the index of the character found
+ there in *indexp. *widthp and *heightp are set to the width and height
+ of the entire text in pixels.
+ */
+
+ /* LATER get this and sys_vgui to work together properly,
+ breaking up messages as needed. As of now, there's
+ a limit of 1950 characters, imposed by sys_vgui(). */
+#define UPBUFSIZE 4000
+#define BOXWIDTH 60
+
+static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp,
+ int *indexp)
+{
+ float dispx, dispy;
+ char tempbuf[UPBUFSIZE], *tp = tempbuf, *bp = x->x_buf;
+ int outchars, inchars = x->x_bufsize, nlines = 0, ncolumns = 0,
+ pixwide, pixhigh;
+ int font = glist_getfont(x->x_glist);
+ int fontwidth = sys_fontwidth(font), fontheight = sys_fontheight(font);
+ int findx = (*widthp + (fontwidth/2)) / fontwidth,
+ findy = *heightp / fontheight;
+ int reportedindex = 0;
+ t_canvas *canvas = glist_getcanvas(x->x_glist);
+ int widthspec = x->x_text->te_width;
+ int widthlimit = (widthspec ? widthspec : BOXWIDTH);
+ while (inchars)
+ {
+ int maxindex = (inchars > widthlimit ? widthlimit : inchars);
+ int eatchar = 1;
+ int foundit = firstone(bp, '\n', maxindex);
+ if (foundit < 0)
+ {
+ if (inchars > widthlimit)
+ {
+ foundit = lastone(bp, ' ', maxindex);
+ if (foundit < 0)
+ {
+ foundit = maxindex;
+ eatchar = 0;
+ }
+ }
+ else
+ {
+ foundit = inchars;
+ eatchar = 0;
+ }
+ }
+ if (nlines == findy)
+ {
+ int actualx = (findx < 0 ? 0 :
+ (findx > foundit ? foundit : findx));
+ *indexp = (bp - x->x_buf) + actualx;
+ reportedindex = 1;
+ }
+ strncpy(tp, bp, foundit);
+ tp += foundit;
+ bp += (foundit + eatchar);
+ inchars -= (foundit + eatchar);
+ if (inchars) *tp++ = '\n';
+ if (foundit > ncolumns) ncolumns = foundit;
+ nlines++;
+ }
+ outchars = tp - tempbuf;
+ if (outchars > 1950) outchars = 1950;
+ if (!reportedindex)
+ *indexp = outchars;
+ dispx = text_xpix(x->x_text, x->x_glist);
+ dispy = text_ypix(x->x_text, x->x_glist);
+ if (nlines < 1) nlines = 1;
+ if (!widthspec)
+ {
+ while (ncolumns < 3)
+ {
+ tempbuf[outchars++] = ' ';
+ ncolumns++;
+ }
+ }
+ else ncolumns = widthspec;
+ pixwide = ncolumns * fontwidth + (LMARGIN + RMARGIN);
+ pixhigh = nlines * fontheight + (TMARGIN + BMARGIN);
+
+ if (action == SEND_FIRST)
+ sys_vgui("pdtk_text_new .x%x.c %s %f %f {%.*s} %d %s\n",
+ canvas, x->x_tag,
+ dispx + LMARGIN, dispy + TMARGIN,
+ outchars, tempbuf, sys_hostfontsize(font),
+ (glist_isselected(x->x_glist,
+ &x->x_glist->gl_gobj)? "blue" : "black"));
+ else if (action == SEND_UPDATE)
+ {
+ sys_vgui("pdtk_text_set .x%x.c %s {%.*s}\n",
+ canvas, x->x_tag, outchars, tempbuf);
+ if (pixwide != x->x_drawnwidth || pixhigh != x->x_drawnheight)
+ text_drawborder(x->x_text, x->x_glist, x->x_tag,
+ pixwide, pixhigh, 0);
+ if (x->x_active)
+ {
+ if (x->x_selend > x->x_selstart)
+ {
+ sys_vgui(".x%x.c select from %s %d\n", canvas,
+ x->x_tag, x->x_selstart);
+ sys_vgui(".x%x.c select to %s %d\n", canvas,
+ x->x_tag, x->x_selend);
+ sys_vgui(".x%x.c focus \"\"\n", canvas);
+ }
+ else
+ {
+ sys_vgui(".x%x.c select clear\n", canvas);
+ sys_vgui(".x%x.c icursor %s %d\n", canvas, x->x_tag,
+ x->x_selstart);
+ sys_vgui(".x%x.c focus %s\n", canvas, x->x_tag);
+ }
+ }
+ }
+ x->x_drawnwidth = pixwide;
+ x->x_drawnheight = pixhigh;
+
+ *widthp = pixwide;
+ *heightp = pixhigh;
+}
+
+void rtext_retext(t_rtext *x)
+{
+ int w = 0, h = 0, indx;
+ t_text *text = x->x_text;
+ t_freebytes(x->x_buf, x->x_bufsize);
+ binbuf_gettext(text->te_binbuf, &x->x_buf, &x->x_bufsize);
+ /* special case: for number boxes, try to pare the number down
+ to the specified width of the box. */
+ if (text->te_width > 0 && text->te_type == T_ATOM &&
+ x->x_bufsize > text->te_width)
+ {
+ t_atom *atomp = binbuf_getvec(text->te_binbuf);
+ int natom = binbuf_getnatom(text->te_binbuf);
+ int bufsize = x->x_bufsize;
+ if (natom == 1 && atomp->a_type == A_FLOAT)
+ {
+ /* try to reduce size by dropping decimal digits */
+ int wantreduce = bufsize - text->te_width;
+ char *decimal = 0, *nextchar, *ebuf = x->x_buf + bufsize,
+ *s1, *s2;
+ int ndecimals;
+ for (decimal = x->x_buf; decimal < ebuf; decimal++)
+ if (*decimal == '.')
+ break;
+ if (decimal >= ebuf)
+ goto giveup;
+ for (nextchar = decimal + 1; nextchar < ebuf; nextchar++)
+ if (*nextchar < '0' || *nextchar > '9')
+ break;
+ if (nextchar - decimal - 1 < wantreduce)
+ goto giveup;
+ for (s1 = nextchar - wantreduce, s2 = s1 + wantreduce;
+ s2 < ebuf; s1++, s2++)
+ *s1 = *s2;
+ t_resizebytes(x->x_buf, bufsize, text->te_width);
+ bufsize = text->te_width;
+ goto done;
+ giveup:
+ /* give up and bash it to "+" or "-" */
+ x->x_buf[0] = (atomp->a_w.w_float < 0 ? '-' : '+');
+ t_resizebytes(x->x_buf, bufsize, 1);
+ bufsize = 1;
+ }
+ else if (bufsize > text->te_width)
+ {
+ x->x_buf[text->te_width - 1] = '>';
+ t_resizebytes(x->x_buf, bufsize, text->te_width);
+ bufsize = text->te_width;
+ }
+ done:
+ x->x_bufsize = bufsize;
+ }
+ rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
+}
+
+/* find the rtext that goes with a text item */
+t_rtext *glist_findrtext(t_glist *gl, t_text *who)
+{
+ t_rtext *x = gl->gl_editor->e_rtext;
+ while (x && x->x_text != who) x = x->x_next;
+ if (!x) bug("glist_findrtext");
+ return (x);
+}
+
+int rtext_width(t_rtext *x)
+{
+ int w = 0, h = 0, indx;
+ rtext_senditup(x, SEND_CHECK, &w, &h, &indx);
+ return (w);
+}
+
+int rtext_height(t_rtext *x)
+{
+ int w = 0, h = 0, indx;
+ rtext_senditup(x, SEND_CHECK, &w, &h, &indx);
+ return (h);
+}
+
+void rtext_displace(t_rtext *x, int dx, int dy)
+{
+ sys_vgui(".x%x.c move %s %d %d\n", glist_getcanvas(x->x_glist),
+ x->x_tag, dx, dy);
+}
+
+void rtext_select(t_rtext *x, int state)
+{
+ t_glist *glist = x->x_glist;
+ t_canvas *canvas = glist_getcanvas(glist);
+ sys_vgui(".x%x.c itemconfigure %s -fill %s\n", canvas,
+ x->x_tag, (state? "blue" : "black"));
+ canvas_editing = canvas;
+}
+
+void rtext_activate(t_rtext *x, int state)
+{
+ int w = 0, h = 0, indx;
+ t_glist *glist = x->x_glist;
+ t_canvas *canvas = glist_getcanvas(glist);
+ if (state)
+ {
+ sys_vgui(".x%x.c focus %s\n", canvas, x->x_tag);
+ glist->gl_editor->e_textedfor = x;
+ glist->gl_editor->e_textdirty = 0;
+ x->x_dragfrom = x->x_selstart = 0;
+ x->x_selend = x->x_bufsize;
+ x->x_active = 1;
+ }
+ else
+ {
+ sys_vgui("selection clear .x%x.c\n", canvas);
+ sys_vgui(".x%x.c focus \"\"\n", canvas);
+ if (glist->gl_editor->e_textedfor == x)
+ glist->gl_editor->e_textedfor = 0;
+ x->x_active = 0;
+ }
+ rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
+}
+
+void rtext_key(t_rtext *x, int keynum, t_symbol *keysym)
+{
+ int w = 0, h = 0, indx, i, newsize, ndel;
+ char *s1, *s2;
+ if (keynum)
+ {
+ int n = keynum;
+ if (n == '\r') n = '\n';
+ if (n == '\b')
+ {
+ if ((!x->x_selstart) && (x->x_selend == x->x_bufsize))
+ {
+ /* LATER delete the box... this causes reentrancy
+ problems now. */
+ /* glist_delete(x->x_glist, &x->x_text->te_g); */
+ return;
+ }
+ else if (x->x_selstart && (x->x_selstart == x->x_selend))
+ x->x_selstart--;
+ }
+ ndel = x->x_selend - x->x_selstart;
+ for (i = x->x_selend; i < x->x_bufsize; i++)
+ x->x_buf[i- ndel] = x->x_buf[i];
+ newsize = x->x_bufsize - ndel;
+ x->x_buf = resizebytes(x->x_buf, x->x_bufsize, newsize);
+ x->x_bufsize = newsize;
+
+ if (n == '\n' || isprint(n))
+ {
+ newsize = x->x_bufsize+1;
+ x->x_buf = resizebytes(x->x_buf, x->x_bufsize, newsize);
+ for (i = x->x_bufsize; i > x->x_selstart; i--)
+ x->x_buf[i] = x->x_buf[i-1];
+ x->x_buf[x->x_selstart] = n;
+ x->x_bufsize = newsize;
+ x->x_selstart = x->x_selstart + 1;
+ }
+ x->x_selend = x->x_selstart;
+ x->x_glist->gl_editor->e_textdirty = 1;
+ }
+ else if (!strcmp(keysym->s_name, "Right"))
+ {
+ if (x->x_selend == x->x_selstart && x->x_selstart < x->x_bufsize)
+ x->x_selend = x->x_selstart = x->x_selstart + 1;
+ else
+ x->x_selstart = x->x_selend;
+ }
+ else if (!strcmp(keysym->s_name, "Left"))
+ {
+ if (x->x_selend == x->x_selstart && x->x_selstart > 0)
+ x->x_selend = x->x_selstart = x->x_selstart - 1;
+ else
+ x->x_selend = x->x_selstart;
+ }
+ /* this should be improved... life's too short */
+ else if (!strcmp(keysym->s_name, "Up"))
+ {
+ if (x->x_selstart)
+ x->x_selstart--;
+ while (x->x_selstart > 0 && x->x_buf[x->x_selstart] != '\n')
+ x->x_selstart--;
+ x->x_selend = x->x_selstart;
+ }
+ else if (!strcmp(keysym->s_name, "Down"))
+ {
+ while (x->x_selend < x->x_bufsize &&
+ x->x_buf[x->x_selend] != '\n')
+ x->x_selend++;
+ if (x->x_selend < x->x_bufsize)
+ x->x_selend++;
+ x->x_selstart = x->x_selend;
+ }
+ rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
+}
+
+void rtext_mouse(t_rtext *x, int xval, int yval, int flag)
+{
+ int w = xval, h = yval, indx;
+ rtext_senditup(x, SEND_CHECK, &w, &h, &indx);
+ if (flag == RTEXT_DOWN)
+ {
+ x->x_dragfrom = x->x_selstart = x->x_selend = indx;
+ }
+ else if (flag == RTEXT_SHIFT)
+ {
+ if (indx * 2 > x->x_selstart + x->x_selend)
+ x->x_dragfrom = x->x_selstart, x->x_selend = indx;
+ else
+ x->x_dragfrom = x->x_selend, x->x_selstart = indx;
+ }
+ else if (flag == RTEXT_DRAG)
+ {
+ x->x_selstart = (x->x_dragfrom < indx ? x->x_dragfrom : indx);
+ x->x_selend = (x->x_dragfrom > indx ? x->x_dragfrom : indx);
+ }
+ rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
+}
diff --git a/pd/src/g_scalar.c b/pd/src/g_scalar.c
new file mode 100644
index 00000000..362fb108
--- /dev/null
+++ b/pd/src/g_scalar.c
@@ -0,0 +1,373 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* This file defines the "scalar" object, which is not a text object, just a
+"gobj". Scalars have templates which describe their structures, which
+can contain numbers, sublists, and arrays.
+
+Also, the "tscalar" object, an ordinary text object that owns a single "scalar"
+and draws it on the parent. This is intended as a way that abstractions can
+control their appearances by adding stuff to draw.
+*/
+
+/* IOhannes :
+ * changed the canvas_restore, so that it might accept $args as well (like "pd $0_test")
+ * so you can make multiple & distinguishable templates
+ * 1511:forum::für::umläute:2001
+ * changes marked with IOhannes
+ * added Krzysztof Czajas fix to avoid crashing...
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h> /* for read/write to files */
+#include "m_pd.h"
+#include "g_canvas.h"
+
+t_class *scalar_class;
+
+void word_init(t_word *wp, t_template *template, t_gpointer *gp)
+{
+ int i, nitems = template->t_n;
+ t_dataslot *datatypes = template->t_vec;
+ for (i = 0; i < nitems; i++, datatypes++, wp++)
+ {
+ int type = datatypes->ds_type;
+ if (type == DT_FLOAT)
+ wp->w_float = 0;
+ else if (type == DT_SYMBOL)
+ wp->w_symbol = &s_symbol;
+ else if (type == DT_ARRAY)
+ {
+ wp->w_array = array_new(datatypes->ds_arraytemplate, gp);
+ }
+ else if (type == DT_LIST)
+ {
+ /* LATER test this and get it to work */
+ wp->w_list = canvas_new(0, 0, 0, 0);
+ }
+ }
+}
+
+void word_restore(t_word *wp, t_template *template,
+ int argc, t_atom *argv)
+{
+ int i, nitems = template->t_n;
+ t_dataslot *datatypes = template->t_vec;
+ for (i = 0; i < nitems; i++, datatypes++, wp++)
+ {
+ int type = datatypes->ds_type;
+ if (type == DT_FLOAT)
+ {
+ float f;
+ if (argc)
+ {
+ f = atom_getfloat(argv);
+ argv++, argc--;
+ }
+ else f = 0;
+ wp->w_float = f;
+ }
+ else if (type == DT_SYMBOL)
+ {
+ t_symbol *s;
+ if (argc)
+ {
+ s = atom_getsymbol(argv);
+ argv++, argc--;
+ }
+ else s = &s_;
+ wp->w_symbol = s;
+ }
+ }
+ if (argc)
+ post("warning: word_restore: extra arguments");
+}
+
+ /* make a new scalar and add to the glist. We create a "gp" here which
+ will be used for array items to point back here. This gp doesn't do
+ reference counting or "validation" updates though; the parent won't go away
+ without the contained arrays going away too. The "gp" is copied out
+ by value in the word_init() routine so we can throw our copy away. */
+
+t_scalar *scalar_new(t_glist *owner, t_symbol *templatesym)
+{
+ t_scalar *x;
+ t_template *template;
+ t_gpointer gp;
+ gpointer_init(&gp);
+ template = template_findbyname(templatesym);
+ if (!template)
+ {
+ error("scalar: couldn't find template %s", templatesym->s_name);
+ return (0);
+ }
+ x = (t_scalar *)getbytes(sizeof(t_scalar) +
+ (template->t_n - 1) * sizeof(*x->sc_vec));
+ x->sc_gobj.g_pd = scalar_class;
+ x->sc_template = templatesym;
+ gpointer_setglist(&gp, owner, x);
+ word_init(x->sc_vec, template, &gp);
+ return (x);
+}
+
+ /* Pd method to create a new scalar, add it to a glist, and initialize
+ it from the message arguments. */
+
+int glist_readscalar(t_glist *x, int natoms, t_atom *vec,
+ int *p_nextmsg, int selectit);
+
+void glist_scalar(t_glist *glist,
+ t_symbol *classname, t_int argc, t_atom *argv)
+{
+ t_symbol *templatesym =
+ canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
+ t_binbuf *b;
+ int natoms, nextmsg = 0;
+ t_atom *vec;
+ if (!template_findbyname(templatesym))
+ {
+ pd_error(glist, "%s: no such template",
+ atom_getsymbolarg(0, argc, argv)->s_name);
+ return;
+ }
+
+ b = binbuf_new();
+ binbuf_restore(b, argc, argv);
+ natoms = binbuf_getnatom(b);
+ vec = binbuf_getvec(b);
+
+ glist_readscalar(glist, natoms, vec, &nextmsg, 0);
+ binbuf_free(b);
+}
+
+/* -------------------- widget behavior for scalar ------------ */
+void scalar_getbasexy(t_scalar *x, float *basex, float *basey)
+{
+ t_template *template = template_findbyname(x->sc_template);
+ *basex = template_getfloat(template, gensym("x"), x->sc_vec, 0);
+ *basey = template_getfloat(template, gensym("y"), x->sc_vec, 0);
+}
+
+static void scalar_getrect(t_gobj *z, t_glist *owner,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_scalar *x = (t_scalar *)z;
+ int hit = 0;
+ t_template *template = template_findbyname(x->sc_template);
+ t_canvas *templatecanvas = template_findcanvas(template);
+ int x1 = 0x7fffffff, x2 = -0x7fffffff, y1 = 0x7fffffff, y2 = -0x7fffffff;
+ t_gobj *y;
+ float basex, basey;
+ scalar_getbasexy(x, &basex, &basey);
+ for (y = templatecanvas->gl_list; y; y = y->g_next)
+ {
+ t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
+ int nx1, ny1, nx2, ny2;
+ if (!wb) continue;
+ (*wb->w_parentgetrectfn)(y, owner,
+ x->sc_vec, template, basex, basey,
+ &nx1, &ny1, &nx2, &ny2);
+ if (hit)
+ {
+ if (nx1 < x1) x1 = nx1;
+ if (ny1 < y1) y1 = ny1;
+ if (nx2 > x2) x2 = nx2;
+ if (ny2 > y2) y2 = ny2;
+ }
+ else x1 = nx1, y1 = ny1, x2 = nx2, y2 = ny2, hit = 1;
+ }
+ if (!hit) x1 = y1 = x2 = y2 = 0;
+ /* post("scalar x1 %d y1 %d x2 %d y2 %d", x1, y1, x2, y2); */
+ *xp1 = x1;
+ *yp1 = y1;
+ *xp2 = x2;
+ *yp2 = y2;
+}
+
+static void scalar_select(t_gobj *z, t_glist *owner, int state)
+{
+ t_scalar *x = (t_scalar *)z;
+ /* post("scalar_select %d", state); */
+ /* later */
+ if (state)
+ {
+ int x1, y1, x2, y2;
+ scalar_getrect(z, owner, &x1, &y1, &x2, &y2);
+ sys_vgui(".x%x.c create line %d %d %d %d %d %d %d %d %d %d \
+ -width 0 -fill blue -tags select%x\n",
+ glist_getcanvas(owner), x1, y1, x1, y2, x2, y2, x2, y1, x1, y1,
+ x);
+ }
+ else sys_vgui(".x%x.c delete select%x\n", glist_getcanvas(owner), x);
+}
+
+static void scalar_displace(t_gobj *z, t_glist *glist, int dx, int dy)
+{
+ t_scalar *x = (t_scalar *)z;
+ t_symbol *templatesym = x->sc_template;
+ t_template *template = template_findbyname(templatesym);
+ t_symbol *zz;
+ int xonset, yonset, xtype, ytype, gotx, goty;
+ if (!template)
+ {
+ error("scalar: couldn't find template %s", templatesym->s_name);
+ return;
+ }
+ gotx = template_find_field(template, gensym("x"), &xonset, &xtype, &zz);
+ if (gotx && (xtype != DT_FLOAT))
+ gotx = 0;
+ goty = template_find_field(template, gensym("y"), &yonset, &ytype, &zz);
+ if (goty && (ytype != DT_FLOAT))
+ goty = 0;
+ if (gotx)
+ *(t_float *)(((char *)(x->sc_vec)) + xonset) +=
+ dx * (glist_pixelstox(glist, 1) - glist_pixelstox(glist, 0));
+ if (goty)
+ *(t_float *)(((char *)(x->sc_vec)) + yonset) +=
+ dy * (glist_pixelstoy(glist, 1) - glist_pixelstoy(glist, 0));
+ glist_redrawitem(glist, z);
+ if (glist_isselected(glist, z))
+ {
+ scalar_select(z, glist, 0);
+ scalar_select(z, glist, 1);
+ }
+}
+
+static void scalar_activate(t_gobj *z, t_glist *owner, int state)
+{
+ /* post("scalar_activate %d", state); */
+ /* later */
+}
+
+static void scalar_delete(t_gobj *z, t_glist *glist)
+{
+ /* nothing to do */
+}
+
+static void scalar_vis(t_gobj *z, t_glist *owner, int vis)
+{
+ t_scalar *x = (t_scalar *)z;
+ t_template *template = template_findbyname(x->sc_template);
+ t_canvas *templatecanvas = template_findcanvas(template);
+ t_gobj *y;
+ float basex, basey;
+ if (!templatecanvas)
+ {
+ bug("scalar_vis"); /* it's still a bug, have to fix this for real... */
+ return; /* proposed by Krzysztof Czaja to avoid crashing */
+ }
+ scalar_getbasexy(x, &basex, &basey);
+
+ for (y = templatecanvas->gl_list; y; y = y->g_next)
+ {
+ t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
+ if (!wb) continue;
+ (*wb->w_parentvisfn)(y, owner, x->sc_vec, template, basex, basey, vis);
+ }
+}
+
+static int scalar_click(t_gobj *z, struct _glist *owner,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ t_scalar *x = (t_scalar *)z;
+ int hit = 0;
+ t_template *template = template_findbyname(x->sc_template);
+ t_canvas *templatecanvas = template_findcanvas(template);
+ t_gobj *y;
+ float basex, basey;
+ scalar_getbasexy(x, &basex, &basey);
+ for (y = templatecanvas->gl_list; y; y = y->g_next)
+ {
+ t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
+ if (!wb) continue;
+ if (hit = (*wb->w_parentclickfn)(y, owner,
+ x, template, basex, basey,
+ xpix, ypix, shift, alt, dbl, doit))
+ return (hit);
+ }
+ return (0);
+}
+
+void canvas_writescalar(t_symbol *templatesym, t_word *w, t_binbuf *b,
+ int amarrayelement);
+
+static void scalar_save(t_gobj *z, t_binbuf *b)
+{
+ t_scalar *x = (t_scalar *)z;
+ t_binbuf *b2 = binbuf_new();
+ t_atom a, *argv;
+ int i, argc;
+ canvas_writescalar(x->sc_template, x->sc_vec, b2, 0);
+ binbuf_addv(b, "ss", &s__X, gensym("scalar"));
+ binbuf_addbinbuf(b, b2);
+ binbuf_addsemi(b);
+ binbuf_free(b2);
+}
+
+static void scalar_properties(t_gobj *z, struct _glist *owner)
+{
+ t_scalar *x = (t_scalar *)z;
+ char *buf, buf2[80];
+ int bufsize;
+ t_binbuf *b;
+ glist_noselect(owner);
+ glist_select(owner, z);
+ b = glist_writetobinbuf(owner, 0);
+ binbuf_gettext(b, &buf, &bufsize);
+ binbuf_free(b);
+ t_resizebytes(buf, bufsize, bufsize+1);
+ buf[bufsize] = 0;
+ sprintf(buf2, "pdtk_data_dialog %%s {");
+ gfxstub_new((t_pd *)owner, x, buf2);
+ sys_gui(buf);
+ sys_gui("}\n");
+ t_freebytes(buf, bufsize+1);
+}
+
+static t_widgetbehavior scalar_widgetbehavior =
+{
+ scalar_getrect,
+ scalar_displace,
+ scalar_select,
+ scalar_activate,
+ scalar_delete,
+ scalar_vis,
+ scalar_click,
+ scalar_save,
+ scalar_properties,
+};
+
+static void scalar_free(t_scalar *x)
+{
+ int i;
+ t_dataslot *datatypes, *dt;
+ t_symbol *templatesym = x->sc_template;
+ t_template *template = template_findbyname(templatesym);
+ if (!template)
+ {
+ error("scalar: couldn't find template %s", templatesym->s_name);
+ return;
+ }
+ for (dt = template->t_vec, i = 0; i < template->t_n; i++, dt++)
+ {
+ if (dt->ds_type == DT_ARRAY)
+ array_free(x->sc_vec[i].w_array);
+ else if (dt->ds_type == DT_LIST)
+ canvas_free(x->sc_vec[i].w_list);
+ }
+ gfxstub_deleteforkey(x);
+ /* the "size" field in the class is zero, so Pd doesn't try to free
+ us automatically (see pd_free()) */
+ freebytes(x, sizeof(t_scalar) + (template->t_n - 1) * sizeof(*x->sc_vec));
+}
+
+/* ----------------- setup function ------------------- */
+
+void g_scalar_setup(void)
+{
+ scalar_class = class_new(gensym("scalar"), 0, (t_method)scalar_free, 0,
+ CLASS_GOBJ, 0);
+ class_setwidget(scalar_class, &scalar_widgetbehavior);
+}
diff --git a/pd/src/g_template.c b/pd/src/g_template.c
new file mode 100644
index 00000000..5e11cc5a
--- /dev/null
+++ b/pd/src/g_template.c
@@ -0,0 +1,1673 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "m_imp.h" /* for sys_hostfontsize */
+#include "g_canvas.h"
+
+/*
+This file contains text objects you would put in a canvas to define a
+template. Templates describe objects of type "array" (g_array.c) and
+"scalar" (g_scalar.c).
+*/
+
+ /* the structure of a "struct" object (also the obsolete "gtemplate"
+ you get when using the name "template" in a box.) */
+
+struct _gtemplate
+{
+ t_object x_obj;
+ t_template *x_template;
+ t_canvas *x_owner;
+ t_symbol *x_sym;
+ struct _gtemplate *x_next;
+ int x_argc;
+ t_atom *x_argv;
+};
+
+/* ---------------- forward definitions ---------------- */
+
+static void template_conformarray(t_template *tfrom, t_template *tto,
+ int *conformaction, t_array *a);
+static void template_conformglist(t_template *tfrom, t_template *tto,
+ t_glist *glist, int *conformaction);
+
+/* ---------------------- storage ------------------------- */
+
+static t_class *gtemplate_class;
+static t_class *template_class;
+
+/* there's a pre-defined "float" template. LATER should we bind this
+to a symbol such as "pd-float"??? */
+
+static t_dataslot template_float_vec =
+{
+ DT_FLOAT,
+ &s_y,
+ &s_
+};
+
+static t_template template_float =
+{
+ 0, /* class -- fill in in setup routine */
+ 0, /* list of "struct"/t_gtemplate objects */
+ &s_float, /* name */
+ 1, /* number of items */
+ &template_float_vec
+};
+
+ /* return true if two dataslot definitions match */
+static int dataslot_matches(t_dataslot *ds1, t_dataslot *ds2,
+ int nametoo)
+{
+ return ((!nametoo || ds1->ds_name == ds2->ds_name) &&
+ ds1->ds_type == ds2->ds_type &&
+ (ds1->ds_type != DT_ARRAY ||
+ ds1->ds_arraytemplate == ds2->ds_arraytemplate));
+}
+
+/* -- templates, the active ingredient in gtemplates defined below. ------- */
+
+t_template *template_new(t_symbol *templatesym, int argc, t_atom *argv)
+{
+ t_template *x = (t_template *)pd_new(template_class);
+ x->t_n = 0;
+ x->t_vec = (t_dataslot *)t_getbytes(0);
+ while (argc > 0)
+ {
+ int newtype, oldn, newn;
+ t_symbol *newname, *newarraytemplate = &s_, *newtypesym;
+ if (argc < 2 || argv[0].a_type != A_SYMBOL ||
+ argv[1].a_type != A_SYMBOL)
+ goto bad;
+ newtypesym = argv[0].a_w.w_symbol;
+ newname = argv[1].a_w.w_symbol;
+ if (newtypesym == &s_float)
+ newtype = DT_FLOAT;
+ else if (newtypesym == &s_symbol)
+ newtype = DT_SYMBOL;
+ else if (newtypesym == &s_list)
+ newtype = DT_LIST;
+ else if (newtypesym == gensym("array"))
+ {
+ if (argc < 3 || argv[2].a_type != A_SYMBOL)
+ {
+ pd_error(x, "array lacks element template or name");
+ goto bad;
+ }
+ newarraytemplate = canvas_makebindsym(argv[2].a_w.w_symbol);
+ newtype = DT_ARRAY;
+ argc--;
+ argv++;
+ }
+ else
+ {
+ pd_error(x, "%s: no such type", newtypesym->s_name);
+ return (0);
+ }
+ newn = (oldn = x->t_n) + 1;
+ x->t_vec = (t_dataslot *)t_resizebytes(x->t_vec,
+ oldn * sizeof(*x->t_vec), newn * sizeof(*x->t_vec));
+ x->t_n = newn;
+ x->t_vec[oldn].ds_type = newtype;
+ x->t_vec[oldn].ds_name = newname;
+ x->t_vec[oldn].ds_arraytemplate = newarraytemplate;
+ bad:
+ argc -= 2; argv += 2;
+ }
+ if (templatesym->s_name)
+ {
+ x->t_sym = templatesym;
+ pd_bind(&x->t_pd, x->t_sym);
+ }
+ else x->t_sym = templatesym;
+ return (x);
+}
+
+int template_size(t_template *x)
+{
+ return (x->t_n * sizeof(t_word));
+}
+
+int template_find_field(t_template *x, t_symbol *name, int *p_onset,
+ int *p_type, t_symbol **p_arraytype)
+{
+ t_template *t;
+ int i, n;
+ if (!x)
+ {
+ bug("template_find_field");
+ return (0);
+ }
+ n = x->t_n;
+ for (i = 0; i < n; i++)
+ if (x->t_vec[i].ds_name == name)
+ {
+ *p_onset = i * sizeof(t_word);
+ *p_type = x->t_vec[i].ds_type;
+ *p_arraytype = x->t_vec[i].ds_arraytemplate;
+ return (1);
+ }
+ return (0);
+}
+
+t_float template_getfloat(t_template *x, t_symbol *fieldname, t_word *wp,
+ int loud)
+{
+ int onset, type;
+ t_symbol *arraytype;
+ float val = 0;
+ if (template_find_field(x, fieldname, &onset, &type, &arraytype))
+ {
+ if (type == DT_FLOAT)
+ val = *(t_float *)(((char *)wp) + onset);
+ else if (loud) error("%s.%s: not a number",
+ x->t_sym->s_name, fieldname->s_name);
+ }
+ else if (loud) error("%s.%s: no such field",
+ x->t_sym->s_name, fieldname->s_name);
+ return (val);
+}
+
+void template_setfloat(t_template *x, t_symbol *fieldname, t_word *wp,
+ t_float f, int loud)
+{
+ int onset, type;
+ t_symbol *arraytype;
+ if (template_find_field(x, fieldname, &onset, &type, &arraytype))
+ {
+ if (type == DT_FLOAT)
+ *(t_float *)(((char *)wp) + onset) = f;
+ else if (loud) error("%s.%s: not a number",
+ x->t_sym->s_name, fieldname->s_name);
+ }
+ else if (loud) error("%s.%s: no such field",
+ x->t_sym->s_name, fieldname->s_name);
+}
+
+t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname, t_word *wp,
+ int loud)
+{
+ int onset, type;
+ t_symbol *arraytype;
+ t_symbol *val = &s_;
+ if (template_find_field(x, fieldname, &onset, &type, &arraytype))
+ {
+ if (type == DT_SYMBOL)
+ val = *(t_symbol **)(((char *)wp) + onset);
+ else if (loud) error("%s.%s: not a symbol",
+ x->t_sym->s_name, fieldname->s_name);
+ }
+ else if (loud) error("%s.%s: no such field",
+ x->t_sym->s_name, fieldname->s_name);
+ return (val);
+}
+
+void template_setsymbol(t_template *x, t_symbol *fieldname, t_word *wp,
+ t_symbol *s, int loud)
+{
+ int onset, type;
+ t_symbol *arraytype;
+ if (template_find_field(x, fieldname, &onset, &type, &arraytype))
+ {
+ if (type == DT_SYMBOL)
+ *(t_symbol **)(((char *)wp) + onset) = s;
+ else if (loud) error("%s.%s: not a symbol",
+ x->t_sym->s_name, fieldname->s_name);
+ }
+ else if (loud) error("%s.%s: no such field",
+ x->t_sym->s_name, fieldname->s_name);
+}
+
+ /* stringent check to see if a "saved" template, x2, matches the current
+ one (x1). It's OK if x1 has additional scalar elements but not (yet)
+ arrays or lists. This is used for reading in "data files". */
+int template_match(t_template *x1, t_template *x2)
+{
+ int i;
+ if (x1->t_n < x2->t_n)
+ return (0);
+ for (i = x2->t_n; i < x1->t_n; i++)
+ {
+ if (x1->t_vec[i].ds_type == DT_ARRAY ||
+ x1->t_vec[i].ds_type == DT_LIST)
+ return (0);
+ }
+ if (x2->t_n > x1->t_n)
+ post("add elements...");
+ for (i = 0; i < x2->t_n; i++)
+ if (!dataslot_matches(&x1->t_vec[i], &x2->t_vec[i], 1))
+ return (0);
+ return (1);
+}
+
+/* --------------- CONFORMING TO CHANGES IN A TEMPLATE ------------ */
+
+/* the following routines handle updating scalars to agree with changes
+in their template. The old template is assumed to be the "installed" one
+so we can delete old items; but making new ones we have to avoid scalar_new
+which would make an old one whereas we will want a new one (but whose array
+elements might still be old ones.
+ LATER deal with graphics updates too... */
+
+ /* conform the word vector of a scalar to the new template */
+static void template_conformwords(t_template *tfrom, t_template *tto,
+ int *conformaction, t_word *wfrom, t_word *wto)
+{
+ int nfrom = tfrom->t_n, nto = tto->t_n, i;
+ for (i = 0; i < nto; i++)
+ {
+ if (conformaction[i] >= 0)
+ {
+ /* we swap the two, in case it's an array or list, so that
+ when "wfrom" is deleted the old one gets cleaned up. */
+ t_word wwas = wto[i];
+ wto[i] = wfrom[conformaction[i]];
+ wfrom[conformaction[i]] = wwas;
+ }
+ }
+}
+
+ /* conform a scalar, recursively conforming sublists and arrays */
+static t_scalar *template_conformscalar(t_template *tfrom, t_template *tto,
+ int *conformaction, t_glist *glist, t_scalar *scfrom)
+{
+ t_scalar *x;
+ t_gpointer gp;
+ int nto = tto->t_n, nfrom = tfrom->t_n, i;
+ post("conform scalar");
+ /* possibly replace the scalar */
+ if (scfrom->sc_template == tfrom->t_sym)
+ {
+ post("match");
+ /* see scalar_new() for comment about the gpointer. */
+ gpointer_init(&gp);
+ x = (t_scalar *)getbytes(sizeof(t_scalar) +
+ (tto->t_n - 1) * sizeof(*x->sc_vec));
+ x->sc_gobj.g_pd = scalar_class;
+ x->sc_template = tfrom->t_sym;
+ gpointer_setglist(&gp, glist, x);
+ /* Here we initialize to the new template, but array and list
+ elements will still belong to old template. */
+ word_init(x->sc_vec, tto, &gp);
+
+ template_conformwords(tfrom, tto, conformaction,
+ scfrom->sc_vec, x->sc_vec);
+
+ /* replace the old one with the new one in the list */
+ if (glist->gl_list == &scfrom->sc_gobj)
+ {
+ glist->gl_list = &x->sc_gobj;
+ x->sc_gobj.g_next = scfrom->sc_gobj.g_next;
+ }
+ else
+ {
+ t_gobj *y, *y2;
+ for (y = glist->gl_list; y2 = y->g_next; y = y2)
+ if (y2 == &scfrom->sc_gobj)
+ {
+ x->sc_gobj.g_next = y2->g_next;
+ y->g_next = &x->sc_gobj;
+ goto nobug;
+ }
+ bug("template_conformscalar");
+ nobug: ;
+ }
+ /* burn the old one */
+ pd_free(&scfrom->sc_gobj.g_pd);
+ }
+ else x = scfrom;
+ /* convert all array elements and sublists */
+ for (i = 0; i < nto; i++)
+ {
+ if (tto->t_vec[i].ds_type == DT_LIST)
+ {
+ t_glist *gl2 = x->sc_vec[i].w_list;
+ template_conformglist(tfrom, tto, gl2, conformaction);
+ }
+ else if (tto->t_vec[i].ds_type == DT_ARRAY)
+ {
+ template_conformarray(tfrom, tto, conformaction,
+ x->sc_vec[i].w_array);
+ }
+ }
+ return (x);
+}
+
+ /* conform an array, recursively conforming sublists and arrays */
+static void template_conformarray(t_template *tfrom, t_template *tto,
+ int *conformaction, t_array *a)
+{
+ int i;
+ if (a->a_templatesym == tfrom->t_sym)
+ {
+ /* the array elements must all be conformed */
+ int oldelemsize = sizeof(t_word) * tfrom->t_n,
+ newelemsize = sizeof(t_word) * tto->t_n;
+ char *newarray = getbytes(sizeof(t_word) * tto->t_n * a->a_n);
+ char *oldarray = a->a_vec;
+ if (a->a_elemsize != oldelemsize)
+ bug("template_conformarray");
+ for (i = 0; i < a->a_n; i++)
+ {
+ t_word *wp = (t_word *)(newarray + newelemsize * i);
+ word_init(wp, tto, &a->a_gp);
+ template_conformwords(tfrom, tto, conformaction,
+ (t_word *)(oldarray + oldelemsize * i), wp);
+ }
+ }
+ bug("template_conformarray: this part not written");
+ /* go through item by item conforming subarrays and sublists... */
+}
+
+ /* this routine searches for every scalar in the glist that belongs
+ to the "from" template and makes it belong to the "to" template. Descend
+ glists recursively.
+ We don't handle redrawing here; this is to be filled in LATER... */
+
+static void template_conformglist(t_template *tfrom, t_template *tto,
+ t_glist *glist, int *conformaction)
+{
+ t_gobj *g;
+ post("conform glist %s", glist->gl_name->s_name);
+ for (g = glist->gl_list; g; g = g->g_next)
+ {
+ if (pd_class(&g->g_pd) == scalar_class)
+ g = &template_conformscalar(tfrom, tto, conformaction,
+ glist, (t_scalar *)g)->sc_gobj;
+ else if (pd_class(&g->g_pd) == canvas_class)
+ template_conformglist(tfrom, tto, (t_glist *)g, conformaction);
+ }
+}
+
+ /* globally conform all scalars from one template to another */
+void template_conform(t_template *tfrom, t_template *tto)
+{
+ int nto = tto->t_n, nfrom = tfrom->t_n, i, j,
+ *conformaction = (int *)getbytes(sizeof(int) * nto),
+ *conformedfrom = (int *)getbytes(sizeof(int) * nfrom), doit = 0;
+ for (i = 0; i < nto; i++)
+ conformaction[i] = -1;
+ for (i = 0; i < nfrom; i++)
+ conformedfrom[i] = 0;
+ for (i = 0; i < nto; i++)
+ {
+ t_dataslot *dataslot = &tto->t_vec[i];
+ for (j = 0; j < nfrom; j++)
+ {
+ t_dataslot *dataslot2 = &tfrom->t_vec[j];
+ if (dataslot_matches(dataslot, dataslot2, 1))
+ {
+ conformaction[i] = j;
+ conformedfrom[j] = 1;
+ }
+ }
+ }
+ for (i = 0; i < nto; i++)
+ if (conformaction[i] < 0)
+ {
+ t_dataslot *dataslot = &tto->t_vec[i];
+ for (j = 0; j < nfrom; j++)
+ if (!conformedfrom[j] &&
+ dataslot_matches(dataslot, &tfrom->t_vec[j], 1))
+ {
+ conformaction[i] = j;
+ conformedfrom[j] = 1;
+ }
+ }
+ if (nto != nfrom)
+ doit = 1;
+ else for (i = 0; i < nto; i++)
+ if (conformaction[i] != i)
+ doit = 1;
+
+ if (doit)
+ {
+ t_glist *gl;
+ post("conforming template '%s' to new structure",
+ tfrom->t_sym->s_name);
+ for (i = 0; i < nto; i++)
+ post("... %d", conformaction[i]);
+ for (gl = canvas_list; gl; gl = gl->gl_next)
+ template_conformglist(tfrom, tto, gl, conformaction);
+ }
+ freebytes(conformaction, sizeof(int) * nto);
+ freebytes(conformedfrom, sizeof(int) * nfrom);
+}
+
+t_template *template_findbyname(t_symbol *s)
+{
+ int i;
+ if (s == &s_float)
+ return (&template_float);
+ else return ((t_template *)pd_findbyclass(s, template_class));
+}
+
+t_canvas *template_findcanvas(t_template *template)
+{
+ t_gtemplate *gt;
+ if (!template)
+ bug("template_findcanvas");
+ if (!(gt = template->t_list))
+ return (0);
+ return (gt->x_owner);
+ /* return ((t_canvas *)pd_findbyclass(template->t_sym, canvas_class)); */
+}
+
+ /* call this when reading a patch from a file to declare what templates
+ we'll need. If there's already a template, check if it matches.
+ If it doesn't it's still OK as long as there are no "struct" (gtemplate)
+ objects hanging from it; we just conform everyone to the new template.
+ If there are still struct objects belonging to the other template, we're
+ in trouble. LATER we'll figure out how to conform the new patch's objects
+ to the pre-existing struct. */
+static void *template_usetemplate(void *dummy, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ t_template *x;
+ t_symbol *templatesym =
+ canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
+ if (!argc)
+ return (0);
+ argc--; argv++;
+ /* check if there's already a template by this name. */
+ if ((x = (t_template *)pd_findbyclass(templatesym, template_class)))
+ {
+ t_template *y = template_new(&s_, argc, argv);
+ /* If the new template is the same as the old one,
+ there's nothing to do. */
+ if (!template_match(x, y))
+ {
+ /* Are there "struct" objects upholding this template? */
+ if (x->t_list)
+ {
+ /* don't know what to do here! */
+ error("%s: template mismatch",
+ templatesym->s_name);
+ }
+ else
+ {
+ /* conform everyone to the new template */
+ template_conform(x, y);
+ pd_free(&x->t_pd);
+ template_new(templatesym, argc, argv);
+ }
+ }
+ pd_free(&y->t_pd);
+ }
+ /* otherwise, just make one. */
+ else template_new(templatesym, argc, argv);
+ return (0);
+}
+
+ /* here we assume someone has already cleaned up all instances of this. */
+void template_free(t_template *x)
+{
+ if (*x->t_sym->s_name)
+ pd_unbind(&x->t_pd, x->t_sym);
+ t_freebytes(x->t_vec, x->t_n * sizeof(*x->t_vec));
+}
+
+static void template_setup(void)
+{
+ template_class = class_new(gensym("template"), 0, (t_method)template_free,
+ sizeof(t_template), CLASS_PD, 0);
+ class_addmethod(pd_canvasmaker, (t_method)template_usetemplate,
+ gensym("struct"), A_GIMME, 0);
+
+}
+
+/* ---------------- gtemplates. One per canvas. ----------- */
+
+/* this is a "text" object that searches for, and if necessary creates,
+a "template" (above). Other objects in the canvas then can give drawing
+instructions for the template. The template doesn't go away when the
+gtemplate is deleted, so that you can replace it with
+another one to add new fields, for example. */
+
+static void *gtemplate_donew(t_symbol *sym, int argc, t_atom *argv)
+{
+ t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class);
+ t_template *t = template_findbyname(sym);
+ int i;
+ t_symbol *sx = gensym("x");
+ x->x_owner = canvas_getcurrent();
+ x->x_next = 0;
+ x->x_sym = sym;
+ x->x_argc = argc;
+ x->x_argv = (t_atom *)getbytes(argc * sizeof(t_atom));
+ for (i = 0; i < argc; i++)
+ x->x_argv[i] = argv[i];
+
+ /* already have a template by this name? */
+ if (t)
+ {
+ x->x_template = t;
+ /* if it's already got a "struct" or "gtemplate" object we
+ just tack this one to the end of the list and leave it
+ there. */
+ if (t->t_list)
+ {
+ t_gtemplate *x2, *x3;
+ for (x2 = x->x_template->t_list; x3 = x2->x_next; x2 = x3)
+ ;
+ x2->x_next = x;
+ post("template %s: warning: already exists.", sym->s_name);
+ }
+ else
+ {
+ /* if there's none, we just replace the template with
+ our own and conform it. */
+ t_template *y = template_new(&s_, argc, argv);
+ /* Unless the new template is different from the old one,
+ there's nothing to do. */
+ if (!template_match(t, y))
+ {
+ /* conform everyone to the new template */
+ template_conform(t, y);
+ pd_free(&t->t_pd);
+ t = template_new(sym, argc, argv);
+ }
+ pd_free(&y->t_pd);
+ t->t_list = x;
+ }
+ }
+ else
+ {
+ /* otherwise make a new one and we're the only struct on it. */
+ x->x_template = t = template_new(sym, argc, argv);
+ t->t_list = x;
+ }
+ return (x);
+}
+
+static void *gtemplate_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class);
+ t_symbol *sym = atom_getsymbolarg(0, argc, argv);
+ if (argc >= 1)
+ argc--; argv++;
+ return (gtemplate_donew(canvas_makebindsym(sym), argc, argv));
+}
+
+ /* old version (0.34) -- delete 2003 or so */
+static void *gtemplate_new_old(t_symbol *s, int argc, t_atom *argv)
+{
+ t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class);
+ t_symbol *sym = canvas_makebindsym(canvas_getcurrent()->gl_name);
+ static int warned;
+ if (!warned)
+ {
+ post("warning -- 'template' is obsolete; replace with 'struct'");
+ warned = 1;
+ }
+ post("name: %s", sym->s_name);
+ return (gtemplate_donew(sym, argc, argv));
+}
+
+t_template *gtemplate_get(t_gtemplate *x)
+{
+ return (x->x_template);
+}
+
+static void gtemplate_free(t_gtemplate *x)
+{
+ /* get off the template's list */
+ t_template *t = x->x_template;
+ if (x == t->t_list)
+ {
+ if (x->x_next)
+ {
+ /* if we were first on the list, and there are others on
+ the list, make a new template corresponding to the new
+ first-on-list and replace teh existing template with it. */
+ t_template *z = template_new(&s_, x->x_argc, x->x_argv);
+ template_conform(t, z);
+ pd_free(&t->t_pd);
+ pd_free(&z->t_pd);
+ z = template_new(x->x_sym, x->x_argc, x->x_argv);
+ z->t_list = x->x_next;
+ }
+ else t->t_list = 0;
+ }
+ else
+ {
+ t_gtemplate *x2, *x3;
+ for (x2 = t->t_list; x3 = x2->x_next; x2 = x3)
+ {
+ if (x == x3)
+ {
+ x2->x_next = x3->x_next;
+ break;
+ }
+ }
+ }
+ freebytes(x->x_argv, sizeof(t_atom) * x->x_argc);
+}
+
+static void gtemplate_setup(void)
+{
+ gtemplate_class = class_new(gensym("struct"),
+ (t_newmethod)gtemplate_new, (t_method)gtemplate_free,
+ sizeof(t_gtemplate), CLASS_NOINLET, A_GIMME, 0);
+ class_addcreator((t_newmethod)gtemplate_new_old, gensym("template"),
+ A_GIMME, 0);
+}
+
+/* --------------- FIELD DESCRIPTORS ---------------------- */
+
+/* a field descriptor can hold a constant or a variable; if a variable,
+it's the name of a field in the template we belong to. LATER, we might
+want to cache the offset of the field so we don't have to search for it
+every single time we draw the object.
+*/
+
+typedef struct _fielddesc
+{
+ char fd_type; /* LATER consider removing this? */
+ char fd_var;
+ union
+ {
+ t_float fd_float; /* the field is a constant float */
+ t_symbol *fd_symbol; /* the field is a constant symbol */
+ t_symbol *fd_varsym; /* the field is variable and this is the name */
+ } fd_un;
+} t_fielddesc;
+
+#define FIELDDESC_SETFLOAT(x, f) \
+ ((x)->fd_type = A_FLOAT, (x)->fd_var = 0, (x)->fd_un.fd_float = (f))
+#define FIELDDESC_SETSYMBOL(x, s) \
+ ((x)->fd_type = A_SYMBOL, (x)->fd_var = 0, (x)->fd_un.fd_symbol = (s))
+#define FIELDDESC_SETVAR(x, s, type) \
+ ((x)->fd_type = type, (x)->fd_var = 1, (x)->fd_un.fd_varsym = (s))
+
+#define CLOSED 1
+#define BEZ 2
+#define A_ARRAY 55 /* LATER decide whether to enshrine this in m_pd.h */
+
+static void fielddesc_setfloatarg(t_fielddesc *fd, int argc, t_atom *argv)
+{
+ if (argc <= 0) FIELDDESC_SETFLOAT(fd, 0);
+ else if (argv->a_type == A_SYMBOL)
+ FIELDDESC_SETVAR(fd, argv->a_w.w_symbol, A_FLOAT);
+ else FIELDDESC_SETFLOAT(fd, argv->a_w.w_float);
+}
+
+static void fielddesc_setarrayarg(t_fielddesc *fd, int argc, t_atom *argv)
+{
+ if (argc <= 0) FIELDDESC_SETFLOAT(fd, 0);
+ else if (argv->a_type == A_SYMBOL)
+ FIELDDESC_SETVAR(fd, argv->a_w.w_symbol, A_ARRAY);
+ else FIELDDESC_SETFLOAT(fd, argv->a_w.w_float);
+}
+
+static t_float fielddesc_getfloat(t_fielddesc *f, t_template *template,
+ t_word *wp, int loud)
+{
+ if (f->fd_type == A_FLOAT)
+ {
+ if (f->fd_var)
+ return (template_getfloat(template, f->fd_un.fd_varsym, wp, loud));
+ else return (f->fd_un.fd_float);
+ }
+ else
+ {
+ if (loud)
+ error("symbolic data field used as number");
+ return (0);
+ }
+}
+
+static t_symbol *fielddesc_getsymbol(t_fielddesc *f, t_template *template,
+ t_word *wp, int loud)
+{
+ if (f->fd_type == A_SYMBOL)
+ {
+ if (f->fd_var)
+ return(template_getsymbol(template, f->fd_un.fd_varsym, wp, loud));
+ else return (f->fd_un.fd_symbol);
+ }
+ else
+ {
+ if (loud)
+ error("numeric data field used as symbol");
+ return (&s_);
+ }
+}
+
+/* ---------------- curves and polygons (joined segments) ---------------- */
+
+/*
+curves belong to templates and describe how the data in the template are to
+be drawn. The coordinates of the curve (and other display features) can
+be attached to fields in the template.
+*/
+
+t_class *curve_class;
+
+typedef struct _curve
+{
+ t_object x_obj;
+ int x_flags; /* CLOSED and/or BEZ */
+ t_fielddesc x_fillcolor;
+ t_fielddesc x_outlinecolor;
+ t_fielddesc x_width;
+ int x_npoints;
+ t_fielddesc *x_vec;
+} t_curve;
+
+static void *curve_new(t_symbol *classsym, t_int argc, t_atom *argv)
+{
+ t_curve *x = (t_curve *)pd_new(curve_class);
+ char *classname = classsym->s_name;
+ int flags = 0;
+ int nxy, i;
+ t_fielddesc *fd;
+ if (classname[0] == 'f')
+ {
+ classname += 6;
+ flags |= CLOSED;
+ if (argc) fielddesc_setfloatarg(&x->x_fillcolor, argc--, argv++);
+ else FIELDDESC_SETFLOAT(&x->x_outlinecolor, 0);
+ }
+ else classname += 4;
+ if (classname[0] == 'c') flags |= BEZ;
+ x->x_flags = flags;
+ if (argc) fielddesc_setfloatarg(&x->x_outlinecolor, argc--, argv++);
+ else FIELDDESC_SETFLOAT(&x->x_outlinecolor, 0);
+ if (argc) fielddesc_setfloatarg(&x->x_width, argc--, argv++);
+ else FIELDDESC_SETFLOAT(&x->x_width, 1);
+ if (argc < 0) argc = 0;
+ nxy = (argc + (argc & 1));
+ x->x_npoints = (nxy>>1);
+ x->x_vec = (t_fielddesc *)t_getbytes(nxy * sizeof(t_fielddesc));
+ for (i = 0, fd = x->x_vec; i < argc; i++, fd++, argv++)
+ fielddesc_setfloatarg(fd, 1, argv);
+ if (argc & 1) FIELDDESC_SETFLOAT(fd, 0);
+
+ return (x);
+}
+
+/* -------------------- widget behavior for curve ------------ */
+
+static void curve_getrect(t_gobj *z, t_glist *glist,
+ t_word *data, t_template *template, float basex, float basey,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_curve *x = (t_curve *)z;
+ int i, n = x->x_npoints;
+ t_fielddesc *f = x->x_vec;
+ int x1 = 0x7fffffff, x2 = -0x7fffffff, y1 = 0x7fffffff, y2 = -0x7fffffff;
+ for (i = 0, f = x->x_vec; i < n; i++, f += 2)
+ {
+ int xloc = glist_xtopixels(glist,
+ basex + fielddesc_getfloat(f, template, data, 0));
+ int yloc = glist_ytopixels(glist,
+ basey + fielddesc_getfloat(f+1, template, data, 0));
+ if (xloc < x1) x1 = xloc;
+ if (xloc > x2) x2 = xloc;
+ if (yloc < y1) y1 = yloc;
+ if (yloc > y2) y2 = yloc;
+ }
+ *xp1 = x1;
+ *yp1 = y1;
+ *xp2 = x2;
+ *yp2 = y2;
+}
+
+static void curve_displace(t_gobj *z, t_glist *glist,
+ t_word *data, t_template *template, float basex, float basey,
+ int dx, int dy)
+{
+ /* refuse */
+}
+
+static void curve_select(t_gobj *z, t_glist *glist,
+ t_word *data, t_template *template, float basex, float basey,
+ int state)
+{
+ /* fill in later */
+}
+
+static void curve_activate(t_gobj *z, t_glist *glist,
+ t_word *data, t_template *template, float basex, float basey,
+ int state)
+{
+ /* fill in later */
+}
+
+static int rangecolor(int n) /* 0 to 9 in 5 steps */
+{
+ int n2 = n/2; /* 0 to 4 */
+ int ret = (n << 6); /* 0 to 256 in 5 steps */
+ if (ret > 255) ret = 255;
+ return (ret);
+}
+
+static void numbertocolor(int n, char *s)
+{
+ int red, blue, green;
+ if (n < 0) n = 0;
+ red = n / 100;
+ blue = ((n / 10) % 10);
+ green = n % 10;
+ sprintf(s, "#%2.2x%2.2x%2.2x", rangecolor(red), rangecolor(blue),
+ rangecolor(green));
+}
+
+static void curve_vis(t_gobj *z, t_glist *glist,
+ t_word *data, t_template *template, float basex, float basey,
+ int vis)
+{
+ t_curve *x = (t_curve *)z;
+ int i, n = x->x_npoints;
+ t_fielddesc *f = x->x_vec;
+
+ if (vis)
+ {
+ if (n > 1)
+ {
+ int flags = x->x_flags, closed = (flags & CLOSED);
+ float width = fielddesc_getfloat(&x->x_width, template, data, 1);
+ char outline[20], fill[20];
+ if (width < 1) width = 1;
+ numbertocolor(
+ fielddesc_getfloat(&x->x_outlinecolor, template, data, 1),
+ outline);
+ if (flags & CLOSED)
+ {
+ numbertocolor(
+ fielddesc_getfloat(&x->x_fillcolor, template, data, 1),
+ fill);
+ sys_vgui(".x%x.c create polygon\\\n",
+ glist_getcanvas(glist));
+ }
+ else sys_vgui(".x%x.c create line\\\n",
+ glist_getcanvas(glist));
+ for (i = 0, f = x->x_vec; i < n; i++, f += 2)
+ {
+ float xloc = glist_xtopixels(glist,
+ basex + fielddesc_getfloat(f, template, data, 1));
+ float yloc = glist_ytopixels(glist,
+ basey + fielddesc_getfloat(f+1, template, data, 1));
+ sys_vgui("%d %d\\\n", (int)xloc, (int)yloc);
+ }
+ sys_vgui("-width %f\\\n",
+ fielddesc_getfloat(&x->x_width, template, data, 1));
+ if (flags & CLOSED) sys_vgui("-fill %s -outline %s\\\n",
+ fill, outline);
+ else sys_vgui("-fill %s\\\n", outline);
+ if (flags & BEZ) sys_vgui("-smooth 1\\\n");
+ sys_vgui("-tags curve%x\n", data);
+ }
+ else post("warning: curves need at least two points to be graphed");
+ }
+ else
+ {
+ if (n > 1) sys_vgui(".x%x.c delete curve%x\n",
+ glist_getcanvas(glist), data);
+ }
+}
+
+static int curve_motion_field;
+static float curve_motion_xcumulative;
+static float curve_motion_xbase;
+static float curve_motion_xper;
+static float curve_motion_ycumulative;
+static float curve_motion_ybase;
+static float curve_motion_yper;
+static t_glist *curve_motion_glist;
+static t_gobj *curve_motion_gobj;
+static t_word *curve_motion_wp;
+static t_template *curve_motion_template;
+
+ /* LATER protect against the template changing or the scalar disappearing
+ probably by attaching a gpointer here ... */
+
+static void curve_motion(void *z, t_floatarg dx, t_floatarg dy)
+{
+ t_curve *x = (t_curve *)z;
+ t_fielddesc *f = x->x_vec + curve_motion_field;
+ curve_motion_xcumulative += dx;
+ curve_motion_ycumulative += dy;
+ if (f->fd_var)
+ {
+ template_setfloat(curve_motion_template,
+ f->fd_un.fd_varsym,
+ curve_motion_wp,
+ curve_motion_xbase + curve_motion_xcumulative * curve_motion_xper,
+ 1);
+ }
+ if ((f+1)->fd_var)
+ {
+ template_setfloat(curve_motion_template,
+ (f+1)->fd_un.fd_varsym,
+ curve_motion_wp,
+ curve_motion_ybase + curve_motion_ycumulative * curve_motion_yper,
+ 1);
+ }
+ glist_redrawitem(curve_motion_glist, curve_motion_gobj);
+}
+
+static int curve_click(t_gobj *z, t_glist *glist,
+ t_scalar *sc, t_template *template, float basex, float basey,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ t_curve *x = (t_curve *)z;
+ int i, n = x->x_npoints;
+ int bestn = -1;
+ int besterror = 0x7fffffff;
+ t_fielddesc *f = x->x_vec;
+ t_word *data = sc->sc_vec;
+ for (i = 0, f = x->x_vec; i < n; i++, f += 2)
+ {
+ int xloc = glist_xtopixels(glist,
+ basex + fielddesc_getfloat(f, template, data, 0));
+ int yloc = glist_ytopixels(glist,
+ basey + fielddesc_getfloat(f+1, template, data, 0));
+ int xerr = xloc - xpix, yerr = yloc - ypix;
+ if (!f->fd_var && !(f+1)->fd_var)
+ continue;
+ if (xerr < 0)
+ xerr = -xerr;
+ if (yerr < 0)
+ yerr = -yerr;
+ if (yerr > xerr)
+ xerr = yerr;
+ if (xerr < besterror)
+ {
+ besterror = xerr;
+ bestn = i;
+ curve_motion_xbase = fielddesc_getfloat(f, template, data, 0);
+ curve_motion_ybase = fielddesc_getfloat(f+1, template, data, 0);
+ }
+ }
+ if (besterror > 10)
+ return (0);
+ if (doit)
+ {
+ curve_motion_xper = glist_pixelstox(glist, 1)
+ - glist_pixelstox(glist, 0);
+ curve_motion_yper = glist_pixelstoy(glist, 1)
+ - glist_pixelstoy(glist, 0);
+ curve_motion_xcumulative = curve_motion_ycumulative = 0;
+ curve_motion_glist = glist;
+ curve_motion_gobj = &sc->sc_gobj;
+ curve_motion_wp = data;
+ curve_motion_field = 2*bestn;
+ curve_motion_template = template;
+ glist_grab(glist, z, curve_motion, 0, xpix, ypix);
+ }
+ return (1);
+}
+
+t_parentwidgetbehavior curve_widgetbehavior =
+{
+ curve_getrect,
+ curve_displace,
+ curve_select,
+ curve_activate,
+ curve_vis,
+ curve_click,
+};
+
+static void curve_free(t_curve *x)
+{
+ t_freebytes(x->x_vec, 2 * x->x_npoints * sizeof(*x->x_vec));
+}
+
+static void curve_setup(void)
+{
+ curve_class = class_new(gensym("drawpolygon"), (t_newmethod)curve_new,
+ (t_method)curve_free, sizeof(t_curve), CLASS_NOINLET, A_GIMME, 0);
+ class_setdrawcommand(curve_class);
+ class_addcreator((t_newmethod)curve_new, gensym("drawcurve"),
+ A_GIMME, 0);
+ class_addcreator((t_newmethod)curve_new, gensym("filledpolygon"),
+ A_GIMME, 0);
+ class_addcreator((t_newmethod)curve_new, gensym("filledcurve"),
+ A_GIMME, 0);
+ class_setparentwidget(curve_class, &curve_widgetbehavior);
+}
+
+/* --------- plots for showing arrays --------------- */
+
+t_class *plot_class;
+
+typedef struct _plot
+{
+ t_object x_obj;
+ int x_flags;
+ t_fielddesc x_outlinecolor;
+ t_fielddesc x_width;
+ t_fielddesc x_xloc;
+ t_fielddesc x_yloc;
+ t_fielddesc x_xinc;
+ t_fielddesc x_data;
+} t_plot;
+
+static void *plot_new(t_symbol *classsym, t_int argc, t_atom *argv)
+{
+ t_plot *x = (t_plot *)pd_new(plot_class);
+ int flags = 0;
+ int nxy, i;
+ t_fielddesc *fd;
+ t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
+ if (!strcmp(firstarg->s_name, "curve"))
+ {
+ flags |= BEZ;
+ argc--, argv++;
+ }
+ if (argc) fielddesc_setarrayarg(&x->x_data, argc--, argv++);
+ else FIELDDESC_SETFLOAT(&x->x_data, 1);
+ if (argc) fielddesc_setfloatarg(&x->x_outlinecolor, argc--, argv++);
+ else FIELDDESC_SETFLOAT(&x->x_outlinecolor, 0);
+ if (argc) fielddesc_setfloatarg(&x->x_width, argc--, argv++);
+ else FIELDDESC_SETFLOAT(&x->x_width, 1);
+ if (argc) fielddesc_setfloatarg(&x->x_xloc, argc--, argv++);
+ else FIELDDESC_SETFLOAT(&x->x_xloc, 1);
+ if (argc) fielddesc_setfloatarg(&x->x_yloc, argc--, argv++);
+ else FIELDDESC_SETFLOAT(&x->x_yloc, 1);
+ if (argc) fielddesc_setfloatarg(&x->x_xinc, argc--, argv++);
+ else FIELDDESC_SETFLOAT(&x->x_xinc, 1);
+ x->x_flags = flags;
+ return (x);
+}
+
+/* -------------------- widget behavior for plot ------------ */
+
+
+ /* get everything we'll need from the owner template of the array being
+ plotted. Not used for garrays, but see below */
+static int plot_readownertemplate(t_plot *x,
+ t_word *data, t_template *ownertemplate,
+ t_symbol **elemtemplatesymp, t_array **arrayp,
+ float *linewidthp, float *xlocp, float *xincp, float *ylocp)
+{
+ int arrayonset, type;
+ t_symbol *elemtemplatesym;
+ t_array *array;
+
+ /* find the data and verify it's an array */
+ if (x->x_data.fd_type != A_ARRAY || !x->x_data.fd_var)
+ {
+ error("plot: needs an array field");
+ return (-1);
+ }
+ if (!template_find_field(ownertemplate, x->x_data.fd_un.fd_varsym,
+ &arrayonset, &type, &elemtemplatesym))
+ {
+ error("plot: %s: no such field", x->x_data.fd_un.fd_varsym->s_name);
+ return (-1);
+ }
+ if (type != DT_ARRAY)
+ {
+ error("plot: %s: not an array", x->x_data.fd_un.fd_varsym->s_name);
+ return (-1);
+ }
+ array = *(t_array **)(((char *)data) + arrayonset);
+ *linewidthp = fielddesc_getfloat(&x->x_width, ownertemplate, data, 1);
+ *xlocp = fielddesc_getfloat(&x->x_xloc, ownertemplate, data, 1);
+ *xincp = fielddesc_getfloat(&x->x_xinc, ownertemplate, data, 1);
+ *ylocp = fielddesc_getfloat(&x->x_yloc, ownertemplate, data, 1);
+ *elemtemplatesymp = elemtemplatesym;
+ *arrayp = array;
+ return (0);
+}
+
+ /* get everything else you could possibly need about a plot,
+ either for plot's own purposes or for plotting a "garray" */
+int array_getfields(t_symbol *elemtemplatesym,
+ t_canvas **elemtemplatecanvasp,
+ t_template **elemtemplatep, int *elemsizep,
+ int *xonsetp, int *yonsetp, int *wonsetp)
+{
+ int arrayonset, elemsize, yonset, wonset, xonset, type;
+ t_template *elemtemplate;
+ t_symbol *dummy;
+ t_canvas *elemtemplatecanvas = 0;
+
+ /* the "float" template is special in not having to have a canvas;
+ template_findbyname is hardwired to return a predefined
+ template. */
+
+ if (!(elemtemplate = template_findbyname(elemtemplatesym)))
+ {
+ error("plot: %s: no such template", elemtemplatesym->s_name);
+ return (-1);
+ }
+ if (!((elemtemplatesym == &s_float) ||
+ (elemtemplatecanvas = template_findcanvas(elemtemplate))))
+ {
+ error("plot: %s: no canvas for this template", elemtemplatesym->s_name);
+ return (-1);
+ }
+ elemsize = elemtemplate->t_n * sizeof(t_word);
+ if (!template_find_field(elemtemplate, gensym("y"), &yonset, &type, &dummy)
+ || type != DT_FLOAT)
+ yonset = -1;
+ if (!template_find_field(elemtemplate, gensym("x"), &xonset, &type, &dummy)
+ || type != DT_FLOAT)
+ xonset = -1;
+ if (!template_find_field(elemtemplate, gensym("w"), &wonset, &type, &dummy)
+ || type != DT_FLOAT)
+ wonset = -1;
+
+ /* fill in slots for return values */
+ *elemtemplatecanvasp = elemtemplatecanvas;
+ *elemtemplatep = elemtemplate;
+ *elemsizep = elemsize;
+ *xonsetp = xonset;
+ *yonsetp = yonset;
+ *wonsetp = wonset;
+ return (0);
+}
+
+static void plot_getrect(t_gobj *z, t_glist *glist,
+ t_word *data, t_template *template, float basex, float basey,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_plot *x = (t_plot *)z;
+ int elemsize, yonset, wonset, xonset;
+ t_canvas *elemtemplatecanvas;
+ t_template *elemtemplate;
+ t_symbol *elemtemplatesym;
+ float linewidth, xloc, xinc, yloc;
+ t_array *array;
+ float x1 = 0x7fffffff, y1 = 0x7fffffff, x2 = -0x7fffffff, y2 = -0x7fffffff;
+ int i;
+ float xpix, ypix, wpix;
+
+ if (!plot_readownertemplate(x, data, template,
+ &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc) &&
+ !array_getfields(elemtemplatesym, &elemtemplatecanvas,
+ &elemtemplate, &elemsize, &xonset, &yonset, &wonset))
+ {
+ for (i = 0; i < array->a_n; i++)
+ {
+ array_getcoordinate(glist, (char *)(array->a_vec) + i * elemsize,
+ xonset, yonset, wonset, i, basex + xloc, basey + yloc, xinc,
+ &xpix, &ypix, &wpix);
+ if (xpix < x1)
+ x1 = xpix;
+ if (xpix > x2)
+ x2 = xpix;
+ if (ypix - wpix < y1)
+ y1 = ypix - wpix;
+ if (ypix + wpix > y2)
+ y2 = ypix + wpix;
+ }
+ }
+
+ *xp1 = x1;
+ *yp1 = y1;
+ *xp2 = x2;
+ *yp2 = y2;
+}
+
+static void plot_displace(t_gobj *z, t_glist *glist,
+ t_word *data, t_template *template, float basex, float basey,
+ int dx, int dy)
+{
+ /* not yet */
+}
+
+static void plot_select(t_gobj *z, t_glist *glist,
+ t_word *data, t_template *template, float basex, float basey,
+ int state)
+{
+ /* not yet */
+}
+
+static void plot_activate(t_gobj *z, t_glist *glist,
+ t_word *data, t_template *template, float basex, float basey,
+ int state)
+{
+ /* not yet */
+}
+
+static void plot_vis(t_gobj *z, t_glist *glist,
+ t_word *data, t_template *template, float basex, float basey,
+ int vis)
+{
+ t_plot *x = (t_plot *)z;
+ int elemsize, yonset, wonset, xonset;
+ t_canvas *elemtemplatecanvas;
+ t_template *elemtemplate;
+ t_symbol *elemtemplatesym;
+ float linewidth, xloc, xinc, yloc;
+ t_array *array;
+ int nelem;
+ char *elem;
+ if (plot_readownertemplate(x, data, template,
+ &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc) ||
+ array_getfields(elemtemplatesym, &elemtemplatecanvas,
+ &elemtemplate, &elemsize, &xonset, &yonset, &wonset))
+ return;
+ nelem = array->a_n;
+ elem = (char *)array->a_vec;
+ if (vis)
+ {
+ char outline[20];
+ int lastpixel = -1, ndrawn = 0;
+ float xsum, yval = 0, wval = 0, xpix;
+ int ixpix = 0, i;
+
+ /* draw the trace */
+ numbertocolor(fielddesc_getfloat(&x->x_outlinecolor, template, data, 1),
+ outline);
+ if (wonset >= 0)
+ {
+ /* found "w" field which controls linewidth. The trace is
+ a filled polygon with 2n points. */
+ sys_vgui(".x%x.c create polygon \\\n",
+ glist_getcanvas(glist));
+
+ for (i = 0, xsum = xloc; i < nelem; i++)
+ {
+ float usexloc;
+ if (xonset >= 0)
+ usexloc = xloc + *(float *)((elem + elemsize * i) + xonset);
+ else usexloc = xsum, xsum += xinc;
+ if (yonset >= 0)
+ yval = *(float *)((elem + elemsize * i) + yonset);
+ else yval = 0;
+ wval = *(float *)((elem + elemsize * i) + wonset);
+ xpix = glist_xtopixels(glist, basex + usexloc);
+ ixpix = xpix + 0.5;
+ if (xonset >= 0 || ixpix != lastpixel)
+ {
+ sys_vgui("%d %f \\\n", ixpix,
+ glist_ytopixels(glist,
+ basey + yloc + yval - wval));
+ ndrawn++;
+ }
+ lastpixel = ixpix;
+ if (ndrawn >= 1000) goto ouch;
+ }
+ lastpixel = -1;
+ for (i = nelem-1; i >= 0; i--)
+ {
+ float usexloc;
+ if (xonset >= 0)
+ usexloc = xloc + *(float *)((elem + elemsize * i) + xonset);
+ else xsum -= xinc, usexloc = xsum;
+ if (yonset >= 0)
+ yval = *(float *)((elem + elemsize * i) + yonset);
+ else yval = 0;
+ wval = *(float *)((elem + elemsize * i) + wonset);
+ xpix = glist_xtopixels(glist, basex + usexloc);
+ ixpix = xpix + 0.5;
+ if (xonset >= 0 || ixpix != lastpixel)
+ {
+ sys_vgui("%d %f \\\n", ixpix, glist_ytopixels(glist,
+ basey + yloc + yval + wval));
+ ndrawn++;
+ }
+ lastpixel = ixpix;
+ if (ndrawn >= 1000) goto ouch;
+ }
+ /* TK will complain if there aren't at least 3 points. There
+ should be at least two already. */
+ if (ndrawn < 4)
+ {
+ sys_vgui("%d %f \\\n", ixpix + 10, glist_ytopixels(glist,
+ basey + yloc + yval + wval));
+ sys_vgui("%d %f \\\n", ixpix + 10, glist_ytopixels(glist,
+ basey + yloc + yval - wval));
+ }
+ ouch:
+ sys_vgui(" -width 1 -fill %s -outline %s\\\n", outline, outline);
+ if (x->x_flags & BEZ) sys_vgui("-smooth 1\\\n");
+
+ sys_vgui("-tags plot%x\n", data);
+ }
+ else if (linewidth > 0)
+ {
+ /* no "w" field. If the linewidth is positive, draw a
+ segmented line with the requested width; otherwise don't
+ draw the trace at all. */
+ sys_vgui(".x%x.c create line \\\n", glist_getcanvas(glist));
+
+ for (xsum = xloc, i = 0; i < nelem; i++)
+ {
+ float usexloc;
+ if (xonset >= 0)
+ usexloc = xloc + *(float *)((elem + elemsize * i) + xonset);
+ else usexloc = xsum, xsum += xinc;
+ if (yonset >= 0)
+ yval = *(float *)((elem + elemsize * i) + yonset);
+ else yval = 0;
+ xpix = glist_xtopixels(glist, basex + usexloc);
+ ixpix = xpix + 0.5;
+ if (xonset >= 0 || ixpix != lastpixel)
+ {
+ sys_vgui("%d %f \\\n", ixpix,
+ glist_ytopixels(glist, basey + yloc + yval));
+ ndrawn++;
+ }
+ lastpixel = ixpix;
+ if (ndrawn >= 1000) break;
+ }
+ /* TK will complain if there aren't at least 2 points... */
+ if (ndrawn == 0) sys_vgui("0 0 0 0 \\\n");
+ else if (ndrawn == 1) sys_vgui("%d %f \\\n", ixpix + 10,
+ glist_ytopixels(glist, basey + yloc + yval));
+
+ sys_vgui("-width %f\\\n", linewidth);
+ sys_vgui("-fill %s\\\n", outline);
+ if (x->x_flags & BEZ) sys_vgui("-smooth 1\\\n");
+
+ sys_vgui("-tags plot%x\n", data);
+ }
+ /* We're done with the outline; now draw all the points.
+ This code is inefficient since the template has to be
+ searched for drawing instructions for every last point. */
+
+ for (xsum = xloc, i = 0; i < nelem; i++)
+ {
+ float usexloc, useyloc;
+ t_gobj *y;
+ if (xonset >= 0)
+ usexloc = basex + xloc +
+ *(float *)((elem + elemsize * i) + xonset);
+ else usexloc = basex + xsum, xsum += xinc;
+ if (yonset >= 0)
+ yval = *(float *)((elem + elemsize * i) + yonset);
+ else yval = 0;
+ useyloc = basey + yloc + yval;
+ for (y = elemtemplatecanvas->gl_list; y; y = y->g_next)
+ {
+ t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
+ if (!wb) continue;
+ (*wb->w_parentvisfn)(y, glist,
+ (t_word *)(elem + elemsize * i),
+ elemtemplate, usexloc, useyloc, vis);
+ }
+ }
+ }
+ else
+ {
+ /* un-draw the individual points */
+ int i;
+ for (i = 0; i < nelem; i++)
+ {
+ t_gobj *y;
+ for (y = elemtemplatecanvas->gl_list; y; y = y->g_next)
+ {
+ t_parentwidgetbehavior *wb = pd_getparentwidget(&y->g_pd);
+ if (!wb) continue;
+ (*wb->w_parentvisfn)(y, glist,
+ (t_word *)(elem + elemsize * i), elemtemplate,
+ 0, 0, 0);
+ }
+ }
+ /* and then the trace */
+ sys_vgui(".x%x.c delete plot%x\n",
+ glist_getcanvas(glist), data);
+ }
+}
+
+
+static int plot_click(t_gobj *z, t_glist *glist,
+ t_scalar *sc, t_template *template, float basex, float basey,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ t_plot *x = (t_plot *)z;
+ t_symbol *elemtemplatesym;
+ float linewidth, xloc, xinc, yloc;
+ t_array *array;
+ t_word *data = sc->sc_vec;
+
+ if (!plot_readownertemplate(x, data, template,
+ &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc))
+ {
+ return (array_doclick(array, glist, &sc->sc_gobj,
+ elemtemplatesym,
+ linewidth, basex + xloc, xinc, basey + yloc,
+ xpix, ypix, shift, alt, dbl, doit));
+ }
+ else return (0);
+}
+
+t_parentwidgetbehavior plot_widgetbehavior =
+{
+ plot_getrect,
+ plot_displace,
+ plot_select,
+ plot_activate,
+ plot_vis,
+ plot_click,
+};
+
+static void plot_setup(void)
+{
+ plot_class = class_new(gensym("plot"), (t_newmethod)plot_new, 0,
+ sizeof(t_plot), CLASS_NOINLET, A_GIMME, 0);
+ class_setdrawcommand(plot_class);
+ class_setparentwidget(plot_class, &plot_widgetbehavior);
+}
+
+/* ---------------- drawnumber: draw a number ---------------- */
+
+/*
+ drawnumbers draw numeric fields at controllable locations, with
+ controllable color and label .
+ invocation: (drawnumber|drawsymbol) variable x y color label
+*/
+
+t_class *drawnumber_class;
+
+#define DRAW_SYMBOL 1
+
+typedef struct _drawnumber
+{
+ t_object x_obj;
+ t_fielddesc x_value;
+ t_fielddesc x_xloc;
+ t_fielddesc x_yloc;
+ t_fielddesc x_color;
+ t_symbol *x_label;
+ int x_flags;
+} t_drawnumber;
+
+static void *drawnumber_new(t_symbol *classsym, t_int argc, t_atom *argv)
+{
+ t_drawnumber *x = (t_drawnumber *)pd_new(drawnumber_class);
+ char *classname = classsym->s_name;
+ int flags = 0;
+ if (classname[4] == 's')
+ flags |= DRAW_SYMBOL;
+ x->x_flags = flags;
+ if (argc) fielddesc_setfloatarg(&x->x_value, argc--, argv++);
+ else FIELDDESC_SETFLOAT(&x->x_value, 0);
+ if (argc) fielddesc_setfloatarg(&x->x_xloc, argc--, argv++);
+ else FIELDDESC_SETFLOAT(&x->x_xloc, 0);
+ if (argc) fielddesc_setfloatarg(&x->x_yloc, argc--, argv++);
+ else FIELDDESC_SETFLOAT(&x->x_yloc, 0);
+ if (argc) fielddesc_setfloatarg(&x->x_color, argc--, argv++);
+ else FIELDDESC_SETFLOAT(&x->x_color, 1);
+ if (argc)
+ x->x_label = atom_getsymbolarg(0, argc, argv);
+ else x->x_label = &s_;
+
+ return (x);
+}
+
+/* -------------------- widget behavior for drawnumber ------------ */
+
+#define DRAWNUMBER_BUFSIZE 80
+static void drawnumber_sprintf(t_drawnumber *x, char *buf, t_atom *ap)
+{
+ int nchars;
+ strncpy(buf, x->x_label->s_name, DRAWNUMBER_BUFSIZE);
+ buf[DRAWNUMBER_BUFSIZE - 1] = 0;
+ nchars = strlen(buf);
+ atom_string(ap, buf + nchars, DRAWNUMBER_BUFSIZE - nchars);
+}
+
+static void drawnumber_getrect(t_gobj *z, t_glist *glist,
+ t_word *data, t_template *template, float basex, float basey,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_drawnumber *x = (t_drawnumber *)z;
+ t_atom at;
+ int xloc = glist_xtopixels(glist,
+ basex + fielddesc_getfloat(&x->x_xloc, template, data, 0));
+ int yloc = glist_ytopixels(glist,
+ basey + fielddesc_getfloat(&x->x_yloc, template, data, 0));
+ int font = glist_getfont(glist);
+ int fontwidth = sys_fontwidth(font), fontheight = sys_fontheight(font);
+ char buf[DRAWNUMBER_BUFSIZE];
+ if (x->x_flags & DRAW_SYMBOL)
+ SETSYMBOL(&at, fielddesc_getsymbol(&x->x_value, template, data, 0));
+ else SETFLOAT(&at, fielddesc_getfloat(&x->x_value, template, data, 0));
+ drawnumber_sprintf(x, buf, &at);
+ *xp1 = xloc;
+ *yp1 = yloc;
+ *xp2 = xloc + fontwidth * strlen(buf);
+ *yp2 = yloc + fontheight;
+}
+
+static void drawnumber_displace(t_gobj *z, t_glist *glist,
+ t_word *data, t_template *template, float basex, float basey,
+ int dx, int dy)
+{
+ /* refuse */
+}
+
+static void drawnumber_select(t_gobj *z, t_glist *glist,
+ t_word *data, t_template *template, float basex, float basey,
+ int state)
+{
+ post("drawnumber_select %d", state);
+ /* fill in later */
+}
+
+static void drawnumber_activate(t_gobj *z, t_glist *glist,
+ t_word *data, t_template *template, float basex, float basey,
+ int state)
+{
+ post("drawnumber_activate %d", state);
+}
+
+static void drawnumber_vis(t_gobj *z, t_glist *glist,
+ t_word *data, t_template *template, float basex, float basey,
+ int vis)
+{
+ t_drawnumber *x = (t_drawnumber *)z;
+
+ if (vis)
+ {
+ t_atom at;
+ int xloc = glist_xtopixels(glist,
+ basex + fielddesc_getfloat(&x->x_xloc, template, data, 0));
+ int yloc = glist_ytopixels(glist,
+ basey + fielddesc_getfloat(&x->x_yloc, template, data, 0));
+ char colorstring[20], buf[DRAWNUMBER_BUFSIZE];
+ numbertocolor(fielddesc_getfloat(&x->x_color, template, data, 1),
+ colorstring);
+ if (x->x_flags & DRAW_SYMBOL)
+ SETSYMBOL(&at, fielddesc_getsymbol(&x->x_value, template, data, 0));
+ else SETFLOAT(&at, fielddesc_getfloat(&x->x_value, template, data, 0));
+ drawnumber_sprintf(x, buf, &at);
+ sys_vgui(".x%x.c create text %d %d -anchor nw -fill %s -text {%s}",
+ glist_getcanvas(glist), xloc, yloc, colorstring, buf);
+ sys_vgui(" -font -*-courier-bold--normal--%d-*",
+ sys_hostfontsize(glist_getfont(glist)));
+ sys_vgui(" -tags drawnumber%x\n", data);
+ }
+ else sys_vgui(".x%x.c delete drawnumber%x\n", glist_getcanvas(glist), data);
+}
+
+static float drawnumber_motion_ycumulative;
+static t_glist *drawnumber_motion_glist;
+static t_gobj *drawnumber_motion_gobj;
+static t_word *drawnumber_motion_wp;
+static t_template *drawnumber_motion_template;
+
+ /* LATER protect against the template changing or the scalar disappearing
+ probably by attaching a gpointer here ... */
+
+static void drawnumber_motion(void *z, t_floatarg dx, t_floatarg dy)
+{
+ t_drawnumber *x = (t_drawnumber *)z;
+ t_fielddesc *f = &x->x_value;
+ drawnumber_motion_ycumulative -= dy;
+ template_setfloat(drawnumber_motion_template,
+ f->fd_un.fd_varsym,
+ drawnumber_motion_wp,
+ drawnumber_motion_ycumulative,
+ 1);
+ glist_redrawitem(drawnumber_motion_glist, drawnumber_motion_gobj);
+}
+
+static int drawnumber_click(t_gobj *z, t_glist *glist,
+ t_scalar *sc, t_template *template, float basex, float basey,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ t_drawnumber *x = (t_drawnumber *)z;
+ int x1, y1, x2, y2;
+ t_word *data = sc->sc_vec;
+ drawnumber_getrect(z, glist,
+ sc->sc_vec, template, basex, basey,
+ &x1, &y1, &x2, &y2);
+ if (xpix >= x1 && xpix <= x2 && ypix >= y1 && ypix <= y2
+ && x->x_value.fd_var)
+ {
+ if (doit)
+ {
+ drawnumber_motion_glist = glist;
+ drawnumber_motion_gobj = &sc->sc_gobj;
+ drawnumber_motion_wp = data;
+ drawnumber_motion_template = template;
+ drawnumber_motion_ycumulative =
+ fielddesc_getfloat(&x->x_value, template, data, 0);
+ glist_grab(glist, z, drawnumber_motion, 0, xpix, ypix);
+ }
+ return (1);
+ }
+ else return (0);
+}
+
+t_parentwidgetbehavior drawnumber_widgetbehavior =
+{
+ drawnumber_getrect,
+ drawnumber_displace,
+ drawnumber_select,
+ drawnumber_activate,
+ drawnumber_vis,
+ drawnumber_click,
+};
+
+static void drawnumber_free(t_drawnumber *x)
+{
+}
+
+static void drawnumber_setup(void)
+{
+ drawnumber_class = class_new(gensym("drawnumber"),
+ (t_newmethod)drawnumber_new, (t_method)drawnumber_free,
+ sizeof(t_drawnumber), CLASS_NOINLET, A_GIMME, 0);
+ class_setdrawcommand(drawnumber_class);
+ class_addcreator((t_newmethod)drawnumber_new, gensym("drawsymbol"),
+ A_GIMME, 0);
+ class_setparentwidget(drawnumber_class, &drawnumber_widgetbehavior);
+}
+
+/* ---------------------- setup function ---------------------------- */
+
+void g_template_setup(void)
+{
+ template_setup();
+ gtemplate_setup();
+ template_float.t_pd = template_class;
+ curve_setup();
+ plot_setup();
+ drawnumber_setup();
+}
+
diff --git a/pd/src/g_text.c b/pd/src/g_text.c
new file mode 100644
index 00000000..226ddc7a
--- /dev/null
+++ b/pd/src/g_text.c
@@ -0,0 +1,1070 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* changes by Thomas Musil IEM KUG Graz Austria 2001 */
+/* the methods for calling the gui-objects from menu are implemented */
+/* all changes are labeled with iemlib */
+
+#include <stdlib.h>
+#include "m_imp.h"
+#include "t_tk.h"
+#include "g_canvas.h"
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+static t_class *text_class;
+static t_class *message_class;
+static t_class *gatom_class;
+void canvas_startmotion(t_canvas *x);
+t_widgetbehavior text_widgetbehavior;
+
+/* ----------------- the "text" object. ------------------ */
+
+
+ /* add a "text" object (comment) to a glist. While this one goes for any glist,
+ the other 3 below are for canvases only. (why?) This is called
+ without args if invoked from the GUI; otherwise at least x and y
+ are provided. */
+
+void glist_text(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
+{
+ t_text *x = (t_text *)pd_new(text_class);
+ t_atom at;
+ x->te_width = 0; /* don't know it yet. */
+ x->te_type = T_TEXT;
+ x->te_binbuf = binbuf_new();
+ if (argc > 1)
+ {
+ x->te_xpix = atom_getfloatarg(0, argc, argv);
+ x->te_ypix = atom_getfloatarg(1, argc, argv);
+ if (argc > 2) binbuf_restore(x->te_binbuf, argc-2, argv+2);
+ else
+ {
+ SETSYMBOL(&at, gensym("comment"));
+ binbuf_restore(x->te_binbuf, 1, &at);
+ }
+ glist_add(gl, &x->te_g);
+ }
+ else
+ {
+ int xpix, ypix;
+ pd_vmess((t_pd *)glist_getcanvas(gl), gensym("editmode"), "i", 1);
+ SETSYMBOL(&at, gensym("comment"));
+ glist_noselect(gl);
+ glist_getnextxy(gl, &xpix, &ypix);
+ x->te_xpix = glist_pixelstox(gl, xpix-3);
+ x->te_ypix = glist_pixelstoy(gl, ypix-3);
+ binbuf_restore(x->te_binbuf, 1, &at);
+ glist_add(gl, &x->te_g);
+ glist_noselect(gl);
+ glist_select(gl, &x->te_g);
+ canvas_startmotion(glist_getcanvas(gl));
+ }
+}
+
+/* ----------------- the "object" object. ------------------ */
+
+extern t_pd *newest;
+void canvas_getargs(int *argcp, t_atom **argvp);
+
+static void canvas_objtext(t_glist *gl, int xpix, int ypix, int selected,
+ t_binbuf *b)
+{
+ t_text *x;
+ int argc;
+ t_atom *argv;
+ newest = 0;
+ canvas_setcurrent((t_canvas *)gl);
+ canvas_getargs(&argc, &argv);
+ binbuf_eval(b, &pd_objectmaker, argc, argv);
+ if (binbuf_getnatom(b))
+ {
+ if (!newest)
+ {
+ binbuf_print(b);
+ post("... couldn't create");
+ x = 0;
+ }
+ else if (!(x = pd_checkobject(newest)))
+ {
+ binbuf_print(b);
+ post("... didn't return a patchable object");
+ }
+ }
+ else x = 0;
+ if (!x)
+ {
+
+ /* LATER make the color reflect this */
+ x = (t_text *)pd_new(text_class);
+ }
+ x->te_binbuf = b;
+ x->te_xpix = xpix;
+ x->te_ypix = ypix;
+ x->te_width = 0;
+ x->te_type = T_OBJECT;
+ glist_add(gl, &x->te_g);
+ if (selected)
+ {
+ /* this is called if we've been created from the menu. */
+ glist_select(gl, &x->te_g);
+ gobj_activate(&x->te_g, gl, 1);
+ }
+ if (pd_class(&x->ob_pd) == vinlet_class)
+ canvas_resortinlets(glist_getcanvas(gl));
+ if (pd_class(&x->ob_pd) == voutlet_class)
+ canvas_resortoutlets(glist_getcanvas(gl));
+ canvas_unsetcurrent((t_canvas *)gl);
+}
+
+ /* object creation routine. These are called without any arguments if
+ they're invoked from the
+ gui; when pasting or restoring from a file, we get at least x and y. */
+
+void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
+{
+ t_text *x;
+ if (argc >= 2)
+ {
+ t_binbuf *b = binbuf_new();
+ binbuf_restore(b, argc-2, argv+2);
+ canvas_objtext(gl, atom_getintarg(0, argc, argv),
+ atom_getintarg(1, argc, argv), 0, b);
+ }
+ else
+ {
+ t_binbuf *b = binbuf_new();
+ int xpix, ypix;
+ pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
+ glist_noselect(gl);
+ glist_getnextxy(gl, &xpix, &ypix);
+ canvas_objtext(gl, xpix, ypix, 1, b);
+ canvas_startmotion(glist_getcanvas(gl));
+ }
+}
+
+/* make an object box for an object that's already there. */
+
+/* iemlib */
+void canvas_iemguis(t_glist *gl, t_symbol *guiobjname)
+{
+ t_atom at;
+ t_binbuf *b = binbuf_new();
+ int xpix, ypix;
+
+ pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
+ glist_noselect(gl);
+ SETSYMBOL(&at, guiobjname);
+ binbuf_restore(b, 1, &at);
+ glist_getnextxy(gl, &xpix, &ypix);
+ canvas_objtext(gl, xpix, ypix, 1, b);
+ canvas_startmotion(glist_getcanvas(gl));
+}
+
+void canvas_bng(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
+{
+ canvas_iemguis(gl, gensym("bng"));
+}
+
+void canvas_toggle(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
+{
+ canvas_iemguis(gl, gensym("tgl"));
+}
+
+void canvas_vslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
+{
+ canvas_iemguis(gl, gensym("vsl"));
+}
+
+void canvas_hslider(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
+{
+ canvas_iemguis(gl, gensym("hsl"));
+}
+
+void canvas_hdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
+{
+ canvas_iemguis(gl, gensym("hdl"));
+}
+
+void canvas_vdial(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
+{
+ canvas_iemguis(gl, gensym("vdl"));
+}
+
+void canvas_vumeter(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
+{
+ canvas_iemguis(gl, gensym("vu"));
+}
+
+void canvas_mycnv(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
+{
+ canvas_iemguis(gl, gensym("cnv"));
+}
+
+void canvas_numbox(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
+{
+ canvas_iemguis(gl, gensym("nbx"));
+}
+
+/* iemlib */
+
+void canvas_objfor(t_glist *gl, t_text *x, int argc, t_atom *argv)
+{
+ x->te_width = 0; /* don't know it yet. */
+ x->te_type = T_OBJECT;
+ x->te_binbuf = binbuf_new();
+ x->te_xpix = atom_getfloatarg(0, argc, argv);
+ x->te_ypix = atom_getfloatarg(1, argc, argv);
+ if (argc > 2) binbuf_restore(x->te_binbuf, argc-2, argv+2);
+ glist_add(gl, &x->te_g);
+}
+
+/* ---------------------- the "message" text item ------------------------ */
+
+typedef struct _messresponder
+{
+ t_pd mr_pd;
+ t_outlet *mr_outlet;
+} t_messresponder;
+
+typedef struct _message
+{
+ t_text m_text;
+ t_messresponder m_messresponder;
+ t_glist *m_glist;
+ t_clock *m_clock;
+} t_message;
+
+static t_class *message_class, *messresponder_class;
+
+static void messresponder_bang(t_messresponder *x)
+{
+ outlet_bang(x->mr_outlet);
+}
+
+static void messresponder_float(t_messresponder *x, t_float f)
+{
+ outlet_float(x->mr_outlet, f);
+}
+
+static void messresponder_symbol(t_messresponder *x, t_symbol *s)
+{
+ outlet_symbol(x->mr_outlet, s);
+}
+
+static void messresponder_list(t_messresponder *x,
+ t_symbol *s, int argc, t_atom *argv)
+{
+ outlet_list(x->mr_outlet, s, argc, argv);
+}
+
+static void messresponder_anything(t_messresponder *x,
+ t_symbol *s, int argc, t_atom *argv)
+{
+ outlet_anything(x->mr_outlet, s, argc, argv);
+}
+
+static void message_bang(t_message *x)
+{
+ binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 0, 0);
+}
+
+static void message_float(t_message *x, t_float f)
+{
+ t_atom at;
+ SETFLOAT(&at, f);
+ binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 1, &at);
+}
+
+static void message_symbol(t_message *x, t_symbol *s)
+{
+ t_atom at;
+ SETSYMBOL(&at, s);
+ binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, 1, &at);
+}
+
+static void message_list(t_message *x, t_symbol *s, int argc, t_atom *argv)
+{
+ binbuf_eval(x->m_text.te_binbuf, &x->m_messresponder.mr_pd, argc, argv);
+}
+
+static void message_set(t_message *x, t_symbol *s, int argc, t_atom *argv)
+{
+ binbuf_clear(x->m_text.te_binbuf);
+ binbuf_add(x->m_text.te_binbuf, argc, argv);
+ glist_retext(x->m_glist, &x->m_text);
+}
+
+static void message_add2(t_message *x, t_symbol *s, int argc, t_atom *argv)
+{
+ binbuf_add(x->m_text.te_binbuf, argc, argv);
+ glist_retext(x->m_glist, &x->m_text);
+}
+
+static void message_add(t_message *x, t_symbol *s, int argc, t_atom *argv)
+{
+ binbuf_add(x->m_text.te_binbuf, argc, argv);
+ binbuf_addsemi(x->m_text.te_binbuf);
+ glist_retext(x->m_glist, &x->m_text);
+}
+
+static void message_click(t_message *x,
+ t_floatarg xpos, t_floatarg ypos, t_floatarg shift,
+ t_floatarg ctrl, t_floatarg alt)
+{
+ message_float(x, 0);
+ if (glist_isvisible(x->m_glist))
+ {
+ t_rtext *y = glist_findrtext(x->m_glist, &x->m_text);
+ sys_vgui(".x%x.c itemconfigure %sR -width 5\n",
+ glist_getcanvas(x->m_glist), rtext_gettag(y));
+ clock_delay(x->m_clock, 120);
+ }
+}
+
+static void message_tick(t_message *x)
+{
+ if (glist_isvisible(x->m_glist))
+ {
+ t_rtext *y = glist_findrtext(x->m_glist, &x->m_text);
+ sys_vgui(".x%x.c itemconfigure %sR -width 1\n",
+ glist_getcanvas(x->m_glist), rtext_gettag(y));
+ }
+}
+
+static void message_free(t_message *x)
+{
+ clock_free(x->m_clock);
+}
+
+void canvas_msg(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
+{
+ t_message *x = (t_message *)pd_new(message_class);
+ x->m_messresponder.mr_pd = messresponder_class;
+ x->m_messresponder.mr_outlet = outlet_new(&x->m_text, &s_float);
+ x->m_text.te_width = 0; /* don't know it yet. */
+ x->m_text.te_type = T_MESSAGE;
+ x->m_text.te_binbuf = binbuf_new();
+ x->m_glist = gl;
+ x->m_clock = clock_new(x, (t_method)message_tick);
+ if (argc > 1)
+ {
+ x->m_text.te_xpix = atom_getfloatarg(0, argc, argv);
+ x->m_text.te_ypix = atom_getfloatarg(1, argc, argv);
+ if (argc > 2) binbuf_restore(x->m_text.te_binbuf, argc-2, argv+2);
+ glist_add(gl, &x->m_text.te_g);
+ }
+ else
+ {
+ int xpix, ypix;
+ pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
+ glist_noselect(gl);
+ glist_getnextxy(gl, &xpix, &ypix);
+ x->m_text.te_xpix = xpix-3;
+ x->m_text.te_ypix = ypix-3;
+ glist_add(gl, &x->m_text.te_g);
+ glist_noselect(gl);
+ glist_select(gl, &x->m_text.te_g);
+ canvas_startmotion(glist_getcanvas(gl));
+ }
+}
+
+/* ---------------------- the "atom" text item ------------------------ */
+
+#define ATOMBUFSIZE 40
+
+typedef struct _gatom
+{
+ t_text a_text;
+ t_atom a_atom; /* this holds the value and the type */
+ t_glist *a_glist; /* owning glist */
+ t_float a_toggle; /* value to toggle to */
+ t_float a_draghi; /* high end of drag range */
+ t_float a_draglo; /* low end of drag range */
+ char a_buf[ATOMBUFSIZE];
+ char a_shift;
+} t_gatom;
+
+static void gatom_set(t_gatom *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if (!argc) return;
+ if (x->a_atom.a_type == A_FLOAT)
+ x->a_atom.a_w.w_float = atom_getfloat(argv);
+ else if (x->a_atom.a_type == A_SYMBOL)
+ x->a_atom.a_w.w_symbol = atom_getsymbol(argv);
+ binbuf_clear(x->a_text.te_binbuf);
+ binbuf_add(x->a_text.te_binbuf, 1, &x->a_atom);
+ glist_retext(x->a_glist, &x->a_text);
+ x->a_buf[0] = 0;
+}
+
+static void gatom_bang(t_gatom *x)
+{
+ if (x->a_atom.a_type == A_FLOAT)
+ outlet_float(x->a_text.te_outlet, x->a_atom.a_w.w_float);
+ else if (x->a_atom.a_type == A_SYMBOL)
+ outlet_symbol(x->a_text.te_outlet, x->a_atom.a_w.w_symbol);
+}
+
+static void gatom_float(t_gatom *x, t_float f)
+{
+ t_atom at;
+ SETFLOAT(&at, f);
+ gatom_set(x, 0, 1, &at);
+ gatom_bang(x);
+}
+
+static void gatom_clipfloat(t_gatom *x, t_float f)
+{
+ if (x->a_draglo != 0 || x->a_draghi != 0)
+ {
+ if (f < x->a_draglo)
+ f = x->a_draglo;
+ if (f > x->a_draghi)
+ f = x->a_draghi;
+ }
+ gatom_float(x, f);
+}
+
+static void gatom_symbol(t_gatom *x, t_symbol *s)
+{
+ t_atom at;
+ SETSYMBOL(&at, s);
+ gatom_set(x, 0, 1, &at);
+ gatom_bang(x);
+}
+
+static void gatom_motion(void *z, t_floatarg dx, t_floatarg dy)
+{
+ t_gatom *x = (t_gatom *)z;
+ if (dy == 0) return;
+ if (x->a_atom.a_type == A_FLOAT)
+ {
+ if (x->a_shift)
+ {
+ double nval = x->a_atom.a_w.w_float - 0.01 * dy;
+ double trunc = 0.01 * (floor(100. * nval + 0.5));
+ if (trunc < nval + 0.0001 && trunc > nval - 0.0001) nval = trunc;
+ gatom_clipfloat(x, nval);
+ }
+ else
+ {
+ double nval = x->a_atom.a_w.w_float - dy;
+ double trunc = 0.01 * (floor(100. * nval + 0.5));
+ if (trunc < nval + 0.0001 && trunc > nval - 0.0001) nval = trunc;
+ trunc = floor(nval + 0.5);
+ if (trunc < nval + 0.001 && trunc > nval - 0.001) nval = trunc;
+ gatom_clipfloat(x, nval);
+ }
+ }
+}
+
+static void gatom_key(void *z, t_floatarg f)
+{
+ t_gatom *x = (t_gatom *)z;
+ int c = f;
+ int l = strlen(x->a_buf);
+ t_atom at;
+ char sbuf[ATOMBUFSIZE + 4];
+ if (c == ' ') return;
+ else if (c == '\b')
+ {
+ if (l > 0)
+ {
+ x->a_buf[l-1] = 0;
+ goto redraw;
+ }
+ }
+ else if (c == '\n')
+ {
+ if (x->a_atom.a_type == A_FLOAT)
+ gatom_float(x, atof(x->a_buf));
+ else if (x->a_atom.a_type == A_SYMBOL)
+ gatom_symbol(x, gensym(x->a_buf));
+ else bug("gatom_key");
+ }
+ else if (l < (ATOMBUFSIZE-1))
+ {
+ x->a_buf[l] = c;
+ x->a_buf[l+1] = 0;
+ goto redraw;
+ }
+ return;
+redraw:
+ /* LATER figure out how to avoid creating all these symbols! */
+ sprintf(sbuf, "%s...", x->a_buf);
+ SETSYMBOL(&at, gensym(sbuf));
+ binbuf_clear(x->a_text.te_binbuf);
+ binbuf_add(x->a_text.te_binbuf, 1, &at);
+ glist_retext(x->a_glist, &x->a_text);
+}
+
+static void gatom_click(t_gatom *x,
+ t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl,
+ t_floatarg alt)
+{
+ if (x->a_text.te_width == 1)
+ {
+ if (x->a_atom.a_type == A_FLOAT)
+ gatom_float(x, (x->a_atom.a_w.w_float == 0));
+ }
+ else
+ {
+ if (alt)
+ {
+ if (x->a_atom.a_type != A_FLOAT) return;
+ if (x->a_atom.a_w.w_float != 0)
+ {
+ x->a_toggle = x->a_atom.a_w.w_float;
+ gatom_float(x, 0);
+ return;
+ }
+ else gatom_float(x, x->a_toggle);
+ }
+ x->a_shift = shift;
+ x->a_buf[0] = 0;
+ glist_grab(x->a_glist, &x->a_text.te_g, gatom_motion, gatom_key,
+ xpos, ypos);
+ }
+}
+
+static void gatom_param(t_gatom *x, t_floatarg width, t_floatarg draglo,
+ t_floatarg draghi)
+{
+ if (draglo >= draghi)
+ draglo = draghi = 0;
+ x->a_draglo = draglo;
+ x->a_draghi = draghi;
+ if (width < 0)
+ width = 4;
+ else if (width > 80)
+ width = 80;
+ x->a_text.te_width = width;
+ glist_retext(x->a_glist, &x->a_text);
+}
+
+void canvas_atom(t_glist *gl, t_atomtype type,
+ t_symbol *s, int argc, t_atom *argv)
+{
+ t_gatom *x = (t_gatom *)pd_new(gatom_class);
+ t_atom at;
+ x->a_text.te_width = 0; /* don't know it yet. */
+ x->a_text.te_type = T_ATOM;
+ x->a_text.te_binbuf = binbuf_new();
+ x->a_glist = gl;
+ x->a_atom.a_type = type;
+ x->a_toggle = 1;
+ x->a_draglo = 0;
+ x->a_draghi = 0;
+ if (type == A_FLOAT)
+ {
+ x->a_atom.a_w.w_float = 0;
+ x->a_text.te_width = 5;
+ outlet_new(&x->a_text, &s_float);
+ SETFLOAT(&at, 0);
+ }
+ else
+ {
+ x->a_atom.a_w.w_symbol = &s_symbol;
+ x->a_text.te_width = 10;
+ outlet_new(&x->a_text, &s_symbol);
+ SETSYMBOL(&at, &s_symbol);
+ }
+ binbuf_add(x->a_text.te_binbuf, 1, &at);
+ if (argc > 1)
+ {
+ x->a_text.te_xpix = atom_getfloatarg(0, argc, argv);
+ x->a_text.te_ypix = atom_getfloatarg(1, argc, argv);
+ x->a_text.te_width = atom_getintarg(2, argc, argv);
+ /* sanity check because some very old patches have trash in this
+ field... remove this in 2003 or so: */
+ if (x->a_text.te_width < 0 || x->a_text.te_width > 500)
+ x->a_text.te_width = 4;
+ x->a_draglo = atom_getfloatarg(3, argc, argv);
+ x->a_draghi = atom_getfloatarg(4, argc, argv);
+ glist_add(gl, &x->a_text.te_g);
+ }
+ else
+ {
+ int xpix, ypix;
+ pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
+ glist_noselect(gl);
+ glist_getnextxy(gl, &xpix, &ypix);
+ x->a_text.te_xpix = xpix;
+ x->a_text.te_ypix = ypix;
+ glist_add(gl, &x->a_text.te_g);
+ glist_noselect(gl);
+ glist_select(gl, &x->a_text.te_g);
+ canvas_startmotion(glist_getcanvas(gl));
+ }
+}
+
+void canvas_floatatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
+{
+ canvas_atom(gl, A_FLOAT, s, argc, argv);
+}
+
+void canvas_symbolatom(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
+{
+ canvas_atom(gl, A_SYMBOL, s, argc, argv);
+}
+
+static void gatom_free(t_gatom *x)
+{
+ gfxstub_deleteforkey(x);
+}
+
+static void gatom_properties(t_gobj *z, t_glist *owner)
+{
+ t_gatom *x = (t_gatom *)z;
+ char buf[200];
+ sprintf(buf, "pdtk_gatom_dialog %%s %d %g %g\n",
+ x->a_text.te_width, x->a_draglo, x->a_draghi);
+ gfxstub_new(&x->a_text.te_pd, x, buf);
+}
+
+
+/* -------------------- widget behavior for text objects ------------ */
+
+static void text_getrect(t_gobj *z, t_glist *glist,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_text *x = (t_text *)z;
+ int width, height, iscomment = (x->te_type == T_TEXT);
+ float x1, y1, x2, y2;
+
+ /* for number boxes, we know width and height a priori, and should
+ report them here so that graphs can get swelled to fit. */
+
+ if (x->te_type == T_ATOM && x->te_width > 0)
+ {
+ int font = glist_getfont(glist);
+ int fontwidth = sys_fontwidth(font), fontheight = sys_fontheight(font);
+ width = (x->te_width > 0 ? x->te_width : 6) * fontwidth + 2;
+ height = fontheight + 1; /* borrowed from TMARGIN, etc, in g_rtext.c */
+ }
+ /* if we're invisible we don't know our size so we just lie about
+ it. This is called on invisible boxes to establish order of inlets
+ and possibly other reasons.
+ To find out if the box is visible we can't just check the "vis"
+ flag because we might be within the vis() routine and not have set
+ that yet. So we check directly whether the "rtext" list has been
+ built. LATER reconsider when "vis" flag should be on and off? */
+
+ else if (glist->gl_editor && glist->gl_editor->e_rtext)
+ {
+ t_rtext *y = glist_findrtext(glist, x);
+ width = rtext_width(y);
+ height = rtext_height(y) - (iscomment << 1);
+ }
+ else width = height = 10;
+ x1 = text_xpix(x, glist);
+ y1 = text_ypix(x, glist);
+ x2 = x1 + width;
+ y2 = y1 + height;
+ y1 += iscomment;
+ *xp1 = x1;
+ *yp1 = y1;
+ *xp2 = x2;
+ *yp2 = y2;
+}
+
+static void text_displace(t_gobj *z, t_glist *glist,
+ int dx, int dy)
+{
+ t_text *x = (t_text *)z;
+ x->te_xpix += dx;
+ x->te_ypix += dy;
+ if (glist_isvisible(glist))
+ {
+ t_rtext *y = glist_findrtext(glist, x);
+ rtext_displace(y, dx, dy);
+ text_drawborder(x, glist, rtext_gettag(y),
+ rtext_width(y), rtext_height(y), 0);
+ canvas_fixlinesfor(glist_getcanvas(glist), x);
+ }
+}
+
+static void text_select(t_gobj *z, t_glist *glist, int state)
+{
+ t_text *x = (t_text *)z;
+ t_rtext *y = glist_findrtext(glist, x);
+ rtext_select(y, state);
+ sys_vgui(".x%x.c itemconfigure %sR -fill %s\n", glist,
+ rtext_gettag(y), (state? "blue" : "black"));
+}
+
+static void text_activate(t_gobj *z, t_glist *glist, int state)
+{
+ t_text *x = (t_text *)z;
+ t_rtext *y = glist_findrtext(glist, x);
+ if (z->g_pd != gatom_class) rtext_activate(y, state);
+}
+
+static void text_delete(t_gobj *z, t_glist *glist)
+{
+ t_text *x = (t_text *)z;
+ canvas_deletelinesfor(glist, x);
+}
+
+ /* return true if the text box should be drawn.
+ We don't show object boxes inside graphs. */
+int text_shouldvis(t_text *x, t_glist *glist)
+{
+ return (glist->gl_havewindow ||
+ (x->te_pd != canvas_class && x->te_pd->c_wb != &text_widgetbehavior) ||
+ (x->te_pd == canvas_class && (((t_glist *)x)->gl_isgraph)));
+}
+
+static void text_vis(t_gobj *z, t_glist *glist, int vis)
+{
+ t_text *x = (t_text *)z;
+ if (vis)
+ {
+ if (text_shouldvis(x, glist))
+ {
+ t_rtext *y = rtext_new(glist, x, glist->gl_editor->e_rtext, 1);
+ if (x->te_type == T_ATOM)
+ glist_retext(glist, x);
+ text_drawborder(x, glist, rtext_gettag(y),
+ rtext_width(y), rtext_height(y), 1);
+ }
+ else rtext_new(glist, x, glist->gl_editor->e_rtext, 0);
+ }
+ else
+ {
+ t_rtext *y = glist_findrtext(glist, x);
+ if (text_shouldvis(x, glist))
+ text_eraseborder(x, glist, rtext_gettag(y));
+ rtext_free(y);
+ }
+}
+
+static int text_click(t_gobj *z, struct _glist *glist,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ t_text *x = (t_text *)z;
+ if (x->te_type == T_OBJECT)
+ {
+ t_symbol *clicksym = gensym("click");
+ if (zgetfn(&x->te_pd, clicksym))
+ {
+ if (doit)
+ pd_vmess(&x->te_pd, clicksym, "fffff",
+ (double)xpix, (double)ypix,
+ (double)shift, 0, (double)alt);
+ return (1);
+ }
+ else return (0);
+ }
+ else if (x->te_type == T_ATOM)
+ {
+ if (doit)
+ gatom_click((t_gatom *)x, (t_floatarg)xpix, (t_floatarg)ypix,
+ (t_floatarg)shift, 0, (t_floatarg)alt);
+ return (1);
+ }
+ else if (x->te_type == T_MESSAGE)
+ {
+ if (doit)
+ message_click((t_message *)x, (t_floatarg)xpix, (t_floatarg)ypix,
+ (t_floatarg)shift, 0, (t_floatarg)alt);
+ return (1);
+ }
+ else return (0);
+}
+
+static void text_save(t_gobj *z, t_binbuf *b)
+{
+ t_text *x = (t_text *)z;
+ if (x->te_type == T_OBJECT)
+ {
+ /* if we have a "saveto" method, and if we don't happen to be
+ a canvas that's an abstraction, the saveto method does the work */
+ if (zgetfn(&x->te_pd, gensym("saveto")) &&
+ !((pd_class(&x->te_pd) == canvas_class) &&
+ (canvas_isabstraction((t_canvas *)x)
+ || canvas_istable((t_canvas *)x))))
+ {
+ mess1(&x->te_pd, gensym("saveto"), b);
+ binbuf_addv(b, "ssii", gensym("#X"), gensym("restore"),
+ (t_int)x->te_xpix, (t_int)x->te_ypix);
+ }
+ else /* otherwise just save the text */
+ {
+ binbuf_addv(b, "ssii", gensym("#X"), gensym("obj"),
+ (t_int)x->te_xpix, (t_int)x->te_ypix);
+ }
+ binbuf_addbinbuf(b, x->te_binbuf);
+ binbuf_addv(b, ";");
+ }
+ else if (x->te_type == T_MESSAGE)
+ {
+ binbuf_addv(b, "ssii", gensym("#X"), gensym("msg"),
+ (t_int)x->te_xpix, (t_int)x->te_ypix);
+ binbuf_addbinbuf(b, x->te_binbuf);
+ binbuf_addv(b, ";");
+ }
+ else if (x->te_type == T_ATOM)
+ {
+ t_atomtype t = ((t_gatom *)x)->a_atom.a_type;
+ t_symbol *sel = (t == A_SYMBOL ? gensym("symbolatom") :
+ (t == A_FLOAT ? gensym("floatatom") : gensym("intatom")));
+ binbuf_addv(b, "ssiiiff", gensym("#X"), sel,
+ (t_int)x->te_xpix, (t_int)x->te_ypix, (t_int)x->te_width,
+ (double)((t_gatom *)x)->a_draglo, (double)((t_gatom *)x)->a_draghi);
+ binbuf_addv(b, ";");
+ }
+ else
+ {
+ binbuf_addv(b, "ssii", gensym("#X"), gensym("text"),
+ (t_int)x->te_xpix, (t_int)x->te_ypix);
+ binbuf_addbinbuf(b, x->te_binbuf);
+ binbuf_addv(b, ";");
+ }
+}
+
+ /* this one is for everyone but "gatoms"; it's imposed in m_class.c */
+t_widgetbehavior text_widgetbehavior =
+{
+ text_getrect,
+ text_displace,
+ text_select,
+ text_activate,
+ text_delete,
+ text_vis,
+ text_click,
+ text_save,
+ 0,
+};
+
+static t_widgetbehavior gatom_widgetbehavior =
+{
+ text_getrect,
+ text_displace,
+ text_select,
+ text_activate,
+ text_delete,
+ text_vis,
+ text_click,
+ text_save,
+ gatom_properties,
+};
+
+/* -------------------- the "text" class ------------ */
+
+#ifdef MACOSX
+#define EXTRAPIX 2
+#else
+#define EXTRAPIX 1
+#endif
+
+ /* draw inlets and outlets for a text object or for a graph. */
+void glist_drawiofor(t_glist *glist, t_object *ob, int firsttime,
+ char *tag, int x1, int y1, int x2, int y2)
+{
+ int n = obj_noutlets(ob), nplus = (n == 1 ? 1 : n-1), i;
+ int width = x2 - x1;
+ for (i = 0; i < n; i++)
+ {
+ int onset = x1 + (width - IOWIDTH) * i / nplus;
+ if (firsttime)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %so%d\n",
+ glist_getcanvas(glist),
+ onset, y2 - 1,
+ onset + IOWIDTH, y2,
+ tag, i);
+ else
+ sys_vgui(".x%x.c coords %so%d %d %d %d %d\n",
+ glist_getcanvas(glist), tag, i,
+ onset, y2 - 1,
+ onset + IOWIDTH, y2);
+ }
+ n = obj_ninlets(ob);
+ nplus = (n == 1 ? 1 : n-1);
+ for (i = 0; i < n; i++)
+ {
+ int onset = x1 + (width - IOWIDTH) * i / nplus;
+ if (firsttime)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %si%d\n",
+ glist_getcanvas(glist),
+ onset, y1,
+ onset + IOWIDTH, y1 + EXTRAPIX,
+ tag, i);
+ else
+ sys_vgui(".x%x.c coords %si%d %d %d %d %d\n",
+ glist_getcanvas(glist), tag, i,
+ onset, y1,
+ onset + IOWIDTH, y1 + EXTRAPIX);
+ }
+}
+
+void text_drawborder(t_text *x, t_glist *glist,
+ char *tag, int width2, int height2, int firsttime)
+{
+ t_object *ob;
+ int x1, y1, x2, y2, width, height;
+ text_getrect(&x->te_g, glist, &x1, &y1, &x2, &y2);
+ width = x2 - x1;
+ height = y2 - y1;
+ if (x->te_type == T_OBJECT)
+ {
+ if (firsttime)
+ sys_vgui(".x%x.c create line\
+ %d %d %d %d %d %d %d %d %d %d -tags %sR\n",
+ glist_getcanvas(glist),
+ x1, y1, x2, y1, x2, y2, x1, y2, x1, y1, tag);
+ else
+ sys_vgui(".x%x.c coords %sR\
+ %d %d %d %d %d %d %d %d %d %d\n",
+ glist_getcanvas(glist), tag,
+ x1, y1, x2, y1, x2, y2, x1, y2, x1, y1);
+ }
+ else if (x->te_type == T_MESSAGE)
+ {
+ if (firsttime)
+ sys_vgui(".x%x.c create line\
+ %d %d %d %d %d %d %d %d %d %d %d %d %d %d -tags %sR\n",
+ glist_getcanvas(glist),
+ x1, y1, x2+4, y1, x2, y1+4, x2, y2-4, x2+4, y2,
+ x1, y2, x1, y1,
+ tag);
+ else
+ sys_vgui(".x%x.c coords %sR\
+ %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+ glist_getcanvas(glist), tag,
+ x1, y1, x2+4, y1, x2, y1+4, x2, y2-4, x2+4, y2,
+ x1, y2, x1, y1);
+ }
+ else if (x->te_type == T_ATOM)
+ {
+ if (firsttime)
+ sys_vgui(".x%x.c create line\
+ %d %d %d %d %d %d %d %d %d %d %d %d -tags %sR\n",
+ glist_getcanvas(glist),
+ x1, y1, x2-4, y1, x2, y1+4, x2, y2, x1, y2, x1, y1,
+ tag);
+ else
+ sys_vgui(".x%x.c coords %sR\
+ %d %d %d %d %d %d %d %d %d %d %d %d\n",
+ glist_getcanvas(glist), tag,
+ x1, y1, x2, y1, x2+4, y1+4, x2+4, y2, x1, y2, x1, y1);
+ }
+ /* draw inlets/outlets */
+
+ if (ob = pd_checkobject(&x->te_pd))
+ glist_drawiofor(glist, ob, firsttime, tag, x1, y1, x2, y2);
+}
+
+void glist_eraseiofor(t_glist *glist, t_object *ob, char *tag)
+{
+ int i, n;
+ n = obj_noutlets(ob);
+ for (i = 0; i < n; i++)
+ sys_vgui(".x%x.c delete %so%d\n",
+ glist_getcanvas(glist), tag, i);
+ n = obj_ninlets(ob);
+ for (i = 0; i < n; i++)
+ sys_vgui(".x%x.c delete %si%d\n",
+ glist_getcanvas(glist), tag, i);
+}
+
+void text_eraseborder(t_text *x, t_glist *glist, char *tag)
+{
+ if (x->te_type == T_TEXT) return;
+ sys_vgui(".x%x.c delete %sR\n",
+ glist_getcanvas(glist), tag);
+ glist_eraseiofor(glist, x, tag);
+}
+
+ /* change text; if T_OBJECT, remake it. LATER we'll have an undo buffer
+ which should be filled in here before making the change. */
+
+void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize)
+{
+ if (x->te_type == T_OBJECT)
+ {
+ t_binbuf *b = binbuf_new();
+ int natom1, natom2;
+ t_atom *vec1, *vec2;
+ binbuf_text(b, buf, bufsize);
+ natom1 = binbuf_getnatom(x->te_binbuf);
+ vec1 = binbuf_getvec(x->te_binbuf);
+ natom2 = binbuf_getnatom(b);
+ vec2 = binbuf_getvec(b);
+ /* special case: if pd args change just pass the message on. */
+ if (natom1 >= 1 && natom2 >= 1 && vec1[0].a_type == A_SYMBOL
+ && !strcmp(vec1[0].a_w.w_symbol->s_name, "pd") &&
+ vec2[0].a_type == A_SYMBOL
+ && !strcmp(vec2[0].a_w.w_symbol->s_name, "pd"))
+ {
+ typedmess(&x->te_pd, gensym("rename"), natom2-1, vec2+1);
+ binbuf_free(x->te_binbuf);
+ x->te_binbuf = b;
+ }
+ else /* normally, just destroy the old one and make a new one. */
+ {
+ int xwas = x->te_xpix, ywas = x->te_ypix;
+ glist_delete(glist, &x->te_g);
+ canvas_objtext(glist, xwas, ywas, 0, b);
+ /* if it's an abstraction loadbang it here */
+ if (newest && pd_class(newest) == canvas_class)
+ canvas_loadbang((t_canvas *)newest);
+ canvas_restoreconnections(glist_getcanvas(glist));
+ }
+ /* if we made a new "pd" or changed a window name,
+ update window list */
+ if (natom2 >= 1 && vec2[0].a_type == A_SYMBOL
+ && !strcmp(vec2[0].a_w.w_symbol->s_name, "pd"))
+ canvas_updatewindowlist();
+ }
+ else binbuf_text(x->te_binbuf, buf, bufsize);
+}
+
+void g_text_setup(void)
+{
+ text_class = class_new(gensym("text"), 0, 0, sizeof(t_text),
+ CLASS_NOINLET | CLASS_PATCHABLE, 0);
+
+ message_class = class_new(gensym("message"), 0, (t_method)message_free,
+ sizeof(t_message), CLASS_PATCHABLE, 0);
+ class_addbang(message_class, message_bang);
+ class_addfloat(message_class, message_float);
+ class_addsymbol(message_class, message_symbol);
+ class_addlist(message_class, message_list);
+ class_addanything(message_class, message_list);
+
+ class_addmethod(message_class, (t_method)message_click, gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(message_class, (t_method)message_set, gensym("set"),
+ A_GIMME, 0);
+ class_addmethod(message_class, (t_method)message_add, gensym("add"),
+ A_GIMME, 0);
+ class_addmethod(message_class, (t_method)message_add2, gensym("add2"),
+ A_GIMME, 0);
+
+ messresponder_class = class_new(gensym("messresponder"), 0, 0,
+ sizeof(t_text), CLASS_PD, 0);
+ class_addbang(messresponder_class, messresponder_bang);
+ class_addfloat(messresponder_class, (t_method) messresponder_float);
+ class_addsymbol(messresponder_class, messresponder_symbol);
+ class_addlist(messresponder_class, messresponder_list);
+ class_addanything(messresponder_class, messresponder_anything);
+
+ gatom_class = class_new(gensym("gatom"), 0, (t_method)gatom_free,
+ sizeof(t_gatom), CLASS_PATCHABLE, 0);
+ class_addbang(gatom_class, gatom_bang);
+ class_addfloat(gatom_class, gatom_float);
+ class_addsymbol(gatom_class, gatom_symbol);
+ class_addmethod(gatom_class, (t_method)gatom_set, gensym("set"),
+ A_GIMME, 0);
+ class_addmethod(gatom_class, (t_method)gatom_click, gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(gatom_class, (t_method)gatom_param, gensym("param"),
+ A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_setwidget(gatom_class, &gatom_widgetbehavior);
+}
+
+
diff --git a/pd/src/g_toggle.c b/pd/src/g_toggle.c
new file mode 100644
index 00000000..6eba64d2
--- /dev/null
+++ b/pd/src/g_toggle.c
@@ -0,0 +1,528 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
+/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "m_imp.h"
+#include "g_canvas.h"
+#include "t_tk.h"
+#include "g_all_guis.h"
+#include <math.h>
+
+#ifdef NT
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+/* --------------- tgl gui-toggle ------------------------- */
+
+t_widgetbehavior toggle_widgetbehavior;
+static t_class *toggle_class;
+
+/* widget helper functions */
+
+void toggle_draw_update(t_toggle *x, t_glist *glist)
+{
+ if(glist_isvisible(glist))
+ {
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c itemconfigure %xX1 -fill #%6.6x\n", canvas, x,
+ (x->x_on!=0.0)?x->x_gui.x_fcol:x->x_gui.x_bcol);
+ sys_vgui(".x%x.c itemconfigure %xX2 -fill #%6.6x\n", canvas, x,
+ (x->x_on!=0.0)?x->x_gui.x_fcol:x->x_gui.x_bcol);
+ }
+}
+
+void toggle_draw_new(t_toggle *x, t_glist *glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ int w=1, xx=text_xpix(&x->x_gui.x_obj, glist), yy=text_ypix(&x->x_gui.x_obj, glist);
+
+ if(x->x_gui.x_w >= 30)
+ w = 2;
+ if(x->x_gui.x_w >= 60)
+ w = 3;
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE\n",
+ canvas, xx, yy, xx + x->x_gui.x_w, yy + x->x_gui.x_h,
+ x->x_gui.x_bcol, x);
+ sys_vgui(".x%x.c create line %d %d %d %d -width %d -fill #%6.6x -tags %xX1\n",
+ canvas, xx+w+1, yy+w+1, xx + x->x_gui.x_w-w, yy + x->x_gui.x_h-w, w,
+ (x->x_on!=0.0)?x->x_gui.x_fcol:x->x_gui.x_bcol, x);
+ sys_vgui(".x%x.c create line %d %d %d %d -width %d -fill #%6.6x -tags %xX2\n",
+ canvas, xx+w+1, yy + x->x_gui.x_h-w-1, xx + x->x_gui.x_w-w, yy+w, w,
+ (x->x_on!=0.0)?x->x_gui.x_fcol:x->x_gui.x_bcol, x);
+ sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
+ -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
+ canvas, xx+x->x_gui.x_ldx,
+ yy+x->x_gui.x_ldy,
+ strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
+ x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+ canvas, xx, yy + x->x_gui.x_h-1, xx + IOWIDTH, yy + x->x_gui.x_h, x, 0);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
+ canvas, xx, yy, xx + IOWIDTH, yy+1, x, 0);
+}
+
+void toggle_draw_move(t_toggle *x, t_glist *glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ int w=1, xx=text_xpix(&x->x_gui.x_obj, glist), yy=text_ypix(&x->x_gui.x_obj, glist);
+
+ if(x->x_gui.x_w >= 30)
+ w = 2;
+
+ if(x->x_gui.x_w >= 60)
+ w = 3;
+ sys_vgui(".x%x.c coords %xBASE %d %d %d %d\n",
+ canvas, x, xx, yy, xx + x->x_gui.x_w, yy + x->x_gui.x_h);
+ sys_vgui(".x%x.c itemconfigure %xX1 -width %d\n", canvas, x, w);
+ sys_vgui(".x%x.c coords %xX1 %d %d %d %d\n",
+ canvas, x, xx+w+1, yy+w+1, xx + x->x_gui.x_w-w, yy + x->x_gui.x_h-w);
+ sys_vgui(".x%x.c itemconfigure %xX2 -width %d\n", canvas, x, w);
+ sys_vgui(".x%x.c coords %xX2 %d %d %d %d\n",
+ canvas, x, xx+w+1, yy + x->x_gui.x_h-w-1, xx + x->x_gui.x_w-w, yy+w);
+ sys_vgui(".x%x.c coords %xLABEL %d %d\n",
+ canvas, x, xx+x->x_gui.x_ldx, yy+x->x_gui.x_ldy);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
+ canvas, x, 0, xx, yy + x->x_gui.x_h-1, xx + IOWIDTH, yy + x->x_gui.x_h);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
+ canvas, x, 0, xx, yy, xx + IOWIDTH, yy+1);
+}
+
+void toggle_draw_erase(t_toggle* x, t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c delete %xBASE\n", canvas, x);
+ sys_vgui(".x%x.c delete %xX1\n", canvas, x);
+ sys_vgui(".x%x.c delete %xX2\n", canvas, x);
+ sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
+}
+
+void toggle_draw_config(t_toggle* x, t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
+ canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
+ x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
+ strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
+ sys_vgui(".x%x.c itemconfigure %xBASE -fill #%6.6x\n", canvas, x,
+ x->x_gui.x_bcol);
+ sys_vgui(".x%x.c itemconfigure %xX1 -fill #%6.6x\n", canvas, x,
+ x->x_on?x->x_gui.x_fcol:x->x_gui.x_bcol);
+ sys_vgui(".x%x.c itemconfigure %xX2 -fill #%6.6x\n", canvas, x,
+ x->x_on?x->x_gui.x_fcol:x->x_gui.x_bcol);
+}
+
+void toggle_draw_io(t_toggle* x, t_glist* glist, int old_snd_rcv_flags)
+{
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+ canvas, xpos,
+ ypos + x->x_gui.x_h-1, xpos + IOWIDTH,
+ ypos + x->x_gui.x_h, x, 0);
+ if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
+ if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
+ canvas, xpos, ypos,
+ xpos + IOWIDTH, ypos+1, x, 0);
+ if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
+}
+
+void toggle_draw_select(t_toggle* x, t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if(x->x_gui.x_fsf.x_selected)
+ {
+ pd_bind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+ sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+ }
+ else
+ {
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
+ sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol);
+ }
+}
+
+void toggle_draw(t_toggle *x, t_glist *glist, int mode)
+{
+ if(mode == IEM_GUI_DRAW_MODE_UPDATE)
+ toggle_draw_update(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_MOVE)
+ toggle_draw_move(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_NEW)
+ toggle_draw_new(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_SELECT)
+ toggle_draw_select(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_ERASE)
+ toggle_draw_erase(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
+ toggle_draw_config(x, glist);
+ else if(mode >= IEM_GUI_DRAW_MODE_IO)
+ toggle_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
+}
+
+/* ------------------------ tgl widgetbehaviour----------------------------- */
+
+static void toggle_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_toggle *x = (t_toggle *)z;
+
+ *xp1 = text_xpix(&x->x_gui.x_obj, glist);
+ *yp1 = text_ypix(&x->x_gui.x_obj, glist);
+ *xp2 = *xp1 + x->x_gui.x_w;
+ *yp2 = *yp1 + x->x_gui.x_h;
+}
+
+static void toggle_save(t_gobj *z, t_binbuf *b)
+{
+ t_toggle *x = (t_toggle *)z;
+ int bflcol[3], *ip1, *ip2;
+ t_symbol *srl[3];
+
+ iemgui_save(&x->x_gui, srl, bflcol);
+ ip1 = (int *)(&x->x_gui.x_isa);
+ ip2 = (int *)(&x->x_gui.x_fsf);
+ binbuf_addv(b, "ssiisiisssiiiiiiiff", gensym("#X"),gensym("obj"),
+ (t_int)x->x_gui.x_obj.te_xpix,
+ (t_int)x->x_gui.x_obj.te_ypix,
+ gensym("tgl"), x->x_gui.x_w,
+ (*ip1)&IEM_INIT_ARGS_ALL,
+ srl[0], srl[1], srl[2],
+ x->x_gui.x_ldx, x->x_gui.x_ldy,
+ (*ip2)&IEM_FSTYLE_FLAGS_ALL, x->x_gui.x_fontsize,
+ bflcol[0], bflcol[1], bflcol[2], x->x_on, x->x_nonzero);
+ binbuf_addv(b, ";");
+}
+
+static void toggle_properties(t_gobj *z, t_glist *owner)
+{
+ t_toggle *x = (t_toggle *)z;
+ char buf[800];
+ t_symbol *srl[3];
+
+ iemgui_properties(&x->x_gui, srl);
+ sprintf(buf, "pdtk_iemgui_dialog %%s TOGGLE \
+ ----------dimensions(pix):----------- %d %d size: 0 0 empty \
+ -----------non-zero-value:----------- %g value: 0.0 empty %g \
+ -1 lin log %d %d empty %d \
+ %s %s \
+ %s %d %d \
+ %d %d \
+ %d %d %d\n",
+ x->x_gui.x_w, IEM_GUI_MINSIZE,
+ x->x_nonzero, 1.0,/*non_zero-schedule*/
+ x->x_gui.x_isa.x_loadinit, -1, -1,/*no multi*/
+ srl[0]->s_name, srl[1]->s_name,
+ srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
+ x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
+ 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
+ gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
+}
+
+static void toggle_bang(t_toggle *x)
+{
+ x->x_on = (x->x_on==0.0)?x->x_nonzero:0.0;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_float(x->x_gui.x_snd->s_thing, x->x_on);
+}
+
+static void toggle_dialog(t_toggle *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_symbol *srl[3];
+ int a = (int)atom_getintarg(0, argc, argv);
+ float nonzero = (float)atom_getfloatarg(2, argc, argv);
+ int sr_flags;
+
+ if(nonzero == 0.0)
+ nonzero = 1.0;
+ x->x_nonzero = nonzero;
+ if(x->x_on != 0.0)
+ x->x_on = x->x_nonzero;
+ sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
+ x->x_gui.x_w = iemgui_clip_size(a);
+ x->x_gui.x_h = x->x_gui.x_w;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
+}
+
+static void toggle_click(t_toggle *x, t_floatarg xpos, t_floatarg ypos, t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{toggle_bang(x);}
+
+static int toggle_newclick(t_gobj *z, struct _glist *glist, int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ if(doit)
+ toggle_click((t_toggle *)z, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift, 0, (t_floatarg)alt);
+ return (1);
+}
+
+static void toggle_set(t_toggle *x, t_floatarg f)
+{
+ x->x_on = f;
+ if(f != 0.0)
+ x->x_nonzero = f;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+}
+
+static void toggle_float(t_toggle *x, t_floatarg f)
+{
+ toggle_set(x, f);
+ if(x->x_gui.x_fsf.x_put_in2out)
+ {
+ outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_float(x->x_gui.x_snd->s_thing, x->x_on);
+ }
+}
+
+static void toggle_fout(t_toggle *x, t_floatarg f)
+{
+ toggle_set(x, f);
+ outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_float(x->x_gui.x_snd->s_thing, x->x_on);
+}
+
+static void toggle_loadbang(t_toggle *x)
+{
+ if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
+ toggle_fout(x, (float)x->x_on);
+}
+
+static void toggle_size(t_toggle *x, t_symbol *s, int ac, t_atom *av)
+{
+ x->x_gui.x_w = iemgui_clip_size((int)atom_getintarg(0, ac, av));
+ x->x_gui.x_h = x->x_gui.x_w;
+ iemgui_size((void *)x, &x->x_gui);
+}
+
+static void toggle_delta(t_toggle *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
+
+static void toggle_pos(t_toggle *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
+
+static void toggle_color(t_toggle *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
+
+static void toggle_send(t_toggle *x, t_symbol *s)
+{iemgui_send(x, &x->x_gui, s);}
+
+static void toggle_receive(t_toggle *x, t_symbol *s)
+{iemgui_receive(x, &x->x_gui, s);}
+
+static void toggle_label(t_toggle *x, t_symbol *s)
+{iemgui_label((void *)x, &x->x_gui, s);}
+
+static void toggle_label_font(t_toggle *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
+
+static void toggle_label_pos(t_toggle *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
+
+static void toggle_init(t_toggle *x, t_floatarg f)
+{
+ x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
+}
+
+static void toggle_nonzero(t_toggle *x, t_floatarg f)
+{
+ if(f != 0.0)
+ x->x_nonzero = f;
+}
+
+static void toggle_list(t_toggle *x, t_symbol *s, int ac, t_atom *av)
+{
+ int l=iemgui_list((void *)x, &x->x_gui, s, ac, av);
+
+ if(l < 0)
+ {
+ if(IS_A_FLOAT(av,0))
+ toggle_float(x, atom_getfloatarg(0, ac, av));
+ }
+ else if(l > 0)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
+ }
+}
+
+static void *toggle_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_toggle *x = (t_toggle *)pd_new(toggle_class);
+ int bflcol[]={-262144, -1, -1};
+ t_symbol *srl[3];
+ int a=IEM_GUI_DEFAULTSIZE, f=0;
+ int ldx=0, ldy=-6;
+ int fs=8, iinit=0, ifstyle=0;
+ float on=0.0, nonzero=1.0;
+ t_iem_init_symargs *init=(t_iem_init_symargs *)(&iinit);
+ t_iem_fstyle_flags *fstyle=(t_iem_fstyle_flags *)(&ifstyle);
+ char str[144];
+
+ srl[0] = gensym("empty");
+ srl[1] = gensym("empty");
+ srl[2] = gensym("empty");
+
+ if(((argc == 13)||(argc == 14))&&IS_A_FLOAT(argv,0)
+ &&IS_A_FLOAT(argv,1)
+ &&(IS_A_SYMBOL(argv,2)||IS_A_FLOAT(argv,2))
+ &&(IS_A_SYMBOL(argv,3)||IS_A_FLOAT(argv,3))
+ &&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4))
+ &&IS_A_FLOAT(argv,5)&&IS_A_FLOAT(argv,6)
+ &&IS_A_FLOAT(argv,7)&&IS_A_FLOAT(argv,8)&&IS_A_FLOAT(argv,9)
+ &&IS_A_FLOAT(argv,10)&&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12))
+ {
+ a = (int)atom_getintarg(0, argc, argv);
+ iinit = (int)atom_getintarg(1, argc, argv);
+ if(IS_A_SYMBOL(argv,2))
+ srl[0] = atom_getsymbolarg(2, argc, argv);
+ else if(IS_A_FLOAT(argv,2))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(2, argc, argv));
+ srl[0] = gensym(str);
+ }
+ if(IS_A_SYMBOL(argv,3))
+ srl[1] = atom_getsymbolarg(3, argc, argv);
+ else if(IS_A_FLOAT(argv,3))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(3, argc, argv));
+ srl[1] = gensym(str);
+ }
+ if(IS_A_SYMBOL(argv,4))
+ srl[2] = atom_getsymbolarg(4, argc, argv);
+ else if(IS_A_FLOAT(argv,4))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(4, argc, argv));
+ srl[2] = gensym(str);
+ }
+ ldx = (int)atom_getintarg(5, argc, argv);
+ ldy = (int)atom_getintarg(6, argc, argv);
+ ifstyle = (int)atom_getintarg(7, argc, argv);
+ fs = (int)atom_getintarg(8, argc, argv);
+ bflcol[0] = (int)atom_getintarg(9, argc, argv);
+ bflcol[1] = (int)atom_getintarg(10, argc, argv);
+ bflcol[2] = (int)atom_getintarg(11, argc, argv);
+ on = (float)atom_getfloatarg(12, argc, argv);
+ }
+ if((argc == 14)&&IS_A_FLOAT(argv,13))
+ nonzero = (float)atom_getfloatarg(13, argc, argv);
+ x->x_gui.x_draw = (t_iemfunptr)toggle_draw;
+ iinit &= IEM_INIT_ARGS_ALL;
+ ifstyle &= IEM_FSTYLE_FLAGS_ALL;
+
+ fstyle->x_snd_able = 1;
+ fstyle->x_rcv_able = 1;
+ x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
+ x->x_gui.x_isa = *init;
+ if(!strcmp(srl[0]->s_name, "empty")) fstyle->x_snd_able = 0;
+ if(!strcmp(srl[1]->s_name, "empty")) fstyle->x_rcv_able = 0;
+ x->x_gui.x_unique_num = 0;
+ if(fstyle->x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
+ else if(fstyle->x_font_style == 2) strcpy(x->x_gui.x_font, "times");
+ else { fstyle->x_font_style = 0;
+ strcpy(x->x_gui.x_font, "courier"); }
+ x->x_gui.x_fsf = *fstyle;
+ x->x_nonzero = (nonzero!=0.0)?nonzero:1.0;
+ if(x->x_gui.x_isa.x_loadinit)
+ x->x_on = (on!=0.0)?nonzero:0.0;
+ else
+ x->x_on = 0.0;
+ iemgui_first_dollararg2sym(&x->x_gui, srl);
+ if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, srl[1]);
+ x->x_gui.x_snd = srl[0];
+ x->x_gui.x_rcv = srl[1];
+ x->x_gui.x_lab = srl[2];
+ x->x_gui.x_ldx = ldx;
+ x->x_gui.x_ldy = ldy;
+
+ if(fs < 4)
+ fs = 4;
+ x->x_gui.x_fontsize = fs;
+ x->x_gui.x_w = iemgui_clip_size(a);
+ x->x_gui.x_h = x->x_gui.x_w;
+ iemgui_all_colfromload(&x->x_gui, bflcol);
+ iemgui_verify_snd_ne_rcv(&x->x_gui);
+ outlet_new(&x->x_gui.x_obj, &s_float);
+ return (x);
+}
+
+static void toggle_ff(t_toggle *x)
+{
+ if(x->x_gui.x_fsf.x_selected)
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ if(x->x_gui.x_fsf.x_rcv_able)
+ pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
+ gfxstub_deleteforkey(x);
+}
+
+void g_toggle_setup(void)
+{
+ toggle_class = class_new(gensym("tgl"), (t_newmethod)toggle_new,
+ (t_method)toggle_ff, sizeof(t_toggle), 0, A_GIMME, 0);
+ class_addcreator((t_newmethod)toggle_new, gensym("toggle"), A_GIMME, 0);
+ class_addbang(toggle_class, toggle_bang);
+ class_addfloat(toggle_class, toggle_float);
+ class_addlist(toggle_class, toggle_list);
+ class_addmethod(toggle_class, (t_method)toggle_click, gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(toggle_class, (t_method)toggle_dialog, gensym("dialog"),
+ A_GIMME, 0);
+ class_addmethod(toggle_class, (t_method)toggle_loadbang, gensym("loadbang"), 0);
+ class_addmethod(toggle_class, (t_method)toggle_set, gensym("set"), A_FLOAT, 0);
+ class_addmethod(toggle_class, (t_method)toggle_size, gensym("size"), A_GIMME, 0);
+ class_addmethod(toggle_class, (t_method)toggle_delta, gensym("delta"), A_GIMME, 0);
+ class_addmethod(toggle_class, (t_method)toggle_pos, gensym("pos"), A_GIMME, 0);
+ class_addmethod(toggle_class, (t_method)toggle_color, gensym("color"), A_GIMME, 0);
+ class_addmethod(toggle_class, (t_method)toggle_send, gensym("send"), A_DEFSYM, 0);
+ class_addmethod(toggle_class, (t_method)toggle_receive, gensym("receive"), A_DEFSYM, 0);
+ class_addmethod(toggle_class, (t_method)toggle_label, gensym("label"), A_DEFSYM, 0);
+ class_addmethod(toggle_class, (t_method)toggle_label_pos, gensym("label_pos"), A_GIMME, 0);
+ class_addmethod(toggle_class, (t_method)toggle_label_font, gensym("label_font"), A_GIMME, 0);
+ class_addmethod(toggle_class, (t_method)toggle_init, gensym("init"), A_FLOAT, 0);
+ class_addmethod(toggle_class, (t_method)toggle_nonzero, gensym("nonzero"), A_FLOAT, 0);
+ if(!iemgui_key_sym)
+ iemgui_key_sym = gensym("#keyname");
+ toggle_widgetbehavior.w_getrectfn = toggle_getrect;
+ toggle_widgetbehavior.w_displacefn = iemgui_displace;
+ toggle_widgetbehavior.w_selectfn = iemgui_select;
+ toggle_widgetbehavior.w_activatefn = NULL;
+ toggle_widgetbehavior.w_deletefn = iemgui_delete;
+ toggle_widgetbehavior.w_visfn = iemgui_vis;
+ toggle_widgetbehavior.w_clickfn = toggle_newclick;
+ toggle_widgetbehavior.w_propertiesfn = toggle_properties;
+ toggle_widgetbehavior.w_savefn = toggle_save;
+ class_setwidget(toggle_class, &toggle_widgetbehavior);
+ class_sethelpsymbol(toggle_class, gensym("toggle"));
+}
diff --git a/pd/src/g_traversal.c b/pd/src/g_traversal.c
new file mode 100644
index 00000000..a9e8ce03
--- /dev/null
+++ b/pd/src/g_traversal.c
@@ -0,0 +1,1084 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* This file defines Text objects which traverse data contained in scalars
+and arrays:
+
+pointer - point to an object belonging to a template
+get - get numeric fields
+set - change numeric fields
+element - get an array element
+getsize - get the size of an array
+setsize - change the size of an array
+append - add an element to a list
+sublist - get a pointer into a list which is an element of another scalar
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h> /* for read/write to files */
+#include "m_pd.h"
+#include "g_canvas.h"
+
+/* ------------- gstubs and gpointers - safe pointing --------------- */
+
+/* create a gstub which is "owned" by a glist (gl) or an array ("a"). */
+
+t_gstub *gstub_new(t_glist *gl, t_array *a)
+{
+ t_gstub *gs = t_getbytes(sizeof(*gs));
+ if (gl)
+ {
+ gs->gs_which = GP_GLIST;
+ gs->gs_un.gs_glist = gl;
+ }
+ else
+ {
+ gs->gs_which = GP_ARRAY;
+ gs->gs_un.gs_array = a;
+ }
+ gs->gs_refcount = 0;
+ return (gs);
+}
+
+/* when a "gpointer" is set to point to this stub (so we can later chase
+down the owner) we increase a reference count. The following routine is called
+whenever a gpointer is unset from pointing here. If the owner is
+gone and the refcount goes to zero, we can free the gstub safely. */
+
+static void gstub_dis(t_gstub *gs)
+{
+ int refcount = --gs->gs_refcount;
+ if ((!refcount) && gs->gs_which == GP_NONE)
+ t_freebytes(gs, sizeof (*gs));
+ else if (refcount < 0) bug("gstub_dis");
+}
+
+/* this routing is called by the owner to inform the gstub that it is
+being deleted. If no gpointers are pointing here, we can free the gstub;
+otherwise we wait for the last gstub_dis() to free it. */
+
+void gstub_cutoff(t_gstub *gs)
+{
+ gs->gs_which = GP_NONE;
+ if (gs->gs_refcount < 0) bug("gstub_cutoff");
+ if (!gs->gs_refcount) t_freebytes(gs, sizeof (*gs));
+}
+
+/* call this to verify that a pointer is fresh, i.e., that it either
+points to real data or to the head of a list, and that in either case
+the object hasn't disappeared since this pointer was generated.
+Unless "headok" is set, the routine also fails for the head of a list. */
+
+int gpointer_check(const t_gpointer *gp, int headok)
+{
+ t_gstub *gs = gp->gp_stub;
+ if (!gs) return (0);
+ if (gs->gs_which == GP_ARRAY)
+ {
+ if (gs->gs_un.gs_array->a_valid != gp->gp_valid) return (0);
+ else return (1);
+ }
+ else if (gs->gs_which == GP_GLIST)
+ {
+ if (!headok && !gp->gp_un.gp_scalar) return (0);
+ else if (gs->gs_un.gs_glist->gl_valid != gp->gp_valid) return (0);
+ else return (1);
+ }
+ else return (0);
+}
+
+/* call this if you know the pointer is fresh but don't know if we're pointing
+to the head of a list or to real data. Any pointer is known to be fresh
+when it appears as the argument of a message, but if your "pointer" method
+or inlet stores it and you use it later, call gpointer_check above. */
+
+/* LATER reconsider the above... I no longer think it's true! */
+
+static int gpointer_ishead(const t_gpointer *gp)
+{
+ return ((gp->gp_stub->gs_which == GP_GLIST) && !gp->gp_un.gp_scalar);
+}
+
+/* get the template for the object pointer to. Assumes we've already checked
+freshness. Returns 0 if head of list. */
+
+static t_symbol *gpointer_gettemplatesym(const t_gpointer *gp)
+{
+ t_gstub *gs = gp->gp_stub;
+ if (gs->gs_which == GP_GLIST)
+ {
+ t_scalar *sc = gp->gp_un.gp_scalar;
+ if (sc)
+ return (sc->sc_template);
+ else return (0);
+ }
+ else
+ {
+ t_array *a = gs->gs_un.gs_array;
+ return (a->a_templatesym);
+ }
+}
+
+ /* copy a pointer to another, assuming the first one is fresh and
+ the second one hasn't yet been initialized. */
+void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto)
+{
+ *gpto = *gpfrom;
+ if (gpto->gp_stub)
+ gpto->gp_stub->gs_refcount++;
+ else bug("gpointer_copy");
+}
+
+void gpointer_unset(t_gpointer *gp)
+{
+ t_gstub *gs;
+ if (gs = gp->gp_stub)
+ {
+ gstub_dis(gs);
+ gp->gp_stub = 0;
+ }
+}
+
+void gpointer_setglist(t_gpointer *gp, t_glist *glist, t_scalar *x)
+{
+ t_gstub *gs;
+ if (gs = gp->gp_stub) gstub_dis(gs);
+ gp->gp_stub = gs = glist->gl_stub;
+ gp->gp_valid = glist->gl_valid;
+ gp->gp_un.gp_scalar = x;
+ gs->gs_refcount++;
+}
+
+static void gpointer_setarray(t_gpointer *gp, t_array *array, t_word *w)
+{
+ t_gstub *gs;
+ if (gs = gp->gp_stub) gstub_dis(gs);
+ gp->gp_stub = gs = array->a_stub;
+ gp->gp_valid = array->a_valid;
+ gp->gp_un.gp_w = w;
+ gs->gs_refcount++;
+}
+
+void gpointer_init(t_gpointer *gp)
+{
+ gp->gp_stub = 0;
+ gp->gp_valid = 0;
+ gp->gp_un.gp_scalar = 0;
+}
+
+/* ---------------------- pointers ----------------------------- */
+
+static t_class *ptrobj_class;
+
+typedef struct
+{
+ t_symbol *to_type;
+ t_outlet *to_outlet;
+} t_typedout;
+
+typedef struct _ptrobj
+{
+ t_object x_obj;
+ t_gpointer x_gp;
+ t_typedout *x_typedout;
+ int x_ntypedout;
+ t_outlet *x_otherout;
+ t_outlet *x_bangout;
+} t_ptrobj;
+
+static void *ptrobj_new(t_symbol *classname, int argc, t_atom *argv)
+{
+ t_ptrobj *x = (t_ptrobj *)pd_new(ptrobj_class);
+ t_typedout *to;
+ int n;
+ gpointer_init(&x->x_gp);
+ x->x_typedout = to = (t_typedout *)getbytes(argc * sizeof (*to));
+ x->x_ntypedout = n = argc;
+ for (; n--; to++)
+ {
+ to->to_outlet = outlet_new(&x->x_obj, &s_pointer);
+ to->to_type = canvas_makebindsym(atom_getsymbol(argv++));
+ }
+ x->x_otherout = outlet_new(&x->x_obj, &s_pointer);
+ x->x_bangout = outlet_new(&x->x_obj, &s_bang);
+ pointerinlet_new(&x->x_obj, &x->x_gp);
+ return (x);
+}
+
+static void ptrobj_traverse(t_ptrobj *x, t_symbol *s)
+{
+ t_glist *glist = (t_glist *)pd_findbyclass(s, canvas_class);
+ if (glist) gpointer_setglist(&x->x_gp, glist, 0);
+ else pd_error(x, "pointer: list '%s' not found", s->s_name);
+}
+
+static void ptrobj_vnext(t_ptrobj *x, float f)
+{
+ t_gobj *gobj;
+ t_gpointer *gp = &x->x_gp;
+ t_gstub *gs = gp->gp_stub;
+ t_glist *glist;
+ int wantselected = (f != 0);
+
+ if (!gs)
+ {
+ pd_error(x, "ptrobj_next: no current pointer");
+ return;
+ }
+ if (gs->gs_which != GP_GLIST)
+ {
+ pd_error(x, "ptrobj_next: lists only, not arrays");
+ return;
+ }
+ glist = gs->gs_un.gs_glist;
+ if (glist->gl_valid != gp->gp_valid)
+ {
+ pd_error(x, "ptrobj_next: stale pointer");
+ return;
+ }
+ if (wantselected && !glist_isvisible(glist))
+ {
+ pd_error(x,
+ "ptrobj_vnext: next-selected only works for a visible window");
+ return;
+ }
+ gobj = &gp->gp_un.gp_scalar->sc_gobj;
+
+ if (!gobj) gobj = glist->gl_list;
+ else gobj = gobj->g_next;
+ while (gobj && ((pd_class(&gobj->g_pd) != scalar_class) ||
+ (wantselected && !glist_isselected(glist, gobj))))
+ gobj = gobj->g_next;
+
+ if (gobj)
+ {
+ t_typedout *to;
+ int n;
+ t_scalar *sc = (t_scalar *)gobj;
+ t_symbol *templatesym = sc->sc_template;
+
+ gp->gp_un.gp_scalar = sc;
+ for (n = x->x_ntypedout, to = x->x_typedout; n--; to++)
+ {
+ if (to->to_type == templatesym)
+ {
+ outlet_pointer(to->to_outlet, &x->x_gp);
+ return;
+ }
+ }
+ outlet_pointer(x->x_otherout, &x->x_gp);
+ }
+ else
+ {
+ gpointer_unset(gp);
+ outlet_bang(x->x_bangout);
+ }
+}
+
+static void ptrobj_next(t_ptrobj *x)
+{
+ ptrobj_vnext(x, 0);
+}
+
+static void ptrobj_sendwindow(t_ptrobj *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_scalar *sc;
+ t_symbol *templatesym;
+ int n;
+ t_typedout *to;
+ t_glist *glist;
+ t_pd *canvas;
+ t_gstub *gs;
+ if (!gpointer_check(&x->x_gp, 1))
+ {
+ pd_error(x, "ptrobj_bang: empty pointer");
+ return;
+ }
+ gs = x->x_gp.gp_stub;
+ if (gs->gs_which == GP_GLIST)
+ glist = gs->gs_un.gs_glist;
+ else
+ {
+ t_array *owner_array = gs->gs_un.gs_array;
+ while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
+ owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
+ glist = owner_array->a_gp.gp_stub->gs_un.gs_glist;
+ }
+ canvas = (t_pd *)glist_getcanvas(glist);
+ if (argc && argv->a_type == A_SYMBOL)
+ pd_typedmess(canvas, argv->a_w.w_symbol, argc-1, argv+1);
+ else pd_error(x, "send-window: no message?");
+}
+
+static void ptrobj_bang(t_ptrobj *x)
+{
+ t_symbol *templatesym;
+ int n;
+ t_typedout *to;
+ if (!gpointer_check(&x->x_gp, 1))
+ {
+ pd_error(x, "ptrobj_bang: empty pointer");
+ return;
+ }
+ templatesym = gpointer_gettemplatesym(&x->x_gp);
+ for (n = x->x_ntypedout, to = x->x_typedout; n--; to++)
+ {
+ if (to->to_type == templatesym)
+ {
+ outlet_pointer(to->to_outlet, &x->x_gp);
+ return;
+ }
+ }
+ outlet_pointer(x->x_otherout, &x->x_gp);
+}
+
+
+static void ptrobj_pointer(t_ptrobj *x, t_gpointer *gp)
+{
+ gpointer_unset(&x->x_gp);
+ gpointer_copy(gp, &x->x_gp);
+ ptrobj_bang(x);
+}
+
+static void ptrobj_free(t_ptrobj *x)
+{
+ freebytes(x->x_typedout, x->x_ntypedout * sizeof (*x->x_typedout));
+ gpointer_unset(&x->x_gp);
+}
+
+static void ptrobj_setup(void)
+{
+ ptrobj_class = class_new(gensym("pointer"), (t_newmethod)ptrobj_new,
+ (t_method)ptrobj_free, sizeof(t_ptrobj), 0, A_GIMME, 0);
+ class_addmethod(ptrobj_class, (t_method)ptrobj_traverse, gensym("traverse"),
+ A_SYMBOL, 0);
+ class_addmethod(ptrobj_class, (t_method)ptrobj_next, gensym("next"), 0);
+ class_addmethod(ptrobj_class, (t_method)ptrobj_vnext, gensym("vnext"),
+ A_DEFFLOAT, 0);
+ class_addmethod(ptrobj_class, (t_method)ptrobj_sendwindow,
+ gensym("send-window"), A_GIMME, 0);
+ class_addpointer(ptrobj_class, ptrobj_pointer);
+ class_addbang(ptrobj_class, ptrobj_bang);
+}
+
+/* ---------------------- get ----------------------------- */
+
+static t_class *get_class;
+
+typedef struct _getvariable
+{
+ t_symbol *gv_sym;
+ t_outlet *gv_outlet;
+} t_getvariable;
+
+typedef struct _get
+{
+ t_object x_obj;
+ t_symbol *x_templatesym;
+ int x_nout;
+ t_getvariable *x_variables;
+} t_get;
+
+static void *get_new(t_symbol *why, int argc, t_atom *argv)
+{
+ t_get *x = (t_get *)pd_new(get_class);
+ int i;
+ t_getvariable *sp;
+ x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
+ if (argc) argc--, argv++;
+ x->x_variables
+ = (t_getvariable *)getbytes(argc * sizeof (*x->x_variables));
+ x->x_nout = argc;
+ for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
+ {
+ sp->gv_sym = atom_getsymbolarg(i, argc, argv);
+ sp->gv_outlet = outlet_new(&x->x_obj, 0);
+ /* LATER connect with the template and set the outlet's type
+ correctly. We can't yet guarantee that the template is there
+ before we hit this routine. */
+ }
+ return (x);
+}
+
+static void get_pointer(t_get *x, t_gpointer *gp)
+{
+ int nitems = x->x_nout, i;
+ t_symbol *templatesym = x->x_templatesym;
+ t_template *template = template_findbyname(templatesym);
+ t_gstub *gs = gp->gp_stub;
+ t_word *vec;
+ t_getvariable *vp;
+ if (!template)
+ {
+ pd_error(x, "get: couldn't find template %s", templatesym->s_name);
+ return;
+ }
+ if (gpointer_ishead(gp))
+ {
+ pd_error(x, "get: empty pointer");
+ return;
+ }
+ if (gs->gs_which == GP_ARRAY) vec = gp->gp_un.gp_w;
+ else vec = gp->gp_un.gp_scalar->sc_vec;
+ for (i = nitems - 1, vp = x->x_variables + i; i >= 0; i--, vp--)
+ {
+ float f = template_getfloat(template, vp->gv_sym, vec, 1);
+ outlet_float(vp->gv_outlet, f);
+ /* LATER deal with other types. */
+ }
+}
+
+static void get_free(t_get *x)
+{
+ freebytes(x->x_variables, x->x_nout * sizeof (*x->x_variables));
+}
+
+static void get_setup(void)
+{
+ get_class = class_new(gensym("get"), (t_newmethod)get_new,
+ (t_method)get_free, sizeof(t_get), 0, A_GIMME, 0);
+ class_addpointer(get_class, get_pointer);
+}
+
+/* ---------------------- set ----------------------------- */
+
+static t_class *set_class;
+
+typedef struct _setvariable
+{
+ t_symbol *gv_sym;
+ t_float gv_f; /* LATER take other types */
+} t_setvariable;
+
+typedef struct _set
+{
+ t_object x_obj;
+ t_gpointer x_gp;
+ t_symbol *x_templatesym;
+ int x_nin;
+ t_setvariable *x_variables;
+} t_set;
+
+static void *set_new(t_symbol *why, int argc, t_atom *argv)
+{
+ t_set *x = (t_set *)pd_new(set_class);
+ int i;
+ t_setvariable *sp;
+ x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
+ if (argc) argc--, argv++;
+ x->x_variables
+ = (t_setvariable *)getbytes(argc * sizeof (*x->x_variables));
+ x->x_nin = argc;
+ if (argc)
+ {
+ for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
+ {
+ sp->gv_sym = atom_getsymbolarg(i, argc, argv);
+ sp->gv_f = 0;
+ if (i) floatinlet_new(&x->x_obj, &sp->gv_f);
+ /* LATER figure out type as in "get" object. */
+ }
+ }
+ pointerinlet_new(&x->x_obj, &x->x_gp);
+ gpointer_init(&x->x_gp);
+ return (x);
+}
+
+static void set_float(t_set *x, t_float f)
+{
+ int nitems = x->x_nin, i;
+ t_symbol *templatesym = x->x_templatesym;
+ t_template *template = template_findbyname(templatesym);
+ t_setvariable *vp;
+ t_gpointer *gp = &x->x_gp;
+ t_gstub *gs = gp->gp_stub;
+ t_word *vec;
+ if (!template)
+ {
+ pd_error(x, "set: couldn't find template %s", templatesym->s_name);
+ return;
+ }
+ if (!gpointer_check(gp, 0))
+ {
+ pd_error(x, "set: empty pointer");
+ return;
+ }
+ if (gpointer_gettemplatesym(gp) != x->x_templatesym)
+ {
+ pd_error(x, "set %s: got wrong template (%s)",
+ x->x_templatesym->s_name, gpointer_gettemplatesym(gp)->s_name);
+ return;
+ }
+ if (!nitems) return;
+ x->x_variables[0].gv_f = f;
+ if (gs->gs_which == GP_ARRAY) vec = gp->gp_un.gp_w;
+ else vec = gp->gp_un.gp_scalar->sc_vec;
+ for (i = 0, vp = x->x_variables; i < nitems; i++, vp++)
+ {
+ template_setfloat(template, vp->gv_sym, vec, vp->gv_f, 1);
+ /* LATER deal with other types ala get_pointer. */
+ }
+ if (gs->gs_which == GP_GLIST)
+ glist_redrawitem(gs->gs_un.gs_glist, (t_gobj *)(gp->gp_un.gp_scalar));
+ else
+ {
+ t_array *owner_array = gs->gs_un.gs_array;
+ while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
+ owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
+ glist_redrawitem(owner_array->a_gp.gp_stub->gs_un.gs_glist,
+ (t_gobj *)(owner_array->a_gp.gp_un.gp_scalar));
+ }
+}
+
+static void set_free(t_set *x)
+{
+ freebytes(x->x_variables, x->x_nin * sizeof (*x->x_variables));
+ gpointer_unset(&x->x_gp);
+}
+
+static void set_setup(void)
+{
+ set_class = class_new(gensym("set"), (t_newmethod)set_new,
+ (t_method)set_free, sizeof(t_set), 0, A_GIMME, 0);
+ class_addfloat(set_class, set_float);
+}
+
+/* ---------------------- elem ----------------------------- */
+
+static t_class *elem_class;
+
+typedef struct _elem
+{
+ t_object x_obj;
+ t_symbol *x_templatesym;
+ t_symbol *x_fieldsym;
+ t_gpointer x_gp;
+ t_gpointer x_gparent;
+} t_elem;
+
+static void *elem_new(t_symbol *templatesym, t_symbol *fieldsym)
+{
+ t_elem *x = (t_elem *)pd_new(elem_class);
+ x->x_templatesym = canvas_makebindsym(templatesym);
+ x->x_fieldsym = fieldsym;
+ gpointer_init(&x->x_gp);
+ gpointer_init(&x->x_gparent);
+ pointerinlet_new(&x->x_obj, &x->x_gparent);
+ outlet_new(&x->x_obj, &s_pointer);
+ return (x);
+}
+
+static void elem_float(t_elem *x, t_float f)
+{
+ int indx = f, nitems, onset;
+ t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
+ *elemtemplatesym;
+ t_template *template = template_findbyname(templatesym);
+ t_template *elemtemplate;
+ t_gpointer *gparent = &x->x_gparent;
+ t_word *w;
+ t_array *array;
+ int elemsize, type;
+
+ if (!gpointer_check(gparent, 0))
+ {
+ pd_error(x, "element: empty pointer");
+ return;
+ }
+ if (gpointer_gettemplatesym(gparent) != x->x_templatesym)
+ {
+ pd_error(x, "element %s: got wrong template (%s)",
+ x->x_templatesym->s_name, gpointer_gettemplatesym(gparent)->s_name);
+ return;
+ }
+ if (gparent->gp_stub->gs_which == GP_ARRAY) w = gparent->gp_un.gp_w;
+ else w = gparent->gp_un.gp_scalar->sc_vec;
+ if (!template)
+ {
+ pd_error(x, "element: couldn't find template %s", templatesym->s_name);
+ return;
+ }
+ if (!template_find_field(template, fieldsym,
+ &onset, &type, &elemtemplatesym))
+ {
+ pd_error(x, "element: couldn't find array field %s", fieldsym->s_name);
+ return;
+ }
+ if (type != DT_ARRAY)
+ {
+ pd_error(x, "element: field %s not of type array", fieldsym->s_name);
+ return;
+ }
+ if (!(elemtemplate = template_findbyname(elemtemplatesym)))
+ {
+ pd_error(x, "element: couldn't find field template %s",
+ elemtemplatesym->s_name);
+ return;
+ }
+
+ elemsize = elemtemplate->t_n * sizeof(t_word);
+
+ array = *(t_array **)(((char *)w) + onset);
+
+ nitems = array->a_n;
+ if (indx < 0) indx = 0;
+ if (indx >= nitems) indx = nitems-1;
+
+ gpointer_setarray(&x->x_gp, array,
+ (t_word *)((char *)(array->a_vec) + indx * elemsize));
+ outlet_pointer(x->x_obj.ob_outlet, &x->x_gp);
+}
+
+static void elem_free(t_elem *x, t_gpointer *gp)
+{
+ gpointer_unset(&x->x_gp);
+ gpointer_unset(&x->x_gparent);
+}
+
+static void elem_setup(void)
+{
+ elem_class = class_new(gensym("element"), (t_newmethod)elem_new,
+ (t_method)elem_free, sizeof(t_elem), 0, A_DEFSYM, A_DEFSYM, 0);
+ class_addfloat(elem_class, elem_float);
+}
+
+/* ---------------------- getsize ----------------------------- */
+
+static t_class *getsize_class;
+
+typedef struct _getsize
+{
+ t_object x_obj;
+ t_symbol *x_templatesym;
+ t_symbol *x_fieldsym;
+} t_getsize;
+
+static void *getsize_new(t_symbol *templatesym, t_symbol *fieldsym)
+{
+ t_getsize *x = (t_getsize *)pd_new(getsize_class);
+ x->x_templatesym = canvas_makebindsym(templatesym);
+ x->x_fieldsym = fieldsym;
+ outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+static void getsize_pointer(t_getsize *x, t_gpointer *gp)
+{
+ int nitems, onset, type;
+ t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
+ *elemtemplatesym;
+ t_template *template = template_findbyname(templatesym);
+ t_word *w;
+ t_array *array;
+ int elemsize;
+ t_gstub *gs = gp->gp_stub;
+ if (!template)
+ {
+ pd_error(x, "getsize: couldn't find template %s", templatesym->s_name);
+ return;
+ }
+ if (!template_find_field(template, fieldsym,
+ &onset, &type, &elemtemplatesym))
+ {
+ pd_error(x, "getsize: couldn't find array field %s", fieldsym->s_name);
+ return;
+ }
+ if (type != DT_ARRAY)
+ {
+ pd_error(x, "getsize: field %s not of type array", fieldsym->s_name);
+ return;
+ }
+ if (gpointer_ishead(gp))
+ {
+ pd_error(x, "getsize: empty pointer");
+ return;
+ }
+ if (gpointer_gettemplatesym(gp) != x->x_templatesym)
+ {
+ pd_error(x, "getsize %s: got wrong template (%s)",
+ x->x_templatesym->s_name, gpointer_gettemplatesym(gp)->s_name);
+ return;
+ }
+ if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
+ else w = gp->gp_un.gp_scalar->sc_vec;
+
+ array = *(t_array **)(((char *)w) + onset);
+ outlet_float(x->x_obj.ob_outlet, (float)(array->a_n));
+}
+
+static void getsize_setup(void)
+{
+ getsize_class = class_new(gensym("getsize"), (t_newmethod)getsize_new, 0,
+ sizeof(t_getsize), 0, A_DEFSYM, A_DEFSYM, 0);
+ class_addpointer(getsize_class, getsize_pointer);
+}
+
+/* ---------------------- setsize ----------------------------- */
+
+static t_class *setsize_class;
+
+typedef struct _setsize
+{
+ t_object x_obj;
+ t_symbol *x_templatesym;
+ t_symbol *x_fieldsym;
+ t_gpointer x_gp;
+} t_setsize;
+
+static void *setsize_new(t_symbol *templatesym, t_symbol *fieldsym,
+ t_floatarg newsize)
+{
+ t_setsize *x = (t_setsize *)pd_new(setsize_class);
+ x->x_templatesym = canvas_makebindsym(templatesym);
+ x->x_fieldsym = fieldsym;
+ gpointer_init(&x->x_gp);
+
+ pointerinlet_new(&x->x_obj, &x->x_gp);
+ return (x);
+}
+
+static void setsize_float(t_setsize *x, t_float f)
+{
+ int nitems, onset, type;
+ t_symbol *templatesym = x->x_templatesym, *fieldsym = x->x_fieldsym,
+ *elemtemplatesym;
+ t_template *template = template_findbyname(templatesym);
+ t_template *elemtemplate;
+ t_word *w;
+ t_atom at;
+ t_array *array;
+ int elemsize;
+ int newsize = f;
+ t_gpointer *gp = &x->x_gp;
+ t_gstub *gs = gp->gp_stub;
+ if (!gpointer_check(&x->x_gp, 0))
+ {
+ pd_error(x, "setsize: empty pointer");
+ return;
+ }
+ if (gpointer_gettemplatesym(&x->x_gp) != x->x_templatesym)
+ {
+ pd_error(x, "setsize %s: got wrong template (%s)",
+ x->x_templatesym->s_name,
+ gpointer_gettemplatesym(&x->x_gp)->s_name);
+ return;
+ }
+ if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
+ else w = gp->gp_un.gp_scalar->sc_vec;
+
+ if (!template)
+ {
+ pd_error(x,"setsize: couldn't find template %s", templatesym->s_name);
+ return;
+ }
+ if (!template_find_field(template, fieldsym,
+ &onset, &type, &elemtemplatesym))
+ {
+ pd_error(x,"setsize: couldn't find array field %s", fieldsym->s_name);
+ return;
+ }
+ if (type != DT_ARRAY)
+ {
+ pd_error(x,"setsize: field %s not of type array", fieldsym->s_name);
+ return;
+ }
+
+ if (!(elemtemplate = template_findbyname(elemtemplatesym)))
+ {
+ pd_error(x,"element: couldn't find field template %s",
+ elemtemplatesym->s_name);
+ return;
+ }
+
+ elemsize = elemtemplate->t_n * sizeof(t_word);
+
+ array = *(t_array **)(((char *)w) + onset);
+
+ if (elemsize != array->a_elemsize) bug("setsize_gpointer");
+
+ nitems = array->a_n;
+ if (newsize < 1) newsize = 1;
+ if (newsize == nitems) return;
+
+ /* erase the array before resizing it. If we belong to a
+ scalar it's easy, but if we belong to an element of another
+ array we have to search back until we get to a scalar to erase.
+ When graphics updates become queueable this may fall apart... */
+
+
+ if (gs->gs_which == GP_GLIST)
+ {
+ if (glist_isvisible(gs->gs_un.gs_glist))
+ gobj_vis((t_gobj *)(gp->gp_un.gp_scalar), gs->gs_un.gs_glist, 0);
+ }
+ else
+ {
+ t_array *owner_array = gs->gs_un.gs_array;
+ while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
+ owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
+ if (glist_isvisible(owner_array->a_gp.gp_stub->gs_un.gs_glist))
+ gobj_vis((t_gobj *)(owner_array->a_gp.gp_un.gp_scalar),
+ owner_array->a_gp.gp_stub->gs_un.gs_glist, 0);
+ }
+ /* now do the resizing and, if growing, initialize new scalars */
+ array->a_vec = (char *)resizebytes(array->a_vec,
+ elemsize * nitems, elemsize * newsize);
+ array->a_n = newsize;
+ if (newsize > nitems)
+ {
+ char *newelem = ((char *)array->a_vec) + nitems * elemsize;
+ int i = 0, nnew = newsize - nitems;
+
+ while (nnew--)
+ {
+ word_init((t_word *)newelem, elemtemplate, gp);
+ newelem += elemsize;
+ /* post("new %x %x, ntypes %d", newelem, *(int *)newelem, ntypes); */
+ }
+ }
+
+ /* redraw again. */
+ if (gs->gs_which == GP_GLIST)
+ {
+ if (glist_isvisible(gs->gs_un.gs_glist))
+ gobj_vis((t_gobj *)(gp->gp_un.gp_scalar), gs->gs_un.gs_glist, 1);
+ }
+ else
+ {
+ t_array *owner_array = gs->gs_un.gs_array;
+ while (owner_array->a_gp.gp_stub->gs_which == GP_ARRAY)
+ owner_array = owner_array->a_gp.gp_stub->gs_un.gs_array;
+ if (glist_isvisible(owner_array->a_gp.gp_stub->gs_un.gs_glist))
+ gobj_vis((t_gobj *)(owner_array->a_gp.gp_un.gp_scalar),
+ owner_array->a_gp.gp_stub->gs_un.gs_glist, 1);
+ }
+}
+
+
+static void setsize_free(t_setsize *x)
+{
+ gpointer_unset(&x->x_gp);
+}
+
+static void setsize_setup(void)
+{
+ setsize_class = class_new(gensym("setsize"), (t_newmethod)setsize_new,
+ (t_method)setsize_free, sizeof(t_setsize), 0,
+ A_DEFSYM, A_DEFSYM, A_DEFFLOAT, 0);
+ class_addfloat(setsize_class, setsize_float);
+}
+
+/* ---------------------- append ----------------------------- */
+
+static t_class *append_class;
+
+typedef struct _appendvariable
+{
+ t_symbol *gv_sym;
+ t_float gv_f;
+} t_appendvariable;
+
+typedef struct _append
+{
+ t_object x_obj;
+ t_gpointer x_gp;
+ t_symbol *x_templatesym;
+ int x_nin;
+ t_appendvariable *x_variables;
+} t_append;
+
+static void *append_new(t_symbol *why, int argc, t_atom *argv)
+{
+ t_append *x = (t_append *)pd_new(append_class);
+ int i;
+ t_appendvariable *sp;
+ x->x_templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
+ if (argc) argc--, argv++;
+ x->x_variables
+ = (t_appendvariable *)getbytes(argc * sizeof (*x->x_variables));
+ x->x_nin = argc;
+ if (argc)
+ {
+ for (i = 0, sp = x->x_variables; i < argc; i++, sp++)
+ {
+ sp->gv_sym = atom_getsymbolarg(i, argc, argv);
+ sp->gv_f = 0;
+ if (i) floatinlet_new(&x->x_obj, &sp->gv_f);
+ }
+ }
+ pointerinlet_new(&x->x_obj, &x->x_gp);
+ outlet_new(&x->x_obj, &s_pointer);
+ gpointer_init(&x->x_gp);
+ return (x);
+}
+
+static void append_float(t_append *x, t_float f)
+{
+ int nitems = x->x_nin, i;
+ t_symbol *templatesym = x->x_templatesym;
+ t_template *template = template_findbyname(templatesym);
+ t_appendvariable *vp;
+ t_gpointer *gp = &x->x_gp;
+ t_gstub *gs = gp->gp_stub;
+ t_word *vec;
+ t_scalar *sc, *oldsc;
+ t_glist *glist;
+ if (!template)
+ {
+ pd_error(x, "append: couldn't find template %s", templatesym->s_name);
+ return;
+ }
+ if (!gs)
+ {
+ pd_error(x, "append: no current pointer");
+ return;
+ }
+ if (gs->gs_which != GP_GLIST)
+ {
+ pd_error(x, "append: lists only, not arrays");
+ return;
+ }
+ glist = gs->gs_un.gs_glist;
+ if (glist->gl_valid != gp->gp_valid)
+ {
+ pd_error(x, "append: stale pointer");
+ return;
+ }
+ if (!nitems) return;
+ x->x_variables[0].gv_f = f;
+
+ sc = scalar_new(glist, templatesym);
+ if (!sc)
+ {
+ pd_error(x, "%s: couldn't create scalar", templatesym->s_name);
+ return;
+ }
+ oldsc = gp->gp_un.gp_scalar;
+
+ if (oldsc)
+ {
+ sc->sc_gobj.g_next = oldsc->sc_gobj.g_next;
+ oldsc->sc_gobj.g_next = &sc->sc_gobj;
+ }
+ else
+ {
+ sc->sc_gobj.g_next = glist->gl_list;
+ glist->gl_list = &sc->sc_gobj;
+ }
+ if (glist_isvisible(glist_getcanvas(glist)))
+ gobj_vis(&sc->sc_gobj, glist, 1);
+
+ gp->gp_un.gp_scalar = sc;
+ vec = sc->sc_vec;
+ for (i = 0, vp = x->x_variables; i < nitems; i++, vp++)
+ {
+ template_setfloat(template, vp->gv_sym, vec, vp->gv_f, 1);
+ }
+
+ glist_redrawitem(glist, (t_gobj *)sc);
+
+ outlet_pointer(x->x_obj.ob_outlet, gp);
+}
+
+static void append_free(t_append *x)
+{
+ freebytes(x->x_variables, x->x_nin * sizeof (*x->x_variables));
+ gpointer_unset(&x->x_gp);
+}
+
+static void append_setup(void)
+{
+ append_class = class_new(gensym("append"), (t_newmethod)append_new,
+ (t_method)append_free, sizeof(t_append), 0, A_GIMME, 0);
+ class_addfloat(append_class, append_float);
+}
+
+/* ---------------------- sublist ----------------------------- */
+
+static t_class *sublist_class;
+
+typedef struct _sublist
+{
+ t_object x_obj;
+ t_symbol *x_templatesym;
+ t_symbol *x_fieldsym;
+ t_gpointer x_gp;
+} t_sublist;
+
+static void *sublist_new(t_symbol *templatesym, t_symbol *fieldsym)
+{
+ t_sublist *x = (t_sublist *)pd_new(sublist_class);
+ x->x_templatesym = canvas_makebindsym(templatesym);
+ x->x_fieldsym = fieldsym;
+ gpointer_init(&x->x_gp);
+ outlet_new(&x->x_obj, &s_pointer);
+ return (x);
+}
+
+static void sublist_pointer(t_sublist *x, t_gpointer *gp)
+{
+ t_symbol *templatesym = x->x_templatesym, *dummy;
+ t_template *template = template_findbyname(templatesym);
+ t_gstub *gs = gp->gp_stub;
+ t_word *vec;
+ t_getvariable *vp;
+ int onset, type;
+ t_word *w;
+
+ if (!template)
+ {
+ pd_error(x, "sublist: couldn't find template %s", templatesym->s_name);
+ return;
+ }
+ if (gpointer_ishead(gp))
+ {
+ pd_error(x, "sublist: empty pointer");
+ return;
+ }
+ if (!template_find_field(template, x->x_fieldsym,
+ &onset, &type, &dummy))
+ {
+ pd_error(x, "sublist: couldn't find field %s", x->x_fieldsym->s_name);
+ return;
+ }
+ if (type != DT_LIST)
+ {
+ pd_error(x, "sublist: field %s not of type list", x->x_fieldsym->s_name);
+ return;
+ }
+ if (gs->gs_which == GP_ARRAY) w = gp->gp_un.gp_w;
+ else w = gp->gp_un.gp_scalar->sc_vec;
+
+ gpointer_setglist(&x->x_gp, *(t_glist **)(((char *)w) + onset), 0);
+
+ outlet_pointer(x->x_obj.ob_outlet, &x->x_gp);
+}
+
+static void sublist_free(t_sublist *x, t_gpointer *gp)
+{
+ gpointer_unset(&x->x_gp);
+}
+
+static void sublist_setup(void)
+{
+ sublist_class = class_new(gensym("sublist"), (t_newmethod)sublist_new,
+ (t_method)sublist_free, sizeof(t_sublist), 0, A_DEFSYM, A_DEFSYM, 0);
+ class_addpointer(sublist_class, sublist_pointer);
+}
+
+/* ----------------- setup function ------------------- */
+
+void g_traversal_setup(void)
+{
+ ptrobj_setup();
+ get_setup();
+ set_setup();
+ elem_setup();
+ getsize_setup();
+ setsize_setup();
+ append_setup();
+ sublist_setup();
+}
diff --git a/pd/src/g_vdial.c b/pd/src/g_vdial.c
new file mode 100644
index 00000000..49c8d0d4
--- /dev/null
+++ b/pd/src/g_vdial.c
@@ -0,0 +1,672 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* vdial.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "m_imp.h"
+#include "g_canvas.h"
+#include "t_tk.h"
+#include "g_all_guis.h"
+#include <math.h>
+
+/*------------------ global varaibles -------------------------*/
+
+
+/*------------------ global functions -------------------------*/
+
+
+
+
+/* ------------- vdl gui-vertical dial ---------------------- */
+
+t_widgetbehavior vdial_widgetbehavior;
+static t_class *vdial_class;
+
+/* widget helper functions */
+
+void vdial_draw_update(t_vdial *x, t_glist *glist)
+{
+ if(glist_isvisible(glist))
+ {
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c itemconfigure %xBUT%d -fill #%6.6x -outline #%6.6x\n",
+ canvas, x, x->x_on_old,
+ x->x_gui.x_bcol, x->x_gui.x_bcol);
+ sys_vgui(".x%x.c itemconfigure %xBUT%d -fill #%6.6x -outline #%6.6x\n",
+ canvas, x, x->x_on,
+ x->x_gui.x_fcol, x->x_gui.x_fcol);
+ }
+}
+
+void vdial_draw_new(t_vdial *x, t_glist *glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ int n=x->x_number, i, dy=x->x_gui.x_h, s4=dy/4;
+ int yy11b=text_ypix(&x->x_gui.x_obj, glist);
+ int yy11=yy11b, yy12=yy11+dy;
+ int yy21=yy11+s4, yy22=yy12-s4;
+ int xx11=text_xpix(&x->x_gui.x_obj, glist), xx12=xx11+dy;
+ int xx21=xx11+s4, xx22=xx12-s4;
+
+ for(i=0; i<n; i++)
+ {
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE%d\n",
+ canvas, xx11, yy11, xx12, yy12,
+ x->x_gui.x_bcol, x, i);
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -outline #%6.6x -tags %xBUT%d\n",
+ canvas, xx21, yy21, xx22, yy22,
+ (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol,
+ (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol, x, i);
+ yy11 += dy;
+ yy12 += dy;
+ yy21 += dy;
+ yy22 += dy;
+ }
+ sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
+ -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
+ canvas, xx11+x->x_gui.x_ldx, yy11b+x->x_gui.x_ldy,
+ strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
+ x->x_gui.x_font, x->x_gui.x_fontsize,
+ x->x_gui.x_lcol, x);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+ canvas, xx11, yy11-1, xx11 + IOWIDTH, yy11, x, 0);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
+ canvas, xx11, yy11b, xx11 + IOWIDTH, yy11b+1, x, 0);
+}
+
+void vdial_draw_move(t_vdial *x, t_glist *glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ int n=x->x_number, i, dy=x->x_gui.x_h, s4=dy/4;
+ int yy11b=text_ypix(&x->x_gui.x_obj, glist);
+ int yy11=yy11b, yy12=yy11+dy;
+ int yy21=yy11+s4, yy22=yy12-s4;
+ int xx11=text_xpix(&x->x_gui.x_obj, glist), xx12=xx11+dy;
+ int xx21=xx11+s4, xx22=xx12-s4;
+
+ for(i=0; i<n; i++)
+ {
+ sys_vgui(".x%x.c coords %xBASE%d %d %d %d %d\n",
+ canvas, x, i, xx11, yy11, xx12, yy12);
+ sys_vgui(".x%x.c coords %xBUT%d %d %d %d %d\n",
+ canvas, x, i, xx21, yy21, xx22, yy22);
+ yy11 += dy;
+ yy12 += dy;
+ yy21 += dy;
+ yy22 += dy;
+ }
+ sys_vgui(".x%x.c coords %xLABEL %d %d\n",
+ canvas, x, xx11+x->x_gui.x_ldx, yy11b+x->x_gui.x_ldy);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
+ canvas, x, 0, xx11, yy11-1, xx11 + IOWIDTH, yy11);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
+ canvas, x, 0, xx11, yy11b, xx11 + IOWIDTH, yy11b+1);
+}
+
+void vdial_draw_erase(t_vdial* x, t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ int n=x->x_number, i;
+
+ for(i=0; i<n; i++)
+ {
+ sys_vgui(".x%x.c delete %xBASE%d\n", canvas, x, i);
+ sys_vgui(".x%x.c delete %xBUT%d\n", canvas, x, i);
+ }
+ sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
+}
+
+void vdial_draw_config(t_vdial* x, t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ int n=x->x_number, i;
+
+ sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
+ canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
+ x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
+ strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
+ for(i=0; i<n; i++)
+ {
+ sys_vgui(".x%x.c itemconfigure %xBASE%d -fill #%6.6x\n", canvas, x, i,
+ x->x_gui.x_bcol);
+ sys_vgui(".x%x.c itemconfigure %xBUT%d -fill #%6.6x -outline #%6.6x\n", canvas, x, i,
+ (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol,
+ (x->x_on==i)?x->x_gui.x_fcol:x->x_gui.x_bcol);
+ }
+}
+
+void vdial_draw_io(t_vdial* x, t_glist* glist, int old_snd_rcv_flags)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+
+ if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+ canvas, xpos,
+ ypos+(x->x_number*x->x_gui.x_h)-1,
+ xpos+ IOWIDTH,
+ ypos+(x->x_number*x->x_gui.x_h), x, 0);
+ if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
+ if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
+ canvas, xpos, ypos,
+ xpos+ IOWIDTH, ypos+1,
+ x, 0);
+ if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
+}
+
+void vdial_draw_select(t_vdial* x, t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+ int n=x->x_number, i;
+
+ if(x->x_gui.x_fsf.x_selected)
+ {
+ pd_bind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ for(i=0; i<n; i++)
+ {
+ sys_vgui(".x%x.c itemconfigure %xBASE%d -outline #%6.6x\n", canvas, x, i,
+ IEM_GUI_COLOR_SELECTED);
+ }
+ sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+ }
+ else
+ {
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ for(i=0; i<n; i++)
+ {
+ sys_vgui(".x%x.c itemconfigure %xBASE%d -outline #%6.6x\n", canvas, x, i,
+ IEM_GUI_COLOR_NORMAL);
+ }
+ sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x,
+ x->x_gui.x_lcol);
+ }
+}
+
+void vdial_draw(t_vdial *x, t_glist *glist, int mode)
+{
+ if(mode == IEM_GUI_DRAW_MODE_UPDATE)
+ vdial_draw_update(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_MOVE)
+ vdial_draw_move(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_NEW)
+ vdial_draw_new(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_SELECT)
+ vdial_draw_select(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_ERASE)
+ vdial_draw_erase(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
+ vdial_draw_config(x, glist);
+ else if(mode >= IEM_GUI_DRAW_MODE_IO)
+ vdial_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
+}
+
+/* ------------------------ vdl widgetbehaviour----------------------------- */
+
+static void vdial_getrect(t_gobj *z, t_glist *glist, int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_vdial *x = (t_vdial *)z;
+
+ *xp1 = text_xpix(&x->x_gui.x_obj, glist);
+ *yp1 = text_ypix(&x->x_gui.x_obj, glist);
+ *xp2 = *xp1 + x->x_gui.x_w;
+ *yp2 = *yp1 + x->x_gui.x_h*x->x_number;
+}
+
+static void vdial_save(t_gobj *z, t_binbuf *b)
+{
+ t_vdial *x = (t_vdial *)z;
+ int bflcol[3], *ip1, *ip2;
+ t_symbol *srl[3];
+
+ iemgui_save(&x->x_gui, srl, bflcol);
+ ip1 = (int *)(&x->x_gui.x_isa);
+ ip2 = (int *)(&x->x_gui.x_fsf);
+ binbuf_addv(b, "ssiisiiiisssiiiiiiii", gensym("#X"),gensym("obj"),
+ (t_int)x->x_gui.x_obj.te_xpix,
+ (t_int)x->x_gui.x_obj.te_ypix,
+ gensym("vdl"), x->x_gui.x_w,
+ x->x_change, (*ip1)&IEM_INIT_ARGS_ALL, x->x_number,
+ srl[0], srl[1], srl[2],
+ x->x_gui.x_ldx, x->x_gui.x_ldy,
+ (*ip2)&IEM_FSTYLE_FLAGS_ALL, x->x_gui.x_fontsize,
+ bflcol[0], bflcol[1], bflcol[2], x->x_on);
+ binbuf_addv(b, ";");
+}
+
+static void vdial_properties(t_gobj *z, t_glist *owner)
+{
+ t_vdial *x = (t_vdial *)z;
+ char buf[800];
+ t_symbol *srl[3];
+
+ iemgui_properties(&x->x_gui, srl);
+ sprintf(buf, "pdtk_iemgui_dialog %%s VDIAL \
+ ----------dimensions(pix):----------- %d %d size: 0 0 empty \
+ empty 0.0 empty 0.0 empty %d \
+ %d new-only new&old %d %d number: %d \
+ %s %s \
+ %s %d %d \
+ %d %d \
+ %d %d %d\n",
+ x->x_gui.x_w, IEM_GUI_MINSIZE,
+ 0,/*no_schedule*/
+ x->x_change, x->x_gui.x_isa.x_loadinit, -1, x->x_number,
+ srl[0]->s_name, srl[1]->s_name,
+ srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
+ x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
+ 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
+ gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
+}
+
+static void vdial_dialog(t_vdial *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_symbol *srl[3];
+ int a = (int)atom_getintarg(0, argc, argv);
+ int chg = (int)atom_getintarg(4, argc, argv);
+ int num = (int)atom_getintarg(6, argc, argv);
+ int sr_flags;
+
+ if(chg != 0) chg = 1;
+ x->x_change = chg;
+ sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
+ x->x_gui.x_w = iemgui_clip_size(a);
+ x->x_gui.x_h = x->x_gui.x_w;
+ if(x->x_number != num)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_ERASE);
+ x->x_number = num;
+ if(x->x_on >= x->x_number)
+ {
+ x->x_on = x->x_number - 1;
+ x->x_on_old = x->x_on;
+ }
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_NEW);
+ }
+ else
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
+ }
+}
+
+static void vdial_set(t_vdial *x, t_floatarg f)
+{
+ int i=(int)f;
+ int old;
+
+ if(i < 0)
+ i = 0;
+ if(i >= x->x_number)
+ i = x->x_number-1;
+ if(x->x_on != x->x_on_old)
+ {
+ old = x->x_on_old;
+ x->x_on_old = x->x_on;
+ x->x_on = i;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ x->x_on_old = old;
+ }
+ else
+ {
+ x->x_on = i;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ }
+}
+
+static void vdial_bang(t_vdial *x)
+{
+ if((x->x_change)&&(x->x_on != x->x_on_old))
+ {
+ SETFLOAT(x->x_at, (float)x->x_on_old);
+ SETFLOAT(x->x_at+1, 0.0);
+ outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
+ }
+ x->x_on_old = x->x_on;
+ SETFLOAT(x->x_at, (float)x->x_on);
+ SETFLOAT(x->x_at+1, 1.0);
+ outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
+}
+
+static void vdial_fout(t_vdial *x, t_floatarg f)
+{
+ int i=(int)f;
+
+ if(i < 0)
+ i = 0;
+ if(i >= x->x_number)
+ i = x->x_number-1;
+
+ if((x->x_change)&&(i != x->x_on_old))
+ {
+ SETFLOAT(x->x_at, (float)x->x_on_old);
+ SETFLOAT(x->x_at+1, 0.0);
+ outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
+ }
+ if(x->x_on != x->x_on_old)
+ x->x_on_old = x->x_on;
+ x->x_on = i;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ x->x_on_old = x->x_on;
+ SETFLOAT(x->x_at, (float)x->x_on);
+ SETFLOAT(x->x_at+1, 1.0);
+ outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
+}
+
+static void vdial_float(t_vdial *x, t_floatarg f)
+{
+ int i=(int)f;
+
+ if(i < 0)
+ i = 0;
+ if(i >= x->x_number)
+ i = x->x_number-1;
+
+ if((x->x_change)&&(i != x->x_on_old))
+ {
+ if(x->x_gui.x_fsf.x_put_in2out)
+ {
+ SETFLOAT(x->x_at, (float)x->x_on_old);
+ SETFLOAT(x->x_at+1, 0.0);
+ outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
+ }
+ }
+ if(x->x_on != x->x_on_old)
+ x->x_on_old = x->x_on;
+ x->x_on = i;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ x->x_on_old = x->x_on;
+ if(x->x_gui.x_fsf.x_put_in2out)
+ {
+ SETFLOAT(x->x_at, (float)x->x_on);
+ SETFLOAT(x->x_at+1, 1.0);
+ outlet_list(x->x_gui.x_obj.ob_outlet, &s_list, 2, x->x_at);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
+ }
+}
+
+static void vdial_click(t_vdial *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ int yy = (int)ypos - text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist);
+
+ vdial_fout(x, (float)(yy / x->x_gui.x_h));
+}
+
+static int vdial_newclick(t_gobj *z, struct _glist *glist, int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ if(doit)
+ vdial_click((t_vdial *)z, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift, 0, (t_floatarg)alt);
+ return (1);
+}
+
+static void vdial_loadbang(t_vdial *x)
+{
+ if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
+ vdial_bang(x);
+}
+
+static void vdial_number(t_vdial *x, t_floatarg num)
+{
+ int n=(int)num;
+
+ if(n < 1)
+ n = 1;
+ if(n > IEM_RADIO_MAX)
+ n = IEM_RADIO_MAX;
+ if(n != x->x_number)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_ERASE);
+ x->x_number = n;
+ if(x->x_on >= x->x_number)
+ x->x_on = x->x_number - 1;
+ x->x_on_old = x->x_on;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_NEW);
+ }
+}
+
+static void vdial_size(t_vdial *x, t_symbol *s, int ac, t_atom *av)
+{
+ x->x_gui.x_w = iemgui_clip_size((int)atom_getintarg(0, ac, av));
+ x->x_gui.x_h = x->x_gui.x_w;
+ iemgui_size((void *)x, &x->x_gui);
+}
+
+static void vdial_delta(t_vdial *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
+
+static void vdial_pos(t_vdial *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
+
+static void vdial_color(t_vdial *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
+
+static void vdial_send(t_vdial *x, t_symbol *s)
+{iemgui_send(x, &x->x_gui, s);}
+
+static void vdial_receive(t_vdial *x, t_symbol *s)
+{iemgui_receive(x, &x->x_gui, s);}
+
+static void vdial_label(t_vdial *x, t_symbol *s)
+{iemgui_label((void *)x, &x->x_gui, s);}
+
+static void vdial_label_pos(t_vdial *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
+
+static void vdial_label_font(t_vdial *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
+
+static void vdial_init(t_vdial *x, t_floatarg f)
+{
+ x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
+}
+
+static void vdial_double_change(t_vdial *x)
+{x->x_change = 1;}
+
+static void vdial_single_change(t_vdial *x)
+{x->x_change = 0;}
+
+static void vdial_list(t_vdial *x, t_symbol *s, int ac, t_atom *av)
+{
+ int l=iemgui_list((void *)x, &x->x_gui, s, ac, av);
+
+ if(l < 0)
+ {
+ if(IS_A_FLOAT(av,0))
+ vdial_float(x, atom_getfloatarg(0, ac, av));
+ }
+ else if(l > 0)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
+ }
+}
+
+static void *vdial_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_vdial *x = (t_vdial *)pd_new(vdial_class);
+ int bflcol[]={-262144, -1, -1};
+ t_symbol *srl[3];
+ int a=IEM_GUI_DEFAULTSIZE, on=0, f=0;
+ int ldx=0, ldy=-6, chg=1, num=8;
+ int fs=8, iinit=0, ifstyle=0;
+ int ftbreak=IEM_BNG_DEFAULTBREAKFLASHTIME, fthold=IEM_BNG_DEFAULTHOLDFLASHTIME;
+ t_iem_init_symargs *init=(t_iem_init_symargs *)(&iinit);
+ t_iem_fstyle_flags *fstyle=(t_iem_fstyle_flags *)(&ifstyle);
+ char str[144];
+
+ srl[0] = gensym("empty");
+ srl[1] = gensym("empty");
+ srl[2] = gensym("empty");
+
+ if((argc == 15)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)&&IS_A_FLOAT(argv,2)
+ &&IS_A_FLOAT(argv,3)
+ &&(IS_A_SYMBOL(argv,4)||IS_A_FLOAT(argv,4))
+ &&(IS_A_SYMBOL(argv,5)||IS_A_FLOAT(argv,5))
+ &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
+ &&IS_A_FLOAT(argv,7)&&IS_A_FLOAT(argv,8)
+ &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)&&IS_A_FLOAT(argv,11)
+ &&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)&&IS_A_FLOAT(argv,14))
+ {
+ a = (int)atom_getintarg(0, argc, argv);
+ chg = (int)atom_getintarg(1, argc, argv);
+ iinit = (int)atom_getintarg(2, argc, argv);
+ num = (int)atom_getintarg(3, argc, argv);
+ if(IS_A_SYMBOL(argv,4))
+ srl[0] = atom_getsymbolarg(4, argc, argv);
+ else if(IS_A_FLOAT(argv,4))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(4, argc, argv));
+ srl[0] = gensym(str);
+ }
+ if(IS_A_SYMBOL(argv,5))
+ srl[1] = atom_getsymbolarg(5, argc, argv);
+ else if(IS_A_FLOAT(argv,5))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(5, argc, argv));
+ srl[1] = gensym(str);
+ }
+ if(IS_A_SYMBOL(argv,6))
+ srl[2] = atom_getsymbolarg(6, argc, argv);
+ else if(IS_A_FLOAT(argv,6))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(6, argc, argv));
+ srl[2] = gensym(str);
+ }
+ ldx = (int)atom_getintarg(7, argc, argv);
+ ldy = (int)atom_getintarg(8, argc, argv);
+ ifstyle = (int)atom_getintarg(9, argc, argv);
+ fs = (int)atom_getintarg(10, argc, argv);
+ bflcol[0] = (int)atom_getintarg(11, argc, argv);
+ bflcol[1] = (int)atom_getintarg(12, argc, argv);
+ bflcol[2] = (int)atom_getintarg(13, argc, argv);
+ on = (int)atom_getintarg(14, argc, argv);
+ }
+ x->x_gui.x_draw = (t_iemfunptr)vdial_draw;
+ iinit &= IEM_INIT_ARGS_ALL;
+ ifstyle &= IEM_FSTYLE_FLAGS_ALL;
+ fstyle->x_snd_able = 1;
+ fstyle->x_rcv_able = 1;
+ x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
+ x->x_gui.x_isa = *init;
+ if(!strcmp(srl[0]->s_name, "empty")) fstyle->x_snd_able = 0;
+ if(!strcmp(srl[1]->s_name, "empty")) fstyle->x_rcv_able = 0;
+ if(fstyle->x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
+ else if(fstyle->x_font_style == 2) strcpy(x->x_gui.x_font, "times");
+ else { fstyle->x_font_style = 0;
+ strcpy(x->x_gui.x_font, "courier"); }
+ x->x_gui.x_fsf = *fstyle;
+ x->x_gui.x_unique_num = 0;
+ if(num < 1)
+ num = 1;
+ if(num > IEM_RADIO_MAX)
+ num = IEM_RADIO_MAX;
+ x->x_number = num;
+ if(on < 0)
+ on = 0;
+ if(on >= x->x_number)
+ on = x->x_number - 1;
+ if(x->x_gui.x_isa.x_loadinit)
+ x->x_on = on;
+ else
+ x->x_on = 0;
+ x->x_on_old = x->x_on;
+ x->x_change = (chg==0)?0:1;
+ iemgui_first_dollararg2sym(&x->x_gui, srl);
+ if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, srl[1]);
+ x->x_gui.x_snd = srl[0];
+ x->x_gui.x_rcv = srl[1];
+ x->x_gui.x_lab = srl[2];
+ x->x_gui.x_ldx = ldx;
+ x->x_gui.x_ldy = ldy;
+ if(fs < 4)
+ fs = 4;
+ x->x_gui.x_fontsize = fs;
+ x->x_gui.x_w = iemgui_clip_size(a);
+ x->x_gui.x_h = x->x_gui.x_w;
+ iemgui_verify_snd_ne_rcv(&x->x_gui);
+ iemgui_all_colfromload(&x->x_gui, bflcol);
+ outlet_new(&x->x_gui.x_obj, &s_list);
+ return (x);
+}
+
+static void vdial_ff(t_vdial *x)
+{
+ if(x->x_gui.x_fsf.x_selected)
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ if(x->x_gui.x_fsf.x_rcv_able)
+ pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
+ gfxstub_deleteforkey(x);
+}
+
+void g_vdial_setup(void)
+{
+ vdial_class = class_new(gensym("vdl"), (t_newmethod)vdial_new,
+ (t_method)vdial_ff, sizeof(t_vdial), 0, A_GIMME, 0);
+ class_addbang(vdial_class, vdial_bang);
+ class_addfloat(vdial_class, vdial_float);
+ class_addlist(vdial_class, vdial_list);
+ class_addmethod(vdial_class, (t_method)vdial_click, gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(vdial_class, (t_method)vdial_dialog, gensym("dialog"),
+ A_GIMME, 0);
+ class_addmethod(vdial_class, (t_method)vdial_loadbang, gensym("loadbang"), 0);
+ class_addmethod(vdial_class, (t_method)vdial_set, gensym("set"), A_FLOAT, 0);
+ class_addmethod(vdial_class, (t_method)vdial_size, gensym("size"), A_GIMME, 0);
+ class_addmethod(vdial_class, (t_method)vdial_delta, gensym("delta"), A_GIMME, 0);
+ class_addmethod(vdial_class, (t_method)vdial_pos, gensym("pos"), A_GIMME, 0);
+ class_addmethod(vdial_class, (t_method)vdial_color, gensym("color"), A_GIMME, 0);
+ class_addmethod(vdial_class, (t_method)vdial_send, gensym("send"), A_DEFSYM, 0);
+ class_addmethod(vdial_class, (t_method)vdial_receive, gensym("receive"), A_DEFSYM, 0);
+ class_addmethod(vdial_class, (t_method)vdial_label, gensym("label"), A_DEFSYM, 0);
+ class_addmethod(vdial_class, (t_method)vdial_label_pos, gensym("label_pos"), A_GIMME, 0);
+ class_addmethod(vdial_class, (t_method)vdial_label_font, gensym("label_font"), A_GIMME, 0);
+ class_addmethod(vdial_class, (t_method)vdial_init, gensym("init"), A_FLOAT, 0);
+ class_addmethod(vdial_class, (t_method)vdial_number, gensym("number"), A_FLOAT, 0);
+ class_addmethod(vdial_class, (t_method)vdial_single_change, gensym("single_change"), 0);
+ class_addmethod(vdial_class, (t_method)vdial_double_change, gensym("double_change"), 0);
+ if(!iemgui_key_sym)
+ iemgui_key_sym = gensym("#keyname");
+ vdial_widgetbehavior.w_getrectfn = vdial_getrect;
+ vdial_widgetbehavior.w_displacefn = iemgui_displace;
+ vdial_widgetbehavior.w_selectfn = iemgui_select;
+ vdial_widgetbehavior.w_activatefn = NULL;
+ vdial_widgetbehavior.w_deletefn = iemgui_delete;
+ vdial_widgetbehavior.w_visfn = iemgui_vis;
+ vdial_widgetbehavior.w_clickfn = vdial_newclick;
+ vdial_widgetbehavior.w_propertiesfn = vdial_properties;
+ vdial_widgetbehavior.w_savefn = vdial_save;
+ class_setwidget(vdial_class, &vdial_widgetbehavior);
+ class_sethelpsymbol(vdial_class, gensym("vdial"));
+}
diff --git a/pd/src/g_vslider.c b/pd/src/g_vslider.c
new file mode 100644
index 00000000..12cc4213
--- /dev/null
+++ b/pd/src/g_vslider.c
@@ -0,0 +1,688 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
+/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "m_imp.h"
+#include "g_canvas.h"
+#include "t_tk.h"
+#include "g_all_guis.h"
+#include <math.h>
+
+#ifdef NT
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+
+/* ------------ vsl gui-vertical slider ----------------------- */
+
+t_widgetbehavior vslider_widgetbehavior;
+static t_class *vslider_class;
+
+/* widget helper functions */
+
+static void vslider_draw_update(t_vslider *x, t_glist *glist)
+{
+ if (glist_isvisible(glist))
+ {
+ int r = text_ypix(&x->x_gui.x_obj, glist) + x->x_gui.x_h - (x->x_val + 50)/100;
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+
+ sys_vgui(".x%x.c coords %xKNOB %d %d %d %d\n",
+ glist_getcanvas(glist), x, xpos+1, r,
+ xpos + x->x_gui.x_w, r);
+ }
+}
+
+static void vslider_draw_new(t_vslider *x, t_glist *glist)
+{
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ int r = ypos + x->x_gui.x_h - (x->x_val + 50)/100;
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE\n",
+ canvas, xpos, ypos-2,
+ xpos + x->x_gui.x_w, ypos + x->x_gui.x_h+3,
+ x->x_gui.x_bcol, x);
+ sys_vgui(".x%x.c create line %d %d %d %d -width 3 -fill #%6.6x -tags %xKNOB\n",
+ canvas, xpos+1, r,
+ xpos + x->x_gui.x_w, r, x->x_gui.x_fcol, x);
+ sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
+ -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
+ canvas, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy,
+ strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
+ x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+ canvas,
+ xpos, ypos + x->x_gui.x_h+2,
+ xpos+7, ypos + x->x_gui.x_h+3,
+ x, 0);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
+ canvas,
+ xpos, ypos-2,
+ xpos+7, ypos-1,
+ x, 0);
+}
+
+static void vslider_draw_move(t_vslider *x, t_glist *glist)
+{
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ int r = ypos + x->x_gui.x_h - (x->x_val + 50)/100;
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c coords %xBASE %d %d %d %d\n",
+ canvas, x,
+ xpos, ypos-2,
+ xpos + x->x_gui.x_w, ypos + x->x_gui.x_h+3);
+ sys_vgui(".x%x.c coords %xKNOB %d %d %d %d\n",
+ canvas, x, xpos+1, r,
+ xpos + x->x_gui.x_w, r);
+ sys_vgui(".x%x.c coords %xLABEL %d %d\n",
+ canvas, x, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
+ canvas, x, 0,
+ xpos, ypos + x->x_gui.x_h+2,
+ xpos+7, ypos + x->x_gui.x_h+3);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
+ canvas, x, 0,
+ xpos, ypos-2,
+ xpos+7, ypos-1);
+}
+
+static void vslider_draw_erase(t_vslider* x,t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c delete %xBASE\n", canvas, x);
+ sys_vgui(".x%x.c delete %xKNOB\n", canvas, x);
+ sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
+}
+
+static void vslider_draw_config(t_vslider* x,t_glist* glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
+ canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
+ x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
+ strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
+ sys_vgui(".x%x.c itemconfigure %xKNOB -fill #%6.6x\n", canvas,
+ x, x->x_gui.x_fcol);
+ sys_vgui(".x%x.c itemconfigure %xBASE -fill #%6.6x\n", canvas,
+ x, x->x_gui.x_bcol);
+}
+
+static void vslider_draw_io(t_vslider* x,t_glist* glist, int old_snd_rcv_flags)
+{
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+ canvas,
+ xpos, ypos + x->x_gui.x_h+2,
+ xpos+7, ypos + x->x_gui.x_h+3,
+ x, 0);
+ if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
+ sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
+ if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
+ canvas,
+ xpos, ypos-2,
+ xpos+7, ypos-1,
+ x, 0);
+ if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
+ sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
+}
+
+static void vslider_draw_select(t_vslider *x, t_glist *glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if(x->x_gui.x_fsf.x_selected)
+ {
+ pd_bind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+ sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+ }
+ else
+ {
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
+ sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol);
+ }
+}
+
+void vslider_draw(t_vslider *x, t_glist *glist, int mode)
+{
+ if(mode == IEM_GUI_DRAW_MODE_UPDATE)
+ vslider_draw_update(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_MOVE)
+ vslider_draw_move(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_NEW)
+ vslider_draw_new(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_SELECT)
+ vslider_draw_select(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_ERASE)
+ vslider_draw_erase(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
+ vslider_draw_config(x, glist);
+ else if(mode >= IEM_GUI_DRAW_MODE_IO)
+ vslider_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
+}
+
+/* ------------------------ vsl widgetbehaviour----------------------------- */
+
+
+static void vslider_getrect(t_gobj *z, t_glist *glist,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_vslider* x = (t_vslider*)z;
+
+ *xp1 = text_xpix(&x->x_gui.x_obj, glist);
+ *yp1 = text_ypix(&x->x_gui.x_obj, glist) - 2;
+ *xp2 = *xp1 + x->x_gui.x_w;
+ *yp2 = *yp1 + x->x_gui.x_h + 5;
+}
+
+static void vslider_save(t_gobj *z, t_binbuf *b)
+{
+ t_vslider *x = (t_vslider *)z;
+ int bflcol[3], *ip1, *ip2;
+ t_symbol *srl[3];
+
+ iemgui_save(&x->x_gui, srl, bflcol);
+ ip1 = (int *)(&x->x_gui.x_isa);
+ ip2 = (int *)(&x->x_gui.x_fsf);
+ binbuf_addv(b, "ssiisiiffiisssiiiiiiiii", gensym("#X"),gensym("obj"),
+ (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
+ gensym("vsl"), x->x_gui.x_w, x->x_gui.x_h,
+ (float)x->x_min, (float)x->x_max,
+ x->x_lin0_log1, (*ip1)&IEM_INIT_ARGS_ALL,
+ srl[0], srl[1], srl[2],
+ x->x_gui.x_ldx, x->x_gui.x_ldy,
+ (*ip2)&IEM_FSTYLE_FLAGS_ALL, x->x_gui.x_fontsize,
+ bflcol[0], bflcol[1], bflcol[2],
+ x->x_val, x->x_steady);
+ binbuf_addv(b, ";");
+}
+
+void vslider_check_height(t_vslider *x, int h)
+{
+ if(h < IEM_SL_MINSIZE)
+ h = IEM_SL_MINSIZE;
+ x->x_gui.x_h = h;
+ if(x->x_val > (x->x_gui.x_h*100 - 100))
+ {
+ x->x_pos = x->x_gui.x_h*100 - 100;
+ x->x_val = x->x_pos;
+ }
+ if(x->x_lin0_log1)
+ x->x_k = log(x->x_max/x->x_min)/(double)(x->x_gui.x_h - 1);
+ else
+ x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_h - 1);
+}
+
+void vslider_check_minmax(t_vslider *x, double min, double max)
+{
+ if(x->x_lin0_log1)
+ {
+ if((min == 0.0)&&(max == 0.0))
+ max = 1.0;
+ if(max > 0.0)
+ {
+ if(min <= 0.0)
+ min = 0.01*max;
+ }
+ else
+ {
+ if(min > 0.0)
+ max = 0.01*min;
+ }
+ }
+ x->x_min = min;
+ x->x_max = max;
+ if(x->x_min > x->x_max) /* bugfix */
+ x->x_gui.x_isa.x_reverse = 1;
+ else
+ x->x_gui.x_isa.x_reverse = 0;
+ if(x->x_lin0_log1)
+ x->x_k = log(x->x_max/x->x_min)/(double)(x->x_gui.x_h - 1);
+ else
+ x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_h - 1);
+}
+
+static void vslider_properties(t_gobj *z, t_glist *owner)
+{
+ t_vslider *x = (t_vslider *)z;
+ char buf[800];
+ t_symbol *srl[3];
+
+ iemgui_properties(&x->x_gui, srl);
+
+ sprintf(buf, "pdtk_iemgui_dialog %%s VSLIDER \
+ --------dimensions(pix)(pix):-------- %d %d width: %d %d height: \
+ -----------output-range:----------- %g bottom: %g top: %d \
+ %d lin log %d %d empty %d \
+ %s %s \
+ %s %d %d \
+ %d %d \
+ %d %d %d\n",
+ x->x_gui.x_w, IEM_GUI_MINSIZE, x->x_gui.x_h, IEM_SL_MINSIZE,
+ x->x_min, x->x_max, 0,/*no_schedule*/
+ x->x_lin0_log1, x->x_gui.x_isa.x_loadinit, x->x_steady, -1,/*no multi, but iem-characteristic*/
+ srl[0]->s_name, srl[1]->s_name,
+ srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
+ x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
+ 0xffffff & x->x_gui.x_bcol, 0xffffff & x->x_gui.x_fcol, 0xffffff & x->x_gui.x_lcol);
+ gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
+}
+
+static void vslider_bang(t_vslider *x)
+{
+ double out;
+
+ if(x->x_lin0_log1)
+ out = x->x_min*exp(x->x_k*(double)(x->x_val)*0.01);
+ else
+ out = (double)(x->x_val)*0.01*x->x_k + x->x_min;
+ if((out < 1.0e-10)&&(out > -1.0e-10))
+ out = 0.0;
+
+ outlet_float(x->x_gui.x_obj.ob_outlet, out);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_float(x->x_gui.x_snd->s_thing, out);
+}
+
+static void vslider_dialog(t_vslider *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_symbol *srl[3];
+ int w = (int)atom_getintarg(0, argc, argv);
+ int h = (int)atom_getintarg(1, argc, argv);
+ double min = (double)atom_getfloatarg(2, argc, argv);
+ double max = (double)atom_getfloatarg(3, argc, argv);
+ int lilo = (int)atom_getintarg(4, argc, argv);
+ int steady = (int)atom_getintarg(17, argc, argv);
+ int sr_flags;
+
+ if(lilo != 0) lilo = 1;
+ x->x_lin0_log1 = lilo;
+ if(steady)
+ x->x_steady = 1;
+ else
+ x->x_steady = 0;
+ sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
+ x->x_gui.x_w = iemgui_clip_size(w);
+ vslider_check_height(x, h);
+ vslider_check_minmax(x, min, max);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
+}
+
+static void vslider_motion(t_vslider *x, t_floatarg dx, t_floatarg dy)
+{
+ int old = x->x_val;
+
+ if(x->x_gui.x_fsf.x_finemoved)
+ x->x_pos -= (int)dy;
+ else
+ x->x_pos -= 100*(int)dy;
+ x->x_val = x->x_pos;
+ if(x->x_val > (100*x->x_gui.x_h - 100))
+ {
+ x->x_val = 100*x->x_gui.x_h - 100;
+ x->x_pos += 50;
+ x->x_pos -= x->x_pos%100;
+ }
+ if(x->x_val < 0)
+ {
+ x->x_val = 0;
+ x->x_pos -= 50;
+ x->x_pos -= x->x_pos%100;
+ }
+ if(old != x->x_val)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ vslider_bang(x);
+ }
+}
+
+static void vslider_click(t_vslider *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ if(!x->x_steady)
+ x->x_val = (int)(100.0 * (x->x_gui.x_h + text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist) - ypos));
+ if(x->x_val > (100*x->x_gui.x_h - 100))
+ x->x_val = 100*x->x_gui.x_h - 100;
+ if(x->x_val < 0)
+ x->x_val = 0;
+ x->x_pos = x->x_val;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ vslider_bang(x);
+ glist_grab(x->x_gui.x_glist, &x->x_gui.x_obj.te_g, (t_glistmotionfn)vslider_motion,
+ 0, xpos, ypos);
+}
+
+static int vslider_newclick(t_gobj *z, struct _glist *glist,
+ int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+ t_vslider* x = (t_vslider *)z;
+
+ if(doit)
+ {
+ vslider_click( x, (t_floatarg)xpix, (t_floatarg)ypix, (t_floatarg)shift,
+ 0, (t_floatarg)alt);
+ if(shift)
+ x->x_gui.x_fsf.x_finemoved = 1;
+ else
+ x->x_gui.x_fsf.x_finemoved = 0;
+ }
+ return (1);
+}
+
+static void vslider_set(t_vslider *x, t_floatarg f)
+{
+ double g;
+
+ if(x->x_gui.x_isa.x_reverse) /* bugfix */
+ {
+ if(f > x->x_min)
+ f = x->x_min;
+ if(f < x->x_max)
+ f = x->x_max;
+ }
+ else
+ {
+ if(f > x->x_max)
+ f = x->x_max;
+ if(f < x->x_min)
+ f = x->x_min;
+ }
+ if(x->x_lin0_log1)
+ g = log(f/x->x_min)/x->x_k;
+ else
+ g = (f - x->x_min) / x->x_k;
+ x->x_val = (int)(100.0*g + 0.49999);
+ x->x_pos = x->x_val;
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+}
+
+static void vslider_float(t_vslider *x, t_floatarg f)
+{
+ vslider_set(x, f);
+ if(x->x_gui.x_fsf.x_put_in2out)
+ vslider_bang(x);
+}
+
+static void vslider_size(t_vslider *x, t_symbol *s, int ac, t_atom *av)
+{
+ x->x_gui.x_w = iemgui_clip_size((int)atom_getintarg(0, ac, av));
+ if(ac > 1)
+ vslider_check_height(x, (int)atom_getintarg(1, ac, av));
+ iemgui_size((void *)x, &x->x_gui);
+}
+
+static void vslider_delta(t_vslider *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
+
+static void vslider_pos(t_vslider *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
+
+static void vslider_range(t_vslider *x, t_symbol *s, int ac, t_atom *av)
+{
+ vslider_check_minmax(x, (double)atom_getfloatarg(0, ac, av),
+ (double)atom_getfloatarg(1, ac, av));
+}
+
+static void vslider_color(t_vslider *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
+
+static void vslider_send(t_vslider *x, t_symbol *s)
+{iemgui_send(x, &x->x_gui, s);}
+
+static void vslider_receive(t_vslider *x, t_symbol *s)
+{iemgui_receive(x, &x->x_gui, s);}
+
+static void vslider_label(t_vslider *x, t_symbol *s)
+{iemgui_label((void *)x, &x->x_gui, s);}
+
+static void vslider_label_pos(t_vslider *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
+
+static void vslider_label_font(t_vslider *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
+
+static void vslider_log(t_vslider *x)
+{
+ x->x_lin0_log1 = 1;
+ vslider_check_minmax(x, x->x_min, x->x_max);
+}
+
+static void vslider_lin(t_vslider *x)
+{
+ x->x_lin0_log1 = 0;
+ x->x_k = (x->x_max - x->x_min)/(double)(x->x_gui.x_h - 1);
+}
+
+static void vslider_init(t_vslider *x, t_floatarg f)
+{
+ x->x_gui.x_isa.x_loadinit = (f==0.0)?0:1;
+}
+
+static void vslider_steady(t_vslider *x, t_floatarg f)
+{
+ x->x_steady = (f==0.0)?0:1;
+}
+
+static void vslider_loadbang(t_vslider *x)
+{
+ if(!sys_noloadbang && x->x_gui.x_isa.x_loadinit)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
+ vslider_bang(x);
+ }
+}
+
+static void vslider_list(t_vslider *x, t_symbol *s, int ac, t_atom *av)
+{
+ int l=iemgui_list((void *)x, &x->x_gui, s, ac, av);
+
+ if(l < 0)
+ {
+ if(IS_A_FLOAT(av,0))
+ vslider_float(x, atom_getfloatarg(0, ac, av));
+ }
+ else if(l > 0)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
+ }
+}
+
+static void *vslider_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_vslider *x = (t_vslider *)pd_new(vslider_class);
+ int bflcol[]={-262144, -1, -1};
+ t_symbol *srl[3];
+ int w=IEM_GUI_DEFAULTSIZE, h=IEM_SL_DEFAULTSIZE;
+ int lilo=0, f=0, ldx=0, ldy=-8;
+ int fs=8, iinit=0, ifstyle=0, v=0, steady=1;
+ double min=0.0, max=(double)(IEM_SL_DEFAULTSIZE-1);
+ t_iem_init_symargs *init=(t_iem_init_symargs *)(&iinit);
+ t_iem_fstyle_flags *fstyle=(t_iem_fstyle_flags *)(&ifstyle);
+ char str[144];
+
+ srl[0] = gensym("empty");
+ srl[1] = gensym("empty");
+ srl[2] = gensym("empty");
+
+
+ if(((argc == 17)||(argc == 18))&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)
+ &&IS_A_FLOAT(argv,2)&&IS_A_FLOAT(argv,3)
+ &&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5)
+ &&(IS_A_SYMBOL(argv,6)||IS_A_FLOAT(argv,6))
+ &&(IS_A_SYMBOL(argv,7)||IS_A_FLOAT(argv,7))
+ &&(IS_A_SYMBOL(argv,8)||IS_A_FLOAT(argv,8))
+ &&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10)
+ &&IS_A_FLOAT(argv,11)&&IS_A_FLOAT(argv,12)&&IS_A_FLOAT(argv,13)
+ &&IS_A_FLOAT(argv,14)&&IS_A_FLOAT(argv,15)&&IS_A_FLOAT(argv,16))
+ {
+ w = (int)atom_getintarg(0, argc, argv);
+ h = (int)atom_getintarg(1, argc, argv);
+ min = (double)atom_getfloatarg(2, argc, argv);
+ max = (double)atom_getfloatarg(3, argc, argv);
+ lilo = (int)atom_getintarg(4, argc, argv);
+ iinit = (int)atom_getintarg(5, argc, argv);
+ srl[0] = atom_getsymbolarg(6, argc, argv);
+ srl[1] = atom_getsymbolarg(7, argc, argv);
+ srl[2] = atom_getsymbolarg(8, argc, argv);
+ if(IS_A_SYMBOL(argv,6))
+ srl[0] = atom_getsymbolarg(6, argc, argv);
+ else if(IS_A_FLOAT(argv,6))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(6, argc, argv));
+ srl[0] = gensym(str);
+ }
+ if(IS_A_SYMBOL(argv,7))
+ srl[1] = atom_getsymbolarg(7, argc, argv);
+ else if(IS_A_FLOAT(argv,7))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(7, argc, argv));
+ srl[1] = gensym(str);
+ }
+ if(IS_A_SYMBOL(argv,8))
+ srl[2] = atom_getsymbolarg(8, argc, argv);
+ else if(IS_A_FLOAT(argv,8))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(8, argc, argv));
+ srl[2] = gensym(str);
+ }
+ ldx = (int)atom_getintarg(9, argc, argv);
+ ldy = (int)atom_getintarg(10, argc, argv);
+ ifstyle = (int)atom_getintarg(11, argc, argv);
+ fs = (int)atom_getintarg(12, argc, argv);
+ bflcol[0] = (int)atom_getintarg(13, argc, argv);
+ bflcol[1] = (int)atom_getintarg(14, argc, argv);
+ bflcol[2] = (int)atom_getintarg(15, argc, argv);
+ v = (int)atom_getintarg(16, argc, argv);
+ }
+ if((argc == 18)&&IS_A_FLOAT(argv,17))
+ steady = (int)atom_getintarg(17, argc, argv);
+ x->x_gui.x_draw = (t_iemfunptr)vslider_draw;
+ iinit &= IEM_INIT_ARGS_ALL;
+ ifstyle &= IEM_FSTYLE_FLAGS_ALL;
+ fstyle->x_snd_able = 1;
+ fstyle->x_rcv_able = 1;
+ x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
+ x->x_gui.x_isa = *init;
+ if(x->x_gui.x_isa.x_loadinit)
+ x->x_val = v;
+ else
+ x->x_val = 0;
+ x->x_pos = x->x_val;
+ if(lilo != 0) lilo = 1;
+ x->x_lin0_log1 = lilo;
+ if(steady != 0) steady = 1;
+ x->x_steady = steady;
+ if(!strcmp(srl[0]->s_name, "empty")) fstyle->x_snd_able = 0;
+ if(!strcmp(srl[1]->s_name, "empty")) fstyle->x_rcv_able = 0;
+ x->x_gui.x_unique_num = 0;
+ if(fstyle->x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
+ else if(fstyle->x_font_style == 2) strcpy(x->x_gui.x_font, "times");
+ else { fstyle->x_font_style = 0;
+ strcpy(x->x_gui.x_font, "courier"); }
+ x->x_gui.x_fsf = *fstyle;
+ iemgui_first_dollararg2sym(&x->x_gui, srl);
+ if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, srl[1]);
+ x->x_gui.x_snd = srl[0];
+ x->x_gui.x_rcv = srl[1];
+ x->x_gui.x_lab = srl[2];
+ x->x_gui.x_ldx = ldx;
+ x->x_gui.x_ldy = ldy;
+ if(fs < 4)
+ fs = 4;
+ x->x_gui.x_fontsize = fs;
+ x->x_gui.x_w = iemgui_clip_size(w);
+ vslider_check_height(x, h);
+ vslider_check_minmax(x, min, max);
+ iemgui_all_colfromload(&x->x_gui, bflcol);
+ iemgui_verify_snd_ne_rcv(&x->x_gui);
+ outlet_new(&x->x_gui.x_obj, &s_float);
+ return (x);
+}
+
+static void vslider_free(t_vslider *x)
+{
+ if(x->x_gui.x_fsf.x_selected)
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ if(x->x_gui.x_fsf.x_rcv_able)
+ pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
+ gfxstub_deleteforkey(x);
+}
+
+void g_vslider_setup(void)
+{
+ vslider_class = class_new(gensym("vsl"), (t_newmethod)vslider_new,
+ (t_method)vslider_free, sizeof(t_vslider), 0, A_GIMME, 0);
+ class_addcreator((t_newmethod)vslider_new, gensym("vslider"), A_GIMME, 0);
+ class_addbang(vslider_class,vslider_bang);
+ class_addfloat(vslider_class,vslider_float);
+ class_addlist(vslider_class, vslider_list);
+ class_addmethod(vslider_class, (t_method)vslider_click, gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(vslider_class, (t_method)vslider_motion, gensym("motion"),
+ A_FLOAT, A_FLOAT, 0);
+ class_addmethod(vslider_class, (t_method)vslider_dialog, gensym("dialog"),
+ A_GIMME, 0);
+ class_addmethod(vslider_class, (t_method)vslider_loadbang, gensym("loadbang"), 0);
+ class_addmethod(vslider_class, (t_method)vslider_set, gensym("set"), A_FLOAT, 0);
+ class_addmethod(vslider_class, (t_method)vslider_size, gensym("size"), A_GIMME, 0);
+ class_addmethod(vslider_class, (t_method)vslider_delta, gensym("delta"), A_GIMME, 0);
+ class_addmethod(vslider_class, (t_method)vslider_pos, gensym("pos"), A_GIMME, 0);
+ class_addmethod(vslider_class, (t_method)vslider_range, gensym("range"), A_GIMME, 0);
+ class_addmethod(vslider_class, (t_method)vslider_color, gensym("color"), A_GIMME, 0);
+ class_addmethod(vslider_class, (t_method)vslider_send, gensym("send"), A_DEFSYM, 0);
+ class_addmethod(vslider_class, (t_method)vslider_receive, gensym("receive"), A_DEFSYM, 0);
+ class_addmethod(vslider_class, (t_method)vslider_label, gensym("label"), A_DEFSYM, 0);
+ class_addmethod(vslider_class, (t_method)vslider_label_pos, gensym("label_pos"), A_GIMME, 0);
+ class_addmethod(vslider_class, (t_method)vslider_label_font, gensym("label_font"), A_GIMME, 0);
+ class_addmethod(vslider_class, (t_method)vslider_log, gensym("log"), 0);
+ class_addmethod(vslider_class, (t_method)vslider_lin, gensym("lin"), 0);
+ class_addmethod(vslider_class, (t_method)vslider_init, gensym("init"), A_FLOAT, 0);
+ class_addmethod(vslider_class, (t_method)vslider_steady, gensym("steady"), A_FLOAT, 0);
+ if(!iemgui_key_sym)
+ iemgui_key_sym = gensym("#keyname");
+ vslider_widgetbehavior.w_getrectfn = vslider_getrect;
+ vslider_widgetbehavior.w_displacefn = iemgui_displace;
+ vslider_widgetbehavior.w_selectfn = iemgui_select;
+ vslider_widgetbehavior.w_activatefn = NULL;
+ vslider_widgetbehavior.w_deletefn = iemgui_delete;
+ vslider_widgetbehavior.w_visfn = iemgui_vis;
+ vslider_widgetbehavior.w_clickfn = vslider_newclick;
+ vslider_widgetbehavior.w_propertiesfn = vslider_properties;;
+ vslider_widgetbehavior.w_savefn = vslider_save;
+ class_setwidget(vslider_class, &vslider_widgetbehavior);
+ class_sethelpsymbol(vslider_class, gensym("vslider"));
+}
diff --git a/pd/src/g_vumeter.c b/pd/src/g_vumeter.c
new file mode 100644
index 00000000..b257c588
--- /dev/null
+++ b/pd/src/g_vumeter.c
@@ -0,0 +1,762 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* g_7_guis.c written by Thomas Musil (c) IEM KUG Graz Austria 2000-2001 */
+/* thanks to Miller Puckette, Guenther Geiger and Krzystof Czaja */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "m_imp.h"
+#include "g_canvas.h"
+#include "t_tk.h"
+#include "g_all_guis.h"
+#include <math.h>
+
+#ifdef NT
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+/* ----- vu gui-peak- & rms- vu-meter-display ---------- */
+
+t_widgetbehavior vu_widgetbehavior;
+static t_class *vu_class;
+
+/* widget helper functions */
+
+static void vu_update_rms(t_vu *x, t_glist *glist)
+{
+ if(glist_isvisible(glist))
+ {
+ int w4=x->x_gui.x_w/4, off=text_ypix(&x->x_gui.x_obj, glist)-1;
+ int xpos=text_xpix(&x->x_gui.x_obj, glist), quad1=xpos+w4+1, quad3=xpos+x->x_gui.x_w-w4-1;
+
+ sys_vgui(".x%x.c coords %xRCOVER %d %d %d %d\n",
+ glist_getcanvas(glist), x, quad1, off, quad3,
+ off + (x->x_led_size+1)*(IEM_VU_STEPS-x->x_rms));
+ }
+}
+
+static void vu_update_peak(t_vu *x, t_glist *glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if(glist_isvisible(glist))
+ {
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+
+ if(x->x_peak)
+ {
+ int i=iemgui_vu_col[x->x_peak];
+ int j=ypos + (x->x_led_size+1)*(IEM_VU_STEPS+1-x->x_peak)
+ - (x->x_led_size+1)/2;
+
+ sys_vgui(".x%x.c coords %xPLED %d %d %d %d\n", canvas, x,
+ xpos, j,
+ xpos+x->x_gui.x_w+1, j);
+ sys_vgui(".x%x.c itemconfigure %xPLED -fill #%6.6x\n", canvas, x,
+ iemgui_color_hex[i]);
+ }
+ else
+ {
+ int mid=xpos+x->x_gui.x_w/2;
+
+ sys_vgui(".x%x.c itemconfigure %xPLED -fill #%6.6x\n",
+ canvas, x, x->x_gui.x_bcol);
+ sys_vgui(".x%x.c coords %xPLED %d %d %d %d\n",
+ canvas, x, mid, ypos+20,
+ mid, ypos+20);
+ }
+ }
+}
+
+static void vu_draw_new(t_vu *x, t_glist *glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ int w4=x->x_gui.x_w/4, mid=xpos+x->x_gui.x_w/2,
+ quad1=xpos+w4+1;
+ int quad3=xpos+x->x_gui.x_w-w4,
+ end=xpos+x->x_gui.x_w+4;
+ int k1=x->x_led_size+1, k2=IEM_VU_STEPS+1, k3=k1/2;
+ int led_col, yyy, i, k4=ypos-k3;
+
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -tags %xBASE\n",
+ canvas, xpos-1, ypos-2,
+ xpos+x->x_gui.x_w+1,
+ ypos+x->x_gui.x_h+2, x->x_gui.x_bcol, x);
+ for(i=1; i<=IEM_VU_STEPS; i++)
+ {
+ led_col = iemgui_vu_col[i];
+ yyy = k4 + k1*(k2-i);
+ sys_vgui(".x%x.c create line %d %d %d %d -width %d -fill #%6.6x -tags %xRLED%d\n",
+ canvas, quad1, yyy, quad3, yyy, x->x_led_size, iemgui_color_hex[led_col], x, i);
+ if(((i+2)&3) && (x->x_scale))
+ sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
+ -font {%s %d bold} -fill #%6.6x -tags %xSCALE%d\n",
+ canvas, end, yyy+k3, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
+ x->x_gui.x_lcol, x, i);
+ }
+ if(x->x_scale)
+ {
+ i=IEM_VU_STEPS+1;
+ yyy = k4 + k1*(k2-i);
+ sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
+ -font {%s %d bold} -fill #%6.6x -tags %xSCALE%d\n",
+ canvas, end, yyy+k3, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
+ x->x_gui.x_lcol, x, i);
+ }
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -fill #%6.6x -outline #%6.6x -tags %xRCOVER\n",
+ canvas, quad1, ypos-1, quad3-1,
+ ypos-1 + k1*IEM_VU_STEPS, x->x_gui.x_bcol, x->x_gui.x_bcol, x);
+ sys_vgui(".x%x.c create line %d %d %d %d -width %d -fill #%6.6x -tags %xPLED\n",
+ canvas, mid, ypos+10,
+ mid, ypos+10, x->x_led_size, x->x_gui.x_bcol, x);
+ sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
+ -font {%s %d bold} -fill #%6.6x -tags %xLABEL\n",
+ canvas, xpos+x->x_gui.x_ldx, ypos+x->x_gui.x_ldy,
+ strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"",
+ x->x_gui.x_font, x->x_gui.x_fontsize, x->x_gui.x_lcol, x);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ {
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+ canvas,
+ xpos-1, ypos + x->x_gui.x_h+1,
+ xpos + IOWIDTH-1, ypos + x->x_gui.x_h+2,
+ x, 0);
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+ canvas,
+ xpos+x->x_gui.x_w+1-IOWIDTH, ypos + x->x_gui.x_h+1,
+ xpos+x->x_gui.x_w+1, ypos + x->x_gui.x_h+2,
+ x, 1);
+ }
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ {
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
+ canvas,
+ xpos-1, ypos-2,
+ xpos + IOWIDTH-1, ypos-1,
+ x, 0);
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
+ canvas,
+ xpos+x->x_gui.x_w+1-IOWIDTH, ypos-2,
+ xpos+x->x_gui.x_w+1, ypos-1,
+ x, 1);
+ }
+}
+
+
+static void vu_draw_move(t_vu *x, t_glist *glist)
+{
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ int w4=x->x_gui.x_w/4, quad1=xpos+w4+1;
+ int quad3=xpos+x->x_gui.x_w-w4,
+ end=xpos+x->x_gui.x_w+4;
+ int k1=x->x_led_size+1, k2=IEM_VU_STEPS+1, k3=k1/2;
+ int yyy, i, k4=ypos-k3;
+
+ sys_vgui(".x%x.c coords %xBASE %d %d %d %d\n",
+ canvas, x, xpos-1, ypos-2,
+ xpos+x->x_gui.x_w+1,ypos+x->x_gui.x_h+2);
+ for(i=1; i<=IEM_VU_STEPS; i++)
+ {
+ yyy = k4 + k1*(k2-i);
+ sys_vgui(".x%x.c coords %xRLED%d %d %d %d %d\n",
+ canvas, x, i, quad1, yyy, quad3, yyy);
+ if(((i+2)&3) && (x->x_scale))
+ sys_vgui(".x%x.c coords %xSCALE%d %d %d\n",
+ canvas, x, i, end, yyy+k3);
+ }
+ if(x->x_scale)
+ {
+ i=IEM_VU_STEPS+1;
+ yyy = k4 + k1*(k2-i);
+ sys_vgui(".x%x.c coords %xSCALE%d %d %d\n",
+ canvas, x, i, end, yyy+k3);
+ }
+ vu_update_peak(x, glist);
+ vu_update_rms(x, glist);
+ sys_vgui(".x%x.c coords %xLABEL %d %d\n",
+ canvas, x, xpos+x->x_gui.x_ldx,
+ ypos+x->x_gui.x_ldy);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ {
+ sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
+ canvas, x, 0,
+ xpos-1, ypos + x->x_gui.x_h+1,
+ xpos + IOWIDTH-1, ypos + x->x_gui.x_h+2);
+ sys_vgui(".x%x.c coords %xOUT%d %d %d %d %d\n",
+ canvas, x, 1,
+ xpos+x->x_gui.x_w+1-IOWIDTH, ypos + x->x_gui.x_h+1,
+ xpos+x->x_gui.x_w+1, ypos + x->x_gui.x_h+2);
+ }
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ {
+ sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
+ canvas, x, 0,
+ xpos-1, ypos-2,
+ xpos + IOWIDTH-1, ypos-1);
+ sys_vgui(".x%x.c coords %xIN%d %d %d %d %d\n",
+ canvas, x, 1,
+ xpos+x->x_gui.x_w+1-IOWIDTH, ypos-2,
+ xpos+x->x_gui.x_w+1, ypos-1);
+ }
+}
+
+static void vu_draw_erase(t_vu* x,t_glist* glist)
+{
+ int i;
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c delete %xBASE\n", canvas, x);
+ for(i=1; i<=IEM_VU_STEPS; i++)
+ {
+ sys_vgui(".x%x.c delete %xRLED%d\n", canvas, x, i);
+ if(((i+2)&3) && (x->x_scale))
+ sys_vgui(".x%x.c delete %xSCALE%d\n", canvas, x, i);
+ }
+ if(x->x_scale)
+ {
+ i=IEM_VU_STEPS+1;
+ sys_vgui(".x%x.c delete %xSCALE%d\n", canvas, x, i);
+ }
+ sys_vgui(".x%x.c delete %xPLED\n", canvas, x);
+ sys_vgui(".x%x.c delete %xRCOVER\n", canvas, x);
+ sys_vgui(".x%x.c delete %xLABEL\n", canvas, x);
+ if(!x->x_gui.x_fsf.x_snd_able)
+ {
+ sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
+ sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 1);
+ }
+ if(!x->x_gui.x_fsf.x_rcv_able)
+ {
+ sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
+ sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 1);
+ }
+}
+
+static void vu_draw_config(t_vu* x, t_glist* glist)
+{
+ int i;
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ sys_vgui(".x%x.c itemconfigure %xBASE -fill #%6.6x\n", canvas, x, x->x_gui.x_bcol);
+ for(i=1; i<=IEM_VU_STEPS; i++)
+ {
+ sys_vgui(".x%x.c itemconfigure %xRLED%d -width %d\n", canvas, x, i,
+ x->x_led_size);
+ if(((i+2)&3) && (x->x_scale))
+ sys_vgui(".x%x.c itemconfigure %xSCALE%d -text {%s} -font {%s %d bold} -fill #%6.6x\n",
+ canvas, x, i, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
+ x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol);
+ }
+ if(x->x_scale)
+ {
+ i=IEM_VU_STEPS+1;
+ sys_vgui(".x%x.c itemconfigure %xSCALE%d -text {%s} -font {%s %d bold} -fill #%6.6x\n",
+ canvas, x, i, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
+ x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol);
+ }
+ sys_vgui(".x%x.c itemconfigure %xLABEL -font {%s %d bold} -fill #%6.6x -text {%s} \n",
+ canvas, x, x->x_gui.x_font, x->x_gui.x_fontsize,
+ x->x_gui.x_fsf.x_selected?IEM_GUI_COLOR_SELECTED:x->x_gui.x_lcol,
+ strcmp(x->x_gui.x_lab->s_name, "empty")?x->x_gui.x_lab->s_name:"");
+
+ sys_vgui(".x%x.c itemconfigure %xRCOVER -fill #%6.6x -outline #%6.6x\n", canvas,
+ x, x->x_gui.x_bcol, x->x_gui.x_bcol);
+ sys_vgui(".x%x.c itemconfigure %xPLED -width %d\n", canvas, x,
+ x->x_led_size);
+}
+
+static void vu_draw_io(t_vu* x, t_glist* glist, int old_snd_rcv_flags)
+{
+ int xpos=text_xpix(&x->x_gui.x_obj, glist);
+ int ypos=text_ypix(&x->x_gui.x_obj, glist);
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
+ {
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+ canvas,
+ xpos-1, ypos + x->x_gui.x_h+1,
+ xpos + IOWIDTH-1, ypos + x->x_gui.x_h+2,
+ x, 0);
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xOUT%d\n",
+ canvas,
+ xpos+x->x_gui.x_w+1-IOWIDTH, ypos + x->x_gui.x_h+1,
+ xpos+x->x_gui.x_w+1, ypos + x->x_gui.x_h+2,
+ x, 1);
+ }
+ if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
+ {
+ sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 0);
+ sys_vgui(".x%x.c delete %xOUT%d\n", canvas, x, 1);
+ }
+ if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
+ {
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
+ canvas,
+ xpos-1, ypos-2,
+ xpos + IOWIDTH-1, ypos-1,
+ x, 0);
+ sys_vgui(".x%x.c create rectangle %d %d %d %d -tags %xIN%d\n",
+ canvas,
+ xpos+x->x_gui.x_w+1-IOWIDTH, ypos-2,
+ xpos+x->x_gui.x_w+1, ypos-1,
+ x, 1);
+ }
+ if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
+ {
+ sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 0);
+ sys_vgui(".x%x.c delete %xIN%d\n", canvas, x, 1);
+ }
+}
+
+static void vu_draw_select(t_vu* x,t_glist* glist)
+{
+ int i;
+ t_canvas *canvas=glist_getcanvas(glist);
+
+ if(x->x_gui.x_fsf.x_selected)
+ {
+ pd_bind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+ for(i=1; i<=IEM_VU_STEPS; i++)
+ {
+ if(((i+2)&3) && (x->x_scale))
+ sys_vgui(".x%x.c itemconfigure %xSCALE%d -fill #%6.6x\n",
+ canvas, x, i, IEM_GUI_COLOR_SELECTED);
+ }
+ if(x->x_scale)
+ {
+ i=IEM_VU_STEPS+1;
+ sys_vgui(".x%x.c itemconfigure %xSCALE%d -fill #%6.6x\n",
+ canvas, x, i, IEM_GUI_COLOR_SELECTED);
+ }
+ sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, IEM_GUI_COLOR_SELECTED);
+ }
+ else
+ {
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ sys_vgui(".x%x.c itemconfigure %xBASE -outline #%6.6x\n", canvas, x, IEM_GUI_COLOR_NORMAL);
+ for(i=1; i<=IEM_VU_STEPS; i++)
+ {
+ if(((i+2)&3) && (x->x_scale))
+ sys_vgui(".x%x.c itemconfigure %xSCALE%d -fill #%6.6x\n",
+ canvas, x, i, x->x_gui.x_lcol);
+ }
+ if(x->x_scale)
+ {
+ i=IEM_VU_STEPS+1;
+ sys_vgui(".x%x.c itemconfigure %xSCALE%d -fill #%6.6x\n",
+ canvas, x, i, x->x_gui.x_lcol);
+ }
+ sys_vgui(".x%x.c itemconfigure %xLABEL -fill #%6.6x\n", canvas, x, x->x_gui.x_lcol);
+ }
+}
+
+void vu_draw(t_vu *x, t_glist *glist, int mode)
+{
+ if(mode == IEM_GUI_DRAW_MODE_MOVE)
+ vu_draw_move(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_NEW)
+ vu_draw_new(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_SELECT)
+ vu_draw_select(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_ERASE)
+ vu_draw_erase(x, glist);
+ else if(mode == IEM_GUI_DRAW_MODE_CONFIG)
+ vu_draw_config(x, glist);
+ else if(mode >= IEM_GUI_DRAW_MODE_IO)
+ vu_draw_io(x, glist, mode - IEM_GUI_DRAW_MODE_IO);
+}
+
+/* ------------------------ vu widgetbehaviour----------------------------- */
+
+
+static void vu_getrect(t_gobj *z, t_glist *glist,
+ int *xp1, int *yp1, int *xp2, int *yp2)
+{
+ t_vu* x = (t_vu*)z;
+
+ *xp1 = text_xpix(&x->x_gui.x_obj, glist) - 1;
+ *yp1 = text_ypix(&x->x_gui.x_obj, glist) - 2;
+ *xp2 = *xp1 + x->x_gui.x_w + 2;
+ *yp2 = *yp1 + x->x_gui.x_h + 4;
+}
+
+static void vu_save(t_gobj *z, t_binbuf *b)
+{
+ t_vu *x = (t_vu *)z;
+ int bflcol[3], *ip1, *ip2;
+ t_symbol *srl[3];
+
+ iemgui_save(&x->x_gui, srl, bflcol);
+ ip1 = (int *)(&x->x_gui.x_isa);
+ ip2 = (int *)(&x->x_gui.x_fsf);
+ binbuf_addv(b, "ssiisiissiiiiiiii", gensym("#X"),gensym("obj"),
+ (t_int)x->x_gui.x_obj.te_xpix, (t_int)x->x_gui.x_obj.te_ypix,
+ gensym("vu"), x->x_gui.x_w, x->x_gui.x_h,
+ srl[1], srl[2],
+ x->x_gui.x_ldx, x->x_gui.x_ldy,
+ (*ip2)&IEM_FSTYLE_FLAGS_ALL, x->x_gui.x_fontsize,
+ bflcol[0], bflcol[2], x->x_scale, (*ip1)&IEM_INIT_ARGS_ALL);
+ binbuf_addv(b, ";");
+}
+
+void vu_check_height(t_vu *x, int h)
+{
+ int n;
+
+ n = h / IEM_VU_STEPS;
+ if(n < IEM_VU_MINSIZE)
+ n = IEM_VU_MINSIZE;
+ x->x_led_size = n-1;
+ x->x_gui.x_h = IEM_VU_STEPS * n;
+}
+
+static void vu_scale(t_vu *x, t_floatarg fscale)
+{
+ int i, scale = (int)fscale;
+
+ if(scale != 0) scale = 1;
+ if(x->x_scale && !scale)
+ {
+ t_canvas *canvas=glist_getcanvas(x->x_gui.x_glist);
+
+ x->x_scale = (int)scale;
+ if(glist_isvisible(x->x_gui.x_glist))
+ {
+ for(i=1; i<=IEM_VU_STEPS; i++)
+ {
+ if((i+2)&3)
+ sys_vgui(".x%x.c delete %xSCALE%d\n", canvas, x, i);
+ }
+ i=IEM_VU_STEPS+1;
+ sys_vgui(".x%x.c delete %xSCALE%d\n", canvas, x, i);
+ }
+ }
+ if(!x->x_scale && scale)
+ {
+ int w4=x->x_gui.x_w/4, end=text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist)+x->x_gui.x_w+4;
+ int k1=x->x_led_size+1, k2=IEM_VU_STEPS+1, k3=k1/2;
+ int yyy, k4=text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist)-k3;
+ t_canvas *canvas=glist_getcanvas(x->x_gui.x_glist);
+
+ x->x_scale = (int)scale;
+ if(glist_isvisible(x->x_gui.x_glist))
+ {
+ for(i=1; i<=IEM_VU_STEPS; i++)
+ {
+ yyy = k4 + k1*(k2-i);
+ if((i+2)&3)
+ sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
+ -font {%s %d bold} -fill #%6.6x -tags %xSCALE%d\n",
+ canvas, end, yyy+k3, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
+ x->x_gui.x_lcol, x, i);
+ }
+ i=IEM_VU_STEPS+1;
+ yyy = k4 + k1*(k2-i);
+ sys_vgui(".x%x.c create text %d %d -text {%s} -anchor w \
+ -font {%s %d bold} -fill #%6.6x -tags %xSCALE%d\n",
+ canvas, end, yyy+k3, iemgui_vu_scale_str[i], x->x_gui.x_font, x->x_gui.x_fontsize,
+ x->x_gui.x_lcol, x, i);
+ }
+ }
+}
+
+static void vu_properties(t_gobj *z, t_glist *owner)
+{
+ t_vu *x = (t_vu *)z;
+ char buf[800];
+ t_symbol *srl[3];
+
+ iemgui_properties(&x->x_gui, srl);
+ sprintf(buf, "pdtk_iemgui_dialog %%s VU-METER \
+ --------dimensions(pix)(pix):-------- %d %d width: %d %d height: \
+ empty 0.0 empty 0.0 empty %d \
+ %d no_scale scale %d %d empty %d \
+ %s %s \
+ %s %d %d \
+ %d %d \
+ %d %d %d\n",
+ x->x_gui.x_w, IEM_GUI_MINSIZE, x->x_gui.x_h, IEM_VU_STEPS*IEM_VU_MINSIZE,
+ 0,/*no_schedule*/
+ x->x_scale, -1, -1, -1,/*no linlog, no init, no multi*/
+ "nosndno", srl[1]->s_name,/*no send*/
+ srl[2]->s_name, x->x_gui.x_ldx, x->x_gui.x_ldy,
+ x->x_gui.x_fsf.x_font_style, x->x_gui.x_fontsize,
+ 0xffffff & x->x_gui.x_bcol, -1/*no front-color*/, 0xffffff & x->x_gui.x_lcol);
+ gfxstub_new(&x->x_gui.x_obj.ob_pd, x, buf);
+}
+
+static void vu_dialog(t_vu *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_symbol *srl[3];
+ int w = (int)atom_getintarg(0, argc, argv);
+ int h = (int)atom_getintarg(1, argc, argv);
+ int scale = (int)atom_getintarg(4, argc, argv);
+ int sr_flags;
+
+ srl[0] = gensym("empty");
+ sr_flags = iemgui_dialog(&x->x_gui, srl, argc, argv);
+ x->x_gui.x_fsf.x_snd_able = 0;
+ x->x_gui.x_isa.x_loadinit = 0;
+ x->x_gui.x_w = iemgui_clip_size(w);
+ vu_check_height(x, h);
+ if(scale != 0)
+ scale = 1;
+ vu_scale(x, (float)scale);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_IO + sr_flags);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
+}
+
+static void vu_size(t_vu *x, t_symbol *s, int ac, t_atom *av)
+{
+ x->x_gui.x_w = iemgui_clip_size((int)atom_getintarg(0, ac, av));
+ if(ac > 1)
+ vu_check_height(x, (int)atom_getintarg(1, ac, av));
+ if(glist_isvisible(x->x_gui.x_glist))
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_CONFIG);
+ canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
+ }
+}
+
+static void vu_delta(t_vu *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_delta((void *)x, &x->x_gui, s, ac, av);}
+
+static void vu_pos(t_vu *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_pos((void *)x, &x->x_gui, s, ac, av);}
+
+static void vu_color(t_vu *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_color((void *)x, &x->x_gui, s, ac, av);}
+
+static void vu_receive(t_vu *x, t_symbol *s)
+{iemgui_receive(x, &x->x_gui, s);}
+
+static void vu_label(t_vu *x, t_symbol *s)
+{iemgui_label((void *)x, &x->x_gui, s);}
+
+static void vu_label_pos(t_vu *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_label_pos((void *)x, &x->x_gui, s, ac, av);}
+
+static void vu_label_font(t_vu *x, t_symbol *s, int ac, t_atom *av)
+{iemgui_label_font((void *)x, &x->x_gui, s, ac, av);}
+
+static void vu_float(t_vu *x, t_floatarg rms)
+{
+ int i;
+
+ if(rms <= IEM_VU_MINDB)
+ x->x_rms = 0;
+ else if(rms >= IEM_VU_MAXDB)
+ x->x_rms = IEM_VU_STEPS;
+ else
+ {
+ int i = (int)(2.0*(rms + IEM_VU_OFFSET));
+ x->x_rms = iemgui_vu_db2i[i];
+ }
+ i = (int)(100.0*rms + 10000.5);
+ rms = 0.01*(float)(i - 10000);
+ x->x_fr = rms;
+ outlet_float(x->x_out_rms, rms);
+ vu_update_rms(x, x->x_gui.x_glist);
+}
+
+static void vu_ft1(t_vu *x, t_floatarg peak)
+{
+ int i;
+
+ if(peak <= IEM_VU_MINDB)
+ x->x_peak = 0;
+ else if(peak >= IEM_VU_MAXDB)
+ x->x_peak = IEM_VU_STEPS;
+ else
+ {
+ int i = (int)(2.0*(peak + IEM_VU_OFFSET));
+ x->x_peak = iemgui_vu_db2i[i];
+ }
+ i = (int)(100.0*peak + 10000.5);
+ peak = 0.01*(float)(i - 10000);
+ x->x_fp = peak;
+ outlet_float(x->x_out_peak, peak);
+ vu_update_peak(x, x->x_gui.x_glist);
+}
+
+static void vu_list(t_vu *x, t_symbol *s, int ac, t_atom *av)
+{
+ int l=iemgui_list((void *)x, &x->x_gui, s, ac, av);
+
+ if(l < 0)
+ {
+ if((IS_A_FLOAT(av,0))&&(IS_A_FLOAT(av,1)))
+ {
+ vu_ft1(x, atom_getfloatarg(1, ac, av));
+ vu_float(x, atom_getfloatarg(0, ac, av));
+ }
+ }
+ else if(l > 0)
+ {
+ (*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_MOVE);
+ canvas_fixlinesfor(glist_getcanvas(x->x_gui.x_glist), (t_text*)x);
+ }
+}
+
+static void vu_bang(t_vu *x)
+{
+ outlet_float(x->x_out_peak, x->x_fp);
+ outlet_float(x->x_out_rms, x->x_fr);
+ vu_update_rms(x, x->x_gui.x_glist);
+ vu_update_peak(x, x->x_gui.x_glist);
+}
+
+static void *vu_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_vu *x = (t_vu *)pd_new(vu_class);
+ int bflcol[]={-66577, -1, -1};
+ t_symbol *srl[3];
+ int w=IEM_GUI_DEFAULTSIZE, h=IEM_VU_STEPS*IEM_VU_DEFAULTSIZE;
+ int ldx=-1, ldy=-8, f=0, fs=8, scale=1;
+ int iinit=0, ifstyle=0;
+ int ftbreak=IEM_BNG_DEFAULTBREAKFLASHTIME, fthold=IEM_BNG_DEFAULTHOLDFLASHTIME;
+ t_iem_init_symargs *init=(t_iem_init_symargs *)(&iinit);
+ t_iem_fstyle_flags *fstyle=(t_iem_fstyle_flags *)(&ifstyle);
+ char str[144];
+
+ srl[0] = gensym("empty");
+ srl[1] = gensym("empty");
+ srl[2] = gensym("empty");
+
+ if((argc >= 11)&&IS_A_FLOAT(argv,0)&&IS_A_FLOAT(argv,1)
+ &&(IS_A_SYMBOL(argv,2)||IS_A_FLOAT(argv,2))
+ &&(IS_A_SYMBOL(argv,3)||IS_A_FLOAT(argv,3))
+ &&IS_A_FLOAT(argv,4)&&IS_A_FLOAT(argv,5)
+ &&IS_A_FLOAT(argv,6)&&IS_A_FLOAT(argv,7)
+ &&IS_A_FLOAT(argv,8)&&IS_A_FLOAT(argv,9)&&IS_A_FLOAT(argv,10))
+ {
+ w = (int)atom_getintarg(0, argc, argv);
+ h = (int)atom_getintarg(1, argc, argv);
+ if(IS_A_SYMBOL(argv,2))
+ srl[1] = atom_getsymbolarg(2, argc, argv);
+ else if(IS_A_FLOAT(argv,2))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(2, argc, argv));
+ srl[1] = gensym(str);
+ }
+ if(IS_A_SYMBOL(argv,3))
+ srl[2] = atom_getsymbolarg(3, argc, argv);
+ else if(IS_A_FLOAT(argv,3))
+ {
+ sprintf(str, "%d", (int)atom_getintarg(3, argc, argv));
+ srl[2] = gensym(str);
+ }
+ ldx = (int)atom_getintarg(4, argc, argv);
+ ldy = (int)atom_getintarg(5, argc, argv);
+ ifstyle = (int)atom_getintarg(6, argc, argv);
+ fs = (int)atom_getintarg(7, argc, argv);
+ bflcol[0] = (int)atom_getintarg(8, argc, argv);
+ bflcol[2] = (int)atom_getintarg(9, argc, argv);
+ scale = (int)atom_getintarg(10, argc, argv);
+ }
+ if((argc == 12)&&IS_A_FLOAT(argv,11))
+ iinit = (int)atom_getintarg(11, argc, argv);
+ x->x_gui.x_draw = (t_iemfunptr)vu_draw;
+ iinit &= IEM_INIT_ARGS_ALL;
+ ifstyle &= IEM_FSTYLE_FLAGS_ALL;
+
+ fstyle->x_snd_able = 0;
+ fstyle->x_rcv_able = 1;
+ x->x_gui.x_glist = (t_glist *)canvas_getcurrent();
+ x->x_gui.x_isa = *init;
+ if(!strcmp(srl[1]->s_name, "empty")) fstyle->x_rcv_able = 0;
+ x->x_gui.x_unique_num = 0;
+ if(fstyle->x_font_style == 1) strcpy(x->x_gui.x_font, "helvetica");
+ else if(fstyle->x_font_style == 2) strcpy(x->x_gui.x_font, "times");
+ else { fstyle->x_font_style = 0;
+ strcpy(x->x_gui.x_font, "courier"); }
+ x->x_gui.x_fsf = *fstyle;
+ iemgui_first_dollararg2sym(&x->x_gui, srl);
+ if(x->x_gui.x_fsf.x_rcv_able) pd_bind(&x->x_gui.x_obj.ob_pd, srl[1]);
+ x->x_gui.x_snd = srl[0];
+ x->x_gui.x_rcv = srl[1];
+ x->x_gui.x_lab = srl[2];
+ x->x_gui.x_ldx = ldx;
+ x->x_gui.x_ldy = ldy;
+
+ if(fs < 4)
+ fs = 4;
+ x->x_gui.x_fontsize = fs;
+ x->x_gui.x_w = iemgui_clip_size(w);
+ vu_check_height(x, h);
+ iemgui_all_colfromload(&x->x_gui, bflcol);
+ if(scale != 0)
+ scale = 1;
+ x->x_scale = scale;
+ x->x_peak = 0;
+ x->x_rms = 0;
+ x->x_fp = -101.0;
+ x->x_fr = -101.0;
+ iemgui_verify_snd_ne_rcv(&x->x_gui);
+ inlet_new(&x->x_gui.x_obj, &x->x_gui.x_obj.ob_pd, &s_float, gensym("ft1"));
+ x->x_out_rms = outlet_new(&x->x_gui.x_obj, &s_float);
+ x->x_out_peak = outlet_new(&x->x_gui.x_obj, &s_float);
+ return (x);
+}
+
+static void vu_free(t_vu *x)
+{
+ if(x->x_gui.x_fsf.x_selected)
+ pd_unbind(&x->x_gui.x_obj.ob_pd, iemgui_key_sym);
+ if(x->x_gui.x_fsf.x_rcv_able)
+ pd_unbind(&x->x_gui.x_obj.ob_pd, x->x_gui.x_rcv);
+ gfxstub_deleteforkey(x);
+}
+
+void g_vumeter_setup(void)
+{
+ vu_class = class_new(gensym("vu"), (t_newmethod)vu_new, (t_method)vu_free,
+ sizeof(t_vu), 0, A_GIMME, 0);
+ class_addbang(vu_class,vu_bang);
+ class_addfloat(vu_class,vu_float);
+ class_addmethod(vu_class, (t_method)vu_ft1, gensym("ft1"), A_FLOAT, 0);
+ class_addlist(vu_class, vu_list);
+ class_addmethod(vu_class, (t_method)vu_dialog, gensym("dialog"),
+ A_GIMME, 0);
+ class_addmethod(vu_class, (t_method)vu_size, gensym("size"), A_GIMME, 0);
+ class_addmethod(vu_class, (t_method)vu_scale, gensym("scale"), A_DEFFLOAT, 0);
+ class_addmethod(vu_class, (t_method)vu_delta, gensym("delta"), A_GIMME, 0);
+ class_addmethod(vu_class, (t_method)vu_pos, gensym("pos"), A_GIMME, 0);
+ class_addmethod(vu_class, (t_method)vu_color, gensym("color"), A_GIMME, 0);
+ class_addmethod(vu_class, (t_method)vu_receive, gensym("receive"), A_DEFSYM, 0);
+ class_addmethod(vu_class, (t_method)vu_label, gensym("label"), A_DEFSYM, 0);
+ class_addmethod(vu_class, (t_method)vu_label_pos, gensym("label_pos"), A_GIMME, 0);
+ class_addmethod(vu_class, (t_method)vu_label_font, gensym("label_font"), A_GIMME, 0);
+ if(!iemgui_key_sym)
+ iemgui_key_sym = gensym("#keyname");
+ vu_widgetbehavior.w_getrectfn = vu_getrect;
+ vu_widgetbehavior.w_displacefn = iemgui_displace;
+ vu_widgetbehavior.w_selectfn = iemgui_select;
+ vu_widgetbehavior.w_activatefn = NULL;
+ vu_widgetbehavior.w_deletefn = iemgui_delete;
+ vu_widgetbehavior.w_visfn = iemgui_vis;
+ vu_widgetbehavior.w_clickfn = NULL;
+ vu_widgetbehavior.w_propertiesfn = vu_properties;
+ vu_widgetbehavior.w_savefn = vu_save;
+ class_setwidget(vu_class,&vu_widgetbehavior);
+ class_sethelpsymbol(vu_class, gensym("vu"));
+}
diff --git a/pd/src/install-sh b/pd/src/install-sh
new file mode 100644
index 00000000..e9de2384
--- /dev/null
+++ b/pd/src/install-sh
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/pd/src/m_atom.c b/pd/src/m_atom.c
new file mode 100644
index 00000000..c9c4c284
--- /dev/null
+++ b/pd/src/m_atom.c
@@ -0,0 +1,129 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_imp.h"
+#include <stdio.h>
+#include <string.h>
+
+ /* convenience routines for checking and getting values of
+ atoms. There's no "pointer" version since there's nothing
+ safe to return if there's an error. */
+
+t_float atom_getfloat(t_atom *a)
+{
+ if (a->a_type == A_FLOAT) return (a->a_w.w_float);
+ else return (0);
+}
+
+t_int atom_getint(t_atom *a)
+{
+ return (atom_getfloat(a));
+}
+
+t_symbol *atom_getsymbol(t_atom *a) /* LATER think about this more carefully */
+{
+ char buf[30];
+ if (a->a_type == A_SYMBOL) return (a->a_w.w_symbol);
+ else return (&s_float);
+}
+
+t_symbol *atom_gensym(t_atom *a) /* this works better for graph labels */
+{
+ char buf[30];
+ if (a->a_type == A_SYMBOL) return (a->a_w.w_symbol);
+ else if (a->a_type == A_FLOAT)
+ sprintf(buf, "%g", a->a_w.w_float);
+ else strcpy(buf, "???");
+ return (gensym(buf));
+}
+
+t_float atom_getfloatarg(int which, int argc, t_atom *argv)
+{
+ if (argc <= which) return (0);
+ argv += which;
+ if (argv->a_type == A_FLOAT) return (argv->a_w.w_float);
+ else return (0);
+}
+
+t_int atom_getintarg(int which, int argc, t_atom *argv)
+{
+ return (atom_getfloatarg(which, argc, argv));
+}
+
+t_symbol *atom_getsymbolarg(int which, int argc, t_atom *argv)
+{
+ if (argc <= which) return (&s_);
+ argv += which;
+ if (argv->a_type == A_SYMBOL) return (argv->a_w.w_symbol);
+ else return (&s_);
+}
+
+/* convert an atom into a string, in the reverse sense of binbuf_text (q.v.)
+* special attention is paid to symbols containing the special characters
+* ';', ',', '$', and '\'; these are quoted with a preceding '\', except that
+* the '$' only gets quoted at the beginning of the string.
+*/
+
+void atom_string(t_atom *a, char *buf, unsigned int bufsize)
+{
+ char tbuf[30];
+ switch(a->a_type)
+ {
+ case A_SEMI: strcpy(buf, ";"); break;
+ case A_COMMA: strcpy(buf, ","); break;
+ case A_POINTER:
+ strcpy(buf, "(pointer)");
+ break;
+ case A_FLOAT:
+ sprintf(tbuf, "%g", a->a_w.w_float);
+ if (strlen(tbuf) < bufsize-1) strcpy(buf, tbuf);
+ else if (a->a_w.w_float < 0) strcpy(buf, "-");
+ else strcat(buf, "+");
+ break;
+ case A_SYMBOL:
+ {
+ char *sp;
+ unsigned int len;
+ int quote;
+ for (sp = a->a_w.w_symbol->s_name, len = 0, quote = 0; *sp; sp++, len++)
+ if (*sp == ';' || *sp == ',' || *sp == '\\' ||
+ (*sp == '$' && sp == a->a_w.w_symbol->s_name && sp[1] >= '0'
+ && sp[1] <= '9'))
+ quote = 1;
+ if (quote)
+ {
+ char *bp = buf, *ep = buf + (bufsize-2);
+ sp = a->a_w.w_symbol->s_name;
+ while (bp < ep && *sp)
+ {
+ if (*sp == ';' || *sp == ',' || *sp == '\\' ||
+ (*sp == '$' && bp == buf && sp[1] >= '0' && sp[1] <= '9'))
+ *bp++ = '\\';
+ *bp++ = *sp++;
+ }
+ if (*sp) *bp++ = '*';
+ *bp = 0;
+ /* post("quote %s -> %s", a->a_w.w_symbol->s_name, buf); */
+ }
+ else
+ {
+ if (len < bufsize-1) strcpy(buf, a->a_w.w_symbol->s_name);
+ else
+ {
+ strncpy(buf, a->a_w.w_symbol->s_name, bufsize - 2);
+ strcpy(buf + (bufsize - 2), "*");
+ }
+ }
+ }
+ break;
+ case A_DOLLAR:
+ sprintf(buf, "$%d", a->a_w.w_index);
+ break;
+ case A_DOLLSYM:
+ sprintf(buf, "$%s", a->a_w.w_symbol->s_name);
+ break;
+ default:
+ bug("atom_string");
+ }
+}
diff --git a/pd/src/m_binbuf.c b/pd/src/m_binbuf.c
new file mode 100644
index 00000000..6ff79e93
--- /dev/null
+++ b/pd/src/m_binbuf.c
@@ -0,0 +1,1138 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+
+/* IOhannes :
+ * changed the canvas_restore in "g_canvas.c", so that it might accept $args as well (like "pd $0_test")
+ * so you can make multiple & distinguishable templates
+ * 1511:forum::für::umläute:2001
+ * change marked with IOhannes
+ */
+
+#include <stdlib.h>
+#include "m_pd.h"
+#include <stdio.h>
+#ifdef UNIX
+#include <unistd.h>
+#endif
+#ifdef NT
+#include <io.h>
+#endif
+#include <fcntl.h>
+#include <string.h>
+#include <stdarg.h>
+
+struct _binbuf
+{
+ int b_n;
+ t_atom *b_vec;
+};
+
+t_binbuf *binbuf_new(void)
+{
+ t_binbuf *x = (t_binbuf *)t_getbytes(sizeof(*x));
+ x->b_n = 0;
+ x->b_vec = t_getbytes(0);
+ return (x);
+}
+
+void binbuf_free(t_binbuf *x)
+{
+ t_freebytes(x->b_vec, x->b_n * sizeof(*x->b_vec));
+ t_freebytes(x, sizeof(*x));
+}
+
+void binbuf_clear(t_binbuf *x)
+{
+ x->b_vec = t_resizebytes(x->b_vec, x->b_n * sizeof(*x->b_vec), 0);
+ x->b_n = 0;
+}
+
+ /* convert text to a binbuf */
+void binbuf_text(t_binbuf *x, char *text, size_t size)
+{
+ char buf[MAXPDSTRING+1], *bufp, *ebuf = buf+MAXPDSTRING;
+ const char *textp = text, *etext = text+size;
+ t_atom *ap;
+ int nalloc = 16, natom = 0;
+ t_freebytes(x->b_vec, x->b_n * sizeof(*x->b_vec));
+ x->b_vec = t_getbytes(nalloc * sizeof(*x->b_vec));
+ ap = x->b_vec;
+ x->b_n = 0;
+ while (1)
+ {
+ int type;
+ /* skip leading space */
+ while ((textp != etext) && (*textp == ' ' || *textp == '\n'
+ || *textp == '\r' || *textp == '\t')) textp++;
+ if (textp == etext) break;
+ if (*textp == ';') SETSEMI(ap), textp++;
+ else if (*textp == ',') SETCOMMA(ap), textp++;
+ else
+ {
+ /* it's an atom other than a comma or semi */
+ char c;
+ int floatstate = 0, slash = 0, lastslash = 0,
+ firstslash = (*textp == '\\');
+ bufp = buf;
+ do
+ {
+ c = *bufp = *textp++;
+ lastslash = slash;
+ slash = (c == '\\');
+
+ if (floatstate >= 0)
+ {
+ int digit = (c >= '0' && c <= '9'),
+ dot = (c == '.'), minus = (c == '-'),
+ plusminus = (minus || (c == '+')),
+ expon = (c == 'e' || c == 'E');
+ if (floatstate == 0) /* beginning */
+ {
+ if (minus) floatstate = 1;
+ else if (digit) floatstate = 2;
+ else if (dot) floatstate = 3;
+ else floatstate = -1;
+ }
+ else if (floatstate == 1) /* got minus */
+ {
+ if (digit) floatstate = 2;
+ else if (dot) floatstate = 3;
+ else floatstate = -1;
+ }
+ else if (floatstate == 2) /* got digits */
+ {
+ if (dot) floatstate = 4;
+ else if (expon) floatstate = 6;
+ else if (!digit) floatstate = -1;
+ }
+ else if (floatstate == 3) /* got '.' without digits */
+ {
+ if (digit) floatstate = 5;
+ else floatstate = -1;
+ }
+ else if (floatstate == 4) /* got '.' after digits */
+ {
+ if (digit) floatstate = 5;
+ else if (expon) floatstate = 6;
+ else floatstate = -1;
+ }
+ else if (floatstate == 5) /* got digits after . */
+ {
+ if (expon) floatstate = 6;
+ else if (!digit) floatstate = -1;
+ }
+ else if (floatstate == 6) /* got 'e' */
+ {
+ if (plusminus) floatstate = 7;
+ else if (digit) floatstate = 8;
+ else floatstate = -1;
+ }
+ else if (floatstate == 7) /* got plus or minus */
+ {
+ if (digit) floatstate = 8;
+ else floatstate = -1;
+ }
+ else if (floatstate == 8) /* got digits */
+ {
+ if (!digit) floatstate = -1;
+ }
+ }
+ if (!slash) bufp++;
+ }
+ while (textp != etext && bufp != ebuf &&
+ (slash || (*textp != ' ' && *textp != '\n' && *textp != '\r'
+ && *textp != '\t' &&*textp != ',' && *textp != ';')));
+ *bufp = 0;
+#if 0
+ post("buf %s", buf);
+#endif
+ if (*buf == '$' && buf[1] >= '0' && buf[1] <= '9' && !firstslash)
+ {
+ for (bufp = buf+2; *bufp; bufp++)
+ if (*bufp < '0' || *bufp > '9')
+ {
+ SETDOLLSYM(ap, gensym(buf+1));
+ goto didit;
+ }
+ SETDOLLAR(ap, atoi(buf+1));
+ didit: ;
+ }
+ else
+ {
+ if (floatstate == 2 || floatstate == 4 || floatstate == 5 ||
+ floatstate == 8)
+ SETFLOAT(ap, atof(buf));
+ else SETSYMBOL(ap, gensym(buf));
+ }
+ }
+ ap++;
+ natom++;
+ if (natom == nalloc)
+ {
+ x->b_vec = t_resizebytes(x->b_vec, nalloc * sizeof(*x->b_vec),
+ nalloc * (2*sizeof(*x->b_vec)));
+ nalloc = nalloc * 2;
+ ap = x->b_vec + natom;
+ }
+ if (textp == etext) break;
+ }
+ /* reallocate the vector to exactly the right size */
+ x->b_vec = t_resizebytes(x->b_vec, nalloc * sizeof(*x->b_vec),
+ natom * sizeof(*x->b_vec));
+ x->b_n = natom;
+}
+
+ /* convert a binbuf to text; no null termination. */
+void binbuf_gettext(t_binbuf *x, char **bufp, int *lengthp)
+{
+ char *buf = getbytes(0), *newbuf;
+ int length = 0;
+ char string[MAXPDSTRING];
+ t_atom *ap;
+ int indx;
+
+ for (ap = x->b_vec, indx = x->b_n; indx--; ap++)
+ {
+ int newlength;
+ if ((ap->a_type == A_SEMI || ap->a_type == A_COMMA) &&
+ length && buf[length-1] == ' ') length--;
+ atom_string(ap, string, MAXPDSTRING);
+ newlength = length + strlen(string) + 1;
+ if (!(newbuf = resizebytes(buf, length, newlength))) break;
+ buf = newbuf;
+ strcpy(buf + length, string);
+ length = newlength;
+ if (ap->a_type == A_SEMI) buf[length-1] = '\n';
+ else buf[length-1] = ' ';
+ }
+ if (length && buf[length-1] == ' ')
+ {
+ if (newbuf = t_resizebytes(buf, length, length-1))
+ {
+ buf = newbuf;
+ length--;
+ }
+ }
+ *bufp = buf;
+ *lengthp = length;
+}
+
+/* LATER improve the out-of-space behavior below. Also fix this so that
+writing to file doesn't buffer everything together. */
+
+void binbuf_add(t_binbuf *x, int argc, t_atom *argv)
+{
+ int newsize = x->b_n + argc, i;
+ t_atom *ap;
+ if (ap = t_resizebytes(x->b_vec, x->b_n * sizeof(*x->b_vec),
+ newsize * sizeof(*x->b_vec)))
+ x->b_vec = ap;
+ else
+ {
+ error("binbuf_addmessage: out of space");
+ return;
+ }
+#if 0
+ startpost("binbuf_add: ");
+ postatom(argc, argv);
+ endpost();
+#endif
+ for (ap = x->b_vec + x->b_n, i = argc; i--; ap++)
+ *ap = *(argv++);
+ x->b_n = newsize;
+}
+
+#define MAXADDMESSV 100
+void binbuf_addv(t_binbuf *x, char *fmt, ...)
+{
+ va_list ap;
+ t_atom arg[MAXADDMESSV], *at =arg;
+ int nargs = 0;
+ char *fp = fmt;
+
+ va_start(ap, fmt);
+ while (1)
+ {
+ if (nargs >= MAXADDMESSV)
+ {
+ error("binbuf_addmessv: only %d allowed", MAXADDMESSV);
+ break;
+ }
+ switch(*fp++)
+ {
+ case 'i': SETFLOAT(at, va_arg(ap, t_int)); break;
+ case 'f': SETFLOAT(at, va_arg(ap, double)); break;
+ case 's': SETSYMBOL(at, va_arg(ap, t_symbol *)); break;
+ case ';': SETSEMI(at); break;
+ case ',': SETCOMMA(at); break;
+ default: goto done;
+ }
+ at++;
+ nargs++;
+ }
+done:
+ va_end(ap);
+ binbuf_add(x, nargs, arg);
+}
+
+/* add a binbuf to another one for saving. Semicolons and commas go to
+symbols ";", "'",; the symbol ";" goes to "\;", etc. */
+
+void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y)
+{
+ t_binbuf *z = binbuf_new();
+ int i;
+ t_atom *ap;
+ binbuf_add(z, y->b_n, y->b_vec);
+ for (i = 0, ap = z->b_vec; i < z->b_n; i++, ap++)
+ {
+ char tbuf[MAXPDSTRING];
+ switch (ap->a_type)
+ {
+ case A_FLOAT:
+ break;
+ case A_SEMI:
+ SETSYMBOL(ap, gensym(";"));
+ break;
+ case A_COMMA:
+ SETSYMBOL(ap, gensym(","));
+ break;
+ case A_DOLLAR:
+ sprintf(tbuf, "$%d", ap->a_w.w_index);
+ SETSYMBOL(ap, gensym(tbuf));
+ break;
+ case A_DOLLSYM:
+ sprintf(tbuf, "$%s", ap->a_w.w_symbol->s_name);
+ SETSYMBOL(ap, gensym(tbuf));
+ break;
+ case A_SYMBOL:
+ /* FIXME make this general */
+ if (!strcmp(ap->a_w.w_symbol->s_name, ";"))
+ SETSYMBOL(ap, gensym(";"));
+ else if (!strcmp(ap->a_w.w_symbol->s_name, ","))
+ SETSYMBOL(ap, gensym(","));
+ break;
+ default:
+ bug("binbuf_addbinbuf");
+ }
+ }
+
+ binbuf_add(x, z->b_n, z->b_vec);
+}
+
+void binbuf_addsemi(t_binbuf *x)
+{
+ t_atom a;
+ SETSEMI(&a);
+ binbuf_add(x, 1, &a);
+}
+
+/* Supply atoms to a binbuf from a message, making the opposite changes
+from binbuf_addbinbuf. The symbol ";" goes to a semicolon, etc. */
+
+void binbuf_restore(t_binbuf *x, int argc, t_atom *argv)
+{
+ int newsize = x->b_n + argc, i;
+ t_atom *ap;
+ if (ap = t_resizebytes(x->b_vec, x->b_n * sizeof(*x->b_vec),
+ newsize * sizeof(*x->b_vec)))
+ x->b_vec = ap;
+ else
+ {
+ error("binbuf_addmessage: out of space");
+ return;
+ }
+
+ for (ap = x->b_vec + x->b_n, i = argc; i--; ap++)
+ {
+ if (argv->a_type == A_SYMBOL)
+ {
+ char *str = argv->a_w.w_symbol->s_name;
+ if (!strcmp(str, ";")) SETSEMI(ap);
+ else if (!strcmp(str, ",")) SETCOMMA(ap);
+ else if (str[0] == '$' && str[1] >= '0' && str[1] <= '9')
+ {
+ int dollsym = 0;
+ char *str2;
+ for (str2 = str + 2; *str2; str2++)
+ if (*str2 < '0' || *str2 > '9')
+ dollsym = 1;
+ if (dollsym)
+ SETDOLLSYM(ap, gensym(str + 1));
+ else
+ {
+ int dollar = 0;
+ sscanf(argv->a_w.w_symbol->s_name + 1, "%d", &dollar);
+ SETDOLLAR(ap, dollar);
+ }
+ }
+ else *ap = *argv;
+ argv++;
+ }
+ else *ap = *(argv++);
+ }
+ x->b_n = newsize;
+}
+
+
+#define MSTACKSIZE 2048
+
+void binbuf_print(t_binbuf *x)
+{
+ int i, startedpost = 0, newline = 1;
+ for (i = 0; i < x->b_n; i++)
+ {
+ if (newline)
+ {
+ if (startedpost) endpost();
+ startpost("");
+ startedpost = 1;
+ }
+ postatom(1, x->b_vec + i);
+ if (x->b_vec[i].a_type == A_SEMI)
+ newline = 1;
+ else newline = 0;
+ }
+ if (startedpost) endpost();
+}
+
+int binbuf_getnatom(t_binbuf *x)
+{
+ return (x->b_n);
+}
+
+t_atom *binbuf_getvec(t_binbuf *x)
+{
+ return (x->b_vec);
+}
+
+int canvas_getdollarzero( void);
+
+t_symbol *realizedollsym(t_symbol *s, int ac, t_atom *av, int tonew) /* IOhannes: not static any more */
+{
+ int argno = atol(s->s_name), lastnum;
+ char buf[MAXPDSTRING], c, *sp;
+ for (lastnum = 0, sp = s->s_name; ((c = *sp) && c >= '0' && c <= '9');
+ sp++, lastnum++)
+ if (!c || argno < 0 || argno > ac)
+ {
+ if (!tonew)
+ return (0);
+ else sprintf(buf, "$%d", argno);
+ }
+ else if (argno == 0)
+ sprintf(buf, "%d", canvas_getdollarzero());
+ else
+ atom_string(av+(argno-1), buf, MAXPDSTRING/2-1);
+ strncat(buf, sp, MAXPDSTRING/2-1);
+ return (gensym(buf));
+}
+
+void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv)
+{
+ static t_atom mstack[MSTACKSIZE], *msp = mstack, *ems = mstack+MSTACKSIZE;
+ t_atom *stackwas = msp;
+ t_atom *at = x->b_vec;
+ int ac = x->b_n;
+ int nargs;
+
+ while (1)
+ {
+ t_pd *nexttarget;
+ /* get a target. */
+ while (!target)
+ {
+ t_symbol *s;
+ while (ac && (at->a_type == A_SEMI || at->a_type == A_COMMA))
+ ac--, at++;
+ if (!ac) break;
+ if (at->a_type == A_DOLLAR)
+ {
+ if (at->a_w.w_index <= 0 || at->a_w.w_index > argc)
+ {
+ error("$%d: not enough arguments supplied",
+ at->a_w.w_index);
+ goto cleanup;
+ }
+ else if (argv[at->a_w.w_index-1].a_type != A_SYMBOL)
+ {
+ error("$%d: symbol needed as message destination",
+ at->a_w.w_index);
+ goto cleanup;
+ }
+ else s = argv[at->a_w.w_index-1].a_w.w_symbol;
+ }
+ else if (at->a_type == A_DOLLSYM)
+ {
+ if (!(s = realizedollsym(at->a_w.w_symbol, argc, argv, 0)))
+ {
+ error("$%s: not enough arguments supplied",
+ at->a_w.w_symbol->s_name);
+ goto cleanup;
+ }
+ }
+ else s = atom_getsymbol(at);
+ if (!(target = s->s_thing))
+ {
+ error("%s: no such object", s->s_name);
+ cleanup:
+ do at++, ac--;
+ while (ac && at->a_type != A_SEMI);
+ /* LATER eat args until semicolon and continue */
+ continue;
+ }
+ else
+ {
+ at++, ac--;
+ break;
+ }
+ }
+ if (!ac) break;
+ nargs = 0;
+ nexttarget = target;
+ while (1)
+ {
+ t_symbol *s9;
+ if (!ac) goto gotmess;
+ if (msp >= ems)
+ {
+ error("message stack overflow");
+ goto broken;
+ }
+ switch (at->a_type)
+ {
+ case A_SEMI:
+ /* semis and commas in new message just get bashed to
+ a symbol. This is needed so you can pass them to "expr." */
+ if (target == &pd_objectmaker)
+ {
+ SETSYMBOL(msp, gensym(";"));
+ break;
+ }
+ else
+ {
+ nexttarget = 0;
+ goto gotmess;
+ }
+ case A_COMMA:
+ if (target == &pd_objectmaker)
+ {
+ SETSYMBOL(msp, gensym(","));
+ break;
+ }
+ else goto gotmess;
+ case A_FLOAT:
+ case A_SYMBOL:
+ *msp = *at;
+ break;
+ case A_DOLLAR:
+ if (at->a_w.w_index > 0 && at->a_w.w_index <= argc)
+ *msp = argv[at->a_w.w_index-1];
+ else if (at->a_w.w_index == 0)
+ SETFLOAT(msp, canvas_getdollarzero());
+ else
+ {
+ if (target == &pd_objectmaker)
+ SETFLOAT(msp, 0);
+ else
+ {
+ error("$%d: argument number out of range",
+ at->a_w.w_index);
+ SETFLOAT(msp, 0);
+ }
+ }
+ break;
+ case A_DOLLSYM:
+ s9 = realizedollsym(at->a_w.w_symbol, argc, argv,
+ target == &pd_objectmaker);
+ if (!s9)
+ goto broken;
+ SETSYMBOL(msp, s9);
+ break;
+ default:
+ bug("bad item in binbuf");
+ goto broken;
+ }
+ msp++;
+ ac--;
+ at++;
+ nargs++;
+ }
+ gotmess:
+ if (nargs)
+ {
+ switch (stackwas->a_type)
+ {
+ case A_SYMBOL:
+ typedmess(target, stackwas->a_w.w_symbol, nargs-1, stackwas+1);
+ break;
+ case A_FLOAT:
+ if (nargs == 1) pd_float(target, stackwas->a_w.w_float);
+ else pd_list(target, 0, nargs, stackwas);
+ break;
+ }
+ }
+ msp = stackwas;
+ if (!ac) break;
+ target = nexttarget;
+ at++;
+ ac--;
+ }
+
+ return;
+broken:
+ msp = stackwas;
+}
+
+static int binbuf_doopen(char *s, int mode)
+{
+ char namebuf[MAXPDSTRING];
+#ifdef NT
+ mode |= O_BINARY;
+#endif
+ sys_bashfilename(s, namebuf);
+ return (open(namebuf, mode));
+}
+
+static FILE *binbuf_dofopen(char *s, char *mode)
+{
+ char namebuf[MAXPDSTRING];
+ sys_bashfilename(s, namebuf);
+ return (fopen(namebuf, mode));
+}
+
+int binbuf_read(t_binbuf *b, char *filename, char *dirname, int crflag)
+{
+ long length;
+ int fd;
+ int readret;
+ char *buf;
+ char namebuf[MAXPDSTRING];
+
+ namebuf[0] = 0;
+ if (*dirname)
+ strcat(namebuf, dirname), strcat(namebuf, "/");
+ strcat(namebuf, filename);
+
+ if ((fd = binbuf_doopen(namebuf, 0)) < 0)
+ {
+ fprintf(stderr, "open: ");
+ perror(namebuf);
+ return (1);
+ }
+ if ((length = lseek(fd, 0, SEEK_END)) < 0 || lseek(fd, 0, SEEK_SET) < 0
+ || !(buf = t_getbytes(length)))
+ {
+ fprintf(stderr, "lseek: ");
+ perror(namebuf);
+ close(fd);
+ return(1);
+ }
+ if ((readret = read(fd, buf, length)) < length)
+ {
+ fprintf(stderr, "read (%d %ld) -> %d\n", fd, length, readret);
+ perror(namebuf);
+ close(fd);
+ t_freebytes(buf, length);
+ return(1);
+ }
+ /* optionally map carriage return to semicolon */
+ if (crflag)
+ {
+ int i;
+ for (i = 0; i < length; i++)
+ if (buf[i] == '\n')
+ buf[i] = ';';
+ }
+ binbuf_text(b, buf, length);
+
+#if 0
+ startpost("binbuf_read "); postatom(b->b_n, b->b_vec); endpost();
+#endif
+
+ t_freebytes(buf, length);
+ close(fd);
+ return (0);
+}
+
+int binbuf_read_via_path(t_binbuf *b, char *filename, char *dirname,
+ int crflag)
+{
+ int filedesc;
+ char buf[MAXPDSTRING], *bufptr;
+ if ((filedesc = open_via_path(
+ dirname, filename, "", buf, &bufptr, MAXPDSTRING, 0)) < 0)
+ {
+ error("%s: can't open", filename);
+ return (1);
+ }
+ else close (filedesc);
+ if (binbuf_read(b, bufptr, buf, crflag))
+ return (1);
+ else return (0);
+}
+
+#define WBUFSIZE 4096
+static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd);
+
+ /* write a binbuf to a text file. If "crflag" is set we suppress
+ semicolons. */
+int binbuf_write(t_binbuf *x, char *filename, char *dir, int crflag)
+{
+ FILE *f = 0;
+ char sbuf[WBUFSIZE], fbuf[MAXPDSTRING], *bp = sbuf, *ep = sbuf + WBUFSIZE;
+ t_atom *ap;
+ int indx, deleteit = 0;
+ int ncolumn = 0;
+
+ fbuf[0] = 0;
+ if (*dir)
+ strcat(fbuf, dir), strcat(fbuf, "/");
+ strcat(fbuf, filename);
+ if (!strcmp(filename + strlen(filename) - 4, ".pat"))
+ {
+ x = binbuf_convert(x, 0);
+ deleteit = 1;
+ }
+
+ if (!(f = binbuf_dofopen(fbuf, "w")))
+ {
+ fprintf(stderr, "open: ");
+ sys_unixerror(fbuf);
+ goto fail;
+ }
+ for (ap = x->b_vec, indx = x->b_n; indx--; ap++)
+ {
+ int length;
+ /* estimate how many characters will be needed. Printing out
+ symbols may need extra characters for inserting backslashes. */
+ if (ap->a_type == A_SYMBOL || ap->a_type == A_DOLLSYM)
+ length = 80 + strlen(ap->a_w.w_symbol->s_name);
+ else length = 40;
+ if (ep - bp < length)
+ {
+ if (fwrite(sbuf, bp-sbuf, 1, f) < 1)
+ {
+ sys_unixerror(fbuf);
+ goto fail;
+ }
+ bp = sbuf;
+ }
+ if ((ap->a_type == A_SEMI || ap->a_type == A_COMMA) &&
+ bp > sbuf && bp[-1] == ' ') bp--;
+ if (!crflag || ap->a_type != A_SEMI)
+ {
+ atom_string(ap, bp, (ep-bp)-2);
+ length = strlen(bp);
+ bp += length;
+ ncolumn += length;
+ }
+ if (ap->a_type == A_SEMI || ncolumn > 65)
+ {
+ *bp++ = '\n';
+ ncolumn = 0;
+ }
+ else
+ {
+ *bp++ = ' ';
+ ncolumn++;
+ }
+ }
+ if (fwrite(sbuf, bp-sbuf, 1, f) < 1)
+ {
+ sys_unixerror(fbuf);
+ goto fail;
+ }
+ if (deleteit)
+ binbuf_free(x);
+ fclose(f);
+ return (0);
+fail:
+ if (deleteit)
+ binbuf_free(x);
+ if (f)
+ fclose(f);
+ return (1);
+}
+
+/* The following routine attempts to convert from max to pd or back. The
+max to pd direction is working OK but you will need to make lots of
+abstractions for objects like "gate" which don't exist in Pd. conversion
+from Pd to Max hasn't been tested for patches with subpatches yet! */
+
+#define MAXSTACK 1000
+
+#define ISSYMBOL(a, b) ((a)->a_type == A_SYMBOL && \
+ !strcmp((a)->a_w.w_symbol->s_name, (b)))
+
+static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd)
+{
+ t_binbuf *newb = binbuf_new();
+ t_atom *vec = oldb->b_vec;
+ t_int n = oldb->b_n, nextindex, stackdepth = 0, stack[MAXSTACK],
+ nobj = 0, i;
+ t_atom outmess[MAXSTACK], *nextmess;
+ if (!maxtopd)
+ binbuf_addv(newb, "ss;", gensym("max"), gensym("v2"));
+ for (nextindex = 0; nextindex < n; )
+ {
+ int endmess, natom;
+ char *first, *second;
+ for (endmess = nextindex; endmess < n && vec[endmess].a_type != A_SEMI;
+ endmess++)
+ ;
+ if (endmess == n) break;
+ if (endmess == nextindex || endmess == nextindex + 1
+ || vec[nextindex].a_type != A_SYMBOL ||
+ vec[nextindex+1].a_type != A_SYMBOL)
+ {
+ nextindex = endmess + 1;
+ continue;
+ }
+ natom = endmess - nextindex;
+ if (natom > MAXSTACK-10) natom = MAXSTACK-10;
+ nextmess = vec + nextindex;
+ first = nextmess->a_w.w_symbol->s_name;
+ second = (nextmess+1)->a_w.w_symbol->s_name;
+ if (maxtopd)
+ {
+ /* case 1: importing a ".pat" file into Pd. */
+
+ /* dollar signs in file translate to symbols */
+ for (i = 0; i < natom; i++)
+ {
+ if (nextmess[i].a_type == A_DOLLAR)
+ {
+ char buf[100];
+ sprintf(buf, "$%d", nextmess[i].a_w.w_index);
+ SETSYMBOL(nextmess+i, gensym(buf));
+ }
+ else if (nextmess[i].a_type == A_DOLLSYM)
+ {
+ char buf[100];
+ sprintf(buf, "$%s", nextmess[i].a_w.w_symbol->s_name);
+ SETSYMBOL(nextmess+i, gensym(buf));
+ }
+ }
+ if (!strcmp(first, "#N"))
+ {
+ if (!strcmp(second, "vpatcher"))
+ {
+ if (stackdepth >= MAXSTACK)
+ {
+ post("too many embedded patches");
+ return (newb);
+ }
+ stack[stackdepth] = nobj;
+ stackdepth++;
+ nobj = 0;
+ binbuf_addv(newb, "ssfffff;",
+ gensym("#N"), gensym("canvas"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ atom_getfloatarg(4, natom, nextmess) -
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(5, natom, nextmess) -
+ atom_getfloatarg(3, natom, nextmess),
+ 12.);
+ }
+ }
+ if (!strcmp(first, "#P"))
+ {
+ if (natom >= 7 && !strcmp(second, "newobj")
+ && (ISSYMBOL(&nextmess[6], "patcher") ||
+ ISSYMBOL(&nextmess[6], "p")))
+ {
+ binbuf_addv(newb, "ssffss;",
+ gensym("#X"), gensym("restore"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ gensym("pd"), atom_getsymbolarg(7, natom, nextmess));
+ if (stackdepth) stackdepth--;
+ nobj = stack[stackdepth];
+ nobj++;
+ }
+ else if (!strcmp(second, "newex") || !strcmp(second, "newobj"))
+ {
+ t_symbol *classname =
+ atom_getsymbolarg(6, natom, nextmess);
+ if (classname == gensym("trigger") ||
+ classname == gensym("t"))
+ {
+ for (i = 7; i < natom; i++)
+ if (nextmess[i].a_type == A_SYMBOL &&
+ nextmess[i].a_w.w_symbol == gensym("i"))
+ nextmess[i].a_w.w_symbol = gensym("f");
+ }
+ SETSYMBOL(outmess, gensym("#X"));
+ SETSYMBOL(outmess + 1, gensym("obj"));
+ outmess[2] = nextmess[2];
+ outmess[3] = nextmess[3];
+ for (i = 6; i < natom; i++)
+ outmess[i-2] = nextmess[i];
+ SETSEMI(outmess + natom - 2);
+ binbuf_add(newb, natom - 1, outmess);
+ nobj++;
+ }
+ else if (!strcmp(second, "message") ||
+ !strcmp(second, "comment"))
+ {
+ SETSYMBOL(outmess, gensym("#X"));
+ SETSYMBOL(outmess + 1, gensym(
+ (strcmp(second, "message") ? "text" : "msg")));
+ outmess[2] = nextmess[2];
+ outmess[3] = nextmess[3];
+ for (i = 6; i < natom; i++)
+ outmess[i-2] = nextmess[i];
+ SETSEMI(outmess + natom - 2);
+ binbuf_add(newb, natom - 1, outmess);
+ nobj++;
+ }
+ else if (!strcmp(second, "button"))
+ {
+ binbuf_addv(newb, "ssffs;",
+ gensym("#X"), gensym("msg"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ gensym("bang"));
+ nobj++;
+ }
+ else if (!strcmp(second, "slider") || !strcmp(second, "number")
+ || !strcmp(second, "flonum") || !strcmp(second, "toggle"))
+ {
+ binbuf_addv(newb, "ssff;",
+ gensym("#X"), gensym("floatatom"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess));
+ nobj++;
+ }
+ else if (!strcmp(second, "inlet"))
+ {
+ binbuf_addv(newb, "ssffs;",
+ gensym("#X"), gensym("obj"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ gensym((natom > 5 ? "inlet~" : "inlet")));
+ nobj++;
+ }
+ else if (!strcmp(second, "outlet"))
+ {
+ binbuf_addv(newb, "ssffs;",
+ gensym("#X"), gensym("obj"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ gensym((natom > 5 ? "outlet~" : "outlet")));
+ nobj++;
+ }
+ else if (!strcmp(second, "connect")||
+ !strcmp(second, "fasten"))
+ {
+ binbuf_addv(newb, "ssffff;",
+ gensym("#X"), gensym("connect"),
+ nobj - atom_getfloatarg(2, natom, nextmess) - 1,
+ atom_getfloatarg(3, natom, nextmess),
+ nobj - atom_getfloatarg(4, natom, nextmess) - 1,
+ atom_getfloatarg(5, natom, nextmess));
+ }
+ }
+ }
+ else /* Pd to Max */
+ {
+ if (!strcmp(first, "#N"))
+ {
+ if (!strcmp(second, "canvas"))
+ {
+ if (stackdepth >= MAXSTACK)
+ {
+ post("too many embedded patches");
+ return (newb);
+ }
+ stack[stackdepth] = nobj;
+ stackdepth++;
+ nobj = 0;
+ binbuf_addv(newb, "ssffff;",
+ gensym("#N"), gensym("vpatcher"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ atom_getfloatarg(4, natom, nextmess),
+ atom_getfloatarg(5, natom, nextmess));
+ }
+ }
+ if (!strcmp(first, "#X"))
+ {
+ if (natom >= 5 && !strcmp(second, "restore")
+ && (ISSYMBOL (&nextmess[4], "pd")))
+ {
+ binbuf_addv(newb, "ss;", gensym("#P"), gensym("pop"));
+ binbuf_addv(newb, "ssffffss;",
+ gensym("#P"), gensym("newobj"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess), 50., 1.,
+ gensym("patcher"),
+ atom_getsymbolarg(5, natom, nextmess));
+ if (stackdepth) stackdepth--;
+ nobj = stack[stackdepth];
+ nobj++;
+ }
+ else if (!strcmp(second, "obj"))
+ {
+ t_symbol *classname =
+ atom_getsymbolarg(4, natom, nextmess);
+ if (classname == gensym("inlet"))
+ binbuf_addv(newb, "ssfff;", gensym("#P"),
+ gensym("inlet"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ 15.);
+ else if (classname == gensym("inlet~"))
+ binbuf_addv(newb, "ssffff;", gensym("#P"),
+ gensym("inlet"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ 15., 1.);
+ else if (classname == gensym("outlet"))
+ binbuf_addv(newb, "ssfff;", gensym("#P"),
+ gensym("outlet"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ 15.);
+ else if (classname == gensym("outlet~"))
+ binbuf_addv(newb, "ssffff;", gensym("#P"),
+ gensym("outlet"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ 15., 1.);
+ else
+ {
+ SETSYMBOL(outmess, gensym("#P"));
+ SETSYMBOL(outmess + 1, gensym("newex"));
+ outmess[2] = nextmess[2];
+ outmess[3] = nextmess[3];
+ SETFLOAT(outmess + 4, 50);
+ SETFLOAT(outmess + 5, 1);
+ for (i = 4; i < natom; i++)
+ outmess[i+2] = nextmess[i];
+ SETSEMI(outmess + natom + 2);
+ binbuf_add(newb, natom + 3, outmess);
+ }
+ nobj++;
+
+ }
+ else if (!strcmp(second, "msg") ||
+ !strcmp(second, "text"))
+ {
+ SETSYMBOL(outmess, gensym("#P"));
+ SETSYMBOL(outmess + 1, gensym(
+ (strcmp(second, "msg") ? "comment" : "message")));
+ outmess[2] = nextmess[2];
+ outmess[3] = nextmess[3];
+ SETFLOAT(outmess + 4, 50);
+ SETFLOAT(outmess + 5, 1);
+ for (i = 4; i < natom; i++)
+ outmess[i+2] = nextmess[i];
+ SETSEMI(outmess + natom + 2);
+ binbuf_add(newb, natom + 3, outmess);
+ nobj++;
+ }
+ else if (!strcmp(second, "floatatom"))
+ {
+ binbuf_addv(newb, "ssfff;",
+ gensym("#P"), gensym("flonum"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess), 35);
+ nobj++;
+ }
+ else if (!strcmp(second, "connect"))
+ {
+ binbuf_addv(newb, "ssffff;",
+ gensym("#P"), gensym("connect"),
+ nobj - atom_getfloatarg(2, natom, nextmess) - 1,
+ atom_getfloatarg(3, natom, nextmess),
+ nobj - atom_getfloatarg(4, natom, nextmess) - 1,
+ atom_getfloatarg(5, natom, nextmess));
+ }
+ }
+ }
+ nextindex = endmess + 1;
+ }
+ if (!maxtopd)
+ binbuf_addv(newb, "ss;", gensym("#P"), gensym("pop"));
+#if 1
+ binbuf_write(newb, "import-result.pd", "/tmp", 0);
+#endif
+ return (newb);
+}
+
+ /* function to support searching */
+int binbuf_match(t_binbuf *inbuf, t_binbuf *searchbuf)
+{
+ int indexin, nmatched;
+ for (indexin = 0; indexin <= inbuf->b_n - searchbuf->b_n; indexin++)
+ {
+ for (nmatched = 0; nmatched < searchbuf->b_n; nmatched++)
+ {
+ t_atom *a1 = &inbuf->b_vec[indexin + nmatched],
+ *a2 = &searchbuf->b_vec[nmatched];
+ if (a1->a_type != a2->a_type ||
+ a1->a_type == A_SYMBOL && a1->a_w.w_symbol != a2->a_w.w_symbol
+ ||
+ a1->a_type == A_FLOAT && a1->a_w.w_float != a2->a_w.w_float
+ ||
+ a1->a_type == A_DOLLAR && a1->a_w.w_index != a2->a_w.w_index
+ ||
+ a1->a_type == A_DOLLSYM && a1->a_w.w_symbol != a2->a_w.w_symbol)
+ goto nomatch;
+ }
+ return (1);
+ nomatch: ;
+ }
+ return (0);
+}
+
+void pd_doloadbang(void);
+
+/* LATER make this evaluate the file on-the-fly. */
+/* LATER figure out how to log errors */
+void binbuf_evalfile(t_symbol *name, t_symbol *dir)
+{
+ t_binbuf *b = binbuf_new();
+ int import = !strcmp(name->s_name + strlen(name->s_name) - 4, ".pat");
+ /* set filename so that new canvases can pick them up */
+ int dspstate = canvas_suspend_dsp();
+ glob_setfilename(0, name, dir);
+ if (binbuf_read(b, name->s_name, dir->s_name, 0))
+ {
+ perror(name->s_name);
+ }
+ else
+ {
+ if (import)
+ {
+ t_binbuf *newb = binbuf_convert(b, 1);
+ binbuf_free(b);
+ b = newb;
+ }
+ binbuf_eval(b, 0, 0, 0);
+ }
+ glob_setfilename(0, &s_, &s_); /* bug fix by Krzysztof Czaja */
+ binbuf_free(b);
+ canvas_resume_dsp(dspstate);
+}
+
+void glob_evalfile(t_pd *ignore, t_symbol *name, t_symbol *dir)
+{
+ t_pd *x = 0;
+ /* even though binbuf_evalfile appears to take care of dspstate,
+ we have to do it again here, because canvas_startdsp() assumes
+ that all toplevel canvases are visible. LATER check if this
+ is still necessary -- probably not. */
+
+ int dspstate = canvas_suspend_dsp();
+ binbuf_evalfile(name, dir);
+ while ((x != s__X.s_thing) && (x = s__X.s_thing))
+ vmess(x, gensym("pop"), "i", 1);
+ pd_doloadbang();
+ canvas_resume_dsp(dspstate);
+}
diff --git a/pd/src/m_class.c b/pd/src/m_class.c
new file mode 100644
index 00000000..9d6329d6
--- /dev/null
+++ b/pd/src/m_class.c
@@ -0,0 +1,772 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#define PD_CLASS_DEF
+#include "m_imp.h"
+#include <stdlib.h>
+#ifdef UNIX
+#include <unistd.h>
+#endif
+#ifdef NT
+#include <io.h>
+#endif
+
+#include <stdarg.h>
+#include <string.h>
+
+static t_symbol *class_loadsym; /* name under which an extern is invoked */
+static void pd_defaultfloat(t_pd *x, t_float f);
+static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv);
+t_pd pd_objectmaker; /* factory for creating "object" boxes */
+t_pd pd_canvasmaker; /* factory for creating canvases */
+
+static void pd_defaultanything(t_pd *x, t_symbol *s, int argc, t_atom *argv)
+{
+ pd_error(x, "%s: no method for '%s'", (*x)->c_name->s_name, s->s_name);
+}
+
+static void pd_defaultbang(t_pd *x)
+{
+ if (*(*x)->c_listmethod != pd_defaultlist)
+ (*(*x)->c_listmethod)(x, 0, 0, 0);
+ else (*(*x)->c_anymethod)(x, &s_bang, 0, 0);
+}
+
+static void pd_defaultpointer(t_pd *x, t_gpointer *gp)
+{
+ if (*(*x)->c_listmethod != pd_defaultlist)
+ {
+ t_atom at;
+ SETPOINTER(&at, gp);
+ (*(*x)->c_listmethod)(x, 0, 1, &at);
+ }
+ else
+ {
+ t_atom at;
+ SETPOINTER(&at, gp);
+ (*(*x)->c_anymethod)(x, &s_pointer, 1, &at);
+ }
+}
+
+static void pd_defaultfloat(t_pd *x, t_float f)
+{
+ if (*(*x)->c_listmethod != pd_defaultlist)
+ {
+ t_atom at;
+ SETFLOAT(&at, f);
+ (*(*x)->c_listmethod)(x, 0, 1, &at);
+ }
+ else
+ {
+ t_atom at;
+ SETFLOAT(&at, f);
+ (*(*x)->c_anymethod)(x, &s_float, 1, &at);
+ }
+}
+
+static void pd_defaultsymbol(t_pd *x, t_symbol *s)
+{
+ if (*(*x)->c_listmethod != pd_defaultlist)
+ {
+ t_atom at;
+ SETSYMBOL(&at, s);
+ (*(*x)->c_listmethod)(x, 0, 1, &at);
+ }
+ else
+ {
+ t_atom at;
+ SETSYMBOL(&at, s);
+ (*(*x)->c_anymethod)(x, &s_symbol, 1, &at);
+ }
+}
+
+void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv);
+
+ /* handle "list" messages to Pds without explicit list methods defined. */
+static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv)
+{
+ /* a list with one element which is a number can be handled by a
+ "float" method if any is defined; same for "symbol", "pointer". */
+ if (argc == 1)
+ {
+ if (argv->a_type == A_FLOAT &&
+ *(*x)->c_floatmethod != pd_defaultfloat)
+ {
+ (*(*x)->c_floatmethod)(x, argv->a_w.w_float);
+ return;
+ }
+ else if (argv->a_type == A_SYMBOL &&
+ *(*x)->c_symbolmethod != pd_defaultsymbol)
+ {
+ (*(*x)->c_symbolmethod)(x, argv->a_w.w_symbol);
+ return;
+ }
+ else if (argv->a_type == A_POINTER &&
+ *(*x)->c_pointermethod != pd_defaultpointer)
+ {
+ (*(*x)->c_pointermethod)(x, argv->a_w.w_gpointer);
+ return;
+ }
+ }
+ /* Next try for an "anything" method */
+ if ((*x)->c_anymethod != pd_defaultanything)
+ (*(*x)->c_anymethod)(x, &s_list, argc, argv);
+
+ /* if the object is patchable (i.e., can have proper inlets)
+ send it on to obj_list which will unpack the list into the inlets */
+ else if ((*x)->c_patchable)
+ obj_list((t_object *)x, s, argc, argv);
+ /* otherwise gove up and complain. */
+ else pd_defaultanything(x, &s_list, argc, argv);
+}
+
+ /* for now we assume that all "gobjs" are text unless explicitly
+ overridden later by calling class_setbehavior(). I'm not sure
+ how to deal with Pds that aren't gobjs; shouldn't there be a
+ way to check that at run time? Perhaps the presence of a "newmethod"
+ should be our cue, or perhaps the "tiny" flag. */
+
+ /* another matter. This routine does two unrelated things: it creates
+ a Pd class, but also adds a "new" method to create an instance of it.
+ These are combined for historical reasons and for brevity in writing
+ objects. To avoid adding a "new" method send a null function pointer.
+ To add additional ones, use class_addcreator below. Some "classes", like
+ "select", are actually two classes of the same name, one for the single-
+ argument form, one for the multiple one; see select_setup() to find out
+ how this is handled. */
+
+extern t_widgetbehavior text_widgetbehavior;
+
+t_class *class_new(t_symbol *s, t_newmethod newmethod, t_method freemethod,
+ size_t size, int flags, t_atomtype type1, ...)
+{
+ va_list ap;
+ t_atomtype vec[MAXPDARG+1], *vp = vec;
+ int count = 0;
+ t_class *c;
+ int typeflag = flags & CLASS_TYPEMASK;
+ if (!typeflag) typeflag = CLASS_PATCHABLE;
+ *vp = type1;
+
+ va_start(ap, type1);
+ while (*vp)
+ {
+ if (count == MAXPDARG)
+ {
+ error("class %s: sorry: only %d creation args allowed",
+ s->s_name, MAXPDARG);
+ break;
+ }
+ vp++;
+ count++;
+ *vp = va_arg(ap, t_atomtype);
+ }
+ va_end(ap);
+ if (pd_objectmaker && newmethod)
+ {
+ /* add a "new" method by the name specified by the object */
+ class_addmethod(pd_objectmaker, (t_method)newmethod, s,
+ vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]);
+ if (class_loadsym)
+ {
+ /* if we're loading an extern it might have been invoked by a
+ longer file name; in this case, make this an admissible name
+ too. */
+ char *loadstring = class_loadsym->s_name,
+ l1 = strlen(s->s_name), l2 = strlen(loadstring);
+ if (l2 > l1 && !strcmp(s->s_name, loadstring + (l2 - l1)))
+ class_addmethod(pd_objectmaker, (t_method)newmethod,
+ class_loadsym,
+ vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]);
+ }
+ }
+ c = (t_class *)t_getbytes(sizeof(*c));
+ c->c_name = c->c_helpname = s;
+ c->c_size = size;
+ c->c_methods = t_getbytes(0);
+ c->c_nmethod = 0;
+ c->c_freemethod = (t_method)freemethod;
+ c->c_bangmethod = pd_defaultbang;
+ c->c_pointermethod = pd_defaultpointer;
+ c->c_floatmethod = pd_defaultfloat;
+ c->c_symbolmethod = pd_defaultsymbol;
+ c->c_listmethod = pd_defaultlist;
+ c->c_anymethod = pd_defaultanything;
+ c->c_wb = (typeflag == CLASS_PATCHABLE ? &text_widgetbehavior : 0);
+ c->c_pwb = 0;
+ c->c_firstin = ((flags & CLASS_NOINLET) == 0);
+ c->c_patchable = (typeflag == CLASS_PATCHABLE);
+ c->c_gobj = (typeflag >= CLASS_GOBJ);
+ c->c_drawcommand = 0;
+ c->c_floatsignalin = 0;
+#if 0
+ post("class: %s", c->c_name->s_name);
+#endif
+ return (c);
+}
+
+ /* add a creation method, which is a function that returns a Pd object
+ suitable for putting in an object box. We presume you've got a class it
+ can belong to, but this won't be used until the newmethod is actually
+ called back (and the new method explicitly takes care of this.) */
+
+void class_addcreator(t_newmethod newmethod, t_symbol *s,
+ t_atomtype type1, ...)
+{
+ va_list ap;
+ t_atomtype vec[MAXPDARG+1], *vp = vec;
+ int count = 0;
+ *vp = type1;
+
+ va_start(ap, type1);
+ while (*vp)
+ {
+ if (count == MAXPDARG)
+ {
+ error("class %s: sorry: only %d creation args allowed",
+ s->s_name, MAXPDARG);
+ break;
+ }
+ vp++;
+ count++;
+ *vp = va_arg(ap, t_atomtype);
+ }
+ va_end(ap);
+ class_addmethod(pd_objectmaker, (t_method)newmethod, s,
+ vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]);
+}
+
+void class_addmethod(t_class *c, t_method fn, t_symbol *sel,
+ t_atomtype arg1, ...)
+{
+ va_list ap;
+ t_methodentry *m;
+ t_atomtype argtype = arg1;
+ int nargs;
+
+ va_start(ap, arg1);
+ /* "signal" method specifies that we take audio signals but
+ that we don't want automatic float to signal conversion. This
+ is obsolete; you should now use the CLASS_MAINSIGNALIN macro. */
+ if (sel == &s_signal)
+ {
+ if (c->c_floatsignalin)
+ post("warning: signal method overrides class_mainsignalin");
+ c->c_floatsignalin = -1;
+ }
+ /* check for special cases. "Pointer" is missing here so that
+ pd_objectmaker's pointer method can be typechecked differently. */
+ if (sel == &s_bang)
+ {
+ if (argtype) goto phooey;
+ class_addbang(c, fn);
+ }
+ else if (sel == &s_float)
+ {
+ if (argtype != A_FLOAT || va_arg(ap, t_atomtype)) goto phooey;
+ class_doaddfloat(c, fn);
+ }
+ else if (sel == &s_symbol)
+ {
+ if (argtype != A_SYMBOL || va_arg(ap, t_atomtype)) goto phooey;
+ class_addsymbol(c, fn);
+ }
+ else if (sel == &s_list)
+ {
+ if (argtype != A_GIMME) goto phooey;
+ class_addlist(c, fn);
+ }
+ else if (sel == &s_anything)
+ {
+ if (argtype != A_GIMME) goto phooey;
+ class_addanything(c, fn);
+ }
+ else
+ {
+ c->c_methods = t_resizebytes(c->c_methods,
+ c->c_nmethod * sizeof(*c->c_methods),
+ (c->c_nmethod + 1) * sizeof(*c->c_methods));
+ m = c->c_methods + c->c_nmethod;
+ c->c_nmethod++;
+ m->me_name = sel;
+ m->me_fun = (t_gotfn)fn;
+ nargs = 0;
+ while (argtype != A_NULL && nargs < MAXPDARG)
+ {
+ m->me_arg[nargs++] = argtype;
+ argtype = va_arg(ap, t_atomtype);
+ }
+ if (argtype != A_NULL)
+ error("%s_%s: only 5 arguments are typecheckable; use A_GIMME",
+ c->c_name->s_name, sel->s_name);
+ va_end(ap);
+ m->me_arg[nargs] = A_NULL;
+ }
+ return;
+phooey:
+ bug("class_addmethod: %s_%s: bad argument types\n",
+ c->c_name->s_name, sel->s_name);
+}
+
+ /* Instead of these, see the "class_addfloat", etc., macros in m_pd.h */
+void class_addbang(t_class *c, t_method fn)
+{
+ c->c_bangmethod = (t_bangmethod)fn;
+}
+
+void class_addpointer(t_class *c, t_method fn)
+{
+ c->c_pointermethod = (t_pointermethod)fn;
+}
+
+void class_doaddfloat(t_class *c, t_method fn)
+{
+ c->c_floatmethod = (t_floatmethod)fn;
+}
+
+void class_addsymbol(t_class *c, t_method fn)
+{
+ c->c_symbolmethod = (t_symbolmethod)fn;
+}
+
+void class_addlist(t_class *c, t_method fn)
+{
+ c->c_listmethod = (t_listmethod)fn;
+}
+
+void class_addanything(t_class *c, t_method fn)
+{
+ c->c_anymethod = (t_anymethod)fn;
+}
+
+void class_setwidget(t_class *c, t_widgetbehavior *w)
+{
+ c->c_wb = w;
+}
+
+void class_setparentwidget(t_class *c, t_parentwidgetbehavior *pw)
+{
+ c->c_pwb = pw;
+}
+
+char *class_getname(t_class *c)
+{
+ return (c->c_name->s_name);
+}
+
+char *class_gethelpname(t_class *c)
+{
+ return (c->c_helpname->s_name);
+}
+
+void class_sethelpsymbol(t_class *c, t_symbol *s)
+{
+ c->c_helpname = s;
+}
+
+t_parentwidgetbehavior *pd_getparentwidget(t_pd *x)
+{
+ return ((*x)->c_pwb);
+}
+
+void class_setdrawcommand(t_class *c)
+{
+ c->c_drawcommand = 1;
+}
+
+int class_isdrawcommand(t_class *c)
+{
+ return (c->c_drawcommand);
+}
+
+static void pd_floatforsignal(t_pd *x, t_float f)
+{
+ int offset = (*x)->c_floatsignalin;
+ if (offset > 0)
+ *(t_sample *)(((char *)x) + offset) = f;
+ else
+ pd_error(x, "%s: float unexpected for signal input",
+ (*x)->c_name->s_name);
+}
+
+void class_domainsignalin(t_class *c, int onset)
+{
+ if (onset <= 0) onset = -1;
+ else
+ {
+ if (c->c_floatmethod != pd_defaultfloat)
+ post("warning: %s: float method overwritten", c->c_name->s_name);
+ c->c_floatmethod = (t_floatmethod)pd_floatforsignal;
+ }
+ c->c_floatsignalin = onset;
+}
+
+/* ---------------- the symbol table ------------------------ */
+
+#define HASHSIZE 1024
+
+static t_symbol *symhash[HASHSIZE];
+
+t_symbol *dogensym(char *s, t_symbol *oldsym)
+{
+ t_symbol **sym1, *sym2;
+ unsigned int hash1 = 0, hash2 = 0;
+ int length = 0;
+ char *s2 = s;
+ while (*s2)
+ {
+ hash1 += *s2;
+ hash2 += hash1;
+ length++;
+ s2++;
+ }
+ sym1 = symhash + (hash2 & (HASHSIZE-1));
+ while (sym2 = *sym1)
+ {
+ if (!strcmp(sym2->s_name, s)) return(sym2);
+ sym1 = &sym2->s_next;
+ }
+ if (oldsym) sym2 = oldsym;
+ else
+ {
+ sym2 = (t_symbol *)t_getbytes(sizeof(*sym2));
+ sym2->s_name = t_getbytes(length+1);
+ sym2->s_next = 0;
+ sym2->s_thing = 0;
+ strcpy(sym2->s_name, s);
+ }
+ *sym1 = sym2;
+ return (sym2);
+}
+
+t_symbol *gensym(char *s)
+{
+ return(dogensym(s, 0));
+}
+
+static t_symbol *addfileextent(t_symbol *s)
+{
+ char namebuf[MAXPDSTRING], *str = s->s_name;
+ int ln = strlen(str);
+ if (!strcmp(str + ln - 3, ".pd")) return (s);
+ strcpy(namebuf, str);
+ strcpy(namebuf+ln, ".pd");
+ return (gensym(namebuf));
+}
+
+static int tryingalready;
+
+void canvas_popabstraction(t_canvas *x);
+extern t_pd *newest;
+
+t_symbol* pathsearch(t_symbol *s,char* ext);
+int pd_setloadingabstraction(t_symbol *sym);
+
+ /* this routine is called when a new "object" is requested whose class Pd
+ doesn't know. Pd tries to load it as an extern, then as an absteaction. */
+void new_anything(void *dummy, t_symbol *s, int argc, t_atom *argv)
+{
+ t_pd *current;
+ t_symbol *dir = canvas_getcurrentdir();
+ int fd;
+ char dirbuf[MAXPDSTRING], *nameptr;
+ if (tryingalready) return;
+ newest = 0;
+ class_loadsym = s;
+ if (sys_load_lib(dir->s_name, s->s_name))
+ {
+ tryingalready = 1;
+ typedmess(dummy, s, argc, argv);
+ tryingalready = 0;
+ return;
+ }
+ class_loadsym = 0;
+ current = s__X.s_thing;
+ if ((fd = open_via_path(dir->s_name, s->s_name, ".pd",
+ dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0)
+ {
+ close (fd);
+ if (!pd_setloadingabstraction(s))
+ {
+ canvas_setargs(argc, argv); /* bug fix by Krzysztof Czaja */
+ binbuf_evalfile(gensym(nameptr), gensym(dirbuf));
+ if (s__X.s_thing != current)
+ canvas_popabstraction((t_canvas *)(s__X.s_thing));
+ canvas_setargs(0, 0);
+ }
+ else error("%s: can't load abstraction within itself\n", s->s_name);
+ }
+ else newest = 0;
+}
+
+t_symbol s_pointer = {"pointer", 0, 0};
+t_symbol s_float = {"float", 0, 0};
+t_symbol s_symbol = {"symbol", 0, 0};
+t_symbol s_bang = {"bang", 0, 0};
+t_symbol s_list = {"list", 0, 0};
+t_symbol s_anything = {"anything", 0, 0};
+t_symbol s_signal = {"signal", 0, 0};
+t_symbol s__N = {"#N", 0, 0};
+t_symbol s__X = {"#X", 0, 0};
+t_symbol s_x = {"x", 0, 0};
+t_symbol s_y = {"y", 0, 0};
+t_symbol s_ = {"", 0, 0};
+
+static t_symbol *symlist[] = { &s_pointer, &s_float, &s_symbol, &s_bang,
+ &s_list, &s_anything, &s_signal, &s__N, &s__X, &s_x, &s_y, &s_};
+
+void mess_init(void)
+{
+ t_symbol **sp;
+ int i;
+
+ if (pd_objectmaker) return;
+ for (i = sizeof(symlist)/sizeof(*symlist), sp = symlist; i--; sp++)
+ (void) dogensym((*sp)->s_name, *sp);
+ pd_objectmaker = class_new(gensym("objectmaker"), 0, 0, sizeof(t_pd),
+ CLASS_DEFAULT, A_NULL);
+ pd_canvasmaker = class_new(gensym("classmaker"), 0, 0, sizeof(t_pd),
+ CLASS_DEFAULT, A_NULL);
+ pd_bind(&pd_canvasmaker, &s__N);
+ class_addanything(pd_objectmaker, (t_method)new_anything);
+}
+
+t_pd *newest;
+
+ /* horribly, we need prototypes for each of the artificial function
+ calls in typedmess(), to keep the compiler quiet. */
+typedef t_pd *(*t_newgimme)(t_symbol *s, int argc, t_atom *argv);
+typedef void(*t_messgimme)(t_pd *x, t_symbol *s, int argc, t_atom *argv);
+
+typedef t_pd *(*t_fun0)(
+ t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
+typedef t_pd *(*t_fun1)(t_int i1,
+ t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
+typedef t_pd *(*t_fun2)(t_int i1, t_int i2,
+ t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
+typedef t_pd *(*t_fun3)(t_int i1, t_int i2, t_int i3,
+ t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
+typedef t_pd *(*t_fun4)(t_int i1, t_int i2, t_int i3, t_int i4,
+ t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
+typedef t_pd *(*t_fun5)(t_int i1, t_int i2, t_int i3, t_int i4, t_int i5,
+ t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
+typedef t_pd *(*t_fun6)(t_int i1, t_int i2, t_int i3, t_int i4, t_int i5, t_int i6,
+ t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5);
+
+void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_method *f;
+ t_class *c = *x;
+ t_methodentry *m;
+ t_atomtype *wp, wanttype;
+ int i;
+ t_int ai[MAXPDARG+1], *ap = ai;
+ t_floatarg ad[MAXPDARG+1], *dp = ad;
+ int narg = 0;
+ t_pd *bonzo;
+
+ /* check for messages that are handled by fixed slots in the class
+ structure. We don't catch "pointer" though so that sending "pointer"
+ to pd_objectmaker doesn't require that we supply a pointer value. */
+ if (s == &s_float)
+ {
+ if (!argc) (*c->c_floatmethod)(x, 0.);
+ else if (argv->a_type == A_FLOAT)
+ (*c->c_floatmethod)(x, argv->a_w.w_float);
+ else goto badarg;
+ return;
+ }
+ if (s == &s_bang)
+ {
+ (*c->c_bangmethod)(x);
+ return;
+ }
+ if (s == &s_list)
+ {
+ (*c->c_listmethod)(x, s, argc, argv);
+ return;
+ }
+ if (s == &s_symbol)
+ {
+ if (argc && argv->a_type == A_SYMBOL)
+ (*c->c_symbolmethod)(x, argv->a_w.w_symbol);
+ else
+ (*c->c_symbolmethod)(x, &s_);
+ return;
+ }
+ for (i = c->c_nmethod, m = c->c_methods; i--; m++)
+ if (m->me_name == s)
+ {
+ wp = m->me_arg;
+ if (*wp == A_GIMME)
+ {
+ if (x == &pd_objectmaker)
+ newest = (*((t_newgimme)(m->me_fun)))(s, argc, argv);
+ else (*((t_messgimme)(m->me_fun)))(x, s, argc, argv);
+ return;
+ }
+ if (argc > MAXPDARG) argc = MAXPDARG;
+ if (x != &pd_objectmaker) *(ap++) = (t_int)x, narg++;
+ while (wanttype = *wp++)
+ {
+ switch (wanttype)
+ {
+ case A_POINTER:
+ if (!argc) goto badarg;
+ else
+ {
+ if (argv->a_type == A_POINTER)
+ *ap = (t_int)(argv->a_w.w_gpointer);
+ else goto badarg;
+ argc--;
+ argv++;
+ }
+ narg++;
+ ap++;
+ break;
+ case A_FLOAT:
+ if (!argc) goto badarg;
+ case A_DEFFLOAT:
+ if (!argc) *dp = 0;
+ else
+ {
+ if (argv->a_type == A_FLOAT)
+ *dp = argv->a_w.w_float;
+ else goto badarg;
+ argc--;
+ argv++;
+ }
+ dp++;
+ break;
+ case A_SYMBOL:
+ if (!argc) goto badarg;
+ case A_DEFSYM:
+ if (!argc) *ap = (t_int)(&s_);
+ else
+ {
+ if (argv->a_type == A_SYMBOL)
+ *ap = (t_int)(argv->a_w.w_symbol);
+ /* if it's an unfilled "dollar" argument it appears
+ as zero here; cheat and bash it to the null
+ symbol. Unfortunately, this lets real zeros
+ pass as symbols too, which seems wrong... */
+ else if (x == &pd_objectmaker && argv->a_type == A_FLOAT
+ && argv->a_w.w_float == 0)
+ *ap = (t_int)(&s_);
+ else goto badarg;
+ argc--;
+ argv++;
+ }
+ narg++;
+ ap++;
+ }
+ }
+ switch (narg)
+ {
+ case 0 : bonzo = (*(t_fun0)(m->me_fun))
+ (ad[0], ad[1], ad[2], ad[3], ad[4]); break;
+ case 1 : bonzo = (*(t_fun1)(m->me_fun))
+ (ai[0], ad[0], ad[1], ad[2], ad[3], ad[4]); break;
+ case 2 : bonzo = (*(t_fun2)(m->me_fun))
+ (ai[0], ai[1], ad[0], ad[1], ad[2], ad[3], ad[4]); break;
+ case 3 : bonzo = (*(t_fun3)(m->me_fun))
+ (ai[0], ai[1], ai[2], ad[0], ad[1], ad[2], ad[3], ad[4]); break;
+ case 4 : bonzo = (*(t_fun4)(m->me_fun))
+ (ai[0], ai[1], ai[2], ai[3],
+ ad[0], ad[1], ad[2], ad[3], ad[4]); break;
+ case 5 : bonzo = (*(t_fun5)(m->me_fun))
+ (ai[0], ai[1], ai[2], ai[3], ai[4],
+ ad[0], ad[1], ad[2], ad[3], ad[4]); break;
+ case 6 : bonzo = (*(t_fun6)(m->me_fun))
+ (ai[0], ai[1], ai[2], ai[3], ai[4], ai[5],
+ ad[0], ad[1], ad[2], ad[3], ad[4]); break;
+ default: bonzo = 0;
+ }
+ if (x == &pd_objectmaker)
+ newest = bonzo;
+ return;
+ }
+ (*c->c_anymethod)(x, s, argc, argv);
+ return;
+badarg:
+ pd_error(x, "Bad arguments for message '%s' to object '%s'",
+ s->s_name, c->c_name->s_name);
+}
+
+void pd_vmess(t_pd *x, t_symbol *sel, char *fmt, ...)
+{
+ va_list ap;
+ t_atom arg[MAXPDARG], *at =arg;
+ int nargs = 0;
+ char *fp = fmt;
+
+ va_start(ap, fmt);
+ while (1)
+ {
+ if (nargs > MAXPDARG)
+ {
+ pd_error(x, "pd_vmess: only %d allowed", MAXPDARG);
+ break;
+ }
+ switch(*fp++)
+ {
+ case 'f': SETFLOAT(at, va_arg(ap, double)); break;
+ case 's': SETSYMBOL(at, va_arg(ap, t_symbol *)); break;
+ case 'i': SETFLOAT(at, va_arg(ap, t_int)); break;
+ case 'p': SETPOINTER(at, va_arg(ap, t_gpointer *)); break;
+ default: goto done;
+ }
+ at++;
+ nargs++;
+ }
+done:
+ va_end(ap);
+ typedmess(x, sel, nargs, arg);
+}
+
+void pd_forwardmess(t_pd *x, int argc, t_atom *argv)
+{
+ if (argc)
+ {
+ t_atomtype t = argv->a_type;
+ if (t == A_SYMBOL) pd_typedmess(x, argv->a_w.w_symbol, argc-1, argv+1);
+ else if (t == A_POINTER)
+ {
+ if (argc == 1) pd_pointer(x, argv->a_w.w_gpointer);
+ else pd_list(x, &s_list, argc, argv);
+ }
+ else if (t == A_FLOAT)
+ {
+ if (argc == 1) pd_float(x, argv->a_w.w_float);
+ else pd_list(x, &s_list, argc, argv);
+ }
+ else bug("pd_forwardmess");
+ }
+
+}
+
+void nullfn(void) {}
+
+t_gotfn getfn(t_pd *x, t_symbol *s)
+{
+ t_class *c = *x;
+ t_methodentry *m;
+ int i;
+
+ for (i = c->c_nmethod, m = c->c_methods; i--; m++)
+ if (m->me_name == s) return(m->me_fun);
+ pd_error(x, "%s: no method for message '%s'", c->c_name->s_name, s->s_name);
+ return((t_gotfn)nullfn);
+}
+
+t_gotfn zgetfn(t_pd *x, t_symbol *s)
+{
+ t_class *c = *x;
+ t_methodentry *m;
+ int i;
+
+ for (i = c->c_nmethod, m = c->c_methods; i--; m++)
+ if (m->me_name == s) return(m->me_fun);
+ return(0);
+}
diff --git a/pd/src/m_conf.c b/pd/src/m_conf.c
new file mode 100644
index 00000000..04cddeda
--- /dev/null
+++ b/pd/src/m_conf.c
@@ -0,0 +1,100 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* changes by Thomas Musil IEM KUG Graz Austria 2001 */
+/* all changes are labeled with iemlib */
+
+#include "m_imp.h"
+
+void g_array_setup(void);
+void g_canvas_setup(void);
+void g_guiconnect_setup(void);
+/* iemlib */
+void g_bang_setup(void);
+void g_hdial_setup(void);
+void g_hslider_setup(void);
+void g_mycanvas_setup(void);
+void g_numbox_setup(void);
+void g_toggle_setup(void);
+void g_vdial_setup(void);
+void g_vslider_setup(void);
+void g_vumeter_setup(void);
+/* iemlib */
+void g_io_setup(void);
+void g_scalar_setup(void);
+void g_template_setup(void);
+void g_text_setup(void);
+void g_traversal_setup(void);
+void m_pd_setup(void);
+void x_acoustics_setup(void);
+void x_interface_setup(void);
+void x_connective_setup(void);
+void x_time_setup(void);
+void x_arithmetic_setup(void);
+void x_midi_setup(void);
+void x_misc_setup(void);
+void x_net_setup(void);
+void x_qlist_setup(void);
+void x_gui_setup(void);
+void d_arithmetic_setup(void);
+void d_array_setup(void);
+void d_ctl_setup(void);
+void d_dac_setup(void);
+void d_delay_setup(void);
+void d_fft_setup(void);
+void d_filter_setup(void);
+void d_global_setup(void);
+void d_math_setup(void);
+void d_misc_setup(void);
+void d_osc_setup(void);
+void d_soundfile_setup(void);
+void d_ugen_setup(void);
+
+void conf_init(void)
+{
+ g_array_setup();
+ g_canvas_setup();
+ g_guiconnect_setup();
+/* iemlib */
+ g_bang_setup();
+ g_hdial_setup();
+ g_hslider_setup();
+ g_mycanvas_setup();
+ g_numbox_setup();
+ g_toggle_setup();
+ g_vdial_setup();
+ g_vslider_setup();
+ g_vumeter_setup();
+/* iemlib */
+ g_io_setup();
+ g_scalar_setup();
+ g_template_setup();
+ g_text_setup();
+ g_traversal_setup();
+ m_pd_setup();
+ x_acoustics_setup();
+ x_interface_setup();
+ x_connective_setup();
+ x_time_setup();
+ x_arithmetic_setup();
+ x_midi_setup();
+ x_misc_setup();
+ x_net_setup();
+ x_qlist_setup();
+ x_gui_setup();
+ d_arithmetic_setup();
+ d_array_setup();
+ d_ctl_setup();
+ d_dac_setup();
+ d_delay_setup();
+ d_fft_setup();
+ d_filter_setup();
+ d_global_setup();
+ d_math_setup();
+ d_misc_setup();
+ d_osc_setup();
+ d_soundfile_setup();
+ d_ugen_setup();
+}
+
diff --git a/pd/src/m_glob.c b/pd/src/m_glob.c
new file mode 100644
index 00000000..3be209d6
--- /dev/null
+++ b/pd/src/m_glob.c
@@ -0,0 +1,121 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_imp.h"
+
+static t_class *pdclass;
+static t_class *maxclass;
+
+/* These "glob" routines, which implement messages to Pd, are from all
+over. Some others are prototyped in m_imp.h as well. */
+
+void glob_setfilename(void *dummy, t_symbol *name, t_symbol *dir);
+void glob_quit(void *dummy);
+void glob_dsp(void *dummy, t_symbol *s, int argc, t_atom *argv);
+void glob_meters(void *dummy, t_floatarg f);
+void glob_key(void *dummy, t_symbol *s, int ac, t_atom *av);
+void glob_audiostatus(void *dummy);
+void glob_finderror(t_pd *dummy);
+void glob_ping(t_pd *dummy);
+
+#if 0 /* this doesn't work for OSS or for ALSA... discouraged... */
+
+#ifdef UNIX
+#include <unistd.h>
+#endif
+
+void glob_restart_audio(t_pd *dummy)
+{
+ int inchans = sys_get_inchannels();
+ int outchans = sys_get_outchannels();
+ post("1");
+ sys_close_audio();
+ post("2");
+#ifdef UNIX
+ sleep(2);
+#endif
+ post("3");
+ sys_open_audio(1, 0, 1, 0, /* IOhannes */
+ 1, &inchans, 1, &outchans, sys_dacsr);
+ post("4");
+}
+#endif
+
+void alsa_resync( void);
+
+
+#ifdef ALSA01
+void glob_restart_alsa(t_pd *dummy)
+{
+ alsa_resync();
+}
+#endif
+
+#ifdef NT
+void glob_audio(void *dummy, t_floatarg adc, t_floatarg dac);
+#endif
+
+/* a method you add for debugging printout */
+void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv);
+
+#if 0
+void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
+{
+ *(int *)1 = 3;
+}
+#endif
+
+void max_default(t_pd *x, t_symbol *s, int argc, t_atom *argv)
+{
+ int i;
+ char str[80];
+ startpost("%s: unknown message %s ", class_getname(pd_class(x)),
+ s->s_name);
+ for (i = 0; i < argc; i++)
+ {
+ atom_string(argv+i, str, 80);
+ poststring(str);
+ }
+ endpost();
+}
+
+void glob_init(void)
+{
+ maxclass = class_new(gensym("max"), 0, 0, sizeof(t_pd),
+ CLASS_DEFAULT, A_NULL);
+ class_addanything(maxclass, max_default);
+ pd_bind(&maxclass, gensym("max"));
+
+ pdclass = class_new(gensym("pd"), 0, 0, sizeof(t_pd),
+ CLASS_DEFAULT, A_NULL);
+ class_addmethod(pdclass, (t_method)glob_initfromgui, gensym("init"),
+ A_GIMME, 0);
+ class_addmethod(pdclass, (t_method)glob_setfilename, gensym("filename"),
+ A_SYMBOL, A_SYMBOL, 0);
+ class_addmethod(pdclass, (t_method)glob_evalfile, gensym("open"),
+ A_SYMBOL, A_SYMBOL, 0);
+ class_addmethod(pdclass, (t_method)glob_quit, gensym("quit"), 0);
+ class_addmethod(pdclass, (t_method)glob_foo, gensym("foo"), A_GIMME, 0);
+ class_addmethod(pdclass, (t_method)glob_dsp, gensym("dsp"), A_GIMME, 0);
+ class_addmethod(pdclass, (t_method)glob_meters, gensym("meters"),
+ A_FLOAT, 0);
+ class_addmethod(pdclass, (t_method)glob_key, gensym("key"), A_GIMME, 0);
+ class_addmethod(pdclass, (t_method)glob_audiostatus,
+ gensym("audiostatus"), 0);
+ class_addmethod(pdclass, (t_method)glob_finderror,
+ gensym("finderror"), 0);
+#ifdef UNIX
+ class_addmethod(pdclass, (t_method)glob_ping, gensym("ping"), 0);
+#endif
+#ifdef NT
+ class_addmethod(pdclass, (t_method)glob_audio, gensym("audio"),
+ A_DEFFLOAT, A_DEFFLOAT, 0);
+#endif
+#ifdef ALSA01
+ class_addmethod(pdclass, (t_method)glob_restart_alsa,
+ gensym("restart-audio"), 0);
+#endif
+ class_addanything(pdclass, max_default);
+ pd_bind(&pdclass, gensym("pd"));
+}
diff --git a/pd/src/m_imp.h b/pd/src/m_imp.h
new file mode 100644
index 00000000..7a6bd69e
--- /dev/null
+++ b/pd/src/m_imp.h
@@ -0,0 +1,223 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* This file contains function prototypes and data types used to implement
+Pd, but not shared with Pd objects. */
+
+#include "m_pd.h"
+
+/* LATER consider whether to use 'char' for method arg types to save space */
+
+/* the structure for a method handler ala Max */
+typedef struct _methodentry
+{
+ t_symbol *me_name;
+ t_gotfn me_fun;
+ t_atomtype me_arg[MAXPDARG+1];
+} t_methodentry;
+
+EXTERN_STRUCT _widgetbehavior;
+
+typedef void (*t_bangmethod)(t_pd *x);
+typedef void (*t_pointermethod)(t_pd *x, t_gpointer *gp);
+typedef void (*t_floatmethod)(t_pd *x, t_float f);
+typedef void (*t_symbolmethod)(t_pd *x, t_symbol *s);
+typedef void (*t_listmethod)(t_pd *x, t_symbol *s, int argc, t_atom *argv);
+typedef void (*t_anymethod)(t_pd *x, t_symbol *s, int argc, t_atom *argv);
+
+struct _class
+{
+ t_symbol *c_name; /* name (mostly for error reporting) */
+ t_symbol *c_helpname; /* name of help file */
+ size_t c_size; /* size of an instance */
+ t_methodentry *c_methods; /* methods other than bang, etc below */
+ int c_nmethod; /* number of methods */
+ t_method c_freemethod; /* function to call before freeing */
+ t_bangmethod c_bangmethod; /* common methods */
+ t_pointermethod c_pointermethod;
+ t_floatmethod c_floatmethod;
+ t_symbolmethod c_symbolmethod;
+ t_listmethod c_listmethod;
+ t_anymethod c_anymethod;
+ struct _widgetbehavior *c_wb; /* "gobjs" only */
+ struct _parentwidgetbehavior *c_pwb;/* widget behavior in parent */
+ int c_floatsignalin; /* onset to float for signal input */
+ char c_gobj; /* true if is a gobj */
+ char c_patchable; /* true if we have a t_object header */
+ char c_firstin; /* if patchable, true if draw first inlet */
+ char c_drawcommand; /* a drawing command for a template */
+};
+
+/* s_file.c */
+typedef struct _namelist
+{
+ struct _namelist *nl_next;
+ char *nl_string;
+} t_namelist;
+
+t_namelist *namelist_append(t_namelist *listwas, const char *s);
+void namelist_free(t_namelist *listwas);
+
+extern int sys_debuglevel;
+extern int sys_verbose;
+
+#define DEBUG_MESSUP 1 /* messages up from pd to pd-gui */
+#define DEBUG_MESSDOWN 2 /* messages down from pd-gui to pd */
+
+extern int sys_noloadbang;
+extern int sys_nogui;
+extern char *sys_guicmd;
+
+/* in s_main.c */
+EXTERN int sys_nearestfontsize(int fontsize);
+EXTERN int sys_hostfontsize(int fontsize);
+
+extern int sys_defaultfont;
+extern t_symbol *sys_libdir; /* library directory for auxilliary files */
+/* s_loader.c */
+int sys_load_lib(char *dirname, char *filename);
+
+/* s_unix.c */
+EXTERN void sys_microsleep(int microsec);
+
+/* s_sgi.c, s_nt.c, s_linux.c each implement the same API for audio
+and MIDI I/O as follows: */
+
+#define DACBLKSIZE 64
+
+#define SENDDACS_NO 0 /* return values for sys_send_dacs() */
+#define SENDDACS_YES 1
+#define SENDDACS_SLEPT 2
+
+#define API_OSS 0 /* API choices */
+#define API_ALSA 1
+#define API_RME 2
+#define API_MMIO 3
+#define API_PORTAUDIO 4
+
+
+ /* MIDI input and output */
+#define MAXMIDIINDEV 16 /* max. number of input ports */
+#define MAXMIDIOUTDEV 16 /* max. number of output ports */
+extern int sys_nmidiin;
+extern int sys_nmidiout;
+extern int sys_midiindevlist[];
+extern int sys_midioutdevlist[];
+
+EXTERN void sys_putmidimess(int portno, int a, int b, int c);
+EXTERN void sys_putmidibyte(int portno, int a);
+EXTERN void sys_poll_midi(void);
+EXTERN void sys_setmiditimediff(double inbuftime, double outbuftime);
+EXTERN void sys_midibytein(int portno, int byte);
+
+extern int sys_hipriority; /* real-time flag, true if priority boosted */
+extern t_sample *sys_soundout;
+extern t_sample *sys_soundin;
+extern float sys_dacsr;
+extern int sys_schedadvance;
+extern int sys_sleepgrain;
+EXTERN void sys_open_audio(int naudioindev, int *audioindev, int nchindev, int *chindev,
+ int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev,
+ int srate); /* IOhannes */
+
+EXTERN void sys_close_audio(void);
+
+EXTERN void sys_open_midi(int nmidiin, int *midiinvec,
+ int nmidiout, int *midioutvec);
+EXTERN void sys_close_midi(void);
+
+EXTERN int sys_send_dacs(void);
+EXTERN void sys_reportidle(void);
+EXTERN void sys_set_priority(int higher);
+EXTERN void sys_audiobuf(int nbufs);
+EXTERN void sys_getmeters(float *inmax, float *outmax);
+EXTERN void sys_listdevs(void);
+EXTERN void sys_setblocksize(int n);
+
+ /* for NT and Linux, there are additional bits of fluff as follows. */
+#ifdef NT
+EXTERN void nt_soundindev(int which);
+EXTERN void nt_soundoutdev(int which);
+EXTERN void nt_midiindev(int which);
+EXTERN void nt_midioutdev(int which);
+EXTERN void nt_noresync( void);
+EXTERN void nt_set_sound_api(int which);
+#endif
+
+#ifdef __linux__
+ /* the following definitions allow you to switch at run time
+ between audio APIs in Linux and later in NT. */
+void linux_set_sound_api(int which);
+
+void linux_setfrags(int n);
+void linux_streammode( void);
+void linux_32bit( void);
+void rme_soundindev(int which);
+void rme_soundoutdev(int which);
+void linux_alsa_queue_size(int size);
+#ifdef ALSA99 /* old fashioned ALSA */
+void linux_alsa_devno(int devno);
+#else
+void linux_alsa_devname(char *devname);
+#endif
+#endif /* __linux__ */
+
+/* portaudio, used in Windows and Mac versions... */
+
+int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin,
+ t_sample *soundout, int framesperbuf, int nbuffers,
+ int indeviceno, int outdeviceno);
+void pa_close_audio(void);
+int pa_send_dacs(void);
+void pa_reportidle(void);
+void pa_listdevs(void);
+
+/* m_sched.c */
+EXTERN void sys_log_error(int type);
+#define ERR_NOTHING 0
+#define ERR_ADCSLEPT 1
+#define ERR_DACSLEPT 2
+#define ERR_RESYNC 3
+#define ERR_DATALATE 4
+
+/* s_inter.c */
+
+EXTERN void sys_bail(int exitcode);
+EXTERN int sys_pollgui(void);
+
+EXTERN_STRUCT _socketreceiver;
+#define t_socketreceiver struct _socketreceiver
+
+typedef void (*t_socketnotifier)(void *x);
+typedef void (*t_socketreceivefn)(void *x, t_binbuf *b);
+
+EXTERN t_socketreceiver *socketreceiver_new(void *owner,
+ t_socketnotifier notifier, t_socketreceivefn socketreceivefn, int udp);
+EXTERN void socketreceiver_read(t_socketreceiver *x, int fd);
+EXTERN void sys_sockerror(char *s);
+EXTERN void sys_closesocket(int fd);
+
+typedef void (*t_fdpollfn)(void *ptr, int fd);
+EXTERN void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr);
+EXTERN void sys_rmpollfn(int fd);
+#ifdef UNIX
+void sys_setalarm(int microsec);
+void sys_setvirtualalarm( void);
+#endif
+
+/* m_obj.c */
+EXTERN int obj_noutlets(t_object *x);
+EXTERN int obj_ninlets(t_object *x);
+EXTERN t_outconnect *obj_starttraverseoutlet(t_object *x, t_outlet **op,
+ int nout);
+EXTERN t_outconnect *obj_nexttraverseoutlet(t_outconnect *lastconnect,
+ t_object **destp, t_inlet **inletp, int *whichp);
+EXTERN t_outconnect *obj_connect(t_object *source, int outno,
+ t_object *sink, int inno);
+EXTERN void obj_disconnect(t_object *source, int outno, t_object *sink,
+ int inno);
+EXTERN void outlet_setstacklim(void);
+/* misc */
+EXTERN void glob_evalfile(t_pd *ignore, t_symbol *name, t_symbol *dir);
+EXTERN void glob_initfromgui(void *dummy, t_symbol *s, int argc, t_atom *argv);
diff --git a/pd/src/m_memory.c b/pd/src/m_memory.c
new file mode 100644
index 00000000..cb94e4b1
--- /dev/null
+++ b/pd/src/m_memory.c
@@ -0,0 +1,88 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <stdlib.h>
+#include <string.h>
+#include "m_imp.h"
+
+/* #define LOUD */
+#ifdef LOUD
+#include <stdio.h>
+#endif
+
+/* #define DEBUGMEM */
+#ifdef DEBUGMEM
+static int totalmem = 0;
+#endif
+
+void *getbytes(size_t nbytes)
+{
+ void *ret;
+ if (nbytes < 1) nbytes = 1;
+ ret = (void *)calloc(nbytes, 1);
+#ifdef LOUD
+ fprintf(stderr, "new %x %d\n", (int)ret, nbytes);
+#endif /* LOUD */
+#ifdef DEBUGMEM
+ totalmem += nbytes;
+#endif
+ if (!ret)
+ post("pd: getbytes() failed -- out of memory");
+ return (ret);
+}
+
+void *getzbytes(size_t nbytes) /* obsolete name */
+{
+ return (getbytes(nbytes));
+}
+
+void *copybytes(void *src, size_t nbytes)
+{
+ void *ret;
+ ret = getbytes(nbytes);
+ if (nbytes)
+ memcpy(ret, src, nbytes);
+ return (ret);
+}
+
+void *resizebytes(void *old, size_t oldsize, size_t newsize)
+{
+ void *ret;
+ if (newsize < 1) newsize = 1;
+ if (oldsize < 1) oldsize = 1;
+ ret = (void *)realloc((char *)old, newsize);
+ if (newsize > oldsize && ret)
+ memset(((char *)ret) + oldsize, 0, newsize - oldsize);
+#ifdef LOUD
+ fprintf(stderr, "resize %x %d --> %x %d\n", (int)old, oldsize, (int)ret, newsize);
+#endif /* LOUD */
+#ifdef DEBUGMEM
+ totalmem += (newsize - oldsize);
+#endif
+ if (!ret)
+ post("pd: resizebytes() failed -- out of memory");
+ return (ret);
+}
+
+void freebytes(void *fatso, size_t nbytes)
+{
+ if (nbytes == 0)
+ nbytes = 1;
+#ifdef LOUD
+ fprintf(stderr, "free %x %d\n", (int)fatso, nbytes);
+#endif /* LOUD */
+#ifdef DEBUGMEM
+ totalmem -= nbytes;
+#endif
+ free(fatso);
+}
+
+#ifdef DEBUGMEM
+#include <stdio.h>
+
+void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
+{
+ fprintf(stderr, "total mem %d\n", totalmem);
+}
+#endif
diff --git a/pd/src/m_obj.c b/pd/src/m_obj.c
new file mode 100644
index 00000000..6b9ea932
--- /dev/null
+++ b/pd/src/m_obj.c
@@ -0,0 +1,676 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* this file handles Max-style patchable objects, i.e., objects which
+can interconnect via inlets and outlets; also, the (terse) generic
+behavior for "gobjs" appears at the end of this file. */
+
+#include "m_imp.h"
+
+union inletunion
+{
+ t_symbol *iu_symto;
+ t_gpointer *iu_pointerslot;
+ t_float *iu_floatslot;
+ t_symbol **iu_symslot;
+ t_sample iu_floatsignalvalue;
+};
+
+struct _inlet
+{
+ t_pd i_pd;
+ struct _inlet *i_next;
+ t_object *i_owner;
+ t_pd *i_dest;
+ t_symbol *i_symfrom;
+ union inletunion i_un;
+};
+
+#define i_symto i_un.iu_symto
+#define i_pointerslot i_un.iu_pointerslot
+#define i_floatslot i_un.iu_floatslot
+#define i_symslot i_un.iu_symslot
+
+static t_class *inlet_class, *pointerinlet_class, *floatinlet_class,
+ *symbolinlet_class;
+
+#define ISINLET(pd) ((*(pd) == inlet_class) || \
+ (*(pd) == pointerinlet_class) || \
+ (*(pd) == floatinlet_class) || \
+ (*(pd) == symbolinlet_class))
+
+/* --------------------- generic inlets ala max ------------------ */
+
+t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1, t_symbol *s2)
+{
+ t_inlet *x = (t_inlet *)pd_new(inlet_class), *y, *y2;
+ x->i_owner = owner;
+ x->i_dest = dest;
+ if (s1 == &s_signal)
+ x->i_un.iu_floatsignalvalue = 0;
+ else x->i_symto = s2;
+ x->i_symfrom = s1;
+ x->i_next = 0;
+ if (y = owner->ob_inlet)
+ {
+ while (y2 = y->i_next) y = y2;
+ y->i_next = x;
+ }
+ else owner->ob_inlet = x;
+ return (x);
+}
+
+static void inlet_wrong(t_inlet *x, t_symbol *s)
+{
+ pd_error(x->i_owner, "inlet: expected '%s' but got '%s'",
+ x->i_symfrom->s_name, s->s_name);
+}
+
+ /* LATER figure out how to make these efficient: */
+static void inlet_bang(t_inlet *x)
+{
+ if (x->i_symfrom == &s_bang)
+ pd_vmess(x->i_dest, x->i_symto, "");
+ else if (!x->i_symfrom) pd_bang(x->i_dest);
+ else inlet_wrong(x, &s_bang);
+}
+
+static void inlet_pointer(t_inlet *x, t_gpointer *gp)
+{
+ if (x->i_symfrom == &s_pointer)
+ pd_vmess(x->i_dest, x->i_symto, "p", gp);
+ else if (!x->i_symfrom) pd_pointer(x->i_dest, gp);
+ else inlet_wrong(x, &s_pointer);
+}
+
+static void inlet_float(t_inlet *x, t_float f)
+{
+ if (x->i_symfrom == &s_float)
+ pd_vmess(x->i_dest, x->i_symto, "f", (t_floatarg)f);
+ else if (x->i_symfrom == &s_signal)
+ x->i_un.iu_floatsignalvalue = f;
+ else if (!x->i_symfrom)
+ pd_float(x->i_dest, f);
+ else inlet_wrong(x, &s_float);
+}
+
+static void inlet_symbol(t_inlet *x, t_symbol *s)
+{
+ if (x->i_symfrom == &s_symbol)
+ pd_vmess(x->i_dest, x->i_symto, "s", s);
+ else if (!x->i_symfrom) pd_symbol(x->i_dest, s);
+ else inlet_wrong(x, &s_symbol);
+}
+
+static void inlet_list(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_atom at;
+ if (x->i_symfrom == &s_list || x->i_symfrom == &s_float
+ || x->i_symfrom == &s_symbol || x->i_symfrom == &s_pointer)
+ typedmess(x->i_dest, x->i_symto, argc, argv);
+ else if (!x->i_symfrom) pd_list(x->i_dest, s, argc, argv);
+ else inlet_wrong(x, &s_list);
+}
+
+static void inlet_anything(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if (x->i_symfrom == s)
+ typedmess(x->i_dest, x->i_symto, argc, argv);
+ else if (!x->i_symfrom)
+ typedmess(x->i_dest, s, argc, argv);
+ else inlet_wrong(x, s);
+}
+
+void inlet_free(t_inlet *x)
+{
+ t_object *y = x->i_owner;
+ t_inlet *x2;
+ if (y->ob_inlet == x) y->ob_inlet = x->i_next;
+ else for (x2 = y->ob_inlet; x2; x2 = x2->i_next)
+ if (x2->i_next == x)
+ {
+ x2->i_next = x->i_next;
+ break;
+ }
+ t_freebytes(x, sizeof(*x));
+}
+
+/* ----- pointerinlets, floatinlets, syminlets: optimized inlets ------- */
+
+static void pointerinlet_pointer(t_inlet *x, t_gpointer *gp)
+{
+ gpointer_unset(x->i_pointerslot);
+ *(x->i_pointerslot) = *gp;
+ if (gp->gp_stub) gp->gp_stub->gs_refcount++;
+}
+
+t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp)
+{
+ t_inlet *x = (t_inlet *)pd_new(pointerinlet_class), *y, *y2;
+ x->i_owner = owner;
+ x->i_dest = 0;
+ x->i_symfrom = &s_pointer;
+ x->i_pointerslot = gp;
+ x->i_next = 0;
+ if (y = owner->ob_inlet)
+ {
+ while (y2 = y->i_next) y = y2;
+ y->i_next = x;
+ }
+ else owner->ob_inlet = x;
+ return (x);
+}
+
+static void floatinlet_float(t_inlet *x, t_float f)
+{
+ *(x->i_floatslot) = f;
+}
+
+t_inlet *floatinlet_new(t_object *owner, t_float *fp)
+{
+ t_inlet *x = (t_inlet *)pd_new(floatinlet_class), *y, *y2;
+ x->i_owner = owner;
+ x->i_dest = 0;
+ x->i_symfrom = &s_float;
+ x->i_floatslot = fp;
+ x->i_next = 0;
+ if (y = owner->ob_inlet)
+ {
+ while (y2 = y->i_next) y = y2;
+ y->i_next = x;
+ }
+ else owner->ob_inlet = x;
+ return (x);
+}
+
+static void symbolinlet_symbol(t_inlet *x, t_symbol *s)
+{
+ *(x->i_symslot) = s;
+}
+
+t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp)
+{
+ t_inlet *x = (t_inlet *)pd_new(symbolinlet_class), *y, *y2;
+ x->i_owner = owner;
+ x->i_dest = 0;
+ x->i_symfrom = &s_symbol;
+ x->i_symslot = sp;
+ x->i_next = 0;
+ if (y = owner->ob_inlet)
+ {
+ while (y2 = y->i_next) y = y2;
+ y->i_next = x;
+ }
+ else owner->ob_inlet = x;
+ return (x);
+}
+
+/* ---------------------- routine to handle lists ---------------------- */
+
+ /* objects interpret lists by feeding them to the individual inlets.
+ Before you call this check that the object doesn't have a more
+ specific way to handle lists. */
+void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_atom *ap;
+ int count;
+ t_inlet *ip = ((t_object *)x)->ob_inlet;
+ if (!argc) return;
+ for (count = argc-1, ap = argv+1; ip && count--; ap++, ip = ip->i_next)
+ {
+ if (ap->a_type == A_POINTER) pd_pointer(&ip->i_pd, ap->a_w.w_gpointer);
+ else if (ap->a_type == A_FLOAT) pd_float(&ip->i_pd, ap->a_w.w_float);
+ else pd_symbol(&ip->i_pd, ap->a_w.w_symbol);
+ }
+ if (argv->a_type == A_POINTER) pd_pointer(&x->ob_pd, argv->a_w.w_gpointer);
+ else if (argv->a_type == A_FLOAT) pd_float(&x->ob_pd, argv->a_w.w_float);
+ else pd_symbol(&x->ob_pd, argv->a_w.w_symbol);
+}
+
+void obj_init(void)
+{
+ inlet_class = class_new(gensym("inlet"), 0, 0,
+ sizeof(t_inlet), CLASS_PD, 0);
+ class_addbang(inlet_class, inlet_bang);
+ class_addpointer(inlet_class, inlet_pointer);
+ class_addfloat(inlet_class, inlet_float);
+ class_addsymbol(inlet_class, inlet_symbol);
+ class_addlist(inlet_class, inlet_list);
+ class_addanything(inlet_class, inlet_anything);
+
+ pointerinlet_class = class_new(gensym("inlet"), 0, 0,
+ sizeof(t_inlet), CLASS_PD, 0);
+ class_addpointer(pointerinlet_class, pointerinlet_pointer);
+
+ floatinlet_class = class_new(gensym("inlet"), 0, 0,
+ sizeof(t_inlet), CLASS_PD, 0);
+ class_addfloat(floatinlet_class, (t_method)floatinlet_float);
+
+ symbolinlet_class = class_new(gensym("inlet"), 0, 0,
+ sizeof(t_inlet), CLASS_PD, 0);
+ class_addsymbol(symbolinlet_class, symbolinlet_symbol);
+
+}
+
+/* --------------------------- outlets ------------------------------ */
+
+static char *stacklimit, *topstack;
+#define STACKSIZE 1000000
+static int outlet_eventno;
+
+ /* set a stack limit (on each incoming event that can set off messages)
+ for the outlet functions to check to prevent stack overflow from message
+ recursion */
+void outlet_setstacklim(void)
+{
+ char c;
+ topstack = &c;
+ stacklimit = (&c) - STACKSIZE;
+ outlet_eventno++;
+}
+
+ /* get a number unique to the (clock, MIDI, GUI, etc.) event we're on */
+int sched_geteventno( void)
+{
+ return (outlet_eventno);
+}
+
+struct _outconnect
+{
+ struct _outconnect *oc_next;
+ t_pd *oc_to;
+};
+
+struct _outlet
+{
+ t_object *o_owner;
+ struct _outlet *o_next;
+ t_outconnect *o_connections;
+ t_symbol *o_sym;
+};
+
+t_outlet *outlet_new(t_object *owner, t_symbol *s)
+{
+ t_outlet *x = (t_outlet *)getbytes(sizeof(*x)), *y, *y2;
+ x->o_owner = owner;
+ x->o_next = 0;
+ if (y = owner->ob_outlet)
+ {
+ while (y2 = y->o_next) y = y2;
+ y->o_next = x;
+ }
+ else owner->ob_outlet = x;
+ x->o_connections = 0;
+ x->o_sym = s;
+ return (x);
+}
+
+static void outlet_stackerror(t_outlet *x)
+{
+ pd_error(x->o_owner, "stack overflow");
+ stacklimit = topstack;
+}
+
+void outlet_bang(t_outlet *x)
+{
+ t_outconnect *oc;
+ char c;
+ if (&c < stacklimit)
+ outlet_stackerror(x);
+ else for (oc = x->o_connections; oc; oc = oc->oc_next)
+ pd_bang(oc->oc_to);
+}
+
+void outlet_pointer(t_outlet *x, t_gpointer *gp)
+{
+ t_outconnect *oc;
+ t_gpointer gpointer;
+ char c;
+ if (&c < stacklimit)
+ outlet_stackerror(x);
+ else
+ {
+#if 0
+ gpointer_copy(gp, &gpointer);
+ for (oc = x->o_connections; oc; oc = oc->oc_next)
+ pd_pointer(oc->oc_to, &gpointer);
+ gpointer_unset(&gpointer);
+#else
+ gpointer = *gp;
+ for (oc = x->o_connections; oc; oc = oc->oc_next)
+ pd_pointer(oc->oc_to, &gpointer);
+#endif
+ }
+}
+
+void outlet_float(t_outlet *x, t_float f)
+{
+ t_outconnect *oc;
+ char c;
+ if (&c < stacklimit)
+ outlet_stackerror(x);
+ else for (oc = x->o_connections; oc; oc = oc->oc_next)
+ pd_float(oc->oc_to, f);
+}
+
+void outlet_symbol(t_outlet *x, t_symbol *s)
+{
+ t_outconnect *oc;
+ char c;
+ if (&c < stacklimit)
+ outlet_stackerror(x);
+ else for (oc = x->o_connections; oc; oc = oc->oc_next)
+ pd_symbol(oc->oc_to, s);
+}
+
+void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_outconnect *oc;
+ char c;
+ if (&c < stacklimit)
+ outlet_stackerror(x);
+ else for (oc = x->o_connections; oc; oc = oc->oc_next)
+ pd_list(oc->oc_to, s, argc, argv);
+}
+
+void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_outconnect *oc;
+ char c;
+ if (&c < stacklimit)
+ outlet_stackerror(x);
+ else for (oc = x->o_connections; oc; oc = oc->oc_next)
+ typedmess(oc->oc_to, s, argc, argv);
+}
+
+void outlet_free(t_outlet *x)
+{
+ t_object *y = x->o_owner;
+ t_outlet *x2;
+ if (y->ob_outlet == x) y->ob_outlet = x->o_next;
+ else for (x2 = y->ob_outlet; x2; x2 = x2->o_next)
+ if (x2->o_next == x)
+ {
+ x2->o_next = x->o_next;
+ break;
+ }
+ t_freebytes(x, sizeof(*x));
+}
+
+t_outconnect *obj_connect(t_object *source, int outno,
+ t_object *sink, int inno)
+{
+ t_inlet *i;
+ t_outlet *o;
+ t_pd *to;
+ t_outconnect *oc, *oc2;
+
+ for (o = source->ob_outlet; o && outno; o = o->o_next, outno--) ;
+ if (!o) return (0);
+
+ if (sink->ob_pd->c_firstin)
+ {
+ if (!inno)
+ {
+ to = &sink->ob_pd;
+ goto doit;
+ }
+ else inno--;
+ }
+ for (i = sink->ob_inlet; i && inno; i = i->i_next, inno--) ;
+ if (!i) return (0);
+ to = &i->i_pd;
+doit:
+ oc = (t_outconnect *)t_getbytes(sizeof(*oc));
+ oc->oc_next = 0;
+ oc->oc_to = to;
+ /* append it to the end of the list */
+ /* LATER we might cache the last "oc" to make this faster. */
+ if ((oc2 = o->o_connections))
+ {
+ while (oc2->oc_next) oc2 = oc2->oc_next;
+ oc2->oc_next = oc;
+ }
+ else o->o_connections = oc;
+ if (o->o_sym == &s_signal) canvas_update_dsp();
+
+ return (oc);
+}
+
+void obj_disconnect(t_object *source, int outno, t_object *sink, int inno)
+{
+ t_inlet *i;
+ t_outlet *o;
+ t_pd *to;
+ t_outconnect *oc, *oc2;
+
+ for (o = source->ob_outlet; o && outno; o = o->o_next, outno--)
+ if (!o) return;
+ if (sink->ob_pd->c_firstin)
+ {
+ if (!inno)
+ {
+ to = &sink->ob_pd;
+ goto doit;
+ }
+ else inno--;
+ }
+ for (i = sink->ob_inlet; i && inno; i = i->i_next, inno--) ;
+ if (!i) return;
+ to = &i->i_pd;
+doit:
+ if (!(oc = o->o_connections)) return;
+ if (oc->oc_to == to)
+ {
+ o->o_connections = oc->oc_next;
+ freebytes(oc, sizeof(*oc));
+ goto done;
+ }
+ while (oc2 = oc->oc_next)
+ {
+ if (oc2->oc_to == to)
+ {
+ oc->oc_next = oc2->oc_next;
+ freebytes(oc2, sizeof(*oc2));
+ goto done;
+ }
+ oc = oc2;
+ }
+done:
+ if (o->o_sym == &s_signal) canvas_update_dsp();
+}
+
+/* ------ traversal routines for code that can't see our structures ------ */
+
+int obj_noutlets(t_object *x)
+{
+ int n;
+ t_outlet *o;
+ for (o = x->ob_outlet, n = 0; o; o = o->o_next) n++;
+ return (n);
+}
+
+int obj_ninlets(t_object *x)
+{
+ int n;
+ t_inlet *i;
+ for (i = x->ob_inlet, n = 0; i; i = i->i_next) n++;
+ if (x->ob_pd->c_firstin) n++;
+ return (n);
+}
+
+t_outconnect *obj_starttraverseoutlet(t_object *x, t_outlet **op, int nout)
+{
+ t_outlet *o = x->ob_outlet;
+ while (nout-- && o) o = o->o_next;
+ *op = o;
+ if (o) return (o->o_connections);
+ else return (0);
+}
+
+t_outconnect *obj_nexttraverseoutlet(t_outconnect *lastconnect,
+ t_object **destp, t_inlet **inletp, int *whichp)
+{
+ t_pd *y;
+ y = lastconnect->oc_to;
+ if (ISINLET(y))
+ {
+ int n;
+ t_inlet *i = (t_inlet *)y, *i2;
+ t_object *dest = i->i_owner;
+ for (n = dest->ob_pd->c_firstin, i2 = dest->ob_inlet;
+ i2 && i2 != i; i2 = i2->i_next) n++;
+ *whichp = n;
+ *destp = dest;
+ *inletp = i;
+ }
+ else
+ {
+ *whichp = 0;
+ *inletp = 0;
+ *destp = ((t_object *)y);
+ }
+ return (lastconnect->oc_next);
+}
+
+ /* this one checks that a pd is indeed a patchable object, and returns
+ it, correctly typed, or zero if the check failed. */
+t_object *pd_checkobject(t_pd *x)
+{
+ if ((*x)->c_patchable) return ((t_object *)x);
+ else return (0);
+}
+
+ /* move an inlet or outlet to the head of the list */
+void obj_moveinletfirst(t_object *x, t_inlet *i)
+{
+ t_inlet *i2;
+ if (x->ob_inlet == i) return;
+ else for (i2 = x->ob_inlet; i2; i2 = i2->i_next)
+ if (i2->i_next == i)
+ {
+ i2->i_next = i->i_next;
+ i->i_next = x->ob_inlet;
+ x->ob_inlet = i;
+ return;
+ }
+}
+
+void obj_moveoutletfirst(t_object *x, t_outlet *o)
+{
+ t_outlet *o2;
+ if (x->ob_outlet == o) return;
+ else for (o2 = x->ob_outlet; o2; o2 = o2->o_next)
+ if (o2->o_next == o)
+ {
+ o2->o_next = o->o_next;
+ o->o_next = x->ob_outlet;
+ x->ob_outlet = o;
+ return;
+ }
+}
+
+ /* routines for DSP sorting, which are used in d_ugen.c and g_canvas.c */
+ /* LATER try to consolidate all the slightly different routines. */
+
+int obj_nsiginlets(t_object *x)
+{
+ int n;
+ t_inlet *i;
+ for (i = x->ob_inlet, n = 0; i; i = i->i_next)
+ if (i->i_symfrom == &s_signal) n++;
+ if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin) n++;
+ return (n);
+}
+
+ /* get the index, among signal inlets, of the mth inlet overall */
+int obj_siginletindex(t_object *x, int m)
+{
+ int n = 0;
+ t_inlet *i;
+ if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin)
+ {
+ if (!m--) return (0);
+ n++;
+ }
+ for (i = x->ob_inlet; i; i = i->i_next, m--)
+ if (i->i_symfrom == &s_signal)
+ {
+ if (m == 0) return (n);
+ n++;
+ }
+ return (-1);
+}
+
+int obj_nsigoutlets(t_object *x)
+{
+ int n;
+ t_outlet *o;
+ for (o = x->ob_outlet, n = 0; o; o = o->o_next)
+ if (o->o_sym == &s_signal) n++;
+ return (n);
+}
+
+int obj_sigoutletindex(t_object *x, int m)
+{
+ int n;
+ t_outlet *o2;
+ for (o2 = x->ob_outlet, n = 0; o2; o2 = o2->o_next, m--)
+ if (o2->o_sym == &s_signal)
+ {
+ if (m == 0) return (n);
+ n++;
+ }
+ return (-1);
+}
+
+int obj_issignaloutlet(t_object *x, int m)
+{
+ int n;
+ t_outlet *o2;
+ for (o2 = x->ob_outlet, n = 0; o2 && m--; o2 = o2->o_next);
+ return (o2 && (o2->o_sym == &s_signal));
+}
+
+t_sample *obj_findsignalscalar(t_object *x, int m)
+{
+ int n = 0;
+ t_inlet *i;
+ if (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin)
+ {
+ if (!m--)
+ return (x->ob_pd->c_floatsignalin > 0 ?
+ (t_sample *)(((char *)x) + x->ob_pd->c_floatsignalin) : 0);
+ n++;
+ }
+ for (i = x->ob_inlet; i; i = i->i_next, m--)
+ if (i->i_symfrom == &s_signal)
+ {
+ if (m == 0)
+ return (&i->i_un.iu_floatsignalvalue);
+ n++;
+ }
+ return (0);
+}
+
+/* and these are only used in g_io.c... */
+
+int inlet_getsignalindex(t_inlet *x)
+{
+ int n = 0;
+ t_inlet *i;
+ for (i = x->i_owner->ob_inlet, n = 0; i && i != x; i = i->i_next)
+ if (i->i_symfrom == &s_signal) n++;
+ return (n);
+}
+
+int outlet_getsignalindex(t_outlet *x)
+{
+ int n = 0;
+ t_outlet *o;
+ for (o = x->o_owner->ob_outlet, n = 0; o && o != x; o = o->o_next)
+ if (o->o_sym == &s_signal) n++;
+ return (n);
+}
+
diff --git a/pd/src/m_pd.c b/pd/src/m_pd.c
new file mode 100644
index 00000000..713d65ad
--- /dev/null
+++ b/pd/src/m_pd.c
@@ -0,0 +1,296 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <stdlib.h>
+#include "m_imp.h"
+
+ /* FIXME no out-of-memory testing yet! */
+
+t_pd *pd_new(t_class *c)
+{
+ t_pd *x;
+ if (!c)
+ bug ("pd_new: apparently called before setup routine");
+ x = (t_pd *)t_getbytes(c->c_size);
+ *x = c;
+ if (c->c_patchable)
+ {
+ ((t_object *)x)->ob_inlet = 0;
+ ((t_object *)x)->ob_outlet = 0;
+ }
+ return (x);
+}
+
+void pd_free(t_pd *x)
+{
+ t_class *c = *x;
+ if (c->c_freemethod) (*(t_gotfn)(c->c_freemethod))(x);
+ if (c->c_patchable)
+ {
+ while (((t_object *)x)->ob_outlet)
+ outlet_free(((t_object *)x)->ob_outlet);
+ while (((t_object *)x)->ob_inlet)
+ inlet_free(((t_object *)x)->ob_inlet);
+ if (((t_object *)x)->ob_binbuf)
+ binbuf_free(((t_object *)x)->ob_binbuf);
+ }
+ if (c->c_size) t_freebytes(x, c->c_size);
+}
+
+/* deal with several objects bound to the same symbol. If more than one, we
+actually bind a collection object to the symbol, which forwards messages sent
+to the symbol. */
+
+static t_class *bindlist_class;
+
+typedef struct _bindelem
+{
+ t_pd *e_who;
+ struct _bindelem *e_next;
+} t_bindelem;
+
+typedef struct _bindlist
+{
+ t_pd b_pd;
+ t_bindelem *b_list;
+} t_bindlist;
+
+static void bindlist_bang(t_bindlist *x)
+{
+ t_bindelem *e;
+ for (e = x->b_list; e; e = e->e_next)
+ pd_bang(e->e_who);
+}
+
+static void bindlist_float(t_bindlist *x, t_float f)
+{
+ t_bindelem *e;
+ for (e = x->b_list; e; e = e->e_next)
+ pd_float(e->e_who, f);
+}
+
+static void bindlist_symbol(t_bindlist *x, t_symbol *s)
+{
+ t_bindelem *e;
+ for (e = x->b_list; e; e = e->e_next)
+ pd_symbol(e->e_who, s);
+}
+
+static void bindlist_pointer(t_bindlist *x, t_gpointer *gp)
+{
+ t_bindelem *e;
+ for (e = x->b_list; e; e = e->e_next)
+ pd_pointer(e->e_who, gp);
+}
+
+static void bindlist_list(t_bindlist *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ t_bindelem *e;
+ for (e = x->b_list; e; e = e->e_next)
+ pd_list(e->e_who, s, argc, argv);
+}
+
+static void bindlist_anything(t_bindlist *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ t_bindelem *e;
+ for (e = x->b_list; e; e = e->e_next)
+ pd_typedmess(e->e_who, s, argc, argv);
+}
+
+void m_pd_setup(void)
+{
+ bindlist_class = class_new(gensym("bindlist"), 0, 0,
+ sizeof(t_bindlist), CLASS_PD, 0);
+ class_addbang(bindlist_class, bindlist_bang);
+ class_addfloat(bindlist_class, (t_method)bindlist_float);
+ class_addsymbol(bindlist_class, bindlist_symbol);
+ class_addpointer(bindlist_class, bindlist_pointer);
+ class_addlist(bindlist_class, bindlist_list);
+ class_addanything(bindlist_class, bindlist_anything);
+}
+
+void pd_bind(t_pd *x, t_symbol *s)
+{
+ if (s->s_thing)
+ {
+ if (*s->s_thing == bindlist_class)
+ {
+ t_bindlist *b = (t_bindlist *)s->s_thing;
+ t_bindelem *e = (t_bindelem *)getbytes(sizeof(t_bindelem));
+ e->e_next = b->b_list;
+ e->e_who = x;
+ b->b_list = e;
+ }
+ else
+ {
+ t_bindlist *b = (t_bindlist *)pd_new(bindlist_class);
+ t_bindelem *e1 = (t_bindelem *)getbytes(sizeof(t_bindelem));
+ t_bindelem *e2 = (t_bindelem *)getbytes(sizeof(t_bindelem));
+ b->b_list = e1;
+ e1->e_who = x;
+ e1->e_next = e2;
+ e2->e_who = s->s_thing;
+ e2->e_next = 0;
+ s->s_thing = &b->b_pd;
+ }
+ }
+ else s->s_thing = x;
+}
+
+void pd_unbind(t_pd *x, t_symbol *s)
+{
+ if (s->s_thing == x) s->s_thing = 0;
+ else if (s->s_thing && *s->s_thing == bindlist_class)
+ {
+ /* bindlists always have at least two elements... if the number
+ goes down to one, get rid of the bindlist and bind the symbol
+ straight to the remaining element. */
+
+ t_bindlist *b = (t_bindlist *)s->s_thing;
+ t_bindelem *e, *e2;
+ if ((e = b->b_list)->e_who == x)
+ {
+ b->b_list = e->e_next;
+ freebytes(e, sizeof(t_bindelem));
+ }
+ else for (e = b->b_list; e2 = e->e_next; e = e2)
+ if (e2->e_who == x)
+ {
+ e->e_next = e2->e_next;
+ freebytes(e2, sizeof(t_bindelem));
+ break;
+ }
+ if (!b->b_list->e_next)
+ {
+ s->s_thing = b->b_list->e_who;
+ freebytes(b->b_list, sizeof(t_bindelem));
+ pd_free(&b->b_pd);
+ }
+ }
+ else pd_error(x, "%s: couldn't unbind", s->s_name);
+}
+
+void zz(void) {}
+
+t_pd *pd_findbyclass(t_symbol *s, t_class *c)
+{
+ t_pd *x = 0;
+
+ if (!s->s_thing) return (0);
+ if (*s->s_thing == c) return (s->s_thing);
+ if (*s->s_thing == bindlist_class)
+ {
+ t_bindlist *b = (t_bindlist *)s->s_thing;
+ t_bindelem *e, *e2;
+ int warned = 0;
+ for (e = b->b_list; e; e = e->e_next)
+ if (*e->e_who == c)
+ {
+ if (x && !warned)
+ {
+ zz();
+ post("warning: %s: multiply defined", s->s_name);
+ warned = 1;
+ }
+ x = e->e_who;
+ }
+ }
+ return x;
+}
+
+/* stack for maintaining bindings for the #X symbol during nestable loads.
+*/
+
+typedef struct _gstack
+{
+ t_pd *g_what;
+ t_symbol *g_loadingabstraction;
+ struct _gstack *g_next;
+} t_gstack;
+
+static t_gstack *gstack_head = 0;
+static t_pd *lastpopped;
+static t_symbol *pd_loadingabstraction;
+
+int pd_setloadingabstraction(t_symbol *sym)
+{
+ t_gstack *foo = gstack_head;
+ for (foo = gstack_head; foo; foo = foo->g_next)
+ if (foo->g_loadingabstraction == sym)
+ return (1);
+ pd_loadingabstraction = sym;
+ return (0);
+}
+
+void pd_pushsym(t_pd *x)
+{
+ t_gstack *y = (t_gstack *)t_getbytes(sizeof(*y));
+ y->g_what = s__X.s_thing;
+ y->g_next = gstack_head;
+ y->g_loadingabstraction = pd_loadingabstraction;
+ pd_loadingabstraction = 0;
+ gstack_head = y;
+ s__X.s_thing = x;
+}
+
+void pd_popsym(t_pd *x)
+{
+ if (!gstack_head || s__X.s_thing != x) bug("gstack_pop");
+ else
+ {
+ t_gstack *headwas = gstack_head;
+ s__X.s_thing = headwas->g_what;
+ gstack_head = headwas->g_next;
+ t_freebytes(headwas, sizeof(*headwas));
+ lastpopped = x;
+ }
+}
+
+void pd_doloadbang(void)
+{
+ if (lastpopped)
+ pd_vmess(lastpopped, gensym("loadbang"), "");
+ lastpopped = 0;
+}
+
+void pd_bang(t_pd *x)
+{
+ (*(*x)->c_bangmethod)(x);
+}
+
+void pd_float(t_pd *x, t_float f)
+{
+ (*(*x)->c_floatmethod)(x, f);
+}
+
+void pd_pointer(t_pd *x, t_gpointer *gp)
+{
+ (*(*x)->c_pointermethod)(x, gp);
+}
+
+void pd_symbol(t_pd *x, t_symbol *s)
+{
+ (*(*x)->c_symbolmethod)(x, s);
+}
+
+void pd_list(t_pd *x, t_symbol *s, int argc, t_atom *argv)
+{
+ (*(*x)->c_listmethod)(x, &s_list, argc, argv);
+}
+
+void mess_init(void);
+void obj_init(void);
+void conf_init(void);
+void glob_init(void);
+
+void pd_init(void)
+{
+ mess_init();
+ obj_init();
+ conf_init();
+ glob_init();
+}
+
diff --git a/pd/src/m_pd.h b/pd/src/m_pd.h
new file mode 100644
index 00000000..172bf49d
--- /dev/null
+++ b/pd/src/m_pd.h
@@ -0,0 +1,594 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+extern "C" {
+#endif
+
+#ifdef NT
+// #pragma warning( disable : 4091 )
+#pragma warning( disable : 4305 ) /* uncast const double to float */
+#pragma warning( disable : 4244 ) /* uncast float/int conversion etc. */
+#pragma warning( disable : 4101 ) /* unused automatic variables */
+#endif /* NT */
+
+ /* the external storage class is "extern" in UNIX; in NT it's ugly. */
+#ifdef NT
+#ifdef PD_INTERNAL
+#define EXTERN __declspec(dllexport) extern
+#else
+#define EXTERN __declspec(dllimport) extern
+#endif /* PD_INTERNAL */
+#else
+#define EXTERN extern
+#endif /* NT */
+
+ /* and depending on the compiler, hidden data structures are
+ declared differently: */
+#ifdef __GNUC__
+#define EXTERN_STRUCT struct
+#else
+#define EXTERN_STRUCT extern struct
+#endif
+
+
+#if !defined(_SIZE_T) && !defined(_SIZE_T_)
+#include <stddef.h> /* just for size_t -- how lame! */
+#endif
+
+#define MAXPDSTRING 1000 /* use this for anything you want */
+#define MAXPDARG 5 /* max number of args we can typecheck today */
+
+ /* signed and unsigned integer types the size of a pointer: */
+#ifdef __alpha__
+typedef long t_int;
+#else
+typedef int t_int;
+#endif
+
+typedef float t_float; /* a floating-point number at most the same size */
+typedef float t_floatarg; /* floating-point type for function calls */
+
+typedef struct _symbol
+{
+ char *s_name;
+ struct _class **s_thing;
+ struct _symbol *s_next;
+} t_symbol;
+
+EXTERN_STRUCT _array;
+#define t_array struct _array /* g_canvas.h */
+
+/* pointers to glist and array elements go through a "stub" which sticks
+around after the glist or array is freed. The stub itself is deleted when
+both the glist/array is gone and the refcount is zero, ensuring that no
+gpointers are pointing here. */
+
+#define GP_NONE 0 /* the stub points nowhere (has been cut off) */
+#define GP_GLIST 1 /* the stub points to a glist element */
+#define GP_ARRAY 2 /* ... or array */
+
+typedef struct _gstub
+{
+ union
+ {
+ struct _glist *gs_glist; /* glist we're in */
+ struct _array *gs_array; /* array we're in */
+ } gs_un;
+ int gs_which; /* GP_GLIST/GP_ARRAY */
+ int gs_refcount; /* number of gpointers pointing here */
+} t_gstub;
+
+typedef struct _gpointer /* pointer to a gobj in a glist */
+{
+ union
+ {
+ struct _scalar *gp_scalar; /* scalar we're in (if glist) */
+ union word *gp_w; /* raw data (if array) */
+ } gp_un;
+ int gp_valid; /* number which must match gpointee */
+ t_gstub *gp_stub; /* stub which points to glist/array */
+} t_gpointer;
+
+typedef union word
+{
+ t_float w_float;
+ t_symbol *w_symbol;
+ t_gpointer *w_gpointer;
+ t_array *w_array;
+ struct _glist *w_list;
+ int w_index;
+} t_word;
+
+typedef enum
+{
+ A_NULL,
+ A_FLOAT,
+ A_SYMBOL,
+ A_POINTER,
+ A_SEMI,
+ A_COMMA,
+ A_DEFFLOAT,
+ A_DEFSYM,
+ A_DOLLAR,
+ A_DOLLSYM,
+ A_GIMME,
+ A_CANT
+} t_atomtype;
+
+#define A_DEFSYMBOL A_DEFSYM /* better name for this */
+
+typedef struct _atom
+{
+ t_atomtype a_type;
+ union word a_w;
+} t_atom;
+
+EXTERN_STRUCT _class;
+#define t_class struct _class
+
+EXTERN_STRUCT _outlet;
+#define t_outlet struct _outlet
+
+EXTERN_STRUCT _inlet;
+#define t_inlet struct _inlet
+
+EXTERN_STRUCT _binbuf;
+#define t_binbuf struct _binbuf
+
+EXTERN_STRUCT _clock;
+#define t_clock struct _clock
+
+EXTERN_STRUCT _outconnect;
+#define t_outconnect struct _outconnect
+
+EXTERN_STRUCT _glist;
+#define t_glist struct _glist
+#define t_canvas struct _glist /* LATER lose this */
+
+typedef t_class *t_pd; /* pure datum: nothing but a class pointer */
+
+typedef struct _gobj /* a graphical object */
+{
+ t_pd g_pd; /* pure datum header (class) */
+ struct _gobj *g_next; /* next in list */
+} t_gobj;
+
+typedef struct _scalar /* a graphical object holding data */
+{
+ t_gobj sc_gobj; /* header for graphical object */
+ t_symbol *sc_template; /* template name (LATER replace with pointer) */
+ t_word sc_vec[1]; /* indeterminate-length array of words */
+} t_scalar;
+
+typedef struct _text /* patchable object - graphical, with text */
+{
+ t_gobj te_g; /* header for graphical object */
+ t_binbuf *te_binbuf; /* holder for the text */
+ t_outlet *te_outlet; /* linked list of outlets */
+ t_inlet *te_inlet; /* linked list of inlets */
+ short te_xpix; /* x&y location (within the toplevel) */
+ short te_ypix;
+ short te_width; /* requested width in chars, 0 if auto */
+ unsigned int te_type:2; /* from defs below */
+} t_text;
+
+#define T_TEXT 0 /* just a textual comment */
+#define T_OBJECT 1 /* a MAX style patchable object */
+#define T_MESSAGE 2 /* a MAX stype message */
+#define T_ATOM 3 /* a cell to display a number or symbol */
+
+#define te_pd te_g.g_pd
+
+ /* t_object is synonym for t_text (LATER unify them) */
+
+typedef struct _text t_object;
+
+#define ob_outlet te_outlet
+#define ob_inlet te_inlet
+#define ob_binbuf te_binbuf
+#define ob_pd te_g.g_pd
+#define ob_g te_g
+
+typedef void (*t_method)(void);
+typedef void *(*t_newmethod)( void);
+typedef void (*t_gotfn)(void *x, ...);
+
+/* ---------------- pre-defined objects and symbols --------------*/
+EXTERN t_pd pd_objectmaker; /* factory for creating "object" boxes */
+EXTERN t_pd pd_canvasmaker; /* factory for creating canvases */
+EXTERN t_symbol s_pointer;
+EXTERN t_symbol s_float;
+EXTERN t_symbol s_symbol;
+EXTERN t_symbol s_bang;
+EXTERN t_symbol s_list;
+EXTERN t_symbol s_anything;
+EXTERN t_symbol s_signal;
+EXTERN t_symbol s__N;
+EXTERN t_symbol s__X;
+EXTERN t_symbol s_x;
+EXTERN t_symbol s_y;
+EXTERN t_symbol s_;
+
+/* --------- prototypes from the central message system ----------- */
+EXTERN void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN void pd_forwardmess(t_pd *x, int argc, t_atom *argv);
+EXTERN t_symbol *gensym(char *s);
+EXTERN t_gotfn getfn(t_pd *x, t_symbol *s);
+EXTERN t_gotfn zgetfn(t_pd *x, t_symbol *s);
+EXTERN void nullfn(void);
+EXTERN void pd_vmess(t_pd *x, t_symbol *s, char *fmt, ...);
+#define mess0(x, s) ((*getfn((x), (s)))((x)))
+#define mess1(x, s, a) ((*getfn((x), (s)))((x), (a)))
+#define mess2(x, s, a,b) ((*getfn((x), (s)))((x), (a),(b)))
+#define mess3(x, s, a,b,c) ((*getfn((x), (s)))((x), (a),(b),(c)))
+#define mess4(x, s, a,b,c,d) ((*getfn((x), (s)))((x), (a),(b),(c),(d)))
+#define mess5(x, s, a,b,c,d,e) ((*getfn((x), (s)))((x), (a),(b),(c),(d),(e)))
+void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv);
+
+/* --------------- memory management -------------------- */
+EXTERN void *getbytes(size_t nbytes);
+EXTERN void *getzbytes(size_t nbytes);
+EXTERN void *copybytes(void *src, size_t nbytes);
+EXTERN void freebytes(void *x, size_t nbytes);
+EXTERN void *resizebytes(void *x, size_t oldsize, size_t newsize);
+
+/* -------------------- atoms ----------------------------- */
+
+#define SETSEMI(atom) ((atom)->a_type = A_SEMI, (atom)->a_w.w_index = 0)
+#define SETCOMMA(atom) ((atom)->a_type = A_COMMA, (atom)->a_w.w_index = 0)
+#define SETPOINTER(atom, gp) ((atom)->a_type = A_POINTER, \
+ (atom)->a_w.w_gpointer = (gp))
+#define SETFLOAT(atom, f) ((atom)->a_type = A_FLOAT, (atom)->a_w.w_float = (f))
+#define SETSYMBOL(atom, s) ((atom)->a_type = A_SYMBOL, \
+ (atom)->a_w.w_symbol = (s))
+#define SETDOLLAR(atom, n) ((atom)->a_type = A_DOLLAR, \
+ (atom)->a_w.w_index = (n))
+#define SETDOLLSYM(atom, s) ((atom)->a_type = A_DOLLSYM, \
+ (atom)->a_w.w_symbol= (s))
+
+EXTERN t_float atom_getfloat(t_atom *a);
+EXTERN t_int atom_getint(t_atom *a);
+EXTERN t_symbol *atom_getsymbol(t_atom *a);
+EXTERN t_symbol *atom_gensym(t_atom *a);
+EXTERN t_float atom_getfloatarg(int which, int argc, t_atom *argv);
+EXTERN t_int atom_getintarg(int which, int argc, t_atom *argv);
+EXTERN t_symbol *atom_getsymbolarg(int which, int argc, t_atom *argv);
+
+EXTERN void atom_string(t_atom *a, char *buf, unsigned int bufsize);
+
+/* ------------------ binbufs --------------- */
+
+EXTERN t_binbuf *binbuf_new(void);
+EXTERN void binbuf_free(t_binbuf *x);
+
+EXTERN void binbuf_text(t_binbuf *x, char *text, size_t size);
+EXTERN void binbuf_gettext(t_binbuf *x, char **bufp, int *lengthp);
+EXTERN void binbuf_clear(t_binbuf *x);
+EXTERN void binbuf_add(t_binbuf *x, int argc, t_atom *argv);
+EXTERN void binbuf_addv(t_binbuf *x, char *fmt, ...);
+EXTERN void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y);
+EXTERN void binbuf_addsemi(t_binbuf *x);
+EXTERN void binbuf_restore(t_binbuf *x, int argc, t_atom *argv);
+EXTERN void binbuf_print(t_binbuf *x);
+EXTERN int binbuf_getnatom(t_binbuf *x);
+EXTERN t_atom *binbuf_getvec(t_binbuf *x);
+EXTERN void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv);
+EXTERN int binbuf_read(t_binbuf *b, char *filename, char *dirname,
+ int crflag);
+EXTERN int binbuf_read_via_path(t_binbuf *b, char *filename, char *dirname,
+ int crflag);
+EXTERN int binbuf_write(t_binbuf *x, char *filename, char *dir,
+ int crflag);
+EXTERN void binbuf_evalfile(t_symbol *name, t_symbol *dir);
+
+/* ------------------ clocks --------------- */
+
+EXTERN t_clock *clock_new(void *owner, t_method fn);
+EXTERN void clock_set(t_clock *x, double systime);
+EXTERN void clock_delay(t_clock *x, double delaytime);
+EXTERN void clock_unset(t_clock *x);
+EXTERN double clock_getlogicaltime(void);
+EXTERN double clock_getsystime(void); /* OBSOLETE; use clock_getlogicaltime() */
+EXTERN double clock_gettimesince(double prevsystime);
+EXTERN double clock_getsystimeafter(double delaytime);
+EXTERN void clock_free(t_clock *x);
+
+/* ----------------- pure data ---------------- */
+EXTERN t_pd *pd_new(t_class *cls);
+EXTERN void pd_free(t_pd *x);
+EXTERN void pd_bind(t_pd *x, t_symbol *s);
+EXTERN void pd_unbind(t_pd *x, t_symbol *s);
+EXTERN t_pd *pd_findbyclass(t_symbol *s, t_class *c);
+EXTERN void pd_pushsym(t_pd *x);
+EXTERN void pd_popsym(t_pd *x);
+EXTERN t_symbol *pd_getfilename(void);
+EXTERN t_symbol *pd_getdirname(void);
+EXTERN void pd_bang(t_pd *x);
+EXTERN void pd_pointer(t_pd *x, t_gpointer *gp);
+EXTERN void pd_float(t_pd *x, t_float f);
+EXTERN void pd_symbol(t_pd *x, t_symbol *s);
+EXTERN void pd_list(t_pd *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN void pd_anything(t_pd *x, t_symbol *s, int argc, t_atom *argv);
+#define pd_class(x) (*(x))
+
+/* ----------------- pointers ---------------- */
+EXTERN void gpointer_init(t_gpointer *gp);
+EXTERN void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto);
+EXTERN void gpointer_unset(t_gpointer *gp);
+EXTERN int gpointer_check(const t_gpointer *gp, int headok);
+
+/* ----------------- patchable "objects" -------------- */
+EXTERN_STRUCT _inlet;
+#define t_inlet struct _inlet
+EXTERN_STRUCT _outlet;
+#define t_outlet struct _outlet
+
+EXTERN t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1,
+ t_symbol *s2);
+EXTERN t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp);
+EXTERN t_inlet *floatinlet_new(t_object *owner, t_float *fp);
+EXTERN t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp);
+EXTERN void inlet_free(t_inlet *x);
+
+EXTERN t_outlet *outlet_new(t_object *owner, t_symbol *s);
+EXTERN void outlet_bang(t_outlet *x);
+EXTERN void outlet_pointer(t_outlet *x, t_gpointer *gp);
+EXTERN void outlet_float(t_outlet *x, t_float f);
+EXTERN void outlet_symbol(t_outlet *x, t_symbol *s);
+EXTERN void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN void outlet_free(t_outlet *x);
+EXTERN t_object *pd_checkobject(t_pd *x);
+
+
+/* -------------------- canvases -------------- */
+
+EXTERN void glob_setfilename(void *dummy, t_symbol *name, t_symbol *dir);
+
+EXTERN void canvas_setargs(int argc, t_atom *argv);
+EXTERN t_atom *canvas_getarg(int which);
+EXTERN t_symbol *canvas_getcurrentdir(void);
+EXTERN t_glist *canvas_getcurrent(void);
+EXTERN void canvas_makefilename(t_glist *c, char *file,
+ char *result,int resultsize);
+EXTERN t_symbol *canvas_getdir(t_glist *x);
+EXTERN int sys_fontwidth(int fontsize);
+EXTERN int sys_fontheight(int fontsize);
+EXTERN void canvas_dataproperties(t_glist *x, t_scalar *sc, t_binbuf *b);
+
+/* ---------------- widget behaviors ---------------------- */
+
+EXTERN_STRUCT _widgetbehavior;
+#define t_widgetbehavior struct _widgetbehavior
+
+EXTERN_STRUCT _parentwidgetbehavior;
+#define t_parentwidgetbehavior struct _parentwidgetbehavior
+EXTERN t_parentwidgetbehavior *pd_getparentwidget(t_pd *x);
+
+/* -------------------- classes -------------- */
+
+#define CLASS_DEFAULT 0 /* flags for new classes below */
+#define CLASS_PD 1
+#define CLASS_GOBJ 2
+#define CLASS_PATCHABLE 3
+#define CLASS_NOINLET 8
+
+#define CLASS_TYPEMASK 3
+
+
+EXTERN t_class *class_new(t_symbol *name, t_newmethod newmethod,
+ t_method freemethod, size_t size, int flags, t_atomtype arg1, ...);
+EXTERN void class_addcreator(t_newmethod newmethod, t_symbol *s,
+ t_atomtype type1, ...);
+EXTERN void class_addmethod(t_class *c, t_method fn, t_symbol *sel,
+ t_atomtype arg1, ...);
+EXTERN void class_addbang(t_class *c, t_method fn);
+EXTERN void class_addpointer(t_class *c, t_method fn);
+EXTERN void class_doaddfloat(t_class *c, t_method fn);
+EXTERN void class_addsymbol(t_class *c, t_method fn);
+EXTERN void class_addlist(t_class *c, t_method fn);
+EXTERN void class_addanything(t_class *c, t_method fn);
+EXTERN void class_sethelpsymbol(t_class *c, t_symbol *s);
+EXTERN void class_setwidget(t_class *c, t_widgetbehavior *w);
+EXTERN void class_setparentwidget(t_class *c, t_parentwidgetbehavior *w);
+EXTERN t_parentwidgetbehavior *class_parentwidget(t_class *c);
+EXTERN char *class_getname(t_class *c);
+EXTERN char *class_gethelpname(t_class *c);
+EXTERN void class_setdrawcommand(t_class *c);
+EXTERN int class_isdrawcommand(t_class *c);
+EXTERN void class_domainsignalin(t_class *c, int onset);
+#define CLASS_MAINSIGNALIN(c, type, field) \
+ class_domainsignalin(c, (char *)(&((type *)0)->field) - (char *)0)
+
+#ifndef PD_CLASS_DEF
+#define class_addbang(x, y) class_addbang((x), (t_method)(y))
+#define class_addpointer(x, y) class_addpointer((x), (t_method)(y))
+#define class_addfloat(x, y) class_doaddfloat((x), (t_method)(y))
+#define class_addsymbol(x, y) class_addsymbol((x), (t_method)(y))
+#define class_addlist(x, y) class_addlist((x), (t_method)(y))
+#define class_addanything(x, y) class_addanything((x), (t_method)(y))
+#endif
+
+/* ------------ printing --------------------------------- */
+EXTERN void post(char *fmt, ...);
+EXTERN void startpost(char *fmt, ...);
+EXTERN void poststring(char *s);
+EXTERN void postfloat(float f);
+EXTERN void postatom(int argc, t_atom *argv);
+EXTERN void endpost(void);
+EXTERN void error(char *fmt, ...);
+EXTERN void bug(char *fmt, ...);
+EXTERN void pd_error(void *object, char *fmt, ...);
+EXTERN void sys_logerror(char *object, char *s);
+EXTERN void sys_unixerror(char *object);
+EXTERN void sys_ouch(void);
+
+#ifdef __linux__
+EXTERN char* sys_get_path( void);
+#endif
+EXTERN void sys_addpath(const char* p);
+
+
+/* ------------ system interface routines ------------------- */
+EXTERN int sys_isreadablefile(const char *name);
+EXTERN void sys_bashfilename(const char *from, char *to);
+EXTERN void sys_unbashfilename(const char *from, char *to);
+EXTERN int open_via_path(const char *name, const char *ext, const char *dir,
+ char *dirresult, char **nameresult, unsigned int size, int bin);
+EXTERN int sys_geteventno(void);
+EXTERN double sys_getrealtime(void);
+
+/* --------------- signals ----------------------------------- */
+
+typedef float t_sample;
+#define MAXLOGSIG 32
+#define MAXSIGSIZE (1 << MAXLOGSIG)
+
+typedef struct _signal
+{
+ int s_n; /* number of points in the array */
+ t_sample *s_vec; /* the array */
+ float s_sr; /* sample rate */
+ int s_refcount; /* number of times used */
+ int s_isborrowed; /* whether we're going to borrow our array */
+ struct _signal *s_borrowedfrom; /* signal to borrow it from */
+ struct _signal *s_nextfree; /* next in freelist */
+ struct _signal *s_nextused; /* next in used list */
+} t_signal;
+
+
+typedef t_int *(*t_perfroutine)(t_int *args);
+
+EXTERN t_int *plus_perform(t_int *args);
+EXTERN t_int *zero_perform(t_int *args);
+EXTERN t_int *copy_perform(t_int *args);
+
+EXTERN void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n);
+EXTERN void dsp_add_copy(t_sample *in, t_sample *out, int n);
+EXTERN void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n);
+EXTERN void dsp_add_zero(t_sample *out, int n);
+
+EXTERN int sys_getblksize(void);
+EXTERN float sys_getsr(void);
+EXTERN int sys_get_inchannels(void);
+EXTERN int sys_get_outchannels(void);
+
+EXTERN void dsp_add(t_perfroutine f, int n, ...);
+EXTERN void dsp_addv(t_perfroutine f, int n, t_int *vec);
+EXTERN void pd_fft(float *buf, int npoints, int inverse);
+EXTERN int ilog2(int n);
+
+EXTERN void mayer_fht(float *fz, int n);
+EXTERN void mayer_fft(int n, float *real, float *imag);
+EXTERN void mayer_ifft(int n, float *real, float *imag);
+EXTERN void mayer_realfft(int n, float *real);
+EXTERN void mayer_realifft(int n, float *real);
+
+EXTERN float *cos_table;
+#define LOGCOSTABSIZE 9
+#define COSTABSIZE (1<<LOGCOSTABSIZE)
+
+EXTERN int canvas_suspend_dsp(void);
+EXTERN void canvas_resume_dsp(int oldstate);
+EXTERN void canvas_update_dsp(void);
+
+/* IOhannes { (up/downsampling) */
+typedef struct _resample
+{
+ int method; /* up/downsampling method ID */
+
+ t_int downsample; /* downsampling factor */
+ t_int upsample; /* upsampling factor */
+
+ t_float *s_vec; /* here we hold the resampled data */
+ int s_n;
+
+ t_float *coeffs; /* coefficients for filtering... */
+ int coefsize;
+
+ t_float *buffer; /* buffer for filtering */
+ int bufsize;
+} t_resample;
+
+EXTERN void resample_init(t_resample *x);
+EXTERN void resample_free(t_resample *x);
+
+EXTERN void resample_dsp(t_resample *x, t_sample *in, int insize, t_sample *out, int outsize, int method);
+EXTERN void resamplefrom_dsp(t_resample *x, t_sample *in, int insize, int outsize, int method);
+EXTERN void resampleto_dsp(t_resample *x, t_sample *out, int insize, int outsize, int method);
+/* } IOhannes */
+
+/* ----------------------- utility functions for signals -------------- */
+EXTERN float mtof(float);
+EXTERN float ftom(float);
+EXTERN float rmstodb(float);
+EXTERN float powtodb(float);
+EXTERN float dbtorms(float);
+EXTERN float dbtopow(float);
+
+EXTERN float q8_sqrt(float);
+EXTERN float q8_rsqrt(float);
+#ifndef N32
+EXTERN float qsqrt(float); /* old names kept for extern compatibility */
+EXTERN float qrsqrt(float);
+#endif
+/* --------------------- data --------------------------------- */
+
+ /* graphical arrays */
+EXTERN_STRUCT _garray;
+#define t_garray struct _garray
+
+EXTERN t_class *garray_class;
+EXTERN int garray_getfloatarray(t_garray *x, int *size, t_float **vec);
+EXTERN float garray_get(t_garray *x, t_symbol *s, t_int indx);
+EXTERN void garray_redraw(t_garray *x);
+EXTERN int garray_npoints(t_garray *x);
+EXTERN char *garray_vec(t_garray *x);
+EXTERN void garray_resize(t_garray *x, t_floatarg f);
+EXTERN void garray_usedindsp(t_garray *x);
+EXTERN void garray_setsaveit(t_garray *x, int saveit);
+EXTERN t_class *scalar_class;
+
+EXTERN t_float *value_get(t_symbol *s);
+EXTERN void value_release(t_symbol *s);
+EXTERN int value_getfloat(t_symbol *s, t_float *f);
+EXTERN int value_setfloat(t_symbol *s, t_float f);
+
+/* ------- GUI interface - functions to send strings to TK --------- */
+EXTERN void sys_vgui(char *fmt, ...);
+EXTERN void sys_gui(char *s);
+
+EXTERN void gfxstub_new(t_pd *owner, void *key, const char *cmd);
+EXTERN void gfxstub_deleteforkey(void *key);
+
+/*------------- Max 0.26 compatibility --------------------*/
+
+/* the following reflects the new way classes are laid out, with the class
+ pointing to the messlist and not vice versa. Externs shouldn't feel it. */
+typedef t_class *t_externclass;
+
+EXTERN void c_extern(t_externclass *cls, t_newmethod newroutine,
+ t_method freeroutine, t_symbol *name, size_t size, int tiny, \
+ t_atomtype arg1, ...);
+EXTERN void c_addmess(t_method fn, t_symbol *sel, t_atomtype arg1, ...);
+
+#define t_getbytes getbytes
+#define t_freebytes freebytes
+#define t_resizebytes resizebytes
+#define typedmess pd_typedmess
+#define vmess pd_vmess
+
+#ifdef MACOSX
+#define cabs() smerdyakov(void)
+#endif
+
+/* A definition to help gui objects straddle 0.34-0.35 changes. If this is
+defined, there is a "te_xpix" field in objects, not a "te_xpos" as before: */
+
+#define PD_USE_TE_XPIX
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+}
+#endif
diff --git a/pd/src/m_sched.c b/pd/src/m_sched.c
new file mode 100644
index 00000000..514e6f8b
--- /dev/null
+++ b/pd/src/m_sched.c
@@ -0,0 +1,462 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* scheduling stuff */
+
+#include "m_imp.h"
+
+ /* LATER consider making this variable. It's now the LCM of all sample
+ rates we expect to see: 32000, 44100, 48000, 88200, 96000. */
+#define TIMEUNITPERSEC (32.*441000.)
+
+static int sys_quit;
+static double sys_time;
+static double sys_time_per_dsp_tick;
+static double sys_time_per_msec;
+
+int sys_usecsincelastsleep(void);
+int sys_sleepgrain;
+
+typedef void (*t_clockmethod)(void *client);
+
+struct _clock
+{
+ double c_settime;
+ void *c_owner;
+ t_clockmethod c_fn;
+ struct _clock *c_next;
+};
+
+t_clock *clock_setlist;
+
+#ifdef UNIX
+#include <unistd.h>
+#endif
+
+t_clock *clock_new(void *owner, t_method fn)
+{
+ t_clock *x = (t_clock *)getbytes(sizeof *x);
+ x->c_settime = -1;
+ x->c_owner = owner;
+ x->c_fn = (t_clockmethod)fn;
+ x->c_next = 0;
+ return (x);
+}
+
+void clock_unset(t_clock *x)
+{
+ if (x->c_settime >= 0)
+ {
+ if (x == clock_setlist) clock_setlist = x->c_next;
+ else
+ {
+ t_clock *x2 = clock_setlist;
+ while (x2->c_next != x) x2 = x2->c_next;
+ x2->c_next = x->c_next;
+ }
+ x->c_settime = -1;
+ }
+}
+
+ /* set the clock to call back at an absolute system time */
+void clock_set(t_clock *x, double setticks)
+{
+ if (setticks < sys_time) setticks = sys_time;
+ clock_unset(x);
+ x->c_settime = setticks;
+ if (clock_setlist && clock_setlist->c_settime <= setticks)
+ {
+ t_clock *cbefore, *cafter;
+ for (cbefore = clock_setlist, cafter = clock_setlist->c_next;
+ cbefore; cbefore = cafter, cafter = cbefore->c_next)
+ {
+ if (!cafter || cafter->c_settime > setticks)
+ {
+ cbefore->c_next = x;
+ x->c_next = cafter;
+ return;
+ }
+ }
+ }
+ else x->c_next = clock_setlist, clock_setlist = x;
+}
+
+ /* set the clock to call back after a delay in msec */
+void clock_delay(t_clock *x, double delaytime)
+{
+ clock_set(x, sys_time + sys_time_per_msec * delaytime);
+}
+
+ /* get current logical time. We don't specify what units this is in;
+ use clock_gettimesince() to measure intervals from time of this call.
+ This was previously, incorrectly named "clock_getsystime"; the old
+ name is aliased to the new one in m_pd.h. */
+double clock_getlogicaltime( void)
+{
+ return (sys_time);
+}
+ /* OBSOLETE NAME */
+double clock_getsystime( void) { return (sys_time); }
+
+ /* elapsed time in milliseconds since the given system time */
+double clock_gettimesince(double prevsystime)
+{
+ return ((sys_time - prevsystime)/sys_time_per_msec);
+}
+
+ /* what value the system clock will have after a delay */
+double clock_getsystimeafter(double delaytime)
+{
+ return (sys_time + sys_time_per_msec * delaytime);
+}
+
+void clock_free(t_clock *x)
+{
+ clock_unset(x);
+ freebytes(x, sizeof *x);
+}
+
+/* the following routines maintain a real-execution-time histogram of the
+various phases of real-time execution. */
+
+static int sys_bin[] = {0, 2, 5, 10, 20, 30, 50, 100, 1000};
+#define NBIN (sizeof(sys_bin)/sizeof(*sys_bin))
+#define NHIST 10
+static int sys_histogram[NHIST][NBIN];
+static double sys_histtime;
+static int sched_diddsp, sched_didmidi, sched_didpoll, sched_didnothing;
+
+static void sys_clearhist( void)
+{
+ unsigned int i, j;
+ for (i = 0; i < NHIST; i++)
+ for (j = 0; j < NBIN; j++) sys_histogram[i][j] = 0;
+ sys_histtime = sys_getrealtime();
+ sched_diddsp = sched_didmidi = sched_didpoll = sched_didnothing = 0;
+}
+
+void sys_printhist( void)
+{
+ unsigned int i, j;
+ for (i = 0; i < NHIST; i++)
+ {
+ int doit = 0;
+ for (j = 0; j < NBIN; j++) if (sys_histogram[i][j]) doit = 1;
+ if (doit)
+ {
+ post("%2d %8d %8d %8d %8d %8d %8d %8d %8d", i,
+ sys_histogram[i][0],
+ sys_histogram[i][1],
+ sys_histogram[i][2],
+ sys_histogram[i][3],
+ sys_histogram[i][4],
+ sys_histogram[i][5],
+ sys_histogram[i][6],
+ sys_histogram[i][7]);
+ }
+ }
+ post("dsp %d, midi %d, poll %d, nothing %d",
+ sched_diddsp, sched_didmidi, sched_didpoll, sched_didnothing);
+}
+
+static int sys_histphase;
+
+int sys_addhist(int phase)
+{
+ int i, j, phasewas = sys_histphase;
+ double newtime = sys_getrealtime();
+ int msec = (newtime - sys_histtime) * 1000.;
+ for (j = NBIN-1; j >= 0; j--)
+ {
+ if (msec >= sys_bin[j])
+ {
+ sys_histogram[phasewas][j]++;
+ break;
+ }
+ }
+ sys_histtime = newtime;
+ sys_histphase = phase;
+ return (phasewas);
+}
+
+#define NRESYNC 20
+
+typedef struct _resync
+{
+ int r_ntick;
+ int r_error;
+} t_resync;
+
+static int oss_resyncphase = 0;
+static int oss_nresync = 0;
+static t_resync oss_resync[NRESYNC];
+
+#ifdef __linux__
+void linux_audiostatus(void);
+#endif
+
+static char *(oss_errornames[]) = {
+"unknown",
+"ADC blocked",
+"DAC blocked",
+"A/D/A sync",
+"data late"
+};
+
+void glob_audiostatus(void)
+{
+ int dev, nresync, nresyncphase, i;
+#ifdef __linux__
+ linux_audiostatus();
+#endif
+ nresync = (oss_nresync >= NRESYNC ? NRESYNC : oss_nresync);
+ nresyncphase = oss_resyncphase - 1;
+ post("audio I/O error history:");
+ post("seconds ago\terror type");
+ for (i = 0; i < nresync; i++)
+ {
+ int errtype;
+ if (nresyncphase < 0)
+ nresyncphase += NRESYNC;
+ errtype = oss_resync[nresyncphase].r_error;
+ if (errtype < 0 || errtype > 4)
+ errtype = 0;
+
+ post("%9.2f\t%s",
+ (sched_diddsp - oss_resync[nresyncphase].r_ntick)
+ * ((double)DACBLKSIZE) / sys_dacsr,
+ oss_errornames[errtype]);
+ nresyncphase--;
+ }
+}
+
+static int sched_diored;
+static int sched_dioredtime;
+static int sched_meterson;
+
+void sys_log_error(int type)
+{
+ oss_resync[oss_resyncphase].r_ntick = sched_diddsp;
+ oss_resync[oss_resyncphase].r_error = type;
+ oss_nresync++;
+ if (++oss_resyncphase == NRESYNC) oss_resyncphase = 0;
+ if (type != ERR_NOTHING && !sched_diored)
+ {
+ sys_vgui("pdtk_pd_dio 1\n");
+ sched_diored = 1;
+ }
+ sched_dioredtime =
+ sched_diddsp + (int)(sys_dacsr /(double)DACBLKSIZE);
+}
+
+static int sched_lastinclip, sched_lastoutclip,
+ sched_lastindb, sched_lastoutdb;
+
+void glob_ping(t_pd *dummy);
+
+static void sched_pollformeters( void)
+{
+ int inclip, outclip, indb, outdb;
+ static int sched_nextmeterpolltime, sched_nextpingtime;
+
+ /* if there's no GUI but we're running in "realtime", here is
+ where we arrange to ping the watchdog every 2 seconds. */
+#ifdef UNIX
+ if (sys_nogui && sys_hipriority && (sched_diddsp - sched_nextpingtime > 0))
+ {
+ glob_ping(0);
+ /* ping every 2 seconds */
+ sched_nextpingtime = sched_diddsp +
+ 2 * (int)(sys_dacsr /(double)DACBLKSIZE);
+ }
+#endif
+
+ if (sched_diddsp - sched_nextmeterpolltime < 0)
+ return;
+ if (sched_diored && (sched_diddsp - sched_dioredtime > 0))
+ {
+ sys_vgui("pdtk_pd_dio 0\n");
+ sched_diored = 0;
+ }
+ if (sched_meterson)
+ {
+ float inmax, outmax;
+ sys_getmeters(&inmax, &outmax);
+ indb = 0.5 + rmstodb(inmax);
+ outdb = 0.5 + rmstodb(outmax);
+ inclip = (inmax > 0.999);
+ outclip = (outmax >= 1.0);
+ }
+ else
+ {
+ indb = outdb = 0;
+ inclip = outclip = 0;
+ }
+ if (inclip != sched_lastinclip || outclip != sched_lastoutclip
+ || indb != sched_lastindb || outdb != sched_lastoutdb)
+ {
+ sys_vgui("pdtk_pd_meters %d %d %d %d\n", indb, outdb, inclip, outclip);
+ sched_lastinclip = inclip;
+ sched_lastoutclip = outclip;
+ sched_lastindb = indb;
+ sched_lastoutdb = outdb;
+ }
+ sched_nextmeterpolltime =
+ sched_diddsp + (int)(sys_dacsr /(double)DACBLKSIZE);
+}
+
+void glob_meters(void *dummy, float f)
+{
+ if (f == 0)
+ sys_getmeters(0, 0);
+ sched_meterson = (f != 0);
+ sched_lastinclip = sched_lastoutclip = sched_lastindb = sched_lastoutdb =
+ -1;
+}
+
+#if 1
+void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
+{
+ if (argc) sys_clearhist();
+ else sys_printhist();
+}
+#endif
+
+void dsp_tick(void);
+
+static int m_nodacs = 0;
+
+ /* this must be called earlier than any patches are loaded */
+void m_schedsetsr( void)
+{
+ sys_time_per_dsp_tick =
+ (TIMEUNITPERSEC) * ((double)DACBLKSIZE) / sys_dacsr;
+ sys_time_per_msec =
+ TIMEUNITPERSEC / 1000.;
+}
+
+/*
+Here is Pd's "main loop." This routine dispatches clock timeouts and DSP
+"ticks" deterministically, and polls for input from MIDI and the GUI. If
+we're left idle we also poll for graphics updates; but these are considered
+lower priority than the rest.
+
+The time source is normally the audio I/O subsystem via the "sys_send_dacs()"
+call. This call returns true if samples were transferred; false means that
+the audio I/O system is still bussy with previous transfers.
+The sys_send_dacs call is OS dependent and is variously implemented in
+s_linux.c, s_nt.c, and s_sgi.c.
+*/
+
+void sys_pollmidiqueue( void);
+void sys_initmidiqueue( void);
+
+int m_scheduler(int nodacs)
+{
+ int lasttimeforward = SENDDACS_YES;
+ int idlecount = 0;
+ double lastdactime = 0;
+ sys_clearhist();
+ m_nodacs = nodacs;
+ if (sys_sleepgrain < 1000)
+ sys_sleepgrain = (sys_schedadvance >= 4000?
+ (sys_schedadvance >> 2) : 1000);
+ sys_initmidiqueue();
+ while (1)
+ {
+ int didsomething = 0;
+ int timeforward;
+
+ sys_addhist(0);
+ if (m_nodacs)
+ {
+ double elapsed = sys_getrealtime() - lastdactime;
+ static double next = 0;
+ if (elapsed > next)
+ {
+ timeforward = SENDDACS_YES;
+ next += (double)DACBLKSIZE / sys_dacsr;
+ }
+ else timeforward = SENDDACS_NO;
+ }
+ else
+ {
+ timeforward = sys_send_dacs();
+
+ /* if dacs remain "idle" for 1 sec, they're hung up. */
+ if (timeforward != 0) idlecount = 0;
+ else
+ {
+ idlecount++;
+ if (!(idlecount & 31))
+ {
+ static double idletime;
+ /* on 32nd idle, start a clock watch; every
+ 32 ensuing idles, check it */
+ if (idlecount == 32)
+ idletime = sys_getrealtime();
+ else if (sys_getrealtime() - idletime > 1.)
+ {
+ post("audio I/O stuck... closing audio\n");
+ m_nodacs = 1;
+ sys_close_audio();
+ lastdactime = sys_getrealtime();
+ }
+ }
+ }
+ }
+ sys_setmiditimediff(0, 1e-6 * sys_schedadvance);
+ lasttimeforward = timeforward;
+ sys_addhist(1);
+ if (timeforward != SENDDACS_NO)
+ {
+ /* time has moved forward. Check MIDI and clocks */
+
+ double next_sys_time = sys_time + sys_time_per_dsp_tick;
+ int countdown = 5000;
+ while (clock_setlist && clock_setlist->c_settime < next_sys_time)
+ {
+ t_clock *c = clock_setlist;
+ sys_time = c->c_settime;
+ clock_unset(clock_setlist);
+ outlet_setstacklim();
+ (*c->c_fn)(c->c_owner);
+ if (!countdown--)
+ {
+ countdown = 5000;
+ sys_pollgui();
+ }
+ }
+ sys_time = next_sys_time;
+ if (sys_quit) break;
+ dsp_tick();
+ if (timeforward != SENDDACS_SLEPT)
+ didsomething = 1;
+ sched_diddsp++;
+ }
+
+ sys_addhist(2);
+ sys_pollmidiqueue();
+ if (sys_pollgui())
+ {
+ if (!didsomething)
+ sched_didpoll++;
+ didsomething = 1;
+ }
+ sys_addhist(3);
+ /* test for idle; if so, do graphics updates. */
+ if (!didsomething)
+ {
+ sched_pollformeters();
+ sys_reportidle();
+ if (timeforward != SENDDACS_SLEPT)
+ sys_microsleep(sys_sleepgrain);
+ sys_addhist(5);
+ sched_didnothing++;
+ }
+ }
+ return (0);
+}
+
+
diff --git a/pd/src/makefile b/pd/src/makefile
new file mode 100644
index 00000000..62e5f34b
--- /dev/null
+++ b/pd/src/makefile
@@ -0,0 +1,3 @@
+all:
+ ./configure
+ make
diff --git a/pd/src/makefile.clean b/pd/src/makefile.clean
new file mode 100644
index 00000000..62e5f34b
--- /dev/null
+++ b/pd/src/makefile.clean
@@ -0,0 +1,3 @@
+all:
+ ./configure
+ make
diff --git a/pd/src/makefile.dependencies b/pd/src/makefile.dependencies
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/pd/src/makefile.dependencies
diff --git a/pd/src/makefile.in b/pd/src/makefile.in
new file mode 100644
index 00000000..b7eb1104
--- /dev/null
+++ b/pd/src/makefile.in
@@ -0,0 +1,233 @@
+#
+#
+#
+
+VPATH = ../obj:./
+OBJ_DIR = ../obj
+BIN_DIR = ../bin
+PDEXEC = $(BIN_DIR)/pd
+EXT= @EXT@
+GUINAME= @GUINAME@
+
+INSTALL_PREFIX = @prefix@
+GFLAGS = -DINSTALL_PREFIX=\"$(INSTALL_PREFIX)\"
+
+# ALSA compilation
+
+SOUND_ALSA = @alsa@
+
+# RME compilation
+
+SOUND_RME = @rme@
+
+DEFINES = @DEFINES@
+MORECFLAGS = @MORECFLAGS@
+
+INCLUDE = -I.
+GINCLUDE = $(INCLUDE) @GUIFLAGS@
+GLIB = @LIBS@
+
+LDFLAGS = @LDFLAGS@
+LIB = @PDLIB@
+
+#select either the DBG and OPT compiler flags below:
+OPT_CFLAGS = @OPT_CFLAGS@
+WARN_CFLAGS = -Wall -W -Wstrict-prototypes -Werror \
+ -Wno-unused -Wno-parentheses -Wno-switch
+ARCH_CFLAGS = -DPD -DUNIX
+
+CFLAGS = $(ARCH_CFLAGS) $(WARN_CFLAGS) $(OPT_CFLAGS) $(DEFINES) $(MORECFLAGS)
+
+# you might want ALSA linked in non-shared because
+# many Linux machines don't have the ALSA shared library. To link
+# ALSA non-shared, move the # sign below.
+
+ifeq (${SOUND_ALSA},yes)
+CFLAGS += -DALSA01
+#LIB += /usr/lib/libasound.a
+#LIB += -lasound
+endif
+
+ifeq (${SOUND_ALSA},old)
+CFLAGS += -DALSA99
+#LIB += /usr/lib/libasound.a
+#LIB += -lasound
+endif
+
+ifeq (${SOUND_RME},yes)
+CFLAGS += -DRME_HAMMERFALL
+endif
+
+
+# Which system
+
+SYSTEM = $(shell uname -m)
+
+ifeq (${SYSTEM},alpha)
+#LIB += -lffm -lm
+CFLAGS += -mieee -mcpu=ev56
+endif
+
+# Which compiler
+
+ifeq (${CC},ccc)
+CFLAGS += -g3 -D__COMPAQC__ -arch host
+endif
+
+# the sources
+
+SYSSRC = @SYSSRC@
+
+SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \
+ g_scalar.c g_traversal.c g_guiconnect.c g_readwrite.c g_editor.c \
+ g_all_guis.c g_bang.c g_hdial.c g_hslider.c g_mycanvas.c g_numbox.c \
+ g_toggle.c g_vdial.c g_vslider.c g_vumeter.c \
+ m_pd.c m_class.c m_obj.c m_atom.c m_memory.c m_binbuf.c \
+ m_conf.c m_glob.c m_sched.c \
+ s_main.c s_inter.c s_unix.c s_file.c s_print.c \
+ s_loader.c s_path.c s_entry.c \
+ d_ugen.c d_ctl.c d_arithmetic.c d_osc.c d_filter.c d_dac.c d_misc.c \
+ d_math.c d_fft.c d_mayer_fft.c d_fftroutine.c d_array.c d_global.c \
+ d_delay.c d_resample.c \
+ x_arithmetic.c x_connective.c x_interface.c x_midi.c x_misc.c \
+ x_time.c x_acoustics.c x_net.c x_qlist.c x_gui.c d_soundfile.c \
+ $(SYSSRC)
+
+
+OBJ = $(SRC:.c=.o)
+EXTERNS = ../extra/*/*.$(EXT)
+
+GSRC = t_main.c t_tkcmd.c
+
+GOBJ = $(GSRC:.c=.o)
+
+#
+# ------------------ targets ------------------------------------
+#
+
+.PHONY: pd gui externs
+
+all: $(PDEXEC) $(BIN_DIR)/pd-watchdog $(BIN_DIR)/$(GUINAME) $(BIN_DIR)/pdsend \
+ $(BIN_DIR)/pdreceive $(BIN_DIR)/pd.tk externs
+
+bin: $(PDEXEC) $(BIN_DIR)/pd-watchdog $(BIN_DIR)/$(GUINAME) $(BIN_DIR)/pdsend \
+ $(BIN_DIR)/pdreceive $(BIN_DIR)/pd.tk
+
+$(OBJ) : %.o : %.c
+ $(CC) $(CFLAGS) $(GFLAGS) $(INCLUDE) -c -o $(OBJ_DIR)/$*.o $*.c
+
+$(GOBJ) : %.o : %.c
+ $(CC) $(CFLAGS) $(GFLAGS) $(GINCLUDE) -c -o $(OBJ_DIR)/$*.o $*.c
+
+pd: $(PDEXEC)
+
+gui: $(BIN_DIR)/$(GUINAME)
+
+pd-watchdog: $(BIN_DIR)/pd-watchdog
+
+$(BIN_DIR)/pd-watchdog: s_watchdog.c
+ cc -O2 $(STRIPFLAG) -o $(BIN_DIR)/pd-watchdog s_watchdog.c
+
+$(BIN_DIR)/pdsend: u_pdsend.c
+ cc $(CFLAGS) $(STRIPFLAG) -o $(BIN_DIR)/pdsend u_pdsend.c
+
+$(BIN_DIR)/pdreceive: u_pdreceive.c
+ cc $(CFLAGS) $(STRIPFLAG) -o $(BIN_DIR)/pdreceive u_pdreceive.c
+
+$(PDEXEC): $(OBJ)
+ cd ../obj; $(CC) $(LDFLAGS) $(DBG_CFLAGS) -o $(PDEXEC) $(OBJ) \
+ $(LIB)
+
+$(BIN_DIR)/pd-gui: $(GOBJ) $(GSRC)
+ cd ../obj; $(CC) $(INCLUDE) -o $(BIN_DIR)/$(GUINAME) $(GOBJ) \
+ $(GLIB)
+
+$(BIN_DIR)/pd.tk: u_main.tk
+ echo set pd_nt @OSNUMBER@ > $(BIN_DIR)/pd.tk
+ grep -v "set pd_nt" < u_main.tk >> $(BIN_DIR)/pd.tk
+
+#this is for Max OSX only...
+$(BIN_DIR)/pdtcl: $(GOBJ) $(GSRC)
+ cd ../obj; libtool -dynamic -o $(BIN_DIR)/pdtcl $(GOBJ) \
+ /Library/Frameworks/Tk.framework/Versions/Current/Tk \
+ /Library/Frameworks/Tcl.framework/Versions/Current/Tcl \
+ /usr/lib/libSystem.B.dylib
+
+externs:
+ cd ../extra/bonk~;make @EXTERNTARGET@
+ cd ../extra/choice;make @EXTERNTARGET@
+ cd ../extra/expr~;make @EXTERNTARGET@
+ cd ../extra/fiddle~;make @EXTERNTARGET@
+ cd ../extra/loop~;make @EXTERNTARGET@
+ cd ../extra/lrshift~;make @EXTERNTARGET@
+ cd ../extra/paf~;make @EXTERNTARGET@
+ cd ../extra/pique;make @EXTERNTARGET@
+
+INSTDIR = $(DESTDIR)/$(INSTALL_PREFIX)
+install:
+ install -d $(INSTDIR)/lib/pd/bin
+ install $(BIN_DIR)/$(GUINAME) $(INSTDIR)/lib/pd/bin/$(GUINAME)
+ install $(BIN_DIR)/pd-watchdog $(INSTDIR)/lib/pd/bin/pd-watchdog
+ install -m644 $(BIN_DIR)/pd.tk $(INSTDIR)/lib/pd/bin/pd.tk
+ install -d $(INSTDIR)/bin
+ install -m755 $(PDEXEC) $(INSTDIR)/bin/pd
+ install -m 755 $(BIN_DIR)/pdsend $(INSTDIR)/bin/pdsend
+ install -m 755 $(BIN_DIR)/pdreceive $(INSTDIR)/bin/pdreceive
+ install -d $(INSTDIR)/lib/pd/extra
+ install -d $(INSTDIR)/lib/pd/externs
+ install -m 644 $(EXTERNS) $(INSTDIR)/lib/pd/extra
+ cp -r ../doc $(INSTDIR)/lib/pd/
+ install -d $(INSTDIR)/include
+ install -m644 m_pd.h $(INSTDIR)/include/m_pd.h
+ gzip < ../man/pd.1 > $(INSTDIR)/man/man1/pd.1.gz
+ chmod 644 $(INSTDIR)/man/man1/pd.1.gz
+ gzip < ../man/pdsend.1 > $(INSTDIR)/man/man1/pdsend.1.gz
+ chmod 644 $(INSTDIR)/man/man1/pdsend.1.gz
+ gzip < ../man/pdreceive.1 > $(INSTDIR)/man/man1/pdreceive.1.gz
+ chmod 644 $(INSTDIR)/man/man1/pdreceive.1.gz
+
+local-clean:
+ -rm -f ../obj/* $(BIN_DIR)/pd $(BIN_DIR)/$(GUINAME) $(BIN_DIR)/pdsend \
+ $(BIN_DIR)/pdreceive $(BIN_DIR)/pd-watchdog m_stamp.c
+ -rm -f *~
+ -rm -f $(BIN_DIR)/pdsend $(BIN_DIR)/pdreceive
+ -(cd ../doc/6.externs; rm -f *.pd_linux)
+ -rm -f makefile.dependencies
+ touch makefile.dependencies
+ chmod 666 makefile.dependencies
+
+extra-clean:
+ -rm -f `find ../extra/ -name "*.pd_*"`
+ -rm -f tags
+
+clean: extra-clean local-clean
+
+distclean: clean
+ -rm config.cache config.log config.status makefile tags
+ echo all: > makefile
+ echo -e "\t./configure" >> makefile
+ echo -e "\tmake" >> makefile
+
+tags: $(SRC) $(GSRC); ctags *.[ch]
+
+depend:
+ $(CC) $(INCLUDE) $(CFLAGS) -M $(SRC) > makefile.dependencies
+
+uninstall:
+ -rm -r $(INSTDIR)/lib/pd
+ -rm $(INSTDIR)/bin/pd
+ -rm $(INSTDIR)/bin/pdsend
+ -rm $(INSTDIR)/bin/pdreceive
+ -rm $(INSTDIR)/include/m_pd.h
+ -rm $(INSTDIR)/man/man1/pd.1.gz
+ -rm $(INSTDIR)/man/man1/pdsend.1.gz
+ -rm $(INSTDIR)/man/man1/pdreceive.1.gz
+
+include makefile.dependencies
+
+
+
+
+
+
+
diff --git a/pd/src/makefile.irix b/pd/src/makefile.irix
new file mode 100644
index 00000000..07975f04
--- /dev/null
+++ b/pd/src/makefile.irix
@@ -0,0 +1,65 @@
+# these can be altered from the command line to create an N32 version:
+# make EXECUTABLE=../bin/pd-n32 \
+XF1="-n32 -DN32 -woff 1080,1064,1185 -Ofast=ip32" \
+XF2="-OPT:cray_ivdep=true -r10000 -OPT:roundoff=3 -OPT:IEEE_arithmetic=3" pd
+
+EXECUTABLE=../bin/pd
+XF1=-o32 -fullwarn -O2
+XF2=
+all: $(EXECUTABLE) ../bin/pd-gui ../bin/pd.tk
+
+VPATH=../obj
+
+INCLUDE = -I. -I../../../irix/tk/generic -I../../../irix/tcl/generic
+GLIB = ../tk/unix/libtk8.0.a ../tcl/unix/libtcl8.0.a -lm -lX11
+LIB = -laudio -lmd -lm
+CFLAGS = -DUNIX -DIRIX -DPD $(XF1) $(XF2)
+LDFLAGS = $(XF1) $(XF2)
+
+SYSSRC = s_sgi.c
+
+SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \
+ g_scalar.c g_traversal.c g_guiconnect.c g_readwrite.c g_editor.c \
+ g_all_guis.c g_bang.c g_hdial.c g_hslider.c g_mycanvas.c g_numbox.c \
+ g_toggle.c g_vdial.c g_vslider.c g_vumeter.c \
+ m_pd.c m_class.c m_obj.c m_atom.c m_memory.c m_binbuf.c \
+ m_conf.c m_glob.c m_sched.c \
+ s_main.c s_inter.c s_unix.c s_file.c s_print.c \
+ s_loader.c s_path.c s_entry.c \
+ d_ugen.c d_ctl.c d_arithmetic.c d_osc.c d_filter.c d_dac.c d_misc.c \
+ d_math.c d_fft.c d_mayer_fft.c d_fftroutine.c d_array.c d_global.c \
+ d_delay.c d_resample.c \
+ x_arithmetic.c x_connective.c x_interface.c x_midi.c x_misc.c \
+ x_time.c x_acoustics.c x_net.c x_qlist.c x_gui.c d_soundfile.c \
+ $(SYSSRC)
+
+OBJ = $(SRC:.c=.o)
+
+GSRC = t_main.c t_tkcmd.c
+
+GOBJ = $(GSRC:.c=.o)
+.PHONY: pd gui
+
+.c.o:
+ cc $(CFLAGS) $(INCLUDE) -c -o $(VPATH)/$*.o $*.c
+
+pd: $(EXECUTABLE)
+
+gui: ../bin/pd-gui
+
+$(EXECUTABLE): $(OBJ)
+ cd ../obj; cc $(LDFLAGS) -o $(EXECUTABLE) $(OBJ) \
+ $(LIB)
+
+../bin/pd-gui: $(GOBJ)
+ cd ../obj; cc $(LDFLAGS) -o ../bin/pd-gui $(GOBJ) \
+ $(GLIB) -lm -lX11
+
+../bin/pd.tk: u_main.tk; cp u_main.tk ../bin/pd.tk
+
+tags: $(SRC) $(GSRC); ctags *.[ch]
+
+depend:; cc -M $(CFLAGS) $(INCLUDE) $(SRC) > makefile.dependencies
+
+include makefile.dependencies
+
diff --git a/pd/src/makefile.nt b/pd/src/makefile.nt
new file mode 100644
index 00000000..91d34051
--- /dev/null
+++ b/pd/src/makefile.nt
@@ -0,0 +1,95 @@
+# Makefile for portaudio ASIO driver version of PD
+
+all: pd gui ..\bin\pd.tk
+
+VC = "C:\Program Files\Microsoft Visual Studio\VC98"
+#VC="\Program Files\DevStudio\Vc"
+INCLUDE = -I.\ -I..\Tcl\include -I$(VC)\include
+
+LDIR = $(VC)\lib
+
+LIB = /NODEFAULTLIB:libc /NODEFAULTLIB:oldnames /NODEFAULTLIB:kernel \
+ /NODEFAULTLIB:uuid \
+ $(LDIR)\libc.lib $(LDIR)\oldnames.lib $(LDIR)\kernel32.lib \
+ $(LDIR)\wsock32.lib $(LDIR)\winmm.lib ..\bin\pthreadVC.lib
+
+GLIB = $(LIB) ..\lib\tcl83.lib ..\lib\tk83.lib
+CFLAGS = /nologo /W3 /DNT /DPD /DPD_INTERNAL /DWIN32 /DWINDOWS /Ox
+LFLAGS = /nologo
+
+SYSSRC = s_nt.c s_portaudio.c
+
+SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \
+ g_scalar.c g_traversal.c g_guiconnect.c g_readwrite.c g_editor.c \
+ g_all_guis.c g_bang.c g_hdial.c g_hslider.c g_mycanvas.c g_numbox.c \
+ g_toggle.c g_vdial.c g_vslider.c g_vumeter.c \
+ m_pd.c m_class.c m_obj.c m_atom.c m_memory.c m_binbuf.c \
+ m_conf.c m_glob.c m_sched.c \
+ s_main.c s_inter.c s_unix.c s_file.c s_print.c \
+ s_loader.c s_path.c s_entry.c \
+ d_ugen.c d_ctl.c d_arithmetic.c d_osc.c d_filter.c d_dac.c d_misc.c \
+ d_math.c d_fft.c d_mayer_fft.c d_fftroutine.c d_array.c d_global.c \
+ d_delay.c d_resample.c \
+ x_arithmetic.c x_connective.c x_interface.c x_midi.c x_misc.c \
+ x_time.c x_acoustics.c x_net.c x_qlist.c x_gui.c d_soundfile.c \
+ $(SYSSRC)
+
+PADIR = ..\portaudio
+INCPA = -I$(PADIR) -I$(PADIR)\pa_common -I$(PADIR)\pablio -I..\lib\asio
+SRCPA = $(PADIR)/pa_common/pa_lib.c $(PADIR)/pa_common/pa_trace.c \
+ $(PADIR)/pablio/pablio_pd.c $(PADIR)/pablio/ringbuffer_pd.c
+SRCASIO = $(PADIR)/pa_asio/pa_asio.cpp
+
+ASIOLIB = $(LDIR)\user32.lib $(LDIR)\gdi32.lib $(LDIR)\winspool.lib $(LDIR)\comdlg32.lib \
+$(LDIR)\advapi32.lib $(LDIR)\shell32.lib $(LDIR)\ole32.lib $(LDIR)\oleaut32.lib $(LDIR)\uuid.lib \
+$(LDIR)\odbc32.lib $(LDIR)\odbccp32.lib ..\lib\asio\asiolib.lib
+
+
+PAOBJ = pa_lib.obj pa_trace.obj pablio_pd.obj ringbuffer_pd.obj pa_asio.obj
+OBJC = $(SRC:.c=.obj) $(PAOBJ)
+
+GSRC = t_main.c t_tkcmd.c
+
+GOBJ = $(GSRC:.c=.obj)
+.PHONY: pd gui
+
+ALLCF = $(CFLAGS) $(INCLUDE) $(INCASIO) $(INCPA) /D_WINDOWS
+
+.c.obj:
+ cl /c $(ALLCF) /Tc$*.c
+
+pd: ..\bin\pd.exe
+
+gui: ..\bin\pdtcl.dll
+
+..\bin\pd.exe: s_entry.obj ..\bin\pd.lib
+ link $(LFLAGS) /out:..\bin\pd.exe /INCREMENTAL:NO s_entry.obj \
+ ..\bin\pd.lib $(LIB) $(ASIOLIB)
+
+..\bin\pd.dll ..\bin\pd.lib: $(OBJC) $(OBJASIO)
+ link $(LFLAGS) /dll /export:sys_main /out:..\bin\pd.dll $(OBJC) \
+ $(OBJASIO) $(LIB) $(ASIOLIB)
+
+..\bin\pdtcl.dll: t_tkcmd.obj
+ link $(LFLAGS) /dll /export:Pdtcl_Init /out:..\bin\pdtcl.dll \
+ t_tkcmd.obj $(GLIB)
+
+..\bin\pd.tk: u_main.tk; copy u_main.tk ..\bin\pd.tk
+
+# explicit rules to compile portaudio sources:
+pa_lib.obj: $(PADIR)\pa_common\pa_lib.c
+ cl /c $(ALLCF) $(PADIR)\pa_common\pa_lib.c
+pa_trace.obj: $(PADIR)\pa_common\pa_trace.c
+ cl /c $(ALLCF) $(PADIR)\pa_common\pa_trace.c
+pablio_pd.obj: $(PADIR)\pablio\pablio_pd.c
+ cl /c $(ALLCF) $(PADIR)\pablio\pablio_pd.c
+ringbuffer_pd.obj: $(PADIR)\pablio\ringbuffer_pd.c
+ cl /c $(ALLCF) $(PADIR)\pablio\ringbuffer_pd.c
+pa_asio.obj: $(PADIR)\pa_asio\pa_asio.cpp
+ cl /c $(ALLCF) $(PADIR)\pa_asio\pa_asio.cpp
+
+# the following should also clean up "bin" but it doesn't because "bin" holds
+# precious stuff from elsewhere.
+clean:
+ del *.obj
+
diff --git a/pd/src/notes.txt b/pd/src/notes.txt
new file mode 100644
index 00000000..6a01dd0b
--- /dev/null
+++ b/pd/src/notes.txt
@@ -0,0 +1,264 @@
+---------------- dolist --------------------
+++portno wierdness in gcc 3 worked around (Burton)
+non-power-of-2 channel counts in ASIO (Olaf Matthes)
+Bug, David McCallum, Jul. 13 -- find last error crashes
+
+
+last-minute bug fixes:
+add flag to select MIDI open to use select()?
+check top-of-window problem in OSX
+denormal protection
+
+doc:
+fix readme file and recopy to web page (add to README in dist instructions)
+
+problems:
+don't draw in/outlets on gui objects in graphs
+Alsa degradation after several hours running on soundblaster
+font size should depend on subpatch/abstraction
+moving a bang toward top of window creates problem
+figure out O_NDELAY for linux audio?
+missed Thomas's multi-dialog trick???
+fix iemguis not to bash symbol names
+check what happens when going back and forth between graph-on-parent
+deal with spaces in iemgui labels and send/receive names
+David McCallum, table crashes in 98?
+font hack (pix@test.at, 30 Nov 2001
+ perl -pi -e 's/-[*%a-z0-9-]*\*[*%a-z0-9-]*/fixed/' u_main.tk
+get rid of messages causing renaming; try to prevent patches closing themselves.
+Krzysztof's qlist_next reentrancy bug
+dac~/ adc~/ block~ incompatibility
+is ALSA really checking /proc!?
+scofo reports error on reading score1.txt
+data copy/paste doesn't check templates aren't changed
+rfft~ loses nyquist bin -- see "to hell with it" comment in d_fft.c
+soundfile writing gets wrong sample rate; see /* lie */ in d_soundfile.c
+
+data:
+vget, vset traversal objects
+cursor to show (x, y) location
+better hit detection (getrect is too greedy)
+click on points of plot
+typing at drawnumbers
+fix templates to be loaded on demand and belong to a globally known patch
+test and debug list elements of templates
+sublists should display on parent if desired?
+sublists seem not to handle canvas allocation right (get.pd->pointer.pd bug)
+scalar hook to catch the mouse
+protect against "plots" going away while you drag on them
+
+features:
+Pd to open html help on windows/mac
+flag to hide array names
+??? have a way to disambiguate externs from different libs???
+put serial object in main dist (see rat@telecoma, Apr. 25; winfried May 22)
+if there's just one array, don't do stringent hit check.
+netsend separate thread
+netreceive (and netsend?) message to set port number
+delete-in-rectangle message to Pds
+pasting should look at current mouse location
+"regular" numbers/symbols to do send/receive thing ala IEMGUI
+make selecting text grab keyboard focus
+think about x and y scale preservation when changing between graph and object
+show outlines of objects even when graph is "open"
+make graph labels persistent and add to dialog
+array click protection (Krzysztof's suggestion)
+Pd support for jack audio system: http://home.t-online.de/home/pdq808/jack-patch
+offer audiooutdev 1,3 feature on Windows
+Alsa in data late should carefuly reset DAC/ADC fill&empty pointers
+increase MIDIQSIZE to at least 1024 in s_unix.c
+add nonblock to linux open calls instead of using alarm
+make a hook so objects can specify help windows to open (for scheme object)
+graph_vis() to decorate graphs when they're toplevel (parent_glist == 0)
+get graphs to expand to hold their contents
+writing FLOAT wav files
+make "table" rescalable vertically
+-compat34 flag to save files so that 0.34 can read them
+suita.chopin.edu.pl/~czaja/miXed/externs/xeq.html -- MIDI file reader
+in glist_delete, consider why this can't be just "vis 0" -- why do we need it?
+abstraction auto-reload
+closebang
+switching between dac and gettimeofday timing on dsp_start/stop
+check that -blocksize really reflects in audiobuf calc for Hammerfall
+-version to print version and exit; usage() also to print version
+NT and OSX: opening HTML files?
+message to change block~ sizes dynamically
+MIDI file reading/writing?
+makefile to have make install depend on make local.
+borrow arrow keys from IEMLIB
+pd messages to close and reopen sound driver
+Float method for random
+figure out list, message objects
+separate control over alsaindev and alsaoutdev
+pd -version
+make "import"/export use IEMLIB objects
+object to get/set table size; random; quantile
+put in something for tilde order forcing
+extensible "toolbar" so people can add external GUI objects
+text cut and paste; see XStoreBytes
+new objects: nexttick~, extend threshold~ and snapshot~
+allow spaces in paths
+gem: try XSetBorderWidth, XMoveWindow, xcopyarea (/usr/share/doc/XF*)
+dialog for audio and MIDI settings
+prepend help to help filenames and add help search path
+read/writesf~ for NT
+variable send and receive -- check how max/MSP does it?
+number boxes to darken for typing and/or received messages
+delayed updates
+invisible toplevels
+dialog to change lib flag and path
+fastedit moves
+pique~ and fiddle~ unification (notice pique filtering is different!)
+new message box look
+figure out what to do when "pd sym" conflicts with window title as in Pluton?
+
+
+LATER
+Hammerfall adapt to ALSA
++~ 0 faster than +~ -- detect scalar input; also, order forcing inputs
+bonk~ file path handling
+unify arrays and garrays
+dialog to give values of $1, ... for the canvas
+bang at end of line~, tabwrite~, etc.
+recording to part of a table
+printout to main window
+should sys_bail kill all "threads" on the way out?
+check a_valid usage
+allow backslashes (or else really disallow them)
+icon & desktop integration
+vreadsf~
+benchmarking
+flash menu when accelerator hits?
+fix edit mode menu item
+"undo"
+fancier text editing
+tools (reassigns meaning of primary click)
+get gui to notice early EOF
+rewrite t_getbytes properly
+obj_new should do a longjmp on out-of-memory
+
+--------------------- source notes --------------------------
+
+0. structure definition roadmap. First, the containment tree of things
+that can be sent messages ("pure data"). (note that t_object and t_text,
+and t_graph and t_canvas, should be unified...)
+
+------------ BFFORE 0.35: ---------
+m_pd.h t_pd anything with a class
+ t_gobj "graphic object"
+ t_text text object
+g_canvas.h
+ t_glist list of graphic objects
+g_canvas.c t_canvas Pd "document"
+
+------------ AFTER 0.35: ---------
+m_pd.h t_pd anything with a class
+ t_gobj "graphic object"
+ t_text patchable object, AKA t_object
+g_canvas.h t_glist list of graphic objects, AKA t_canvas
+
+... and other structures:
+g_canvas.h t_selection -- linked list of gobjs
+ t_editor -- editor state, allocated for visible glists
+m_imp.h t_methodentry -- method handler
+ t_widgetbehavior -- class-dependent editing behavior for gobjs
+ t_parentwidgetbehavior -- objects' behavior on parent window
+ t_class -- method definitions, instance size, flags, etc.
+
+
+1. C coding style. The source should pass most "warnings" of C compilers
+(-Wall on linux, for instance; see the makefile.) Some informalities
+are intentional, for instance the loose use of function prototypes (see
+below) and uncast conversions from longer to shorter numerical formats.
+The code doesn't respect "const" yet.
+
+1.1. Prefixes in structure elements. The names of structure elements always
+have a K&R-style prefix, as in ((t_atom)x)->a_type, where the "a_" prefix
+indicates "atom." This is intended to enhance readability (although the
+convention arose from a limitation of early C compilers.) Common prefixes are
+"w_" (word), "a_" (atom), "s_" (symbol), "ob_" (object), "te_" (text object),
+"g_" (graphical object), and "gl_" (glist, a list of graphical objects). Also,
+global symbols sometimes get prefixes, as in "s_float" (the symbol whose string
+is "float). Typedefs are prefixed by "t_". Most _private_ structures, i.e.,
+structures whose definitions appear in a ".c" file, are prefixed by "x_".
+
+1.2. Function arguments. Many functions take as their first
+argument a pointer named "x", which is a pointer to a structure suggested
+by the function prefix; e.g., canvas_dirty(x, n) where "x" points to a canvas
+(t_canvas *x).
+
+1.3. Function Prototypes. Functions which are used in at least two different
+files (besides where they originate) are prototyped in the appropriate include
+file. Functions which are provided in one file and used in one other are
+prototyped right where they are used. This is just to keep the size of the
+".h" files down for readability's sake.
+
+1.4. Whacko private terminology. Some terms are lifted from other historically
+relevant programs, notably "ugen" (which is just a tilde object; see d_ugen.c.)
+
+1.5. Spacing. Tabs are 8 spaces; indentation is 4 spaces. Indenting
+curly brackets are by themselves on their own lines, as in:
+
+ if (x)
+ {
+ x = 0;
+ }
+
+Lines should fit within 80 spaces.
+
+2. Max patch-level compatibility. "Import" and "Export" functions are
+provided which aspire to strict compatibility with 0.26 patches (ISPW version),
+but which don't get anywhere close to that yet. Where possible, features
+appearing on the Mac will comeday also be provided; for instance, the connect
+message on the Mac offers segmented patch cords; these will devolve into
+straight lines in Pd. Many, many UI objects in Opcode Max will not appear in
+Pd, at least at first.
+
+3. Compatibility with Max 0.26 "externs", i.e., source-level compatibility. Pd
+objects follow the style of 0.26 objects as closely as possible, making
+exceptions in cases where the 0.26 model is clearly deficient. These are:
+
+3.1. Anything involving the MacIntosh "Handle" data type is changed to use
+char * or void * instead.
+
+3.2. Pd passes true single-precision floating-point arguments to methods;
+Max uses double.
+Typedefs are provided:
+ t_floatarg, t_intarg for arguments passed by the message system
+ t_float, t_int for the "word" union (in atoms, for example.)
+
+3.3. Badly-named entities got name changes:
+
+ w_long --> w_int (in the "union word" structure)
+
+3.4. Many library functions are renamed and have different arguments;
+I hope to provide an include file to alias them when compiling Max externs.
+
+4. Function name prefixes.
+Many function names have prefixes which indicate what "package" they belong
+to. The exceptions are:
+ typedmess, vmess, getfn, gensym (m_class.c)
+ getbytes, freebytes, resizebytes (m_memory.c)
+ post, error, bug (s_print.c)
+which are all frequently called and which don't fit into simple categories.
+Important packages are:
+(pd-gui:) pdgui -- everything
+(pd:) pd -- functions common to all "pd" objects
+ obj -- fuctions common to all "patchable" objects ala Max
+ sys -- "system" level functions
+ binbuf -- functions manipulating binbufs
+ class -- functions manipulating classes
+ (other) -- functions common to the named Pd class
+
+5. Source file prefixes.
+PD:
+s system interface
+m message system
+g graphics stuff
+d DSP objects
+x control objects
+z other
+
+PD-GUI:
+t TK front end
+
diff --git a/pd/src/s_entry.c b/pd/src/s_entry.c
new file mode 100644
index 00000000..354512e5
--- /dev/null
+++ b/pd/src/s_entry.c
@@ -0,0 +1,10 @@
+/* In NT, this is all there is to pd; the rest sits in a "pdlib" dll so
+that externs can link back to functions defined in pd. */
+
+
+int sys_main(int argc, char **argv);
+
+int main(int argc, char **argv)
+{
+ return (sys_main(argc, argv));
+}
diff --git a/pd/src/s_file.c b/pd/src/s_file.c
new file mode 100644
index 00000000..32d2fcaa
--- /dev/null
+++ b/pd/src/s_file.c
@@ -0,0 +1,54 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/*
+ * this file contains file-handling routines.
+ */
+
+#include "m_imp.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+ /* LATER delete this? -- replaced by find_via_path() in s_path.c */
+int sys_isreadablefile(const char *s)
+{
+ struct stat statbuf;
+ int mode;
+ if (stat(s, &statbuf) < 0) return (0);
+#ifdef UNIX
+ mode = statbuf.st_mode;
+ if (S_ISDIR(mode)) return (0);
+#endif
+ return (1);
+}
+
+ /* change '/' characters to the system's native file separator */
+void sys_bashfilename(const char *from, char *to)
+{
+ char c;
+ while (c = *from++)
+ {
+#ifdef NT
+ if (c == '/') c = '\\';
+#endif
+ *to++ = c;
+ }
+ *to = 0;
+}
+
+
+ /* change the system's native file separator to '/' characters */
+void sys_unbashfilename(const char *from, char *to)
+{
+ char c;
+ while (c = *from++)
+ {
+#ifdef NT
+ if (c == '\\') c = '/';
+#endif
+ *to++ = c;
+ }
+ *to = 0;
+}
+
diff --git a/pd/src/s_freebsd.c b/pd/src/s_freebsd.c
new file mode 100644
index 00000000..4ed4241b
--- /dev/null
+++ b/pd/src/s_freebsd.c
@@ -0,0 +1,3072 @@
+/* Copyright (c) 1997-1999 Guenter Geiger, Miller Puckette, Larry Troxler,
+* Winfried Ritsch, Karl MacMillan, and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* this file implements the sys_ functions profiled in m_imp.h for
+ audio and MIDI I/O. In Linux there might be several APIs for doing the
+ audio part; right now there are three (OSS, ALSA, RME); the third is
+ for the RME 9652 driver by Ritsch (but not for the OSS compatible
+ one by Geiger; for that one, OSS should work.)
+
+ FUNCTION PREFIXES.
+ sys_ -- functions which must be exported to Pd on all platforms
+ linux_ -- linux-specific objects which don't depend on API,
+ mostly static but some exported.
+ oss_, alsa_, rme_ -- API-specific functions, all of which are
+ static.
+
+ ALSA SUPPORT. If ALSA99 is defined we support ALSA 0.5x; if ALSA01,
+ ALSA 0.9x. (the naming scheme reflects the possibility of further API
+ changes in the future...) We define "ALSA" for code relevant to both
+ APIs.
+
+ For MIDI, we only offer the OSS API; ALSA has to emulate OSS for us.
+*/
+
+/* OSS include (whether we're doing OSS audio or not we need this for MIDI) */
+
+
+/* IOhannes:::
+ * hacked this to add advanced multidevice-support
+ * 1311:forum::für::umläute:2001
+ */
+
+#include <sys/soundcard.h>
+
+#if (defined(ALSA01) || defined(ALSA99))
+#define ALSA
+#endif
+
+#ifdef ALSA99
+#include <sys/asoundlib.h>
+#endif
+#ifdef ALSA01
+#include <alsa/asoundlib.h>
+#endif
+
+#include "m_imp.h"
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <sys/mman.h>
+
+/* local function prototypes */
+
+static void linux_close_midi( void);
+
+static int oss_open_audio(int naudioindev, int *audioindev, int nchindev,
+ int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
+ int *choutdev, int rate); /* IOhannes */
+
+static void oss_close_audio(void);
+static int oss_send_dacs(void);
+static void oss_reportidle(void);
+
+#ifdef ALSA
+typedef int16_t t_alsa_sample16;
+typedef int32_t t_alsa_sample32;
+#define ALSA_SAMPLEWIDTH_16 sizeof(t_alsa_sample16)
+#define ALSA_SAMPLEWIDTH_32 sizeof(t_alsa_sample32)
+#define ALSA_XFERSIZE16 (signed int)(sizeof(t_alsa_sample16) * DACBLKSIZE)
+#define ALSA_XFERSIZE32 (signed int)(sizeof(t_alsa_sample32) * DACBLKSIZE)
+#define ALSA_MAXDEV 1
+#define ALSA_JITTER 1024
+#define ALSA_EXTRABUFFER 2048
+#define ALSA_DEFFRAGSIZE 64
+#define ALSA_DEFNFRAG 12
+
+#ifdef ALSA99
+typedef struct _alsa_dev
+{
+ snd_pcm_t *handle;
+ snd_pcm_channel_info_t info;
+ snd_pcm_channel_setup_t setup;
+} t_alsa_dev;
+
+t_alsa_dev alsa_device[ALSA_MAXDEV];
+static int n_alsa_dev;
+static char *alsa_buf;
+static int alsa_samplewidth;
+#endif /* ALSA99 */
+
+#ifdef ALSA01
+typedef struct _alsa_dev
+{
+ snd_pcm_t *inhandle;
+ snd_pcm_t *outhandle;
+} t_alsa_dev;
+
+t_alsa_dev alsa_device;
+static short *alsa_buf;
+static int alsa_samplewidth;
+static snd_pcm_status_t* in_status;
+static snd_pcm_status_t* out_status;
+#endif /* ALSA01 */
+
+#if 0 /* early alsa 0.9 beta dists had different names for these: */
+#define SND_PCM_ACCESS_RW_INTERLEAVED SNDRV_PCM_ACCESS_RW_INTERLEAVED
+#define SND_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32
+#define SND_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16
+#define SND_PCM_SUBFORMAT_STD SNDRV_PCM_SUBFORMAT_STD
+#endif
+
+static int alsa_mode;
+static int alsa_open_audio(int inchans, int outchans, int rate);
+static void alsa_close_audio(void);
+static int alsa_send_dacs(void);
+static void alsa_set_params(t_alsa_dev *dev, int dir, int rate, int voices);
+static void alsa_reportidle(void);
+#endif /* ALSA */
+
+#ifdef RME_HAMMERFALL
+static int rme9652_open_audio(int inchans, int outchans, int rate);
+static void rme9652_close_audio(void);
+static int rme9652_send_dacs(void);
+static void rme9652_reportidle(void);
+#endif /* RME_HAMMERFALL */
+
+/* Defines */
+#define DEBUG(x) x
+#define DEBUG2(x) {x;}
+
+#define OSS_MAXCHPERDEV 32 /* max channels per OSS device */
+#define OSS_MAXDEV 4 /* maximum number of input or output devices */
+#define OSS_DEFFRAGSIZE 256 /* default log fragment size (frames) */
+#define OSS_DEFAUDIOBUF 40000 /* default audiobuffer, microseconds */
+#define OSS_DEFAULTCH 2
+#define RME_DEFAULTCH 8 /* need this even if RME undefined */
+typedef int16_t t_oss_int16;
+typedef int32_t t_oss_int32;
+#define OSS_MAXSAMPLEWIDTH sizeof(t_oss_int32)
+#define OSS_BYTESPERCHAN(width) (DACBLKSIZE * (width))
+#define OSS_XFERSAMPS(chans) (DACBLKSIZE* (chans))
+#define OSS_XFERSIZE(chans, width) (DACBLKSIZE * (chans) * (width))
+
+#ifdef RME_HAMMERFALL
+typedef int32_t t_rme_sample;
+#define RME_SAMPLEWIDTH sizeof(t_rme_sample)
+#define RME_BYTESPERCHAN (DACBLKSIZE * RME_SAMPLEWIDTH)
+#endif /* RME_HAMMERFALL */
+
+/* GLOBALS */
+static int linux_whichapi = API_OSS;
+static int linux_inchannels;
+static int linux_outchannels;
+static int linux_advance_samples; /* scheduler advance in samples */
+static int linux_meters; /* true if we're metering */
+static float linux_inmax; /* max input amplitude */
+static float linux_outmax; /* max output amplitude */
+static int linux_fragsize = 0; /* for block mode; block size (sample frames) */
+static int linux_nfragment = 0; /* ... and number of blocks. */
+
+#ifdef ALSA99
+static int alsa_devno = 1;
+#endif
+#ifdef ALSA01
+static char alsa_devname[512] = "hw:0,0";
+static int alsa_use_plugin = 0;
+#endif
+
+/* our device handles */
+
+typedef struct _oss_dev
+{
+ int d_fd;
+ unsigned int d_space; /* bytes available for writing/reading */
+ int d_bufsize; /* total buffer size in blocks for this device */
+ int d_dropcount; /* # of buffers to drop for resync (output only) */
+ unsigned int d_nchannels; /* number of channels for this device */
+ unsigned int d_bytespersamp; /* bytes per sample (2 for 16 bit, 4 for 32) */
+} t_oss_dev;
+
+static t_oss_dev linux_dacs[OSS_MAXDEV];
+static t_oss_dev linux_adcs[OSS_MAXDEV];
+static int linux_noutdevs = 0;
+static int linux_nindevs = 0;
+
+ /* exported variables */
+int sys_schedadvance = OSS_DEFAUDIOBUF; /* scheduler advance in microsecs */
+float sys_dacsr;
+int sys_hipriority = 0;
+t_sample *sys_soundout;
+t_sample *sys_soundin;
+
+ /* OSS-specific private variables */
+static int oss_blockmode = 1; /* flag to use "blockmode" */
+static char ossdsp[] = "/dev/dsp%d";
+
+#ifndef INT32_MAX
+#define INT32_MAX 0x7fffffff
+#endif
+#define CLIP32(x) (((x)>INT32_MAX)?INT32_MAX:((x) < -INT32_MAX)?-INT32_MAX:(x))
+
+
+/* ------------- private routines for all APIS ------------------- */
+
+static void linux_flush_all_underflows_to_zero(void)
+{
+/*
+ TODO: Implement similar thing for linux (GGeiger)
+
+ One day we will figure this out, I hope, because it
+ costs CPU time dearly on Intel - LT
+ */
+ /* union fpc_csr f;
+ f.fc_word = get_fpc_csr();
+ f.fc_struct.flush = 1;
+ set_fpc_csr(f.fc_word);
+ */
+}
+
+ /* set sample rate and channels. Must set sample rate before "configuring"
+ any devices so we know scheduler advance in samples. */
+
+static void linux_setsr(int sr)
+{
+ sys_dacsr = sr;
+ linux_advance_samples = (sys_schedadvance * sys_dacsr) / (1000000.);
+ if (linux_advance_samples < 3 * DACBLKSIZE)
+ linux_advance_samples = 3 * DACBLKSIZE;
+}
+
+static void linux_setch(int chin, int chout)
+{
+ int nblk;
+ int inbytes = chin * (DACBLKSIZE*sizeof(float));
+ int outbytes = chout * (DACBLKSIZE*sizeof(float));
+
+ linux_inchannels = chin;
+ linux_outchannels = chout;
+ if (sys_soundin)
+ free(sys_soundin);
+ sys_soundin = (t_float *)malloc(inbytes);
+ memset(sys_soundin, 0, inbytes);
+
+ if (sys_soundout)
+ free(sys_soundout);
+ sys_soundout = (t_float *)malloc(outbytes);
+ memset(sys_soundout, 0, outbytes);
+
+ if (sys_verbose)
+ post("input channels = %d, output channels = %d",
+ linux_inchannels, linux_outchannels);
+}
+
+/* ---------------- MIDI routines -------------------------- */
+
+static int oss_nmidiin;
+static int oss_midiinfd[MAXMIDIINDEV];
+static int oss_nmidiout;
+static int oss_midioutfd[MAXMIDIOUTDEV];
+
+static void oss_midiout(int fd, int n)
+{
+ char b = n;
+ if ((write(fd, (char *) &b, 1)) != 1)
+ perror("midi write");
+}
+
+#define O_MIDIFLAG O_NDELAY
+
+void linux_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec)
+{
+ int i;
+ for (i = 0; i < nmidiout; i++)
+ oss_midioutfd[i] = -1;
+ for (i = 0, oss_nmidiin = 0; i < nmidiin; i++)
+ {
+ int fd = -1, j, outdevindex = -1;
+ char namebuf[80];
+ int devno = midiinvec[i];
+
+ for (j = 0; j < nmidiout; j++)
+ if (midioutvec[j] == midiinvec[i])
+ outdevindex = j;
+
+ /* try to open the device for read/write. */
+ if (devno == 1 && fd < 0 && outdevindex >= 0)
+ {
+ sys_setalarm(1000000);
+ fd = open("/dev/midi", O_RDWR | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr,
+ "device 1: tried /dev/midi READ/WRITE; returned %d\n", fd);
+ if (outdevindex >= 0 && fd >= 0)
+ oss_midioutfd[outdevindex] = fd;
+ }
+ if (fd < 0 && outdevindex >= 0)
+ {
+ sys_setalarm(1000000);
+ sprintf(namebuf, "/dev/midi%2.2d", devno-1);
+ fd = open(namebuf, O_RDWR | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr,
+ "device %d: tried %s READ/WRITE; returned %d\n",
+ devno, namebuf, fd);
+ if (outdevindex >= 0 && fd >= 0)
+ oss_midioutfd[outdevindex] = fd;
+ }
+ if (fd < 0 && outdevindex >= 0)
+ {
+ sys_setalarm(1000000);
+ sprintf(namebuf, "/dev/midi%d", devno-1);
+ fd = open(namebuf, O_RDWR | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr, "device %d: tried %s READ/WRITE; returned %d\n",
+ devno, namebuf, fd);
+ if (outdevindex >= 0 && fd >= 0)
+ oss_midioutfd[outdevindex] = fd;
+ }
+ if (devno == 1 && fd < 0)
+ {
+ sys_setalarm(1000000);
+ fd = open("/dev/midi", O_RDONLY | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr,
+ "device 1: tried /dev/midi READONLY; returned %d\n", fd);
+ }
+ if (fd < 0)
+ {
+ sys_setalarm(1000000);
+ sprintf(namebuf, "/dev/midi%2.2d", devno-1);
+ fd = open(namebuf, O_RDONLY | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr, "device %d: tried %s READONLY; returned %d\n",
+ devno, namebuf, fd);
+ }
+ if (fd < 0)
+ {
+ sys_setalarm(1000000);
+ sprintf(namebuf, "/dev/midi%d", devno-1);
+ fd = open(namebuf, O_RDONLY | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr, "device %d: tried %s READONLY; returned %d\n",
+ devno, namebuf, fd);
+ }
+ if (fd >= 0)
+ oss_midiinfd[oss_nmidiin++] = fd;
+ else post("couldn't open MIDI input device %d", devno);
+ }
+ for (i = 0, oss_nmidiout = 0; i < nmidiout; i++)
+ {
+ int fd = oss_midioutfd[i];
+ char namebuf[80];
+ int devno = midioutvec[i];
+ if (devno == 1 && fd < 0)
+ {
+ sys_setalarm(1000000);
+ fd = open("/dev/midi", O_WRONLY | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr,
+ "device 1: tried /dev/midi WRITEONLY; returned %d\n", fd);
+ }
+ if (fd < 0)
+ {
+ sys_setalarm(1000000);
+ sprintf(namebuf, "/dev/midi%2.2d", devno-1);
+ fd = open(namebuf, O_WRONLY | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr, "device %d: tried %s WRITEONLY; returned %d\n",
+ devno, namebuf, fd);
+ }
+ if (fd < 0)
+ {
+ sys_setalarm(1000000);
+ sprintf(namebuf, "/dev/midi%d", devno-1);
+ fd = open(namebuf, O_WRONLY | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr, "device %d: tried %s WRITEONLY; returned %d\n",
+ devno, namebuf, fd);
+ }
+ if (fd >= 0)
+ oss_midioutfd[oss_nmidiout++] = fd;
+ else post("couldn't open MIDI output device %d", devno);
+ }
+
+ if (oss_nmidiin < nmidiin || oss_nmidiout < nmidiout || sys_verbose)
+ post("opened %d MIDI input device(s) and %d MIDI output device(s).",
+ oss_nmidiin, oss_nmidiout);
+}
+
+#define md_msglen(x) (((x)<0xC0)?2:((x)<0xE0)?1:((x)<0xF0)?2:\
+ ((x)==0xF2)?2:((x)<0xF4)?1:0)
+
+void sys_putmidimess(int portno, int a, int b, int c)
+{
+ if (portno >= 0 && portno < oss_nmidiout)
+ {
+ switch (md_msglen(a))
+ {
+ case 2:
+ oss_midiout(oss_midioutfd[portno],a);
+ oss_midiout(oss_midioutfd[portno],b);
+ oss_midiout(oss_midioutfd[portno],c);
+ return;
+ case 1:
+ oss_midiout(oss_midioutfd[portno],a);
+ oss_midiout(oss_midioutfd[portno],b);
+ return;
+ case 0:
+ oss_midiout(oss_midioutfd[portno],a);
+ return;
+ };
+ }
+}
+
+void sys_putmidibyte(int portno, int byte)
+{
+ if (portno >= 0 && portno < oss_nmidiout)
+ oss_midiout(oss_midioutfd[portno], byte);
+}
+
+#if 0 /* this is the "select" version which doesn't work with OSS
+ driver for emu10k1 (it doesn't implement select.) */
+void sys_poll_midi(void)
+{
+ int i, throttle = 100;
+ struct timeval timout;
+ int did = 1, maxfd = 0;
+ while (did)
+ {
+ fd_set readset, writeset, exceptset;
+ did = 0;
+ if (throttle-- < 0)
+ break;
+ timout.tv_sec = 0;
+ timout.tv_usec = 0;
+
+ FD_ZERO(&writeset);
+ FD_ZERO(&readset);
+ FD_ZERO(&exceptset);
+ for (i = 0; i < oss_nmidiin; i++)
+ {
+ if (oss_midiinfd[i] > maxfd)
+ maxfd = oss_midiinfd[i];
+ FD_SET(oss_midiinfd[i], &readset);
+ }
+ select(maxfd+1, &readset, &writeset, &exceptset, &timout);
+ for (i = 0; i < oss_nmidiin; i++)
+ if (FD_ISSET(oss_midiinfd[i], &readset))
+ {
+ char c;
+ int ret = read(oss_midiinfd[i], &c, 1);
+ if (ret <= 0)
+ fprintf(stderr, "Midi read error\n");
+ else sys_midibytein(i, (c & 0xff));
+ did = 1;
+ }
+ }
+}
+#else
+
+ /* this version uses the asynchronous "read()" ... */
+void sys_poll_midi(void)
+{
+ int i, throttle = 100;
+ struct timeval timout;
+ int did = 1, maxfd = 0;
+ while (did)
+ {
+ fd_set readset, writeset, exceptset;
+ did = 0;
+ if (throttle-- < 0)
+ break;
+ for (i = 0; i < oss_nmidiin; i++)
+ {
+ char c;
+ int ret = read(oss_midiinfd[i], &c, 1);
+ if (ret < 0)
+ {
+ if (errno != EAGAIN)
+ perror("MIDI");
+ }
+ else if (ret != 0)
+ {
+ sys_midibytein(i, (c & 0xff));
+ did = 1;
+ }
+ }
+ }
+}
+#endif
+
+void linux_close_midi()
+{
+ int i;
+ for (i = 0; i < oss_nmidiin; i++)
+ close(oss_midiinfd[i]);
+ for (i = 0; i < oss_nmidiout; i++)
+ close(oss_midioutfd[i]);
+ oss_nmidiin = oss_nmidiout = 0;
+}
+
+#define MAXAUDIODEV 4
+#define DEFAULTINDEV 1
+#define DEFAULTOUTDEV 1
+
+/* ----------------------- public routines ----------------------- */
+void sys_listdevs( void)
+{
+ post("device listing not implemented in Linux yet\n");
+}
+
+void sys_open_audio(int naudioindev, int *audioindev, int nchindev,
+ int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
+ int *choutdev, int rate)
+{ /* IOhannes */
+ int i, *ip;
+ int defaultchannels =
+ (linux_whichapi == API_RME ? RME_DEFAULTCH : OSS_DEFAULTCH);
+ if (rate < 1)
+ rate=44100;
+
+ if (naudioindev == -1)
+ { /* not set */
+ if (nchindev==-1)
+ {
+ nchindev=1;
+ chindev[0]=defaultchannels;
+ naudioindev=1;
+ audioindev[0] = DEFAULTINDEV;
+ }
+ else
+ {
+ for (i = 0; i < MAXAUDIODEV; i++)
+ audioindev[i]=i+1;
+ naudioindev = nchindev;
+ }
+ }
+ else
+ {
+ if (nchindev == -1)
+ {
+ nchindev = naudioindev;
+ for (i = 0; i < naudioindev; i++)
+ chindev[i] = defaultchannels;
+ }
+ else if (nchindev > naudioindev)
+ {
+ for (i = naudioindev; i < nchindev; i++)
+ {
+ if (i == 0)
+ audioindev[0] = DEFAULTINDEV;
+ else audioindev[i] = audioindev[i-1] + 1;
+ }
+ naudioindev = nchindev;
+ }
+ else if (nchindev < naudioindev)
+ {
+ for (i = nchindev; i < naudioindev; i++)
+ {
+ if (i == 0)
+ chindev[0] = defaultchannels;
+ else chindev[i] = chindev[i-1];
+ }
+ naudioindev = nchindev;
+ }
+ }
+
+ if (naudiooutdev == -1)
+ { /* not set */
+ if (nchoutdev==-1)
+ {
+ nchoutdev=1;
+ choutdev[0]=defaultchannels;
+ naudiooutdev=1;
+ audiooutdev[0] = DEFAULTOUTDEV;
+ }
+ else
+ {
+ for (i = 0; i < MAXAUDIODEV; i++)
+ audiooutdev[i] = i+1;
+ naudiooutdev = nchoutdev;
+ }
+ }
+ else
+ {
+ if (nchoutdev == -1)
+ {
+ nchoutdev = naudiooutdev;
+ for (i = 0; i < naudiooutdev; i++)
+ choutdev[i] = defaultchannels;
+ }
+ else if (nchoutdev > naudiooutdev)
+ {
+ for (i = naudiooutdev; i < nchoutdev; i++)
+ {
+ if (i == 0)
+ audiooutdev[0] = DEFAULTOUTDEV;
+ else audiooutdev[i] = audiooutdev[i-1] + 1;
+ }
+ naudiooutdev = nchoutdev;
+ }
+ else if (nchoutdev < naudiooutdev)
+ {
+ for (i = nchoutdev; i < naudiooutdev; i++)
+ {
+ if (i == 0)
+ choutdev[0] = defaultchannels;
+ else choutdev[i] = choutdev[i-1];
+ }
+ naudiooutdev = nchoutdev;
+ }
+ }
+
+ linux_flush_all_underflows_to_zero();
+#ifdef ALSA
+ if (linux_whichapi == API_ALSA)
+ alsa_open_audio((naudioindev > 0 ? chindev[0] : 0),
+ (naudiooutdev > 0 ? choutdev[0] : 0), rate);
+ else
+#endif
+#ifdef RME_HAMMERFALL
+ if (linux_whichapi == API_RME)
+ rme9652_open_audio((naudioindev > 0 ? chindev[0] : 0),
+ (naudiooutdev > 0 ? choutdev[0] : 0), rate);
+ else
+#endif
+ oss_open_audio(naudioindev, audioindev, nchindev, chindev,
+ naudiooutdev, audiooutdev, nchoutdev, choutdev, rate);
+}
+
+void sys_close_audio(void)
+{
+ /* set timeout to avoid hanging close() call */
+
+ sys_setalarm(1000000);
+
+#ifdef ALSA
+ if (linux_whichapi == API_ALSA)
+ alsa_close_audio();
+ else
+#endif
+#ifdef RME_HAMMERFALL
+ if (linux_whichapi == API_RME)
+ rme9652_close_audio();
+ else
+#endif
+ oss_close_audio();
+
+ sys_setalarm(0);
+}
+
+void sys_open_midi(int nmidiin, int *midiinvec,
+ int nmidiout, int *midioutvec)
+{
+ linux_open_midi(nmidiin, midiinvec, nmidiout, midioutvec);
+}
+
+void sys_close_midi( void)
+{
+ sys_setalarm(1000000);
+ linux_close_midi();
+ sys_setalarm(0);
+}
+
+int sys_send_dacs(void)
+{
+ if (linux_meters)
+ {
+ int i, n;
+ float maxsamp;
+ for (i = 0, n = linux_inchannels * DACBLKSIZE, maxsamp = linux_inmax;
+ i < n; i++)
+ {
+ float f = sys_soundin[i];
+ if (f > maxsamp) maxsamp = f;
+ else if (-f > maxsamp) maxsamp = -f;
+ }
+ linux_inmax = maxsamp;
+ for (i = 0, n = linux_outchannels * DACBLKSIZE, maxsamp = linux_outmax;
+ i < n; i++)
+ {
+ float f = sys_soundout[i];
+ if (f > maxsamp) maxsamp = f;
+ else if (-f > maxsamp) maxsamp = -f;
+ }
+ linux_outmax = maxsamp;
+ }
+#ifdef ALSA
+ if (linux_whichapi == API_ALSA)
+ return alsa_send_dacs();
+#endif
+#ifdef RME_HAMMERFALL
+ if (linux_whichapi == API_RME)
+ return rme9652_send_dacs();
+#endif
+ return oss_send_dacs();
+}
+
+float sys_getsr(void)
+{
+ return (sys_dacsr);
+}
+
+int sys_get_outchannels(void)
+{
+ return (linux_outchannels);
+}
+
+int sys_get_inchannels(void)
+{
+ return (linux_inchannels);
+}
+
+void sys_audiobuf(int n)
+{
+ /* set the size, in milliseconds, of the audio FIFO */
+ if (n < 5) n = 5;
+ else if (n > 5000) n = 5000;
+ sys_schedadvance = n * 1000;
+}
+
+void sys_getmeters(float *inmax, float *outmax)
+{
+ if (inmax)
+ {
+ linux_meters = 1;
+ *inmax = linux_inmax;
+ *outmax = linux_outmax;
+ }
+ else
+ linux_meters = 0;
+ linux_inmax = linux_outmax = 0;
+}
+
+void sys_reportidle(void)
+{
+}
+
+void sys_set_priority(int higher)
+{
+ struct sched_param par;
+ int p1 ,p2, p3;
+#ifdef _POSIX_PRIORITY_SCHEDULING
+
+ p1 = sched_get_priority_min(SCHED_FIFO);
+ p2 = sched_get_priority_max(SCHED_FIFO);
+ p3 = (higher ? p2 - 1 : p2 - 3);
+ par.sched_priority = p3;
+
+ if (sched_setscheduler(0,SCHED_FIFO,&par) != -1)
+ fprintf(stderr, "priority %d scheduling enabled.\n", p3);
+#endif
+
+#ifdef _POSIX_MEMLOCK
+ if (mlockall(MCL_FUTURE) != -1)
+ fprintf(stderr, "memory locking enabled.\n");
+#endif
+}
+
+/* ------------ linux-specific command-line flags -------------- */
+
+void linux_setfrags(int n)
+{
+ linux_nfragment = n;
+ oss_blockmode = 1;
+}
+
+void linux_setfragsize(int n)
+{
+ if (n < 1)
+ n = 1;
+ linux_fragsize = n;
+ oss_blockmode = 1;
+}
+
+void linux_streammode( void)
+{
+ oss_blockmode = 0;
+}
+
+void linux_set_sound_api(int which)
+{
+ linux_whichapi = which;
+ if (sys_verbose)
+ post("linux_whichapi %d", linux_whichapi);
+}
+
+#ifdef ALSA99
+void linux_alsa_devno(int devno)
+{
+ alsa_devno = devno;
+}
+
+#endif
+
+#ifdef ALSA01
+void linux_alsa_devname(char *devname)
+{
+ strncpy(alsa_devname, devname, 511);
+}
+
+void linux_alsa_use_plugin(int t)
+{
+ if (t == 1)
+ alsa_use_plugin = 1;
+ else
+ alsa_use_plugin = 0;
+}
+
+#endif
+
+/* -------------- Audio I/O using the OSS API ------------------ */
+
+typedef struct _multidev {
+ int fd;
+ int channels;
+ int format;
+} t_multidev;
+
+int oss_reset(int fd) {
+ int err;
+ if ((err = ioctl(fd,SNDCTL_DSP_RESET)) < 0)
+ error("OSS: Could not reset");
+ return err;
+}
+
+ /* The AFMT_S32_BLOCKED format is not defined in standard linux kernels
+ but is proposed by Guenter Geiger to support extending OSS to handle
+ 32 bit sample. This is user in Geiger's OSS driver for RME Hammerfall.
+ I'm not clear why this isn't called AFMT_S32_[SLN]E... */
+
+#ifndef AFMT_S32_BLOCKED
+#define AFMT_S32_BLOCKED 0x0000400
+#endif
+
+void oss_configure(t_oss_dev *dev, int srate, int dac, int skipblocksize)
+{ /* IOhannes */
+ int orig, param, nblk, fd = dev->d_fd, wantformat;
+ int nchannels = dev->d_nchannels;
+ int advwas = sys_schedadvance;
+
+ audio_buf_info ainfo;
+
+ /* IOhannes :
+ * pd is very likely to crash if different formats are used on
+ multiple soundcards
+ */
+
+ /* set resolution - first try 4 byte samples */
+ if ((ioctl(fd,SNDCTL_DSP_GETFMTS,&param) >= 0) &&
+ (param & AFMT_S32_BLOCKED))
+ {
+ wantformat = AFMT_S32_BLOCKED;
+ dev->d_bytespersamp = 4;
+ }
+ else
+ {
+/* FreeBSD's soundcard.h does not define AFMT_S16_NE */
+ wantformat = AFMT_S16_BE;
+ dev->d_bytespersamp = 2;
+ }
+ param = wantformat;
+
+ if (sys_verbose)
+ post("bytes per sample = %d", dev->d_bytespersamp);
+ if (ioctl(fd, SNDCTL_DSP_SETFMT, &param) == -1)
+ fprintf(stderr,"OSS: Could not set DSP format\n");
+ else if (wantformat != param)
+ fprintf(stderr,"OSS: DSP format: wanted %d, got %d\n",
+ wantformat, param);
+
+ /* sample rate */
+ orig = param = srate;
+ if (ioctl(fd, SNDCTL_DSP_SPEED, &param) == -1)
+ fprintf(stderr,"OSS: Could not set sampling rate for device\n");
+ else if( orig != param )
+ fprintf(stderr,"OSS: sampling rate: wanted %d, got %d\n",
+ orig, param );
+
+ if (oss_blockmode && !skipblocksize)
+ {
+ int fragbytes, logfragsize, nfragment;
+ /* setting fragment count and size. */
+ if (linux_nfragment) /* if nfrags specified, take literally */
+ {
+ nfragment = linux_nfragment;
+ if (!linux_fragsize)
+ linux_fragsize = OSS_DEFFRAGSIZE;
+ sys_schedadvance = ((nfragment * linux_fragsize) * 1.e6)
+ / (float)srate;
+ linux_setsr(srate);
+ }
+ else
+ {
+ if (!linux_fragsize)
+ {
+ linux_fragsize = OSS_DEFFRAGSIZE;
+ while (linux_fragsize > DACBLKSIZE
+ && linux_fragsize * 4 > linux_advance_samples)
+ linux_fragsize = linux_fragsize/2;
+ }
+ /* post("adv_samples %d", linux_advance_samples); */
+ nfragment = (sys_schedadvance * (44100. * 1.e-6)) / linux_fragsize;
+ }
+ fragbytes = linux_fragsize * (dev->d_bytespersamp * nchannels);
+ logfragsize = ilog2(fragbytes);
+
+ if (fragbytes != (1 << logfragsize))
+ post("warning: OSS takes only power of 2 blocksize; using %d",
+ (1 << logfragsize)/(dev->d_bytespersamp * nchannels));
+ if (sys_verbose)
+ post("setting nfrags = %d, fragsize %d\n", nfragment, fragbytes);
+
+ param = orig = (nfragment<<16) + logfragsize;
+ if (ioctl(fd,SNDCTL_DSP_SETFRAGMENT, &param) == -1)
+ error("OSS: Could not set or read fragment size\n");
+ if (param != orig)
+ {
+ nfragment = ((param >> 16) & 0xffff);
+ logfragsize = (param & 0xffff);
+ post("warning: actual fragments %d, blocksize %d",
+ nfragment, (1 << logfragsize));
+ }
+ if (sys_verbose)
+ post("audiobuffer set to %d msec", (int)(0.001 * sys_schedadvance));
+ }
+
+ if (dac)
+ {
+ /* use "free space" to learn the buffer size. Normally you
+ should set this to your own desired value; but this seems not
+ to be implemented uniformly across different sound cards. LATER
+ we should figure out what to do if the requested scheduler advance
+ is greater than this buffer size; for now, we just print something
+ out. */
+
+ int defect;
+ if (ioctl(fd, SOUND_PCM_GETOSPACE,&ainfo) < 0)
+ fprintf(stderr,"OSS: ioctl on output device failed");
+ dev->d_bufsize = ainfo.bytes;
+
+ defect = linux_advance_samples * (dev->d_bytespersamp * nchannels)
+ - dev->d_bufsize - OSS_XFERSIZE(nchannels, dev->d_bytespersamp);
+ if (defect > 0)
+ {
+ if (sys_verbose || defect > (dev->d_bufsize >> 2))
+ fprintf(stderr,
+ "OSS: requested audio buffer size %d limited to %d\n",
+ linux_advance_samples * (dev->d_bytespersamp * nchannels),
+ dev->d_bufsize);
+ linux_advance_samples =
+ (dev->d_bufsize - OSS_XFERSAMPS(nchannels)) /
+ (dev->d_bytespersamp *nchannels);
+ }
+ }
+}
+
+static int oss_setchannels(int fd, int wantchannels, char *devname)
+{ /* IOhannes */
+ int param = wantchannels;
+
+ while (param>1) {
+ int save = param;
+ if (ioctl(fd, SNDCTL_DSP_CHANNELS, &param) == -1) {
+ error("OSS: SNDCTL_DSP_CHANNELS failed %s",devname);
+ } else {
+ if (param == save) return (param);
+ }
+ param=save-1;
+ }
+
+ return (0);
+}
+
+int oss_open_audio(int nindev, int *indev, int nchin, int *chin,
+ int noutdev, int *outdev, int nchout, int *chout, int rate)
+{ /* IOhannes */
+ int capabilities = 0;
+ int inchannels = 0, outchannels = 0;
+ char devname[20];
+ int n, i, fd;
+ char buf[OSS_MAXSAMPLEWIDTH * DACBLKSIZE * OSS_MAXCHPERDEV];
+ int num_devs = 0;
+ int wantmore=0;
+ int spread = 0;
+ audio_buf_info ainfo;
+
+ linux_nindevs = linux_noutdevs = 0;
+
+ /* set logical sample rate amd calculate linux_advance_samples. */
+ linux_setsr(rate);
+
+ /* mark input devices unopened */
+ for (i = 0; i < OSS_MAXDEV; i++)
+ linux_adcs[i].d_fd = -1;
+
+ /* open output devices */
+ wantmore=0;
+ if (noutdev < 0 || nindev < 0)
+ bug("linux_open_audio");
+
+ for (n = 0; n < noutdev; n++)
+ {
+ int gotchans, j, inindex = -1;
+ int thisdevice=outdev[n];
+ int wantchannels = (nchout>n) ? chout[n] : wantmore;
+ fd = -1;
+ if (!wantchannels)
+ goto end_out_loop;
+
+ if (thisdevice > 1)
+ sprintf(devname, "/dev/dsp%d", thisdevice-1);
+ else sprintf(devname, "/dev/dsp");
+
+ /* search for input request for same device. Succeed only
+ if the number of channels matches. */
+ for (j = 0; j < nindev; j++)
+ if (indev[j] == thisdevice && chin[j] == wantchannels)
+ inindex = j;
+
+ /* if the same device is requested for input and output,
+ try to open it read/write */
+ if (inindex >= 0)
+ {
+ sys_setalarm(1000000);
+ if ((fd = open(devname, O_RDWR)) == -1)
+ {
+ post("%s (read/write): %s", devname, strerror(errno));
+ post("(now will try write-only...)");
+ }
+ else
+ {
+ if (sys_verbose)
+ post("opened %s for reading and writing\n", devname);
+ linux_adcs[inindex].d_fd = fd;
+ }
+ }
+ /* if that didn't happen or if it failed, try write-only */
+ if (fd == -1)
+ {
+ sys_setalarm(1000000);
+ if ((fd = open(devname, O_WRONLY)) == -1)
+ {
+ post("%s (writeonly): %s",
+ devname, strerror(errno));
+ break;
+ }
+ if (sys_verbose)
+ post("opened %s for writing only\n", devname);
+ }
+ if (ioctl(fd, SNDCTL_DSP_GETCAPS, &capabilities) == -1)
+ error("OSS: SNDCTL_DSP_GETCAPS failed %s", devname);
+
+ gotchans = oss_setchannels(fd,
+ (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels,
+ devname);
+
+ if (sys_verbose)
+ post("opened audio output on %s; got %d channels",
+ devname, gotchans);
+
+ if (gotchans < 2)
+ {
+ /* can't even do stereo? just give up. */
+ close(fd);
+ }
+ else
+ {
+ linux_dacs[linux_noutdevs].d_nchannels = gotchans;
+ linux_dacs[linux_noutdevs].d_fd = fd;
+ oss_configure(linux_dacs+linux_noutdevs, rate, 1, 0);
+
+ linux_noutdevs++;
+ outchannels += gotchans;
+ if (inindex >= 0)
+ {
+ linux_adcs[inindex].d_nchannels = gotchans;
+ chin[inindex] = gotchans;
+ }
+ }
+ /* LATER think about spreading large numbers of channels over
+ various dsp's and vice-versa */
+ wantmore = wantchannels - gotchans;
+ end_out_loop: ;
+ }
+
+ /* open input devices */
+ wantmore = 0;
+ if (nindev==-1)
+ nindev=4; /* spread channels over default-devices */
+ for (n = 0; n < nindev; n++)
+ {
+ int gotchans=0;
+ int thisdevice=indev[n];
+ int wantchannels = (nchin>n)?chin[n]:wantmore;
+ int alreadyopened = 0;
+ if (!wantchannels)
+ goto end_in_loop;
+
+ if (thisdevice > 1)
+ sprintf(devname, "/dev/dsp%d", thisdevice - 1);
+ else sprintf(devname, "/dev/dsp");
+
+ sys_setalarm(1000000);
+
+ /* perhaps it's already open from the above? */
+ if (linux_dacs[n].d_fd >= 0)
+ {
+ fd = linux_dacs[n].d_fd;
+ alreadyopened = 1;
+ }
+ else
+ {
+ /* otherwise try to open it here. */
+ if ((fd = open(devname, O_RDONLY)) == -1)
+ {
+ post("%s (readonly): %s", devname, strerror(errno));
+ goto end_in_loop;
+ }
+ if (sys_verbose)
+ post("opened %s for reading only\n", devname);
+ }
+ linux_adcs[linux_nindevs].d_fd = fd;
+ gotchans = oss_setchannels(fd,
+ (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels,
+ devname);
+ if (sys_verbose)
+ post("opened audio input device %s; got %d channels",
+ devname, gotchans);
+
+ if (gotchans < 1)
+ {
+ close(fd);
+ goto end_in_loop;
+ }
+
+ linux_adcs[linux_nindevs].d_nchannels = gotchans;
+
+ oss_configure(linux_adcs+linux_nindevs, rate, 0, alreadyopened);
+
+ inchannels += gotchans;
+ linux_nindevs++;
+
+ wantmore = wantchannels-gotchans;
+ /* LATER think about spreading large numbers of channels over
+ various dsp's and vice-versa */
+ end_in_loop: ;
+ }
+
+ linux_setch(inchannels, outchannels);
+
+ /* We have to do a read to start the engine. This is
+ necessary because sys_send_dacs waits until the input
+ buffer is filled and only reads on a filled buffer.
+ This is good, because it's a way to make sure that we
+ will not block. But I wonder why we only have to read
+ from one of the devices and not all of them??? */
+
+ if (linux_nindevs)
+ {
+ if (sys_verbose)
+ fprintf(stderr,("OSS: issuing first ADC 'read' ... "));
+ read(linux_adcs[0].d_fd, buf,
+ linux_adcs[0].d_bytespersamp *
+ linux_adcs[0].d_nchannels * DACBLKSIZE);
+ if (sys_verbose)
+ fprintf(stderr, "...done.\n");
+ }
+ sys_setalarm(0);
+ return (0);
+}
+
+void oss_close_audio( void)
+{
+ int i;
+ for (i=0;i<linux_nindevs;i++)
+ close(linux_adcs[i].d_fd);
+
+ for (i=0;i<linux_noutdevs;i++)
+ close(linux_dacs[i].d_fd);
+
+ linux_nindevs = linux_noutdevs = 0;
+}
+
+static int linux_dacs_write(int fd,void* buf,long bytes)
+{
+ return write(fd, buf, bytes);
+}
+
+static int linux_adcs_read(int fd,void* buf,long bytes)
+{
+ return read(fd, buf, bytes);
+}
+
+ /* query audio devices for "available" data size. */
+static void oss_calcspace(void)
+{
+ int dev;
+ audio_buf_info ainfo;
+ for (dev=0; dev < linux_noutdevs; dev++)
+ {
+ if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0)
+ fprintf(stderr,"OSS: ioctl on output device %d failed",dev);
+ linux_dacs[dev].d_space = ainfo.bytes;
+ }
+
+ for (dev = 0; dev < linux_nindevs; dev++)
+ {
+ if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE,&ainfo) < 0)
+ fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed",
+ dev, linux_adcs[dev].d_fd);
+ linux_adcs[dev].d_space = ainfo.bytes;
+ }
+}
+
+void linux_audiostatus(void)
+{
+ int dev;
+ if (!oss_blockmode)
+ {
+ oss_calcspace();
+ for (dev=0; dev < linux_noutdevs; dev++)
+ fprintf(stderr, "dac %d space %d\n", dev, linux_dacs[dev].d_space);
+
+ for (dev = 0; dev < linux_nindevs; dev++)
+ fprintf(stderr, "adc %d space %d\n", dev, linux_adcs[dev].d_space);
+
+ }
+}
+
+/* this call resyncs audio output and input which will cause discontinuities
+in audio output and/or input. */
+
+static void oss_doresync( void)
+{
+ int dev, zeroed = 0, wantsize;
+ char buf[OSS_MAXSAMPLEWIDTH * DACBLKSIZE * OSS_MAXCHPERDEV];
+ audio_buf_info ainfo;
+
+ /* 1. if any input devices are ahead (have more than 1 buffer stored),
+ drop one or more buffers worth */
+ for (dev = 0; dev < linux_nindevs; dev++)
+ {
+ if (linux_adcs[dev].d_space == 0)
+ {
+ linux_adcs_read(linux_adcs[dev].d_fd, buf,
+ OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
+ linux_adcs[dev].d_bytespersamp));
+ }
+ else while (linux_adcs[dev].d_space >
+ OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
+ linux_adcs[dev].d_bytespersamp))
+ {
+ linux_adcs_read(linux_adcs[dev].d_fd, buf,
+ OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
+ linux_adcs[dev].d_bytespersamp));
+ if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE, &ainfo) < 0)
+ {
+ fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed",
+ dev, linux_adcs[dev].d_fd);
+ break;
+ }
+ linux_adcs[dev].d_space = ainfo.bytes;
+ }
+ }
+
+ /* 2. if any output devices are behind, feed them zeros to catch them
+ up */
+ for (dev = 0; dev < linux_noutdevs; dev++)
+ {
+ while (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize -
+ linux_advance_samples * (linux_dacs[dev].d_nchannels *
+ linux_dacs[dev].d_bytespersamp))
+ {
+ if (!zeroed)
+ {
+ unsigned int i;
+ for (i = 0; i < OSS_XFERSAMPS(linux_dacs[dev].d_nchannels);
+ i++)
+ buf[i] = 0;
+ zeroed = 1;
+ }
+ linux_dacs_write(linux_dacs[dev].d_fd, buf,
+ OSS_XFERSIZE(linux_dacs[dev].d_nchannels,
+ linux_dacs[dev].d_bytespersamp));
+ if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0)
+ {
+ fprintf(stderr, "OSS: ioctl on output device %d, fd %d failed",
+ dev, linux_dacs[dev].d_fd);
+ break;
+ }
+ linux_dacs[dev].d_space = ainfo.bytes;
+ }
+ }
+ /* 3. if any DAC devices are too far ahead, plan to drop the
+ number of frames which will let the others catch up. */
+ for (dev = 0; dev < linux_noutdevs; dev++)
+ {
+ if (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize -
+ (linux_advance_samples - 1) * linux_dacs[dev].d_nchannels *
+ linux_dacs[dev].d_bytespersamp)
+ {
+ linux_dacs[dev].d_dropcount = linux_advance_samples - 1 -
+ (linux_dacs[dev].d_space - linux_dacs[dev].d_bufsize) /
+ (linux_dacs[dev].d_nchannels *
+ linux_dacs[dev].d_bytespersamp) ;
+ }
+ else linux_dacs[dev].d_dropcount = 0;
+ }
+}
+
+int oss_send_dacs(void)
+{
+ float *fp1, *fp2;
+ long fill;
+ int i, j, dev, rtnval = SENDDACS_YES;
+ char buf[OSS_MAXSAMPLEWIDTH * DACBLKSIZE * OSS_MAXCHPERDEV];
+ t_oss_int16 *sp;
+ t_oss_int32 *lp;
+ /* the maximum number of samples we should have in the ADC buffer */
+ int idle = 0;
+ int thischan;
+ double timeref, timenow;
+
+ if (!linux_nindevs && !linux_noutdevs)
+ return (SENDDACS_NO);
+
+ if (!oss_blockmode)
+ {
+ /* determine whether we're idle. This is true if either (1)
+ some input device has less than one buffer to read or (2) some
+ output device has fewer than (linux_advance_samples) blocks buffered
+ already. */
+ oss_calcspace();
+
+ for (dev=0; dev < linux_noutdevs; dev++)
+ if (linux_dacs[dev].d_dropcount ||
+ (linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space >
+ linux_advance_samples * linux_dacs[dev].d_bytespersamp *
+ linux_dacs[dev].d_nchannels))
+ idle = 1;
+ for (dev=0; dev < linux_nindevs; dev++)
+ if (linux_adcs[dev].d_space <
+ OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
+ linux_adcs[dev].d_bytespersamp))
+ idle = 1;
+ }
+
+ if (idle && !oss_blockmode)
+ {
+ /* sometimes---rarely---when the ADC available-byte-count is
+ zero, it's genuine, but usually it's because we're so
+ late that the ADC has overrun its entire kernel buffer. We
+ distinguish between the two by waiting 2 msec and asking again.
+ There should be an error flag we could check instead; look for this
+ someday... */
+ for (dev = 0;dev < linux_nindevs; dev++)
+ if (linux_adcs[dev].d_space == 0)
+ {
+ audio_buf_info ainfo;
+ sys_microsleep(2000);
+ oss_calcspace();
+ if (linux_adcs[dev].d_space != 0) continue;
+
+ /* here's the bad case. Give up and resync. */
+ sys_log_error(ERR_DATALATE);
+ oss_doresync();
+ return (SENDDACS_NO);
+ }
+ /* check for slippage between devices, either because
+ data got lost in the driver from a previous late condition, or
+ because the devices aren't synced. When we're idle, no
+ input device should have more than one buffer readable and
+ no output device should have less than linux_advance_samples-1
+ */
+
+ for (dev=0; dev < linux_noutdevs; dev++)
+ if (!linux_dacs[dev].d_dropcount &&
+ (linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space <
+ (linux_advance_samples - 2) *
+ (linux_dacs[dev].d_bytespersamp *
+ linux_dacs[dev].d_nchannels)))
+ goto badsync;
+ for (dev=0; dev < linux_nindevs; dev++)
+ if (linux_adcs[dev].d_space > 3 *
+ OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
+ linux_adcs[dev].d_bytespersamp))
+ goto badsync;
+
+ /* return zero to tell the scheduler we're idle. */
+ return (SENDDACS_NO);
+ badsync:
+ sys_log_error(ERR_RESYNC);
+ oss_doresync();
+ return (SENDDACS_NO);
+
+ }
+
+ /* do output */
+
+ timeref = sys_getrealtime();
+ for (dev=0, thischan = 0; dev < linux_noutdevs; dev++)
+ {
+ int nchannels = linux_dacs[dev].d_nchannels;
+ if (linux_dacs[dev].d_dropcount)
+ linux_dacs[dev].d_dropcount--;
+ else
+ {
+ if (linux_dacs[dev].d_bytespersamp == 4)
+ {
+ for (i = DACBLKSIZE * nchannels, fp1 = sys_soundout +
+ DACBLKSIZE*thischan,
+ lp = (t_oss_int32 *)buf; i--; fp1++, lp++)
+ {
+ float f = *fp1 * 2147483648.;
+ *lp = (f >= 2147483647. ? 2147483647. :
+ (f < -2147483648. ? -2147483648. : f));
+ }
+ }
+ else
+ {
+ for (i = DACBLKSIZE, fp1 = sys_soundout +
+ DACBLKSIZE*thischan,
+ sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels)
+ {
+ for (j=0, fp2 = fp1; j<nchannels; j++, fp2 += DACBLKSIZE)
+ {
+ int s = *fp2 * 32767.;
+ if (s > 32767) s = 32767;
+ else if (s < -32767) s = -32767;
+ sp[j] = s;
+ }
+ }
+ }
+ linux_dacs_write(linux_dacs[dev].d_fd, buf,
+ OSS_XFERSIZE(nchannels, linux_dacs[dev].d_bytespersamp));
+ if ((timenow = sys_getrealtime()) - timeref > 0.002)
+ {
+ if (!oss_blockmode)
+ sys_log_error(ERR_DACSLEPT);
+ else rtnval = SENDDACS_SLEPT;
+ }
+ timeref = timenow;
+ }
+ thischan += nchannels;
+ }
+ memset(sys_soundout, 0,
+ linux_outchannels * (sizeof(float) * DACBLKSIZE));
+
+ /* do input */
+
+ for (dev = 0, thischan = 0; dev < linux_nindevs; dev++)
+ {
+ int nchannels = linux_adcs[dev].d_nchannels;
+ linux_adcs_read(linux_adcs[dev].d_fd, buf,
+ OSS_XFERSIZE(nchannels, linux_adcs[dev].d_bytespersamp));
+
+ if ((timenow = sys_getrealtime()) - timeref > 0.002)
+ {
+ if (!oss_blockmode)
+ sys_log_error(ERR_ADCSLEPT);
+ else
+ rtnval = SENDDACS_SLEPT;
+ }
+ timeref = timenow;
+
+ if (linux_adcs[dev].d_bytespersamp == 4)
+ {
+ for (i = DACBLKSIZE*nchannels,
+ fp1 = sys_soundin + thischan*DACBLKSIZE,
+ lp = (t_oss_int32 *)buf; i--; fp1++, lp++)
+ {
+ *fp1 = ((float)(*lp))*(float)(1./2147483648.);
+ }
+ }
+ else
+ {
+ for (i = DACBLKSIZE,fp1 = sys_soundin + thischan*DACBLKSIZE,
+ sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels)
+ {
+ for (j=0;j<linux_inchannels;j++)
+ fp1[j*DACBLKSIZE] = (float)sp[j]*(float)3.051850e-05;
+ }
+ }
+ thischan += nchannels;
+ }
+ if (thischan != linux_inchannels)
+ bug("inchannels");
+ return (rtnval);
+}
+
+/* ----------------- audio I/O using the ALSA native API ---------------- */
+
+#ifdef ALSA
+static void alsa_checkversion( void)
+{
+ char snox[512];
+ int fd, nbytes;
+ if ((fd = open("/proc/asound/version", 0)) < 0 ||
+ (nbytes = read(fd, snox, 511)) < 1)
+ {
+ perror("cannot check Alsa version -- /proc/asound/version");
+ return;
+ }
+ snox[nbytes] = 0;
+#ifdef ALSA99
+ if (!strstr(snox, "Version 0.5"))
+ {
+ fprintf(stderr,
+"warning: Pd compiled for Alsa version 0.5 appears to be incompatible with\n\
+the installed version of ALSA. Here is what I found in /proc/asound/version:\n"
+ );
+ fprintf(stderr, "%s", snox);
+ }
+#else
+ if (!strstr(snox, "Version 0.9"))
+ {
+ fprintf(stderr,
+"warning: Pd compiled for Alsa version 0.9 appears to be incompatible with\n\
+the installed version of ALSA. Here is what I found in /proc/asound/version:\n"
+ );
+ fprintf(stderr, "%s", snox);
+ }
+#endif
+}
+#endif
+
+#ifdef ALSA99
+static int alsa_open_audio(int wantinchans, int wantoutchans,
+ int srate)
+{
+ int dir, voices, bsize;
+ int err, id, rate, i;
+ char *cardname;
+ snd_ctl_hw_info_t hwinfo;
+ snd_pcm_info_t pcminfo;
+ snd_pcm_channel_info_t channelinfo;
+ snd_ctl_t *handle;
+ snd_pcm_sync_t sync;
+
+ linux_inchannels = 0;
+ linux_outchannels = 0;
+
+ rate = 44100;
+ alsa_samplewidth = 4; /* first try 4 byte samples */
+
+ if (!wantinchans && !wantoutchans)
+ return (1);
+
+ alsa_checkversion();
+ if (sys_verbose)
+ {
+ if ((err = snd_card_get_longname(alsa_devno-1, &cardname)) < 0)
+ {
+ fprintf(stderr, "PD-ALSA: unable to get name of card number %d\n",
+ alsa_devno);
+ return 1;
+ }
+ fprintf(stderr, "PD-ALSA: using card %s\n", cardname);
+ free(cardname);
+ }
+
+ if ((err = snd_ctl_open(&handle, alsa_devno-1)) < 0)
+ {
+ fprintf(stderr, "PD-ALSA: unable to open control: %s\n",
+ snd_strerror(err));
+ return 1;
+ }
+
+ if ((err = snd_ctl_hw_info(handle, &hwinfo)) < 0)
+ {
+ fprintf(stderr, "PD-ALSA: unable to open get info: %s\n",
+ snd_strerror(err));
+ return 1;
+ }
+ if (hwinfo.pcmdevs < 1)
+ {
+ fprintf(stderr, "PD-ALSA: device %d doesn't support PCM\n",
+ alsa_devno);
+ snd_ctl_close(handle);
+ return 1;
+ }
+
+ if ((err = snd_ctl_pcm_info(handle, 0, &pcminfo)) < 0)
+ {
+ fprintf(stderr, "PD-ALSA: unable to open get pcm info: %s\n",
+ snd_strerror(err));
+ snd_ctl_close(handle);
+ return (1);
+ }
+ snd_ctl_close(handle);
+
+ /* find out if opening for input, output, or both and check that the
+ device can handle it. */
+ if (wantinchans && wantoutchans)
+ {
+ if (!(pcminfo.flags & SND_PCM_INFO_DUPLEX))
+ {
+ fprintf(stderr, "PD-ALSA: device is not full duplex\n");
+ return (1);
+ }
+ dir = SND_PCM_OPEN_DUPLEX;
+ }
+ else if (wantoutchans)
+ {
+ if (!(pcminfo.flags & SND_PCM_INFO_PLAYBACK))
+ {
+ fprintf(stderr, "PD-ALSA: device is not full duplex\n");
+ return (1);
+ }
+ dir = SND_PCM_OPEN_PLAYBACK;
+ }
+ else
+ {
+ if (!(pcminfo.flags & SND_PCM_INFO_CAPTURE))
+ {
+ fprintf(stderr, "PD-ALSA: device is not full duplex\n");
+ return (1);
+ }
+ dir = SND_PCM_OPEN_CAPTURE;
+ }
+
+ /* try to open the device */
+ if ((err = snd_pcm_open(&alsa_device[0].handle, alsa_devno-1, 0, dir)) < 0)
+ {
+ fprintf(stderr, "PD-ALSA: error opening device: %s\n",
+ snd_strerror(err));
+ return (1);
+ }
+ /* get information from the handle */
+ if (wantinchans)
+ {
+ channelinfo.channel = SND_PCM_CHANNEL_CAPTURE;
+ channelinfo.subdevice = 0;
+ if ((err = snd_pcm_channel_info(alsa_device[0].handle, &channelinfo))
+ < 0)
+ {
+ fprintf(stderr, "PD-ALSA: snd_pcm_channel_info (input): %s\n",
+ snd_strerror(err));
+ return (1);
+ }
+ if (sys_verbose)
+ post("input channels supported: %d-%d\n",
+ channelinfo.min_voices, channelinfo.max_voices);
+
+ if (wantinchans < channelinfo.min_voices)
+ post("increasing input channels to minimum of %d\n",
+ wantinchans = channelinfo.min_voices);
+ if (wantinchans > channelinfo.max_voices)
+ post("decreasing input channels to maximum of %d\n",
+ wantinchans = channelinfo.max_voices);
+ if (alsa_samplewidth == 4 &&
+ !(channelinfo.formats & (1<<SND_PCM_SFMT_S32_LE)))
+ {
+ fprintf(stderr,
+ "PD_ALSA: input doesn't support 32-bit samples; using 16\n");
+ alsa_samplewidth = 2;
+ }
+ if (alsa_samplewidth == 2 &&
+ !(channelinfo.formats & (1<<SND_PCM_SFMT_S16_LE)))
+ {
+ fprintf(stderr,
+ "PD_ALSA: can't find 4 or 2 byte format; giving up\n");
+ return (1);
+ }
+ }
+
+ if (wantoutchans)
+ {
+ channelinfo.channel = SND_PCM_CHANNEL_PLAYBACK;
+ channelinfo.subdevice = 0;
+ if ((err = snd_pcm_channel_info(alsa_device[0].handle, &channelinfo))
+ < 0)
+ {
+ fprintf(stderr, "PD-ALSA: snd_pcm_channel_info (output): %s\n",
+ snd_strerror(err));
+ return (1);
+ }
+ if (sys_verbose)
+ post("output channels supported: %d-%d\n",
+ channelinfo.min_voices, channelinfo.max_voices);
+ if (wantoutchans < channelinfo.min_voices)
+ post("increasing output channels to minimum of %d\n",
+ wantoutchans = channelinfo.min_voices);
+ if (wantoutchans > channelinfo.max_voices)
+ post("decreasing output channels to maximum of %d\n",
+ wantoutchans = channelinfo.max_voices);
+ if (alsa_samplewidth == 4 &&
+ !(channelinfo.formats & (1<<SND_PCM_SFMT_S32_LE)))
+ {
+ fprintf(stderr,
+ "PD_ALSA: output doesn't support 32-bit samples; using 16\n");
+ alsa_samplewidth = 2;
+ }
+ if (alsa_samplewidth == 2 &&
+ !(channelinfo.formats & (1<<SND_PCM_SFMT_S16_LE)))
+ {
+ fprintf(stderr,
+ "PD_ALSA: can't find 4 or 2 byte format; giving up\n");
+ return (1);
+ }
+ }
+
+ linux_setsr(rate);
+ linux_setch(wantinchans, wantoutchans);
+
+ if (wantinchans)
+ alsa_set_params(&alsa_device[0], SND_PCM_CHANNEL_CAPTURE,
+ srate, wantinchans);
+ if (wantoutchans)
+ alsa_set_params(&alsa_device[0], SND_PCM_CHANNEL_PLAYBACK,
+ srate, wantoutchans);
+
+ n_alsa_dev = 1;
+
+ /* check that all is as we think it should be */
+ for (i = 0; i < n_alsa_dev; i++)
+ {
+ /* We need to handle if the rate is not the same for all
+ * devices. For now just hope. */
+ rate = alsa_device[i].setup.format.rate;
+
+ /* It turns out that this checking does not work on all of my cards
+ * - in full duplex on my trident 4dwave the setup on the capture channel
+ * shows a sampling rate of 0. This is not true on my ess solo1. Checking
+ * the dac last helps the problem. All of this needs to be much smarter
+ * anyway (last minute hack). A warning above is all I have time for.
+ */
+ if (rate != srate)
+ {
+ post("PD-ALSA: unable to obtain rate %i using %i", srate, rate);
+ post("PD-ALSA: (despite this warning Pd might still work.)");
+ }
+ }
+ bsize = alsa_samplewidth *
+ (linux_inchannels > linux_outchannels ? linux_inchannels :
+ linux_outchannels) * DACBLKSIZE;
+ alsa_buf = malloc(bsize);
+ if (!alsa_buf)
+ return (1);
+ memset(alsa_buf, 0, bsize);
+ return 0;
+}
+
+void alsa_set_params(t_alsa_dev *dev, int dir, int rate, int voices)
+{
+ int err;
+ struct snd_pcm_channel_params params;
+
+ memset(&dev->info, 0, sizeof(dev->info));
+ dev->info.channel = dir;
+ if ((err = snd_pcm_channel_info(dev->handle, &dev->info) < 0))
+ {
+ fprintf(stderr, "PD-ALSA: error getting channel info: %s\n",
+ snd_strerror(err));
+ }
+ memset(&params, 0, sizeof(params));
+ params.format.interleave = 1; /* may do non-interleaved later */
+ /* format is 2 or 4 bytes per sample depending on what was possible */
+ params.format.format =
+ (alsa_samplewidth == 4 ? SND_PCM_SFMT_S32_LE : SND_PCM_SFMT_S16_LE);
+
+ /*will check this further down -just try for now*/
+ params.format.rate = rate;
+ params.format.voices = voices;
+ params.start_mode = SND_PCM_START_GO; /* seems most reliable */
+ /*do not stop at overrun/underrun*/
+ params.stop_mode = SND_PCM_STOP_ROLLOVER;
+
+ params.channel = dir; /* playback|capture */
+ params.buf.stream.queue_size =
+ (ALSA_EXTRABUFFER + linux_advance_samples)
+ * alsa_samplewidth * voices;
+ params.buf.stream.fill = SND_PCM_FILL_SILENCE_WHOLE;
+ params.mode = SND_PCM_MODE_STREAM;
+
+ if ((err = snd_pcm_channel_params(dev->handle, &params)) < 0)
+ {
+ printf("PD-ALSA: error setting parameters %s", snd_strerror(err));
+ }
+
+ /* This should clear the buffers but does not. There is often noise at
+ startup that sounds like crap left in the buffers - maybe in the lib
+ instead of the driver? Some solution needs to be found.
+ */
+
+ if ((err = snd_pcm_channel_prepare(dev->handle, dir)) < 0)
+ {
+ printf("PD-ALSA: error preparing channel %s", snd_strerror(err));
+ }
+ dev->setup.channel = dir;
+
+ if ((err = snd_pcm_channel_setup(dev->handle, &dev->setup)) < 0)
+ {
+ printf("PD-ALSA: error getting setup %s", snd_strerror(err));
+ }
+ /* for some reason, if you don't writesomething before starting the
+ converters we get trash on startup */
+ if (dir == SND_PCM_CHANNEL_PLAYBACK)
+ {
+ char foo[1024];
+ int xxx = 1024 - (1024 % (linux_outchannels * alsa_samplewidth));
+ int i, r;
+ for (i = 0; i < xxx; i++)
+ foo[i] = 0;
+ if ((r = snd_pcm_write(dev->handle, foo, xxx)) < xxx)
+ fprintf(stderr, "alsa_write: %s\n", snd_strerror(errno));
+ }
+ snd_pcm_channel_go(dev->handle, dir);
+}
+
+void alsa_close_audio(void)
+{
+ int i;
+ for(i = 0; i < n_alsa_dev; i++)
+ snd_pcm_close(alsa_device[i].handle);
+}
+
+/* #define DEBUG_ALSA_XFER */
+
+int alsa_send_dacs(void)
+{
+ static int16_t *sp;
+ t_sample *fp, *fp1, *fp2;
+ int i, j, k, err, devno = 0;
+ int inputcount = 0, outputcount = 0, inputlate = 0, outputlate = 0;
+ int result;
+ snd_pcm_channel_status_t stat;
+ static int callno = 0;
+ static int xferno = 0;
+ int countwas = 0;
+ double timelast;
+ static double timenow;
+ int inchannels = linux_inchannels;
+ int outchannels = linux_outchannels;
+ int inbytesperframe = inchannels * alsa_samplewidth;
+ int outbytesperframe = outchannels * alsa_samplewidth;
+ int intransfersize = DACBLKSIZE * inbytesperframe;
+ int outtransfersize = DACBLKSIZE * outbytesperframe;
+ int alsaerror;
+ int loggederror = 0;
+
+ if (!inchannels && !outchannels)
+ return (SENDDACS_NO);
+ timelast = timenow;
+ timenow = sys_getrealtime();
+
+#ifdef DEBUG_ALSA_XFER
+ if (timenow - timelast > 0.050)
+ fprintf(stderr, "(%d)",
+ (int)(1000 * (timenow - timelast))), fflush(stderr);
+#endif
+
+ callno++;
+ /* get input and output channel status */
+ if (inchannels > 0)
+ {
+ devno = 0;
+ stat.channel = SND_PCM_CHANNEL_CAPTURE;
+ if (alsaerror = snd_pcm_channel_status(alsa_device[devno].handle,
+ &stat))
+ {
+ fprintf(stderr, "snd_pcm_channel_status (input): %s\n",
+ snd_strerror(alsaerror));
+ return (SENDDACS_NO);
+ }
+ inputcount = stat.count;
+ inputlate = (stat.underrun > 0 || stat.overrun > 0);
+ }
+ if (outchannels > 0)
+ {
+ devno = 0;
+ stat.channel = SND_PCM_CHANNEL_PLAYBACK;
+ if (alsaerror = snd_pcm_channel_status(alsa_device[devno].handle,
+ &stat))
+ {
+ fprintf(stderr, "snd_pcm_channel_status (output): %s\n",
+ snd_strerror(alsaerror));
+ return (SENDDACS_NO);
+ }
+ outputcount = stat.count;
+ outputlate = (stat.underrun > 0 || stat.overrun > 0);
+ }
+
+ /* check if input not ready */
+ if (inputcount < intransfersize)
+ {
+ /* fprintf(stderr, "no adc; count %d, free %d, call %d, xfer %d\n",
+ stat.count,
+ stat.free,
+ callno, xferno); */
+ if (outchannels > 0)
+ {
+ /* if there's no input but output is hungry, feed output. */
+ while (outputcount < (linux_advance_samples + ALSA_JITTER)
+ * outbytesperframe)
+ {
+ if (!loggederror)
+ sys_log_error(ERR_RESYNC), loggederror = 1;
+ memset(alsa_buf, 0, outtransfersize);
+ result = snd_pcm_write(alsa_device[devno].handle,
+ alsa_buf, outtransfersize);
+ if (result < outtransfersize)
+ {
+#ifdef DEBUG_ALSA_XFER
+ if (result >= 0 || errno == EAGAIN)
+ fprintf(stderr, "ALSA: write returned %d of %d\n",
+ result, outtransfersize);
+ else fprintf(stderr, "ALSA: write: %s\n",
+ snd_strerror(errno));
+ fprintf(stderr,
+ "inputcount %d, outputcount %d, outbufsize %d\n",
+ inputcount, outputcount,
+ (ALSA_EXTRABUFFER + linux_advance_samples)
+ * alsa_samplewidth * outchannels);
+#endif
+ return (SENDDACS_NO);
+ }
+ stat.channel = SND_PCM_CHANNEL_PLAYBACK;
+ if (alsaerror =
+ snd_pcm_channel_status(alsa_device[devno].handle,
+ &stat))
+ {
+ fprintf(stderr, "snd_pcm_channel_status (output): %s\n",
+ snd_strerror(alsaerror));
+ return (SENDDACS_NO);
+ }
+ outputcount = stat.count;
+ }
+ }
+
+ return SENDDACS_NO;
+ }
+
+ /* if output buffer has at least linux_advance_samples in it, we're
+ not ready for this batch. */
+ if (outputcount > linux_advance_samples * outbytesperframe)
+ {
+ if (inchannels > 0)
+ {
+ while (inputcount > (DACBLKSIZE + ALSA_JITTER) * outbytesperframe)
+ {
+ if (!loggederror)
+ sys_log_error(ERR_RESYNC), loggederror = 1;
+ devno = 0;
+ result = snd_pcm_read(alsa_device[devno].handle, alsa_buf,
+ intransfersize);
+ if (result < intransfersize)
+ {
+#ifdef DEBUG_ALSA_XFER
+ if (result < 0)
+ fprintf(stderr,
+ "snd_pcm_read %d %d: %s\n",
+ callno, xferno, snd_strerror(errno));
+ else fprintf(stderr,
+ "snd_pcm_read %d %d returned only %d\n",
+ callno, xferno, result);
+ fprintf(stderr,
+ "inputcount %d, outputcount %d, inbufsize %d\n",
+ inputcount, outputcount,
+ (ALSA_EXTRABUFFER + linux_advance_samples)
+ * alsa_samplewidth * inchannels);
+#endif
+ return (SENDDACS_NO);
+ }
+ devno = 0;
+ stat.channel = SND_PCM_CHANNEL_CAPTURE;
+ if (alsaerror =
+ snd_pcm_channel_status(alsa_device[devno].handle,
+ &stat))
+ {
+ fprintf(stderr, "snd_pcm_channel_status (input): %s\n",
+ snd_strerror(alsaerror));
+ return (SENDDACS_NO);
+ }
+ inputcount = stat.count;
+ inputlate = (stat.underrun > 0 || stat.overrun > 0);
+ }
+ return (SENDDACS_NO);
+ }
+ }
+ if (sys_getrealtime() - timenow > 0.002)
+ {
+#ifdef DEBUG_ALSA_XFER
+ fprintf(stderr, "check %d took %d msec\n",
+ callno, (int)(1000 * (timenow - timelast))), fflush(stderr);
+#endif
+ sys_log_error(ERR_DACSLEPT);
+ timenow = sys_getrealtime();
+ }
+ if (inputlate || outputlate)
+ sys_log_error(ERR_DATALATE);
+
+ /* do output */
+ /* this "for" loop won't work for more than one device. */
+ for (devno = 0, fp = sys_soundout; devno < (outchannels > 0); devno++,
+ fp += 128)
+ {
+ if (alsa_samplewidth == 4)
+ {
+ for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DACBLKSIZE)
+ {
+ for (j = i, k = DACBLKSIZE, fp2 = fp1; k--;
+ j += outchannels, fp2++)
+ {
+ float s1 = *fp2 * INT32_MAX;
+ ((t_alsa_sample32 *)alsa_buf)[j] = CLIP32(s1);
+ }
+ }
+ }
+ else
+ {
+ for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DACBLKSIZE)
+ {
+ for (j = i, k = DACBLKSIZE, fp2 = fp1; k--;
+ j += outchannels, fp2++)
+ {
+ int s = *fp2 * 32767.;
+ if (s > 32767)
+ s = 32767;
+ else if (s < -32767)
+ s = -32767;
+ ((t_alsa_sample16 *)alsa_buf)[j] = s;
+ }
+ }
+ }
+
+ result = snd_pcm_write(alsa_device[devno].handle, alsa_buf,
+ outtransfersize);
+ if (result < outtransfersize)
+ {
+#ifdef DEBUG_ALSA_XFER
+ if (result >= 0 || errno == EAGAIN)
+ fprintf(stderr, "ALSA: write returned %d of %d\n",
+ result, outtransfersize);
+ else fprintf(stderr, "ALSA: write: %s\n",
+ snd_strerror(errno));
+ fprintf(stderr,
+ "inputcount %d, outputcount %d, outbufsize %d\n",
+ inputcount, outputcount,
+ (ALSA_EXTRABUFFER + linux_advance_samples)
+ * alsa_samplewidth * outchannels);
+#endif
+ sys_log_error(ERR_DACSLEPT);
+ return (SENDDACS_NO);
+ }
+ }
+ /* zero out the output buffer */
+ memset(sys_soundout, 0, DACBLKSIZE * sizeof(*sys_soundout) *
+ linux_outchannels);
+ if (sys_getrealtime() - timenow > 0.002)
+ {
+#if DEBUG_ALSA_XFER
+ fprintf(stderr, "output %d took %d msec\n",
+ callno, (int)(1000 * (timenow - timelast))), fflush(stderr);
+#endif
+ timenow = sys_getrealtime();
+ sys_log_error(ERR_DACSLEPT);
+ }
+
+ /* do input */
+ for (devno = 0, fp = sys_soundin; devno < (linux_inchannels > 0); devno++,
+ fp += 128)
+ {
+ result = snd_pcm_read(alsa_device[devno].handle, alsa_buf,
+ intransfersize);
+ if (result < intransfersize)
+ {
+#ifdef DEBUG_ALSA_XFER
+ if (result < 0)
+ fprintf(stderr,
+ "snd_pcm_read %d %d: %s\n",
+ callno, xferno, snd_strerror(errno));
+ else fprintf(stderr,
+ "snd_pcm_read %d %d returned only %d\n",
+ callno, xferno, result);
+ fprintf(stderr,
+ "inputcount %d, outputcount %d, inbufsize %d\n",
+ inputcount, outputcount,
+ (ALSA_EXTRABUFFER + linux_advance_samples)
+ * alsa_samplewidth * inchannels);
+#endif
+ sys_log_error(ERR_ADCSLEPT);
+ return (SENDDACS_NO);
+ }
+ if (alsa_samplewidth == 4)
+ {
+ for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DACBLKSIZE)
+ {
+ for (j = i, k = DACBLKSIZE, fp2 = fp1; k--;
+ j += inchannels, fp2++)
+ *fp2 = (float) ((t_alsa_sample32 *)alsa_buf)[j]
+ * (1./ INT32_MAX);
+ }
+ }
+ else
+ {
+ for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DACBLKSIZE)
+ {
+ for (j = i, k = DACBLKSIZE, fp2 = fp1; k--; j += inchannels, fp2++)
+ *fp2 = (float) ((t_alsa_sample16 *)alsa_buf)[j]
+ * 3.051850e-05;
+ }
+ }
+ }
+ xferno++;
+ if (sys_getrealtime() - timenow > 0.002)
+ {
+#ifdef DEBUG_ALSA_XFER
+ fprintf(stderr, "routine took %d msec\n",
+ (int)(1000 * (sys_getrealtime() - timenow)));
+#endif
+ sys_log_error(ERR_ADCSLEPT);
+ }
+ return SENDDACS_YES;
+}
+
+#endif /* ALSA99 */
+
+/* support for ALSA pcmv2 api by Karl MacMillan<karlmac@peabody.jhu.edu> */
+
+#ifdef ALSA01
+
+static void check_error(int err, const char *why)
+{
+ if (err < 0)
+ fprintf(stderr, "%s: %s\n", why, snd_strerror(err));
+}
+
+static int alsa_open_audio(int wantinchans, int wantoutchans, int srate)
+{
+ int err, inchans = 0, outchans = 0, subunitdir;
+ char devname[512];
+ snd_pcm_hw_params_t* hw_params;
+ snd_pcm_sw_params_t* sw_params;
+ snd_output_t* out;
+ int frag_size = (linux_fragsize ? linux_fragsize : ALSA_DEFFRAGSIZE);
+ int nfrags, i;
+ short* tmp_buf;
+ unsigned int tmp_uint;
+ int advwas = sys_schedadvance;
+
+ if (linux_nfragment)
+ {
+ nfrags = linux_nfragment;
+ sys_schedadvance = (frag_size * linux_nfragment * 1.0e6) / srate;
+ }
+ else nfrags = sys_schedadvance * (float)srate / (1e6 * frag_size);
+
+ if (sys_verbose || (sys_schedadvance != advwas))
+ post("audio buffer set to %d", (int)(0.001 * sys_schedadvance));
+ if (wantinchans || wantoutchans)
+ alsa_checkversion();
+ if (wantinchans)
+ {
+ err = snd_pcm_open(&alsa_device.inhandle, alsa_devname,
+ SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
+
+ check_error(err, "snd_pcm_open (input)");
+ if (err < 0)
+ inchans = 0;
+ else
+ {
+ inchans = wantinchans;
+ snd_pcm_nonblock(alsa_device.inhandle, 1);
+ }
+ }
+ if (wantoutchans)
+ {
+ err = snd_pcm_open(&alsa_device.outhandle, alsa_devname,
+ SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
+
+ check_error(err, "snd_pcm_open (output)");
+ if (err < 0)
+ outchans = 0;
+ else
+ {
+ outchans = wantoutchans;
+ snd_pcm_nonblock(alsa_device.outhandle, 1);
+ }
+ }
+ if (inchans)
+ {
+ if (sys_verbose)
+ post("opening sound input...");
+ err = snd_pcm_hw_params_malloc(&hw_params);
+ check_error(err, "snd_pcm_hw_params_malloc (input)");
+
+ // get the default params
+ err = snd_pcm_hw_params_any(alsa_device.inhandle, hw_params);
+ check_error(err, "snd_pcm_hw_params_any (input)");
+ // set interleaved access - FIXME deal with other access types
+ err = snd_pcm_hw_params_set_access(alsa_device.inhandle, hw_params,
+ SND_PCM_ACCESS_RW_INTERLEAVED);
+ check_error(err, "snd_pcm_hw_params_set_access (input)");
+ // Try to set 32 bit format first
+ err = snd_pcm_hw_params_set_format(alsa_device.inhandle, hw_params,
+ SND_PCM_FORMAT_S32);
+ if (err < 0)
+ {
+ /* fprintf(stderr,
+ "PD-ALSA: 32 bit format not available - using 16\n"); */
+ err = snd_pcm_hw_params_set_format(alsa_device.inhandle, hw_params,
+ SND_PCM_FORMAT_S16);
+ check_error(err, "snd_pcm_hw_params_set_format (input)");
+ alsa_samplewidth = 2;
+ }
+ else
+ {
+ alsa_samplewidth = 4;
+ }
+ post("Sample width set to %d bytes", alsa_samplewidth);
+ // set the subformat
+ err = snd_pcm_hw_params_set_subformat(alsa_device.inhandle, hw_params,
+ SND_PCM_SUBFORMAT_STD);
+ check_error(err, "snd_pcm_hw_params_set_subformat (input)");
+ // set the number of channels
+ tmp_uint = inchans;
+ err = snd_pcm_hw_params_set_channels_min(alsa_device.inhandle,
+ hw_params, &tmp_uint);
+ check_error(err, "snd_pcm_hw_params_set_channels (input)");
+ if (tmp_uint != (unsigned)inchans)
+ post("ALSA: set input channels to %d", tmp_uint);
+ inchans = tmp_uint;
+ // set the sampling rate
+ err = snd_pcm_hw_params_set_rate_min(alsa_device.inhandle, hw_params,
+ &srate, 0);
+ check_error(err, "snd_pcm_hw_params_set_rate_min (input)");
+#if 0
+ err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir);
+ post("input sample rate %d", err);
+#endif
+ // set the period - ie frag size
+ // post("fragsize a %d", frag_size);
+
+ /* LATER try this to get a recommended period size...
+ right now, it trips an assertion failure in ALSA lib */
+#if 0
+ post("input period was %d, min %d, max %d\n",
+ snd_pcm_hw_params_get_period_size(hw_params, 0),
+ snd_pcm_hw_params_get_period_size_min(hw_params, 0),
+ snd_pcm_hw_params_get_period_size_max(hw_params, 0));
+#endif
+ err = snd_pcm_hw_params_set_period_size_near(alsa_device.inhandle,
+ hw_params,
+ (snd_pcm_uframes_t)
+ frag_size, 0);
+ check_error(err, "snd_pcm_hw_params_set_period_size_near (input)");
+ // post("fragsize b %d", frag_size);
+ // set the number of periods - ie numfrags
+ // post("nfrags a %d", nfrags);
+ err = snd_pcm_hw_params_set_periods_near(alsa_device.inhandle,
+ hw_params, nfrags, 0);
+ check_error(err, "snd_pcm_hw_params_set_periods_near (input)");
+ // set the buffer size
+ err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.inhandle,
+ hw_params, nfrags * frag_size);
+ check_error(err, "snd_pcm_hw_params_set_buffer_size_near (input)");
+
+ err = snd_pcm_hw_params(alsa_device.inhandle, hw_params);
+ check_error(err, "snd_pcm_hw_params (input)");
+
+ snd_pcm_hw_params_free(hw_params);
+
+ err = snd_pcm_sw_params_malloc(&sw_params);
+ check_error(err, "snd_pcm_sw_params_malloc (input)");
+ err = snd_pcm_sw_params_current(alsa_device.inhandle, sw_params);
+ check_error(err, "snd_pcm_sw_params_current (input)");
+#if 1
+ err = snd_pcm_sw_params_set_start_mode(alsa_device.inhandle, sw_params,
+ SND_PCM_START_EXPLICIT);
+ check_error(err, "snd_pcm_sw_params_set_start_mode (input)");
+ err = snd_pcm_sw_params_set_xrun_mode(alsa_device.inhandle, sw_params,
+ SND_PCM_XRUN_NONE);
+ check_error(err, "snd_pcm_sw_params_set_xrun_mode (input)");
+#else
+ err = snd_pcm_sw_params_set_start_threshold(alsa_device.inhandle,
+ sw_params, nfrags * frag_size);
+ check_error(err, "snd_pcm_sw_params_set_start_threshold (input)");
+ err = snd_pcm_sw_params_set_stop_threshold(alsa_device.inhandle,
+ sw_params, 1);
+ check_error(err, "snd_pcm_sw_params_set_stop_threshold (input)");
+#endif
+
+ err = snd_pcm_sw_params_set_avail_min(alsa_device.inhandle, sw_params,
+ frag_size);
+ check_error(err, "snd_pcm_sw_params_set_avail_min (input)");
+ err = snd_pcm_sw_params(alsa_device.inhandle, sw_params);
+ check_error(err, "snd_pcm_sw_params (input)");
+
+ snd_pcm_sw_params_free(sw_params);
+
+ snd_output_stdio_attach(&out, stderr, 0);
+#if 0
+ if (sys_verbose)
+ {
+ snd_pcm_dump_hw_setup(alsa_device.inhandle, out);
+ snd_pcm_dump_sw_setup(alsa_device.inhandle, out);
+ }
+#endif
+ }
+
+ if (outchans)
+ {
+ int foo;
+ if (sys_verbose)
+ post("opening sound output...");
+ err = snd_pcm_hw_params_malloc(&hw_params);
+ check_error(err, "snd_pcm_sw_params (output)");
+
+ // get the default params
+ err = snd_pcm_hw_params_any(alsa_device.outhandle, hw_params);
+ check_error(err, "snd_pcm_hw_params_any (output)");
+ // set interleaved access - FIXME deal with other access types
+ err = snd_pcm_hw_params_set_access(alsa_device.outhandle, hw_params,
+ SND_PCM_ACCESS_RW_INTERLEAVED);
+ check_error(err, "snd_pcm_hw_params_set_access (output)");
+ // Try to set 32 bit format first
+ err = snd_pcm_hw_params_set_format(alsa_device.outhandle, hw_params,
+ SND_PCM_FORMAT_S32);
+ if (err < 0)
+ {
+ err = snd_pcm_hw_params_set_format(alsa_device.outhandle,
+ hw_params,SND_PCM_FORMAT_S16);
+ check_error(err, "snd_pcm_hw_params_set_format (output)");
+ /* fprintf(stderr,
+ "PD-ALSA: 32 bit format not available - using 16\n"); */
+ alsa_samplewidth = 2;
+ }
+ else
+ {
+ alsa_samplewidth = 4;
+ }
+ // set the subformat
+ err = snd_pcm_hw_params_set_subformat(alsa_device.outhandle, hw_params,
+ SND_PCM_SUBFORMAT_STD);
+ check_error(err, "snd_pcm_hw_params_set_subformat (output)");
+ // set the number of channels
+ tmp_uint = outchans;
+ err = snd_pcm_hw_params_set_channels_min(alsa_device.outhandle,
+ hw_params, &tmp_uint);
+ check_error(err, "snd_pcm_hw_params_set_channels (output)");
+ if (tmp_uint != (unsigned)outchans)
+ post("alsa: set output channels to %d", tmp_uint);
+ outchans = tmp_uint;
+ // set the sampling rate
+ err = snd_pcm_hw_params_set_rate_min(alsa_device.outhandle, hw_params,
+ &srate, 0);
+ check_error(err, "snd_pcm_hw_params_set_rate_min (output)");
+#if 0
+ err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir);
+ post("output sample rate %d", err);
+#endif
+ // set the period - ie frag size
+#if 0
+ post("output period was %d, min %d, max %d\n",
+ snd_pcm_hw_params_get_period_size(hw_params, 0),
+ snd_pcm_hw_params_get_period_size_min(hw_params, 0),
+ snd_pcm_hw_params_get_period_size_max(hw_params, 0));
+#endif
+ // post("fragsize c %d", frag_size);
+ err = snd_pcm_hw_params_set_period_size_near(alsa_device.outhandle,
+ hw_params,
+ (snd_pcm_uframes_t)
+ frag_size, 0);
+ // post("fragsize d %d", frag_size);
+ check_error(err, "snd_pcm_hw_params_set_period_size_near (output)");
+ // set the number of periods - ie numfrags
+ err = snd_pcm_hw_params_set_periods_near(alsa_device.outhandle,
+ hw_params, nfrags, 0);
+ check_error(err, "snd_pcm_hw_params_set_periods_near (output)");
+ // set the buffer size
+ err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.outhandle,
+ hw_params, nfrags * frag_size);
+
+ check_error(err, "snd_pcm_hw_params_set_buffer_size_near (output)");
+
+ err = snd_pcm_hw_params(alsa_device.outhandle, hw_params);
+ check_error(err, "snd_pcm_hw_params (output)");
+
+ snd_pcm_hw_params_free(hw_params);
+
+ err = snd_pcm_sw_params_malloc(&sw_params);
+ check_error(err, "snd_pcm_sw_params_malloc (output)");
+ err = snd_pcm_sw_params_current(alsa_device.outhandle, sw_params);
+ check_error(err, "snd_pcm_sw_params_current (output)");
+#if 1
+ err = snd_pcm_sw_params_set_start_mode(alsa_device.outhandle,
+ sw_params,
+ SND_PCM_START_EXPLICIT);
+ check_error(err, "snd_pcm_sw_params_set_start_mode (output)");
+ err = snd_pcm_sw_params_set_xrun_mode(alsa_device.outhandle, sw_params,
+ SND_PCM_XRUN_NONE);
+ check_error(err, "snd_pcm_sw_params_set_xrun_mode (output)");
+#else
+ err = snd_pcm_sw_params_set_start_threshold(alsa_device.inhandle,
+ sw_params, nfrags * frag_size);
+ check_error(err, "snd_pcm_sw_params_set_start_threshold (output)");
+ err = snd_pcm_sw_params_set_stop_threshold(alsa_device.inhandle,
+ sw_params, 1);
+ check_error(err, "snd_pcm_sw_params_set_stop_threshold (output)");
+#endif
+
+ err = snd_pcm_sw_params_set_avail_min(alsa_device.outhandle, sw_params,
+ frag_size);
+ check_error(err, "snd_pcm_sw_params_set_avail_min (output)");
+ err = snd_pcm_sw_params(alsa_device.outhandle, sw_params);
+ check_error(err, "snd_pcm_sw_params (output)");
+
+ snd_pcm_sw_params_free(sw_params);
+
+ snd_output_stdio_attach(&out, stderr, 0);
+#if 0
+ if (sys_verbose)
+ {
+ snd_pcm_dump_hw_setup(alsa_device.outhandle, out);
+ snd_pcm_dump_sw_setup(alsa_device.outhandle, out);
+ }
+#endif
+ }
+
+ linux_setsr(srate);
+ linux_setch(inchans, outchans);
+
+ if (inchans)
+ snd_pcm_prepare(alsa_device.inhandle);
+ if (outchans)
+ snd_pcm_prepare(alsa_device.outhandle);
+
+ // if duplex we can link the channels so they start together
+ if (inchans && outchans)
+ snd_pcm_link(alsa_device.inhandle, alsa_device.outhandle);
+
+ // set up the buffer
+ if (outchans > inchans)
+ alsa_buf = (short *)calloc(sizeof(char) * alsa_samplewidth, DACBLKSIZE
+ * outchans);
+ else
+ alsa_buf = (short *)calloc(sizeof(char) * alsa_samplewidth, DACBLKSIZE
+ * inchans);
+ // fill the buffer with silence
+ if (outchans)
+ {
+ i = nfrags + 1;
+ while (i--)
+ snd_pcm_writei(alsa_device.outhandle, alsa_buf, frag_size);
+ }
+
+ // set up the status variables
+ err = snd_pcm_status_malloc(&in_status);
+ check_error(err, "snd_pcm_status_malloc");
+ err = snd_pcm_status_malloc(&out_status);
+ check_error(err, "snd_pcm_status_malloc");
+
+ // start the device
+#if 1
+ if (outchans)
+ {
+ err = snd_pcm_start(alsa_device.outhandle);
+ check_error(err, "snd_pcm_start");
+ }
+ else if (inchans)
+ {
+ err = snd_pcm_start(alsa_device.inhandle);
+ check_error(err, "snd_pcm_start");
+ }
+#endif
+
+ return 0;
+}
+
+void alsa_close_audio(void)
+{
+ int err;
+ if (linux_inchannels)
+ {
+ err = snd_pcm_close(alsa_device.inhandle);
+ check_error(err, "snd_pcm_close (input)");
+ }
+ if (linux_outchannels)
+ {
+ err = snd_pcm_close(alsa_device.outhandle);
+ check_error(err, "snd_pcm_close (output)");
+ }
+}
+
+// #define DEBUG_ALSA_XFER
+
+int alsa_send_dacs(void)
+{
+ static int16_t *sp;
+ static int xferno = 0;
+ static int callno = 0;
+ static double timenow;
+ double timelast;
+ t_sample *fp, *fp1, *fp2;
+ int i, j, k, err, devno = 0;
+ int inputcount = 0, outputcount = 0, inputlate = 0, outputlate = 0;
+ int result;
+ int inchannels = linux_inchannels;
+ int outchannels = linux_outchannels;
+ unsigned int intransfersize = DACBLKSIZE;
+ unsigned int outtransfersize = DACBLKSIZE;
+
+ // get the status
+ if (!inchannels && !outchannels)
+ {
+ return SENDDACS_NO;
+ }
+
+ timelast = timenow;
+ timenow = sys_getrealtime();
+
+#ifdef DEBUG_ALSA_XFER
+ if (timenow - timelast > 0.050)
+ fprintf(stderr, "(%d)",
+ (int)(1000 * (timenow - timelast))), fflush(stderr);
+#endif
+
+ callno++;
+
+ if (inchannels)
+ {
+ snd_pcm_status(alsa_device.inhandle, in_status);
+ if (snd_pcm_status_get_avail(in_status) < intransfersize)
+ return SENDDACS_NO;
+ }
+ if (outchannels)
+ {
+ snd_pcm_status(alsa_device.outhandle, out_status);
+ if (snd_pcm_status_get_avail(out_status) < outtransfersize)
+ return SENDDACS_NO;
+ }
+
+ /* do output */
+ if (outchannels)
+ {
+ fp = sys_soundout;
+ if (alsa_samplewidth == 4)
+ {
+ for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DACBLKSIZE)
+ {
+ for (j = i, k = DACBLKSIZE, fp2 = fp1; k--;
+ j += outchannels, fp2++)
+ {
+ float s1 = *fp2 * INT32_MAX;
+ ((t_alsa_sample32 *)alsa_buf)[j] = CLIP32(s1);
+ }
+ }
+ }
+ else
+ {
+ for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DACBLKSIZE)
+ {
+ for (j = i, k = DACBLKSIZE, fp2 = fp1; k--;
+ j += outchannels, fp2++)
+ {
+ int s = *fp2 * 32767.;
+ if (s > 32767)
+ s = 32767;
+ else if (s < -32767)
+ s = -32767;
+ ((t_alsa_sample16 *)alsa_buf)[j] = s;
+ }
+ }
+ }
+
+ result = snd_pcm_writei(alsa_device.outhandle, alsa_buf,
+ outtransfersize);
+ if (result != (int)outtransfersize)
+ {
+ #ifdef DEBUG_ALSA_XFER
+ if (result >= 0 || errno == EAGAIN)
+ fprintf(stderr, "ALSA: write returned %d of %d\n",
+ result, outtransfersize);
+ else fprintf(stderr, "ALSA: write: %s\n",
+ snd_strerror(errno));
+ fprintf(stderr,
+ "inputcount %d, outputcount %d, outbufsize %d\n",
+ inputcount, outputcount,
+ (ALSA_EXTRABUFFER + linux_advance_samples)
+ * alsa_samplewidth * outchannels);
+ #endif
+ sys_log_error(ERR_DACSLEPT);
+ return (SENDDACS_NO);
+ }
+
+ /* zero out the output buffer */
+ memset(sys_soundout, 0, DACBLKSIZE * sizeof(*sys_soundout) *
+ linux_outchannels);
+ if (sys_getrealtime() - timenow > 0.002)
+ {
+ #ifdef DEBUG_ALSA_XFER
+ fprintf(stderr, "output %d took %d msec\n",
+ callno, (int)(1000 * (timenow - timelast))), fflush(stderr);
+ #endif
+ timenow = sys_getrealtime();
+ sys_log_error(ERR_DACSLEPT);
+ }
+ }
+ /* do input */
+ if (linux_inchannels)
+ {
+ result = snd_pcm_readi(alsa_device.inhandle, alsa_buf, intransfersize);
+ if (result < (int)intransfersize)
+ {
+#ifdef DEBUG_ALSA_XFER
+ if (result < 0)
+ fprintf(stderr,
+ "snd_pcm_read %d %d: %s\n",
+ callno, xferno, snd_strerror(errno));
+ else fprintf(stderr,
+ "snd_pcm_read %d %d returned only %d\n",
+ callno, xferno, result);
+ fprintf(stderr,
+ "inputcount %d, outputcount %d, inbufsize %d\n",
+ inputcount, outputcount,
+ (ALSA_EXTRABUFFER + linux_advance_samples)
+ * alsa_samplewidth * inchannels);
+#endif
+ sys_log_error(ERR_ADCSLEPT);
+ return (SENDDACS_NO);
+ }
+ fp = sys_soundin;
+ if (alsa_samplewidth == 4)
+ {
+ for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DACBLKSIZE)
+ {
+ for (j = i, k = DACBLKSIZE, fp2 = fp1; k--;
+ j += inchannels, fp2++)
+ *fp2 = (float) ((t_alsa_sample32 *)alsa_buf)[j]
+ * (1./ INT32_MAX);
+ }
+ }
+ else
+ {
+ for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DACBLKSIZE)
+ {
+ for (j = i, k = DACBLKSIZE, fp2 = fp1; k--; j += inchannels,
+ fp2++)
+ *fp2 = (float) ((t_alsa_sample16 *)alsa_buf)[j]
+ * 3.051850e-05;
+ }
+ }
+ }
+ xferno++;
+ if (sys_getrealtime() - timenow > 0.002)
+ {
+#ifdef DEBUG_ALSA_XFER
+ fprintf(stderr, "routine took %d msec\n",
+ (int)(1000 * (sys_getrealtime() - timenow)));
+#endif
+ sys_log_error(ERR_ADCSLEPT);
+ }
+ return SENDDACS_YES;
+}
+
+void alsa_resync( void)
+{
+ int i, result;
+ memset(alsa_buf, 0,
+ sizeof(char) * alsa_samplewidth * DACBLKSIZE * linux_outchannels);
+ for (i = 0; i < 100; i++)
+ {
+ result = snd_pcm_writei(alsa_device.outhandle, alsa_buf,
+ DACBLKSIZE);
+ if (result != (int)DACBLKSIZE)
+ break;
+ }
+ post("%d written", i);
+}
+
+
+#endif /* ALSA01 */
+
+/***************************************************
+ * Code using the RME_9652 API
+ */
+
+ /*
+ trying native device for future use of native memory map:
+ because of busmaster if you dont use the dac, you dont need
+ CPU Power und also no nearly no CPU-Power is used in device
+
+ since always all DAs and ADs are synced (else they wouldnt work)
+ we use linux_dacs[0], linux_adcs[0]
+ */
+
+#ifdef RME_HAMMERFALL
+
+#define RME9652_MAX_CHANNELS 26
+
+#define RME9652_CH_PER_NATIVE_DEVICE 1
+
+static int rme9652_dac_devices[RME9652_MAX_CHANNELS];
+static int rme9652_adc_devices[RME9652_MAX_CHANNELS];
+
+static char rme9652_dsp_dac[] = "/dev/rme9652/C0da%d";
+static char rme9652_dsp_adc[] = "/dev/rme9652/C0ad%d";
+
+static int num_of_rme9652_dac = 0;
+static int num_of_rme9652_adc = 0;
+
+static int rme_soundindevonset = 1;
+static int rme_soundoutdevonset = 1;
+
+void rme_soundindev(int which)
+{
+ rme_soundindevonset = which;
+}
+
+void rme_soundoutdev(int which)
+{
+ rme_soundoutdevonset = which;
+}
+
+void rme9652_configure(int dev, int fd,int srate, int dac) {
+ int orig, param, nblk;
+ audio_buf_info ainfo;
+ orig = param = srate;
+
+ /* samplerate */
+
+ fprintf(stderr,"RME9652: configuring %d, fd=%d, sr=%d\n, dac=%d\n",
+ dev,fd,srate,dac);
+
+ if (ioctl(fd,SNDCTL_DSP_SPEED,&param) == -1)
+ fprintf(stderr,"RME9652: Could not set sampling rate for device\n");
+ else if( orig != param )
+ fprintf(stderr,"RME9652: sampling rate: wanted %d, got %d\n",
+ orig, param );
+
+ // setting the correct samplerate (could be different than expected)
+ srate = param;
+
+
+ /* setting resolution */
+
+ /* use ctrlpanel to change, experiment, channels 1 */
+
+ orig = param = AFMT_S16_BE;
+ if (ioctl(fd,SNDCTL_DSP_SETFMT,&param) == -1)
+ fprintf(stderr,"RME9652: Could not set DSP format\n");
+ else if( orig != param )
+ fprintf(stderr,"RME9652: DSP format: wanted %d, got %d\n",orig, param );
+
+ /* setting channels */
+ orig = param = RME9652_CH_PER_NATIVE_DEVICE;
+
+ if (ioctl(fd,SNDCTL_DSP_CHANNELS,&param) == -1)
+ fprintf(stderr,"RME9652: Could not set channels\n");
+ else if( orig != param )
+ fprintf(stderr,"RME9652: num channels: wanted %d, got %d\n",orig, param );
+
+ if (dac)
+ {
+
+ /* use "free space" to learn the buffer size. Normally you
+ should set this to your own desired value; but this seems not
+ to be implemented uniformly across different sound cards. LATER
+ we should figure out what to do if the requested scheduler advance
+ is greater than this buffer size; for now, we just print something
+ out. */
+
+ if( ioctl(linux_dacs[0].d_fd, SOUND_PCM_GETOSPACE,&ainfo) < 0 )
+ fprintf(stderr,"RME: ioctl on output device %d failed",dev);
+
+ linux_dacs[0].d_bufsize = ainfo.bytes;
+
+ fprintf(stderr,"RME: ioctl SOUND_PCM_GETOSPACE says %d buffsize\n",
+ linux_dacs[0].d_bufsize);
+
+
+ if (linux_advance_samples * (RME_SAMPLEWIDTH *
+ RME9652_CH_PER_NATIVE_DEVICE)
+ > linux_dacs[0].d_bufsize - RME_BYTESPERCHAN)
+ {
+ fprintf(stderr,
+ "RME: requested audio buffer size %d limited to %d\n",
+ linux_advance_samples
+ * (RME_SAMPLEWIDTH * RME9652_CH_PER_NATIVE_DEVICE),
+ linux_dacs[0].d_bufsize);
+ linux_advance_samples =
+ (linux_dacs[0].d_bufsize - RME_BYTESPERCHAN)
+ / (RME_SAMPLEWIDTH *RME9652_CH_PER_NATIVE_DEVICE);
+ }
+ }
+}
+
+
+int rme9652_open_audio(int inchans, int outchans,int srate)
+{
+ int orig;
+ int tmp;
+ int inchannels = 0,outchannels = 0;
+ char devname[20];
+ int i;
+ char buf[RME_SAMPLEWIDTH*RME9652_CH_PER_NATIVE_DEVICE*DACBLKSIZE];
+ int num_devs = 0;
+ audio_buf_info ainfo;
+
+ linux_nindevs = linux_noutdevs = 0;
+
+ if (sys_verbose)
+ post("RME open");
+ /* First check if we can */
+ /* open the write ports */
+
+ for (num_devs=0; outchannels < outchans; num_devs++)
+ {
+ int channels = RME9652_CH_PER_NATIVE_DEVICE;
+
+ sprintf(devname, rme9652_dsp_dac, num_devs + rme_soundoutdevonset);
+ if ((tmp = open(devname,O_WRONLY)) == -1)
+ {
+ DEBUG(fprintf(stderr,"RME9652: failed to open %s writeonly\n",
+ devname);)
+ break;
+ }
+ DEBUG(fprintf(stderr,"RME9652: out device Nr. %d (%d) on %s\n",
+ linux_noutdevs+1,tmp,devname);)
+
+ if (outchans > outchannels)
+ {
+ rme9652_dac_devices[linux_noutdevs] = tmp;
+ linux_noutdevs++;
+ outchannels += channels;
+ }
+ else close(tmp);
+ }
+ if( linux_noutdevs > 0)
+ linux_dacs[0].d_fd = rme9652_dac_devices[0];
+
+ /* Second check if we can */
+ /* open the read ports */
+
+ for (num_devs=0; inchannels < inchans; num_devs++)
+ {
+ int channels = RME9652_CH_PER_NATIVE_DEVICE;
+
+ sprintf(devname, rme9652_dsp_adc, num_devs+rme_soundindevonset);
+
+ if ((tmp = open(devname,O_RDONLY)) == -1)
+ {
+ DEBUG(fprintf(stderr,"RME9652: failed to open %s readonly\n",
+ devname);)
+ break;
+ }
+ DEBUG(fprintf(stderr,"RME9652: in device Nr. %d (%d) on %s\n",
+ linux_nindevs+1,tmp,devname);)
+
+ if (inchans > inchannels)
+ {
+ rme9652_adc_devices[linux_nindevs] = tmp;
+ linux_nindevs++;
+ inchannels += channels;
+ }
+ else
+ close(tmp);
+ }
+ if(linux_nindevs > 0)
+ linux_adcs[0].d_fd = rme9652_adc_devices[0];
+
+ /* configure soundcards */
+
+ rme9652_configure(0, linux_adcs[0].d_fd,srate, 0);
+ rme9652_configure(0, linux_dacs[0].d_fd,srate, 1);
+
+ /* We have to do a read to start the engine. This is
+ necessary because sys_send_dacs waits until the input
+ buffer is filled and only reads on a filled buffer.
+ This is good, because it's a way to make sure that we
+ will not block */
+
+ if (linux_nindevs)
+ {
+ fprintf(stderr,("RME9652: starting read engine ... "));
+
+
+ for (num_devs=0; num_devs < linux_nindevs; num_devs++)
+ read(rme9652_adc_devices[num_devs],
+ buf, RME_SAMPLEWIDTH* RME9652_CH_PER_NATIVE_DEVICE*
+ DACBLKSIZE);
+
+
+ for (num_devs=0; num_devs < linux_noutdevs; num_devs++)
+ write(rme9652_dac_devices[num_devs],
+ buf, RME_SAMPLEWIDTH* RME9652_CH_PER_NATIVE_DEVICE*
+ DACBLKSIZE);
+
+ if(linux_noutdevs)
+ ioctl(rme9652_dac_devices[0],SNDCTL_DSP_SYNC);
+
+ fprintf(stderr,"done\n");
+ }
+
+ linux_setsr(srate);
+ linux_setch(linux_nindevs, linux_noutdevs);
+
+ num_of_rme9652_dac = linux_noutdevs;
+ num_of_rme9652_adc = linux_nindevs;
+
+ if(linux_noutdevs)linux_noutdevs=1;
+ if(linux_nindevs)linux_nindevs=1;
+
+ /* trick RME9652 behaves as one device fromread write pointers */
+ return (0);
+}
+
+void rme9652_close_audio( void)
+{
+ int i;
+ for (i=0;i<num_of_rme9652_dac;i++)
+ close(rme9652_dac_devices[i]);
+
+ for (i=0;i<num_of_rme9652_adc;i++)
+ close(rme9652_adc_devices[i]);
+}
+
+
+/* query audio devices for "available" data size. */
+/* not needed because oss_calcspace does the same */
+static int rme9652_calcspace(void)
+{
+ audio_buf_info ainfo;
+
+
+ /* one for all */
+
+ if (ioctl(linux_dacs[0].d_fd, SOUND_PCM_GETOSPACE,&ainfo) < 0)
+ fprintf(stderr,
+ "RME9652: calc ioctl SOUND_PCM_GETOSPACE on output device fd %d failed\n",
+ linux_dacs[0].d_fd);
+ linux_dacs[0].d_space = ainfo.bytes;
+
+ if (ioctl(linux_adcs[0].d_fd, SOUND_PCM_GETISPACE,&ainfo) < 0)
+ fprintf(stderr,
+ "RME9652: calc ioctl SOUND_PCM_GETISPACE on input device fd %d failed\n",
+ rme9652_adc_devices[0]);
+
+ linux_adcs[0].d_space = ainfo.bytes;
+
+ return 1;
+}
+
+/* this call resyncs audio output and input which will cause discontinuities
+in audio output and/or input. */
+
+static void rme9652_doresync( void)
+{
+ if(linux_noutdevs)
+ ioctl(rme9652_dac_devices[0],SNDCTL_DSP_SYNC);
+}
+
+static int mycount =0;
+
+int rme9652_send_dacs(void)
+{
+ float *fp;
+ long fill;
+ int i, j, dev;
+ /* the maximum number of samples we should have in the ADC buffer */
+ t_rme_sample buf[RME9652_CH_PER_NATIVE_DEVICE*DACBLKSIZE], *sp;
+
+ double timeref, timenow;
+
+ mycount++;
+
+ if (!linux_nindevs && !linux_noutdevs) return (0);
+
+ rme9652_calcspace();
+
+ /* do output */
+
+ timeref = sys_getrealtime();
+
+ if(linux_noutdevs){
+
+ if (linux_dacs[0].d_dropcount)
+ linux_dacs[0].d_dropcount--;
+ else{
+ /* fprintf(stderr,"output %d\n", linux_outchannels);*/
+
+ for(j=0;j<linux_outchannels;j++){
+
+ t_rme_sample *a,*b,*c,*d;
+ float *fp1,*fp2,*fp3,*fp4;
+
+ fp1 = sys_soundout + j*DACBLKSIZE-4;
+ fp2 = fp1 + 1;
+ fp3 = fp1 + 2;
+ fp4 = fp1 + 3;
+ a = buf-4;
+ b=a+1;
+ c=a+2;
+ d=a+3;
+
+ for (i = DACBLKSIZE>>2;i--;)
+ {
+ float s1 = *(fp1+=4) * INT32_MAX;
+ float s2 = *(fp2+=4) * INT32_MAX;
+ float s3 = *(fp3+=4) * INT32_MAX;
+ float s4 = *(fp4+=4) * INT32_MAX;
+
+ *(a+=4) = CLIP32(s1);
+ *(b+=4) = CLIP32(s2);
+ *(c+=4) = CLIP32(s3);
+ *(d+=4) = CLIP32(s4);
+ }
+
+ linux_dacs_write(rme9652_dac_devices[j],buf,RME_BYTESPERCHAN);
+ }
+ }
+
+ if ((timenow = sys_getrealtime()) - timeref > 0.02)
+ sys_log_error(ERR_DACSLEPT);
+ timeref = timenow;
+ }
+
+ memset(sys_soundout, 0,
+ linux_outchannels * (sizeof(float) * DACBLKSIZE));
+
+ /* do input */
+
+ if(linux_nindevs) {
+
+ for(j=0;j<linux_inchannels;j++){
+
+ linux_adcs_read(rme9652_adc_devices[j], buf, RME_BYTESPERCHAN);
+
+ if ((timenow = sys_getrealtime()) - timeref > 0.02)
+ sys_log_error(ERR_ADCSLEPT);
+ timeref = timenow;
+ {
+ t_rme_sample *a,*b,*c,*d;
+ float *fp1,*fp2,*fp3,*fp4;
+
+ fp1 = sys_soundin + j*DACBLKSIZE-4;
+ fp2 = fp1 + 1;
+ fp3 = fp1 + 2;
+ fp4 = fp1 + 3;
+ a = buf-4;
+ b=a+1;
+ c=a+2;
+ d=a+3;
+
+ for (i = (DACBLKSIZE>>2);i--;)
+ {
+ *(fp1+=4) = *(a+=4) * (float)(1./INT32_MAX);
+ *(fp2+=4) = *(b+=4) * (float)(1./INT32_MAX);
+ *(fp3+=4) = *(c+=4) * (float)(1./INT32_MAX);
+ *(fp4+=4) = *(d+=4) * (float)(1./INT32_MAX);
+ }
+ }
+ }
+ }
+ /* fprintf(stderr,"ready \n");*/
+
+ return (1);
+}
+
+#endif /* RME_HAMMERFALL */
diff --git a/pd/src/s_inter.c b/pd/src/s_inter.c
new file mode 100644
index 00000000..b9f52d68
--- /dev/null
+++ b/pd/src/s_inter.c
@@ -0,0 +1,794 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* Pd side of the Pd/Pd-gui interface. */
+
+#include "m_imp.h"
+#ifdef UNIX
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#endif
+#ifdef HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#ifdef NT
+#include <io.h>
+#include <fcntl.h>
+#include <process.h>
+#include <winsock.h>
+typedef int pid_t;
+#define EADDRINUSE WSAEADDRINUSE
+#endif
+#include <stdarg.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef MACOSX
+#include <sys/types.h>
+#include <sys/stat.h>
+#else
+#include <stdlib.h>
+#endif
+
+extern char pd_version[];
+
+typedef struct _fdpoll
+{
+ int fdp_fd;
+ t_fdpollfn fdp_fn;
+ void *fdp_ptr;
+} t_fdpoll;
+
+#define INBUFSIZE 4096
+
+struct _socketreceiver
+{
+ char *sr_inbuf;
+ int sr_inhead;
+ int sr_intail;
+ void *sr_owner;
+ int sr_udp;
+ t_socketnotifier sr_notifier;
+ t_socketreceivefn sr_socketreceivefn;
+};
+
+static int sys_nfdpoll;
+static t_fdpoll *sys_fdpoll;
+static int sys_maxfd;
+static int sys_guisock;
+
+static t_binbuf *inbinbuf;
+static t_socketreceiver *sys_socketreceiver;
+extern int sys_addhist(int phase);
+
+void sys_sockerror(char *s)
+{
+#ifdef NT
+ int err = WSAGetLastError();
+ if (err == 10054) return;
+ else if (err == 10044)
+ {
+ fprintf(stderr,
+ "Warning: you might not have TCP/IP \"networking\" turned on\n");
+ fprintf(stderr, "which is needed for Pd to talk to its GUI layer.\n");
+ }
+#endif
+#ifdef UNIX
+ int err = errno;
+#endif
+ fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
+}
+
+void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr)
+{
+ int nfd = sys_nfdpoll;
+ int size = nfd * sizeof(t_fdpoll);
+ t_fdpoll *fp;
+ sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size,
+ size + sizeof(t_fdpoll));
+ fp = sys_fdpoll + nfd;
+ fp->fdp_fd = fd;
+ fp->fdp_fn = fn;
+ fp->fdp_ptr = ptr;
+ sys_nfdpoll = nfd + 1;
+ if (fd >= sys_maxfd) sys_maxfd = fd + 1;
+}
+
+void sys_rmpollfn(int fd)
+{
+ int nfd = sys_nfdpoll;
+ int i, size = nfd * sizeof(t_fdpoll);
+ t_fdpoll *fp;
+ for (i = nfd, fp = sys_fdpoll; i--; fp++)
+ {
+ if (fp->fdp_fd == fd)
+ {
+ while (i--)
+ {
+ fp[0] = fp[1];
+ fp++;
+ }
+ sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size,
+ size - sizeof(t_fdpoll));
+ sys_nfdpoll = nfd - 1;
+ return;
+ }
+ }
+ post("warning: %d removed from poll list but not found", fd);
+}
+
+static int sys_domicrosleep(int microsec, int pollem)
+{
+ struct timeval timout;
+ int i, didsomething = 0;
+ t_fdpoll *fp;
+ timout.tv_sec = 0;
+ timout.tv_usec = microsec;
+ if (pollem)
+ {
+ fd_set readset, writeset, exceptset;
+ FD_ZERO(&writeset);
+ FD_ZERO(&readset);
+ FD_ZERO(&exceptset);
+ for (fp = sys_fdpoll, i = sys_nfdpoll; i--; fp++)
+ FD_SET(fp->fdp_fd, &readset);
+ select(sys_maxfd+1, &readset, &writeset, &exceptset, &timout);
+ for (i = 0; i < sys_nfdpoll; i++)
+ if (FD_ISSET(sys_fdpoll[i].fdp_fd, &readset))
+ {
+ (*sys_fdpoll[i].fdp_fn)(sys_fdpoll[i].fdp_ptr, sys_fdpoll[i].fdp_fd);
+ didsomething = 1;
+ }
+ return (didsomething);
+ }
+ else
+ {
+ select(0, 0, 0, 0, &timout);
+ return (0);
+ }
+}
+
+void sys_microsleep(int microsec)
+{
+ sys_domicrosleep(microsec, 1);
+}
+
+t_socketreceiver *socketreceiver_new(void *owner, t_socketnotifier notifier,
+ t_socketreceivefn socketreceivefn, int udp)
+{
+ t_socketreceiver *x = (t_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_socketreceiver");;
+ return (x);
+}
+
+void socketreceiver_free(t_socketreceiver *x)
+{
+ free(x->sr_inbuf);
+ freebytes(x, sizeof(*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 socketreceiver_doread(t_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))
+ {
+ /* if we hit a semi that isn't preceeded by a \, it's a message
+ boundary. LATER we should deal with the possibility that the
+ preceeding \ might itself be escaped! */
+ char c = *bp++ = inbuf[indx];
+ if (c == ';' && (!indx || inbuf[indx-1] != '\\'))
+ {
+ intail = (indx+1)&(INBUFSIZE-1);
+ binbuf_text(inbinbuf, messbuf, bp - messbuf);
+ if (sys_debuglevel & DEBUG_MESSDOWN)
+ {
+ write(2, messbuf, bp - messbuf);
+ write(2, "\n", 1);
+ }
+ x->sr_inhead = inhead;
+ x->sr_intail = intail;
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static void socketreceiver_getudp(t_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("socketreceiver_getudp");
+ }
+ }
+}
+
+void socketreceiver_read(t_socketreceiver *x, int fd)
+{
+ if (x->sr_udp) /* UDP ("datagram") socket protocol */
+ 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;
+
+ /* the input buffer might be full. If so, drop the whole thing */
+ if (readto == x->sr_inhead)
+ {
+ fprintf(stderr, "pd: dropped message from gui\n");
+ 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 == sys_socketreceiver) sys_bail(1);
+ else
+ {
+ if (x->sr_notifier) (*x->sr_notifier)(x->sr_owner);
+ sys_rmpollfn(fd);
+ sys_closesocket(fd);
+ }
+ }
+ else if (ret == 0)
+ {
+ if (x == sys_socketreceiver)
+ {
+ fprintf(stderr, "pd: exiting\n");
+ sys_bail(0);
+ }
+ else
+ {
+ post("EOF on socket %d\n", 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 (socketreceiver_doread(x))
+ {
+ outlet_setstacklim();
+ if (x->sr_socketreceivefn)
+ (*x->sr_socketreceivefn)(x->sr_owner, inbinbuf);
+ else binbuf_eval(inbinbuf, 0, 0, 0);
+ }
+ }
+ }
+ }
+}
+
+void sys_closesocket(int fd)
+{
+#ifdef UNIX
+ close(fd);
+#endif
+#ifdef NT
+ closesocket(fd);
+#endif
+}
+
+
+void sys_gui(char *s)
+{
+ int length = strlen(s), written = 0, res, histwas = sys_addhist(4);
+ if (sys_debuglevel & DEBUG_MESSUP)
+ fprintf(stderr, "%s", s);
+ if (sys_nogui)
+ return;
+ while (1)
+ {
+ res = send(sys_guisock, s + written, length, 0);
+ if (res < 0)
+ {
+ perror("pd output pipe");
+ sys_bail(1);
+ }
+ else
+ {
+ written += res;
+ if (written >= length)
+ break;
+ }
+ }
+ sys_addhist(histwas);
+}
+
+/* LATER should do a bounds check -- but how do you get printf to do that?
+ See also rtext_senditup() in this regard */
+
+void sys_vgui(char *fmt, ...)
+{
+ int result, i;
+ char buf[2048];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ sys_gui(buf);
+ va_end(ap);
+}
+
+
+#define FIRSTPORTNUM 5400
+
+/* -------------- signal handling for UNIX -------------- */
+
+#ifdef UNIX
+typedef void (*sighandler_t)(int);
+
+static void sys_signal(int signo, sighandler_t sigfun)
+{
+ struct sigaction action;
+ action.sa_flags = 0;
+ action.sa_handler = sigfun;
+ memset(&action.sa_mask, 0, sizeof(action.sa_mask));
+#ifdef __linux__
+ action.sa_restorer = 0;
+#endif
+ if (sigaction(signo, &action, 0) < 0)
+ perror("sigaction");
+}
+
+static void sys_exithandler(int n)
+{
+ static int trouble = 0;
+ if (!trouble)
+ {
+ trouble = 1;
+ fprintf(stderr, "Pd: signal %d\n", n);
+ sys_bail(1);
+
+ }
+ else _exit(1);
+}
+
+static void sys_alarmhandler(int n)
+{
+ fprintf(stderr, "Pd: system call timed out\n");
+}
+
+static void sys_huphandler(int n)
+{
+ struct timeval timout;
+ timout.tv_sec = 0;
+ timout.tv_usec = 30000;
+ select(1, 0, 0, 0, &timout);
+}
+
+void sys_setalarm(int microsec)
+{
+ struct itimerval gonzo;
+#if 0
+ fprintf(stderr, "timer %d\n", microsec);
+#endif
+ gonzo.it_interval.tv_sec = 0;
+ gonzo.it_interval.tv_usec = 0;
+ gonzo.it_value.tv_sec = 0;
+ gonzo.it_value.tv_usec = microsec;
+ if (microsec)
+ sys_signal(SIGALRM, sys_alarmhandler);
+ else sys_signal(SIGALRM, SIG_IGN);
+ setitimer(ITIMER_REAL, &gonzo, 0);
+}
+
+#endif
+
+static int sys_watchfd;
+
+void glob_ping(t_pd *dummy)
+{
+ if (write(sys_watchfd, "\n", 1) < 1)
+ {
+ fprintf(stderr, "pd: watchdog process died\n");
+ sys_bail(1);
+ }
+}
+
+static int defaultfontshit[] = {
+ 8, 5, 9, 10, 6, 10, 12, 7, 13, 14, 9, 17, 16, 10, 19, 24, 15, 28,
+ 24, 15, 28};
+
+int sys_startgui(const char *guidir)
+{
+ pid_t childpid;
+ char cmdbuf[4*MAXPDSTRING];
+ struct sockaddr_in server;
+ int msgsock;
+ char buf[15];
+ int len = sizeof(server);
+ int ntry = 0, portno = FIRSTPORTNUM;
+ int xsock = -1;
+#ifdef NT
+ short version = MAKEWORD(2, 0);
+ WSADATA nobby;
+#endif
+#ifdef UNIX
+ int stdinpipe[2];
+#endif
+ /* create an empty FD poll list */
+ sys_fdpoll = (t_fdpoll *)t_getbytes(0);
+ sys_nfdpoll = 0;
+ inbinbuf = binbuf_new();
+
+#ifdef UNIX
+ signal(SIGHUP, sys_huphandler);
+ signal(SIGINT, sys_exithandler);
+ signal(SIGQUIT, sys_exithandler);
+ signal(SIGILL, sys_exithandler);
+ signal(SIGIOT, sys_exithandler);
+ signal(SIGFPE, SIG_IGN);
+ /* signal(SIGILL, sys_exithandler);
+ signal(SIGBUS, sys_exithandler);
+ signal(SIGSEGV, sys_exithandler); */
+ signal(SIGPIPE, sys_exithandler);
+ signal(SIGALRM, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+#ifdef __linux__
+ signal(SIGSTKFLT, sys_exithandler);
+#endif
+#endif
+#ifdef NT
+ if (WSAStartup(version, &nobby)) sys_sockerror("WSAstartup");
+#endif
+
+ if (sys_nogui)
+ {
+ /* fake the GUI's message giving cwd and font sizes; then
+ skip starting the GUI up. */
+ t_atom zz[19];
+ int i;
+#ifdef NT
+ if (GetCurrentDirectory(MAXPDSTRING, cmdbuf) == 0)
+ strcpy(cmdbuf, ".");
+#endif
+#ifdef UNIX
+ if (!getcwd(cmdbuf, MAXPDSTRING))
+ strcpy(cmdbuf, ".");
+
+#endif
+ SETSYMBOL(zz, gensym(cmdbuf));
+ for (i = 1; i < 22; i++)
+ SETFLOAT(zz + i, defaultfontshit[i-1]);
+ glob_initfromgui(0, 0, 22, zz);
+ }
+ else
+ {
+#ifdef NT
+ char scriptbuf[MAXPDSTRING+30], wishbuf[MAXPDSTRING+30], portbuf[80];
+ int spawnret;
+
+#endif
+ int intarg;
+
+ /* create a socket */
+ xsock = socket(AF_INET, SOCK_STREAM, 0);
+ if (xsock < 0) sys_sockerror("socket");
+#if 0
+ intarg = 0;
+ if (setsockopt(xsock, SOL_SOCKET, SO_SNDBUF,
+ &intarg, sizeof(intarg)) < 0)
+ post("setsockopt (SO_RCVBUF) failed\n");
+ intarg = 0;
+ if (setsockopt(xsock, SOL_SOCKET, SO_RCVBUF,
+ &intarg, sizeof(intarg)) < 0)
+ post("setsockopt (SO_RCVBUF) failed\n");
+#endif
+ intarg = 1;
+ if (setsockopt(xsock, IPPROTO_TCP, TCP_NODELAY,
+ &intarg, sizeof(intarg)) < 0)
+ post("setsockopt (TCP_NODELAY) failed\n");
+
+
+ server.sin_family = AF_INET;
+ server.sin_addr.s_addr = INADDR_ANY;
+
+ /* assign server port number */
+ server.sin_port = htons((unsigned short)portno);
+
+ /* name the socket */
+ while (bind(xsock, (struct sockaddr *)&server, sizeof(server)) < 0)
+ {
+#ifdef NT
+ int err = WSAGetLastError();
+#endif
+#ifdef UNIX
+ int err = errno;
+#endif
+ if ((ntry++ > 20) || (err != EADDRINUSE))
+ {
+ perror("bind");
+ fprintf(stderr,
+ "Pd needs your machine to be configured with\n");
+ fprintf(stderr,
+ "'networking' turned on (see Pd's html doc for details.)\n");
+ exit(1);
+ }
+ portno++;
+ server.sin_port = htons((unsigned short)(portno));
+ }
+
+ if (sys_verbose) fprintf(stderr, "port %d\n", portno);
+
+ sys_socketreceiver = socketreceiver_new(0, 0, 0, 0);
+
+#ifdef UNIX
+ childpid = fork();
+ if (childpid < 0)
+ {
+ if (errno) perror("sys_startgui");
+ else fprintf(stderr, "sys_startgui failed\n");
+ return (1);
+ }
+ else if (!childpid) /* we're the child */
+ {
+ seteuid(getuid()); /* lose setuid priveliges */
+#ifndef MACOSX
+ /* the wish process in Unix will make a wish shell and
+ read/write standard in and out unless we close the
+ file descriptors. Somehow this doesn't make the MAC OSX
+ version of Wish happy...*/
+ if (pipe(stdinpipe) < 0)
+ sys_sockerror("pipe");
+ else
+ {
+ if (stdinpipe[0] != 0)
+ {
+ close (0);
+ dup2(stdinpipe[0], 0);
+ close(stdinpipe[0]);
+ }
+ }
+#endif
+ if (!sys_guicmd)
+ {
+#ifdef MACOSX
+ char *homedir = getenv("HOME"), filename[250];
+ struct stat statbuf;
+ if (!homedir || strlen(homedir) > 150)
+ goto nexttry;
+ sprintf(filename,
+ "%s/Applications/Wish shell.app/Contents/MacOS/Wish Shell",
+ homedir);
+
+ if (stat(filename, &statbuf) >= 0)
+ goto foundit;
+ nexttry:
+ strcpy(filename,
+ "/Applications/Wish Shell.app/Contents/MacOS/Wish Shell");
+ foundit:
+ sprintf(cmdbuf, "\"%s\" %s/pd.tk %d\n", filename, guidir, portno);
+#else
+ sprintf(cmdbuf,
+"TCL_LIBRARY=\"%s/tcl/library\" TK_LIBRARY=\"%s/tk/library\" \
+ \"%s/pd-gui\" %d\n",
+ sys_libdir->s_name, sys_libdir->s_name, guidir, portno);
+#endif
+ sys_guicmd = cmdbuf;
+ }
+ if (sys_verbose) fprintf(stderr, "%s", sys_guicmd);
+ execl("/bin/sh", "sh", "-c", sys_guicmd, 0);
+ perror("pd: exec");
+ _exit(1);
+ }
+#endif /* UNIX */
+
+#ifdef NT
+ /* in NT land "guipath" is unused; we just do everything from
+ the libdir. */
+ fprintf(stderr, "%s\n", sys_libdir->s_name);
+
+ strcpy(scriptbuf, "\"");
+ strcat(scriptbuf, sys_libdir->s_name);
+ strcat(scriptbuf, "/bin/pd.tk\"");
+ sys_bashfilename(scriptbuf, scriptbuf);
+
+ sprintf(portbuf, "%d", portno);
+
+ strcpy(wishbuf, sys_libdir->s_name);
+ strcat(wishbuf, "/bin/wish83.exe");
+ sys_bashfilename(wishbuf, wishbuf);
+
+ spawnret = _spawnl(P_NOWAIT, wishbuf, "wish83", scriptbuf, portbuf, 0);
+ if (spawnret < 0)
+ {
+ perror("spawnl");
+ fprintf(stderr, "%s: couldn't load TCL\n", wishbuf);
+ exit(1);
+ }
+
+#endif /* NT */
+ }
+
+#ifdef UNIX
+ /* now that we've spun off the child process we can promote
+ our process's priority, if we happen to be root. */
+ if (sys_hipriority)
+ {
+ if (!getuid() || !geteuid())
+ {
+ /* To prevent lockup, we fork off a watchdog process with
+ higher real-time priority than ours. The GUI has to send
+ a stream of ping messages to the watchdog THROUGH the Pd
+ process which has to pick them up from the GUI and forward
+ them. If any of these things aren't happening the watchdog
+ starts sending "stop" and "cont" signals to the Pd process
+ to make it timeshare with the rest of the system. (Version
+ 0.33P2 : if there's no GUI, the watchdog pinging is done
+ from the scheduler idle routine in this process instead.) */
+
+ int pipe9[2], watchpid;
+ if (pipe(pipe9) < 0)
+ {
+ seteuid(getuid()); /* lose setuid priveliges */
+ sys_sockerror("pipe");
+ return (1);
+ }
+ watchpid = fork();
+ if (watchpid < 0)
+ {
+ seteuid(getuid()); /* lose setuid priveliges */
+ if (errno)
+ perror("sys_startgui");
+ else fprintf(stderr, "sys_startgui failed\n");
+ return (1);
+ }
+ else if (!watchpid) /* we're the child */
+ {
+ sys_set_priority(1);
+ seteuid(getuid()); /* lose setuid priveliges */
+ if (pipe9[1] != 0)
+ {
+ dup2(pipe9[0], 0);
+ close(pipe9[0]);
+ }
+ close(pipe9[1]);
+
+ sprintf(cmdbuf, "%s/pd-watchdog\n", guidir);
+ if (sys_verbose) fprintf(stderr, "%s", cmdbuf);
+ execl("/bin/sh", "sh", "-c", cmdbuf, 0);
+ perror("pd: exec");
+ _exit(1);
+ }
+ else /* we're the parent */
+ {
+ sys_set_priority(0);
+ seteuid(getuid()); /* lose setuid priveliges */
+ close(pipe9[0]);
+ sys_watchfd = pipe9[1];
+ /* We also have to start the ping loop in the GUI;
+ this is done later when the socket is open. */
+ }
+ }
+ else
+ {
+ post("realtime setting failed because not root\n");
+ sys_hipriority = 0;
+ }
+ }
+
+ seteuid(getuid()); /* lose setuid priveliges */
+#endif /* UNIX */
+
+#ifdef NT
+ if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
+ fprintf(stderr, "pd: couldn't set high priority class\n");
+#endif
+
+ if (!sys_nogui)
+ {
+ if (sys_verbose)
+ fprintf(stderr, "Waiting for connection request... \n");
+ if (listen(xsock, 5) < 0) sys_sockerror("listen");
+
+ sys_guisock = accept(xsock, (struct sockaddr *) &server, &len);
+#ifdef OOPS
+ close(xsock);
+#endif
+ if (sys_guisock < 0) sys_sockerror("accept");
+ sys_addpollfn(sys_guisock, (t_fdpollfn)socketreceiver_read,
+ sys_socketreceiver);
+
+ if (sys_verbose)
+ fprintf(stderr, "... connected\n");
+
+ /* here is where we start the pinging. */
+ if (sys_hipriority)
+ sys_gui("pdtk_watchdog\n");
+
+ sys_vgui("pdtk_pd_startup {%s}\n", pd_version);
+ }
+ return (0);
+
+}
+
+
+static int sys_poll_togui(void)
+{
+ /* LATER use this to flush output buffer to gui */
+ return (0);
+}
+
+int sys_pollgui(void)
+{
+ return (sys_domicrosleep(0, 1) || sys_poll_togui());
+}
+
+/* LATER try to save dirty documents */
+void sys_bail(int n)
+{
+ static int reentered = 0;
+ if (!reentered)
+ {
+ reentered = 1;
+ sys_close_audio();
+ sys_close_midi();
+ }
+ _exit(n);
+}
+
+void glob_quit(void *dummy)
+{
+ sys_vgui("exit\n");
+ if (!sys_nogui)
+ close(sys_guisock);
+ sys_bail(0);
+}
+
diff --git a/pd/src/s_linux.c b/pd/src/s_linux.c
new file mode 100644
index 00000000..5c394674
--- /dev/null
+++ b/pd/src/s_linux.c
@@ -0,0 +1,3087 @@
+/* Copyright (c) 1997-1999 Guenter Geiger, Miller Puckette, Larry Troxler,
+* Winfried Ritsch, Karl MacMillan, and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* this file implements the sys_ functions profiled in m_imp.h for
+ audio and MIDI I/O. In Linux there might be several APIs for doing the
+ audio part; right now there are three (OSS, ALSA, RME); the third is
+ for the RME 9652 driver by Ritsch (but not for the OSS compatible
+ one by Geiger; for that one, OSS should work.)
+
+ FUNCTION PREFIXES.
+ sys_ -- functions which must be exported to Pd on all platforms
+ linux_ -- linux-specific objects which don't depend on API,
+ mostly static but some exported.
+ oss_, alsa_, rme_ -- API-specific functions, all of which are
+ static.
+
+ ALSA SUPPORT. If ALSA99 is defined we support ALSA 0.5x; if ALSA01,
+ ALSA 0.9x. (the naming scheme reflects the possibility of further API
+ changes in the future...) We define "ALSA" for code relevant to both
+ APIs.
+
+ For MIDI, we only offer the OSS API; ALSA has to emulate OSS for us.
+*/
+
+/* OSS include (whether we're doing OSS audio or not we need this for MIDI) */
+
+
+/* IOhannes:::
+ * hacked this to add advanced multidevice-support
+ * 1311:forum::für::umläute:2001
+ */
+
+#include <linux/soundcard.h>
+
+#if (defined(ALSA01) || defined(ALSA99))
+#define ALSA
+#endif
+
+#ifdef ALSA99
+#include <sys/asoundlib.h>
+#endif
+#ifdef ALSA01
+#include <alsa/asoundlib.h>
+#endif
+
+#include "m_imp.h"
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <sys/mman.h>
+
+/* local function prototypes */
+
+static void linux_close_midi( void);
+
+static int oss_open_audio(int naudioindev, int *audioindev, int nchindev,
+ int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
+ int *choutdev, int rate); /* IOhannes */
+
+static void oss_close_audio(void);
+static int oss_send_dacs(void);
+static void oss_reportidle(void);
+
+#ifdef ALSA
+typedef int16_t t_alsa_sample16;
+typedef int32_t t_alsa_sample32;
+#define ALSA_SAMPLEWIDTH_16 sizeof(t_alsa_sample16)
+#define ALSA_SAMPLEWIDTH_32 sizeof(t_alsa_sample32)
+#define ALSA_XFERSIZE16 (signed int)(sizeof(t_alsa_sample16) * DACBLKSIZE)
+#define ALSA_XFERSIZE32 (signed int)(sizeof(t_alsa_sample32) * DACBLKSIZE)
+#define ALSA_MAXDEV 1
+#define ALSA_JITTER 1024
+#define ALSA_EXTRABUFFER 2048
+#define ALSA_DEFFRAGSIZE 64
+#define ALSA_DEFNFRAG 12
+
+#ifdef ALSA99
+typedef struct _alsa_dev
+{
+ snd_pcm_t *handle;
+ snd_pcm_channel_info_t info;
+ snd_pcm_channel_setup_t setup;
+} t_alsa_dev;
+
+t_alsa_dev alsa_device[ALSA_MAXDEV];
+static int n_alsa_dev;
+static char *alsa_buf;
+static int alsa_samplewidth;
+#endif /* ALSA99 */
+
+#ifdef ALSA01
+typedef struct _alsa_dev
+{
+ snd_pcm_t *inhandle;
+ snd_pcm_t *outhandle;
+} t_alsa_dev;
+
+t_alsa_dev alsa_device;
+static short *alsa_buf;
+static int alsa_samplewidth;
+static snd_pcm_status_t* in_status;
+static snd_pcm_status_t* out_status;
+#endif /* ALSA01 */
+
+#if 0 /* early alsa 0.9 beta dists had different names for these: */
+#define SND_PCM_ACCESS_RW_INTERLEAVED SNDRV_PCM_ACCESS_RW_INTERLEAVED
+#define SND_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32
+#define SND_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16
+#define SND_PCM_SUBFORMAT_STD SNDRV_PCM_SUBFORMAT_STD
+#endif
+
+static int alsa_mode;
+static int alsa_open_audio(int inchans, int outchans, int rate);
+static void alsa_close_audio(void);
+static int alsa_send_dacs(void);
+static void alsa_set_params(t_alsa_dev *dev, int dir, int rate, int voices);
+static void alsa_reportidle(void);
+#endif /* ALSA */
+
+#ifdef RME_HAMMERFALL
+static int rme9652_open_audio(int inchans, int outchans, int rate);
+static void rme9652_close_audio(void);
+static int rme9652_send_dacs(void);
+static void rme9652_reportidle(void);
+#endif /* RME_HAMMERFALL */
+
+/* Defines */
+#define DEBUG(x) x
+#define DEBUG2(x) {x;}
+
+#define OSS_MAXCHPERDEV 32 /* max channels per OSS device */
+#define OSS_MAXDEV 4 /* maximum number of input or output devices */
+#define OSS_DEFFRAGSIZE 256 /* default log fragment size (frames) */
+#define OSS_DEFAUDIOBUF 40000 /* default audiobuffer, microseconds */
+#define OSS_DEFAULTCH 2
+#define RME_DEFAULTCH 8 /* need this even if RME undefined */
+typedef int16_t t_oss_int16;
+typedef int32_t t_oss_int32;
+#define OSS_MAXSAMPLEWIDTH sizeof(t_oss_int32)
+#define OSS_BYTESPERCHAN(width) (DACBLKSIZE * (width))
+#define OSS_XFERSAMPS(chans) (DACBLKSIZE* (chans))
+#define OSS_XFERSIZE(chans, width) (DACBLKSIZE * (chans) * (width))
+
+#ifdef RME_HAMMERFALL
+typedef int32_t t_rme_sample;
+#define RME_SAMPLEWIDTH sizeof(t_rme_sample)
+#define RME_BYTESPERCHAN (DACBLKSIZE * RME_SAMPLEWIDTH)
+#endif /* RME_HAMMERFALL */
+
+/* GLOBALS */
+static int linux_whichapi = API_OSS;
+static int linux_inchannels;
+static int linux_outchannels;
+static int linux_advance_samples; /* scheduler advance in samples */
+static int linux_meters; /* true if we're metering */
+static float linux_inmax; /* max input amplitude */
+static float linux_outmax; /* max output amplitude */
+static int linux_fragsize = 0; /* for block mode; block size (sample frames) */
+static int linux_nfragment = 0; /* ... and number of blocks. */
+
+#ifdef ALSA99
+static int alsa_devno = 1;
+#endif
+#ifdef ALSA01
+static char alsa_devname[512] = "hw:0,0";
+static int alsa_use_plugin = 0;
+#endif
+
+/* our device handles */
+
+typedef struct _oss_dev
+{
+ int d_fd;
+ unsigned int d_space; /* bytes available for writing/reading */
+ int d_bufsize; /* total buffer size in blocks for this device */
+ int d_dropcount; /* # of buffers to drop for resync (output only) */
+ unsigned int d_nchannels; /* number of channels for this device */
+ unsigned int d_bytespersamp; /* bytes per sample (2 for 16 bit, 4 for 32) */
+} t_oss_dev;
+
+static t_oss_dev linux_dacs[OSS_MAXDEV];
+static t_oss_dev linux_adcs[OSS_MAXDEV];
+static int linux_noutdevs = 0;
+static int linux_nindevs = 0;
+
+ /* exported variables */
+int sys_schedadvance = OSS_DEFAUDIOBUF; /* scheduler advance in microsecs */
+float sys_dacsr;
+int sys_hipriority = 0;
+t_sample *sys_soundout;
+t_sample *sys_soundin;
+
+ /* OSS-specific private variables */
+static int oss_blockmode = 1; /* flag to use "blockmode" */
+static int oss_32bit = 0; /* allow 23 bit transfers in OSS */
+static char ossdsp[] = "/dev/dsp%d";
+
+#ifndef INT32_MAX
+#define INT32_MAX 0x7fffffff
+#endif
+ /* don't assume we can turn all 31 bits when doing float-to-fix;
+ otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */
+#define FMAX 0x7ffff000
+#define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x))
+
+
+/* ------------- private routines for all APIS ------------------- */
+
+static void linux_flush_all_underflows_to_zero(void)
+{
+/*
+ TODO: Implement similar thing for linux (GGeiger)
+
+ One day we will figure this out, I hope, because it
+ costs CPU time dearly on Intel - LT
+ */
+ /* union fpc_csr f;
+ f.fc_word = get_fpc_csr();
+ f.fc_struct.flush = 1;
+ set_fpc_csr(f.fc_word);
+ */
+}
+
+ /* set sample rate and channels. Must set sample rate before "configuring"
+ any devices so we know scheduler advance in samples. */
+
+static void linux_setsr(int sr)
+{
+ sys_dacsr = sr;
+ linux_advance_samples = (sys_schedadvance * sys_dacsr) / (1000000.);
+ if (linux_advance_samples < 3 * DACBLKSIZE)
+ linux_advance_samples = 3 * DACBLKSIZE;
+}
+
+static void linux_setch(int chin, int chout)
+{
+ int nblk;
+ int inbytes = chin * (DACBLKSIZE*sizeof(float));
+ int outbytes = chout * (DACBLKSIZE*sizeof(float));
+
+ linux_inchannels = chin;
+ linux_outchannels = chout;
+ if (sys_soundin)
+ free(sys_soundin);
+ sys_soundin = (t_float *)malloc(inbytes);
+ memset(sys_soundin, 0, inbytes);
+
+ if (sys_soundout)
+ free(sys_soundout);
+ sys_soundout = (t_float *)malloc(outbytes);
+ memset(sys_soundout, 0, outbytes);
+
+ if (sys_verbose)
+ post("input channels = %d, output channels = %d",
+ linux_inchannels, linux_outchannels);
+}
+
+/* ---------------- MIDI routines -------------------------- */
+
+static int oss_nmidiin;
+static int oss_midiinfd[MAXMIDIINDEV];
+static int oss_nmidiout;
+static int oss_midioutfd[MAXMIDIOUTDEV];
+
+static void oss_midiout(int fd, int n)
+{
+ char b = n;
+ if ((write(fd, (char *) &b, 1)) != 1)
+ perror("midi write");
+}
+
+#define O_MIDIFLAG O_NDELAY
+
+void linux_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec)
+{
+ int i;
+ for (i = 0; i < nmidiout; i++)
+ oss_midioutfd[i] = -1;
+ for (i = 0, oss_nmidiin = 0; i < nmidiin; i++)
+ {
+ int fd = -1, j, outdevindex = -1;
+ char namebuf[80];
+ int devno = midiinvec[i];
+
+ for (j = 0; j < nmidiout; j++)
+ if (midioutvec[j] == midiinvec[i])
+ outdevindex = j;
+
+ /* try to open the device for read/write. */
+ if (devno == 1 && fd < 0 && outdevindex >= 0)
+ {
+ sys_setalarm(1000000);
+ fd = open("/dev/midi", O_RDWR | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr,
+ "device 1: tried /dev/midi READ/WRITE; returned %d\n", fd);
+ if (outdevindex >= 0 && fd >= 0)
+ oss_midioutfd[outdevindex] = fd;
+ }
+ if (fd < 0 && outdevindex >= 0)
+ {
+ sys_setalarm(1000000);
+ sprintf(namebuf, "/dev/midi%2.2d", devno-1);
+ fd = open(namebuf, O_RDWR | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr,
+ "device %d: tried %s READ/WRITE; returned %d\n",
+ devno, namebuf, fd);
+ if (outdevindex >= 0 && fd >= 0)
+ oss_midioutfd[outdevindex] = fd;
+ }
+ if (fd < 0 && outdevindex >= 0)
+ {
+ sys_setalarm(1000000);
+ sprintf(namebuf, "/dev/midi%d", devno-1);
+ fd = open(namebuf, O_RDWR | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr, "device %d: tried %s READ/WRITE; returned %d\n",
+ devno, namebuf, fd);
+ if (outdevindex >= 0 && fd >= 0)
+ oss_midioutfd[outdevindex] = fd;
+ }
+ if (devno == 1 && fd < 0)
+ {
+ sys_setalarm(1000000);
+ fd = open("/dev/midi", O_RDONLY | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr,
+ "device 1: tried /dev/midi READONLY; returned %d\n", fd);
+ }
+ if (fd < 0)
+ {
+ sys_setalarm(1000000);
+ sprintf(namebuf, "/dev/midi%2.2d", devno-1);
+ fd = open(namebuf, O_RDONLY | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr, "device %d: tried %s READONLY; returned %d\n",
+ devno, namebuf, fd);
+ }
+ if (fd < 0)
+ {
+ sys_setalarm(1000000);
+ sprintf(namebuf, "/dev/midi%d", devno-1);
+ fd = open(namebuf, O_RDONLY | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr, "device %d: tried %s READONLY; returned %d\n",
+ devno, namebuf, fd);
+ }
+ if (fd >= 0)
+ oss_midiinfd[oss_nmidiin++] = fd;
+ else post("couldn't open MIDI input device %d", devno);
+ }
+ for (i = 0, oss_nmidiout = 0; i < nmidiout; i++)
+ {
+ int fd = oss_midioutfd[i];
+ char namebuf[80];
+ int devno = midioutvec[i];
+ if (devno == 1 && fd < 0)
+ {
+ sys_setalarm(1000000);
+ fd = open("/dev/midi", O_WRONLY | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr,
+ "device 1: tried /dev/midi WRITEONLY; returned %d\n", fd);
+ }
+ if (fd < 0)
+ {
+ sys_setalarm(1000000);
+ sprintf(namebuf, "/dev/midi%2.2d", devno-1);
+ fd = open(namebuf, O_WRONLY | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr, "device %d: tried %s WRITEONLY; returned %d\n",
+ devno, namebuf, fd);
+ }
+ if (fd < 0)
+ {
+ sys_setalarm(1000000);
+ sprintf(namebuf, "/dev/midi%d", devno-1);
+ fd = open(namebuf, O_WRONLY | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr, "device %d: tried %s WRITEONLY; returned %d\n",
+ devno, namebuf, fd);
+ }
+ if (fd >= 0)
+ oss_midioutfd[oss_nmidiout++] = fd;
+ else post("couldn't open MIDI output device %d", devno);
+ }
+
+ if (oss_nmidiin < nmidiin || oss_nmidiout < nmidiout || sys_verbose)
+ post("opened %d MIDI input device(s) and %d MIDI output device(s).",
+ oss_nmidiin, oss_nmidiout);
+}
+
+#define md_msglen(x) (((x)<0xC0)?2:((x)<0xE0)?1:((x)<0xF0)?2:\
+ ((x)==0xF2)?2:((x)<0xF4)?1:0)
+
+void sys_putmidimess(int portno, int a, int b, int c)
+{
+ if (portno >= 0 && portno < oss_nmidiout)
+ {
+ switch (md_msglen(a))
+ {
+ case 2:
+ oss_midiout(oss_midioutfd[portno],a);
+ oss_midiout(oss_midioutfd[portno],b);
+ oss_midiout(oss_midioutfd[portno],c);
+ return;
+ case 1:
+ oss_midiout(oss_midioutfd[portno],a);
+ oss_midiout(oss_midioutfd[portno],b);
+ return;
+ case 0:
+ oss_midiout(oss_midioutfd[portno],a);
+ return;
+ };
+ }
+}
+
+void sys_putmidibyte(int portno, int byte)
+{
+ if (portno >= 0 && portno < oss_nmidiout)
+ oss_midiout(oss_midioutfd[portno], byte);
+}
+
+#if 0 /* this is the "select" version which doesn't work with OSS
+ driver for emu10k1 (it doesn't implement select.) */
+void sys_poll_midi(void)
+{
+ int i, throttle = 100;
+ struct timeval timout;
+ int did = 1, maxfd = 0;
+ while (did)
+ {
+ fd_set readset, writeset, exceptset;
+ did = 0;
+ if (throttle-- < 0)
+ break;
+ timout.tv_sec = 0;
+ timout.tv_usec = 0;
+
+ FD_ZERO(&writeset);
+ FD_ZERO(&readset);
+ FD_ZERO(&exceptset);
+ for (i = 0; i < oss_nmidiin; i++)
+ {
+ if (oss_midiinfd[i] > maxfd)
+ maxfd = oss_midiinfd[i];
+ FD_SET(oss_midiinfd[i], &readset);
+ }
+ select(maxfd+1, &readset, &writeset, &exceptset, &timout);
+ for (i = 0; i < oss_nmidiin; i++)
+ if (FD_ISSET(oss_midiinfd[i], &readset))
+ {
+ char c;
+ int ret = read(oss_midiinfd[i], &c, 1);
+ if (ret <= 0)
+ fprintf(stderr, "Midi read error\n");
+ else sys_midibytein(i, (c & 0xff));
+ did = 1;
+ }
+ }
+}
+#else
+
+ /* this version uses the asynchronous "read()" ... */
+void sys_poll_midi(void)
+{
+ int i, throttle = 100;
+ struct timeval timout;
+ int did = 1, maxfd = 0;
+ while (did)
+ {
+ fd_set readset, writeset, exceptset;
+ did = 0;
+ if (throttle-- < 0)
+ break;
+ for (i = 0; i < oss_nmidiin; i++)
+ {
+ char c;
+ int ret = read(oss_midiinfd[i], &c, 1);
+ if (ret < 0)
+ {
+ if (errno != EAGAIN)
+ perror("MIDI");
+ }
+ else if (ret != 0)
+ {
+ sys_midibytein(i, (c & 0xff));
+ did = 1;
+ }
+ }
+ }
+}
+#endif
+
+void linux_close_midi()
+{
+ int i;
+ for (i = 0; i < oss_nmidiin; i++)
+ close(oss_midiinfd[i]);
+ for (i = 0; i < oss_nmidiout; i++)
+ close(oss_midioutfd[i]);
+ oss_nmidiin = oss_nmidiout = 0;
+}
+
+#define MAXAUDIODEV 4
+#define DEFAULTINDEV 1
+#define DEFAULTOUTDEV 1
+
+/* ----------------------- public routines ----------------------- */
+void sys_listdevs( void)
+{
+ post("device listing not implemented in Linux yet\n");
+}
+
+void sys_open_audio(int naudioindev, int *audioindev, int nchindev,
+ int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
+ int *choutdev, int rate)
+{ /* IOhannes */
+ int i, *ip;
+ int defaultchannels =
+ (linux_whichapi == API_RME ? RME_DEFAULTCH : OSS_DEFAULTCH);
+ if (rate < 1)
+ rate=44100;
+
+ if (naudioindev == -1)
+ { /* not set */
+ if (nchindev==-1)
+ {
+ nchindev=1;
+ chindev[0]=defaultchannels;
+ naudioindev=1;
+ audioindev[0] = DEFAULTINDEV;
+ }
+ else
+ {
+ for (i = 0; i < MAXAUDIODEV; i++)
+ audioindev[i]=i+1;
+ naudioindev = nchindev;
+ }
+ }
+ else
+ {
+ if (nchindev == -1)
+ {
+ nchindev = naudioindev;
+ for (i = 0; i < naudioindev; i++)
+ chindev[i] = defaultchannels;
+ }
+ else if (nchindev > naudioindev)
+ {
+ for (i = naudioindev; i < nchindev; i++)
+ {
+ if (i == 0)
+ audioindev[0] = DEFAULTINDEV;
+ else audioindev[i] = audioindev[i-1] + 1;
+ }
+ naudioindev = nchindev;
+ }
+ else if (nchindev < naudioindev)
+ {
+ for (i = nchindev; i < naudioindev; i++)
+ {
+ if (i == 0)
+ chindev[0] = defaultchannels;
+ else chindev[i] = chindev[i-1];
+ }
+ naudioindev = nchindev;
+ }
+ }
+
+ if (naudiooutdev == -1)
+ { /* not set */
+ if (nchoutdev==-1)
+ {
+ nchoutdev=1;
+ choutdev[0]=defaultchannels;
+ naudiooutdev=1;
+ audiooutdev[0] = DEFAULTOUTDEV;
+ }
+ else
+ {
+ for (i = 0; i < MAXAUDIODEV; i++)
+ audiooutdev[i] = i+1;
+ naudiooutdev = nchoutdev;
+ }
+ }
+ else
+ {
+ if (nchoutdev == -1)
+ {
+ nchoutdev = naudiooutdev;
+ for (i = 0; i < naudiooutdev; i++)
+ choutdev[i] = defaultchannels;
+ }
+ else if (nchoutdev > naudiooutdev)
+ {
+ for (i = naudiooutdev; i < nchoutdev; i++)
+ {
+ if (i == 0)
+ audiooutdev[0] = DEFAULTOUTDEV;
+ else audiooutdev[i] = audiooutdev[i-1] + 1;
+ }
+ naudiooutdev = nchoutdev;
+ }
+ else if (nchoutdev < naudiooutdev)
+ {
+ for (i = nchoutdev; i < naudiooutdev; i++)
+ {
+ if (i == 0)
+ choutdev[0] = defaultchannels;
+ else choutdev[i] = choutdev[i-1];
+ }
+ naudiooutdev = nchoutdev;
+ }
+ }
+
+ linux_flush_all_underflows_to_zero();
+#ifdef ALSA
+ if (linux_whichapi == API_ALSA)
+ alsa_open_audio((naudioindev > 0 ? chindev[0] : 0),
+ (naudiooutdev > 0 ? choutdev[0] : 0), rate);
+ else
+#endif
+#ifdef RME_HAMMERFALL
+ if (linux_whichapi == API_RME)
+ rme9652_open_audio((naudioindev > 0 ? chindev[0] : 0),
+ (naudiooutdev > 0 ? choutdev[0] : 0), rate);
+ else
+#endif
+ oss_open_audio(naudioindev, audioindev, nchindev, chindev,
+ naudiooutdev, audiooutdev, nchoutdev, choutdev, rate);
+}
+
+void sys_close_audio(void)
+{
+ /* set timeout to avoid hanging close() call */
+
+ sys_setalarm(1000000);
+
+#ifdef ALSA
+ if (linux_whichapi == API_ALSA)
+ alsa_close_audio();
+ else
+#endif
+#ifdef RME_HAMMERFALL
+ if (linux_whichapi == API_RME)
+ rme9652_close_audio();
+ else
+#endif
+ oss_close_audio();
+
+ sys_setalarm(0);
+}
+
+void sys_open_midi(int nmidiin, int *midiinvec,
+ int nmidiout, int *midioutvec)
+{
+ linux_open_midi(nmidiin, midiinvec, nmidiout, midioutvec);
+}
+
+void sys_close_midi( void)
+{
+ sys_setalarm(1000000);
+ linux_close_midi();
+ sys_setalarm(0);
+}
+
+int sys_send_dacs(void)
+{
+ if (linux_meters)
+ {
+ int i, n;
+ float maxsamp;
+ for (i = 0, n = linux_inchannels * DACBLKSIZE, maxsamp = linux_inmax;
+ i < n; i++)
+ {
+ float f = sys_soundin[i];
+ if (f > maxsamp) maxsamp = f;
+ else if (-f > maxsamp) maxsamp = -f;
+ }
+ linux_inmax = maxsamp;
+ for (i = 0, n = linux_outchannels * DACBLKSIZE, maxsamp = linux_outmax;
+ i < n; i++)
+ {
+ float f = sys_soundout[i];
+ if (f > maxsamp) maxsamp = f;
+ else if (-f > maxsamp) maxsamp = -f;
+ }
+ linux_outmax = maxsamp;
+ }
+#ifdef ALSA
+ if (linux_whichapi == API_ALSA)
+ return alsa_send_dacs();
+#endif
+#ifdef RME_HAMMERFALL
+ if (linux_whichapi == API_RME)
+ return rme9652_send_dacs();
+#endif
+ return oss_send_dacs();
+}
+
+float sys_getsr(void)
+{
+ return (sys_dacsr);
+}
+
+int sys_get_outchannels(void)
+{
+ return (linux_outchannels);
+}
+
+int sys_get_inchannels(void)
+{
+ return (linux_inchannels);
+}
+
+void sys_audiobuf(int n)
+{
+ /* set the size, in milliseconds, of the audio FIFO */
+ if (n < 5) n = 5;
+ else if (n > 5000) n = 5000;
+ sys_schedadvance = n * 1000;
+}
+
+void sys_getmeters(float *inmax, float *outmax)
+{
+ if (inmax)
+ {
+ linux_meters = 1;
+ *inmax = linux_inmax;
+ *outmax = linux_outmax;
+ }
+ else
+ linux_meters = 0;
+ linux_inmax = linux_outmax = 0;
+}
+
+void sys_reportidle(void)
+{
+}
+
+void sys_set_priority(int higher)
+{
+ struct sched_param par;
+ int p1 ,p2, p3;
+#ifdef _POSIX_PRIORITY_SCHEDULING
+
+ p1 = sched_get_priority_min(SCHED_FIFO);
+ p2 = sched_get_priority_max(SCHED_FIFO);
+ p3 = (higher ? p2 - 1 : p2 - 3);
+ par.sched_priority = p3;
+
+ if (sched_setscheduler(0,SCHED_FIFO,&par) != -1)
+ fprintf(stderr, "priority %d scheduling enabled.\n", p3);
+#endif
+
+#ifdef _POSIX_MEMLOCK
+ if (mlockall(MCL_FUTURE) != -1)
+ fprintf(stderr, "memory locking enabled.\n");
+#endif
+}
+
+void sys_setblocksize(int n)
+{
+ if (n < 1)
+ n = 1;
+ linux_fragsize = n;
+ oss_blockmode = 1;
+}
+
+/* ------------ linux-specific command-line flags -------------- */
+
+void linux_setfrags(int n)
+{
+ linux_nfragment = n;
+ oss_blockmode = 1;
+}
+
+void linux_streammode( void)
+{
+ oss_blockmode = 0;
+}
+
+void linux_32bit( void)
+{
+ oss_32bit = 1;
+}
+
+void linux_set_sound_api(int which)
+{
+ linux_whichapi = which;
+ if (sys_verbose)
+ post("linux_whichapi %d", linux_whichapi);
+}
+
+#ifdef ALSA99
+void linux_alsa_devno(int devno)
+{
+ alsa_devno = devno;
+}
+
+#endif
+
+#ifdef ALSA01
+void linux_alsa_devname(char *devname)
+{
+ strncpy(alsa_devname, devname, 511);
+}
+
+void linux_alsa_use_plugin(int t)
+{
+ if (t == 1)
+ alsa_use_plugin = 1;
+ else
+ alsa_use_plugin = 0;
+}
+
+#endif
+
+/* -------------- Audio I/O using the OSS API ------------------ */
+
+typedef struct _multidev {
+ int fd;
+ int channels;
+ int format;
+} t_multidev;
+
+int oss_reset(int fd) {
+ int err;
+ if ((err = ioctl(fd,SNDCTL_DSP_RESET)) < 0)
+ error("OSS: Could not reset");
+ return err;
+}
+
+ /* The AFMT_S32_BLOCKED format is not defined in standard linux kernels
+ but is proposed by Guenter Geiger to support extending OSS to handle
+ 32 bit sample. This is user in Geiger's OSS driver for RME Hammerfall.
+ I'm not clear why this isn't called AFMT_S32_[SLN]E... */
+
+#ifndef AFMT_S32_BLOCKED
+#define AFMT_S32_BLOCKED 0x0000400
+#endif
+
+void oss_configure(t_oss_dev *dev, int srate, int dac, int skipblocksize)
+{ /* IOhannes */
+ int orig, param, nblk, fd = dev->d_fd, wantformat;
+ int nchannels = dev->d_nchannels;
+ int advwas = sys_schedadvance;
+
+ audio_buf_info ainfo;
+
+ /* IOhannes :
+ * pd is very likely to crash if different formats are used on
+ multiple soundcards
+ */
+
+ /* set resolution - first try 4 byte samples */
+ if (oss_32bit && (ioctl(fd,SNDCTL_DSP_GETFMTS,&param) >= 0) &&
+ (param & AFMT_S32_BLOCKED))
+ {
+ wantformat = AFMT_S32_BLOCKED;
+ dev->d_bytespersamp = 4;
+ }
+ else
+ {
+ wantformat = AFMT_S16_NE;
+ dev->d_bytespersamp = 2;
+ }
+ param = wantformat;
+
+ if (sys_verbose)
+ post("bytes per sample = %d", dev->d_bytespersamp);
+ if (ioctl(fd, SNDCTL_DSP_SETFMT, &param) == -1)
+ fprintf(stderr,"OSS: Could not set DSP format\n");
+ else if (wantformat != param)
+ fprintf(stderr,"OSS: DSP format: wanted %d, got %d\n",
+ wantformat, param);
+
+ /* sample rate */
+ orig = param = srate;
+ if (ioctl(fd, SNDCTL_DSP_SPEED, &param) == -1)
+ fprintf(stderr,"OSS: Could not set sampling rate for device\n");
+ else if( orig != param )
+ fprintf(stderr,"OSS: sampling rate: wanted %d, got %d\n",
+ orig, param );
+
+ if (oss_blockmode && !skipblocksize)
+ {
+ int fragbytes, logfragsize, nfragment;
+ /* setting fragment count and size. */
+ if (linux_nfragment) /* if nfrags specified, take literally */
+ {
+ nfragment = linux_nfragment;
+ if (!linux_fragsize)
+ linux_fragsize = OSS_DEFFRAGSIZE;
+ sys_schedadvance = ((nfragment * linux_fragsize) * 1.e6)
+ / (float)srate;
+ linux_setsr(srate);
+ }
+ else
+ {
+ if (!linux_fragsize)
+ {
+ linux_fragsize = OSS_DEFFRAGSIZE;
+ while (linux_fragsize > DACBLKSIZE
+ && linux_fragsize * 4 > linux_advance_samples)
+ linux_fragsize = linux_fragsize/2;
+ }
+ /* post("adv_samples %d", linux_advance_samples); */
+ nfragment = (sys_schedadvance * (44100. * 1.e-6)) / linux_fragsize;
+ }
+ fragbytes = linux_fragsize * (dev->d_bytespersamp * nchannels);
+ logfragsize = ilog2(fragbytes);
+
+ if (fragbytes != (1 << logfragsize))
+ post("warning: OSS takes only power of 2 blocksize; using %d",
+ (1 << logfragsize)/(dev->d_bytespersamp * nchannels));
+ if (sys_verbose)
+ post("setting nfrags = %d, fragsize %d\n", nfragment, fragbytes);
+
+ param = orig = (nfragment<<16) + logfragsize;
+ if (ioctl(fd,SNDCTL_DSP_SETFRAGMENT, &param) == -1)
+ error("OSS: Could not set or read fragment size\n");
+ if (param != orig)
+ {
+ nfragment = ((param >> 16) & 0xffff);
+ logfragsize = (param & 0xffff);
+ post("warning: actual fragments %d, blocksize %d",
+ nfragment, (1 << logfragsize));
+ }
+ if (sys_verbose)
+ post("audiobuffer set to %d msec", (int)(0.001 * sys_schedadvance));
+ }
+
+ if (dac)
+ {
+ /* use "free space" to learn the buffer size. Normally you
+ should set this to your own desired value; but this seems not
+ to be implemented uniformly across different sound cards. LATER
+ we should figure out what to do if the requested scheduler advance
+ is greater than this buffer size; for now, we just print something
+ out. */
+
+ int defect;
+ if (ioctl(fd, SOUND_PCM_GETOSPACE,&ainfo) < 0)
+ fprintf(stderr,"OSS: ioctl on output device failed");
+ dev->d_bufsize = ainfo.bytes;
+
+ defect = linux_advance_samples * (dev->d_bytespersamp * nchannels)
+ - dev->d_bufsize - OSS_XFERSIZE(nchannels, dev->d_bytespersamp);
+ if (defect > 0)
+ {
+ if (sys_verbose || defect > (dev->d_bufsize >> 2))
+ fprintf(stderr,
+ "OSS: requested audio buffer size %d limited to %d\n",
+ linux_advance_samples * (dev->d_bytespersamp * nchannels),
+ dev->d_bufsize);
+ linux_advance_samples =
+ (dev->d_bufsize - OSS_XFERSAMPS(nchannels)) /
+ (dev->d_bytespersamp *nchannels);
+ }
+ }
+}
+
+static int oss_setchannels(int fd, int wantchannels, char *devname)
+{ /* IOhannes */
+ int param = wantchannels;
+
+ while (param>1) {
+ int save = param;
+ if (ioctl(fd, SNDCTL_DSP_CHANNELS, &param) == -1) {
+ error("OSS: SNDCTL_DSP_CHANNELS failed %s",devname);
+ } else {
+ if (param == save) return (param);
+ }
+ param=save-1;
+ }
+
+ return (0);
+}
+
+#define O_AUDIOFLAG 0 /* O_NDELAY */
+
+int oss_open_audio(int nindev, int *indev, int nchin, int *chin,
+ int noutdev, int *outdev, int nchout, int *chout, int rate)
+{ /* IOhannes */
+ int capabilities = 0;
+ int inchannels = 0, outchannels = 0;
+ char devname[20];
+ int n, i, fd;
+ char buf[OSS_MAXSAMPLEWIDTH * DACBLKSIZE * OSS_MAXCHPERDEV];
+ int num_devs = 0;
+ int wantmore=0;
+ int spread = 0;
+ audio_buf_info ainfo;
+
+ linux_nindevs = linux_noutdevs = 0;
+
+ /* set logical sample rate amd calculate linux_advance_samples. */
+ linux_setsr(rate);
+
+ /* mark input devices unopened */
+ for (i = 0; i < OSS_MAXDEV; i++)
+ linux_adcs[i].d_fd = -1;
+
+ /* open output devices */
+ wantmore=0;
+ if (noutdev < 0 || nindev < 0)
+ bug("linux_open_audio");
+
+ for (n = 0; n < noutdev; n++)
+ {
+ int gotchans, j, inindex = -1;
+ int thisdevice=outdev[n];
+ int wantchannels = (nchout>n) ? chout[n] : wantmore;
+ fd = -1;
+ if (!wantchannels)
+ goto end_out_loop;
+
+ if (thisdevice > 1)
+ sprintf(devname, "/dev/dsp%d", thisdevice-1);
+ else sprintf(devname, "/dev/dsp");
+
+ /* search for input request for same device. Succeed only
+ if the number of channels matches. */
+ for (j = 0; j < nindev; j++)
+ if (indev[j] == thisdevice && chin[j] == wantchannels)
+ inindex = j;
+
+ /* if the same device is requested for input and output,
+ try to open it read/write */
+ if (inindex >= 0)
+ {
+ sys_setalarm(1000000);
+ if ((fd = open(devname, O_RDWR | O_AUDIOFLAG)) == -1)
+ {
+ post("%s (read/write): %s", devname, strerror(errno));
+ post("(now will try write-only...)");
+ }
+ else
+ {
+ if (sys_verbose)
+ post("opened %s for reading and writing\n", devname);
+ linux_adcs[inindex].d_fd = fd;
+ }
+ }
+ /* if that didn't happen or if it failed, try write-only */
+ if (fd == -1)
+ {
+ sys_setalarm(1000000);
+ if ((fd = open(devname, O_WRONLY | O_AUDIOFLAG)) == -1)
+ {
+ post("%s (writeonly): %s",
+ devname, strerror(errno));
+ break;
+ }
+ if (sys_verbose)
+ post("opened %s for writing only\n", devname);
+ }
+ if (ioctl(fd, SNDCTL_DSP_GETCAPS, &capabilities) == -1)
+ error("OSS: SNDCTL_DSP_GETCAPS failed %s", devname);
+
+ gotchans = oss_setchannels(fd,
+ (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels,
+ devname);
+
+ if (sys_verbose)
+ post("opened audio output on %s; got %d channels",
+ devname, gotchans);
+
+ if (gotchans < 2)
+ {
+ /* can't even do stereo? just give up. */
+ close(fd);
+ }
+ else
+ {
+ linux_dacs[linux_noutdevs].d_nchannels = gotchans;
+ linux_dacs[linux_noutdevs].d_fd = fd;
+ oss_configure(linux_dacs+linux_noutdevs, rate, 1, 0);
+
+ linux_noutdevs++;
+ outchannels += gotchans;
+ if (inindex >= 0)
+ {
+ linux_adcs[inindex].d_nchannels = gotchans;
+ chin[inindex] = gotchans;
+ }
+ }
+ /* LATER think about spreading large numbers of channels over
+ various dsp's and vice-versa */
+ wantmore = wantchannels - gotchans;
+ end_out_loop: ;
+ }
+
+ /* open input devices */
+ wantmore = 0;
+ if (nindev==-1)
+ nindev=4; /* spread channels over default-devices */
+ for (n = 0; n < nindev; n++)
+ {
+ int gotchans=0;
+ int thisdevice=indev[n];
+ int wantchannels = (nchin>n)?chin[n]:wantmore;
+ int alreadyopened = 0;
+ if (!wantchannels)
+ goto end_in_loop;
+
+ if (thisdevice > 1)
+ sprintf(devname, "/dev/dsp%d", thisdevice - 1);
+ else sprintf(devname, "/dev/dsp");
+
+ sys_setalarm(1000000);
+
+ /* perhaps it's already open from the above? */
+ if (linux_dacs[n].d_fd >= 0)
+ {
+ fd = linux_dacs[n].d_fd;
+ alreadyopened = 1;
+ }
+ else
+ {
+ /* otherwise try to open it here. */
+ if ((fd = open(devname, O_RDONLY | O_AUDIOFLAG)) == -1)
+ {
+ post("%s (readonly): %s", devname, strerror(errno));
+ goto end_in_loop;
+ }
+ if (sys_verbose)
+ post("opened %s for reading only\n", devname);
+ }
+ linux_adcs[linux_nindevs].d_fd = fd;
+ gotchans = oss_setchannels(fd,
+ (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels,
+ devname);
+ if (sys_verbose)
+ post("opened audio input device %s; got %d channels",
+ devname, gotchans);
+
+ if (gotchans < 1)
+ {
+ close(fd);
+ goto end_in_loop;
+ }
+
+ linux_adcs[linux_nindevs].d_nchannels = gotchans;
+
+ oss_configure(linux_adcs+linux_nindevs, rate, 0, alreadyopened);
+
+ inchannels += gotchans;
+ linux_nindevs++;
+
+ wantmore = wantchannels-gotchans;
+ /* LATER think about spreading large numbers of channels over
+ various dsp's and vice-versa */
+ end_in_loop: ;
+ }
+
+ linux_setch(inchannels, outchannels);
+
+ /* We have to do a read to start the engine. This is
+ necessary because sys_send_dacs waits until the input
+ buffer is filled and only reads on a filled buffer.
+ This is good, because it's a way to make sure that we
+ will not block. But I wonder why we only have to read
+ from one of the devices and not all of them??? */
+
+ if (linux_nindevs)
+ {
+ if (sys_verbose)
+ fprintf(stderr,("OSS: issuing first ADC 'read' ... "));
+ read(linux_adcs[0].d_fd, buf,
+ linux_adcs[0].d_bytespersamp *
+ linux_adcs[0].d_nchannels * DACBLKSIZE);
+ if (sys_verbose)
+ fprintf(stderr, "...done.\n");
+ }
+ sys_setalarm(0);
+ return (0);
+}
+
+void oss_close_audio( void)
+{
+ int i;
+ for (i=0;i<linux_nindevs;i++)
+ close(linux_adcs[i].d_fd);
+
+ for (i=0;i<linux_noutdevs;i++)
+ close(linux_dacs[i].d_fd);
+
+ linux_nindevs = linux_noutdevs = 0;
+}
+
+static int linux_dacs_write(int fd,void* buf,long bytes)
+{
+ return write(fd, buf, bytes);
+}
+
+static int linux_adcs_read(int fd,void* buf,long bytes)
+{
+ return read(fd, buf, bytes);
+}
+
+ /* query audio devices for "available" data size. */
+static void oss_calcspace(void)
+{
+ int dev;
+ audio_buf_info ainfo;
+ for (dev=0; dev < linux_noutdevs; dev++)
+ {
+ if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0)
+ fprintf(stderr,"OSS: ioctl on output device %d failed",dev);
+ linux_dacs[dev].d_space = ainfo.bytes;
+ }
+
+ for (dev = 0; dev < linux_nindevs; dev++)
+ {
+ if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE,&ainfo) < 0)
+ fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed",
+ dev, linux_adcs[dev].d_fd);
+ linux_adcs[dev].d_space = ainfo.bytes;
+ }
+}
+
+void linux_audiostatus(void)
+{
+ int dev;
+ if (!oss_blockmode)
+ {
+ oss_calcspace();
+ for (dev=0; dev < linux_noutdevs; dev++)
+ fprintf(stderr, "dac %d space %d\n", dev, linux_dacs[dev].d_space);
+
+ for (dev = 0; dev < linux_nindevs; dev++)
+ fprintf(stderr, "adc %d space %d\n", dev, linux_adcs[dev].d_space);
+
+ }
+}
+
+/* this call resyncs audio output and input which will cause discontinuities
+in audio output and/or input. */
+
+static void oss_doresync( void)
+{
+ int dev, zeroed = 0, wantsize;
+ char buf[OSS_MAXSAMPLEWIDTH * DACBLKSIZE * OSS_MAXCHPERDEV];
+ audio_buf_info ainfo;
+
+ /* 1. if any input devices are ahead (have more than 1 buffer stored),
+ drop one or more buffers worth */
+ for (dev = 0; dev < linux_nindevs; dev++)
+ {
+ if (linux_adcs[dev].d_space == 0)
+ {
+ linux_adcs_read(linux_adcs[dev].d_fd, buf,
+ OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
+ linux_adcs[dev].d_bytespersamp));
+ }
+ else while (linux_adcs[dev].d_space >
+ OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
+ linux_adcs[dev].d_bytespersamp))
+ {
+ linux_adcs_read(linux_adcs[dev].d_fd, buf,
+ OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
+ linux_adcs[dev].d_bytespersamp));
+ if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE, &ainfo) < 0)
+ {
+ fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed",
+ dev, linux_adcs[dev].d_fd);
+ break;
+ }
+ linux_adcs[dev].d_space = ainfo.bytes;
+ }
+ }
+
+ /* 2. if any output devices are behind, feed them zeros to catch them
+ up */
+ for (dev = 0; dev < linux_noutdevs; dev++)
+ {
+ while (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize -
+ linux_advance_samples * (linux_dacs[dev].d_nchannels *
+ linux_dacs[dev].d_bytespersamp))
+ {
+ if (!zeroed)
+ {
+ unsigned int i;
+ for (i = 0; i < OSS_XFERSAMPS(linux_dacs[dev].d_nchannels);
+ i++)
+ buf[i] = 0;
+ zeroed = 1;
+ }
+ linux_dacs_write(linux_dacs[dev].d_fd, buf,
+ OSS_XFERSIZE(linux_dacs[dev].d_nchannels,
+ linux_dacs[dev].d_bytespersamp));
+ if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0)
+ {
+ fprintf(stderr, "OSS: ioctl on output device %d, fd %d failed",
+ dev, linux_dacs[dev].d_fd);
+ break;
+ }
+ linux_dacs[dev].d_space = ainfo.bytes;
+ }
+ }
+ /* 3. if any DAC devices are too far ahead, plan to drop the
+ number of frames which will let the others catch up. */
+ for (dev = 0; dev < linux_noutdevs; dev++)
+ {
+ if (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize -
+ (linux_advance_samples - 1) * linux_dacs[dev].d_nchannels *
+ linux_dacs[dev].d_bytespersamp)
+ {
+ linux_dacs[dev].d_dropcount = linux_advance_samples - 1 -
+ (linux_dacs[dev].d_space - linux_dacs[dev].d_bufsize) /
+ (linux_dacs[dev].d_nchannels *
+ linux_dacs[dev].d_bytespersamp) ;
+ }
+ else linux_dacs[dev].d_dropcount = 0;
+ }
+}
+
+int oss_send_dacs(void)
+{
+ float *fp1, *fp2;
+ long fill;
+ int i, j, dev, rtnval = SENDDACS_YES;
+ char buf[OSS_MAXSAMPLEWIDTH * DACBLKSIZE * OSS_MAXCHPERDEV];
+ t_oss_int16 *sp;
+ t_oss_int32 *lp;
+ /* the maximum number of samples we should have in the ADC buffer */
+ int idle = 0;
+ int thischan;
+ double timeref, timenow;
+
+ if (!linux_nindevs && !linux_noutdevs)
+ return (SENDDACS_NO);
+
+ if (!oss_blockmode)
+ {
+ /* determine whether we're idle. This is true if either (1)
+ some input device has less than one buffer to read or (2) some
+ output device has fewer than (linux_advance_samples) blocks buffered
+ already. */
+ oss_calcspace();
+
+ for (dev=0; dev < linux_noutdevs; dev++)
+ if (linux_dacs[dev].d_dropcount ||
+ (linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space >
+ linux_advance_samples * linux_dacs[dev].d_bytespersamp *
+ linux_dacs[dev].d_nchannels))
+ idle = 1;
+ for (dev=0; dev < linux_nindevs; dev++)
+ if (linux_adcs[dev].d_space <
+ OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
+ linux_adcs[dev].d_bytespersamp))
+ idle = 1;
+ }
+
+ if (idle && !oss_blockmode)
+ {
+ /* sometimes---rarely---when the ADC available-byte-count is
+ zero, it's genuine, but usually it's because we're so
+ late that the ADC has overrun its entire kernel buffer. We
+ distinguish between the two by waiting 2 msec and asking again.
+ There should be an error flag we could check instead; look for this
+ someday... */
+ for (dev = 0;dev < linux_nindevs; dev++)
+ if (linux_adcs[dev].d_space == 0)
+ {
+ audio_buf_info ainfo;
+ sys_microsleep(2000);
+ oss_calcspace();
+ if (linux_adcs[dev].d_space != 0) continue;
+
+ /* here's the bad case. Give up and resync. */
+ sys_log_error(ERR_DATALATE);
+ oss_doresync();
+ return (SENDDACS_NO);
+ }
+ /* check for slippage between devices, either because
+ data got lost in the driver from a previous late condition, or
+ because the devices aren't synced. When we're idle, no
+ input device should have more than one buffer readable and
+ no output device should have less than linux_advance_samples-1
+ */
+
+ for (dev=0; dev < linux_noutdevs; dev++)
+ if (!linux_dacs[dev].d_dropcount &&
+ (linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space <
+ (linux_advance_samples - 2) *
+ (linux_dacs[dev].d_bytespersamp *
+ linux_dacs[dev].d_nchannels)))
+ goto badsync;
+ for (dev=0; dev < linux_nindevs; dev++)
+ if (linux_adcs[dev].d_space > 3 *
+ OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
+ linux_adcs[dev].d_bytespersamp))
+ goto badsync;
+
+ /* return zero to tell the scheduler we're idle. */
+ return (SENDDACS_NO);
+ badsync:
+ sys_log_error(ERR_RESYNC);
+ oss_doresync();
+ return (SENDDACS_NO);
+
+ }
+
+ /* do output */
+
+ timeref = sys_getrealtime();
+ for (dev=0, thischan = 0; dev < linux_noutdevs; dev++)
+ {
+ int nchannels = linux_dacs[dev].d_nchannels;
+ if (linux_dacs[dev].d_dropcount)
+ linux_dacs[dev].d_dropcount--;
+ else
+ {
+ if (linux_dacs[dev].d_bytespersamp == 4)
+ {
+ for (i = DACBLKSIZE * nchannels, fp1 = sys_soundout +
+ DACBLKSIZE*thischan,
+ lp = (t_oss_int32 *)buf; i--; fp1++, lp++)
+ {
+ float f = *fp1 * 2147483648.;
+ *lp = (f >= 2147483647. ? 2147483647. :
+ (f < -2147483648. ? -2147483648. : f));
+ }
+ }
+ else
+ {
+ for (i = DACBLKSIZE, fp1 = sys_soundout +
+ DACBLKSIZE*thischan,
+ sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels)
+ {
+ for (j=0, fp2 = fp1; j<nchannels; j++, fp2 += DACBLKSIZE)
+ {
+ int s = *fp2 * 32767.;
+ if (s > 32767) s = 32767;
+ else if (s < -32767) s = -32767;
+ sp[j] = s;
+ }
+ }
+ }
+ linux_dacs_write(linux_dacs[dev].d_fd, buf,
+ OSS_XFERSIZE(nchannels, linux_dacs[dev].d_bytespersamp));
+ if ((timenow = sys_getrealtime()) - timeref > 0.002)
+ {
+ if (!oss_blockmode)
+ sys_log_error(ERR_DACSLEPT);
+ else rtnval = SENDDACS_SLEPT;
+ }
+ timeref = timenow;
+ }
+ thischan += nchannels;
+ }
+ memset(sys_soundout, 0,
+ linux_outchannels * (sizeof(float) * DACBLKSIZE));
+
+ /* do input */
+
+ for (dev = 0, thischan = 0; dev < linux_nindevs; dev++)
+ {
+ int nchannels = linux_adcs[dev].d_nchannels;
+ linux_adcs_read(linux_adcs[dev].d_fd, buf,
+ OSS_XFERSIZE(nchannels, linux_adcs[dev].d_bytespersamp));
+
+ if ((timenow = sys_getrealtime()) - timeref > 0.002)
+ {
+ if (!oss_blockmode)
+ sys_log_error(ERR_ADCSLEPT);
+ else
+ rtnval = SENDDACS_SLEPT;
+ }
+ timeref = timenow;
+
+ if (linux_adcs[dev].d_bytespersamp == 4)
+ {
+ for (i = DACBLKSIZE*nchannels,
+ fp1 = sys_soundin + thischan*DACBLKSIZE,
+ lp = (t_oss_int32 *)buf; i--; fp1++, lp++)
+ {
+ *fp1 = ((float)(*lp))*(float)(1./2147483648.);
+ }
+ }
+ else
+ {
+ for (i = DACBLKSIZE,fp1 = sys_soundin + thischan*DACBLKSIZE,
+ sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels)
+ {
+ for (j=0;j<linux_inchannels;j++)
+ fp1[j*DACBLKSIZE] = (float)sp[j]*(float)3.051850e-05;
+ }
+ }
+ thischan += nchannels;
+ }
+ if (thischan != linux_inchannels)
+ bug("inchannels");
+ return (rtnval);
+}
+
+/* ----------------- audio I/O using the ALSA native API ---------------- */
+
+#ifdef ALSA
+static void alsa_checkversion( void)
+{
+ char snox[512];
+ int fd, nbytes;
+ if ((fd = open("/proc/asound/version", 0)) < 0 ||
+ (nbytes = read(fd, snox, 511)) < 1)
+ {
+ perror("cannot check Alsa version -- /proc/asound/version");
+ return;
+ }
+ snox[nbytes] = 0;
+#ifdef ALSA99
+ if (!strstr(snox, "Version 0.5"))
+ {
+ fprintf(stderr,
+"warning: Pd compiled for Alsa version 0.5 appears to be incompatible with\n\
+the installed version of ALSA. Here is what I found in /proc/asound/version:\n"
+ );
+ fprintf(stderr, "%s", snox);
+ }
+#else
+ if (!strstr(snox, "Version 0.9"))
+ {
+ fprintf(stderr,
+"warning: Pd compiled for Alsa version 0.9 appears to be incompatible with\n\
+the installed version of ALSA. Here is what I found in /proc/asound/version:\n"
+ );
+ fprintf(stderr, "%s", snox);
+ }
+#endif
+}
+#endif
+
+#ifdef ALSA99
+static int alsa_open_audio(int wantinchans, int wantoutchans,
+ int srate)
+{
+ int dir, voices, bsize;
+ int err, id, rate, i;
+ char *cardname;
+ snd_ctl_hw_info_t hwinfo;
+ snd_pcm_info_t pcminfo;
+ snd_pcm_channel_info_t channelinfo;
+ snd_ctl_t *handle;
+ snd_pcm_sync_t sync;
+
+ linux_inchannels = 0;
+ linux_outchannels = 0;
+
+ rate = 44100;
+ alsa_samplewidth = 4; /* first try 4 byte samples */
+
+ if (!wantinchans && !wantoutchans)
+ return (1);
+
+ alsa_checkversion();
+ if (sys_verbose)
+ {
+ if ((err = snd_card_get_longname(alsa_devno-1, &cardname)) < 0)
+ {
+ fprintf(stderr, "PD-ALSA: unable to get name of card number %d\n",
+ alsa_devno);
+ return 1;
+ }
+ fprintf(stderr, "PD-ALSA: using card %s\n", cardname);
+ free(cardname);
+ }
+
+ if ((err = snd_ctl_open(&handle, alsa_devno-1)) < 0)
+ {
+ fprintf(stderr, "PD-ALSA: unable to open control: %s\n",
+ snd_strerror(err));
+ return 1;
+ }
+
+ if ((err = snd_ctl_hw_info(handle, &hwinfo)) < 0)
+ {
+ fprintf(stderr, "PD-ALSA: unable to open get info: %s\n",
+ snd_strerror(err));
+ return 1;
+ }
+ if (hwinfo.pcmdevs < 1)
+ {
+ fprintf(stderr, "PD-ALSA: device %d doesn't support PCM\n",
+ alsa_devno);
+ snd_ctl_close(handle);
+ return 1;
+ }
+
+ if ((err = snd_ctl_pcm_info(handle, 0, &pcminfo)) < 0)
+ {
+ fprintf(stderr, "PD-ALSA: unable to open get pcm info: %s\n",
+ snd_strerror(err));
+ snd_ctl_close(handle);
+ return (1);
+ }
+ snd_ctl_close(handle);
+
+ /* find out if opening for input, output, or both and check that the
+ device can handle it. */
+ if (wantinchans && wantoutchans)
+ {
+ if (!(pcminfo.flags & SND_PCM_INFO_DUPLEX))
+ {
+ fprintf(stderr, "PD-ALSA: device is not full duplex\n");
+ return (1);
+ }
+ dir = SND_PCM_OPEN_DUPLEX;
+ }
+ else if (wantoutchans)
+ {
+ if (!(pcminfo.flags & SND_PCM_INFO_PLAYBACK))
+ {
+ fprintf(stderr, "PD-ALSA: device is not full duplex\n");
+ return (1);
+ }
+ dir = SND_PCM_OPEN_PLAYBACK;
+ }
+ else
+ {
+ if (!(pcminfo.flags & SND_PCM_INFO_CAPTURE))
+ {
+ fprintf(stderr, "PD-ALSA: device is not full duplex\n");
+ return (1);
+ }
+ dir = SND_PCM_OPEN_CAPTURE;
+ }
+
+ /* try to open the device */
+ if ((err = snd_pcm_open(&alsa_device[0].handle, alsa_devno-1, 0, dir)) < 0)
+ {
+ fprintf(stderr, "PD-ALSA: error opening device: %s\n",
+ snd_strerror(err));
+ return (1);
+ }
+ /* get information from the handle */
+ if (wantinchans)
+ {
+ channelinfo.channel = SND_PCM_CHANNEL_CAPTURE;
+ channelinfo.subdevice = 0;
+ if ((err = snd_pcm_channel_info(alsa_device[0].handle, &channelinfo))
+ < 0)
+ {
+ fprintf(stderr, "PD-ALSA: snd_pcm_channel_info (input): %s\n",
+ snd_strerror(err));
+ return (1);
+ }
+ if (sys_verbose)
+ post("input channels supported: %d-%d\n",
+ channelinfo.min_voices, channelinfo.max_voices);
+
+ if (wantinchans < channelinfo.min_voices)
+ post("increasing input channels to minimum of %d\n",
+ wantinchans = channelinfo.min_voices);
+ if (wantinchans > channelinfo.max_voices)
+ post("decreasing input channels to maximum of %d\n",
+ wantinchans = channelinfo.max_voices);
+ if (alsa_samplewidth == 4 &&
+ !(channelinfo.formats & (1<<SND_PCM_SFMT_S32_LE)))
+ {
+ fprintf(stderr,
+ "PD_ALSA: input doesn't support 32-bit samples; using 16\n");
+ alsa_samplewidth = 2;
+ }
+ if (alsa_samplewidth == 2 &&
+ !(channelinfo.formats & (1<<SND_PCM_SFMT_S16_LE)))
+ {
+ fprintf(stderr,
+ "PD_ALSA: can't find 4 or 2 byte format; giving up\n");
+ return (1);
+ }
+ }
+
+ if (wantoutchans)
+ {
+ channelinfo.channel = SND_PCM_CHANNEL_PLAYBACK;
+ channelinfo.subdevice = 0;
+ if ((err = snd_pcm_channel_info(alsa_device[0].handle, &channelinfo))
+ < 0)
+ {
+ fprintf(stderr, "PD-ALSA: snd_pcm_channel_info (output): %s\n",
+ snd_strerror(err));
+ return (1);
+ }
+ if (sys_verbose)
+ post("output channels supported: %d-%d\n",
+ channelinfo.min_voices, channelinfo.max_voices);
+ if (wantoutchans < channelinfo.min_voices)
+ post("increasing output channels to minimum of %d\n",
+ wantoutchans = channelinfo.min_voices);
+ if (wantoutchans > channelinfo.max_voices)
+ post("decreasing output channels to maximum of %d\n",
+ wantoutchans = channelinfo.max_voices);
+ if (alsa_samplewidth == 4 &&
+ !(channelinfo.formats & (1<<SND_PCM_SFMT_S32_LE)))
+ {
+ fprintf(stderr,
+ "PD_ALSA: output doesn't support 32-bit samples; using 16\n");
+ alsa_samplewidth = 2;
+ }
+ if (alsa_samplewidth == 2 &&
+ !(channelinfo.formats & (1<<SND_PCM_SFMT_S16_LE)))
+ {
+ fprintf(stderr,
+ "PD_ALSA: can't find 4 or 2 byte format; giving up\n");
+ return (1);
+ }
+ }
+
+ linux_setsr(rate);
+ linux_setch(wantinchans, wantoutchans);
+
+ if (wantinchans)
+ alsa_set_params(&alsa_device[0], SND_PCM_CHANNEL_CAPTURE,
+ srate, wantinchans);
+ if (wantoutchans)
+ alsa_set_params(&alsa_device[0], SND_PCM_CHANNEL_PLAYBACK,
+ srate, wantoutchans);
+
+ n_alsa_dev = 1;
+
+ /* check that all is as we think it should be */
+ for (i = 0; i < n_alsa_dev; i++)
+ {
+ /* We need to handle if the rate is not the same for all
+ * devices. For now just hope. */
+ rate = alsa_device[i].setup.format.rate;
+
+ /* It turns out that this checking does not work on all of my cards
+ * - in full duplex on my trident 4dwave the setup on the capture channel
+ * shows a sampling rate of 0. This is not true on my ess solo1. Checking
+ * the dac last helps the problem. All of this needs to be much smarter
+ * anyway (last minute hack). A warning above is all I have time for.
+ */
+ if (rate != srate)
+ {
+ post("PD-ALSA: unable to obtain rate %i using %i", srate, rate);
+ post("PD-ALSA: (despite this warning Pd might still work.)");
+ }
+ }
+ bsize = alsa_samplewidth *
+ (linux_inchannels > linux_outchannels ? linux_inchannels :
+ linux_outchannels) * DACBLKSIZE;
+ alsa_buf = malloc(bsize);
+ if (!alsa_buf)
+ return (1);
+ memset(alsa_buf, 0, bsize);
+ return 0;
+}
+
+void alsa_set_params(t_alsa_dev *dev, int dir, int rate, int voices)
+{
+ int err;
+ struct snd_pcm_channel_params params;
+
+ memset(&dev->info, 0, sizeof(dev->info));
+ dev->info.channel = dir;
+ if ((err = snd_pcm_channel_info(dev->handle, &dev->info) < 0))
+ {
+ fprintf(stderr, "PD-ALSA: error getting channel info: %s\n",
+ snd_strerror(err));
+ }
+ memset(&params, 0, sizeof(params));
+ params.format.interleave = 1; /* may do non-interleaved later */
+ /* format is 2 or 4 bytes per sample depending on what was possible */
+ params.format.format =
+ (alsa_samplewidth == 4 ? SND_PCM_SFMT_S32_LE : SND_PCM_SFMT_S16_LE);
+
+ /*will check this further down -just try for now*/
+ params.format.rate = rate;
+ params.format.voices = voices;
+ params.start_mode = SND_PCM_START_GO; /* seems most reliable */
+ /*do not stop at overrun/underrun*/
+ params.stop_mode = SND_PCM_STOP_ROLLOVER;
+
+ params.channel = dir; /* playback|capture */
+ params.buf.stream.queue_size =
+ (ALSA_EXTRABUFFER + linux_advance_samples)
+ * alsa_samplewidth * voices;
+ params.buf.stream.fill = SND_PCM_FILL_SILENCE_WHOLE;
+ params.mode = SND_PCM_MODE_STREAM;
+
+ if ((err = snd_pcm_channel_params(dev->handle, &params)) < 0)
+ {
+ printf("PD-ALSA: error setting parameters %s", snd_strerror(err));
+ }
+
+ /* This should clear the buffers but does not. There is often noise at
+ startup that sounds like crap left in the buffers - maybe in the lib
+ instead of the driver? Some solution needs to be found.
+ */
+
+ if ((err = snd_pcm_channel_prepare(dev->handle, dir)) < 0)
+ {
+ printf("PD-ALSA: error preparing channel %s", snd_strerror(err));
+ }
+ dev->setup.channel = dir;
+
+ if ((err = snd_pcm_channel_setup(dev->handle, &dev->setup)) < 0)
+ {
+ printf("PD-ALSA: error getting setup %s", snd_strerror(err));
+ }
+ /* for some reason, if you don't writesomething before starting the
+ converters we get trash on startup */
+ if (dir == SND_PCM_CHANNEL_PLAYBACK)
+ {
+ char foo[1024];
+ int xxx = 1024 - (1024 % (linux_outchannels * alsa_samplewidth));
+ int i, r;
+ for (i = 0; i < xxx; i++)
+ foo[i] = 0;
+ if ((r = snd_pcm_write(dev->handle, foo, xxx)) < xxx)
+ fprintf(stderr, "alsa_write: %s\n", snd_strerror(errno));
+ }
+ snd_pcm_channel_go(dev->handle, dir);
+}
+
+void alsa_close_audio(void)
+{
+ int i;
+ for(i = 0; i < n_alsa_dev; i++)
+ snd_pcm_close(alsa_device[i].handle);
+}
+
+/* #define DEBUG_ALSA_XFER */
+
+int alsa_send_dacs(void)
+{
+ static int16_t *sp;
+ t_sample *fp, *fp1, *fp2;
+ int i, j, k, err, devno = 0;
+ int inputcount = 0, outputcount = 0, inputlate = 0, outputlate = 0;
+ int result;
+ snd_pcm_channel_status_t stat;
+ static int callno = 0;
+ static int xferno = 0;
+ int countwas = 0;
+ double timelast;
+ static double timenow;
+ int inchannels = linux_inchannels;
+ int outchannels = linux_outchannels;
+ int inbytesperframe = inchannels * alsa_samplewidth;
+ int outbytesperframe = outchannels * alsa_samplewidth;
+ int intransfersize = DACBLKSIZE * inbytesperframe;
+ int outtransfersize = DACBLKSIZE * outbytesperframe;
+ int alsaerror;
+ int loggederror = 0;
+
+ if (!inchannels && !outchannels)
+ return (SENDDACS_NO);
+ timelast = timenow;
+ timenow = sys_getrealtime();
+
+#ifdef DEBUG_ALSA_XFER
+ if (timenow - timelast > 0.050)
+ fprintf(stderr, "(%d)",
+ (int)(1000 * (timenow - timelast))), fflush(stderr);
+#endif
+
+ callno++;
+ /* get input and output channel status */
+ if (inchannels > 0)
+ {
+ devno = 0;
+ stat.channel = SND_PCM_CHANNEL_CAPTURE;
+ if (alsaerror = snd_pcm_channel_status(alsa_device[devno].handle,
+ &stat))
+ {
+ fprintf(stderr, "snd_pcm_channel_status (input): %s\n",
+ snd_strerror(alsaerror));
+ return (SENDDACS_NO);
+ }
+ inputcount = stat.count;
+ inputlate = (stat.underrun > 0 || stat.overrun > 0);
+ }
+ if (outchannels > 0)
+ {
+ devno = 0;
+ stat.channel = SND_PCM_CHANNEL_PLAYBACK;
+ if (alsaerror = snd_pcm_channel_status(alsa_device[devno].handle,
+ &stat))
+ {
+ fprintf(stderr, "snd_pcm_channel_status (output): %s\n",
+ snd_strerror(alsaerror));
+ return (SENDDACS_NO);
+ }
+ outputcount = stat.count;
+ outputlate = (stat.underrun > 0 || stat.overrun > 0);
+ }
+
+ /* check if input not ready */
+ if (inputcount < intransfersize)
+ {
+ /* fprintf(stderr, "no adc; count %d, free %d, call %d, xfer %d\n",
+ stat.count,
+ stat.free,
+ callno, xferno); */
+ if (outchannels > 0)
+ {
+ /* if there's no input but output is hungry, feed output. */
+ while (outputcount < (linux_advance_samples + ALSA_JITTER)
+ * outbytesperframe)
+ {
+ if (!loggederror)
+ sys_log_error(ERR_RESYNC), loggederror = 1;
+ memset(alsa_buf, 0, outtransfersize);
+ result = snd_pcm_write(alsa_device[devno].handle,
+ alsa_buf, outtransfersize);
+ if (result < outtransfersize)
+ {
+#ifdef DEBUG_ALSA_XFER
+ if (result >= 0 || errno == EAGAIN)
+ fprintf(stderr, "ALSA: write returned %d of %d\n",
+ result, outtransfersize);
+ else fprintf(stderr, "ALSA: write: %s\n",
+ snd_strerror(errno));
+ fprintf(stderr,
+ "inputcount %d, outputcount %d, outbufsize %d\n",
+ inputcount, outputcount,
+ (ALSA_EXTRABUFFER + linux_advance_samples)
+ * alsa_samplewidth * outchannels);
+#endif
+ return (SENDDACS_NO);
+ }
+ stat.channel = SND_PCM_CHANNEL_PLAYBACK;
+ if (alsaerror =
+ snd_pcm_channel_status(alsa_device[devno].handle,
+ &stat))
+ {
+ fprintf(stderr, "snd_pcm_channel_status (output): %s\n",
+ snd_strerror(alsaerror));
+ return (SENDDACS_NO);
+ }
+ outputcount = stat.count;
+ }
+ }
+
+ return SENDDACS_NO;
+ }
+
+ /* if output buffer has at least linux_advance_samples in it, we're
+ not ready for this batch. */
+ if (outputcount > linux_advance_samples * outbytesperframe)
+ {
+ if (inchannels > 0)
+ {
+ while (inputcount > (DACBLKSIZE + ALSA_JITTER) * outbytesperframe)
+ {
+ if (!loggederror)
+ sys_log_error(ERR_RESYNC), loggederror = 1;
+ devno = 0;
+ result = snd_pcm_read(alsa_device[devno].handle, alsa_buf,
+ intransfersize);
+ if (result < intransfersize)
+ {
+#ifdef DEBUG_ALSA_XFER
+ if (result < 0)
+ fprintf(stderr,
+ "snd_pcm_read %d %d: %s\n",
+ callno, xferno, snd_strerror(errno));
+ else fprintf(stderr,
+ "snd_pcm_read %d %d returned only %d\n",
+ callno, xferno, result);
+ fprintf(stderr,
+ "inputcount %d, outputcount %d, inbufsize %d\n",
+ inputcount, outputcount,
+ (ALSA_EXTRABUFFER + linux_advance_samples)
+ * alsa_samplewidth * inchannels);
+#endif
+ return (SENDDACS_NO);
+ }
+ devno = 0;
+ stat.channel = SND_PCM_CHANNEL_CAPTURE;
+ if (alsaerror =
+ snd_pcm_channel_status(alsa_device[devno].handle,
+ &stat))
+ {
+ fprintf(stderr, "snd_pcm_channel_status (input): %s\n",
+ snd_strerror(alsaerror));
+ return (SENDDACS_NO);
+ }
+ inputcount = stat.count;
+ inputlate = (stat.underrun > 0 || stat.overrun > 0);
+ }
+ return (SENDDACS_NO);
+ }
+ }
+ if (sys_getrealtime() - timenow > 0.002)
+ {
+#ifdef DEBUG_ALSA_XFER
+ fprintf(stderr, "check %d took %d msec\n",
+ callno, (int)(1000 * (timenow - timelast))), fflush(stderr);
+#endif
+ sys_log_error(ERR_DACSLEPT);
+ timenow = sys_getrealtime();
+ }
+ if (inputlate || outputlate)
+ sys_log_error(ERR_DATALATE);
+
+ /* do output */
+ /* this "for" loop won't work for more than one device. */
+ for (devno = 0, fp = sys_soundout; devno < (outchannels > 0); devno++,
+ fp += 128)
+ {
+ if (alsa_samplewidth == 4)
+ {
+ for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DACBLKSIZE)
+ {
+ for (j = i, k = DACBLKSIZE, fp2 = fp1; k--;
+ j += outchannels, fp2++)
+ {
+ float s1 = *fp2 * INT32_MAX;
+ ((t_alsa_sample32 *)alsa_buf)[j] = CLIP32(s1);
+ }
+ }
+ }
+ else
+ {
+ for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DACBLKSIZE)
+ {
+ for (j = i, k = DACBLKSIZE, fp2 = fp1; k--;
+ j += outchannels, fp2++)
+ {
+ int s = *fp2 * 32767.;
+ if (s > 32767)
+ s = 32767;
+ else if (s < -32767)
+ s = -32767;
+ ((t_alsa_sample16 *)alsa_buf)[j] = s;
+ }
+ }
+ }
+
+ result = snd_pcm_write(alsa_device[devno].handle, alsa_buf,
+ outtransfersize);
+ if (result < outtransfersize)
+ {
+#ifdef DEBUG_ALSA_XFER
+ if (result >= 0 || errno == EAGAIN)
+ fprintf(stderr, "ALSA: write returned %d of %d\n",
+ result, outtransfersize);
+ else fprintf(stderr, "ALSA: write: %s\n",
+ snd_strerror(errno));
+ fprintf(stderr,
+ "inputcount %d, outputcount %d, outbufsize %d\n",
+ inputcount, outputcount,
+ (ALSA_EXTRABUFFER + linux_advance_samples)
+ * alsa_samplewidth * outchannels);
+#endif
+ sys_log_error(ERR_DACSLEPT);
+ return (SENDDACS_NO);
+ }
+ }
+ /* zero out the output buffer */
+ memset(sys_soundout, 0, DACBLKSIZE * sizeof(*sys_soundout) *
+ linux_outchannels);
+ if (sys_getrealtime() - timenow > 0.002)
+ {
+#if DEBUG_ALSA_XFER
+ fprintf(stderr, "output %d took %d msec\n",
+ callno, (int)(1000 * (timenow - timelast))), fflush(stderr);
+#endif
+ timenow = sys_getrealtime();
+ sys_log_error(ERR_DACSLEPT);
+ }
+
+ /* do input */
+ for (devno = 0, fp = sys_soundin; devno < (linux_inchannels > 0); devno++,
+ fp += 128)
+ {
+ result = snd_pcm_read(alsa_device[devno].handle, alsa_buf,
+ intransfersize);
+ if (result < intransfersize)
+ {
+#ifdef DEBUG_ALSA_XFER
+ if (result < 0)
+ fprintf(stderr,
+ "snd_pcm_read %d %d: %s\n",
+ callno, xferno, snd_strerror(errno));
+ else fprintf(stderr,
+ "snd_pcm_read %d %d returned only %d\n",
+ callno, xferno, result);
+ fprintf(stderr,
+ "inputcount %d, outputcount %d, inbufsize %d\n",
+ inputcount, outputcount,
+ (ALSA_EXTRABUFFER + linux_advance_samples)
+ * alsa_samplewidth * inchannels);
+#endif
+ sys_log_error(ERR_ADCSLEPT);
+ return (SENDDACS_NO);
+ }
+ if (alsa_samplewidth == 4)
+ {
+ for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DACBLKSIZE)
+ {
+ for (j = i, k = DACBLKSIZE, fp2 = fp1; k--;
+ j += inchannels, fp2++)
+ *fp2 = (float) ((t_alsa_sample32 *)alsa_buf)[j]
+ * (1./ INT32_MAX);
+ }
+ }
+ else
+ {
+ for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DACBLKSIZE)
+ {
+ for (j = i, k = DACBLKSIZE, fp2 = fp1; k--; j += inchannels, fp2++)
+ *fp2 = (float) ((t_alsa_sample16 *)alsa_buf)[j]
+ * 3.051850e-05;
+ }
+ }
+ }
+ xferno++;
+ if (sys_getrealtime() - timenow > 0.002)
+ {
+#ifdef DEBUG_ALSA_XFER
+ fprintf(stderr, "routine took %d msec\n",
+ (int)(1000 * (sys_getrealtime() - timenow)));
+#endif
+ sys_log_error(ERR_ADCSLEPT);
+ }
+ return SENDDACS_YES;
+}
+
+#endif /* ALSA99 */
+
+/* support for ALSA pcmv2 api by Karl MacMillan<karlmac@peabody.jhu.edu> */
+
+#ifdef ALSA01
+
+static void check_error(int err, const char *why)
+{
+ if (err < 0)
+ fprintf(stderr, "%s: %s\n", why, snd_strerror(err));
+}
+
+static int alsa_open_audio(int wantinchans, int wantoutchans, int srate)
+{
+ int err, inchans = 0, outchans = 0, subunitdir;
+ char devname[512];
+ snd_pcm_hw_params_t* hw_params;
+ snd_pcm_sw_params_t* sw_params;
+ snd_output_t* out;
+ int frag_size = (linux_fragsize ? linux_fragsize : ALSA_DEFFRAGSIZE);
+ int nfrags, i;
+ short* tmp_buf;
+ unsigned int tmp_uint;
+ int advwas = sys_schedadvance;
+
+ if (linux_nfragment)
+ {
+ nfrags = linux_nfragment;
+ sys_schedadvance = (frag_size * linux_nfragment * 1.0e6) / srate;
+ }
+ else nfrags = sys_schedadvance * (float)srate / (1e6 * frag_size);
+
+ if (sys_verbose || (sys_schedadvance != advwas))
+ post("audio buffer set to %d", (int)(0.001 * sys_schedadvance));
+ if (wantinchans || wantoutchans)
+ alsa_checkversion();
+ if (wantinchans)
+ {
+ err = snd_pcm_open(&alsa_device.inhandle, alsa_devname,
+ SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
+
+ check_error(err, "snd_pcm_open (input)");
+ if (err < 0)
+ inchans = 0;
+ else
+ {
+ inchans = wantinchans;
+ snd_pcm_nonblock(alsa_device.inhandle, 1);
+ }
+ }
+ if (wantoutchans)
+ {
+ err = snd_pcm_open(&alsa_device.outhandle, alsa_devname,
+ SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
+
+ check_error(err, "snd_pcm_open (output)");
+ if (err < 0)
+ outchans = 0;
+ else
+ {
+ outchans = wantoutchans;
+ snd_pcm_nonblock(alsa_device.outhandle, 1);
+ }
+ }
+ if (inchans)
+ {
+ if (sys_verbose)
+ post("opening sound input...");
+ err = snd_pcm_hw_params_malloc(&hw_params);
+ check_error(err, "snd_pcm_hw_params_malloc (input)");
+
+ // get the default params
+ err = snd_pcm_hw_params_any(alsa_device.inhandle, hw_params);
+ check_error(err, "snd_pcm_hw_params_any (input)");
+ // set interleaved access - FIXME deal with other access types
+ err = snd_pcm_hw_params_set_access(alsa_device.inhandle, hw_params,
+ SND_PCM_ACCESS_RW_INTERLEAVED);
+ check_error(err, "snd_pcm_hw_params_set_access (input)");
+ // Try to set 32 bit format first
+ err = snd_pcm_hw_params_set_format(alsa_device.inhandle, hw_params,
+ SND_PCM_FORMAT_S32);
+ if (err < 0)
+ {
+ /* fprintf(stderr,
+ "PD-ALSA: 32 bit format not available - using 16\n"); */
+ err = snd_pcm_hw_params_set_format(alsa_device.inhandle, hw_params,
+ SND_PCM_FORMAT_S16);
+ check_error(err, "snd_pcm_hw_params_set_format (input)");
+ alsa_samplewidth = 2;
+ }
+ else
+ {
+ alsa_samplewidth = 4;
+ }
+ post("Sample width set to %d bytes", alsa_samplewidth);
+ // set the subformat
+ err = snd_pcm_hw_params_set_subformat(alsa_device.inhandle, hw_params,
+ SND_PCM_SUBFORMAT_STD);
+ check_error(err, "snd_pcm_hw_params_set_subformat (input)");
+ // set the number of channels
+ tmp_uint = inchans;
+ err = snd_pcm_hw_params_set_channels_min(alsa_device.inhandle,
+ hw_params, &tmp_uint);
+ check_error(err, "snd_pcm_hw_params_set_channels (input)");
+ if (tmp_uint != (unsigned)inchans)
+ post("ALSA: set input channels to %d", tmp_uint);
+ inchans = tmp_uint;
+ // set the sampling rate
+ err = snd_pcm_hw_params_set_rate_min(alsa_device.inhandle, hw_params,
+ &srate, 0);
+ check_error(err, "snd_pcm_hw_params_set_rate_min (input)");
+#if 0
+ err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir);
+ post("input sample rate %d", err);
+#endif
+ // set the period - ie frag size
+ // post("fragsize a %d", frag_size);
+
+ /* LATER try this to get a recommended period size...
+ right now, it trips an assertion failure in ALSA lib */
+#if 0
+ post("input period was %d, min %d, max %d\n",
+ snd_pcm_hw_params_get_period_size(hw_params, 0),
+ snd_pcm_hw_params_get_period_size_min(hw_params, 0),
+ snd_pcm_hw_params_get_period_size_max(hw_params, 0));
+#endif
+ err = snd_pcm_hw_params_set_period_size_near(alsa_device.inhandle,
+ hw_params,
+ (snd_pcm_uframes_t)
+ frag_size, 0);
+ check_error(err, "snd_pcm_hw_params_set_period_size_near (input)");
+ // post("fragsize b %d", frag_size);
+ // set the number of periods - ie numfrags
+ // post("nfrags a %d", nfrags);
+ err = snd_pcm_hw_params_set_periods_near(alsa_device.inhandle,
+ hw_params, nfrags, 0);
+ check_error(err, "snd_pcm_hw_params_set_periods_near (input)");
+ // set the buffer size
+ err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.inhandle,
+ hw_params, nfrags * frag_size);
+ check_error(err, "snd_pcm_hw_params_set_buffer_size_near (input)");
+
+ err = snd_pcm_hw_params(alsa_device.inhandle, hw_params);
+ check_error(err, "snd_pcm_hw_params (input)");
+
+ snd_pcm_hw_params_free(hw_params);
+
+ err = snd_pcm_sw_params_malloc(&sw_params);
+ check_error(err, "snd_pcm_sw_params_malloc (input)");
+ err = snd_pcm_sw_params_current(alsa_device.inhandle, sw_params);
+ check_error(err, "snd_pcm_sw_params_current (input)");
+#if 1
+ err = snd_pcm_sw_params_set_start_mode(alsa_device.inhandle, sw_params,
+ SND_PCM_START_EXPLICIT);
+ check_error(err, "snd_pcm_sw_params_set_start_mode (input)");
+ err = snd_pcm_sw_params_set_xrun_mode(alsa_device.inhandle, sw_params,
+ SND_PCM_XRUN_NONE);
+ check_error(err, "snd_pcm_sw_params_set_xrun_mode (input)");
+#else
+ err = snd_pcm_sw_params_set_start_threshold(alsa_device.inhandle,
+ sw_params, nfrags * frag_size);
+ check_error(err, "snd_pcm_sw_params_set_start_threshold (input)");
+ err = snd_pcm_sw_params_set_stop_threshold(alsa_device.inhandle,
+ sw_params, 1);
+ check_error(err, "snd_pcm_sw_params_set_stop_threshold (input)");
+#endif
+
+ err = snd_pcm_sw_params_set_avail_min(alsa_device.inhandle, sw_params,
+ frag_size);
+ check_error(err, "snd_pcm_sw_params_set_avail_min (input)");
+ err = snd_pcm_sw_params(alsa_device.inhandle, sw_params);
+ check_error(err, "snd_pcm_sw_params (input)");
+
+ snd_pcm_sw_params_free(sw_params);
+
+ snd_output_stdio_attach(&out, stderr, 0);
+#if 0
+ if (sys_verbose)
+ {
+ snd_pcm_dump_hw_setup(alsa_device.inhandle, out);
+ snd_pcm_dump_sw_setup(alsa_device.inhandle, out);
+ }
+#endif
+ }
+
+ if (outchans)
+ {
+ int foo;
+ if (sys_verbose)
+ post("opening sound output...");
+ err = snd_pcm_hw_params_malloc(&hw_params);
+ check_error(err, "snd_pcm_sw_params (output)");
+
+ // get the default params
+ err = snd_pcm_hw_params_any(alsa_device.outhandle, hw_params);
+ check_error(err, "snd_pcm_hw_params_any (output)");
+ // set interleaved access - FIXME deal with other access types
+ err = snd_pcm_hw_params_set_access(alsa_device.outhandle, hw_params,
+ SND_PCM_ACCESS_RW_INTERLEAVED);
+ check_error(err, "snd_pcm_hw_params_set_access (output)");
+ // Try to set 32 bit format first
+ err = snd_pcm_hw_params_set_format(alsa_device.outhandle, hw_params,
+ SND_PCM_FORMAT_S32);
+ if (err < 0)
+ {
+ err = snd_pcm_hw_params_set_format(alsa_device.outhandle,
+ hw_params,SND_PCM_FORMAT_S16);
+ check_error(err, "snd_pcm_hw_params_set_format (output)");
+ /* fprintf(stderr,
+ "PD-ALSA: 32 bit format not available - using 16\n"); */
+ alsa_samplewidth = 2;
+ }
+ else
+ {
+ alsa_samplewidth = 4;
+ }
+ // set the subformat
+ err = snd_pcm_hw_params_set_subformat(alsa_device.outhandle, hw_params,
+ SND_PCM_SUBFORMAT_STD);
+ check_error(err, "snd_pcm_hw_params_set_subformat (output)");
+ // set the number of channels
+ tmp_uint = outchans;
+ err = snd_pcm_hw_params_set_channels_min(alsa_device.outhandle,
+ hw_params, &tmp_uint);
+ check_error(err, "snd_pcm_hw_params_set_channels (output)");
+ if (tmp_uint != (unsigned)outchans)
+ post("alsa: set output channels to %d", tmp_uint);
+ outchans = tmp_uint;
+ // set the sampling rate
+ err = snd_pcm_hw_params_set_rate_min(alsa_device.outhandle, hw_params,
+ &srate, 0);
+ check_error(err, "snd_pcm_hw_params_set_rate_min (output)");
+#if 0
+ err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir);
+ post("output sample rate %d", err);
+#endif
+ // set the period - ie frag size
+#if 0
+ post("output period was %d, min %d, max %d\n",
+ snd_pcm_hw_params_get_period_size(hw_params, 0),
+ snd_pcm_hw_params_get_period_size_min(hw_params, 0),
+ snd_pcm_hw_params_get_period_size_max(hw_params, 0));
+#endif
+ // post("fragsize c %d", frag_size);
+ err = snd_pcm_hw_params_set_period_size_near(alsa_device.outhandle,
+ hw_params,
+ (snd_pcm_uframes_t)
+ frag_size, 0);
+ // post("fragsize d %d", frag_size);
+ check_error(err, "snd_pcm_hw_params_set_period_size_near (output)");
+ // set the number of periods - ie numfrags
+ err = snd_pcm_hw_params_set_periods_near(alsa_device.outhandle,
+ hw_params, nfrags, 0);
+ check_error(err, "snd_pcm_hw_params_set_periods_near (output)");
+ // set the buffer size
+ err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.outhandle,
+ hw_params, nfrags * frag_size);
+
+ check_error(err, "snd_pcm_hw_params_set_buffer_size_near (output)");
+
+ err = snd_pcm_hw_params(alsa_device.outhandle, hw_params);
+ check_error(err, "snd_pcm_hw_params (output)");
+
+ snd_pcm_hw_params_free(hw_params);
+
+ err = snd_pcm_sw_params_malloc(&sw_params);
+ check_error(err, "snd_pcm_sw_params_malloc (output)");
+ err = snd_pcm_sw_params_current(alsa_device.outhandle, sw_params);
+ check_error(err, "snd_pcm_sw_params_current (output)");
+#if 1
+ err = snd_pcm_sw_params_set_start_mode(alsa_device.outhandle,
+ sw_params,
+ SND_PCM_START_EXPLICIT);
+ check_error(err, "snd_pcm_sw_params_set_start_mode (output)");
+ err = snd_pcm_sw_params_set_xrun_mode(alsa_device.outhandle, sw_params,
+ SND_PCM_XRUN_NONE);
+ check_error(err, "snd_pcm_sw_params_set_xrun_mode (output)");
+#else
+ err = snd_pcm_sw_params_set_start_threshold(alsa_device.inhandle,
+ sw_params, nfrags * frag_size);
+ check_error(err, "snd_pcm_sw_params_set_start_threshold (output)");
+ err = snd_pcm_sw_params_set_stop_threshold(alsa_device.inhandle,
+ sw_params, 1);
+ check_error(err, "snd_pcm_sw_params_set_stop_threshold (output)");
+#endif
+
+ err = snd_pcm_sw_params_set_avail_min(alsa_device.outhandle, sw_params,
+ frag_size);
+ check_error(err, "snd_pcm_sw_params_set_avail_min (output)");
+ err = snd_pcm_sw_params(alsa_device.outhandle, sw_params);
+ check_error(err, "snd_pcm_sw_params (output)");
+
+ snd_pcm_sw_params_free(sw_params);
+
+ snd_output_stdio_attach(&out, stderr, 0);
+#if 0
+ if (sys_verbose)
+ {
+ snd_pcm_dump_hw_setup(alsa_device.outhandle, out);
+ snd_pcm_dump_sw_setup(alsa_device.outhandle, out);
+ }
+#endif
+ }
+
+ linux_setsr(srate);
+ linux_setch(inchans, outchans);
+
+ if (inchans)
+ snd_pcm_prepare(alsa_device.inhandle);
+ if (outchans)
+ snd_pcm_prepare(alsa_device.outhandle);
+
+ // if duplex we can link the channels so they start together
+ if (inchans && outchans)
+ snd_pcm_link(alsa_device.inhandle, alsa_device.outhandle);
+
+ // set up the buffer
+ if (outchans > inchans)
+ alsa_buf = (short *)calloc(sizeof(char) * alsa_samplewidth, DACBLKSIZE
+ * outchans);
+ else
+ alsa_buf = (short *)calloc(sizeof(char) * alsa_samplewidth, DACBLKSIZE
+ * inchans);
+ // fill the buffer with silence
+ if (outchans)
+ {
+ i = nfrags + 1;
+ while (i--)
+ snd_pcm_writei(alsa_device.outhandle, alsa_buf, frag_size);
+ }
+
+ // set up the status variables
+ err = snd_pcm_status_malloc(&in_status);
+ check_error(err, "snd_pcm_status_malloc");
+ err = snd_pcm_status_malloc(&out_status);
+ check_error(err, "snd_pcm_status_malloc");
+
+ // start the device
+#if 1
+ if (outchans)
+ {
+ err = snd_pcm_start(alsa_device.outhandle);
+ check_error(err, "snd_pcm_start");
+ }
+ else if (inchans)
+ {
+ err = snd_pcm_start(alsa_device.inhandle);
+ check_error(err, "snd_pcm_start");
+ }
+#endif
+
+ return 0;
+}
+
+void alsa_close_audio(void)
+{
+ int err;
+ if (linux_inchannels)
+ {
+ err = snd_pcm_close(alsa_device.inhandle);
+ check_error(err, "snd_pcm_close (input)");
+ }
+ if (linux_outchannels)
+ {
+ err = snd_pcm_close(alsa_device.outhandle);
+ check_error(err, "snd_pcm_close (output)");
+ }
+}
+
+// #define DEBUG_ALSA_XFER
+
+int alsa_send_dacs(void)
+{
+ static int16_t *sp;
+ static int xferno = 0;
+ static int callno = 0;
+ static double timenow;
+ double timelast;
+ t_sample *fp, *fp1, *fp2;
+ int i, j, k, err, devno = 0;
+ int inputcount = 0, outputcount = 0, inputlate = 0, outputlate = 0;
+ int result;
+ int inchannels = linux_inchannels;
+ int outchannels = linux_outchannels;
+ unsigned int intransfersize = DACBLKSIZE;
+ unsigned int outtransfersize = DACBLKSIZE;
+
+ // get the status
+ if (!inchannels && !outchannels)
+ {
+ return SENDDACS_NO;
+ }
+
+ timelast = timenow;
+ timenow = sys_getrealtime();
+
+#ifdef DEBUG_ALSA_XFER
+ if (timenow - timelast > 0.050)
+ fprintf(stderr, "(%d)",
+ (int)(1000 * (timenow - timelast))), fflush(stderr);
+#endif
+
+ callno++;
+
+ if (inchannels)
+ {
+ snd_pcm_status(alsa_device.inhandle, in_status);
+ if (snd_pcm_status_get_avail(in_status) < intransfersize)
+ return SENDDACS_NO;
+ }
+ if (outchannels)
+ {
+ snd_pcm_status(alsa_device.outhandle, out_status);
+ if (snd_pcm_status_get_avail(out_status) < outtransfersize)
+ return SENDDACS_NO;
+ }
+
+ /* do output */
+ if (outchannels)
+ {
+ fp = sys_soundout;
+ if (alsa_samplewidth == 4)
+ {
+ for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DACBLKSIZE)
+ {
+ for (j = i, k = DACBLKSIZE, fp2 = fp1; k--;
+ j += outchannels, fp2++)
+ {
+ float s1 = *fp2 * INT32_MAX;
+ ((t_alsa_sample32 *)alsa_buf)[j] = CLIP32(s1);
+ }
+ }
+ }
+ else
+ {
+ for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DACBLKSIZE)
+ {
+ for (j = i, k = DACBLKSIZE, fp2 = fp1; k--;
+ j += outchannels, fp2++)
+ {
+ int s = *fp2 * 32767.;
+ if (s > 32767)
+ s = 32767;
+ else if (s < -32767)
+ s = -32767;
+ ((t_alsa_sample16 *)alsa_buf)[j] = s;
+ }
+ }
+ }
+
+ result = snd_pcm_writei(alsa_device.outhandle, alsa_buf,
+ outtransfersize);
+ if (result != (int)outtransfersize)
+ {
+ #ifdef DEBUG_ALSA_XFER
+ if (result >= 0 || errno == EAGAIN)
+ fprintf(stderr, "ALSA: write returned %d of %d\n",
+ result, outtransfersize);
+ else fprintf(stderr, "ALSA: write: %s\n",
+ snd_strerror(errno));
+ fprintf(stderr,
+ "inputcount %d, outputcount %d, outbufsize %d\n",
+ inputcount, outputcount,
+ (ALSA_EXTRABUFFER + linux_advance_samples)
+ * alsa_samplewidth * outchannels);
+ #endif
+ sys_log_error(ERR_DACSLEPT);
+ return (SENDDACS_NO);
+ }
+
+ /* zero out the output buffer */
+ memset(sys_soundout, 0, DACBLKSIZE * sizeof(*sys_soundout) *
+ linux_outchannels);
+ if (sys_getrealtime() - timenow > 0.002)
+ {
+ #ifdef DEBUG_ALSA_XFER
+ fprintf(stderr, "output %d took %d msec\n",
+ callno, (int)(1000 * (timenow - timelast))), fflush(stderr);
+ #endif
+ timenow = sys_getrealtime();
+ sys_log_error(ERR_DACSLEPT);
+ }
+ }
+ /* do input */
+ if (linux_inchannels)
+ {
+ result = snd_pcm_readi(alsa_device.inhandle, alsa_buf, intransfersize);
+ if (result < (int)intransfersize)
+ {
+#ifdef DEBUG_ALSA_XFER
+ if (result < 0)
+ fprintf(stderr,
+ "snd_pcm_read %d %d: %s\n",
+ callno, xferno, snd_strerror(errno));
+ else fprintf(stderr,
+ "snd_pcm_read %d %d returned only %d\n",
+ callno, xferno, result);
+ fprintf(stderr,
+ "inputcount %d, outputcount %d, inbufsize %d\n",
+ inputcount, outputcount,
+ (ALSA_EXTRABUFFER + linux_advance_samples)
+ * alsa_samplewidth * inchannels);
+#endif
+ sys_log_error(ERR_ADCSLEPT);
+ return (SENDDACS_NO);
+ }
+ fp = sys_soundin;
+ if (alsa_samplewidth == 4)
+ {
+ for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DACBLKSIZE)
+ {
+ for (j = i, k = DACBLKSIZE, fp2 = fp1; k--;
+ j += inchannels, fp2++)
+ *fp2 = (float) ((t_alsa_sample32 *)alsa_buf)[j]
+ * (1./ INT32_MAX);
+ }
+ }
+ else
+ {
+ for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DACBLKSIZE)
+ {
+ for (j = i, k = DACBLKSIZE, fp2 = fp1; k--; j += inchannels,
+ fp2++)
+ *fp2 = (float) ((t_alsa_sample16 *)alsa_buf)[j]
+ * 3.051850e-05;
+ }
+ }
+ }
+ xferno++;
+ if (sys_getrealtime() - timenow > 0.002)
+ {
+#ifdef DEBUG_ALSA_XFER
+ fprintf(stderr, "routine took %d msec\n",
+ (int)(1000 * (sys_getrealtime() - timenow)));
+#endif
+ sys_log_error(ERR_ADCSLEPT);
+ }
+ return SENDDACS_YES;
+}
+
+void alsa_resync( void)
+{
+ int i, result;
+ if (linux_whichapi != API_ALSA)
+ {
+ error("restart-audio: implemented for ALSA only.");
+ return;
+ }
+ memset(alsa_buf, 0,
+ sizeof(char) * alsa_samplewidth * DACBLKSIZE * linux_outchannels);
+ for (i = 0; i < 100; i++)
+ {
+ result = snd_pcm_writei(alsa_device.outhandle, alsa_buf,
+ DACBLKSIZE);
+ if (result != (int)DACBLKSIZE)
+ break;
+ }
+ post("%d written", i);
+}
+
+
+#endif /* ALSA01 */
+
+/***************************************************
+ * Code using the RME_9652 API
+ */
+
+ /*
+ trying native device for future use of native memory map:
+ because of busmaster if you dont use the dac, you dont need
+ CPU Power und also no nearly no CPU-Power is used in device
+
+ since always all DAs and ADs are synced (else they wouldnt work)
+ we use linux_dacs[0], linux_adcs[0]
+ */
+
+#ifdef RME_HAMMERFALL
+
+#define RME9652_MAX_CHANNELS 26
+
+#define RME9652_CH_PER_NATIVE_DEVICE 1
+
+static int rme9652_dac_devices[RME9652_MAX_CHANNELS];
+static int rme9652_adc_devices[RME9652_MAX_CHANNELS];
+
+static char rme9652_dsp_dac[] = "/dev/rme9652/C0da%d";
+static char rme9652_dsp_adc[] = "/dev/rme9652/C0ad%d";
+
+static int num_of_rme9652_dac = 0;
+static int num_of_rme9652_adc = 0;
+
+static int rme_soundindevonset = 1;
+static int rme_soundoutdevonset = 1;
+
+void rme_soundindev(int which)
+{
+ rme_soundindevonset = which;
+}
+
+void rme_soundoutdev(int which)
+{
+ rme_soundoutdevonset = which;
+}
+
+void rme9652_configure(int dev, int fd,int srate, int dac) {
+ int orig, param, nblk;
+ audio_buf_info ainfo;
+ orig = param = srate;
+
+ /* samplerate */
+
+ fprintf(stderr,"RME9652: configuring %d, fd=%d, sr=%d\n, dac=%d\n",
+ dev,fd,srate,dac);
+
+ if (ioctl(fd,SNDCTL_DSP_SPEED,&param) == -1)
+ fprintf(stderr,"RME9652: Could not set sampling rate for device\n");
+ else if( orig != param )
+ fprintf(stderr,"RME9652: sampling rate: wanted %d, got %d\n",
+ orig, param );
+
+ // setting the correct samplerate (could be different than expected)
+ srate = param;
+
+
+ /* setting resolution */
+
+ /* use ctrlpanel to change, experiment, channels 1 */
+
+ orig = param = AFMT_S16_NE;
+ if (ioctl(fd,SNDCTL_DSP_SETFMT,&param) == -1)
+ fprintf(stderr,"RME9652: Could not set DSP format\n");
+ else if( orig != param )
+ fprintf(stderr,"RME9652: DSP format: wanted %d, got %d\n",orig, param );
+
+ /* setting channels */
+ orig = param = RME9652_CH_PER_NATIVE_DEVICE;
+
+ if (ioctl(fd,SNDCTL_DSP_CHANNELS,&param) == -1)
+ fprintf(stderr,"RME9652: Could not set channels\n");
+ else if( orig != param )
+ fprintf(stderr,"RME9652: num channels: wanted %d, got %d\n",orig, param );
+
+ if (dac)
+ {
+
+ /* use "free space" to learn the buffer size. Normally you
+ should set this to your own desired value; but this seems not
+ to be implemented uniformly across different sound cards. LATER
+ we should figure out what to do if the requested scheduler advance
+ is greater than this buffer size; for now, we just print something
+ out. */
+
+ if( ioctl(linux_dacs[0].d_fd, SOUND_PCM_GETOSPACE,&ainfo) < 0 )
+ fprintf(stderr,"RME: ioctl on output device %d failed",dev);
+
+ linux_dacs[0].d_bufsize = ainfo.bytes;
+
+ fprintf(stderr,"RME: ioctl SOUND_PCM_GETOSPACE says %d buffsize\n",
+ linux_dacs[0].d_bufsize);
+
+
+ if (linux_advance_samples * (RME_SAMPLEWIDTH *
+ RME9652_CH_PER_NATIVE_DEVICE)
+ > linux_dacs[0].d_bufsize - RME_BYTESPERCHAN)
+ {
+ fprintf(stderr,
+ "RME: requested audio buffer size %d limited to %d\n",
+ linux_advance_samples
+ * (RME_SAMPLEWIDTH * RME9652_CH_PER_NATIVE_DEVICE),
+ linux_dacs[0].d_bufsize);
+ linux_advance_samples =
+ (linux_dacs[0].d_bufsize - RME_BYTESPERCHAN)
+ / (RME_SAMPLEWIDTH *RME9652_CH_PER_NATIVE_DEVICE);
+ }
+ }
+}
+
+
+int rme9652_open_audio(int inchans, int outchans,int srate)
+{
+ int orig;
+ int tmp;
+ int inchannels = 0,outchannels = 0;
+ char devname[20];
+ int i;
+ char buf[RME_SAMPLEWIDTH*RME9652_CH_PER_NATIVE_DEVICE*DACBLKSIZE];
+ int num_devs = 0;
+ audio_buf_info ainfo;
+
+ linux_nindevs = linux_noutdevs = 0;
+
+ if (sys_verbose)
+ post("RME open");
+ /* First check if we can */
+ /* open the write ports */
+
+ for (num_devs=0; outchannels < outchans; num_devs++)
+ {
+ int channels = RME9652_CH_PER_NATIVE_DEVICE;
+
+ sprintf(devname, rme9652_dsp_dac, num_devs + rme_soundoutdevonset);
+ if ((tmp = open(devname,O_WRONLY)) == -1)
+ {
+ DEBUG(fprintf(stderr,"RME9652: failed to open %s writeonly\n",
+ devname);)
+ break;
+ }
+ DEBUG(fprintf(stderr,"RME9652: out device Nr. %d (%d) on %s\n",
+ linux_noutdevs+1,tmp,devname);)
+
+ if (outchans > outchannels)
+ {
+ rme9652_dac_devices[linux_noutdevs] = tmp;
+ linux_noutdevs++;
+ outchannels += channels;
+ }
+ else close(tmp);
+ }
+ if( linux_noutdevs > 0)
+ linux_dacs[0].d_fd = rme9652_dac_devices[0];
+
+ /* Second check if we can */
+ /* open the read ports */
+
+ for (num_devs=0; inchannels < inchans; num_devs++)
+ {
+ int channels = RME9652_CH_PER_NATIVE_DEVICE;
+
+ sprintf(devname, rme9652_dsp_adc, num_devs+rme_soundindevonset);
+
+ if ((tmp = open(devname,O_RDONLY)) == -1)
+ {
+ DEBUG(fprintf(stderr,"RME9652: failed to open %s readonly\n",
+ devname);)
+ break;
+ }
+ DEBUG(fprintf(stderr,"RME9652: in device Nr. %d (%d) on %s\n",
+ linux_nindevs+1,tmp,devname);)
+
+ if (inchans > inchannels)
+ {
+ rme9652_adc_devices[linux_nindevs] = tmp;
+ linux_nindevs++;
+ inchannels += channels;
+ }
+ else
+ close(tmp);
+ }
+ if(linux_nindevs > 0)
+ linux_adcs[0].d_fd = rme9652_adc_devices[0];
+
+ /* configure soundcards */
+
+ rme9652_configure(0, linux_adcs[0].d_fd,srate, 0);
+ rme9652_configure(0, linux_dacs[0].d_fd,srate, 1);
+
+ /* We have to do a read to start the engine. This is
+ necessary because sys_send_dacs waits until the input
+ buffer is filled and only reads on a filled buffer.
+ This is good, because it's a way to make sure that we
+ will not block */
+
+ if (linux_nindevs)
+ {
+ fprintf(stderr,("RME9652: starting read engine ... "));
+
+
+ for (num_devs=0; num_devs < linux_nindevs; num_devs++)
+ read(rme9652_adc_devices[num_devs],
+ buf, RME_SAMPLEWIDTH* RME9652_CH_PER_NATIVE_DEVICE*
+ DACBLKSIZE);
+
+
+ for (num_devs=0; num_devs < linux_noutdevs; num_devs++)
+ write(rme9652_dac_devices[num_devs],
+ buf, RME_SAMPLEWIDTH* RME9652_CH_PER_NATIVE_DEVICE*
+ DACBLKSIZE);
+
+ if(linux_noutdevs)
+ ioctl(rme9652_dac_devices[0],SNDCTL_DSP_SYNC);
+
+ fprintf(stderr,"done\n");
+ }
+
+ linux_setsr(srate);
+ linux_setch(linux_nindevs, linux_noutdevs);
+
+ num_of_rme9652_dac = linux_noutdevs;
+ num_of_rme9652_adc = linux_nindevs;
+
+ if(linux_noutdevs)linux_noutdevs=1;
+ if(linux_nindevs)linux_nindevs=1;
+
+ /* trick RME9652 behaves as one device fromread write pointers */
+ return (0);
+}
+
+void rme9652_close_audio( void)
+{
+ int i;
+ for (i=0;i<num_of_rme9652_dac;i++)
+ close(rme9652_dac_devices[i]);
+
+ for (i=0;i<num_of_rme9652_adc;i++)
+ close(rme9652_adc_devices[i]);
+}
+
+
+/* query audio devices for "available" data size. */
+/* not needed because oss_calcspace does the same */
+static int rme9652_calcspace(void)
+{
+ audio_buf_info ainfo;
+
+
+ /* one for all */
+
+ if (ioctl(linux_dacs[0].d_fd, SOUND_PCM_GETOSPACE,&ainfo) < 0)
+ fprintf(stderr,
+ "RME9652: calc ioctl SOUND_PCM_GETOSPACE on output device fd %d failed\n",
+ linux_dacs[0].d_fd);
+ linux_dacs[0].d_space = ainfo.bytes;
+
+ if (ioctl(linux_adcs[0].d_fd, SOUND_PCM_GETISPACE,&ainfo) < 0)
+ fprintf(stderr,
+ "RME9652: calc ioctl SOUND_PCM_GETISPACE on input device fd %d failed\n",
+ rme9652_adc_devices[0]);
+
+ linux_adcs[0].d_space = ainfo.bytes;
+
+ return 1;
+}
+
+/* this call resyncs audio output and input which will cause discontinuities
+in audio output and/or input. */
+
+static void rme9652_doresync( void)
+{
+ if(linux_noutdevs)
+ ioctl(rme9652_dac_devices[0],SNDCTL_DSP_SYNC);
+}
+
+static int mycount =0;
+
+int rme9652_send_dacs(void)
+{
+ float *fp;
+ long fill;
+ int i, j, dev;
+ /* the maximum number of samples we should have in the ADC buffer */
+ t_rme_sample buf[RME9652_CH_PER_NATIVE_DEVICE*DACBLKSIZE], *sp;
+
+ double timeref, timenow;
+
+ mycount++;
+
+ if (!linux_nindevs && !linux_noutdevs) return (0);
+
+ rme9652_calcspace();
+
+ /* do output */
+
+ timeref = sys_getrealtime();
+
+ if(linux_noutdevs){
+
+ if (linux_dacs[0].d_dropcount)
+ linux_dacs[0].d_dropcount--;
+ else{
+ /* fprintf(stderr,"output %d\n", linux_outchannels);*/
+
+ for(j=0;j<linux_outchannels;j++){
+
+ t_rme_sample *a,*b,*c,*d;
+ float *fp1,*fp2,*fp3,*fp4;
+
+ fp1 = sys_soundout + j*DACBLKSIZE-4;
+ fp2 = fp1 + 1;
+ fp3 = fp1 + 2;
+ fp4 = fp1 + 3;
+ a = buf-4;
+ b=a+1;
+ c=a+2;
+ d=a+3;
+
+ for (i = DACBLKSIZE>>2;i--;)
+ {
+ float s1 = *(fp1+=4) * INT32_MAX;
+ float s2 = *(fp2+=4) * INT32_MAX;
+ float s3 = *(fp3+=4) * INT32_MAX;
+ float s4 = *(fp4+=4) * INT32_MAX;
+
+ *(a+=4) = CLIP32(s1);
+ *(b+=4) = CLIP32(s2);
+ *(c+=4) = CLIP32(s3);
+ *(d+=4) = CLIP32(s4);
+ }
+
+ linux_dacs_write(rme9652_dac_devices[j],buf,RME_BYTESPERCHAN);
+ }
+ }
+
+ if ((timenow = sys_getrealtime()) - timeref > 0.02)
+ sys_log_error(ERR_DACSLEPT);
+ timeref = timenow;
+ }
+
+ memset(sys_soundout, 0,
+ linux_outchannels * (sizeof(float) * DACBLKSIZE));
+
+ /* do input */
+
+ if(linux_nindevs) {
+
+ for(j=0;j<linux_inchannels;j++){
+
+ linux_adcs_read(rme9652_adc_devices[j], buf, RME_BYTESPERCHAN);
+
+ if ((timenow = sys_getrealtime()) - timeref > 0.02)
+ sys_log_error(ERR_ADCSLEPT);
+ timeref = timenow;
+ {
+ t_rme_sample *a,*b,*c,*d;
+ float *fp1,*fp2,*fp3,*fp4;
+
+ fp1 = sys_soundin + j*DACBLKSIZE-4;
+ fp2 = fp1 + 1;
+ fp3 = fp1 + 2;
+ fp4 = fp1 + 3;
+ a = buf-4;
+ b=a+1;
+ c=a+2;
+ d=a+3;
+
+ for (i = (DACBLKSIZE>>2);i--;)
+ {
+ *(fp1+=4) = *(a+=4) * (float)(1./INT32_MAX);
+ *(fp2+=4) = *(b+=4) * (float)(1./INT32_MAX);
+ *(fp3+=4) = *(c+=4) * (float)(1./INT32_MAX);
+ *(fp4+=4) = *(d+=4) * (float)(1./INT32_MAX);
+ }
+ }
+ }
+ }
+ /* fprintf(stderr,"ready \n");*/
+
+ return (1);
+}
+
+#endif /* RME_HAMMERFALL */
diff --git a/pd/src/s_loader.c b/pd/src/s_loader.c
new file mode 100644
index 00000000..4c0ef972
--- /dev/null
+++ b/pd/src/s_loader.c
@@ -0,0 +1,142 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifdef DL_OPEN
+#include <dlfcn.h>
+#endif
+#ifdef UNIX
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+#ifdef NT
+#include <io.h>
+#include <windows.h>
+#endif
+#ifdef MACOSX
+#include <mach-o/dyld.h>
+#endif
+#include <string.h>
+#include "m_imp.h"
+#include <stdio.h>
+
+typedef void (*t_xxx)(void);
+
+static char sys_dllextent[] =
+#ifdef __FreeBSD__
+ ".pd_freebsd";
+#endif
+#ifdef IRIX
+#ifdef N32
+ ".pd_irix6";
+#else
+ ".pd_irix5";
+#endif
+#endif
+#ifdef __linux__
+ ".pd_linux";
+#endif
+#ifdef MACOSX
+ ".pd_darwin";
+#endif
+#ifdef NT
+ ".dll";
+#endif
+
+
+int sys_load_lib(char *dirname, char *classname)
+{
+ char symname[MAXPDSTRING], filename[MAXPDSTRING], dirbuf[MAXPDSTRING],
+ *nameptr, *lastdot;
+ void *dlobj;
+ t_xxx makeout;
+ int fd;
+#ifdef NT
+ HINSTANCE ntdll;
+#endif
+#if 0
+ fprintf(stderr, "lib %s %s\n", dirname, classname);
+#endif
+ if ((fd = open_via_path(dirname, classname, sys_dllextent,
+ dirbuf, &nameptr, MAXPDSTRING, 1)) < 0)
+ {
+ return (0);
+ }
+ else
+ {
+ close(fd);
+ /* refabricate the pathname */
+ strcpy(filename, dirbuf);
+ strcat(filename, "/");
+ strcat(filename, nameptr);
+ /* extract the setup function name */
+ if (lastdot = strrchr(nameptr, '.'))
+ *lastdot = 0;
+
+#ifdef MACOSX
+ strcpy(symname, "_");
+ strcat(symname, nameptr);
+#else
+ strcpy(symname, nameptr);
+#endif
+ /* if the last character is a tilde, replace with "_tilde" */
+ if (symname[strlen(symname) - 1] == '~')
+ strcpy(symname + (strlen(symname) - 1), "_tilde");
+ /* and append _setup to form the C setup function name */
+ strcat(symname, "_setup");
+#ifdef DL_OPEN
+ dlobj = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
+ if (!dlobj)
+ {
+ post("%s: %s", filename, dlerror());
+ return (0);
+ }
+ makeout = (t_xxx)dlsym(dlobj, symname);
+#endif
+#ifdef NT
+ sys_bashfilename(filename, filename);
+ ntdll = LoadLibrary(filename);
+ if (!ntdll)
+ {
+ post("%s: couldn't load", filename);
+ return (0);
+ }
+ makeout = (t_xxx)GetProcAddress(ntdll, symname);
+#endif
+#ifdef MACOSX
+ {
+ NSObjectFileImage image;
+ void *ret;
+ NSSymbol s;
+ if ( NSCreateObjectFileImageFromFile( filename, &image) != NSObjectFileImageSuccess )
+ {
+ post("%s: couldn't load", filename);
+ return 0;
+ }
+ ret = NSLinkModule( image, filename, NSLINKMODULE_OPTION_BINDNOW);
+
+ s = NSLookupSymbolInModule(ret, symname);
+
+ if (s)
+ makeout = (t_xxx)NSAddressOfSymbol( s);
+ else makeout = 0;
+ }
+#endif
+ }
+ if (!makeout)
+ {
+ post("load_object: Symbol \"%s\" not found", symname);
+ return 0;
+ }
+ (*makeout)();
+ return (1);
+}
+
+
+
+
+
+
+
+
+
diff --git a/pd/src/s_mac.c b/pd/src/s_mac.c
new file mode 100644
index 00000000..a36f192a
--- /dev/null
+++ b/pd/src/s_mac.c
@@ -0,0 +1,356 @@
+/* Copyright (c) 1997-2001 Guenter Geiger, Miller Puckette, Larry Troxler,
+* Winfried Ritsch, Karl MacMillan, and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* this file implements the sys_ functions profiled in m_imp.h for
+ audio and MIDI I/O on Macintosh OS X.
+
+ Audio simply calls routines in s_portaudio.c, which in turn call the
+ portaudio package. s_portaudio.c is also intended for use from NT.
+
+ MIDI is handled by "portmidi".
+*/
+
+
+#include "m_imp.h"
+#include <stdio.h>
+#ifdef UNIX
+#include <unistd.h>
+#endif
+#ifndef MACOSX
+#include <stdlib.h>
+#else
+#include <stdlib.h>
+#include "portaudio.h"
+#include "portmidi.h"
+#include "porttime.h"
+#include "pminternal.h"
+#endif
+#include <string.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <errno.h>
+
+/* Defines */
+#define DEBUG(x) x
+#define DEBUG2(x) {x;}
+
+#define PA_DEFAULTCH 2 /* portaudio specific? */
+#define PA_MAXCH 100
+#define PA_DEFAULTSRATE 44100
+typedef short t_pa_sample;
+#define PA_SAMPLEWIDTH sizeof(t_pa_sample)
+#define PA_BYTESPERCHAN (DACBLKSIZE * PA_SAMPLEWIDTH)
+#define PA_XFERSAMPS (PA_DEFAULTCH*DACBLKSIZE)
+#define PA_XFERSIZE (PA_SAMPLEWIDTH * PA_XFERSAMPS)
+
+static int mac_whichapi = API_PORTAUDIO;
+static int mac_inchannels;
+static int mac_outchannels;
+static int mac_advance_samples; /* scheduler advance in samples */
+static int mac_meters; /* true if we're metering */
+static float mac_inmax; /* max input amplitude */
+static float mac_outmax; /* max output amplitude */
+static int mac_blocksize = 256; /* audio I/O block size in sample frames */
+
+ /* exported variables */
+int sys_schedadvance = 50000; /* scheduler advance in microseconds */
+float sys_dacsr;
+int sys_hipriority = 0;
+t_sample *sys_soundout;
+t_sample *sys_soundin;
+
+static PmStream *mac_midiindevlist[MAXMIDIINDEV];
+static PmStream *mac_midioutdevlist[MAXMIDIOUTDEV];
+static int mac_nmidiindev;
+static int mac_nmidioutdev;
+
+ /* set channels and sample rate. */
+
+static void mac_setchsr(int chin, int chout, int sr)
+{
+ int nblk;
+ int inbytes = chin * (DACBLKSIZE*sizeof(float));
+ int outbytes = chout * (DACBLKSIZE*sizeof(float));
+
+ mac_inchannels = chin;
+ mac_outchannels = chout;
+ sys_dacsr = sr;
+ mac_advance_samples = (sys_schedadvance * sys_dacsr) / (1000000.);
+ if (mac_advance_samples < 3 * DACBLKSIZE)
+ mac_advance_samples = 3 * DACBLKSIZE;
+
+ if (sys_soundin)
+ free(sys_soundin);
+ sys_soundin = (t_float *)malloc(inbytes);
+ memset(sys_soundin, 0, inbytes);
+
+ if (sys_soundout)
+ free(sys_soundout);
+ sys_soundout = (t_float *)malloc(outbytes);
+ memset(sys_soundout, 0, outbytes);
+
+ if (sys_verbose)
+ post("input channels = %d, output channels = %d",
+ mac_inchannels, mac_outchannels);
+}
+
+/* ----------------------- public routines ----------------------- */
+
+void sys_open_audio(int naudioindev, int *audioindev, int nchindev,
+ int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
+ int *choutdev, int rate) /* IOhannes */
+{
+ int inchans=
+ (nchindev > 0 ? chindev[0] : (nchindev == 0 ? 0 : PA_DEFAULTCH));
+ int outchans=
+ (nchoutdev > 0 ? choutdev[0] : (nchoutdev == 0 ? 0 : PA_DEFAULTCH));
+ int soundindev = (naudioindev <= 0 ? -1 : (audioindev[0]-1));
+ int soundoutdev = (naudiooutdev <= 0 ? -1 : (audiooutdev[0]-1));
+ int sounddev = (inchans > 0 ? soundindev : soundoutdev);
+ if (naudioindev > 1 || nchindev > 1 || naudiooutdev > 1 || nchoutdev > 1)
+ post("sorry, only one portaudio device can be open at once.\n");
+ /* post("nindev %d, noutdev %d", naudioindev, naudiooutdev);
+ post("soundindev %d, soundoutdev %d", soundindev, soundoutdev); */
+ if (sys_verbose)
+ post("channels in %d, out %d", inchans, outchans);
+ if (rate < 1)
+ rate = PA_DEFAULTSRATE;
+ mac_setchsr(inchans, outchans, rate);
+ pa_open_audio(inchans, outchans, rate, sys_soundin, sys_soundout,
+ mac_blocksize, mac_advance_samples/mac_blocksize,
+ soundindev, soundoutdev);
+}
+
+void sys_close_audio(void)
+{
+ pa_close_audio();
+}
+
+
+int sys_send_dacs(void)
+{
+ if (mac_meters)
+ {
+ int i, n;
+ float maxsamp;
+ for (i = 0, n = mac_inchannels * DACBLKSIZE, maxsamp = mac_inmax;
+ i < n; i++)
+ {
+ float f = sys_soundin[i];
+ if (f > maxsamp) maxsamp = f;
+ else if (-f > maxsamp) maxsamp = -f;
+ }
+ mac_inmax = maxsamp;
+ for (i = 0, n = mac_outchannels * DACBLKSIZE, maxsamp = mac_outmax;
+ i < n; i++)
+ {
+ float f = sys_soundout[i];
+ if (f > maxsamp) maxsamp = f;
+ else if (-f > maxsamp) maxsamp = -f;
+ }
+ mac_outmax = maxsamp;
+ }
+ return pa_send_dacs();
+}
+
+float sys_getsr(void)
+{
+ return (sys_dacsr);
+}
+
+int sys_get_outchannels(void)
+{
+ return (mac_outchannels);
+}
+
+int sys_get_inchannels(void)
+{
+ return (mac_inchannels);
+}
+
+void sys_audiobuf(int n)
+{
+ /* set the size, in milliseconds, of the audio FIFO */
+ if (n < 5) n = 5;
+ else if (n > 5000) n = 5000;
+ sys_schedadvance = n * 1000;
+}
+
+void sys_getmeters(float *inmax, float *outmax)
+{
+ if (inmax)
+ {
+ mac_meters = 1;
+ *inmax = mac_inmax;
+ *outmax = mac_outmax;
+ }
+ else
+ mac_meters = 0;
+ mac_inmax = mac_outmax = 0;
+}
+
+void sys_reportidle(void)
+{
+}
+
+void sys_open_midi(int nmidiin, int *midiinvec,
+ int nmidiout, int *midioutvec)
+{
+ int i = 0;
+ int n = 0;
+ PmError err;
+
+ Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
+ mac_nmidiindev = 0;
+
+ for (i = 0; i < nmidiin; i++)
+ {
+ err = Pm_OpenInput(&mac_midiindevlist[mac_nmidiindev], midiinvec[i],
+ NULL, 100, NULL, NULL, NULL);
+ if (err)
+ post("could not open midi input device number %d: %s",
+ midiinvec[i], Pm_GetErrorText(err));
+ else
+ {
+ if (sys_verbose)
+ post("Midi Input opened.\n");
+ mac_nmidiindev++;
+ }
+ }
+
+ mac_nmidioutdev = 0;
+ for (i = 0; i < nmidiout; i++)
+ {
+ err = Pm_OpenOutput(&mac_midioutdevlist[mac_nmidioutdev], midioutvec[i],
+ NULL, 0, NULL, NULL, 0);
+ if (err)
+ post("could not open midi output device number %d: %s",
+ midioutvec[i], Pm_GetErrorText(err));
+ else
+ {
+ if (sys_verbose)
+ post("Midi Output opened.\n");
+ mac_nmidioutdev++;
+ }
+ }
+}
+
+void sys_close_midi( void)
+{
+ int i;
+ for (i = 0; i < mac_nmidiindev; i++)
+ Pm_Close(mac_midiindevlist[mac_nmidiindev]);
+ mac_nmidiindev = 0;
+ for (i = 0; i < mac_nmidioutdev; i++)
+ Pm_Close(mac_midioutdevlist[mac_nmidioutdev]);
+ mac_nmidioutdev = 0;
+}
+
+void sys_putmidimess(int portno, int a, int b, int c)
+{
+ PmEvent buffer;
+ fprintf(stderr, "put 1 msg %d %d\n", portno, mac_nmidioutdev);
+ if (portno >= 0 && portno < mac_nmidioutdev)
+ {
+ buffer.message = Pm_Message(a, b, c);
+ buffer.timestamp = 0;
+ fprintf(stderr, "put msg\n");
+ Pm_Write(mac_midioutdevlist[portno], &buffer, 1);
+ }
+}
+
+void sys_putmidibyte(int portno, int byte)
+{
+ post("sorry, no byte-by-byte MIDI output implemented in MAC OSX");
+}
+
+void sys_poll_midi(void)
+{
+ int i, nmess;
+ PmEvent buffer;
+ for (i = 0; i < mac_nmidiindev; i++)
+ {
+ int nmess = Pm_Read(mac_midiindevlist[i], &buffer, 1);
+ if (nmess > 0)
+ {
+ int status = Pm_MessageStatus(buffer.message);
+ int data1 = Pm_MessageData1(buffer.message);
+ int data2 = Pm_MessageData2(buffer.message);
+ int msgtype = (status >> 4) - 8;
+ switch (msgtype)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 6:
+ sys_midibytein(i, status);
+ sys_midibytein(i, data1);
+ sys_midibytein(i, data2);
+ break;
+ case 4:
+ case 5:
+ sys_midibytein(i, status);
+ sys_midibytein(i, data1);
+ break;
+ case 7:
+ sys_midibytein(i, status);
+ break;
+ }
+ }
+ }
+}
+
+void sys_set_priority(int higher)
+{
+ int retval;
+ errno = 0;
+ retval = setpriority(PRIO_PROCESS, 0, (higher? -20 : -19));
+ if (retval == -1 & errno != 0)
+ {
+ perror("setpriority");
+ fprintf(stderr, "priority bost faled.\n");
+ }
+}
+
+void sys_listdevs(void )
+{
+ pa_listdevs();
+}
+
+void sys_setblocksize(int n)
+{
+ if (n < 1)
+ n = 1;
+ if (n != (1 << ilog2(n)))
+ warn("blocksize adjusted to power of 2: %d",
+ (n = (1 << ilog2(n))));
+ mac_blocksize = n;
+}
+
+ /* dummy stuff that shouldn't he here */
+void nt_soundindev(int which)
+{
+}
+
+void nt_soundoutdev(int which)
+{
+}
+
+void nt_midiindev(int which)
+{
+}
+
+void nt_midioutdev(int which)
+{
+}
+
+void nt_noresync(void )
+{
+}
+
+void glob_audio(void *dummy, t_floatarg fadc, t_floatarg fdac)
+{
+}
diff --git a/pd/src/s_main.c b/pd/src/s_main.c
new file mode 100644
index 00000000..3c0f4164
--- /dev/null
+++ b/pd/src/s_main.c
@@ -0,0 +1,803 @@
+/* Copyright (c) 1997-1999 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. */
+
+/* IOhannes :
+ * hacked the code to add advanced multidevice-support
+ * 1311:forum::für::umläute:2001
+ */
+
+char pd_version[] = "Pd version 0.35\n";
+char pd_compiletime[] = __TIME__;
+char pd_compiledate[] = __DATE__;
+
+#include "m_imp.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#ifdef UNIX
+#include <unistd.h>
+#endif
+#ifdef NT
+#include <io.h>
+#include <windows.h>
+#include <winbase.h>
+#endif
+
+void pd_init(void);
+int sys_argparse(int argc, char **argv);
+void sys_findprogdir(char *progname);
+int sys_startgui(const char *guipath);
+int sys_rcfile(void);
+int m_scheduler(int nodacs);
+void m_schedsetsr( void);
+
+int sys_debuglevel;
+int sys_verbose;
+int sys_noloadbang;
+int sys_nogui;
+char *sys_guicmd;
+t_symbol *sys_libdir;
+static t_symbol *sys_guidir;
+static t_namelist *sys_externlist;
+static t_namelist *sys_openlist;
+static t_namelist *sys_messagelist;
+
+int sys_nmidiout = 1;
+#ifdef NT
+int sys_nmidiin = 0;
+#define DEFMIDIOUTDEV 0 /* For output, in NT, default to "midi_mapper" */
+#else
+int sys_nmidiin = 1;
+#define DEFMIDIOUTDEV 1 /* in other OSes, default to first MIDI device */
+#endif
+#define DEFMIDIINDEV 1 /* for NT this isn't used since sys_nmidiin is 0. */
+int sys_midiindevlist[MAXMIDIINDEV] = {DEFMIDIINDEV};
+int sys_midioutdevlist[MAXMIDIOUTDEV] = {DEFMIDIOUTDEV};
+
+typedef struct _fontinfo
+{
+ int fi_fontsize;
+ int fi_maxwidth;
+ int fi_maxheight;
+ int fi_hostfontsize;
+ int fi_width;
+ int fi_height;
+} t_fontinfo;
+
+ /* these give the nominal point size and maximum height of the characters
+ in the six fonts. */
+
+static t_fontinfo sys_fontlist[] = {
+ {8, 5, 9, 0, 0, 0}, {10, 7, 13, 0, 0, 0}, {12, 9, 16, 0, 0, 0},
+ {16, 10, 20, 0, 0, 0}, {24, 15, 25, 0, 0, 0}, {36, 25, 45, 0, 0, 0}};
+#define NFONT (sizeof(sys_fontlist)/sizeof(*sys_fontlist))
+
+/* here are the actual font size structs on msp's systems:
+NT:
+font 8 5 9 8 5 11
+font 10 7 13 10 6 13
+font 12 9 16 14 8 16
+font 16 10 20 16 10 18
+font 24 15 25 16 10 18
+font 36 25 42 36 22 41
+
+linux:
+font 8 5 9 8 5 9
+font 10 7 13 12 7 13
+font 12 9 16 14 9 15
+font 16 10 20 16 10 19
+font 24 15 25 24 15 24
+font 36 25 42 36 22 41
+*/
+
+static t_fontinfo *sys_findfont(int fontsize)
+{
+ unsigned int i;
+ t_fontinfo *fi;
+ for (i = 0, fi = sys_fontlist; i < (NFONT-1); i++, fi++)
+ if (fontsize < fi[1].fi_fontsize) return (fi);
+ return (sys_fontlist + (NFONT-1));
+}
+
+int sys_nearestfontsize(int fontsize)
+{
+ return (sys_findfont(fontsize)->fi_fontsize);
+}
+
+int sys_hostfontsize(int fontsize)
+{
+ return (sys_findfont(fontsize)->fi_hostfontsize);
+}
+
+int sys_fontwidth(int fontsize)
+{
+ return (sys_findfont(fontsize)->fi_width);
+}
+
+int sys_fontheight(int fontsize)
+{
+ return (sys_findfont(fontsize)->fi_height);
+}
+
+int sys_defaultfont;
+#ifdef NT
+#define DEFAULTFONT 12
+#else
+#define DEFAULTFONT 10
+#endif
+
+
+static int inchannels = -1, outchannels = -1;
+static int srate = 44100;
+
+/* IOhannes { */
+#define MAXSOUNDINDEV 4
+#define MAXSOUNDOUTDEV 4
+
+int sys_nsoundin = -1;
+int sys_nsoundout = -1;
+int sys_soundindevlist[MAXSOUNDINDEV] = {-1};
+int sys_soundoutdevlist[MAXSOUNDOUTDEV] = {-1};
+
+int sys_nchin = -1;
+int sys_nchout = -1;
+int sys_chinlist[MAXSOUNDINDEV] = {-1};
+int sys_choutlist[MAXSOUNDOUTDEV] = {-1};
+/* } IOhannes */
+
+static void openit(const char *dirname, const char *filename)
+{
+ char dirbuf[MAXPDSTRING], *nameptr;
+ int fd = open_via_path(dirname, filename, "", dirbuf, &nameptr,
+ MAXPDSTRING, 0);
+ if (fd)
+ {
+ close (fd);
+ glob_evalfile(0, gensym(nameptr), gensym(dirbuf));
+ }
+ else
+ error("%s: can't open", filename);
+}
+
+#define NHOSTFONT 7
+
+/* this is called from the gui process. The first argument is the cwd, and
+succeeding args give the widths and heights of known fonts. We wait until
+these are known to open files and send messages specified on the command line.
+We ask the GUI to specify the "cwd" in case we don't have a local OS to get it
+from; for instance we could be some kind of RT embedded system. However, to
+really make this make sense we would have to implement
+open(), read(), etc, calls to be served somehow from the GUI too. */
+
+void glob_initfromgui(void *dummy, t_symbol *s, int argc, t_atom *argv)
+{
+ char *cwd = atom_getsymbolarg(0, argc, argv)->s_name;
+ t_namelist *nl;
+ unsigned int i, j;
+ if (argc != 1 + 3 * NHOSTFONT) bug("glob_initfromgui");
+ for (i = 0; i < NFONT; i++)
+ {
+ int wantheight = sys_fontlist[i].fi_maxheight;
+ for (j = 0; j < NHOSTFONT-1; j++)
+ {
+ if (atom_getintarg(3 * (j + 1) + 3, argc, argv) > wantheight)
+ break;
+ }
+ /* j is now the "real" font index for the desired font index i. */
+ sys_fontlist[i].fi_hostfontsize = atom_getintarg(3 * j + 1, argc, argv);
+ sys_fontlist[i].fi_width = atom_getintarg(3 * j + 2, argc, argv);
+ sys_fontlist[i].fi_height = atom_getintarg(3 * j + 3, argc, argv);
+ }
+#if 0
+ for (i = 0; i < 6; i++)
+ fprintf(stderr, "font %d %d %d %d %d\n",
+ sys_fontlist[i].fi_fontsize,
+ sys_fontlist[i].fi_maxheight,
+ sys_fontlist[i].fi_hostfontsize,
+ sys_fontlist[i].fi_width,
+ sys_fontlist[i].fi_height);
+#endif
+ /* load dynamic libraries specified with "-lib" args */
+ for (nl = sys_externlist; nl; nl = nl->nl_next)
+ if (!sys_load_lib(cwd, nl->nl_string))
+ post("%s: can't load library", nl->nl_string);
+ namelist_free(sys_externlist);
+ sys_externlist = 0;
+ /* open patches specifies with "-open" args */
+ for (nl = sys_openlist; nl; nl = nl->nl_next)
+ openit(cwd, nl->nl_string);
+ namelist_free(sys_openlist);
+ sys_openlist = 0;
+ /* send messages specified with "-send" args */
+ for (nl = sys_messagelist; nl; nl = nl->nl_next)
+ {
+ t_binbuf *b = binbuf_new();
+ binbuf_text(b, nl->nl_string, strlen(nl->nl_string));
+ binbuf_eval(b, 0, 0, 0);
+ binbuf_free(b);
+ }
+ namelist_free(sys_messagelist);
+ sys_messagelist = 0;
+}
+
+static void sys_addextrapath(void);
+
+/* this is called from main() in s_entry.c */
+int sys_main(int argc, char **argv)
+{
+#ifdef PD_DEBUG
+ fprintf(stderr, "Pd: COMPILED FOR DEBUGGING\n");
+#endif
+ pd_init(); /* start the message system */
+ sys_findprogdir(argv[0]); /* set sys_progname, guipath */
+#ifdef __linux__
+ sys_rcfile(); /* parse the startup file */
+#endif
+ if (sys_argparse(argc, argv)) return (1); /* parse cmd line */
+ sys_addextrapath();
+ if (sys_verbose) fprintf(stderr, "%s compiled %s %s\n",
+ pd_version, pd_compiletime, pd_compiledate);
+ /* open audio and MIDI */
+ sys_open_midi(sys_nmidiin, sys_midiindevlist,
+ sys_nmidiout, sys_midioutdevlist);
+ sys_open_audio(sys_nsoundin, sys_soundindevlist, sys_nchin, sys_chinlist,
+ sys_nsoundout, sys_soundoutdevlist, sys_nchout, sys_choutlist, srate);
+
+ /* tell scheduler the sample rate */
+ m_schedsetsr();
+ if (sys_startgui(sys_guidir->s_name)) /* start the gui */
+ return(1);
+
+ /* run scheduler until it quits */
+ return (m_scheduler(!(inchannels || outchannels)));
+}
+
+static char *(usagemessage[]) = {
+"usage: pd [-flags] [file]...\n",
+"\naudio configuration flags:\n",
+"-r <n> -- specify sample rate\n",
+#if defined(__linux__) || defined(NT)
+"-inchannels ... -- number of audio in channels (by device, like \"2\" or \"16,8\")\n",
+"-outchannels ... -- number of audio out channels (by device)\n",
+#else
+"-inchannels <n> -- number of audio input channels\n",
+"-outchannels <n> -- number of audio output channels\n",
+#endif
+"-channels ... -- specify both input and output channels\n",
+"-audiobuf <n> -- specify size of audio buffer in msec\n",
+"-blocksize <n> -- specify audio I/O block size in sample frames\n",
+"-sleepgrain <n> -- specify number of milliseconds to sleep when idle\n",
+"-nodac -- suppress audio output\n",
+"-noadc -- suppress audio input\n",
+"-noaudio -- suppress audio input and output (-nosound is synonym) \n",
+"-listdev -- list audio and MIDI devices\n",
+
+#ifdef __linux__
+"-frags <n> -- specify number of audio fragments (defeats audiobuf)\n",
+"-fragsize <n> -- specify log of fragment size ('blocksize' is better...)\n",
+"-stream -- use stream mode audio (e.g., for es1370 audio cards)\n",
+"-32bit -- allow 32 bit OSS audio transfers (for RME Hammerfall)\n",
+#endif
+
+#ifdef ALSA99
+"-alsa -- use ALSA audio drivers\n",
+"-alsadev <n> -- specify ALSA I/O device number (counting from 1)\n",
+#endif
+
+#ifdef ALSA01
+"-alsa -- use ALSA audio drivers\n",
+"-alsadev <n> -- ALSA device # (counting from 1) or name: default hw:0,0\n",
+#endif
+
+#ifdef RME_HAMMERFALL
+"-rme -- use Ritsch's RME 9652 audio driver\n",
+#endif
+"-audioindev ... -- sound in device list; e.g., \"2,1\" for second and first\n",
+"-audiooutdev ... -- sound out device list, same as above \n",
+"-audiodev ... -- specify both -audioindev and -audiooutdev together\n",
+
+#ifdef NT
+"-resync -- resynchronize audio (default if more than 2 channels)\n",
+"-noresync -- never resynchronize audio I/O (default for stereo)\n",
+"-asio -- use ASIO audio driver (and not the 'MMIO' default)\n",
+#endif
+
+"\nMIDI configuration flags:\n",
+"-midiindev ... -- midi in device list; e.g., \"1,3\" for first and third\n",
+"-midioutdev ... -- midi out device list, same format\n",
+"-mididev ... -- specify -midioutdev and -midiindev together\n",
+"-nomidiin -- suppress MIDI input\n",
+"-nomidiout -- suppress MIDI output\n",
+"-nomidi -- suppress MIDI input and output\n",
+
+"\ngeneral flags:\n",
+"-path <path> -- add to file search path\n",
+"-open <file> -- open file(s) on startup\n",
+"-lib <file> -- load object library(s)\n",
+"-font <n> -- specify default font size in points\n",
+"-verbose -- extra printout on startup and when searching for files\n",
+"-d <n> -- specify debug level\n",
+"-noloadbang -- suppress all loadbangs\n",
+"-nogui -- suppress starting the GUI\n",
+"-guicmd \"cmd...\" -- substitute another GUI program (e.g., rsh)\n",
+"-send \"msg...\" -- send a message at startup (after patches are loaded)\n",
+#ifdef UNIX
+"-rt or -realtime -- use real-time priority (needs root privilege)\n",
+#endif
+};
+
+static void sys_parsedevlist(int *np, int *vecp, int max, char *str)
+{
+ int n = 0;
+ while (n < max)
+ {
+ if (!*str) break;
+ else
+ {
+ char *endp;
+ vecp[n] = strtol(str, &endp, 10);
+ if (endp == str)
+ break;
+ n++;
+ if (!endp)
+ break;
+ str = endp + 1;
+ }
+ }
+ *np = n;
+}
+
+static int sys_getmultidevchannels(int n, int *devlist)
+{
+ int sum = 0;
+ if (n<0)return(-1);
+ if (n==0)return 0;
+ while(n--)sum+=*devlist++;
+ return sum;
+}
+
+
+ /* this routine tries to figure out where to find the auxilliary files
+ Pd will need to run. This is either done by looking at the command line
+ invokation for Pd, or if htat fails, by consulting the variable
+ INSTALL_PREFIX. In NT, we don't try to use INSTALL_PREFIX. */
+void sys_findprogdir(char *progname)
+{
+ char sbuf[MAXPDSTRING], sbuf2[MAXPDSTRING], *sp;
+ char *lastslash;
+#ifdef UNIX
+ struct stat statbuf;
+#endif
+
+ /* find out by what string Pd was invoked; put answer in "sbuf". */
+#ifdef NT
+ GetModuleFileName(NULL, sbuf2, sizeof(sbuf2));
+ sbuf2[MAXPDSTRING-1] = 0;
+ sys_unbashfilename(sbuf2, sbuf);
+#endif /* NT */
+#ifdef UNIX
+ strncpy(sbuf, progname, MAXPDSTRING);
+ sbuf[MAXPDSTRING-1] = 0;
+#endif
+ lastslash = strrchr(sbuf, '/');
+ if (lastslash)
+ {
+ /* bash last slash to zero so that sbuf is directory pd was in,
+ e.g., ~/pd/bin */
+ *lastslash = 0;
+ /* go back to the parent from there, e.g., ~/pd */
+ lastslash = strrchr(sbuf, '/');
+ if (lastslash)
+ {
+ strncpy(sbuf2, sbuf, lastslash-sbuf);
+ sbuf2[lastslash-sbuf] = 0;
+ }
+ else strcpy(sbuf2, "..");
+ }
+ else
+ {
+ /* no slashes found. Try INSTALL_PREFIX. */
+#ifdef INSTALL_PREFIX
+ strcpy(sbuf2, INSTALL_PREFIX);
+#else
+ strcpy(sbuf2, ".");
+#endif
+ }
+ /* now we believe sbuf2 holds the parent directory of the directory
+ pd was found in. We now want to infer the "lib" directory and the
+ "gui" directory. In "simple" UNIX installations, the layout is
+ .../bin/pd
+ .../bin/pd-gui
+ .../doc
+ and in "complicated" UNIX installations, it's:
+ .../bin/pd
+ .../lib/pd/bin/pd-gui
+ .../lib/pd/doc
+ To decide which, we stat .../lib/pd; if that exists, we assume it's
+ the complicated layout. In NT, it's the "simple" layout, but
+ the gui program is straight wish80:
+ .../bin/pd
+ .../bin/wish80.exe
+ .../doc
+ */
+#ifdef UNIX
+ strncpy(sbuf, sbuf2, MAXPDSTRING-30);
+ sbuf[MAXPDSTRING-30] = 0;
+ strcat(sbuf, "/lib/pd");
+ if (stat(sbuf, &statbuf) >= 0)
+ {
+ /* complicated layout: lib dir is the one we just stat-ed above */
+ sys_libdir = gensym(sbuf);
+ /* gui lives in .../lib/pd/bin */
+ strncpy(sbuf, sbuf2, MAXPDSTRING-30);
+ sbuf[MAXPDSTRING-30] = 0;
+ strcat(sbuf, "/lib/pd/bin");
+ sys_guidir = gensym(sbuf);
+ }
+ else
+ {
+ /* simple layout: lib dir is the parent */
+ sys_libdir = gensym(sbuf2);
+ /* gui lives in .../bin */
+ strncpy(sbuf, sbuf2, MAXPDSTRING-30);
+ sbuf[MAXPDSTRING-30] = 0;
+ strcat(sbuf, "/bin");
+ sys_guidir = gensym(sbuf);
+ }
+#endif
+#ifdef NT
+ sys_libdir = gensym(sbuf2);
+ sys_guidir = &s_; /* in NT the guipath just depends on the libdir */
+#endif
+}
+
+int sys_argparse(int argc, char **argv)
+{
+ char sbuf[MAXPDSTRING];
+#ifdef NT
+ int resync = -1;
+#endif
+ argc--; argv++;
+ while ((argc > 0) && **argv == '-')
+ {
+ if (!strcmp(*argv, "-r") && argc > 1 &&
+ sscanf(argv[1], "%d", &srate) >= 1)
+ {
+ argc -= 2;
+ argv += 2;
+ }
+ else if (!strcmp(*argv, "-inchannels"))
+ { /* IOhannes */
+ sys_parsedevlist(&sys_nchin, sys_chinlist, MAXSOUNDINDEV, argv[1]);
+ inchannels=sys_getmultidevchannels(sys_nchin, sys_chinlist);
+
+ if (!sys_nchin)
+ goto usage;
+
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(*argv, "-outchannels"))
+ { /* IOhannes */
+ sys_parsedevlist(&sys_nchout, sys_choutlist,MAXSOUNDOUTDEV, argv[1]);
+ outchannels=sys_getmultidevchannels(sys_nchout, sys_choutlist);
+
+ if (!sys_nchout)
+ goto usage;
+
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(*argv, "-channels"))
+ {
+ sys_parsedevlist(&sys_nchin, sys_chinlist,MAXSOUNDINDEV,
+ argv[1]);
+ inchannels = sys_getmultidevchannels(sys_nchin, sys_chinlist);
+ sys_parsedevlist(&sys_nchout, sys_choutlist,MAXSOUNDOUTDEV,
+ argv[1]);
+ outchannels = sys_getmultidevchannels(sys_nchout, sys_choutlist);
+
+ if (!sys_nchout)
+ goto usage;
+
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(*argv, "-soundbuf") || !strcmp(*argv, "-audiobuf"))
+ {
+ sys_audiobuf(atoi(argv[1]));
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(*argv, "-blocksize"))
+ {
+ sys_setblocksize(atoi(argv[1]));
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(*argv, "-sleepgrain"))
+ {
+ sys_sleepgrain = 1000 * atoi(argv[1]);
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(*argv, "-nodac"))
+ { /* IOhannes */
+ sys_nsoundout=0;
+ sys_nchout = 0;
+ outchannels =0;
+ argc--; argv++;
+ }
+ else if (!strcmp(*argv, "-noadc"))
+ { /* IOhannes */
+ sys_nsoundin=0;
+ sys_nchin = 0;
+ inchannels =0;
+ argc--; argv++;
+ }
+ else if (!strcmp(*argv, "-nosound") || !strcmp(*argv, "-noaudio"))
+ { /* IOhannes */
+ sys_nsoundin=sys_nsoundout = 0;
+ sys_nchin = sys_nchout = 0;
+ inchannels =outchannels =0;
+ argc--; argv++;
+ }
+ else if (!strcmp(*argv, "-nomidiin"))
+ {
+ sys_nmidiin = 0;
+ argc--; argv++;
+ }
+ else if (!strcmp(*argv, "-nomidiout"))
+ {
+ sys_nmidiout = 0;
+ argc--; argv++;
+ }
+ else if (!strcmp(*argv, "-nomidi"))
+ {
+ sys_nmidiin = sys_nmidiout = 0;
+ argc--; argv++;
+ }
+ else if (!strcmp(*argv, "-midiindev"))
+ {
+ sys_parsedevlist(&sys_nmidiin, sys_midiindevlist, MAXMIDIINDEV,
+ argv[1]);
+ if (!sys_nmidiin)
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(*argv, "-midioutdev"))
+ {
+ sys_parsedevlist(&sys_nmidiout, sys_midioutdevlist, MAXMIDIOUTDEV,
+ argv[1]);
+ if (!sys_nmidiout)
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(*argv, "-mididev"))
+ {
+ sys_parsedevlist(&sys_nmidiin, sys_midiindevlist, MAXMIDIINDEV,
+ argv[1]);
+ sys_parsedevlist(&sys_nmidiout, sys_midioutdevlist, MAXMIDIOUTDEV,
+ argv[1]);
+ if (!sys_nmidiout)
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(*argv, "-path"))
+ {
+ sys_addpath(argv[1]);
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(*argv, "-open") && argc > 1)
+ {
+ sys_openlist = namelist_append(sys_openlist, argv[1]);
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(*argv, "-lib") && argc > 1)
+ {
+ sys_externlist = namelist_append(sys_externlist, argv[1]);
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(*argv, "-font") && argc > 1)
+ {
+ sys_defaultfont = sys_nearestfontsize(atoi(argv[1]));
+ argc -= 2;
+ argv += 2;
+ }
+ else if (!strcmp(*argv, "-verbose"))
+ {
+ sys_verbose = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp(*argv, "-d") && argc > 1 &&
+ sscanf(argv[1], "%d", &sys_debuglevel) >= 1)
+ {
+ argc -= 2;
+ argv += 2;
+ }
+ else if (!strcmp(*argv, "-noloadbang"))
+ {
+ sys_noloadbang = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp(*argv, "-nogui"))
+ {
+ sys_nogui = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp(*argv, "-guicmd") && argc > 1)
+ {
+ sys_guicmd = argv[1];
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(*argv, "-send") && argc > 1)
+ {
+ sys_messagelist = namelist_append(sys_messagelist, argv[1]);
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(*argv, "-listdev"))
+ {
+ sys_listdevs();
+ argc--; argv++;
+ }
+#ifdef UNIX
+ else if (!strcmp(*argv, "-rt"))
+ {
+ sys_hipriority = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp(*argv, "-realtime"))
+ {
+ sys_hipriority = 1;
+ argc--; argv++;
+ }
+#endif
+#ifdef __linux__
+ else if (!strcmp(*argv, "-frags"))
+ {
+ linux_setfrags(atoi(argv[1]));
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(*argv, "-fragsize"))
+ {
+ post("pd: -fragsize argument is obsolete; use '-blocksize %d'\n",
+ (1 << atoi(argv[1])));
+ sys_setblocksize(1 << atoi(argv[1]));
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(*argv, "-stream"))
+ {
+ linux_streammode();
+ argc--; argv++;
+ }
+ else if (!strcmp(*argv, "-32bit"))
+ {
+ linux_32bit();
+ argc--; argv++;
+ }
+#ifdef ALSA01
+ else if (!strcmp(*argv, "-alsa"))
+ {
+ linux_set_sound_api(API_ALSA);
+ argc--; argv++;
+ }
+ else if (!strcmp(*argv, "-alsadev"))
+ {
+ if (argv[1][0] >= '1' && argv[1][0] <= '9')
+ {
+ char buf[80];
+ sprintf(buf, "hw:%d,0", atoi(argv[1]) - 1);
+ linux_alsa_devname(buf);
+ }
+ else linux_alsa_devname(argv[1]);
+ linux_set_sound_api(API_ALSA);
+ argc -= 2; argv +=2;
+ }
+#endif
+#ifdef ALSA99
+ else if (!strcmp(*argv, "-alsa"))
+ {
+ linux_set_sound_api(API_ALSA);
+ argc--; argv++;
+ }
+ else if (!strcmp(*argv, "-alsadev"))
+ {
+ linux_alsa_devno(atoi(argv[1]));
+ linux_set_sound_api(API_ALSA);
+ argc -= 2; argv +=2;
+ }
+#endif
+#ifdef RME_HAMMERFALL
+ else if (!strcmp(*argv, "-rme"))
+ {
+ linux_set_sound_api(API_RME);
+ argc--; argv++;
+ }
+#endif
+#endif
+ else if (!strcmp(*argv, "-soundindev") ||
+ !strcmp(*argv, "-audioindev"))
+ { /* IOhannes */
+ sys_parsedevlist(&sys_nsoundin, sys_soundindevlist,
+ MAXSOUNDINDEV, argv[1]);
+ if (!sys_nsoundin)
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(*argv, "-soundoutdev") ||
+ !strcmp(*argv, "-audiooutdev"))
+ { /* IOhannes */
+ sys_parsedevlist(&sys_nsoundout, sys_soundoutdevlist,
+ MAXSOUNDOUTDEV, argv[1]);
+ if (!sys_nsoundout)
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(*argv, "-sounddev") || !strcmp(*argv, "-audiodev"))
+ {
+ sys_parsedevlist(&sys_nsoundin, sys_soundindevlist,
+ MAXSOUNDINDEV, argv[1]);
+ sys_parsedevlist(&sys_nsoundout, sys_soundoutdevlist,
+ MAXSOUNDOUTDEV, argv[1]);
+ if (!sys_nsoundout)
+ goto usage;
+ argc -= 2; argv += 2;
+ }
+#ifdef NT
+ else if (!strcmp(*argv, "-asio"))
+ {
+ nt_set_sound_api(API_PORTAUDIO);
+ argc--; argv++;
+ }
+ else if (!strcmp(*argv, "-noresync"))
+ {
+ resync = 0;
+ argc--; argv++;
+ }
+ else if (!strcmp(*argv, "-resync"))
+ {
+ resync = 1;
+ argc--; argv++;
+ }
+
+#endif /* NT */
+ else
+ {
+ unsigned int i;
+ usage:
+ for (i = 0; i < sizeof(usagemessage)/sizeof(*usagemessage); i++)
+ fprintf(stderr, "%s", usagemessage[i]);
+ return (1);
+ }
+ }
+#ifdef NT
+ /* resynchronization is on by default for mulltichannel, otherwise
+ off. */
+ if (resync == -1)
+ resync = (inchannels > 2 || outchannels > 2);
+ if (!resync)
+ nt_noresync();
+#endif
+ if (!sys_defaultfont) sys_defaultfont = DEFAULTFONT;
+ for (; argc > 0; argc--, argv++)
+ sys_openlist = namelist_append(sys_openlist, *argv);
+
+
+ return (0);
+}
+
+int sys_getblksize(void)
+{
+ return (DACBLKSIZE);
+}
+
+static void sys_addextrapath(void)
+{
+ char sbuf[MAXPDSTRING];
+ /* add "extra" library to path */
+ strncpy(sbuf, sys_libdir->s_name, MAXPDSTRING-30);
+ sbuf[MAXPDSTRING-30] = 0;
+ strcat(sbuf, "/extra");
+ sys_addpath(sbuf);
+}
+
diff --git a/pd/src/s_nt.c b/pd/src/s_nt.c
new file mode 100644
index 00000000..99346e7c
--- /dev/null
+++ b/pd/src/s_nt.c
@@ -0,0 +1,1586 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* modified 2/98 by Winfried Ritsch to deal with up to 4 synchronized
+"wave" devices, which is how ADAT boards appear to the WAVE API. */
+
+#include "m_imp.h"
+#include <stdio.h>
+
+#include <windows.h>
+
+#include <MMSYSTEM.H>
+
+/* ------------------------- audio -------------------------- */
+
+static void nt_close_midiin(void);
+
+static void postflags(void);
+
+#define NAPORTS 16 /* wini hack for multiple ADDA devices */
+#define NT_MAXCH (2 * NAPORTS)
+#define CHANNELS_PER_DEVICE 2
+#define DEFAULTCHANS 2
+#define DEFAULTSRATE 44100
+#define SAMPSIZE 2
+
+#define REALDACBLKSIZE (4 * DACBLKSIZE) /* larger underlying bufsize */
+
+#define MAXBUFFER 100 /* number of buffers in use at maximum advance */
+#define DEFBUFFER 30 /* default is about 30x6 = 180 msec! */
+static int nt_naudiobuffer = DEFBUFFER;
+static int nt_advance_samples;
+
+float sys_dacsr = DEFAULTSRATE;
+
+static int nt_whichapi = API_MMIO;
+static int nt_meters; /* true if we're metering */
+static float nt_inmax; /* max input amplitude */
+static float nt_outmax; /* max output amplitude */
+static int nt_nwavein, nt_nwaveout; /* number of WAVE devices in and out */
+static int nt_blocksize = 0; /* audio I/O block size in sample frames */
+int sys_schedadvance = 20000; /* scheduler advance in microseconds */
+
+typedef struct _sbuf
+{
+ HANDLE hData;
+ HPSTR lpData; // pointer to waveform data memory
+ HANDLE hWaveHdr;
+ WAVEHDR *lpWaveHdr; // pointer to header structure
+} t_sbuf;
+
+t_sbuf ntsnd_outvec[NAPORTS][MAXBUFFER]; /* circular buffer array */
+HWAVEOUT ntsnd_outdev[NAPORTS]; /* output device */
+static int ntsnd_outphase[NAPORTS]; /* index of next buffer to send */
+
+t_sbuf ntsnd_invec[NAPORTS][MAXBUFFER]; /* circular buffer array */
+HWAVEIN ntsnd_indev[NAPORTS]; /* input device */
+static int ntsnd_inphase[NAPORTS]; /* index of next buffer to read */
+int sys_hipriority = 0;
+
+static void nt_waveinerror(char *s, int err)
+{
+ char t[256];
+ waveInGetErrorText(err, t, 256);
+ fprintf(stderr, s, t);
+}
+
+static void nt_waveouterror(char *s, int err)
+{
+ char t[256];
+ waveOutGetErrorText(err, t, 256);
+ fprintf(stderr, s, t);
+}
+
+static void wave_prep(t_sbuf *bp)
+{
+ WAVEHDR *wh;
+ short *sp;
+ int i;
+ /*
+ * Allocate and lock memory for the waveform data. The memory
+ * for waveform data must be globally allocated with
+ * GMEM_MOVEABLE and GMEM_SHARE flags.
+ */
+
+ if (!(bp->hData =
+ GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
+ (DWORD) (CHANNELS_PER_DEVICE * REALDACBLKSIZE * SAMPSIZE))))
+ printf("alloc 1 failed\n");
+
+ if (!(bp->lpData =
+ (HPSTR) GlobalLock(bp->hData)))
+ printf("lock 1 failed\n");
+
+ /* Allocate and lock memory for the header. */
+
+ if (!(bp->hWaveHdr =
+ GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD) sizeof(WAVEHDR))))
+ printf("alloc 2 failed\n");
+
+ if (!(wh = bp->lpWaveHdr =
+ (WAVEHDR *) GlobalLock(bp->hWaveHdr)))
+ printf("lock 2 failed\n");
+
+ for (i = CHANNELS_PER_DEVICE * REALDACBLKSIZE,
+ sp = (short *)bp->lpData; i--; )
+ *sp++ = 0;
+
+ wh->lpData = bp->lpData;
+ wh->dwBufferLength = (CHANNELS_PER_DEVICE * REALDACBLKSIZE * SAMPSIZE);
+ wh->dwFlags = 0;
+ wh->dwLoops = 0L;
+ wh->lpNext = 0;
+ wh->reserved = 0;
+}
+
+static int nt_inalloc[NAPORTS], nt_outalloc[NAPORTS];
+static UINT nt_whichdac = WAVE_MAPPER, nt_whichadc = WAVE_MAPPER;
+
+int mmio_open_audio(void)
+{
+ PCMWAVEFORMAT form;
+ int i;
+ UINT mmresult;
+ int nad, nda;
+
+ if (sys_verbose)
+ post("%d devices in, %d devices out",
+ nt_nwavein, nt_nwaveout);
+
+ form.wf.wFormatTag = WAVE_FORMAT_PCM;
+ form.wf.nChannels = CHANNELS_PER_DEVICE;
+ form.wf.nSamplesPerSec = sys_dacsr;
+ form.wf.nAvgBytesPerSec = sys_dacsr * (CHANNELS_PER_DEVICE * SAMPSIZE);
+ form.wf.nBlockAlign = CHANNELS_PER_DEVICE * SAMPSIZE;
+ form.wBitsPerSample = 8 * SAMPSIZE;
+
+ for (nad=0; nad < nt_nwavein; nad++)
+ {
+ /* Open waveform device(s), sucessively numbered, for input */
+
+ mmresult = waveInOpen(&ntsnd_indev[nad], nt_whichadc+nad,
+ (WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL);
+
+ if (sys_verbose)
+ printf("opened adc device %d with return %d\n",
+ nt_whichadc+nad,mmresult);
+
+ if (mmresult != MMSYSERR_NOERROR)
+ {
+ nt_waveinerror("waveInOpen: %s\n", mmresult);
+ nt_nwavein = nad; /* nt_nwavein = 0 wini */
+ }
+ else
+ {
+ if (!nt_inalloc[nad])
+ {
+ for (i = 0; i < nt_naudiobuffer; i++)
+ wave_prep(&ntsnd_invec[nad][i]);
+ nt_inalloc[nad] = 1;
+ }
+ for (i = 0; i < nt_naudiobuffer; i++)
+ {
+ mmresult = waveInPrepareHeader(ntsnd_indev[nad],
+ ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR));
+ if (mmresult != MMSYSERR_NOERROR)
+ nt_waveinerror("waveinprepareheader: %s\n", mmresult);
+ mmresult = waveInAddBuffer(ntsnd_indev[nad],
+ ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR));
+ if (mmresult != MMSYSERR_NOERROR)
+ nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
+ }
+ }
+ }
+ /* quickly start them all together */
+ for(nad=0; nad < nt_nwavein; nad++)
+ waveInStart(ntsnd_indev[nad]);
+
+ for(nda=0; nda < nt_nwaveout; nda++)
+ {
+
+ /* Open a waveform device for output in sucessiv device numbering*/
+ mmresult = waveOutOpen(&ntsnd_outdev[nda], nt_whichdac + nda,
+ (WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL);
+
+ if (sys_verbose)
+ fprintf(stderr,"opened dac device %d, with return %d\n",
+ nt_whichdac +nda, mmresult);
+
+ if (mmresult != MMSYSERR_NOERROR)
+ {
+ fprintf(stderr,"Wave out open device %d + %d\n",nt_whichdac,nda);
+ nt_waveouterror("waveOutOpen device: %s\n", mmresult);
+ nt_nwaveout = nda;
+ }
+ else
+ {
+ if (!(nt_outalloc[nda]))
+ {
+ for (i = 0; i < nt_naudiobuffer; i++)
+ {
+ wave_prep(&ntsnd_outvec[nda][i]);
+ /* set DONE flag as if we had queued them */
+ ntsnd_outvec[nda][i].lpWaveHdr->dwFlags = WHDR_DONE;
+ }
+ nt_outalloc[nda] = 1;
+ }
+ }
+ }
+
+ return (0);
+}
+
+void mmio_close_audio( void)
+{
+ int errcode;
+ int nda, nad;
+ if (sys_verbose)
+ post("closing audio...");
+
+ for (nda=0; nda < nt_nwaveout; nda++) /*if (nt_nwaveout) wini */
+ {
+ errcode = waveOutReset(ntsnd_outdev[nda]);
+ if (errcode != MMSYSERR_NOERROR)
+ printf("error resetting output %d: %d\n", nda, errcode);
+ errcode = waveOutClose(ntsnd_outdev[nda]);
+ if (errcode != MMSYSERR_NOERROR)
+ printf("error closing output %d: %d\n",nda , errcode);
+ }
+ nt_nwaveout = 0;
+
+ for(nad=0; nad < nt_nwavein;nad++) /* if (nt_nwavein) wini */
+ {
+ errcode = waveInReset(ntsnd_indev[nad]);
+ if (errcode != MMSYSERR_NOERROR)
+ printf("error resetting input: %d\n", errcode);
+ errcode = waveInClose(ntsnd_indev[nad]);
+ if (errcode != MMSYSERR_NOERROR)
+ printf("error closing input: %d\n", errcode);
+ }
+ nt_nwavein = 0;
+}
+
+
+#define ADCJITTER 10 /* We tolerate X buffers of jitter by default */
+#define DACJITTER 10
+
+static int nt_adcjitterbufsallowed = ADCJITTER;
+static int nt_dacjitterbufsallowed = DACJITTER;
+
+ /* ------------- MIDI time stamping from audio clock ------------ */
+
+#ifdef MIDI_TIMESTAMP
+
+static double nt_hibuftime;
+static double initsystime = -1;
+
+ /* call this whenever we reset audio */
+static void nt_resetmidisync(void)
+{
+ initsystime = clock_getsystime();
+ nt_hibuftime = sys_getrealtime();
+}
+
+ /* call this whenever we're idled waiting for audio to be ready.
+ The routine maintains a high and low water point for the difference
+ between real and DAC time. */
+
+static void nt_midisync(void)
+{
+ double jittersec, diff;
+
+ if (initsystime == -1) nt_resetmidisync();
+ jittersec = (nt_dacjitterbufsallowed > nt_adcjitterbufsallowed ?
+ nt_dacjitterbufsallowed : nt_adcjitterbufsallowed)
+ * REALDACBLKSIZE / sys_getsr();
+ diff = sys_getrealtime() - 0.001 * clock_gettimesince(initsystime);
+ if (diff > nt_hibuftime) nt_hibuftime = diff;
+ if (diff < nt_hibuftime - jittersec)
+ {
+ post("jitter excess %d %f", dac, diff);
+ nt_resetmidisync();
+ }
+}
+
+static double nt_midigettimefor(LARGE_INTEGER timestamp)
+{
+ /* this is broken now... used to work when "timestamp" was derived from
+ QueryPerformanceCounter() instead of the gates approved
+ timeGetSystemTime() call in the MIDI callback routine below. */
+ return (nt_tixtotime(timestamp) - nt_hibuftime);
+}
+#endif /* MIDI_TIMESTAMP */
+
+
+static int nt_fill = 0;
+#define WRAPFWD(x) ((x) >= nt_naudiobuffer ? (x) - nt_naudiobuffer: (x))
+#define WRAPBACK(x) ((x) < 0 ? (x) + nt_naudiobuffer: (x))
+#define MAXRESYNC 500
+
+#if 0 /* this is used for debugging */
+static void nt_printaudiostatus(void)
+{
+ int nad, nda;
+ for (nad = 0; nad < nt_nwavein; nad++)
+ {
+ int phase = ntsnd_inphase[nad];
+ int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0;
+ int firstphasedone = -1, firstphasebusy = -1;
+ for (count = 0; count < nt_naudiobuffer; count++)
+ {
+ int donethis =
+ (ntsnd_invec[nad][phase2].lpWaveHdr->dwFlags & WHDR_DONE);
+ int donenext =
+ (ntsnd_invec[nad][phase3].lpWaveHdr->dwFlags & WHDR_DONE);
+ if (donethis && !donenext)
+ {
+ if (firstphasebusy >= 0) goto multipleadc;
+ firstphasebusy = count;
+ }
+ if (!donethis && donenext)
+ {
+ if (firstphasedone >= 0) goto multipleadc;
+ firstphasedone = count;
+ }
+ phase2 = phase3;
+ phase3 = WRAPFWD(phase2 + 1);
+ }
+ post("nad %d phase %d busy %d done %d", nad, phase, firstphasebusy,
+ firstphasedone);
+ continue;
+ multipleadc:
+ startpost("nad %d phase %d: oops:", nad, phase);
+ for (count = 0; count < nt_naudiobuffer; count++)
+ {
+ char buf[80];
+ sprintf(buf, " %d",
+ (ntsnd_invec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE));
+ poststring(buf);
+ }
+ endpost();
+ }
+ for (nda = 0; nda < nt_nwaveout; nda++)
+ {
+ int phase = ntsnd_outphase[nad];
+ int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0;
+ int firstphasedone = -1, firstphasebusy = -1;
+ for (count = 0; count < nt_naudiobuffer; count++)
+ {
+ int donethis =
+ (ntsnd_outvec[nda][phase2].lpWaveHdr->dwFlags & WHDR_DONE);
+ int donenext =
+ (ntsnd_outvec[nda][phase3].lpWaveHdr->dwFlags & WHDR_DONE);
+ if (donethis && !donenext)
+ {
+ if (firstphasebusy >= 0) goto multipledac;
+ firstphasebusy = count;
+ }
+ if (!donethis && donenext)
+ {
+ if (firstphasedone >= 0) goto multipledac;
+ firstphasedone = count;
+ }
+ phase2 = phase3;
+ phase3 = WRAPFWD(phase2 + 1);
+ }
+ if (firstphasebusy < 0) post("nda %d phase %d all %d",
+ nda, phase, (ntsnd_outvec[nad][0].lpWaveHdr->dwFlags & WHDR_DONE));
+ else post("nda %d phase %d busy %d done %d", nda, phase, firstphasebusy,
+ firstphasedone);
+ continue;
+ multipledac:
+ startpost("nda %d phase %d: oops:", nda, phase);
+ for (count = 0; count < nt_naudiobuffer; count++)
+ {
+ char buf[80];
+ sprintf(buf, " %d",
+ (ntsnd_outvec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE));
+ poststring(buf);
+ }
+ endpost();
+ }
+}
+#endif /* 0 */
+
+/* this is a hack to avoid ever resyncing audio pointers in case for whatever
+reason the sync testing below gives false positives. */
+
+static int nt_resync_cancelled;
+
+void nt_noresync( void)
+{
+ nt_resync_cancelled = 1;
+}
+
+static void nt_resyncaudio(void)
+{
+ UINT mmresult;
+ int nad, nda, count;
+ if (nt_resync_cancelled)
+ return;
+ /* for each open input device, eat all buffers which are marked
+ ready. The next one will thus be "busy". */
+ post("resyncing audio");
+ for (nad = 0; nad < nt_nwavein; nad++)
+ {
+ int phase = ntsnd_inphase[nad];
+ for (count = 0; count < MAXRESYNC; count++)
+ {
+ WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
+ if (!(inwavehdr->dwFlags & WHDR_DONE)) break;
+ if (inwavehdr->dwFlags & WHDR_PREPARED)
+ waveInUnprepareHeader(ntsnd_indev[nad],
+ inwavehdr, sizeof(WAVEHDR));
+ inwavehdr->dwFlags = 0L;
+ waveInPrepareHeader(ntsnd_indev[nad], inwavehdr, sizeof(WAVEHDR));
+ mmresult = waveInAddBuffer(ntsnd_indev[nad], inwavehdr,
+ sizeof(WAVEHDR));
+ if (mmresult != MMSYSERR_NOERROR)
+ nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
+ ntsnd_inphase[nad] = phase = WRAPFWD(phase + 1);
+ }
+ if (count == MAXRESYNC) post("resync error 1");
+ }
+ /* Each output buffer which is "ready" is filled with zeros and
+ queued. */
+ for (nda = 0; nda < nt_nwaveout; nda++)
+ {
+ int phase = ntsnd_outphase[nda];
+ for (count = 0; count < MAXRESYNC; count++)
+ {
+ WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
+ if (!(outwavehdr->dwFlags & WHDR_DONE)) break;
+ if (outwavehdr->dwFlags & WHDR_PREPARED)
+ waveOutUnprepareHeader(ntsnd_outdev[nda],
+ outwavehdr, sizeof(WAVEHDR));
+ outwavehdr->dwFlags = 0L;
+ memset((char *)(ntsnd_outvec[nda][phase].lpData),
+ 0, (CHANNELS_PER_DEVICE * REALDACBLKSIZE * SAMPSIZE));
+ waveOutPrepareHeader(ntsnd_outdev[nda], outwavehdr,
+ sizeof(WAVEHDR));
+ mmresult = waveOutWrite(ntsnd_outdev[nda], outwavehdr,
+ sizeof(WAVEHDR));
+ if (mmresult != MMSYSERR_NOERROR)
+ nt_waveouterror("waveOutAddBuffer: %s\n", mmresult);
+ ntsnd_outphase[nda] = phase = WRAPFWD(phase + 1);
+ }
+ if (count == MAXRESYNC) post("resync error 2");
+ }
+
+#ifdef MIDI_TIMESTAMP
+ nt_resetmidisync();
+#endif
+
+}
+
+#define LATE 0
+#define RESYNC 1
+#define NOTHING 2
+static int nt_errorcount;
+static int nt_resynccount;
+static double nt_nextreporttime = -1;
+
+void nt_logerror(int which)
+{
+#if 0
+ post("error %d %d", count, which);
+ if (which < NOTHING) nt_errorcount++;
+ if (which == RESYNC) nt_resynccount++;
+ if (sys_getrealtime() > nt_nextreporttime)
+ {
+ post("%d audio I/O error%s", nt_errorcount,
+ (nt_errorcount > 1 ? "s" : ""));
+ if (nt_resynccount) post("DAC/ADC sync error");
+ nt_errorcount = nt_resynccount = 0;
+ nt_nextreporttime = sys_getrealtime() - 5;
+ }
+#endif
+}
+
+/* system buffer with t_sample types for one tick */
+t_sample *sys_soundout;
+t_sample *sys_soundin;
+float sys_dacsr;
+
+int mmio_send_dacs(void)
+{
+ HMMIO hmmio;
+ UINT mmresult;
+ HANDLE hFormat;
+ int i, j;
+ short *sp1, *sp2;
+ float *fp1, *fp2;
+ int nextfill, doxfer = 0;
+ int nda, nad;
+ if (!nt_nwavein && !nt_nwaveout) return (0);
+
+
+ if (nt_meters)
+ {
+ int i, n;
+ float maxsamp;
+ for (i = 0, n = 2 * nt_nwavein * DACBLKSIZE, maxsamp = nt_inmax;
+ i < n; i++)
+ {
+ float f = sys_soundin[i];
+ if (f > maxsamp) maxsamp = f;
+ else if (-f > maxsamp) maxsamp = -f;
+ }
+ nt_inmax = maxsamp;
+ for (i = 0, n = 2 * nt_nwaveout * DACBLKSIZE, maxsamp = nt_outmax;
+ i < n; i++)
+ {
+ float f = sys_soundout[i];
+ if (f > maxsamp) maxsamp = f;
+ else if (-f > maxsamp) maxsamp = -f;
+ }
+ nt_outmax = maxsamp;
+ }
+
+ /* the "fill pointer" nt_fill controls where in the next
+ I/O buffers we will write and/or read. If it's zero, we
+ first check whether the buffers are marked "done". */
+
+ if (!nt_fill)
+ {
+ for (nad = 0; nad < nt_nwavein; nad++)
+ {
+ int phase = ntsnd_inphase[nad];
+ WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
+ if (!(inwavehdr->dwFlags & WHDR_DONE)) goto idle;
+ }
+ for (nda = 0; nda < nt_nwaveout; nda++)
+ {
+ int phase = ntsnd_outphase[nda];
+ WAVEHDR *outwavehdr =
+ ntsnd_outvec[nda][phase].lpWaveHdr;
+ if (!(outwavehdr->dwFlags & WHDR_DONE)) goto idle;
+ }
+ for (nad = 0; nad < nt_nwavein; nad++)
+ {
+ int phase = ntsnd_inphase[nad];
+ WAVEHDR *inwavehdr =
+ ntsnd_invec[nad][phase].lpWaveHdr;
+ if (inwavehdr->dwFlags & WHDR_PREPARED)
+ waveInUnprepareHeader(ntsnd_indev[nad],
+ inwavehdr, sizeof(WAVEHDR));
+ }
+ for (nda = 0; nda < nt_nwaveout; nda++)
+ {
+ int phase = ntsnd_outphase[nda];
+ WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
+ if (outwavehdr->dwFlags & WHDR_PREPARED)
+ waveOutUnprepareHeader(ntsnd_outdev[nda],
+ outwavehdr, sizeof(WAVEHDR));
+ }
+ }
+
+ /* Convert audio output to fixed-point and put it in the output
+ buffer. */
+ for (nda = 0, fp1 = sys_soundout; nda < nt_nwaveout; nda++)
+ {
+ int phase = ntsnd_outphase[nda];
+
+ for (i = 0, sp1 = (short *)(ntsnd_outvec[nda][phase].lpData) +
+ CHANNELS_PER_DEVICE * nt_fill;
+ i < 2; i++, fp1 += DACBLKSIZE, sp1++)
+ {
+ for (j = 0, fp2 = fp1, sp2 = sp1; j < DACBLKSIZE;
+ j++, fp2++, sp2 += CHANNELS_PER_DEVICE)
+ {
+ int x1 = 32767.f * *fp2;
+ if (x1 > 32767) x1 = 32767;
+ else if (x1 < -32767) x1 = -32767;
+ *sp2 = x1;
+ }
+ }
+ }
+ memset(sys_soundout, 0,
+ (DACBLKSIZE*sizeof(t_sample)*CHANNELS_PER_DEVICE)*nt_nwaveout);
+
+ /* vice versa for the input buffer */
+
+ for (nad = 0, fp1 = sys_soundin; nad < nt_nwavein; nad++)
+ {
+ int phase = ntsnd_inphase[nad];
+
+ for (i = 0, sp1 = (short *)(ntsnd_invec[nad][phase].lpData) +
+ CHANNELS_PER_DEVICE * nt_fill;
+ i < 2; i++, fp1 += DACBLKSIZE, sp1++)
+ {
+ for (j = 0, fp2 = fp1, sp2 = sp1; j < DACBLKSIZE;
+ j++, fp2++, sp2 += CHANNELS_PER_DEVICE)
+ {
+ *fp2 = ((float)(1./32767.)) * (float)(*sp2);
+ }
+ }
+ }
+
+ nt_fill = nt_fill + DACBLKSIZE;
+ if (nt_fill == REALDACBLKSIZE)
+ {
+ nt_fill = 0;
+
+ for (nad = 0; nad < nt_nwavein; nad++)
+ {
+ int phase = ntsnd_inphase[nad];
+ HWAVEIN device = ntsnd_indev[nad];
+ WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
+ waveInPrepareHeader(device, inwavehdr, sizeof(WAVEHDR));
+ mmresult = waveInAddBuffer(device, inwavehdr, sizeof(WAVEHDR));
+ if (mmresult != MMSYSERR_NOERROR)
+ nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
+ ntsnd_inphase[nad] = WRAPFWD(phase + 1);
+ }
+ for (nda = 0; nda < nt_nwaveout; nda++)
+ {
+ int phase = ntsnd_outphase[nda];
+ HWAVEOUT device = ntsnd_outdev[nda];
+ WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
+ waveOutPrepareHeader(device, outwavehdr, sizeof(WAVEHDR));
+ mmresult = waveOutWrite(device, outwavehdr, sizeof(WAVEHDR));
+ if (mmresult != MMSYSERR_NOERROR)
+ nt_waveouterror("waveOutWrite: %s\n", mmresult);
+ ntsnd_outphase[nda] = WRAPFWD(phase + 1);
+ }
+
+ /* check for DAC underflow or ADC overflow. */
+ for (nad = 0; nad < nt_nwavein; nad++)
+ {
+ int phase = WRAPBACK(ntsnd_inphase[nad] - 2);
+ WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
+ if (inwavehdr->dwFlags & WHDR_DONE) goto late;
+ }
+ for (nda = 0; nda < nt_nwaveout; nda++)
+ {
+ int phase = WRAPBACK(ntsnd_outphase[nda] - 2);
+ WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
+ if (outwavehdr->dwFlags & WHDR_DONE) goto late;
+ }
+ }
+ return (1);
+
+late:
+
+ nt_logerror(LATE);
+ nt_resyncaudio();
+ return (1);
+
+idle:
+
+ /* If more than nt_adcjitterbufsallowed ADC buffers are ready
+ on any input device, resynchronize */
+
+ for (nad = 0; nad < nt_nwavein; nad++)
+ {
+ int phase = ntsnd_inphase[nad];
+ WAVEHDR *inwavehdr =
+ ntsnd_invec[nad]
+ [WRAPFWD(phase + nt_adcjitterbufsallowed)].lpWaveHdr;
+ if (inwavehdr->dwFlags & WHDR_DONE)
+ {
+ nt_resyncaudio();
+ return (0);
+ }
+ }
+
+ /* test dac sync the same way */
+ for (nda = 0; nda < nt_nwaveout; nda++)
+ {
+ int phase = ntsnd_outphase[nda];
+ WAVEHDR *outwavehdr =
+ ntsnd_outvec[nda]
+ [WRAPFWD(phase + nt_dacjitterbufsallowed)].lpWaveHdr;
+ if (outwavehdr->dwFlags & WHDR_DONE)
+ {
+ nt_resyncaudio();
+ return (0);
+ }
+ }
+#ifdef MIDI_TIMESTAMP
+ nt_midisync();
+#endif
+ return (0);
+}
+
+
+static void nt_setchsr(int inchannels, int outchannels, int sr)
+{
+ int inbytes = inchannels * (DACBLKSIZE*sizeof(float));
+ int outbytes = outchannels * (DACBLKSIZE*sizeof(float));
+
+ if (nt_nwavein)
+ free(sys_soundin);
+ if (nt_nwaveout)
+ free(sys_soundout);
+
+ nt_nwavein = inchannels/CHANNELS_PER_DEVICE;
+ nt_nwaveout = outchannels/CHANNELS_PER_DEVICE;
+ sys_dacsr = sr;
+
+ sys_soundin = (t_float *)malloc(inbytes);
+ memset(sys_soundin, 0, inbytes);
+
+ sys_soundout = (t_float *)malloc(outbytes);
+ memset(sys_soundout, 0, outbytes);
+
+ nt_advance_samples = (sys_schedadvance * sys_dacsr) / (1000000.);
+ if (nt_advance_samples < 3 * DACBLKSIZE)
+ nt_advance_samples = 3 * DACBLKSIZE;
+}
+
+/* ------------------------- MIDI output -------------------------- */
+static void nt_midiouterror(char *s, int err)
+{
+ char t[256];
+ midiOutGetErrorText(err, t, 256);
+ fprintf(stderr, s, t);
+}
+
+static HMIDIOUT hMidiOut[MAXMIDIOUTDEV]; /* output device */
+static int nt_nmidiout; /* number of devices */
+
+static void nt_open_midiout(int nmidiout, int *midioutvec)
+{
+ UINT result, wRtn;
+ int i;
+ int dev;
+ MIDIOUTCAPS midioutcaps;
+ if (nmidiout > MAXMIDIOUTDEV)
+ nmidiout = MAXMIDIOUTDEV;
+
+ dev = 0;
+
+ for (i = 0; i < nmidiout; i++)
+ {
+ MIDIOUTCAPS mocap;
+ result = midiOutOpen(&hMidiOut[dev], midioutvec[i]-1, 0, 0,
+ CALLBACK_NULL);
+ wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) &mocap,
+ sizeof(mocap));
+ if (result != MMSYSERR_NOERROR)
+ {
+ fprintf(stderr,"midiOutOpen: %s\n",midioutcaps.szPname);
+ nt_midiouterror("midiOutOpen: %s\n", result);
+ }
+ else
+ {
+ if (sys_verbose)
+ fprintf(stderr,"midiOutOpen: Open %s as Port %d\n",
+ midioutcaps.szPname, dev);
+ dev++;
+ }
+ }
+ nt_nmidiout = dev;
+}
+
+void sys_putmidimess(int portno, int a, int b, int c)
+{
+ DWORD foo;
+ MMRESULT res;
+ if (portno >= 0 && portno < nt_nmidiout)
+ {
+ foo = (a & 0xff) | ((b & 0xff) << 8) | ((c & 0xff) << 16);
+ res = midiOutShortMsg(hMidiOut[portno], foo);
+ if (res != MMSYSERR_NOERROR)
+ post("MIDI out error %d", res);
+ }
+}
+
+void sys_putmidibyte(int portno, int byte)
+{
+ MMRESULT res;
+ if (portno >= 0 && portno < nt_nmidiout)
+ {
+ res = midiOutShortMsg(hMidiOut[portno], byte);
+ if (res != MMSYSERR_NOERROR)
+ post("MIDI out error %d", res);
+ }
+}
+
+static void nt_close_midiout(void)
+{
+ int i;
+ for (i = 0; i < nt_nmidiout; i++)
+ {
+ midiOutReset(hMidiOut[i]);
+ midiOutClose(hMidiOut[i]);
+ }
+ nt_nmidiout = 0;
+}
+
+/* -------------------------- MIDI input ---------------------------- */
+
+#define INPUT_BUFFER_SIZE 1000 // size of input buffer in events
+
+static void nt_midiinerror(char *s, int err)
+{
+ char t[256];
+ midiInGetErrorText(err, t, 256);
+ fprintf(stderr, s, t);
+}
+
+
+/* Structure to represent a single MIDI event.
+ */
+
+#define EVNT_F_ERROR 0x00000001L
+
+typedef struct event_tag
+{
+ DWORD fdwEvent;
+ DWORD dwDevice;
+ LARGE_INTEGER timestamp;
+ DWORD data;
+} EVENT;
+typedef EVENT FAR *LPEVENT;
+
+/* Structure to manage the circular input buffer.
+ */
+typedef struct circularBuffer_tag
+{
+ HANDLE hSelf; /* handle to this structure */
+ HANDLE hBuffer; /* buffer handle */
+ WORD wError; /* error flags */
+ DWORD dwSize; /* buffer size (in EVENTS) */
+ DWORD dwCount; /* byte count (in EVENTS) */
+ LPEVENT lpStart; /* ptr to start of buffer */
+ LPEVENT lpEnd; /* ptr to end of buffer (last byte + 1) */
+ LPEVENT lpHead; /* ptr to head (next location to fill) */
+ LPEVENT lpTail; /* ptr to tail (next location to empty) */
+} CIRCULARBUFFER;
+typedef CIRCULARBUFFER FAR *LPCIRCULARBUFFER;
+
+
+/* Structure to pass instance data from the application
+ to the low-level callback function.
+ */
+typedef struct callbackInstance_tag
+{
+ HANDLE hSelf;
+ DWORD dwDevice;
+ LPCIRCULARBUFFER lpBuf;
+} CALLBACKINSTANCEDATA;
+typedef CALLBACKINSTANCEDATA FAR *LPCALLBACKINSTANCEDATA;
+
+/* Function prototypes
+ */
+LPCALLBACKINSTANCEDATA FAR PASCAL AllocCallbackInstanceData(void);
+void FAR PASCAL FreeCallbackInstanceData(LPCALLBACKINSTANCEDATA lpBuf);
+
+LPCIRCULARBUFFER AllocCircularBuffer(DWORD dwSize);
+void FreeCircularBuffer(LPCIRCULARBUFFER lpBuf);
+WORD FAR PASCAL GetEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent);
+
+// Callback instance data pointers
+LPCALLBACKINSTANCEDATA lpCallbackInstanceData[MAXMIDIINDEV];
+
+UINT wNumDevices = 0; // Number of MIDI input devices opened
+BOOL bRecordingEnabled = 1; // Enable/disable recording flag
+int nNumBufferLines = 0; // Number of lines in display buffer
+RECT rectScrollClip; // Clipping rectangle for scrolling
+
+LPCIRCULARBUFFER lpInputBuffer; // Input buffer structure
+EVENT incomingEvent; // Incoming MIDI event structure
+
+MIDIINCAPS midiInCaps[MAXMIDIINDEV]; // Device capabilities structures
+HMIDIIN hMidiIn[MAXMIDIINDEV]; // MIDI input device handles
+
+
+/* AllocCallbackInstanceData - Allocates a CALLBACKINSTANCEDATA
+ * structure. This structure is used to pass information to the
+ * low-level callback function, each time it receives a message.
+ *
+ * Because this structure is accessed by the low-level callback
+ * function, it must be allocated using GlobalAlloc() with the
+ * GMEM_SHARE and GMEM_MOVEABLE flags and page-locked with
+ * GlobalPageLock().
+ *
+ * Params: void
+ *
+ * Return: A pointer to the allocated CALLBACKINSTANCE data structure.
+ */
+LPCALLBACKINSTANCEDATA FAR PASCAL AllocCallbackInstanceData(void)
+{
+ HANDLE hMem;
+ LPCALLBACKINSTANCEDATA lpBuf;
+
+ /* Allocate and lock global memory.
+ */
+ hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE,
+ (DWORD)sizeof(CALLBACKINSTANCEDATA));
+ if(hMem == NULL)
+ return NULL;
+
+ lpBuf = (LPCALLBACKINSTANCEDATA)GlobalLock(hMem);
+ if(lpBuf == NULL){
+ GlobalFree(hMem);
+ return NULL;
+ }
+
+ /* Page lock the memory.
+ */
+ //GlobalPageLock((HGLOBAL)HIWORD(lpBuf));
+
+ /* Save the handle.
+ */
+ lpBuf->hSelf = hMem;
+
+ return lpBuf;
+}
+
+/* FreeCallbackInstanceData - Frees the given CALLBACKINSTANCEDATA structure.
+ *
+ * Params: lpBuf - Points to the CALLBACKINSTANCEDATA structure to be freed.
+ *
+ * Return: void
+ */
+void FAR PASCAL FreeCallbackInstanceData(LPCALLBACKINSTANCEDATA lpBuf)
+{
+ HANDLE hMem;
+
+ /* Save the handle until we're through here.
+ */
+ hMem = lpBuf->hSelf;
+
+ /* Free the structure.
+ */
+ //GlobalPageUnlock((HGLOBAL)HIWORD(lpBuf));
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+}
+
+
+/*
+ * AllocCircularBuffer - Allocates memory for a CIRCULARBUFFER structure
+ * and a buffer of the specified size. Each memory block is allocated
+ * with GlobalAlloc() using GMEM_SHARE and GMEM_MOVEABLE flags, locked
+ * with GlobalLock(), and page-locked with GlobalPageLock().
+ *
+ * Params: dwSize - The size of the buffer, in events.
+ *
+ * Return: A pointer to a CIRCULARBUFFER structure identifying the
+ * allocated display buffer. NULL if the buffer could not be allocated.
+ */
+
+
+LPCIRCULARBUFFER AllocCircularBuffer(DWORD dwSize)
+{
+ HANDLE hMem;
+ LPCIRCULARBUFFER lpBuf;
+ LPEVENT lpMem;
+
+ /* Allocate and lock a CIRCULARBUFFER structure.
+ */
+ hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE,
+ (DWORD)sizeof(CIRCULARBUFFER));
+ if(hMem == NULL)
+ return NULL;
+
+ lpBuf = (LPCIRCULARBUFFER)GlobalLock(hMem);
+ if(lpBuf == NULL)
+ {
+ GlobalFree(hMem);
+ return NULL;
+ }
+
+ /* Page lock the memory. Global memory blocks accessed by
+ * low-level callback functions must be page locked.
+ */
+#ifndef _WIN32
+ GlobalSmartPageLock((HGLOBAL)HIWORD(lpBuf));
+#endif
+
+ /* Save the memory handle.
+ */
+ lpBuf->hSelf = hMem;
+
+ /* Allocate and lock memory for the actual buffer.
+ */
+ hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, dwSize * sizeof(EVENT));
+ if(hMem == NULL)
+ {
+#ifndef _WIN32
+ GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf));
+#endif
+ GlobalUnlock(lpBuf->hSelf);
+ GlobalFree(lpBuf->hSelf);
+ return NULL;
+ }
+
+ lpMem = (LPEVENT)GlobalLock(hMem);
+ if(lpMem == NULL)
+ {
+ GlobalFree(hMem);
+#ifndef _WIN32
+ GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf));
+#endif
+ GlobalUnlock(lpBuf->hSelf);
+ GlobalFree(lpBuf->hSelf);
+ return NULL;
+ }
+
+ /* Page lock the memory. Global memory blocks accessed by
+ * low-level callback functions must be page locked.
+ */
+#ifndef _WIN32
+ GlobalSmartPageLock((HGLOBAL)HIWORD(lpMem));
+#endif
+
+ /* Set up the CIRCULARBUFFER structure.
+ */
+ lpBuf->hBuffer = hMem;
+ lpBuf->wError = 0;
+ lpBuf->dwSize = dwSize;
+ lpBuf->dwCount = 0L;
+ lpBuf->lpStart = lpMem;
+ lpBuf->lpEnd = lpMem + dwSize;
+ lpBuf->lpTail = lpMem;
+ lpBuf->lpHead = lpMem;
+
+ return lpBuf;
+}
+
+/* FreeCircularBuffer - Frees the memory for the given CIRCULARBUFFER
+ * structure and the memory for the buffer it references.
+ *
+ * Params: lpBuf - Points to the CIRCULARBUFFER to be freed.
+ *
+ * Return: void
+ */
+void FreeCircularBuffer(LPCIRCULARBUFFER lpBuf)
+{
+ HANDLE hMem;
+
+ /* Free the buffer itself.
+ */
+#ifndef _WIN32
+ GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf->lpStart));
+#endif
+ GlobalUnlock(lpBuf->hBuffer);
+ GlobalFree(lpBuf->hBuffer);
+
+ /* Free the CIRCULARBUFFER structure.
+ */
+ hMem = lpBuf->hSelf;
+#ifndef _WIN32
+ GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf));
+#endif
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+}
+
+/* GetEvent - Gets a MIDI event from the circular input buffer. Events
+ * are removed from the buffer. The corresponding PutEvent() function
+ * is called by the low-level callback function, so it must reside in
+ * the callback DLL. PutEvent() is defined in the CALLBACK.C module.
+ *
+ * Params: lpBuf - Points to the circular buffer.
+ * lpEvent - Points to an EVENT structure that is filled with the
+ * retrieved event.
+ *
+ * Return: Returns non-zero if successful, zero if there are no
+ * events to get.
+ */
+WORD FAR PASCAL GetEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent)
+{
+ /* If no event available, return */
+ if (!wNumDevices || lpBuf->dwCount <= 0) return (0);
+
+ /* Get the event.
+ */
+ *lpEvent = *lpBuf->lpTail;
+
+ /* Decrement the byte count, bump the tail pointer.
+ */
+ --lpBuf->dwCount;
+ ++lpBuf->lpTail;
+
+ /* Wrap the tail pointer, if necessary.
+ */
+ if(lpBuf->lpTail >= lpBuf->lpEnd)
+ lpBuf->lpTail = lpBuf->lpStart;
+
+ return 1;
+}
+
+/* PutEvent - Puts an EVENT in a CIRCULARBUFFER. If the buffer is full,
+ * it sets the wError element of the CIRCULARBUFFER structure
+ * to be non-zero.
+ *
+ * Params: lpBuf - Points to the CIRCULARBUFFER.
+ * lpEvent - Points to the EVENT.
+ *
+ * Return: void
+*/
+
+void FAR PASCAL PutEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent)
+{
+ /* If the buffer is full, set an error and return.
+ */
+ if(lpBuf->dwCount >= lpBuf->dwSize){
+ lpBuf->wError = 1;
+ return;
+ }
+
+ /* Put the event in the buffer, bump the head pointer and the byte count.
+ */
+ *lpBuf->lpHead = *lpEvent;
+
+ ++lpBuf->lpHead;
+ ++lpBuf->dwCount;
+
+ /* Wrap the head pointer, if necessary.
+ */
+ if(lpBuf->lpHead >= lpBuf->lpEnd)
+ lpBuf->lpHead = lpBuf->lpStart;
+}
+
+/* midiInputHandler - Low-level callback function to handle MIDI input.
+ * Installed by midiInOpen(). The input handler takes incoming
+ * MIDI events and places them in the circular input buffer. It then
+ * notifies the application by posting a MM_MIDIINPUT message.
+ *
+ * This function is accessed at interrupt time, so it should be as
+ * fast and efficient as possible. You can't make any
+ * Windows calls here, except PostMessage(). The only Multimedia
+ * Windows call you can make are timeGetSystemTime(), midiOutShortMsg().
+ *
+ *
+ * Param: hMidiIn - Handle for the associated input device.
+ * wMsg - One of the MIM_***** messages.
+ * dwInstance - Points to CALLBACKINSTANCEDATA structure.
+ * dwParam1 - MIDI data.
+ * dwParam2 - Timestamp (in milliseconds)
+ *
+ * Return: void
+ */
+void FAR PASCAL midiInputHandler(
+HMIDIIN hMidiIn,
+WORD wMsg,
+DWORD dwInstance,
+DWORD dwParam1,
+DWORD dwParam2)
+{
+ EVENT event;
+
+ switch(wMsg)
+ {
+ case MIM_OPEN:
+ break;
+
+ /* The only error possible is invalid MIDI data, so just pass
+ * the invalid data on so we'll see it.
+ */
+ case MIM_ERROR:
+ case MIM_DATA:
+ event.fdwEvent = (wMsg == MIM_ERROR) ? EVNT_F_ERROR : 0;
+ event.dwDevice = ((LPCALLBACKINSTANCEDATA)dwInstance)->dwDevice;
+ event.data = dwParam1;
+#ifdef MIDI_TIMESTAMP
+ event.timestamp = timeGetSystemTime();
+#endif
+ /* Put the MIDI event in the circular input buffer.
+ */
+
+ PutEvent(((LPCALLBACKINSTANCEDATA)dwInstance)->lpBuf,
+ (LPEVENT) &event);
+
+ break;
+
+ default:
+ break;
+ }
+}
+
+void nt_open_midiin(int nmidiin, int *midiinvec)
+{
+ UINT wRtn;
+ char szErrorText[256];
+ unsigned int i;
+ unsigned int ndev = 0;
+ /* Allocate a circular buffer for low-level MIDI input. This buffer
+ * is filled by the low-level callback function and emptied by the
+ * application.
+ */
+ lpInputBuffer = AllocCircularBuffer((DWORD)(INPUT_BUFFER_SIZE));
+ if (lpInputBuffer == NULL)
+ {
+ printf("Not enough memory available for input buffer.\n");
+ return;
+ }
+
+ /* Open all MIDI input devices after allocating and setting up
+ * instance data for each device. The instance data is used to
+ * pass buffer management information between the application and
+ * the low-level callback function. It also includes a device ID,
+ * a handle to the MIDI Mapper, and a handle to the application's
+ * display window, so the callback can notify the window when input
+ * data is available. A single callback function is used to service
+ * all opened input devices.
+ */
+ for (i=0; (i<(unsigned)nmidiin) && (i<MAXMIDIINDEV); i++)
+ {
+ if ((lpCallbackInstanceData[ndev] = AllocCallbackInstanceData()) == NULL)
+ {
+ printf("Not enough memory available.\n");
+ FreeCircularBuffer(lpInputBuffer);
+ return;
+ }
+ lpCallbackInstanceData[i]->dwDevice = i;
+ lpCallbackInstanceData[i]->lpBuf = lpInputBuffer;
+
+ wRtn = midiInOpen((LPHMIDIIN)&hMidiIn[ndev],
+ midiinvec[i] - 1,
+ (DWORD)midiInputHandler,
+ (DWORD)lpCallbackInstanceData[ndev],
+ CALLBACK_FUNCTION);
+ if (wRtn)
+ {
+ FreeCallbackInstanceData(lpCallbackInstanceData[ndev]);
+ nt_midiinerror("midiInOpen: %s\n", wRtn);
+ }
+ else ndev++;
+ }
+
+ /* Start MIDI input.
+ */
+ for (i=0; i<ndev; i++)
+ {
+ if (hMidiIn[i])
+ midiInStart(hMidiIn[i]);
+ }
+ wNumDevices = ndev;
+}
+
+static void nt_close_midiin(void)
+{
+ unsigned int i;
+ /* Stop, reset, close MIDI input. Free callback instance data.
+ */
+
+ for (i=0; (i<wNumDevices) && (i<MAXMIDIINDEV); i++)
+ {
+ if (hMidiIn[i])
+ {
+ if (sys_verbose)
+ post("closing MIDI input %d...", i);
+ midiInStop(hMidiIn[i]);
+ midiInReset(hMidiIn[i]);
+ midiInClose(hMidiIn[i]);
+ FreeCallbackInstanceData(lpCallbackInstanceData[i]);
+ }
+ }
+
+ /* Free input buffer.
+ */
+ if (lpInputBuffer)
+ FreeCircularBuffer(lpInputBuffer);
+
+ if (sys_verbose)
+ post("...done");
+ wNumDevices = 0;
+}
+
+void inmidi_noteon(int portno, int channel, int pitch, int velo);
+void inmidi_controlchange(int portno, int channel, int ctlnumber, int value);
+void inmidi_programchange(int portno, int channel, int value);
+void inmidi_pitchbend(int portno, int channel, int value);
+void inmidi_aftertouch(int portno, int channel, int value);
+void inmidi_polyaftertouch(int portno, int channel, int pitch, int value);
+void inmidi_realtimein(int portno, int rtmsg);
+
+void sys_poll_midi(void)
+{
+ static EVENT nt_nextevent;
+ static int nt_isnextevent;
+ static double nt_nexteventtime;
+
+ while (1)
+ {
+ if (!nt_isnextevent)
+ {
+ if (!GetEvent(lpInputBuffer, &nt_nextevent)) break;
+ nt_isnextevent = 1;
+#ifdef MIDI_TIMESTAMP
+ nt_nexteventtime = nt_midigettimefor(&foo.timestamp);
+#endif
+ }
+#ifdef MIDI_TIMESTAMP
+ if (0.001 * clock_gettimesince(initsystime) >= nt_nexteventtime)
+#endif
+ {
+ int msgtype = ((nt_nextevent.data & 0xf0) >> 4) - 8;
+ int commandbyte = nt_nextevent.data & 0xff;
+ int byte1 = (nt_nextevent.data >> 8) & 0xff;
+ int byte2 = (nt_nextevent.data >> 16) & 0xff;
+ int portno = nt_nextevent.dwDevice;
+ switch (msgtype)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 6:
+ sys_midibytein(portno, commandbyte);
+ sys_midibytein(portno, byte1);
+ sys_midibytein(portno, byte2);
+ break;
+ case 4:
+ case 5:
+ sys_midibytein(portno, commandbyte);
+ sys_midibytein(portno, byte1);
+ break;
+ case 7:
+ sys_midibytein(portno, commandbyte);
+ break;
+ }
+ nt_isnextevent = 0;
+ }
+ }
+}
+
+/* ------------------- public routines -------------------------- */
+
+void sys_open_audio(int naudioindev, int *audioindev,
+ int nchindev, int *chindev, int naudiooutdev, int *audiooutdev,
+ int nchoutdev, int *choutdev, int rate) /* IOhannes */
+{
+ int inchans, outchans;
+ if (nchindev < 0)
+ inchans = (nchindev < 1 ? -1 : chindev[0]);
+ else
+ {
+ int i = nchindev;
+ int *l = chindev;
+ inchans = 0;
+ while (i--)
+ inchans += *l++;
+ }
+ if (nchoutdev<0)
+ outchans = (nchoutdev < 1 ? -1 : choutdev[0]);
+ else
+ {
+ int i = nchoutdev;
+ int *l = choutdev;
+ outchans = 0;
+ while (i--)
+ outchans += *l++;
+ }
+ if (inchans < 0)
+ inchans = DEFAULTCHANS;
+ if (outchans < 0)
+ outchans = DEFAULTCHANS;
+ if (inchans & 1)
+ {
+ post("input channels rounded up to even number");
+ inchans += 1;
+ }
+ if (outchans & 1)
+ {
+ post("output channels rounded up to even number");
+ outchans += 1;
+ }
+ if (inchans > NT_MAXCH)
+ inchans = NT_MAXCH;
+ if (outchans > NT_MAXCH)
+ outchans = NT_MAXCH;
+ if (sys_verbose)
+ post("channels in %d, out %d", inchans, outchans);
+ if (rate < 1)
+ rate = DEFAULTSRATE;
+ nt_setchsr(inchans, outchans, rate);
+ if (nt_whichapi == API_PORTAUDIO)
+ {
+ int blocksize = (nt_blocksize ? nt_blocksize : 256);
+ if (blocksize != (1 << ilog2(blocksize)))
+ post("warning: blocksize adjusted to power of 2: %d",
+ (blocksize = (1 << ilog2(blocksize))));
+ pa_open_audio(inchans, outchans, rate, sys_soundin, sys_soundout,
+ blocksize, nt_advance_samples/blocksize,
+ (naudioindev < 1 ? -1 : audioindev[0]),
+ (naudiooutdev < 1 ? -1 : audiooutdev[0]));
+ }
+ else
+ {
+ nt_nwavein = inchans / 2;
+ nt_nwaveout = outchans / 2;
+ nt_whichdac = (naudiooutdev < 1 ? (nt_nwaveout > 1 ? 0 : -1) : audiooutdev[0] - 1);
+ nt_whichadc = (naudioindev < 1 ? (nt_nwavein > 1 ? 0 : -1) : audioindev[0] - 1);
+ if (naudiooutdev > 1 || naudioindev > 1)
+ post("separate audio device choice not supported; using sequential devices.");
+ if (nt_blocksize)
+ post("warning: blocksize not settable for MMIO, just ASIO");
+ mmio_open_audio();
+ }
+}
+
+void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec)
+{
+ if (nmidiout)
+ nt_open_midiout(nmidiout, midioutvec);
+ if (nmidiin)
+ {
+ post(
+ "midi input enabled; warning, don't close the DOS window directly!");
+ nt_open_midiin(nmidiin, midiinvec);
+ }
+ else post("not using MIDI input (use 'pd -midiindev 1' to override)");
+}
+
+float sys_getsr(void)
+{
+ return (sys_dacsr);
+}
+
+int sys_get_inchannels(void)
+{
+ return (2 * nt_nwavein);
+}
+
+int sys_get_outchannels(void)
+{
+ return (2 * nt_nwaveout);
+}
+
+void sys_audiobuf(int n)
+{
+ /* set the size, in msec, of the audio FIFO. It's incorrect to
+ calculate this on the basis of 44100 sample rate; really, the
+ work should have been done in nt_setchsr(). */
+ int nbuf = n * (44100./(REALDACBLKSIZE * 1000.));
+ if (nbuf >= MAXBUFFER)
+ {
+ fprintf(stderr, "pd: audio buffering maxed out to %d\n",
+ (int)(MAXBUFFER * ((REALDACBLKSIZE * 1000.)/44100.)));
+ nbuf = MAXBUFFER;
+ }
+ else if (nbuf < 4) nbuf = 4;
+ fprintf(stderr, "%d audio buffers\n", nbuf);
+ nt_naudiobuffer = nbuf;
+ if (nt_adcjitterbufsallowed > nbuf - 2)
+ nt_adcjitterbufsallowed = nbuf - 2;
+ if (nt_dacjitterbufsallowed > nbuf - 2)
+ nt_dacjitterbufsallowed = nbuf - 2;
+ sys_schedadvance = 1000 * n;
+}
+
+void sys_getmeters(float *inmax, float *outmax)
+{
+ if (inmax)
+ {
+ nt_meters = 1;
+ *inmax = nt_inmax;
+ *outmax = nt_outmax;
+ }
+ else
+ nt_meters = 0;
+ nt_inmax = nt_outmax = 0;
+}
+
+void sys_reportidle(void)
+{
+}
+
+int sys_send_dacs(void)
+{
+ if (nt_whichapi == API_PORTAUDIO)
+ return (pa_send_dacs());
+ else return (mmio_send_dacs());
+}
+
+void sys_close_audio( void)
+{
+ if (nt_whichapi == API_PORTAUDIO)
+ pa_close_audio();
+ else mmio_close_audio();
+}
+
+void sys_close_midi( void)
+{
+ nt_close_midiin();
+ nt_close_midiout();
+}
+
+void sys_setblocksize(int n)
+{
+ if (n < 1)
+ n = 1;
+ nt_blocksize = n;
+}
+
+/* ----------- public routines which are only defined for MSW/NT ---------- */
+
+/* select between MMIO and ASIO audio APIs */
+void nt_set_sound_api(int which)
+{
+ nt_whichapi = which;
+ if (sys_verbose)
+ post("nt_whichapi %d", nt_whichapi);
+}
+
+/* list the audio and MIDI device names */
+void sys_listdevs(void)
+{
+ UINT wRtn, ndevices;
+ unsigned int i;
+
+ /* for MIDI and audio in and out, get the number of devices.
+ Then get the capabilities of each device and print its description. */
+
+ ndevices = midiInGetNumDevs();
+ for (i = 0; i < ndevices; i++)
+ {
+ MIDIINCAPS micap;
+ wRtn = midiInGetDevCaps(i, (LPMIDIINCAPS) &micap,
+ sizeof(micap));
+ if (wRtn) nt_midiinerror("midiInGetDevCaps: %s\n", wRtn);
+ else fprintf(stderr,
+ "MIDI input device #%d: %s\n", i+1, micap.szPname);
+ }
+
+ ndevices = midiOutGetNumDevs();
+ for (i = 0; i < ndevices; i++)
+ {
+ MIDIOUTCAPS mocap;
+ wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) &mocap,
+ sizeof(mocap));
+ if (wRtn) nt_midiouterror("midiOutGetDevCaps: %s\n", wRtn);
+ else fprintf(stderr,
+ "MIDI output device #%d: %s\n", i+1, mocap.szPname);
+ }
+
+ if (nt_whichapi == API_PORTAUDIO)
+ {
+ pa_listdevs();
+ return;
+ }
+ ndevices = waveInGetNumDevs();
+ for (i = 0; i < ndevices; i++)
+ {
+ WAVEINCAPS wicap;
+ wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap,
+ sizeof(wicap));
+ if (wRtn) nt_waveinerror("waveInGetDevCaps: %s\n", wRtn);
+ else fprintf(stderr,
+ "audio input device #%d: %s\n", i+1, wicap.szPname);
+ }
+
+ ndevices = waveOutGetNumDevs();
+ for (i = 0; i < ndevices; i++)
+ {
+ WAVEOUTCAPS wocap;
+ wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap,
+ sizeof(wocap));
+ if (wRtn) nt_waveouterror("waveOutGetDevCaps: %s\n", wRtn);
+ else fprintf(stderr,
+ "audio output device #%d: %s\n", i+1, wocap.szPname);
+ }
+}
+
+void nt_soundindev(int which)
+{
+ nt_whichadc = which - 1;
+}
+
+void nt_soundoutdev(int which)
+{
+ nt_whichdac = which - 1;
+}
+
+void glob_audio(void *dummy, t_floatarg fadc, t_floatarg fdac)
+{
+ int adc = fadc, dac = fdac;
+ if (!dac && !adc)
+ post("%d channels in, %d channels out",
+ 2 * nt_nwavein, 2 * nt_nwaveout);
+ else
+ {
+ sys_close_audio();
+ sys_open_audio(1, 0, 1, 0, /* dummy parameters */
+ 1, &adc, 1, &dac, sys_dacsr);
+ }
+}
+
diff --git a/pd/src/s_path.c b/pd/src/s_path.c
new file mode 100644
index 00000000..a61956f1
--- /dev/null
+++ b/pd/src/s_path.c
@@ -0,0 +1,279 @@
+/* Copyright (c) 1999 Guenter Geiger and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/*
+ * This file implements the loader for linux, which includes
+ * a little bit of path handling.
+ *
+ * Generalized by MSP to provide an open_via_path function
+ * and lists of files for all purposes.
+ */
+
+/* #define DEBUG(x) x */
+#define DEBUG(x)
+void readsf_banana( void); /* debugging */
+
+#include <stdlib.h>
+#ifdef UNIX
+#include <unistd.h>
+#include <sys/stat.h>
+#endif
+#ifdef NT
+#include <io.h>
+#endif
+
+#include <string.h>
+#include "m_imp.h"
+#include <stdio.h>
+#include <fcntl.h>
+
+static t_namelist *pd_path;
+
+/* Utility functions */
+
+/* copy until delimiter and return position after delimiter in string */
+/* if it was the last substring, return NULL */
+
+static const char* strtokcpy(char *to, const char *from, int delim)
+{
+ int size = 0;
+
+ while (from[size] != (char)delim && from[size] != '\0')
+ size++;
+
+ strncpy(to,from,size);
+ to[size] = '\0';
+ if (from[size] == '\0') return NULL;
+ if (size) return from+size+1;
+ else return NULL;
+}
+
+/* add a colon-separated list of names to a namelist */
+
+#ifdef NT
+#define SEPARATOR ';'
+#else
+#define SEPARATOR ':'
+#endif
+
+static t_namelist *namelist_doappend(t_namelist *listwas, const char *s)
+{
+ t_namelist *nl = listwas, *rtn = listwas, *nl2;
+ nl2 = (t_namelist *)(getbytes(sizeof(*nl)));
+ nl2->nl_next = 0;
+ nl2->nl_string = (char *)getbytes(strlen(s) + 1);
+ strcpy(nl2->nl_string, s);
+ sys_unbashfilename(nl2->nl_string, nl2->nl_string);
+ if (!nl)
+ nl = rtn = nl2;
+ else
+ {
+ while (nl->nl_next)
+ nl = nl->nl_next;
+ nl->nl_next = nl2;
+ }
+ return (rtn);
+
+}
+
+t_namelist *namelist_append(t_namelist *listwas, const char *s)
+{
+ const char *npos;
+ char temp[MAXPDSTRING];
+ t_namelist *nl = listwas, *rtn = listwas;
+
+ npos = s;
+ do
+ {
+ npos = strtokcpy(temp, npos, SEPARATOR);
+ if (! *temp) continue;
+ nl = namelist_doappend(nl, temp);
+ }
+ while (npos);
+ return (nl);
+}
+
+void namelist_free(t_namelist *listwas)
+{
+ t_namelist *nl, *nl2;
+ for (nl = listwas; nl; nl = nl2)
+ {
+ nl2 = nl->nl_next;
+ t_freebytes(nl->nl_string, strlen(nl->nl_string) + 1);
+ t_freebytes(nl, sizeof(*nl));
+ }
+}
+
+void sys_addpath(const char *p)
+{
+ pd_path = namelist_append(pd_path, p);
+}
+
+#ifdef NT
+#define NTOPENFLAG (bin ? _O_BINARY : _O_TEXT)
+#else
+#define NTOPENFLAG 0
+#endif
+
+/* search for a file in a specified directory, then along the globally
+defined search path, using ext as filename extension. Exception:
+if the 'name' starts with a slash or a letter, colon, and slash in NT,
+there is no search and instead we just try to open the file literally. The
+fd is returned, the directory ends up in the "dirresult" which must be at
+least "size" bytes. "nameresult" is set to point to the filename, which
+ends up in the same buffer as dirresult. */
+
+int open_via_path(const char *dir, const char *name, const char* ext,
+ char *dirresult, char **nameresult, unsigned int size, int bin)
+{
+ t_namelist *nl, thislist;
+ int fd = -1;
+ char listbuf[MAXPDSTRING];
+
+ if (name[0] == '/'
+#ifdef NT
+ || (name[1] == ':' && name[2] == '/')
+#endif
+ )
+ {
+ thislist.nl_next = 0;
+ thislist.nl_string = listbuf;
+ listbuf[0] = 0;
+ }
+ else
+ {
+ thislist.nl_string = listbuf;
+ thislist.nl_next = pd_path;
+ strncpy(listbuf, dir, MAXPDSTRING);
+ listbuf[MAXPDSTRING-1] = 0;
+ sys_unbashfilename(listbuf, listbuf);
+ }
+ for (nl = &thislist; nl; nl = nl->nl_next)
+ {
+ if (strlen(nl->nl_string) + strlen(name) + strlen(ext) + 4 >
+ size)
+ continue;
+ strcpy(dirresult, nl->nl_string);
+ if (*dirresult && dirresult[strlen(dirresult)-1] != '/')
+ strcat(dirresult, "/");
+ strcat(dirresult, name);
+ strcat(dirresult, ext);
+ sys_bashfilename(dirresult, dirresult);
+
+ DEBUG(post("looking for %s",dirresult));
+ /* see if we can open the file for reading */
+ if ((fd=open(dirresult,O_RDONLY | NTOPENFLAG)) >= 0)
+ {
+ /* in UNIX, further check that it's not a directory */
+#ifdef UNIX
+ struct stat statbuf;
+ int ok = ((fstat(fd, &statbuf) >= 0) &&
+ !S_ISDIR(statbuf.st_mode));
+ if (!ok)
+ {
+ if (sys_verbose) post("tried %s; stat failed or directory",
+ dirresult);
+ close (fd);
+ fd = -1;
+ }
+ else
+#endif
+ {
+ char *slash;
+ if (sys_verbose) post("tried %s and succeeded", dirresult);
+ sys_unbashfilename(dirresult, dirresult);
+ slash = strrchr(dirresult, '/');
+ if (slash)
+ {
+ *slash = 0;
+ *nameresult = slash + 1;
+ }
+ else *nameresult = dirresult;
+
+ return (fd);
+ }
+ }
+ else
+ {
+ if (sys_verbose) post("tried %s and failed", dirresult);
+ }
+ }
+ *dirresult = 0;
+ *nameresult = dirresult;
+ return (-1);
+}
+
+/* Startup file reading for linux */
+
+#ifdef __linux__
+
+#define STARTUPNAME ".pdrc"
+#define NUMARGS 1000
+
+int sys_argparse(int argc, char **argv);
+
+int sys_rcfile(void)
+{
+ FILE* file;
+ int i;
+ int k;
+ int rcargc;
+ char* rcargv[NUMARGS];
+ char* buffer;
+ char fname[MAXPDSTRING], buf[1000];
+
+ /* parse a startup file */
+
+ *fname = '\0';
+
+ strncat(fname, getenv("HOME"), MAXPDSTRING-10);
+ strcat(fname, "/");
+
+ strcat(fname, STARTUPNAME);
+
+ if (!(file = fopen(fname, "r")))
+ return 1;
+
+ post("reading startup file: %s", fname);
+
+ rcargv[0] = "."; /* this no longer matters to sys_argparse() */
+
+ for (i = 1; i < NUMARGS-1; i++)
+ {
+ if (fscanf(file, "%999s", buf) < 0)
+ break;
+ buf[1000] = 0;
+ if (!(rcargv[i] = malloc(strlen(buf) + 1)))
+ return (1);
+ strcpy(rcargv[i], buf);
+ }
+ if (i >= NUMARGS-1)
+ fprintf(stderr, "startup file too long; extra args dropped\n");
+ rcargv[i] = 0;
+
+ rcargc = i;
+
+ /* parse the options */
+
+ fclose(file);
+ if (sys_verbose)
+ {
+ if (rcargv)
+ {
+ post("startup args from RC file:");
+ for (i = 1; i < rcargc; i++)
+ post("%s", rcargv[i]);
+ }
+ else post("no RC file arguments found");
+ }
+ if (sys_argparse(rcargc, rcargv))
+ {
+ post("error parsing RC arguments");
+ return (1);
+ }
+ return (0);
+}
+#endif /* __linux__ */
+
+
diff --git a/pd/src/s_portaudio.c b/pd/src/s_portaudio.c
new file mode 100644
index 00000000..73dd55ab
--- /dev/null
+++ b/pd/src/s_portaudio.c
@@ -0,0 +1,197 @@
+/* Copyright (c) 2001 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. */
+
+/* this file calls Ross Bencina's and Phil Burk's Portaudio package. It's
+ the main way in for Mac OS and, with Michael Casey's help, also into
+ ASIO in Windows. */
+
+/* dolist.
+ write a version of OpenAudioStream to take nchannels param
+ how do we specify latency?
+ listing devices?
+ choosing devices?
+*/
+
+#include "m_imp.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "pablio_pd.h"
+#include "portaudio.h"
+#ifndef NT
+#include "portmidi.h"
+#include "porttime.h"
+#include "pminternal.h"
+#endif
+
+ /* public interface declared in m_imp.h */
+
+ /* implementation */
+static PABLIO_Stream *pa_stream;
+static int pa_inchans, pa_outchans;
+static float *pa_soundin, *pa_soundout;
+
+#define MAX_PA_CHANS 32
+#define MAX_SAMPLES_PER_FRAME MAX_PA_CHANS * DACBLKSIZE
+
+int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin,
+ t_sample *soundout, int framesperbuf, int nbuffers,
+ int indeviceno, int outdeviceno)
+{
+ PaError err;
+ /* post("in %d out %d rate %d device %d", inchans, outchans, rate, deviceno); */
+ if (inchans != 0 && outchans != 0 && inchans != outchans)
+ error("portaudio: number of input and output channels must match");
+ if (sys_verbose)
+ post("portaudio: opening for %d channels in, %d out",
+ inchans, outchans);
+ if (inchans > MAX_PA_CHANS)
+ {
+ post("input channels reduced to maximum %d", MAX_PA_CHANS);
+ inchans = MAX_PA_CHANS;
+ }
+ if (outchans > MAX_PA_CHANS)
+ {
+ post("output channels reduced to maximum %d", MAX_PA_CHANS);
+ outchans = MAX_PA_CHANS;
+ }
+
+ if (inchans && outchans)
+ err = OpenAudioStream( &pa_stream, rate, paFloat32,
+ PABLIO_READ_WRITE, inchans, framesperbuf, nbuffers, indeviceno, outdeviceno);
+ else if (inchans)
+ err = OpenAudioStream( &pa_stream, rate, paFloat32,
+ PABLIO_READ, inchans, framesperbuf, nbuffers, indeviceno, outdeviceno);
+ else if (outchans)
+ err = OpenAudioStream( &pa_stream, rate, paFloat32,
+ PABLIO_WRITE, outchans, framesperbuf, nbuffers, indeviceno, outdeviceno);
+ else err = 0;
+ if ( err != paNoError )
+ {
+ fprintf( stderr, "Error number %d occured opening portaudio stream\n",
+ err);
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ Pa_Terminate();
+ return (1);
+ }
+ else if (sys_verbose)
+ post("... opened OK.");
+ pa_inchans = inchans;
+ pa_outchans = outchans;
+ pa_soundin = soundin;
+ pa_soundout = soundout;
+ return (0);
+}
+
+void pa_close_audio( void)
+{
+ if (pa_inchans || pa_outchans)
+ CloseAudioStream( pa_stream );
+ pa_inchans = pa_outchans = 0;
+}
+
+int pa_send_dacs(void)
+{
+ float samples[MAX_SAMPLES_PER_FRAME], *fp1, *fp2;
+ int i, j;
+ double timebefore;
+
+ timebefore = sys_getrealtime();
+ if (pa_inchans)
+ {
+ ReadAudioStream(pa_stream, samples, DACBLKSIZE);
+ for (j = 0, fp1 = pa_soundin; j < pa_inchans; j++, fp1 += DACBLKSIZE)
+ for (i = 0, fp2 = samples + j; i < DACBLKSIZE; i++,
+ fp2 += pa_inchans)
+ {
+ fp1[i] = *fp2;
+ }
+ }
+ if (pa_outchans)
+ {
+ for (j = 0, fp1 = pa_soundout; j < pa_outchans; j++, fp1 += DACBLKSIZE)
+ for (i = 0, fp2 = samples + j; i < DACBLKSIZE; i++,
+ fp2 += pa_outchans)
+ {
+ *fp2 = fp1[i];
+ fp1[i] = 0;
+ }
+ WriteAudioStream(pa_stream, samples, DACBLKSIZE);
+ }
+
+ if (sys_getrealtime() > timebefore + 0.002)
+ return (SENDDACS_SLEPT);
+ else return (SENDDACS_YES);
+}
+
+
+void pa_listdevs(void) /* lifted from pa_devs.c in portaudio */
+{
+ int i,j;
+ int numDevices;
+ const PaDeviceInfo *pdi;
+ PaError err;
+ Pa_Initialize();
+ numDevices = Pa_CountDevices();
+ if( numDevices < 0 )
+ {
+ fprintf(stderr, "ERROR: Pa_CountDevices returned 0x%x\n", numDevices );
+ err = numDevices;
+ goto error;
+ }
+ fprintf(stderr, "Number of devices = %d\n", numDevices );
+ for( i=0; i<numDevices; i++ )
+ {
+ pdi = Pa_GetDeviceInfo( i );
+ fprintf(stderr, "---------------------------------------------- #%d",
+ i+1 );
+ if( i == Pa_GetDefaultInputDeviceID() ) fprintf(stderr, " DefaultInput");
+ if( i == Pa_GetDefaultOutputDeviceID() ) fprintf(stderr, " DefaultOutput");
+ fprintf(stderr, "\nName = %s\n", pdi->name );
+ fprintf(stderr, "Max Inputs = %d", pdi->maxInputChannels );
+ fprintf(stderr, ", Max Outputs = %d\n", pdi->maxOutputChannels );
+ if( pdi->numSampleRates == -1 )
+ {
+ fprintf(stderr, "Sample Rate Range = %f to %f\n", pdi->sampleRates[0], pdi->sampleRates[1] );
+ }
+ else
+ {
+ fprintf(stderr, "Sample Rates =");
+ for( j=0; j<pdi->numSampleRates; j++ )
+ {
+ fprintf(stderr, " %8.2f,", pdi->sampleRates[j] );
+ }
+ fprintf(stderr, "\n");
+ }
+ fprintf(stderr, "Native Sample Formats = ");
+ if( pdi->nativeSampleFormats & paInt8 ) fprintf(stderr, "paInt8, ");
+ if( pdi->nativeSampleFormats & paUInt8 ) fprintf(stderr, "paUInt8, ");
+ if( pdi->nativeSampleFormats & paInt16 ) fprintf(stderr, "paInt16, ");
+ if( pdi->nativeSampleFormats & paInt32 ) fprintf(stderr, "paInt32, ");
+ if( pdi->nativeSampleFormats & paFloat32 ) fprintf(stderr, "paFloat32, ");
+ if( pdi->nativeSampleFormats & paInt24 ) fprintf(stderr, "paInt24, ");
+ if( pdi->nativeSampleFormats & paPackedInt24 ) fprintf(stderr, "paPackedInt24, ");
+ fprintf(stderr, "\n");
+ }
+
+ fprintf(stderr, "----------------------------------------------\n");
+ goto midi;
+
+error:
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+
+ /* and MIDI */
+midi: ;
+#ifndef NT
+ for (i = 0; i < Pm_CountDevices(); i++)
+ {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+ printf("%d: %s, %s", i, info->interf, info->name);
+ if (info->input) printf(" (input)");
+ if (info->output) printf(" (output)");
+ printf("\n");
+ }
+#endif
+}
diff --git a/pd/src/s_print.c b/pd/src/s_print.c
new file mode 100644
index 00000000..33944286
--- /dev/null
+++ b/pd/src/s_print.c
@@ -0,0 +1,150 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+
+void post(char *fmt, ...)
+{
+ va_list ap;
+ t_int arg[8];
+ int i;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ putc('\n', stderr);
+}
+
+void startpost(char *fmt, ...)
+{
+ va_list ap;
+ t_int arg[8];
+ int i;
+ va_start(ap, fmt);
+
+ for (i = 0 ; i < 8; i++) arg[i] = va_arg(ap, t_int);
+ va_end(ap);
+ fprintf(stderr, fmt, arg[0], arg[1], arg[2], arg[3],
+ arg[4], arg[5], arg[6], arg[7]);
+}
+
+void poststring(char *s)
+{
+ fprintf(stderr, " %s", s);
+}
+
+void postatom(int argc, t_atom *argv)
+{
+ int i;
+ for (i = 0; i < argc; i++)
+ {
+ char buf[80];
+ atom_string(argv+i, buf, 80);
+ poststring(buf);
+ }
+}
+
+void postfloat(float f)
+{
+ char buf[80];
+ t_atom a;
+ SETFLOAT(&a, f);
+ postatom(1, &a);
+}
+
+void endpost(void)
+{
+ fprintf(stderr, "\n");
+}
+
+void error(char *fmt, ...)
+{
+ va_list ap;
+ t_int arg[8];
+ int i;
+ va_start(ap, fmt);
+ fprintf(stderr, "error: ");
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ putc('\n', stderr);
+}
+
+ /* here's the good way to log errors -- keep a pointer to the
+ offending or offended object around so the user can search for it
+ later. */
+
+static void *error_object;
+static char error_string[256];
+void canvas_finderror(void *object);
+
+void pd_error(void *object, char *fmt, ...)
+{
+ va_list ap;
+ t_int arg[8];
+ int i;
+ static int saidit = 0;
+ va_start(ap, fmt);
+ vsprintf(error_string, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "error: %s\n", error_string);
+ error_object = object;
+ if (!saidit)
+ {
+ post("... you might be able to track this down from the Find menu.");
+ saidit = 1;
+ }
+}
+
+void glob_finderror(t_pd *dummy)
+{
+ if (!error_object)
+ post("no findable error yet.");
+ else
+ {
+ post("last trackable error:");
+ post("%s", error_string);
+ canvas_finderror(error_object);
+ }
+}
+
+void bug(char *fmt, ...)
+{
+ va_list ap;
+ t_int arg[8];
+ int i;
+ va_start(ap, fmt);
+
+ for (i = 0 ; i < 8; i++) arg[i] = va_arg(ap, t_int);
+ va_end(ap);
+ fprintf(stderr, "Consistency check failed: ");
+ fprintf(stderr, fmt, arg[0], arg[1], arg[2], arg[3],
+ arg[4], arg[5], arg[6], arg[7]);
+ putc('\n', stderr);
+}
+
+ /* this isn't worked out yet. */
+static char *errobject;
+static char *errstring;
+
+void sys_logerror(char *object, char *s)
+{
+ errobject = object;
+ errstring = s;
+}
+
+void sys_unixerror(char *object)
+{
+ errobject = object;
+ errstring = strerror(errno);
+}
+
+void sys_ouch(void)
+{
+ if (*errobject) error("%s: %s", errobject, errstring);
+ else error("%s", errstring);
+}
diff --git a/pd/src/s_sgi.c b/pd/src/s_sgi.c
new file mode 100644
index 00000000..82a23dfb
--- /dev/null
+++ b/pd/src/s_sgi.c
@@ -0,0 +1,433 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_imp.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#ifdef HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <dmedia/audio.h>
+#include <sys/fpu.h>
+#include <dmedia/midi.h>
+int mdInit(void); /* prototype was messed up in midi.h */
+/* #include "sys/select.h" */
+
+static ALport iport;
+static ALport oport;
+static ALconfig sgi_config;
+#define DEFAULTCHANS 2
+#define SGI_MAXCH 8
+static int sys_inchannels, sys_outchannels;
+static int sys_audiobufsamps;
+int sys_schedadvance = 50000; /* scheduler advance in microseconds */
+ /* (this is set ridiculously high until we can get the real-time
+ scheduling act together.) */
+int sys_hipriority = 0;
+static int sgi_meters; /* true if we're metering */
+static float sgi_inmax; /* max input amplitude */
+static float sgi_outmax; /* max output amplitude */
+
+
+ /*
+ set the special "flush zero" but (FS, bit 24) in the
+ Control Status Register of the FPU of R4k and beyond
+ so that the result of any underflowing operation will
+ be clamped to zero, and no exception of any kind will
+ be generated on the CPU.
+
+ thanks to cpirazzi@cp.esd.sgi.com (Chris Pirazzi).
+ */
+
+static void sgi_flush_all_underflows_to_zero(void)
+{
+ union fpc_csr f;
+ f.fc_word = get_fpc_csr();
+ f.fc_struct.flush = 1;
+ set_fpc_csr(f.fc_word);
+}
+
+static void sgi_setchsr(int inchans, int outchans, int sr)
+{
+ int inbytes = inchans * (DACBLKSIZE*sizeof(float));
+ int outbytes = outchans * (DACBLKSIZE*sizeof(float));
+
+ sys_audiobufsamps = 64 * (int)(((float)sys_schedadvance)* sr / 64000000.);
+ sys_inchannels = inchans;
+ sys_outchannels = outchans;
+ sys_dacsr = sr;
+
+ if (sys_soundin)
+ free(sys_soundin);
+ sys_soundin = (t_float *)malloc(inbytes);
+ memset(sys_soundin, 0, inbytes);
+
+ if (sys_soundout)
+ free(sys_soundout);
+ sys_soundout = (t_float *)malloc(outbytes);
+ memset(sys_soundout, 0, outbytes);
+
+ memset(sys_soundout, 0, sys_outchannels * (DACBLKSIZE*sizeof(float)));
+ memset(sys_soundin, 0, sys_inchannels * (DACBLKSIZE*sizeof(float)));
+}
+
+static void sgi_open_audio(void)
+{
+ long pvbuf[4];
+ long pvbuflen;
+ /* get current sample rate -- should use this to set logical SR */
+ pvbuf[0] = AL_INPUT_RATE;
+ pvbuf[2] = AL_OUTPUT_RATE;
+ pvbuflen = 4;
+
+ ALgetparams(AL_DEFAULT_DEVICE, pvbuf, pvbuflen);
+
+ if (sys_inchannels && pvbuf[1] != sys_dacsr)
+ post("warning: input sample rate (%d) doesn't match mine (%f)\n",
+ pvbuf[1], sys_dacsr);
+
+ if (sys_outchannels && pvbuf[3] != sys_dacsr)
+ post("warning: output sample rate (%d) doesn't match mine (%f)\n",
+ pvbuf[3], sys_dacsr);
+
+ pvbuf[3] = pvbuf[1];
+ ALsetparams(AL_DEFAULT_DEVICE, pvbuf, pvbuflen);
+
+ sgi_config = ALnewconfig();
+
+ ALsetsampfmt(sgi_config, AL_SAMPFMT_FLOAT);
+
+ if (sys_outchannels)
+ {
+ ALsetchannels(sgi_config, sys_outchannels);
+ ALsetqueuesize(sgi_config, sys_audiobufsamps * sys_outchannels);
+ oport = ALopenport("the ouput port", "w", sgi_config);
+ if (!oport)
+ fprintf(stderr,"Pd: failed to open audio write port\n");
+ }
+ else oport = 0;
+ if (sys_inchannels)
+ {
+ ALsetchannels(sgi_config, sys_inchannels);
+ ALsetqueuesize(sgi_config, sys_audiobufsamps * sys_inchannels);
+ iport = ALopenport("the input port", "r", sgi_config);
+ if (!iport)
+ fprintf(stderr,"Pd: failed to open audio read port\n");
+ }
+ else iport = 0;
+}
+
+void sys_close_audio( void)
+{
+ if (iport) ALcloseport(iport);
+ if (oport) ALcloseport(oport);
+}
+
+void sys_close_midi( void)
+{
+ /* ??? */
+}
+
+t_sample *sys_soundout;
+t_sample *sys_soundin;
+float sys_dacsr;
+
+int sys_send_dacs(void)
+{
+ float buf[SGI_MAXCH * DACBLKSIZE], *fp1, *fp2, *fp3, *fp4;
+ long outfill, infill;
+ int outchannels = sys_outchannels, inchannels = sys_inchannels;
+ int i, nwait = 0, channel;
+ int outblk = DACBLKSIZE * outchannels;
+ int inblk = DACBLKSIZE * inchannels;
+ outfill = ALgetfillable(oport);
+ if (sgi_meters)
+ {
+ int i, n;
+ float maxsamp;
+ for (i = 0, n = sys_inchannels * DACBLKSIZE, maxsamp = sgi_inmax;
+ i < n; i++)
+ {
+ float f = sys_soundin[i];
+ if (f > maxsamp) maxsamp = f;
+ else if (-f > maxsamp) maxsamp = -f;
+ }
+ sgi_inmax = maxsamp;
+ for (i = 0, n = sys_outchannels * DACBLKSIZE, maxsamp = sgi_outmax;
+ i < n; i++)
+ {
+ float f = sys_soundout[i];
+ if (f > maxsamp) maxsamp = f;
+ else if (-f > maxsamp) maxsamp = -f;
+ }
+ sgi_outmax = maxsamp;
+ }
+
+ if (outfill <= outblk)
+ {
+ while ((infill = ALgetfilled(iport)) > 2*inblk)
+ {
+ if (sys_verbose) post("drop ADC buf");
+ ALreadsamps(iport, buf, inblk);
+ return (0);
+ }
+ }
+ if (outchannels)
+ {
+ for (channel = 0, fp1 = buf, fp2 = sys_soundout;
+ channel < outchannels; channel++, fp1++, fp2 += DACBLKSIZE)
+ {
+ for (i = 0, fp3 = fp1, fp4 = fp2; i < DACBLKSIZE;
+ i++, fp3 += outchannels, fp4++)
+ *fp3 = *fp4, *fp4 = 0;
+ }
+ ALwritesamps(oport, buf, outchannels* DACBLKSIZE);
+ }
+ if (inchannels)
+ {
+ if (infill > inblk)
+ ALreadsamps(iport, buf, inchannels* DACBLKSIZE);
+ else
+ {
+ if (sys_verbose) post("extra ADC buf");
+ memset(buf, 0, inblk*sizeof(float));
+ }
+ for (channel = 0, fp1 = buf, fp2 = sys_soundin;
+ channel < inchannels; channel++, fp1++, fp2 += DACBLKSIZE)
+ {
+ for (i = 0, fp3 = fp1, fp4 = fp2; i < DACBLKSIZE;
+ i++, fp3 += inchannels, fp4++)
+ *fp4 = *fp3;
+ }
+ }
+ return (1);
+}
+
+/* ------------------------- MIDI -------------------------- */
+
+#define NPORT 2
+
+static MDport sgi_inport[NPORT];
+static MDport sgi_outport[NPORT];
+
+void sgi_open_midi(int midiin, int midiout)
+{
+ int i;
+ int sgi_nports = mdInit();
+ if (sgi_nports < 0) sgi_nports = 0;
+ else if (sgi_nports > NPORT) sgi_nports = NPORT;
+ if (sys_verbose)
+ {
+ if (!sgi_nports)
+ {
+ post("no serial ports are configured for MIDI;");
+ post("if you want to use MIDI, try exiting Pd, typing");
+ post("'startmidi -d /dev/ttyd2' to a shell, and restarting Pd.");
+ }
+ else if (sgi_nports == 1)
+ post("Found one MIDI port on %s", mdGetName(0));
+ else if (sgi_nports == 2)
+ post("Found MIDI ports on %s and %s",
+ mdGetName(0), mdGetName(1));
+ }
+ if (midiin)
+ {
+ for (i = 0; i < sgi_nports; i++)
+ {
+ if (!(sgi_inport[i] = mdOpenInPort(mdGetName(i))))
+ error("MIDI input port %d: open failed", i+1);;
+ }
+ }
+ if (midiout)
+ {
+ for (i = 0; i < sgi_nports; i++)
+ {
+ if (!(sgi_outport[i] = mdOpenOutPort(mdGetName(i))))
+ error("MIDI output port %d: open failed", i+1);;
+ }
+ }
+ return;
+}
+
+void sys_putmidimess(int portno, int a, int b, int c)
+{
+ MDevent mdv;
+ if (portno >= NPORT || portno < 0 || !sgi_outport[portno]) return;
+ mdv.msg[0] = a;
+ mdv.msg[1] = b;
+ mdv.msg[2] = c;
+ mdv.msg[3] = 0;
+ mdv.sysexmsg = 0;
+ mdv.stamp = 0;
+ mdv.msglen = 0;
+ if (mdSend(sgi_outport[portno], &mdv, 1) < 0)
+ error("MIDI output error\n");
+ post("msg out %d %d %d", a, b, c);
+}
+
+void sys_putmidibyte(int portno, int foo)
+{
+ error("MIDI raw byte output not available on SGI");
+}
+
+void inmidi_noteon(int portno, int channel, int pitch, int velo);
+void inmidi_controlchange(int portno, int channel, int ctlnumber, int value);
+void inmidi_programchange(int portno, int channel, int value);
+void inmidi_pitchbend(int portno, int channel, int value);
+void inmidi_aftertouch(int portno, int channel, int value);
+void inmidi_polyaftertouch(int portno, int channel, int pitch, int value);
+
+void sys_poll_midi(void)
+{
+ int i;
+ MDport *mp;
+ for (i = 0, mp = sgi_inport; i < NPORT; i++, mp++)
+ {
+ int ret, status, b1, b2, nfds;
+ MDevent mdv;
+ fd_set inports;
+ struct timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ if (!*mp) continue;
+ FD_ZERO(&inports);
+ FD_SET(mdGetFd(*mp), &inports);
+
+ if (select(mdGetFd(*mp)+1 , &inports, 0, 0, &timeout) < 0)
+ perror("midi select");
+ if (FD_ISSET(mdGetFd(*mp),&inports))
+ {
+ if (mdReceive(*mp, &mdv, 1) < 0)
+ error("failure receiving message\n");
+ else if (mdv.msg[0] == MD_SYSEX) mdFree(mdv.sysexmsg);
+
+ else
+ {
+ int status = mdv.msg[0];
+ int channel = (status & 0xf) + 1;
+ int b1 = mdv.msg[1];
+ int b2 = mdv.msg[2];
+ switch(status & 0xf0)
+ {
+ case MD_NOTEOFF:
+ inmidi_noteon(i, channel, b1, 0);
+ break;
+ case MD_NOTEON:
+ inmidi_noteon(i, channel, b1, b2);
+ break;
+ case MD_POLYKEYPRESSURE:
+ inmidi_polyaftertouch(i, channel, b1, b2);
+ break;
+ case MD_CONTROLCHANGE:
+ inmidi_controlchange(i, channel, b1, b2);
+ break;
+ case MD_PITCHBENDCHANGE:
+ inmidi_pitchbend(i, channel, ((b2 << 7) + b1));
+ break;
+ case MD_PROGRAMCHANGE:
+ inmidi_programchange(i, channel, b1);
+ break;
+ case MD_CHANNELPRESSURE:
+ inmidi_aftertouch(i, channel, b1);
+ break;
+ }
+ }
+ }
+ }
+}
+
+ /* public routines */
+
+void sys_open_audio(int naudioindev, int *audioindev, int nchindev, int *chindev,
+ int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev,
+ int rate) /* IOhannes */
+{
+ int inchans=0;
+ int outchans=0;
+ if (nchindev<0)inchans == -1;
+ else {
+ int i=nchindev;
+ int *l=chindev;
+ while(i--)inchans+=*l++;
+ }
+ if (nchoutdev<0)outchans == -1;
+ else {
+ int i=nchoutdev;
+ int *l=choutdev;
+ while(i--)outchans+=*l++;
+ }
+
+ if (inchans < 0) inchans = DEFAULTCHANS;
+ if (outchans < 0) outchans = DEFAULTCHANS;
+ if (inchans > SGI_MAXCH) inchans = SGI_MAXCH;
+ if (outchans > SGI_MAXCH) outchans = SGI_MAXCH;
+
+ sgi_setchsr(inchans, outchans, rate);
+ sgi_flush_all_underflows_to_zero();
+ sgi_open_audio();
+}
+
+void sys_open_midi(int nmidiin, int *midiinvec,
+ int nmidiout, int *midioutvec)
+{
+ sgi_open_midi(nmidiin!=0, nmidiout!=0);
+}
+
+float sys_getsr(void)
+{
+ return (sys_dacsr);
+}
+
+void sys_audiobuf(int n)
+{
+ /* set the size, in milliseconds, of the audio FIFO */
+ if (n < 5) n = 5;
+ else if (n > 5000) n = 5000;
+ fprintf(stderr, "audio buffer set to %d milliseconds\n", n);
+ sys_schedadvance = n * 1000;
+}
+
+void sys_getmeters(float *inmax, float *outmax)
+{
+ if (inmax)
+ {
+ sgi_meters = 1;
+ *inmax = sgi_inmax;
+ *outmax = sgi_outmax;
+ }
+ else
+ sgi_meters = 0;
+ sgi_inmax = sgi_outmax = 0;
+}
+
+void sys_reportidle(void)
+{
+}
+
+int sys_get_inchannels(void)
+{
+ return (sys_inchannels);
+}
+
+int sys_get_outchannels(void)
+{
+ return (sys_outchannels);
+}
+
+void sys_set_priority(int foo)
+{
+ fprintf(stderr,
+ "warning: priority boosting in IRIX not implemented yet\n");
+}
+
+void sys_setblocksize(int n)
+{
+ fprintf(stderr,
+ "warning: blocksize not settable in IRIX\n");
+}
diff --git a/pd/src/s_unix.c b/pd/src/s_unix.c
new file mode 100644
index 00000000..ee0ce160
--- /dev/null
+++ b/pd/src/s_unix.c
@@ -0,0 +1,445 @@
+/* Copyright (c) 1997-1999 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. */
+
+/* this file is misnamed. It seems to handle clock functions and MIDI I/O;
+probably should be called "s_midi.c" */
+
+#include "m_imp.h"
+#ifdef UNIX
+#include <unistd.h>
+#include <sys/time.h>
+#ifdef HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#endif
+#ifdef NT
+#include <winsock.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <wtypes.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <signal.h>
+
+#ifdef NT
+static LARGE_INTEGER nt_inittime;
+static double nt_freq = 0;
+
+static void sys_initntclock(void)
+{
+ LARGE_INTEGER f1;
+ LARGE_INTEGER now;
+ QueryPerformanceCounter(&now);
+ if (!QueryPerformanceFrequency(&f1))
+ {
+ fprintf(stderr, "pd: QueryPerformanceFrequency failed\n");
+ f1.QuadPart = 1;
+ }
+ nt_freq = f1.QuadPart;
+ nt_inittime = now;
+}
+
+#if 0
+ /* this is a version you can call if you did the QueryPerformanceCounter
+ call yourself. Necessary for time tagging incoming MIDI at interrupt
+ level, for instance; but we're not doing that just now. */
+
+double nt_tixtotime(LARGE_INTEGER *dumbass)
+{
+ if (nt_freq == 0) sys_initntclock();
+ return (((double)(dumbass->QuadPart - nt_inittime.QuadPart)) / nt_freq);
+}
+#endif
+#endif /* NT */
+
+double sys_getrealtime(void) /* get "real time" in seconds */
+{
+#ifdef UNIX
+ static struct timeval then;
+ struct timeval now;
+ gettimeofday(&now, 0);
+ if (then.tv_sec == 0 && then.tv_usec == 0) then = now;
+ return ((now.tv_sec - then.tv_sec) +
+ (1./1000000.) * (now.tv_usec - then.tv_usec));
+#endif
+#ifdef NT
+ LARGE_INTEGER now;
+ QueryPerformanceCounter(&now);
+ if (nt_freq == 0) sys_initntclock();
+ return (((double)(now.QuadPart - nt_inittime.QuadPart)) / nt_freq);
+#endif
+}
+
+typedef struct _midiqelem
+{
+ double q_time;
+ int q_portno;
+ unsigned char q_onebyte;
+ unsigned char q_byte1;
+ unsigned char q_byte2;
+ unsigned char q_byte3;
+} t_midiqelem;
+
+#define MIDIQSIZE 1024
+
+t_midiqelem midi_outqueue[MIDIQSIZE];
+int midi_outhead, midi_outtail;
+t_midiqelem midi_inqueue[MIDIQSIZE];
+int midi_inhead, midi_intail;
+static double sys_midiinittime;
+
+ /* this is our current estimate for at what "system" real time the
+ current logical time's output should occur. */
+static double sys_dactimeminusrealtime;
+ /* same for input, should be schduler advance earlier. */
+static double sys_adctimeminusrealtime;
+
+static double sys_newdactimeminusrealtime = -1e20;
+static double sys_newadctimeminusrealtime = -1e20;
+static double sys_whenupdate;
+
+void sys_initmidiqueue( void)
+{
+ sys_midiinittime = clock_getlogicaltime();
+ sys_dactimeminusrealtime = sys_adctimeminusrealtime = 0;
+}
+
+ /* this is called from the OS dependent code from time to time when we
+ think we know the delay (outbuftime) in seconds, at which the last-output
+ audio sample will go out the door. */
+void sys_setmiditimediff(double inbuftime, double outbuftime)
+{
+ double dactimeminusrealtime =
+ .001 * clock_gettimesince(sys_midiinittime)
+ - outbuftime - sys_getrealtime();
+ double adctimeminusrealtime =
+ .001 * clock_gettimesince(sys_midiinittime)
+ + inbuftime - sys_getrealtime();
+ if (dactimeminusrealtime > sys_newdactimeminusrealtime)
+ sys_newdactimeminusrealtime = dactimeminusrealtime;
+ if (adctimeminusrealtime > sys_newadctimeminusrealtime)
+ sys_newadctimeminusrealtime = adctimeminusrealtime;
+ if (sys_getrealtime() > sys_whenupdate)
+ {
+ sys_dactimeminusrealtime = sys_newdactimeminusrealtime;
+ sys_adctimeminusrealtime = sys_newadctimeminusrealtime;
+ sys_newdactimeminusrealtime = -1e20;
+ sys_newadctimeminusrealtime = -1e20;
+ sys_whenupdate = sys_getrealtime() + 1;
+ }
+}
+
+ /* return the logical time of the DAC sample we believe is currently
+ going out, based on how much "system time" has elapsed since the
+ last time sys_setmiditimediff got called. */
+static double sys_getmidioutrealtime( void)
+{
+ return (sys_getrealtime() + sys_dactimeminusrealtime);
+}
+
+static double sys_getmidiinrealtime( void)
+{
+ return (sys_getrealtime() + sys_adctimeminusrealtime);
+}
+
+static void sys_putnext( void)
+{
+ int portno = midi_outqueue[midi_outtail].q_portno;
+ if (midi_outqueue[midi_outtail].q_onebyte)
+ sys_putmidibyte(portno, midi_outqueue[midi_outtail].q_byte1);
+ else sys_putmidimess(portno, midi_outqueue[midi_outtail].q_byte1,
+ midi_outqueue[midi_outtail].q_byte2,
+ midi_outqueue[midi_outtail].q_byte3);
+ midi_outtail = (midi_outtail + 1 == MIDIQSIZE ? 0 : midi_outtail + 1);
+}
+
+/* #define TEST_DEJITTER */
+
+void sys_pollmidioutqueue( void)
+{
+#ifdef TEST_DEJITTER
+ static int db = 0;
+#endif
+ double midirealtime = sys_getmidioutrealtime();
+#ifdef TEST_DEJITTER
+ if (midi_outhead == midi_outtail)
+ db = 0;
+#endif
+ while (midi_outhead != midi_outtail)
+ {
+#ifdef TEST_DEJITTER
+ if (!db)
+ {
+ post("out: del %f, midiRT %f logicaltime %f, RT %f dacminusRT %f",
+ (midi_outqueue[midi_outtail].q_time - midirealtime),
+ midirealtime, .001 * clock_gettimesince(sys_midiinittime),
+ sys_getrealtime(), sys_dactimeminusrealtime);
+ db = 1;
+ }
+#endif
+ if (midi_outqueue[midi_outtail].q_time <= midirealtime)
+ sys_putnext();
+ else break;
+ }
+}
+
+static void sys_queuemidimess(int portno, int onebyte, int a, int b, int c)
+{
+ t_midiqelem *midiqelem;
+ int newhead = midi_outhead +1;
+ if (newhead == MIDIQSIZE)
+ newhead = 0;
+ /* if FIFO is full flush an element to make room */
+ if (newhead == midi_outtail)
+ sys_putnext();
+ midi_outqueue[midi_outhead].q_portno = portno;
+ midi_outqueue[midi_outhead].q_onebyte = onebyte;
+ midi_outqueue[midi_outhead].q_byte1 = a;
+ midi_outqueue[midi_outhead].q_byte2 = b;
+ midi_outqueue[midi_outhead].q_byte3 = c;
+ midi_outqueue[midi_outhead].q_time =
+ .001 * clock_gettimesince(sys_midiinittime);
+ midi_outhead = newhead;
+ sys_pollmidioutqueue();
+}
+
+#define MIDI_NOTEON 144
+#define MIDI_POLYAFTERTOUCH 160
+#define MIDI_CONTROLCHANGE 176
+#define MIDI_PROGRAMCHANGE 192
+#define MIDI_AFTERTOUCH 208
+#define MIDI_PITCHBEND 224
+
+void outmidi_noteon(int portno, int channel, int pitch, int velo)
+{
+ if (pitch < 0) pitch = 0;
+ else if (pitch > 127) pitch = 127;
+ if (velo < 0) velo = 0;
+ else if (velo > 127) velo = 127;
+ sys_queuemidimess(portno, 0, MIDI_NOTEON + (channel & 0xf), pitch, velo);
+}
+
+void outmidi_controlchange(int portno, int channel, int ctl, int value)
+{
+ if (ctl < 0) ctl = 0;
+ else if (ctl > 127) ctl = 127;
+ if (value < 0) value = 0;
+ else if (value > 127) value = 127;
+ sys_queuemidimess(portno, 0, MIDI_CONTROLCHANGE + (channel & 0xf),
+ ctl, value);
+}
+
+void outmidi_programchange(int portno, int channel, int value)
+{
+ if (value < 0) value = 0;
+ else if (value > 127) value = 127;
+ sys_queuemidimess(portno, 0,
+ MIDI_PROGRAMCHANGE + (channel & 0xf), value, 0);
+}
+
+void outmidi_pitchbend(int portno, int channel, int value)
+{
+ if (value < 0) value = 0;
+ else if (value > 16383) value = 16383;
+ sys_queuemidimess(portno, 0, MIDI_PITCHBEND + (channel & 0xf),
+ (value & 127), ((value>>7) & 127));
+}
+
+void outmidi_aftertouch(int portno, int channel, int value)
+{
+ if (value < 0) value = 0;
+ else if (value > 127) value = 127;
+ sys_queuemidimess(portno, 0, MIDI_AFTERTOUCH + (channel & 0xf), value, 0);
+}
+
+void outmidi_polyaftertouch(int portno, int channel, int pitch, int value)
+{
+ if (pitch < 0) pitch = 0;
+ else if (pitch > 127) pitch = 127;
+ if (value < 0) value = 0;
+ else if (value > 127) value = 127;
+ sys_queuemidimess(portno, 0, MIDI_POLYAFTERTOUCH + (channel & 0xf),
+ pitch, value);
+}
+
+void outmidi_mclk(int portno)
+{
+ sys_queuemidimess(portno, 1, 0xf8, 0,0);
+}
+
+/* ------------------------- MIDI input queue handling ------------------ */
+typedef struct midiparser
+{
+ int mp_status;
+ int mp_sysex;
+ int mp_gotbyte1;
+ int mp_byte1;
+} t_midiparser;
+
+#define MIDINOTEOFF 0x80
+#define MIDINOTEON 0x90
+#define MIDIPOLYTOUCH 0xa0
+#define MIDICONTROLCHANGE 0xb0
+#define MIDIPROGRAMCHANGE 0xc0
+#define MIDICHANNELTOUCH 0xd0
+#define MIDIPITCHBEND 0xe0
+ /* functions in x_midi.c */
+void inmidi_realtimein(int portno, int cmd);
+void inmidi_byte(int portno, int byte);
+void inmidi_sysex(int portno, int byte);
+void inmidi_noteon(int portno, int channel, int pitch, int velo);
+void inmidi_controlchange(int portno, int channel, int ctlnumber, int value);
+void inmidi_programchange(int portno, int channel, int value);
+void inmidi_pitchbend(int portno, int channel, int value);
+void inmidi_aftertouch(int portno, int channel, int value);
+void inmidi_polyaftertouch(int portno, int channel, int pitch, int value);
+
+static void sys_dispatchnextmidiin( void)
+{
+ static t_midiparser parser[MAXMIDIINDEV], *parserp;
+ int portno = midi_inqueue[midi_intail].q_portno,
+ byte = midi_inqueue[midi_intail].q_byte1;
+ if (!midi_inqueue[midi_intail].q_onebyte)
+ bug("sys_dispatchnextmidiin");
+ if (portno < 0 || portno >= MAXMIDIINDEV)
+ bug("sys_dispatchnextmidiin 2");
+ parserp = parser + portno;
+ outlet_setstacklim();
+
+ if (byte >= 0xf8)
+ inmidi_realtimein(portno, byte);
+ else
+ {
+ inmidi_byte(portno, byte);
+ if (byte < 0xf0)
+ {
+ if (byte & 0x80)
+ {
+ parserp->mp_status = byte;
+ parserp->mp_gotbyte1 = 0;
+ }
+ else
+ {
+ int cmd = (parserp->mp_status & 0xf0);
+ int chan = (parserp->mp_status & 0xf);
+ int byte1 = parserp->mp_byte1, gotbyte1 = parserp->mp_gotbyte1;
+ switch (cmd)
+ {
+ case MIDINOTEOFF:
+ if (gotbyte1)
+ inmidi_noteon(portno, chan, byte1, 0),
+ parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDINOTEON:
+ if (gotbyte1)
+ inmidi_noteon(portno, chan, byte1, byte),
+ parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDIPOLYTOUCH:
+ if (gotbyte1)
+ inmidi_polyaftertouch(portno, chan, byte1, byte),
+ parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDICONTROLCHANGE:
+ if (gotbyte1)
+ inmidi_controlchange(portno, chan, byte1, byte),
+ parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDIPROGRAMCHANGE:
+ inmidi_programchange(portno, chan, byte);
+ break;
+ case MIDICHANNELTOUCH:
+ inmidi_aftertouch(portno, chan, byte);
+ break;
+ case MIDIPITCHBEND:
+ if (gotbyte1)
+ inmidi_pitchbend(portno, chan, ((byte << 7) + byte1)),
+ parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ }
+ }
+ }
+ }
+ midi_intail = (midi_intail + 1 == MIDIQSIZE ? 0 : midi_intail + 1);
+}
+
+void sys_pollmidiinqueue( void)
+{
+#ifdef TEST_DEJITTER
+ static int db = 0;
+#endif
+ double logicaltime = .001 * clock_gettimesince(sys_midiinittime);
+#ifdef TEST_DEJITTER
+ if (midi_inhead == midi_intail)
+ db = 0;
+#endif
+ while (midi_inhead != midi_intail)
+ {
+#ifdef TEST_DEJITTER
+ if (!db)
+ {
+ post("in del %f, logicaltime %f, RT %f adcminusRT %f",
+ (midi_inqueue[midi_intail].q_time - logicaltime),
+ logicaltime, sys_getrealtime(), sys_adctimeminusrealtime);
+ db = 1;
+ }
+#endif
+#if 0
+ if (midi_inqueue[midi_intail].q_time <= logicaltime - 0.007)
+ post("late %f",
+ 1000 * (logicaltime - midi_inqueue[midi_intail].q_time));
+#endif
+ if (midi_inqueue[midi_intail].q_time <= logicaltime)
+ {
+#if 0
+ post("diff %f",
+ 1000* (logicaltime - midi_inqueue[midi_intail].q_time));
+#endif
+ sys_dispatchnextmidiin();
+ }
+ else break;
+ }
+}
+
+ /* this should be called from the system dependent MIDI code when a byte
+ comes in, as a result of our calling sys_poll_midi. We stick it on a
+ timetag queue and dispatch it at the appropriate logical time. */
+
+void sys_midibytein(int portno, int byte)
+{
+ t_midiqelem *midiqelem;
+ int newhead = midi_inhead +1;
+ if (newhead == MIDIQSIZE)
+ newhead = 0;
+ /* if FIFO is full flush an element to make room */
+ if (newhead == midi_intail)
+ post("flush"), sys_dispatchnextmidiin();
+ midi_inqueue[midi_inhead].q_portno = portno;
+ midi_inqueue[midi_inhead].q_onebyte = 1;
+ midi_inqueue[midi_inhead].q_byte1 = byte;
+ midi_inqueue[midi_inhead].q_time = sys_getmidiinrealtime();
+ midi_inhead = newhead;
+ sys_pollmidiinqueue();
+}
+
+void sys_pollmidiqueue( void)
+{
+#if 0
+ static double lasttime;
+ double newtime = sys_getrealtime();
+ if (newtime - lasttime > 0.007)
+ post("delay %d", (int)(1000 * (newtime - lasttime)));
+ lasttime = newtime;
+#endif
+ sys_poll_midi(); /* OS dependent poll for MIDI input */
+ sys_pollmidioutqueue();
+ sys_pollmidiinqueue();
+}
+
diff --git a/pd/src/s_watchdog.c b/pd/src/s_watchdog.c
new file mode 100644
index 00000000..a2122824
--- /dev/null
+++ b/pd/src/s_watchdog.c
@@ -0,0 +1,47 @@
+/* Copyright (c) 1997-2000 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* This file is compiled into the separate program, "pd-watchdog," which
+tries to prevent Pd from locking up the processor if it's at realtime
+priority. Linux only. Invoked from s_inter.c. */
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ int happy = 1;
+ while (1)
+ {
+ struct timeval timout;
+ fd_set readset;
+ if (happy)
+ {
+ timout.tv_sec = 5;
+ timout.tv_usec = 0;
+ }
+ else
+ {
+ timout.tv_sec = 2;
+ timout.tv_usec = 0;
+ }
+ FD_ZERO(&readset);
+ FD_SET(0, &readset);
+ select(1, &readset, 0, 0, &timout);
+ if (FD_ISSET(0, &readset))
+ {
+ char buf[100];
+ happy = 1;
+ if (read(0, &buf, 100) <= 0)
+ return (0);
+ else continue;
+ }
+ happy = 0;
+ kill(getppid(), SIGHUP);
+ fprintf(stderr, "watchdog: signaling pd...\n");
+ }
+}
diff --git a/pd/src/t_main.c b/pd/src/t_main.c
new file mode 100644
index 00000000..d4d48c63
--- /dev/null
+++ b/pd/src/t_main.c
@@ -0,0 +1,123 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* This file should be compared with the corresponding thing in the TK
+* distribution whenever updating to newer versions of TCL/TK. */
+
+/*
+ * Copyright (c) 1993 The Regents of the University of California.
+ * Copyright (c) 1994 Sun Microsystems, Inc.
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ */
+
+
+#ifndef MACOSX /* linux and IRIX only; in MACOSX we don't link this in */
+#include "tk.h"
+#include <stdlib.h>
+
+/*
+ * The following variable is a special hack that is needed in order for
+ * Sun shared libraries to be used for Tcl.
+ */
+
+extern int matherr(void);
+int *tclDummyMathPtr = (int *) matherr;
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * main --
+ *
+ * This is the main program for the application.
+ *
+ * Results:
+ * None: Tk_Main never returns here, so this procedure never
+ * returns either.
+ *
+ * Side effects:
+ * Whatever the application does.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void pdgui_startup(Tcl_Interp *interp);
+void pdgui_setname(char *name);
+void pdgui_setsock(int port);
+void pdgui_sethost(char *name);
+
+int
+main(int argc, char **argv)
+{
+ pdgui_setname(argv[0]);
+ if (argc >= 2)
+ {
+ pdgui_setsock(atoi(argv[1]));
+ argc--; argv++;
+ argv[0] = "Pd";
+ }
+ if (argc >= 2)
+ {
+ pdgui_sethost(argv[1]);
+ argc--; argv++;
+ argv[0] = "Pd";
+ }
+ Tk_Main(argc, argv, Tcl_AppInit);
+ return 0; /* Needed only to prevent compiler warning. */
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_AppInit --
+ *
+ * This procedure performs application-specific initialization.
+ * Most applications, especially those that incorporate additional
+ * packages, will have their own version of this procedure.
+ *
+ * Results:
+ * Returns a standard Tcl completion code, and leaves an error
+ * message in interp->result if an error occurs.
+ *
+ * Side effects:
+ * Depends on the startup script.
+ *
+ *----------------------------------------------------------------------
+ */
+
+
+int
+Tcl_AppInit(interp)
+ Tcl_Interp *interp; /* Interpreter for application. */
+{
+ Tk_Window mainwindow;
+
+ if (Tcl_Init(interp) == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+ if (Tk_Init(interp) == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+
+ /* setup specific to pd-gui: */
+
+ pdgui_startup(interp);
+
+ /*
+ * Specify a user-specific startup file to invoke if the application
+ * is run interactively. Typically the startup file is "~/.apprc"
+ * where "app" is the name of the application. If this line is deleted
+ * then no user-specific startup file will be run under any conditions.
+ */
+
+#if 0
+ tcl_RcFileName = "~/.pdrc";
+#endif
+
+ return TCL_OK;
+}
+
+#endif /* MACOSX */
diff --git a/pd/src/t_tk.h b/pd/src/t_tk.h
new file mode 100644
index 00000000..a6943679
--- /dev/null
+++ b/pd/src/t_tk.h
@@ -0,0 +1,10 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+void pdgui_vmess(char *fmt, ...);
+void pdgui_mess(char *s);
+
+void pdgui_evalfile(char *s);
+
+#define GUISTRING 1000
diff --git a/pd/src/t_tkcmd.c b/pd/src/t_tkcmd.c
new file mode 100644
index 00000000..c2abd846
--- /dev/null
+++ b/pd/src/t_tkcmd.c
@@ -0,0 +1,367 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifdef UNIX /* in unix this only works first; in NT it only works last. */
+#include "tk.h"
+#endif
+
+#include "t_tk.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#ifdef UNIX
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#ifdef HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#include <sys/time.h>
+#include <errno.h>
+#endif
+#ifdef NT
+#include <winsock.h>
+#include <io.h>
+#endif
+#ifdef NT
+#pragma warning( disable : 4305 ) /* uncast const double to float */
+#pragma warning( disable : 4244 ) /* uncast double to float */
+#pragma warning( disable : 4101 ) /* unused local variables */
+#endif
+
+#ifdef NT
+#include "tk.h"
+#endif
+
+void tcl_mess(char *s);
+
+/***************** the socket setup code ********************/
+
+static int portno = 5400;
+
+ /* some installations of linux don't know about "localhost" so give
+ the loopback address; NT, on the other hand, can't understand the
+ hostname "127.0.0.1". */
+char hostname[100] =
+#ifdef __linux__
+ "127.0.0.1";
+#else
+ "localhost";
+#endif
+
+void pdgui_setsock(int port)
+{
+ portno = port;
+}
+
+void pdgui_sethost(char *name)
+{
+ strncpy(hostname, name, 100);
+ hostname[99] = 0;
+}
+
+static void pdgui_sockerror(char *s)
+{
+#ifdef NT
+ int err = WSAGetLastError();
+#endif
+#ifdef UNIX
+ int err = errno;
+#endif
+
+ fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
+ tcl_mess("exit\n");
+ exit(1);
+}
+
+static int sockfd;
+
+/* The "pd_suck" command, which polls the socket.
+ FIXME: if Pd sends something bigger than SOCKSIZE we're in trouble!
+ This has to be set bigger than any array update message for instance.
+*/
+#define SOCKSIZE 20000
+
+static char pd_tkbuf[SOCKSIZE+1];
+int pd_spillbytes = 0;
+
+static void pd_readsocket(ClientData cd, int mask)
+{
+ int ngot;
+ fd_set readset, writeset, exceptset;
+ struct timeval timout;
+
+ timout.tv_sec = 0;
+ timout.tv_usec = 0;
+ FD_ZERO(&writeset);
+ FD_ZERO(&readset);
+ FD_ZERO(&exceptset);
+ FD_SET(sockfd, &readset);
+ FD_SET(sockfd, &exceptset);
+
+ if (select(sockfd+1, &readset, &writeset, &exceptset, &timout) < 0)
+ perror("select");
+ if (FD_ISSET(sockfd, &exceptset) || FD_ISSET(sockfd, &readset))
+ {
+ int ret;
+ ret = recv(sockfd, pd_tkbuf + pd_spillbytes,
+ SOCKSIZE - pd_spillbytes, 0);
+ if (ret < 0) pdgui_sockerror("socket receive error");
+ else if (ret == 0)
+ {
+ /* fprintf(stderr, "read %d\n", SOCKSIZE - pd_spillbytes); */
+ fprintf(stderr, "pd_gui: pd process exited\n");
+ tcl_mess("exit\n");
+ }
+ else
+ {
+ char *lastcr = 0, *bp = pd_tkbuf, *ep = bp + (pd_spillbytes + ret);
+ int brace = 0;
+ char lastc = 0;
+ while (bp < ep)
+ {
+ char c = *bp;
+ if (c == '}' && brace) brace--;
+ else if (c == '{') brace++;
+ else if (!brace && c == '\n' && lastc != '\\') lastcr = bp;
+ lastc = c;
+ bp++;
+ }
+ if (lastcr)
+ {
+ int xtra = pd_tkbuf + pd_spillbytes + ret - (lastcr+1);
+ char bashwas = lastcr[1];
+ lastcr[1] = 0;
+ tcl_mess(pd_tkbuf);
+ lastcr[1] = bashwas;
+ if (xtra)
+ {
+ /* fprintf(stderr, "x %d\n", xtra); */
+ memmove(pd_tkbuf, lastcr+1, xtra);
+ }
+ pd_spillbytes = xtra;
+ }
+ else
+ {
+ pd_spillbytes += ret;
+ }
+ }
+ }
+}
+
+#ifndef UNIX
+ /* if we aren't UNIX, we add a tcl command to poll the
+ socket for data. */
+static int pd_pollsocketCmd(ClientData cd, Tcl_Interp *interp,
+ int argc, char **argv)
+{
+ pd_readsocket(cd, 0);
+ return (TCL_OK);
+}
+#endif
+
+void pdgui_setupsocket(void)
+{
+ struct sockaddr_in server;
+ struct hostent *hp;
+
+#ifdef NT
+ short version = MAKEWORD(2, 0);
+ WSADATA nobby;
+
+ if (WSAStartup(version, &nobby)) pdgui_sockerror("setup");
+#endif
+
+ /* create a socket */
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (sockfd < 0) pdgui_sockerror("socket");
+
+ /* connect socket using hostname provided in command line */
+ server.sin_family = AF_INET;
+
+ hp = gethostbyname(hostname);
+
+ if (hp == 0)
+ {
+ fprintf(stderr,
+ "localhost not found (inet protocol not installed?)\n");
+ exit(1);
+ }
+ memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
+
+ /* assign client port number */
+ server.sin_port = htons((unsigned short)portno);
+
+ /* try to connect */
+ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
+ pdgui_sockerror("connecting stream socket");
+
+#ifdef UNIX
+ /* in unix we ask TK to call us back. In NT we have to poll. */
+ Tk_CreateFileHandler(sockfd, TK_READABLE | TK_EXCEPTION,
+ pd_readsocket, 0);
+#endif
+}
+
+/**************************** commands ************************/
+static char *pdgui_path;
+
+/* The "pd" command, which cats its args together and throws the result
+* at the Pd interpreter.
+*/
+#define MAXWRITE 1024
+
+static int pdCmd(ClientData cd, Tcl_Interp *interp, int argc, char **argv)
+{
+ if (argc == 2)
+ {
+ int n = strlen(argv[1]);
+ if (send(sockfd, argv[1], n, 0) < n)
+ {
+ perror("stdout");
+ tcl_mess("exit\n");
+ }
+ }
+ else
+ {
+ int i;
+ char buf[MAXWRITE];
+ buf[0] = 0;
+ for (i = 1; i < argc; i++)
+ {
+ if (strlen(argv[i]) + strlen(buf) + 2 > MAXWRITE)
+ {
+ interp->result = "pd: arg list too long";
+ return (TCL_ERROR);
+ }
+ if (i > 1) strcat(buf, " ");
+ strcat(buf, argv[i]);
+ }
+ if (send(sockfd, buf, strlen(buf), 0) < 0)
+ {
+ perror("stdout");
+ tcl_mess("exit\n");
+ }
+ }
+ return (TCL_OK);
+}
+
+/*********** "c" level access to tk functions. ******************/
+
+static Tcl_Interp *tk_myinterp;
+
+void tcl_mess(char *s)
+{
+ int result;
+ result = Tcl_Eval(tk_myinterp, s);
+ if (result != TCL_OK)
+ {
+ if (*tk_myinterp->result) printf("%s\n", tk_myinterp->result);
+ }
+}
+
+/* LATER should do a bounds check -- but how do you get printf to do that? */
+void tcl_vmess(char *fmt, ...)
+{
+ int result, i;
+ char buf[MAXWRITE];
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ vsprintf(buf, fmt, ap);
+ result = Tcl_Eval(tk_myinterp, buf);
+ if (result != TCL_OK)
+ {
+ if (*tk_myinterp->result) printf("%s\n", tk_myinterp->result);
+ }
+ va_end(ap);
+}
+
+#ifdef UNIX
+void pdgui_doevalfile(Tcl_Interp *interp, char *s)
+{
+ char buf[GUISTRING];
+ sprintf(buf, "set pd_guidir \"%s\"\n", pdgui_path);
+ tcl_mess(buf);
+ strcpy(buf, pdgui_path);
+ strcat(buf, "/bin/");
+ strcat(buf, s);
+ if (Tcl_EvalFile(interp, buf) != TCL_OK)
+ {
+ char buf2[1000];
+ sprintf(buf2, "puts [concat tcl: %s: can't open script]\n",
+ buf);
+ tcl_mess(buf2);
+ }
+}
+
+void pdgui_evalfile(char *s)
+{
+ pdgui_doevalfile(tk_myinterp, s);
+}
+#endif
+
+void pdgui_startup(Tcl_Interp *interp)
+{
+
+ /* save pointer to the main interpreter */
+ tk_myinterp = interp;
+
+
+ /* add our own TK commands */
+ Tcl_CreateCommand(interp, "pd", pdCmd, (ClientData)NULL,
+ (Tcl_CmdDeleteProc *)NULL);
+#ifndef UNIX
+ Tcl_CreateCommand(interp, "pd_pollsocket", pd_pollsocketCmd,
+ (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
+#endif
+ pdgui_setupsocket();
+
+ /* read in the startup file */
+#if !defined(NT) && !defined(MACOSX)
+ pdgui_evalfile("pd.tk");
+#endif
+}
+
+#ifdef UNIX
+void pdgui_setname(char *s)
+{
+ char *t;
+ char *str;
+ int n;
+ if (t = strrchr(s, '/')) str = s, n = (t-s) + 1;
+ else str = "./", n = 2;
+ if (n > GUISTRING-100) n = GUISTRING-100;
+ pdgui_path = malloc(n+9);
+
+ strncpy(pdgui_path, str, n);
+ while (strlen(pdgui_path) > 0 && pdgui_path[strlen(pdgui_path)-1] == '/')
+ pdgui_path[strlen(pdgui_path)-1] = 0;
+ if (t = strrchr(pdgui_path, '/'))
+ *t = 0;
+}
+#endif
+
+int Pdtcl_Init(Tcl_Interp *interp)
+{
+ char *myvalue = Tcl_GetVar(interp, "argv", 0);
+ int myportno;
+ if (myvalue && (myportno = atoi(myvalue)) > 1)
+ pdgui_setsock(myportno);
+ tk_myinterp = interp;
+ pdgui_startup(interp);
+ interp->result = "loaded pdtcl_init";
+
+ return (TCL_OK);
+}
+
+int Pdtcl_SafeInit(Tcl_Interp *interp) {
+ fprintf(stderr, "Pdtcl_Safeinit 51\n");
+ return (TCL_OK);
+}
+
diff --git a/pd/src/u_main.tk b/pd/src/u_main.tk
new file mode 100644
index 00000000..a19b0951
--- /dev/null
+++ b/pd/src/u_main.tk
@@ -0,0 +1,2570 @@
+set pd_nt 0
+# (The above is 0 for unix, 1 for microsoft, and 2 for Mac OSX. The first
+# line is automatically munged by the relevant makefiles.)
+
+# Copyright (c) 1997-1999 Miller Puckette.
+# For information on usage and redistribution, and for a DISCLAIMER OF ALL
+# WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+
+# changed by Thomas Musil 09.2001
+# between "pdtk_graph_dialog -- dialog window for graphs"
+# and "pdtk_array_dialog -- dialog window for arrays"
+# a new dialogbox was inserted, named:
+# "pdtk_iemgui_dialog -- dialog window for iem guis"
+#
+# there are 2 new features: 1.) line-delete-protection in edit-menue
+#
+# 2.) there are all iem-guis in a seperated put-gui-menue
+#
+# all this changes are labeled with #######iemlib##########
+
+if {$pd_nt == 1} {
+ global pd_guidir
+ set pd_gui2 [string range $argv0 0 [expr [string last \\ $argv0 ] - 1]]
+ regsub -all \\\\ $pd_gui2 / pd_gui3
+ set pd_guidir $pd_gui3/..
+ load $pd_guidir/bin/pdtcl
+}
+
+if {$pd_nt == 2} {
+ global pd_guidir
+ set pd_gui2 [string range $argv0 0 [expr [string last / $argv0 ] - 1]]
+ set pd_guidir $pd_gui2/..
+ load $pd_guidir/bin/pdtcl
+}
+
+# it's unfortunate but we seem to have to turn off global bindings
+# for Text objects to get control-s and control-t to do what we want for
+# "text" dialogs below. Also we have to get rid of tab's changing the focus.
+
+bind all <Key-Tab> ""
+bind all <Shift-Key-Tab> ""
+bind Text <Control-t> {}
+bind Text <Control-s> {}
+# puts stderr [bind all]
+
+################## set up main window #########################
+frame .mbar -relief raised -bd 2
+canvas .dummy -height 1c -width 1c
+frame .controls
+pack .mbar .controls .dummy -side top -fill x
+menubutton .mbar.file -text File -menu .mbar.file.menu
+menubutton .mbar.find -text Find -menu .mbar.find.menu
+menubutton .mbar.windows -text Windows -menu .mbar.windows.menu
+menubutton .mbar.audio -text Audio -menu .mbar.audio.menu
+menubutton .mbar.help -text Help -menu .mbar.help.menu
+pack .mbar.file .mbar.find .mbar.windows .mbar.audio -side left
+pack .mbar.help -side right
+menu .mbar.file.menu
+menu .mbar.find.menu
+menu .mbar.windows.menu -postcommand [concat pdtk_fixwindowmenu]
+menu .mbar.audio.menu
+menu .mbar.help.menu
+
+set ctrls_audio_on 0
+set ctrls_meter_on 0
+set ctrls_inlevel 0
+set ctrls_outlevel 0
+
+frame .controls.switches
+checkbutton .controls.switches.audiobutton -text {compute audio} \
+ -variable ctrls_audio_on \
+ -anchor w \
+ -command {pd [concat pd dsp $ctrls_audio_on \;]}
+
+checkbutton .controls.switches.meterbutton -text {peak meters} \
+ -variable ctrls_meter_on \
+ -anchor w \
+ -command {pd [concat pd meters $ctrls_meter_on \;]}
+
+pack .controls.switches.meterbutton .controls.switches.audiobutton -side left
+
+frame .controls.in
+label .controls.in.label -text IN
+entry .controls.in.level -textvariable ctrls_inlevel -width 3
+button .controls.in.clip -text {CLIP} -state disabled
+pack .controls.in.label .controls.in.level .controls.in.clip -side top
+
+frame .controls.out
+label .controls.out.label -text OUT
+entry .controls.out.level -textvariable ctrls_outlevel -width 3
+button .controls.out.clip -text {CLIP} -state disabled
+pack .controls.out.label .controls.out.level .controls.out.clip -side top
+
+button .controls.dio -text "DIO\nerrors" \
+ -command {pd [concat pd audiostatus \;]}
+
+pack .controls.switches -side bottom
+pack .controls.in .controls.out -side left
+pack .controls.dio -side right
+
+bind . <Control-Key> {pdtk_pd_ctrlkey %W %K 0}
+bind . <Control-Shift-Key> {pdtk_pd_ctrlkey %W %K 1}
+
+
+############### set up global variables ################################
+
+set untitled_number 1
+set untitled_directory [pwd]
+set saveas_client doggy
+set pd_opendir $untitled_directory
+############iemlib##################
+# need it to know, if new or open file
+set iem_new_open_flag "open"
+############iemlib##################
+
+################ utility functions #########################
+
+proc pdtk_enquote {x} {
+ set foo [string map {"," "" ";" "" \" ""} $x]
+ set foo2 [string map {" " "\\ "} $foo]
+ concat $foo2
+}
+
+proc pdtk_debug {x} {
+ tk_messageBox -message $x -type ok
+}
+
+proc pdtk_watchdog {} {
+ pd [concat pd ping \;]
+ after 2000 {pdtk_watchdog}
+}
+
+proc pdtk_check {x message} {
+ set answer [tk_messageBox \-message $x \-type yesno \-icon question]
+ switch $answer {
+ yes {pd $message} }
+# no {tk_messageBox \-message "cancelled" \-type ok}
+}
+
+set menu_windowlist {}
+
+proc pdtk_fixwindowmenu {} {
+ global menu_windowlist
+ .mbar.windows.menu delete 0 end
+ foreach i $menu_windowlist {
+ .mbar.windows.menu add command -label [lindex $i 0] \
+ -command [concat menu_domenuwindow [lindex $i 1]]
+ }
+}
+
+############### the "New" menu command ########################
+proc menu_new {} {
+ global untitled_number
+ global untitled_directory
+############iemlib##################
+ global iem_new_open_flag
+
+ set iem_new_open_flag "new"
+############iemlib##################
+ pd [concat pd filename Untitled-$untitled_number $untitled_directory \;]
+ pd {
+ #N canvas;
+ #X pop 1;
+ }
+ set untitled_number [expr $untitled_number + 1]
+}
+
+################## the "Open" menu command #########################
+
+proc menu_open {} {
+ global pd_opendir
+ global pd_nt
+############iemlib##################
+ global iem_new_open_flag
+
+ set iem_new_open_flag "open"
+############iemlib##################
+
+# workaround -- initialdir doesn't work on MACOSX yet ---
+ if {$pd_nt == 2} {
+ cd $pd_opendir
+ set filename [tk_getOpenFile -defaultextension .pd \
+ -filetypes { {{pd files} {.pd}} {{max files} {.pat}}} ]
+ } else {
+ set filename [tk_getOpenFile -defaultextension .pd \
+ -filetypes { {{pd files} {.pd}} {{max files} {.pat}}} \
+ -initialdir $pd_opendir]
+ }
+# puts stderr $filename
+ if {$filename != ""} {
+ set directory [string range $filename 0 \
+ [expr [string last / $filename ] - 1]]
+ set pd_opendir $directory
+ set basename [string range $filename \
+ [expr [string last / $filename ] + 1] end]
+
+# pd_debug [concat file $filename base $basename dir $directory]
+
+ pd [concat pd open [pdtk_enquote $basename] \
+ [pdtk_enquote $directory]\;]
+ }
+}
+
+################## the "Message" menu command #########################
+proc menu_send {} {
+ toplevel .sendpanel
+ entry .sendpanel.entry -textvariable send_textvariable
+ pack .sendpanel.entry -side bottom -fill both -ipadx 100
+ .sendpanel.entry select from 0
+ .sendpanel.entry select adjust end
+ bind .sendpanel.entry <KeyPress-Return> {
+ pd [concat $send_textvariable \;]
+ after 50 {destroy .sendpanel}
+ }
+ focus .sendpanel.entry
+}
+
+################## the "Quit" menu command #########################
+proc menu_really_quit {} {pd {pd quit;}}
+
+proc menu_quit {} {pdtk_check {Really quit?} {pd quit;}}
+
+######### the "Pd" menu command, which puts the Pd window on top ########
+proc menu_pop_pd {} {raise .}
+
+######### the "audio" menu command ###############
+proc menu_audio {flag} {pd [concat pd dsp $flag \;]}
+
+######### the "documentation" menu command ###############
+
+set doc_number 1
+
+proc menu_opentext {filename} {
+ global doc_number
+ global pd_guidir
+ global pd_myversion
+ set name [format ".help%d" $doc_number]
+ toplevel $name
+ text $name.text -relief raised -bd 2 -font -*-courier-bold--normal--12-* \
+ -yscrollcommand "$name.scroll set" -background white
+ scrollbar $name.scroll -command "$name.text yview"
+ pack $name.scroll -side right -fill y
+ pack $name.text -side left -fill both -expand 1
+
+ set f [open $filename]
+ while {![eof $f]} {
+ set bigstring [read $f 1000]
+ regsub -all PD_BASEDIR $bigstring $pd_guidir bigstring2
+ regsub -all PD_VERSION $bigstring2 $pd_myversion bigstring3
+ $name.text insert end $bigstring3
+ }
+ close $f
+ set doc_number [expr $doc_number + 1]
+}
+
+set help_directory $pd_guidir/doc
+
+proc menu_documentation {} {
+ global help_directory
+ global pd_nt
+############iemlib##################
+ global iem_new_open_flag
+
+ set iem_new_open_flag "open"
+############iemlib##################
+
+ if {$pd_nt == 2} {
+ cd $help_directory
+ set filename [tk_getOpenFile -defaultextension .pd \
+ -filetypes { {{documentation} {.pd .txt .htm}} } ]
+ } else {
+ set filename [tk_getOpenFile -defaultextension .pd \
+ -filetypes { {{documentation} {.pd .txt .htm}} } \
+ -initialdir $help_directory]
+ }
+
+ if {$filename != ""} {
+ if {[string first .txt $filename] >= 0} {
+ menu_opentext $filename
+ } elseif {[string first .htm $filename] >= 0} {
+ if {$pd_nt == 0} {
+#I wish I could get this to run in the background; the "&" doesn't do it:
+ exec sh -c \
+ [format "mozilla file:%s || netscape file:%s &\n" \
+ $filename $filename]
+ } else {
+ tk_messageBox -message \
+ {sorry -- can't open htm files yet; open this manually} \
+ -type ok
+ }
+ } else {
+ set help_directory [string range $filename 0 \
+ [expr [string last / $filename ] - 1]]
+ set basename [string range $filename \
+ [expr [string last / $filename ] + 1] end]
+ pd [concat pd open [pdtk_enquote $basename] \
+ [pdtk_enquote $help_directory] \;]
+ }
+ }
+}
+
+proc menu_doc_open {subdir basename} {
+ global pd_guidir
+############iemlib##################
+ global iem_new_open_flag
+
+ set iem_new_open_flag "open"
+############iemlib##################
+
+ set dirname $pd_guidir/$subdir
+
+ if {[string first .txt $basename] >= 0} {
+ menu_opentext $dirname/$basename
+ } else {
+ pd [concat pd open [pdtk_enquote $basename] \
+ [pdtk_enquote $dirname] \;]
+ }
+}
+
+#################### the "File" menu for the Pd window ##############
+.mbar.file.menu add command -label New -command {menu_new} \
+ -accelerator "Ctrl+n"
+.mbar.file.menu add command -label Open -command {menu_open} \
+ -accelerator "Ctrl+o"
+.mbar.file.menu add command -label Message -command {menu_send} \
+ -accelerator "Ctrl+m"
+.mbar.file.menu add separator
+.mbar.file.menu add command -label Quit -command {menu_quit} \
+ -accelerator "Ctrl+q"
+
+#################### the "Find" menu for the Pd window ##############
+.mbar.find.menu add command -label {last error?} -command {menu_finderror}
+
+#################### the "Audio" menu for the Pd window ##############
+.mbar.audio.menu add command -label On -accelerator "Ctrl+/" \
+ -command {menu_audio 1}
+.mbar.audio.menu add command -label Off -accelerator "Ctrl+." \
+ -command {menu_audio 0}
+
+#################### the "Help" menu for the Pd window ##############
+.mbar.help.menu add command -label {About Pd} \
+ -command {menu_doc_open doc/1.manual 1.introduction.txt}
+.mbar.help.menu add command -label {Test Audio and MIDI} \
+ -command {menu_doc_open doc/7.stuff/tools testtone.pd}
+.mbar.help.menu add command -label {Load Meter} \
+ -command {menu_doc_open doc/7.stuff/tools load-meter.pd}
+.mbar.help.menu add command -label {Pure Documentation...} \
+ -command {menu_documentation}
+
+########### functions for menu functions on document windows ########
+
+proc menu_save {name} {
+ pdtk_canvas_checkgeometry $name
+ pd [concat $name menusave \;]
+}
+
+proc menu_saveas {name} {
+ pdtk_canvas_checkgeometry $name
+ pd [concat $name menusaveas \;]
+}
+
+proc menu_print {name} {
+ $name.c postscript -file x.ps
+}
+
+proc menu_close {name} {
+ pd [concat $name menuclose \;]
+}
+
+proc menu_cut {name} {
+ pd [concat $name cut \;]
+}
+
+proc menu_copy {name} {
+ pd [concat $name copy \;]
+}
+
+proc menu_paste {name} {
+ pd [concat $name paste \;]
+}
+
+proc menu_duplicate {name} {
+ pd [concat $name duplicate \;]
+}
+
+proc menu_selectall {name} {
+ pd [concat $name selectall \;]
+}
+
+proc menu_texteditor {name} {
+ pd [concat $name texteditor \;]
+}
+
+proc menu_font {name} {
+ pd [concat $name menufont \;]
+}
+
+proc menu_tidyup {name} {
+ pd [concat $name tidy \;]
+}
+
+proc menu_editmode {name} {
+ pd [concat $name editmode 0 \;]
+}
+
+proc menu_object {name accel} {
+ pd [concat $name obj $accel \;]
+}
+
+proc menu_message {name accel} {
+ pd [concat $name msg $accel \;]
+}
+
+proc menu_floatatom {name accel} {
+ pd [concat $name floatatom $accel \;]
+}
+
+proc menu_symbolatom {name accel} {
+ pd [concat $name symbolatom $accel \;]
+}
+
+proc menu_comment {name accel} {
+ pd [concat $name text $accel \;]
+}
+
+proc menu_graph {name} {
+ pd [concat $name graph \;]
+}
+
+proc menu_array {name} {
+ pd [concat $name menuarray \;]
+}
+
+############iemlib##################
+proc menu_bng {name accel} {
+ pd [concat $name bng $accel \;]
+}
+
+proc menu_toggle {name accel} {
+ pd [concat $name toggle $accel \;]
+}
+
+proc menu_numbox {name accel} {
+ pd [concat $name numbox $accel \;]
+}
+
+proc menu_vslider {name accel} {
+ pd [concat $name vslider $accel \;]
+}
+
+proc menu_hslider {name accel} {
+ pd [concat $name hslider $accel \;]
+}
+
+proc menu_hdial {name accel} {
+ pd [concat $name hdial $accel \;]
+}
+
+proc menu_vdial {name accel} {
+ pd [concat $name vdial $accel \;]
+}
+
+proc menu_vumeter {name accel} {
+ pd [concat $name vumeter $accel \;]
+}
+
+proc menu_mycnv {name accel} {
+ pd [concat $name mycnv $accel \;]
+}
+
+proc menu_protectmode {name} {
+ pd [concat $name protectmode 0 \;]
+}
+
+############iemlib##################
+
+proc menu_windowparent {name} {
+ pd [concat $name findparent \;]
+}
+
+proc menu_findagain {name} {
+ pd [concat $name findagain \;]
+}
+
+proc menu_finderror {} {
+ pd [concat pd finderror \;]
+}
+
+proc menu_domenuwindow {i} {
+ raise $i
+}
+
+proc menu_fixwindowmenu {name} {
+ global menu_windowlist
+ $name.m.windows.m add command
+ $name.m.windows.m delete 4 end
+ foreach i $menu_windowlist {
+ $name.m.windows.m add command -label [lindex $i 0] \
+ -command [concat menu_domenuwindow [lindex $i 1]]
+ }
+}
+
+################## the "find" menu item ###################
+
+set find_canvas nobody
+set find_string ""
+set find_count 1
+
+proc find_apply {name} {
+ global find_string
+ global find_canvas
+ regsub -all \; $find_string " _semi_ " find_string2
+ regsub -all \, $find_string2 " _comma_ " find_string3
+# puts stderr [concat $find_canvas find $find_string3 \
+# \;]
+ pd [concat $find_canvas find $find_string3 \
+ \;]
+ after 50 destroy $name
+}
+
+proc find_cancel {name} {
+ after 50 destroy $name
+}
+
+proc menu_findobject {canvas} {
+ global find_string
+ global find_canvas
+ global find_count
+
+ set name [format ".find%d" $find_count]
+ set find_count [expr $find_count + 1]
+
+ set find_canvas $canvas
+
+ toplevel $name
+
+ label $name.label -text {find...}
+ pack $name.label -side top
+
+ entry $name.entry -textvariable find_string
+ pack $name.entry -side top
+
+ frame $name.buttonframe
+ pack $name.buttonframe -side bottom -fill x -pady 2m
+ button $name.buttonframe.cancel -text {Cancel}\
+ -command "find_cancel $name"
+ button $name.buttonframe.ok -text {OK}\
+ -command "find_apply $name"
+ pack $name.buttonframe.cancel -side left -expand 1
+ pack $name.buttonframe.ok -side left -expand 1
+
+ $name.entry select from 0
+ $name.entry select adjust end
+ bind $name.entry <KeyPress-Return> [ concat find_apply $name]
+ focus $name.entry
+}
+
+
+############# pdtk_canvas_new -- create a new canvas ###############
+proc pdtk_canvas_new {name width height geometry} {
+ global pd_opendir
+ global iem_new_open_flag
+
+ toplevel $name
+ frame $name.m -relief raised -bd 2
+# puts stderr [concat geometry: $geometry]
+ wm geometry $name $geometry
+ canvas $name.c -width $width -height $height -background white \
+ -yscrollcommand "$name.scrollvert set" \
+ -xscrollcommand "$name.scrollhort set" \
+ -scrollregion [concat 0 0 $width $height]
+
+ scrollbar $name.scrollvert -command "$name.c yview"
+ scrollbar $name.scrollhort -command "$name.c xview" \
+ -orient horizontal
+
+ pack $name.m -side top -fill x
+ pack $name.scrollhort -side bottom -fill x
+ pack $name.scrollvert -side right -fill y
+ pack $name.c -side left -expand 1 -fill both
+ wm minsize $name 1 1
+ wm geometry $name $geometry
+
+# the file menu
+
+ menubutton $name.m.file -text File -menu $name.m.file.m
+ pack $name.m.file -side left
+ menu $name.m.file.m
+
+ $name.m.file.m add command -label New -command {menu_new} \
+ -accelerator "Ctrl+n"
+
+ $name.m.file.m add command -label Open -command {menu_open} \
+ -accelerator "Ctrl+o"
+
+ $name.m.file.m add command -label Message -command {menu_send} \
+ -accelerator "Ctrl+m"
+
+ $name.m.file.m add separator
+ $name.m.file.m add command -label Save -command [concat menu_save $name] \
+ -accelerator "Ctrl+s"
+
+ $name.m.file.m add command -label Close \
+ -command [concat menu_close $name] \
+ -accelerator "Ctrl+w"
+
+ $name.m.file.m add command -label "Save as..." \
+ -command [concat menu_saveas $name] \
+ -accelerator "Ctrl+S"
+
+ $name.m.file.m add command -label Print -command [concat menu_print $name] \
+ -accelerator "Ctrl+p"
+
+ $name.m.file.m add separator
+
+ $name.m.file.m add command -label Quit -command {menu_quit} \
+ -accelerator "Ctrl+q"
+
+# the edit menu
+ menubutton $name.m.edit -text Edit -menu $name.m.edit.m
+ pack $name.m.edit -side left
+ menu $name.m.edit.m
+
+
+ $name.m.edit.m add command -label Cut -command [concat menu_cut $name] \
+ -accelerator "Ctrl+x"
+
+ $name.m.edit.m add command -label Copy -command [concat menu_copy $name] \
+ -accelerator "Ctrl+c"
+
+ $name.m.edit.m add command -label Paste \
+ -command [concat menu_paste $name] \
+ -accelerator "Ctrl+v"
+
+ $name.m.edit.m add command -label Duplicate \
+ -command [concat menu_duplicate $name] \
+ -accelerator "Ctrl+d"
+
+ $name.m.edit.m add command -label {Select all} \
+ -command [concat menu_selectall $name] \
+ -accelerator "Ctrl+a"
+
+ $name.m.edit.m add command -label {Text Editor} \
+ -command [concat menu_texteditor $name] \
+ -accelerator "Ctrl+t"
+
+ $name.m.edit.m add command -label Font \
+ -command [concat menu_font $name]
+
+ $name.m.edit.m add command -label {Tidy Up} \
+ -command [concat menu_tidyup $name]
+
+ $name.m.edit.m add separator
+
+############iemlib##################
+# instead of "red = #BC3C60" we take "grey85", so there is no difference,
+# if widget is selected or not.
+
+ $name.m.edit.m add checkbutton -label "Edit mode" \
+ -indicatoron true -selectcolor grey85 \
+ -command [concat menu_editmode $name] \
+ -accelerator "Ctrl+e"
+
+
+
+ $name.m.edit.m add checkbutton -label "Protect" \
+ -indicatoron true -selectcolor grey85 \
+ -command [concat menu_protectmode $name] \
+ -accelerator "Ctrl+r"
+
+ if { $iem_new_open_flag == "open" } {
+ $name.m.edit.m entryconfigure "Edit mode" -indicatoron false }
+ $name.m.edit.m entryconfigure "Protect" -indicatoron false
+
+############iemlib##################
+
+# the put menu
+ menubutton $name.m.put -text Put -menu $name.m.put.m
+ pack $name.m.put -side left
+ menu $name.m.put.m
+
+ $name.m.put.m add command -label Object \
+ -command [concat menu_object $name 0] \
+ -accelerator "Ctrl+1"
+
+ $name.m.put.m add command -label Message \
+ -command [concat menu_message $name 0] \
+ -accelerator "Ctrl+2"
+
+ $name.m.put.m add command -label Number \
+ -command [concat menu_floatatom $name 0] \
+ -accelerator "Ctrl+3"
+
+ $name.m.put.m add command -label Symbol \
+ -command [concat menu_symbolatom $name 0] \
+ -accelerator "Ctrl+4"
+
+ $name.m.put.m add command -label Comment \
+ -command [concat menu_comment $name 0] \
+ -accelerator "Ctrl+5"
+
+############iemlib##################
+
+ $name.m.put.m add command -label Bang \
+ -command [concat menu_bng $name 0] \
+ -accelerator "Alt+b"
+
+ $name.m.put.m add command -label Toggle \
+ -command [concat menu_toggle $name 0] \
+ -accelerator "Alt+t"
+
+ $name.m.put.m add command -label Number2 \
+ -command [concat menu_numbox $name 0] \
+ -accelerator "Alt+n"
+
+ $name.m.put.m add command -label Vslider \
+ -command [concat menu_vslider $name 0] \
+ -accelerator "Alt+v"
+
+ $name.m.put.m add command -label Hslider \
+ -command [concat menu_hslider $name 0] \
+ -accelerator "Alt+h"
+
+ $name.m.put.m add command -label Vdial \
+ -command [concat menu_vdial $name 0] \
+ -accelerator "Alt+d"
+
+ $name.m.put.m add command -label Hdial \
+ -command [concat menu_hdial $name 0] \
+ -accelerator "Alt+i"
+
+ $name.m.put.m add command -label VU \
+ -command [concat menu_vumeter $name 0] \
+ -accelerator "Alt+u"
+
+ $name.m.put.m add command -label Canvas \
+ -command [concat menu_mycnv $name 0] \
+ -accelerator "Alt+c"
+
+############iemlib##################
+
+ $name.m.put.m add command -label Graph \
+ -command [concat menu_graph $name]
+
+ $name.m.put.m add command -label Array \
+ -command [concat menu_array $name]
+
+
+
+# the find menu
+ menubutton $name.m.find -text Find -menu $name.m.find.m
+ pack $name.m.find -side left
+ menu $name.m.find.m
+ $name.m.find.m add command -label {Find...} -accelerator "Ctrl+f" \
+ -command [concat menu_findobject $name]
+ $name.m.find.m add command -label {Find Again} -accelerator "Ctrl+g" \
+ -command [concat menu_findagain $name]
+ $name.m.find.m add command -label {Find last error} \
+ -command [concat menu_finderror]
+
+# the window menu
+ menubutton $name.m.windows -text Windows -menu $name.m.windows.m
+ pack $name.m.windows -side left
+ menu $name.m.windows.m -postcommand [concat menu_fixwindowmenu $name]
+ $name.m.windows.m add command -label {parent window}\
+ -command [concat menu_windowparent $name]
+ $name.m.windows.m add command -label {Pd window} -command menu_pop_pd
+ $name.m.windows.m add separator
+
+# the audio menu
+ menubutton $name.m.audio -text Audio -menu $name.m.audio.m
+ pack $name.m.audio -side left
+ menu $name.m.audio.m
+ $name.m.audio.m add command -label On -accelerator "Ctrl+/" \
+ -command {menu_audio 1}
+ $name.m.audio.m add command -label Off -accelerator "Ctrl+." \
+ -command {menu_audio 0}
+
+# the help menu
+ menubutton $name.m.help -text Help -menu $name.m.help.m
+ pack $name.m.help -side right
+ menu $name.m.help.m
+ $name.m.help.m add command -label {Getting Started} \
+ -command {menu_doc_open doc/1.manual 1.introduction.txt}
+ $name.m.help.m add command -label {Test Audio and MIDI} \
+ -command {menu_doc_open doc/7.stuff/tools testtone.pd}
+ $name.m.help.m add command -label {Load Meter} \
+ -command {menu_doc_open doc/7.stuff/tools load-meter.pd}
+ $name.m.help.m add command -label {Pure Documentation} \
+ -command {menu_documentation}
+
+# the popup menu
+ menu $name.popup -tearoff false
+ $name.popup add command -label {Properties} \
+ -command [concat popup_action $name 0]
+ $name.popup add command -label {Open} \
+ -command [concat popup_action $name 1]
+ $name.popup add command -label {Help} \
+ -command [concat popup_action $name 2]
+
+# WM protocol
+ wm protocol $name WM_DELETE_WINDOW [concat menu_close $name]
+
+# bindings.
+# this is idiotic -- how do you just sense what mod keys are down and
+# pass them on? I can't find it anywhere.
+# Here we encode shift as 1, control 2, alt 4, in agreement
+# with definitions in g_canvas.c. The third button gets "8" but we don't
+# bother with modifiers there.
+# We don't handle multiple clicks yet.
+
+ bind $name.c <Button> {pdtk_canvas_click %W %x %y %b 0}
+ bind $name.c <Shift-Button> {pdtk_canvas_click %W %x %y %b 1}
+ bind $name.c <Control-Button> {pdtk_canvas_click %W %x %y %b 2}
+ bind $name.c <Control-Shift-Button> {pdtk_canvas_click %W %x %y %b 3}
+ bind $name.c <Alt-Button> {pdtk_canvas_click %W %x %y %b 4}
+ bind $name.c <Alt-Shift-Button> {pdtk_canvas_click %W %x %y %b 5}
+ bind $name.c <Alt-Control-Button> {pdtk_canvas_click %W %x %y %b 6}
+ bind $name.c <Alt-Control-Shift-Button> {pdtk_canvas_click %W %x %y %b 7}
+ bind $name.c <Button-3> {pdtk_canvas_click %W %x %y %b 8}
+
+ bind $name.c <ButtonRelease> {pdtk_canvas_mouseup %W %x %y %b}
+ bind $name.c <Control-Key> {pdtk_canvas_ctrlkey %W %K 0}
+ bind $name.c <Control-Shift-Key> {pdtk_canvas_ctrlkey %W %K 1}
+ bind $name.c <Alt-Key> {pdtk_canvas_altkey %W %K %A}
+# bind $name.c <Mod1-Key> {puts stderr [concat mod1 %W %K %A]}
+ bind $name.c <Key> {pdtk_canvas_key %W %K %A}
+ bind $name.c <KeyRelease> {pdtk_canvas_keyup %W %K %A}
+ bind $name.c <Motion> {pdtk_canvas_motion %W %x %y 0}
+ bind $name.c <Alt-Motion> {pdtk_canvas_motion %W %x %y 4}
+ bind $name.c <Map> {pdtk_canvas_map %W %s}
+# bind $name.c <Unmap> {puts stderr map}
+ focus $name.c
+# puts stderr "all done"
+# after 1 [concat raise $name]
+}
+
+#################### event binding procedures ################
+
+#get the name of the toplevel window for a canvas; this is also
+#the name of the canvas object in Pd.
+
+proc canvastosym {name} {
+ string range $name 0 [expr [string length $name] - 3]
+}
+
+set pdtk_lastcanvasconfigured ""
+set pdtk_lastcanvasconfiguration ""
+
+proc pdtk_canvas_checkgeometry {topname} {
+ set boo [winfo geometry $topname.c]
+ set boo2 [wm geometry $topname]
+ global pdtk_lastcanvasconfigured
+ global pdtk_lastcanvasconfiguration
+ if {$topname != $pdtk_lastcanvasconfigured || \
+ $boo != $pdtk_lastcanvasconfiguration} {
+ set pdtk_lastcanvasconfigured $topname
+ set pdtk_lastcanvasconfiguration $boo
+ pd $topname relocate $boo $boo2 \;
+ }
+}
+
+proc pdtk_canvas_click {name x y b f} {
+# puts stderr [concat got $f]
+ pd [canvastosym $name] mouse [$name canvasx $x] [$name canvasy $y] $b $f \;
+}
+
+proc pdtk_canvas_shiftclick {name x y b} {
+ pd [canvastosym $name] mouse [$name canvasx $x] [$name canvasy $y] $b 1 \;
+}
+
+proc pdtk_canvas_ctrlclick {name x y b} {
+ pd [canvastosym $name] mouse [$name canvasx $x] [$name canvasy $y] $b 2 \;
+}
+
+proc pdtk_canvas_altclick {name x y b} {
+ pd [canvastosym $name] mouse [$name canvasx $x] [$name canvasy $y] $b 3 \;
+}
+
+proc pdtk_canvas_dblclick {name x y b} {
+ pd [canvastosym $name] mouse [$name canvasx $x] [$name canvasy $y] $b 4 \;
+}
+
+set pdtk_canvas_mouseup_name 0
+set pdtk_canvas_mouseup_xminval 0
+set pdtk_canvas_mouseup_xmaxval 0
+set pdtk_canvas_mouseup_yminval 0
+set pdtk_canvas_mouseup_ymaxval 0
+
+proc pdtk_canvas_mouseup {name x y b} {
+ pd [concat [canvastosym $name] mouseup [$name canvasx $x] \
+ [$name canvasy $y] $b \;]
+
+# we use the mouseup event to update scrollbar ranges and recheck the
+# geometry of the window since I haven't taken the time to figure out
+# how to do it right.
+
+ global pdtk_canvas_mouseup_name
+ global pdtk_canvas_mouseup_xminval
+ global pdtk_canvas_mouseup_xmaxval
+ global pdtk_canvas_mouseup_yminval
+ global pdtk_canvas_mouseup_ymaxval
+
+ set size [$name bbox all]
+ if {$size != ""} {
+ set xminval 0
+ set yminval 0
+ set xmaxval 100
+ set ymaxval 100
+ set x1 [lindex $size 0]
+ set x2 [lindex $size 2]
+ set y1 [lindex $size 1]
+ set y2 [lindex $size 3]
+
+ if {$x1 < 0} {set xminval $x1}
+ if {$y1 < 0} {set yminval $y1}
+
+ if {$x2 > 100} {set xmaxval $x2}
+ if {$y2 > 100} {set ymaxval $y2}
+
+ if {$pdtk_canvas_mouseup_name != $name || \
+ $pdtk_canvas_mouseup_xminval != $xminval || \
+ $pdtk_canvas_mouseup_xmaxval != $xmaxval || \
+ $pdtk_canvas_mouseup_yminval != $yminval || \
+ $pdtk_canvas_mouseup_ymaxval != $ymaxval } {
+
+ set newsize "$xminval $yminval $xmaxval $ymaxval"
+ $name configure -scrollregion $newsize
+ set pdtk_canvas_mouseup_name $name
+ set pdtk_canvas_mouseup_xminval $xminval
+ set pdtk_canvas_mouseup_xmaxval $xmaxval
+ set pdtk_canvas_mouseup_yminval $yminval
+ set pdtk_canvas_mouseup_ymaxval $ymaxval
+ }
+
+ }
+ pdtk_canvas_checkgeometry [canvastosym $name]
+}
+
+proc pdtk_canvas_key {name key iso} {
+# puts stderr [concat down key= $key iso= $iso]
+# .controls.switches.meterbutton configure -text $key
+# HACK for MAC OSX -- backspace seems different; I don't understand why.
+# invesigate this LATER...
+ global pd_nt
+ if {$pd_nt == 2} {
+ if {$key == "BackSpace"} {
+ set key 8
+ set keynum 8
+ }
+ if {$key == "Delete"} {
+ set key 8
+ set keynum 8
+ }
+ }
+ if {$iso != ""} {
+ scan $iso %c keynum
+ pd [canvastosym $name] key 1 $keynum \;
+ } else {
+ pd [canvastosym $name] key 1 $key \;
+ }
+}
+
+proc pdtk_canvas_keyup {name key iso} {
+# puts stderr [concat up key= $key iso= $iso]
+ if {$iso != ""} {
+ scan $iso %c keynum
+ pd [canvastosym $name] key 0 $keynum \;
+ } else {
+ pd [canvastosym $name] key 0 $key \;
+ }
+}
+
+proc pdtk_canvas_altkey {name key iso} {
+# puts stderr [concat alt-key $iso]
+############iemlib##################
+ set topname [string trimright $name .c]
+ if {$key == "b" || $key == "B"} {menu_bng $topname 1}
+ if {$key == "t" || $key == "T"} {menu_toggle $topname 1}
+ if {$key == "n" || $key == "N"} {menu_numbox $topname 1}
+ if {$key == "v" || $key == "V"} {menu_vslider $topname 1}
+ if {$key == "h" || $key == "H"} {menu_hslider $topname 1}
+ if {$key == "i" || $key == "I"} {menu_hdial $topname 1}
+ if {$key == "d" || $key == "D"} {menu_vdial $topname 1}
+ if {$key == "u" || $key == "U"} {menu_vumeter $topname 1}
+ if {$key == "c" || $key == "C"} {menu_mycnv $topname 1}
+############iemlib##################
+}
+
+proc pdtk_canvas_ctrlkey {name key shift} {
+# first get rid of ".c" suffix; we'll refer to the toplevel instead
+ set topname [string trimright $name .c]
+# puts stderr [concat ctrl-key $key $topname]
+
+ if {$key == "n" || $key == "N"} {menu_new}
+ if {$key == "o" || $key == "O"} {menu_open}
+ if {$key == "m" || $key == "M"} {menu_send}
+ if {$key == "q" || $key == "Q"} {
+ if {$shift == 1} {menu_really_quit} else {menu_quit}
+ }
+ if {$key == "s" || $key == "S"} {
+ if {$shift == 1} {menu_saveas $topname} else {menu_save $topname}
+ }
+ if {$key == "w" || $key == "W"} {menu_close $topname}
+ if {$key == "p" || $key == "P"} {menu_print $topname}
+ if {$key == "x" || $key == "X"} {menu_cut $topname}
+ if {$key == "c" || $key == "C"} {menu_copy $topname}
+ if {$key == "v" || $key == "V"} {menu_paste $topname}
+ if {$key == "d" || $key == "D"} {menu_duplicate $topname}
+ if {$key == "a" || $key == "A"} {menu_selectall $topname}
+ if {$key == "t" || $key == "T"} {menu_texteditor $topname}
+ if {$key == "f" || $key == "F"} {menu_findobject $topname}
+ if {$key == "g" || $key == "G"} {menu_findagain $topname}
+ if {$key == "1"} {menu_object $topname 1}
+ if {$key == "2"} {menu_message $topname 1}
+ if {$key == "3"} {menu_floatatom $topname 1}
+ if {$key == "4"} {menu_symbolatom $topname 1}
+ if {$key == "5"} {menu_comment $topname 1}
+ if {$key == "slash"} {menu_audio 1}
+ if {$key == "period"} {menu_audio 0}
+ if {$key == "e" || $key == "E"} {menu_editmode $topname}
+############iemlib##################
+ if {$key == "r" || $key == "R"} {menu_protectmode $topname}
+############iemlib##################
+}
+
+proc pdtk_canvas_motion {name x y mods} {
+# puts stderr [concat [canvastosym $name] $name $x $y]
+ pd [canvastosym $name] motion [$name canvasx $x] [$name canvasy $y] $mods \;
+}
+
+# "map" event tells us when the canvas becomes visible (arg is "0") or
+# invisible (arg is ""). Invisibility means the Window Manager has minimized
+# us. We don't get a final "unmap" event when we destroy the window.
+proc pdtk_canvas_map {name arg} {
+ if {$arg == "0"} {
+ pd [canvastosym $name] map 1 \;
+ } else {
+ pd [canvastosym $name] map 0 \;
+ }
+}
+
+set saveas_dir nowhere
+
+############ pdtk_canvas_saveas -- run a saveas dialog ##############
+
+proc pdtk_canvas_saveas {name initfile initdir} {
+ global pd_nt
+ if {$pd_nt == 2} {
+ cd $initdir
+ set filename [tk_getSaveFile -initialfile $initfile \
+ -defaultextension .pd \
+ -filetypes { {{pd files} {.pd}} {{max files} {.pat}} }]
+ } else {
+ set filename [tk_getSaveFile -initialfile $initfile \
+ -initialdir $initdir -defaultextension .pd \
+ -filetypes { {{pd files} {.pd}} {{max files} {.pat}} }]
+ }
+ if {$filename != ""} {
+ set directory [string range $filename 0 \
+ [expr [string last / $filename ] - 1]]
+ set basename [string range $filename \
+ [expr [string last / $filename ] + 1] end]
+ pd [concat $name savetofile [pdtk_enquote $basename] \
+ [pdtk_enquote $directory] \;]
+# pd [concat $name savetofile $basename $directory \;]
+ }
+}
+
+############ pdtk_canvas_dofont -- run a font and resize dialog #########
+
+set fontsize 0
+set stretchval 0
+set whichstretch 0
+
+proc dofont_apply {name} {
+ global fontsize
+ global stretchval
+ global whichstretch
+ set cmd [concat $name font $fontsize $stretchval $whichstretch \;]
+# puts stderr $cmd
+ pd $cmd
+}
+
+proc dofont_cancel {name} {
+ set cmd [concat $name cancel \;]
+# puts stderr $cmd
+ pd $cmd
+}
+
+proc pdtk_canvas_dofont {name initsize} {
+
+ global fontsize
+ set fontsize $initsize
+
+ global stretchval
+ set stretchval 100
+
+ global whichstretch
+ set whichstretch 1
+
+ toplevel $name
+ wm title $name {FONT BOMB}
+ wm protocol $name WM_DELETE_WINDOW [concat dofont_cancel $name]
+
+ frame $name.buttonframe
+ pack $name.buttonframe -side bottom -fill x -pady 2m
+ button $name.buttonframe.cancel -text {Cancel}\
+ -command "dofont_cancel $name"
+ button $name.buttonframe.ok -text {Do it}\
+ -command "dofont_apply $name"
+ pack $name.buttonframe.cancel -side left -expand 1
+ pack $name.buttonframe.ok -side left -expand 1
+
+ frame $name.radiof
+ pack $name.radiof -side left
+
+ label $name.radiof.label -text {Font Size:}
+ pack $name.radiof.label -side top
+
+ radiobutton $name.radiof.radio8 -value 8 -variable fontsize -text "8"
+ radiobutton $name.radiof.radio10 -value 10 -variable fontsize -text "10"
+ radiobutton $name.radiof.radio12 -value 12 -variable fontsize -text "12"
+ radiobutton $name.radiof.radio16 -value 16 -variable fontsize -text "16"
+ radiobutton $name.radiof.radio24 -value 24 -variable fontsize -text "24"
+ radiobutton $name.radiof.radio36 -value 36 -variable fontsize -text "36"
+ pack $name.radiof.radio8 -side top -anchor w
+ pack $name.radiof.radio10 -side top -anchor w
+ pack $name.radiof.radio12 -side top -anchor w
+ pack $name.radiof.radio16 -side top -anchor w
+ pack $name.radiof.radio24 -side top -anchor w
+ pack $name.radiof.radio36 -side top -anchor w
+
+ frame $name.stretchf
+ pack $name.stretchf -side left
+
+ label $name.stretchf.label -text {Stretch:}
+ pack $name.stretchf.label -side top
+
+ entry $name.stretchf.entry -textvariable stretchval -width 5
+ pack $name.stretchf.entry -side left
+
+ radiobutton $name.stretchf.radio1 \
+ -value 1 -variable whichstretch -text "X and Y"
+ radiobutton $name.stretchf.radio2 \
+ -value 2 -variable whichstretch -text "X only"
+ radiobutton $name.stretchf.radio3 \
+ -value 3 -variable whichstretch -text "Y only"
+
+ pack $name.stretchf.radio1 -side top -anchor w
+ pack $name.stretchf.radio2 -side top -anchor w
+ pack $name.stretchf.radio3 -side top -anchor w
+
+}
+
+############ pdtk_gatom_dialog -- run a gatom dialog #########
+
+set gatomwidth 0
+set gatomlo 0
+set gatomhi 0
+
+proc dogatom_apply {name} {
+ global gatomwidth gatomlo gatomhi
+ set cmd [concat $name param $gatomwidth $gatomlo $gatomhi \;]
+# puts stderr $cmd
+ pd $cmd
+}
+
+proc dogatom_cancel {name} {
+ set cmd [concat $name cancel \;]
+# puts stderr $cmd
+ pd $cmd
+}
+
+proc dogatom_ok {name} {
+ dogatom_apply $name
+ dogatom_cancel $name
+}
+
+proc pdtk_gatom_dialog {name initwidth initlo inithi} {
+
+ global gatomwidth gatomlo gatomhi
+ set gatomwidth $initwidth
+ set gatomlo $initlo
+ set gatomhi $inithi
+
+ toplevel $name
+ wm title $name {Atom}
+ wm protocol $name WM_DELETE_WINDOW [concat dogatom_cancel $name]
+
+ frame $name.buttonframe
+ pack $name.buttonframe -side bottom -fill x -pady 2m
+ button $name.buttonframe.cancel -text {Cancel}\
+ -command "dogatom_cancel $name"
+ button $name.buttonframe.ok -text {Apply}\
+ -command "dogatom_apply $name"
+ pack $name.buttonframe.cancel -side left -expand 1
+ pack $name.buttonframe.ok -side left -expand 1
+
+ frame $name.paramhi
+ pack $name.paramhi -side bottom
+ label $name.paramhi.entryname -text "upper limit"
+ entry $name.paramhi.entry -textvariable gatomhi -width 8
+ pack $name.paramhi.entryname $name.paramhi.entry -side left
+
+ frame $name.paramlo
+ pack $name.paramlo -side bottom
+ label $name.paramlo.entryname -text "lower limit"
+ entry $name.paramlo.entry -textvariable gatomlo -width 8
+ pack $name.paramlo.entryname $name.paramlo.entry -side left
+
+ frame $name.params
+ pack $name.params -side bottom
+ label $name.params.entryname -text width
+ entry $name.params.entry -textvariable gatomwidth -width 4
+ pack $name.params.entryname $name.params.entry -side left
+
+ bind $name.paramhi.entry <KeyPress-Return> [concat dogatom_ok $name]
+ bind $name.paramlo.entry <KeyPress-Return> [concat dogatom_ok $name]
+ bind $name.params.entry <KeyPress-Return> [concat dogatom_ok $name]
+ $name.params.entry select from 0
+ $name.params.entry select adjust end
+ focus $name.params.entry
+}
+
+############ pdtk_canvas_popup -- popup menu for canvas #########
+
+set popup_xpix 0
+set popup_ypix 0
+
+proc popup_action {name action} {
+ global popup_xpix popup_ypix
+ set cmd [concat $name done-popup $action $popup_xpix $popup_ypix \;]
+# puts stderr $cmd
+ pd $cmd
+}
+
+proc pdtk_canvas_popup {name xpix ypix canprop canopen} {
+ global popup_xpix popup_ypix
+ set popup_xpix $xpix
+ set popup_ypix $ypix
+ if {$canprop == 0} {$name.popup entryconfigure 0 -state disabled}
+ if {$canprop == 1} {$name.popup entryconfigure 0 -state active}
+ if {$canopen == 0} {$name.popup entryconfigure 1 -state disabled}
+ if {$canopen == 1} {$name.popup entryconfigure 1 -state active}
+ tk_popup $name.popup [expr $xpix + [winfo rootx $name.c]] \
+ [expr $ypix + [winfo rooty $name.c]] 0
+}
+
+############ pdtk_graph_dialog -- dialog window for graphs #########
+
+# the graph and array dialogs can come up in many copies; but in TK the easiest
+# way to get data from an "entry", etc., is to set an associated variable
+# name. This is especially true for grouped "radio buttons". So we have
+# to synthesize variable names for each instance of the dialog. The dialog
+# gets a TK pathname $id, from which it strips the leading "." to make a
+# variable suffix $vid. Then you can get the actual value out by asking for
+# [eval concat $$variablename]. There should be an easier way but I don't see
+# it yet.
+
+proc graph_apply {id} {
+# strip "." from the TK id to make a variable name suffix
+ set vid [string trimleft $id .]
+# for each variable, make a local variable to hold its name...
+ set var_graph_x1 [concat graph_x1_$vid]
+ global $var_graph_x1
+ set var_graph_x2 [concat graph_x2_$vid]
+ global $var_graph_x2
+ set var_graph_xpix [concat graph_xpix_$vid]
+ global $var_graph_xpix
+ set var_graph_y1 [concat graph_y1_$vid]
+ global $var_graph_y1
+ set var_graph_y2 [concat graph_y2_$vid]
+ global $var_graph_y2
+ set var_graph_ypix [concat graph_ypix_$vid]
+ global $var_graph_ypix
+
+ pd [concat $id dialog \
+ [eval concat $$var_graph_x1] \
+ [eval concat $$var_graph_y1] \
+ [eval concat $$var_graph_x2] \
+ [eval concat $$var_graph_y2] \
+ [eval concat $$var_graph_xpix] \
+ [eval concat $$var_graph_ypix] \
+ \;]
+}
+
+proc graph_cancel {id} {
+ set cmd [concat $id cancel \;]
+# puts stderr $cmd
+ pd $cmd
+}
+
+proc graph_ok {id} {
+ graph_apply $id
+ graph_cancel $id
+}
+
+proc pdtk_graph_dialog {id x1 y1 x2 y2 xpix ypix} {
+ set vid [string trimleft $id .]
+ set var_graph_x1 [concat graph_x1_$vid]
+ global $var_graph_x1
+ set var_graph_x2 [concat graph_x2_$vid]
+ global $var_graph_x2
+ set var_graph_xpix [concat graph_xpix_$vid]
+ global $var_graph_xpix
+ set var_graph_y1 [concat graph_y1_$vid]
+ global $var_graph_y1
+ set var_graph_y2 [concat graph_y2_$vid]
+ global $var_graph_y2
+ set var_graph_ypix [concat graph_ypix_$vid]
+ global $var_graph_ypix
+
+ set $var_graph_x1 $x1
+ set $var_graph_x2 $x2
+ set $var_graph_xpix $xpix
+ set $var_graph_y1 $y1
+ set $var_graph_y2 $y2
+ set $var_graph_ypix $ypix
+
+ toplevel $id
+ wm title $id {graph}
+ wm protocol $id WM_DELETE_WINDOW [concat graph_cancel $id]
+
+ label $id.label -text {GRAPH BOUNDS}
+ pack $id.label -side top
+
+ frame $id.buttonframe
+ pack $id.buttonframe -side bottom -fill x -pady 2m
+ button $id.buttonframe.cancel -text {Cancel}\
+ -command "graph_cancel $id"
+ button $id.buttonframe.apply -text {Apply}\
+ -command "graph_apply $id"
+ button $id.buttonframe.ok -text {OK}\
+ -command "graph_ok $id"
+ pack $id.buttonframe.cancel -side left -expand 1
+ pack $id.buttonframe.apply -side left -expand 1
+ pack $id.buttonframe.ok -side left -expand 1
+
+ frame $id.xrangef
+ pack $id.xrangef -side top
+
+ label $id.xrangef.l1 -text "X from:"
+ entry $id.xrangef.x1 -textvariable $var_graph_x1 -width 7
+ label $id.xrangef.l2 -text "to:"
+ entry $id.xrangef.x2 -textvariable $var_graph_x2 -width 7
+ label $id.xrangef.l3 -text "screen width:"
+ entry $id.xrangef.xpix -textvariable $var_graph_xpix -width 7
+ pack $id.xrangef.l1 $id.xrangef.x1 \
+ $id.xrangef.l2 $id.xrangef.x2 \
+ $id.xrangef.l3 $id.xrangef.xpix -side left
+
+ frame $id.yrangef
+ pack $id.yrangef -side top
+
+# dig in the following that the upper bound is labeled y1 but the variable is
+# y2, etc. This is to deal with the inconsistent use of "upper and lower"
+# graph bounds... in the dialog the upper Y bound is the lower valued Y pixel.
+ label $id.yrangef.l1 -text "Y from:"
+ entry $id.yrangef.y1 -textvariable $var_graph_y2 -width 7
+ label $id.yrangef.l2 -text "to:"
+ entry $id.yrangef.y2 -textvariable $var_graph_y1 -width 7
+ label $id.yrangef.l3 -text "screen height:"
+ entry $id.yrangef.ypix -textvariable $var_graph_ypix -width 7
+ pack $id.yrangef.l1 $id.yrangef.y1 \
+ $id.yrangef.l2 $id.yrangef.y2 \
+ $id.yrangef.l3 $id.yrangef.ypix -side left
+
+ bind $id.xrangef.x1 <KeyPress-Return> [concat graph_ok $id]
+ bind $id.xrangef.x2 <KeyPress-Return> [concat graph_ok $id]
+ bind $id.xrangef.xpix <KeyPress-Return> [concat graph_ok $id]
+ bind $id.yrangef.y1 <KeyPress-Return> [concat graph_ok $id]
+ bind $id.yrangef.y2 <KeyPress-Return> [concat graph_ok $id]
+ bind $id.yrangef.ypix <KeyPress-Return> [concat graph_ok $id]
+ $id.xrangef.x2 select from 0
+ $id.xrangef.x2 select adjust end
+ focus $id.xrangef.x2
+}
+
+# begin of change "iemlib"
+############ pdtk_iemgui_dialog -- dialog window for iem guis #########
+
+set iemgui_define_min_flashhold 50
+set iemgui_define_min_flashbreak 10
+set iemgui_define_min_fontsize 4
+
+proc iemgui_clip_dim {id} {
+ set vid [string trimleft $id .]
+
+ set var_iemgui_wdt [concat iemgui_wdt_$vid]
+ global $var_iemgui_wdt
+ set var_iemgui_min_wdt [concat iemgui_min_wdt_$vid]
+ global $var_iemgui_min_wdt
+ set var_iemgui_hgt [concat iemgui_hgt_$vid]
+ global $var_iemgui_hgt
+ set var_iemgui_min_hgt [concat iemgui_min_hgt_$vid]
+ global $var_iemgui_min_hgt
+
+ if {[eval concat $$var_iemgui_wdt] < [eval concat $$var_iemgui_min_wdt]} {
+ set $var_iemgui_wdt [eval concat $$var_iemgui_min_wdt]
+ $id.dim.w_ent configure -textvariable $var_iemgui_wdt
+ }
+ if {[eval concat $$var_iemgui_hgt] < [eval concat $$var_iemgui_min_hgt]} {
+ set $var_iemgui_hgt [eval concat $$var_iemgui_min_hgt]
+ $id.dim.h_ent configure -textvariable $var_iemgui_hgt
+ }
+}
+
+proc iemgui_clip_num {id} {
+ set vid [string trimleft $id .]
+
+ set var_iemgui_num [concat iemgui_num_$vid]
+ global $var_iemgui_num
+
+ if {[eval concat $$var_iemgui_num] > 2000} {
+ set $var_iemgui_num 2000
+ $id.para.num_ent configure -textvariable $var_iemgui_num
+ }
+ if {[eval concat $$var_iemgui_num] < 1} {
+ set $var_iemgui_num 1
+ $id.para.num_ent configure -textvariable $var_iemgui_num
+ }
+}
+
+proc iemgui_sched_rng {id} {
+ set vid [string trimleft $id .]
+
+ set var_iemgui_min_rng [concat iemgui_min_rng_$vid]
+ global $var_iemgui_min_rng
+ set var_iemgui_max_rng [concat iemgui_max_rng_$vid]
+ global $var_iemgui_max_rng
+ set var_iemgui_rng_sch [concat iemgui_rng_sch_$vid]
+ global $var_iemgui_rng_sch
+
+ global iemgui_define_min_flashhold
+ global iemgui_define_min_flashbreak
+
+ if {[eval concat $$var_iemgui_rng_sch] == 2} {
+ if {[eval concat $$var_iemgui_max_rng] < [eval concat $$var_iemgui_min_rng]} {
+ set hhh [eval concat $$var_iemgui_min_rng]
+ set $var_iemgui_min_rng [eval concat $$var_iemgui_max_rng]
+ set $var_iemgui_max_rng $hhh
+ $id.rng.max_ent configure -textvariable $var_iemgui_max_rng
+ $id.rng.min_ent configure -textvariable $var_iemgui_min_rng }
+ if {[eval concat $$var_iemgui_max_rng] < $iemgui_define_min_flashhold} {
+ set $var_iemgui_max_rng $iemgui_define_min_flashhold
+ $id.rng.max_ent configure -textvariable $var_iemgui_max_rng
+ }
+ if {[eval concat $$var_iemgui_min_rng] < $iemgui_define_min_flashbreak} {
+ set $var_iemgui_min_rng $iemgui_define_min_flashbreak
+ $id.rng.min_ent configure -textvariable $var_iemgui_min_rng
+ }
+ }
+ if {[eval concat $$var_iemgui_rng_sch] == 1} {
+ if {[eval concat $$var_iemgui_min_rng] == 0.0} {
+ set $var_iemgui_min_rng 1.0
+ $id.rng.min_ent configure -textvariable $var_iemgui_min_rng
+ }
+ }
+}
+
+proc iemgui_verify_rng {id} {
+ set vid [string trimleft $id .]
+
+ set var_iemgui_min_rng [concat iemgui_min_rng_$vid]
+ global $var_iemgui_min_rng
+ set var_iemgui_max_rng [concat iemgui_max_rng_$vid]
+ global $var_iemgui_max_rng
+ set var_iemgui_lin0_log1 [concat iemgui_lin0_log1_$vid]
+ global $var_iemgui_lin0_log1
+
+ if {[eval concat $$var_iemgui_lin0_log1] == 1} {
+ if {[eval concat $$var_iemgui_max_rng] == 0.0 && [eval concat $$var_iemgui_min_rng] == 0.0} {
+ set $var_iemgui_max_rng 1.0
+ $id.rng.max_ent configure -textvariable $var_iemgui_max_rng
+ }
+ if {[eval concat $$var_iemgui_max_rng] > 0} {
+ if {[eval concat $$var_iemgui_min_rng] <= 0} {
+ set $var_iemgui_min_rng [expr [eval concat $$var_iemgui_max_rng] * 0.01]
+ $id.rng.min_ent configure -textvariable $var_iemgui_min_rng
+ }
+ } else {
+ if {[eval concat $$var_iemgui_min_rng] > 0} {
+ set $var_iemgui_max_rng [expr [eval concat $$var_iemgui_min_rng] * 0.01]
+ $id.rng.max_ent configure -textvariable $var_iemgui_max_rng
+ }
+ }
+ }
+}
+
+proc iemgui_clip_fontsize {id} {
+ set vid [string trimleft $id .]
+
+ set var_iemgui_gn_fs [concat iemgui_gn_fs_$vid]
+ global $var_iemgui_gn_fs
+
+ global iemgui_define_min_fontsize
+
+ if {[eval concat $$var_iemgui_gn_fs] < $iemgui_define_min_fontsize} {
+ set $var_iemgui_gn_fs $iemgui_define_min_fontsize
+ $id.gnfs.fs_ent configure -textvariable $var_iemgui_gn_fs
+ }
+}
+
+proc iemgui_set_col_example {id} {
+ set vid [string trimleft $id .]
+
+ set var_iemgui_bcol [concat iemgui_bcol_$vid]
+ global $var_iemgui_bcol
+ set var_iemgui_fcol [concat iemgui_fcol_$vid]
+ global $var_iemgui_fcol
+ set var_iemgui_lcol [concat iemgui_lcol_$vid]
+ global $var_iemgui_lcol
+
+ $id.col_example_choose.lb_bk configure \
+ -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+ -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+ -foreground [format "#%6.6x" [eval concat $$var_iemgui_lcol]] \
+ -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_lcol]]
+
+ if { [eval concat $$var_iemgui_fcol] >= 0 } {
+ $id.col_example_choose.fr_bk configure \
+ -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+ -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+ -foreground [format "#%6.6x" [eval concat $$var_iemgui_fcol]] \
+ -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_fcol]]
+ } else {
+ $id.col_example_choose.fr_bk configure \
+ -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+ -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+ -foreground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+ -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_bcol]]}
+}
+
+proc iemgui_preset_col {id presetcol} {
+ set vid [string trimleft $id .]
+
+ set var_iemgui_l2_f1_b0 [concat iemgui_l2_f1_b0_$vid]
+ global $var_iemgui_l2_f1_b0
+ set var_iemgui_bcol [concat iemgui_bcol_$vid]
+ global $var_iemgui_bcol
+ set var_iemgui_fcol [concat iemgui_fcol_$vid]
+ global $var_iemgui_fcol
+ set var_iemgui_lcol [concat iemgui_lcol_$vid]
+ global $var_iemgui_lcol
+
+ if { [eval concat $$var_iemgui_l2_f1_b0] == 0 } { set $var_iemgui_bcol $presetcol }
+ if { [eval concat $$var_iemgui_l2_f1_b0] == 1 } { set $var_iemgui_fcol $presetcol }
+ if { [eval concat $$var_iemgui_l2_f1_b0] == 2 } { set $var_iemgui_lcol $presetcol }
+ iemgui_set_col_example $id
+}
+
+proc iemgui_choose_col_bkfrlb {id} {
+ set vid [string trimleft $id .]
+
+ set var_iemgui_l2_f1_b0 [concat iemgui_l2_f1_b0_$vid]
+ global $var_iemgui_l2_f1_b0
+ set var_iemgui_bcol [concat iemgui_bcol_$vid]
+ global $var_iemgui_bcol
+ set var_iemgui_fcol [concat iemgui_fcol_$vid]
+ global $var_iemgui_fcol
+ set var_iemgui_lcol [concat iemgui_lcol_$vid]
+ global $var_iemgui_lcol
+
+ if {[eval concat $$var_iemgui_l2_f1_b0] == 0} {
+ set $var_iemgui_bcol [expr [eval concat $$var_iemgui_bcol] & 0xFCFCFC]
+ set helpstring [tk_chooseColor -title "Background-Color" -initialcolor [format "#%6.6x" [eval concat $$var_iemgui_bcol]]]
+ if { $helpstring != "" } {
+ set $var_iemgui_bcol [string replace $helpstring 0 0 "0x"]
+ set $var_iemgui_bcol [expr [eval concat $$var_iemgui_bcol] & 0xFCFCFC] }
+ }
+ if {[eval concat $$var_iemgui_l2_f1_b0] == 1} {
+ set $var_iemgui_fcol [expr [eval concat $$var_iemgui_fcol] & 0xFCFCFC]
+ set helpstring [tk_chooseColor -title "Front-Color" -initialcolor [format "#%6.6x" [eval concat $$var_iemgui_fcol]]]
+ if { $helpstring != "" } {
+ set $var_iemgui_fcol [string replace $helpstring 0 0 "0x"]
+ set $var_iemgui_fcol [expr [eval concat $$var_iemgui_fcol] & 0xFCFCFC] }
+ }
+ if {[eval concat $$var_iemgui_l2_f1_b0] == 2} {
+ set $var_iemgui_lcol [expr [eval concat $$var_iemgui_lcol] & 0xFCFCFC]
+ set helpstring [tk_chooseColor -title "Label-Color" -initialcolor [format "#%6.6x" [eval concat $$var_iemgui_lcol]]]
+ if { $helpstring != "" } {
+ set $var_iemgui_lcol [string replace $helpstring 0 0 "0x"]
+ set $var_iemgui_lcol [expr [eval concat $$var_iemgui_lcol] & 0xFCFCFC] }
+ }
+ iemgui_set_col_example $id
+}
+
+proc iemgui_lilo {id} {
+ set vid [string trimleft $id .]
+
+ set var_iemgui_lin0_log1 [concat iemgui_lin0_log1_$vid]
+ global $var_iemgui_lin0_log1
+ set var_iemgui_lilo0 [concat iemgui_lilo0_$vid]
+ global $var_iemgui_lilo0
+ set var_iemgui_lilo1 [concat iemgui_lilo1_$vid]
+ global $var_iemgui_lilo1
+
+ iemgui_sched_rng $id
+
+ if {[eval concat $$var_iemgui_lin0_log1] == 0} {
+ set $var_iemgui_lin0_log1 1
+ $id.para.lilo configure -text [eval concat $$var_iemgui_lilo1]
+ iemgui_verify_rng $id
+ iemgui_sched_rng $id
+ } else {
+ set $var_iemgui_lin0_log1 0
+ $id.para.lilo configure -text [eval concat $$var_iemgui_lilo0]
+ }
+}
+
+proc iemgui_toggle_font {id} {
+ set vid [string trimleft $id .]
+
+ set var_iemgui_gn_f [concat iemgui_gn_f_$vid]
+ global $var_iemgui_gn_f
+
+ set $var_iemgui_gn_f [expr [eval concat $$var_iemgui_gn_f] + 1]
+ if {[eval concat $$var_iemgui_gn_f] > 2} {set $var_iemgui_gn_f 0}
+ if {[eval concat $$var_iemgui_gn_f] == 0} {$id.gnfs.fb configure -text "courier" -font {courier 10 bold}}
+ if {[eval concat $$var_iemgui_gn_f] == 1} {$id.gnfs.fb configure -text "helvetica" -font {helvetica 10 bold}}
+ if {[eval concat $$var_iemgui_gn_f] == 2} {$id.gnfs.fb configure -text "times" -font {times 10 bold}}
+}
+
+proc iemgui_lb {id} {
+ set vid [string trimleft $id .]
+
+ set var_iemgui_loadbang [concat iemgui_loadbang_$vid]
+ global $var_iemgui_loadbang
+
+ if {[eval concat $$var_iemgui_loadbang] == 0} {
+ set $var_iemgui_loadbang 1
+ $id.para.lb configure -text "init"
+ } else {
+ set $var_iemgui_loadbang 0
+ $id.para.lb configure -text "no init"
+ }
+}
+
+proc iemgui_stdy_jmp {id} {
+ set vid [string trimleft $id .]
+
+ set var_iemgui_steady [concat iemgui_steady_$vid]
+ global $var_iemgui_steady
+
+ if {[eval concat $$var_iemgui_steady]} {
+ set $var_iemgui_steady 0
+ $id.para.stdy_jmp configure -text "jump on click"
+ } else {
+ set $var_iemgui_steady 1
+ $id.para.stdy_jmp configure -text "steady on click"
+ }
+}
+
+proc iemgui_apply {id} {
+ set vid [string trimleft $id .]
+
+ set var_iemgui_wdt [concat iemgui_wdt_$vid]
+ global $var_iemgui_wdt
+ set var_iemgui_min_wdt [concat iemgui_min_wdt_$vid]
+ global $var_iemgui_min_wdt
+ set var_iemgui_hgt [concat iemgui_hgt_$vid]
+ global $var_iemgui_hgt
+ set var_iemgui_min_hgt [concat iemgui_min_hgt_$vid]
+ global $var_iemgui_min_hgt
+ set var_iemgui_min_rng [concat iemgui_min_rng_$vid]
+ global $var_iemgui_min_rng
+ set var_iemgui_max_rng [concat iemgui_max_rng_$vid]
+ global $var_iemgui_max_rng
+ set var_iemgui_lin0_log1 [concat iemgui_lin0_log1_$vid]
+ global $var_iemgui_lin0_log1
+ set var_iemgui_lilo0 [concat iemgui_lilo0_$vid]
+ global $var_iemgui_lilo0
+ set var_iemgui_lilo1 [concat iemgui_lilo1_$vid]
+ global $var_iemgui_lilo1
+ set var_iemgui_loadbang [concat iemgui_loadbang_$vid]
+ global $var_iemgui_loadbang
+ set var_iemgui_num [concat iemgui_num_$vid]
+ global $var_iemgui_num
+ set var_iemgui_steady [concat iemgui_steady_$vid]
+ global $var_iemgui_steady
+ set var_iemgui_snd [concat iemgui_snd_$vid]
+ global $var_iemgui_snd
+ set var_iemgui_rcv [concat iemgui_rcv_$vid]
+ global $var_iemgui_rcv
+ set var_iemgui_gui_nam [concat iemgui_gui_nam_$vid]
+ global $var_iemgui_gui_nam
+ set var_iemgui_gn_dx [concat iemgui_gn_dx_$vid]
+ global $var_iemgui_gn_dx
+ set var_iemgui_gn_dy [concat iemgui_gn_dy_$vid]
+ global $var_iemgui_gn_dy
+ set var_iemgui_gn_f [concat iemgui_gn_f_$vid]
+ global $var_iemgui_gn_f
+ set var_iemgui_gn_fs [concat iemgui_gn_fs_$vid]
+ global $var_iemgui_gn_fs
+ set var_iemgui_bcol [concat iemgui_bcol_$vid]
+ global $var_iemgui_bcol
+ set var_iemgui_fcol [concat iemgui_fcol_$vid]
+ global $var_iemgui_fcol
+ set var_iemgui_lcol [concat iemgui_lcol_$vid]
+ global $var_iemgui_lcol
+
+ iemgui_clip_dim $id
+ iemgui_clip_num $id
+ iemgui_sched_rng $id
+ iemgui_verify_rng $id
+ iemgui_sched_rng $id
+ iemgui_clip_fontsize $id
+
+ if {[eval concat $$var_iemgui_snd] == ""} {set hhhsnd "empty"} else {set hhhsnd [eval concat $$var_iemgui_snd]}
+ if {[eval concat $$var_iemgui_rcv] == ""} {set hhhrcv "empty"} else {set hhhrcv [eval concat $$var_iemgui_rcv]}
+ if {[eval concat $$var_iemgui_gui_nam] == ""} {set hhhgui_nam "empty"
+ } else {
+ set hhhgui_nam [eval concat $$var_iemgui_gui_nam]}
+
+ if {[string index $hhhsnd 0] == "$"} {
+ set hhhsnd [string replace $hhhsnd 0 0 #] }
+ if {[string index $hhhrcv 0] == "$"} {
+ set hhhrcv [string replace $hhhrcv 0 0 #] }
+ if {[string index $hhhgui_nam 0] == "$"} {
+ set hhhgui_nam [string replace $hhhgui_nam 0 0 #] }
+
+ pd [concat $id dialog \
+ [eval concat $$var_iemgui_wdt] \
+ [eval concat $$var_iemgui_hgt] \
+ [eval concat $$var_iemgui_min_rng] \
+ [eval concat $$var_iemgui_max_rng] \
+ [eval concat $$var_iemgui_lin0_log1] \
+ [eval concat $$var_iemgui_loadbang] \
+ [eval concat $$var_iemgui_num] \
+ $hhhsnd \
+ $hhhrcv \
+ $hhhgui_nam \
+ [eval concat $$var_iemgui_gn_dx] \
+ [eval concat $$var_iemgui_gn_dy] \
+ [eval concat $$var_iemgui_gn_f] \
+ [eval concat $$var_iemgui_gn_fs] \
+ [eval concat $$var_iemgui_bcol] \
+ [eval concat $$var_iemgui_fcol] \
+ [eval concat $$var_iemgui_lcol] \
+ [eval concat $$var_iemgui_steady] \
+ \;]
+}
+
+proc iemgui_cancel {id} {pd [concat $id cancel \;]}
+
+proc iemgui_ok {id} {
+ iemgui_apply $id
+ iemgui_cancel $id
+}
+
+proc pdtk_iemgui_dialog {id mainheader \
+ dim_header wdt min_wdt wdt_label hgt min_hgt hgt_label \
+ rng_header min_rng min_rng_label max_rng max_rng_label rng_sched \
+ lin0_log1 lilo0_label lilo1_label loadbang steady num_label num \
+ snd rcv \
+ gui_name \
+ gn_dx gn_dy \
+ gn_f gn_fs \
+ bcol fcol lcol} {
+
+ set vid [string trimleft $id .]
+
+ set var_iemgui_wdt [concat iemgui_wdt_$vid]
+ global $var_iemgui_wdt
+ set var_iemgui_min_wdt [concat iemgui_min_wdt_$vid]
+ global $var_iemgui_min_wdt
+ set var_iemgui_hgt [concat iemgui_hgt_$vid]
+ global $var_iemgui_hgt
+ set var_iemgui_min_hgt [concat iemgui_min_hgt_$vid]
+ global $var_iemgui_min_hgt
+ set var_iemgui_min_rng [concat iemgui_min_rng_$vid]
+ global $var_iemgui_min_rng
+ set var_iemgui_max_rng [concat iemgui_max_rng_$vid]
+ global $var_iemgui_max_rng
+ set var_iemgui_rng_sch [concat iemgui_rng_sch_$vid]
+ global $var_iemgui_rng_sch
+ set var_iemgui_lin0_log1 [concat iemgui_lin0_log1_$vid]
+ global $var_iemgui_lin0_log1
+ set var_iemgui_lilo0 [concat iemgui_lilo0_$vid]
+ global $var_iemgui_lilo0
+ set var_iemgui_lilo1 [concat iemgui_lilo1_$vid]
+ global $var_iemgui_lilo1
+ set var_iemgui_loadbang [concat iemgui_loadbang_$vid]
+ global $var_iemgui_loadbang
+ set var_iemgui_num [concat iemgui_num_$vid]
+ global $var_iemgui_num
+ set var_iemgui_steady [concat iemgui_steady_$vid]
+ global $var_iemgui_steady
+ set var_iemgui_snd [concat iemgui_snd_$vid]
+ global $var_iemgui_snd
+ set var_iemgui_rcv [concat iemgui_rcv_$vid]
+ global $var_iemgui_rcv
+ set var_iemgui_gui_nam [concat iemgui_gui_nam_$vid]
+ global $var_iemgui_gui_nam
+ set var_iemgui_gn_dx [concat iemgui_gn_dx_$vid]
+ global $var_iemgui_gn_dx
+ set var_iemgui_gn_dy [concat iemgui_gn_dy_$vid]
+ global $var_iemgui_gn_dy
+ set var_iemgui_gn_f [concat iemgui_gn_f_$vid]
+ global $var_iemgui_gn_f
+ set var_iemgui_gn_fs [concat iemgui_gn_fs_$vid]
+ global $var_iemgui_gn_fs
+ set var_iemgui_l2_f1_b0 [concat iemgui_l2_f1_b0_$vid]
+ global $var_iemgui_l2_f1_b0
+ set var_iemgui_bcol [concat iemgui_bcol_$vid]
+ global $var_iemgui_bcol
+ set var_iemgui_fcol [concat iemgui_fcol_$vid]
+ global $var_iemgui_fcol
+ set var_iemgui_lcol [concat iemgui_lcol_$vid]
+ global $var_iemgui_lcol
+
+ set $var_iemgui_wdt $wdt
+ set $var_iemgui_min_wdt $min_wdt
+ set $var_iemgui_hgt $hgt
+ set $var_iemgui_min_hgt $min_hgt
+ set $var_iemgui_min_rng $min_rng
+ set $var_iemgui_max_rng $max_rng
+ set $var_iemgui_rng_sch $rng_sched
+ set $var_iemgui_lin0_log1 $lin0_log1
+ set $var_iemgui_lilo0 $lilo0_label
+ set $var_iemgui_lilo1 $lilo1_label
+ set $var_iemgui_loadbang $loadbang
+ set $var_iemgui_num $num
+ set $var_iemgui_steady $steady
+ if {$snd == "empty"} {set $var_iemgui_snd [format ""]
+ } else {set $var_iemgui_snd [format "%s" $snd]}
+ if {$rcv == "empty"} {set $var_iemgui_rcv [format ""]
+ } else {set $var_iemgui_rcv [format "%s" $rcv]}
+ if {$gui_name == "empty"} {set $var_iemgui_gui_nam [format ""]
+ } else {set $var_iemgui_gui_nam [format "%s" $gui_name]}
+
+ if {[string index [eval concat $$var_iemgui_snd] 0] == "#"} {
+ set $var_iemgui_snd [string replace [eval concat $$var_iemgui_snd] 0 0 $] }
+ if {[string index [eval concat $$var_iemgui_rcv] 0] == "#"} {
+ set $var_iemgui_rcv [string replace [eval concat $$var_iemgui_rcv] 0 0 $] }
+ if {[string index [eval concat $$var_iemgui_gui_nam] 0] == "#"} {
+ set $var_iemgui_gui_nam [string replace [eval concat $$var_iemgui_gui_nam] 0 0 $] }
+ set $var_iemgui_gn_dx $gn_dx
+ set $var_iemgui_gn_dy $gn_dy
+ set $var_iemgui_gn_f $gn_f
+ set $var_iemgui_gn_fs $gn_fs
+
+ set $var_iemgui_bcol $bcol
+ set $var_iemgui_fcol $fcol
+ set $var_iemgui_lcol $lcol
+
+ set $var_iemgui_l2_f1_b0 0
+
+ toplevel $id
+ wm title $id [format "%s-PROPERTIES" $mainheader]
+ wm protocol $id WM_DELETE_WINDOW [concat iemgui_cancel $id]
+
+ frame $id.dim
+ pack $id.dim -side top
+ label $id.dim.head -text $dim_header
+ label $id.dim.w_lab -text $wdt_label -width 6
+ entry $id.dim.w_ent -textvariable $var_iemgui_wdt -width 5
+ label $id.dim.dummy1 -text " " -width 10
+ label $id.dim.h_lab -text $hgt_label -width 6
+ entry $id.dim.h_ent -textvariable $var_iemgui_hgt -width 5
+ pack $id.dim.head -side top
+ pack $id.dim.w_lab $id.dim.w_ent $id.dim.dummy1 -side left
+ if { $hgt_label != "empty" } {
+ pack $id.dim.h_lab $id.dim.h_ent -side left}
+
+ frame $id.rng
+ pack $id.rng -side top
+ label $id.rng.head -text $rng_header
+ label $id.rng.min_lab -text $min_rng_label -width 6
+ entry $id.rng.min_ent -textvariable $var_iemgui_min_rng -width 9
+ label $id.rng.dummy1 -text " " -width 1
+ label $id.rng.max_lab -text $max_rng_label -width 8
+ entry $id.rng.max_ent -textvariable $var_iemgui_max_rng -width 9
+ if { $rng_header != "empty" } {
+ pack $id.rng.head -side top
+ if { $min_rng_label != "empty" } {
+ pack $id.rng.min_lab $id.rng.min_ent -side left}
+ if { $max_rng_label != "empty" } {
+ pack $id.rng.dummy1 \
+ $id.rng.max_lab $id.rng.max_ent -side left} }
+
+ if { [eval concat $$var_iemgui_lin0_log1] >= 0 || [eval concat $$var_iemgui_loadbang] >= 0 || [eval concat $$var_iemgui_num] > 0 || [eval concat $$var_iemgui_steady] >= 0 } {
+ label $id.space1 -text "---------------------------------"
+ pack $id.space1 -side top }
+
+ frame $id.para
+ pack $id.para -side top
+ label $id.para.dummy2 -text "" -width 1
+ label $id.para.dummy3 -text "" -width 1
+ if {[eval concat $$var_iemgui_lin0_log1] == 0} {
+ button $id.para.lilo -text [eval concat $$var_iemgui_lilo0] -width 5 -command "iemgui_lilo $id" }
+ if {[eval concat $$var_iemgui_lin0_log1] == 1} {
+ button $id.para.lilo -text [eval concat $$var_iemgui_lilo1] -width 5 -command "iemgui_lilo $id" }
+ if {[eval concat $$var_iemgui_loadbang] == 0} {
+ button $id.para.lb -text "no init" -width 5 -command "iemgui_lb $id" }
+ if {[eval concat $$var_iemgui_loadbang] == 1} {
+ button $id.para.lb -text "init" -width 5 -command "iemgui_lb $id" }
+ label $id.para.num_lab -text $num_label -width 9
+ entry $id.para.num_ent -textvariable $var_iemgui_num -width 4
+ if {[eval concat $$var_iemgui_steady] == 0} {
+ button $id.para.stdy_jmp -text "jump on click" -width 11 -command "iemgui_stdy_jmp $id" }
+ if {[eval concat $$var_iemgui_steady] == 1} {
+ button $id.para.stdy_jmp -text "steady on click" -width 11 -command "iemgui_stdy_jmp $id" }
+ if {[eval concat $$var_iemgui_lin0_log1] >= 0} {
+ pack $id.para.lilo -side left -expand 1}
+ if {[eval concat $$var_iemgui_loadbang] >= 0} {
+ pack $id.para.dummy2 $id.para.lb -side left -expand 1}
+ if {[eval concat $$var_iemgui_num] > 0} {
+ pack $id.para.dummy3 $id.para.num_lab $id.para.num_ent -side left -expand 1}
+ if {[eval concat $$var_iemgui_steady] >= 0} {
+ pack $id.para.dummy3 $id.para.stdy_jmp -side left -expand 1}
+ if { $snd != "nosndno" || $rcv != "norcvno" } {
+ label $id.space2 -text "---------------------------------"
+ pack $id.space2 -side top }
+
+ frame $id.snd
+ pack $id.snd -side top
+ label $id.snd.dummy1 -text "" -width 2
+ label $id.snd.lab -text "send-symbol:" -width 12
+ entry $id.snd.ent -textvariable $var_iemgui_snd -width 20
+ if { $snd != "nosndno" } {
+ pack $id.snd.dummy1 $id.snd.lab $id.snd.ent -side left}
+
+ frame $id.rcv
+ pack $id.rcv -side top
+ label $id.rcv.lab -text "receive-symbol:" -width 15
+ entry $id.rcv.ent -textvariable $var_iemgui_rcv -width 20
+ if { $rcv != "norcvno" } {
+ pack $id.rcv.lab $id.rcv.ent -side left}
+
+ frame $id.gnam
+ pack $id.gnam -side top
+ label $id.gnam.head -text "--------------label:---------------"
+ label $id.gnam.dummy1 -text "" -width 1
+ label $id.gnam.lab -text "name:" -width 6
+ entry $id.gnam.ent -textvariable $var_iemgui_gui_nam -width 29
+ label $id.gnam.dummy2 -text "" -width 1
+ pack $id.gnam.head -side top
+ pack $id.gnam.dummy1 $id.gnam.lab $id.gnam.ent $id.gnam.dummy2 -side left
+
+ frame $id.gnxy
+ pack $id.gnxy -side top
+ label $id.gnxy.x_lab -text "x_off:" -width 6
+ entry $id.gnxy.x_ent -textvariable $var_iemgui_gn_dx -width 5
+ label $id.gnxy.dummy1 -text " " -width 10
+ label $id.gnxy.y_lab -text "y_off:" -width 6
+ entry $id.gnxy.y_ent -textvariable $var_iemgui_gn_dy -width 5
+ pack $id.gnxy.x_lab $id.gnxy.x_ent $id.gnxy.dummy1 \
+ $id.gnxy.y_lab $id.gnxy.y_ent -side left
+
+ frame $id.gnfs
+ pack $id.gnfs -side top
+ label $id.gnfs.f_lab -text "font:" -width 6
+ if {[eval concat $$var_iemgui_gn_f] == 0} {
+ button $id.gnfs.fb -text "courier" -font {courier 10 bold} -width 7 -command "iemgui_toggle_font $id" }
+ if {[eval concat $$var_iemgui_gn_f] == 1} {
+ button $id.gnfs.fb -text "helvetica" -font {helvetica 10 bold} -width 7 -command "iemgui_toggle_font $id" }
+ if {[eval concat $$var_iemgui_gn_f] == 2} {
+ button $id.gnfs.fb -text "times" -font {times 10 bold} -width 7 -command "iemgui_toggle_font $id" }
+ label $id.gnfs.dummy1 -text "" -width 1
+ label $id.gnfs.fs_lab -text "fontsize:" -width 8
+ entry $id.gnfs.fs_ent -textvariable $var_iemgui_gn_fs -width 5
+ pack $id.gnfs.f_lab $id.gnfs.fb $id.gnfs.dummy1 \
+ $id.gnfs.fs_lab $id.gnfs.fs_ent -side left
+
+ label $id.col_head -text "--------------colors:--------------"
+ pack $id.col_head -side top
+
+ frame $id.col_select
+ pack $id.col_select -side top
+ radiobutton $id.col_select.radio0 -value 0 -variable $var_iemgui_l2_f1_b0 \
+ -text "backgd" -width 5
+ radiobutton $id.col_select.radio1 -value 1 -variable $var_iemgui_l2_f1_b0 \
+ -text "front" -width 5
+ radiobutton $id.col_select.radio2 -value 2 -variable $var_iemgui_l2_f1_b0 \
+ -text "label" -width 5
+ if { [eval concat $$var_iemgui_fcol] >= 0 } {
+ pack $id.col_select.radio0 $id.col_select.radio1 $id.col_select.radio2 -side left
+ } else {pack $id.col_select.radio0 $id.col_select.radio2 -side left}
+
+ frame $id.col_example_choose
+ pack $id.col_example_choose -side top
+ button $id.col_example_choose.but -text "compose color" -width 10 \
+ -command "iemgui_choose_col_bkfrlb $id"
+ label $id.col_example_choose.dummy1 -text "" -width 1
+ if { [eval concat $$var_iemgui_fcol] >= 0 } {
+ button $id.col_example_choose.fr_bk -text "o=||=o" -width 5 \
+ -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+ -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+ -foreground [format "#%6.6x" [eval concat $$var_iemgui_fcol]] \
+ -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_fcol]] -pady 2
+ } else {
+ button $id.col_example_choose.fr_bk -text "o=||=o" -width 5 \
+ -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+ -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+ -foreground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+ -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] -pady 2}
+ button $id.col_example_choose.lb_bk -text "testlabel" -width 7 \
+ -background [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+ -activebackground [format "#%6.6x" [eval concat $$var_iemgui_bcol]] \
+ -foreground [format "#%6.6x" [eval concat $$var_iemgui_lcol]] \
+ -activeforeground [format "#%6.6x" [eval concat $$var_iemgui_lcol]] -pady 2
+
+ pack $id.col_example_choose.but $id.col_example_choose.dummy1 \
+ $id.col_example_choose.fr_bk $id.col_example_choose.lb_bk -side left
+
+ label $id.space3 -text "------or click color preset:-------"
+ pack $id.space3 -side top
+
+ frame $id.bcol
+ pack $id.bcol -side top
+ foreach i { 0 1 2 3 4 5 6 7 8 9 } hexcol { 16579836 14737632 12369084 \
+ 16572640 16572608 16579784 14220504 14220540 14476540 16308476 } {
+ button $id.bcol.c$i -background [format "#%6.6x" $hexcol] \
+ -activebackground [format "#%6.6x" $hexcol] \
+ -font {courier 2 normal} -padx 7 -pady 6 \
+ -command [format "iemgui_preset_col %s %d" $id $hexcol] }
+ pack $id.bcol.c0 $id.bcol.c1 $id.bcol.c2 $id.bcol.c3 $id.bcol.c4 \
+ $id.bcol.c5 $id.bcol.c6 $id.bcol.c7 $id.bcol.c8 $id.bcol.c9 -side left
+
+ frame $id.fcol
+ pack $id.fcol -side top
+ foreach i { 0 1 2 3 4 5 6 7 8 9 } hexcol { 10526880 8158332 6316128 \
+ 16525352 16559172 15263784 1370132 2684148 3952892 16003312 } {
+ button $id.fcol.c$i -background [format "#%6.6x" $hexcol] \
+ -activebackground [format "#%6.6x" $hexcol] \
+ -font {courier 2 normal} -padx 7 -pady 6 \
+ -command [format "iemgui_preset_col %s %d" $id $hexcol] }
+ pack $id.fcol.c0 $id.fcol.c1 $id.fcol.c2 $id.fcol.c3 $id.fcol.c4 \
+ $id.fcol.c5 $id.fcol.c6 $id.fcol.c7 $id.fcol.c8 $id.fcol.c9 -side left
+
+ frame $id.lcol
+ pack $id.lcol -side top
+ foreach i { 0 1 2 3 4 5 6 7 8 9 } hexcol { 4210752 2105376 0 \
+ 9177096 5779456 7874580 2641940 17488 5256 5767248 } {
+ button $id.lcol.c$i -background [format "#%6.6x" $hexcol] \
+ -activebackground [format "#%6.6x" $hexcol] \
+ -font {courier 2 normal} -padx 7 -pady 6 \
+ -command [format "iemgui_preset_col %s %d" $id $hexcol] }
+ pack $id.lcol.c0 $id.lcol.c1 $id.lcol.c2 $id.lcol.c3 $id.lcol.c4 \
+ $id.lcol.c5 $id.lcol.c6 $id.lcol.c7 $id.lcol.c8 $id.lcol.c9 -side left
+
+
+ label $id.space4 -text "---------------------------------"
+ pack $id.space4 -side top
+
+ frame $id.cao
+ pack $id.cao -side top
+ button $id.cao.cancel -text {Cancel} -width 6 \
+ -command "iemgui_cancel $id"
+ label $id.cao.dummy1 -text "" -width 3
+ button $id.cao.apply -text {Apply} -width 6 \
+ -command "iemgui_apply $id"
+ label $id.cao.dummy2 -text "" -width 3
+ button $id.cao.ok -text {OK} -width 6 \
+ -command "iemgui_ok $id"
+ pack $id.cao.cancel $id.cao.dummy1 \
+ $id.cao.apply $id.cao.dummy2 \
+ $id.cao.ok -side left
+
+ label $id.space5 -text ""
+ pack $id.space5 -side top
+
+ bind $id.dim.w_ent <KeyPress-Return> [concat iemgui_ok $id]
+ bind $id.dim.h_ent <KeyPress-Return> [concat iemgui_ok $id]
+ bind $id.rng.min_ent <KeyPress-Return> [concat iemgui_ok $id]
+ bind $id.rng.max_ent <KeyPress-Return> [concat iemgui_ok $id]
+ bind $id.para.num_ent <KeyPress-Return> [concat iemgui_ok $id]
+ bind $id.snd.ent <KeyPress-Return> [concat iemgui_ok $id]
+ bind $id.rcv.ent <KeyPress-Return> [concat iemgui_ok $id]
+ bind $id.gnam.ent <KeyPress-Return> [concat iemgui_ok $id]
+ bind $id.gnxy.x_ent <KeyPress-Return> [concat iemgui_ok $id]
+ bind $id.gnxy.y_ent <KeyPress-Return> [concat iemgui_ok $id]
+ bind $id.gnfs.fs_ent <KeyPress-Return> [concat iemgui_ok $id]
+ bind $id.cao.ok <KeyPress-Return> [concat iemgui_ok $id]
+
+ $id.dim.w_ent select from 0
+ $id.dim.w_ent select adjust end
+ focus $id.dim.w_ent
+}
+# end of change "iemlib"
+
+############ pdtk_array_dialog -- dialog window for arrays #########
+proc array_apply {id} {
+# strip "." from the TK id to make a variable name suffix
+ set vid [string trimleft $id .]
+# for each variable, make a local variable to hold its name...
+ set var_array_name [concat array_name_$vid]
+ global $var_array_name
+ set var_array_n [concat array_n_$vid]
+ global $var_array_n
+ set var_array_saveit [concat array_saveit_$vid]
+ global $var_array_saveit
+ set var_array_otherflag [concat array_otherflag_$vid]
+ global $var_array_otherflag
+ set mofo [eval concat $$var_array_name]
+ if {[string index $mofo 0] == "$"} {
+ set mofo [string replace $mofo 0 0 #] }
+
+ pd [concat $id arraydialog $mofo \
+ [eval concat $$var_array_n] \
+ [eval concat $$var_array_saveit] \
+ [eval concat $$var_array_otherflag] \
+ \;]
+}
+
+proc array_cancel {id} {
+ set cmd [concat $id cancel \;]
+ pd $cmd
+}
+
+proc array_ok {id} {
+ array_apply $id
+ array_cancel $id
+}
+
+proc pdtk_array_dialog {id name n saveit newone} {
+ set vid [string trimleft $id .]
+
+ set var_array_name [concat array_name_$vid]
+ global $var_array_name
+ set var_array_n [concat array_n_$vid]
+ global $var_array_n
+ set var_array_saveit [concat array_saveit_$vid]
+ global $var_array_saveit
+ set var_array_otherflag [concat array_otherflag_$vid]
+ global $var_array_otherflag
+
+ set $var_array_name $name
+ set $var_array_n $n
+ set $var_array_saveit $saveit
+ set $var_array_otherflag 0
+
+ toplevel $id
+ wm title $id {array}
+ wm protocol $id WM_DELETE_WINDOW [concat array_cancel $id]
+
+ frame $id.name
+ pack $id.name -side top
+ label $id.name.label -text "name"
+ entry $id.name.entry -textvariable $var_array_name
+ pack $id.name.label $id.name.entry -side left
+
+ frame $id.n
+ pack $id.n -side top
+ label $id.n.label -text "size"
+ entry $id.n.entry -textvariable $var_array_n
+ pack $id.n.label $id.n.entry -side left
+
+ checkbutton $id.saveme -text {save contents} -variable $var_array_saveit \
+ -anchor w
+ pack $id.saveme -side top
+
+ if {$newone != 0} {
+ frame $id.radio
+ pack $id.radio -side top
+ radiobutton $id.radio.radio0 -value 0 \
+ -variable $var_array_otherflag \
+ -text "in new graph"
+ radiobutton $id.radio.radio1 -value 1 \
+ -variable $var_array_otherflag \
+ -text "in last graph"
+ pack $id.radio.radio0 -side top -anchor w
+ pack $id.radio.radio1 -side top -anchor w
+ } else {
+ checkbutton $id.deleteme -text {delete me} \
+ -variable $var_array_otherflag -anchor w
+ pack $id.deleteme -side top
+ }
+ frame $id.buttonframe
+ pack $id.buttonframe -side bottom -fill x -pady 2m
+ button $id.buttonframe.cancel -text {Cancel}\
+ -command "array_cancel $id"
+ if {$newone == 0} {button $id.buttonframe.apply -text {Apply}\
+ -command "array_apply $id"}
+ button $id.buttonframe.ok -text {OK}\
+ -command "array_ok $id"
+ pack $id.buttonframe.cancel -side left -expand 1
+ if {$newone == 0} {pack $id.buttonframe.apply -side left -expand 1}
+ pack $id.buttonframe.ok -side left -expand 1
+
+ bind $id.name.entry <KeyPress-Return> [concat array_ok $id]
+ bind $id.n.entry <KeyPress-Return> [concat array_ok $id]
+ $id.name.entry select from 0
+ $id.name.entry select adjust end
+ focus $id.name.entry
+}
+
+############ pdtk_canvas_dialog -- dialog window for canvass #########
+proc canvas_apply {id} {
+# strip "." from the TK id to make a variable name suffix
+ set vid [string trimleft $id .]
+# for each variable, make a local variable to hold its name...
+ set var_canvas_xscale [concat canvas_xscale_$vid]
+ global $var_canvas_xscale
+ set var_canvas_yscale [concat canvas_yscale_$vid]
+ global $var_canvas_yscale
+ set var_canvas_graphme [concat canvas_graphme_$vid]
+ global $var_canvas_graphme
+# set var_canvas_stretch [concat canvas_stretch_$vid]
+# global $var_canvas_stretch
+ pd [concat $id donecanvasdialog \
+ [eval concat $$var_canvas_xscale] \
+ [eval concat $$var_canvas_yscale] \
+ [eval concat $$var_canvas_graphme] \
+ \;]
+}
+
+proc canvas_cancel {id} {
+ set cmd [concat $id cancel \;]
+ pd $cmd
+}
+
+proc canvas_ok {id} {
+ canvas_apply $id
+ canvas_cancel $id
+}
+
+proc pdtk_canvas_dialog {id xscale yscale graphme stretch} {
+ set vid [string trimleft $id .]
+
+ set var_canvas_xscale [concat canvas_xscale_$vid]
+ global $var_canvas_xscale
+ set var_canvas_yscale [concat canvas_yscale_$vid]
+ global $var_canvas_yscale
+ set var_canvas_graphme [concat canvas_graphme_$vid]
+ global $var_canvas_graphme
+# set var_canvas_stretch [concat canvas_stretch_$vid]
+# global $var_canvas_stretch
+
+ set $var_canvas_xscale $xscale
+ set $var_canvas_yscale $yscale
+ set $var_canvas_graphme $graphme
+# set $var_canvas_stretch $stretch
+
+ toplevel $id
+ wm title $id {canvas}
+ wm protocol $id WM_DELETE_WINDOW [concat canvas_cancel $id]
+
+ frame $id.xscale
+ pack $id.xscale -side top
+ label $id.xscale.label -text "X units per pixel"
+ entry $id.xscale.entry -textvariable $var_canvas_xscale -width 10
+ pack $id.xscale.label $id.xscale.entry -side left
+
+ frame $id.yscale
+ pack $id.yscale -side top
+ label $id.yscale.label -text "Y units per pixel"
+ entry $id.yscale.entry -textvariable $var_canvas_yscale -width 10
+ pack $id.yscale.label $id.yscale.entry -side left
+
+ checkbutton $id.graphme -text {graph on parent} \
+ -variable $var_canvas_graphme -anchor w
+ pack $id.graphme -side top
+
+# checkbutton $id.stretch -text {stretch on resize} \
+# -variable $var_canvas_stretch -anchor w
+# pack $id.stretch -side top
+
+
+ frame $id.buttonframe
+ pack $id.buttonframe -side bottom -fill x -pady 2m
+ button $id.buttonframe.cancel -text {Cancel}\
+ -command "canvas_cancel $id"
+ button $id.buttonframe.apply -text {Apply}\
+ -command "canvas_apply $id"
+ button $id.buttonframe.ok -text {OK}\
+ -command "canvas_ok $id"
+ pack $id.buttonframe.cancel -side left -expand 1
+ pack $id.buttonframe.apply -side left -expand 1
+ pack $id.buttonframe.ok -side left -expand 1
+
+ bind $id.xscale.entry <KeyPress-Return> [concat canvas_ok $id]
+ bind $id.yscale.entry <KeyPress-Return> [concat canvas_ok $id]
+ $id.xscale.entry select from 0
+ $id.xscale.entry select adjust end
+ focus $id.xscale.entry
+}
+
+############ pdtk_data_dialog -- run a data dialog #########
+proc dodata_send {name} {
+# puts stderr [$name.text get 0.0 end]
+
+ for {set i 1} {[$name.text compare [concat $i.0 + 3 chars] < end]} \
+ {incr i 1} {
+# puts stderr [concat it's [$name.text get $i.0 [expr $i + 1].0]]
+ set cmd [concat $name data [$name.text get $i.0 [expr $i + 1].0] \;]
+# puts stderr $cmd
+ pd $cmd
+ }
+ set cmd [concat $name end \;]
+# puts stderr $cmd
+ pd $cmd
+}
+
+proc dodata_cancel {name} {
+ set cmd [concat $name cancel \;]
+# puts stderr $cmd
+ pd $cmd
+}
+
+proc dodata_ok {name} {
+ dodata_send $name
+ dodata_cancel $name
+}
+
+proc pdtk_data_dialog {name stuff} {
+
+ toplevel $name
+ wm title $name {Atom}
+ wm protocol $name WM_DELETE_WINDOW [concat dodata_cancel $name]
+
+ frame $name.buttonframe
+ pack $name.buttonframe -side bottom -fill x -pady 2m
+ button $name.buttonframe.send -text {Send (Ctrl s)}\
+ -command [concat dodata_send $name]
+ button $name.buttonframe.ok -text {OK (Ctrl t)}\
+ -command [concat dodata_ok $name]
+ pack $name.buttonframe.send -side left -expand 1
+ pack $name.buttonframe.ok -side left -expand 1
+
+ text $name.text -relief raised -bd 2 -height 40 -width 60 \
+ -yscrollcommand "$name.scroll set" -font -*-courier-bold--normal--12-*
+ scrollbar $name.scroll -command "$name.text yview"
+ pack $name.scroll -side right -fill y
+ pack $name.text -side left -fill both -expand 1
+ $name.text insert end $stuff
+ focus $name.text
+ bind $name.text <Control-t> [concat dodata_ok $name]
+ bind $name.text <Control-s> [concat dodata_send $name]
+}
+
+############ check or uncheck the "edit" menu item ##############
+#####################iemlib#######################
+proc pdtk_canvas_editval {name value} {
+ if { $value } {
+ $name.m.edit.m entryconfigure "Edit mode" -indicatoron true
+ } else {
+ $name.m.edit.m entryconfigure "Edit mode" -indicatoron false
+ }
+}
+
+proc pdtk_canvas_protectval {name value} {
+ if { $value } {
+ $name.m.edit.m entryconfigure "Protect" -indicatoron true
+ } else {
+ $name.m.edit.m entryconfigure "Protect" -indicatoron false
+ }
+}
+#####################iemlib#######################
+
+############ pdtk_text_new -- create a new text object #2###########
+proc pdtk_text_new {canvasname myname x y text font color} {
+# if {$font < 13} {set fontname [format -*-courier-bold----%d-* $font]}
+# if {$font >= 13} {set fontname [format -*-courier-----%d-* $font]}
+ $canvasname create text $x $y \
+ -font [format -*-courier-bold--normal--%d-* $font] \
+ -tags $myname -text $text -fill $color -anchor nw
+# pd [concat $myname size [$canvasname bbox $myname] \;]
+}
+
+################ pdtk_text_set -- change the text ##################
+proc pdtk_text_set {canvasname myname text} {
+ $canvasname itemconfig $myname -text $text
+# pd [concat $myname size [$canvasname bbox $myname] \;]
+}
+
+############### event binding procedures for Pd window ################
+
+proc pdtk_pd_ctrlkey {name key shift} {
+# puts stderr [concat key $key shift $shift]
+# .dummy itemconfig goo -text [concat ---> control-key event $key];
+ if {$key == "n" || $key == "N"} {menu_new}
+ if {$key == "o" || $key == "O"} {menu_open}
+ if {$key == "m" || $key == "M"} {menu_send}
+ if {$key == "q" || $key == "Q"} {
+ if {$shift == 1} {menu_really_quit} else {menu_quit}
+ }
+ if {$key == "slash"} {menu_audio 1}
+ if {$key == "period"} {menu_audio 0}
+}
+
+######### startup function. ##############
+# Tell pd the current directory; this is used in case the command line
+# asked pd to open something. Also, get character width and height for
+# font sizes 8, 10, 12, 14, 16, and 24.
+
+proc pdtk_pd_startup {version} {
+ global pd_myversion
+ set pd_myversion $version
+
+ set width1 [font measure -*-courier-bold--normal--8-* x]
+ set height1 [lindex [font metrics -*-courier-bold--normal--8-*] 5]
+
+ set width2 [font measure -*-courier-bold--normal--10-* x]
+ set height2 [lindex [font metrics -*-courier-bold--normal--10-*] 5]
+
+ set width3 [font measure -*-courier-bold--normal--12-* x]
+ set height3 [lindex [font metrics -*-courier-bold--normal--12-*] 5]
+
+ set width4 [font measure -*-courier-bold--normal--14-* x]
+ set height4 [lindex [font metrics -*-courier-bold--normal--14-*] 5]
+
+ set width5 [font measure -*-courier-bold--normal--16-* x]
+ set height5 [lindex [font metrics -*-courier-bold--normal--16-*] 5]
+
+ set width6 [font measure -*-courier-bold--normal--24-* x]
+ set height6 [lindex [font metrics -*-courier-bold--normal--24-*] 5]
+
+ set width7 [font measure -*-courier-bold--normal--36-* x]
+ set height7 [lindex [font metrics -*-courier-bold--normal--36-*] 5]
+
+ pd [concat pd init [pdtk_enquote [pwd]] \
+ 8 $width1 $height1 \
+ 10 $width2 $height2 \
+ 12 $width3 $height3 \
+ 14 $width4 $height4 \
+ 16 $width5 $height5 \
+ 24 $width6 $height6 \
+ 36 $width7 $height7 \
+ \;];
+}
+
+##################### DSP ON/OFF, METERS, DIO ERROR ###################
+proc pdtk_pd_dsp {value} {
+ global ctrls_audio_on
+ if {$value == "ON"} {set ctrls_audio_on 1} else {set ctrls_audio_on 0}
+# puts stderr [concat its $ctrls_audio_on]
+}
+
+proc pdtk_pd_meters {indb outdb inclip outclip} {
+# puts stderr [concat meters $indb $outdb $inclip $outclip]
+ global ctrls_inlevel ctrls_outlevel
+ set ctrls_inlevel $indb
+ if {$inclip == 1} {
+ .controls.in.clip configure -background red
+ } else {
+ .controls.in.clip configure -background grey
+ }
+ set ctrls_outlevel $outdb
+ if {$outclip == 1} {
+ .controls.out.clip configure -background red
+ } else {
+ .controls.out.clip configure -background grey
+ }
+
+}
+
+proc pdtk_pd_dio {red} {
+# puts stderr [concat dio $red]
+ if {$red == 1} {
+ .controls.dio configure -background red -activebackground red
+ } else {
+ .controls.dio configure -background grey -activebackground lightgrey
+ }
+
+}
+
+############# text editing from the "edit" menu ###################
+set edit_number 1
+
+proc texteditor_send {name} {
+ set topname [string trimright $name .text]
+ for {set i 0} \
+ {[$name compare [concat 0.0 + [expr $i + 1] chars] < end]} \
+ {incr i 1} {
+ set cha [$name get [concat 0.0 + $i chars]]
+ scan $cha %c keynum
+ pd [concat pd key 1 $keynum \;]
+ }
+}
+
+proc texteditor_ok {name} {
+ set topname [string trimright $name .text]
+ texteditor_send $name
+ destroy $topname
+}
+
+
+proc pdtk_pd_texteditor {stuff} {
+ global edit_number
+ set name [format ".text%d" $edit_number]
+ set edit_number [expr $edit_number + 1]
+
+ toplevel $name
+ wm title $name {TEXT}
+
+ frame $name.buttons
+ pack $name.buttons -side bottom -fill x -pady 2m
+ button $name.buttons.send -text {Send (Ctrl s)}\
+ -command "texteditor_send $name.text"
+ button $name.buttons.ok -text {OK (Ctrl t)}\
+ -command "texteditor_ok $name.text"
+ pack $name.buttons.send -side left -expand 1
+ pack $name.buttons.ok -side left -expand 1
+
+ text $name.text -relief raised -bd 2 -height 12 -width 60 \
+ -yscrollcommand "$name.scroll set" -font -*-courier-bold--normal--12-*
+ scrollbar $name.scroll -command "$name.text yview"
+ pack $name.scroll -side right -fill y
+ pack $name.text -side left -fill both -expand 1
+ $name.text insert end $stuff
+ focus $name.text
+ bind $name.text <Control-t> {texteditor_ok %W}
+ bind $name.text <Control-s> {texteditor_send %W}
+}
+
+############# open and save dialogs for objects in Pd ##########
+
+proc pdtk_openpanel {target} {
+ global pd_opendir
+ global pd_nt
+ if {$pd_nt == 2} {
+ cd $pd_opendir
+ set filename [tk_getOpenFile ]
+ } else {
+ set filename [tk_getOpenFile \
+ -initialdir $pd_opendir]
+ }
+ if {$filename != ""} {
+ set directory [string range $filename 0 \
+ [expr [string last / $filename ] - 1]]
+ set pd_opendir $directory
+
+ pd [concat $target symbol [pdtk_enquote $filename] \;]
+ }
+}
+
+proc pdtk_savepanel {target} {
+ set filename [tk_getSaveFile]
+ if {$filename != ""} {
+ pd [concat $target symbol [pdtk_enquote $filename] \;]
+ }
+}
+
+########################### comport hack ########################
+
+set com1 0
+set com2 0
+set com3 0
+set com4 0
+
+proc com1_open {} {
+ global com1
+ set com1 [open com1 w]
+ .dummy itemconfig goo -text $com1
+ fconfigure $com1 -buffering none
+ fconfigure $com1 -mode 19200,e,8,2
+}
+
+proc com1_send {str} {
+ global com1
+ puts -nonewline $com1 $str
+}
+
+
+############# start a polling process to watch the socket ##############
+# this is needed for nt, and presumably for Mac as well.
+# in UNIX this is handled by a tcl callback (set up in t_tkcmd.c)
+
+if {$pd_nt == 1} {
+ proc polleofloop {} {
+ pd_pollsocket
+ after 20 polleofloop
+ }
+
+ polleofloop
+}
+
diff --git a/pd/src/u_pdreceive.c b/pd/src/u_pdreceive.c
new file mode 100644
index 00000000..8d3f83e9
--- /dev/null
+++ b/pd/src/u_pdreceive.c
@@ -0,0 +1,305 @@
+/* Copyright (c) 2000 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in the Pd distribution. */
+
+/* the "pdreceive" command. This is a standalone program that receives messages
+from Pd via the netsend/netreceive ("FUDI") protocol, and copies them to
+standard output. */
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#ifdef UNIX
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#define SOCKET_ERROR -1
+#else
+#include <winsock.h>
+#endif
+
+typedef struct _fdpoll
+{
+ int fdp_fd;
+ char *fdp_inbuf;
+ int fdp_inhead;
+ int fdp_intail;
+ int fdp_udp;
+} t_fdpoll;
+
+static int nfdpoll;
+static t_fdpoll *fdpoll;
+static int maxfd;
+static int sockfd;
+static int protocol;
+
+static void sockerror(char *s);
+static void closesocket(int fd);
+static void dopoll(void);
+#define BUFSIZE 4096
+
+int main(int argc, char **argv)
+{
+ int portno;
+ struct sockaddr_in server;
+ int nretry = 10;
+ if (argc < 2 || sscanf(argv[1], "%d", &portno) < 1 || portno <= 0)
+ goto usage;
+ if (argc >= 3)
+ {
+ if (!strcmp(argv[2], "tcp"))
+ protocol = SOCK_STREAM;
+ else if (!strcmp(argv[2], "udp"))
+ protocol = SOCK_DGRAM;
+ else goto usage;
+ }
+ else protocol = SOCK_STREAM;
+ sockfd = socket(AF_INET, protocol, 0);
+ if (sockfd < 0)
+ {
+ sockerror("socket()");
+ exit(1);
+ }
+ maxfd = sockfd + 1;
+ 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 client port number */
+ server.sin_port = htons((unsigned short)portno);
+
+ /* name the socket */
+ if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
+ {
+ sockerror("bind");
+ closesocket(sockfd);
+ return (0);
+ }
+ if (protocol == SOCK_STREAM)
+ {
+ if (listen(sockfd, 5) < 0)
+ {
+ sockerror("listen");
+ closesocket(sockfd);
+ exit(1);
+ }
+ }
+ /* now loop forever selecting on sockets */
+ while (1)
+ dopoll();
+
+usage:
+ fprintf(stderr, "usage: pdreceive <portnumber> [udp|tcp]\n");
+ fprintf(stderr, "(default is tcp)\n");
+ exit(1);
+}
+
+static void addport(int fd)
+{
+ int nfd = nfdpoll;
+ t_fdpoll *fp;
+ fdpoll = (t_fdpoll *)realloc(fdpoll,
+ (nfdpoll+1) * sizeof(t_fdpoll));
+ fp = fdpoll + nfdpoll;
+ fp->fdp_fd = fd;
+ nfdpoll++;
+ if (fd >= maxfd) maxfd = fd + 1;
+ fp->fdp_inhead = fp->fdp_intail = 0;
+ if (!(fp->fdp_inbuf = malloc(BUFSIZE)))
+ {
+ fprintf(stderr, "out of memory");
+ exit(1);
+ }
+ printf("number_connected %d;\n", nfdpoll);
+}
+
+static void rmport(t_fdpoll *x)
+{
+ int nfd = nfdpoll;
+ int i, size = nfdpoll * sizeof(t_fdpoll);
+ t_fdpoll *fp;
+ for (i = nfdpoll, fp = fdpoll; i--; fp++)
+ {
+ if (fp == x)
+ {
+ closesocket(fp->fdp_fd);
+ free(fp->fdp_inbuf);
+ while (i--)
+ {
+ fp[0] = fp[1];
+ fp++;
+ }
+ fdpoll = (t_fdpoll *)realloc(fdpoll,
+ (nfdpoll-1) * sizeof(t_fdpoll));
+ nfdpoll--;
+ printf("number_connected %d;\n", nfdpoll);
+ return;
+ }
+ }
+ fprintf(stderr, "warning: item removed from poll list but not found");
+}
+
+static void doconnect(void)
+{
+ int fd = accept(sockfd, 0, 0);
+ if (fd < 0)
+ perror("accept");
+ else addport(fd);
+}
+
+static void udpread(void)
+{
+ char buf[BUFSIZE];
+ int ret = recv(sockfd, buf, BUFSIZE, 0);
+ if (ret < 0)
+ {
+ sockerror("recv (udp)");
+ close(sockfd);
+ exit(1);
+ }
+ else if (ret > 0)
+ {
+ if (write(1, buf, ret) < ret)
+ {
+ perror("write");
+ exit(1);
+ }
+ }
+}
+
+static int tcpmakeoutput(t_fdpoll *x)
+{
+ char messbuf[BUFSIZE+1], *bp = messbuf;
+ int indx;
+ int inhead = x->fdp_inhead;
+ int intail = x->fdp_intail;
+ char *inbuf = x->fdp_inbuf;
+ if (intail == inhead)
+ return (0);
+ for (indx = intail; indx != inhead; indx = (indx+1)&(BUFSIZE-1))
+ {
+ /* search for a semicolon. */
+ char c = *bp++ = inbuf[indx];
+ if (c == ';')
+ {
+ intail = (indx+1)&(BUFSIZE-1);
+ if (inbuf[intail] == '\n')
+ intail = (intail+1)&(BUFSIZE-1);
+ *bp++ = '\n';
+ write(1, messbuf, bp - messbuf);
+ x->fdp_inhead = inhead;
+ x->fdp_intail = intail;
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static void tcpread(t_fdpoll *x)
+{
+ char *semi;
+ int readto =
+ (x->fdp_inhead >= x->fdp_intail ? BUFSIZE : x->fdp_intail-1);
+ int ret;
+
+ /* the input buffer might be full. If so, drop the whole thing */
+ if (readto == x->fdp_inhead)
+ {
+ fprintf(stderr, "pd: dropped message from gui\n");
+ x->fdp_inhead = x->fdp_intail = 0;
+ readto = BUFSIZE;
+ }
+ else
+ {
+ ret = recv(x->fdp_fd, x->fdp_inbuf + x->fdp_inhead,
+ readto - x->fdp_inhead, 0);
+ if (ret < 0)
+ {
+ sockerror("recv (tcp)");
+ rmport(x);
+ }
+ else if (ret == 0)
+ rmport(x);
+ else
+ {
+ x->fdp_inhead += ret;
+ if (x->fdp_inhead >= BUFSIZE)
+ x->fdp_inhead = 0;
+ while (tcpmakeoutput(x))
+ ;
+ }
+ }
+}
+
+static void dopoll(void)
+{
+ int i;
+ t_fdpoll *fp;
+ fd_set readset, writeset, exceptset;
+ FD_ZERO(&writeset);
+ FD_ZERO(&readset);
+ FD_ZERO(&exceptset);
+
+ FD_SET(sockfd, &readset);
+ if (protocol == SOCK_STREAM)
+ {
+ for (fp = fdpoll, i = nfdpoll; i--; fp++)
+ FD_SET(fp->fdp_fd, &readset);
+ }
+ if (select(maxfd+1, &readset, &writeset, &exceptset, 0) < 0)
+ {
+ perror("select");
+ exit(1);
+ }
+ if (protocol == SOCK_STREAM)
+ {
+ for (i = 0; i < nfdpoll; i++)
+ if (FD_ISSET(fdpoll[i].fdp_fd, &readset))
+ tcpread(&fdpoll[i]);
+ if (FD_ISSET(sockfd, &readset))
+ doconnect();
+ }
+ else
+ {
+ if (FD_ISSET(sockfd, &readset))
+ udpread();
+ }
+}
+
+
+static void sockerror(char *s)
+{
+#ifdef NT
+ int err = WSAGetLastError();
+ if (err == 10054) return;
+ else if (err == 10044)
+ {
+ fprintf(stderr,
+ "Warning: you might not have TCP/IP \"networking\" turned on\n");
+ }
+#endif
+#ifdef UNIX
+ int err = errno;
+#endif
+ fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
+}
+
+static void closesocket(int fd)
+{
+#ifdef UNIX
+ close(fd);
+#endif
+#ifdef NT
+ closesocket(fd);
+#endif
+}
diff --git a/pd/src/u_pdsend.c b/pd/src/u_pdsend.c
new file mode 100644
index 00000000..87e7150d
--- /dev/null
+++ b/pd/src/u_pdsend.c
@@ -0,0 +1,150 @@
+/* Copyright (c) 2000 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in the Pd distribution. */
+
+/* the "pdsend" command. This is a standalone program that forwards messages
+from its standard input to Pd via the netsend/netreceive ("FUDI") protocol. */
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#ifdef UNIX
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#define SOCKET_ERROR -1
+#else
+#include <winsock.h>
+#endif
+
+void sockerror(char *s);
+void closesocket(int fd);
+#define BUFSIZE 4096
+
+int main(int argc, char **argv)
+{
+ int sockfd, portno, protocol;
+ struct sockaddr_in server;
+ struct hostent *hp;
+ char *hostname;
+ int nretry = 10;
+ if (argc < 2 || sscanf(argv[1], "%d", &portno) < 1 || portno <= 0)
+ goto usage;
+ if (argc >= 3)
+ hostname = argv[2];
+ else hostname = "127.0.0.1";
+ if (argc >= 4)
+ {
+ if (!strcmp(argv[3], "tcp"))
+ protocol = SOCK_STREAM;
+ else if (!strcmp(argv[3], "udp"))
+ protocol = SOCK_DGRAM;
+ else goto usage;
+ }
+ else protocol = SOCK_STREAM;
+
+ sockfd = socket(AF_INET, protocol, 0);
+ if (sockfd < 0)
+ {
+ sockerror("socket()");
+ exit(1);
+ }
+ /* connect socket using hostname provided in command line */
+ server.sin_family = AF_INET;
+ hp = gethostbyname(hostname);
+ if (hp == 0)
+ {
+ fprintf(stderr, "%s: unknown host\n", hostname);
+ closesocket(sockfd);
+ exit(1);
+ }
+ memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
+
+ /* assign client port number */
+ server.sin_port = htons((unsigned short)portno);
+
+#if 0 /* try this again for 4.0; this crashed my RH 6.2 machine!) */
+
+ /* try to connect. */
+ for (nretry = 0; nretry < (protocol == SOCK_STREAM ? 10 : 1); nretry++)
+
+ {
+ if (nretry > 0)
+ {
+ sleep (nretry < 5 ? 1 : 5);
+ fprintf(stderr, "retrying...");
+ }
+ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) >= 0)
+ goto connected;
+ sockerror("connect");
+ }
+ closesocket(sockfd);
+ exit(1);
+connected: ;
+#else
+ /* try to connect. */
+ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
+ {
+ sockerror("connect");
+ closesocket(sockfd);
+ exit(1);
+ }
+#endif
+ /* now loop reading stdin and sending it to socket */
+ while (1)
+ {
+ char buf[BUFSIZE], *bp, nsent, nsend;
+ if (!fgets(buf, BUFSIZE, stdin))
+ break;
+ nsend = strlen(buf);
+ for (bp = buf, nsent = 0; nsent < nsend;)
+ {
+ int res = send(sockfd, buf, nsend-nsent, 0);
+ if (res < 0)
+ {
+ sockerror("send");
+ goto done;
+ }
+ nsent += res;
+ bp += res;
+ }
+ }
+done:
+ if (ferror(stdin))
+ perror("stdin");
+ exit (0);
+usage:
+ fprintf(stderr, "usage: pdsend <portnumber> [host] [udp|tcp]\n");
+ fprintf(stderr, "(default is localhost and tcp)\n");
+ exit(1);
+}
+
+void sockerror(char *s)
+{
+#ifdef NT
+ int err = WSAGetLastError();
+ if (err == 10054) return;
+ else if (err == 10044)
+ {
+ fprintf(stderr,
+ "Warning: you might not have TCP/IP \"networking\" turned on\n");
+ }
+#endif
+#ifdef UNIX
+ int err = errno;
+#endif
+ fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
+}
+
+void closesocket(int fd)
+{
+#ifdef UNIX
+ close(fd);
+#endif
+#ifdef NT
+ closesocket(fd);
+#endif
+}
diff --git a/pd/src/x_acoustics.c b/pd/src/x_acoustics.c
new file mode 100644
index 00000000..ee7250df
--- /dev/null
+++ b/pd/src/x_acoustics.c
@@ -0,0 +1,193 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* utility functions for signals
+*/
+
+#include "m_pd.h"
+#include <math.h>
+#define LOGTEN 2.302585092994
+
+float mtof(float f)
+{
+ if (f <= -1500) return(0);
+ else if (f > 1499) return(mtof(1499));
+ else return (8.17579891564 * exp(.0577622650 * f));
+}
+
+float ftom(float f)
+{
+ return (f > 0 ? 17.3123405046 * log(.12231220585 * f) : -1500);
+}
+
+float powtodb(float f)
+{
+ if (f <= 0) return (0);
+ else
+ {
+ float val = 100 + 10./LOGTEN * log(f);
+ return (val < 0 ? 0 : val);
+ }
+}
+
+float rmstodb(float f)
+{
+ if (f <= 0) return (0);
+ else
+ {
+ float val = 100 + 20./LOGTEN * log(f);
+ return (val < 0 ? 0 : val);
+ }
+}
+
+float dbtopow(float f)
+{
+ if (f <= 0)
+ return(0);
+ else
+ {
+ if (f > 870)
+ f = 870;
+ return (exp((LOGTEN * 0.1) * (f-100.)));
+ }
+}
+
+float dbtorms(float f)
+{
+ if (f <= 0)
+ return(0);
+ else
+ {
+ if (f > 485)
+ f = 485;
+ }
+ return (exp((LOGTEN * 0.05) * (f-100.)));
+}
+
+/* ------------- corresponding objects ----------------------- */
+
+static t_class *mtof_class;
+
+static void *mtof_new(void)
+{
+ t_object *x = (t_object *)pd_new(mtof_class);
+ outlet_new(x, &s_float);
+ return (x);
+}
+
+static void mtof_float(t_object *x, t_float f)
+{
+ outlet_float(x->ob_outlet, mtof(f));
+}
+
+
+static t_class *ftom_class;
+
+static void *ftom_new(void)
+{
+ t_object *x = (t_object *)pd_new(ftom_class);
+ outlet_new(x, &s_float);
+ return (x);
+}
+
+static void ftom_float(t_object *x, t_float f)
+{
+ outlet_float(x->ob_outlet, ftom(f));
+}
+
+
+static t_class *rmstodb_class;
+
+static void *rmstodb_new(void)
+{
+ t_object *x = (t_object *)pd_new(rmstodb_class);
+ outlet_new(x, &s_float);
+ return (x);
+}
+
+static void rmstodb_float(t_object *x, t_float f)
+{
+ outlet_float(x->ob_outlet, rmstodb(f));
+}
+
+
+static t_class *powtodb_class;
+
+static void *powtodb_new(void)
+{
+ t_object *x = (t_object *)pd_new(powtodb_class);
+ outlet_new(x, &s_float);
+ return (x);
+}
+
+static void powtodb_float(t_object *x, t_float f)
+{
+ outlet_float(x->ob_outlet, powtodb(f));
+}
+
+
+static t_class *dbtopow_class;
+
+static void *dbtopow_new(void)
+{
+ t_object *x = (t_object *)pd_new(dbtopow_class);
+ outlet_new(x, &s_float);
+ return (x);
+}
+
+static void dbtopow_float(t_object *x, t_float f)
+{
+ outlet_float(x->ob_outlet, dbtopow(f));
+}
+
+
+static t_class *dbtorms_class;
+
+static void *dbtorms_new(void)
+{
+ t_object *x = (t_object *)pd_new(dbtorms_class);
+ outlet_new(x, &s_float);
+ return (x);
+}
+
+static void dbtorms_float(t_object *x, t_float f)
+{
+ outlet_float(x->ob_outlet, dbtorms(f));
+}
+
+
+void x_acoustics_setup(void)
+{
+ t_symbol *s = gensym("acoustics.pd");
+ mtof_class = class_new(gensym("mtof"), mtof_new, 0,
+ sizeof(t_object), 0, 0);
+ class_addfloat(mtof_class, (t_method)mtof_float);
+ class_sethelpsymbol(mtof_class, s);
+
+ ftom_class = class_new(gensym("ftom"), ftom_new, 0,
+ sizeof(t_object), 0, 0);
+ class_addfloat(ftom_class, (t_method)ftom_float);
+ class_sethelpsymbol(ftom_class, s);
+
+ powtodb_class = class_new(gensym("powtodb"), powtodb_new, 0,
+ sizeof(t_object), 0, 0);
+ class_addfloat(powtodb_class, (t_method)powtodb_float);
+ class_sethelpsymbol(powtodb_class, s);
+
+ rmstodb_class = class_new(gensym("rmstodb"), rmstodb_new, 0,
+ sizeof(t_object), 0, 0);
+ class_addfloat(rmstodb_class, (t_method)rmstodb_float);
+ class_sethelpsymbol(rmstodb_class, s);
+
+ dbtopow_class = class_new(gensym("dbtopow"), dbtopow_new, 0,
+ sizeof(t_object), 0, 0);
+ class_addfloat(dbtopow_class, (t_method)dbtopow_float);
+ class_sethelpsymbol(dbtopow_class, s);
+
+ dbtorms_class = class_new(gensym("dbtorms"), dbtorms_new, 0,
+ sizeof(t_object), 0, 0);
+ class_addfloat(dbtorms_class, (t_method)dbtorms_float);
+ class_sethelpsymbol(dbtorms_class, s);
+}
+
diff --git a/pd/src/x_arithmetic.c b/pd/src/x_arithmetic.c
new file mode 100644
index 00000000..f975f542
--- /dev/null
+++ b/pd/src/x_arithmetic.c
@@ -0,0 +1,898 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* arithmetic: binops ala C language. The 4 functions and relationals are
+done on floats; the logical and bitwise binops convert their
+inputs to int and their outputs back to float. */
+
+#include "m_pd.h"
+#include <math.h>
+
+
+/* NT and OSX don't appear to have single-precision ANSI math */
+#if defined(NT) || defined(MACOSX)
+#define sinf sin
+#define cosf cos
+#define atanf atan
+#define atan2f atan2
+#define sqrtf sqrt
+#define logf log
+#define expf exp
+#define fabsf fabs
+#define powf pow
+#endif
+
+typedef struct _binop
+{
+ t_object x_obj;
+ t_float x_f1;
+ t_float x_f2;
+} t_binop;
+
+/* ------------------ binop1: +, -, *, / ----------------------------- */
+
+static void *binop1_new(t_class *floatclass, t_floatarg f)
+{
+ t_binop *x = (t_binop *)pd_new(floatclass);
+ outlet_new(&x->x_obj, &s_float);
+ floatinlet_new(&x->x_obj, &x->x_f2);
+ x->x_f1 = 0;
+ x->x_f2 = f;
+ return (x);
+}
+
+/* --------------------- addition ------------------------------- */
+
+static t_class *binop1_plus_class;
+
+static void *binop1_plus_new(t_floatarg f)
+{
+ return (binop1_new(binop1_plus_class, f));
+}
+
+static void binop1_plus_bang(t_binop *x)
+{
+ outlet_float(x->x_obj.ob_outlet, x->x_f1 + x->x_f2);
+}
+
+static void binop1_plus_float(t_binop *x, t_float f)
+{
+ outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) + x->x_f2);
+}
+
+/* --------------------- subtraction ------------------------------- */
+
+static t_class *binop1_minus_class;
+
+static void *binop1_minus_new(t_floatarg f)
+{
+ return (binop1_new(binop1_minus_class, f));
+}
+
+static void binop1_minus_bang(t_binop *x)
+{
+ outlet_float(x->x_obj.ob_outlet, x->x_f1 - x->x_f2);
+}
+
+static void binop1_minus_float(t_binop *x, t_float f)
+{
+ outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) - x->x_f2);
+}
+
+/* --------------------- multiplication ------------------------------- */
+
+static t_class *binop1_times_class;
+
+static void *binop1_times_new(t_floatarg f)
+{
+ return (binop1_new(binop1_times_class, f));
+}
+
+static void binop1_times_bang(t_binop *x)
+{
+ outlet_float(x->x_obj.ob_outlet, x->x_f1 * x->x_f2);
+}
+
+static void binop1_times_float(t_binop *x, t_float f)
+{
+ outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) * x->x_f2);
+}
+
+/* --------------------- division ------------------------------- */
+
+static t_class *binop1_div_class;
+
+static void *binop1_div_new(t_floatarg f)
+{
+ return (binop1_new(binop1_div_class, f));
+}
+
+static void binop1_div_bang(t_binop *x)
+{
+ outlet_float(x->x_obj.ob_outlet,
+ (x->x_f2 != 0 ? x->x_f1 / x->x_f2 : 0));
+}
+
+static void binop1_div_float(t_binop *x, t_float f)
+{
+ x->x_f1 = f;
+ outlet_float(x->x_obj.ob_outlet,
+ (x->x_f2 != 0 ? x->x_f1 / x->x_f2 : 0));
+}
+
+/* ------------------------ pow -------------------------------- */
+
+static t_class *binop1_pow_class;
+
+static void *binop1_pow_new(t_floatarg f)
+{
+ return (binop1_new(binop1_pow_class, f));
+}
+
+static void binop1_pow_bang(t_binop *x)
+{
+ outlet_float(x->x_obj.ob_outlet,
+ (x->x_f1 > 0 ? powf(x->x_f1, x->x_f2) : 0));
+}
+
+static void binop1_pow_float(t_binop *x, t_float f)
+{
+ x->x_f1 = f;
+ outlet_float(x->x_obj.ob_outlet,
+ (x->x_f1 > 0 ? powf(x->x_f1, x->x_f2) : 0));
+}
+
+/* ------------------------ max -------------------------------- */
+
+static t_class *binop1_max_class;
+
+static void *binop1_max_new(t_floatarg f)
+{
+ return (binop1_new(binop1_max_class, f));
+}
+
+static void binop1_max_bang(t_binop *x)
+{
+ outlet_float(x->x_obj.ob_outlet,
+ (x->x_f1 > x->x_f2 ? x->x_f1 : x->x_f2));
+}
+
+static void binop1_max_float(t_binop *x, t_float f)
+{
+ x->x_f1 = f;
+ outlet_float(x->x_obj.ob_outlet,
+ (x->x_f1 > x->x_f2 ? x->x_f1 : x->x_f2));
+}
+
+/* ------------------------ min -------------------------------- */
+
+static t_class *binop1_min_class;
+
+static void *binop1_min_new(t_floatarg f)
+{
+ return (binop1_new(binop1_min_class, f));
+}
+
+static void binop1_min_bang(t_binop *x)
+{
+ outlet_float(x->x_obj.ob_outlet,
+ (x->x_f1 < x->x_f2 ? x->x_f1 : x->x_f2));
+}
+
+static void binop1_min_float(t_binop *x, t_float f)
+{
+ x->x_f1 = f;
+ outlet_float(x->x_obj.ob_outlet,
+ (x->x_f1 < x->x_f2 ? x->x_f1 : x->x_f2));
+}
+
+/* ------------------ binop2: ==, !=, >, <, >=, <=. -------------------- */
+
+static void *binop2_new(t_class *floatclass, t_floatarg f)
+{
+ t_binop *x = (t_binop *)pd_new(floatclass);
+ outlet_new(&x->x_obj, &s_float);
+ floatinlet_new(&x->x_obj, &x->x_f2);
+ x->x_f1 = 0;
+ x->x_f2 = f;
+ return (x);
+}
+
+/* --------------------- == ------------------------------- */
+
+static t_class *binop2_ee_class;
+
+static void *binop2_ee_new(t_floatarg f)
+{
+ return (binop2_new(binop2_ee_class, f));
+}
+
+static void binop2_ee_bang(t_binop *x)
+{
+ outlet_float(x->x_obj.ob_outlet, x->x_f1 == x->x_f2);
+}
+
+static void binop2_ee_float(t_binop *x, t_float f)
+{
+ outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) == x->x_f2);
+}
+
+/* --------------------- != ------------------------------- */
+
+static t_class *binop2_ne_class;
+
+static void *binop2_ne_new(t_floatarg f)
+{
+ return (binop2_new(binop2_ne_class, f));
+}
+
+static void binop2_ne_bang(t_binop *x)
+{
+ outlet_float(x->x_obj.ob_outlet, x->x_f1 != x->x_f2);
+}
+
+static void binop2_ne_float(t_binop *x, t_float f)
+{
+ outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) != x->x_f2);
+}
+
+/* --------------------- > ------------------------------- */
+
+static t_class *binop2_gt_class;
+
+static void *binop2_gt_new(t_floatarg f)
+{
+ return (binop2_new(binop2_gt_class, f));
+}
+
+static void binop2_gt_bang(t_binop *x)
+{
+ outlet_float(x->x_obj.ob_outlet, x->x_f1 > x->x_f2);
+}
+
+static void binop2_gt_float(t_binop *x, t_float f)
+{
+ outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) > x->x_f2);
+}
+
+/* --------------------- < ------------------------------- */
+
+static t_class *binop2_lt_class;
+
+static void *binop2_lt_new(t_floatarg f)
+{
+ return (binop2_new(binop2_lt_class, f));
+}
+
+static void binop2_lt_bang(t_binop *x)
+{
+ outlet_float(x->x_obj.ob_outlet, x->x_f1 < x->x_f2);
+}
+
+static void binop2_lt_float(t_binop *x, t_float f)
+{
+ outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) < x->x_f2);
+}
+
+/* --------------------- >= ------------------------------- */
+
+static t_class *binop2_ge_class;
+
+static void *binop2_ge_new(t_floatarg f)
+{
+ return (binop2_new(binop2_ge_class, f));
+}
+
+static void binop2_ge_bang(t_binop *x)
+{
+ outlet_float(x->x_obj.ob_outlet, x->x_f1 >= x->x_f2);
+}
+
+static void binop2_ge_float(t_binop *x, t_float f)
+{
+ outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) >= x->x_f2);
+}
+
+/* --------------------- <= ------------------------------- */
+
+static t_class *binop2_le_class;
+
+static void *binop2_le_new(t_floatarg f)
+{
+ return (binop2_new(binop2_le_class, f));
+}
+
+static void binop2_le_bang(t_binop *x)
+{
+ outlet_float(x->x_obj.ob_outlet, x->x_f1 <= x->x_f2);
+}
+
+static void binop2_le_float(t_binop *x, t_float f)
+{
+ outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) <= x->x_f2);
+}
+
+/* ------------- binop3: &, |, &&, ||, <<, >>, %, mod, div ------------------ */
+
+static void *binop3_new(t_class *fixclass, t_floatarg f)
+{
+ t_binop *x = (t_binop *)pd_new(fixclass);
+ outlet_new(&x->x_obj, &s_float);
+ floatinlet_new(&x->x_obj, &x->x_f2);
+ x->x_f1 = 0;
+ x->x_f2 = f;
+ return (x);
+}
+
+/* --------------------------- & ---------------------------- */
+
+static t_class *binop3_ba_class;
+
+static void *binop3_ba_new(t_floatarg f)
+{
+ return (binop3_new(binop3_ba_class, f));
+}
+
+static void binop2_ba_bang(t_binop *x)
+{
+ outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) & (int)(x->x_f2));
+}
+
+static void binop2_ba_float(t_binop *x, t_float f)
+{
+ outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) & (int)(x->x_f2));
+}
+
+/* --------------------------- && ---------------------------- */
+
+static t_class *binop3_la_class;
+
+static void *binop3_la_new(t_floatarg f)
+{
+ return (binop3_new(binop3_la_class, f));
+}
+
+static void binop2_la_bang(t_binop *x)
+{
+ outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) && (int)(x->x_f2));
+}
+
+static void binop2_la_float(t_binop *x, t_float f)
+{
+ outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) && (int)(x->x_f2));
+}
+
+/* --------------------------- | ---------------------------- */
+
+static t_class *binop3_bo_class;
+
+static void *binop3_bo_new(t_floatarg f)
+{
+ return (binop3_new(binop3_bo_class, f));
+}
+
+static void binop2_bo_bang(t_binop *x)
+{
+ outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) | (int)(x->x_f2));
+}
+
+static void binop2_bo_float(t_binop *x, t_float f)
+{
+ outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) | (int)(x->x_f2));
+}
+
+/* --------------------------- || ---------------------------- */
+
+static t_class *binop3_lo_class;
+
+static void *binop3_lo_new(t_floatarg f)
+{
+ return (binop3_new(binop3_lo_class, f));
+}
+
+static void binop2_lo_bang(t_binop *x)
+{
+ outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) || (int)(x->x_f2));
+}
+
+static void binop2_lo_float(t_binop *x, t_float f)
+{
+ outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) || (int)(x->x_f2));
+}
+
+/* --------------------------- << ---------------------------- */
+
+static t_class *binop3_ls_class;
+
+static void *binop3_ls_new(t_floatarg f)
+{
+ return (binop3_new(binop3_ls_class, f));
+}
+
+static void binop2_ls_bang(t_binop *x)
+{
+ outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) << (int)(x->x_f2));
+}
+
+static void binop2_ls_float(t_binop *x, t_float f)
+{
+ outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) << (int)(x->x_f2));
+}
+
+/* --------------------------- >> ---------------------------- */
+
+static t_class *binop3_rs_class;
+
+static void *binop3_rs_new(t_floatarg f)
+{
+ return (binop3_new(binop3_rs_class, f));
+}
+
+static void binop2_rs_bang(t_binop *x)
+{
+ outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) >> (int)(x->x_f2));
+}
+
+static void binop2_rs_float(t_binop *x, t_float f)
+{
+ outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) >> (int)(x->x_f2));
+}
+
+/* --------------------------- % ---------------------------- */
+
+static t_class *binop3_pc_class;
+
+static void *binop3_pc_new(t_floatarg f)
+{
+ return (binop3_new(binop3_pc_class, f));
+}
+
+static void binop2_pc_bang(t_binop *x)
+{
+ int n2 = x->x_f2;
+ outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1)) % (n2 ? n2 : 1));
+}
+
+static void binop2_pc_float(t_binop *x, t_float f)
+{
+ int n2 = x->x_f2;
+ outlet_float(x->x_obj.ob_outlet, ((int)(x->x_f1 = f)) % (n2 ? n2 : 1));
+}
+
+/* --------------------------- mod ---------------------------- */
+
+static t_class *binop3_mod_class;
+
+static void *binop3_mod_new(t_floatarg f)
+{
+ return (binop3_new(binop3_mod_class, f));
+}
+
+static void binop3_mod_bang(t_binop *x)
+{
+ int n2 = x->x_f2, result;
+ if (n2 < 0) n2 = -n2;
+ else if (!n2) n2 = 1;
+ result = ((int)(x->x_f1)) % n2;
+ if (result < 0) result += n2;
+ outlet_float(x->x_obj.ob_outlet, (t_float)result);
+}
+
+static void binop3_mod_float(t_binop *x, t_float f)
+{
+ x->x_f1 = f;
+ binop3_mod_bang(x);
+}
+
+/* --------------------------- div ---------------------------- */
+
+static t_class *binop3_div_class;
+
+static void *binop3_div_new(t_floatarg f)
+{
+ return (binop3_new(binop3_div_class, f));
+}
+
+static void binop3_div_bang(t_binop *x)
+{
+ int n1 = x->x_f1, n2 = x->x_f2, result;
+ if (n2 < 0) n2 = -n2;
+ else if (!n2) n2 = 1;
+ if (n1 < 0) n1 -= (n2-1);
+ result = n1 / n2;
+ outlet_float(x->x_obj.ob_outlet, (t_float)result);
+}
+
+static void binop3_div_float(t_binop *x, t_float f)
+{
+ x->x_f1 = f;
+ binop3_div_bang(x);
+}
+
+/* -------------------- mathematical functions ------------------ */
+
+static t_class *sin_class; /* ----------- sin --------------- */
+
+static void *sin_new(void)
+{
+ t_object *x = (t_object *)pd_new(sin_class);
+ outlet_new(x, &s_float);
+ return (x);
+}
+
+static void sin_float(t_object *x, t_float f)
+{
+ outlet_float(x->ob_outlet, sinf(f));
+}
+
+static t_class *cos_class; /* ----------- cos --------------- */
+
+static void *cos_new(void)
+{
+ t_object *x = (t_object *)pd_new(cos_class);
+ outlet_new(x, &s_float);
+ return (x);
+}
+
+static void cos_float(t_object *x, t_float f)
+{
+ outlet_float(x->ob_outlet, cosf(f));
+}
+
+static t_class *tan_class; /* ----------- tan --------------- */
+
+static void *tan_new(void)
+{
+ t_object *x = (t_object *)pd_new(tan_class);
+ outlet_new(x, &s_float);
+ return (x);
+}
+
+static void tan_float(t_object *x, t_float f)
+{
+ float c = cosf(f);
+ float t = (c == 0 ? 0 : sinf(f)/c);
+ outlet_float(x->ob_outlet, t);
+}
+
+static t_class *atan_class; /* ----------- atan --------------- */
+
+static void *atan_new(void)
+{
+ t_object *x = (t_object *)pd_new(atan_class);
+ outlet_new(x, &s_float);
+ return (x);
+}
+
+static void atan_float(t_object *x, t_float f)
+{
+ outlet_float(x->ob_outlet, atanf(f));
+}
+
+static t_class *atan2_class; /* ----------- atan2 --------------- */
+
+typedef struct _atan2
+{
+ t_object x_ob;
+ float x_y;
+} t_atan2;
+
+static void *atan2_new(void)
+{
+ t_atan2 *x = (t_atan2 *)pd_new(atan2_class);
+ floatinlet_new(&x->x_ob, &x->x_y);
+ outlet_new(&x->x_ob, &s_float);
+ return (x);
+}
+
+static void atan2_float(t_atan2 *x, t_float f)
+{
+ float r = (f == 0 && x->x_y == 0 ? 0 : atan2f(x->x_y, f));
+ outlet_float(x->x_ob.ob_outlet, r);
+}
+
+static t_class *sqrt_class; /* ----------- sqrt --------------- */
+
+static void *sqrt_new(void)
+{
+ t_object *x = (t_object *)pd_new(sqrt_class);
+ outlet_new(x, &s_float);
+ return (x);
+}
+
+static void sqrt_float(t_object *x, t_float f)
+{
+ float r = (f > 0 ? sqrtf(f) : 0);
+ outlet_float(x->ob_outlet, r);
+}
+
+static t_class *log_class; /* ----------- log --------------- */
+
+static void *log_new(void)
+{
+ t_object *x = (t_object *)pd_new(log_class);
+ outlet_new(x, &s_float);
+ return (x);
+}
+
+static void log_float(t_object *x, t_float f)
+{
+ float r = (f > 0 ? logf(f) : -1000);
+ outlet_float(x->ob_outlet, r);
+}
+
+
+static t_class *exp_class; /* ----------- exp --------------- */
+
+static void *exp_new(void)
+{
+ t_object *x = (t_object *)pd_new(exp_class);
+ outlet_new(x, &s_float);
+ return (x);
+}
+
+#define MAXLOG 87.3365
+static void exp_float(t_object *x, t_float f)
+{
+ float g;
+#ifdef NT
+ char buf[10];
+#endif
+ if (f > MAXLOG) f = MAXLOG;
+ g = expf(f);
+ outlet_float(x->ob_outlet, g);
+}
+
+static t_class *abs_class; /* ----------- abs --------------- */
+
+static void *abs_new(void)
+{
+ t_object *x = (t_object *)pd_new(abs_class);
+ outlet_new(x, &s_float);
+ return (x);
+}
+
+static void abs_float(t_object *x, t_float f)
+{
+ outlet_float(x->ob_outlet, fabsf(f));
+}
+
+/* ------------------------ misc ------------------------ */
+
+static t_class *clip_class;
+
+typedef struct _clip
+{
+ t_object x_ob;
+ t_outlet *x_out2;
+ float x_f1;
+ float x_f2;
+} t_clip;
+
+static void *clip_new(t_floatarg f1, t_floatarg f2)
+{
+ t_clip *x = (t_clip *)pd_new(clip_class);
+ floatinlet_new(&x->x_ob, &x->x_f1);
+ floatinlet_new(&x->x_ob, &x->x_f2);
+ outlet_new(&x->x_ob, &s_float);
+ x->x_out2 = outlet_new(&x->x_ob, &s_float);
+ x->x_f1 = f1;
+ x->x_f2 = f2;
+ return (x);
+}
+
+static void clip_float(t_clip *x, t_float f)
+{
+ outlet_float(x->x_ob.ob_outlet, (f < x->x_f1 ? x->x_f1 : (
+ f > x->x_f2 ? x->x_f2 : f)));
+}
+
+static void clip_setup(void)
+{
+ clip_class = class_new(gensym("clip"), (t_newmethod)clip_new, 0,
+ sizeof(t_clip), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addfloat(clip_class, clip_float);
+}
+
+void x_arithmetic_setup(void)
+{
+ t_symbol *binop1_sym = gensym("operators");
+ t_symbol *binop23_sym = gensym("otherbinops");
+ t_symbol *math_sym = gensym("math");
+
+ binop1_plus_class = class_new(gensym("+"), (t_newmethod)binop1_plus_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop1_plus_class, binop1_plus_bang);
+ class_addfloat(binop1_plus_class, (t_method)binop1_plus_float);
+ class_sethelpsymbol(binop1_plus_class, binop1_sym);
+
+ binop1_minus_class = class_new(gensym("-"),
+ (t_newmethod)binop1_minus_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop1_minus_class, binop1_minus_bang);
+ class_addfloat(binop1_minus_class, (t_method)binop1_minus_float);
+ class_sethelpsymbol(binop1_minus_class, binop1_sym);
+
+ binop1_times_class = class_new(gensym("*"),
+ (t_newmethod)binop1_times_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop1_times_class, binop1_times_bang);
+ class_addfloat(binop1_times_class, (t_method)binop1_times_float);
+ class_sethelpsymbol(binop1_times_class, binop1_sym);
+
+ binop1_div_class = class_new(gensym("/"),
+ (t_newmethod)binop1_div_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop1_div_class, binop1_div_bang);
+ class_addfloat(binop1_div_class, (t_method)binop1_div_float);
+ class_sethelpsymbol(binop1_div_class, binop1_sym);
+
+ binop1_pow_class = class_new(gensym("pow"),
+ (t_newmethod)binop1_pow_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop1_pow_class, binop1_pow_bang);
+ class_addfloat(binop1_pow_class, (t_method)binop1_pow_float);
+ class_sethelpsymbol(binop1_pow_class, binop1_sym);
+
+ binop1_max_class = class_new(gensym("max"),
+ (t_newmethod)binop1_max_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop1_max_class, binop1_max_bang);
+ class_addfloat(binop1_max_class, (t_method)binop1_max_float);
+ class_sethelpsymbol(binop1_max_class, binop1_sym);
+
+ binop1_min_class = class_new(gensym("min"),
+ (t_newmethod)binop1_min_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop1_min_class, binop1_min_bang);
+ class_addfloat(binop1_min_class, (t_method)binop1_min_float);
+ class_sethelpsymbol(binop1_min_class, binop1_sym);
+
+ /* ------------------ binop2 ----------------------- */
+
+ binop2_ee_class = class_new(gensym("=="), (t_newmethod)binop2_ee_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop2_ee_class, binop2_ee_bang);
+ class_addfloat(binop2_ee_class, (t_method)binop2_ee_float);
+ class_sethelpsymbol(binop2_ee_class, binop23_sym);
+
+ binop2_ne_class = class_new(gensym("!="), (t_newmethod)binop2_ne_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop2_ne_class, binop2_ne_bang);
+ class_addfloat(binop2_ne_class, (t_method)binop2_ne_float);
+ class_sethelpsymbol(binop2_ne_class, binop23_sym);
+
+ binop2_gt_class = class_new(gensym(">"), (t_newmethod)binop2_gt_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop2_gt_class, binop2_gt_bang);
+ class_addfloat(binop2_gt_class, (t_method)binop2_gt_float);
+ class_sethelpsymbol(binop2_gt_class, binop23_sym);
+
+ binop2_lt_class = class_new(gensym("<"), (t_newmethod)binop2_lt_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop2_lt_class, binop2_lt_bang);
+ class_addfloat(binop2_lt_class, (t_method)binop2_lt_float);
+ class_sethelpsymbol(binop2_lt_class, binop23_sym);
+
+ binop2_ge_class = class_new(gensym(">="), (t_newmethod)binop2_ge_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop2_ge_class, binop2_ge_bang);
+ class_addfloat(binop2_ge_class, (t_method)binop2_ge_float);
+ class_sethelpsymbol(binop2_ge_class, binop23_sym);
+
+ binop2_le_class = class_new(gensym("<="), (t_newmethod)binop2_le_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop2_le_class, binop2_le_bang);
+ class_addfloat(binop2_le_class, (t_method)binop2_le_float);
+ class_sethelpsymbol(binop2_le_class, binop23_sym);
+
+ /* ------------------ binop3 ----------------------- */
+
+ binop3_ba_class = class_new(gensym("&"), (t_newmethod)binop3_ba_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop3_ba_class, binop2_ba_bang);
+ class_addfloat(binop3_ba_class, (t_method)binop2_ba_float);
+ class_sethelpsymbol(binop3_ba_class, binop23_sym);
+
+ binop3_la_class = class_new(gensym("&&"), (t_newmethod)binop3_la_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop3_la_class, binop2_la_bang);
+ class_addfloat(binop3_la_class, (t_method)binop2_la_float);
+ class_sethelpsymbol(binop3_la_class, binop23_sym);
+
+ binop3_bo_class = class_new(gensym("|"), (t_newmethod)binop3_bo_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop3_bo_class, binop2_bo_bang);
+ class_addfloat(binop3_bo_class, (t_method)binop2_bo_float);
+ class_sethelpsymbol(binop3_bo_class, binop23_sym);
+
+ binop3_lo_class = class_new(gensym("||"), (t_newmethod)binop3_lo_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop3_lo_class, binop2_lo_bang);
+ class_addfloat(binop3_lo_class, (t_method)binop2_lo_float);
+ class_sethelpsymbol(binop3_lo_class, binop23_sym);
+
+ binop3_ls_class = class_new(gensym("<<"), (t_newmethod)binop3_ls_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop3_ls_class, binop2_ls_bang);
+ class_addfloat(binop3_ls_class, (t_method)binop2_ls_float);
+ class_sethelpsymbol(binop3_ls_class, binop23_sym);
+
+ binop3_rs_class = class_new(gensym(">>"), (t_newmethod)binop3_rs_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop3_rs_class, binop2_rs_bang);
+ class_addfloat(binop3_rs_class, (t_method)binop2_rs_float);
+ class_sethelpsymbol(binop3_rs_class, binop23_sym);
+
+ binop3_pc_class = class_new(gensym("%"), (t_newmethod)binop3_pc_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop3_pc_class, binop2_pc_bang);
+ class_addfloat(binop3_pc_class, (t_method)binop2_pc_float);
+ class_sethelpsymbol(binop3_pc_class, binop23_sym);
+
+ binop3_mod_class = class_new(gensym("mod"), (t_newmethod)binop3_mod_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop3_mod_class, binop3_mod_bang);
+ class_addfloat(binop3_mod_class, (t_method)binop3_mod_float);
+ class_sethelpsymbol(binop3_mod_class, binop23_sym);
+
+ binop3_div_class = class_new(gensym("div"), (t_newmethod)binop3_div_new, 0,
+ sizeof(t_binop), 0, A_DEFFLOAT, 0);
+ class_addbang(binop3_div_class, binop3_div_bang);
+ class_addfloat(binop3_div_class, (t_method)binop3_div_float);
+ class_sethelpsymbol(binop3_div_class, binop23_sym);
+
+ /* ------------------- math functions --------------- */
+
+ sin_class = class_new(gensym("sin"), sin_new, 0,
+ sizeof(t_object), 0, 0);
+ class_addfloat(sin_class, (t_method)sin_float);
+ class_sethelpsymbol(sin_class, math_sym);
+
+ cos_class = class_new(gensym("cos"), cos_new, 0,
+ sizeof(t_object), 0, 0);
+ class_addfloat(cos_class, (t_method)cos_float);
+ class_sethelpsymbol(cos_class, math_sym);
+
+ tan_class = class_new(gensym("tan"), tan_new, 0,
+ sizeof(t_object), 0, 0);
+ class_addfloat(tan_class, (t_method)tan_float);
+ class_sethelpsymbol(tan_class, math_sym);
+
+ atan_class = class_new(gensym("atan"), atan_new, 0,
+ sizeof(t_object), 0, 0);
+ class_addfloat(atan_class, (t_method)atan_float);
+ class_sethelpsymbol(atan_class, math_sym);
+
+ atan2_class = class_new(gensym("atan2"), atan2_new, 0,
+ sizeof(t_atan2), 0, 0);
+ class_addfloat(atan2_class, (t_method)atan2_float);
+ class_sethelpsymbol(atan2_class, math_sym);
+
+ sqrt_class = class_new(gensym("sqrt"), sqrt_new, 0,
+ sizeof(t_object), 0, 0);
+ class_addfloat(sqrt_class, (t_method)sqrt_float);
+ class_sethelpsymbol(sqrt_class, math_sym);
+
+ log_class = class_new(gensym("log"), log_new, 0,
+ sizeof(t_object), 0, 0);
+ class_addfloat(log_class, (t_method)log_float);
+ class_sethelpsymbol(log_class, math_sym);
+
+ exp_class = class_new(gensym("exp"), exp_new, 0,
+ sizeof(t_object), 0, 0);
+ class_addfloat(exp_class, (t_method)exp_float);
+ class_sethelpsymbol(exp_class, math_sym);
+
+ abs_class = class_new(gensym("abs"), abs_new, 0,
+ sizeof(t_object), 0, 0);
+ class_addfloat(abs_class, (t_method)abs_float);
+ class_sethelpsymbol(abs_class, math_sym);
+
+/* ------------------------ misc ------------------------ */
+
+ clip_setup();
+}
+
+
diff --git a/pd/src/x_connective.c b/pd/src/x_connective.c
new file mode 100644
index 00000000..2b28f052
--- /dev/null
+++ b/pd/src/x_connective.c
@@ -0,0 +1,1452 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* connective objects */
+
+#include "m_pd.h"
+
+#include <string.h>
+#include <stdio.h>
+extern t_pd *newest;
+
+/* -------------------------- int ------------------------------ */
+static t_class *pdint_class;
+
+typedef struct _pdint
+{
+ t_object x_obj;
+ t_float x_f;
+} t_pdint;
+
+static void *pdint_new(t_floatarg f)
+{
+ t_pdint *x = (t_pdint *)pd_new(pdint_class);
+ x->x_f = f;
+ outlet_new(&x->x_obj, &s_float);
+ floatinlet_new(&x->x_obj, &x->x_f);
+ return (x);
+}
+
+static void pdint_bang(t_pdint *x)
+{
+ outlet_float(x->x_obj.ob_outlet, (t_float)(int)(x->x_f));
+}
+
+static void pdint_float(t_pdint *x, t_float f)
+{
+ outlet_float(x->x_obj.ob_outlet, (t_float)(int)(x->x_f = f));
+}
+
+void pdint_setup(void)
+{
+ pdint_class = class_new(gensym("int"), (t_newmethod)pdint_new, 0,
+ sizeof(t_pdint), 0, A_DEFFLOAT, 0);
+ class_addcreator((t_newmethod)pdint_new, gensym("i"), A_DEFFLOAT, 0);
+ class_addbang(pdint_class, pdint_bang);
+ class_addfloat(pdint_class, pdint_float);
+}
+
+/* -------------------------- float ------------------------------ */
+static t_class *pdfloat_class;
+
+typedef struct _pdfloat
+{
+ t_object x_obj;
+ t_float x_f;
+} t_pdfloat;
+
+ /* "float," "symbol," and "bang" are special because
+ they're created by short-circuited messages to the "new"
+ object which are handled specially in pd_typedmess(). */
+
+static void *pdfloat_new(t_pd *dummy, t_float f)
+{
+ t_pdfloat *x = (t_pdfloat *)pd_new(pdfloat_class);
+ x->x_f = f;
+ outlet_new(&x->x_obj, &s_float);
+ floatinlet_new(&x->x_obj, &x->x_f);
+ newest = &x->x_obj.ob_pd;
+ return (x);
+}
+
+static void *pdfloat_new2(t_floatarg f)
+{
+ return (pdfloat_new(0, f));
+}
+
+static void pdfloat_bang(t_pdfloat *x)
+{
+ outlet_float(x->x_obj.ob_outlet, x->x_f);
+}
+
+static void pdfloat_float(t_pdfloat *x, t_float f)
+{
+ outlet_float(x->x_obj.ob_outlet, x->x_f = f);
+}
+
+void pdfloat_setup(void)
+{
+ pdfloat_class = class_new(gensym("float"), (t_newmethod)pdfloat_new, 0,
+ sizeof(t_pdfloat), 0, A_FLOAT, 0);
+ class_addcreator((t_newmethod)pdfloat_new2, gensym("f"), A_DEFFLOAT, 0);
+ class_addbang(pdfloat_class, pdfloat_bang);
+ class_addfloat(pdfloat_class, (t_method)pdfloat_float);
+}
+
+/* -------------------------- symbol ------------------------------ */
+static t_class *pdsymbol_class;
+
+typedef struct _pdsymbol
+{
+ t_object x_obj;
+ t_symbol *x_s;
+} t_pdsymbol;
+
+static void *pdsymbol_new(t_pd *dummy, t_symbol *s)
+{
+ t_pdsymbol *x = (t_pdsymbol *)pd_new(pdsymbol_class);
+ x->x_s = s;
+ outlet_new(&x->x_obj, &s_symbol);
+ symbolinlet_new(&x->x_obj, &x->x_s);
+ newest = &x->x_obj.ob_pd;
+ return (x);
+}
+
+static void pdsymbol_bang(t_pdsymbol *x)
+{
+ outlet_symbol(x->x_obj.ob_outlet, x->x_s);
+}
+
+static void pdsymbol_symbol(t_pdsymbol *x, t_symbol *s)
+{
+ outlet_symbol(x->x_obj.ob_outlet, x->x_s = s);
+}
+
+static void pdsymbol_anything(t_pdsymbol *x, t_symbol *s, int ac, t_atom *av)
+{
+ outlet_symbol(x->x_obj.ob_outlet, x->x_s = s);
+}
+
+void pdsymbol_setup(void)
+{
+ pdsymbol_class = class_new(gensym("symbol"), (t_newmethod)pdsymbol_new, 0,
+ sizeof(t_pdsymbol), 0, A_SYMBOL, 0);
+ class_addbang(pdsymbol_class, pdsymbol_bang);
+ class_addsymbol(pdsymbol_class, pdsymbol_symbol);
+ class_addanything(pdsymbol_class, pdsymbol_anything);
+}
+
+/* -------------------------- bang ------------------------------ */
+static t_class *bang_class;
+
+typedef struct _bang
+{
+ t_object x_obj;
+} t_bang;
+
+static void *bang_new(t_pd *dummy)
+{
+ t_bang *x = (t_bang *)pd_new(bang_class);
+ outlet_new(&x->x_obj, &s_bang);
+ newest = &x->x_obj.ob_pd;
+ return (x);
+}
+
+static void *bang_new2(t_bang f)
+{
+ return (bang_new(0));
+}
+
+static void bang_bang(t_bang *x)
+{
+ outlet_bang(x->x_obj.ob_outlet);
+}
+
+void bang_setup(void)
+{
+ bang_class = class_new(gensym("bang"), (t_newmethod)bang_new, 0,
+ sizeof(t_bang), 0, 0);
+ class_addcreator((t_newmethod)bang_new2, gensym("b"), 0);
+ class_addbang(bang_class, bang_bang);
+ class_addfloat(bang_class, bang_bang);
+ class_addsymbol(bang_class, bang_bang);
+ class_addlist(bang_class, bang_bang);
+ class_addanything(bang_class, bang_bang);
+}
+
+/* -------------------- send ------------------------------ */
+
+static t_class *send_class;
+
+typedef struct _send
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+} t_send;
+
+static void send_bang(t_send *x)
+{
+ if (x->x_sym->s_thing) pd_bang(x->x_sym->s_thing);
+}
+
+static void send_float(t_send *x, t_float f)
+{
+ if (x->x_sym->s_thing) pd_float(x->x_sym->s_thing, f);
+}
+
+static void send_symbol(t_send *x, t_symbol *s)
+{
+ if (x->x_sym->s_thing) pd_symbol(x->x_sym->s_thing, s);
+}
+
+static void send_pointer(t_send *x, t_gpointer *gp)
+{
+ if (x->x_sym->s_thing) pd_pointer(x->x_sym->s_thing, gp);
+}
+
+static void send_list(t_send *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if (x->x_sym->s_thing) pd_list(x->x_sym->s_thing, s, argc, argv);
+}
+
+static void send_anything(t_send *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if (x->x_sym->s_thing) typedmess(x->x_sym->s_thing, s, argc, argv);
+}
+
+static void *send_new(t_symbol *s)
+{
+ t_send *x = (t_send *)pd_new(send_class);
+ x->x_sym = s;
+ return (x);
+}
+
+static void send_setup(void)
+{
+ send_class = class_new(gensym("send"), (t_newmethod)send_new, 0,
+ sizeof(t_send), 0, A_DEFSYM, 0);
+ class_addcreator((t_newmethod)send_new, gensym("s"), A_DEFSYM, 0);
+ class_addbang(send_class, send_bang);
+ class_addfloat(send_class, send_float);
+ class_addsymbol(send_class, send_symbol);
+ class_addpointer(send_class, send_pointer);
+ class_addlist(send_class, send_list);
+ class_addanything(send_class, send_anything);
+}
+/* -------------------- receive ------------------------------ */
+
+static t_class *receive_class;
+
+typedef struct _receive
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+} t_receive;
+
+static void receive_bang(t_receive *x)
+{
+ outlet_bang(x->x_obj.ob_outlet);
+}
+
+static void receive_float(t_receive *x, t_float f)
+{
+ outlet_float(x->x_obj.ob_outlet, f);
+}
+
+static void receive_symbol(t_receive *x, t_symbol *s)
+{
+ outlet_symbol(x->x_obj.ob_outlet, s);
+}
+
+static void receive_pointer(t_receive *x, t_gpointer *gp)
+{
+ outlet_pointer(x->x_obj.ob_outlet, gp);
+}
+
+static void receive_list(t_receive *x, t_symbol *s, int argc, t_atom *argv)
+{
+ outlet_list(x->x_obj.ob_outlet, s, argc, argv);
+}
+
+static void receive_anything(t_receive *x, t_symbol *s, int argc, t_atom *argv)
+{
+ outlet_anything(x->x_obj.ob_outlet, s, argc, argv);
+}
+
+static void *receive_new(t_symbol *s)
+{
+ t_receive *x = (t_receive *)pd_new(receive_class);
+ x->x_sym = s;
+ pd_bind(&x->x_obj.ob_pd, s);
+ outlet_new(&x->x_obj, 0);
+ return (x);
+}
+
+static void receive_free(t_receive *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, x->x_sym);
+}
+
+static void receive_setup(void)
+{
+ receive_class = class_new(gensym("receive"), (t_newmethod)receive_new,
+ (t_method)receive_free, sizeof(t_receive), CLASS_NOINLET, A_DEFSYM, 0);
+ class_addcreator((t_newmethod)receive_new, gensym("r"), A_DEFSYM, 0);
+ class_addbang(receive_class, receive_bang);
+ class_addfloat(receive_class, (t_method)receive_float);
+ class_addsymbol(receive_class, receive_symbol);
+ class_addpointer(receive_class, receive_pointer);
+ class_addlist(receive_class, receive_list);
+ class_addanything(receive_class, receive_anything);
+}
+
+/* -------------------------- select ------------------------------ */
+
+static t_class *sel1_class;
+
+typedef struct _sel1
+{
+ t_object x_obj;
+ t_atom x_atom;
+ t_outlet *x_outlet1;
+ t_outlet *x_outlet2;
+} t_sel1;
+
+static void sel1_float(t_sel1 *x, t_float f)
+{
+ if (x->x_atom.a_type == A_FLOAT && f == x->x_atom.a_w.w_float)
+ outlet_bang(x->x_outlet1);
+ else outlet_float(x->x_outlet2, f);
+}
+
+static void sel1_symbol(t_sel1 *x, t_symbol *s)
+{
+ if (x->x_atom.a_type == A_SYMBOL && s == x->x_atom.a_w.w_symbol)
+ outlet_bang(x->x_outlet1);
+ else outlet_symbol(x->x_outlet2, s);
+}
+
+static t_class *sel2_class;
+
+typedef struct _selectelement
+{
+ t_word e_w;
+ t_outlet *e_outlet;
+} t_selectelement;
+
+typedef struct _sel2
+{
+ t_object x_obj;
+ t_atomtype x_type;
+ t_int x_nelement;
+ t_selectelement *x_vec;
+ t_outlet *x_rejectout;
+} t_sel2;
+
+static void sel2_float(t_sel2 *x, t_float f)
+{
+ t_selectelement *e;
+ int nelement;
+ if (x->x_type == A_FLOAT)
+ {
+ for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
+ if (e->e_w.w_float == f)
+ {
+ outlet_bang(e->e_outlet);
+ return;
+ }
+ }
+ outlet_float(x->x_rejectout, f);
+}
+
+static void sel2_symbol(t_sel2 *x, t_symbol *s)
+{
+ t_selectelement *e;
+ int nelement;
+ if (x->x_type == A_SYMBOL)
+ {
+ for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
+ if (e->e_w.w_symbol == s)
+ {
+ outlet_bang(e->e_outlet);
+ return;
+ }
+ }
+ outlet_symbol(x->x_rejectout, s);
+}
+
+static void sel2_free(t_sel2 *x)
+{
+ freebytes(x->x_vec, x->x_nelement * sizeof(*x->x_vec));
+}
+
+static void *select_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_atom a;
+ if (argc == 0)
+ {
+ argc = 1;
+ SETFLOAT(&a, 0);
+ argv = &a;
+ }
+ if (argc == 1)
+ {
+ t_sel1 *x = (t_sel1 *)pd_new(sel1_class);
+ x->x_atom = *argv;
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_bang);
+ if (argv->a_type == A_FLOAT)
+ {
+ floatinlet_new(&x->x_obj, &x->x_atom.a_w.w_float);
+ x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
+ }
+ else
+ {
+ symbolinlet_new(&x->x_obj, &x->x_atom.a_w.w_symbol);
+ x->x_outlet2 = outlet_new(&x->x_obj, &s_symbol);
+ }
+ return (x);
+ }
+ else
+ {
+ int n;
+ t_selectelement *e;
+ t_sel2 *x = (t_sel2 *)pd_new(sel2_class);
+ x->x_nelement = argc;
+ x->x_vec = (t_selectelement *)getbytes(argc * sizeof(*x->x_vec));
+ x->x_type = argv[0].a_type;
+ for (n = 0, e = x->x_vec; n < argc; n++, e++)
+ {
+ e->e_outlet = outlet_new(&x->x_obj, &s_bang);
+ if ((x->x_type = argv->a_type) == A_FLOAT)
+ e->e_w.w_float = atom_getfloatarg(n, argc, argv);
+ else e->e_w.w_symbol = atom_getsymbolarg(n, argc, argv);
+ }
+ x->x_rejectout = outlet_new(&x->x_obj, &s_float);
+ return (x);
+ }
+
+}
+
+void select_setup(void)
+{
+ sel1_class = class_new(gensym("select"), 0, 0,
+ sizeof(t_sel1), 0, 0);
+ class_addfloat(sel1_class, sel1_float);
+ class_addsymbol(sel1_class, sel1_symbol);
+
+ sel2_class = class_new(gensym("select"), 0, (t_method)sel2_free,
+ sizeof(t_sel2), 0, 0);
+ class_addfloat(sel2_class, sel2_float);
+ class_addsymbol(sel2_class, sel2_symbol);
+
+ class_addcreator((t_newmethod)select_new, gensym("select"), A_GIMME, 0);
+ class_addcreator((t_newmethod)select_new, gensym("sel"), A_GIMME, 0);
+}
+
+/* -------------------------- route ------------------------------ */
+
+static t_class *route_class;
+
+typedef struct _routeelement
+{
+ t_word e_w;
+ t_outlet *e_outlet;
+} t_routeelement;
+
+typedef struct _route
+{
+ t_object x_obj;
+ t_atomtype x_type;
+ t_int x_nelement;
+ t_routeelement *x_vec;
+ t_outlet *x_rejectout;
+} t_route;
+
+static void route_anything(t_route *x, t_symbol *sel, int argc, t_atom *argv)
+{
+ t_routeelement *e;
+ int nelement;
+ if (x->x_type == A_SYMBOL)
+ {
+ for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
+ if (e->e_w.w_symbol == sel)
+ {
+ if (argc > 0 && argv[0].a_type == A_SYMBOL)
+ outlet_anything(e->e_outlet, argv[0].a_w.w_symbol,
+ argc-1, argv+1);
+ else outlet_list(e->e_outlet, 0, argc, argv);
+ return;
+ }
+ }
+ outlet_anything(x->x_rejectout, sel, argc, argv);
+}
+
+static void route_list(t_route *x, t_symbol *sel, int argc, t_atom *argv)
+{
+ t_routeelement *e;
+ int nelement;
+ if (x->x_type == A_FLOAT)
+ {
+ float f;
+ if (!argc) return;
+ f = atom_getfloat(argv);
+ for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
+ if (e->e_w.w_float == f)
+ {
+ if (argc > 1 && argv[1].a_type == A_SYMBOL)
+ outlet_anything(e->e_outlet, argv[1].a_w.w_symbol,
+ argc-2, argv+2);
+ else outlet_list(e->e_outlet, 0, argc-1, argv+1);
+ return;
+ }
+ }
+ else /* symbol arguments */
+ {
+ if (argc > 1) /* 2 or more args: treat as "list" */
+ {
+ for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
+ {
+ if (e->e_w.w_symbol == &s_list)
+ {
+ if (argc > 0 && argv[0].a_type == A_SYMBOL)
+ outlet_anything(e->e_outlet, argv[0].a_w.w_symbol,
+ argc-1, argv+1);
+ else outlet_list(e->e_outlet, 0, argc, argv);
+ return;
+ }
+ }
+ }
+ else if (argc == 0) /* no args: treat as "bang" */
+ {
+ for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
+ {
+ if (e->e_w.w_symbol == &s_bang)
+ {
+ outlet_bang(e->e_outlet);
+ return;
+ }
+ }
+ }
+ else if (argv[0].a_type == A_FLOAT) /* one float arg */
+ {
+ for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
+ {
+ if (e->e_w.w_symbol == &s_float)
+ {
+ outlet_float(e->e_outlet, argv[0].a_w.w_float);
+ return;
+ }
+ }
+ }
+ else
+ {
+ for (nelement = x->x_nelement, e = x->x_vec; nelement--; e++)
+ {
+ if (e->e_w.w_symbol == &s_symbol)
+ {
+ outlet_symbol(e->e_outlet, argv[0].a_w.w_symbol);
+ return;
+ }
+ }
+ }
+ }
+ outlet_list(x->x_rejectout, 0, argc, argv);
+}
+
+
+static void route_free(t_route *x)
+{
+ freebytes(x->x_vec, x->x_nelement * sizeof(*x->x_vec));
+}
+
+static void *route_new(t_symbol *s, int argc, t_atom *argv)
+{
+ int n;
+ t_routeelement *e;
+ t_route *x = (t_route *)pd_new(route_class);
+ t_atom a;
+ if (argc == 0)
+ {
+ argc = 1;
+ SETFLOAT(&a, 0);
+ argv = &a;
+ }
+ x->x_type = argv[0].a_type;
+ x->x_nelement = argc;
+ x->x_vec = (t_routeelement *)getbytes(argc * sizeof(*x->x_vec));
+ for (n = 0, e = x->x_vec; n < argc; n++, e++)
+ {
+ e->e_outlet = outlet_new(&x->x_obj, &s_list);
+ if (x->x_type == A_FLOAT)
+ e->e_w.w_float = atom_getfloatarg(n, argc, argv);
+ else e->e_w.w_symbol = atom_getsymbolarg(n, argc, argv);
+ }
+ x->x_rejectout = outlet_new(&x->x_obj, &s_list);
+ return (x);
+}
+
+void route_setup(void)
+{
+ route_class = class_new(gensym("route"), (t_newmethod)route_new,
+ (t_method)route_free, sizeof(t_route), 0, A_GIMME, 0);
+ class_addlist(route_class, route_list);
+ class_addanything(route_class, route_anything);
+}
+
+/* -------------------------- pack ------------------------------ */
+
+static t_class *pack_class;
+
+typedef struct _pack
+{
+ t_object x_obj;
+ t_int x_n; /* number of args */
+ t_atom *x_vec; /* input values */
+ t_int x_nptr; /* number of pointers */
+ t_gpointer *x_gpointer; /* the pointers */
+ t_atom *x_outvec; /* space for output values */
+} t_pack;
+
+static void *pack_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_pack *x = (t_pack *)pd_new(pack_class);
+ t_atom defarg[2], *ap, *vec, *vp;
+ t_gpointer *gp;
+ int nptr = 0;
+ int i;
+ if (!argc)
+ {
+ argv = defarg;
+ argc = 2;
+ SETFLOAT(&defarg[0], 0);
+ SETFLOAT(&defarg[1], 0);
+ }
+
+ x->x_n = argc;
+ vec = x->x_vec = (t_atom *)getbytes(argc * sizeof(*x->x_vec));
+ x->x_outvec = (t_atom *)getbytes(argc * sizeof(*x->x_outvec));
+
+ for (i = argc, ap = argv; i--; ap++)
+ if (ap->a_type == A_SYMBOL && *ap->a_w.w_symbol->s_name == 'p')
+ nptr++;
+
+ gp = x->x_gpointer = (t_gpointer *)t_getbytes(nptr * sizeof (*gp));
+ x->x_nptr = nptr;
+
+ for (i = 0, vp = x->x_vec, ap = argv; i < argc; i++, ap++, vp++)
+ {
+ if (ap->a_type == A_FLOAT)
+ {
+ *vp = *ap;
+ if (i) floatinlet_new(&x->x_obj, &vp->a_w.w_float);
+ }
+ else if (ap->a_type == A_SYMBOL)
+ {
+ char c = *ap->a_w.w_symbol->s_name;
+ if (c == 's')
+ {
+ SETSYMBOL(vp, &s_symbol);
+ if (i) symbolinlet_new(&x->x_obj, &vp->a_w.w_symbol);
+ }
+ else if (c == 'p')
+ {
+ vp->a_type = A_POINTER;
+ vp->a_w.w_gpointer = gp;
+ gpointer_init(gp);
+ if (i) pointerinlet_new(&x->x_obj, gp);
+ gp++;
+ }
+ else
+ {
+ if (c != 'f') pd_error(x, "pack: %s: bad type",
+ ap->a_w.w_symbol->s_name);
+ SETFLOAT(vp, 0);
+ if (i) floatinlet_new(&x->x_obj, &vp->a_w.w_float);
+ }
+ }
+ }
+ outlet_new(&x->x_obj, &s_list);
+ return (x);
+}
+
+static void pack_bang(t_pack *x)
+{
+ int i, reentered = 0, size = x->x_n * sizeof (t_atom);
+ t_gpointer *gp;
+ t_atom *outvec;
+ for (i = x->x_nptr, gp = x->x_gpointer; i--; gp++)
+ if (!gpointer_check(gp, 1))
+ {
+ pd_error(x, "pack: stale pointer");
+ return;
+ }
+ /* reentrancy protection. The first time through use the pre-allocated
+ x_outvec; if we're reentered we have to allocate new memory. */
+ if (!x->x_outvec)
+ {
+ /* LATER figure out how to deal with reentrancy and pointers... */
+ if (x->x_nptr)
+ post("pack_bang: warning: reentry with pointers unprotected");
+ outvec = t_getbytes(size);
+ reentered = 1;
+ }
+ else
+ {
+ outvec = x->x_outvec;
+ x->x_outvec = 0;
+ }
+ memcpy(outvec, x->x_vec, size);
+ outlet_list(x->x_obj.ob_outlet, &s_list, x->x_n, outvec);
+ if (reentered)
+ t_freebytes(outvec, size);
+ else x->x_outvec = outvec;
+}
+
+static void pack_pointer(t_pack *x, t_gpointer *gp)
+{
+ if (x->x_vec->a_type == A_POINTER)
+ {
+ gpointer_unset(x->x_gpointer);
+ *x->x_gpointer = *gp;
+ if (gp->gp_stub) gp->gp_stub->gs_refcount++;
+ pack_bang(x);
+ }
+ else pd_error(x, "pack_pointer: wrong type");
+}
+
+static void pack_float(t_pack *x, t_float f)
+{
+ if (x->x_vec->a_type == A_FLOAT)
+ {
+ x->x_vec->a_w.w_float = f;
+ pack_bang(x);
+ }
+ else pd_error(x, "pack_float: wrong type");
+}
+
+static void pack_symbol(t_pack *x, t_symbol *s)
+{
+ if (x->x_vec->a_type == A_SYMBOL)
+ {
+ x->x_vec->a_w.w_symbol = s;
+ pack_bang(x);
+ }
+ else pd_error(x, "pack_symbol: wrong type");
+}
+
+static void pack_list(t_pack *x, t_symbol *s, int ac, t_atom *av)
+{
+ obj_list(&x->x_obj, 0, ac, av);
+}
+
+static void pack_anything(t_pack *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_atom *av2 = (t_atom *)getbytes((ac + 1) * sizeof(t_atom));
+ int i;
+ for (i = 0; i < ac; i++)
+ av2[i + 1] = av[i];
+ SETSYMBOL(av2, s);
+ obj_list(&x->x_obj, 0, ac+1, av2);
+ freebytes(av2, (ac + 1) * sizeof(t_atom));
+}
+
+static void pack_free(t_pack *x)
+{
+ t_gpointer *gp;
+ int i;
+ for (gp = x->x_gpointer, i = x->x_nptr; i--; gp++)
+ gpointer_unset(gp);
+ freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec));
+ freebytes(x->x_outvec, x->x_n * sizeof(*x->x_outvec));
+ freebytes(x->x_gpointer, x->x_nptr * sizeof(*x->x_gpointer));
+}
+
+static void pack_setup(void)
+{
+ pack_class = class_new(gensym("pack"), (t_newmethod)pack_new,
+ (t_method)pack_free, sizeof(t_pack), 0, A_GIMME, 0);
+ class_addbang(pack_class, pack_bang);
+ class_addpointer(pack_class, pack_pointer);
+ class_addfloat(pack_class, pack_float);
+ class_addsymbol(pack_class, pack_symbol);
+ class_addlist(pack_class, pack_list);
+ class_addanything(pack_class, pack_anything);
+}
+
+/* -------------------------- unpack ------------------------------ */
+
+static t_class *unpack_class;
+
+typedef struct unpackout
+{
+ t_atomtype u_type;
+ t_outlet *u_outlet;
+} t_unpackout;
+
+typedef struct _unpack
+{
+ t_object x_obj;
+ t_int x_n;
+ t_unpackout *x_vec;
+} t_unpack;
+
+static void *unpack_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_unpack *x = (t_unpack *)pd_new(unpack_class);
+ t_atom defarg[2], *ap;
+ t_unpackout *u;
+ int i;
+ if (!argc)
+ {
+ argv = defarg;
+ argc = 2;
+ SETFLOAT(&defarg[0], 0);
+ SETFLOAT(&defarg[1], 0);
+ }
+ x->x_n = argc;
+ x->x_vec = (t_unpackout *)getbytes(argc * sizeof(*x->x_vec));
+ for (i = 0, ap = argv, u = x->x_vec; i < argc; u++, ap++, i++)
+ {
+ t_atomtype type = ap->a_type;
+ if (type == A_SYMBOL)
+ {
+ char c = *ap->a_w.w_symbol->s_name;
+ if (c == 's')
+ {
+ u->u_type = A_SYMBOL;
+ u->u_outlet = outlet_new(&x->x_obj, &s_symbol);
+ }
+ else if (c == 'p')
+ {
+ u->u_type = A_POINTER;
+ u->u_outlet = outlet_new(&x->x_obj, &s_pointer);
+ }
+ else
+ {
+ if (c != 'f') pd_error(x, "unpack: %s: bad type",
+ ap->a_w.w_symbol->s_name);
+ u->u_type = A_FLOAT;
+ u->u_outlet = outlet_new(&x->x_obj, &s_float);
+ }
+ }
+ else
+ {
+ u->u_type = A_FLOAT;
+ u->u_outlet = outlet_new(&x->x_obj, &s_float);
+ }
+ }
+ return (x);
+}
+
+static void unpack_list(t_unpack *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_atom *ap;
+ t_unpackout *u;
+ int i;
+ if (argc > x->x_n) argc = x->x_n;
+ for (i = argc, u = x->x_vec + i, ap = argv + i; u--, ap--, i--;)
+ {
+ t_atomtype type = u->u_type;
+ if (type != ap->a_type)
+ pd_error(x, "unpack: type mismatch");
+ else if (type == A_FLOAT)
+ outlet_float(u->u_outlet, ap->a_w.w_float);
+ else if (type == A_SYMBOL)
+ outlet_symbol(u->u_outlet, ap->a_w.w_symbol);
+ else outlet_pointer(u->u_outlet, ap->a_w.w_gpointer);
+ }
+}
+
+static void unpack_anything(t_unpack *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_atom *av2 = (t_atom *)getbytes((ac + 1) * sizeof(t_atom));
+ int i;
+ for (i = 0; i < ac; i++)
+ av2[i + 1] = av[i];
+ SETSYMBOL(av2, s);
+ unpack_list(x, 0, ac+1, av2);
+ freebytes(av2, (ac + 1) * sizeof(t_atom));
+}
+
+static void unpack_free(t_unpack *x)
+{
+ freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec));
+}
+
+static void unpack_setup(void)
+{
+ unpack_class = class_new(gensym("unpack"), (t_newmethod)unpack_new,
+ (t_method)unpack_free, sizeof(t_unpack), 0, A_GIMME, 0);
+ class_addlist(unpack_class, unpack_list);
+ class_addanything(unpack_class, unpack_anything);
+}
+
+/* -------------------------- trigger ------------------------------ */
+
+static t_class *trigger_class;
+#define TR_BANG 0
+#define TR_FLOAT 1
+#define TR_SYMBOL 2
+#define TR_POINTER 3
+#define TR_LIST 4
+#define TR_ANYTHING 5
+
+typedef struct triggerout
+{
+ int u_type; /* outlet type from above */
+ t_outlet *u_outlet;
+} t_triggerout;
+
+typedef struct _trigger
+{
+ t_object x_obj;
+ t_int x_n;
+ t_triggerout *x_vec;
+} t_trigger;
+
+static void *trigger_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_trigger *x = (t_trigger *)pd_new(trigger_class);
+ t_atom defarg[2], *ap;
+ t_triggerout *u;
+ int i;
+ if (!argc)
+ {
+ argv = defarg;
+ argc = 2;
+ SETSYMBOL(&defarg[0], &s_bang);
+ SETSYMBOL(&defarg[1], &s_bang);
+ }
+ x->x_n = argc;
+ x->x_vec = (t_triggerout *)getbytes(argc * sizeof(*x->x_vec));
+ for (i = 0, ap = argv, u = x->x_vec; i < argc; u++, ap++, i++)
+ {
+ t_atomtype thistype = ap->a_type;
+ char c;
+ if (thistype == TR_SYMBOL) c = ap->a_w.w_symbol->s_name[0];
+ else if (thistype == TR_FLOAT) c = 'f';
+ else c = 0;
+ if (c == 'p')
+ u->u_type = TR_POINTER,
+ u->u_outlet = outlet_new(&x->x_obj, &s_pointer);
+ else if (c == 'f')
+ u->u_type = TR_FLOAT, u->u_outlet = outlet_new(&x->x_obj, &s_float);
+ else if (c == 'b')
+ u->u_type = TR_BANG, u->u_outlet = outlet_new(&x->x_obj, &s_bang);
+ else if (c == 'l')
+ u->u_type = TR_LIST, u->u_outlet = outlet_new(&x->x_obj, &s_list);
+ else if (c == 's')
+ u->u_type = TR_SYMBOL,
+ u->u_outlet = outlet_new(&x->x_obj, &s_symbol);
+ else if (c == 'a')
+ u->u_type = TR_ANYTHING,
+ u->u_outlet = outlet_new(&x->x_obj, &s_symbol);
+ else
+ {
+ pd_error(x, "trigger: %s: bad type", ap->a_w.w_symbol->s_name);
+ u->u_type = TR_FLOAT, u->u_outlet = outlet_new(&x->x_obj, &s_float);
+ }
+ }
+ return (x);
+}
+
+static void trigger_list(t_trigger *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_triggerout *u;
+ int i;
+ t_atom at;
+ if (!argc)
+ {
+ argc = 1;
+ SETFLOAT(&at, 0);
+ argv = &at;
+ }
+ for (i = x->x_n, u = x->x_vec + i; u--, i--;)
+ {
+ if (u->u_type == TR_FLOAT)
+ outlet_float(u->u_outlet, atom_getfloat(argv));
+ else if (u->u_type == TR_BANG)
+ outlet_bang(u->u_outlet);
+ else if (u->u_type == TR_SYMBOL)
+ outlet_symbol(u->u_outlet, atom_getsymbol(argv));
+ else if (u->u_type == TR_POINTER)
+ {
+ if (argv->a_type != TR_POINTER)
+ pd_error(x, "unpack: bad pointer");
+ else outlet_pointer(u->u_outlet, argv->a_w.w_gpointer);
+ }
+ else outlet_list(u->u_outlet, &s_list, argc, argv);
+ }
+}
+
+static void trigger_anything(t_trigger *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_triggerout *u;
+ int i;
+ for (i = x->x_n, u = x->x_vec + i; u--, i--;)
+ {
+ if (u->u_type == TR_BANG)
+ outlet_bang(u->u_outlet);
+ else if (u->u_type == TR_ANYTHING)
+ outlet_anything(u->u_outlet, s, argc, argv);
+ else pd_error(x, "trigger: can only convert 's' to 'b' or 'a'",
+ s->s_name);
+ }
+}
+
+static void trigger_bang(t_trigger *x)
+{
+ trigger_list(x, 0, 0, 0);
+}
+
+static void trigger_pointer(t_trigger *x, t_gpointer *gp)
+{
+ t_atom at;
+ SETPOINTER(&at, gp);
+ trigger_list(x, 0, 1, &at);
+}
+
+static void trigger_float(t_trigger *x, t_float f)
+{
+ t_atom at;
+ SETFLOAT(&at, f);
+ trigger_list(x, 0, 1, &at);
+}
+
+static void trigger_symbol(t_trigger *x, t_symbol *s)
+{
+ t_atom at;
+ SETSYMBOL(&at, s);
+ trigger_list(x, 0, 1, &at);
+}
+
+static void trigger_free(t_trigger *x)
+{
+ freebytes(x->x_vec, x->x_n * sizeof(*x->x_vec));
+}
+
+static void trigger_setup(void)
+{
+ trigger_class = class_new(gensym("trigger"), (t_newmethod)trigger_new,
+ (t_method)trigger_free, sizeof(t_trigger), 0, A_GIMME, 0);
+ class_addcreator((t_newmethod)trigger_new, gensym("t"), A_GIMME, 0);
+ class_addlist(trigger_class, trigger_list);
+ class_addbang(trigger_class, trigger_bang);
+ class_addpointer(trigger_class, trigger_pointer);
+ class_addfloat(trigger_class, (t_method)trigger_float);
+ class_addsymbol(trigger_class, trigger_symbol);
+ class_addanything(trigger_class, trigger_anything);
+}
+
+/* -------------------------- spigot ------------------------------ */
+static t_class *spigot_class;
+
+typedef struct _spigot
+{
+ t_object x_obj;
+ float x_state;
+} t_spigot;
+
+static void *spigot_new(void)
+{
+ t_spigot *x = (t_spigot *)pd_new(spigot_class);
+ floatinlet_new(&x->x_obj, &x->x_state);
+ outlet_new(&x->x_obj, 0);
+ x->x_state = 0;
+ return (x);
+}
+
+static void spigot_bang(t_spigot *x)
+{
+ if (x->x_state != 0) outlet_bang(x->x_obj.ob_outlet);
+}
+
+static void spigot_pointer(t_spigot *x, t_gpointer *gp)
+{
+ if (x->x_state != 0) outlet_pointer(x->x_obj.ob_outlet, gp);
+}
+
+static void spigot_float(t_spigot *x, t_float f)
+{
+ if (x->x_state != 0) outlet_float(x->x_obj.ob_outlet, f);
+}
+
+static void spigot_symbol(t_spigot *x, t_symbol *s)
+{
+ if (x->x_state != 0) outlet_symbol(x->x_obj.ob_outlet, s);
+}
+
+static void spigot_list(t_spigot *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if (x->x_state != 0) outlet_list(x->x_obj.ob_outlet, s, argc, argv);
+}
+
+static void spigot_anything(t_spigot *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if (x->x_state != 0) outlet_anything(x->x_obj.ob_outlet, s, argc, argv);
+}
+
+static void spigot_setup(void)
+{
+ spigot_class = class_new(gensym("spigot"), (t_newmethod)spigot_new, 0,
+ sizeof(t_spigot), 0, A_DEFSYM, 0);
+ class_addbang(spigot_class, spigot_bang);
+ class_addpointer(spigot_class, spigot_pointer);
+ class_addfloat(spigot_class, spigot_float);
+ class_addsymbol(spigot_class, spigot_symbol);
+ class_addlist(spigot_class, spigot_list);
+ class_addanything(spigot_class, spigot_anything);
+}
+
+/* --------------------------- moses ----------------------------- */
+static t_class *moses_class;
+
+typedef struct _moses
+{
+ t_object x_ob;
+ t_outlet *x_out2;
+ float x_y;
+} t_moses;
+
+static void *moses_new(t_floatarg f)
+{
+ t_moses *x = (t_moses *)pd_new(moses_class);
+ floatinlet_new(&x->x_ob, &x->x_y);
+ outlet_new(&x->x_ob, &s_float);
+ x->x_out2 = outlet_new(&x->x_ob, &s_float);
+ x->x_y = f;
+ return (x);
+}
+
+static void moses_float(t_moses *x, t_float f)
+{
+ if (f < x->x_y) outlet_float(x->x_ob.ob_outlet, f);
+ else outlet_float(x->x_out2, f);
+}
+
+static void moses_setup(void)
+{
+ moses_class = class_new(gensym("moses"), (t_newmethod)moses_new, 0,
+ sizeof(t_moses), 0, A_DEFFLOAT, 0);
+ class_addfloat(moses_class, moses_float);
+}
+
+/* ----------------------- until --------------------- */
+
+static t_class *until_class;
+
+typedef struct _until
+{
+ t_object x_obj;
+ int x_run;
+ int x_count;
+} t_until;
+
+static void *until_new(void)
+{
+ t_until *x = (t_until *)pd_new(until_class);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("bang"), gensym("bang2"));
+ outlet_new(&x->x_obj, &s_bang);
+ x->x_run = 0;
+ return (x);
+}
+
+static void until_bang(t_until *x)
+{
+ x->x_run = 1;
+ x->x_count = -1;
+ while (x->x_run && x->x_count)
+ x->x_count--, outlet_bang(x->x_obj.ob_outlet);
+}
+
+static void until_float(t_until *x, t_float f)
+{
+ x->x_run = 1;
+ x->x_count = f;
+ while (x->x_run && x->x_count)
+ x->x_count--, outlet_bang(x->x_obj.ob_outlet);
+}
+
+static void until_bang2(t_until *x)
+{
+ x->x_run = 0;
+}
+
+static void until_setup(void)
+{
+ until_class = class_new(gensym("until"), (t_newmethod)until_new, 0,
+ sizeof(t_until), 0, 0);
+ class_addbang(until_class, until_bang);
+ class_addfloat(until_class, until_float);
+ class_addmethod(until_class, (t_method)until_bang2, gensym("bang2"), 0);
+}
+
+/* ----------------------- makefilename --------------------- */
+
+static t_class *makefilename_class;
+
+typedef struct _makefilename
+{
+ t_object x_obj;
+ t_symbol *x_format;
+} t_makefilename;
+
+static void *makefilename_new(t_symbol *s)
+{
+ t_makefilename *x = (t_makefilename *)pd_new(makefilename_class);
+ if (!s->s_name) s = gensym("file.%d");
+ outlet_new(&x->x_obj, &s_symbol);
+ x->x_format = s;
+ return (x);
+}
+
+static void makefilename_float(t_makefilename *x, t_floatarg f)
+{
+ char buf[MAXPDSTRING];
+ sprintf(buf, x->x_format->s_name, (int)f);
+ outlet_symbol(x->x_obj.ob_outlet, gensym(buf));
+}
+
+static void makefilename_symbol(t_makefilename *x, t_symbol *s)
+{
+ char buf[MAXPDSTRING];
+ sprintf(buf, x->x_format->s_name, s->s_name);
+ outlet_symbol(x->x_obj.ob_outlet, gensym(buf));
+}
+
+static void makefilename_setup(void)
+{
+ makefilename_class = class_new(gensym("makefilename"),
+ (t_newmethod)makefilename_new, 0,
+ sizeof(t_makefilename), 0, A_DEFSYM, 0);
+ class_addfloat(makefilename_class, makefilename_float);
+ class_addsymbol(makefilename_class, makefilename_symbol);
+}
+
+/* -------------------------- swap ------------------------------ */
+static t_class *swap_class;
+
+typedef struct _swap
+{
+ t_object x_obj;
+ t_outlet *x_out2;
+ t_float x_f1;
+ t_float x_f2;
+} t_swap;
+
+static void *swap_new(t_floatarg f)
+{
+ t_swap *x = (t_swap *)pd_new(swap_class);
+ x->x_f2 = f;
+ x->x_f1 = 0;
+ outlet_new(&x->x_obj, &s_float);
+ x->x_out2 = outlet_new(&x->x_obj, &s_float);
+ floatinlet_new(&x->x_obj, &x->x_f2);
+ return (x);
+}
+
+static void swap_bang(t_swap *x)
+{
+ outlet_float(x->x_out2, x->x_f1);
+ outlet_float(x->x_obj.ob_outlet, x->x_f2);
+}
+
+static void swap_float(t_swap *x, t_float f)
+{
+ x->x_f1 = f;
+ swap_bang(x);
+}
+
+void swap_setup(void)
+{
+ swap_class = class_new(gensym("swap"), (t_newmethod)swap_new, 0,
+ sizeof(t_swap), 0, A_DEFFLOAT, 0);
+ class_addcreator((t_newmethod)swap_new, gensym("fswap"), A_DEFFLOAT, 0);
+ class_addbang(swap_class, swap_bang);
+ class_addfloat(swap_class, swap_float);
+}
+
+/* -------------------------- change ------------------------------ */
+static t_class *change_class;
+
+typedef struct _change
+{
+ t_object x_obj;
+ t_float x_f;
+} t_change;
+
+static void *change_new(t_floatarg f)
+{
+ t_change *x = (t_change *)pd_new(change_class);
+ x->x_f = f;
+ outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+static void change_bang(t_change *x)
+{
+ outlet_float(x->x_obj.ob_outlet, x->x_f);
+}
+
+static void change_float(t_change *x, t_float f)
+{
+ if (f != x->x_f)
+ {
+ x->x_f = f;
+ outlet_float(x->x_obj.ob_outlet, x->x_f);
+ }
+}
+
+static void change_set(t_change *x, t_float f)
+{
+ x->x_f = f;
+}
+
+void change_setup(void)
+{
+ change_class = class_new(gensym("change"), (t_newmethod)change_new, 0,
+ sizeof(t_change), 0, A_DEFFLOAT, 0);
+ class_addbang(change_class, change_bang);
+ class_addfloat(change_class, change_float);
+ class_addmethod(change_class, (t_method)change_set, gensym("set"),
+ A_DEFFLOAT, 0);
+}
+
+/* -------------------- value ------------------------------ */
+
+static t_class *value_class, *vcommon_class;
+
+typedef struct vcommon
+{
+ t_pd c_pd;
+ int c_refcount;
+ t_float c_f;
+} t_vcommon;
+
+typedef struct _value
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+ t_float *x_floatstar;
+} t_value;
+
+ /* get a pointer to a named floating-point variable. The variable
+ belongs to a "vcommon" object, which is created if necessary. */
+t_float *value_get(t_symbol *s)
+{
+ t_vcommon *c = (t_vcommon *)pd_findbyclass(s, vcommon_class);
+ if (!c)
+ {
+ c = (t_vcommon *)pd_new(vcommon_class);
+ c->c_f = 0;
+ c->c_refcount = 0;
+ pd_bind(&c->c_pd, s);
+ }
+ c->c_refcount++;
+ return (&c->c_f);
+}
+
+ /* release a variable. This only frees the "vcommon" resource when the
+ last interested party releases it. */
+void value_release(t_symbol *s)
+{
+ t_vcommon *c = (t_vcommon *)pd_findbyclass(s, vcommon_class);
+ if (c)
+ {
+ if (!--c->c_refcount)
+ {
+ pd_unbind(&c->c_pd, s);
+ pd_free(&c->c_pd);
+ }
+ }
+ else bug("value_release");
+}
+
+/*
+ * value_getfloat -- obtain the float value of a "value" object
+ * return 0 on success, 1 otherwise
+ */
+int
+value_getfloat(t_symbol *s, t_float *f)
+{
+ t_vcommon *c = (t_vcommon *)pd_findbyclass(s, vcommon_class);
+ if (!c)
+ return (1);
+ *f = c->c_f;
+ return (0);
+}
+
+/*
+ * value_setfloat -- set the float value of a "value" object
+ * return 0 on success, 1 otherwise
+ */
+int
+value_setfloat(t_symbol *s, t_float f)
+{
+ t_vcommon *c = (t_vcommon *)pd_findbyclass(s, vcommon_class);
+ if (!c)
+ return (1);
+ c->c_f = f;
+ return (0);
+}
+
+static void *value_new(t_symbol *s)
+{
+ t_value *x = (t_value *)pd_new(value_class);
+ x->x_sym = s;
+ x->x_floatstar = value_get(s);
+ outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+static void value_bang(t_value *x)
+{
+ outlet_float(x->x_obj.ob_outlet, *x->x_floatstar);
+}
+
+static void value_float(t_value *x, t_float f)
+{
+ *x->x_floatstar = f;
+}
+
+static void value_ff(t_value *x)
+{
+ value_release(x->x_sym);
+}
+
+static void value_setup(void)
+{
+ value_class = class_new(gensym("value"), (t_newmethod)value_new,
+ (t_method)value_ff,
+ sizeof(t_value), 0, A_DEFSYM, 0);
+ class_addcreator((t_newmethod)value_new, gensym("v"), A_DEFSYM, 0);
+ class_addbang(value_class, value_bang);
+ class_addfloat(value_class, value_float);
+ vcommon_class = class_new(gensym("value"), 0, 0,
+ sizeof(t_vcommon), CLASS_PD, 0);
+}
+
+/* -------------- overall setup routine for this file ----------------- */
+
+void x_connective_setup(void)
+{
+ pdint_setup();
+ pdfloat_setup();
+ pdsymbol_setup();
+ bang_setup();
+ send_setup();
+ receive_setup();
+ select_setup();
+ route_setup();
+ pack_setup();
+ unpack_setup();
+ trigger_setup();
+ spigot_setup();
+ moses_setup();
+ until_setup();
+ makefilename_setup();
+ swap_setup();
+ change_setup();
+ value_setup();
+}
diff --git a/pd/src/x_gui.c b/pd/src/x_gui.c
new file mode 100644
index 00000000..03e1b0dd
--- /dev/null
+++ b/pd/src/x_gui.c
@@ -0,0 +1,377 @@
+/* Copyright (c) 1997-2000 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* dialogs. LATER, deal with the situation where the object goes
+away before the panel does... */
+
+#include "m_pd.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef UNIX
+#include <unistd.h>
+#endif
+
+/* --------------------- graphics responder ---------------- */
+
+/* make one of these if you want to put up a dialog window but want to be
+protected from getting deleted and then having the dialog call you back. In
+this design the calling object doesn't have to keep the address of the dialog
+window around; instead we keep a list of all open dialogs. Any object that
+might have dialogs, when it is deleted, simply checks down the dialog window
+list and breaks off any dialogs that might later have sent messages to it.
+Only when the dialog window itself closes do we delete the gfxstub object. */
+
+static t_class *gfxstub_class;
+
+typedef struct _gfxstub
+{
+ t_pd x_pd;
+ t_pd *x_owner;
+ void *x_key;
+ t_symbol *x_sym;
+ struct _gfxstub *x_next;
+} t_gfxstub;
+
+static t_gfxstub *gfxstub_list;
+
+ /* create a new one. the "key" is an address by which the owner
+ will identify it later; if the owner only wants one dialog, this
+ could just be a pointer to the owner itself. The string "cmd"
+ is a TK command to create the dialog, with "%s" embedded in
+ it so we can provide a name by which the GUI can send us back
+ messages; e.g., "pdtk_canvas_dofont %s 10". */
+
+void gfxstub_new(t_pd *owner, void *key, const char *cmd)
+{
+ char buf[MAXPDSTRING];
+ char namebuf[80];
+ t_gfxstub *x;
+ t_symbol *s;
+ /* if any exists with matching key, no need to make a
+ new one; just tell tk to send it front. */
+ for (x = gfxstub_list; x; x = x->x_next)
+ {
+ if (x->x_key == key)
+ {
+ sys_vgui("raise .gfxstub%x\n", x);
+ sys_vgui("focus .gfxstub%x\n", x);
+ return;
+ }
+ }
+ if (strlen(cmd) + 84 > MAXPDSTRING)
+ return;
+ x = (t_gfxstub *)pd_new(gfxstub_class);
+ sprintf(namebuf, ".gfxstub%x", (t_int)x);
+
+ s = gensym(namebuf);
+ pd_bind(&x->x_pd, s);
+ x->x_owner = owner;
+ x->x_sym = s;
+ x->x_key = key;
+ x->x_next = gfxstub_list;
+ gfxstub_list = x;
+ sprintf(buf, cmd, s->s_name);
+ sys_gui(buf);
+}
+
+static void gfxstub_offlist(t_gfxstub *x)
+{
+ t_gfxstub *y1, *y2;
+ if (gfxstub_list == x)
+ gfxstub_list = x->x_next;
+ else for (y1 = gfxstub_list; y2 = y1->x_next; y1 = y2)
+ if (y2 == x)
+ {
+ y1->x_next = y2->x_next;
+ break;
+ }
+}
+
+ /* if the owner disappears, we still may have to stay around until our
+ dialog window signs off. Anyway we can now tell the GUI to destroy the
+ window. */
+void gfxstub_deleteforkey(void *key)
+{
+ t_gfxstub *y;
+ int didit = 1;
+ while (didit)
+ {
+ didit = 0;
+ for (y = gfxstub_list; y; y = y->x_next)
+ {
+ if (y->x_key == key)
+ {
+ sys_vgui("destroy .gfxstub%x\n", y);
+ y->x_owner = 0;
+ gfxstub_offlist(y);
+ didit = 1;
+ break;
+ }
+ }
+ }
+}
+
+/* --------- pd messages for gfxstub (these come from the GUI) ---------- */
+
+ /* "cancel" to request that we close the dialog window. */
+static void gfxstub_cancel(t_gfxstub *x)
+{
+ gfxstub_deleteforkey(x->x_key);
+}
+
+ /* "signoff" comes from the GUI to say the dialog window closed. */
+static void gfxstub_signoff(t_gfxstub *x)
+{
+ gfxstub_offlist(x);
+ pd_free(&x->x_pd);
+}
+
+static t_binbuf *gfxstub_binbuf;
+
+ /* a series of "data" messages rebuilds a scalar */
+static void gfxstub_data(t_gfxstub *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if (!gfxstub_binbuf)
+ gfxstub_binbuf = binbuf_new();
+ binbuf_add(gfxstub_binbuf, argc, argv);
+ binbuf_addsemi(gfxstub_binbuf);
+}
+ /* the "end" message terminates rebuilding the scalar */
+static void gfxstub_end(t_gfxstub *x)
+{
+ canvas_dataproperties((t_canvas *)x->x_owner,
+ (t_scalar *)x->x_key, gfxstub_binbuf);
+ binbuf_free(gfxstub_binbuf);
+ gfxstub_binbuf = 0;
+}
+
+ /* anything else is a message from the dialog window to the owner;
+ just forward it. */
+static void gfxstub_anything(t_gfxstub *x, t_symbol *s, int argc, t_atom *argv)
+{
+ if (x->x_owner)
+ pd_typedmess(x->x_owner, s, argc, argv);
+}
+
+static void gfxstub_free(t_gfxstub *x)
+{
+ pd_unbind(&x->x_pd, x->x_sym);
+}
+
+static void gfxstub_setup(void)
+{
+ gfxstub_class = class_new(gensym("gfxstub"), (t_newmethod)gfxstub_new,
+ (t_method)gfxstub_free,
+ sizeof(t_gfxstub), CLASS_PD, 0);
+ class_addanything(gfxstub_class, gfxstub_anything);
+ class_addmethod(gfxstub_class, (t_method)gfxstub_signoff,
+ gensym("signoff"), 0);
+ class_addmethod(gfxstub_class, (t_method)gfxstub_data,
+ gensym("data"), A_GIMME, 0);
+ class_addmethod(gfxstub_class, (t_method)gfxstub_end,
+ gensym("end"), 0);
+ class_addmethod(gfxstub_class, (t_method)gfxstub_cancel,
+ gensym("cancel"), 0);
+}
+
+/* -------------------------- openpanel ------------------------------ */
+
+static t_class *openpanel_class;
+
+typedef struct _openpanel
+{
+ t_object x_obj;
+ t_symbol *x_s;
+} t_openpanel;
+
+static void *openpanel_new(void)
+{
+ char buf[50];
+ t_openpanel *x = (t_openpanel *)pd_new(openpanel_class);
+ sprintf(buf, "d%x", (t_int)x);
+ x->x_s = gensym(buf);
+ pd_bind(&x->x_obj.ob_pd, x->x_s);
+ outlet_new(&x->x_obj, &s_symbol);
+ return (x);
+}
+
+static void openpanel_bang(t_openpanel *x)
+{
+ sys_vgui("pdtk_openpanel %s\n", x->x_s->s_name);
+}
+
+static void openpanel_symbol(t_openpanel *x, t_symbol *s)
+{
+ outlet_symbol(x->x_obj.ob_outlet, s);
+}
+
+static void openpanel_free(t_openpanel *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, x->x_s);
+}
+
+static void openpanel_setup(void)
+{
+ openpanel_class = class_new(gensym("openpanel"),
+ (t_newmethod)openpanel_new, (t_method)openpanel_free,
+ sizeof(t_openpanel), 0, A_DEFFLOAT, 0);
+ class_addbang(openpanel_class, openpanel_bang);
+ class_addsymbol(openpanel_class, openpanel_symbol);
+}
+
+/* -------------------------- savepanel ------------------------------ */
+
+static t_class *savepanel_class;
+
+typedef struct _savepanel
+{
+ t_object x_obj;
+ t_symbol *x_s;
+} t_savepanel;
+
+static void *savepanel_new(void)
+{
+ char buf[50];
+ t_savepanel *x = (t_savepanel *)pd_new(savepanel_class);
+ sprintf(buf, "d%x", (t_int)x);
+ x->x_s = gensym(buf);
+ pd_bind(&x->x_obj.ob_pd, x->x_s);
+ outlet_new(&x->x_obj, &s_symbol);
+ return (x);
+}
+
+static void savepanel_bang(t_savepanel *x)
+{
+ sys_vgui("pdtk_savepanel %s\n", x->x_s->s_name);
+}
+
+static void savepanel_symbol(t_savepanel *x, t_symbol *s)
+{
+ outlet_symbol(x->x_obj.ob_outlet, s);
+}
+
+static void savepanel_free(t_savepanel *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, x->x_s);
+}
+
+static void savepanel_setup(void)
+{
+ savepanel_class = class_new(gensym("savepanel"),
+ (t_newmethod)savepanel_new, (t_method)savepanel_free,
+ sizeof(t_savepanel), 0, A_DEFFLOAT, 0);
+ class_addbang(savepanel_class, savepanel_bang);
+ class_addsymbol(savepanel_class, savepanel_symbol);
+}
+
+/* ---------------------- key and its relatives ------------------ */
+
+static t_symbol *key_sym, *keyup_sym, *keyname_sym;
+static t_class *key_class, *keyup_class, *keyname_class;
+
+typedef struct _key
+{
+ t_object x_obj;
+} t_key;
+
+static void *key_new( void)
+{
+ t_key *x = (t_key *)pd_new(key_class);
+ outlet_new(&x->x_obj, &s_float);
+ pd_bind(&x->x_obj.ob_pd, key_sym);
+ return (x);
+}
+
+static void key_float(t_key *x, t_floatarg f)
+{
+ outlet_float(x->x_obj.ob_outlet, f);
+}
+
+static void key_free(t_key *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, key_sym);
+}
+
+typedef struct _keyup
+{
+ t_object x_obj;
+} t_keyup;
+
+static void *keyup_new( void)
+{
+ t_keyup *x = (t_keyup *)pd_new(keyup_class);
+ outlet_new(&x->x_obj, &s_float);
+ pd_bind(&x->x_obj.ob_pd, keyup_sym);
+ return (x);
+}
+
+static void keyup_float(t_keyup *x, t_floatarg f)
+{
+ outlet_float(x->x_obj.ob_outlet, f);
+}
+
+static void keyup_free(t_keyup *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, keyup_sym);
+}
+
+typedef struct _keyname
+{
+ t_object x_obj;
+ t_outlet *x_outlet1;
+ t_outlet *x_outlet2;
+} t_keyname;
+
+static void *keyname_new( void)
+{
+ t_keyname *x = (t_keyname *)pd_new(keyname_class);
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet2 = outlet_new(&x->x_obj, &s_symbol);
+ pd_bind(&x->x_obj.ob_pd, keyname_sym);
+ return (x);
+}
+
+static void keyname_list(t_keyname *x, t_symbol *s, int ac, t_atom *av)
+{
+ outlet_symbol(x->x_outlet2, atom_getsymbolarg(1, ac, av));
+ outlet_float(x->x_outlet1, atom_getfloatarg(0, ac, av));
+}
+
+static void keyname_free(t_keyname *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, keyname_sym);
+}
+
+static void key_setup(void)
+{
+ key_class = class_new(gensym("key"),
+ (t_newmethod)key_new, (t_method)key_free,
+ sizeof(t_key), CLASS_NOINLET, 0);
+ class_addfloat(key_class, key_float);
+ key_sym = gensym("#key");
+
+ keyup_class = class_new(gensym("keyup"),
+ (t_newmethod)keyup_new, (t_method)keyup_free,
+ sizeof(t_keyup), CLASS_NOINLET, 0);
+ class_addfloat(keyup_class, keyup_float);
+ keyup_sym = gensym("#keyup");
+ class_sethelpsymbol(keyup_class, gensym("key"));
+
+ keyname_class = class_new(gensym("keyname"),
+ (t_newmethod)keyname_new, (t_method)keyname_free,
+ sizeof(t_keyname), CLASS_NOINLET, 0);
+ class_addlist(keyname_class, keyname_list);
+ keyname_sym = gensym("#keyname");
+ class_sethelpsymbol(keyname_class, gensym("key"));
+}
+
+/* -------------------------- setup routine ------------------------------ */
+
+void x_gui_setup(void)
+{
+ gfxstub_setup();
+ openpanel_setup();
+ savepanel_setup();
+ key_setup();
+}
diff --git a/pd/src/x_interface.c b/pd/src/x_interface.c
new file mode 100644
index 00000000..068b0bbc
--- /dev/null
+++ b/pd/src/x_interface.c
@@ -0,0 +1,78 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* interface objects */
+
+#include "m_pd.h"
+
+/* -------------------------- print ------------------------------ */
+static t_class *print_class;
+
+typedef struct _print
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+} t_print;
+
+static void *print_new(t_symbol *s)
+{
+ t_print *x = (t_print *)pd_new(print_class);
+ if (*s->s_name) x->x_sym = s;
+ else x->x_sym = gensym("print");
+ return (x);
+}
+
+static void print_bang(t_print *x)
+{
+ post("%s: bang", x->x_sym->s_name);
+}
+
+static void print_pointer(t_print *x, t_gpointer *gp)
+{
+ post("%s: (gpointer)", x->x_sym->s_name);
+}
+
+static void print_float(t_print *x, t_float f)
+{
+ post("%s: %g", x->x_sym->s_name, f);
+}
+
+static void print_list(t_print *x, t_symbol *s, int argc, t_atom *argv)
+{
+ int i;
+ char buf[80];
+ if (argc && argv->a_type != A_SYMBOL) startpost("%s:", x->x_sym->s_name);
+ else startpost("%s: %s", x->x_sym->s_name,
+ (argc > 1 ? s_list.s_name : (argc == 1 ? s_symbol.s_name :
+ s_bang.s_name)));
+ postatom(argc, argv);
+ endpost();
+}
+
+static void print_anything(t_print *x, t_symbol *s, int argc, t_atom *argv)
+{
+ int i;
+ char buf[80];
+ startpost("%s: %s", x->x_sym->s_name, s->s_name);
+ postatom(argc, argv);
+ endpost();
+}
+
+static void print_setup(void)
+{
+ print_class = class_new(gensym("print"), (t_newmethod)print_new, 0,
+ sizeof(t_print), 0, A_DEFSYM, 0);
+ class_addbang(print_class, print_bang);
+ class_addfloat(print_class, print_float);
+ class_addpointer(print_class, print_pointer);
+ class_addlist(print_class, print_list);
+ class_addanything(print_class, print_anything);
+}
+
+
+
+void x_interface_setup(void)
+{
+ print_setup();
+}
diff --git a/pd/src/x_midi.c b/pd/src/x_midi.c
new file mode 100644
index 00000000..f7d6529f
--- /dev/null
+++ b/pd/src/x_midi.c
@@ -0,0 +1,1314 @@
+/* Copyright (c) 1997-2001 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. */
+
+/* MIDI. */
+
+#include "m_pd.h"
+void outmidi_noteon(int portno, int channel, int pitch, int velo);
+void outmidi_controlchange(int portno, int channel, int ctlno, int value);
+void outmidi_programchange(int portno, int channel, int value);
+void outmidi_pitchbend(int portno, int channel, int value);
+void outmidi_aftertouch(int portno, int channel, int value);
+void outmidi_polyaftertouch(int portno, int channel, int pitch, int value);
+void outmidi_mclk(int portno);
+
+/* ----------------------- midiin and sysexin ------------------------- */
+
+static t_symbol *midiin_sym, *sysexin_sym;
+
+static t_class *midiin_class, *sysexin_class;
+
+typedef struct _midiin
+{
+ t_object x_obj;
+ t_outlet *x_outlet1;
+ t_outlet *x_outlet2;
+} t_midiin;
+
+static void *midiin_new( void)
+{
+ t_midiin *x = (t_midiin *)pd_new(midiin_class);
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
+ pd_bind(&x->x_obj.ob_pd, midiin_sym);
+#ifndef __linux__
+ pd_error(x, "midiin: works under Linux only");
+#endif
+ return (x);
+}
+
+static void midiin_list(t_midiin *x, t_symbol *s, int ac, t_atom *av)
+{
+ outlet_float(x->x_outlet2, atom_getfloatarg(1, ac, av) + 1);
+ outlet_float(x->x_outlet1, atom_getfloatarg(0, ac, av));
+}
+
+static void midiin_free(t_midiin *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, midiin_sym);
+}
+
+static void *sysexin_new( void)
+{
+ t_midiin *x = (t_midiin *)pd_new(sysexin_class);
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
+ pd_bind(&x->x_obj.ob_pd, sysexin_sym);
+#ifndef __linux__
+ pd_error(x, "sysexin: works under Linux only");
+#endif
+ return (x);
+}
+
+static void sysexin_free(t_midiin *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, sysexin_sym);
+}
+
+static void midiin_setup(void)
+{
+ midiin_class = class_new(gensym("midiin"), (t_newmethod)midiin_new,
+ (t_method)midiin_free, sizeof(t_midiin),
+ CLASS_NOINLET, A_DEFFLOAT, 0);
+ class_addlist(midiin_class, midiin_list);
+ class_sethelpsymbol(midiin_class, gensym("midi"));
+ midiin_sym = gensym("#midiin");
+
+ sysexin_class = class_new(gensym("sysexin"), (t_newmethod)sysexin_new,
+ (t_method)sysexin_free, sizeof(t_midiin),
+ CLASS_NOINLET, A_DEFFLOAT, 0);
+ class_addlist(sysexin_class, midiin_list);
+ class_sethelpsymbol(sysexin_class, gensym("midi"));
+ sysexin_sym = gensym("#sysexin");
+}
+
+void inmidi_byte(int portno, int byte)
+{
+ static int sysex;
+ t_atom at[2];
+ if (byte == 0xf0)
+ sysex |= (1 << portno);
+ if (sysexin_sym->s_thing && (sysex & (1 << portno)))
+ {
+ SETFLOAT(at, byte);
+ SETFLOAT(at+1, portno + 1);
+ pd_list(sysexin_sym->s_thing, 0, 2, at);
+ }
+ if (byte == 0xf7)
+ sysex &= (~(1 << portno));
+
+ if (midiin_sym->s_thing)
+ {
+ SETFLOAT(at, byte);
+ SETFLOAT(at+1, portno + 1);
+ pd_list(midiin_sym->s_thing, 0, 2, at);
+ }
+}
+
+/* ----------------------- notein ------------------------- */
+
+static t_symbol *notein_sym;
+
+static t_class *notein_class;
+
+typedef struct _notein
+{
+ t_object x_obj;
+ t_float x_channel;
+ t_outlet *x_outlet1;
+ t_outlet *x_outlet2;
+ t_outlet *x_outlet3;
+} t_notein;
+
+static void *notein_new(t_floatarg f)
+{
+ t_notein *x = (t_notein *)pd_new(notein_class);
+ x->x_channel = f;
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
+ if (f == 0) x->x_outlet3 = outlet_new(&x->x_obj, &s_float);
+ pd_bind(&x->x_obj.ob_pd, notein_sym);
+ return (x);
+}
+
+static void notein_list(t_notein *x, t_symbol *s, int argc, t_atom *argv)
+{
+ float pitch = atom_getfloatarg(0, argc, argv);
+ float velo = atom_getfloatarg(1, argc, argv);
+ float channel = atom_getfloatarg(2, argc, argv);
+ if (x->x_channel != 0)
+ {
+ if (channel != x->x_channel) return;
+ outlet_float(x->x_outlet2, velo);
+ outlet_float(x->x_outlet1, pitch);
+ }
+ else
+ {
+ outlet_float(x->x_outlet3, channel);
+ outlet_float(x->x_outlet2, velo);
+ outlet_float(x->x_outlet1, pitch);
+ }
+}
+
+static void notein_free(t_notein *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, notein_sym);
+}
+
+static void notein_setup(void)
+{
+ notein_class = class_new(gensym("notein"), (t_newmethod)notein_new,
+ (t_method)notein_free, sizeof(t_notein), CLASS_NOINLET, A_DEFFLOAT, 0);
+ class_addlist(notein_class, notein_list);
+ class_sethelpsymbol(notein_class, gensym("midi"));
+ notein_sym = gensym("#notein");
+}
+
+void inmidi_noteon(int portno, int channel, int pitch, int velo)
+{
+ if (notein_sym->s_thing)
+ {
+ t_atom at[3];
+ SETFLOAT(at, pitch);
+ SETFLOAT(at+1, velo);
+ SETFLOAT(at+2, (channel + (portno << 4) + 1));
+ pd_list(notein_sym->s_thing, &s_list, 3, at);
+ }
+}
+
+/* ----------------------- ctlin ------------------------- */
+
+static t_symbol *ctlin_sym;
+
+static t_class *ctlin_class;
+
+typedef struct _ctlin
+{
+ t_object x_obj;
+ t_float x_channel;
+ t_float x_ctlno;
+ t_outlet *x_outlet1;
+ t_outlet *x_outlet2;
+ t_outlet *x_outlet3;
+} t_ctlin;
+
+static void *ctlin_new(t_symbol *s, int argc, t_atom *argv)
+{
+ int ctlno, channel;
+ t_ctlin *x = (t_ctlin *)pd_new(ctlin_class);
+ if (!argc) ctlno = -1;
+ else ctlno = atom_getfloatarg(0, argc, argv);
+ channel = atom_getfloatarg(1, argc, argv);
+ x->x_channel = channel;
+ x->x_ctlno = ctlno;
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
+ if (!channel)
+ {
+ if (x->x_ctlno < 0) x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet3 = outlet_new(&x->x_obj, &s_float);
+ }
+ pd_bind(&x->x_obj.ob_pd, ctlin_sym);
+ return (x);
+}
+
+static void ctlin_list(t_ctlin *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_float ctlnumber = atom_getfloatarg(0, argc, argv);
+ t_float value = atom_getfloatarg(1, argc, argv);
+ t_float channel = atom_getfloatarg(2, argc, argv);
+ if (x->x_ctlno >= 0 && x->x_ctlno != ctlnumber) return;
+ if (x->x_channel > 0 && x->x_channel != channel) return;
+ if (x->x_channel == 0) outlet_float(x->x_outlet3, channel);
+ if (x->x_ctlno < 0) outlet_float(x->x_outlet2, ctlnumber);
+ outlet_float(x->x_outlet1, value);
+}
+
+static void ctlin_free(t_ctlin *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, ctlin_sym);
+}
+
+static void ctlin_setup(void)
+{
+ ctlin_class = class_new(gensym("ctlin"), (t_newmethod)ctlin_new,
+ (t_method)ctlin_free, sizeof(t_ctlin),
+ CLASS_NOINLET, A_GIMME, 0);
+ class_addlist(ctlin_class, ctlin_list);
+ class_sethelpsymbol(ctlin_class, gensym("midi"));
+ ctlin_sym = gensym("#ctlin");
+}
+
+void inmidi_controlchange(int portno, int channel, int ctlnumber, int value)
+{
+ if (ctlin_sym->s_thing)
+ {
+ t_atom at[3];
+ SETFLOAT(at, ctlnumber);
+ SETFLOAT(at+1, value);
+ SETFLOAT(at+2, (channel + (portno << 4) + 1));
+ pd_list(ctlin_sym->s_thing, &s_list, 3, at);
+ }
+}
+
+/* ----------------------- pgmin ------------------------- */
+
+static t_symbol *pgmin_sym;
+
+static t_class *pgmin_class;
+
+typedef struct _pgmin
+{
+ t_object x_obj;
+ t_float x_channel;
+ t_outlet *x_outlet1;
+ t_outlet *x_outlet2;
+} t_pgmin;
+
+static void *pgmin_new(t_floatarg f)
+{
+ t_pgmin *x = (t_pgmin *)pd_new(pgmin_class);
+ x->x_channel = f;
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
+ if (f == 0) x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
+ pd_bind(&x->x_obj.ob_pd, pgmin_sym);
+ return (x);
+}
+
+static void pgmin_list(t_pgmin *x, t_symbol *s, int argc, t_atom *argv)
+{
+ float value = atom_getfloatarg(0, argc, argv);
+ float channel = atom_getfloatarg(1, argc, argv);
+ if (x->x_channel != 0)
+ {
+ if (channel != x->x_channel) return;
+ outlet_float(x->x_outlet1, value);
+ }
+ else
+ {
+ outlet_float(x->x_outlet2, channel);
+ outlet_float(x->x_outlet1, value);
+ }
+}
+
+static void pgmin_free(t_pgmin *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, pgmin_sym);
+}
+
+static void pgmin_setup(void)
+{
+ pgmin_class = class_new(gensym("pgmin"), (t_newmethod)pgmin_new,
+ (t_method)pgmin_free, sizeof(t_pgmin),
+ CLASS_NOINLET, A_DEFFLOAT, 0);
+ class_addlist(pgmin_class, pgmin_list);
+ class_sethelpsymbol(pgmin_class, gensym("midi"));
+ pgmin_sym = gensym("#pgmin");
+}
+
+void inmidi_programchange(int portno, int channel, int value)
+{
+ if (pgmin_sym->s_thing)
+ {
+ t_atom at[2];
+ SETFLOAT(at, value + 1);
+ SETFLOAT(at+1, (channel + (portno << 4) + 1));
+ pd_list(pgmin_sym->s_thing, &s_list, 2, at);
+ }
+}
+
+/* ----------------------- bendin ------------------------- */
+
+static t_symbol *bendin_sym;
+
+static t_class *bendin_class;
+
+typedef struct _bendin
+{
+ t_object x_obj;
+ t_float x_channel;
+ t_outlet *x_outlet1;
+ t_outlet *x_outlet2;
+} t_bendin;
+
+static void *bendin_new(t_floatarg f)
+{
+ t_bendin *x = (t_bendin *)pd_new(bendin_class);
+ x->x_channel = f;
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
+ if (f == 0) x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
+ pd_bind(&x->x_obj.ob_pd, bendin_sym);
+ return (x);
+}
+
+static void bendin_list(t_bendin *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_float value = atom_getfloatarg(0, argc, argv);
+ t_float channel = atom_getfloatarg(1, argc, argv);
+ if (x->x_channel != 0)
+ {
+ if (channel != x->x_channel) return;
+ outlet_float(x->x_outlet1, value);
+ }
+ else
+ {
+ outlet_float(x->x_outlet2, channel);
+ outlet_float(x->x_outlet1, value);
+ }
+}
+
+static void bendin_free(t_bendin *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, bendin_sym);
+}
+
+static void bendin_setup(void)
+{
+ bendin_class = class_new(gensym("bendin"), (t_newmethod)bendin_new,
+ (t_method)bendin_free, sizeof(t_bendin), CLASS_NOINLET, A_DEFFLOAT, 0);
+ class_addlist(bendin_class, bendin_list);
+ class_sethelpsymbol(bendin_class, gensym("midi"));
+ bendin_sym = gensym("#bendin");
+}
+
+void inmidi_pitchbend(int portno, int channel, int value)
+{
+ if (bendin_sym->s_thing)
+ {
+ t_atom at[2];
+ SETFLOAT(at, value);
+ SETFLOAT(at+1, (channel + (portno << 4) + 1));
+ pd_list(bendin_sym->s_thing, &s_list, 2, at);
+ }
+}
+
+/* ----------------------- touchin ------------------------- */
+
+static t_symbol *touchin_sym;
+
+static t_class *touchin_class;
+
+typedef struct _touchin
+{
+ t_object x_obj;
+ t_float x_channel;
+ t_outlet *x_outlet1;
+ t_outlet *x_outlet2;
+} t_touchin;
+
+static void *touchin_new(t_floatarg f)
+{
+ t_touchin *x = (t_touchin *)pd_new(touchin_class);
+ x->x_channel = f;
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
+ if (f == 0) x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
+ pd_bind(&x->x_obj.ob_pd, touchin_sym);
+ return (x);
+}
+
+static void touchin_list(t_touchin *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_float value = atom_getfloatarg(0, argc, argv);
+ t_float channel = atom_getfloatarg(1, argc, argv);
+ if (x->x_channel)
+ {
+ if (channel != x->x_channel) return;
+ outlet_float(x->x_outlet1, value);
+ }
+ else
+ {
+ outlet_float(x->x_outlet2, channel);
+ outlet_float(x->x_outlet1, value);
+ }
+}
+
+static void touchin_free(t_touchin *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, touchin_sym);
+}
+
+static void touchin_setup(void)
+{
+ touchin_class = class_new(gensym("touchin"), (t_newmethod)touchin_new,
+ (t_method)touchin_free, sizeof(t_touchin),
+ CLASS_NOINLET, A_DEFFLOAT, 0);
+ class_addlist(touchin_class, touchin_list);
+ class_sethelpsymbol(touchin_class, gensym("midi"));
+ touchin_sym = gensym("#touchin");
+}
+
+void inmidi_aftertouch(int portno, int channel, int value)
+{
+ if (touchin_sym->s_thing)
+ {
+ t_atom at[2];
+ SETFLOAT(at, value);
+ SETFLOAT(at+1, (channel + (portno << 4) + 1));
+ pd_list(touchin_sym->s_thing, &s_list, 2, at);
+ }
+}
+
+/* ----------------------- polytouchin ------------------------- */
+
+static t_symbol *polytouchin_sym;
+
+static t_class *polytouchin_class;
+
+typedef struct _polytouchin
+{
+ t_object x_obj;
+ t_float x_channel;
+ t_outlet *x_outlet1;
+ t_outlet *x_outlet2;
+ t_outlet *x_outlet3;
+} t_polytouchin;
+
+static void *polytouchin_new(t_floatarg f)
+{
+ t_polytouchin *x = (t_polytouchin *)pd_new(polytouchin_class);
+ x->x_channel = f;
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
+ if (f == 0) x->x_outlet3 = outlet_new(&x->x_obj, &s_float);
+ pd_bind(&x->x_obj.ob_pd, polytouchin_sym);
+ return (x);
+}
+
+static void polytouchin_list(t_polytouchin *x, t_symbol *s, int argc,
+ t_atom *argv)
+{
+ t_float pitch = atom_getfloatarg(0, argc, argv);
+ t_float value = atom_getfloatarg(1, argc, argv);
+ t_float channel = atom_getfloatarg(2, argc, argv);
+ if (x->x_channel != 0)
+ {
+ if (channel != x->x_channel) return;
+ outlet_float(x->x_outlet2, pitch);
+ outlet_float(x->x_outlet1, value);
+ }
+ else
+ {
+ outlet_float(x->x_outlet3, channel);
+ outlet_float(x->x_outlet2, pitch);
+ outlet_float(x->x_outlet1, value);
+ }
+}
+
+static void polytouchin_free(t_polytouchin *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, polytouchin_sym);
+}
+
+static void polytouchin_setup(void)
+{
+ polytouchin_class = class_new(gensym("polytouchin"),
+ (t_newmethod)polytouchin_new, (t_method)polytouchin_free,
+ sizeof(t_polytouchin), CLASS_NOINLET, A_DEFFLOAT, 0);
+ class_addlist(polytouchin_class, polytouchin_list);
+ class_sethelpsymbol(polytouchin_class, gensym("midi"));
+ polytouchin_sym = gensym("#polytouchin");
+}
+
+void inmidi_polyaftertouch(int portno, int channel, int pitch, int value)
+{
+ if (polytouchin_sym->s_thing)
+ {
+ t_atom at[3];
+ SETFLOAT(at, pitch);
+ SETFLOAT(at+1, value);
+ SETFLOAT(at+2, (channel + (portno << 4) + 1));
+ pd_list(polytouchin_sym->s_thing, &s_list, 3, at);
+ }
+}
+
+/*----------------------- midiclkin--(midi F8 message )---------------------*/
+static t_symbol *midiclkin_sym;
+
+static t_class *midiclkin_class;
+
+
+typedef struct _midiclkin
+{
+ t_object x_obj;
+ t_outlet *x_outlet1;
+ t_outlet *x_outlet2;
+} t_midiclkin;
+
+static void *midiclkin_new(t_floatarg f)
+{
+ t_midiclkin *x = (t_midiclkin *)pd_new(midiclkin_class);
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
+ pd_bind(&x->x_obj.ob_pd, midiclkin_sym);
+ return (x);
+}
+
+static void midiclkin_list(t_midiclkin *x, t_symbol *s, int argc, t_atom *argv)
+{
+ float value = atom_getfloatarg(0, argc, argv);
+ float count = atom_getfloatarg(1, argc, argv);
+ outlet_float(x->x_outlet2, count);
+ outlet_float(x->x_outlet1, value);
+}
+
+static void midiclkin_free(t_midiclkin *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, midiclkin_sym);
+}
+
+static void midiclkin_setup(void)
+{
+ midiclkin_class = class_new(gensym("midiclkin"),
+ (t_newmethod)midiclkin_new, (t_method)midiclkin_free,
+ sizeof(t_midiclkin), CLASS_NOINLET, A_DEFFLOAT, 0);
+ class_addlist(midiclkin_class, midiclkin_list);
+ class_sethelpsymbol(midiclkin_class, gensym("midi"));
+ midiclkin_sym = gensym("#midiclkin");
+}
+
+void inmidi_clk(double timing)
+{
+
+ static float prev = 0;
+ static float count = 0;
+ float cur,diff;
+
+ if (midiclkin_sym->s_thing)
+ {
+ t_atom at[2];
+ diff =timing - prev;
+ count++;
+
+ if (count == 3)
+ { /* 24 count per quoter note */
+ SETFLOAT(at, 1 );
+ count = 0;
+ }
+ else SETFLOAT(at, 0);
+
+ SETFLOAT(at+1, diff);
+ pd_list(midiclkin_sym->s_thing, &s_list, 2, at);
+ prev = timing;
+ }
+}
+
+/*----------midirealtimein (midi FA,FB,FC,FF message )-----------------*/
+
+static t_symbol *midirealtimein_sym;
+
+static t_class *midirealtimein_class;
+
+typedef struct _midirealtimein
+{
+ t_object x_obj;
+ t_outlet *x_outlet1;
+ t_outlet *x_outlet2;
+} t_midirealtimein;
+
+static void *midirealtimein_new( void)
+{
+ t_midirealtimein *x = (t_midirealtimein *)pd_new(midirealtimein_class);
+ x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
+ pd_bind(&x->x_obj.ob_pd, midirealtimein_sym);
+#ifndef NT
+ pd_error(x, "midirealtimein: works under NT only");
+#endif
+ return (x);
+}
+
+static void midirealtimein_list(t_midirealtimein *x, t_symbol *s,
+ int argc, t_atom *argv)
+{
+ float portno = atom_getfloatarg(0, argc, argv);
+ float byte = atom_getfloatarg(1, argc, argv);
+
+ outlet_float(x->x_outlet2, portno);
+ outlet_float(x->x_outlet1, byte);
+}
+
+static void midirealtimein_free(t_midirealtimein *x)
+{
+ pd_unbind(&x->x_obj.ob_pd, midirealtimein_sym);
+}
+
+static void midirealtimein_setup(void)
+{
+ midirealtimein_class = class_new(gensym("midirealtimein"),
+ (t_newmethod)midirealtimein_new, (t_method)midirealtimein_free,
+ sizeof(t_midirealtimein), CLASS_NOINLET, A_DEFFLOAT, 0);
+ class_addlist(midirealtimein_class, midirealtimein_list);
+ class_sethelpsymbol(midirealtimein_class, gensym("midi"));
+ midirealtimein_sym = gensym("#midirealtimein");
+}
+
+void inmidi_realtimein(int portno, int SysMsg)
+{
+ if (midirealtimein_sym->s_thing)
+ {
+ t_atom at[2];
+ SETFLOAT(at, portno);
+ SETFLOAT(at+1, SysMsg);
+ pd_list(midirealtimein_sym->s_thing, &s_list, 1, at);
+ }
+}
+
+/* -------------------------- midiout -------------------------- */
+
+static t_class *midiout_class;
+
+void sys_putmidibyte(int portno, int byte);
+
+typedef struct _midiout
+{
+ t_object x_obj;
+ t_float x_portno;
+} t_midiout;
+
+static void *midiout_new(t_floatarg portno)
+{
+ t_midiout *x = (t_midiout *)pd_new(midiout_class);
+ if (portno <= 0) portno = 1;
+ x->x_portno = portno;
+ floatinlet_new(&x->x_obj, &x->x_portno);
+#ifdef __irix__
+ post("midiout: unimplemented in IRIX");
+#endif
+ return (x);
+}
+
+static void midiout_float(t_midiout *x, t_floatarg f)
+{
+ sys_putmidibyte(x->x_portno - 1, f);
+}
+
+static void midiout_setup(void)
+{
+ midiout_class = class_new(gensym("midiout"), (t_newmethod)midiout_new, 0,
+ sizeof(t_midiout), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addfloat(midiout_class, midiout_float);
+ class_sethelpsymbol(midiout_class, gensym("midi"));
+}
+
+/* -------------------------- noteout -------------------------- */
+
+static t_class *noteout_class;
+
+typedef struct _noteout
+{
+ t_object x_obj;
+ t_float x_velo;
+ t_float x_channel;
+} t_noteout;
+
+static void *noteout_new(t_floatarg channel)
+{
+ t_noteout *x = (t_noteout *)pd_new(noteout_class);
+ x->x_velo = 0;
+ if (channel < 1) channel = 1;
+ x->x_channel = channel;
+ floatinlet_new(&x->x_obj, &x->x_velo);
+ floatinlet_new(&x->x_obj, &x->x_channel);
+ return (x);
+}
+
+static void noteout_float(t_noteout *x, t_float f)
+{
+ int binchan = x->x_channel - 1;
+ if (binchan < 0)
+ binchan = 0;
+ outmidi_noteon((binchan >> 4),
+ (binchan & 15), (int)f, (int)x->x_velo);
+}
+
+static void noteout_setup(void)
+{
+ noteout_class = class_new(gensym("noteout"), (t_newmethod)noteout_new, 0,
+ sizeof(t_noteout), 0, A_DEFFLOAT, 0);
+ class_addfloat(noteout_class, noteout_float);
+ class_sethelpsymbol(noteout_class, gensym("midi"));
+}
+
+
+/* -------------------------- ctlout -------------------------- */
+
+static t_class *ctlout_class;
+
+typedef struct _ctlout
+{
+ t_object x_obj;
+ t_float x_ctl;
+ t_float x_channel;
+} t_ctlout;
+
+static void *ctlout_new(t_floatarg ctl, t_floatarg channel)
+{
+ t_ctlout *x = (t_ctlout *)pd_new(ctlout_class);
+ x->x_ctl = ctl;
+ if (channel <= 0) channel = 1;
+ x->x_channel = channel;
+ floatinlet_new(&x->x_obj, &x->x_ctl);
+ floatinlet_new(&x->x_obj, &x->x_channel);
+ return (x);
+}
+
+static void ctlout_float(t_ctlout *x, t_float f)
+{
+ int binchan = x->x_channel - 1;
+ if (binchan < 0)
+ binchan = 0;
+ outmidi_controlchange((binchan >> 4),
+ (binchan & 15), (int)(x->x_ctl), (int)f);
+}
+
+static void ctlout_setup(void)
+{
+ ctlout_class = class_new(gensym("ctlout"), (t_newmethod)ctlout_new, 0,
+ sizeof(t_ctlout), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addfloat(ctlout_class, ctlout_float);
+ class_sethelpsymbol(ctlout_class, gensym("midi"));
+}
+
+
+/* -------------------------- pgmout -------------------------- */
+
+static t_class *pgmout_class;
+
+typedef struct _pgmout
+{
+ t_object x_obj;
+ t_float x_channel;
+} t_pgmout;
+
+static void *pgmout_new(t_floatarg channel)
+{
+ t_pgmout *x = (t_pgmout *)pd_new(pgmout_class);
+ if (channel <= 0) channel = 1;
+ x->x_channel = channel;
+ floatinlet_new(&x->x_obj, &x->x_channel);
+ return (x);
+}
+
+static void pgmout_float(t_pgmout *x, t_floatarg f)
+{
+ int binchan = x->x_channel - 1;
+ int n = f - 1;
+ if (binchan < 0)
+ binchan = 0;
+ if (n < 0) n = 0;
+ else if (n > 127) n = 127;
+ outmidi_programchange((binchan >> 4),
+ (binchan & 15), n);
+}
+
+static void pgmout_setup(void)
+{
+ pgmout_class = class_new(gensym("pgmout"), (t_newmethod)pgmout_new, 0,
+ sizeof(t_pgmout), 0, A_DEFFLOAT, 0);
+ class_addfloat(pgmout_class, pgmout_float);
+ class_sethelpsymbol(pgmout_class, gensym("midi"));
+}
+
+
+/* -------------------------- bendout -------------------------- */
+
+static t_class *bendout_class;
+
+typedef struct _bendout
+{
+ t_object x_obj;
+ t_float x_channel;
+} t_bendout;
+
+static void *bendout_new(t_floatarg channel)
+{
+ t_bendout *x = (t_bendout *)pd_new(bendout_class);
+ if (channel <= 0) channel = 1;
+ x->x_channel = channel;
+ floatinlet_new(&x->x_obj, &x->x_channel);
+ return (x);
+}
+
+static void bendout_float(t_bendout *x, t_float f)
+{
+ int binchan = x->x_channel - 1;
+ int n = (int)f + 8192;
+ if (binchan < 0)
+ binchan = 0;
+ outmidi_pitchbend((binchan >> 4), (binchan & 15), n);
+}
+
+static void bendout_setup(void)
+{
+ bendout_class = class_new(gensym("bendout"), (t_newmethod)bendout_new, 0,
+ sizeof(t_bendout), 0, A_DEFFLOAT, 0);
+ class_addfloat(bendout_class, bendout_float);
+ class_sethelpsymbol(bendout_class, gensym("midi"));
+}
+
+/* -------------------------- touch -------------------------- */
+
+static t_class *touchout_class;
+
+typedef struct _touchout
+{
+ t_object x_obj;
+ t_float x_channel;
+} t_touchout;
+
+static void *touchout_new(t_floatarg channel)
+{
+ t_touchout *x = (t_touchout *)pd_new(touchout_class);
+ if (channel <= 0) channel = 1;
+ x->x_channel = channel;
+ floatinlet_new(&x->x_obj, &x->x_channel);
+ return (x);
+}
+
+static void touchout_float(t_touchout *x, t_float f)
+{
+ int binchan = x->x_channel - 1;
+ if (binchan < 0)
+ binchan = 0;
+ outmidi_aftertouch((binchan >> 4), (binchan & 15), (int)f);
+}
+
+static void touchout_setup(void)
+{
+ touchout_class = class_new(gensym("touchout"), (t_newmethod)touchout_new, 0,
+ sizeof(t_touchout), 0, A_DEFFLOAT, 0);
+ class_addfloat(touchout_class, touchout_float);
+ class_sethelpsymbol(touchout_class, gensym("midi"));
+}
+
+/* -------------------------- polytouch -------------------------- */
+
+static t_class *polytouchout_class;
+
+typedef struct _polytouchout
+{
+ t_object x_obj;
+ t_float x_channel;
+ t_float x_pitch;
+} t_polytouchout;
+
+static void *polytouchout_new(t_floatarg channel)
+{
+ t_polytouchout *x = (t_polytouchout *)pd_new(polytouchout_class);
+ if (channel <= 0) channel = 1;
+ x->x_channel = channel;
+ x->x_pitch = 0;
+ floatinlet_new(&x->x_obj, &x->x_pitch);
+ floatinlet_new(&x->x_obj, &x->x_channel);
+ return (x);
+}
+
+static void polytouchout_float(t_polytouchout *x, t_float n)
+{
+ int binchan = x->x_channel - 1;
+ if (binchan < 0)
+ binchan = 0;
+ outmidi_polyaftertouch((binchan >> 4), (binchan & 15), x->x_pitch, n);
+}
+
+static void polytouchout_setup(void)
+{
+ polytouchout_class = class_new(gensym("polytouchout"),
+ (t_newmethod)polytouchout_new, 0,
+ sizeof(t_polytouchout), 0, A_DEFFLOAT, 0);
+ class_addfloat(polytouchout_class, polytouchout_float);
+ class_sethelpsymbol(polytouchout_class, gensym("midi"));
+}
+
+/* -------------------------- makenote -------------------------- */
+
+static t_class *makenote_class;
+
+typedef struct _hang
+{
+ t_clock *h_clock;
+ struct _hang *h_next;
+ t_float h_pitch;
+ struct _makenote *h_owner;
+} t_hang;
+
+typedef struct _makenote
+{
+ t_object x_obj;
+ t_float x_velo;
+ t_float x_dur;
+ t_outlet *x_pitchout;
+ t_outlet *x_velout;
+ t_hang *x_hang;
+} t_makenote;
+
+static void *makenote_new(t_floatarg velo, t_floatarg dur)
+{
+ t_makenote *x = (t_makenote *)pd_new(makenote_class);
+ x->x_velo = velo;
+ x->x_dur = dur;
+ floatinlet_new(&x->x_obj, &x->x_velo);
+ floatinlet_new(&x->x_obj, &x->x_dur);
+ x->x_pitchout = outlet_new(&x->x_obj, &s_float);
+ x->x_velout = outlet_new(&x->x_obj, &s_float);
+ x->x_hang = 0;
+ return (x);
+}
+
+static void makenote_tick(t_hang *hang)
+{
+ t_makenote *x = hang->h_owner;
+ t_hang *h2, *h3;
+ outlet_float(x->x_velout, 0);
+ outlet_float(x->x_pitchout, hang->h_pitch);
+ if (x->x_hang == hang) x->x_hang = hang->h_next;
+ else for (h2 = x->x_hang; h3 = h2->h_next; h2 = h3)
+ {
+ if (h3 == hang)
+ {
+ h2->h_next = h3->h_next;
+ break;
+ }
+ }
+ clock_free(hang->h_clock);
+ freebytes(hang, sizeof(*hang));
+}
+
+static void makenote_float(t_makenote *x, t_float f)
+{
+ t_hang *hang;
+ if (!x->x_velo) return;
+ outlet_float(x->x_velout, x->x_velo);
+ outlet_float(x->x_pitchout, f);
+ hang = (t_hang *)getbytes(sizeof *hang);
+ hang->h_next = x->x_hang;
+ x->x_hang = hang;
+ hang->h_pitch = f;
+ hang->h_owner = x;
+ hang->h_clock = clock_new(hang, (t_method)makenote_tick);
+ clock_delay(hang->h_clock, (x->x_dur >= 0 ? x->x_dur : 0));
+}
+
+static void makenote_stop(t_makenote *x)
+{
+ t_hang *hang;
+ while (hang = x->x_hang)
+ {
+ outlet_float(x->x_velout, 0);
+ outlet_float(x->x_pitchout, hang->h_pitch);
+ x->x_hang = hang->h_next;
+ clock_free(hang->h_clock);
+ freebytes(hang, sizeof(*hang));
+ }
+}
+
+static void makenote_clear(t_makenote *x)
+{
+ t_hang *hang;
+ while (hang = x->x_hang)
+ {
+ x->x_hang = hang->h_next;
+ clock_free(hang->h_clock);
+ freebytes(hang, sizeof(*hang));
+ }
+}
+
+static void makenote_setup(void)
+{
+ makenote_class = class_new(gensym("makenote"),
+ (t_newmethod)makenote_new, (t_method)makenote_clear,
+ sizeof(t_makenote), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addfloat(makenote_class, makenote_float);
+ class_addmethod(makenote_class, (t_method)makenote_stop, gensym("stop"),
+ 0);
+ class_addmethod(makenote_class, (t_method)makenote_clear, gensym("clear"),
+ 0);
+}
+
+/* -------------------------- stripnote -------------------------- */
+
+static t_class *stripnote_class;
+
+typedef struct _stripnote
+{
+ t_object x_obj;
+ t_float x_velo;
+ t_outlet *x_pitchout;
+ t_outlet *x_velout;
+} t_stripnote;
+
+static void *stripnote_new(void )
+{
+ t_stripnote *x = (t_stripnote *)pd_new(stripnote_class);
+ floatinlet_new(&x->x_obj, &x->x_velo);
+ x->x_pitchout = outlet_new(&x->x_obj, &s_float);
+ x->x_velout = outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+static void stripnote_float(t_stripnote *x, t_float f)
+{
+ t_hang *hang;
+ if (!x->x_velo) return;
+ outlet_float(x->x_velout, x->x_velo);
+ outlet_float(x->x_pitchout, f);
+}
+
+static void stripnote_setup(void)
+{
+ stripnote_class = class_new(gensym("stripnote"),
+ (t_newmethod)stripnote_new, 0, sizeof(t_stripnote), 0, 0);
+ class_addfloat(stripnote_class, stripnote_float);
+}
+
+/* -------------------------- poly -------------------------- */
+
+static t_class *poly_class;
+
+typedef struct voice
+{
+ float v_pitch;
+ int v_used;
+ unsigned long v_serial;
+} t_voice;
+
+typedef struct poly
+{
+ t_object x_obj;
+ int x_n;
+ t_voice *x_vec;
+ float x_vel;
+ t_outlet *x_pitchout;
+ t_outlet *x_velout;
+ unsigned long x_serial;
+ int x_steal;
+} t_poly;
+
+static void *poly_new(float fnvoice, float fsteal)
+{
+ int i, n = fnvoice;
+ t_poly *x = (t_poly *)pd_new(poly_class);
+ t_voice *v;
+ if (n < 1) n = 1;
+ x->x_n = n;
+ x->x_vec = (t_voice *)getbytes(n * sizeof(*x->x_vec));
+ for (v = x->x_vec, i = n; i--; v++)
+ v->v_pitch = v->v_used = v->v_serial = 0;
+ x->x_vel = 0;
+ x->x_steal = (fsteal != 0);
+ floatinlet_new(&x->x_obj, &x->x_vel);
+ outlet_new(&x->x_obj, &s_float);
+ x->x_pitchout = outlet_new(&x->x_obj, &s_float);
+ x->x_velout = outlet_new(&x->x_obj, &s_float);
+ x->x_serial = 0;
+ return (x);
+}
+
+static void poly_float(t_poly *x, t_float f)
+{
+ int i;
+ t_voice *v;
+ t_voice *firston, *firstoff;
+ unsigned int serialon, serialoff, onindex = 0, offindex = 0;
+ if (x->x_vel > 0)
+ {
+ /* note on. Look for a vacant voice */
+ for (v = x->x_vec, i = 0, firston = firstoff = 0,
+ serialon = serialoff = 0xffffffff; i < x->x_n; v++, i++)
+ {
+ if (v->v_used && v->v_serial < serialon)
+ firston = v, serialon = v->v_serial, onindex = i;
+ else if (!v->v_used && v->v_serial < serialoff)
+ firstoff = v, serialoff = v->v_serial, offindex = i;
+ }
+ if (firstoff)
+ {
+ outlet_float(x->x_velout, x->x_vel);
+ outlet_float(x->x_pitchout, firstoff->v_pitch = f);
+ outlet_float(x->x_obj.ob_outlet, offindex+1);
+ firstoff->v_used = 1;
+ firstoff->v_serial = x->x_serial++;
+ }
+ /* if none, steal one */
+ else if (firston && x->x_steal)
+ {
+ outlet_float(x->x_velout, 0);
+ outlet_float(x->x_pitchout, firston->v_pitch);
+ outlet_float(x->x_obj.ob_outlet, onindex+1);
+ outlet_float(x->x_velout, x->x_vel);
+ outlet_float(x->x_pitchout, firston->v_pitch = f);
+ outlet_float(x->x_obj.ob_outlet, onindex+1);
+ firston->v_serial = x->x_serial++;
+ }
+ }
+ else /* note off. Turn off oldest match */
+ {
+ for (v = x->x_vec, i = 0, firston = 0, serialon = 0xffffffff;
+ i < x->x_n; v++, i++)
+ if (v->v_used && v->v_pitch == f && v->v_serial < serialon)
+ firston = v, serialon = v->v_serial, onindex = i;
+ if (firston)
+ {
+ firston->v_used = 0;
+ firston->v_serial = x->x_serial++;
+ outlet_float(x->x_velout, 0);
+ outlet_float(x->x_pitchout, firston->v_pitch);
+ outlet_float(x->x_obj.ob_outlet, onindex+1);
+ }
+ }
+}
+
+static void poly_stop(t_poly *x)
+{
+ int i;
+ t_voice *v;
+ for (i = 0, v = x->x_vec; i < x->x_n; i++, v++)
+ if (v->v_used)
+ {
+ outlet_float(x->x_velout, 0L);
+ outlet_float(x->x_pitchout, v->v_pitch);
+ outlet_float(x->x_obj.ob_outlet, i+1);
+ v->v_used = 0;
+ v->v_serial = x->x_serial++;
+ }
+}
+
+static void poly_clear(t_poly *x)
+{
+ int i;
+ t_voice *v;
+ for (v = x->x_vec, i = x->x_n; i--; v++) v->v_used = v->v_serial = 0;
+}
+
+static void poly_free(t_poly *x)
+{
+ freebytes(x->x_vec, x->x_n * sizeof (*x->x_vec));
+}
+
+static void poly_setup(void)
+{
+ poly_class = class_new(gensym("poly"),
+ (t_newmethod)poly_new, (t_method)poly_clear,
+ sizeof(t_poly), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addfloat(poly_class, poly_float);
+ class_addmethod(poly_class, (t_method)poly_stop, gensym("stop"), 0);
+ class_addmethod(poly_class, (t_method)poly_clear, gensym("clear"), 0);
+}
+
+/* -------------------------- bag -------------------------- */
+
+static t_class *bag_class;
+
+typedef struct _bagelem
+{
+ struct _bagelem *e_next;
+ t_float e_value;
+} t_bagelem;
+
+typedef struct _bag
+{
+ t_object x_obj;
+ t_float x_velo;
+ t_bagelem *x_first;
+} t_bag;
+
+static void *bag_new(void )
+{
+ t_bag *x = (t_bag *)pd_new(bag_class);
+ x->x_velo = 0;
+ floatinlet_new(&x->x_obj, &x->x_velo);
+ outlet_new(&x->x_obj, &s_float);
+ x->x_first = 0;
+ return (x);
+}
+
+static void bag_float(t_bag *x, t_float f)
+{
+ t_bagelem *bagelem, *e2, *e3;
+ if (x->x_velo != 0)
+ {
+ bagelem = (t_bagelem *)getbytes(sizeof *bagelem);
+ bagelem->e_next = 0;
+ bagelem->e_value = f;
+ if (!x->x_first) x->x_first = bagelem;
+ else /* LATER replace with a faster algorithm */
+ {
+ for (e2 = x->x_first; e3 = e2->e_next; e2 = e3)
+ ;
+ e2->e_next = bagelem;
+ }
+ }
+ else
+ {
+ if (!x->x_first) return;
+ if (x->x_first->e_value == f)
+ {
+ bagelem = x->x_first;
+ x->x_first = x->x_first->e_next;
+ freebytes(bagelem, sizeof(*bagelem));
+ return;
+ }
+ for (e2 = x->x_first; e3 = e2->e_next; e2 = e3)
+ if (e3->e_value == f)
+ {
+ e2->e_next = e3->e_next;
+ freebytes(e3, sizeof(*e3));
+ return;
+ }
+ }
+}
+
+static void bag_flush(t_bag *x)
+{
+ t_bagelem *bagelem;
+ while (bagelem = x->x_first)
+ {
+ outlet_float(x->x_obj.ob_outlet, bagelem->e_value);
+ x->x_first = bagelem->e_next;
+ freebytes(bagelem, sizeof(*bagelem));
+ }
+}
+
+static void bag_clear(t_bag *x)
+{
+ t_bagelem *bagelem;
+ while (bagelem = x->x_first)
+ {
+ x->x_first = bagelem->e_next;
+ freebytes(bagelem, sizeof(*bagelem));
+ }
+}
+
+static void bag_setup(void)
+{
+ bag_class = class_new(gensym("bag"),
+ (t_newmethod)bag_new, (t_method)bag_clear,
+ sizeof(t_bag), 0, 0);
+ class_addfloat(bag_class, bag_float);
+ class_addmethod(bag_class, (t_method)bag_flush, gensym("flush"), 0);
+ class_addmethod(bag_class, (t_method)bag_clear, gensym("clear"), 0);
+}
+
+void x_midi_setup(void)
+{
+ midiin_setup();
+ midirealtimein_setup();
+ notein_setup();
+ ctlin_setup();
+ pgmin_setup();
+ bendin_setup();
+ touchin_setup();
+ polytouchin_setup();
+ midiclkin_setup();
+ midiout_setup();
+ noteout_setup();
+ ctlout_setup();
+ pgmout_setup();
+ bendout_setup();
+ touchout_setup();
+ polytouchout_setup();
+ makenote_setup();
+ stripnote_setup();
+ poly_setup();
+ bag_setup();
+}
diff --git a/pd/src/x_misc.c b/pd/src/x_misc.c
new file mode 100644
index 00000000..8ba5191f
--- /dev/null
+++ b/pd/src/x_misc.c
@@ -0,0 +1,319 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* misc. */
+
+#include "m_imp.h"
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef UNIX
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <sys/param.h>
+#endif
+#ifdef NT
+#include <wtypes.h>
+#include <time.h>
+#endif
+
+#if defined (MACOSX) || defined (__FreeBSD__)
+#define HZ CLK_TCK
+#endif
+
+/* -------------------------- random ------------------------------ */
+/* this is strictly homebrew and untested. */
+
+static t_class *random_class;
+
+typedef struct _random
+{
+ t_object x_obj;
+ t_float x_f;
+ unsigned int x_state;
+} t_random;
+
+
+static int makeseed(void)
+{
+ static unsigned int random_nextseed = 1489853723;
+ random_nextseed = random_nextseed * 435898247 + 938284287;
+ return (random_nextseed & 0x7fffffff);
+}
+
+static void *random_new(t_floatarg f)
+{
+ t_random *x = (t_random *)pd_new(random_class);
+ x->x_f = f;
+ x->x_state = makeseed();
+ floatinlet_new(&x->x_obj, &x->x_f);
+ outlet_new(&x->x_obj, &s_float);
+ return (x);
+}
+
+static void random_bang(t_random *x)
+{
+ int n = x->x_f, nval;
+ int range = (n < 1 ? 1 : n);
+ unsigned int randval = x->x_state;
+ x->x_state = randval = randval * 472940017 + 832416023;
+ nval = ((double)range) * ((double)randval)
+ * (1./4294967296.);
+ if (nval >= range) nval = range-1;
+ outlet_float(x->x_obj.ob_outlet, nval);
+}
+
+static void random_seed(t_random *x, float f, float glob)
+{
+ x->x_state = f;
+}
+
+static void random_setup(void)
+{
+ random_class = class_new(gensym("random"), (t_newmethod)random_new, 0,
+ sizeof(t_random), 0, A_DEFFLOAT, 0);
+ class_addbang(random_class, random_bang);
+ class_addmethod(random_class, (t_method)random_seed,
+ gensym("seed"), A_FLOAT, 0);
+}
+
+
+/* -------------------------- loadbang ------------------------------ */
+static t_class *loadbang_class;
+
+typedef struct _loadbang
+{
+ t_object x_obj;
+} t_loadbang;
+
+static void *loadbang_new(void)
+{
+ t_loadbang *x = (t_loadbang *)pd_new(loadbang_class);
+ outlet_new(&x->x_obj, &s_bang);
+ return (x);
+}
+
+static void loadbang_loadbang(t_loadbang *x)
+{
+ if (!sys_noloadbang)
+ outlet_bang(x->x_obj.ob_outlet);
+}
+
+static void loadbang_setup(void)
+{
+ loadbang_class = class_new(gensym("loadbang"), (t_newmethod)loadbang_new, 0,
+ sizeof(t_loadbang), 0, 0);
+ class_addmethod(loadbang_class, (t_method)loadbang_loadbang,
+ gensym("loadbang"), 0);
+}
+
+/* ------------- namecanvas (delete this later) --------------------- */
+static t_class *namecanvas_class;
+
+typedef struct _namecanvas
+{
+ t_object x_obj;
+ t_symbol *x_sym;
+ t_pd *x_owner;
+} t_namecanvas;
+
+static void *namecanvas_new(t_symbol *s)
+{
+ t_namecanvas *x = (t_namecanvas *)pd_new(namecanvas_class);
+ x->x_owner = (t_pd *)canvas_getcurrent();
+ x->x_sym = s;
+ if (*s->s_name) pd_bind(x->x_owner, s);
+ return (x);
+}
+
+static void namecanvas_free(t_namecanvas *x)
+{
+ if (*x->x_sym->s_name) pd_unbind(x->x_owner, x->x_sym);
+}
+
+static void namecanvas_setup(void)
+{
+ namecanvas_class = class_new(gensym("namecanvas"),
+ (t_newmethod)namecanvas_new, (t_method)namecanvas_free,
+ sizeof(t_namecanvas), CLASS_NOINLET, A_DEFSYM, 0);
+}
+
+/* ---------------serial ports (NT only -- hack) ------------------------- */
+#define MAXSERIAL 100
+
+static t_class *serial_class;
+
+typedef struct _serial
+{
+ t_object x_obj;
+ int x_portno;
+ int x_open;
+} t_serial;
+
+static void serial_float(t_serial *x, t_float f)
+{
+ int n = f;
+ char message[MAXSERIAL * 4 + 100];
+ if (!x->x_open)
+ {
+ sys_vgui("com%d_open\n", x->x_portno);
+ x->x_open = 1;
+ }
+ sprintf(message, "com%d_send \"\\%3.3o\"\n", x->x_portno, n);
+ sys_gui(message);
+}
+
+static void *serial_new(t_floatarg fportno)
+{
+ int portno = fportno;
+ t_serial *x = (t_serial *)pd_new(serial_class);
+ if (!portno) portno = 1;
+ x->x_portno = portno;
+ x->x_open = 0;
+ return (x);
+}
+
+static void serial_setup(void)
+{
+ serial_class = class_new(gensym("serial"), (t_newmethod)serial_new, 0,
+ sizeof(t_serial), 0, A_DEFFLOAT, 0);
+ class_addfloat(serial_class, serial_float);
+}
+
+/* -------------------------- cputime ------------------------------ */
+
+static t_class *cputime_class;
+
+typedef struct _cputime
+{
+ t_object x_obj;
+#ifdef UNIX
+ struct tms x_setcputime;
+#endif
+#ifdef NT
+ LARGE_INTEGER x_kerneltime;
+ LARGE_INTEGER x_usertime;
+ int x_warned;
+#endif
+} t_cputime;
+
+static void cputime_bang(t_cputime *x)
+{
+#ifdef UNIX
+ times(&x->x_setcputime);
+#endif
+#ifdef NT
+ FILETIME ignorethis, ignorethat;
+ BOOL retval;
+ retval = GetProcessTimes(GetCurrentProcess(), &ignorethis, &ignorethat,
+ (FILETIME *)&x->x_kerneltime, (FILETIME *)&x->x_usertime);
+ if (!retval)
+ {
+ if (!x->x_warned)
+ post("cputime is apparently not supported on your platform");
+ x->x_warned = 1;
+ x->x_kerneltime.QuadPart = 0;
+ x->x_usertime.QuadPart = 0;
+ }
+#endif
+}
+
+static void cputime_bang2(t_cputime *x)
+{
+#ifdef UNIX
+ float elapsedcpu;
+ struct tms newcputime;
+ times(&newcputime);
+ elapsedcpu = 1000 * (
+ newcputime.tms_utime + newcputime.tms_stime -
+ x->x_setcputime.tms_utime - x->x_setcputime.tms_stime) / HZ;
+ outlet_float(x->x_obj.ob_outlet, elapsedcpu);
+#endif
+#ifdef NT
+ float elapsedcpu;
+ FILETIME ignorethis, ignorethat;
+ LARGE_INTEGER usertime, kerneltime;
+ BOOL retval;
+
+ retval = GetProcessTimes(GetCurrentProcess(), &ignorethis, &ignorethat,
+ (FILETIME *)&kerneltime, (FILETIME *)&usertime);
+ if (retval)
+ elapsedcpu = 0.0001 *
+ ((kerneltime.QuadPart - x->x_kerneltime.QuadPart) +
+ (usertime.QuadPart - x->x_usertime.QuadPart));
+ else elapsedcpu = 0;
+ outlet_float(x->x_obj.ob_outlet, elapsedcpu);
+#endif
+}
+
+static void *cputime_new(void)
+{
+ t_cputime *x = (t_cputime *)pd_new(cputime_class);
+ outlet_new(&x->x_obj, gensym("float"));
+
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("bang"), gensym("bang2"));
+#ifdef NT
+ x->x_warned = 0;
+#endif
+ cputime_bang(x);
+ return (x);
+}
+
+static void cputime_setup(void)
+{
+ cputime_class = class_new(gensym("cputime"), (t_newmethod)cputime_new, 0,
+ sizeof(t_cputime), 0, 0);
+ class_addbang(cputime_class, cputime_bang);
+ class_addmethod(cputime_class, (t_method)cputime_bang2, gensym("bang2"), 0);
+}
+
+/* -------------------------- realtime ------------------------------ */
+
+static t_class *realtime_class;
+
+typedef struct _realtime
+{
+ t_object x_obj;
+ double x_setrealtime;
+} t_realtime;
+
+static void realtime_bang(t_realtime *x)
+{
+ x->x_setrealtime = sys_getrealtime();
+}
+
+static void realtime_bang2(t_realtime *x)
+{
+ outlet_float(x->x_obj.ob_outlet,
+ (sys_getrealtime() - x->x_setrealtime) * 1000.);
+}
+
+static void *realtime_new(void)
+{
+ t_realtime *x = (t_realtime *)pd_new(realtime_class);
+ outlet_new(&x->x_obj, gensym("float"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("bang"), gensym("bang2"));
+ realtime_bang(x);
+ return (x);
+}
+
+static void realtime_setup(void)
+{
+ realtime_class = class_new(gensym("realtime"), (t_newmethod)realtime_new, 0,
+ sizeof(t_realtime), 0, 0);
+ class_addbang(realtime_class, realtime_bang);
+ class_addmethod(realtime_class, (t_method)realtime_bang2, gensym("bang2"),
+ 0);
+}
+
+void x_misc_setup(void)
+{
+ random_setup();
+ loadbang_setup();
+ namecanvas_setup();
+ serial_setup();
+ cputime_setup();
+ realtime_setup();
+}
diff --git a/pd/src/x_net.c b/pd/src/x_net.c
new file mode 100644
index 00000000..d14538e7
--- /dev/null
+++ b/pd/src/x_net.c
@@ -0,0 +1,362 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* network */
+
+#include "m_imp.h"
+
+#include <sys/types.h>
+#include <string.h>
+#ifdef UNIX
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <stdio.h>
+#define SOCKET_ERROR -1
+#else
+#include <winsock.h>
+#endif
+
+static t_class *netsend_class;
+
+typedef struct _netsend
+{
+ t_object x_obj;
+ int x_fd;
+ int x_protocol;
+} t_netsend;
+
+static void *netsend_new(t_floatarg udpflag)
+{
+ t_netsend *x = (t_netsend *)pd_new(netsend_class);
+ outlet_new(&x->x_obj, &s_float);
+ x->x_fd = -1;
+ x->x_protocol = (udpflag != 0 ? SOCK_DGRAM : SOCK_STREAM);
+ return (x);
+}
+
+static void netsend_connect(t_netsend *x, t_symbol *hostname,
+ t_floatarg fportno)
+{
+ struct sockaddr_in server;
+ struct hostent *hp;
+ int sockfd;
+ int portno = fportno;
+ int intarg;
+ if (x->x_fd >= 0)
+ {
+ error("netsend_connect: already connected");
+ return;
+ }
+
+ /* 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;
+ }
+ /* connect socket using hostname provided in command line */
+ server.sin_family = AF_INET;
+ hp = gethostbyname(hostname->s_name);
+ if (hp == 0)
+ {
+ post("bad host?\n");
+ return;
+ }
+#if 0
+ intarg = 0;
+ if (setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF,
+ &intarg, sizeof(intarg)) < 0)
+ post("setsockopt (SO_RCVBUF) failed\n");
+#endif
+ /* for stream (TCP) sockets, specify "nodelay" */
+ if (x->x_protocol == SOCK_STREAM)
+ {
+ intarg = 1;
+ if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY,
+ &intarg, sizeof(intarg)) < 0)
+ post("setsockopt (TCP_NODELAY) failed\n");
+ }
+ 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. LATER make a separate thread to do this
+ because it might block */
+ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
+ {
+ sys_sockerror("connecting stream socket");
+ sys_closesocket(sockfd);
+ return;
+ }
+ x->x_fd = sockfd;
+ outlet_float(x->x_obj.ob_outlet, 1);
+}
+
+static void netsend_disconnect(t_netsend *x)
+{
+ if (x->x_fd >= 0)
+ {
+ sys_closesocket(x->x_fd);
+ x->x_fd = -1;
+ outlet_float(x->x_obj.ob_outlet, 0);
+ }
+}
+
+static void netsend_send(t_netsend *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("netsend blocked %d msec",
+ (int)(1000 * ((timeafter - timebefore) + pleasewarn)));
+ pleasewarn = 0;
+ lastwarntime = timeafter;
+ }
+ else if (late) pleasewarn += timeafter - timebefore;
+ }
+ if (res <= 0)
+ {
+ sys_sockerror("netsend");
+ netsend_disconnect(x);
+ break;
+ }
+ else
+ {
+ sent += res;
+ bp += res;
+ }
+ }
+ t_freebytes(buf, length);
+ binbuf_free(b);
+ }
+ else error("netsend: not connected");
+}
+
+static void netsend_free(t_netsend *x)
+{
+ netsend_disconnect(x);
+}
+
+static void netsend_setup(void)
+{
+ netsend_class = class_new(gensym("netsend"), (t_newmethod)netsend_new,
+ (t_method)netsend_free,
+ sizeof(t_netsend), 0, A_DEFFLOAT, 0);
+ class_addmethod(netsend_class, (t_method)netsend_connect,
+ gensym("connect"), A_SYMBOL, A_FLOAT, 0);
+ class_addmethod(netsend_class, (t_method)netsend_disconnect,
+ gensym("disconnect"), 0);
+ class_addmethod(netsend_class, (t_method)netsend_send, gensym("send"),
+ A_GIMME, 0);
+}
+
+/* ----------------------------- netreceive ------------------------- */
+
+static t_class *netreceive_class;
+
+typedef struct _netreceive
+{
+ t_object x_obj;
+ t_outlet *x_msgout;
+ t_outlet *x_connectout;
+ int x_connectsocket;
+ int x_nconnections;
+ int x_udp;
+} t_netreceive;
+
+static void netreceive_notify(t_netreceive *x)
+{
+ outlet_float(x->x_connectout, --x->x_nconnections);
+}
+
+static void netreceive_doit(void *z, t_binbuf *b)
+{
+ t_atom messbuf[1024];
+ t_netreceive *x = (t_netreceive *)z;
+ int msg, natom = binbuf_getnatom(b);
+ t_atom *at = binbuf_getvec(b);
+ 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 i;
+ for (i = msg; i < emsg; i++)
+ if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM)
+ {
+ pd_error(x, "netreceive: 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 netreceive_connectpoll(t_netreceive *x)
+{
+ int fd = accept(x->x_connectsocket, 0, 0);
+ if (fd < 0) post("netreceive: accept failed");
+ else
+ {
+ t_socketreceiver *y = socketreceiver_new((void *)x,
+ (t_socketnotifier)netreceive_notify,
+ (x->x_msgout ? netreceive_doit : 0), 0);
+ sys_addpollfn(fd, (t_fdpollfn)socketreceiver_read, y);
+ outlet_float(x->x_connectout, ++x->x_nconnections);
+ }
+}
+
+static void *netreceive_new(t_symbol *compatflag,
+ t_floatarg fportno, t_floatarg udpflag)
+{
+ t_netreceive *x;
+ struct sockaddr_in server;
+ int sockfd, portno = fportno, udp = (udpflag != 0);
+ int old = !strcmp(compatflag->s_name , "old");
+ int intarg;
+ /* create a socket */
+ sockfd = socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0);
+#if 0
+ fprintf(stderr, "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;
+
+#if 1
+ /* ask OS to allow another Pd to repoen this port after we close it. */
+ intarg = 1;
+ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
+ &intarg, sizeof(intarg)) < 0)
+ post("setsockopt (SO_REUSEADDR) failed\n");
+#endif
+#if 0
+ intarg = 0;
+ if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
+ &intarg, sizeof(intarg)) < 0)
+ post("setsockopt (SO_RCVBUF) failed\n");
+#endif
+ /* Stream (TCP) sockets are set NODELAY */
+ if (!udp)
+ {
+ intarg = 1;
+ if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY,
+ &intarg, sizeof(intarg)) < 0)
+ post("setsockopt (TCP_NODELAY) failed\n");
+ }
+ /* 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_netreceive *)pd_new(netreceive_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_socketreceiver *y = socketreceiver_new((void *)x,
+ (t_socketnotifier)netreceive_notify,
+ (x->x_msgout ? netreceive_doit : 0), 1);
+ sys_addpollfn(sockfd, (t_fdpollfn)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)netreceive_connectpoll, x);
+ x->x_connectout = outlet_new(&x->x_obj, &s_float);
+ }
+ }
+ x->x_connectsocket = sockfd;
+ x->x_nconnections = 0;
+ x->x_udp = udp;
+
+ return (x);
+}
+
+static void netreceive_free(t_netreceive *x)
+{
+ /* LATER make me clean up open connections */
+ if (x->x_connectsocket >= 0)
+ {
+ sys_rmpollfn(x->x_connectsocket);
+ sys_closesocket(x->x_connectsocket);
+ }
+}
+
+static void netreceive_setup(void)
+{
+ netreceive_class = class_new(gensym("netreceive"),
+ (t_newmethod)netreceive_new, (t_method)netreceive_free,
+ sizeof(t_netreceive), CLASS_NOINLET, A_DEFFLOAT, A_DEFFLOAT,
+ A_DEFSYM, 0);
+}
+
+void x_net_setup(void)
+{
+ netsend_setup();
+ netreceive_setup();
+}
+
diff --git a/pd/src/x_qlist.c b/pd/src/x_qlist.c
new file mode 100644
index 00000000..922cfe12
--- /dev/null
+++ b/pd/src/x_qlist.c
@@ -0,0 +1,345 @@
+/* Copyright (c) 1997-1999 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 "m_pd.h"
+#include <string.h>
+#ifdef UNIX
+#include <unistd.h>
+#endif
+#ifdef NT
+#include <io.h>
+#endif
+
+typedef struct _qlist
+{
+ t_object x_ob;
+ t_outlet *x_bangout;
+ void *x_binbuf;
+ int x_onset; /* playback position */
+ t_clock *x_clock;
+ float x_tempo;
+ double x_whenclockset;
+ float x_clockdelay;
+ t_symbol *x_dir;
+ t_canvas *x_canvas;
+ int x_reentered;
+} t_qlist;
+
+static void qlist_tick(t_qlist *x);
+
+static t_class *qlist_class;
+
+static void *qlist_new( void)
+{
+ t_symbol *name, *filename = 0;
+ t_qlist *x = (t_qlist *)pd_new(qlist_class);
+ x->x_binbuf = binbuf_new();
+ x->x_clock = clock_new(x, (t_method)qlist_tick);
+ outlet_new(&x->x_ob, &s_list);
+ x->x_bangout = outlet_new(&x->x_ob, &s_bang);
+ x->x_onset = 0x7fffffff;
+ x->x_tempo = 1;
+ x->x_whenclockset = 0;
+ x->x_clockdelay = 0;
+ x->x_canvas = canvas_getcurrent();
+ x->x_reentered = 0;
+ return (x);
+}
+
+static void qlist_rewind(t_qlist *x)
+{
+ x->x_onset = 0;
+ if (x->x_clock) clock_unset(x->x_clock);
+ x->x_whenclockset = 0;
+ x->x_reentered = 1;
+}
+
+static void qlist_donext(t_qlist *x, int drop, int automatic)
+{
+ t_pd *target = 0;
+ while (1)
+ {
+ int argc = binbuf_getnatom(x->x_binbuf),
+ count, onset = x->x_onset, onset2, wasreentered;
+ t_atom *argv = binbuf_getvec(x->x_binbuf);
+ t_atom *ap = argv + onset, *ap2;
+ if (onset >= argc) goto end;
+ while (ap->a_type == A_SEMI || ap->a_type == A_COMMA)
+ {
+ if (ap->a_type == A_SEMI) target = 0;
+ onset++, ap++;
+ if (onset >= argc) goto end;
+ }
+
+ if (!target && ap->a_type == A_FLOAT)
+ {
+ ap2 = ap + 1;
+ onset2 = onset + 1;
+ while (onset2 < argc && ap2->a_type == A_FLOAT)
+ onset2++, ap2++;
+ x->x_onset = onset2;
+ if (automatic)
+ {
+ clock_delay(x->x_clock,
+ x->x_clockdelay = ap->a_w.w_float * x->x_tempo);
+ x->x_whenclockset = clock_getsystime();
+ }
+ else outlet_list(x->x_ob.ob_outlet, 0, onset2-onset, ap);
+ return;
+ }
+ ap2 = ap + 1;
+ onset2 = onset + 1;
+ while (onset2 < argc &&
+ (ap2->a_type == A_FLOAT || ap2->a_type == A_SYMBOL))
+ onset2++, ap2++;
+ x->x_onset = onset2;
+ count = onset2 - onset;
+ if (!target)
+ {
+ if (ap->a_type != A_SYMBOL) continue;
+ else if (!(target = ap->a_w.w_symbol->s_thing))
+ {
+ error("qlist: %s: no such object", ap->a_w.w_symbol->s_name);
+ continue;
+ }
+ ap++;
+ onset++;
+ count--;
+ if (!count)
+ {
+ x->x_onset = onset2;
+ continue;
+ }
+ }
+ wasreentered = x->x_reentered;
+ x->x_reentered = 0;
+ if (!drop)
+ {
+ if (ap->a_type == A_FLOAT)
+ typedmess(target, &s_list, count, ap);
+ else if (ap->a_type == A_SYMBOL)
+ typedmess(target, ap->a_w.w_symbol, count-1, ap+1);
+ }
+ if (x->x_reentered)
+ return;
+ x->x_reentered = wasreentered;
+ } /* while (1); never falls through */
+
+end:
+ x->x_onset = 0x7fffffff;
+ outlet_bang(x->x_bangout);
+ x->x_whenclockset = 0;
+}
+
+static void qlist_next(t_qlist *x, t_floatarg drop)
+{
+ qlist_donext(x, drop != 0, 0);
+}
+
+static void qlist_bang(t_qlist *x)
+{
+ qlist_rewind(x);
+ qlist_donext(x, 0, 1);
+}
+
+static void qlist_tick(t_qlist *x)
+{
+ x->x_whenclockset = 0;
+ qlist_donext(x, 0, 1);
+}
+
+static void qlist_add(t_qlist *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_atom a;
+ SETSEMI(&a);
+ binbuf_add(x->x_binbuf, ac, av);
+ binbuf_add(x->x_binbuf, 1, &a);
+}
+
+static void qlist_add2(t_qlist *x, t_symbol *s, int ac, t_atom *av)
+{
+ binbuf_add(x->x_binbuf, ac, av);
+}
+
+static void qlist_clear(t_qlist *x)
+{
+ qlist_rewind(x);
+ binbuf_clear(x->x_binbuf);
+}
+
+static void qlist_set(t_qlist *x, t_symbol *s, int ac, t_atom *av)
+{
+ qlist_clear(x);
+ qlist_add(x, s, ac, av);
+}
+
+static void qlist_read(t_qlist *x, t_symbol *filename, t_symbol *format)
+{
+ int cr = 0;
+ if (!strcmp(format->s_name, "cr"))
+ cr = 1;
+ else if (*format->s_name)
+ error("qlist_read: unknown flag: %s", format->s_name);
+
+ if (binbuf_read_via_path(x->x_binbuf, filename->s_name,
+ canvas_getdir(x->x_canvas)->s_name, cr))
+ error("%s: read failed", filename->s_name);
+ x->x_onset = 0x7fffffff;
+ x->x_reentered = 1;
+}
+
+static void qlist_write(t_qlist *x, t_symbol *filename, t_symbol *format)
+{
+ int cr = 0;
+ char buf[MAXPDSTRING];
+ canvas_makefilename(x->x_canvas, filename->s_name,
+ buf, MAXPDSTRING);
+ if (!strcmp(format->s_name, "cr"))
+ cr = 1;
+ else if (*format->s_name)
+ error("qlist_read: unknown flag: %s", format->s_name);
+ if (binbuf_write(x->x_binbuf, buf, "", cr))
+ error("%s: write failed", filename->s_name);
+}
+
+static void qlist_print(t_qlist *x)
+{
+ post("--------- textfile or qlist contents: -----------");
+ binbuf_print(x->x_binbuf);
+}
+
+static void qlist_tempo(t_qlist *x, t_float f)
+{
+ float newtempo;
+ if (f < 1e-20) f = 1e-20;
+ else if (f > 1e20) f = 1e20;
+ newtempo = 1./f;
+ if (x->x_whenclockset != 0)
+ {
+ float elapsed = clock_gettimesince(x->x_whenclockset);
+ float left = x->x_clockdelay - elapsed;
+ if (left < 0) left = 0;
+ left *= newtempo / x->x_tempo;
+ clock_delay(x->x_clock, left);
+ }
+ x->x_tempo = newtempo;
+}
+
+static void qlist_free(t_qlist *x)
+{
+ binbuf_free(x->x_binbuf);
+ if (x->x_clock) clock_free(x->x_clock);
+}
+
+/* -------------------- textfile ------------------------------- */
+
+static t_class *textfile_class;
+typedef t_qlist t_textfile;
+
+static void *textfile_new( void)
+{
+ t_symbol *name, *filename = 0;
+ t_textfile *x = (t_textfile *)pd_new(textfile_class);
+ x->x_binbuf = binbuf_new();
+ outlet_new(&x->x_ob, &s_list);
+ x->x_bangout = outlet_new(&x->x_ob, &s_bang);
+ x->x_onset = 0x7fffffff;
+ x->x_reentered = 0;
+ x->x_tempo = 1;
+ x->x_whenclockset = 0;
+ x->x_clockdelay = 0;
+ x->x_clock = NULL;
+ x->x_canvas = canvas_getcurrent();
+ return (x);
+}
+
+static void textfile_bang(t_textfile *x)
+{
+ int argc = binbuf_getnatom(x->x_binbuf),
+ count, onset = x->x_onset, onset2;
+ t_atom *argv = binbuf_getvec(x->x_binbuf);
+ t_atom *ap = argv + onset, *ap2;
+ while (onset < argc &&
+ (ap->a_type == A_SEMI || ap->a_type == A_COMMA))
+ onset++, ap++;
+ onset2 = onset;
+ ap2 = ap;
+ while (onset2 < argc &&
+ (ap2->a_type != A_SEMI && ap2->a_type != A_COMMA))
+ onset2++, ap2++;
+ if (onset2 > onset)
+ {
+ x->x_onset = onset2;
+ if (ap->a_type == A_SYMBOL)
+ outlet_anything(x->x_ob.ob_outlet, ap->a_w.w_symbol,
+ onset2-onset-1, ap+1);
+ else outlet_list(x->x_ob.ob_outlet, 0, onset2-onset, ap);
+ }
+ else
+ {
+ x->x_onset = 0x7fffffff;
+ outlet_bang(x->x_bangout);
+ }
+}
+
+static void textfile_rewind(t_qlist *x)
+{
+ x->x_onset = 0;
+}
+
+static void textfile_free(t_textfile *x)
+{
+ binbuf_free(x->x_binbuf);
+}
+
+/* ---------------- global setup function -------------------- */
+
+void x_qlist_setup(void )
+{
+ qlist_class = class_new(gensym("qlist"), (t_newmethod)qlist_new,
+ (t_method)qlist_free, sizeof(t_qlist), 0, 0);
+ class_addmethod(qlist_class, (t_method)qlist_rewind, gensym("rewind"), 0);
+ class_addmethod(qlist_class, (t_method)qlist_next,
+ gensym("next"), A_DEFFLOAT, 0);
+ class_addmethod(qlist_class, (t_method)qlist_set, gensym("set"),
+ A_GIMME, 0);
+ class_addmethod(qlist_class, (t_method)qlist_clear, gensym("clear"), 0);
+ class_addmethod(qlist_class, (t_method)qlist_add, gensym("add"),
+ A_GIMME, 0);
+ class_addmethod(qlist_class, (t_method)qlist_add2, gensym("add2"),
+ A_GIMME, 0);
+ class_addmethod(qlist_class, (t_method)qlist_add, gensym("append"),
+ A_GIMME, 0);
+ class_addmethod(qlist_class, (t_method)qlist_read, gensym("read"),
+ A_SYMBOL, A_DEFSYM, 0);
+ class_addmethod(qlist_class, (t_method)qlist_write, gensym("write"),
+ A_SYMBOL, A_DEFSYM, 0);
+ class_addmethod(qlist_class, (t_method)qlist_print, gensym("print"),
+ A_DEFSYM, 0);
+ class_addmethod(qlist_class, (t_method)qlist_tempo,
+ gensym("tempo"), A_FLOAT, 0);
+ class_addbang(qlist_class, qlist_bang);
+
+ textfile_class = class_new(gensym("textfile"), (t_newmethod)textfile_new,
+ (t_method)textfile_free, sizeof(t_textfile), 0, 0);
+ class_addmethod(textfile_class, (t_method)textfile_rewind, gensym("rewind"),
+ 0);
+ class_addmethod(textfile_class, (t_method)qlist_set, gensym("set"),
+ A_GIMME, 0);
+ class_addmethod(textfile_class, (t_method)qlist_clear, gensym("clear"), 0);
+ class_addmethod(textfile_class, (t_method)qlist_add, gensym("add"),
+ A_GIMME, 0);
+ class_addmethod(textfile_class, (t_method)qlist_add2, gensym("add2"),
+ A_GIMME, 0);
+ class_addmethod(textfile_class, (t_method)qlist_add, gensym("append"),
+ A_GIMME, 0);
+ class_addmethod(textfile_class, (t_method)qlist_read, gensym("read"),
+ A_SYMBOL, A_DEFSYM, 0);
+ class_addmethod(textfile_class, (t_method)qlist_write, gensym("write"),
+ A_SYMBOL, A_DEFSYM, 0);
+ class_addmethod(textfile_class, (t_method)qlist_print, gensym("print"),
+ A_DEFSYM, 0);
+ class_addbang(textfile_class, textfile_bang);
+}
+
diff --git a/pd/src/x_time.c b/pd/src/x_time.c
new file mode 100644
index 00000000..2ea17fd3
--- /dev/null
+++ b/pd/src/x_time.c
@@ -0,0 +1,519 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* clock objects */
+
+#include "m_pd.h"
+#include <stdio.h>
+/* -------------------------- delay ------------------------------ */
+static t_class *delay_class;
+
+typedef struct _delay
+{
+ t_object x_obj;
+ t_clock *x_clock;
+ double x_deltime;
+} t_delay;
+
+static void delay_bang(t_delay *x)
+{
+ clock_delay(x->x_clock, x->x_deltime);
+}
+
+static void delay_stop(t_delay *x)
+{
+ clock_unset(x->x_clock);
+}
+
+static void delay_ft1(t_delay *x, t_floatarg g)
+{
+ if (g < 0) g = 0;
+ x->x_deltime = g;
+}
+
+static void delay_float(t_delay *x, t_float f)
+{
+ delay_ft1(x, f);
+ delay_bang(x);
+}
+
+static void delay_tick(t_delay *x)
+{
+ outlet_bang(x->x_obj.ob_outlet);
+}
+
+static void delay_free(t_delay *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void *delay_new(t_floatarg f)
+{
+ t_delay *x = (t_delay *)pd_new(delay_class);
+ delay_ft1(x, f);
+ x->x_clock = clock_new(x, (t_method)delay_tick);
+ outlet_new(&x->x_obj, gensym("bang"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
+ return (x);
+}
+
+static void delay_setup(void)
+{
+ delay_class = class_new(gensym("delay"), (t_newmethod)delay_new,
+ (t_method)delay_free, sizeof(t_delay), 0, A_DEFFLOAT, 0);
+ class_addcreator((t_newmethod)delay_new, gensym("del"), A_DEFFLOAT, 0);
+ class_addbang(delay_class, delay_bang);
+ class_addmethod(delay_class, (t_method)delay_stop, gensym("stop"), 0);
+ class_addmethod(delay_class, (t_method)delay_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addfloat(delay_class, (t_method)delay_float);
+}
+
+/* -------------------------- metro ------------------------------ */
+static t_class *metro_class;
+
+typedef struct _metro
+{
+ t_object x_obj;
+ t_clock *x_clock;
+ double x_deltime;
+ int x_hit;
+} t_metro;
+
+static void metro_tick(t_metro *x)
+{
+ x->x_hit = 0;
+ outlet_bang(x->x_obj.ob_outlet);
+ if (!x->x_hit) clock_delay(x->x_clock, x->x_deltime);
+}
+
+static void metro_float(t_metro *x, t_float f)
+{
+ if (f != 0) metro_tick(x);
+ else clock_unset(x->x_clock);
+ x->x_hit = 1;
+}
+
+static void metro_bang(t_metro *x)
+{
+ metro_float(x, 1);
+}
+
+static void metro_stop(t_metro *x)
+{
+ metro_float(x, 0);
+}
+
+static void metro_ft1(t_metro *x, t_floatarg g)
+{
+ if (g < 1) g = 1;
+ x->x_deltime = g;
+}
+
+static void metro_free(t_metro *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void *metro_new(t_floatarg f)
+{
+ t_metro *x = (t_metro *)pd_new(metro_class);
+ metro_ft1(x, f);
+ x->x_hit = 0;
+ x->x_clock = clock_new(x, (t_method)metro_tick);
+ outlet_new(&x->x_obj, gensym("bang"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
+ return (x);
+}
+
+static void metro_setup(void)
+{
+ metro_class = class_new(gensym("metro"), (t_newmethod)metro_new,
+ (t_method)metro_free, sizeof(t_metro), 0, A_DEFFLOAT, 0);
+ class_addbang(metro_class, metro_bang);
+ class_addmethod(metro_class, (t_method)metro_stop, gensym("stop"), 0);
+ class_addmethod(metro_class, (t_method)metro_ft1, gensym("ft1"),
+ A_FLOAT, 0);
+ class_addfloat(metro_class, (t_method)metro_float);
+}
+
+/* -------------------------- line ------------------------------ */
+static t_class *line_class;
+
+typedef struct _line
+{
+ 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;
+ double x_1overtimediff;
+ double x_in1val;
+} t_line;
+
+static void line_tick(t_line *x)
+{
+ 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
+ {
+ outlet_float(x->x_obj.ob_outlet,
+ x->x_setval + x->x_1overtimediff * (timenow - x->x_prevtime)
+ * (x->x_targetval - x->x_setval));
+ clock_delay(x->x_clock,
+ (x->x_grain > msectogo ? msectogo : x->x_grain));
+ }
+}
+
+static void line_float(t_line *x, t_float f)
+{
+ double timenow = clock_getsystime();
+ if (x->x_gotinlet && x->x_in1val > 0)
+ {
+ 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_targettime = clock_getsystimeafter(x->x_in1val);
+ x->x_targetval = f;
+ line_tick(x);
+ x->x_gotinlet = 0;
+ x->x_1overtimediff = 1./ (x->x_targettime - timenow);
+ clock_delay(x->x_clock,
+ (x->x_grain > x->x_in1val ? x->x_in1val : x->x_grain));
+
+ }
+ 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 line_ft1(t_line *x, t_floatarg g)
+{
+ x->x_in1val = g;
+ x->x_gotinlet = 1;
+}
+
+static void line_stop(t_line *x)
+{
+ x->x_targetval = x->x_setval;
+ clock_unset(x->x_clock);
+}
+
+static void line_free(t_line *x)
+{
+ clock_free(x->x_clock);
+}
+
+static void *line_new(t_floatarg f, t_floatarg grain)
+{
+ t_line *x = (t_line *)pd_new(line_class);
+ x->x_targetval = x->x_setval = f;
+ x->x_gotinlet = 0;
+ x->x_1overtimediff = 1;
+ x->x_clock = clock_new(x, (t_method)line_tick);
+ x->x_targettime = x->x_prevtime = clock_getsystime();
+ if (grain <= 0) grain = 20;
+ x->x_grain = grain;
+ outlet_new(&x->x_obj, gensym("float"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1"));
+ return (x);
+}
+
+static void line_setup(void)
+{
+ line_class = class_new(gensym("line"), (t_newmethod)line_new,
+ (t_method)line_free, sizeof(t_line), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(line_class, (t_method)line_ft1,
+ gensym("ft1"), A_FLOAT, 0);
+ class_addmethod(line_class, (t_method)line_stop,
+ gensym("stop"), 0);
+ class_addfloat(line_class, (t_method)line_float);
+}
+
+/* -------------------------- timer ------------------------------ */
+static t_class *timer_class;
+
+typedef struct _timer
+{
+ t_object x_obj;
+ double x_settime;
+} t_timer;
+
+static void timer_bang(t_timer *x)
+{
+ x->x_settime = clock_getsystime();
+}
+
+static void timer_bang2(t_timer *x)
+{
+ outlet_float(x->x_obj.ob_outlet, clock_gettimesince(x->x_settime));
+}
+
+static void *timer_new(t_floatarg f)
+{
+ t_timer *x = (t_timer *)pd_new(timer_class);
+ timer_bang(x);
+ outlet_new(&x->x_obj, gensym("float"));
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("bang"), gensym("bang2"));
+ return (x);
+}
+
+static void timer_setup(void)
+{
+ timer_class = class_new(gensym("timer"), (t_newmethod)timer_new, 0,
+ sizeof(t_timer), 0, A_DEFFLOAT, 0);
+ class_addbang(timer_class, timer_bang);
+ class_addmethod(timer_class, (t_method)timer_bang2, gensym("bang2"), 0);
+}
+
+
+/* -------------------------- pipe -------------------------- */
+
+static t_class *pipe_class;
+
+typedef struct _hang
+{
+ t_clock *h_clock;
+ struct _hang *h_next;
+ struct _pipe *h_owner;
+ t_gpointer *h_gp;
+ union word h_vec[1]; /* not the actual number. */
+} t_hang;
+
+typedef struct pipeout
+{
+ t_atom p_atom;
+ t_outlet *p_outlet;
+} t_pipeout;
+
+typedef struct _pipe
+{
+ t_object x_obj;
+ int x_n;
+ int x_nptr;
+ float x_deltime;
+ t_pipeout *x_vec;
+ t_gpointer *x_gp;
+ t_hang *x_hang;
+} t_pipe;
+
+static void *pipe_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_pipe *x = (t_pipe *)pd_new(pipe_class);
+ t_atom defarg, *ap;
+ t_pipeout *vec, *vp;
+ t_gpointer *gp;
+ int nptr = 0;
+ int i;
+ float deltime;
+ if (argc)
+ {
+ if (argv[argc-1].a_type != A_FLOAT)
+ {
+ char stupid[80];
+ atom_string(&argv[argc-1], stupid, 79);
+ post("pipe: %s: bad time delay value", stupid);
+ deltime = 0;
+ }
+ else deltime = argv[argc-1].a_w.w_float;
+ argc--;
+ }
+ else deltime = 0;
+ if (!argc)
+ {
+ argv = &defarg;
+ argc = 1;
+ SETFLOAT(&defarg, 0);
+ }
+ x->x_n = argc;
+ vec = x->x_vec = (t_pipeout *)getbytes(argc * sizeof(*x->x_vec));
+
+ for (i = argc, ap = argv; i--; ap++)
+ if (ap->a_type == A_SYMBOL && *ap->a_w.w_symbol->s_name == 'p')
+ nptr++;
+
+ gp = x->x_gp = (t_gpointer *)t_getbytes(nptr * sizeof (*gp));
+ x->x_nptr = nptr;
+
+ for (i = 0, vp = vec, ap = argv; i < argc; i++, ap++, vp++)
+ {
+ if (ap->a_type == A_FLOAT)
+ {
+ vp->p_atom = *ap;
+ vp->p_outlet = outlet_new(&x->x_obj, &s_float);
+ if (i) floatinlet_new(&x->x_obj, &vp->p_atom.a_w.w_float);
+ }
+ else if (ap->a_type == A_SYMBOL)
+ {
+ char c = *ap->a_w.w_symbol->s_name;
+ if (c == 's')
+ {
+ SETSYMBOL(&vp->p_atom, &s_symbol);
+ vp->p_outlet = outlet_new(&x->x_obj, &s_symbol);
+ if (i) symbolinlet_new(&x->x_obj, &vp->p_atom.a_w.w_symbol);
+ }
+ else if (c == 'p')
+ {
+ vp->p_atom.a_type = A_POINTER;
+ vp->p_atom.a_w.w_gpointer = gp;
+ gpointer_init(gp);
+ vp->p_outlet = outlet_new(&x->x_obj, &s_pointer);
+ if (i) pointerinlet_new(&x->x_obj, gp);
+ gp++;
+ }
+ else
+ {
+ if (c != 'f') error("pack: %s: bad type",
+ ap->a_w.w_symbol->s_name);
+ SETFLOAT(&vp->p_atom, 0);
+ vp->p_outlet = outlet_new(&x->x_obj, &s_float);
+ if (i) floatinlet_new(&x->x_obj, &vp->p_atom.a_w.w_float);
+ }
+ }
+ }
+ floatinlet_new(&x->x_obj, &x->x_deltime);
+ x->x_hang = 0;
+ x->x_deltime = deltime;
+ return (x);
+}
+
+static void hang_free(t_hang *h)
+{
+ t_pipe *x = h->h_owner;
+ t_gpointer *gp;
+ int i;
+ for (gp = h->h_gp, i = x->x_nptr; i--; gp++)
+ gpointer_unset(gp);
+ freebytes(h->h_gp, x->x_nptr * sizeof(*h->h_gp));
+ clock_free(h->h_clock);
+ freebytes(h, sizeof(*h) + (x->x_n - 1) * sizeof(*h->h_vec));
+}
+
+static void hang_tick(t_hang *h)
+{
+ t_pipe *x = h->h_owner;
+ t_hang *h2, *h3;
+ t_pipeout *p;
+ int i;
+ union word *w;
+ if (x->x_hang == h) x->x_hang = h->h_next;
+ else for (h2 = x->x_hang; h3 = h2->h_next; h2 = h3)
+ {
+ if (h3 == h)
+ {
+ h2->h_next = h3->h_next;
+ break;
+ }
+ }
+ for (i = x->x_n, p = x->x_vec + (x->x_n - 1), w = h->h_vec + (x->x_n - 1);
+ i--; p--, w--)
+ {
+ switch (p->p_atom.a_type)
+ {
+ case A_FLOAT: outlet_float(p->p_outlet, w->w_float); break;
+ case A_SYMBOL: outlet_symbol(p->p_outlet, w->w_symbol); break;
+ case A_POINTER:
+ if (gpointer_check(w->w_gpointer, 1))
+ outlet_pointer(p->p_outlet, w->w_gpointer);
+ else post("pipe: stale pointer");
+ break;
+ }
+ }
+ hang_free(h);
+}
+
+static void pipe_list(t_pipe *x, t_symbol *s, int ac, t_atom *av)
+{
+ t_hang *h = (t_hang *)
+ getbytes(sizeof(*h) + (x->x_n - 1) * sizeof(*h->h_vec));
+ t_gpointer *gp, *gp2;
+ t_pipeout *p;
+ int i, n = x->x_n;
+ t_atom *ap;
+ t_word *w;
+ h->h_gp = (t_gpointer *)getbytes(x->x_nptr * sizeof(t_gpointer));
+ if (ac > n) ac = n;
+ for (i = 0, gp = x->x_gp, p = x->x_vec, ap = av; i < ac;
+ i++, p++, ap++)
+ {
+ switch (p->p_atom.a_type)
+ {
+ case A_FLOAT: p->p_atom.a_w.w_float = atom_getfloat(ap); break;
+ case A_SYMBOL: p->p_atom.a_w.w_symbol = atom_getsymbol(ap); break;
+ case A_POINTER:
+ gpointer_unset(gp);
+ if (ap->a_type != A_POINTER)
+ post("pipe: bad pointer");
+ else
+ {
+ *gp = *(ap->a_w.w_gpointer);
+ if (gp->gp_stub) gp->gp_stub->gs_refcount++;
+ }
+ gp++;
+ }
+ }
+ for (i = 0, gp = x->x_gp, gp2 = h->h_gp, p = x->x_vec, w = h->h_vec;
+ i < n; i++, p++, w++)
+ {
+ if (p->p_atom.a_type == A_POINTER)
+ {
+ if (gp->gp_stub) gp->gp_stub->gs_refcount++;
+ w->w_gpointer = gp2;
+ *gp2++ = *gp++;
+ }
+ else *w = p->p_atom.a_w;
+ }
+ h->h_next = x->x_hang;
+ x->x_hang = h;
+ h->h_owner = x;
+ h->h_clock = clock_new(h, (t_method)hang_tick);
+ clock_delay(h->h_clock, (x->x_deltime >= 0 ? x->x_deltime : 0));
+}
+
+static void pipe_flush(t_pipe *x)
+{
+ while (x->x_hang) hang_tick(x->x_hang);
+}
+
+static void pipe_clear(t_pipe *x)
+{
+ t_hang *hang;
+ while (hang = x->x_hang)
+ {
+ x->x_hang = hang->h_next;
+ hang_free(hang);
+ }
+}
+
+static void pipe_setup(void)
+{
+ pipe_class = class_new(gensym("pipe"),
+ (t_newmethod)pipe_new, (t_method)pipe_clear,
+ sizeof(t_pipe), 0, A_GIMME, 0);
+ class_addlist(pipe_class, pipe_list);
+ class_addmethod(pipe_class, (t_method)pipe_flush, gensym("flush"), 0);
+ class_addmethod(pipe_class, (t_method)pipe_clear, gensym("clear"), 0);
+}
+
+void x_time_setup(void)
+{
+ delay_setup();
+ metro_setup();
+ line_setup();
+ timer_setup();
+ pipe_setup();
+}
diff --git a/pd/src/z.pd b/pd/src/z.pd
new file mode 100644
index 00000000..09812537
--- /dev/null
+++ b/pd/src/z.pd
@@ -0,0 +1,41 @@
+#N canvas 471 67 626 431 10;
+#X obj 30 45 vsl 15 128 0 127 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 2200 1;
+#X obj 83 132 vsl 15 128 0 127 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 2200 1;
+#X obj 527 56 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 1
+;
+#X obj 421 222 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0
+1;
+#X obj 405 241 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0
+1;
+#X obj 358 219 tgl 15 0 empty empty empty 20 8 0 8 -262144 -1 -1 0
+1;
+#N canvas 0 0 450 300 graph1 0;
+#X array array1 100 float 1;
+#A 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 -0.0142856 -0.0428569 -0.0714282 -0.128571 -0.185713 -0.233332
+-0.280951 -0.32857 -0.366665 -0.40476 -0.442855 -0.482415 -0.521975
+-0.561535 -0.601096 -0.640656 -0.680216 -0.719776 -0.759336 -0.798897
+-0.838457 -0.878017 -0.917577 -0.957137 -0.985709 -1.02857 -0.285713
+-0.0857139 -0.0285714 0.0285711 0.157142 0.299998 0.357141 0.442854
+0.490473 0.538092 0.628568 0.628568 0.642853 0.657139 0.657139 0.657139
+0.642853 0.599996 0.566663 0.53333 0.499997 0.471426 0.442854 0.414283
+0.364283 0.314284 0.271427 0.235713 0.199999 0.157142 0.12857 0.109523
+0.0904755 0.071428 0.0428567 0.0142854 -2.0396e-07 -2.0396e-07 0 0
+;
+#X coords 0 -1 99 1 200 140 1;
+#X restore 115 241 graph;
+#X msg 424 249 \; array1 ylabel -10 -1 1;
+#X floatatom 94 47 5 0 0;
+#X floatatom 202 29 5 0 0;
+#N canvas 468 345 450 300 foo3 0;
+#X obj 100 117 spigot;
+#X obj 265 75 r foo1;
+#X obj 259 114 +;
+#X connect 1 0 2 0;
+#X restore 356 29 pd foo3;
+#X obj 230 59 z2 \$0-doo;
+#X msg 503 105 \; foo1 sdf;
+#X connect 0 0 11 0;
+#X connect 11 0 1 0;
diff --git a/pd/src/z2.pd b/pd/src/z2.pd
new file mode 100644
index 00000000..1f36fbf3
--- /dev/null
+++ b/pd/src/z2.pd
@@ -0,0 +1,12 @@
+#N canvas 682 208 558 499 10;
+#X obj 225 80 inlet;
+#X obj 119 198 outlet;
+#X obj 109 160 hsl 128 15 0 127 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 1;
+#X floatatom 495 43 5 0 0;
+#N canvas 0 0 450 300 foo3 0;
+#X restore 82 78 pd foo3;
+#X obj 54 151 print;
+#X connect 0 0 2 0;
+#X connect 2 0 1 0;
+#X coords 0 0 1 1 200 140 1;
diff --git a/pd/src/z3.pd b/pd/src/z3.pd
new file mode 100644
index 00000000..ee8dc6f6
--- /dev/null
+++ b/pd/src/z3.pd
@@ -0,0 +1,3 @@
+#N canvas 408 176 626 431 12;
+#X obj 104 154 z4 foo;
+#X obj 102 200 z4 baz;
diff --git a/pd/src/z4.pd b/pd/src/z4.pd
new file mode 100644
index 00000000..653e036b
--- /dev/null
+++ b/pd/src/z4.pd
@@ -0,0 +1,2 @@
+#N canvas 140 411 616 323 12;
+#X obj 293 98 table \$1-bar 45;
diff --git a/pd/src/z5.pd b/pd/src/z5.pd
new file mode 100644
index 00000000..1adc7b08
--- /dev/null
+++ b/pd/src/z5.pd
@@ -0,0 +1,8 @@
+#N canvas 223 88 626 431 12;
+#N canvas 0 0 450 300 numbox 0;
+#X obj 125 47 loadbang;
+#X msg 124 75 123.456;
+#X floatatom 124 99 3 0 0;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X restore 212 48 pd numbox;
diff --git a/pd/src/z6.pd b/pd/src/z6.pd
new file mode 100644
index 00000000..f8502dc2
--- /dev/null
+++ b/pd/src/z6.pd
@@ -0,0 +1,4 @@
+#N canvas 121 193 452 302 12;
+#X obj 101 40 inlet;
+#X obj 92 138 outlet;
+#X coords 0 0 1 1 200 140 1;