diff --git a/packages/win32_inno/Makefile b/packages/win32_inno/Makefile
index a198acb643eff42abfed413a5154edbfaeddc223..12b2f93c08262d54e184d41010ffa68f892c0d27 100755
--- a/packages/win32_inno/Makefile
+++ b/packages/win32_inno/Makefile
@@ -117,7 +117,7 @@ ifneq ($(LIGHT),yes)
 	# For other external libs
 	install -p $(bin_src)/lua53.dll          $(DESTDIR)$(bindir)/
 	#install -p $(bin_src)/pthreadGC2.dll     $(DESTDIR)$(bindir)/
-	install -p $(bin_src)/libdl.dll     $(DESTDIR)$(bindir)/
+	#install -p $(bin_src)/libdl.dll     $(DESTDIR)$(bindir)/
 	install -p $(bin_src)/libportaudio-2.dll     $(DESTDIR)$(bindir)/
 	install -p $(bin_src)/libFLAC-8.dll     $(DESTDIR)$(bindir)/
 	install -p $(bin_src)/libspeex-1.dll     $(DESTDIR)$(bindir)/
diff --git a/pd/doc/5.reference/soundfiler-help.pd b/pd/doc/5.reference/soundfiler-help.pd
index 3fa80f90aa9a124ffa45b2cf1916313baf18b7b3..f24e1a5d9ad55210eea5c24efec64f2332b3c70a 100644
--- a/pd/doc/5.reference/soundfiler-help.pd
+++ b/pd/doc/5.reference/soundfiler-help.pd
@@ -1,10 +1,10 @@
-#N canvas 429 34 555 619 10;
+#N canvas 75 64 555 619 10;
 #X obj 0 595 cnv 15 552 21 empty \$0-pddp.cnv.footer empty 20 12 0
-14 -228856 -66577 0;
+14 #dcdcdc #404040 0;
 #X obj 0 0 cnv 15 552 40 empty \$0-pddp.cnv.header soundfiler 3 12
-0 18 -204280 -1 0;
-#X obj 0 387 cnv 3 550 3 empty \$0-pddp.cnv.inlets inlets 8 12 0 13
--228856 -1 0;
+0 18 #c4dcdc #000000 0;
+#X obj 0 352 cnv 3 550 3 empty \$0-pddp.cnv.inlets inlets 8 12 0 13
+#dcdcdc #000000 0;
 #N canvas 490 283 494 344 META 0;
 #X text 12 105 LIBRARY internal;
 #X text 12 145 WEBSITE http://crca.ucsd.edu/~msp/;
@@ -19,16 +19,16 @@ Wilkes revised the patch to conform to the PDDP template for Pd version
 #X text 12 5 KEYWORDS control array filesystem;
 #X text 12 165 RELEASE_DATE 1997;
 #X restore 500 597 pd META;
-#X obj 0 487 cnv 3 550 3 empty \$0-pddp.cnv.outlets outlets 8 12 0
-13 -228856 -1 0;
+#X obj 0 452 cnv 3 550 3 empty \$0-pddp.cnv.outlets outlets 8 12 0
+13 #dcdcdc #000000 0;
 #X obj 0 529 cnv 3 550 3 empty \$0-pddp.cnv.argument arguments 8 12
-0 13 -228856 -1 0;
+0 13 #dcdcdc #000000 0;
 #X obj 0 554 cnv 3 550 3 empty \$0-pddp.cnv.more_info more_info 8 12
-0 13 -228856 -1 0;
+0 13 #dcdcdc #000000 0;
 #X text 98 533 (none);
 #N canvas 217 519 428 106 Related_objects 0;
 #X obj 0 1 cnv 15 425 20 empty \$0-pddp.cnv.subheading empty 3 12 0
-14 -204280 -1 0;
+14 #c4dcdc #000000 0;
 #X text 7 2 [soundfiler] Related Objects;
 #X obj 22 43 tabwrite~;
 #X obj 22 69 tabread4~;
@@ -36,16 +36,16 @@ Wilkes revised the patch to conform to the PDDP template for Pd version
 #X obj 143 69 writesf~;
 #X obj 87 69 readsf~;
 #X restore 102 597 pd Related_objects;
-#X obj 78 396 cnv 17 3 80 empty \$0-pddp.cnv.let.0 0 5 9 0 16 -228856
--162280 0;
-#X text 98 495 float;
-#X obj 78 496 cnv 17 3 17 empty \$0-pddp.cnv.let.0 0 5 9 0 16 -228856
--162280 0;
+#X obj 78 361 cnv 17 3 80 empty \$0-pddp.cnv.let.0 0 5 9 0 16 #dcdcdc
+#9c9c9c 0;
+#X text 98 460 float;
+#X obj 78 461 cnv 17 3 17 empty \$0-pddp.cnv.let.0 0 5 9 0 16 #dcdcdc
+#9c9c9c 0;
 #X obj 477 10 soundfiler;
 #X text 11 23 read and write soundfiles to arrays;
-#X text 98 395 read;
-#X text 98 412 write;
-#X text 168 495 - the output specifies the total number of samples
+#X text 98 360 read;
+#X text 98 377 write;
+#X text 168 460 - the output specifies the total number of samples
 that have been read or written.;
 #X obj 20 293 soundfiler;
 #X floatatom 20 317 0 0 0 0 - - -;
@@ -54,16 +54,16 @@ that have been read or written.;
 #X text 322 224 write a file;
 #X text 358 268 write stereo;
 #N canvas 0 0 450 300 (subpatch) 0;
-#X array sf-array1 77971 float 0;
-#X coords 0 1 77971 -1 130 70 1;
-#X restore 135 306 graph;
+#X array sf-array1 77971 float 0 black black;
+#X coords 0 1 77970 -1 130 50 1;
+#X restore 185 296 graph;
 #N canvas 0 0 450 300 (subpatch) 0;
-#X array sf-array2 77971 float 0;
-#X coords 0 1 77971 -1 130 70 1;
-#X restore 288 306 graph;
+#X array sf-array2 77971 float 0 black black;
+#X coords 0 1 77970 -1 130 50 1;
+#X restore 338 296 graph;
 #N canvas 110 93 428 434 flags 0;
 #X obj 0 0 cnv 15 425 20 empty \$0-pddp.cnv.subheading empty 3 12 0
-14 -204280 -1 0;
+14 #c4dcdc #000000 0;
 #X text 19 37 When reading you can leave soundfiler to figure out which
 of the three known soundfile formats the file belongs to or override
 all header information using the "-raw" flag.;
@@ -88,9 +88,9 @@ prefers.;
 #X text 17 400 The number of channels is limited to 64;
 #X text 37 371 -rate <sample rate>;
 #X text 7 1 [soundfiler] Flags;
-#X restore 172 459 pd flags;
-#X text 168 412 - write a soundfile.;
-#X text 169 428 The "read" and "write" messages accept flags. See the
+#X restore 172 424 pd flags;
+#X text 168 377 - write a soundfile.;
+#X text 169 393 The "read" and "write" messages accept flags. See the
 subpatch below for details:;
 #X msg 20 138 read ../sound/bell.aiff sf-array2;
 #X msg 20 161 read -resize ../sound/bell.aiff sf-array2;
@@ -102,7 +102,7 @@ subpatch below for details:;
 ;
 #X text 399 197 overriding everything;
 #X text 398 183 ...or even;
-#X text 168 395 - read a soundfile.;
+#X text 168 360 - read a soundfile.;
 #X text 17 41 The [soundfiler] object reads and writes floating point
 arrays to binary soundfiles which may contain 2 or 3 byte fixed point
 or 4 byte floating point samples in wave \, aiff \, or next formats
@@ -113,7 +113,14 @@ and unsupplied channels are zeroed out).;
 #X obj 4 597 pddp/pddplink all_about_help_patches.pd -text Usage Guide
 ;
 #X obj 98 575 pddp/pddplink all_about_arrays.pd;
+#X obj 78 497 cnv 17 3 17 empty \$0-pddp.cnv.let.0 0 5 9 0 16 #dcdcdc
+#9c9c9c 0;
+#X text 98 496 list;
+#X obj 77 318 print sf_stats;
+#X text 168 496 - stats for the file being read or written: <samplerate>
+<headersize> <nchannels> <bytespersample> <endianness>;
 #X connect 17 0 18 0;
+#X connect 17 1 43 0;
 #X connect 28 0 17 0;
 #X connect 29 0 17 0;
 #X connect 30 0 17 0;
diff --git a/pd/src/d_soundfile.c b/pd/src/d_soundfile.c
index e59b558f7778e5dd3577d4151e285f33b75e2f67..f0720e7c350d285fec6f8c36d740ddb862d83531 100644
--- a/pd/src/d_soundfile.c
+++ b/pd/src/d_soundfile.c
@@ -30,6 +30,7 @@ objects use Posix-like threads. */
 #include <string.h>
 #include <errno.h>
 #include <math.h>
+#include <limits.h>
 
 #include "m_pd.h"
 
@@ -207,6 +208,25 @@ static void swapstring(char *foo, int doit)
     }
 }
 
