shithub: sox

Download patch

ref: 3179089d57fad71e119e9546d4e36cdce173aa35
parent: 4066d990dd6e23709714b54220071e1d8596c0d3
author: cbagwell <cbagwell>
date: Sat Sep 17 00:41:59 EDT 2005

Change ALSA driver to asoundlib.  Add st_open and st_close helper
functions.

--- a/Changelog
+++ b/Changelog
@@ -30,6 +30,12 @@
   o Add support for displaying a status line that tracks progress
     of read/write routines.  Part of information requires read
     file handlers to be able to determine file length.
+  o Converted alsa driver to use asoundlib instead of directly
+    talking to kernel driver.  This also means that device names
+    are now the ALSA logical names instead of /dev type names.
+  o Added ALSA support to play/rec scripts.
+  o Added st_open* and st_close() routines to help simply
+    developer interface to libst.
 
 sox-12.17.8
 -----------
--- a/configure
+++ b/configure
@@ -1,7 +1,7 @@
 #! /bin/sh
-# From configure.in 1.8.
+# From configure.in 1.9.
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.59 for sox 12.17.8.
+# Generated by GNU Autoconf 2.59 for sox 12.17.9.
 #
 # Report bugs to <cbagwell@users.sourceforge.net>.
 #
@@ -269,9 +269,9 @@
 
 # Identity of this package.
 PACKAGE_NAME='sox'
-PACKAGE_TARNAME='"sox-12.17.8"'
-PACKAGE_VERSION='12.17.8'
-PACKAGE_STRING='sox 12.17.8'
+PACKAGE_TARNAME='"sox-12.17.9"'
+PACKAGE_VERSION='12.17.9'
+PACKAGE_STRING='sox 12.17.9'
 PACKAGE_BUGREPORT='cbagwell@users.sourceforge.net'
 
 ac_unique_file="sox.1"
