parent
1e632fd324
commit
c918001551
@ -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, (¶ms)); |
||||||
|
_(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…
Reference in new issue