+    /* read sample rate from an 80-bit AIFF-compatible number */
+static double readaiffsamprate(char *shit, int swap)
+{
+    unsigned long mantissa, last = 0;
+    unsigned char exp;
+
+    swapstring(shit+2, swap);
+
+    mantissa = (unsigned long) *((unsigned long *)(shit+2));
+    exp = 30 - *(shit+1);
+    while (exp--)
+    {
+        last = mantissa;
+        mantissa >>= 1;
+    }
+    if (last & 0x00000001) mantissa++;
+        return mantissa;
+}
+
     /* write a sample rate as an 80-bit AIFF-compatible number */
 static void makeaiffsamprate(double sr, unsigned char *shit)
 {
@@ -224,6 +244,28 @@ static void makeaiffsamprate(double sr, unsigned char *shit)
 
 /******************** soundfile access routines **********************/
 
+typedef struct _soundfile_info
+{
+    int samplerate;
+    int channels;
+    int bytespersample;
+    int headersize;
+    int bigendian;
+    long bytelimit;
+} t_soundfile_info;
+
+static void outlet_soundfile_info(t_outlet *out, t_soundfile_info *info)
+{
+    t_atom info_list[5];
+    SETFLOAT((t_atom *)info_list, (t_float)info->samplerate);
+    SETFLOAT((t_atom *)info_list+1,
+        (t_float)(info->headersize < 0 ? 0 : info->headersize));
+    SETFLOAT((t_atom *)info_list+2, (t_float)info->channels);
+    SETFLOAT((t_atom *)info_list+3, (t_float)info->bytespersample);
+    SETSYMBOL((t_atom *)info_list+4, gensym((info->bigendian ? "b" : "l")));
+    outlet_list(out, &s_list, 5, (t_atom *)info_list);
+}
+
 /* 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
@@ -233,19 +275,20 @@ static void makeaiffsamprate(double sr, unsigned char *shit)
 * header and fill in the properties.
 */
 
-int open_soundfile_via_fd(int fd, int headersize,
-    int *p_bytespersamp, int *p_bigendian, int *p_nchannels, long *p_bytelimit,
-    long skipframes)
+int open_soundfile_via_fd(int fd, t_soundfile_info *p_info, long skipframes)
 {
-    int nchannels, bigendian, bytespersamp, swap, sysrtn;
-    long bytelimit = 0x7fffffff;
+    int nchannels, bigendian, bytespersamp, samprate, swap;
+    int headersize = 0;
+    long sysrtn, bytelimit = 0x7fffffff;
     errno = 0;
-    if (headersize >= 0) /* header detection overridden */
+    if (p_info->headersize >= 0) /* header detection overridden */
     {
-        bigendian = *p_bigendian;
-        nchannels = *p_nchannels;
-        bytespersamp = *p_bytespersamp;
-        bytelimit = *p_bytelimit;
+        headersize = p_info->headersize;
+        bigendian = p_info->bigendian;
+        nchannels = p_info->channels;
+        bytespersamp = p_info->bytespersample;
+        bytelimit = p_info->samplerate;
+        samprate = p_info->samplerate;
     }
     else
     {
@@ -288,6 +331,7 @@ int open_soundfile_via_fd(int fd, int headersize,
                 bytespersamp = 4;
             else goto badheader;
             bytelimit = 0x7fffffff;
+            samprate = swap4(((t_nextstep *)buf)->ns_sr, swap);
         }
         else if (format == FORMAT_WAVE)     /* wave header */
         {
@@ -302,6 +346,7 @@ int open_soundfile_via_fd(int fd, int headersize,
                 no "fmt" chunk to follow. */
             nchannels = 1;
             bytespersamp = 2;
+            samprate = 44100;
                 /* copy the first chunk header to beginnning of buffer. */
             memcpy(buf, buf + headersize, sizeof(t_wavechunk));
             /* post("chunk %c %c %c %c",
@@ -333,8 +378,10 @@ int open_soundfile_via_fd(int fd, int headersize,
                     else if (format == 32)
                         bytespersamp = 4;
                     else goto badheader;
+                    samprate = swap4(
+                        ((t_fmt *)buf)->f_samplespersec, swap);
                 }
-                seekout = lseek(fd, seekto, SEEK_SET);
+                seekout = (long)lseek(fd, seekto, SEEK_SET);
                 if (seekout != seekto)
                     goto badheader;
                 if (read(fd, buf, sizeof(t_wavechunk)) <
@@ -345,7 +392,7 @@ int open_soundfile_via_fd(int fd, int headersize,
                     ((t_wavechunk *)buf)->wc_id[1],
                     ((t_wavechunk *)buf)->wc_id[2],
                     ((t_wavechunk *)buf)->wc_id[3], seekto); */
-                headersize = seekto;
+                headersize = (int)seekto;
             }
             bytelimit = swap4(((t_wavechunk *)buf)->wc_size, swap);
             headersize += 8;
@@ -360,6 +407,7 @@ int open_soundfile_via_fd(int fd, int headersize,
                 no COMM block to follow. */
             nchannels = 1;
             bytespersamp = 2;
+            samprate = 44100;
                 /* 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 */
@@ -390,21 +438,23 @@ int open_soundfile_via_fd(int fd, int headersize,
                     else if (format == 24)
                         bytespersamp = 3;
                     else goto badheader;
+                    samprate = readaiffsamprate(
+                        (char *)((t_comm *)buf)->c_samprate, swap);
                 }
-                seekout = lseek(fd, seekto, SEEK_SET);
+                seekout = (long)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;
+                headersize = (int)seekto;
             }
             bytelimit = swap4(((t_datachunk *)buf)->dc_size, swap) - 8;
             headersize += sizeof(t_datachunk);
         }
     }
         /* seek past header and any sample frames to skip */
-    sysrtn = lseek(fd,
+    sysrtn = (long)lseek(fd,
         ((off_t)nchannels) * bytespersamp * skipframes + headersize, 0);
     if (sysrtn != nchannels * bytespersamp * skipframes + headersize)
         return (-1);
@@ -412,10 +462,12 @@ int open_soundfile_via_fd(int fd, int headersize,
      if (bytelimit < 0)
         bytelimit = 0;
         /* copy sample format back to caller */
-    *p_bigendian = bigendian;
-    *p_nchannels = nchannels;
-    *p_bytespersamp = bytespersamp;
-    *p_bytelimit = bytelimit;
+    p_info->headersize = headersize;
+    p_info->bigendian = bigendian;
+    p_info->channels = nchannels;
+    p_info->bytespersample = bytespersamp;
+    p_info->bytelimit = bytelimit;
+    p_info->samplerate = samprate;
     return (fd);
 badheader:
         /* the header wasn't recognized.  We're threadable here so let's not
@@ -427,17 +479,15 @@ badheader:
     /* open a soundfile, using open_via_path().  This is used by readsf~ in
     a not-perfectly-threadsafe way.  LATER replace with a thread-hardened
     version of open_soundfile_via_canvas() */
-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)
+int open_soundfile(const char *dirname, const char *filename,
+    t_soundfile_info *p_info, long skipframes)
 {
     char buf[FILENAME_MAX], *bufptr;
     int fd, sf_fd;
     fd = open_via_path(dirname, filename, "", buf, &bufptr, FILENAME_MAX, 1);
     if (fd < 0)
         return (-1);
-    sf_fd = open_soundfile_via_fd(fd, headersize, p_bytespersamp,
-        p_bigendian, p_nchannels, p_bytelimit, skipframes);
+    sf_fd = open_soundfile_via_fd(fd, p_info, skipframes);
     if (sf_fd < 0)
         sys_close(fd);
     return (sf_fd);
@@ -446,17 +496,15 @@ int open_soundfile(const char *dirname, const char *filename, int headersize,
     /* open a soundfile, using open_via_canvas().  This is used by readsf~ in
     a not-perfectly-threadsafe way.  LATER replace with a thread-hardened
     version of open_soundfile_via_canvas() */
-int open_soundfile_via_canvas(t_canvas *canvas, const char *filename, int headersize,
-    int *p_bytespersamp, int *p_bigendian, int *p_nchannels, long *p_bytelimit,
-    long skipframes)
+int open_soundfile_via_canvas(t_canvas *canvas, const char *filename,
+    t_soundfile_info *p_info, long skipframes)
 {
     char buf[FILENAME_MAX], *bufptr;
     int fd, sf_fd;
     fd = canvas_open(canvas, filename, "", buf, &bufptr, FILENAME_MAX, 1);
     if (fd < 0)
         return (-1);
-    sf_fd = open_soundfile_via_fd(fd, headersize, p_bytespersamp,
-        p_bigendian, p_nchannels, p_bytelimit, skipframes);
+    sf_fd = open_soundfile_via_fd(fd, p_info, skipframes);
     if (sf_fd < 0)
         sys_close(fd);
     return (sf_fd);
@@ -464,7 +512,7 @@ int open_soundfile_via_canvas(t_canvas *canvas, const char *filename, int header
 
 static void soundfile_xferin_sample(int sfchannels, int nvecs, t_sample **vecs,
     long itemsread, unsigned char *buf, int nitems, int bytespersamp,
-    int bigendian, int spread)
+    int bigendian)
 {
     int i, j;
     unsigned char *sp, *sp2;
@@ -478,14 +526,14 @@ static void soundfile_xferin_sample(int sfchannels, int nvecs, t_sample **vecs,
         {
             if (bigendian)
             {
-                for (j = 0, sp2 = sp, fp=vecs[i] + spread * itemsread;
-                    j < nitems; j++, sp2 += bytesperframe, fp += spread)
+                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] + spread * itemsread;
-                    j < nitems; j++, sp2 += bytesperframe, fp += spread)
+                for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+                    j < nitems; j++, sp2 += bytesperframe, fp ++)
                         *fp = SCALE * ((sp2[1] << 24) | (sp2[0] << 16));
             }
         }
@@ -493,15 +541,15 @@ static void soundfile_xferin_sample(int sfchannels, int nvecs, t_sample **vecs,
         {
             if (bigendian)
             {
-                for (j = 0, sp2 = sp, fp=vecs[i] + spread * itemsread;
-                    j < nitems; j++, sp2 += bytesperframe, fp += spread)
+                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] + spread * itemsread;
-                    j < nitems; j++, sp2 += bytesperframe, fp += spread)
+                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));
             }
@@ -510,8 +558,8 @@ static void soundfile_xferin_sample(int sfchannels, int nvecs, t_sample **vecs,
         {
             if (bigendian)
             {
-                for (j = 0, sp2 = sp, fp=vecs[i] + spread * itemsread;
-                     j < nitems; j++, sp2 += bytesperframe, fp += spread)
+                for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+                     j < nitems; j++, sp2 += bytesperframe, fp++)
                     {
                         alias.ui = ((sp2[0] << 24) | (sp2[1] << 16)
                             | (sp2[2] << 8) | sp2[3]);
@@ -520,8 +568,8 @@ static void soundfile_xferin_sample(int sfchannels, int nvecs, t_sample **vecs,
             }
             else
             {
-                for (j = 0, sp2 = sp, fp=vecs[i] + spread * itemsread;
-                     j < nitems; j++, sp2 += bytesperframe, fp += spread)
+                for (j = 0, sp2 = sp, fp=vecs[i] + itemsread;
+                     j < nitems; j++, sp2 += bytesperframe, fp++)
                     {
                         alias.ui = ((sp2[3] << 24) | (sp2[2] << 16)
                             | (sp2[1] << 8) | sp2[0]);
@@ -626,115 +674,294 @@ static void soundfile_xferin_float(int sfchannels, int nvecs, t_float **vecs,
         -little
     */
 
+
+static void argerror(void *obj, t_symbol *s, int argc, t_atom *argv,
+    const char *fmt, ...)
+{
+    char error_str[MAXPDSTRING];
+    char *user_msg; /* message from user that triggered the error */
+    int len;
+    char *classname = class_getname(pd_class((t_pd *)obj));
+    va_list ap;
+    t_binbuf *b = binbuf_new();
+    va_start(ap, fmt);
+    vsnprintf(error_str, MAXPDSTRING-1, fmt, ap);
+    va_end(ap);
+
+    binbuf_addv(b, "s", s);
+    binbuf_add(b, argc, argv);
+    binbuf_gettext(b, &user_msg, &len); /* not null-terminated! */
+    
+    pd_error(obj, "%s: '%.*s': %s",
+        classname,
+        len < MAXPDSTRING ? len : MAXPDSTRING,
+        user_msg,
+        error_str);
+}
+
+static int flag_missing_floatarg(void *obj, t_symbol *s, int argc,
+    t_atom *argv, char *flag, int flagc, t_atom *flagv)
+{
+        /* First check if our flag has an arg at all. If not, error out.
+           (flagc includes the flag itself.) */
+    if (flagc < 2)
+    {
+        argerror(obj, s, argc, argv,
+            "'%s' flag expects a float argument", flag);
+        return 1;
+    }
+    if (flagv[1].a_type != A_FLOAT)
+    {
+        argerror(obj, s, argc, argv, "'%s' flag expects a float but got '%s'",
+           flag,
+           flagv[1].a_type == A_SYMBOL ?
+           flagv[1].a_w.w_symbol->s_name :
+           "unexpected arg type");
+        return 1;
+    }
+    return 0;
+}
+
+static int flag_has_unexpected_floatarg(void *obj, t_symbol *s,
+    int argc, t_atom *argv, char *flag, int flagc, t_atom *flagv)
+{
+    if (flagc < 2) return 0;
+    if (flagv[1].a_type == A_FLOAT)
+    {
+        argerror(obj, s, argc, argv,
+            "'%s' flag does not accept a float argument", flag);
+        return 1;
+    }
+    return 0;
+}
+
+    /* catch filenames that are flags, with and without pre-fixed '-' */
+static int file_is_a_flag_name(t_symbol *sym, int *nodash)
+{
+    char *s = sym->s_name;
+    if (s[0] == '-')
+    {
+        s++;
+        *nodash = 1;
+    }
+    else
+        *nodash = 0;
+
+    if (!strcmp(s, "skip")
+        || !strcmp(s, "nframes")
+        || !strcmp(s, "bytes")
+        || !strcmp(s, "normalize")
+        || !strcmp(s, "wave")
+        || !strcmp(s, "nextstep")
+        || !strcmp(s, "aiff")
+        || !strcmp(s, "big")
+        || !strcmp(s, "little")
+        || !strcmp(s, "r")
+        || !strcmp(s, "rate"))
+    {
+        return 1;
+    }
+    else
+        return 0;
+}
+
     /* 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"
+    errors.  For streaming to a file the "normalize", "skip" 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,
+    /* Also note that streaming objects like writesf~ don't take args after
+       the filename, while soundfiler does to specify the source tables */
+static int soundfiler_writeargparse(void *obj, t_symbol *s,
+    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, t_float *p_rate)
 {
+    /* copies for convenience, and for the ruthless mutation below. :) */
     int argc = *p_argc;
+    int ac = argc;
     t_atom *argv = *p_argv;
+    t_atom *av = argv;
     int bytespersamp = 2, bigendian = 0,
         endianness = -1, swap, filetype = -1, normalize = 0;
     long onset = 0, nframes = 0x7fffffff;
     t_symbol *filesym;
     t_float rate = -1;
     
-    while (argc > 0 && argv->a_type == A_SYMBOL &&
-        *argv->a_w.w_symbol->s_name == '-')
+    while (ac > 0 && atom_getsymbol(av)->s_name[0] == '-')
     {
-        char *flag = argv->a_w.w_symbol->s_name + 1;
-        if (!strcmp(flag, "skip"))
+        char *flag = av->a_w.w_symbol->s_name;
+        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;
+            if (flag_missing_floatarg(obj, s, argc, argv, flag, ac, av))
+                goto usage;
+            if ((onset = av[1].a_w.w_float) < 0)
+            {
+                argerror(obj, s, argc, argv,
+                    "'-skip' flag does not allow a negative number");
+                goto usage;
+            }
+            ac -= 2; av += 2;
         }
-        else if (!strcmp(flag, "nframes"))
+        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;
+            if (flag_missing_floatarg(obj, s, argc, argv, flag, ac, av))
+                goto usage;
+            if ((nframes = av[1].a_w.w_float) < 0)
+            {
+                argerror(obj, s, argc, argv,
+                    "'-nframes' flag does not allow a negative number");
+                goto usage;
+            }
+            ac -= 2; av += 2;
         }
-        else if (!strcmp(flag, "bytes"))
+        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;
+            if (flag_missing_floatarg(obj, s, argc, argv, flag, ac, av))
+                goto usage;
+            if ((bytespersamp = av[1].a_w.w_float) < 2 ||
+                   bytespersamp > 4)
+            {
+                argerror(obj, s, argc, argv,
+                    "'-bytes' flag requires a number between 2 and 4");
+                goto usage;
+            }
+            ac -= 2; av += 2;
         }
-        else if (!strcmp(flag, "normalize"))
+        else if (!strcmp(flag, "-normalize"))
         {
+            if (flag_has_unexpected_floatarg(obj, s, argc, argv,
+                flag, ac, av))
+            {
+                goto usage;
+            }
             normalize = 1;
-            argc -= 1; argv += 1;
+            ac -= 1; av += 1;
         }
-        else if (!strcmp(flag, "wave"))
+        else if (!strcmp(flag, "-wave"))
         {
+            if (flag_has_unexpected_floatarg(obj, s, argc, argv,
+                flag, ac, av))
+            {
+                goto usage;
+            }
             filetype = FORMAT_WAVE;
-            argc -= 1; argv += 1;
+            ac -= 1; av += 1;
         }
-        else if (!strcmp(flag, "nextstep"))
+        else if (!strcmp(flag, "-nextstep"))
         {
+            if (flag_has_unexpected_floatarg(obj, s, argc, argv,
+                flag, ac, av))
+            {
+                goto usage;
+            }
             filetype = FORMAT_NEXT;
-            argc -= 1; argv += 1;
+            ac -= 1; av += 1;
         }
-        else if (!strcmp(flag, "aiff"))
+        else if (!strcmp(flag, "-aiff"))
         {
+            if (flag_has_unexpected_floatarg(obj, s, argc, argv,
+                flag, ac, av))
+            {
+                goto usage;
+            }
             filetype = FORMAT_AIFF;
-            argc -= 1; argv += 1;
+            ac -= 1; av += 1;
         }
-        else if (!strcmp(flag, "big"))
+        else if (!strcmp(flag, "-big"))
         {
+            if (flag_has_unexpected_floatarg(obj, s, argc, argv,
+                flag, ac, av))
+            {
+                goto usage;
+            }
             endianness = 1;
-            argc -= 1; argv += 1;
+            ac -= 1; av += 1;
         }
-        else if (!strcmp(flag, "little"))
+        else if (!strcmp(flag, "-little"))
         {
+            if (flag_has_unexpected_floatarg(obj, s, argc, argv,
+                flag, ac, av))
+            {
+                goto usage;
+            }
             endianness = 0;
-            argc -= 1; argv += 1;
+            ac -= 1; av += 1;
         }
-        else if (!strcmp(flag, "r") || !strcmp(flag, "rate"))
+        else if (!strcmp(flag, "-r") || !strcmp(flag, "-rate"))
         {
-            if (argc < 2 || argv[1].a_type != A_FLOAT ||
-                ((rate = argv[1].a_w.w_float) <= 0))
-                    goto usage;
-            argc -= 2; argv += 2;
+            if (flag_missing_floatarg(obj, s, argc, argv,
+                flag, ac, av))
+            {
+                goto usage;
+            }
+            if ((rate = av[1].a_w.w_float) <= 0)
+            {
+                argerror(obj, s, argc, argv,
+                    "'%s' flag must have a float arg greater than zero", flag);
+                goto usage;
+            }
+            ac -= 2; av += 2;
+        }
+        else
+        {
+            argerror(obj, s, argc, argv, "unknown flag '%s'", flag);
+            goto usage;
         }
-        else goto usage;
     }
-    if (!argc || argv->a_type != A_SYMBOL)
+    if (ac < 1)
+    {
+            /* a bit tricky-- writesf~ "open" method doesn't need table args */
+        argerror(obj, s, argc, argv, "%s",
+            s == gensym("open") ? "need a filename" :
+            "need a filename and table argument(s)");
         goto usage;
-    filesym = argv->a_w.w_symbol;
-    
+    }
+        /* Now that we know we have at least one arg, let's make sure it's
+           a symbol. */
+    if (av->a_type != A_SYMBOL)
+    {
+        argerror(obj, s, argc, argv, "filename must be a symbol");
+        goto usage;
+    }
+    filesym = av->a_w.w_symbol;
+        /* check if filesym is a flag name, and warn if so. */
+    int nodash;
+    if (file_is_a_flag_name(filesym, &nodash))
+    {
+        post("warning: filename '%s' looks like a flag%s",
+            filesym->s_name, nodash ? " name" : "");
+    }
         /* check if format not specified and fill in */
     if (filetype < 0) 
     {
         if (strlen(filesym->s_name) >= 5 &&
-                        (!strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".aif") ||
-                        !strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".AIF")))
-                filetype = FORMAT_AIFF;
+             (!strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".aif") ||
+              !strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".AIF")))
+        {
+            filetype = FORMAT_AIFF;
+        }
         if (strlen(filesym->s_name) >= 6 &&
-                        (!strcmp(filesym->s_name + strlen(filesym->s_name) - 5, ".aiff") ||
-                        !strcmp(filesym->s_name + strlen(filesym->s_name) - 5, ".AIFF")))
-                filetype = FORMAT_AIFF;
+             (!strcmp(filesym->s_name + strlen(filesym->s_name) - 5, ".aiff") ||
+              !strcmp(filesym->s_name + strlen(filesym->s_name) - 5, ".AIFF")))
+        {
+            filetype = FORMAT_AIFF;
+        }
         if (strlen(filesym->s_name) >= 5 &&
-                        (!strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".snd") ||
-                        !strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".SND")))
-                filetype = FORMAT_NEXT;
+             (!strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".snd") ||
+              !strcmp(filesym->s_name + strlen(filesym->s_name) - 4, ".SND")))
+        {
+            filetype = FORMAT_NEXT;
+        }
         if (strlen(filesym->s_name) >= 4 &&
-                        (!strcmp(filesym->s_name + strlen(filesym->s_name) - 3, ".au") ||
-                        !strcmp(filesym->s_name + strlen(filesym->s_name) - 3, ".AU")))
-                filetype = FORMAT_NEXT;
+             (!strcmp(filesym->s_name + strlen(filesym->s_name) - 3, ".au") ||
+              !strcmp(filesym->s_name + strlen(filesym->s_name) - 3, ".AU")))
+        {
+            filetype = FORMAT_NEXT;
+        }
         if (filetype < 0)
             filetype = FORMAT_WAVE;
     }
