add library of sox

dev
xufulong 3 years ago
parent 1e632fd324
commit c918001551
  1. 342
      app/src/main/cpp/sox/8svx.c
  2. 184
      app/src/main/cpp/sox/Makefile.am
  3. 367
      app/src/main/cpp/sox/adpcm.c
  4. 79
      app/src/main/cpp/sox/adpcm.h
  5. 322
      app/src/main/cpp/sox/adpcms.c
  6. 55
      app/src/main/cpp/sox/adpcms.h
  7. 36
      app/src/main/cpp/sox/aifc-fmt.c
  8. 33
      app/src/main/cpp/sox/aiff-fmt.c
  9. 1151
      app/src/main/cpp/sox/aiff.c
  10. 22
      app/src/main/cpp/sox/aiff.h
  11. 21
      app/src/main/cpp/sox/al-fmt.c
  12. 379
      app/src/main/cpp/sox/alsa.c
  13. 90
      app/src/main/cpp/sox/amr-nb.c
  14. 115
      app/src/main/cpp/sox/amr-wb.c
  15. 335
      app/src/main/cpp/sox/amr.h
  16. 134
      app/src/main/cpp/sox/ao.c
  17. 237
      app/src/main/cpp/sox/au.c
  18. 287
      app/src/main/cpp/sox/avr.c
  19. 47
      app/src/main/cpp/sox/band.h
  20. 325
      app/src/main/cpp/sox/bend.c
  21. 178
      app/src/main/cpp/sox/biquad.c
  22. 78
      app/src/main/cpp/sox/biquad.h
  23. 416
      app/src/main/cpp/sox/biquads.c
  24. 273
      app/src/main/cpp/sox/bit-rot/CoreAudio/CoreAudio.h
  25. 0
      app/src/main/cpp/sox/bit-rot/mmreg.h
  26. 89
      app/src/main/cpp/sox/bit-rot/mmsystem.h
  27. 160
      app/src/main/cpp/sox/bit-rot/sndio.h
  28. 289
      app/src/main/cpp/sox/bit-rot/sys/audioio.h
  29. 34
      app/src/main/cpp/sox/bit-rot/windows.h
  30. 35
      app/src/main/cpp/sox/caf.c
  31. 49
      app/src/main/cpp/sox/cdr.c
  32. 351
      app/src/main/cpp/sox/chorus.c
  33. 293
      app/src/main/cpp/sox/compand.c
  34. 229
      app/src/main/cpp/sox/compandt.c
  35. 52
      app/src/main/cpp/sox/compandt.h
  36. 49
      app/src/main/cpp/sox/contrast.c
  37. 418
      app/src/main/cpp/sox/coreaudio.c
  38. 114
      app/src/main/cpp/sox/cvsd-fmt.c
  39. 680
      app/src/main/cpp/sox/cvsd.c
  40. 68
      app/src/main/cpp/sox/cvsd.h
  41. 112
      app/src/main/cpp/sox/cvsdfilt.h
  42. 162
      app/src/main/cpp/sox/dat.c
  43. 165
      app/src/main/cpp/sox/dcshift.c
  44. 118
      app/src/main/cpp/sox/deemph.plt
  45. 163
      app/src/main/cpp/sox/delay.c
  46. 137
      app/src/main/cpp/sox/dft_filter.c
  47. 16
      app/src/main/cpp/sox/dft_filter.h
  48. 436
      app/src/main/cpp/sox/dither.c
  49. 63
      app/src/main/cpp/sox/dither.h
  50. 73
      app/src/main/cpp/sox/divide.c
  51. 85
      app/src/main/cpp/sox/downsample.c
  52. 32
      app/src/main/cpp/sox/dvms-fmt.c
  53. 97
      app/src/main/cpp/sox/earwax.c
  54. 266
      app/src/main/cpp/sox/echo.c
  55. 278
      app/src/main/cpp/sox/echos.c
  56. 669
      app/src/main/cpp/sox/effects.c
  57. 90
      app/src/main/cpp/sox/effects.h
  58. 483
      app/src/main/cpp/sox/effects_i.c
  59. 645
      app/src/main/cpp/sox/effects_i_dsp.c
  60. 97
      app/src/main/cpp/sox/example0.c
  61. 167
      app/src/main/cpp/sox/example1.c
  62. 118
      app/src/main/cpp/sox/example2.c
  63. 113
      app/src/main/cpp/sox/example3.c
  64. 98
      app/src/main/cpp/sox/example4.c
  65. 83
      app/src/main/cpp/sox/example5.c
  66. 128
      app/src/main/cpp/sox/example6.c
  67. 21
      app/src/main/cpp/sox/f4-fmt.c
  68. 21
      app/src/main/cpp/sox/f8-fmt.c
  69. 399
      app/src/main/cpp/sox/fade.c
  70. 31
      app/src/main/cpp/sox/fap.c
  71. 1362
      app/src/main/cpp/sox/fft4g.c
  72. 37
      app/src/main/cpp/sox/fft4g.h
  73. 119
      app/src/main/cpp/sox/fifo.h
  74. 105
      app/src/main/cpp/sox/fir.c
  75. 145
      app/src/main/cpp/sox/firfit.c
  76. 606
      app/src/main/cpp/sox/flac.c
  77. 275
      app/src/main/cpp/sox/flanger.c
  78. 1351
      app/src/main/cpp/sox/formats.c
  79. 130
      app/src/main/cpp/sox/formats.h
  80. 545
      app/src/main/cpp/sox/formats_i.c
  81. 2421
      app/src/main/cpp/sox/g711.c
  82. 21
      app/src/main/cpp/sox/g711.h
  83. 167
      app/src/main/cpp/sox/g721.c
  84. 151
      app/src/main/cpp/sox/g723_24.c
  85. 171
      app/src/main/cpp/sox/g723_40.c
  86. 575
      app/src/main/cpp/sox/g72x.c
  87. 157
      app/src/main/cpp/sox/g72x.h
  88. 276
      app/src/main/cpp/sox/gain.c
  89. 349
      app/src/main/cpp/sox/getopt.c
  90. 247
      app/src/main/cpp/sox/gsm.c
  91. 207
      app/src/main/cpp/sox/gsrt.c
  92. 502
      app/src/main/cpp/sox/hcom.c
  93. 102
      app/src/main/cpp/sox/hilbert.c
  94. 80
      app/src/main/cpp/sox/htk.c
  95. 227
      app/src/main/cpp/sox/id3.c
  96. 25
      app/src/main/cpp/sox/id3.h
  97. 33
      app/src/main/cpp/sox/ima-fmt.c
  98. 365
      app/src/main/cpp/sox/ima_rw.c
  99. 84
      app/src/main/cpp/sox/ima_rw.h
  100. 58
      app/src/main/cpp/sox/input.c
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,342 @@
/* Amiga 8SVX format handler: W V Neisius, February 1992 */
#include "sox_i.h"
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define BUFLEN 512
/* Private data used by writer */
typedef struct{
uint32_t nsamples;
uint32_t left;
off_t ch0_pos;
sox_uint8_t buf[4][BUFLEN];
FILE* tmp[4];
} priv_t;
static void svxwriteheader(sox_format_t *, size_t);
/*======================================================================*/
/* 8SVXSTARTREAD */
/*======================================================================*/
static int startread(sox_format_t * ft)
{
priv_t * p = (priv_t * ) ft->priv;
char buf[12];
char *chunk_buf;
uint32_t totalsize;
uint32_t chunksize;
uint32_t channels;
unsigned short rate;
if (! ft->seekable)
{
lsx_fail_errno(ft,SOX_EINVAL,"8svx input file must be a file, not a pipe");
return (SOX_EOF);
}
rate = 0;
channels = 1;
/* read FORM chunk */
if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || strncmp(buf, "FORM", (size_t)4) != 0)
{
lsx_fail_errno(ft, SOX_EHDR, "Header did not begin with magic word `FORM'");
return(SOX_EOF);
}
lsx_readdw(ft, &totalsize);
if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || strncmp(buf, "8SVX", (size_t)4) != 0)
{
lsx_fail_errno(ft, SOX_EHDR, "'FORM' chunk does not specify `8SVX' as type");
return(SOX_EOF);
}
/* read chunks until 'BODY' (or end) */
while (lsx_reads(ft, buf, (size_t)4) == SOX_SUCCESS && strncmp(buf,"BODY",(size_t)4) != 0) {
if (strncmp(buf,"VHDR",(size_t)4) == 0) {
lsx_readdw(ft, &chunksize);
if (chunksize != 20)
{
lsx_fail_errno(ft, SOX_EHDR, "VHDR chunk has bad size");
return(SOX_EOF);
}
lsx_seeki(ft,(off_t)12,SEEK_CUR);
lsx_readw(ft, &rate);
lsx_seeki(ft,(off_t)1,SEEK_CUR);
lsx_readbuf(ft, buf,(size_t)1);
if (buf[0] != 0)
{
lsx_fail_errno(ft, SOX_EFMT, "Unsupported data compression");
return(SOX_EOF);
}
lsx_seeki(ft,(off_t)4,SEEK_CUR);
continue;
}
if (strncmp(buf,"ANNO",(size_t)4) == 0) {
lsx_readdw(ft, &chunksize);
if (chunksize & 1)
chunksize++;
chunk_buf = lsx_malloc(chunksize + (size_t)2);
if (lsx_readbuf(ft, chunk_buf,(size_t)chunksize)
!= chunksize)
{
lsx_fail_errno(ft, SOX_EHDR, "Couldn't read all of header");
return(SOX_EOF);
}
chunk_buf[chunksize] = '\0';
lsx_debug("%s",chunk_buf);
free(chunk_buf);
continue;
}
if (strncmp(buf,"NAME",(size_t)4) == 0) {
lsx_readdw(ft, &chunksize);
if (chunksize & 1)
chunksize++;
chunk_buf = lsx_malloc(chunksize + (size_t)1);
if (lsx_readbuf(ft, chunk_buf,(size_t)chunksize)
!= chunksize)
{
lsx_fail_errno(ft, SOX_EHDR, "Couldn't read all of header");
return(SOX_EOF);
}
chunk_buf[chunksize] = '\0';
lsx_debug("%s",chunk_buf);
free(chunk_buf);
continue;
}
if (strncmp(buf,"CHAN",(size_t)4) == 0) {
lsx_readdw(ft, &chunksize);
if (chunksize != 4)
{
lsx_fail_errno(ft, SOX_EHDR, "Couldn't read all of header");
return(SOX_EOF);
}
lsx_readdw(ft, &channels);
channels = (channels & 0x01) +
((channels & 0x02) >> 1) +
((channels & 0x04) >> 2) +
((channels & 0x08) >> 3);
continue;
}
/* some other kind of chunk */
lsx_readdw(ft, &chunksize);
if (chunksize & 1)
chunksize++;
lsx_seeki(ft,(off_t)chunksize,SEEK_CUR);
continue;
}
if (rate == 0)
{
lsx_fail_errno(ft, SOX_EHDR, "Invalid sample rate");
return(SOX_EOF);
}
if (strncmp(buf,"BODY",(size_t)4) != 0)
{
lsx_fail_errno(ft, SOX_EHDR, "BODY chunk not found");
return(SOX_EOF);
}
lsx_readdw(ft, &(p->nsamples));
p->left = p->nsamples;
p->ch0_pos = lsx_tell(ft);
ft->signal.length = p->nsamples;
ft->signal.channels = channels;
ft->signal.rate = rate;
ft->encoding.encoding = SOX_ENCODING_SIGN2;
ft->encoding.bits_per_sample = 8;
return(SOX_SUCCESS);
}
/*======================================================================*/
/* 8SVXREAD */
/*======================================================================*/
static size_t read_samples(sox_format_t * ft, sox_sample_t *buf, size_t nsamp)
{
size_t done = 0;
priv_t * p = (priv_t * ) ft->priv;
size_t frames = nsamp / ft->signal.channels;
unsigned width = p->nsamples / ft->signal.channels;
if (p->left < frames)
frames = p->left;
while (done != frames) {
size_t chunk = frames - done;
size_t i;
unsigned ch;
if (chunk > BUFLEN)
chunk = BUFLEN;
for (ch = 0; ch != ft->signal.channels; ch++) {
if (lsx_seeki(ft, p->ch0_pos + ch * width, SEEK_SET) ||
chunk != lsx_readbuf(ft, p->buf[ch], chunk))
return done * ft->signal.channels;
}
for (i = 0; i != chunk; i++) {
for (ch = 0; ch != ft->signal.channels; ch++) {
/* scale signed up to long's range */
*buf++ = SOX_SIGNED_8BIT_TO_SAMPLE(p->buf[ch][i], dummy);
}
}
done += chunk;
p->left -= chunk * ft->signal.channels;
p->ch0_pos += chunk;
}
return done * ft->signal.channels;
}
/*======================================================================*/
/* 8SVXSTARTWRITE */
/*======================================================================*/
static int startwrite(sox_format_t * ft)
{
priv_t * p = (priv_t * ) ft->priv;
size_t i;
/* open channel output files */
for (i = 0; i < ft->signal.channels; i++) {
if ((p->tmp[i] = lsx_tmpfile()) == NULL)
{
lsx_fail_errno(ft,errno,"Can't open channel output file");
return(SOX_EOF);
}
}
p->nsamples = 0;
return(SOX_SUCCESS);
}
/*======================================================================*/
/* 8SVXWRITE */
/*======================================================================*/
static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t len)
{
priv_t * p = (priv_t * ) ft->priv;
SOX_SAMPLE_LOCALS;
unsigned char datum;
size_t done = 0, i;
p->nsamples += len;
while(done < len) {
for (i = 0; i < ft->signal.channels; i++) {
datum = SOX_SAMPLE_TO_SIGNED_8BIT(*buf++, ft->clips);
putc(datum, p->tmp[i]);
}
done += ft->signal.channels;
}
return (done);
}
/*======================================================================*/
/* 8SVXSTOPWRITE */
/*======================================================================*/
static int stopwrite(sox_format_t * ft)
{
priv_t * p = (priv_t * ) ft->priv;
size_t i, len;
char svxbuf[512];
svxwriteheader(ft, (size_t) p->nsamples);
/* append all channel pieces to channel 0 */
/* close temp files */
for (i = 0; i < ft->signal.channels; i++) {
if (fseeko(p->tmp[i], (off_t)0, 0))
{
lsx_fail_errno (ft,errno,"Can't rewind channel output file %lu",(unsigned long)i);
return(SOX_EOF);
}
while (!feof(p->tmp[i])) {
len = fread(svxbuf, (size_t) 1, (size_t) 512, p->tmp[i]);
if (lsx_writebuf(ft, svxbuf, len) != len) {
lsx_fail_errno (ft,errno,"Can't write channel output file %lu",(unsigned long)i);
return SOX_EOF;
}
}
fclose (p->tmp[i]);
}
/* add a pad byte if BODY size is odd */
if(p->nsamples % 2 != 0)
lsx_writeb(ft, '\0');
return(SOX_SUCCESS);
}
/*======================================================================*/
/* 8SVXWRITEHEADER */
/*======================================================================*/
#define SVXHEADERSIZE 100
static void svxwriteheader(sox_format_t * ft, size_t nsamples)
{
size_t formsize = nsamples + SVXHEADERSIZE - 8;
/* FORM size must be even */
if(formsize % 2 != 0) formsize++;
lsx_writes(ft, "FORM");
lsx_writedw(ft, (unsigned) formsize); /* size of file */
lsx_writes(ft, "8SVX"); /* File type */
lsx_writes(ft, "VHDR");
lsx_writedw(ft, 20); /* number of bytes to follow */
lsx_writedw(ft, (unsigned) nsamples/ft->signal.channels); /* samples, 1-shot */
lsx_writedw(ft, 0); /* samples, repeat */
lsx_writedw(ft, 0); /* samples per repeat cycle */
lsx_writew(ft, min(65535, (unsigned)(ft->signal.rate + .5)));
lsx_writeb(ft,1); /* number of octabes */
lsx_writeb(ft,0); /* data compression (none) */
lsx_writew(ft,1); lsx_writew(ft,0); /* volume */
lsx_writes(ft, "ANNO");
lsx_writedw(ft, 32); /* length of block */
lsx_writes(ft, "File created by Sound Exchange ");
lsx_writes(ft, "CHAN");
lsx_writedw(ft, 4);
lsx_writedw(ft, (ft->signal.channels == 2) ? 6u :
(ft->signal.channels == 4) ? 15u : 2u);
lsx_writes(ft, "BODY");
lsx_writedw(ft, (unsigned) nsamples); /* samples in file */
}
LSX_FORMAT_HANDLER(svx)
{
static char const * const names[] = {"8svx", NULL};
static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 8, 0, 0};
static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
"Amiga audio format (a subformat of the Interchange File Format)",
names, SOX_FILE_BIG_END|SOX_FILE_MONO|SOX_FILE_STEREO|SOX_FILE_QUAD,
startread, read_samples, NULL,
startwrite, write_samples, stopwrite,
NULL, write_encodings, NULL, sizeof(priv_t)
};
return &handler;
}

@ -0,0 +1,184 @@
## Process this file with automake to produce Makefile.in
RM = rm -f
AM_CPPFLAGS = -DLADSPA_PATH="\"@LADSPA_PATH@\""
if HAVE_LIBLTDL
# This is being used as a short cut to turn off versioning of ALL dynamic
# fmt libraries. If any fmt ever needs to add a specific LDFLAGS
# then it will need to also add -avoid-version because AM_LDFLAGS
# is ignored when you specify a more specific one.
# We want to version libsox and we are OK because they
# have a more specific LDFLAGS that includes -version-info.
AM_LDFLAGS = -avoid-version -module
AM_CPPFLAGS += -DPKGLIBDIR="\"$(pkglibdir)\""
endif
#########################
# SoX - the application #
#########################
bin_PROGRAMS = sox
EXTRA_PROGRAMS = example0 example1 example2 example3 example4 example5 example6 sox_sample_test
lib_LTLIBRARIES = libsox.la
include_HEADERS = sox.h
sox_SOURCES = sox.c
if HAVE_WIN32_GLOB
sox_SOURCES += win32/glob.c win32/glob.h
AM_CPPFLAGS += -I$(srcdir)/win32
endif
sox_LDADD = libsox.la
example0_SOURCES = example0.c
example1_SOURCES = example1.c
example2_SOURCES = example2.c
example3_SOURCES = example3.c
example4_SOURCES = example4.c
example5_SOURCES = example5.c
example6_SOURCES = example6.c
sox_sample_test_SOURCES = sox_sample_test.c
######################################################
# libsox - file format, effects, and utility library #
######################################################
# Format handlers and utils source
libsox_la_SOURCES = adpcms.c adpcms.h aiff.c aiff.h cvsd.c cvsd.h cvsdfilt.h \
g711.c g711.h g721.c g723_24.c g723_40.c g72x.c g72x.h vox.c vox.h \
raw.c raw.h formats.c formats.h formats_i.c sox_i.h skelform.c \
xmalloc.c xmalloc.h getopt.c \
util.c util.h libsox.c libsox_i.c sox-fmt.c soxomp.h
# Effects source
libsox_la_SOURCES += \
band.h bend.c biquad.c biquad.h biquads.c chorus.c compand.c \
compandt.c compandt.h contrast.c dcshift.c delay.c dft_filter.c \
dft_filter.h dither.c dither.h divide.c downsample.c earwax.c \
echo.c echos.c effects.c effects.h effects_i.c effects_i_dsp.c \
fade.c fft4g.c fft4g.h fifo.h fir.c firfit.c flanger.c gain.c \
hilbert.c input.c ladspa.h ladspa.c loudness.c mcompand.c \
mcompand_xover.h noiseprof.c noisered.c \
noisered.h output.c overdrive.c pad.c phaser.c rate.c \
rate_filters.h rate_half_fir.h rate_poly_fir0.h rate_poly_fir.h \
remix.c repeat.c reverb.c reverse.c silence.c sinc.c skeleff.c \
speed.c splice.c stat.c stats.c stretch.c swap.c \
synth.c tempo.c tremolo.c trim.c upsample.c vad.c vol.c
if HAVE_PNG
libsox_la_SOURCES += spectrogram.c
endif
libsox_la_LIBADD =
# Libraries required by libsox for file handlers, effects, or utils;
# regardless if libltdl is used or not.
if HAVE_PNG
libsox_la_LIBADD += @PNG_LIBS@
endif
if HAVE_MAGIC
libsox_la_LIBADD += @MAGIC_LIBS@
endif
if HAVE_LIBGSM
libsox_la_LIBADD += @LIBGSM_LIBS@
endif
libsox_la_CFLAGS =
libsox_la_LDFLAGS = -no-undefined -version-info @SHLIB_VERSION@ \
-export-symbols $(srcdir)/libsox.sym
EXTRA_libsox_la_DEPENDENCIES = $(srcdir)/libsox.sym
if HAVE_LIBLTDL
libsox_la_CFLAGS += $(LIBLTDL_CFLAGS)
libsox_la_LIBADD += $(LIBLTDL_LIBS)
endif
#########################
# libsox - File Formats #
#########################
# Uncomment for bit-rot detection on linux
#libsox_la_SOURCES += coreaudio.c sndio.c sunaudio.c
#libsox_la_CFLAGS += -Ibit-rot
libsox_la_SOURCES += raw-fmt.c s1-fmt.c s2-fmt.c s3-fmt.c \
s4-fmt.c u1-fmt.c u2-fmt.c u3-fmt.c u4-fmt.c al-fmt.c la-fmt.c ul-fmt.c \
lu-fmt.c 8svx.c aiff-fmt.c aifc-fmt.c au.c avr.c cdr.c cvsd-fmt.c \
dvms-fmt.c dat.c hcom.c htk.c maud.c prc.c sf.c smp.c \
sounder.c soundtool.c sphere.c tx16w.c voc.c vox-fmt.c ima-fmt.c adpcm.c adpcm.h \
ima_rw.c ima_rw.h wav.c wve.c xa.c nulfile.c f4-fmt.c f8-fmt.c gsrt.c \
id3.c id3.h
if HAVE_ID3TAG
libsox_la_LIBADD += @ID3TAG_LIBS@
endif
pkglib_LTLIBRARIES =
include optional-fmts.am
# example programs will need same link options as sox does.
example0_LDADD = ${sox_LDADD}
example1_LDADD = ${sox_LDADD}
example2_LDADD = ${sox_LDADD}
example3_LDADD = ${sox_LDADD}
example4_LDADD = ${sox_LDADD}
example5_LDADD = ${sox_LDADD}
example6_LDADD = ${sox_LDADD}
EXTRA_DIST = monkey.wav optional-fmts.am \
tests.sh testall.sh tests.bat testall.bat test-comments
all: sox$(EXEEXT)
examples: example0$(EXEEXT) example1$(EXEEXT) example2$(EXEEXT) example3$(EXEEXT) example4$(EXEEXT) example5$(EXEEXT) example6$(EXEEXT)
extras: examples sox_sample_test$(EXEEXT)
MAKELINKS = for n in $(SYMLINKS); do $(RM) $$n$(EXEEXT) && $(LN_S) sox$(EXEEXT) $$n$(EXEEXT); done
all-local: sox$(EXEEXT)
$(MAKELINKS)
install-exec-hook:
cd $(DESTDIR)$(bindir) && $(MAKELINKS)
uninstall-hook:
cd $(DESTDIR)$(bindir) && $(RM) play$(EXEEXT) rec$(EXEEXT) soxi$(EXEEXT)
clean-local:
$(RM) play$(EXEEXT) rec$(EXEEXT) soxi$(EXEEXT)
$(RM) sox_sample_test$(EXEEXT)
$(RM) example0$(EXEEXT) example1$(EXEEXT) example2$(EXEEXT) example3$(EXEEXT) example4$(EXEEXT) example5$(EXEEXT) example6$(EXEEXT)
distclean-local:
loc:
sloccount \
$(include_HEADERS) \
$(sox_SOURCES) \
$(example0_SOURCES) \
$(example1_SOURCES) \
$(example2_SOURCES) \
$(example3_SOURCES) \
$(example4_SOURCES) \
$(example5_SOURCES) \
$(example6_SOURCES) \
$(sox_sample_test_SOURCES) \
$(libsox_la_SOURCES)
# Ideally we would use the "check" target so that "make distcheck"
# would run the test suite, but an uninstalled libltdl build cannot
# currently load its formats and effects, so the checks would fail.
installcheck:
$(srcdir)/tests.sh --bindir=$(DESTDIR)${bindir} --builddir=${builddir} --srcdir=${srcdir}
$(srcdir)/testall.sh --bindir=$(DESTDIR)${bindir} --srcdir=${srcdir}

@ -0,0 +1,367 @@
/* adpcm.c codex functions for MS_ADPCM data
* (hopefully) provides interoperability with
* Microsoft's ADPCM format, but, as usual,
* see LACK-OF-WARRANTY information below.
*
* Copyright (C) 1999 Stanley J. Brooks <stabro@megsinet.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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
/*
* November 22, 1999
* specs I've seen are unclear about ADPCM supporting more than 2 channels,
* but these routines support more channels in a manner which looks (IMHO)
* like the most natural extension.
*
* Remark: code still turbulent, encoding very new.
*
*/
#include "sox_i.h"
#include "adpcm.h"
#include <sys/types.h>
#include <stdio.h>
typedef struct {
sox_sample_t step; /* step size */
short coef[2];
} MsState_t;
#define lsbshortldi(x,p) { (x)=((short)((int)(p)[0] + ((int)(p)[1]<<8))); (p) += 2; }
/*
* Lookup tables for MS ADPCM format
*/
/* these are step-size adjust factors, where
* 1.0 is scaled to 0x100
*/
static const
sox_sample_t stepAdjustTable[] = {
230, 230, 230, 230, 307, 409, 512, 614,
768, 614, 512, 409, 307, 230, 230, 230
};
/* TODO : The first 7 lsx_ms_adpcm_i_coef sets are always hardcoded and must
appear in the actual WAVE file. They should be read in
in case a sound program added extras to the list. */
const short lsx_ms_adpcm_i_coef[7][2] = {
{ 256, 0},
{ 512,-256},
{ 0, 0},
{ 192, 64},
{ 240, 0},
{ 460,-208},
{ 392,-232}
};
extern void *lsx_ms_adpcm_alloc(unsigned chans)
{
return lsx_malloc(chans * sizeof(MsState_t));
}
static inline sox_sample_t AdpcmDecode(sox_sample_t c, MsState_t *state,
sox_sample_t sample1, sox_sample_t sample2)
{
sox_sample_t vlin;
sox_sample_t sample;
sox_sample_t step;
/** Compute next step value **/
step = state->step;
{
sox_sample_t nstep;
nstep = (stepAdjustTable[c] * step) >> 8;
state->step = (nstep < 16)? 16:nstep;
}
/** make linear prediction for next sample **/
vlin =
((sample1 * state->coef[0]) +
(sample2 * state->coef[1])) >> 8;
/** then add the code*step adjustment **/
c -= (c & 0x08) << 1;
sample = (c * step) + vlin;
if (sample > 0x7fff) sample = 0x7fff;
else if (sample < -0x8000) sample = -0x8000;
return (sample);
}
/* lsx_ms_adpcm_block_expand_i() outputs interleaved samples into one output buffer */
const char *lsx_ms_adpcm_block_expand_i(
void *priv,
unsigned chans, /* total channels */
int nCoef,
const short *coef,
const unsigned char *ibuff,/* input buffer[blockAlign] */
SAMPL *obuff, /* output samples, n*chans */
int n /* samples to decode PER channel */
)
{
const unsigned char *ip;
unsigned ch;
const char *errmsg = NULL;
MsState_t *state = priv; /* One decompressor state for each channel */
/* Read the four-byte header for each channel */
ip = ibuff;
for (ch = 0; ch < chans; ch++) {
unsigned char bpred = *ip++;
if (bpred >= nCoef) {
errmsg = "MSADPCM bpred >= nCoef, arbitrarily using 0\n";
bpred = 0;
}
state[ch].coef[0] = coef[(int)bpred*2+0];
state[ch].coef[1] = coef[(int)bpred*2+1];
}
for (ch = 0; ch < chans; ch++)
lsbshortldi(state[ch].step, ip);
/* sample1's directly into obuff */
for (ch = 0; ch < chans; ch++)
lsbshortldi(obuff[chans+ch], ip);
/* sample2's directly into obuff */
for (ch = 0; ch < chans; ch++)
lsbshortldi(obuff[ch], ip);
{
unsigned ch2;
unsigned char b;
short *op, *top, *tmp;
/* already have 1st 2 samples from block-header */
op = obuff + 2*chans;
top = obuff + n*chans;
ch2 = 0;
while (op < top) { /*** N.B. Without int casts, crashes on 64-bit arch ***/
b = *ip++;
tmp = op;
*op++ = AdpcmDecode(b >> 4, state+ch2, tmp[-(int)chans], tmp[-(int)(2*chans)]);
if (++ch2 == chans) ch2 = 0;
tmp = op;
*op++ = AdpcmDecode(b&0x0f, state+ch2, tmp[-(int)chans], tmp[-(int)(2*chans)]);
if (++ch2 == chans) ch2 = 0;
}
}
return errmsg;
}
static int AdpcmMashS(
unsigned ch, /* channel number to encode, REQUIRE 0 <= ch < chans */
unsigned chans, /* total channels */
SAMPL v[2], /* values to use as starting 2 */
const short coef[2],/* lin predictor coeffs */
const SAMPL *ibuff, /* ibuff[] is interleaved input samples */
int n, /* samples to encode PER channel */
int *iostep, /* input/output step, REQUIRE 16 <= *st <= 0x7fff */
unsigned char *obuff /* output buffer[blockAlign], or NULL for no output */
)
{
const SAMPL *ip, *itop;
unsigned char *op;
int ox = 0; /* */
int d, v0, v1, step;
double d2; /* long long is okay also, speed abt the same */
ip = ibuff + ch; /* point ip to 1st input sample for this channel */
itop = ibuff + n*chans;
v0 = v[0];
v1 = v[1];
d = *ip - v1; ip += chans; /* 1st input sample for this channel */
d2 = d*d; /* d2 will be sum of squares of errors, given input v0 and *st */
d = *ip - v0; ip += chans; /* 2nd input sample for this channel */
d2 += d*d;
step = *iostep;
op = obuff; /* output pointer (or NULL) */
if (op) { /* NULL means don't output, just compute the rms error */
op += chans; /* skip bpred indices */
op += 2*ch; /* channel's stepsize */
op[0] = step; op[1] = step>>8;
op += 2*chans; /* skip to v0 */
op[0] = v0; op[1] = v0>>8;
op += 2*chans; /* skip to v1 */
op[0] = v1; op[1] = v1>>8;
op = obuff+7*chans; /* point to base of output nibbles */
ox = 4*ch;
}
for (; ip < itop; ip+=chans) {
int vlin,d3,dp,c;
/* make linear prediction for next sample */
vlin = (v0 * coef[0] + v1 * coef[1]) >> 8;
d3 = *ip - vlin; /* difference between linear prediction and current sample */
dp = d3 + (step<<3) + (step>>1);
c = 0;
if (dp>0) {
c = dp/step;
if (c>15) c = 15;
}
c -= 8;
dp = c * step; /* quantized estimate of samp - vlin */
c &= 0x0f; /* mask to 4 bits */
v1 = v0; /* shift history */
v0 = vlin + dp;
if (v0<-0x8000) v0 = -0x8000;
else if (v0>0x7fff) v0 = 0x7fff;
d3 = *ip - v0;
d2 += d3*d3; /* update square-error */
if (op) { /* if we want output, put it in proper place */
op[ox>>3] |= (ox&4)? c:(c<<4);
ox += 4*chans;
lsx_debug_more("%.1x",c);
}
/* Update the step for the next sample */
step = (stepAdjustTable[c] * step) >> 8;
if (step < 16) step = 16;
}
if (op) lsx_debug_more("\n");
d2 /= n; /* be sure it's non-negative */
lsx_debug_more("ch%d: st %d->%d, d %.1f\n", ch, *iostep, step, sqrt(d2));
*iostep = step;
return (int) sqrt(d2);
}
static inline void AdpcmMashChannel(
unsigned ch, /* channel number to encode, REQUIRE 0 <= ch < chans */
unsigned chans, /* total channels */
const SAMPL *ip, /* ip[] is interleaved input samples */
int n, /* samples to encode PER channel, REQUIRE */
int *st, /* input/output steps, 16<=st[i] */
unsigned char *obuff /* output buffer[blockAlign] */
)
{
SAMPL v[2];
int n0,s0,s1,ss,smin;
int dmin,k,kmin;
n0 = n/2; if (n0>32) n0=32;
if (*st<16) *st = 16;
v[1] = ip[ch];
v[0] = ip[ch+chans];
dmin = 0; kmin = 0; smin = 0;
/* for each of 7 standard coeff sets, we try compression
* beginning with last step-value, and with slightly
* forward-adjusted step-value, taking best of the 14
*/
for (k=0; k<7; k++) {
int d0,d1;
ss = s0 = *st;
d0=AdpcmMashS(ch, chans, v, lsx_ms_adpcm_i_coef[k], ip, n, &ss, NULL); /* with step s0 */
s1 = s0;
AdpcmMashS(ch, chans, v, lsx_ms_adpcm_i_coef[k], ip, n0, &s1, NULL);
lsx_debug_more(" s32 %d\n",s1);
ss = s1 = (3*s0+s1)/4;
d1=AdpcmMashS(ch, chans, v, lsx_ms_adpcm_i_coef[k], ip, n, &ss, NULL); /* with step s1 */
if (!k || d0<dmin || d1<dmin) {
kmin = k;
if (d0<=d1) {
dmin = d0;
smin = s0;
}else{
dmin = d1;
smin = s1;
}
}
}
*st = smin;
lsx_debug_more("kmin %d, smin %5d, ",kmin,smin);
AdpcmMashS(ch, chans, v, lsx_ms_adpcm_i_coef[kmin], ip, n, st, obuff);
obuff[ch] = kmin;
}
void lsx_ms_adpcm_block_mash_i(
unsigned chans, /* total channels */
const SAMPL *ip, /* ip[n*chans] is interleaved input samples */
int n, /* samples to encode PER channel */
int *st, /* input/output steps, 16<=st[i] */
unsigned char *obuff, /* output buffer[blockAlign] */
int blockAlign /* >= 7*chans + chans*(n-2)/2.0 */
)
{
unsigned ch;
unsigned char *p;
lsx_debug_more("AdpcmMashI(chans %d, ip %p, n %d, st %p, obuff %p, bA %d)\n",
chans, (void *)ip, n, (void *)st, obuff, blockAlign);
for (p=obuff+7*chans; p<obuff+blockAlign; p++) *p=0;
for (ch=0; ch<chans; ch++)
AdpcmMashChannel(ch, chans, ip, n, st+ch, obuff);
}
/*
* lsx_ms_adpcm_samples_in(dataLen, chans, blockAlign, samplesPerBlock)
* returns the number of samples/channel which would be
* in the dataLen, given the other parameters ...
* if input samplesPerBlock is 0, then returns the max
* samplesPerBlock which would go into a block of size blockAlign
* Yes, it is confusing usage.
*/
size_t lsx_ms_adpcm_samples_in(
size_t dataLen,
size_t chans,
size_t blockAlign,
size_t samplesPerBlock
){
size_t m, n;
if (samplesPerBlock) {
n = (dataLen / blockAlign) * samplesPerBlock;
m = (dataLen % blockAlign);
} else {
n = 0;
m = blockAlign;
}
if (m >= (size_t)(7*chans)) {
m -= 7*chans; /* bytes beyond block-header */
m = (2*m)/chans + 2; /* nibbles/chans + 2 in header */
if (samplesPerBlock && m > samplesPerBlock) m = samplesPerBlock;
n += m;
}
return n;
}
size_t lsx_ms_adpcm_bytes_per_block(
size_t chans,
size_t samplesPerBlock
)
{
size_t n;
n = 7*chans; /* header */
if (samplesPerBlock > 2)
n += (((size_t)samplesPerBlock-2)*chans + 1)/2;
return n;
}

@ -0,0 +1,79 @@
/* adpcm.h codex functions for MS_ADPCM data
* (hopefully) provides interoperability with
* Microsoft's ADPCM format, but, as usual,
* see LACK-OF-WARRANTY information below.
*
* Copyright (C) 1999 Stanley J. Brooks <stabro@megsinet.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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "sox.h"
#ifndef SAMPL
#define SAMPL short
#endif
/* default coef sets */
extern const short lsx_ms_adpcm_i_coef[7][2];
extern void *lsx_ms_adpcm_alloc(unsigned chans);
/* lsx_ms_adpcm_block_expand_i() outputs interleaved samples into one output buffer */
extern const char *lsx_ms_adpcm_block_expand_i(
void *priv,
unsigned chans, /* total channels */
int nCoef,
const short *coef,
const unsigned char *ibuff,/* input buffer[blockAlign] */
SAMPL *obuff, /* output samples, n*chans */
int n /* samples to decode PER channel, REQUIRE n % 8 == 1 */
);
extern void lsx_ms_adpcm_block_mash_i(
unsigned chans, /* total channels */
const SAMPL *ip, /* ip[n*chans] is interleaved input samples */
int n, /* samples to encode PER channel, REQUIRE */
int *st, /* input/output steps, 16<=st[i] */
unsigned char *obuff, /* output buffer[blockAlign] */
int blockAlign /* >= 7*chans + n/2 */
);
/* Some helper functions for computing samples/block and blockalign */
/*
* lsx_ms_adpcm_samples_in(dataLen, chans, blockAlign, samplesPerBlock)
* returns the number of samples/channel which would be
* in the dataLen, given the other parameters ...
* if input samplesPerBlock is 0, then returns the max
* samplesPerBlock which would go into a block of size blockAlign
* Yes, it is confusing usage.
*/
extern size_t lsx_ms_adpcm_samples_in(
size_t dataLen,
size_t chans,
size_t blockAlign,
size_t samplesPerBlock
);
/*
* size_t lsx_ms_adpcm_bytes_per_block(chans, samplesPerBlock)
* return minimum blocksize which would be required
* to encode number of chans with given samplesPerBlock
*/
extern size_t lsx_ms_adpcm_bytes_per_block(
size_t chans,
size_t samplesPerBlock
);

@ -0,0 +1,322 @@
/* libSoX ADPCM codecs: IMA, OKI, CL. (c) 2007-8 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
#include "adpcms.h"
static int const ima_steps[89] = { /* ~16-bit precision; 4 bit code */
7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230,
253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963,
1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327,
3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442,
11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
32767};
static int const oki_steps[49] = { /* ~12-bit precision; 4 bit code */
256, 272, 304, 336, 368, 400, 448, 496, 544, 592, 656, 720, 800, 880, 960,
1056, 1168, 1280, 1408, 1552, 1712, 1888, 2080, 2288, 2512, 2768, 3040, 3344,
3680, 4048, 4464, 4912, 5392, 5936, 6528, 7184, 7904, 8704, 9568, 10528,
11584, 12736, 14016, 15408, 16960, 18656, 20512, 22576, 24832};
static int const step_changes[8] = {-1, -1, -1, -1, 2, 4, 6, 8};
/* Creative Labs ~8 bit precision; 4, 3, & 2 bit codes: */
static int const cl4_steps[4] = {0x100, 0x200, 0x400, 0x800};
static int const cl4_changes[8] = {-1, 0, 0, 0, 0, 1, 1, 1};
static int const cl3_steps[5] = {0x100, 0x200, 0x400, 0x800, 0xA00};
static int const cl3_changes[4] = {-1, 0, 0, 1};
static int const cl2_steps[6] = {0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000};
static int const cl2_changes[2] = {-1, 1};
static adpcm_setup_t const setup_table[] = {
{88, 8, 2, ima_steps, step_changes, ~0},
{48, 8, 2, oki_steps, step_changes, ~15},
{ 3, 8, 0, cl4_steps, cl4_changes , ~255},
{ 4, 4, 0, cl3_steps, cl3_changes , ~255},
{ 5, 2, 0, cl2_steps, cl2_changes , ~255},
};
void lsx_adpcm_init(adpcm_t * p, int type, int first_sample)
{
p->setup = setup_table[type];
p->last_output = first_sample;
p->step_index = 0;
p->errors = 0;
}
#define min_sample -0x8000
#define max_sample 0x7fff
int lsx_adpcm_decode(int code, adpcm_t * p)
{
int s = ((code & (p->setup.sign - 1)) << 1) | 1;
s = ((p->setup.steps[p->step_index] * s) >> (p->setup.shift + 1)) & p->setup.mask;
if (code & p->setup.sign)
s = -s;
s += p->last_output;
if (s < min_sample || s > max_sample) {
int grace = (p->setup.steps[p->step_index] >> (p->setup.shift + 1)) & p->setup.mask;
if (s < min_sample - grace || s > max_sample + grace) {
lsx_debug_most("code=%i step=%i grace=%i s=%i",
code & (2 * p->setup.sign - 1), p->setup.steps[p->step_index], grace, s);
p->errors++;
}
s = s < min_sample? min_sample : max_sample;
}
p->step_index += p->setup.changes[code & (p->setup.sign - 1)];
p->step_index = range_limit(p->step_index, 0, p->setup.max_step_index);
return p->last_output = s;
}
int lsx_adpcm_encode(int sample, adpcm_t * p)
{
int delta = sample - p->last_output;
int sign = 0;
int code;
if (delta < 0) {
sign = p->setup.sign;
delta = -delta;
}
code = (delta << p->setup.shift) / p->setup.steps[p->step_index];
code = sign | min(code, p->setup.sign - 1);
lsx_adpcm_decode(code, p); /* Update encoder state */
return code;
}
/*
* Format methods
*
* Almost like the raw format functions, but cannot be used directly
* since they require an additional state parameter.
*/
/******************************************************************************
* Function : lsx_adpcm_reset
* Description: Resets the ADPCM codec state.
* Parameters : state - ADPCM state structure
* type - SOX_ENCODING_OKI_ADPCM or SOX_ENCODING_IMA_ADPCM
* Returns :
* Exceptions :
* Notes : 1. This function is used for framed ADPCM formats to reset
* the decoder between frames.
******************************************************************************/
void lsx_adpcm_reset(adpcm_io_t * state, sox_encoding_t type)
{
state->file.count = 0;
state->file.pos = 0;
state->store.byte = 0;
state->store.flag = 0;
lsx_adpcm_init(&state->encoder, (type == SOX_ENCODING_OKI_ADPCM) ? 1 : 0, 0);
}
/******************************************************************************
* Function : lsx_adpcm_start
* Description: Initialises the file parameters and ADPCM codec state.
* Parameters : ft - file info structure
* state - ADPCM state structure
* type - SOX_ENCODING_OKI_ADPCM or SOX_ENCODING_IMA_ADPCM
* Returns : int - SOX_SUCCESS
* SOX_EOF
* Exceptions :
* Notes : 1. This function can be used as a startread or
* startwrite method.
* 2. VOX file format is 4-bit OKI ADPCM that decodes to
* to 12 bit signed linear PCM.
* 3. Dialogic only supports 6kHz, 8kHz and 11 kHz sampling
* rates but the codecs allows any user specified rate.
******************************************************************************/
static int adpcm_start(sox_format_t * ft, adpcm_io_t * state, sox_encoding_t type)
{
/* setup file info */
state->file.buf = lsx_malloc(sox_globals.bufsiz);
state->file.size = sox_globals.bufsiz;
ft->signal.channels = 1;
lsx_adpcm_reset(state, type);
return lsx_rawstart(ft, sox_true, sox_false, sox_true, type, 4);
}
int lsx_adpcm_oki_start(sox_format_t * ft, adpcm_io_t * state)
{
return adpcm_start(ft, state, SOX_ENCODING_OKI_ADPCM);
}
int lsx_adpcm_ima_start(sox_format_t * ft, adpcm_io_t * state)
{
return adpcm_start(ft, state, SOX_ENCODING_IMA_ADPCM);
}
/******************************************************************************
* Function : lsx_adpcm_read
* Description: Converts the OKI ADPCM 4-bit samples to 16-bit signed PCM and
* then scales the samples to full sox_sample_t range.
* Parameters : ft - file info structure
* state - ADPCM state structure
* buffer - output buffer
* len - size of output buffer
* Returns : - number of samples returned in buffer
* Exceptions :
* Notes :
******************************************************************************/
size_t lsx_adpcm_read(sox_format_t * ft, adpcm_io_t * state, sox_sample_t * buffer, size_t len)
{
size_t n = 0;
uint8_t byte;
int16_t word;
if (len && state->store.flag) {
word = lsx_adpcm_decode(state->store.byte, &state->encoder);
*buffer++ = SOX_SIGNED_16BIT_TO_SAMPLE(word, ft->clips);
state->store.flag = 0;
++n;
}
while (n < len && lsx_read_b_buf(ft, &byte, (size_t) 1) == 1) {
word = lsx_adpcm_decode(byte >> 4, &state->encoder);
*buffer++ = SOX_SIGNED_16BIT_TO_SAMPLE(word, ft->clips);
if (++n < len) {
word = lsx_adpcm_decode(byte, &state->encoder);
*buffer++ = SOX_SIGNED_16BIT_TO_SAMPLE(word, ft->clips);
++n;
} else {
state->store.byte = byte;
state->store.flag = 1;
}
}
return n;
}
/******************************************************************************
* Function : stopread
* Description: Frees the internal buffer allocated in voxstart/imastart.
* Parameters : ft - file info structure
* state - ADPCM state structure
* Returns : int - SOX_SUCCESS
* Exceptions :
* Notes :
******************************************************************************/
int lsx_adpcm_stopread(sox_format_t * ft UNUSED, adpcm_io_t * state)
{
if (state->encoder.errors)
lsx_warn("%s: ADPCM state errors: %u", ft->filename, state->encoder.errors);
free(state->file.buf);
return (SOX_SUCCESS);
}
/******************************************************************************
* Function : write
* Description: Converts the supplied buffer to 12 bit linear PCM and encodes
* to OKI ADPCM 4-bit samples (packed a two nibbles per byte).
* Parameters : ft - file info structure
* state - ADPCM state structure
* buffer - output buffer
* length - size of output buffer
* Returns : int - SOX_SUCCESS
* SOX_EOF
* Exceptions :
* Notes :
******************************************************************************/
size_t lsx_adpcm_write(sox_format_t * ft, adpcm_io_t * state, const sox_sample_t * buffer, size_t length)
{
size_t count = 0;
uint8_t byte = state->store.byte;
uint8_t flag = state->store.flag;
short word;
while (count < length) {
SOX_SAMPLE_LOCALS;
word = SOX_SAMPLE_TO_SIGNED_16BIT(*buffer++, ft->clips);
byte <<= 4;
byte |= lsx_adpcm_encode(word, &state->encoder) & 0x0F;
flag = !flag;
if (flag == 0) {
state->file.buf[state->file.count++] = byte;
if (state->file.count >= state->file.size) {
lsx_writebuf(ft, state->file.buf, state->file.count);
state->file.count = 0;
}
}
count++;
}
/* keep last byte across calls */
state->store.byte = byte;
state->store.flag = flag;
return (count);
}
/******************************************************************************
* Function : lsx_adpcm_flush
* Description: Flushes any leftover samples.
* Parameters : ft - file info structure
* state - ADPCM state structure
* Returns :
* Exceptions :
* Notes : 1. Called directly for writing framed formats
******************************************************************************/
void lsx_adpcm_flush(sox_format_t * ft, adpcm_io_t * state)
{
uint8_t byte = state->store.byte;
uint8_t flag = state->store.flag;
/* flush remaining samples */
if (flag != 0) {
byte <<= 4;
state->file.buf[state->file.count++] = byte;
}
if (state->file.count > 0)
lsx_writebuf(ft, state->file.buf, state->file.count);
}
/******************************************************************************
* Function : lsx_adpcm_stopwrite
* Description: Flushes any leftover samples and frees the internal buffer
* allocated in voxstart/imastart.
* Parameters : ft - file info structure
* state - ADPCM state structure
* Returns : int - SOX_SUCCESS
* Exceptions :
* Notes :
******************************************************************************/
int lsx_adpcm_stopwrite(sox_format_t * ft, adpcm_io_t * state)
{
lsx_adpcm_flush(ft, state);
free(state->file.buf);
return (SOX_SUCCESS);
}

@ -0,0 +1,55 @@
/* libSoX ADPCM codecs: IMA, OKI, CL. (c) 2007-8 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
typedef struct {
int max_step_index;
int sign;
int shift;
int const * steps;
int const * changes;
int mask;
} adpcm_setup_t;
typedef struct {
adpcm_setup_t setup;
int last_output;
int step_index;
int errors;
} adpcm_t;
void lsx_adpcm_init(adpcm_t * p, int type, int first_sample);
int lsx_adpcm_decode(int code, adpcm_t * p);
int lsx_adpcm_encode(int sample, adpcm_t * p);
typedef struct {
adpcm_t encoder;
struct {
uint8_t byte; /* write store */
uint8_t flag;
} store;
sox_fileinfo_t file;
} adpcm_io_t;
/* Format methods */
void lsx_adpcm_reset(adpcm_io_t * state, sox_encoding_t type);
int lsx_adpcm_oki_start(sox_format_t * ft, adpcm_io_t * state);
int lsx_adpcm_ima_start(sox_format_t * ft, adpcm_io_t * state);
size_t lsx_adpcm_read(sox_format_t * ft, adpcm_io_t * state, sox_sample_t *buffer, size_t len);
int lsx_adpcm_stopread(sox_format_t * ft, adpcm_io_t * state);
size_t lsx_adpcm_write(sox_format_t * ft, adpcm_io_t * state, const sox_sample_t *buffer, size_t length);
void lsx_adpcm_flush(sox_format_t * ft, adpcm_io_t * state);
int lsx_adpcm_stopwrite(sox_format_t * ft, adpcm_io_t * state);

@ -0,0 +1,36 @@
/* File format: AIFF-C (see aiff.c) (c) 2007-8 SoX contributors
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
#include "aiff.h"
LSX_FORMAT_HANDLER(aifc)
{
static char const * const names[] = {"aifc", "aiffc", NULL};
static unsigned const write_encodings[] = {
SOX_ENCODING_SIGN2, 32, 24, 16, 8, 0,
SOX_ENCODING_FLOAT, 32, 64, 0,
0};
static sox_format_handler_t const sox_aifc_format = {SOX_LIB_VERSION_CODE,
"AIFF-C (not compressed), defined in DAVIC 1.4 Part 9 Annex B",
names, SOX_FILE_BIG_END,
lsx_aiffstartread, lsx_rawread, lsx_aiffstopread,
lsx_aifcstartwrite, lsx_rawwrite, lsx_aifcstopwrite,
lsx_rawseek, write_encodings, NULL, 0
};
return &sox_aifc_format;
}

@ -0,0 +1,33 @@
/* File format: AIFF (see aiff.c) (c) 2007-8 SoX contributors
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
#include "aiff.h"
LSX_FORMAT_HANDLER(aiff)
{
static char const * const names[] = {"aiff", "aif", NULL};
static unsigned const write_encodings[] = {
SOX_ENCODING_SIGN2, 32, 24, 16, 8, 0, 0};
static sox_format_handler_t const sox_aiff_format = {SOX_LIB_VERSION_CODE,
"AIFF files used on Apple IIc/IIgs and SGI", names, SOX_FILE_BIG_END,
lsx_aiffstartread, lsx_rawread, lsx_aiffstopread,
lsx_aiffstartwrite, lsx_rawwrite, lsx_aiffstopwrite,
lsx_rawseek, write_encodings, NULL, 0
};
return &sox_aiff_format;
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,22 @@
/* libSoX SGI/Amiga AIFF format.
* Copyright 1991-2007 Guido van Rossum And Sundry Contributors
*
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
* Guido van Rossum And Sundry Contributors are not responsible for
* the consequences of using this software.
*
* Used by SGI on 4D/35 and Indigo.
* This is a subformat of the EA-IFF-85 format.
* This is related to the IFF format used by the Amiga.
* But, apparently, not the same.
* Also AIFF-C format output that is defined in DAVIC 1.4 Part 9 Annex B
* (usable for japanese-data-broadcasting, specified by ARIB STD-B24.)
*/
int lsx_aiffstartread(sox_format_t * ft);
int lsx_aiffstopread(sox_format_t * ft);
int lsx_aiffstartwrite(sox_format_t * ft);
int lsx_aiffstopwrite(sox_format_t * ft);
int lsx_aifcstartwrite(sox_format_t * ft);
int lsx_aifcstopwrite(sox_format_t * ft);

@ -0,0 +1,21 @@
/* File format: raw A-law (c) 2007-8 SoX contributors
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
#include "raw.h"
RAW_FORMAT(al, 8, 0, ALAW)

@ -0,0 +1,379 @@
/* libSoX device driver: ALSA (c) 2006-2012 SoX contributors
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
#include <alsa/asoundlib.h>
typedef struct {
snd_pcm_uframes_t buf_len, period;
snd_pcm_t * pcm;
char * buf;
unsigned int format;
} priv_t;
static const
struct {
unsigned int bits;
enum _snd_pcm_format alsa_fmt;
unsigned int bytes; /* occupied in the buffer per sample */
sox_encoding_t enc;
} formats[] = {
/* order by # of bits; within that, preferred first */
{ 8, SND_PCM_FORMAT_S8, 1, SOX_ENCODING_SIGN2 },
{ 8, SND_PCM_FORMAT_U8, 1, SOX_ENCODING_UNSIGNED },
{ 16, SND_PCM_FORMAT_S16, 2, SOX_ENCODING_SIGN2 },
{ 16, SND_PCM_FORMAT_U16, 2, SOX_ENCODING_UNSIGNED },
{ 24, SND_PCM_FORMAT_S24, 4, SOX_ENCODING_SIGN2 },
{ 24, SND_PCM_FORMAT_U24, 4, SOX_ENCODING_UNSIGNED },
{ 24, SND_PCM_FORMAT_S24_3LE, 3, SOX_ENCODING_SIGN2 },
{ 32, SND_PCM_FORMAT_S32, 4, SOX_ENCODING_SIGN2 },
{ 32, SND_PCM_FORMAT_U32, 4, SOX_ENCODING_UNSIGNED },
{ 0, 0, 0, SOX_ENCODING_UNKNOWN } /* end of list */
};
static int select_format(
sox_encoding_t * encoding_,
unsigned * nbits_,
snd_pcm_format_mask_t const * mask,
unsigned int * format)
{
unsigned int from = 0, to; /* NB: "to" actually points one after the last */
int cand = -1;
while (formats[from].bits < *nbits_ && formats[from].bits != 0)
from++; /* find the first entry with at least *nbits_ bits */
for (to = from; formats[to].bits != 0; to++) ; /* find end of list */
while (to > 0) {
unsigned int i, bits_next = 0;
for (i = from; i < to; i++) {
lsx_debug_most("select_format: trying #%u", i);
if (snd_pcm_format_mask_test(mask, formats[i].alsa_fmt)) {
if (formats[i].enc == *encoding_) {
cand = i;
break; /* found a match */
} else if (cand == -1) /* don't overwrite a candidate that
was earlier in the list */
cand = i; /* will work, but encoding differs */
}
}
if (cand != -1)
break;
/* no candidate found yet; now try formats with less bits: */
to = from;
if (from > 0)
bits_next = formats[from-1].bits;
while (from && formats[from-1].bits == bits_next)
from--; /* go back to the first entry with bits_next bits */
}
if (cand == -1) {
lsx_debug("select_format: no suitable ALSA format found");
return -1;
}
if (*nbits_ != formats[cand].bits || *encoding_ != formats[cand].enc) {
lsx_warn("can't encode %u-bit %s", *nbits_,
sox_encodings_info[*encoding_].desc);
*nbits_ = formats[cand].bits;
*encoding_ = formats[cand].enc;
}
lsx_debug("selecting format %d: %s (%s)", cand,
snd_pcm_format_name(formats[cand].alsa_fmt),
snd_pcm_format_description(formats[cand].alsa_fmt));
*format = cand;
return 0;
}
#define _(x,y) do {if ((err = x y) < 0) {lsx_fail_errno(ft, SOX_EPERM, #x " error: %s", snd_strerror(err)); goto error;} } while (0)
static int setup(sox_format_t * ft)
{
priv_t * p = (priv_t *)ft->priv;
snd_pcm_hw_params_t * params = NULL;
snd_pcm_format_mask_t * mask = NULL;
snd_pcm_uframes_t min, max;
unsigned n;
int err;
_(snd_pcm_open, (&p->pcm, ft->filename, ft->mode == 'r'? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, 0));
_(snd_pcm_hw_params_malloc, (&params));
_(snd_pcm_hw_params_any, (p->pcm, params));
#if SND_LIB_VERSION >= 0x010009 /* Disable alsa-lib resampling: */
_(snd_pcm_hw_params_set_rate_resample, (p->pcm, params, 0));
#endif
_(snd_pcm_hw_params_set_access, (p->pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED));
_(snd_pcm_format_mask_malloc, (&mask)); /* Set format: */
snd_pcm_hw_params_get_format_mask(params, mask);
_(select_format, (&ft->encoding.encoding, &ft->encoding.bits_per_sample, mask, &p->format));
_(snd_pcm_hw_params_set_format, (p->pcm, params, formats[p->format].alsa_fmt));
snd_pcm_format_mask_free(mask), mask = NULL;
n = ft->signal.rate; /* Set rate: */
_(snd_pcm_hw_params_set_rate_near, (p->pcm, params, &n, 0));
ft->signal.rate = n;
n = ft->signal.channels; /* Set channels: */
_(snd_pcm_hw_params_set_channels_near, (p->pcm, params, &n));
ft->signal.channels = n;
/* Get number of significant bits: */
if ((err = snd_pcm_hw_params_get_sbits(params)) > 0)
ft->signal.precision = min(err, SOX_SAMPLE_PRECISION);
else lsx_debug("snd_pcm_hw_params_get_sbits can't tell precision: %s",
snd_strerror(err));
/* Set buf_len > > sox_globals.bufsiz for no underrun: */
p->buf_len = sox_globals.bufsiz * 8 / formats[p->format].bytes /
ft->signal.channels;
_(snd_pcm_hw_params_get_buffer_size_min, (params, &min));
_(snd_pcm_hw_params_get_buffer_size_max, (params, &max));
p->period = range_limit(p->buf_len, min, max) / 8;
p->buf_len = p->period * 8;
_(snd_pcm_hw_params_set_period_size_near, (p->pcm, params, &p->period, 0));
_(snd_pcm_hw_params_set_buffer_size_near, (p->pcm, params, &p->buf_len));
if (p->period * 2 > p->buf_len) {
lsx_fail_errno(ft, SOX_EPERM, "buffer too small");
goto error;
}
_(snd_pcm_hw_params, (p->pcm, params)); /* Configure ALSA */
snd_pcm_hw_params_free(params), params = NULL;
_(snd_pcm_prepare, (p->pcm));
p->buf_len *= ft->signal.channels; /* No longer in `frames' */
p->buf = lsx_malloc(p->buf_len * formats[p->format].bytes);
return SOX_SUCCESS;
error:
if (mask) snd_pcm_format_mask_free(mask);
if (params) snd_pcm_hw_params_free(params);
return SOX_EOF;
}
static int recover(sox_format_t * ft, snd_pcm_t * pcm, int err)
{
if (err == -EPIPE)
lsx_warn("%s-run", ft->mode == 'r'? "over" : "under");
else if (err != -ESTRPIPE)
lsx_warn("%s", snd_strerror(err));
else while ((err = snd_pcm_resume(pcm)) == -EAGAIN) {
lsx_report("suspended");
sleep(1); /* Wait until the suspend flag is released */
}
if (err < 0 && (err = snd_pcm_prepare(pcm)) < 0)
lsx_fail_errno(ft, SOX_EPERM, "%s", snd_strerror(err));
return err;
}
static size_t read_(sox_format_t * ft, sox_sample_t * buf, size_t len)
{
priv_t * p = (priv_t *)ft->priv;
snd_pcm_sframes_t i, n;
size_t done;
len = min(len, p->buf_len);
for (done = 0; done < len; done += n) {
do {
n = snd_pcm_readi(p->pcm, p->buf, (len - done) / ft->signal.channels);
if (n < 0 && recover(ft, p->pcm, (int)n) < 0)
return 0;
} while (n <= 0);
i = n *= ft->signal.channels;
switch (formats[p->format].alsa_fmt) {
case SND_PCM_FORMAT_S8: {
int8_t * buf1 = (int8_t *)p->buf;
while (i--) *buf++ = SOX_SIGNED_8BIT_TO_SAMPLE(*buf1++,);
break;
}
case SND_PCM_FORMAT_U8: {
uint8_t * buf1 = (uint8_t *)p->buf;
while (i--) *buf++ = SOX_UNSIGNED_8BIT_TO_SAMPLE(*buf1++,);
break;
}
case SND_PCM_FORMAT_S16: {
int16_t * buf1 = (int16_t *)p->buf;
if (ft->encoding.reverse_bytes) while (i--)
*buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(lsx_swapw(*buf1++),);
else
while (i--) *buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(*buf1++,);
break;
}
case SND_PCM_FORMAT_U16: {
uint16_t * buf1 = (uint16_t *)p->buf;
if (ft->encoding.reverse_bytes) while (i--)
*buf++ = SOX_UNSIGNED_16BIT_TO_SAMPLE(lsx_swapw(*buf1++),);
else
while (i--) *buf++ = SOX_UNSIGNED_16BIT_TO_SAMPLE(*buf1++,);
break;
}
case SND_PCM_FORMAT_S24: {
sox_int24_t * buf1 = (sox_int24_t *)p->buf;
while (i--) *buf++ = SOX_SIGNED_24BIT_TO_SAMPLE(*buf1++,);
break;
}
case SND_PCM_FORMAT_S24_3LE: {
unsigned char *buf1 = (unsigned char *)p->buf;
while (i--) {
uint32_t temp;
temp = *buf1++;
temp |= *buf1++ << 8;
temp |= *buf1++ << 16;
*buf++ = SOX_SIGNED_24BIT_TO_SAMPLE((sox_int24_t)temp,);
}
break;
}
case SND_PCM_FORMAT_U24: {
sox_uint24_t * buf1 = (sox_uint24_t *)p->buf;
while (i--) *buf++ = SOX_UNSIGNED_24BIT_TO_SAMPLE(*buf1++,);
break;
}
case SND_PCM_FORMAT_S32: {
int32_t * buf1 = (int32_t *)p->buf;
while (i--) *buf++ = SOX_SIGNED_32BIT_TO_SAMPLE(*buf1++,);
break;
}
case SND_PCM_FORMAT_U32: {
uint32_t * buf1 = (uint32_t *)p->buf;
while (i--) *buf++ = SOX_UNSIGNED_32BIT_TO_SAMPLE(*buf1++,);
break;
}
default: lsx_fail_errno(ft, SOX_EFMT, "invalid format");
return 0;
}
}
return len;
}
static size_t write_(sox_format_t * ft, sox_sample_t const * buf, size_t len)
{
priv_t * p = (priv_t *)ft->priv;
size_t done, i, n;
snd_pcm_sframes_t actual;
SOX_SAMPLE_LOCALS;
for (done = 0; done < len; done += n) {
i = n = min(len - done, p->buf_len);
switch (formats[p->format].alsa_fmt) {
case SND_PCM_FORMAT_S8: {
int8_t * buf1 = (int8_t *)p->buf;
while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_8BIT(*buf++, ft->clips);
break;
}
case SND_PCM_FORMAT_U8: {
uint8_t * buf1 = (uint8_t *)p->buf;
while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_8BIT(*buf++, ft->clips);
break;
}
case SND_PCM_FORMAT_S16: {
int16_t * buf1 = (int16_t *)p->buf;
if (ft->encoding.reverse_bytes) while (i--)
*buf1++ = lsx_swapw(SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips));
else
while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips);
break;
}
case SND_PCM_FORMAT_U16: {
uint16_t * buf1 = (uint16_t *)p->buf;
if (ft->encoding.reverse_bytes) while (i--)
*buf1++ = lsx_swapw(SOX_SAMPLE_TO_UNSIGNED_16BIT(*buf++, ft->clips));
else
while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_16BIT(*buf++, ft->clips);
break;
}
case SND_PCM_FORMAT_S24: {
sox_int24_t * buf1 = (sox_int24_t *)p->buf;
while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_24BIT(*buf++, ft->clips);
break;
}
case SND_PCM_FORMAT_S24_3LE: {
unsigned char *buf1 = (unsigned char *)p->buf;
while (i--) {
uint32_t temp = (uint32_t)SOX_SAMPLE_TO_SIGNED_24BIT(*buf++, ft->clips);
*buf1++ = (temp & 0x000000FF);
*buf1++ = (temp & 0x0000FF00) >> 8;
*buf1++ = (temp & 0x00FF0000) >> 16;
}
break;
}
case SND_PCM_FORMAT_U24: {
sox_uint24_t * buf1 = (sox_uint24_t *)p->buf;
while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_24BIT(*buf++, ft->clips);
break;
}
case SND_PCM_FORMAT_S32: {
int32_t * buf1 = (int32_t *)p->buf;
while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_32BIT(*buf++, ft->clips);
break;
}
case SND_PCM_FORMAT_U32: {
uint32_t * buf1 = (uint32_t *)p->buf;
while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_32BIT(*buf++, ft->clips);
break;
}
default: lsx_fail_errno(ft, SOX_EFMT, "invalid format");
return 0;
}
for (i = 0; i < n; i += actual * ft->signal.channels) do {
actual = snd_pcm_writei(p->pcm,
p->buf + i * formats[p->format].bytes,
(n - i) / ft->signal.channels);
if (errno == EAGAIN) /* Happens naturally; don't report it: */
errno = 0;
if (actual < 0 && recover(ft, p->pcm, (int)actual) < 0)
return 0;
} while (actual < 0);
}
return len;
}
static int stop(sox_format_t * ft)
{
priv_t * p = (priv_t *)ft->priv;
snd_pcm_close(p->pcm);
free(p->buf);
return SOX_SUCCESS;
}
static int stop_write(sox_format_t * ft)
{
priv_t * p = (priv_t *)ft->priv;
size_t n = ft->signal.channels * p->period, npad = n - (ft->olength % n);
sox_sample_t * buf = lsx_calloc(npad, sizeof(*buf)); /* silent samples */
if (npad != n) /* pad to hardware period: */
write_(ft, buf, npad);
free(buf);
snd_pcm_drain(p->pcm);
return stop(ft);
}
LSX_FORMAT_HANDLER(alsa)
{
static char const * const names[] = {"alsa", NULL};
static unsigned const write_encodings[] = {
SOX_ENCODING_SIGN2 , 32, 24, 16, 8, 0,
SOX_ENCODING_UNSIGNED, 32, 24, 16, 8, 0,
0};
static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
"Advanced Linux Sound Architecture device driver",
names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO,
setup, read_, stop, setup, write_, stop_write,
NULL, write_encodings, NULL, sizeof(priv_t)
};
return &handler;
}

@ -0,0 +1,90 @@
/* File format: AMR-NB (c) 2007 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* In order to use the AMR format with SoX, you need to have an
* AMR library installed at SoX build time. The SoX build system
* recognizes the AMR implementations available from
* http://opencore-amr.sourceforge.net/
*/
#include "sox_i.h"
/* Common definitions: */
enum amrnb_mode { amrnb_mode_dummy };
static const unsigned amrnb_block_size[] = {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 1};
static char const amrnb_magic[] = "#!AMR\n";
#define amr_block_size amrnb_block_size
#define amr_magic amrnb_magic
#define amr_priv_t amrnb_priv_t
#define amr_opencore_funcs amrnb_opencore_funcs
#define amr_gp3_funcs amrnb_gp3_funcs
#define AMR_CODED_MAX 32 /* max coded size */
#define AMR_ENCODING SOX_ENCODING_AMR_NB
#define AMR_FORMAT_FN lsx_amr_nb_format_fn
#define AMR_FRAME 160 /* 20ms @ 8kHz */
#define AMR_MODE_MAX 7
#define AMR_NAMES "amr-nb", "anb"
#define AMR_RATE 8000
#define AMR_DESC "3GPP Adaptive Multi Rate Narrow-Band (AMR-NB) lossy speech compressor"
#ifdef DL_OPENCORE_AMRNB
#define AMR_FUNC LSX_DLENTRY_DYNAMIC
#else
#define AMR_FUNC LSX_DLENTRY_STATIC
#endif /* DL_AMRNB */
/* OpenCore definitions: */
#define AMR_OPENCORE 1
#define AMR_OPENCORE_ENABLE_ENCODE 1
#define AMR_OPENCORE_FUNC_ENTRIES(f,x) \
AMR_FUNC(f,x, void*, Encoder_Interface_init, (int dtx)) \
AMR_FUNC(f,x, int, Encoder_Interface_Encode, (void* state, enum amrnb_mode mode, const short* in, unsigned char* out, int forceSpeech)) \
AMR_FUNC(f,x, void, Encoder_Interface_exit, (void* state)) \
AMR_FUNC(f,x, void*, Decoder_Interface_init, (void)) \
AMR_FUNC(f,x, void, Decoder_Interface_Decode, (void* state, const unsigned char* in, short* out, int bfi)) \
AMR_FUNC(f,x, void, Decoder_Interface_exit, (void* state)) \
#define AmrEncoderInit() \
Encoder_Interface_init(1)
#define AmrEncoderEncode(state, mode, in, out, forceSpeech) \
Encoder_Interface_Encode(state, mode, in, out, forceSpeech)
#define AmrEncoderExit(state) \
Encoder_Interface_exit(state)
#define AmrDecoderInit() \
Decoder_Interface_init()
#define AmrDecoderDecode(state, in, out, bfi) \
Decoder_Interface_Decode(state, in, out, bfi)
#define AmrDecoderExit(state) \
Decoder_Interface_exit(state)
#define AMR_OPENCORE_DESC "amr-nb OpenCore library"
static const char* const amr_opencore_library_names[] =
{
#ifdef DL_OPENCORE_AMRNB
"libopencore-amrnb",
"libopencore-amrnb-0",
#endif
NULL
};
#include "amr.h"

@ -0,0 +1,115 @@
/* File format: AMR-WB (c) 2007 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* In order to use the AMR format with SoX, you need to have an
* AMR library installed at SoX build time. The SoX build system
* recognizes the AMR implementations available from
* http://opencore-amr.sourceforge.net/
*/
#include "sox_i.h"
/* Common definitions: */
static const uint8_t amrwb_block_size[] = {18, 24, 33, 37, 41, 47, 51, 59, 61, 6, 6, 0, 0, 0, 1, 1};
static char const amrwb_magic[] = "#!AMR-WB\n";
#define amr_block_size amrwb_block_size
#define amr_magic amrwb_magic
#define amr_priv_t amrwb_priv_t
#define amr_opencore_funcs amrwb_opencore_funcs
#define amr_vo_funcs amrwb_vo_funcs
#define AMR_CODED_MAX 61 /* NB_SERIAL_MAX */
#define AMR_ENCODING SOX_ENCODING_AMR_WB
#define AMR_FORMAT_FN lsx_amr_wb_format_fn
#define AMR_FRAME 320 /* L_FRAME16k */
#define AMR_MODE_MAX 8
#define AMR_NAMES "amr-wb", "awb"
#define AMR_RATE 16000
#define AMR_DESC "3GPP Adaptive Multi Rate Wide-Band (AMR-WB) lossy speech compressor"
/* OpenCore definitions: */
#ifdef DL_OPENCORE_AMRWB
#define AMR_OC_FUNC LSX_DLENTRY_DYNAMIC
#else
#define AMR_OC_FUNC LSX_DLENTRY_STATIC
#endif
#if defined(HAVE_OPENCORE_AMRWB_DEC_IF_H) || defined(DL_OPENCORE_AMRWB)
#define AMR_OPENCORE 1
#define AMR_OPENCORE_ENABLE_ENCODE 0
#endif
#define AMR_OPENCORE_FUNC_ENTRIES(f,x) \
AMR_OC_FUNC(f,x, void*, D_IF_init, (void)) \
AMR_OC_FUNC(f,x, void, D_IF_decode, (void* state, const unsigned char* in, short* out, int bfi)) \
AMR_OC_FUNC(f,x, void, D_IF_exit, (void* state)) \
#define AmrDecoderInit() \
D_IF_init()
#define AmrDecoderDecode(state, in, out, bfi) \
D_IF_decode(state, in, out, bfi)
#define AmrDecoderExit(state) \
D_IF_exit(state)
#define AMR_OPENCORE_DESC "amr-wb OpenCore library"
static const char* const amr_opencore_library_names[] =
{
#ifdef DL_OPENCORE_AMRWB
"libopencore-amrwb",
"libopencore-amrwb-0",
#endif
NULL
};
/* VO definitions: */
#ifdef DL_VO_AMRWBENC
#define AMR_VO_FUNC LSX_DLENTRY_DYNAMIC
#else
#define AMR_VO_FUNC LSX_DLENTRY_STATIC
#endif
#if defined(HAVE_VO_AMRWBENC_ENC_IF_H) || defined(DL_VO_AMRWBENC)
#define AMR_VO 1
#endif
#define AMR_VO_FUNC_ENTRIES(f,x) \
AMR_VO_FUNC(f,x, void*, E_IF_init, (void)) \
AMR_VO_FUNC(f,x, int, E_IF_encode,(void* state, int16_t mode, int16_t* in, uint8_t* out, int16_t dtx)) \
AMR_VO_FUNC(f,x, void, E_IF_exit, (void* state)) \
#define AmrEncoderInit() \
E_IF_init()
#define AmrEncoderEncode(state, mode, in, out, forceSpeech) \
E_IF_encode(state, mode, in, out, forceSpeech)
#define AmrEncoderExit(state) \
E_IF_exit(state)
#define AMR_VO_DESC "amr-wb VisualOn library"
static const char* const amr_vo_library_names[] =
{
#ifdef DL_VO_AMRWBENC
"libvo-amrwbenc",
"libvo-amrwbenc-0",
#endif
NULL
};
#include "amr.h"

@ -0,0 +1,335 @@
/* File format: AMR (c) 2007 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
#include <math.h>
#ifdef AMR_OPENCORE
LSX_DLENTRIES_TO_FUNCTIONS(AMR_OPENCORE_FUNC_ENTRIES)
typedef struct amr_opencore_funcs {
LSX_DLENTRIES_TO_PTRS(AMR_OPENCORE_FUNC_ENTRIES, amr_dl);
} amr_opencore_funcs;
#endif /* AMR_OPENCORE */
#ifdef AMR_VO
LSX_DLENTRIES_TO_FUNCTIONS(AMR_VO_FUNC_ENTRIES)
typedef struct amr_vo_funcs {
LSX_DLENTRIES_TO_PTRS(AMR_VO_FUNC_ENTRIES, amr_dl);
} amr_vo_funcs;
#endif /* AMR_VO */
#define AMR_CALL(p, func, args) ((p)->opencore.func args)
#ifdef AMR_VO
#define AMR_CALL_ENCODER(p, func, args) ((p)->vo.func args)
#else
#define AMR_CALL_ENCODER(p, func, args) ((p)->opencore.func args)
#endif
typedef struct amr_priv_t {
void* state;
unsigned mode;
size_t pcm_index;
#ifdef AMR_OPENCORE
amr_opencore_funcs opencore;
#endif /* AMR_OPENCORE */
#ifdef AMR_VO
amr_vo_funcs vo;
#endif /* AMR_VO */
short pcm[AMR_FRAME];
} priv_t;
#ifdef AMR_OPENCORE
static size_t decode_1_frame(sox_format_t * ft)
{
priv_t * p = (priv_t *)ft->priv;
size_t n;
uint8_t coded[AMR_CODED_MAX];
if (lsx_readbuf(ft, &coded[0], (size_t)1) != 1)
return AMR_FRAME;
n = amr_block_size[(coded[0] >> 3) & 0x0F];
if (!n) {
lsx_fail("invalid block type");
return AMR_FRAME;
}
n--;
if (lsx_readbuf(ft, &coded[1], n) != n)
return AMR_FRAME;
AMR_CALL(p, AmrDecoderDecode, (p->state, coded, p->pcm, 0));
return 0;
}
#endif
static int openlibrary(priv_t* p, int encoding)
{
int open_library_result;
(void)encoding;
#ifdef AMR_OPENCORE
if (AMR_OPENCORE_ENABLE_ENCODE || !encoding)
{
LSX_DLLIBRARY_TRYOPEN(
0,
&p->opencore,
amr_dl,
AMR_OPENCORE_FUNC_ENTRIES,
AMR_OPENCORE_DESC,
amr_opencore_library_names,
open_library_result);
if (!open_library_result)
return SOX_SUCCESS;
lsx_fail("Unable to open " AMR_OPENCORE_DESC);
return SOX_EOF;
}
#endif /* AMR_OPENCORE */
#ifdef AMR_VO
if (encoding) {
LSX_DLLIBRARY_TRYOPEN(
0,
&p->vo,
amr_dl,
AMR_VO_FUNC_ENTRIES,
AMR_VO_DESC,
amr_vo_library_names,
open_library_result);
if (!open_library_result)
return SOX_SUCCESS;
lsx_fail("Unable to open " AMR_VO_DESC);
}
#endif /* AMR_VO */
return SOX_EOF;
}
static void closelibrary(priv_t* p)
{
#ifdef AMR_OPENCORE
LSX_DLLIBRARY_CLOSE(&p->opencore, amr_dl);
#endif
#ifdef AMR_VO
LSX_DLLIBRARY_CLOSE(&p->vo, amr_dl);
#endif
}
#ifdef AMR_OPENCORE
static size_t amr_duration_frames(sox_format_t * ft)
{
off_t frame_size, data_start_offset = lsx_tell(ft);
size_t frames;
uint8_t coded;
for (frames = 0; lsx_readbuf(ft, &coded, (size_t)1) == 1; ++frames) {
frame_size = amr_block_size[coded >> 3 & 15];
if (!frame_size) {
lsx_fail("invalid block type");
break;
}
if (lsx_seeki(ft, frame_size - 1, SEEK_CUR)) {
lsx_fail("seek");
break;
}
}
lsx_debug("frames=%lu", (unsigned long)frames);
lsx_seeki(ft, data_start_offset, SEEK_SET);
return frames;
}
#endif
static int startread(sox_format_t * ft)
{
#if !defined(AMR_OPENCORE)
lsx_fail_errno(ft, SOX_EOF, "SoX was compiled without AMR-WB decoding support.");
return SOX_EOF;
#else
priv_t * p = (priv_t *)ft->priv;
char buffer[sizeof(amr_magic) - 1];
int open_library_result;
if (lsx_readchars(ft, buffer, sizeof(buffer)))
return SOX_EOF;
if (memcmp(buffer, amr_magic, sizeof(buffer))) {
lsx_fail_errno(ft, SOX_EHDR, "invalid magic number");
return SOX_EOF;
}
open_library_result = openlibrary(p, 0);
if (open_library_result != SOX_SUCCESS)
return open_library_result;
p->pcm_index = AMR_FRAME;
p->state = AMR_CALL(p, AmrDecoderInit, ());
if (!p->state)
{
closelibrary(p);
lsx_fail("AMR decoder failed to initialize.");
return SOX_EOF;
}
ft->signal.rate = AMR_RATE;
ft->encoding.encoding = AMR_ENCODING;
ft->signal.channels = 1;
ft->signal.length = ft->signal.length != SOX_IGNORE_LENGTH && ft->seekable?
(size_t)(amr_duration_frames(ft) * .02 * ft->signal.rate +.5) : SOX_UNSPEC;
return SOX_SUCCESS;
#endif
}
#ifdef AMR_OPENCORE
static size_t read_samples(sox_format_t * ft, sox_sample_t * buf, size_t len)
{
priv_t * p = (priv_t *)ft->priv;
size_t done;
for (done = 0; done < len; done++) {
if (p->pcm_index >= AMR_FRAME)
p->pcm_index = decode_1_frame(ft);
if (p->pcm_index >= AMR_FRAME)
break;
*buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(p->pcm[p->pcm_index++], ft->clips);
}
return done;
}
static int stopread(sox_format_t * ft)
{
priv_t * p = (priv_t *)ft->priv;
AMR_CALL(p, AmrDecoderExit, (p->state));
closelibrary(p);
return SOX_SUCCESS;
}
#else
#define read_samples NULL
#define stopread NULL
#endif
static int startwrite(sox_format_t * ft)
{
#if !defined(AMR_VO) && !AMR_OPENCORE_ENABLE_ENCODE
lsx_fail_errno(ft, SOX_EOF, "SoX was compiled without AMR-WB encoding support.");
return SOX_EOF;
#else
priv_t * p = (priv_t *)ft->priv;
int open_library_result;
if (ft->encoding.compression != HUGE_VAL) {
p->mode = (unsigned)ft->encoding.compression;
if (p->mode != ft->encoding.compression || p->mode > AMR_MODE_MAX) {
lsx_fail_errno(ft, SOX_EINVAL, "compression level must be a whole number from 0 to %i", AMR_MODE_MAX);
return SOX_EOF;
}
}
else p->mode = 0;
open_library_result = openlibrary(p, 1);
if (open_library_result != SOX_SUCCESS)
return open_library_result;
p->state = AMR_CALL_ENCODER(p, AmrEncoderInit, ());
if (!p->state)
{
closelibrary(p);
lsx_fail("AMR encoder failed to initialize.");
return SOX_EOF;
}
lsx_writes(ft, amr_magic);
p->pcm_index = 0;
return SOX_SUCCESS;
#endif
}
#if defined(AMR_VO) || AMR_OPENCORE_ENABLE_ENCODE
static sox_bool encode_1_frame(sox_format_t * ft)
{
priv_t * p = (priv_t *)ft->priv;
uint8_t coded[AMR_CODED_MAX];
int n = AMR_CALL_ENCODER(p, AmrEncoderEncode, (p->state, p->mode, p->pcm, coded, 1));
sox_bool result = lsx_writebuf(ft, coded, (size_t) (size_t) (unsigned)n) == (unsigned)n;
if (!result)
lsx_fail_errno(ft, errno, "write error");
return result;
}
static size_t write_samples(sox_format_t * ft, const sox_sample_t * buf, size_t len)
{
priv_t * p = (priv_t *)ft->priv;
size_t done;
for (done = 0; done < len; ++done) {
SOX_SAMPLE_LOCALS;
p->pcm[p->pcm_index++] = SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips);
if (p->pcm_index == AMR_FRAME) {
p->pcm_index = 0;
if (!encode_1_frame(ft))
return 0;
}
}
return done;
}
static int stopwrite(sox_format_t * ft)
{
priv_t * p = (priv_t *)ft->priv;
int result = SOX_SUCCESS;
if (p->pcm_index) {
do {
p->pcm[p->pcm_index++] = 0;
} while (p->pcm_index < AMR_FRAME);
if (!encode_1_frame(ft))
result = SOX_EOF;
}
AMR_CALL_ENCODER(p, AmrEncoderExit, (p->state));
return result;
}
#else
#define write_samples NULL
#define stopwrite NULL
#endif /* defined(AMR_VO) || AMR_OPENCORE_ENABLE_ENCODE */
sox_format_handler_t const * AMR_FORMAT_FN(void);
sox_format_handler_t const * AMR_FORMAT_FN(void)
{
static char const * const names[] = {AMR_NAMES, NULL};
static sox_rate_t const write_rates[] = {AMR_RATE, 0};
static unsigned const write_encodings[] = {AMR_ENCODING, 0, 0};
static sox_format_handler_t handler = {
SOX_LIB_VERSION_CODE,
AMR_DESC,
names, SOX_FILE_MONO,
startread, read_samples, stopread,
startwrite, write_samples, stopwrite,
NULL, write_encodings, write_rates, sizeof(priv_t)
};
return &handler;
}

@ -0,0 +1,134 @@
/* libao player support for sox
* (c) Reuben Thomas <rrt@sc3d.org> 2007
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ao/ao.h>
typedef struct {
int driver_id;
ao_device *device;
ao_sample_format format;
char *buf;
size_t buf_size;
} priv_t;
static int startwrite(sox_format_t * ft)
{
priv_t * ao = (priv_t *)ft->priv;
ao->buf_size = sox_globals.bufsiz - (sox_globals.bufsiz % (ft->encoding.bits_per_sample >> 3));
ao->buf_size *= (ft->encoding.bits_per_sample >> 3);
ao->buf = lsx_malloc(ao->buf_size);
if (!ao->buf)
{
lsx_fail_errno(ft, SOX_ENOMEM, "Can not allocate memory for ao driver");
return SOX_EOF;
}
ao_initialize();
if (strcmp(ft->filename,"default") == 0)
{
if ((ao->driver_id = ao_default_driver_id()) < 0) {
lsx_fail("Could not find a default ao driver");
return SOX_EOF;
}
}
else
{
if ((ao->driver_id = ao_driver_id(ft->filename)) < 0) {
lsx_fail("Could not find a ao driver %s", ft->filename);
return SOX_EOF;
}
}
ao->format.bits = ft->encoding.bits_per_sample;
ao->format.rate = ft->signal.rate;
ao->format.channels = ft->signal.channels;
ao->format.byte_format = AO_FMT_NATIVE;
if ((ao->device = ao_open_live(ao->driver_id, &ao->format, NULL)) == NULL) {
lsx_fail("Could not open device: error %d", errno);
return SOX_EOF;
}
return SOX_SUCCESS;
}
static void sox_sw_write_buf(char *buf1, sox_sample_t const * buf2, size_t len, sox_bool swap, sox_uint64_t * clips)
{
while (len--)
{
SOX_SAMPLE_LOCALS;
uint16_t datum = SOX_SAMPLE_TO_SIGNED_16BIT(*buf2++, *clips);
if (swap)
datum = lsx_swapw(datum);
*(uint16_t *)buf1 = datum;
buf1++; buf1++;
}
}
static size_t write_samples(sox_format_t *ft, const sox_sample_t *buf, size_t len)
{
priv_t * ao = (priv_t *)ft->priv;
uint_32 aobuf_size;
if (len > ao->buf_size / (ft->encoding.bits_per_sample >> 3))
len = ao->buf_size / (ft->encoding.bits_per_sample >> 3);
aobuf_size = (ft->encoding.bits_per_sample >> 3) * len;
sox_sw_write_buf(ao->buf, buf, len, ft->encoding.reverse_bytes,
&(ft->clips));
if (ao_play(ao->device, (void *)ao->buf, aobuf_size) == 0)
return 0;
return len;
}
static int stopwrite(sox_format_t * ft)
{
priv_t * ao = (priv_t *)ft->priv;
free(ao->buf);
if (ao_close(ao->device) == 0) {
lsx_fail("Error closing libao output");
return SOX_EOF;
}
ao_shutdown();
return SOX_SUCCESS;
}
LSX_FORMAT_HANDLER(ao)
{
static char const * const names[] = {"ao", NULL};
static unsigned const encodings[] = {SOX_ENCODING_SIGN2, 16, 0, 0};
static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
"Xiph's libao device driver", names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO,
NULL, NULL, NULL,
startwrite, write_samples, stopwrite,
NULL, encodings, NULL, sizeof(priv_t)
};
return &handler;
}

@ -0,0 +1,237 @@
/* libSoX Sun format with header (SunOS 4.1; see /usr/demo/SOUND).
* Copyright 1991, 1992, 1993 Guido van Rossum And Sundry Contributors.
*
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
* Guido van Rossum And Sundry Contributors are not responsible for
* the consequences of using this software.
*
* October 7, 1998 - cbagwell@sprynet.com
* G.723 was using incorrect # of bits. Corrected to 3 and 5 bits.
*
* NeXT uses this format also, but has more format codes defined.
* DEC uses a slight variation and swaps bytes.
* We support only the common formats, plus
* CCITT G.721 (32 kbit/s) and G.723 (24/40 kbit/s),
* courtesy of Sun's public domain implementation.
*/
#include "sox_i.h"
#include "g72x.h"
#include <string.h>
/* Magic numbers used in Sun and NeXT audio files */
static struct {char str[4]; sox_bool reverse_bytes; char const * desc;} id[] = {
{"\x2e\x73\x6e\x64", MACHINE_IS_LITTLEENDIAN, "big-endian `.snd'"},
{"\x64\x6e\x73\x2e", MACHINE_IS_BIGENDIAN , "little-endian `.snd'"},
{"\x00\x64\x73\x2e", MACHINE_IS_BIGENDIAN , "little-endian `\\0ds.' (for DEC)"},
{"\x2e\x73\x64\x00", MACHINE_IS_LITTLEENDIAN, "big-endian `\\0ds.'"},
{" ", 0, NULL}
};
#define FIXED_HDR 24
#define SUN_UNSPEC ~0u /* Unspecified data size (this is legal) */
typedef enum {
Unspecified, Mulaw_8, Linear_8, Linear_16, Linear_24, Linear_32, Float,
Double, Indirect, Nested, Dsp_core, Dsp_data_8, Dsp_data_16, Dsp_data_24,
Dsp_data_32, Unknown, Display, Mulaw_squelch, Emphasized, Compressed,
Compressed_emphasized, Dsp_commands, Dsp_commands_samples, Adpcm_g721,
Adpcm_g722, Adpcm_g723_3, Adpcm_g723_5, Alaw_8, Unknown_other} ft_encoding_t;
static char const * const str[] = {
"Unspecified", "8-bit mu-law", "8-bit signed linear", "16-bit signed linear",
"24-bit signed linear", "32-bit signed linear", "Floating-point",
"Double precision float", "Fragmented sampled data", "Unknown", "DSP program",
"8-bit fixed-point", "16-bit fixed-point", "24-bit fixed-point",
"32-bit fixed-point", "Unknown", "Non-audio data", "Mu-law squelch",
"16-bit linear with emphasis", "16-bit linear with compression",
"16-bit linear with emphasis and compression", "Music Kit DSP commands",
"Music Kit DSP samples", "4-bit G.721 ADPCM", "G.722 ADPCM",
"3-bit G.723 ADPCM", "5-bit G.723 ADPCM", "8-bit a-law", "Unknown"};
static ft_encoding_t ft_enc(unsigned size, sox_encoding_t encoding)
{
if (encoding == SOX_ENCODING_ULAW && size == 8) return Mulaw_8;
if (encoding == SOX_ENCODING_ALAW && size == 8) return Alaw_8;
if (encoding == SOX_ENCODING_SIGN2 && size == 8) return Linear_8;
if (encoding == SOX_ENCODING_SIGN2 && size == 16) return Linear_16;
if (encoding == SOX_ENCODING_SIGN2 && size == 24) return Linear_24;
if (encoding == SOX_ENCODING_SIGN2 && size == 32) return Linear_32;
if (encoding == SOX_ENCODING_FLOAT && size == 32) return Float;
if (encoding == SOX_ENCODING_FLOAT && size == 64) return Double;
return Unspecified;
}
static sox_encoding_t sox_enc(uint32_t ft_encoding, unsigned * size)
{
switch (ft_encoding) {
case Mulaw_8 : *size = 8; return SOX_ENCODING_ULAW;
case Alaw_8 : *size = 8; return SOX_ENCODING_ALAW;
case Linear_8 : *size = 8; return SOX_ENCODING_SIGN2;
case Linear_16 : *size = 16; return SOX_ENCODING_SIGN2;
case Linear_24 : *size = 24; return SOX_ENCODING_SIGN2;
case Linear_32 : *size = 32; return SOX_ENCODING_SIGN2;
case Float : *size = 32; return SOX_ENCODING_FLOAT;
case Double : *size = 64; return SOX_ENCODING_FLOAT;
case Adpcm_g721 : *size = 4; return SOX_ENCODING_G721; /* read-only */
case Adpcm_g723_3: *size = 3; return SOX_ENCODING_G723; /* read-only */
case Adpcm_g723_5: *size = 5; return SOX_ENCODING_G723; /* read-only */
default: return SOX_ENCODING_UNKNOWN;
}
}
typedef struct { /* For G72x decoding: */
struct g72x_state state;
int (*dec_routine)(int i, int out_coding, struct g72x_state *state_ptr);
unsigned int in_buffer;
int in_bits;
} priv_t;
/*
* Unpack input codes and pass them back as bytes.
* Returns 1 if there is residual input, returns -1 if eof, else returns 0.
* (Adapted from Sun's decode.c.)
*/
static int unpack_input(sox_format_t * ft, unsigned char *code)
{
priv_t * p = (priv_t *) ft->priv;
unsigned char in_byte;
if (p->in_bits < (int)ft->encoding.bits_per_sample) {
if (lsx_read_b_buf(ft, &in_byte, (size_t) 1) != 1) {
*code = 0;
return -1;
}
p->in_buffer |= (in_byte << p->in_bits);
p->in_bits += 8;
}
*code = p->in_buffer & ((1 << ft->encoding.bits_per_sample) - 1);
p->in_buffer >>= ft->encoding.bits_per_sample;
p->in_bits -= ft->encoding.bits_per_sample;
return p->in_bits > 0;
}
static size_t dec_read(sox_format_t *ft, sox_sample_t *buf, size_t samp)
{
priv_t * p = (priv_t *)ft->priv;
unsigned char code;
size_t done;
for (done = 0; samp > 0 && unpack_input(ft, &code) >= 0; ++done, --samp)
*buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(
(*p->dec_routine)(code, AUDIO_ENCODING_LINEAR, &p->state),);
return done;
}
static int startread(sox_format_t * ft)
{
priv_t * p = (priv_t *) ft->priv;
char magic[4]; /* These 6 variables represent a Sun sound */
uint32_t hdr_size; /* header on disk. The uint32_t are written as */
uint32_t data_size; /* big-endians. At least extra bytes (totalling */
uint32_t ft_encoding; /* hdr_size - FIXED_HDR) are an "info" field of */
uint32_t rate; /* unspecified nature, usually a string. By */
uint32_t channels; /* convention the header size is a multiple of 4. */
unsigned i, bits_per_sample;
sox_encoding_t encoding;
if (lsx_readchars(ft, magic, sizeof(magic)))
return SOX_EOF;
for (i = 0; id[i].desc && memcmp(magic, id[i].str, sizeof(magic)); ++i);
if (!id[i].desc) {
lsx_fail_errno(ft, SOX_EHDR, "au: can't find Sun/NeXT/DEC identifier");
return SOX_EOF;
}
lsx_report("found %s identifier", id[i].desc);
ft->encoding.reverse_bytes = id[i].reverse_bytes;
if (lsx_readdw(ft, &hdr_size) ||
lsx_readdw(ft, &data_size) || /* Can be SUN_UNSPEC */
lsx_readdw(ft, &ft_encoding) ||
lsx_readdw(ft, &rate) ||
lsx_readdw(ft, &channels))
return SOX_EOF;
if (hdr_size < FIXED_HDR) {
lsx_fail_errno(ft, SOX_EHDR, "header size %u is too small", hdr_size);
return SOX_EOF;
}
if (hdr_size < FIXED_HDR + 4)
lsx_warn("header size %u is too small", hdr_size);
if (!(encoding = sox_enc(ft_encoding, &bits_per_sample))) {
int n = min(ft_encoding, Unknown_other);
lsx_fail_errno(ft, SOX_EFMT, "unsupported encoding `%s' (%#x)", str[n], ft_encoding);
return SOX_EOF;
}
switch (ft_encoding) {
case Adpcm_g721 : p->dec_routine = g721_decoder ; break;
case Adpcm_g723_3: p->dec_routine = g723_24_decoder; break;
case Adpcm_g723_5: p->dec_routine = g723_40_decoder; break;
}
if (p->dec_routine) {
g72x_init_state(&p->state);
ft->handler.seek = NULL;
ft->handler.read = dec_read;
}
if (hdr_size > FIXED_HDR) {
size_t info_size = hdr_size - FIXED_HDR;
char * buf = lsx_calloc(1, info_size + 1); /* +1 ensures null-terminated */
if (lsx_readchars(ft, buf, info_size) != SOX_SUCCESS) {
free(buf);
return SOX_EOF;
}
sox_append_comments(&ft->oob.comments, buf);
free(buf);
}
if (data_size == SUN_UNSPEC)
data_size = SOX_UNSPEC;
return lsx_check_read_params(ft, channels, (sox_rate_t)rate, encoding,
bits_per_sample, div_bits(data_size, bits_per_sample), sox_true);
}
static int write_header(sox_format_t * ft)
{
char * comment = lsx_cat_comments(ft->oob.comments);
size_t len = strlen(comment) + 1; /* Write out null-terminated */
size_t info_len = max(4, (len + 3) & ~3u); /* Minimum & multiple of 4 bytes */
int i = ft->encoding.reverse_bytes == MACHINE_IS_BIGENDIAN? 2 : 0;
uint64_t size64 = ft->olength ? ft->olength : ft->signal.length;
unsigned size = size64 == SOX_UNSPEC
? SUN_UNSPEC
: size64*(ft->encoding.bits_per_sample >> 3) > UINT_MAX
? SUN_UNSPEC
: (unsigned)(size64*(ft->encoding.bits_per_sample >> 3));
sox_bool error = sox_false
||lsx_writechars(ft, id[i].str, sizeof(id[i].str))
||lsx_writedw(ft, FIXED_HDR + (unsigned)info_len)
||lsx_writedw(ft, size)
||lsx_writedw(ft, ft_enc(ft->encoding.bits_per_sample, ft->encoding.encoding))
||lsx_writedw(ft, (unsigned)(ft->signal.rate + .5))
||lsx_writedw(ft, ft->signal.channels)
||lsx_writechars(ft, comment, len)
||lsx_padbytes(ft, info_len - len);
free(comment);
return error? SOX_EOF: SOX_SUCCESS;
}
LSX_FORMAT_HANDLER(au)
{
static char const * const names[] = {"au", "snd", NULL};
static unsigned const write_encodings[] = {
SOX_ENCODING_ULAW, 8, 0,
SOX_ENCODING_ALAW, 8, 0,
SOX_ENCODING_SIGN2, 8, 16, 24, 32, 0,
SOX_ENCODING_FLOAT, 32, 64, 0,
0};
static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
"PCM file format used widely on Sun systems",
names, SOX_FILE_BIG_END | SOX_FILE_REWIND,
startread, lsx_rawread, NULL,
write_header, lsx_rawwrite, NULL,
lsx_rawseek, write_encodings, NULL, sizeof(priv_t)
};
return &handler;
}

@ -0,0 +1,287 @@
/* AVR file format handler for SoX
* Copyright (C) 1999 Jan Paul Schmidt <jps@fundament.org>
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
#include <stdio.h>
#include <string.h>
#define AVR_MAGIC "2BIT"
/* Taken from the Audio File Formats FAQ */
typedef struct {
char magic [5]; /* 2BIT */
char name [8]; /* null-padded sample name */
unsigned short mono; /* 0 = mono, 0xffff = stereo */
unsigned short rez; /* 8 = 8 bit, 16 = 16 bit */
unsigned short sign; /* 0 = unsigned, 0xffff = signed */
unsigned short loop; /* 0 = no loop, 0xffff = looping sample */
unsigned short midi; /* 0xffff = no MIDI note assigned,
0xffXX = single key note assignment
0xLLHH = key split, low/hi note */
uint32_t rate; /* sample frequency in hertz */
uint32_t size; /* sample length in bytes or words (see rez) */
uint32_t lbeg; /* offset to start of loop in bytes or words.
set to zero if unused. */
uint32_t lend; /* offset to end of loop in bytes or words.
set to sample length if unused. */
unsigned short res1; /* Reserved, MIDI keyboard split */
unsigned short res2; /* Reserved, sample compression */
unsigned short res3; /* Reserved */
char ext[20]; /* Additional filename space, used
if (name[7] != 0) */
char user[64]; /* User defined. Typically ASCII message. */
} priv_t;
/*
* Do anything required before you start reading samples.
* Read file header.
* Find out sampling rate,
* size and encoding of samples,
* mono/stereo/quad.
*/
static int startread(sox_format_t * ft)
{
priv_t * avr = (priv_t *)ft->priv;
int rc;
lsx_reads(ft, avr->magic, (size_t)4);
if (strncmp (avr->magic, AVR_MAGIC, (size_t)4)) {
lsx_fail_errno(ft,SOX_EHDR,"AVR: unknown header");
return(SOX_EOF);
}
lsx_readbuf(ft, avr->name, sizeof(avr->name));
lsx_readw (ft, &(avr->mono));
if (avr->mono) {
ft->signal.channels = 2;
}
else {
ft->signal.channels = 1;
}
lsx_readw (ft, &(avr->rez));
if (avr->rez == 8) {
ft->encoding.bits_per_sample = 8;
}
else if (avr->rez == 16) {
ft->encoding.bits_per_sample = 16;
}
else {
lsx_fail_errno(ft,SOX_EFMT,"AVR: unsupported sample resolution");
return(SOX_EOF);
}
lsx_readw (ft, &(avr->sign));
if (avr->sign) {
ft->encoding.encoding = SOX_ENCODING_SIGN2;
}
else {
ft->encoding.encoding = SOX_ENCODING_UNSIGNED;
}
lsx_readw (ft, &(avr->loop));
lsx_readw (ft, &(avr->midi));
lsx_readdw (ft, &(avr->rate));
/*
* No support for AVRs created by ST-Replay,
* Replay Proffesional and PRO-Series 12.
*
* Just masking the upper byte out.
*/
ft->signal.rate = (avr->rate & 0x00ffffff);
lsx_readdw (ft, &(avr->size));
lsx_readdw (ft, &(avr->lbeg));
lsx_readdw (ft, &(avr->lend));
lsx_readw (ft, &(avr->res1));
lsx_readw (ft, &(avr->res2));
lsx_readw (ft, &(avr->res3));
lsx_readbuf(ft, avr->ext, sizeof(avr->ext));
lsx_readbuf(ft, avr->user, sizeof(avr->user));
rc = lsx_rawstartread (ft);
if (rc)
return rc;
return(SOX_SUCCESS);
}
static int startwrite(sox_format_t * ft)
{
priv_t * avr = (priv_t *)ft->priv;
int rc;
if (!ft->seekable) {
lsx_fail_errno(ft,SOX_EOF,"AVR: file is not seekable");
return(SOX_EOF);
}
rc = lsx_rawstartwrite (ft);
if (rc)
return rc;
/* magic */
lsx_writes(ft, AVR_MAGIC);
/* name */
lsx_writeb(ft, 0);
lsx_writeb(ft, 0);
lsx_writeb(ft, 0);
lsx_writeb(ft, 0);
lsx_writeb(ft, 0);
lsx_writeb(ft, 0);
lsx_writeb(ft, 0);
lsx_writeb(ft, 0);
/* mono */
if (ft->signal.channels == 1) {
lsx_writew (ft, 0);
}
else if (ft->signal.channels == 2) {
lsx_writew (ft, 0xffff);
}
else {
lsx_fail_errno(ft,SOX_EFMT,"AVR: number of channels not supported");
return(0);
}
/* rez */
if (ft->encoding.bits_per_sample == 8) {
lsx_writew (ft, 8);
}
else if (ft->encoding.bits_per_sample == 16) {
lsx_writew (ft, 16);
}
else {
lsx_fail_errno(ft,SOX_EFMT,"AVR: unsupported sample resolution");
return(SOX_EOF);
}
/* sign */
if (ft->encoding.encoding == SOX_ENCODING_SIGN2) {
lsx_writew (ft, 0xffff);
}
else if (ft->encoding.encoding == SOX_ENCODING_UNSIGNED) {
lsx_writew (ft, 0);
}
else {
lsx_fail_errno(ft,SOX_EFMT,"AVR: unsupported encoding");
return(SOX_EOF);
}
/* loop */
lsx_writew (ft, 0xffff);
/* midi */
lsx_writew (ft, 0xffff);
/* rate */
lsx_writedw(ft, (unsigned)(ft->signal.rate + .5));
/* size */
/* Don't know the size yet. */
lsx_writedw (ft, 0);
/* lbeg */
lsx_writedw (ft, 0);
/* lend */
/* Don't know the size yet, so we can't set lend, either. */
lsx_writedw (ft, 0);
/* res1 */
lsx_writew (ft, 0);
/* res2 */
lsx_writew (ft, 0);
/* res3 */
lsx_writew (ft, 0);
/* ext */
lsx_writebuf(ft, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", sizeof(avr->ext));
/* user */
lsx_writebuf(ft,
"\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"
"\0\0\0\0", sizeof (avr->user));
return(SOX_SUCCESS);
}
static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t nsamp)
{
priv_t * avr = (priv_t *)ft->priv;
avr->size += nsamp;
return (lsx_rawwrite (ft, buf, nsamp));
}
static int stopwrite(sox_format_t * ft)
{
priv_t * avr = (priv_t *)ft->priv;
unsigned size = avr->size / ft->signal.channels;
/* Fix size */
lsx_seeki(ft, (off_t)26, SEEK_SET);
lsx_writedw (ft, size);
/* Fix lend */
lsx_seeki(ft, (off_t)34, SEEK_SET);
lsx_writedw (ft, size);
return(SOX_SUCCESS);
}
LSX_FORMAT_HANDLER(avr)
{
static char const * const names[] = { "avr", NULL };
static unsigned const write_encodings[] = {
SOX_ENCODING_SIGN2, 16, 8, 0,
SOX_ENCODING_UNSIGNED, 16, 8, 0,
0};
static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE,
"Audio Visual Research format; used on the Mac",
names, SOX_FILE_BIG_END | SOX_FILE_MONO | SOX_FILE_STEREO,
startread, lsx_rawread, NULL,
startwrite, write_samples, stopwrite,
NULL, write_encodings, NULL, sizeof(priv_t)
};
return &handler;
}

@ -0,0 +1,47 @@
/* libSoX Bandpass effect file. July 5, 1991
* Copyright 1991 Lance Norskog And Sundry Contributors
*
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
* Lance Norskog And Sundry Contributors are not responsible for
* the consequences of using this software.
*
* Algorithm: 2nd order recursive filter.
* Formula stolen from MUSIC56K, a toolkit of 56000 assembler stuff.
* Quote:
* This is a 2nd order recursive band pass filter of the form.
* y(n)= a * x(n) - b * y(n-1) - c * y(n-2)
* where :
* x(n) = "IN"
* "OUT" = y(n)
* c = EXP(-2*pi*cBW/S_RATE)
* b = -4*c/(1+c)*COS(2*pi*cCF/S_RATE)
* if cSCL=2 (i.e. noise input)
* a = SQT(((1+c)*(1+c)-b*b)*(1-c)/(1+c))
* else
* a = SQT(1-b*b/(4*c))*(1-c)
* endif
* note : cCF is the center frequency in Hertz
* cBW is the band width in Hertz
* cSCL is a scale factor, use 1 for pitched sounds
* use 2 for noise.
*
*
* July 1, 1999 - Jan Paul Schmidt <jps@fundament.org>
*
* This looks like the resonator band pass in SPKit. It's a
* second order all-pole (IIR) band-pass filter described
* at the pages 186 - 189 in
* Dodge, Charles & Jerse, Thomas A. 1985:
* Computer Music -- Synthesis, Composition and Performance.
* New York: Schirmer Books.
* Reference from the SPKit manual.
*/
p->a2 = exp(-2 * M_PI * bw_Hz / effp->in_signal.rate);
p->a1 = -4 * p->a2 / (1 + p->a2) * cos(2 * M_PI * p->fc / effp->in_signal.rate);
p->b0 = sqrt(1 - p->a1 * p->a1 / (4 * p->a2)) * (1 - p->a2);
if (p->filter_type == filter_BPF_SPK_N) {
mult = sqrt(((1+p->a2) * (1+p->a2) - p->a1*p->a1) * (1-p->a2) / (1+p->a2)) / p->b0;
p->b0 *= mult;
}

@ -0,0 +1,325 @@
/* libSoX effect: Pitch Bend (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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* Portions based on http://www.dspdimension.com/download smbPitchShift.cpp:
*
* COPYRIGHT 1999-2006 Stephan M. Bernsee <smb [AT] dspdimension [DOT] com>
*
* The Wide Open License (WOL)
*
* Permission to use, copy, modify, distribute and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice and this license appear in all source copies.
* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF
* ANY KIND. See http://www.dspguru.com/wol.htm for more information.
*/
#ifdef NDEBUG /* Enable assert always. */
#undef NDEBUG /* Must undef above assert.h or other that might include it. */
#endif
#include "sox_i.h"
#include <assert.h>
#define MAX_FRAME_LENGTH 8192
typedef struct {
unsigned nbends; /* Number of bends requested */
struct {
char *str; /* Command-line argument to parse for this bend */
uint64_t start; /* Start bending when in_pos equals this */
double cents;
uint64_t duration; /* Number of samples to bend */
} *bends;
unsigned frame_rate;
size_t in_pos; /* Number of samples read from the input stream */
unsigned bends_pos; /* Number of bends completed so far */
double shift;
float gInFIFO[MAX_FRAME_LENGTH];
float gOutFIFO[MAX_FRAME_LENGTH];
double gFFTworksp[2 * MAX_FRAME_LENGTH];
float gLastPhase[MAX_FRAME_LENGTH / 2 + 1];
float gSumPhase[MAX_FRAME_LENGTH / 2 + 1];
float gOutputAccum[2 * MAX_FRAME_LENGTH];
float gAnaFreq[MAX_FRAME_LENGTH];
float gAnaMagn[MAX_FRAME_LENGTH];
float gSynFreq[MAX_FRAME_LENGTH];
float gSynMagn[MAX_FRAME_LENGTH];
long gRover;
int fftFrameSize, ovsamp;
} priv_t;
static int parse(sox_effect_t * effp, char **argv, sox_rate_t rate)
{
priv_t *p = (priv_t *) effp->priv;
size_t i;
char const *next;
uint64_t last_seen = 0;
const uint64_t in_length = argv ? 0 :
(effp->in_signal.length != SOX_UNKNOWN_LEN ?
effp->in_signal.length / effp->in_signal.channels : SOX_UNKNOWN_LEN);
for (i = 0; i < p->nbends; ++i) {
if (argv) /* 1st parse only */
p->bends[i].str = lsx_strdup(argv[i]);
next = lsx_parseposition(rate, p->bends[i].str,
argv ? NULL : &p->bends[i].start, last_seen, in_length, '+');
last_seen = p->bends[i].start;
if (next == NULL || *next != ',')
break;
p->bends[i].cents = strtod(next + 1, (char **)&next);
if (p->bends[i].cents == 0 || *next != ',')
break;
next = lsx_parseposition(rate, next + 1,
argv ? NULL : &p->bends[i].duration, last_seen, in_length, '+');
last_seen = p->bends[i].duration;
if (next == NULL || *next != '\0')
break;
/* sanity checks */
if (!argv && p->bends[i].duration < p->bends[i].start) {
lsx_fail("Bend %" PRIuPTR " has negative width", i+1);
break;
}
if (!argv && i && p->bends[i].start < p->bends[i-1].start) {
lsx_fail("Bend %" PRIuPTR " overlaps with previous one", i+1);
break;
}
p->bends[i].duration -= p->bends[i].start;
}
if (i < p->nbends)
return lsx_usage(effp);
return SOX_SUCCESS;
}
static int create(sox_effect_t * effp, int argc, char **argv)
{
priv_t *p = (priv_t *) effp->priv;
char const * opts = "f:o:";
int c;
lsx_getopt_t optstate;
lsx_getopt_init(argc, argv, opts, NULL, lsx_getopt_flag_none, 1, &optstate);
p->frame_rate = 25;
p->ovsamp = 16;
while ((c = lsx_getopt(&optstate)) != -1) switch (c) {
GETOPT_NUMERIC(optstate, 'f', frame_rate, 10 , 80)
GETOPT_NUMERIC(optstate, 'o', ovsamp, 4 , 32)
default: lsx_fail("unknown option `-%c'", optstate.opt); return lsx_usage(effp);
}
argc -= optstate.ind, argv += optstate.ind;
p->nbends = argc;
p->bends = lsx_calloc(p->nbends, sizeof(*p->bends));
return parse(effp, argv, 0.); /* No rate yet; parse with dummy */
}
static int start(sox_effect_t * effp)
{
priv_t *p = (priv_t *) effp->priv;
unsigned i;
int n = effp->in_signal.rate / p->frame_rate + .5;
for (p->fftFrameSize = 2; n > 2; p->fftFrameSize <<= 1, n >>= 1);
assert(p->fftFrameSize <= MAX_FRAME_LENGTH);
p->shift = 1;
parse(effp, 0, effp->in_signal.rate); /* Re-parse now rate is known */
p->in_pos = p->bends_pos = 0;
for (i = 0; i < p->nbends; ++i)
if (p->bends[i].duration)
return SOX_SUCCESS;
return SOX_EFF_NULL;
}
static int flow(sox_effect_t * effp, const sox_sample_t * ibuf,
sox_sample_t * obuf, size_t * isamp, size_t * osamp)
{
priv_t *p = (priv_t *) effp->priv;
size_t i, len = *isamp = *osamp = min(*isamp, *osamp);
double magn, phase, tmp, window, real, imag;
double freqPerBin, expct;
long k, qpd, index, inFifoLatency, stepSize, fftFrameSize2;
float pitchShift = p->shift;
/* set up some handy variables */
fftFrameSize2 = p->fftFrameSize / 2;
stepSize = p->fftFrameSize / p->ovsamp;
freqPerBin = effp->in_signal.rate / p->fftFrameSize;
expct = 2. * M_PI * (double) stepSize / (double) p->fftFrameSize;
inFifoLatency = p->fftFrameSize - stepSize;
if (!p->gRover)
p->gRover = inFifoLatency;
/* main processing loop */
for (i = 0; i < len; i++) {
SOX_SAMPLE_LOCALS;
++p->in_pos;
/* As long as we have not yet collected enough data just read in */
p->gInFIFO[p->gRover] = SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[i], effp->clips);
obuf[i] = SOX_FLOAT_32BIT_TO_SAMPLE(
p->gOutFIFO[p->gRover - inFifoLatency], effp->clips);
p->gRover++;
/* now we have enough data for processing */
if (p->gRover >= p->fftFrameSize) {
if (p->bends_pos != p->nbends && p->in_pos >=
p->bends[p->bends_pos].start + p->bends[p->bends_pos].duration) {
pitchShift = p->shift *= pow(2., p->bends[p->bends_pos].cents / 1200);
++p->bends_pos;
}
if (p->bends_pos != p->nbends && p->in_pos >= p->bends[p->bends_pos].start) {
double progress = (double)(p->in_pos - p->bends[p->bends_pos].start) /
p->bends[p->bends_pos].duration;
progress = 1 - cos(M_PI * progress);
progress *= p->bends[p->bends_pos].cents * (.5 / 1200);
pitchShift = p->shift * pow(2., progress);
}
p->gRover = inFifoLatency;
/* do windowing and re,im interleave */
for (k = 0; k < p->fftFrameSize; k++) {
window = -.5 * cos(2 * M_PI * k / (double) p->fftFrameSize) + .5;
p->gFFTworksp[2 * k] = p->gInFIFO[k] * window;
p->gFFTworksp[2 * k + 1] = 0.;
}
/* ***************** ANALYSIS ******************* */
lsx_safe_cdft(2 * p->fftFrameSize, 1, p->gFFTworksp);
/* this is the analysis step */
for (k = 0; k <= fftFrameSize2; k++) {
/* de-interlace FFT buffer */
real = p->gFFTworksp[2 * k];
imag = - p->gFFTworksp[2 * k + 1];
/* compute magnitude and phase */
magn = 2. * sqrt(real * real + imag * imag);
phase = atan2(imag, real);
/* compute phase difference */
tmp = phase - p->gLastPhase[k];
p->gLastPhase[k] = phase;
tmp -= (double) k *expct; /* subtract expected phase difference */
/* map delta phase into +/- Pi interval */
qpd = tmp / M_PI;
if (qpd >= 0)
qpd += qpd & 1;
else qpd -= qpd & 1;
tmp -= M_PI * (double) qpd;
/* get deviation from bin frequency from the +/- Pi interval */
tmp = p->ovsamp * tmp / (2. * M_PI);
/* compute the k-th partials' true frequency */
tmp = (double) k *freqPerBin + tmp * freqPerBin;
/* store magnitude and true frequency in analysis arrays */
p->gAnaMagn[k] = magn;
p->gAnaFreq[k] = tmp;
}
/* this does the actual pitch shifting */
memset(p->gSynMagn, 0, p->fftFrameSize * sizeof(float));
memset(p->gSynFreq, 0, p->fftFrameSize * sizeof(float));
for (k = 0; k <= fftFrameSize2; k++) {
index = k * pitchShift;
if (index <= fftFrameSize2) {
p->gSynMagn[index] += p->gAnaMagn[k];
p->gSynFreq[index] = p->gAnaFreq[k] * pitchShift;
}
}
for (k = 0; k <= fftFrameSize2; k++) { /* SYNTHESIS */
/* get magnitude and true frequency from synthesis arrays */
magn = p->gSynMagn[k], tmp = p->gSynFreq[k];
tmp -= (double) k *freqPerBin; /* subtract bin mid frequency */
tmp /= freqPerBin; /* get bin deviation from freq deviation */
tmp = 2. * M_PI * tmp / p->ovsamp; /* take p->ovsamp into account */
tmp += (double) k *expct; /* add the overlap phase advance back in */
p->gSumPhase[k] += tmp; /* accumulate delta phase to get bin phase */
phase = p->gSumPhase[k];
/* get real and imag part and re-interleave */
p->gFFTworksp[2 * k] = magn * cos(phase);
p->gFFTworksp[2 * k + 1] = - magn * sin(phase);
}
for (k = p->fftFrameSize + 2; k < 2 * p->fftFrameSize; k++)
p->gFFTworksp[k] = 0.; /* zero negative frequencies */
lsx_safe_cdft(2 * p->fftFrameSize, -1, p->gFFTworksp);
/* do windowing and add to output accumulator */
for (k = 0; k < p->fftFrameSize; k++) {
window =
-.5 * cos(2. * M_PI * (double) k / (double) p->fftFrameSize) + .5;
p->gOutputAccum[k] +=
2. * window * p->gFFTworksp[2 * k] / (fftFrameSize2 * p->ovsamp);
}
for (k = 0; k < stepSize; k++)
p->gOutFIFO[k] = p->gOutputAccum[k];
memmove(p->gOutputAccum, /* shift accumulator */
p->gOutputAccum + stepSize, p->fftFrameSize * sizeof(float));
for (k = 0; k < inFifoLatency; k++) /* move input FIFO */
p->gInFIFO[k] = p->gInFIFO[k + stepSize];
}
}
return SOX_SUCCESS;
}
static int stop(sox_effect_t * effp)
{
priv_t *p = (priv_t *) effp->priv;
if (p->bends_pos != p->nbends)
lsx_warn("Input audio too short; bends not applied: %u",
p->nbends - p->bends_pos);
return SOX_SUCCESS;
}
static int lsx_kill(sox_effect_t * effp)
{
priv_t *p = (priv_t *) effp->priv;
unsigned i;
for (i = 0; i < p->nbends; ++i)
free(p->bends[i].str);
free(p->bends);
return SOX_SUCCESS;
}
sox_effect_handler_t const *lsx_bend_effect_fn(void)
{
static sox_effect_handler_t handler = {
"bend", "[-f frame-rate(25)] [-o over-sample(16)] {start,cents,end}",
0, create, start, flow, 0, stop, lsx_kill, sizeof(priv_t)
};
return &handler;
}

@ -0,0 +1,178 @@
/* libSoX Biquad filter common functions (c) 2006-7 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "biquad.h"
#include <string.h>
typedef biquad_t priv_t;
static char const * const width_str[] = {
"band-width(Hz)",
"band-width(kHz)",
"band-width(Hz, no warp)", /* deprecated */
"band-width(octaves)",
"Q",
"slope",
};
static char const all_width_types[] = "hkboqs";
int lsx_biquad_getopts(sox_effect_t * effp, int argc, char **argv,
int min_args, int max_args, int fc_pos, int width_pos, int gain_pos,
char const * allowed_width_types, filter_t filter_type)
{
priv_t * p = (priv_t *)effp->priv;
char width_type = *allowed_width_types;
char dummy, * dummy_p; /* To check for extraneous chars. */
--argc, ++argv;
p->filter_type = filter_type;
if (argc < min_args || argc > max_args ||
(argc > fc_pos && ((p->fc = lsx_parse_frequency(argv[fc_pos], &dummy_p)) <= 0 || *dummy_p)) ||
(argc > width_pos && ((unsigned)(sscanf(argv[width_pos], "%lf%c %c", &p->width, &width_type, &dummy)-1) > 1 || p->width <= 0)) ||
(argc > gain_pos && sscanf(argv[gain_pos], "%lf %c", &p->gain, &dummy) != 1) ||
!strchr(allowed_width_types, width_type) || (width_type == 's' && p->width > 1))
return lsx_usage(effp);
p->width_type = strchr(all_width_types, width_type) - all_width_types;
if ((size_t)p->width_type >= strlen(all_width_types))
p->width_type = 0;
if (p->width_type == width_bw_kHz) {
p->width *= 1000;
p->width_type = width_bw_Hz;
}
return SOX_SUCCESS;
}
static int start(sox_effect_t * effp)
{
priv_t * p = (priv_t *)effp->priv;
/* Simplify: */
p->b2 /= p->a0;
p->b1 /= p->a0;
p->b0 /= p->a0;
p->a2 /= p->a0;
p->a1 /= p->a0;
p->o2 = p->o1 = p->i2 = p->i1 = 0;
return SOX_SUCCESS;
}
int lsx_biquad_start(sox_effect_t * effp)
{
priv_t * p = (priv_t *)effp->priv;
start(effp);
if (effp->global_info->plot == sox_plot_octave) {
printf(
"%% GNU Octave file (may also work with MATLAB(R) )\n"
"Fs=%g;minF=10;maxF=Fs/2;\n"
"sweepF=logspace(log10(minF),log10(maxF),200);\n"
"[h,w]=freqz([%.15e %.15e %.15e],[1 %.15e %.15e],sweepF,Fs);\n"
"semilogx(w,20*log10(h))\n"
"title('SoX effect: %s gain=%g frequency=%g %s=%g (rate=%g)')\n"
"xlabel('Frequency (Hz)')\n"
"ylabel('Amplitude Response (dB)')\n"
"axis([minF maxF -35 25])\n"
"grid on\n"
"disp('Hit return to continue')\n"
"pause\n"
, effp->in_signal.rate, p->b0, p->b1, p->b2, p->a1, p->a2
, effp->handler.name, p->gain, p->fc, width_str[p->width_type], p->width
, effp->in_signal.rate);
return SOX_EOF;
}
if (effp->global_info->plot == sox_plot_gnuplot) {
printf(
"# gnuplot file\n"
"set title 'SoX effect: %s gain=%g frequency=%g %s=%g (rate=%g)'\n"
"set xlabel 'Frequency (Hz)'\n"
"set ylabel 'Amplitude Response (dB)'\n"
"Fs=%g\n"
"b0=%.15e; b1=%.15e; b2=%.15e; a1=%.15e; a2=%.15e\n"
"o=2*pi/Fs\n"
"H(f)=sqrt((b0*b0+b1*b1+b2*b2+2.*(b0*b1+b1*b2)*cos(f*o)+2.*(b0*b2)*cos(2.*f*o))/(1.+a1*a1+a2*a2+2.*(a1+a1*a2)*cos(f*o)+2.*a2*cos(2.*f*o)))\n"
"set logscale x\n"
"set samples 250\n"
"set grid xtics ytics\n"
"set key off\n"
"plot [f=10:Fs/2] [-35:25] 20*log10(H(f))\n"
"pause -1 'Hit return to continue'\n"
, effp->handler.name, p->gain, p->fc, width_str[p->width_type], p->width
, effp->in_signal.rate, effp->in_signal.rate
, p->b0, p->b1, p->b2, p->a1, p->a2);
return SOX_EOF;
}
if (effp->global_info->plot == sox_plot_data) {
printf("# SoX effect: %s gain=%g frequency=%g %s=%g (rate=%g)\n"
"# IIR filter\n"
"# rate: %g\n"
"# name: b\n"
"# type: matrix\n"
"# rows: 3\n"
"# columns: 1\n"
"%24.16e\n%24.16e\n%24.16e\n"
"# name: a\n"
"# type: matrix\n"
"# rows: 3\n"
"# columns: 1\n"
"%24.16e\n%24.16e\n%24.16e\n"
, effp->handler.name, p->gain, p->fc, width_str[p->width_type], p->width
, effp->in_signal.rate, effp->in_signal.rate
, p->b0, p->b1, p->b2, 1. /* a0 */, p->a1, p->a2);
return SOX_EOF;
}
return SOX_SUCCESS;
}
int lsx_biquad_flow(sox_effect_t * effp, const sox_sample_t *ibuf,
sox_sample_t *obuf, size_t *isamp, size_t *osamp)
{
priv_t * p = (priv_t *)effp->priv;
size_t len = *isamp = *osamp = min(*isamp, *osamp);
while (len--) {
double o0 = *ibuf*p->b0 + p->i1*p->b1 + p->i2*p->b2 - p->o1*p->a1 - p->o2*p->a2;
p->i2 = p->i1, p->i1 = *ibuf++;
p->o2 = p->o1, p->o1 = o0;
*obuf++ = SOX_ROUND_CLIP_COUNT(o0, effp->clips);
}
return SOX_SUCCESS;
}
static int create(sox_effect_t * effp, int argc, char * * argv)
{
priv_t * p = (priv_t *)effp->priv;
double * d = &p->b0;
char c;
--argc, ++argv;
if (argc == 6)
for (; argc && sscanf(*argv, "%lf%c", d, &c) == 1; --argc, ++argv, ++d);
return argc? lsx_usage(effp) : SOX_SUCCESS;
}
sox_effect_handler_t const * lsx_biquad_effect_fn(void)
{
static sox_effect_handler_t handler = {
"biquad", "b0 b1 b2 a0 a1 a2", 0,
create, lsx_biquad_start, lsx_biquad_flow, NULL, NULL, NULL, sizeof(priv_t)
};
return &handler;
}

@ -0,0 +1,78 @@
/* libSoX Biquad filter common definitions (c) 2006-7 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef biquad_included
#define biquad_included
#define LSX_EFF_ALIAS
#include "sox_i.h"
typedef enum {
filter_LPF,
filter_HPF,
filter_BPF_CSG,
filter_BPF,
filter_notch,
filter_APF,
filter_peakingEQ,
filter_lowShelf,
filter_highShelf,
filter_LPF_1,
filter_HPF_1,
filter_BPF_SPK,
filter_BPF_SPK_N,
filter_AP1,
filter_AP2,
filter_deemph,
filter_riaa
} filter_t;
typedef enum {
width_bw_Hz,
width_bw_kHz,
/* The old, non-RBJ, non-freq-warped band-pass/reject response;
* leaving here for now just in case anybody misses it: */
width_bw_old,
width_bw_oct,
width_Q,
width_slope
} width_t;
/* Private data for the biquad filter effects */
typedef struct {
double gain; /* For EQ filters */
double fc; /* Centre/corner/cutoff frequency */
double width; /* Filter width; interpreted as per width_type */
width_t width_type;
filter_t filter_type;
double b0, b1, b2; /* Filter coefficients */
double a0, a1, a2; /* Filter coefficients */
sox_sample_t i1, i2; /* Filter memory */
double o1, o2; /* Filter memory */
} biquad_t;
int lsx_biquad_getopts(sox_effect_t * effp, int n, char **argv,
int min_args, int max_args, int fc_pos, int width_pos, int gain_pos,
char const * allowed_width_types, filter_t filter_type);
int lsx_biquad_start(sox_effect_t * effp);
int lsx_biquad_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,
size_t *isamp, size_t *osamp);
#endif

@ -0,0 +1,416 @@
/* libSoX Biquad filter effects (c) 2006-8 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*
* 2-pole filters designed by Robert Bristow-Johnson <rbj@audioimagination.com>
* see https://webaudio.github.io/Audio-EQ-Cookbook/audio-eq-cookbook.html
*
* 1-pole filters based on code (c) 2000 Chris Bagwell <cbagwell@sprynet.com>
* Algorithms: Recursive single pole low/high pass filter
* Reference: The Scientist and Engineer's Guide to Digital Signal Processing
*
* low-pass: output[N] = input[N] * A + output[N-1] * B
* X = exp(-2.0 * pi * Fc)
* A = 1 - X
* B = X
* Fc = cutoff freq / sample rate
*
* Mimics an RC low-pass filter:
*
* ---/\/\/\/\----------->
* |
* --- C
* ---
* |
* |
* V
*
* high-pass: output[N] = A0 * input[N] + A1 * input[N-1] + B1 * output[N-1]
* X = exp(-2.0 * pi * Fc)
* A0 = (1 + X) / 2
* A1 = -(1 + X) / 2
* B1 = X
* Fc = cutoff freq / sample rate
*
* Mimics an RC high-pass filter:
*
* || C
* ----||--------->
* || |
* <
* > R
* <
* |
* V
*/
#include "biquad.h"
#include <assert.h>
#include <string.h>
typedef biquad_t priv_t;
static int hilo1_getopts(sox_effect_t * effp, int argc, char **argv) {
return lsx_biquad_getopts(effp, argc, argv, 1, 1, 0, 1, 2, "",
*effp->handler.name == 'l'? filter_LPF_1 : filter_HPF_1);
}
static int hilo2_getopts(sox_effect_t * effp, int argc, char **argv) {
priv_t * p = (priv_t *)effp->priv;
if (argc > 1 && strcmp(argv[1], "-1") == 0)
return hilo1_getopts(effp, argc - 1, argv + 1);
if (argc > 1 && strcmp(argv[1], "-2") == 0)
++argv, --argc;
p->width = sqrt(0.5); /* Default to Butterworth */
return lsx_biquad_getopts(effp, argc, argv, 1, 2, 0, 1, 2, "qohk",
*effp->handler.name == 'l'? filter_LPF : filter_HPF);
}
static int bandpass_getopts(sox_effect_t * effp, int argc, char **argv) {
filter_t type = filter_BPF;
if (argc > 1 && strcmp(argv[1], "-c") == 0)
++argv, --argc, type = filter_BPF_CSG;
return lsx_biquad_getopts(effp, argc, argv, 2, 2, 0, 1, 2, "hkqob", type);
}
static int bandrej_getopts(sox_effect_t * effp, int argc, char **argv) {
return lsx_biquad_getopts(effp, argc, argv, 2, 2, 0, 1, 2, "hkqob", filter_notch);
}
static int allpass_getopts(sox_effect_t * effp, int argc, char **argv) {
filter_t type = filter_APF;
int m;
if (argc > 1 && strcmp(argv[1], "-1") == 0)
++argv, --argc, type = filter_AP1;
else if (argc > 1 && strcmp(argv[1], "-2") == 0)
++argv, --argc, type = filter_AP2;
m = 1 + (type == filter_APF);
return lsx_biquad_getopts(effp, argc, argv, m, m, 0, 1, 2, "hkqo", type);
}
static int tone_getopts(sox_effect_t * effp, int argc, char **argv) {
priv_t * p = (priv_t *)effp->priv;
p->width = 0.5;
p->fc = *effp->handler.name == 'b'? 100 : 3000;
return lsx_biquad_getopts(effp, argc, argv, 1, 3, 1, 2, 0, "shkqo",
*effp->handler.name == 'b'? filter_lowShelf: filter_highShelf);
}
static int equalizer_getopts(sox_effect_t * effp, int argc, char **argv) {
return lsx_biquad_getopts(effp, argc, argv, 3, 3, 0, 1, 2, "qohk", filter_peakingEQ);
}
static int band_getopts(sox_effect_t * effp, int argc, char **argv) {
filter_t type = filter_BPF_SPK;
if (argc > 1 && strcmp(argv[1], "-n") == 0)
++argv, --argc, type = filter_BPF_SPK_N;
return lsx_biquad_getopts(effp, argc, argv, 1, 2, 0, 1, 2, "hkqo", type);
}
static int deemph_getopts(sox_effect_t * effp, int argc, char **argv) {
return lsx_biquad_getopts(effp, argc, argv, 0, 0, 0, 1, 2, "s", filter_deemph);
}
static int riaa_getopts(sox_effect_t * effp, int argc, char **argv) {
priv_t * p = (priv_t *)effp->priv;
p->filter_type = filter_riaa;
(void)argv;
return --argc? lsx_usage(effp) : SOX_SUCCESS;
}
static void make_poly_from_roots(
double const * roots, size_t num_roots, double * poly)
{
size_t i, j;
poly[0] = 1;
poly[1] = -roots[0];
memset(poly + 2, 0, (num_roots + 1 - 2) * sizeof(*poly));
for (i = 1; i < num_roots; ++i)
for (j = num_roots; j > 0; --j)
poly[j] -= poly[j - 1] * roots[i];
}
static int start(sox_effect_t * effp)
{
priv_t * p = (priv_t *)effp->priv;
double w0, A, alpha, mult;
if (p->filter_type == filter_deemph) { /* See deemph.plt for documentation */
if (effp->in_signal.rate == 44100) {
p->fc = 5283;
p->width = 0.4845;
p->gain = -9.477;
}
else if (effp->in_signal.rate == 48000) {
p->fc = 5356;
p->width = 0.479;
p->gain = -9.62;
}
else {
lsx_fail("sample rate must be 44100 (audio-CD) or 48000 (DAT)");
return SOX_EOF;
}
}
w0 = 2 * M_PI * p->fc / effp->in_signal.rate;
A = exp(p->gain / 40 * log(10.));
alpha = 0, mult = dB_to_linear(max(p->gain, 0));
if (w0 > M_PI) {
lsx_fail("frequency must be less than half the sample-rate (Nyquist rate)");
return SOX_EOF;
}
/* Set defaults: */
p->b0 = p->b1 = p->b2 = p->a1 = p->a2 = 0;
p->a0 = 1;
if (p->width) switch (p->width_type) {
case width_slope:
alpha = sin(w0)/2 * sqrt((A + 1/A)*(1/p->width - 1) + 2);
break;
case width_Q:
alpha = sin(w0)/(2*p->width);
break;
case width_bw_oct:
alpha = sin(w0)*sinh(log(2.)/2 * p->width * w0/sin(w0));
break;
case width_bw_Hz:
alpha = sin(w0)/(2*p->fc/p->width);
break;
case width_bw_kHz: assert(0); /* Shouldn't get here */
case width_bw_old:
alpha = tan(M_PI * p->width / effp->in_signal.rate);
break;
}
switch (p->filter_type) {
case filter_LPF: /* H(s) = 1 / (s^2 + s/Q + 1) */
p->b0 = (1 - cos(w0))/2;
p->b1 = 1 - cos(w0);
p->b2 = (1 - cos(w0))/2;
p->a0 = 1 + alpha;
p->a1 = -2*cos(w0);
p->a2 = 1 - alpha;
break;
case filter_HPF: /* H(s) = s^2 / (s^2 + s/Q + 1) */
p->b0 = (1 + cos(w0))/2;
p->b1 = -(1 + cos(w0));
p->b2 = (1 + cos(w0))/2;
p->a0 = 1 + alpha;
p->a1 = -2*cos(w0);
p->a2 = 1 - alpha;
break;
case filter_BPF_CSG: /* H(s) = s / (s^2 + s/Q + 1) (constant skirt gain, peak gain = Q) */
p->b0 = sin(w0)/2;
p->b1 = 0;
p->b2 = -sin(w0)/2;
p->a0 = 1 + alpha;
p->a1 = -2*cos(w0);
p->a2 = 1 - alpha;
break;
case filter_BPF: /* H(s) = (s/Q) / (s^2 + s/Q + 1) (constant 0 dB peak gain) */
p->b0 = alpha;
p->b1 = 0;
p->b2 = -alpha;
p->a0 = 1 + alpha;
p->a1 = -2*cos(w0);
p->a2 = 1 - alpha;
break;
case filter_notch: /* H(s) = (s^2 + 1) / (s^2 + s/Q + 1) */
p->b0 = 1;
p->b1 = -2*cos(w0);
p->b2 = 1;
p->a0 = 1 + alpha;
p->a1 = -2*cos(w0);
p->a2 = 1 - alpha;
break;
case filter_APF: /* H(s) = (s^2 - s/Q + 1) / (s^2 + s/Q + 1) */
p->b0 = 1 - alpha;
p->b1 = -2*cos(w0);
p->b2 = 1 + alpha;
p->a0 = 1 + alpha;
p->a1 = -2*cos(w0);
p->a2 = 1 - alpha;
break;
case filter_peakingEQ: /* H(s) = (s^2 + s*(A/Q) + 1) / (s^2 + s/(A*Q) + 1) */
if (A == 1)
return SOX_EFF_NULL;
p->b0 = 1 + alpha*A;
p->b1 = -2*cos(w0);
p->b2 = 1 - alpha*A;
p->a0 = 1 + alpha/A;
p->a1 = -2*cos(w0);
p->a2 = 1 - alpha/A;
break;
case filter_lowShelf: /* H(s) = A * (s^2 + (sqrt(A)/Q)*s + A)/(A*s^2 + (sqrt(A)/Q)*s + 1) */
if (A == 1)
return SOX_EFF_NULL;
p->b0 = A*( (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha );
p->b1 = 2*A*( (A-1) - (A+1)*cos(w0) );
p->b2 = A*( (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha );
p->a0 = (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha;
p->a1 = -2*( (A-1) + (A+1)*cos(w0) );
p->a2 = (A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha;
break;
case filter_deemph: /* Falls through to high-shelf... */
case filter_highShelf: /* H(s) = A * (A*s^2 + (sqrt(A)/Q)*s + 1)/(s^2 + (sqrt(A)/Q)*s + A) */
if (!A)
return SOX_EFF_NULL;
p->b0 = A*( (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha );
p->b1 = -2*A*( (A-1) + (A+1)*cos(w0) );
p->b2 = A*( (A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha );
p->a0 = (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha;
p->a1 = 2*( (A-1) - (A+1)*cos(w0) );
p->a2 = (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha;
break;
case filter_LPF_1: /* single-pole */
p->a1 = -exp(-w0);
p->b0 = 1 + p->a1;
break;
case filter_HPF_1: /* single-pole */
p->a1 = -exp(-w0);
p->b0 = (1 - p->a1)/2;
p->b1 = -p->b0;
break;
case filter_BPF_SPK: case filter_BPF_SPK_N: {
double bw_Hz;
if (!p->width)
p->width = p->fc / 2;
bw_Hz = p->width_type == width_Q? p->fc / p->width :
p->width_type == width_bw_Hz? p->width :
p->fc * (pow(2., p->width) - 1) * pow(2., -0.5 * p->width); /* bw_oct */
#include "band.h" /* Has different licence */
break;
}
case filter_AP1: /* Experimental 1-pole all-pass from Tom Erbe @ UCSD */
p->b0 = exp(-w0);
p->b1 = -1;
p->a1 = -exp(-w0);
break;
case filter_AP2: /* Experimental 2-pole all-pass from Tom Erbe @ UCSD */
p->b0 = 1 - sin(w0);
p->b1 = -2 * cos(w0);
p->b2 = 1 + sin(w0);
p->a0 = 1 + sin(w0);
p->a1 = -2 * cos(w0);
p->a2 = 1 - sin(w0);
break;
case filter_riaa: /* http://www.dsprelated.com/showmessage/73300/3.php */
if (effp->in_signal.rate == 44100) {
static const double zeros[] = {-0.2014898, 0.9233820};
static const double poles[] = {0.7083149, 0.9924091};
make_poly_from_roots(zeros, (size_t)2, &p->b0);
make_poly_from_roots(poles, (size_t)2, &p->a0);
}
else if (effp->in_signal.rate == 48000) {
static const double zeros[] = {-0.1766069, 0.9321590};
static const double poles[] = {0.7396325, 0.9931330};
make_poly_from_roots(zeros, (size_t)2, &p->b0);
make_poly_from_roots(poles, (size_t)2, &p->a0);
}
else if (effp->in_signal.rate == 88200) {
static const double zeros[] = {-0.1168735, 0.9648312};
static const double poles[] = {0.8590646, 0.9964002};
make_poly_from_roots(zeros, (size_t)2, &p->b0);
make_poly_from_roots(poles, (size_t)2, &p->a0);
}
else if (effp->in_signal.rate == 96000) {
static const double zeros[] = {-0.1141486, 0.9676817};
static const double poles[] = {0.8699137, 0.9966946};
make_poly_from_roots(zeros, (size_t)2, &p->b0);
make_poly_from_roots(poles, (size_t)2, &p->a0);
}
else if (effp->in_signal.rate == 192000) {
static const double zeros[] = {-0.1040610965, 0.9837523263};
static const double poles[] = {0.9328992971, 0.9983633125};
make_poly_from_roots(zeros, (size_t)2, &p->b0);
make_poly_from_roots(poles, (size_t)2, &p->a0);
}
else {
lsx_fail("Sample rate must be 44.1k, 48k, 88.2k, 96k, or 192k");
return SOX_EOF;
}
{ /* Normalise to 0dB at 1kHz (Thanks to Glenn Davis) */
double y = 2 * M_PI * 1000 / effp->in_signal.rate;
double b_re = p->b0 + p->b1 * cos(-y) + p->b2 * cos(-2 * y);
double a_re = p->a0 + p->a1 * cos(-y) + p->a2 * cos(-2 * y);
double b_im = p->b1 * sin(-y) + p->b2 * sin(-2 * y);
double a_im = p->a1 * sin(-y) + p->a2 * sin(-2 * y);
double g = 1 / sqrt((sqr(b_re) + sqr(b_im)) / (sqr(a_re) + sqr(a_im)));
p->b0 *= g; p->b1 *= g; p->b2 *= g;
}
mult = (p->b0 + p->b1 + p->b2) / (p->a0 + p->a1 + p->a2);
lsx_debug("gain=%f", linear_to_dB(mult));
break;
}
if (effp->in_signal.mult)
*effp->in_signal.mult /= mult;
return lsx_biquad_start(effp);
}
#define BIQUAD_EFFECT(name,group,usage,flags) \
sox_effect_handler_t const * lsx_##name##_effect_fn(void) { \
static sox_effect_handler_t handler = { \
#name, usage, flags, \
group##_getopts, start, lsx_biquad_flow, 0, 0, 0, sizeof(biquad_t)\
}; \
return &handler; \
}
BIQUAD_EFFECT(highpass, hilo2, "[-1|-2] frequency [width[q|o|h|k](0.707q)]", 0)
BIQUAD_EFFECT(lowpass, hilo2, "[-1|-2] frequency [width[q|o|h|k]](0.707q)", 0)
BIQUAD_EFFECT(bandpass, bandpass, "[-c] frequency width[h|k|q|o]", 0)
BIQUAD_EFFECT(bandreject,bandrej, "frequency width[h|k|q|o]", 0)
BIQUAD_EFFECT(allpass, allpass, "frequency width[h|k|q|o]", 0)
BIQUAD_EFFECT(bass, tone, "gain [frequency(100) [width[s|h|k|q|o]](0.5s)]", 0)
BIQUAD_EFFECT(treble, tone, "gain [frequency(3000) [width[s|h|k|q|o]](0.5s)]", 0)
BIQUAD_EFFECT(equalizer, equalizer,"frequency width[q|o|h|k] gain", 0)
BIQUAD_EFFECT(band, band, "[-n] center [width[h|k|q|o]]", 0)
BIQUAD_EFFECT(deemph, deemph, NULL, 0)
BIQUAD_EFFECT(riaa, riaa, NULL, 0)

@ -0,0 +1,273 @@
#ifndef HAVE_COREAUDIO
/*
* SoX bit-rot detection file; cobbled together
*/
enum {
kAudioHardwarePropertyProcessIsMaster,
kAudioHardwarePropertyIsInitingOrExiting,
kAudioHardwarePropertyDevices,
kAudioHardwarePropertyDefaultInputDevice,
kAudioHardwarePropertyDefaultOutputDevice,
kAudioHardwarePropertyDefaultSystemOutputDevice,
kAudioHardwarePropertyDeviceForUID,
kAudioHardwarePropertySleepingIsAllowed,
kAudioHardwarePropertyUnloadingIsAllowed,
kAudioHardwarePropertyHogModeIsAllowed,
kAudioHardwarePropertyRunLoop,
kAudioHardwarePropertyPlugInForBundleID
};
enum {
kAudioObjectPropertyClass,
kAudioObjectPropertyOwner,
kAudioObjectPropertyCreator,
kAudioObjectPropertyName,
kAudioObjectPropertyManufacturer,
kAudioObjectPropertyElementName,
kAudioObjectPropertyElementCategoryName,
kAudioObjectPropertyElementNumberName,
kAudioObjectPropertyOwnedObjects,
kAudioObjectPropertyListenerAdded,
kAudioObjectPropertyListenerRemoved
};
enum {
kAudioDevicePropertyDeviceName,
kAudioDevicePropertyDeviceNameCFString = kAudioObjectPropertyName,
kAudioDevicePropertyDeviceManufacturer,
kAudioDevicePropertyDeviceManufacturerCFString =
kAudioObjectPropertyManufacturer,
kAudioDevicePropertyRegisterBufferList,
kAudioDevicePropertyBufferSize,
kAudioDevicePropertyBufferSizeRange,
kAudioDevicePropertyChannelName,
kAudioDevicePropertyChannelNameCFString = kAudioObjectPropertyElementName,
kAudioDevicePropertyChannelCategoryName,
kAudioDevicePropertyChannelCategoryNameCFString =
kAudioObjectPropertyElementCategoryName,
kAudioDevicePropertyChannelNumberName,
kAudioDevicePropertyChannelNumberNameCFString =
kAudioObjectPropertyElementNumberName,
kAudioDevicePropertySupportsMixing,
kAudioDevicePropertyStreamFormat,
kAudioDevicePropertyStreamFormats,
kAudioDevicePropertyStreamFormatSupported,
kAudioDevicePropertyStreamFormatMatch,
kAudioDevicePropertyDataSourceNameForID,
kAudioDevicePropertyClockSourceNameForID,
kAudioDevicePropertyPlayThruDestinationNameForID,
kAudioDevicePropertyChannelNominalLineLevelNameForID
};
enum {
kAudioDevicePropertyPlugIn,
kAudioDevicePropertyConfigurationApplication,
kAudioDevicePropertyDeviceUID,
kAudioDevicePropertyModelUID,
kAudioDevicePropertyTransportType,
kAudioDevicePropertyRelatedDevices,
kAudioDevicePropertyClockDomain,
kAudioDevicePropertyDeviceIsAlive,
kAudioDevicePropertyDeviceHasChanged,
kAudioDevicePropertyDeviceIsRunning,
kAudioDevicePropertyDeviceIsRunningSomewhere,
kAudioDevicePropertyDeviceCanBeDefaultDevice,
kAudioDevicePropertyDeviceCanBeDefaultSystemDevice,
kAudioDeviceProcessorOverload,
kAudioDevicePropertyHogMode,
kAudioDevicePropertyLatency,
kAudioDevicePropertyBufferFrameSize,
kAudioDevicePropertyBufferFrameSizeRange,
kAudioDevicePropertyUsesVariableBufferFrameSizes,
kAudioDevicePropertyStreams,
kAudioDevicePropertySafetyOffset,
kAudioDevicePropertyIOCycleUsage,
kAudioDevicePropertyStreamConfiguration,
kAudioDevicePropertyIOProcStreamUsage,
kAudioDevicePropertyPreferredChannelsForStereo,
kAudioDevicePropertyPreferredChannelLayout,
kAudioDevicePropertyNominalSampleRate,
kAudioDevicePropertyAvailableNominalSampleRates,
kAudioDevicePropertyActualSampleRate
};
enum {
kAudioFormatLinearPCM,
kAudioFormatAC3,
kAudioFormat60958AC3,
kAudioFormatAppleIMA4,
kAudioFormatMPEG4AAC,
kAudioFormatMPEG4CELP,
kAudioFormatMPEG4HVXC,
kAudioFormatMPEG4TwinVQ,
kAudioFormatMACE3,
kAudioFormatMACE6,
kAudioFormatULaw,
kAudioFormatALaw,
kAudioFormatQDesign,
kAudioFormatQDesign2,
kAudioFormatQUALCOMM,
kAudioFormatMPEGLayer1,
kAudioFormatMPEGLayer2,
kAudioFormatMPEGLayer3,
kAudioFormatDVAudio,
kAudioFormatVariableDurationDVAudio,
kAudioFormatTimeCode,
kAudioFormatMIDIStream,
kAudioFormatParameterValueStream,
kAudioFormatAppleLossless
};
enum {
kAudioFormatFlagIsFloat = (1L << 0),
kAudioFormatFlagIsBigEndian = (1L << 1),
kAudioFormatFlagIsSignedInteger = (1L << 2),
kAudioFormatFlagIsPacked = (1L << 3),
kAudioFormatFlagIsAlignedHigh = (1L << 4),
kAudioFormatFlagIsNonInterleaved = (1L << 5),
kAudioFormatFlagIsNonMixable = (1L << 6),
kLinearPCMFormatFlagIsFloat = kAudioFormatFlagIsFloat,
kLinearPCMFormatFlagIsBigEndian = kAudioFormatFlagIsBigEndian,
kLinearPCMFormatFlagIsSignedInteger = kAudioFormatFlagIsSignedInteger,
kLinearPCMFormatFlagIsPacked = kAudioFormatFlagIsPacked,
kLinearPCMFormatFlagIsAlignedHigh = kAudioFormatFlagIsAlignedHigh,
kLinearPCMFormatFlagIsNonInterleaved = kAudioFormatFlagIsNonInterleaved,
kLinearPCMFormatFlagIsNonMixable = kAudioFormatFlagIsNonMixable,
kAppleLosslessFormatFlag_16BitSourceData = 1,
kAppleLosslessFormatFlag_20BitSourceData = 2,
kAppleLosslessFormatFlag_24BitSourceData = 3,
kAppleLosslessFormatFlag_32BitSourceData = 4
};
enum {
kAudioFormatFlagsNativeEndian = kAudioFormatFlagIsBigEndian,
kAudioFormatFlagsNativeFloatPacked =
kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian |
kAudioFormatFlagIsPacked
};
enum {
kAudioDeviceUnknown
};
enum {
kVariableLengthArray = 1
};
enum {
kAudioHardwareNoError = 0,
noErr = kAudioHardwareNoError
};
enum {
false
};
typedef double Float64;
typedef float Float32;
typedef int SInt32;
typedef int Boolean;
typedef int OSErr;
typedef short SInt16;
typedef unsigned int UInt32;
typedef unsigned long int UInt64;
typedef SInt32 OSStatus;
typedef UInt32 AudioObjectID;
typedef UInt32 AudioHardwarePropertyID;
typedef UInt32 AudioDevicePropertyID;
typedef AudioObjectID AudioDeviceID;
struct AudioStreamBasicDescription {
Float64 mSampleRate;
UInt32 mFormatID;
UInt32 mFormatFlags;
UInt32 mBytesPerPacket;
UInt32 mFramesPerPacket;
UInt32 mBytesPerFrame;
UInt32 mChannelsPerFrame;
UInt32 mBitsPerChannel;
UInt32 mReserved;
};
typedef struct AudioStreamBasicDescription AudioStreamBasicDescription;
struct SMPTETime {
SInt16 mSubframes;
SInt16 mSubframeDivisor;
UInt32 mCounter;
UInt32 mType;
UInt32 mFlags;
SInt16 mHours;
SInt16 mMinutes;
SInt16 mSeconds;
SInt16 mFrames;
};
typedef struct SMPTETime SMPTETime;
struct AudioTimeStamp {
Float64 mSampleTime;
UInt64 mHostTime;
Float64 mRateScalar;
UInt64 mWordClockTime;
SMPTETime mSMPTETime;
UInt32 mFlags;
UInt32 mReserved;
};
typedef struct AudioTimeStamp AudioTimeStamp;
struct AudioBuffer {
UInt32 mNumberChannels;
UInt32 mDataByteSize;
void *mData;
};
typedef struct AudioBuffer AudioBuffer;
struct AudioBufferList {
UInt32 mNumberBuffers;
AudioBuffer mBuffers[kVariableLengthArray];
};
typedef struct AudioBufferList AudioBufferList;
typedef OSStatus(*AudioDeviceIOProc) (AudioDeviceID inDevice,
const AudioTimeStamp * inNow,
const AudioBufferList * inInputData,
const AudioTimeStamp * inInputTime,
AudioBufferList * outOutputData,
const AudioTimeStamp * inOutputTime,
void *inClientData);
OSStatus AudioHardwareGetProperty(AudioHardwarePropertyID inPropertyID,
UInt32 * ioPropertyDataSize,
void *outPropertyData);
OSStatus AudioHardwareGetPropertyInfo(AudioHardwarePropertyID inPropertyID,
UInt32 * ioPropertyDataSize,
void *outPropertyData);
OSStatus AudioDeviceSetProperty(AudioDeviceID inDevice,
const AudioTimeStamp * inWhen,
UInt32 inChannel, Boolean isInput,
AudioDevicePropertyID inPropertyID,
UInt32 inPropertyDataSize,
const void *inPropertyData);
OSStatus AudioDeviceGetProperty(AudioDeviceID inDevice, UInt32 inChannel,
Boolean isInput,
AudioDevicePropertyID inPropertyID,
UInt32 * ioPropertyDataSize,
void *outPropertyData);
OSStatus AudioDeviceAddIOProc(AudioDeviceID inDevice,
AudioDeviceIOProc inProc, void *inClientData);
OSStatus AudioDeviceStart(AudioDeviceID inDevice, AudioDeviceIOProc inProc);
OSStatus AudioDeviceStop(AudioDeviceID inDevice, AudioDeviceIOProc inProc);
#endif

@ -0,0 +1,89 @@
/*
* SoX bit-rot detection file; cobbled together
*/
#define HWAVEIN HANDLE
#define HWAVEOUT HANDLE
#define MMRESULT UINT
#define MMVERSION UINT
#define UNALIGNED
enum {
MMSYSERR_NOERROR,
MAXPNAMELEN,
WAVE_FORMAT_PCM,
WAVE_FORMAT_EXTENSIBLE,
WAVE_FORMAT_QUERY,
WAVE_MAPPER,
WAVERR_STILLPLAYING,
WHDR_DONE,
WHDR_INQUEUE
};
typedef struct wavehdr_tag {
LPSTR lpData;
DWORD dwBufferLength;
DWORD dwBytesRecorded;
DWORD dwUser;
DWORD dwFlags;
DWORD dwLoops;
struct wavehdr_tag *lpNext;
DWORD reserved;
} WAVEHDR,*PWAVEHDR,*LPWAVEHDR;
typedef struct _WAVEFORMATEX {
WORD wFormatTag;
WORD nChannels;
DWORD nSamplesPerSec;
DWORD nAvgBytesPerSec;
WORD nBlockAlign;
WORD wBitsPerSample;
WORD cbSize;
} WAVEFORMATEX, *PWAVEFORMATEX, *NPWAVEFORMATEX, *LPWAVEFORMATEX;
typedef struct tagWAVEINCAPSA {
WORD wMid;
WORD wPid;
MMVERSION vDriverVersion;
CHAR szPname[MAXPNAMELEN];
DWORD dwFormats;
WORD wChannels;
WORD wReserved1;
} WAVEINCAPSA,*PWAVEINCAPSA,*LPWAVEINCAPSA;
typedef struct tagWAVEOUTCAPSA {
WORD wMid;
WORD wPid;
MMVERSION vDriverVersion;
CHAR szPname[MAXPNAMELEN];
DWORD dwFormats;
WORD wChannels;
WORD wReserved1;
DWORD dwSupport;
} WAVEOUTCAPSA,*PWAVEOUTCAPSA,*LPWAVEOUTCAPSA;
MMRESULT WINAPI waveInAddBuffer(HWAVEIN,LPWAVEHDR,UINT);
MMRESULT WINAPI waveInClose(HWAVEIN);
MMRESULT WINAPI waveInGetDevCapsA(UINT,LPWAVEINCAPSA,UINT);
MMRESULT WINAPI waveInGetNumDevs(void);
MMRESULT WINAPI waveInOpen(HWAVEIN*,UINT,WAVEFORMATEX*,DWORD*,DWORD*,DWORD);
MMRESULT WINAPI waveInPrepareHeader(HWAVEIN,LPWAVEHDR,UINT);
MMRESULT WINAPI waveInReset(HWAVEIN);
MMRESULT WINAPI waveInStart(HWAVEIN);
MMRESULT WINAPI waveOutClose(HWAVEOUT);
MMRESULT WINAPI waveOutGetDevCapsA(UINT,LPWAVEOUTCAPSA,UINT);
MMRESULT WINAPI waveOutGetNumDevs(void);
MMRESULT WINAPI waveOutOpen(HWAVEOUT*,UINT,WAVEFORMATEX*,DWORD*,DWORD*,DWORD);
MMRESULT WINAPI waveOutPrepareHeader(HWAVEOUT,LPWAVEHDR,UINT);
MMRESULT WINAPI waveOutReset(HWAVEOUT);
MMRESULT WINAPI waveOutWrite(HWAVEOUT,LPWAVEHDR,UINT);
typedef struct {
WAVEFORMATEX Format;
union {
WORD wValidBitsPerSample;
WORD wSamplesPerBlock;
WORD wReserved;
} Samples;
DWORD dwChannelMask;
GUID SubFormat;
} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;

@ -0,0 +1,160 @@
#ifndef HAVE_SNDIO
/*
* SoX bit-rot detection file, obtained from:
* http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libsndio/sndio.h
*/
#if defined __GNUC__
#pragma GCC system_header
#endif
/* $OpenBSD: sndio.h,v 1.7 2009/02/03 19:44:58 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef SNDIO_H
#define SNDIO_H
#include <sys/param.h>
/*
* private ``handle'' structure
*/
struct sio_hdl;
/*
* parameters of a full-duplex stream
*/
struct sio_par {
unsigned bits; /* bits per sample */
unsigned bps; /* bytes per sample */
unsigned sig; /* 1 = signed, 0 = unsigned */
unsigned le; /* 1 = LE, 0 = BE byte order */
unsigned msb; /* 1 = MSB, 0 = LSB aligned */
unsigned rchan; /* number channels for recording direction */
unsigned pchan; /* number channels for playback direction */
unsigned rate; /* frames per second */
unsigned bufsz; /* end-to-end buffer size */
#define SIO_IGNORE 0 /* pause during xrun */
#define SIO_SYNC 1 /* resync after xrun */
#define SIO_ERROR 2 /* terminate on xrun */
unsigned xrun; /* what to do on overruns/underruns */
unsigned round; /* optimal bufsz divisor */
unsigned appbufsz; /* minimum buffer size */
int __pad[3]; /* for future use */
int __magic; /* for internal/debug purposes only */
};
/*
* capabilities of a stream
*/
struct sio_cap {
#define SIO_NENC 8
#define SIO_NCHAN 8
#define SIO_NRATE 16
#define SIO_NCONF 4
struct sio_enc { /* allowed sample encodings */
unsigned bits;
unsigned bps;
unsigned sig;
unsigned le;
unsigned msb;
} enc[SIO_NENC];
unsigned rchan[SIO_NCHAN]; /* allowed values for rchan */
unsigned pchan[SIO_NCHAN]; /* allowed values for pchan */
unsigned rate[SIO_NRATE]; /* allowed rates */
int __pad[7]; /* for future use */
unsigned nconf; /* number of elements in confs[] */
struct sio_conf {
unsigned enc; /* mask of enc[] indexes */
unsigned rchan; /* mask of chan[] indexes (rec) */
unsigned pchan; /* mask of chan[] indexes (play) */
unsigned rate; /* mask of rate[] indexes */
} confs[SIO_NCONF];
};
#define SIO_XSTRINGS { "ignore", "sync", "error" }
/*
* mode bitmap
*/
#define SIO_PLAY 1
#define SIO_REC 2
/*
* maximum size of the encording string (the longest possible
* encoding is ``s24le3msb'')
*/
#define SIO_ENCMAX 10
/*
* default bytes per sample for the given bits per sample
*/
#define SIO_BPS(bits) (((bits) <= 8) ? 1 : (((bits) <= 16) ? 2 : 4))
/*
* default value of "sio_par->le" flag
*/
#if BYTE_ORDER == LITTLE_ENDIAN
#define SIO_LE_NATIVE 1
#else
#define SIO_LE_NATIVE 0
#endif
/*
* default device for the sun audio(4) back-end
*/
#define SIO_SUN_PATH "/dev/audio"
/*
* default socket name for the aucat(1) back-end
*/
#define SIO_AUCAT_PATH "default"
/*
* maximum value of volume, eg. for sio_setvol()
*/
#define SIO_MAXVOL 127
#ifdef __cplusplus
extern "C" {
#endif
int sio_strtoenc(struct sio_par *, char *);
int sio_enctostr(struct sio_par *, char *);
void sio_initpar(struct sio_par *);
struct sio_hdl *sio_open(char *, unsigned, int);
void sio_close(struct sio_hdl *);
int sio_setpar(struct sio_hdl *, struct sio_par *);
int sio_getpar(struct sio_hdl *, struct sio_par *);
int sio_getcap(struct sio_hdl *, struct sio_cap *);
void sio_onmove(struct sio_hdl *, void (*)(void *, int), void *);
size_t sio_write(struct sio_hdl *, void *, size_t);
size_t sio_read(struct sio_hdl *, void *, size_t);
int sio_start(struct sio_hdl *);
int sio_stop(struct sio_hdl *);
int sio_nfds(struct sio_hdl *);
int sio_pollfd(struct sio_hdl *, struct pollfd *, int);
int sio_revents(struct sio_hdl *, struct pollfd *);
int sio_eof(struct sio_hdl *);
int sio_setvol(struct sio_hdl *, unsigned);
void sio_onvol(struct sio_hdl *, void (*)(void *, unsigned), void *);
#ifdef __cplusplus
}
#endif
#endif /* !defined(SNDIO_H) */
#endif

@ -0,0 +1,289 @@
#ifndef HAVE_SUN_AUDIO
/*
* SoX bit-rot detection file, obtained from: Solaris 9 /usr/include/sys
*/
#if defined __GNUC__
#pragma GCC system_header
#endif
/*
* Copyright (c) 1995-2001 by Sun Microsystems, Inc.
* All rights reserved.
*/
#ifndef _SYS_AUDIOIO_H
#define _SYS_AUDIOIO_H
#pragma ident "@(#)audioio.h 1.30 01/01/10 SMI"
#include <sys/types.h>
#if 0
#include <sys/types32.h>
#include <sys/time.h>
#include <sys/ioccom.h>
#else
#define ushort_t unsigned short
#define uint_t unsigned int
#define uchar_t unsigned char
struct timeval32
{
unsigned tv_sec;
unsigned tv_usec;
};
#endif
/*
* These are the ioctl calls for all Solaris audio devices, including
* the x86 and SPARCstation audio devices.
*
* You are encouraged to design your code in a modular fashion so that
* future changes to the interface can be incorporated with little
* trouble.
*/
#ifdef __cplusplus
extern "C" {
#endif
/*
* This structure contains state information for audio device IO streams.
*/
struct audio_prinfo {
/*
* The following values describe the audio data encoding.
*/
uint_t sample_rate; /* samples per second */
uint_t channels; /* number of interleaved channels */
uint_t precision; /* bit-width of each sample */
uint_t encoding; /* data encoding method */
/*
* The following values control audio device configuration
*/
uint_t gain; /* gain level: 0 - 255 */
uint_t port; /* selected I/O port (see below) */
uint_t avail_ports; /* available I/O ports (see below) */
uint_t mod_ports; /* I/O ports that are modifiable (see below) */
uint_t _xxx; /* Reserved for future use */
uint_t buffer_size; /* I/O buffer size */
/*
* The following values describe driver state
*/
uint_t samples; /* number of samples converted */
uint_t eof; /* End Of File counter (play only) */
uchar_t pause; /* non-zero for pause, zero to resume */
uchar_t error; /* non-zero if overflow/underflow */
uchar_t waiting; /* non-zero if a process wants access */
uchar_t balance; /* stereo channel balance */
ushort_t minordev;
/*
* The following values are read-only state flags
*/
uchar_t open; /* non-zero if open access permitted */
uchar_t active; /* non-zero if I/O is active */
};
typedef struct audio_prinfo audio_prinfo_t;
/*
* This structure describes the current state of the audio device.
*/
struct audio_info {
/*
* Per-stream information
*/
audio_prinfo_t play; /* output status information */
audio_prinfo_t record; /* input status information */
/*
* Per-unit/channel information
*/
uint_t monitor_gain; /* input to output mix: 0 - 255 */
uchar_t output_muted; /* non-zero if output is muted */
uchar_t ref_cnt; /* driver reference count, read only */
uchar_t _xxx[2]; /* Reserved for future use */
uint_t hw_features; /* hardware features this driver supports */
uint_t sw_features; /* supported SW features */
uint_t sw_features_enabled; /* supported SW feat. enabled */
};
typedef struct audio_info audio_info_t;
/*
* Audio encoding types
*/
#define AUDIO_ENCODING_NONE (0) /* no encoding assigned */
#define AUDIO_ENCODING_ULAW (1) /* u-law encoding */
#define AUDIO_ENCODING_ALAW (2) /* A-law encoding */
#define AUDIO_ENCODING_LINEAR (3) /* Signed Linear PCM encoding */
#define AUDIO_ENCODING_DVI (104) /* DVI ADPCM */
#define AUDIO_ENCODING_LINEAR8 (105) /* 8 bit UNSIGNED */
/*
* These ranges apply to record, play, and monitor gain values
*/
#define AUDIO_MIN_GAIN (0) /* minimum gain value */
#define AUDIO_MAX_GAIN (255) /* maximum gain value */
#define AUDIO_MID_GAIN (AUDIO_MAX_GAIN / 2)
/*
* These values apply to the balance field to adjust channel gain values
*/
#define AUDIO_LEFT_BALANCE (0) /* left channel only */
#define AUDIO_MID_BALANCE (32) /* equal left/right channel */
#define AUDIO_RIGHT_BALANCE (64) /* right channel only */
#define AUDIO_BALANCE_SHIFT (3)
/*
* Generic minimum/maximum limits for number of channels, both modes
*/
#define AUDIO_CHANNELS_MONO (1)
#define AUDIO_CHANNELS_STEREO (2)
#define AUDIO_MIN_PLAY_CHANNELS (AUDIO_CHANNELS_MONO)
#define AUDIO_MAX_PLAY_CHANNELS (AUDIO_CHANNELS_STEREO)
#define AUDIO_MIN_REC_CHANNELS (AUDIO_CHANNELS_MONO)
#define AUDIO_MAX_REC_CHANNELS (AUDIO_CHANNELS_STEREO)
/*
* Generic minimum/maximum limits for sample precision
*/
#define AUDIO_PRECISION_8 (8)
#define AUDIO_PRECISION_16 (16)
#define AUDIO_MIN_PLAY_PRECISION (8)
#define AUDIO_MAX_PLAY_PRECISION (32)
#define AUDIO_MIN_REC_PRECISION (8)
#define AUDIO_MAX_REC_PRECISION (32)
/*
* Define some convenient names for typical audio ports
*/
#define AUDIO_NONE 0x00 /* all ports off */
/*
* output ports (several may be enabled simultaneously)
*/
#define AUDIO_SPEAKER 0x01 /* output to built-in speaker */
#define AUDIO_HEADPHONE 0x02 /* output to headphone jack */
#define AUDIO_LINE_OUT 0x04 /* output to line out */
#define AUDIO_SPDIF_OUT 0x08 /* output to SPDIF port */
#define AUDIO_AUX1_OUT 0x10 /* output to aux1 out */
#define AUDIO_AUX2_OUT 0x20 /* output to aux2 out */
/*
* input ports (usually only one at a time)
*/
#define AUDIO_MICROPHONE 0x01 /* input from microphone */
#define AUDIO_LINE_IN 0x02 /* input from line in */
#define AUDIO_CD 0x04 /* input from on-board CD inputs */
#define AUDIO_INTERNAL_CD_IN AUDIO_CD /* input from internal CDROM */
#define AUDIO_SPDIF_IN 0x08 /* input from SPDIF port */
#define AUDIO_AUX1_IN 0x10 /* input from aux1 in */
#define AUDIO_AUX2_IN 0x20 /* input from aux2 in */
#define AUDIO_CODEC_LOOPB_IN 0x40 /* input from Codec internal loopback */
#define AUDIO_SUNVTS 0x80 /* SunVTS input setting-internal LB */
/*
* Define the hw_features
*/
#define AUDIO_HWFEATURE_DUPLEX 0x00000001u /* simult. play & rec support */
#define AUDIO_HWFEATURE_MSCODEC 0x00000002u /* multi-stream Codec */
#define AUDIO_HWFEATURE_IN2OUT 0x00000004u /* input to output loopback */
#define AUDIO_HWFEATURE_PLAY 0x00000008u /* device supports play */
#define AUDIO_HWFEATURE_RECORD 0x00000010u /* device supports record */
/*
* Define the sw_features
*/
#define AUDIO_SWFEATURE_MIXER 0x00000001u /* audio mixer audio pers mod */
/*
* This macro initializes an audio_info structure to 'harmless' values.
* Note that (~0) might not be a harmless value for a flag that was
* a signed int.
*/
#define AUDIO_INITINFO(i) { \
uint_t *__x__; \
for (__x__ = (uint_t *)(i); \
(char *)__x__ < (((char *)(i)) + sizeof (audio_info_t)); \
*__x__++ = ~0); \
}
/*
* Parameter for the AUDIO_GETDEV ioctl to determine current
* audio devices.
*/
#define MAX_AUDIO_DEV_LEN (16)
struct audio_device {
char name[MAX_AUDIO_DEV_LEN];
char version[MAX_AUDIO_DEV_LEN];
char config[MAX_AUDIO_DEV_LEN];
};
typedef struct audio_device audio_device_t;
/*
* Ioctl calls for the audio device.
*/
/*
* AUDIO_GETINFO retrieves the current state of the audio device.
*
* AUDIO_SETINFO copies all fields of the audio_info structure whose
* values are not set to the initialized value (-1) to the device state.
* It performs an implicit AUDIO_GETINFO to return the new state of the
* device. Note that the record.samples and play.samples fields are set
* to the last value before the AUDIO_SETINFO took effect. This allows
* an application to reset the counters while atomically retrieving the
* last value.
*
* AUDIO_DRAIN suspends the calling process until the write buffers are
* empty.
*
* AUDIO_GETDEV returns a structure of type audio_device_t which contains
* three strings. The string "name" is a short identifying string (for
* example, the SBus Fcode name string), the string "version" identifies
* the current version of the device, and the "config" string identifies
* the specific configuration of the audio stream. All fields are
* device-dependent -- see the device specific manual pages for details.
*/
#define AUDIO_GETINFO _IOR('A', 1, audio_info_t)
#define AUDIO_SETINFO _IOWR('A', 2, audio_info_t)
#define AUDIO_DRAIN _IO('A', 3)
#define AUDIO_GETDEV _IOR('A', 4, audio_device_t)
/*
* The following ioctl sets the audio device into an internal loopback mode,
* if the hardware supports this. The argument is TRUE to set loopback,
* FALSE to reset to normal operation. If the hardware does not support
* internal loopback, the ioctl should fail with EINVAL.
*/
#define AUDIO_DIAG_LOOPBACK _IOW('A', 101, int)
/*
* Structure sent up as a M_PROTO message on trace streams
*/
struct audtrace_hdr {
uint_t seq; /* Sequence number (per-aud_stream) */
int type; /* device-dependent */
#if defined(_LP64) || defined(_I32LPx)
struct timeval32 timestamp;
#else
struct timeval timestamp;
#endif
char _f[8]; /* filler */
};
typedef struct audtrace_hdr audtrace_hdr_t;
#ifdef __cplusplus
}
#endif
#endif /* _SYS_AUDIOIO_H */
#endif

@ -0,0 +1,34 @@
/*
* SoX bit-rot detection file; cobbled together
*/
#define BYTE uint8_t
#define CHAR char
#define DWORD_PTR DWORD *
#define DWORD uint32_t
#define HANDLE void *
#define LPCSTR char *
#define LPCVOID void *
#define LPDWORD DWORD *
#define LPSTR char const *
#define UINT DWORD
#define WCHAR int16_t
#define WINAPI
#define WIN_BOOL int
#define WORD uint16_t
typedef char GUID[16];
enum {
FALSE,
TRUE,
FORMAT_MESSAGE_FROM_SYSTEM,
FORMAT_MESSAGE_IGNORE_INSERTS,
INFINITE,
CALLBACK_EVENT
};
DWORD CloseHandle(HANDLE);
DWORD FormatMessageA(DWORD,LPCVOID,DWORD,DWORD,LPSTR, DWORD,LPDWORD);
DWORD GetLastError(void);
DWORD WaitForSingleObject(HANDLE, DWORD);
HANDLE CreateEventA(LPCVOID,WIN_BOOL,WIN_BOOL,LPCSTR);

@ -0,0 +1,35 @@
/* libSoX file format: CAF Copyright (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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
LSX_FORMAT_HANDLER(caf)
{
static char const * const names[] = {"caf", NULL};
static unsigned const write_encodings[] = {
SOX_ENCODING_SIGN2, 16, 24, 32, 8, 0,
SOX_ENCODING_FLOAT, 32, 64, 0,
SOX_ENCODING_ALAW, 8, 0,
SOX_ENCODING_ULAW, 8, 0,
0};
static sox_format_handler_t handler;
handler = *lsx_sndfile_format_fn();
handler.description = "Apples's Core Audio Format";
handler.names = names;
handler.write_formats = write_encodings;
return &handler;
}

@ -0,0 +1,49 @@
/* libSoX file format: cdda (c) 2006-8 SoX contributors
* Based on an original idea by David Elliott
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
static int start(sox_format_t * ft)
{
return lsx_check_read_params(ft, 2, 44100., SOX_ENCODING_SIGN2, 16, (uint64_t)0, sox_true);
}
static int stopwrite(sox_format_t * ft)
{
unsigned const sector_num_samples = 588 * ft->signal.channels;
unsigned i = ft->olength % sector_num_samples;
if (i) while (i++ < sector_num_samples) /* Pad with silence to multiple */
lsx_writew(ft, 0); /* of 1/75th of a second. */
return SOX_SUCCESS;
}
LSX_FORMAT_HANDLER(cdr)
{
static char const * const names[] = {"cdda", "cdr", NULL};
static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 16, 0, 0};
static sox_rate_t const write_rates[] = {44100, 0};
static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE,
"Red Book Compact Disc Digital Audio",
names, SOX_FILE_BIG_END|SOX_FILE_STEREO,
start, lsx_rawread, NULL,
NULL, lsx_rawwrite, stopwrite,
lsx_rawseek, write_encodings, write_rates, 0
};
return &handler;
}

@ -0,0 +1,351 @@
/* August 24, 1998
* Copyright (C) 1998 Juergen Mueller And Sundry Contributors
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
* Juergen Mueller And Sundry Contributors are not responsible for
* the consequences of using this software.
*/
/*
* Chorus effect.
*
* Flow diagram scheme for n delays ( 1 <= n <= MAX_CHORUS ):
*
* * gain-in ___
* ibuff -----+--------------------------------------------->| |
* | _________ | |
* | | | * decay 1 | |
* +---->| delay 1 |----------------------------->| |
* | |_________| | |
* | /|\ | |
* : | | |
* : +-----------------+ +--------------+ | + |
* : | Delay control 1 |<--| mod. speed 1 | | |
* : +-----------------+ +--------------+ | |
* | _________ | |
* | | | * decay n | |
* +---->| delay n |----------------------------->| |
* |_________| | |
* /|\ |___|
* | |
* +-----------------+ +--------------+ | * gain-out
* | Delay control n |<--| mod. speed n | |
* +-----------------+ +--------------+ +----->obuff
*
*
* The delay i is controled by a sine or triangle modulation i ( 1 <= i <= n).
*
* Usage:
* chorus gain-in gain-out delay-1 decay-1 speed-1 depth-1 -s1|t1 [
* delay-2 decay-2 speed-2 depth-2 -s2|-t2 ... ]
*
* Where:
* gain-in, decay-1 ... decay-n : 0.0 ... 1.0 volume
* gain-out : 0.0 ... volume
* delay-1 ... delay-n : 20.0 ... 100.0 msec
* speed-1 ... speed-n : 0.1 ... 5.0 Hz modulation 1 ... n
* depth-1 ... depth-n : 0.0 ... 10.0 msec modulated delay 1 ... n
* -s1 ... -sn : modulation by sine 1 ... n
* -t1 ... -tn : modulation by triangle 1 ... n
*
* Note:
* when decay is close to 1.0, the samples can begin clipping and the output
* can saturate!
*
* Hint:
* 1 / out-gain < gain-in ( 1 + decay-1 + ... + decay-n )
*
*/
/*
* libSoX chorus effect file.
*/
#include "sox_i.h"
#include <stdlib.h> /* Harmless, and prototypes atof() etc. --dgc */
#include <string.h>
#define MOD_SINE 0
#define MOD_TRIANGLE 1
#define MAX_CHORUS 7
typedef struct {
int num_chorus;
int modulation[MAX_CHORUS];
int counter;
long phase[MAX_CHORUS];
float *chorusbuf;
float in_gain, out_gain;
float delay[MAX_CHORUS], decay[MAX_CHORUS];
float speed[MAX_CHORUS], depth[MAX_CHORUS];
long length[MAX_CHORUS];
int *lookup_tab[MAX_CHORUS];
int depth_samples[MAX_CHORUS], samples[MAX_CHORUS];
int maxsamples;
unsigned int fade_out;
} priv_t;
/*
* Process options
*/
static int sox_chorus_getopts(sox_effect_t * effp, int argc, char **argv)
{
priv_t * chorus = (priv_t *) effp->priv;
int i;
--argc, ++argv;
chorus->num_chorus = 0;
i = 0;
if ( ( argc < 7 ) || (( argc - 2 ) % 5 ) )
return lsx_usage(effp);
sscanf(argv[i++], "%f", &chorus->in_gain);
sscanf(argv[i++], "%f", &chorus->out_gain);
while ( i < argc ) {
if ( chorus->num_chorus > MAX_CHORUS )
{
lsx_fail("chorus: to many delays, use less than %i delays", MAX_CHORUS);
return (SOX_EOF);
}
sscanf(argv[i++], "%f", &chorus->delay[chorus->num_chorus]);
sscanf(argv[i++], "%f", &chorus->decay[chorus->num_chorus]);
sscanf(argv[i++], "%f", &chorus->speed[chorus->num_chorus]);
sscanf(argv[i++], "%f", &chorus->depth[chorus->num_chorus]);
if ( !strcmp(argv[i], "-s"))
chorus->modulation[chorus->num_chorus] = MOD_SINE;
else if ( ! strcmp(argv[i], "-t"))
chorus->modulation[chorus->num_chorus] = MOD_TRIANGLE;
else
return lsx_usage(effp);
i++;
chorus->num_chorus++;
}
return (SOX_SUCCESS);
}
/*
* Prepare for processing.
*/
static int sox_chorus_start(sox_effect_t * effp)
{
priv_t * chorus = (priv_t *) effp->priv;
int i;
float sum_in_volume;
chorus->maxsamples = 0;
if ( chorus->in_gain < 0.0 )
{
lsx_fail("chorus: gain-in must be positive!");
return (SOX_EOF);
}
if ( chorus->in_gain > 1.0 )
{
lsx_fail("chorus: gain-in must be less than 1.0!");
return (SOX_EOF);
}
if ( chorus->out_gain < 0.0 )
{
lsx_fail("chorus: gain-out must be positive!");
return (SOX_EOF);
}
for ( i = 0; i < chorus->num_chorus; i++ ) {
chorus->samples[i] = (int) ( ( chorus->delay[i] +
chorus->depth[i] ) * effp->in_signal.rate / 1000.0);
chorus->depth_samples[i] = (int) (chorus->depth[i] *
effp->in_signal.rate / 1000.0);
if ( chorus->delay[i] < 20.0 )
{
lsx_fail("chorus: delay must be more than 20.0 msec!");
return (SOX_EOF);
}
if ( chorus->delay[i] > 100.0 )
{
lsx_fail("chorus: delay must be less than 100.0 msec!");
return (SOX_EOF);
}
if ( chorus->speed[i] < 0.1 )
{
lsx_fail("chorus: speed must be more than 0.1 Hz!");
return (SOX_EOF);
}
if ( chorus->speed[i] > 5.0 )
{
lsx_fail("chorus: speed must be less than 5.0 Hz!");
return (SOX_EOF);
}
if ( chorus->depth[i] < 0.0 )
{
lsx_fail("chorus: delay must be more positive!");
return (SOX_EOF);
}
if ( chorus->depth[i] > 10.0 )
{
lsx_fail("chorus: delay must be less than 10.0 msec!");
return (SOX_EOF);
}
if ( chorus->decay[i] < 0.0 )
{
lsx_fail("chorus: decay must be positive!" );
return (SOX_EOF);
}
if ( chorus->decay[i] > 1.0 )
{
lsx_fail("chorus: decay must be less that 1.0!" );
return (SOX_EOF);
}
chorus->length[i] = effp->in_signal.rate / chorus->speed[i];
chorus->lookup_tab[i] = lsx_malloc(sizeof (int) * chorus->length[i]);
if (chorus->modulation[i] == MOD_SINE)
lsx_generate_wave_table(SOX_WAVE_SINE, SOX_INT, chorus->lookup_tab[i],
(size_t)chorus->length[i], 0., (double)chorus->depth_samples[i], 0.);
else
lsx_generate_wave_table(SOX_WAVE_TRIANGLE, SOX_INT, chorus->lookup_tab[i],
(size_t)chorus->length[i],
(double)(chorus->samples[i] - 1 - 2 * chorus->depth_samples[i]),
(double)(chorus->samples[i] - 1), 3 * M_PI_2);
chorus->phase[i] = 0;
if ( chorus->samples[i] > chorus->maxsamples )
chorus->maxsamples = chorus->samples[i];
}
/* Be nice and check the hint with warning, if... */
sum_in_volume = 1.0;
for ( i = 0; i < chorus->num_chorus; i++ )
sum_in_volume += chorus->decay[i];
if ( chorus->in_gain * ( sum_in_volume ) > 1.0 / chorus->out_gain )
lsx_warn("chorus: warning >>> gain-out can cause saturation or clipping of output <<<");
chorus->chorusbuf = lsx_malloc(sizeof (float) * chorus->maxsamples);
for ( i = 0; i < chorus->maxsamples; i++ )
chorus->chorusbuf[i] = 0.0;
chorus->counter = 0;
chorus->fade_out = chorus->maxsamples;
effp->out_signal.length = SOX_UNKNOWN_LEN; /* TODO: calculate actual length */
return (SOX_SUCCESS);
}
/*
* Processed signed long samples from ibuf to obuf.
* Return number of samples processed.
*/
static int sox_chorus_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,
size_t *isamp, size_t *osamp)
{
priv_t * chorus = (priv_t *) effp->priv;
int i;
float d_in, d_out;
sox_sample_t out;
size_t len = min(*isamp, *osamp);
*isamp = *osamp = len;
while (len--) {
/* Store delays as 24-bit signed longs */
d_in = (float) *ibuf++ / 256;
/* Compute output first */
d_out = d_in * chorus->in_gain;
for ( i = 0; i < chorus->num_chorus; i++ )
d_out += chorus->chorusbuf[(chorus->maxsamples +
chorus->counter - chorus->lookup_tab[i][chorus->phase[i]]) %
chorus->maxsamples] * chorus->decay[i];
/* Adjust the output volume and size to 24 bit */
d_out = d_out * chorus->out_gain;
out = SOX_24BIT_CLIP_COUNT((sox_sample_t) d_out, effp->clips);
*obuf++ = out * 256;
/* Mix decay of delay and input */
chorus->chorusbuf[chorus->counter] = d_in;
chorus->counter =
( chorus->counter + 1 ) % chorus->maxsamples;
for ( i = 0; i < chorus->num_chorus; i++ )
chorus->phase[i] =
( chorus->phase[i] + 1 ) % chorus->length[i];
}
/* processed all samples */
return (SOX_SUCCESS);
}
/*
* Drain out reverb lines.
*/
static int sox_chorus_drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp)
{
priv_t * chorus = (priv_t *) effp->priv;
size_t done;
int i;
float d_in, d_out;
sox_sample_t out;
done = 0;
while ( ( done < *osamp ) && ( done < chorus->fade_out ) ) {
d_in = 0;
d_out = 0;
/* Compute output first */
for ( i = 0; i < chorus->num_chorus; i++ )
d_out += chorus->chorusbuf[(chorus->maxsamples +
chorus->counter - chorus->lookup_tab[i][chorus->phase[i]]) %
chorus->maxsamples] * chorus->decay[i];
/* Adjust the output volume and size to 24 bit */
d_out = d_out * chorus->out_gain;
out = SOX_24BIT_CLIP_COUNT((sox_sample_t) d_out, effp->clips);
*obuf++ = out * 256;
/* Mix decay of delay and input */
chorus->chorusbuf[chorus->counter] = d_in;
chorus->counter =
( chorus->counter + 1 ) % chorus->maxsamples;
for ( i = 0; i < chorus->num_chorus; i++ )
chorus->phase[i] =
( chorus->phase[i] + 1 ) % chorus->length[i];
done++;
chorus->fade_out--;
}
/* samples played, it remains */
*osamp = done;
if (chorus->fade_out == 0)
return SOX_EOF;
else
return SOX_SUCCESS;
}
/*
* Clean up chorus effect.
*/
static int sox_chorus_stop(sox_effect_t * effp)
{
priv_t * chorus = (priv_t *) effp->priv;
int i;
free(chorus->chorusbuf);
chorus->chorusbuf = NULL;
for ( i = 0; i < chorus->num_chorus; i++ ) {
free(chorus->lookup_tab[i]);
chorus->lookup_tab[i] = NULL;
}
return (SOX_SUCCESS);
}
static sox_effect_handler_t sox_chorus_effect = {
"chorus",
"gain-in gain-out delay decay speed depth [ -s | -t ]",
SOX_EFF_LENGTH | SOX_EFF_GAIN,
sox_chorus_getopts,
sox_chorus_start,
sox_chorus_flow,
sox_chorus_drain,
sox_chorus_stop,
NULL, sizeof(priv_t)
};
const sox_effect_handler_t *lsx_chorus_effect_fn(void)
{
return &sox_chorus_effect;
}

@ -0,0 +1,293 @@
/* libSoX compander effect
*
* Written by Nick Bailey (nick@bailey-family.org.uk or
* n.bailey@elec.gla.ac.uk)
*
* Copyright 1999 Chris Bagwell And Nick Bailey
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
* Chris Bagwell And Nick Bailey are not responsible for
* the consequences of using this software.
*/
#include "sox_i.h"
#include <string.h>
#include <stdlib.h>
#include "compandt.h"
/*
* Compressor/expander effect for libSoX.
*
* Flow diagram for one channel:
*
* ------------ ---------------
* | | | | ---
* ibuff ---+---| integrator |--->| transfer func |--->| |
* | | | | | | |
* | ------------ --------------- | | * gain
* | | * |----------->obuff
* | ------- | |
* | | | | |
* +----->| delay |-------------------------->| |
* | | ---
* -------
*/
#define compand_usage \
"attack1,decay1{,attack2,decay2} [soft-knee-dB:]in-dB1[,out-dB1]{,in-dB2,out-dB2} [gain [initial-volume-dB [delay]]]\n" \
"\twhere {} means optional and repeatable and [] means optional.\n" \
"\tdB values are floating point or -inf'; times are in seconds."
/*
* Note: clipping can occur if the transfer function pushes things too
* close to 0 dB. In that case, use a negative gain, or reduce the
* output level of the transfer function.
*/
typedef struct {
sox_compandt_t transfer_fn;
struct {
double attack_times[2]; /* 0:attack_time, 1:decay_time */
double volume; /* Current "volume" of each channel */
} * channels;
unsigned expectedChannels;/* Also flags that channels aren't to be treated
individually when = 1 and input not mono */
double delay; /* Delay to apply before companding */
sox_sample_t *delay_buf; /* Old samples, used for delay processing */
ptrdiff_t delay_buf_size;/* Size of delay_buf in samples */
ptrdiff_t delay_buf_index; /* Index into delay_buf */
ptrdiff_t delay_buf_cnt; /* No. of active entries in delay_buf */
int delay_buf_full; /* Shows buffer situation (important for drain) */
char *arg0; /* copies of arguments, so that they may be modified */
char *arg1;
char *arg2;
} priv_t;
static int getopts(sox_effect_t * effp, int argc, char * * argv)
{
priv_t * l = (priv_t *) effp->priv;
char * s;
char dummy; /* To check for extraneous chars. */
unsigned pairs, i, j, commas;
--argc, ++argv;
if (argc < 2 || argc > 5)
return lsx_usage(effp);
l->arg0 = lsx_strdup(argv[0]);
l->arg1 = lsx_strdup(argv[1]);
l->arg2 = argc > 2 ? lsx_strdup(argv[2]) : NULL;
/* Start by checking the attack and decay rates */
for (s = l->arg0, commas = 0; *s; ++s) if (*s == ',') ++commas;
if ((commas % 2) == 0) {
lsx_fail("there must be an even number of attack/decay parameters");
return SOX_EOF;
}
pairs = 1 + commas/2;
l->channels = lsx_calloc(pairs, sizeof(*l->channels));
l->expectedChannels = pairs;
/* Now tokenise the rates string and set up these arrays. Keep
them in seconds at the moment: we don't know the sample rate yet. */
for (i = 0, s = strtok(l->arg0, ","); s != NULL; ++i) {
for (j = 0; j < 2; ++j) {
if (sscanf(s, "%lf %c", &l->channels[i].attack_times[j], &dummy) != 1) {
lsx_fail("syntax error trying to read attack/decay time");
return SOX_EOF;
} else if (l->channels[i].attack_times[j] < 0) {
lsx_fail("attack & decay times can't be less than 0 seconds");
return SOX_EOF;
}
s = strtok(NULL, ",");
}
}
if (!lsx_compandt_parse(&l->transfer_fn, l->arg1, l->arg2))
return SOX_EOF;
/* Set the initial "volume" to be attibuted to the input channels.
Unless specified, choose 0dB otherwise clipping will
result if the user has seleced a long attack time */
for (i = 0; i < l->expectedChannels; ++i) {
double init_vol_dB = 0;
if (argc > 3 && sscanf(argv[3], "%lf %c", &init_vol_dB, &dummy) != 1) {
lsx_fail("syntax error trying to read initial volume");
return SOX_EOF;
} else if (init_vol_dB > 0) {
lsx_fail("initial volume is relative to maximum volume so can't exceed 0dB");
return SOX_EOF;
}
l->channels[i].volume = pow(10., init_vol_dB / 20);
}
/* If there is a delay, store it. */
if (argc > 4 && sscanf(argv[4], "%lf %c", &l->delay, &dummy) != 1) {
lsx_fail("syntax error trying to read delay value");
return SOX_EOF;
} else if (l->delay < 0) {
lsx_fail("delay can't be less than 0 seconds");
return SOX_EOF;
}
return SOX_SUCCESS;
}
static int start(sox_effect_t * effp)
{
priv_t * l = (priv_t *) effp->priv;
unsigned i, j;
lsx_debug("%i input channel(s) expected: actually %i",
l->expectedChannels, effp->out_signal.channels);
for (i = 0; i < l->expectedChannels; ++i)
lsx_debug("Channel %i: attack = %g decay = %g", i,
l->channels[i].attack_times[0], l->channels[i].attack_times[1]);
if (!lsx_compandt_show(&l->transfer_fn, effp->global_info->plot))
return SOX_EOF;
/* Convert attack and decay rates using number of samples */
for (i = 0; i < l->expectedChannels; ++i)
for (j = 0; j < 2; ++j)
if (l->channels[i].attack_times[j] > 1.0/effp->out_signal.rate)
l->channels[i].attack_times[j] = 1.0 -
exp(-1.0/(effp->out_signal.rate * l->channels[i].attack_times[j]));
else
l->channels[i].attack_times[j] = 1.0;
/* Allocate the delay buffer */
l->delay_buf_size = l->delay * effp->out_signal.rate * effp->out_signal.channels;
if (l->delay_buf_size > 0)
l->delay_buf = lsx_calloc((size_t)l->delay_buf_size, sizeof(*l->delay_buf));
l->delay_buf_index = 0;
l->delay_buf_cnt = 0;
l->delay_buf_full= 0;
return SOX_SUCCESS;
}
/*
* Update a volume value using the given sample
* value, the attack rate and decay rate
*/
static void doVolume(double *v, double samp, priv_t * l, int chan)
{
double s = -samp / SOX_SAMPLE_MIN;
double delta = s - *v;
if (delta > 0.0) /* increase volume according to attack rate */
*v += delta * l->channels[chan].attack_times[0];
else /* reduce volume according to decay rate */
*v += delta * l->channels[chan].attack_times[1];
}
static int flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,
size_t *isamp, size_t *osamp)
{
priv_t * l = (priv_t *) effp->priv;
int len = (*isamp > *osamp) ? *osamp : *isamp;
int filechans = effp->out_signal.channels;
int idone,odone;
for (idone = 0,odone = 0; idone < len; ibuf += filechans) {
int chan;
/* Maintain the volume fields by simulating a leaky pump circuit */
for (chan = 0; chan < filechans; ++chan) {
if (l->expectedChannels == 1 && filechans > 1) {
/* User is expecting same compander for all channels */
int i;
double maxsamp = 0.0;
for (i = 0; i < filechans; ++i) {
double rect = fabs((double)ibuf[i]);
if (rect > maxsamp) maxsamp = rect;
}
doVolume(&l->channels[0].volume, maxsamp, l, 0);
break;
} else
doVolume(&l->channels[chan].volume, fabs((double)ibuf[chan]), l, chan);
}
/* Volume memory is updated: perform compand */
for (chan = 0; chan < filechans; ++chan) {
int ch = l->expectedChannels > 1 ? chan : 0;
double level_in_lin = l->channels[ch].volume;
double level_out_lin = lsx_compandt(&l->transfer_fn, level_in_lin);
double checkbuf;
if (l->delay_buf_size <= 0) {
checkbuf = ibuf[chan] * level_out_lin;
SOX_SAMPLE_CLIP_COUNT(checkbuf, effp->clips);
obuf[odone++] = checkbuf;
idone++;
} else {
if (l->delay_buf_cnt >= l->delay_buf_size) {
l->delay_buf_full=1; /* delay buffer is now definitely full */
checkbuf = l->delay_buf[l->delay_buf_index] * level_out_lin;
SOX_SAMPLE_CLIP_COUNT(checkbuf, effp->clips);
obuf[odone] = checkbuf;
odone++;
idone++;
} else {
l->delay_buf_cnt++;
idone++; /* no "odone++" because we did not fill obuf[...] */
}
l->delay_buf[l->delay_buf_index++] = ibuf[chan];
l->delay_buf_index %= l->delay_buf_size;
}
}
}
*isamp = idone; *osamp = odone;
return (SOX_SUCCESS);
}
static int drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp)
{
priv_t * l = (priv_t *) effp->priv;
size_t chan, done = 0;
if (l->delay_buf_full == 0)
l->delay_buf_index = 0;
while (done+effp->out_signal.channels <= *osamp && l->delay_buf_cnt > 0)
for (chan = 0; chan < effp->out_signal.channels; ++chan) {
int c = l->expectedChannels > 1 ? chan : 0;
double level_in_lin = l->channels[c].volume;
double level_out_lin = lsx_compandt(&l->transfer_fn, level_in_lin);
obuf[done++] = l->delay_buf[l->delay_buf_index++] * level_out_lin;
l->delay_buf_index %= l->delay_buf_size;
l->delay_buf_cnt--;
}
*osamp = done;
return l->delay_buf_cnt > 0 ? SOX_SUCCESS : SOX_EOF;
}
static int stop(sox_effect_t * effp)
{
priv_t * l = (priv_t *) effp->priv;
free(l->delay_buf);
return SOX_SUCCESS;
}
static int lsx_kill(sox_effect_t * effp)
{
priv_t * l = (priv_t *) effp->priv;
lsx_compandt_kill(&l->transfer_fn);
free(l->channels);
free(l->arg0);
free(l->arg1);
free(l->arg2);
return SOX_SUCCESS;
}
sox_effect_handler_t const * lsx_compand_effect_fn(void)
{
static sox_effect_handler_t handler = {
"compand", compand_usage, SOX_EFF_MCHAN | SOX_EFF_GAIN,
getopts, start, flow, drain, stop, lsx_kill, sizeof(priv_t)
};
return &handler;
}

@ -0,0 +1,229 @@
/* libSoX Compander Transfer Function: (c) 2007 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
#include "compandt.h"
#include <string.h>
#define LOG_TO_LOG10(x) ((x) * 20 / M_LN10)
sox_bool lsx_compandt_show(sox_compandt_t * t, sox_plot_t plot)
{
int i;
for (i = 1; t->segments[i-1].x; ++i)
lsx_debug("TF: %g %g %g %g",
LOG_TO_LOG10(t->segments[i].x),
LOG_TO_LOG10(t->segments[i].y),
LOG_TO_LOG10(t->segments[i].a),
LOG_TO_LOG10(t->segments[i].b));
if (plot == sox_plot_octave) {
printf(
"%% GNU Octave file (may also work with MATLAB(R) )\n"
"in=linspace(-99.5,0,200);\n"
"out=[");
for (i = -199; i <= 0; ++i) {
double in = i/2.;
double in_lin = pow(10., in/20);
printf("%g ", in + 20 * log10(lsx_compandt(t, in_lin)));
}
printf(
"];\n"
"plot(in,out)\n"
"title('SoX effect: compand')\n"
"xlabel('Input level (dB)')\n"
"ylabel('Output level (dB)')\n"
"grid on\n"
"disp('Hit return to continue')\n"
"pause\n");
return sox_false;
}
if (plot == sox_plot_gnuplot) {
printf(
"# gnuplot file\n"
"set title 'SoX effect: compand'\n"
"set xlabel 'Input level (dB)'\n"
"set ylabel 'Output level (dB)'\n"
"set grid xtics ytics\n"
"set key off\n"
"plot '-' with lines\n");
for (i = -199; i <= 0; ++i) {
double in = i/2.;
double in_lin = pow(10., in/20);
printf("%g %g\n", in, in + 20 * log10(lsx_compandt(t, in_lin)));
}
printf(
"e\n"
"pause -1 'Hit return to continue'\n");
return sox_false;
}
return sox_true;
}
static void prepare_transfer_fn(sox_compandt_t * t)
{
int i;
double radius = t->curve_dB * M_LN10 / 20;
for (i = 0; !i || t->segments[i-2].x; i += 2) {
t->segments[i].y += t->outgain_dB;
t->segments[i].x *= M_LN10 / 20; /* Convert to natural logs */
t->segments[i].y *= M_LN10 / 20;
}
#define line1 t->segments[i - 4]
#define curve t->segments[i - 3]
#define line2 t->segments[i - 2]
#define line3 t->segments[i - 0]
for (i = 4; t->segments[i - 2].x; i += 2) {
double x, y, cx, cy, in1, in2, out1, out2, theta, len, r;
line1.a = 0;
line1.b = (line2.y - line1.y) / (line2.x - line1.x);
line2.a = 0;
line2.b = (line3.y - line2.y) / (line3.x - line2.x);
theta = atan2(line2.y - line1.y, line2.x - line1.x);
len = sqrt(pow(line2.x - line1.x, 2.) + pow(line2.y - line1.y, 2.));
r = min(radius, len);
curve.x = line2.x - r * cos(theta);
curve.y = line2.y - r * sin(theta);
theta = atan2(line3.y - line2.y, line3.x - line2.x);
len = sqrt(pow(line3.x - line2.x, 2.) + pow(line3.y - line2.y, 2.));
r = min(radius, len / 2);
x = line2.x + r * cos(theta);
y = line2.y + r * sin(theta);
cx = (curve.x + line2.x + x) / 3;
cy = (curve.y + line2.y + y) / 3;
line2.x = x;
line2.y = y;
in1 = cx - curve.x;
out1 = cy - curve.y;
in2 = line2.x - curve.x;
out2 = line2.y - curve.y;
curve.a = (out2/in2 - out1/in1) / (in2-in1);
curve.b = out1/in1 - curve.a*in1;
}
#undef line1
#undef curve
#undef line2
#undef line3
t->segments[i - 3].x = 0;
t->segments[i - 3].y = t->segments[i - 2].y;
t->in_min_lin = exp(t->segments[1].x);
t->out_min_lin= exp(t->segments[1].y);
}
static sox_bool parse_transfer_value(char const * text, double * value)
{
char dummy; /* To check for extraneous chars. */
if (!text) {
lsx_fail("syntax error trying to read transfer function value");
return sox_false;
}
if (!strcmp(text, "-inf"))
*value = -20 * log10(-(double)SOX_SAMPLE_MIN);
else if (sscanf(text, "%lf %c", value, &dummy) != 1) {
lsx_fail("syntax error trying to read transfer function value");
return sox_false;
}
else if (*value > 0) {
lsx_fail("transfer function values are relative to maximum volume so can't exceed 0dB");
return sox_false;
}
return sox_true;
}
sox_bool lsx_compandt_parse(sox_compandt_t * t, char * points, char * gain)
{
char const * text = points;
unsigned i, j, num, pairs, commas = 0;
char dummy; /* To check for extraneous chars. */
if (sscanf(points, "%lf %c", &t->curve_dB, &dummy) == 2 && dummy == ':')
points = strchr(points, ':') + 1;
else t->curve_dB = 0;
t->curve_dB = max(t->curve_dB, .01);
while (*text) commas += *text++ == ',';
pairs = 1 + commas / 2;
++pairs; /* allow room for extra pair at the beginning */
pairs *= 2; /* allow room for the auto-curves */
++pairs; /* allow room for 0,0 at end */
t->segments = lsx_calloc(pairs, sizeof(*t->segments));
#define s(n) t->segments[2*((n)+1)]
for (i = 0, text = strtok(points, ","); text != NULL; ++i) {
if (!parse_transfer_value(text, &s(i).x))
return sox_false;
if (i && s(i-1).x > s(i).x) {
lsx_fail("transfer function input values must be strictly increasing");
return sox_false;
}
if (i || (commas & 1)) {
text = strtok(NULL, ",");
if (!parse_transfer_value(text, &s(i).y))
return sox_false;
s(i).y -= s(i).x;
}
text = strtok(NULL, ",");
}
num = i;
if (num == 0 || s(num-1).x) /* Add 0,0 if necessary */
++num;
#undef s
if (gain && sscanf(gain, "%lf %c", &t->outgain_dB, &dummy) != 1) {
lsx_fail("syntax error trying to read post-processing gain value");
return sox_false;
}
#define s(n) t->segments[2*(n)]
s(0).x = s(1).x - 2 * t->curve_dB; /* Add a tail off segment at the start */
s(0).y = s(1).y;
++num;
for (i = 2; i < num; ++i) { /* Join adjacent colinear segments */
double g1 = (s(i-1).y - s(i-2).y) * (s(i-0).x - s(i-1).x);
double g2 = (s(i-0).y - s(i-1).y) * (s(i-1).x - s(i-2).x);
if (fabs(g1 - g2)) /* fabs stops epsilon problems */
continue;
--num;
for (j = --i; j < num; ++j)
s(j) = s(j+1);
}
#undef s
prepare_transfer_fn(t);
return sox_true;
}
void lsx_compandt_kill(sox_compandt_t * p)
{
free(p->segments);
}

@ -0,0 +1,52 @@
/* libSoX Compander Transfer Function (c) 2007 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <math.h>
typedef struct {
struct sox_compandt_segment {
double x, y; /* 1st point in segment */
double a, b; /* Quadratic coeffecients for rest of segment */
} * segments;
double in_min_lin;
double out_min_lin;
double outgain_dB; /* Post processor gain */
double curve_dB;
} sox_compandt_t;
sox_bool lsx_compandt_parse(sox_compandt_t * t, char * points, char * gain);
sox_bool lsx_compandt_show(sox_compandt_t * t, sox_plot_t plot);
void lsx_compandt_kill(sox_compandt_t * p);
/* Place in header to allow in-lining */
static double lsx_compandt(sox_compandt_t * t, double in_lin)
{
struct sox_compandt_segment * s;
double in_log, out_log;
if (in_lin <= t->in_min_lin)
return t->out_min_lin;
in_log = log(in_lin);
for (s = t->segments + 1; in_log > s[1].x; ++s);
in_log -= s->x;
out_log = s->y + in_log * (s->a * in_log + s->b);
return exp(out_log);
}

@ -0,0 +1,49 @@
/* libSoX effect: Contrast Enhancement (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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
typedef struct {double contrast;} priv_t;
static int create(sox_effect_t * effp, int argc, char * * argv)
{
priv_t * p = (priv_t *)effp->priv;
p->contrast = 75;
--argc, ++argv;
do {NUMERIC_PARAMETER(contrast, 0, 100)} while (0);
p->contrast /= 750; /* shift range to 0 to 0.1333, default 0.1 */
return argc? lsx_usage(effp) : SOX_SUCCESS;
}
static int flow(sox_effect_t * effp, const sox_sample_t * ibuf,
sox_sample_t * obuf, size_t * isamp, size_t * osamp)
{
priv_t * p = (priv_t *)effp->priv;
size_t len = *isamp = *osamp = min(*isamp, *osamp);
while (len--) {
double d = *ibuf++ * (-M_PI_2 / SOX_SAMPLE_MIN);
*obuf++ = sin(d + p->contrast * sin(d * 4)) * SOX_SAMPLE_MAX;
}
return SOX_SUCCESS;
}
sox_effect_handler_t const * lsx_contrast_effect_fn(void)
{
static sox_effect_handler_t handler = {"contrast", "[enhancement (75)]",
0, create, NULL, flow, NULL, NULL, NULL, sizeof(priv_t)};
return &handler;
}

@ -0,0 +1,418 @@
/* AudioCore sound handler
*
* Copyright 2008 Chris Bagwell And Sundry Contributors
*/
#include "sox_i.h"
#include <CoreAudio/CoreAudio.h>
#include <pthread.h>
#define Buffactor 4
typedef struct {
AudioDeviceID adid;
pthread_mutex_t mutex;
pthread_cond_t cond;
int device_started;
size_t bufsize;
size_t bufrd;
size_t bufwr;
size_t bufrdavail;
float *buf;
} priv_t;
static OSStatus PlaybackIOProc(AudioDeviceID inDevice UNUSED,
const AudioTimeStamp *inNow UNUSED,
const AudioBufferList *inInputData UNUSED,
const AudioTimeStamp *inInputTime UNUSED,
AudioBufferList *outOutputData,
const AudioTimeStamp *inOutputTime UNUSED,
void *inClientData)
{
priv_t *ac = (priv_t*)((sox_format_t*)inClientData)->priv;
AudioBuffer *buf;
size_t copylen, avail;
pthread_mutex_lock(&ac->mutex);
for(buf = outOutputData->mBuffers;
buf != outOutputData->mBuffers + outOutputData->mNumberBuffers;
buf++){
copylen = buf->mDataByteSize / sizeof(float);
if(copylen > ac->bufrdavail)
copylen = ac->bufrdavail;
avail = ac->bufsize - ac->bufrd;
if(buf->mData == NULL){
/*do nothing-hardware can't play audio*/
}else if(copylen > avail){
memcpy(buf->mData, ac->buf + ac->bufrd, avail * sizeof(float));
memcpy((float*)buf->mData + avail, ac->buf, (copylen - avail) * sizeof(float));
}else{
memcpy(buf->mData, ac->buf + ac->bufrd, copylen * sizeof(float));
}
buf->mDataByteSize = copylen * sizeof(float);
ac->bufrd += copylen;
if(ac->bufrd >= ac->bufsize)
ac->bufrd -= ac->bufsize;
ac->bufrdavail -= copylen;
}
pthread_cond_signal(&ac->cond);
pthread_mutex_unlock(&ac->mutex);
return kAudioHardwareNoError;
}
static OSStatus RecIOProc(AudioDeviceID inDevice UNUSED,
const AudioTimeStamp *inNow UNUSED,
const AudioBufferList *inInputData,
const AudioTimeStamp *inInputTime UNUSED,
AudioBufferList *outOutputData UNUSED,
const AudioTimeStamp *inOutputTime UNUSED,
void *inClientData)
{
priv_t *ac = (priv_t *)((sox_format_t*)inClientData)->priv;
AudioBuffer const *buf;
size_t nfree, copylen, avail;
pthread_mutex_lock(&ac->mutex);
for(buf = inInputData->mBuffers;
buf != inInputData->mBuffers + inInputData->mNumberBuffers;
buf++){
if(buf->mData == NULL)
continue;
copylen = buf->mDataByteSize / sizeof(float);
nfree = ac->bufsize - ac->bufrdavail - 1;
if(nfree == 0)
lsx_warn("coreaudio: unhandled buffer overrun. Data discarded.");
if(copylen > nfree)
copylen = nfree;
avail = ac->bufsize - ac->bufwr;
if(copylen > avail){
memcpy(ac->buf + ac->bufwr, buf->mData, avail * sizeof(float));
memcpy(ac->buf, (float*)buf->mData + avail, (copylen - avail) * sizeof(float));
}else{
memcpy(ac->buf + ac->bufwr, buf->mData, copylen * sizeof(float));
}
ac->bufwr += copylen;
if(ac->bufwr >= ac->bufsize)
ac->bufwr -= ac->bufsize;
ac->bufrdavail += copylen;
}
pthread_cond_signal(&ac->cond);
pthread_mutex_unlock(&ac->mutex);
return kAudioHardwareNoError;
}
static int setup(sox_format_t *ft, int is_input)
{
priv_t *ac = (priv_t *)ft->priv;
OSStatus status;
UInt32 property_size;
struct AudioStreamBasicDescription stream_desc;
int32_t buf_size;
int rc;
if (strncmp(ft->filename, "default", (size_t)7) == 0)
{
property_size = sizeof(ac->adid);
if (is_input)
status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &property_size, &ac->adid);
else
status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &property_size, &ac->adid);
}
else
{
Boolean is_writable;
status = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &property_size, &is_writable);
if (status == noErr)
{
int device_count = property_size/sizeof(AudioDeviceID);
AudioDeviceID *devices;
devices = malloc(property_size);
status = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &property_size, devices);
if (status == noErr)
{
int i;
for (i = 0; i < device_count; i++)
{
char name[256];
status = AudioDeviceGetProperty(devices[i],0,false,kAudioDevicePropertyDeviceName,&property_size,&name);
lsx_report("Found Audio Device \"%s\"\n",name);
/* String returned from OS is truncated so only compare
* as much as returned.
*/
if (strncmp(name,ft->filename,strlen(name)) == 0)
{
ac->adid = devices[i];
break;
}
}
}
free(devices);
}
}
if (status || ac->adid == kAudioDeviceUnknown)
{
lsx_fail_errno(ft, SOX_EPERM, "can not open audio device");
return SOX_EOF;
}
/* Query device to get initial values */
property_size = sizeof(struct AudioStreamBasicDescription);
status = AudioDeviceGetProperty(ac->adid, 0, is_input,
kAudioDevicePropertyStreamFormat,
&property_size, &stream_desc);
if (status)
{
lsx_fail_errno(ft, SOX_EPERM, "can not get audio device properties");
return SOX_EOF;
}
if (!(stream_desc.mFormatFlags & kLinearPCMFormatFlagIsFloat))
{
lsx_fail_errno(ft, SOX_EPERM, "audio device does not accept floats");
return SOX_EOF;
}
/* OS X effectively only supports these values. */
ft->signal.channels = 2;
ft->signal.rate = 44100;
ft->encoding.bits_per_sample = 32;
/* TODO: My limited experience with hardware can only get floats working
* withh a fixed sample rate and stereo. I know that is a limitiation of
* audio device I have so this may not be standard operating orders.
* If some hardware supports setting sample rates and channel counts
* then should do that over resampling and mixing.
*/
#if 0
stream_desc.mSampleRate = ft->signal.rate;
stream_desc.mChannelsPerFrame = ft->signal.channels;
/* Write them back */
property_size = sizeof(struct AudioStreamBasicDescription);
status = AudioDeviceSetProperty(ac->adid, NULL, 0, is_input,
kAudioDevicePropertyStreamFormat,
property_size, &stream_desc);
if (status)
{
lsx_fail_errno(ft, SOX_EPERM, "can not set audio device properties");
return SOX_EOF;
}
/* Query device to see if it worked */
property_size = sizeof(struct AudioStreamBasicDescription);
status = AudioDeviceGetProperty(ac->adid, 0, is_input,
kAudioDevicePropertyStreamFormat,
&property_size, &stream_desc);
if (status)
{
lsx_fail_errno(ft, SOX_EPERM, "can not get audio device properties");
return SOX_EOF;
}
#endif
if (stream_desc.mChannelsPerFrame != ft->signal.channels)
{
lsx_debug("audio device did not accept %d channels. Use %d channels instead.", (int)ft->signal.channels,
(int)stream_desc.mChannelsPerFrame);
ft->signal.channels = stream_desc.mChannelsPerFrame;
}
if (stream_desc.mSampleRate != ft->signal.rate)
{
lsx_debug("audio device did not accept %d sample rate. Use %d instead.", (int)ft->signal.rate,
(int)stream_desc.mSampleRate);
ft->signal.rate = stream_desc.mSampleRate;
}
ac->bufsize = sox_globals.bufsiz / sizeof(sox_sample_t) * Buffactor;
ac->bufrd = 0;
ac->bufwr = 0;
ac->bufrdavail = 0;
ac->buf = lsx_malloc(ac->bufsize * sizeof(float));
buf_size = sox_globals.bufsiz / sizeof(sox_sample_t) * sizeof(float);
property_size = sizeof(buf_size);
status = AudioDeviceSetProperty(ac->adid, NULL, 0, is_input,
kAudioDevicePropertyBufferSize,
property_size, &buf_size);
rc = pthread_mutex_init(&ac->mutex, NULL);
if (rc)
{
lsx_fail_errno(ft, SOX_EPERM, "failed initializing mutex");
return SOX_EOF;
}
rc = pthread_cond_init(&ac->cond, NULL);
if (rc)
{
lsx_fail_errno(ft, SOX_EPERM, "failed initializing condition");
return SOX_EOF;
}
ac->device_started = 0;
/* Registers callback with the device without activating it. */
if (is_input)
status = AudioDeviceAddIOProc(ac->adid, RecIOProc, (void *)ft);
else
status = AudioDeviceAddIOProc(ac->adid, PlaybackIOProc, (void *)ft);
return SOX_SUCCESS;
}
static int startread(sox_format_t *ft)
{
return setup(ft, 1);
}
static size_t read_samples(sox_format_t *ft, sox_sample_t *buf, size_t nsamp)
{
priv_t *ac = (priv_t *)ft->priv;
size_t len;
SOX_SAMPLE_LOCALS;
if (!ac->device_started) {
AudioDeviceStart(ac->adid, RecIOProc);
ac->device_started = 1;
}
pthread_mutex_lock(&ac->mutex);
/* Wait until input buffer has been filled by device driver */
while (ac->bufrdavail == 0)
pthread_cond_wait(&ac->cond, &ac->mutex);
len = 0;
while(len < nsamp && ac->bufrdavail > 0){
buf[len] = SOX_FLOAT_32BIT_TO_SAMPLE(ac->buf[ac->bufrd], ft->clips);
len++;
ac->bufrd++;
if(ac->bufrd == ac->bufsize)
ac->bufrd = 0;
ac->bufrdavail--;
}
pthread_mutex_unlock(&ac->mutex);
return len;
}
static int stopread(sox_format_t * ft)
{
priv_t *ac = (priv_t *)ft->priv;
AudioDeviceStop(ac->adid, RecIOProc);
AudioDeviceRemoveIOProc(ac->adid, RecIOProc);
pthread_cond_destroy(&ac->cond);
pthread_mutex_destroy(&ac->mutex);
free(ac->buf);
return SOX_SUCCESS;
}
static int startwrite(sox_format_t * ft)
{
return setup(ft, 0);
}
static size_t write_samples(sox_format_t *ft, const sox_sample_t *buf, size_t nsamp)
{
priv_t *ac = (priv_t *)ft->priv;
size_t i;
SOX_SAMPLE_LOCALS;
pthread_mutex_lock(&ac->mutex);
/* Wait to start until mutex is locked to help prevent callback
* getting zero samples.
*/
if(!ac->device_started){
if(AudioDeviceStart(ac->adid, PlaybackIOProc)){
pthread_mutex_unlock(&ac->mutex);
return SOX_EOF;
}
ac->device_started = 1;
}
/* globals.bufsize is in samples
* buf_offset is in bytes
* buf_size is in bytes
*/
for(i = 0; i < nsamp; i++){
while(ac->bufrdavail == ac->bufsize - 1)
pthread_cond_wait(&ac->cond, &ac->mutex);
ac->buf[ac->bufwr] = SOX_SAMPLE_TO_FLOAT_32BIT(buf[i], ft->clips);
ac->bufwr++;
if(ac->bufwr == ac->bufsize)
ac->bufwr = 0;
ac->bufrdavail++;
}
pthread_mutex_unlock(&ac->mutex);
return nsamp;
}
static int stopwrite(sox_format_t * ft)
{
priv_t *ac = (priv_t *)ft->priv;
if(ac->device_started){
pthread_mutex_lock(&ac->mutex);
while (ac->bufrdavail > 0)
pthread_cond_wait(&ac->cond, &ac->mutex);
pthread_mutex_unlock(&ac->mutex);
AudioDeviceStop(ac->adid, PlaybackIOProc);
}
AudioDeviceRemoveIOProc(ac->adid, PlaybackIOProc);
pthread_cond_destroy(&ac->cond);
pthread_mutex_destroy(&ac->mutex);
free(ac->buf);
return SOX_SUCCESS;
}
LSX_FORMAT_HANDLER(coreaudio)
{
static char const *const names[] = { "coreaudio", NULL };
static unsigned const write_encodings[] = {
SOX_ENCODING_FLOAT, 32, 0,
0};
static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
"Mac AudioCore device driver",
names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO,
startread, read_samples, stopread,
startwrite, write_samples, stopwrite,
NULL, write_encodings, NULL, sizeof(priv_t)
};
return &handler;
}

@ -0,0 +1,114 @@
/* libSoX file format: CVSD (see cvsd.c) (c) 2007-8 SoX contributors
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "cvsd.h"
LSX_FORMAT_HANDLER(cvsd)
{
static char const * const names[] = {"cvsd", "cvs", NULL};
static unsigned const write_encodings[] = {SOX_ENCODING_CVSD, 1, 0, 0};
static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
"Headerless MIL Std 188 113 Continuously Variable Slope Delta modulation",
names, SOX_FILE_MONO,
lsx_cvsdstartread, lsx_cvsdread, lsx_cvsdstopread,
lsx_cvsdstartwrite, lsx_cvsdwrite, lsx_cvsdstopwrite,
lsx_rawseek, write_encodings, NULL, sizeof(cvsd_priv_t)
};
return &handler;
}
/* libSoX file format: CVU (c) 2008 robs@users.sourceforge.net
* Unfiltered, therefore, on decode, use with either filter -4k or rate 8k */
typedef struct {
double sample, step, step_mult, step_add;
unsigned last_n_bits;
unsigned char byte;
off_t bit_count;
} priv_t;
static int start(sox_format_t * ft)
{
priv_t *p = (priv_t *) ft->priv;
ft->signal.channels = 1;
lsx_rawstart(ft, sox_true, sox_false, sox_true, SOX_ENCODING_CVSD, 1);
p->last_n_bits = 5; /* 101 */
p->step_mult = exp((-1 / .005 / ft->signal.rate));
p->step_add = (1 - p->step_mult) * (.1 * SOX_SAMPLE_MAX);
lsx_debug("step_mult=%g step_add=%f", p->step_mult, p->step_add);
return SOX_SUCCESS;
}
static void decode(priv_t * p, int bit)
{
p->last_n_bits = ((p->last_n_bits << 1) | bit) & 7;
p->step *= p->step_mult;
if (p->last_n_bits == 0 || p->last_n_bits == 7)
p->step += p->step_add;
if (p->last_n_bits & 1)
p->sample = min(p->step_mult * p->sample + p->step, SOX_SAMPLE_MAX);
else
p->sample = max(p->step_mult * p->sample - p->step, SOX_SAMPLE_MIN);
}
static size_t cvsdread(sox_format_t * ft, sox_sample_t * buf, size_t len)
{
priv_t *p = (priv_t *) ft->priv;
size_t i;
for (i = 0; i < len; ++i) {
if (!(p->bit_count & 7))
if (lsx_read_b_buf(ft, &p->byte, (size_t)1) != 1)
break;
++p->bit_count;
decode(p, p->byte & 1);
p->byte >>= 1;
*buf++ = floor(p->sample + .5);
}
return i;
}
static size_t cvsdwrite(sox_format_t * ft, sox_sample_t const * buf, size_t len)
{
priv_t *p = (priv_t *) ft->priv;
size_t i;
for (i = 0; i < len; ++i) {
decode(p, *buf++ > p->sample);
p->byte >>= 1;
p->byte |= p->last_n_bits << 7;
if (!(++p->bit_count & 7))
if (lsx_writeb(ft, p->byte) != SOX_SUCCESS)
break;
}
return len;
}
LSX_FORMAT_HANDLER(cvu)
{
static char const * const names[] = {"cvu", NULL};
static unsigned const write_encodings[] = {SOX_ENCODING_CVSD, 1, 0, 0};
static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
"Headerless Continuously Variable Slope Delta modulation (unfiltered)",
names, SOX_FILE_MONO, start, cvsdread, NULL, start, cvsdwrite, NULL,
lsx_rawseek, write_encodings, NULL, sizeof(priv_t)
};
return &handler;
}

@ -0,0 +1,680 @@
/* libSoX CVSD (Continuously Variable Slope Delta modulation)
* conversion routines
*
* The CVSD format is described in the MIL Std 188 113, which is
* available from http://bbs.itsi.disa.mil:5580/T3564
*
* Copyright (C) 1996
* Thomas Sailer (sailer@ife.ee.ethz.ch) (HB9JNX/AE4WA)
* Swiss Federal Institute of Technology, Electronics Lab
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Change History:
*
* June 1, 1998 - Chris Bagwell (cbagwell@sprynet.com)
* Fixed compile warnings reported by Kjetil Torgrim Homme
* <kjetilho@ifi.uio.no>
*
* June 20, 2006 - Kimberly Rockwell (pyxis13317 (at) yahoo.com)
* Speed optimization: Unrolled float_conv() loop in seperate
* functions for encoding and decoding. 15% speed up decoding.
*
* Aug. 24, 2009 - P. Chaintreuil (sox-cvsd-peep (at) parallaxshift.com)
* Speed optimization: Replaced calls to memmove() with a
* mirrored circular buffer. This doubles the size of the
* dec.output_filter (48 -> 96 floats) and enc.input_filter
* (16 -> 32 floats), but keeps the memory from having to
* be copied so many times. 56% speed increase decoding;
* less than 5% encoding speed increase.
*/
#include "sox_i.h"
#include "cvsd.h"
#include "cvsdfilt.h"
#include <string.h>
#include <time.h>
/* ---------------------------------------------------------------------- */
/*
* private data structures
*/
typedef cvsd_priv_t priv_t;
static int debug_count = 0;
/* ---------------------------------------------------------------------- */
/* This float_conv() function is not used as more specialized/optimized
* versions exist below. However, those new versions are tied to
* very percise filters defined in cvsdfilt.h. If those are modified
* or different filters are found to be required, this function may
* be needed. Thus I leave it here for possible future use, but commented
* out to avoid compiler warnings about it not being used.
static float float_conv(float const *fp1, float const *fp2,int n)
{
float res = 0;
for(; n > 0; n--)
res += (*fp1++) * (*fp2++);
return res;
}
*/
static float float_conv_enc(float const *fp1, float const *fp2)
{
/* This is a specialzed version of float_conv() for encoding
* which simply assumes a CVSD_ENC_FILTERLEN (16) length of
* the two arrays and unrolls that loop.
*
* fp1 should be the enc.input_filter array and must be
* CVSD_ENC_FILTERLEN (16) long.
*
* fp2 should be one of the enc_filter_xx_y() tables listed
* in cvsdfilt.h. At minimum, fp2 must be CVSD_ENC_FILTERLEN
* (16) entries long.
*/
float res = 0;
/* unrolling loop */
res += fp1[0] * fp2[0];
res += fp1[1] * fp2[1];
res += fp1[2] * fp2[2];
res += fp1[3] * fp2[3];
res += fp1[4] * fp2[4];
res += fp1[5] * fp2[5];
res += fp1[6] * fp2[6];
res += fp1[7] * fp2[7];
res += fp1[8] * fp2[8];
res += fp1[9] * fp2[9];
res += fp1[10] * fp2[10];
res += fp1[11] * fp2[11];
res += fp1[12] * fp2[12];
res += fp1[13] * fp2[13];
res += fp1[14] * fp2[14];
res += fp1[15] * fp2[15];
return res;
}
static float float_conv_dec(float const *fp1, float const *fp2)
{
/* This is a specialzed version of float_conv() for decoding
* which assumes a specific length and structure to the data
* in fp2.
*
* fp1 should be the dec.output_filter array and must be
* CVSD_DEC_FILTERLEN (48) long.
*
* fp2 should be one of the dec_filter_xx() tables listed
* in cvsdfilt.h. fp2 is assumed to be CVSD_DEC_FILTERLEN
* (48) entries long, is assumed to have 0.0 in the last
* entry, and is a symmetrical mirror around fp2[23] (ie,
* fp2[22] == fp2[24], fp2[0] == fp2[47], etc).
*/
float res = 0;
/* unrolling loop, also taking advantage of the symmetry
* of the sampling rate array*/
res += (fp1[0] + fp1[46]) * fp2[0];
res += (fp1[1] + fp1[45]) * fp2[1];
res += (fp1[2] + fp1[44]) * fp2[2];
res += (fp1[3] + fp1[43]) * fp2[3];
res += (fp1[4] + fp1[42]) * fp2[4];
res += (fp1[5] + fp1[41]) * fp2[5];
res += (fp1[6] + fp1[40]) * fp2[6];
res += (fp1[7] + fp1[39]) * fp2[7];
res += (fp1[8] + fp1[38]) * fp2[8];
res += (fp1[9] + fp1[37]) * fp2[9];
res += (fp1[10] + fp1[36]) * fp2[10];
res += (fp1[11] + fp1[35]) * fp2[11];
res += (fp1[12] + fp1[34]) * fp2[12];
res += (fp1[13] + fp1[33]) * fp2[13];
res += (fp1[14] + fp1[32]) * fp2[14];
res += (fp1[15] + fp1[31]) * fp2[15];
res += (fp1[16] + fp1[30]) * fp2[16];
res += (fp1[17] + fp1[29]) * fp2[17];
res += (fp1[18] + fp1[28]) * fp2[18];
res += (fp1[19] + fp1[27]) * fp2[19];
res += (fp1[20] + fp1[26]) * fp2[20];
res += (fp1[21] + fp1[25]) * fp2[21];
res += (fp1[22] + fp1[24]) * fp2[22];
res += (fp1[23]) * fp2[23];
return res;
}
/* ---------------------------------------------------------------------- */
/*
* some remarks about the implementation of the CVSD decoder
* the principal integrator is integrated into the output filter
* to achieve this, the coefficients of the output filter are multiplied
* with (1/(1-1/z)) in the initialisation code.
* the output filter must have a sharp zero at f=0 (i.e. the sum of the
* filter parameters must be zero). This prevents an accumulation of
* DC voltage at the principal integration.
*/
/* ---------------------------------------------------------------------- */
static void cvsdstartcommon(sox_format_t * ft)
{
priv_t *p = (priv_t *) ft->priv;
p->cvsd_rate = (ft->signal.rate <= 24000) ? 16000 : 32000;
ft->signal.rate = 8000;
ft->signal.channels = 1;
lsx_rawstart(ft, sox_true, sox_false, sox_true, SOX_ENCODING_CVSD, 1);
/*
* initialize the decoder
*/
p->com.overload = 0x5;
p->com.mla_int = 0;
/*
* timeconst = (1/e)^(200 / SR) = exp(-200/SR)
* SR is the sampling rate
*/
p->com.mla_tc0 = exp((-200.0)/((float)(p->cvsd_rate)));
/*
* phase_inc = 32000 / SR
*/
p->com.phase_inc = 32000 / p->cvsd_rate;
/*
* initialize bit shift register
*/
p->bit.shreg = p->bit.cnt = 0;
p->bit.mask = 1;
/*
* count the bytes written
*/
p->bytes_written = 0;
p->com.v_min = 1;
p->com.v_max = -1;
lsx_report("cvsd: bit rate %dbit/s, bits from %s", p->cvsd_rate,
ft->encoding.reverse_bits ? "msb to lsb" : "lsb to msb");
}
/* ---------------------------------------------------------------------- */
int lsx_cvsdstartread(sox_format_t * ft)
{
priv_t *p = (priv_t *) ft->priv;
float *fp1;
int i;
cvsdstartcommon(ft);
p->com.mla_tc1 = 0.1 * (1 - p->com.mla_tc0);
p->com.phase = 0;
/*
* initialize the output filter coeffs (i.e. multiply
* the coeffs with (1/(1-1/z)) to achieve integration
* this is now done in the filter parameter generation utility
*/
/*
* zero the filter
*/
for(fp1 = p->c.dec.output_filter, i = CVSD_DEC_FILTERLEN*2; i > 0; i--)
*fp1++ = 0;
/* initialize mirror circular buffer offset to anything sane. */
p->c.dec.offset = CVSD_DEC_FILTERLEN - 1;
return (SOX_SUCCESS);
}
/* ---------------------------------------------------------------------- */
int lsx_cvsdstartwrite(sox_format_t * ft)
{
priv_t *p = (priv_t *) ft->priv;
float *fp1;
int i;
cvsdstartcommon(ft);
p->com.mla_tc1 = 0.1 * (1 - p->com.mla_tc0);
p->com.phase = 4;
/*
* zero the filter
*/
for(fp1 = p->c.enc.input_filter, i = CVSD_ENC_FILTERLEN*2; i > 0; i--)
*fp1++ = 0;
p->c.enc.recon_int = 0;
/* initialize mirror circular buffer offset to anything sane. */
p->c.enc.offset = CVSD_ENC_FILTERLEN - 1;
return(SOX_SUCCESS);
}
/* ---------------------------------------------------------------------- */
int lsx_cvsdstopwrite(sox_format_t * ft)
{
priv_t *p = (priv_t *) ft->priv;
if (p->bit.cnt) {
lsx_writeb(ft, p->bit.shreg);
p->bytes_written++;
}
lsx_debug("cvsd: min slope %f, max slope %f",
p->com.v_min, p->com.v_max);
return (SOX_SUCCESS);
}
/* ---------------------------------------------------------------------- */
int lsx_cvsdstopread(sox_format_t * ft)
{
priv_t *p = (priv_t *) ft->priv;
lsx_debug("cvsd: min value %f, max value %f",
p->com.v_min, p->com.v_max);
return(SOX_SUCCESS);
}
/* ---------------------------------------------------------------------- */
size_t lsx_cvsdread(sox_format_t * ft, sox_sample_t *buf, size_t nsamp)
{
priv_t *p = (priv_t *) ft->priv;
size_t done = 0;
float oval;
while (done < nsamp) {
if (!p->bit.cnt) {
if (lsx_read_b_buf(ft, &(p->bit.shreg), (size_t) 1) != 1)
return done;
p->bit.cnt = 8;
p->bit.mask = 1;
}
/*
* handle one bit
*/
p->bit.cnt--;
p->com.overload = ((p->com.overload << 1) |
(!!(p->bit.shreg & p->bit.mask))) & 7;
p->bit.mask <<= 1;
p->com.mla_int *= p->com.mla_tc0;
if ((p->com.overload == 0) || (p->com.overload == 7))
p->com.mla_int += p->com.mla_tc1;
/* shift output filter window in mirror cirular buffer. */
if (p->c.dec.offset != 0)
--p->c.dec.offset;
else p->c.dec.offset = CVSD_DEC_FILTERLEN - 1;
/* write into both halves of the mirror circular buffer */
if (p->com.overload & 1)
{
p->c.dec.output_filter[p->c.dec.offset] = p->com.mla_int;
p->c.dec.output_filter[p->c.dec.offset + CVSD_DEC_FILTERLEN] = p->com.mla_int;
}
else
{
p->c.dec.output_filter[p->c.dec.offset] = -p->com.mla_int;
p->c.dec.output_filter[p->c.dec.offset + CVSD_DEC_FILTERLEN] = -p->com.mla_int;
}
/*
* check if the next output is due
*/
p->com.phase += p->com.phase_inc;
if (p->com.phase >= 4) {
oval = float_conv_dec(
p->c.dec.output_filter + p->c.dec.offset,
(p->cvsd_rate < 24000) ?
dec_filter_16 : dec_filter_32);
lsx_debug_more("input %d %f\n", debug_count, p->com.mla_int);
lsx_debug_more("recon %d %f\n", debug_count, oval);
debug_count++;
if (oval > p->com.v_max)
p->com.v_max = oval;
if (oval < p->com.v_min)
p->com.v_min = oval;
*buf++ = (oval * ((float)SOX_SAMPLE_MAX));
done++;
}
p->com.phase &= 3;
}
return done;
}
/* ---------------------------------------------------------------------- */
size_t lsx_cvsdwrite(sox_format_t * ft, const sox_sample_t *buf, size_t nsamp)
{
priv_t *p = (priv_t *) ft->priv;
size_t done = 0;
float inval;
for(;;) {
/*
* check if the next input is due
*/
if (p->com.phase >= 4) {
if (done >= nsamp)
return done;
/* shift input filter window in mirror cirular buffer. */
if (p->c.enc.offset != 0)
--p->c.enc.offset;
else p->c.enc.offset = CVSD_ENC_FILTERLEN - 1;
/* write into both halves of the mirror circular buffer */
p->c.enc.input_filter[p->c.enc.offset] =
p->c.enc.input_filter[p->c.enc.offset
+ CVSD_ENC_FILTERLEN] =
(*buf++) /
((float)SOX_SAMPLE_MAX);
done++;
}
p->com.phase &= 3;
/* insert input filter here! */
inval = float_conv_enc(
p->c.enc.input_filter + p->c.enc.offset,
(p->cvsd_rate < 24000) ?
(enc_filter_16[(p->com.phase >= 2)]) :
(enc_filter_32[p->com.phase]));
/*
* encode one bit
*/
p->com.overload = (((p->com.overload << 1) |
(inval > p->c.enc.recon_int)) & 7);
p->com.mla_int *= p->com.mla_tc0;
if ((p->com.overload == 0) || (p->com.overload == 7))
p->com.mla_int += p->com.mla_tc1;
if (p->com.mla_int > p->com.v_max)
p->com.v_max = p->com.mla_int;
if (p->com.mla_int < p->com.v_min)
p->com.v_min = p->com.mla_int;
if (p->com.overload & 1) {
p->c.enc.recon_int += p->com.mla_int;
p->bit.shreg |= p->bit.mask;
} else
p->c.enc.recon_int -= p->com.mla_int;
if ((++(p->bit.cnt)) >= 8) {
lsx_writeb(ft, p->bit.shreg);
p->bytes_written++;
p->bit.shreg = p->bit.cnt = 0;
p->bit.mask = 1;
} else
p->bit.mask <<= 1;
p->com.phase += p->com.phase_inc;
lsx_debug_more("input %d %f\n", debug_count, inval);
lsx_debug_more("recon %d %f\n", debug_count, p->c.enc.recon_int);
debug_count++;
}
}
/* ---------------------------------------------------------------------- */
/*
* DVMS file header
*/
/* FIXME: eliminate these 4 functions */
static uint32_t get32_le(unsigned char **p)
{
uint32_t val = (((*p)[3]) << 24) | (((*p)[2]) << 16) |
(((*p)[1]) << 8) | (**p);
(*p) += 4;
return val;
}
static uint16_t get16_le(unsigned char **p)
{
unsigned val = (((*p)[1]) << 8) | (**p);
(*p) += 2;
return val;
}
static void put32_le(unsigned char **p, uint32_t val)
{
*(*p)++ = val & 0xff;
*(*p)++ = (val >> 8) & 0xff;
*(*p)++ = (val >> 16) & 0xff;
*(*p)++ = (val >> 24) & 0xff;
}
static void put16_le(unsigned char **p, unsigned val)
{
*(*p)++ = val & 0xff;
*(*p)++ = (val >> 8) & 0xff;
}
struct dvms_header {
char Filename[14];
unsigned Id;
unsigned State;
time_t Unixtime;
unsigned Usender;
unsigned Ureceiver;
size_t Length;
unsigned Srate;
unsigned Days;
unsigned Custom1;
unsigned Custom2;
char Info[16];
char extend[64];
unsigned Crc;
};
#define DVMS_HEADER_LEN 120
/* ---------------------------------------------------------------------- */
static int dvms_read_header(sox_format_t * ft, struct dvms_header *hdr)
{
unsigned char hdrbuf[DVMS_HEADER_LEN];
unsigned char *pch = hdrbuf;
int i;
unsigned sum;
if (lsx_readbuf(ft, hdrbuf, sizeof(hdrbuf)) != sizeof(hdrbuf))
{
return (SOX_EOF);
}
for(i = sizeof(hdrbuf), sum = 0; i > /*2*/3; i--) /* Deti bug */
sum += *pch++;
pch = hdrbuf;
memcpy(hdr->Filename, pch, sizeof(hdr->Filename));
pch += sizeof(hdr->Filename);
hdr->Id = get16_le(&pch);
hdr->State = get16_le(&pch);
hdr->Unixtime = get32_le(&pch);
hdr->Usender = get16_le(&pch);
hdr->Ureceiver = get16_le(&pch);
hdr->Length = get32_le(&pch);
hdr->Srate = get16_le(&pch);
hdr->Days = get16_le(&pch);
hdr->Custom1 = get16_le(&pch);
hdr->Custom2 = get16_le(&pch);
memcpy(hdr->Info, pch, sizeof(hdr->Info));
pch += sizeof(hdr->Info);
memcpy(hdr->extend, pch, sizeof(hdr->extend));
pch += sizeof(hdr->extend);
hdr->Crc = get16_le(&pch);
if (sum != hdr->Crc)
{
lsx_report("DVMS header checksum error, read %u, calculated %u",
hdr->Crc, sum);
return (SOX_EOF);
}
return (SOX_SUCCESS);
}
/* ---------------------------------------------------------------------- */
/*
* note! file must be seekable
*/
static int dvms_write_header(sox_format_t * ft, struct dvms_header *hdr)
{
unsigned char hdrbuf[DVMS_HEADER_LEN];
unsigned char *pch = hdrbuf;
unsigned char *pchs = hdrbuf;
int i;
unsigned sum;
memcpy(pch, hdr->Filename, sizeof(hdr->Filename));
pch += sizeof(hdr->Filename);
put16_le(&pch, hdr->Id);
put16_le(&pch, hdr->State);
put32_le(&pch, (unsigned)hdr->Unixtime);
put16_le(&pch, hdr->Usender);
put16_le(&pch, hdr->Ureceiver);
put32_le(&pch, (unsigned) hdr->Length);
put16_le(&pch, hdr->Srate);
put16_le(&pch, hdr->Days);
put16_le(&pch, hdr->Custom1);
put16_le(&pch, hdr->Custom2);
memcpy(pch, hdr->Info, sizeof(hdr->Info));
pch += sizeof(hdr->Info);
memcpy(pch, hdr->extend, sizeof(hdr->extend));
pch += sizeof(hdr->extend);
for(i = sizeof(hdrbuf), sum = 0; i > /*2*/3; i--) /* Deti bug */
sum += *pchs++;
hdr->Crc = sum;
put16_le(&pch, hdr->Crc);
if (lsx_seeki(ft, (off_t)0, SEEK_SET) < 0)
{
lsx_report("seek failed\n: %s",strerror(errno));
return (SOX_EOF);
}
if (lsx_writebuf(ft, hdrbuf, sizeof(hdrbuf)) != sizeof(hdrbuf))
{
lsx_report("%s",strerror(errno));
return (SOX_EOF);
}
return (SOX_SUCCESS);
}
/* ---------------------------------------------------------------------- */
static void make_dvms_hdr(sox_format_t * ft, struct dvms_header *hdr)
{
priv_t *p = (priv_t *) ft->priv;
size_t len;
char * comment = lsx_cat_comments(ft->oob.comments);
memset(hdr->Filename, 0, sizeof(hdr->Filename));
len = strlen(ft->filename);
if (len >= sizeof(hdr->Filename))
len = sizeof(hdr->Filename)-1;
memcpy(hdr->Filename, ft->filename, len);
hdr->Id = hdr->State = 0;
hdr->Unixtime = sox_globals.repeatable? 0 : time(NULL);
hdr->Usender = hdr->Ureceiver = 0;
hdr->Length = p->bytes_written;
hdr->Srate = p->cvsd_rate/100;
hdr->Days = hdr->Custom1 = hdr->Custom2 = 0;
memset(hdr->Info, 0, sizeof(hdr->Info));
len = strlen(comment);
if (len >= sizeof(hdr->Info))
len = sizeof(hdr->Info)-1;
memcpy(hdr->Info, comment, len);
memset(hdr->extend, 0, sizeof(hdr->extend));
free(comment);
}
/* ---------------------------------------------------------------------- */
int lsx_dvmsstartread(sox_format_t * ft)
{
struct dvms_header hdr;
int rc;
rc = dvms_read_header(ft, &hdr);
if (rc){
lsx_fail_errno(ft,SOX_EHDR,"unable to read DVMS header");
return rc;
}
lsx_debug("DVMS header of source file \"%s\":", ft->filename);
lsx_debug(" filename \"%.14s\"", hdr.Filename);
lsx_debug(" id 0x%x", hdr.Id);
lsx_debug(" state 0x%x", hdr.State);
lsx_debug(" time %s", ctime(&hdr.Unixtime)); /* ctime generates lf */
lsx_debug(" usender %u", hdr.Usender);
lsx_debug(" ureceiver %u", hdr.Ureceiver);
lsx_debug(" length %" PRIuPTR, hdr.Length);
lsx_debug(" srate %u", hdr.Srate);
lsx_debug(" days %u", hdr.Days);
lsx_debug(" custom1 %u", hdr.Custom1);
lsx_debug(" custom2 %u", hdr.Custom2);
lsx_debug(" info \"%.16s\"", hdr.Info);
ft->signal.rate = (hdr.Srate < 240) ? 16000 : 32000;
lsx_debug("DVMS rate %dbit/s using %gbit/s deviation %g%%",
hdr.Srate*100, ft->signal.rate,
((ft->signal.rate - hdr.Srate*100) * 100) / ft->signal.rate);
rc = lsx_cvsdstartread(ft);
if (rc)
return rc;
return(SOX_SUCCESS);
}
/* ---------------------------------------------------------------------- */
int lsx_dvmsstartwrite(sox_format_t * ft)
{
struct dvms_header hdr;
int rc;
rc = lsx_cvsdstartwrite(ft);
if (rc)
return rc;
make_dvms_hdr(ft, &hdr);
rc = dvms_write_header(ft, &hdr);
if (rc){
lsx_fail_errno(ft,rc,"cannot write DVMS header");
return rc;
}
if (!ft->seekable)
lsx_warn("Length in output .DVMS header will wrong since can't seek to fix it");
return(SOX_SUCCESS);
}
/* ---------------------------------------------------------------------- */
int lsx_dvmsstopwrite(sox_format_t * ft)
{
struct dvms_header hdr;
int rc;
lsx_cvsdstopwrite(ft);
if (!ft->seekable)
{
lsx_warn("File not seekable");
return (SOX_EOF);
}
if (lsx_seeki(ft, (off_t)0, 0) != 0)
{
lsx_fail_errno(ft,errno,"Can't rewind output file to rewrite DVMS header.");
return(SOX_EOF);
}
make_dvms_hdr(ft, &hdr);
rc = dvms_write_header(ft, &hdr);
if(rc){
lsx_fail_errno(ft,rc,"cannot write DVMS header");
return rc;
}
return rc;
}

@ -0,0 +1,68 @@
/* libSoX DVMS format module (implementation in cvsd.c)
*
* Copyright (C) 1996-2007 Thomas Sailer and SoX Contributors
* Thomas Sailer (sailer@ife.ee.ethz.ch) (HB9JNX/AE4WA)
* Swiss Federal Institute of Technology, Electronics Lab
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "sox_i.h"
#define CVSD_ENC_FILTERLEN 16 /* PCM sampling rate */
#define CVSD_DEC_FILTERLEN 48 /* CVSD sampling rate */
typedef struct {
struct {
unsigned overload;
float mla_int;
float mla_tc0;
float mla_tc1;
unsigned phase;
unsigned phase_inc;
float v_min, v_max;
} com;
union {
struct {
/* mirror circular buffer */
float output_filter[CVSD_DEC_FILTERLEN*2];
unsigned offset; /* into output_filter; always in first half */
} dec;
struct {
float recon_int;
/* mirror circular buffer */
float input_filter[CVSD_ENC_FILTERLEN*2];
unsigned offset; /* into input_filter; always in first half */
} enc;
} c;
struct {
unsigned char shreg;
unsigned mask;
unsigned cnt;
} bit;
unsigned bytes_written;
unsigned cvsd_rate;
} cvsd_priv_t;
int lsx_cvsdstartread(sox_format_t * ft);
int lsx_cvsdstartwrite(sox_format_t * ft);
size_t lsx_cvsdread(sox_format_t * ft, sox_sample_t *buf, size_t nsamp);
size_t lsx_cvsdwrite(sox_format_t * ft, const sox_sample_t *buf, size_t nsamp);
int lsx_cvsdstopread(sox_format_t * ft);
int lsx_cvsdstopwrite(sox_format_t * ft);
int lsx_dvmsstartread(sox_format_t * ft);
int lsx_dvmsstartwrite(sox_format_t * ft);
int lsx_dvmsstopwrite(sox_format_t * ft);

@ -0,0 +1,112 @@
/* libSoX CVSD (Continuously Variable Slope Delta modulation)
* conversion routines
*
* The CVSD format is described in the MIL Std 188 113, which is
* available from http://bbs.itsi.disa.mil:5580/T3564
*
* Copyright (C) 1996
* Thomas Sailer (sailer@ife.ee.ethz.ch) (HB9JNX/AE4WA)
* Swiss Federal Institute of Technology, Electronics Lab
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
static const float dec_filter_16[48] = {
0.001102, 0.001159, 0.000187, -0.000175,
0.002097, 0.006543, 0.009384, 0.008004,
0.006562, 0.013569, 0.030745, 0.047053,
0.050491, 0.047388, 0.062171, 0.109115,
0.167120, 0.197144, 0.195471, 0.222098,
0.354745, 0.599184, 0.849632, 0.956536,
0.849632, 0.599184, 0.354745, 0.222098,
0.195471, 0.197144, 0.167120, 0.109115,
0.062171, 0.047388, 0.050491, 0.047053,
0.030745, 0.013569, 0.006562, 0.008004,
0.009384, 0.006543, 0.002097, -0.000175,
0.000187, 0.001159, 0.001102, 0.000000
};
/* ---------------------------------------------------------------------- */
static const float dec_filter_32[48] = {
0.001950, 0.004180, 0.006331, 0.007907,
0.008510, 0.008342, 0.008678, 0.011827,
0.020282, 0.035231, 0.055200, 0.075849,
0.091585, 0.098745, 0.099031, 0.101287,
0.120058, 0.170672, 0.262333, 0.392047,
0.542347, 0.684488, 0.786557, 0.823702,
0.786557, 0.684488, 0.542347, 0.392047,
0.262333, 0.170672, 0.120058, 0.101287,
0.099031, 0.098745, 0.091585, 0.075849,
0.055200, 0.035231, 0.020282, 0.011827,
0.008678, 0.008342, 0.008510, 0.007907,
0.006331, 0.004180, 0.001950, -0.000000
};
/* ---------------------------------------------------------------------- */
static const float enc_filter_16_0[16] = {
-0.000362, 0.004648, 0.001381, 0.008312,
0.041490, -0.001410, 0.124061, 0.247446,
-0.106761, -0.236326, -0.023798, -0.023506,
-0.030097, 0.001493, -0.005363, -0.001672
};
static const float enc_filter_16_1[16] = {
0.001672, 0.005363, -0.001493, 0.030097,
0.023506, 0.023798, 0.236326, 0.106761,
-0.247446, -0.124061, 0.001410, -0.041490,
-0.008312, -0.001381, -0.004648, 0.000362
};
static const float *enc_filter_16[2] = {
enc_filter_16_0, enc_filter_16_1
};
/* ---------------------------------------------------------------------- */
static const float enc_filter_32_0[16] = {
-0.000289, 0.002112, 0.001421, 0.002235,
0.021003, 0.001237, 0.047132, 0.129636,
-0.027328, -0.126462, -0.021456, -0.008069,
-0.017959, 0.000301, -0.002538, -0.001278
};
static const float enc_filter_32_1[16] = {
-0.000010, 0.002787, 0.000055, 0.006813,
0.020249, -0.000995, 0.077912, 0.112870,
-0.076980, -0.106971, -0.005096, -0.015449,
-0.012591, 0.000813, -0.003003, -0.000527
};
static const float enc_filter_32_2[16] = {
0.000527, 0.003003, -0.000813, 0.012591,
0.015449, 0.005096, 0.106971, 0.076980,
-0.112870, -0.077912, 0.000995, -0.020249,
-0.006813, -0.000055, -0.002787, 0.000010
};
static const float enc_filter_32_3[16] = {
0.001278, 0.002538, -0.000301, 0.017959,
0.008069, 0.021456, 0.126462, 0.027328,
-0.129636, -0.047132, -0.001237, -0.021003,
-0.002235, -0.001421, -0.002112, 0.000289
};
static const float *enc_filter_32[4] = {
enc_filter_32_0, enc_filter_32_1, enc_filter_32_2, enc_filter_32_3
};
/* ---------------------------------------------------------------------- */

@ -0,0 +1,162 @@
/* libSoX text format file. Tom Littlejohn, March 93.
*
* Reads/writes sound files as text.
*
* Copyright 1998-2006 Chris Bagwell and SoX Contributors
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
* Lance Norskog And Sundry Contributors are not responsible for
* the consequences of using this software.
*/
#include "sox_i.h"
#include <string.h>
#define LINEWIDTH (size_t)256
/* Private data for dat file */
typedef struct {
double timevalue, deltat;
int buffered;
char prevline[LINEWIDTH];
} priv_t;
static int sox_datstartread(sox_format_t * ft)
{
char inpstr[LINEWIDTH];
long rate;
int chan;
int status;
char sc;
/* Read lines until EOF or first non-comment line */
while ((status = lsx_reads(ft, inpstr, LINEWIDTH-1)) != SOX_EOF) {
inpstr[LINEWIDTH-1] = 0;
if ((sscanf(inpstr," %c", &sc) != 0) && (sc != ';')) break;
if (sscanf(inpstr," ; Sample Rate %ld", &rate)) {
ft->signal.rate=rate;
} else if (sscanf(inpstr," ; Channels %d", &chan)) {
ft->signal.channels=chan;
}
}
/* Hold a copy of the last line we read (first non-comment) */
if (status != SOX_EOF) {
strncpy(((priv_t *)ft->priv)->prevline, inpstr, (size_t)LINEWIDTH);
((priv_t *)ft->priv)->buffered = 1;
} else {
((priv_t *)ft->priv)->buffered = 0;
}
/* Default channels to 1 if not found */
if (ft->signal.channels == 0)
ft->signal.channels = 1;
ft->encoding.encoding = SOX_ENCODING_FLOAT_TEXT;
return (SOX_SUCCESS);
}
static int sox_datstartwrite(sox_format_t * ft)
{
priv_t * dat = (priv_t *) ft->priv;
char s[LINEWIDTH];
dat->timevalue = 0.0;
dat->deltat = 1.0 / (double)ft->signal.rate;
/* Write format comments to start of file */
sprintf(s,"; Sample Rate %ld\015\n", (long)ft->signal.rate);
lsx_writes(ft, s);
sprintf(s,"; Channels %d\015\n", (int)ft->signal.channels);
lsx_writes(ft, s);
return (SOX_SUCCESS);
}
static size_t sox_datread(sox_format_t * ft, sox_sample_t *buf, size_t nsamp)
{
char inpstr[LINEWIDTH];
int inpPtr = 0;
int inpPtrInc = 0;
double sampval = 0.0;
int retc = 0;
char sc = 0;
size_t done = 0;
size_t i=0;
/* Always read a complete set of channels */
nsamp -= (nsamp % ft->signal.channels);
while (done < nsamp) {
/* Read a line or grab the buffered first line */
if (((priv_t *)ft->priv)->buffered) {
strncpy(inpstr, ((priv_t *)ft->priv)->prevline, (size_t)LINEWIDTH);
inpstr[LINEWIDTH-1] = 0;
((priv_t *)ft->priv)->buffered=0;
} else {
lsx_reads(ft, inpstr, LINEWIDTH-1);
inpstr[LINEWIDTH-1] = 0;
if (lsx_eof(ft)) return (done);
}
/* Skip over comments - ie. 0 or more whitespace, then ';' */
if ((sscanf(inpstr," %c", &sc) != 0) && (sc==';')) continue;
/* Read a complete set of channels */
sscanf(inpstr," %*s%n", &inpPtr);
for (i=0; i<ft->signal.channels; i++) {
SOX_SAMPLE_LOCALS;
retc = sscanf(&inpstr[inpPtr]," %lg%n", &sampval, &inpPtrInc);
inpPtr += inpPtrInc;
if (retc != 1) {
lsx_fail_errno(ft,SOX_EOF,"Unable to read sample.");
return 0;
}
*buf++ = SOX_FLOAT_64BIT_TO_SAMPLE(sampval, ft->clips);
done++;
}
}
return (done);
}
static size_t sox_datwrite(sox_format_t * ft, const sox_sample_t *buf, size_t nsamp)
{
priv_t * dat = (priv_t *) ft->priv;
size_t done = 0;
double sampval=0.0;
char s[LINEWIDTH];
size_t i=0;
/* Always write a complete set of channels */
nsamp -= (nsamp % ft->signal.channels);
/* Write time, then sample values, then CRLF newline */
while(done < nsamp) {
sprintf(s," %15.8g ",dat->timevalue);
lsx_writes(ft, s);
for (i=0; i<ft->signal.channels; i++) {
sampval = SOX_SAMPLE_TO_FLOAT_64BIT(*buf++, ft->clips);
sprintf(s," %15.11g", sampval);
lsx_writes(ft, s);
done++;
}
sprintf(s," \r\n");
lsx_writes(ft, s);
dat->timevalue += dat->deltat;
}
return done;
}
LSX_FORMAT_HANDLER(dat)
{
static char const * const names[] = {"dat", NULL};
static unsigned const write_encodings[] = {SOX_ENCODING_FLOAT_TEXT, 0, 0};
static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
"Textual representation of the sampled audio", names, 0,
sox_datstartread, sox_datread, NULL,
sox_datstartwrite, sox_datwrite, NULL,
NULL, write_encodings, NULL, sizeof(priv_t)
};
return &handler;
}

@ -0,0 +1,165 @@
/* libSoX dcshift.c
* (c) 2000.04.15 Chris Ausbrooks <weed@bucket.pp.ualr.edu>
*
* based on vol.c which is
* (c) 20/03/2000 Fabien COELHO <fabien@coelho.net> for sox.
*
* DC shift a sound file, with basic linear amplitude formula.
* Beware of saturations! clipping is checked and reported.
* Cannot handle different number of channels.
* Cannot handle rate change.
*/
#include "sox_i.h"
typedef struct {
double dcshift; /* DC shift. */
int uselimiter; /* boolean: are we using the limiter? */
double limiterthreshhold;
double limitergain; /* limiter gain. */
uint64_t limited; /* number of limited values to report. */
uint64_t totalprocessed;
} priv_t;
/*
* Process options: dcshift (double) type (amplitude, power, dB)
*/
static int sox_dcshift_getopts(sox_effect_t * effp, int argc, char **argv)
{
priv_t * dcs = (priv_t *) effp->priv;
dcs->dcshift = 1.0; /* default is no change */
dcs->uselimiter = 0; /* default is no limiter */
--argc, ++argv;
if (argc < 1)
return lsx_usage(effp);
if (argc && (!sscanf(argv[0], "%lf", &dcs->dcshift)))
return lsx_usage(effp);
if (argc>1)
{
if (!sscanf(argv[1], "%lf", &dcs->limitergain))
return lsx_usage(effp);
dcs->uselimiter = 1; /* ok, we'll use it */
/* The following equation is derived so that there is no
* discontinuity in output amplitudes */
/* and a SOX_SAMPLE_MAX input always maps to a SOX_SAMPLE_MAX output
* when the limiter is activated. */
/* (NOTE: There **WILL** be a discontinuity in the slope of the
* output amplitudes when using the limiter.) */
dcs->limiterthreshhold = SOX_SAMPLE_MAX * (1.0 - (fabs(dcs->dcshift) - dcs->limitergain));
}
return SOX_SUCCESS;
}
/*
* Start processing
*/
static int sox_dcshift_start(sox_effect_t * effp)
{
priv_t * dcs = (priv_t *) effp->priv;
if (dcs->dcshift == 0)
return SOX_EFF_NULL;
dcs->limited = 0;
dcs->totalprocessed = 0;
return SOX_SUCCESS;
}
/*
* Process data.
*/
static int sox_dcshift_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,
size_t *isamp, size_t *osamp)
{
priv_t * dcs = (priv_t *) effp->priv;
double dcshift = dcs->dcshift;
double limitergain = dcs->limitergain;
double limiterthreshhold = dcs->limiterthreshhold;
double sample;
size_t len;
len = min(*osamp, *isamp);
/* report back dealt with amount. */
*isamp = len; *osamp = len;
if (dcs->uselimiter)
{
dcs->totalprocessed += len;
for (;len>0; len--)
{
sample = *ibuf++;
if (sample > limiterthreshhold && dcshift > 0)
{
sample = (sample - limiterthreshhold) * limitergain / (SOX_SAMPLE_MAX - limiterthreshhold) + limiterthreshhold + dcshift;
dcs->limited++;
}
else if (sample < -limiterthreshhold && dcshift < 0)
{
/* Note this should really be SOX_SAMPLE_MIN but
* the clip() below will take care of the overflow.
*/
sample = (sample + limiterthreshhold) * limitergain / (SOX_SAMPLE_MAX - limiterthreshhold) - limiterthreshhold + dcshift;
dcs->limited++;
}
else
{
/* Note this should consider SOX_SAMPLE_MIN but
* the clip() below will take care of the overflow.
*/
sample = dcshift * SOX_SAMPLE_MAX + sample;
}
SOX_SAMPLE_CLIP_COUNT(sample, effp->clips);
*obuf++ = sample;
}
}
else for (; len > 0; --len) { /* quite basic, with clipping */
double d = dcshift * (SOX_SAMPLE_MAX + 1.) + *ibuf++;
*obuf++ = SOX_ROUND_CLIP_COUNT(d, effp->clips);
}
return SOX_SUCCESS;
}
/*
* Do anything required when you stop reading samples.
* Don't close input file!
*/
static int sox_dcshift_stop(sox_effect_t * effp)
{
priv_t * dcs = (priv_t *) effp->priv;
if (dcs->limited)
{
lsx_warn("DCSHIFT limited %" PRIu64 " values (%d percent).",
dcs->limited, (int) (dcs->limited * 100.0 / dcs->totalprocessed));
}
return SOX_SUCCESS;
}
static sox_effect_handler_t sox_dcshift_effect = {
"dcshift",
"shift [ limitergain ]\n"
"\tThe peak limiter has a gain much less than 1.0 (ie 0.05 or 0.02) which\n"
"\tis only used on peaks to prevent clipping. (default is no limiter)",
SOX_EFF_MCHAN | SOX_EFF_GAIN,
sox_dcshift_getopts,
sox_dcshift_start,
sox_dcshift_flow,
NULL,
sox_dcshift_stop,
NULL, sizeof(priv_t)
};
const sox_effect_handler_t *lsx_dcshift_effect_fn(void)
{
return &sox_dcshift_effect;
}

@ -0,0 +1,118 @@
# 15/50us EIAJ de-emphasis filter for CD/DAT
#
# 09/02/98 (c) Heiko Eissfeldt
#
# 18/03/07 robs@users.sourceforge.net: changed to biquad for slightly
# better accuracy.
#
# License: LGPL (Lesser Gnu Public License)
#
# This implements the inverse filter of the optional pre-emphasis stage
# as defined by IEC 60908 (describing the audio cd format).
#
# Background: In the early days of audio cds, there were recording
# problems with noise (for example in classical recordings). The high
# dynamics of audio cds exposed these recording errors a lot.
#
# The commonly used solution at that time was to 'pre-emphasize' the
# trebles to have a better signal-noise-ratio. That is trebles were
# amplified before recording, so that they would give a stronger signal
# compared to the underlying (tape) noise.
#
# For that purpose the audio signal was prefiltered with the following
# frequency response (simple first order filter):
#
# V (in dB)
# ^
# |
# |~10dB _________________
# | /
# | / |
# | 20dB / decade ->/ |
# | / |
# |____________________/_ _ |_ _ _ _ _ _ _ _ _ Frequency
# |0 dB | |
# | | |
# | | |
# 3.1kHz ~10kHz
#
# So the recorded audio signal has amplified trebles compared to the
# original. HiFi cd players do correct this by applying an inverse
# filter automatically, the cd-rom drives or cd burners used by digital
# sampling programs (like cdda2wav) however do not.
#
# So, this is what this effect does.
#
# This is the gnuplot file for the frequency response of the deemphasis.
#
# The absolute error is <=0.04dB up to ~12kHz, and <=0.06dB up to 20kHz.
# First define the ideal filter:
# Filter parameters
T = 1. / 441000. # we use the tenfold sampling frequency
OmegaU = 1. / 15e-6
OmegaL = 15. / 50. * OmegaU
# Calculate filter coefficients
V0 = OmegaL / OmegaU
H0 = V0 - 1.
B = V0 * tan(OmegaU * T / 2.)
A1 = (B - 1.) / (B + 1.)
B0 = (1. + (1. - A1) * H0 / 2.)
B1 = (A1 + (A1 - 1.) * H0 / 2.)
# helper variables
D = B1 / B0
O = 2 * pi * T
# Ideal transfer function
Hi(f) = B0*sqrt((1 + 2*cos(f*O)*D + D*D)/(1 + 2*cos(f*O)*A1 + A1*A1))
# Now use a biquad (RBJ high shelf) with sampling frequency of 44100Hz
# to approximate the ideal curve:
# Filter parameters
t = 1. / 44100.
gain = -9.477
slope = .4845
f0 = 5283
# Calculate filter coefficients
A = exp(gain / 40. * log(10.))
w0 = 2. * pi * f0 * t
alpha = sin(w0) / 2. * sqrt((A + 1. / A) * (1. / slope - 1.) + 2.)
b0 = A * ((A + 1.) + (A - 1.) * cos(w0) + 2. * sqrt(A) * alpha)
b1 = -2. * A * ((A - 1.) + (A + 1.) * cos(w0))
b2 = A * ((A + 1.) + (A - 1.) * cos(w0) - 2. * sqrt(A) * alpha)
a0 = (A + 1.) - (A - 1.) * cos(w0) + 2. * sqrt(A) * alpha
a1 = 2. * ((A - 1.) - (A + 1.) * cos(w0))
a2 = (A + 1.) - (A - 1.) * cos(w0) - 2. * sqrt(A) * alpha
b2 = b2 / a0
b1 = b1 / a0
b0 = b0 / a0
a2 = a2 / a0
a1 = a1 / a0
# helper variables
o = 2 * pi * t
# Best fit transfer function
Hb(f) = sqrt((b0*b0 + b1*b1 + b2*b2 +\
2.*(b0*b1 + b1*b2)*cos(f*o) + 2.*(b0*b2)* cos(2.*f*o)) /\
(1. + a1*a1 + a2*a2 + 2.*(a1 + a1*a2)*cos(f*o) + 2.*a2*cos(2.*f*o)))
# plot real, best, ideal, level with halved attenuation,
# level at full attentuation, 10fold magnified error
set logscale x
set grid xtics ytics mxtics mytics
set key left bottom
plot [f=1000:20000] [-12:2] \
20 * log10(Hi(f)),\
20 * log10(Hb(f)),\
20 * log10(OmegaL/(2 * pi * f)),\
.5 * 20 * log10(V0),\
20 * log10(V0),\
200 * log10(Hb(f)/Hi(f))
pause -1 "Hit return to continue"

@ -0,0 +1,163 @@
/* libSoX effect: Delay one or more channels (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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
#include <string.h>
typedef struct {
size_t argc;
struct { char *str; uint64_t delay; } *args;
uint64_t *max_delay;
uint64_t delay, pre_pad, pad;
size_t buffer_size, buffer_index;
sox_sample_t * buffer;
sox_bool drain_started;
} priv_t;
static int lsx_kill(sox_effect_t * effp)
{
priv_t * p = (priv_t *)effp->priv;
unsigned i;
for (i = 0; i < p->argc; ++i)
free(p->args[i].str);
free(p->args);
free(p->max_delay);
return SOX_SUCCESS;
}
static int create(sox_effect_t * effp, int argc, char * * argv)
{
priv_t * p = (priv_t *)effp->priv;
unsigned i;
--argc, ++argv;
p->argc = argc;
p->args = lsx_calloc(p->argc, sizeof(*p->args));
p->max_delay = lsx_malloc(sizeof(*p->max_delay));
for (i = 0; i < p->argc; ++i) {
char const * next = lsx_parseposition(0., p->args[i].str = lsx_strdup(argv[i]), NULL, (uint64_t)0, (uint64_t)0, '=');
if (!next || *next) {
lsx_kill(effp);
return lsx_usage(effp);
}
}
return SOX_SUCCESS;
}
static int stop(sox_effect_t * effp)
{
priv_t * p = (priv_t *)effp->priv;
free(p->buffer);
return SOX_SUCCESS;
}
static int start(sox_effect_t * effp)
{
priv_t * p = (priv_t *)effp->priv;
uint64_t max_delay = 0, last_seen = 0, delay;
uint64_t in_length = effp->in_signal.length != SOX_UNKNOWN_LEN ?
effp->in_signal.length / effp->in_signal.channels : SOX_UNKNOWN_LEN;
if (effp->flow == 0) {
unsigned i;
if (p->argc > effp->in_signal.channels) {
lsx_fail("too few input channels");
return SOX_EOF;
}
for (i = 0; i < p->argc; ++i) {
if (!lsx_parseposition(effp->in_signal.rate, p->args[i].str, &delay, last_seen, in_length, '=') || delay == SOX_UNKNOWN_LEN) {
lsx_fail("Position relative to end of audio specified, but audio length is unknown");
return SOX_EOF;
}
p->args[i].delay = last_seen = delay;
if (delay > max_delay) {
max_delay = delay;
}
}
*p->max_delay = max_delay;
if (max_delay == 0)
return SOX_EFF_NULL;
effp->out_signal.length = effp->in_signal.length != SOX_UNKNOWN_LEN ?
effp->in_signal.length + max_delay * effp->in_signal.channels :
SOX_UNKNOWN_LEN;
lsx_debug("extending audio by %" PRIu64 " samples", max_delay);
}
max_delay = *p->max_delay;
if (effp->flow < p->argc)
p->buffer_size = p->args[effp->flow].delay;
p->buffer_index = p->delay = p->pre_pad = 0;
p->pad = max_delay - p->buffer_size;
p->buffer = lsx_malloc(p->buffer_size * sizeof(*p->buffer));
p->drain_started = sox_false;
return SOX_SUCCESS;
}
static int flow(sox_effect_t * effp, const sox_sample_t * ibuf,
sox_sample_t * obuf, size_t * isamp, size_t * osamp)
{
priv_t * p = (priv_t *)effp->priv;
size_t len = *isamp = *osamp = min(*isamp, *osamp);
if (!p->buffer_size)
memcpy(obuf, ibuf, len * sizeof(*obuf));
else for (; len; --len) {
if (p->delay < p->buffer_size) {
p->buffer[p->delay++] = *ibuf++;
*obuf++ = 0;
} else {
*obuf++ = p->buffer[p->buffer_index];
p->buffer[p->buffer_index++] = *ibuf++;
p->buffer_index %= p->buffer_size;
}
}
return SOX_SUCCESS;
}
static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp)
{
priv_t * p = (priv_t *)effp->priv;
size_t len;
if (! p->drain_started) {
p->drain_started = sox_true;
p->pre_pad = p->buffer_size - p->delay;
/* If the input was too short to fill the buffer completely,
flow() has not yet output enough silence to reach the
desired delay. */
}
len = *osamp = min(p->pre_pad + p->delay + p->pad, *osamp);
for (; p->pre_pad && len; --p->pre_pad, --len)
*obuf++ = 0;
for (; p->delay && len; --p->delay, --len) {
*obuf++ = p->buffer[p->buffer_index++];
p->buffer_index %= p->buffer_size;
}
for (; p->pad && len; --p->pad, --len)
*obuf++ = 0;
return SOX_SUCCESS;
}
sox_effect_handler_t const * lsx_delay_effect_fn(void)
{
static sox_effect_handler_t handler = {
"delay", "{position}", SOX_EFF_LENGTH | SOX_EFF_MODIFY,
create, start, flow, drain, stop, lsx_kill, sizeof(priv_t)
};
return &handler;
}

@ -0,0 +1,137 @@
/* Abstract effect: dft filter Copyright (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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
#include "fft4g.h"
#include "dft_filter.h"
#include <string.h>
typedef dft_filter_t filter_t;
typedef dft_filter_priv_t priv_t;
void lsx_set_dft_filter(dft_filter_t *f, double *h, int n, int post_peak)
{
int i;
f->num_taps = n;
f->post_peak = post_peak;
f->dft_length = lsx_set_dft_length(f->num_taps);
f->coefs = lsx_calloc(f->dft_length, sizeof(*f->coefs));
for (i = 0; i < f->num_taps; ++i)
f->coefs[(i + f->dft_length - f->num_taps + 1) & (f->dft_length - 1)] = h[i] / f->dft_length * 2;
lsx_safe_rdft(f->dft_length, 1, f->coefs);
free(h);
}
static int start(sox_effect_t * effp)
{
priv_t * p = (priv_t *) effp->priv;
fifo_create(&p->input_fifo, (int)sizeof(double));
memset(fifo_reserve(&p->input_fifo,
p->filter_ptr->post_peak), 0, sizeof(double) * p->filter_ptr->post_peak);
fifo_create(&p->output_fifo, (int)sizeof(double));
return SOX_SUCCESS;
}
static void filter(priv_t * p)
{
int i, num_in = max(0, fifo_occupancy(&p->input_fifo));
filter_t const * f = p->filter_ptr;
int const overlap = f->num_taps - 1;
double * output;
while (num_in >= f->dft_length) {
double const * input = fifo_read_ptr(&p->input_fifo);
fifo_read(&p->input_fifo, f->dft_length - overlap, NULL);
num_in -= f->dft_length - overlap;
output = fifo_reserve(&p->output_fifo, f->dft_length);
fifo_trim_by(&p->output_fifo, overlap);
memcpy(output, input, f->dft_length * sizeof(*output));
lsx_safe_rdft(f->dft_length, 1, output);
output[0] *= f->coefs[0];
output[1] *= f->coefs[1];
for (i = 2; i < f->dft_length; i += 2) {
double tmp = output[i];
output[i ] = f->coefs[i ] * tmp - f->coefs[i+1] * output[i+1];
output[i+1] = f->coefs[i+1] * tmp + f->coefs[i ] * output[i+1];
}
lsx_safe_rdft(f->dft_length, -1, output);
}
}
static int flow(sox_effect_t * effp, const sox_sample_t * ibuf,
sox_sample_t * obuf, size_t * isamp, size_t * osamp)
{
priv_t * p = (priv_t *)effp->priv;
size_t odone = min(*osamp, (size_t)fifo_occupancy(&p->output_fifo));
double const * s = fifo_read(&p->output_fifo, (int)odone, NULL);
lsx_save_samples(obuf, s, odone, &effp->clips);
p->samples_out += odone;
if (*isamp && odone < *osamp) {
double * t = fifo_write(&p->input_fifo, (int)*isamp, NULL);
p->samples_in += *isamp;
lsx_load_samples(t, ibuf, *isamp);
filter(p);
}
else *isamp = 0;
*osamp = odone;
return SOX_SUCCESS;
}
static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp)
{
priv_t * p = (priv_t *)effp->priv;
static size_t isamp = 0;
size_t remaining = p->samples_in > p->samples_out ?
(size_t)(p->samples_in - p->samples_out) : 0;
double * buff = lsx_calloc(1024, sizeof(*buff));
if (remaining > 0) {
while ((size_t)fifo_occupancy(&p->output_fifo) < remaining) {
fifo_write(&p->input_fifo, 1024, buff);
p->samples_in += 1024;
filter(p);
}
fifo_trim_to(&p->output_fifo, (int)remaining);
p->samples_in = 0;
}
free(buff);
return flow(effp, 0, obuf, &isamp, osamp);
}
static int stop(sox_effect_t * effp)
{
priv_t * p = (priv_t *) effp->priv;
fifo_delete(&p->input_fifo);
fifo_delete(&p->output_fifo);
free(p->filter_ptr->coefs);
memset(p->filter_ptr, 0, sizeof(*p->filter_ptr));
return SOX_SUCCESS;
}
sox_effect_handler_t const * lsx_dft_filter_effect_fn(void)
{
static sox_effect_handler_t handler = {
NULL, NULL, SOX_EFF_GAIN, NULL, start, flow, drain, stop, NULL, 0
};
return &handler;
}

@ -0,0 +1,16 @@
#include "fft4g.h"
#define FIFO_SIZE_T int
#include "fifo.h"
typedef struct {
int dft_length, num_taps, post_peak;
double * coefs;
} dft_filter_t;
typedef struct {
uint64_t samples_in, samples_out;
fifo_t input_fifo, output_fifo;
dft_filter_t filter, * filter_ptr;
} dft_filter_priv_t;
void lsx_set_dft_filter(dft_filter_t * f, double * h, int n, int post_peak);

@ -0,0 +1,436 @@
/* Effect: dither/noise-shape Copyright (c) 2008-9 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef NDEBUG /* Enable assert always. */
#undef NDEBUG /* Must undef above assert.h or other that might include it. */
#endif
#include "sox_i.h"
#include <assert.h>
#undef RANQD1
#define RANQD1 ranqd1(p->ranqd1)
typedef enum { /* Collection of various filters from the net */
Shape_none, Shape_lipshitz, Shape_f_weighted, Shape_modified_e_weighted,
Shape_improved_e_weighted, Shape_gesemann, Shape_shibata, Shape_low_shibata, Shape_high_shibata
} filter_name_t;
static lsx_enum_item const filter_names[] = {
LSX_ENUM_ITEM(Shape_,none)
LSX_ENUM_ITEM(Shape_,lipshitz)
{"f-weighted", Shape_f_weighted},
{"modified-e-weighted", Shape_modified_e_weighted},
{"improved-e-weighted", Shape_improved_e_weighted},
LSX_ENUM_ITEM(Shape_,gesemann)
LSX_ENUM_ITEM(Shape_,shibata)
{"low-shibata", Shape_low_shibata},
{"high-shibata", Shape_high_shibata},
{0, 0}};
typedef struct {
sox_rate_t rate;
enum {fir, iir} type;
size_t len;
int gain_cB; /* Chosen so clips are few if any, but not guaranteed none. */
double const * coefs;
filter_name_t name;
} filter_t;
static double const lip44[] = {2.033, -2.165, 1.959, -1.590, .6149};
static double const fwe44[] = {
2.412, -3.370, 3.937, -4.174, 3.353, -2.205, 1.281, -.569, .0847};
static double const mew44[] = {
1.662, -1.263, .4827, -.2913, .1268, -.1124, .03252, -.01265, -.03524};
static double const iew44[] = {
2.847, -4.685, 6.214, -7.184, 6.639, -5.032, 3.263, -1.632, .4191};
static double const ges44[] = {
2.2061, -.4706, -.2534, -.6214, 1.0587, .0676, -.6054, -.2738};
static double const ges48[] = {
2.2374, -.7339, -.1251, -.6033, .903, .0116, -.5853, -.2571};
static double const shi48[] = {
2.8720729351043701172, -5.0413231849670410156, 6.2442994117736816406,
-5.8483986854553222656, 3.7067542076110839844, -1.0495119094848632812,
-1.1830236911773681641, 2.1126792430877685547, -1.9094531536102294922,
0.99913084506988525391, -0.17090806365013122559, -0.32615602016448974609,
0.39127644896507263184, -0.26876461505889892578, 0.097676105797290802002,
-0.023473845794796943665,
};
static double const shi44[] = {
2.6773197650909423828, -4.8308925628662109375, 6.570110321044921875,
-7.4572014808654785156, 6.7263274192810058594, -4.8481650352478027344,
2.0412089824676513672, 0.7006359100341796875, -2.9537565708160400391,
4.0800385475158691406, -4.1845216751098632812, 3.3311812877655029297,
-2.1179926395416259766, 0.879302978515625, -0.031759146600961685181,
-0.42382788658142089844, 0.47882103919982910156, -0.35490813851356506348,
0.17496839165687561035, -0.060908168554306030273,
};
static double const shi38[] = {
1.6335992813110351562, -2.2615492343902587891, 2.4077029228210449219,
-2.6341717243194580078, 2.1440362930297851562, -1.8153258562088012695,
1.0816224813461303711, -0.70302653312683105469, 0.15991993248462677002,
0.041549518704414367676, -0.29416576027870178223, 0.2518316805362701416,
-0.27766478061676025391, 0.15785403549671173096, -0.10165894031524658203,
0.016833892092108726501,
};
static double const shi32[] =
{ /* dmaker 32000: bestmax=4.99659 (inverted) */
0.82118552923202515,
-1.0063692331314087,
0.62341964244842529,
-1.0447187423706055,
0.64532512426376343,
-0.87615132331848145,
0.52219754457473755,
-0.67434263229370117,
0.44954317808151245,
-0.52557498216629028,
0.34567299485206604,
-0.39618203043937683,
0.26791760325431824,
-0.28936097025871277,
0.1883765310049057,
-0.19097308814525604,
0.10431359708309174,
-0.10633844882249832,
0.046832218766212463,
-0.039653312414884567,
};
static double const shi22[] =
{ /* dmaker 22050: bestmax=5.77762 (inverted) */
0.056581053882837296,
-0.56956905126571655,
-0.40727734565734863,
-0.33870288729667664,
-0.29810553789138794,
-0.19039161503314972,
-0.16510021686553955,
-0.13468159735202789,
-0.096633769571781158,
-0.081049129366874695,
-0.064953058958053589,
-0.054459091275930405,
-0.043378707021474838,
-0.03660014271736145,
-0.026256965473294258,
-0.018786206841468811,
-0.013387725688517094,
-0.0090983230620622635,
-0.0026585909072309732,
-0.00042083300650119781,
};
static double const shi16[] =
{ /* dmaker 16000: bestmax=5.97128 (inverted) */
-0.37251132726669312,
-0.81423574686050415,
-0.55010956525802612,
-0.47405767440795898,
-0.32624706625938416,
-0.3161766529083252,
-0.2286367267370224,
-0.22916607558727264,
-0.19565616548061371,
-0.18160104751586914,
-0.15423151850700378,
-0.14104481041431427,
-0.11844276636838913,
-0.097583092749118805,
-0.076493598520755768,
-0.068106919527053833,
-0.041881654411554337,
-0.036922425031661987,
-0.019364040344953537,
-0.014994367957115173,
};
static double const shi11[] =
{ /* dmaker 11025: bestmax=5.9406 (inverted) */
-0.9264228343963623,
-0.98695987462997437,
-0.631156325340271,
-0.51966935396194458,
-0.39738872647285461,
-0.35679301619529724,
-0.29720726609230042,
-0.26310476660728455,
-0.21719355881214142,
-0.18561814725399017,
-0.15404847264289856,
-0.12687471508979797,
-0.10339745879173279,
-0.083688631653785706,
-0.05875682458281517,
-0.046893671154975891,
-0.027950936928391457,
-0.020740609616041183,
-0.009366452693939209,
-0.0060260160826146603,
};
static double const shi08[] =
{ /* dmaker 8000: bestmax=5.56234 (inverted) */
-1.202863335609436,
-0.94103097915649414,
-0.67878556251525879,
-0.57650017738342285,
-0.50004476308822632,
-0.44349345564842224,
-0.37833768129348755,
-0.34028723835945129,
-0.29413089156150818,
-0.24994957447052002,
-0.21715600788593292,
-0.18792112171649933,
-0.15268312394618988,
-0.12135542929172516,
-0.099610626697540283,
-0.075273610651493073,
-0.048787496984004974,
-0.042586319148540497,
-0.028991291299462318,
-0.011869125068187714,
};
static double const shl48[] = {
2.3925774097442626953, -3.4350297451019287109, 3.1853709220886230469,
-1.8117271661758422852, -0.20124770700931549072, 1.4759907722473144531,
-1.7210904359817504883, 0.97746700048446655273, -0.13790138065814971924,
-0.38185903429985046387, 0.27421241998672485352, 0.066584214568138122559,
-0.35223302245140075684, 0.37672343850135803223, -0.23964276909828186035,
0.068674825131893157959,
};
static double const shl44[] = {
2.0833916664123535156, -3.0418450832366943359, 3.2047898769378662109,
-2.7571926116943359375, 1.4978630542755126953, -0.3427594602108001709,
-0.71733748912811279297, 1.0737057924270629883, -1.0225815773010253906,
0.56649994850158691406, -0.20968692004680633545, -0.065378531813621520996,
0.10322438180446624756, -0.067442022264003753662, -0.00495197344571352005,
};
static double const shh44[] = {
3.0259189605712890625, -6.0268716812133789062, 9.195003509521484375,
-11.824929237365722656, 12.767142295837402344, -11.917946815490722656,
9.1739168167114257812, -5.3712320327758789062, 1.1393624544143676758,
2.4484779834747314453, -4.9719839096069335938, 6.0392003059387207031,
-5.9359521865844726562, 4.903278350830078125, -3.5527443885803222656,
2.1909697055816650391, -1.1672389507293701172, 0.4903914332389831543,
-0.16519790887832641602, 0.023217858746647834778,
};
static const filter_t filters[] = {
{44100, fir, 5, 210, lip44, Shape_lipshitz},
{46000, fir, 9, 276, fwe44, Shape_f_weighted},
{46000, fir, 9, 160, mew44, Shape_modified_e_weighted},
{46000, fir, 9, 321, iew44, Shape_improved_e_weighted},
{48000, iir, 4, 220, ges48, Shape_gesemann},
{44100, iir, 4, 230, ges44, Shape_gesemann},
{48000, fir, 16, 301, shi48, Shape_shibata},
{44100, fir, 20, 333, shi44, Shape_shibata},
{37800, fir, 16, 240, shi38, Shape_shibata},
{32000, fir, 20, 240/*TBD*/, shi32, Shape_shibata},
{22050, fir, 20, 240/*TBD*/, shi22, Shape_shibata},
{16000, fir, 20, 240/*TBD*/, shi16, Shape_shibata},
{11025, fir, 20, 240/*TBD*/, shi11, Shape_shibata},
{ 8000, fir, 20, 240/*TBD*/, shi08, Shape_shibata},
{48000, fir, 16, 250, shl48, Shape_low_shibata},
{44100, fir, 15, 250, shl44, Shape_low_shibata},
{44100, fir, 20, 383, shh44, Shape_high_shibata},
{ 0, fir, 0, 0, NULL, Shape_none},
};
#define MAX_N 20
typedef struct {
filter_name_t filter_name;
sox_bool auto_detect, alt_tpdf;
double dummy;
double previous_errors[MAX_N * 2];
double previous_outputs[MAX_N * 2];
size_t pos, prec;
uint64_t num_output;
int32_t history, ranqd1, r;
double const * coefs;
sox_bool dither_off;
sox_effect_handler_flow flow;
} priv_t;
#define CONVOLVE _ _ _ _
#define NAME flow_iir_4
#define IIR
#define N 4
#include "dither.h"
#undef IIR
#define CONVOLVE _ _ _ _ _
#define NAME flow_fir_5
#define N 5
#include "dither.h"
#define CONVOLVE _ _ _ _ _ _ _ _ _
#define NAME flow_fir_9
#define N 9
#include "dither.h"
#define CONVOLVE _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
#define NAME flow_fir_15
#define N 15
#include "dither.h"
#define CONVOLVE _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
#define NAME flow_fir_16
#define N 16
#include "dither.h"
#define CONVOLVE _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
#define NAME flow_fir_20
#define N 20
#include "dither.h"
static int flow_no_shape(sox_effect_t * effp, const sox_sample_t * ibuf,
sox_sample_t * obuf, size_t * isamp, size_t * osamp)
{
priv_t * p = (priv_t *)effp->priv;
size_t len = *isamp = *osamp = min(*isamp, *osamp);
while (len--) {
if (p->auto_detect) {
p->history = (p->history << 1) +
!!(*ibuf & (((unsigned)-1) >> p->prec));
if (p->history && p->dither_off) {
p->dither_off = sox_false;
lsx_debug("flow %" PRIuPTR ": on @ %" PRIu64, effp->flow, p->num_output);
} else if (!p->history && !p->dither_off) {
p->dither_off = sox_true;
lsx_debug("flow %" PRIuPTR ": off @ %" PRIu64, effp->flow, p->num_output);
}
}
if (!p->dither_off) {
int32_t r = RANQD1 >> p->prec;
double d = ((double)*ibuf++ + r + (p->alt_tpdf? -p->r : (RANQD1 >> p->prec))) / (1 << (32 - p->prec));
int i = d < 0? d - .5 : d + .5;
p->r = r;
if (i <= (-1 << (p->prec-1)))
++effp->clips, *obuf = SOX_SAMPLE_MIN;
else if (i > (int)SOX_INT_MAX(p->prec))
++effp->clips, *obuf = SOX_INT_MAX(p->prec) << (32 - p->prec);
else *obuf = i << (32 - p->prec);
++obuf;
}
else
*obuf++ = *ibuf++;
++p->num_output;
}
return SOX_SUCCESS;
}
static int getopts(sox_effect_t * effp, int argc, char * * argv)
{
priv_t * p = (priv_t *)effp->priv;
int c;
lsx_getopt_t optstate;
lsx_getopt_init(argc, argv, "+aSsf:p:", NULL, lsx_getopt_flag_none, 1, &optstate);
while ((c = lsx_getopt(&optstate)) != -1) switch (c) {
case 'a': p->auto_detect = sox_true; break;
case 'S': p->alt_tpdf = sox_true; break;
case 's': p->filter_name = Shape_shibata; break;
case 'f':
p->filter_name = lsx_enum_option(c, optstate.arg, filter_names);
if (p->filter_name == INT_MAX)
return SOX_EOF;
break;
GETOPT_NUMERIC(optstate, 'p', prec, 1, 24)
default: lsx_fail("invalid option `-%c'", optstate.opt); return lsx_usage(effp);
}
argc -= optstate.ind, argv += optstate.ind;
return argc? lsx_usage(effp) : SOX_SUCCESS;
}
static int start(sox_effect_t * effp)
{
priv_t * p = (priv_t *)effp->priv;
double mult = 1; /* Amount the noise shaping multiplies up the TPDF (+/-1) */
if (p->prec == 0)
p->prec = effp->out_signal.precision;
if (effp->in_signal.precision <= p->prec || p->prec > 24)
return SOX_EFF_NULL; /* Dithering not needed at this resolution */
if (p->prec == 1) {
/* The general dither routines don't work in this case, so notify
user and leave it at that for now.
TODO: Some special-case treatment of 1-bit noise shaping will be
needed for meaningful DSD write support. */
lsx_warn("Dithering/noise-shaping to 1 bit is currently not supported.");
return SOX_EFF_NULL;
}
effp->out_signal.precision = p->prec;
p->flow = flow_no_shape;
if (p->filter_name) {
filter_t const * f;
for (f = filters; f->len && (f->name != p->filter_name || fabs(effp->in_signal.rate - f->rate) / f->rate > .05); ++f); /* 5% leeway on frequency */
if (!f->len) {
p->alt_tpdf |= effp->in_signal.rate >= 22050;
if (!effp->flow)
lsx_warn("no `%s' filter is available for rate %g; using %s TPDF",
lsx_find_enum_value(p->filter_name, filter_names)->text,
effp->in_signal.rate, p->alt_tpdf? "sloped" : "plain");
}
else {
assert(f->len <= MAX_N);
if (f->type == fir) switch(f->len) {
case 5: p->flow = flow_fir_5 ; break;
case 9: p->flow = flow_fir_9 ; break;
case 15: p->flow = flow_fir_15; break;
case 16: p->flow = flow_fir_16; break;
case 20: p->flow = flow_fir_20; break;
default: assert(sox_false);
} else switch(f->len) {
case 4: p->flow = flow_iir_4 ; break;
default: assert(sox_false);
}
p->coefs = f->coefs;
mult = dB_to_linear(f->gain_cB * 0.1);
}
}
p->ranqd1 = ranqd1(sox_globals.ranqd1) + effp->flow;
if (effp->in_signal.mult) /* (Takes account of ostart mult (sox.c). */
*effp->in_signal.mult *= (SOX_SAMPLE_MAX - (1 << (31 - p->prec)) *
(2 * mult + 1)) / (SOX_SAMPLE_MAX - (1 << (31 - p->prec)));
return SOX_SUCCESS;
}
static int flow(sox_effect_t * effp, const sox_sample_t * ibuf,
sox_sample_t * obuf, size_t * isamp, size_t * osamp)
{
priv_t * p = (priv_t *)effp->priv;
return p->flow(effp, ibuf, obuf, isamp, osamp);
}
sox_effect_handler_t const * lsx_dither_effect_fn(void)
{
static sox_effect_handler_t handler = {
"dither", "[-S|-s|-f filter] [-a] [-p precision]"
"\n (none) Use TPDF"
"\n -S Use sloped TPDF (without noise shaping)"
"\n -s Shape noise (with shibata filter)"
"\n -f name Set shaping filter to one of: lipshitz, f-weighted,"
"\n modified-e-weighted, improved-e-weighted, gesemann,"
"\n shibata, low-shibata, high-shibata."
"\n -a Automatically turn on & off dithering as needed (use with caution!)"
"\n -p bits Override the target sample precision",
SOX_EFF_PREC, getopts, start, flow, 0, 0, 0, sizeof(priv_t)
};
return &handler;
}

@ -0,0 +1,63 @@
#ifdef IIR
#define _ output += p->coefs[j] * p->previous_errors[p->pos + j] \
- p->coefs[N + j] * p->previous_outputs[p->pos + j], ++j;
#else
#define _ d -= p->coefs[j] * p->previous_errors[p->pos + j], ++j;
#endif
static int NAME(sox_effect_t * effp, const sox_sample_t * ibuf,
sox_sample_t * obuf, size_t * isamp, size_t * osamp)
{
priv_t * p = (priv_t *)effp->priv;
size_t len = *isamp = *osamp = min(*isamp, *osamp);
while (len--) {
if (p->auto_detect) {
p->history = (p->history << 1) +
!!(*ibuf & (((unsigned)-1) >> p->prec));
if (p->history && p->dither_off) {
p->dither_off = sox_false;
lsx_debug("flow %" PRIuPTR ": on @ %" PRIu64, effp->flow, p->num_output);
} else if (!p->history && !p->dither_off) {
p->dither_off = sox_true;
memset(p->previous_errors, 0, sizeof(p->previous_errors));
memset(p->previous_outputs, 0, sizeof(p->previous_outputs));
lsx_debug("flow %" PRIuPTR ": off @ %" PRIu64, effp->flow, p->num_output);
}
}
if (!p->dither_off) {
int32_t r1 = RANQD1 >> p->prec, r2 = RANQD1 >> p->prec; /* Defer add! */
#ifdef IIR
double d1, d, output = 0;
#else
double d1, d = *ibuf++;
#endif
int i, j = 0;
CONVOLVE
assert(j == N);
p->pos = p->pos? p->pos - 1 : p->pos - 1 + N;
#ifdef IIR
d = *ibuf++ - output;
p->previous_outputs[p->pos + N] = p->previous_outputs[p->pos] = output;
#endif
d1 = (d + r1 + r2) / (1 << (32 - p->prec));
i = d1 < 0? d1 - .5 : d1 + .5;
p->previous_errors[p->pos + N] = p->previous_errors[p->pos] =
(double)i * (1 << (32 - p->prec)) - d;
if (i < (-1 << (p->prec-1)))
++effp->clips, *obuf = SOX_SAMPLE_MIN;
else if (i > (int)SOX_INT_MAX(p->prec))
++effp->clips, *obuf = SOX_INT_MAX(p->prec) << (32 - p->prec);
else *obuf = i << (32 - p->prec);
++obuf;
}
else
*obuf++ = *ibuf++;
++p->num_output;
}
return SOX_SUCCESS;
}
#undef CONVOLVE
#undef _
#undef NAME
#undef N

@ -0,0 +1,73 @@
/* libSoX effect: divide Copyright (c) 2009 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* This is W.I.P. hence marked SOX_EFF_ALPHA for now.
* Needs better handling of when the divisor approaches or is zero; some
* sort of interpolation of the output values perhaps.
*/
#include "sox_i.h"
#include <string.h>
typedef struct {
sox_sample_t * last;
} priv_t;
static int start(sox_effect_t * effp)
{
priv_t * p = (priv_t *)effp->priv;
p->last = lsx_calloc(effp->in_signal.channels, sizeof(*p->last));
return SOX_SUCCESS;
}
static int flow(sox_effect_t * effp, const sox_sample_t * ibuf,
sox_sample_t * obuf, size_t * isamp, size_t * osamp)
{
priv_t * p = (priv_t *)effp->priv;
size_t i, len = min(*isamp, *osamp) / effp->in_signal.channels;
*osamp = *isamp = len * effp->in_signal.channels;
while (len--) {
double divisor = *obuf++ = *ibuf++;
if (divisor) {
double out, mult = 1. / SOX_SAMPLE_TO_FLOAT_64BIT(divisor,);
for (i = 1; i < effp->in_signal.channels; ++i) {
out = *ibuf++ * mult;
p->last[i] = *obuf++ = SOX_ROUND_CLIP_COUNT(out, effp->clips);
}
}
else for (i = 1; i < effp->in_signal.channels; ++i, ++ibuf)
*obuf++ = p->last[i];
}
return SOX_SUCCESS;
}
static int stop(sox_effect_t * effp)
{
priv_t * p = (priv_t *)effp->priv;
free(p->last);
return SOX_SUCCESS;
}
sox_effect_handler_t const * lsx_divide_effect_fn(void)
{
static sox_effect_handler_t handler = {
"divide", NULL, SOX_EFF_MCHAN | SOX_EFF_GAIN | SOX_EFF_ALPHA,
NULL, start, flow, NULL, stop, NULL, sizeof(priv_t)
};
return &handler;
}

@ -0,0 +1,85 @@
/* libSoX effect: Downsample
*
* First version of this effect written 11/2011 by Ulrich Klauer.
*
* Copyright 2011 Chris Bagwell and SoX Contributors
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
typedef struct {
unsigned int factor;
unsigned int carry; /* number of samples still to be discarded,
carried over from last block */
} priv_t;
static int create(sox_effect_t *effp, int argc, char **argv)
{
priv_t *p = (priv_t*)effp->priv;
p->factor = 2;
--argc, ++argv;
do { /* break-able block */
NUMERIC_PARAMETER(factor, 1, 16384)
} while (0);
return argc ? lsx_usage(effp) : SOX_SUCCESS;
}
static int start(sox_effect_t *effp)
{
priv_t *p = (priv_t*) effp->priv;
effp->out_signal.rate = effp->in_signal.rate / p->factor;
return p->factor == 1 ? SOX_EFF_NULL : SOX_SUCCESS;
}
static int flow(sox_effect_t *effp, const sox_sample_t *ibuf,
sox_sample_t *obuf, size_t *isamp, size_t *osamp)
{
priv_t *p = (priv_t*)effp->priv;
size_t ilen = *isamp, olen = *osamp;
size_t t;
t = min(p->carry, ilen);
p->carry -= t;
ibuf += t; ilen -= t;
/* NB: either p->carry (usually) or ilen is now zero; hence, a
non-zero value of ilen implies p->carry == 0, and there is no
need to test for this in the following while and if. */
while (ilen >= p->factor && olen) {
*obuf++ = *ibuf;
ibuf += p->factor;
olen--; ilen -= p->factor;
}
if (ilen && olen) {
*obuf++ = *ibuf;
p->carry = p->factor - ilen;
olen--; ilen = 0;
}
*isamp -= ilen, *osamp -= olen;
return SOX_SUCCESS;
}
sox_effect_handler_t const *lsx_downsample_effect_fn(void)
{
static sox_effect_handler_t handler = {"downsample", "[factor (2)]",
SOX_EFF_RATE | SOX_EFF_MODIFY,
create, start, flow, NULL, NULL, NULL, sizeof(priv_t)};
return &handler;
}

@ -0,0 +1,32 @@
/* libSoX file format: DVMS (see cvsd.c) (c) 2007-8 SoX contributors
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "cvsd.h"
LSX_FORMAT_HANDLER(dvms)
{
static char const * const names[] = {"dvms", "vms", NULL};
static unsigned const write_encodings[] = {SOX_ENCODING_CVSD, 1, 0, 0};
static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
"MIL Std 188 113 Continuously Variable Slope Delta modulation with header",
names, SOX_FILE_MONO,
lsx_dvmsstartread, lsx_cvsdread, lsx_cvsdstopread,
lsx_dvmsstartwrite, lsx_cvsdwrite, lsx_dvmsstopwrite,
NULL, write_encodings, NULL, sizeof(cvsd_priv_t)
};
return &handler;
}

@ -0,0 +1,97 @@
/* libSoX earwax - makes listening to headphones easier November 9, 2000
*
* Copyright (c) 2000 Edward Beingessner And Sundry Contributors.
* This source code is freely redistributable and may be used for any purpose.
* This copyright notice must be maintained. Edward Beingessner And Sundry
* Contributors are not responsible for the consequences of using this
* software.
*
* This effect takes a 44.1kHz stereo (CD format) signal that is meant to be
* listened to on headphones, and adds audio cues to move the soundstage from
* inside your head (standard for headphones) to outside and in front of the
* listener (standard for speakers). This makes the sound much easier to listen
* to on headphones.
*/
#include "sox_i.h"
#include <string.h>
static const sox_sample_t filt[32 * 2] = {
/* 30° 330° */
4, -6, /* 32 tap stereo FIR filter. */
4, -11, /* One side filters as if the */
-1, -5, /* signal was from 30 degrees */
3, 3, /* from the ear, the other as */
-2, 5, /* if 330 degrees. */
-5, 0,
9, 1,
6, 3, /* Input */
-4, -1, /* Left Right */
-5, -3, /* __________ __________ */
-2, -5, /* | | | | */
-7, 1, /* .---| Hh,0(f) | | Hh,0(f) |---. */
6, -7, /* / |__________| |__________| \ */
30, -29, /* / \ / \ */
12, -3, /* / X \ */
-11, 4, /* / / \ \ */
-3, 7, /* ____V_____ __________V V__________ _____V____ */
-20, 23, /* | | | | | | | | */
2, 0, /* | Hh,30(f) | | Hh,330(f)| | Hh,330(f)| | Hh,30(f) | */
1, -6, /* |__________| |__________| |__________| |__________| */
-14, -5, /* \ ___ / \ ___ / */
15, -18, /* \ / \ / _____ \ / \ / */
6, 7, /* `->| + |<--' / \ `-->| + |<-' */
15, -10, /* \___/ _/ \_ \___/ */
-14, 22, /* \ / \ / \ / */
-7, -2, /* `--->| | | |<---' */
-4, 9, /* \_/ \_/ */
6, -12, /* */
6, -6, /* Headphones */
0, -11,
0, -5,
4, 0};
#define NUMTAPS array_length(filt)
typedef struct {sox_sample_t tap[NUMTAPS];} priv_t; /* FIR filter z^-1 delays */
static int start(sox_effect_t * effp)
{
priv_t * p = (priv_t *)effp->priv;
if (effp->in_signal.rate != 44100 || effp->in_signal.channels != 2) {
lsx_fail("works only with stereo audio sampled at 44100Hz (i.e. CDDA)");
return SOX_EOF;
}
memset(p->tap, 0, NUMTAPS * sizeof(*p->tap)); /* zero tap memory */
if (effp->in_signal.mult)
*effp->in_signal.mult *= dB_to_linear(-4.4);
return SOX_SUCCESS;
}
static int flow(sox_effect_t * effp, const sox_sample_t * ibuf,
sox_sample_t * obuf, size_t * isamp, size_t * osamp)
{
priv_t * p = (priv_t *)effp->priv;
size_t i, len = *isamp = *osamp = min(*isamp, *osamp);
while (len--) { /* update taps and calculate output */
double output = 0;
for (i = NUMTAPS - 1; i; --i) {
p->tap[i] = p->tap[i - 1];
output += p->tap[i] * filt[i];
}
p->tap[0] = *ibuf++ / 64; /* scale output */
output += p->tap[0] * filt[0];
*obuf++ = SOX_ROUND_CLIP_COUNT(output, effp->clips);
}
return SOX_SUCCESS;
}
/* No drain: preserve audio file length; it's only 32 samples anyway. */
sox_effect_handler_t const *lsx_earwax_effect_fn(void)
{
static sox_effect_handler_t handler = {"earwax", NULL, SOX_EFF_MCHAN,
NULL, start, flow, NULL, NULL, NULL, sizeof(priv_t)};
return &handler;
}

@ -0,0 +1,266 @@
/* libSoX Echo effect August 24, 1998
*
* Copyright (C) 1998 Juergen Mueller And Sundry Contributors
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
* Juergen Mueller And Sundry Contributors are not responsible for
* the consequences of using this software.
*
*
* Flow diagram scheme for n delays ( 1 <= n <= MAX_ECHOS ):
*
* * gain-in ___
* ibuff -----------+------------------------------------------>| |
* | _________ | |
* | | | * decay 1 | |
* +----->| delay 1 |------------------------->| |
* | |_________| | |
* | _________ | + |
* | | | * decay 2 | |
* +---------->| delay 2 |-------------------->| |
* | |_________| | |
* : _________ | |
* | | | * decay n | |
* +--------------->| delay n |--------------->|___|
* |_________| |
* | * gain-out
* |
* +----->obuff
* Usage:
* echo gain-in gain-out delay-1 decay-1 [delay-2 decay-2 ... delay-n decay-n]
*
* Where:
* gain-in, decay-1 ... decay-n : 0.0 ... 1.0 volume
* gain-out : 0.0 ... volume
* delay-1 ... delay-n : > 0.0 msec
*
* Note:
* when decay is close to 1.0, the samples can begin clipping and the output
* can saturate!
*
* Hint:
* 1 / out-gain > gain-in ( 1 + decay-1 + ... + decay-n )
*/
#include "sox_i.h"
#include <stdlib.h> /* Harmless, and prototypes atof() etc. --dgc */
#define DELAY_BUFSIZ ( 50 * 50U * 1024 )
#define MAX_ECHOS 7 /* 24 bit x ( 1 + MAX_ECHOS ) = */
/* 24 bit x 8 = 32 bit !!! */
/* Private data for SKEL file */
typedef struct {
int counter;
int num_delays;
double *delay_buf;
float in_gain, out_gain;
float delay[MAX_ECHOS], decay[MAX_ECHOS];
ptrdiff_t samples[MAX_ECHOS], maxsamples;
size_t fade_out;
} priv_t;
/* Private data for SKEL file */
/*
* Process options
*/
static int sox_echo_getopts(sox_effect_t * effp, int argc, char **argv)
{
priv_t * echo = (priv_t *) effp->priv;
int i;
--argc, ++argv;
echo->num_delays = 0;
if ((argc < 4) || (argc % 2))
return lsx_usage(effp);
i = 0;
sscanf(argv[i++], "%f", &echo->in_gain);
sscanf(argv[i++], "%f", &echo->out_gain);
while (i < argc) {
if ( echo->num_delays >= MAX_ECHOS )
lsx_fail("echo: to many delays, use less than %i delays",
MAX_ECHOS);
/* Linux bug and it's cleaner. */
sscanf(argv[i++], "%f", &echo->delay[echo->num_delays]);
sscanf(argv[i++], "%f", &echo->decay[echo->num_delays]);
echo->num_delays++;
}
return (SOX_SUCCESS);
}
/*
* Prepare for processing.
*/
static int sox_echo_start(sox_effect_t * effp)
{
priv_t * echo = (priv_t *) effp->priv;
int i;
float sum_in_volume;
long j;
echo->maxsamples = 0;
if ( echo->in_gain < 0.0 )
{
lsx_fail("echo: gain-in must be positive!");
return (SOX_EOF);
}
if ( echo->in_gain > 1.0 )
{
lsx_fail("echo: gain-in must be less than 1.0!");
return (SOX_EOF);
}
if ( echo->out_gain < 0.0 )
{
lsx_fail("echo: gain-in must be positive!");
return (SOX_EOF);
}
for ( i = 0; i < echo->num_delays; i++ ) {
echo->samples[i] = echo->delay[i] * effp->in_signal.rate / 1000.0;
if ( echo->samples[i] < 1 )
{
lsx_fail("echo: delay must be positive!");
return (SOX_EOF);
}
if ( echo->samples[i] > (ptrdiff_t)DELAY_BUFSIZ )
{
lsx_fail("echo: delay must be less than %g seconds!",
DELAY_BUFSIZ / effp->in_signal.rate );
return (SOX_EOF);
}
if ( echo->decay[i] < 0.0 )
{
lsx_fail("echo: decay must be positive!" );
return (SOX_EOF);
}
if ( echo->decay[i] > 1.0 )
{
lsx_fail("echo: decay must be less than 1.0!" );
return (SOX_EOF);
}
if ( echo->samples[i] > echo->maxsamples )
echo->maxsamples = echo->samples[i];
}
echo->delay_buf = lsx_malloc(sizeof (double) * echo->maxsamples);
for ( j = 0; j < echo->maxsamples; ++j )
echo->delay_buf[j] = 0.0;
/* Be nice and check the hint with warning, if... */
sum_in_volume = 1.0;
for ( i = 0; i < echo->num_delays; i++ )
sum_in_volume += echo->decay[i];
if ( sum_in_volume * echo->in_gain > 1.0 / echo->out_gain )
lsx_warn("echo: warning >>> gain-out can cause saturation of output <<<");
echo->counter = 0;
echo->fade_out = echo->maxsamples;
effp->out_signal.length = SOX_UNKNOWN_LEN; /* TODO: calculate actual length */
return (SOX_SUCCESS);
}
/*
* Processed signed long samples from ibuf to obuf.
* Return number of samples processed.
*/
static int sox_echo_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,
size_t *isamp, size_t *osamp)
{
priv_t * echo = (priv_t *) effp->priv;
int j;
double d_in, d_out;
sox_sample_t out;
size_t len = min(*isamp, *osamp);
*isamp = *osamp = len;
while (len--) {
/* Store delays as 24-bit signed longs */
d_in = (double) *ibuf++ / 256;
/* Compute output first */
d_out = d_in * echo->in_gain;
for ( j = 0; j < echo->num_delays; j++ ) {
d_out += echo->delay_buf[
(echo->counter + echo->maxsamples - echo->samples[j]) % echo->maxsamples]
* echo->decay[j];
}
/* Adjust the output volume and size to 24 bit */
d_out = d_out * echo->out_gain;
out = SOX_24BIT_CLIP_COUNT((sox_sample_t) d_out, effp->clips);
*obuf++ = out * 256;
/* Store input in delay buffer */
echo->delay_buf[echo->counter] = d_in;
/* Adjust the counter */
echo->counter = ( echo->counter + 1 ) % echo->maxsamples;
}
/* processed all samples */
return (SOX_SUCCESS);
}
/*
* Drain out reverb lines.
*/
static int sox_echo_drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp)
{
priv_t * echo = (priv_t *) effp->priv;
double d_in, d_out;
sox_sample_t out;
int j;
size_t done;
done = 0;
/* drain out delay samples */
while ( ( done < *osamp ) && ( done < echo->fade_out ) ) {
d_in = 0;
d_out = 0;
for ( j = 0; j < echo->num_delays; j++ ) {
d_out += echo->delay_buf[
(echo->counter + echo->maxsamples - echo->samples[j]) % echo->maxsamples]
* echo->decay[j];
}
/* Adjust the output volume and size to 24 bit */
d_out = d_out * echo->out_gain;
out = SOX_24BIT_CLIP_COUNT((sox_sample_t) d_out, effp->clips);
*obuf++ = out * 256;
/* Store input in delay buffer */
echo->delay_buf[echo->counter] = d_in;
/* Adjust the counters */
echo->counter = ( echo->counter + 1 ) % echo->maxsamples;
done++;
echo->fade_out--;
};
/* samples played, it remains */
*osamp = done;
if (echo->fade_out == 0)
return SOX_EOF;
else
return SOX_SUCCESS;
}
static int sox_echo_stop(sox_effect_t * effp)
{
priv_t * echo = (priv_t *) effp->priv;
free(echo->delay_buf);
echo->delay_buf = NULL;
return (SOX_SUCCESS);
}
static sox_effect_handler_t sox_echo_effect = {
"echo",
"gain-in gain-out delay decay [ delay decay ... ]",
SOX_EFF_LENGTH | SOX_EFF_GAIN,
sox_echo_getopts,
sox_echo_start,
sox_echo_flow,
sox_echo_drain,
sox_echo_stop,
NULL, sizeof(priv_t)
};
const sox_effect_handler_t *lsx_echo_effect_fn(void)
{
return &sox_echo_effect;
}

@ -0,0 +1,278 @@
/* libSoX Echo effect August 24, 1998
*
* Copyright (C) 1998 Juergen Mueller And Sundry Contributors
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
* Juergen Mueller And Sundry Contributors are not responsible for
* the consequences of using this software.
*
*
* Flow diagram scheme for n delays ( 1 <= n <= MAX_ECHOS ):
*
* * gain-in ___
* ibuff --+--------------------------------------------------->| |
* | * decay 1 | |
* | +----------------------------------->| |
* | | * decay 2 | + |
* | | +--------------------->| |
* | | | * decay n | |
* | _________ | _________ | _________ +--->|___|
* | | | | | | | | | | |
* +-->| delay 1 |-+-| delay 2 |-+...-| delay n |--+ | * gain-out
* |_________| |_________| |_________| |
* +----->obuff
* Usage:
* echos gain-in gain-out delay-1 decay-1 [delay-2 decay-2 ... delay-n decay-n]
*
* Where:
* gain-in, decay-1 ... decay-n : 0.0 ... 1.0 volume
* gain-out : 0.0 ... volume
* delay-1 ... delay-n : > 0.0 msec
*
* Note:
* when decay is close to 1.0, the samples can begin clipping and the output
* can saturate!
*
* Hint:
* 1 / out-gain > gain-in ( 1 + decay-1 + ... + decay-n )
*
*/
#include "sox_i.h"
#include <stdlib.h> /* Harmless, and prototypes atof() etc. --dgc */
#define DELAY_BUFSIZ ( 50 * 50U * 1024 )
#define MAX_ECHOS 7 /* 24 bit x ( 1 + MAX_ECHOS ) = */
/* 24 bit x 8 = 32 bit !!! */
/* Private data for SKEL file */
typedef struct {
int counter[MAX_ECHOS];
int num_delays;
double *delay_buf;
float in_gain, out_gain;
float delay[MAX_ECHOS], decay[MAX_ECHOS];
ptrdiff_t samples[MAX_ECHOS], pointer[MAX_ECHOS];
size_t sumsamples;
} priv_t;
/* Private data for SKEL file */
/*
* Process options
*/
static int sox_echos_getopts(sox_effect_t * effp, int argc, char **argv)
{
priv_t * echos = (priv_t *) effp->priv;
int i;
echos->num_delays = 0;
--argc, ++argv;
if ((argc < 4) || (argc % 2))
return lsx_usage(effp);
i = 0;
sscanf(argv[i++], "%f", &echos->in_gain);
sscanf(argv[i++], "%f", &echos->out_gain);
while (i < argc) {
/* Linux bug and it's cleaner. */
sscanf(argv[i++], "%f", &echos->delay[echos->num_delays]);
sscanf(argv[i++], "%f", &echos->decay[echos->num_delays]);
echos->num_delays++;
if ( echos->num_delays > MAX_ECHOS )
{
lsx_fail("echos: to many delays, use less than %i delays",
MAX_ECHOS);
return (SOX_EOF);
}
}
echos->sumsamples = 0;
return (SOX_SUCCESS);
}
/*
* Prepare for processing.
*/
static int sox_echos_start(sox_effect_t * effp)
{
priv_t * echos = (priv_t *) effp->priv;
int i;
float sum_in_volume;
unsigned long j;
if ( echos->in_gain < 0.0 )
{
lsx_fail("echos: gain-in must be positive!");
return (SOX_EOF);
}
if ( echos->in_gain > 1.0 )
{
lsx_fail("echos: gain-in must be less than 1.0!");
return (SOX_EOF);
}
if ( echos->out_gain < 0.0 )
{
lsx_fail("echos: gain-in must be positive!");
return (SOX_EOF);
}
for ( i = 0; i < echos->num_delays; i++ ) {
echos->samples[i] = echos->delay[i] * effp->in_signal.rate / 1000.0;
if ( echos->samples[i] < 1 )
{
lsx_fail("echos: delay must be positive!");
return (SOX_EOF);
}
if ( echos->samples[i] > (ptrdiff_t)DELAY_BUFSIZ )
{
lsx_fail("echos: delay must be less than %g seconds!",
DELAY_BUFSIZ / effp->in_signal.rate );
return (SOX_EOF);
}
if ( echos->decay[i] < 0.0 )
{
lsx_fail("echos: decay must be positive!" );
return (SOX_EOF);
}
if ( echos->decay[i] > 1.0 )
{
lsx_fail("echos: decay must be less than 1.0!" );
return (SOX_EOF);
}
echos->counter[i] = 0;
echos->pointer[i] = echos->sumsamples;
echos->sumsamples += echos->samples[i];
}
echos->delay_buf = lsx_malloc(sizeof (double) * echos->sumsamples);
for ( j = 0; j < echos->sumsamples; ++j )
echos->delay_buf[j] = 0.0;
/* Be nice and check the hint with warning, if... */
sum_in_volume = 1.0;
for ( i = 0; i < echos->num_delays; i++ )
sum_in_volume += echos->decay[i];
if ( sum_in_volume * echos->in_gain > 1.0 / echos->out_gain )
lsx_warn("echos: warning >>> gain-out can cause saturation of output <<<");
effp->out_signal.length = SOX_UNKNOWN_LEN; /* TODO: calculate actual length */
return (SOX_SUCCESS);
}
/*
* Processed signed long samples from ibuf to obuf.
* Return number of samples processed.
*/
static int sox_echos_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,
size_t *isamp, size_t *osamp)
{
priv_t * echos = (priv_t *) effp->priv;
int j;
double d_in, d_out;
sox_sample_t out;
size_t len = min(*isamp, *osamp);
*isamp = *osamp = len;
while (len--) {
/* Store delays as 24-bit signed longs */
d_in = (double) *ibuf++ / 256;
/* Compute output first */
d_out = d_in * echos->in_gain;
for ( j = 0; j < echos->num_delays; j++ ) {
d_out += echos->delay_buf[echos->counter[j] + echos->pointer[j]] * echos->decay[j];
}
/* Adjust the output volume and size to 24 bit */
d_out = d_out * echos->out_gain;
out = SOX_24BIT_CLIP_COUNT((sox_sample_t) d_out, effp->clips);
*obuf++ = out * 256;
/* Mix decay of delays and input */
for ( j = 0; j < echos->num_delays; j++ ) {
if ( j == 0 )
echos->delay_buf[echos->counter[j] + echos->pointer[j]] = d_in;
else
echos->delay_buf[echos->counter[j] + echos->pointer[j]] =
echos->delay_buf[echos->counter[j-1] + echos->pointer[j-1]] + d_in;
}
/* Adjust the counters */
for ( j = 0; j < echos->num_delays; j++ )
echos->counter[j] =
( echos->counter[j] + 1 ) % echos->samples[j];
}
/* processed all samples */
return (SOX_SUCCESS);
}
/*
* Drain out reverb lines.
*/
static int sox_echos_drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp)
{
priv_t * echos = (priv_t *) effp->priv;
double d_in, d_out;
sox_sample_t out;
int j;
size_t done;
done = 0;
/* drain out delay samples */
while ( ( done < *osamp ) && ( done < echos->sumsamples ) ) {
d_in = 0;
d_out = 0;
for ( j = 0; j < echos->num_delays; j++ ) {
d_out += echos->delay_buf[echos->counter[j] + echos->pointer[j]] * echos->decay[j];
}
/* Adjust the output volume and size to 24 bit */
d_out = d_out * echos->out_gain;
out = SOX_24BIT_CLIP_COUNT((sox_sample_t) d_out, effp->clips);
*obuf++ = out * 256;
/* Mix decay of delays and input */
for ( j = 0; j < echos->num_delays; j++ ) {
if ( j == 0 )
echos->delay_buf[echos->counter[j] + echos->pointer[j]] = d_in;
else
echos->delay_buf[echos->counter[j] + echos->pointer[j]] =
echos->delay_buf[echos->counter[j-1] + echos->pointer[j-1]];
}
/* Adjust the counters */
for ( j = 0; j < echos->num_delays; j++ )
echos->counter[j] =
( echos->counter[j] + 1 ) % echos->samples[j];
done++;
echos->sumsamples--;
};
/* samples played, it remains */
*osamp = done;
if (echos->sumsamples == 0)
return SOX_EOF;
else
return SOX_SUCCESS;
}
/*
* Clean up echos effect.
*/
static int sox_echos_stop(sox_effect_t * effp)
{
priv_t * echos = (priv_t *) effp->priv;
free(echos->delay_buf);
echos->delay_buf = NULL;
return (SOX_SUCCESS);
}
static sox_effect_handler_t sox_echos_effect = {
"echos",
"gain-in gain-out delay decay [ delay decay ... ]",
SOX_EFF_LENGTH | SOX_EFF_GAIN,
sox_echos_getopts,
sox_echos_start,
sox_echos_flow,
sox_echos_drain,
sox_echos_stop,
NULL, sizeof(priv_t)
};
const sox_effect_handler_t *lsx_echos_effect_fn(void)
{
return &sox_echos_effect;
}

@ -0,0 +1,669 @@
/* SoX Effects chain (c) 2007 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define LSX_EFF_ALIAS
#include "sox_i.h"
#include <assert.h>
#include <string.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#define DEBUG_EFFECTS_CHAIN 0
/* Default effect handler functions for do-nothing situations: */
static int default_function(sox_effect_t * effp UNUSED)
{
return SOX_SUCCESS;
}
/* Pass through samples verbatim */
int lsx_flow_copy(sox_effect_t * effp UNUSED, const sox_sample_t * ibuf,
sox_sample_t * obuf, size_t * isamp, size_t * osamp)
{
*isamp = *osamp = min(*isamp, *osamp);
memcpy(obuf, ibuf, *isamp * sizeof(*obuf));
return SOX_SUCCESS;
}
/* Inform no more samples to drain */
static int default_drain(sox_effect_t * effp UNUSED, sox_sample_t *obuf UNUSED, size_t *osamp)
{
*osamp = 0;
return SOX_EOF;
}
/* Check that no parameters have been given */
static int default_getopts(sox_effect_t * effp, int argc, char **argv UNUSED)
{
return --argc? lsx_usage(effp) : SOX_SUCCESS;
}
/* Partially initialise the effect structure; signal info will come later */
sox_effect_t * sox_create_effect(sox_effect_handler_t const * eh)
{
sox_effect_t * effp = lsx_calloc(1, sizeof(*effp));
effp->obuf = NULL;
effp->global_info = sox_get_effects_globals();
effp->handler = *eh;
if (!effp->handler.getopts) effp->handler.getopts = default_getopts;
if (!effp->handler.start ) effp->handler.start = default_function;
if (!effp->handler.flow ) effp->handler.flow = lsx_flow_copy;
if (!effp->handler.drain ) effp->handler.drain = default_drain;
if (!effp->handler.stop ) effp->handler.stop = default_function;
if (!effp->handler.kill ) effp->handler.kill = default_function;
effp->priv = lsx_calloc(1, effp->handler.priv_size);
return effp;
} /* sox_create_effect */
int sox_effect_options(sox_effect_t *effp, int argc, char * const argv[])
{
int result;
char * * argv2 = lsx_malloc((argc + 1) * sizeof(*argv2));
argv2[0] = (char *)effp->handler.name;
memcpy(argv2 + 1, argv, argc * sizeof(*argv2));
result = effp->handler.getopts(effp, argc + 1, argv2);
free(argv2);
return result;
} /* sox_effect_options */
/* Effects chain: */
sox_effects_chain_t * sox_create_effects_chain(
sox_encodinginfo_t const * in_enc, sox_encodinginfo_t const * out_enc)
{
sox_effects_chain_t * result = lsx_calloc(1, sizeof(sox_effects_chain_t));
result->global_info = *sox_get_effects_globals();
result->in_enc = in_enc;
result->out_enc = out_enc;
return result;
} /* sox_create_effects_chain */
void sox_delete_effects_chain(sox_effects_chain_t *ecp)
{
if (ecp && ecp->length)
sox_delete_effects(ecp);
free(ecp->effects);
free(ecp);
} /* sox_delete_effects_chain */
/* Effect can call in start() or flow() to set minimum input size to flow() */
int lsx_effect_set_imin(sox_effect_t * effp, size_t imin)
{
if (imin > sox_globals.bufsiz / effp->flows) {
lsx_fail("sox_bufsiz not big enough");
return SOX_EOF;
}
effp->imin = imin;
return SOX_SUCCESS;
}
/* Effects table to be extended in steps of EFF_TABLE_STEP */
#define EFF_TABLE_STEP 8
/* Add an effect to the chain. *in is the input signal for this effect. *out is
* a suggestion as to what the output signal should be, but depending on its
* given options and *in, the effect can choose to do differently. Whatever
* output rate and channels the effect does produce are written back to *in,
* ready for the next effect in the chain.
*/
int sox_add_effect(sox_effects_chain_t * chain, sox_effect_t * effp, sox_signalinfo_t * in, sox_signalinfo_t const * out)
{
int ret, (*start)(sox_effect_t * effp) = effp->handler.start;
size_t f;
sox_effect_t eff0; /* Copy of effect for flow 0 before calling start */
effp->global_info = &chain->global_info;
effp->in_signal = *in;
effp->out_signal = *out;
effp->in_encoding = chain->in_enc;
effp->out_encoding = chain->out_enc;
if (!(effp->handler.flags & SOX_EFF_CHAN))
effp->out_signal.channels = in->channels;
if (!(effp->handler.flags & SOX_EFF_RATE))
effp->out_signal.rate = in->rate;
if (!(effp->handler.flags & SOX_EFF_PREC))
effp->out_signal.precision = (effp->handler.flags & SOX_EFF_MODIFY)?
in->precision : SOX_SAMPLE_PRECISION;
if (!(effp->handler.flags & SOX_EFF_GAIN))
effp->out_signal.mult = in->mult;
effp->flows =
(effp->handler.flags & SOX_EFF_MCHAN)? 1 : effp->in_signal.channels;
effp->clips = 0;
effp->imin = 0;
eff0 = *effp, eff0.priv = lsx_memdup(eff0.priv, eff0.handler.priv_size);
eff0.in_signal.mult = NULL; /* Only used in channel 0 */
ret = start(effp);
if (ret == SOX_EFF_NULL) {
lsx_report("has no effect in this configuration");
free(eff0.priv);
effp->handler.kill(effp);
free(effp->priv);
effp->priv = NULL;
return SOX_SUCCESS;
}
if (ret != SOX_SUCCESS) {
free(eff0.priv);
return SOX_EOF;
}
if (in->mult)
lsx_debug("mult=%g", *in->mult);
if (!(effp->handler.flags & SOX_EFF_LENGTH)) {
effp->out_signal.length = in->length;
if (effp->out_signal.length != SOX_UNKNOWN_LEN) {
if (effp->handler.flags & SOX_EFF_CHAN)
effp->out_signal.length =
effp->out_signal.length / in->channels * effp->out_signal.channels;
if (effp->handler.flags & SOX_EFF_RATE)
effp->out_signal.length =
effp->out_signal.length / in->rate * effp->out_signal.rate + .5;
}
}
*in = effp->out_signal;
if (chain->length == chain->table_size) {
chain->table_size += EFF_TABLE_STEP;
lsx_debug_more("sox_add_effect: extending effects table, "
"new size = %" PRIuPTR, chain->table_size);
lsx_revalloc(chain->effects, chain->table_size);
}
chain->effects[chain->length] =
lsx_calloc(effp->flows, sizeof(chain->effects[chain->length][0]));
chain->effects[chain->length][0] = *effp;
for (f = 1; f < effp->flows; ++f) {
chain->effects[chain->length][f] = eff0;
chain->effects[chain->length][f].flow = f;
chain->effects[chain->length][f].priv = lsx_memdup(eff0.priv, eff0.handler.priv_size);
if (start(&chain->effects[chain->length][f]) != SOX_SUCCESS) {
free(eff0.priv);
return SOX_EOF;
}
}
++chain->length;
free(eff0.priv);
return SOX_SUCCESS;
}
/* An effect's output buffer (effp->obuf) generally has this layout:
* |. . . A1A2A3B1B2B3C1C2C3. . . . . . . . . . . . . . . . . . |
* ^0 ^obeg ^oend ^bufsiz
* (where A1 is the first sample of channel 1, A2 the first sample of
* channel 2, etc.), i.e. the channels are interleaved.
* However, while sox_flow_effects() is running, output buffers are
* adapted to how the following effect expects its input, to avoid
* back-and-forth conversions. If the following effect operates on
* each of several channels separately (flows > 1), the layout is
* changed to this uninterleaved form:
* |. A1B1C1. . . . . . . A2B2C2. . . . . . . A3B3C3. . . . . . |
* ^0 ^obeg ^oend ^bufsiz
* <--- channel 1 ----><--- channel 2 ----><--- channel 3 ---->
* The buffer is logically subdivided into channel buffers of size
* bufsiz/flows each, starting at offsets 0, bufsiz/flows,
* 2*(bufsiz/flows) etc. Within the channel buffers, the data starts
* at position obeg/flows and ends before oend/flows. In case bufsiz
* is not evenly divisible by flows, there will be an unused area at
* the very end of the output buffer.
* The interleave() and deinterleave() functions convert between these
* two representations.
*/
static void interleave(size_t flows, size_t length, sox_sample_t *from,
size_t bufsiz, size_t offset, sox_sample_t *to);
static void deinterleave(size_t flows, size_t length, sox_sample_t *from,
sox_sample_t *to, size_t bufsiz, size_t offset);
static int flow_effect(sox_effects_chain_t * chain, size_t n)
{
sox_effect_t *effp1 = chain->effects[n - 1];
sox_effect_t *effp = chain->effects[n];
int effstatus = SOX_SUCCESS;
size_t f = 0;
size_t idone = effp1->oend - effp1->obeg;
size_t obeg = sox_globals.bufsiz - effp->oend;
sox_bool il_change = (effp->flows == 1) !=
(chain->length == n + 1 || chain->effects[n+1]->flows == 1);
#if DEBUG_EFFECTS_CHAIN
size_t pre_idone = idone;
size_t pre_odone = obeg;
#endif
if (effp->flows == 1) { /* Run effect on all channels at once */
idone -= idone % effp->in_signal.channels;
effstatus = effp->handler.flow(effp, effp1->obuf + effp1->obeg,
il_change ? chain->il_buf : effp->obuf + effp->oend,
&idone, &obeg);
if (obeg % effp->out_signal.channels != 0) {
lsx_fail("multi-channel effect flowed asymmetrically!");
effstatus = SOX_EOF;
}
if (il_change)
deinterleave(chain->effects[n+1]->flows, obeg, chain->il_buf,
effp->obuf, sox_globals.bufsiz, effp->oend);
} else { /* Run effect on each channel individually */
sox_sample_t *obuf = il_change ? chain->il_buf : effp->obuf;
size_t flow_offs = sox_globals.bufsiz/effp->flows;
size_t idone_min = SOX_SIZE_MAX, idone_max = 0;
size_t odone_min = SOX_SIZE_MAX, odone_max = 0;
#ifdef HAVE_OPENMP_3_1
#pragma omp parallel for \
if(sox_globals.use_threads) \
schedule(static) default(none) \
shared(effp,effp1,idone,obeg,obuf,flow_offs,chain,n,effstatus) \
reduction(min:idone_min,odone_min) reduction(max:idone_max,odone_max)
#elif defined HAVE_OPENMP
#pragma omp parallel for \
if(sox_globals.use_threads) \
schedule(static) default(none) \
shared(effp,effp1,idone,obeg,obuf,flow_offs,chain,n,effstatus) \
firstprivate(idone_min,odone_min,idone_max,odone_max) \
lastprivate(idone_min,odone_min,idone_max,odone_max)
#endif
for (f = 0; f < effp->flows; ++f) {
size_t idonec = idone / effp->flows;
size_t odonec = obeg / effp->flows;
int eff_status_c = effp->handler.flow(&chain->effects[n][f],
effp1->obuf + f*flow_offs + effp1->obeg/effp->flows,
obuf + f*flow_offs + effp->oend/effp->flows,
&idonec, &odonec);
idone_min = min(idonec, idone_min); idone_max = max(idonec, idone_max);
odone_min = min(odonec, odone_min); odone_max = max(odonec, odone_max);
if (eff_status_c != SOX_SUCCESS)
effstatus = SOX_EOF;
}
if (idone_min != idone_max || odone_min != odone_max) {
lsx_fail("flowed asymmetrically!");
effstatus = SOX_EOF;
}
idone = effp->flows * idone_max;
obeg = effp->flows * odone_max;
if (il_change)
interleave(effp->flows, obeg, chain->il_buf, sox_globals.bufsiz,
effp->oend, effp->obuf + effp->oend);
}
effp1->obeg += idone;
if (effp1->obeg == effp1->oend)
effp1->obeg = effp1->oend = 0;
else if (effp1->oend - effp1->obeg < effp->imin) { /* Need to refill? */
size_t flow_offs = sox_globals.bufsiz/effp->flows;
for (f = 0; f < effp->flows; ++f)
memcpy(effp1->obuf + f * flow_offs,
effp1->obuf + f * flow_offs + effp1->obeg/effp->flows,
(effp1->oend - effp1->obeg)/effp->flows * sizeof(*effp1->obuf));
effp1->oend -= effp1->obeg;
effp1->obeg = 0;
}
effp->oend += obeg;
#if DEBUG_EFFECTS_CHAIN
lsx_report("\t" "flow: %2" PRIuPTR " (%1" PRIuPTR ") "
"%5" PRIuPTR " %5" PRIuPTR " %5" PRIuPTR " %5" PRIuPTR " "
"%5" PRIuPTR " [%" PRIuPTR "-%" PRIuPTR "]",
n, effp->flows, pre_idone, pre_odone, idone, obeg,
effp1->oend - effp1->obeg, effp1->obeg, effp1->oend);
#endif
return effstatus == SOX_SUCCESS? SOX_SUCCESS : SOX_EOF;
}
/* The same as flow_effect but with no input */
static int drain_effect(sox_effects_chain_t * chain, size_t n)
{
sox_effect_t *effp = chain->effects[n];
int effstatus = SOX_SUCCESS;
size_t f = 0;
size_t obeg = sox_globals.bufsiz - effp->oend;
sox_bool il_change = (effp->flows == 1) !=
(chain->length == n + 1 || chain->effects[n+1]->flows == 1);
#if DEBUG_EFFECTS_CHAIN
size_t pre_odone = obeg;
#endif
if (effp->flows == 1) { /* Run effect on all channels at once */
effstatus = effp->handler.drain(effp,
il_change ? chain->il_buf : effp->obuf + effp->oend,
&obeg);
if (obeg % effp->out_signal.channels != 0) {
lsx_fail("multi-channel effect drained asymmetrically!");
effstatus = SOX_EOF;
}
if (il_change)
deinterleave(chain->effects[n+1]->flows, obeg, chain->il_buf,
effp->obuf, sox_globals.bufsiz, effp->oend);
} else { /* Run effect on each channel individually */
sox_sample_t *obuf = il_change ? chain->il_buf : effp->obuf;
size_t flow_offs = sox_globals.bufsiz/effp->flows;
size_t odone_last = 0; /* Initialised to prevent warning */
for (f = 0; f < effp->flows; ++f) {
size_t odonec = obeg / effp->flows;
int eff_status_c = effp->handler.drain(&chain->effects[n][f],
obuf + f*flow_offs + effp->oend/effp->flows,
&odonec);
if (f && (odonec != odone_last)) {
lsx_fail("drained asymmetrically!");
effstatus = SOX_EOF;
}
odone_last = odonec;
if (eff_status_c != SOX_SUCCESS)
effstatus = SOX_EOF;
}
obeg = effp->flows * odone_last;
if (il_change)
interleave(effp->flows, obeg, chain->il_buf, sox_globals.bufsiz,
effp->oend, effp->obuf + effp->oend);
}
if (!obeg) /* This is the only thing that drain has and flow hasn't */
effstatus = SOX_EOF;
effp->oend += obeg;
#if DEBUG_EFFECTS_CHAIN
lsx_report("\t" "drain: %2" PRIuPTR " (%1" PRIuPTR ") "
"%5" PRIuPTR " %5" PRIuPTR " %5" PRIuPTR " %5" PRIuPTR,
n, effp->flows, (size_t)0, pre_odone, (size_t)0, obeg);
#endif
return effstatus == SOX_SUCCESS? SOX_SUCCESS : SOX_EOF;
}
/* Flow data through the effects chain until an effect or callback gives EOF */
int sox_flow_effects(sox_effects_chain_t * chain, int (* callback)(sox_bool all_done, void * client_data), void * client_data)
{
int flow_status = SOX_SUCCESS;
size_t e, source_e = 0; /* effect indices */
size_t max_flows = 0;
sox_bool draining = sox_true;
for (e = 0; e < chain->length; ++e) {
sox_effect_t *effp = chain->effects[e];
effp->obuf =
lsx_realloc(effp->obuf, sox_globals.bufsiz * sizeof(*effp->obuf));
/* Memory will be freed by sox_delete_effect() later. */
/* Possibly there was already a buffer, if this is a used effect;
it may still contain samples in that case. */
if (effp->oend > sox_globals.bufsiz) {
lsx_warn("buffer size insufficient; buffered samples were dropped");
/* can only happen if bufsize has been reduced since the last run */
effp->obeg = effp->oend = 0;
}
max_flows = max(max_flows, effp->flows);
}
if (max_flows > 1) /* might need interleave buffer */
chain->il_buf = lsx_malloc(sox_globals.bufsiz * sizeof(sox_sample_t));
else
chain->il_buf = NULL;
/* Go through the effects, and if there are samples in one of the
buffers, deinterleave it (if necessary). */
for (e = 0; e + 1 < chain->length; e++) {
sox_effect_t *effp = chain->effects[e];
if (effp->oend > effp->obeg && chain->effects[e+1]->flows > 1) {
sox_sample_t *sw = chain->il_buf; chain->il_buf = effp->obuf; effp->obuf = sw;
deinterleave(chain->effects[e+1]->flows, effp->oend - effp->obeg,
chain->il_buf, effp->obuf, sox_globals.bufsiz, effp->obeg);
}
}
e = chain->length - 1;
while (source_e < chain->length) {
#define have_imin (e > 0 && e < chain->length && chain->effects[e - 1]->oend - chain->effects[e - 1]->obeg >= chain->effects[e]->imin)
size_t osize = chain->effects[e]->oend - chain->effects[e]->obeg;
if (e == source_e && (draining || !have_imin)) {
if (drain_effect(chain, e) == SOX_EOF) {
++source_e;
draining = sox_false;
}
} else if (have_imin && flow_effect(chain, e) == SOX_EOF) {
flow_status = SOX_EOF;
if (e == chain->length - 1)
break;
source_e = e;
draining = sox_true;
}
if (e < chain->length && chain->effects[e]->oend - chain->effects[e]->obeg > osize) /* False for output */
++e;
else if (e == source_e)
draining = sox_true;
else if (e < source_e)
e = source_e;
else
--e;
if (callback && callback(source_e == chain->length, client_data) != SOX_SUCCESS) {
flow_status = SOX_EOF; /* Client has requested to stop the flow. */
break;
}
}
/* If an effect's output buffer still has samples, and if it is
uninterleaved, then re-interleave it. Necessary since it might
be reused, and at that time possibly followed by an MCHAN effect. */
for (e = 0; e + 1 < chain->length; e++) {
sox_effect_t *effp = chain->effects[e];
if (effp->oend > effp->obeg && chain->effects[e+1]->flows > 1) {
sox_sample_t *sw = chain->il_buf; chain->il_buf = effp->obuf; effp->obuf = sw;
interleave(chain->effects[e+1]->flows, effp->oend - effp->obeg,
chain->il_buf, sox_globals.bufsiz, effp->obeg, effp->obuf);
}
}
free(chain->il_buf);
return flow_status;
}
sox_uint64_t sox_effects_clips(sox_effects_chain_t * chain)
{
size_t i, f;
uint64_t clips = 0;
for (i = 1; i < chain->length - 1; ++i)
for (f = 0; f < chain->effects[i][0].flows; ++f)
clips += chain->effects[i][f].clips;
return clips;
}
sox_uint64_t sox_stop_effect(sox_effect_t *effp)
{
size_t f;
uint64_t clips = 0;
for (f = 0; f < effp->flows; ++f) {
effp[f].handler.stop(&effp[f]);
clips += effp[f].clips;
}
return clips;
}
void sox_push_effect_last(sox_effects_chain_t *chain, sox_effect_t *effp)
{
if (chain->length == chain->table_size) {
chain->table_size += EFF_TABLE_STEP;
lsx_debug_more("sox_push_effect_last: extending effects table, "
"new size = %" PRIuPTR, chain->table_size);
lsx_revalloc(chain->effects, chain->table_size);
}
chain->effects[chain->length++] = effp;
} /* sox_push_effect_last */
sox_effect_t *sox_pop_effect_last(sox_effects_chain_t *chain)
{
if (chain->length > 0)
{
sox_effect_t *effp;
chain->length--;
effp = chain->effects[chain->length];
chain->effects[chain->length] = NULL;
return effp;
}
else
return NULL;
} /* sox_pop_effect_last */
/* Free resources related to effect.
* Note: This currently closes down the effect which might
* not be obvious from name.
*/
void sox_delete_effect(sox_effect_t *effp)
{
uint64_t clips;
size_t f;
if ((clips = sox_stop_effect(effp)) != 0)
lsx_warn("%s clipped %" PRIu64 " samples; decrease volume?",
effp->handler.name, clips);
if (effp->obeg != effp->oend)
lsx_debug("output buffer still held %" PRIuPTR " samples; dropped.",
(effp->oend - effp->obeg)/effp->out_signal.channels);
/* May or may not indicate a problem; it is normal if the user aborted
processing, or if an effect like "trim" stopped early. */
effp->handler.kill(effp); /* N.B. only one kill; not one per flow */
for (f = 0; f < effp->flows; ++f)
free(effp[f].priv);
free(effp->obuf);
free(effp);
}
void sox_delete_effect_last(sox_effects_chain_t *chain)
{
if (chain->length > 0)
{
chain->length--;
sox_delete_effect(chain->effects[chain->length]);
chain->effects[chain->length] = NULL;
}
} /* sox_delete_effect_last */
/* Remove all effects from the chain.
* Note: This currently closes down the effect which might
* not be obvious from name.
*/
void sox_delete_effects(sox_effects_chain_t * chain)
{
size_t e;
for (e = 0; e < chain->length; ++e) {
sox_delete_effect(chain->effects[e]);
chain->effects[e] = NULL;
}
chain->length = 0;
}
/*----------------------------- Effects library ------------------------------*/
static sox_effect_fn_t s_sox_effect_fns[] = {
#define EFFECT(f) lsx_##f##_effect_fn,
#include "effects.h"
#undef EFFECT
NULL
};
const sox_effect_fn_t*
sox_get_effect_fns(void)
{
return s_sox_effect_fns;
}
/* Find a named effect in the effects library */
sox_effect_handler_t const * sox_find_effect(char const * name)
{
int e;
sox_effect_fn_t const * fns = sox_get_effect_fns();
for (e = 0; fns[e]; ++e) {
const sox_effect_handler_t *eh = fns[e] ();
if (eh && eh->name && strcasecmp(eh->name, name) == 0)
return eh; /* Found it. */
}
return NULL;
}
/*----------------------------- Helper functions -----------------------------*/
/* interleave() parameters:
* flows: number of samples per wide sample
* length: number of samples to copy
* [pertaining to the (non-interleaved) source buffer:]
* from: start address
* bufsiz: total size
* offset: position at which to start reading
* [pertaining to the (interleaved) destination buffer:]
* to: start address
*/
static void interleave(size_t flows, size_t length, sox_sample_t *from,
size_t bufsiz, size_t offset, sox_sample_t *to)
{
size_t i;
const size_t wide_samples = length/flows;
const size_t flow_offs = bufsiz/flows;
from += offset/flows;
for (i = 0; i < wide_samples; i++) {
sox_sample_t *inner_from = from + i;
sox_sample_t *inner_to = to + i * flows;
size_t f;
for (f = 0; f < flows; f++) {
*inner_to++ = *inner_from;
inner_from += flow_offs;
}
}
}
/* deinterleave() parameters:
* flows: number of samples per wide sample
* length: number of samples to copy
* [pertaining to the (interleaved) source buffer:]
* from: start address
* [pertaining to the (non-interleaved) destination buffer:]
* to: start address
* bufsiz: total size
* offset: position at which to start writing
*/
static void deinterleave(size_t flows, size_t length, sox_sample_t *from,
sox_sample_t *to, size_t bufsiz, size_t offset)
{
const size_t wide_samples = length/flows;
const size_t flow_offs = bufsiz/flows;
size_t f;
to += offset/flows;
for (f = 0; f < flows; f++) {
sox_sample_t *inner_to = to + f*flow_offs;
sox_sample_t *inner_from = from + f;
size_t i = wide_samples;
while (i--) {
*inner_to++ = *inner_from;
inner_from += flows;
}
}
}

@ -0,0 +1,90 @@
/* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* FIXME: generate this list automatically */
EFFECT(allpass)
EFFECT(band)
EFFECT(bandpass)
EFFECT(bandreject)
EFFECT(bass)
EFFECT(bend)
EFFECT(biquad)
EFFECT(chorus)
EFFECT(channels)
EFFECT(compand)
EFFECT(contrast)
EFFECT(dcshift)
EFFECT(deemph)
EFFECT(delay)
EFFECT(dft_filter) /* abstract */
EFFECT(dither)
EFFECT(divide)
EFFECT(downsample)
EFFECT(earwax)
EFFECT(echo)
EFFECT(echos)
EFFECT(equalizer)
EFFECT(fade)
EFFECT(fir)
EFFECT(firfit)
EFFECT(flanger)
EFFECT(gain)
EFFECT(highpass)
EFFECT(hilbert)
EFFECT(input)
#ifdef HAVE_LADSPA_H
EFFECT(ladspa)
#endif
EFFECT(loudness)
EFFECT(lowpass)
EFFECT(mcompand)
EFFECT(noiseprof)
EFFECT(noisered)
EFFECT(norm)
EFFECT(oops)
EFFECT(output)
EFFECT(overdrive)
EFFECT(pad)
EFFECT(phaser)
EFFECT(pitch)
EFFECT(rate)
EFFECT(remix)
EFFECT(repeat)
EFFECT(reverb)
EFFECT(reverse)
EFFECT(riaa)
EFFECT(silence)
EFFECT(sinc)
#ifdef HAVE_PNG
EFFECT(spectrogram)
#endif
EFFECT(speed)
#ifdef HAVE_SPEEXDSP
EFFECT(speexdsp)
#endif
EFFECT(splice)
EFFECT(stat)
EFFECT(stats)
EFFECT(stretch)
EFFECT(swap)
EFFECT(synth)
EFFECT(tempo)
EFFECT(treble)
EFFECT(tremolo)
EFFECT(trim)
EFFECT(upsample)
EFFECT(vad)
EFFECT(vol)

@ -0,0 +1,483 @@
/* Implements a libSoX internal interface for implementing effects.
* All public functions & data are prefixed with lsx_ .
*
* Copyright (c) 2005-2012 Chris Bagwell and SoX contributors
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define LSX_EFF_ALIAS
#include "sox_i.h"
#include <string.h>
#include <ctype.h>
int lsx_usage(sox_effect_t * effp)
{
if (effp->handler.usage)
lsx_fail("usage: %s", effp->handler.usage);
else
lsx_fail("this effect takes no parameters");
return SOX_EOF;
}
char * lsx_usage_lines(char * * usage, char const * const * lines, size_t n)
{
if (!*usage) {
size_t i, len;
for (len = i = 0; i < n; len += strlen(lines[i++]) + 1);
*usage = lsx_malloc(len); /* FIXME: this memory will never be freed */
strcpy(*usage, lines[0]);
for (i = 1; i < n; ++i) {
strcat(*usage, "\n");
strcat(*usage, lines[i]);
}
}
return *usage;
}
static lsx_enum_item const s_lsx_wave_enum[] = {
LSX_ENUM_ITEM(SOX_WAVE_,SINE)
LSX_ENUM_ITEM(SOX_WAVE_,TRIANGLE)
{0, 0}};
lsx_enum_item const * lsx_get_wave_enum(void)
{
return s_lsx_wave_enum;
}
void lsx_generate_wave_table(
lsx_wave_t wave_type,
sox_data_t data_type,
void *table,
size_t table_size,
double min,
double max,
double phase)
{
uint32_t t;
uint32_t phase_offset = phase / M_PI / 2 * table_size + 0.5;
for (t = 0; t < table_size; t++)
{
uint32_t point = (t + phase_offset) % table_size;
double d;
switch (wave_type)
{
case SOX_WAVE_SINE:
d = (sin((double)point / table_size * 2 * M_PI) + 1) / 2;
break;
case SOX_WAVE_TRIANGLE:
d = (double)point * 2 / table_size;
switch (4 * point / table_size)
{
case 0: d = d + 0.5; break;
case 1: case 2: d = 1.5 - d; break;
case 3: d = d - 1.5; break;
}
break;
default: /* Oops! FIXME */
d = 0.0; /* Make sure we have a value */
break;
}
d = d * (max - min) + min;
switch (data_type)
{
case SOX_FLOAT:
{
float *fp = (float *)table;
*fp++ = (float)d;
table = fp;
continue;
}
case SOX_DOUBLE:
{
double *dp = (double *)table;
*dp++ = d;
table = dp;
continue;
}
default: break;
}
d += d < 0? -0.5 : +0.5;
switch (data_type)
{
case SOX_SHORT:
{
short *sp = table;
*sp++ = (short)d;
table = sp;
continue;
}
case SOX_INT:
{
int *ip = table;
*ip++ = (int)d;
table = ip;
continue;
}
default: break;
}
}
}
/*
* lsx_parsesamples
*
* Parse a string for # of samples. The input consists of one or more
* parts, with '+' or '-' between them indicating if the sample count
* should be added to or subtracted from the previous value.
* If a part ends with a 's' then it is interpreted as a
* user-calculated # of samples.
* If a part contains ':' or '.' but no 'e' or if it ends with a 't'
* then it is treated as an amount of time. This is converted into
* seconds and fraction of seconds, then the sample rate is used to
* calculate # of samples.
* Parameter def specifies which interpretation should be the default
* for a bare number like "123". It can either be 't' or 's'.
* Returns NULL on error, pointer to next char to parse otherwise.
*/
static char const * parsesamples(sox_rate_t rate, const char *str0, uint64_t *samples, int def, int combine);
char const * lsx_parsesamples(sox_rate_t rate, const char *str0, uint64_t *samples, int def)
{
*samples = 0;
return parsesamples(rate, str0, samples, def, '+');
}
static char const * parsesamples(sox_rate_t rate, const char *str0, uint64_t *samples, int def, int combine)
{
char * str = (char *)str0;
do {
uint64_t samples_part;
sox_bool found_samples = sox_false, found_time = sox_false;
char const * end;
char const * pos;
sox_bool found_colon, found_dot, found_e;
for (;*str == ' '; ++str);
for (end = str; *end && strchr("0123456789:.ets", *end); ++end);
if (end == str)
return NULL; /* error: empty input */
pos = strchr(str, ':');
found_colon = pos && pos < end;
pos = strchr(str, '.');
found_dot = pos && pos < end;
pos = strchr(str, 'e');
found_e = pos && pos < end;
if (found_colon || (found_dot && !found_e) || *(end-1) == 't')
found_time = sox_true;
else if (*(end-1) == 's')
found_samples = sox_true;
if (found_time || (def == 't' && !found_samples)) {
int i;
if (found_e)
return NULL; /* error: e notation in time */
for (samples_part = 0, i = 0; *str != '.' && i < 3; ++i) {
char * last_str = str;
long part = strtol(str, &str, 10);
if (!i && str == last_str)
return NULL; /* error: empty first component */
samples_part += rate * part;
if (i < 2) {
if (*str != ':')
break;
++str;
samples_part *= 60;
}
}
if (*str == '.') {
char * last_str = str;
double part = strtod(str, &str);
if (str == last_str)
return NULL; /* error: empty fractional part */
samples_part += rate * part + .5;
}
if (*str == 't')
str++;
} else {
char * last_str = str;
double part = strtod(str, &str);
if (str == last_str)
return NULL; /* error: no sample count */
samples_part = part + .5;
if (*str == 's')
str++;
}
if (str != end)
return NULL; /* error: trailing characters */
switch (combine) {
case '+': *samples += samples_part; break;
case '-': *samples = samples_part <= *samples ?
*samples - samples_part : 0;
break;
}
combine = '\0';
if (*str && strchr("+-", *str))
combine = *str++;
} while (combine);
return str;
}
#if 0
#include <assert.h>
#define TEST(st, samp, len) \
str = st; \
next = lsx_parsesamples(10000, str, &samples, 't'); \
assert(samples == samp && next == str + len);
int main(int argc, char * * argv)
{
char const * str, * next;
uint64_t samples;
TEST("0" , 0, 1)
TEST("1" , 10000, 1)
TEST("0s" , 0, 2)
TEST("0s,", 0, 2)
TEST("0s/", 0, 2)
TEST("0s@", 0, 2)
TEST("0t" , 0, 2)
TEST("0t,", 0, 2)
TEST("0t/", 0, 2)
TEST("0t@", 0, 2)
TEST("1s" , 1, 2)
TEST("1s,", 1, 2)
TEST("1s/", 1, 2)
TEST("1s@", 1, 2)
TEST(" 01s" , 1, 4)
TEST("1e6s" , 1000000, 4)
TEST("1t" , 10000, 2)
TEST("1t,", 10000, 2)
TEST("1t/", 10000, 2)
TEST("1t@", 10000, 2)
TEST("1.1t" , 11000, 4)
TEST("1.1t,", 11000, 4)
TEST("1.1t/", 11000, 4)
TEST("1.1t@", 11000, 4)
assert(!lsx_parsesamples(10000, "1e6t", &samples, 't'));
TEST(".0", 0, 2)
TEST("0.0", 0, 3)
TEST("0:0.0", 0, 5)
TEST("0:0:0.0", 0, 7)
TEST(".1", 1000, 2)
TEST(".10", 1000, 3)
TEST("0.1", 1000, 3)
TEST("1.1", 11000, 3)
TEST("1:1.1", 611000, 5)
TEST("1:1:1.1", 36611000, 7)
TEST("1:1", 610000, 3)
TEST("1:01", 610000, 4)
TEST("1:1:1", 36610000, 5)
TEST("1:", 600000, 2)
TEST("1::", 36000000, 3)
TEST("0.444444", 4444, 8)
TEST("0.555555", 5556, 8)
assert(!lsx_parsesamples(10000, "x", &samples, 't'));
TEST("1:23+37", 1200000, 7)
TEST("12t+12s", 120012, 7)
TEST("1e6s-10", 900000, 7)
TEST("10-2:00", 0, 7)
TEST("123-45+12s+2:00-3e3s@foo", 1977012, 20)
TEST("1\0" "2", 10000, 1)
return 0;
}
#endif
/*
* lsx_parseposition
*
* Parse a string for an audio position. Similar to lsx_parsesamples
* above, but an initial '=', '+' or '-' indicates that the specified time
* is relative to the start of audio, last used position or end of audio,
* respectively. Parameter def states which of these is the default.
* Parameters latest and end are the positions to which '+' and '-' relate;
* end may be SOX_UNKNOWN_LEN, in which case "-0" is the only valid
* end-relative input and will result in a position of SOX_UNKNOWN_LEN.
* Other parameters and return value are the same as for lsx_parsesamples.
*
* A test parse that only checks for valid syntax can be done by
* specifying samples = NULL. If this passes, a later reparse of the same
* input will only fail if it is relative to the end ("-"), not "-0", and
* the end position is unknown.
*/
char const * lsx_parseposition(sox_rate_t rate, const char *str0, uint64_t *samples, uint64_t latest, uint64_t end, int def)
{
char *str = (char *)str0;
char anchor, combine;
if (!strchr("+-=", def))
return NULL; /* error: invalid default anchor */
anchor = def;
if (*str && strchr("+-=", *str))
anchor = *str++;
combine = '+';
if (strchr("+-", anchor)) {
combine = anchor;
if (*str && strchr("+-", *str))
combine = *str++;
}
if (!samples) {
/* dummy parse, syntax checking only */
uint64_t dummy = 0;
return parsesamples(0., str, &dummy, 't', '+');
}
switch (anchor) {
case '=': *samples = 0; break;
case '+': *samples = latest; break;
case '-': *samples = end; break;
}
if (anchor == '-' && end == SOX_UNKNOWN_LEN) {
/* "-0" only valid input here */
char const *l;
for (l = str; *l && strchr("0123456789:.ets+-", *l); ++l);
if (l == str+1 && *str == '0') {
/* *samples already set to SOX_UNKNOWN_LEN */
return l;
}
return NULL; /* error: end-relative position, but end unknown */
}
return parsesamples(rate, str, samples, 't', combine);
}
/* a note is given as an int,
* 0 => 440 Hz = A
* >0 => number of half notes 'up',
* <0 => number of half notes down,
* example 12 => A of next octave, 880Hz
*
* calculated by freq = 440Hz * 2**(note/12)
*/
static double calc_note_freq(double note, int key)
{
if (key != INT_MAX) { /* Just intonation. */
static const int n[] = {16, 9, 6, 5, 4, 7}; /* Numerator. */
static const int d[] = {15, 8, 5, 4, 3, 5}; /* Denominator. */
static double j[13]; /* Just semitones */
int i, m = floor(note);
if (!j[1]) for (i = 1; i <= 12; ++i)
j[i] = i <= 6? log((double)n[i - 1] / d[i - 1]) / log(2.) : 1 - j[12 - i];
note -= m;
m -= key = m - ((INT_MAX / 2 - ((INT_MAX / 2) % 12) + m - key) % 12);
return 440 * pow(2., key / 12. + j[m] + (j[m + 1] - j[m]) * note);
}
return 440 * pow(2., note / 12);
}
int lsx_parse_note(char const * text, char * * end_ptr)
{
int result = INT_MAX;
if (*text >= 'A' && *text <= 'G') {
result = (int)(5/3. * (*text++ - 'A') + 9.5) % 12 - 9;
if (*text == 'b') {--result; ++text;}
else if (*text == '#') {++result; ++text;}
if (isdigit((unsigned char)*text))
result += 12 * (*text++ - '4');
}
*end_ptr = (char *)text;
return result;
}
/* Read string 'text' and convert to frequency.
* 'text' can be a positive number which is the frequency in Hz.
* If 'text' starts with a '%' and a following number the corresponding
* note is calculated.
* Return -1 on error.
*/
double lsx_parse_frequency_k(char const * text, char * * end_ptr, int key)
{
double result;
if (*text == '%') {
result = strtod(text + 1, end_ptr);
if (*end_ptr == text + 1)
return -1;
return calc_note_freq(result, key);
}
if (*text >= 'A' && *text <= 'G') {
int result2 = lsx_parse_note(text, end_ptr);
return result2 == INT_MAX? - 1 : calc_note_freq((double)result2, key);
}
result = strtod(text, end_ptr);
if (end_ptr) {
if (*end_ptr == text)
return -1;
if (**end_ptr == 'k') {
result *= 1000;
++*end_ptr;
}
}
return result < 0 ? -1 : result;
}
FILE * lsx_open_input_file(sox_effect_t * effp, char const * filename, sox_bool text_mode)
{
FILE * file;
if (!filename || !strcmp(filename, "-")) {
if (effp->global_info->global_info->stdin_in_use_by) {
lsx_fail("stdin already in use by `%s'", effp->global_info->global_info->stdin_in_use_by);
return NULL;
}
effp->global_info->global_info->stdin_in_use_by = effp->handler.name;
file = stdin;
}
else if (!(file = fopen(filename, text_mode ? "r" : "rb"))) {
lsx_fail("couldn't open file %s: %s", filename, strerror(errno));
return NULL;
}
return file;
}
int lsx_effects_init(void)
{
init_fft_cache();
return SOX_SUCCESS;
}
int lsx_effects_quit(void)
{
clear_fft_cache();
return SOX_SUCCESS;
}

@ -0,0 +1,645 @@
/* libSoX internal DSP functions.
* All public functions & data are prefixed with lsx_ .
*
* Copyright (c) 2008,2012 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef NDEBUG /* Enable assert always. */
#undef NDEBUG /* Must undef above assert.h or other that might include it. */
#endif
#include "sox_i.h"
#include <assert.h>
#include <string.h>
/* Concurrent Control with "Readers" and "Writers", P.J. Courtois et al, 1971:*/
#if defined HAVE_OPENMP
typedef struct {
int readcount, writecount; /* initial value = 0 */
omp_lock_t mutex_1, mutex_2, mutex_3, w, r; /* initial value = 1 */
} ccrw2_t; /* Problem #2: `writers-preference' */
#define ccrw2_become_reader(p) do {\
omp_set_lock(&p.mutex_3);\
omp_set_lock(&p.r);\
omp_set_lock(&p.mutex_1);\
if (++p.readcount == 1) omp_set_lock(&p.w);\
omp_unset_lock(&p.mutex_1);\
omp_unset_lock(&p.r);\
omp_unset_lock(&p.mutex_3);\
} while (0)
#define ccrw2_cease_reading(p) do {\
omp_set_lock(&p.mutex_1);\
if (!--p.readcount) omp_unset_lock(&p.w);\
omp_unset_lock(&p.mutex_1);\
} while (0)
#define ccrw2_become_writer(p) do {\
omp_set_lock(&p.mutex_2);\
if (++p.writecount == 1) omp_set_lock(&p.r);\
omp_unset_lock(&p.mutex_2);\
omp_set_lock(&p.w);\
} while (0)
#define ccrw2_cease_writing(p) do {\
omp_unset_lock(&p.w);\
omp_set_lock(&p.mutex_2);\
if (!--p.writecount) omp_unset_lock(&p.r);\
omp_unset_lock(&p.mutex_2);\
} while (0)
#define ccrw2_init(p) do {\
omp_init_lock(&p.mutex_1);\
omp_init_lock(&p.mutex_2);\
omp_init_lock(&p.mutex_3);\
omp_init_lock(&p.w);\
omp_init_lock(&p.r);\
} while (0)
#define ccrw2_clear(p) do {\
omp_destroy_lock(&p.r);\
omp_destroy_lock(&p.w);\
omp_destroy_lock(&p.mutex_3);\
omp_destroy_lock(&p.mutex_2);\
omp_destroy_lock(&p.mutex_1);\
} while (0)
#else
#define ccrw2_become_reader(x) (void)0
#define ccrw2_cease_reading(x) (void)0
#define ccrw2_become_writer(x) (void)0
#define ccrw2_cease_writing(x) (void)0
#define ccrw2_init(x) (void)0
#define ccrw2_clear(x) (void)0
#endif /* HAVE_OPENMP */
/* Numerical Recipes cubic spline: */
void lsx_prepare_spline3(double const * x, double const * y, int n,
double start_1d, double end_1d, double * y_2d)
{
double p, qn, sig, un, * u = lsx_malloc((n - 1) * sizeof(*u));
int i;
if (start_1d == HUGE_VAL)
y_2d[0] = u[0] = 0; /* Start with natural spline or */
else { /* set the start first derivative */
y_2d[0] = -.5;
u[0] = (3 / (x[1] - x[0])) * ((y[1] - y[0]) / (x[1] - x[0]) - start_1d);
}
for (i = 1; i < n - 1; ++i) {
sig = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]);
p = sig * y_2d[i - 1] + 2;
y_2d[i] = (sig - 1) / p;
u[i] = (y[i + 1] - y[i]) / (x[i + 1] - x[i]) -
(y[i] - y[i - 1]) / (x[i] - x[i - 1]);
u[i] = (6 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p;
}
if (end_1d == HUGE_VAL)
qn = un = 0; /* End with natural spline or */
else { /* set the end first derivative */
qn = .5;
un = 3 / (x[n - 1] - x[n - 2]) * (end_1d - (y[n - 1] - y[n - 2]) / (x[n - 1] - x[n - 2]));
}
y_2d[n - 1] = (un - qn * u[n - 2]) / (qn * y_2d[n - 2] + 1);
for (i = n - 2; i >= 0; --i)
y_2d[i] = y_2d[i] * y_2d[i + 1] + u[i];
free(u);
}
double lsx_spline3(double const * x, double const * y, double const * y_2d,
int n, double x1)
{
int t, i[2] = {0, 0};
double d, a, b;
for (i[1] = n - 1; i[1] - i[0] > 1; t = (i[1] + i[0]) >> 1, i[x[t] > x1] = t);
d = x[i[1]] - x[i[0]];
assert(d != 0);
a = (x[i[1]] - x1) / d;
b = (x1 - x[i[0]]) / d;
return a * y[i[0]] + b * y[i[1]] +
((a * a * a - a) * y_2d[i[0]] + (b * b * b - b) * y_2d[i[1]]) * d * d / 6;
}
double lsx_bessel_I_0(double x)
{
double term = 1, sum = 1, last_sum, x2 = x / 2;
int i = 1;
do {
double y = x2 / i++;
last_sum = sum, sum += term *= y * y;
} while (sum != last_sum);
return sum;
}
int lsx_set_dft_length(int num_taps) /* Set to 4 x nearest power of 2 */
{ /* or half of that if danger of causing too many cache misses. */
int min = sox_globals.log2_dft_min_size;
double d = log((double)num_taps) / log(2.);
return 1 << range_limit((int)(d + 2.77), min, max((int)(d + 1.77), 17));
}
#include "fft4g.h"
static int * lsx_fft_br;
static double * lsx_fft_sc;
static int fft_len = -1;
#if defined HAVE_OPENMP
static ccrw2_t fft_cache_ccrw;
#endif
void init_fft_cache(void)
{
assert(lsx_fft_br == NULL);
assert(lsx_fft_sc == NULL);
assert(fft_len == -1);
ccrw2_init(fft_cache_ccrw);
fft_len = 0;
}
void clear_fft_cache(void)
{
assert(fft_len >= 0);
ccrw2_clear(fft_cache_ccrw);
free(lsx_fft_br);
free(lsx_fft_sc);
lsx_fft_sc = NULL;
lsx_fft_br = NULL;
fft_len = -1;
}
static sox_bool update_fft_cache(int len)
{
assert(lsx_is_power_of_2(len));
assert(fft_len >= 0);
ccrw2_become_reader(fft_cache_ccrw);
if (len > fft_len) {
ccrw2_cease_reading(fft_cache_ccrw);
ccrw2_become_writer(fft_cache_ccrw);
if (len > fft_len) {
int old_n = fft_len;
fft_len = len;
lsx_fft_br = lsx_realloc(lsx_fft_br, dft_br_len(fft_len) * sizeof(*lsx_fft_br));
lsx_fft_sc = lsx_realloc(lsx_fft_sc, dft_sc_len(fft_len) * sizeof(*lsx_fft_sc));
if (!old_n)
lsx_fft_br[0] = 0;
return sox_true;
}
ccrw2_cease_writing(fft_cache_ccrw);
ccrw2_become_reader(fft_cache_ccrw);
}
return sox_false;
}
static void done_with_fft_cache(sox_bool is_writer)
{
if (is_writer)
ccrw2_cease_writing(fft_cache_ccrw);
else ccrw2_cease_reading(fft_cache_ccrw);
}
void lsx_safe_rdft(int len, int type, double * d)
{
sox_bool is_writer = update_fft_cache(len);
lsx_rdft(len, type, d, lsx_fft_br, lsx_fft_sc);
done_with_fft_cache(is_writer);
}
void lsx_safe_cdft(int len, int type, double * d)
{
sox_bool is_writer = update_fft_cache(len);
lsx_cdft(len, type, d, lsx_fft_br, lsx_fft_sc);
done_with_fft_cache(is_writer);
}
void lsx_power_spectrum(int n, double const * in, double * out)
{
int i;
double * work = lsx_memdup(in, n * sizeof(*work));
lsx_safe_rdft(n, 1, work);
out[0] = sqr(work[0]);
for (i = 2; i < n; i += 2)
out[i >> 1] = sqr(work[i]) + sqr(work[i + 1]);
out[i >> 1] = sqr(work[1]);
free(work);
}
void lsx_power_spectrum_f(int n, float const * in, float * out)
{
int i;
double * work = lsx_malloc(n * sizeof(*work));
for (i = 0; i< n; ++i) work[i] = in[i];
lsx_safe_rdft(n, 1, work);
out[0] = sqr(work[0]);
for (i = 2; i < n; i += 2)
out[i >> 1] = sqr(work[i]) + sqr(work[i + 1]);
out[i >> 1] = sqr(work[1]);
free(work);
}
void lsx_apply_hann_f(float h[], const int num_points)
{
int i, m = num_points - 1;
for (i = 0; i < num_points; ++i) {
double x = 2 * M_PI * i / m;
h[i] *= .5 - .5 * cos(x);
}
}
void lsx_apply_hann(double h[], const int num_points)
{
int i, m = num_points - 1;
for (i = 0; i < num_points; ++i) {
double x = 2 * M_PI * i / m;
h[i] *= .5 - .5 * cos(x);
}
}
void lsx_apply_hamming(double h[], const int num_points)
{
int i, m = num_points - 1;
for (i = 0; i < num_points; ++i) {
double x = 2 * M_PI * i / m;
h[i] *= .53836 - .46164 * cos(x);
}
}
void lsx_apply_bartlett(double h[], const int num_points)
{
int i, m = num_points - 1;
for (i = 0; i < num_points; ++i) {
h[i] *= 2. / m * (m / 2. - fabs(i - m / 2.));
}
}
void lsx_apply_blackman(double h[], const int num_points, double alpha /*.16*/)
{
int i, m = num_points - 1;
for (i = 0; i < num_points; ++i) {
double x = 2 * M_PI * i / m;
h[i] *= (1 - alpha) *.5 - .5 * cos(x) + alpha * .5 * cos(2 * x);
}
}
void lsx_apply_blackman_nutall(double h[], const int num_points)
{
int i, m = num_points - 1;
for (i = 0; i < num_points; ++i) {
double x = 2 * M_PI * i / m;
h[i] *= .3635819 - .4891775 * cos(x) + .1365995 * cos(2 * x) - .0106411 * cos(3 * x);
}
}
double lsx_kaiser_beta(double att, double tr_bw)
{
if (att >= 60) {
static const double coefs[][4] = {
{-6.784957e-10,1.02856e-05,0.1087556,-0.8988365+.001},
{-6.897885e-10,1.027433e-05,0.10876,-0.8994658+.002},
{-1.000683e-09,1.030092e-05,0.1087677,-0.9007898+.003},
{-3.654474e-10,1.040631e-05,0.1087085,-0.8977766+.006},
{8.106988e-09,6.983091e-06,0.1091387,-0.9172048+.015},
{9.519571e-09,7.272678e-06,0.1090068,-0.9140768+.025},
{-5.626821e-09,1.342186e-05,0.1083999,-0.9065452+.05},
{-9.965946e-08,5.073548e-05,0.1040967,-0.7672778+.085},
{1.604808e-07,-5.856462e-05,0.1185998,-1.34824+.1},
{-1.511964e-07,6.363034e-05,0.1064627,-0.9876665+.18},
};
double realm = log(tr_bw/.0005)/log(2.);
double const * c0 = coefs[range_limit( (int)realm, 0, (int)array_length(coefs)-1)];
double const * c1 = coefs[range_limit(1+(int)realm, 0, (int)array_length(coefs)-1)];
double b0 = ((c0[0]*att + c0[1])*att + c0[2])*att + c0[3];
double b1 = ((c1[0]*att + c1[1])*att + c1[2])*att + c1[3];
return b0 + (b1 - b0) * (realm - (int)realm);
}
if (att > 50 ) return .1102 * (att - 8.7);
if (att > 20.96) return .58417 * pow(att -20.96, .4) + .07886 * (att - 20.96);
return 0;
}
void lsx_apply_kaiser(double h[], const int num_points, double beta)
{
int i, m = num_points - 1;
for (i = 0; i <= m; ++i) {
double x = 2. * i / m - 1;
h[i] *= lsx_bessel_I_0(beta * sqrt(1 - x * x)) / lsx_bessel_I_0(beta);
}
}
void lsx_apply_dolph(double h[], const int N, double att)
{
double b = cosh(acosh(pow(10., att/20)) / (N-1)), sum, t, c, norm = 0;
int i, j;
for (c = 1 - 1 / (b*b), i = (N-1) / 2; i >= 0; --i) {
for (sum = !i, b = t = j = 1; j <= i && sum != t; b *= (i-j) * (1./j), ++j)
t = sum, sum += (b *= c * (N - i - j) * (1./j));
sum /= (N - 1 - i), sum /= (norm = norm? norm : sum);
h[i] *= sum, h[N - 1 - i] *= sum;
}
}
double * lsx_make_lpf(int num_taps, double Fc, double beta, double rho,
double scale, sox_bool dc_norm)
{
int i, m = num_taps - 1;
double * h = calloc(num_taps, sizeof(*h)), sum = 0;
double mult = scale / lsx_bessel_I_0(beta), mult1 = 1 / (.5 * m + rho);
assert(Fc >= 0 && Fc <= 1);
lsx_debug("make_lpf(n=%i Fc=%.7g β=%g ρ=%g dc-norm=%i scale=%g)", num_taps, Fc, beta, rho, dc_norm, scale);
if (!h)
return NULL;
for (i = 0; i <= m / 2; ++i) {
double z = i - .5 * m, x = z * M_PI, y = z * mult1;
h[i] = x? sin(Fc * x) / x : Fc;
sum += h[i] *= lsx_bessel_I_0(beta * sqrt(1 - y * y)) * mult;
if (m - i != i)
sum += h[m - i] = h[i];
}
for (i = 0; dc_norm && i < num_taps; ++i) h[i] *= scale / sum;
return h;
}
void lsx_kaiser_params(double att, double Fc, double tr_bw, double * beta, int * num_taps)
{
*beta = *beta < 0? lsx_kaiser_beta(att, tr_bw * .5 / Fc): *beta;
att = att < 60? (att - 7.95) / (2.285 * M_PI * 2) :
((.0007528358-1.577737e-05**beta)**beta+.6248022)**beta+.06186902;
*num_taps = !*num_taps? ceil(att/tr_bw + 1) : *num_taps;
}
double * lsx_design_lpf(
double Fp, /* End of pass-band */
double Fs, /* Start of stop-band */
double Fn, /* Nyquist freq; e.g. 0.5, 1, PI */
double att, /* Stop-band attenuation in dB */
int * num_taps, /* 0: value will be estimated */
int k, /* >0: number of phases; <0: num_taps ≡ 1 (mod -k) */
double beta) /* <0: value will be estimated */
{
int n = *num_taps, phases = max(k, 1), modulo = max(-k, 1);
double tr_bw, Fc, rho = phases == 1? .5 : att < 120? .63 : .75;
Fp /= fabs(Fn), Fs /= fabs(Fn); /* Normalise to Fn = 1 */
tr_bw = .5 * (Fs - Fp); /* Transition band-width: 6dB to stop points */
tr_bw /= phases, Fs /= phases;
tr_bw = min(tr_bw, .5 * Fs);
Fc = Fs - tr_bw;
assert(Fc - tr_bw >= 0);
lsx_kaiser_params(att, Fc, tr_bw, &beta, num_taps);
if (!n)
*num_taps = phases > 1? *num_taps / phases * phases + phases - 1 : (*num_taps + modulo - 2) / modulo * modulo + 1;
return Fn < 0? 0 : lsx_make_lpf(
*num_taps, Fc, beta, rho, (double)phases, sox_false);
}
static double safe_log(double x)
{
assert(x >= 0);
if (x)
return log(x);
lsx_debug("log(0)");
return -26;
}
void lsx_fir_to_phase(double * * h, int * len, int * post_len, double phase)
{
double * pi_wraps, * work, phase1 = (phase > 50 ? 100 - phase : phase) / 50;
int i, work_len, begin, end, imp_peak = 0, peak = 0;
double imp_sum = 0, peak_imp_sum = 0;
double prev_angle2 = 0, cum_2pi = 0, prev_angle1 = 0, cum_1pi = 0;
for (i = *len, work_len = 2 * 2 * 8; i > 1; work_len <<= 1, i >>= 1);
work = lsx_calloc((size_t)work_len + 2, sizeof(*work)); /* +2: (UN)PACK */
pi_wraps = lsx_malloc((((size_t)work_len + 2) / 2) * sizeof(*pi_wraps));
memcpy(work, *h, *len * sizeof(*work));
lsx_safe_rdft(work_len, 1, work); /* Cepstral: */
LSX_UNPACK(work, work_len);
for (i = 0; i <= work_len; i += 2) {
double angle = atan2(work[i + 1], work[i]);
double detect = 2 * M_PI;
double delta = angle - prev_angle2;
double adjust = detect * ((delta < -detect * .7) - (delta > detect * .7));
prev_angle2 = angle;
cum_2pi += adjust;
angle += cum_2pi;
detect = M_PI;
delta = angle - prev_angle1;
adjust = detect * ((delta < -detect * .7) - (delta > detect * .7));
prev_angle1 = angle;
cum_1pi += fabs(adjust); /* fabs for when 2pi and 1pi have combined */
pi_wraps[i >> 1] = cum_1pi;
work[i] = safe_log(sqrt(sqr(work[i]) + sqr(work[i + 1])));
work[i + 1] = 0;
}
LSX_PACK(work, work_len);
lsx_safe_rdft(work_len, -1, work);
for (i = 0; i < work_len; ++i) work[i] *= 2. / work_len;
for (i = 1; i < work_len / 2; ++i) { /* Window to reject acausal components */
work[i] *= 2;
work[i + work_len / 2] = 0;
}
lsx_safe_rdft(work_len, 1, work);
for (i = 2; i < work_len; i += 2) /* Interpolate between linear & min phase */
work[i + 1] = phase1 * i / work_len * pi_wraps[work_len >> 1] +
(1 - phase1) * (work[i + 1] + pi_wraps[i >> 1]) - pi_wraps[i >> 1];
work[0] = exp(work[0]), work[1] = exp(work[1]);
for (i = 2; i < work_len; i += 2) {
double x = exp(work[i]);
work[i ] = x * cos(work[i + 1]);
work[i + 1] = x * sin(work[i + 1]);
}
lsx_safe_rdft(work_len, -1, work);
for (i = 0; i < work_len; ++i) work[i] *= 2. / work_len;
/* Find peak pos. */
for (i = 0; i <= (int)(pi_wraps[work_len >> 1] / M_PI + .5); ++i) {
imp_sum += work[i];
if (fabs(imp_sum) > fabs(peak_imp_sum)) {
peak_imp_sum = imp_sum;
peak = i;
}
if (work[i] > work[imp_peak]) /* For debug check only */
imp_peak = i;
}
while (peak && fabs(work[peak-1]) > fabs(work[peak]) && work[peak-1] * work[peak] > 0)
--peak;
if (!phase1)
begin = 0;
else if (phase1 == 1)
begin = peak - *len / 2;
else {
begin = (.997 - (2 - phase1) * .22) * *len + .5;
end = (.997 + (0 - phase1) * .22) * *len + .5;
begin = peak - (begin & ~3);
end = peak + 1 + ((end + 3) & ~3);
*len = end - begin;
*h = lsx_realloc(*h, *len * sizeof(**h));
}
for (i = 0; i < *len; ++i) (*h)[i] =
work[(begin + (phase > 50 ? *len - 1 - i : i) + work_len) & (work_len - 1)];
*post_len = phase > 50 ? peak - begin : begin + *len - (peak + 1);
lsx_debug("nPI=%g peak-sum@%i=%g (val@%i=%g); len=%i post=%i (%g%%)",
pi_wraps[work_len >> 1] / M_PI, peak, peak_imp_sum, imp_peak,
work[imp_peak], *len, *post_len, 100 - 100. * *post_len / (*len - 1));
free(pi_wraps), free(work);
}
void lsx_plot_fir(double * h, int num_points, sox_rate_t rate, sox_plot_t type, char const * title, double y1, double y2)
{
int i, N = lsx_set_dft_length(num_points);
if (type == sox_plot_gnuplot) {
double * h1 = lsx_calloc(N, sizeof(*h1));
double * H = lsx_malloc((N / 2 + 1) * sizeof(*H));
memcpy(h1, h, sizeof(*h1) * num_points);
lsx_power_spectrum(N, h1, H);
printf(
"# gnuplot file\n"
"set title '%s'\n"
"set xlabel 'Frequency (Hz)'\n"
"set ylabel 'Amplitude Response (dB)'\n"
"set grid xtics ytics\n"
"set key off\n"
"plot '-' with lines\n"
, title);
for (i = 0; i <= N/2; ++i)
printf("%g %g\n", i * rate / N, 10 * log10(H[i]));
printf(
"e\n"
"pause -1 'Hit return to continue'\n");
free(H);
free(h1);
}
else if (type == sox_plot_octave) {
printf("%% GNU Octave file (may also work with MATLAB(R) )\nb=[");
for (i = 0; i < num_points; ++i)
printf("%24.16e\n", h[i]);
printf("];\n"
"[h,w]=freqz(b,1,%i);\n"
"plot(%g*w/pi,20*log10(h))\n"
"title('%s')\n"
"xlabel('Frequency (Hz)')\n"
"ylabel('Amplitude Response (dB)')\n"
"grid on\n"
"axis([0 %g %g %g])\n"
"disp('Hit return to continue')\n"
"pause\n"
, N, rate * .5, title, rate * .5, y1, y2);
}
else if (type == sox_plot_data) {
printf("# %s\n"
"# FIR filter\n"
"# rate: %g\n"
"# name: b\n"
"# type: matrix\n"
"# rows: %i\n"
"# columns: 1\n", title, rate, num_points);
for (i = 0; i < num_points; ++i)
printf("%24.16e\n", h[i]);
}
}
#if HAVE_FENV_H
#include <fenv.h>
#if defined FE_INVALID
#if HAVE_LRINT && LONG_MAX == 2147483647
#define lrint32 lrint
#elif defined __GNUC__ && defined __x86_64__
#define lrint32 lrint32
static __inline sox_int32_t lrint32(double input) {
sox_int32_t result;
__asm__ __volatile__("fistpl %0": "=m"(result): "t"(input): "st");
return result;
}
#endif
#endif
#endif
#if defined lrint32
#define _ dest[i] = lrint32(src[i]), ++i,
#pragma STDC FENV_ACCESS ON
static void rint_clip(sox_sample_t * const dest, double const * const src,
size_t i, size_t const n, sox_uint64_t * const clips)
{
for (; i < n; ++i) {
dest[i] = lrint32(src[i]);
if (fetestexcept(FE_INVALID)) {
feclearexcept(FE_INVALID);
dest[i] = src[i] > 0? SOX_SAMPLE_MAX : SOX_SAMPLE_MIN;
++*clips;
}
}
}
void lsx_save_samples(sox_sample_t * const dest, double const * const src,
size_t const n, sox_uint64_t * const clips)
{
size_t i;
feclearexcept(FE_INVALID);
for (i = 0; i < (n & ~7);) {
_ _ _ _ _ _ _ _ 0;
if (fetestexcept(FE_INVALID)) {
feclearexcept(FE_INVALID);
rint_clip(dest, src, i - 8, i, clips);
}
}
rint_clip(dest, src, i, n, clips);
}
void lsx_load_samples(double * const dest, sox_sample_t const * const src,
size_t const n)
{
size_t i;
for (i = 0; i < n; ++i)
dest[i] = src[i];
}
#pragma STDC FENV_ACCESS OFF
#undef _
#else
void lsx_save_samples(sox_sample_t * const dest, double const * const src,
size_t const n, sox_uint64_t * const clips)
{
SOX_SAMPLE_LOCALS;
size_t i;
for (i = 0; i < n; ++i)
dest[i] = SOX_FLOAT_64BIT_TO_SAMPLE(src[i], *clips);
}
void lsx_load_samples(double * const dest, sox_sample_t const * const src,
size_t const n)
{
size_t i;
for (i = 0; i < n; ++i)
dest[i] = SOX_SAMPLE_TO_FLOAT_64BIT(src[i],);
}
#endif

@ -0,0 +1,97 @@
/* Simple example of using SoX libraries
*
* Copyright (c) 2007-8 robs@users.sourceforge.net
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program 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 General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifdef NDEBUG /* N.B. assert used with active statements so enable always. */
#undef NDEBUG /* Must undef above assert.h or other that might include it. */
#endif
#include "sox.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
/*
* Reads input file, applies vol & flanger effects, stores in output file.
* E.g. example1 monkey.au monkey.aiff
*/
int main(int argc, char * argv[])
{
static sox_format_t * in, * out; /* input and output files */
sox_effects_chain_t * chain;
sox_effect_t * e;
char * args[10];
assert(argc == 3);
/* All libSoX applications must start by initialising the SoX library */
assert(sox_init() == SOX_SUCCESS);
/* Open the input file (with default parameters) */
assert((in = sox_open_read(argv[1], NULL, NULL, NULL)));
/* Open the output file; we must specify the output signal characteristics.
* Since we are using only simple effects, they are the same as the input
* file characteristics */
assert((out = sox_open_write(argv[2], &in->signal, NULL, NULL, NULL, NULL)));
/* Create an effects chain; some effects need to know about the input
* or output file encoding so we provide that information here */
chain = sox_create_effects_chain(&in->encoding, &out->encoding);
/* The first effect in the effect chain must be something that can source
* samples; in this case, we use the built-in handler that inputs
* data from an audio file */
e = sox_create_effect(sox_find_effect("input"));
args[0] = (char *)in, assert(sox_effect_options(e, 1, args) == SOX_SUCCESS);
/* This becomes the first `effect' in the chain */
assert(sox_add_effect(chain, e, &in->signal, &in->signal) == SOX_SUCCESS);
free(e);
/* Create the `vol' effect, and initialise it with the desired parameters: */
e = sox_create_effect(sox_find_effect("vol"));
args[0] = "3dB", assert(sox_effect_options(e, 1, args) == SOX_SUCCESS);
/* Add the effect to the end of the effects processing chain: */
assert(sox_add_effect(chain, e, &in->signal, &in->signal) == SOX_SUCCESS);
free(e);
/* Create the `flanger' effect, and initialise it with default parameters: */
e = sox_create_effect(sox_find_effect("flanger"));
assert(sox_effect_options(e, 0, NULL) == SOX_SUCCESS);
/* Add the effect to the end of the effects processing chain: */
assert(sox_add_effect(chain, e, &in->signal, &in->signal) == SOX_SUCCESS);
free(e);
/* The last effect in the effect chain must be something that only consumes
* samples; in this case, we use the built-in handler that outputs
* data to an audio file */
e = sox_create_effect(sox_find_effect("output"));
args[0] = (char *)out, assert(sox_effect_options(e, 1, args) == SOX_SUCCESS);
assert(sox_add_effect(chain, e, &in->signal, &in->signal) == SOX_SUCCESS);
free(e);
/* Flow samples through the effects processing chain until EOF is reached */
sox_flow_effects(chain, NULL, NULL);
/* All done; tidy up: */
sox_delete_effects_chain(chain);
sox_close(out);
sox_close(in);
sox_quit();
return 0;
}

@ -0,0 +1,167 @@
/* Simple example of using SoX libraries
*
* Copyright (c) 2007-8 robs@users.sourceforge.net
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program 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 General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifdef NDEBUG /* N.B. assert used with active statements so enable always. */
#undef NDEBUG /* Must undef above assert.h or other that might include it. */
#endif
#include "sox.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
static sox_format_t * in, * out; /* input and output files */
/* The function that will be called to input samples into the effects chain.
* In this example, we get samples to process from a SoX-openned audio file.
* In a different application, they might be generated or come from a different
* part of the application. */
static int input_drain(
sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp)
{
(void)effp; /* This parameter is not needed in this example */
/* ensure that *osamp is a multiple of the number of channels. */
*osamp -= *osamp % effp->out_signal.channels;
/* Read up to *osamp samples into obuf; store the actual number read
* back to *osamp */
*osamp = sox_read(in, obuf, *osamp);
/* sox_read may return a number that is less than was requested; only if
* 0 samples is returned does it indicate that end-of-file has been reached
* or an error has occurred */
if (!*osamp && in->sox_errno)
fprintf(stderr, "%s: %s\n", in->filename, in->sox_errstr);
return *osamp? SOX_SUCCESS : SOX_EOF;
}
/* The function that will be called to output samples from the effects chain.
* In this example, we store the samples in a SoX-opened audio file.
* In a different application, they might perhaps be analysed in some way,
* or displayed as a wave-form */
static int output_flow(sox_effect_t *effp LSX_UNUSED, sox_sample_t const * ibuf,
sox_sample_t * obuf LSX_UNUSED, size_t * isamp, size_t * osamp)
{
/* Write out *isamp samples */
size_t len = sox_write(out, ibuf, *isamp);
/* len is the number of samples that were actually written out; if this is
* different to *isamp, then something has gone wrong--most often, it's
* out of disc space */
if (len != *isamp) {
fprintf(stderr, "%s: %s\n", out->filename, out->sox_errstr);
return SOX_EOF;
}
/* Outputting is the last `effect' in the effect chain so always passes
* 0 samples on to the next effect (as there isn't one!) */
*osamp = 0;
(void)effp; /* This parameter is not needed in this example */
return SOX_SUCCESS; /* All samples output successfully */
}
/* A `stub' effect handler to handle inputting samples to the effects
* chain; the only function needed for this example is `drain' */
static sox_effect_handler_t const * input_handler(void)
{
static sox_effect_handler_t handler = {
"input", NULL, SOX_EFF_MCHAN, NULL, NULL, NULL, input_drain, NULL, NULL, 0
};
return &handler;
}
/* A `stub' effect handler to handle outputting samples from the effects
* chain; the only function needed for this example is `flow' */
static sox_effect_handler_t const * output_handler(void)
{
static sox_effect_handler_t handler = {
"output", NULL, SOX_EFF_MCHAN, NULL, NULL, output_flow, NULL, NULL, NULL, 0
};
return &handler;
}
/*
* Reads input file, applies vol & flanger effects, stores in output file.
* E.g. example1 monkey.au monkey.aiff
*/
int main(int argc, char * argv[])
{
sox_effects_chain_t * chain;
sox_effect_t * e;
char * vol[] = {"3dB"};
assert(argc == 3);
/* All libSoX applications must start by initialising the SoX library */
assert(sox_init() == SOX_SUCCESS);
/* Open the input file (with default parameters) */
assert((in = sox_open_read(argv[1], NULL, NULL, NULL)));
/* Open the output file; we must specify the output signal characteristics.
* Since we are using only simple effects, they are the same as the input
* file characteristics */
assert((out = sox_open_write(argv[2], &in->signal, NULL, NULL, NULL, NULL)));
/* Create an effects chain; some effects need to know about the input
* or output file encoding so we provide that information here */
chain = sox_create_effects_chain(&in->encoding, &out->encoding);
/* The first effect in the effect chain must be something that can source
* samples; in this case, we have defined an input handler that inputs
* data from an audio file */
e = sox_create_effect(input_handler());
/* This becomes the first `effect' in the chain */
assert(sox_add_effect(chain, e, &in->signal, &in->signal) == SOX_SUCCESS);
free(e);
/* Create the `vol' effect, and initialise it with the desired parameters: */
e = sox_create_effect(sox_find_effect("vol"));
assert(sox_effect_options(e, 1, vol) == SOX_SUCCESS);
/* Add the effect to the end of the effects processing chain: */
assert(sox_add_effect(chain, e, &in->signal, &in->signal) == SOX_SUCCESS);
free(e);
/* Create the `flanger' effect, and initialise it with default parameters: */
e = sox_create_effect(sox_find_effect("flanger"));
assert(sox_effect_options(e, 0, NULL) == SOX_SUCCESS);
/* Add the effect to the end of the effects processing chain: */
assert(sox_add_effect(chain, e, &in->signal, &in->signal) == SOX_SUCCESS);
free(e);
/* The last effect in the effect chain must be something that only consumes
* samples; in this case, we have defined an output handler that outputs
* data to an audio file */
e = sox_create_effect(output_handler());
assert(sox_add_effect(chain, e, &in->signal, &in->signal) == SOX_SUCCESS);
free(e);
/* Flow samples through the effects processing chain until EOF is reached */
sox_flow_effects(chain, NULL, NULL);
/* All done; tidy up: */
sox_delete_effects_chain(chain);
sox_close(out);
sox_close(in);
sox_quit();
return 0;
}

@ -0,0 +1,118 @@
/* Simple example of using SoX libraries
*
* Copyright (c) 2008 robs@users.sourceforge.net
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program 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 General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifdef NDEBUG /* N.B. assert used with active statements so enable always. */
#undef NDEBUG /* Must undef above assert.h or other that might include it. */
#endif
#include "sox.h"
#include "util.h"
#include <stdio.h>
#include <math.h>
#include <assert.h>
/*
* Reads input file and displays a few seconds of wave-form, starting from
* a given time through the audio. E.g. example2 song2.au 30.75 1
*/
int main(int argc, char * argv[])
{
sox_format_t * in;
sox_sample_t * buf;
size_t blocks, block_size;
/* Period of audio over which we will measure its volume in order to
* display the wave-form: */
static const double block_period = 0.025; /* seconds */
double start_secs = 0, period = 2;
char dummy;
uint64_t seek;
/* All libSoX applications must start by initialising the SoX library */
assert(sox_init() == SOX_SUCCESS);
assert(argc > 1);
++argv, --argc; /* Move to 1st parameter */
/* Open the input file (with default parameters) */
assert((in = sox_open_read(*argv, NULL, NULL, NULL)));
++argv, --argc; /* Move past this parameter */
if (argc) { /* If given, read the start time: */
assert(sscanf(*argv, "%lf%c", &start_secs, &dummy) == 1);
++argv, --argc; /* Move past this parameter */
}
if (argc) { /* If given, read the period of time to display: */
assert(sscanf(*argv, "%lf%c", &period, &dummy) == 1);
++argv, --argc; /* Move past this parameter */
}
/* Calculate the start position in number of samples: */
seek = start_secs * in->signal.rate * in->signal.channels + .5;
/* Make sure that this is at a `wide sample' boundary: */
seek -= seek % in->signal.channels;
/* Move the file pointer to the desired starting position */
assert(sox_seek(in, seek, SOX_SEEK_SET) == SOX_SUCCESS);
/* Convert block size (in seconds) to a number of samples: */
block_size = block_period * in->signal.rate * in->signal.channels + .5;
/* Make sure that this is at a `wide sample' boundary: */
block_size -= block_size % in->signal.channels;
/* Allocate a block of memory to store the block of audio samples: */
assert((buf = malloc(sizeof(sox_sample_t) * block_size)));
/* This example program requires that the audio has precisely 2 channels: */
assert(in->signal.channels == 2);
/* Read and process blocks of audio for the selected period or until EOF: */
for (blocks = 0; sox_read(in, buf, block_size) == block_size && blocks * block_period < period; ++blocks) {
double left = 0, right = 0;
size_t i;
static const char line[] = "===================================";
int l, r;
for (i = 0; i < block_size; ++i) {
SOX_SAMPLE_LOCALS;
/* convert the sample from SoX's internal format to a `double' for
* processing in this application: */
double sample = SOX_SAMPLE_TO_FLOAT_64BIT(buf[i],);
/* The samples for each channel are interleaved; in this example
* we allow only stereo audio, so the left channel audio can be found in
* even-numbered samples, and the right channel audio in odd-numbered
* samples: */
if (i & 1)
right = max(right, fabs(sample)); /* Find the peak volume in the block */
else
left = max(left, fabs(sample)); /* Find the peak volume in the block */
}
/* Build up the wave form by displaying the left & right channel
* volume as a line length: */
l = (1 - left) * 35 + .5;
r = (1 - right) * 35 + .5;
printf("%8.3f%36s|%s\n", start_secs + blocks * block_period, line + l, line + r);
}
/* All done; tidy up: */
free(buf);
sox_close(in);
sox_quit();
return 0;
}

@ -0,0 +1,113 @@
/* Simple example of using SoX libraries
*
* Copyright (c) 2007-9 robs@users.sourceforge.net
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program 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 General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifdef NDEBUG /* N.B. assert used with active statements so enable always. */
#undef NDEBUG /* Must undef above assert.h or other that might include it. */
#endif
#include "sox.h"
#include "util.h"
#include <stdio.h>
#include <assert.h>
/*
* Example of a custom output message handler.
*/
static void output_message(unsigned level, const char *filename, const char *fmt, va_list ap)
{
char const * const str[] = {"FAIL", "WARN", "INFO", "DBUG"};
if (sox_globals.verbosity >= level) {
char base_name[128];
sox_basename(base_name, sizeof(base_name), filename);
fprintf(stderr, "%s %s: ", str[min(level - 1, 3)], base_name);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
}
}
/*
* On an alsa capable system, plays an audio file starting 10 seconds in.
* Copes with sample-rate and channel change if necessary since its
* common for audio drivers to support a subset of rates and channel
* counts.
* E.g. example3 song2.ogg
*
* Can easily be changed to work with other audio device drivers supported
* by libSoX; e.g. "oss", "ao", "coreaudio", etc.
* See the soxformat(7) manual page.
*/
int main(int argc, char * argv[])
{
static sox_format_t * in, * out; /* input and output files */
sox_effects_chain_t * chain;
sox_effect_t * e;
sox_signalinfo_t interm_signal;
char * args[10];
assert(argc == 2);
sox_globals.output_message_handler = output_message;
sox_globals.verbosity = 1;
assert(sox_init() == SOX_SUCCESS);
assert((in = sox_open_read(argv[1], NULL, NULL, NULL)));
/* Change "alsa" in this line to use an alternative audio device driver: */
assert((out= sox_open_write("default", &in->signal, NULL, "alsa", NULL, NULL)));
chain = sox_create_effects_chain(&in->encoding, &out->encoding);
interm_signal = in->signal; /* NB: deep copy */
e = sox_create_effect(sox_find_effect("input"));
args[0] = (char *)in, assert(sox_effect_options(e, 1, args) == SOX_SUCCESS);
assert(sox_add_effect(chain, e, &interm_signal, &in->signal) == SOX_SUCCESS);
free(e);
e = sox_create_effect(sox_find_effect("trim"));
args[0] = "10", assert(sox_effect_options(e, 1, args) == SOX_SUCCESS);
assert(sox_add_effect(chain, e, &interm_signal, &in->signal) == SOX_SUCCESS);
free(e);
if (in->signal.rate != out->signal.rate) {
e = sox_create_effect(sox_find_effect("rate"));
assert(sox_effect_options(e, 0, NULL) == SOX_SUCCESS);
assert(sox_add_effect(chain, e, &interm_signal, &out->signal) == SOX_SUCCESS);
free(e);
}
if (in->signal.channels != out->signal.channels) {
e = sox_create_effect(sox_find_effect("channels"));
assert(sox_effect_options(e, 0, NULL) == SOX_SUCCESS);
assert(sox_add_effect(chain, e, &interm_signal, &out->signal) == SOX_SUCCESS);
free(e);
}
e = sox_create_effect(sox_find_effect("output"));
args[0] = (char *)out, assert(sox_effect_options(e, 1, args) == SOX_SUCCESS);
assert(sox_add_effect(chain, e, &interm_signal, &out->signal) == SOX_SUCCESS);
free(e);
sox_flow_effects(chain, NULL, NULL);
sox_delete_effects_chain(chain);
sox_close(out);
sox_close(in);
sox_quit();
return 0;
}

@ -0,0 +1,98 @@
/* Simple example of using SoX libraries
*
* Copyright (c) 2009 robs@users.sourceforge.net
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program 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 General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "sox.h"
#include <stdio.h>
/* Concatenate audio files. Note that the files must have the same number
* of channels and the same sample rate.
*
* Usage: example4 input-1 input-2 [... input-n] output
*/
#define check(x) do if (!(x)) { \
fprintf(stderr, "check failed: %s\n", #x); goto error; } while (0)
int main(int argc, char * argv[])
{
sox_format_t * output = NULL;
int i;
check(argc >= 1 + 2 + 1); /* Need at least 2 input files + 1 output file. */
check(sox_init() == SOX_SUCCESS);
/* Defer openning the output file as we want to set its characteristics
* based on those of the input files. */
for (i = 1; i < argc - 1; ++i) { /* For each input file... */
sox_format_t * input;
static sox_signalinfo_t signal; /* static quashes `uninitialised' warning.*/
/* The (maximum) number of samples that we shall read/write at a time;
* chosen as a rough match to typical operating system I/O buffer size: */
#define MAX_SAMPLES (size_t)2048
sox_sample_t samples[MAX_SAMPLES]; /* Temporary store whilst copying. */
size_t number_read;
/* Open this input file: */
check(input = sox_open_read(argv[i], NULL, NULL, NULL));
if (i == 1) { /* If this is the first input file... */
/* Open the output file using the same signal and encoding character-
* istics as the first input file. Note that here, input->signal.length
* will not be equal to the output file length so we are relying on
* libSoX to set the output length correctly (i.e. non-seekable output
* is not catered for); an alternative would be to first calculate the
* output length by summing the lengths of the input files and modifying
* the second parameter to sox_open_write accordingly. */
check(output = sox_open_write(argv[argc - 1],
&input->signal, &input->encoding, NULL, NULL, NULL));
/* Also, we'll store the signal characteristics of the first file
* so that we can check that these match those of the other inputs: */
signal = input->signal;
}
else { /* Second or subsequent input file... */
/* Check that this input file's signal matches that of the first file: */
check(input->signal.channels == signal.channels);
check(input->signal.rate == signal.rate);
}
/* Copy all of the audio from this input file to the output file: */
while ((number_read = sox_read(input, samples, MAX_SAMPLES)))
check(sox_write(output, samples, number_read) == number_read);
check(sox_close(input) == SOX_SUCCESS); /* Finished with this input file.*/
}
check(sox_close(output) == SOX_SUCCESS); /* Finished with the output file. */
output = NULL;
check(sox_quit() == SOX_SUCCESS);
return 0;
error: /* Truncate output file on error: */
if (output) {
FILE * f;
sox_close(output);
if ((f = fopen(argv[argc - 1], "w"))) fclose(f);
}
return 1;
}

@ -0,0 +1,83 @@
/* Simple example of using SoX libraries
*
* Copyright (c) 2009 robs@users.sourceforge.net
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program 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 General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifdef NDEBUG /* N.B. assert used with active statements so enable always. */
#undef NDEBUG /* Must undef above assert.h or other that might include it. */
#endif
#include "sox.h"
#include "util.h"
#include <stdio.h>
#include <assert.h>
/* Example of reading and writing audio files stored in memory buffers
* rather than actual files.
*
* Usage: example5 input output
*/
/* Uncomment following line for fixed instead of malloc'd buffer: */
/*#define FIXED_BUFFER */
#if defined FIXED_BUFFER
#define buffer_size 123456
static char buffer[buffer_size];
#endif
int main(int argc, char * argv[])
{
static sox_format_t * in, * out; /* input and output files */
#define MAX_SAMPLES (size_t)2048
sox_sample_t samples[MAX_SAMPLES]; /* Temporary store whilst copying. */
#if !defined FIXED_BUFFER
char * buffer;
size_t buffer_size;
#endif
size_t number_read;
assert(argc == 3);
/* All libSoX applications must start by initialising the SoX library */
assert(sox_init() == SOX_SUCCESS);
/* Open the input file (with default parameters) */
assert((in = sox_open_read(argv[1], NULL, NULL, NULL)));
#if defined FIXED_BUFFER
assert((out = sox_open_mem_write(buffer, buffer_size, &in->signal, NULL, "sox", NULL)));
#else
assert((out = sox_open_memstream_write(&buffer, &buffer_size, &in->signal, NULL, "sox", NULL)));
#endif
while ((number_read = sox_read(in, samples, MAX_SAMPLES)))
assert(sox_write(out, samples, number_read) == number_read);
sox_close(out);
sox_close(in);
assert((in = sox_open_mem_read(buffer, buffer_size, NULL, NULL, NULL)));
assert((out = sox_open_write(argv[2], &in->signal, NULL, NULL, NULL, NULL)));
while ((number_read = sox_read(in, samples, MAX_SAMPLES)))
assert(sox_write(out, samples, number_read) == number_read);
sox_close(out);
sox_close(in);
#if !defined FIXED_BUFFER
free(buffer);
#endif
sox_quit();
return 0;
}

@ -0,0 +1,128 @@
/* Simple example of using SoX libraries
*
* Copyright (c) 2007-14 robs@users.sourceforge.net
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program 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 General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifdef NDEBUG /* N.B. assert used with active statements so enable always. */
#undef NDEBUG /* Must undef above assert.h or other that might include it. */
#endif
#include "sox.h"
#include "util.h"
#include <stdio.h>
#include <assert.h>
/*
* Shows how to explicitly specify output file signal and encoding attributes.
*
* The example converts a given input file of any type to mono mu-law at 8kHz
* sampling-rate (providing that this is supported by the given output file
* type).
*
* For example:
*
* sox -r 16k -n input.wav synth 8 sin 0:8k sin 8k:0 gain -1
* ./example6 input.wav output.wav
* soxi input.wav output.wav
*
* gives:
*
* Input File : 'input.wav'
* Channels : 2
* Sample Rate : 16000
* Precision : 32-bit
* Duration : 00:00:08.00 = 128000 samples ~ 600 CDDA sectors
* File Size : 1.02M
* Bit Rate : 1.02M
* Sample Encoding: 32-bit Signed Integer PCM
*
* Input File : 'output.wav'
* Channels : 1
* Sample Rate : 8000
* Precision : 14-bit
* Duration : 00:00:08.00 = 64000 samples ~ 600 CDDA sectors
* File Size : 64.1k
* Bit Rate : 64.1k
* Sample Encoding: 8-bit u-law
*/
int main(int argc, char * argv[])
{
static sox_format_t * in, * out; /* input and output files */
sox_effects_chain_t * chain;
sox_effect_t * e;
char * args[10];
sox_signalinfo_t interm_signal; /* @ intermediate points in the chain. */
sox_encodinginfo_t out_encoding = {
SOX_ENCODING_ULAW,
8,
0,
sox_option_default,
sox_option_default,
sox_option_default,
sox_false
};
sox_signalinfo_t out_signal = {
8000,
1,
0,
0,
NULL
};
assert(argc == 3);
assert(sox_init() == SOX_SUCCESS);
assert((in = sox_open_read(argv[1], NULL, NULL, NULL)));
assert((out = sox_open_write(argv[2], &out_signal, &out_encoding, NULL, NULL, NULL)));
chain = sox_create_effects_chain(&in->encoding, &out->encoding);
interm_signal = in->signal; /* NB: deep copy */
e = sox_create_effect(sox_find_effect("input"));
args[0] = (char *)in, assert(sox_effect_options(e, 1, args) == SOX_SUCCESS);
assert(sox_add_effect(chain, e, &interm_signal, &in->signal) == SOX_SUCCESS);
free(e);
if (in->signal.rate != out->signal.rate) {
e = sox_create_effect(sox_find_effect("rate"));
assert(sox_effect_options(e, 0, NULL) == SOX_SUCCESS);
assert(sox_add_effect(chain, e, &interm_signal, &out->signal) == SOX_SUCCESS);
free(e);
}
if (in->signal.channels != out->signal.channels) {
e = sox_create_effect(sox_find_effect("channels"));
assert(sox_effect_options(e, 0, NULL) == SOX_SUCCESS);
assert(sox_add_effect(chain, e, &interm_signal, &out->signal) == SOX_SUCCESS);
free(e);
}
e = sox_create_effect(sox_find_effect("output"));
args[0] = (char *)out, assert(sox_effect_options(e, 1, args) == SOX_SUCCESS);
assert(sox_add_effect(chain, e, &interm_signal, &out->signal) == SOX_SUCCESS);
free(e);
sox_flow_effects(chain, NULL, NULL);
sox_delete_effects_chain(chain);
sox_close(out);
sox_close(in);
sox_quit();
return 0;
}

@ -0,0 +1,21 @@
/* libSoX file formats: raw (c) 2007-8 SoX contributors
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
#include "raw.h"
RAW_FORMAT1(f4, "f32", 32, 0, FLOAT)

@ -0,0 +1,21 @@
/* libSoX file formats: raw (c) 2007-8 SoX contributors
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
#include "raw.h"
RAW_FORMAT1(f8, "f64", 64, 0, FLOAT)

@ -0,0 +1,399 @@
/* Ari Moisio <armoi@sci.fi> Aug 29 2000, based on skeleton effect
* Written by Chris Bagwell (cbagwell@sprynet.com) - March 16, 1999
*
* Copyright 1999 Chris Bagwell And Sundry Contributors
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
* Chris Bagwell And Sundry Contributors are not responsible for
* the consequences of using this software.
*/
#include "sox_i.h"
/* Fade curves */
#define FADE_QUARTER 'q' /* Quarter of sine wave, 0 to pi/2 */
#define FADE_HALF 'h' /* Half of sine wave, pi/2 to 1.5 * pi
* scaled so that -1 means no output
* and 1 means 0 db attenuation. */
#define FADE_LOG 'l' /* Logarithmic curve. Fades -100 db
* in given time. */
#define FADE_TRI 't' /* Linear slope. */
#define FADE_PAR 'p' /* Inverted parabola. */
#include <string.h>
/* Private data for fade file */
typedef struct { /* These are measured as samples */
uint64_t in_start, in_stop, out_start, out_stop, samplesdone;
char *in_stop_str, *out_start_str, *out_stop_str;
char in_fadetype, out_fadetype;
char do_out;
int endpadwarned;
} priv_t;
/* prototypes */
static double fade_gain(uint64_t index, uint64_t range, int fadetype);
/*
* Process options
*
* Don't do initialization now.
* The 'info' fields are not yet filled in.
*/
static int sox_fade_getopts(sox_effect_t * effp, int argc, char **argv)
{
priv_t * fade = (priv_t *) effp->priv;
char t_char[2];
int t_argno;
uint64_t samples;
const char *n;
--argc, ++argv;
if (argc < 1 || argc > 4)
return lsx_usage(effp);
/* because sample rate is unavailable at this point we store the
* string off for later computations.
*/
if (sscanf(argv[0], "%1[qhltp]", t_char))
{
fade->in_fadetype = *t_char;
fade->out_fadetype = *t_char;
argv++;
argc--;
}
else
{
/* No type given. */
fade->in_fadetype = 'l';
fade->out_fadetype = 'l';
}
fade->in_stop_str = lsx_strdup(argv[0]);
/* Do a dummy parse to see if it will fail */
n = lsx_parsesamples(0., fade->in_stop_str, &samples, 't');
if (!n || *n)
return lsx_usage(effp);
fade->in_stop = samples;
fade->out_start_str = fade->out_stop_str = 0;
for (t_argno = 1; t_argno < argc && t_argno < 3; t_argno++)
{
/* See if there is fade-in/fade-out times/curves specified. */
if(t_argno == 1)
{
fade->out_stop_str = lsx_strdup(argv[t_argno]);
/* Do a dummy parse to see if it will fail */
n = lsx_parseposition(0., fade->out_stop_str, NULL, (uint64_t)0, (uint64_t)0, '=');
if (!n || *n)
return lsx_usage(effp);
fade->out_stop = samples;
}
else
{
fade->out_start_str = lsx_strdup(argv[t_argno]);
/* Do a dummy parse to see if it will fail */
n = lsx_parsesamples(0., fade->out_start_str, &samples, 't');
if (!n || *n)
return lsx_usage(effp);
fade->out_start = samples;
}
} /* End for(t_argno) */
return(SOX_SUCCESS);
}
/*
* Prepare processing.
* Do all initializations.
*/
static int sox_fade_start(sox_effect_t * effp)
{
priv_t * fade = (priv_t *) effp->priv;
sox_bool truncate = sox_false;
uint64_t samples;
uint64_t in_length = effp->in_signal.length != SOX_UNKNOWN_LEN ?
effp->in_signal.length / effp->in_signal.channels : SOX_UNKNOWN_LEN;
/* converting time values to samples */
fade->in_start = 0;
if (lsx_parsesamples(effp->in_signal.rate, fade->in_stop_str,
&samples, 't') == NULL)
return lsx_usage(effp);
fade->in_stop = samples;
fade->do_out = 0;
/* See if user specified a stop time */
if (fade->out_stop_str)
{
fade->do_out = 1;
if (!lsx_parseposition(effp->in_signal.rate, fade->out_stop_str,
&samples, (uint64_t)0, in_length, '=') ||
samples == SOX_UNKNOWN_LEN) {
lsx_fail("audio length is unknown");
return SOX_EOF;
}
fade->out_stop = samples;
if (!(truncate = !!fade->out_stop)) {
fade->out_stop = effp->in_signal.length != SOX_UNKNOWN_LEN ?
effp->in_signal.length / effp->in_signal.channels :
0;
if (!fade->out_stop) {
lsx_fail("cannot fade out: audio length is neither known nor given");
return SOX_EOF;
}
}
/* See if user wants to fade out. */
if (fade->out_start_str)
{
if (lsx_parsesamples(effp->in_signal.rate, fade->out_start_str,
&samples, 't') == NULL)
return lsx_usage(effp);
/* Fade time is relative to stop time. */
fade->out_start = fade->out_stop - samples;
}
else
/* If user doesn't specify fade out length then
* use same length as input side. This is stored
* in in_stop.
*/
fade->out_start = fade->out_stop - fade->in_stop;
}
else
/* If not specified then user wants to process all
* of file. Use a value of zero to indicate this.
*/
fade->out_stop = 0;
if (fade->out_start) { /* Sanity check */
if (fade->in_stop > fade->out_start)
--fade->in_stop; /* 1 sample grace for rounding error. */
if (fade->in_stop > fade->out_start) {
lsx_fail("fade-out overlaps fade-in");
return SOX_EOF;
}
}
fade->samplesdone = fade->in_start;
fade->endpadwarned = 0;
lsx_debug("in_start = %" PRIu64 " in_stop = %" PRIu64 " "
"out_start = %" PRIu64 " out_stop = %" PRIu64,
fade->in_start, fade->in_stop, fade->out_start, fade->out_stop);
if (fade->in_start == fade->in_stop && !truncate &&
fade->out_start == fade->out_stop)
return SOX_EFF_NULL;
effp->out_signal.length = truncate ?
fade->out_stop * effp->in_signal.channels : effp->in_signal.length;
return SOX_SUCCESS;
}
/*
* Processed signed long samples from ibuf to obuf.
* Return number of samples processed.
*/
static int sox_fade_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,
size_t *isamp, size_t *osamp)
{
priv_t * fade = (priv_t *) effp->priv;
/* len is total samples, chcnt counts channels */
int len = 0, t_output = 1, more_output = 1;
sox_sample_t t_ibuf;
size_t chcnt = 0;
len = ((*isamp > *osamp) ? *osamp : *isamp);
*osamp = 0;
*isamp = 0;
for(; len && more_output; len--)
{
t_ibuf = *ibuf;
if ((fade->samplesdone >= fade->in_start) &&
(!fade->do_out || fade->samplesdone < fade->out_stop))
{ /* something to generate output */
if (fade->samplesdone < fade->in_stop)
{ /* fade-in phase, increase gain */
*obuf = t_ibuf *
fade_gain(fade->samplesdone - fade->in_start,
fade->in_stop - fade->in_start,
fade->in_fadetype);
} /* endif fade-in */
else if (!fade->do_out || fade->samplesdone < fade->out_start)
{ /* steady gain phase */
*obuf = t_ibuf;
} /* endif steady phase */
else
{ /* fade-out phase, decrease gain */
*obuf = t_ibuf *
fade_gain(fade->out_stop - fade->samplesdone,
fade->out_stop - fade->out_start,
fade->out_fadetype);
} /* endif fade-out */
if (!(!fade->do_out || fade->samplesdone < fade->out_stop))
more_output = 0;
t_output = 1;
}
else
{ /* No output generated */
t_output = 0;
} /* endif something to output */
*isamp += 1;
ibuf++;
if (t_output)
{ /* Output generated, update pointers and counters */
obuf++;
*osamp += 1;
} /* endif t_output */
/* Process next channel */
chcnt++;
if (chcnt >= effp->in_signal.channels)
{ /* all channels of this sample processed */
chcnt = 0;
fade->samplesdone += 1;
} /* endif all channels */
} /* endfor */
/* If not more samples will be returned, let application know
* this.
*/
if (fade->do_out && fade->samplesdone >= fade->out_stop)
return SOX_EOF;
else
return SOX_SUCCESS;
}
/*
* Drain out remaining samples if the effect generates any.
*/
static int sox_fade_drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp)
{
priv_t * fade = (priv_t *) effp->priv;
int len;
size_t t_chan = 0;
len = *osamp;
len -= len % effp->in_signal.channels;
*osamp = 0;
if (fade->do_out && fade->samplesdone < fade->out_stop &&
!(fade->endpadwarned))
{ /* Warning about padding silence into end of sample */
lsx_warn("End time past end of audio. Padding with silence");
fade->endpadwarned = 1;
} /* endif endpadwarned */
for (;len && (fade->do_out &&
fade->samplesdone < fade->out_stop); len--)
{
*obuf = 0;
obuf++;
*osamp += 1;
t_chan++;
if (t_chan >= effp->in_signal.channels)
{
fade->samplesdone += 1;
t_chan = 0;
} /* endif channels */
} /* endfor */
if (fade->do_out && fade->samplesdone >= fade->out_stop)
return SOX_EOF;
else
return SOX_SUCCESS;
}
/*
* Do anything required when you stop reading samples.
* (free allocated memory, etc.)
*/
static int lsx_kill(sox_effect_t * effp)
{
priv_t * fade = (priv_t *) effp->priv;
free(fade->in_stop_str);
free(fade->out_start_str);
free(fade->out_stop_str);
return (SOX_SUCCESS);
}
/* Function returns gain value 0.0 - 1.0 according index / range ratio
* and -1.0 if type is invalid
* todo: to optimize performance calculate gain every now and then and interpolate */
static double fade_gain(uint64_t index, uint64_t range, int type)
{
double retval = 0.0, findex = 0.0;
/* TODO: does it really have to be contrained to [0.0, 1.0]? */
findex = max(0.0, min(1.0, 1.0 * index / range));
switch (type) {
case FADE_TRI : /* triangle */
retval = findex;
break;
case FADE_QUARTER : /* quarter of sinewave */
retval = sin(findex * M_PI / 2);
break;
case FADE_HALF : /* half of sinewave... eh cosine wave */
retval = (1 - cos(findex * M_PI )) / 2 ;
break;
case FADE_LOG : /* logarithmic */
/* 5 means 100 db attenuation. */
/* TODO: should this be adopted with bit depth */
retval = pow(0.1, (1 - findex) * 5);
break;
case FADE_PAR : /* inverted parabola */
retval = (1 - (1 - findex) * (1 - findex));
break;
/* TODO: more fade curves? */
default : /* Error indicating wrong fade curve */
retval = -1.0;
break;
}
return retval;
}
static sox_effect_handler_t sox_fade_effect = {
"fade",
"[ type ] fade-in-length [ stop-position [ fade-out-length ] ]\n"
" Time is in hh:mm:ss.frac format.\n"
" Fade type one of q, h, t, l or p.",
SOX_EFF_MCHAN | SOX_EFF_LENGTH,
sox_fade_getopts,
sox_fade_start,
sox_fade_flow,
sox_fade_drain,
NULL,
lsx_kill, sizeof(priv_t)
};
const sox_effect_handler_t *lsx_fade_effect_fn(void)
{
return &sox_fade_effect;
}

@ -0,0 +1,31 @@
/* libSoX file format: FAP Copyright (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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
LSX_FORMAT_HANDLER(fap)
{
static char const * const names[] = {"fap", NULL};
static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 24, 16, 8,0,0};
static sox_format_handler_t handler;
handler = *lsx_sndfile_format_fn();
handler.description =
"Ensoniq PARIS digital audio editing system (little endian)";
handler.names = names;
handler.write_formats = write_encodings;
return &handler;
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,37 @@
/* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FFT4G_MAX_SIZE 262144
void lsx_cdft(int, int, double *, int *, double *);
void lsx_rdft(int, int, double *, int *, double *);
void lsx_ddct(int, int, double *, int *, double *);
void lsx_ddst(int, int, double *, int *, double *);
void lsx_dfct(int, double *, double *, int *, double *);
void lsx_dfst(int, double *, double *, int *, double *);
void lsx_cdft_f(int, int, float *, int *, float *);
void lsx_rdft_f(int, int, float *, int *, float *);
void lsx_ddct_f(int, int, float *, int *, float *);
void lsx_ddst_f(int, int, float *, int *, float *);
void lsx_dfct_f(int, float *, float *, int *, float *);
void lsx_dfst_f(int, float *, float *, int *, float *);
#define dft_br_len(l) (2 + (1 << (int)(log(l / 2 + .5) / log(2.)) / 2))
#define dft_sc_len(l) (l / 2)
/* Over-allocate h by 2 to use these macros */
#define LSX_PACK(h, n) h[1] = h[n]
#define LSX_UNPACK(h, n) h[n] = h[1], h[n + 1] = h[1] = 0;

@ -0,0 +1,119 @@
/* Addressable FIFO buffer Copyright (c) 2007 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef fifo_included
#define fifo_included
#include <string.h>
#ifndef FIFO_SIZE_T
#define FIFO_SIZE_T size_t
#endif
typedef struct {
char * data;
size_t allocation; /* Number of bytes allocated for data. */
size_t item_size; /* Size of each item in data */
size_t begin; /* Offset of the first byte to read. */
size_t end; /* 1 + Offset of the last byte byte to read. */
} fifo_t;
#define FIFO_MIN 0x4000
UNUSED static void fifo_clear(fifo_t * f)
{
f->end = f->begin = 0;
}
UNUSED static void * fifo_reserve(fifo_t * f, FIFO_SIZE_T n)
{
n *= f->item_size;
if (f->begin == f->end)
fifo_clear(f);
while (1) {
if (f->end + n <= f->allocation) {
void *p = f->data + f->end;
f->end += n;
return p;
}
if (f->begin > FIFO_MIN) {
memmove(f->data, f->data + f->begin, f->end - f->begin);
f->end -= f->begin;
f->begin = 0;
continue;
}
f->allocation += n;
f->data = lsx_realloc(f->data, f->allocation);
}
}
UNUSED static void * fifo_write(fifo_t * f, FIFO_SIZE_T n, void const * data)
{
void * s = fifo_reserve(f, n);
if (data)
memcpy(s, data, n * f->item_size);
return s;
}
UNUSED static void fifo_trim_to(fifo_t * f, FIFO_SIZE_T n)
{
n *= f->item_size;
f->end = f->begin + n;
}
UNUSED static void fifo_trim_by(fifo_t * f, FIFO_SIZE_T n)
{
n *= f->item_size;
f->end -= n;
}
UNUSED static FIFO_SIZE_T fifo_occupancy(fifo_t * f)
{
return (f->end - f->begin) / f->item_size;
}
UNUSED static void * fifo_read(fifo_t * f, FIFO_SIZE_T n, void * data)
{
char * ret = f->data + f->begin;
n *= f->item_size;
if (n > (FIFO_SIZE_T)(f->end - f->begin))
return NULL;
if (data)
memcpy(data, ret, (size_t)n);
f->begin += n;
return ret;
}
#define fifo_read_ptr(f) fifo_read(f, (FIFO_SIZE_T)0, NULL)
UNUSED static void fifo_delete(fifo_t * f)
{
free(f->data);
}
UNUSED static void fifo_create(fifo_t * f, FIFO_SIZE_T item_size)
{
f->item_size = item_size;
f->allocation = FIFO_MIN;
f->data = lsx_malloc(f->allocation);
fifo_clear(f);
}
#endif

@ -0,0 +1,105 @@
/* Effect: fir filter from coefs Copyright (c) 2009 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
#include "dft_filter.h"
typedef struct {
dft_filter_priv_t base;
char const * filename;
double * h;
int n;
} priv_t;
static int create(sox_effect_t * effp, int argc, char * * argv)
{
priv_t * p = (priv_t *)effp->priv;
dft_filter_priv_t * b = &p->base;
double d;
char c;
b->filter_ptr = &b->filter;
--argc, ++argv;
if (!argc)
p->filename = "-"; /* default to stdin */
else if (argc == 1)
p->filename = argv[0], --argc;
else for (; argc && sscanf(*argv, "%lf%c", &d, &c) == 1; --argc, ++argv) {
p->n++;
p->h = lsx_realloc(p->h, p->n * sizeof(*p->h));
p->h[p->n - 1] = d;
}
return argc? lsx_usage(effp) : SOX_SUCCESS;
}
static int start(sox_effect_t * effp)
{
priv_t * p = (priv_t *)effp->priv;
dft_filter_t * f = p->base.filter_ptr;
double d;
char c;
int i;
if (!f->num_taps) {
if (!p->n && p->filename) {
FILE * file = lsx_open_input_file(effp, p->filename, sox_true);
if (!file)
return SOX_EOF;
while ((i = fscanf(file, " #%*[^\n]%c", &c)) >= 0) {
if (i >= 1) continue; /* found and skipped a comment */
if ((i = fscanf(file, "%lf", &d)) > 0) {
/* found a coefficient value */
p->n++;
p->h = lsx_realloc(p->h, p->n * sizeof(*p->h));
p->h[p->n - 1] = d;
} else break; /* either EOF, or something went wrong
(read or syntax error) */
}
if (!feof(file)) {
lsx_fail("error reading coefficient file");
if (file != stdin) fclose(file);
return SOX_EOF;
}
if (file != stdin) fclose(file);
}
lsx_report("%i coefficients", p->n);
if (!p->n)
return SOX_EFF_NULL;
if (effp->global_info->plot != sox_plot_off) {
char title[100];
sprintf(title, "SoX effect: fir (%d coefficients)", p->n);
lsx_plot_fir(p->h, p->n, effp->in_signal.rate,
effp->global_info->plot, title, -30., 30.);
free(p->h);
return SOX_EOF;
}
lsx_set_dft_filter(f, p->h, p->n, p->n >> 1);
}
return lsx_dft_filter_effect_fn()->start(effp);
}
sox_effect_handler_t const * lsx_fir_effect_fn(void)
{
static sox_effect_handler_t handler;
handler = *lsx_dft_filter_effect_fn();
handler.name = "fir";
handler.usage = "[coef-file|coefs]";
handler.getopts = create;
handler.start = start;
handler.priv_size = sizeof(priv_t);
return &handler;
}

@ -0,0 +1,145 @@
/* Effect: firfit filter Copyright (c) 2009 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* This is W.I.P. hence marked SOX_EFF_ALPHA for now.
* Need to add other interpolation types e.g. linear, bspline, window types,
* and filter length, maybe phase response type too.
*/
#include "sox_i.h"
#include "dft_filter.h"
typedef struct {
dft_filter_priv_t base;
char const * filename;
struct {double f, gain;} * knots;
int num_knots, n;
} priv_t;
static int create(sox_effect_t * effp, int argc, char **argv)
{
priv_t * p = (priv_t *)effp->priv;
dft_filter_priv_t * b = &p->base;
b->filter_ptr = &b->filter;
--argc, ++argv;
if (argc == 1)
p->filename = argv[0], --argc;
p->n = 2047;
return argc? lsx_usage(effp) : SOX_SUCCESS;
}
static double * make_filter(sox_effect_t * effp)
{
priv_t * p = (priv_t *)effp->priv;
double * log_freqs, * gains, * d, * work, * h;
sox_rate_t rate = effp->in_signal.rate;
int i, work_len;
lsx_valloc(log_freqs , p->num_knots);
lsx_valloc(gains, p->num_knots);
lsx_valloc(d , p->num_knots);
for (i = 0; i < p->num_knots; ++i) {
log_freqs[i] = log(max(p->knots[i].f, 1));
gains[i] = p->knots[i].gain;
}
lsx_prepare_spline3(log_freqs, gains, p->num_knots, HUGE_VAL, HUGE_VAL, d);
for (work_len = 8192; work_len < rate / 2; work_len <<= 1);
work = lsx_calloc(work_len + 2, sizeof(*work));
lsx_valloc(h, p->n);
for (i = 0; i <= work_len; i += 2) {
double f = rate * 0.5 * i / work_len;
double spl1 = f < max(p->knots[0].f, 1)? gains[0] :
f > p->knots[p->num_knots - 1].f? gains[p->num_knots - 1] :
lsx_spline3(log_freqs, gains, d, p->num_knots, log(f));
work[i] = dB_to_linear(spl1);
}
LSX_PACK(work, work_len);
lsx_safe_rdft(work_len, -1, work);
for (i = 0; i < p->n; ++i)
h[i] = work[(work_len - p->n / 2 + i) % work_len] * 2. / work_len;
lsx_apply_blackman_nutall(h, p->n);
free(work);
return h;
}
static sox_bool read_knots(sox_effect_t * effp)
{
priv_t * p = (priv_t *) effp->priv;
FILE * file = lsx_open_input_file(effp, p->filename, sox_true);
sox_bool result = sox_false;
int num_converted = 1;
char c;
if (file) {
lsx_valloc(p->knots, 1);
while (fscanf(file, " #%*[^\n]%c", &c) >= 0) {
num_converted = fscanf(file, "%lf %lf",
&p->knots[p->num_knots].f, &p->knots[p->num_knots].gain);
if (num_converted == 2) {
if (p->num_knots && p->knots[p->num_knots].f <= p->knots[p->num_knots - 1].f) {
lsx_fail("knot frequencies must be strictly increasing");
break;
}
lsx_revalloc(p->knots, ++p->num_knots + 1);
} else if (num_converted != 0)
break;
}
lsx_report("%i knots", p->num_knots);
if (feof(file) && num_converted != 1)
result = sox_true;
else lsx_fail("error reading knot file `%s', line number %u", p->filename, 1 + p->num_knots);
if (file != stdin)
fclose(file);
}
return result;
}
static int start(sox_effect_t * effp)
{
priv_t * p = (priv_t *) effp->priv;
dft_filter_t * f = p->base.filter_ptr;
if (!f->num_taps) {
double * h;
if (!p->num_knots && !read_knots(effp))
return SOX_EOF;
h = make_filter(effp);
if (effp->global_info->plot != sox_plot_off) {
lsx_plot_fir(h, p->n, effp->in_signal.rate,
effp->global_info->plot, "SoX effect: firfit", -30., +30.);
return SOX_EOF;
}
lsx_set_dft_filter(f, h, p->n, p->n >> 1);
}
return lsx_dft_filter_effect_fn()->start(effp);
}
sox_effect_handler_t const * lsx_firfit_effect_fn(void)
{
static sox_effect_handler_t handler;
handler = *lsx_dft_filter_effect_fn();
handler.name = "firfit";
handler.usage = "[knots-file]";
handler.flags |= SOX_EFF_ALPHA;
handler.getopts = create;
handler.start = start;
handler.priv_size = sizeof(priv_t);
return &handler;
}

@ -0,0 +1,606 @@
/* libSoX file format: FLAC (c) 2006-7 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
#include <string.h>
/* Next line for systems that don't define off_t when you #include
stdio.h; apparently OS/2 has this bug */
#include <sys/types.h>
#include <FLAC/all.h>
#define MAX_COMPRESSION 8
typedef struct {
/* Info: */
unsigned bits_per_sample;
unsigned channels;
unsigned sample_rate;
uint64_t total_samples;
/* Decode buffer: */
sox_sample_t *req_buffer; /* this may be on the stack */
size_t number_of_requested_samples;
sox_sample_t *leftover_buf; /* heap */
unsigned number_of_leftover_samples;
FLAC__StreamDecoder * decoder;
FLAC__bool eof;
sox_bool seek_pending;
uint64_t seek_offset;
/* Encode buffer: */
FLAC__int32 * decoded_samples;
unsigned number_of_samples;
FLAC__StreamEncoder * encoder;
FLAC__StreamMetadata * metadata[2];
unsigned num_metadata;
} priv_t;
static FLAC__StreamDecoderReadStatus decoder_read_callback(FLAC__StreamDecoder const* decoder UNUSED, FLAC__byte buffer[], size_t* bytes, void* ft_data)
{
sox_format_t* ft = (sox_format_t*)ft_data;
if(*bytes > 0) {
*bytes = lsx_readbuf(ft, buffer, *bytes);
if(lsx_error(ft))
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
else if(*bytes == 0)
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
else
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}
else
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
}
static FLAC__StreamDecoderSeekStatus decoder_seek_callback(FLAC__StreamDecoder const* decoder UNUSED, FLAC__uint64 absolute_byte_offset, void* ft_data)
{
sox_format_t* ft = (sox_format_t*)ft_data;
if(lsx_seeki(ft, (off_t)absolute_byte_offset, SEEK_SET) < 0)
return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
else
return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
}
static FLAC__StreamDecoderTellStatus decoder_tell_callback(FLAC__StreamDecoder const* decoder UNUSED, FLAC__uint64* absolute_byte_offset, void* ft_data)
{
sox_format_t* ft = (sox_format_t*)ft_data;
off_t pos;
if((pos = lsx_tell(ft)) < 0)
return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
else {
*absolute_byte_offset = (FLAC__uint64)pos;
return FLAC__STREAM_DECODER_TELL_STATUS_OK;
}
}
static FLAC__StreamDecoderLengthStatus decoder_length_callback(FLAC__StreamDecoder const* decoder UNUSED, FLAC__uint64* stream_length, void* ft_data)
{
sox_format_t* ft = (sox_format_t*)ft_data;
*stream_length = lsx_filelength(ft);
return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
}
static FLAC__bool decoder_eof_callback(FLAC__StreamDecoder const* decoder UNUSED, void* ft_data)
{
sox_format_t* ft = (sox_format_t*)ft_data;
return lsx_eof(ft) ? 1 : 0;
}
static void decoder_metadata_callback(FLAC__StreamDecoder const * const flac, FLAC__StreamMetadata const * const metadata, void * const client_data)
{
sox_format_t * ft = (sox_format_t *) client_data;
priv_t * p = (priv_t *)ft->priv;
(void) flac;
if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
p->bits_per_sample = metadata->data.stream_info.bits_per_sample;
p->channels = metadata->data.stream_info.channels;
p->sample_rate = metadata->data.stream_info.sample_rate;
p->total_samples = metadata->data.stream_info.total_samples;
}
else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
const FLAC__StreamMetadata_VorbisComment *vc = &metadata->data.vorbis_comment;
size_t i;
if (vc->num_comments == 0)
return;
if (ft->oob.comments != NULL) {
lsx_warn("multiple Vorbis comment block ignored");
return;
}
for (i = 0; i < vc->num_comments; ++i)
if (vc->comments[i].entry)
sox_append_comment(&ft->oob.comments, (char const *) vc->comments[i].entry);
}
}
static void decoder_error_callback(FLAC__StreamDecoder const * const flac, FLAC__StreamDecoderErrorStatus const status, void * const client_data)
{
sox_format_t * ft = (sox_format_t *) client_data;
(void) flac;
lsx_fail_errno(ft, SOX_EINVAL, "%s", FLAC__StreamDecoderErrorStatusString[status]);
}
static FLAC__StreamDecoderWriteStatus decoder_write_callback(FLAC__StreamDecoder const * const flac, FLAC__Frame const * const frame, FLAC__int32 const * const buffer[], void * const client_data)
{
sox_format_t * ft = (sox_format_t *) client_data;
priv_t * p = (priv_t *)ft->priv;
sox_sample_t * dst = p->req_buffer;
unsigned channel;
unsigned nsamples = frame->header.blocksize;
unsigned sample = 0;
size_t actual = nsamples * p->channels;
(void) flac;
if (frame->header.bits_per_sample != p->bits_per_sample || frame->header.channels != p->channels || frame->header.sample_rate != p->sample_rate) {
lsx_fail_errno(ft, SOX_EINVAL, "FLAC ERROR: parameters differ between frame and header");
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
}
if (dst == NULL) {
lsx_warn("FLAC ERROR: entered write callback without a buffer (SoX bug)");
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
}
/* FLAC may give us too much data, prepare the leftover buffer */
if (actual > p->number_of_requested_samples) {
size_t to_stash = actual - p->number_of_requested_samples;
p->leftover_buf = lsx_malloc(to_stash * sizeof(sox_sample_t));
p->number_of_leftover_samples = to_stash;
nsamples = p->number_of_requested_samples / p->channels;
p->req_buffer += p->number_of_requested_samples;
p->number_of_requested_samples = 0;
} else {
p->req_buffer += actual;
p->number_of_requested_samples -= actual;
}
leftover_copy:
for (; sample < nsamples; sample++) {
for (channel = 0; channel < p->channels; channel++) {
FLAC__int32 d = buffer[channel][sample];
switch (p->bits_per_sample) {
case 8: *dst++ = SOX_SIGNED_8BIT_TO_SAMPLE(d,); break;
case 16: *dst++ = SOX_SIGNED_16BIT_TO_SAMPLE(d,); break;
case 24: *dst++ = SOX_SIGNED_24BIT_TO_SAMPLE(d,); break;
case 32: *dst++ = SOX_SIGNED_32BIT_TO_SAMPLE(d,); break;
}
}
}
/* copy into the leftover buffer if we've prepared it */
if (sample < frame->header.blocksize) {
nsamples = frame->header.blocksize;
dst = p->leftover_buf;
goto leftover_copy;
}
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
static int start_read(sox_format_t * const ft)
{
priv_t * p = (priv_t *)ft->priv;
lsx_debug("API version %u", FLAC_API_VERSION_CURRENT);
p->decoder = FLAC__stream_decoder_new();
if (p->decoder == NULL) {
lsx_fail_errno(ft, SOX_ENOMEM, "FLAC ERROR creating the decoder instance");
return SOX_EOF;
}
FLAC__stream_decoder_set_md5_checking(p->decoder, sox_true);
FLAC__stream_decoder_set_metadata_respond_all(p->decoder);
if (FLAC__stream_decoder_init_stream(
p->decoder,
decoder_read_callback,
ft->seekable ? decoder_seek_callback : NULL,
ft->seekable ? decoder_tell_callback : NULL,
ft->seekable ? decoder_length_callback : NULL,
ft->seekable ? decoder_eof_callback : NULL,
decoder_write_callback,
decoder_metadata_callback,
decoder_error_callback,
ft) != FLAC__STREAM_DECODER_INIT_STATUS_OK){
lsx_fail_errno(ft, SOX_EHDR, "FLAC ERROR initialising decoder");
return SOX_EOF;
}
if (!FLAC__stream_decoder_process_until_end_of_metadata(p->decoder)) {
lsx_fail_errno(ft, SOX_EHDR, "FLAC ERROR whilst decoding metadata");
return SOX_EOF;
}
if (FLAC__stream_decoder_get_state(p->decoder) > FLAC__STREAM_DECODER_END_OF_STREAM) {
lsx_fail_errno(ft, SOX_EHDR, "FLAC ERROR during metadata decoding");
return SOX_EOF;
}
ft->encoding.encoding = SOX_ENCODING_FLAC;
ft->signal.rate = p->sample_rate;
ft->encoding.bits_per_sample = p->bits_per_sample;
ft->signal.channels = p->channels;
ft->signal.length = p->total_samples * p->channels;
return SOX_SUCCESS;
}
static size_t read_samples(sox_format_t * const ft, sox_sample_t * sampleBuffer, size_t const requested)
{
priv_t * p = (priv_t *)ft->priv;
size_t prev_requested;
if (p->seek_pending) {
p->seek_pending = sox_false;
/* discard leftover decoded data */
free(p->leftover_buf);
p->leftover_buf = NULL;
p->number_of_leftover_samples = 0;
p->req_buffer = sampleBuffer;
p->number_of_requested_samples = requested;
/* calls decoder_write_callback */
if (!FLAC__stream_decoder_seek_absolute(p->decoder, (FLAC__uint64)(p->seek_offset / ft->signal.channels))) {
p->req_buffer = NULL;
return 0;
}
} else if (p->number_of_leftover_samples > 0) {
/* small request, no need to decode more samples since we have leftovers */
if (requested < p->number_of_leftover_samples) {
size_t req_bytes = requested * sizeof(sox_sample_t);
memcpy(sampleBuffer, p->leftover_buf, req_bytes);
p->number_of_leftover_samples -= requested;
memmove(p->leftover_buf, (char *)p->leftover_buf + req_bytes,
(size_t)p->number_of_leftover_samples * sizeof(sox_sample_t));
return requested;
}
/* first, give them all of our leftover data: */
memcpy(sampleBuffer, p->leftover_buf,
p->number_of_leftover_samples * sizeof(sox_sample_t));
p->req_buffer = sampleBuffer + p->number_of_leftover_samples;
p->number_of_requested_samples = requested - p->number_of_leftover_samples;
free(p->leftover_buf);
p->leftover_buf = NULL;
p->number_of_leftover_samples = 0;
/* continue invoking decoder below */
} else {
p->req_buffer = sampleBuffer;
p->number_of_requested_samples = requested;
}
/* invoke the decoder, calls decoder_write_callback */
while ((prev_requested = p->number_of_requested_samples) && !p->eof) {
if (!FLAC__stream_decoder_process_single(p->decoder))
break; /* error, but maybe got earlier in the loop, though */
/* number_of_requested_samples decrements as the decoder progresses */
if (p->number_of_requested_samples == prev_requested)
p->eof = sox_true;
}
p->req_buffer = NULL;
return requested - p->number_of_requested_samples;
}
static int stop_read(sox_format_t * const ft)
{
priv_t * p = (priv_t *)ft->priv;
if (!FLAC__stream_decoder_finish(p->decoder) && p->eof)
lsx_warn("decoder MD5 checksum mismatch.");
FLAC__stream_decoder_delete(p->decoder);
free(p->leftover_buf);
p->leftover_buf = NULL;
p->number_of_leftover_samples = 0;
return SOX_SUCCESS;
}
static FLAC__StreamEncoderWriteStatus flac_stream_encoder_write_callback(FLAC__StreamEncoder const * const flac, const FLAC__byte buffer[], size_t const bytes, unsigned const samples, unsigned const current_frame, void * const client_data)
{
sox_format_t * const ft = (sox_format_t *) client_data;
(void) flac, (void) samples, (void) current_frame;
return lsx_writebuf(ft, buffer, bytes) == bytes ? FLAC__STREAM_ENCODER_WRITE_STATUS_OK : FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
}
static void flac_stream_encoder_metadata_callback(FLAC__StreamEncoder const * encoder, FLAC__StreamMetadata const * metadata, void * client_data)
{
(void) encoder, (void) metadata, (void) client_data;
}
static FLAC__StreamEncoderSeekStatus flac_stream_encoder_seek_callback(FLAC__StreamEncoder const * encoder, FLAC__uint64 absolute_byte_offset, void * client_data)
{
sox_format_t * const ft = (sox_format_t *) client_data;
(void) encoder;
if (!ft->seekable)
return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
else if (lsx_seeki(ft, (off_t)absolute_byte_offset, SEEK_SET) != SOX_SUCCESS)
return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
else
return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
}
static FLAC__StreamEncoderTellStatus flac_stream_encoder_tell_callback(FLAC__StreamEncoder const * encoder, FLAC__uint64 * absolute_byte_offset, void * client_data)
{
sox_format_t * const ft = (sox_format_t *) client_data;
off_t pos;
(void) encoder;
if (!ft->seekable)
return FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED;
else if ((pos = lsx_tell(ft)) < 0)
return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
else {
*absolute_byte_offset = (FLAC__uint64)pos;
return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
}
}
static int start_write(sox_format_t * const ft)
{
priv_t * p = (priv_t *)ft->priv;
FLAC__StreamEncoderInitStatus status;
unsigned compression_level = MAX_COMPRESSION; /* Default to "best" */
if (ft->encoding.compression != HUGE_VAL) {
compression_level = ft->encoding.compression;
if (compression_level != ft->encoding.compression ||
compression_level > MAX_COMPRESSION) {
lsx_fail_errno(ft, SOX_EINVAL,
"FLAC compression level must be a whole number from 0 to %i",
MAX_COMPRESSION);
return SOX_EOF;
}
}
p->encoder = FLAC__stream_encoder_new();
if (p->encoder == NULL) {
lsx_fail_errno(ft, SOX_ENOMEM, "FLAC ERROR creating the encoder instance");
return SOX_EOF;
}
p->bits_per_sample = ft->encoding.bits_per_sample;
ft->signal.precision = ft->encoding.bits_per_sample;
lsx_report("encoding at %i bits per sample", p->bits_per_sample);
FLAC__stream_encoder_set_channels(p->encoder, ft->signal.channels);
FLAC__stream_encoder_set_bits_per_sample(p->encoder, p->bits_per_sample);
FLAC__stream_encoder_set_sample_rate(p->encoder, (unsigned)(ft->signal.rate + .5));
{ /* Check if rate is streamable: */
static const unsigned streamable_rates[] =
{8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000};
size_t i;
sox_bool streamable = sox_false;
for (i = 0; !streamable && i < array_length(streamable_rates); ++i)
streamable = (streamable_rates[i] == ft->signal.rate);
if (!streamable) {
lsx_report("non-standard rate; output may not be streamable");
FLAC__stream_encoder_set_streamable_subset(p->encoder, sox_false);
}
}
#if FLAC_API_VERSION_CURRENT >= 10
FLAC__stream_encoder_set_compression_level(p->encoder, compression_level);
#else
{
static struct {
unsigned blocksize;
FLAC__bool do_exhaustive_model_search;
FLAC__bool do_mid_side_stereo;
FLAC__bool loose_mid_side_stereo;
unsigned max_lpc_order;
unsigned max_residual_partition_order;
unsigned min_residual_partition_order;
} const options[MAX_COMPRESSION + 1] = {
{1152, sox_false, sox_false, sox_false, 0, 2, 2},
{1152, sox_false, sox_true, sox_true, 0, 2, 2},
{1152, sox_false, sox_true, sox_false, 0, 3, 0},
{4608, sox_false, sox_false, sox_false, 6, 3, 3},
{4608, sox_false, sox_true, sox_true, 8, 3, 3},
{4608, sox_false, sox_true, sox_false, 8, 3, 3},
{4608, sox_false, sox_true, sox_false, 8, 4, 0},
{4608, sox_true, sox_true, sox_false, 8, 6, 0},
{4608, sox_true, sox_true, sox_false, 12, 6, 0},
};
#define SET_OPTION(x) do {\
lsx_report(#x" = %i", options[compression_level].x); \
FLAC__stream_encoder_set_##x(p->encoder, options[compression_level].x);\
} while (0)
SET_OPTION(blocksize);
SET_OPTION(do_exhaustive_model_search);
SET_OPTION(max_lpc_order);
SET_OPTION(max_residual_partition_order);
SET_OPTION(min_residual_partition_order);
if (ft->signal.channels == 2) {
SET_OPTION(do_mid_side_stereo);
SET_OPTION(loose_mid_side_stereo);
}
#undef SET_OPTION
}
#endif
if (ft->signal.length != 0) {
FLAC__stream_encoder_set_total_samples_estimate(p->encoder, (FLAC__uint64)(ft->signal.length / ft->signal.channels));
p->metadata[p->num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE);
if (p->metadata[p->num_metadata] == NULL) {
lsx_fail_errno(ft, SOX_ENOMEM, "FLAC ERROR creating the encoder seek table template");
return SOX_EOF;
}
{
if (!FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(p->metadata[p->num_metadata], (unsigned)(10 * ft->signal.rate + .5), (FLAC__uint64)(ft->signal.length/ft->signal.channels))) {
lsx_fail_errno(ft, SOX_ENOMEM, "FLAC ERROR creating the encoder seek table points");
return SOX_EOF;
}
}
p->metadata[p->num_metadata]->is_last = sox_false; /* the encoder will set this for us */
++p->num_metadata;
}
if (ft->oob.comments) { /* Make the comment structure */
FLAC__StreamMetadata_VorbisComment_Entry entry;
int i;
p->metadata[p->num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
for (i = 0; ft->oob.comments[i]; ++i) {
static const char prepend[] = "Comment=";
char * text = lsx_calloc(strlen(prepend) + strlen(ft->oob.comments[i]) + 1, sizeof(*text));
/* Prepend `Comment=' if no field-name already in the comment */
if (!strchr(ft->oob.comments[i], '='))
strcpy(text, prepend);
entry.entry = (FLAC__byte *) strcat(text, ft->oob.comments[i]);
entry.length = strlen(text);
FLAC__metadata_object_vorbiscomment_append_comment(p->metadata[p->num_metadata], entry, /*copy= */ sox_true);
free(text);
}
++p->num_metadata;
}
if (p->num_metadata)
FLAC__stream_encoder_set_metadata(p->encoder, p->metadata, p->num_metadata);
status = FLAC__stream_encoder_init_stream(p->encoder, flac_stream_encoder_write_callback,
flac_stream_encoder_seek_callback, flac_stream_encoder_tell_callback, flac_stream_encoder_metadata_callback, ft);
if (status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
lsx_fail_errno(ft, SOX_EINVAL, "%s", FLAC__StreamEncoderInitStatusString[status]);
return SOX_EOF;
}
return SOX_SUCCESS;
}
static size_t write_samples(sox_format_t * const ft, sox_sample_t const * const sampleBuffer, size_t const len)
{
priv_t * p = (priv_t *)ft->priv;
unsigned i;
/* allocate or grow buffer */
if (p->number_of_samples < len) {
p->number_of_samples = len;
free(p->decoded_samples);
p->decoded_samples = lsx_malloc(p->number_of_samples * sizeof(FLAC__int32));
}
for (i = 0; i < len; ++i) {
SOX_SAMPLE_LOCALS;
long pcm = SOX_SAMPLE_TO_SIGNED_32BIT(sampleBuffer[i], ft->clips);
p->decoded_samples[i] = pcm >> (32 - p->bits_per_sample);
switch (p->bits_per_sample) {
case 8: p->decoded_samples[i] =
SOX_SAMPLE_TO_SIGNED_8BIT(sampleBuffer[i], ft->clips);
break;
case 16: p->decoded_samples[i] =
SOX_SAMPLE_TO_SIGNED_16BIT(sampleBuffer[i], ft->clips);
break;
case 24: p->decoded_samples[i] = /* sign extension: */
SOX_SAMPLE_TO_SIGNED_24BIT(sampleBuffer[i],ft->clips) << 8;
p->decoded_samples[i] >>= 8;
break;
case 32: p->decoded_samples[i] =
SOX_SAMPLE_TO_SIGNED_32BIT(sampleBuffer[i],ft->clips);
break;
}
}
FLAC__stream_encoder_process_interleaved(p->encoder, p->decoded_samples, (unsigned) len / ft->signal.channels);
return FLAC__stream_encoder_get_state(p->encoder) == FLAC__STREAM_ENCODER_OK ? len : 0;
}
static int stop_write(sox_format_t * const ft)
{
priv_t * p = (priv_t *)ft->priv;
FLAC__StreamEncoderState state = FLAC__stream_encoder_get_state(p->encoder);
unsigned i;
FLAC__stream_encoder_finish(p->encoder);
FLAC__stream_encoder_delete(p->encoder);
for (i = 0; i < p->num_metadata; ++i)
FLAC__metadata_object_delete(p->metadata[i]);
free(p->decoded_samples);
if (state != FLAC__STREAM_ENCODER_OK) {
lsx_fail_errno(ft, SOX_EINVAL, "FLAC ERROR: failed to encode to end of stream");
return SOX_EOF;
}
return SOX_SUCCESS;
}
static int seek(sox_format_t * ft, uint64_t offset)
{
priv_t * p = (priv_t *)ft->priv;
p->seek_offset = offset;
p->seek_pending = sox_true;
return ft->mode == 'r' ? SOX_SUCCESS : SOX_EOF;
}
LSX_FORMAT_HANDLER(flac)
{
static char const * const names[] = {"flac", NULL};
static unsigned const encodings[] = {SOX_ENCODING_FLAC, 8, 16, 24, 0, 0};
static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
"Free Lossless Audio CODEC compressed audio", names, 0,
start_read, read_samples, stop_read,
start_write, write_samples, stop_write,
seek, encodings, NULL, sizeof(priv_t)
};
return &handler;
}

@ -0,0 +1,275 @@
/* libSoX effect: Stereo Flanger (c) 2006 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* TODO: Slide in the delay at the start? */
#include "sox_i.h"
#include <string.h>
typedef enum {INTERP_LINEAR, INTERP_QUADRATIC} interp_t;
#define MAX_CHANNELS 4
typedef struct {
/* Parameters */
double delay_min;
double delay_depth;
double feedback_gain;
double delay_gain;
double speed;
lsx_wave_t wave_shape;
double channel_phase;
interp_t interpolation;
/* Delay buffers */
double * delay_bufs[MAX_CHANNELS];
size_t delay_buf_length;
size_t delay_buf_pos;
double delay_last[MAX_CHANNELS];
/* Low Frequency Oscillator */
float * lfo;
size_t lfo_length;
size_t lfo_pos;
/* Balancing */
double in_gain;
} priv_t;
static lsx_enum_item const interp_enum[] = {
LSX_ENUM_ITEM(INTERP_,LINEAR)
LSX_ENUM_ITEM(INTERP_,QUADRATIC)
{0, 0}};
static int getopts(sox_effect_t * effp, int argc, char *argv[])
{
priv_t * p = (priv_t *) effp->priv;
--argc, ++argv;
/* Set non-zero defaults: */
p->delay_depth = 2;
p->delay_gain = 71;
p->speed = 0.5;
p->channel_phase= 25;
do { /* break-able block */
NUMERIC_PARAMETER(delay_min , 0 , 30 )
NUMERIC_PARAMETER(delay_depth , 0 , 10 )
NUMERIC_PARAMETER(feedback_gain,-95 , 95 )
NUMERIC_PARAMETER(delay_gain , 0 , 100)
NUMERIC_PARAMETER(speed , 0.1, 10 )
TEXTUAL_PARAMETER(wave_shape, lsx_get_wave_enum())
NUMERIC_PARAMETER(channel_phase, 0 , 100)
TEXTUAL_PARAMETER(interpolation, interp_enum)
} while (0);
if (argc != 0)
return lsx_usage(effp);
lsx_report("parameters:\n"
"delay = %gms\n"
"depth = %gms\n"
"regen = %g%%\n"
"width = %g%%\n"
"speed = %gHz\n"
"shape = %s\n"
"phase = %g%%\n"
"interp= %s",
p->delay_min,
p->delay_depth,
p->feedback_gain,
p->delay_gain,
p->speed,
lsx_get_wave_enum()[p->wave_shape].text,
p->channel_phase,
interp_enum[p->interpolation].text);
/* Scale to unity: */
p->feedback_gain /= 100;
p->delay_gain /= 100;
p->channel_phase /= 100;
p->delay_min /= 1000;
p->delay_depth /= 1000;
return SOX_SUCCESS;
}
static int start(sox_effect_t * effp)
{
priv_t * f = (priv_t *) effp->priv;
int c, channels = effp->in_signal.channels;
if (channels > MAX_CHANNELS) {
lsx_fail("Can not operate with more than %i channels", MAX_CHANNELS);
return SOX_EOF;
}
/* Balance output: */
f->in_gain = 1 / (1 + f->delay_gain);
f->delay_gain /= 1 + f->delay_gain;
/* Balance feedback loop: */
f->delay_gain *= 1 - fabs(f->feedback_gain);
lsx_debug("in_gain=%g feedback_gain=%g delay_gain=%g\n",
f->in_gain, f->feedback_gain, f->delay_gain);
/* Create the delay buffers, one for each channel: */
f->delay_buf_length =
(f->delay_min + f->delay_depth) * effp->in_signal.rate + 0.5;
++f->delay_buf_length; /* Need 0 to n, i.e. n + 1. */
++f->delay_buf_length; /* Quadratic interpolator needs one more. */
for (c = 0; c < channels; ++c)
f->delay_bufs[c] = lsx_calloc(f->delay_buf_length, sizeof(*f->delay_bufs[0]));
/* Create the LFO lookup table: */
f->lfo_length = effp->in_signal.rate / f->speed;
f->lfo = lsx_calloc(f->lfo_length, sizeof(*f->lfo));
lsx_generate_wave_table(
f->wave_shape,
SOX_FLOAT,
f->lfo,
f->lfo_length,
floor(f->delay_min * effp->in_signal.rate + .5),
f->delay_buf_length - 2.,
3 * M_PI_2); /* Start the sweep at minimum delay (for mono at least) */
lsx_debug("delay_buf_length=%" PRIuPTR " lfo_length=%" PRIuPTR "\n",
f->delay_buf_length, f->lfo_length);
return SOX_SUCCESS;
}
static int flow(sox_effect_t * effp, sox_sample_t const * ibuf,
sox_sample_t * obuf, size_t * isamp, size_t * osamp)
{
priv_t * f = (priv_t *) effp->priv;
int c, channels = effp->in_signal.channels;
size_t len = (*isamp > *osamp ? *osamp : *isamp) / channels;
*isamp = *osamp = len * channels;
while (len--) {
f->delay_buf_pos =
(f->delay_buf_pos + f->delay_buf_length - 1) % f->delay_buf_length;
for (c = 0; c < channels; ++c) {
double delayed_0, delayed_1;
double delayed;
double in, out;
size_t channel_phase = c * f->lfo_length * f->channel_phase + .5;
double delay = f->lfo[(f->lfo_pos + channel_phase) % f->lfo_length];
double frac_delay = modf(delay, &delay);
size_t int_delay = (size_t)delay;
in = *ibuf++;
f->delay_bufs[c][f->delay_buf_pos] = in + f->delay_last[c] * f->feedback_gain;
delayed_0 = f->delay_bufs[c]
[(f->delay_buf_pos + int_delay++) % f->delay_buf_length];
delayed_1 = f->delay_bufs[c]
[(f->delay_buf_pos + int_delay++) % f->delay_buf_length];
if (f->interpolation == INTERP_LINEAR)
delayed = delayed_0 + (delayed_1 - delayed_0) * frac_delay;
else /* if (f->interpolation == INTERP_QUADRATIC) */
{
double a, b;
double delayed_2 = f->delay_bufs[c]
[(f->delay_buf_pos + int_delay++) % f->delay_buf_length];
delayed_2 -= delayed_0;
delayed_1 -= delayed_0;
a = delayed_2 *.5 - delayed_1;
b = delayed_1 * 2 - delayed_2 *.5;
delayed = delayed_0 + (a * frac_delay + b) * frac_delay;
}
f->delay_last[c] = delayed;
out = in * f->in_gain + delayed * f->delay_gain;
*obuf++ = SOX_ROUND_CLIP_COUNT(out, effp->clips);
}
f->lfo_pos = (f->lfo_pos + 1) % f->lfo_length;
}
return SOX_SUCCESS;
}
static int stop(sox_effect_t * effp)
{
priv_t * f = (priv_t *) effp->priv;
int c, channels = effp->in_signal.channels;
for (c = 0; c < channels; ++c)
free(f->delay_bufs[c]);
free(f->lfo);
memset(f, 0, sizeof(*f));
return SOX_SUCCESS;
}
sox_effect_handler_t const * lsx_flanger_effect_fn(void)
{
static sox_effect_handler_t handler = {
"flanger", NULL, SOX_EFF_MCHAN,
getopts, start, flow, NULL, stop, NULL, sizeof(priv_t)};
static char const * lines[] = {
"[delay depth regen width speed shape phase interp]",
" .",
" /|regen",
" / |",
" +--( |------------+",
" | \\ | | .",
" _V_ \\| _______ | |\\ width ___",
" | | ' | | | | \\ | |",
" +-->| + |---->| DELAY |--+-->| )----->| |",
" | |___| |_______| | / | |",
" | delay : depth |/ | |",
" In | : interp ' | | Out",
" --->+ __:__ | + |--->",
" | | |speed | |",
" | | ~ |shape | |",
" | |_____|phase | |",
" +------------------------------------->| |",
" |___|",
" RANGE DEFAULT DESCRIPTION",
"delay 0 30 0 base delay in milliseconds",
"depth 0 10 2 added swept delay in milliseconds",
"regen -95 +95 0 percentage regeneration (delayed signal feedback)",
"width 0 100 71 percentage of delayed signal mixed with original",
"speed 0.1 10 0.5 sweeps per second (Hz) ",
"shape -- sin swept wave shape: sine|triangle",
"phase 0 100 25 swept wave percentage phase-shift for multi-channel",
" (e.g. stereo) flange; 0 = 100 = same phase on each channel",
"interp -- lin delay-line interpolation: linear|quadratic"
};
static char * usage;
handler.usage = lsx_usage_lines(&usage, lines, array_length(lines));
return &handler;
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,130 @@
/* libSoX static formats list (c) 2006-9 Chris Bagwell and SoX contributors
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*-------------------------- Static format handlers --------------------------*/
FORMAT(aifc)
FORMAT(aiff)
FORMAT(al)
FORMAT(au)
FORMAT(avr)
FORMAT(cdr)
FORMAT(cvsd)
FORMAT(cvu)
FORMAT(dat)
FORMAT(dvms)
FORMAT(f4)
FORMAT(f8)
FORMAT(gsrt)
FORMAT(hcom)
FORMAT(htk)
FORMAT(ima)
FORMAT(la)
FORMAT(lu)
FORMAT(maud)
FORMAT(nul)
FORMAT(prc)
FORMAT(raw)
FORMAT(s1)
FORMAT(s2)
FORMAT(s3)
FORMAT(s4)
FORMAT(sf)
FORMAT(sln)
FORMAT(smp)
FORMAT(sounder)
FORMAT(soundtool)
FORMAT(sox)
FORMAT(sphere)
FORMAT(svx)
FORMAT(txw)
FORMAT(u1)
FORMAT(u2)
FORMAT(u3)
FORMAT(u4)
FORMAT(ul)
FORMAT(voc)
FORMAT(vox)
FORMAT(wav)
FORMAT(wve)
FORMAT(xa)
/*--------------------- Plugin or static format handlers ---------------------*/
#if defined HAVE_ALSA && (defined STATIC_ALSA || !defined HAVE_LIBLTDL)
FORMAT(alsa)
#endif
#if defined HAVE_AMRNB && (defined STATIC_AMRNB || !defined HAVE_LIBLTDL)
FORMAT(amr_nb)
#endif
#if defined HAVE_AMRWB && (defined STATIC_AMRWB || !defined HAVE_LIBLTDL)
FORMAT(amr_wb)
#endif
#if defined HAVE_AO && (defined STATIC_AO || !defined HAVE_LIBLTDL)
FORMAT(ao)
#endif
#if defined HAVE_COREAUDIO && (defined STATIC_COREAUDIO || !defined HAVE_LIBLTDL)
FORMAT(coreaudio)
#endif
#if defined HAVE_FLAC && (defined STATIC_FLAC || !defined HAVE_LIBLTDL)
FORMAT(flac)
#endif
#if defined HAVE_GSM && (defined STATIC_GSM || !defined HAVE_LIBLTDL)
FORMAT(gsm)
#endif
#if defined HAVE_LPC10 && (defined STATIC_LPC10 || !defined HAVE_LIBLTDL)
FORMAT(lpc10)
#endif
#if defined HAVE_MP3 && (defined STATIC_MP3 || !defined HAVE_LIBLTDL)
FORMAT(mp3)
#endif
#if defined HAVE_OPUS && (defined STATIC_OPUS || !defined HAVE_LIBLTDL)
FORMAT(opus)
#endif
#if defined HAVE_OSS && (defined STATIC_OSS || !defined HAVE_LIBLTDL)
FORMAT(oss)
#endif
#if defined HAVE_PULSEAUDIO && (defined STATIC_PULSEAUDIO || !defined HAVE_LIBLTDL)
FORMAT(pulseaudio)
#endif
#if defined HAVE_WAVEAUDIO && (defined STATIC_WAVEAUDIO || !defined HAVE_LIBLTDL)
FORMAT(waveaudio)
#endif
#if defined HAVE_SNDIO && (defined STATIC_SNDIO || !defined HAVE_LIBLTDL)
FORMAT(sndio)
#endif
#if defined HAVE_SNDFILE && (defined STATIC_SNDFILE || !defined HAVE_LIBLTDL)
FORMAT(sndfile)
FORMAT(caf)
FORMAT(fap)
FORMAT(mat4)
FORMAT(mat5)
FORMAT(paf)
FORMAT(pvf)
FORMAT(sd2)
FORMAT(w64)
FORMAT(xi)
#endif
#if defined HAVE_SUNAUDIO && (defined STATIC_SUNAUDIO || !defined HAVE_LIBLTDL)
FORMAT(sunau)
#endif
#if defined HAVE_OGGVORBIS && (defined STATIC_OGGVORBIS || !defined HAVE_LIBLTDL)
FORMAT(vorbis)
#endif
#if defined HAVE_WAVPACK && (defined STATIC_WAVPACK || !defined HAVE_LIBLTDL)
FORMAT(wavpack)
#endif

@ -0,0 +1,545 @@
/* Implements a libSoX internal interface for use in implementing file formats.
* All public functions & data are prefixed with lsx_ .
*
* (c) 2005-8 Chris Bagwell and SoX contributors
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
#include <string.h>
#include <sys/stat.h>
#include <stdarg.h>
void lsx_fail_errno(sox_format_t * ft, int sox_errno, const char *fmt, ...)
{
va_list args;
ft->sox_errno = sox_errno;
va_start(args, fmt);
#ifdef HAVE_VSNPRINTF
vsnprintf(ft->sox_errstr, sizeof(ft->sox_errstr), fmt, args);
#else
vsprintf(ft->sox_errstr, fmt, args);
#endif
va_end(args);
ft->sox_errstr[255] = '\0';
}
void lsx_set_signal_defaults(sox_format_t * ft)
{
if (!ft->signal.rate ) ft->signal.rate = SOX_DEFAULT_RATE;
if (!ft->signal.precision) ft->signal.precision = SOX_DEFAULT_PRECISION;
if (!ft->signal.channels ) ft->signal.channels = SOX_DEFAULT_CHANNELS;
if (!ft->encoding.bits_per_sample)
ft->encoding.bits_per_sample = ft->signal.precision;
if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN)
ft->encoding.encoding = SOX_ENCODING_SIGN2;
}
int lsx_check_read_params(sox_format_t * ft, unsigned channels,
sox_rate_t rate, sox_encoding_t encoding, unsigned bits_per_sample,
uint64_t num_samples, sox_bool check_length)
{
ft->signal.length = ft->signal.length == SOX_IGNORE_LENGTH? SOX_UNSPEC : num_samples;
if (ft->seekable)
ft->data_start = lsx_tell(ft);
if (channels && ft->signal.channels && ft->signal.channels != channels)
lsx_warn("`%s': overriding number of channels", ft->filename);
else ft->signal.channels = channels;
if (rate && ft->signal.rate && ft->signal.rate != rate)
lsx_warn("`%s': overriding sample rate", ft->filename);
else ft->signal.rate = rate;
if (encoding && ft->encoding.encoding && ft->encoding.encoding != encoding)
lsx_warn("`%s': overriding encoding type", ft->filename);
else ft->encoding.encoding = encoding;
if (bits_per_sample && ft->encoding.bits_per_sample && ft->encoding.bits_per_sample != bits_per_sample)
lsx_warn("`%s': overriding encoding size", ft->filename);
ft->encoding.bits_per_sample = bits_per_sample;
if (check_length && ft->encoding.bits_per_sample && lsx_filelength(ft)) {
uint64_t calculated_length = div_bits(lsx_filelength(ft) - ft->data_start, ft->encoding.bits_per_sample);
if (!ft->signal.length)
ft->signal.length = calculated_length;
else if (num_samples != calculated_length)
lsx_warn("`%s': file header gives the total number of samples as %" PRIu64 " but file length indicates the number is in fact %" PRIu64, ft->filename, num_samples, calculated_length);
}
if (sox_precision(ft->encoding.encoding, ft->encoding.bits_per_sample))
return SOX_SUCCESS;
lsx_fail_errno(ft, EINVAL, "invalid format for this file type");
return SOX_EOF;
}
/* Read in a buffer of data of length len bytes.
* Returns number of bytes read.
*/
size_t lsx_readbuf(sox_format_t * ft, void *buf, size_t len)
{
size_t ret = fread(buf, (size_t) 1, len, (FILE*)ft->fp);
if (ret != len && ferror((FILE*)ft->fp))
lsx_fail_errno(ft, errno, "lsx_readbuf");
ft->tell_off += ret;
return ret;
}
/* Skip input without seeking. */
int lsx_skipbytes(sox_format_t * ft, size_t n)
{
unsigned char trash;
while (n--)
if (lsx_readb(ft, &trash) == SOX_EOF)
return (SOX_EOF);
return (SOX_SUCCESS);
}
/* Pad output. */
int lsx_padbytes(sox_format_t * ft, size_t n)
{
while (n--)
if (lsx_writeb(ft, '\0') == SOX_EOF)
return (SOX_EOF);
return (SOX_SUCCESS);
}
/* Write a buffer of data of length bytes.
* Returns number of bytes written.
*/
size_t lsx_writebuf(sox_format_t * ft, void const * buf, size_t len)
{
size_t ret = fwrite(buf, (size_t) 1, len, (FILE*)ft->fp);
if (ret != len) {
lsx_fail_errno(ft, errno, "error writing output file");
clearerr((FILE*)ft->fp); /* Allows us to seek back to write header */
}
ft->tell_off += ret;
return ret;
}
sox_uint64_t lsx_filelength(sox_format_t * ft)
{
struct stat st;
int ret = ft->fp ? fstat(fileno((FILE*)ft->fp), &st) : 0;
return (!ret && (st.st_mode & S_IFREG))? (uint64_t)st.st_size : 0;
}
int lsx_flush(sox_format_t * ft)
{
return fflush((FILE*)ft->fp);
}
off_t lsx_tell(sox_format_t * ft)
{
return ft->seekable? (off_t)ftello((FILE*)ft->fp) : (off_t)ft->tell_off;
}
int lsx_eof(sox_format_t * ft)
{
return feof((FILE*)ft->fp);
}
int lsx_error(sox_format_t * ft)
{
return ferror((FILE*)ft->fp);
}
void lsx_rewind(sox_format_t * ft)
{
rewind((FILE*)ft->fp);
ft->tell_off = 0;
}
void lsx_clearerr(sox_format_t * ft)
{
clearerr((FILE*)ft->fp);
ft->sox_errno = 0;
}
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.
*
* N.B. Can only seek forwards on non-seekable streams!
*/
int lsx_seeki(sox_format_t * ft, off_t offset, int whence)
{
if (ft->seekable == 0) {
/* If a stream peel off chars else EPERM */
if (whence == SEEK_CUR) {
while (offset > 0 && !feof((FILE*)ft->fp)) {
getc((FILE*)ft->fp);
offset--;
++ft->tell_off;
}
if (offset)
lsx_fail_errno(ft,SOX_EOF, "offset past EOF");
else
ft->sox_errno = SOX_SUCCESS;
} else
lsx_fail_errno(ft,SOX_EPERM, "file not seekable");
} else {
if (fseeko((FILE*)ft->fp, offset, whence) == -1)
lsx_fail_errno(ft,errno, "%s", strerror(errno));
else
ft->sox_errno = SOX_SUCCESS;
}
return ft->sox_errno;
}
int lsx_offset_seek(sox_format_t * ft, off_t byte_offset, off_t to_sample)
{
double wide_sample = to_sample - (to_sample % ft->signal.channels);
double to_d = wide_sample * ft->encoding.bits_per_sample / 8;
off_t to = to_d;
return (to != to_d)? SOX_EOF : lsx_seeki(ft, (byte_offset + to), SEEK_SET);
}
/* Read and write known datatypes in "machine format". Swap if indicated.
* They all return SOX_EOF on error and SOX_SUCCESS on success.
*/
/* Read n-char string (and possibly null-terminating).
* Stop reading and null-terminate string if either a 0 or \n is reached.
*/
int lsx_reads(sox_format_t * ft, char *c, size_t len)
{
char *sc;
char in;
sc = c;
do
{
if (lsx_readbuf(ft, &in, (size_t)1) != 1)
{
*sc = 0;
return (SOX_EOF);
}
if (in == 0 || in == '\n')
break;
*sc = in;
sc++;
} while (sc - c < (ptrdiff_t)len);
*sc = 0;
return(SOX_SUCCESS);
}
/* Write null-terminated string (without \0). */
int lsx_writes(sox_format_t * ft, char const * c)
{
if (lsx_writebuf(ft, c, strlen(c)) != strlen(c))
return(SOX_EOF);
return(SOX_SUCCESS);
}
/* return swapped 32-bit float */
static void lsx_swapf(float * f)
{
union {
uint32_t dw;
float f;
} u;
u.f= *f;
u.dw= (u.dw>>24) | ((u.dw>>8)&0xff00) | ((u.dw<<8)&0xff0000) | (u.dw<<24);
*f = u.f;
}
static void swap(void * data, size_t len)
{
uint8_t * bytes = (uint8_t *)data;
size_t i;
for (i = 0; i < len / 2; ++i) {
char tmp = bytes[i];
bytes[i] = bytes[len - 1 - i];
bytes[len - 1 - i] = tmp;
}
}
static double lsx_swapdf(double data)
{
swap(&data, sizeof(data));
return data;
}
static uint64_t lsx_swapqw(uint64_t data)
{
swap(&data, sizeof(data));
return data;
}
/* Lookup table to reverse the bit order of a byte. ie MSB become LSB */
static uint8_t const cswap[256] = {
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0,
0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4,
0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC,
0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA,
0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6,
0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1,
0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9,
0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD,
0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3,
0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7,
0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF,
0x3F, 0xBF, 0x7F, 0xFF
};
/* Utilities to byte-swap values, use libc optimized macros if possible */
#define TWIDDLE_BYTE(ub, type) \
do { \
if (ft->encoding.reverse_bits) \
ub = cswap[ub]; \
if (ft->encoding.reverse_nibbles) \
ub = ((ub & 15) << 4) | (ub >> 4); \
} while (0);
#define TWIDDLE_WORD(uw, type) \
if (ft->encoding.reverse_bytes) \
uw = lsx_swap ## type(uw);
#define TWIDDLE_FLOAT(f, type) \
if (ft->encoding.reverse_bytes) \
lsx_swapf(&f);
/* N.B. This macro doesn't work for unaligned types (e.g. 3-byte
types). */
#define READ_FUNC(type, size, ctype, twiddle) \
size_t lsx_read_ ## type ## _buf( \
sox_format_t * ft, ctype *buf, size_t len) \
{ \
size_t n, nread; \
nread = lsx_readbuf(ft, buf, len * size) / size; \
for (n = 0; n < nread; n++) \
twiddle(buf[n], type); \
return nread; \
}
/* Unpack a 3-byte value from a uint8_t * */
#define sox_unpack3(p) (ft->encoding.reverse_bytes == MACHINE_IS_BIGENDIAN? \
((p)[0] | ((p)[1] << 8) | ((p)[2] << 16)) : \
((p)[2] | ((p)[1] << 8) | ((p)[0] << 16)))
/* This (slower) macro works for unaligned types (e.g. 3-byte types)
that need to be unpacked. */
#define READ_FUNC_UNPACK(type, size, ctype, twiddle) \
size_t lsx_read_ ## type ## _buf( \
sox_format_t * ft, ctype *buf, size_t len) \
{ \
size_t n, nread; \
uint8_t *data = lsx_malloc(size * len); \
nread = lsx_readbuf(ft, data, len * size) / size; \
for (n = 0; n < nread; n++) \
buf[n] = sox_unpack ## size(data + n * size); \
free(data); \
return n; \
}
READ_FUNC(b, 1, uint8_t, TWIDDLE_BYTE)
READ_FUNC(w, 2, uint16_t, TWIDDLE_WORD)
READ_FUNC_UNPACK(3, 3, sox_uint24_t, TWIDDLE_WORD)
READ_FUNC(dw, 4, uint32_t, TWIDDLE_WORD)
READ_FUNC(qw, 8, uint64_t, TWIDDLE_WORD)
READ_FUNC(f, sizeof(float), float, TWIDDLE_FLOAT)
READ_FUNC(df, sizeof(double), double, TWIDDLE_WORD)
#define READ1_FUNC(type, ctype) \
int lsx_read ## type(sox_format_t * ft, ctype * datum) { \
if (lsx_read_ ## type ## _buf(ft, datum, (size_t)1) == 1) \
return SOX_SUCCESS; \
if (!lsx_error(ft)) \
lsx_fail_errno(ft, errno, premature_eof); \
return SOX_EOF; \
}
static char const premature_eof[] = "premature EOF";
READ1_FUNC(b, uint8_t)
READ1_FUNC(w, uint16_t)
READ1_FUNC(3, sox_uint24_t)
READ1_FUNC(dw, uint32_t)
READ1_FUNC(qw, uint64_t)
READ1_FUNC(f, float)
READ1_FUNC(df, double)
int lsx_readchars(sox_format_t * ft, char * chars, size_t len)
{
size_t ret = lsx_readbuf(ft, chars, len);
if (ret == len)
return SOX_SUCCESS;
if (!lsx_error(ft))
lsx_fail_errno(ft, errno, premature_eof);
return SOX_EOF;
}
int lsx_read_fields(sox_format_t *ft, uint32_t *len, const char *spec, ...)
{
int err = SOX_SUCCESS;
va_list ap;
#define do_read(type, f, n) do { \
size_t nr; \
if (*len < n * sizeof(type)) { \
err = SOX_EOF; \
goto end; \
} \
nr = lsx_read_##f##_buf(ft, va_arg(ap, type *), r); \
if (nr != n) \
err = SOX_EOF; \
*len -= nr * sizeof(type); \
} while (0)
va_start(ap, spec);
while (*spec) {
unsigned long r = 1;
char c = *spec;
if (c >= '0' && c <= '9') {
char *next;
r = strtoul(spec, &next, 10);
spec = next;
c = *spec;
} else if (c == '*') {
r = va_arg(ap, int);
c = *++spec;
}
switch (c) {
case 'b': do_read(uint8_t, b, r); break;
case 'h': do_read(uint16_t, w, r); break;
case 'i': do_read(uint32_t, dw, r); break;
case 'q': do_read(uint64_t, qw, r); break;
case 'x': err = lsx_skipbytes(ft, r); break;
default:
lsx_fail("lsx_read_fields: invalid format character '%c'", c);
err = SOX_EOF;
break;
}
if (err)
break;
spec++;
}
end:
va_end(ap);
#undef do_read
return err;
}
/* N.B. This macro doesn't work for unaligned types (e.g. 3-byte
types). */
#define WRITE_FUNC(type, size, ctype, twiddle) \
size_t lsx_write_ ## type ## _buf( \
sox_format_t * ft, ctype *buf, size_t len) \
{ \
size_t n, nwritten; \
for (n = 0; n < len; n++) \
twiddle(buf[n], type); \
nwritten = lsx_writebuf(ft, buf, len * size); \
return nwritten / size; \
}
/* Pack a 3-byte value to a uint8_t * */
#define sox_pack3(p, v) do {if (ft->encoding.reverse_bytes == MACHINE_IS_BIGENDIAN)\
{(p)[0] = v & 0xff; (p)[1] = (v >> 8) & 0xff; (p)[2] = (v >> 16) & 0xff;} else \
{(p)[2] = v & 0xff; (p)[1] = (v >> 8) & 0xff; (p)[0] = (v >> 16) & 0xff;} \
} while (0)
/* This (slower) macro works for unaligned types (e.g. 3-byte types)
that need to be packed. */
#define WRITE_FUNC_PACK(type, size, ctype, twiddle) \
size_t lsx_write_ ## type ## _buf( \
sox_format_t * ft, ctype *buf, size_t len) \
{ \
size_t n, nwritten; \
uint8_t *data = lsx_malloc(size * len); \
for (n = 0; n < len; n++) \
sox_pack ## size(data + n * size, buf[n]); \
nwritten = lsx_writebuf(ft, data, len * size); \
free(data); \
return nwritten / size; \
}
WRITE_FUNC(b, 1, uint8_t, TWIDDLE_BYTE)
WRITE_FUNC(w, 2, uint16_t, TWIDDLE_WORD)
WRITE_FUNC_PACK(3, 3, sox_uint24_t, TWIDDLE_WORD)
WRITE_FUNC(dw, 4, uint32_t, TWIDDLE_WORD)
WRITE_FUNC(qw, 8, uint64_t, TWIDDLE_WORD)
WRITE_FUNC(f, sizeof(float), float, TWIDDLE_FLOAT)
WRITE_FUNC(df, sizeof(double), double, TWIDDLE_WORD)
#define WRITE1U_FUNC(type, ctype) \
int lsx_write ## type(sox_format_t * ft, unsigned d) \
{ ctype datum = (ctype)d; \
return lsx_write_ ## type ## _buf(ft, &datum, (size_t)1) == 1 ? SOX_SUCCESS : SOX_EOF; \
}
#define WRITE1S_FUNC(type, ctype) \
int lsx_writes ## type(sox_format_t * ft, signed d) \
{ ctype datum = (ctype)d; \
return lsx_write_ ## type ## _buf(ft, &datum, (size_t)1) == 1 ? SOX_SUCCESS : SOX_EOF; \
}
#define WRITE1_FUNC(type, ctype) \
int lsx_write ## type(sox_format_t * ft, ctype datum) \
{ \
return lsx_write_ ## type ## _buf(ft, &datum, (size_t)1) == 1 ? SOX_SUCCESS : SOX_EOF; \
}
WRITE1U_FUNC(b, uint8_t)
WRITE1U_FUNC(w, uint16_t)
WRITE1U_FUNC(3, sox_uint24_t)
WRITE1U_FUNC(dw, uint32_t)
WRITE1_FUNC(qw, uint64_t)
WRITE1S_FUNC(b, uint8_t)
WRITE1S_FUNC(w, uint16_t)
WRITE1_FUNC(df, double)
int lsx_writef(sox_format_t * ft, double datum)
{
float f = datum;
return lsx_write_f_buf(ft, &f, (size_t) 1) == 1 ? SOX_SUCCESS : SOX_EOF;
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,21 @@
/* libSoX G711.h - include for G711 u-law and a-law conversion routines
*
* Copyright (C) 2001 Chris Bagwell
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation. This software is provided "as is" without express or
* implied warranty.
*/
extern const uint8_t lsx_13linear2alaw[0x2000];
extern const int16_t lsx_alaw2linear16[256];
#define sox_13linear2alaw(sw) (lsx_13linear2alaw[((sw) + 0x1000)])
#define sox_alaw2linear16(uc) (lsx_alaw2linear16[uc])
extern const uint8_t lsx_14linear2ulaw[0x4000];
extern const int16_t lsx_ulaw2linear16[256];
#define sox_14linear2ulaw(sw) (lsx_14linear2ulaw[((sw) + 0x2000)])
#define sox_ulaw2linear16(uc) (lsx_ulaw2linear16[uc])

@ -0,0 +1,167 @@
/* This source code is a product of Sun Microsystems, Inc. and is provided
* for unrestricted use. Users may copy or modify this source code without
* charge.
*
* SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun source code is provided with no support and without any obligation on
* the part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
/*
* g721.c
*
* Description:
*
* g721_encoder(), g721_decoder()
*
* These routines comprise an implementation of the CCITT G.721 ADPCM
* coding algorithm. Essentially, this implementation is identical to
* the bit level description except for a few deviations which
* take advantage of work station attributes, such as hardware 2's
* complement arithmetic and large memory. Specifically, certain time
* consuming operations such as multiplications are replaced
* with lookup tables and software 2's complement operations are
* replaced with hardware 2's complement.
*
* The deviation from the bit level specification (lookup tables)
* preserves the bit level performance specifications.
*
* As outlined in the G.721 Recommendation, the algorithm is broken
* down into modules. Each section of code below is preceded by
* the name of the module which it is implementing.
*
*/
#include "sox_i.h"
#include "g72x.h"
#include "g711.h"
static const short qtab_721[7] = {-124, 80, 178, 246, 300, 349, 400};
/*
* Maps G.721 code word to reconstructed scale factor normalized log
* magnitude values.
*/
static const short _dqlntab[16] = {-2048, 4, 135, 213, 273, 323, 373, 425,
425, 373, 323, 273, 213, 135, 4, -2048};
/* Maps G.721 code word to log of scale factor multiplier. */
static const short _witab[16] = {-12, 18, 41, 64, 112, 198, 355, 1122,
1122, 355, 198, 112, 64, 41, 18, -12};
/*
* Maps G.721 code words to a set of values whose long and short
* term averages are computed and then compared to give an indication
* how stationary (steady state) the signal is.
*/
static const short _fitab[16] = {0, 0, 0, 0x200, 0x200, 0x200, 0x600, 0xE00,
0xE00, 0x600, 0x200, 0x200, 0x200, 0, 0, 0};
/*
* g721_encoder()
*
* Encodes the input vale of linear PCM, A-law or u-law data sl and returns
* the resulting code. -1 is returned for unknown input coding value.
*/
int g721_encoder(int sl, int in_coding, struct g72x_state *state_ptr)
{
short sezi, se, sez; /* ACCUM */
short d; /* SUBTA */
short sr; /* ADDB */
short y; /* MIX */
short dqsez; /* ADDC */
short dq, i;
switch (in_coding) { /* linearize input sample to 14-bit PCM */
case AUDIO_ENCODING_ALAW:
sl = sox_alaw2linear16(sl) >> 2;
break;
case AUDIO_ENCODING_ULAW:
sl = sox_ulaw2linear16(sl) >> 2;
break;
case AUDIO_ENCODING_LINEAR:
sl >>= 2; /* 14-bit dynamic range */
break;
default:
return (-1);
}
sezi = predictor_zero(state_ptr);
sez = sezi >> 1;
se = (sezi + predictor_pole(state_ptr)) >> 1; /* estimated signal */
d = sl - se; /* estimation difference */
/* quantize the prediction difference */
y = step_size(state_ptr); /* quantizer step size */
i = quantize(d, y, qtab_721, 7); /* i = ADPCM code */
dq = reconstruct(i & 8, _dqlntab[i], y); /* quantized est diff */
sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq; /* reconst. signal */
dqsez = sr + sez - se; /* pole prediction diff. */
update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr);
return (i);
}
/*
* g721_decoder()
*
* Description:
*
* Decodes a 4-bit code of G.721 encoded data of i and
* returns the resulting linear PCM, A-law or u-law value.
* return -1 for unknown out_coding value.
*/
int g721_decoder(int i, int out_coding, struct g72x_state *state_ptr)
{
short sezi, sei, sez, se; /* ACCUM */
short y; /* MIX */
short sr; /* ADDB */
short dq;
short dqsez;
i &= 0x0f; /* mask to get proper bits */
sezi = predictor_zero(state_ptr);
sez = sezi >> 1;
sei = sezi + predictor_pole(state_ptr);
se = sei >> 1; /* se = estimated signal */
y = step_size(state_ptr); /* dynamic quantizer step size */
dq = reconstruct(i & 0x08, _dqlntab[i], y); /* quantized diff. */
sr = (dq < 0) ? (se - (dq & 0x3FFF)) : se + dq; /* reconst. signal */
dqsez = sr - se + sez; /* pole prediction diff. */
update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr);
switch (out_coding) {
case AUDIO_ENCODING_ALAW:
return (tandem_adjust_alaw(sr, se, y, i, 8, qtab_721));
case AUDIO_ENCODING_ULAW:
return (tandem_adjust_ulaw(sr, se, y, i, 8, qtab_721));
case AUDIO_ENCODING_LINEAR:
return (sr << 2); /* sr was 14-bit dynamic range */
default:
return (-1);
}
}

@ -0,0 +1,151 @@
/* This source code is a product of Sun Microsystems, Inc. and is provided
* for unrestricted use. Users may copy or modify this source code without
* charge.
*
* SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun source code is provided with no support and without any obligation on
* the part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
/*
* g723_24.c
*
* Description:
*
* g723_24_encoder(), g723_24_decoder()
*
* These routines comprise an implementation of the CCITT G.723 24 Kbps
* ADPCM coding algorithm. Essentially, this implementation is identical to
* the bit level description except for a few deviations which take advantage
* of workstation attributes, such as hardware 2's complement arithmetic.
*
*/
#include "sox_i.h"
#include "g711.h"
#include "g72x.h"
/*
* Maps G.723_24 code word to reconstructed scale factor normalized log
* magnitude values.
*/
static const short _dqlntab[8] = {-2048, 135, 273, 373, 373, 273, 135, -2048};
/* Maps G.723_24 code word to log of scale factor multiplier. */
static const short _witab[8] = {-128, 960, 4384, 18624, 18624, 4384, 960, -128};
/*
* Maps G.723_24 code words to a set of values whose long and short
* term averages are computed and then compared to give an indication
* how stationary (steady state) the signal is.
*/
static const short _fitab[8] = {0, 0x200, 0x400, 0xE00, 0xE00, 0x400, 0x200, 0};
static const short qtab_723_24[3] = {8, 218, 331};
/*
* g723_24_encoder()
*
* Encodes a linear PCM, A-law or u-law input sample and returns its 3-bit code.
* Returns -1 if invalid input coding value.
*/
int g723_24_encoder(int sl, int in_coding, struct g72x_state *state_ptr)
{
short sei, sezi, se, sez; /* ACCUM */
short d; /* SUBTA */
short y; /* MIX */
short sr; /* ADDB */
short dqsez; /* ADDC */
short dq, i;
switch (in_coding) { /* linearize input sample to 14-bit PCM */
case AUDIO_ENCODING_ALAW:
sl = sox_alaw2linear16(sl) >> 2;
break;
case AUDIO_ENCODING_ULAW:
sl = sox_ulaw2linear16(sl) >> 2;
break;
case AUDIO_ENCODING_LINEAR:
sl >>= 2; /* sl of 14-bit dynamic range */
break;
default:
return (-1);
}
sezi = predictor_zero(state_ptr);
sez = sezi >> 1;
sei = sezi + predictor_pole(state_ptr);
se = sei >> 1; /* se = estimated signal */
d = sl - se; /* d = estimation diff. */
/* quantize prediction difference d */
y = step_size(state_ptr); /* quantizer step size */
i = quantize(d, y, qtab_723_24, 3); /* i = ADPCM code */
dq = reconstruct(i & 4, _dqlntab[i], y); /* quantized diff. */
sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq; /* reconstructed signal */
dqsez = sr + sez - se; /* pole prediction diff. */
update(3, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr);
return (i);
}
/*
* g723_24_decoder()
*
* Decodes a 3-bit CCITT G.723_24 ADPCM code and returns
* the resulting 16-bit linear PCM, A-law or u-law sample value.
* -1 is returned if the output coding is unknown.
*/
int g723_24_decoder(int i, int out_coding, struct g72x_state *state_ptr)
{
short sezi, sei, sez, se; /* ACCUM */
short y; /* MIX */
short sr; /* ADDB */
short dq;
short dqsez;
i &= 0x07; /* mask to get proper bits */
sezi = predictor_zero(state_ptr);
sez = sezi >> 1;
sei = sezi + predictor_pole(state_ptr);
se = sei >> 1; /* se = estimated signal */
y = step_size(state_ptr); /* adaptive quantizer step size */
dq = reconstruct(i & 0x04, _dqlntab[i], y); /* unquantize pred diff */
sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); /* reconst. signal */
dqsez = sr - se + sez; /* pole prediction diff. */
update(3, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr);
switch (out_coding) {
case AUDIO_ENCODING_ALAW:
return (tandem_adjust_alaw(sr, se, y, i, 4, qtab_723_24));
case AUDIO_ENCODING_ULAW:
return (tandem_adjust_ulaw(sr, se, y, i, 4, qtab_723_24));
case AUDIO_ENCODING_LINEAR:
return (sr << 2); /* sr was of 14-bit dynamic range */
default:
return (-1);
}
}

@ -0,0 +1,171 @@
/* This source code is a product of Sun Microsystems, Inc. and is provided
* for unrestricted use. Users may copy or modify this source code without
* charge.
*
* SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun source code is provided with no support and without any obligation on
* the part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
/*
* g723_40.c
*
* Description:
*
* g723_40_encoder(), g723_40_decoder()
*
* These routines comprise an implementation of the CCITT G.723 40Kbps
* ADPCM coding algorithm. Essentially, this implementation is identical to
* the bit level description except for a few deviations which
* take advantage of workstation attributes, such as hardware 2's
* complement arithmetic.
*
* The deviation from the bit level specification (lookup tables),
* preserves the bit level performance specifications.
*
* As outlined in the G.723 Recommendation, the algorithm is broken
* down into modules. Each section of code below is preceded by
* the name of the module which it is implementing.
*
*/
#include "sox_i.h"
#include "g711.h"
#include "g72x.h"
/*
* Maps G.723_40 code word to ructeconstructed scale factor normalized log
* magnitude values.
*/
static const short _dqlntab[32] = {-2048, -66, 28, 104, 169, 224, 274, 318,
358, 395, 429, 459, 488, 514, 539, 566,
566, 539, 514, 488, 459, 429, 395, 358,
318, 274, 224, 169, 104, 28, -66, -2048};
/* Maps G.723_40 code word to log of scale factor multiplier. */
static const short _witab[32] = {448, 448, 768, 1248, 1280, 1312, 1856, 3200,
4512, 5728, 7008, 8960, 11456, 14080, 16928, 22272,
22272, 16928, 14080, 11456, 8960, 7008, 5728, 4512,
3200, 1856, 1312, 1280, 1248, 768, 448, 448};
/*
* Maps G.723_40 code words to a set of values whose long and short
* term averages are computed and then compared to give an indication
* how stationary (steady state) the signal is.
*/
static const short _fitab[32] = {0, 0, 0, 0, 0, 0x200, 0x200, 0x200,
0x200, 0x200, 0x400, 0x600, 0x800, 0xA00, 0xC00, 0xC00,
0xC00, 0xC00, 0xA00, 0x800, 0x600, 0x400, 0x200, 0x200,
0x200, 0x200, 0x200, 0, 0, 0, 0, 0};
static const short qtab_723_40[15] = {-122, -16, 68, 139, 198, 250, 298, 339,
378, 413, 445, 475, 502, 528, 553};
/*
* g723_40_encoder()
*
* Encodes a 16-bit linear PCM, A-law or u-law input sample and retuens
* the resulting 5-bit CCITT G.723 40Kbps code.
* Returns -1 if the input coding value is invalid.
*/
int g723_40_encoder(int sl, int in_coding, struct g72x_state *state_ptr)
{
short sei, sezi, se, sez; /* ACCUM */
short d; /* SUBTA */
short y; /* MIX */
short sr; /* ADDB */
short dqsez; /* ADDC */
short dq, i;
switch (in_coding) { /* linearize input sample to 14-bit PCM */
case AUDIO_ENCODING_ALAW:
sl = sox_alaw2linear16(sl) >> 2;
break;
case AUDIO_ENCODING_ULAW:
sl = sox_ulaw2linear16(sl) >> 2;
break;
case AUDIO_ENCODING_LINEAR:
sl >>= 2; /* sl of 14-bit dynamic range */
break;
default:
return (-1);
}
sezi = predictor_zero(state_ptr);
sez = sezi >> 1;
sei = sezi + predictor_pole(state_ptr);
se = sei >> 1; /* se = estimated signal */
d = sl - se; /* d = estimation difference */
/* quantize prediction difference */
y = step_size(state_ptr); /* adaptive quantizer step size */
i = quantize(d, y, qtab_723_40, 15); /* i = ADPCM code */
dq = reconstruct(i & 0x10, _dqlntab[i], y); /* quantized diff */
sr = (dq < 0) ? se - (dq & 0x7FFF) : se + dq; /* reconstructed signal */
dqsez = sr + sez - se; /* dqsez = pole prediction diff. */
update(5, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr);
return (i);
}
/*
* g723_40_decoder()
*
* Decodes a 5-bit CCITT G.723 40Kbps code and returns
* the resulting 16-bit linear PCM, A-law or u-law sample value.
* -1 is returned if the output coding is unknown.
*/
int g723_40_decoder(int i, int out_coding, struct g72x_state *state_ptr)
{
short sezi, sei, sez, se; /* ACCUM */
short y; /* MIX */
short sr; /* ADDB */
short dq;
short dqsez;
i &= 0x1f; /* mask to get proper bits */
sezi = predictor_zero(state_ptr);
sez = sezi >> 1;
sei = sezi + predictor_pole(state_ptr);
se = sei >> 1; /* se = estimated signal */
y = step_size(state_ptr); /* adaptive quantizer step size */
dq = reconstruct(i & 0x10, _dqlntab[i], y); /* estimation diff. */
sr = (dq < 0) ? (se - (dq & 0x7FFF)) : (se + dq); /* reconst. signal */
dqsez = sr - se + sez; /* pole prediction diff. */
update(5, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr);
switch (out_coding) {
case AUDIO_ENCODING_ALAW:
return (tandem_adjust_alaw(sr, se, y, i, 0x10, qtab_723_40));
case AUDIO_ENCODING_ULAW:
return (tandem_adjust_ulaw(sr, se, y, i, 0x10, qtab_723_40));
case AUDIO_ENCODING_LINEAR:
return (sr << 2); /* sr was of 14-bit dynamic range */
default:
return (-1);
}
}

@ -0,0 +1,575 @@
/* Common routines for G.721 and G.723 conversions.
*
* (c) SoX Contributors
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*
* This code is based on code from Sun, which came with the following
* copyright notice:
* -----------------------------------------------------------------------
* This source code is a product of Sun Microsystems, Inc. and is provided
* for unrestricted use. Users may copy or modify this source code without
* charge.
*
* SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun source code is provided with no support and without any obligation on
* the part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
* -----------------------------------------------------------------------
*/
#include "sox_i.h"
#include "g711.h"
#include "g72x.h"
static const char LogTable256[] =
{
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
};
static inline int log2plus1(int val)
{
/* From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup */
unsigned int v = (unsigned int)val; /* 32-bit word to find the log of */
unsigned r; /* r will be lg(v) */
register unsigned int t, tt; /* temporaries */
if ((tt = v >> 16))
{
r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
}
else
{
r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
}
return r + 1;
}
/*
* quan()
*
* quantizes the input val against the table of size short integers.
* It returns i if table[i - 1] <= val < table[i].
*
* Using linear search for simple coding.
*/
static int quan(int val, short const *table, int size)
{
int i;
for (i = 0; i < size; i++)
if (val < *table++)
break;
return (i);
}
/*
* fmult()
*
* returns the integer product of the 14-bit integer "an" and
* "floating point" representation (4-bit exponent, 6-bit mantessa) "srn".
*/
static int fmult(int an, int srn)
{
short anmag, anexp, anmant;
short wanexp, wanmant;
short retval;
anmag = (an > 0) ? an : ((-an) & 0x1FFF);
anexp = log2plus1(anmag) - 6;
anmant = (anmag == 0) ? 32 :
(anexp >= 0) ? anmag >> anexp : anmag << -anexp;
wanexp = anexp + ((srn >> 6) & 0xF) - 13;
wanmant = (anmant * (srn & 077) + 0x30) >> 4;
retval = (wanexp >= 0) ? ((wanmant << wanexp) & 0x7FFF) :
(wanmant >> -wanexp);
return (((an ^ srn) < 0) ? -retval : retval);
}
/*
* g72x_init_state()
*
* This routine initializes and/or resets the g72x_state structure
* pointed to by 'state_ptr'.
* All the initial state values are specified in the CCITT G.721 document.
*/
void g72x_init_state(struct g72x_state *state_ptr)
{
int cnta;
state_ptr->yl = 34816;
state_ptr->yu = 544;
state_ptr->dms = 0;
state_ptr->dml = 0;
state_ptr->ap = 0;
for (cnta = 0; cnta < 2; cnta++) {
state_ptr->a[cnta] = 0;
state_ptr->pk[cnta] = 0;
state_ptr->sr[cnta] = 32;
}
for (cnta = 0; cnta < 6; cnta++) {
state_ptr->b[cnta] = 0;
state_ptr->dq[cnta] = 32;
}
state_ptr->td = 0;
}
/*
* predictor_zero()
*
* computes the estimated signal from 6-zero predictor.
*
*/
int predictor_zero(struct g72x_state *state_ptr)
{
int i;
int sezi;
sezi = fmult(state_ptr->b[0] >> 2, state_ptr->dq[0]);
for (i = 1; i < 6; i++) /* ACCUM */
sezi += fmult(state_ptr->b[i] >> 2, state_ptr->dq[i]);
return (sezi);
}
/*
* predictor_pole()
*
* computes the estimated signal from 2-pole predictor.
*
*/
int predictor_pole(struct g72x_state *state_ptr)
{
return (fmult(state_ptr->a[1] >> 2, state_ptr->sr[1]) +
fmult(state_ptr->a[0] >> 2, state_ptr->sr[0]));
}
/*
* step_size()
*
* computes the quantization step size of the adaptive quantizer.
*
*/
int step_size(struct g72x_state *state_ptr)
{
int y;
int dif;
int al;
if (state_ptr->ap >= 256)
return (state_ptr->yu);
else {
y = state_ptr->yl >> 6;
dif = state_ptr->yu - y;
al = state_ptr->ap >> 2;
if (dif > 0)
y += (dif * al) >> 6;
else if (dif < 0)
y += (dif * al + 0x3F) >> 6;
return (y);
}
}
/*
* quantize()
*
* Given a raw sample, 'd', of the difference signal and a
* quantization step size scale factor, 'y', this routine returns the
* ADPCM codeword to which that sample gets quantized. The step
* size scale factor division operation is done in the log base 2 domain
* as a subtraction.
*/
int quantize(int d, int y, short const *table, int size)
{
short dqm; /* Magnitude of 'd' */
short exp; /* Integer part of base 2 log of 'd' */
short mant; /* Fractional part of base 2 log */
short dl; /* Log of magnitude of 'd' */
short dln; /* Step size scale factor normalized log */
int i;
/*
* LOG
*
* Compute base 2 log of 'd', and store in 'dl'.
*/
dqm = abs(d);
exp = log2plus1(dqm >> 1);
mant = ((dqm << 7) >> exp) & 0x7F; /* Fractional portion. */
dl = (exp << 7) + mant;
/*
* SUBTB
*
* "Divide" by step size multiplier.
*/
dln = dl - (y >> 2);
/*
* QUAN
*
* Obtain codword i for 'd'.
*/
i = quan(dln, table, size);
if (d < 0) /* take 1's complement of i */
return ((size << 1) + 1 - i);
else if (i == 0) /* take 1's complement of 0 */
return ((size << 1) + 1); /* new in 1988 */
else
return (i);
}
/*
* reconstruct()
*
* Returns reconstructed difference signal 'dq' obtained from
* codeword 'i' and quantization step size scale factor 'y'.
* Multiplication is performed in log base 2 domain as addition.
*/
int reconstruct(int sign, int dqln, int y)
{
short dql; /* Log of 'dq' magnitude */
short dex; /* Integer part of log */
short dqt;
short dq; /* Reconstructed difference signal sample */
dql = dqln + (y >> 2); /* ADDA */
if (dql < 0) {
return ((sign) ? -0x8000 : 0);
} else { /* ANTILOG */
dex = (dql >> 7) & 15;
dqt = 128 + (dql & 127);
dq = (dqt << 7) >> (14 - dex);
return ((sign) ? (dq - 0x8000) : dq);
}
}
/*
* update()
*
* updates the state variables for each output code
*/
void update(int code_size, int y, int wi, int fi, int dq, int sr,
int dqsez, struct g72x_state *state_ptr)
{
int cnt;
short mag, exp; /* Adaptive predictor, FLOAT A */
short a2p=0; /* LIMC */
short a1ul; /* UPA1 */
short pks1; /* UPA2 */
short fa1;
char tr; /* tone/transition detector */
short ylint, thr2, dqthr;
short ylfrac, thr1;
short pk0;
pk0 = (dqsez < 0) ? 1 : 0; /* needed in updating predictor poles */
mag = dq & 0x7FFF; /* prediction difference magnitude */
/* TRANS */
ylint = state_ptr->yl >> 15; /* exponent part of yl */
ylfrac = (state_ptr->yl >> 10) & 0x1F; /* fractional part of yl */
thr1 = (32 + ylfrac) << ylint; /* threshold */
thr2 = (ylint > 9) ? 31 << 10 : thr1; /* limit thr2 to 31 << 10 */
dqthr = (thr2 + (thr2 >> 1)) >> 1; /* dqthr = 0.75 * thr2 */
if (state_ptr->td == 0) /* signal supposed voice */
tr = 0;
else if (mag <= dqthr) /* supposed data, but small mag */
tr = 0; /* treated as voice */
else /* signal is data (modem) */
tr = 1;
/*
* Quantizer scale factor adaptation.
*/
/* FUNCTW & FILTD & DELAY */
/* update non-steady state step size multiplier */
state_ptr->yu = y + ((wi - y) >> 5);
/* LIMB */
if (state_ptr->yu < 544) /* 544 <= yu <= 5120 */
state_ptr->yu = 544;
else if (state_ptr->yu > 5120)
state_ptr->yu = 5120;
/* FILTE & DELAY */
/* update steady state step size multiplier */
state_ptr->yl += state_ptr->yu + ((-state_ptr->yl) >> 6);
/*
* Adaptive predictor coefficients.
*/
if (tr == 1) { /* reset a's and b's for modem signal */
state_ptr->a[0] = 0;
state_ptr->a[1] = 0;
state_ptr->b[0] = 0;
state_ptr->b[1] = 0;
state_ptr->b[2] = 0;
state_ptr->b[3] = 0;
state_ptr->b[4] = 0;
state_ptr->b[5] = 0;
} else { /* update a's and b's */
pks1 = pk0 ^ state_ptr->pk[0]; /* UPA2 */
/* update predictor pole a[1] */
a2p = state_ptr->a[1] - (state_ptr->a[1] >> 7);
if (dqsez != 0) {
fa1 = (pks1) ? state_ptr->a[0] : -state_ptr->a[0];
if (fa1 < -8191) /* a2p = function of fa1 */
a2p -= 0x100;
else if (fa1 > 8191)
a2p += 0xFF;
else
a2p += fa1 >> 5;
if (pk0 ^ state_ptr->pk[1])
{
/* LIMC */
if (a2p <= -12160)
a2p = -12288;
else if (a2p >= 12416)
a2p = 12288;
else
a2p -= 0x80;
}
else if (a2p <= -12416)
a2p = -12288;
else if (a2p >= 12160)
a2p = 12288;
else
a2p += 0x80;
}
/* Possible bug: a2p not initialized if dqsez == 0) */
/* TRIGB & DELAY */
state_ptr->a[1] = a2p;
/* UPA1 */
/* update predictor pole a[0] */
state_ptr->a[0] -= state_ptr->a[0] >> 8;
if (dqsez != 0)
{
if (pks1 == 0)
state_ptr->a[0] += 192;
else
state_ptr->a[0] -= 192;
}
/* LIMD */
a1ul = 15360 - a2p;
if (state_ptr->a[0] < -a1ul)
state_ptr->a[0] = -a1ul;
else if (state_ptr->a[0] > a1ul)
state_ptr->a[0] = a1ul;
/* UPB : update predictor zeros b[6] */
for (cnt = 0; cnt < 6; cnt++) {
if (code_size == 5) /* for 40Kbps G.723 */
state_ptr->b[cnt] -= state_ptr->b[cnt] >> 9;
else /* for G.721 and 24Kbps G.723 */
state_ptr->b[cnt] -= state_ptr->b[cnt] >> 8;
if (dq & 0x7FFF) { /* XOR */
if ((dq ^ state_ptr->dq[cnt]) >= 0)
state_ptr->b[cnt] += 128;
else
state_ptr->b[cnt] -= 128;
}
}
}
for (cnt = 5; cnt > 0; cnt--)
state_ptr->dq[cnt] = state_ptr->dq[cnt-1];
/* FLOAT A : convert dq[0] to 4-bit exp, 6-bit mantissa f.p. */
if (mag == 0) {
state_ptr->dq[0] = (dq >= 0) ? 0x20 : (short)(unsigned short)0xFC20;
} else {
exp = log2plus1(mag);
state_ptr->dq[0] = (dq >= 0) ?
(exp << 6) + ((mag << 6) >> exp) :
(exp << 6) + ((mag << 6) >> exp) - 0x400;
}
state_ptr->sr[1] = state_ptr->sr[0];
/* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */
if (sr == 0) {
state_ptr->sr[0] = 0x20;
} else if (sr > 0) {
exp = log2plus1(sr);
state_ptr->sr[0] = (exp << 6) + ((sr << 6) >> exp);
} else if (sr > -32768) {
mag = -sr;
exp = log2plus1(mag);
state_ptr->sr[0] = (exp << 6) + ((mag << 6) >> exp) - 0x400;
} else
state_ptr->sr[0] = (short)(unsigned short)0xFC20;
/* DELAY A */
state_ptr->pk[1] = state_ptr->pk[0];
state_ptr->pk[0] = pk0;
/* TONE */
if (tr == 1) /* this sample has been treated as data */
state_ptr->td = 0; /* next one will be treated as voice */
else if (a2p < -11776) /* small sample-to-sample correlation */
state_ptr->td = 1; /* signal may be data */
else /* signal is voice */
state_ptr->td = 0;
/*
* Adaptation speed control.
*/
state_ptr->dms += (fi - state_ptr->dms) >> 5; /* FILTA */
state_ptr->dml += (((fi << 2) - state_ptr->dml) >> 7); /* FILTB */
if (tr == 1)
state_ptr->ap = 256;
else if (y < 1536) /* SUBTC */
state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
else if (state_ptr->td == 1)
state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
else if (abs((state_ptr->dms << 2) - state_ptr->dml) >=
(state_ptr->dml >> 3))
state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
else
state_ptr->ap += (-state_ptr->ap) >> 4;
}
/*
* tandem_adjust(sr, se, y, i, sign)
*
* At the end of ADPCM decoding, it simulates an encoder which may be receiving
* the output of this decoder as a tandem process. If the output of the
* simulated encoder differs from the input to this decoder, the decoder output
* is adjusted by one level of A-law or u-law codes.
*
* Input:
* sr decoder output linear PCM sample,
* se predictor estimate sample,
* y quantizer step size,
* i decoder input code,
* sign sign bit of code i
*
* Return:
* adjusted A-law or u-law compressed sample.
*/
int tandem_adjust_alaw(int sr, int se, int y, int i, int sign, short const *qtab)
{
unsigned char sp; /* A-law compressed 8-bit code */
short dx; /* prediction error */
char id; /* quantized prediction error */
int sd; /* adjusted A-law decoded sample value */
int im; /* biased magnitude of i */
int imx; /* biased magnitude of id */
if (sr <= -32768)
sr = -1;
sp = sox_13linear2alaw(((sr >> 1) << 3));/* short to A-law compression */
dx = (sox_alaw2linear16(sp) >> 2) - se; /* 16-bit prediction error */
id = quantize(dx, y, qtab, sign - 1);
if (id == i) { /* no adjustment on sp */
return (sp);
} else { /* sp adjustment needed */
/* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */
im = i ^ sign; /* 2's complement to biased unsigned */
imx = id ^ sign;
if (imx > im) { /* sp adjusted to next lower value */
if (sp & 0x80) {
sd = (sp == 0xD5) ? 0x55 :
((sp ^ 0x55) - 1) ^ 0x55;
} else {
sd = (sp == 0x2A) ? 0x2A :
((sp ^ 0x55) + 1) ^ 0x55;
}
} else { /* sp adjusted to next higher value */
if (sp & 0x80)
sd = (sp == 0xAA) ? 0xAA :
((sp ^ 0x55) + 1) ^ 0x55;
else
sd = (sp == 0x55) ? 0xD5 :
((sp ^ 0x55) - 1) ^ 0x55;
}
return (sd);
}
}
int tandem_adjust_ulaw(int sr, int se, int y, int i, int sign, short const *qtab)
{
unsigned char sp; /* u-law compressed 8-bit code */
short dx; /* prediction error */
char id; /* quantized prediction error */
int sd; /* adjusted u-law decoded sample value */
int im; /* biased magnitude of i */
int imx; /* biased magnitude of id */
if (sr <= -32768)
sr = 0;
sp = sox_14linear2ulaw((sr << 2));/* short to u-law compression */
dx = (sox_ulaw2linear16(sp) >> 2) - se; /* 16-bit prediction error */
id = quantize(dx, y, qtab, sign - 1);
if (id == i) {
return (sp);
} else {
/* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */
im = i ^ sign; /* 2's complement to biased unsigned */
imx = id ^ sign;
if (imx > im) { /* sp adjusted to next lower value */
if (sp & 0x80)
sd = (sp == 0xFF) ? 0x7E : sp + 1;
else
sd = (sp == 0) ? 0 : sp - 1;
} else { /* sp adjusted to next higher value */
if (sp & 0x80)
sd = (sp == 0x80) ? 0x80 : sp - 1;
else
sd = (sp == 0x7F) ? 0xFE : sp + 1;
}
return (sd);
}
}

@ -0,0 +1,157 @@
/* This source code is a product of Sun Microsystems, Inc. and is provided
* for unrestricted use. Users may copy or modify this source code without
* charge.
*
* SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun source code is provided with no support and without any obligation on
* the part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
/*
* g72x.h
*
* Header file for CCITT conversion routines.
*
*/
#ifndef _G72X_H
#define _G72X_H
/* aliases */
#define g721_decoder lsx_g721_decoder
#define g721_encoder lsx_g721_encoder
#define g723_24_decoder lsx_g723_24_decoder
#define g723_24_encoder lsx_g723_24_encoder
#define g723_40_decoder lsx_g723_40_decoder
#define g723_40_encoder lsx_g723_40_encoder
#define g72x_init_state lsx_g72x_init_state
#define predictor_pole lsx_g72x_predictor_pole
#define predictor_zero lsx_g72x_predictor_zero
#define quantize lsx_g72x_quantize
#define reconstruct lsx_g72x_reconstruct
#define step_size lsx_g72x_step_size
#define tandem_adjust_alaw lsx_g72x_tandem_adjust_alaw
#define tandem_adjust_ulaw lsx_g72x_tandem_adjust_ulaw
#define update lsx_g72x_update
#define AUDIO_ENCODING_ULAW (1) /* ISDN u-law */
#define AUDIO_ENCODING_ALAW (2) /* ISDN A-law */
#define AUDIO_ENCODING_LINEAR (3) /* PCM 2's-complement (0-center) */
/*
* The following is the definition of the state structure
* used by the G.721/G.723 encoder and decoder to preserve their internal
* state between successive calls. The meanings of the majority
* of the state structure fields are explained in detail in the
* CCITT Recommendation G.721. The field names are essentially indentical
* to variable names in the bit level description of the coding algorithm
* included in this Recommendation.
*/
struct g72x_state {
long yl; /* Locked or steady state step size multiplier. */
short yu; /* Unlocked or non-steady state step size multiplier. */
short dms; /* Short term energy estimate. */
short dml; /* Long term energy estimate. */
short ap; /* Linear weighting coefficient of 'yl' and 'yu'. */
short a[2]; /* Coefficients of pole portion of prediction filter. */
short b[6]; /* Coefficients of zero portion of prediction filter. */
short pk[2]; /*
* Signs of previous two samples of a partially
* reconstructed signal.
*/
short dq[6]; /*
* Previous 6 samples of the quantized difference
* signal represented in an internal floating point
* format.
*/
short sr[2]; /*
* Previous 2 samples of the quantized difference
* signal represented in an internal floating point
* format.
*/
char td; /* delayed tone detect, new in 1988 version */
};
/* External function definitions. */
extern void g72x_init_state(struct g72x_state *);
extern int g721_encoder(
int sample,
int in_coding,
struct g72x_state *state_ptr);
extern int g721_decoder(
int code,
int out_coding,
struct g72x_state *state_ptr);
extern int g723_16_encoder(
int sample,
int in_coding,
struct g72x_state *state_ptr);
extern int g723_16_decoder(
int code,
int out_coding,
struct g72x_state *state_ptr);
extern int g723_24_encoder(
int sample,
int in_coding,
struct g72x_state *state_ptr);
extern int g723_24_decoder(
int code,
int out_coding,
struct g72x_state *state_ptr);
extern int g723_40_encoder(
int sample,
int in_coding,
struct g72x_state *state_ptr);
extern int g723_40_decoder(
int code,
int out_coding,
struct g72x_state *state_ptr);
int predictor_zero(struct g72x_state *state_ptr);
int predictor_pole(struct g72x_state *state_ptr);
int step_size(struct g72x_state *state_ptr);
int quantize(int d,
int y,
short const *table,
int size);
int reconstruct(int sign,
int dqln,
int y);
void update(int code_size,
int y,
int wi,
int fi,
int dq,
int sr,
int dqsez,
struct g72x_state *state_ptr);
int tandem_adjust_alaw(int sr,
int se,
int y,
int i,
int sign,
short const *qtab);
int tandem_adjust_ulaw(int sr,
int se,
int y,
int i,
int sign,
short const *qtab);
#endif /* !_G72X_H */

@ -0,0 +1,276 @@
/* libSoX effect: gain/norm/etc. (c) 2008-9 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define LSX_EFF_ALIAS
#include "sox_i.h"
#include <ctype.h>
#include <string.h>
typedef struct {
sox_bool do_equalise, do_balance, do_balance_no_clip, do_limiter;
sox_bool do_restore, make_headroom, do_normalise, do_scan;
double fixed_gain; /* Valid only in channel 0 */
double mult, reclaim, rms, limiter;
off_t num_samples;
sox_sample_t min, max;
FILE * tmp_file;
} priv_t;
static int create(sox_effect_t * effp, int argc, char * * argv)
{
priv_t * p = (priv_t *)effp->priv;
char const * q;
for (--argc, ++argv; argc && **argv == '-' && argv[0][1] &&
!isdigit((unsigned char)argv[0][1]) && argv[0][1] != '.'; --argc, ++argv)
for (q = &argv[0][1]; *q; ++q) switch (*q) {
case 'n': p->do_scan = p->do_normalise = sox_true; break;
case 'e': p->do_scan = p->do_equalise = sox_true; break;
case 'B': p->do_scan = p->do_balance = sox_true; break;
case 'b': p->do_scan = p->do_balance_no_clip = sox_true; break;
case 'r': p->do_scan = p->do_restore = sox_true; break;
case 'h': p->make_headroom = sox_true; break;
case 'l': p->do_limiter = sox_true; break;
default: lsx_fail("invalid option `-%c'", *q); return lsx_usage(effp);
}
if ((p->do_equalise + p->do_balance + p->do_balance_no_clip + p->do_restore)/ sox_true > 1) {
lsx_fail("only one of -e, -B, -b, -r may be given");
return SOX_EOF;
}
if (p->do_normalise && p->do_restore) {
lsx_fail("only one of -n, -r may be given");
return SOX_EOF;
}
if (p->do_limiter && p->make_headroom) {
lsx_fail("only one of -l, -h may be given");
return SOX_EOF;
}
do {NUMERIC_PARAMETER(fixed_gain, -HUGE_VAL, HUGE_VAL)} while (0);
p->fixed_gain = dB_to_linear(p->fixed_gain);
return argc? lsx_usage(effp) : SOX_SUCCESS;
}
static int start(sox_effect_t * effp)
{
priv_t * p = (priv_t *)effp->priv;
if (effp->flow == 0) {
if (p->do_restore) {
if (!effp->in_signal.mult || *effp->in_signal.mult >= 1) {
lsx_fail("can't reclaim headroom");
return SOX_EOF;
}
p->reclaim = 1 / *effp->in_signal.mult;
}
effp->out_signal.mult = p->make_headroom? &p->fixed_gain : NULL;
if (!p->do_equalise && !p->do_balance && !p->do_balance_no_clip)
effp->flows = 1; /* essentially a conditional SOX_EFF_MCHAN */
}
p->mult = 0;
p->max = 1;
p->min = -1;
if (p->do_scan) {
p->tmp_file = lsx_tmpfile();
if (p->tmp_file == NULL) {
lsx_fail("can't create temporary file: %s", strerror(errno));
return SOX_EOF;
}
}
if (p->do_limiter)
p->limiter = (1 - 1 / p->fixed_gain) * (1. / SOX_SAMPLE_MAX);
else if (p->fixed_gain == floor(p->fixed_gain) && !p->do_scan)
effp->out_signal.precision = effp->in_signal.precision;
return SOX_SUCCESS;
}
static int flow(sox_effect_t * effp, const sox_sample_t * ibuf,
sox_sample_t * obuf, size_t * isamp, size_t * osamp)
{
priv_t * p = (priv_t *)effp->priv;
size_t len;
if (p->do_scan) {
if (fwrite(ibuf, sizeof(*ibuf), *isamp, p->tmp_file) != *isamp) {
lsx_fail("error writing temporary file: %s", strerror(errno));
return SOX_EOF;
}
if (p->do_balance && !p->do_normalise)
for (len = *isamp; len; --len, ++ibuf) {
double d = SOX_SAMPLE_TO_FLOAT_64BIT(*ibuf, effp->clips);
p->rms += sqr(d);
++p->num_samples;
}
else if (p->do_balance || p->do_balance_no_clip)
for (len = *isamp; len; --len, ++ibuf) {
double d = SOX_SAMPLE_TO_FLOAT_64BIT(*ibuf, effp->clips);
p->rms += sqr(d);
++p->num_samples;
p->max = max(p->max, *ibuf);
p->min = min(p->min, *ibuf);
}
else for (len = *isamp; len; --len, ++ibuf) {
p->max = max(p->max, *ibuf);
p->min = min(p->min, *ibuf);
}
*osamp = 0; /* samples not output until drain */
}
else {
double mult = ((priv_t *)(effp - effp->flow)->priv)->fixed_gain;
len = *isamp = *osamp = min(*isamp, *osamp);
if (!p->do_limiter) for (; len; --len, ++ibuf)
*obuf++ = SOX_ROUND_CLIP_COUNT(*ibuf * mult, effp->clips);
else for (; len; --len, ++ibuf) {
double d = *ibuf * mult;
*obuf++ = d < 0 ? 1 / (1 / d - p->limiter) - .5 :
d > 0 ? 1 / (1 / d + p->limiter) + .5 : 0;
}
}
return SOX_SUCCESS;
}
static void start_drain(sox_effect_t * effp)
{
priv_t * p = (priv_t *)effp->priv;
double max = SOX_SAMPLE_MAX, max_peak = 0, max_rms = 0;
size_t i;
if (p->do_balance || p->do_balance_no_clip) {
for (i = 0; i < effp->flows; ++i) {
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv;
max_rms = max(max_rms, sqrt(q->rms / q->num_samples));
rewind(q->tmp_file);
}
for (i = 0; i < effp->flows; ++i) {
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv;
double this_rms = sqrt(q->rms / q->num_samples);
double this_peak = max(q->max / max, q->min / (double)SOX_SAMPLE_MIN);
q->mult = this_rms != 0? max_rms / this_rms : 1;
max_peak = max(max_peak, q->mult * this_peak);
q->mult *= p->fixed_gain;
}
if (p->do_normalise || (p->do_balance_no_clip && max_peak > 1))
for (i = 0; i < effp->flows; ++i) {
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv;
q->mult /= max_peak;
}
} else if (p->do_equalise && !p->do_normalise) {
for (i = 0; i < effp->flows; ++i) {
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv;
double this_peak = max(q->max / max, q->min / (double)SOX_SAMPLE_MIN);
max_peak = max(max_peak, this_peak);
q->mult = p->fixed_gain / this_peak;
rewind(q->tmp_file);
}
for (i = 0; i < effp->flows; ++i) {
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv;
q->mult *= max_peak;
}
} else {
p->mult = min(max / p->max, (double)SOX_SAMPLE_MIN / p->min);
if (p->do_restore) {
if (p->reclaim > p->mult)
lsx_report("%.3gdB not reclaimed", linear_to_dB(p->reclaim / p->mult));
else p->mult = p->reclaim;
}
p->mult *= p->fixed_gain;
rewind(p->tmp_file);
}
}
static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp)
{
priv_t * p = (priv_t *)effp->priv;
size_t len;
int result = SOX_SUCCESS;
*osamp -= *osamp % effp->in_signal.channels;
if (p->do_scan) {
if (!p->mult)
start_drain(effp);
len = fread(obuf, sizeof(*obuf), *osamp, p->tmp_file);
if (len != *osamp && !feof(p->tmp_file)) {
lsx_fail("error reading temporary file: %s", strerror(errno));
result = SOX_EOF;
}
if (!p->do_limiter) for (*osamp = len; len; --len, ++obuf)
*obuf = SOX_ROUND_CLIP_COUNT(*obuf * p->mult, effp->clips);
else for (*osamp = len; len; --len) {
double d = *obuf * p->mult;
*obuf++ = d < 0 ? 1 / (1 / d - p->limiter) - .5 :
d > 0 ? 1 / (1 / d + p->limiter) + .5 : 0;
}
}
else *osamp = 0;
return result;
}
static int stop(sox_effect_t * effp)
{
priv_t * p = (priv_t *)effp->priv;
if (p->do_scan)
fclose(p->tmp_file); /* auto-deleted by lsx_tmpfile */
return SOX_SUCCESS;
}
sox_effect_handler_t const * lsx_gain_effect_fn(void)
{
static sox_effect_handler_t handler = {
"gain", NULL, SOX_EFF_GAIN,
create, start, flow, drain, stop, NULL, sizeof(priv_t)};
static char const * lines[] = {
"[-e|-b|-B|-r] [-n] [-l|-h] [gain-dB]",
"-e\t Equalise channels: peak to that with max peak;",
"-B\t Balance channels: rms to that with max rms; no clip protection",
"-b\t Balance channels: rms to that with max rms; clip protection",
"\t Note -Bn = -bn",
"-r\t Reclaim headroom (as much as possible without clipping); see -h",
"-n\t Norm file to 0dBfs(output precision); gain-dB, if present, usually <0",
"-l\t Use simple limiter",
"-h\t Apply attenuation for headroom for subsequent effects; gain-dB, if",
"\t present, is subject to reclaim by a subsequent gain -r",
"gain-dB\t Apply gain in dB",
};
static char * usage;
handler.usage = lsx_usage_lines(&usage, lines, array_length(lines));
return &handler;
}
/*------------------ emulation of the old `normalise' effect -----------------*/
static int norm_getopts(sox_effect_t * effp, int argc, char * * argv)
{
char * argv2[3];
int argc2 = 2;
argv2[0] = argv[0], --argc, ++argv;
argv2[1] = "-n";
if (argc)
argv2[argc2++] = *argv, --argc, ++argv;
return argc? lsx_usage(effp) :
lsx_gain_effect_fn()->getopts(effp, argc2, argv2);
}
sox_effect_handler_t const * lsx_norm_effect_fn(void)
{
static sox_effect_handler_t handler;
handler = *lsx_gain_effect_fn();
handler.name = "norm";
handler.usage = "[level]";
handler.getopts = norm_getopts;
return &handler;
}

@ -0,0 +1,349 @@
/* lsx_getopt for SoX
*
* (c) 2011 Doug Cook and SoX contributors
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
void
lsx_getopt_init(
LSX_PARAM_IN int argc, /* Number of arguments in argv */
LSX_PARAM_IN_COUNT(argc) char * const * argv, /* Array of arguments */
LSX_PARAM_IN_Z char const * shortopts, /* Short option characters */
LSX_PARAM_IN_OPT lsx_option_t const * longopts, /* Array of long option descriptors */
LSX_PARAM_IN lsx_getopt_flags_t flags, /* Flags for longonly and opterr */
LSX_PARAM_IN int first, /* First argument to check (usually 1) */
LSX_PARAM_OUT lsx_getopt_t * state) /* State object to initialize */
{
assert(argc >= 0);
assert(argv != NULL);
assert(shortopts);
assert(first >= 0);
assert(first <= argc);
assert(state);
if (state)
{
if (argc < 0 ||
!argv ||
!shortopts ||
first < 0 ||
first > argc)
{
memset(state, 0, sizeof(*state));
}
else
{
state->argc = argc;
state->argv = argv;
state->shortopts =
(shortopts[0] == '+' || shortopts[0] == '-') /* Requesting GNU special behavior? */
? shortopts + 1 /* Ignore request. */
: shortopts; /* No special behavior requested. */
state->longopts = longopts;
state->flags = flags;
state->curpos = NULL;
state->ind = first;
state->opt = '?';
state->arg = NULL;
state->lngind = -1;
}
}
}
static void CheckCurPosEnd(
LSX_PARAM_INOUT lsx_getopt_t * state)
{
if (!state->curpos[0])
{
state->curpos = NULL;
state->ind++;
}
}
int
lsx_getopt(
LSX_PARAM_INOUT lsx_getopt_t * state)
{
int oerr;
assert(state);
if (!state)
{
lsx_fail("lsx_getopt called with state=NULL");
return -1;
}
assert(state->argc >= 0);
assert(state->argv != NULL);
assert(state->shortopts);
assert(state->ind >= 0);
assert(state->ind <= state->argc + 1);
oerr = 0 != (state->flags & lsx_getopt_flag_opterr);
state->opt = 0;
state->arg = NULL;
state->lngind = -1;
if (state->argc < 0 ||
!state->argv ||
!state->shortopts ||
state->ind < 0)
{ /* programmer error */
lsx_fail("lsx_getopt called with invalid information");
state->curpos = NULL;
return -1;
}
else if (
state->argc <= state->ind ||
!state->argv[state->ind] ||
state->argv[state->ind][0] != '-' ||
state->argv[state->ind][1] == '\0')
{ /* return no more options */
state->curpos = NULL;
return -1;
}
else if (state->argv[state->ind][1] == '-' && state->argv[state->ind][2] == '\0')
{ /* skip "--", return no more options. */
state->curpos = NULL;
state->ind++;
return -1;
}
else
{ /* Look for the next option */
char const * current = state->argv[state->ind];
char const * param = current + 1;
if (state->curpos == NULL ||
state->curpos <= param ||
param + strlen(param) <= state->curpos)
{ /* Start parsing a new parameter - check for a long option */
state->curpos = NULL;
if (state->longopts &&
(param[0] == '-' || (state->flags & lsx_getopt_flag_longonly)))
{
size_t nameLen;
int doubleDash = param[0] == '-';
if (doubleDash)
{
param++;
}
for (nameLen = 0; param[nameLen] && param[nameLen] != '='; nameLen++)
{}
/* For single-dash, you have to specify at least two letters in the name. */
if (doubleDash || nameLen >= 2)
{
lsx_option_t const * pCur;
lsx_option_t const * pMatch = NULL;
int matches = 0;
for (pCur = state->longopts; pCur->name; pCur++)
{
if (0 == strncmp(pCur->name, param, nameLen))
{ /* Prefix match. */
matches++;
pMatch = pCur;
if (nameLen == strlen(pCur->name))
{ /* Exact match - no ambiguity, stop search. */
matches = 1;
break;
}
}
}
if (matches == 1)
{ /* Matched. */
state->ind++;
if (param[nameLen])
{ /* --name=value */
if (pMatch->has_arg)
{ /* Required or optional arg - done. */
state->arg = param + nameLen + 1;
}
else
{ /* No arg expected. */
if (oerr)
{
lsx_warn("`%s' did not expect an argument from `%s'",
pMatch->name,
current);
}
return '?';
}
}
else if (pMatch->has_arg == lsx_option_arg_required)
{ /* Arg required. */
state->arg = state->argv[state->ind];
state->ind++;
if (state->ind > state->argc)
{
if (oerr)
{
lsx_warn("`%s' requires an argument from `%s'",
pMatch->name,
current);
}
return state->shortopts[0] == ':' ? ':' : '?'; /* Missing required value. */
}
}
state->lngind = pMatch - state->longopts;
if (pMatch->flag)
{
*pMatch->flag = pMatch->val;
return 0;
}
else
{
return pMatch->val;
}
}
else if (matches == 0 && doubleDash)
{ /* No match */
if (oerr)
{
lsx_warn("parameter not recognized from `%s'", current);
}
state->ind++;
return '?';
}
else if (matches > 1)
{ /* Ambiguous. */
if (oerr)
{
lsx_warn("parameter `%s' is ambiguous:", current);
for (pCur = state->longopts; pCur->name; pCur++)
{
if (0 == strncmp(pCur->name, param, nameLen))
{
lsx_warn("parameter `%s' could be `--%s'", current, pCur->name);
}
}
}
state->ind++;
return '?';
}
}
}
state->curpos = param;
}
state->opt = state->curpos[0];
if (state->opt == ':')
{ /* ':' is never a valid short option character */
if (oerr)
{
lsx_warn("option `%c' not recognized", state->opt);
}
state->curpos++;
CheckCurPosEnd(state);
return '?'; /* unrecognized option */
}
else
{ /* Short option needs to be matched from option list */
char const * pShortopt = strchr(state->shortopts, state->opt);
state->curpos++;
if (!pShortopt)
{ /* unrecognized option */
if (oerr)
{
lsx_warn("option `%c' not recognized", state->opt);
}
CheckCurPosEnd(state);
return '?';
}
else if (pShortopt[1] == ':' && state->curpos[0])
{ /* Return the rest of the parameter as the option's value */
state->arg = state->curpos;
state->curpos = NULL;
state->ind++;
return state->opt;
}
else if (pShortopt[1] == ':' && pShortopt[2] != ':')
{ /* Option requires a value */
state->curpos = NULL;
state->ind++;
state->arg = state->argv[state->ind];
state->ind++;
if (state->ind <= state->argc)
{ /* A value was present, so we're good. */
return state->opt;
}
else
{ /* Missing required value. */
if (oerr)
{
lsx_warn("option `%c' requires an argument",
state->opt);
}
return state->shortopts[0] == ':' ? ':' : '?';
}
}
else
{ /* Option without a value. */
CheckCurPosEnd(state);
return state->opt;
}
}
}
}
#ifdef TEST_GETOPT
#include <stdio.h>
int main(int argc, char const * argv[])
{
static int help = 0;
static lsx_option_t longopts[] =
{
{"a11", 0, 0, 101},
{"a12", 0, 0, 102},
{"a122", 0, 0, 103},
{"rarg", 1, 0, 104},
{"oarg", 2, 0, 105},
{"help", 0, &help, 106},
{0}
};
int ch;
lsx_getopt_t state;
lsx_getopt_init(argc, argv, "abc:d:v::0123456789", longopts, sox_true, 1, &state);
while (-1 != (ch = lsx_getopt(&state)))
{
printf(
"H=%d ch=%d, ind=%d opt=%d lng=%d arg=%s\n",
help,
ch,
state.ind,
state.opt,
state.lngind,
state.arg ? state.arg : "NULL");
}
return 0;
}
#endif /* TEST_GETOPT */

@ -0,0 +1,247 @@
/* Copyright 1991, 1992, 1993 Guido van Rossum And Sundry Contributors.
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
* Guido van Rossum And Sundry Contributors are not responsible for
* the consequences of using this software.
*/
/*
* GSM 06.10 courtesy Communications and Operating Systems Research Group,
* Technische Universitaet Berlin
*
* Source code and more information on this format can be obtained from
* http://www.quut.com/gsm/
*
* Written 26 Jan 1995 by Andrew Pam
* Portions Copyright (c) 1995 Serious Cybernetics
*
* July 19, 1998 - Chris Bagwell (cbagwell@sprynet.com)
* Added GSM support to SOX from patches floating around with the help
* of Dima Barsky (ess2db@ee.surrey.ac.uk).
*
* Nov. 26, 1999 - Stan Brooks (stabro@megsinet.com)
* Rewritten to support multiple channels
*/
#include "sox_i.h"
#ifdef HAVE_GSM_GSM_H
#include <gsm/gsm.h>
#else
#include <gsm.h>
#endif
#include <errno.h>
#define MAXCHANS 16
/* sizeof(gsm_frame) */
#define FRAMESIZE (size_t)33
/* samples per gsm_frame */
#define BLOCKSIZE 160
/* Private data */
typedef struct {
unsigned channels;
gsm_signal *samples;
gsm_signal *samplePtr;
gsm_signal *sampleTop;
gsm_byte *frames;
gsm handle[MAXCHANS];
} priv_t;
static int gsmstart_rw(sox_format_t * ft, int w)
{
priv_t *p = (priv_t *) ft->priv;
unsigned ch;
ft->encoding.encoding = SOX_ENCODING_GSM;
if (!ft->signal.rate)
ft->signal.rate = 8000;
if (ft->signal.channels == 0)
ft->signal.channels = 1;
p->channels = ft->signal.channels;
if (p->channels > MAXCHANS || p->channels <= 0)
{
lsx_fail_errno(ft,SOX_EFMT,"gsm: channels(%d) must be in 1-16", ft->signal.channels);
return(SOX_EOF);
}
for (ch=0; ch<p->channels; ch++) {
p->handle[ch] = gsm_create();
if (!p->handle[ch])
{
lsx_fail_errno(ft,errno,"unable to create GSM stream");
return (SOX_EOF);
}
}
p->frames = lsx_malloc(p->channels*FRAMESIZE);
p->samples = lsx_malloc(BLOCKSIZE * (p->channels+1) * sizeof(gsm_signal));
p->sampleTop = p->samples + BLOCKSIZE*p->channels;
p->samplePtr = (w)? p->samples : p->sampleTop;
return (SOX_SUCCESS);
}
static int sox_gsmstartread(sox_format_t * ft)
{
return gsmstart_rw(ft,0);
}
static int sox_gsmstartwrite(sox_format_t * ft)
{
return gsmstart_rw(ft,1);
}
/*
* Read up to len samples from file.
* Convert to signed longs.
* Place in buf[].
* Return number of samples read.
*/
static size_t sox_gsmread(sox_format_t * ft, sox_sample_t *buf, size_t samp)
{
size_t done = 0, r;
int ch, chans;
gsm_signal *gbuff;
priv_t *p = (priv_t *) ft->priv;
chans = p->channels;
while (done < samp)
{
while (p->samplePtr < p->sampleTop && done < samp)
buf[done++] =
SOX_SIGNED_16BIT_TO_SAMPLE(*(p->samplePtr)++,);
if (done>=samp) break;
r = lsx_readbuf(ft, p->frames, p->channels * FRAMESIZE);
if (r != p->channels * FRAMESIZE)
break;
p->samplePtr = p->samples;
for (ch=0; ch<chans; ch++) {
int i;
gsm_signal *gsp;
gbuff = p->sampleTop;
if (gsm_decode(p->handle[ch], p->frames + ch*FRAMESIZE, gbuff) < 0)
{
lsx_fail_errno(ft,errno,"error during GSM decode");
return (0);
}
gsp = p->samples + ch;
for (i=0; i<BLOCKSIZE; i++) {
*gsp = *gbuff++;
gsp += chans;
}
}
}
return done;
}
static int gsmflush(sox_format_t * ft)
{
int r, ch, chans;
gsm_signal *gbuff;
priv_t *p = (priv_t *) ft->priv;
chans = p->channels;
/* zero-fill samples as needed */
while (p->samplePtr < p->sampleTop)
*(p->samplePtr)++ = 0;
gbuff = p->sampleTop;
for (ch=0; ch<chans; ch++) {
int i;
gsm_signal *gsp;
gsp = p->samples + ch;
for (i=0; i<BLOCKSIZE; i++) {
gbuff[i] = *gsp;
gsp += chans;
}
gsm_encode(p->handle[ch], gbuff, p->frames);
r = lsx_writebuf(ft, p->frames, FRAMESIZE);
if (r != FRAMESIZE)
{
lsx_fail_errno(ft,errno,"write error");
return(SOX_EOF);
}
}
p->samplePtr = p->samples;
return (SOX_SUCCESS);
}
static size_t sox_gsmwrite(sox_format_t * ft, const sox_sample_t *buf, size_t samp)
{
size_t done = 0;
priv_t *p = (priv_t *) ft->priv;
while (done < samp)
{
SOX_SAMPLE_LOCALS;
while ((p->samplePtr < p->sampleTop) && (done < samp))
*(p->samplePtr)++ =
SOX_SAMPLE_TO_SIGNED_16BIT(buf[done++], ft->clips);
if (p->samplePtr == p->sampleTop)
{
if(gsmflush(ft))
{
return 0;
}
}
}
return done;
}
static int sox_gsmstopread(sox_format_t * ft)
{
priv_t *p = (priv_t *) ft->priv;
unsigned ch;
for (ch=0; ch<p->channels; ch++)
gsm_destroy(p->handle[ch]);
free(p->samples);
free(p->frames);
return (SOX_SUCCESS);
}
static int sox_gsmstopwrite(sox_format_t * ft)
{
int rc;
priv_t *p = (priv_t *) ft->priv;
if (p->samplePtr > p->samples)
{
rc = gsmflush(ft);
if (rc)
return rc;
}
return sox_gsmstopread(ft); /* destroy handles and free buffers */
}
LSX_FORMAT_HANDLER(gsm)
{
static char const * const names[] = {"gsm", NULL};
static sox_rate_t const write_rates[] = {8000, 0};
static unsigned const write_encodings[] = {SOX_ENCODING_GSM, 0, 0};
static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE,
"GSM 06.10 (full-rate) lossy speech compression", names, 0,
sox_gsmstartread, sox_gsmread, sox_gsmstopread,
sox_gsmstartwrite, sox_gsmwrite, sox_gsmstopwrite,
NULL, write_encodings, write_rates, sizeof(priv_t)
};
return &handler;
}

@ -0,0 +1,207 @@
/* libSoX file format: Grandstream ring tone (c) 2009 robs@users.sourceforge.net
*
* See https://web.archive.org/web/20101128121923/http://grandstream.com/ringtone.html
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
#include <time.h>
#define VERSION_ 0x1000000
#define MAX_FILE_SIZE 0x10000
#define HEADER_SIZE (size_t)512
#define PADDING_SIZE (size_t)478
static char const id[16] = "ring.bin";
typedef struct {
char const * string;
int ft_encoding;
unsigned bits_per_sample;
sox_encoding_t sox_encoding;
} table_t;
static table_t const table[] = {
{NULL, 0, 8, SOX_ENCODING_ULAW},
{"G726", 2, 0, SOX_ENCODING_UNKNOWN},
{NULL, 3, 0, SOX_ENCODING_GSM},
{NULL, 4, 0, SOX_ENCODING_G723},
{NULL, 8, 8, SOX_ENCODING_ALAW},
{"G722", 9, 0, SOX_ENCODING_UNKNOWN},
{"G728", 15, 2, SOX_ENCODING_UNKNOWN},
{"iLBC", 98, 0, SOX_ENCODING_UNKNOWN},
};
static int ft_enc(unsigned bits_per_sample, sox_encoding_t encoding)
{
size_t i;
for (i = 0; i < array_length(table); ++i) {
table_t const * t = &table[i];
if (t->sox_encoding == encoding && t->bits_per_sample == bits_per_sample)
return t->ft_encoding;
}
return -1; /* Should never get here. */
}
static sox_encoding_t sox_enc(int ft_encoding, unsigned * bits_per_sample)
{
size_t i;
for (i = 0; i < array_length(table); ++i) {
table_t const * t = &table[i];
if (t->ft_encoding == ft_encoding) {
*bits_per_sample = t->bits_per_sample;
if (t->sox_encoding == SOX_ENCODING_UNKNOWN)
lsx_report("unsupported encoding: %s", t->string);
return t->sox_encoding;
}
}
*bits_per_sample = 0;
return SOX_ENCODING_UNKNOWN;
}
static int start_read(sox_format_t * ft)
{
off_t num_samples;
char read_id[array_length(id)];
uint32_t file_size;
int16_t ft_encoding;
sox_encoding_t encoding;
unsigned bits_per_sample;
lsx_readdw(ft, &file_size);
num_samples = file_size? file_size * 2 - HEADER_SIZE : SOX_UNSPEC;
if (file_size >= 2 && ft->seekable) {
int i, checksum = (file_size >> 16) + file_size;
for (i = file_size - 2; i; --i) {
int16_t int16;
lsx_readsw(ft, &int16);
checksum += int16;
}
if (lsx_seeki(ft, (off_t)sizeof(file_size), SEEK_SET) != 0)
return SOX_EOF;
if (checksum & 0xffff)
lsx_warn("invalid checksum in input file %s", ft->filename);
}
lsx_skipbytes(ft, (size_t)(2 + 4 + 6)); /* Checksum, version, time stamp. */
lsx_readchars(ft, read_id, sizeof(read_id));
if (memcmp(read_id, id, strlen(id))) {
lsx_fail_errno(ft, SOX_EHDR, "gsrt: invalid file name in header");
return SOX_EOF;
}
lsx_readsw(ft, &ft_encoding);
encoding = sox_enc(ft_encoding, &bits_per_sample);
if (encoding != SOX_ENCODING_ALAW &&
encoding != SOX_ENCODING_ULAW)
ft->handler.read = NULL;
lsx_skipbytes(ft, PADDING_SIZE);
return lsx_check_read_params(ft, 1, 8000., encoding,
bits_per_sample, (uint64_t)num_samples, sox_true);
}
static int start_write(sox_format_t * ft)
{
int i, encoding = ft_enc(ft->encoding.bits_per_sample, ft->encoding.encoding);
time_t now = sox_globals.repeatable? 0 : time(NULL);
struct tm const * t = sox_globals.repeatable? gmtime(&now) : localtime(&now);
int checksum = (VERSION_ >> 16) + VERSION_;
checksum += t->tm_year + 1900;
checksum += ((t->tm_mon + 1) << 8) + t->tm_mday;
checksum += (t->tm_hour << 8) + t->tm_min;
for (i = sizeof(id) - 2; i >= 0; i -= 2)
checksum += (id[i] << 8) + id[i + 1];
checksum += encoding;
return lsx_writedw(ft, 0)
|| lsx_writesw(ft, -checksum)
|| lsx_writedw(ft, VERSION_)
|| lsx_writesw(ft, t->tm_year + 1900)
|| lsx_writesb(ft, t->tm_mon + 1)
|| lsx_writesb(ft, t->tm_mday)
|| lsx_writesb(ft, t->tm_hour)
|| lsx_writesb(ft, t->tm_min)
|| lsx_writechars(ft, id, sizeof(id))
|| lsx_writesw(ft, encoding)
|| lsx_padbytes(ft, PADDING_SIZE) ? SOX_EOF : SOX_SUCCESS;
}
static size_t write_samples(
sox_format_t * ft, sox_sample_t const * buf, size_t nsamp)
{
size_t n = min(nsamp, MAX_FILE_SIZE - (size_t)ft->tell_off);
if (n != nsamp)
lsx_warn("audio truncated");
return lsx_rawwrite(ft, buf, n);
}
static int stop_write(sox_format_t * ft)
{
long num_samples = ft->tell_off - HEADER_SIZE;
if (num_samples & 1) {
sox_sample_t pad = 0;
lsx_rawwrite(ft, &pad, 1);
}
if (ft->seekable) {
unsigned i, file_size = ft->tell_off >> 1;
int16_t int16;
int checksum;
if (!lsx_seeki(ft, (off_t)sizeof(uint32_t), SEEK_SET)) {
lsx_readsw(ft, &int16);
checksum = (file_size >> 16) + file_size - int16;
if (!lsx_seeki(ft, (off_t)HEADER_SIZE, SEEK_SET)) {
for (i = (num_samples + 1) >> 1; i; --i) {
lsx_readsw(ft, &int16);
checksum += int16;
}
if (!lsx_seeki(ft, (off_t)0, SEEK_SET)) {
lsx_writedw(ft, file_size);
lsx_writesw(ft, -checksum);
return SOX_SUCCESS;
}
}
}
}
lsx_warn("can't seek in output file `%s'; "
"length in file header will be unspecified", ft->filename);
return SOX_SUCCESS;
}
LSX_FORMAT_HANDLER(gsrt)
{
static char const *const names[] = { "gsrt", NULL };
static sox_rate_t const write_rates[] = { 8000, 0 };
static unsigned const write_encodings[] = {
SOX_ENCODING_ALAW, 8, 0,
SOX_ENCODING_ULAW, 8, 0,
0
};
static sox_format_handler_t const handler = {
SOX_LIB_VERSION_CODE, "Grandstream ring tone",
names, SOX_FILE_BIG_END | SOX_FILE_MONO,
start_read, lsx_rawread, NULL,
start_write, write_samples, stop_write,
lsx_rawseek, write_encodings, write_rates, 0
};
return &handler;
}

@ -0,0 +1,502 @@
/* libSoX Macintosh HCOM format.
* These are really FSSD type files with Huffman compression,
* in MacBinary format.
* TODO: make the MacBinary format optional (so that .data files
* are also acceptable). (How to do this on output?)
*
* September 25, 1991
* Copyright 1991 Guido van Rossum And Sundry Contributors
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
* Guido van Rossum And Sundry Contributors are not responsible for
* the consequences of using this software.
*
* April 28, 1998 - Chris Bagwell (cbagwell@sprynet.com)
*
* Rearranged some functions so that they are declared before they are
* used, clearing up some compiler warnings. Because these functions
* passed floats, it helped some dumb compilers pass stuff on the
* stack correctly.
*
*/
#include "sox_i.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
/* FIXME: eliminate these 2 functions */
static void put32_be(unsigned char **p, int32_t val)
{
*(*p)++ = (val >> 24) & 0xff;
*(*p)++ = (val >> 16) & 0xff;
*(*p)++ = (val >> 8) & 0xff;
*(*p)++ = val & 0xff;
}
static void put16_be(unsigned char **p, int val)
{
*(*p)++ = (val >> 8) & 0xff;
*(*p)++ = val & 0xff;
}
/* Dictionary entry for Huffman (de)compression */
typedef struct {
long frequ;
short dict_leftson;
short dict_rightson;
} dictent;
typedef struct {
/* Static data from the header */
dictent *dictionary;
int32_t checksum;
int deltacompression;
/* Engine state */
long huffcount;
long cksum;
int dictentry;
int nrbits;
uint32_t current;
short sample;
/* Dictionary */
dictent *de;
int32_t new_checksum;
int nbits;
int32_t curword;
/* Private data used by writer */
unsigned char *data; /* Buffer allocated with lsx_malloc */
size_t size; /* Size of allocated buffer */
size_t pos; /* Where next byte goes */
} priv_t;
static int dictvalid(int n, int size, int left, int right)
{
if (n > 0 && left < 0)
return 1;
return (unsigned)left < size && (unsigned)right < size;
}
static int startread(sox_format_t * ft)
{
priv_t *p = (priv_t *) ft->priv;
int i;
char buf[5];
uint32_t datasize, rsrcsize;
uint32_t huffcount, checksum, compresstype, divisor;
unsigned short dictsize;
int rc;
/* Skip first 65 bytes of header */
rc = lsx_skipbytes(ft, (size_t) 65);
if (rc)
return rc;
/* Check the file type (bytes 65-68) */
if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || strncmp(buf, "FSSD", (size_t)4) != 0)
{
lsx_fail_errno(ft,SOX_EHDR,"Mac header type is not FSSD");
return (SOX_EOF);
}
/* Skip to byte 83 */
rc = lsx_skipbytes(ft, (size_t) 83-69);
if (rc)
return rc;
/* Get essential numbers from the header */
lsx_readdw(ft, &datasize); /* bytes 83-86 */
lsx_readdw(ft, &rsrcsize); /* bytes 87-90 */
/* Skip the rest of the header (total 128 bytes) */
rc = lsx_skipbytes(ft, (size_t) 128-91);
if (rc != 0)
return rc;
/* The data fork must contain a "HCOM" header */
if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || strncmp(buf, "HCOM", (size_t)4) != 0)
{
lsx_fail_errno(ft,SOX_EHDR,"Mac data fork is not HCOM");
return (SOX_EOF);
}
/* Then follow various parameters */
lsx_readdw(ft, &huffcount);
lsx_readdw(ft, &checksum);
lsx_readdw(ft, &compresstype);
if (compresstype > 1)
{
lsx_fail_errno(ft,SOX_EHDR,"Bad compression type in HCOM header");
return (SOX_EOF);
}
lsx_readdw(ft, &divisor);
if (divisor == 0 || divisor > 4)
{
lsx_fail_errno(ft,SOX_EHDR,"Bad sampling rate divisor in HCOM header");
return (SOX_EOF);
}
lsx_readw(ft, &dictsize);
/* Translate to sox parameters */
ft->encoding.encoding = SOX_ENCODING_HCOM;
ft->encoding.bits_per_sample = 8;
ft->signal.rate = 22050 / divisor;
ft->signal.channels = 1;
ft->signal.length = huffcount;
/* Allocate memory for the dictionary */
p->dictionary = lsx_malloc(511 * sizeof(dictent));
/* Read dictionary */
for(i = 0; i < dictsize; i++) {
lsx_readsw(ft, &(p->dictionary[i].dict_leftson));
lsx_readsw(ft, &(p->dictionary[i].dict_rightson));
lsx_debug("%d %d",
p->dictionary[i].dict_leftson,
p->dictionary[i].dict_rightson);
if (!dictvalid(i, dictsize, p->dictionary[i].dict_leftson,
p->dictionary[i].dict_rightson)) {
lsx_fail_errno(ft, SOX_EHDR, "Invalid dictionary");
return SOX_EOF;
}
}
rc = lsx_skipbytes(ft, (size_t) 1); /* skip pad byte */
if (rc)
return rc;
/* Initialized the decompression engine */
p->checksum = checksum;
p->deltacompression = compresstype;
if (!p->deltacompression)
lsx_debug("HCOM data using value compression");
p->huffcount = huffcount;
p->cksum = 0;
p->dictentry = 0;
p->nrbits = -1; /* Special case to get first byte */
return (SOX_SUCCESS);
}
static size_t read_samples(sox_format_t * ft, sox_sample_t *buf, size_t len)
{
register priv_t *p = (priv_t *) ft->priv;
int done = 0;
unsigned char sample_rate;
if (p->nrbits < 0) {
/* The first byte is special */
if (p->huffcount == 0)
return 0; /* Don't know if this can happen... */
if (lsx_readb(ft, &sample_rate) == SOX_EOF)
{
return (0);
}
p->sample = sample_rate;
*buf++ = SOX_UNSIGNED_8BIT_TO_SAMPLE(p->sample,);
p->huffcount--;
p->nrbits = 0;
done++;
len--;
if (len == 0)
return done;
}
while (p->huffcount > 0) {
if(p->nrbits == 0) {
lsx_readdw(ft, &(p->current));
if (lsx_eof(ft))
{
lsx_fail_errno(ft,SOX_EOF,"unexpected EOF in HCOM data");
return (0);
}
p->cksum += p->current;
p->nrbits = 32;
}
if(p->current & 0x80000000) {
p->dictentry =
p->dictionary[p->dictentry].dict_rightson;
} else {
p->dictentry =
p->dictionary[p->dictentry].dict_leftson;
}
p->current = p->current << 1;
p->nrbits--;
if(p->dictionary[p->dictentry].dict_leftson < 0) {
short datum;
datum = p->dictionary[p->dictentry].dict_rightson;
if (!p->deltacompression)
p->sample = 0;
p->sample = (p->sample + datum) & 0xff;
p->huffcount--;
*buf++ = SOX_UNSIGNED_8BIT_TO_SAMPLE(p->sample,);
p->dictentry = 0;
done++;
len--;
if (len == 0)
break;
}
}
return done;
}
static int stopread(sox_format_t * ft)
{
register priv_t *p = (priv_t *) ft->priv;
if (p->huffcount != 0)
{
lsx_fail_errno(ft,SOX_EFMT,"not all HCOM data read");
return (SOX_EOF);
}
if(p->cksum != p->checksum)
{
lsx_fail_errno(ft,SOX_EFMT,"checksum error in HCOM data");
return (SOX_EOF);
}
free(p->dictionary);
p->dictionary = NULL;
return (SOX_SUCCESS);
}
#define BUFINCR (10*BUFSIZ)
static int startwrite(sox_format_t * ft)
{
priv_t * p = (priv_t *) ft->priv;
p->size = BUFINCR;
p->pos = 0;
p->data = lsx_malloc(p->size);
return SOX_SUCCESS;
}
static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t len)
{
priv_t *p = (priv_t *) ft->priv;
sox_sample_t datum;
size_t i;
if (len == 0)
return 0;
if (p->pos == INT32_MAX)
return SOX_EOF;
if (p->pos + len > INT32_MAX) {
lsx_warn("maximum file size exceeded");
len = INT32_MAX - p->pos;
}
if (p->pos + len > p->size) {
p->size = ((p->pos + len) / BUFINCR + 1) * BUFINCR;
p->data = lsx_realloc(p->data, p->size);
}
for (i = 0; i < len; i++) {
SOX_SAMPLE_LOCALS;
datum = *buf++;
p->data[p->pos++] = SOX_SAMPLE_TO_UNSIGNED_8BIT(datum, ft->clips);
}
return len;
}
static void makecodes(int e, int c, int s, int b, dictent newdict[511], long codes[256], long codesize[256])
{
assert(b); /* Prevent stack overflow */
if (newdict[e].dict_leftson < 0) {
codes[newdict[e].dict_rightson] = c;
codesize[newdict[e].dict_rightson] = s;
} else {
makecodes(newdict[e].dict_leftson, c, s + 1, b << 1, newdict, codes, codesize);
makecodes(newdict[e].dict_rightson, c + b, s + 1, b << 1, newdict, codes, codesize);
}
}
static void putcode(sox_format_t * ft, long codes[256], long codesize[256], unsigned c, unsigned char **df)
{
priv_t *p = (priv_t *) ft->priv;
long code, size;
int i;
code = codes[c];
size = codesize[c];
for(i = 0; i < size; i++) {
p->curword <<= 1;
if (code & 1)
p->curword += 1;
p->nbits++;
if (p->nbits == 32) {
put32_be(df, p->curword);
p->new_checksum += p->curword;
p->nbits = 0;
p->curword = 0;
}
code >>= 1;
}
}
static void compress(sox_format_t * ft, unsigned char **df, int32_t *dl)
{
priv_t *p = (priv_t *) ft->priv;
int samplerate;
unsigned char *datafork = *df;
unsigned char *ddf, *dfp;
short dictsize;
int frequtable[256];
long codes[256], codesize[256];
dictent newdict[511];
int i, sample, j, k, d, l, frequcount;
int64_t csize;
sample = *datafork;
memset(frequtable, 0, sizeof(frequtable));
memset(codes, 0, sizeof(codes));
memset(codesize, 0, sizeof(codesize));
memset(newdict, 0, sizeof(newdict));
for (i = 1; i < *dl; i++) {
d = (datafork[i] - (sample & 0xff)) & 0xff; /* creates absolute entries LMS */
sample = datafork[i];
datafork[i] = d;
assert(d >= 0 && d <= 255); /* check our table is accessed correctly */
frequtable[d]++;
}
p->de = newdict;
for (i = 0; i < 256; i++)
if (frequtable[i] != 0) {
p->de->frequ = -frequtable[i];
p->de->dict_leftson = -1;
p->de->dict_rightson = i;
p->de++;
}
frequcount = p->de - newdict;
for (i = 0; i < frequcount; i++) {
for (j = i + 1; j < frequcount; j++) {
if (newdict[i].frequ > newdict[j].frequ) {
k = newdict[i].frequ;
newdict[i].frequ = newdict[j].frequ;
newdict[j].frequ = k;
k = newdict[i].dict_leftson;
newdict[i].dict_leftson = newdict[j].dict_leftson;
newdict[j].dict_leftson = k;
k = newdict[i].dict_rightson;
newdict[i].dict_rightson = newdict[j].dict_rightson;
newdict[j].dict_rightson = k;
}
}
}
while (frequcount > 1) {
j = frequcount - 1;
p->de->frequ = newdict[j - 1].frequ;
p->de->dict_leftson = newdict[j - 1].dict_leftson;
p->de->dict_rightson = newdict[j - 1].dict_rightson;
l = newdict[j - 1].frequ + newdict[j].frequ;
for (i = j - 2; i >= 0 && l < newdict[i].frequ; i--)
newdict[i + 1] = newdict[i];
i = i + 1;
newdict[i].frequ = l;
newdict[i].dict_leftson = j;
newdict[i].dict_rightson = p->de - newdict;
p->de++;
frequcount--;
}
dictsize = p->de - newdict;
makecodes(0, 0, 0, 1, newdict, codes, codesize);
csize = 0;
for (i = 0; i < 256; i++)
csize += frequtable[i] * codesize[i];
l = (((csize + 31) >> 5) << 2) + 24 + dictsize * 4;
lsx_debug(" Original size: %6d bytes", *dl);
lsx_debug("Compressed size: %6d bytes", l);
datafork = lsx_malloc((size_t)l);
ddf = datafork + 22;
for(i = 0; i < dictsize; i++) {
put16_be(&ddf, newdict[i].dict_leftson);
put16_be(&ddf, newdict[i].dict_rightson);
}
*ddf++ = 0;
*ddf++ = *(*df)++;
p->new_checksum = 0;
p->nbits = 0;
p->curword = 0;
for (i = 1; i < *dl; i++)
putcode(ft, codes, codesize, *(*df)++, &ddf);
if (p->nbits != 0) {
codes[0] = 0;
codesize[0] = 32 - p->nbits;
putcode(ft, codes, codesize, 0, &ddf);
}
memcpy(datafork, "HCOM", (size_t)4);
dfp = datafork + 4;
put32_be(&dfp, *dl);
put32_be(&dfp, p->new_checksum);
put32_be(&dfp, 1);
samplerate = 22050 / ft->signal.rate + .5;
put32_be(&dfp, samplerate);
put16_be(&dfp, dictsize);
*df = datafork; /* reassign passed pointer to new datafork */
*dl = l; /* and its compressed length */
}
/* End of hcom utility routines */
static int stopwrite(sox_format_t * ft)
{
priv_t *p = (priv_t *) ft->priv;
unsigned char *compressed_data = p->data;
int32_t compressed_len = p->pos;
int rc = SOX_SUCCESS;
/* Compress it all at once */
if (compressed_len) {
compress(ft, &compressed_data, &compressed_len);
free(p->data);
}
/* Write the header */
lsx_writebuf(ft, "\000\001A", (size_t) 3); /* Dummy file name "A" */
lsx_padbytes(ft, (size_t) 65-3);
lsx_writes(ft, "FSSD");
lsx_padbytes(ft, (size_t) 83-69);
lsx_writedw(ft, (unsigned) compressed_len); /* compressed_data size */
lsx_writedw(ft, 0); /* rsrc size */
lsx_padbytes(ft, (size_t) 128 - 91);
if (lsx_error(ft)) {
lsx_fail_errno(ft, errno, "write error in HCOM header");
rc = SOX_EOF;
} else if (lsx_writebuf(ft, compressed_data, compressed_len) != compressed_len) {
/* Write the compressed_data fork */
lsx_fail_errno(ft, errno, "can't write compressed HCOM data");
rc = SOX_EOF;
}
free(compressed_data);
if (rc == SOX_SUCCESS)
/* Pad the compressed_data fork to a multiple of 128 bytes */
lsx_padbytes(ft, 128u - (compressed_len % 128));
return rc;
}
LSX_FORMAT_HANDLER(hcom)
{
static char const * const names[] = {"hcom", NULL};
static sox_rate_t const write_rates[] = {22050,22050/2,22050/3,22050/4.,0};
static unsigned const write_encodings[] = {
SOX_ENCODING_HCOM, 8, 0, 0};
static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE,
"Mac FSSD files with Huffman compression",
names, SOX_FILE_BIG_END|SOX_FILE_MONO,
startread, read_samples, stopread,
startwrite, write_samples, stopwrite,
NULL, write_encodings, write_rates, sizeof(priv_t)
};
return &handler;
}

@ -0,0 +1,102 @@
/* libSoX effect: Hilbert transform filter
*
* First version of this effect written 11/2011 by Ulrich Klauer, using maths
* from "Understanding digital signal processing" by Richard G. Lyons.
*
* Copyright 2011 Chris Bagwell and SoX Contributors
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
#include "dft_filter.h"
typedef struct {
dft_filter_priv_t base;
double *h;
int taps;
} priv_t;
static int getopts(sox_effect_t *effp, int argc, char **argv)
{
lsx_getopt_t optstate;
int c;
priv_t *p = (priv_t*)effp->priv;
dft_filter_priv_t *b = &p->base;
b->filter_ptr = &b->filter;
lsx_getopt_init(argc, argv, "+n:", NULL, lsx_getopt_flag_none, 1, &optstate);
while ((c = lsx_getopt(&optstate)) != -1) switch (c) {
GETOPT_NUMERIC(optstate, 'n', taps, 3, 32767)
default: lsx_fail("invalid option `-%c'", optstate.opt); return lsx_usage(effp);
}
if (p->taps && p->taps%2 == 0) {
lsx_fail("only filters with an odd number of taps are supported");
return SOX_EOF;
}
return optstate.ind != argc ? lsx_usage(effp) : SOX_SUCCESS;
}
static int start(sox_effect_t *effp)
{
priv_t *p = (priv_t*)effp->priv;
dft_filter_t *f = p->base.filter_ptr;
if (!f->num_taps) {
int i;
if (!p->taps) {
p->taps = effp->in_signal.rate/76.5 + 2;
p->taps += 1 - (p->taps%2);
/* results in a cutoff frequency of about 75 Hz with a Blackman window */
lsx_debug("choosing number of taps = %d (override with -n)", p->taps);
}
lsx_valloc(p->h, p->taps);
for (i = 0; i < p->taps; i++) {
int k = -(p->taps/2) + i;
if (k%2 == 0) {
p->h[i] = 0.0;
} else {
double pk = M_PI * k;
p->h[i] = (1 - cos(pk))/pk;
}
}
lsx_apply_blackman(p->h, p->taps, .16);
if (effp->global_info->plot != sox_plot_off) {
char title[100];
sprintf(title, "SoX effect: hilbert (%d taps)", p->taps);
lsx_plot_fir(p->h, p->taps, effp->in_signal.rate,
effp->global_info->plot, title, -20., 5.);
free(p->h);
return SOX_EOF;
}
lsx_set_dft_filter(f, p->h, p->taps, p->taps/2);
}
return lsx_dft_filter_effect_fn()->start(effp);
}
sox_effect_handler_t const *lsx_hilbert_effect_fn(void)
{
static sox_effect_handler_t handler;
handler = *lsx_dft_filter_effect_fn();
handler.name = "hilbert";
handler.usage = "[-n taps]";
handler.getopts = getopts;
handler.start = start;
handler.priv_size = sizeof(priv_t);
return &handler;
}

@ -0,0 +1,80 @@
/* libSoX file format: HTK (c) 2008 robs@users.sourceforge.net
*
* See http://labrosa.ee.columbia.edu/doc/HTKBook21/HTKBook.html
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
typedef enum {
Waveform, Lpc, Lprefc, Lpcepstra, Lpdelcep, Irefc,
Mfcc, Fbank, Melspec, User, Discrete, Unknown} kind_t;
static char const * const str[] = {
"Sampled waveform", "Linear prediction filter", "Linear prediction",
"LPC cepstral", "LPC cepstra plus delta", "LPC reflection coef in",
"Mel-frequency cepstral", "Log mel-filter bank", "Linear mel-filter bank",
"User defined sample", "Vector quantised data", "Unknown"};
static int start_read(sox_format_t * ft)
{
uint32_t period_100ns, num_samples;
uint16_t bytes_per_sample, parmKind;
if (lsx_readdw(ft, &num_samples ) ||
lsx_readdw(ft, &period_100ns ) ||
lsx_readw (ft, &bytes_per_sample) ||
lsx_readw (ft, &parmKind )) return SOX_EOF;
if (parmKind != Waveform) {
int n = min(parmKind & 077, Unknown);
lsx_fail_errno(ft, SOX_EFMT, "unsupported HTK type `%s' (0%o)", str[n], parmKind);
return SOX_EOF;
}
return lsx_check_read_params(ft, 1, 1e7 / period_100ns, SOX_ENCODING_SIGN2,
(unsigned)bytes_per_sample << 3, (uint64_t)num_samples, sox_true);
}
static int write_header(sox_format_t * ft)
{
double period_100ns = 1e7 / ft->signal.rate;
uint64_t len = ft->olength? ft->olength:ft->signal.length;
if (len > UINT_MAX)
{
lsx_warn("length greater than 32 bits - cannot fit actual length in header");
len = UINT_MAX;
}
if (!ft->olength && floor(period_100ns) != period_100ns)
lsx_warn("rounding sample period %f (x 100ns) to nearest integer", period_100ns);
return lsx_writedw(ft, (unsigned)len)
|| lsx_writedw(ft, (unsigned)(period_100ns + .5))
|| lsx_writew(ft, ft->encoding.bits_per_sample >> 3)
|| lsx_writew(ft, Waveform) ? SOX_EOF : SOX_SUCCESS;
}
LSX_FORMAT_HANDLER(htk)
{
static char const * const names[] = {"htk", NULL};
static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 16, 0, 0};
static sox_format_handler_t handler = {
SOX_LIB_VERSION_CODE,
"PCM format used for Hidden Markov Model speech processing",
names, SOX_FILE_BIG_END | SOX_FILE_MONO | SOX_FILE_REWIND,
start_read, lsx_rawread, NULL,
write_header, lsx_rawwrite, NULL,
lsx_rawseek, write_encodings, NULL, 0
};
return &handler;
}

@ -0,0 +1,227 @@
/* libSoX MP3 utilities Copyright (c) 2007-9 SoX contributors
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
#include "id3.h"
#ifdef HAVE_ID3TAG
#include <id3tag.h>
static char const * id3tagmap[][2] =
{
{"TIT2", "Title"},
{"TPE1", "Artist"},
{"TALB", "Album"},
{"TCOM", "Composer"},
{"TRCK", "Tracknumber"},
{"TDRC", "Year"},
{"TCON", "Genre"},
{"COMM", "Comment"},
{"TPOS", "Discnumber"},
{NULL, NULL}
};
static id3_utf8_t * utf8_id3tag_findframe(
struct id3_tag * tag, const char * const frameid, unsigned index)
{
struct id3_frame const * frame = id3_tag_findframe(tag, frameid, index);
if (frame) {
unsigned nfields = frame->nfields;
while (nfields--) {
union id3_field const *field = id3_frame_field(frame, nfields);
int ftype = id3_field_type(field);
const id3_ucs4_t *ucs4 = NULL;
unsigned nstrings;
switch (ftype) {
case ID3_FIELD_TYPE_STRING:
ucs4 = id3_field_getstring(field);
break;
case ID3_FIELD_TYPE_STRINGFULL:
ucs4 = id3_field_getfullstring(field);
break;
case ID3_FIELD_TYPE_STRINGLIST:
nstrings = id3_field_getnstrings(field);
while (nstrings--) {
ucs4 = id3_field_getstrings(field, nstrings);
if (ucs4)
break;
}
break;
}
if (ucs4)
return id3_ucs4_utf8duplicate(ucs4); /* Must call free() on this */
}
}
return NULL;
}
struct tag_info_node
{
struct tag_info_node * next;
off_t start;
off_t end;
};
struct tag_info {
sox_format_t * ft;
struct tag_info_node * head;
struct id3_tag * tag;
};
static int add_tag(struct tag_info * info)
{
struct tag_info_node * current;
off_t start, end;
id3_byte_t query[ID3_TAG_QUERYSIZE];
id3_byte_t * buffer;
long size;
int result = 0;
/* Ensure we're at the start of a valid tag and get its size. */
if (ID3_TAG_QUERYSIZE != lsx_readbuf(info->ft, query, ID3_TAG_QUERYSIZE) ||
!(size = id3_tag_query(query, ID3_TAG_QUERYSIZE))) {
return 0;
}
if (size < 0) {
if (0 != lsx_seeki(info->ft, size, SEEK_CUR) ||
ID3_TAG_QUERYSIZE != lsx_readbuf(info->ft, query, ID3_TAG_QUERYSIZE) ||
(size = id3_tag_query(query, ID3_TAG_QUERYSIZE)) <= 0) {
return 0;
}
}
/* Don't read a tag more than once. */
start = lsx_tell(info->ft);
end = start + size;
for (current = info->head; current; current = current->next) {
if (start == current->start && end == current->end) {
return 1;
} else if (start < current->end && current->start < end) {
return 0;
}
}
buffer = lsx_malloc((size_t)size);
if (!buffer) {
return 0;
}
memcpy(buffer, query, ID3_TAG_QUERYSIZE);
if ((unsigned long)size - ID3_TAG_QUERYSIZE ==
lsx_readbuf(info->ft, buffer + ID3_TAG_QUERYSIZE, (size_t)size - ID3_TAG_QUERYSIZE)) {
struct id3_tag * tag = id3_tag_parse(buffer, (size_t)size);
if (tag) {
current = lsx_malloc(sizeof(struct tag_info_node));
if (current) {
current->next = info->head;
current->start = start;
current->end = end;
info->head = current;
if (info->tag && (info->tag->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE)) {
struct id3_frame * frame;
unsigned i;
for (i = 0; (frame = id3_tag_findframe(tag, NULL, i)); i++) {
id3_tag_attachframe(info->tag, frame);
}
id3_tag_delete(tag);
} else {
if (info->tag) {
id3_tag_delete(info->tag);
}
info->tag = tag;
}
}
}
}
free(buffer);
return result;
}
void lsx_id3_read_tag(sox_format_t * ft, sox_bool search)
{
struct tag_info info;
id3_utf8_t * utf8;
int i;
int has_id3v1 = 0;
info.ft = ft;
info.head = NULL;
info.tag = NULL;
/*
We look for:
ID3v1 at end (EOF - 128).
ID3v2 at start.
ID3v2 at end (but before ID3v1 from end if there was one).
*/
if (search) {
if (0 == lsx_seeki(ft, -128, SEEK_END)) {
has_id3v1 =
add_tag(&info) &&
1 == ID3_TAG_VERSION_MAJOR(id3_tag_version(info.tag));
}
if (0 == lsx_seeki(ft, 0, SEEK_SET)) {
add_tag(&info);
}
if (0 == lsx_seeki(ft, has_id3v1 ? -138 : -10, SEEK_END)) {
add_tag(&info);
}
} else {
add_tag(&info);
}
if (info.tag && info.tag->frames) {
for (i = 0; id3tagmap[i][0]; ++i) {
if ((utf8 = utf8_id3tag_findframe(info.tag, id3tagmap[i][0], 0))) {
char * comment = lsx_malloc(strlen(id3tagmap[i][1]) + 1 + strlen((char *)utf8) + 1);
sprintf(comment, "%s=%s", id3tagmap[i][1], utf8);
sox_append_comment(&ft->oob.comments, comment);
free(comment);
free(utf8);
}
}
if ((utf8 = utf8_id3tag_findframe(info.tag, "TLEN", 0))) {
unsigned long tlen = strtoul((char *)utf8, NULL, 10);
if (tlen > 0 && tlen < ULONG_MAX) {
ft->signal.length= tlen; /* In ms; convert to samples later */
lsx_debug("got exact duration from ID3 TLEN");
}
free(utf8);
}
}
while (info.head) {
struct tag_info_node * head = info.head;
info.head = head->next;
free(head);
}
if (info.tag) {
id3_tag_delete(info.tag);
}
}
#else
/* Stub for format modules */
void lsx_id3_read_tag(sox_format_t *ft, sox_bool search) { }
#endif

@ -0,0 +1,25 @@
/* libSoX MP3 utilities Copyright (c) 2007-9 SoX contributors
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef SOX_ID3_H
#define SOX_ID3_H
#include "sox_i.h"
void lsx_id3_read_tag(sox_format_t *ft, sox_bool search);
#endif

@ -0,0 +1,33 @@
/* libSoX format: raw IMA ADPCM (c) 2007-8 SoX contributors
*
* 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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
#include "adpcms.h"
#include "vox.h"
LSX_FORMAT_HANDLER(ima)
{
static char const * const names[] = {"ima", NULL};
static unsigned const write_encodings[] = {SOX_ENCODING_IMA_ADPCM, 4, 0, 0};
static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE,
"Raw IMA ADPCM", names, SOX_FILE_MONO,
lsx_ima_start, lsx_vox_read, lsx_vox_stopread,
lsx_ima_start, lsx_vox_write, lsx_vox_stopwrite,
lsx_rawseek, write_encodings, NULL, sizeof(adpcm_io_t)
};
return &handler;
}

@ -0,0 +1,365 @@
/* libSoX ima_rw.c -- codex utilities for WAV_FORMAT_IMA_ADPCM
* Copyright (C) 1999 Stanley J. Brooks <stabro@megsinet.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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
#include "ima_rw.h"
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
/*
*
* Lookup tables for IMA ADPCM format
*
*/
#define ISSTMAX 88
static const int imaStepSizeTable[ISSTMAX + 1] = {
7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34,
37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143,
157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494,
544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552,
1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026,
4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442,
11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623,
27086, 29794, 32767
};
#define imaStateAdjust(c) (((c)<4)? -1:(2*(c)-6))
/* +0 - +3, decrease step size */
/* +4 - +7, increase step size */
/* -0 - -3, decrease step size */
/* -4 - -7, increase step size */
static unsigned char imaStateAdjustTable[ISSTMAX+1][8];
void lsx_ima_init_table(void)
{
int i,j,k;
for (i=0; i<=ISSTMAX; i++) {
for (j=0; j<8; j++) {
k = i + imaStateAdjust(j);
if (k<0) k=0;
else if (k>ISSTMAX) k=ISSTMAX;
imaStateAdjustTable[i][j] = k;
}
}
}
static void ImaExpandS(
unsigned ch, /* channel number to decode, REQUIRE 0 <= ch < chans */
unsigned chans, /* total channels */
const unsigned char *ibuff,/* input buffer[blockAlign] */
SAMPL *obuff, /* obuff[n] will be output samples */
int n, /* samples to decode PER channel, REQUIRE n % 8 == 1 */
unsigned o_inc /* index difference between successive output samples */
)
{
const unsigned char *ip;
int i_inc;
SAMPL *op;
int i, val, state;
ip = ibuff + 4*ch; /* input pointer to 4-byte block state-initializer */
i_inc = 4*(chans-1); /* amount by which to incr ip after each 4-byte read */
val = (short)(ip[0] + (ip[1]<<8)); /* need cast for sign-extend */
state = ip[2];
if (state > ISSTMAX) {
lsx_warn("IMA_ADPCM block ch%d initial-state (%d) out of range", ch, state);
state = 0;
}
/* specs say to ignore ip[3] , but write it as 0 */
ip += 4+i_inc;
op = obuff;
*op = val; /* 1st output sample for this channel */
op += o_inc;
for (i = 1; i < n; i++) {
int step,dp,c,cm;
if (i&1) { /* 1st of pair */
cm = *ip & 0x0f;
} else {
cm = (*ip++)>>4;
if ((i&7) == 0) /* ends the 8-sample input block for this channel */
ip += i_inc; /* skip ip for next group */
}
step = imaStepSizeTable[state];
/* Update the state for the next sample */
c = cm & 0x07;
state = imaStateAdjustTable[state][c];
dp = 0;
if (c & 4) dp += step;
step = step >> 1;
if (c & 2) dp += step;
step = step >> 1;
if (c & 1) dp += step;
step = step >> 1;
dp += step;
if (c != cm) {
val -= dp;
if (val<-0x8000) val = -0x8000;
} else {
val += dp;
if (val>0x7fff) val = 0x7fff;
}
*op = val;
op += o_inc;
}
return;
}
/* lsx_ima_block_expand_i() outputs interleaved samples into one output buffer */
void lsx_ima_block_expand_i(
unsigned chans, /* total channels */
const unsigned char *ibuff,/* input buffer[blockAlign] */
SAMPL *obuff, /* output samples, n*chans */
int n /* samples to decode PER channel, REQUIRE n % 8 == 1 */
)
{
unsigned ch;
for (ch=0; ch<chans; ch++)
ImaExpandS(ch, chans, ibuff, obuff+ch, n, chans);
}
/* lsx_ima_block_expand_m() outputs non-interleaved samples into chan separate output buffers */
void lsx_ima_block_expand_m(
unsigned chans, /* total channels */
const unsigned char *ibuff,/* input buffer[blockAlign] */
SAMPL **obuffs, /* chan output sample buffers, each takes n samples */
int n /* samples to decode PER channel, REQUIRE n % 8 == 1 */
)
{
unsigned ch;
for (ch=0; ch<chans; ch++)
ImaExpandS(ch, chans, ibuff, obuffs[ch], n, 1);
}
static int ImaMashS(
unsigned ch, /* channel number to encode, REQUIRE 0 <= ch < chans */
unsigned chans, /* total channels */
int v0, /* value to use as starting prediction0 */
const SAMPL *ibuff, /* ibuff[] is interleaved input samples */
int n, /* samples to encode PER channel, REQUIRE n % 8 == 1 */
int *st, /* input/output state, REQUIRE 0 <= *st <= ISSTMAX */
unsigned char *obuff /* output buffer[blockAlign], or NULL for no output */
)
{
const SAMPL *ip, *itop;
unsigned char *op;
int o_inc = 0; /* set 0 only to shut up gcc's 'might be uninitialized' */
int i, val;
int state;
double d2; /* long long is okay also, speed abt the same */
ip = ibuff + ch; /* point ip to 1st input sample for this channel */
itop = ibuff + n*chans;
val = *ip - v0; ip += chans;/* 1st input sample for this channel */
d2 = val*val;/* d2 will be sum of squares of errors, given input v0 and *st */
val = v0;
op = obuff; /* output pointer (or NULL) */
if (op) { /* NULL means don't output, just compute the rms error */
op += 4*ch; /* where to put this channel's 4-byte block state-initializer */
o_inc = 4*(chans-1); /* amount by which to incr op after each 4-byte written */
*op++ = val; *op++ = val>>8;
*op++ = *st; *op++ = 0; /* they could have put a mid-block state-correction here */
op += o_inc; /* _sigh_ NEVER waste a byte. It's a rule! */
}
state = *st;
for (i = 0; ip < itop; ip+=chans) {
int step,d,dp,c;
d = *ip - val; /* difference between last prediction and current sample */
step = imaStepSizeTable[state];
c = (abs(d)<<2)/step;
if (c > 7) c = 7;
/* Update the state for the next sample */
state = imaStateAdjustTable[state][c];
if (op) { /* if we want output, put it in proper place */
int cm = c;
if (d<0) cm |= 8;
if (i&1) { /* odd numbered output */
*op++ |= (cm<<4);
if (i == 7) /* ends the 8-sample output block for this channel */
op += o_inc; /* skip op for next group */
} else {
*op = cm;
}
i = (i+1) & 0x07;
}
dp = 0;
if (c & 4) dp += step;
step = step >> 1;
if (c & 2) dp += step;
step = step >> 1;
if (c & 1) dp += step;
step = step >> 1;
dp += step;
if (d<0) {
val -= dp;
if (val<-0x8000) val = -0x8000;
} else {
val += dp;
if (val>0x7fff) val = 0x7fff;
}
{
int x = *ip - val;
d2 += x*x;
}
}
d2 /= n; /* be sure it's non-negative */
*st = state;
return (int) sqrt(d2);
}
/* mash one channel... if you want to use opt>0, 9 is a reasonable value */
inline static void ImaMashChannel(
unsigned ch, /* channel number to encode, REQUIRE 0 <= ch < chans */
unsigned chans, /* total channels */
const SAMPL *ip, /* ip[] is interleaved input samples */
int n, /* samples to encode PER channel, REQUIRE n % 8 == 1 */
int *st, /* input/output state, REQUIRE 0 <= *st <= ISSTMAX */
unsigned char *obuff, /* output buffer[blockAlign] */
int opt /* non-zero allows some cpu-intensive code to improve output */
)
{
int snext;
int s0,d0;
s0 = *st;
if (opt>0) {
int low,hi,w;
int low0,hi0;
snext = s0;
d0 = ImaMashS(ch, chans, ip[ch], ip,n,&snext, NULL);
w = 0;
low=hi=s0;
low0 = low-opt; if (low0<0) low0=0;
hi0 = hi+opt; if (hi0>ISSTMAX) hi0=ISSTMAX;
while (low>low0 || hi<hi0) {
if (!w && low>low0) {
int d2;
snext = --low;
d2 = ImaMashS(ch, chans, ip[ch], ip,n,&snext, NULL);
if (d2<d0) {
d0=d2; s0=low;
low0 = low-opt; if (low0<0) low0=0;
hi0 = low+opt; if (hi0>ISSTMAX) hi0=ISSTMAX;
}
}
if (w && hi<hi0) {
int d2;
snext = ++hi;
d2 = ImaMashS(ch, chans, ip[ch], ip,n,&snext, NULL);
if (d2<d0) {
d0=d2; s0=hi;
low0 = hi-opt; if (low0<0) low0=0;
hi0 = hi+opt; if (hi0>ISSTMAX) hi0=ISSTMAX;
}
}
w=1-w;
}
*st = s0;
}
ImaMashS(ch, chans, ip[ch], ip,n,st, obuff);
}
/* mash one block. if you want to use opt>0, 9 is a reasonable value */
void lsx_ima_block_mash_i(
unsigned chans, /* total channels */
const SAMPL *ip, /* ip[] is interleaved input samples */
int n, /* samples to encode PER channel, REQUIRE n % 8 == 1 */
int *st, /* input/output state, REQUIRE 0 <= *st <= ISSTMAX */
unsigned char *obuff, /* output buffer[blockAlign] */
int opt /* non-zero allows some cpu-intensive code to improve output */
)
{
unsigned ch;
for (ch=0; ch<chans; ch++)
ImaMashChannel(ch, chans, ip, n, st+ch, obuff, opt);
}
/*
* lsx_ima_samples_in(dataLen, chans, blockAlign, samplesPerBlock)
* returns the number of samples/channel which would go
* in the dataLen, given the other parameters ...
* if input samplesPerBlock is 0, then returns the max
* samplesPerBlock which would go into a block of size blockAlign
* Yes, it is confusing.
*/
size_t lsx_ima_samples_in(
size_t dataLen,
size_t chans,
size_t blockAlign,
size_t samplesPerBlock
)
{
size_t m, n;
if (samplesPerBlock) {
n = (dataLen / blockAlign) * samplesPerBlock;
m = (dataLen % blockAlign);
} else {
n = 0;
m = blockAlign;
}
if (m >= (size_t)4*chans) {
m -= 4*chans; /* number of bytes beyond block-header */
m /= 4*chans; /* number of 4-byte blocks/channel beyond header */
m = 8*m + 1; /* samples/chan beyond header + 1 in header */
if (samplesPerBlock && m > samplesPerBlock) m = samplesPerBlock;
n += m;
}
return n;
/*wSamplesPerBlock = ((wBlockAlign - 4*wChannels)/(4*wChannels))*8 + 1;*/
}
/*
* size_t lsx_ima_bytes_per_block(chans, samplesPerBlock)
* return minimum blocksize which would be required
* to encode number of chans with given samplesPerBlock
*/
size_t lsx_ima_bytes_per_block(
size_t chans,
size_t samplesPerBlock
)
{
size_t n;
/* per channel, ima has blocks of len 4, the 1st has 1st sample, the others
* up to 8 samples per block,
* so number of later blocks is (nsamp-1 + 7)/8, total blocks/chan is
* (nsamp-1+7)/8 + 1 = (nsamp+14)/8
*/
n = ((size_t)samplesPerBlock + 14)/8 * 4 * chans;
return n;
}

@ -0,0 +1,84 @@
/* libSoX ima_rw.h -- codex utilities for WAV_FORMAT_IMA_ADPCM
* Copyright (C) 1999 Stanley J. Brooks <stabro@megsinet.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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox.h"
#ifndef SAMPL
#define SAMPL short
#endif
/*
* call lsx_ima_init_table() before any other Ima* functions,
* to create the fast lookup tables
*/
extern void lsx_ima_init_table(void);
/* lsx_ima_block_expand_i() outputs interleaved samples into one output buffer */
extern void lsx_ima_block_expand_i(
unsigned chans, /* total channels */
const unsigned char *ibuff,/* input buffer[blockAlign] */
SAMPL *obuff, /* output samples, n*chans */
int n /* samples to decode PER channel, REQUIRE n % 8 == 1 */
);
/* lsx_ima_block_expand_m() outputs non-interleaved samples into chan separate output buffers */
extern void lsx_ima_block_expand_m(
unsigned chans, /* total channels */
const unsigned char *ibuff,/* input buffer[blockAlign] */
SAMPL **obuffs, /* chan output sample buffers, each takes n samples */
int n /* samples to decode PER channel, REQUIRE n % 8 == 1 */
);
/* mash one block. if you want to use opt>0, 9 is a reasonable value */
extern void lsx_ima_block_mash_i(
unsigned chans, /* total channels */
const SAMPL *ip, /* ip[] is interleaved input samples */
int n, /* samples to encode PER channel, REQUIRE n % 8 == 1 */
int *st, /* input/output state[chans], REQUIRE 0 <= st[ch] <= ISSTMAX */
unsigned char *obuff, /* output buffer[blockAlign] */
int opt /* non-zero allows some cpu-intensive code to improve output */
);
/* Some helper functions for computing samples/block and blockalign */
/*
* lsx_ima_samples_in(dataLen, chans, blockAlign, samplesPerBlock)
* returns the number of samples/channel which would go
* in the dataLen, given the other parameters ...
* if input samplesPerBlock is 0, then returns the max
* samplesPerBlock which would go into a block of size blockAlign
* Yes, it is confusing usage.
*/
extern size_t lsx_ima_samples_in(
size_t dataLen,
size_t chans,
size_t blockAlign,
size_t samplesPerBlock
);
/*
* size_t lsx_ima_bytes_per_block(chans, samplesPerBlock)
* return minimum blocksize which would be required
* to encode number of chans with given samplesPerBlock
*/
extern size_t lsx_ima_bytes_per_block(
size_t chans,
size_t samplesPerBlock
);

@ -0,0 +1,58 @@
/* libSoX effect: Input audio from a file (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.1 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,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "sox_i.h"
typedef struct {sox_format_t * file;} priv_t;
static int getopts(sox_effect_t * effp, int argc, char * * argv)
{
priv_t * p = (priv_t *)effp->priv;
if (argc != 2 || !(p->file = (sox_format_t *)argv[1]) || p->file->mode != 'r')
return SOX_EOF;
return SOX_SUCCESS;
}
static int drain(
sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp)
{
priv_t * p = (priv_t *)effp->priv;
/* ensure that *osamp is a multiple of the number of channels. */
*osamp -= *osamp % effp->out_signal.channels;
/* Read up to *osamp samples into obuf; store the actual number read
* back to *osamp */
*osamp = sox_read(p->file, obuf, *osamp);
/* sox_read may return a number that is less than was requested; only if
* 0 samples is returned does it indicate that end-of-file has been reached
* or an error has occurred */
if (!*osamp && p->file->sox_errno)
lsx_fail("%s: %s", p->file->filename, p->file->sox_errstr);
return *osamp? SOX_SUCCESS : SOX_EOF;
}
sox_effect_handler_t const * lsx_input_effect_fn(void)
{
static sox_effect_handler_t handler = {
"input", NULL, SOX_EFF_MCHAN | SOX_EFF_LENGTH | SOX_EFF_INTERNAL,
getopts, NULL, NULL, drain, NULL, NULL, sizeof(priv_t)
};
return &handler;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save