diff --git a/pd/extra/pd~/GNUmakefile.am b/pd/extra/pd~/GNUmakefile.am
index 6110c88c3a140bf75f4db1cc85437bab10526823..bdecdf9026681ac4507c9957b570ccf60203ebc8 100644
--- a/pd/extra/pd~/GNUmakefile.am
+++ b/pd/extra/pd~/GNUmakefile.am
@@ -1,31 +1,42 @@
-## Makefile.am -- Process this file with automake to produce Makefile.in
+#########################################
+##### Defaults & Paths #####
 
 NAME=pd~
 
-PATCHES =  pd~-help.pd pd~-subprocess.pd
+external_LTLIBRARIES = pd~.la pdsched.la
+PATCHES = pd~-help.pd pd~-subprocess.pd
 OTHERDATA = 
 
 pd__la_SOURCES = pd~.c
 pdsched_la_SOURCES = pdsched.c
 
-external_LTLIBRARIES = pd~.la pdsched.la
-dist_external_DATA = $(PATCHES) $(OTHERDATA)
-
+EXTRA_DIST = makefile notes.txt binarymsg.c
 
+#########################################
+##### Files, Binaries, & Libs #####
 
+# you shouldn't need to add anything below here
+dist_external_DATA = $(PATCHES) $(OTHERDATA)
 
 AUTOMAKE_OPTIONS = foreign
-AM_CPPFLAGS	 = -I$(top_srcdir)/src -DPD
-AM_CFLAGS = @ARCH_CFLAGS@
+AM_CFLAGS = @EXTERNAL_CFLAGS@
+AM_CPPFLAGS	+= -I$(top_srcdir)/src -DPD
 AM_LIBS = $(LIBM)
-AM_LDFLAGS = -module -avoid-version -shared @ARCH_LDFLAGS@ -shrext .@EXTERNAL_EXTENSION@ -L$(top_srcdir)/src
+AM_LDFLAGS = -module -avoid-version -shared @EXTERNAL_LDFLAGS@ \
+    -shrext .@EXTERNAL_EXTENSION@ -L$(top_builddir)/src
 
 externaldir = $(pkglibdir)/extra/$(NAME)
 
-
-if MINGW
-AM_LIBS += -lpd
-endif
+#########################################
+##### Targets #####
 
 libtool: $(LIBTOOL_DEPS)
 	$(SHELL) ./config.status --recheck
+
+# create convenience link for running locally
+all-local:
+	rm -f *.@EXTERNAL_EXTENSION@
+	-$(LN_S) $(wildcard .libs/*.@EXTERNAL_EXTENSION@) ./
+
+clean-local:
+	rm -f *.@EXTERNAL_EXTENSION@
diff --git a/pd/extra/pd~/binarymsg.c b/pd/extra/pd~/binarymsg.c
new file mode 100644
index 0000000000000000000000000000000000000000..2af97930508dea1a577212ac770012a1c1a8ecd9
--- /dev/null
+++ b/pd/extra/pd~/binarymsg.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include "m_pd.h"
+
+static void pd_tilde_putfloat(float f, FILE *fd)
+{
+    putc(A_FLOAT, fd);
+    fwrite(&f, sizeof(f), 1, fd);
+}
+
+static void pd_tilde_putsymbol(t_symbol *s, FILE *fd)
+{
+    char *sp = s->s_name;
+    putc(A_SYMBOL, fd);
+    do
+        putc(*sp, fd);
+    while (*sp++);
+}
+
+static int pd_tilde_getatom(t_atom *ap, FILE *fd)
+{
+    char buf[MAXPDSTRING];
+    while (1)
+    {
+        int type = getc(fd), fill;
+        float f;
+        switch (type)
+        {
+        case EOF:
+            return (0);
+        case A_SEMI:
+            SETSEMI(ap);
+            return (1);
+        case A_FLOAT:
+            if (fread(&f, sizeof(f), 1, fd) >= 1)
+            {
+                SETFLOAT(ap, f);
+                return (1);
+            }
+            else return (0);
+        case A_SYMBOL:
+            for (fill = 0; fill < MAXPDSTRING; fill++)
+            {
+                int c = getc(fd);
+                if (c == EOF)
+                    return (0);
+                else buf[fill] = c;
+                if (!c)
+                {
+                    SETSYMBOL(ap, gensym(buf));
+                    return (1);
+                }
+            }
+            return (0);
+        }
+    }
+}
diff --git a/pd/extra/pd~/makefile b/pd/extra/pd~/makefile
index 5fc5d26b3881712f85417302bb21d8ed558d4208..781617fd8aa4c395967c84efcd6f45bdf73021cd 100644
--- a/pd/extra/pd~/makefile
+++ b/pd/extra/pd~/makefile
@@ -4,6 +4,7 @@ CSYM=pd_tilde
 include ../makefile.subdir
 
 pd_linux: pdsched.pd_linux
+pd_nt: pdsched.dll
 
 d_fat: pdsched.d_fat
 d_ppc: pdsched.d_ppc
@@ -12,3 +13,8 @@ pdsched.pd_linux: pdsched.c
 	$(CC) $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
 	$(CC) -shared -o $*.pd_linux $*.o -lc -lm
 	rm -f $*.o
+
+pdsched.dll: pdsched.c
+	$(MSCC) $(PDNTCFLAGS) $(PDNTINCLUDE) /c $*.c
+	$(MSLN) /nologo /dll /export:pd_extern_sched $*.obj $(PDNTLIB)
+	rm -f $*.obj
diff --git a/pd/extra/pd~/pdsched.c b/pd/extra/pd~/pdsched.c
index e5e8072ad7473de04a173e008c137957462759a2..7ad2eed48473bd5afa1800b8522e8c607ea0e6a9 100644
--- a/pd/extra/pd~/pdsched.c
+++ b/pd/extra/pd~/pdsched.c
@@ -12,19 +12,25 @@ outputs audio and messages. */
 */    
 #include "m_pd.h"
 #include "s_stuff.h"
+#include "m_imp.h"
 #include <stdio.h>
+#ifdef _WIN32
+#include <io.h>
+#include <fcntl.h>
+#endif
 
-#define BUFSIZE 65536
-static char inbuf[BUFSIZE];
+#include "binarymsg.c"
 
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__GNU__)
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)\
+     || defined(__GNU__)
 void glob_watchdog(t_pd *dummy);
 
 static void pollwatchdog( void)
 {
     static int sched_diddsp, sched_nextpingtime;
     sched_diddsp++;
-    if (sys_nogui && sys_hipriority && (sched_diddsp - sched_nextpingtime > 0))
+    if (sys_nogui && sys_hipriority &&
+        (sched_diddsp - sched_nextpingtime > 0))
     {
         glob_watchdog(0);
             /* ping every 2 seconds */
@@ -34,11 +40,53 @@ static void pollwatchdog( void)
 }
 #endif
 
+static t_class *pd_ambinary_class;
+#define BUFSIZE 65536
+static char *ascii_inbuf;
+
+static int readasciimessage(t_binbuf *b)
+{
+    int fill = 0, c;
+
+    binbuf_clear(b);
+    while ((c = getchar()) != EOF)
+    {
+        if (c == ';')
+        {
+            binbuf_text(b, ascii_inbuf, fill);
+            return (1);
+        }
+        else if (fill < BUFSIZE)
+            ascii_inbuf[fill++] = c;
+        else if (fill == BUFSIZE)
+            fprintf(stderr, "pd-extern: input buffer overflow\n");
+    }
+    return (0);
+}
+
+static int readbinmessage(t_binbuf *b)
+{
+    binbuf_clear(b);
+    while (1)
+    {
+        t_atom at;
+        if (!pd_tilde_getatom(&at, stdin))
+        {
+            fprintf(stderr, "pd-extern: EOF on input\n");
+            return (0);
+        }
+        else if (at.a_type == A_SEMI)
+            return (1);
+        else binbuf_add(b, 1, &at);
+    }
+}
+
 int pd_extern_sched(char *flags)
 {
     int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV];
     int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV];