@@ -743,7 +970,8 @@ static int soundfiler_writeargparse(void *obj, int *p_argc, t_atom **p_argv,
     {
         if (filetype == FORMAT_AIFF)
         {
-            pd_error(obj, "AIFF floating-point file format unavailable");
+            argerror(obj, s, argc, argv,
+                "AIFF floating-point file format unavailable");
             goto usage;
         }
     }
@@ -767,10 +995,10 @@ static int soundfiler_writeargparse(void *obj, int *p_argc, t_atom **p_argv,
     else bigendian = endianness;
     swap = (bigendian != garray_ambigendian());
     
-    argc--; argv++;
+    ac--; av++;
     
-    *p_argc = argc;
-    *p_argv = argv;
+    *p_argc = ac;
+    *p_argv = av;
     *p_filesym = filesym;
     *p_filetype = filetype;
     *p_bytespersamp = bytespersamp;
@@ -785,9 +1013,11 @@ usage:
     return (-1);
 }
 
+    /* p_headersize is a getter, set to NULL if not needed */
 static int create_soundfile(t_canvas *canvas, const char *filename,
-    int filetype, int nframes, int bytespersamp,
-    int bigendian, int nchannels, int swap, t_float samplerate)
+    int filetype, long nframes, int bytespersamp,
+    int bigendian, int nchannels, int swap, t_float samplerate,
+    int *p_headersize)
 {
     char filenamebuf[FILENAME_MAX], buf2[FILENAME_MAX];
     char headerbuf[WRITEHDRSIZE];
@@ -804,8 +1034,8 @@ static int create_soundfile(t_canvas *canvas, const char *filename,
         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);
+            memcpy(nexthdr->ns_fileid, ".snd", 4);
+        else memcpy(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 :
@@ -823,18 +1053,19 @@ static int create_soundfile(t_canvas *canvas, const char *filename,
         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);
+        memcpy(aiffhdr->a_fileid, "FORM", 4);
+        aiffhdr->a_chunksize = swap4((uint32_t)(datasize +
+            sizeof(*aiffhdr) + 4), swap);
+        memcpy(aiffhdr->a_aiffid, "AIFF", 4);
+        memcpy(aiffhdr->a_fmtid, "COMM", 4);
         aiffhdr->a_fmtchunksize = swap4(18, swap);
         aiffhdr->a_nchannels = swap2(nchannels, swap);
-        longtmp = swap4(nframes, swap);
+        longtmp = swap4((uint32_t)nframes, swap);
         memcpy(&aiffhdr->a_nframeshi, &longtmp, 4);
         aiffhdr->a_bitspersamp = swap2(8 * bytespersamp, swap);
         makeaiffsamprate(samplerate, aiffhdr->a_samprate);
-        strncpy(((char *)(&aiffhdr->a_samprate))+10, "SSND", 4);
-        longtmp = swap4(datasize + 8, swap);
+        memcpy(((char *)(&aiffhdr->a_samprate))+10, "SSND", 4);
+        longtmp = swap4((uint32_t)(datasize + 8), swap);
         memcpy(((char *)(&aiffhdr->a_samprate))+14, &longtmp, 4);
         memset(((char *)(&aiffhdr->a_samprate))+18, 0, 8);
         headersize = AIFFPLUS;
@@ -844,10 +1075,11 @@ static int create_soundfile(t_canvas *canvas, const char *filename,
         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);
+        memcpy(wavehdr->w_fileid, "RIFF", 4);
+        wavehdr->w_chunksize = swap4((uint32_t)(datasize +
+            sizeof(*wavehdr) - 8), swap);
+        memcpy(wavehdr->w_waveid, "WAVE", 4);
+        memcpy(wavehdr->w_fmtid, "fmt ", 4);
         wavehdr->w_fmtchunksize = swap4(16, swap);
         wavehdr->w_fmttag =
             swap2((bytespersamp == 4 ? WAV_FLOAT : WAV_INT), swap);
@@ -857,11 +1089,10 @@ static int create_soundfile(t_canvas *canvas, const char *filename,
             swap4((int)(samplerate * nchannels * bytespersamp), swap);
         wavehdr->w_nblockalign = swap2(nchannels * bytespersamp, swap);
         wavehdr->w_nbitspersample = swap2(8 * bytespersamp, swap);
-        strncpy(wavehdr->w_datachunkid, "data", 4);
-        wavehdr->w_datachunksize = swap4(datasize, swap);
+        memcpy(wavehdr->w_datachunkid, "data", 4);
+        wavehdr->w_datachunksize = swap4((uint32_t)datasize, swap);
         headersize = sizeof(t_wave);
     }
-
     canvas_makefilename(canvas, filenamebuf, buf2, FILENAME_MAX);
     sys_bashfilename(buf2, buf2);
     if ((fd = sys_open(buf2, BINCREATE, 0666)) < 0)
@@ -872,6 +1103,8 @@ static int create_soundfile(t_canvas *canvas, const char *filename,
         sys_close (fd);
         return (-1);
     }
+    if (p_headersize)
+        *p_headersize = headersize;
     return (fd);
 }
 
@@ -892,14 +1125,14 @@ static void soundfile_finishwrite(void *obj, char *filename, int fd,
                 ((char *)(&((t_wave *)0)->w_chunksize)) - (char *)0,
                     SEEK_SET) == 0)
                         goto baddonewrite;