@@ -781,7 +781,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures sox 12.17.8 to adapt to many kinds of systems.
+\`configure' configures sox 12.17.9 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -843,7 +843,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of sox 12.17.8:";;
+     short | recursive ) echo "Configuration of sox 12.17.9:";;
    esac
   cat <<\_ACEOF
 
@@ -969,7 +969,7 @@
 test -n "$ac_init_help" && exit 0
 if $ac_init_version; then
   cat <<\_ACEOF
-sox configure 12.17.8
+sox configure 12.17.9
 generated by GNU Autoconf 2.59
 
 Copyright (C) 2003 Free Software Foundation, Inc.
@@ -983,7 +983,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by sox $as_me 12.17.8, which was
+It was created by sox $as_me 12.17.9, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   $ $0 $@
@@ -4913,7 +4913,7 @@
 if test "$enable_alsa_dsp" = yes
 then
 
-for ac_header in linux/asound.h
+for ac_header in alsa/asoundlib.h
 do
 as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
 if eval "test \"\${$as_ac_Header+set}\" = set"; then
@@ -5057,27 +5057,21 @@
   cat >>confdefs.h <<_ACEOF
 #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
 _ACEOF
- alsa_type=check_ioctl
+ found_alsa_dsp=yes
 fi
 
 done
 
 
-for ac_header in sound/asound.h
-do
-as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if eval "test \"\${$as_ac_Header+set}\" = set"; then
-  echo "$as_me:$LINENO: checking for $ac_header" >&5
-echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
-if eval "test \"\${$as_ac_Header+set}\" = set"; then
+    if test "$found_alsa_dsp" = yes
+    then
+        echo "$as_me:$LINENO: checking for snd_pcm_open in -lasound" >&5
+echo $ECHO_N "checking for snd_pcm_open in -lasound... $ECHO_C" >&6
+if test "${ac_cv_lib_asound_snd_pcm_open+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
-fi
-echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
-echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
 else
-  # Is the header compilable?
-echo "$as_me:$LINENO: checking $ac_header usability" >&5
-echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lasound  $LIBS"
 cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
 _ACEOF
@@ -5084,162 +5078,25 @@
 cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
-  (eval $ac_compile) 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"
-			 || test ! -s conftest.err'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-	 { ac_try='test -s conftest.$ac_objext'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_header_compiler=yes
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
 
-ac_header_compiler=no
-fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
-echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-echo "${ECHO_T}$ac_header_compiler" >&6
-
-# Is the header present?
-echo "$as_me:$LINENO: checking $ac_header presence" >&5
-echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
-  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null; then
-  if test -s conftest.err; then
-    ac_cpp_err=$ac_c_preproc_warn_flag
-    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
-  else
-    ac_cpp_err=
-  fi
-else
-  ac_cpp_err=yes
-fi
-if test -z "$ac_cpp_err"; then
-  ac_header_preproc=yes
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  ac_header_preproc=no
-fi
-rm -f conftest.err conftest.$ac_ext
-echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-echo "${ECHO_T}$ac_header_preproc" >&6
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
-    (
-      cat <<\_ASBOX
-## --------------------------------------------- ##
-## Report this to cbagwell@users.sourceforge.net ##
-## --------------------------------------------- ##
-_ASBOX
-    ) |
-      sed "s/^/$as_me: WARNING:     /" >&2
-    ;;
-esac
-echo "$as_me:$LINENO: checking for $ac_header" >&5
-echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
-if eval "test \"\${$as_ac_Header+set}\" = set"; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  eval "$as_ac_Header=\$ac_header_preproc"
-fi
-echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
-echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
-
-fi
-if test `eval echo '${'$as_ac_Header'}'` = yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
- alsa_type=alsa9
-fi
-
-done
-
-
-    echo "$as_me:$LINENO: checking for ALSA ioctl API" >&5
-echo $ECHO_N "checking for ALSA ioctl API... $ECHO_C" >&6
-
-    if test "$alsa_type" = check_ioctl
-    then
-	cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-
-#include <linux/asound.h>
-
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char snd_pcm_open ();
 int
 main ()
 {
-
-snd_pcm_capture_info_t c_info;
-
+snd_pcm_open ();
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
-  (eval $ac_compile) 2>conftest.er1
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
   ac_status=$?
   grep -v '^ *+' conftest.er1 >conftest.err
   rm -f conftest.er1
@@ -5253,74 +5110,40 @@
   ac_status=$?
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); }; } &&
-	 { ac_try='test -s conftest.$ac_objext'
+	 { ac_try='test -s conftest$ac_exeext'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); }; }; then
-  alsa_type=alsa4
+  ac_cv_lib_asound_snd_pcm_open=yes
 else
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-alsa_type=alsa5
+ac_cv_lib_asound_snd_pcm_open=no
 fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
-    fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_asound_snd_pcm_open" >&5
+echo "${ECHO_T}$ac_cv_lib_asound_snd_pcm_open" >&6
+if test $ac_cv_lib_asound_snd_pcm_open = yes; then
+  LIBS="$LIBS -lasound"
+                     NEED_ALSA=1
+                     PLAY_SUPPORT=1
 
-    if test "$alsa_type" = alsa9
-    then
-
 cat >>confdefs.h <<\_ACEOF
 #define HAVE_ALSA 1
 _ACEOF
 
+else
+  enable_lame=no
+fi
 
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_ALSA9 1
-_ACEOF
-
-	NEED_ALSA=1
-	PLAY_SUPPORT=1
-	echo "$as_me:$LINENO: result: 0.9.X" >&5
-echo "${ECHO_T}0.9.X" >&6
-    elif test "$alsa_type" = alsa5
-    then
-
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_ALSA 1
-_ACEOF
-
-
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_ALSA5 1
-_ACEOF
-
-	NEED_ALSA=1
-	PLAY_SUPPORT=1
-	echo "$as_me:$LINENO: result: 0.5.X" >&5
-echo "${ECHO_T}0.5.X" >&6
-    elif test "$alsa_type" = alsa4
-    then
-
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_ALSA 1
-_ACEOF
-
-
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_ALSA4 1
-_ACEOF
-
-	NEED_ALSA=1
-	PLAY_SUPPORT=1
-	echo "$as_me:$LINENO: result: 0.4.X" >&5
-echo "${ECHO_T}0.4.X" >&6
     else
-	echo "$as_me:$LINENO: result: not found" >&5
-echo "${ECHO_T}not found" >&6
-	enable_alsa_dsp=no
+        enable_alsa_dsp=no
     fi
 fi
 
@@ -6047,7 +5870,7 @@
 } >&5
 cat >&5 <<_CSEOF
 
-This file was extended by sox $as_me 12.17.8, which was
+This file was extended by sox $as_me 12.17.9, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -6107,7 +5930,7 @@
 
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-sox config.status 12.17.8
+sox config.status 12.17.9
 configured by $0, generated by GNU Autoconf 2.59,
   with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
 
--- a/configure.in
+++ b/configure.in
@@ -3,9 +3,9 @@
 dnl configure.in
 dnl
 
-AC_REVISION(1.8)
+AC_REVISION(1.9)
 
-AC_INIT(sox, 12.17.8, cbagwell@users.sourceforge.net, "sox-12.17.8")
+AC_INIT(sox, 12.17.9, cbagwell@users.sourceforge.net, "sox-12.17.9")
 
 AC_CONFIG_SRCDIR(sox.1)
 
@@ -181,53 +181,19 @@
 
 if test "$enable_alsa_dsp" = yes
 then
-    AC_CHECK_HEADERS(linux/asound.h, alsa_type=check_ioctl)
-    AC_CHECK_HEADERS(sound/asound.h, alsa_type=alsa9)
+    AC_CHECK_HEADERS(alsa/asoundlib.h, found_alsa_dsp=yes)
 
-    AC_MSG_CHECKING([for ALSA ioctl API])
-
-    if test "$alsa_type" = check_ioctl
+    if test "$found_alsa_dsp" = yes
     then
-	AC_TRY_COMPILE(
-[
-#include <linux/asound.h>
-],
-[
-snd_pcm_capture_info_t c_info;
-],
-		alsa_type=alsa4,alsa_type=alsa5)
-    fi
-
-    if test "$alsa_type" = alsa9
-    then
-        AC_DEFINE([HAVE_ALSA], 1, 
-                  [Define if you have ALSA installed])
-        AC_DEFINE([HAVE_ALSA9], 1, 
-                  [Define if you have ALSA 0.9 installed])
-	NEED_ALSA=1
-	PLAY_SUPPORT=1
-	AC_MSG_RESULT([0.9.X])
-    elif test "$alsa_type" = alsa5
-    then
-        AC_DEFINE([HAVE_ALSA], 1, 
-                  [Define if you have ALSA installed])
-        AC_DEFINE([HAVE_ALSA5], 1, 
-                  [Define if you have ALSA 0.5 installed])
-	NEED_ALSA=1
-	PLAY_SUPPORT=1
-	AC_MSG_RESULT([0.5.X])
-    elif test "$alsa_type" = alsa4
-    then
-        AC_DEFINE([HAVE_ALSA], 1, 
-                  [Define if you have ALSA installed])
-        AC_DEFINE([HAVE_ALSA4], 1, 
-                  [Define if you have ALSA 0.4 installed])
-	NEED_ALSA=1
-	PLAY_SUPPORT=1
-	AC_MSG_RESULT([0.4.X])
+        AC_CHECK_LIB(asound, snd_pcm_open,
+                     LIBS="$LIBS -lasound"
+                     NEED_ALSA=1
+                     PLAY_SUPPORT=1
+                     AC_DEFINE([HAVE_ALSA], 1, 
+		               [Define if you have ALSA library installed]),
+		     enable_lame=no)
     else
-	AC_MSG_RESULT([not found])
-	enable_alsa_dsp=no
+        enable_alsa_dsp=no
     fi
 fi
 
--- a/src/8svx.c
+++ b/src/8svx.c
@@ -84,7 +84,7 @@
                         st_seek(ft,12,SEEK_CUR);
                         st_readw(ft, &rate);
                         st_seek(ft,1,SEEK_CUR);
-                        st_read(ft, buf,1,1);
+                        st_readbuf(ft, buf,1,1);
                         if (buf[0] != 0)
                         {
                                 st_fail_errno(ft, ST_EFMT, "Unsupported data compression");
@@ -104,7 +104,7 @@
                             st_fail_errno(ft, ST_ENOMEM, "Unable to alloc memory");
                             return(ST_EOF);
                         }
-                        if (st_read(ft, chunk_buf,1,(size_t)chunksize) 
+                        if (st_readbuf(ft, chunk_buf,1,(size_t)chunksize) 
                                         != chunksize)
                         {
                                 st_fail_errno(ft, ST_EHDR, "Couldn't read all of header");
@@ -127,7 +127,7 @@
                             st_fail_errno(ft, ST_ENOMEM, "Unable to alloc memory");
                             return(ST_EOF);
                         }
-                        if (st_read(ft, chunk_buf,1,(size_t)chunksize) 
+                        if (st_readbuf(ft, chunk_buf,1,(size_t)chunksize) 
                                         != chunksize)
                         {
                                 st_fail_errno(ft, ST_EHDR, "Couldn't read all of header");
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -69,7 +69,7 @@
 ALSAOBJ_1   = alsa.o
 EXTRAOBJS   = $(OSSOBJ_$(NEED_OSS)) $(SUNAUOBJ_$(NEED_SUNAU)) $(ALSAOBJ_$(NEED_ALSA)) $(GSMOBJ_$(GSM_SUPPORT))
 
-LIBOBJS = $(FOBJ) $(EOBJ) handlers.o misc.o util.o getopt.o $(EXTRAOBJS)
+LIBOBJS = $(FOBJ) $(EOBJ) handlers.o stio.o misc.o util.o getopt.o $(EXTRAOBJS)
 
 # Building libgsm.a is kinda a hack.  It switches to a different
 # makefile with hardcoded options.  We really want the object files
--- a/src/aiff.c
+++ b/src/aiff.c
@@ -523,7 +523,7 @@
     st_fail_errno(ft,ST_ENOMEM,"AIFF: Couldn't allocate %s header", chunkDescription);
     return(ST_EOF);
   }
-  if (st_read(ft, *text, 1, chunksize) != chunksize)
+  if (st_readbuf(ft, *text, 1, chunksize) != chunksize)
   {
     st_fail_errno(ft,ST_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
     return(ST_EOF);
@@ -533,7 +533,7 @@
         {
                 /* Read past pad byte */
                 char c;
-                if (st_read(ft, &c, 1, 1) != 1)
+                if (st_readbuf(ft, &c, 1, 1) != 1)
                 {
                 st_fail_errno(ft,ST_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
                         return(ST_EOF);
@@ -578,7 +578,7 @@
         st_fail_errno(ft,ST_ENOMEM,"AIFF: Couldn't allocate %s header", chunkDescription);
         return(ST_EOF);
     }
-    if (st_read(ft, *text + totalCommentLength - commentLength, 1, commentLength) != commentLength) {
+    if (st_readbuf(ft, *text + totalCommentLength - commentLength, 1, commentLength) != commentLength) {
         st_fail_errno(ft,ST_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
         return(ST_EOF);
     }
@@ -587,7 +587,7 @@
     if (commentLength % 2) {
         /* Read past pad byte */
         char c;
-        if (st_read(ft, &c, 1, 1) != 1) {
+        if (st_readbuf(ft, &c, 1, 1) != 1) {
             st_fail_errno(ft,ST_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription);
             return(ST_EOF);
         }
@@ -599,7 +599,7 @@
        int i;
        char c;
        for (i=0; i < chunksize - totalReadLength; i++ ) {
-               st_read(ft, &c, 1, 1);
+               st_readbuf(ft, &c, 1, 1);
        }
   }
   return(ST_SUCCESS);
@@ -631,7 +631,7 @@
         {
             while (! st_eof(ft)) 
             {
-                if (st_read(ft, buf, 1, 4) != 4)
+                if (st_readbuf(ft, buf, 1, 4) != 4)
                         break;
 
                 st_readdw(ft, &chunksize);
@@ -877,7 +877,7 @@
 static double read_ieee_extended(ft_t ft)
 {
         char buf[10];
-        if (st_read(ft, buf, 1, 10) != 10)
+        if (st_readbuf(ft, buf, 1, 10) != 10)
         {
                 st_fail_errno(ft,ST_EOF,"EOF while reading IEEE extended number");
                 return(ST_EOF);
@@ -895,7 +895,7 @@
                 buf[0], buf[1], buf[2], buf[3], buf[4],
                 buf[5], buf[6], buf[7], buf[8], buf[9]);
         */
-        (void)st_write(ft, buf, 1, 10);
+        (void)st_writebuf(ft, buf, 1, 10);
 }
 
 
--- a/src/alsa.c
+++ b/src/alsa.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997 Jimen Ching And Sundry Contributors
+ * Copyright 1997-2005 Jimen Ching And Sundry Contributors
  * This source code is freely redistributable and may be used for
  * any purpose.  This copyright notice must be maintained.
  * Jimen Ching And Sundry Contributors are not
@@ -6,8 +6,9 @@
  * responsible for the consequences of using this software.
  */
 
-/* Direct to ALSA sound driver
+/* ALSA sound driver
  *
+ * converted to alsalib cbagwell 20050914
  * added by Jimen Ching (jching@flex.com) 19990207
  * based on info grabed from aplay.c in alsa-utils package.
  * Updated for ALSA 0.9.X API 20020824.
@@ -17,196 +18,175 @@
 
 #if defined(HAVE_ALSA)
 
-#include <string.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
+#include <alsa/asoundlib.h>
 
-static int get_format(ft_t ft, int formats, int *fmt);
+typedef struct alsa_priv
+{
+    snd_pcm_t *pcm_handle;
+    void *buf;
+    st_ssize_t buf_size;
+} *alsa_priv_t;
 
-#if HAVE_ALSA9
+static int get_format(ft_t ft, snd_pcm_format_mask_t *fmask, int *fmt);
 
-/* Temporary hack until glibc and alsa kernel drivers match each other. */
-#ifndef __user
-#define __user
-#endif
-#ifndef __kernel
-#define __kernel
-#endif
+extern void st_ub_write_buf(char* buf1, st_sample_t *buf2, st_ssize_t len, char swap);
+extern void st_sb_write_buf(char *buf1, st_sample_t *buf2, st_ssize_t len, char swap);
+extern void st_uw_write_buf(char *buf1, st_sample_t *buf2, st_ssize_t len, char swap);
+extern void st_sw_write_buf(char *buf1, st_sample_t *buf2, st_ssize_t len, char swap);
+extern void st_ub_read_buf(st_sample_t *buf1, char *buf2, st_ssize_t len, char swap);
+extern void st_sb_read_buf(st_sample_t *buf1, char *buf2, st_ssize_t len, char swap);
+extern void st_uw_read_buf(st_sample_t *buf1, char *buf2, st_ssize_t len, char swap);
+extern void st_sw_read_buf(st_sample_t *buf1, char *buf2, st_ssize_t len, char swap);
 
-#include <limits.h>
-#include <sound/asound.h>
+int st_alsasetup(ft_t ft, snd_pcm_stream_t mode)
+{
+    int fmt = SND_PCM_FORMAT_S16;
+    int err;
+    alsa_priv_t alsa = (alsa_priv_t)ft->priv;
+    snd_pcm_hw_params_t *hw_params;
+    unsigned int min_rate, max_rate;
+    unsigned int min_chan, max_chan;
+    unsigned int rate;
+    int dir;
+    snd_pcm_format_mask_t *fmask;
 
-/* Backwards compatibility. */
-#define SND_PCM_SFMT_S8     SNDRV_PCM_FORMAT_S8
-#define SND_PCM_SFMT_U8     SNDRV_PCM_FORMAT_U8
-#define SND_PCM_SFMT_S16_LE SNDRV_PCM_FORMAT_S16
-#define SND_PCM_SFMT_U16_LE SNDRV_PCM_FORMAT_U16
+    /* Reserve buffer for 16-bit data.  FIXME: Whats a good size? */
+    alsa->buf_size = ST_BUFSIZ*2;
 
-#define SND_PCM_FMT_S8      (1 << SNDRV_PCM_FORMAT_S8)
-#define SND_PCM_FMT_U8      (1 << SNDRV_PCM_FORMAT_U8)
-#define SND_PCM_FMT_S16     (1 << SNDRV_PCM_FORMAT_S16)
-#define SND_PCM_FMT_U16     (1 << SNDRV_PCM_FORMAT_U16)
+    if ((alsa->buf = malloc(alsa->buf_size)) == NULL) 
+    {
+        st_fail_errno(ft,ST_ENOMEM,
+                      "unable to allocate output buffer of size %d", 
+                      ft->file.size);
+        return(ST_EOF);
+    }
 
-#define alsa_params_masks(p, i) \
-    (&((p)->masks[(i)-SNDRV_PCM_HW_PARAM_FIRST_MASK]))
-#define alsa_params_intervals(p, i) \
-    (&((p)->intervals[(i)-SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]))
+    if ((err = snd_pcm_open(&(alsa->pcm_handle), ft->filename, 
+                            mode, 0)) < 0) 
+    {
+        st_fail_errno(ft, ST_EPERM, "cannot open audio device\n");
+        return ST_EOF;
+    }
 
-struct alsa_info
-{
-    unsigned int formats;
-    unsigned int min_buffer_size;
-    unsigned int max_buffer_size;
-    unsigned int min_channels;
-    unsigned int max_channels;
-    unsigned int min_rate;
-    unsigned int max_rate;
-    unsigned int min_periods;
-    unsigned int max_periods;
-    unsigned int min_period_size;
-    unsigned int max_period_size;
-};
+    if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) 
+    {
+        st_fail_errno(ft, ST_ENOMEM, 
+                      "cannot allocate hardware parameter structure\n");
+        return ST_EOF;
+    }
 
-struct alsa_setup
-{
-    int format;
-    char channels;
-    st_rate_t rate;
-    size_t buffer_size;
-    int periods;
-    size_t period_size;
-};
+    if ((err = snd_pcm_hw_params_any(alsa->pcm_handle, hw_params)) < 0) 
+    {
+        st_fail_errno(ft, ST_EPERM,
+                      "cannot initialize hardware parameter structure\n");
+        return ST_EOF;
+    }
 
-int
-alsa_hw_info_get(fd, a_info, params)
-int fd;
-struct alsa_info *a_info;
-struct sndrv_pcm_hw_params *params;
-{
-    unsigned int i;
-    struct sndrv_mask *msk;
-    struct sndrv_interval *intr;
-
-    memset(params, '\0', sizeof(struct sndrv_pcm_hw_params));
-    for (i = 0; i <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; ++i)
+    if ((err = snd_pcm_hw_params_set_access(alsa->pcm_handle, hw_params, 
+                                            SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
     {
-        if (i >= SNDRV_PCM_HW_PARAM_FIRST_MASK &&
-            i <= SNDRV_PCM_HW_PARAM_LAST_MASK)
-        {
-            msk = alsa_params_masks(params, i);
-            memset(msk->bits, 0xff, sizeof(msk->bits));
-        }
-        else
-        {
-            intr = alsa_params_intervals(params, i);
-            intr->min = 0;
-            intr->openmin = 0;
-            intr->max = UINT_MAX;
-            intr->openmax = 0;
-            intr->integer = 0;
-            intr->empty = 0;
-        }
-        params->cmask |= 1 << i;
-        params->rmask |= 1 << i;
+        st_fail_errno(ft, ST_EPERM,
+                      "cannot set access type\n");
+        return ST_EOF;
     }
-    if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, params) < 0) {
-        return -1;
-    }
-    msk = alsa_params_masks(params, SNDRV_PCM_HW_PARAM_FORMAT);
-    a_info->formats = msk->bits[0]; /* Only care about first 32 bits. */
-    a_info->min_buffer_size = alsa_params_intervals(params, SNDRV_PCM_HW_PARAM_BUFFER_BYTES)->min;
-    a_info->max_buffer_size = alsa_params_intervals(params, SNDRV_PCM_HW_PARAM_BUFFER_BYTES)->max;
-    a_info->min_channels = alsa_params_intervals(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min;
-    a_info->max_channels = alsa_params_intervals(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max;
-    a_info->min_rate = alsa_params_intervals(params, SNDRV_PCM_HW_PARAM_RATE)->min;
-    a_info->max_rate = alsa_params_intervals(params, SNDRV_PCM_HW_PARAM_RATE)->max;
-    a_info->min_periods = alsa_params_intervals(params, SNDRV_PCM_HW_PARAM_PERIODS)->min;
-    a_info->max_periods = alsa_params_intervals(params, SNDRV_PCM_HW_PARAM_PERIODS)->max;
-    a_info->min_period_size = alsa_params_intervals(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)->min;
-    a_info->max_period_size = alsa_params_intervals(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)->max;
-    return 0;
-}
 
-int
-alsa_hw_info_set(fd, params, setup)
-int fd;
-struct sndrv_pcm_hw_params *params;
-struct alsa_setup *setup;
-{
-    int i;
-    struct sndrv_mask *msk;
-    struct sndrv_interval *intr;
+    snd_pcm_hw_params_get_channels_min(hw_params, &min_chan);
+    snd_pcm_hw_params_get_channels_max(hw_params, &max_chan);
+    if (ft->info.channels == -1) 
+        ft->info.channels = min_chan;
+    else 
+        if (ft->info.channels > max_chan) 
+            ft->info.channels = max_chan;
+        else if (ft->info.channels < min_chan) 
+            ft->info.channels = min_chan;
 
-    params->cmask = 0;
-    params->rmask = 0;
+    snd_pcm_format_mask_malloc(&fmask);
+    snd_pcm_hw_params_get_format_mask(hw_params, fmask);
 
-    i = SNDRV_PCM_HW_PARAM_ACCESS;
-    msk = alsa_params_masks(params, i);
-    msk->bits[0] &= 1 << SNDRV_PCM_ACCESS_RW_INTERLEAVED; /* Only care about first 32 bits. */
-    params->cmask |= 1 << i;
-    params->rmask |= 1 << i;
+    if (get_format(ft, fmask, &fmt) < 0)
+        return (ST_EOF);
 
-    i = SNDRV_PCM_HW_PARAM_FORMAT;
-    msk = alsa_params_masks(params, i);
-    msk->bits[0] &= 1 << setup->format; /* Only care about first 32 bits. */
-    params->cmask |= 1 << i;
-    params->rmask |= 1 << i;
+    snd_pcm_format_mask_free(fmask);
 
-    i = SNDRV_PCM_HW_PARAM_CHANNELS;
-    intr = alsa_params_intervals(params, i);
-    intr->empty = 0;
-    intr->min = intr->max = setup->channels;
-    intr->openmin = intr->openmax = 0;
-    intr->integer = 1;
-    params->cmask |= 1 << i;
-    params->rmask |= 1 << i;
+    if ((err = snd_pcm_hw_params_set_format(alsa->pcm_handle, 
+                                            hw_params, fmt)) < 0) 
+    {
+        st_fail_errno(ft, ST_EPERM, "cannot set sample format\n");
+        return ST_EOF;
+    }
 
-    i = SNDRV_PCM_HW_PARAM_RATE;
-    intr = alsa_params_intervals(params, i);
-    intr->empty = 0;
-    intr->min = intr->max = setup->rate;
-    intr->openmin = intr->openmax = 0;
-    intr->integer = 1;
-    params->cmask |= 1 << i;
-    params->rmask |= 1 << i;
+    snd_pcm_hw_params_get_rate_min(hw_params, &min_rate, &dir);
+    snd_pcm_hw_params_get_rate_max(hw_params, &max_rate, &dir);
 
-    i = SNDRV_PCM_HW_PARAM_BUFFER_BYTES;
-    intr = alsa_params_intervals(params, i);
-    intr->empty = 0;
-    intr->min = intr->max = setup->buffer_size;
-    intr->openmin = intr->openmax = 0;
-    intr->integer = 1;
-    params->cmask |= 1 << i;
-    params->rmask |= 1 << i;
+    rate = ft->info.rate;
+    if (rate < min_rate) 
+        rate = min_rate;
+    else 
+        if (rate > max_rate) 
+            rate = max_rate;
+    if (rate != ft->info.rate)
+    {
+        st_warn("alsa: Hardware does not support %d.  Forcing sample rate to %d.\n", ft->info.rate, rate);
+    }
 
-    i = SNDRV_PCM_HW_PARAM_PERIODS;
-    intr = alsa_params_intervals(params, i);
-    intr->empty = 0;
-    intr->min = intr->max = setup->periods;
-    intr->openmin = intr->openmax = 0;
-    intr->integer = 1;
-    params->cmask |= 1 << i;
-    params->rmask |= 1 << i;
+    dir = 0;
+    if ((err = snd_pcm_hw_params_set_rate_near(alsa->pcm_handle, 
+                                               hw_params, 
+                                               &rate,
+                                               &dir)) < 0) 
+    {
+        st_fail_errno(ft, ST_EPERM, "cannot set sample rate\n");
+        return ST_EOF;
+    }
+    if (rate != ft->info.rate)
+    {
+        st_warn("Could not set exact rate of %d.  Approximating with %d\n",
+                ft->info.rate, rate);
+    }
 
-    i = SNDRV_PCM_HW_PARAM_PERIOD_BYTES;
-    intr = alsa_params_intervals(params, i);
-    intr->empty = 0;
-    intr->min = intr->max = setup->period_size;
-    intr->openmin = intr->openmax = 0;
-    intr->integer = 1;
-    params->cmask |= 1 << i;
-    params->rmask |= 1 << i;
+    snd_pcm_hw_params_get_rate(hw_params, &rate, &dir);
 
-    if (ioctl(fd, SNDRV_PCM_IOCTL_HW_PARAMS, params) < 0) {
-        return -1;
+    if ((err = snd_pcm_hw_params_set_channels(alsa->pcm_handle,
+                                              hw_params, 
+                                              ft->info.channels)) < 0) 
+    {
+        st_fail_errno(ft, ST_EPERM, "cannot set channel count\n");
+        return ST_EOF;
     }
-    if (ioctl(fd, SNDRV_PCM_IOCTL_PREPARE) < 0) {
-        return -1;
+
+#if 0
+    /* Set number of periods. Periods used to be called fragments. */ 
+    if (snd_pcm_hw_params_set_periods(alsa->pcm_handle, hw_params, 2, 0) < 0) 
+    {
+        st_fail_errno(ft, ST_EPERM, "Error setting periods.\n");
+        return ST_EOF;
     }
-    return 0;
+
+    /* Set buffer size (in frames). The resulting latency is given by */
+    /* latency = periodsize * periods / (rate * bytes_per_frame)     */
+    if (snd_pcm_hw_params_set_buffer_size(alsa->pcm_handle, hw_params, (ST_BUFSIZ * 8)>>2) < 0) {
+      st_fail_errno(ft, ST_EPERM, "Error setting buffersize.\n");
+      return ST_EOF;
+    }
+#endif
+
+    if ((err = snd_pcm_hw_params(alsa->pcm_handle, hw_params)) < 0) 
+    {
+        st_fail_errno(ft, ST_EPERM, "cannot set parameters\n");
+        return ST_EOF;
+    }
+
+    snd_pcm_hw_params_free(hw_params);
+
+    if ((err = snd_pcm_prepare(alsa->pcm_handle)) < 0) 
+    {
+        st_fail_errno(ft, ST_EPERM, "cannot prepare audio interface for use\n");
+        return ST_EOF;
+    }
+
+    sigintreg(ft);      /* Prepare to catch SIGINT */
+
+    return (ST_SUCCESS);
 }
 
 /*
@@ -216,393 +196,348 @@
  *      size and encoding of samples,
  *      mono/stereo/quad.
  */
-int st_alsastartread(ft)
-ft_t ft;
+int st_alsastartread(ft_t ft)
 {
-    int fmt;
-    struct alsa_info a_info;
-    struct alsa_setup a_setup;
-    struct sndrv_pcm_hw_params params;
+    return st_alsasetup(ft, SND_PCM_STREAM_CAPTURE);
+}
 
-    if (alsa_hw_info_get(fileno(ft->fp), &a_info, &params) < 0) {
-        st_fail_errno(ft,ST_EPERM,"ioctl operation failed %d",errno);
-        return(ST_EOF);
-    }
-    ft->file.count = 0;
-    ft->file.pos = 0;
-    ft->file.eof = 0;
-    ft->file.size = a_info.max_buffer_size;
-    if ((ft->file.buf = malloc (ft->file.size)) == NULL) {
-        st_fail_errno(ft,ST_ENOMEM,"unable to allocate output buffer of size %d", ft->file.size);
-        return(ST_EOF);
-    }
-    if (ft->info.rate < a_info.min_rate) ft->info.rate = a_info.min_rate;
-    else if (ft->info.rate > a_info.max_rate) ft->info.rate = a_info.max_rate;
-    if (ft->info.channels == -1) ft->info.channels = a_info.min_channels;
-    else if (ft->info.channels > a_info.max_channels) ft->info.channels = a_info.max_channels;
-    else if (ft->info.channels < a_info.min_channels) ft->info.channels = a_info.min_channels;
-    if (get_format(ft, a_info.formats, &fmt) < 0)
-        return (ST_EOF);
+st_ssize_t st_alsaread(ft_t ft, st_sample_t *buf, st_ssize_t nsamp)
+{
+    st_ssize_t len;
+    alsa_priv_t alsa = (alsa_priv_t)ft->priv;
+    void (*read_buf)(st_sample_t *, char *, st_ssize_t, char) = 0;
 
-    a_setup.format = fmt;
-    a_setup.channels = ft->info.channels;
-    a_setup.rate = ft->info.rate;
-    a_setup.buffer_size = ft->file.size;
-    a_setup.periods = 16;
-    if (a_setup.periods < a_info.min_periods) a_setup.periods = a_info.min_periods;
-    else if (a_setup.periods > a_info.max_periods) a_setup.periods = a_info.max_periods;
-    a_setup.period_size = a_setup.buffer_size / a_setup.periods;
-    if (a_setup.period_size < a_info.min_period_size) a_setup.period_size = a_info.min_period_size;
-    else if (a_setup.period_size > a_info.max_period_size) a_setup.period_size = a_info.max_period_size;
-    if (alsa_hw_info_set(fileno(ft->fp), &params, &a_setup) < 0) {
-        st_fail_errno(ft,ST_EPERM,"ioctl operation failed %d",errno);
-        return(ST_EOF);
+    /* Check to see if user sent SIGINT and if so return ST_EOF to
+     * stop playing.
+     */
+    if (ft->file.eof)
+        return ST_EOF;
+
+
+    switch(ft->info.size) {
+        case ST_SIZE_BYTE:
+            switch(ft->info.encoding)
+            {
+                case ST_ENCODING_SIGN2:
+                    read_buf = st_sb_read_buf;
+                    break;
+                case ST_ENCODING_UNSIGNED:
+                    read_buf = st_ub_read_buf;
+                    break;
+                default:
+                    st_fail_errno(ft,ST_EFMT,"Do not support this encoding for this data size");
+                    return ST_EOF;
+            }
+            break;
+        case ST_SIZE_WORD:
+            switch(ft->info.encoding)
+            {
+                case ST_ENCODING_SIGN2:
+                    read_buf = st_sw_read_buf;
+                    break;
+                case ST_ENCODING_UNSIGNED:
+                    read_buf = st_uw_read_buf;
+                    break;
+                default:
+                    st_fail_errno(ft,ST_EFMT,"Do not support this encoding for this data size");
+                    return ST_EOF;
+            }
+            break;
+        default:
+            st_fail_errno(ft,ST_EFMT,"Do not support this data size for this handler");
+            return ST_EOF;
     }
 
-    /* Change to non-buffered I/O */
-    setvbuf(ft->fp, NULL, _IONBF, sizeof(char) * ft->file.size);
+    /* Prevent overflow */
+    if (nsamp > alsa->buf_size/ft->info.size)
+        nsamp = (alsa->buf_size/ft->info.size);
 
-    sigintreg(ft);      /* Prepare to catch SIGINT */
+    len = snd_pcm_readi(alsa->pcm_handle, alsa->buf, nsamp);
 
-    return (ST_SUCCESS);
+    read_buf(buf, alsa->buf, len, ft->swap);
+
+    return len;
 }
 
-int st_alsastartwrite(ft)
+int st_alsastopread(ft)
 ft_t ft;
 {
-    int fmt;
-    struct alsa_info a_info;
-    struct alsa_setup a_setup;
-    struct sndrv_pcm_hw_params params;
+    alsa_priv_t alsa = (alsa_priv_t)ft->priv;
 
-    if (alsa_hw_info_get(fileno(ft->fp), &a_info, &params) < 0) {
-        st_fail_errno(ft,ST_EPERM,"ioctl operation failed %d",errno);
-        return(ST_EOF);
-    }
-    ft->file.pos = 0;
-    ft->file.eof = 0;
-    ft->file.size = a_info.max_buffer_size;
-    if ((ft->file.buf = malloc (ft->file.size)) == NULL) {
-        st_fail_errno(ft,ST_ENOMEM,"unable to allocate output buffer of size %d", ft->file.size);
-        return(ST_EOF);
-    }
-    if (ft->info.rate < a_info.min_rate) ft->info.rate = a_info.min_rate;
-    else if (ft->info.rate > a_info.max_rate) ft->info.rate = a_info.max_rate;
-    if (ft->info.channels == -1) ft->info.channels = a_info.min_channels;
-    else if (ft->info.channels > a_info.max_channels) ft->info.channels = a_info.max_channels;
-    else if (ft->info.channels < a_info.min_channels) ft->info.channels = a_info.min_channels;
-    if (get_format(ft, a_info.formats, &fmt) < 0)
-        return (ST_EOF);
+    snd_pcm_close(alsa->pcm_handle);
 
-    a_setup.format = fmt;
-    a_setup.channels = ft->info.channels;
-    a_setup.rate = ft->info.rate;
-    a_setup.buffer_size = ft->file.size;
-    a_setup.periods = 16;
-    if (a_setup.periods < a_info.min_periods) a_setup.periods = a_info.min_periods;
-    else if (a_setup.periods > a_info.max_periods) a_setup.periods = a_info.max_periods;
-    a_setup.period_size = a_setup.buffer_size / a_setup.periods;
-    if (a_setup.period_size < a_info.min_period_size) a_setup.period_size = a_info.min_period_size;
-    else if (a_setup.period_size > a_info.max_period_size) a_setup.period_size = a_info.max_period_size;
-    if (alsa_hw_info_set(fileno(ft->fp), &params, &a_setup) < 0) {
-        st_fail_errno(ft,ST_EPERM,"ioctl operation failed %d",errno);
-        return(ST_EOF);
-    }
+    free(alsa->buf);
 
-    /* Change to non-buffered I/O */
-    setvbuf(ft->fp, NULL, _IONBF, sizeof(char) * ft->file.size);
-
-    return(ST_SUCCESS);
+    return ST_SUCCESS;
 }
 
-int st_alsastopwrite(ft)
-ft_t ft;
+int st_alsastartwrite(ft_t ft)
 {
-    int rc;
+    return st_alsasetup(ft, SND_PCM_STREAM_PLAYBACK);
 
-    rc = st_rawstopwrite(ft);
-    ioctl(fileno(ft->fp), SNDRV_PCM_IOCTL_DRAIN);
-    return(rc);
-}
+    int fmt = SND_PCM_FORMAT_S16;
+    int err;
+    alsa_priv_t alsa = (alsa_priv_t)ft->priv;
+    snd_pcm_hw_params_t *hw_params;
+    unsigned int min_rate, max_rate;
+    unsigned int min_chan, max_chan;
+    unsigned int rate;
+    int dir;
+    snd_pcm_format_mask_t *fmask;
 
-#else /* ! HAVE_ALSA9 */
+    /* Reserve buffer for 16-bit data.  FIXME: Whats a good size? */
+    alsa->buf_size = ST_BUFSIZ*2;
 
-#include <linux/asound.h>
-
-#if HAVE_ALSA4 /* Start 0.4.x API */
-
-int st_alsastartread(ft)
-ft_t ft;
-{
-    int bps, fmt, size;
-    snd_pcm_capture_info_t c_info;
-    snd_pcm_format_t format;
-    snd_pcm_capture_params_t c_params;
-
-    memset(&c_info, 0, sizeof(c_info));
-    if (ioctl(fileno(ft->fp), SND_PCM_IOCTL_CAPTURE_INFO, &c_info) < 0) {
-        st_fail_errno(ft,ST_EPERM,"ioctl operation failed %d",errno);
+    if ((alsa->buf = malloc(alsa->buf_size)) == NULL) 
+    {
+        st_fail_errno(ft,ST_ENOMEM,
+                      "unable to allocate output buffer of size %d", 
+                      ft->file.size);
         return(ST_EOF);
     }
-    ft->file.count = 0;
-    ft->file.pos = 0;
-    ft->file.eof = 0;
-    ft->file.size = c_info.buffer_size;
-    if ((ft->file.buf = malloc (ft->file.size)) == NULL) {
-        st_fail_errno(ft,ST_ENOMEM,"unable to allocate output buffer of size %d", ft->file.size);
-        return(ST_EOF);
+
+    if ((err = snd_pcm_open(&(alsa->pcm_handle), ft->filename, 
+                            SND_PCM_STREAM_PLAYBACK, 0)) < 0) 
+    {
+        st_fail_errno(ft, ST_EPERM, "cannot open audio device\n");
+        return ST_EOF;
     }
-    if (ft->info.rate < c_info.min_rate) ft->info.rate = 2 * c_info.min_rate;
-    else if (ft->info.rate > c_info.max_rate) ft->info.rate = c_info.max_rate;
-    if (ft->info.channels == -1) ft->info.channels = c_info.min_channels;
-    else if (ft->info.channels > c_info.max_channels) ft->info.channels = c_info.max_channels;
-    if (get_format(ft, c_info.hw_formats, &fmt) < 0)
-        return(ST_EOF);
 
-    memset(&format, 0, sizeof(format));
-    format.format = fmt;
-    format.rate = ft->info.rate;
-    format.channels = ft->info.channels;
-    if (ioctl(fileno(ft->fp), SND_PCM_IOCTL_CAPTURE_FORMAT, &format) < 0) {
-        st_fail_errno(ft,ST_EPERM,"ioctl operation failed %d",errno);
-        return(ST_EOF);
+    if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) 
+    {
+        st_fail_errno(ft, ST_ENOMEM, 
+                      "cannot allocate hardware parameter structure\n");
+        return ST_EOF;
     }
 
-    size = ft->file.size;
-    bps = format.rate * format.channels;
-    if (ft->info.size == ST_SIZE_WORD) bps <<= 1;
-    bps >>= 2;
-    while (size > bps) size >>= 1;
-    if (size < 16) size = 16;
-    memset(&c_params, 0, sizeof(c_params));
-    c_params.fragment_size = size;
-    c_params.fragments_min = 1;
-    if (ioctl(fileno(ft->fp), SND_PCM_IOCTL_CAPTURE_PARAMS, &c_params) < 0) {
-        st_fail_errno(ft,ST_EPERM,"ioctl operation failed %d",errno);
-        return(ST_EOF);
+    if ((err = snd_pcm_hw_params_any(alsa->pcm_handle, hw_params)) < 0) 
+    {
+        st_fail_errno(ft, ST_EPERM,
+                      "cannot initialize hardware parameter structure\n");
+        return ST_EOF;
     }
 
-    /* Change to non-buffered I/O */
-    setvbuf(ft->fp, NULL, _IONBF, sizeof(char) * ft->file.size);
+    if ((err = snd_pcm_hw_params_set_access(alsa->pcm_handle, hw_params, 
+                                            SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
+    {
+        st_fail_errno(ft, ST_EPERM,
+                      "cannot set access type\n");
+        return ST_EOF;
+    }
 
-    sigintreg(ft);      /* Prepare to catch SIGINT */
+    snd_pcm_hw_params_get_channels_min(hw_params, &min_chan);
+    snd_pcm_hw_params_get_channels_max(hw_params, &max_chan);
+    if (ft->info.channels == -1) 
+        ft->info.channels = min_chan;
+    else 
+        if (ft->info.channels > max_chan) 
+            ft->info.channels = max_chan;
+        else if (ft->info.channels < min_chan) 
+            ft->info.channels = min_chan;
 
-    return (ST_SUCCESS);
-}
+    snd_pcm_format_mask_malloc(&fmask);
+    snd_pcm_hw_params_get_format_mask(hw_params, fmask);
 
-int st_alsastartwrite(ft)
-ft_t ft;
-{
-    int bps, fmt, size;
-    snd_pcm_playback_info_t p_info;
-    snd_pcm_format_t format;
-    snd_pcm_playback_params_t p_params;
+    if (get_format(ft, fmask, &fmt) < 0)
+        return (ST_EOF);
 
-    memset(&p_info, 0, sizeof(p_info));
-    if (ioctl(fileno(ft->fp), SND_PCM_IOCTL_PLAYBACK_INFO, &p_info) < 0) {
-        st_fail_errno(ft,ST_EPERM,"ioctl operation failed %d",errno);
-        return(ST_EOF);
+    snd_pcm_format_mask_free(fmask);
+
+    if ((err = snd_pcm_hw_params_set_format(alsa->pcm_handle, 
+                                            hw_params, fmt)) < 0) 
+    {
+        st_fail_errno(ft, ST_EPERM, "cannot set sample format\n");
+        return ST_EOF;
     }
-    ft->file.pos = 0;
-    ft->file.eof = 0;
-    ft->file.size = p_info.buffer_size;
-    if ((ft->file.buf = malloc (ft->file.size)) == NULL) {
-        st_fail_errno(ft,ST_ENOMEM,"unable to allocate output buffer of size %d", ft->file.size);
-        return(ST_EOF);
+
+    snd_pcm_hw_params_get_rate_min(hw_params, &min_rate, &dir);
+    snd_pcm_hw_params_get_rate_max(hw_params, &max_rate, &dir);
+
+    rate = ft->info.rate;
+    if (rate < min_rate) 
+        rate = min_rate;
+    else 
+        if (rate > max_rate) 
+            rate = max_rate;
+    if (rate != ft->info.rate)
+    {
+        st_warn("alsa: Hardware does not support %d.  Forcing sample rate to %d.\n", ft->info.rate, rate);
     }
-    if (ft->info.rate < p_info.min_rate) ft->info.rate = 2 * p_info.min_rate;
-    else if (ft->info.rate > p_info.max_rate) ft->info.rate = p_info.max_rate;
-    if (ft->info.channels == -1) ft->info.channels = p_info.min_channels;
-    else if (ft->info.channels > p_info.max_channels) ft->info.channels = p_info.max_channels;
-    if (get_format(ft, p_info.hw_formats, &fmt) < 0)
-        return(ST_EOF);
 
-    memset(&format, 0, sizeof(format));
-    format.format = fmt;
-    format.rate = ft->info.rate;
-    format.channels = ft->info.channels;
-    if (ioctl(fileno(ft->fp), SND_PCM_IOCTL_PLAYBACK_FORMAT, &format) < 0) {
-        st_fail_errno(ft,ST_EPERM,"ioctl operation failed %d",errno);
-        return(ST_EOF);
+    dir = 0;
+    if ((err = snd_pcm_hw_params_set_rate_near(alsa->pcm_handle, 
+                                               hw_params, 
+                                               &rate,
+                                               &dir)) < 0) 
+    {
+        st_fail_errno(ft, ST_EPERM, "cannot set sample rate\n");
+        return ST_EOF;
     }
+    if (rate != ft->info.rate)
+    {
+        st_warn("Could not set exact rate of %d.  Approximating with %d\n",
+                ft->info.rate, rate);
+    }
 
-    size = ft->file.size;
-    bps = format.rate * format.channels;
-    if (ft->info.size == ST_SIZE_WORD) bps <<= 1;
-    bps >>= 2;
-    while (size > bps) size >>= 1;
-    if (size < 16) size = 16;
-    memset(&p_params, 0, sizeof(p_params));
-    p_params.fragment_size = size;
-    p_params.fragments_max = -1;
-    p_params.fragments_room = 1;
-    if (ioctl(fileno(ft->fp), SND_PCM_IOCTL_PLAYBACK_PARAMS, &p_params) < 0) {
-        st_fail_errno(ft,ST_EPERM,"ioctl operation failed %d",errno);
-        return(ST_EOF);
+    snd_pcm_hw_params_get_rate(hw_params, &rate, &dir);
+
+    if ((err = snd_pcm_hw_params_set_channels(alsa->pcm_handle,
+                                              hw_params, 
+                                              ft->info.channels)) < 0) 
+    {
+        st_fail_errno(ft, ST_EPERM, "cannot set channel count\n");
+        return ST_EOF;
     }
 
-    /* Change to non-buffered I/O */
-    setvbuf(ft->fp, NULL, _IONBF, sizeof(char) * ft->file.size);
+#if 0
+    /* Set number of periods. Periods used to be called fragments. */ 
+    if (snd_pcm_hw_params_set_periods(alsa->pcm_handle, hw_params, 2, 0) < 0) 
+    {
+        st_fail_errno(ft, ST_EPERM, "Error setting periods.\n");
+        return ST_EOF;
+    }
 
-    return(ST_SUCCESS);
-}
-
-int st_alsastopwrite(ft)
-ft_t ft;
-{
-    /* Is there a drain operation for ALSA 0.4.X? */
-    return(st_rawstopwrite(ft));
-}
-
-#elif HAVE_ALSA5 /* Start 0.5.x API */
-
-int st_alsastartread(ft)
-ft_t ft;
-{
-    int bps, fmt, size;
-    snd_pcm_channel_info_t c_info;
-    snd_pcm_channel_params_t c_params;
-
-    memset(&c_info, 0, sizeof(c_info));
-    if (ioctl(fileno(ft->fp), SND_PCM_IOCTL_CHANNEL_INFO, &c_info) < 0) {
-        st_fail_errno(ft,ST_EPERM,"ioctl operation failed %d",errno);
-        return(ST_EOF);
+    /* Set buffer size (in frames). The resulting latency is given by */
+    /* latency = periodsize * periods / (rate * bytes_per_frame)     */
+    if (snd_pcm_hw_params_set_buffer_size(alsa->pcm_handle, hw_params, (ST_BUFSIZ * 8)>>2) < 0) {
+      st_fail_errno(ft, ST_EPERM, "Error setting buffersize.\n");
+      return ST_EOF;
     }
-    ft->file.count = 0;
-    ft->file.pos = 0;
-    ft->file.eof = 0;
-    ft->file.size = c_info.buffer_size;
-    if ((ft->file.buf = malloc (ft->file.size)) == NULL) {
-        st_fail_errno(ft,ST_ENOMEM,"unable to allocate output buffer of size %d", ft->file.size);
-        return(ST_EOF);
-    }
-    if (ft->info.rate < c_info.min_rate) ft->info.rate = 2 * c_info.min_rate;
-    else if (ft->info.rate > c_info.max_rate) ft->info.rate = c_info.max_rate;
-    if (ft->info.channels == -1) ft->info.channels = c_info.min_voices;
-    else if (ft->info.channels > c_info.max_voices) ft->info.channels = c_info.max_voices;
-    if (get_format(ft, c_info.formats, &fmt) < 0)
-        return (ST_EOF);
+#endif
 
-    memset(&c_params, 0, sizeof(c_params));
-    c_params.format.format = fmt;
-    c_params.format.rate = ft->info.rate;
-    c_params.format.voices = ft->info.channels;
-    c_params.format.interleave = 1;
-    c_params.channel = SND_PCM_CHANNEL_CAPTURE;
-    c_params.mode = SND_PCM_MODE_BLOCK;
-    c_params.start_mode = SND_PCM_START_DATA;
-    c_params.stop_mode = SND_PCM_STOP_STOP;
-    bps = c_params.format.rate * c_params.format.voices;
-    if (ft->info.size == ST_SIZE_WORD) bps <<= 1;
-    bps >>= 2;
-    size = 1;
-    while ((size << 1) < bps) size <<= 1;
-    if (size > ft->file.size) size = ft->file.size;
-    if (size < c_info.min_fragment_size) size = c_info.min_fragment_size;
-    else if (size > c_info.max_fragment_size) size = c_info.max_fragment_size;
-    c_params.buf.block.frag_size = size;
-    c_params.buf.block.frags_max = 32;
-    c_params.buf.block.frags_min = 1;
-    if (ioctl(fileno(ft->fp), SND_PCM_IOCTL_CHANNEL_PARAMS, &c_params) < 0) {
-        st_fail_errno(ft,ST_EPERM,"ioctl operation failed %d",errno);
-        return(ST_EOF);
+    if ((err = snd_pcm_hw_params(alsa->pcm_handle, hw_params)) < 0) 
+    {
+        st_fail_errno(ft, ST_EPERM, "cannot set parameters\n");
+        return ST_EOF;
     }
-    if (ioctl(fileno(ft->fp), SND_PCM_IOCTL_CHANNEL_PREPARE) < 0) {
-        st_fail_errno(ft,ST_EPERM,"ioctl operation failed %d",errno);
-        return(ST_EOF);
-    }
 
-    /* Change to non-buffered I/O */
-    setvbuf(ft->fp, NULL, _IONBF, sizeof(char) * ft->file.size);
+    snd_pcm_hw_params_free(hw_params);
 
+    if ((err = snd_pcm_prepare(alsa->pcm_handle)) < 0) 
+    {
+        st_fail_errno(ft, ST_EPERM, "cannot prepare audio interface for use\n");
+        return ST_EOF;
+    }
+
     sigintreg(ft);      /* Prepare to catch SIGINT */
 
     return (ST_SUCCESS);
 }
 
-int st_alsastartwrite(ft)
-ft_t ft;
+st_ssize_t st_alsawrite(ft_t ft, st_sample_t *buf, st_ssize_t nsamp)
 {
-    int bps, fmt, size;
-    snd_pcm_channel_info_t p_info;
-    snd_pcm_channel_params_t p_params;
+    st_ssize_t len;
+    alsa_priv_t alsa = (alsa_priv_t)ft->priv;
+    void (*write_buf)(char *, st_sample_t *, st_ssize_t, char) = 0;
 
-    memset(&p_info, 0, sizeof(p_info));
-    if (ioctl(fileno(ft->fp), SND_PCM_IOCTL_CHANNEL_INFO, &p_info) < 0) {
-        st_fail_errno(ft,ST_EPERM,"ioctl operation failed %d",errno);
-        return(ST_EOF);
-    }
-    ft->file.pos = 0;
-    ft->file.eof = 0;
-    ft->file.size = p_info.buffer_size;
-    if ((ft->file.buf = malloc (ft->file.size)) == NULL) {
-        st_fail_errno(ft,ST_ENOMEM,"unable to allocate output buffer of size %d", ft->file.size);
-        return(ST_EOF);
-    }
-    if (ft->info.rate < p_info.min_rate) ft->info.rate = 2 * p_info.min_rate;
-    else if (ft->info.rate > p_info.max_rate) ft->info.rate = p_info.max_rate;
-    if (ft->info.channels == -1) ft->info.channels = p_info.min_voices;
-    else if (ft->info.channels > p_info.max_voices) ft->info.channels = p_info.max_voices;
-    if (get_format(ft, p_info.formats, &fmt) < 0)
-        return(ST_EOF);
+    /* Check to see if user sent SIGINT and if so return ST_EOF to
+     * stop recording
+     */
+    if (ft->file.eof)
+        return ST_EOF;
 
-    memset(&p_params, 0, sizeof(p_params));
-    p_params.format.format = fmt;
-    p_params.format.rate = ft->info.rate;
-    p_params.format.voices = ft->info.channels;
-    p_params.format.interleave = 1;
-    p_params.channel = SND_PCM_CHANNEL_PLAYBACK;
-    p_params.mode = SND_PCM_MODE_BLOCK;
-    p_params.start_mode = SND_PCM_START_DATA;
-    p_params.stop_mode = SND_PCM_STOP_STOP;
-    bps = p_params.format.rate * p_params.format.voices;
-    if (ft->info.size == ST_SIZE_WORD) bps <<= 1;
-    bps >>= 2;
-    size = 1;
-    while ((size << 1) < bps) size <<= 1;
-    if (size > ft->file.size) size = ft->file.size;
-    if (size < p_info.min_fragment_size) size = p_info.min_fragment_size;
-    else if (size > p_info.max_fragment_size) size = p_info.max_fragment_size;
-    p_params.buf.block.frag_size = size;
-    p_params.buf.block.frags_max = -1; /* Little trick (playback only) */
-    p_params.buf.block.frags_min = 1;
-    if (ioctl(fileno(ft->fp), SND_PCM_IOCTL_CHANNEL_PARAMS, &p_params) < 0) {
-        st_fail_errno(ft,ST_EPERM,"ioctl operation failed %d",errno);
-        return(ST_EOF);
+    switch(ft->info.size) {
+        case ST_SIZE_BYTE:
+            switch(ft->info.encoding)
+            {
+                case ST_ENCODING_SIGN2:
+                    write_buf = st_sb_write_buf;
+                    break;
+                case ST_ENCODING_UNSIGNED:
+                    write_buf = st_ub_write_buf;
+                    break;
+                default:
+                    st_fail_errno(ft,ST_EFMT,"Do not support this encoding for this data size");
+                    return ST_EOF;
+            }
+            break;
+        case ST_SIZE_WORD:
+            switch(ft->info.encoding)
+            {
+                case ST_ENCODING_SIGN2:
+                    write_buf = st_sw_write_buf;
+                    break;
+                case ST_ENCODING_UNSIGNED:
+                    write_buf = st_uw_write_buf;
+                    break;
+                default:
+                    st_fail_errno(ft,ST_EFMT,"Do not support this encoding for this data size");
+                    return ST_EOF;
+            }
+            break;
+        default:
+            st_fail_errno(ft,ST_EFMT,"Do not support this data size for this handler");
+            return ST_EOF;
     }
-    if (ioctl(fileno(ft->fp), SND_PCM_IOCTL_CHANNEL_PREPARE) < 0) {
-        st_fail_errno(ft,ST_EPERM,"ioctl operation failed %d",errno);
-        return(ST_EOF);
-    }
 
-    /* Change to non-buffered I/O */
-    setvbuf(ft->fp, NULL, _IONBF, sizeof(char) * ft->file.size);
+    /* Prevent overflow */
+    if (nsamp > alsa->buf_size/ft->info.size)
+        nsamp = (alsa->buf_size/ft->info.size);
 
-    return(ST_SUCCESS);
+    write_buf(alsa->buf, buf, nsamp, ft->swap);
+
+    if ((len = snd_pcm_writei(alsa->pcm_handle, alsa->buf, nsamp)) != nsamp) {
+        snd_pcm_prepare(alsa->pcm_handle);
+    }
+
+    return len;
 }
 
+
 int st_alsastopwrite(ft)
 ft_t ft;
 {
-    ioctl(fileno(ft->fp), SND_PCM_IOCTL_CHANNEL_DRAIN);
-    return(st_rawstopwrite(ft));
-}
+    alsa_priv_t alsa = (alsa_priv_t)ft->priv;
 
-#endif /* HAVE_ALSA4/5 */
+    snd_pcm_close(alsa->pcm_handle);
 
-#endif /* HAVE_ALSA9 */
+    free(alsa->buf);
 
+    return ST_SUCCESS;
+}
+
 #define EMSGFMT "ALSA driver does not support %s %s output"
 
-static int get_format(ft_t ft, int formats, int *fmt)
+static int get_format(ft_t ft, snd_pcm_format_mask_t *fmask, int *fmt)
 {
     if (ft->info.size == -1)
         ft->info.size = ST_SIZE_WORD;
 
+    if (ft->info.encoding == -1)
+    {
+        if (ft->info.size == ST_SIZE_WORD)
+            ft->info.encoding = ST_ENCODING_SIGN2;
+        else
+            ft->info.encoding = ST_ENCODING_UNSIGNED;
+    }
+
+    if (ft->info.size != ST_SIZE_WORD &&
+        ft->info.size != ST_SIZE_BYTE)
+    {
+        st_warn("ALSA driver only supports byte and word samples.  Changing to word.\n");
+        ft->info.size = ST_SIZE_WORD;
+    }
+
+    if (ft->info.encoding != ST_ENCODING_SIGN2 &&
+        ft->info.encoding != ST_ENCODING_UNSIGNED)
+    {
+        if (ft->info.size == ST_SIZE_WORD)
+        {
+            st_warn("ALSA driver only supports signed and unsigned samples.  Changing to signed.\n");
+            ft->info.encoding = ST_ENCODING_SIGN2;
+        }
+        else
+        {
+            st_warn("ALSA driver only supports signed and unsigned samples.  Changing to unsigned.\n");
+            ft->info.encoding = ST_ENCODING_UNSIGNED;
+        }
+    }
+
     /* Some hardware only wants to work with 8-bit or 16-bit data */
     if (ft->info.size == ST_SIZE_BYTE)
     {
-        if (!(formats & SND_PCM_FMT_U8) && !(formats & SND_PCM_FMT_S8))
+        if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U8)) && 
+            !(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S8)))
         {
             st_report("ALSA driver doesn't supported byte samples.  Changing to words.");
             ft->info.size = ST_SIZE_WORD;
@@ -610,7 +545,8 @@
     }
     else if (ft->info.size == ST_SIZE_WORD)
     {
-        if (!(formats & SND_PCM_FMT_U16) && !(formats & SND_PCM_FMT_S16))
+        if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U16)) && 
+            !(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S16)))
         {
             st_report("ALSA driver doesn't supported word samples.  Changing to bytes.");
             ft->info.size = ST_SIZE_BYTE;
@@ -618,7 +554,8 @@
     }
     else
     {
-        if ((formats & SND_PCM_FMT_U16) || (formats & SND_PCM_FMT_S16))
+        if ((snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U16)) ||
+            (snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S16)))
         {
             st_report("ALSA driver doesn't supported %s samples.  Changing to words.", st_sizes_str[(unsigned char)ft->info.size]);
             ft->info.size = ST_SIZE_WORD;
@@ -628,16 +565,13 @@
             st_report("ALSA driver doesn't supported %s samples.  Changing to bytes.", st_sizes_str[(unsigned char)ft->info.size]);
             ft->info.size = ST_SIZE_BYTE;
         }
-
     }
 
     if (ft->info.size == ST_SIZE_BYTE) {
-        if (ft->info.encoding == -1)
-            ft->info.encoding = ST_ENCODING_UNSIGNED;
         switch (ft->info.encoding)
         {
             case ST_ENCODING_SIGN2:
-                if (!(formats & SND_PCM_FMT_S8))
+                if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S8)))
                 {
                     st_report("ALSA driver doesn't supported signed byte samples.  Changing to unsigned bytes.");
                     ft->info.encoding = ST_ENCODING_UNSIGNED;
@@ -644,82 +578,68 @@
                 }
                 break;
             case ST_ENCODING_UNSIGNED:
-                if (!(formats & SND_PCM_FMT_U8))
+                if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U8)))
                 {
                     st_report("ALSA driver doesn't supported unsigned byte samples.  Changing to signed bytes.");
                     ft->info.encoding = ST_ENCODING_SIGN2;
                 }
                 break;
-            default:
-                if (formats & SND_PCM_FMT_S8)
-                {
-                    st_report("ALSA driver doesn't support %s %s.  Changing to signed bytes.", 
-                            st_encodings_str[(unsigned char)ft->info.encoding], "byte");
-                    ft->info.encoding = ST_ENCODING_SIGN2;
-                }
-                else
-                {
-                    st_report("ALSA driver doesn't support %s %s.  Changing to unsigned bytes.", 
-                              st_encodings_str[(unsigned char)ft->info.encoding], "byte");
-                    ft->info.encoding = ST_ENCODING_UNSIGNED;
-                }
         }
         switch (ft->info.encoding)
         {
             case ST_ENCODING_SIGN2:
-                if (!(formats & SND_PCM_FMT_S8)) {
+                if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S8)))
+                {
                     st_fail_errno(ft,ST_EFMT,"ALSA driver does not support signed byte samples");
                     return ST_EOF;
                 }
-                *fmt = SND_PCM_SFMT_S8;
+                *fmt = SND_PCM_FORMAT_S8;
                 break;
             case ST_ENCODING_UNSIGNED:
-                if (!(formats & SND_PCM_FMT_U8)) {
+                if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U8)))
+                {
                     st_fail_errno(ft,ST_EFMT,"ALSA driver does not support unsigned byte samples");
                     return ST_EOF;
                 }
-                *fmt = SND_PCM_SFMT_U8;
+                *fmt = SND_PCM_FORMAT_U8;
                 break;
         }
     }
     else if (ft->info.size == ST_SIZE_WORD) {
-        if (ft->info.encoding == -1)
-            ft->info.encoding = ST_ENCODING_SIGN2;
         switch (ft->info.encoding)
         {
             case ST_ENCODING_SIGN2:
-                if (!(formats & SND_PCM_FMT_S16)) {
+                if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S16)))
+                {
                     st_report("ALSA driver does not support signed word samples.  Changing to unsigned words.");
                     ft->info.encoding = ST_ENCODING_UNSIGNED;
                 }
                 break;
             case ST_ENCODING_UNSIGNED:
-                if (!(formats & SND_PCM_FMT_U16)) {
+                if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U16)))
+                {
                     st_report("ALSA driver does not support unsigned word samples.  Changing to signed words.");
                     ft->info.encoding = ST_ENCODING_SIGN2;
                 }
                 break;
-            default:
-                st_report("ALSA driver doesn't support %s %s.  Changing to signed words.", 
-                        st_encodings_str[(unsigned char)ft->info.encoding], "word");
-                ft->info.encoding = ST_ENCODING_SIGN2;
-                break;
         }
         switch (ft->info.encoding)
         {
             case ST_ENCODING_SIGN2:
-                if (!(formats & SND_PCM_FMT_S16)) {
+                if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S16)))
+                {
                     st_fail_errno(ft,ST_EFMT,"ALSA driver does not support signed word samples");
                     return ST_EOF;
                 }
-                *fmt = SND_PCM_SFMT_S16_LE;
+                *fmt = SND_PCM_FORMAT_S16_LE;
                 break;
             case ST_ENCODING_UNSIGNED:
-                if (!(formats & SND_PCM_FMT_U16)) {
+                if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U16)))
+                {
                     st_fail_errno(ft,ST_EFMT,"ALSA driver does not support unsigned word samples");
                     return ST_EOF;
                 }
-                *fmt = SND_PCM_SFMT_U16_LE;
+                *fmt = SND_PCM_FORMAT_U16_LE;
                 break;
         }
     }
@@ -728,71 +648,6 @@
         return ST_EOF;
     }
     return 0;
-}
-
-st_ssize_t st_alsaread(ft_t ft, st_sample_t *buf, st_ssize_t nsamp)
-{
-    st_ssize_t len;
-
-    len = st_rawread(ft, buf, nsamp);
-
-#if HAVE_ALSA9
-    /* ALSA 0.9 and above require that we detects underruns and
-     * reset the driver if it occurs.
-     */
-    if (len != nsamp)
-    {
-        /* Reset the driver.  A future enhancement would be to
-         * fill up the empty spots in the buffer (starting at
-         * nsamp - len).  But I'm being lazy (cbagwell) and just
-         * returning with a partial buffer.
-         */
-        ioctl(fileno(ft->fp), SNDRV_PCM_IOCTL_PREPARE);
-
-        /* Raw routines use eof flag to store when we've
-         * hit EOF or if an internal error occurs.  The
-         * above ioctl is much like calling the stdio clearerr() function
-         * and so we should reset libst's flag as well.  If the
-         * error condition is still really there, it will be
-         * detected on a future read.
-         */
-        ft->file.eof = ST_SUCCESS;
-    }
-#endif
-
-    return len;
-}
-
-st_ssize_t st_alsawrite(ft_t ft, st_sample_t *buf, st_ssize_t nsamp)
-{
-    st_ssize_t len;
-
-    len = st_rawwrite(ft, buf, nsamp);
-
-#if HAVE_ALSA9
-    /* ALSA 0.9 and above require that we detects overruns and
-     * reset the driver if it occurs.
-     */
-    if (len != nsamp)
-    {
-        /* Reset the driver.  A future enhancement would be to
-         * resend the remaining data (starting at (nsamp - len) in the buffer).
-         * But since we've already lost some data, I'm being lazy
-         * and letting a little more data be lost as well.
-         */
-        ioctl(fileno(ft->fp), SNDRV_PCM_IOCTL_PREPARE);
-
-        /* Raw routines use eof flag to store when an internal error
-         * the above ioctl is much like calling the stdio clearerr() function
-         * and so we should reset libst's flag as well.  If the
-         * error condition is still really there, it will be
-         * detected on a future write.
-         */
-        ft->file.eof = ST_SUCCESS;
-    }
-#endif
-
-    return len;
 }
 
 #endif /* HAVE_ALSA */
--- a/src/auto.c
+++ b/src/auto.c
@@ -41,7 +41,7 @@
          * file.  So we start checking for those filetypes first.
          */
         memset(header,0,4);
-        if (st_read(ft, header, 1, 4) == 4)
+        if (st_readbuf(ft, header, 1, 4) == 4)
         {
             /* Look for .snd or dns. header of AU files */
             if ((strncmp(header, ".snd", 4) == 0) ||
@@ -56,7 +56,7 @@
             else if (strncmp(header, "FORM", 4) == 0) 
             {
                 /* Need to read more data to see what type of FORM file */
-                if (st_read(ft, header, 1, 8) == 8)
+                if (st_readbuf(ft, header, 1, 8) == 8)
                 {
                     if (strncmp(header + 4, "AIFF", 4) == 0)
                         type = "aiff";
@@ -70,7 +70,7 @@
             }
             else if (strncmp(header, "RIFF", 4) == 0)
             {
-                if (st_read(ft, header, 1, 8) == 8)
+                if (st_readbuf(ft, header, 1, 8) == 8)
                 {
                     if (strncmp(header + 4, "WAVE", 4) == 0)
                         type = "wav";
@@ -78,7 +78,7 @@
             }
             else if (strncmp(header, "Crea", 4) == 0) 
             {
-                if (st_read(ft, header, 1, 15) == 15)
+                if (st_readbuf(ft, header, 1, 15) == 15)
                 {
                     if (strncmp(header, "tive Voice File", 15) == 0) 
                         type = "voc";
@@ -87,10 +87,10 @@
             else if (strncmp(header, "SOUN", 4) == 0)
             {
                 /* Check for SOUND magic header */
-                if (st_read(ft, header, 1, 1) == 1 && *header == 'D')
+                if (st_readbuf(ft, header, 1, 1) == 1 && *header == 'D')
                 {
                     /* Once we've found SOUND see if its smp or sndt */
-                    if (st_read(ft, header, 1, 12) == 12)
+                    if (st_readbuf(ft, header, 1, 12) == 12)
                     {
                         if (strncmp(header, " SAMPLE DATA", 12) == 0)
                             type = "smp";
@@ -107,7 +107,7 @@
             }
             else if (strncmp(header, "NIST", 4) == 0) 
             {
-                if (st_read(ft, header, 1, 3) == 3)
+                if (st_readbuf(ft, header, 1, 3) == 3)
                 {
                     if (strncmp(header, "_1A", 3) == 0) 
                         type = "sph";
@@ -115,7 +115,7 @@
             }
             else if (strncmp(header, "ALaw", 4) == 0)
             {
-                if (st_read(ft, header, 1, 11) == 11)
+                if (st_readbuf(ft, header, 1, 11) == 11)
                 {
                     if (strncmp(header, "SoundFile**", 11) == 0)
                     {
@@ -137,19 +137,19 @@
             loop = 61;
             while (loop--)
             {
-                if (st_read(ft, header, 1, 1) != 1)
+                if (st_readbuf(ft, header, 1, 1) != 1)
                     loop = 0;
             }
-            if (st_read(ft, header, 1, 4) == 4 && 
+            if (st_readbuf(ft, header, 1, 4) == 4 && 
                 strncmp(header, "FSSD", 4) == 0)
             {
                 loop = 63;
                 while (loop--)
                 {
-                    if (st_read(ft, header, 1, 1) != 1)
+                    if (st_readbuf(ft, header, 1, 1) != 1)
                         loop = 0;
                 }
-                if (st_read(ft, header, 1, 4) == 0 && 
+                if (st_readbuf(ft, header, 1, 4) == 0 && 
                     strncmp(header, "HCOM", 4) == 0)
                     type = "hcom";
             }
@@ -173,7 +173,8 @@
             type = NULL;
     }
 
-    ft->filetype = type;
+    free(ft->filetype);
+    ft->filetype = strdup(type);
     rc = st_gettype(ft); /* Change ft->h to the new format */
     if(rc != ST_SUCCESS)
     {
--- a/src/avr.c
+++ b/src/avr.c
@@ -82,7 +82,7 @@
     return(ST_EOF);
   }
 
-  st_read(ft, avr->name, 1, sizeof(avr->name));
+  st_readbuf(ft, avr->name, 1, sizeof(avr->name));
 
   st_readw (ft, &(avr->mono));
   if (avr->mono) {
@@ -137,9 +137,9 @@
 
   st_readw (ft, &(avr->res3));
 
-  st_read(ft, avr->ext, 1, sizeof(avr->ext));
+  st_readbuf(ft, avr->ext, 1, sizeof(avr->ext));
 
-  st_read(ft, avr->user, 1, sizeof(avr->user));
+  st_readbuf(ft, avr->user, 1, sizeof(avr->user));
 
   rc = st_rawstartread (ft);
   if (rc)
@@ -248,10 +248,10 @@
   st_writew (ft, 0);
 
   /* ext */
-  st_write(ft, (void *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 1, sizeof(avr->ext));
+  st_writebuf(ft, (void *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 1, sizeof(avr->ext));
 
   /* user */
-  st_write(ft, 
+  st_writebuf(ft, 
            (void *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
            "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
            "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
--- a/src/cvsd.c
+++ b/src/cvsd.c
@@ -470,7 +470,7 @@
         int i;
         unsigned sum;
 
-        if (st_read(ft, hdrbuf, sizeof(hdrbuf), 1) != 1)
+        if (st_readbuf(ft, hdrbuf, sizeof(hdrbuf), 1) != 1)
         {
                 return (ST_EOF);
         }
@@ -541,7 +541,7 @@
                 st_report("seek failed\n: %s",strerror(errno));
                 return (ST_EOF);
         }
-        if (st_write(ft, hdrbuf, sizeof(hdrbuf), 1) != 1)
+        if (st_writebuf(ft, hdrbuf, sizeof(hdrbuf), 1) != 1)
         {
                 st_report("%s\n",strerror(errno));
                 return (ST_EOF);
--- a/src/gsm.c
+++ b/src/gsm.c
@@ -121,7 +121,7 @@
 
                 if (done>=samp) break;
 
-                r = st_read(ft, p->frames, p->channels*FRAMESIZE, 1);
+                r = st_readbuf(ft, p->frames, p->channels*FRAMESIZE, 1);
                 if (r != 1) break;
 
                 p->samplePtr = p->samples;
@@ -170,7 +170,7 @@
                         gsp += chans;
                 }
                 gsm_encode(p->handle[ch], gbuff, p->frames);
-                r = st_write(ft, p->frames, FRAMESIZE, 1);
+                r = st_writebuf(ft, p->frames, FRAMESIZE, 1);
                 if (r != 1)
                 {
                         st_fail_errno(ft,errno,"write error");
--- a/src/handlers.c
+++ b/src/handlers.c
@@ -262,8 +262,8 @@
         st_alstartread, st_rawread, st_rawstopread,
         st_alstartwrite, st_rawwrite, st_rawstopwrite, st_format_nothing_seek},
 #ifdef HAVE_ALSA
-    {alsanames, ST_FILE_STEREO,
-        st_alsastartread, st_alsaread, st_rawstopread,
+    {alsanames, ST_FILE_STEREO | ST_FILE_NOSTDIO,
+        st_alsastartread, st_alsaread, st_alsastopread,
         st_alsastartwrite, st_alsawrite, st_alsastopwrite,
         st_format_nothing_seek},
 #endif
@@ -316,7 +316,7 @@
         st_mp3startread, st_mp3read, st_mp3stopread,
         st_mp3startwrite, st_mp3write, st_mp3stopwrite, st_format_nothing_seek},
 #endif
-    {nulnames, ST_FILE_STEREO,
+    {nulnames, ST_FILE_STEREO | ST_FILE_NOSTDIO,
         st_nulstartread, st_nulread, st_nulstopread,
         st_nulstartwrite, st_nulwrite, st_nulstopwrite, st_format_nothing_seek},
 #ifdef HAVE_OSS
--- a/src/hcom.c
+++ b/src/hcom.c
@@ -540,7 +540,7 @@
         }
 
         /* Write the header */
-        st_write(ft, (void *)"\000\001A", 1, 3); /* Dummy file name "A" */
+        st_writebuf(ft, (void *)"\000\001A", 1, 3); /* Dummy file name "A" */
         padbytes(ft, 65-3);
         st_writes(ft, "FSSD");
         padbytes(ft, 83-69);
@@ -554,7 +554,7 @@
         }
 
         /* Write the compressed_data fork */
-        if (st_write(ft, compressed_data, 1, (int)compressed_len) != compressed_len)
+        if (st_writebuf(ft, compressed_data, 1, (int)compressed_len) != compressed_len)
         {
                 st_fail_errno(ft,errno,"can't write compressed HCOM data");
                 rc = ST_EOF;
--- a/src/maud.c
+++ b/src/maud.c
@@ -189,7 +189,7 @@
                             st_fail_errno(ft,ST_ENOMEM,"Couldn't alloc resources");
                             return(ST_EOF);
                         }
-                        if (st_read(ft, chunk_buf, 1, (int)chunksize) 
+                        if (st_readbuf(ft, chunk_buf, 1, (int)chunksize) 
                             != chunksize)
                         {
                                 st_fail_errno(ft,ST_EOF,"MAUD: Unexpected EOF in ANNO header");
--- a/src/misc.c
+++ b/src/misc.c
@@ -80,7 +80,7 @@
  * Returns number of elements read, not bytes read.
  */
 
-st_ssize_t st_read(ft_t ft, void *buf, size_t size, st_ssize_t len)
+st_ssize_t st_readbuf(ft_t ft, void *buf, size_t size, st_ssize_t len)
 {
     return fread(buf, size, len, ft->fp);
 }
@@ -89,7 +89,7 @@
  * Returns number of elements writen, not bytes writen.
  */
 
-st_ssize_t st_write(ft_t ft, void *buf, size_t size, st_ssize_t len)
+st_ssize_t st_writebuf(ft_t ft, void *buf, size_t size, st_ssize_t len)
 {
     return fwrite(buf, size, len, ft->fp);
 }
@@ -147,7 +147,7 @@
     sc = c;
     do
     {
-        if (st_read(ft, &in, 1, 1) != 1)
+        if (st_readbuf(ft, &in, 1, 1) != 1)
         {
             *sc = 0;
                 st_fail_errno(ft,errno,readerr);
@@ -168,7 +168,7 @@
 /* Write null-terminated string (without \0). */
 int st_writes(ft_t ft, char *c)
 {
-        if (st_write(ft, c, 1, strlen(c)) != strlen(c))
+        if (st_writebuf(ft, c, 1, strlen(c)) != strlen(c))
         {
                 st_fail_errno(ft,errno,writerr);
                 return(ST_EOF);
@@ -179,7 +179,7 @@
 /* Read byte. */
 int st_readb(ft_t ft, uint8_t *ub)
 {
-        if (st_read(ft, ub, 1, 1) != 1)
+        if (st_readbuf(ft, ub, 1, 1) != 1)
         {
                 st_fail_errno(ft,errno,readerr);
             return(ST_EOF);
@@ -190,7 +190,7 @@
 /* Write byte. */
 int st_writeb(ft_t ft, uint8_t ub)
 {
-        if (st_write(ft, &ub, 1, 1) != 1)
+        if (st_writebuf(ft, &ub, 1, 1) != 1)
         {
                 st_fail_errno(ft,errno,writerr);
                 return(ST_EOF);
@@ -201,7 +201,7 @@
 /* Read word. */
 int st_readw(ft_t ft, uint16_t *uw)
 {
-        if (st_read(ft, uw, 2, 1) != 1)
+        if (st_readbuf(ft, uw, 2, 1) != 1)
         {
                 st_fail_errno(ft,errno,readerr);
             return (ST_EOF);
@@ -216,7 +216,7 @@
 {
         if (ft->swap)
                 uw = st_swapw(uw);
-        if (st_write(ft, &uw, 2, 1) != 1)
+        if (st_writebuf(ft, &uw, 2, 1) != 1)
         {
                 st_fail_errno(ft,errno,writerr);
                 return (ST_EOF);
@@ -227,7 +227,7 @@
 /* Read double word. */
 int st_readdw(ft_t ft, uint32_t *udw)
 {
-        if (st_read(ft, udw, 4, 1) != 1)
+        if (st_readbuf(ft, udw, 4, 1) != 1)
         {
                 st_fail_errno(ft,errno,readerr);
             return (ST_EOF);
@@ -242,7 +242,7 @@
 {
         if (ft->swap)
                 udw = st_swapdw(udw);
-        if (st_write(ft, &udw, 4, 1) != 1)
+        if (st_writebuf(ft, &udw, 4, 1) != 1)
         {
                 st_fail_errno(ft,errno,writerr);
                 return (ST_EOF);
@@ -253,7 +253,7 @@
 /* Read float. */
 int st_readf(ft_t ft, float *f)
 {
-        if (st_read(ft, f, sizeof(float), 1) != 1)
+        if (st_readbuf(ft, f, sizeof(float), 1) != 1)
         {
             return(ST_EOF);
         }
@@ -269,7 +269,7 @@
 
         if (ft->swap)
                 t = st_swapf(t);
-        if (st_write(ft, &t, sizeof(float), 1) != 1)
+        if (st_writebuf(ft, &t, sizeof(float), 1) != 1)
         {
                 st_fail_errno(ft,errno,writerr);
                 return (ST_EOF);
@@ -280,7 +280,7 @@
 /* Read double. */
 int st_readdf(ft_t ft, double *d)
 {
-        if (st_read(ft, d, sizeof(double), 1) != 1)
+        if (st_readbuf(ft, d, sizeof(double), 1) != 1)
         {
             return(ST_EOF);
         }
@@ -294,7 +294,7 @@
 {
         if (ft->swap)
                 d = st_swapd(d);
-        if (st_write(ft, &d, sizeof(double), 1) != 1)
+        if (st_writebuf(ft, &d, sizeof(double), 1) != 1)
         {
                 st_fail_errno(ft,errno,writerr);
                 return (ST_EOF);
--- a/src/mp3.c
+++ b/src/mp3.c
@@ -133,7 +133,7 @@
         /* We need to decode the first frame,
          * so we know the output format */
 more_data:
-        ReadSize=st_read(ft, p->InputBuffer, 1, INPUT_BUFFER_SIZE);
+        ReadSize=st_readbuf(ft, p->InputBuffer, 1, INPUT_BUFFER_SIZE);
         if(ReadSize<=0)
         {
                 if(st_error(ft))
@@ -159,7 +159,7 @@
                 /* Read another buffer full of data. */
                 memmove(p->InputBuffer, p->Stream->this_frame, remaining);
 
-                ReadSize=st_read(ft, p->InputBuffer+remaining, 1, INPUT_BUFFER_SIZE-remaining);
+                ReadSize=st_readbuf(ft, p->InputBuffer+remaining, 1, INPUT_BUFFER_SIZE-remaining);
                 if (ReadSize <= 0) {
                   st_fail_errno(ft,ST_EOF,"The file is not an MP3 file or it is corrupted");
                   return ST_EOF;
@@ -192,9 +192,9 @@
                 while (tagsize > 0)
                 {
                     if (tagsize < INPUT_BUFFER_SIZE)
-                        ReadSize=st_read(ft, p->InputBuffer, 1, tagsize);
+                        ReadSize=st_readbuf(ft, p->InputBuffer, 1, tagsize);
                     else
-                        ReadSize=st_read(ft, p->InputBuffer, 1, INPUT_BUFFER_SIZE);
+                        ReadSize=st_readbuf(ft, p->InputBuffer, 1, INPUT_BUFFER_SIZE);
                     tagsize -= ReadSize;
                 }
                 goto more_data;
@@ -289,7 +289,7 @@
         Remaining=p->Stream->bufend - p->Stream->next_frame;
         memmove(p->InputBuffer,p->Stream->next_frame,Remaining);
 
-        ReadSize=st_read(ft, p->InputBuffer+Remaining, 1, 
+        ReadSize=st_readbuf(ft, p->InputBuffer+Remaining, 1, 
                          INPUT_BUFFER_SIZE-Remaining);
         if(ReadSize == 0){
           p->eof=1;
@@ -466,7 +466,7 @@
     goto end;
   }
 
-  if (st_write(ft, mp3buffer, 1, written) < written){
+  if (st_writebuf(ft, mp3buffer, 1, written) < written){
      st_fail_errno(ft,ST_EOF,"File write failed");
      goto end;
   }
@@ -493,7 +493,7 @@
   if ( (written=lame_encode_flush(p->gfp, (unsigned char *)mp3buffer, 7200)) <0){
     st_fail_errno(ft,ST_EOF,"Encoding failed");
   }
-  else if (st_write(ft, mp3buffer, 1, written) < written){
+  else if (st_writebuf(ft, mp3buffer, 1, written) < written){
     st_fail_errno(ft,ST_EOF,"File write failed");
   }
 
--- a/src/play.in
+++ b/src/play.in
@@ -18,6 +18,10 @@
 exec_prefix=@exec_prefix@
 bindir=@bindir@
 
+HAVE_ALSA=@NEED_ALSA@
+HAVE_OSS=@NEED_OSS@
+HAVE_SUNAU=@NEED_ALSA@
+
 # Look for sox in install directory first and then in current direction
 # if not found.
 PATH="$bindir:.:$PATH"
@@ -167,42 +171,50 @@
     shift
 done
 
-arch=`uname -s`
-case $arch in
-  SunOS)
-    case `uname -r` in
-        # Solaris software can auto-detect hardware capabilities.
-        5.*)
-	    arch_defines="-t sunau"
-	    ;;
-	# For SunOS default to signed words.  Some hardware can only play u-law and would need
-	# to be changed here.
-	*)
-	    arch_defines="-t sunau -w -s"
-	    ;;
-    esac
-    if [ -z "$device" ]; then
-	device="/dev/audio"
-    fi
-    ;;
-  Linux|FreeBSD)
-    arch_defines="-t ossdsp"
-    if [ -z "$device" ]; then
-	device="/dev/dsp"
-    fi
-    ;;
-  NetBSD|OpenBSD)
-    arch_defines="-t sunau"
-    if [ -z "$device" ]; then
-        device="/dev/audio"
-    fi
-    ;;
-esac
-
 # If user sets AUDIODEV environment variable then force output device
 # to by that.  Solaris SunRay's make use of this for sure.
 if [ -n "$AUDIODEV" ]; then
     device="$AUDIODEV"
+fi
+
+if [ "$HAVE_ALSA" == "1" ]; then
+    arch_defines="-t alsa"
+    if [ -z "$device" ]; then
+	device="default"
+    fi
+else
+    if [ "$HAVE_OSS" == "1" ]; then
+        arch_defines="-t ossdsp"
+        if [ -z "$device" ]; then
+            device="/dev/dsp"
+        fi
+    else
+        arch=`uname -s`
+        case $arch in
+            SunOS)
+            case `uname -r` in
+                # Solaris software can auto-detect hardware capabilities.
+                5.*)
+                arch_defines="-t sunau"
+                ;;
+                # For SunOS default to signed words.  Some hardware can only play u-law and would need
+                # to be changed here.
+                *)
+                arch_defines="-t sunau -w -s"
+                ;;
+            esac
+            if [ -z "$device" ]; then
+                device="/dev/audio"
+            fi
+            ;;
+            NetBSD|OpenBSD)
+            arch_defines="-t sunau"
+            if [ -z "$device" ]; then
+                device="/dev/audio"
+            fi
+            ;;
+        esac
+    fi
 fi
 
 # If name is "rec" then record else assume user is wanting to play
--- a/src/prc.c
+++ b/src/prc.c
@@ -84,7 +84,7 @@
         }
 
         /* Check the header */
-        st_read(ft, head,1, sizeof(header));
+        st_readbuf(ft, head,1, sizeof(header));
         if (memcmp(head, header, sizeof(header))==0) {
                 st_report("Found Psion record.app header");
         }
@@ -99,7 +99,7 @@
         st_report("Found length=%d",len);
 
         /* dummy read rest */
-        st_read(ft, head,1,14+2+2);
+        st_readbuf(ft, head,1,14+2+2);
 
         ft->info.encoding = ST_ENCODING_ALAW;
         ft->info.size = ST_SIZE_BYTE;
@@ -203,9 +203,9 @@
 
   st_report("Final length=%d",p->length);
   memset(nullbuf,0,14);
-  st_write(ft, header, 1, sizeof(header));
+  st_writebuf(ft, header, 1, sizeof(header));
   st_writew(ft, p->length);
-  st_write(ft, nullbuf,1,14);
+  st_writebuf(ft, nullbuf,1,14);
   st_writew(ft, p->length);
-  st_write(ft, nullbuf,1,2);
+  st_writebuf(ft, nullbuf,1,2);
 }
--- a/src/raw.c
+++ b/src/raw.c
@@ -451,7 +451,7 @@
             i = ft->file.count-ft->file.pos;
             ft->file.pos = 0;
 
-            ft->file.count = st_read(ft, ft->file.buf+i, 1, ft->file.size-i);
+            ft->file.count = st_readbuf(ft, ft->file.buf+i, 1, ft->file.size-i);
             if (ft->file.count != ft->file.size-i || ft->file.count == 0)
             {
                 ft->file.eof = 1;
@@ -641,7 +641,7 @@
 
 static void writeflush(ft_t ft)
 {
-        if (st_write(ft, ft->file.buf, 1, ft->file.pos) != ft->file.pos)
+        if (st_writebuf(ft, ft->file.buf, 1, ft->file.pos) != ft->file.pos)
         {
             ft->file.eof = ST_EOF;
         }
--- a/src/sf.c
+++ b/src/sf.c
@@ -102,7 +102,7 @@
         int rc;
         int samplesize = 0;
 
-        if (st_read(ft, &sfhead, 1, sizeof(sfhead)) != sizeof(sfhead))
+        if (st_readbuf(ft, &sfhead, 1, sizeof(sfhead)) != sizeof(sfhead))
         {
                 st_fail("unexpected EOF in SF header");
                 return(ST_EOF);
@@ -216,7 +216,7 @@
         sfcharp = (char *) sfcodep + sizeof(SFCODE);
         while(sfcharp < (char *) &sfhead + SIZEOF_BSD_HEADER)
                 *sfcharp++ = '\0';
-        st_write(ft, &sfhead, 1, sizeof(SFHEADER));
+        st_writebuf(ft, &sfhead, 1, sizeof(SFHEADER));
 
         return(ST_SUCCESS);
 }
--- a/src/smp.c
+++ b/src/smp.c
@@ -93,7 +93,7 @@
                 ft->loops[i].count = trailer->loops[i].count;
         }
         for(i = 0; i < 8; i++) {        /* read the 8 markers */
-                if (st_read(ft, trailer->markers[i].name, 1, MARKERLEN) != 10)
+                if (st_readbuf(ft, trailer->markers[i].name, 1, MARKERLEN) != 10)
                 {
                     st_fail_errno(ft,ST_EHDR,"EOF in SMP");
                     return(ST_EOF);
@@ -227,7 +227,7 @@
         }
 
         /* Read SampleVision header */
-        if (st_read(ft, (char *)&header, 1, HEADERSIZE) != HEADERSIZE)
+        if (st_readbuf(ft, (char *)&header, 1, HEADERSIZE) != HEADERSIZE)
         {
                 st_fail_errno(ft,ST_EHDR,"unexpected EOF in SMP header");
                 return(ST_EOF);
@@ -387,7 +387,7 @@
         sprintf(header.name, "%-*.*s", NAMELEN, NAMELEN, ft->comment);
 
         /* Write file header */
-        if(st_write(ft, &header, 1, HEADERSIZE) != HEADERSIZE)
+        if(st_writebuf(ft, &header, 1, HEADERSIZE) != HEADERSIZE)
         {
             st_fail_errno(ft,errno,"SMP: Can't write header completely");
             return(ST_EOF);
--- a/src/sndrtool.c
+++ b/src/sndrtool.c
@@ -84,7 +84,7 @@
          and second word is between 4000 & 25000 then this is sounder sound */
         /* otherwise, its probably raw, not handled here */
 
-        if (st_read(ft, buf, 1, 2) != 2)
+        if (st_readbuf(ft, buf, 1, 2) != 2)
         {
                 st_fail_errno(ft,errno,"SND: unexpected EOF");
                 return(ST_EOF);
@@ -103,7 +103,7 @@
         else
         {
         /* sndtool ? */
-        st_read(ft, &buf[2], 1, 6);
+        st_readbuf(ft, &buf[2], 1, 6);
         if (strncmp(buf,"SOUND",5))
         {
                 st_fail_errno(ft,ST_EFMT,"SND: unrecognized SND format");
@@ -253,6 +253,6 @@
     st_writew (ft,4);
     memset (name_buf, 0, 96);
     sprintf (name_buf,"%.62s - File created by Sound Exchange",ft->filename);
-    st_write(ft, name_buf, 1, 96);
+    st_writebuf(ft, name_buf, 1, 96);
 }
 
--- a/src/sox.c
+++ b/src/sox.c
@@ -33,8 +33,6 @@
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
 #endif
-#include <sys/types.h>          /* for fstat() */
-#include <sys/stat.h>           /* for fstat() */
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>             /* for unlink() */
 #endif
@@ -49,6 +47,8 @@
 #endif
 #endif
 
+#include <sys/types.h> /* for fstat() */
+#include <sys/stat.h> /* for fstat() */
 #ifdef _MSC_VER
 /*
  * __STDC__ is defined, so these symbols aren't created.
@@ -96,27 +96,22 @@
 
 /* local forward declarations */
 static void doopts(file_options_t *fo, int, char **);
-static void copy_input(int offset);
-static void open_input(ft_t);
-static void copy_output(int offset);
-static void open_output(ft_t);
 static void usage(char *) NORET;
-static int filetype(int);
 static void process(void);
 static void print_input_status(int input);
 static void update_status(void);
 static void statistics(void);
 static st_sample_t volumechange(st_sample_t *buf, st_ssize_t ct, double vol);
-void parse_effects(int argc, char **argv);
-void check_effects(void);
-void start_effects(void);
-void reserve_effect_buf(void);
+static void parse_effects(int argc, char **argv);
+static void check_effects(void);
+static void start_effects(void);
+static void reserve_effect_buf(void);
 static int flow_effect_out(void);
 static int flow_effect(int);
-int drain_effect_out(void);
-int drain_effect(int);
-void release_effect_buf(void);
-void stop_effects(void);
+static int drain_effect_out(void);
+static int drain_effect(int);
+static void release_effect_buf(void);
+static void stop_effects(void);
 
 #define MAX_INPUT_FILES 32
 #define MAX_FILES MAX_INPUT_FILES + 1
@@ -243,22 +238,12 @@
         if (!file_opts[i]->uservolume)
             file_opts[i]->volume = 1.0 / input_count;
 #endif
-        copy_input(i);
-        open_input(file_desc[i]);
+        file_desc[i] = st_open_input(file_opts[i]->filename,
+                                     &file_opts[i]->info, 
+                                     file_opts[i]->filetype,
+                                     file_opts[i]->swap);
     }
 
-    if (writing)
-    {
-        copy_output(file_count-1);
-        /* Hold off on opening file until the very last minute.
-         * This allows us to verify header in input files are
-         * what they should be and parse effect command lines.
-         * That way if anything is found invalid, we will abort
-         * without truncating any existing file that has the same
-         * output filename.
-         */
-    }
-
     /* Loop through the reset of the arguments looking for effects */
     parse_effects(argc, argv);
 
@@ -274,144 +259,6 @@
     return(0);
 }
 
-static void copy_input(int offset)
-{
-    /* FIXME: Check for malloc for failures */
-    file_desc[offset] = st_initformat();
-    file_desc[offset]->info = file_opts[offset]->info;
-    file_desc[offset]->filename = file_opts[offset]->filename;
-    /* Let auto effect do the work if user is not overriding. */
-    if (!file_opts[offset]->filetype)
-        file_desc[offset]->filetype = "auto";
-    else
-        file_desc[offset]->filetype = strdup(file_opts[offset]->filetype);
-    file_desc[offset]->swap = file_opts[offset]->swap;
-
-    if (st_gettype(file_desc[offset]))
-        st_fail("Unknown input file format for '%s':  %s", 
-                file_desc[offset]->filename, 
-                file_desc[offset]->st_errstr);
-}
-
-static void open_input(ft_t ft)
-{
-    /* Open file handler based on input name.  Used stdin file handler
-     * if the filename is "-"
-     */
-    if (!strcmp(ft->filename, "-"))
-        ft->fp = stdin;
-    else if ((ft->fp = fopen(ft->filename, "rb")) == NULL)
-        st_fail("Can't open input file '%s': %s", ft->filename,
-                strerror(errno));
-
-    /* See if this file is seekable or not */
-#if     defined(DUMB_FILESYSTEM)
-    ft->seekable = 0;
-#else
-    ft->seekable = (filetype(fileno(ft->fp)) == S_IFREG);
-#endif
-}
-
-#if defined(DOS) || defined(WIN32)
-#define LASTCHAR '\\'
-#else
-#define LASTCHAR '/'
-#endif
-
-static void copy_output(int offset)
-{
-    /* FIXME: Check for malloc for failures */
-    file_desc[offset] = st_initformat();;
-    file_desc[offset]->info = file_opts[offset]->info;
-    file_desc[offset]->filename = file_opts[offset]->filename;
-    file_desc[offset]->filetype = file_opts[offset]->filetype;
-    file_desc[offset]->swap = file_opts[offset]->swap;
-
-    if (writing && !file_desc[offset]->filetype) {
-        /* Use filename extension to determine audio type. */
-
-        /* First, chop off any path portions of filename.  This
-         * prevents the next search from considering that part. */
-        /* FIXME: using strrchr can only lead to problems when knowing
-         * what to free()
-         */
-        if ((file_desc[offset]->filetype = 
-             strrchr(file_desc[offset]->filename, LASTCHAR)) == NULL)
-            file_desc[offset]->filetype = file_desc[offset]->filename;
-
-        /* Now look for an filename extension */
-        if ((file_desc[offset]->filetype = 
-             strrchr(file_desc[offset]->filetype, '.')) != NULL)
-            file_desc[offset]->filetype++;
-        else
-            file_desc[offset]->filetype = NULL;
-    }
-
-    if (writing)
-    {
-        if (st_gettype(file_desc[offset]))
-            st_fail("Unknown output file format for '%s': %s",
-                    file_desc[offset]->filename, 
-                    file_desc[offset]->st_errstr);
-
-        /* When writing to an audio device, auto turn on the
-         * status display to match behavior of ogg123/mpg123
-         * utils.  That is unless user requested us not to display]
-         * anything.
-         */
-        if (strcmp(file_desc[offset]->filetype, "alsa") == 0 ||
-            strcmp(file_desc[offset]->filetype, "ossdsp") == 0 ||
-            strcmp(file_desc[offset]->filetype, "sunau") == 0)
-        {
-            if (!quite)
-                status = 1;
-        }
-    }
-}
-
-static void open_output(ft_t ft)
-{
-    if (writing) {
-        /*
-         * There are two choices here:
-         *      1) stomp the old file - normal shell "> file" behavior
-         *      2) fail if the old file already exists - csh mode
-         */
-        if (! strcmp(ft->filename, "-"))
-        {
-            ft->fp = stdout;
-
-            /* stdout tends to be line-buffered.  Override this */
-            /* to be Full Buffering. */
-            if (setvbuf (ft->fp,NULL,_IOFBF,sizeof(char)*ST_BUFSIZ))
-            {
-                st_fail("Can't set write buffer");
-            }
-        }
-        else {
-
-            ft->fp = fopen(ft->filename, "wb");
-
-            if (ft->fp == NULL)
-                st_fail("Can't open output file '%s': %s",
-                        ft->filename, strerror(errno));
-
-            /* stdout tends to be line-buffered.  Override this */
-            /* to be Full Buffering. */
-            if (setvbuf (ft->fp,NULL,_IOFBF,sizeof(char)*ST_BUFSIZ))
-            {
-                st_fail("Can't set write buffer");
-            }
-
-        } /* end of else != stdout */
-#if     defined(DUMB_FILESYSTEM)
-        ft->seekable = 0;
-#else
-        ft->seekable  = (filetype(fileno(ft->fp)) == S_IFREG);
-#endif
-    }
-}
-
 #ifdef HAVE_GETOPT_H
 static char *getoptstr = "+r:v:t:c:phsuUAaigbwlfdxVSq";
 #else
@@ -590,24 +437,6 @@
 
     for (f = 0; f < input_count; f++)
     {
-        /* Read and write starters can change their formats. */
-        if ((*file_desc[f]->h->startread)(file_desc[f]) != ST_SUCCESS)
-        {
-            st_fail("Failed reading %s: %s",file_desc[f]->filename,
-                    file_desc[f]->st_errstr);
-        }
-
-        /* Go a head and assume 1 channel audio if nothing is detected.
-         * This is because libst usually doesn't set this for mono file
-         * formats (for historical reasons).
-         */
-        if (file_desc[f]->info.channels == -1)
-            file_desc[f]->info.channels = 1;
-
-        if (st_checkformat(file_desc[f]) )
-            st_fail("bad input format for file %s: %s", file_desc[f]->filename,
-                    file_desc[f]->st_errstr);
-
         st_report("Input file %s: using sample rate %lu\n\tsize %s, encoding %s, %d %s",
                   file_desc[f]->filename, file_desc[f]->info.rate,
                   st_sizes_str[(unsigned char)file_desc[f]->info.size],
@@ -630,20 +459,29 @@
 
     if (writing)
     {
-        open_output(file_desc[file_count-1]);
+        file_desc[file_count-1] = 
+            st_open_output(file_opts[file_count-1]->filename,
+                           &file_opts[file_count-1]->info, 
+                           &file_desc[0]->info,
+                           file_desc[0]->comment,
+                           file_desc[0]->loops,
+                           &file_desc[0]->instr,
+                           file_opts[file_count-1]->filetype,
+                           file_opts[file_count-1]->swap);
 
-        /* Always use first input file as a reference for output
-         * file format.
+        /* When writing to an audio device, auto turn on the
+         * status display to match behavior of ogg123/mpg123
+         * utils.  That is unless user requested us not to display]
+         * anything.
          */
-        st_copyformat(file_desc[0], file_desc[file_count-1]);
+        if (strcmp(file_desc[file_count-1]->filetype, "alsa") == 0 ||
+            strcmp(file_desc[file_count-1]->filetype, "ossdsp") == 0 ||
+            strcmp(file_desc[file_count-1]->filetype, "sunau") == 0)
+        {
+            if (!quite)
+                status = 1;
+        }
 
-        if ((*file_desc[file_count-1]->h->startwrite)(file_desc[file_count-1]) == ST_EOF)
-            st_fail(file_desc[file_count-1]->st_errstr);
-
-        if (st_checkformat(file_desc[file_count-1]))
-            st_fail("bad output format: %s", 
-                    file_desc[file_count-1]->st_errstr);
-
         st_report("Output file %s: using sample rate %lu\n\tsize %s, encoding %s, %d %s",
                   file_desc[file_count-1]->filename, 
                   file_desc[file_count-1]->info.rate,
@@ -725,6 +563,8 @@
         else
             efftab[0].olen = ilen;
 
+        read_samples += (efftab[0].olen / file_desc[0]->info.channels);
+
         /* Some file handlers claim 0 bytes instead of returning
          * ST_EOF.  In either case, attempt to go to the next
          * input file.
@@ -764,6 +604,10 @@
             if (ilen[f] == ST_EOF)
                 ilen[f] = 0;
 
+            /* Only count read samples for first file in mix */
+            if (f == 0)
+                read_samples += (efftab[0].olen / file_desc[0]->info.channels);
+
             /* Adjust input side volume based on value specified
              * by user for this file.
              */
@@ -865,10 +709,8 @@
         /* If problems closing input file, just warn user since
          * we are exiting anyways.
          */
-        if ((*file_desc[f]->h->stopread)(file_desc[f]) == ST_EOF)
+        if (st_close(file_desc[f]) == ST_EOF)
             st_warn(file_desc[f]->st_errstr);
-        fclose(file_desc[f]->fp);
-        free(file_desc[f]->filename);
     }
 
     if (writing)
@@ -876,15 +718,12 @@
         /* problem closing output file, just warn user since we
          * are exiting anyways.
          */
-        if ((*file_desc[file_count-1]->h->stopwrite)(file_desc[file_count-1]) == ST_EOF)
+        if (st_close(file_desc[file_count-1]) == ST_EOF)
             st_warn(file_desc[file_count-1]->st_errstr);
-        free(file_desc[file_count-1]->filename);
-        free(file_desc[file_count-1]->comment);
-        fclose(file_desc[file_count-1]->fp);
     }
 }
 
-void parse_effects(int argc, char **argv)
+static void parse_effects(int argc, char **argv)
 {
     int argc_effect;
 
@@ -930,7 +769,7 @@
  * Smart ruleset for multiple effects in sequence.
  *      Puts user-specified effect in right place.
  */
-void check_effects(void)
+static void check_effects(void)
 {
     int i;
     int needchan = 0, needrate = 0, haschan = 0, hasrate = 0;
@@ -1112,7 +951,7 @@
     }
 }
 
-void start_effects(void)
+static void start_effects(void)
 {
     int e;
 
@@ -1123,7 +962,7 @@
     }
 }
 
-void reserve_effect_buf(void)
+static void reserve_effect_buf(void)
 {
     int e;
 
@@ -1205,8 +1044,6 @@
           /* Currently, assuming all bytes were written and resetting
            * buffer pointers accordingly.
            */
-          read_samples += (efftab[neffects-1].olen / 
-                           file_desc[file_count-1]->info.channels);
           output_samples += (efftab[neffects-1].olen / 
                              file_desc[file_count-1]->info.channels);
           efftab[neffects-1].odone = efftab[neffects-1].olen = 0;
@@ -1220,8 +1057,6 @@
       else
       {
           /* Make it look like everything was consumed */
-          read_samples += (efftab[neffects-1].olen / 
-                           file_desc[file_count-1]->info.channels);
           output_samples += (efftab[neffects-1].olen / 
                              file_desc[file_count-1]->info.channels);
           efftab[neffects-1].odone = efftab[neffects-1].olen = 0;
@@ -1242,7 +1077,9 @@
 
           if (efftab[e].odone < efftab[e].olen) {
               havedata = 1;
-              break;
+              /* Don't break out because other things are being
+               * done in loop.
+               */
           }
       }
 
@@ -1370,7 +1207,7 @@
     return ST_SUCCESS;
 }
 
-int drain_effect_out(void)
+static int drain_effect_out(void)
 {
     /* Skip past input effect since we know thats not needed */
     if (input_eff == 0)
@@ -1393,7 +1230,7 @@
     return flow_effect_out();
 }
 
-int drain_effect(int e)
+static int drain_effect(int e)
 {
     st_ssize_t i, olen, olenl, olenr;
     st_sample_t *obuf;
@@ -1440,7 +1277,7 @@
     return rc;
 }
 
-void release_effect_buf(void)
+static void release_effect_buf(void)
 {
     int e;
     
@@ -1452,7 +1289,7 @@
     }
 }
 
-void stop_effects(void)
+static void stop_effects(void)
 {
     int e;
 
@@ -1571,15 +1408,6 @@
         return clips;
 }
 
-static int filetype(int fd)
-{
-        struct stat st;
-
-        fstat(fd, &st);
-
-        return st.st_mode & S_IFMT;
-}
-
 #ifdef SOXMIX
 static char *usagestr =
 "[ gopts ] [ fopts ] ifile1 [fopts] ifile2 [ fopts ] ofile [ effect [ effopts ] ]";
@@ -1618,23 +1446,32 @@
 
 
 /* called from util.c::st_fail() */
-void cleanup(void) {
+void cleanup(void) 
+{
     int i;
+    struct stat st;
+    char *fn;
 
     /* Close the input file and outputfile before exiting*/
     for (i = 0; i < input_count; i++)
     {
-        if (file_desc[i] && file_desc[i]->fp)
-                fclose(file_desc[i]->fp);
         if (file_desc[i])
+        {
+            st_close(file_desc[i]);
             free(file_desc[i]);
+        }
     }
-    if (writing && file_desc[file_count-1] && file_desc[file_count-1]->fp) {
-        fclose(file_desc[file_count-1]->fp);
+    if (writing && file_desc[file_count-1])
+    {
+        fstat(fileno(file_desc[file_count-1]->fp), &st);
+        fn = strdup(file_desc[file_count-1]->filename);
+        st_close(file_desc[file_count-1]);
+
         /* remove the output file because we failed, if it's ours. */
         /* Don't if its not a regular file. */
-        if (filetype(fileno(file_desc[file_count-1]->fp)) == S_IFREG)
-            unlink(file_desc[file_count-1]->filename);
+        if ((st.st_mode & S_IFMT) == S_IFREG)
+            unlink(fn);
+        free(fn);
         if (file_desc[file_count-1])
             free(file_desc[file_count-1]);
     }
--- a/src/sphere.c
+++ b/src/sphere.c
@@ -157,7 +157,7 @@
 
         while (header_size)
         {
-            bytes_read = st_read(ft, buf, ST_SIZE_BYTE, header_size);
+            bytes_read = st_readbuf(ft, buf, ST_SIZE_BYTE, header_size);
             if (bytes_read == 0)
             {
                 free(buf);
--- a/src/st.h
+++ b/src/st.h
@@ -19,8 +19,8 @@
 #include <stdlib.h>
 #include "ststdint.h"
 
-/* Release 12.17.8 of libst */
-#define ST_LIB_VERSION_CODE 0x0c1108
+/* Release 12.17.9 of libst */
+#define ST_LIB_VERSION_CODE 0x0c1109
 #define ST_LIB_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
 
 typedef int32_t st_sample_t;
@@ -148,6 +148,7 @@
     st_loopinfo_t   loops[ST_MAX_NLOOPS]; /* Looping specification */
     char            swap;                 /* do byte- or word-swap */
     char            seekable;             /* can seek on this file */
+    char            mode;                 /* read or write mode */
     /* Total samples per channel of file.  Zero if unknown. */
     st_size_t       length;    
     char            *filename;            /* file name */
@@ -175,6 +176,7 @@
 #define ST_FILE_LOOPS   2  /* does file format support loops? */
 #define ST_FILE_INSTR   4  /* does file format support instrument specs? */
 #define ST_FILE_SEEK    8  /* does file format support seeking? */
+#define ST_FILE_NOSTDIO 16 /* does not use stdio routines */
 
 /* Size field */
 #define ST_SIZE_BYTE    1
@@ -252,6 +254,15 @@
 
 extern st_effect_t st_effects[]; /* declared in handlers.c */
 
+extern ft_t st_open_input(const char *path, const st_signalinfo_t *si, 
+                          const char *filetype, const char swap);
+extern ft_t st_open_output(const char *path, const st_signalinfo_t *info,
+                           const st_signalinfo_t *input_info,
+                           const char *comment, const st_loopinfo_t *loops,
+                           const st_instrinfo_t *instr,
+                           const char *filetype, const char swap);
+extern int st_close(ft_t ft);
+
 int st_geteffect_opt(eff_t, int, char **);
 int st_geteffect(eff_t, char *);
 int st_checkeffect(char *);
@@ -258,8 +269,6 @@
 int st_updateeffect(eff_t, st_signalinfo_t *in, st_signalinfo_t *out, int);
 int st_gettype(ft_t);
 ft_t st_initformat(void);
-void st_copyformat(ft_t, ft_t);
-int st_checkformat(ft_t);
 int st_parsesamples(st_rate_t rate, char *str, st_size_t *samples, char def);
 
 /* FIXME: Recording hacks shouldn't display a "sigint" style interface.
--- a/src/st_i.h
+++ b/src/st_i.h
@@ -67,8 +67,8 @@
  * possible byte swapping.
  */
 /* declared in misc.c */
-st_ssize_t st_read(ft_t ft, void *buf, size_t size, st_ssize_t len);
-st_ssize_t st_write(ft_t ft, void *buf, size_t size, st_ssize_t len);
+st_ssize_t st_readbuf(ft_t ft, void *buf, size_t size, st_ssize_t len);
+st_ssize_t st_writebuf(ft_t ft, void *buf, size_t size, st_ssize_t len);
 int st_reads(ft_t ft, char *c, st_ssize_t len);
 int st_writes(ft_t ft, char *c);
 int st_readb(ft_t ft, uint8_t *ub);
@@ -170,6 +170,7 @@
 #ifdef HAVE_ALSA
 int st_alsastartread(ft_t ft);
 st_ssize_t st_alsaread(ft_t ft, st_sample_t *buf, st_ssize_t len);
+int st_alsastopread(ft_t ft);
 int st_alsastartwrite(ft_t ft);
 st_ssize_t st_alsawrite(ft_t ft, st_sample_t *buf, st_ssize_t len);
 int st_alsastopwrite(ft_t ft);
--- /dev/null
+++ b/src/stio.c
@@ -1,0 +1,350 @@
+#include "st.h"
+#include "st_i.h"
+#include "stconfig.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include <stdlib.h>
+
+#include <sys/types.h> /* for fstat() */
+#include <sys/stat.h> /* for fstat() */
+#ifdef _MSC_VER
+/*
+ * __STDC__ is defined, so these symbols aren't created.
+ */
+#define S_IFMT   _S_IFMT
+#define S_IFREG  _S_IFREG
+#define fstat _fstat
+#endif
+
+static int is_seekable(ft_t ft)
+{
+        struct stat st;
+
+        fstat(fileno(ft->fp), &st);
+
+        return ((st.st_mode & S_IFMT) == S_IFREG);
+}
+
+/* check that all settings have been given */
+static int st_checkformat(ft_t ft)
+{
+
+        ft->st_errno = ST_SUCCESS;
+
+        if (ft->info.rate == 0)
+        {
+                st_fail_errno(ft,ST_EFMT,"sampling rate was not specified");
+                return ST_EOF;
+        }
+
+        if (ft->info.size == -1)
+        {
+                st_fail_errno(ft,ST_EFMT,"data size was not specified");
+                return ST_EOF;
+        }
+
+        if (ft->info.encoding == -1)
+        {
+                st_fail_errno(ft,ST_EFMT,"data encoding was not specified");
+                return ST_EOF;
+        }
+
+        if ((ft->info.size <= 0) || (ft->info.size > ST_INFO_SIZE_MAX))
+        {
+                st_fail_errno(ft,ST_EFMT,"data size %i is invalid");
+                return ST_EOF;
+        }
+
+        /* anyway to check length on st_encoding_str[] ? */
+        if (ft->info.encoding <= 0  || ft->info.encoding > ST_ENCODING_MAX)
+        {
+                st_fail_errno(ft,ST_EFMT,"data encoding %i is invalid");
+                return ST_EOF;
+        }
+
+        return ST_SUCCESS;
+}
+
+ft_t st_open_input(const char *path, const st_signalinfo_t *si,
+                   const char *filetype, const char swap)
+{
+    ft_t ft;
+
+    ft = (ft_t)calloc(sizeof(struct st_soundstream), 1);
+
+    if (!ft )
+        return NULL;
+
+    ft->filename = strdup(path);
+
+    /* Let auto effect do the work if user is not overriding. */
+    if (!filetype)
+        ft->filetype = strdup("auto");
+    else
+        ft->filetype = strdup(filetype);
+
+    if (!ft->filename || !ft->filetype)
+        goto input_error;
+
+    if (st_gettype(ft) != ST_SUCCESS)
+    {
+        /* FIXME */
+        st_fail("Unknown input file format for '%s':  %s", 
+                ft->filename, 
+                ft->st_errstr);
+        goto input_error;
+    }
+
+    ft->info.size = -1;
+    ft->info.encoding = -1;
+    ft->info.channels = -1;
+    ft->info = *si;
+    ft->swap = swap;
+    ft->mode = 'r';
+
+    if (!(ft->h->flags & ST_FILE_NOSTDIO))
+    {
+        /* Open file handler based on input name.  Used stdin file handler
+         * if the filename is "-"
+         */
+        if (!strcmp(ft->filename, "-"))
+            ft->fp = stdin;
+        else if ((ft->fp = fopen(ft->filename, "rb")) == NULL)
+        {
+            /* FIXME */
+            st_fail("Can't open input file '%s': %s", ft->filename,
+                    strerror(errno));
+            goto input_error;
+        }
+
+        /* See if this file is seekable or not */
+        ft->seekable = is_seekable(ft);
+    }
+
+    /* Read and write starters can change their formats. */
+    if ((*ft->h->startread)(ft) != ST_SUCCESS)
+    {
+        /* FIXME */
+        st_fail("Failed reading %s: %s", ft->filename, ft->st_errstr);
+        goto input_error;
+    }
+
+    /* Go a head and assume 1 channel audio if nothing is detected.
+     * This is because libst usually doesn't set this for mono file
+     * formats (for historical reasons).
+     */
+    if (ft->info.channels == -1)
+        ft->info.channels = 1;
+
+    if (st_checkformat(ft) )
+    {
+        st_fail("bad input format for file %s: %s", ft->filename,
+                ft->st_errstr);
+        goto input_error;
+    }
+
+    return ft;
+
+input_error:
+
+    if (ft->filename)
+        free(ft->filename);
+    if (ft->filetype)
+        free(ft->filetype);
+    free(ft);
+    return NULL;
+}
+
+#if defined(DOS) || defined(WIN32)
+#define LASTCHAR '\\'
+#else
+#define LASTCHAR '/'
+#endif
+
+static void st_copyformat(ft_t ft, const st_signalinfo_t *info,
+                          const char *comment, const st_loopinfo_t *loops,
+                          const st_instrinfo_t *instr)
+{
+    int i;
+    double factor;
+
+    if (ft->info.rate == 0)
+        ft->info.rate = info->rate;
+    if (ft->info.size == -1)
+        ft->info.size = info->size;
+    if (ft->info.encoding == -1)
+        ft->info.encoding = info->encoding;
+    if (ft->info.channels == -1)
+        ft->info.channels = info->channels;
+
+    if (ft->comment == NULL && comment != NULL)
+        ft->comment = strdup(comment);
+    else
+        ft->comment = strdup("Processed by SoX");
+
+    /*
+     * copy loop info, resizing appropriately
+     * it's in samples, so # channels don't matter
+     */
+    factor = (double) ft->info.rate / (double) info->rate;
+    for(i = 0; i < ST_MAX_NLOOPS; i++) {
+        ft->loops[i].start = loops[i].start * factor;
+        ft->loops[i].length = loops[i].length * factor;
+        ft->loops[i].count = loops[i].count;
+        ft->loops[i].type = loops[i].type;
+    }
+    /* leave SMPTE # alone since it's absolute */
+    ft->instr = *instr;
+}
+
+ft_t st_open_output(const char *path, const st_signalinfo_t *info,
+                    const st_signalinfo_t *input_info,
+                    const char *comment, const st_loopinfo_t *loops,
+                    const st_instrinfo_t *instr,
+                    const char *filetype, const char swap)
+{
+    ft_t ft;
+    ft = (ft_t)calloc(sizeof(struct st_soundstream), 1);
+
+    if (!ft )
+        return NULL;
+
+    ft->filename = strdup(path);
+
+    /* Let auto effect do the work if user is not overriding. */
+    if (!filetype)
+    {
+        char *chop;
+        int len;
+
+        len = strlen(ft->filename);
+
+        /* Use filename extension to determine audio type. */
+        chop = ft->filename + len;
+        while (chop > ft->filename && *chop != LASTCHAR)
+            chop--;
+
+        while (chop < ft->filename+len && *chop != '.')
+            chop++;
+
+        if (*chop == '.')
+        {
+            chop++;
+            ft->filetype = strdup(chop);
+        }
+    }
+    else
+        ft->filetype = strdup(filetype);
+
+    if (!ft->filename || !ft->filetype)
+        goto output_error;
+
+    if (st_gettype(ft) != ST_SUCCESS)
+    {
+        /* FIXME */
+        st_fail("Unknown output file format for '%s':  %s", 
+                ft->filename, 
+                ft->st_errstr);
+        goto output_error;
+    }
+
+    ft->info.size = -1;
+    ft->info.encoding = -1;
+    ft->info.channels = -1;
+    ft->info = *info;
+    ft->swap = swap;
+    ft->mode = 'w';
+
+    if (!(ft->h->flags & ST_FILE_NOSTDIO))
+    {
+        /* Open file handler based on input name.  Used stdin file handler
+         * if the filename is "-"
+         */
+        if (!strcmp(ft->filename, "-"))
+        {
+            ft->fp = stdout;
+
+        }
+        else if ((ft->fp = fopen(ft->filename, "wb")) == NULL)
+        {
+            /* FIXME */
+            st_fail("Can't open output file '%s': %s", ft->filename,
+                    strerror(errno));
+            goto output_error;
+        }
+
+        /* stdout tends to be line-buffered.  Override this */
+        /* to be Full Buffering. */
+        /* FIXME: Use buffer size from ft structure */
+        if (setvbuf (ft->fp, NULL, _IOFBF, sizeof(char)*ST_BUFSIZ))
+        {
+            /* FIXME */
+            st_fail("Can't set write buffer");
+            goto output_error;
+        }
+
+        /* See if this file is seekable or not */
+        ft->seekable = is_seekable(ft);
+    }
+
+    st_copyformat(ft, input_info, comment, loops, instr);
+
+    /* Read and write starters can change their formats. */
+    if ((*ft->h->startwrite)(ft) != ST_SUCCESS)
+    {
+        /* FIXME */
+        st_fail("Failed writing %s: %s", ft->filename, ft->st_errstr);
+        goto output_error;
+    }
+
+    if (st_checkformat(ft) )
+    {
+        st_fail("bad output format for file %s: %s", ft->filename,
+                ft->st_errstr);
+        goto output_error;
+    }
+
+    return ft;
+
+output_error:
+
+    if (ft->filename)
+        free(ft->filename);
+    if (ft->filetype)
+        free(ft->filetype);
+    free(ft);
+    return NULL;
+}
+
+int st_close(ft_t ft)
+{
+    int rc;
+
+    if (ft->mode == 'r')
+        rc = (*ft->h->stopread)(ft);
+    else
+        rc = (*ft->h->stopwrite)(ft);
+
+    if (!(ft->h->flags & ST_FILE_NOSTDIO))
+    {
+        fclose(ft->fp);
+    }
+    if (ft->filename)
+        free(ft->filename);
+    if (ft->filetype)
+        free(ft->filetype);
+    /* Currently, since startread() mallocs comments, stopread
+     * is expected to also free it.
+     */
+    if (ft->mode == 'w' && ft->comment)
+        free(ft->comment);
+
+    return rc;
+}
--- a/src/tx16w.c
+++ b/src/tx16w.c
@@ -271,7 +271,7 @@
     /* dummy numbers, just for place holder, real header is written
        at end of processing, since byte count is needed */
 
-    st_write(ft, &WH, 1, 32);
+    st_writebuf(ft, &WH, 1, 32);
     writedone = 32;
     return(ST_SUCCESS);
 }
@@ -371,7 +371,7 @@
         magic2[WH.sample_rate];
 
     st_rewind(ft);
-    st_write(ft, &WH, 1, 32);
+    st_writebuf(ft, &WH, 1, 32);
 
     return(ST_SUCCESS);
 }
--- a/src/util.c
+++ b/src/util.c
@@ -323,94 +323,6 @@
 /*
  * File format routines
  */
-
-ft_t st_initformat(void)
-{
-    ft_t ft;
-
-    ft = (ft_t)calloc(sizeof(struct st_soundstream), 1);
-
-    ft->info.size = -1;
-    ft->info.encoding = -1;
-    ft->info.channels = -1;
-
-    return ft;
-}
-
-void st_copyformat(ft_t ft, ft_t ft2)
-{
-    int i;
-    double factor;
-
-    if (ft2->info.rate == 0)
-        ft2->info.rate = ft->info.rate;
-    if (ft2->info.size == -1)
-        ft2->info.size = ft->info.size;
-    if (ft2->info.encoding == -1)
-        ft2->info.encoding = ft->info.encoding;
-    if (ft2->info.channels == -1)
-        ft2->info.channels = ft->info.channels;
-
-    if (ft2->comment == NULL && ft->comment != NULL)
-        ft2->comment = strdup(ft->comment);
-    else
-        ft2->comment = strdup("Processed by SoX");
-
-    /*
-     * copy loop info, resizing appropriately
-     * it's in samples, so # channels don't matter
-     */
-    factor = (double) ft2->info.rate / (double) ft->info.rate;
-    for(i = 0; i < ST_MAX_NLOOPS; i++) {
-        ft2->loops[i].start = ft->loops[i].start * factor;
-        ft2->loops[i].length = ft->loops[i].length * factor;
-        ft2->loops[i].count = ft->loops[i].count;
-        ft2->loops[i].type = ft->loops[i].type;
-    }
-    /* leave SMPTE # alone since it's absolute */
-    ft2->instr = ft->instr;
-}
-
-/* check that all settings have been given */
-int st_checkformat(ft_t ft)
-{
-
-        ft->st_errno = ST_SUCCESS;
-
-        if (ft->info.rate == 0)
-        {
-                st_fail_errno(ft,ST_EFMT,"sampling rate was not specified");
-                return ST_EOF;
-        }
-
-        if (ft->info.size == -1)
-        {
-                st_fail_errno(ft,ST_EFMT,"data size was not specified");
-                return ST_EOF;
-        }
-
-        if (ft->info.encoding == -1)
-        {
-                st_fail_errno(ft,ST_EFMT,"data encoding was not specified");
-                return ST_EOF;
-        }
-
-        if ((ft->info.size <= 0) || (ft->info.size > ST_INFO_SIZE_MAX))
-        {
-                st_fail_errno(ft,ST_EFMT,"data size %i is invalid");
-                return ST_EOF;
-        }
-
-        /* anyway to check length on st_encoding_str[] ? */
-        if (ft->info.encoding <= 0  || ft->info.encoding > ST_ENCODING_MAX)
-        {
-                st_fail_errno(ft,ST_EFMT,"data encoding %i is invalid");
-                return ST_EOF;
-        }
-
-        return ST_SUCCESS;
-}
-
 static ft_t ft_queue[2] = {0, 0};
 
 static void sigint(int s)
--- a/src/voc.c
+++ b/src/voc.c
@@ -230,7 +230,7 @@
         }
 
 
-        if (st_read(ft, header, 1, 20) != 20)
+        if (st_readbuf(ft, header, 1, 20) != 20)
         {
                 st_fail_errno(ft,ST_EHDR,"unexpected EOF in VOC header");
                 return(ST_EOF);
--- a/src/vorbis.c
+++ b/src/vorbis.c
@@ -279,8 +279,8 @@
 int oe_write_page(ogg_page *page, ft_t ft)
 {
         int written;
-        written = st_write(ft, page->header,1,page->header_len);
-        written += st_write(ft, page->body,1,page->body_len);
+        written = st_writebuf(ft, page->header,1,page->header_len);
+        written += st_writebuf(ft, page->body,1,page->body_len);
 
         return written;
 }
--- a/src/vox.c
+++ b/src/vox.c
@@ -169,7 +169,7 @@
                    { // ... refill buffer 
 
                      if (ft->file.pos >= ft->file.count)
-                        { ft->file.count = st_read (ft,ft->file.buf,1,ft->file.size);
+                        { ft->file.count = st_readbuf (ft,ft->file.buf,1,ft->file.size);
                           ft->file.pos   = 0;
 
                           if (ft->file.count == 0)
@@ -288,7 +288,7 @@
                         { ft->file.buf[ft->file.count++] = byte;
 
                           if (ft->file.count >= ft->file.size)
-                             { st_write (ft,ft->file.buf,1,ft->file.count);
+                             { st_writebuf (ft,ft->file.buf,1,ft->file.count);
 
                                ft->file.count = 0;
                              }
@@ -330,7 +330,7 @@
           }
 
        if (ft->file.count > 0)
-          st_write (ft,ft->file.buf,1,ft->file.count);
+          st_writebuf (ft,ft->file.buf,1,ft->file.count);
 
        // ... free buffer
 
--- a/src/wav.c
+++ b/src/wav.c
@@ -135,7 +135,7 @@
     int samplesThisBlock;
 
     /* Pull in the packet and check the header */
-    bytesRead = st_read(ft, wav->packet, 1, wav->blockAlign);
+    bytesRead = st_readbuf(ft, wav->packet, 1, wav->blockAlign);
     samplesThisBlock = wav->samplesPerBlock;
     if (bytesRead < wav->blockAlign) 
     { 
@@ -176,7 +176,7 @@
     const char *errmsg;
 
     /* Pull in the packet and check the header */
-    bytesRead = st_read(ft, wav->packet, 1, wav->blockAlign);
+    bytesRead = st_readbuf(ft, wav->packet, 1, wav->blockAlign);
     samplesThisBlock = wav->samplesPerBlock;
     if (bytesRead < wav->blockAlign) 
     {
@@ -222,7 +222,7 @@
             ImaBlockMashI(chans, wav->samples, wav->samplesPerBlock, wav->state, wav->packet, 9);
         }
         /* write the compressed packet */
-        if (st_write(ft, wav->packet, wav->blockAlign, 1) != 1)
+        if (st_writebuf(ft, wav->packet, wav->blockAlign, 1) != 1)
         {
             st_fail_errno(ft,ST_EOF,"write error");
             return (ST_EOF);
@@ -294,7 +294,7 @@
   /* read and decode loop, possibly leaving some samples in wav->gsmsample */
     while (done < len) {
         wav->gsmindex=0;
-        bytes = st_read(ft, frame, 1, 65);   
+        bytes = st_readbuf(ft, frame, 1, 65);   
         if (bytes <=0)
             return done;
         if (bytes<65) {
@@ -335,7 +335,7 @@
     gsm_encode(wav->gsmhandle, wav->gsmsample, frame);
     /*encode the odd half long (33 byte) frame */
     gsm_encode(wav->gsmhandle, wav->gsmsample+160, frame+32);
-    if (st_write(ft, frame, 1, 65) != 65)
+    if (st_writebuf(ft, frame, 1, 65) != 65)
     {
         st_fail_errno(ft,ST_EOF,"write error");
         return (ST_EOF);