-    int i, j, rate, advance, callback, chin, chout, fill = 0, c, blocksize;
+    int i, j, rate, advance, callback, chin, chout, fill = 0, c, blocksize,
+        useascii = 0;
     t_binbuf *b = binbuf_new();
 
     sys_get_audio_params(&naudioindev, audioindev, chindev,
@@ -47,60 +95,76 @@ int pd_extern_sched(char *flags)
 
     chin = (naudioindev < 1 ? 0 : chindev[0]);
     chout = (naudiooutdev < 1 ? 0 : choutdev[0]);
-
-    fprintf(stderr, "Pd plug-in scheduler called, chans %d %d, sr %d\n",
-        chin, chout, (int)rate);
+    if (!flags || flags[0] != 'a')
+    {
+            /* signal to stdout object to do binary by attaching an object
+            to an obscure symbol name */
+        pd_ambinary_class = class_new(gensym("pd~"), 0, 0, sizeof(t_pd),
+            CLASS_PD, 0);
+        pd_bind(&pd_ambinary_class, gensym("#pd_binary_stdio"));
+            /* On Windows, set stdin and out to "binary" mode */
+#ifdef _WIN32
+        setmode(fileno(stdout),O_BINARY);
+        setmode(fileno(stdin),O_BINARY);
+#endif
+    }
+    else
+    {
+        if (!(ascii_inbuf = getbytes(BUFSIZE)))
+            return (1);
+        useascii = 1;
+    }
+    /* fprintf(stderr, "Pd plug-in scheduler called, chans %d %d, sr %d\n",
+        chin, chout, (int)rate); */
     sys_setchsr(chin, chout, rate);
     sys_audioapi = API_NONE;
-    while ((c = getchar()) != EOF)
+    while (useascii ? readasciimessage(b) : readbinmessage(b) )
     {
-        if (c == ';')
+        t_atom *ap = binbuf_getvec(b);
+        int n = binbuf_getnatom(b);
+        if (n > 0 && ap[0].a_type == A_FLOAT)
         {
-            int n;
-            t_atom *ap;
-            binbuf_text(b, inbuf, fill);
-            n = binbuf_getnatom(b);
-            ap = binbuf_getvec(b);
-            fill = 0;
-            if (n > 0 && ap[0].a_type == A_FLOAT)
-            {
-                /* a list -- take it as incoming signals. */
-                int chan, nchan = n/DEFDACBLKSIZE;
-                t_sample *fp;
-                for (i = chan = 0, fp = sys_soundin; chan < nchan; chan++)
-                    for (j = 0; j < DEFDACBLKSIZE; j++)
-                        *fp++ = atom_getfloat(ap++);
-                for (; chan < chin; chan++)
-                    for (j = 0; j < DEFDACBLKSIZE; j++)
-                        *fp++ = 0;
-                sched_tick();
-                sys_pollgui();
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__GNU__)
-                pollwatchdog();
+            /* a list -- take it as incoming signals. */
+            int chan, nchan = n/DEFDACBLKSIZE;
+            t_sample *fp;
+            for (i = chan = 0, fp = sys_soundin; chan < nchan; chan++)
+                for (j = 0; j < DEFDACBLKSIZE; j++)
+                    *fp++ = atom_getfloat(ap++);
+            for (; chan < chin; chan++)
+                for (j = 0; j < DEFDACBLKSIZE; j++)
+                    *fp++ = 0;
+            sched_tick();
+            sys_pollgui();
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)\
+     || defined(__GNU__)
+            pollwatchdog();
 #endif
+            if (useascii)
                 printf(";\n");
-                for (i = chout*DEFDACBLKSIZE, fp = sys_soundout; i--; fp++)
-                {
-                    printf("%g\n", *fp);
-                    *fp = 0;
-                }
-                printf(";\n");
-                fflush(stdout);
-            }
-            else if (n > 1 && ap[0].a_type == A_SYMBOL)
+            else putchar(A_SEMI);
+            for (i = chout*DEFDACBLKSIZE, fp = sys_soundout; i--;
+                fp++)
             {
-                t_pd *whom = ap[0].a_w.w_symbol->s_thing;
-                if (!whom)
-                    error("%s: no such object", ap[0].a_w.w_symbol->s_name);
-                else if (ap[1].a_type == A_SYMBOL)
-                    typedmess(whom, ap[1].a_w.w_symbol, n-2, ap+2);
-                else pd_list(whom, 0, n-1, ap+1);
+                if (useascii)
+                    printf("%g\n", *fp);
+                else pd_tilde_putfloat(*fp, stdout);
+                *fp = 0;
             }
+            if (useascii)
+                printf(";\n");
+            else putchar(A_SEMI);
+            fflush(stdout);
+        }
+        else if (n > 1 && ap[0].a_type == A_SYMBOL)
+        {
+            t_pd *whom = ap[0].a_w.w_symbol->s_thing;
+            if (!whom)
+                error("%s: no such object", ap[0].a_w.w_symbol->s_name);
+            else if (ap[1].a_type == A_SYMBOL)
+                typedmess(whom, ap[1].a_w.w_symbol, n-2, ap+2);
+            else pd_list(whom, 0, n-1, ap+1);
         }
-        else if (fill < BUFSIZE)
-            inbuf[fill++] = c;
-        else if (fill == BUFSIZE)
-            fprintf(stderr, "pd-extern: input buffer overflow\n");
     }
+    binbuf_free(b);
     return (0);
 }
diff --git a/pd/extra/pd~/pd~-help.pd b/pd/extra/pd~/pd~-help.pd
index 8bc357e0c7b62b9809a578b0cd0751825bc89efb..573a0caf4186f3972a5c343b73413d87771ec8a3 100644
--- a/pd/extra/pd~/pd~-help.pd
+++ b/pd/extra/pd~/pd~-help.pd
@@ -1,32 +1,32 @@
-#N canvas 12 0 566 872 12;
+#N canvas 113 52 638 844 12;
 #X msg 31 406 foo bar baz;
 #X obj 189 466 osc~ 440;
-#X obj 127 645 env~ 8192;
-#X floatatom 127 694 5 0 0 0 - - -;
-#X msg 434 807 \; pd dsp 1;
+#X obj 114 614 env~ 8192;
+#X floatatom 114 663 5 0 0 0 - - -, f 5;
+#X msg 535 750 \; pd dsp 1;
 #X msg 24 332 pd~ stop;
-#X obj 127 670 i;
-#X obj 241 643 env~ 8192;
-#X floatatom 241 693 5 0 0 0 - - -;
-#X obj 241 669 i;
+#X obj 114 639 i;
+#X obj 228 612 env~ 8192;
+#X floatatom 228 662 5 0 0 0 - - -, f 5;
+#X obj 228 638 i;
 #X obj 123 489 *~;
 #X obj 158 490 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
 1;
 #X obj 189 490 *~;
 #X obj 224 491 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
 1;
-#X obj 434 781 loadbang;
-#X obj 14 691 print x;
+#X obj 535 724 loadbang;
+#X obj 12 643 print x;
 #X msg 15 309 pd~ start pd~-subprocess.pd;
 #X obj 14 532 pd~ -ninsig 2 -noutsig 2 -fifo 20;
 #X obj 37 20 pd~;
 #X text 69 22 - run a pd sub-process;
-#X text 27 57 The pd~ object starts and manages a Pd sub-process that
+#X text 27 52 The pd~ object starts and manages a Pd sub-process that
 can communicate with the super-process (this one) via audio channels
 and/or Pd messages. In this way you can take advantage of multi-core
 CPUs \, and/or use Pd features from within Max (if you're using the
 Max version of pd~).;
-#X text 24 251 Sending a new "start" message will stop the sub-process
+#X text 24 246 Sending a new "start" message will stop the sub-process
 and start a new one. If you just want to stop the sub-process \, send
 "stop".;
 #X text 33 353 Any message besides "pd~" is sent to the sub-process.
@@ -34,23 +34,23 @@ For instance \, the message below sends "bar baz" to any object in
 the sub-process named "foo" \, such as a "receive" object.;
 #X text 43 430 Audio signals appear in adc~ objects in the sub-process.
 The sub-process doesn't open real audio devices.;
-#X text 281 473 Creation args:;
-#X text 265 490 -insig <n> sets input audio channels;
-#X text 266 508 -outsig <n> sets output channels;
-#X text 269 542 -fifo <n> sets round-trip delay in blocks;
-#X text 272 559 -pddir <s> sets Pd directory \, e.g. \,;
-#X text 299 574 .../Pd-0.42.app/Contents/Resources;
-#X text 272 590 -scheddir <s> sets scheduler dir \, e.g. \,;
-#X text 297 607 .../.../Resources/extra/pd~;
-#X text 267 524 -sr <n> sets sample rate;
-#X text 20 716 The first outlet reports messages the sub-process sends
+#X text 302 469 Creation args:;
+#X text 286 486 -insig <n> sets input audio channels;
+#X text 287 504 -outsig <n> sets output channels;
+#X text 290 538 -fifo <n> sets round-trip delay in blocks;
+#X text 293 555 -pddir <s> sets Pd directory \, e.g. \,;
+#X text 320 570 .../Pd-0.42.app/Contents/Resources;
+#X text 293 586 -scheddir <s> sets scheduler dir \, e.g. \,;
+#X text 318 603 .../.../Resources/extra/pd~;
+#X text 288 520 -sr <n> sets sample rate;
+#X text 28 699 The first outlet reports messages the sub-process sends
 us via "stdout" objects. Any other outlets are signals corresponding
 to "dac~" objects in the sub-process.;