-            mofo = swap4(datasize + sizeof(t_wave) - 8, swap);
+            mofo = swap4((uint32_t)(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);
+            mofo = swap4((uint32_t)datasize, swap);
             if (write(fd, (char *)(&mofo), 4) < 4)
                 goto baddonewrite;
         }
@@ -910,26 +1143,26 @@ static void soundfile_finishwrite(void *obj, char *filename, int fd,
                 ((char *)(&((t_aiff *)0)->a_nframeshi)) - (char *)0,
                     SEEK_SET) == 0)
                         goto baddonewrite;
-            mofo = swap4(itemswritten, swap);
+            mofo = swap4((uint32_t)itemswritten, swap);
             if (write(fd, (char *)(&mofo), 4) < 4)
                 goto baddonewrite;
             if (lseek(fd,
                 ((char *)(&((t_aiff *)0)->a_chunksize)) - (char *)0,
                     SEEK_SET) == 0)
                         goto baddonewrite;
-            mofo = swap4(itemswritten*bytesperframe+AIFFHDRSIZE, swap);
+            mofo = swap4((uint32_t)itemswritten*bytesperframe+AIFFHDRSIZE, swap);
             if (write(fd, (char *)(&mofo), 4) < 4)
                 goto baddonewrite;
             if (lseek(fd, (AIFFHDRSIZE+4), SEEK_SET) == 0)
                 goto baddonewrite;
-            mofo = swap4(itemswritten*bytesperframe, swap);
+            mofo = swap4((uint32_t)itemswritten*bytesperframe, swap);
             if (write(fd, (char *)(&mofo), 4) < 4)
                 goto baddonewrite;
         }
         if (filetype == FORMAT_NEXT)
         {
             /* do it the lazy way: just set the size field to 'unknown size'*/
-            uint32 nextsize = 0xffffffff;
+            uint32_t nextsize = 0xffffffff;
             if (lseek(fd, 8, SEEK_SET) == 0)
             {
                 goto baddonewrite;
@@ -1165,7 +1398,7 @@ static void soundfile_xferout_float(int nchannels, t_float **vecs,
 }
 
 /* ------- soundfiler - reads and writes soundfiles to/from "garrays" ---- */
-#define DEFMAXSIZE 4000000      /* default maximum 16 MB per channel */
+#define DEFMAXSIZE 0x7fffffff /* default maximum 16 MB per channel */
 #define SAMPBUFSIZE 1024
 
 
@@ -1174,6 +1407,7 @@ static t_class *soundfiler_class;
 typedef struct _soundfiler
 {
     t_object x_obj;
+    t_outlet *x_out2;
     t_canvas *x_canvas;
 } t_soundfiler;
 
@@ -1182,9 +1416,54 @@ 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);
+    x->x_out2 = outlet_new(&x->x_obj, &s_float);
     return (x);
 }
 
