shithub: sox

Download patch

ref: f0724fe5fc30fc597c235b5d6f59e478b10cba0d
parent: 137952b22cdfa5faecb0ae8c04934d95f686a2b3
author: rrt <rrt>
date: Sat Jan 20 15:17:02 EST 2007

Add new formats via libsndfile

--- a/ChangeLog
+++ b/ChangeLog
@@ -90,6 +90,7 @@
   o New .ima file format for raw IMA ADPCM.  (robs)
   o Build system overhaul to use the full set of GNU autotools.
     (Reuben Thomas)
+  o New file formats via libsndfile.  (Reuben Thomas)
 
 sox-12.18.2
 -----------
--- a/configure.ac
+++ b/configure.ac
@@ -94,6 +94,19 @@
    AC_DEFINE(HAVE_SUN_AUDIO, 1, [Define to 1 if you have Sun /dev/audio.])
 fi
 
+dnl Check for libsndfile
+with_sndfile=yes
+AC_ARG_WITH(sndfile,
+    AC_HELP_STRING([--with-sndfile],
+        [Use libsndfile if present (default is YES)]))
+if test "$with_sndfile" = yes; then
+  SOX_PATH_SNDFILE(, 
+                      [with_sndfile=no
+                       AC_MSG_NOTICE([Could not find a usable libsndfile])])
+fi
+AC_SUBST(SNDFILE_CFLAGS)
+AC_SUBST(SNDFILE_LIBS)
+        
 dnl Check for Ogg Vorbis libraries
 AC_CHECK_HEADER(vorbis/codec.h,
     [with_ogg_vorbis=yes
@@ -139,7 +152,7 @@
 with_samplerate=yes
 AC_ARG_WITH(samplerate,
     AC_HELP_STRING([--with-samplerate],
-        [Use libsamplerate (aka Rabbit Code) if present (default is YES)]))
+        [Use libsamplerate (aka Secret Rabbit Code) if present (default is YES)]))
 if test "$with_samplerate" = yes; then
   SOX_PATH_SAMPLERATE(, 
                       [with_samplerate=no
@@ -272,6 +285,7 @@
 echo "ALSA Driver....................... $with_alsa"
 echo "OSS Driver........................ $with_oss"
 echo "SUN /dev/audio.................... $with_sun_audio"
+echo "libsndfile support................ $with_sndfile"
 echo "Ogg Vorbis support................ $with_ogg_vorbis"
 echo "FLAC support...................... $with_flac"
 echo "MAD MP3 Decoder................... $with_mad"
--- /dev/null
+++ b/m4/sndfile.m4
@@ -1,0 +1,70 @@
+dnl SOX_PATH_SNDFILE
+dnl Based off of shout.m4 from xiph package.
+dnl cbagwell@users.sourceforge.net 1-3-2007
+dnl
+dnl Original Authors:
+dnl Jack Moffitt <jack@icecast.org> 08-06-2001
+dnl Rewritten for libshout 2
+dnl Brendan Cully <brendan@xiph.org> 20030612
+dnl
+# SOX_PATH_SNDFILE([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+# Test for libsndfile, and define SNDFILE_CFLAGS and SNDFILE_LIBS
+AC_DEFUN([SOX_PATH_SNDFILE],
+[dnl
+have_sndfile="no"
+SNDFILE_CFLAGS=""
+SNDFILE_LIBS=""
+
+# Step 1: Use pkg-config if available
+m4_ifdef([PKG_CHECK_MODULES],
+  [# PKG_CHECK_MODULES available
+  PKG_CHECK_MODULES([SNDFILE], [sndfile], [$1], [$2])
+  have_sndfile="maybe"],
+  [# PKG_CHECK_MODULES is unavailable, search for pkg-config program
+  AC_PATH_PROG([PKGCONFIG], [pkg-config], [none])
+  if test "$PKGCONFIG" != "none" && `$PKGCONFIG --exists sndfile`
+  then
+    SNDFILE_CFLAGS=`$PKGCONFIG --cflags sndfile`
+    SNDFILE_LIBS=`$PKGCONFIG --libs sndfile`
+    have_sndfile="maybe"
+  else
+    if test "$PKGCONFIG" != "none"
+    then
+      AC_MSG_NOTICE([$PKGCONFIG couldn't find libsndfile. Try adjusting PKG_CONFIG_PATH.])
+    fi
+    # libsndfile doesn't have sndfile-config but other
+    # packages do and so keep around as an example.
+    # Step 2: try sndfile-config
+    #AC_PATH_PROG([SNDFILECONFIG], [sndfile-config], [none])
+    #if test "$SNDFILECONFIG" != "none" && test `$SNDFILECONFIG --package` = "libsndfile"
+    #then
+    #  SNDFILE_CFLAGS=`$SNDFILECONFIG --cflags`
+    #  SNDFILE_LIBS=`$SNDFILECONFIG --libs`
+    #  have_sndfile="maybe"
+    #fi
+  fi
+  ])
+
+# Now try actually using libsndfile
+if test "$have_sndfile" != "no"
+then
+  ac_save_CFLAGS="$CFLAGS"
+  ac_save_LIBS="$LIBS"
+  CFLAGS="$CFLAGS $SNDFILE_CFLAGS"
+  LIBS="$LIBS $SNDFILE_LIBS"
+  AC_CHECK_HEADER([sndfile.h], [
+    AC_DEFINE([HAVE_SNDFILE_H], 1, [Define if you have <sndfile.h>])
+    AC_CHECK_FUNC([sf_open], [
+      ifelse([$1], , :, [$1])
+      have_sndfile="yes"
+    ])
+  ])
+  CFLAGS="$ac_save_CFLAGS"
+  LIBS="$ac_save_LIBS"
+fi
+
+if test "$have_sndfile" != "yes"
+then
+  ifelse([$2], , :, [$2])
+fi
+])dnl SOX_PATH_SNDFILE
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -3,7 +3,8 @@
 SUBDIRS = libgsm
 
 AM_CPPFLAGS = $(LUA_INCLUDES)
-AM_LDFLAGS = @SAMPLERATE_LIBS@
+AM_CFLAGS = @SNDFILE_CFLAGS@ @SAMPLERATE_CFLAGS@
+AM_LDFLAGS = @SNDFILE_LIBS@ @SAMPLERATE_LIBS@
 
 # Pass flags from --enable-silent-libtool
 LIBTOOL = @LIBTOOL@ @LIBTOOLFLAGS@
@@ -17,8 +18,8 @@
 formats = 8svx.c adpcm.c adpcm.h adpcms.c adpcms.h aiff.c au.c auto.c avr.c \
 	  cdr.c cvsd.c cvsdfilt.h dat.c flac.c g711.c g711.h g721.c \
 	  g723_16.c g723_24.c g723_40.c g72x.c g72x.h gsm.c hcom.c \
-	  ima_rw.c ima_rw.h maud.c mp3.c nulfile.c prc.c \
-	  raw.c sf.c sfircam.h skelform.c smp.c sndrtool.c sphere.c tx16w.c \
+	  ima_rw.c ima_rw.h maud.c mp3.c nulfile.c prc.c raw.c sf.c \
+	  sfircam.h skelform.c smp.c sndfile.c sndrtool.c sphere.c tx16w.c \
 	  voc.c vorbis.c vox.c wav.c wav.h wve.c xa.c
 
 effects = avg.c band.c bandpass.c biquad.c biquad.h biquadlh.c breject.c \
--- a/src/handlers.c
+++ b/src/handlers.c
@@ -54,6 +54,9 @@
   st_sl_format_fn,
   st_smp_format_fn,
   st_snd_format_fn,
+#ifdef HAVE_SNDFILE_H
+  st_sndfile_format_fn,
+#endif
   st_sphere_format_fn,
 #ifdef HAVE_SUN_AUDIO
   st_sun_format_fn,
--- /dev/null
+++ b/src/sndfile.c
@@ -1,0 +1,242 @@
+/*
+ * Sound Tools libsndfile formats.
+ *
+ * Copyright 2007 Reuben Thomas <rrt@sc3d.org>
+ * Copyright 1999-2005 Erik de Castro Lopo <eridk@mega-nerd.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, write to the Free Software
+ * Foundation, Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301,
+ * USA.  */
+
+#include "st_i.h"
+
+#ifdef HAVE_SNDFILE_H
+
+#include <stdio.h>
+#include <string.h>
+#include <sndfile.h>
+
+/* Private data for sndfile files */
+typedef struct sndfile
+{
+  SNDFILE *sf_file;
+  SF_INFO *sf_info;
+} *sndfile_t;
+
+assert_static(sizeof(struct sndfile) <= ST_MAX_FILE_PRIVSIZE, 
+              /* else */ sndfile_PRIVSIZE_too_big);
+
+/*
+ * Open file in sndfile.
+ */
+int st_sndfile_startread(ft_t ft)
+{
+  sndfile_t sf = (sndfile_t)ft->priv;
+
+  sf->sf_info = (SF_INFO *)xcalloc(1, sizeof(SF_INFO));
+  if ((sf->sf_file = sf_open(ft->filename, SFM_READ, sf->sf_info)) == NULL) {
+    st_fail("sndfile cannot open file for reading: %s %x", sf_strerror(sf->sf_file), sf->sf_info->format);
+    return ST_EOF;
+  }
+
+  /* Copy format info */
+  ft->signal.rate = sf->sf_info->samplerate;
+  ft->signal.size = ST_SIZE_32BIT;
+  ft->signal.encoding = ST_ENCODING_UNSIGNED;
+  ft->signal.channels = sf->sf_info->channels;
+  ft->length = sf->sf_info->frames * sf->sf_info->channels;
+
+  return ST_SUCCESS;
+}
+
+/*
+ * Read up to len samples of type st_sample_t from file into buf[].
+ * Return number of samples read.
+ */
+st_size_t st_sndfile_read(ft_t ft, st_sample_t *buf, st_size_t len)
+{
+  sndfile_t sf = (sndfile_t)ft->priv;
+
+  /* FIXME: We assume int == st_sample_t here */
+  return (st_size_t)sf_read_int(sf->sf_file, (int *)buf, len);
+}
+
+/*
+ * Close file for libsndfile (this doesn't close the file handle)
+ */
+int st_sndfile_stopread(ft_t ft)
+{
+  sndfile_t sf = (sndfile_t)ft->priv;
+  sf_close(sf->sf_file);
+  return ST_SUCCESS;
+}
+
+static struct {
+  const char *ext;
+  int len;
+  int format;
+} format_map[] =
+{
+  { "aif",	3,	SF_FORMAT_AIFF	},
+  { "wav",	0,	SF_FORMAT_WAV	},
+  { "au",	0,	SF_FORMAT_AU	},
+  { "caf",	0,	SF_FORMAT_CAF	},
+  { "flac",	0,	SF_FORMAT_FLAC	},
+  { "snd",	0,	SF_FORMAT_AU	},
+  { "svx",	0,	SF_FORMAT_SVX	},
+  { "paf",	0,	SF_ENDIAN_BIG | SF_FORMAT_PAF	},
+  { "fap",	0,	SF_ENDIAN_LITTLE | SF_FORMAT_PAF },
+  { "gsm",	0,	SF_FORMAT_RAW	},
+  { "nist", 	0,	SF_FORMAT_NIST	},
+  { "ircam",	0,	SF_FORMAT_IRCAM	},
+  { "sf",	0, 	SF_FORMAT_IRCAM	},
+  { "voc",	0, 	SF_FORMAT_VOC	},
+  { "w64", 	0, 	SF_FORMAT_W64	},
+  { "raw",	0,	SF_FORMAT_RAW	},
+  { "mat4", 	0,	SF_FORMAT_MAT4	},
+  { "mat5", 	0, 	SF_FORMAT_MAT5 	},
+  { "mat",	0, 	SF_FORMAT_MAT4 	},
+  { "pvf",	0, 	SF_FORMAT_PVF 	},
+  { "sds",	0, 	SF_FORMAT_SDS 	},
+  { "sd2",	0, 	SF_FORMAT_SD2 	},
+  { "vox",	0, 	SF_FORMAT_RAW 	},
+  { "xi",	0, 	SF_FORMAT_XI 	}
+};
+
+static int guess_output_file_type(const char *type, int format)
+{
+  int k;
+
+  format &= SF_FORMAT_SUBMASK;
+
+  if (strcmp(type, "gsm") == 0)
+    return SF_FORMAT_RAW | SF_FORMAT_GSM610;
+
+  if (strcmp(type, "vox") == 0)
+    return SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM;
+
+  for (k = 0; k < (int)(sizeof(format_map) / sizeof(format_map [0])); k++) {
+    if (format_map[k].len > 0 && strncmp(type, format_map[k].ext, format_map[k].len) == 0)
+      return format_map[k].format | format;
+    else if (strcmp(type, format_map[k].ext) == 0)
+      return format_map[k].format | format;
+  }
+
+  return 0;
+}
+
+int st_sndfile_startwrite(ft_t ft)
+{
+  sndfile_t sf = (sndfile_t)ft->priv;
+  sf->sf_info = (SF_INFO *)xmalloc(sizeof(SF_INFO));
+
+  /* Copy format info */
+  /* FIXME: Need to have a table of suitable default subtypes */
+  sf->sf_info->format = guess_output_file_type(ft->filetype, SF_FORMAT_PCM_16);
+  sf->sf_info->samplerate = ft->signal.rate;
+  sf->sf_info->channels = ft->signal.channels;
+  sf->sf_info->frames = ft->length / ft->signal.channels;
+
+  if (!sf_format_check(sf->sf_info)) {
+    st_fail("invalid sndfile output format");
+    return ST_EOF;
+  }
+
+  if ((sf->sf_file = sf_open(ft->filename, SFM_WRITE, sf->sf_info)) == NULL) {
+    st_fail("sndfile cannot open file for writing: %s", sf_strerror(sf->sf_file));
+    return ST_EOF;
+  }
+
+  return ST_SUCCESS;
+}
+
+/*
+ * Write len samples of type st_sample_t from buf[] to file.
+ * Return number of samples written.
+ */
+st_size_t st_sndfile_write(ft_t ft, const st_sample_t *buf, st_size_t len)
+{
+  sndfile_t sf = (sndfile_t)ft->priv;
+
+  /* FIXME: We assume int == st_sample_t here */
+  return (st_size_t)sf_write_int(sf->sf_file, (int *)buf, len);
+}
+
+/*
+ * Close file for libsndfile (this doesn't close the file handle)
+ */
+int st_sndfile_stopwrite(ft_t ft)
+{
+  sndfile_t sf = (sndfile_t)ft->priv;
+  sf_close(sf->sf_file);
+  return ST_SUCCESS;
+}
+
+int st_sndfile_seek(ft_t ft, st_size_t offset)
+{
+  sndfile_t sf = (sndfile_t)ft->priv;
+  sf_seek(sf->sf_file, offset / ft->signal.channels, SEEK_CUR);
+  return ST_SUCCESS;
+}
+
+/* Format file suffixes */
+/* For now, comment out formats built-in to SoX */
+static const char *names[] = {
+  /* "aif", */
+  /* "wav", */
+  /* "au", */
+  "caf",
+  /* "flac", */
+  /* "snd", */
+  /* "svx", */
+  "paf",
+  "fap",
+  /* "gsm", */
+  "nist",
+  /* "ircam", */
+  /* "sf", */
+  /* "voc", */
+  "w64",
+  /* "raw", */
+  "mat4",
+  "mat5",
+  "mat",
+  "pvf",
+  "sds",
+  "sd2",
+  /* "vox", */
+  "xi",
+  NULL
+};
+
+/* Format descriptor */
+static st_format_t st_sndfile_format = {
+  names,
+  NULL,
+  ST_FILE_SEEK,
+  st_sndfile_startread,
+  st_sndfile_read,
+  st_sndfile_stopread,
+  st_sndfile_startwrite,
+  st_sndfile_write,
+  st_sndfile_stopwrite,
+  st_sndfile_seek
+};
+
+const st_format_t *st_sndfile_format_fn(void)
+{
+  return &st_sndfile_format;
+}
+
+#endif
--- a/src/st_i.h
+++ b/src/st_i.h
@@ -242,6 +242,9 @@
 extern const st_format_t *st_sf_format_fn(void);
 extern const st_format_t *st_smp_format_fn(void);
 extern const st_format_t *st_snd_format_fn(void);
+#ifdef HAVE_SNDFILE_H
+extern const st_format_t *st_sndfile_format_fn(void);
+#endif
 extern const st_format_t *st_sphere_format_fn(void);
 #ifdef HAVE_SUN_AUDIO
 extern const st_format_t *st_sun_format_fn(void);
@@ -257,8 +260,7 @@
 extern const st_format_t *st_wve_format_fn(void);
 extern const st_format_t *st_xa_format_fn(void);
 
-/* Raw I/O
- */
+/* Raw I/O */
 int st_rawstartread(ft_t ft);
 st_size_t st_rawread(ft_t ft, st_sample_t *buf, st_size_t nsamp);
 int st_rawstopread(ft_t ft);
@@ -266,6 +268,16 @@
 st_size_t st_rawwrite(ft_t ft, const st_sample_t *buf, st_size_t nsamp);
 int st_rawstopwrite(ft_t ft);
 int st_rawseek(ft_t ft, st_size_t offset);
+
+/* libsndfile I/O */
+int st_sndfile_startread(ft_t ft);
+st_size_t st_sndfile_read(ft_t ft, st_sample_t *buf, st_size_t len);
+int st_sndfile_stopread(ft_t ft);
+int st_sndfile_startwrite(ft_t ft);
+st_size_t st_sndfile_write(ft_t ft, const st_sample_t *buf, st_size_t len);
+int st_sndfile_stopwrite(ft_t ft);
+int st_sndfile_seek(ft_t ft, st_size_t offset);
+
 
 /* The following functions can be used to simply return success if
  * a file handler or effect doesn't need to do anything special