-#X text 10 784 ATTENTION: DSP must be running in this process for the
+#X text 21 756 ATTENTION: DSP must be running in this process for the
 sub-process to run. This is because its clock is slaved to audio I/O
 it gets from us!;
-#X text 359 849 Updated for Pd version 0.42.;
-#X text 24 138 Messages with "pd~" selector control the sub-process.
+#X text 393 802 Updated for Pd version 0.42.;
+#X text 24 132 Messages with "pd~" selector control the sub-process.
 "pd~ start" takes as arguments any startup arguments you wish to send
 the sub-process. For example \, specify "-nogui" to stop the sub-process's
 GUI from appearing. You don't have to specify the number of channels
diff --git a/pd/extra/pd~/pd~-subprocess.pd b/pd/extra/pd~/pd~-subprocess.pd
index 1d883ab18862f32895c2aafeb63910822fdbf9cf..22bf457143e4eda52bae78c05c0e17f449f49efe 100644
--- a/pd/extra/pd~/pd~-subprocess.pd
+++ b/pd/extra/pd~/pd~-subprocess.pd
@@ -1,4 +1,4 @@
-#N canvas 577 21 563 559 12;
+#N canvas 600 66 646 598 12;
 #X obj 202 395 r foo;
 #X obj 202 423 print foo;
 #X obj 87 174 adc~;
@@ -6,12 +6,12 @@
 #X msg 72 364 a b c;
 #X msg 455 441 \; pd dsp 1;
 #X obj 87 201 env~ 8192;
-#X floatatom 87 250 5 0 0 0 - - -;
+#X floatatom 87 250 5 0 0 0 - - -, f 5;
 #X obj 87 226 i;
 #X obj 263 253 dac~;
 #X obj 262 185 osc~ 440;
 #X obj 262 219 *~;
-#X obj 297 220 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
+#X obj 297 220 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1
 1;
 #X obj 332 186 osc~ 440;
 #X obj 332 220 *~;
@@ -20,7 +20,7 @@
 #X msg 86 411 bang;
 #X obj 455 417 loadbang;
 #X obj 160 201 env~ 8192;
-#X floatatom 160 250 5 0 0 0 - - -;
+#X floatatom 160 250 5 0 0 0 - - -, f 5;
 #X obj 160 226 i;
 #X msg 86 388 4;
 #X text 62 8 This is a test patch to demonstrate the Pd~ object. It's
@@ -29,7 +29,7 @@ is a separate instance of Pd) can be called from a Max or Pd super-process.
 ;
 #X text 63 73 Audio inlets and outlets on the Pd~ object (in the super-process)
 talk to adc~ and dac~ objects here - so \, for instance \, the first
-adc~ here is the first inlet of the pd~ object \, and the first chanel
+adc~ here is the first inlet of the pd~ object \, and the first channel
 of dac~ goes to the second outlet of pd~ (because the first one is
 for messages \, as shown further below.);
 #X text 58 283 Any message sent to a stdout object in this sub-process
diff --git a/pd/extra/pd~/pd~.c b/pd/extra/pd~/pd~.c
index 71487109b5db5d4c3b7f86be1d52ca3b470b33eb..5c49274592ead8b9a859e39d11fd5cef02154d4d 100644
--- a/pd/extra/pd~/pd~.c
+++ b/pd/extra/pd~/pd~.c
@@ -5,19 +5,30 @@
   BSD license; see README.txt in this distribution for details.
 */
 
+#ifdef _WIN32
+#include <io.h>
+#include <fcntl.h>
+#include <process.h>
+#include <windows.h>
+typedef int socklen_t;
+#define EADDRINUSE WSAEADDRINUSE
+#else
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <ctype.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <sys/wait.h>
 #include <fcntl.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
 
 #ifdef _MSC_VER
 #pragma warning (disable: 4305 4244)
+#define snprintf sprintf_s
+#define stat _stat
 #endif
 
 #ifdef MSP
@@ -33,7 +44,7 @@ typedef double t_floatarg;
 #define A_SYMBOL A_SYM
 #define getbytes t_getbytes
 #define freebytes t_freebytes
-#define ERROR error(
+#define PDERROR error(
 void *pd_tilde_class;
 #define MAXPDSTRING 4096
 #define DEFDACBLKSIZE 64
@@ -43,8 +54,7 @@ void *pd_tilde_class;
 #include "m_pd.h"
 #include "s_stuff.h"
 static t_class *pd_tilde_class;
-char *class_gethelpdir(t_class *c);
-#define ERROR pd_error(x, 
+#define PDERROR pd_error(x, 
 
 #endif
 
@@ -65,6 +75,9 @@ static char pd_tilde_dllextent[] = ".d_fat",
 static char pd_tilde_dllextent[] = ".m_i386", pd_tilde_dllextent2[] = ".dll";
 #endif
 
+#define FOOFOO
+#include "binarymsg.c"
+
 /* ------------------------ pd_tilde~ ----------------------------- */
 
 #define MSGBUFSIZE 65536
@@ -84,14 +97,13 @@ typedef struct _pd_tilde
 #endif /* MSP */
     FILE *x_infd;
     FILE *x_outfd;
-    char *x_msgbuf;
-    int x_msgbufsize;
-    int x_infill;
+    t_binbuf *x_binbuf;
     int x_childpid;
     int x_ninsig;
     int x_noutsig;
     int x_fifo;
-    float x_sr;
+    int x_binary;
+    t_float x_sr;
     t_symbol *x_pddir;
     t_symbol *x_schedlibdir;
     t_sample **x_insig;
@@ -114,169 +126,311 @@ char *strcpy(char *s1, const char *s2);
 static void pd_tilde_tick(t_pd_tilde *x);
 static void pd_tilde_close(t_pd_tilde *x)
 {
+#ifdef _WIN32
+    int termstat;
+#endif
     if (x->x_outfd)
         fclose(x->x_outfd);
     if (x->x_infd)
         fclose(x->x_infd);
     if (x->x_childpid > 0)
+#ifdef _WIN32
+        _cwait(&termstat, x->x_childpid, WAIT_CHILD);
+#else
         waitpid(x->x_childpid, 0, 0);
-    if (x->x_msgbuf)
-        free(x->x_msgbuf);
+#endif
+    binbuf_clear(x->x_binbuf);
     x->x_infd = x->x_outfd = 0;
     x->x_childpid = -1;
-    x->x_msgbuf = 0;
-    x->x_msgbufsize = 0;
 }
 
 static void pd_tilde_readmessages(t_pd_tilde *x)
 {
-    int gotsomething = 0, setclock = 0, wasempty = (x->x_infill == 0);
-    FILE *infd = x->x_infd;
-    while (1)
+    t_atom at;
+    binbuf_clear(x->x_binbuf);
+    if (x->x_binary)
     {
-        int c = getc(infd);
-        if (c == EOF)
+        int nonempty = 0;
+        while (1)
         {
-            ERROR "pd~: %s", strerror(errno));
-            pd_tilde_close(x);
-            break;
+            pd_tilde_getatom(&at, x->x_infd);
+            if (!nonempty && at.a_type == A_SEMI)
+                break;
+            nonempty = (at.a_type != A_SEMI);
+            binbuf_add(x->x_binbuf, 1, &at);
         }
-        if (x->x_infill >= x->x_msgbufsize)
+    }
+    else    /* ASCII */
+    {
+        t_binbuf *tmpb = binbuf_new();
+        while (1)
         {
-            char *z = realloc(x->x_msgbuf, x->x_msgbufsize+MSGBUFSIZE);
-            if (!z)
+            char msgbuf[MAXPDSTRING];
+            int c, infill = 0, n;
+            t_atom *vec;
+            while (isspace((c = getc(x->x_infd))) && c != EOF)
+                ;
+            if (c == EOF)
+                return;
+            do
+                msgbuf[infill++] = c;
+            while (!isspace((c = getc(x->x_infd))) && c != ';' && c != EOF) ;
+            binbuf_text(tmpb, msgbuf, infill);
+            n = binbuf_getnatom(tmpb);
+            vec = binbuf_getvec(tmpb);
+            binbuf_add(x->x_binbuf, n, vec);
+            if (!n)
             {
-                ERROR "pd~: failed to grow input buffer");
-                pd_tilde_close(x);
-                break;
+                bug("pd~");
+                break;  /* shouldn't happen */
             }
-            x->x_msgbuf = z;
-            x->x_msgbufsize += MSGBUFSIZE;
-        }
-        x->x_msgbuf[x->x_infill++] = c;
-        if (c == ';')
-        {
-            if (!gotsomething)
+            if (vec[0].a_type == A_SEMI)
                 break;
-            gotsomething = 0;
         }
-        else if (!isspace(c))
-            gotsomething = setclock = 1;
+        binbuf_free(tmpb);
+        /* if (binbuf_getnatom(x->x_binbuf) > 1)
+            binbuf_print(x->x_binbuf); */
     }
