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