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, ¶ms) < 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), ¶ms, &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, ¶ms) < 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), ¶ms, &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);