-    if (setclock)
-        clock_delay(x->x_clock, 0);
-    else if (wasempty)
-        x->x_infill = 0;
+    clock_delay(x->x_clock, 0);
 }
 
+#define FIXEDARG 14
+#define MAXARG 100
+#ifdef _WIN32
+#define EXTENT ".com"
+#else
+#define EXTENT ""
+#endif
+
 static void pd_tilde_donew(t_pd_tilde *x, char *pddir, char *schedlibdir,
-    char *patchdir, char *pdargs, int ninsig, int noutsig, int fifo,
-    float samplerate)
+    char *patchdir, int argc, t_atom *argv, int ninsig, int noutsig,
+    int fifo, t_float samplerate)
 {
     int i, pid, pipe1[2], pipe2[2];
-    char cmdbuf[MAXPDSTRING], pdexecbuf[MAXPDSTRING], schedbuf[MAXPDSTRING];
+    char pdexecbuf[MAXPDSTRING], schedbuf[MAXPDSTRING], tmpbuf[MAXPDSTRING];
+    char *execargv[FIXEDARG+MAXARG+1], ninsigstr[20], noutsigstr[20],
+        sampleratestr[40];
     struct stat statbuf;
     x->x_infd = x->x_outfd = 0;
     x->x_childpid = -1;
-    snprintf(pdexecbuf, MAXPDSTRING, "%s/bin/pd-l2ork", pddir);
+    if (argc > MAXARG)
+    {
+        post("pd~: args truncated to %d items", MAXARG);
+        argc = MAXARG;
+    }
+    sprintf(ninsigstr, "%d", ninsig);
+    sprintf(noutsigstr, "%d", noutsig);
+    sprintf(sampleratestr, "%f", (float)samplerate);
+    /* Windows is still relying on makefile.mingw which still uses the
+       name "pd" for the executable, so we need an ifdef here. Yuck! */
+#ifdef _WIN32
+    snprintf(tmpbuf, MAXPDSTRING, "%s/bin/pd" EXTENT, pddir);
+#else
+    snprintf(tmpbuf, MAXPDSTRING, "%s/bin/pd-l2ork" EXTENT, pddir);
+#endif
+    sys_bashfilename(tmpbuf, pdexecbuf);
     if (stat(pdexecbuf, &statbuf) < 0)
     {
-        snprintf(pdexecbuf, MAXPDSTRING, "%s/../../../bin/pd-l2ork", pddir);
+        snprintf(tmpbuf, MAXPDSTRING, "%s/../../../bin/pd" EXTENT, pddir);
+        sys_bashfilename(tmpbuf, pdexecbuf);
         if (stat(pdexecbuf, &statbuf) < 0)
         {
-            snprintf(pdexecbuf, MAXPDSTRING, "%s/pd-l2ork", pddir);
+            snprintf(tmpbuf, MAXPDSTRING, "%s/pd" EXTENT, pddir);
+            sys_bashfilename(tmpbuf, pdexecbuf);
             if (stat(pdexecbuf, &statbuf) < 0)
             {
-                ERROR "pd~: can't stat %s", pdexecbuf);
+                PDERROR "pd~: can't stat %s", pdexecbuf);
                 goto fail1;
             }
         }
     }
-    snprintf(schedbuf, MAXPDSTRING, "%s/pdsched%s", schedlibdir, 
+    snprintf(tmpbuf, MAXPDSTRING, "%s/pdsched%s", schedlibdir, 
         pd_tilde_dllextent);
+    sys_bashfilename(tmpbuf, schedbuf);
     if (stat(schedbuf, &statbuf) < 0)
     {
-        snprintf(schedbuf, MAXPDSTRING, "%s/pdsched%s", schedlibdir, 
+        snprintf(tmpbuf, MAXPDSTRING, "%s/pdsched%s", schedlibdir, 
             pd_tilde_dllextent2);
+        sys_bashfilename(tmpbuf, schedbuf);
         if (stat(schedbuf, &statbuf) < 0)
         {
-            ERROR "pd~: can't stat %s", schedbuf);
+            PDERROR "pd~: can't stat %s", schedbuf);
             goto fail1;
         }       
     }
-    snprintf(cmdbuf, MAXPDSTRING,
-"%s -unique -schedlib %s/pdsched -path %s -inchannels %d -outchannels %d -r %g %s\n",
-        pdexecbuf, schedlibdir, patchdir, ninsig, noutsig, samplerate, pdargs);
-#if 0
+        /* but the sub-process wants the scheduler name without the suffix */
+    snprintf(tmpbuf, MAXPDSTRING, "%s/pdsched", schedlibdir);
+    sys_bashfilename(tmpbuf, schedbuf);
+    /* We have to quote the executable under Windows to make sure spaces
+       in the path don't confuse Windows. */
+#ifdef _WIN32
+    char quoted_execbuf[MAXPDSTRING];
+    sprintf(quoted_execbuf, "\"%s\"", pdexecbuf);
+    execargv[0] = quoted_execbuf;
+#else
+    execargv[0] = pdexecbuf;
+#endif
+    /* For the moment we must start the child Pd with the "-unique" flag
+       to ensure its GUI gets its own instance. Hopefully at some point in
+       the future we can figure out a usable way to get multiple Pds running
+       connected to the same GUI process. */
+    execargv[1] = "-unique";
+    execargv[2] = "-schedlib";
+#ifdef _WIN32
+    char quoted_schedbuf[MAXPDSTRING];
+    sprintf(quoted_schedbuf, "\"%s\"", schedbuf);
+    execargv[3] = quoted_schedbuf;
+#else
+    execargv[3] = schedbuf;
+#endif
+    execargv[4] = "-extraflags";
+    execargv[5] = (x->x_binary ? "b" : "a");
+    execargv[6] = "-path";
+#ifdef _WIN32
+    char quoted_patchdir[MAXPDSTRING];
+    strcpy(quoted_patchdir, "\"");
+    sys_bashfilename(patchdir, tmpbuf);
+    strcat(quoted_patchdir, tmpbuf);
+    strcat(quoted_patchdir, "\"");
+    execargv[7] = quoted_patchdir;
+#else
+    execargv[7] = patchdir;
+#endif
+    execargv[8] = "-inchannels";
+    execargv[9] = ninsigstr;
+    execargv[10] = "-outchannels";
+    execargv[11] = noutsigstr;
+    execargv[12] = "-r";
+    execargv[13] = sampleratestr;
+
+        /* convert atom arguments to strings (temporarily allocating space) */
+    for (i = 0; i < argc; i++)
+    {
 #ifdef PD
-    fprintf(stderr, "%s", cmdbuf);
+        atom_string(&argv[i], tmpbuf, MAXPDSTRING);
+#endif
+#ifdef MSP
+            /* because Mac pathnames sometimes have an evil preceeding
+            colon character, we test for and silently eat them */
+        if (argv[i].a_type == A_SYM)
+            strncpy(tmpbuf, (*argv->a_w.w_sym->s_name == ':'?
+                argv->a_w.w_sym->s_name+1 : argv->a_w.w_sym->s_name),
+                MAXPDSTRING-3);
+        else if (argv[i].a_type == A_LONG)
+            sprintf(tmpbuf, "%ld", argv->a_w.w_long);
+        else if (argv[i].a_type == A_FLOAT)
+            sprintf(tmpbuf,  "%f", argv->a_w.w_float);
 #endif
-    post("cmd: %s", cmdbuf);
+        execargv[FIXEDARG+i] = malloc(strlen(tmpbuf) + 1);
+        strcpy(execargv[FIXEDARG+i], tmpbuf);
+    }
+    execargv[argc+FIXEDARG] = 0;
+#if 1
+    for (i = 0; i < argc+FIXEDARG; i++)
+        fprintf(stderr, "%s ", execargv[i]);
+    fprintf(stderr, "\n");
 #endif
+#ifdef _WIN32
+    if (_pipe(pipe1, 65536, O_BINARY | O_NOINHERIT) < 0)   
+#else
     if (pipe(pipe1) < 0)   
+#endif
     {
-        ERROR "pd~: can't create pipe");
+        PDERROR "pd~: can't create pipe");
         goto fail1;
     }
+#ifdef _WIN32
+    if (_pipe(pipe2, 65536, O_BINARY | O_NOINHERIT) < 0)   
+#else
     if (pipe(pipe2) < 0)   
+#endif
     {
-        ERROR "pd~: can't create pipe");
+        PDERROR "pd~: can't create pipe");
         goto fail2;
     }
