ref: c3c54e7ea8cc61c0d4bca4bdddade524765466d3
parent: 8099cc1eaf1fc8fb5d8205d993ec13f890911c54
author: robs <robs>
date: Sat Nov 3 10:08:20 EDT 2007
progressing
--- a/src/sndfile.c
+++ b/src/sndfile.c
@@ -29,16 +29,50 @@
#include <ctype.h>
#include <sndfile.h>
+#define LOG_MAX 2048 /* As per the SFC_GET_LOG_INFO example */
+
+#ifndef HACKED_LSF
+#define sf_stop(x)
+#endif
+
/* Private data for sndfile files */
typedef struct sndfile
{
SNDFILE *sf_file;
SF_INFO *sf_info;
+ char * log_buffer;
+ char const * log_buffer_ptr;
} *sndfile_t;
assert_static(sizeof(struct sndfile) <= SOX_MAX_FILE_PRIVSIZE,
/* else */ sndfile_PRIVSIZE_too_big);
+/*
+ * Drain LSF's wonderful log buffer
+ */
+static void drain_log_buffer(sox_format_t * ft)
+{
+ sndfile_t sf = (sndfile_t)ft->priv;
+
+ sf_command(sf->sf_file, SFC_GET_LOG_INFO, sf->log_buffer, LOG_MAX);
+ while (*sf->log_buffer_ptr) {
+ static char const warning_prefix[] = "*** Warning : ";
+ char const * end = strchr(sf->log_buffer_ptr, '\n');
+ if (!end)
+ end = strchr(sf->log_buffer_ptr, '\0');
+ if (!strncmp(sf->log_buffer_ptr, warning_prefix, strlen(warning_prefix))) {
+ sf->log_buffer_ptr += strlen(warning_prefix);
+ sox_warn("`%s': %.*s",
+ ft->filename, end - sf->log_buffer_ptr, sf->log_buffer_ptr);
+ } else
+ sox_debug("`%s': %.*s",
+ ft->filename, end - sf->log_buffer_ptr, sf->log_buffer_ptr);
+ sf->log_buffer_ptr = end;
+ if (*sf->log_buffer_ptr == '\n')
+ ++sf->log_buffer_ptr;
+ }
+}
+
/* Get sample encoding and size from libsndfile subtype; return value
is encoding if conversion was made, or SOX_ENCODING_UNKNOWN for
invalid input. If the libsndfile subtype can't be represented in
@@ -109,68 +143,6 @@
return SOX_ENCODING_UNKNOWN;
}
-/*
- * Open file in sndfile.
- */
-static int startread(sox_format_t * ft)
-{
- sndfile_t sf = (sndfile_t)ft->priv;
-
- sf->sf_info = (SF_INFO *)xcalloc(1, sizeof(SF_INFO));
-
- /* Copy format info; FIXME: more to do */
- sf->sf_info->samplerate = ft->signal.rate + .5;
- sf->sf_info->channels = ft->signal.channels;
-
- /* We'd like to use sf_open_fd, but auto file typing has already
- invoked stdio buffering. */
- if ((sf->sf_file = sf_open(ft->filename, SFM_READ, sf->sf_info)) == NULL) {
- sox_fail("sndfile cannot open file for reading: %s", sf_strerror(sf->sf_file));
- free(sf->sf_file);
- return SOX_EOF;
- }
-
- /* Copy format info */
- ft->signal.encoding = sox_encoding_and_size(sf->sf_info->format, &ft->signal.size);
- ft->signal.channels = sf->sf_info->channels;
- ft->length = sf->sf_info->frames * sf->sf_info->channels;
- if (ft->signal.encoding == SOX_ENCODING_OKI_ADPCM) {
- if (ft->signal.rate == 0) {
- sox_warn("'%s': sample rate not specified; trying 8kHz", ft->filename);
- ft->signal.rate = 8000;
- }
- }
- else ft->signal.rate = sf->sf_info->samplerate;
-
- return SOX_SUCCESS;
-}
-
-/*
- * Read up to len samples of type sox_sample_t from file into buf[].
- * Return number of samples read.
- */
-static sox_size_t read(sox_format_t * ft, sox_sample_t *buf, sox_size_t len)
-{
- sndfile_t sf = (sndfile_t)ft->priv;
-
- /* FIXME: We assume int == sox_sample_t here */
- return (sox_size_t)sf_read_int(sf->sf_file, (int *)buf, (sf_count_t)len);
-}
-
-/*
- * Close file for libsndfile (this doesn't close the file handle)
- */
-static int stopread(sox_format_t * ft)
-{
- sndfile_t sf = (sndfile_t)ft->priv;
- int ret = sf_close(sf->sf_file);
- if (ft->signal.encoding == SOX_ENCODING_OKI_ADPCM) {
- if (ret)
- sox_warn("%s: ADPCM state errors: %i", ft->filename, ret);
- }
- return SOX_SUCCESS;
-}
-
static struct {
const char *ext;
unsigned len;
@@ -288,21 +260,93 @@
}
}
-static int startwrite(sox_format_t * ft)
+static void start(sox_format_t * ft)
{
sndfile_t sf = (sndfile_t)ft->priv;
int subtype = sndfile_format(ft->signal.encoding, ft->signal.size);
- sf->sf_info = (SF_INFO *)xmalloc(sizeof(SF_INFO));
+ sf->log_buffer_ptr = sf->log_buffer = xmalloc(LOG_MAX);
+ sf->sf_info = (SF_INFO *)xcalloc(1, sizeof(SF_INFO));
/* Copy format info */
- if (strcmp(ft->filetype, "sndfile") == 0)
- sf->sf_info->format = name_to_format(ft->filename) | subtype;
- else
- sf->sf_info->format = name_to_format(ft->filetype) | subtype;
+ if (subtype) {
+ if (strcmp(ft->filetype, "sndfile") == 0)
+ sf->sf_info->format = name_to_format(ft->filename) | subtype;
+ else
+ sf->sf_info->format = name_to_format(ft->filetype) | subtype;
+ }
sf->sf_info->samplerate = ft->signal.rate;
sf->sf_info->channels = ft->signal.channels;
- sf->sf_info->frames = ft->length / ft->signal.channels;
+ if (ft->signal.channels)
+ sf->sf_info->frames = ft->length / ft->signal.channels;
+}
+/*
+ * Open file in sndfile.
+ */
+static int startread(sox_format_t * ft)
+{
+ sndfile_t sf = (sndfile_t)ft->priv;
+
+ start(ft);
+
+ /* We'd like to use sf_open_fd, but auto file typing has already
+ invoked stdio buffering. */
+ sf->sf_file = sf_open(ft->filename, SFM_READ, sf->sf_info);
+ drain_log_buffer(ft);
+
+ if (sf->sf_file == NULL) {
+ memset(ft->sox_errstr, 0, sizeof(ft->sox_errstr));
+ strncpy(ft->sox_errstr, sf_strerror(sf->sf_file), sizeof(ft->sox_errstr)-1);
+ free(sf->sf_file);
+ return SOX_EOF;
+ }
+
+ /* Copy format info */
+ ft->signal.encoding = sox_encoding_and_size(sf->sf_info->format, &ft->signal.size);
+ ft->signal.channels = sf->sf_info->channels;
+ ft->length = sf->sf_info->frames * sf->sf_info->channels;
+
+ /* FIXME: it would be better if LSF was able to do this */
+ if ((sf->sf_info->format & SF_FORMAT_TYPEMASK) == SF_FORMAT_RAW) {
+ if (ft->signal.rate == 0) {
+ sox_warn("'%s': sample rate not specified; trying 8kHz", ft->filename);
+ ft->signal.rate = 8000;
+ }
+ }
+ else ft->signal.rate = sf->sf_info->samplerate;
+
+ return SOX_SUCCESS;
+}
+
+/*
+ * Read up to len samples of type sox_sample_t from file into buf[].
+ * Return number of samples read.
+ */
+static sox_size_t read(sox_format_t * ft, sox_sample_t *buf, sox_size_t len)
+{
+ sndfile_t sf = (sndfile_t)ft->priv;
+
+ /* FIXME: We assume int == sox_sample_t here */
+ return (sox_size_t)sf_read_int(sf->sf_file, (int *)buf, (sf_count_t)len);
+}
+
+/*
+ * Close file for libsndfile (this doesn't close the file handle)
+ */
+static int stopread(sox_format_t * ft)
+{
+ sndfile_t sf = (sndfile_t)ft->priv;
+ sf_stop(sf->sf_file);
+ drain_log_buffer(ft);
+ sf_close(sf->sf_file);
+ return SOX_SUCCESS;
+}
+
+static int startwrite(sox_format_t * ft)
+{
+ sndfile_t sf = (sndfile_t)ft->priv;
+
+ start(ft);
/* If output format is invalid, try to find a sensible default */
if (!sf_format_check(sf->sf_info)) {
SF_FORMAT_INFO format_info;
@@ -324,12 +368,17 @@
sox_fail("cannot find a usable output encoding");
return SOX_EOF;
}
- if (sf->sf_info->format != SF_FORMAT_RAW + SF_FORMAT_VOX_ADPCM)
+ if ((sf->sf_info->format & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW)
sox_warn("cannot use desired output encoding, choosing default");
}
- if ((sf->sf_file = sf_open(ft->filename, SFM_WRITE, sf->sf_info)) == NULL) {
- sox_fail("sndfile cannot open file for writing: %s", sf_strerror(sf->sf_file));
+ sf->sf_file = sf_open(ft->filename, SFM_WRITE, sf->sf_info);
+ drain_log_buffer(ft);
+
+ if (sf->sf_file == NULL) {
+ memset(ft->sox_errstr, 0, sizeof(ft->sox_errstr));
+ strncpy(ft->sox_errstr, sf_strerror(sf->sf_file), sizeof(ft->sox_errstr)-1);
+ free(sf->sf_file);
return SOX_EOF;
}
@@ -354,6 +403,8 @@
static int stopwrite(sox_format_t * ft)
{
sndfile_t sf = (sndfile_t)ft->priv;
+ sf_stop(sf->sf_file);
+ drain_log_buffer(ft);
sf_close(sf->sf_file);
return SOX_SUCCESS;
}