+static void soundfiler_readascii(t_soundfiler *x, char *filename,
+    int narray, t_garray **garrays, t_word **vecs, int resize, int finalsize)
+{
+    t_binbuf *b = binbuf_new();
+    int n, i, j, nframes, vecsize;
+    t_atom *atoms, *ap;
+    if (binbuf_read_via_canvas(b, filename, x->x_canvas, 0))
+        return;
+    n = binbuf_getnatom(b);
+    atoms = binbuf_getvec(b);
+    nframes = n/narray;
+    if (nframes < 1)
+    {
+        binbuf_free(b);
+        pd_error(x, "soundfiler_read: %s: empty or very short file", filename);
+        return;
+    }
+
+    if (resize)
+    {
+        for (i = 0; i < narray; i++)
+        {
+            garray_resize_long(garrays[i], nframes);
+            if (!garray_getfloatwords(garrays[i], &vecsize, &vecs[i]))
+                bug("garray_getfloatwords[%d]", i);
+        }
+    }
+    else if (finalsize < nframes)
+        nframes = finalsize;
+    for (j = 0, ap = atoms; j < nframes; j++)
+        for (i = 0; i < narray; i++)
+            vecs[i][j].w_float = atom_getfloat(ap++);
+        /* zero out remaining elements of vectors */
+    for (i = 0; i < narray; i++)
+    {
+        int vecsize;
+        if (garray_getfloatwords(garrays[i], &vecsize, &vecs[i]))
+        for (j = nframes; j < vecsize; j++)
+            vecs[i][j].w_float = 0;
+    }
+    for (i = 0; i < narray; i++)
+        garray_redraw(garrays[i]);
+}
+
     /* soundfiler_read ...
     
     usage: read [flags] filename table ...
@@ -1196,13 +1475,21 @@ static t_soundfiler *soundfiler_new(void)
         -maxsize <max-size>
     */
 
+#define RAWSYNTAX "'-raw' flag syntax: " \
+                  "<headersize> <channels> <bytespersample> " \
+                  "<endianness: 'b' for big, 'l' for little, 'n' for auto>"
+
 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;
+    /* copies of argc, argv so we can iterate without mutating
+       the originals (needed for error reporting below) */
+    int ac = argc;
+    t_atom *av = argv;
+    t_soundfile_info info;
+    int resize = 0, i, j;
     long skipframes = 0, finalsize = 0,
-        maxsize = DEFMAXSIZE, itemsread = 0, bytelimit  = 0x7fffffff;
+        maxsize = DEFMAXSIZE, itemsread = 0;
     int fd = -1;
     char endianness, *filename;
     t_garray *garrays[MAXSFCHANS];
@@ -1210,75 +1497,193 @@ static void soundfiler_read(t_soundfiler *x, t_symbol *s,
     char sampbuf[SAMPBUFSIZE];
     int bufframes, nitems;
     FILE *fp;
-    while (argc > 0 && argv->a_type == A_SYMBOL &&
-        *argv->a_w.w_symbol->s_name == '-')
+    int ascii = 0;
+    info.samplerate = 0;
+    info.channels = 0;
+    info.bytespersample = 0;
+    info.headersize = -1;
+    info.bigendian = 0;
+    info.bytelimit = 0x7fffffff;
+    while (ac > 0 && atom_getsymbol(av)->s_name[0] == '-')
     {
-        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, "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;
+        char *flag = av->a_w.w_symbol->s_name;
+        if (!strcmp(flag, "-skip"))
+        {
+            if (flag_missing_floatarg(x, s, argc, argv, flag, ac, av))
+                goto done;
+            if ((skipframes = av[1].a_w.w_float) < 0)
+            {
+                argerror(x, s, argc, argv,
+                    "'-skip' flag does not allow a negative number");
+                goto done;
+            }
+            ac -= 2; av += 2;
+        }
+        else if (!strcmp(flag, "-ascii"))
+        {
+            if (info.headersize >= 0)
+                post("soundfiler_read: '-raw' overidden by '-ascii'");
+            ascii = 1;
+            ac--; av++;
+        }
+        else if (!strcmp(flag, "-raw"))
+        {
+            if (ascii)
+                post("soundfiler_read: '-raw' overridden by '-ascii'");
+            if (ac < 5)
+            {
+                argerror(x, s, argc, argv,
+                    "'-raw' flag needs four arguments\n" RAWSYNTAX);
+                goto done;
+            }
+            if (av[1].a_type != A_FLOAT)
+            {
+                argerror(x, s, argc, argv,
+                  "'-raw' flag needs a float for the headersize\n" RAWSYNTAX);
+                goto done;
+            }
+            info.headersize = av[1].a_w.w_float;
+            if (info.headersize < 0)
+            {
+                argerror(x, s, argc, argv,
+                    "'-raw' headersize cannot be less than zero\n"RAWSYNTAX);
+                goto done;
+            }
+            if (av[2].a_type != A_FLOAT)
+            {
+                argerror(x, s, argc, argv,
+                  "'-raw' flag needs a float to specify channels\n"RAWSYNTAX);
+                goto done;
+            }
+            info.channels = av[2].a_w.w_float;
+            if (info.channels < 1)
+            {
+                argerror(x, s, argc, argv,
+                    "'-raw' flag needs at least one channel\n" RAWSYNTAX);
+                goto done;
+            }
+            if (info.channels > MAXSFCHANS)
+            {
+                argerror(x, s, argc, argv,
+                  "'-raw' channels value %d exceeds "
+                  "maximum of %d channels\n" RAWSYNTAX,
+                    info.channels, MAXSFCHANS);
+                goto done;
+            }
+            if (av[3].a_type != A_FLOAT)
+            {
+                argerror(x, s, argc, argv,
+                    "'-raw' flag needs a float to specify "
+                    "bytes per sample\n" RAWSYNTAX);
+                goto done;
+            }
+            info.bytespersample = av[3].a_w.w_float;
+            if (info.bytespersample < 2)
+            {
+                argerror(x, s, argc, argv,
+                    "'-raw' bytes per sample must be at least 2\n" RAWSYNTAX);
+                goto done;
+            }
+            if (info.bytespersample > 4)
+            {
+                argerror(x, s, argc, argv,
+                   "'-raw' bytes per sample must be less than 4\n" RAWSYNTAX);
+                goto done;
+            }
+            if (av[4].a_type != A_SYMBOL ||
+                ((endianness = av[4].a_w.w_symbol->s_name[0]) != 'b'
+                  && endianness != 'l' && endianness != 'n'))
+            {
+                argerror(x, s, argc, argv,
+                   "'-raw' endianness must be 'l' or 'b' or 'n'\n" RAWSYNTAX);
+                goto done;
+            }
             if (endianness == 'b')
-                bigendian = 1;
+                info.bigendian = 1;
             else if (endianness == 'l')
-                bigendian = 0;
+                info.bigendian = 0;
             else
-                bigendian = garray_ambigendian();
-            argc -= 5; argv += 5;
+                info.bigendian = garray_ambigendian();
+            info.samplerate = sys_getsr();
+            ac -= 5; av += 5;
         }
-        else if (!strcmp(flag, "resize"))
+        else if (!strcmp(flag, "-resize"))
         {
+            if (flag_has_unexpected_floatarg(x, s, argc, argv,
+                flag, ac, av))
+            {
+                goto done;
+            }
             resize = 1;
-            argc -= 1; argv += 1;
+            ac -= 1; av += 1;
         }
-        else if (!strcmp(flag, "maxsize"))
+        else if (!strcmp(flag, "-maxsize"))
         {
-            if (argc < 2 || argv[1].a_type != A_FLOAT ||
-                ((maxsize = argv[1].a_w.w_float) < 0))
-                    goto usage;
+            if (flag_missing_floatarg(x, s, argc, argv, flag, ac, av))
+                goto done;
+            t_float fmax = av[1].a_w.w_float;
+            if (fmax > (t_float)LONG_MAX)
+            {
+                argerror(x, s, argc, argv,
+                    "'-maxsize' overflow detected. "
+                    "Setting '-maxsize' to maximum legal value (%g) and "
+                    "continuing...", (t_float)LONG_MAX);
+                maxsize = LONG_MAX;
+            }
+            else if (fmax < 0.)
+            {
+                argerror(x, s, argc, argv,
+                    "'-maxsize' flag cannot be less than zero");
+                goto done;
+            }
+            else
+            {
+                maxsize = (long)fmax;
+            }
             resize = 1;     /* maxsize implies resize. */
-            argc -= 2; argv += 2;
+            ac -= 2; av += 2;
+        }
+        else
+        {
+            argerror(x, s, argc, argv, "unknown flag '%s'", flag);
+            goto done;
         }
-        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++;
+    if (ac < 1)
+    {
+        argerror(x, s, argc, argv, "need filename and table argument(s)");
+        goto done;
+    }
+    if (ac > MAXSFCHANS + 1)
+    {
+        argerror(x, s, argc, argv,
+            "cannot write more than %d channels", MAXSFCHANS);
+        goto done;
+    }
+    if (av->a_type != A_SYMBOL)
+    {
+        argerror(x, s, argc, argv, "filename must be a symbol");
+        goto done;
+    }
+    filename = av[0].a_w.w_symbol->s_name;
+    ac--; av++;
     
-    for (i = 0; i < argc; i++)
+    for (i = 0; i < ac; i++)
     {
         int vecsize;
-        if (argv[i].a_type != A_SYMBOL)
-            goto usage;
+        if (av[i].a_type != A_SYMBOL)
+            goto done;
         if (!(garrays[i] =
-            (t_garray *)pd_findbyclass(argv[i].a_w.w_symbol, garray_class)))
+            (t_garray *)pd_findbyclass(av[i].a_w.w_symbol, garray_class)))
         {
-            pd_error(x, "%s: no such table", argv[i].a_w.w_symbol->s_name);
+            argerror(x, s, argc, argv, "%s: no such table",
+                av[i].a_w.w_symbol->s_name);
             goto done;
         }
         else if (!garray_getfloatwords(garrays[i], &vecsize, 
                 &vecs[i]))
             error("%s: bad template for tabwrite",
-                argv[i].a_w.w_symbol->s_name);
+                av[i].a_w.w_symbol->s_name);
         if (finalsize && finalsize != vecsize && !resize)
         {
             post("soundfiler_read: arrays have different lengths; resizing...");
@@ -1286,75 +1691,98 @@ static void soundfiler_read(t_soundfiler *x, t_symbol *s,
         }
         finalsize = vecsize;
     }