+#ifdef _WIN32
+    {
+        int stdinwas = _dup(0), stdoutwas = _dup(1);
+        if (pipe2[1] == 0)
+            pipe2[1] = _dup(pipe2[1]);
+        if (pipe1[0] != 0)
+            _dup2(pipe1[0], 0);
+        if (pipe2[1] != 1)
+            _dup2(pipe2[1], 1);
+        pid = _spawnv(P_NOWAIT, pdexecbuf, execargv);
+        if (pid < 0)
+        {
+            post("%s: couldn't start subprocess (%s)\n", execargv[0],
+                strerror(errno));
+            goto fail1;
+        }
+        _dup2(stdinwas, 0);
+        _dup2(stdoutwas, 1);
+        _close(stdinwas);
+        _close(stdoutwas);
+    }
+#else /* _WIN32 */
     if ((pid = fork()) < 0)
     {
-        ERROR "pd~: can't fork");
+        PDERROR "pd~: can't fork");
         goto fail3;
     }
     else if (pid == 0)
     {
         /* child process */
+            /* the first dup2 below would bash pipe2[1] if it happens to be
+                zero so in that case renumber it */
         if (pipe2[1] == 0)
+            pipe2[1] = dup(pipe2[1]);
+        if (pipe1[0] != 0)
+        {
+            dup2(pipe1[0], 0);
+            close (pipe1[0]);
+        }
+        if (pipe2[1] != 1)
         {
-            dup2(pipe2[1], 20);
-            close(pipe2[1]);
-            pipe2[1] = 20;
+            dup2(pipe2[1], 1);
+            close (pipe2[1]);
         }
-        dup2(pipe1[0], 0);
-        dup2(pipe2[1], 1);
-        if (pipe1[0] >= 2)
-            close(pipe1[0]);
         if (pipe1[1] >= 2)
             close(pipe1[1]);
         if (pipe2[0] >= 2)
             close(pipe2[0]);
-        if (pipe2[1] >= 2)
-            close(pipe2[1]);
-        execl("/bin/sh", "sh", "-c", cmdbuf, (char*)0);
+        execv("/usr/lib/pd-l2ork/bin/pd-l2ork", execargv);
+        perror("pd~ execv:");
         _exit(1);
     }
-        /* OK, we're parent */
+#endif /* _WIN32 */
+        /* done with fork/exec or spawn; parent continues here */
     close(pipe1[0]);
     close(pipe2[1]);
+#ifndef _WIN32      /* this was done in windows via the O_NOINHERIT flag */
     fcntl(pipe1[1],  F_SETFD, FD_CLOEXEC);
     fcntl(pipe2[0],  F_SETFD, FD_CLOEXEC);
+#endif
     x->x_outfd = fdopen(pipe1[1], "w");
     x->x_infd = fdopen(pipe2[0], "r");
     x->x_childpid = pid;
     for (i = 0; i < fifo; i++)
-        fprintf(x->x_outfd, "%s", ";\n0;\n");
-    fflush(x->x_outfd);
-    if (!(x->x_msgbuf = calloc(MSGBUFSIZE, 1)))
+        if (x->x_binary)
     {
-        ERROR "pd~: can't allocate message buffer");
-        goto fail3;
+        putc(A_SEMI, x->x_outfd);
+        pd_tilde_putfloat(0, x->x_outfd);
+        putc(A_SEMI, x->x_outfd);
     }
-    x->x_msgbufsize = MSGBUFSIZE;
-    x->x_infill = 0;
-    /* fprintf(stderr, "read...\n"); */
+    else fprintf(x->x_outfd, "%s", ";\n0;\n");
+
+    fflush(x->x_outfd);
+    binbuf_clear(x->x_binbuf);
     pd_tilde_readmessages(x);
-    /* fprintf(stderr, "... done.\n"); */
     return;
+#ifndef _WIN32
 fail3:
     close(pipe2[0]);
     close(pipe2[1]);
     if (x->x_childpid > 0)
-        waitpid(x->x_childpid, 0, 0);
+    waitpid(x->x_childpid, 0, 0);
+#endif
 fail2:
     close(pipe1[0]);
     close(pipe1[1]);
@@ -289,68 +443,120 @@ fail1:
 static t_int *pd_tilde_perform(t_int *w)
 {
     t_pd_tilde *x = (t_pd_tilde *)(w[1]);
-    int n = (int)(w[2]), i, j, numbuffill = 0, c;
+    int n = (int)(w[2]), i, j, nsigs, numbuffill = 0, c;
     char numbuf[80];
     FILE *infd = x->x_infd;
     if (!infd)
         goto zeroit;
-    fprintf(x->x_outfd, ";\n");
-    if (!x->x_ninsig)
-        fprintf(x->x_outfd, "0\n");
-    else for (i = 0; i < x->x_ninsig; i++)
+    if (x->x_binary)
     {
-        t_sample *fp = x->x_insig[i];
-        for (j = 0; j < n; j++)
-            fprintf(x->x_outfd, "%g\n", *fp++);
-        for (; j < DEFDACBLKSIZE; j++)
+        putc(A_SEMI, x->x_outfd);
+        if (!x->x_ninsig)
+            pd_tilde_putfloat(0, x->x_outfd);
+        else for (i = 0; i < x->x_ninsig; i++)
+        {
+            t_sample *fp = x->x_insig[i];
+            for (j = 0; j < n; j++)
+                pd_tilde_putfloat(*fp++, x->x_outfd);
+            for (; j < DEFDACBLKSIZE; j++)
+                pd_tilde_putfloat(0, x->x_outfd);
+        }
+        putc(A_SEMI, x->x_outfd);
+    }
+    else
+    {
+        fprintf(x->x_outfd, ";\n");
+        if (!x->x_ninsig)
             fprintf(x->x_outfd, "0\n");
+        else for (i = 0; i < x->x_ninsig; i++)
+        {
+            t_sample *fp = x->x_insig[i];
+            for (j = 0; j < n; j++)
+                fprintf(x->x_outfd, "%g\n", *fp++);
+            for (; j < DEFDACBLKSIZE; j++)
+                fprintf(x->x_outfd, "0\n");
+        }
+        fprintf(x->x_outfd, ";\n");
     }
-    fprintf(x->x_outfd, ";\n");
     fflush(x->x_outfd);
-    i = j = 0;
-    while (1)
+    nsigs = j = 0;
+    if (x->x_binary)
     {
         while (1)
         {
-            c = getc(infd);
-            if (c == EOF)
+            t_atom at;
+            if (!pd_tilde_getatom(&at, infd))
             {
                 if (errno)
-                    ERROR "pd~: %s", strerror(errno));
-                else ERROR "pd~: subprocess exited");
+                    PDERROR "pd~: %s", strerror(errno));
+                else PDERROR "pd~: subprocess exited");
                 pd_tilde_close(x);
                 goto zeroit;
             }
-            else if (!isspace(c) && c != ';')
+            if (at.a_type == A_SEMI)
+                break;
+            else if (at.a_type == A_FLOAT)
             {
-                if (numbuffill < (80-1))
-                    numbuf[numbuffill++] = c;
+                if (nsigs < x->x_noutsig)
+                    x->x_outsig[nsigs][j] = at.a_w.w_float;
+                if (++j >= DEFDACBLKSIZE)
+                    j = 0, nsigs++;
             }
-            else
+            else PDERROR "pd~: subprocess returned malformed audio");
+        }
+    }
+    else
+    {
+        while (1)
+        {
+            while (1)
             {
-                t_sample z;
-                if (numbuffill)
+                c = getc(infd);
+                if (c == EOF)
                 {
-                    numbuf[numbuffill] = 0;
-                    if (sscanf(numbuf, "%f", &z) < 1)
-                        continue;
-                    if (i < x->x_noutsig)
-                        x->x_outsig[i][j] = z;
-                    if (++j >= DEFDACBLKSIZE)
-                        j = 0, i++;
+                    if (errno)
+                        PDERROR "pd~: %s", strerror(errno));
+                    else PDERROR "pd~: subprocess exited");
+                    pd_tilde_close(x);
+                    goto zeroit;
+                }
+                else if (!isspace(c) && c != ';')
+                {
+                    if (numbuffill < (80-1))
+                        numbuf[numbuffill++] = c;
+                }
+                else
+                {
+                    t_sample z;
+                    if (numbuffill)
+                    {
+                        numbuf[numbuffill] = 0;
+#if PD_FLOATSIZE == 32
+                        if (sscanf(numbuf, "%f", &z) < 1)
+#else
+                        if (sscanf(numbuf, "%lf", &z) < 1)
+#endif
+                            continue;
+                        if (nsigs < x->x_noutsig)
+                            x->x_outsig[nsigs][j] = z;
+                        if (++j >= DEFDACBLKSIZE)
+                            j = 0, nsigs++;
+                    }
+                    numbuffill = 0;
+                    break;
                 }
-                numbuffill = 0;
-                break;
             }
+            /* message terminated */
+            if (c == ';')
+                break;
         }
-        /* message terminated */
-        if (c == ';')
-            break;
     }
