parent
1ad8783ff7
commit
c21a2cf584
@ -1,72 +0,0 @@ |
||||
|
||||
set(PROJECT_NAME sox) |
||||
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR}) |
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCC) |
||||
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion |
||||
OUTPUT_VARIABLE ver) |
||||
string(REGEX REPLACE "([0-9]+)\\.([0-9]+).*" "\\1" major "${ver}") |
||||
string(REGEX REPLACE "([0-9]+)\\.([0-9]+).*" "\\2" minor "${ver}") |
||||
math(EXPR ver "100 * ${major} + ${minor}") |
||||
if(${ver} LESS 403) |
||||
add_definitions(-Wconversion) |
||||
else(${ver} LESS 403) |
||||
add_definitions(-Wtraditional-conversion) |
||||
endif(${ver} LESS 403) |
||||
endif(CMAKE_COMPILER_IS_GNUCC) |
||||
|
||||
if (NOT EXTERNAL_GSM) |
||||
set(optional_libs ${optional_libs} gsm) |
||||
endif (NOT EXTERNAL_GSM) |
||||
|
||||
set(effects_srcs |
||||
delay.c |
||||
downsample.c |
||||
echo.c |
||||
echos.c |
||||
fft4g.c |
||||
input.c |
||||
output.c |
||||
reverb.c |
||||
speed.c |
||||
tempo.c |
||||
upsample.c |
||||
vad.c |
||||
vol.c |
||||
) |
||||
set(formats_srcs |
||||
adpcm.c |
||||
g711.c |
||||
ima_rw.c |
||||
raw.c |
||||
wav.c |
||||
) |
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/bit-rot) |
||||
|
||||
add_library(${PROJECT_NAME} STATIC |
||||
${effects_srcs} |
||||
effects.c |
||||
effects_i.c |
||||
effects_i_dsp.c |
||||
${formats_srcs} |
||||
formats_i.c |
||||
formats.c |
||||
getopt.c |
||||
libsox_i.c |
||||
libsox.c |
||||
util.c |
||||
xmalloc.c |
||||
) |
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) |
||||
|
||||
find_program(LN ln) |
||||
if (LN) |
||||
add_custom_target(rec ALL ${LN} -sf sox rec DEPENDS sox) |
||||
add_custom_target(play ALL ${LN} -sf sox play DEPENDS sox) |
||||
add_custom_target(soxi ALL ${LN} -sf sox soxi DEPENDS sox) |
||||
endif (LN) |
||||
find_program(CTAGS NAMES exuberant-ctags ctags) |
||||
add_custom_target(tags ${CTAGS} --recurse --extra=fq .) |
@ -1,367 +0,0 @@ |
||||
/* 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; |
||||
} |
||||
|
@ -1,79 +0,0 @@ |
||||
/* 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 |
||||
); |
@ -1,163 +0,0 @@ |
||||
/* 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; |
||||
} |
@ -1,85 +0,0 @@ |
||||
/* 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; |
||||
} |
@ -1,266 +0,0 @@ |
||||
/* 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; |
||||
} |
@ -1,278 +0,0 @@ |
||||
/* 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; |
||||
} |
@ -1,669 +0,0 @@ |
||||
/* 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; |
||||
} |
||||
} |
||||
} |
@ -1,38 +0,0 @@ |
||||
/* 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(delay) |
||||
EFFECT(downsample) |
||||
EFFECT(echo) |
||||
EFFECT(echos) |
||||
EFFECT(input) |
||||
#ifdef HAVE_LADSPA_H |
||||
EFFECT(ladspa) |
||||
#endif |
||||
EFFECT(output) |
||||
EFFECT(reverb) |
||||
#ifdef HAVE_PNG |
||||
EFFECT(spectrogram) |
||||
#endif |
||||
EFFECT(speed) |
||||
#ifdef HAVE_SPEEXDSP |
||||
EFFECT(speexdsp) |
||||
#endif |
||||
EFFECT(tempo) |
||||
EFFECT(upsample) |
||||
EFFECT(vad) |
||||
EFFECT(vol) |
@ -1,483 +0,0 @@ |
||||
/* 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; |
||||
} |
@ -1,645 +0,0 @@ |
||||
/* 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 |
@ -1,102 +0,0 @@ |
||||
/* 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); |
||||
|
||||
args[0] = "--wet-only"; |
||||
args[1] = "50"; // reverberance [0, 100] 50%
|
||||
args[2] = "50"; // hf_damping [0, 100] 50%
|
||||
args[3] = "100"; // room_scale [0, 100] 100%
|
||||
args[4] = "100"; // stereo_depth [0, 100] 100%
|
||||
args[5] = "0"; // pre_delay_ms [0, 500] 0ms
|
||||
args[6] = "0"; // wet_gain_dB [-10, 10] 0dB
|
||||
e = sox_create_effect(sox_find_effect("reverb")); |
||||
assert(sox_effect_options(e, 7, args) == SOX_SUCCESS); |
||||
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; |
||||
} |
@ -1,167 +0,0 @@ |
||||
/* 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; |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -1,37 +0,0 @@ |
||||
/* 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; |
@ -1,119 +0,0 @@ |
||||
/* 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 |
File diff suppressed because it is too large
Load Diff
@ -1,130 +0,0 @@ |
||||
/* 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 |
@ -1,545 +0,0 @@ |
||||
/* 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
@ -1,21 +0,0 @@ |
||||
/* 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]) |
@ -1,349 +0,0 @@ |
||||
/* 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 */ |
@ -1,365 +0,0 @@ |
||||
/* 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; |
||||
} |
@ -1,84 +0,0 @@ |
||||
/* 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 |
||||
); |
||||
|
@ -1,58 +0,0 @@ |
||||
/* 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; |
||||
} |
||||
|
@ -1,224 +0,0 @@ |
||||
/* Implements the public API for libSoX general functions
|
||||
* All public functions & data are prefixed with sox_ . |
||||
* |
||||
* (c) 2006-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> |
||||
|
||||
const char *sox_version(void) |
||||
{ |
||||
static char versionstr[20]; |
||||
|
||||
sprintf(versionstr, "%d.%d.%d", |
||||
(SOX_LIB_VERSION_CODE & 0xff0000) >> 16, |
||||
(SOX_LIB_VERSION_CODE & 0x00ff00) >> 8, |
||||
(SOX_LIB_VERSION_CODE & 0x0000ff)); |
||||
return(versionstr); |
||||
} |
||||
|
||||
sox_version_info_t const * sox_version_info(void) |
||||
{ |
||||
#define STRINGIZE1(x) #x |
||||
#define STRINGIZE(x) STRINGIZE1(x) |
||||
static char arch[30]; |
||||
static sox_version_info_t info = { |
||||
/* size */ |
||||
sizeof(sox_version_info_t), |
||||
/* flags */ |
||||
(sox_version_flags_t)( |
||||
#if HAVE_POPEN |
||||
sox_version_have_popen + |
||||
#endif |
||||
#if HAVE_MAGIC |
||||
sox_version_have_magic + |
||||
#endif |
||||
#if HAVE_OPENMP |
||||
sox_version_have_threads + |
||||
#endif |
||||
#ifdef HAVE_FMEMOPEN |
||||
sox_version_have_memopen + |
||||
#endif |
||||
sox_version_none), |
||||
/* version_code */ |
||||
SOX_LIB_VERSION_CODE, |
||||
/* version */ |
||||
NULL, |
||||
/* sox_version_extra */ |
||||
#ifdef PACKAGE_EXTRA |
||||
PACKAGE_EXTRA, |
||||
#else |
||||
NULL, |
||||
#endif |
||||
/* sox_time */ |
||||
__DATE__ " " __TIME__, |
||||
/* sox_distro */ |
||||
#ifdef DISTRO |
||||
DISTRO, |
||||
#else |
||||
NULL, |
||||
#endif |
||||
/* sox_compiler */ |
||||
#if defined __GNUC__ |
||||
"gcc " __VERSION__, |
||||
#elif defined _MSC_VER |
||||
"msvc " STRINGIZE(_MSC_FULL_VER), |
||||
#elif defined __SUNPRO_C |
||||
fprintf(file, "sun c " STRINGIZE(__SUNPRO_C), |
||||
#else |
||||
NULL, |
||||
#endif |
||||
/* sox_arch */ |
||||
NULL |
||||
}; |
||||
|
||||
if (!info.version) |
||||
{ |
||||
info.version = sox_version(); |
||||
} |
||||
|
||||
if (!info.arch) |
||||
{ |
||||
snprintf(arch, sizeof(arch), |
||||
"%" PRIuPTR "%" PRIuPTR "%" PRIuPTR "%" PRIuPTR |
||||
" %" PRIuPTR "%" PRIuPTR " %" PRIuPTR "%" PRIuPTR " %c %s", |
||||
sizeof(char), sizeof(short), sizeof(long), sizeof(off_t), |
||||
sizeof(float), sizeof(double), sizeof(int *), sizeof(int (*)(void)), |
||||
MACHINE_IS_BIGENDIAN ? 'B' : 'L', |
||||
(info.flags & sox_version_have_threads) ? "OMP" : ""); |
||||
arch[sizeof(arch) - 1] = 0; |
||||
info.arch = arch; |
||||
} |
||||
|
||||
return &info; |
||||
} |
||||
|
||||
/* Default routine to output messages; can be overridden */ |
||||
static void output_message( |
||||
unsigned level, const char *filename, const char *fmt, va_list ap) |
||||
{ |
||||
if (sox_globals.verbosity >= level) { |
||||
char base_name[128]; |
||||
sox_basename(base_name, sizeof(base_name), filename); |
||||
fprintf(stderr, "%s: ", base_name); |
||||
vfprintf(stderr, fmt, ap); |
||||
fprintf(stderr, "\n"); |
||||
} |
||||
} |
||||
|
||||
static sox_globals_t s_sox_globals = { |
||||
2, /* unsigned verbosity */ |
||||
output_message, /* sox_output_message_handler */ |
||||
sox_false, /* sox_bool repeatable */ |
||||
8192, /* size_t bufsiz */ |
||||
0, /* size_t input_bufsiz */ |
||||
0, /* int32_t ranqd1 */ |
||||
NULL, /* char const * stdin_in_use_by */ |
||||
NULL, /* char const * stdout_in_use_by */ |
||||
NULL, /* char const * subsystem */ |
||||
NULL, /* char * tmp_path */ |
||||
sox_false, /* sox_bool use_magic */ |
||||
sox_false, /* sox_bool use_threads */ |
||||
10 /* size_t log2_dft_min_size */ |
||||
}; |
||||
|
||||
sox_globals_t * sox_get_globals(void) |
||||
{ |
||||
return &s_sox_globals; |
||||
} |
||||
|
||||
/* FIXME: Not thread safe using globals */ |
||||
static sox_effects_globals_t s_sox_effects_globals = |
||||
{sox_plot_off, &s_sox_globals}; |
||||
|
||||
sox_effects_globals_t * |
||||
sox_get_effects_globals(void) |
||||
{ |
||||
return &s_sox_effects_globals; |
||||
} |
||||
|
||||
char const * sox_strerror(int sox_errno) |
||||
{ |
||||
static char const * const errors[] = { |
||||
"Invalid Audio Header", |
||||
"Unsupported data format", |
||||
"Can't allocate memory", |
||||
"Operation not permitted", |
||||
"Operation not supported", |
||||
"Invalid argument", |
||||
}; |
||||
if (sox_errno < SOX_EHDR) |
||||
return strerror(sox_errno); |
||||
sox_errno -= SOX_EHDR; |
||||
if (sox_errno < 0 || (size_t)sox_errno >= array_length(errors)) |
||||
return "Unknown error"; |
||||
return errors[sox_errno]; |
||||
} |
||||
|
||||
size_t sox_basename(char * base_buffer, size_t base_buffer_len, const char * filename) |
||||
{ |
||||
if (!base_buffer || !base_buffer_len) |
||||
{ |
||||
return 0; |
||||
} |
||||
else |
||||
{ |
||||
char const * slash_pos = LAST_SLASH(filename); |
||||
char const * base_name = slash_pos ? slash_pos + 1 : filename; |
||||
char const * dot_pos = strrchr(base_name, '.'); |
||||
size_t i, len; |
||||
dot_pos = dot_pos ? dot_pos : base_name + strlen(base_name); |
||||
len = dot_pos - base_name; |
||||
len = min(len, base_buffer_len - 1); |
||||
for (i = 0; i < len; i++) |
||||
{ |
||||
base_buffer[i] = base_name[i]; |
||||
} |
||||
base_buffer[i] = 0; |
||||
return i; |
||||
} |
||||
} |
||||
|
||||
#define SOX_MESSAGE_FUNCTION(name,level) \ |
||||
void name(char const * fmt, ...) { \
|
||||
va_list ap; \
|
||||
va_start(ap, fmt); \
|
||||
if (sox_globals.output_message_handler) \
|
||||
(*sox_globals.output_message_handler)(level,sox_globals.subsystem,fmt,ap); \
|
||||
va_end(ap); \
|
||||
} |
||||
|
||||
SOX_MESSAGE_FUNCTION(lsx_fail_impl , 1) |
||||
SOX_MESSAGE_FUNCTION(lsx_warn_impl , 2) |
||||
SOX_MESSAGE_FUNCTION(lsx_report_impl, 3) |
||||
SOX_MESSAGE_FUNCTION(lsx_debug_impl , 4) |
||||
SOX_MESSAGE_FUNCTION(lsx_debug_more_impl , 5) |
||||
SOX_MESSAGE_FUNCTION(lsx_debug_most_impl , 6) |
||||
|
||||
#undef SOX_MESSAGE_FUNCTION |
||||
|
||||
int sox_init(void) |
||||
{ |
||||
return lsx_effects_init(); |
||||
} |
||||
|
||||
int sox_quit(void) |
||||
{ |
||||
sox_format_quit(); |
||||
return lsx_effects_quit(); |
||||
} |
@ -1,116 +0,0 @@ |
||||
/* libSoX internal functions that apply to both formats and effects
|
||||
* All public functions & data are prefixed with lsx_ . |
||||
* |
||||
* 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" |
||||
|
||||
#ifdef HAVE_IO_H |
||||
#include <io.h> |
||||
#endif |
||||
|
||||
#ifdef HAVE_UNISTD_H |
||||
#include <unistd.h> |
||||
#endif |
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__) |
||||
#define MKTEMP_X _O_BINARY|_O_TEMPORARY |
||||
#else |
||||
#define MKTEMP_X 0 |
||||
#endif |
||||
|
||||
#ifndef HAVE_MKSTEMP |
||||
#include <fcntl.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#define mkstemp(t) open(mktemp(t), MKTEMP_X|O_RDWR|O_TRUNC|O_CREAT, S_IREAD|S_IWRITE) |
||||
#define FAKE_MKSTEMP "fake " |
||||
#else |
||||
#define FAKE_MKSTEMP |
||||
#endif |
||||
|
||||
#ifdef WIN32 |
||||
static int check_dir(char * buf, size_t buflen, char const * name) |
||||
{ |
||||
struct stat st; |
||||
if (!name || stat(name, &st) || (st.st_mode & S_IFMT) != S_IFDIR) |
||||
{ |
||||
return 0; |
||||
} |
||||
else |
||||
{ |
||||
strncpy(buf, name, buflen); |
||||
buf[buflen - 1] = 0; |
||||
return strlen(name) == strlen(buf); |
||||
} |
||||
} |
||||
#endif |
||||
|
||||
FILE * lsx_tmpfile(void) |
||||
{ |
||||
char const * path = sox_globals.tmp_path; |
||||
|
||||
/*
|
||||
On Win32, tmpfile() is broken - it creates the file in the root directory of |
||||
the current drive (the user probably doesn't have permission to write there!) |
||||
instead of in a valid temporary directory (like TEMP or TMP). So if tmp_path |
||||
is null, figure out a reasonable default. |
||||
To force use of tmpfile(), set sox_globals.tmp_path = "". |
||||
*/ |
||||
#ifdef WIN32 |
||||
if (!path) |
||||
{ |
||||
static char default_path[260] = ""; |
||||
if (default_path[0] == 0 |
||||
&& !check_dir(default_path, sizeof(default_path), getenv("TEMP")) |
||||
&& !check_dir(default_path, sizeof(default_path), getenv("TMP")) |
||||
#ifdef __CYGWIN__ |
||||
&& !check_dir(default_path, sizeof(default_path), "/tmp") |
||||
#endif |
||||
) |
||||
{ |
||||
strcpy(default_path, "."); |
||||
} |
||||
|
||||
path = default_path; |
||||
} |
||||
#endif |
||||
|
||||
if (path && path[0]) { |
||||
/* Emulate tmpfile (delete on close); tmp dir is given tmp_path: */ |
||||
char const * const end = "/libSoX.tmp.XXXXXX"; |
||||
char * name = lsx_malloc(strlen(path) + strlen(end) + 1); |
||||
int fildes; |
||||
strcpy(name, path); |
||||
strcat(name, end); |
||||
fildes = mkstemp(name); |
||||
#ifdef HAVE_UNISTD_H |
||||
lsx_debug(FAKE_MKSTEMP "mkstemp, name=%s (unlinked)", name); |
||||
unlink(name); |
||||
#else |
||||
lsx_debug(FAKE_MKSTEMP "mkstemp, name=%s (O_TEMPORARY)", name); |
||||
#endif |
||||
free(name); |
||||
return fildes == -1? NULL : fdopen(fildes, "w+b"); |
||||
} |
||||
|
||||
/* Use standard tmpfile (delete on close); tmp dir is undefined: */ |
||||
lsx_debug("tmpfile()"); |
||||
return tmpfile(); |
||||
} |
@ -1,59 +0,0 @@ |
||||
/* libSoX effect: Output audio to 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 != 'w') |
||||
return SOX_EOF; |
||||
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 * p = (priv_t *)effp->priv; |
||||
/* Write out *isamp samples */ |
||||
size_t len = sox_write(p->file, 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) { |
||||
lsx_fail("%s: %s", p->file->filename, p->file->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!) */ |
||||
(void)obuf, *osamp = 0; |
||||
return SOX_SUCCESS; /* All samples output successfully */ |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_output_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"output", NULL, SOX_EFF_MCHAN | SOX_EFF_INTERNAL, |
||||
getopts, NULL, flow, NULL, NULL, NULL, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
||||
|
@ -1,196 +0,0 @@ |
||||
/* libSoX raw I/O
|
||||
* |
||||
* Copyright 1991-2007 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. |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "g711.h" |
||||
|
||||
typedef sox_uint16_t sox_uint14_t; |
||||
typedef sox_uint16_t sox_uint13_t; |
||||
typedef sox_int16_t sox_int14_t; |
||||
typedef sox_int16_t sox_int13_t; |
||||
#define SOX_ULAW_BYTE_TO_SAMPLE(d,clips) SOX_SIGNED_16BIT_TO_SAMPLE(sox_ulaw2linear16(d),clips) |
||||
#define SOX_ALAW_BYTE_TO_SAMPLE(d,clips) SOX_SIGNED_16BIT_TO_SAMPLE(sox_alaw2linear16(d),clips) |
||||
#define SOX_SAMPLE_TO_ULAW_BYTE(d,c) sox_14linear2ulaw(SOX_SAMPLE_TO_UNSIGNED(14,d,c) - 0x2000) |
||||
#define SOX_SAMPLE_TO_ALAW_BYTE(d,c) sox_13linear2alaw(SOX_SAMPLE_TO_UNSIGNED(13,d,c) - 0x1000) |
||||
|
||||
int lsx_rawseek(sox_format_t * ft, uint64_t offset) |
||||
{ |
||||
return lsx_offset_seek(ft, (off_t)ft->data_start, (off_t)offset); |
||||
} |
||||
|
||||
/* Works nicely for starting read and write; lsx_rawstart{read,write}
|
||||
* are #defined in sox_i.h */ |
||||
int lsx_rawstart(sox_format_t * ft, sox_bool default_rate, |
||||
sox_bool default_channels, sox_bool default_length, |
||||
sox_encoding_t encoding, unsigned size) |
||||
{ |
||||
if (default_rate && ft->signal.rate == 0) { |
||||
lsx_warn("`%s': sample rate not specified; trying 8kHz", ft->filename); |
||||
ft->signal.rate = 8000; |
||||
} |
||||
|
||||
if (default_channels && ft->signal.channels == 0) { |
||||
lsx_warn("`%s': # channels not specified; trying mono", ft->filename); |
||||
ft->signal.channels = 1; |
||||
} |
||||
|
||||
if (encoding != SOX_ENCODING_UNKNOWN) { |
||||
if (ft->mode == 'r' && ft->encoding.encoding != SOX_ENCODING_UNKNOWN && |
||||
ft->encoding.encoding != encoding) |
||||
lsx_report("`%s': Format options overriding file-type encoding", |
||||
ft->filename); |
||||
else |
||||
ft->encoding.encoding = encoding; |
||||
} |
||||
|
||||
if (size != 0) { |
||||
if (ft->mode == 'r' && ft->encoding.bits_per_sample != 0 && |
||||
ft->encoding.bits_per_sample != size) |
||||
lsx_report("`%s': Format options overriding file-type sample-size", |
||||
ft->filename); |
||||
else |
||||
ft->encoding.bits_per_sample = size; |
||||
} |
||||
|
||||
if (!ft->signal.length && ft->mode == 'r' && default_length && |
||||
ft->encoding.bits_per_sample) |
||||
ft->signal.length = |
||||
div_bits(lsx_filelength(ft), ft->encoding.bits_per_sample); |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
#define READ_SAMPLES_FUNC(type, size, sign, ctype, uctype, cast) \ |
||||
static size_t sox_read_ ## sign ## type ## _samples( \
|
||||
sox_format_t * ft, sox_sample_t *buf, size_t len) \
|
||||
{ \
|
||||
size_t n, nread; \
|
||||
SOX_SAMPLE_LOCALS; \
|
||||
ctype *data = lsx_malloc(sizeof(ctype) * len); \
|
||||
LSX_USE_VAR(sox_macro_temp_sample), LSX_USE_VAR(sox_macro_temp_double); \
|
||||
nread = lsx_read_ ## type ## _buf(ft, (uctype *)data, len); \
|
||||
for (n = 0; n < nread; n++) \
|
||||
*buf++ = cast(data[n], ft->clips); \
|
||||
free(data); \
|
||||
return nread; \
|
||||
} |
||||
|
||||
READ_SAMPLES_FUNC(b, 1, u, uint8_t, uint8_t, SOX_UNSIGNED_8BIT_TO_SAMPLE) |
||||
READ_SAMPLES_FUNC(b, 1, s, int8_t, uint8_t, SOX_SIGNED_8BIT_TO_SAMPLE) |
||||
READ_SAMPLES_FUNC(b, 1, ulaw, uint8_t, uint8_t, SOX_ULAW_BYTE_TO_SAMPLE) |
||||
READ_SAMPLES_FUNC(b, 1, alaw, uint8_t, uint8_t, SOX_ALAW_BYTE_TO_SAMPLE) |
||||
READ_SAMPLES_FUNC(w, 2, u, uint16_t, uint16_t, SOX_UNSIGNED_16BIT_TO_SAMPLE) |
||||
READ_SAMPLES_FUNC(w, 2, s, int16_t, uint16_t, SOX_SIGNED_16BIT_TO_SAMPLE) |
||||
READ_SAMPLES_FUNC(3, 3, u, sox_uint24_t, sox_uint24_t, SOX_UNSIGNED_24BIT_TO_SAMPLE) |
||||
READ_SAMPLES_FUNC(3, 3, s, sox_int24_t, sox_uint24_t, SOX_SIGNED_24BIT_TO_SAMPLE) |
||||
READ_SAMPLES_FUNC(dw, 4, u, uint32_t, uint32_t, SOX_UNSIGNED_32BIT_TO_SAMPLE) |
||||
READ_SAMPLES_FUNC(dw, 4, s, int32_t, uint32_t, SOX_SIGNED_32BIT_TO_SAMPLE) |
||||
READ_SAMPLES_FUNC(f, sizeof(float), su, float, float, SOX_FLOAT_32BIT_TO_SAMPLE) |
||||
READ_SAMPLES_FUNC(df, sizeof(double), su, double, double, SOX_FLOAT_64BIT_TO_SAMPLE) |
||||
|
||||
#define WRITE_SAMPLES_FUNC(type, size, sign, ctype, uctype, cast) \ |
||||
static size_t sox_write_ ## sign ## type ## _samples( \
|
||||
sox_format_t * ft, sox_sample_t const * buf, size_t len) \
|
||||
{ \
|
||||
SOX_SAMPLE_LOCALS; \
|
||||
size_t n, nwritten; \
|
||||
ctype *data = lsx_malloc(sizeof(ctype) * len); \
|
||||
LSX_USE_VAR(sox_macro_temp_sample), LSX_USE_VAR(sox_macro_temp_double); \
|
||||
for (n = 0; n < len; n++) \
|
||||
data[n] = cast(buf[n], ft->clips); \
|
||||
nwritten = lsx_write_ ## type ## _buf(ft, (uctype *)data, len); \
|
||||
free(data); \
|
||||
return nwritten; \
|
||||
} |
||||
|
||||
|
||||
WRITE_SAMPLES_FUNC(b, 1, u, uint8_t, uint8_t, SOX_SAMPLE_TO_UNSIGNED_8BIT)
|
||||
WRITE_SAMPLES_FUNC(b, 1, s, int8_t, uint8_t, SOX_SAMPLE_TO_SIGNED_8BIT) |
||||
WRITE_SAMPLES_FUNC(b, 1, ulaw, uint8_t, uint8_t, SOX_SAMPLE_TO_ULAW_BYTE)
|
||||
WRITE_SAMPLES_FUNC(b, 1, alaw, uint8_t, uint8_t, SOX_SAMPLE_TO_ALAW_BYTE) |
||||
WRITE_SAMPLES_FUNC(w, 2, u, uint16_t, uint16_t, SOX_SAMPLE_TO_UNSIGNED_16BIT)
|
||||
WRITE_SAMPLES_FUNC(w, 2, s, int16_t, uint16_t, SOX_SAMPLE_TO_SIGNED_16BIT) |
||||
WRITE_SAMPLES_FUNC(3, 3, u, sox_uint24_t, sox_uint24_t, SOX_SAMPLE_TO_UNSIGNED_24BIT)
|
||||
WRITE_SAMPLES_FUNC(3, 3, s, sox_int24_t, sox_uint24_t, SOX_SAMPLE_TO_SIGNED_24BIT) |
||||
WRITE_SAMPLES_FUNC(dw, 4, u, uint32_t, uint32_t, SOX_SAMPLE_TO_UNSIGNED_32BIT)
|
||||
WRITE_SAMPLES_FUNC(dw, 4, s, int32_t, uint32_t, SOX_SAMPLE_TO_SIGNED_32BIT) |
||||
WRITE_SAMPLES_FUNC(f, sizeof(float), su, float, float, SOX_SAMPLE_TO_FLOAT_32BIT)
|
||||
WRITE_SAMPLES_FUNC(df, sizeof (double), su, double, double, SOX_SAMPLE_TO_FLOAT_64BIT) |
||||
|
||||
#define GET_FORMAT(type) \ |
||||
static ft_##type##_fn * type##_fn(sox_format_t * ft) { \
|
||||
switch (ft->encoding.bits_per_sample) { \
|
||||
case 8: \
|
||||
switch (ft->encoding.encoding) { \
|
||||
case SOX_ENCODING_SIGN2: return sox_##type##_sb_samples; \
|
||||
case SOX_ENCODING_UNSIGNED: return sox_##type##_ub_samples; \
|
||||
case SOX_ENCODING_ULAW: return sox_##type##_ulawb_samples; \
|
||||
case SOX_ENCODING_ALAW: return sox_##type##_alawb_samples; \
|
||||
default: break; } \
|
||||
break; \
|
||||
case 16: \
|
||||
switch (ft->encoding.encoding) { \
|
||||
case SOX_ENCODING_SIGN2: return sox_##type##_sw_samples; \
|
||||
case SOX_ENCODING_UNSIGNED: return sox_##type##_uw_samples; \
|
||||
default: break; } \
|
||||
break; \
|
||||
case 24: \
|
||||
switch (ft->encoding.encoding) { \
|
||||
case SOX_ENCODING_SIGN2: return sox_##type##_s3_samples; \
|
||||
case SOX_ENCODING_UNSIGNED: return sox_##type##_u3_samples; \
|
||||
default: break; } \
|
||||
break; \
|
||||
case 32: \
|
||||
switch (ft->encoding.encoding) { \
|
||||
case SOX_ENCODING_SIGN2: return sox_##type##_sdw_samples; \
|
||||
case SOX_ENCODING_UNSIGNED: return sox_##type##_udw_samples; \
|
||||
case SOX_ENCODING_FLOAT: return sox_##type##_suf_samples; \
|
||||
default: break; } \
|
||||
break; \
|
||||
case 64: \
|
||||
switch (ft->encoding.encoding) { \
|
||||
case SOX_ENCODING_FLOAT: return sox_##type##_sudf_samples; \
|
||||
default: break; } \
|
||||
break; \
|
||||
default: \
|
||||
lsx_fail_errno(ft, SOX_EFMT, "this handler does not support this data size"); \
|
||||
return NULL; } \
|
||||
lsx_fail_errno(ft, SOX_EFMT, "this encoding is not supported for this data size"); \
|
||||
return NULL; } |
||||
|
||||
typedef size_t(ft_read_fn) |
||||
(sox_format_t * ft, sox_sample_t * buf, size_t len); |
||||
|
||||
GET_FORMAT(read) |
||||
|
||||
/* Read a stream of some type into SoX's internal buffer format. */ |
||||
size_t lsx_rawread(sox_format_t * ft, sox_sample_t * buf, size_t nsamp) |
||||
{ |
||||
ft_read_fn * read_buf = read_fn(ft); |
||||
|
||||
if (read_buf && nsamp) |
||||
return read_buf(ft, buf, nsamp); |
||||
return 0; |
||||
} |
||||
|
||||
typedef size_t(ft_write_fn) |
||||
(sox_format_t * ft, sox_sample_t const * buf, size_t len); |
||||
|
||||
GET_FORMAT(write) |
||||
|
||||
/* Writes SoX's internal buffer format to buffer of various data types. */ |
||||
size_t lsx_rawwrite( |
||||
sox_format_t * ft, sox_sample_t const * buf, size_t nsamp) |
||||
{ |
||||
ft_write_fn * write_buf = write_fn(ft); |
||||
|
||||
if (write_buf && nsamp) |
||||
return write_buf(ft, buf, nsamp); |
||||
return 0; |
||||
} |
@ -1,54 +0,0 @@ |
||||
/* 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 |
||||
*/ |
||||
|
||||
#define RAW_FORMAT0(id, size, flags, encoding) \ |
||||
static int id ## _start(sox_format_t * ft) { \
|
||||
return lsx_rawstart(ft, sox_true, sox_true, sox_true, SOX_ENCODING_ ## encoding, size); \
|
||||
} \
|
||||
const sox_format_handler_t *lsx_ ## id ## _format_fn(void); \
|
||||
const sox_format_handler_t *lsx_ ## id ## _format_fn(void) { \
|
||||
static unsigned const write_encodings[] = { \
|
||||
SOX_ENCODING_ ## encoding, size, 0, 0}; \
|
||||
static sox_format_handler_t handler = { \
|
||||
SOX_LIB_VERSION_CODE, "Raw audio", \
|
||||
names, flags, \
|
||||
id ## _start, lsx_rawread , NULL, \
|
||||
id ## _start, lsx_rawwrite, NULL, \
|
||||
NULL, write_encodings, NULL, 0 \
|
||||
}; \
|
||||
return &handler; \
|
||||
} |
||||
|
||||
#define RAW_FORMAT(id, size, flags, encoding) \ |
||||
static char const *names[] = {#id, NULL}; \
|
||||
RAW_FORMAT0(id, size, flags, encoding) |
||||
|
||||
#define RAW_FORMAT1(id, alt, size, flags, encoding) \ |
||||
static char const *names[] = {#id, alt, NULL}; \
|
||||
RAW_FORMAT0(id, size, flags, encoding) |
||||
|
||||
#define RAW_FORMAT2(id, alt1, alt2, size, flags, encoding) \ |
||||
static char const *names[] = {#id, alt1, alt2, NULL}; \
|
||||
RAW_FORMAT0(id, size, flags, encoding) |
||||
|
||||
#define RAW_FORMAT3(id, alt1, alt2, alt3, size, flags, encoding) \ |
||||
static char const *names[] = {#id, alt1, alt2, alt3, NULL}; \
|
||||
RAW_FORMAT0(id, size, flags, encoding) |
||||
|
||||
#define RAW_FORMAT4(id, alt1, alt2, alt3, alt4, size, flags, encoding) \ |
||||
static char const *names[] = {#id, alt1, alt2, alt3, alt4, NULL}; \
|
||||
RAW_FORMAT0(id, size, flags, encoding) |
@ -1,277 +0,0 @@ |
||||
/* libSoX effect: stereo reverberation
|
||||
* Copyright (c) 2007 robs@users.sourceforge.net |
||||
* Filter design based on freeverb by Jezar at Dreampoint. |
||||
* |
||||
* 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 "fifo.h" |
||||
|
||||
#define lsx_zalloc(var, n) var = lsx_calloc(n, sizeof(*var)) |
||||
#define filter_advance(p) if (--(p)->ptr < (p)->buffer) (p)->ptr += (p)->size |
||||
#define filter_delete(p) free((p)->buffer) |
||||
|
||||
typedef struct { |
||||
size_t size; |
||||
float * buffer, * ptr; |
||||
float store; |
||||
} filter_t; |
||||
|
||||
static float comb_process(filter_t * p, /* gcc -O2 will inline this */ |
||||
float const * input, float const * feedback, float const * hf_damping) |
||||
{ |
||||
float output = *p->ptr; |
||||
p->store = output + (p->store - output) * *hf_damping; |
||||
*p->ptr = *input + p->store * *feedback; |
||||
filter_advance(p); |
||||
return output; |
||||
} |
||||
|
||||
static float allpass_process(filter_t * p, /* gcc -O2 will inline this */ |
||||
float const * input) |
||||
{ |
||||
float output = *p->ptr; |
||||
*p->ptr = *input + output * .5; |
||||
filter_advance(p); |
||||
return output - *input; |
||||
} |
||||
|
||||
static const size_t /* Filter delay lengths in samples (44100Hz sample-rate) */ |
||||
comb_lengths[] = {1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617}, |
||||
allpass_lengths[] = {225, 341, 441, 556}; |
||||
#define stereo_adjust 12 |
||||
|
||||
typedef struct { |
||||
filter_t comb [array_length(comb_lengths)]; |
||||
filter_t allpass[array_length(allpass_lengths)]; |
||||
} filter_array_t; |
||||
|
||||
static void filter_array_create(filter_array_t * p, double rate, |
||||
double scale, double offset) |
||||
{ |
||||
size_t i; |
||||
double r = rate * (1 / 44100.); /* Compensate for actual sample-rate */ |
||||
|
||||
for (i = 0; i < array_length(comb_lengths); ++i, offset = -offset) |
||||
{ |
||||
filter_t * pcomb = &p->comb[i]; |
||||
pcomb->size = (size_t)(scale * r * (comb_lengths[i] + stereo_adjust * offset) + .5); |
||||
pcomb->ptr = lsx_zalloc(pcomb->buffer, pcomb->size); |
||||
} |
||||
for (i = 0; i < array_length(allpass_lengths); ++i, offset = -offset) |
||||
{ |
||||
filter_t * pallpass = &p->allpass[i]; |
||||
pallpass->size = (size_t)(r * (allpass_lengths[i] + stereo_adjust * offset) + .5); |
||||
pallpass->ptr = lsx_zalloc(pallpass->buffer, pallpass->size); |
||||
} |
||||
} |
||||
|
||||
static void filter_array_process(filter_array_t * p, |
||||
size_t length, float const * input, float * output, |
||||
float const * feedback, float const * hf_damping, float const * gain) |
||||
{ |
||||
while (length--) { |
||||
float out = 0, in = *input++; |
||||
|
||||
size_t i = array_length(comb_lengths) - 1; |
||||
do out += comb_process(p->comb + i, &in, feedback, hf_damping); |
||||
while (i--); |
||||
|
||||
i = array_length(allpass_lengths) - 1; |
||||
do out = allpass_process(p->allpass + i, &out); |
||||
while (i--); |
||||
|
||||
*output++ = out * *gain; |
||||
} |
||||
} |
||||
|
||||
static void filter_array_delete(filter_array_t * p) |
||||
{ |
||||
size_t i; |
||||
|
||||
for (i = 0; i < array_length(allpass_lengths); ++i) |
||||
filter_delete(&p->allpass[i]); |
||||
for (i = 0; i < array_length(comb_lengths); ++i) |
||||
filter_delete(&p->comb[i]); |
||||
} |
||||
|
||||
typedef struct { |
||||
float feedback; |
||||
float hf_damping; |
||||
float gain; |
||||
fifo_t input_fifo; |
||||
filter_array_t chan[2]; |
||||
float * out[2]; |
||||
} reverb_t; |
||||
|
||||
static void reverb_create(reverb_t * p, double sample_rate_Hz, |
||||
double wet_gain_dB, |
||||
double room_scale, /* % */ |
||||
double reverberance, /* % */ |
||||
double hf_damping, /* % */ |
||||
double pre_delay_ms, |
||||
double stereo_depth, |
||||
size_t buffer_size, |
||||
float * * out) |
||||
{ |
||||
size_t i, delay = pre_delay_ms / 1000 * sample_rate_Hz + .5; |
||||
double scale = room_scale / 100 * .9 + .1; |
||||
double depth = stereo_depth / 100; |
||||
double a = -1 / log(1 - /**/.3 /**/); /* Set minimum feedback */ |
||||
double b = 100 / (log(1 - /**/.98/**/) * a + 1); /* Set maximum feedback */ |
||||
|
||||
memset(p, 0, sizeof(*p)); |
||||
p->feedback = 1 - exp((reverberance - b) / (a * b)); |
||||
p->hf_damping = hf_damping / 100 * .3 + .2; |
||||
p->gain = dB_to_linear(wet_gain_dB) * .015; |
||||
fifo_create(&p->input_fifo, sizeof(float)); |
||||
memset(fifo_write(&p->input_fifo, delay, 0), 0, delay * sizeof(float)); |
||||
for (i = 0; i <= ceil(depth); ++i) { |
||||
filter_array_create(p->chan + i, sample_rate_Hz, scale, i * depth); |
||||
out[i] = lsx_zalloc(p->out[i], buffer_size); |
||||
} |
||||
} |
||||
|
||||
static void reverb_process(reverb_t * p, size_t length) |
||||
{ |
||||
size_t i; |
||||
for (i = 0; i < 2 && p->out[i]; ++i) |
||||
filter_array_process(p->chan + i, length, (float *) fifo_read_ptr(&p->input_fifo), p->out[i], &p->feedback, &p->hf_damping, &p->gain); |
||||
fifo_read(&p->input_fifo, length, NULL); |
||||
} |
||||
|
||||
static void reverb_delete(reverb_t * p) |
||||
{ |
||||
size_t i; |
||||
for (i = 0; i < 2 && p->out[i]; ++i) { |
||||
free(p->out[i]); |
||||
filter_array_delete(p->chan + i); |
||||
} |
||||
fifo_delete(&p->input_fifo); |
||||
} |
||||
|
||||
/*------------------------------- SoX Wrapper --------------------------------*/ |
||||
|
||||
typedef struct { |
||||
double reverberance, hf_damping, pre_delay_ms; |
||||
double stereo_depth, wet_gain_dB, room_scale; |
||||
sox_bool wet_only; |
||||
|
||||
size_t ichannels, ochannels; |
||||
struct { |
||||
reverb_t reverb; |
||||
float * dry, * wet[2]; |
||||
} chan[2]; |
||||
} priv_t; |
||||
|
||||
static int getopts(sox_effect_t * effp, int argc, char **argv) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
p->reverberance = p->hf_damping = 50; /* Set non-zero defaults */ |
||||
p->stereo_depth = p->room_scale = 100; |
||||
|
||||
--argc, ++argv; |
||||
p->wet_only = argc && (!strcmp(*argv, "-w") || !strcmp(*argv, "--wet-only")) |
||||
&& (--argc, ++argv, sox_true); |
||||
do { /* break-able block */ |
||||
NUMERIC_PARAMETER(reverberance, 0, 100) |
||||
NUMERIC_PARAMETER(hf_damping, 0, 100) |
||||
NUMERIC_PARAMETER(room_scale, 0, 100) |
||||
NUMERIC_PARAMETER(stereo_depth, 0, 100) |
||||
NUMERIC_PARAMETER(pre_delay_ms, 0, 500) |
||||
NUMERIC_PARAMETER(wet_gain_dB, -10, 10) |
||||
} while (0); |
||||
|
||||
return argc ? lsx_usage(effp) : SOX_SUCCESS; |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
size_t i; |
||||
|
||||
p->ichannels = p->ochannels = 1; |
||||
effp->out_signal.rate = effp->in_signal.rate; |
||||
if (effp->in_signal.channels > 2 && p->stereo_depth) { |
||||
lsx_warn("stereo-depth not applicable with >2 channels"); |
||||
p->stereo_depth = 0; |
||||
} |
||||
if (effp->in_signal.channels == 1 && p->stereo_depth) |
||||
effp->out_signal.channels = p->ochannels = 2; |
||||
else effp->out_signal.channels = effp->in_signal.channels; |
||||
if (effp->in_signal.channels == 2 && p->stereo_depth) |
||||
p->ichannels = p->ochannels = 2; |
||||
else effp->flows = effp->in_signal.channels; |
||||
for (i = 0; i < p->ichannels; ++i) reverb_create( |
||||
&p->chan[i].reverb, effp->in_signal.rate, p->wet_gain_dB, p->room_scale, |
||||
p->reverberance, p->hf_damping, p->pre_delay_ms, p->stereo_depth, |
||||
effp->global_info->global_info->bufsiz / p->ochannels, p->chan[i].wet); |
||||
|
||||
if (effp->in_signal.mult) |
||||
*effp->in_signal.mult /= !p->wet_only + 2 * dB_to_linear(max(0,p->wet_gain_dB)); |
||||
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 c, i, w, len = min(*isamp / p->ichannels, *osamp / p->ochannels); |
||||
SOX_SAMPLE_LOCALS; |
||||
|
||||
*isamp = len * p->ichannels, *osamp = len * p->ochannels; |
||||
for (c = 0; c < p->ichannels; ++c) |
||||
p->chan[c].dry = fifo_write(&p->chan[c].reverb.input_fifo, len, 0); |
||||
for (i = 0; i < len; ++i) for (c = 0; c < p->ichannels; ++c) |
||||
p->chan[c].dry[i] = SOX_SAMPLE_TO_FLOAT_32BIT(*ibuf++, effp->clips); |
||||
for (c = 0; c < p->ichannels; ++c) |
||||
reverb_process(&p->chan[c].reverb, len); |
||||
if (p->ichannels == 2) for (i = 0; i < len; ++i) for (w = 0; w < 2; ++w) { |
||||
float out = (1 - p->wet_only) * p->chan[w].dry[i] + |
||||
.5 * (p->chan[0].wet[w][i] + p->chan[1].wet[w][i]); |
||||
*obuf++ = SOX_FLOAT_32BIT_TO_SAMPLE(out, effp->clips); |
||||
} |
||||
else for (i = 0; i < len; ++i) for (w = 0; w < p->ochannels; ++w) { |
||||
float out = (1 - p->wet_only) * p->chan[0].dry[i] + p->chan[0].wet[w][i]; |
||||
*obuf++ = SOX_FLOAT_32BIT_TO_SAMPLE(out, effp->clips); |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
size_t i; |
||||
for (i = 0; i < p->ichannels; ++i) |
||||
reverb_delete(&p->chan[i].reverb); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const *lsx_reverb_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = {"reverb", |
||||
"[-w|--wet-only]" |
||||
" [reverberance (50%)" |
||||
" [HF-damping (50%)" |
||||
" [room-scale (100%)" |
||||
" [stereo-depth (100%)" |
||||
" [pre-delay (0ms)" |
||||
" [wet-gain (0dB)" |
||||
"]]]]]]", |
||||
SOX_EFF_MCHAN, getopts, start, flow, NULL, stop, NULL, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,416 +0,0 @@ |
||||
/* libSoX Internal header
|
||||
* |
||||
* This file is meant for libSoX internal use only |
||||
* |
||||
* Copyright 2001-2012 Chris Bagwell and SoX Contributors |
||||
* |
||||
* This source code is freely redistributable and may be used for |
||||
* any purpose. This copyright notice must be maintained. |
||||
* Chris Bagwell And SoX Contributors are not responsible for |
||||
* the consequences of using this software. |
||||
*/ |
||||
|
||||
#ifndef SOX_I_H |
||||
#define SOX_I_H |
||||
|
||||
#include "soxomp.h" /* Note: soxomp.h includes soxconfig.h */ |
||||
#include "sox.h" |
||||
|
||||
#if defined HAVE_FMEMOPEN |
||||
#define _GNU_SOURCE |
||||
#endif |
||||
|
||||
#include <errno.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
|
||||
#include "util.h" |
||||
|
||||
#if defined(LSX_EFF_ALIAS) |
||||
#undef lsx_debug |
||||
#undef lsx_fail |
||||
#undef lsx_report |
||||
#undef lsx_warn |
||||
#define lsx_debug sox_globals.subsystem=effp->handler.name,lsx_debug_impl |
||||
#define lsx_fail sox_globals.subsystem=effp->handler.name,lsx_fail_impl |
||||
#define lsx_report sox_globals.subsystem=effp->handler.name,lsx_report_impl |
||||
#define lsx_warn sox_globals.subsystem=effp->handler.name,lsx_warn_impl |
||||
#endif |
||||
|
||||
#define RANQD1 ranqd1(sox_globals.ranqd1) |
||||
#define DRANQD1 dranqd1(sox_globals.ranqd1) |
||||
|
||||
typedef enum {SOX_SHORT, SOX_INT, SOX_FLOAT, SOX_DOUBLE} sox_data_t; |
||||
typedef enum {SOX_WAVE_SINE, SOX_WAVE_TRIANGLE} lsx_wave_t; |
||||
lsx_enum_item const * lsx_get_wave_enum(void); |
||||
|
||||
/* Define fseeko and ftello for platforms lacking them */ |
||||
#ifndef HAVE_FSEEKO |
||||
#define fseeko fseek |
||||
#define ftello ftell |
||||
#endif |
||||
|
||||
#ifdef _FILE_OFFSET_BITS |
||||
assert_static(sizeof(off_t) == _FILE_OFFSET_BITS >> 3, OFF_T_BUILD_PROBLEM); |
||||
#endif |
||||
|
||||
FILE * lsx_tmpfile(void); |
||||
|
||||
void lsx_debug_more_impl(char const * fmt, ...) LSX_PRINTF12; |
||||
void lsx_debug_most_impl(char const * fmt, ...) LSX_PRINTF12; |
||||
|
||||
#define lsx_debug_more sox_get_globals()->subsystem=__FILE__,lsx_debug_more_impl |
||||
#define lsx_debug_most sox_get_globals()->subsystem=__FILE__,lsx_debug_most_impl |
||||
|
||||
/* Digitise one cycle of a wave and store it as
|
||||
* a table of samples of a specified data-type. |
||||
*/ |
||||
void lsx_generate_wave_table( |
||||
lsx_wave_t wave_type, |
||||
sox_data_t data_type, |
||||
void * table, /* Really of type indicated by data_type. */ |
||||
size_t table_size, /* Number of points on the x-axis. */ |
||||
double min, /* Minimum value on the y-axis. (e.g. -1) */ |
||||
double max, /* Maximum value on the y-axis. (e.g. +1) */ |
||||
double phase); /* Phase at 1st point; 0..2pi. (e.g. pi/2 for cosine) */ |
||||
char const * lsx_parsesamples(sox_rate_t rate, const char *str, uint64_t *samples, int def); |
||||
char const * lsx_parseposition(sox_rate_t rate, const char *str, uint64_t *samples, uint64_t latest, uint64_t end, int def); |
||||
int lsx_parse_note(char const * text, char * * end_ptr); |
||||
double lsx_parse_frequency_k(char const * text, char * * end_ptr, int key); |
||||
#define lsx_parse_frequency(a, b) lsx_parse_frequency_k(a, b, INT_MAX) |
||||
FILE * lsx_open_input_file(sox_effect_t * effp, char const * filename, sox_bool text_mode); |
||||
|
||||
void lsx_prepare_spline3(double const * x, double const * y, int n, |
||||
double start_1d, double end_1d, double * y_2d); |
||||
double lsx_spline3(double const * x, double const * y, double const * y_2d, |
||||
int n, double x1); |
||||
|
||||
double lsx_bessel_I_0(double x); |
||||
int lsx_set_dft_length(int num_taps); |
||||
void init_fft_cache(void); |
||||
void clear_fft_cache(void); |
||||
#define lsx_is_power_of_2(x) !(x < 2 || (x & (x - 1))) |
||||
void lsx_safe_rdft(int len, int type, double * d); |
||||
void lsx_safe_cdft(int len, int type, double * d); |
||||
void lsx_power_spectrum(int n, double const * in, double * out); |
||||
void lsx_power_spectrum_f(int n, float const * in, float * out); |
||||
void lsx_apply_hann_f(float h[], const int num_points); |
||||
void lsx_apply_hann(double h[], const int num_points); |
||||
void lsx_apply_hamming(double h[], const int num_points); |
||||
void lsx_apply_bartlett(double h[], const int num_points); |
||||
void lsx_apply_blackman(double h[], const int num_points, double alpha); |
||||
void lsx_apply_blackman_nutall(double h[], const int num_points); |
||||
double lsx_kaiser_beta(double att, double tr_bw); |
||||
void lsx_apply_kaiser(double h[], const int num_points, double beta); |
||||
void lsx_apply_dolph(double h[], const int num_points, double att); |
||||
double * lsx_make_lpf(int num_taps, double Fc, double beta, double rho, |
||||
double scale, sox_bool dc_norm); |
||||
void lsx_kaiser_params(double att, double Fc, double tr_bw, double * beta, int * 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; < 0: dummy run */ |
||||
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 */ |
||||
void lsx_fir_to_phase(double * * h, int * len, |
||||
int * post_len, double phase0); |
||||
void lsx_plot_fir(double * h, int num_points, sox_rate_t rate, sox_plot_t type, char const * title, double y1, double y2); |
||||
void lsx_save_samples(sox_sample_t * const dest, double const * const src, |
||||
size_t const n, sox_uint64_t * const clips); |
||||
void lsx_load_samples(double * const dest, sox_sample_t const * const src, |
||||
size_t const n); |
||||
|
||||
#ifdef HAVE_BYTESWAP_H |
||||
#include <byteswap.h> |
||||
#define lsx_swapw(x) bswap_16(x) |
||||
#define lsx_swapdw(x) bswap_32(x) |
||||
#elif defined(_MSC_VER) |
||||
#define lsx_swapw(x) _byteswap_ushort(x) |
||||
#define lsx_swapdw(x) _byteswap_ulong(x) |
||||
#else |
||||
#define lsx_swapw(uw) (((uw >> 8) | (uw << 8)) & 0xffff) |
||||
#define lsx_swapdw(udw) ((udw >> 24) | ((udw >> 8) & 0xff00) | ((udw << 8) & 0xff0000) | (udw << 24)) |
||||
#endif |
||||
|
||||
|
||||
|
||||
/*------------------------ Implemented in libsoxio.c -------------------------*/ |
||||
|
||||
/* Read and write basic data types from "ft" stream. */ |
||||
size_t lsx_readbuf(sox_format_t * ft, void *buf, size_t len); |
||||
int lsx_skipbytes(sox_format_t * ft, size_t n); |
||||
int lsx_padbytes(sox_format_t * ft, size_t n); |
||||
size_t lsx_writebuf(sox_format_t * ft, void const *buf, size_t len); |
||||
int lsx_reads(sox_format_t * ft, char *c, size_t len); |
||||
int lsx_writes(sox_format_t * ft, char const * c); |
||||
void lsx_set_signal_defaults(sox_format_t * ft); |
||||
#define lsx_writechars(ft, chars, len) (lsx_writebuf(ft, chars, len) == len? SOX_SUCCESS : SOX_EOF) |
||||
|
||||
size_t lsx_read_3_buf(sox_format_t * ft, sox_uint24_t *buf, size_t len); |
||||
size_t lsx_read_b_buf(sox_format_t * ft, uint8_t *buf, size_t len); |
||||
size_t lsx_read_df_buf(sox_format_t * ft, double *buf, size_t len); |
||||
size_t lsx_read_dw_buf(sox_format_t * ft, uint32_t *buf, size_t len); |
||||
size_t lsx_read_qw_buf(sox_format_t * ft, uint64_t *buf, size_t len); |
||||
size_t lsx_read_f_buf(sox_format_t * ft, float *buf, size_t len); |
||||
size_t lsx_read_w_buf(sox_format_t * ft, uint16_t *buf, size_t len); |
||||
|
||||
size_t lsx_write_3_buf(sox_format_t * ft, sox_uint24_t *buf, size_t len); |
||||
size_t lsx_write_b_buf(sox_format_t * ft, uint8_t *buf, size_t len); |
||||
size_t lsx_write_df_buf(sox_format_t * ft, double *buf, size_t len); |
||||
size_t lsx_write_dw_buf(sox_format_t * ft, uint32_t *buf, size_t len); |
||||
size_t lsx_write_qw_buf(sox_format_t * ft, uint64_t *buf, size_t len); |
||||
size_t lsx_write_f_buf(sox_format_t * ft, float *buf, size_t len); |
||||
size_t lsx_write_w_buf(sox_format_t * ft, uint16_t *buf, size_t len); |
||||
|
||||
int lsx_read3(sox_format_t * ft, sox_uint24_t * u3); |
||||
int lsx_readb(sox_format_t * ft, uint8_t * ub); |
||||
int lsx_readchars(sox_format_t * ft, char * chars, size_t len); |
||||
int lsx_readdf(sox_format_t * ft, double * d); |
||||
int lsx_readdw(sox_format_t * ft, uint32_t * udw); |
||||
int lsx_readqw(sox_format_t * ft, uint64_t * udw); |
||||
int lsx_readf(sox_format_t * ft, float * f); |
||||
int lsx_readw(sox_format_t * ft, uint16_t * uw); |
||||
|
||||
#if 1 /* FIXME: use defines */ |
||||
UNUSED static int lsx_readsb(sox_format_t * ft, int8_t * sb) |
||||
{return lsx_readb(ft, (uint8_t *)sb);} |
||||
UNUSED static int lsx_readsw(sox_format_t * ft, int16_t * sw) |
||||
{return lsx_readw(ft, (uint16_t *)sw);} |
||||
#else |
||||
#define lsx_readsb(ft, sb) lsx_readb(ft, (uint8_t *)sb) |
||||
#define lsx_readsw(ft, sw) lsx_readb(ft, (uint16_t *)sw) |
||||
#endif |
||||
|
||||
int lsx_read_fields(sox_format_t *ft, uint32_t *len, const char *spec, ...); |
||||
|
||||
int lsx_write3(sox_format_t * ft, unsigned u3); |
||||
int lsx_writeb(sox_format_t * ft, unsigned ub); |
||||
int lsx_writedf(sox_format_t * ft, double d); |
||||
int lsx_writedw(sox_format_t * ft, unsigned udw); |
||||
int lsx_writeqw(sox_format_t * ft, uint64_t uqw); |
||||
int lsx_writef(sox_format_t * ft, double f); |
||||
int lsx_writew(sox_format_t * ft, unsigned uw); |
||||
|
||||
int lsx_writesb(sox_format_t * ft, signed); |
||||
int lsx_writesw(sox_format_t * ft, signed); |
||||
|
||||
int lsx_eof(sox_format_t * ft); |
||||
int lsx_error(sox_format_t * ft); |
||||
int lsx_flush(sox_format_t * ft); |
||||
int lsx_seeki(sox_format_t * ft, off_t offset, int whence); |
||||
int lsx_unreadb(sox_format_t * ft, unsigned ub); |
||||
/* uint64_t lsx_filelength(sox_format_t * ft); Temporarily Moved to sox.h. */ |
||||
off_t lsx_tell(sox_format_t * ft); |
||||
void lsx_clearerr(sox_format_t * ft); |
||||
void lsx_rewind(sox_format_t * ft); |
||||
|
||||
int lsx_offset_seek(sox_format_t * ft, off_t byte_offset, off_t to_sample); |
||||
|
||||
void lsx_fail_errno(sox_format_t *, int, const char *, ...) |
||||
#ifdef __GNUC__ |
||||
__attribute__ ((format (printf, 3, 4))); |
||||
#else |
||||
; |
||||
#endif |
||||
|
||||
typedef struct sox_formats_globals { /* Global parameters (for formats) */ |
||||
sox_globals_t * global_info; |
||||
} sox_formats_globals; |
||||
|
||||
|
||||
|
||||
/*------------------------------ File Handlers -------------------------------*/ |
||||
|
||||
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); |
||||
#define LSX_FORMAT_HANDLER(name) \ |
||||
sox_format_handler_t const * lsx_##name##_format_fn(void); \
|
||||
sox_format_handler_t const * lsx_##name##_format_fn(void) |
||||
#define div_bits(size, bits) ((uint64_t)(size) * 8 / bits) |
||||
|
||||
/* Raw I/O */ |
||||
int lsx_rawstartread(sox_format_t * ft); |
||||
size_t lsx_rawread(sox_format_t * ft, sox_sample_t *buf, size_t nsamp); |
||||
int lsx_rawstopread(sox_format_t * ft); |
||||
int lsx_rawstartwrite(sox_format_t * ft); |
||||
size_t lsx_rawwrite(sox_format_t * ft, const sox_sample_t *buf, size_t nsamp); |
||||
int lsx_rawseek(sox_format_t * ft, uint64_t offset); |
||||
int lsx_rawstart(sox_format_t * ft, sox_bool default_rate, sox_bool default_channels, sox_bool default_length, sox_encoding_t encoding, unsigned bits_per_sample); |
||||
#define lsx_rawstartread(ft) lsx_rawstart(ft, sox_false, sox_false, sox_false, SOX_ENCODING_UNKNOWN, 0) |
||||
#define lsx_rawstartwrite lsx_rawstartread |
||||
#define lsx_rawstopread NULL |
||||
#define lsx_rawstopwrite NULL |
||||
|
||||
extern sox_format_handler_t const * lsx_sndfile_format_fn(void); |
||||
|
||||
char * lsx_cat_comments(sox_comments_t comments); |
||||
|
||||
/*--------------------------------- Effects ----------------------------------*/ |
||||
|
||||
int lsx_flow_copy(sox_effect_t * effp, const sox_sample_t * ibuf, |
||||
sox_sample_t * obuf, size_t * isamp, size_t * osamp); |
||||
int lsx_usage(sox_effect_t * effp); |
||||
char * lsx_usage_lines(char * * usage, char const * const * lines, size_t n); |
||||
#define EFFECT(f) extern sox_effect_handler_t const * lsx_##f##_effect_fn(void); |
||||
#include "effects.h" |
||||
#undef EFFECT |
||||
|
||||
#define NUMERIC_PARAMETER(name, min, max) { \ |
||||
char * end_ptr; \
|
||||
double d; \
|
||||
if (argc == 0) break; \
|
||||
d = strtod(*argv, &end_ptr); \
|
||||
if (end_ptr != *argv) { \
|
||||
if (d < min || d > max || *end_ptr != '\0') {\
|
||||
lsx_fail("parameter `%s' must be between %g and %g", #name, (double)min, (double)max); \
|
||||
return lsx_usage(effp); \
|
||||
} \
|
||||
p->name = d; \
|
||||
--argc, ++argv; \
|
||||
} \
|
||||
} |
||||
|
||||
#define TEXTUAL_PARAMETER(name, enum_table) { \ |
||||
lsx_enum_item const * e; \
|
||||
if (argc == 0) break; \
|
||||
e = lsx_find_enum_text(*argv, enum_table, 0); \
|
||||
if (e != NULL) { \
|
||||
p->name = e->value; \
|
||||
--argc, ++argv; \
|
||||
} \
|
||||
} |
||||
|
||||
#define GETOPT_LOCAL_NUMERIC(state, ch, name, min, max) case ch:{ \ |
||||
char * end_ptr; \
|
||||
double d = strtod(state.arg, &end_ptr); \
|
||||
if (end_ptr == state.arg || d < min || d > max || *end_ptr != '\0') {\
|
||||
lsx_fail("parameter `%s' must be between %g and %g", #name, (double)min, (double)max); \
|
||||
return lsx_usage(effp); \
|
||||
} \
|
||||
name = d; \
|
||||
break; \
|
||||
} |
||||
#define GETOPT_NUMERIC(state, ch, name, min, max) GETOPT_LOCAL_NUMERIC(state, ch, p->name, min, max) |
||||
|
||||
int lsx_effect_set_imin(sox_effect_t * effp, size_t imin); |
||||
|
||||
int lsx_effects_init(void); |
||||
int lsx_effects_quit(void); |
||||
|
||||
/*--------------------------------- Dynamic Library ----------------------------------*/ |
||||
|
||||
#if defined(HAVE_LIBLTDL) |
||||
#include <ltdl.h> |
||||
typedef lt_dlhandle lsx_dlhandle; |
||||
#else |
||||
struct lsx_dlhandle_tag; |
||||
typedef struct lsx_dlhandle_tag *lsx_dlhandle; |
||||
#endif |
||||
|
||||
typedef void (*lsx_dlptr)(void); |
||||
|
||||
typedef struct lsx_dlfunction_info |
||||
{ |
||||
const char* name; |
||||
lsx_dlptr static_func; |
||||
lsx_dlptr stub_func; |
||||
} lsx_dlfunction_info; |
||||
|
||||
int lsx_open_dllibrary( |
||||
int show_error_on_failure, |
||||
const char* library_description, |
||||
const char * const library_names[], |
||||
const lsx_dlfunction_info func_infos[], |
||||
lsx_dlptr selected_funcs[], |
||||
lsx_dlhandle* pdl); |
||||
|
||||
void lsx_close_dllibrary( |
||||
lsx_dlhandle dl); |
||||
|
||||
#define LSX_DLENTRIES_APPLY__(entries, f, x) entries(f, x) |
||||
|
||||
#define LSX_DLENTRY_TO_PTR__(unused, func_return, func_name, func_args, static_func, stub_func, func_ptr) \ |
||||
func_return (*func_ptr) func_args; |
||||
|
||||
#define LSX_DLENTRIES_TO_FUNCTIONS__(unused, func_return, func_name, func_args, static_func, stub_func, func_ptr) \ |
||||
func_return func_name func_args; |
||||
|
||||
/* LSX_DLENTRIES_TO_PTRS: Given an ENTRIES macro and the name of the dlhandle
|
||||
variable, declares the corresponding function pointer variables and the |
||||
dlhandle variable. */ |
||||
#define LSX_DLENTRIES_TO_PTRS(entries, dlhandle) \ |
||||
LSX_DLENTRIES_APPLY__(entries, LSX_DLENTRY_TO_PTR__, 0) \
|
||||
lsx_dlhandle dlhandle |
||||
|
||||
/* LSX_DLENTRIES_TO_FUNCTIONS: Given an ENTRIES macro, declares the corresponding
|
||||
functions. */ |
||||
#define LSX_DLENTRIES_TO_FUNCTIONS(entries) \ |
||||
LSX_DLENTRIES_APPLY__(entries, LSX_DLENTRIES_TO_FUNCTIONS__, 0) |
||||
|
||||
#define LSX_DLLIBRARY_OPEN1__(unused, func_return, func_name, func_args, static_func, stub_func, func_ptr) \ |
||||
{ #func_name, (lsx_dlptr)(static_func), (lsx_dlptr)(stub_func) }, |
||||
|
||||
#define LSX_DLLIBRARY_OPEN2__(ptr_container, func_return, func_name, func_args, static_func, stub_func, func_ptr) \ |
||||
(ptr_container)->func_ptr = (func_return (*)func_args)lsx_dlfunction_open_library_funcs[lsx_dlfunction_open_library_index++]; |
||||
|
||||
/* LSX_DLLIBRARY_OPEN: Input an ENTRIES macro, the library's description,
|
||||
a null-terminated list of library names (i.e. { "libmp3-0", "libmp3", NULL }), |
||||
the name of the dlhandle variable, the name of the structure that contains |
||||
the function pointer and dlhandle variables, and the name of the variable in |
||||
which the result of the lsx_open_dllibrary call should be stored. This will |
||||
call lsx_open_dllibrary and copy the resulting function pointers into the |
||||
structure members. If the library cannot be opened, show a failure message. */ |
||||
#define LSX_DLLIBRARY_OPEN(ptr_container, dlhandle, entries, library_description, library_names, return_var) \ |
||||
LSX_DLLIBRARY_TRYOPEN(1, ptr_container, dlhandle, entries, library_description, library_names, return_var) |
||||
|
||||
/* LSX_DLLIBRARY_TRYOPEN: Input an ENTRIES macro, the library's description,
|
||||
a null-terminated list of library names (i.e. { "libmp3-0", "libmp3", NULL }), |
||||
the name of the dlhandle variable, the name of the structure that contains |
||||
the function pointer and dlhandle variables, and the name of the variable in |
||||
which the result of the lsx_open_dllibrary call should be stored. This will |
||||
call lsx_open_dllibrary and copy the resulting function pointers into the |
||||
structure members. If the library cannot be opened, show a report or a failure |
||||
message, depending on whether error_on_failure is non-zero. */ |
||||
#define LSX_DLLIBRARY_TRYOPEN(error_on_failure, ptr_container, dlhandle, entries, library_description, library_names, return_var) \ |
||||
do { \
|
||||
lsx_dlfunction_info lsx_dlfunction_open_library_infos[] = { \
|
||||
LSX_DLENTRIES_APPLY__(entries, LSX_DLLIBRARY_OPEN1__, 0) \
|
||||
{NULL,NULL,NULL} }; \
|
||||
int lsx_dlfunction_open_library_index = 0; \
|
||||
lsx_dlptr lsx_dlfunction_open_library_funcs[sizeof(lsx_dlfunction_open_library_infos)/sizeof(lsx_dlfunction_open_library_infos[0])]; \
|
||||
(return_var) = lsx_open_dllibrary((error_on_failure), (library_description), (library_names), lsx_dlfunction_open_library_infos, lsx_dlfunction_open_library_funcs, &(ptr_container)->dlhandle); \
|
||||
LSX_DLENTRIES_APPLY__(entries, LSX_DLLIBRARY_OPEN2__, ptr_container) \
|
||||
} while(0) |
||||
|
||||
#define LSX_DLLIBRARY_CLOSE(ptr_container, dlhandle) \ |
||||
lsx_close_dllibrary((ptr_container)->dlhandle) |
||||
|
||||
/* LSX_DLENTRY_STATIC: For use in creating an ENTRIES macro. func is
|
||||
expected to be available at link time. If not present, link will fail. */ |
||||
#define LSX_DLENTRY_STATIC(f,x, ret, func, args) f(x, ret, func, args, func, NULL, func) |
||||
|
||||
/* LSX_DLENTRY_DYNAMIC: For use in creating an ENTRIES macro. func need
|
||||
not be available at link time (and if present, the link time version will |
||||
not be used). func will be loaded via dlsym. If this function is not |
||||
found in the shared library, the shared library will not be used. */ |
||||
#define LSX_DLENTRY_DYNAMIC(f,x, ret, func, args) f(x, ret, func, args, NULL, NULL, func) |
||||
|
||||
/* LSX_DLENTRY_STUB: For use in creating an ENTRIES macro. func need not
|
||||
be available at link time (and if present, the link time version will not |
||||
be used). If using DL_LAME, the func may be loaded via dlopen/dlsym, but |
||||
if not found, the shared library will still be used if all of the |
||||
non-stub functions are found. If the function is not found via dlsym (or |
||||
if we are not loading any shared libraries), the stub will be used. This |
||||
assumes that the name of the stub function is the name of the function + |
||||
"_stub". */ |
||||
#define LSX_DLENTRY_STUB(f,x, ret, func, args) f(x, ret, func, args, NULL, func##_stub, func) |
||||
|
||||
/* LSX_DLFUNC_IS_STUB: returns true if the named function is a do-nothing
|
||||
stub. Assumes that the name of the stub function is the name of the |
||||
function + "_stub". */ |
||||
#define LSX_DLFUNC_IS_STUB(ptr_container, func) ((ptr_container)->func == func##_stub) |
||||
|
||||
#endif |
@ -1,370 +0,0 @@ |
||||
/* src/soxconfig.h. Generated from soxconfig.h.in by configure. */ |
||||
/* src/soxconfig.h.in. Generated from configure.ac by autoheader. */ |
||||
|
||||
/* Define if building universal (internal helper macro) */ |
||||
/* #undef AC_APPLE_UNIVERSAL_BUILD */ |
||||
|
||||
/* Define to dlopen() amrnb. */ |
||||
/* #undef DL_AMRNB */ |
||||
|
||||
/* Define to dlopen() amrwb. */ |
||||
/* #undef DL_AMRWB */ |
||||
|
||||
/* Define to dlopen() lame. */ |
||||
/* #undef DL_LAME */ |
||||
|
||||
/* Define to dlopen() mad. */ |
||||
/* #undef DL_MAD */ |
||||
|
||||
/* Define to dlopen() sndfile. */ |
||||
/* #undef DL_SNDFILE */ |
||||
|
||||
/* Define to dlopen() libtwolame. */ |
||||
/* #undef DL_TWOLAME */ |
||||
|
||||
/* Define if SSP C support is enabled. */ |
||||
#define ENABLE_SSP_CC 1 |
||||
|
||||
/* Define if you are using an external GSM library */ |
||||
/* #undef EXTERNAL_GSM */ |
||||
|
||||
/* Define if you are using an external LPC10 library */ |
||||
/* #undef EXTERNAL_LPC10 */ |
||||
|
||||
/* Define to 1 if you have alsa. */ |
||||
/* #undef HAVE_ALSA */ |
||||
|
||||
/* Define to 1 if you have amrnb. */ |
||||
/* #undef HAVE_AMRNB */ |
||||
|
||||
/* Define to 1 if you have amrwb. */ |
||||
/* #undef HAVE_AMRWB */ |
||||
|
||||
/* Define to 1 if you have the <amrwb/dec.h> header file. */ |
||||
/* #undef HAVE_AMRWB_DEC_H */ |
||||
|
||||
/* Define to 1 if you have ao. */ |
||||
/* #undef HAVE_AO */ |
||||
|
||||
/* Define to 1 if you have the <byteswap.h> header file. */ |
||||
#define HAVE_BYTESWAP_H 1 |
||||
|
||||
/* Define to 1 if you have coreaudio. */ |
||||
/* #undef HAVE_COREAUDIO */ |
||||
|
||||
/* 1 if DISTRO is defined */ |
||||
/* #undef HAVE_DISTRO */ |
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */ |
||||
#define HAVE_DLFCN_H 1 |
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */ |
||||
#define HAVE_FCNTL_H 1 |
||||
|
||||
/* Define to 1 if you have the <fenv.h> header file. */ |
||||
#define HAVE_FENV_H 1 |
||||
|
||||
/* Define to 1 if you have flac. */ |
||||
/* #undef HAVE_FLAC */ |
||||
|
||||
/* Define to 1 if you have the `fmemopen' function. */ |
||||
/* #undef HAVE_FMEMOPEN */ |
||||
|
||||
/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ |
||||
/* #undef HAVE_FSEEKO */ |
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */ |
||||
#define HAVE_GETTIMEOFDAY 1 |
||||
|
||||
/* Define to 1 if you have the <glob.h> header file. */ |
||||
//#define HAVE_GLOB_H 1 //TODO
|
||||
|
||||
/* Define to 1 if you have gsm. */ |
||||
//#define HAVE_GSM 1 //TODO
|
||||
|
||||
/* Define to 1 if you have the <gsm/gsm.h> header file. */ |
||||
/* #undef HAVE_GSM_GSM_H */ |
||||
|
||||
/* Define to 1 if you have the <gsm.h> header file. */ |
||||
/* #undef HAVE_GSM_H */ |
||||
|
||||
/* Define to 1 if you have id3tag. */ |
||||
/* #undef HAVE_ID3TAG */ |
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */ |
||||
#define HAVE_INTTYPES_H 1 |
||||
|
||||
/* 1 if should enable LADSPA */ |
||||
/* #undef HAVE_LADSPA_H */ |
||||
|
||||
/* Define to 1 if you have the <lame.h> header file. */ |
||||
/* #undef HAVE_LAME_H */ |
||||
|
||||
/* Define to 1 if lame supports optional ID3 tags. */ |
||||
/* #undef HAVE_LAME_ID3TAG */ |
||||
|
||||
/* Define to 1 if you have the <lame/lame.h> header file. */ |
||||
/* #undef HAVE_LAME_LAME_H */ |
||||
|
||||
/* Define to 1 if you have libltdl */ |
||||
/* #undef HAVE_LIBLTDL */ |
||||
|
||||
/* Define to 1 if you have the <libpng/png.h> header file. */ |
||||
/* #undef HAVE_LIBPNG_PNG_H */ |
||||
|
||||
/* Define to 1 if you have lpc10. */ |
||||
//#define HAVE_LPC10 1 //TODO
|
||||
|
||||
/* Define to 1 if you have the <lpc10.h> header file. */ |
||||
/* #undef HAVE_LPC10_H */ |
||||
|
||||
/* Define to 1 if you have the `lrint' function. */ |
||||
#define HAVE_LRINT 1 |
||||
|
||||
/* Define to 1 if you have the <ltdl.h> header file. */ |
||||
/* #undef HAVE_LTDL_H */ |
||||
|
||||
/* Define to 1 if you have the <machine/soundcard.h> header file. */ |
||||
/* #undef HAVE_MACHINE_SOUNDCARD_H */ |
||||
|
||||
/* Define to 1 if you have the <mad.h> header file. */ |
||||
/* #undef HAVE_MAD_H */ |
||||
|
||||
/* Define to 1 if you have magic. */ |
||||
/* #undef HAVE_MAGIC */ |
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */ |
||||
#define HAVE_MEMORY_H 1 |
||||
|
||||
/* Define to 1 if you have the `mkstemp' function. */ |
||||
#define HAVE_MKSTEMP 1 |
||||
|
||||
/* Define to 1 if you have mp3. */ |
||||
/* #undef HAVE_MP3 */ |
||||
|
||||
/* Define to 1 if you have oggvorbis. */ |
||||
/* #undef HAVE_OGG_VORBIS */ |
||||
|
||||
/* Define to 1 if you have the <opencore-amrnb/interf_dec.h> header file. */ |
||||
/* #undef HAVE_OPENCORE_AMRNB_INTERF_DEC_H */ |
||||
|
||||
/* Define to 1 if you have the <opencore-amrwb/dec_if.h> header file. */ |
||||
/* #undef HAVE_OPENCORE_AMRWB_DEC_IF_H */ |
||||
|
||||
/* Define to 1 if you have opus. */ |
||||
//#define HAVE_OPUS 1 //TODO
|
||||
|
||||
/* Define to 1 if you have oss. */ |
||||
/* #undef HAVE_OSS */ |
||||
|
||||
/* Define to 1 if you have PNG. */ |
||||
/* #undef HAVE_PNG */ |
||||
|
||||
/* Define to 1 if you have the <png.h> header file. */ |
||||
/* #undef HAVE_PNG_H */ |
||||
|
||||
/* Define to 1 if you have the `popen' function. */ |
||||
#define HAVE_POPEN 1 |
||||
|
||||
/* Define to 1 if you have pulseaudio. */ |
||||
/* #undef HAVE_PULSEAUDIO */ |
||||
|
||||
/* Define if you have libsndfile with SFC_SFC_SET_SCALE_INT_FLOAT_WRITE */ |
||||
#define HAVE_SFC_SET_SCALE_INT_FLOAT_WRITE 1 |
||||
|
||||
/* Define to 1 if you have sndfile. */ |
||||
/* #undef HAVE_SNDFILE */ |
||||
|
||||
/* Define if you have libsndfile >= 1.0.18 */ |
||||
#define HAVE_SNDFILE_1_0_18 1 |
||||
|
||||
/* Define if you have <sndfile.h> */ |
||||
#define HAVE_SNDFILE_H 1 |
||||
|
||||
/* Define to 1 if you have sndio. */ |
||||
/* #undef HAVE_SNDIO */ |
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */ |
||||
#define HAVE_STDINT_H 1 |
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */ |
||||
#define HAVE_STDLIB_H 1 |
||||
|
||||
/* Define to 1 if you have the `strcasecmp' function. */ |
||||
#define HAVE_STRCASECMP 1 |
||||
|
||||
/* Define to 1 if you have the `strdup' function. */ |
||||
#define HAVE_STRDUP 1 |
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */ |
||||
#define HAVE_STRINGS_H 1 |
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */ |
||||
#define HAVE_STRING_H 1 |
||||
|
||||
/* Define to 1 if you have sunaudio. */ |
||||
/* #undef HAVE_SUN_AUDIO */ |
||||
|
||||
/* Define to 1 if you have the <sun/audioio.h> header file. */ |
||||
/* #undef HAVE_SUN_AUDIOIO_H */ |
||||
|
||||
/* Define to 1 if you have the <sys/audioio.h> header file. */ |
||||
/* #undef HAVE_SYS_AUDIOIO_H */ |
||||
|
||||
/* Define to 1 if you have the <sys/soundcard.h> header file. */ |
||||
/* #undef HAVE_SYS_SOUNDCARD_H */ |
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */ |
||||
#define HAVE_SYS_STAT_H 1 |
||||
|
||||
/* Define to 1 if you have the <sys/timeb.h> header file. */ |
||||
/* #undef HAVE_SYS_TIMEB_H */ |
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */ |
||||
#define HAVE_SYS_TIME_H 1 |
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */ |
||||
#define HAVE_SYS_TYPES_H 1 |
||||
|
||||
/* Define to 1 if you have the <sys/utsname.h> header file. */ |
||||
#define HAVE_SYS_UTSNAME_H 1 |
||||
|
||||
/* Define to 1 if you have the <termios.h> header file. */ |
||||
#define HAVE_TERMIOS_H 1 |
||||
|
||||
/* Define to 1 if you have the <twolame.h> header file. */ |
||||
/* #undef HAVE_TWOLAME_H */ |
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */ |
||||
#define HAVE_UNISTD_H 1 |
||||
|
||||
/* Define to 1 if you have the `vsnprintf' function. */ |
||||
#define HAVE_VSNPRINTF 1 |
||||
|
||||
/* Define to 1 if you have waveaudio. */ |
||||
/* #undef HAVE_WAVEAUDIO */ |
||||
|
||||
/* Define to 1 if you have wavpack. */ |
||||
/* #undef HAVE_WAVPACK */ |
||||
|
||||
/* Define to 1 to use win32 glob */ |
||||
/* #undef HAVE_WIN32_GLOB_H */ |
||||
|
||||
/* Define to 1 to use internal win32 ltdl */ |
||||
/* #undef HAVE_WIN32_LTDL_H */ |
||||
|
||||
/* Define to the sub-directory where libtool stores uninstalled libraries. */ |
||||
#define LT_OBJDIR ".libs/" |
||||
|
||||
/* Name of package */ |
||||
#define PACKAGE "sox" |
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */ |
||||
#define PACKAGE_BUGREPORT "sox-devel@lists.sourceforge.net" |
||||
|
||||
/* Define to the full name of this package. */ |
||||
#define PACKAGE_NAME "SoX" |
||||
|
||||
/* Define to the full name and version of this package. */ |
||||
#define PACKAGE_STRING "SoX 14.4.2" |
||||
|
||||
/* Define to the one symbol short name of this package. */ |
||||
#define PACKAGE_TARNAME "sox" |
||||
|
||||
/* Define to the home page for this package. */ |
||||
#define PACKAGE_URL "" |
||||
|
||||
/* Define to the version of this package. */ |
||||
#define PACKAGE_VERSION "14.4.2" |
||||
|
||||
/* Define to 1 if you have static alsa. */ |
||||
/* #undef STATIC_ALSA */ |
||||
|
||||
/* Define to 1 if you have static amrnb. */ |
||||
/* #undef STATIC_AMRNB */ |
||||
|
||||
/* Define to 1 if you have static amrwb. */ |
||||
/* #undef STATIC_AMRWB */ |
||||
|
||||
/* Define to 1 if you have static ao. */ |
||||
/* #undef STATIC_AO */ |
||||
|
||||
/* Define to 1 if you have static coreaudio. */ |
||||
/* #undef STATIC_COREAUDIO */ |
||||
|
||||
/* Define to 1 if you have static flac. */ |
||||
/* #undef STATIC_FLAC */ |
||||
|
||||
/* Define to 1 if you have static gsm. */ |
||||
#define STATIC_GSM 1 |
||||
|
||||
/* Define to 1 if you have static lpc10. */ |
||||
#define STATIC_LPC10 1 |
||||
|
||||
/* Define to 1 if you have static mp3. */ |
||||
/* #undef STATIC_MP3 */ |
||||
|
||||
/* Define to 1 if you have static oggvorbis. */ |
||||
/* #undef STATIC_OGG_VORBIS */ |
||||
|
||||
/* Define to 1 if you have static opus. */ |
||||
#define STATIC_OPUS 1 |
||||
|
||||
/* Define to 1 if you have static oss. */ |
||||
/* #undef STATIC_OSS */ |
||||
|
||||
/* Define to 1 if you have static pulseaudio. */ |
||||
/* #undef STATIC_PULSEAUDIO */ |
||||
|
||||
/* Define to 1 if you have static sndfile. */ |
||||
/* #undef STATIC_SNDFILE */ |
||||
|
||||
/* Define to 1 if you have static sndio. */ |
||||
/* #undef STATIC_SNDIO */ |
||||
|
||||
/* Define to 1 if you have static sunaudio. */ |
||||
/* #undef STATIC_SUN_AUDIO */ |
||||
|
||||
/* Define to 1 if you have static waveaudio. */ |
||||
/* #undef STATIC_WAVEAUDIO */ |
||||
|
||||
/* Define to 1 if you have static wavpack. */ |
||||
/* #undef STATIC_WAVPACK */ |
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */ |
||||
#define STDC_HEADERS 1 |
||||
|
||||
/* Version number of package */ |
||||
#define VERSION "14.4.2" |
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */ |
||||
#if defined AC_APPLE_UNIVERSAL_BUILD |
||||
# if defined __BIG_ENDIAN__ |
||||
# define WORDS_BIGENDIAN 1 |
||||
# endif |
||||
#else |
||||
# ifndef WORDS_BIGENDIAN |
||||
/* # undef WORDS_BIGENDIAN */ |
||||
# endif |
||||
#endif |
||||
|
||||
/* Enable large inode numbers on Mac OS X 10.5. */ |
||||
#ifndef _DARWIN_USE_64_BIT_INODE |
||||
# define _DARWIN_USE_64_BIT_INODE 1 |
||||
#endif |
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */ |
||||
#define _FILE_OFFSET_BITS 64 |
||||
|
||||
/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ |
||||
#define _LARGEFILE_SOURCE 1 |
||||
|
||||
/* Define for large files, on AIX-style hosts. */ |
||||
/* #undef _LARGE_FILES */ |
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */ |
||||
#ifndef __cplusplus |
||||
/* #undef inline */ |
||||
#endif |
@ -1,47 +0,0 @@ |
||||
#include "soxconfig.h" |
||||
|
||||
#ifdef _OPENMP |
||||
#if _OPENMP >= 200805 /* OpenMP 3.0 */ |
||||
#define HAVE_OPENMP 1 |
||||
#endif |
||||
#if _OPENMP >= 201107 /* OpenMP 3.1 */ |
||||
#define HAVE_OPENMP_3_1 1 |
||||
#endif |
||||
#endif |
||||
|
||||
#ifdef HAVE_OPENMP |
||||
#include <omp.h> |
||||
#else |
||||
|
||||
typedef int omp_lock_t; |
||||
typedef int omp_nest_lock_t; |
||||
|
||||
#define omp_set_num_threads(int) (void)0 |
||||
#define omp_get_num_threads() 1 |
||||
#define omp_get_max_threads() 1 |
||||
#define omp_get_thread_num() 0 |
||||
#define omp_get_num_procs() 1 |
||||
#define omp_in_parallel() 1 |
||||
|
||||
#define omp_set_dynamic(int) (void)0 |
||||
#define omp_get_dynamic() 0 |
||||
|
||||
#define omp_set_nested(int) (void)0 |
||||
#define omp_get_nested() 0 |
||||
|
||||
#define omp_init_lock(omp_lock_t) (void)0 |
||||
#define omp_destroy_lock(omp_lock_t) (void)0 |
||||
#define omp_set_lock(omp_lock_t) (void)0 |
||||
#define omp_unset_lock(omp_lock_t) (void)0 |
||||
#define omp_test_lock(omp_lock_t) 0 |
||||
|
||||
#define omp_init_nest_lock(omp_nest_lock_t) (void)0 |
||||
#define omp_destroy_nest_lock(omp_nest_lock_t) (void)0 |
||||
#define omp_set_nest_lock(omp_nest_lock_t) (void)0 |
||||
#define omp_unset_nest_lock(omp_nest_lock_t) (void)0 |
||||
#define omp_test_nest_lock(omp_nest_lock_t) 0 |
||||
|
||||
#define omp_get_wtime() 0 |
||||
#define omp_get_wtick() 0 |
||||
|
||||
#endif |
@ -1,73 +0,0 @@ |
||||
/* libSoX Effect: Adjust the audio speed (pitch and tempo together)
|
||||
* (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 |
||||
* |
||||
* |
||||
* Adjustment is given as the ratio of the new speed to the old speed, or as |
||||
* a number of cents (100ths of a semitone) to change. Speed change is |
||||
* actually performed by whichever resampling effect is in effect. |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include <string.h> |
||||
|
||||
typedef struct { |
||||
double factor; |
||||
} priv_t; |
||||
|
||||
static int getopts(sox_effect_t * effp, int argc, char * * argv) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
sox_bool is_cents = sox_false; |
||||
|
||||
--argc, ++argv; |
||||
if (argc == 1) { |
||||
char c, dummy; |
||||
int scanned = sscanf(*argv, "%lf%c %c", &p->factor, &c, &dummy); |
||||
if (scanned == 1 || (scanned == 2 && c == 'c')) { |
||||
is_cents |= scanned == 2; |
||||
if (is_cents || p->factor > 0) { |
||||
p->factor = is_cents? pow(2., p->factor / 1200) : p->factor; |
||||
return SOX_SUCCESS; |
||||
} |
||||
} |
||||
} |
||||
return lsx_usage(effp); |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
|
||||
if (p->factor == 1) |
||||
return SOX_EFF_NULL; |
||||
|
||||
effp->out_signal.rate = effp->in_signal.rate * p->factor; |
||||
|
||||
effp->out_signal.length = effp->in_signal.length; |
||||
/* audio length if measured in samples doesn't change */ |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_speed_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"speed", "factor[c]", |
||||
SOX_EFF_MCHAN | SOX_EFF_RATE | SOX_EFF_LENGTH | SOX_EFF_MODIFY, |
||||
getopts, start, lsx_flow_copy, 0, 0, 0, sizeof(priv_t)}; |
||||
return &handler; |
||||
} |
@ -1,360 +0,0 @@ |
||||
/* libSoX effect: change tempo (and duration) or pitch (maintain duration)
|
||||
* Copyright (c) 2007,8 robs@users.sourceforge.net |
||||
* Based on ideas from Olli Parviainen's SoundTouch Library. |
||||
* |
||||
* 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 "fifo.h" |
||||
#include <math.h> |
||||
|
||||
typedef struct { |
||||
/* Configuration parameters: */ |
||||
size_t channels; |
||||
sox_bool quick_search; /* Whether to quick search or linear search */ |
||||
double factor; /* 1 for no change, < 1 for slower, > 1 for faster. */ |
||||
size_t search; /* Wide samples to search for best overlap position */ |
||||
size_t segment; /* Processing segment length in wide samples */ |
||||
size_t overlap; /* In wide samples */ |
||||
|
||||
size_t process_size; /* # input wide samples needed to process 1 segment */ |
||||
|
||||
/* Buffers: */ |
||||
fifo_t input_fifo; |
||||
float * overlap_buf; |
||||
fifo_t output_fifo; |
||||
|
||||
/* Counters: */ |
||||
uint64_t samples_in; |
||||
uint64_t samples_out; |
||||
uint64_t segments_total; |
||||
uint64_t skip_total; |
||||
} tempo_t; |
||||
|
||||
/* Waveform Similarity by least squares; works across multi-channels */ |
||||
static float difference(const float * a, const float * b, size_t length) |
||||
{ |
||||
float diff = 0; |
||||
size_t i = 0; |
||||
|
||||
#define _ diff += sqr(a[i] - b[i]), ++i; /* Loop optimisation */ |
||||
do {_ _ _ _ _ _ _ _} while (i < length); /* N.B. length ≡ 0 (mod 8) */ |
||||
#undef _ |
||||
return diff; |
||||
} |
||||
|
||||
/* Find where the two segments are most alike over the overlap period. */ |
||||
static size_t tempo_best_overlap_position(tempo_t * t, float const * new_win) |
||||
{ |
||||
float * f = t->overlap_buf; |
||||
size_t j, best_pos, prev_best_pos = (t->search + 1) >> 1, step = 64; |
||||
size_t i = best_pos = t->quick_search? prev_best_pos : 0; |
||||
float diff, least_diff = difference(new_win + t->channels * i, f, t->channels * t->overlap); |
||||
int k = 0; |
||||
|
||||
if (t->quick_search) do { /* hierarchical search */ |
||||
for (k = -1; k <= 1; k += 2) for (j = 1; j < 4 || step == 64; ++j) { |
||||
i = prev_best_pos + k * j * step; |
||||
if ((int)i < 0 || i >= t->search) |
||||
break; |
||||
diff = difference(new_win + t->channels * i, f, t->channels * t->overlap); |
||||
if (diff < least_diff) |
||||
least_diff = diff, best_pos = i; |
||||
} |
||||
prev_best_pos = best_pos; |
||||
} while (step >>= 2); |
||||
else for (i = 1; i < t->search; i++) { /* linear search */ |
||||
diff = difference(new_win + t->channels * i, f, t->channels * t->overlap); |
||||
if (diff < least_diff) |
||||
least_diff = diff, best_pos = i; |
||||
} |
||||
return best_pos; |
||||
} |
||||
|
||||
static void tempo_overlap( |
||||
tempo_t * t, const float * in1, const float * in2, float * output) |
||||
{ |
||||
size_t i, j, k = 0; |
||||
float fade_step = 1.0f / (float) t->overlap; |
||||
|
||||
for (i = 0; i < t->overlap; ++i) { |
||||
float fade_in = fade_step * (float) i; |
||||
float fade_out = 1.0f - fade_in; |
||||
for (j = 0; j < t->channels; ++j, ++k) |
||||
output[k] = in1[k] * fade_out + in2[k] * fade_in; |
||||
} |
||||
} |
||||
|
||||
static void tempo_process(tempo_t * t) |
||||
{ |
||||
while (fifo_occupancy(&t->input_fifo) >= t->process_size) { |
||||
size_t skip, offset; |
||||
|
||||
/* Copy or overlap the first bit to the output */ |
||||
if (!t->segments_total) { |
||||
offset = t->search / 2; |
||||
fifo_write(&t->output_fifo, t->overlap, (float *) fifo_read_ptr(&t->input_fifo) + t->channels * offset); |
||||
} else { |
||||
offset = tempo_best_overlap_position(t, fifo_read_ptr(&t->input_fifo)); |
||||
tempo_overlap(t, t->overlap_buf, |
||||
(float *) fifo_read_ptr(&t->input_fifo) + t->channels * offset, |
||||
fifo_write(&t->output_fifo, t->overlap, NULL)); |
||||
} |
||||
/* Copy the middle bit to the output */ |
||||
fifo_write(&t->output_fifo, t->segment - 2 * t->overlap, |
||||
(float *) fifo_read_ptr(&t->input_fifo) + |
||||
t->channels * (offset + t->overlap)); |
||||
|
||||
/* Copy the end bit to overlap_buf ready to be mixed with
|
||||
* the beginning of the next segment. */ |
||||
memcpy(t->overlap_buf, |
||||
(float *) fifo_read_ptr(&t->input_fifo) + |
||||
t->channels * (offset + t->segment - t->overlap), |
||||
t->channels * t->overlap * sizeof(*(t->overlap_buf))); |
||||
|
||||
/* Advance through the input stream */ |
||||
skip = t->factor * (++t->segments_total * (t->segment - t->overlap)) + 0.5; |
||||
t->skip_total += skip -= t->skip_total; |
||||
fifo_read(&t->input_fifo, skip, NULL); |
||||
} |
||||
} |
||||
|
||||
static float * tempo_input(tempo_t * t, float const * samples, size_t n) |
||||
{ |
||||
t->samples_in += n; |
||||
return fifo_write(&t->input_fifo, n, samples); |
||||
} |
||||
|
||||
static float const * tempo_output(tempo_t * t, float * samples, size_t * n) |
||||
{ |
||||
t->samples_out += *n = min(*n, fifo_occupancy(&t->output_fifo)); |
||||
return fifo_read(&t->output_fifo, *n, samples); |
||||
} |
||||
|
||||
/* Flush samples remaining in overlap_buf & input_fifo to the output. */ |
||||
static void tempo_flush(tempo_t * t) |
||||
{ |
||||
uint64_t samples_out = t->samples_in / t->factor + .5; |
||||
size_t remaining = samples_out > t->samples_out ? |
||||
(size_t)(samples_out - t->samples_out) : 0; |
||||
float * buff = lsx_calloc(128 * t->channels, sizeof(*buff)); |
||||
|
||||
if (remaining > 0) { |
||||
while (fifo_occupancy(&t->output_fifo) < remaining) { |
||||
tempo_input(t, buff, (size_t) 128); |
||||
tempo_process(t); |
||||
} |
||||
fifo_trim_to(&t->output_fifo, remaining); |
||||
t->samples_in = 0; |
||||
} |
||||
free(buff); |
||||
} |
||||
|
||||
static void tempo_setup(tempo_t * t, |
||||
double sample_rate, sox_bool quick_search, double factor, |
||||
double segment_ms, double search_ms, double overlap_ms) |
||||
{ |
||||
size_t max_skip; |
||||
t->quick_search = quick_search; |
||||
t->factor = factor; |
||||
t->segment = sample_rate * segment_ms / 1000 + .5; |
||||
t->search = sample_rate * search_ms / 1000 + .5; |
||||
t->overlap = max(sample_rate * overlap_ms / 1000 + 4.5, 16); |
||||
t->overlap &= ~7; /* Make divisible by 8 for loop optimisation */ |
||||
if (t->overlap * 2 > t->segment) |
||||
t->overlap -= 8; |
||||
t->overlap_buf = lsx_malloc(t->overlap * t->channels * sizeof(*t->overlap_buf)); |
||||
max_skip = ceil(factor * (t->segment - t->overlap)); |
||||
t->process_size = max(max_skip + t->overlap, t->segment) + t->search; |
||||
memset(fifo_reserve(&t->input_fifo, t->search / 2), 0, (t->search / 2) * t->channels * sizeof(float)); |
||||
} |
||||
|
||||
static void tempo_delete(tempo_t * t) |
||||
{ |
||||
free(t->overlap_buf); |
||||
fifo_delete(&t->output_fifo); |
||||
fifo_delete(&t->input_fifo); |
||||
free(t); |
||||
} |
||||
|
||||
static tempo_t * tempo_create(size_t channels) |
||||
{ |
||||
tempo_t * t = lsx_calloc(1, sizeof(*t)); |
||||
t->channels = channels; |
||||
fifo_create(&t->input_fifo, t->channels * sizeof(float)); |
||||
fifo_create(&t->output_fifo, t->channels * sizeof(float)); |
||||
return t; |
||||
} |
||||
|
||||
/*------------------------------- SoX Wrapper --------------------------------*/ |
||||
|
||||
typedef struct { |
||||
tempo_t * tempo; |
||||
sox_bool quick_search; |
||||
double factor, segment_ms, search_ms, overlap_ms; |
||||
} priv_t; |
||||
|
||||
static int getopts(sox_effect_t * effp, int argc, char **argv) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
enum {Default, Music, Speech, Linear} profile = Default; |
||||
static const double segments_ms [] = { 82,82, 35 , 20}; |
||||
static const double segments_pow[] = { 0, 1, .33 , 1}; |
||||
static const double overlaps_div[] = {6.833, 7, 2.5 , 2}; |
||||
static const double searches_div[] = {5.587, 6, 2.14, 2}; |
||||
int c; |
||||
lsx_getopt_t optstate; |
||||
lsx_getopt_init(argc, argv, "+qmls", NULL, lsx_getopt_flag_none, 1, &optstate); |
||||
|
||||
p->segment_ms = p->search_ms = p->overlap_ms = HUGE_VAL; |
||||
while ((c = lsx_getopt(&optstate)) != -1) switch (c) { |
||||
case 'q': p->quick_search = sox_true; break; |
||||
case 'm': profile = Music; break; |
||||
case 's': profile = Speech; break; |
||||
case 'l': profile = Linear; p->search_ms = 0; break; |
||||
default: lsx_fail("unknown option `-%c'", optstate.opt); return lsx_usage(effp); |
||||
} |
||||
argc -= optstate.ind, argv += optstate.ind; |
||||
do { /* break-able block */ |
||||
NUMERIC_PARAMETER(factor ,0.1 , 100 ) |
||||
NUMERIC_PARAMETER(segment_ms , 10 , 120) |
||||
NUMERIC_PARAMETER(search_ms , 0 , 30 ) |
||||
NUMERIC_PARAMETER(overlap_ms , 0 , 30 ) |
||||
} while (0); |
||||
|
||||
if (p->segment_ms == HUGE_VAL) |
||||
p->segment_ms = max(10, segments_ms[profile] / max(pow(p->factor, segments_pow[profile]), 1)); |
||||
if (p->overlap_ms == HUGE_VAL) |
||||
p->overlap_ms = p->segment_ms / overlaps_div[profile]; |
||||
if (p->search_ms == HUGE_VAL) |
||||
p->search_ms = p->segment_ms / searches_div[profile]; |
||||
|
||||
p->overlap_ms = min(p->overlap_ms, p->segment_ms / 2); |
||||
lsx_report("quick_search=%u factor=%g segment=%g search=%g overlap=%g", |
||||
p->quick_search, p->factor, p->segment_ms, p->search_ms, p->overlap_ms); |
||||
return argc? lsx_usage(effp) : SOX_SUCCESS; |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
|
||||
if (p->factor == 1) |
||||
return SOX_EFF_NULL; |
||||
|
||||
p->tempo = tempo_create((size_t)effp->in_signal.channels); |
||||
tempo_setup(p->tempo, effp->in_signal.rate, p->quick_search, p->factor, |
||||
p->segment_ms, p->search_ms, p->overlap_ms); |
||||
|
||||
effp->out_signal.length = SOX_UNKNOWN_LEN; |
||||
if (effp->in_signal.length != SOX_UNKNOWN_LEN) { |
||||
uint64_t in_length = effp->in_signal.length / effp->in_signal.channels; |
||||
uint64_t out_length = in_length / p->factor + .5; |
||||
effp->out_signal.length = out_length * effp->in_signal.channels; |
||||
} |
||||
|
||||
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, odone = *osamp /= effp->in_signal.channels; |
||||
float const * s = tempo_output(p->tempo, NULL, &odone); |
||||
SOX_SAMPLE_LOCALS; |
||||
|
||||
for (i = 0; i < odone * effp->in_signal.channels; ++i) |
||||
*obuf++ = SOX_FLOAT_32BIT_TO_SAMPLE(*s++, effp->clips); |
||||
|
||||
if (*isamp && odone < *osamp) { |
||||
float * t = tempo_input(p->tempo, NULL, *isamp / effp->in_signal.channels); |
||||
for (i = *isamp; i; --i) |
||||
*t++ = SOX_SAMPLE_TO_FLOAT_32BIT(*ibuf++, effp->clips); |
||||
tempo_process(p->tempo); |
||||
} |
||||
else *isamp = 0; |
||||
|
||||
*osamp = odone * effp->in_signal.channels; |
||||
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; |
||||
tempo_flush(p->tempo); |
||||
return flow(effp, 0, obuf, &isamp, osamp); |
||||
} |
||||
|
||||
static int stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
tempo_delete(p->tempo); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_tempo_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"tempo", "[-q] [-m | -s | -l] factor [segment-ms [search-ms [overlap-ms]]]", |
||||
SOX_EFF_MCHAN | SOX_EFF_LENGTH, |
||||
getopts, start, flow, drain, stop, NULL, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
||||
|
||||
/*---------------------------------- pitch -----------------------------------*/ |
||||
|
||||
static int pitch_getopts(sox_effect_t * effp, int argc, char **argv) |
||||
{ |
||||
double d; |
||||
char dummy, arg[100], **argv2 = lsx_malloc(argc * sizeof(*argv2)); |
||||
int result, pos = (argc > 1 && !strcmp(argv[1], "-q"))? 2 : 1; |
||||
|
||||
if (argc <= pos || sscanf(argv[pos], "%lf %c", &d, &dummy) != 1) |
||||
return lsx_usage(effp); |
||||
|
||||
d = pow(2., d / 1200); /* cents --> factor */ |
||||
sprintf(arg, "%g", 1 / d); |
||||
memcpy(argv2, argv, argc * sizeof(*argv2)); |
||||
argv2[pos] = arg; |
||||
result = getopts(effp, argc, argv2); |
||||
free(argv2); |
||||
return result; |
||||
} |
||||
|
||||
static int pitch_start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
int result = start(effp); |
||||
|
||||
effp->out_signal.rate = effp->in_signal.rate / p->factor; |
||||
return result; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_pitch_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler; |
||||
handler = *lsx_tempo_effect_fn(); |
||||
handler.name = "pitch"; |
||||
handler.usage = "[-q] shift-in-cents [segment-ms [search-ms [overlap-ms]]]", |
||||
handler.getopts = pitch_getopts; |
||||
handler.start = pitch_start; |
||||
handler.flags &= ~SOX_EFF_LENGTH; |
||||
handler.flags |= SOX_EFF_RATE; |
||||
return &handler; |
||||
} |
@ -1,64 +0,0 @@ |
||||
/* libSoX effect: Upsample (zero stuff) (c) 2011 robs@users.sourceforge.net
|
||||
* |
||||
* Sometimes filters perform better at higher sampling rates, so e.g. |
||||
* sox -r 48k input output upsample 4 filter rate 48k vol 4 |
||||
* |
||||
* 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 factor, pos;} 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 {NUMERIC_PARAMETER(factor, 1, 256)} 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; |
||||
while (sox_true) { |
||||
for (; p->pos && olen; p->pos = (p->pos + 1) % p->factor, --olen) |
||||
*obuf++ = 0; |
||||
if (!ilen || !olen) |
||||
break; |
||||
*obuf++ = *ibuf++; |
||||
--olen, --ilen; |
||||
++p->pos; |
||||
} |
||||
*isamp -= ilen, *osamp -= olen; |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_upsample_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = {"upsample", "[factor (2)]", |
||||
SOX_EFF_RATE | SOX_EFF_MODIFY, create, start, flow, NULL, NULL, NULL, sizeof(priv_t)}; |
||||
return &handler; |
||||
} |
@ -1,304 +0,0 @@ |
||||
/* General purpose, i.e. non SoX specific, utility functions.
|
||||
* Copyright (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 <ctype.h> |
||||
#include <stdio.h> |
||||
|
||||
int lsx_strcasecmp(const char * s1, const char * s2) |
||||
{ |
||||
#if defined(HAVE_STRCASECMP) |
||||
return strcasecmp(s1, s2); |
||||
#elif defined(_MSC_VER) |
||||
return _stricmp(s1, s2); |
||||
#else |
||||
while (*s1 && (toupper(*s1) == toupper(*s2))) |
||||
s1++, s2++; |
||||
return toupper(*s1) - toupper(*s2); |
||||
#endif |
||||
} |
||||
|
||||
int lsx_strncasecmp(char const * s1, char const * s2, size_t n) |
||||
{ |
||||
#if defined(HAVE_STRCASECMP) |
||||
return strncasecmp(s1, s2, n); |
||||
#elif defined(_MSC_VER) |
||||
return _strnicmp(s1, s2, n); |
||||
#else |
||||
while (--n && *s1 && (toupper(*s1) == toupper(*s2))) |
||||
s1++, s2++; |
||||
return toupper(*s1) - toupper(*s2); |
||||
#endif |
||||
} |
||||
|
||||
sox_bool lsx_strends(char const * str, char const * end) |
||||
{ |
||||
size_t str_len = strlen(str), end_len = strlen(end); |
||||
return str_len >= end_len && !strcmp(str + str_len - end_len, end); |
||||
} |
||||
|
||||
char const * lsx_find_file_extension(char const * pathname) |
||||
{ |
||||
/* First, chop off any path portions of filename. This
|
||||
* prevents the next search from considering that part. */ |
||||
char const * result = LAST_SLASH(pathname); |
||||
if (!result) |
||||
result = pathname; |
||||
|
||||
/* Now look for an filename extension */ |
||||
result = strrchr(result, '.'); |
||||
if (result) |
||||
++result; |
||||
return result; |
||||
} |
||||
|
||||
lsx_enum_item const * lsx_find_enum_text(char const * text, lsx_enum_item const * enum_items, int flags) |
||||
{ |
||||
lsx_enum_item const * result = NULL; /* Assume not found */ |
||||
sox_bool sensitive = !!(flags & lsx_find_enum_item_case_sensitive); |
||||
|
||||
while (enum_items->text) { |
||||
if ((!sensitive && !strcasecmp(text, enum_items->text)) || |
||||
( sensitive && ! strcmp(text, enum_items->text))) |
||||
return enum_items; /* Found exact match */ |
||||
if ((!sensitive && !strncasecmp(text, enum_items->text, strlen(text))) || |
||||
( sensitive && ! strncmp(text, enum_items->text, strlen(text)))) { |
||||
if (result != NULL && result->value != enum_items->value) |
||||
return NULL; /* Found ambiguity */ |
||||
result = enum_items; /* Found sub-string match */ |
||||
} |
||||
++enum_items; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
lsx_enum_item const * lsx_find_enum_value(unsigned value, lsx_enum_item const * enum_items) |
||||
{ |
||||
for (;enum_items->text; ++enum_items) |
||||
if (value == enum_items->value) |
||||
return enum_items; |
||||
return NULL; |
||||
} |
||||
|
||||
int lsx_enum_option(int c, char const * arg, lsx_enum_item const * items) |
||||
{ |
||||
lsx_enum_item const * p = lsx_find_enum_text(arg, items, sox_false); |
||||
if (p == NULL) { |
||||
size_t len = 1; |
||||
char * set = lsx_malloc(len); |
||||
*set = 0; |
||||
for (p = items; p->text; ++p) { |
||||
set = lsx_realloc(set, len += 2 + strlen(p->text)); |
||||
strcat(set, ", "); strcat(set, p->text); |
||||
} |
||||
lsx_fail("-%c: `%s' is not one of: %s.", c, arg, set + 2); |
||||
free(set); |
||||
return INT_MAX; |
||||
} |
||||
return p->value; |
||||
} |
||||
|
||||
char const * lsx_sigfigs3(double number) |
||||
{ |
||||
static char const symbols[] = "\0kMGTPEZY"; |
||||
static char string[16][10]; /* FIXME: not thread-safe */ |
||||
static unsigned n; /* ditto */ |
||||
unsigned a, b, c; |
||||
sprintf(string[n = (n+1) & 15], "%#.3g", number); |
||||
switch (sscanf(string[n], "%u.%ue%u", &a, &b, &c)) { |
||||
case 2: if (b) return string[n]; /* Can fall through */ |
||||
case 1: c = 2; break; |
||||
case 3: a = 100*a + b; break; |
||||
} |
||||
if (c < array_length(symbols) * 3 - 3) switch (c%3) { |
||||
case 0: sprintf(string[n], "%u.%02u%c", a/100,a%100, symbols[c/3]); break; |
||||
case 1: sprintf(string[n], "%u.%u%c" , a/10 ,a%10 , symbols[c/3]); break; |
||||
case 2: sprintf(string[n], "%u%c" , a , symbols[c/3]); break; |
||||
} |
||||
return string[n]; |
||||
} |
||||
|
||||
char const * lsx_sigfigs3p(double percentage) |
||||
{ |
||||
static char string[16][10]; |
||||
static unsigned n; |
||||
sprintf(string[n = (n+1) & 15], "%.1f%%", percentage); |
||||
if (strlen(string[n]) < 5) |
||||
sprintf(string[n], "%.2f%%", percentage); |
||||
else if (strlen(string[n]) > 5) |
||||
sprintf(string[n], "%.0f%%", percentage); |
||||
return string[n]; |
||||
} |
||||
|
||||
int lsx_open_dllibrary( |
||||
int show_error_on_failure, |
||||
const char* library_description, |
||||
const char* const library_names[] UNUSED, |
||||
const lsx_dlfunction_info func_infos[], |
||||
lsx_dlptr selected_funcs[], |
||||
lsx_dlhandle* pdl) |
||||
{ |
||||
int failed = 0; |
||||
lsx_dlhandle dl = NULL; |
||||
|
||||
/* Track enough information to give a good error message about one failure.
|
||||
* Let failed symbol load override failed library open, and let failed |
||||
* library open override missing static symbols. |
||||
*/ |
||||
const char* failed_libname = NULL; |
||||
const char* failed_funcname = NULL; |
||||
|
||||
#ifdef HAVE_LIBLTDL |
||||
if (library_names && library_names[0]) |
||||
{ |
||||
const char* const* libname; |
||||
if (lt_dlinit()) |
||||
{ |
||||
lsx_fail( |
||||
"Unable to load %s - failed to initialize ltdl.", |
||||
library_description); |
||||
return 1; |
||||
} |
||||
|
||||
for (libname = library_names; *libname; libname++) |
||||
{ |
||||
lsx_debug("Attempting to open %s (%s).", library_description, *libname); |
||||
dl = lt_dlopenext(*libname); |
||||
if (dl) |
||||
{ |
||||
size_t i; |
||||
lsx_debug("Opened %s (%s).", library_description, *libname); |
||||
for (i = 0; func_infos[i].name; i++) |
||||
{ |
||||
union {lsx_dlptr fn; lt_ptr ptr;} func; |
||||
func.ptr = lt_dlsym(dl, func_infos[i].name); |
||||
selected_funcs[i] = func.fn ? func.fn : func_infos[i].stub_func; |
||||
if (!selected_funcs[i]) |
||||
{ |
||||
lt_dlclose(dl); |
||||
dl = NULL; |
||||
failed_libname = *libname; |
||||
failed_funcname = func_infos[i].name; |
||||
lsx_debug("Cannot use %s (%s) - missing function \"%s\".", library_description, failed_libname, failed_funcname); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (dl) |
||||
break; |
||||
} |
||||
else if (!failed_libname) |
||||
{ |
||||
failed_libname = *libname; |
||||
} |
||||
} |
||||
|
||||
if (!dl) |
||||
lt_dlexit(); |
||||
} |
||||
#endif /* HAVE_LIBLTDL */ |
||||
|
||||
if (!dl) |
||||
{ |
||||
size_t i; |
||||
for (i = 0; func_infos[i].name; i++) |
||||
{ |
||||
selected_funcs[i] = |
||||
func_infos[i].static_func |
||||
? func_infos[i].static_func |
||||
: func_infos[i].stub_func; |
||||
if (!selected_funcs[i]) |
||||
{ |
||||
if (!failed_libname) |
||||
{ |
||||
failed_libname = "static"; |
||||
failed_funcname = func_infos[i].name; |
||||
} |
||||
|
||||
failed = 1; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (failed) |
||||
{ |
||||
size_t i; |
||||
for (i = 0; func_infos[i].name; i++) |
||||
selected_funcs[i] = NULL; |
||||
#ifdef HAVE_LIBLTDL |
||||
#define LTDL_MISSING "" |
||||
#else |
||||
#define LTDL_MISSING " (Dynamic library support not configured.)" |
||||
#endif /* HAVE_LIBLTDL */ |
||||
if (failed_funcname) |
||||
{ |
||||
if (show_error_on_failure) |
||||
lsx_fail( |
||||
"Unable to load %s (%s) function \"%s\"." LTDL_MISSING, |
||||
library_description, |
||||
failed_libname, |
||||
failed_funcname); |
||||
else |
||||
lsx_report( |
||||
"Unable to load %s (%s) function \"%s\"." LTDL_MISSING, |
||||
library_description, |
||||
failed_libname, |
||||
failed_funcname); |
||||
} |
||||
else if (failed_libname) |
||||
{ |
||||
if (show_error_on_failure) |
||||
lsx_fail( |
||||
"Unable to load %s (%s)." LTDL_MISSING, |
||||
library_description, |
||||
failed_libname); |
||||
else |
||||
lsx_report( |
||||
"Unable to load %s (%s)." LTDL_MISSING, |
||||
library_description, |
||||
failed_libname); |
||||
} |
||||
else |
||||
{ |
||||
if (show_error_on_failure) |
||||
lsx_fail( |
||||
"Unable to load %s - no dynamic library names selected." LTDL_MISSING, |
||||
library_description); |
||||
else |
||||
lsx_report( |
||||
"Unable to load %s - no dynamic library names selected." LTDL_MISSING, |
||||
library_description); |
||||
} |
||||
} |
||||
|
||||
*pdl = dl; |
||||
return failed; |
||||
} |
||||
|
||||
void lsx_close_dllibrary( |
||||
lsx_dlhandle dl UNUSED) |
||||
{ |
||||
#ifdef HAVE_LIBLTDL |
||||
if (dl) |
||||
{ |
||||
lt_dlclose(dl); |
||||
lt_dlexit(); |
||||
} |
||||
#endif /* HAVE_LIBLTDL */ |
||||
} |
@ -1,184 +0,0 @@ |
||||
/* General purpose, i.e. non SoX specific, utility functions and macros.
|
||||
* |
||||
* (c) 2006-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 <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <inttypes.h> |
||||
#include "soxconfig.h" |
||||
|
||||
#ifdef HAVE_SYS_TYPES_H |
||||
#include <sys/types.h> /* For off_t not found in stdio.h */ |
||||
#endif |
||||
|
||||
#ifdef HAVE_SYS_STAT_H |
||||
#include <sys/stat.h> /* Needs to be included before we redefine off_t. */ |
||||
#endif |
||||
|
||||
#include "xmalloc.h" |
||||
|
||||
/*---------------------------- Portability stuff -----------------------------*/ |
||||
|
||||
#ifdef __GNUC__ |
||||
#define NORET __attribute__((noreturn)) |
||||
#define UNUSED __attribute__ ((unused)) |
||||
#else |
||||
#define NORET |
||||
#define UNUSED |
||||
#endif |
||||
|
||||
#ifdef _MSC_VER |
||||
|
||||
#define __STDC__ 1 |
||||
#define O_BINARY _O_BINARY |
||||
#define O_CREAT _O_CREAT |
||||
#define O_RDWR _O_RDWR |
||||
#define O_TRUNC _O_TRUNC |
||||
#define S_IFMT _S_IFMT |
||||
#define S_IFREG _S_IFREG |
||||
#define S_IREAD _S_IREAD |
||||
#define S_IWRITE _S_IWRITE |
||||
#define close _close |
||||
#define dup _dup |
||||
#define fdopen _fdopen |
||||
#define fileno _fileno |
||||
|
||||
#ifdef _fstati64 |
||||
#define fstat _fstati64 |
||||
#else |
||||
#define fstat _fstat |
||||
#endif |
||||
|
||||
#define ftime _ftime |
||||
#define inline __inline |
||||
#define isatty _isatty |
||||
#define kbhit _kbhit |
||||
#define mktemp _mktemp |
||||
#define off_t _off_t |
||||
#define open _open |
||||
#define pclose _pclose |
||||
#define popen _popen |
||||
#define setmode _setmode |
||||
#define snprintf _snprintf |
||||
|
||||
#ifdef _stati64 |
||||
#define stat _stati64 |
||||
#else |
||||
#define stat _stat |
||||
#endif |
||||
|
||||
#define strdup _strdup |
||||
#define timeb _timeb |
||||
#define unlink _unlink |
||||
|
||||
#if defined(HAVE__FSEEKI64) && !defined(HAVE_FSEEKO) |
||||
#undef off_t |
||||
#define fseeko _fseeki64 |
||||
#define ftello _ftelli64 |
||||
#define off_t __int64 |
||||
#define HAVE_FSEEKO 1 |
||||
#endif |
||||
|
||||
#elif defined(__MINGW32__) |
||||
|
||||
#if !defined(HAVE_FSEEKO) |
||||
#undef off_t |
||||
#define fseeko fseeko64 |
||||
#define fstat _fstati64 |
||||
#define ftello ftello64 |
||||
#define off_t off64_t |
||||
#define stat _stati64 |
||||
#define HAVE_FSEEKO 1 |
||||
#endif |
||||
|
||||
#endif |
||||
|
||||
#if defined(DOS) || defined(WIN32) || defined(__NT__) || defined(__DJGPP__) || defined(__OS2__) |
||||
#define LAST_SLASH(path) max(strrchr(path, '/'), strrchr(path, '\\')) |
||||
#define IS_ABSOLUTE(path) ((path)[0] == '/' || (path)[0] == '\\' || (path)[1] == ':') |
||||
#define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) |
||||
#define POPEN_MODE "rb" |
||||
#else |
||||
#define LAST_SLASH(path) strrchr(path, '/') |
||||
#define IS_ABSOLUTE(path) ((path)[0] == '/') |
||||
#define SET_BINARY_MODE(file) |
||||
#endif |
||||
|
||||
#ifdef WORDS_BIGENDIAN |
||||
#define MACHINE_IS_BIGENDIAN 1 |
||||
#define MACHINE_IS_LITTLEENDIAN 0 |
||||
#else |
||||
#define MACHINE_IS_BIGENDIAN 0 |
||||
#define MACHINE_IS_LITTLEENDIAN 1 |
||||
#endif |
||||
|
||||
/*--------------------------- Language extensions ----------------------------*/ |
||||
|
||||
/* Compile-time ("static") assertion */ |
||||
/* e.g. assert_static(sizeof(int) >= 4, int_type_too_small) */ |
||||
#define assert_static(e,f) enum {assert_static__##f = 1/(e)} |
||||
#define array_length(a) (sizeof(a)/sizeof(a[0])) |
||||
#define field_offset(type, field) ((size_t)&(((type *)0)->field)) |
||||
#define unless(x) if (!(x)) |
||||
|
||||
/*------------------------------- Maths stuff --------------------------------*/ |
||||
|
||||
#include <math.h> |
||||
|
||||
#ifdef min |
||||
#undef min |
||||
#endif |
||||
#define min(a, b) ((a) <= (b) ? (a) : (b)) |
||||
|
||||
#ifdef max |
||||
#undef max |
||||
#endif |
||||
#define max(a, b) ((a) >= (b) ? (a) : (b)) |
||||
|
||||
#define range_limit(x, lower, upper) (min(max(x, lower), upper)) |
||||
|
||||
#ifndef M_PI |
||||
#define M_PI 3.14159265358979323846 |
||||
#endif |
||||
#ifndef M_PI_2 |
||||
#define M_PI_2 1.57079632679489661923 /* pi/2 */ |
||||
#endif |
||||
#ifndef M_LN10 |
||||
#define M_LN10 2.30258509299404568402 /* natural log of 10 */ |
||||
#endif |
||||
#ifndef M_SQRT2 |
||||
#define M_SQRT2 sqrt(2.) |
||||
#endif |
||||
|
||||
#define sqr(a) ((a) * (a)) |
||||
#define sign(x) ((x) < 0? -1 : 1) |
||||
|
||||
/* Numerical Recipes in C, p. 284 */ |
||||
#define ranqd1(x) ((x) = 1664525L * (x) + 1013904223L) /* int32_t x */ |
||||
#define dranqd1(x) (ranqd1(x) * (1. / (65536. * 32768.))) /* [-1,1) */ |
||||
|
||||
#define dB_to_linear(x) exp((x) * M_LN10 * 0.05) |
||||
#define linear_to_dB(x) (log10(x) * 20) |
||||
|
||||
extern int lsx_strcasecmp(const char *s1, const char *st); |
||||
extern int lsx_strncasecmp(char const *s1, char const *s2, size_t n); |
||||
|
||||
#ifndef HAVE_STRCASECMP |
||||
#define strcasecmp(s1, s2) lsx_strcasecmp((s1), (s2)) |
||||
#define strncasecmp(s1, s2, n) lsx_strncasecmp((s1), (s2), (n)) |
||||
#endif |
@ -1,329 +0,0 @@ |
||||
/* libSoX effect: Voice Activity Detector (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 <string.h> |
||||
|
||||
typedef struct { |
||||
double * dftBuf, * noiseSpectrum, * spectrum, * measures, meanMeas; |
||||
} chan_t; |
||||
|
||||
typedef struct { /* Configuration parameters: */ |
||||
double bootTime, noiseTcUp, noiseTcDown, noiseReductionAmount; |
||||
double measureFreq, measureDuration, measureTc, preTriggerTime; |
||||
double hpFilterFreq, lpFilterFreq, hpLifterFreq, lpLifterFreq; |
||||
double triggerTc, triggerLevel, searchTime, gapTime; |
||||
/* Working variables: */ |
||||
sox_sample_t * samples; |
||||
unsigned dftLen_ws, samplesLen_ns, samplesIndex_ns, flushedLen_ns, gapLen; |
||||
unsigned measurePeriod_ns, measuresLen, measuresIndex; |
||||
unsigned measureTimer_ns, measureLen_ws, measureLen_ns; |
||||
unsigned spectrumStart, spectrumEnd, cepstrumStart, cepstrumEnd; /* bins */ |
||||
int bootCountMax, bootCount; |
||||
double noiseTcUpMult, noiseTcDownMult; |
||||
double measureTcMult, triggerMeasTcMult; |
||||
double * spectrumWindow, * cepstrumWindow; |
||||
chan_t * channels; |
||||
} priv_t; |
||||
|
||||
#define GETOPT_FREQ(optstate, c, name, min) \ |
||||
case c: p->name = lsx_parse_frequency(optstate.arg, &parseIndex); \
|
||||
if (p->name < min || *parseIndex) return lsx_usage(effp); \
|
||||
break; |
||||
|
||||
static int create(sox_effect_t * effp, int argc, char * * argv) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
#define opt_str "+b:N:n:r:f:m:M:h:l:H:L:T:t:s:g:p:" |
||||
int c; |
||||
lsx_getopt_t optstate; |
||||
lsx_getopt_init(argc, argv, opt_str, NULL, lsx_getopt_flag_none, 1, &optstate); |
||||
|
||||
p->bootTime = .35; |
||||
p->noiseTcUp = .1; |
||||
p->noiseTcDown = .01; |
||||
p->noiseReductionAmount = 1.35; |
||||
|
||||
p->measureFreq = 20; |
||||
p->measureDuration = 2 / p->measureFreq; /* 50% overlap */ |
||||
p->measureTc = .4; |
||||
|
||||
p->hpFilterFreq = 50; |
||||
p->lpFilterFreq = 6000; |
||||
p->hpLifterFreq = 150; |
||||
p->lpLifterFreq = 2000; |
||||
|
||||
p->triggerTc = .25; |
||||
p->triggerLevel = 7; |
||||
|
||||
p->searchTime = 1; |
||||
p->gapTime = .25; |
||||
|
||||
while ((c = lsx_getopt(&optstate)) != -1) switch (c) { |
||||
char * parseIndex; |
||||
GETOPT_NUMERIC(optstate, 'b', bootTime , .1 , 10) |
||||
GETOPT_NUMERIC(optstate, 'N', noiseTcUp , .1 , 10) |
||||
GETOPT_NUMERIC(optstate, 'n', noiseTcDown ,.001 , .1) |
||||
GETOPT_NUMERIC(optstate, 'r', noiseReductionAmount,0 , 2) |
||||
GETOPT_NUMERIC(optstate, 'f', measureFreq , 5 , 50) |
||||
GETOPT_NUMERIC(optstate, 'm', measureDuration, .01 , 1) |
||||
GETOPT_NUMERIC(optstate, 'M', measureTc , .1 , 1) |
||||
GETOPT_FREQ( optstate, 'h', hpFilterFreq , 10) |
||||
GETOPT_FREQ( optstate, 'l', lpFilterFreq , 1000) |
||||
GETOPT_FREQ( optstate, 'H', hpLifterFreq , 10) |
||||
GETOPT_FREQ( optstate, 'L', lpLifterFreq , 1000) |
||||
GETOPT_NUMERIC(optstate, 'T', triggerTc , .01 , 1) |
||||
GETOPT_NUMERIC(optstate, 't', triggerLevel , 0 , 20) |
||||
GETOPT_NUMERIC(optstate, 's', searchTime , .1 , 4) |
||||
GETOPT_NUMERIC(optstate, 'g', gapTime , .1 , 1) |
||||
GETOPT_NUMERIC(optstate, 'p', preTriggerTime, 0 , 4) |
||||
default: lsx_fail("invalid option `-%c'", optstate.opt); return lsx_usage(effp); |
||||
} |
||||
return optstate.ind !=argc? lsx_usage(effp) : SOX_SUCCESS; |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
unsigned i, fixedPreTriggerLen_ns, searchPreTriggerLen_ns; |
||||
|
||||
fixedPreTriggerLen_ns = p->preTriggerTime * effp->in_signal.rate + .5; |
||||
fixedPreTriggerLen_ns *= effp->in_signal.channels; |
||||
|
||||
p->measureLen_ws = effp->in_signal.rate * p->measureDuration + .5; |
||||
p->measureLen_ns = p->measureLen_ws * effp->in_signal.channels; |
||||
for (p->dftLen_ws = 16; p->dftLen_ws < p->measureLen_ws; p->dftLen_ws <<= 1); |
||||
lsx_debug("dftLen_ws=%u measureLen_ws=%u", p->dftLen_ws, p->measureLen_ws); |
||||
|
||||
p->measurePeriod_ns = effp->in_signal.rate / p->measureFreq + .5; |
||||
p->measurePeriod_ns *= effp->in_signal.channels; |
||||
p->measuresLen = ceil(p->searchTime * p->measureFreq); |
||||
searchPreTriggerLen_ns = p->measuresLen * p->measurePeriod_ns; |
||||
p->gapLen = p->gapTime * p->measureFreq + .5; |
||||
|
||||
p->samplesLen_ns = |
||||
fixedPreTriggerLen_ns + searchPreTriggerLen_ns + p->measureLen_ns; |
||||
lsx_Calloc(p->samples, p->samplesLen_ns); |
||||
|
||||
lsx_Calloc(p->channels, effp->in_signal.channels); |
||||
for (i = 0; i < effp->in_signal.channels; ++i) { |
||||
chan_t * c = &p->channels[i]; |
||||
lsx_Calloc(c->dftBuf, p->dftLen_ws); |
||||
lsx_Calloc(c->spectrum, p->dftLen_ws); |
||||
lsx_Calloc(c->noiseSpectrum, p->dftLen_ws); |
||||
lsx_Calloc(c->measures, p->measuresLen); |
||||
} |
||||
|
||||
lsx_Calloc(p->spectrumWindow, p->measureLen_ws); |
||||
for (i = 0; i < p->measureLen_ws; ++i) |
||||
p->spectrumWindow[i] = -2./ SOX_SAMPLE_MIN / sqrt((double)p->measureLen_ws); |
||||
lsx_apply_hann(p->spectrumWindow, (int)p->measureLen_ws); |
||||
|
||||
p->spectrumStart = p->hpFilterFreq / effp->in_signal.rate * p->dftLen_ws + .5; |
||||
p->spectrumStart = max(p->spectrumStart, 1); |
||||
p->spectrumEnd = p->lpFilterFreq / effp->in_signal.rate * p->dftLen_ws + .5; |
||||
p->spectrumEnd = min(p->spectrumEnd, p->dftLen_ws / 2); |
||||
|
||||
lsx_Calloc(p->cepstrumWindow, p->spectrumEnd - p->spectrumStart); |
||||
for (i = 0; i < p->spectrumEnd - p->spectrumStart; ++i) |
||||
p->cepstrumWindow[i] = 2 / sqrt((double)p->spectrumEnd - p->spectrumStart); |
||||
lsx_apply_hann(p->cepstrumWindow,(int)(p->spectrumEnd - p->spectrumStart)); |
||||
|
||||
p->cepstrumStart = ceil(effp->in_signal.rate * .5 / p->lpLifterFreq); |
||||
p->cepstrumEnd = floor(effp->in_signal.rate * .5 / p->hpLifterFreq); |
||||
p->cepstrumEnd = min(p->cepstrumEnd, p->dftLen_ws / 4); |
||||
if (p->cepstrumEnd <= p->cepstrumStart) |
||||
return SOX_EOF; |
||||
|
||||
p->noiseTcUpMult = exp(-1 / (p->noiseTcUp * p->measureFreq)); |
||||
p->noiseTcDownMult = exp(-1 / (p->noiseTcDown * p->measureFreq)); |
||||
p->measureTcMult = exp(-1 / (p->measureTc * p->measureFreq)); |
||||
p->triggerMeasTcMult = exp(-1 / (p->triggerTc * p->measureFreq)); |
||||
|
||||
p->bootCountMax = p->bootTime * p->measureFreq - .5; |
||||
p->measureTimer_ns = p->measureLen_ns; |
||||
p->bootCount = p->measuresIndex = p->flushedLen_ns = p->samplesIndex_ns = 0; |
||||
|
||||
effp->out_signal.length = SOX_UNKNOWN_LEN; /* depends on input data */ |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int flowFlush(sox_effect_t * effp, sox_sample_t const * ibuf, |
||||
sox_sample_t * obuf, size_t * ilen, size_t * olen) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
size_t odone = min(p->samplesLen_ns - p->flushedLen_ns, *olen); |
||||
size_t odone1 = min(odone, p->samplesLen_ns - p->samplesIndex_ns); |
||||
|
||||
memcpy(obuf, p->samples + p->samplesIndex_ns, odone1 * sizeof(*obuf)); |
||||
if ((p->samplesIndex_ns += odone1) == p->samplesLen_ns) { |
||||
memcpy(obuf + odone1, p->samples, (odone - odone1) * sizeof(*obuf)); |
||||
p->samplesIndex_ns = odone - odone1; |
||||
} |
||||
if ((p->flushedLen_ns += odone) == p->samplesLen_ns) { |
||||
size_t olen1 = *olen - odone; |
||||
(effp->handler.flow = lsx_flow_copy)(effp, ibuf, obuf +odone, ilen, &olen1); |
||||
odone += olen1; |
||||
} |
||||
else *ilen = 0; |
||||
*olen = odone; |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static double measure( |
||||
priv_t * p, chan_t * c, size_t index_ns, unsigned step_ns, int bootCount) |
||||
{ |
||||
double mult, result = 0; |
||||
size_t i; |
||||
|
||||
for (i = 0; i < p->measureLen_ws; ++i, index_ns = (index_ns + step_ns) % p->samplesLen_ns) |
||||
c->dftBuf[i] = p->samples[index_ns] * p->spectrumWindow[i]; |
||||
memset(c->dftBuf + i, 0, (p->dftLen_ws - i) * sizeof(*c->dftBuf)); |
||||
lsx_safe_rdft((int)p->dftLen_ws, 1, c->dftBuf); |
||||
|
||||
memset(c->dftBuf, 0, p->spectrumStart * sizeof(*c->dftBuf)); |
||||
for (i = p->spectrumStart; i < p->spectrumEnd; ++i) { |
||||
double d = sqrt(sqr(c->dftBuf[2 * i]) + sqr(c->dftBuf[2 * i + 1])); |
||||
mult = bootCount >= 0? bootCount / (1. + bootCount) : p->measureTcMult; |
||||
c->spectrum[i] = c->spectrum[i] * mult + d * (1 - mult); |
||||
d = sqr(c->spectrum[i]); |
||||
mult = bootCount >= 0? 0 : |
||||
d > c->noiseSpectrum[i]? p->noiseTcUpMult : p->noiseTcDownMult; |
||||
c->noiseSpectrum[i] = c->noiseSpectrum[i] * mult + d * (1 - mult); |
||||
d = sqrt(max(0, d - p->noiseReductionAmount * c->noiseSpectrum[i])); |
||||
c->dftBuf[i] = d * p->cepstrumWindow[i - p->spectrumStart]; |
||||
} |
||||
memset(c->dftBuf + i, 0, ((p->dftLen_ws >> 1) - i) * sizeof(*c->dftBuf)); |
||||
lsx_safe_rdft((int)p->dftLen_ws >> 1, 1, c->dftBuf); |
||||
|
||||
for (i = p->cepstrumStart; i < p->cepstrumEnd; ++i) |
||||
result += sqr(c->dftBuf[2 * i]) + sqr(c->dftBuf[2 * i + 1]); |
||||
result = log(result / (p->cepstrumEnd - p->cepstrumStart)); |
||||
return max(0, 21 + result); |
||||
} |
||||
|
||||
static int flowTrigger(sox_effect_t * effp, sox_sample_t const * ibuf, |
||||
sox_sample_t * obuf, size_t * ilen, size_t * olen) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
sox_bool hasTriggered = sox_false; |
||||
size_t i, idone = 0, numMeasuresToFlush = 0; |
||||
|
||||
while (idone < *ilen && !hasTriggered) { |
||||
p->measureTimer_ns -= effp->in_signal.channels; |
||||
for (i = 0; i < effp->in_signal.channels; ++i, ++idone) { |
||||
chan_t * c = &p->channels[i]; |
||||
p->samples[p->samplesIndex_ns++] = *ibuf++; |
||||
if (!p->measureTimer_ns) { |
||||
size_t x = (p->samplesIndex_ns + p->samplesLen_ns - p->measureLen_ns) % p->samplesLen_ns; |
||||
double meas = measure(p, c, x, effp->in_signal.channels, p->bootCount); |
||||
c->measures[p->measuresIndex] = meas; |
||||
c->meanMeas = c->meanMeas * p->triggerMeasTcMult + |
||||
meas *(1 - p->triggerMeasTcMult); |
||||
|
||||
if (hasTriggered |= c->meanMeas >= p->triggerLevel) { |
||||
unsigned n = p->measuresLen, k = p->measuresIndex; |
||||
unsigned j, jTrigger = n, jZero = n; |
||||
for (j = 0; j < n; ++j, k = (k + n - 1) % n) |
||||
if (c->measures[k] >= p->triggerLevel && j <= jTrigger + p->gapLen) |
||||
jZero = jTrigger = j; |
||||
else if (!c->measures[k] && jTrigger >= jZero) |
||||
jZero = j; |
||||
j = min(j, jZero); |
||||
numMeasuresToFlush = range_limit(j, numMeasuresToFlush, n); |
||||
} |
||||
lsx_debug_more("%12g %12g %u", |
||||
meas, c->meanMeas, (unsigned)numMeasuresToFlush); |
||||
} |
||||
} |
||||
if (p->samplesIndex_ns == p->samplesLen_ns) |
||||
p->samplesIndex_ns = 0; |
||||
if (!p->measureTimer_ns) { |
||||
p->measureTimer_ns = p->measurePeriod_ns; |
||||
++p->measuresIndex; |
||||
p->measuresIndex %= p->measuresLen; |
||||
if (p->bootCount >= 0) |
||||
p->bootCount = p->bootCount == p->bootCountMax? -1 : p->bootCount + 1; |
||||
} |
||||
} |
||||
if (hasTriggered) { |
||||
size_t ilen1 = *ilen - idone; |
||||
p->flushedLen_ns = (p->measuresLen - numMeasuresToFlush) * p->measurePeriod_ns; |
||||
p->samplesIndex_ns = (p->samplesIndex_ns + p->flushedLen_ns) % p->samplesLen_ns; |
||||
(effp->handler.flow = flowFlush)(effp, ibuf, obuf, &ilen1, olen); |
||||
idone += ilen1; |
||||
} |
||||
else *olen = 0; |
||||
*ilen = idone; |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * olen) |
||||
{ |
||||
size_t ilen = 0; |
||||
return effp->handler.flow(effp, NULL, obuf, &ilen, olen); |
||||
} |
||||
|
||||
static int stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
unsigned i; |
||||
|
||||
for (i = 0; i < effp->in_signal.channels; ++i) { |
||||
chan_t * c = &p->channels[i]; |
||||
free(c->measures); |
||||
free(c->noiseSpectrum); |
||||
free(c->spectrum); |
||||
free(c->dftBuf); |
||||
} |
||||
free(p->channels); |
||||
free(p->cepstrumWindow); |
||||
free(p->spectrumWindow); |
||||
free(p->samples); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_vad_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = {"vad", NULL, |
||||
SOX_EFF_MCHAN | SOX_EFF_LENGTH | SOX_EFF_MODIFY, |
||||
create, start, flowTrigger, drain, stop, NULL, sizeof(priv_t) |
||||
}; |
||||
static char const * lines[] = { |
||||
"[options]", |
||||
"\t-t trigger-level (7)", |
||||
"\t-T trigger-time-constant (0.25 s)", |
||||
"\t-s search-time (1 s)", |
||||
"\t-g allowed-gap (0.25 s)", |
||||
"\t-p pre-trigger-time (0 s)", |
||||
"Advanced options:", |
||||
"\t-b noise-est-boot-time (0.35 s)", |
||||
"\t-N noise-est-time-constant-up (0.1 s)", |
||||
"\t-n noise-est-time-constant-down (0.01 s)", |
||||
"\t-r noise-reduction-amount (1.35)", |
||||
"\t-f measurement-frequency (20 Hz)", |
||||
"\t-m measurement-duration (0.1 s)", |
||||
"\t-M measurement-time-constant (0.4 s)", |
||||
"\t-h high-pass-filter (50 Hz)", |
||||
"\t-l low-pass-filter (6000 Hz)", |
||||
"\t-H high-pass-lifter (150 Hz)", |
||||
"\t-L low-pass-lifter (2000 Hz)", |
||||
}; |
||||
static char * usage; |
||||
handler.usage = lsx_usage_lines(&usage, lines, array_length(lines)); |
||||
return &handler; |
||||
} |
@ -1,184 +0,0 @@ |
||||
/* Copyright (c) 20/03/2000 Fabien COELHO <fabien@coelho.net>
|
||||
* Copyright (c) 2000-2007 SoX contributors |
||||
* |
||||
* SoX vol effect; change volume with basic linear amplitude formula. |
||||
* Beware of saturations! Clipping is checked and reported. |
||||
* |
||||
* FIXME: deprecate or remove the limiter in favour of compand. |
||||
*/ |
||||
#define vol_usage \ |
||||
"GAIN [TYPE [LIMITERGAIN]]\n" \
|
||||
"\t(default TYPE=amplitude: 1 is constant, < 0 change phase;\n" \
|
||||
"\tTYPE=power 1 is constant; TYPE=dB: 0 is constant, +6 doubles ampl.)\n" \
|
||||
"\tThe peak limiter has a gain much less than 1 (e.g. 0.05 or 0.02) and\n" \
|
||||
"\tis only used on peaks (to prevent clipping); default is no limiter." |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
typedef struct { |
||||
double gain; /* amplitude gain. */ |
||||
sox_bool uselimiter; |
||||
double limiterthreshhold; |
||||
double limitergain; |
||||
uint64_t limited; /* number of limited values to report. */ |
||||
uint64_t totalprocessed; |
||||
} priv_t; |
||||
|
||||
enum {vol_amplitude, vol_dB, vol_power}; |
||||
|
||||
static lsx_enum_item const vol_types[] = { |
||||
LSX_ENUM_ITEM(vol_,amplitude) |
||||
LSX_ENUM_ITEM(vol_,dB) |
||||
LSX_ENUM_ITEM(vol_,power) |
||||
{0, 0}}; |
||||
|
||||
/*
|
||||
* Process options: gain (float) type (amplitude, power, dB) |
||||
*/ |
||||
static int getopts(sox_effect_t * effp, int argc, char **argv) |
||||
{ |
||||
priv_t * vol = (priv_t *) effp->priv; |
||||
char type_string[11]; |
||||
char * type_ptr = type_string; |
||||
char dummy; /* To check for extraneous chars. */ |
||||
sox_bool have_type; |
||||
--argc, ++argv; |
||||
|
||||
vol->gain = 1; /* Default is no change. */ |
||||
vol->uselimiter = sox_false; /* Default is no limiter. */ |
||||
|
||||
/* Get the vol, and the type if it's in the same arg. */ |
||||
if (!argc || (have_type = sscanf(argv[0], "%lf %10s %c", &vol->gain, type_string, &dummy) - 1) > 1) |
||||
return lsx_usage(effp); |
||||
++argv, --argc; |
||||
|
||||
/* No type yet? Get it from the next arg: */ |
||||
if (!have_type && argc) { |
||||
have_type = sox_true; |
||||
type_ptr = *argv; |
||||
++argv, --argc; |
||||
} |
||||
|
||||
if (have_type) { |
||||
lsx_enum_item const * p = lsx_find_enum_text(type_ptr, vol_types, 0); |
||||
if (!p) |
||||
return lsx_usage(effp); |
||||
switch (p->value) { |
||||
case vol_dB: vol->gain = dB_to_linear(vol->gain); break; |
||||
case vol_power: /* power to amplitude, keep phase change */ |
||||
vol->gain = vol->gain > 0 ? sqrt(vol->gain) : -sqrt(-vol->gain); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (argc) { |
||||
if (fabs(vol->gain) < 1 || sscanf(*argv, "%lf %c", &vol->limitergain, &dummy) != 1 || vol->limitergain <= 0 || vol->limitergain >= 1) |
||||
return lsx_usage(effp); |
||||
|
||||
vol->uselimiter = sox_true; |
||||
/* 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.) */ |
||||
vol->limiterthreshhold = SOX_SAMPLE_MAX * (1.0 - vol->limitergain) / (fabs(vol->gain) - vol->limitergain); |
||||
} |
||||
lsx_debug("mult=%g limit=%g", vol->gain, vol->limitergain); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Start processing |
||||
*/ |
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * vol = (priv_t *) effp->priv; |
||||
|
||||
if (vol->gain == 1) |
||||
return SOX_EFF_NULL; |
||||
|
||||
vol->limited = 0; |
||||
vol->totalprocessed = 0; |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Process data. |
||||
*/ |
||||
static int flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, |
||||
size_t *isamp, size_t *osamp) |
||||
{ |
||||
priv_t * vol = (priv_t *) effp->priv; |
||||
register double gain = vol->gain; |
||||
register double limiterthreshhold = vol->limiterthreshhold; |
||||
register double sample; |
||||
register size_t len; |
||||
|
||||
len = min(*osamp, *isamp); |
||||
|
||||
/* report back dealt with amount. */ |
||||
*isamp = len; *osamp = len; |
||||
|
||||
if (vol->uselimiter) |
||||
{ |
||||
vol->totalprocessed += len; |
||||
|
||||
for (;len>0; len--) |
||||
{ |
||||
sample = *ibuf++; |
||||
|
||||
if (sample > limiterthreshhold) |
||||
{ |
||||
sample = (SOX_SAMPLE_MAX - vol->limitergain * (SOX_SAMPLE_MAX - sample)); |
||||
vol->limited++; |
||||
} |
||||
else if (sample < -limiterthreshhold) |
||||
{ |
||||
sample = -(SOX_SAMPLE_MAX - vol->limitergain * (SOX_SAMPLE_MAX + sample)); |
||||
/* FIXME: MIN is (-MAX)-1 so need to make sure we
|
||||
* don't go over that. Probably could do this |
||||
* check inside the above equation but I didn't |
||||
* think it thru. |
||||
*/ |
||||
if (sample < SOX_SAMPLE_MIN) |
||||
sample = SOX_SAMPLE_MIN; |
||||
vol->limited++; |
||||
} else |
||||
sample = gain * sample; |
||||
|
||||
SOX_SAMPLE_CLIP_COUNT(sample, effp->clips); |
||||
*obuf++ = sample; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
/* quite basic, with clipping */ |
||||
for (;len>0; len--) |
||||
{ |
||||
sample = gain * *ibuf++; |
||||
SOX_SAMPLE_CLIP_COUNT(sample, effp->clips); |
||||
*obuf++ = sample; |
||||
} |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * vol = (priv_t *) effp->priv; |
||||
if (vol->limited) { |
||||
lsx_warn("limited %" PRIu64 " values (%d percent).", |
||||
vol->limited, (int) (vol->limited * 100.0 / vol->totalprocessed)); |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_vol_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"vol", vol_usage, SOX_EFF_MCHAN | SOX_EFF_GAIN, getopts, start, flow, 0, stop, 0, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -1,73 +0,0 @@ |
||||
/* SoX Memory allocation functions
|
||||
* |
||||
* Copyright (c) 2005-2006 Reuben Thomas. All rights reserved. |
||||
* |
||||
* 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> |
||||
|
||||
static void *lsx_checkptr(void *ptr) |
||||
{ |
||||
if (!ptr) { |
||||
lsx_fail("out of memory"); |
||||
exit(2); |
||||
} |
||||
|
||||
return ptr; |
||||
} |
||||
|
||||
/* Resize an allocated memory area; abort if not possible.
|
||||
* |
||||
* For malloc, `If the size of the space requested is zero, the behavior is |
||||
* implementation defined: either a null pointer is returned, or the |
||||
* behavior is as if the size were some nonzero value, except that the |
||||
* returned pointer shall not be used to access an object' |
||||
*/ |
||||
void *lsx_realloc(void *ptr, size_t newsize) |
||||
{ |
||||
if (ptr && newsize == 0) { |
||||
free(ptr); |
||||
return NULL; |
||||
} |
||||
|
||||
return lsx_checkptr(realloc(ptr, newsize)); |
||||
} |
||||
|
||||
void *lsx_malloc(size_t size) |
||||
{ |
||||
return lsx_checkptr(malloc(size + !size)); |
||||
} |
||||
|
||||
void *lsx_calloc(size_t n, size_t size) |
||||
{ |
||||
return lsx_checkptr(calloc(n + !n, size + !size)); |
||||
} |
||||
|
||||
void *lsx_realloc_array(void *p, size_t n, size_t size) |
||||
{ |
||||
if (n > (size_t)-1 / size) { |
||||
lsx_fail("malloc size overflow"); |
||||
exit(2); |
||||
} |
||||
|
||||
return lsx_realloc(p, n * size); |
||||
} |
||||
|
||||
char *lsx_strdup(const char *s) |
||||
{ |
||||
return lsx_checkptr(strdup(s)); |
||||
} |
@ -1,36 +0,0 @@ |
||||
/* libSoX Memory allocation functions
|
||||
* |
||||
* Copyright (c) 2005-2006 Reuben Thomas. All rights reserved. |
||||
* |
||||
* 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 LSX_MALLOC_H |
||||
#define LSX_MALLOC_H |
||||
|
||||
#include <stddef.h> |
||||
#include <string.h> |
||||
|
||||
LSX_RETURN_VALID void *lsx_malloc(size_t size); |
||||
LSX_RETURN_VALID void *lsx_calloc(size_t n, size_t size); |
||||
LSX_RETURN_VALID void *lsx_realloc_array(void *p, size_t n, size_t size); |
||||
LSX_RETURN_VALID char *lsx_strdup(const char *s); |
||||
|
||||
#define lsx_Calloc(v,n) v = lsx_calloc(n,sizeof(*(v))) |
||||
#define lsx_memdup(p,s) ((p)? memcpy(lsx_malloc(s), p, s) : NULL) |
||||
#define lsx_valloc(v,n) v = lsx_realloc_array(NULL, n, sizeof(*(v))) |
||||
#define lsx_revalloc(v,n) v = lsx_realloc_array(v, n, sizeof(*(v))) |
||||
|
||||
#endif |
Loading…
Reference in new issue