-    fd = open_soundfile_via_canvas(x->x_canvas, filename,
-        headersize, &bytespersamp, &bigendian, &channels, &bytelimit,
-            skipframes);
+    if (ascii)
+    {
+        soundfiler_readascii(x, filename, ac, garrays, vecs, resize,
+            finalsize);
+        return;
+    }
+    fd = open_soundfile_via_canvas(x->x_canvas, filename, &info, skipframes);
     
     if (fd < 0)
     {
-        pd_error(x, "soundfiler_read: %s: %s", filename, (errno == EIO ?
+        argerror(x, s, argc, argv, "%s: %s", filename, (errno == EIO ?
             "unknown or bad header format" : strerror(errno)));
-        goto done;
+        /* don't bail yet so we can potentially give a warning below */
     }
 
+    /* check if the filename looks like a flag; if so, post a warning */
+    int nodash;
+    if (file_is_a_flag_name(gensym(filename), &nodash))
+    {
+        post("warning: filename '%s' looks like a flag%s",
+            filename, nodash ? " name" : "");
+    }
+
+    /* Now that we've posted our warning, bail if we couldn't open the file */
+    if (fd < 0)
+        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 || eofis < poswas)
         {
-            pd_error(x, "lseek failed: %ld..%ld", poswas, eofis);
+            argerror(x, s, argc, argv, "lseek failed: %ld..%ld", poswas,
+                eofis);
             goto done;
         }
         lseek(fd, poswas, SEEK_SET);
-        framesinfile = (eofis - poswas) / (channels * bytespersamp);
+        framesinfile = (eofis - poswas) / (info.channels * info.bytespersample);
         if (framesinfile > maxsize)
         {
-            pd_error(x, "soundfiler_read: truncated to %ld elements", maxsize);
+            argerror(x, s, argc, argv, "truncated to %ld elements", maxsize);
             framesinfile = maxsize;
         }
-        if (framesinfile > bytelimit / (channels * bytespersamp))
-            framesinfile = bytelimit / (channels * bytespersamp);
+        if (framesinfile > info.bytelimit /
+            (info.channels * info.bytespersample))
+        {
+            framesinfile = info.bytelimit /
+                (info.channels * info.bytespersample);
+        }
         finalsize = framesinfile;
-        for (i = 0; i < argc; i++)
+        for (i = 0; i < ac; i++)
         {
             int vecsize;
 
             garray_resize_long(garrays[i], finalsize);
-                /* for sanity's sake let's clear the save-in-patch flag here */
+
+            /* for sanity's sake let's clear the save-in-patch flag here */
             garray_setsaveit(garrays[i], 0);
             if (!garray_getfloatwords(garrays[i], &vecsize, &vecs[i])
                 || (vecsize != framesinfile))
             {
                 /* if the resize failed, garray_resize reported the error */
-                pd_error(x, "resize failed");
+                argerror(x, s, argc, argv, "resize failed");
                 goto done;
             }
         }
     }
     if (!finalsize) finalsize = 0x7fffffff;
-    if (finalsize > bytelimit / (channels * bytespersamp))
-        finalsize = bytelimit / (channels * bytespersamp);
+    if (finalsize > info.bytelimit / (info.channels * info.bytespersample))
+        finalsize = info.bytelimit / (info.channels * info.bytespersample);
     fp = fdopen(fd, "rb");
-    bufframes = SAMPBUFSIZE / (channels * bytespersamp);
+    bufframes = SAMPBUFSIZE / (info.channels * info.bytespersample);
 
     for (itemsread = 0; itemsread < finalsize; )
     {
-        int thisread = finalsize - itemsread;
+        long thisread = finalsize - itemsread;
         thisread = (thisread > bufframes ? bufframes : thisread);
-        nitems = fread(sampbuf, channels * bytespersamp, thisread, fp);
+        nitems = fread(sampbuf, info.channels * info.bytespersample, thisread,
+            fp);
         if (nitems <= 0) break;
-        soundfile_xferin_float(channels, argc, (t_float **)vecs, itemsread,
-            (unsigned char *)sampbuf, nitems, bytespersamp, bigendian,
-                sizeof(t_word)/sizeof(t_sample));
+        soundfile_xferin_float(info.channels, ac, (t_float **)vecs, itemsread,
+            (unsigned char *)sampbuf, nitems, info.bytespersample,
+            info.bigendian, sizeof(t_word)/sizeof(t_sample));
         itemsread += nitems;
     }
         /* zero out remaining elements of vectors */
         