-    for (; i < x->x_noutsig; i++, j = 0)
+    if (nsigs < x->x_noutsig)
+        post("sigs %d, j %d", nsigs, j);
+    for (; nsigs < x->x_noutsig; nsigs++, j = 0)
     {
         for (; j < DEFDACBLKSIZE; j++)
-            x->x_outsig[i][j] = 0;
+            x->x_outsig[nsigs][j] = 0;
     }
     pd_tilde_readmessages(x);
     return (w+3);
@@ -370,7 +576,10 @@ static void pd_tilde_dsp(t_pd_tilde *x, t_signal **sp)
         
     for (i = 0, g = x->x_insig; i < x->x_ninsig; i++, g++)
         *g = (*(sp++))->s_vec;
-    
+        /* if there were no input signals Pd still provided us with one,
+        which we ignore: */
+    if (!x->x_ninsig)
+        sp++;
     for (i = 0, g = x->x_outsig; i < x->x_noutsig; i++, g++)
         *g = (*(sp++))->s_vec;
     
@@ -391,35 +600,9 @@ static void pd_tilde_pdtilde(t_pd_tilde *x, t_symbol *s,
         pdargstring[0] = 0;
         argc--; argv++;
 #ifdef PD
-        while (argc--)
-        {
-            atom_string(argv++, pdargstring + strlen(pdargstring), 
-                MAXPDSTRING - strlen(pdargstring));
-            if (strlen(pdargstring) < MAXPDSTRING-1)
-                strcat(pdargstring, " ");
-        }
         patchdir = canvas_getdir(x->x_canvas)->s_name;
 #endif
 #ifdef MSP
-        while (argc--)
-        {
-                /* because Mac pathnames sometimes have an evil preceeding
-                colon character, we test for and silently eat them */
-            if (argv->a_type == A_SYM)
-                strncat(pdargstring, (*argv->a_w.w_sym->s_name == ':'?
-                    argv->a_w.w_sym->s_name+1 : argv->a_w.w_sym->s_name),
-                    MAXPDSTRING - strlen(pdargstring)-3);
-            else if (argv->a_type == A_LONG)
-                snprintf(pdargstring+strlen(pdargstring),
-                    MAXPDSTRING - strlen(pdargstring)-3, "%ld",
-                        argv->a_w.w_long);
-            else if (argv->a_type == A_FLOAT)
-                snprintf(pdargstring+strlen(pdargstring),
-                    MAXPDSTRING - strlen(pdargstring)-3, "%f",
-                        argv->a_w.w_float);
-            strcat(pdargstring, " ");
-            argv++;
-        }
         patchdir = ".";
 #endif
         schedlibdir = x->x_schedlibdir;
@@ -433,7 +616,7 @@ static void pd_tilde_pdtilde(t_pd_tilde *x, t_symbol *s,
             schedlibdir = gensym(scheddirstring);
         }
         pd_tilde_donew(x, x->x_pddir->s_name, schedlibdir->s_name,
-            patchdir, pdargstring, x->x_ninsig, x->x_noutsig, x->x_fifo,
+            patchdir, argc, argv, x->x_ninsig, x->x_noutsig, x->x_fifo,
                 x->x_sr);
     }
     else if (sel == gensym("stop"))
@@ -452,9 +635,9 @@ static void pd_tilde_pdtilde(t_pd_tilde *x, t_symbol *s,
 #endif
             x->x_pddir = sym;
         }
-        else ERROR "pd~ pddir: needs symbol argument");
+        else PDERROR "pd~ pddir: needs symbol argument");
     }
-    else ERROR "pd~: unknown control message: %s", sel->s_name);
+    else PDERROR "pd~: unknown control message: %s", sel->s_name);
 }
 
 static void pd_tilde_free(t_pd_tilde *x)
@@ -473,14 +656,9 @@ static void pd_tilde_tick(t_pd_tilde *x)
 {
     int messstart = 0, i, n;
     t_atom *vec;
-    t_binbuf *b;
-    if (!x->x_msgbuf)
-        return;
-    b = binbuf_new();
-    binbuf_text(b, x->x_msgbuf, x->x_infill);
     /* binbuf_print(b); */
-    n = binbuf_getnatom(b);
-    vec = binbuf_getvec(b);
+    n = binbuf_getnatom(x->x_binbuf);
+    vec = binbuf_getvec(x->x_binbuf);
     for (i = 0; i < n; i++)
     {
         if (vec[i].a_type == A_SEMI)
@@ -493,8 +671,7 @@ static void pd_tilde_tick(t_pd_tilde *x)
             messstart = i+1;
         }
     }
-    binbuf_free(b);
-    x->x_infill = 0;
+    binbuf_clear(x->x_binbuf);
 }
 
 static void pd_tilde_anything(t_pd_tilde *x, t_symbol *s,
@@ -503,20 +680,36 @@ static void pd_tilde_anything(t_pd_tilde *x, t_symbol *s,
     char msgbuf[MAXPDSTRING];
     if (!x->x_outfd)
         return;
-    fprintf(x->x_outfd, "%s ", s->s_name);
-    while (argc--)
+    if (x->x_binary)
     {
-        atom_string(argv++, msgbuf, MAXPDSTRING);
-        fprintf(x->x_outfd, "%s ", msgbuf);
+        pd_tilde_putsymbol(s, x->x_outfd);
+        for (; argc--; argv++)
+        {
+            if (argv->a_type == A_FLOAT)
+                pd_tilde_putfloat(argv->a_w.w_float, x->x_outfd);
+            else if (argv->a_type == A_SYMBOL)
+                pd_tilde_putsymbol(argv->a_w.w_symbol, x->x_outfd);
+        }
+        putc(A_SEMI, x->x_outfd);
+    }
+    else
+    {
+        fprintf(x->x_outfd, "%s ", s->s_name);
+        while (argc--)
+        {
+            atom_string(argv++, msgbuf, MAXPDSTRING);
+            fprintf(x->x_outfd, "%s ", msgbuf);
+        }
+        fprintf(x->x_outfd, ";\n");
     }
-    fprintf(x->x_outfd, ";\n");
 }
 
+extern char *class_gethelpdir(t_class *c);
 static void *pd_tilde_new(t_symbol *s, int argc, t_atom *argv)
 {
     t_pd_tilde *x = (t_pd_tilde *)pd_new(pd_tilde_class);
-    int ninsig = 2, noutsig = 2, j, fifo = 5;
-    float sr = sys_getsr();
+    int ninsig = 2, noutsig = 2, j, fifo = 5, binary = 1;
+    t_float sr = sys_getsr();
     t_sample **g;
     t_symbol *pddir = sys_libdir,
         *scheddir = gensym(class_gethelpdir(pd_tilde_class));
@@ -554,6 +747,11 @@ static void *pd_tilde_new(t_symbol *s, int argc, t_atom *argv)
             scheddir = atom_getsymbolarg(1, argc, argv);
             argc -= 2; argv += 2;
         }
+        else if (!strcmp(firstarg->s_name, "-ascii"))
+        {
+            binary = 0;
+            argc--; argv++;
+        }
         else break;
     }
 
@@ -578,15 +776,17 @@ static void *pd_tilde_new(t_symbol *s, int argc, t_atom *argv)
     x->x_outfd = 0;
     x->x_outfd = 0;
     x->x_childpid = -1;
-    x->x_msgbuf = 0;
     x->x_canvas = canvas_getcurrent();
+    x->x_binbuf = binbuf_new();
+    x->x_binary = binary;
     for (j = 1, g = x->x_insig; j < ninsig; j++, g++)
         inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
     x->x_outlet1 = outlet_new(&x->x_obj, 0);
     for (j = 0, g = x->x_outsig; j < noutsig; j++, g++)
         outlet_new(&x->x_obj, &s_signal);
+#ifndef _WIN32
     signal(SIGPIPE, SIG_IGN);
-
+#endif
     return (x);
 }
 
@@ -598,11 +798,11 @@ void pd_tilde_setup(void)
     class_addmethod(pd_tilde_class, (t_method)pd_tilde_dsp, gensym("dsp"), 0);
     class_addmethod(pd_tilde_class, (t_method)pd_tilde_pdtilde, gensym("pd~"), A_GIMME, 0);
     class_addanything(pd_tilde_class, pd_tilde_anything);
-    post("pd~ version 0.2");
+    post("pd~ version 0.3");
 }
 #endif
 
-/* -------------------------- MSP glue ------------------------- */
+/* -------------------------- Max/MSP glue ------------------------- */
 #ifdef MSP
 
 #define LOTS 10000
@@ -612,13 +812,8 @@ static void pd_tilde_tick(t_pd_tilde *x)
     int messstart = 0, i, n = 0;
     t_atom vec[LOTS];
     long z1 = 0, z2 = 0;
