ref: e95bf6acc5d699b6d86fa89d817f9aa9af7f8c42
parent: abde517163c601b461c47533fef2e35a2dbac535
author: robs <robs>
date: Fri Mar 21 18:22:22 EDT 2008
initial support for wavpack
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -86,6 +86,7 @@
endif (NOT HAVE_SYS_SOUNDCARD_H)
optional3(HAVE_OGG_VORBIS vorbis/codec.h vorbis vorbis_analysis_headerout vorbisfile ov_clear vorbisenc vorbis_encode_init_vbr vorbis)
optional3(HAVE_FFMPEG ffmpeg/avformat.h avformat av_open_input_file avutil av_rescale_q avcodec avcodec_decode_audio2 ffmpeg)
+optional(HAVE_WAVPACK wavpack/wavpack.h wavpack WavpackGetSampleRate wavpack)
subdirs(src lpc10)
--- a/configure.ac
+++ b/configure.ac
@@ -394,6 +394,26 @@
AM_CONDITIONAL(HAVE_AMRNB, test x$using_amr_nb = xyes)
AC_SUBST(AMR_NB_LIBS)
+dnl Check for wavpack libraries
+AC_ARG_WITH(wavpack,
+ AC_HELP_STRING([--without-wavpack],
+ [Don't try to use wavpack]))
+using_wavpack=no
+if test "$with_wavpack" != "no"; then
+ using_wavpack=yes
+ AC_CHECK_HEADER(wavpack/wavpack.h,
+ [AC_CHECK_LIB(wavpack, WavpackGetSampleRate, WAVPACK_LIBS="$WAVPACK_LIBS -lwavpack" ,using_wavpack=no)],
+ using_wavpack=no)
+ if test "$with_wavpack" = "yes" -a "$using_wavpack" = "no"; then
+ AC_MSG_FAILURE([cannot find wavpack])
+ fi
+fi
+if test "$using_wavpack" = yes; then
+ AC_DEFINE(HAVE_WAVPACK, 1, [Define to 1 if you have WavPack.])
+fi
+AM_CONDITIONAL(HAVE_WAVPACK, test x$using_wavpack = xyes)
+AC_SUBST(WAVPACK_LIBS)
+
dnl Test for libsamplerate.
AC_ARG_WITH(samplerate,
AC_HELP_STRING([--without-samplerate],
@@ -461,6 +481,7 @@
echo "LAME MP3 writer................... $using_lame"
echo "AMR-WB format..................... $using_amr_wb"
echo "AMR-NB format..................... $using_amr_nb"
+echo "WavPack format.................... $using_wavpack"
echo "LADSPA effects.................... $using_ladspa"
echo "Secret Rabbit Code resampling..... $using_samplerate"
echo "pkg-config location............... $pkgconfig_option"
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -153,6 +153,11 @@
libsox_fmt_amr_nb_la_LIBADD = libsox.la @AMR_NB_LIBS@
pkglib_LTLIBRARIES += libsox_fmt_amr_nb.la
endif
+if HAVE_WAVPACK
+libsox_fmt_wavpack_la_SOURCES = wavpack.c
+libsox_fmt_wavpack_la_LIBADD = libsox.la @WAVPACK_LIBS@
+pkglib_LTLIBRARIES += libsox_fmt_wavpack.la
+endif
if HAVE_MP3
libsox_fmt_mp3_la_SOURCES = mp3.c mp3-duration.h
libsox_fmt_mp3_la_LIBADD = libsox.la @MP3_LIBS@
@@ -254,6 +259,11 @@
libsox_la_SOURCES += amr-nb.c amr.h amr1.h amr2.h
libsox_la_LIBADD += @AMR_NB_LIBS@
sox_LDADD += @AMR_NB_LIBS@
+endif
+if HAVE_WAVPACK
+ libsox_la_SOURCES += wavpack.c
+ libsox_la_LIBADD += @WAVPACK_LIBS@
+ sox_LDADD += @WAVPACK_LIBS@
endif
if HAVE_MP3
libsox_la_SOURCES += mp3.c mp3-duration.h
--- a/src/formats.c
+++ b/src/formats.c
@@ -43,6 +43,8 @@
"Floating Point (text) PCM",
"FLAC",
"HCOM",
+ "WavPack",
+ "Floating Point WavPack",
"", /* Lossless above, lossy below */
"u-law",
"A-law",
@@ -73,6 +75,8 @@
"F.P. PCM",
"FLAC",
"HCOM",
+ "WavPack",
+ "F.P. WavPack",
"", /* Lossless above, lossy below */
"u-law",
"A-law",
@@ -129,6 +133,7 @@
MAGIC(flac , 0, 0, "" , 0, 4, "fLaC")
MAGIC(avr , 0, 0, "" , 0, 4, "2BIT")
MAGIC(caf , 0, 0, "" , 0, 4, "caff")
+ MAGIC(wv , 0, 0, "" , 0, 4, "wvpk")
MAGIC(paf , 0, 0, "" , 0, 4, " paf")
MAGIC(sf , 0, 0, "" , 0, 4, "\144\243\001\0")
MAGIC(sf , 0, 0, "" , 0, 4, "\0\001\243\144")
@@ -148,7 +153,8 @@
{
switch (encoding) {
case SOX_ENCODING_HCOM: return !(bits_per_sample & 7) && (bits_per_sample >> 3) - 1 < 1? bits_per_sample: 0;
- case SOX_ENCODING_FLAC: return !(bits_per_sample & 7) && (bits_per_sample >> 3) - 1 < 3? bits_per_sample: 0;
+ case SOX_ENCODING_WAVPACK:
+ case SOX_ENCODING_FLAC: return !(bits_per_sample & 7) && (bits_per_sample >> 3) - 1 < 4? bits_per_sample: 0;
case SOX_ENCODING_SIGN2: return bits_per_sample <= 32? bits_per_sample : 0;
case SOX_ENCODING_UNSIGNED: return !(bits_per_sample & 7) && (bits_per_sample >> 3) - 1 < 4? bits_per_sample: 0;
@@ -172,6 +178,7 @@
case SOX_ENCODING_AMR_NB:
case SOX_ENCODING_LPC10: return !bits_per_sample? 16: 0;
+ case SOX_ENCODING_WAVPACKF:
case SOX_ENCODING_FLOAT: return bits_per_sample == 32 ? 24: bits_per_sample == 64 ? 53: 0;
case SOX_ENCODING_FLOAT_TEXT: return !bits_per_sample? 53: 0;
@@ -435,8 +442,10 @@
}
}
ft->handler = *handler;
- if (ft->handler.flags & SOX_FILE_NOSTDIO)
+ if (ft->handler.flags & SOX_FILE_NOSTDIO) {
fclose(ft->fp);
+ ft->fp = NULL;
+ }
}
if (!ft->handler.startread && !ft->handler.read) {
sox_fail("file type `%s' isn't readable", filetype);
--- a/src/formats.h
+++ b/src/formats.h
@@ -75,3 +75,6 @@
#if defined HAVE_OGG_VORBIS
FORMAT(vorbis)
#endif
+#if defined HAVE_WAVPACK
+ FORMAT(wavpack)
+#endif
--- a/src/formats_i.c
+++ b/src/formats_i.c
@@ -179,6 +179,11 @@
clearerr(ft->fp);
}
+int lsx_unreadb(sox_format_t * ft, unsigned b)
+{
+ return ungetc((int)b, ft->fp);
+}
+
/* Implements traditional fseek() behavior. Meant to abstract out
* file operations so that they could one day also work on memory
* buffers.
--- a/src/sox.h
+++ b/src/sox.h
@@ -209,6 +209,8 @@
SOX_ENCODING_FLOAT_TEXT, /* floating point (text format) */
SOX_ENCODING_FLAC , /* FLAC compression */
SOX_ENCODING_HCOM , /* */
+ SOX_ENCODING_WAVPACK , /* */
+ SOX_ENCODING_WAVPACKF , /* */
SOX_ENCODING_LOSSLESS , /* Lossless above, lossy below */
--- a/src/sox_i.h
+++ b/src/sox_i.h
@@ -79,47 +79,48 @@
void lsx_set_signal_defaults(sox_signalinfo_t * signal);
#define lsx_writechars(ft, chars, len) (lsx_writebuf(ft, chars, len) == len? SOX_SUCCESS : SOX_EOF)
-sox_size_t lsx_read_b_buf(sox_format_t * ft, uint8_t *buf, sox_size_t len);
-sox_size_t lsx_read_w_buf(sox_format_t * ft, uint16_t *buf, sox_size_t len);
sox_size_t lsx_read_3_buf(sox_format_t * ft, uint24_t *buf, sox_size_t len);
+sox_size_t lsx_read_b_buf(sox_format_t * ft, uint8_t *buf, sox_size_t len);
+sox_size_t lsx_read_df_buf(sox_format_t * ft, double *buf, sox_size_t len);
sox_size_t lsx_read_dw_buf(sox_format_t * ft, uint32_t *buf, sox_size_t len);
sox_size_t lsx_read_f_buf(sox_format_t * ft, float *buf, sox_size_t len);
-sox_size_t lsx_read_df_buf(sox_format_t * ft, double *buf, sox_size_t len);
+sox_size_t lsx_read_w_buf(sox_format_t * ft, uint16_t *buf, sox_size_t len);
-sox_size_t lsx_write_b_buf(sox_format_t * ft, uint8_t *buf, sox_size_t len);
-sox_size_t lsx_write_w_buf(sox_format_t * ft, uint16_t *buf, sox_size_t len);
sox_size_t lsx_write_3_buf(sox_format_t * ft, uint24_t *buf, sox_size_t len);
+sox_size_t lsx_write_b_buf(sox_format_t * ft, uint8_t *buf, sox_size_t len);
+sox_size_t lsx_write_df_buf(sox_format_t * ft, double *buf, sox_size_t len);
sox_size_t lsx_write_dw_buf(sox_format_t * ft, uint32_t *buf, sox_size_t len);
sox_size_t lsx_write_f_buf(sox_format_t * ft, float *buf, sox_size_t len);
-sox_size_t lsx_write_df_buf(sox_format_t * ft, double *buf, sox_size_t len);
+sox_size_t lsx_write_w_buf(sox_format_t * ft, uint16_t *buf, sox_size_t len);
int lsx_read3(sox_format_t * ft, uint24_t * u3);
int lsx_readb(sox_format_t * ft, uint8_t * ub);
+int lsx_readchars(sox_format_t * ft, char * chars, sox_size_t len);
int lsx_readdf(sox_format_t * ft, double * d);
int lsx_readdw(sox_format_t * ft, uint32_t * udw);
int lsx_readf(sox_format_t * ft, float * f);
int lsx_readw(sox_format_t * ft, uint16_t * uw);
-int lsx_readchars(sox_format_t * ft, char * chars, sox_size_t len);
int lsx_write3(sox_format_t * ft, unsigned u3);
int lsx_writeb(sox_format_t * ft, unsigned ub);
+int lsx_writedf(sox_format_t * ft, double d);
int lsx_writedw(sox_format_t * ft, unsigned udw);
int lsx_writef(sox_format_t * ft, double f);
int lsx_writesb(sox_format_t * ft, signed);
int lsx_writesw(sox_format_t * ft, signed);
int lsx_writew(sox_format_t * ft, unsigned uw);
-int lsx_writedf(sox_format_t * ft, double d);
-int lsx_seeki(sox_format_t * ft, sox_ssize_t to_sample, int whence);
-int lsx_offset_seek(sox_format_t * ft, off_t byte_offset, sox_size_t to_sample);
-sox_size_t lsx_filelength(sox_format_t * ft);
-int lsx_flush(sox_format_t * ft);
-sox_ssize_t lsx_tell(sox_format_t * ft);
int lsx_eof(sox_format_t * ft);
int lsx_error(sox_format_t * ft);
-void lsx_rewind(sox_format_t * ft);
+int lsx_flush(sox_format_t * ft);
+int lsx_seeki(sox_format_t * ft, sox_ssize_t offset, int whence);
+int lsx_unreadb(sox_format_t * ft, unsigned ub);
+sox_size_t lsx_filelength(sox_format_t * ft);
+sox_ssize_t lsx_tell(sox_format_t * ft);
void lsx_clearerr(sox_format_t * ft);
+void lsx_rewind(sox_format_t * ft);
+int lsx_offset_seek(sox_format_t * ft, off_t byte_offset, sox_size_t to_sample);
void lsx_fail_errno(sox_format_t *, int, const char *, ...)
#ifdef __GNUC__
@@ -132,8 +133,6 @@
{
sox_globals_t * global_info;
} sox_formats_globals;
-
-
--- a/src/soxconfig.h.cmake
+++ b/src/soxconfig.h.cmake
@@ -34,4 +34,5 @@
#cmakedefine HAVE_SYS_TIME_H 1
#cmakedefine HAVE_UNISTD_H 1
#cmakedefine HAVE_VSNPRINTF 1
+#cmakedefine HAVE_WAVPACK 1
#cmakedefine WORDS_BIGENDIAN 1
--- a/src/tests.sh
+++ b/src/tests.sh
@@ -124,16 +124,16 @@
do_multichannel_formats () {
format1=u1
- convertToAndFrom s1 u1 s2 u2 s3 u3 s4 u4 raw Raw dat au wav aiff aifc flac caf sph
+ convertToAndFrom s1 u1 s2 u2 s3 u3 s4 u4 raw Raw dat au wav aiff aifc flac caf sph wv
format1=s2
- convertToAndFrom s2 u2 s3 u3 s4 u4 raw Raw dat au wav aiff aifc flac caf sph
+ convertToAndFrom s2 u2 s3 u3 s4 u4 raw Raw dat au wav aiff aifc flac caf sph wv
format1=u3
- convertToAndFrom s3 u3 s4 u4 raw Raw wav aiff aifc flac sph
+ convertToAndFrom s3 u3 s4 u4 raw Raw wav aiff aifc flac sph wv
format1=s4
- convertToAndFrom s4 u4 Raw wav aiff aifc caf sph
+ convertToAndFrom s4 u4 Raw wav aiff aifc caf sph wv
format1=al
convertToAndFrom al s2 u2 s4 raw Raw dat aiff aifc flac caf
@@ -196,6 +196,7 @@
${builddir}/sox_sample_test || exit 1
# Don't try to test unsupported stuff
+${bindir}/sox --help|grep "^AUDIO FILE.*\<wv\>">/dev/null || skip="wv $skip"
${bindir}/sox --help|grep "^AUDIO FILE.*\<flac\>">/dev/null || skip="flac $skip"
${bindir}/sox --help|grep "^AUDIO FILE.*\<caf\>" >/dev/null || skip="caf $skip"
--- /dev/null
+++ b/src/wavpack.c
@@ -1,0 +1,181 @@
+/*
+ * File format: WavPack (c) 2008 robs@users.sourceforge.net
+ *
+ * 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 "sox_i.h"
+#include "wavpack/wavpack.h"
+
+typedef struct {
+ WavpackContext * codec;
+ sox_size_t first_block_size;
+} priv_t;
+
+assert_static(sizeof(priv_t) <= SOX_MAX_FILE_PRIVSIZE, WAVPACK_PRIV_TOO_BIG);
+
+static int32_t ft_read_b_buf(void * ft, void * buf, int32_t len) {
+ return (int32_t)lsx_read_b_buf((sox_format_t *)ft, buf, (sox_size_t)len);}
+static uint32_t ft_tell(void * ft) {
+ return lsx_tell((sox_format_t *)ft);}
+static int ft_seek_abs(void * ft, uint32_t offset) {
+ return lsx_seeki((sox_format_t *)ft, (sox_ssize_t)offset, SEEK_SET);}
+static int ft_seek_rel(void * ft, int32_t offset, int mode) {
+ return lsx_seeki((sox_format_t *)ft, offset, mode);}
+static int ft_unreadb(void * ft, int b) {
+ return lsx_unreadb((sox_format_t *)ft, (unsigned)b);}
+static uint32_t ft_filelength(void * ft) {
+ return lsx_filelength((sox_format_t *)ft);}
+static int ft_is_seekable(void *ft) {
+ return ((sox_format_t *)ft)->seekable;}
+static int32_t ft_write_b_buf(void * ft, void * buf, int32_t len) {
+ priv_t * p = (priv_t *)((sox_format_t *)ft)->priv;
+ if (!p->first_block_size)
+ p->first_block_size = len;
+ return (int32_t)lsx_write_b_buf((sox_format_t *)ft, buf, (sox_size_t)len);}
+
+static WavpackStreamReader io_fns = {
+ ft_read_b_buf, ft_tell, ft_seek_abs, ft_seek_rel,
+ ft_unreadb, ft_filelength, ft_is_seekable, ft_write_b_buf
+};
+
+static int start_read(sox_format_t * ft)
+{
+ priv_t * p = (priv_t *)ft->priv;
+ char msg[80];
+
+ p->codec = WavpackOpenFileInputEx(&io_fns, ft, NULL, msg, OPEN_NORMALIZE, 0);
+ ft->encoding.bits_per_sample = WavpackGetBytesPerSample(p->codec) << 3;
+ ft->signal.channels = WavpackGetNumChannels(p->codec);
+ if (WavpackGetSampleRate(p->codec) && ft->signal.rate && ft->signal.rate != WavpackGetSampleRate(p->codec))
+ sox_warn("`%s': overriding sample rate", ft->filename);
+ else ft->signal.rate = WavpackGetSampleRate(p->codec);
+
+ ft->length = WavpackGetNumSamples(p->codec) * ft->signal.channels;
+ ft->encoding.encoding = (WavpackGetMode(p->codec) & MODE_FLOAT)?
+ SOX_ENCODING_WAVPACKF : SOX_ENCODING_WAVPACK;
+ return SOX_SUCCESS;
+}
+
+static sox_size_t read_samples(sox_format_t * ft, sox_sample_t * buf, sox_size_t len)
+{
+ priv_t * p = (priv_t *)ft->priv;
+ size_t i, actual = WavpackUnpackSamples(p->codec, buf, len / ft->signal.channels) * ft->signal.channels;
+ for (i = 0; i < actual; ++i) switch (ft->encoding.bits_per_sample) {
+ case 8: buf[i] = SOX_SIGNED_8BIT_TO_SAMPLE(buf[i],); break;
+ case 16: buf[i] = SOX_SIGNED_16BIT_TO_SAMPLE(buf[i],); break;
+ case 24: buf[i] = SOX_SIGNED_24BIT_TO_SAMPLE(buf[i],); break;
+ case 32: buf[i] = ft->encoding.encoding == SOX_ENCODING_WAVPACKF?
+ SOX_FLOAT_32BIT_TO_SAMPLE(*(float *)&buf[i], ft->clips) :
+ SOX_SIGNED_32BIT_TO_SAMPLE(buf[i],);
+ break;
+ }
+ return actual;
+}
+
+static int stop_read(sox_format_t * ft)
+{
+ priv_t * p = (priv_t *)ft->priv;
+ WavpackCloseFile(p->codec);
+ return SOX_SUCCESS;
+}
+
+static int start_write(sox_format_t * ft)
+{
+ priv_t * p = (priv_t *)ft->priv;
+ WavpackConfig config;
+
+ p->codec = WavpackOpenFileOutput(ft_write_b_buf, ft, NULL);
+ memset(&config, 0, sizeof(config));
+ config.bytes_per_sample = ft->encoding.bits_per_sample >> 3;
+ config.bits_per_sample = ft->encoding.bits_per_sample;
+ config.channel_mask = ft->signal.channels == 1? 4 :
+ ft->signal.channels == 2? 3 : (1 << ft->signal.channels) - 1;
+ config.num_channels = ft->signal.channels;
+ config.sample_rate = (int32_t)(ft->signal.rate + .5);
+ config.flags = CONFIG_VERY_HIGH_FLAG;
+ if (!WavpackSetConfiguration(p->codec, &config, ft->length? ft->length / ft->signal.channels : (uint32_t)-1)) {
+ lsx_fail_errno(ft, SOX_EHDR, WavpackGetErrorMessage(p->codec));
+ return SOX_EOF;
+ }
+ WavpackPackInit(p->codec);
+ return SOX_SUCCESS;
+}
+
+static sox_size_t write_samples(sox_format_t * ft, const sox_sample_t * buf, sox_size_t len)
+{
+ priv_t * p = (priv_t *)ft->priv;
+ size_t i;
+ int32_t * obuf = lsx_malloc(len * sizeof(*obuf));
+ int result;
+
+ for (i = 0; i < len; ++i) switch (ft->encoding.bits_per_sample) {
+ case 8: obuf[i] = SOX_SAMPLE_TO_SIGNED_8BIT(buf[i], ft->clips); break;
+ case 16: obuf[i] = SOX_SAMPLE_TO_SIGNED_16BIT(buf[i], ft->clips); break;
+ case 24: obuf[i] = SOX_SAMPLE_TO_SIGNED_24BIT(buf[i], ft->clips) << 8;
+ obuf[i] >>= 8; break;
+ case 32: obuf[i] = ft->encoding.encoding == SOX_ENCODING_WAVPACKF?
+ SOX_SAMPLE_TO_SIGNED_24BIT(*(float *)&buf[i], ft->clips) :
+ SOX_SAMPLE_TO_SIGNED_32BIT(buf[i], ft->clips);
+ break;
+ }
+ result = WavpackPackSamples(p->codec, obuf, len / ft->signal.channels);
+ free(obuf);
+ return result? len : 0;
+}
+
+static int stop_write(sox_format_t * ft)
+{
+ priv_t * p = (priv_t *)ft->priv;
+ WavpackFlushSamples(p->codec);
+ if (!WavpackFlushSamples(p->codec)) {
+ lsx_fail_errno(ft, SOX_EINVAL, "%s", WavpackGetErrorMessage(p->codec));
+ return SOX_EOF;
+ }
+ if (ft->seekable && WavpackGetNumSamples(p->codec) != WavpackGetSampleIndex(p->codec) && p->first_block_size >= 4) {
+ char * buf = lsx_malloc(p->first_block_size);
+ lsx_rewind(ft);
+ lsx_readchars(ft, buf, p->first_block_size);
+ if (!memcmp(buf, "wvpk", 4))
+ WavpackUpdateNumSamples(p->codec, buf);
+ }
+ p->codec = WavpackCloseFile(p->codec);
+ return SOX_SUCCESS;
+}
+
+static int seek(sox_format_t * ft, sox_size_t offset)
+{
+ priv_t * p = (priv_t *)ft->priv;
+
+ return WavpackSeekSample(p->codec, (offset / ft->signal.channels))? SOX_SUCCESS : SOX_EOF;
+}
+
+SOX_FORMAT_HANDLER(wavpack)
+{
+ static char const * const names[] = {"wv", NULL};
+ static unsigned const write_encodings[] = {
+ SOX_ENCODING_WAVPACK, 8, 16, 24, 32, 0,
+ SOX_ENCODING_WAVPACKF, 32, 0,
+ 0};
+ static sox_format_handler_t handler = {
+ SOX_LIB_VERSION_CODE,
+ "Lossless, lossy, and hybrid audio compression",
+ names, 0,
+ start_read, read_samples, stop_read,
+ start_write, write_samples, stop_write,
+ seek, write_encodings, NULL
+ };
+ return &handler;
+}