-    for (i = 0; i < argc; i++)
+    for (i = 0; i < ac; i++)
     {
         int vecsize;
         if (garray_getfloatwords(garrays[i], &vecsize, &vecs[i]))
@@ -1362,7 +1790,7 @@ static void soundfiler_read(t_soundfiler *x, t_symbol *s,
                 vecs[i][j].w_float = 0;
     }
         /* zero out vectors in excess of number of channels */
-    for (i = channels; i < argc; i++)
+    for (i = info.channels; i < ac; i++)
     {
         int vecsize;
         t_word *foo;
@@ -1371,18 +1799,14 @@ static void soundfiler_read(t_soundfiler *x, t_symbol *s,
                 foo[j].w_float = 0;
     }
         /* do all graphics updates */
-    for (i = 0; i < argc; i++)
+    for (i = 0; i < ac; i++)
         garray_redraw(garrays[i]);
     fclose(fp);
     fd = -1;
-    goto done;
-usage:
-    pd_error(x, "usage: read [flags] filename tablename...");
-    post("flags: -skip <n> -resize -maxsize <n> ...");
-    post("-raw <headerbytes> <channels> <bytespersamp> <endian (b, l, or n)>.");
 done:
     if (fd >= 0)
         sys_close(fd);
+    outlet_soundfile_info(x->x_out2, &info);
     outlet_float(x->x_obj.ob_outlet, (t_float)itemsread); 
 }
 
@@ -1390,10 +1814,13 @@ done:
     call it too... not done yet though. */
 
 long soundfiler_dowrite(void *obj, t_canvas *canvas,
-    int argc, t_atom *argv)
+    int argc, t_atom *argv, t_soundfile_info *info)
 {
-    int bytespersamp, bigendian, swap, filetype, normalize, i, j, nchannels;
-    long onset, nframes, itemswritten = 0;
+    /* workaround for ruthless argc/argv mutation in writeargparse... */
+    int original_argc = argc;
+    t_atom *original_argv = argv;
+    int swap, filetype, normalize, i;
+    long onset, nframes, itemswritten = 0, j;
     t_garray *garrays[MAXSFCHANS];
     t_word *vecs[MAXSFCHANS];
     char sampbuf[SAMPBUFSIZE];
@@ -1403,33 +1830,63 @@ long soundfiler_dowrite(void *obj, t_canvas *canvas,
     t_float samplerate;
     t_symbol *filesym;
 
-    if (soundfiler_writeargparse(obj, &argc, &argv, &filesym, &filetype,
-        &bytespersamp, &swap, &bigendian, &normalize, &onset, &nframes,
-            &samplerate))
+    if (soundfiler_writeargparse(obj, gensym("write"), &argc, &argv,
+        &filesym, &filetype,
+        &info->bytespersample, &swap, &info->bigendian, &normalize, &onset,
+        &nframes, &samplerate))
                 goto usage;
-    nchannels = argc;
-    if (nchannels < 1 || nchannels > MAXSFCHANS)
+    info->channels = argc;
+        /* Need at least one table name for a channel to write... */
+    if (info->channels < 1)
+    {
+        argerror(obj, gensym("write"), original_argc, original_argv,
+            "argument for table name missing");
         goto usage;
+    }
+        /* Can't have more than max number of channels to write */
+    if (info->channels > MAXSFCHANS)
+    {
+        argerror(obj, gensym("write"), original_argc, original_argv,
+            "cannot have more than %d channels", MAXSFCHANS);
+        goto usage;
+    }
     if (samplerate < 0)
-        samplerate = sys_getsr();
-    for (i = 0; i < nchannels; i++)
+        info->samplerate = sys_getsr();
+    else
+        info->samplerate = (int)samplerate;
+    for (i = 0; i < info->channels; i++)
     {
         int vecsize;
         if (argv[i].a_type != A_SYMBOL)
+        {
+            argerror(obj, gensym("write"), original_argc, original_argv,
+                "table name must be 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);
+            argerror(obj, gensym("write"), original_argc, original_argv,
+                "%s: no such table", argv[i].a_w.w_symbol->s_name);
             goto fail;
         }
+            /* need to check this one-- */
         else if (!garray_getfloatwords(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 (nframes <= 0)
+    {
+        argerror(obj, gensym("write"), original_argc, original_argv,
+            "no samples at onset %ld", onset);
+        goto fail;
+    }
+        /* find biggest sample for normalizing */
+    for (i = 0; i < info->channels; i++)
+    {
+        for (j = onset; j < nframes + onset; j++)
         {
             if (vecs[i][j].w_float > biggest)
                 biggest = vecs[i][j].w_float;
@@ -1437,24 +1894,19 @@ long soundfiler_dowrite(void *obj, t_canvas *canvas,
                 biggest = -vecs[i][j].w_float;
         }
     }
-    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, samplerate)) < 0)
+        nframes, info->bytespersample, info->bigendian, info->channels,
+            swap, info->samplerate, &info->headersize)) < 0)
     {
         post("%s: %s\n", filesym->s_name, strerror(errno));
         goto fail;
     }
     if (!normalize)
     {
-        if ((bytespersamp != 4) && (biggest > 1))
+        if ((info->bytespersample != 4) && (biggest > 1))
         {
-            post("%s: normalizing max amplitude %f to 1", filesym->s_name, biggest);
+            post("%s: normalizing max amplitude %f to 1", filesym->s_name,
+                biggest);
             normalize = 1;
         }
         else post("%s: biggest amplitude = %f", filesym->s_name, biggest);
@@ -1463,21 +1915,22 @@ long soundfiler_dowrite(void *obj, t_canvas *canvas,
         normfactor = (biggest > 0 ? 32767./(32768. * biggest) : 1);
     else normfactor = 1;
 
-    bufframes = SAMPBUFSIZE / (nchannels * bytespersamp);
+    bufframes = SAMPBUFSIZE / (info->channels * info->bytespersample);
 
     for (itemswritten = 0; itemswritten < nframes; )
     {
         int thiswrite = nframes - itemswritten, nbytes;
         thiswrite = (thiswrite > bufframes ? bufframes : thiswrite);
         soundfile_xferout_float(argc, (t_float **)vecs, (unsigned char *)sampbuf,
-            thiswrite, onset, bytespersamp, bigendian, normfactor,
+            thiswrite, onset, info->bytespersample, info->bigendian, normfactor,
                  sizeof(t_word)/sizeof(t_sample));
-        nbytes = write(fd, sampbuf, nchannels * bytespersamp * thiswrite);
-        if (nbytes < nchannels * bytespersamp * thiswrite)
+        nbytes = write(fd, sampbuf, info->channels * info->bytespersample *
+            thiswrite);
+        if (nbytes < info->channels * info->bytespersample * thiswrite)
         {
             post("%s: %s", filesym->s_name, strerror(errno));
             if (nbytes > 0)
-                itemswritten += nbytes / (nchannels * bytespersamp);
+                itemswritten += nbytes / (info->channels * info->bytespersample);
             break;
         }
         itemswritten += thiswrite;
@@ -1486,15 +1939,12 @@ long soundfiler_dowrite(void *obj, t_canvas *canvas,
     if (fd >= 0)
     {
         soundfile_finishwrite(obj, filesym->s_name, fd,
-            filetype, nframes, itemswritten, nchannels * bytespersamp, swap);
+            filetype, nframes, itemswritten,
+            info->channels * info->bytespersample, swap);
         sys_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)
         sys_close(fd);
@@ -1504,8 +1954,17 @@ fail:
 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);
+    t_soundfile_info info;
+    long bozo;
+    info.samplerate = 0,
+    info.channels = 0,
+    info.bytespersample = 0,
+    info.headersize = -1,
+    info.bigendian = 0,
+    info.bytelimit = 0x7fffffff;
+
+    bozo = soundfiler_dowrite(x, x->x_canvas, argc, argv, &info);
+    outlet_soundfile_info(x->x_out2, &info);
     outlet_float(x->x_obj.ob_outlet, (t_float)bozo); 
 }
 
@@ -1659,12 +2118,14 @@ static void *readsf_child_main(void *zz)
             
                 /* copy file stuff out of the data structure so we can
                 relinquish the mutex while we're in open_soundfile(). */
+            t_soundfile_info info;
             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;
+            info.samplerate = x->x_samplerate;
+            info.channels = x->x_sfchannels;
+            info.headersize = x->x_skipheaderbytes;
+            info.bytespersample = x->x_bytespersample;
+            info.bigendian = x->x_bigendian;
+            info.bytelimit = 0x7fffffff;
             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
@@ -1688,20 +2149,18 @@ static void *readsf_child_main(void *zz)
             }
                 /* open the soundfile with the mutex unlocked */
             pthread_mutex_unlock(&x->x_mutex);
-            fd = open_soundfile(dirname, filename,
-                skipheaderbytes, &bytespersample, &bigendian,
-                &sfchannels, &bytelimit, onsetframes);      
+            fd = open_soundfile(dirname, filename, &info, onsetframes);      
             pthread_mutex_lock(&x->x_mutex);
 
 #ifdef DEBUG_SOUNDFILE
             pute("5\n");
 #endif
                 /* copy back into the instance structure. */
-            x->x_bytespersample = bytespersample;
-            x->x_sfchannels = sfchannels;
-            x->x_bigendian = bigendian;
+            x->x_bytespersample = info.bytespersample;
+            x->x_sfchannels = info.channels;
+            x->x_bigendian = info.bigendian;
             x->x_fd = fd;
-            x->x_bytelimit = bytelimit;
+            x->x_bytelimit = info.bytelimit;
             if (fd < 0)
             {
                 x->x_fileerror = errno;
@@ -1731,6 +2190,7 @@ static void *readsf_child_main(void *zz)
                     /* arrange for the "request" condition to be signalled 16
                     times per buffer */
 #ifdef DEBUG_SOUNDFILE
+            char boo[80];
             sprintf(boo, "fifosize %d\n", 
                 x->x_fifosize);
             pute(boo);
@@ -2014,7 +2474,7 @@ static t_int *readsf_perform(t_int *w)
             {
                 soundfile_xferin_sample(sfchannels, noutlets, x->x_outvec, 0,
                     (unsigned char *)(x->x_buf + x->x_fifotail), xfersize,
-                        bytespersample, bigendian, 1);
+                        bytespersample, bigendian);
                 vecsize -= xfersize;
             }
                 /* then zero out the (rest of the) output */
@@ -2029,7 +2489,7 @@ static t_int *readsf_perform(t_int *w)
 
         soundfile_xferin_sample(sfchannels, noutlets, x->x_outvec, 0,
             (unsigned char *)(x->x_buf + x->x_fifotail), vecsize,
-                bytespersample, bigendian, 1);
+                bytespersample, bigendian);
         
         x->x_fifotail += wantbytes;
         if (x->x_fifotail >= x->x_fifosize)
@@ -2264,7 +2724,7 @@ static void *writesf_child_main(void *zz)
             pthread_mutex_unlock(&x->x_mutex);
             fd = create_soundfile(canvas, filename, filetype, 0,
                     bytespersample, bigendian, sfchannels, 
-                        garray_ambigendian() != bigendian, samplerate);
+                        garray_ambigendian() != bigendian, samplerate, 0);
             pthread_mutex_lock(&x->x_mutex);
 #ifdef DEBUG_SOUNDFILE
             pute("5\n");
@@ -2543,17 +3003,15 @@ static void writesf_open(t_writesf *x, t_symbol *s, int argc, t_atom *argv)
     {
         writesf_stop(x);
     }