-    void *b;
-    if (!x->x_msgbuf)
-        return;
-    b = binbuf_new();
-    binbuf_text(b, &x->x_msgbuf, x->x_infill);
     /* binbuf_print(b); */
-    while (!binbuf_getatom(b, &z1, &z2, vec+n))
+    while (!binbuf_getatom(x->x_binbuf, &z1, &z2, vec+n))
     if (++n >= LOTS)
         break;
     for (i = 0; i < n; i++)
@@ -641,8 +836,7 @@ static void pd_tilde_tick(t_pd_tilde *x)
             messstart = i+1;
         }
     }
-    binbuf_free(b);
-    x->x_infill = 0;
+    binbuf_clear(b);
 }
 
 static void pd_tilde_anything(t_pd_tilde *x, t_symbol *s,
@@ -688,14 +882,14 @@ int main()
 
     class_register(CLASS_BOX, c);
     pd_tilde_class = c;
-    post("pd~ version 0.2");
+    post("pd~ version 0.3");
     return (0);
 }
 
 static void *pd_tilde_new(t_symbol *s, long ac, t_atom *av)
 {
     int ninsig = 2, noutsig = 2, fifo = 5, j;
-    float sr = sys_getsr();
+    t_float sr = sys_getsr();
     t_symbol *pddir = gensym("."), *scheddir = gensym(".");
     t_pd_tilde *x;
 
@@ -759,7 +953,8 @@ static void *pd_tilde_new(t_symbol *s, long ac, t_atom *av)
         x->x_outfd = 0;
         x->x_outfd = 0;
         x->x_childpid = -1;
-        x->x_msgbuf = 0;
+        x->x_binbuf = binbuf_new();
+        x->x_binary = binary;
     }
     return (x);
 }