-    if (soundfiler_writeargparse(x, &argc,
+    if (soundfiler_writeargparse(x, gensym("open"), &argc,
         &argv, &filesym, &filetype, &bytespersamp, &swap, &bigendian,
         &normalize, &onset, &nframes, &samplerate))
     {
-        pd_error(x,
-            "writesf~: usage: open [-bytes [234]] [-wave,-nextstep,-aiff] ...");
-        post("... [-big,-little] [-rate ####] filename");
+            /* errors handled above in soundfiler_writeargparse */
         return;
     }
     if (normalize || onset || (nframes != 0x7fffffff))
-        pd_error(x, "normalize/onset/nframes argument to writesf~: ignored");
+        pd_error(x, "normalize/skip/nframes argument to writesf~: ignored");
     if (argc)
         pd_error(x, "extra argument(s) to writesf~: ignored");
     pthread_mutex_lock(&x->x_mutex);
diff --git a/scripts/regression_tests.pd b/scripts/regression_tests.pd
index 4b8a8c20c7713b30c986cb19b34e0e4d0c16751c..1e09b63357eca779f4c5eaa890961c023963ff70 100644
--- a/scripts/regression_tests.pd
+++ b/scripts/regression_tests.pd
@@ -1,4 +1,4 @@
-#N canvas -9 -9 771 392 12;
+#N canvas 128 123 771 392 12;
 #X obj 465 281 r \$0-result;
 #X obj 212 239 bng 15 250 50 0 empty empty Run_all 17 7 0 10 #fcfcfc
 #000000 #000000;
@@ -25,7 +25,7 @@ is handy for some binbuf tests.;
 #X obj 198 659 rtest makefilename_double_percent;
 #X obj 198 710 rtest makefilename_code_coverage;
 #N canvas 461 242 450 323 (subpatch) 0;
-#X restore 201 2605 pd;
+#X restore 201 2765 pd;
 #X obj 198 761 rtest makefilename_default;
 #X obj 198 812 rtest makefilename_default_bang;
 #X obj 198 863 rtest makefilename_float;
@@ -66,6 +66,8 @@ is handy for some binbuf tests.;
 #X obj 198 2416 rtest inlet~_fwd_large_message;
 #X obj 198 2471 rtest pow~_negative_numbers;
 #X obj 198 2526 rtest encapsulate;
+#X obj 198 2581 rtest soundfiler_read_coverage;
+#X obj 198 2636 rtest writesf~_open_coverage;
 #X connect 0 0 27 0;
 #X connect 1 0 4 0;
 #X connect 2 0 42 0;
@@ -117,3 +119,5 @@ is handy for some binbuf tests.;
 #X connect 57 0 58 0;
 #X connect 58 0 59 0;
 #X connect 59 0 60 0;
+#X connect 60 0 61 0;
+#X connect 61 0 62 0;
diff --git a/scripts/regression_tests/soundfiler_read_coverage.pd b/scripts/regression_tests/soundfiler_read_coverage.pd
new file mode 100644
index 0000000000000000000000000000000000000000..ca022f36bbc2a1aeb21e694a510e177729b2f014
--- /dev/null
+++ b/scripts/regression_tests/soundfiler_read_coverage.pd
@@ -0,0 +1,56 @@
+#N canvas 106 64 1067 916 12;
+#X obj 53 609 ../utils/method-error soundfiler;
+#X obj 168 684 route bang;
+#X obj 168 713 f 0;
+#X obj 235 713 b;
+#X obj 235 742 f 1;
+#X obj 53 773 list prepend;
+#X obj 53 638 list prepend this message should trigger an error:;
+#X obj 53 10 inlet;
+#X msg 53 89 bang;
+#X obj 53 581 receive \$0-;
+#N canvas 771 533 450 425 \$0-too-many-channels 0;
+#X obj 80 31 inlet;
+#X obj 80 60 f \$0;
+#X msg 80 110 \; \$1- read z z z z z z z z z z z z z z z z z z z z
+z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z
+z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z
+z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z
+z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z
+z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z
+z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z
+z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X restore 169 128 pd \$0-too-many-channels;
+#X msg 169 97 bang;
+#X obj 53 39 trigger bang bang;
+#X text 182 24 This just covers the flags. We probably need to add
+file-loading tests at some point.;
+#X obj 53 802 outlet;
+#X msg 53 158 \; \$1- \$2 -skip \; \$1- \$2 -skip rope \; \$1- \$2
+-skip -1 \; \$1- \$2 -raw \; \$1- \$2 -raw dope \; \$1- \$2 -raw \;
+\$1- \$2 -raw 0 \; \$1- \$2 -raw 0 0 \; \$1- \$2 -raw 0 0 0 \; \$1-
+\$2 -raw dope 0 0 0 \; \$1- \$2 -raw 0 dope 0 0 \; \$1- \$2 -raw 0
+1 dope 0 \; \$1- \$2 -raw 0 1 2 dope \; \$1- \$2 -raw -1 0 0 0 \; \$1-
+\$2 -raw 0 0 2 l \; \$1- \$2 -raw 0 1024 2 n \; \$1- \$2 -raw 0 1 1
+n \; \$1- \$2 -raw 0 1 5 n \; \$1- \$2 -raw 0 1 2 z \; \$1- \$2 -resize
+12 \; \$1- \$2 -maxsize \; \$1- \$2 -maxsize 1e+19 \; \$1- \$2 -reginald
+\; \$1- \$2;
+#X obj 53 118 list \$0 read;
+#X connect 0 0 6 0;
+#X connect 0 1 1 0;
+#X connect 1 0 2 0;
+#X connect 1 1 3 0;
+#X connect 2 0 5 1;
+#X connect 3 0 4 0;
+#X connect 4 0 5 1;
+#X connect 5 0 14 0;
+#X connect 6 0 5 0;
+#X connect 7 0 12 0;
+#X connect 8 0 16 0;
+#X connect 9 0 0 0;
+#X connect 11 0 10 0;
+#X connect 12 0 8 0;
+#X connect 12 1 11 0;
+#X connect 16 0 15 0;
diff --git a/scripts/regression_tests/soundfiler_write_coverage.pd b/scripts/regression_tests/soundfiler_write_coverage.pd
new file mode 100644
index 0000000000000000000000000000000000000000..aaeee8cfa2c1561607382c30b028a52c39102684
--- /dev/null
+++ b/scripts/regression_tests/soundfiler_write_coverage.pd
@@ -0,0 +1,56 @@
+#N canvas 641 120 1067 916 12;
+#X obj 53 669 ../utils/method-error soundfiler;
+#X obj 168 744 route bang;
+#X obj 168 773 f 0;
+#X obj 235 773 b;
+#X obj 235 802 f 1;
+#X obj 53 833 list prepend;
+#X obj 53 698 list prepend this message should trigger an error:;
+#X obj 53 10 inlet;
+#X msg 53 89 bang;
+#X obj 53 641 receive \$0-;
+#N canvas 771 542 450 425 \$0-too-many-channels 1;
+#X obj 80 31 inlet;
+#X obj 80 60 f \$0;
+#X msg 80 110 \; \$1- write z z z z z z z z z z z z z z z z z z z z
+z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z
+z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z
+z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z
+z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z
+z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z
+z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z
+z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X restore 169 128 pd \$0-too-many-channels;
+#X msg 169 97 bang;
+#X obj 53 39 trigger bang bang;
+#X text 182 24 This just covers the flags. We probably need to add
+file-loading tests at some point.;
+#X obj 53 862 outlet;
+#X obj 53 118 list \$0 write;
+#X msg 53 158 \; \$1- \$2 -skip \; \$1- \$2 -skip rope \; \$1- \$2
+-skip -1 \; \$1- \$2 -nframes \; \$1- \$2 -nframes dope \; \$1- \$2
+-nframes -1 \; \$1- \$2 -normalize 12 \; \$1- \$2 -bytes \; \$1- \$2
+-bytes 1 \; \$1- \$2 -bytes 5 \; \$1- \$2 -resize 12 \; \$1- \$2 -wave
+1 \; \$1- \$2 -nextstep 1 \; \$1- \$2 -aiff 1 \; \$1- \$2 -big 1 \;
+\$1- \$2 -little 1 \; \$1- \$2 -r \; \$1- \$2 -rate \; \$1- \$2 -r
+0 \; \$1- \$2 -rate 0 \; \$1- \$2 -reginald \; \$1- \$2 \; \$1- \$2
+12 \; \$1- \$2 foo 12 \; \$1- \$2 -bytes 4 -aiff foo \; \$1- \$2 foo
+no_table \;;
+#X connect 0 0 6 0;
+#X connect 0 1 1 0;
+#X connect 1 0 2 0;
+#X connect 1 1 3 0;
+#X connect 2 0 5 1;
+#X connect 3 0 4 0;
+#X connect 4 0 5 1;
+#X connect 5 0 14 0;
+#X connect 6 0 5 0;
+#X connect 7 0 12 0;
+#X connect 8 0 15 0;
+#X connect 9 0 0 0;
+#X connect 11 0 10 0;
+#X connect 12 0 8 0;
+#X connect 12 1 11 0;
+#X connect 15 0 16 0;
diff --git a/scripts/regression_tests/writesf~_open_coverage.pd b/scripts/regression_tests/writesf~_open_coverage.pd
new file mode 100644
index 0000000000000000000000000000000000000000..70bb25d738132522f89bd2a4a70e909c9b408762
--- /dev/null
+++ b/scripts/regression_tests/writesf~_open_coverage.pd
@@ -0,0 +1,37 @@
+#N canvas 72 64 1067 916 12;
+#X obj 138 754 route bang;
+#X obj 138 783 f 0;
+#X obj 205 783 b;
+#X obj 205 812 f 1;
+#X obj 23 843 list prepend;
+#X obj 23 708 list prepend this message should trigger an error:;
+#X obj 23 20 inlet;
+#X msg 23 99 bang;
+#X obj 23 651 receive \$0-;
+#X text 42 54 This just covers the flags. We probably need to add file-loading
+tests at some point.;
+#X obj 23 872 outlet;
+#X msg 23 168 \; \$1- \$2 -skip \; \$1- \$2 -skip rope \; \$1- \$2
+-skip -1 \; \$1- \$2 -nframes \; \$1- \$2 -nframes dope \; \$1- \$2
+-nframes -1 \; \$1- \$2 -normalize 12 \; \$1- \$2 -bytes \; \$1- \$2
+-bytes 1 \; \$1- \$2 -bytes 5 \; \$1- \$2 -resize 12 \; \$1- \$2 -wave
+1 \; \$1- \$2 -nextstep 1 \; \$1- \$2 -aiff 1 \; \$1- \$2 -big 1 \;
+\$1- \$2 -little 1 \; \$1- \$2 -r \; \$1- \$2 -rate \; \$1- \$2 -r
+0 \; \$1- \$2 -rate 0 \; \$1- \$2 -reginald \; \$1- \$2 \; \$1- \$2
+12 \; \$1- \$2 foo 12 \; \$1- \$2 -bytes 4 -aiff foo \; \$1- \$2 foo
+extra_arg \;;
+#X obj 23 128 list \$0 open;
+#X obj 23 679 ../utils/method-error writesf~;
+#X connect 0 0 1 0;
+#X connect 0 1 2 0;
+#X connect 1 0 4 1;
+#X connect 2 0 3 0;
+#X connect 3 0 4 1;
+#X connect 4 0 10 0;
+#X connect 5 0 4 0;
+#X connect 6 0 7 0;
+#X connect 7 0 12 0;
+#X connect 8 0 13 0;
+#X connect 12 0 11 0;
+#X connect 13 0 5 0;
+#X connect 13 1 0 0;
diff --git a/scripts/utils/method-error.pd b/scripts/utils/method-error.pd
new file mode 100644
index 0000000000000000000000000000000000000000..bc2664b8a50fc2969ffae046b9c73787ee4016a7
--- /dev/null
+++ b/scripts/utils/method-error.pd
@@ -0,0 +1,20 @@
+#N canvas 861 254 781 553 12;
+#X obj 96 28 inlet;
+#X obj 201 125 unpost;
+#X obj 176 178 list;
+#X obj 176 267 outlet;
+#X obj 240 178 \$1;
+#X obj 96 267 outlet;
+#X obj 96 86 trigger anything bang anything bang;
+#X text 143 29 test a method that triggers;
+#X text 143 49 an error;
+#X text 55 220 the message;
+#X text 159 221 the error (formatted as a single symbol);
+#X connect 0 0 6 0;
+#X connect 1 0 2 1;
+#X connect 1 1 4 0;
+#X connect 2 0 3 0;
+#X connect 6 0 5 0;
+#X connect 6 1 2 0;
+#X connect 6 2 1 0;
+#X connect 6 3 2 1;