diff --git a/pd/nw/index.js b/pd/nw/index.js
index 67f65ec00f0b851f1a31b4ffd81300b452875854..ade8c18500964743bd6c90f81d660dcfbf0a941c 100644
--- a/pd/nw/index.js
+++ b/pd/nw/index.js
@@ -31,14 +31,19 @@ function have_args() {
 }
 
 function set_vars(win) {
-    var port_no, font_engine_sanity, pd_engine_id;
+    var port_no, font_engine_sanity, pd_engine_id, argv_offset;
     // If the GUI was started by Pd, our port number is going to be
     // the first argument. If the GUI is supposed to start Pd, we won't
     // have any arguments and need to set it here.
     if (have_args() && gui.App.argv.length > 1) {
-        port_no = gui.App.argv[0]; // fed to us by the Pd process
+        // Unfortunately there's a bug in nw.js where the argument that
+        // specifies the package.json path doesn't get included in the
+        // argv array. This happens under Windows and Linux but apparently
+        // not under OSX. That means we need an offset hack
+        argv_offset = process.platform === "darwin" ? 1 : 0;
+        port_no = gui.App.argv[1 + argv_offset]; // fed to us by the Pd process
         // address unique to the pd_engine
-        pd_engine_id = gui.App.argv[4];
+        pd_engine_id = gui.App.argv[5 + argv_offset];
     } else {
         // If we're starting Pd, this is the first port number to try. (We'll
         // increment it if that port happens to be taken.)
diff --git a/pd/src/makefile.mingw b/pd/src/makefile.mingw
index 14f7be93f92e5233c65942f3d18723860f444faf..47603b10a173cc248d7033e34b0e719d0cdfee65 100755
--- a/pd/src/makefile.mingw
+++ b/pd/src/makefile.mingw
@@ -224,7 +224,7 @@ pd.res: pd.rc
 
 # for making objects included with Pd, [expr] is whacky, so its built
 # separately, and pd~ doesn't build on Windows yet
-EXTERNALS_SRC := $(wildcard $(pd_src)/extra/[a-df-oq-z]*/*.c)
+EXTERNALS_SRC := $(wildcard $(pd_src)/extra/[a-z]*/*.c)
 #EXPR_SRC = vexp.c vexp_fun.c vexp_if.c
 #EXPR_OBJ =  $(patsubst %.c, $(pd_src)/extra/expr~/%.o, $(EXPR_SRC))
 #expr_src = $(pd_src)/extra/expr~
diff --git a/pd/src/s_inter.c b/pd/src/s_inter.c
index 7993fe6453e8222434d83cf26cb795b9c92decc0..486ae7b0c18ac86e5c33c7511fc59891fe8d81a2 100644
--- a/pd/src/s_inter.c
+++ b/pd/src/s_inter.c
@@ -1135,6 +1135,57 @@ static int defaultfontshit[MAXFONTS] = {
         24, 15, 28};
 #define NDEFAULTFONT (sizeof(defaultfontshit)/sizeof(*defaultfontshit))
 
+extern t_symbol *pd_getplatform(void);
+extern void sys_expandpath(const char *from, char *to);
+
+/* set the datadir for nwjs. We use the published nw.js
+   defaults if there's only one instance of the GUI set to
+   run. Otherwise, we append the port number so that
+   nw.js will spawn a new instance for us.
+
+   Currently, users can give a command line arg to force Pd
+   to start with a new GUI instance. A new GUI must also get
+   created when a user turns on audio and there is a [pd~] object
+   on the canvas. The latter would actually be more usable within
+   a single GUI instance, but that would require some way to
+   visually distinguish patches that are associated with different Pd
+   engine processes.
+*/ 
+
+static void set_datadir(char *buf, int new_gui_instance, int portno)
+{
+    char dir[FILENAME_MAX];
+    t_symbol *platform = pd_getplatform(); 
+    strcpy(buf, "--user-data-dir=");
+    /* Let's go ahead and quote the string to handle spaces in
+       paths, etc. */
+    strcat(buf, "\"");
+    if (platform == gensym("darwin"))
+        sys_expandpath("~/Library/Application Support/", dir);
+    else if (platform != gensym("win32"))/* bsd and linux */
+        sys_expandpath("~/.config/", dir);
+#ifdef _WIN32
+        /* win32 has a more robust API for getting the
+           value of %LOCALAPPDATA%, but this works on
+           Windows 7 and is straightforward... */
+        char *env = getenv("LOCALAPPDATA");
+        strcpy(dir, env);
+        strcat(dir, "\\");
+#endif
+    strcat(dir, "purr-data");
+    if (new_gui_instance)
+    {
+        char portbuf[10];
+        sprintf(portbuf, "-%d", portno);
+        strcat(dir, portbuf);
+    }
+    strcat(buf, dir);
+    /* Finally, close quote... */
+    strcat(buf, "\"");
+}
+
+extern int sys_unique;
+
 int sys_startgui(const char *guidir)
 {
     pid_t childpid;
@@ -1146,13 +1197,12 @@ int sys_startgui(const char *guidir)
     int xsock = -1;
     stderr_isatty = isatty(2);
 #ifdef MSW
-        if (GetCurrentDirectory(FILENAME_MAX, cwd) == 0)
-            strcpy(cwd, ".");
+    if (GetCurrentDirectory(FILENAME_MAX, cwd) == 0)
+        strcpy(cwd, ".");
 #endif
 #ifdef HAVE_UNISTD_H
-        if (!getcwd(cwd, FILENAME_MAX))
-            strcpy(cwd, ".");
-
+    if (!getcwd(cwd, FILENAME_MAX))
+        strcpy(cwd, ".");
 #endif
 #ifdef MSW
     short version = MAKEWORD(2, 0);
@@ -1272,7 +1322,6 @@ int sys_startgui(const char *guidir)
 
         /* assign server port number */
         server.sin_port =  htons((unsigned short)portno);
-
         /* name the socket */
         while (bind(xsock, (struct sockaddr *)&server, sizeof(server)) < 0)
         {
@@ -1325,7 +1374,8 @@ int sys_startgui(const char *guidir)
             /* this glob is needed so the Wish executable can have the same
              * filename as the Pd.app, i.e. 'Pd-0.42-3.app' should have a Wish
              * executable called 'Pd-0.42-3.app/Contents/MacOS/Pd-0.42-3' */
-            sprintf(embed_glob, "%s/../../MacOS/Pd*", guidir);
+//            sprintf(embed_glob, "%s/../../MacOS/Pd*", guidir);
+            sprintf(embed_glob, "%s/../../MacOS/nwjs", guidir);
             glob_buffer.gl_matchc = 1; /* we only need one match */
             glob(embed_glob, GLOB_LIMIT, NULL, &glob_buffer);
             if (glob_buffer.gl_pathc > 0) {
@@ -1342,37 +1392,74 @@ int sys_startgui(const char *guidir)
                     break;
             }
             sprintf(cmdbuf,"\"%s\" %s/pd.tk %d\n",wish_paths[i],guidir,portno);
+            char data_dir_flag[MAXPDSTRING];
+            set_datadir(data_dir_flag, sys_unique, portno);
+            /* Make a copy in case the user wants to change to the repo
+               dir while developing... */
+            char guidir2[MAXPDSTRING];
+            /* Let's go ahead and quote the path in case there are spaces
+               in it. This won't happen on a sane Linux/BSD setup. But it
+               will happen under Windows, so we quote here, too, for
+               the sake of consistency. */
+            strcpy(guidir2, "\"");
+            strcat(guidir2, guidir);
+            strcat(guidir2, "\"");
+            /* Uncomment the following line if you want to
+               use the nw binary and GUI code from your local
+               copy of the Purr Data repo. (Make sure to run
+               tar_em_up.sh first to fetch the nw binary.) */
+            //strcpy(guidir2, "\"/home/grieg/purr-data/pd/nw\"");
+            sprintf(cmdbuf,
+                "\"%s\" %s %s "
+                "%d localhost %s %s " X_SPECIFIER,
+                wish_paths[i],
+                data_dir_flag,
+                guidir2,
+                portno,
+                (sys_k12_mode ? "pd-l2ork-k12" : "pd-l2ork"),
+                guidir2,
+                (long unsigned int)pd_this);
 #else
             sprintf(cmdbuf,
                 "TCL_LIBRARY=\"%s/tcl/library\" TK_LIBRARY=\"%s/tk/library\" \
                  \"%s/pd-gui\" %d localhost %s\n",
                  sys_libdir->s_name, sys_libdir->s_name, guidir, portno, (sys_k12_mode ? "pd-l2ork-k12" : "pd-l2ork"));
 
-/* SUPERHACK - let's just load node-webkit and see what happens */
-//            sprintf(cmdbuf,
-//                  "/home/user/Downloads/nwjs-v0.12.2-linux-ia32/nw "
-//                  "/home/nu/Downloads/nwjs-v0.12.0-alpha2-linux-ia32/nw "
-//                "/home/user/pd-nw/pd/nw/ %d localhost %s\n",
-//                portno,
-//                (sys_k12_mode ? "pd-l2ork-k12" : "pd-l2ork"));
-
-fprintf(stderr, "guidir is %s\n", guidir);
+            fprintf(stderr, "guidir is %s\n", guidir);
 
             /* For some reason, the nw binary doesn't give you access to
                the first argument-- this is the path to the directory where
                package.json lives (or the zip file if it's compressed). So
                we add it again as the last argument to make sure we can fetch
                it on the GUI side. */
+            char data_dir_flag[MAXPDSTRING];
+            set_datadir(data_dir_flag, sys_unique, portno);
+
+            /* Make a copy in case the user wants to change to the repo
+               dir while developing... */
+            char guidir2[MAXPDSTRING];
+            /* Let's go ahead and quote the path in case there are spaces
+               in it. This won't happen on a sane Linux/BSD setup. But it
+               will happen under Windows, so we quote here, too, for
+               the sake of consistency. */
+            strcpy(guidir2, "\"");
+            strcat(guidir2, guidir);
+            strcat(guidir2, "\"");
+            /* Uncomment the following line if you want to
+               use the nw binary and GUI code from your local
+               copy of the Purr Data repo. (Make sure to run
+               tar_em_up.sh first to fetch the nw binary.) */
+            //strcpy(guidir2, "\"/home/grieg/purr-data/pd/nw\"");
             sprintf(cmdbuf,
-                "%s/nw/nw %s %d localhost %s %s " X_SPECIFIER,
-                guidir,
-                guidir,
-//                "/home/user/purr-data/pd/nw",
+                "%s/nw/nw %s %s "
+                "%d localhost %s %s " X_SPECIFIER,
+                guidir2,
+                data_dir_flag,
+                guidir2,
                 portno,
                 (sys_k12_mode ? "pd-l2ork-k12" : "pd-l2ork"),
-                guidir,
+                guidir2,
                 (long unsigned int)pd_this);
-
 #endif
             sys_guicmd = cmdbuf;
         }
@@ -1406,6 +1493,7 @@ fprintf(stderr, "guidir is %s\n", guidir);
                     close(stdinpipe[0]);
                 }
             }
+
 #endif
             execl("/bin/sh", "sh", "-c", sys_guicmd, (char*)0);
             perror("pd: exec");
@@ -1441,7 +1529,11 @@ fprintf(stderr, "guidir is %s\n", guidir);
         strcat(wishbuf, "/" PDBINDIR "nw/nw");
         sys_bashfilename(wishbuf, wishbuf);
 
-        spawnret = _spawnl(P_NOWAIT, wishbuf, "pd-nw", scriptbuf,
+        char data_dir_flag[MAXPDSTRING];
+        set_datadir(data_dir_flag, sys_unique, portno);
+        spawnret = _spawnl(P_NOWAIT, wishbuf, "pd-nw",
+            data_dir_flag,
+            scriptbuf,
             portbuf,
             "localhost",
             (sys_k12_mode ? "pd-l2ork-k12" : "pd-l2ork"),
diff --git a/pd/src/s_main.c b/pd/src/s_main.c
index b0b63c42d1923d9603ab4bc40bdd806f386565c5..cbfae74ed97149bf9e619985e66262d29dd07c63 100644
--- a/pd/src/s_main.c
+++ b/pd/src/s_main.c
@@ -485,7 +485,7 @@ static int sys_getmultidevchannels(int n, int *devlist)
 void sys_findprogdir(char *progname)
 {
     char *execdir = pd_getdirname()->s_name, *lastslash;
-    char sbuf[FILENAME_MAX], sbuf2[FILENAME_MAX];
+    char sbuf[FILENAME_MAX], sbuf2[FILENAME_MAX], appbuf[FILENAME_MAX];
     strncpy(sbuf, execdir, FILENAME_MAX-1);
 #ifndef MSW
     struct stat statbuf;
@@ -551,12 +551,20 @@ void sys_findprogdir(char *progname)
     else
     {
             /* simple layout: lib dir is the parent */
-        sys_libdir = gensym(sbuf);
             /* gui lives in .../bin */
         strncpy(sbuf2, sbuf, FILENAME_MAX-30);
+        strncpy(appbuf, sbuf, FILENAME_MAX-30);
         sbuf[FILENAME_MAX-30] = 0;
+        sys_libdir = gensym(sbuf);
         strcat(sbuf2, "/bin");
-        sys_guidir = gensym(sbuf2);
+        /* special case-- with the OSX app bundle the guidir is actually
+           in app.nw instead of app.nw/bin. So we check for a package.json
+           there and then set it accordingly. */
+        strcat(appbuf, "/package.json");
+        if (stat(appbuf, &statbuf) >= 0)
+            sys_guidir = gensym(sbuf);
+        else
+            sys_guidir = gensym(sbuf2);
     }
 #endif
 }
diff --git a/pd/src/s_path.c b/pd/src/s_path.c
index 5a2b6bdbb858abab1d7af16b29e204b9dc1bd827..a4b108cff4898947a525714ba5f38b8008105f8b 100644
--- a/pd/src/s_path.c
+++ b/pd/src/s_path.c
@@ -121,7 +121,7 @@ static void sys_path_replace(
 }
 
 /* expand env vars and ~ at the beginning of a path and make a copy to return */
-static void sys_expandpath(const char *from, char *to)
+void sys_expandpath(const char *from, char *to)
 {
     if ((strlen(from) == 1 && from[0] == '~') || (strncmp(from,"~/", 2) == 0))
     {
diff --git a/pd/src/x_interface.c b/pd/src/x_interface.c
index b35b7ec801679640f8f9418dba2af871571925c2..11ecd48fdef03ea6157775d857e9a3e42399d4ef 100644
--- a/pd/src/x_interface.c
+++ b/pd/src/x_interface.c
@@ -843,23 +843,28 @@ void pdinfo_libdir(t_pdinfo *x, t_symbol *s, int argc, t_atom *argv)
     info_out((t_text *)x, s, 1, at);
 }
 
-void pdinfo_platform(t_pdinfo *x, t_symbol *s, int argc, t_atom *argv)
+t_symbol* pd_getplatform(void)
 {
-    t_atom at[1];
-    t_symbol *p = gensym("unknown");
 #ifdef __APPLE__
-    p = gensym("darwin");
+    return gensym("darwin");
 #endif
 #ifdef __FreeBSD__
-    p = gensym("freebsd");
+    return gensym("freebsd");
 #endif
 #ifdef _WIN32
-    p = gensym("win32");
+    return gensym("win32");
 #endif
 #ifdef __linux__
-    p = gensym("linux");
+    return gensym("linux");
 #endif
-    SETSYMBOL(at, p);
+    /* don't know the platform... */
+    return gensym("unknown");
+}
+
+void pdinfo_platform(t_pdinfo *x, t_symbol *s, int argc, t_atom *argv)
+{
+    t_atom at[1];
+    SETSYMBOL(at, pd_getplatform());
     info_out((t_text *)x, s, 1, at);
 }