parent
965805fd3b
commit
1c848cd2ab
@ -1,322 +0,0 @@ |
||||
/* libSoX ADPCM codecs: IMA, OKI, CL. (c) 2007-8 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "adpcms.h" |
||||
|
||||
static int const ima_steps[89] = { /* ~16-bit precision; 4 bit code */ |
||||
7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, |
||||
50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, |
||||
253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, |
||||
1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, |
||||
3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, |
||||
11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, |
||||
32767}; |
||||
|
||||
static int const oki_steps[49] = { /* ~12-bit precision; 4 bit code */ |
||||
256, 272, 304, 336, 368, 400, 448, 496, 544, 592, 656, 720, 800, 880, 960, |
||||
1056, 1168, 1280, 1408, 1552, 1712, 1888, 2080, 2288, 2512, 2768, 3040, 3344, |
||||
3680, 4048, 4464, 4912, 5392, 5936, 6528, 7184, 7904, 8704, 9568, 10528, |
||||
11584, 12736, 14016, 15408, 16960, 18656, 20512, 22576, 24832}; |
||||
|
||||
static int const step_changes[8] = {-1, -1, -1, -1, 2, 4, 6, 8}; |
||||
|
||||
/* Creative Labs ~8 bit precision; 4, 3, & 2 bit codes: */ |
||||
static int const cl4_steps[4] = {0x100, 0x200, 0x400, 0x800}; |
||||
static int const cl4_changes[8] = {-1, 0, 0, 0, 0, 1, 1, 1}; |
||||
|
||||
static int const cl3_steps[5] = {0x100, 0x200, 0x400, 0x800, 0xA00}; |
||||
static int const cl3_changes[4] = {-1, 0, 0, 1}; |
||||
|
||||
static int const cl2_steps[6] = {0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000}; |
||||
static int const cl2_changes[2] = {-1, 1}; |
||||
|
||||
static adpcm_setup_t const setup_table[] = { |
||||
{88, 8, 2, ima_steps, step_changes, ~0}, |
||||
{48, 8, 2, oki_steps, step_changes, ~15}, |
||||
{ 3, 8, 0, cl4_steps, cl4_changes , ~255}, |
||||
{ 4, 4, 0, cl3_steps, cl3_changes , ~255}, |
||||
{ 5, 2, 0, cl2_steps, cl2_changes , ~255}, |
||||
}; |
||||
|
||||
void lsx_adpcm_init(adpcm_t * p, int type, int first_sample) |
||||
{ |
||||
p->setup = setup_table[type]; |
||||
p->last_output = first_sample; |
||||
p->step_index = 0; |
||||
p->errors = 0; |
||||
} |
||||
|
||||
#define min_sample -0x8000 |
||||
#define max_sample 0x7fff |
||||
|
||||
int lsx_adpcm_decode(int code, adpcm_t * p) |
||||
{ |
||||
int s = ((code & (p->setup.sign - 1)) << 1) | 1; |
||||
s = ((p->setup.steps[p->step_index] * s) >> (p->setup.shift + 1)) & p->setup.mask; |
||||
if (code & p->setup.sign) |
||||
s = -s; |
||||
s += p->last_output; |
||||
if (s < min_sample || s > max_sample) { |
||||
int grace = (p->setup.steps[p->step_index] >> (p->setup.shift + 1)) & p->setup.mask; |
||||
if (s < min_sample - grace || s > max_sample + grace) { |
||||
lsx_debug_most("code=%i step=%i grace=%i s=%i", |
||||
code & (2 * p->setup.sign - 1), p->setup.steps[p->step_index], grace, s); |
||||
p->errors++; |
||||
} |
||||
s = s < min_sample? min_sample : max_sample; |
||||
} |
||||
p->step_index += p->setup.changes[code & (p->setup.sign - 1)]; |
||||
p->step_index = range_limit(p->step_index, 0, p->setup.max_step_index); |
||||
return p->last_output = s; |
||||
} |
||||
|
||||
int lsx_adpcm_encode(int sample, adpcm_t * p) |
||||
{ |
||||
int delta = sample - p->last_output; |
||||
int sign = 0; |
||||
int code; |
||||
if (delta < 0) { |
||||
sign = p->setup.sign; |
||||
delta = -delta; |
||||
} |
||||
code = (delta << p->setup.shift) / p->setup.steps[p->step_index]; |
||||
code = sign | min(code, p->setup.sign - 1); |
||||
lsx_adpcm_decode(code, p); /* Update encoder state */ |
||||
return code; |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* Format methods |
||||
* |
||||
* Almost like the raw format functions, but cannot be used directly |
||||
* since they require an additional state parameter. |
||||
*/ |
||||
|
||||
/******************************************************************************
|
||||
* Function : lsx_adpcm_reset |
||||
* Description: Resets the ADPCM codec state. |
||||
* Parameters : state - ADPCM state structure |
||||
* type - SOX_ENCODING_OKI_ADPCM or SOX_ENCODING_IMA_ADPCM |
||||
* Returns : |
||||
* Exceptions : |
||||
* Notes : 1. This function is used for framed ADPCM formats to reset |
||||
* the decoder between frames. |
||||
******************************************************************************/ |
||||
|
||||
void lsx_adpcm_reset(adpcm_io_t * state, sox_encoding_t type) |
||||
{ |
||||
state->file.count = 0; |
||||
state->file.pos = 0; |
||||
state->store.byte = 0; |
||||
state->store.flag = 0; |
||||
|
||||
lsx_adpcm_init(&state->encoder, (type == SOX_ENCODING_OKI_ADPCM) ? 1 : 0, 0); |
||||
} |
||||
|
||||
/******************************************************************************
|
||||
* Function : lsx_adpcm_start |
||||
* Description: Initialises the file parameters and ADPCM codec state. |
||||
* Parameters : ft - file info structure |
||||
* state - ADPCM state structure |
||||
* type - SOX_ENCODING_OKI_ADPCM or SOX_ENCODING_IMA_ADPCM |
||||
* Returns : int - SOX_SUCCESS |
||||
* SOX_EOF |
||||
* Exceptions : |
||||
* Notes : 1. This function can be used as a startread or |
||||
* startwrite method. |
||||
* 2. VOX file format is 4-bit OKI ADPCM that decodes to |
||||
* to 12 bit signed linear PCM. |
||||
* 3. Dialogic only supports 6kHz, 8kHz and 11 kHz sampling |
||||
* rates but the codecs allows any user specified rate. |
||||
******************************************************************************/ |
||||
|
||||
static int adpcm_start(sox_format_t * ft, adpcm_io_t * state, sox_encoding_t type) |
||||
{ |
||||
/* setup file info */ |
||||
state->file.buf = lsx_malloc(sox_globals.bufsiz); |
||||
state->file.size = sox_globals.bufsiz; |
||||
ft->signal.channels = 1; |
||||
|
||||
lsx_adpcm_reset(state, type); |
||||
|
||||
return lsx_rawstart(ft, sox_true, sox_false, sox_true, type, 4); |
||||
} |
||||
|
||||
int lsx_adpcm_oki_start(sox_format_t * ft, adpcm_io_t * state) |
||||
{ |
||||
return adpcm_start(ft, state, SOX_ENCODING_OKI_ADPCM); |
||||
} |
||||
|
||||
int lsx_adpcm_ima_start(sox_format_t * ft, adpcm_io_t * state) |
||||
{ |
||||
return adpcm_start(ft, state, SOX_ENCODING_IMA_ADPCM); |
||||
} |
||||
|
||||
/******************************************************************************
|
||||
* Function : lsx_adpcm_read |
||||
* Description: Converts the OKI ADPCM 4-bit samples to 16-bit signed PCM and |
||||
* then scales the samples to full sox_sample_t range. |
||||
* Parameters : ft - file info structure |
||||
* state - ADPCM state structure |
||||
* buffer - output buffer |
||||
* len - size of output buffer |
||||
* Returns : - number of samples returned in buffer |
||||
* Exceptions : |
||||
* Notes : |
||||
******************************************************************************/ |
||||
|
||||
size_t lsx_adpcm_read(sox_format_t * ft, adpcm_io_t * state, sox_sample_t * buffer, size_t len) |
||||
{ |
||||
size_t n = 0; |
||||
uint8_t byte; |
||||
int16_t word; |
||||
|
||||
if (len && state->store.flag) { |
||||
word = lsx_adpcm_decode(state->store.byte, &state->encoder); |
||||
*buffer++ = SOX_SIGNED_16BIT_TO_SAMPLE(word, ft->clips); |
||||
state->store.flag = 0; |
||||
++n; |
||||
} |
||||
while (n < len && lsx_read_b_buf(ft, &byte, (size_t) 1) == 1) { |
||||
word = lsx_adpcm_decode(byte >> 4, &state->encoder); |
||||
*buffer++ = SOX_SIGNED_16BIT_TO_SAMPLE(word, ft->clips); |
||||
|
||||
if (++n < len) { |
||||
word = lsx_adpcm_decode(byte, &state->encoder); |
||||
*buffer++ = SOX_SIGNED_16BIT_TO_SAMPLE(word, ft->clips); |
||||
++n; |
||||
} else { |
||||
state->store.byte = byte; |
||||
state->store.flag = 1; |
||||
} |
||||
} |
||||
return n; |
||||
} |
||||
|
||||
/******************************************************************************
|
||||
* Function : stopread |
||||
* Description: Frees the internal buffer allocated in voxstart/imastart. |
||||
* Parameters : ft - file info structure |
||||
* state - ADPCM state structure |
||||
* Returns : int - SOX_SUCCESS |
||||
* Exceptions : |
||||
* Notes : |
||||
******************************************************************************/ |
||||
|
||||
int lsx_adpcm_stopread(sox_format_t * ft UNUSED, adpcm_io_t * state) |
||||
{ |
||||
if (state->encoder.errors) |
||||
lsx_warn("%s: ADPCM state errors: %u", ft->filename, state->encoder.errors); |
||||
free(state->file.buf); |
||||
|
||||
return (SOX_SUCCESS); |
||||
} |
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Function : write |
||||
* Description: Converts the supplied buffer to 12 bit linear PCM and encodes |
||||
* to OKI ADPCM 4-bit samples (packed a two nibbles per byte). |
||||
* Parameters : ft - file info structure |
||||
* state - ADPCM state structure |
||||
* buffer - output buffer |
||||
* length - size of output buffer |
||||
* Returns : int - SOX_SUCCESS |
||||
* SOX_EOF |
||||
* Exceptions : |
||||
* Notes : |
||||
******************************************************************************/ |
||||
|
||||
size_t lsx_adpcm_write(sox_format_t * ft, adpcm_io_t * state, const sox_sample_t * buffer, size_t length) |
||||
{ |
||||
size_t count = 0; |
||||
uint8_t byte = state->store.byte; |
||||
uint8_t flag = state->store.flag; |
||||
short word; |
||||
|
||||
while (count < length) { |
||||
SOX_SAMPLE_LOCALS; |
||||
word = SOX_SAMPLE_TO_SIGNED_16BIT(*buffer++, ft->clips); |
||||
|
||||
byte <<= 4; |
||||
byte |= lsx_adpcm_encode(word, &state->encoder) & 0x0F; |
||||
|
||||
flag = !flag; |
||||
|
||||
if (flag == 0) { |
||||
state->file.buf[state->file.count++] = byte; |
||||
|
||||
if (state->file.count >= state->file.size) { |
||||
lsx_writebuf(ft, state->file.buf, state->file.count); |
||||
|
||||
state->file.count = 0; |
||||
} |
||||
} |
||||
|
||||
count++; |
||||
} |
||||
|
||||
/* keep last byte across calls */ |
||||
state->store.byte = byte; |
||||
state->store.flag = flag; |
||||
return (count); |
||||
} |
||||
|
||||
/******************************************************************************
|
||||
* Function : lsx_adpcm_flush |
||||
* Description: Flushes any leftover samples. |
||||
* Parameters : ft - file info structure |
||||
* state - ADPCM state structure |
||||
* Returns : |
||||
* Exceptions : |
||||
* Notes : 1. Called directly for writing framed formats |
||||
******************************************************************************/ |
||||
|
||||
void lsx_adpcm_flush(sox_format_t * ft, adpcm_io_t * state) |
||||
{ |
||||
uint8_t byte = state->store.byte; |
||||
uint8_t flag = state->store.flag; |
||||
|
||||
/* flush remaining samples */ |
||||
|
||||
if (flag != 0) { |
||||
byte <<= 4; |
||||
state->file.buf[state->file.count++] = byte; |
||||
} |
||||
if (state->file.count > 0) |
||||
lsx_writebuf(ft, state->file.buf, state->file.count); |
||||
} |
||||
|
||||
/******************************************************************************
|
||||
* Function : lsx_adpcm_stopwrite |
||||
* Description: Flushes any leftover samples and frees the internal buffer |
||||
* allocated in voxstart/imastart. |
||||
* Parameters : ft - file info structure |
||||
* state - ADPCM state structure |
||||
* Returns : int - SOX_SUCCESS |
||||
* Exceptions : |
||||
* Notes : |
||||
******************************************************************************/ |
||||
|
||||
int lsx_adpcm_stopwrite(sox_format_t * ft, adpcm_io_t * state) |
||||
{ |
||||
lsx_adpcm_flush(ft, state); |
||||
free(state->file.buf); |
||||
return (SOX_SUCCESS); |
||||
} |
@ -1,55 +0,0 @@ |
||||
/* libSoX ADPCM codecs: IMA, OKI, CL. (c) 2007-8 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
typedef struct { |
||||
int max_step_index; |
||||
int sign; |
||||
int shift; |
||||
int const * steps; |
||||
int const * changes; |
||||
int mask; |
||||
} adpcm_setup_t; |
||||
|
||||
typedef struct { |
||||
adpcm_setup_t setup; |
||||
int last_output; |
||||
int step_index; |
||||
int errors; |
||||
} adpcm_t; |
||||
|
||||
void lsx_adpcm_init(adpcm_t * p, int type, int first_sample); |
||||
int lsx_adpcm_decode(int code, adpcm_t * p); |
||||
int lsx_adpcm_encode(int sample, adpcm_t * p); |
||||
|
||||
typedef struct { |
||||
adpcm_t encoder; |
||||
struct { |
||||
uint8_t byte; /* write store */ |
||||
uint8_t flag; |
||||
} store; |
||||
sox_fileinfo_t file; |
||||
} adpcm_io_t; |
||||
|
||||
/* Format methods */ |
||||
void lsx_adpcm_reset(adpcm_io_t * state, sox_encoding_t type); |
||||
int lsx_adpcm_oki_start(sox_format_t * ft, adpcm_io_t * state); |
||||
int lsx_adpcm_ima_start(sox_format_t * ft, adpcm_io_t * state); |
||||
size_t lsx_adpcm_read(sox_format_t * ft, adpcm_io_t * state, sox_sample_t *buffer, size_t len); |
||||
int lsx_adpcm_stopread(sox_format_t * ft, adpcm_io_t * state); |
||||
size_t lsx_adpcm_write(sox_format_t * ft, adpcm_io_t * state, const sox_sample_t *buffer, size_t length); |
||||
void lsx_adpcm_flush(sox_format_t * ft, adpcm_io_t * state); |
||||
int lsx_adpcm_stopwrite(sox_format_t * ft, adpcm_io_t * state); |
@ -1,21 +0,0 @@ |
||||
/* File format: raw A-law (c) 2007-8 SoX contributors
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "raw.h" |
||||
|
||||
RAW_FORMAT(al, 8, 0, ALAW) |
@ -1,379 +0,0 @@ |
||||
/* libSoX device driver: ALSA (c) 2006-2012 SoX contributors
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include <alsa/asoundlib.h> |
||||
|
||||
typedef struct { |
||||
snd_pcm_uframes_t buf_len, period; |
||||
snd_pcm_t * pcm; |
||||
char * buf; |
||||
unsigned int format; |
||||
} priv_t; |
||||
|
||||
static const |
||||
struct { |
||||
unsigned int bits; |
||||
enum _snd_pcm_format alsa_fmt; |
||||
unsigned int bytes; /* occupied in the buffer per sample */ |
||||
sox_encoding_t enc; |
||||
} formats[] = { |
||||
/* order by # of bits; within that, preferred first */ |
||||
{ 8, SND_PCM_FORMAT_S8, 1, SOX_ENCODING_SIGN2 }, |
||||
{ 8, SND_PCM_FORMAT_U8, 1, SOX_ENCODING_UNSIGNED }, |
||||
{ 16, SND_PCM_FORMAT_S16, 2, SOX_ENCODING_SIGN2 }, |
||||
{ 16, SND_PCM_FORMAT_U16, 2, SOX_ENCODING_UNSIGNED }, |
||||
{ 24, SND_PCM_FORMAT_S24, 4, SOX_ENCODING_SIGN2 }, |
||||
{ 24, SND_PCM_FORMAT_U24, 4, SOX_ENCODING_UNSIGNED }, |
||||
{ 24, SND_PCM_FORMAT_S24_3LE, 3, SOX_ENCODING_SIGN2 }, |
||||
{ 32, SND_PCM_FORMAT_S32, 4, SOX_ENCODING_SIGN2 }, |
||||
{ 32, SND_PCM_FORMAT_U32, 4, SOX_ENCODING_UNSIGNED }, |
||||
{ 0, 0, 0, SOX_ENCODING_UNKNOWN } /* end of list */ |
||||
}; |
||||
|
||||
static int select_format( |
||||
sox_encoding_t * encoding_, |
||||
unsigned * nbits_, |
||||
snd_pcm_format_mask_t const * mask, |
||||
unsigned int * format) |
||||
{ |
||||
unsigned int from = 0, to; /* NB: "to" actually points one after the last */ |
||||
int cand = -1; |
||||
|
||||
while (formats[from].bits < *nbits_ && formats[from].bits != 0) |
||||
from++; /* find the first entry with at least *nbits_ bits */ |
||||
for (to = from; formats[to].bits != 0; to++) ; /* find end of list */ |
||||
|
||||
while (to > 0) { |
||||
unsigned int i, bits_next = 0; |
||||
for (i = from; i < to; i++) { |
||||
lsx_debug_most("select_format: trying #%u", i); |
||||
if (snd_pcm_format_mask_test(mask, formats[i].alsa_fmt)) { |
||||
if (formats[i].enc == *encoding_) { |
||||
cand = i; |
||||
break; /* found a match */ |
||||
} else if (cand == -1) /* don't overwrite a candidate that
|
||||
was earlier in the list */ |
||||
cand = i; /* will work, but encoding differs */ |
||||
} |
||||
} |
||||
if (cand != -1) |
||||
break; |
||||
/* no candidate found yet; now try formats with less bits: */ |
||||
to = from; |
||||
if (from > 0) |
||||
bits_next = formats[from-1].bits; |
||||
while (from && formats[from-1].bits == bits_next) |
||||
from--; /* go back to the first entry with bits_next bits */ |
||||
} |
||||
|
||||
if (cand == -1) { |
||||
lsx_debug("select_format: no suitable ALSA format found"); |
||||
return -1; |
||||
} |
||||
|
||||
if (*nbits_ != formats[cand].bits || *encoding_ != formats[cand].enc) { |
||||
lsx_warn("can't encode %u-bit %s", *nbits_, |
||||
sox_encodings_info[*encoding_].desc); |
||||
*nbits_ = formats[cand].bits; |
||||
*encoding_ = formats[cand].enc; |
||||
} |
||||
lsx_debug("selecting format %d: %s (%s)", cand, |
||||
snd_pcm_format_name(formats[cand].alsa_fmt), |
||||
snd_pcm_format_description(formats[cand].alsa_fmt)); |
||||
*format = cand; |
||||
return 0; |
||||
} |
||||
|
||||
#define _(x,y) do {if ((err = x y) < 0) {lsx_fail_errno(ft, SOX_EPERM, #x " error: %s", snd_strerror(err)); goto error;} } while (0) |
||||
static int setup(sox_format_t * ft) |
||||
{ |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
snd_pcm_hw_params_t * params = NULL; |
||||
snd_pcm_format_mask_t * mask = NULL; |
||||
snd_pcm_uframes_t min, max; |
||||
unsigned n; |
||||
int err; |
||||
|
||||
_(snd_pcm_open, (&p->pcm, ft->filename, ft->mode == 'r'? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, 0)); |
||||
_(snd_pcm_hw_params_malloc, (¶ms)); |
||||
_(snd_pcm_hw_params_any, (p->pcm, params)); |
||||
#if SND_LIB_VERSION >= 0x010009 /* Disable alsa-lib resampling: */ |
||||
_(snd_pcm_hw_params_set_rate_resample, (p->pcm, params, 0)); |
||||
#endif |
||||
_(snd_pcm_hw_params_set_access, (p->pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED)); |
||||
|
||||
_(snd_pcm_format_mask_malloc, (&mask)); /* Set format: */ |
||||
snd_pcm_hw_params_get_format_mask(params, mask); |
||||
_(select_format, (&ft->encoding.encoding, &ft->encoding.bits_per_sample, mask, &p->format)); |
||||
_(snd_pcm_hw_params_set_format, (p->pcm, params, formats[p->format].alsa_fmt)); |
||||
snd_pcm_format_mask_free(mask), mask = NULL; |
||||
|
||||
n = ft->signal.rate; /* Set rate: */ |
||||
_(snd_pcm_hw_params_set_rate_near, (p->pcm, params, &n, 0)); |
||||
ft->signal.rate = n; |
||||
|
||||
n = ft->signal.channels; /* Set channels: */ |
||||
_(snd_pcm_hw_params_set_channels_near, (p->pcm, params, &n)); |
||||
ft->signal.channels = n; |
||||
|
||||
/* Get number of significant bits: */ |
||||
if ((err = snd_pcm_hw_params_get_sbits(params)) > 0) |
||||
ft->signal.precision = min(err, SOX_SAMPLE_PRECISION); |
||||
else lsx_debug("snd_pcm_hw_params_get_sbits can't tell precision: %s", |
||||
snd_strerror(err)); |
||||
|
||||
/* Set buf_len > > sox_globals.bufsiz for no underrun: */ |
||||
p->buf_len = sox_globals.bufsiz * 8 / formats[p->format].bytes / |
||||
ft->signal.channels; |
||||
_(snd_pcm_hw_params_get_buffer_size_min, (params, &min)); |
||||
_(snd_pcm_hw_params_get_buffer_size_max, (params, &max)); |
||||
p->period = range_limit(p->buf_len, min, max) / 8; |
||||
p->buf_len = p->period * 8; |
||||
_(snd_pcm_hw_params_set_period_size_near, (p->pcm, params, &p->period, 0)); |
||||
_(snd_pcm_hw_params_set_buffer_size_near, (p->pcm, params, &p->buf_len)); |
||||
if (p->period * 2 > p->buf_len) { |
||||
lsx_fail_errno(ft, SOX_EPERM, "buffer too small"); |
||||
goto error; |
||||
} |
||||
|
||||
_(snd_pcm_hw_params, (p->pcm, params)); /* Configure ALSA */ |
||||
snd_pcm_hw_params_free(params), params = NULL; |
||||
_(snd_pcm_prepare, (p->pcm)); |
||||
p->buf_len *= ft->signal.channels; /* No longer in `frames' */ |
||||
p->buf = lsx_malloc(p->buf_len * formats[p->format].bytes); |
||||
return SOX_SUCCESS; |
||||
|
||||
error: |
||||
if (mask) snd_pcm_format_mask_free(mask); |
||||
if (params) snd_pcm_hw_params_free(params); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
static int recover(sox_format_t * ft, snd_pcm_t * pcm, int err) |
||||
{ |
||||
if (err == -EPIPE) |
||||
lsx_warn("%s-run", ft->mode == 'r'? "over" : "under"); |
||||
else if (err != -ESTRPIPE) |
||||
lsx_warn("%s", snd_strerror(err)); |
||||
else while ((err = snd_pcm_resume(pcm)) == -EAGAIN) { |
||||
lsx_report("suspended"); |
||||
sleep(1); /* Wait until the suspend flag is released */ |
||||
} |
||||
if (err < 0 && (err = snd_pcm_prepare(pcm)) < 0) |
||||
lsx_fail_errno(ft, SOX_EPERM, "%s", snd_strerror(err)); |
||||
return err; |
||||
} |
||||
|
||||
static size_t read_(sox_format_t * ft, sox_sample_t * buf, size_t len) |
||||
{ |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
snd_pcm_sframes_t i, n; |
||||
size_t done; |
||||
|
||||
len = min(len, p->buf_len); |
||||
for (done = 0; done < len; done += n) { |
||||
do { |
||||
n = snd_pcm_readi(p->pcm, p->buf, (len - done) / ft->signal.channels); |
||||
if (n < 0 && recover(ft, p->pcm, (int)n) < 0) |
||||
return 0; |
||||
} while (n <= 0); |
||||
|
||||
i = n *= ft->signal.channels; |
||||
switch (formats[p->format].alsa_fmt) { |
||||
case SND_PCM_FORMAT_S8: { |
||||
int8_t * buf1 = (int8_t *)p->buf; |
||||
while (i--) *buf++ = SOX_SIGNED_8BIT_TO_SAMPLE(*buf1++,); |
||||
break; |
||||
} |
||||
case SND_PCM_FORMAT_U8: { |
||||
uint8_t * buf1 = (uint8_t *)p->buf; |
||||
while (i--) *buf++ = SOX_UNSIGNED_8BIT_TO_SAMPLE(*buf1++,); |
||||
break; |
||||
} |
||||
case SND_PCM_FORMAT_S16: { |
||||
int16_t * buf1 = (int16_t *)p->buf; |
||||
if (ft->encoding.reverse_bytes) while (i--) |
||||
*buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(lsx_swapw(*buf1++),); |
||||
else |
||||
while (i--) *buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(*buf1++,); |
||||
break; |
||||
} |
||||
case SND_PCM_FORMAT_U16: { |
||||
uint16_t * buf1 = (uint16_t *)p->buf; |
||||
if (ft->encoding.reverse_bytes) while (i--) |
||||
*buf++ = SOX_UNSIGNED_16BIT_TO_SAMPLE(lsx_swapw(*buf1++),); |
||||
else |
||||
while (i--) *buf++ = SOX_UNSIGNED_16BIT_TO_SAMPLE(*buf1++,); |
||||
break; |
||||
} |
||||
case SND_PCM_FORMAT_S24: { |
||||
sox_int24_t * buf1 = (sox_int24_t *)p->buf; |
||||
while (i--) *buf++ = SOX_SIGNED_24BIT_TO_SAMPLE(*buf1++,); |
||||
break; |
||||
} |
||||
case SND_PCM_FORMAT_S24_3LE: { |
||||
unsigned char *buf1 = (unsigned char *)p->buf; |
||||
while (i--) { |
||||
uint32_t temp; |
||||
temp = *buf1++; |
||||
temp |= *buf1++ << 8; |
||||
temp |= *buf1++ << 16; |
||||
*buf++ = SOX_SIGNED_24BIT_TO_SAMPLE((sox_int24_t)temp,); |
||||
} |
||||
break; |
||||
} |
||||
case SND_PCM_FORMAT_U24: { |
||||
sox_uint24_t * buf1 = (sox_uint24_t *)p->buf; |
||||
while (i--) *buf++ = SOX_UNSIGNED_24BIT_TO_SAMPLE(*buf1++,); |
||||
break; |
||||
} |
||||
case SND_PCM_FORMAT_S32: { |
||||
int32_t * buf1 = (int32_t *)p->buf; |
||||
while (i--) *buf++ = SOX_SIGNED_32BIT_TO_SAMPLE(*buf1++,); |
||||
break; |
||||
} |
||||
case SND_PCM_FORMAT_U32: { |
||||
uint32_t * buf1 = (uint32_t *)p->buf; |
||||
while (i--) *buf++ = SOX_UNSIGNED_32BIT_TO_SAMPLE(*buf1++,); |
||||
break; |
||||
} |
||||
default: lsx_fail_errno(ft, SOX_EFMT, "invalid format"); |
||||
return 0; |
||||
} |
||||
} |
||||
return len; |
||||
} |
||||
|
||||
static size_t write_(sox_format_t * ft, sox_sample_t const * buf, size_t len) |
||||
{ |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
size_t done, i, n; |
||||
snd_pcm_sframes_t actual; |
||||
SOX_SAMPLE_LOCALS; |
||||
|
||||
for (done = 0; done < len; done += n) { |
||||
i = n = min(len - done, p->buf_len); |
||||
switch (formats[p->format].alsa_fmt) { |
||||
case SND_PCM_FORMAT_S8: { |
||||
int8_t * buf1 = (int8_t *)p->buf; |
||||
while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_8BIT(*buf++, ft->clips); |
||||
break; |
||||
} |
||||
case SND_PCM_FORMAT_U8: { |
||||
uint8_t * buf1 = (uint8_t *)p->buf; |
||||
while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_8BIT(*buf++, ft->clips); |
||||
break; |
||||
} |
||||
case SND_PCM_FORMAT_S16: { |
||||
int16_t * buf1 = (int16_t *)p->buf; |
||||
if (ft->encoding.reverse_bytes) while (i--) |
||||
*buf1++ = lsx_swapw(SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips)); |
||||
else |
||||
while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips); |
||||
break; |
||||
} |
||||
case SND_PCM_FORMAT_U16: { |
||||
uint16_t * buf1 = (uint16_t *)p->buf; |
||||
if (ft->encoding.reverse_bytes) while (i--) |
||||
*buf1++ = lsx_swapw(SOX_SAMPLE_TO_UNSIGNED_16BIT(*buf++, ft->clips)); |
||||
else |
||||
while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_16BIT(*buf++, ft->clips); |
||||
break; |
||||
} |
||||
case SND_PCM_FORMAT_S24: { |
||||
sox_int24_t * buf1 = (sox_int24_t *)p->buf; |
||||
while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_24BIT(*buf++, ft->clips); |
||||
break; |
||||
} |
||||
case SND_PCM_FORMAT_S24_3LE: { |
||||
unsigned char *buf1 = (unsigned char *)p->buf; |
||||
while (i--) { |
||||
uint32_t temp = (uint32_t)SOX_SAMPLE_TO_SIGNED_24BIT(*buf++, ft->clips); |
||||
*buf1++ = (temp & 0x000000FF); |
||||
*buf1++ = (temp & 0x0000FF00) >> 8; |
||||
*buf1++ = (temp & 0x00FF0000) >> 16; |
||||
} |
||||
break; |
||||
} |
||||
case SND_PCM_FORMAT_U24: { |
||||
sox_uint24_t * buf1 = (sox_uint24_t *)p->buf; |
||||
while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_24BIT(*buf++, ft->clips); |
||||
break; |
||||
} |
||||
case SND_PCM_FORMAT_S32: { |
||||
int32_t * buf1 = (int32_t *)p->buf; |
||||
while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_32BIT(*buf++, ft->clips); |
||||
break; |
||||
} |
||||
case SND_PCM_FORMAT_U32: { |
||||
uint32_t * buf1 = (uint32_t *)p->buf; |
||||
while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_32BIT(*buf++, ft->clips); |
||||
break; |
||||
} |
||||
default: lsx_fail_errno(ft, SOX_EFMT, "invalid format"); |
||||
return 0; |
||||
} |
||||
for (i = 0; i < n; i += actual * ft->signal.channels) do { |
||||
actual = snd_pcm_writei(p->pcm, |
||||
p->buf + i * formats[p->format].bytes, |
||||
(n - i) / ft->signal.channels); |
||||
if (errno == EAGAIN) /* Happens naturally; don't report it: */ |
||||
errno = 0; |
||||
if (actual < 0 && recover(ft, p->pcm, (int)actual) < 0) |
||||
return 0; |
||||
} while (actual < 0); |
||||
} |
||||
return len; |
||||
} |
||||
|
||||
static int stop(sox_format_t * ft) |
||||
{ |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
snd_pcm_close(p->pcm); |
||||
free(p->buf); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int stop_write(sox_format_t * ft) |
||||
{ |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
size_t n = ft->signal.channels * p->period, npad = n - (ft->olength % n); |
||||
sox_sample_t * buf = lsx_calloc(npad, sizeof(*buf)); /* silent samples */ |
||||
|
||||
if (npad != n) /* pad to hardware period: */ |
||||
write_(ft, buf, npad); |
||||
free(buf); |
||||
snd_pcm_drain(p->pcm); |
||||
return stop(ft); |
||||
} |
||||
|
||||
LSX_FORMAT_HANDLER(alsa) |
||||
{ |
||||
static char const * const names[] = {"alsa", NULL}; |
||||
static unsigned const write_encodings[] = { |
||||
SOX_ENCODING_SIGN2 , 32, 24, 16, 8, 0, |
||||
SOX_ENCODING_UNSIGNED, 32, 24, 16, 8, 0, |
||||
0}; |
||||
static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, |
||||
"Advanced Linux Sound Architecture device driver", |
||||
names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO, |
||||
setup, read_, stop, setup, write_, stop_write, |
||||
NULL, write_encodings, NULL, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,90 +0,0 @@ |
||||
/* File format: AMR-NB (c) 2007 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
/*
|
||||
* In order to use the AMR format with SoX, you need to have an |
||||
* AMR library installed at SoX build time. The SoX build system |
||||
* recognizes the AMR implementations available from |
||||
* http://opencore-amr.sourceforge.net/
|
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
/* Common definitions: */ |
||||
|
||||
enum amrnb_mode { amrnb_mode_dummy }; |
||||
|
||||
static const unsigned amrnb_block_size[] = {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 1}; |
||||
static char const amrnb_magic[] = "#!AMR\n"; |
||||
#define amr_block_size amrnb_block_size |
||||
#define amr_magic amrnb_magic |
||||
#define amr_priv_t amrnb_priv_t |
||||
#define amr_opencore_funcs amrnb_opencore_funcs |
||||
#define amr_gp3_funcs amrnb_gp3_funcs |
||||
|
||||
#define AMR_CODED_MAX 32 /* max coded size */ |
||||
#define AMR_ENCODING SOX_ENCODING_AMR_NB |
||||
#define AMR_FORMAT_FN lsx_amr_nb_format_fn |
||||
#define AMR_FRAME 160 /* 20ms @ 8kHz */ |
||||
#define AMR_MODE_MAX 7 |
||||
#define AMR_NAMES "amr-nb", "anb" |
||||
#define AMR_RATE 8000 |
||||
#define AMR_DESC "3GPP Adaptive Multi Rate Narrow-Band (AMR-NB) lossy speech compressor" |
||||
|
||||
#ifdef DL_OPENCORE_AMRNB |
||||
#define AMR_FUNC LSX_DLENTRY_DYNAMIC |
||||
#else |
||||
#define AMR_FUNC LSX_DLENTRY_STATIC |
||||
#endif /* DL_AMRNB */ |
||||
|
||||
/* OpenCore definitions: */ |
||||
|
||||
#define AMR_OPENCORE 1 |
||||
#define AMR_OPENCORE_ENABLE_ENCODE 1 |
||||
|
||||
#define AMR_OPENCORE_FUNC_ENTRIES(f,x) \ |
||||
AMR_FUNC(f,x, void*, Encoder_Interface_init, (int dtx)) \
|
||||
AMR_FUNC(f,x, int, Encoder_Interface_Encode, (void* state, enum amrnb_mode mode, const short* in, unsigned char* out, int forceSpeech)) \
|
||||
AMR_FUNC(f,x, void, Encoder_Interface_exit, (void* state)) \
|
||||
AMR_FUNC(f,x, void*, Decoder_Interface_init, (void)) \
|
||||
AMR_FUNC(f,x, void, Decoder_Interface_Decode, (void* state, const unsigned char* in, short* out, int bfi)) \
|
||||
AMR_FUNC(f,x, void, Decoder_Interface_exit, (void* state)) \
|
||||
|
||||
#define AmrEncoderInit() \ |
||||
Encoder_Interface_init(1) |
||||
#define AmrEncoderEncode(state, mode, in, out, forceSpeech) \ |
||||
Encoder_Interface_Encode(state, mode, in, out, forceSpeech) |
||||
#define AmrEncoderExit(state) \ |
||||
Encoder_Interface_exit(state) |
||||
#define AmrDecoderInit() \ |
||||
Decoder_Interface_init() |
||||
#define AmrDecoderDecode(state, in, out, bfi) \ |
||||
Decoder_Interface_Decode(state, in, out, bfi) |
||||
#define AmrDecoderExit(state) \ |
||||
Decoder_Interface_exit(state) |
||||
|
||||
#define AMR_OPENCORE_DESC "amr-nb OpenCore library" |
||||
static const char* const amr_opencore_library_names[] = |
||||
{ |
||||
#ifdef DL_OPENCORE_AMRNB |
||||
"libopencore-amrnb", |
||||
"libopencore-amrnb-0", |
||||
#endif |
||||
NULL |
||||
}; |
||||
|
||||
#include "amr.h" |
@ -1,115 +0,0 @@ |
||||
/* File format: AMR-WB (c) 2007 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
/*
|
||||
* In order to use the AMR format with SoX, you need to have an |
||||
* AMR library installed at SoX build time. The SoX build system |
||||
* recognizes the AMR implementations available from |
||||
* http://opencore-amr.sourceforge.net/
|
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
/* Common definitions: */ |
||||
|
||||
static const uint8_t amrwb_block_size[] = {18, 24, 33, 37, 41, 47, 51, 59, 61, 6, 6, 0, 0, 0, 1, 1}; |
||||
static char const amrwb_magic[] = "#!AMR-WB\n"; |
||||
#define amr_block_size amrwb_block_size |
||||
#define amr_magic amrwb_magic |
||||
#define amr_priv_t amrwb_priv_t |
||||
#define amr_opencore_funcs amrwb_opencore_funcs |
||||
#define amr_vo_funcs amrwb_vo_funcs |
||||
|
||||
#define AMR_CODED_MAX 61 /* NB_SERIAL_MAX */ |
||||
#define AMR_ENCODING SOX_ENCODING_AMR_WB |
||||
#define AMR_FORMAT_FN lsx_amr_wb_format_fn |
||||
#define AMR_FRAME 320 /* L_FRAME16k */ |
||||
#define AMR_MODE_MAX 8 |
||||
#define AMR_NAMES "amr-wb", "awb" |
||||
#define AMR_RATE 16000 |
||||
#define AMR_DESC "3GPP Adaptive Multi Rate Wide-Band (AMR-WB) lossy speech compressor" |
||||
|
||||
/* OpenCore definitions: */ |
||||
|
||||
#ifdef DL_OPENCORE_AMRWB |
||||
#define AMR_OC_FUNC LSX_DLENTRY_DYNAMIC |
||||
#else |
||||
#define AMR_OC_FUNC LSX_DLENTRY_STATIC |
||||
#endif |
||||
|
||||
#if defined(HAVE_OPENCORE_AMRWB_DEC_IF_H) || defined(DL_OPENCORE_AMRWB) |
||||
#define AMR_OPENCORE 1 |
||||
#define AMR_OPENCORE_ENABLE_ENCODE 0 |
||||
#endif |
||||
|
||||
#define AMR_OPENCORE_FUNC_ENTRIES(f,x) \ |
||||
AMR_OC_FUNC(f,x, void*, D_IF_init, (void)) \
|
||||
AMR_OC_FUNC(f,x, void, D_IF_decode, (void* state, const unsigned char* in, short* out, int bfi)) \
|
||||
AMR_OC_FUNC(f,x, void, D_IF_exit, (void* state)) \
|
||||
|
||||
#define AmrDecoderInit() \ |
||||
D_IF_init() |
||||
#define AmrDecoderDecode(state, in, out, bfi) \ |
||||
D_IF_decode(state, in, out, bfi) |
||||
#define AmrDecoderExit(state) \ |
||||
D_IF_exit(state) |
||||
|
||||
#define AMR_OPENCORE_DESC "amr-wb OpenCore library" |
||||
static const char* const amr_opencore_library_names[] = |
||||
{ |
||||
#ifdef DL_OPENCORE_AMRWB |
||||
"libopencore-amrwb", |
||||
"libopencore-amrwb-0", |
||||
#endif |
||||
NULL |
||||
}; |
||||
|
||||
/* VO definitions: */ |
||||
|
||||
#ifdef DL_VO_AMRWBENC |
||||
#define AMR_VO_FUNC LSX_DLENTRY_DYNAMIC |
||||
#else |
||||
#define AMR_VO_FUNC LSX_DLENTRY_STATIC |
||||
#endif |
||||
|
||||
#if defined(HAVE_VO_AMRWBENC_ENC_IF_H) || defined(DL_VO_AMRWBENC) |
||||
#define AMR_VO 1 |
||||
#endif |
||||
|
||||
#define AMR_VO_FUNC_ENTRIES(f,x) \ |
||||
AMR_VO_FUNC(f,x, void*, E_IF_init, (void)) \
|
||||
AMR_VO_FUNC(f,x, int, E_IF_encode,(void* state, int16_t mode, int16_t* in, uint8_t* out, int16_t dtx)) \
|
||||
AMR_VO_FUNC(f,x, void, E_IF_exit, (void* state)) \
|
||||
|
||||
#define AmrEncoderInit() \ |
||||
E_IF_init() |
||||
#define AmrEncoderEncode(state, mode, in, out, forceSpeech) \ |
||||
E_IF_encode(state, mode, in, out, forceSpeech) |
||||
#define AmrEncoderExit(state) \ |
||||
E_IF_exit(state) |
||||
|
||||
#define AMR_VO_DESC "amr-wb VisualOn library" |
||||
static const char* const amr_vo_library_names[] = |
||||
{ |
||||
#ifdef DL_VO_AMRWBENC |
||||
"libvo-amrwbenc", |
||||
"libvo-amrwbenc-0", |
||||
#endif |
||||
NULL |
||||
}; |
||||
|
||||
#include "amr.h" |
@ -1,335 +0,0 @@ |
||||
/* File format: AMR (c) 2007 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include <string.h> |
||||
#include <math.h> |
||||
|
||||
#ifdef AMR_OPENCORE |
||||
|
||||
LSX_DLENTRIES_TO_FUNCTIONS(AMR_OPENCORE_FUNC_ENTRIES) |
||||
|
||||
typedef struct amr_opencore_funcs { |
||||
LSX_DLENTRIES_TO_PTRS(AMR_OPENCORE_FUNC_ENTRIES, amr_dl); |
||||
} amr_opencore_funcs; |
||||
|
||||
#endif /* AMR_OPENCORE */ |
||||
|
||||
#ifdef AMR_VO |
||||
|
||||
LSX_DLENTRIES_TO_FUNCTIONS(AMR_VO_FUNC_ENTRIES) |
||||
|
||||
typedef struct amr_vo_funcs { |
||||
LSX_DLENTRIES_TO_PTRS(AMR_VO_FUNC_ENTRIES, amr_dl); |
||||
} amr_vo_funcs; |
||||
|
||||
#endif /* AMR_VO */ |
||||
|
||||
#define AMR_CALL(p, func, args) ((p)->opencore.func args) |
||||
|
||||
#ifdef AMR_VO |
||||
#define AMR_CALL_ENCODER(p, func, args) ((p)->vo.func args) |
||||
#else |
||||
#define AMR_CALL_ENCODER(p, func, args) ((p)->opencore.func args) |
||||
#endif |
||||
|
||||
typedef struct amr_priv_t { |
||||
void* state; |
||||
unsigned mode; |
||||
size_t pcm_index; |
||||
#ifdef AMR_OPENCORE |
||||
amr_opencore_funcs opencore; |
||||
#endif /* AMR_OPENCORE */ |
||||
#ifdef AMR_VO |
||||
amr_vo_funcs vo; |
||||
#endif /* AMR_VO */ |
||||
short pcm[AMR_FRAME]; |
||||
} priv_t; |
||||
|
||||
#ifdef AMR_OPENCORE |
||||
static size_t decode_1_frame(sox_format_t * ft) |
||||
{ |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
size_t n; |
||||
uint8_t coded[AMR_CODED_MAX]; |
||||
|
||||
if (lsx_readbuf(ft, &coded[0], (size_t)1) != 1) |
||||
return AMR_FRAME; |
||||
n = amr_block_size[(coded[0] >> 3) & 0x0F]; |
||||
if (!n) { |
||||
lsx_fail("invalid block type"); |
||||
return AMR_FRAME; |
||||
} |
||||
n--; |
||||
if (lsx_readbuf(ft, &coded[1], n) != n) |
||||
return AMR_FRAME; |
||||
AMR_CALL(p, AmrDecoderDecode, (p->state, coded, p->pcm, 0)); |
||||
return 0; |
||||
} |
||||
#endif |
||||
|
||||
static int openlibrary(priv_t* p, int encoding) |
||||
{ |
||||
int open_library_result; |
||||
|
||||
(void)encoding; |
||||
#ifdef AMR_OPENCORE |
||||
if (AMR_OPENCORE_ENABLE_ENCODE || !encoding) |
||||
{ |
||||
LSX_DLLIBRARY_TRYOPEN( |
||||
0, |
||||
&p->opencore, |
||||
amr_dl, |
||||
AMR_OPENCORE_FUNC_ENTRIES, |
||||
AMR_OPENCORE_DESC, |
||||
amr_opencore_library_names, |
||||
open_library_result); |
||||
if (!open_library_result) |
||||
return SOX_SUCCESS; |
||||
lsx_fail("Unable to open " AMR_OPENCORE_DESC); |
||||
return SOX_EOF; |
||||
} |
||||
#endif /* AMR_OPENCORE */ |
||||
|
||||
#ifdef AMR_VO |
||||
if (encoding) { |
||||
LSX_DLLIBRARY_TRYOPEN( |
||||
0, |
||||
&p->vo, |
||||
amr_dl, |
||||
AMR_VO_FUNC_ENTRIES, |
||||
AMR_VO_DESC, |
||||
amr_vo_library_names, |
||||
open_library_result); |
||||
if (!open_library_result) |
||||
return SOX_SUCCESS; |
||||
lsx_fail("Unable to open " AMR_VO_DESC); |
||||
} |
||||
#endif /* AMR_VO */ |
||||
|
||||
return SOX_EOF; |
||||
} |
||||
|
||||
static void closelibrary(priv_t* p) |
||||
{ |
||||
#ifdef AMR_OPENCORE |
||||
LSX_DLLIBRARY_CLOSE(&p->opencore, amr_dl); |
||||
#endif |
||||
#ifdef AMR_VO |
||||
LSX_DLLIBRARY_CLOSE(&p->vo, amr_dl); |
||||
#endif |
||||
} |
||||
|
||||
#ifdef AMR_OPENCORE |
||||
static size_t amr_duration_frames(sox_format_t * ft) |
||||
{ |
||||
off_t frame_size, data_start_offset = lsx_tell(ft); |
||||
size_t frames; |
||||
uint8_t coded; |
||||
|
||||
for (frames = 0; lsx_readbuf(ft, &coded, (size_t)1) == 1; ++frames) { |
||||
frame_size = amr_block_size[coded >> 3 & 15]; |
||||
if (!frame_size) { |
||||
lsx_fail("invalid block type"); |
||||
break; |
||||
} |
||||
if (lsx_seeki(ft, frame_size - 1, SEEK_CUR)) { |
||||
lsx_fail("seek"); |
||||
break; |
||||
} |
||||
} |
||||
lsx_debug("frames=%lu", (unsigned long)frames); |
||||
lsx_seeki(ft, data_start_offset, SEEK_SET); |
||||
return frames; |
||||
} |
||||
#endif |
||||
|
||||
static int startread(sox_format_t * ft) |
||||
{ |
||||
#if !defined(AMR_OPENCORE) |
||||
lsx_fail_errno(ft, SOX_EOF, "SoX was compiled without AMR-WB decoding support."); |
||||
return SOX_EOF; |
||||
#else |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
char buffer[sizeof(amr_magic) - 1]; |
||||
int open_library_result; |
||||
|
||||
if (lsx_readchars(ft, buffer, sizeof(buffer))) |
||||
return SOX_EOF; |
||||
if (memcmp(buffer, amr_magic, sizeof(buffer))) { |
||||
lsx_fail_errno(ft, SOX_EHDR, "invalid magic number"); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
open_library_result = openlibrary(p, 0); |
||||
if (open_library_result != SOX_SUCCESS) |
||||
return open_library_result; |
||||
|
||||
p->pcm_index = AMR_FRAME; |
||||
p->state = AMR_CALL(p, AmrDecoderInit, ()); |
||||
if (!p->state) |
||||
{ |
||||
closelibrary(p); |
||||
lsx_fail("AMR decoder failed to initialize."); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
ft->signal.rate = AMR_RATE; |
||||
ft->encoding.encoding = AMR_ENCODING; |
||||
ft->signal.channels = 1; |
||||
ft->signal.length = ft->signal.length != SOX_IGNORE_LENGTH && ft->seekable? |
||||
(size_t)(amr_duration_frames(ft) * .02 * ft->signal.rate +.5) : SOX_UNSPEC; |
||||
return SOX_SUCCESS; |
||||
#endif |
||||
} |
||||
|
||||
#ifdef AMR_OPENCORE |
||||
|
||||
static size_t read_samples(sox_format_t * ft, sox_sample_t * buf, size_t len) |
||||
{ |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
size_t done; |
||||
|
||||
for (done = 0; done < len; done++) { |
||||
if (p->pcm_index >= AMR_FRAME) |
||||
p->pcm_index = decode_1_frame(ft); |
||||
if (p->pcm_index >= AMR_FRAME) |
||||
break; |
||||
*buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(p->pcm[p->pcm_index++], ft->clips); |
||||
} |
||||
return done; |
||||
} |
||||
|
||||
static int stopread(sox_format_t * ft) |
||||
{ |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
AMR_CALL(p, AmrDecoderExit, (p->state)); |
||||
closelibrary(p); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
#else |
||||
|
||||
#define read_samples NULL |
||||
#define stopread NULL |
||||
|
||||
#endif |
||||
|
||||
static int startwrite(sox_format_t * ft) |
||||
{ |
||||
#if !defined(AMR_VO) && !AMR_OPENCORE_ENABLE_ENCODE |
||||
lsx_fail_errno(ft, SOX_EOF, "SoX was compiled without AMR-WB encoding support."); |
||||
return SOX_EOF; |
||||
#else |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
int open_library_result; |
||||
|
||||
if (ft->encoding.compression != HUGE_VAL) { |
||||
p->mode = (unsigned)ft->encoding.compression; |
||||
if (p->mode != ft->encoding.compression || p->mode > AMR_MODE_MAX) { |
||||
lsx_fail_errno(ft, SOX_EINVAL, "compression level must be a whole number from 0 to %i", AMR_MODE_MAX); |
||||
return SOX_EOF; |
||||
} |
||||
} |
||||
else p->mode = 0; |
||||
|
||||
open_library_result = openlibrary(p, 1); |
||||
if (open_library_result != SOX_SUCCESS) |
||||
return open_library_result; |
||||
|
||||
p->state = AMR_CALL_ENCODER(p, AmrEncoderInit, ()); |
||||
if (!p->state) |
||||
{ |
||||
closelibrary(p); |
||||
lsx_fail("AMR encoder failed to initialize."); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
lsx_writes(ft, amr_magic); |
||||
p->pcm_index = 0; |
||||
return SOX_SUCCESS; |
||||
#endif |
||||
} |
||||
|
||||
#if defined(AMR_VO) || AMR_OPENCORE_ENABLE_ENCODE |
||||
|
||||
static sox_bool encode_1_frame(sox_format_t * ft) |
||||
{ |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
uint8_t coded[AMR_CODED_MAX]; |
||||
int n = AMR_CALL_ENCODER(p, AmrEncoderEncode, (p->state, p->mode, p->pcm, coded, 1)); |
||||
sox_bool result = lsx_writebuf(ft, coded, (size_t) (size_t) (unsigned)n) == (unsigned)n; |
||||
if (!result) |
||||
lsx_fail_errno(ft, errno, "write error"); |
||||
return result; |
||||
} |
||||
|
||||
static size_t write_samples(sox_format_t * ft, const sox_sample_t * buf, size_t len) |
||||
{ |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
size_t done; |
||||
|
||||
for (done = 0; done < len; ++done) { |
||||
SOX_SAMPLE_LOCALS; |
||||
p->pcm[p->pcm_index++] = SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips); |
||||
if (p->pcm_index == AMR_FRAME) { |
||||
p->pcm_index = 0; |
||||
if (!encode_1_frame(ft)) |
||||
return 0; |
||||
} |
||||
} |
||||
return done; |
||||
} |
||||
|
||||
static int stopwrite(sox_format_t * ft) |
||||
{ |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
int result = SOX_SUCCESS; |
||||
|
||||
if (p->pcm_index) { |
||||
do { |
||||
p->pcm[p->pcm_index++] = 0; |
||||
} while (p->pcm_index < AMR_FRAME); |
||||
if (!encode_1_frame(ft)) |
||||
result = SOX_EOF; |
||||
} |
||||
AMR_CALL_ENCODER(p, AmrEncoderExit, (p->state)); |
||||
return result; |
||||
} |
||||
|
||||
#else |
||||
|
||||
#define write_samples NULL |
||||
#define stopwrite NULL |
||||
|
||||
#endif /* defined(AMR_VO) || AMR_OPENCORE_ENABLE_ENCODE */ |
||||
|
||||
sox_format_handler_t const * AMR_FORMAT_FN(void); |
||||
sox_format_handler_t const * AMR_FORMAT_FN(void) |
||||
{ |
||||
static char const * const names[] = {AMR_NAMES, NULL}; |
||||
static sox_rate_t const write_rates[] = {AMR_RATE, 0}; |
||||
static unsigned const write_encodings[] = {AMR_ENCODING, 0, 0}; |
||||
static sox_format_handler_t handler = { |
||||
SOX_LIB_VERSION_CODE, |
||||
AMR_DESC, |
||||
names, SOX_FILE_MONO, |
||||
startread, read_samples, stopread, |
||||
startwrite, write_samples, stopwrite, |
||||
NULL, write_encodings, write_rates, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,47 +0,0 @@ |
||||
/* libSoX Bandpass effect file. July 5, 1991
|
||||
* Copyright 1991 Lance Norskog And Sundry Contributors |
||||
* |
||||
* This source code is freely redistributable and may be used for |
||||
* any purpose. This copyright notice must be maintained. |
||||
* Lance Norskog And Sundry Contributors are not responsible for |
||||
* the consequences of using this software. |
||||
* |
||||
* Algorithm: 2nd order recursive filter. |
||||
* Formula stolen from MUSIC56K, a toolkit of 56000 assembler stuff. |
||||
* Quote: |
||||
* This is a 2nd order recursive band pass filter of the form. |
||||
* y(n)= a * x(n) - b * y(n-1) - c * y(n-2) |
||||
* where : |
||||
* x(n) = "IN" |
||||
* "OUT" = y(n) |
||||
* c = EXP(-2*pi*cBW/S_RATE) |
||||
* b = -4*c/(1+c)*COS(2*pi*cCF/S_RATE) |
||||
* if cSCL=2 (i.e. noise input) |
||||
* a = SQT(((1+c)*(1+c)-b*b)*(1-c)/(1+c)) |
||||
* else |
||||
* a = SQT(1-b*b/(4*c))*(1-c) |
||||
* endif |
||||
* note : cCF is the center frequency in Hertz |
||||
* cBW is the band width in Hertz |
||||
* cSCL is a scale factor, use 1 for pitched sounds |
||||
* use 2 for noise. |
||||
* |
||||
* |
||||
* July 1, 1999 - Jan Paul Schmidt <jps@fundament.org> |
||||
* |
||||
* This looks like the resonator band pass in SPKit. It's a |
||||
* second order all-pole (IIR) band-pass filter described |
||||
* at the pages 186 - 189 in |
||||
* Dodge, Charles & Jerse, Thomas A. 1985: |
||||
* Computer Music -- Synthesis, Composition and Performance. |
||||
* New York: Schirmer Books. |
||||
* Reference from the SPKit manual. |
||||
*/ |
||||
|
||||
p->a2 = exp(-2 * M_PI * bw_Hz / effp->in_signal.rate); |
||||
p->a1 = -4 * p->a2 / (1 + p->a2) * cos(2 * M_PI * p->fc / effp->in_signal.rate); |
||||
p->b0 = sqrt(1 - p->a1 * p->a1 / (4 * p->a2)) * (1 - p->a2); |
||||
if (p->filter_type == filter_BPF_SPK_N) { |
||||
mult = sqrt(((1+p->a2) * (1+p->a2) - p->a1*p->a1) * (1-p->a2) / (1+p->a2)) / p->b0; |
||||
p->b0 *= mult; |
||||
} |
@ -1,325 +0,0 @@ |
||||
/* libSoX effect: Pitch Bend (c) 2008 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
/* Portions based on http://www.dspdimension.com/download smbPitchShift.cpp:
|
||||
* |
||||
* COPYRIGHT 1999-2006 Stephan M. Bernsee <smb [AT] dspdimension [DOT] com> |
||||
* |
||||
* The Wide Open License (WOL) |
||||
* |
||||
* Permission to use, copy, modify, distribute and sell this software and its |
||||
* documentation for any purpose is hereby granted without fee, provided that |
||||
* the above copyright notice and this license appear in all source copies.
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF |
||||
* ANY KIND. See http://www.dspguru.com/wol.htm for more information.
|
||||
*/ |
||||
|
||||
#ifdef NDEBUG /* Enable assert always. */ |
||||
#undef NDEBUG /* Must undef above assert.h or other that might include it. */ |
||||
#endif |
||||
|
||||
#include "sox_i.h" |
||||
#include <assert.h> |
||||
|
||||
#define MAX_FRAME_LENGTH 8192 |
||||
|
||||
typedef struct { |
||||
unsigned nbends; /* Number of bends requested */ |
||||
struct { |
||||
char *str; /* Command-line argument to parse for this bend */ |
||||
uint64_t start; /* Start bending when in_pos equals this */ |
||||
double cents; |
||||
uint64_t duration; /* Number of samples to bend */ |
||||
} *bends; |
||||
|
||||
unsigned frame_rate; |
||||
size_t in_pos; /* Number of samples read from the input stream */ |
||||
unsigned bends_pos; /* Number of bends completed so far */ |
||||
|
||||
double shift; |
||||
|
||||
float gInFIFO[MAX_FRAME_LENGTH]; |
||||
float gOutFIFO[MAX_FRAME_LENGTH]; |
||||
double gFFTworksp[2 * MAX_FRAME_LENGTH]; |
||||
float gLastPhase[MAX_FRAME_LENGTH / 2 + 1]; |
||||
float gSumPhase[MAX_FRAME_LENGTH / 2 + 1]; |
||||
float gOutputAccum[2 * MAX_FRAME_LENGTH]; |
||||
float gAnaFreq[MAX_FRAME_LENGTH]; |
||||
float gAnaMagn[MAX_FRAME_LENGTH]; |
||||
float gSynFreq[MAX_FRAME_LENGTH]; |
||||
float gSynMagn[MAX_FRAME_LENGTH]; |
||||
long gRover; |
||||
int fftFrameSize, ovsamp; |
||||
} priv_t; |
||||
|
||||
static int parse(sox_effect_t * effp, char **argv, sox_rate_t rate) |
||||
{ |
||||
priv_t *p = (priv_t *) effp->priv; |
||||
size_t i; |
||||
char const *next; |
||||
uint64_t last_seen = 0; |
||||
const uint64_t in_length = argv ? 0 : |
||||
(effp->in_signal.length != SOX_UNKNOWN_LEN ? |
||||
effp->in_signal.length / effp->in_signal.channels : SOX_UNKNOWN_LEN); |
||||
|
||||
for (i = 0; i < p->nbends; ++i) { |
||||
if (argv) /* 1st parse only */ |
||||
p->bends[i].str = lsx_strdup(argv[i]); |
||||
|
||||
next = lsx_parseposition(rate, p->bends[i].str, |
||||
argv ? NULL : &p->bends[i].start, last_seen, in_length, '+'); |
||||
last_seen = p->bends[i].start; |
||||
if (next == NULL || *next != ',') |
||||
break; |
||||
|
||||
p->bends[i].cents = strtod(next + 1, (char **)&next); |
||||
if (p->bends[i].cents == 0 || *next != ',') |
||||
break; |
||||
|
||||
next = lsx_parseposition(rate, next + 1, |
||||
argv ? NULL : &p->bends[i].duration, last_seen, in_length, '+'); |
||||
last_seen = p->bends[i].duration; |
||||
if (next == NULL || *next != '\0') |
||||
break; |
||||
|
||||
/* sanity checks */ |
||||
if (!argv && p->bends[i].duration < p->bends[i].start) { |
||||
lsx_fail("Bend %" PRIuPTR " has negative width", i+1); |
||||
break; |
||||
} |
||||
if (!argv && i && p->bends[i].start < p->bends[i-1].start) { |
||||
lsx_fail("Bend %" PRIuPTR " overlaps with previous one", i+1); |
||||
break; |
||||
} |
||||
|
||||
p->bends[i].duration -= p->bends[i].start; |
||||
} |
||||
if (i < p->nbends) |
||||
return lsx_usage(effp); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int create(sox_effect_t * effp, int argc, char **argv) |
||||
{ |
||||
priv_t *p = (priv_t *) effp->priv; |
||||
char const * opts = "f:o:"; |
||||
int c; |
||||
lsx_getopt_t optstate; |
||||
lsx_getopt_init(argc, argv, opts, NULL, lsx_getopt_flag_none, 1, &optstate); |
||||
|
||||
p->frame_rate = 25; |
||||
p->ovsamp = 16; |
||||
while ((c = lsx_getopt(&optstate)) != -1) switch (c) { |
||||
GETOPT_NUMERIC(optstate, 'f', frame_rate, 10 , 80) |
||||
GETOPT_NUMERIC(optstate, 'o', ovsamp, 4 , 32) |
||||
default: lsx_fail("unknown option `-%c'", optstate.opt); return lsx_usage(effp); |
||||
} |
||||
argc -= optstate.ind, argv += optstate.ind; |
||||
|
||||
p->nbends = argc; |
||||
p->bends = lsx_calloc(p->nbends, sizeof(*p->bends)); |
||||
return parse(effp, argv, 0.); /* No rate yet; parse with dummy */ |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t *p = (priv_t *) effp->priv; |
||||
unsigned i; |
||||
|
||||
int n = effp->in_signal.rate / p->frame_rate + .5; |
||||
for (p->fftFrameSize = 2; n > 2; p->fftFrameSize <<= 1, n >>= 1); |
||||
assert(p->fftFrameSize <= MAX_FRAME_LENGTH); |
||||
p->shift = 1; |
||||
parse(effp, 0, effp->in_signal.rate); /* Re-parse now rate is known */ |
||||
p->in_pos = p->bends_pos = 0; |
||||
for (i = 0; i < p->nbends; ++i) |
||||
if (p->bends[i].duration) |
||||
return SOX_SUCCESS; |
||||
return SOX_EFF_NULL; |
||||
} |
||||
|
||||
static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, |
||||
sox_sample_t * obuf, size_t * isamp, size_t * osamp) |
||||
{ |
||||
priv_t *p = (priv_t *) effp->priv; |
||||
size_t i, len = *isamp = *osamp = min(*isamp, *osamp); |
||||
double magn, phase, tmp, window, real, imag; |
||||
double freqPerBin, expct; |
||||
long k, qpd, index, inFifoLatency, stepSize, fftFrameSize2; |
||||
float pitchShift = p->shift; |
||||
|
||||
/* set up some handy variables */ |
||||
fftFrameSize2 = p->fftFrameSize / 2; |
||||
stepSize = p->fftFrameSize / p->ovsamp; |
||||
freqPerBin = effp->in_signal.rate / p->fftFrameSize; |
||||
expct = 2. * M_PI * (double) stepSize / (double) p->fftFrameSize; |
||||
inFifoLatency = p->fftFrameSize - stepSize; |
||||
if (!p->gRover) |
||||
p->gRover = inFifoLatency; |
||||
|
||||
/* main processing loop */ |
||||
for (i = 0; i < len; i++) { |
||||
SOX_SAMPLE_LOCALS; |
||||
++p->in_pos; |
||||
|
||||
/* As long as we have not yet collected enough data just read in */ |
||||
p->gInFIFO[p->gRover] = SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[i], effp->clips); |
||||
obuf[i] = SOX_FLOAT_32BIT_TO_SAMPLE( |
||||
p->gOutFIFO[p->gRover - inFifoLatency], effp->clips); |
||||
p->gRover++; |
||||
|
||||
/* now we have enough data for processing */ |
||||
if (p->gRover >= p->fftFrameSize) { |
||||
if (p->bends_pos != p->nbends && p->in_pos >= |
||||
p->bends[p->bends_pos].start + p->bends[p->bends_pos].duration) { |
||||
pitchShift = p->shift *= pow(2., p->bends[p->bends_pos].cents / 1200); |
||||
++p->bends_pos; |
||||
} |
||||
if (p->bends_pos != p->nbends && p->in_pos >= p->bends[p->bends_pos].start) { |
||||
double progress = (double)(p->in_pos - p->bends[p->bends_pos].start) / |
||||
p->bends[p->bends_pos].duration; |
||||
progress = 1 - cos(M_PI * progress); |
||||
progress *= p->bends[p->bends_pos].cents * (.5 / 1200); |
||||
pitchShift = p->shift * pow(2., progress); |
||||
} |
||||
|
||||
p->gRover = inFifoLatency; |
||||
|
||||
/* do windowing and re,im interleave */ |
||||
for (k = 0; k < p->fftFrameSize; k++) { |
||||
window = -.5 * cos(2 * M_PI * k / (double) p->fftFrameSize) + .5; |
||||
p->gFFTworksp[2 * k] = p->gInFIFO[k] * window; |
||||
p->gFFTworksp[2 * k + 1] = 0.; |
||||
} |
||||
|
||||
/* ***************** ANALYSIS ******************* */ |
||||
lsx_safe_cdft(2 * p->fftFrameSize, 1, p->gFFTworksp); |
||||
|
||||
/* this is the analysis step */ |
||||
for (k = 0; k <= fftFrameSize2; k++) { |
||||
/* de-interlace FFT buffer */ |
||||
real = p->gFFTworksp[2 * k]; |
||||
imag = - p->gFFTworksp[2 * k + 1]; |
||||
|
||||
/* compute magnitude and phase */ |
||||
magn = 2. * sqrt(real * real + imag * imag); |
||||
phase = atan2(imag, real); |
||||
|
||||
/* compute phase difference */ |
||||
tmp = phase - p->gLastPhase[k]; |
||||
p->gLastPhase[k] = phase; |
||||
|
||||
tmp -= (double) k *expct; /* subtract expected phase difference */ |
||||
|
||||
/* map delta phase into +/- Pi interval */ |
||||
qpd = tmp / M_PI; |
||||
if (qpd >= 0) |
||||
qpd += qpd & 1; |
||||
else qpd -= qpd & 1; |
||||
tmp -= M_PI * (double) qpd; |
||||
|
||||
/* get deviation from bin frequency from the +/- Pi interval */ |
||||
tmp = p->ovsamp * tmp / (2. * M_PI); |
||||
|
||||
/* compute the k-th partials' true frequency */ |
||||
tmp = (double) k *freqPerBin + tmp * freqPerBin; |
||||
|
||||
/* store magnitude and true frequency in analysis arrays */ |
||||
p->gAnaMagn[k] = magn; |
||||
p->gAnaFreq[k] = tmp; |
||||
|
||||
} |
||||
|
||||
/* this does the actual pitch shifting */ |
||||
memset(p->gSynMagn, 0, p->fftFrameSize * sizeof(float)); |
||||
memset(p->gSynFreq, 0, p->fftFrameSize * sizeof(float)); |
||||
for (k = 0; k <= fftFrameSize2; k++) { |
||||
index = k * pitchShift; |
||||
if (index <= fftFrameSize2) { |
||||
p->gSynMagn[index] += p->gAnaMagn[k]; |
||||
p->gSynFreq[index] = p->gAnaFreq[k] * pitchShift; |
||||
} |
||||
} |
||||
|
||||
for (k = 0; k <= fftFrameSize2; k++) { /* SYNTHESIS */ |
||||
/* get magnitude and true frequency from synthesis arrays */ |
||||
magn = p->gSynMagn[k], tmp = p->gSynFreq[k]; |
||||
tmp -= (double) k *freqPerBin; /* subtract bin mid frequency */ |
||||
tmp /= freqPerBin; /* get bin deviation from freq deviation */ |
||||
tmp = 2. * M_PI * tmp / p->ovsamp; /* take p->ovsamp into account */ |
||||
tmp += (double) k *expct; /* add the overlap phase advance back in */ |
||||
p->gSumPhase[k] += tmp; /* accumulate delta phase to get bin phase */ |
||||
phase = p->gSumPhase[k]; |
||||
/* get real and imag part and re-interleave */ |
||||
p->gFFTworksp[2 * k] = magn * cos(phase); |
||||
p->gFFTworksp[2 * k + 1] = - magn * sin(phase); |
||||
} |
||||
|
||||
for (k = p->fftFrameSize + 2; k < 2 * p->fftFrameSize; k++) |
||||
p->gFFTworksp[k] = 0.; /* zero negative frequencies */ |
||||
|
||||
lsx_safe_cdft(2 * p->fftFrameSize, -1, p->gFFTworksp); |
||||
|
||||
/* do windowing and add to output accumulator */ |
||||
for (k = 0; k < p->fftFrameSize; k++) { |
||||
window = |
||||
-.5 * cos(2. * M_PI * (double) k / (double) p->fftFrameSize) + .5; |
||||
p->gOutputAccum[k] += |
||||
2. * window * p->gFFTworksp[2 * k] / (fftFrameSize2 * p->ovsamp); |
||||
} |
||||
for (k = 0; k < stepSize; k++) |
||||
p->gOutFIFO[k] = p->gOutputAccum[k]; |
||||
|
||||
memmove(p->gOutputAccum, /* shift accumulator */ |
||||
p->gOutputAccum + stepSize, p->fftFrameSize * sizeof(float)); |
||||
|
||||
for (k = 0; k < inFifoLatency; k++) /* move input FIFO */ |
||||
p->gInFIFO[k] = p->gInFIFO[k + stepSize]; |
||||
} |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t *p = (priv_t *) effp->priv; |
||||
|
||||
if (p->bends_pos != p->nbends) |
||||
lsx_warn("Input audio too short; bends not applied: %u", |
||||
p->nbends - p->bends_pos); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int lsx_kill(sox_effect_t * effp) |
||||
{ |
||||
priv_t *p = (priv_t *) effp->priv; |
||||
unsigned i; |
||||
|
||||
for (i = 0; i < p->nbends; ++i) |
||||
free(p->bends[i].str); |
||||
free(p->bends); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const *lsx_bend_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"bend", "[-f frame-rate(25)] [-o over-sample(16)] {start,cents,end}", |
||||
0, create, start, flow, 0, stop, lsx_kill, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,178 +0,0 @@ |
||||
/* libSoX Biquad filter common functions (c) 2006-7 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "biquad.h" |
||||
#include <string.h> |
||||
|
||||
typedef biquad_t priv_t; |
||||
|
||||
static char const * const width_str[] = { |
||||
"band-width(Hz)", |
||||
"band-width(kHz)", |
||||
"band-width(Hz, no warp)", /* deprecated */ |
||||
"band-width(octaves)", |
||||
"Q", |
||||
"slope", |
||||
}; |
||||
static char const all_width_types[] = "hkboqs"; |
||||
|
||||
|
||||
int lsx_biquad_getopts(sox_effect_t * effp, int argc, char **argv, |
||||
int min_args, int max_args, int fc_pos, int width_pos, int gain_pos, |
||||
char const * allowed_width_types, filter_t filter_type) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
char width_type = *allowed_width_types; |
||||
char dummy, * dummy_p; /* To check for extraneous chars. */ |
||||
--argc, ++argv; |
||||
|
||||
p->filter_type = filter_type; |
||||
if (argc < min_args || argc > max_args || |
||||
(argc > fc_pos && ((p->fc = lsx_parse_frequency(argv[fc_pos], &dummy_p)) <= 0 || *dummy_p)) || |
||||
(argc > width_pos && ((unsigned)(sscanf(argv[width_pos], "%lf%c %c", &p->width, &width_type, &dummy)-1) > 1 || p->width <= 0)) || |
||||
(argc > gain_pos && sscanf(argv[gain_pos], "%lf %c", &p->gain, &dummy) != 1) || |
||||
!strchr(allowed_width_types, width_type) || (width_type == 's' && p->width > 1)) |
||||
return lsx_usage(effp); |
||||
p->width_type = strchr(all_width_types, width_type) - all_width_types; |
||||
if ((size_t)p->width_type >= strlen(all_width_types)) |
||||
p->width_type = 0; |
||||
if (p->width_type == width_bw_kHz) { |
||||
p->width *= 1000; |
||||
p->width_type = width_bw_Hz; |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
/* Simplify: */ |
||||
p->b2 /= p->a0; |
||||
p->b1 /= p->a0; |
||||
p->b0 /= p->a0; |
||||
p->a2 /= p->a0; |
||||
p->a1 /= p->a0; |
||||
|
||||
p->o2 = p->o1 = p->i2 = p->i1 = 0; |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
|
||||
int lsx_biquad_start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
|
||||
start(effp); |
||||
|
||||
if (effp->global_info->plot == sox_plot_octave) { |
||||
printf( |
||||
"%% GNU Octave file (may also work with MATLAB(R) )\n" |
||||
"Fs=%g;minF=10;maxF=Fs/2;\n" |
||||
"sweepF=logspace(log10(minF),log10(maxF),200);\n" |
||||
"[h,w]=freqz([%.15e %.15e %.15e],[1 %.15e %.15e],sweepF,Fs);\n" |
||||
"semilogx(w,20*log10(h))\n" |
||||
"title('SoX effect: %s gain=%g frequency=%g %s=%g (rate=%g)')\n" |
||||
"xlabel('Frequency (Hz)')\n" |
||||
"ylabel('Amplitude Response (dB)')\n" |
||||
"axis([minF maxF -35 25])\n" |
||||
"grid on\n" |
||||
"disp('Hit return to continue')\n" |
||||
"pause\n" |
||||
, effp->in_signal.rate, p->b0, p->b1, p->b2, p->a1, p->a2 |
||||
, effp->handler.name, p->gain, p->fc, width_str[p->width_type], p->width |
||||
, effp->in_signal.rate); |
||||
return SOX_EOF; |
||||
} |
||||
if (effp->global_info->plot == sox_plot_gnuplot) { |
||||
printf( |
||||
"# gnuplot file\n" |
||||
"set title 'SoX effect: %s gain=%g frequency=%g %s=%g (rate=%g)'\n" |
||||
"set xlabel 'Frequency (Hz)'\n" |
||||
"set ylabel 'Amplitude Response (dB)'\n" |
||||
"Fs=%g\n" |
||||
"b0=%.15e; b1=%.15e; b2=%.15e; a1=%.15e; a2=%.15e\n" |
||||
"o=2*pi/Fs\n" |
||||
"H(f)=sqrt((b0*b0+b1*b1+b2*b2+2.*(b0*b1+b1*b2)*cos(f*o)+2.*(b0*b2)*cos(2.*f*o))/(1.+a1*a1+a2*a2+2.*(a1+a1*a2)*cos(f*o)+2.*a2*cos(2.*f*o)))\n" |
||||
"set logscale x\n" |
||||
"set samples 250\n" |
||||
"set grid xtics ytics\n" |
||||
"set key off\n" |
||||
"plot [f=10:Fs/2] [-35:25] 20*log10(H(f))\n" |
||||
"pause -1 'Hit return to continue'\n" |
||||
, effp->handler.name, p->gain, p->fc, width_str[p->width_type], p->width |
||||
, effp->in_signal.rate, effp->in_signal.rate |
||||
, p->b0, p->b1, p->b2, p->a1, p->a2); |
||||
return SOX_EOF; |
||||
} |
||||
if (effp->global_info->plot == sox_plot_data) { |
||||
printf("# SoX effect: %s gain=%g frequency=%g %s=%g (rate=%g)\n" |
||||
"# IIR filter\n" |
||||
"# rate: %g\n" |
||||
"# name: b\n" |
||||
"# type: matrix\n" |
||||
"# rows: 3\n" |
||||
"# columns: 1\n" |
||||
"%24.16e\n%24.16e\n%24.16e\n" |
||||
"# name: a\n" |
||||
"# type: matrix\n" |
||||
"# rows: 3\n" |
||||
"# columns: 1\n" |
||||
"%24.16e\n%24.16e\n%24.16e\n" |
||||
, effp->handler.name, p->gain, p->fc, width_str[p->width_type], p->width |
||||
, effp->in_signal.rate, effp->in_signal.rate |
||||
, p->b0, p->b1, p->b2, 1. /* a0 */, p->a1, p->a2); |
||||
return SOX_EOF; |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
|
||||
int lsx_biquad_flow(sox_effect_t * effp, const sox_sample_t *ibuf, |
||||
sox_sample_t *obuf, size_t *isamp, size_t *osamp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
size_t len = *isamp = *osamp = min(*isamp, *osamp); |
||||
while (len--) { |
||||
double o0 = *ibuf*p->b0 + p->i1*p->b1 + p->i2*p->b2 - p->o1*p->a1 - p->o2*p->a2; |
||||
p->i2 = p->i1, p->i1 = *ibuf++; |
||||
p->o2 = p->o1, p->o1 = o0; |
||||
*obuf++ = SOX_ROUND_CLIP_COUNT(o0, effp->clips); |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int create(sox_effect_t * effp, int argc, char * * argv) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
double * d = &p->b0; |
||||
char c; |
||||
|
||||
--argc, ++argv; |
||||
if (argc == 6) |
||||
for (; argc && sscanf(*argv, "%lf%c", d, &c) == 1; --argc, ++argv, ++d); |
||||
return argc? lsx_usage(effp) : SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_biquad_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"biquad", "b0 b1 b2 a0 a1 a2", 0, |
||||
create, lsx_biquad_start, lsx_biquad_flow, NULL, NULL, NULL, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,78 +0,0 @@ |
||||
/* libSoX Biquad filter common definitions (c) 2006-7 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#ifndef biquad_included |
||||
#define biquad_included |
||||
|
||||
#define LSX_EFF_ALIAS |
||||
#include "sox_i.h" |
||||
|
||||
typedef enum { |
||||
filter_LPF, |
||||
filter_HPF, |
||||
filter_BPF_CSG, |
||||
filter_BPF, |
||||
filter_notch, |
||||
filter_APF, |
||||
filter_peakingEQ, |
||||
filter_lowShelf, |
||||
filter_highShelf, |
||||
filter_LPF_1, |
||||
filter_HPF_1, |
||||
filter_BPF_SPK, |
||||
filter_BPF_SPK_N, |
||||
filter_AP1, |
||||
filter_AP2, |
||||
filter_deemph, |
||||
filter_riaa |
||||
} filter_t; |
||||
|
||||
typedef enum { |
||||
width_bw_Hz, |
||||
width_bw_kHz, |
||||
/* The old, non-RBJ, non-freq-warped band-pass/reject response;
|
||||
* leaving here for now just in case anybody misses it: */ |
||||
width_bw_old, |
||||
width_bw_oct, |
||||
width_Q, |
||||
width_slope |
||||
} width_t; |
||||
|
||||
/* Private data for the biquad filter effects */ |
||||
typedef struct { |
||||
double gain; /* For EQ filters */ |
||||
double fc; /* Centre/corner/cutoff frequency */ |
||||
double width; /* Filter width; interpreted as per width_type */ |
||||
width_t width_type; |
||||
|
||||
filter_t filter_type; |
||||
|
||||
double b0, b1, b2; /* Filter coefficients */ |
||||
double a0, a1, a2; /* Filter coefficients */ |
||||
|
||||
sox_sample_t i1, i2; /* Filter memory */ |
||||
double o1, o2; /* Filter memory */ |
||||
} biquad_t; |
||||
|
||||
int lsx_biquad_getopts(sox_effect_t * effp, int n, char **argv, |
||||
int min_args, int max_args, int fc_pos, int width_pos, int gain_pos, |
||||
char const * allowed_width_types, filter_t filter_type); |
||||
int lsx_biquad_start(sox_effect_t * effp); |
||||
int lsx_biquad_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, |
||||
size_t *isamp, size_t *osamp); |
||||
|
||||
#endif |
@ -1,416 +0,0 @@ |
||||
/* libSoX Biquad filter effects (c) 2006-8 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
* |
||||
* |
||||
* 2-pole filters designed by Robert Bristow-Johnson <rbj@audioimagination.com> |
||||
* see https://webaudio.github.io/Audio-EQ-Cookbook/audio-eq-cookbook.html
|
||||
* |
||||
* 1-pole filters based on code (c) 2000 Chris Bagwell <cbagwell@sprynet.com> |
||||
* Algorithms: Recursive single pole low/high pass filter |
||||
* Reference: The Scientist and Engineer's Guide to Digital Signal Processing |
||||
* |
||||
* low-pass: output[N] = input[N] * A + output[N-1] * B |
||||
* X = exp(-2.0 * pi * Fc) |
||||
* A = 1 - X |
||||
* B = X |
||||
* Fc = cutoff freq / sample rate |
||||
* |
||||
* Mimics an RC low-pass filter: |
||||
* |
||||
* ---/\/\/\/\-----------> |
||||
* | |
||||
* --- C |
||||
* --- |
||||
* | |
||||
* | |
||||
* V |
||||
* |
||||
* high-pass: output[N] = A0 * input[N] + A1 * input[N-1] + B1 * output[N-1] |
||||
* X = exp(-2.0 * pi * Fc) |
||||
* A0 = (1 + X) / 2 |
||||
* A1 = -(1 + X) / 2 |
||||
* B1 = X |
||||
* Fc = cutoff freq / sample rate |
||||
* |
||||
* Mimics an RC high-pass filter: |
||||
* |
||||
* || C |
||||
* ----||---------> |
||||
* || | |
||||
* < |
||||
* > R |
||||
* < |
||||
* | |
||||
* V |
||||
*/ |
||||
|
||||
|
||||
#include "biquad.h" |
||||
#include <assert.h> |
||||
#include <string.h> |
||||
|
||||
typedef biquad_t priv_t; |
||||
|
||||
|
||||
static int hilo1_getopts(sox_effect_t * effp, int argc, char **argv) { |
||||
return lsx_biquad_getopts(effp, argc, argv, 1, 1, 0, 1, 2, "", |
||||
*effp->handler.name == 'l'? filter_LPF_1 : filter_HPF_1); |
||||
} |
||||
|
||||
|
||||
static int hilo2_getopts(sox_effect_t * effp, int argc, char **argv) { |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
if (argc > 1 && strcmp(argv[1], "-1") == 0) |
||||
return hilo1_getopts(effp, argc - 1, argv + 1); |
||||
if (argc > 1 && strcmp(argv[1], "-2") == 0) |
||||
++argv, --argc; |
||||
p->width = sqrt(0.5); /* Default to Butterworth */ |
||||
return lsx_biquad_getopts(effp, argc, argv, 1, 2, 0, 1, 2, "qohk", |
||||
*effp->handler.name == 'l'? filter_LPF : filter_HPF); |
||||
} |
||||
|
||||
|
||||
static int bandpass_getopts(sox_effect_t * effp, int argc, char **argv) { |
||||
filter_t type = filter_BPF; |
||||
if (argc > 1 && strcmp(argv[1], "-c") == 0) |
||||
++argv, --argc, type = filter_BPF_CSG; |
||||
return lsx_biquad_getopts(effp, argc, argv, 2, 2, 0, 1, 2, "hkqob", type); |
||||
} |
||||
|
||||
|
||||
static int bandrej_getopts(sox_effect_t * effp, int argc, char **argv) { |
||||
return lsx_biquad_getopts(effp, argc, argv, 2, 2, 0, 1, 2, "hkqob", filter_notch); |
||||
} |
||||
|
||||
|
||||
static int allpass_getopts(sox_effect_t * effp, int argc, char **argv) { |
||||
filter_t type = filter_APF; |
||||
int m; |
||||
if (argc > 1 && strcmp(argv[1], "-1") == 0) |
||||
++argv, --argc, type = filter_AP1; |
||||
else if (argc > 1 && strcmp(argv[1], "-2") == 0) |
||||
++argv, --argc, type = filter_AP2; |
||||
m = 1 + (type == filter_APF); |
||||
return lsx_biquad_getopts(effp, argc, argv, m, m, 0, 1, 2, "hkqo", type); |
||||
} |
||||
|
||||
|
||||
static int tone_getopts(sox_effect_t * effp, int argc, char **argv) { |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
p->width = 0.5; |
||||
p->fc = *effp->handler.name == 'b'? 100 : 3000; |
||||
return lsx_biquad_getopts(effp, argc, argv, 1, 3, 1, 2, 0, "shkqo", |
||||
*effp->handler.name == 'b'? filter_lowShelf: filter_highShelf); |
||||
} |
||||
|
||||
|
||||
static int equalizer_getopts(sox_effect_t * effp, int argc, char **argv) { |
||||
return lsx_biquad_getopts(effp, argc, argv, 3, 3, 0, 1, 2, "qohk", filter_peakingEQ); |
||||
} |
||||
|
||||
|
||||
static int band_getopts(sox_effect_t * effp, int argc, char **argv) { |
||||
filter_t type = filter_BPF_SPK; |
||||
if (argc > 1 && strcmp(argv[1], "-n") == 0) |
||||
++argv, --argc, type = filter_BPF_SPK_N; |
||||
return lsx_biquad_getopts(effp, argc, argv, 1, 2, 0, 1, 2, "hkqo", type); |
||||
} |
||||
|
||||
|
||||
static int deemph_getopts(sox_effect_t * effp, int argc, char **argv) { |
||||
return lsx_biquad_getopts(effp, argc, argv, 0, 0, 0, 1, 2, "s", filter_deemph); |
||||
} |
||||
|
||||
|
||||
static int riaa_getopts(sox_effect_t * effp, int argc, char **argv) { |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
p->filter_type = filter_riaa; |
||||
(void)argv; |
||||
return --argc? lsx_usage(effp) : SOX_SUCCESS; |
||||
} |
||||
|
||||
|
||||
static void make_poly_from_roots( |
||||
double const * roots, size_t num_roots, double * poly) |
||||
{ |
||||
size_t i, j; |
||||
poly[0] = 1; |
||||
poly[1] = -roots[0]; |
||||
memset(poly + 2, 0, (num_roots + 1 - 2) * sizeof(*poly)); |
||||
for (i = 1; i < num_roots; ++i) |
||||
for (j = num_roots; j > 0; --j) |
||||
poly[j] -= poly[j - 1] * roots[i]; |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
double w0, A, alpha, mult; |
||||
|
||||
if (p->filter_type == filter_deemph) { /* See deemph.plt for documentation */ |
||||
if (effp->in_signal.rate == 44100) { |
||||
p->fc = 5283; |
||||
p->width = 0.4845; |
||||
p->gain = -9.477; |
||||
} |
||||
else if (effp->in_signal.rate == 48000) { |
||||
p->fc = 5356; |
||||
p->width = 0.479; |
||||
p->gain = -9.62; |
||||
} |
||||
else { |
||||
lsx_fail("sample rate must be 44100 (audio-CD) or 48000 (DAT)"); |
||||
return SOX_EOF; |
||||
} |
||||
} |
||||
|
||||
w0 = 2 * M_PI * p->fc / effp->in_signal.rate; |
||||
A = exp(p->gain / 40 * log(10.)); |
||||
alpha = 0, mult = dB_to_linear(max(p->gain, 0)); |
||||
|
||||
if (w0 > M_PI) { |
||||
lsx_fail("frequency must be less than half the sample-rate (Nyquist rate)"); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
/* Set defaults: */ |
||||
p->b0 = p->b1 = p->b2 = p->a1 = p->a2 = 0; |
||||
p->a0 = 1; |
||||
|
||||
if (p->width) switch (p->width_type) { |
||||
case width_slope: |
||||
alpha = sin(w0)/2 * sqrt((A + 1/A)*(1/p->width - 1) + 2); |
||||
break; |
||||
|
||||
case width_Q: |
||||
alpha = sin(w0)/(2*p->width); |
||||
break; |
||||
|
||||
case width_bw_oct: |
||||
alpha = sin(w0)*sinh(log(2.)/2 * p->width * w0/sin(w0)); |
||||
break; |
||||
|
||||
case width_bw_Hz: |
||||
alpha = sin(w0)/(2*p->fc/p->width); |
||||
break; |
||||
|
||||
case width_bw_kHz: assert(0); /* Shouldn't get here */ |
||||
|
||||
case width_bw_old: |
||||
alpha = tan(M_PI * p->width / effp->in_signal.rate); |
||||
break; |
||||
} |
||||
switch (p->filter_type) { |
||||
case filter_LPF: /* H(s) = 1 / (s^2 + s/Q + 1) */ |
||||
p->b0 = (1 - cos(w0))/2; |
||||
p->b1 = 1 - cos(w0); |
||||
p->b2 = (1 - cos(w0))/2; |
||||
p->a0 = 1 + alpha; |
||||
p->a1 = -2*cos(w0); |
||||
p->a2 = 1 - alpha; |
||||
break; |
||||
|
||||
case filter_HPF: /* H(s) = s^2 / (s^2 + s/Q + 1) */ |
||||
p->b0 = (1 + cos(w0))/2; |
||||
p->b1 = -(1 + cos(w0)); |
||||
p->b2 = (1 + cos(w0))/2; |
||||
p->a0 = 1 + alpha; |
||||
p->a1 = -2*cos(w0); |
||||
p->a2 = 1 - alpha; |
||||
break; |
||||
|
||||
case filter_BPF_CSG: /* H(s) = s / (s^2 + s/Q + 1) (constant skirt gain, peak gain = Q) */ |
||||
p->b0 = sin(w0)/2; |
||||
p->b1 = 0; |
||||
p->b2 = -sin(w0)/2; |
||||
p->a0 = 1 + alpha; |
||||
p->a1 = -2*cos(w0); |
||||
p->a2 = 1 - alpha; |
||||
break; |
||||
|
||||
case filter_BPF: /* H(s) = (s/Q) / (s^2 + s/Q + 1) (constant 0 dB peak gain) */ |
||||
p->b0 = alpha; |
||||
p->b1 = 0; |
||||
p->b2 = -alpha; |
||||
p->a0 = 1 + alpha; |
||||
p->a1 = -2*cos(w0); |
||||
p->a2 = 1 - alpha; |
||||
break; |
||||
|
||||
case filter_notch: /* H(s) = (s^2 + 1) / (s^2 + s/Q + 1) */ |
||||
p->b0 = 1; |
||||
p->b1 = -2*cos(w0); |
||||
p->b2 = 1; |
||||
p->a0 = 1 + alpha; |
||||
p->a1 = -2*cos(w0); |
||||
p->a2 = 1 - alpha; |
||||
break; |
||||
|
||||
case filter_APF: /* H(s) = (s^2 - s/Q + 1) / (s^2 + s/Q + 1) */ |
||||
p->b0 = 1 - alpha; |
||||
p->b1 = -2*cos(w0); |
||||
p->b2 = 1 + alpha; |
||||
p->a0 = 1 + alpha; |
||||
p->a1 = -2*cos(w0); |
||||
p->a2 = 1 - alpha; |
||||
break; |
||||
|
||||
case filter_peakingEQ: /* H(s) = (s^2 + s*(A/Q) + 1) / (s^2 + s/(A*Q) + 1) */ |
||||
if (A == 1) |
||||
return SOX_EFF_NULL; |
||||
p->b0 = 1 + alpha*A; |
||||
p->b1 = -2*cos(w0); |
||||
p->b2 = 1 - alpha*A; |
||||
p->a0 = 1 + alpha/A; |
||||
p->a1 = -2*cos(w0); |
||||
p->a2 = 1 - alpha/A; |
||||
break; |
||||
|
||||
case filter_lowShelf: /* H(s) = A * (s^2 + (sqrt(A)/Q)*s + A)/(A*s^2 + (sqrt(A)/Q)*s + 1) */ |
||||
if (A == 1) |
||||
return SOX_EFF_NULL; |
||||
p->b0 = A*( (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha ); |
||||
p->b1 = 2*A*( (A-1) - (A+1)*cos(w0) ); |
||||
p->b2 = A*( (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha ); |
||||
p->a0 = (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha; |
||||
p->a1 = -2*( (A-1) + (A+1)*cos(w0) ); |
||||
p->a2 = (A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha; |
||||
break; |
||||
|
||||
case filter_deemph: /* Falls through to high-shelf... */ |
||||
|
||||
case filter_highShelf: /* H(s) = A * (A*s^2 + (sqrt(A)/Q)*s + 1)/(s^2 + (sqrt(A)/Q)*s + A) */ |
||||
if (!A) |
||||
return SOX_EFF_NULL; |
||||
p->b0 = A*( (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha ); |
||||
p->b1 = -2*A*( (A-1) + (A+1)*cos(w0) ); |
||||
p->b2 = A*( (A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha ); |
||||
p->a0 = (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha; |
||||
p->a1 = 2*( (A-1) - (A+1)*cos(w0) ); |
||||
p->a2 = (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha; |
||||
break; |
||||
|
||||
case filter_LPF_1: /* single-pole */ |
||||
p->a1 = -exp(-w0); |
||||
p->b0 = 1 + p->a1; |
||||
break; |
||||
|
||||
case filter_HPF_1: /* single-pole */ |
||||
p->a1 = -exp(-w0); |
||||
p->b0 = (1 - p->a1)/2; |
||||
p->b1 = -p->b0; |
||||
break; |
||||
|
||||
case filter_BPF_SPK: case filter_BPF_SPK_N: { |
||||
double bw_Hz; |
||||
if (!p->width) |
||||
p->width = p->fc / 2; |
||||
bw_Hz = p->width_type == width_Q? p->fc / p->width : |
||||
p->width_type == width_bw_Hz? p->width : |
||||
p->fc * (pow(2., p->width) - 1) * pow(2., -0.5 * p->width); /* bw_oct */ |
||||
#include "band.h" /* Has different licence */ |
||||
break; |
||||
} |
||||
|
||||
case filter_AP1: /* Experimental 1-pole all-pass from Tom Erbe @ UCSD */ |
||||
p->b0 = exp(-w0); |
||||
p->b1 = -1; |
||||
p->a1 = -exp(-w0); |
||||
break; |
||||
|
||||
case filter_AP2: /* Experimental 2-pole all-pass from Tom Erbe @ UCSD */ |
||||
p->b0 = 1 - sin(w0); |
||||
p->b1 = -2 * cos(w0); |
||||
p->b2 = 1 + sin(w0); |
||||
p->a0 = 1 + sin(w0); |
||||
p->a1 = -2 * cos(w0); |
||||
p->a2 = 1 - sin(w0); |
||||
break; |
||||
|
||||
case filter_riaa: /* http://www.dsprelated.com/showmessage/73300/3.php */ |
||||
if (effp->in_signal.rate == 44100) { |
||||
static const double zeros[] = {-0.2014898, 0.9233820}; |
||||
static const double poles[] = {0.7083149, 0.9924091}; |
||||
make_poly_from_roots(zeros, (size_t)2, &p->b0); |
||||
make_poly_from_roots(poles, (size_t)2, &p->a0); |
||||
} |
||||
else if (effp->in_signal.rate == 48000) { |
||||
static const double zeros[] = {-0.1766069, 0.9321590}; |
||||
static const double poles[] = {0.7396325, 0.9931330}; |
||||
make_poly_from_roots(zeros, (size_t)2, &p->b0); |
||||
make_poly_from_roots(poles, (size_t)2, &p->a0); |
||||
} |
||||
else if (effp->in_signal.rate == 88200) { |
||||
static const double zeros[] = {-0.1168735, 0.9648312}; |
||||
static const double poles[] = {0.8590646, 0.9964002}; |
||||
make_poly_from_roots(zeros, (size_t)2, &p->b0); |
||||
make_poly_from_roots(poles, (size_t)2, &p->a0); |
||||
} |
||||
else if (effp->in_signal.rate == 96000) { |
||||
static const double zeros[] = {-0.1141486, 0.9676817}; |
||||
static const double poles[] = {0.8699137, 0.9966946}; |
||||
make_poly_from_roots(zeros, (size_t)2, &p->b0); |
||||
make_poly_from_roots(poles, (size_t)2, &p->a0); |
||||
} |
||||
else if (effp->in_signal.rate == 192000) { |
||||
static const double zeros[] = {-0.1040610965, 0.9837523263}; |
||||
static const double poles[] = {0.9328992971, 0.9983633125}; |
||||
make_poly_from_roots(zeros, (size_t)2, &p->b0); |
||||
make_poly_from_roots(poles, (size_t)2, &p->a0); |
||||
} |
||||
else { |
||||
lsx_fail("Sample rate must be 44.1k, 48k, 88.2k, 96k, or 192k"); |
||||
return SOX_EOF; |
||||
} |
||||
{ /* Normalise to 0dB at 1kHz (Thanks to Glenn Davis) */ |
||||
double y = 2 * M_PI * 1000 / effp->in_signal.rate; |
||||
double b_re = p->b0 + p->b1 * cos(-y) + p->b2 * cos(-2 * y); |
||||
double a_re = p->a0 + p->a1 * cos(-y) + p->a2 * cos(-2 * y); |
||||
double b_im = p->b1 * sin(-y) + p->b2 * sin(-2 * y); |
||||
double a_im = p->a1 * sin(-y) + p->a2 * sin(-2 * y); |
||||
double g = 1 / sqrt((sqr(b_re) + sqr(b_im)) / (sqr(a_re) + sqr(a_im))); |
||||
p->b0 *= g; p->b1 *= g; p->b2 *= g; |
||||
} |
||||
mult = (p->b0 + p->b1 + p->b2) / (p->a0 + p->a1 + p->a2); |
||||
lsx_debug("gain=%f", linear_to_dB(mult)); |
||||
break; |
||||
} |
||||
if (effp->in_signal.mult) |
||||
*effp->in_signal.mult /= mult; |
||||
return lsx_biquad_start(effp); |
||||
} |
||||
|
||||
|
||||
#define BIQUAD_EFFECT(name,group,usage,flags) \ |
||||
sox_effect_handler_t const * lsx_##name##_effect_fn(void) { \
|
||||
static sox_effect_handler_t handler = { \
|
||||
#name, usage, flags, \ |
||||
group##_getopts, start, lsx_biquad_flow, 0, 0, 0, sizeof(biquad_t)\
|
||||
}; \
|
||||
return &handler; \
|
||||
} |
||||
|
||||
BIQUAD_EFFECT(highpass, hilo2, "[-1|-2] frequency [width[q|o|h|k](0.707q)]", 0) |
||||
BIQUAD_EFFECT(lowpass, hilo2, "[-1|-2] frequency [width[q|o|h|k]](0.707q)", 0) |
||||
BIQUAD_EFFECT(bandpass, bandpass, "[-c] frequency width[h|k|q|o]", 0) |
||||
BIQUAD_EFFECT(bandreject,bandrej, "frequency width[h|k|q|o]", 0) |
||||
BIQUAD_EFFECT(allpass, allpass, "frequency width[h|k|q|o]", 0) |
||||
BIQUAD_EFFECT(bass, tone, "gain [frequency(100) [width[s|h|k|q|o]](0.5s)]", 0) |
||||
BIQUAD_EFFECT(treble, tone, "gain [frequency(3000) [width[s|h|k|q|o]](0.5s)]", 0) |
||||
BIQUAD_EFFECT(equalizer, equalizer,"frequency width[q|o|h|k] gain", 0) |
||||
BIQUAD_EFFECT(band, band, "[-n] center [width[h|k|q|o]]", 0) |
||||
BIQUAD_EFFECT(deemph, deemph, NULL, 0) |
||||
BIQUAD_EFFECT(riaa, riaa, NULL, 0) |
@ -1,273 +0,0 @@ |
||||
#ifndef HAVE_COREAUDIO |
||||
/*
|
||||
* SoX bit-rot detection file; cobbled together |
||||
*/ |
||||
|
||||
enum { |
||||
kAudioHardwarePropertyProcessIsMaster, |
||||
kAudioHardwarePropertyIsInitingOrExiting, |
||||
kAudioHardwarePropertyDevices, |
||||
kAudioHardwarePropertyDefaultInputDevice, |
||||
kAudioHardwarePropertyDefaultOutputDevice, |
||||
kAudioHardwarePropertyDefaultSystemOutputDevice, |
||||
kAudioHardwarePropertyDeviceForUID, |
||||
kAudioHardwarePropertySleepingIsAllowed, |
||||
kAudioHardwarePropertyUnloadingIsAllowed, |
||||
kAudioHardwarePropertyHogModeIsAllowed, |
||||
kAudioHardwarePropertyRunLoop, |
||||
kAudioHardwarePropertyPlugInForBundleID |
||||
}; |
||||
|
||||
enum { |
||||
kAudioObjectPropertyClass, |
||||
kAudioObjectPropertyOwner, |
||||
kAudioObjectPropertyCreator, |
||||
kAudioObjectPropertyName, |
||||
kAudioObjectPropertyManufacturer, |
||||
kAudioObjectPropertyElementName, |
||||
kAudioObjectPropertyElementCategoryName, |
||||
kAudioObjectPropertyElementNumberName, |
||||
kAudioObjectPropertyOwnedObjects, |
||||
kAudioObjectPropertyListenerAdded, |
||||
kAudioObjectPropertyListenerRemoved |
||||
}; |
||||
|
||||
enum { |
||||
kAudioDevicePropertyDeviceName, |
||||
kAudioDevicePropertyDeviceNameCFString = kAudioObjectPropertyName, |
||||
kAudioDevicePropertyDeviceManufacturer, |
||||
kAudioDevicePropertyDeviceManufacturerCFString = |
||||
kAudioObjectPropertyManufacturer, |
||||
kAudioDevicePropertyRegisterBufferList, |
||||
kAudioDevicePropertyBufferSize, |
||||
kAudioDevicePropertyBufferSizeRange, |
||||
kAudioDevicePropertyChannelName, |
||||
kAudioDevicePropertyChannelNameCFString = kAudioObjectPropertyElementName, |
||||
kAudioDevicePropertyChannelCategoryName, |
||||
kAudioDevicePropertyChannelCategoryNameCFString = |
||||
kAudioObjectPropertyElementCategoryName, |
||||
kAudioDevicePropertyChannelNumberName, |
||||
kAudioDevicePropertyChannelNumberNameCFString = |
||||
kAudioObjectPropertyElementNumberName, |
||||
kAudioDevicePropertySupportsMixing, |
||||
kAudioDevicePropertyStreamFormat, |
||||
kAudioDevicePropertyStreamFormats, |
||||
kAudioDevicePropertyStreamFormatSupported, |
||||
kAudioDevicePropertyStreamFormatMatch, |
||||
kAudioDevicePropertyDataSourceNameForID, |
||||
kAudioDevicePropertyClockSourceNameForID, |
||||
kAudioDevicePropertyPlayThruDestinationNameForID, |
||||
kAudioDevicePropertyChannelNominalLineLevelNameForID |
||||
}; |
||||
|
||||
enum { |
||||
kAudioDevicePropertyPlugIn, |
||||
kAudioDevicePropertyConfigurationApplication, |
||||
kAudioDevicePropertyDeviceUID, |
||||
kAudioDevicePropertyModelUID, |
||||
kAudioDevicePropertyTransportType, |
||||
kAudioDevicePropertyRelatedDevices, |
||||
kAudioDevicePropertyClockDomain, |
||||
kAudioDevicePropertyDeviceIsAlive, |
||||
kAudioDevicePropertyDeviceHasChanged, |
||||
kAudioDevicePropertyDeviceIsRunning, |
||||
kAudioDevicePropertyDeviceIsRunningSomewhere, |
||||
kAudioDevicePropertyDeviceCanBeDefaultDevice, |
||||
kAudioDevicePropertyDeviceCanBeDefaultSystemDevice, |
||||
kAudioDeviceProcessorOverload, |
||||
kAudioDevicePropertyHogMode, |
||||
kAudioDevicePropertyLatency, |
||||
kAudioDevicePropertyBufferFrameSize, |
||||
kAudioDevicePropertyBufferFrameSizeRange, |
||||
kAudioDevicePropertyUsesVariableBufferFrameSizes, |
||||
kAudioDevicePropertyStreams, |
||||
kAudioDevicePropertySafetyOffset, |
||||
kAudioDevicePropertyIOCycleUsage, |
||||
kAudioDevicePropertyStreamConfiguration, |
||||
kAudioDevicePropertyIOProcStreamUsage, |
||||
kAudioDevicePropertyPreferredChannelsForStereo, |
||||
kAudioDevicePropertyPreferredChannelLayout, |
||||
kAudioDevicePropertyNominalSampleRate, |
||||
kAudioDevicePropertyAvailableNominalSampleRates, |
||||
kAudioDevicePropertyActualSampleRate |
||||
}; |
||||
|
||||
enum { |
||||
kAudioFormatLinearPCM, |
||||
kAudioFormatAC3, |
||||
kAudioFormat60958AC3, |
||||
kAudioFormatAppleIMA4, |
||||
kAudioFormatMPEG4AAC, |
||||
kAudioFormatMPEG4CELP, |
||||
kAudioFormatMPEG4HVXC, |
||||
kAudioFormatMPEG4TwinVQ, |
||||
kAudioFormatMACE3, |
||||
kAudioFormatMACE6, |
||||
kAudioFormatULaw, |
||||
kAudioFormatALaw, |
||||
kAudioFormatQDesign, |
||||
kAudioFormatQDesign2, |
||||
kAudioFormatQUALCOMM, |
||||
kAudioFormatMPEGLayer1, |
||||
kAudioFormatMPEGLayer2, |
||||
kAudioFormatMPEGLayer3, |
||||
kAudioFormatDVAudio, |
||||
kAudioFormatVariableDurationDVAudio, |
||||
kAudioFormatTimeCode, |
||||
kAudioFormatMIDIStream, |
||||
kAudioFormatParameterValueStream, |
||||
kAudioFormatAppleLossless |
||||
}; |
||||
|
||||
enum { |
||||
kAudioFormatFlagIsFloat = (1L << 0), |
||||
kAudioFormatFlagIsBigEndian = (1L << 1), |
||||
kAudioFormatFlagIsSignedInteger = (1L << 2), |
||||
kAudioFormatFlagIsPacked = (1L << 3), |
||||
kAudioFormatFlagIsAlignedHigh = (1L << 4), |
||||
kAudioFormatFlagIsNonInterleaved = (1L << 5), |
||||
kAudioFormatFlagIsNonMixable = (1L << 6), |
||||
|
||||
kLinearPCMFormatFlagIsFloat = kAudioFormatFlagIsFloat, |
||||
kLinearPCMFormatFlagIsBigEndian = kAudioFormatFlagIsBigEndian, |
||||
kLinearPCMFormatFlagIsSignedInteger = kAudioFormatFlagIsSignedInteger, |
||||
kLinearPCMFormatFlagIsPacked = kAudioFormatFlagIsPacked, |
||||
kLinearPCMFormatFlagIsAlignedHigh = kAudioFormatFlagIsAlignedHigh, |
||||
kLinearPCMFormatFlagIsNonInterleaved = kAudioFormatFlagIsNonInterleaved, |
||||
kLinearPCMFormatFlagIsNonMixable = kAudioFormatFlagIsNonMixable, |
||||
|
||||
kAppleLosslessFormatFlag_16BitSourceData = 1, |
||||
kAppleLosslessFormatFlag_20BitSourceData = 2, |
||||
kAppleLosslessFormatFlag_24BitSourceData = 3, |
||||
kAppleLosslessFormatFlag_32BitSourceData = 4 |
||||
}; |
||||
|
||||
enum { |
||||
kAudioFormatFlagsNativeEndian = kAudioFormatFlagIsBigEndian, |
||||
kAudioFormatFlagsNativeFloatPacked = |
||||
kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | |
||||
kAudioFormatFlagIsPacked |
||||
}; |
||||
|
||||
enum { |
||||
kAudioDeviceUnknown |
||||
}; |
||||
|
||||
enum { |
||||
kVariableLengthArray = 1 |
||||
}; |
||||
|
||||
enum { |
||||
kAudioHardwareNoError = 0, |
||||
noErr = kAudioHardwareNoError |
||||
}; |
||||
|
||||
enum { |
||||
false |
||||
}; |
||||
|
||||
typedef double Float64; |
||||
typedef float Float32; |
||||
typedef int SInt32; |
||||
typedef int Boolean; |
||||
typedef int OSErr; |
||||
typedef short SInt16; |
||||
typedef unsigned int UInt32; |
||||
typedef unsigned long int UInt64; |
||||
|
||||
typedef SInt32 OSStatus; |
||||
typedef UInt32 AudioObjectID; |
||||
typedef UInt32 AudioHardwarePropertyID; |
||||
typedef UInt32 AudioDevicePropertyID; |
||||
typedef AudioObjectID AudioDeviceID; |
||||
|
||||
struct AudioStreamBasicDescription { |
||||
Float64 mSampleRate; |
||||
UInt32 mFormatID; |
||||
UInt32 mFormatFlags; |
||||
UInt32 mBytesPerPacket; |
||||
UInt32 mFramesPerPacket; |
||||
UInt32 mBytesPerFrame; |
||||
UInt32 mChannelsPerFrame; |
||||
UInt32 mBitsPerChannel; |
||||
UInt32 mReserved; |
||||
}; |
||||
typedef struct AudioStreamBasicDescription AudioStreamBasicDescription; |
||||
|
||||
|
||||
|
||||
struct SMPTETime { |
||||
SInt16 mSubframes; |
||||
SInt16 mSubframeDivisor; |
||||
UInt32 mCounter; |
||||
UInt32 mType; |
||||
UInt32 mFlags; |
||||
SInt16 mHours; |
||||
SInt16 mMinutes; |
||||
SInt16 mSeconds; |
||||
SInt16 mFrames; |
||||
}; |
||||
typedef struct SMPTETime SMPTETime; |
||||
|
||||
struct AudioTimeStamp { |
||||
Float64 mSampleTime; |
||||
UInt64 mHostTime; |
||||
Float64 mRateScalar; |
||||
UInt64 mWordClockTime; |
||||
SMPTETime mSMPTETime; |
||||
UInt32 mFlags; |
||||
UInt32 mReserved; |
||||
}; |
||||
typedef struct AudioTimeStamp AudioTimeStamp; |
||||
|
||||
struct AudioBuffer { |
||||
UInt32 mNumberChannels; |
||||
UInt32 mDataByteSize; |
||||
void *mData; |
||||
}; |
||||
typedef struct AudioBuffer AudioBuffer; |
||||
|
||||
struct AudioBufferList { |
||||
UInt32 mNumberBuffers; |
||||
AudioBuffer mBuffers[kVariableLengthArray]; |
||||
}; |
||||
typedef struct AudioBufferList AudioBufferList; |
||||
|
||||
typedef OSStatus(*AudioDeviceIOProc) (AudioDeviceID inDevice, |
||||
const AudioTimeStamp * inNow, |
||||
const AudioBufferList * inInputData, |
||||
const AudioTimeStamp * inInputTime, |
||||
AudioBufferList * outOutputData, |
||||
const AudioTimeStamp * inOutputTime, |
||||
void *inClientData); |
||||
|
||||
|
||||
|
||||
OSStatus AudioHardwareGetProperty(AudioHardwarePropertyID inPropertyID, |
||||
UInt32 * ioPropertyDataSize, |
||||
void *outPropertyData); |
||||
|
||||
OSStatus AudioHardwareGetPropertyInfo(AudioHardwarePropertyID inPropertyID, |
||||
UInt32 * ioPropertyDataSize, |
||||
void *outPropertyData); |
||||
|
||||
OSStatus AudioDeviceSetProperty(AudioDeviceID inDevice, |
||||
const AudioTimeStamp * inWhen, |
||||
UInt32 inChannel, Boolean isInput, |
||||
AudioDevicePropertyID inPropertyID, |
||||
UInt32 inPropertyDataSize, |
||||
const void *inPropertyData); |
||||
OSStatus AudioDeviceGetProperty(AudioDeviceID inDevice, UInt32 inChannel, |
||||
Boolean isInput, |
||||
AudioDevicePropertyID inPropertyID, |
||||
UInt32 * ioPropertyDataSize, |
||||
void *outPropertyData); |
||||
|
||||
|
||||
OSStatus AudioDeviceAddIOProc(AudioDeviceID inDevice, |
||||
AudioDeviceIOProc inProc, void *inClientData); |
||||
OSStatus AudioDeviceStart(AudioDeviceID inDevice, AudioDeviceIOProc inProc); |
||||
|
||||
|
||||
OSStatus AudioDeviceStop(AudioDeviceID inDevice, AudioDeviceIOProc inProc); |
||||
#endif |
@ -1,35 +0,0 @@ |
||||
/* libSoX file format: CAF Copyright (c) 2008 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
LSX_FORMAT_HANDLER(caf) |
||||
{ |
||||
static char const * const names[] = {"caf", NULL}; |
||||
static unsigned const write_encodings[] = { |
||||
SOX_ENCODING_SIGN2, 16, 24, 32, 8, 0, |
||||
SOX_ENCODING_FLOAT, 32, 64, 0, |
||||
SOX_ENCODING_ALAW, 8, 0, |
||||
SOX_ENCODING_ULAW, 8, 0, |
||||
0}; |
||||
static sox_format_handler_t handler; |
||||
handler = *lsx_sndfile_format_fn(); |
||||
handler.description = "Apples's Core Audio Format"; |
||||
handler.names = names; |
||||
handler.write_formats = write_encodings; |
||||
return &handler; |
||||
} |
@ -1,351 +0,0 @@ |
||||
/* August 24, 1998
|
||||
* Copyright (C) 1998 Juergen Mueller And Sundry Contributors |
||||
* This source code is freely redistributable and may be used for |
||||
* any purpose. This copyright notice must be maintained. |
||||
* Juergen Mueller And Sundry Contributors are not responsible for |
||||
* the consequences of using this software. |
||||
*/ |
||||
|
||||
/*
|
||||
* Chorus effect. |
||||
* |
||||
* Flow diagram scheme for n delays ( 1 <= n <= MAX_CHORUS ): |
||||
* |
||||
* * gain-in ___ |
||||
* ibuff -----+--------------------------------------------->| | |
||||
* | _________ | | |
||||
* | | | * decay 1 | | |
||||
* +---->| delay 1 |----------------------------->| | |
||||
* | |_________| | | |
||||
* | /|\ | | |
||||
* : | | | |
||||
* : +-----------------+ +--------------+ | + | |
||||
* : | Delay control 1 |<--| mod. speed 1 | | | |
||||
* : +-----------------+ +--------------+ | | |
||||
* | _________ | | |
||||
* | | | * decay n | | |
||||
* +---->| delay n |----------------------------->| | |
||||
* |_________| | | |
||||
* /|\ |___| |
||||
* | | |
||||
* +-----------------+ +--------------+ | * gain-out |
||||
* | Delay control n |<--| mod. speed n | | |
||||
* +-----------------+ +--------------+ +----->obuff |
||||
* |
||||
* |
||||
* The delay i is controled by a sine or triangle modulation i ( 1 <= i <= n). |
||||
* |
||||
* Usage: |
||||
* chorus gain-in gain-out delay-1 decay-1 speed-1 depth-1 -s1|t1 [ |
||||
* delay-2 decay-2 speed-2 depth-2 -s2|-t2 ... ] |
||||
* |
||||
* Where: |
||||
* gain-in, decay-1 ... decay-n : 0.0 ... 1.0 volume |
||||
* gain-out : 0.0 ... volume |
||||
* delay-1 ... delay-n : 20.0 ... 100.0 msec |
||||
* speed-1 ... speed-n : 0.1 ... 5.0 Hz modulation 1 ... n |
||||
* depth-1 ... depth-n : 0.0 ... 10.0 msec modulated delay 1 ... n |
||||
* -s1 ... -sn : modulation by sine 1 ... n |
||||
* -t1 ... -tn : modulation by triangle 1 ... n |
||||
* |
||||
* Note: |
||||
* when decay is close to 1.0, the samples can begin clipping and the output |
||||
* can saturate! |
||||
* |
||||
* Hint: |
||||
* 1 / out-gain < gain-in ( 1 + decay-1 + ... + decay-n ) |
||||
* |
||||
*/ |
||||
|
||||
/*
|
||||
* libSoX chorus effect file. |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
#include <stdlib.h> /* Harmless, and prototypes atof() etc. --dgc */ |
||||
#include <string.h> |
||||
|
||||
#define MOD_SINE 0 |
||||
#define MOD_TRIANGLE 1 |
||||
#define MAX_CHORUS 7 |
||||
|
||||
typedef struct { |
||||
int num_chorus; |
||||
int modulation[MAX_CHORUS]; |
||||
int counter; |
||||
long phase[MAX_CHORUS]; |
||||
float *chorusbuf; |
||||
float in_gain, out_gain; |
||||
float delay[MAX_CHORUS], decay[MAX_CHORUS]; |
||||
float speed[MAX_CHORUS], depth[MAX_CHORUS]; |
||||
long length[MAX_CHORUS]; |
||||
int *lookup_tab[MAX_CHORUS]; |
||||
int depth_samples[MAX_CHORUS], samples[MAX_CHORUS]; |
||||
int maxsamples; |
||||
unsigned int fade_out; |
||||
} priv_t; |
||||
|
||||
/*
|
||||
* Process options |
||||
*/ |
||||
static int sox_chorus_getopts(sox_effect_t * effp, int argc, char **argv) |
||||
{ |
||||
priv_t * chorus = (priv_t *) effp->priv; |
||||
int i; |
||||
--argc, ++argv; |
||||
|
||||
chorus->num_chorus = 0; |
||||
i = 0; |
||||
|
||||
if ( ( argc < 7 ) || (( argc - 2 ) % 5 ) ) |
||||
return lsx_usage(effp); |
||||
|
||||
sscanf(argv[i++], "%f", &chorus->in_gain); |
||||
sscanf(argv[i++], "%f", &chorus->out_gain); |
||||
while ( i < argc ) { |
||||
if ( chorus->num_chorus > MAX_CHORUS ) |
||||
{ |
||||
lsx_fail("chorus: to many delays, use less than %i delays", MAX_CHORUS); |
||||
return (SOX_EOF); |
||||
} |
||||
sscanf(argv[i++], "%f", &chorus->delay[chorus->num_chorus]); |
||||
sscanf(argv[i++], "%f", &chorus->decay[chorus->num_chorus]); |
||||
sscanf(argv[i++], "%f", &chorus->speed[chorus->num_chorus]); |
||||
sscanf(argv[i++], "%f", &chorus->depth[chorus->num_chorus]); |
||||
if ( !strcmp(argv[i], "-s")) |
||||
chorus->modulation[chorus->num_chorus] = MOD_SINE; |
||||
else if ( ! strcmp(argv[i], "-t")) |
||||
chorus->modulation[chorus->num_chorus] = MOD_TRIANGLE; |
||||
else |
||||
return lsx_usage(effp); |
||||
i++; |
||||
chorus->num_chorus++; |
||||
} |
||||
return (SOX_SUCCESS); |
||||
} |
||||
|
||||
/*
|
||||
* Prepare for processing. |
||||
*/ |
||||
static int sox_chorus_start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * chorus = (priv_t *) effp->priv; |
||||
int i; |
||||
float sum_in_volume; |
||||
|
||||
chorus->maxsamples = 0; |
||||
|
||||
if ( chorus->in_gain < 0.0 ) |
||||
{ |
||||
lsx_fail("chorus: gain-in must be positive!"); |
||||
return (SOX_EOF); |
||||
} |
||||
if ( chorus->in_gain > 1.0 ) |
||||
{ |
||||
lsx_fail("chorus: gain-in must be less than 1.0!"); |
||||
return (SOX_EOF); |
||||
} |
||||
if ( chorus->out_gain < 0.0 ) |
||||
{ |
||||
lsx_fail("chorus: gain-out must be positive!"); |
||||
return (SOX_EOF); |
||||
} |
||||
for ( i = 0; i < chorus->num_chorus; i++ ) { |
||||
chorus->samples[i] = (int) ( ( chorus->delay[i] + |
||||
chorus->depth[i] ) * effp->in_signal.rate / 1000.0); |
||||
chorus->depth_samples[i] = (int) (chorus->depth[i] * |
||||
effp->in_signal.rate / 1000.0); |
||||
|
||||
if ( chorus->delay[i] < 20.0 ) |
||||
{ |
||||
lsx_fail("chorus: delay must be more than 20.0 msec!"); |
||||
return (SOX_EOF); |
||||
} |
||||
if ( chorus->delay[i] > 100.0 ) |
||||
{ |
||||
lsx_fail("chorus: delay must be less than 100.0 msec!"); |
||||
return (SOX_EOF); |
||||
} |
||||
if ( chorus->speed[i] < 0.1 ) |
||||
{ |
||||
lsx_fail("chorus: speed must be more than 0.1 Hz!"); |
||||
return (SOX_EOF); |
||||
} |
||||
if ( chorus->speed[i] > 5.0 ) |
||||
{ |
||||
lsx_fail("chorus: speed must be less than 5.0 Hz!"); |
||||
return (SOX_EOF); |
||||
} |
||||
if ( chorus->depth[i] < 0.0 ) |
||||
{ |
||||
lsx_fail("chorus: delay must be more positive!"); |
||||
return (SOX_EOF); |
||||
} |
||||
if ( chorus->depth[i] > 10.0 ) |
||||
{ |
||||
lsx_fail("chorus: delay must be less than 10.0 msec!"); |
||||
return (SOX_EOF); |
||||
} |
||||
if ( chorus->decay[i] < 0.0 ) |
||||
{ |
||||
lsx_fail("chorus: decay must be positive!" ); |
||||
return (SOX_EOF); |
||||
} |
||||
if ( chorus->decay[i] > 1.0 ) |
||||
{ |
||||
lsx_fail("chorus: decay must be less that 1.0!" ); |
||||
return (SOX_EOF); |
||||
} |
||||
chorus->length[i] = effp->in_signal.rate / chorus->speed[i]; |
||||
chorus->lookup_tab[i] = lsx_malloc(sizeof (int) * chorus->length[i]); |
||||
|
||||
if (chorus->modulation[i] == MOD_SINE) |
||||
lsx_generate_wave_table(SOX_WAVE_SINE, SOX_INT, chorus->lookup_tab[i], |
||||
(size_t)chorus->length[i], 0., (double)chorus->depth_samples[i], 0.); |
||||
else |
||||
lsx_generate_wave_table(SOX_WAVE_TRIANGLE, SOX_INT, chorus->lookup_tab[i], |
||||
(size_t)chorus->length[i], |
||||
(double)(chorus->samples[i] - 1 - 2 * chorus->depth_samples[i]), |
||||
(double)(chorus->samples[i] - 1), 3 * M_PI_2); |
||||
chorus->phase[i] = 0; |
||||
|
||||
if ( chorus->samples[i] > chorus->maxsamples ) |
||||
chorus->maxsamples = chorus->samples[i]; |
||||
} |
||||
|
||||
/* Be nice and check the hint with warning, if... */ |
||||
sum_in_volume = 1.0; |
||||
for ( i = 0; i < chorus->num_chorus; i++ ) |
||||
sum_in_volume += chorus->decay[i]; |
||||
if ( chorus->in_gain * ( sum_in_volume ) > 1.0 / chorus->out_gain ) |
||||
lsx_warn("chorus: warning >>> gain-out can cause saturation or clipping of output <<<"); |
||||
|
||||
|
||||
chorus->chorusbuf = lsx_malloc(sizeof (float) * chorus->maxsamples); |
||||
for ( i = 0; i < chorus->maxsamples; i++ ) |
||||
chorus->chorusbuf[i] = 0.0; |
||||
|
||||
chorus->counter = 0; |
||||
chorus->fade_out = chorus->maxsamples; |
||||
|
||||
effp->out_signal.length = SOX_UNKNOWN_LEN; /* TODO: calculate actual length */ |
||||
|
||||
return (SOX_SUCCESS); |
||||
} |
||||
|
||||
/*
|
||||
* Processed signed long samples from ibuf to obuf. |
||||
* Return number of samples processed. |
||||
*/ |
||||
static int sox_chorus_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, |
||||
size_t *isamp, size_t *osamp) |
||||
{ |
||||
priv_t * chorus = (priv_t *) effp->priv; |
||||
int i; |
||||
float d_in, d_out; |
||||
sox_sample_t out; |
||||
size_t len = min(*isamp, *osamp); |
||||
*isamp = *osamp = len; |
||||
|
||||
while (len--) { |
||||
/* Store delays as 24-bit signed longs */ |
||||
d_in = (float) *ibuf++ / 256; |
||||
/* Compute output first */ |
||||
d_out = d_in * chorus->in_gain; |
||||
for ( i = 0; i < chorus->num_chorus; i++ ) |
||||
d_out += chorus->chorusbuf[(chorus->maxsamples + |
||||
chorus->counter - chorus->lookup_tab[i][chorus->phase[i]]) % |
||||
chorus->maxsamples] * chorus->decay[i]; |
||||
/* Adjust the output volume and size to 24 bit */ |
||||
d_out = d_out * chorus->out_gain; |
||||
out = SOX_24BIT_CLIP_COUNT((sox_sample_t) d_out, effp->clips); |
||||
*obuf++ = out * 256; |
||||
/* Mix decay of delay and input */ |
||||
chorus->chorusbuf[chorus->counter] = d_in; |
||||
chorus->counter = |
||||
( chorus->counter + 1 ) % chorus->maxsamples; |
||||
for ( i = 0; i < chorus->num_chorus; i++ ) |
||||
chorus->phase[i] = |
||||
( chorus->phase[i] + 1 ) % chorus->length[i]; |
||||
} |
||||
/* processed all samples */ |
||||
return (SOX_SUCCESS); |
||||
} |
||||
|
||||
/*
|
||||
* Drain out reverb lines. |
||||
*/ |
||||
static int sox_chorus_drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp) |
||||
{ |
||||
priv_t * chorus = (priv_t *) effp->priv; |
||||
size_t done; |
||||
int i; |
||||
|
||||
float d_in, d_out; |
||||
sox_sample_t out; |
||||
|
||||
done = 0; |
||||
while ( ( done < *osamp ) && ( done < chorus->fade_out ) ) { |
||||
d_in = 0; |
||||
d_out = 0; |
||||
/* Compute output first */ |
||||
for ( i = 0; i < chorus->num_chorus; i++ ) |
||||
d_out += chorus->chorusbuf[(chorus->maxsamples + |
||||
chorus->counter - chorus->lookup_tab[i][chorus->phase[i]]) % |
||||
chorus->maxsamples] * chorus->decay[i]; |
||||
/* Adjust the output volume and size to 24 bit */ |
||||
d_out = d_out * chorus->out_gain; |
||||
out = SOX_24BIT_CLIP_COUNT((sox_sample_t) d_out, effp->clips); |
||||
*obuf++ = out * 256; |
||||
/* Mix decay of delay and input */ |
||||
chorus->chorusbuf[chorus->counter] = d_in; |
||||
chorus->counter = |
||||
( chorus->counter + 1 ) % chorus->maxsamples; |
||||
for ( i = 0; i < chorus->num_chorus; i++ ) |
||||
chorus->phase[i] = |
||||
( chorus->phase[i] + 1 ) % chorus->length[i]; |
||||
done++; |
||||
chorus->fade_out--; |
||||
} |
||||
/* samples played, it remains */ |
||||
*osamp = done; |
||||
if (chorus->fade_out == 0) |
||||
return SOX_EOF; |
||||
else |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Clean up chorus effect. |
||||
*/ |
||||
static int sox_chorus_stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * chorus = (priv_t *) effp->priv; |
||||
int i; |
||||
|
||||
free(chorus->chorusbuf); |
||||
chorus->chorusbuf = NULL; |
||||
for ( i = 0; i < chorus->num_chorus; i++ ) { |
||||
free(chorus->lookup_tab[i]); |
||||
chorus->lookup_tab[i] = NULL; |
||||
} |
||||
return (SOX_SUCCESS); |
||||
} |
||||
|
||||
static sox_effect_handler_t sox_chorus_effect = { |
||||
"chorus", |
||||
"gain-in gain-out delay decay speed depth [ -s | -t ]", |
||||
SOX_EFF_LENGTH | SOX_EFF_GAIN, |
||||
sox_chorus_getopts, |
||||
sox_chorus_start, |
||||
sox_chorus_flow, |
||||
sox_chorus_drain, |
||||
sox_chorus_stop, |
||||
NULL, sizeof(priv_t) |
||||
}; |
||||
|
||||
const sox_effect_handler_t *lsx_chorus_effect_fn(void) |
||||
{ |
||||
return &sox_chorus_effect; |
||||
} |
@ -1,293 +0,0 @@ |
||||
/* libSoX compander effect
|
||||
* |
||||
* Written by Nick Bailey (nick@bailey-family.org.uk or |
||||
* n.bailey@elec.gla.ac.uk) |
||||
* |
||||
* Copyright 1999 Chris Bagwell And Nick Bailey |
||||
* This source code is freely redistributable and may be used for |
||||
* any purpose. This copyright notice must be maintained. |
||||
* Chris Bagwell And Nick Bailey are not responsible for |
||||
* the consequences of using this software. |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include "compandt.h" |
||||
|
||||
/*
|
||||
* Compressor/expander effect for libSoX. |
||||
* |
||||
* Flow diagram for one channel: |
||||
* |
||||
* ------------ --------------- |
||||
* | | | | --- |
||||
* ibuff ---+---| integrator |--->| transfer func |--->| | |
||||
* | | | | | | | |
||||
* | ------------ --------------- | | * gain |
||||
* | | * |----------->obuff |
||||
* | ------- | | |
||||
* | | | | | |
||||
* +----->| delay |-------------------------->| | |
||||
* | | --- |
||||
* ------- |
||||
*/ |
||||
#define compand_usage \ |
||||
"attack1,decay1{,attack2,decay2} [soft-knee-dB:]in-dB1[,out-dB1]{,in-dB2,out-dB2} [gain [initial-volume-dB [delay]]]\n" \
|
||||
"\twhere {} means optional and repeatable and [] means optional.\n" \
|
||||
"\tdB values are floating point or -inf'; times are in seconds." |
||||
/*
|
||||
* Note: clipping can occur if the transfer function pushes things too |
||||
* close to 0 dB. In that case, use a negative gain, or reduce the |
||||
* output level of the transfer function. |
||||
*/ |
||||
|
||||
typedef struct { |
||||
sox_compandt_t transfer_fn; |
||||
|
||||
struct { |
||||
double attack_times[2]; /* 0:attack_time, 1:decay_time */ |
||||
double volume; /* Current "volume" of each channel */ |
||||
} * channels; |
||||
unsigned expectedChannels;/* Also flags that channels aren't to be treated
|
||||
individually when = 1 and input not mono */ |
||||
double delay; /* Delay to apply before companding */ |
||||
sox_sample_t *delay_buf; /* Old samples, used for delay processing */ |
||||
ptrdiff_t delay_buf_size;/* Size of delay_buf in samples */ |
||||
ptrdiff_t delay_buf_index; /* Index into delay_buf */ |
||||
ptrdiff_t delay_buf_cnt; /* No. of active entries in delay_buf */ |
||||
int delay_buf_full; /* Shows buffer situation (important for drain) */ |
||||
|
||||
char *arg0; /* copies of arguments, so that they may be modified */ |
||||
char *arg1; |
||||
char *arg2; |
||||
} priv_t; |
||||
|
||||
static int getopts(sox_effect_t * effp, int argc, char * * argv) |
||||
{ |
||||
priv_t * l = (priv_t *) effp->priv; |
||||
char * s; |
||||
char dummy; /* To check for extraneous chars. */ |
||||
unsigned pairs, i, j, commas; |
||||
|
||||
--argc, ++argv; |
||||
if (argc < 2 || argc > 5) |
||||
return lsx_usage(effp); |
||||
|
||||
l->arg0 = lsx_strdup(argv[0]); |
||||
l->arg1 = lsx_strdup(argv[1]); |
||||
l->arg2 = argc > 2 ? lsx_strdup(argv[2]) : NULL; |
||||
|
||||
/* Start by checking the attack and decay rates */ |
||||
for (s = l->arg0, commas = 0; *s; ++s) if (*s == ',') ++commas; |
||||
if ((commas % 2) == 0) { |
||||
lsx_fail("there must be an even number of attack/decay parameters"); |
||||
return SOX_EOF; |
||||
} |
||||
pairs = 1 + commas/2; |
||||
l->channels = lsx_calloc(pairs, sizeof(*l->channels)); |
||||
l->expectedChannels = pairs; |
||||
|
||||
/* Now tokenise the rates string and set up these arrays. Keep
|
||||
them in seconds at the moment: we don't know the sample rate yet. */ |
||||
for (i = 0, s = strtok(l->arg0, ","); s != NULL; ++i) { |
||||
for (j = 0; j < 2; ++j) { |
||||
if (sscanf(s, "%lf %c", &l->channels[i].attack_times[j], &dummy) != 1) { |
||||
lsx_fail("syntax error trying to read attack/decay time"); |
||||
return SOX_EOF; |
||||
} else if (l->channels[i].attack_times[j] < 0) { |
||||
lsx_fail("attack & decay times can't be less than 0 seconds"); |
||||
return SOX_EOF; |
||||
} |
||||
s = strtok(NULL, ","); |
||||
} |
||||
} |
||||
|
||||
if (!lsx_compandt_parse(&l->transfer_fn, l->arg1, l->arg2)) |
||||
return SOX_EOF; |
||||
|
||||
/* Set the initial "volume" to be attibuted to the input channels.
|
||||
Unless specified, choose 0dB otherwise clipping will |
||||
result if the user has seleced a long attack time */ |
||||
for (i = 0; i < l->expectedChannels; ++i) { |
||||
double init_vol_dB = 0; |
||||
if (argc > 3 && sscanf(argv[3], "%lf %c", &init_vol_dB, &dummy) != 1) { |
||||
lsx_fail("syntax error trying to read initial volume"); |
||||
return SOX_EOF; |
||||
} else if (init_vol_dB > 0) { |
||||
lsx_fail("initial volume is relative to maximum volume so can't exceed 0dB"); |
||||
return SOX_EOF; |
||||
} |
||||
l->channels[i].volume = pow(10., init_vol_dB / 20); |
||||
} |
||||
|
||||
/* If there is a delay, store it. */ |
||||
if (argc > 4 && sscanf(argv[4], "%lf %c", &l->delay, &dummy) != 1) { |
||||
lsx_fail("syntax error trying to read delay value"); |
||||
return SOX_EOF; |
||||
} else if (l->delay < 0) { |
||||
lsx_fail("delay can't be less than 0 seconds"); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * l = (priv_t *) effp->priv; |
||||
unsigned i, j; |
||||
|
||||
lsx_debug("%i input channel(s) expected: actually %i", |
||||
l->expectedChannels, effp->out_signal.channels); |
||||
for (i = 0; i < l->expectedChannels; ++i) |
||||
lsx_debug("Channel %i: attack = %g decay = %g", i, |
||||
l->channels[i].attack_times[0], l->channels[i].attack_times[1]); |
||||
if (!lsx_compandt_show(&l->transfer_fn, effp->global_info->plot)) |
||||
return SOX_EOF; |
||||
|
||||
/* Convert attack and decay rates using number of samples */ |
||||
for (i = 0; i < l->expectedChannels; ++i) |
||||
for (j = 0; j < 2; ++j) |
||||
if (l->channels[i].attack_times[j] > 1.0/effp->out_signal.rate) |
||||
l->channels[i].attack_times[j] = 1.0 - |
||||
exp(-1.0/(effp->out_signal.rate * l->channels[i].attack_times[j])); |
||||
else |
||||
l->channels[i].attack_times[j] = 1.0; |
||||
|
||||
/* Allocate the delay buffer */ |
||||
l->delay_buf_size = l->delay * effp->out_signal.rate * effp->out_signal.channels; |
||||
if (l->delay_buf_size > 0) |
||||
l->delay_buf = lsx_calloc((size_t)l->delay_buf_size, sizeof(*l->delay_buf)); |
||||
l->delay_buf_index = 0; |
||||
l->delay_buf_cnt = 0; |
||||
l->delay_buf_full= 0; |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Update a volume value using the given sample |
||||
* value, the attack rate and decay rate |
||||
*/ |
||||
static void doVolume(double *v, double samp, priv_t * l, int chan) |
||||
{ |
||||
double s = -samp / SOX_SAMPLE_MIN; |
||||
double delta = s - *v; |
||||
|
||||
if (delta > 0.0) /* increase volume according to attack rate */ |
||||
*v += delta * l->channels[chan].attack_times[0]; |
||||
else /* reduce volume according to decay rate */ |
||||
*v += delta * l->channels[chan].attack_times[1]; |
||||
} |
||||
|
||||
static int flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, |
||||
size_t *isamp, size_t *osamp) |
||||
{ |
||||
priv_t * l = (priv_t *) effp->priv; |
||||
int len = (*isamp > *osamp) ? *osamp : *isamp; |
||||
int filechans = effp->out_signal.channels; |
||||
int idone,odone; |
||||
|
||||
for (idone = 0,odone = 0; idone < len; ibuf += filechans) { |
||||
int chan; |
||||
|
||||
/* Maintain the volume fields by simulating a leaky pump circuit */ |
||||
for (chan = 0; chan < filechans; ++chan) { |
||||
if (l->expectedChannels == 1 && filechans > 1) { |
||||
/* User is expecting same compander for all channels */ |
||||
int i; |
||||
double maxsamp = 0.0; |
||||
for (i = 0; i < filechans; ++i) { |
||||
double rect = fabs((double)ibuf[i]); |
||||
if (rect > maxsamp) maxsamp = rect; |
||||
} |
||||
doVolume(&l->channels[0].volume, maxsamp, l, 0); |
||||
break; |
||||
} else |
||||
doVolume(&l->channels[chan].volume, fabs((double)ibuf[chan]), l, chan); |
||||
} |
||||
|
||||
/* Volume memory is updated: perform compand */ |
||||
for (chan = 0; chan < filechans; ++chan) { |
||||
int ch = l->expectedChannels > 1 ? chan : 0; |
||||
double level_in_lin = l->channels[ch].volume; |
||||
double level_out_lin = lsx_compandt(&l->transfer_fn, level_in_lin); |
||||
double checkbuf; |
||||
|
||||
if (l->delay_buf_size <= 0) { |
||||
checkbuf = ibuf[chan] * level_out_lin; |
||||
SOX_SAMPLE_CLIP_COUNT(checkbuf, effp->clips); |
||||
obuf[odone++] = checkbuf; |
||||
idone++; |
||||
} else { |
||||
if (l->delay_buf_cnt >= l->delay_buf_size) { |
||||
l->delay_buf_full=1; /* delay buffer is now definitely full */ |
||||
checkbuf = l->delay_buf[l->delay_buf_index] * level_out_lin; |
||||
SOX_SAMPLE_CLIP_COUNT(checkbuf, effp->clips); |
||||
obuf[odone] = checkbuf; |
||||
odone++; |
||||
idone++; |
||||
} else { |
||||
l->delay_buf_cnt++; |
||||
idone++; /* no "odone++" because we did not fill obuf[...] */ |
||||
} |
||||
l->delay_buf[l->delay_buf_index++] = ibuf[chan]; |
||||
l->delay_buf_index %= l->delay_buf_size; |
||||
} |
||||
} |
||||
} |
||||
|
||||
*isamp = idone; *osamp = odone; |
||||
return (SOX_SUCCESS); |
||||
} |
||||
|
||||
static int drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp) |
||||
{ |
||||
priv_t * l = (priv_t *) effp->priv; |
||||
size_t chan, done = 0; |
||||
|
||||
if (l->delay_buf_full == 0) |
||||
l->delay_buf_index = 0; |
||||
while (done+effp->out_signal.channels <= *osamp && l->delay_buf_cnt > 0) |
||||
for (chan = 0; chan < effp->out_signal.channels; ++chan) { |
||||
int c = l->expectedChannels > 1 ? chan : 0; |
||||
double level_in_lin = l->channels[c].volume; |
||||
double level_out_lin = lsx_compandt(&l->transfer_fn, level_in_lin); |
||||
obuf[done++] = l->delay_buf[l->delay_buf_index++] * level_out_lin; |
||||
l->delay_buf_index %= l->delay_buf_size; |
||||
l->delay_buf_cnt--; |
||||
} |
||||
*osamp = done; |
||||
return l->delay_buf_cnt > 0 ? SOX_SUCCESS : SOX_EOF; |
||||
} |
||||
|
||||
static int stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * l = (priv_t *) effp->priv; |
||||
|
||||
free(l->delay_buf); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int lsx_kill(sox_effect_t * effp) |
||||
{ |
||||
priv_t * l = (priv_t *) effp->priv; |
||||
|
||||
lsx_compandt_kill(&l->transfer_fn); |
||||
free(l->channels); |
||||
free(l->arg0); |
||||
free(l->arg1); |
||||
free(l->arg2); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_compand_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"compand", compand_usage, SOX_EFF_MCHAN | SOX_EFF_GAIN, |
||||
getopts, start, flow, drain, stop, lsx_kill, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,229 +0,0 @@ |
||||
/* libSoX Compander Transfer Function: (c) 2007 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
#include "compandt.h" |
||||
#include <string.h> |
||||
|
||||
#define LOG_TO_LOG10(x) ((x) * 20 / M_LN10) |
||||
|
||||
sox_bool lsx_compandt_show(sox_compandt_t * t, sox_plot_t plot) |
||||
{ |
||||
int i; |
||||
|
||||
for (i = 1; t->segments[i-1].x; ++i) |
||||
lsx_debug("TF: %g %g %g %g", |
||||
LOG_TO_LOG10(t->segments[i].x), |
||||
LOG_TO_LOG10(t->segments[i].y), |
||||
LOG_TO_LOG10(t->segments[i].a), |
||||
LOG_TO_LOG10(t->segments[i].b)); |
||||
|
||||
if (plot == sox_plot_octave) { |
||||
printf( |
||||
"%% GNU Octave file (may also work with MATLAB(R) )\n" |
||||
"in=linspace(-99.5,0,200);\n" |
||||
"out=["); |
||||
for (i = -199; i <= 0; ++i) { |
||||
double in = i/2.; |
||||
double in_lin = pow(10., in/20); |
||||
printf("%g ", in + 20 * log10(lsx_compandt(t, in_lin))); |
||||
} |
||||
printf( |
||||
"];\n" |
||||
"plot(in,out)\n" |
||||
"title('SoX effect: compand')\n" |
||||
"xlabel('Input level (dB)')\n" |
||||
"ylabel('Output level (dB)')\n" |
||||
"grid on\n" |
||||
"disp('Hit return to continue')\n" |
||||
"pause\n"); |
||||
return sox_false; |
||||
} |
||||
if (plot == sox_plot_gnuplot) { |
||||
printf( |
||||
"# gnuplot file\n" |
||||
"set title 'SoX effect: compand'\n" |
||||
"set xlabel 'Input level (dB)'\n" |
||||
"set ylabel 'Output level (dB)'\n" |
||||
"set grid xtics ytics\n" |
||||
"set key off\n" |
||||
"plot '-' with lines\n"); |
||||
for (i = -199; i <= 0; ++i) { |
||||
double in = i/2.; |
||||
double in_lin = pow(10., in/20); |
||||
printf("%g %g\n", in, in + 20 * log10(lsx_compandt(t, in_lin))); |
||||
} |
||||
printf( |
||||
"e\n" |
||||
"pause -1 'Hit return to continue'\n"); |
||||
return sox_false; |
||||
} |
||||
return sox_true; |
||||
} |
||||
|
||||
static void prepare_transfer_fn(sox_compandt_t * t) |
||||
{ |
||||
int i; |
||||
double radius = t->curve_dB * M_LN10 / 20; |
||||
|
||||
for (i = 0; !i || t->segments[i-2].x; i += 2) { |
||||
t->segments[i].y += t->outgain_dB; |
||||
t->segments[i].x *= M_LN10 / 20; /* Convert to natural logs */ |
||||
t->segments[i].y *= M_LN10 / 20; |
||||
} |
||||
|
||||
#define line1 t->segments[i - 4] |
||||
#define curve t->segments[i - 3] |
||||
#define line2 t->segments[i - 2] |
||||
#define line3 t->segments[i - 0] |
||||
for (i = 4; t->segments[i - 2].x; i += 2) { |
||||
double x, y, cx, cy, in1, in2, out1, out2, theta, len, r; |
||||
|
||||
line1.a = 0; |
||||
line1.b = (line2.y - line1.y) / (line2.x - line1.x); |
||||
|
||||
line2.a = 0; |
||||
line2.b = (line3.y - line2.y) / (line3.x - line2.x); |
||||
|
||||
theta = atan2(line2.y - line1.y, line2.x - line1.x); |
||||
len = sqrt(pow(line2.x - line1.x, 2.) + pow(line2.y - line1.y, 2.)); |
||||
r = min(radius, len); |
||||
curve.x = line2.x - r * cos(theta); |
||||
curve.y = line2.y - r * sin(theta); |
||||
|
||||
theta = atan2(line3.y - line2.y, line3.x - line2.x); |
||||
len = sqrt(pow(line3.x - line2.x, 2.) + pow(line3.y - line2.y, 2.)); |
||||
r = min(radius, len / 2); |
||||
x = line2.x + r * cos(theta); |
||||
y = line2.y + r * sin(theta); |
||||
|
||||
cx = (curve.x + line2.x + x) / 3; |
||||
cy = (curve.y + line2.y + y) / 3; |
||||
|
||||
line2.x = x; |
||||
line2.y = y; |
||||
|
||||
in1 = cx - curve.x; |
||||
out1 = cy - curve.y; |
||||
in2 = line2.x - curve.x; |
||||
out2 = line2.y - curve.y; |
||||
curve.a = (out2/in2 - out1/in1) / (in2-in1); |
||||
curve.b = out1/in1 - curve.a*in1; |
||||
} |
||||
#undef line1 |
||||
#undef curve |
||||
#undef line2 |
||||
#undef line3 |
||||
t->segments[i - 3].x = 0; |
||||
t->segments[i - 3].y = t->segments[i - 2].y; |
||||
|
||||
t->in_min_lin = exp(t->segments[1].x); |
||||
t->out_min_lin= exp(t->segments[1].y); |
||||
} |
||||
|
||||
static sox_bool parse_transfer_value(char const * text, double * value) |
||||
{ |
||||
char dummy; /* To check for extraneous chars. */ |
||||
|
||||
if (!text) { |
||||
lsx_fail("syntax error trying to read transfer function value"); |
||||
return sox_false; |
||||
} |
||||
if (!strcmp(text, "-inf")) |
||||
*value = -20 * log10(-(double)SOX_SAMPLE_MIN); |
||||
else if (sscanf(text, "%lf %c", value, &dummy) != 1) { |
||||
lsx_fail("syntax error trying to read transfer function value"); |
||||
return sox_false; |
||||
} |
||||
else if (*value > 0) { |
||||
lsx_fail("transfer function values are relative to maximum volume so can't exceed 0dB"); |
||||
return sox_false; |
||||
} |
||||
return sox_true; |
||||
} |
||||
|
||||
sox_bool lsx_compandt_parse(sox_compandt_t * t, char * points, char * gain) |
||||
{ |
||||
char const * text = points; |
||||
unsigned i, j, num, pairs, commas = 0; |
||||
char dummy; /* To check for extraneous chars. */ |
||||
|
||||
if (sscanf(points, "%lf %c", &t->curve_dB, &dummy) == 2 && dummy == ':') |
||||
points = strchr(points, ':') + 1; |
||||
else t->curve_dB = 0; |
||||
t->curve_dB = max(t->curve_dB, .01); |
||||
|
||||
while (*text) commas += *text++ == ','; |
||||
pairs = 1 + commas / 2; |
||||
++pairs; /* allow room for extra pair at the beginning */ |
||||
pairs *= 2; /* allow room for the auto-curves */ |
||||
++pairs; /* allow room for 0,0 at end */ |
||||
t->segments = lsx_calloc(pairs, sizeof(*t->segments)); |
||||
|
||||
#define s(n) t->segments[2*((n)+1)] |
||||
for (i = 0, text = strtok(points, ","); text != NULL; ++i) { |
||||
if (!parse_transfer_value(text, &s(i).x)) |
||||
return sox_false; |
||||
if (i && s(i-1).x > s(i).x) { |
||||
lsx_fail("transfer function input values must be strictly increasing"); |
||||
return sox_false; |
||||
} |
||||
if (i || (commas & 1)) { |
||||
text = strtok(NULL, ","); |
||||
if (!parse_transfer_value(text, &s(i).y)) |
||||
return sox_false; |
||||
s(i).y -= s(i).x; |
||||
} |
||||
text = strtok(NULL, ","); |
||||
} |
||||
num = i; |
||||
|
||||
if (num == 0 || s(num-1).x) /* Add 0,0 if necessary */ |
||||
++num; |
||||
#undef s |
||||
|
||||
if (gain && sscanf(gain, "%lf %c", &t->outgain_dB, &dummy) != 1) { |
||||
lsx_fail("syntax error trying to read post-processing gain value"); |
||||
return sox_false; |
||||
} |
||||
|
||||
#define s(n) t->segments[2*(n)] |
||||
s(0).x = s(1).x - 2 * t->curve_dB; /* Add a tail off segment at the start */ |
||||
s(0).y = s(1).y; |
||||
++num; |
||||
|
||||
for (i = 2; i < num; ++i) { /* Join adjacent colinear segments */ |
||||
double g1 = (s(i-1).y - s(i-2).y) * (s(i-0).x - s(i-1).x); |
||||
double g2 = (s(i-0).y - s(i-1).y) * (s(i-1).x - s(i-2).x); |
||||
if (fabs(g1 - g2)) /* fabs stops epsilon problems */ |
||||
continue; |
||||
--num; |
||||
for (j = --i; j < num; ++j) |
||||
s(j) = s(j+1); |
||||
} |
||||
#undef s |
||||
|
||||
prepare_transfer_fn(t); |
||||
return sox_true; |
||||
} |
||||
|
||||
void lsx_compandt_kill(sox_compandt_t * p) |
||||
{ |
||||
free(p->segments); |
||||
} |
||||
|
@ -1,52 +0,0 @@ |
||||
/* libSoX Compander Transfer Function (c) 2007 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include <math.h> |
||||
|
||||
typedef struct { |
||||
struct sox_compandt_segment { |
||||
double x, y; /* 1st point in segment */ |
||||
double a, b; /* Quadratic coeffecients for rest of segment */ |
||||
} * segments; |
||||
double in_min_lin; |
||||
double out_min_lin; |
||||
double outgain_dB; /* Post processor gain */ |
||||
double curve_dB; |
||||
} sox_compandt_t; |
||||
|
||||
sox_bool lsx_compandt_parse(sox_compandt_t * t, char * points, char * gain); |
||||
sox_bool lsx_compandt_show(sox_compandt_t * t, sox_plot_t plot); |
||||
void lsx_compandt_kill(sox_compandt_t * p); |
||||
|
||||
/* Place in header to allow in-lining */ |
||||
static double lsx_compandt(sox_compandt_t * t, double in_lin) |
||||
{ |
||||
struct sox_compandt_segment * s; |
||||
double in_log, out_log; |
||||
|
||||
if (in_lin <= t->in_min_lin) |
||||
return t->out_min_lin; |
||||
|
||||
in_log = log(in_lin); |
||||
|
||||
for (s = t->segments + 1; in_log > s[1].x; ++s); |
||||
|
||||
in_log -= s->x; |
||||
out_log = s->y + in_log * (s->a * in_log + s->b); |
||||
|
||||
return exp(out_log); |
||||
} |
@ -1,49 +0,0 @@ |
||||
/* libSoX effect: Contrast Enhancement (c) 2008 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
typedef struct {double contrast;} priv_t; |
||||
|
||||
static int create(sox_effect_t * effp, int argc, char * * argv) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
p->contrast = 75; |
||||
--argc, ++argv; |
||||
do {NUMERIC_PARAMETER(contrast, 0, 100)} while (0); |
||||
p->contrast /= 750; /* shift range to 0 to 0.1333, default 0.1 */ |
||||
return argc? lsx_usage(effp) : SOX_SUCCESS; |
||||
} |
||||
|
||||
static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, |
||||
sox_sample_t * obuf, size_t * isamp, size_t * osamp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
size_t len = *isamp = *osamp = min(*isamp, *osamp); |
||||
while (len--) { |
||||
double d = *ibuf++ * (-M_PI_2 / SOX_SAMPLE_MIN); |
||||
*obuf++ = sin(d + p->contrast * sin(d * 4)) * SOX_SAMPLE_MAX; |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_contrast_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = {"contrast", "[enhancement (75)]", |
||||
0, create, NULL, flow, NULL, NULL, NULL, sizeof(priv_t)}; |
||||
return &handler; |
||||
} |
@ -1,418 +0,0 @@ |
||||
/* AudioCore sound handler
|
||||
* |
||||
* Copyright 2008 Chris Bagwell And Sundry Contributors |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
#include "CoreAudio/CoreAudio.h" |
||||
#include <pthread.h> |
||||
|
||||
#define Buffactor 4 |
||||
|
||||
typedef struct { |
||||
AudioDeviceID adid; |
||||
pthread_mutex_t mutex; |
||||
pthread_cond_t cond; |
||||
int device_started; |
||||
size_t bufsize; |
||||
size_t bufrd; |
||||
size_t bufwr; |
||||
size_t bufrdavail; |
||||
float *buf; |
||||
} priv_t; |
||||
|
||||
static OSStatus PlaybackIOProc(AudioDeviceID inDevice UNUSED, |
||||
const AudioTimeStamp *inNow UNUSED, |
||||
const AudioBufferList *inInputData UNUSED, |
||||
const AudioTimeStamp *inInputTime UNUSED, |
||||
AudioBufferList *outOutputData, |
||||
const AudioTimeStamp *inOutputTime UNUSED, |
||||
void *inClientData) |
||||
{ |
||||
priv_t *ac = (priv_t*)((sox_format_t*)inClientData)->priv; |
||||
AudioBuffer *buf; |
||||
size_t copylen, avail; |
||||
|
||||
pthread_mutex_lock(&ac->mutex); |
||||
|
||||
for(buf = outOutputData->mBuffers; |
||||
buf != outOutputData->mBuffers + outOutputData->mNumberBuffers; |
||||
buf++){ |
||||
|
||||
copylen = buf->mDataByteSize / sizeof(float); |
||||
if(copylen > ac->bufrdavail) |
||||
copylen = ac->bufrdavail; |
||||
|
||||
avail = ac->bufsize - ac->bufrd; |
||||
if(buf->mData == NULL){ |
||||
/*do nothing-hardware can't play audio*/ |
||||
}else if(copylen > avail){ |
||||
memcpy(buf->mData, ac->buf + ac->bufrd, avail * sizeof(float)); |
||||
memcpy((float*)buf->mData + avail, ac->buf, (copylen - avail) * sizeof(float)); |
||||
}else{ |
||||
memcpy(buf->mData, ac->buf + ac->bufrd, copylen * sizeof(float)); |
||||
} |
||||
|
||||
buf->mDataByteSize = copylen * sizeof(float); |
||||
ac->bufrd += copylen; |
||||
if(ac->bufrd >= ac->bufsize) |
||||
ac->bufrd -= ac->bufsize; |
||||
ac->bufrdavail -= copylen; |
||||
} |
||||
|
||||
pthread_cond_signal(&ac->cond); |
||||
pthread_mutex_unlock(&ac->mutex); |
||||
|
||||
return kAudioHardwareNoError; |
||||
} |
||||
|
||||
static OSStatus RecIOProc(AudioDeviceID inDevice UNUSED, |
||||
const AudioTimeStamp *inNow UNUSED, |
||||
const AudioBufferList *inInputData, |
||||
const AudioTimeStamp *inInputTime UNUSED, |
||||
AudioBufferList *outOutputData UNUSED, |
||||
const AudioTimeStamp *inOutputTime UNUSED, |
||||
void *inClientData) |
||||
{ |
||||
priv_t *ac = (priv_t *)((sox_format_t*)inClientData)->priv; |
||||
AudioBuffer const *buf; |
||||
size_t nfree, copylen, avail; |
||||
|
||||
pthread_mutex_lock(&ac->mutex); |
||||
|
||||
for(buf = inInputData->mBuffers; |
||||
buf != inInputData->mBuffers + inInputData->mNumberBuffers; |
||||
buf++){ |
||||
|
||||
if(buf->mData == NULL) |
||||
continue; |
||||
|
||||
copylen = buf->mDataByteSize / sizeof(float); |
||||
nfree = ac->bufsize - ac->bufrdavail - 1; |
||||
if(nfree == 0) |
||||
lsx_warn("coreaudio: unhandled buffer overrun. Data discarded."); |
||||
|
||||
if(copylen > nfree) |
||||
copylen = nfree; |
||||
|
||||
avail = ac->bufsize - ac->bufwr; |
||||
if(copylen > avail){ |
||||
memcpy(ac->buf + ac->bufwr, buf->mData, avail * sizeof(float)); |
||||
memcpy(ac->buf, (float*)buf->mData + avail, (copylen - avail) * sizeof(float)); |
||||
}else{ |
||||
memcpy(ac->buf + ac->bufwr, buf->mData, copylen * sizeof(float)); |
||||
} |
||||
|
||||
ac->bufwr += copylen; |
||||
if(ac->bufwr >= ac->bufsize) |
||||
ac->bufwr -= ac->bufsize; |
||||
ac->bufrdavail += copylen; |
||||
} |
||||
|
||||
pthread_cond_signal(&ac->cond); |
||||
pthread_mutex_unlock(&ac->mutex); |
||||
|
||||
return kAudioHardwareNoError; |
||||
} |
||||
|
||||
static int setup(sox_format_t *ft, int is_input) |
||||
{ |
||||
priv_t *ac = (priv_t *)ft->priv; |
||||
OSStatus status; |
||||
UInt32 property_size; |
||||
struct AudioStreamBasicDescription stream_desc; |
||||
int32_t buf_size; |
||||
int rc; |
||||
|
||||
if (strncmp(ft->filename, "default", (size_t)7) == 0) |
||||
{ |
||||
property_size = sizeof(ac->adid); |
||||
if (is_input) |
||||
status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &property_size, &ac->adid); |
||||
else |
||||
status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &property_size, &ac->adid); |
||||
} |
||||
else |
||||
{ |
||||
Boolean is_writable; |
||||
status = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &property_size, &is_writable); |
||||
|
||||
if (status == noErr) |
||||
{ |
||||
int device_count = property_size/sizeof(AudioDeviceID); |
||||
AudioDeviceID *devices; |
||||
|
||||
devices = malloc(property_size); |
||||
status = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &property_size, devices); |
||||
|
||||
if (status == noErr) |
||||
{ |
||||
int i; |
||||
for (i = 0; i < device_count; i++) |
||||
{ |
||||
char name[256]; |
||||
status = AudioDeviceGetProperty(devices[i],0,false,kAudioDevicePropertyDeviceName,&property_size,&name); |
||||
|
||||
lsx_report("Found Audio Device \"%s\"\n",name); |
||||
|
||||
/* String returned from OS is truncated so only compare
|
||||
* as much as returned. |
||||
*/ |
||||
if (strncmp(name,ft->filename,strlen(name)) == 0) |
||||
{ |
||||
ac->adid = devices[i]; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
free(devices); |
||||
} |
||||
} |
||||
|
||||
if (status || ac->adid == kAudioDeviceUnknown) |
||||
{ |
||||
lsx_fail_errno(ft, SOX_EPERM, "can not open audio device"); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
/* Query device to get initial values */ |
||||
property_size = sizeof(struct AudioStreamBasicDescription); |
||||
status = AudioDeviceGetProperty(ac->adid, 0, is_input, |
||||
kAudioDevicePropertyStreamFormat, |
||||
&property_size, &stream_desc); |
||||
if (status) |
||||
{ |
||||
lsx_fail_errno(ft, SOX_EPERM, "can not get audio device properties"); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
if (!(stream_desc.mFormatFlags & kLinearPCMFormatFlagIsFloat)) |
||||
{ |
||||
lsx_fail_errno(ft, SOX_EPERM, "audio device does not accept floats"); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
/* OS X effectively only supports these values. */ |
||||
ft->signal.channels = 2; |
||||
ft->signal.rate = 44100; |
||||
ft->encoding.bits_per_sample = 32; |
||||
|
||||
/* TODO: My limited experience with hardware can only get floats working
|
||||
* withh a fixed sample rate and stereo. I know that is a limitiation of |
||||
* audio device I have so this may not be standard operating orders. |
||||
* If some hardware supports setting sample rates and channel counts |
||||
* then should do that over resampling and mixing. |
||||
*/ |
||||
#if 0 |
||||
stream_desc.mSampleRate = ft->signal.rate; |
||||
stream_desc.mChannelsPerFrame = ft->signal.channels; |
||||
|
||||
/* Write them back */ |
||||
property_size = sizeof(struct AudioStreamBasicDescription); |
||||
status = AudioDeviceSetProperty(ac->adid, NULL, 0, is_input, |
||||
kAudioDevicePropertyStreamFormat, |
||||
property_size, &stream_desc); |
||||
if (status) |
||||
{ |
||||
lsx_fail_errno(ft, SOX_EPERM, "can not set audio device properties"); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
/* Query device to see if it worked */ |
||||
property_size = sizeof(struct AudioStreamBasicDescription); |
||||
status = AudioDeviceGetProperty(ac->adid, 0, is_input, |
||||
kAudioDevicePropertyStreamFormat, |
||||
&property_size, &stream_desc); |
||||
|
||||
if (status) |
||||
{ |
||||
lsx_fail_errno(ft, SOX_EPERM, "can not get audio device properties"); |
||||
return SOX_EOF; |
||||
} |
||||
#endif |
||||
|
||||
if (stream_desc.mChannelsPerFrame != ft->signal.channels) |
||||
{ |
||||
lsx_debug("audio device did not accept %d channels. Use %d channels instead.", (int)ft->signal.channels, |
||||
(int)stream_desc.mChannelsPerFrame); |
||||
ft->signal.channels = stream_desc.mChannelsPerFrame; |
||||
} |
||||
|
||||
if (stream_desc.mSampleRate != ft->signal.rate) |
||||
{ |
||||
lsx_debug("audio device did not accept %d sample rate. Use %d instead.", (int)ft->signal.rate, |
||||
(int)stream_desc.mSampleRate); |
||||
ft->signal.rate = stream_desc.mSampleRate; |
||||
} |
||||
|
||||
ac->bufsize = sox_globals.bufsiz / sizeof(sox_sample_t) * Buffactor; |
||||
ac->bufrd = 0; |
||||
ac->bufwr = 0; |
||||
ac->bufrdavail = 0; |
||||
ac->buf = lsx_malloc(ac->bufsize * sizeof(float)); |
||||
|
||||
buf_size = sox_globals.bufsiz / sizeof(sox_sample_t) * sizeof(float); |
||||
property_size = sizeof(buf_size); |
||||
status = AudioDeviceSetProperty(ac->adid, NULL, 0, is_input, |
||||
kAudioDevicePropertyBufferSize, |
||||
property_size, &buf_size); |
||||
|
||||
rc = pthread_mutex_init(&ac->mutex, NULL); |
||||
if (rc) |
||||
{ |
||||
lsx_fail_errno(ft, SOX_EPERM, "failed initializing mutex"); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
rc = pthread_cond_init(&ac->cond, NULL); |
||||
if (rc) |
||||
{ |
||||
lsx_fail_errno(ft, SOX_EPERM, "failed initializing condition"); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
ac->device_started = 0; |
||||
|
||||
/* Registers callback with the device without activating it. */ |
||||
if (is_input) |
||||
status = AudioDeviceAddIOProc(ac->adid, RecIOProc, (void *)ft); |
||||
else |
||||
status = AudioDeviceAddIOProc(ac->adid, PlaybackIOProc, (void *)ft); |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int startread(sox_format_t *ft) |
||||
{ |
||||
return setup(ft, 1); |
||||
} |
||||
|
||||
static size_t read_samples(sox_format_t *ft, sox_sample_t *buf, size_t nsamp) |
||||
{ |
||||
priv_t *ac = (priv_t *)ft->priv; |
||||
size_t len; |
||||
SOX_SAMPLE_LOCALS; |
||||
|
||||
if (!ac->device_started) { |
||||
AudioDeviceStart(ac->adid, RecIOProc); |
||||
ac->device_started = 1; |
||||
} |
||||
|
||||
pthread_mutex_lock(&ac->mutex); |
||||
|
||||
/* Wait until input buffer has been filled by device driver */ |
||||
while (ac->bufrdavail == 0) |
||||
pthread_cond_wait(&ac->cond, &ac->mutex); |
||||
|
||||
len = 0; |
||||
while(len < nsamp && ac->bufrdavail > 0){ |
||||
buf[len] = SOX_FLOAT_32BIT_TO_SAMPLE(ac->buf[ac->bufrd], ft->clips); |
||||
len++; |
||||
ac->bufrd++; |
||||
if(ac->bufrd == ac->bufsize) |
||||
ac->bufrd = 0; |
||||
ac->bufrdavail--; |
||||
} |
||||
|
||||
pthread_mutex_unlock(&ac->mutex); |
||||
|
||||
return len; |
||||
} |
||||
|
||||
static int stopread(sox_format_t * ft) |
||||
{ |
||||
priv_t *ac = (priv_t *)ft->priv; |
||||
|
||||
AudioDeviceStop(ac->adid, RecIOProc); |
||||
AudioDeviceRemoveIOProc(ac->adid, RecIOProc); |
||||
pthread_cond_destroy(&ac->cond); |
||||
pthread_mutex_destroy(&ac->mutex); |
||||
free(ac->buf); |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int startwrite(sox_format_t * ft) |
||||
{ |
||||
return setup(ft, 0); |
||||
} |
||||
|
||||
static size_t write_samples(sox_format_t *ft, const sox_sample_t *buf, size_t nsamp) |
||||
{ |
||||
priv_t *ac = (priv_t *)ft->priv; |
||||
size_t i; |
||||
|
||||
SOX_SAMPLE_LOCALS; |
||||
|
||||
pthread_mutex_lock(&ac->mutex); |
||||
|
||||
/* Wait to start until mutex is locked to help prevent callback
|
||||
* getting zero samples. |
||||
*/ |
||||
if(!ac->device_started){ |
||||
if(AudioDeviceStart(ac->adid, PlaybackIOProc)){ |
||||
pthread_mutex_unlock(&ac->mutex); |
||||
return SOX_EOF; |
||||
} |
||||
ac->device_started = 1; |
||||
} |
||||
|
||||
/* globals.bufsize is in samples
|
||||
* buf_offset is in bytes |
||||
* buf_size is in bytes |
||||
*/ |
||||
for(i = 0; i < nsamp; i++){ |
||||
while(ac->bufrdavail == ac->bufsize - 1) |
||||
pthread_cond_wait(&ac->cond, &ac->mutex); |
||||
|
||||
ac->buf[ac->bufwr] = SOX_SAMPLE_TO_FLOAT_32BIT(buf[i], ft->clips); |
||||
ac->bufwr++; |
||||
if(ac->bufwr == ac->bufsize) |
||||
ac->bufwr = 0; |
||||
ac->bufrdavail++; |
||||
} |
||||
|
||||
pthread_mutex_unlock(&ac->mutex); |
||||
return nsamp; |
||||
} |
||||
|
||||
|
||||
static int stopwrite(sox_format_t * ft) |
||||
{ |
||||
priv_t *ac = (priv_t *)ft->priv; |
||||
|
||||
if(ac->device_started){ |
||||
pthread_mutex_lock(&ac->mutex); |
||||
|
||||
while (ac->bufrdavail > 0) |
||||
pthread_cond_wait(&ac->cond, &ac->mutex); |
||||
|
||||
pthread_mutex_unlock(&ac->mutex); |
||||
|
||||
AudioDeviceStop(ac->adid, PlaybackIOProc); |
||||
} |
||||
|
||||
AudioDeviceRemoveIOProc(ac->adid, PlaybackIOProc); |
||||
pthread_cond_destroy(&ac->cond); |
||||
pthread_mutex_destroy(&ac->mutex); |
||||
free(ac->buf); |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
LSX_FORMAT_HANDLER(coreaudio) |
||||
{ |
||||
static char const *const names[] = { "coreaudio", NULL }; |
||||
static unsigned const write_encodings[] = { |
||||
SOX_ENCODING_FLOAT, 32, 0, |
||||
0}; |
||||
static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, |
||||
"Mac AudioCore device driver", |
||||
names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO, |
||||
startread, read_samples, stopread, |
||||
startwrite, write_samples, stopwrite, |
||||
NULL, write_encodings, NULL, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,165 +0,0 @@ |
||||
/* libSoX dcshift.c
|
||||
* (c) 2000.04.15 Chris Ausbrooks <weed@bucket.pp.ualr.edu> |
||||
* |
||||
* based on vol.c which is |
||||
* (c) 20/03/2000 Fabien COELHO <fabien@coelho.net> for sox. |
||||
* |
||||
* DC shift a sound file, with basic linear amplitude formula. |
||||
* Beware of saturations! clipping is checked and reported. |
||||
* Cannot handle different number of channels. |
||||
* Cannot handle rate change. |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
typedef struct { |
||||
double dcshift; /* DC shift. */ |
||||
int uselimiter; /* boolean: are we using the limiter? */ |
||||
double limiterthreshhold; |
||||
double limitergain; /* limiter gain. */ |
||||
uint64_t limited; /* number of limited values to report. */ |
||||
uint64_t totalprocessed; |
||||
} priv_t; |
||||
|
||||
/*
|
||||
* Process options: dcshift (double) type (amplitude, power, dB) |
||||
*/ |
||||
static int sox_dcshift_getopts(sox_effect_t * effp, int argc, char **argv) |
||||
{ |
||||
priv_t * dcs = (priv_t *) effp->priv; |
||||
dcs->dcshift = 1.0; /* default is no change */ |
||||
dcs->uselimiter = 0; /* default is no limiter */ |
||||
|
||||
--argc, ++argv; |
||||
if (argc < 1) |
||||
return lsx_usage(effp); |
||||
|
||||
if (argc && (!sscanf(argv[0], "%lf", &dcs->dcshift))) |
||||
return lsx_usage(effp); |
||||
|
||||
if (argc>1) |
||||
{ |
||||
if (!sscanf(argv[1], "%lf", &dcs->limitergain)) |
||||
return lsx_usage(effp); |
||||
|
||||
dcs->uselimiter = 1; /* ok, we'll use it */ |
||||
/* The following equation is derived so that there is no
|
||||
* discontinuity in output amplitudes */ |
||||
/* and a SOX_SAMPLE_MAX input always maps to a SOX_SAMPLE_MAX output
|
||||
* when the limiter is activated. */ |
||||
/* (NOTE: There **WILL** be a discontinuity in the slope of the
|
||||
* output amplitudes when using the limiter.) */ |
||||
dcs->limiterthreshhold = SOX_SAMPLE_MAX * (1.0 - (fabs(dcs->dcshift) - dcs->limitergain)); |
||||
} |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Start processing |
||||
*/ |
||||
static int sox_dcshift_start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * dcs = (priv_t *) effp->priv; |
||||
|
||||
if (dcs->dcshift == 0) |
||||
return SOX_EFF_NULL; |
||||
|
||||
dcs->limited = 0; |
||||
dcs->totalprocessed = 0; |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Process data. |
||||
*/ |
||||
static int sox_dcshift_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, |
||||
size_t *isamp, size_t *osamp) |
||||
{ |
||||
priv_t * dcs = (priv_t *) effp->priv; |
||||
double dcshift = dcs->dcshift; |
||||
double limitergain = dcs->limitergain; |
||||
double limiterthreshhold = dcs->limiterthreshhold; |
||||
double sample; |
||||
size_t len; |
||||
|
||||
len = min(*osamp, *isamp); |
||||
|
||||
/* report back dealt with amount. */ |
||||
*isamp = len; *osamp = len; |
||||
|
||||
if (dcs->uselimiter) |
||||
{ |
||||
dcs->totalprocessed += len; |
||||
|
||||
for (;len>0; len--) |
||||
{ |
||||
sample = *ibuf++; |
||||
|
||||
if (sample > limiterthreshhold && dcshift > 0) |
||||
{ |
||||
sample = (sample - limiterthreshhold) * limitergain / (SOX_SAMPLE_MAX - limiterthreshhold) + limiterthreshhold + dcshift; |
||||
dcs->limited++; |
||||
} |
||||
else if (sample < -limiterthreshhold && dcshift < 0) |
||||
{ |
||||
/* Note this should really be SOX_SAMPLE_MIN but
|
||||
* the clip() below will take care of the overflow. |
||||
*/ |
||||
sample = (sample + limiterthreshhold) * limitergain / (SOX_SAMPLE_MAX - limiterthreshhold) - limiterthreshhold + dcshift; |
||||
dcs->limited++; |
||||
} |
||||
else |
||||
{ |
||||
/* Note this should consider SOX_SAMPLE_MIN but
|
||||
* the clip() below will take care of the overflow. |
||||
*/ |
||||
sample = dcshift * SOX_SAMPLE_MAX + sample; |
||||
} |
||||
|
||||
SOX_SAMPLE_CLIP_COUNT(sample, effp->clips); |
||||
*obuf++ = sample; |
||||
} |
||||
} |
||||
else for (; len > 0; --len) { /* quite basic, with clipping */ |
||||
double d = dcshift * (SOX_SAMPLE_MAX + 1.) + *ibuf++; |
||||
*obuf++ = SOX_ROUND_CLIP_COUNT(d, effp->clips); |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Do anything required when you stop reading samples. |
||||
* Don't close input file! |
||||
*/ |
||||
static int sox_dcshift_stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * dcs = (priv_t *) effp->priv; |
||||
|
||||
if (dcs->limited) |
||||
{ |
||||
lsx_warn("DCSHIFT limited %" PRIu64 " values (%d percent).", |
||||
dcs->limited, (int) (dcs->limited * 100.0 / dcs->totalprocessed)); |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static sox_effect_handler_t sox_dcshift_effect = { |
||||
"dcshift", |
||||
"shift [ limitergain ]\n" |
||||
"\tThe peak limiter has a gain much less than 1.0 (ie 0.05 or 0.02) which\n" |
||||
"\tis only used on peaks to prevent clipping. (default is no limiter)", |
||||
SOX_EFF_MCHAN | SOX_EFF_GAIN, |
||||
sox_dcshift_getopts, |
||||
sox_dcshift_start, |
||||
sox_dcshift_flow, |
||||
NULL, |
||||
sox_dcshift_stop, |
||||
NULL, sizeof(priv_t) |
||||
}; |
||||
|
||||
const sox_effect_handler_t *lsx_dcshift_effect_fn(void) |
||||
{ |
||||
return &sox_dcshift_effect; |
||||
} |
@ -1,137 +0,0 @@ |
||||
/* Abstract effect: dft filter Copyright (c) 2008 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "fft4g.h" |
||||
#include "dft_filter.h" |
||||
#include <string.h> |
||||
|
||||
typedef dft_filter_t filter_t; |
||||
typedef dft_filter_priv_t priv_t; |
||||
|
||||
void lsx_set_dft_filter(dft_filter_t *f, double *h, int n, int post_peak) |
||||
{ |
||||
int i; |
||||
f->num_taps = n; |
||||
f->post_peak = post_peak; |
||||
f->dft_length = lsx_set_dft_length(f->num_taps); |
||||
f->coefs = lsx_calloc(f->dft_length, sizeof(*f->coefs)); |
||||
for (i = 0; i < f->num_taps; ++i) |
||||
f->coefs[(i + f->dft_length - f->num_taps + 1) & (f->dft_length - 1)] = h[i] / f->dft_length * 2; |
||||
lsx_safe_rdft(f->dft_length, 1, f->coefs); |
||||
free(h); |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
|
||||
fifo_create(&p->input_fifo, (int)sizeof(double)); |
||||
memset(fifo_reserve(&p->input_fifo, |
||||
p->filter_ptr->post_peak), 0, sizeof(double) * p->filter_ptr->post_peak); |
||||
fifo_create(&p->output_fifo, (int)sizeof(double)); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static void filter(priv_t * p) |
||||
{ |
||||
int i, num_in = max(0, fifo_occupancy(&p->input_fifo)); |
||||
filter_t const * f = p->filter_ptr; |
||||
int const overlap = f->num_taps - 1; |
||||
double * output; |
||||
|
||||
while (num_in >= f->dft_length) { |
||||
double const * input = fifo_read_ptr(&p->input_fifo); |
||||
fifo_read(&p->input_fifo, f->dft_length - overlap, NULL); |
||||
num_in -= f->dft_length - overlap; |
||||
|
||||
output = fifo_reserve(&p->output_fifo, f->dft_length); |
||||
fifo_trim_by(&p->output_fifo, overlap); |
||||
memcpy(output, input, f->dft_length * sizeof(*output)); |
||||
|
||||
lsx_safe_rdft(f->dft_length, 1, output); |
||||
output[0] *= f->coefs[0]; |
||||
output[1] *= f->coefs[1]; |
||||
for (i = 2; i < f->dft_length; i += 2) { |
||||
double tmp = output[i]; |
||||
output[i ] = f->coefs[i ] * tmp - f->coefs[i+1] * output[i+1]; |
||||
output[i+1] = f->coefs[i+1] * tmp + f->coefs[i ] * output[i+1]; |
||||
} |
||||
lsx_safe_rdft(f->dft_length, -1, output); |
||||
} |
||||
} |
||||
|
||||
static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, |
||||
sox_sample_t * obuf, size_t * isamp, size_t * osamp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
size_t odone = min(*osamp, (size_t)fifo_occupancy(&p->output_fifo)); |
||||
|
||||
double const * s = fifo_read(&p->output_fifo, (int)odone, NULL); |
||||
lsx_save_samples(obuf, s, odone, &effp->clips); |
||||
p->samples_out += odone; |
||||
|
||||
if (*isamp && odone < *osamp) { |
||||
double * t = fifo_write(&p->input_fifo, (int)*isamp, NULL); |
||||
p->samples_in += *isamp; |
||||
lsx_load_samples(t, ibuf, *isamp); |
||||
filter(p); |
||||
} |
||||
else *isamp = 0; |
||||
*osamp = odone; |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
static size_t isamp = 0; |
||||
size_t remaining = p->samples_in > p->samples_out ? |
||||
(size_t)(p->samples_in - p->samples_out) : 0; |
||||
double * buff = lsx_calloc(1024, sizeof(*buff)); |
||||
|
||||
if (remaining > 0) { |
||||
while ((size_t)fifo_occupancy(&p->output_fifo) < remaining) { |
||||
fifo_write(&p->input_fifo, 1024, buff); |
||||
p->samples_in += 1024; |
||||
filter(p); |
||||
} |
||||
fifo_trim_to(&p->output_fifo, (int)remaining); |
||||
p->samples_in = 0; |
||||
} |
||||
free(buff); |
||||
return flow(effp, 0, obuf, &isamp, osamp); |
||||
} |
||||
|
||||
static int stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
|
||||
fifo_delete(&p->input_fifo); |
||||
fifo_delete(&p->output_fifo); |
||||
free(p->filter_ptr->coefs); |
||||
memset(p->filter_ptr, 0, sizeof(*p->filter_ptr)); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_dft_filter_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
NULL, NULL, SOX_EFF_GAIN, NULL, start, flow, drain, stop, NULL, 0 |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,16 +0,0 @@ |
||||
#include "fft4g.h" |
||||
#define FIFO_SIZE_T int |
||||
#include "fifo.h" |
||||
|
||||
typedef struct { |
||||
int dft_length, num_taps, post_peak; |
||||
double * coefs; |
||||
} dft_filter_t; |
||||
|
||||
typedef struct { |
||||
uint64_t samples_in, samples_out; |
||||
fifo_t input_fifo, output_fifo; |
||||
dft_filter_t filter, * filter_ptr; |
||||
} dft_filter_priv_t; |
||||
|
||||
void lsx_set_dft_filter(dft_filter_t * f, double * h, int n, int post_peak); |
@ -1,436 +0,0 @@ |
||||
/* Effect: dither/noise-shape Copyright (c) 2008-9 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#ifdef NDEBUG /* Enable assert always. */ |
||||
#undef NDEBUG /* Must undef above assert.h or other that might include it. */ |
||||
#endif |
||||
|
||||
#include "sox_i.h" |
||||
#include <assert.h> |
||||
|
||||
#undef RANQD1 |
||||
#define RANQD1 ranqd1(p->ranqd1) |
||||
|
||||
typedef enum { /* Collection of various filters from the net */ |
||||
Shape_none, Shape_lipshitz, Shape_f_weighted, Shape_modified_e_weighted, |
||||
Shape_improved_e_weighted, Shape_gesemann, Shape_shibata, Shape_low_shibata, Shape_high_shibata |
||||
} filter_name_t; |
||||
static lsx_enum_item const filter_names[] = { |
||||
LSX_ENUM_ITEM(Shape_,none) |
||||
LSX_ENUM_ITEM(Shape_,lipshitz) |
||||
{"f-weighted", Shape_f_weighted}, |
||||
{"modified-e-weighted", Shape_modified_e_weighted}, |
||||
{"improved-e-weighted", Shape_improved_e_weighted}, |
||||
LSX_ENUM_ITEM(Shape_,gesemann) |
||||
LSX_ENUM_ITEM(Shape_,shibata) |
||||
{"low-shibata", Shape_low_shibata}, |
||||
{"high-shibata", Shape_high_shibata}, |
||||
{0, 0}}; |
||||
|
||||
typedef struct { |
||||
sox_rate_t rate; |
||||
enum {fir, iir} type; |
||||
size_t len; |
||||
int gain_cB; /* Chosen so clips are few if any, but not guaranteed none. */ |
||||
double const * coefs; |
||||
filter_name_t name; |
||||
} filter_t; |
||||
|
||||
static double const lip44[] = {2.033, -2.165, 1.959, -1.590, .6149}; |
||||
static double const fwe44[] = { |
||||
2.412, -3.370, 3.937, -4.174, 3.353, -2.205, 1.281, -.569, .0847}; |
||||
static double const mew44[] = { |
||||
1.662, -1.263, .4827, -.2913, .1268, -.1124, .03252, -.01265, -.03524}; |
||||
static double const iew44[] = { |
||||
2.847, -4.685, 6.214, -7.184, 6.639, -5.032, 3.263, -1.632, .4191}; |
||||
static double const ges44[] = { |
||||
2.2061, -.4706, -.2534, -.6214, 1.0587, .0676, -.6054, -.2738}; |
||||
static double const ges48[] = { |
||||
2.2374, -.7339, -.1251, -.6033, .903, .0116, -.5853, -.2571}; |
||||
|
||||
static double const shi48[] = { |
||||
2.8720729351043701172, -5.0413231849670410156, 6.2442994117736816406, |
||||
-5.8483986854553222656, 3.7067542076110839844, -1.0495119094848632812, |
||||
-1.1830236911773681641, 2.1126792430877685547, -1.9094531536102294922, |
||||
0.99913084506988525391, -0.17090806365013122559, -0.32615602016448974609, |
||||
0.39127644896507263184, -0.26876461505889892578, 0.097676105797290802002, |
||||
-0.023473845794796943665, |
||||
}; |
||||
static double const shi44[] = { |
||||
2.6773197650909423828, -4.8308925628662109375, 6.570110321044921875, |
||||
-7.4572014808654785156, 6.7263274192810058594, -4.8481650352478027344, |
||||
2.0412089824676513672, 0.7006359100341796875, -2.9537565708160400391, |
||||
4.0800385475158691406, -4.1845216751098632812, 3.3311812877655029297, |
||||
-2.1179926395416259766, 0.879302978515625, -0.031759146600961685181, |
||||
-0.42382788658142089844, 0.47882103919982910156, -0.35490813851356506348, |
||||
0.17496839165687561035, -0.060908168554306030273, |
||||
}; |
||||
static double const shi38[] = { |
||||
1.6335992813110351562, -2.2615492343902587891, 2.4077029228210449219, |
||||
-2.6341717243194580078, 2.1440362930297851562, -1.8153258562088012695, |
||||
1.0816224813461303711, -0.70302653312683105469, 0.15991993248462677002, |
||||
0.041549518704414367676, -0.29416576027870178223, 0.2518316805362701416, |
||||
-0.27766478061676025391, 0.15785403549671173096, -0.10165894031524658203, |
||||
0.016833892092108726501, |
||||
}; |
||||
static double const shi32[] = |
||||
{ /* dmaker 32000: bestmax=4.99659 (inverted) */ |
||||
0.82118552923202515, |
||||
-1.0063692331314087, |
||||
0.62341964244842529, |
||||
-1.0447187423706055, |
||||
0.64532512426376343, |
||||
-0.87615132331848145, |
||||
0.52219754457473755, |
||||
-0.67434263229370117, |
||||
0.44954317808151245, |
||||
-0.52557498216629028, |
||||
0.34567299485206604, |
||||
-0.39618203043937683, |
||||
0.26791760325431824, |
||||
-0.28936097025871277, |
||||
0.1883765310049057, |
||||
-0.19097308814525604, |
||||
0.10431359708309174, |
||||
-0.10633844882249832, |
||||
0.046832218766212463, |
||||
-0.039653312414884567, |
||||
}; |
||||
static double const shi22[] = |
||||
{ /* dmaker 22050: bestmax=5.77762 (inverted) */ |
||||
0.056581053882837296, |
||||
-0.56956905126571655, |
||||
-0.40727734565734863, |
||||
-0.33870288729667664, |
||||
-0.29810553789138794, |
||||
-0.19039161503314972, |
||||
-0.16510021686553955, |
||||
-0.13468159735202789, |
||||
-0.096633769571781158, |
||||
-0.081049129366874695, |
||||
-0.064953058958053589, |
||||
-0.054459091275930405, |
||||
-0.043378707021474838, |
||||
-0.03660014271736145, |
||||
-0.026256965473294258, |
||||
-0.018786206841468811, |
||||
-0.013387725688517094, |
||||
-0.0090983230620622635, |
||||
-0.0026585909072309732, |
||||
-0.00042083300650119781, |
||||
}; |
||||
static double const shi16[] = |
||||
{ /* dmaker 16000: bestmax=5.97128 (inverted) */ |
||||
-0.37251132726669312, |
||||
-0.81423574686050415, |
||||
-0.55010956525802612, |
||||
-0.47405767440795898, |
||||
-0.32624706625938416, |
||||
-0.3161766529083252, |
||||
-0.2286367267370224, |
||||
-0.22916607558727264, |
||||
-0.19565616548061371, |
||||
-0.18160104751586914, |
||||
-0.15423151850700378, |
||||
-0.14104481041431427, |
||||
-0.11844276636838913, |
||||
-0.097583092749118805, |
||||
-0.076493598520755768, |
||||
-0.068106919527053833, |
||||
-0.041881654411554337, |
||||
-0.036922425031661987, |
||||
-0.019364040344953537, |
||||
-0.014994367957115173, |
||||
}; |
||||
static double const shi11[] = |
||||
{ /* dmaker 11025: bestmax=5.9406 (inverted) */ |
||||
-0.9264228343963623, |
||||
-0.98695987462997437, |
||||
-0.631156325340271, |
||||
-0.51966935396194458, |
||||
-0.39738872647285461, |
||||
-0.35679301619529724, |
||||
-0.29720726609230042, |
||||
-0.26310476660728455, |
||||
-0.21719355881214142, |
||||
-0.18561814725399017, |
||||
-0.15404847264289856, |
||||
-0.12687471508979797, |
||||
-0.10339745879173279, |
||||
-0.083688631653785706, |
||||
-0.05875682458281517, |
||||
-0.046893671154975891, |
||||
-0.027950936928391457, |
||||
-0.020740609616041183, |
||||
-0.009366452693939209, |
||||
-0.0060260160826146603, |
||||
}; |
||||
static double const shi08[] = |
||||
{ /* dmaker 8000: bestmax=5.56234 (inverted) */ |
||||
-1.202863335609436, |
||||
-0.94103097915649414, |
||||
-0.67878556251525879, |
||||
-0.57650017738342285, |
||||
-0.50004476308822632, |
||||
-0.44349345564842224, |
||||
-0.37833768129348755, |
||||
-0.34028723835945129, |
||||
-0.29413089156150818, |
||||
-0.24994957447052002, |
||||
-0.21715600788593292, |
||||
-0.18792112171649933, |
||||
-0.15268312394618988, |
||||
-0.12135542929172516, |
||||
-0.099610626697540283, |
||||
-0.075273610651493073, |
||||
-0.048787496984004974, |
||||
-0.042586319148540497, |
||||
-0.028991291299462318, |
||||
-0.011869125068187714, |
||||
}; |
||||
static double const shl48[] = { |
||||
2.3925774097442626953, -3.4350297451019287109, 3.1853709220886230469, |
||||
-1.8117271661758422852, -0.20124770700931549072, 1.4759907722473144531, |
||||
-1.7210904359817504883, 0.97746700048446655273, -0.13790138065814971924, |
||||
-0.38185903429985046387, 0.27421241998672485352, 0.066584214568138122559, |
||||
-0.35223302245140075684, 0.37672343850135803223, -0.23964276909828186035, |
||||
0.068674825131893157959, |
||||
}; |
||||
static double const shl44[] = { |
||||
2.0833916664123535156, -3.0418450832366943359, 3.2047898769378662109, |
||||
-2.7571926116943359375, 1.4978630542755126953, -0.3427594602108001709, |
||||
-0.71733748912811279297, 1.0737057924270629883, -1.0225815773010253906, |
||||
0.56649994850158691406, -0.20968692004680633545, -0.065378531813621520996, |
||||
0.10322438180446624756, -0.067442022264003753662, -0.00495197344571352005, |
||||
}; |
||||
static double const shh44[] = { |
||||
3.0259189605712890625, -6.0268716812133789062, 9.195003509521484375, |
||||
-11.824929237365722656, 12.767142295837402344, -11.917946815490722656, |
||||
9.1739168167114257812, -5.3712320327758789062, 1.1393624544143676758, |
||||
2.4484779834747314453, -4.9719839096069335938, 6.0392003059387207031, |
||||
-5.9359521865844726562, 4.903278350830078125, -3.5527443885803222656, |
||||
2.1909697055816650391, -1.1672389507293701172, 0.4903914332389831543, |
||||
-0.16519790887832641602, 0.023217858746647834778, |
||||
}; |
||||
|
||||
static const filter_t filters[] = { |
||||
{44100, fir, 5, 210, lip44, Shape_lipshitz}, |
||||
{46000, fir, 9, 276, fwe44, Shape_f_weighted}, |
||||
{46000, fir, 9, 160, mew44, Shape_modified_e_weighted}, |
||||
{46000, fir, 9, 321, iew44, Shape_improved_e_weighted}, |
||||
{48000, iir, 4, 220, ges48, Shape_gesemann}, |
||||
{44100, iir, 4, 230, ges44, Shape_gesemann}, |
||||
{48000, fir, 16, 301, shi48, Shape_shibata}, |
||||
{44100, fir, 20, 333, shi44, Shape_shibata}, |
||||
{37800, fir, 16, 240, shi38, Shape_shibata}, |
||||
{32000, fir, 20, 240/*TBD*/, shi32, Shape_shibata}, |
||||
{22050, fir, 20, 240/*TBD*/, shi22, Shape_shibata}, |
||||
{16000, fir, 20, 240/*TBD*/, shi16, Shape_shibata}, |
||||
{11025, fir, 20, 240/*TBD*/, shi11, Shape_shibata}, |
||||
{ 8000, fir, 20, 240/*TBD*/, shi08, Shape_shibata}, |
||||
{48000, fir, 16, 250, shl48, Shape_low_shibata}, |
||||
{44100, fir, 15, 250, shl44, Shape_low_shibata}, |
||||
{44100, fir, 20, 383, shh44, Shape_high_shibata}, |
||||
{ 0, fir, 0, 0, NULL, Shape_none}, |
||||
}; |
||||
|
||||
#define MAX_N 20 |
||||
|
||||
typedef struct { |
||||
filter_name_t filter_name; |
||||
sox_bool auto_detect, alt_tpdf; |
||||
double dummy; |
||||
|
||||
double previous_errors[MAX_N * 2]; |
||||
double previous_outputs[MAX_N * 2]; |
||||
size_t pos, prec; |
||||
uint64_t num_output; |
||||
int32_t history, ranqd1, r; |
||||
double const * coefs; |
||||
sox_bool dither_off; |
||||
sox_effect_handler_flow flow; |
||||
} priv_t; |
||||
|
||||
#define CONVOLVE _ _ _ _ |
||||
#define NAME flow_iir_4 |
||||
#define IIR |
||||
#define N 4 |
||||
#include "dither.h" |
||||
#undef IIR |
||||
#define CONVOLVE _ _ _ _ _ |
||||
#define NAME flow_fir_5 |
||||
#define N 5 |
||||
#include "dither.h" |
||||
#define CONVOLVE _ _ _ _ _ _ _ _ _ |
||||
#define NAME flow_fir_9 |
||||
#define N 9 |
||||
#include "dither.h" |
||||
#define CONVOLVE _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
||||
#define NAME flow_fir_15 |
||||
#define N 15 |
||||
#include "dither.h" |
||||
#define CONVOLVE _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
||||
#define NAME flow_fir_16 |
||||
#define N 16 |
||||
#include "dither.h" |
||||
#define CONVOLVE _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
||||
#define NAME flow_fir_20 |
||||
#define N 20 |
||||
#include "dither.h" |
||||
|
||||
static int flow_no_shape(sox_effect_t * effp, const sox_sample_t * ibuf, |
||||
sox_sample_t * obuf, size_t * isamp, size_t * osamp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
size_t len = *isamp = *osamp = min(*isamp, *osamp); |
||||
|
||||
while (len--) { |
||||
if (p->auto_detect) { |
||||
p->history = (p->history << 1) + |
||||
!!(*ibuf & (((unsigned)-1) >> p->prec)); |
||||
if (p->history && p->dither_off) { |
||||
p->dither_off = sox_false; |
||||
lsx_debug("flow %" PRIuPTR ": on @ %" PRIu64, effp->flow, p->num_output); |
||||
} else if (!p->history && !p->dither_off) { |
||||
p->dither_off = sox_true; |
||||
lsx_debug("flow %" PRIuPTR ": off @ %" PRIu64, effp->flow, p->num_output); |
||||
} |
||||
} |
||||
|
||||
if (!p->dither_off) { |
||||
int32_t r = RANQD1 >> p->prec; |
||||
double d = ((double)*ibuf++ + r + (p->alt_tpdf? -p->r : (RANQD1 >> p->prec))) / (1 << (32 - p->prec)); |
||||
int i = d < 0? d - .5 : d + .5; |
||||
p->r = r; |
||||
if (i <= (-1 << (p->prec-1))) |
||||
++effp->clips, *obuf = SOX_SAMPLE_MIN; |
||||
else if (i > (int)SOX_INT_MAX(p->prec)) |
||||
++effp->clips, *obuf = SOX_INT_MAX(p->prec) << (32 - p->prec); |
||||
else *obuf = i << (32 - p->prec); |
||||
++obuf; |
||||
} |
||||
else |
||||
*obuf++ = *ibuf++; |
||||
++p->num_output; |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int getopts(sox_effect_t * effp, int argc, char * * argv) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
int c; |
||||
lsx_getopt_t optstate; |
||||
lsx_getopt_init(argc, argv, "+aSsf:p:", NULL, lsx_getopt_flag_none, 1, &optstate); |
||||
|
||||
while ((c = lsx_getopt(&optstate)) != -1) switch (c) { |
||||
case 'a': p->auto_detect = sox_true; break; |
||||
case 'S': p->alt_tpdf = sox_true; break; |
||||
case 's': p->filter_name = Shape_shibata; break; |
||||
case 'f': |
||||
p->filter_name = lsx_enum_option(c, optstate.arg, filter_names); |
||||
if (p->filter_name == INT_MAX) |
||||
return SOX_EOF; |
||||
break; |
||||
GETOPT_NUMERIC(optstate, 'p', prec, 1, 24) |
||||
default: lsx_fail("invalid option `-%c'", optstate.opt); return lsx_usage(effp); |
||||
} |
||||
argc -= optstate.ind, argv += optstate.ind; |
||||
return argc? lsx_usage(effp) : SOX_SUCCESS; |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
double mult = 1; /* Amount the noise shaping multiplies up the TPDF (+/-1) */ |
||||
|
||||
if (p->prec == 0) |
||||
p->prec = effp->out_signal.precision; |
||||
|
||||
if (effp->in_signal.precision <= p->prec || p->prec > 24) |
||||
return SOX_EFF_NULL; /* Dithering not needed at this resolution */ |
||||
|
||||
if (p->prec == 1) { |
||||
/* The general dither routines don't work in this case, so notify
|
||||
user and leave it at that for now. |
||||
TODO: Some special-case treatment of 1-bit noise shaping will be |
||||
needed for meaningful DSD write support. */ |
||||
lsx_warn("Dithering/noise-shaping to 1 bit is currently not supported."); |
||||
return SOX_EFF_NULL; |
||||
} |
||||
|
||||
effp->out_signal.precision = p->prec; |
||||
|
||||
p->flow = flow_no_shape; |
||||
if (p->filter_name) { |
||||
filter_t const * f; |
||||
|
||||
for (f = filters; f->len && (f->name != p->filter_name || fabs(effp->in_signal.rate - f->rate) / f->rate > .05); ++f); /* 5% leeway on frequency */ |
||||
if (!f->len) { |
||||
p->alt_tpdf |= effp->in_signal.rate >= 22050; |
||||
if (!effp->flow) |
||||
lsx_warn("no `%s' filter is available for rate %g; using %s TPDF", |
||||
lsx_find_enum_value(p->filter_name, filter_names)->text, |
||||
effp->in_signal.rate, p->alt_tpdf? "sloped" : "plain"); |
||||
} |
||||
else { |
||||
assert(f->len <= MAX_N); |
||||
if (f->type == fir) switch(f->len) { |
||||
case 5: p->flow = flow_fir_5 ; break; |
||||
case 9: p->flow = flow_fir_9 ; break; |
||||
case 15: p->flow = flow_fir_15; break; |
||||
case 16: p->flow = flow_fir_16; break; |
||||
case 20: p->flow = flow_fir_20; break; |
||||
default: assert(sox_false); |
||||
} else switch(f->len) { |
||||
case 4: p->flow = flow_iir_4 ; break; |
||||
default: assert(sox_false); |
||||
} |
||||
p->coefs = f->coefs; |
||||
mult = dB_to_linear(f->gain_cB * 0.1); |
||||
} |
||||
} |
||||
p->ranqd1 = ranqd1(sox_globals.ranqd1) + effp->flow; |
||||
if (effp->in_signal.mult) /* (Takes account of ostart mult (sox.c). */ |
||||
*effp->in_signal.mult *= (SOX_SAMPLE_MAX - (1 << (31 - p->prec)) * |
||||
(2 * mult + 1)) / (SOX_SAMPLE_MAX - (1 << (31 - p->prec))); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, |
||||
sox_sample_t * obuf, size_t * isamp, size_t * osamp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
return p->flow(effp, ibuf, obuf, isamp, osamp); |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_dither_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"dither", "[-S|-s|-f filter] [-a] [-p precision]" |
||||
"\n (none) Use TPDF" |
||||
"\n -S Use sloped TPDF (without noise shaping)" |
||||
"\n -s Shape noise (with shibata filter)" |
||||
"\n -f name Set shaping filter to one of: lipshitz, f-weighted," |
||||
"\n modified-e-weighted, improved-e-weighted, gesemann," |
||||
"\n shibata, low-shibata, high-shibata." |
||||
"\n -a Automatically turn on & off dithering as needed (use with caution!)" |
||||
"\n -p bits Override the target sample precision", |
||||
SOX_EFF_PREC, getopts, start, flow, 0, 0, 0, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,63 +0,0 @@ |
||||
#ifdef IIR |
||||
#define _ output += p->coefs[j] * p->previous_errors[p->pos + j] \ |
||||
- p->coefs[N + j] * p->previous_outputs[p->pos + j], ++j; |
||||
#else |
||||
#define _ d -= p->coefs[j] * p->previous_errors[p->pos + j], ++j; |
||||
#endif |
||||
static int NAME(sox_effect_t * effp, const sox_sample_t * ibuf, |
||||
sox_sample_t * obuf, size_t * isamp, size_t * osamp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
size_t len = *isamp = *osamp = min(*isamp, *osamp); |
||||
|
||||
while (len--) { |
||||
if (p->auto_detect) { |
||||
p->history = (p->history << 1) + |
||||
!!(*ibuf & (((unsigned)-1) >> p->prec)); |
||||
if (p->history && p->dither_off) { |
||||
p->dither_off = sox_false; |
||||
lsx_debug("flow %" PRIuPTR ": on @ %" PRIu64, effp->flow, p->num_output); |
||||
} else if (!p->history && !p->dither_off) { |
||||
p->dither_off = sox_true; |
||||
memset(p->previous_errors, 0, sizeof(p->previous_errors)); |
||||
memset(p->previous_outputs, 0, sizeof(p->previous_outputs)); |
||||
lsx_debug("flow %" PRIuPTR ": off @ %" PRIu64, effp->flow, p->num_output); |
||||
} |
||||
} |
||||
|
||||
if (!p->dither_off) { |
||||
int32_t r1 = RANQD1 >> p->prec, r2 = RANQD1 >> p->prec; /* Defer add! */ |
||||
#ifdef IIR |
||||
double d1, d, output = 0; |
||||
#else |
||||
double d1, d = *ibuf++; |
||||
#endif |
||||
int i, j = 0; |
||||
CONVOLVE |
||||
assert(j == N); |
||||
p->pos = p->pos? p->pos - 1 : p->pos - 1 + N; |
||||
#ifdef IIR |
||||
d = *ibuf++ - output; |
||||
p->previous_outputs[p->pos + N] = p->previous_outputs[p->pos] = output; |
||||
#endif |
||||
d1 = (d + r1 + r2) / (1 << (32 - p->prec)); |
||||
i = d1 < 0? d1 - .5 : d1 + .5; |
||||
p->previous_errors[p->pos + N] = p->previous_errors[p->pos] = |
||||
(double)i * (1 << (32 - p->prec)) - d; |
||||
if (i < (-1 << (p->prec-1))) |
||||
++effp->clips, *obuf = SOX_SAMPLE_MIN; |
||||
else if (i > (int)SOX_INT_MAX(p->prec)) |
||||
++effp->clips, *obuf = SOX_INT_MAX(p->prec) << (32 - p->prec); |
||||
else *obuf = i << (32 - p->prec); |
||||
++obuf; |
||||
} |
||||
else |
||||
*obuf++ = *ibuf++; |
||||
++p->num_output; |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
#undef CONVOLVE |
||||
#undef _ |
||||
#undef NAME |
||||
#undef N |
@ -1,73 +0,0 @@ |
||||
/* libSoX effect: divide Copyright (c) 2009 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
/* This is W.I.P. hence marked SOX_EFF_ALPHA for now.
|
||||
* Needs better handling of when the divisor approaches or is zero; some |
||||
* sort of interpolation of the output values perhaps. |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include <string.h> |
||||
|
||||
typedef struct { |
||||
sox_sample_t * last; |
||||
} priv_t; |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
p->last = lsx_calloc(effp->in_signal.channels, sizeof(*p->last)); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, |
||||
sox_sample_t * obuf, size_t * isamp, size_t * osamp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
size_t i, len = min(*isamp, *osamp) / effp->in_signal.channels; |
||||
*osamp = *isamp = len * effp->in_signal.channels; |
||||
|
||||
while (len--) { |
||||
double divisor = *obuf++ = *ibuf++; |
||||
if (divisor) { |
||||
double out, mult = 1. / SOX_SAMPLE_TO_FLOAT_64BIT(divisor,); |
||||
for (i = 1; i < effp->in_signal.channels; ++i) { |
||||
out = *ibuf++ * mult; |
||||
p->last[i] = *obuf++ = SOX_ROUND_CLIP_COUNT(out, effp->clips); |
||||
} |
||||
} |
||||
else for (i = 1; i < effp->in_signal.channels; ++i, ++ibuf) |
||||
*obuf++ = p->last[i]; |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
free(p->last); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_divide_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"divide", NULL, SOX_EFF_MCHAN | SOX_EFF_GAIN | SOX_EFF_ALPHA, |
||||
NULL, start, flow, NULL, stop, NULL, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,97 +0,0 @@ |
||||
/* libSoX earwax - makes listening to headphones easier November 9, 2000
|
||||
* |
||||
* Copyright (c) 2000 Edward Beingessner And Sundry Contributors. |
||||
* This source code is freely redistributable and may be used for any purpose. |
||||
* This copyright notice must be maintained. Edward Beingessner And Sundry |
||||
* Contributors are not responsible for the consequences of using this |
||||
* software. |
||||
* |
||||
* This effect takes a 44.1kHz stereo (CD format) signal that is meant to be |
||||
* listened to on headphones, and adds audio cues to move the soundstage from |
||||
* inside your head (standard for headphones) to outside and in front of the |
||||
* listener (standard for speakers). This makes the sound much easier to listen |
||||
* to on headphones. |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include <string.h> |
||||
|
||||
static const sox_sample_t filt[32 * 2] = { |
||||
/* 30° 330° */ |
||||
4, -6, /* 32 tap stereo FIR filter. */ |
||||
4, -11, /* One side filters as if the */ |
||||
-1, -5, /* signal was from 30 degrees */ |
||||
3, 3, /* from the ear, the other as */ |
||||
-2, 5, /* if 330 degrees. */ |
||||
-5, 0, |
||||
9, 1, |
||||
6, 3, /* Input */ |
||||
-4, -1, /* Left Right */ |
||||
-5, -3, /* __________ __________ */ |
||||
-2, -5, /* | | | | */ |
||||
-7, 1, /* .---| Hh,0(f) | | Hh,0(f) |---. */ |
||||
6, -7, /* / |__________| |__________| \ */ |
||||
30, -29, /* / \ / \ */ |
||||
12, -3, /* / X \ */ |
||||
-11, 4, /* / / \ \ */ |
||||
-3, 7, /* ____V_____ __________V V__________ _____V____ */ |
||||
-20, 23, /* | | | | | | | | */ |
||||
2, 0, /* | Hh,30(f) | | Hh,330(f)| | Hh,330(f)| | Hh,30(f) | */ |
||||
1, -6, /* |__________| |__________| |__________| |__________| */ |
||||
-14, -5, /* \ ___ / \ ___ / */ |
||||
15, -18, /* \ / \ / _____ \ / \ / */ |
||||
6, 7, /* `->| + |<--' / \ `-->| + |<-' */ |
||||
15, -10, /* \___/ _/ \_ \___/ */ |
||||
-14, 22, /* \ / \ / \ / */ |
||||
-7, -2, /* `--->| | | |<---' */ |
||||
-4, 9, /* \_/ \_/ */ |
||||
6, -12, /* */ |
||||
6, -6, /* Headphones */ |
||||
0, -11, |
||||
0, -5, |
||||
4, 0}; |
||||
|
||||
#define NUMTAPS array_length(filt) |
||||
typedef struct {sox_sample_t tap[NUMTAPS];} priv_t; /* FIR filter z^-1 delays */ |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
if (effp->in_signal.rate != 44100 || effp->in_signal.channels != 2) { |
||||
lsx_fail("works only with stereo audio sampled at 44100Hz (i.e. CDDA)"); |
||||
return SOX_EOF; |
||||
} |
||||
memset(p->tap, 0, NUMTAPS * sizeof(*p->tap)); /* zero tap memory */ |
||||
if (effp->in_signal.mult) |
||||
*effp->in_signal.mult *= dB_to_linear(-4.4); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, |
||||
sox_sample_t * obuf, size_t * isamp, size_t * osamp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
size_t i, len = *isamp = *osamp = min(*isamp, *osamp); |
||||
|
||||
while (len--) { /* update taps and calculate output */ |
||||
double output = 0; |
||||
|
||||
for (i = NUMTAPS - 1; i; --i) { |
||||
p->tap[i] = p->tap[i - 1]; |
||||
output += p->tap[i] * filt[i]; |
||||
} |
||||
p->tap[0] = *ibuf++ / 64; /* scale output */ |
||||
output += p->tap[0] * filt[0]; |
||||
*obuf++ = SOX_ROUND_CLIP_COUNT(output, effp->clips); |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/* No drain: preserve audio file length; it's only 32 samples anyway. */ |
||||
|
||||
sox_effect_handler_t const *lsx_earwax_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = {"earwax", NULL, SOX_EFF_MCHAN, |
||||
NULL, start, flow, NULL, NULL, NULL, sizeof(priv_t)}; |
||||
return &handler; |
||||
} |
@ -1,21 +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 |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "raw.h" |
||||
|
||||
RAW_FORMAT1(f4, "f32", 32, 0, FLOAT) |
@ -1,21 +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 |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "raw.h" |
||||
|
||||
RAW_FORMAT1(f8, "f64", 64, 0, FLOAT) |
@ -1,399 +0,0 @@ |
||||
/* Ari Moisio <armoi@sci.fi> Aug 29 2000, based on skeleton effect
|
||||
* Written by Chris Bagwell (cbagwell@sprynet.com) - March 16, 1999 |
||||
* |
||||
* Copyright 1999 Chris Bagwell And Sundry Contributors |
||||
* This source code is freely redistributable and may be used for |
||||
* any purpose. This copyright notice must be maintained. |
||||
* Chris Bagwell And Sundry Contributors are not responsible for |
||||
* the consequences of using this software. |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
/* Fade curves */ |
||||
#define FADE_QUARTER 'q' /* Quarter of sine wave, 0 to pi/2 */ |
||||
#define FADE_HALF 'h' /* Half of sine wave, pi/2 to 1.5 * pi |
||||
* scaled so that -1 means no output |
||||
* and 1 means 0 db attenuation. */ |
||||
#define FADE_LOG 'l' /* Logarithmic curve. Fades -100 db |
||||
* in given time. */ |
||||
#define FADE_TRI 't' /* Linear slope. */ |
||||
#define FADE_PAR 'p' /* Inverted parabola. */ |
||||
|
||||
#include <string.h> |
||||
|
||||
/* Private data for fade file */ |
||||
typedef struct { /* These are measured as samples */ |
||||
uint64_t in_start, in_stop, out_start, out_stop, samplesdone; |
||||
char *in_stop_str, *out_start_str, *out_stop_str; |
||||
char in_fadetype, out_fadetype; |
||||
char do_out; |
||||
int endpadwarned; |
||||
} priv_t; |
||||
|
||||
/* prototypes */ |
||||
static double fade_gain(uint64_t index, uint64_t range, int fadetype); |
||||
|
||||
/*
|
||||
* Process options |
||||
* |
||||
* Don't do initialization now. |
||||
* The 'info' fields are not yet filled in. |
||||
*/ |
||||
|
||||
static int sox_fade_getopts(sox_effect_t * effp, int argc, char **argv) |
||||
{ |
||||
|
||||
priv_t * fade = (priv_t *) effp->priv; |
||||
char t_char[2]; |
||||
int t_argno; |
||||
uint64_t samples; |
||||
const char *n; |
||||
--argc, ++argv; |
||||
|
||||
if (argc < 1 || argc > 4) |
||||
return lsx_usage(effp); |
||||
|
||||
/* because sample rate is unavailable at this point we store the
|
||||
* string off for later computations. |
||||
*/ |
||||
|
||||
if (sscanf(argv[0], "%1[qhltp]", t_char)) |
||||
{ |
||||
fade->in_fadetype = *t_char; |
||||
fade->out_fadetype = *t_char; |
||||
|
||||
argv++; |
||||
argc--; |
||||
} |
||||
else |
||||
{ |
||||
/* No type given. */ |
||||
fade->in_fadetype = 'l'; |
||||
fade->out_fadetype = 'l'; |
||||
} |
||||
|
||||
fade->in_stop_str = lsx_strdup(argv[0]); |
||||
/* Do a dummy parse to see if it will fail */ |
||||
n = lsx_parsesamples(0., fade->in_stop_str, &samples, 't'); |
||||
if (!n || *n) |
||||
return lsx_usage(effp); |
||||
|
||||
fade->in_stop = samples; |
||||
fade->out_start_str = fade->out_stop_str = 0; |
||||
|
||||
for (t_argno = 1; t_argno < argc && t_argno < 3; t_argno++) |
||||
{ |
||||
/* See if there is fade-in/fade-out times/curves specified. */ |
||||
if(t_argno == 1) |
||||
{ |
||||
fade->out_stop_str = lsx_strdup(argv[t_argno]); |
||||
|
||||
/* Do a dummy parse to see if it will fail */ |
||||
n = lsx_parseposition(0., fade->out_stop_str, NULL, (uint64_t)0, (uint64_t)0, '='); |
||||
if (!n || *n) |
||||
return lsx_usage(effp); |
||||
fade->out_stop = samples; |
||||
} |
||||
else |
||||
{ |
||||
fade->out_start_str = lsx_strdup(argv[t_argno]); |
||||
|
||||
/* Do a dummy parse to see if it will fail */ |
||||
n = lsx_parsesamples(0., fade->out_start_str, &samples, 't'); |
||||
if (!n || *n) |
||||
return lsx_usage(effp); |
||||
fade->out_start = samples; |
||||
} |
||||
} /* End for(t_argno) */ |
||||
|
||||
return(SOX_SUCCESS); |
||||
} |
||||
|
||||
/*
|
||||
* Prepare processing. |
||||
* Do all initializations. |
||||
*/ |
||||
static int sox_fade_start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * fade = (priv_t *) effp->priv; |
||||
sox_bool truncate = sox_false; |
||||
uint64_t samples; |
||||
uint64_t in_length = effp->in_signal.length != SOX_UNKNOWN_LEN ? |
||||
effp->in_signal.length / effp->in_signal.channels : SOX_UNKNOWN_LEN; |
||||
|
||||
/* converting time values to samples */ |
||||
fade->in_start = 0; |
||||
if (lsx_parsesamples(effp->in_signal.rate, fade->in_stop_str, |
||||
&samples, 't') == NULL) |
||||
return lsx_usage(effp); |
||||
|
||||
fade->in_stop = samples; |
||||
fade->do_out = 0; |
||||
/* See if user specified a stop time */ |
||||
if (fade->out_stop_str) |
||||
{ |
||||
fade->do_out = 1; |
||||
if (!lsx_parseposition(effp->in_signal.rate, fade->out_stop_str, |
||||
&samples, (uint64_t)0, in_length, '=') || |
||||
samples == SOX_UNKNOWN_LEN) { |
||||
lsx_fail("audio length is unknown"); |
||||
return SOX_EOF; |
||||
} |
||||
fade->out_stop = samples; |
||||
|
||||
if (!(truncate = !!fade->out_stop)) { |
||||
fade->out_stop = effp->in_signal.length != SOX_UNKNOWN_LEN ? |
||||
effp->in_signal.length / effp->in_signal.channels : |
||||
0; |
||||
if (!fade->out_stop) { |
||||
lsx_fail("cannot fade out: audio length is neither known nor given"); |
||||
return SOX_EOF; |
||||
} |
||||
} |
||||
|
||||
/* See if user wants to fade out. */ |
||||
if (fade->out_start_str) |
||||
{ |
||||
if (lsx_parsesamples(effp->in_signal.rate, fade->out_start_str, |
||||
&samples, 't') == NULL) |
||||
return lsx_usage(effp); |
||||
/* Fade time is relative to stop time. */ |
||||
fade->out_start = fade->out_stop - samples; |
||||
} |
||||
else |
||||
/* If user doesn't specify fade out length then
|
||||
* use same length as input side. This is stored |
||||
* in in_stop. |
||||
*/ |
||||
fade->out_start = fade->out_stop - fade->in_stop; |
||||
} |
||||
else |
||||
/* If not specified then user wants to process all
|
||||
* of file. Use a value of zero to indicate this. |
||||
*/ |
||||
fade->out_stop = 0; |
||||
|
||||
if (fade->out_start) { /* Sanity check */ |
||||
if (fade->in_stop > fade->out_start) |
||||
--fade->in_stop; /* 1 sample grace for rounding error. */ |
||||
if (fade->in_stop > fade->out_start) { |
||||
lsx_fail("fade-out overlaps fade-in"); |
||||
return SOX_EOF; |
||||
} |
||||
} |
||||
|
||||
fade->samplesdone = fade->in_start; |
||||
fade->endpadwarned = 0; |
||||
|
||||
lsx_debug("in_start = %" PRIu64 " in_stop = %" PRIu64 " " |
||||
"out_start = %" PRIu64 " out_stop = %" PRIu64, |
||||
fade->in_start, fade->in_stop, fade->out_start, fade->out_stop); |
||||
|
||||
if (fade->in_start == fade->in_stop && !truncate && |
||||
fade->out_start == fade->out_stop) |
||||
return SOX_EFF_NULL; |
||||
|
||||
effp->out_signal.length = truncate ? |
||||
fade->out_stop * effp->in_signal.channels : effp->in_signal.length; |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Processed signed long samples from ibuf to obuf. |
||||
* Return number of samples processed. |
||||
*/ |
||||
static int sox_fade_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, |
||||
size_t *isamp, size_t *osamp) |
||||
{ |
||||
priv_t * fade = (priv_t *) effp->priv; |
||||
/* len is total samples, chcnt counts channels */ |
||||
int len = 0, t_output = 1, more_output = 1; |
||||
sox_sample_t t_ibuf; |
||||
size_t chcnt = 0; |
||||
|
||||
len = ((*isamp > *osamp) ? *osamp : *isamp); |
||||
|
||||
*osamp = 0; |
||||
*isamp = 0; |
||||
|
||||
for(; len && more_output; len--) |
||||
{ |
||||
t_ibuf = *ibuf; |
||||
|
||||
if ((fade->samplesdone >= fade->in_start) && |
||||
(!fade->do_out || fade->samplesdone < fade->out_stop)) |
||||
{ /* something to generate output */ |
||||
|
||||
if (fade->samplesdone < fade->in_stop) |
||||
{ /* fade-in phase, increase gain */ |
||||
*obuf = t_ibuf * |
||||
fade_gain(fade->samplesdone - fade->in_start, |
||||
fade->in_stop - fade->in_start, |
||||
fade->in_fadetype); |
||||
} /* endif fade-in */ |
||||
else if (!fade->do_out || fade->samplesdone < fade->out_start) |
||||
{ /* steady gain phase */ |
||||
*obuf = t_ibuf; |
||||
} /* endif steady phase */ |
||||
else |
||||
{ /* fade-out phase, decrease gain */ |
||||
*obuf = t_ibuf * |
||||
fade_gain(fade->out_stop - fade->samplesdone, |
||||
fade->out_stop - fade->out_start, |
||||
fade->out_fadetype); |
||||
} /* endif fade-out */ |
||||
|
||||
if (!(!fade->do_out || fade->samplesdone < fade->out_stop)) |
||||
more_output = 0; |
||||
|
||||
t_output = 1; |
||||
} |
||||
else |
||||
{ /* No output generated */ |
||||
t_output = 0; |
||||
} /* endif something to output */ |
||||
|
||||
*isamp += 1; |
||||
ibuf++; |
||||
|
||||
if (t_output) |
||||
{ /* Output generated, update pointers and counters */ |
||||
obuf++; |
||||
*osamp += 1; |
||||
} /* endif t_output */ |
||||
|
||||
/* Process next channel */ |
||||
chcnt++; |
||||
if (chcnt >= effp->in_signal.channels) |
||||
{ /* all channels of this sample processed */ |
||||
chcnt = 0; |
||||
fade->samplesdone += 1; |
||||
} /* endif all channels */ |
||||
} /* endfor */ |
||||
|
||||
/* If not more samples will be returned, let application know
|
||||
* this. |
||||
*/ |
||||
if (fade->do_out && fade->samplesdone >= fade->out_stop) |
||||
return SOX_EOF; |
||||
else |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Drain out remaining samples if the effect generates any. |
||||
*/ |
||||
static int sox_fade_drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp) |
||||
{ |
||||
priv_t * fade = (priv_t *) effp->priv; |
||||
int len; |
||||
size_t t_chan = 0; |
||||
|
||||
len = *osamp; |
||||
len -= len % effp->in_signal.channels; |
||||
*osamp = 0; |
||||
|
||||
if (fade->do_out && fade->samplesdone < fade->out_stop && |
||||
!(fade->endpadwarned)) |
||||
{ /* Warning about padding silence into end of sample */ |
||||
lsx_warn("End time past end of audio. Padding with silence"); |
||||
fade->endpadwarned = 1; |
||||
} /* endif endpadwarned */ |
||||
|
||||
for (;len && (fade->do_out && |
||||
fade->samplesdone < fade->out_stop); len--) |
||||
{ |
||||
*obuf = 0; |
||||
obuf++; |
||||
*osamp += 1; |
||||
|
||||
t_chan++; |
||||
if (t_chan >= effp->in_signal.channels) |
||||
{ |
||||
fade->samplesdone += 1; |
||||
t_chan = 0; |
||||
} /* endif channels */ |
||||
} /* endfor */ |
||||
|
||||
if (fade->do_out && fade->samplesdone >= fade->out_stop) |
||||
return SOX_EOF; |
||||
else |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Do anything required when you stop reading samples. |
||||
* (free allocated memory, etc.) |
||||
*/ |
||||
static int lsx_kill(sox_effect_t * effp) |
||||
{ |
||||
priv_t * fade = (priv_t *) effp->priv; |
||||
|
||||
free(fade->in_stop_str); |
||||
free(fade->out_start_str); |
||||
free(fade->out_stop_str); |
||||
return (SOX_SUCCESS); |
||||
} |
||||
|
||||
/* Function returns gain value 0.0 - 1.0 according index / range ratio
|
||||
* and -1.0 if type is invalid |
||||
* todo: to optimize performance calculate gain every now and then and interpolate */ |
||||
static double fade_gain(uint64_t index, uint64_t range, int type) |
||||
{ |
||||
double retval = 0.0, findex = 0.0; |
||||
|
||||
/* TODO: does it really have to be contrained to [0.0, 1.0]? */ |
||||
findex = max(0.0, min(1.0, 1.0 * index / range)); |
||||
|
||||
switch (type) { |
||||
case FADE_TRI : /* triangle */ |
||||
retval = findex; |
||||
break; |
||||
|
||||
case FADE_QUARTER : /* quarter of sinewave */ |
||||
retval = sin(findex * M_PI / 2); |
||||
break; |
||||
|
||||
case FADE_HALF : /* half of sinewave... eh cosine wave */ |
||||
retval = (1 - cos(findex * M_PI )) / 2 ; |
||||
break; |
||||
|
||||
case FADE_LOG : /* logarithmic */ |
||||
/* 5 means 100 db attenuation. */ |
||||
/* TODO: should this be adopted with bit depth */ |
||||
retval = pow(0.1, (1 - findex) * 5); |
||||
break; |
||||
|
||||
case FADE_PAR : /* inverted parabola */ |
||||
retval = (1 - (1 - findex) * (1 - findex)); |
||||
break; |
||||
|
||||
/* TODO: more fade curves? */ |
||||
default : /* Error indicating wrong fade curve */ |
||||
retval = -1.0; |
||||
break; |
||||
} |
||||
|
||||
return retval; |
||||
} |
||||
|
||||
static sox_effect_handler_t sox_fade_effect = { |
||||
"fade", |
||||
"[ type ] fade-in-length [ stop-position [ fade-out-length ] ]\n" |
||||
" Time is in hh:mm:ss.frac format.\n" |
||||
" Fade type one of q, h, t, l or p.", |
||||
SOX_EFF_MCHAN | SOX_EFF_LENGTH, |
||||
sox_fade_getopts, |
||||
sox_fade_start, |
||||
sox_fade_flow, |
||||
sox_fade_drain, |
||||
NULL, |
||||
lsx_kill, sizeof(priv_t) |
||||
}; |
||||
|
||||
const sox_effect_handler_t *lsx_fade_effect_fn(void) |
||||
{ |
||||
return &sox_fade_effect; |
||||
} |
@ -1,31 +0,0 @@ |
||||
/* libSoX file format: FAP Copyright (c) 2008 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
LSX_FORMAT_HANDLER(fap) |
||||
{ |
||||
static char const * const names[] = {"fap", NULL}; |
||||
static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 24, 16, 8,0,0}; |
||||
static sox_format_handler_t handler; |
||||
handler = *lsx_sndfile_format_fn(); |
||||
handler.description = |
||||
"Ensoniq PARIS digital audio editing system (little endian)"; |
||||
handler.names = names; |
||||
handler.write_formats = write_encodings; |
||||
return &handler; |
||||
} |
@ -1,105 +0,0 @@ |
||||
/* Effect: fir filter from coefs Copyright (c) 2009 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "dft_filter.h" |
||||
|
||||
typedef struct { |
||||
dft_filter_priv_t base; |
||||
char const * filename; |
||||
double * h; |
||||
int n; |
||||
} priv_t; |
||||
|
||||
static int create(sox_effect_t * effp, int argc, char * * argv) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
dft_filter_priv_t * b = &p->base; |
||||
double d; |
||||
char c; |
||||
|
||||
b->filter_ptr = &b->filter; |
||||
--argc, ++argv; |
||||
if (!argc) |
||||
p->filename = "-"; /* default to stdin */ |
||||
else if (argc == 1) |
||||
p->filename = argv[0], --argc; |
||||
else for (; argc && sscanf(*argv, "%lf%c", &d, &c) == 1; --argc, ++argv) { |
||||
p->n++; |
||||
p->h = lsx_realloc(p->h, p->n * sizeof(*p->h)); |
||||
p->h[p->n - 1] = d; |
||||
} |
||||
return argc? lsx_usage(effp) : SOX_SUCCESS; |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
dft_filter_t * f = p->base.filter_ptr; |
||||
double d; |
||||
char c; |
||||
int i; |
||||
|
||||
if (!f->num_taps) { |
||||
if (!p->n && p->filename) { |
||||
FILE * file = lsx_open_input_file(effp, p->filename, sox_true); |
||||
if (!file) |
||||
return SOX_EOF; |
||||
while ((i = fscanf(file, " #%*[^\n]%c", &c)) >= 0) { |
||||
if (i >= 1) continue; /* found and skipped a comment */ |
||||
if ((i = fscanf(file, "%lf", &d)) > 0) { |
||||
/* found a coefficient value */ |
||||
p->n++; |
||||
p->h = lsx_realloc(p->h, p->n * sizeof(*p->h)); |
||||
p->h[p->n - 1] = d; |
||||
} else break; /* either EOF, or something went wrong
|
||||
(read or syntax error) */ |
||||
} |
||||
if (!feof(file)) { |
||||
lsx_fail("error reading coefficient file"); |
||||
if (file != stdin) fclose(file); |
||||
return SOX_EOF; |
||||
} |
||||
if (file != stdin) fclose(file); |
||||
} |
||||
lsx_report("%i coefficients", p->n); |
||||
if (!p->n) |
||||
return SOX_EFF_NULL; |
||||
if (effp->global_info->plot != sox_plot_off) { |
||||
char title[100]; |
||||
sprintf(title, "SoX effect: fir (%d coefficients)", p->n); |
||||
lsx_plot_fir(p->h, p->n, effp->in_signal.rate, |
||||
effp->global_info->plot, title, -30., 30.); |
||||
free(p->h); |
||||
return SOX_EOF; |
||||
} |
||||
lsx_set_dft_filter(f, p->h, p->n, p->n >> 1); |
||||
} |
||||
return lsx_dft_filter_effect_fn()->start(effp); |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_fir_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler; |
||||
handler = *lsx_dft_filter_effect_fn(); |
||||
handler.name = "fir"; |
||||
handler.usage = "[coef-file|coefs]"; |
||||
handler.getopts = create; |
||||
handler.start = start; |
||||
handler.priv_size = sizeof(priv_t); |
||||
return &handler; |
||||
} |
@ -1,145 +0,0 @@ |
||||
/* Effect: firfit filter Copyright (c) 2009 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
/* This is W.I.P. hence marked SOX_EFF_ALPHA for now.
|
||||
* Need to add other interpolation types e.g. linear, bspline, window types, |
||||
* and filter length, maybe phase response type too. |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "dft_filter.h" |
||||
|
||||
typedef struct { |
||||
dft_filter_priv_t base; |
||||
char const * filename; |
||||
struct {double f, gain;} * knots; |
||||
int num_knots, n; |
||||
} priv_t; |
||||
|
||||
static int create(sox_effect_t * effp, int argc, char **argv) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
dft_filter_priv_t * b = &p->base; |
||||
b->filter_ptr = &b->filter; |
||||
--argc, ++argv; |
||||
if (argc == 1) |
||||
p->filename = argv[0], --argc; |
||||
p->n = 2047; |
||||
return argc? lsx_usage(effp) : SOX_SUCCESS; |
||||
} |
||||
|
||||
static double * make_filter(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
double * log_freqs, * gains, * d, * work, * h; |
||||
sox_rate_t rate = effp->in_signal.rate; |
||||
int i, work_len; |
||||
|
||||
lsx_valloc(log_freqs , p->num_knots); |
||||
lsx_valloc(gains, p->num_knots); |
||||
lsx_valloc(d , p->num_knots); |
||||
for (i = 0; i < p->num_knots; ++i) { |
||||
log_freqs[i] = log(max(p->knots[i].f, 1)); |
||||
gains[i] = p->knots[i].gain; |
||||
} |
||||
lsx_prepare_spline3(log_freqs, gains, p->num_knots, HUGE_VAL, HUGE_VAL, d); |
||||
|
||||
for (work_len = 8192; work_len < rate / 2; work_len <<= 1); |
||||
work = lsx_calloc(work_len + 2, sizeof(*work)); |
||||
lsx_valloc(h, p->n); |
||||
|
||||
for (i = 0; i <= work_len; i += 2) { |
||||
double f = rate * 0.5 * i / work_len; |
||||
double spl1 = f < max(p->knots[0].f, 1)? gains[0] :
|
||||
f > p->knots[p->num_knots - 1].f? gains[p->num_knots - 1] : |
||||
lsx_spline3(log_freqs, gains, d, p->num_knots, log(f)); |
||||
work[i] = dB_to_linear(spl1); |
||||
} |
||||
LSX_PACK(work, work_len); |
||||
lsx_safe_rdft(work_len, -1, work); |
||||
for (i = 0; i < p->n; ++i) |
||||
h[i] = work[(work_len - p->n / 2 + i) % work_len] * 2. / work_len; |
||||
lsx_apply_blackman_nutall(h, p->n); |
||||
|
||||
free(work); |
||||
return h; |
||||
} |
||||
|
||||
static sox_bool read_knots(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
FILE * file = lsx_open_input_file(effp, p->filename, sox_true); |
||||
sox_bool result = sox_false; |
||||
int num_converted = 1; |
||||
char c; |
||||
|
||||
if (file) { |
||||
lsx_valloc(p->knots, 1); |
||||
while (fscanf(file, " #%*[^\n]%c", &c) >= 0) { |
||||
num_converted = fscanf(file, "%lf %lf", |
||||
&p->knots[p->num_knots].f, &p->knots[p->num_knots].gain); |
||||
if (num_converted == 2) { |
||||
if (p->num_knots && p->knots[p->num_knots].f <= p->knots[p->num_knots - 1].f) { |
||||
lsx_fail("knot frequencies must be strictly increasing"); |
||||
break; |
||||
} |
||||
lsx_revalloc(p->knots, ++p->num_knots + 1); |
||||
} else if (num_converted != 0) |
||||
break; |
||||
} |
||||
lsx_report("%i knots", p->num_knots); |
||||
if (feof(file) && num_converted != 1) |
||||
result = sox_true; |
||||
else lsx_fail("error reading knot file `%s', line number %u", p->filename, 1 + p->num_knots); |
||||
if (file != stdin) |
||||
fclose(file); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
dft_filter_t * f = p->base.filter_ptr; |
||||
|
||||
if (!f->num_taps) { |
||||
double * h; |
||||
if (!p->num_knots && !read_knots(effp)) |
||||
return SOX_EOF; |
||||
h = make_filter(effp); |
||||
if (effp->global_info->plot != sox_plot_off) { |
||||
lsx_plot_fir(h, p->n, effp->in_signal.rate, |
||||
effp->global_info->plot, "SoX effect: firfit", -30., +30.); |
||||
return SOX_EOF; |
||||
} |
||||
lsx_set_dft_filter(f, h, p->n, p->n >> 1); |
||||
} |
||||
return lsx_dft_filter_effect_fn()->start(effp); |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_firfit_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler; |
||||
handler = *lsx_dft_filter_effect_fn(); |
||||
handler.name = "firfit"; |
||||
handler.usage = "[knots-file]"; |
||||
handler.flags |= SOX_EFF_ALPHA; |
||||
handler.getopts = create; |
||||
handler.start = start; |
||||
handler.priv_size = sizeof(priv_t); |
||||
return &handler; |
||||
} |
@ -1,606 +0,0 @@ |
||||
/* libSoX file format: FLAC (c) 2006-7 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
#include <string.h> |
||||
/* Next line for systems that don't define off_t when you #include
|
||||
stdio.h; apparently OS/2 has this bug */ |
||||
#include <sys/types.h> |
||||
|
||||
#include <FLAC/all.h> |
||||
|
||||
#define MAX_COMPRESSION 8 |
||||
|
||||
|
||||
typedef struct { |
||||
/* Info: */ |
||||
unsigned bits_per_sample; |
||||
unsigned channels; |
||||
unsigned sample_rate; |
||||
uint64_t total_samples; |
||||
|
||||
/* Decode buffer: */ |
||||
sox_sample_t *req_buffer; /* this may be on the stack */ |
||||
size_t number_of_requested_samples; |
||||
sox_sample_t *leftover_buf; /* heap */ |
||||
unsigned number_of_leftover_samples; |
||||
|
||||
FLAC__StreamDecoder * decoder; |
||||
FLAC__bool eof; |
||||
sox_bool seek_pending; |
||||
uint64_t seek_offset; |
||||
|
||||
/* Encode buffer: */ |
||||
FLAC__int32 * decoded_samples; |
||||
unsigned number_of_samples; |
||||
|
||||
FLAC__StreamEncoder * encoder; |
||||
FLAC__StreamMetadata * metadata[2]; |
||||
unsigned num_metadata; |
||||
} priv_t; |
||||
|
||||
|
||||
static FLAC__StreamDecoderReadStatus decoder_read_callback(FLAC__StreamDecoder const* decoder UNUSED, FLAC__byte buffer[], size_t* bytes, void* ft_data) |
||||
{ |
||||
sox_format_t* ft = (sox_format_t*)ft_data; |
||||
if(*bytes > 0) { |
||||
*bytes = lsx_readbuf(ft, buffer, *bytes); |
||||
if(lsx_error(ft)) |
||||
return FLAC__STREAM_DECODER_READ_STATUS_ABORT; |
||||
else if(*bytes == 0) |
||||
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; |
||||
else |
||||
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; |
||||
} |
||||
else |
||||
return FLAC__STREAM_DECODER_READ_STATUS_ABORT; |
||||
} |
||||
|
||||
static FLAC__StreamDecoderSeekStatus decoder_seek_callback(FLAC__StreamDecoder const* decoder UNUSED, FLAC__uint64 absolute_byte_offset, void* ft_data) |
||||
{ |
||||
sox_format_t* ft = (sox_format_t*)ft_data; |
||||
if(lsx_seeki(ft, (off_t)absolute_byte_offset, SEEK_SET) < 0) |
||||
return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; |
||||
else |
||||
return FLAC__STREAM_DECODER_SEEK_STATUS_OK; |
||||
} |
||||
|
||||
static FLAC__StreamDecoderTellStatus decoder_tell_callback(FLAC__StreamDecoder const* decoder UNUSED, FLAC__uint64* absolute_byte_offset, void* ft_data) |
||||
{ |
||||
sox_format_t* ft = (sox_format_t*)ft_data; |
||||
off_t pos; |
||||
if((pos = lsx_tell(ft)) < 0) |
||||
return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; |
||||
else { |
||||
*absolute_byte_offset = (FLAC__uint64)pos; |
||||
return FLAC__STREAM_DECODER_TELL_STATUS_OK; |
||||
} |
||||
} |
||||
|
||||
static FLAC__StreamDecoderLengthStatus decoder_length_callback(FLAC__StreamDecoder const* decoder UNUSED, FLAC__uint64* stream_length, void* ft_data) |
||||
{ |
||||
sox_format_t* ft = (sox_format_t*)ft_data; |
||||
*stream_length = lsx_filelength(ft); |
||||
return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; |
||||
} |
||||
|
||||
static FLAC__bool decoder_eof_callback(FLAC__StreamDecoder const* decoder UNUSED, void* ft_data) |
||||
{ |
||||
sox_format_t* ft = (sox_format_t*)ft_data; |
||||
return lsx_eof(ft) ? 1 : 0; |
||||
} |
||||
|
||||
static void decoder_metadata_callback(FLAC__StreamDecoder const * const flac, FLAC__StreamMetadata const * const metadata, void * const client_data) |
||||
{ |
||||
sox_format_t * ft = (sox_format_t *) client_data; |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
|
||||
(void) flac; |
||||
|
||||
if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { |
||||
p->bits_per_sample = metadata->data.stream_info.bits_per_sample; |
||||
p->channels = metadata->data.stream_info.channels; |
||||
p->sample_rate = metadata->data.stream_info.sample_rate; |
||||
p->total_samples = metadata->data.stream_info.total_samples; |
||||
} |
||||
else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { |
||||
const FLAC__StreamMetadata_VorbisComment *vc = &metadata->data.vorbis_comment; |
||||
size_t i; |
||||
|
||||
if (vc->num_comments == 0) |
||||
return; |
||||
|
||||
if (ft->oob.comments != NULL) { |
||||
lsx_warn("multiple Vorbis comment block ignored"); |
||||
return; |
||||
} |
||||
|
||||
for (i = 0; i < vc->num_comments; ++i) |
||||
if (vc->comments[i].entry) |
||||
sox_append_comment(&ft->oob.comments, (char const *) vc->comments[i].entry); |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
static void decoder_error_callback(FLAC__StreamDecoder const * const flac, FLAC__StreamDecoderErrorStatus const status, void * const client_data) |
||||
{ |
||||
sox_format_t * ft = (sox_format_t *) client_data; |
||||
|
||||
(void) flac; |
||||
|
||||
lsx_fail_errno(ft, SOX_EINVAL, "%s", FLAC__StreamDecoderErrorStatusString[status]); |
||||
} |
||||
|
||||
|
||||
|
||||
static FLAC__StreamDecoderWriteStatus decoder_write_callback(FLAC__StreamDecoder const * const flac, FLAC__Frame const * const frame, FLAC__int32 const * const buffer[], void * const client_data) |
||||
{ |
||||
sox_format_t * ft = (sox_format_t *) client_data; |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
sox_sample_t * dst = p->req_buffer; |
||||
unsigned channel; |
||||
unsigned nsamples = frame->header.blocksize; |
||||
unsigned sample = 0; |
||||
size_t actual = nsamples * p->channels; |
||||
|
||||
(void) flac; |
||||
|
||||
if (frame->header.bits_per_sample != p->bits_per_sample || frame->header.channels != p->channels || frame->header.sample_rate != p->sample_rate) { |
||||
lsx_fail_errno(ft, SOX_EINVAL, "FLAC ERROR: parameters differ between frame and header"); |
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; |
||||
} |
||||
if (dst == NULL) { |
||||
lsx_warn("FLAC ERROR: entered write callback without a buffer (SoX bug)"); |
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; |
||||
} |
||||
|
||||
/* FLAC may give us too much data, prepare the leftover buffer */ |
||||
if (actual > p->number_of_requested_samples) { |
||||
size_t to_stash = actual - p->number_of_requested_samples; |
||||
|
||||
p->leftover_buf = lsx_malloc(to_stash * sizeof(sox_sample_t)); |
||||
p->number_of_leftover_samples = to_stash; |
||||
nsamples = p->number_of_requested_samples / p->channels; |
||||
|
||||
p->req_buffer += p->number_of_requested_samples; |
||||
p->number_of_requested_samples = 0; |
||||
} else { |
||||
p->req_buffer += actual; |
||||
p->number_of_requested_samples -= actual; |
||||
} |
||||
|
||||
leftover_copy: |
||||
|
||||
for (; sample < nsamples; sample++) { |
||||
for (channel = 0; channel < p->channels; channel++) { |
||||
FLAC__int32 d = buffer[channel][sample]; |
||||
switch (p->bits_per_sample) { |
||||
case 8: *dst++ = SOX_SIGNED_8BIT_TO_SAMPLE(d,); break; |
||||
case 16: *dst++ = SOX_SIGNED_16BIT_TO_SAMPLE(d,); break; |
||||
case 24: *dst++ = SOX_SIGNED_24BIT_TO_SAMPLE(d,); break; |
||||
case 32: *dst++ = SOX_SIGNED_32BIT_TO_SAMPLE(d,); break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* copy into the leftover buffer if we've prepared it */ |
||||
if (sample < frame->header.blocksize) { |
||||
nsamples = frame->header.blocksize; |
||||
dst = p->leftover_buf; |
||||
goto leftover_copy; |
||||
} |
||||
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; |
||||
} |
||||
|
||||
|
||||
|
||||
static int start_read(sox_format_t * const ft) |
||||
{ |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
lsx_debug("API version %u", FLAC_API_VERSION_CURRENT); |
||||
p->decoder = FLAC__stream_decoder_new(); |
||||
if (p->decoder == NULL) { |
||||
lsx_fail_errno(ft, SOX_ENOMEM, "FLAC ERROR creating the decoder instance"); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
FLAC__stream_decoder_set_md5_checking(p->decoder, sox_true); |
||||
FLAC__stream_decoder_set_metadata_respond_all(p->decoder); |
||||
if (FLAC__stream_decoder_init_stream( |
||||
p->decoder, |
||||
decoder_read_callback, |
||||
ft->seekable ? decoder_seek_callback : NULL, |
||||
ft->seekable ? decoder_tell_callback : NULL, |
||||
ft->seekable ? decoder_length_callback : NULL, |
||||
ft->seekable ? decoder_eof_callback : NULL, |
||||
decoder_write_callback, |
||||
decoder_metadata_callback, |
||||
decoder_error_callback, |
||||
ft) != FLAC__STREAM_DECODER_INIT_STATUS_OK){ |
||||
lsx_fail_errno(ft, SOX_EHDR, "FLAC ERROR initialising decoder"); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
if (!FLAC__stream_decoder_process_until_end_of_metadata(p->decoder)) { |
||||
lsx_fail_errno(ft, SOX_EHDR, "FLAC ERROR whilst decoding metadata"); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
if (FLAC__stream_decoder_get_state(p->decoder) > FLAC__STREAM_DECODER_END_OF_STREAM) { |
||||
lsx_fail_errno(ft, SOX_EHDR, "FLAC ERROR during metadata decoding"); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
ft->encoding.encoding = SOX_ENCODING_FLAC; |
||||
ft->signal.rate = p->sample_rate; |
||||
ft->encoding.bits_per_sample = p->bits_per_sample; |
||||
ft->signal.channels = p->channels; |
||||
ft->signal.length = p->total_samples * p->channels; |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
|
||||
static size_t read_samples(sox_format_t * const ft, sox_sample_t * sampleBuffer, size_t const requested) |
||||
{ |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
size_t prev_requested; |
||||
|
||||
if (p->seek_pending) { |
||||
p->seek_pending = sox_false;
|
||||
|
||||
/* discard leftover decoded data */ |
||||
free(p->leftover_buf); |
||||
p->leftover_buf = NULL; |
||||
p->number_of_leftover_samples = 0; |
||||
|
||||
p->req_buffer = sampleBuffer; |
||||
p->number_of_requested_samples = requested; |
||||
|
||||
/* calls decoder_write_callback */ |
||||
if (!FLAC__stream_decoder_seek_absolute(p->decoder, (FLAC__uint64)(p->seek_offset / ft->signal.channels))) { |
||||
p->req_buffer = NULL; |
||||
return 0; |
||||
} |
||||
} else if (p->number_of_leftover_samples > 0) { |
||||
|
||||
/* small request, no need to decode more samples since we have leftovers */ |
||||
if (requested < p->number_of_leftover_samples) { |
||||
size_t req_bytes = requested * sizeof(sox_sample_t); |
||||
|
||||
memcpy(sampleBuffer, p->leftover_buf, req_bytes); |
||||
p->number_of_leftover_samples -= requested; |
||||
memmove(p->leftover_buf, (char *)p->leftover_buf + req_bytes, |
||||
(size_t)p->number_of_leftover_samples * sizeof(sox_sample_t)); |
||||
return requested; |
||||
} |
||||
|
||||
/* first, give them all of our leftover data: */ |
||||
memcpy(sampleBuffer, p->leftover_buf, |
||||
p->number_of_leftover_samples * sizeof(sox_sample_t)); |
||||
|
||||
p->req_buffer = sampleBuffer + p->number_of_leftover_samples; |
||||
p->number_of_requested_samples = requested - p->number_of_leftover_samples; |
||||
|
||||
free(p->leftover_buf); |
||||
p->leftover_buf = NULL; |
||||
p->number_of_leftover_samples = 0; |
||||
|
||||
/* continue invoking decoder below */ |
||||
} else { |
||||
p->req_buffer = sampleBuffer; |
||||
p->number_of_requested_samples = requested; |
||||
} |
||||
|
||||
/* invoke the decoder, calls decoder_write_callback */ |
||||
while ((prev_requested = p->number_of_requested_samples) && !p->eof) { |
||||
if (!FLAC__stream_decoder_process_single(p->decoder)) |
||||
break; /* error, but maybe got earlier in the loop, though */ |
||||
|
||||
/* number_of_requested_samples decrements as the decoder progresses */ |
||||
if (p->number_of_requested_samples == prev_requested) |
||||
p->eof = sox_true; |
||||
} |
||||
p->req_buffer = NULL; |
||||
|
||||
return requested - p->number_of_requested_samples; |
||||
} |
||||
|
||||
|
||||
|
||||
static int stop_read(sox_format_t * const ft) |
||||
{ |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
if (!FLAC__stream_decoder_finish(p->decoder) && p->eof) |
||||
lsx_warn("decoder MD5 checksum mismatch."); |
||||
FLAC__stream_decoder_delete(p->decoder); |
||||
|
||||
free(p->leftover_buf); |
||||
p->leftover_buf = NULL; |
||||
p->number_of_leftover_samples = 0; |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
|
||||
|
||||
static FLAC__StreamEncoderWriteStatus flac_stream_encoder_write_callback(FLAC__StreamEncoder const * const flac, const FLAC__byte buffer[], size_t const bytes, unsigned const samples, unsigned const current_frame, void * const client_data) |
||||
{ |
||||
sox_format_t * const ft = (sox_format_t *) client_data; |
||||
(void) flac, (void) samples, (void) current_frame; |
||||
|
||||
return lsx_writebuf(ft, buffer, bytes) == bytes ? FLAC__STREAM_ENCODER_WRITE_STATUS_OK : FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; |
||||
} |
||||
|
||||
|
||||
|
||||
static void flac_stream_encoder_metadata_callback(FLAC__StreamEncoder const * encoder, FLAC__StreamMetadata const * metadata, void * client_data) |
||||
{ |
||||
(void) encoder, (void) metadata, (void) client_data; |
||||
} |
||||
|
||||
|
||||
|
||||
static FLAC__StreamEncoderSeekStatus flac_stream_encoder_seek_callback(FLAC__StreamEncoder const * encoder, FLAC__uint64 absolute_byte_offset, void * client_data) |
||||
{ |
||||
sox_format_t * const ft = (sox_format_t *) client_data; |
||||
(void) encoder; |
||||
if (!ft->seekable) |
||||
return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED; |
||||
else if (lsx_seeki(ft, (off_t)absolute_byte_offset, SEEK_SET) != SOX_SUCCESS) |
||||
return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR; |
||||
else |
||||
return FLAC__STREAM_ENCODER_SEEK_STATUS_OK; |
||||
} |
||||
|
||||
|
||||
|
||||
static FLAC__StreamEncoderTellStatus flac_stream_encoder_tell_callback(FLAC__StreamEncoder const * encoder, FLAC__uint64 * absolute_byte_offset, void * client_data) |
||||
{ |
||||
sox_format_t * const ft = (sox_format_t *) client_data; |
||||
off_t pos; |
||||
(void) encoder; |
||||
if (!ft->seekable) |
||||
return FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED; |
||||
else if ((pos = lsx_tell(ft)) < 0) |
||||
return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR; |
||||
else { |
||||
*absolute_byte_offset = (FLAC__uint64)pos; |
||||
return FLAC__STREAM_ENCODER_TELL_STATUS_OK; |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
static int start_write(sox_format_t * const ft) |
||||
{ |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
FLAC__StreamEncoderInitStatus status; |
||||
unsigned compression_level = MAX_COMPRESSION; /* Default to "best" */ |
||||
|
||||
if (ft->encoding.compression != HUGE_VAL) { |
||||
compression_level = ft->encoding.compression; |
||||
if (compression_level != ft->encoding.compression || |
||||
compression_level > MAX_COMPRESSION) { |
||||
lsx_fail_errno(ft, SOX_EINVAL, |
||||
"FLAC compression level must be a whole number from 0 to %i", |
||||
MAX_COMPRESSION); |
||||
return SOX_EOF; |
||||
} |
||||
} |
||||
|
||||
p->encoder = FLAC__stream_encoder_new(); |
||||
if (p->encoder == NULL) { |
||||
lsx_fail_errno(ft, SOX_ENOMEM, "FLAC ERROR creating the encoder instance"); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
p->bits_per_sample = ft->encoding.bits_per_sample; |
||||
ft->signal.precision = ft->encoding.bits_per_sample; |
||||
|
||||
lsx_report("encoding at %i bits per sample", p->bits_per_sample); |
||||
|
||||
FLAC__stream_encoder_set_channels(p->encoder, ft->signal.channels); |
||||
FLAC__stream_encoder_set_bits_per_sample(p->encoder, p->bits_per_sample); |
||||
FLAC__stream_encoder_set_sample_rate(p->encoder, (unsigned)(ft->signal.rate + .5)); |
||||
|
||||
{ /* Check if rate is streamable: */ |
||||
static const unsigned streamable_rates[] = |
||||
{8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000}; |
||||
size_t i; |
||||
sox_bool streamable = sox_false; |
||||
for (i = 0; !streamable && i < array_length(streamable_rates); ++i) |
||||
streamable = (streamable_rates[i] == ft->signal.rate); |
||||
if (!streamable) { |
||||
lsx_report("non-standard rate; output may not be streamable"); |
||||
FLAC__stream_encoder_set_streamable_subset(p->encoder, sox_false); |
||||
} |
||||
} |
||||
|
||||
#if FLAC_API_VERSION_CURRENT >= 10 |
||||
FLAC__stream_encoder_set_compression_level(p->encoder, compression_level); |
||||
#else |
||||
{ |
||||
static struct { |
||||
unsigned blocksize; |
||||
FLAC__bool do_exhaustive_model_search; |
||||
FLAC__bool do_mid_side_stereo; |
||||
FLAC__bool loose_mid_side_stereo; |
||||
unsigned max_lpc_order; |
||||
unsigned max_residual_partition_order; |
||||
unsigned min_residual_partition_order; |
||||
} const options[MAX_COMPRESSION + 1] = { |
||||
{1152, sox_false, sox_false, sox_false, 0, 2, 2}, |
||||
{1152, sox_false, sox_true, sox_true, 0, 2, 2}, |
||||
{1152, sox_false, sox_true, sox_false, 0, 3, 0}, |
||||
{4608, sox_false, sox_false, sox_false, 6, 3, 3}, |
||||
{4608, sox_false, sox_true, sox_true, 8, 3, 3}, |
||||
{4608, sox_false, sox_true, sox_false, 8, 3, 3}, |
||||
{4608, sox_false, sox_true, sox_false, 8, 4, 0}, |
||||
{4608, sox_true, sox_true, sox_false, 8, 6, 0}, |
||||
{4608, sox_true, sox_true, sox_false, 12, 6, 0}, |
||||
}; |
||||
#define SET_OPTION(x) do {\ |
||||
lsx_report(#x" = %i", options[compression_level].x); \
|
||||
FLAC__stream_encoder_set_##x(p->encoder, options[compression_level].x);\
|
||||
} while (0) |
||||
SET_OPTION(blocksize); |
||||
SET_OPTION(do_exhaustive_model_search); |
||||
SET_OPTION(max_lpc_order); |
||||
SET_OPTION(max_residual_partition_order); |
||||
SET_OPTION(min_residual_partition_order); |
||||
if (ft->signal.channels == 2) { |
||||
SET_OPTION(do_mid_side_stereo); |
||||
SET_OPTION(loose_mid_side_stereo); |
||||
} |
||||
#undef SET_OPTION |
||||
} |
||||
#endif |
||||
|
||||
if (ft->signal.length != 0) { |
||||
FLAC__stream_encoder_set_total_samples_estimate(p->encoder, (FLAC__uint64)(ft->signal.length / ft->signal.channels)); |
||||
|
||||
p->metadata[p->num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE); |
||||
if (p->metadata[p->num_metadata] == NULL) { |
||||
lsx_fail_errno(ft, SOX_ENOMEM, "FLAC ERROR creating the encoder seek table template"); |
||||
return SOX_EOF; |
||||
} |
||||
{ |
||||
if (!FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(p->metadata[p->num_metadata], (unsigned)(10 * ft->signal.rate + .5), (FLAC__uint64)(ft->signal.length/ft->signal.channels))) { |
||||
lsx_fail_errno(ft, SOX_ENOMEM, "FLAC ERROR creating the encoder seek table points"); |
||||
return SOX_EOF; |
||||
} |
||||
} |
||||
p->metadata[p->num_metadata]->is_last = sox_false; /* the encoder will set this for us */ |
||||
++p->num_metadata; |
||||
} |
||||
|
||||
if (ft->oob.comments) { /* Make the comment structure */ |
||||
FLAC__StreamMetadata_VorbisComment_Entry entry; |
||||
int i; |
||||
|
||||
p->metadata[p->num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); |
||||
for (i = 0; ft->oob.comments[i]; ++i) { |
||||
static const char prepend[] = "Comment="; |
||||
char * text = lsx_calloc(strlen(prepend) + strlen(ft->oob.comments[i]) + 1, sizeof(*text)); |
||||
/* Prepend `Comment=' if no field-name already in the comment */ |
||||
if (!strchr(ft->oob.comments[i], '=')) |
||||
strcpy(text, prepend); |
||||
entry.entry = (FLAC__byte *) strcat(text, ft->oob.comments[i]); |
||||
entry.length = strlen(text); |
||||
FLAC__metadata_object_vorbiscomment_append_comment(p->metadata[p->num_metadata], entry, /*copy= */ sox_true); |
||||
free(text); |
||||
} |
||||
++p->num_metadata; |
||||
} |
||||
|
||||
if (p->num_metadata) |
||||
FLAC__stream_encoder_set_metadata(p->encoder, p->metadata, p->num_metadata); |
||||
|
||||
status = FLAC__stream_encoder_init_stream(p->encoder, flac_stream_encoder_write_callback, |
||||
flac_stream_encoder_seek_callback, flac_stream_encoder_tell_callback, flac_stream_encoder_metadata_callback, ft); |
||||
|
||||
if (status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { |
||||
lsx_fail_errno(ft, SOX_EINVAL, "%s", FLAC__StreamEncoderInitStatusString[status]); |
||||
return SOX_EOF; |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
|
||||
|
||||
static size_t write_samples(sox_format_t * const ft, sox_sample_t const * const sampleBuffer, size_t const len) |
||||
{ |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
unsigned i; |
||||
|
||||
/* allocate or grow buffer */ |
||||
if (p->number_of_samples < len) { |
||||
p->number_of_samples = len; |
||||
free(p->decoded_samples); |
||||
p->decoded_samples = lsx_malloc(p->number_of_samples * sizeof(FLAC__int32)); |
||||
} |
||||
|
||||
for (i = 0; i < len; ++i) { |
||||
SOX_SAMPLE_LOCALS; |
||||
long pcm = SOX_SAMPLE_TO_SIGNED_32BIT(sampleBuffer[i], ft->clips); |
||||
p->decoded_samples[i] = pcm >> (32 - p->bits_per_sample); |
||||
switch (p->bits_per_sample) { |
||||
case 8: p->decoded_samples[i] = |
||||
SOX_SAMPLE_TO_SIGNED_8BIT(sampleBuffer[i], ft->clips); |
||||
break; |
||||
case 16: p->decoded_samples[i] = |
||||
SOX_SAMPLE_TO_SIGNED_16BIT(sampleBuffer[i], ft->clips); |
||||
break; |
||||
case 24: p->decoded_samples[i] = /* sign extension: */ |
||||
SOX_SAMPLE_TO_SIGNED_24BIT(sampleBuffer[i],ft->clips) << 8; |
||||
p->decoded_samples[i] >>= 8; |
||||
break; |
||||
case 32: p->decoded_samples[i] = |
||||
SOX_SAMPLE_TO_SIGNED_32BIT(sampleBuffer[i],ft->clips); |
||||
break; |
||||
} |
||||
} |
||||
FLAC__stream_encoder_process_interleaved(p->encoder, p->decoded_samples, (unsigned) len / ft->signal.channels); |
||||
return FLAC__stream_encoder_get_state(p->encoder) == FLAC__STREAM_ENCODER_OK ? len : 0; |
||||
} |
||||
|
||||
|
||||
|
||||
static int stop_write(sox_format_t * const ft) |
||||
{ |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
FLAC__StreamEncoderState state = FLAC__stream_encoder_get_state(p->encoder); |
||||
unsigned i; |
||||
|
||||
FLAC__stream_encoder_finish(p->encoder); |
||||
FLAC__stream_encoder_delete(p->encoder); |
||||
for (i = 0; i < p->num_metadata; ++i) |
||||
FLAC__metadata_object_delete(p->metadata[i]); |
||||
free(p->decoded_samples); |
||||
if (state != FLAC__STREAM_ENCODER_OK) { |
||||
lsx_fail_errno(ft, SOX_EINVAL, "FLAC ERROR: failed to encode to end of stream"); |
||||
return SOX_EOF; |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
|
||||
|
||||
static int seek(sox_format_t * ft, uint64_t offset) |
||||
{ |
||||
priv_t * p = (priv_t *)ft->priv; |
||||
p->seek_offset = offset; |
||||
p->seek_pending = sox_true; |
||||
return ft->mode == 'r' ? SOX_SUCCESS : SOX_EOF; |
||||
} |
||||
|
||||
|
||||
|
||||
LSX_FORMAT_HANDLER(flac) |
||||
{ |
||||
static char const * const names[] = {"flac", NULL}; |
||||
static unsigned const encodings[] = {SOX_ENCODING_FLAC, 8, 16, 24, 0, 0}; |
||||
static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, |
||||
"Free Lossless Audio CODEC compressed audio", names, 0, |
||||
start_read, read_samples, stop_read, |
||||
start_write, write_samples, stop_write, |
||||
seek, encodings, NULL, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,275 +0,0 @@ |
||||
/* libSoX effect: Stereo Flanger (c) 2006 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
/* TODO: Slide in the delay at the start? */ |
||||
|
||||
#include "sox_i.h" |
||||
#include <string.h> |
||||
|
||||
typedef enum {INTERP_LINEAR, INTERP_QUADRATIC} interp_t; |
||||
|
||||
#define MAX_CHANNELS 4 |
||||
|
||||
typedef struct { |
||||
/* Parameters */ |
||||
double delay_min; |
||||
double delay_depth; |
||||
double feedback_gain; |
||||
double delay_gain; |
||||
double speed; |
||||
lsx_wave_t wave_shape; |
||||
double channel_phase; |
||||
interp_t interpolation; |
||||
|
||||
/* Delay buffers */ |
||||
double * delay_bufs[MAX_CHANNELS]; |
||||
size_t delay_buf_length; |
||||
size_t delay_buf_pos; |
||||
double delay_last[MAX_CHANNELS]; |
||||
|
||||
/* Low Frequency Oscillator */ |
||||
float * lfo; |
||||
size_t lfo_length; |
||||
size_t lfo_pos; |
||||
|
||||
/* Balancing */ |
||||
double in_gain; |
||||
} priv_t; |
||||
|
||||
|
||||
|
||||
static lsx_enum_item const interp_enum[] = { |
||||
LSX_ENUM_ITEM(INTERP_,LINEAR) |
||||
LSX_ENUM_ITEM(INTERP_,QUADRATIC) |
||||
{0, 0}}; |
||||
|
||||
|
||||
|
||||
static int getopts(sox_effect_t * effp, int argc, char *argv[]) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
--argc, ++argv; |
||||
|
||||
/* Set non-zero defaults: */ |
||||
p->delay_depth = 2; |
||||
p->delay_gain = 71; |
||||
p->speed = 0.5; |
||||
p->channel_phase= 25; |
||||
|
||||
do { /* break-able block */ |
||||
NUMERIC_PARAMETER(delay_min , 0 , 30 ) |
||||
NUMERIC_PARAMETER(delay_depth , 0 , 10 ) |
||||
NUMERIC_PARAMETER(feedback_gain,-95 , 95 ) |
||||
NUMERIC_PARAMETER(delay_gain , 0 , 100) |
||||
NUMERIC_PARAMETER(speed , 0.1, 10 ) |
||||
TEXTUAL_PARAMETER(wave_shape, lsx_get_wave_enum()) |
||||
NUMERIC_PARAMETER(channel_phase, 0 , 100) |
||||
TEXTUAL_PARAMETER(interpolation, interp_enum) |
||||
} while (0); |
||||
|
||||
if (argc != 0) |
||||
return lsx_usage(effp); |
||||
|
||||
lsx_report("parameters:\n" |
||||
"delay = %gms\n" |
||||
"depth = %gms\n" |
||||
"regen = %g%%\n" |
||||
"width = %g%%\n" |
||||
"speed = %gHz\n" |
||||
"shape = %s\n" |
||||
"phase = %g%%\n" |
||||
"interp= %s", |
||||
p->delay_min, |
||||
p->delay_depth, |
||||
p->feedback_gain, |
||||
p->delay_gain, |
||||
p->speed, |
||||
lsx_get_wave_enum()[p->wave_shape].text, |
||||
p->channel_phase, |
||||
interp_enum[p->interpolation].text); |
||||
|
||||
/* Scale to unity: */ |
||||
p->feedback_gain /= 100; |
||||
p->delay_gain /= 100; |
||||
p->channel_phase /= 100; |
||||
p->delay_min /= 1000; |
||||
p->delay_depth /= 1000; |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
|
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * f = (priv_t *) effp->priv; |
||||
int c, channels = effp->in_signal.channels; |
||||
|
||||
if (channels > MAX_CHANNELS) { |
||||
lsx_fail("Can not operate with more than %i channels", MAX_CHANNELS); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
/* Balance output: */ |
||||
f->in_gain = 1 / (1 + f->delay_gain); |
||||
f->delay_gain /= 1 + f->delay_gain; |
||||
|
||||
/* Balance feedback loop: */ |
||||
f->delay_gain *= 1 - fabs(f->feedback_gain); |
||||
|
||||
lsx_debug("in_gain=%g feedback_gain=%g delay_gain=%g\n", |
||||
f->in_gain, f->feedback_gain, f->delay_gain); |
||||
|
||||
/* Create the delay buffers, one for each channel: */ |
||||
f->delay_buf_length = |
||||
(f->delay_min + f->delay_depth) * effp->in_signal.rate + 0.5; |
||||
++f->delay_buf_length; /* Need 0 to n, i.e. n + 1. */ |
||||
++f->delay_buf_length; /* Quadratic interpolator needs one more. */ |
||||
for (c = 0; c < channels; ++c) |
||||
f->delay_bufs[c] = lsx_calloc(f->delay_buf_length, sizeof(*f->delay_bufs[0])); |
||||
|
||||
/* Create the LFO lookup table: */ |
||||
f->lfo_length = effp->in_signal.rate / f->speed; |
||||
f->lfo = lsx_calloc(f->lfo_length, sizeof(*f->lfo)); |
||||
lsx_generate_wave_table( |
||||
f->wave_shape, |
||||
SOX_FLOAT, |
||||
f->lfo, |
||||
f->lfo_length, |
||||
floor(f->delay_min * effp->in_signal.rate + .5), |
||||
f->delay_buf_length - 2., |
||||
3 * M_PI_2); /* Start the sweep at minimum delay (for mono at least) */ |
||||
|
||||
lsx_debug("delay_buf_length=%" PRIuPTR " lfo_length=%" PRIuPTR "\n", |
||||
f->delay_buf_length, f->lfo_length); |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
|
||||
|
||||
static int flow(sox_effect_t * effp, sox_sample_t const * ibuf, |
||||
sox_sample_t * obuf, size_t * isamp, size_t * osamp) |
||||
{ |
||||
priv_t * f = (priv_t *) effp->priv; |
||||
int c, channels = effp->in_signal.channels; |
||||
size_t len = (*isamp > *osamp ? *osamp : *isamp) / channels; |
||||
|
||||
*isamp = *osamp = len * channels; |
||||
|
||||
while (len--) { |
||||
f->delay_buf_pos = |
||||
(f->delay_buf_pos + f->delay_buf_length - 1) % f->delay_buf_length; |
||||
for (c = 0; c < channels; ++c) { |
||||
double delayed_0, delayed_1; |
||||
double delayed; |
||||
double in, out; |
||||
size_t channel_phase = c * f->lfo_length * f->channel_phase + .5; |
||||
double delay = f->lfo[(f->lfo_pos + channel_phase) % f->lfo_length]; |
||||
double frac_delay = modf(delay, &delay); |
||||
size_t int_delay = (size_t)delay; |
||||
|
||||
in = *ibuf++; |
||||
f->delay_bufs[c][f->delay_buf_pos] = in + f->delay_last[c] * f->feedback_gain; |
||||
|
||||
delayed_0 = f->delay_bufs[c] |
||||
[(f->delay_buf_pos + int_delay++) % f->delay_buf_length]; |
||||
delayed_1 = f->delay_bufs[c] |
||||
[(f->delay_buf_pos + int_delay++) % f->delay_buf_length]; |
||||
|
||||
if (f->interpolation == INTERP_LINEAR) |
||||
delayed = delayed_0 + (delayed_1 - delayed_0) * frac_delay; |
||||
else /* if (f->interpolation == INTERP_QUADRATIC) */ |
||||
{ |
||||
double a, b; |
||||
double delayed_2 = f->delay_bufs[c] |
||||
[(f->delay_buf_pos + int_delay++) % f->delay_buf_length]; |
||||
delayed_2 -= delayed_0; |
||||
delayed_1 -= delayed_0; |
||||
a = delayed_2 *.5 - delayed_1; |
||||
b = delayed_1 * 2 - delayed_2 *.5; |
||||
delayed = delayed_0 + (a * frac_delay + b) * frac_delay; |
||||
} |
||||
|
||||
f->delay_last[c] = delayed; |
||||
out = in * f->in_gain + delayed * f->delay_gain; |
||||
*obuf++ = SOX_ROUND_CLIP_COUNT(out, effp->clips); |
||||
} |
||||
f->lfo_pos = (f->lfo_pos + 1) % f->lfo_length; |
||||
} |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
|
||||
|
||||
static int stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * f = (priv_t *) effp->priv; |
||||
int c, channels = effp->in_signal.channels; |
||||
|
||||
for (c = 0; c < channels; ++c) |
||||
free(f->delay_bufs[c]); |
||||
|
||||
free(f->lfo); |
||||
|
||||
memset(f, 0, sizeof(*f)); |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
|
||||
|
||||
sox_effect_handler_t const * lsx_flanger_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"flanger", NULL, SOX_EFF_MCHAN, |
||||
getopts, start, flow, NULL, stop, NULL, sizeof(priv_t)}; |
||||
static char const * lines[] = { |
||||
"[delay depth regen width speed shape phase interp]", |
||||
" .", |
||||
" /|regen", |
||||
" / |", |
||||
" +--( |------------+", |
||||
" | \\ | | .", |
||||
" _V_ \\| _______ | |\\ width ___", |
||||
" | | ' | | | | \\ | |", |
||||
" +-->| + |---->| DELAY |--+-->| )----->| |", |
||||
" | |___| |_______| | / | |", |
||||
" | delay : depth |/ | |", |
||||
" In | : interp ' | | Out", |
||||
" --->+ __:__ | + |--->", |
||||
" | | |speed | |", |
||||
" | | ~ |shape | |", |
||||
" | |_____|phase | |", |
||||
" +------------------------------------->| |", |
||||
" |___|", |
||||
" RANGE DEFAULT DESCRIPTION", |
||||
"delay 0 30 0 base delay in milliseconds", |
||||
"depth 0 10 2 added swept delay in milliseconds", |
||||
"regen -95 +95 0 percentage regeneration (delayed signal feedback)", |
||||
"width 0 100 71 percentage of delayed signal mixed with original", |
||||
"speed 0.1 10 0.5 sweeps per second (Hz) ", |
||||
"shape -- sin swept wave shape: sine|triangle", |
||||
"phase 0 100 25 swept wave percentage phase-shift for multi-channel", |
||||
" (e.g. stereo) flange; 0 = 100 = same phase on each channel", |
||||
"interp -- lin delay-line interpolation: linear|quadratic" |
||||
}; |
||||
static char * usage; |
||||
handler.usage = lsx_usage_lines(&usage, lines, array_length(lines)); |
||||
return &handler; |
||||
} |
@ -1,167 +0,0 @@ |
||||
/* This source code is a product of Sun Microsystems, Inc. and is provided
|
||||
* for unrestricted use. Users may copy or modify this source code without |
||||
* charge. |
||||
* |
||||
* SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING |
||||
* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. |
||||
* |
||||
* Sun source code is provided with no support and without any obligation on |
||||
* the part of Sun Microsystems, Inc. to assist in its use, correction, |
||||
* modification or enhancement. |
||||
* |
||||
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE |
||||
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE |
||||
* OR ANY PART THEREOF. |
||||
* |
||||
* In no event will Sun Microsystems, Inc. be liable for any lost revenue |
||||
* or profits or other special, indirect and consequential damages, even if |
||||
* Sun has been advised of the possibility of such damages. |
||||
* |
||||
* Sun Microsystems, Inc. |
||||
* 2550 Garcia Avenue |
||||
* Mountain View, California 94043 |
||||
*/ |
||||
|
||||
/*
|
||||
* g721.c |
||||
* |
||||
* Description: |
||||
* |
||||
* g721_encoder(), g721_decoder() |
||||
* |
||||
* These routines comprise an implementation of the CCITT G.721 ADPCM |
||||
* coding algorithm. Essentially, this implementation is identical to |
||||
* the bit level description except for a few deviations which |
||||
* take advantage of work station attributes, such as hardware 2's |
||||
* complement arithmetic and large memory. Specifically, certain time |
||||
* consuming operations such as multiplications are replaced |
||||
* with lookup tables and software 2's complement operations are |
||||
* replaced with hardware 2's complement. |
||||
* |
||||
* The deviation from the bit level specification (lookup tables) |
||||
* preserves the bit level performance specifications. |
||||
* |
||||
* As outlined in the G.721 Recommendation, the algorithm is broken |
||||
* down into modules. Each section of code below is preceded by |
||||
* the name of the module which it is implementing. |
||||
* |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "g72x.h" |
||||
#include "g711.h" |
||||
|
||||
static const short qtab_721[7] = {-124, 80, 178, 246, 300, 349, 400}; |
||||
/*
|
||||
* Maps G.721 code word to reconstructed scale factor normalized log |
||||
* magnitude values. |
||||
*/ |
||||
static const short _dqlntab[16] = {-2048, 4, 135, 213, 273, 323, 373, 425, |
||||
425, 373, 323, 273, 213, 135, 4, -2048}; |
||||
|
||||
/* Maps G.721 code word to log of scale factor multiplier. */ |
||||
static const short _witab[16] = {-12, 18, 41, 64, 112, 198, 355, 1122, |
||||
1122, 355, 198, 112, 64, 41, 18, -12}; |
||||
/*
|
||||
* Maps G.721 code words to a set of values whose long and short |
||||
* term averages are computed and then compared to give an indication |
||||
* how stationary (steady state) the signal is. |
||||
*/ |
||||
static const short _fitab[16] = {0, 0, 0, 0x200, 0x200, 0x200, 0x600, 0xE00, |
||||
0xE00, 0x600, 0x200, 0x200, 0x200, 0, 0, 0}; |
||||
|
||||
/*
|
||||
* g721_encoder() |
||||
* |
||||
* Encodes the input vale of linear PCM, A-law or u-law data sl and returns |
||||
* the resulting code. -1 is returned for unknown input coding value. |
||||
*/ |
||||
int g721_encoder(int sl, int in_coding, struct g72x_state *state_ptr) |
||||
{ |
||||
short sezi, se, sez; /* ACCUM */ |
||||
short d; /* SUBTA */ |
||||
short sr; /* ADDB */ |
||||
short y; /* MIX */ |
||||
short dqsez; /* ADDC */ |
||||
short dq, i; |
||||
|
||||
switch (in_coding) { /* linearize input sample to 14-bit PCM */ |
||||
case AUDIO_ENCODING_ALAW: |
||||
sl = sox_alaw2linear16(sl) >> 2; |
||||
break; |
||||
case AUDIO_ENCODING_ULAW: |
||||
sl = sox_ulaw2linear16(sl) >> 2; |
||||
break; |
||||
case AUDIO_ENCODING_LINEAR: |
||||
sl >>= 2; /* 14-bit dynamic range */ |
||||
break; |
||||
default: |
||||
return (-1); |
||||
} |
||||
|
||||
sezi = predictor_zero(state_ptr); |
||||
sez = sezi >> 1; |
||||
se = (sezi + predictor_pole(state_ptr)) >> 1; /* estimated signal */ |
||||
|
||||
d = sl - se; /* estimation difference */ |
||||
|
||||
/* quantize the prediction difference */ |
||||
y = step_size(state_ptr); /* quantizer step size */ |
||||
i = quantize(d, y, qtab_721, 7); /* i = ADPCM code */ |
||||
|
||||
dq = reconstruct(i & 8, _dqlntab[i], y); /* quantized est diff */ |
||||
|
||||
sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq; /* reconst. signal */ |
||||
|
||||
dqsez = sr + sez - se; /* pole prediction diff. */ |
||||
|
||||
update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr); |
||||
|
||||
return (i); |
||||
} |
||||
|
||||
/*
|
||||
* g721_decoder() |
||||
* |
||||
* Description: |
||||
* |
||||
* Decodes a 4-bit code of G.721 encoded data of i and |
||||
* returns the resulting linear PCM, A-law or u-law value. |
||||
* return -1 for unknown out_coding value. |
||||
*/ |
||||
int g721_decoder(int i, int out_coding, struct g72x_state *state_ptr) |
||||
{ |
||||
short sezi, sei, sez, se; /* ACCUM */ |
||||
short y; /* MIX */ |
||||
short sr; /* ADDB */ |
||||
short dq; |
||||
short dqsez; |
||||
|
||||
i &= 0x0f; /* mask to get proper bits */ |
||||
sezi = predictor_zero(state_ptr); |
||||
sez = sezi >> 1; |
||||
sei = sezi + predictor_pole(state_ptr); |
||||
se = sei >> 1; /* se = estimated signal */ |
||||
|
||||
y = step_size(state_ptr); /* dynamic quantizer step size */ |
||||
|
||||
dq = reconstruct(i & 0x08, _dqlntab[i], y); /* quantized diff. */ |
||||
|
||||
sr = (dq < 0) ? (se - (dq & 0x3FFF)) : se + dq; /* reconst. signal */ |
||||
|
||||
dqsez = sr - se + sez; /* pole prediction diff. */ |
||||
|
||||
update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr); |
||||
|
||||
switch (out_coding) { |
||||
case AUDIO_ENCODING_ALAW: |
||||
return (tandem_adjust_alaw(sr, se, y, i, 8, qtab_721)); |
||||
case AUDIO_ENCODING_ULAW: |
||||
return (tandem_adjust_ulaw(sr, se, y, i, 8, qtab_721)); |
||||
case AUDIO_ENCODING_LINEAR: |
||||
return (sr << 2); /* sr was 14-bit dynamic range */ |
||||
default: |
||||
return (-1); |
||||
} |
||||
} |
@ -1,151 +0,0 @@ |
||||
/* This source code is a product of Sun Microsystems, Inc. and is provided
|
||||
* for unrestricted use. Users may copy or modify this source code without |
||||
* charge. |
||||
* |
||||
* SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING |
||||
* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. |
||||
* |
||||
* Sun source code is provided with no support and without any obligation on |
||||
* the part of Sun Microsystems, Inc. to assist in its use, correction, |
||||
* modification or enhancement. |
||||
* |
||||
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE |
||||
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE |
||||
* OR ANY PART THEREOF. |
||||
* |
||||
* In no event will Sun Microsystems, Inc. be liable for any lost revenue |
||||
* or profits or other special, indirect and consequential damages, even if |
||||
* Sun has been advised of the possibility of such damages. |
||||
* |
||||
* Sun Microsystems, Inc. |
||||
* 2550 Garcia Avenue |
||||
* Mountain View, California 94043 |
||||
*/ |
||||
|
||||
/*
|
||||
* g723_24.c |
||||
* |
||||
* Description: |
||||
* |
||||
* g723_24_encoder(), g723_24_decoder() |
||||
* |
||||
* These routines comprise an implementation of the CCITT G.723 24 Kbps |
||||
* ADPCM coding algorithm. Essentially, this implementation is identical to |
||||
* the bit level description except for a few deviations which take advantage |
||||
* of workstation attributes, such as hardware 2's complement arithmetic. |
||||
* |
||||
*/ |
||||
#include "sox_i.h" |
||||
#include "g711.h" |
||||
#include "g72x.h" |
||||
|
||||
/*
|
||||
* Maps G.723_24 code word to reconstructed scale factor normalized log |
||||
* magnitude values. |
||||
*/ |
||||
static const short _dqlntab[8] = {-2048, 135, 273, 373, 373, 273, 135, -2048}; |
||||
|
||||
/* Maps G.723_24 code word to log of scale factor multiplier. */ |
||||
static const short _witab[8] = {-128, 960, 4384, 18624, 18624, 4384, 960, -128}; |
||||
|
||||
/*
|
||||
* Maps G.723_24 code words to a set of values whose long and short |
||||
* term averages are computed and then compared to give an indication |
||||
* how stationary (steady state) the signal is. |
||||
*/ |
||||
static const short _fitab[8] = {0, 0x200, 0x400, 0xE00, 0xE00, 0x400, 0x200, 0}; |
||||
|
||||
static const short qtab_723_24[3] = {8, 218, 331}; |
||||
|
||||
/*
|
||||
* g723_24_encoder() |
||||
* |
||||
* Encodes a linear PCM, A-law or u-law input sample and returns its 3-bit code. |
||||
* Returns -1 if invalid input coding value. |
||||
*/ |
||||
int g723_24_encoder(int sl, int in_coding, struct g72x_state *state_ptr) |
||||
{ |
||||
short sei, sezi, se, sez; /* ACCUM */ |
||||
short d; /* SUBTA */ |
||||
short y; /* MIX */ |
||||
short sr; /* ADDB */ |
||||
short dqsez; /* ADDC */ |
||||
short dq, i; |
||||
|
||||
switch (in_coding) { /* linearize input sample to 14-bit PCM */ |
||||
case AUDIO_ENCODING_ALAW: |
||||
sl = sox_alaw2linear16(sl) >> 2; |
||||
break; |
||||
case AUDIO_ENCODING_ULAW: |
||||
sl = sox_ulaw2linear16(sl) >> 2; |
||||
break; |
||||
case AUDIO_ENCODING_LINEAR: |
||||
sl >>= 2; /* sl of 14-bit dynamic range */ |
||||
break; |
||||
default: |
||||
return (-1); |
||||
} |
||||
|
||||
sezi = predictor_zero(state_ptr); |
||||
sez = sezi >> 1; |
||||
sei = sezi + predictor_pole(state_ptr); |
||||
se = sei >> 1; /* se = estimated signal */ |
||||
|
||||
d = sl - se; /* d = estimation diff. */ |
||||
|
||||
/* quantize prediction difference d */ |
||||
y = step_size(state_ptr); /* quantizer step size */ |
||||
i = quantize(d, y, qtab_723_24, 3); /* i = ADPCM code */ |
||||
dq = reconstruct(i & 4, _dqlntab[i], y); /* quantized diff. */ |
||||
|
||||
sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq; /* reconstructed signal */ |
||||
|
||||
dqsez = sr + sez - se; /* pole prediction diff. */ |
||||
|
||||
update(3, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr); |
||||
|
||||
return (i); |
||||
} |
||||
|
||||
/*
|
||||
* g723_24_decoder() |
||||
* |
||||
* Decodes a 3-bit CCITT G.723_24 ADPCM code and returns |
||||
* the resulting 16-bit linear PCM, A-law or u-law sample value. |
||||
* -1 is returned if the output coding is unknown. |
||||
*/ |
||||
int g723_24_decoder(int i, int out_coding, struct g72x_state *state_ptr) |
||||
{ |
||||
short sezi, sei, sez, se; /* ACCUM */ |
||||
short y; /* MIX */ |
||||
short sr; /* ADDB */ |
||||
short dq; |
||||
short dqsez; |
||||
|
||||
i &= 0x07; /* mask to get proper bits */ |
||||
sezi = predictor_zero(state_ptr); |
||||
sez = sezi >> 1; |
||||
sei = sezi + predictor_pole(state_ptr); |
||||
se = sei >> 1; /* se = estimated signal */ |
||||
|
||||
y = step_size(state_ptr); /* adaptive quantizer step size */ |
||||
dq = reconstruct(i & 0x04, _dqlntab[i], y); /* unquantize pred diff */ |
||||
|
||||
sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); /* reconst. signal */ |
||||
|
||||
dqsez = sr - se + sez; /* pole prediction diff. */ |
||||
|
||||
update(3, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr); |
||||
|
||||
switch (out_coding) { |
||||
case AUDIO_ENCODING_ALAW: |
||||
return (tandem_adjust_alaw(sr, se, y, i, 4, qtab_723_24)); |
||||
case AUDIO_ENCODING_ULAW: |
||||
return (tandem_adjust_ulaw(sr, se, y, i, 4, qtab_723_24)); |
||||
case AUDIO_ENCODING_LINEAR: |
||||
return (sr << 2); /* sr was of 14-bit dynamic range */ |
||||
default: |
||||
return (-1); |
||||
} |
||||
} |
@ -1,171 +0,0 @@ |
||||
/* This source code is a product of Sun Microsystems, Inc. and is provided
|
||||
* for unrestricted use. Users may copy or modify this source code without |
||||
* charge. |
||||
* |
||||
* SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING |
||||
* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. |
||||
* |
||||
* Sun source code is provided with no support and without any obligation on |
||||
* the part of Sun Microsystems, Inc. to assist in its use, correction, |
||||
* modification or enhancement. |
||||
* |
||||
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE |
||||
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE |
||||
* OR ANY PART THEREOF. |
||||
* |
||||
* In no event will Sun Microsystems, Inc. be liable for any lost revenue |
||||
* or profits or other special, indirect and consequential damages, even if |
||||
* Sun has been advised of the possibility of such damages. |
||||
* |
||||
* Sun Microsystems, Inc. |
||||
* 2550 Garcia Avenue |
||||
* Mountain View, California 94043 |
||||
*/ |
||||
|
||||
/*
|
||||
* g723_40.c |
||||
* |
||||
* Description: |
||||
* |
||||
* g723_40_encoder(), g723_40_decoder() |
||||
* |
||||
* These routines comprise an implementation of the CCITT G.723 40Kbps |
||||
* ADPCM coding algorithm. Essentially, this implementation is identical to |
||||
* the bit level description except for a few deviations which |
||||
* take advantage of workstation attributes, such as hardware 2's |
||||
* complement arithmetic. |
||||
* |
||||
* The deviation from the bit level specification (lookup tables), |
||||
* preserves the bit level performance specifications. |
||||
* |
||||
* As outlined in the G.723 Recommendation, the algorithm is broken |
||||
* down into modules. Each section of code below is preceded by |
||||
* the name of the module which it is implementing. |
||||
* |
||||
*/ |
||||
#include "sox_i.h" |
||||
#include "g711.h" |
||||
#include "g72x.h" |
||||
|
||||
/*
|
||||
* Maps G.723_40 code word to ructeconstructed scale factor normalized log |
||||
* magnitude values. |
||||
*/ |
||||
static const short _dqlntab[32] = {-2048, -66, 28, 104, 169, 224, 274, 318, |
||||
358, 395, 429, 459, 488, 514, 539, 566, |
||||
566, 539, 514, 488, 459, 429, 395, 358, |
||||
318, 274, 224, 169, 104, 28, -66, -2048}; |
||||
|
||||
/* Maps G.723_40 code word to log of scale factor multiplier. */ |
||||
static const short _witab[32] = {448, 448, 768, 1248, 1280, 1312, 1856, 3200, |
||||
4512, 5728, 7008, 8960, 11456, 14080, 16928, 22272, |
||||
22272, 16928, 14080, 11456, 8960, 7008, 5728, 4512, |
||||
3200, 1856, 1312, 1280, 1248, 768, 448, 448}; |
||||
|
||||
/*
|
||||
* Maps G.723_40 code words to a set of values whose long and short |
||||
* term averages are computed and then compared to give an indication |
||||
* how stationary (steady state) the signal is. |
||||
*/ |
||||
static const short _fitab[32] = {0, 0, 0, 0, 0, 0x200, 0x200, 0x200, |
||||
0x200, 0x200, 0x400, 0x600, 0x800, 0xA00, 0xC00, 0xC00, |
||||
0xC00, 0xC00, 0xA00, 0x800, 0x600, 0x400, 0x200, 0x200, |
||||
0x200, 0x200, 0x200, 0, 0, 0, 0, 0}; |
||||
|
||||
static const short qtab_723_40[15] = {-122, -16, 68, 139, 198, 250, 298, 339, |
||||
378, 413, 445, 475, 502, 528, 553}; |
||||
|
||||
/*
|
||||
* g723_40_encoder() |
||||
* |
||||
* Encodes a 16-bit linear PCM, A-law or u-law input sample and retuens |
||||
* the resulting 5-bit CCITT G.723 40Kbps code. |
||||
* Returns -1 if the input coding value is invalid. |
||||
*/ |
||||
int g723_40_encoder(int sl, int in_coding, struct g72x_state *state_ptr) |
||||
{ |
||||
short sei, sezi, se, sez; /* ACCUM */ |
||||
short d; /* SUBTA */ |
||||
short y; /* MIX */ |
||||
short sr; /* ADDB */ |
||||
short dqsez; /* ADDC */ |
||||
short dq, i; |
||||
|
||||
switch (in_coding) { /* linearize input sample to 14-bit PCM */ |
||||
case AUDIO_ENCODING_ALAW: |
||||
sl = sox_alaw2linear16(sl) >> 2; |
||||
break; |
||||
case AUDIO_ENCODING_ULAW: |
||||
sl = sox_ulaw2linear16(sl) >> 2; |
||||
break; |
||||
case AUDIO_ENCODING_LINEAR: |
||||
sl >>= 2; /* sl of 14-bit dynamic range */ |
||||
break; |
||||
default: |
||||
return (-1); |
||||
} |
||||
|
||||
sezi = predictor_zero(state_ptr); |
||||
sez = sezi >> 1; |
||||
sei = sezi + predictor_pole(state_ptr); |
||||
se = sei >> 1; /* se = estimated signal */ |
||||
|
||||
d = sl - se; /* d = estimation difference */ |
||||
|
||||
/* quantize prediction difference */ |
||||
y = step_size(state_ptr); /* adaptive quantizer step size */ |
||||
i = quantize(d, y, qtab_723_40, 15); /* i = ADPCM code */ |
||||
|
||||
dq = reconstruct(i & 0x10, _dqlntab[i], y); /* quantized diff */ |
||||
|
||||
sr = (dq < 0) ? se - (dq & 0x7FFF) : se + dq; /* reconstructed signal */ |
||||
|
||||
dqsez = sr + sez - se; /* dqsez = pole prediction diff. */ |
||||
|
||||
update(5, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr); |
||||
|
||||
return (i); |
||||
} |
||||
|
||||
/*
|
||||
* g723_40_decoder() |
||||
* |
||||
* Decodes a 5-bit CCITT G.723 40Kbps code and returns |
||||
* the resulting 16-bit linear PCM, A-law or u-law sample value. |
||||
* -1 is returned if the output coding is unknown. |
||||
*/ |
||||
int g723_40_decoder(int i, int out_coding, struct g72x_state *state_ptr) |
||||
{ |
||||
short sezi, sei, sez, se; /* ACCUM */ |
||||
short y; /* MIX */ |
||||
short sr; /* ADDB */ |
||||
short dq; |
||||
short dqsez; |
||||
|
||||
i &= 0x1f; /* mask to get proper bits */ |
||||
sezi = predictor_zero(state_ptr); |
||||
sez = sezi >> 1; |
||||
sei = sezi + predictor_pole(state_ptr); |
||||
se = sei >> 1; /* se = estimated signal */ |
||||
|
||||
y = step_size(state_ptr); /* adaptive quantizer step size */ |
||||
dq = reconstruct(i & 0x10, _dqlntab[i], y); /* estimation diff. */ |
||||
|
||||
sr = (dq < 0) ? (se - (dq & 0x7FFF)) : (se + dq); /* reconst. signal */ |
||||
|
||||
dqsez = sr - se + sez; /* pole prediction diff. */ |
||||
|
||||
update(5, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr); |
||||
|
||||
switch (out_coding) { |
||||
case AUDIO_ENCODING_ALAW: |
||||
return (tandem_adjust_alaw(sr, se, y, i, 0x10, qtab_723_40)); |
||||
case AUDIO_ENCODING_ULAW: |
||||
return (tandem_adjust_ulaw(sr, se, y, i, 0x10, qtab_723_40)); |
||||
case AUDIO_ENCODING_LINEAR: |
||||
return (sr << 2); /* sr was of 14-bit dynamic range */ |
||||
default: |
||||
return (-1); |
||||
} |
||||
} |
@ -1,575 +0,0 @@ |
||||
/* Common routines for G.721 and G.723 conversions.
|
||||
* |
||||
* (c) SoX Contributors |
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
* |
||||
* |
||||
* This code is based on code from Sun, which came with the following |
||||
* copyright notice: |
||||
* ----------------------------------------------------------------------- |
||||
* This source code is a product of Sun Microsystems, Inc. and is provided |
||||
* for unrestricted use. Users may copy or modify this source code without |
||||
* charge. |
||||
* |
||||
* SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING |
||||
* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. |
||||
* |
||||
* Sun source code is provided with no support and without any obligation on |
||||
* the part of Sun Microsystems, Inc. to assist in its use, correction, |
||||
* modification or enhancement. |
||||
* |
||||
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE |
||||
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE |
||||
* OR ANY PART THEREOF. |
||||
* |
||||
* In no event will Sun Microsystems, Inc. be liable for any lost revenue |
||||
* or profits or other special, indirect and consequential damages, even if |
||||
* Sun has been advised of the possibility of such damages. |
||||
* |
||||
* Sun Microsystems, Inc. |
||||
* 2550 Garcia Avenue |
||||
* Mountain View, California 94043 |
||||
* ----------------------------------------------------------------------- |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "g711.h" |
||||
#include "g72x.h" |
||||
|
||||
static const char LogTable256[] = |
||||
{ |
||||
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, |
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, |
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, |
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, |
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 |
||||
}; |
||||
|
||||
static inline int log2plus1(int val) |
||||
{ |
||||
/* From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup */ |
||||
unsigned int v = (unsigned int)val; /* 32-bit word to find the log of */ |
||||
unsigned r; /* r will be lg(v) */ |
||||
register unsigned int t, tt; /* temporaries */ |
||||
|
||||
if ((tt = v >> 16)) |
||||
{ |
||||
r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt]; |
||||
} |
||||
else |
||||
{ |
||||
r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v]; |
||||
} |
||||
|
||||
return r + 1; |
||||
} |
||||
|
||||
/*
|
||||
* quan() |
||||
* |
||||
* quantizes the input val against the table of size short integers. |
||||
* It returns i if table[i - 1] <= val < table[i]. |
||||
* |
||||
* Using linear search for simple coding. |
||||
*/ |
||||
static int quan(int val, short const *table, int size) |
||||
{ |
||||
int i; |
||||
|
||||
for (i = 0; i < size; i++) |
||||
if (val < *table++) |
||||
break; |
||||
return (i); |
||||
} |
||||
|
||||
/*
|
||||
* fmult() |
||||
* |
||||
* returns the integer product of the 14-bit integer "an" and |
||||
* "floating point" representation (4-bit exponent, 6-bit mantessa) "srn". |
||||
*/ |
||||
static int fmult(int an, int srn) |
||||
{ |
||||
short anmag, anexp, anmant; |
||||
short wanexp, wanmant; |
||||
short retval; |
||||
|
||||
anmag = (an > 0) ? an : ((-an) & 0x1FFF); |
||||
anexp = log2plus1(anmag) - 6; |
||||
anmant = (anmag == 0) ? 32 : |
||||
(anexp >= 0) ? anmag >> anexp : anmag << -anexp; |
||||
wanexp = anexp + ((srn >> 6) & 0xF) - 13; |
||||
|
||||
wanmant = (anmant * (srn & 077) + 0x30) >> 4; |
||||
retval = (wanexp >= 0) ? ((wanmant << wanexp) & 0x7FFF) : |
||||
(wanmant >> -wanexp); |
||||
|
||||
return (((an ^ srn) < 0) ? -retval : retval); |
||||
} |
||||
|
||||
/*
|
||||
* g72x_init_state() |
||||
* |
||||
* This routine initializes and/or resets the g72x_state structure |
||||
* pointed to by 'state_ptr'. |
||||
* All the initial state values are specified in the CCITT G.721 document. |
||||
*/ |
||||
void g72x_init_state(struct g72x_state *state_ptr) |
||||
{ |
||||
int cnta; |
||||
|
||||
state_ptr->yl = 34816; |
||||
state_ptr->yu = 544; |
||||
state_ptr->dms = 0; |
||||
state_ptr->dml = 0; |
||||
state_ptr->ap = 0; |
||||
for (cnta = 0; cnta < 2; cnta++) { |
||||
state_ptr->a[cnta] = 0; |
||||
state_ptr->pk[cnta] = 0; |
||||
state_ptr->sr[cnta] = 32; |
||||
} |
||||
for (cnta = 0; cnta < 6; cnta++) { |
||||
state_ptr->b[cnta] = 0; |
||||
state_ptr->dq[cnta] = 32; |
||||
} |
||||
state_ptr->td = 0; |
||||
} |
||||
|
||||
/*
|
||||
* predictor_zero() |
||||
* |
||||
* computes the estimated signal from 6-zero predictor. |
||||
* |
||||
*/ |
||||
int predictor_zero(struct g72x_state *state_ptr) |
||||
{ |
||||
int i; |
||||
int sezi; |
||||
|
||||
sezi = fmult(state_ptr->b[0] >> 2, state_ptr->dq[0]); |
||||
for (i = 1; i < 6; i++) /* ACCUM */ |
||||
sezi += fmult(state_ptr->b[i] >> 2, state_ptr->dq[i]); |
||||
return (sezi); |
||||
} |
||||
/*
|
||||
* predictor_pole() |
||||
* |
||||
* computes the estimated signal from 2-pole predictor. |
||||
* |
||||
*/ |
||||
int predictor_pole(struct g72x_state *state_ptr) |
||||
{ |
||||
return (fmult(state_ptr->a[1] >> 2, state_ptr->sr[1]) + |
||||
fmult(state_ptr->a[0] >> 2, state_ptr->sr[0])); |
||||
} |
||||
/*
|
||||
* step_size() |
||||
* |
||||
* computes the quantization step size of the adaptive quantizer. |
||||
* |
||||
*/ |
||||
int step_size(struct g72x_state *state_ptr) |
||||
{ |
||||
int y; |
||||
int dif; |
||||
int al; |
||||
|
||||
if (state_ptr->ap >= 256) |
||||
return (state_ptr->yu); |
||||
else { |
||||
y = state_ptr->yl >> 6; |
||||
dif = state_ptr->yu - y; |
||||
al = state_ptr->ap >> 2; |
||||
if (dif > 0) |
||||
y += (dif * al) >> 6; |
||||
else if (dif < 0) |
||||
y += (dif * al + 0x3F) >> 6; |
||||
return (y); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* quantize() |
||||
* |
||||
* Given a raw sample, 'd', of the difference signal and a |
||||
* quantization step size scale factor, 'y', this routine returns the |
||||
* ADPCM codeword to which that sample gets quantized. The step |
||||
* size scale factor division operation is done in the log base 2 domain |
||||
* as a subtraction. |
||||
*/ |
||||
int quantize(int d, int y, short const *table, int size) |
||||
{ |
||||
short dqm; /* Magnitude of 'd' */ |
||||
short exp; /* Integer part of base 2 log of 'd' */ |
||||
short mant; /* Fractional part of base 2 log */ |
||||
short dl; /* Log of magnitude of 'd' */ |
||||
short dln; /* Step size scale factor normalized log */ |
||||
int i; |
||||
|
||||
/*
|
||||
* LOG |
||||
* |
||||
* Compute base 2 log of 'd', and store in 'dl'. |
||||
*/ |
||||
dqm = abs(d); |
||||
exp = log2plus1(dqm >> 1); |
||||
mant = ((dqm << 7) >> exp) & 0x7F; /* Fractional portion. */ |
||||
dl = (exp << 7) + mant; |
||||
|
||||
/*
|
||||
* SUBTB |
||||
* |
||||
* "Divide" by step size multiplier. |
||||
*/ |
||||
dln = dl - (y >> 2); |
||||
|
||||
/*
|
||||
* QUAN |
||||
* |
||||
* Obtain codword i for 'd'. |
||||
*/ |
||||
i = quan(dln, table, size); |
||||
if (d < 0) /* take 1's complement of i */ |
||||
return ((size << 1) + 1 - i); |
||||
else if (i == 0) /* take 1's complement of 0 */ |
||||
return ((size << 1) + 1); /* new in 1988 */ |
||||
else |
||||
return (i); |
||||
} |
||||
/*
|
||||
* reconstruct() |
||||
* |
||||
* Returns reconstructed difference signal 'dq' obtained from |
||||
* codeword 'i' and quantization step size scale factor 'y'. |
||||
* Multiplication is performed in log base 2 domain as addition. |
||||
*/ |
||||
int reconstruct(int sign, int dqln, int y) |
||||
{ |
||||
short dql; /* Log of 'dq' magnitude */ |
||||
short dex; /* Integer part of log */ |
||||
short dqt; |
||||
short dq; /* Reconstructed difference signal sample */ |
||||
|
||||
dql = dqln + (y >> 2); /* ADDA */ |
||||
|
||||
if (dql < 0) { |
||||
return ((sign) ? -0x8000 : 0); |
||||
} else { /* ANTILOG */ |
||||
dex = (dql >> 7) & 15; |
||||
dqt = 128 + (dql & 127); |
||||
dq = (dqt << 7) >> (14 - dex); |
||||
return ((sign) ? (dq - 0x8000) : dq); |
||||
} |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* update() |
||||
* |
||||
* updates the state variables for each output code |
||||
*/ |
||||
void update(int code_size, int y, int wi, int fi, int dq, int sr, |
||||
int dqsez, struct g72x_state *state_ptr) |
||||
{ |
||||
int cnt; |
||||
short mag, exp; /* Adaptive predictor, FLOAT A */ |
||||
short a2p=0; /* LIMC */ |
||||
short a1ul; /* UPA1 */ |
||||
short pks1; /* UPA2 */ |
||||
short fa1; |
||||
char tr; /* tone/transition detector */ |
||||
short ylint, thr2, dqthr; |
||||
short ylfrac, thr1; |
||||
short pk0; |
||||
|
||||
pk0 = (dqsez < 0) ? 1 : 0; /* needed in updating predictor poles */ |
||||
|
||||
mag = dq & 0x7FFF; /* prediction difference magnitude */ |
||||
/* TRANS */ |
||||
ylint = state_ptr->yl >> 15; /* exponent part of yl */ |
||||
ylfrac = (state_ptr->yl >> 10) & 0x1F; /* fractional part of yl */ |
||||
thr1 = (32 + ylfrac) << ylint; /* threshold */ |
||||
thr2 = (ylint > 9) ? 31 << 10 : thr1; /* limit thr2 to 31 << 10 */ |
||||
dqthr = (thr2 + (thr2 >> 1)) >> 1; /* dqthr = 0.75 * thr2 */ |
||||
if (state_ptr->td == 0) /* signal supposed voice */ |
||||
tr = 0; |
||||
else if (mag <= dqthr) /* supposed data, but small mag */ |
||||
tr = 0; /* treated as voice */ |
||||
else /* signal is data (modem) */ |
||||
tr = 1; |
||||
|
||||
/*
|
||||
* Quantizer scale factor adaptation. |
||||
*/ |
||||
|
||||
/* FUNCTW & FILTD & DELAY */ |
||||
/* update non-steady state step size multiplier */ |
||||
state_ptr->yu = y + ((wi - y) >> 5); |
||||
|
||||
/* LIMB */ |
||||
if (state_ptr->yu < 544) /* 544 <= yu <= 5120 */ |
||||
state_ptr->yu = 544; |
||||
else if (state_ptr->yu > 5120) |
||||
state_ptr->yu = 5120; |
||||
|
||||
/* FILTE & DELAY */ |
||||
/* update steady state step size multiplier */ |
||||
state_ptr->yl += state_ptr->yu + ((-state_ptr->yl) >> 6); |
||||
|
||||
/*
|
||||
* Adaptive predictor coefficients. |
||||
*/ |
||||
if (tr == 1) { /* reset a's and b's for modem signal */ |
||||
state_ptr->a[0] = 0; |
||||
state_ptr->a[1] = 0; |
||||
state_ptr->b[0] = 0; |
||||
state_ptr->b[1] = 0; |
||||
state_ptr->b[2] = 0; |
||||
state_ptr->b[3] = 0; |
||||
state_ptr->b[4] = 0; |
||||
state_ptr->b[5] = 0; |
||||
} else { /* update a's and b's */ |
||||
pks1 = pk0 ^ state_ptr->pk[0]; /* UPA2 */ |
||||
|
||||
/* update predictor pole a[1] */ |
||||
a2p = state_ptr->a[1] - (state_ptr->a[1] >> 7); |
||||
if (dqsez != 0) { |
||||
fa1 = (pks1) ? state_ptr->a[0] : -state_ptr->a[0]; |
||||
if (fa1 < -8191) /* a2p = function of fa1 */ |
||||
a2p -= 0x100; |
||||
else if (fa1 > 8191) |
||||
a2p += 0xFF; |
||||
else |
||||
a2p += fa1 >> 5; |
||||
|
||||
if (pk0 ^ state_ptr->pk[1]) |
||||
{ |
||||
/* LIMC */ |
||||
if (a2p <= -12160) |
||||
a2p = -12288; |
||||
else if (a2p >= 12416) |
||||
a2p = 12288; |
||||
else |
||||
a2p -= 0x80; |
||||
} |
||||
else if (a2p <= -12416) |
||||
a2p = -12288; |
||||
else if (a2p >= 12160) |
||||
a2p = 12288; |
||||
else |
||||
a2p += 0x80; |
||||
} |
||||
|
||||
/* Possible bug: a2p not initialized if dqsez == 0) */ |
||||
/* TRIGB & DELAY */ |
||||
state_ptr->a[1] = a2p; |
||||
|
||||
/* UPA1 */ |
||||
/* update predictor pole a[0] */ |
||||
state_ptr->a[0] -= state_ptr->a[0] >> 8; |
||||
if (dqsez != 0) |
||||
{ |
||||
if (pks1 == 0) |
||||
state_ptr->a[0] += 192; |
||||
else |
||||
state_ptr->a[0] -= 192; |
||||
} |
||||
/* LIMD */ |
||||
a1ul = 15360 - a2p; |
||||
if (state_ptr->a[0] < -a1ul) |
||||
state_ptr->a[0] = -a1ul; |
||||
else if (state_ptr->a[0] > a1ul) |
||||
state_ptr->a[0] = a1ul; |
||||
|
||||
/* UPB : update predictor zeros b[6] */ |
||||
for (cnt = 0; cnt < 6; cnt++) { |
||||
if (code_size == 5) /* for 40Kbps G.723 */ |
||||
state_ptr->b[cnt] -= state_ptr->b[cnt] >> 9; |
||||
else /* for G.721 and 24Kbps G.723 */ |
||||
state_ptr->b[cnt] -= state_ptr->b[cnt] >> 8; |
||||
if (dq & 0x7FFF) { /* XOR */ |
||||
if ((dq ^ state_ptr->dq[cnt]) >= 0) |
||||
state_ptr->b[cnt] += 128; |
||||
else |
||||
state_ptr->b[cnt] -= 128; |
||||
} |
||||
} |
||||
} |
||||
|
||||
for (cnt = 5; cnt > 0; cnt--) |
||||
state_ptr->dq[cnt] = state_ptr->dq[cnt-1]; |
||||
/* FLOAT A : convert dq[0] to 4-bit exp, 6-bit mantissa f.p. */ |
||||
if (mag == 0) { |
||||
state_ptr->dq[0] = (dq >= 0) ? 0x20 : (short)(unsigned short)0xFC20; |
||||
} else { |
||||
exp = log2plus1(mag); |
||||
state_ptr->dq[0] = (dq >= 0) ? |
||||
(exp << 6) + ((mag << 6) >> exp) : |
||||
(exp << 6) + ((mag << 6) >> exp) - 0x400; |
||||
} |
||||
|
||||
state_ptr->sr[1] = state_ptr->sr[0]; |
||||
/* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */ |
||||
if (sr == 0) { |
||||
state_ptr->sr[0] = 0x20; |
||||
} else if (sr > 0) { |
||||
exp = log2plus1(sr); |
||||
state_ptr->sr[0] = (exp << 6) + ((sr << 6) >> exp); |
||||
} else if (sr > -32768) { |
||||
mag = -sr; |
||||
exp = log2plus1(mag); |
||||
state_ptr->sr[0] = (exp << 6) + ((mag << 6) >> exp) - 0x400; |
||||
} else |
||||
state_ptr->sr[0] = (short)(unsigned short)0xFC20; |
||||
|
||||
/* DELAY A */ |
||||
state_ptr->pk[1] = state_ptr->pk[0]; |
||||
state_ptr->pk[0] = pk0; |
||||
|
||||
/* TONE */ |
||||
if (tr == 1) /* this sample has been treated as data */ |
||||
state_ptr->td = 0; /* next one will be treated as voice */ |
||||
else if (a2p < -11776) /* small sample-to-sample correlation */ |
||||
state_ptr->td = 1; /* signal may be data */ |
||||
else /* signal is voice */ |
||||
state_ptr->td = 0; |
||||
|
||||
/*
|
||||
* Adaptation speed control. |
||||
*/ |
||||
state_ptr->dms += (fi - state_ptr->dms) >> 5; /* FILTA */ |
||||
state_ptr->dml += (((fi << 2) - state_ptr->dml) >> 7); /* FILTB */ |
||||
|
||||
if (tr == 1) |
||||
state_ptr->ap = 256; |
||||
else if (y < 1536) /* SUBTC */ |
||||
state_ptr->ap += (0x200 - state_ptr->ap) >> 4; |
||||
else if (state_ptr->td == 1) |
||||
state_ptr->ap += (0x200 - state_ptr->ap) >> 4; |
||||
else if (abs((state_ptr->dms << 2) - state_ptr->dml) >= |
||||
(state_ptr->dml >> 3)) |
||||
state_ptr->ap += (0x200 - state_ptr->ap) >> 4; |
||||
else |
||||
state_ptr->ap += (-state_ptr->ap) >> 4; |
||||
} |
||||
|
||||
/*
|
||||
* tandem_adjust(sr, se, y, i, sign) |
||||
* |
||||
* At the end of ADPCM decoding, it simulates an encoder which may be receiving |
||||
* the output of this decoder as a tandem process. If the output of the |
||||
* simulated encoder differs from the input to this decoder, the decoder output |
||||
* is adjusted by one level of A-law or u-law codes. |
||||
* |
||||
* Input: |
||||
* sr decoder output linear PCM sample, |
||||
* se predictor estimate sample, |
||||
* y quantizer step size, |
||||
* i decoder input code, |
||||
* sign sign bit of code i |
||||
* |
||||
* Return: |
||||
* adjusted A-law or u-law compressed sample. |
||||
*/ |
||||
int tandem_adjust_alaw(int sr, int se, int y, int i, int sign, short const *qtab) |
||||
{ |
||||
unsigned char sp; /* A-law compressed 8-bit code */ |
||||
short dx; /* prediction error */ |
||||
char id; /* quantized prediction error */ |
||||
int sd; /* adjusted A-law decoded sample value */ |
||||
int im; /* biased magnitude of i */ |
||||
int imx; /* biased magnitude of id */ |
||||
|
||||
if (sr <= -32768) |
||||
sr = -1; |
||||
sp = sox_13linear2alaw(((sr >> 1) << 3));/* short to A-law compression */ |
||||
dx = (sox_alaw2linear16(sp) >> 2) - se; /* 16-bit prediction error */ |
||||
id = quantize(dx, y, qtab, sign - 1); |
||||
|
||||
if (id == i) { /* no adjustment on sp */ |
||||
return (sp); |
||||
} else { /* sp adjustment needed */ |
||||
/* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */ |
||||
im = i ^ sign; /* 2's complement to biased unsigned */ |
||||
imx = id ^ sign; |
||||
|
||||
if (imx > im) { /* sp adjusted to next lower value */ |
||||
if (sp & 0x80) { |
||||
sd = (sp == 0xD5) ? 0x55 : |
||||
((sp ^ 0x55) - 1) ^ 0x55; |
||||
} else { |
||||
sd = (sp == 0x2A) ? 0x2A : |
||||
((sp ^ 0x55) + 1) ^ 0x55; |
||||
} |
||||
} else { /* sp adjusted to next higher value */ |
||||
if (sp & 0x80) |
||||
sd = (sp == 0xAA) ? 0xAA : |
||||
((sp ^ 0x55) + 1) ^ 0x55; |
||||
else |
||||
sd = (sp == 0x55) ? 0xD5 : |
||||
((sp ^ 0x55) - 1) ^ 0x55; |
||||
} |
||||
return (sd); |
||||
} |
||||
} |
||||
|
||||
int tandem_adjust_ulaw(int sr, int se, int y, int i, int sign, short const *qtab) |
||||
{ |
||||
unsigned char sp; /* u-law compressed 8-bit code */ |
||||
short dx; /* prediction error */ |
||||
char id; /* quantized prediction error */ |
||||
int sd; /* adjusted u-law decoded sample value */ |
||||
int im; /* biased magnitude of i */ |
||||
int imx; /* biased magnitude of id */ |
||||
|
||||
if (sr <= -32768) |
||||
sr = 0; |
||||
sp = sox_14linear2ulaw((sr << 2));/* short to u-law compression */ |
||||
dx = (sox_ulaw2linear16(sp) >> 2) - se; /* 16-bit prediction error */ |
||||
id = quantize(dx, y, qtab, sign - 1); |
||||
if (id == i) { |
||||
return (sp); |
||||
} else { |
||||
/* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */ |
||||
im = i ^ sign; /* 2's complement to biased unsigned */ |
||||
imx = id ^ sign; |
||||
if (imx > im) { /* sp adjusted to next lower value */ |
||||
if (sp & 0x80) |
||||
sd = (sp == 0xFF) ? 0x7E : sp + 1; |
||||
else |
||||
sd = (sp == 0) ? 0 : sp - 1; |
||||
|
||||
} else { /* sp adjusted to next higher value */ |
||||
if (sp & 0x80) |
||||
sd = (sp == 0x80) ? 0x80 : sp - 1; |
||||
else |
||||
sd = (sp == 0x7F) ? 0xFE : sp + 1; |
||||
} |
||||
return (sd); |
||||
} |
||||
} |
@ -1,157 +0,0 @@ |
||||
/* This source code is a product of Sun Microsystems, Inc. and is provided
|
||||
* for unrestricted use. Users may copy or modify this source code without |
||||
* charge. |
||||
* |
||||
* SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING |
||||
* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. |
||||
* |
||||
* Sun source code is provided with no support and without any obligation on |
||||
* the part of Sun Microsystems, Inc. to assist in its use, correction, |
||||
* modification or enhancement. |
||||
* |
||||
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE |
||||
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE |
||||
* OR ANY PART THEREOF. |
||||
* |
||||
* In no event will Sun Microsystems, Inc. be liable for any lost revenue |
||||
* or profits or other special, indirect and consequential damages, even if |
||||
* Sun has been advised of the possibility of such damages. |
||||
* |
||||
* Sun Microsystems, Inc. |
||||
* 2550 Garcia Avenue |
||||
* Mountain View, California 94043 |
||||
*/ |
||||
|
||||
/*
|
||||
* g72x.h |
||||
* |
||||
* Header file for CCITT conversion routines. |
||||
* |
||||
*/ |
||||
#ifndef _G72X_H |
||||
#define _G72X_H |
||||
|
||||
/* aliases */ |
||||
#define g721_decoder lsx_g721_decoder |
||||
#define g721_encoder lsx_g721_encoder |
||||
#define g723_24_decoder lsx_g723_24_decoder |
||||
#define g723_24_encoder lsx_g723_24_encoder |
||||
#define g723_40_decoder lsx_g723_40_decoder |
||||
#define g723_40_encoder lsx_g723_40_encoder |
||||
#define g72x_init_state lsx_g72x_init_state |
||||
#define predictor_pole lsx_g72x_predictor_pole |
||||
#define predictor_zero lsx_g72x_predictor_zero |
||||
#define quantize lsx_g72x_quantize |
||||
#define reconstruct lsx_g72x_reconstruct |
||||
#define step_size lsx_g72x_step_size |
||||
#define tandem_adjust_alaw lsx_g72x_tandem_adjust_alaw |
||||
#define tandem_adjust_ulaw lsx_g72x_tandem_adjust_ulaw |
||||
#define update lsx_g72x_update |
||||
|
||||
#define AUDIO_ENCODING_ULAW (1) /* ISDN u-law */ |
||||
#define AUDIO_ENCODING_ALAW (2) /* ISDN A-law */ |
||||
#define AUDIO_ENCODING_LINEAR (3) /* PCM 2's-complement (0-center) */ |
||||
|
||||
/*
|
||||
* The following is the definition of the state structure |
||||
* used by the G.721/G.723 encoder and decoder to preserve their internal |
||||
* state between successive calls. The meanings of the majority |
||||
* of the state structure fields are explained in detail in the |
||||
* CCITT Recommendation G.721. The field names are essentially indentical |
||||
* to variable names in the bit level description of the coding algorithm |
||||
* included in this Recommendation. |
||||
*/ |
||||
struct g72x_state { |
||||
long yl; /* Locked or steady state step size multiplier. */ |
||||
short yu; /* Unlocked or non-steady state step size multiplier. */ |
||||
short dms; /* Short term energy estimate. */ |
||||
short dml; /* Long term energy estimate. */ |
||||
short ap; /* Linear weighting coefficient of 'yl' and 'yu'. */ |
||||
|
||||
short a[2]; /* Coefficients of pole portion of prediction filter. */ |
||||
short b[6]; /* Coefficients of zero portion of prediction filter. */ |
||||
short pk[2]; /*
|
||||
* Signs of previous two samples of a partially |
||||
* reconstructed signal. |
||||
*/ |
||||
short dq[6]; /*
|
||||
* Previous 6 samples of the quantized difference |
||||
* signal represented in an internal floating point |
||||
* format. |
||||
*/ |
||||
short sr[2]; /*
|
||||
* Previous 2 samples of the quantized difference |
||||
* signal represented in an internal floating point |
||||
* format. |
||||
*/ |
||||
char td; /* delayed tone detect, new in 1988 version */ |
||||
}; |
||||
|
||||
/* External function definitions. */ |
||||
|
||||
extern void g72x_init_state(struct g72x_state *); |
||||
extern int g721_encoder( |
||||
int sample, |
||||
int in_coding, |
||||
struct g72x_state *state_ptr); |
||||
extern int g721_decoder( |
||||
int code, |
||||
int out_coding, |
||||
struct g72x_state *state_ptr); |
||||
extern int g723_16_encoder( |
||||
int sample, |
||||
int in_coding, |
||||
struct g72x_state *state_ptr); |
||||
extern int g723_16_decoder( |
||||
int code, |
||||
int out_coding, |
||||
struct g72x_state *state_ptr); |
||||
extern int g723_24_encoder( |
||||
int sample, |
||||
int in_coding, |
||||
struct g72x_state *state_ptr); |
||||
extern int g723_24_decoder( |
||||
int code, |
||||
int out_coding, |
||||
struct g72x_state *state_ptr); |
||||
extern int g723_40_encoder( |
||||
int sample, |
||||
int in_coding, |
||||
struct g72x_state *state_ptr); |
||||
extern int g723_40_decoder( |
||||
int code, |
||||
int out_coding, |
||||
struct g72x_state *state_ptr); |
||||
|
||||
int predictor_zero(struct g72x_state *state_ptr); |
||||
int predictor_pole(struct g72x_state *state_ptr); |
||||
int step_size(struct g72x_state *state_ptr); |
||||
int quantize(int d, |
||||
int y, |
||||
short const *table, |
||||
int size); |
||||
int reconstruct(int sign, |
||||
int dqln, |
||||
int y); |
||||
void update(int code_size, |
||||
int y, |
||||
int wi, |
||||
int fi, |
||||
int dq, |
||||
int sr, |
||||
int dqsez, |
||||
struct g72x_state *state_ptr); |
||||
int tandem_adjust_alaw(int sr, |
||||
int se, |
||||
int y, |
||||
int i, |
||||
int sign, |
||||
short const *qtab); |
||||
int tandem_adjust_ulaw(int sr, |
||||
int se, |
||||
int y, |
||||
int i, |
||||
int sign, |
||||
short const *qtab); |
||||
#endif /* !_G72X_H */ |
@ -1,276 +0,0 @@ |
||||
/* libSoX effect: gain/norm/etc. (c) 2008-9 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#define LSX_EFF_ALIAS |
||||
#include "sox_i.h" |
||||
#include <ctype.h> |
||||
#include <string.h> |
||||
|
||||
typedef struct { |
||||
sox_bool do_equalise, do_balance, do_balance_no_clip, do_limiter; |
||||
sox_bool do_restore, make_headroom, do_normalise, do_scan; |
||||
double fixed_gain; /* Valid only in channel 0 */ |
||||
|
||||
double mult, reclaim, rms, limiter; |
||||
off_t num_samples; |
||||
sox_sample_t min, max; |
||||
FILE * tmp_file; |
||||
} priv_t; |
||||
|
||||
static int create(sox_effect_t * effp, int argc, char * * argv) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
char const * q; |
||||
for (--argc, ++argv; argc && **argv == '-' && argv[0][1] && |
||||
!isdigit((unsigned char)argv[0][1]) && argv[0][1] != '.'; --argc, ++argv) |
||||
for (q = &argv[0][1]; *q; ++q) switch (*q) { |
||||
case 'n': p->do_scan = p->do_normalise = sox_true; break; |
||||
case 'e': p->do_scan = p->do_equalise = sox_true; break; |
||||
case 'B': p->do_scan = p->do_balance = sox_true; break; |
||||
case 'b': p->do_scan = p->do_balance_no_clip = sox_true; break; |
||||
case 'r': p->do_scan = p->do_restore = sox_true; break; |
||||
case 'h': p->make_headroom = sox_true; break; |
||||
case 'l': p->do_limiter = sox_true; break; |
||||
default: lsx_fail("invalid option `-%c'", *q); return lsx_usage(effp); |
||||
} |
||||
if ((p->do_equalise + p->do_balance + p->do_balance_no_clip + p->do_restore)/ sox_true > 1) { |
||||
lsx_fail("only one of -e, -B, -b, -r may be given"); |
||||
return SOX_EOF; |
||||
} |
||||
if (p->do_normalise && p->do_restore) { |
||||
lsx_fail("only one of -n, -r may be given"); |
||||
return SOX_EOF; |
||||
} |
||||
if (p->do_limiter && p->make_headroom) { |
||||
lsx_fail("only one of -l, -h may be given"); |
||||
return SOX_EOF; |
||||
} |
||||
do {NUMERIC_PARAMETER(fixed_gain, -HUGE_VAL, HUGE_VAL)} while (0); |
||||
p->fixed_gain = dB_to_linear(p->fixed_gain); |
||||
return argc? lsx_usage(effp) : SOX_SUCCESS; |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
|
||||
if (effp->flow == 0) { |
||||
if (p->do_restore) { |
||||
if (!effp->in_signal.mult || *effp->in_signal.mult >= 1) { |
||||
lsx_fail("can't reclaim headroom"); |
||||
return SOX_EOF; |
||||
} |
||||
p->reclaim = 1 / *effp->in_signal.mult; |
||||
} |
||||
effp->out_signal.mult = p->make_headroom? &p->fixed_gain : NULL; |
||||
if (!p->do_equalise && !p->do_balance && !p->do_balance_no_clip) |
||||
effp->flows = 1; /* essentially a conditional SOX_EFF_MCHAN */ |
||||
} |
||||
p->mult = 0; |
||||
p->max = 1; |
||||
p->min = -1; |
||||
if (p->do_scan) { |
||||
p->tmp_file = lsx_tmpfile(); |
||||
if (p->tmp_file == NULL) { |
||||
lsx_fail("can't create temporary file: %s", strerror(errno)); |
||||
return SOX_EOF; |
||||
} |
||||
} |
||||
if (p->do_limiter) |
||||
p->limiter = (1 - 1 / p->fixed_gain) * (1. / SOX_SAMPLE_MAX); |
||||
else if (p->fixed_gain == floor(p->fixed_gain) && !p->do_scan) |
||||
effp->out_signal.precision = effp->in_signal.precision; |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, |
||||
sox_sample_t * obuf, size_t * isamp, size_t * osamp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
size_t len; |
||||
|
||||
if (p->do_scan) { |
||||
if (fwrite(ibuf, sizeof(*ibuf), *isamp, p->tmp_file) != *isamp) { |
||||
lsx_fail("error writing temporary file: %s", strerror(errno)); |
||||
return SOX_EOF; |
||||
} |
||||
if (p->do_balance && !p->do_normalise) |
||||
for (len = *isamp; len; --len, ++ibuf) { |
||||
double d = SOX_SAMPLE_TO_FLOAT_64BIT(*ibuf, effp->clips); |
||||
p->rms += sqr(d); |
||||
++p->num_samples; |
||||
} |
||||
else if (p->do_balance || p->do_balance_no_clip) |
||||
for (len = *isamp; len; --len, ++ibuf) { |
||||
double d = SOX_SAMPLE_TO_FLOAT_64BIT(*ibuf, effp->clips); |
||||
p->rms += sqr(d); |
||||
++p->num_samples; |
||||
p->max = max(p->max, *ibuf); |
||||
p->min = min(p->min, *ibuf); |
||||
} |
||||
else for (len = *isamp; len; --len, ++ibuf) { |
||||
p->max = max(p->max, *ibuf); |
||||
p->min = min(p->min, *ibuf); |
||||
} |
||||
*osamp = 0; /* samples not output until drain */ |
||||
} |
||||
else { |
||||
double mult = ((priv_t *)(effp - effp->flow)->priv)->fixed_gain; |
||||
len = *isamp = *osamp = min(*isamp, *osamp); |
||||
if (!p->do_limiter) for (; len; --len, ++ibuf) |
||||
*obuf++ = SOX_ROUND_CLIP_COUNT(*ibuf * mult, effp->clips); |
||||
else for (; len; --len, ++ibuf) { |
||||
double d = *ibuf * mult; |
||||
*obuf++ = d < 0 ? 1 / (1 / d - p->limiter) - .5 : |
||||
d > 0 ? 1 / (1 / d + p->limiter) + .5 : 0; |
||||
} |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static void start_drain(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
double max = SOX_SAMPLE_MAX, max_peak = 0, max_rms = 0; |
||||
size_t i; |
||||
|
||||
if (p->do_balance || p->do_balance_no_clip) { |
||||
for (i = 0; i < effp->flows; ++i) { |
||||
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; |
||||
max_rms = max(max_rms, sqrt(q->rms / q->num_samples)); |
||||
rewind(q->tmp_file); |
||||
} |
||||
for (i = 0; i < effp->flows; ++i) { |
||||
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; |
||||
double this_rms = sqrt(q->rms / q->num_samples); |
||||
double this_peak = max(q->max / max, q->min / (double)SOX_SAMPLE_MIN); |
||||
q->mult = this_rms != 0? max_rms / this_rms : 1; |
||||
max_peak = max(max_peak, q->mult * this_peak); |
||||
q->mult *= p->fixed_gain; |
||||
} |
||||
if (p->do_normalise || (p->do_balance_no_clip && max_peak > 1)) |
||||
for (i = 0; i < effp->flows; ++i) { |
||||
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; |
||||
q->mult /= max_peak; |
||||
} |
||||
} else if (p->do_equalise && !p->do_normalise) { |
||||
for (i = 0; i < effp->flows; ++i) { |
||||
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; |
||||
double this_peak = max(q->max / max, q->min / (double)SOX_SAMPLE_MIN); |
||||
max_peak = max(max_peak, this_peak); |
||||
q->mult = p->fixed_gain / this_peak; |
||||
rewind(q->tmp_file); |
||||
} |
||||
for (i = 0; i < effp->flows; ++i) { |
||||
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; |
||||
q->mult *= max_peak; |
||||
} |
||||
} else { |
||||
p->mult = min(max / p->max, (double)SOX_SAMPLE_MIN / p->min); |
||||
if (p->do_restore) { |
||||
if (p->reclaim > p->mult) |
||||
lsx_report("%.3gdB not reclaimed", linear_to_dB(p->reclaim / p->mult)); |
||||
else p->mult = p->reclaim; |
||||
} |
||||
p->mult *= p->fixed_gain; |
||||
rewind(p->tmp_file); |
||||
} |
||||
} |
||||
|
||||
static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
size_t len; |
||||
int result = SOX_SUCCESS; |
||||
|
||||
*osamp -= *osamp % effp->in_signal.channels; |
||||
|
||||
if (p->do_scan) { |
||||
if (!p->mult) |
||||
start_drain(effp); |
||||
len = fread(obuf, sizeof(*obuf), *osamp, p->tmp_file); |
||||
if (len != *osamp && !feof(p->tmp_file)) { |
||||
lsx_fail("error reading temporary file: %s", strerror(errno)); |
||||
result = SOX_EOF; |
||||
} |
||||
if (!p->do_limiter) for (*osamp = len; len; --len, ++obuf) |
||||
*obuf = SOX_ROUND_CLIP_COUNT(*obuf * p->mult, effp->clips); |
||||
else for (*osamp = len; len; --len) { |
||||
double d = *obuf * p->mult; |
||||
*obuf++ = d < 0 ? 1 / (1 / d - p->limiter) - .5 : |
||||
d > 0 ? 1 / (1 / d + p->limiter) + .5 : 0; |
||||
} |
||||
} |
||||
else *osamp = 0; |
||||
return result; |
||||
} |
||||
|
||||
static int stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
if (p->do_scan) |
||||
fclose(p->tmp_file); /* auto-deleted by lsx_tmpfile */ |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_gain_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"gain", NULL, SOX_EFF_GAIN, |
||||
create, start, flow, drain, stop, NULL, sizeof(priv_t)}; |
||||
static char const * lines[] = { |
||||
"[-e|-b|-B|-r] [-n] [-l|-h] [gain-dB]", |
||||
"-e\t Equalise channels: peak to that with max peak;", |
||||
"-B\t Balance channels: rms to that with max rms; no clip protection", |
||||
"-b\t Balance channels: rms to that with max rms; clip protection", |
||||
"\t Note -Bn = -bn", |
||||
"-r\t Reclaim headroom (as much as possible without clipping); see -h", |
||||
"-n\t Norm file to 0dBfs(output precision); gain-dB, if present, usually <0", |
||||
"-l\t Use simple limiter", |
||||
"-h\t Apply attenuation for headroom for subsequent effects; gain-dB, if", |
||||
"\t present, is subject to reclaim by a subsequent gain -r", |
||||
"gain-dB\t Apply gain in dB", |
||||
}; |
||||
static char * usage; |
||||
handler.usage = lsx_usage_lines(&usage, lines, array_length(lines)); |
||||
return &handler; |
||||
} |
||||
|
||||
/*------------------ emulation of the old `normalise' effect -----------------*/ |
||||
|
||||
static int norm_getopts(sox_effect_t * effp, int argc, char * * argv) |
||||
{ |
||||
char * argv2[3]; |
||||
int argc2 = 2; |
||||
|
||||
argv2[0] = argv[0], --argc, ++argv; |
||||
argv2[1] = "-n"; |
||||
if (argc) |
||||
argv2[argc2++] = *argv, --argc, ++argv; |
||||
return argc? lsx_usage(effp) : |
||||
lsx_gain_effect_fn()->getopts(effp, argc2, argv2); |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_norm_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler; |
||||
handler = *lsx_gain_effect_fn(); |
||||
handler.name = "norm"; |
||||
handler.usage = "[level]"; |
||||
handler.getopts = norm_getopts; |
||||
return &handler; |
||||
} |
@ -1,102 +0,0 @@ |
||||
/* libSoX effect: Hilbert transform filter
|
||||
* |
||||
* First version of this effect written 11/2011 by Ulrich Klauer, using maths |
||||
* from "Understanding digital signal processing" by Richard G. Lyons. |
||||
* |
||||
* Copyright 2011 Chris Bagwell and SoX Contributors |
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "dft_filter.h" |
||||
|
||||
typedef struct { |
||||
dft_filter_priv_t base; |
||||
double *h; |
||||
int taps; |
||||
} priv_t; |
||||
|
||||
static int getopts(sox_effect_t *effp, int argc, char **argv) |
||||
{ |
||||
lsx_getopt_t optstate; |
||||
int c; |
||||
priv_t *p = (priv_t*)effp->priv; |
||||
dft_filter_priv_t *b = &p->base; |
||||
|
||||
b->filter_ptr = &b->filter; |
||||
|
||||
lsx_getopt_init(argc, argv, "+n:", NULL, lsx_getopt_flag_none, 1, &optstate); |
||||
|
||||
while ((c = lsx_getopt(&optstate)) != -1) switch (c) { |
||||
GETOPT_NUMERIC(optstate, 'n', taps, 3, 32767) |
||||
default: lsx_fail("invalid option `-%c'", optstate.opt); return lsx_usage(effp); |
||||
} |
||||
if (p->taps && p->taps%2 == 0) { |
||||
lsx_fail("only filters with an odd number of taps are supported"); |
||||
return SOX_EOF; |
||||
} |
||||
return optstate.ind != argc ? lsx_usage(effp) : SOX_SUCCESS; |
||||
} |
||||
|
||||
static int start(sox_effect_t *effp) |
||||
{ |
||||
priv_t *p = (priv_t*)effp->priv; |
||||
dft_filter_t *f = p->base.filter_ptr; |
||||
|
||||
if (!f->num_taps) { |
||||
int i; |
||||
if (!p->taps) { |
||||
p->taps = effp->in_signal.rate/76.5 + 2; |
||||
p->taps += 1 - (p->taps%2); |
||||
/* results in a cutoff frequency of about 75 Hz with a Blackman window */ |
||||
lsx_debug("choosing number of taps = %d (override with -n)", p->taps); |
||||
} |
||||
lsx_valloc(p->h, p->taps); |
||||
for (i = 0; i < p->taps; i++) { |
||||
int k = -(p->taps/2) + i; |
||||
if (k%2 == 0) { |
||||
p->h[i] = 0.0; |
||||
} else { |
||||
double pk = M_PI * k; |
||||
p->h[i] = (1 - cos(pk))/pk; |
||||
} |
||||
} |
||||
lsx_apply_blackman(p->h, p->taps, .16); |
||||
|
||||
if (effp->global_info->plot != sox_plot_off) { |
||||
char title[100]; |
||||
sprintf(title, "SoX effect: hilbert (%d taps)", p->taps); |
||||
lsx_plot_fir(p->h, p->taps, effp->in_signal.rate, |
||||
effp->global_info->plot, title, -20., 5.); |
||||
free(p->h); |
||||
return SOX_EOF; |
||||
} |
||||
lsx_set_dft_filter(f, p->h, p->taps, p->taps/2); |
||||
} |
||||
return lsx_dft_filter_effect_fn()->start(effp); |
||||
} |
||||
|
||||
sox_effect_handler_t const *lsx_hilbert_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler; |
||||
handler = *lsx_dft_filter_effect_fn(); |
||||
handler.name = "hilbert"; |
||||
handler.usage = "[-n taps]"; |
||||
handler.getopts = getopts; |
||||
handler.start = start; |
||||
handler.priv_size = sizeof(priv_t); |
||||
return &handler; |
||||
} |
@ -1,227 +0,0 @@ |
||||
/* libSoX MP3 utilities Copyright (c) 2007-9 SoX contributors
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "id3.h" |
||||
|
||||
#ifdef HAVE_ID3TAG |
||||
|
||||
#include <id3tag.h> |
||||
|
||||
static char const * id3tagmap[][2] = |
||||
{ |
||||
{"TIT2", "Title"}, |
||||
{"TPE1", "Artist"}, |
||||
{"TALB", "Album"}, |
||||
{"TCOM", "Composer"}, |
||||
{"TRCK", "Tracknumber"}, |
||||
{"TDRC", "Year"}, |
||||
{"TCON", "Genre"}, |
||||
{"COMM", "Comment"}, |
||||
{"TPOS", "Discnumber"}, |
||||
{NULL, NULL} |
||||
}; |
||||
|
||||
static id3_utf8_t * utf8_id3tag_findframe( |
||||
struct id3_tag * tag, const char * const frameid, unsigned index) |
||||
{ |
||||
struct id3_frame const * frame = id3_tag_findframe(tag, frameid, index); |
||||
if (frame) { |
||||
unsigned nfields = frame->nfields; |
||||
|
||||
while (nfields--) { |
||||
union id3_field const *field = id3_frame_field(frame, nfields); |
||||
int ftype = id3_field_type(field); |
||||
const id3_ucs4_t *ucs4 = NULL; |
||||
unsigned nstrings; |
||||
|
||||
switch (ftype) { |
||||
case ID3_FIELD_TYPE_STRING: |
||||
ucs4 = id3_field_getstring(field); |
||||
break; |
||||
|
||||
case ID3_FIELD_TYPE_STRINGFULL: |
||||
ucs4 = id3_field_getfullstring(field); |
||||
break; |
||||
|
||||
case ID3_FIELD_TYPE_STRINGLIST: |
||||
nstrings = id3_field_getnstrings(field); |
||||
while (nstrings--) { |
||||
ucs4 = id3_field_getstrings(field, nstrings); |
||||
if (ucs4) |
||||
break; |
||||
} |
||||
break; |
||||
} |
||||
|
||||
if (ucs4) |
||||
return id3_ucs4_utf8duplicate(ucs4); /* Must call free() on this */ |
||||
} |
||||
} |
||||
return NULL; |
||||
} |
||||
|
||||
struct tag_info_node |
||||
{ |
||||
struct tag_info_node * next; |
||||
off_t start; |
||||
off_t end; |
||||
}; |
||||
|
||||
struct tag_info { |
||||
sox_format_t * ft; |
||||
struct tag_info_node * head; |
||||
struct id3_tag * tag; |
||||
}; |
||||
|
||||
static int add_tag(struct tag_info * info) |
||||
{ |
||||
struct tag_info_node * current; |
||||
off_t start, end; |
||||
id3_byte_t query[ID3_TAG_QUERYSIZE]; |
||||
id3_byte_t * buffer; |
||||
long size; |
||||
int result = 0; |
||||
|
||||
/* Ensure we're at the start of a valid tag and get its size. */ |
||||
if (ID3_TAG_QUERYSIZE != lsx_readbuf(info->ft, query, ID3_TAG_QUERYSIZE) || |
||||
!(size = id3_tag_query(query, ID3_TAG_QUERYSIZE))) { |
||||
return 0; |
||||
} |
||||
if (size < 0) { |
||||
if (0 != lsx_seeki(info->ft, size, SEEK_CUR) || |
||||
ID3_TAG_QUERYSIZE != lsx_readbuf(info->ft, query, ID3_TAG_QUERYSIZE) || |
||||
(size = id3_tag_query(query, ID3_TAG_QUERYSIZE)) <= 0) { |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
/* Don't read a tag more than once. */ |
||||
start = lsx_tell(info->ft); |
||||
end = start + size; |
||||
for (current = info->head; current; current = current->next) { |
||||
if (start == current->start && end == current->end) { |
||||
return 1; |
||||
} else if (start < current->end && current->start < end) { |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
buffer = lsx_malloc((size_t)size); |
||||
if (!buffer) { |
||||
return 0; |
||||
} |
||||
memcpy(buffer, query, ID3_TAG_QUERYSIZE); |
||||
if ((unsigned long)size - ID3_TAG_QUERYSIZE == |
||||
lsx_readbuf(info->ft, buffer + ID3_TAG_QUERYSIZE, (size_t)size - ID3_TAG_QUERYSIZE)) { |
||||
struct id3_tag * tag = id3_tag_parse(buffer, (size_t)size); |
||||
if (tag) { |
||||
current = lsx_malloc(sizeof(struct tag_info_node)); |
||||
if (current) { |
||||
current->next = info->head; |
||||
current->start = start; |
||||
current->end = end; |
||||
info->head = current; |
||||
if (info->tag && (info->tag->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE)) { |
||||
struct id3_frame * frame; |
||||
unsigned i; |
||||
for (i = 0; (frame = id3_tag_findframe(tag, NULL, i)); i++) { |
||||
id3_tag_attachframe(info->tag, frame); |
||||
} |
||||
id3_tag_delete(tag); |
||||
} else { |
||||
if (info->tag) { |
||||
id3_tag_delete(info->tag); |
||||
} |
||||
info->tag = tag; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
free(buffer); |
||||
return result; |
||||
} |
||||
|
||||
void lsx_id3_read_tag(sox_format_t * ft, sox_bool search) |
||||
{ |
||||
struct tag_info info; |
||||
id3_utf8_t * utf8; |
||||
int i; |
||||
int has_id3v1 = 0; |
||||
|
||||
info.ft = ft; |
||||
info.head = NULL; |
||||
info.tag = NULL; |
||||
|
||||
/*
|
||||
We look for: |
||||
ID3v1 at end (EOF - 128). |
||||
ID3v2 at start. |
||||
ID3v2 at end (but before ID3v1 from end if there was one). |
||||
*/ |
||||
|
||||
if (search) { |
||||
if (0 == lsx_seeki(ft, -128, SEEK_END)) { |
||||
has_id3v1 = |
||||
add_tag(&info) && |
||||
1 == ID3_TAG_VERSION_MAJOR(id3_tag_version(info.tag)); |
||||
} |
||||
if (0 == lsx_seeki(ft, 0, SEEK_SET)) { |
||||
add_tag(&info); |
||||
} |
||||
if (0 == lsx_seeki(ft, has_id3v1 ? -138 : -10, SEEK_END)) { |
||||
add_tag(&info); |
||||
} |
||||
} else { |
||||
add_tag(&info); |
||||
} |
||||
|
||||
if (info.tag && info.tag->frames) { |
||||
for (i = 0; id3tagmap[i][0]; ++i) { |
||||
if ((utf8 = utf8_id3tag_findframe(info.tag, id3tagmap[i][0], 0))) { |
||||
char * comment = lsx_malloc(strlen(id3tagmap[i][1]) + 1 + strlen((char *)utf8) + 1); |
||||
sprintf(comment, "%s=%s", id3tagmap[i][1], utf8); |
||||
sox_append_comment(&ft->oob.comments, comment); |
||||
free(comment); |
||||
free(utf8); |
||||
} |
||||
} |
||||
if ((utf8 = utf8_id3tag_findframe(info.tag, "TLEN", 0))) { |
||||
unsigned long tlen = strtoul((char *)utf8, NULL, 10); |
||||
if (tlen > 0 && tlen < ULONG_MAX) { |
||||
ft->signal.length= tlen; /* In ms; convert to samples later */ |
||||
lsx_debug("got exact duration from ID3 TLEN"); |
||||
} |
||||
free(utf8); |
||||
} |
||||
} |
||||
while (info.head) { |
||||
struct tag_info_node * head = info.head; |
||||
info.head = head->next; |
||||
free(head); |
||||
} |
||||
if (info.tag) { |
||||
id3_tag_delete(info.tag); |
||||
} |
||||
} |
||||
|
||||
#else |
||||
|
||||
/* Stub for format modules */ |
||||
void lsx_id3_read_tag(sox_format_t *ft, sox_bool search) { } |
||||
|
||||
#endif |
@ -1,25 +0,0 @@ |
||||
/* libSoX MP3 utilities Copyright (c) 2007-9 SoX contributors
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#ifndef SOX_ID3_H |
||||
#define SOX_ID3_H |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
void lsx_id3_read_tag(sox_format_t *ft, sox_bool search); |
||||
|
||||
#endif |
@ -1,33 +0,0 @@ |
||||
/* libSoX format: raw IMA ADPCM (c) 2007-8 SoX contributors
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "adpcms.h" |
||||
#include "vox.h" |
||||
|
||||
LSX_FORMAT_HANDLER(ima) |
||||
{ |
||||
static char const * const names[] = {"ima", NULL}; |
||||
static unsigned const write_encodings[] = {SOX_ENCODING_IMA_ADPCM, 4, 0, 0}; |
||||
static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE, |
||||
"Raw IMA ADPCM", names, SOX_FILE_MONO, |
||||
lsx_ima_start, lsx_vox_read, lsx_vox_stopread, |
||||
lsx_ima_start, lsx_vox_write, lsx_vox_stopwrite, |
||||
lsx_rawseek, write_encodings, NULL, sizeof(adpcm_io_t) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,21 +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 |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "raw.h" |
||||
|
||||
RAW_FORMAT(la, 8, SOX_FILE_BIT_REV, ALAW) |
@ -1,492 +0,0 @@ |
||||
/* LADSPA effect support for sox
|
||||
* (c) Reuben Thomas <rrt@sc3d.org> 2007 |
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
#ifdef HAVE_LADSPA_H |
||||
|
||||
#include <assert.h> |
||||
#include <limits.h> |
||||
#include <string.h> |
||||
#include <math.h> |
||||
#include "ladspa.h" |
||||
|
||||
/*
|
||||
* Assuming LADSPA_Data == float. This is the case in 2012 and has been |
||||
* the case for many years now. |
||||
*/ |
||||
#define SOX_SAMPLE_TO_LADSPA_DATA(d,clips) \ |
||||
SOX_SAMPLE_TO_FLOAT_32BIT((d),(clips)) |
||||
#define LADSPA_DATA_TO_SOX_SAMPLE(d,clips) \ |
||||
SOX_FLOAT_32BIT_TO_SAMPLE((d),(clips)) |
||||
|
||||
static sox_effect_handler_t sox_ladspa_effect; |
||||
|
||||
/* Private data for resampling */ |
||||
typedef struct { |
||||
char *name; /* plugin name */ |
||||
lt_dlhandle lth; /* dynamic object handle */ |
||||
sox_bool clone; |
||||
const LADSPA_Descriptor *desc; /* plugin descriptor */ |
||||
LADSPA_Handle *handles; /* instantiated plugin handles */ |
||||
size_t handle_count; |
||||
LADSPA_Data *control; /* control ports */ |
||||
unsigned long *inputs; |
||||
size_t input_count; |
||||
unsigned long *outputs; |
||||
size_t output_count; |
||||
sox_bool latency_compensation; |
||||
LADSPA_Data *latency_control_port; |
||||
unsigned long in_latency; |
||||
unsigned long out_latency; |
||||
} priv_t; |
||||
|
||||
static LADSPA_Data ladspa_default(const LADSPA_PortRangeHint *p) |
||||
{ |
||||
LADSPA_Data d; |
||||
|
||||
if (LADSPA_IS_HINT_DEFAULT_0(p->HintDescriptor)) |
||||
d = 0.0; |
||||
else if (LADSPA_IS_HINT_DEFAULT_1(p->HintDescriptor)) |
||||
d = 1.0; |
||||
else if (LADSPA_IS_HINT_DEFAULT_100(p->HintDescriptor)) |
||||
d = 100.0; |
||||
else if (LADSPA_IS_HINT_DEFAULT_440(p->HintDescriptor)) |
||||
d = 440.0; |
||||
else if (LADSPA_IS_HINT_DEFAULT_MINIMUM(p->HintDescriptor)) |
||||
d = p->LowerBound; |
||||
else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(p->HintDescriptor)) |
||||
d = p->UpperBound; |
||||
else if (LADSPA_IS_HINT_DEFAULT_LOW(p->HintDescriptor)) { |
||||
if (LADSPA_IS_HINT_LOGARITHMIC(p->HintDescriptor)) |
||||
d = exp(log(p->LowerBound) * 0.75 + log(p->UpperBound) * 0.25); |
||||
else |
||||
d = p->LowerBound * 0.75 + p->UpperBound * 0.25; |
||||
} else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(p->HintDescriptor)) { |
||||
if (LADSPA_IS_HINT_LOGARITHMIC(p->HintDescriptor)) |
||||
d = exp(log(p->LowerBound) * 0.5 + log(p->UpperBound) * 0.5); |
||||
else |
||||
d = p->LowerBound * 0.5 + p->UpperBound * 0.5; |
||||
} else if (LADSPA_IS_HINT_DEFAULT_HIGH(p->HintDescriptor)) { |
||||
if (LADSPA_IS_HINT_LOGARITHMIC(p->HintDescriptor)) |
||||
d = exp(log(p->LowerBound) * 0.25 + log(p->UpperBound) * 0.75); |
||||
else |
||||
d = p->LowerBound * 0.25 + p->UpperBound * 0.75; |
||||
} else { /* shouldn't happen */ |
||||
/* FIXME: Deal with this at a higher level */ |
||||
lsx_fail("non-existent default value; using 0.1"); |
||||
d = 0.1; /* Should at least avoid divide by 0 */ |
||||
} |
||||
|
||||
return d; |
||||
} |
||||
|
||||
/*
|
||||
* Process options |
||||
*/ |
||||
static int sox_ladspa_getopts(sox_effect_t *effp, int argc, char **argv) |
||||
{ |
||||
priv_t * l_st = (priv_t *)effp->priv; |
||||
char *path; |
||||
int c; |
||||
union {LADSPA_Descriptor_Function fn; lt_ptr ptr;} ltptr; |
||||
unsigned long index = 0, i; |
||||
double arg; |
||||
lsx_getopt_t optstate; |
||||
lsx_getopt_init(argc, argv, "+rl", NULL, lsx_getopt_flag_none, 1, &optstate); |
||||
|
||||
while ((c = lsx_getopt(&optstate)) != -1) switch (c) { |
||||
case 'r': l_st->clone = sox_true; break; |
||||
case 'l': l_st->latency_compensation = sox_true; break; |
||||
default: |
||||
lsx_fail("unknown option `-%c'", optstate.opt); |
||||
return lsx_usage(effp); |
||||
} |
||||
argc -= optstate.ind, argv += optstate.ind; |
||||
|
||||
/* Get module name */ |
||||
if (argc >= 1) { |
||||
l_st->name = argv[0]; |
||||
argc--; argv++; |
||||
} |
||||
|
||||
/* Load module */ |
||||
path = getenv("LADSPA_PATH"); |
||||
if (path == NULL) |
||||
path = LADSPA_PATH; |
||||
|
||||
if(lt_dlinit() || lt_dlsetsearchpath(path) |
||||
|| (l_st->lth = lt_dlopenext(l_st->name)) == NULL) { |
||||
lsx_fail("could not open LADSPA plugin %s", l_st->name); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
/* Get descriptor function */ |
||||
if ((ltptr.ptr = lt_dlsym(l_st->lth, "ladspa_descriptor")) == NULL) { |
||||
lsx_fail("could not find ladspa_descriptor"); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
/* If no plugins in this module, complain */ |
||||
if (ltptr.fn(0UL) == NULL) { |
||||
lsx_fail("no plugins found"); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
/* Get first plugin descriptor */ |
||||
l_st->desc = ltptr.fn(0UL); |
||||
assert(l_st->desc); /* We already know this will work */ |
||||
|
||||
/* If more than one plugin, or first argument is not a number, try
|
||||
to use first argument as plugin label. */ |
||||
if (argc > 0 && (ltptr.fn(1UL) != NULL || !sscanf(argv[0], "%lf", &arg))) { |
||||
while (l_st->desc && strcmp(l_st->desc->Label, argv[0]) != 0) |
||||
l_st->desc = ltptr.fn(++index); |
||||
if (l_st->desc == NULL) { |
||||
lsx_fail("no plugin called `%s' found", argv[0]); |
||||
return SOX_EOF; |
||||
} |
||||
argc--; argv++; |
||||
} |
||||
|
||||
/* Scan the ports for inputs and outputs */ |
||||
l_st->control = lsx_calloc(l_st->desc->PortCount, sizeof(LADSPA_Data)); |
||||
l_st->inputs = lsx_malloc(l_st->desc->PortCount * sizeof(unsigned long)); |
||||
l_st->outputs = lsx_malloc(l_st->desc->PortCount * sizeof(unsigned long)); |
||||
|
||||
for (i = 0; i < l_st->desc->PortCount; i++) { |
||||
const LADSPA_PortDescriptor port = l_st->desc->PortDescriptors[i]; |
||||
|
||||
/* Check port is well specified. All control ports should be
|
||||
inputs, but don't bother checking, as we never rely on this. */ |
||||
if (LADSPA_IS_PORT_INPUT(port) && LADSPA_IS_PORT_OUTPUT(port)) { |
||||
lsx_fail("port %lu is both input and output", i); |
||||
return SOX_EOF; |
||||
} else if (LADSPA_IS_PORT_CONTROL(port) && LADSPA_IS_PORT_AUDIO(port)) { |
||||
lsx_fail("port %lu is both audio and control", i); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
if (LADSPA_IS_PORT_AUDIO(port)) { |
||||
if (LADSPA_IS_PORT_INPUT(port)) { |
||||
l_st->inputs[l_st->input_count++] = i; |
||||
} else if (LADSPA_IS_PORT_OUTPUT(port)) { |
||||
l_st->outputs[l_st->output_count++] = i; |
||||
} |
||||
} else { /* Control port */ |
||||
if (l_st->latency_compensation && |
||||
LADSPA_IS_PORT_CONTROL(port) && |
||||
LADSPA_IS_PORT_OUTPUT(port) && |
||||
strcmp(l_st->desc->PortNames[i], "latency") == 0) { |
||||
/* automatic latency compensation, Ardour does this, too */ |
||||
l_st->latency_control_port = &l_st->control[i]; |
||||
assert(*l_st->latency_control_port == 0); |
||||
lsx_debug("latency control port is %lu", i); |
||||
} else if (argc == 0) { |
||||
if (!LADSPA_IS_HINT_HAS_DEFAULT(l_st->desc->PortRangeHints[i].HintDescriptor)) { |
||||
lsx_fail("not enough arguments for control ports"); |
||||
return SOX_EOF; |
||||
} |
||||
l_st->control[i] = ladspa_default(&(l_st->desc->PortRangeHints[i])); |
||||
lsx_debug("default argument for port %lu is %f", i, l_st->control[i]); |
||||
} else { |
||||
if (!sscanf(argv[0], "%lf", &arg)) |
||||
return lsx_usage(effp); |
||||
l_st->control[i] = (LADSPA_Data)arg; |
||||
lsx_debug("argument for port %lu is %f", i, l_st->control[i]); |
||||
argc--; argv++; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* Stop if we have any unused arguments */ |
||||
return argc? lsx_usage(effp) : SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Prepare processing. |
||||
*/ |
||||
static int sox_ladspa_start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * l_st = (priv_t *)effp->priv; |
||||
unsigned long i; |
||||
size_t h; |
||||
unsigned long rate = (unsigned long)effp->in_signal.rate; |
||||
|
||||
/* Instantiate the plugin */ |
||||
lsx_debug("rate for plugin is %g", effp->in_signal.rate); |
||||
|
||||
if (l_st->input_count == 1 && l_st->output_count == 1 && |
||||
effp->in_signal.channels == effp->out_signal.channels) { |
||||
/* for mono plugins, they are common */ |
||||
|
||||
if (!l_st->clone && effp->in_signal.channels > 1) { |
||||
lsx_fail("expected 1 input channel(s), found %u; consider using -r", |
||||
effp->in_signal.channels); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
/*
|
||||
* create one handle per channel for mono plugins. ecasound does this, too. |
||||
* mono LADSPA plugins are common and SoX supported mono LADSPA plugins |
||||
* exclusively for a while. |
||||
*/ |
||||
l_st->handles = lsx_malloc(effp->in_signal.channels * |
||||
sizeof(LADSPA_Handle *)); |
||||
|
||||
while (l_st->handle_count < effp->in_signal.channels) |
||||
l_st->handles[l_st->handle_count++] = l_st->desc->instantiate(l_st->desc, rate); |
||||
|
||||
} else { |
||||
/*
|
||||
* assume the plugin is multi-channel capable with one instance, |
||||
* Some LADSPA plugins are stereo (e.g. bs2b-ladspa) |
||||
*/ |
||||
|
||||
if (l_st->input_count < effp->in_signal.channels) { |
||||
lsx_fail("fewer plugin input ports than input channels (%u < %u)", |
||||
(unsigned)l_st->input_count, effp->in_signal.channels); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
/* warn if LADSPA audio ports are unused. ecasound does this, too */ |
||||
if (l_st->input_count > effp->in_signal.channels) |
||||
lsx_warn("more plugin input ports than input channels (%u > %u)", |
||||
(unsigned)l_st->input_count, effp->in_signal.channels); |
||||
|
||||
/*
|
||||
* some LADSPA plugins increase/decrease the channel count |
||||
* (e.g. "mixer" in cmt or vocoder): |
||||
*/ |
||||
if (l_st->output_count != effp->out_signal.channels) { |
||||
lsx_debug("changing output channels to match plugin output ports (%u => %u)", |
||||
effp->out_signal.channels, (unsigned)l_st->output_count); |
||||
effp->out_signal.channels = l_st->output_count; |
||||
} |
||||
|
||||
l_st->handle_count = 1; |
||||
l_st->handles = lsx_malloc(sizeof(LADSPA_Handle *)); |
||||
l_st->handles[0] = l_st->desc->instantiate(l_st->desc, rate); |
||||
} |
||||
|
||||
/* abandon everything completely on any failed handle instantiation */ |
||||
for (h = 0; h < l_st->handle_count; h++) { |
||||
if (l_st->handles[h] == NULL) { |
||||
/* cleanup the handles that did instantiate successfully */ |
||||
for (h = 0; l_st->desc->cleanup && h < l_st->handle_count; h++) { |
||||
if (l_st->handles[h]) |
||||
l_st->desc->cleanup(l_st->handles[h]); |
||||
} |
||||
|
||||
free(l_st->handles); |
||||
l_st->handle_count = 0; |
||||
lsx_fail("could not instantiate plugin"); |
||||
return SOX_EOF; |
||||
} |
||||
} |
||||
|
||||
for (i = 0; i < l_st->desc->PortCount; i++) { |
||||
const LADSPA_PortDescriptor port = l_st->desc->PortDescriptors[i]; |
||||
|
||||
if (LADSPA_IS_PORT_CONTROL(port)) { |
||||
for (h = 0; h < l_st->handle_count; h++) |
||||
l_st->desc->connect_port(l_st->handles[h], i, &(l_st->control[i])); |
||||
} |
||||
} |
||||
|
||||
/* If needed, activate the plugin instances */ |
||||
if (l_st->desc->activate) { |
||||
for (h = 0; h < l_st->handle_count; h++) |
||||
l_st->desc->activate(l_st->handles[h]); |
||||
} |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Process one bufferful of data. |
||||
*/ |
||||
static int sox_ladspa_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, |
||||
size_t *isamp, size_t *osamp) |
||||
{ |
||||
priv_t * l_st = (priv_t *)effp->priv; |
||||
size_t i, len = min(*isamp, *osamp); |
||||
size_t j; |
||||
size_t h; |
||||
const size_t total_input_count = l_st->input_count * l_st->handle_count; |
||||
const size_t total_output_count = l_st->output_count * l_st->handle_count; |
||||
const size_t input_len = len / total_input_count; |
||||
size_t output_len = len / total_output_count; |
||||
|
||||
if (total_output_count < total_input_count) |
||||
output_len = input_len; |
||||
|
||||
*isamp = len; |
||||
*osamp = 0; |
||||
|
||||
if (len) { |
||||
LADSPA_Data *buf = lsx_calloc(len, sizeof(LADSPA_Data)); |
||||
LADSPA_Data *outbuf = lsx_calloc(len, sizeof(LADSPA_Data)); |
||||
LADSPA_Handle handle; |
||||
unsigned long port, l; |
||||
SOX_SAMPLE_LOCALS; |
||||
|
||||
/*
|
||||
* prepare buffer for LADSPA input |
||||
* deinterleave sox samples and write non-interleaved data to |
||||
* input_port-specific buffer locations |
||||
*/ |
||||
for (i = 0; i < input_len; i++) { |
||||
for (j = 0; j < total_input_count; j++) { |
||||
const sox_sample_t s = *ibuf++; |
||||
buf[j * input_len + i] = SOX_SAMPLE_TO_LADSPA_DATA(s, effp->clips); |
||||
} |
||||
} |
||||
|
||||
/* Connect the LADSPA input port(s) to the prepared buffers */ |
||||
for (j = 0; j < total_input_count; j++) { |
||||
handle = l_st->handles[j / l_st->input_count]; |
||||
port = l_st->inputs[j / l_st->handle_count]; |
||||
l_st->desc->connect_port(handle, port, buf + j * input_len); |
||||
} |
||||
|
||||
/* Connect the LADSPA output port(s) if used */ |
||||
for (j = 0; j < total_output_count; j++) { |
||||
handle = l_st->handles[j / l_st->output_count]; |
||||
port = l_st->outputs[j / l_st->handle_count]; |
||||
l_st->desc->connect_port(handle, port, outbuf + j * output_len); |
||||
} |
||||
|
||||
/* Run the plugin for each handle */ |
||||
for (h = 0; h < l_st->handle_count; h++) |
||||
l_st->desc->run(l_st->handles[h], input_len); |
||||
|
||||
/* check the latency control port if we have one */ |
||||
if (l_st->latency_control_port) { |
||||
lsx_debug("latency detected is %g", *l_st->latency_control_port); |
||||
l_st->in_latency = (unsigned long)floor(*l_st->latency_control_port); |
||||
|
||||
/* we will need this later in sox_ladspa_drain */ |
||||
l_st->out_latency = l_st->in_latency; |
||||
|
||||
/* latency for plugins is constant, only compensate once */ |
||||
l_st->latency_control_port = NULL; |
||||
} |
||||
|
||||
/* Grab output if effect produces it, re-interleaving it */ |
||||
l = min(output_len, l_st->in_latency); |
||||
for (i = l; i < output_len; i++) { |
||||
for (j = 0; j < total_output_count; j++) { |
||||
LADSPA_Data d = outbuf[j * output_len + i]; |
||||
*obuf++ = LADSPA_DATA_TO_SOX_SAMPLE(d, effp->clips); |
||||
(*osamp)++; |
||||
} |
||||
} |
||||
l_st->in_latency -= l; |
||||
|
||||
free(outbuf); |
||||
free(buf); |
||||
} |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Nothing to do if the plugin has no latency or latency compensation is |
||||
* disabled. |
||||
*/ |
||||
static int sox_ladspa_drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp) |
||||
{ |
||||
priv_t * l_st = (priv_t *)effp->priv; |
||||
sox_sample_t *ibuf, *dbuf; |
||||
size_t isamp, dsamp; |
||||
int r; |
||||
|
||||
if (l_st->out_latency == 0) { |
||||
*osamp = 0; |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/* feed some silence at the end to push the rest of the data out */ |
||||
isamp = l_st->out_latency * effp->in_signal.channels; |
||||
dsamp = l_st->out_latency * effp->out_signal.channels; |
||||
ibuf = lsx_calloc(isamp, sizeof(sox_sample_t)); |
||||
dbuf = lsx_calloc(dsamp, sizeof(sox_sample_t)); |
||||
|
||||
r = sox_ladspa_flow(effp, ibuf, dbuf, &isamp, &dsamp); |
||||
*osamp = min(dsamp, *osamp); |
||||
memcpy(obuf, dbuf, *osamp * sizeof(sox_sample_t)); |
||||
|
||||
free(ibuf); |
||||
free(dbuf); |
||||
|
||||
return r == SOX_SUCCESS ? SOX_EOF : 0; |
||||
} |
||||
|
||||
/*
|
||||
* Do anything required when you stop reading samples. |
||||
* Don't close input file! |
||||
*/ |
||||
static int sox_ladspa_stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * l_st = (priv_t *)effp->priv; |
||||
size_t h; |
||||
|
||||
for (h = 0; h < l_st->handle_count; h++) { |
||||
/* If needed, deactivate and cleanup the plugin */ |
||||
if (l_st->desc->deactivate) |
||||
l_st->desc->deactivate(l_st->handles[h]); |
||||
if (l_st->desc->cleanup) |
||||
l_st->desc->cleanup(l_st->handles[h]); |
||||
} |
||||
free(l_st->handles); |
||||
l_st->handle_count = 0; |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int sox_ladspa_kill(sox_effect_t * effp) |
||||
{ |
||||
priv_t * l_st = (priv_t *)effp->priv; |
||||
|
||||
free(l_st->control); |
||||
free(l_st->inputs); |
||||
free(l_st->outputs); |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static sox_effect_handler_t sox_ladspa_effect = { |
||||
"ladspa", |
||||
"MODULE [PLUGIN] [ARGUMENT...]", |
||||
SOX_EFF_MCHAN | SOX_EFF_CHAN | SOX_EFF_GAIN, |
||||
sox_ladspa_getopts, |
||||
sox_ladspa_start, |
||||
sox_ladspa_flow, |
||||
sox_ladspa_drain, |
||||
sox_ladspa_stop, |
||||
sox_ladspa_kill, |
||||
sizeof(priv_t) |
||||
}; |
||||
|
||||
const sox_effect_handler_t *lsx_ladspa_effect_fn(void) |
||||
{ |
||||
return &sox_ladspa_effect; |
||||
} |
||||
|
||||
#endif /* HAVE_LADSPA */ |
@ -1,603 +0,0 @@ |
||||
/* ladspa.h
|
||||
|
||||
Linux Audio Developer's Simple Plugin API Version 1.1[LGPL]. |
||||
Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis, |
||||
Stefan Westerfeld. |
||||
|
||||
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 St, Fifth Floor, Boston, MA 02110-1301 |
||||
USA. */ |
||||
|
||||
#ifndef LADSPA_INCLUDED |
||||
#define LADSPA_INCLUDED |
||||
|
||||
#define LADSPA_VERSION "1.1" |
||||
#define LADSPA_VERSION_MAJOR 1 |
||||
#define LADSPA_VERSION_MINOR 1 |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/*****************************************************************************/ |
||||
|
||||
/* Overview:
|
||||
|
||||
There is a large number of synthesis packages in use or development |
||||
on the Linux platform at this time. This API (`The Linux Audio |
||||
Developer's Simple Plugin API') attempts to give programmers the |
||||
ability to write simple `plugin' audio processors in C/C++ and link |
||||
them dynamically (`plug') into a range of these packages (`hosts'). |
||||
It should be possible for any host and any plugin to communicate |
||||
completely through this interface. |
||||
|
||||
This API is deliberately short and simple. To achieve compatibility |
||||
with a range of promising Linux sound synthesis packages it |
||||
attempts to find the `greatest common divisor' in their logical |
||||
behaviour. Having said this, certain limiting decisions are |
||||
implicit, notably the use of a fixed type (LADSPA_Data) for all |
||||
data transfer and absence of a parameterised `initialisation' |
||||
phase. See below for the LADSPA_Data typedef. |
||||
|
||||
Plugins are expected to distinguish between control and audio |
||||
data. Plugins have `ports' that are inputs or outputs for audio or |
||||
control data and each plugin is `run' for a `block' corresponding |
||||
to a short time interval measured in samples. Audio data is |
||||
communicated using arrays of LADSPA_Data, allowing a block of audio |
||||
to be processed by the plugin in a single pass. Control data is |
||||
communicated using single LADSPA_Data values. Control data has a |
||||
single value at the start of a call to the `run()' or `run_adding()' |
||||
function, and may be considered to remain this value for its |
||||
duration. The plugin may assume that all its input and output ports |
||||
have been connected to the relevant data location (see the |
||||
`connect_port()' function below) before it is asked to run. |
||||
|
||||
Plugins will reside in shared object files suitable for dynamic |
||||
linking by dlopen() and family. The file will provide a number of |
||||
`plugin types' that can be used to instantiate actual plugins |
||||
(sometimes known as `plugin instances') that can be connected |
||||
together to perform tasks. |
||||
|
||||
This API contains very limited error-handling. */ |
||||
|
||||
/*****************************************************************************/ |
||||
|
||||
/* Fundamental data type passed in and out of plugin. This data type
|
||||
is used to communicate audio samples and control values. It is |
||||
assumed that the plugin will work sensibly given any numeric input |
||||
value although it may have a preferred range (see hints below).
|
||||
|
||||
For audio it is generally assumed that 1.0f is the `0dB' reference |
||||
amplitude and is a `normal' signal level. */ |
||||
|
||||
typedef float LADSPA_Data; |
||||
|
||||
/*****************************************************************************/ |
||||
|
||||
/* Special Plugin Properties:
|
||||
|
||||
Optional features of the plugin type are encapsulated in the |
||||
LADSPA_Properties type. This is assembled by ORing individual |
||||
properties together. */ |
||||
|
||||
typedef int LADSPA_Properties; |
||||
|
||||
/* Property LADSPA_PROPERTY_REALTIME indicates that the plugin has a
|
||||
real-time dependency (e.g. listens to a MIDI device) and so its |
||||
output must not be cached or subject to significant latency. */ |
||||
#define LADSPA_PROPERTY_REALTIME 0x1 |
||||
|
||||
/* Property LADSPA_PROPERTY_INPLACE_BROKEN indicates that the plugin
|
||||
may cease to work correctly if the host elects to use the same data |
||||
location for both input and output (see connect_port()). This |
||||
should be avoided as enabling this flag makes it impossible for |
||||
hosts to use the plugin to process audio `in-place.' */ |
||||
#define LADSPA_PROPERTY_INPLACE_BROKEN 0x2 |
||||
|
||||
/* Property LADSPA_PROPERTY_HARD_RT_CAPABLE indicates that the plugin
|
||||
is capable of running not only in a conventional host but also in a |
||||
`hard real-time' environment. To qualify for this the plugin must |
||||
satisfy all of the following: |
||||
|
||||
(1) The plugin must not use malloc(), free() or other heap memory |
||||
management within its run() or run_adding() functions. All new |
||||
memory used in run() must be managed via the stack. These |
||||
restrictions only apply to the run() function. |
||||
|
||||
(2) The plugin will not attempt to make use of any library |
||||
functions with the exceptions of functions in the ANSI standard C |
||||
and C maths libraries, which the host is expected to provide. |
||||
|
||||
(3) The plugin will not access files, devices, pipes, sockets, IPC |
||||
or any other mechanism that might result in process or thread |
||||
blocking. |
||||
|
||||
(4) The plugin will take an amount of time to execute a run() or |
||||
run_adding() call approximately of form (A+B*SampleCount) where A |
||||
and B depend on the machine and host in use. This amount of time |
||||
may not depend on input signals or plugin state. The host is left |
||||
the responsibility to perform timings to estimate upper bounds for |
||||
A and B. */ |
||||
#define LADSPA_PROPERTY_HARD_RT_CAPABLE 0x4 |
||||
|
||||
#define LADSPA_IS_REALTIME(x) ((x) & LADSPA_PROPERTY_REALTIME) |
||||
#define LADSPA_IS_INPLACE_BROKEN(x) ((x) & LADSPA_PROPERTY_INPLACE_BROKEN) |
||||
#define LADSPA_IS_HARD_RT_CAPABLE(x) ((x) & LADSPA_PROPERTY_HARD_RT_CAPABLE) |
||||
|
||||
/*****************************************************************************/ |
||||
|
||||
/* Plugin Ports:
|
||||
|
||||
Plugins have `ports' that are inputs or outputs for audio or |
||||
data. Ports can communicate arrays of LADSPA_Data (for audio |
||||
inputs/outputs) or single LADSPA_Data values (for control |
||||
input/outputs). This information is encapsulated in the |
||||
LADSPA_PortDescriptor type which is assembled by ORing individual |
||||
properties together. |
||||
|
||||
Note that a port must be an input or an output port but not both |
||||
and that a port must be a control or audio port but not both. */ |
||||
|
||||
typedef int LADSPA_PortDescriptor; |
||||
|
||||
/* Property LADSPA_PORT_INPUT indicates that the port is an input. */ |
||||
#define LADSPA_PORT_INPUT 0x1 |
||||
|
||||
/* Property LADSPA_PORT_OUTPUT indicates that the port is an output. */ |
||||
#define LADSPA_PORT_OUTPUT 0x2 |
||||
|
||||
/* Property LADSPA_PORT_CONTROL indicates that the port is a control
|
||||
port. */ |
||||
#define LADSPA_PORT_CONTROL 0x4 |
||||
|
||||
/* Property LADSPA_PORT_AUDIO indicates that the port is a audio
|
||||
port. */ |
||||
#define LADSPA_PORT_AUDIO 0x8 |
||||
|
||||
#define LADSPA_IS_PORT_INPUT(x) ((x) & LADSPA_PORT_INPUT) |
||||
#define LADSPA_IS_PORT_OUTPUT(x) ((x) & LADSPA_PORT_OUTPUT) |
||||
#define LADSPA_IS_PORT_CONTROL(x) ((x) & LADSPA_PORT_CONTROL) |
||||
#define LADSPA_IS_PORT_AUDIO(x) ((x) & LADSPA_PORT_AUDIO) |
||||
|
||||
/*****************************************************************************/ |
||||
|
||||
/* Plugin Port Range Hints:
|
||||
|
||||
The host may wish to provide a representation of data entering or |
||||
leaving a plugin (e.g. to generate a GUI automatically). To make |
||||
this more meaningful, the plugin should provide `hints' to the host |
||||
describing the usual values taken by the data. |
||||
|
||||
Note that these are only hints. The host may ignore them and the |
||||
plugin must not assume that data supplied to it is meaningful. If |
||||
the plugin receives invalid input data it is expected to continue |
||||
to run without failure and, where possible, produce a sensible |
||||
output (e.g. a high-pass filter given a negative cutoff frequency |
||||
might switch to an all-pass mode). |
||||
|
||||
Hints are meaningful for all input and output ports but hints for |
||||
input control ports are expected to be particularly useful. |
||||
|
||||
More hint information is encapsulated in the |
||||
LADSPA_PortRangeHintDescriptor type which is assembled by ORing |
||||
individual hint types together. Hints may require further |
||||
LowerBound and UpperBound information. |
||||
|
||||
All the hint information for a particular port is aggregated in the |
||||
LADSPA_PortRangeHint structure. */ |
||||
|
||||
typedef int LADSPA_PortRangeHintDescriptor; |
||||
|
||||
/* Hint LADSPA_HINT_BOUNDED_BELOW indicates that the LowerBound field
|
||||
of the LADSPA_PortRangeHint should be considered meaningful. The |
||||
value in this field should be considered the (inclusive) lower |
||||
bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also |
||||
specified then the value of LowerBound should be multiplied by the |
||||
sample rate. */ |
||||
#define LADSPA_HINT_BOUNDED_BELOW 0x1 |
||||
|
||||
/* Hint LADSPA_HINT_BOUNDED_ABOVE indicates that the UpperBound field
|
||||
of the LADSPA_PortRangeHint should be considered meaningful. The |
||||
value in this field should be considered the (inclusive) upper |
||||
bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also |
||||
specified then the value of UpperBound should be multiplied by the |
||||
sample rate. */ |
||||
#define LADSPA_HINT_BOUNDED_ABOVE 0x2 |
||||
|
||||
/* Hint LADSPA_HINT_TOGGLED indicates that the data item should be
|
||||
considered a Boolean toggle. Data less than or equal to zero should |
||||
be considered `off' or `false,' and data above zero should be |
||||
considered `on' or `true.' LADSPA_HINT_TOGGLED may not be used in |
||||
conjunction with any other hint except LADSPA_HINT_DEFAULT_0 or |
||||
LADSPA_HINT_DEFAULT_1. */ |
||||
#define LADSPA_HINT_TOGGLED 0x4 |
||||
|
||||
/* Hint LADSPA_HINT_SAMPLE_RATE indicates that any bounds specified
|
||||
should be interpreted as multiples of the sample rate. For |
||||
instance, a frequency range from 0Hz to the Nyquist frequency (half |
||||
the sample rate) could be requested by this hint in conjunction |
||||
with LowerBound = 0 and UpperBound = 0.5. Hosts that support bounds |
||||
at all must support this hint to retain meaning. */ |
||||
#define LADSPA_HINT_SAMPLE_RATE 0x8 |
||||
|
||||
/* Hint LADSPA_HINT_LOGARITHMIC indicates that it is likely that the
|
||||
user will find it more intuitive to view values using a logarithmic |
||||
scale. This is particularly useful for frequencies and gains. */ |
||||
#define LADSPA_HINT_LOGARITHMIC 0x10 |
||||
|
||||
/* Hint LADSPA_HINT_INTEGER indicates that a user interface would
|
||||
probably wish to provide a stepped control taking only integer |
||||
values. Any bounds set should be slightly wider than the actual |
||||
integer range required to avoid floating point rounding errors. For |
||||
instance, the integer set {0,1,2,3} might be described as [-0.1, |
||||
3.1]. */ |
||||
#define LADSPA_HINT_INTEGER 0x20 |
||||
|
||||
/* The various LADSPA_HINT_HAS_DEFAULT_* hints indicate a `normal'
|
||||
value for the port that is sensible as a default. For instance, |
||||
this value is suitable for use as an initial value in a user |
||||
interface or as a value the host might assign to a control port |
||||
when the user has not provided one. Defaults are encoded using a |
||||
mask so only one default may be specified for a port. Some of the |
||||
hints make use of lower and upper bounds, in which case the |
||||
relevant bound or bounds must be available and |
||||
LADSPA_HINT_SAMPLE_RATE must be applied as usual. The resulting |
||||
default must be rounded if LADSPA_HINT_INTEGER is present. Default |
||||
values were introduced in LADSPA v1.1. */ |
||||
#define LADSPA_HINT_DEFAULT_MASK 0x3C0 |
||||
|
||||
/* This default values indicates that no default is provided. */ |
||||
#define LADSPA_HINT_DEFAULT_NONE 0x0 |
||||
|
||||
/* This default hint indicates that the suggested lower bound for the
|
||||
port should be used. */ |
||||
#define LADSPA_HINT_DEFAULT_MINIMUM 0x40 |
||||
|
||||
/* This default hint indicates that a low value between the suggested
|
||||
lower and upper bounds should be chosen. For ports with |
||||
LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.75 + |
||||
log(upper) * 0.25). Otherwise, this should be (lower * 0.75 + upper |
||||
* 0.25). */ |
||||
#define LADSPA_HINT_DEFAULT_LOW 0x80 |
||||
|
||||
/* This default hint indicates that a middle value between the
|
||||
suggested lower and upper bounds should be chosen. For ports with |
||||
LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.5 + |
||||
log(upper) * 0.5). Otherwise, this should be (lower * 0.5 + upper * |
||||
0.5). */ |
||||
#define LADSPA_HINT_DEFAULT_MIDDLE 0xC0 |
||||
|
||||
/* This default hint indicates that a high value between the suggested
|
||||
lower and upper bounds should be chosen. For ports with |
||||
LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.25 + |
||||
log(upper) * 0.75). Otherwise, this should be (lower * 0.25 + upper |
||||
* 0.75). */ |
||||
#define LADSPA_HINT_DEFAULT_HIGH 0x100 |
||||
|
||||
/* This default hint indicates that the suggested upper bound for the
|
||||
port should be used. */ |
||||
#define LADSPA_HINT_DEFAULT_MAXIMUM 0x140 |
||||
|
||||
/* This default hint indicates that the number 0 should be used. Note
|
||||
that this default may be used in conjunction with |
||||
LADSPA_HINT_TOGGLED. */ |
||||
#define LADSPA_HINT_DEFAULT_0 0x200 |
||||
|
||||
/* This default hint indicates that the number 1 should be used. Note
|
||||
that this default may be used in conjunction with |
||||
LADSPA_HINT_TOGGLED. */ |
||||
#define LADSPA_HINT_DEFAULT_1 0x240 |
||||
|
||||
/* This default hint indicates that the number 100 should be used. */ |
||||
#define LADSPA_HINT_DEFAULT_100 0x280 |
||||
|
||||
/* This default hint indicates that the Hz frequency of `concert A'
|
||||
should be used. This will be 440 unless the host uses an unusual |
||||
tuning convention, in which case it may be within a few Hz. */ |
||||
#define LADSPA_HINT_DEFAULT_440 0x2C0 |
||||
|
||||
#define LADSPA_IS_HINT_BOUNDED_BELOW(x) ((x) & LADSPA_HINT_BOUNDED_BELOW) |
||||
#define LADSPA_IS_HINT_BOUNDED_ABOVE(x) ((x) & LADSPA_HINT_BOUNDED_ABOVE) |
||||
#define LADSPA_IS_HINT_TOGGLED(x) ((x) & LADSPA_HINT_TOGGLED) |
||||
#define LADSPA_IS_HINT_SAMPLE_RATE(x) ((x) & LADSPA_HINT_SAMPLE_RATE) |
||||
#define LADSPA_IS_HINT_LOGARITHMIC(x) ((x) & LADSPA_HINT_LOGARITHMIC) |
||||
#define LADSPA_IS_HINT_INTEGER(x) ((x) & LADSPA_HINT_INTEGER) |
||||
|
||||
#define LADSPA_IS_HINT_HAS_DEFAULT(x) ((x) & LADSPA_HINT_DEFAULT_MASK) |
||||
#define LADSPA_IS_HINT_DEFAULT_MINIMUM(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ |
||||
== LADSPA_HINT_DEFAULT_MINIMUM) |
||||
#define LADSPA_IS_HINT_DEFAULT_LOW(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ |
||||
== LADSPA_HINT_DEFAULT_LOW) |
||||
#define LADSPA_IS_HINT_DEFAULT_MIDDLE(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ |
||||
== LADSPA_HINT_DEFAULT_MIDDLE) |
||||
#define LADSPA_IS_HINT_DEFAULT_HIGH(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ |
||||
== LADSPA_HINT_DEFAULT_HIGH) |
||||
#define LADSPA_IS_HINT_DEFAULT_MAXIMUM(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ |
||||
== LADSPA_HINT_DEFAULT_MAXIMUM) |
||||
#define LADSPA_IS_HINT_DEFAULT_0(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ |
||||
== LADSPA_HINT_DEFAULT_0) |
||||
#define LADSPA_IS_HINT_DEFAULT_1(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ |
||||
== LADSPA_HINT_DEFAULT_1) |
||||
#define LADSPA_IS_HINT_DEFAULT_100(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ |
||||
== LADSPA_HINT_DEFAULT_100) |
||||
#define LADSPA_IS_HINT_DEFAULT_440(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ |
||||
== LADSPA_HINT_DEFAULT_440) |
||||
|
||||
typedef struct _LADSPA_PortRangeHint { |
||||
|
||||
/* Hints about the port. */ |
||||
LADSPA_PortRangeHintDescriptor HintDescriptor; |
||||
|
||||
/* Meaningful when hint LADSPA_HINT_BOUNDED_BELOW is active. When
|
||||
LADSPA_HINT_SAMPLE_RATE is also active then this value should be |
||||
multiplied by the relevant sample rate. */ |
||||
LADSPA_Data LowerBound; |
||||
|
||||
/* Meaningful when hint LADSPA_HINT_BOUNDED_ABOVE is active. When
|
||||
LADSPA_HINT_SAMPLE_RATE is also active then this value should be |
||||
multiplied by the relevant sample rate. */ |
||||
LADSPA_Data UpperBound; |
||||
|
||||
} LADSPA_PortRangeHint; |
||||
|
||||
/*****************************************************************************/ |
||||
|
||||
/* Plugin Handles:
|
||||
|
||||
This plugin handle indicates a particular instance of the plugin |
||||
concerned. It is valid to compare this to NULL (0 for C++) but |
||||
otherwise the host should not attempt to interpret it. The plugin |
||||
may use it to reference internal instance data. */ |
||||
|
||||
typedef void * LADSPA_Handle; |
||||
|
||||
/*****************************************************************************/ |
||||
|
||||
/* Descriptor for a Type of Plugin:
|
||||
|
||||
This structure is used to describe a plugin type. It provides a |
||||
number of functions to examine the type, instantiate it, link it to |
||||
buffers and workspaces and to run it. */ |
||||
|
||||
typedef struct _LADSPA_Descriptor {
|
||||
|
||||
/* This numeric identifier indicates the plugin type
|
||||
uniquely. Plugin programmers may reserve ranges of IDs from a |
||||
central body to avoid clashes. Hosts may assume that IDs are |
||||
below 0x1000000. */ |
||||
unsigned long UniqueID; |
||||
|
||||
/* This identifier can be used as a unique, case-sensitive
|
||||
identifier for the plugin type within the plugin file. Plugin |
||||
types should be identified by file and label rather than by index |
||||
or plugin name, which may be changed in new plugin |
||||
versions. Labels must not contain white-space characters. */ |
||||
const char * Label; |
||||
|
||||
/* This indicates a number of properties of the plugin. */ |
||||
LADSPA_Properties Properties; |
||||
|
||||
/* This member points to the null-terminated name of the plugin
|
||||
(e.g. "Sine Oscillator"). */ |
||||
const char * Name; |
||||
|
||||
/* This member points to the null-terminated string indicating the
|
||||
maker of the plugin. This can be an empty string but not NULL. */ |
||||
const char * Maker; |
||||
|
||||
/* This member points to the null-terminated string indicating any
|
||||
copyright applying to the plugin. If no Copyright applies the |
||||
string "None" should be used. */ |
||||
const char * Copyright; |
||||
|
||||
/* This indicates the number of ports (input AND output) present on
|
||||
the plugin. */ |
||||
unsigned long PortCount; |
||||
|
||||
/* This member indicates an array of port descriptors. Valid indices
|
||||
vary from 0 to PortCount-1. */ |
||||
const LADSPA_PortDescriptor * PortDescriptors; |
||||
|
||||
/* This member indicates an array of null-terminated strings
|
||||
describing ports (e.g. "Frequency (Hz)"). Valid indices vary from |
||||
0 to PortCount-1. */ |
||||
const char * const * PortNames; |
||||
|
||||
/* This member indicates an array of range hints for each port (see
|
||||
above). Valid indices vary from 0 to PortCount-1. */ |
||||
const LADSPA_PortRangeHint * PortRangeHints; |
||||
|
||||
/* This may be used by the plugin developer to pass any custom
|
||||
implementation data into an instantiate call. It must not be used |
||||
or interpreted by the host. It is expected that most plugin |
||||
writers will not use this facility as LADSPA_Handle should be |
||||
used to hold instance data. */ |
||||
void * ImplementationData; |
||||
|
||||
/* This member is a function pointer that instantiates a plugin. A
|
||||
handle is returned indicating the new plugin instance. The |
||||
instantiation function accepts a sample rate as a parameter. The |
||||
plugin descriptor from which this instantiate function was found |
||||
must also be passed. This function must return NULL if |
||||
instantiation fails.
|
||||
|
||||
Note that instance initialisation should generally occur in |
||||
activate() rather than here. */ |
||||
LADSPA_Handle (*instantiate)(const struct _LADSPA_Descriptor * Descriptor, |
||||
unsigned long SampleRate); |
||||
|
||||
/* This member is a function pointer that connects a port on an
|
||||
instantiated plugin to a memory location at which a block of data |
||||
for the port will be read/written. The data location is expected |
||||
to be an array of LADSPA_Data for audio ports or a single |
||||
LADSPA_Data value for control ports. Memory issues will be |
||||
managed by the host. The plugin must read/write the data at these |
||||
locations every time run() or run_adding() is called and the data |
||||
present at the time of this connection call should not be |
||||
considered meaningful. |
||||
|
||||
connect_port() may be called more than once for a plugin instance |
||||
to allow the host to change the buffers that the plugin is |
||||
reading or writing. These calls may be made before or after |
||||
activate() or deactivate() calls. |
||||
|
||||
connect_port() must be called at least once for each port before |
||||
run() or run_adding() is called. When working with blocks of |
||||
LADSPA_Data the plugin should pay careful attention to the block |
||||
size passed to the run function as the block allocated may only |
||||
just be large enough to contain the block of samples. |
||||
|
||||
Plugin writers should be aware that the host may elect to use the |
||||
same buffer for more than one port and even use the same buffer |
||||
for both input and output (see LADSPA_PROPERTY_INPLACE_BROKEN). |
||||
However, overlapped buffers or use of a single buffer for both |
||||
audio and control data may result in unexpected behaviour. */ |
||||
void (*connect_port)(LADSPA_Handle Instance, |
||||
unsigned long Port, |
||||
LADSPA_Data * DataLocation); |
||||
|
||||
/* This member is a function pointer that initialises a plugin
|
||||
instance and activates it for use. This is separated from |
||||
instantiate() to aid real-time support and so that hosts can |
||||
reinitialise a plugin instance by calling deactivate() and then |
||||
activate(). In this case the plugin instance must reset all state |
||||
information dependent on the history of the plugin instance |
||||
except for any data locations provided by connect_port() and any |
||||
gain set by set_run_adding_gain(). If there is nothing for |
||||
activate() to do then the plugin writer may provide a NULL rather |
||||
than an empty function. |
||||
|
||||
When present, hosts must call this function once before run() (or |
||||
run_adding()) is called for the first time. This call should be |
||||
made as close to the run() call as possible and indicates to |
||||
real-time plugins that they are now live. Plugins should not rely |
||||
on a prompt call to run() after activate(). activate() may not be |
||||
called again unless deactivate() is called first. Note that |
||||
connect_port() may be called before or after a call to |
||||
activate(). */ |
||||
void (*activate)(LADSPA_Handle Instance); |
||||
|
||||
/* This method is a function pointer that runs an instance of a
|
||||
plugin for a block. Two parameters are required: the first is a |
||||
handle to the particular instance to be run and the second |
||||
indicates the block size (in samples) for which the plugin |
||||
instance may run. |
||||
|
||||
Note that if an activate() function exists then it must be called |
||||
before run() or run_adding(). If deactivate() is called for a |
||||
plugin instance then the plugin instance may not be reused until |
||||
activate() has been called again. |
||||
|
||||
If the plugin has the property LADSPA_PROPERTY_HARD_RT_CAPABLE |
||||
then there are various things that the plugin should not do |
||||
within the run() or run_adding() functions (see above). */ |
||||
void (*run)(LADSPA_Handle Instance, |
||||
unsigned long SampleCount); |
||||
|
||||
/* This method is a function pointer that runs an instance of a
|
||||
plugin for a block. This has identical behaviour to run() except |
||||
in the way data is output from the plugin. When run() is used, |
||||
values are written directly to the memory areas associated with |
||||
the output ports. However when run_adding() is called, values |
||||
must be added to the values already present in the memory |
||||
areas. Furthermore, output values written must be scaled by the |
||||
current gain set by set_run_adding_gain() (see below) before |
||||
addition. |
||||
|
||||
run_adding() is optional. When it is not provided by a plugin, |
||||
this function pointer must be set to NULL. When it is provided, |
||||
the function set_run_adding_gain() must be provided also. */ |
||||
void (*run_adding)(LADSPA_Handle Instance, |
||||
unsigned long SampleCount); |
||||
|
||||
/* This method is a function pointer that sets the output gain for
|
||||
use when run_adding() is called (see above). If this function is |
||||
never called the gain is assumed to default to 1. Gain |
||||
information should be retained when activate() or deactivate() |
||||
are called. |
||||
|
||||
This function should be provided by the plugin if and only if the |
||||
run_adding() function is provided. When it is absent this |
||||
function pointer must be set to NULL. */ |
||||
void (*set_run_adding_gain)(LADSPA_Handle Instance, |
||||
LADSPA_Data Gain); |
||||
|
||||
/* This is the counterpart to activate() (see above). If there is
|
||||
nothing for deactivate() to do then the plugin writer may provide |
||||
a NULL rather than an empty function. |
||||
|
||||
Hosts must deactivate all activated units after they have been |
||||
run() (or run_adding()) for the last time. This call should be |
||||
made as close to the last run() call as possible and indicates to |
||||
real-time plugins that they are no longer live. Plugins should |
||||
not rely on prompt deactivation. Note that connect_port() may be |
||||
called before or after a call to deactivate(). |
||||
|
||||
Deactivation is not similar to pausing as the plugin instance |
||||
will be reinitialised when activate() is called to reuse it. */ |
||||
void (*deactivate)(LADSPA_Handle Instance); |
||||
|
||||
/* Once an instance of a plugin has been finished with it can be
|
||||
deleted using the following function. The instance handle passed |
||||
ceases to be valid after this call. |
||||
|
||||
If activate() was called for a plugin instance then a |
||||
corresponding call to deactivate() must be made before cleanup() |
||||
is called. */ |
||||
void (*cleanup)(LADSPA_Handle Instance); |
||||
|
||||
} LADSPA_Descriptor; |
||||
|
||||
/**********************************************************************/ |
||||
|
||||
/* Accessing a Plugin: */ |
||||
|
||||
/* The exact mechanism by which plugins are loaded is host-dependent,
|
||||
however all most hosts will need to know is the name of shared |
||||
object file containing the plugin types. To allow multiple hosts to |
||||
share plugin types, hosts may wish to check for environment |
||||
variable LADSPA_PATH. If present, this should contain a |
||||
colon-separated path indicating directories that should be searched |
||||
(in order) when loading plugin types. |
||||
|
||||
A plugin programmer must include a function called |
||||
"ladspa_descriptor" with the following function prototype within |
||||
the shared object file. This function will have C-style linkage (if |
||||
you are using C++ this is taken care of by the `extern "C"' clause |
||||
at the top of the file). |
||||
|
||||
A host will find the plugin shared object file by one means or |
||||
another, find the ladspa_descriptor() function, call it, and |
||||
proceed from there. |
||||
|
||||
Plugin types are accessed by index (not ID) using values from 0 |
||||
upwards. Out of range indexes must result in this function |
||||
returning NULL, so the plugin count can be determined by checking |
||||
for the least index that results in NULL being returned. */ |
||||
|
||||
const LADSPA_Descriptor * ladspa_descriptor(unsigned long Index); |
||||
|
||||
/* Datatype corresponding to the ladspa_descriptor() function. */ |
||||
typedef const LADSPA_Descriptor *
|
||||
(*LADSPA_Descriptor_Function)(unsigned long Index); |
||||
|
||||
/**********************************************************************/ |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* LADSPA_INCLUDED */ |
||||
|
||||
/* EOF */ |
@ -1,129 +0,0 @@ |
||||
/* Effect: loudness filter Copyright (c) 2008 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "dft_filter.h" |
||||
#include <string.h> |
||||
|
||||
typedef struct { |
||||
dft_filter_priv_t base; |
||||
double delta, start; |
||||
int n; |
||||
} priv_t; |
||||
|
||||
static int create(sox_effect_t * effp, int argc, char **argv) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
dft_filter_priv_t * b = &p->base; |
||||
b->filter_ptr = &b->filter; |
||||
p->delta = -10; |
||||
p->start = 65; |
||||
p->n = 1023; |
||||
--argc, ++argv; |
||||
do { /* break-able block */ |
||||
NUMERIC_PARAMETER(delta,-50 , 15) /* FIXME expand range */ |
||||
NUMERIC_PARAMETER(start, 50 , 75) /* FIXME expand range */ |
||||
NUMERIC_PARAMETER(n ,127 ,2047) |
||||
} while (0); |
||||
p->n = 2 * p->n + 1; |
||||
return argc? lsx_usage(effp) : SOX_SUCCESS; |
||||
} |
||||
|
||||
static double * make_filter(int n, double start, double delta, double rate) |
||||
{ |
||||
static const struct {double f, af, lu, tf;} iso226_table[] = { |
||||
{ 20,0.532,-31.6,78.5},{ 25,0.506,-27.2,68.7},{ 31.5,0.480,-23.0,59.5}, |
||||
{ 40,0.455,-19.1,51.1},{ 50,0.432,-15.9,44.0},{ 63,0.409,-13.0,37.5}, |
||||
{ 80,0.387,-10.3,31.5},{ 100,0.367, -8.1,26.5},{ 125,0.349, -6.2,22.1}, |
||||
{ 160,0.330, -4.5,17.9},{ 200,0.315, -3.1,14.4},{ 250,0.301, -2.0,11.4}, |
||||
{ 315,0.288, -1.1, 8.6},{ 400,0.276, -0.4, 6.2},{ 500,0.267, 0.0, 4.4}, |
||||
{ 630,0.259, 0.3, 3.0},{ 800,0.253, 0.5, 2.2},{ 1000,0.250, 0.0, 2.4}, |
||||
{ 1250,0.246, -2.7, 3.5},{ 1600,0.244, -4.1, 1.7},{ 2000,0.243, -1.0,-1.3}, |
||||
{ 2500,0.243, 1.7,-4.2},{ 3150,0.243, 2.5,-6.0},{ 4000,0.242, 1.2,-5.4}, |
||||
{ 5000,0.242, -2.1,-1.5},{ 6300,0.245, -7.1, 6.0},{ 8000,0.254,-11.2,12.6}, |
||||
{10000,0.271,-10.7,13.9},{12500,0.301, -3.1,12.3}, |
||||
}; |
||||
#define LEN (array_length(iso226_table) + 2) |
||||
#define SPL(phon, t) (10 / t.af * log10(4.47e-3 * (pow(10., .025 * (phon)) - \ |
||||
1.15) + pow(.4 * pow(10., (t.tf + t.lu) / 10 - 9), t.af)) - t.lu + 94) |
||||
double fs[LEN], spl[LEN], d[LEN], * work, * h; |
||||
int i, work_len; |
||||
|
||||
fs[0] = log(1.); |
||||
spl[0] = delta * .2; |
||||
for (i = 0; i < (int)LEN - 2; ++i) { |
||||
spl[i + 1] = SPL(start + delta, iso226_table[i]) - |
||||
SPL(start , iso226_table[i]); |
||||
fs[i + 1] = log(iso226_table[i].f); |
||||
} |
||||
fs[i + 1] = log(100000.); |
||||
spl[i + 1] = spl[0]; |
||||
lsx_prepare_spline3(fs, spl, (int)LEN, HUGE_VAL, HUGE_VAL, d); |
||||
|
||||
for (work_len = 8192; work_len < rate / 2; work_len <<= 1); |
||||
work = lsx_calloc(work_len, sizeof(*work)); |
||||
h = lsx_calloc(n, sizeof(*h)); |
||||
|
||||
for (i = 0; i <= work_len / 2; ++i) { |
||||
double f = rate * i / work_len; |
||||
double spl1 = f < 1? spl[0] : lsx_spline3(fs, spl, d, (int)LEN, log(f)); |
||||
work[i < work_len / 2 ? 2 * i : 1] = dB_to_linear(spl1); |
||||
} |
||||
lsx_safe_rdft(work_len, -1, work); |
||||
for (i = 0; i < n; ++i) |
||||
h[i] = work[(work_len - n / 2 + i) % work_len] * 2. / work_len; |
||||
lsx_apply_kaiser(h, n, lsx_kaiser_beta(40 + 2./3 * fabs(delta), .1)); |
||||
|
||||
free(work); |
||||
return h; |
||||
#undef SPL |
||||
#undef LEN |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
dft_filter_t * f = p->base.filter_ptr; |
||||
|
||||
if (p->delta == 0) |
||||
return SOX_EFF_NULL; |
||||
|
||||
if (!f->num_taps) { |
||||
double * h = make_filter(p->n, p->start, p->delta, effp->in_signal.rate); |
||||
if (effp->global_info->plot != sox_plot_off) { |
||||
char title[100]; |
||||
sprintf(title, "SoX effect: loudness %g (%g)", p->delta, p->start); |
||||
lsx_plot_fir(h, p->n, effp->in_signal.rate, |
||||
effp->global_info->plot, title, p->delta - 5, 0.); |
||||
return SOX_EOF; |
||||
} |
||||
lsx_set_dft_filter(f, h, p->n, p->n >> 1); |
||||
} |
||||
return lsx_dft_filter_effect_fn()->start(effp); |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_loudness_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler; |
||||
handler = *lsx_dft_filter_effect_fn(); |
||||
handler.name = "loudness"; |
||||
handler.usage = "[gain [ref]]"; |
||||
handler.getopts = create; |
||||
handler.start = start; |
||||
handler.priv_size = sizeof(priv_t); |
||||
return &handler; |
||||
} |
@ -1,21 +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 |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "raw.h" |
||||
|
||||
RAW_FORMAT(lu, 8, SOX_FILE_BIT_REV, ULAW) |
@ -1,524 +0,0 @@ |
||||
/* multiband compander effect for SoX
|
||||
* by Daniel Pouzzner <douzzer@mega.nu> 2002-Oct-8 |
||||
* |
||||
* Compander code adapted from the SoX compand effect, by Nick Bailey |
||||
* |
||||
* SoX is Copyright 1999 Chris Bagwell And Nick Bailey This source code is |
||||
* freely redistributable and may be used for any purpose. This copyright |
||||
* notice must be maintained. Chris Bagwell And Nick Bailey are not |
||||
* responsible for the consequences of using this software. |
||||
* |
||||
* |
||||
* Usage: |
||||
* mcompand quoted_compand_args [crossover_frequency |
||||
* quoted_compand_args [...]] |
||||
* |
||||
* quoted_compand_args are as for the compand effect: |
||||
* |
||||
* attack1,decay1[,attack2,decay2...] |
||||
* in-dB1,out-dB1[,in-dB2,out-dB2...] |
||||
* [ gain [ initial-volume [ delay ] ] ] |
||||
* |
||||
* Beware a variety of headroom (clipping) bugaboos. |
||||
* |
||||
* Implementation details: |
||||
* The input is divided into bands using 4th order Linkwitz-Riley IIRs. |
||||
* This is akin to the crossover of a loudspeaker, and results in flat |
||||
* frequency response absent compander action. |
||||
* |
||||
* The outputs of the array of companders is summed, and sample truncation |
||||
* is done on the final sum. |
||||
* |
||||
* Modifications to the predictive compression code properly maintain |
||||
* alignment of the outputs of the array of companders when the companders |
||||
* have different prediction intervals (volume application delays). Note |
||||
* that the predictive mode of the limiter needs some TLC - in fact, a |
||||
* rewrite - since what's really useful is to assure that a waveform won't |
||||
* be clipped, by slewing the volume in advance so that the peak is at |
||||
* limit (or below, if there's a higher subsequent peak visible in the |
||||
* lookahead window) once it's reached. */ |
||||
|
||||
#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> |
||||
#include <stdlib.h> |
||||
#include "compandt.h" |
||||
#include "mcompand_xover.h" |
||||
|
||||
typedef struct { |
||||
sox_compandt_t transfer_fn; |
||||
|
||||
size_t expectedChannels; /* Also flags that channels aren't to be treated
|
||||
individually when = 1 and input not mono */ |
||||
double *attackRate; /* An array of attack rates */ |
||||
double *decayRate; /* ... and of decay rates */ |
||||
double *volume; /* Current "volume" of each channel */ |
||||
double delay; /* Delay to apply before companding */ |
||||
double topfreq; /* upper bound crossover frequency */ |
||||
crossover_t filter; |
||||
sox_sample_t *delay_buf; /* Old samples, used for delay processing */ |
||||
size_t delay_size; /* lookahead for this band (in samples) - function of delay, above */ |
||||
ptrdiff_t delay_buf_ptr; /* Index into delay_buf */ |
||||
size_t delay_buf_cnt; /* No. of active entries in delay_buf */ |
||||
} comp_band_t; |
||||
|
||||
typedef struct { |
||||
size_t nBands; |
||||
sox_sample_t *band_buf1, *band_buf2, *band_buf3; |
||||
size_t band_buf_len; |
||||
size_t delay_buf_size;/* Size of delay_buf in samples */ |
||||
comp_band_t *bands; |
||||
|
||||
char *arg; /* copy of current argument */ |
||||
} priv_t; |
||||
|
||||
/*
|
||||
* Process options |
||||
* |
||||
* Don't do initialization now. |
||||
* The 'info' fields are not yet filled in. |
||||
*/ |
||||
static int sox_mcompand_getopts_1(comp_band_t * l, size_t n, char **argv) |
||||
{ |
||||
char *s; |
||||
size_t rates, i, commas; |
||||
|
||||
/* Start by checking the attack and decay rates */ |
||||
|
||||
for (s = argv[0], commas = 0; *s; ++s) |
||||
if (*s == ',') ++commas; |
||||
|
||||
if (commas % 2 == 0) /* There must be an even number of
|
||||
attack/decay parameters */ |
||||
{ |
||||
lsx_fail("compander: Odd number of attack & decay rate parameters"); |
||||
return (SOX_EOF); |
||||
} |
||||
|
||||
rates = 1 + commas/2; |
||||
l->attackRate = lsx_malloc(sizeof(double) * rates); |
||||
l->decayRate = lsx_malloc(sizeof(double) * rates); |
||||
l->volume = lsx_malloc(sizeof(double) * rates); |
||||
l->expectedChannels = rates; |
||||
l->delay_buf = NULL; |
||||
|
||||
/* Now tokenise the rates string and set up these arrays. Keep
|
||||
them in seconds at the moment: we don't know the sample rate yet. */ |
||||
|
||||
s = strtok(argv[0], ","); i = 0; |
||||
do { |
||||
l->attackRate[i] = atof(s); s = strtok(NULL, ","); |
||||
l->decayRate[i] = atof(s); s = strtok(NULL, ","); |
||||
++i; |
||||
} while (s != NULL); |
||||
|
||||
if (!lsx_compandt_parse(&l->transfer_fn, argv[1], n>2 ? argv[2] : 0)) |
||||
return SOX_EOF; |
||||
|
||||
/* Set the initial "volume" to be attibuted to the input channels.
|
||||
Unless specified, choose 1.0 (maximum) otherwise clipping will |
||||
result if the user has seleced a long attack time */ |
||||
for (i = 0; i < l->expectedChannels; ++i) { |
||||
double v = n>=4 ? pow(10.0, atof(argv[3])/20) : 1.0; |
||||
l->volume[i] = v; |
||||
|
||||
/* If there is a delay, store it. */ |
||||
if (n >= 5) l->delay = atof(argv[4]); |
||||
else l->delay = 0.0; |
||||
} |
||||
return (SOX_SUCCESS); |
||||
} |
||||
|
||||
static int parse_subarg(char *s, char **subargv, size_t *subargc) { |
||||
char **ap; |
||||
char *s_p; |
||||
|
||||
s_p = s; |
||||
*subargc = 0; |
||||
for (ap = subargv; (*ap = strtok(s_p, " \t")) != NULL;) { |
||||
s_p = NULL; |
||||
if (*subargc == 5) { |
||||
++*subargc; |
||||
break; |
||||
} |
||||
if (**ap != '\0') { |
||||
++ap; |
||||
++*subargc; |
||||
} |
||||
} |
||||
|
||||
if (*subargc < 2 || *subargc > 5) |
||||
{ |
||||
lsx_fail("Wrong number of parameters for the compander effect within mcompand; usage:\n" |
||||
"\tattack1,decay1{,attack2,decay2} [soft-knee-dB:]in-dB1[,out-dB1]{,in-dB2,out-dB2} [gain [initial-volume-dB [delay]]]\n" |
||||
"\twhere {} means optional and repeatable and [] means optional.\n" |
||||
"\tdB values are floating point or -inf'; times are in seconds."); |
||||
return (SOX_EOF); |
||||
} else |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int getopts(sox_effect_t * effp, int argc, char **argv) |
||||
{ |
||||
char *subargv[6], *cp; |
||||
size_t subargc, i; |
||||
|
||||
priv_t * c = (priv_t *) effp->priv; |
||||
--argc, ++argv; |
||||
|
||||
c->band_buf1 = c->band_buf2 = c->band_buf3 = 0; |
||||
c->band_buf_len = 0; |
||||
|
||||
/* how many bands? */ |
||||
if (! (argc&1)) { |
||||
lsx_fail("mcompand accepts only an odd number of arguments:\argc" |
||||
" mcompand quoted_compand_args [crossover_freq quoted_compand_args [...]]"); |
||||
return SOX_EOF; |
||||
} |
||||
c->nBands = (argc+1)>>1; |
||||
|
||||
c->bands = lsx_calloc(c->nBands, sizeof(comp_band_t)); |
||||
|
||||
for (i=0;i<c->nBands;++i) { |
||||
c->arg = lsx_strdup(argv[i<<1]); |
||||
if (parse_subarg(c->arg,subargv,&subargc) != SOX_SUCCESS) |
||||
return SOX_EOF; |
||||
if (sox_mcompand_getopts_1(&c->bands[i], subargc, &subargv[0]) != SOX_SUCCESS) |
||||
return SOX_EOF; |
||||
free(c->arg); |
||||
c->arg = NULL; |
||||
if (i == (c->nBands-1)) |
||||
c->bands[i].topfreq = 0; |
||||
else { |
||||
c->bands[i].topfreq = lsx_parse_frequency(argv[(i<<1)+1],&cp); |
||||
if (*cp) { |
||||
lsx_fail("bad frequency in args to mcompand"); |
||||
return SOX_EOF; |
||||
} |
||||
if ((i>0) && (c->bands[i].topfreq < c->bands[i-1].topfreq)) { |
||||
lsx_fail("mcompand crossover frequencies must be in ascending order."); |
||||
return SOX_EOF; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Prepare processing. |
||||
* Do all initializations. |
||||
*/ |
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * c = (priv_t *) effp->priv; |
||||
comp_band_t * l; |
||||
size_t i; |
||||
size_t band; |
||||
|
||||
for (band=0;band<c->nBands;++band) { |
||||
l = &c->bands[band]; |
||||
l->delay_size = c->bands[band].delay * effp->out_signal.rate * effp->out_signal.channels; |
||||
if (l->delay_size > c->delay_buf_size) |
||||
c->delay_buf_size = l->delay_size; |
||||
} |
||||
|
||||
for (band=0;band<c->nBands;++band) { |
||||
l = &c->bands[band]; |
||||
/* Convert attack and decay rates using number of samples */ |
||||
|
||||
for (i = 0; i < l->expectedChannels; ++i) { |
||||
if (l->attackRate[i] > 1.0/effp->out_signal.rate) |
||||
l->attackRate[i] = 1.0 - |
||||
exp(-1.0/(effp->out_signal.rate * l->attackRate[i])); |
||||
else |
||||
l->attackRate[i] = 1.0; |
||||
if (l->decayRate[i] > 1.0/effp->out_signal.rate) |
||||
l->decayRate[i] = 1.0 - |
||||
exp(-1.0/(effp->out_signal.rate * l->decayRate[i])); |
||||
else |
||||
l->decayRate[i] = 1.0; |
||||
} |
||||
|
||||
/* Allocate the delay buffer */ |
||||
if (c->delay_buf_size > 0) |
||||
l->delay_buf = lsx_calloc(sizeof(long), c->delay_buf_size); |
||||
l->delay_buf_ptr = 0; |
||||
l->delay_buf_cnt = 0; |
||||
|
||||
if (l->topfreq != 0) |
||||
crossover_setup(effp, &l->filter, l->topfreq); |
||||
} |
||||
return (SOX_SUCCESS); |
||||
} |
||||
|
||||
/*
|
||||
* Update a volume value using the given sample |
||||
* value, the attack rate and decay rate |
||||
*/ |
||||
|
||||
static void doVolume(double *v, double samp, comp_band_t * l, size_t chan) |
||||
{ |
||||
double s = samp/(~((sox_sample_t)1<<31)); |
||||
double delta = s - *v; |
||||
|
||||
if (delta > 0.0) /* increase volume according to attack rate */ |
||||
*v += delta * l->attackRate[chan]; |
||||
else /* reduce volume according to decay rate */ |
||||
*v += delta * l->decayRate[chan]; |
||||
} |
||||
|
||||
static int sox_mcompand_flow_1(sox_effect_t * effp, priv_t * c, comp_band_t * l, const sox_sample_t *ibuf, sox_sample_t *obuf, size_t len, size_t filechans) |
||||
{ |
||||
size_t idone, odone; |
||||
|
||||
for (idone = 0, odone = 0; idone < len; ibuf += filechans) { |
||||
size_t chan; |
||||
|
||||
/* Maintain the volume fields by simulating a leaky pump circuit */ |
||||
|
||||
if (l->expectedChannels == 1 && filechans > 1) { |
||||
/* User is expecting same compander for all channels */ |
||||
double maxsamp = 0.0; |
||||
for (chan = 0; chan < filechans; ++chan) { |
||||
double rect = fabs((double)ibuf[chan]); |
||||
if (rect > maxsamp) |
||||
maxsamp = rect; |
||||
} |
||||
doVolume(&l->volume[0], maxsamp, l, (size_t) 0); |
||||
} else { |
||||
for (chan = 0; chan < filechans; ++chan) |
||||
doVolume(&l->volume[chan], fabs((double)ibuf[chan]), l, chan); |
||||
} |
||||
|
||||
/* Volume memory is updated: perform compand */ |
||||
for (chan = 0; chan < filechans; ++chan) { |
||||
int ch = l->expectedChannels > 1 ? chan : 0; |
||||
double level_in_lin = l->volume[ch]; |
||||
double level_out_lin = lsx_compandt(&l->transfer_fn, level_in_lin); |
||||
double checkbuf; |
||||
|
||||
if (c->delay_buf_size <= 0) { |
||||
checkbuf = ibuf[chan] * level_out_lin; |
||||
SOX_SAMPLE_CLIP_COUNT(checkbuf, effp->clips); |
||||
obuf[odone++] = checkbuf; |
||||
idone++; |
||||
} else { |
||||
/* FIXME: note that this lookahead algorithm is really lame:
|
||||
the response to a peak is released before the peak |
||||
arrives. */ |
||||
|
||||
/* because volume application delays differ band to band, but
|
||||
total delay doesn't, the volume is applied in an iteration |
||||
preceding that in which the sample goes to obuf, except in |
||||
the band(s) with the longest vol app delay. |
||||
|
||||
the offset between delay_buf_ptr and the sample to apply |
||||
vol to, is a constant equal to the difference between this |
||||
band's delay and the longest delay of all the bands. */ |
||||
|
||||
if (l->delay_buf_cnt >= l->delay_size) { |
||||
checkbuf = l->delay_buf[(l->delay_buf_ptr + c->delay_buf_size - l->delay_size)%c->delay_buf_size] * level_out_lin; |
||||
SOX_SAMPLE_CLIP_COUNT(checkbuf, effp->clips); |
||||
l->delay_buf[(l->delay_buf_ptr + c->delay_buf_size - l->delay_size)%c->delay_buf_size] = checkbuf; |
||||
} |
||||
if (l->delay_buf_cnt >= c->delay_buf_size) { |
||||
obuf[odone] = l->delay_buf[l->delay_buf_ptr]; |
||||
odone++; |
||||
idone++; |
||||
} else { |
||||
l->delay_buf_cnt++; |
||||
idone++; /* no "odone++" because we did not fill obuf[...] */ |
||||
} |
||||
l->delay_buf[l->delay_buf_ptr++] = ibuf[chan]; |
||||
l->delay_buf_ptr %= c->delay_buf_size; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (idone != odone || idone != len) { |
||||
/* Emergency brake - will lead to memory corruption otherwise since we
|
||||
cannot report back to flow() how many samples were consumed/emitted. |
||||
Additionally, flow() doesn't know how to handle diverging |
||||
sub-compander delays. */ |
||||
lsx_fail("Using a compander delay within mcompand is currently not supported"); |
||||
exit(1); |
||||
/* FIXME */ |
||||
} |
||||
|
||||
return (SOX_SUCCESS); |
||||
} |
||||
|
||||
/*
|
||||
* Processed signed long samples from ibuf to obuf. |
||||
* Return number of samples processed. |
||||
*/ |
||||
static int flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, |
||||
size_t *isamp, size_t *osamp) { |
||||
priv_t * c = (priv_t *) effp->priv; |
||||
comp_band_t * l; |
||||
size_t len = min(*isamp, *osamp); |
||||
size_t band, i; |
||||
sox_sample_t *abuf, *bbuf, *cbuf, *oldabuf, *ibuf_copy; |
||||
double out; |
||||
|
||||
if (c->band_buf_len < len) { |
||||
c->band_buf1 = lsx_realloc(c->band_buf1,len*sizeof(sox_sample_t)); |
||||
c->band_buf2 = lsx_realloc(c->band_buf2,len*sizeof(sox_sample_t)); |
||||
c->band_buf3 = lsx_realloc(c->band_buf3,len*sizeof(sox_sample_t)); |
||||
c->band_buf_len = len; |
||||
} |
||||
|
||||
len -= len % effp->out_signal.channels; |
||||
|
||||
ibuf_copy = lsx_malloc(*isamp * sizeof(sox_sample_t)); |
||||
memcpy(ibuf_copy, ibuf, *isamp * sizeof(sox_sample_t)); |
||||
|
||||
/* split ibuf into bands using filters, pipe each band through sox_mcompand_flow_1, then add back together and write to obuf */ |
||||
|
||||
memset(obuf,0,len * sizeof *obuf); |
||||
for (band=0,abuf=ibuf_copy,bbuf=c->band_buf2,cbuf=c->band_buf1;band<c->nBands;++band) { |
||||
l = &c->bands[band]; |
||||
|
||||
if (l->topfreq) |
||||
crossover_flow(effp, &l->filter, abuf, bbuf, cbuf, len); |
||||
else { |
||||
bbuf = abuf; |
||||
abuf = cbuf; |
||||
} |
||||
if (abuf == ibuf_copy) |
||||
abuf = c->band_buf3; |
||||
(void)sox_mcompand_flow_1(effp, c,l,bbuf,abuf,len, (size_t)effp->out_signal.channels); |
||||
for (i=0;i<len;++i) |
||||
{ |
||||
out = (double)obuf[i] + (double)abuf[i]; |
||||
SOX_SAMPLE_CLIP_COUNT(out, effp->clips); |
||||
obuf[i] = out; |
||||
} |
||||
oldabuf = abuf; |
||||
abuf = cbuf; |
||||
cbuf = oldabuf; |
||||
} |
||||
|
||||
*isamp = *osamp = len; |
||||
|
||||
free(ibuf_copy); |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int sox_mcompand_drain_1(sox_effect_t * effp, priv_t * c, comp_band_t * l, sox_sample_t *obuf, size_t maxdrain) |
||||
{ |
||||
size_t done; |
||||
double out; |
||||
|
||||
/*
|
||||
* Drain out delay samples. Note that this loop does all channels. |
||||
*/ |
||||
for (done = 0; done < maxdrain && l->delay_buf_cnt > 0; done++) { |
||||
out = obuf[done] + l->delay_buf[l->delay_buf_ptr++]; |
||||
SOX_SAMPLE_CLIP_COUNT(out, effp->clips); |
||||
obuf[done] = out; |
||||
l->delay_buf_ptr %= c->delay_buf_size; |
||||
l->delay_buf_cnt--; |
||||
} |
||||
|
||||
/* tell caller number of samples played */ |
||||
return done; |
||||
|
||||
} |
||||
|
||||
/*
|
||||
* Drain out compander delay lines. |
||||
*/ |
||||
static int drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp) |
||||
{ |
||||
size_t band, drained, mostdrained = 0; |
||||
priv_t * c = (priv_t *)effp->priv; |
||||
comp_band_t * l; |
||||
|
||||
*osamp -= *osamp % effp->out_signal.channels; |
||||
|
||||
memset(obuf,0,*osamp * sizeof *obuf); |
||||
for (band=0;band<c->nBands;++band) { |
||||
l = &c->bands[band]; |
||||
drained = sox_mcompand_drain_1(effp, c,l,obuf,*osamp); |
||||
if (drained > mostdrained) |
||||
mostdrained = drained; |
||||
} |
||||
|
||||
*osamp = mostdrained; |
||||
|
||||
if (mostdrained) |
||||
return SOX_SUCCESS; |
||||
else |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
/*
|
||||
* Clean up compander effect. |
||||
*/ |
||||
static int stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * c = (priv_t *) effp->priv; |
||||
comp_band_t * l; |
||||
size_t band; |
||||
|
||||
free(c->band_buf1); |
||||
c->band_buf1 = NULL; |
||||
free(c->band_buf2); |
||||
c->band_buf2 = NULL; |
||||
free(c->band_buf3); |
||||
c->band_buf3 = NULL; |
||||
|
||||
for (band = 0; band < c->nBands; band++) { |
||||
l = &c->bands[band]; |
||||
free(l->delay_buf); |
||||
if (l->topfreq != 0) |
||||
free(l->filter.previous); |
||||
} |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int lsx_kill(sox_effect_t * effp) |
||||
{ |
||||
priv_t * c = (priv_t *) effp->priv; |
||||
comp_band_t * l; |
||||
size_t band; |
||||
|
||||
for (band = 0; band < c->nBands; band++) { |
||||
l = &c->bands[band]; |
||||
lsx_compandt_kill(&l->transfer_fn); |
||||
free(l->decayRate); |
||||
free(l->attackRate); |
||||
free(l->volume); |
||||
} |
||||
free(c->arg); |
||||
free(c->bands); |
||||
c->bands = NULL; |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
const sox_effect_handler_t *lsx_mcompand_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"mcompand", |
||||
"quoted_compand_args [crossover_frequency[k] quoted_compand_args [...]]\n" |
||||
"\n" |
||||
"quoted_compand_args are as for the compand effect:\n" |
||||
"\n" |
||||
" attack1,decay1[,attack2,decay2...]\n" |
||||
" in-dB1,out-dB1[,in-dB2,out-dB2...]\n" |
||||
" [ gain [ initial-volume [ delay ] ] ]", |
||||
SOX_EFF_MCHAN | SOX_EFF_GAIN, |
||||
getopts, start, flow, drain, stop, lsx_kill, sizeof(priv_t) |
||||
}; |
||||
|
||||
return &handler; |
||||
} |
@ -1,106 +0,0 @@ |
||||
/* libSoX Compander Crossover Filter (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 |
||||
*/ |
||||
|
||||
#define N 4 /* 4th order Linkwitz-Riley IIRs */ |
||||
#define CONVOLVE _ _ _ _ |
||||
|
||||
typedef struct {double in, out_low, out_high;} previous_t[N * 2]; |
||||
|
||||
typedef struct { |
||||
previous_t * previous; |
||||
size_t pos; |
||||
double coefs[3 *(N+1)]; |
||||
} crossover_t; |
||||
|
||||
static void square_quadratic(char const * name, double const * x, double * y) |
||||
{ |
||||
assert(N == 4); |
||||
y[0] = x[0] * x[0]; |
||||
y[1] = 2 * x[0] * x[1]; |
||||
y[2] = 2 * x[0] * x[2] + x[1] * x[1]; |
||||
y[3] = 2 * x[1] * x[2]; |
||||
y[4] = x[2] * x[2]; |
||||
lsx_debug("%s=[%.16g %.16g %.16g %.16g %.16g];", name, |
||||
y[0], y[1], y[2], y[3], y[4]); |
||||
} |
||||
|
||||
static int crossover_setup(sox_effect_t * effp, crossover_t * p, double frequency) |
||||
{ |
||||
double w0 = 2 * M_PI * frequency / effp->in_signal.rate; |
||||
double Q = sqrt(.5), alpha = sin(w0)/(2*Q); |
||||
double x[9], norm; |
||||
int i; |
||||
|
||||
if (w0 > M_PI) { |
||||
lsx_fail("frequency must not exceed half the sample-rate (Nyquist rate)"); |
||||
return SOX_EOF; |
||||
} |
||||
x[0] = (1 - cos(w0))/2; /* Cf. filter_LPF in biquads.c */ |
||||
x[1] = 1 - cos(w0); |
||||
x[2] = (1 - cos(w0))/2; |
||||
x[3] = (1 + cos(w0))/2; /* Cf. filter_HPF in biquads.c */ |
||||
x[4] = -(1 + cos(w0)); |
||||
x[5] = (1 + cos(w0))/2; |
||||
x[6] = 1 + alpha; |
||||
x[7] = -2*cos(w0); |
||||
x[8] = 1 - alpha; |
||||
for (norm = x[6], i = 0; i < 9; ++i) x[i] /= norm; |
||||
square_quadratic("lb", x , p->coefs); |
||||
square_quadratic("hb", x + 3, p->coefs + 5); |
||||
square_quadratic("a" , x + 6, p->coefs + 10); |
||||
|
||||
p->previous = lsx_calloc(effp->in_signal.channels, sizeof(*p->previous)); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int crossover_flow(sox_effect_t * effp, crossover_t * p, sox_sample_t |
||||
*ibuf, sox_sample_t *obuf_low, sox_sample_t *obuf_high, size_t len0) |
||||
{ |
||||
double out_low, out_high; |
||||
size_t c, len = len0 / effp->in_signal.channels; |
||||
assert(len * effp->in_signal.channels == len0); |
||||
|
||||
while (len--) { |
||||
p->pos = p->pos? p->pos - 1 : N - 1; |
||||
for (c = 0; c < effp->in_signal.channels; ++c) { |
||||
#define _ out_low += p->coefs[j] * p->previous[c][p->pos + j].in \ |
||||
- p->coefs[2*N+2 + j] * p->previous[c][p->pos + j].out_low, ++j; |
||||
{ |
||||
int j = 1; |
||||
out_low = p->coefs[0] * *ibuf; |
||||
CONVOLVE |
||||
assert(j == N+1); |
||||
*obuf_low++ = SOX_ROUND_CLIP_COUNT(out_low, effp->clips); |
||||
} |
||||
#undef _ |
||||
#define _ out_high += p->coefs[j+N+1] * p->previous[c][p->pos + j].in \ |
||||
- p->coefs[2*N+2 + j] * p->previous[c][p->pos + j].out_high, ++j; |
||||
{ |
||||
int j = 1; |
||||
out_high = p->coefs[N+1] * *ibuf; |
||||
CONVOLVE |
||||
assert(j == N+1); |
||||
*obuf_high++ = SOX_ROUND_CLIP_COUNT(out_high, effp->clips); |
||||
} |
||||
p->previous[c][p->pos + N].in = p->previous[c][p->pos].in = *ibuf++; |
||||
p->previous[c][p->pos + N].out_low = p->previous[c][p->pos].out_low = out_low; |
||||
p->previous[c][p->pos + N].out_high = p->previous[c][p->pos].out_high = out_high; |
||||
} |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
@ -1,171 +0,0 @@ |
||||
/* libSoX MP3 utilities Copyright (c) 2007-9 SoX contributors
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include <sys/stat.h> |
||||
|
||||
#if defined(HAVE_LAME) |
||||
|
||||
static void write_comments(sox_format_t * ft) |
||||
{ |
||||
priv_t *p = (priv_t *) ft->priv; |
||||
const char* comment; |
||||
|
||||
p->id3tag_init(p->gfp); |
||||
p->id3tag_set_pad(p->gfp, (size_t)ID3PADDING); |
||||
|
||||
/* Note: id3tag_set_fieldvalue is not present in LAME 3.97, so we're using
|
||||
the 3.97-compatible methods for all of the tags that 3.97 supported. */ |
||||
/* FIXME: This is no more necessary, since support for LAME 3.97 has ended. */ |
||||
if ((comment = sox_find_comment(ft->oob.comments, "Title"))) |
||||
p->id3tag_set_title(p->gfp, comment); |
||||
if ((comment = sox_find_comment(ft->oob.comments, "Artist"))) |
||||
p->id3tag_set_artist(p->gfp, comment); |
||||
if ((comment = sox_find_comment(ft->oob.comments, "Album"))) |
||||
p->id3tag_set_album(p->gfp, comment); |
||||
if ((comment = sox_find_comment(ft->oob.comments, "Tracknumber"))) |
||||
p->id3tag_set_track(p->gfp, comment); |
||||
if ((comment = sox_find_comment(ft->oob.comments, "Year"))) |
||||
p->id3tag_set_year(p->gfp, comment); |
||||
if ((comment = sox_find_comment(ft->oob.comments, "Comment"))) |
||||
p->id3tag_set_comment(p->gfp, comment); |
||||
if ((comment = sox_find_comment(ft->oob.comments, "Genre"))) |
||||
{ |
||||
if (p->id3tag_set_genre(p->gfp, comment)) |
||||
lsx_warn("\"%s\" is not a recognized ID3v1 genre.", comment); |
||||
} |
||||
|
||||
if ((comment = sox_find_comment(ft->oob.comments, "Discnumber"))) |
||||
{ |
||||
char* id3tag_buf = lsx_malloc(strlen(comment) + 6); |
||||
if (id3tag_buf) |
||||
{ |
||||
sprintf(id3tag_buf, "TPOS=%s", comment); |
||||
p->id3tag_set_fieldvalue(p->gfp, id3tag_buf); |
||||
free(id3tag_buf); |
||||
} |
||||
} |
||||
} |
||||
|
||||
#endif /* HAVE_LAME */ |
||||
|
||||
#ifdef HAVE_MAD_H |
||||
|
||||
static unsigned long xing_frames(priv_t * p, struct mad_bitptr ptr, unsigned bitlen) |
||||
{ |
||||
#define XING_MAGIC ( ('X' << 24) | ('i' << 16) | ('n' << 8) | 'g' ) |
||||
if (bitlen >= 96 && p->mad_bit_read(&ptr, 32) == XING_MAGIC && |
||||
(p->mad_bit_read(&ptr, 32) & 1 )) /* XING_FRAMES */ |
||||
return p->mad_bit_read(&ptr, 32); |
||||
return 0; |
||||
} |
||||
|
||||
static size_t mp3_duration(sox_format_t * ft) |
||||
{ |
||||
priv_t * p = (priv_t *) ft->priv; |
||||
struct mad_stream mad_stream; |
||||
struct mad_header mad_header; |
||||
struct mad_frame mad_frame; |
||||
size_t initial_bitrate = 0; /* Initialised to prevent warning */ |
||||
size_t tagsize = 0, consumed = 0, frames = 0; |
||||
sox_bool vbr = sox_false, depadded = sox_false; |
||||
size_t num_samples = 0; |
||||
|
||||
p->mad_stream_init(&mad_stream); |
||||
p->mad_header_init(&mad_header); |
||||
p->mad_frame_init(&mad_frame); |
||||
|
||||
do { /* Read data from the MP3 file */ |
||||
int read, padding = 0; |
||||
size_t leftover = mad_stream.bufend - mad_stream.next_frame; |
||||
|
||||
memmove(p->mp3_buffer, mad_stream.this_frame, leftover); |
||||
read = lsx_readbuf(ft, p->mp3_buffer + leftover, p->mp3_buffer_size - leftover); |
||||
if (read <= 0) { |
||||
lsx_debug("got exact duration by scan to EOF (frames=%" PRIuPTR " leftover=%" PRIuPTR ")", frames, leftover); |
||||
break; |
||||
} |
||||
for (; !depadded && padding < read && !p->mp3_buffer[padding]; ++padding); |
||||
depadded = sox_true; |
||||
p->mad_stream_buffer(&mad_stream, p->mp3_buffer + padding, leftover + read - padding); |
||||
|
||||
while (sox_true) { /* Decode frame headers */ |
||||
mad_stream.error = MAD_ERROR_NONE; |
||||
if (p->mad_header_decode(&mad_header, &mad_stream) == -1) { |
||||
if (mad_stream.error == MAD_ERROR_BUFLEN) |
||||
break; /* Normal behaviour; get some more data from the file */ |
||||
if (!MAD_RECOVERABLE(mad_stream.error)) { |
||||
lsx_warn("unrecoverable MAD error"); |
||||
break; |
||||
} |
||||
if (mad_stream.error == MAD_ERROR_LOSTSYNC) { |
||||
unsigned available = (mad_stream.bufend - mad_stream.this_frame); |
||||
tagsize = tagtype(mad_stream.this_frame, (size_t) available); |
||||
if (tagsize) { /* It's some ID3 tags, so just skip */ |
||||
if (tagsize >= available) { |
||||
lsx_seeki(ft, (off_t)(tagsize - available), SEEK_CUR); |
||||
depadded = sox_false; |
||||
} |
||||
p->mad_stream_skip(&mad_stream, min(tagsize, available)); |
||||
} |
||||
else lsx_warn("MAD lost sync"); |
||||
} |
||||
else lsx_warn("recoverable MAD error"); |
||||
continue; /* Not an audio frame */ |
||||
} |
||||
|
||||
num_samples += MAD_NSBSAMPLES(&mad_header) * 32; |
||||
consumed += mad_stream.next_frame - mad_stream.this_frame; |
||||
|
||||
lsx_debug_more("bitrate=%lu", mad_header.bitrate); |
||||
if (!frames) { |
||||
initial_bitrate = mad_header.bitrate; |
||||
|
||||
/* Get the precise frame count from the XING header if present */ |
||||
mad_frame.header = mad_header; |
||||
if (p->mad_frame_decode(&mad_frame, &mad_stream) == -1) |
||||
if (!MAD_RECOVERABLE(mad_stream.error)) { |
||||
lsx_warn("unrecoverable MAD error"); |
||||
break; |
||||
} |
||||
if ((frames = xing_frames(p, mad_stream.anc_ptr, mad_stream.anc_bitlen))) { |
||||
num_samples *= frames; |
||||
lsx_debug("got exact duration from XING frame count (%" PRIuPTR ")", frames); |
||||
break; |
||||
} |
||||
} |
||||
else vbr |= mad_header.bitrate != initial_bitrate; |
||||
|
||||
/* If not VBR, we can time just a few frames then extrapolate */ |
||||
if (++frames == 25 && !vbr) { |
||||
double frame_size = (double) consumed / frames; |
||||
size_t num_frames = (lsx_filelength(ft) - tagsize) / frame_size; |
||||
num_samples = num_samples / frames * num_frames; |
||||
lsx_debug("got approx. duration by CBR extrapolation"); |
||||
break; |
||||
} |
||||
} |
||||
} while (mad_stream.error == MAD_ERROR_BUFLEN); |
||||
|
||||
p->mad_frame_finish(&mad_frame); |
||||
mad_header_finish(&mad_header); |
||||
p->mad_stream_finish(&mad_stream); |
||||
lsx_rewind(ft); |
||||
|
||||
return num_samples; |
||||
} |
||||
|
||||
#endif /* HAVE_MAD_H */ |
File diff suppressed because it is too large
Load Diff
@ -1,223 +0,0 @@ |
||||
/* noiseprof - SoX Noise Profiling Effect.
|
||||
* |
||||
* Written by Ian Turner (vectro@vectro.org) |
||||
* Copyright 1999 Ian Turner and others |
||||
* |
||||
* 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 "noisered.h" |
||||
|
||||
#include <assert.h> |
||||
#include <string.h> |
||||
#include <errno.h> |
||||
|
||||
typedef struct { |
||||
float *sum; |
||||
int *profilecount; |
||||
|
||||
float *window; |
||||
} chandata_t; |
||||
|
||||
typedef struct { |
||||
char* output_filename; |
||||
FILE* output_file; |
||||
|
||||
chandata_t *chandata; |
||||
size_t bufdata; |
||||
} priv_t; |
||||
|
||||
/*
|
||||
* Get the filename, if any. We don't open it until sox_noiseprof_start. |
||||
*/ |
||||
static int sox_noiseprof_getopts(sox_effect_t * effp, int argc, char **argv) |
||||
{ |
||||
priv_t * data = (priv_t *) effp->priv; |
||||
--argc, ++argv; |
||||
|
||||
if (argc == 1) { |
||||
data->output_filename = argv[0]; |
||||
} else if (argc > 1) |
||||
return lsx_usage(effp); |
||||
|
||||
return (SOX_SUCCESS); |
||||
} |
||||
|
||||
/*
|
||||
* Prepare processing. |
||||
* Do all initializations. |
||||
*/ |
||||
static int sox_noiseprof_start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * data = (priv_t *) effp->priv; |
||||
unsigned channels = effp->in_signal.channels; |
||||
unsigned i; |
||||
|
||||
/* Note: don't fall back to stderr if stdout is unavailable
|
||||
* since we already use stderr for diagnostics. */ |
||||
if (!data->output_filename || !strcmp(data->output_filename, "-")) { |
||||
if (effp->global_info->global_info->stdout_in_use_by) { |
||||
lsx_fail("stdout already in use by `%s'", effp->global_info->global_info->stdout_in_use_by); |
||||
return SOX_EOF; |
||||
} |
||||
effp->global_info->global_info->stdout_in_use_by = effp->handler.name; |
||||
data->output_file = stdout; |
||||
} |
||||
else if ((data->output_file = fopen(data->output_filename, "wb")) == NULL) { |
||||
lsx_fail("Couldn't open profile file %s: %s", data->output_filename, strerror(errno)); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
data->chandata = lsx_calloc(channels, sizeof(*(data->chandata))); |
||||
data->bufdata = 0; |
||||
for (i = 0; i < channels; i ++) { |
||||
data->chandata[i].sum = lsx_calloc(FREQCOUNT, sizeof(float)); |
||||
data->chandata[i].profilecount = lsx_calloc(FREQCOUNT, sizeof(int)); |
||||
data->chandata[i].window = lsx_calloc(WINDOWSIZE, sizeof(float)); |
||||
} |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/* Collect statistics from the complete window on channel chan. */ |
||||
static void collect_data(chandata_t* chan) { |
||||
float *out = lsx_calloc(FREQCOUNT, sizeof(float)); |
||||
int i; |
||||
|
||||
lsx_power_spectrum_f(WINDOWSIZE, chan->window, out); |
||||
|
||||
for (i = 0; i < FREQCOUNT; i ++) { |
||||
if (out[i] > 0) { |
||||
float value = log(out[i]); |
||||
chan->sum[i] += value; |
||||
chan->profilecount[i] ++; |
||||
} |
||||
} |
||||
|
||||
free(out); |
||||
} |
||||
|
||||
/*
|
||||
* Grab what we can from ibuf, and process if we have a whole window. |
||||
*/ |
||||
static int sox_noiseprof_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 samp = min(*isamp, *osamp); |
||||
size_t chans = effp->in_signal.channels; |
||||
size_t i, j, n = min(samp / chans, WINDOWSIZE - p->bufdata); |
||||
|
||||
memcpy(obuf, ibuf, n * chans * sizeof(*obuf)); /* Pass on audio unaffected */ |
||||
*isamp = *osamp = n * chans; |
||||
|
||||
/* Collect data for every channel. */ |
||||
for (i = 0; i < chans; i ++) { |
||||
SOX_SAMPLE_LOCALS; |
||||
chandata_t * chan = &(p->chandata[i]); |
||||
for (j = 0; j < n; j ++) |
||||
chan->window[j + p->bufdata] = |
||||
SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[i + j * chans],); |
||||
if (n + p->bufdata == WINDOWSIZE) |
||||
collect_data(chan); |
||||
} |
||||
|
||||
p->bufdata += n; |
||||
assert(p->bufdata <= WINDOWSIZE); |
||||
if (p->bufdata == WINDOWSIZE) |
||||
p->bufdata = 0; |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Finish off the last window. |
||||
*/ |
||||
|
||||
static int sox_noiseprof_drain(sox_effect_t * effp, sox_sample_t *obuf UNUSED, size_t *osamp) |
||||
{ |
||||
priv_t * data = (priv_t *) effp->priv; |
||||
int tracks = effp->in_signal.channels; |
||||
int i; |
||||
|
||||
*osamp = 0; |
||||
|
||||
if (data->bufdata == 0) { |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
for (i = 0; i < tracks; i ++) { |
||||
int j; |
||||
for (j = data->bufdata+1; j < WINDOWSIZE; j ++) { |
||||
data->chandata[i].window[j] = 0; |
||||
} |
||||
collect_data(&(data->chandata[i])); |
||||
} |
||||
|
||||
if (data->bufdata == WINDOWSIZE || data->bufdata == 0) |
||||
return SOX_EOF; |
||||
else |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Print profile and clean up. |
||||
*/ |
||||
static int sox_noiseprof_stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * data = (priv_t *) effp->priv; |
||||
size_t i; |
||||
|
||||
for (i = 0; i < effp->in_signal.channels; i ++) { |
||||
int j; |
||||
chandata_t* chan = &(data->chandata[i]); |
||||
|
||||
fprintf(data->output_file, "Channel %lu: ", (unsigned long)i); |
||||
|
||||
for (j = 0; j < FREQCOUNT; j ++) { |
||||
double r = chan->profilecount[j] != 0 ? |
||||
chan->sum[j] / chan->profilecount[j] : 0; |
||||
fprintf(data->output_file, "%s%f", j == 0 ? "" : ", ", r); |
||||
} |
||||
fprintf(data->output_file, "\n"); |
||||
|
||||
free(chan->sum); |
||||
free(chan->profilecount); |
||||
} |
||||
|
||||
free(data->chandata); |
||||
|
||||
if (data->output_file != stdout) |
||||
fclose(data->output_file); |
||||
|
||||
return (SOX_SUCCESS); |
||||
} |
||||
|
||||
static sox_effect_handler_t sox_noiseprof_effect = { |
||||
"noiseprof", |
||||
"[profile-file]", |
||||
SOX_EFF_MCHAN | SOX_EFF_MODIFY, |
||||
sox_noiseprof_getopts, |
||||
sox_noiseprof_start, |
||||
sox_noiseprof_flow, |
||||
sox_noiseprof_drain, |
||||
sox_noiseprof_stop, |
||||
NULL, sizeof(priv_t) |
||||
}; |
||||
|
||||
const sox_effect_handler_t *lsx_noiseprof_effect_fn(void) |
||||
{ |
||||
return &sox_noiseprof_effect; |
||||
} |
@ -1,357 +0,0 @@ |
||||
/* noisered - Noise Reduction Effect.
|
||||
* |
||||
* Written by Ian Turner (vectro@vectro.org) |
||||
* |
||||
* Copyright 1999 Ian Turner |
||||
* This source code is freely redistributable and may be used for |
||||
* any purpose. This copyright notice must be maintained. |
||||
* Authors are not responsible for the consequences of using this software. |
||||
*/ |
||||
|
||||
#include "noisered.h" |
||||
|
||||
#include <stdlib.h> |
||||
#include <errno.h> |
||||
#include <string.h> |
||||
#include <assert.h> |
||||
|
||||
typedef struct { |
||||
float *window; |
||||
float *lastwindow; |
||||
float *noisegate; |
||||
float *smoothing; |
||||
} chandata_t; |
||||
|
||||
/* Holds profile information */ |
||||
typedef struct { |
||||
char* profile_filename; |
||||
float threshold; |
||||
|
||||
chandata_t *chandata; |
||||
size_t bufdata; |
||||
} priv_t; |
||||
|
||||
static void FFT(unsigned NumSamples, |
||||
int InverseTransform, |
||||
const float *RealIn, float *ImagIn, float *RealOut, float *ImagOut) |
||||
{ |
||||
unsigned i; |
||||
double * work = malloc(2 * NumSamples * sizeof(*work)); |
||||
for (i = 0; i < 2 * NumSamples; i += 2) { |
||||
work[i] = RealIn[i >> 1]; |
||||
work[i + 1] = ImagIn? ImagIn[i >> 1] : 0; |
||||
} |
||||
lsx_safe_cdft(2 * (int)NumSamples, InverseTransform? -1 : 1, work); |
||||
if (InverseTransform) for (i = 0; i < 2 * NumSamples; i += 2) { |
||||
RealOut[i >> 1] = work[i] / NumSamples; |
||||
ImagOut[i >> 1] = work[i + 1] / NumSamples; |
||||
} |
||||
else for (i = 0; i < 2 * NumSamples; i += 2) { |
||||
RealOut[i >> 1] = work[i]; |
||||
ImagOut[i >> 1] = work[i + 1]; |
||||
} |
||||
free(work); |
||||
} |
||||
|
||||
/*
|
||||
* Get the options. Default file is stdin (if the audio |
||||
* input file isn't coming from there, of course!) |
||||
*/ |
||||
static int sox_noisered_getopts(sox_effect_t * effp, int argc, char **argv) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
--argc, ++argv; |
||||
|
||||
if (argc > 0) { |
||||
p->profile_filename = argv[0]; |
||||
++argv; |
||||
--argc; |
||||
} |
||||
|
||||
p->threshold = 0.5; |
||||
do { /* break-able block */ |
||||
NUMERIC_PARAMETER(threshold, 0, 1); |
||||
} while (0); |
||||
|
||||
return argc? lsx_usage(effp) : SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Prepare processing. |
||||
* Do all initializations. |
||||
*/ |
||||
static int sox_noisered_start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * data = (priv_t *) effp->priv; |
||||
size_t fchannels = 0; |
||||
size_t channels = effp->in_signal.channels; |
||||
size_t i; |
||||
FILE * ifp = lsx_open_input_file(effp, data->profile_filename, sox_false); |
||||
|
||||
if (!ifp) |
||||
return SOX_EOF; |
||||
|
||||
data->chandata = lsx_calloc(channels, sizeof(*(data->chandata))); |
||||
data->bufdata = 0; |
||||
for (i = 0; i < channels; i ++) { |
||||
data->chandata[i].noisegate = lsx_calloc(FREQCOUNT, sizeof(float)); |
||||
data->chandata[i].smoothing = lsx_calloc(FREQCOUNT, sizeof(float)); |
||||
data->chandata[i].lastwindow = NULL; |
||||
} |
||||
while (1) { |
||||
unsigned long i1_ul; |
||||
size_t i1; |
||||
float f1; |
||||
if (2 != fscanf(ifp, " Channel %lu: %f", &i1_ul, &f1)) |
||||
break; |
||||
i1 = i1_ul; |
||||
if (i1 != fchannels) { |
||||
lsx_fail("noisered: Got channel %lu, expected channel %lu.", |
||||
(unsigned long)i1, (unsigned long)fchannels); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
data->chandata[fchannels].noisegate[0] = f1; |
||||
for (i = 1; i < FREQCOUNT; i ++) { |
||||
if (1 != fscanf(ifp, ", %f", &f1)) { |
||||
lsx_fail("noisered: Not enough data for channel %lu " |
||||
"(expected %d, got %lu)", (unsigned long)fchannels, FREQCOUNT, (unsigned long)i); |
||||
return SOX_EOF; |
||||
} |
||||
data->chandata[fchannels].noisegate[i] = f1; |
||||
} |
||||
fchannels ++; |
||||
} |
||||
if (fchannels != channels) { |
||||
lsx_fail("noisered: channel mismatch: %lu in input, %lu in profile.", |
||||
(unsigned long)channels, (unsigned long)fchannels); |
||||
return SOX_EOF; |
||||
} |
||||
if (ifp != stdin) |
||||
fclose(ifp); |
||||
|
||||
effp->out_signal.length = SOX_UNKNOWN_LEN; /* TODO: calculate actual length */ |
||||
|
||||
return (SOX_SUCCESS); |
||||
} |
||||
|
||||
/* Mangle a single window. Each output sample (except the first and last
|
||||
* half-window) is the result of two distinct calls to this function, |
||||
* due to overlapping windows. */ |
||||
static void reduce_noise(chandata_t* chan, float* window, double level) |
||||
{ |
||||
float *inr, *ini, *outr, *outi, *power; |
||||
float *smoothing = chan->smoothing; |
||||
int i; |
||||
|
||||
inr = lsx_calloc(WINDOWSIZE * 5, sizeof(float)); |
||||
ini = inr + WINDOWSIZE; |
||||
outr = ini + WINDOWSIZE; |
||||
outi = outr + WINDOWSIZE; |
||||
power = outi + WINDOWSIZE; |
||||
|
||||
for (i = 0; i < FREQCOUNT; i ++) |
||||
assert(smoothing[i] >= 0 && smoothing[i] <= 1); |
||||
|
||||
memcpy(inr, window, WINDOWSIZE*sizeof(float)); |
||||
|
||||
FFT(WINDOWSIZE, 0, inr, NULL, outr, outi); |
||||
|
||||
memcpy(inr, window, WINDOWSIZE*sizeof(float)); |
||||
lsx_apply_hann_f(inr, WINDOWSIZE); |
||||
lsx_power_spectrum_f(WINDOWSIZE, inr, power); |
||||
|
||||
for (i = 0; i < FREQCOUNT; i ++) { |
||||
float smooth; |
||||
float plog; |
||||
plog = log(power[i]); |
||||
if (power[i] != 0 && plog < chan->noisegate[i] + level*8.0) |
||||
smooth = 0.0; |
||||
else |
||||
smooth = 1.0; |
||||
|
||||
smoothing[i] = smooth * 0.5 + smoothing[i] * 0.5; |
||||
} |
||||
|
||||
/* Audacity says this code will eliminate tinkle bells.
|
||||
* I have no idea what that means. */ |
||||
for (i = 2; i < FREQCOUNT - 2; i ++) { |
||||
if (smoothing[i]>=0.5 && |
||||
smoothing[i]<=0.55 && |
||||
smoothing[i-1]<0.1 && |
||||
smoothing[i-2]<0.1 && |
||||
smoothing[i+1]<0.1 && |
||||
smoothing[i+2]<0.1) |
||||
smoothing[i] = 0.0; |
||||
} |
||||
|
||||
outr[0] *= smoothing[0]; |
||||
outi[0] *= smoothing[0]; |
||||
outr[FREQCOUNT-1] *= smoothing[FREQCOUNT-1]; |
||||
outi[FREQCOUNT-1] *= smoothing[FREQCOUNT-1]; |
||||
|
||||
for (i = 1; i < FREQCOUNT-1; i ++) { |
||||
int j = WINDOWSIZE - i; |
||||
float smooth = smoothing[i]; |
||||
|
||||
outr[i] *= smooth; |
||||
outi[i] *= smooth; |
||||
outr[j] *= smooth; |
||||
outi[j] *= smooth; |
||||
} |
||||
|
||||
FFT(WINDOWSIZE, 1, outr, outi, inr, ini); |
||||
lsx_apply_hann_f(inr, WINDOWSIZE); |
||||
|
||||
memcpy(window, inr, WINDOWSIZE*sizeof(float)); |
||||
|
||||
for (i = 0; i < FREQCOUNT; i ++) |
||||
assert(smoothing[i] >= 0 && smoothing[i] <= 1); |
||||
|
||||
free(inr); |
||||
} |
||||
|
||||
/* Do window management once we have a complete window, including mangling
|
||||
* the current window. */ |
||||
static int process_window(sox_effect_t * effp, priv_t * data, unsigned chan_num, unsigned num_chans, |
||||
sox_sample_t *obuf, unsigned len) { |
||||
int j; |
||||
float* nextwindow; |
||||
int use = min(len, WINDOWSIZE)-min(len,(WINDOWSIZE/2)); |
||||
chandata_t *chan = &(data->chandata[chan_num]); |
||||
int first = (chan->lastwindow == NULL); |
||||
SOX_SAMPLE_LOCALS; |
||||
|
||||
if ((nextwindow = lsx_calloc(WINDOWSIZE, sizeof(float))) == NULL) |
||||
return SOX_EOF; |
||||
|
||||
memcpy(nextwindow, chan->window+WINDOWSIZE/2, |
||||
sizeof(float)*(WINDOWSIZE/2)); |
||||
|
||||
reduce_noise(chan, chan->window, data->threshold); |
||||
if (!first) { |
||||
for (j = 0; j < use; j ++) { |
||||
float s = chan->window[j] + chan->lastwindow[WINDOWSIZE/2 + j]; |
||||
obuf[chan_num + num_chans * j] = |
||||
SOX_FLOAT_32BIT_TO_SAMPLE(s, effp->clips); |
||||
} |
||||
free(chan->lastwindow); |
||||
} else { |
||||
for (j = 0; j < use; j ++) { |
||||
assert(chan->window[j] >= -1 && chan->window[j] <= 1); |
||||
obuf[chan_num + num_chans * j] = |
||||
SOX_FLOAT_32BIT_TO_SAMPLE(chan->window[j], effp->clips); |
||||
} |
||||
} |
||||
chan->lastwindow = chan->window; |
||||
chan->window = nextwindow; |
||||
|
||||
return use; |
||||
} |
||||
|
||||
/*
|
||||
* Read in windows, and call process_window once we get a whole one. |
||||
*/ |
||||
static int sox_noisered_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, |
||||
size_t *isamp, size_t *osamp) |
||||
{ |
||||
priv_t * data = (priv_t *) effp->priv; |
||||
size_t samp = min(*isamp, *osamp); |
||||
size_t tracks = effp->in_signal.channels; |
||||
size_t track_samples = samp / tracks; |
||||
size_t ncopy = min(track_samples, WINDOWSIZE-data->bufdata); |
||||
size_t whole_window = (ncopy + data->bufdata == WINDOWSIZE); |
||||
int oldbuf = data->bufdata; |
||||
size_t i; |
||||
|
||||
/* FIXME: Make this automatic for all effects */ |
||||
assert(effp->in_signal.channels == effp->out_signal.channels); |
||||
|
||||
if (whole_window) |
||||
data->bufdata = WINDOWSIZE/2; |
||||
else |
||||
data->bufdata += ncopy; |
||||
|
||||
/* Reduce noise on every channel. */ |
||||
for (i = 0; i < tracks; i ++) { |
||||
SOX_SAMPLE_LOCALS; |
||||
chandata_t* chan = &(data->chandata[i]); |
||||
size_t j; |
||||
|
||||
if (chan->window == NULL) |
||||
chan->window = lsx_calloc(WINDOWSIZE, sizeof(float)); |
||||
|
||||
for (j = 0; j < ncopy; j ++) |
||||
chan->window[oldbuf + j] = |
||||
SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[i + tracks * j], effp->clips); |
||||
|
||||
if (!whole_window) |
||||
continue; |
||||
else |
||||
process_window(effp, data, (unsigned) i, (unsigned) tracks, obuf, (unsigned) (oldbuf + ncopy)); |
||||
} |
||||
|
||||
*isamp = tracks*ncopy; |
||||
if (whole_window) |
||||
*osamp = tracks*(WINDOWSIZE/2); |
||||
else |
||||
*osamp = 0; |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* We have up to half a window left to dump. |
||||
*/ |
||||
|
||||
static int sox_noisered_drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp) |
||||
{ |
||||
priv_t * data = (priv_t *)effp->priv; |
||||
unsigned i; |
||||
unsigned tracks = effp->in_signal.channels; |
||||
for (i = 0; i < tracks; i ++) |
||||
*osamp = process_window(effp, data, i, tracks, obuf, (unsigned) data->bufdata); |
||||
|
||||
/* FIXME: This is very picky. osamp needs to be big enough to get all
|
||||
* remaining data or it will be discarded. |
||||
*/ |
||||
return (SOX_EOF); |
||||
} |
||||
|
||||
/*
|
||||
* Clean up. |
||||
*/ |
||||
static int sox_noisered_stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * data = (priv_t *) effp->priv; |
||||
size_t i; |
||||
|
||||
for (i = 0; i < effp->in_signal.channels; i ++) { |
||||
chandata_t* chan = &(data->chandata[i]); |
||||
free(chan->lastwindow); |
||||
free(chan->window); |
||||
free(chan->smoothing); |
||||
free(chan->noisegate); |
||||
} |
||||
|
||||
free(data->chandata); |
||||
|
||||
return (SOX_SUCCESS); |
||||
} |
||||
|
||||
static sox_effect_handler_t sox_noisered_effect = { |
||||
"noisered", |
||||
"[profile-file [amount]]", |
||||
SOX_EFF_MCHAN|SOX_EFF_LENGTH, |
||||
sox_noisered_getopts, |
||||
sox_noisered_start, |
||||
sox_noisered_flow, |
||||
sox_noisered_drain, |
||||
sox_noisered_stop, |
||||
NULL, sizeof(priv_t) |
||||
}; |
||||
|
||||
const sox_effect_handler_t *lsx_noisered_effect_fn(void) |
||||
{ |
||||
return &sox_noisered_effect; |
||||
} |
@ -1,26 +0,0 @@ |
||||
/* noiseprof.h - Headers for SoX Noise Profiling Effect.
|
||||
* |
||||
* Written by Ian Turner (vectro@vectro.org) |
||||
* Copyright 1999 Ian Turner and others |
||||
* |
||||
* 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 <math.h> |
||||
|
||||
#define WINDOWSIZE 2048 |
||||
#define HALFWINDOW (WINDOWSIZE / 2) |
||||
#define FREQCOUNT (HALFWINDOW + 1) |
@ -1,235 +0,0 @@ |
||||
/* libSoX Opus-in-Ogg sound format handler
|
||||
* Copyright (C) 2013 John Stumpo <stump@jstump.com> |
||||
* |
||||
* Largely based on vorbis.c: |
||||
* libSoX Ogg Vorbis sound format handler |
||||
* Copyright 2001, Stan Seibert <indigo@aztec.asu.edu> |
||||
* |
||||
* Portions from oggenc, (c) Michael Smith <msmith@labyrinth.net.au>, |
||||
* ogg123, (c) Kenneth Arnold <kcarnold@yahoo.com>, and |
||||
* libvorbisfile (c) Xiphophorus Company |
||||
* |
||||
* May 9, 2001 - Stan Seibert (indigo@aztec.asu.edu) |
||||
* Ogg Vorbis handler initially written. |
||||
* |
||||
* July 5, 1991 - Skeleton file |
||||
* Copyright 1991 Lance Norskog And Sundry Contributors |
||||
* This source code is freely redistributable and may be used for |
||||
* any purpose. This copyright notice must be maintained. |
||||
* Lance Norskog And Sundry Contributors are not responsible for |
||||
* the consequences of using this software. |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <errno.h> |
||||
|
||||
#include <opusfile.h> |
||||
|
||||
#define DEF_BUF_LEN 4096 |
||||
|
||||
#define BUF_ERROR -1 |
||||
#define BUF_EOF 0 |
||||
#define BUF_DATA 1 |
||||
|
||||
typedef struct { |
||||
/* Decoding data */ |
||||
OggOpusFile *of; |
||||
char *buf; |
||||
size_t buf_len; |
||||
size_t start; |
||||
size_t end; /* Unsent data samples in buf[start] through buf[end-1] */ |
||||
int current_section; |
||||
int eof; |
||||
} priv_t; |
||||
|
||||
/******** Callback functions used in op_open_callbacks ************/ |
||||
|
||||
static int callback_read(void* ft_data, unsigned char* ptr, int nbytes) |
||||
{ |
||||
sox_format_t* ft = (sox_format_t*)ft_data; |
||||
return lsx_readbuf(ft, ptr, (size_t)nbytes); |
||||
} |
||||
|
||||
static int callback_seek(void* ft_data, opus_int64 off, int whence) |
||||
{ |
||||
sox_format_t* ft = (sox_format_t*)ft_data; |
||||
int ret = ft->seekable ? lsx_seeki(ft, (off_t)off, whence) : -1; |
||||
|
||||
if (ret == EBADF) |
||||
ret = -1; |
||||
return ret; |
||||
} |
||||
|
||||
static int callback_close(void* ft_data UNUSED) |
||||
{ |
||||
/* Do nothing so sox can close the file for us */ |
||||
return 0; |
||||
} |
||||
|
||||
static opus_int64 callback_tell(void* ft_data) |
||||
{ |
||||
sox_format_t* ft = (sox_format_t*)ft_data; |
||||
return lsx_tell(ft); |
||||
} |
||||
|
||||
/********************* End callbacks *****************************/ |
||||
|
||||
|
||||
/*
|
||||
* Do anything required before you start reading samples. |
||||
* Read file header. |
||||
* Find out sampling rate, |
||||
* size and encoding of samples, |
||||
* mono/stereo/quad. |
||||
*/ |
||||
static int startread(sox_format_t * ft) |
||||
{ |
||||
priv_t * vb = (priv_t *) ft->priv; |
||||
const OpusTags *ot; |
||||
int i; |
||||
|
||||
OpusFileCallbacks callbacks = { |
||||
callback_read, |
||||
callback_seek, |
||||
callback_tell, |
||||
callback_close |
||||
}; |
||||
|
||||
/* Init the decoder */ |
||||
vb->of = op_open_callbacks(ft, &callbacks, NULL, (size_t) 0, NULL); |
||||
if (vb->of == NULL) { |
||||
lsx_fail_errno(ft, SOX_EHDR, "Input not an Ogg Opus audio stream"); |
||||
return (SOX_EOF); |
||||
} |
||||
|
||||
/* Get info about the Opus stream */ |
||||
ot = op_tags(vb->of, -1); |
||||
|
||||
/* Record audio info */ |
||||
ft->signal.rate = 48000; /* libopusfile always uses 48 kHz */ |
||||
ft->encoding.encoding = SOX_ENCODING_OPUS; |
||||
ft->signal.channels = op_channel_count(vb->of, -1); |
||||
|
||||
/* op_pcm_total doesn't work on non-seekable files so
|
||||
* skip that step in that case. Also, it reports |
||||
* "frame"-ish results so we must * channels. |
||||
*/ |
||||
if (ft->seekable) |
||||
ft->signal.length = op_pcm_total(vb->of, -1) * ft->signal.channels; |
||||
|
||||
/* Record comments */ |
||||
for (i = 0; i < ot->comments; i++) |
||||
sox_append_comment(&ft->oob.comments, ot->user_comments[i]); |
||||
|
||||
/* Setup buffer */ |
||||
vb->buf_len = DEF_BUF_LEN; |
||||
vb->buf_len -= vb->buf_len % (ft->signal.channels*2); /* 2 bytes per sample */ |
||||
vb->buf = lsx_calloc(vb->buf_len, sizeof(char)); |
||||
vb->start = vb->end = 0; |
||||
|
||||
/* Fill in other info */ |
||||
vb->eof = 0; |
||||
vb->current_section = -1; |
||||
|
||||
return (SOX_SUCCESS); |
||||
} |
||||
|
||||
|
||||
/* Refill the buffer with samples. Returns BUF_EOF if the end of the
|
||||
* Opus data was reached while the buffer was being filled, |
||||
* BUF_ERROR is something bad happens, and BUF_DATA otherwise */ |
||||
static int refill_buffer(sox_format_t * ft) |
||||
{ |
||||
priv_t * vb = (priv_t *) ft->priv; |
||||
int num_read; |
||||
|
||||
if (vb->start == vb->end) /* Samples all played */ |
||||
vb->start = vb->end = 0; |
||||
|
||||
while (vb->end < vb->buf_len) { |
||||
num_read = op_read(vb->of, (opus_int16*) (vb->buf + vb->end), |
||||
(int) ((vb->buf_len - vb->end) / sizeof(opus_int16)), |
||||
&vb->current_section); |
||||
if (num_read == 0) |
||||
return (BUF_EOF); |
||||
else if (num_read == OP_HOLE) |
||||
lsx_warn("Warning: hole in stream; probably harmless"); |
||||
else if (num_read < 0) |
||||
return (BUF_ERROR); |
||||
else |
||||
vb->end += num_read * sizeof(opus_int16) * ft->signal.channels; |
||||
} |
||||
return (BUF_DATA); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* Read up to len samples from file. |
||||
* Convert to signed longs. |
||||
* Place in buf[]. |
||||
* Return number of samples read. |
||||
*/ |
||||
|
||||
static size_t read_samples(sox_format_t * ft, sox_sample_t * buf, size_t len) |
||||
{ |
||||
priv_t * vb = (priv_t *) ft->priv; |
||||
size_t i; |
||||
int ret; |
||||
sox_sample_t l; |
||||
|
||||
|
||||
for (i = 0; i < len; i++) { |
||||
if (vb->start == vb->end) { |
||||
if (vb->eof) |
||||
break; |
||||
ret = refill_buffer(ft); |
||||
if (ret == BUF_EOF || ret == BUF_ERROR) { |
||||
vb->eof = 1; |
||||
if (vb->end == 0) |
||||
break; |
||||
} |
||||
} |
||||
|
||||
l = (vb->buf[vb->start + 1] << 24) |
||||
| (0xffffff & (vb->buf[vb->start] << 16)); |
||||
*(buf + i) = l; |
||||
vb->start += 2; |
||||
} |
||||
return i; |
||||
} |
||||
|
||||
/*
|
||||
* Do anything required when you stop reading samples. |
||||
* Don't close input file! |
||||
*/ |
||||
static int stopread(sox_format_t * ft) |
||||
{ |
||||
priv_t * vb = (priv_t *) ft->priv; |
||||
|
||||
free(vb->buf); |
||||
op_free(vb->of); |
||||
|
||||
return (SOX_SUCCESS); |
||||
} |
||||
|
||||
static int seek(sox_format_t * ft, uint64_t offset) |
||||
{ |
||||
priv_t * vb = (priv_t *) ft->priv; |
||||
|
||||
return op_pcm_seek(vb->of, (opus_int64)(offset / ft->signal.channels))? SOX_EOF:SOX_SUCCESS; |
||||
} |
||||
|
||||
LSX_FORMAT_HANDLER(opus) |
||||
{ |
||||
static const char *const names[] = {"opus", NULL}; |
||||
static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE, |
||||
"Xiph.org's Opus lossy compression", names, 0, |
||||
startread, read_samples, stopread, |
||||
NULL, NULL, NULL, |
||||
seek, NULL, NULL, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,446 +0,0 @@ |
||||
/* Copyright 1997 Chris Bagwell And Sundry Contributors
|
||||
* This source code is freely redistributable and may be used for |
||||
* any purpose. This copyright notice must be maintained. |
||||
* Chris Bagwell And Sundry Contributors are not |
||||
* responsible for the consequences of using this software. |
||||
* |
||||
* Direct to Open Sound System (OSS) sound driver |
||||
* OSS is a popular unix sound driver for Intel x86 unices (eg. Linux) |
||||
* and several other unixes (such as SunOS/Solaris). |
||||
* This driver is compatible with OSS original source that was called |
||||
* USS, Voxware and TASD. |
||||
* |
||||
* added by Chris Bagwell (cbagwell@sprynet.com) on 2/19/96 |
||||
* based on info grabed from vplay.c in Voxware snd-utils-3.5 package. |
||||
* and on LINUX_PLAYER patches added by Greg Lee |
||||
* which was originally from Directo to Sound Blaster device driver (sbdsp.c). |
||||
* SBLAST patches by John T. Kohl. |
||||
* |
||||
* Changes: |
||||
* |
||||
* Nov. 26, 1999 Stan Brooks <stabro@megsinet.net> |
||||
* Moved initialization code common to startread and startwrite |
||||
* into a single function ossdspinit(). |
||||
* |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <fcntl.h> |
||||
#ifdef HAVE_SYS_SOUNDCARD_H |
||||
#include <sys/soundcard.h> |
||||
#endif |
||||
#ifdef HAVE_UNISTD_H |
||||
#include <unistd.h> |
||||
#endif |
||||
|
||||
/* these appear in the sys/soundcard.h of OSS 4.x, and in Linux's
|
||||
* sound/core/oss/pcm_oss.c (2.6.24 and later), but are typically |
||||
* not included in system header files. |
||||
*/ |
||||
#ifndef AFMT_S32_LE |
||||
#define AFMT_S32_LE 0x00001000 |
||||
#endif |
||||
#ifndef AFMT_S32_BE |
||||
#define AFMT_S32_BE 0x00002000 |
||||
#endif |
||||
|
||||
#include <sys/ioctl.h> |
||||
|
||||
typedef struct |
||||
{ |
||||
char* pOutput; |
||||
unsigned cOutput; |
||||
int device; |
||||
unsigned sample_shift; |
||||
} priv_t; |
||||
|
||||
/* common r/w initialization code */ |
||||
static int ossinit(sox_format_t* ft) |
||||
{ |
||||
int sampletype, samplesize; |
||||
int tmp, rc; |
||||
char const* szDevname; |
||||
priv_t* pPriv = (priv_t*)ft->priv; |
||||
|
||||
if (ft->filename == 0 || ft->filename[0] == 0 || !strcasecmp("default", ft->filename)) |
||||
{ |
||||
szDevname = getenv("OSS_AUDIODEV"); |
||||
if (szDevname != NULL) |
||||
{ |
||||
lsx_report("Using device name from OSS_AUDIODEV environment variable: %s", szDevname); |
||||
} |
||||
else |
||||
{ |
||||
szDevname = "/dev/dsp"; |
||||
lsx_report("Using default OSS device name: %s", szDevname); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
szDevname = ft->filename; |
||||
lsx_report("Using user-specified device name: %s", szDevname); |
||||
} |
||||
|
||||
pPriv->device = open( |
||||
szDevname, |
||||
ft->mode == 'r' ? O_RDONLY : O_WRONLY); |
||||
if (pPriv->device < 0) { |
||||
lsx_fail_errno(ft, errno, "open failed for device: %s", szDevname); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
if (ft->encoding.bits_per_sample == 8) { |
||||
sampletype = AFMT_U8; |
||||
samplesize = 8; |
||||
pPriv->sample_shift = 0; |
||||
if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) |
||||
ft->encoding.encoding = SOX_ENCODING_UNSIGNED; |
||||
if (ft->encoding.encoding != SOX_ENCODING_UNSIGNED) { |
||||
lsx_report("OSS driver only supports unsigned with bytes"); |
||||
lsx_report("Forcing to unsigned"); |
||||
ft->encoding.encoding = SOX_ENCODING_UNSIGNED; |
||||
} |
||||
} |
||||
else if (ft->encoding.bits_per_sample == 16) { |
||||
/* Attempt to use endian that user specified */ |
||||
if (ft->encoding.reverse_bytes) |
||||
sampletype = (MACHINE_IS_BIGENDIAN) ? AFMT_S16_LE : AFMT_S16_BE; |
||||
else |
||||
sampletype = (MACHINE_IS_BIGENDIAN) ? AFMT_S16_BE : AFMT_S16_LE; |
||||
samplesize = 16; |
||||
pPriv->sample_shift = 1; |
||||
if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) |
||||
ft->encoding.encoding = SOX_ENCODING_SIGN2; |
||||
if (ft->encoding.encoding != SOX_ENCODING_SIGN2) { |
||||
lsx_report("OSS driver only supports signed with words"); |
||||
lsx_report("Forcing to signed linear"); |
||||
ft->encoding.encoding = SOX_ENCODING_SIGN2; |
||||
} |
||||
} |
||||
else if (ft->encoding.bits_per_sample == 32) { |
||||
/* Attempt to use endian that user specified */ |
||||
if (ft->encoding.reverse_bytes) |
||||
sampletype = (MACHINE_IS_BIGENDIAN) ? AFMT_S32_LE : AFMT_S32_BE; |
||||
else |
||||
sampletype = (MACHINE_IS_BIGENDIAN) ? AFMT_S32_BE : AFMT_S32_LE; |
||||
samplesize = 32; |
||||
pPriv->sample_shift = 2; |
||||
if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) |
||||
ft->encoding.encoding = SOX_ENCODING_SIGN2; |
||||
if (ft->encoding.encoding != SOX_ENCODING_SIGN2) { |
||||
lsx_report("OSS driver only supports signed with words"); |
||||
lsx_report("Forcing to signed linear"); |
||||
ft->encoding.encoding = SOX_ENCODING_SIGN2; |
||||
} |
||||
} |
||||
else { |
||||
/* Attempt to use endian that user specified */ |
||||
if (ft->encoding.reverse_bytes) |
||||
sampletype = (MACHINE_IS_BIGENDIAN) ? AFMT_S16_LE : AFMT_S16_BE; |
||||
else |
||||
sampletype = (MACHINE_IS_BIGENDIAN) ? AFMT_S16_BE : AFMT_S16_LE; |
||||
samplesize = 16; |
||||
pPriv->sample_shift = 1; |
||||
ft->encoding.bits_per_sample = 16; |
||||
ft->encoding.encoding = SOX_ENCODING_SIGN2; |
||||
lsx_report("OSS driver only supports bytes and words"); |
||||
lsx_report("Forcing to signed linear word"); |
||||
} |
||||
|
||||
ft->signal.channels = 2; |
||||
|
||||
if (ioctl(pPriv->device, (size_t) SNDCTL_DSP_RESET, 0) < 0) |
||||
{ |
||||
lsx_fail_errno(ft,SOX_EOF,"Unable to reset OSS device %s. Possibly accessing an invalid file/device", szDevname); |
||||
return(SOX_EOF); |
||||
} |
||||
|
||||
/* Query the supported formats and find the best match
|
||||
*/ |
||||
rc = ioctl(pPriv->device, SNDCTL_DSP_GETFMTS, &tmp); |
||||
if (rc == 0) { |
||||
if ((tmp & sampletype) == 0) |
||||
{ |
||||
/* is 16-bit supported? */ |
||||
if (samplesize == 16 && (tmp & (AFMT_S16_LE|AFMT_S16_BE)) == 0) |
||||
{ |
||||
/* Must not like 16-bits, try 8-bits */ |
||||
ft->encoding.bits_per_sample = 8; |
||||
ft->encoding.encoding = SOX_ENCODING_UNSIGNED; |
||||
lsx_report("OSS driver doesn't like signed words"); |
||||
lsx_report("Forcing to unsigned bytes"); |
||||
tmp = sampletype = AFMT_U8; |
||||
samplesize = 8; |
||||
pPriv->sample_shift = 0; |
||||
} |
||||
/* is 8-bit supported */ |
||||
else if (samplesize == 8 && (tmp & AFMT_U8) == 0) |
||||
{ |
||||
ft->encoding.bits_per_sample = 16; |
||||
ft->encoding.encoding = SOX_ENCODING_SIGN2; |
||||
lsx_report("OSS driver doesn't like unsigned bytes"); |
||||
lsx_report("Forcing to signed words"); |
||||
sampletype = (MACHINE_IS_BIGENDIAN) ? AFMT_S16_BE : AFMT_S16_LE; |
||||
samplesize = 16; |
||||
pPriv->sample_shift = 1; |
||||
} |
||||
/* determine which 16-bit format to use */ |
||||
if (samplesize == 16 && (tmp & sampletype) == 0) |
||||
{ |
||||
/* Either user requested something not supported
|
||||
* or hardware doesn't support machine endian. |
||||
* Force to opposite as the above test showed |
||||
* it supports at least one of the two endians. |
||||
*/ |
||||
sampletype = (sampletype == AFMT_S16_BE) ? AFMT_S16_LE : AFMT_S16_BE; |
||||
ft->encoding.reverse_bytes = !ft->encoding.reverse_bytes; |
||||
} |
||||
|
||||
} |
||||
tmp = sampletype; |
||||
rc = ioctl(pPriv->device, SNDCTL_DSP_SETFMT, &tmp); |
||||
} |
||||
/* Give up and exit */ |
||||
if (rc < 0 || tmp != sampletype) |
||||
{ |
||||
lsx_fail_errno(ft,SOX_EOF,"Unable to set the sample size to %d", samplesize); |
||||
return (SOX_EOF); |
||||
} |
||||
|
||||
tmp = 1; |
||||
if (ioctl(pPriv->device, SNDCTL_DSP_STEREO, &tmp) < 0 || tmp != 1) |
||||
{ |
||||
lsx_warn("Couldn't set to stereo"); |
||||
ft->signal.channels = 1; |
||||
} |
||||
|
||||
tmp = ft->signal.rate; |
||||
if (ioctl(pPriv->device, SNDCTL_DSP_SPEED, &tmp) < 0 || |
||||
(int)ft->signal.rate != tmp) { |
||||
/* If the rate the sound card is using is not within 1% of what
|
||||
* the user specified then override the user setting. |
||||
* The only reason not to always override this is because of |
||||
* clock-rounding problems. Sound cards will sometimes use |
||||
* things like 44101 when you ask for 44100. No need overriding |
||||
* this and having strange output file rates for something that |
||||
* we can't hear anyways. |
||||
*/ |
||||
if ((int)ft->signal.rate - tmp > (tmp * .01) || |
||||
tmp - (int)ft->signal.rate > (tmp * .01)) |
||||
ft->signal.rate = tmp; |
||||
} |
||||
|
||||
if (ioctl(pPriv->device, (size_t) SNDCTL_DSP_SYNC, NULL) < 0) { |
||||
lsx_fail_errno(ft,SOX_EOF,"Unable to sync dsp"); |
||||
return (SOX_EOF); |
||||
} |
||||
|
||||
if (ft->mode == 'r') { |
||||
pPriv->cOutput = 0; |
||||
pPriv->pOutput = NULL; |
||||
} else { |
||||
size_t cbOutput = sox_globals.bufsiz; |
||||
pPriv->cOutput = cbOutput >> pPriv->sample_shift; |
||||
pPriv->pOutput = lsx_malloc(cbOutput); |
||||
} |
||||
|
||||
return(SOX_SUCCESS); |
||||
} |
||||
|
||||
static int ossstop(sox_format_t* ft) |
||||
{ |
||||
priv_t* pPriv = (priv_t*)ft->priv; |
||||
if (pPriv->device >= 0) { |
||||
close(pPriv->device); |
||||
} |
||||
if (pPriv->pOutput) { |
||||
free(pPriv->pOutput); |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static size_t ossread(sox_format_t* ft, sox_sample_t* pOutput, size_t cOutput) |
||||
{ |
||||
priv_t* pPriv = (priv_t*)ft->priv; |
||||
char* pbOutput = (char*)pOutput; |
||||
size_t cbOutputLeft = cOutput << pPriv->sample_shift; |
||||
size_t i, cRead; |
||||
int cbRead; |
||||
SOX_SAMPLE_LOCALS; |
||||
LSX_USE_VAR(sox_macro_temp_double); |
||||
|
||||
while (cbOutputLeft) { |
||||
cbRead = read(pPriv->device, pbOutput, cbOutputLeft); |
||||
if (cbRead <= 0) { |
||||
if (cbRead < 0) { |
||||
lsx_fail_errno(ft, errno, "Error reading from device"); |
||||
return 0; |
||||
} |
||||
break; |
||||
} |
||||
cbOutputLeft -= cbRead; |
||||
pbOutput += cbRead; |
||||
} |
||||
|
||||
/* Convert in-place (backwards) */ |
||||
cRead = cOutput - (cbOutputLeft >> pPriv->sample_shift); |
||||
if (ft->encoding.reverse_bytes) { |
||||
switch (pPriv->sample_shift) |
||||
{ |
||||
case 0: |
||||
for (i = cRead; i != 0; i--) { |
||||
pOutput[i - 1] = SOX_UNSIGNED_8BIT_TO_SAMPLE( |
||||
((sox_uint8_t*)pOutput)[i - 1], |
||||
dummy); |
||||
} |
||||
break; |
||||
case 1: |
||||
for (i = cRead; i != 0; i--) { |
||||
pOutput[i - 1] = SOX_SIGNED_16BIT_TO_SAMPLE( |
||||
lsx_swapw(((sox_int16_t*)pOutput)[i - 1]), |
||||
dummy); |
||||
} |
||||
break; |
||||
case 2: |
||||
for (i = cRead; i != 0; i--) { |
||||
pOutput[i - 1] = SOX_SIGNED_32BIT_TO_SAMPLE( |
||||
lsx_swapdw(((sox_int32_t*)pOutput)[i - 1]), |
||||
dummy); |
||||
} |
||||
break; |
||||
} |
||||
} else { |
||||
switch (pPriv->sample_shift) |
||||
{ |
||||
case 0: |
||||
for (i = cRead; i != 0; i--) { |
||||
pOutput[i - 1] = SOX_UNSIGNED_8BIT_TO_SAMPLE( |
||||
((sox_uint8_t*)pOutput)[i - 1], |
||||
dummy); |
||||
} |
||||
break; |
||||
case 1: |
||||
for (i = cRead; i != 0; i--) { |
||||
pOutput[i - 1] = SOX_SIGNED_16BIT_TO_SAMPLE( |
||||
((sox_int16_t*)pOutput)[i - 1], |
||||
dummy); |
||||
} |
||||
break; |
||||
case 2: |
||||
for (i = cRead; i != 0; i--) { |
||||
pOutput[i - 1] = SOX_SIGNED_32BIT_TO_SAMPLE( |
||||
((sox_int32_t*)pOutput)[i - 1], |
||||
dummy); |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return cRead; |
||||
} |
||||
|
||||
static size_t osswrite( |
||||
sox_format_t* ft, |
||||
const sox_sample_t* pInput, |
||||
size_t cInput) |
||||
{ |
||||
priv_t* pPriv = (priv_t*)ft->priv; |
||||
size_t cInputRemaining = cInput; |
||||
unsigned cClips = 0; |
||||
SOX_SAMPLE_LOCALS; |
||||
|
||||
while (cInputRemaining) { |
||||
size_t cStride; |
||||
size_t i; |
||||
size_t cbStride; |
||||
int cbWritten; |
||||
|
||||
cStride = cInputRemaining; |
||||
if (cStride > pPriv->cOutput) { |
||||
cStride = pPriv->cOutput; |
||||
} |
||||
|
||||
if (ft->encoding.reverse_bytes) |
||||
{ |
||||
switch (pPriv->sample_shift) |
||||
{ |
||||
case 0: |
||||
for (i = 0; i != cStride; i++) { |
||||
((sox_uint8_t*)pPriv->pOutput)[i] = |
||||
SOX_SAMPLE_TO_UNSIGNED_8BIT(pInput[i], cClips); |
||||
} |
||||
break; |
||||
case 1: |
||||
for (i = 0; i != cStride; i++) { |
||||
sox_int16_t s16 = SOX_SAMPLE_TO_SIGNED_16BIT(pInput[i], cClips); |
||||
((sox_int16_t*)pPriv->pOutput)[i] = lsx_swapw(s16); |
||||
} |
||||
break; |
||||
case 2: |
||||
for (i = 0; i != cStride; i++) { |
||||
((sox_int32_t*)pPriv->pOutput)[i] = |
||||
lsx_swapdw(SOX_SAMPLE_TO_SIGNED_32BIT(pInput[i], cClips)); |
||||
} |
||||
break; |
||||
} |
||||
} else { |
||||
switch (pPriv->sample_shift) |
||||
{ |
||||
case 0: |
||||
for (i = 0; i != cStride; i++) { |
||||
((sox_uint8_t*)pPriv->pOutput)[i] = |
||||
SOX_SAMPLE_TO_UNSIGNED_8BIT(pInput[i], cClips); |
||||
} |
||||
break; |
||||
case 1: |
||||
for (i = 0; i != cStride; i++) { |
||||
((sox_int16_t*)pPriv->pOutput)[i] = |
||||
SOX_SAMPLE_TO_SIGNED_16BIT(pInput[i], cClips); |
||||
} |
||||
break; |
||||
case 2: |
||||
for (i = 0; i != cStride; i++) { |
||||
((sox_int32_t*)pPriv->pOutput)[i] = |
||||
SOX_SAMPLE_TO_SIGNED_32BIT(pInput[i], cClips); |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
|
||||
cbStride = cStride << pPriv->sample_shift; |
||||
i = 0; |
||||
do { |
||||
cbWritten = write(pPriv->device, &pPriv->pOutput[i], cbStride - i); |
||||
i += cbWritten; |
||||
if (cbWritten <= 0) { |
||||
lsx_fail_errno(ft, errno, "Error writing to device"); |
||||
return 0; |
||||
} |
||||
} while (i != cbStride); |
||||
|
||||
cInputRemaining -= cStride; |
||||
pInput += cStride; |
||||
} |
||||
|
||||
return cInput; |
||||
} |
||||
|
||||
LSX_FORMAT_HANDLER(oss) |
||||
{ |
||||
static char const* const names[] = {"ossdsp", "oss", NULL}; |
||||
static unsigned const write_encodings[] = { |
||||
SOX_ENCODING_SIGN2, 32, 16, 0, |
||||
SOX_ENCODING_UNSIGNED, 8, 0, |
||||
0}; |
||||
static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, |
||||
"Open Sound System device driver for unix-like systems", |
||||
names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO, |
||||
ossinit, ossread, ossstop, |
||||
ossinit, osswrite, ossstop, |
||||
NULL, write_encodings, NULL, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,71 +0,0 @@ |
||||
/* libSoX effect: Overdrive (c) 2008 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
typedef struct { |
||||
double gain, colour, last_in, last_out, b0, b1, a1; |
||||
} priv_t; |
||||
|
||||
static int create(sox_effect_t * effp, int argc, char * * argv) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
--argc, ++argv; |
||||
p->gain = p->colour = 20; |
||||
do { |
||||
NUMERIC_PARAMETER(gain, 0, 100) |
||||
NUMERIC_PARAMETER(colour, 0, 100) |
||||
} while (0); |
||||
p->gain = dB_to_linear(p->gain); |
||||
p->colour /= 200; |
||||
return argc? lsx_usage(effp) : SOX_SUCCESS; |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
|
||||
if (p->gain == 1) |
||||
return SOX_EFF_NULL; |
||||
|
||||
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 dummy = 0, len = *isamp = *osamp = min(*isamp, *osamp); |
||||
while (len--) { |
||||
SOX_SAMPLE_LOCALS; |
||||
double d = SOX_SAMPLE_TO_FLOAT_64BIT(*ibuf++, dummy), d0 = d; |
||||
d *= p->gain; |
||||
d += p->colour; |
||||
d = d < -1? -2./3 : d > 1? 2./3 : d - d * d * d * (1./3); |
||||
p->last_out = d - p->last_in + .995 * p->last_out; |
||||
p->last_in = d; |
||||
*obuf++ = SOX_FLOAT_64BIT_TO_SAMPLE(d0 * .5 + p->last_out * .75, dummy); |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_overdrive_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = {"overdrive", "[gain [colour]]", |
||||
SOX_EFF_GAIN, create, start, flow, NULL, NULL, NULL, sizeof(priv_t)}; |
||||
return &handler; |
||||
} |
@ -1,180 +0,0 @@ |
||||
/* libSoX effect: Pad With Silence (c) 2006 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
typedef struct { |
||||
unsigned npads; /* Number of pads requested */ |
||||
struct { |
||||
char * str; /* Command-line argument to parse for this pad */ |
||||
uint64_t start; /* Start padding when in_pos equals this */ |
||||
uint64_t pad; /* Number of samples to pad */ |
||||
} * pads; |
||||
|
||||
uint64_t in_pos; /* Number of samples read from the input stream */ |
||||
unsigned pads_pos; /* Number of pads completed so far */ |
||||
uint64_t pad_pos; /* Number of samples through the current pad */ |
||||
} priv_t; |
||||
|
||||
static int parse(sox_effect_t * effp, char * * argv, sox_rate_t rate) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
char const * next; |
||||
unsigned i; |
||||
uint64_t last_seen = 0; |
||||
const uint64_t in_length = argv ? 0 : |
||||
(effp->in_signal.length != SOX_UNKNOWN_LEN ? |
||||
effp->in_signal.length / effp->in_signal.channels : SOX_UNKNOWN_LEN); |
||||
|
||||
for (i = 0; i < p->npads; ++i) { |
||||
if (argv) /* 1st parse only */ |
||||
p->pads[i].str = lsx_strdup(argv[i]); |
||||
next = lsx_parsesamples(rate, p->pads[i].str, &p->pads[i].pad, 't'); |
||||
if (next == NULL) break; |
||||
if (*next == '\0') |
||||
p->pads[i].start = i? UINT64_MAX : 0; |
||||
else { |
||||
if (*next != '@') break; |
||||
next = lsx_parseposition(rate, next+1, argv ? NULL : &p->pads[i].start, |
||||
last_seen, in_length, '='); |
||||
if (next == NULL || *next != '\0') break; |
||||
last_seen = p->pads[i].start; |
||||
if (p->pads[i].start == SOX_UNKNOWN_LEN) |
||||
p->pads[i].start = UINT64_MAX; /* currently the same value, but ... */ |
||||
} |
||||
if (!argv) { |
||||
/* Do this check only during the second pass when the actual
|
||||
sample rate is known, otherwise it might fail on legal |
||||
commands like |
||||
pad 1@0.5 1@30000s |
||||
if the rate is, e.g., 48k. */ |
||||
if (i > 0 && p->pads[i].start <= p->pads[i-1].start) break; |
||||
} |
||||
} |
||||
if (i < p->npads) |
||||
return lsx_usage(effp); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int create(sox_effect_t * effp, int argc, char * * argv) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
--argc, ++argv; |
||||
p->npads = argc; |
||||
p->pads = lsx_calloc(p->npads, sizeof(*p->pads)); |
||||
return parse(effp, argv, 1e5); /* No rate yet; parse with dummy */ |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
unsigned i; |
||||
|
||||
/* Re-parse now rate is known */ |
||||
if (parse(effp, 0, effp->in_signal.rate) != SOX_SUCCESS) |
||||
return SOX_EOF; |
||||
|
||||
if ((effp->out_signal.length = effp->in_signal.length) != SOX_UNKNOWN_LEN) { |
||||
for (i = 0; i < p->npads; ++i) |
||||
effp->out_signal.length += |
||||
p->pads[i].pad * effp->in_signal.channels; |
||||
|
||||
/* Check that the last pad position (except for "at the end")
|
||||
is within bounds. */ |
||||
i = p->npads; |
||||
if (i > 0 && p->pads[i-1].start == UINT64_MAX) |
||||
i--; |
||||
if (i > 0 && |
||||
p->pads[i-1].start * effp->in_signal.channels |
||||
> effp->in_signal.length) |
||||
{ |
||||
lsx_fail("pad position after end of audio"); |
||||
return SOX_EOF; |
||||
} |
||||
} |
||||
|
||||
p->in_pos = p->pad_pos = p->pads_pos = 0; |
||||
for (i = 0; i < p->npads; ++i) |
||||
if (p->pads[i].pad) |
||||
return SOX_SUCCESS; |
||||
return SOX_EFF_NULL; |
||||
} |
||||
|
||||
static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, |
||||
sox_sample_t * obuf, size_t * isamp, size_t * osamp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
size_t c, idone = 0, odone = 0; |
||||
*isamp /= effp->in_signal.channels; |
||||
*osamp /= effp->in_signal.channels; |
||||
|
||||
do { |
||||
/* Copying: */ |
||||
for (; idone < *isamp && odone < *osamp && !(p->pads_pos != p->npads && p->in_pos == p->pads[p->pads_pos].start); ++idone, ++odone, ++p->in_pos) |
||||
for (c = 0; c < effp->in_signal.channels; ++c) *obuf++ = *ibuf++; |
||||
|
||||
/* Padding: */ |
||||
if (p->pads_pos != p->npads && p->in_pos == p->pads[p->pads_pos].start) { |
||||
for (; odone < *osamp && p->pad_pos < p->pads[p->pads_pos].pad; ++odone, ++p->pad_pos) |
||||
for (c = 0; c < effp->in_signal.channels; ++c) *obuf++ = 0; |
||||
if (p->pad_pos == p->pads[p->pads_pos].pad) { /* Move to next pad? */ |
||||
++p->pads_pos; |
||||
p->pad_pos = 0; |
||||
} |
||||
} |
||||
} while (idone < *isamp && odone < *osamp); |
||||
|
||||
*isamp = idone * effp->in_signal.channels; |
||||
*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; |
||||
if (p->pads_pos != p->npads && p->in_pos != p->pads[p->pads_pos].start) |
||||
p->in_pos = UINT64_MAX; /* Invoke the final pad (with no given start) */ |
||||
return flow(effp, 0, obuf, &isamp, osamp); |
||||
} |
||||
|
||||
static int stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
if (p->pads_pos != p->npads) |
||||
lsx_warn("Input audio too short; pads not applied: %u", p->npads-p->pads_pos); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int lsx_kill(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
unsigned i; |
||||
for (i = 0; i < p->npads; ++i) |
||||
free(p->pads[i].str); |
||||
free(p->pads); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_pad_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"pad", "{length[@position]}", SOX_EFF_MCHAN|SOX_EFF_LENGTH|SOX_EFF_MODIFY, |
||||
create, start, flow, drain, stop, lsx_kill, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,31 +0,0 @@ |
||||
/* libSoX file format: PAF Copyright (c) 2008 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
LSX_FORMAT_HANDLER(paf) |
||||
{ |
||||
static char const * const names[] = {"paf", NULL}; |
||||
static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 24, 16, 8,0,0}; |
||||
static sox_format_handler_t handler; |
||||
handler = *lsx_sndfile_format_fn(); |
||||
handler.description = |
||||
"Ensoniq PARIS digital audio editing system (big endian)"; |
||||
handler.names = names; |
||||
handler.write_formats = write_encodings; |
||||
return &handler; |
||||
} |
@ -1,147 +0,0 @@ |
||||
/* Effect: phaser 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: August 24, 1998 |
||||
* |
||||
* * gain-in +---+ * gain-out |
||||
* ibuff ----------->| |----------------------------------> obuff |
||||
* | + | * decay |
||||
* | |<------------+ |
||||
* +---+ _______ | |
||||
* | | | | |
||||
* +---| delay |---+ |
||||
* |_______| |
||||
* /|\
|
||||
* | |
||||
* +---------------+ +------------------+ |
||||
* | Delay control |<-----| modulation speed | |
||||
* +---------------+ +------------------+ |
||||
* |
||||
* The delay is controled by a sine or triangle modulation. |
||||
* |
||||
* Usage: |
||||
* phaser gain-in gain-out delay decay speed [ -s | -t ] |
||||
* |
||||
* Where: |
||||
* gain-in, decay : 0.0 .. 1.0 volume |
||||
* gain-out : 0.0 .. volume |
||||
* delay : 0.0 .. 5.0 msec |
||||
* speed : 0.1 .. 2.0 Hz modulation speed |
||||
* -s : modulation by sine (default) |
||||
* -t : modulation by triangle |
||||
* |
||||
* Note: |
||||
* When decay is close to 1.0, the samples may begin clipping or the output |
||||
* can saturate! Hint: |
||||
* in-gain < (1 - decay * decay) |
||||
* 1 / out-gain > gain-in / (1 - decay) |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include <string.h> |
||||
|
||||
typedef struct { |
||||
double in_gain, out_gain, delay_ms, decay, mod_speed; |
||||
lsx_wave_t mod_type; |
||||
|
||||
int * mod_buf; |
||||
size_t mod_buf_len; |
||||
int mod_pos; |
||||
|
||||
double * delay_buf; |
||||
size_t delay_buf_len; |
||||
int delay_pos; |
||||
} priv_t; |
||||
|
||||
static int getopts(sox_effect_t * effp, int argc, char * * argv) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
char chars[2]; |
||||
|
||||
/* Set non-zero defaults: */ |
||||
p->in_gain = .4; |
||||
p->out_gain = .74; |
||||
p->delay_ms = 3.; |
||||
p->decay = .4; |
||||
p->mod_speed = .5; |
||||
|
||||
--argc, ++argv; |
||||
do { /* break-able block */ |
||||
NUMERIC_PARAMETER(in_gain , .0, 1) |
||||
NUMERIC_PARAMETER(out_gain , .0, 1e9) |
||||
NUMERIC_PARAMETER(delay_ms , .0, 5) |
||||
NUMERIC_PARAMETER(decay , .0, .99) |
||||
NUMERIC_PARAMETER(mod_speed, .1, 2) |
||||
} while (0); |
||||
|
||||
if (argc && sscanf(*argv, "-%1[st]%c", chars, chars + 1) == 1) { |
||||
p->mod_type = *chars == 's'? SOX_WAVE_SINE : SOX_WAVE_TRIANGLE; |
||||
--argc, ++argv; |
||||
} |
||||
|
||||
if (p->in_gain > (1 - p->decay * p->decay)) |
||||
lsx_warn("warning: gain-in might cause clipping"); |
||||
if (p->in_gain / (1 - p->decay) > 1 / p->out_gain) |
||||
lsx_warn("warning: gain-out might cause clipping"); |
||||
|
||||
return argc? lsx_usage(effp) : SOX_SUCCESS; |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
|
||||
p->delay_buf_len = p->delay_ms * .001 * effp->in_signal.rate + .5; |
||||
p->delay_buf = lsx_calloc(p->delay_buf_len, sizeof(*p->delay_buf)); |
||||
|
||||
p->mod_buf_len = effp->in_signal.rate / p->mod_speed + .5; |
||||
p->mod_buf = lsx_malloc(p->mod_buf_len * sizeof(*p->mod_buf)); |
||||
lsx_generate_wave_table(p->mod_type, SOX_INT, p->mod_buf, p->mod_buf_len, |
||||
1., (double)p->delay_buf_len, M_PI_2); |
||||
|
||||
p->delay_pos = p->mod_pos = 0; |
||||
|
||||
effp->out_signal.length = SOX_UNKNOWN_LEN; /* TODO: calculate actual length */ |
||||
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); |
||||
|
||||
while (len--) { |
||||
double d = *ibuf++ * p->in_gain + p->delay_buf[ |
||||
(p->delay_pos + p->mod_buf[p->mod_pos]) % p->delay_buf_len] * p->decay; |
||||
p->mod_pos = (p->mod_pos + 1) % p->mod_buf_len; |
||||
|
||||
p->delay_pos = (p->delay_pos + 1) % p->delay_buf_len; |
||||
p->delay_buf[p->delay_pos] = d; |
||||
|
||||
*obuf++ = SOX_ROUND_CLIP_COUNT(d * p->out_gain, effp->clips); |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
|
||||
free(p->delay_buf); |
||||
free(p->mod_buf); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_phaser_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"phaser", "gain-in gain-out delay decay speed [ -s | -t ]", |
||||
SOX_EFF_LENGTH | SOX_EFF_GAIN, getopts, start, flow, NULL, stop, NULL, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,172 +0,0 @@ |
||||
/* Pulse Audio sound handler
|
||||
* |
||||
* Copyright 2008 Chris Bagwell And Sundry Contributors |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
#include <pulse/simple.h> |
||||
#include <pulse/error.h> |
||||
|
||||
typedef struct { |
||||
pa_simple *pasp; |
||||
} priv_t; |
||||
|
||||
static int setup(sox_format_t *ft, int is_input) |
||||
{ |
||||
priv_t *pa = (priv_t *)ft->priv; |
||||
char *server; |
||||
pa_stream_direction_t dir; |
||||
char *app_str; |
||||
char *dev; |
||||
pa_sample_spec spec; |
||||
int error; |
||||
|
||||
/* TODO: If user specified device of type "server:dev" then
|
||||
* break up and override server. |
||||
*/ |
||||
server = NULL; |
||||
|
||||
if (is_input) |
||||
{ |
||||
dir = PA_STREAM_RECORD; |
||||
app_str = "record"; |
||||
} |
||||
else |
||||
{ |
||||
dir = PA_STREAM_PLAYBACK; |
||||
app_str = "playback"; |
||||
} |
||||
|
||||
if (strncmp(ft->filename, "default", (size_t)7) == 0) |
||||
dev = NULL; |
||||
else |
||||
dev = ft->filename; |
||||
|
||||
/* If user doesn't specify, default to some reasonable values.
|
||||
* Since this is mainly for recording case, default to typical |
||||
* 16-bit values to prevent saving larger files then average user |
||||
* wants. Power users can override to 32-bit if they wish. |
||||
*/ |
||||
if (ft->signal.channels == 0) |
||||
ft->signal.channels = 2; |
||||
if (ft->signal.rate == 0) |
||||
ft->signal.rate = 44100; |
||||
if (ft->encoding.bits_per_sample == 0) |
||||
{ |
||||
ft->encoding.bits_per_sample = 16; |
||||
ft->encoding.encoding = SOX_ENCODING_SIGN2; |
||||
} |
||||
|
||||
spec.format = PA_SAMPLE_S32NE; |
||||
spec.rate = ft->signal.rate; |
||||
spec.channels = ft->signal.channels; |
||||
|
||||
pa->pasp = pa_simple_new(server, "SoX", dir, dev, app_str, &spec, |
||||
NULL, NULL, &error); |
||||
|
||||
if (pa->pasp == NULL) |
||||
{ |
||||
lsx_fail_errno(ft, SOX_EPERM, "can not open audio device: %s", pa_strerror(error)); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
/* TODO: Is it better to convert format/rates in SoX or in
|
||||
* always let Pulse Audio do it? Since we don't know what |
||||
* hardware prefers, assume it knows best and give it |
||||
* what user specifies. |
||||
*/ |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int startread(sox_format_t *ft) |
||||
{ |
||||
return setup(ft, 1); |
||||
} |
||||
|
||||
static int stopread(sox_format_t * ft) |
||||
{ |
||||
priv_t *pa = (priv_t *)ft->priv; |
||||
|
||||
pa_simple_free(pa->pasp); |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static size_t read_samples(sox_format_t *ft, sox_sample_t *buf, size_t nsamp) |
||||
{ |
||||
priv_t *pa = (priv_t *)ft->priv; |
||||
size_t len; |
||||
int rc, error; |
||||
|
||||
/* Pulse Audio buffer lengths are true buffer lengths and not
|
||||
* count of samples. */ |
||||
len = nsamp * sizeof(sox_sample_t); |
||||
|
||||
rc = pa_simple_read(pa->pasp, buf, len, &error); |
||||
|
||||
if (rc < 0) |
||||
{ |
||||
lsx_fail_errno(ft, SOX_EPERM, "error reading from pulse audio device: %s", pa_strerror(error)); |
||||
return SOX_EOF; |
||||
} |
||||
else |
||||
return nsamp; |
||||
} |
||||
|
||||
static int startwrite(sox_format_t * ft) |
||||
{ |
||||
return setup(ft, 0); |
||||
} |
||||
|
||||
static size_t write_samples(sox_format_t *ft, const sox_sample_t *buf, size_t nsamp) |
||||
{ |
||||
priv_t *pa = (priv_t *)ft->priv; |
||||
size_t len; |
||||
int rc, error; |
||||
|
||||
if (!nsamp) |
||||
return 0; |
||||
|
||||
/* Pulse Audio buffer lengths are true buffer lengths and not
|
||||
* count of samples. */ |
||||
len = nsamp * sizeof(sox_sample_t); |
||||
|
||||
rc = pa_simple_write(pa->pasp, buf, len, &error); |
||||
|
||||
if (rc < 0) |
||||
{ |
||||
lsx_fail_errno(ft, SOX_EPERM, "error writing to pulse audio device: %s", pa_strerror(error)); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
return nsamp; |
||||
} |
||||
|
||||
static int stopwrite(sox_format_t * ft) |
||||
{ |
||||
priv_t *pa = (priv_t *)ft->priv; |
||||
int error; |
||||
|
||||
pa_simple_drain(pa->pasp, &error); |
||||
pa_simple_free(pa->pasp); |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
LSX_FORMAT_HANDLER(pulseaudio) |
||||
{ |
||||
static char const *const names[] = { "pulseaudio", NULL }; |
||||
static unsigned const write_encodings[] = { |
||||
SOX_ENCODING_SIGN2, 32, 0, |
||||
0}; |
||||
static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, |
||||
"Pulse Audio client", |
||||
names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO, |
||||
startread, read_samples, stopread, |
||||
startwrite, write_samples, stopwrite, |
||||
NULL, write_encodings, NULL, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,30 +0,0 @@ |
||||
/* libSoX file format: PVF Copyright (c) 2008 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
LSX_FORMAT_HANDLER(pvf) |
||||
{ |
||||
static char const * const names[] = {"pvf", NULL}; |
||||
static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 32, 16, 8,0,0}; |
||||
static sox_format_handler_t handler; |
||||
handler = *lsx_sndfile_format_fn(); |
||||
handler.description = "Portable Voice Format"; |
||||
handler.names = names; |
||||
handler.write_formats = write_encodings; |
||||
return &handler; |
||||
} |
@ -1,712 +0,0 @@ |
||||
/* Effect: change sample rate Copyright (c) 2008,12 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 |
||||
*/ |
||||
|
||||
/* Inspired by, and builds upon some of the ideas presented in:
|
||||
* `The Quest For The Perfect Resampler' by Laurent De Soras; |
||||
* http://ldesoras.free.fr/doc/articles/resampler-en.pdf */
|
||||
|
||||
#ifdef NDEBUG /* Enable assert always. */ |
||||
#undef NDEBUG /* Must undef above assert.h or other that might include it. */ |
||||
#endif |
||||
|
||||
#define _GNU_SOURCE |
||||
#include "sox_i.h" |
||||
#include "fft4g.h" |
||||
#include "dft_filter.h" |
||||
#include <assert.h> |
||||
#include <string.h> |
||||
|
||||
#define calloc lsx_calloc |
||||
#define malloc lsx_malloc |
||||
#define raw_coef_t double |
||||
|
||||
#if 0 /* For float32 version, as used in foobar */
|
||||
#define sample_t float |
||||
#define num_coefs4 ((num_coefs + 3) & ~3) /* align coefs for SSE */ |
||||
#define coefs4_check(i) ((i) < num_coefs) |
||||
#else |
||||
#define sample_t double |
||||
#define num_coefs4 num_coefs |
||||
#define coefs4_check(i) 1 |
||||
#endif |
||||
|
||||
#if defined M_PIl |
||||
#define hi_prec_clock_t long double /* __float128 is also a (slow) option */ |
||||
#else |
||||
#define hi_prec_clock_t double |
||||
#endif |
||||
|
||||
#define coef(coef_p, interp_order, fir_len, phase_num, coef_interp_num, fir_coef_num) coef_p[(fir_len) * ((interp_order) + 1) * (phase_num) + ((interp_order) + 1) * (fir_coef_num) + (interp_order - coef_interp_num)] |
||||
|
||||
static sample_t * prepare_coefs(raw_coef_t const * coefs, int num_coefs, |
||||
int num_phases, int interp_order, int multiplier) |
||||
{ |
||||
int i, j, length = num_coefs4 * num_phases; |
||||
sample_t * result = malloc(length * (interp_order + 1) * sizeof(*result)); |
||||
double fm1 = coefs[0], f1 = 0, f2 = 0; |
||||
|
||||
for (i = num_coefs4 - 1; i >= 0; --i) |
||||
for (j = num_phases - 1; j >= 0; --j) { |
||||
double f0 = fm1, b = 0, c = 0, d = 0; /* = 0 to kill compiler warning */ |
||||
int pos = i * num_phases + j - 1; |
||||
fm1 = coefs4_check(i) && pos > 0 ? coefs[pos - 1] * multiplier : 0; |
||||
switch (interp_order) { |
||||
case 1: b = f1 - f0; break; |
||||
case 2: b = f1 - (.5 * (f2+f0) - f1) - f0; c = .5 * (f2+f0) - f1; break; |
||||
case 3: c=.5*(f1+fm1)-f0;d=(1/6.)*(f2-f1+fm1-f0-4*c);b=f1-f0-d-c; break; |
||||
default: if (interp_order) assert(0); |
||||
} |
||||
#define coef_coef(x) \ |
||||
coef(result, interp_order, num_coefs4, j, x, num_coefs4 - 1 - i) |
||||
coef_coef(0) = f0; |
||||
if (interp_order > 0) coef_coef(1) = b; |
||||
if (interp_order > 1) coef_coef(2) = c; |
||||
if (interp_order > 2) coef_coef(3) = d; |
||||
#undef coef_coef |
||||
f2 = f1, f1 = f0; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
typedef struct { /* So generated filter coefs may be shared between channels */ |
||||
sample_t * poly_fir_coefs; |
||||
dft_filter_t dft_filter[2]; |
||||
} rate_shared_t; |
||||
|
||||
struct stage; |
||||
typedef void (* stage_fn_t)(struct stage * input, fifo_t * output); |
||||
typedef struct stage { |
||||
/* Common to all stage types: */ |
||||
stage_fn_t fn; |
||||
fifo_t fifo; |
||||
int pre; /* Number of past samples to store */ |
||||
int pre_post; /* pre + number of future samples to store */ |
||||
int preload; /* Number of zero samples to pre-load the fifo */ |
||||
double out_in_ratio; /* For buffer management. */ |
||||
|
||||
/* For a stage with variable (run-time generated) filter coefs: */ |
||||
rate_shared_t * shared; |
||||
int dft_filter_num; /* Which, if any, of the 2 DFT filters to use */ |
||||
|
||||
/* For a stage with variable L/M: */ |
||||
union { /* 32bit.32bit fixed point arithmetic */ |
||||
#if defined(WORDS_BIGENDIAN) |
||||
struct {int32_t integer; uint32_t fraction;} parts; |
||||
#else |
||||
struct {uint32_t fraction; int32_t integer;} parts; |
||||
#endif |
||||
int64_t all; |
||||
#define MULT32 (65536. * 65536.) |
||||
|
||||
hi_prec_clock_t hi_prec_clock; |
||||
} at, step; |
||||
sox_bool use_hi_prec_clock; |
||||
int L, remL, remM; |
||||
int n, phase_bits; |
||||
} stage_t; |
||||
|
||||
#define stage_occupancy(s) max(0, fifo_occupancy(&(s)->fifo) - (s)->pre_post) |
||||
#define stage_read_p(s) ((sample_t *)fifo_read_ptr(&(s)->fifo) + (s)->pre) |
||||
|
||||
static void cubic_stage_fn(stage_t * p, fifo_t * output_fifo) |
||||
{ |
||||
int i, num_in = stage_occupancy(p), max_num_out = 1 + num_in*p->out_in_ratio; |
||||
sample_t const * input = stage_read_p(p); |
||||
sample_t * output = fifo_reserve(output_fifo, max_num_out); |
||||
|
||||
for (i = 0; p->at.parts.integer < num_in; ++i, p->at.all += p->step.all) { |
||||
sample_t const * s = input + p->at.parts.integer; |
||||
sample_t x = p->at.parts.fraction * (1 / MULT32); |
||||
sample_t b = .5*(s[1]+s[-1])-*s, a = (1/6.)*(s[2]-s[1]+s[-1]-*s-4*b); |
||||
sample_t c = s[1]-*s-a-b; |
||||
output[i] = ((a*x + b)*x + c)*x + *s; |
||||
} |
||||
assert(max_num_out - i >= 0); |
||||
fifo_trim_by(output_fifo, max_num_out - i); |
||||
fifo_read(&p->fifo, p->at.parts.integer, NULL); |
||||
p->at.parts.integer = 0; |
||||
} |
||||
|
||||
static void dft_stage_fn(stage_t * p, fifo_t * output_fifo) |
||||
{ |
||||
sample_t * output, tmp; |
||||
int i, j, num_in = max(0, fifo_occupancy(&p->fifo)); |
||||
rate_shared_t const * s = p->shared; |
||||
dft_filter_t const * f = &s->dft_filter[p->dft_filter_num]; |
||||
int const overlap = f->num_taps - 1; |
||||
|
||||
while (p->remL + p->L * num_in >= f->dft_length) { |
||||
div_t divd = div(f->dft_length - overlap - p->remL + p->L - 1, p->L); |
||||
sample_t const * input = fifo_read_ptr(&p->fifo); |
||||
fifo_read(&p->fifo, divd.quot, NULL); |
||||
num_in -= divd.quot; |
||||
|
||||
output = fifo_reserve(output_fifo, f->dft_length); |
||||
if (lsx_is_power_of_2(p->L)) { /* F-domain */ |
||||
int portion = f->dft_length / p->L; |
||||
memcpy(output, input, (unsigned)portion * sizeof(*output)); |
||||
lsx_safe_rdft(portion, 1, output); |
||||
for (i = portion + 2; i < (portion << 1); i += 2) |
||||
output[i] = output[(portion << 1) - i], |
||||
output[i+1] = -output[(portion << 1) - i + 1]; |
||||
output[portion] = output[1]; |
||||
output[portion + 1] = 0; |
||||
output[1] = output[0]; |
||||
for (portion <<= 1; i < f->dft_length; i += portion, portion <<= 1) { |
||||
memcpy(output + i, output, portion * sizeof(*output)); |
||||
output[i + 1] = 0; |
||||
} |
||||
} else { |
||||
if (p->L == 1) |
||||
memcpy(output, input, f->dft_length * sizeof(*output)); |
||||
else { |
||||
memset(output, 0, f->dft_length * sizeof(*output)); |
||||
for (j = 0, i = p->remL; i < f->dft_length; ++j, i += p->L) |
||||
output[i] = input[j]; |
||||
p->remL = p->L - 1 - divd.rem; |
||||
} |
||||
lsx_safe_rdft(f->dft_length, 1, output); |
||||
} |
||||
output[0] *= f->coefs[0]; |
||||
if (p->step.parts.integer > 0) { |
||||
output[1] *= f->coefs[1]; |
||||
for (i = 2; i < f->dft_length; i += 2) { |
||||
tmp = output[i]; |
||||
output[i ] = f->coefs[i ] * tmp - f->coefs[i+1] * output[i+1]; |
||||
output[i+1] = f->coefs[i+1] * tmp + f->coefs[i ] * output[i+1]; |
||||
} |
||||
lsx_safe_rdft(f->dft_length, -1, output); |
||||
if (p->step.parts.integer != 1) { |
||||
for (j = 0, i = p->remM; i < f->dft_length - overlap; ++j, |
||||
i += p->step.parts.integer) |
||||
output[j] = output[i]; |
||||
p->remM = i - (f->dft_length - overlap); |
||||
fifo_trim_by(output_fifo, f->dft_length - j); |
||||
} |
||||
else fifo_trim_by(output_fifo, overlap); |
||||
} |
||||
else { /* F-domain */ |
||||
int m = -p->step.parts.integer; |
||||
for (i = 2; i < (f->dft_length >> m); i += 2) { |
||||
tmp = output[i]; |
||||
output[i ] = f->coefs[i ] * tmp - f->coefs[i+1] * output[i+1]; |
||||
output[i+1] = f->coefs[i+1] * tmp + f->coefs[i ] * output[i+1]; |
||||
} |
||||
output[1] = f->coefs[i] * output[i] - f->coefs[i+1] * output[i+1]; |
||||
lsx_safe_rdft(f->dft_length >> m, -1, output); |
||||
fifo_trim_by(output_fifo, (((1 << m) - 1) * f->dft_length + overlap) >>m); |
||||
} |
||||
} |
||||
} |
||||
|
||||
static void dft_stage_init( |
||||
unsigned instance, double Fp, double Fs, double Fn, double att, |
||||
double phase, stage_t * stage, int L, int M) |
||||
{ |
||||
dft_filter_t * f = &stage->shared->dft_filter[instance]; |
||||
|
||||
if (!f->num_taps) { |
||||
int num_taps = 0, dft_length, i; |
||||
int k = phase == 50 && lsx_is_power_of_2(L) && Fn == L? L << 1 : 4; |
||||
double * h = lsx_design_lpf(Fp, Fs, Fn, att, &num_taps, -k, -1.); |
||||
|
||||
if (phase != 50) |
||||
lsx_fir_to_phase(&h, &num_taps, &f->post_peak, phase); |
||||
else f->post_peak = num_taps / 2; |
||||
|
||||
dft_length = lsx_set_dft_length(num_taps); |
||||
f->coefs = calloc(dft_length, sizeof(*f->coefs)); |
||||
for (i = 0; i < num_taps; ++i) |
||||
f->coefs[(i + dft_length - num_taps + 1) & (dft_length - 1)] |
||||
= h[i] / dft_length * 2 * L; |
||||
free(h); |
||||
f->num_taps = num_taps; |
||||
f->dft_length = dft_length; |
||||
lsx_safe_rdft(dft_length, 1, f->coefs); |
||||
lsx_debug("fir_len=%i dft_length=%i Fp=%g Fs=%g Fn=%g att=%g %i/%i", |
||||
num_taps, dft_length, Fp, Fs, Fn, att, L, M); |
||||
} |
||||
stage->fn = dft_stage_fn; |
||||
stage->preload = f->post_peak / L; |
||||
stage->remL = f->post_peak % L; |
||||
stage->L = L; |
||||
stage->step.parts.integer = abs(3-M) == 1 && Fs == 1? -M/2 : M; |
||||
stage->dft_filter_num = instance; |
||||
} |
||||
|
||||
#include "rate_filters.h" |
||||
|
||||
typedef struct { |
||||
double factor; |
||||
uint64_t samples_in, samples_out; |
||||
int num_stages; |
||||
stage_t * stages; |
||||
} rate_t; |
||||
|
||||
#define pre_stage p->stages[shift] |
||||
#define arb_stage p->stages[shift + have_pre_stage] |
||||
#define post_stage p->stages[shift + have_pre_stage + have_arb_stage] |
||||
#define have_pre_stage (preM * preL != 1) |
||||
#define have_arb_stage (arbM * arbL != 1) |
||||
#define have_post_stage (postM * postL != 1) |
||||
|
||||
#define TO_3dB(a) ((1.6e-6*a-7.5e-4)*a+.646) |
||||
#define LOW_Q_BW0_PC (67 + 5 / 8.) |
||||
|
||||
typedef enum { |
||||
rolloff_none, rolloff_small /* <= 0.01 dB */, rolloff_medium /* <= 0.35 dB */ |
||||
} rolloff_t; |
||||
|
||||
static void rate_init( |
||||
/* Private work areas (to be supplied by the client): */ |
||||
rate_t * p, /* Per audio channel. */ |
||||
rate_shared_t * shared, /* Between channels (undergoing same rate change)*/ |
||||
|
||||
/* Public parameters: Typically */ |
||||
double factor, /* Input rate divided by output rate. */ |
||||
double bits, /* Required bit-accuracy (pass + stop) 16|20|28 */ |
||||
double phase, /* Linear/minimum etc. filter phase. 50 */ |
||||
double bw_pc, /* Pass-band % (0dB pt.) to preserve. 91.3|98.4*/ |
||||
double anti_aliasing_pc, /* % bandwidth without aliasing 100 */ |
||||
rolloff_t rolloff, /* Pass-band roll-off small */ |
||||
sox_bool maintain_3dB_pt, /* true */ |
||||
|
||||
/* Primarily for test/development purposes: */ |
||||
sox_bool use_hi_prec_clock,/* Increase irrational ratio accuracy. false */ |
||||
int interpolator, /* Force a particular coef interpolator. -1 */ |
||||
int max_coefs_size, /* k bytes of coefs to try to keep below. 400 */ |
||||
sox_bool noSmallIntOpt) /* Disable small integer optimisations. false */ |
||||
{ |
||||
double att = (bits + 1) * linear_to_dB(2.), attArb = att; /* pass + stop */ |
||||
double tbw0 = 1 - bw_pc / 100, Fs_a = 2 - anti_aliasing_pc / 100; |
||||
double arbM = factor, tbw_tighten = 1; |
||||
int n = 0, i, preL = 1, preM = 1, shift = 0, arbL = 1, postL = 1, postM = 1; |
||||
sox_bool upsample = sox_false, rational = sox_false, iOpt = !noSmallIntOpt; |
||||
int mode = rolloff > rolloff_small? factor > 1 || bw_pc > LOW_Q_BW0_PC : |
||||
ceil(2 + (bits - 17) / 4); |
||||
stage_t * s; |
||||
|
||||
assert(factor > 0); |
||||
assert(!bits || (15 <= bits && bits <= 33)); |
||||
assert(0 <= phase && phase <= 100); |
||||
assert(53 <= bw_pc && bw_pc <= 100); |
||||
assert(85 <= anti_aliasing_pc && anti_aliasing_pc <= 100); |
||||
|
||||
p->factor = factor; |
||||
if (bits) while (!n++) { /* Determine stages: */ |
||||
int try, L, M, x, maxL = interpolator > 0? 1 : mode? 2048 : |
||||
ceil(max_coefs_size * 1000. / (U100_l * sizeof(sample_t))); |
||||
double d, epsilon = 0, frac; |
||||
upsample = arbM < 1; |
||||
for (i = arbM * .5, shift = 0; i >>= 1; arbM *= .5, ++shift); |
||||
preM = upsample || (arbM > 1.5 && arbM < 2); |
||||
postM = 1 + (arbM > 1 && preM), arbM /= postM; |
||||
preL = 1 + (!preM && arbM < 2) + (upsample && mode), arbM *= preL; |
||||
if ((frac = arbM - (int)arbM)) |
||||
epsilon = fabs((uint32_t)(frac * MULT32 + .5) / (frac * MULT32) - 1); |
||||
for (i = 1, rational = !frac; i <= maxL && !rational; ++i) { |
||||
d = frac * i, try = d + .5; |
||||
if ((rational = fabs(try / d - 1) <= epsilon)) { /* No long doubles! */ |
||||
if (try == i) |
||||
arbM = ceil(arbM), shift += arbM > 2, arbM /= 1 + (arbM > 2); |
||||
else arbM = i * (int)arbM + try, arbL = i; |
||||
} |
||||
} |
||||
L = preL * arbL, M = arbM * postM, x = (L|M)&1, L >>= !x, M >>= !x; |
||||
if (iOpt && postL == 1 && (d = preL * arbL / arbM) > 4 && d != 5) { |
||||
for (postL = 4, i = d / 16; i >>= 1; postL <<= 1); |
||||
arbM = arbM * postL / arbL / preL, arbL = 1, n = 0; |
||||
} else if (rational && (max(L, M) < 3 + 2 * iOpt || L * M < 6 * iOpt)) |
||||
preL = L, preM = M, arbM = arbL = postM = 1; |
||||
if (!mode && (!rational || !n)) |
||||
++mode, n = 0; |
||||
} |
||||
|
||||
p->num_stages = shift + have_pre_stage + have_arb_stage + have_post_stage; |
||||
|
||||
if (!p->num_stages) |
||||
return; |
||||
|
||||
p->stages = calloc(p->num_stages + 1, sizeof(*p->stages)); |
||||
for (i = 0; i < p->num_stages; ++i) |
||||
p->stages[i].shared = shared; |
||||
|
||||
if ((n = p->num_stages) > 1) { /* Att. budget: */ |
||||
if (have_arb_stage) |
||||
att += linear_to_dB(2.), attArb = att, --n;
|
||||
att += linear_to_dB((double)n); |
||||
} |
||||
|
||||
for (n = 0; n + 1u < array_length(half_firs) && att > half_firs[n].att; ++n); |
||||
for (i = 0, s = p->stages; i < shift; ++i, ++s) { |
||||
s->fn = half_firs[n].fn; |
||||
s->pre_post = 4 * half_firs[n].num_coefs; |
||||
s->preload = s->pre = s->pre_post >> 1; |
||||
} |
||||
|
||||
if (have_pre_stage) { |
||||
if (maintain_3dB_pt && have_post_stage) { /* Trans. bands overlapping. */ |
||||
double tbw3 = tbw0 * TO_3dB(att); /* TODO: consider Fs_a. */ |
||||
double x = ((2.1429e-4 - 5.2083e-7 * att) * att - .015863) * att + 3.95; |
||||
x = att * pow((tbw0 - tbw3) / (postM / (factor * postL) - 1 + tbw0), x); |
||||
if (x > .035) { |
||||
tbw_tighten = ((4.3074e-3 - 3.9121e-4 * x) * x - .040009) * x + 1.0014; |
||||
lsx_debug("x=%g tbw_tighten=%g", x, tbw_tighten); |
||||
} |
||||
} |
||||
dft_stage_init(0, 1 - tbw0 * tbw_tighten, Fs_a, preM? max(preL, preM) : |
||||
arbM / arbL, att, phase, &pre_stage, preL, max(preM, 1)); |
||||
} |
||||
|
||||
if (!bits) { /* Quick and dirty arb stage: */ |
||||
arb_stage.fn = cubic_stage_fn; |
||||
arb_stage.step.all = arbM * MULT32 + .5; |
||||
arb_stage.pre_post = max(3, arb_stage.step.parts.integer); |
||||
arb_stage.preload = arb_stage.pre = 1; |
||||
arb_stage.out_in_ratio = MULT32 * arbL / arb_stage.step.all; |
||||
} |
||||
else if (have_arb_stage) { /* Higher quality arb stage: */ |
||||
poly_fir_t const * f = &poly_firs[6*(upsample + !!preM) + mode - !upsample]; |
||||
int order, num_coefs = f->interp[0].scalar, phase_bits, phases, coefs_size; |
||||
double x = .5, at, Fp, Fs, Fn, mult = upsample? 1 : arbL / arbM; |
||||
poly_fir1_t const * f1; |
||||
|
||||
Fn = !upsample && preM? x = arbM / arbL : 1; |
||||
Fp = !preM? mult : mode? .5 : 1; |
||||
Fs = 2 - Fp; /* Ignore Fs_a; it would have little benefit here. */ |
||||
Fp *= 1 - tbw0; |
||||
if (rolloff > rolloff_small && mode) |
||||
Fp = !preM? mult * .5 - .125 : mult * .05 + .1; |
||||
else if (rolloff == rolloff_small) |
||||
Fp = Fs - (Fs - .148 * x - Fp * .852) * (.00813 * bits + .973); |
||||
|
||||
i = (interpolator < 0? !rational : max(interpolator, !rational)) - 1; |
||||
do { |
||||
f1 = &f->interp[++i]; |
||||
assert(f1->fn); |
||||
if (i) |
||||
arbM /= arbL, arbL = 1, rational = sox_false; |
||||
phase_bits = ceil(f1->scalar + log(mult)/log(2.)); |
||||
phases = !rational? (1 << phase_bits) : arbL; |
||||
if (!f->interp[0].scalar) { |
||||
int phases0 = max(phases, 19), n0 = 0; |
||||
lsx_design_lpf(Fp, Fs, -Fn, attArb, &n0, phases0, f->beta); |
||||
num_coefs = n0 / phases0 + 1, num_coefs += num_coefs & !preM; |
||||
} |
||||
if ((num_coefs & 1) && rational && (arbL & 1)) |
||||
phases <<= 1, arbL <<= 1, arbM *= 2; |
||||
at = arbL * .5 * (num_coefs & 1); |
||||
order = i + (i && mode > 4); |
||||
coefs_size = num_coefs4 * phases * (order + 1) * sizeof(sample_t); |
||||
} while (interpolator < 0 && i < 2 && f->interp[i+1].fn && |
||||
coefs_size / 1000 > max_coefs_size); |
||||
|
||||
if (!arb_stage.shared->poly_fir_coefs) { |
||||
int num_taps = num_coefs * phases - 1; |
||||
raw_coef_t * coefs = lsx_design_lpf( |
||||
Fp, Fs, Fn, attArb, &num_taps, phases, f->beta); |
||||
arb_stage.shared->poly_fir_coefs = prepare_coefs( |
||||
coefs, num_coefs, phases, order, 1); |
||||
lsx_debug("fir_len=%i phases=%i coef_interp=%i size=%s", |
||||
num_coefs, phases, order, lsx_sigfigs3((double)coefs_size)); |
||||
free(coefs); |
||||
} |
||||
arb_stage.fn = f1->fn; |
||||
arb_stage.pre_post = num_coefs4 - 1; |
||||
arb_stage.preload = (num_coefs - 1) >> 1; |
||||
arb_stage.n = num_coefs4; |
||||
arb_stage.phase_bits = phase_bits; |
||||
arb_stage.L = arbL; |
||||
arb_stage.use_hi_prec_clock = mode > 1 && use_hi_prec_clock && !rational; |
||||
if (arb_stage.use_hi_prec_clock) { |
||||
arb_stage.at.hi_prec_clock = at; |
||||
arb_stage.step.hi_prec_clock = arbM; |
||||
arb_stage.out_in_ratio = arbL / arb_stage.step.hi_prec_clock; |
||||
} else { |
||||
arb_stage.at.all = at * MULT32 + .5; |
||||
arb_stage.step.all = arbM * MULT32 + .5; |
||||
arb_stage.out_in_ratio = MULT32 * arbL / arb_stage.step.all; |
||||
} |
||||
} |
||||
|
||||
if (have_post_stage) |
||||
dft_stage_init(1, 1 - (1 - (1 - tbw0) * |
||||
(upsample? factor * postL / postM : 1)) * tbw_tighten, Fs_a, |
||||
(double)max(postL, postM), att, phase, &post_stage, postL, postM); |
||||
|
||||
for (i = 0, s = p->stages; i < p->num_stages; ++i, ++s) { |
||||
fifo_create(&s->fifo, (int)sizeof(sample_t)); |
||||
memset(fifo_reserve(&s->fifo, s->preload), 0, sizeof(sample_t)*s->preload); |
||||
lsx_debug("%5i|%-5i preload=%i remL=%i", |
||||
s->pre, s->pre_post - s->pre, s->preload, s->remL); |
||||
} |
||||
fifo_create(&s->fifo, (int)sizeof(sample_t)); |
||||
} |
||||
|
||||
static void rate_process(rate_t * p) |
||||
{ |
||||
stage_t * stage = p->stages; |
||||
int i; |
||||
|
||||
for (i = 0; i < p->num_stages; ++i, ++stage) |
||||
stage->fn(stage, &(stage+1)->fifo); |
||||
} |
||||
|
||||
static sample_t * rate_input(rate_t * p, sample_t const * samples, size_t n) |
||||
{ |
||||
p->samples_in += n; |
||||
return fifo_write(&p->stages[0].fifo, (int)n, samples); |
||||
} |
||||
|
||||
static sample_t const * rate_output(rate_t * p, sample_t * samples, size_t * n) |
||||
{ |
||||
fifo_t * fifo = &p->stages[p->num_stages].fifo; |
||||
p->samples_out += *n = min(*n, (size_t)fifo_occupancy(fifo)); |
||||
return fifo_read(fifo, (int)*n, samples); |
||||
} |
||||
|
||||
static void rate_flush(rate_t * p) |
||||
{ |
||||
fifo_t * fifo = &p->stages[p->num_stages].fifo; |
||||
uint64_t samples_out = p->samples_in / p->factor + .5; |
||||
size_t remaining = samples_out > p->samples_out ? |
||||
(size_t)(samples_out - p->samples_out) : 0; |
||||
sample_t * buff = calloc(1024, sizeof(*buff)); |
||||
|
||||
if (remaining > 0) { |
||||
while ((size_t)fifo_occupancy(fifo) < remaining) { |
||||
rate_input(p, buff, (size_t) 1024); |
||||
rate_process(p); |
||||
} |
||||
fifo_trim_to(fifo, (int)remaining); |
||||
p->samples_in = 0; |
||||
} |
||||
free(buff); |
||||
} |
||||
|
||||
static void rate_close(rate_t * p) |
||||
{ |
||||
rate_shared_t *shared; |
||||
int i; |
||||
|
||||
if (!p->num_stages) |
||||
return; |
||||
|
||||
shared = p->stages[0].shared; |
||||
|
||||
for (i = 0; i <= p->num_stages; ++i) |
||||
fifo_delete(&p->stages[i].fifo); |
||||
free(shared->dft_filter[0].coefs); |
||||
free(shared->dft_filter[1].coefs); |
||||
free(shared->poly_fir_coefs); |
||||
memset(shared, 0, sizeof(*shared)); |
||||
free(p->stages); |
||||
} |
||||
|
||||
/*------------------------------- SoX Wrapper --------------------------------*/ |
||||
|
||||
typedef struct { |
||||
sox_rate_t out_rate; |
||||
int rolloff, coef_interp, max_coefs_size; |
||||
double bit_depth, phase, bw_0dB_pc, anti_aliasing_pc; |
||||
sox_bool use_hi_prec_clock, noIOpt, given_0dB_pt; |
||||
rate_t rate; |
||||
rate_shared_t shared, * shared_ptr; |
||||
} priv_t; |
||||
|
||||
static int create(sox_effect_t * effp, int argc, char **argv) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
int c, quality; |
||||
char * dummy_p, * found_at; |
||||
char const * opts = "+i:c:b:B:A:p:Q:R:d:MILafnost" "qlmghevu"; |
||||
char const * qopts = strchr(opts, 'q'); |
||||
double rej = 0, bw_3dB_pc = 0; |
||||
sox_bool allow_aliasing = sox_false; |
||||
lsx_getopt_t optstate; |
||||
lsx_getopt_init(argc, argv, opts, NULL, lsx_getopt_flag_none, 1, &optstate); |
||||
|
||||
p->coef_interp = quality = -1; |
||||
p->rolloff = rolloff_small; |
||||
p->phase = 50; |
||||
p->max_coefs_size = 400; |
||||
p->shared_ptr = &p->shared; |
||||
|
||||
while ((c = lsx_getopt(&optstate)) != -1) switch (c) { |
||||
GETOPT_NUMERIC(optstate, 'i', coef_interp, -1, 2) |
||||
GETOPT_NUMERIC(optstate, 'c', max_coefs_size, 100, INT_MAX) |
||||
GETOPT_NUMERIC(optstate, 'p', phase, 0, 100) |
||||
GETOPT_NUMERIC(optstate, 'B', bw_0dB_pc, 53, 99.5) |
||||
GETOPT_NUMERIC(optstate, 'A', anti_aliasing_pc, 85, 100) |
||||
GETOPT_NUMERIC(optstate, 'd', bit_depth, 15, 33) |
||||
GETOPT_LOCAL_NUMERIC(optstate, 'b', bw_3dB_pc, 74, 99.7) |
||||
GETOPT_LOCAL_NUMERIC(optstate, 'R', rej, 90, 200) |
||||
GETOPT_LOCAL_NUMERIC(optstate, 'Q', quality, 0, 7) |
||||
case 'M': p->phase = 0; break; |
||||
case 'I': p->phase = 25; break; |
||||
case 'L': p->phase = 50; break; |
||||
case 'a': allow_aliasing = sox_true; break; |
||||
case 'f': p->rolloff = rolloff_none; break; |
||||
case 'n': p->noIOpt = sox_true; break; |
||||
case 's': bw_3dB_pc = 99; break; |
||||
case 't': p->use_hi_prec_clock = sox_true; break; |
||||
default: |
||||
if ((found_at = strchr(qopts, c))) |
||||
quality = found_at - qopts; |
||||
else { |
||||
lsx_fail("unknown option `-%c'", optstate.opt); |
||||
return lsx_usage(effp); |
||||
} |
||||
} |
||||
argc -= optstate.ind, argv += optstate.ind; |
||||
|
||||
if ((unsigned)quality < 2 && (p->bw_0dB_pc || bw_3dB_pc || p->phase != 50 || |
||||
allow_aliasing || rej || p->bit_depth || p->anti_aliasing_pc)) { |
||||
lsx_fail("override options not allowed with this quality level"); |
||||
return SOX_EOF; |
||||
} |
||||
if (quality < 0 && rej == 0 && p->bit_depth == 0) |
||||
quality = 4; |
||||
if (rej) |
||||
p->bit_depth = rej / linear_to_dB(2.); |
||||
else { |
||||
if (quality >= 0) { |
||||
p->bit_depth = quality? 16 + 4 * max(quality - 3, 0) : 0; |
||||
if (quality <= 2) |
||||
p->rolloff = rolloff_medium; |
||||
} |
||||
rej = p->bit_depth * linear_to_dB(2.); |
||||
} |
||||
|
||||
if (bw_3dB_pc && p->bw_0dB_pc) { |
||||
lsx_fail("conflicting bandwidth options"); |
||||
return SOX_EOF; |
||||
} |
||||
allow_aliasing |= p->anti_aliasing_pc != 0; |
||||
if (!bw_3dB_pc && !p->bw_0dB_pc) |
||||
p->bw_0dB_pc = quality == 1? LOW_Q_BW0_PC : 100 - 5 / TO_3dB(rej); |
||||
else if (bw_3dB_pc && bw_3dB_pc < 85 && allow_aliasing) { |
||||
lsx_fail("minimum allowed 3dB bandwidth with aliasing is %g%%", 85.); |
||||
return SOX_EOF; |
||||
} |
||||
else if (p->bw_0dB_pc && p->bw_0dB_pc < 74 && allow_aliasing) { |
||||
lsx_fail("minimum allowed bandwidth with aliasing is %g%%", 74.); |
||||
return SOX_EOF; |
||||
} |
||||
if (bw_3dB_pc) |
||||
p->bw_0dB_pc = 100 - (100 - bw_3dB_pc) / TO_3dB(rej); |
||||
else { |
||||
bw_3dB_pc = 100 - (100 - p->bw_0dB_pc) * TO_3dB(rej); |
||||
p->given_0dB_pt = sox_true; |
||||
} |
||||
p->anti_aliasing_pc = p->anti_aliasing_pc? p->anti_aliasing_pc : |
||||
allow_aliasing? bw_3dB_pc : 100; |
||||
|
||||
if (argc) { |
||||
if ((p->out_rate = lsx_parse_frequency(*argv, &dummy_p)) <= 0 || *dummy_p) |
||||
return lsx_usage(effp); |
||||
argc--; argv++; |
||||
effp->out_signal.rate = p->out_rate; |
||||
} |
||||
return argc? lsx_usage(effp) : SOX_SUCCESS; |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
double out_rate = p->out_rate != 0 ? p->out_rate : effp->out_signal.rate; |
||||
|
||||
if (effp->in_signal.rate == out_rate) |
||||
return SOX_EFF_NULL; |
||||
|
||||
if (effp->in_signal.mult) |
||||
*effp->in_signal.mult *= .705; /* 1/(2/sinc(pi/3)-1); see De Soras 4.1.2 */ |
||||
|
||||
effp->out_signal.channels = effp->in_signal.channels; |
||||
effp->out_signal.rate = out_rate; |
||||
rate_init(&p->rate, p->shared_ptr, effp->in_signal.rate/out_rate,p->bit_depth, |
||||
p->phase, p->bw_0dB_pc, p->anti_aliasing_pc, p->rolloff, !p->given_0dB_pt, |
||||
p->use_hi_prec_clock, p->coef_interp, p->max_coefs_size, p->noIOpt); |
||||
|
||||
if (!p->rate.num_stages) { |
||||
lsx_warn("input and output rates too close, skipping resampling"); |
||||
return SOX_EFF_NULL; |
||||
} |
||||
|
||||
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 odone = *osamp; |
||||
|
||||
sample_t const * s = rate_output(&p->rate, NULL, &odone); |
||||
lsx_save_samples(obuf, s, odone, &effp->clips); |
||||
|
||||
if (*isamp && odone < *osamp) { |
||||
sample_t * t = rate_input(&p->rate, NULL, *isamp); |
||||
lsx_load_samples(t, ibuf, *isamp); |
||||
rate_process(&p->rate); |
||||
} |
||||
else *isamp = 0; |
||||
*osamp = odone; |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
static size_t isamp = 0; |
||||
rate_flush(&p->rate); |
||||
return flow(effp, 0, obuf, &isamp, osamp); |
||||
} |
||||
|
||||
static int stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
rate_close(&p->rate); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_rate_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"rate", 0, SOX_EFF_RATE, create, start, flow, drain, stop, 0, sizeof(priv_t) |
||||
}; |
||||
static char const * lines[] = { |
||||
"[-q|-l|-m|-h|-v] [override-options] RATE[k]", |
||||
" BAND-", |
||||
" QUALITY WIDTH REJ dB TYPICAL USE", |
||||
" -q quick n/a ~30 @ Fs/4 playback on ancient hardware", |
||||
" -l low 80% 100 playback on old hardware", |
||||
" -m medium 95% 100 audio playback", |
||||
" -h high (default) 95% 125 16-bit mastering (use with dither)", |
||||
" -v very high 95% 175 24-bit mastering", |
||||
" OVERRIDE OPTIONS (only with -m, -h, -v)", |
||||
" -M/-I/-L Phase response = minimum/intermediate/linear(default)", |
||||
" -s Steep filter (band-width = 99%)", |
||||
" -a Allow aliasing above the pass-band", |
||||
" -b 74-99.7 Any band-width %", |
||||
" -p 0-100 Any phase response (0 = minimum, 25 = intermediate,", |
||||
" 50 = linear, 100 = maximum)", |
||||
}; |
||||
static char * usage; |
||||
handler.usage = lsx_usage_lines(&usage, lines, array_length(lines)); |
||||
return &handler; |
||||
} |
@ -1,187 +0,0 @@ |
||||
/* Effect: change sample rate Copyright (c) 2008,12 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 |
||||
*/ |
||||
|
||||
static const sample_t half_fir_coefs_8[] = { |
||||
0.3115465451887802, -0.08734497241282892, 0.03681452335604365, |
||||
-0.01518925831569441, 0.005454118437408876, -0.001564400922162005, |
||||
0.0003181701445034203, -3.48001341225749e-5, |
||||
}; |
||||
#define FUNCTION h8 |
||||
#define CONVOLVE _ _ _ _ _ _ _ _ |
||||
#define h8_l 8 |
||||
#define COEFS half_fir_coefs_8 |
||||
#include "rate_half_fir.h" |
||||
|
||||
static const sample_t half_fir_coefs_9[] = { |
||||
0.3122703613711853, -0.08922155288172305, 0.03913974805854332, |
||||
-0.01725059723447163, 0.006858970092378141, -0.002304518467568703, |
||||
0.0006096426006051062, -0.0001132393923815236, 1.119795386287666e-5, |
||||
}; |
||||
#define FUNCTION h9 |
||||
#define CONVOLVE _ _ _ _ _ _ _ _ _ |
||||
#define h9_l 9 |
||||
#define COEFS half_fir_coefs_9 |
||||
#include "rate_half_fir.h" |
||||
|
||||
static const sample_t half_fir_coefs_10[] = { |
||||
0.3128545521327376, -0.09075671986104322, 0.04109637155154835, |
||||
-0.01906629512749895, 0.008184039342054333, -0.0030766775017262, |
||||
0.0009639607022414314, -0.0002358552746579827, 4.025184282444155e-5, |
||||
-3.629779111541012e-6, |
||||
}; |
||||
#define FUNCTION h10 |
||||
#define CONVOLVE _ _ _ _ _ _ _ _ _ _ |
||||
#define h10_l 10 |
||||
#define COEFS half_fir_coefs_10 |
||||
#include "rate_half_fir.h" |
||||
|
||||
static const sample_t half_fir_coefs_11[] = { |
||||
0.3133358837508807, -0.09203588680609488, 0.04276515428384758, |
||||
-0.02067356614745591, 0.00942253142371517, -0.003856330993895144, |
||||
0.001363470684892284, -0.0003987400965541919, 9.058629923971627e-5, |
||||
-1.428553070915318e-5, 1.183455238783835e-6, |
||||
}; |
||||
#define FUNCTION h11 |
||||
#define CONVOLVE _ _ _ _ _ _ _ _ _ _ _ |
||||
#define h11_l 11 |
||||
#define COEFS half_fir_coefs_11 |
||||
#include "rate_half_fir.h" |
||||
|
||||
static const sample_t half_fir_coefs_12[] = { |
||||
0.3137392991811407, -0.0931182192961332, 0.0442050575271454, |
||||
-0.02210391200618091, 0.01057473015666001, -0.00462766983973885, |
||||
0.001793630226239453, -0.0005961819959665878, 0.0001631475979359577, |
||||
-3.45557865639653e-5, 5.06188341942088e-6, -3.877010943315563e-7, |
||||
}; |
||||
#define FUNCTION h12 |
||||
#define CONVOLVE _ _ _ _ _ _ _ _ _ _ _ _ |
||||
#define h12_l 12 |
||||
#define COEFS half_fir_coefs_12 |
||||
#include "rate_half_fir.h" |
||||
|
||||
static const sample_t half_fir_coefs_13[] = { |
||||
0.3140822554324578, -0.0940458550886253, 0.04545990399121566, |
||||
-0.02338339450796002, 0.01164429409071052, -0.005380686021429845, |
||||
0.002242915773871009, -0.000822047600000082, 0.0002572510962395222, |
||||
-6.607320708956279e-5, 1.309926399120154e-5, -1.790719575255006e-6, |
||||
1.27504961098836e-7, |
||||
}; |
||||
#define FUNCTION h13 |
||||
#define CONVOLVE _ _ _ _ _ _ _ _ _ _ _ _ _ |
||||
#define h13_l 13 |
||||
#define COEFS half_fir_coefs_13 |
||||
#include "rate_half_fir.h" |
||||
|
||||
static struct {int num_coefs; stage_fn_t fn; float att;} const half_firs[] = { |
||||
{ 8, h8 , 136.51}, |
||||
{ 9, h9 , 152.32}, |
||||
{10, h10, 168.07}, |
||||
{11, h11, 183.78}, |
||||
{12, h12, 199.44}, |
||||
{13, h13, 212.75}, |
||||
}; |
||||
|
||||
#define HI_PREC_CLOCK |
||||
|
||||
#define VAR_LENGTH p->n |
||||
#define VAR_CONVOLVE while (j < FIR_LENGTH) _ |
||||
#define VAR_POLY_PHASE_BITS p->phase_bits |
||||
|
||||
#define FUNCTION vpoly0 |
||||
#define FIR_LENGTH VAR_LENGTH |
||||
#define CONVOLVE VAR_CONVOLVE |
||||
#include "rate_poly_fir0.h" |
||||
|
||||
#define FUNCTION vpoly1 |
||||
#define COEF_INTERP 1 |
||||
#define PHASE_BITS VAR_POLY_PHASE_BITS |
||||
#define FIR_LENGTH VAR_LENGTH |
||||
#define CONVOLVE VAR_CONVOLVE |
||||
#include "rate_poly_fir.h" |
||||
|
||||
#define FUNCTION vpoly2 |
||||
#define COEF_INTERP 2 |
||||
#define PHASE_BITS VAR_POLY_PHASE_BITS |
||||
#define FIR_LENGTH VAR_LENGTH |
||||
#define CONVOLVE VAR_CONVOLVE |
||||
#include "rate_poly_fir.h" |
||||
|
||||
#define FUNCTION vpoly3 |
||||
#define COEF_INTERP 3 |
||||
#define PHASE_BITS VAR_POLY_PHASE_BITS |
||||
#define FIR_LENGTH VAR_LENGTH |
||||
#define CONVOLVE VAR_CONVOLVE |
||||
#include "rate_poly_fir.h" |
||||
|
||||
#undef HI_PREC_CLOCK |
||||
|
||||
#define U100_l 42 |
||||
#define poly_fir_convolve_U100 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ |
||||
#define FUNCTION U100_0 |
||||
#define FIR_LENGTH U100_l |
||||
#define CONVOLVE poly_fir_convolve_U100 |
||||
#include "rate_poly_fir0.h" |
||||
|
||||
#define u100_l 11 |
||||
#define poly_fir_convolve_u100 _ _ _ _ _ _ _ _ _ _ _ |
||||
#define FUNCTION u100_0 |
||||
#define FIR_LENGTH u100_l |
||||
#define CONVOLVE poly_fir_convolve_u100 |
||||
#include "rate_poly_fir0.h" |
||||
|
||||
#define FUNCTION u100_1 |
||||
#define COEF_INTERP 1 |
||||
#define PHASE_BITS 8 |
||||
#define FIR_LENGTH u100_l |
||||
#define CONVOLVE poly_fir_convolve_u100 |
||||
#include "rate_poly_fir.h" |
||||
#define u100_1_b 8 |
||||
|
||||
#define FUNCTION u100_2 |
||||
#define COEF_INTERP 2 |
||||
#define PHASE_BITS 6 |
||||
#define FIR_LENGTH u100_l |
||||
#define CONVOLVE poly_fir_convolve_u100 |
||||
#include "rate_poly_fir.h" |
||||
#define u100_2_b 6 |
||||
|
||||
typedef struct {float scalar; stage_fn_t fn;} poly_fir1_t; |
||||
typedef struct {float beta; poly_fir1_t interp[3];} poly_fir_t; |
||||
|
||||
static poly_fir_t const poly_firs[] = { |
||||
{-1, {{0, vpoly0}, { 7.2, vpoly1}, {5.0, vpoly2}}},
|
||||
{-1, {{0, vpoly0}, { 9.4, vpoly1}, {6.7, vpoly2}}},
|
||||
{-1, {{0, vpoly0}, {12.4, vpoly1}, {7.8, vpoly2}}},
|
||||
{-1, {{0, vpoly0}, {13.6, vpoly1}, {9.3, vpoly2}}},
|
||||
{-1, {{0, vpoly0}, {10.5, vpoly2}, {8.4, vpoly3}}},
|
||||
{-1, {{0, vpoly0}, {11.85,vpoly2}, {9.0, vpoly3}}},
|
||||
|
||||
{-1, {{0, vpoly0}, { 8.0, vpoly1}, {5.3, vpoly2}}},
|
||||
{-1, {{0, vpoly0}, { 8.6, vpoly1}, {5.7, vpoly2}}},
|
||||
{-1, {{0, vpoly0}, {10.6, vpoly1}, {6.75,vpoly2}}},
|
||||
{-1, {{0, vpoly0}, {12.6, vpoly1}, {8.6, vpoly2}}},
|
||||
{-1, {{0, vpoly0}, { 9.6, vpoly2}, {7.6, vpoly3}}},
|
||||
{-1, {{0, vpoly0}, {11.4, vpoly2}, {8.65,vpoly3}}},
|
||||
|
||||
{10.62, {{U100_l, U100_0}, {0, 0}, {0, 0}}},
|
||||
{11.28, {{u100_l, u100_0}, {u100_1_b, u100_1}, {u100_2_b, u100_2}}},
|
||||
{-1, {{0, vpoly0}, { 9, vpoly1}, { 6, vpoly2}}},
|
||||
{-1, {{0, vpoly0}, { 11, vpoly1}, { 7, vpoly2}}},
|
||||
{-1, {{0, vpoly0}, { 13, vpoly1}, { 8, vpoly2}}},
|
||||
{-1, {{0, vpoly0}, { 10, vpoly2}, { 8, vpoly3}}},
|
||||
{-1, {{0, vpoly0}, { 12, vpoly2}, { 9, vpoly3}}},
|
||||
}; |
@ -1,39 +0,0 @@ |
||||
/* Effect: change sample rate Copyright (c) 2008,12 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 |
||||
*/ |
||||
|
||||
/* Down-sample by a factor of 2 using a FIR with odd length (LEN).*/ |
||||
/* Input must be preceded and followed by LEN >> 1 samples. */ |
||||
|
||||
#define _ sum += (input[-(2*j +1)] + input[(2*j +1)]) * COEFS[j], ++j; |
||||
static void FUNCTION(stage_t * p, fifo_t * output_fifo) |
||||
{ |
||||
sample_t const * input = stage_read_p(p); |
||||
int i, num_out = (stage_occupancy(p) + 1) / 2; |
||||
sample_t * output = fifo_reserve(output_fifo, num_out); |
||||
|
||||
for (i = 0; i < num_out; ++i, input += 2) { |
||||
int j = 0; |
||||
sample_t sum = input[0] * .5; |
||||
CONVOLVE |
||||
output[i] = sum; |
||||
} |
||||
fifo_read(&p->fifo, 2 * num_out, NULL); |
||||
} |
||||
#undef _ |
||||
#undef COEFS |
||||
#undef CONVOLVE |
||||
#undef FUNCTION |
@ -1,91 +0,0 @@ |
||||
/* Effect: change sample rate Copyright (c) 2008,12 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 |
||||
*/ |
||||
|
||||
/* Resample using an interpolated poly-phase FIR with length LEN.*/ |
||||
/* Input must be followed by LEN-1 samples. */ |
||||
|
||||
#define a (coef(p->shared->poly_fir_coefs, COEF_INTERP, FIR_LENGTH, phase, 0,j)) |
||||
#define b (coef(p->shared->poly_fir_coefs, COEF_INTERP, FIR_LENGTH, phase, 1,j)) |
||||
#define c (coef(p->shared->poly_fir_coefs, COEF_INTERP, FIR_LENGTH, phase, 2,j)) |
||||
#define d (coef(p->shared->poly_fir_coefs, COEF_INTERP, FIR_LENGTH, phase, 3,j)) |
||||
#if COEF_INTERP == 0 |
||||
#define _ sum += a *in[j], ++j; |
||||
#elif COEF_INTERP == 1 |
||||
#define _ sum += (b *x + a)*in[j], ++j; |
||||
#elif COEF_INTERP == 2 |
||||
#define _ sum += ((c *x + b)*x + a)*in[j], ++j; |
||||
#elif COEF_INTERP == 3 |
||||
#define _ sum += (((d*x + c)*x + b)*x + a)*in[j], ++j; |
||||
#else |
||||
#error COEF_INTERP |
||||
#endif |
||||
|
||||
static void FUNCTION(stage_t * p, fifo_t * output_fifo) |
||||
{ |
||||
sample_t const * input = stage_read_p(p); |
||||
int i, num_in = stage_occupancy(p), max_num_out = 1 + num_in*p->out_in_ratio; |
||||
sample_t * output = fifo_reserve(output_fifo, max_num_out); |
||||
|
||||
#if defined HI_PREC_CLOCK |
||||
if (p->use_hi_prec_clock) { |
||||
hi_prec_clock_t at = p->at.hi_prec_clock; |
||||
for (i = 0; (int)at < num_in; ++i, at += p->step.hi_prec_clock) { |
||||
sample_t const * in = input + (int)at; |
||||
hi_prec_clock_t fraction = at - (int)at; |
||||
int phase = fraction * (1 << PHASE_BITS); |
||||
#if COEF_INTERP > 0 |
||||
sample_t x = fraction * (1 << PHASE_BITS) - phase; |
||||
#endif |
||||
sample_t sum = 0; |
||||
int j = 0; |
||||
CONVOLVE |
||||
output[i] = sum; |
||||
} |
||||
fifo_read(&p->fifo, (int)at, NULL); |
||||
p->at.hi_prec_clock = at - (int)at; |
||||
} else |
||||
#endif |
||||
{ |
||||
for (i = 0; p->at.parts.integer < num_in; ++i, p->at.all += p->step.all) { |
||||
sample_t const * in = input + p->at.parts.integer; |
||||
uint32_t fraction = p->at.parts.fraction; |
||||
int phase = fraction >> (32 - PHASE_BITS); /* high-order bits */ |
||||
#if COEF_INTERP > 0 /* low-order bits, scaled to [0,1) */ |
||||
sample_t x = (sample_t) (fraction << PHASE_BITS) * (1 / MULT32); |
||||
#endif |
||||
sample_t sum = 0; |
||||
int j = 0; |
||||
CONVOLVE |
||||
output[i] = sum; |
||||
} |
||||
fifo_read(&p->fifo, p->at.parts.integer, NULL); |
||||
p->at.parts.integer = 0; |
||||
} |
||||
assert(max_num_out - i >= 0); |
||||
fifo_trim_by(output_fifo, max_num_out - i); |
||||
} |
||||
|
||||
#undef _ |
||||
#undef a |
||||
#undef b |
||||
#undef c |
||||
#undef d |
||||
#undef COEF_INTERP |
||||
#undef CONVOLVE |
||||
#undef FIR_LENGTH |
||||
#undef FUNCTION |
||||
#undef PHASE_BITS |
@ -1,48 +0,0 @@ |
||||
/* Effect: change sample rate Copyright (c) 2008,12 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 |
||||
*/ |
||||
|
||||
/* Resample using a non-interpolated poly-phase FIR with length LEN.*/ |
||||
/* Input must be followed by LEN-1 samples. */ |
||||
|
||||
#define _ sum += (coef(p->shared->poly_fir_coefs, 0, FIR_LENGTH, divided.rem, 0, j)) *at[j], ++j; |
||||
|
||||
static void FUNCTION(stage_t * p, fifo_t * output_fifo) |
||||
{ |
||||
sample_t const * input = stage_read_p(p); |
||||
int i, num_in = stage_occupancy(p), max_num_out = 1 + num_in*p->out_in_ratio; |
||||
sample_t * output = fifo_reserve(output_fifo, max_num_out); |
||||
div_t divided2; |
||||
|
||||
for (i = 0; p->at.parts.integer < num_in * p->L; ++i, p->at.parts.integer += p->step.parts.integer) { |
||||
div_t divided = div(p->at.parts.integer, p->L); |
||||
sample_t const * at = input + divided.quot; |
||||
sample_t sum = 0; |
||||
int j = 0; |
||||
CONVOLVE |
||||
output[i] = sum; |
||||
} |
||||
assert(max_num_out - i >= 0); |
||||
fifo_trim_by(output_fifo, max_num_out - i); |
||||
divided2 = div(p->at.parts.integer, p->L); |
||||
fifo_read(&p->fifo, divided2.quot, NULL); |
||||
p->at.parts.integer = divided2.rem; |
||||
} |
||||
|
||||
#undef _ |
||||
#undef CONVOLVE |
||||
#undef FIR_LENGTH |
||||
#undef FUNCTION |
@ -1,61 +0,0 @@ |
||||
/* libSoX file formats: raw (c) 2007-11 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" |
||||
|
||||
static int raw_start(sox_format_t * ft) { |
||||
return lsx_rawstart(ft, sox_false, sox_false, sox_true, SOX_ENCODING_UNKNOWN, 0); |
||||
} |
||||
|
||||
LSX_FORMAT_HANDLER(raw) |
||||
{ |
||||
static char const * const names[] = {"raw", NULL}; |
||||
static unsigned const encodings[] = { |
||||
SOX_ENCODING_SIGN2, 32, 24, 16, 8, 0, |
||||
SOX_ENCODING_UNSIGNED, 32, 24, 16, 8, 0, |
||||
SOX_ENCODING_ULAW, 8, 0, |
||||
SOX_ENCODING_ALAW, 8, 0, |
||||
SOX_ENCODING_FLOAT, 64, 32, 0, |
||||
0}; |
||||
static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, |
||||
"Raw PCM, mu-law, or A-law", names, 0, |
||||
raw_start, lsx_rawread , NULL, |
||||
raw_start, lsx_rawwrite, NULL, |
||||
lsx_rawseek, encodings, NULL, 0 |
||||
}; |
||||
return &handler; |
||||
} |
||||
|
||||
static int sln_start(sox_format_t * ft) |
||||
{ |
||||
return lsx_check_read_params(ft, 1, 8000., SOX_ENCODING_SIGN2, 16, (uint64_t)0, sox_false); |
||||
} |
||||
|
||||
LSX_FORMAT_HANDLER(sln) |
||||
{ |
||||
static char const * const names[] = {"sln", NULL}; |
||||
static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 16, 0, 0}; |
||||
static sox_rate_t const write_rates[] = {8000, 0}; |
||||
static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE, |
||||
"Asterisk PBX headerless format", |
||||
names, SOX_FILE_LIT_END|SOX_FILE_MONO, |
||||
sln_start, lsx_rawread, NULL, |
||||
NULL, lsx_rawwrite, NULL, |
||||
lsx_rawseek, write_encodings, write_rates, 0 |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,284 +0,0 @@ |
||||
/* libSoX effect: remix Copyright (c) 2008-9 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include <string.h> |
||||
|
||||
typedef struct { |
||||
enum {semi, automatic, manual} mode; |
||||
sox_bool mix_power; |
||||
unsigned num_out_channels, min_in_channels; |
||||
struct { |
||||
char * str; /* Command-line argument to parse for this out_spec */ |
||||
unsigned num_in_channels; |
||||
struct in_spec { |
||||
unsigned channel_num; |
||||
double multiplier; |
||||
} * in_specs; |
||||
} * out_specs; |
||||
} priv_t; |
||||
|
||||
#define PARSE(SEP, SCAN, VAR, MIN, SEPARATORS) do {\ |
||||
end = strpbrk(text, SEPARATORS); \
|
||||
if (end == text) \
|
||||
SEP = *text++; \
|
||||
else { \
|
||||
SEP = (SEPARATORS)[strlen(SEPARATORS) - 1]; \
|
||||
n = sscanf(text, SCAN"%c", &VAR, &SEP); \
|
||||
if (n == 0 || VAR < MIN || (n == 2 && !strchr(SEPARATORS, SEP))) \
|
||||
return lsx_usage(effp); \
|
||||
text = end? end + 1 : text + strlen(text); \
|
||||
} \
|
||||
} while (0) |
||||
|
||||
static int parse(sox_effect_t * effp, char * * argv, unsigned channels) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
unsigned i, j; |
||||
double mult; |
||||
|
||||
p->min_in_channels = 0; |
||||
for (i = 0; i < p->num_out_channels; ++i) { |
||||
sox_bool mul_spec = sox_false; |
||||
char * text, * end; |
||||
if (argv) /* 1st parse only */ |
||||
p->out_specs[i].str = lsx_strdup(argv[i]); |
||||
for (j = 0, text = p->out_specs[i].str; *text;) { |
||||
static char const separators[] = "-vpi,"; |
||||
char sep1, sep2; |
||||
int chan1 = 1, chan2 = channels, n; |
||||
double multiplier = HUGE_VAL; |
||||
|
||||
PARSE(sep1, "%i", chan1, 0, separators); |
||||
if (!chan1) { |
||||
if (j || *text) |
||||
return lsx_usage(effp); |
||||
continue; |
||||
} |
||||
if (sep1 == '-') |
||||
PARSE(sep1, "%i", chan2, 0, separators + 1); |
||||
else chan2 = chan1; |
||||
if (sep1 != ',') { |
||||
multiplier = sep1 == 'v' ? 1 : 0; |
||||
PARSE(sep2, "%lf", multiplier, -HUGE_VAL, separators + 4); |
||||
if (sep1 != 'v') |
||||
multiplier = (sep1 == 'p'? 1 : -1) * dB_to_linear(multiplier); |
||||
mul_spec = sox_true; |
||||
} |
||||
if (chan2 < chan1) {int t = chan1; chan1 = chan2; chan2 = t;} |
||||
p->out_specs[i].in_specs = lsx_realloc(p->out_specs[i].in_specs, |
||||
(j + chan2 - chan1 + 1) * sizeof(*p->out_specs[i].in_specs)); |
||||
while (chan1 <= chan2) { |
||||
p->out_specs[i].in_specs[j].channel_num = chan1++ - 1; |
||||
p->out_specs[i].in_specs[j++].multiplier = multiplier; |
||||
} |
||||
p->min_in_channels = max(p->min_in_channels, (unsigned)chan2); |
||||
} |
||||
p->out_specs[i].num_in_channels = j; |
||||
mult = 1. / (p->mix_power? sqrt((double)j) : j); |
||||
for (j = 0; j < p->out_specs[i].num_in_channels; ++j) |
||||
if (p->out_specs[i].in_specs[j].multiplier == HUGE_VAL) |
||||
p->out_specs[i].in_specs[j].multiplier = (p->mode == automatic || (p->mode == semi && !mul_spec)) ? mult : 1; |
||||
} |
||||
effp->out_signal.channels = p->num_out_channels; |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int show(priv_t *p) |
||||
{ |
||||
unsigned i, j; |
||||
|
||||
for (j = 0; j < p->num_out_channels; j++) { |
||||
lsx_debug("%i: ", j); |
||||
for (i = 0; i < p->out_specs[j].num_in_channels; i++) |
||||
lsx_debug("\t%i %g", p->out_specs[j].in_specs[i].channel_num, p->out_specs[j].in_specs[i].multiplier); |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int create(sox_effect_t * effp, int argc, char * * argv) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
--argc, ++argv; |
||||
if (argc && !strcmp(*argv, "-m")) p->mode = manual , ++argv, --argc; |
||||
if (argc && !strcmp(*argv, "-a")) p->mode = automatic, ++argv, --argc; |
||||
if (argc && !strcmp(*argv, "-p")) p->mix_power = sox_true, ++argv, --argc; |
||||
if (!argc) { |
||||
lsx_fail("must specify at least one output channel"); |
||||
return SOX_EOF; |
||||
} |
||||
p->num_out_channels = argc; |
||||
p->out_specs = lsx_calloc(p->num_out_channels, sizeof(*p->out_specs)); |
||||
return parse(effp, argv, 1); /* No channels yet; parse with dummy */ |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
double max_sum = 0; |
||||
unsigned i, j; |
||||
int non_integer = 0; |
||||
|
||||
parse(effp, NULL, effp->in_signal.channels); |
||||
if (effp->in_signal.channels < p->min_in_channels) { |
||||
lsx_fail("too few input channels"); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
for (j = 0; j < effp->out_signal.channels; j++) { |
||||
double sum = 0; |
||||
for (i = 0; i < p->out_specs[j].num_in_channels; i++) { |
||||
double mult = p->out_specs[j].in_specs[i].multiplier; |
||||
sum += fabs(mult); |
||||
non_integer += floor(mult) != mult; |
||||
} |
||||
max_sum = max(max_sum, sum); |
||||
} |
||||
if (effp->in_signal.mult && max_sum > 1) |
||||
*effp->in_signal.mult /= max_sum; |
||||
if (!non_integer) |
||||
effp->out_signal.precision = effp->in_signal.precision; |
||||
else |
||||
effp->out_signal.precision = SOX_SAMPLE_PRECISION; |
||||
show(p); |
||||
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; |
||||
unsigned i, j, len; |
||||
len = min(*isamp / effp->in_signal.channels, *osamp / effp->out_signal.channels); |
||||
*isamp = len * effp->in_signal.channels; |
||||
*osamp = len * effp->out_signal.channels; |
||||
|
||||
for (; len--; ibuf += effp->in_signal.channels) for (j = 0; j < effp->out_signal.channels; j++) { |
||||
double out = 0; |
||||
for (i = 0; i < p->out_specs[j].num_in_channels; i++) |
||||
out += ibuf[p->out_specs[j].in_specs[i].channel_num] * p->out_specs[j].in_specs[i].multiplier; |
||||
*obuf++ = SOX_ROUND_CLIP_COUNT(out, effp->clips); |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int closedown(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
unsigned i; |
||||
for (i = 0; i < p->num_out_channels; ++i) { |
||||
free(p->out_specs[i].str); |
||||
free(p->out_specs[i].in_specs); |
||||
} |
||||
free(p->out_specs); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_remix_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"remix", "[-m|-a] [-p] <0|in-chan[v|p|i volume]{,in-chan[v|p|i volume]}>", |
||||
SOX_EFF_MCHAN | SOX_EFF_CHAN | SOX_EFF_GAIN | SOX_EFF_PREC, |
||||
create, start, flow, NULL, NULL, closedown, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
||||
|
||||
/*----------------------- The `channels' effect alias ------------------------*/ |
||||
|
||||
static int channels_create(sox_effect_t * effp, int argc, char * * argv) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
char dummy; /* To check for extraneous chars. */ |
||||
|
||||
if (argc == 2) { |
||||
if (sscanf(argv[1], "%d %c", (int *)&p->num_out_channels, |
||||
&dummy) != 1 || (int)p->num_out_channels <= 0) |
||||
return lsx_usage(effp); |
||||
effp->out_signal.channels = p->num_out_channels; |
||||
} |
||||
else if (argc != 1) |
||||
return lsx_usage(effp); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int channels_start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
unsigned num_out_channels = p->num_out_channels != 0 ? |
||||
p->num_out_channels : effp->out_signal.channels; |
||||
unsigned i, j; |
||||
|
||||
p->out_specs = lsx_calloc(num_out_channels, sizeof(*p->out_specs)); |
||||
if (effp->in_signal.channels == num_out_channels) |
||||
return SOX_EFF_NULL; |
||||
|
||||
if (effp->in_signal.channels > num_out_channels) { |
||||
for (j = 0; j < num_out_channels; j++) { |
||||
unsigned in_per_out = (effp->in_signal.channels + |
||||
num_out_channels - 1 - j) / num_out_channels; |
||||
lsx_valloc(p->out_specs[j].in_specs, in_per_out); |
||||
p->out_specs[j].num_in_channels = in_per_out; |
||||
for (i = 0; i < in_per_out; ++i) { |
||||
p->out_specs[j].in_specs[i].channel_num = i * num_out_channels + j; |
||||
p->out_specs[j].in_specs[i].multiplier = 1. / in_per_out; |
||||
} |
||||
} |
||||
} |
||||
else for (j = 0; j < num_out_channels; j++) { |
||||
lsx_valloc(p->out_specs[j].in_specs, 1); |
||||
p->out_specs[j].num_in_channels = 1; |
||||
p->out_specs[j].in_specs[0].channel_num = j % effp->in_signal.channels; |
||||
p->out_specs[j].in_specs[0].multiplier = 1; |
||||
} |
||||
effp->out_signal.channels = p->num_out_channels = num_out_channels; |
||||
effp->out_signal.precision = (effp->in_signal.channels > num_out_channels) ? |
||||
SOX_SAMPLE_PRECISION : effp->in_signal.precision; |
||||
show(p); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_channels_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler; |
||||
handler = *lsx_remix_effect_fn(); |
||||
handler.name = "channels"; |
||||
handler.usage = "number"; |
||||
handler.flags &= ~SOX_EFF_GAIN; |
||||
handler.getopts = channels_create; |
||||
handler.start = channels_start; |
||||
return &handler; |
||||
} |
||||
|
||||
/*------------------------- The `oops' effect alias --------------------------*/ |
||||
|
||||
static int oops_getopts(sox_effect_t *effp, int argc, char **argv) |
||||
{ |
||||
char *args[] = {0, "1,2i", "1,2i"}; |
||||
args[0] = argv[0]; |
||||
return --argc? lsx_usage(effp) : create(effp, 3, args); |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_oops_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler; |
||||
handler = *lsx_remix_effect_fn(); |
||||
handler.name = "oops"; |
||||
handler.usage = NULL; |
||||
handler.getopts = oops_getopts; |
||||
return &handler; |
||||
} |
@ -1,114 +0,0 @@ |
||||
/* libSoX repeat effect Copyright (c) 2004 Jan Paul Schmidt <jps@fundament.org>
|
||||
* Re-write (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 { |
||||
unsigned num_repeats, remaining_repeats; |
||||
uint64_t num_samples, remaining_samples; |
||||
FILE * tmp_file; |
||||
} priv_t; |
||||
|
||||
static int create(sox_effect_t * effp, int argc, char * * argv) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
p->num_repeats = 1; |
||||
--argc, ++argv; |
||||
if (argc == 1 && !strcmp(*argv, "-")) { |
||||
p->num_repeats = UINT_MAX; |
||||
return SOX_SUCCESS; |
||||
} |
||||
do {NUMERIC_PARAMETER(num_repeats, 0, UINT_MAX - 1)} while (0); |
||||
return argc? lsx_usage(effp) : SOX_SUCCESS; |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
if (!p->num_repeats) |
||||
return SOX_EFF_NULL; |
||||
|
||||
if (!(p->tmp_file = lsx_tmpfile())) { |
||||
lsx_fail("can't create temporary file: %s", strerror(errno)); |
||||
return SOX_EOF; |
||||
} |
||||
p->num_samples = p->remaining_samples = 0; |
||||
p->remaining_repeats = p->num_repeats; |
||||
if (effp->in_signal.length != SOX_UNKNOWN_LEN && p->num_repeats != UINT_MAX) |
||||
effp->out_signal.length = effp->in_signal.length * (p->num_repeats + 1); |
||||
else |
||||
effp->out_signal.length = SOX_UNKNOWN_LEN; |
||||
|
||||
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 = min(*isamp, *osamp); |
||||
memcpy(obuf, ibuf, len * sizeof(*obuf)); |
||||
if (fwrite(ibuf, sizeof(*ibuf), len, p->tmp_file) != len) { |
||||
lsx_fail("error writing temporary file: %s", strerror(errno)); |
||||
return SOX_EOF; |
||||
} |
||||
p->num_samples += len; |
||||
*isamp = *osamp = len; |
||||
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 odone = 0, n; |
||||
|
||||
*osamp -= *osamp % effp->in_signal.channels; |
||||
|
||||
while ((p->remaining_samples || p->remaining_repeats) && odone < *osamp) { |
||||
if (!p->remaining_samples) { |
||||
p->remaining_samples = p->num_samples; |
||||
if (p->remaining_repeats != UINT_MAX) |
||||
--p->remaining_repeats; |
||||
rewind(p->tmp_file); |
||||
} |
||||
n = min(p->remaining_samples, *osamp - odone); |
||||
if ((fread(obuf + odone, sizeof(*obuf), n, p->tmp_file)) != n) { |
||||
lsx_fail("error reading temporary file: %s", strerror(errno)); |
||||
return SOX_EOF; |
||||
} |
||||
p->remaining_samples -= n; |
||||
odone += n; |
||||
} |
||||
*osamp = odone; |
||||
return p->remaining_samples || p->remaining_repeats? SOX_SUCCESS : SOX_EOF; |
||||
} |
||||
|
||||
static int stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
fclose(p->tmp_file); /* auto-deleted by lsx_tmpfile */ |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_repeat_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t effect = {"repeat", "[count (1)]", |
||||
SOX_EFF_MCHAN | SOX_EFF_LENGTH | SOX_EFF_MODIFY, |
||||
create, start, flow, drain, stop, NULL, sizeof(priv_t)}; |
||||
return &effect; |
||||
} |
@ -1,86 +0,0 @@ |
||||
/* June 1, 1992
|
||||
* Copyright 1992 Guido van Rossum And Sundry Contributors |
||||
* This source code is freely redistributable and may be used for |
||||
* any purpose. This copyright notice must be maintained. |
||||
* Guido van Rossum And Sundry Contributors are not responsible for |
||||
* the consequences of using this software. |
||||
*/ |
||||
|
||||
/*
|
||||
* "reverse" effect, uses a temporary file created by lsx_tmpfile(). |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include <string.h> |
||||
|
||||
typedef struct { |
||||
off_t pos; |
||||
FILE * tmp_file; |
||||
} priv_t; |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
p->pos = 0; |
||||
p->tmp_file = lsx_tmpfile(); |
||||
if (p->tmp_file == NULL) { |
||||
lsx_fail("can't create temporary file: %s", strerror(errno)); |
||||
return SOX_EOF; |
||||
} |
||||
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; |
||||
if (fwrite(ibuf, sizeof(*ibuf), *isamp, p->tmp_file) != *isamp) { |
||||
lsx_fail("error writing temporary file: %s", strerror(errno)); |
||||
return SOX_EOF; |
||||
} |
||||
(void)obuf, *osamp = 0; /* samples not output until drain */ |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
int i, j; |
||||
|
||||
if (p->pos == 0) { |
||||
fflush(p->tmp_file); |
||||
p->pos = ftello(p->tmp_file); |
||||
if (p->pos % sizeof(sox_sample_t) != 0) { |
||||
lsx_fail("temporary file has incorrect size"); |
||||
return SOX_EOF; |
||||
} |
||||
p->pos /= sizeof(sox_sample_t); |
||||
} |
||||
p->pos -= *osamp = min((off_t)*osamp, p->pos); |
||||
fseeko(p->tmp_file, (off_t)(p->pos * sizeof(sox_sample_t)), SEEK_SET); |
||||
if (fread(obuf, sizeof(sox_sample_t), *osamp, p->tmp_file) != *osamp) { |
||||
lsx_fail("error reading temporary file: %s", strerror(errno)); |
||||
return SOX_EOF; |
||||
} |
||||
for (i = 0, j = *osamp - 1; i < j; ++i, --j) { /* reverse the samples */ |
||||
sox_sample_t temp = obuf[i]; |
||||
obuf[i] = obuf[j]; |
||||
obuf[j] = temp; |
||||
} |
||||
return p->pos? SOX_SUCCESS : SOX_EOF; |
||||
} |
||||
|
||||
static int stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
fclose(p->tmp_file); /* auto-deleted by lsx_tmpfile */ |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_reverse_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"reverse", NULL, SOX_EFF_MODIFY, NULL, start, flow, drain, stop, NULL, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,21 +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 |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "raw.h" |
||||
|
||||
RAW_FORMAT2(s1, "s8", "sb", 8, 0, SIGN2) |
@ -1,21 +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 |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "raw.h" |
||||
|
||||
RAW_FORMAT2(s2, "s16", "sw", 16, 0, SIGN2) |
@ -1,21 +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 |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "raw.h" |
||||
|
||||
RAW_FORMAT1(s3, "s24", 24, 0, SIGN2) |
@ -1,21 +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 |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "raw.h" |
||||
|
||||
RAW_FORMAT2(s4, "s32", "sl", 32, 0, SIGN2) |
@ -1,30 +0,0 @@ |
||||
/* libSoX file format: SD2 Copyright (c) 2008 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
LSX_FORMAT_HANDLER(sd2) |
||||
{ |
||||
static char const * const names[] = {"sd2", NULL}; |
||||
static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 24, 16, 8,0,0}; |
||||
static sox_format_handler_t handler; |
||||
handler = *lsx_sndfile_format_fn(); |
||||
handler.description = "Sound Designer II"; |
||||
handler.names = names; |
||||
handler.write_formats = write_encodings; |
||||
return &handler; |
||||
} |
@ -1,690 +0,0 @@ |
||||
/* Silence effect for SoX
|
||||
* by Heikki Leinonen (heilei@iki.fi) 25.03.2001 |
||||
* Major Modifications by Chris Bagwell 06.08.2001 |
||||
* Minor addition by Donnie Smith 13.08.2003 |
||||
* |
||||
* This effect can delete samples from the start of a sound file |
||||
* until it sees a specified count of samples exceed a given threshold |
||||
* (any of the channels). |
||||
* This effect can also delete samples from the end of a sound file |
||||
* when it sees a specified count of samples below a given threshold |
||||
* (all channels). |
||||
* It may also be used to delete samples anywhere in a sound file. |
||||
* Thesholds can be given as either a percentage or in decibels. |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
/* Private data for silence effect. */ |
||||
|
||||
#define SILENCE_TRIM 0 |
||||
#define SILENCE_TRIM_FLUSH 1 |
||||
#define SILENCE_COPY 2 |
||||
#define SILENCE_COPY_FLUSH 3 |
||||
#define SILENCE_STOP 4 |
||||
|
||||
typedef struct { |
||||
char start; |
||||
int start_periods; |
||||
char *start_duration_str; |
||||
size_t start_duration; |
||||
double start_threshold; |
||||
char start_unit; /* "d" for decibels or "%" for percent. */ |
||||
int restart; |
||||
|
||||
sox_sample_t *start_holdoff; |
||||
size_t start_holdoff_offset; |
||||
size_t start_holdoff_end; |
||||
int start_found_periods; |
||||
|
||||
char stop; |
||||
int stop_periods; |
||||
char *stop_duration_str; |
||||
size_t stop_duration; |
||||
double stop_threshold; |
||||
char stop_unit; |
||||
|
||||
sox_sample_t *stop_holdoff; |
||||
size_t stop_holdoff_offset; |
||||
size_t stop_holdoff_end; |
||||
int stop_found_periods; |
||||
|
||||
double *window; |
||||
double *window_current; |
||||
double *window_end; |
||||
size_t window_size; |
||||
double rms_sum; |
||||
|
||||
char leave_silence; |
||||
|
||||
/* State Machine */ |
||||
char mode; |
||||
} priv_t; |
||||
|
||||
static void clear_rms(sox_effect_t * effp) |
||||
|
||||
{ |
||||
priv_t * silence = (priv_t *) effp->priv; |
||||
|
||||
memset(silence->window, 0, |
||||
silence->window_size * sizeof(double)); |
||||
|
||||
silence->window_current = silence->window; |
||||
silence->window_end = silence->window + silence->window_size; |
||||
silence->rms_sum = 0; |
||||
} |
||||
|
||||
static int sox_silence_getopts(sox_effect_t * effp, int argc, char **argv) |
||||
{ |
||||
priv_t * silence = (priv_t *) effp->priv; |
||||
int parse_count; |
||||
uint64_t temp; |
||||
const char *n; |
||||
--argc, ++argv; |
||||
|
||||
/* check for option switches */ |
||||
silence->leave_silence = sox_false; |
||||
if (argc > 0) |
||||
{ |
||||
if (!strcmp("-l", *argv)) { |
||||
argc--; argv++; |
||||
silence->leave_silence = sox_true; |
||||
} |
||||
} |
||||
|
||||
if (argc < 1) |
||||
return lsx_usage(effp); |
||||
|
||||
/* Parse data related to trimming front side */ |
||||
silence->start = sox_false; |
||||
if (sscanf(argv[0], "%d", &silence->start_periods) != 1) |
||||
return lsx_usage(effp); |
||||
if (silence->start_periods < 0) |
||||
{ |
||||
lsx_fail("Periods must not be negative"); |
||||
return(SOX_EOF); |
||||
} |
||||
argv++; |
||||
argc--; |
||||
|
||||
if (silence->start_periods > 0) |
||||
{ |
||||
silence->start = sox_true; |
||||
if (argc < 2) |
||||
return lsx_usage(effp); |
||||
|
||||
/* We do not know the sample rate so we can not fully
|
||||
* parse the duration info yet. So save argument off |
||||
* for future processing. |
||||
*/ |
||||
silence->start_duration_str = lsx_strdup(argv[0]); |
||||
/* Perform a fake parse to do error checking */ |
||||
n = lsx_parsesamples(0.,silence->start_duration_str,&temp,'s'); |
||||
if (!n || *n) |
||||
return lsx_usage(effp); |
||||
silence->start_duration = temp; |
||||
|
||||
parse_count = sscanf(argv[1], "%lf%c", &silence->start_threshold, |
||||
&silence->start_unit); |
||||
if (parse_count < 1) |
||||
return lsx_usage(effp); |
||||
else if (parse_count < 2) |
||||
silence->start_unit = '%'; |
||||
|
||||
argv++; argv++; |
||||
argc--; argc--; |
||||
} |
||||
|
||||
silence->stop = sox_false; |
||||
/* Parse data needed for trimming of backside */ |
||||
if (argc > 0) |
||||
{ |
||||
if (argc < 3) |
||||
return lsx_usage(effp); |
||||
if (sscanf(argv[0], "%d", &silence->stop_periods) != 1) |
||||
return lsx_usage(effp); |
||||
if (silence->stop_periods < 0) |
||||
{ |
||||
silence->stop_periods = -silence->stop_periods; |
||||
silence->restart = 1; |
||||
} |
||||
else |
||||
silence->restart = 0; |
||||
silence->stop = sox_true; |
||||
argv++; |
||||
argc--; |
||||
|
||||
/* We do not know the sample rate so we can not fully
|
||||
* parse the duration info yet. So save argument off |
||||
* for future processing. |
||||
*/ |
||||
silence->stop_duration_str = lsx_strdup(argv[0]); |
||||
/* Perform a fake parse to do error checking */ |
||||
n = lsx_parsesamples(0.,silence->stop_duration_str,&temp,'s'); |
||||
if (!n || *n) |
||||
return lsx_usage(effp); |
||||
silence->stop_duration = temp; |
||||
|
||||
parse_count = sscanf(argv[1], "%lf%c", &silence->stop_threshold, |
||||
&silence->stop_unit); |
||||
if (parse_count < 1) |
||||
return lsx_usage(effp); |
||||
else if (parse_count < 2) |
||||
silence->stop_unit = '%'; |
||||
|
||||
argv++; argv++; |
||||
argc--; argc--; |
||||
} |
||||
|
||||
/* Error checking */ |
||||
if (silence->start) |
||||
{ |
||||
if ((silence->start_unit != '%') && (silence->start_unit != 'd')) |
||||
{ |
||||
lsx_fail("Invalid unit specified"); |
||||
return lsx_usage(effp); |
||||
} |
||||
if ((silence->start_unit == '%') && ((silence->start_threshold < 0.0) |
||||
|| (silence->start_threshold > 100.0))) |
||||
{ |
||||
lsx_fail("silence threshold should be between 0.0 and 100.0 %%"); |
||||
return (SOX_EOF); |
||||
} |
||||
if ((silence->start_unit == 'd') && (silence->start_threshold >= 0.0)) |
||||
{ |
||||
lsx_fail("silence threshold should be less than 0.0 dB"); |
||||
return(SOX_EOF); |
||||
} |
||||
} |
||||
|
||||
if (silence->stop) |
||||
{ |
||||
if ((silence->stop_unit != '%') && (silence->stop_unit != 'd')) |
||||
{ |
||||
lsx_fail("Invalid unit specified"); |
||||
return(SOX_EOF); |
||||
} |
||||
if ((silence->stop_unit == '%') && ((silence->stop_threshold < 0.0) || |
||||
(silence->stop_threshold > 100.0))) |
||||
{ |
||||
lsx_fail("silence threshold should be between 0.0 and 100.0 %%"); |
||||
return (SOX_EOF); |
||||
} |
||||
if ((silence->stop_unit == 'd') && (silence->stop_threshold >= 0.0)) |
||||
{ |
||||
lsx_fail("silence threshold should be less than 0.0 dB"); |
||||
return(SOX_EOF); |
||||
} |
||||
} |
||||
return(SOX_SUCCESS); |
||||
} |
||||
|
||||
static int sox_silence_start(sox_effect_t * effp) |
||||
{ |
||||
priv_t *silence = (priv_t *)effp->priv; |
||||
uint64_t temp; |
||||
|
||||
/* When you want to remove silence, small window sizes are
|
||||
* better or else RMS will look like non-silence at |
||||
* aburpt changes from load to silence. |
||||
*/ |
||||
silence->window_size = (effp->in_signal.rate / 50) *
|
||||
effp->in_signal.channels; |
||||
silence->window = lsx_malloc(silence->window_size * sizeof(double)); |
||||
|
||||
clear_rms(effp); |
||||
|
||||
/* Now that we know sample rate, reparse duration. */ |
||||
if (silence->start) |
||||
{ |
||||
if (lsx_parsesamples(effp->in_signal.rate, silence->start_duration_str, |
||||
&temp, 's') == NULL) |
||||
return lsx_usage(effp); |
||||
silence->start_duration = temp * effp->in_signal.channels; |
||||
} |
||||
if (silence->stop) |
||||
{ |
||||
if (lsx_parsesamples(effp->in_signal.rate,silence->stop_duration_str, |
||||
&temp,'s') == NULL) |
||||
return lsx_usage(effp); |
||||
silence->stop_duration = temp * effp->in_signal.channels; |
||||
} |
||||
|
||||
if (silence->start) |
||||
silence->mode = SILENCE_TRIM; |
||||
else |
||||
silence->mode = SILENCE_COPY; |
||||
|
||||
silence->start_holdoff = lsx_malloc(sizeof(sox_sample_t)*silence->start_duration); |
||||
silence->start_holdoff_offset = 0; |
||||
silence->start_holdoff_end = 0; |
||||
silence->start_found_periods = 0; |
||||
|
||||
silence->stop_holdoff = lsx_malloc(sizeof(sox_sample_t)*silence->stop_duration); |
||||
silence->stop_holdoff_offset = 0; |
||||
silence->stop_holdoff_end = 0; |
||||
silence->stop_found_periods = 0; |
||||
|
||||
effp->out_signal.length = SOX_UNKNOWN_LEN; /* depends on input data */ |
||||
|
||||
return(SOX_SUCCESS); |
||||
} |
||||
|
||||
static sox_bool aboveThreshold(sox_effect_t const * effp, |
||||
sox_sample_t value /* >= 0 */, double threshold, int unit) |
||||
{ |
||||
/* When scaling low bit data, noise values got scaled way up */ |
||||
/* Only consider the original bits when looking for silence */ |
||||
sox_sample_t masked_value = value & (-1 << (32 - effp->in_signal.precision)); |
||||
|
||||
double scaled_value = (double)masked_value / SOX_SAMPLE_MAX; |
||||
|
||||
if (unit == '%') |
||||
scaled_value *= 100; |
||||
else if (unit == 'd') |
||||
scaled_value = linear_to_dB(scaled_value); |
||||
|
||||
return scaled_value > threshold; |
||||
} |
||||
|
||||
static sox_sample_t compute_rms(sox_effect_t * effp, sox_sample_t sample) |
||||
{ |
||||
priv_t * silence = (priv_t *) effp->priv; |
||||
double new_sum; |
||||
sox_sample_t rms; |
||||
|
||||
new_sum = silence->rms_sum; |
||||
new_sum -= *silence->window_current; |
||||
new_sum += ((double)sample * (double)sample); |
||||
|
||||
rms = sqrt(new_sum / silence->window_size); |
||||
|
||||
return (rms); |
||||
} |
||||
|
||||
static void update_rms(sox_effect_t * effp, sox_sample_t sample) |
||||
{ |
||||
priv_t * silence = (priv_t *) effp->priv; |
||||
|
||||
silence->rms_sum -= *silence->window_current; |
||||
*silence->window_current = ((double)sample * (double)sample); |
||||
silence->rms_sum += *silence->window_current; |
||||
|
||||
silence->window_current++; |
||||
if (silence->window_current >= silence->window_end) |
||||
silence->window_current = silence->window; |
||||
} |
||||
|
||||
/* Process signed long samples from ibuf to obuf. */ |
||||
/* Return number of samples processed in isamp and osamp. */ |
||||
static int sox_silence_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, |
||||
size_t *isamp, size_t *osamp) |
||||
{ |
||||
priv_t * silence = (priv_t *) effp->priv; |
||||
int threshold; |
||||
size_t i, j; |
||||
size_t nrOfTicks, /* sometimes wide, sometimes non-wide samples */ |
||||
nrOfInSamplesRead, nrOfOutSamplesWritten; /* non-wide samples */ |
||||
|
||||
nrOfInSamplesRead = 0; |
||||
nrOfOutSamplesWritten = 0; |
||||
|
||||
switch (silence->mode) |
||||
{ |
||||
case SILENCE_TRIM: |
||||
/* Reads and discards all input data until it detects a
|
||||
* sample that is above the specified threshold. Turns on |
||||
* copy mode when detected. |
||||
* Need to make sure and copy input in groups of "channels" to |
||||
* prevent getting buffers out of sync. |
||||
* nrOfTicks counts wide samples here. |
||||
*/ |
||||
silence_trim: |
||||
nrOfTicks = min((*isamp-nrOfInSamplesRead), |
||||
(*osamp-nrOfOutSamplesWritten)) / |
||||
effp->in_signal.channels; |
||||
for(i = 0; i < nrOfTicks; i++) |
||||
{ |
||||
threshold = 0; |
||||
for (j = 0; j < effp->in_signal.channels; j++) |
||||
{ |
||||
threshold |= aboveThreshold(effp, |
||||
compute_rms(effp, ibuf[j]), |
||||
silence->start_threshold, |
||||
silence->start_unit); |
||||
} |
||||
|
||||
if (threshold) |
||||
{ |
||||
/* Add to holdoff buffer */ |
||||
for (j = 0; j < effp->in_signal.channels; j++) |
||||
{ |
||||
update_rms(effp, *ibuf); |
||||
silence->start_holdoff[ |
||||
silence->start_holdoff_end++] = *ibuf++; |
||||
nrOfInSamplesRead++; |
||||
} |
||||
|
||||
if (silence->start_holdoff_end >= |
||||
silence->start_duration) |
||||
{ |
||||
if (++silence->start_found_periods >= |
||||
silence->start_periods) |
||||
{ |
||||
silence->mode = SILENCE_TRIM_FLUSH; |
||||
goto silence_trim_flush; |
||||
} |
||||
/* Trash holdoff buffer since its not
|
||||
* needed. Start looking again. |
||||
*/ |
||||
silence->start_holdoff_offset = 0; |
||||
silence->start_holdoff_end = 0; |
||||
} |
||||
} |
||||
else /* !above Threshold */ |
||||
{ |
||||
silence->start_holdoff_end = 0; |
||||
for (j = 0; j < effp->in_signal.channels; j++) |
||||
{ |
||||
update_rms(effp, ibuf[j]); |
||||
} |
||||
ibuf += effp->in_signal.channels; |
||||
nrOfInSamplesRead += effp->in_signal.channels; |
||||
} |
||||
} /* for nrOfTicks */ |
||||
break; |
||||
|
||||
case SILENCE_TRIM_FLUSH: |
||||
/* nrOfTicks counts non-wide samples here. */ |
||||
silence_trim_flush: |
||||
nrOfTicks = min((silence->start_holdoff_end - |
||||
silence->start_holdoff_offset), |
||||
(*osamp-nrOfOutSamplesWritten)); |
||||
nrOfTicks -= nrOfTicks % effp->in_signal.channels; |
||||
for(i = 0; i < nrOfTicks; i++) |
||||
{ |
||||
*obuf++ = silence->start_holdoff[silence->start_holdoff_offset++]; |
||||
nrOfOutSamplesWritten++; |
||||
} |
||||
|
||||
/* If fully drained holdoff then switch to copy mode */ |
||||
if (silence->start_holdoff_offset == silence->start_holdoff_end) |
||||
{ |
||||
silence->start_holdoff_offset = 0; |
||||
silence->start_holdoff_end = 0; |
||||
silence->mode = SILENCE_COPY; |
||||
goto silence_copy; |
||||
} |
||||
break; |
||||
|
||||
case SILENCE_COPY: |
||||
/* Attempts to copy samples into output buffer.
|
||||
* |
||||
* Case B: |
||||
* If not looking for silence to terminate copy then |
||||
* blindly copy data into output buffer. |
||||
* |
||||
* Case A: |
||||
* |
||||
* Case 1a: |
||||
* If previous silence was detect then see if input sample is |
||||
* above threshold. If found then flush out hold off buffer |
||||
* and copy over to output buffer. |
||||
* |
||||
* Case 1b: |
||||
* If no previous silence detect then see if input sample |
||||
* is above threshold. If found then copy directly |
||||
* to output buffer. |
||||
* |
||||
* Case 2: |
||||
* If not above threshold then silence is detect so |
||||
* store in hold off buffer and do not write to output |
||||
* buffer. Even though it wasn't put in output |
||||
* buffer, inform user that input was consumed. |
||||
* |
||||
* If hold off buffer is full after this then stop |
||||
* copying data and discard data in hold off buffer. |
||||
* |
||||
* Special leave_silence logic: |
||||
* |
||||
* During this mode, go ahead and copy input |
||||
* samples to output buffer instead of holdoff buffer |
||||
* Then also short ciruit any flushes that would occur |
||||
* when non-silence is detect since samples were already |
||||
* copied. This has the effect of always leaving |
||||
* holdoff[] amount of silence but deleting any |
||||
* beyond that amount. |
||||
* |
||||
* nrOfTicks counts wide samples here. |
||||
*/ |
||||
silence_copy: |
||||
nrOfTicks = min((*isamp-nrOfInSamplesRead), |
||||
(*osamp-nrOfOutSamplesWritten)) / |
||||
effp->in_signal.channels; |
||||
if (silence->stop) |
||||
{ |
||||
/* Case A */ |
||||
for(i = 0; i < nrOfTicks; i++) |
||||
{ |
||||
threshold = 1; |
||||
for (j = 0; j < effp->in_signal.channels; j++) |
||||
{ |
||||
threshold &= aboveThreshold(effp, |
||||
compute_rms(effp, ibuf[j]), |
||||
silence->stop_threshold, |
||||
silence->stop_unit); |
||||
} |
||||
|
||||
/* Case 1a
|
||||
* If above threshold, check to see if we where holding |
||||
* off previously. If so then flush this buffer. |
||||
* We haven't incremented any pointers yet so nothing |
||||
* is lost. |
||||
* |
||||
* If user wants to leave_silence, then we |
||||
* were already copying the data and so no |
||||
* need to flush the old data. Just resume |
||||
* copying as if we were not holding off. |
||||
*/ |
||||
if (threshold && silence->stop_holdoff_end |
||||
&& !silence->leave_silence) |
||||
{ |
||||
silence->mode = SILENCE_COPY_FLUSH; |
||||
goto silence_copy_flush; |
||||
} |
||||
/* Case 1b */ |
||||
else if (threshold) |
||||
{ |
||||
/* Not holding off so copy into output buffer */ |
||||
for (j = 0; j < effp->in_signal.channels; j++) |
||||
{ |
||||
update_rms(effp, *ibuf); |
||||
*obuf++ = *ibuf++; |
||||
nrOfInSamplesRead++; |
||||
nrOfOutSamplesWritten++; |
||||
} |
||||
} |
||||
/* Case 2 */ |
||||
else if (!threshold) |
||||
{ |
||||
/* Add to holdoff buffer */ |
||||
for (j = 0; j < effp->in_signal.channels; j++) |
||||
{ |
||||
update_rms(effp, *ibuf); |
||||
if (silence->leave_silence) { |
||||
*obuf++ = *ibuf; |
||||
nrOfOutSamplesWritten++; |
||||
} |
||||
silence->stop_holdoff[ |
||||
silence->stop_holdoff_end++] = *ibuf++; |
||||
nrOfInSamplesRead++; |
||||
} |
||||
|
||||
/* Check if holdoff buffer is greater than duration
|
||||
*/ |
||||
if (silence->stop_holdoff_end >= |
||||
silence->stop_duration) |
||||
{ |
||||
/* Increment found counter and see if this
|
||||
* is the last period. If so then exit. |
||||
*/ |
||||
if (++silence->stop_found_periods >= |
||||
silence->stop_periods) |
||||
{ |
||||
silence->stop_holdoff_offset = 0; |
||||
silence->stop_holdoff_end = 0; |
||||
if (!silence->restart) |
||||
{ |
||||
*isamp = nrOfInSamplesRead; |
||||
*osamp = nrOfOutSamplesWritten; |
||||
silence->mode = SILENCE_STOP; |
||||
/* Return SOX_EOF since no more processing */ |
||||
return (SOX_EOF); |
||||
} |
||||
else |
||||
{ |
||||
silence->stop_found_periods = 0; |
||||
silence->start_found_periods = 0; |
||||
silence->start_holdoff_offset = 0; |
||||
silence->start_holdoff_end = 0; |
||||
clear_rms(effp); |
||||
silence->mode = SILENCE_TRIM; |
||||
|
||||
goto silence_trim; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
/* Flush this buffer and start
|
||||
* looking again. |
||||
*/ |
||||
silence->mode = SILENCE_COPY_FLUSH; |
||||
goto silence_copy_flush; |
||||
} |
||||
break; |
||||
} /* Filled holdoff buffer */ |
||||
} /* Detected silence */ |
||||
} /* For # of samples */ |
||||
} /* Trimming off backend */ |
||||
else /* !(silence->stop) */ |
||||
{ |
||||
/* Case B */ |
||||
memcpy(obuf, ibuf, sizeof(sox_sample_t)*nrOfTicks* |
||||
effp->in_signal.channels); |
||||
nrOfInSamplesRead += (nrOfTicks*effp->in_signal.channels); |
||||
nrOfOutSamplesWritten += (nrOfTicks*effp->in_signal.channels); |
||||
} |
||||
break; |
||||
|
||||
case SILENCE_COPY_FLUSH: |
||||
/* nrOfTicks counts non-wide samples here. */ |
||||
silence_copy_flush: |
||||
nrOfTicks = min((silence->stop_holdoff_end - |
||||
silence->stop_holdoff_offset), |
||||
(*osamp-nrOfOutSamplesWritten)); |
||||
nrOfTicks -= nrOfTicks % effp->in_signal.channels; |
||||
|
||||
for(i = 0; i < nrOfTicks; i++) |
||||
{ |
||||
*obuf++ = silence->stop_holdoff[silence->stop_holdoff_offset++]; |
||||
nrOfOutSamplesWritten++; |
||||
} |
||||
|
||||
/* If fully drained holdoff then return to copy mode */ |
||||
if (silence->stop_holdoff_offset == silence->stop_holdoff_end) |
||||
{ |
||||
silence->stop_holdoff_offset = 0; |
||||
silence->stop_holdoff_end = 0; |
||||
silence->mode = SILENCE_COPY; |
||||
goto silence_copy; |
||||
} |
||||
break; |
||||
|
||||
case SILENCE_STOP: |
||||
/* This code can't be reached. */ |
||||
nrOfInSamplesRead = *isamp; |
||||
break; |
||||
} |
||||
|
||||
*isamp = nrOfInSamplesRead; |
||||
*osamp = nrOfOutSamplesWritten; |
||||
|
||||
return (SOX_SUCCESS); |
||||
} |
||||
|
||||
static int sox_silence_drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp) |
||||
{ |
||||
priv_t * silence = (priv_t *) effp->priv; |
||||
size_t i; |
||||
size_t nrOfTicks, nrOfOutSamplesWritten = 0; /* non-wide samples */ |
||||
|
||||
/* Only if in flush mode will there be possible samples to write
|
||||
* out during drain() call. |
||||
*/ |
||||
if (silence->mode == SILENCE_COPY_FLUSH || |
||||
silence->mode == SILENCE_COPY) |
||||
{ |
||||
nrOfTicks = min((silence->stop_holdoff_end - |
||||
silence->stop_holdoff_offset), *osamp); |
||||
nrOfTicks -= nrOfTicks % effp->in_signal.channels; |
||||
for(i = 0; i < nrOfTicks; i++) |
||||
{ |
||||
*obuf++ = silence->stop_holdoff[silence->stop_holdoff_offset++]; |
||||
nrOfOutSamplesWritten++; |
||||
} |
||||
|
||||
/* If fully drained holdoff then stop */ |
||||
if (silence->stop_holdoff_offset == silence->stop_holdoff_end) |
||||
{ |
||||
silence->stop_holdoff_offset = 0; |
||||
silence->stop_holdoff_end = 0; |
||||
silence->mode = SILENCE_STOP; |
||||
} |
||||
} |
||||
|
||||
*osamp = nrOfOutSamplesWritten; |
||||
if (silence->mode == SILENCE_STOP || *osamp == 0) |
||||
return SOX_EOF; |
||||
else |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int sox_silence_stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * silence = (priv_t *) effp->priv; |
||||
|
||||
free(silence->window); |
||||
free(silence->start_holdoff); |
||||
free(silence->stop_holdoff); |
||||
|
||||
return(SOX_SUCCESS); |
||||
} |
||||
|
||||
static int lsx_kill(sox_effect_t * effp) |
||||
{ |
||||
priv_t * silence = (priv_t *) effp->priv; |
||||
|
||||
free(silence->start_duration_str); |
||||
free(silence->stop_duration_str); |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static sox_effect_handler_t sox_silence_effect = { |
||||
"silence", |
||||
"[ -l ] above_periods [ duration threshold[d|%] ] [ below_periods duration threshold[d|%] ]", |
||||
SOX_EFF_MCHAN | SOX_EFF_MODIFY | SOX_EFF_LENGTH, |
||||
sox_silence_getopts, |
||||
sox_silence_start, |
||||
sox_silence_flow, |
||||
sox_silence_drain, |
||||
sox_silence_stop, |
||||
lsx_kill, sizeof(priv_t) |
||||
}; |
||||
|
||||
const sox_effect_handler_t *lsx_silence_effect_fn(void) |
||||
{ |
||||
return &sox_silence_effect; |
||||
} |
@ -1,157 +0,0 @@ |
||||
/* Effect: sinc filters Copyright (c) 2008-9 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "dft_filter.h" |
||||
#include <string.h> |
||||
|
||||
typedef struct { |
||||
dft_filter_priv_t base; |
||||
double att, beta, phase, Fc0, Fc1, tbw0, tbw1; |
||||
int num_taps[2]; |
||||
sox_bool round; |
||||
} priv_t; |
||||
|
||||
static int create(sox_effect_t * effp, int argc, char * * argv) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
dft_filter_priv_t * b = &p->base; |
||||
char * parse_ptr = argv[0]; |
||||
int i = 0; |
||||
lsx_getopt_t optstate; |
||||
lsx_getopt_init(argc, argv, "+ra:b:p:MILt:n:", NULL, lsx_getopt_flag_none, 1, &optstate); |
||||
|
||||
b->filter_ptr = &b->filter; |
||||
p->phase = 50; |
||||
p->beta = -1; |
||||
while (i < 2) { |
||||
int c = 1; |
||||
while (c && (c = lsx_getopt(&optstate)) != -1) switch (c) { |
||||
char * parse_ptr2; |
||||
case 'r': p->round = sox_true; break; |
||||
GETOPT_NUMERIC(optstate, 'a', att, 40 , 180) |
||||
GETOPT_NUMERIC(optstate, 'b', beta, 0 , 256) |
||||
GETOPT_NUMERIC(optstate, 'p', phase, 0, 100) |
||||
case 'M': p->phase = 0; break; |
||||
case 'I': p->phase = 25; break; |
||||
case 'L': p->phase = 50; break; |
||||
GETOPT_NUMERIC(optstate, 'n', num_taps[1], 11, 32767) |
||||
case 't': p->tbw1 = lsx_parse_frequency(optstate.arg, &parse_ptr2); |
||||
if (p->tbw1 < 1 || *parse_ptr2) return lsx_usage(effp); |
||||
break; |
||||
default: c = 0; |
||||
} |
||||
if ((p->att && p->beta >= 0) || (p->tbw1 && p->num_taps[1])) |
||||
return lsx_usage(effp); |
||||
if (!i || !p->Fc1) |
||||
p->tbw0 = p->tbw1, p->num_taps[0] = p->num_taps[1]; |
||||
if (!i++ && optstate.ind < argc) { |
||||
if (*(parse_ptr = argv[optstate.ind++]) != '-') |
||||
p->Fc0 = lsx_parse_frequency(parse_ptr, &parse_ptr); |
||||
if (*parse_ptr == '-') |
||||
p->Fc1 = lsx_parse_frequency(parse_ptr + 1, &parse_ptr); |
||||
} |
||||
} |
||||
return optstate.ind != argc || p->Fc0 < 0 || p->Fc1 < 0 || *parse_ptr ? |
||||
lsx_usage(effp) : SOX_SUCCESS; |
||||
} |
||||
|
||||
static void invert(double * h, int n) |
||||
{ |
||||
int i; |
||||
for (i = 0; i < n; ++i) |
||||
h[i] = -h[i]; |
||||
h[(n - 1) / 2] += 1; |
||||
} |
||||
|
||||
static double * lpf(double Fn, double Fc, double tbw, int * num_taps, double att, double * beta, sox_bool round) |
||||
{ |
||||
int n = *num_taps; |
||||
if ((Fc /= Fn) <= 0 || Fc >= 1) { |
||||
*num_taps = 0; |
||||
return NULL; |
||||
} |
||||
att = att? att : 120; |
||||
lsx_kaiser_params(att, Fc, (tbw? tbw / Fn : .05) * .5, beta, num_taps); |
||||
if (!n) { |
||||
n = *num_taps; |
||||
*num_taps = range_limit(n, 11, 32767); |
||||
if (round) |
||||
*num_taps = 1 + 2 * (int)((int)((*num_taps / 2) * Fc + .5) / Fc + .5); |
||||
lsx_report("num taps = %i (from %i)", *num_taps, n); |
||||
} |
||||
return lsx_make_lpf(*num_taps |= 1, Fc, *beta, 0., 1., sox_false); |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
dft_filter_t * f = p->base.filter_ptr; |
||||
|
||||
if (!f->num_taps) { |
||||
double Fn = effp->in_signal.rate * .5; |
||||
double * h[2]; |
||||
int i, n, post_peak, longer; |
||||
|
||||
if (p->Fc0 >= Fn || p->Fc1 >= Fn) { |
||||
lsx_fail("filter frequency must be less than sample-rate / 2"); |
||||
return SOX_EOF; |
||||
} |
||||
h[0] = lpf(Fn, p->Fc0, p->tbw0, &p->num_taps[0], p->att, &p->beta,p->round); |
||||
h[1] = lpf(Fn, p->Fc1, p->tbw1, &p->num_taps[1], p->att, &p->beta,p->round); |
||||
if (h[0]) |
||||
invert(h[0], p->num_taps[0]); |
||||
|
||||
longer = p->num_taps[1] > p->num_taps[0]; |
||||
n = p->num_taps[longer]; |
||||
if (h[0] && h[1]) { |
||||
for (i = 0; i < p->num_taps[!longer]; ++i) |
||||
h[longer][i + (n - p->num_taps[!longer])/2] += h[!longer][i]; |
||||
|
||||
if (p->Fc0 < p->Fc1) |
||||
invert(h[longer], n); |
||||
|
||||
free(h[!longer]); |
||||
} |
||||
if (p->phase != 50) |
||||
lsx_fir_to_phase(&h[longer], &n, &post_peak, p->phase); |
||||
else post_peak = n >> 1; |
||||
|
||||
if (effp->global_info->plot != sox_plot_off) { |
||||
char title[100]; |
||||
sprintf(title, "SoX effect: sinc filter freq=%g-%g", |
||||
p->Fc0, p->Fc1? p->Fc1 : Fn); |
||||
lsx_plot_fir(h[longer], n, effp->in_signal.rate, |
||||
effp->global_info->plot, title, -p->beta * 10 - 25, 5.); |
||||
return SOX_EOF; |
||||
} |
||||
lsx_set_dft_filter(f, h[longer], n, post_peak); |
||||
} |
||||
return lsx_dft_filter_effect_fn()->start(effp); |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_sinc_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler; |
||||
handler = *lsx_dft_filter_effect_fn(); |
||||
handler.name = "sinc"; |
||||
handler.usage = "[-a att|-b beta] [-p phase|-M|-I|-L] [-t tbw|-n taps] [freqHP][-freqLP [-t tbw|-n taps]]"; |
||||
handler.getopts = create; |
||||
handler.start = start; |
||||
handler.priv_size = sizeof(priv_t); |
||||
return &handler; |
||||
} |
@ -1,141 +0,0 @@ |
||||
/* libSoX effect: Skeleton effect used as sample for creating new effects.
|
||||
* |
||||
* Copyright 1999-2008 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" |
||||
|
||||
/* Private data for effect */ |
||||
typedef struct { |
||||
int localdata; |
||||
} priv_t; |
||||
|
||||
/*
|
||||
* Process command-line options but don't do other |
||||
* initialization now: effp->in_signal & effp->out_signal are not |
||||
* yet filled in. |
||||
*/ |
||||
static int getopts(sox_effect_t * effp, int argc, char UNUSED **argv) |
||||
{ |
||||
priv_t * UNUSED p = (priv_t *)effp->priv; |
||||
|
||||
if (argc != 2) |
||||
return lsx_usage(effp); |
||||
|
||||
p->localdata = atoi(argv[1]); |
||||
|
||||
return p->localdata > 0 ? SOX_SUCCESS : SOX_EOF; |
||||
} |
||||
|
||||
/*
|
||||
* Prepare processing. |
||||
* Do all initializations. |
||||
*/ |
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
if (effp->out_signal.channels == 1) { |
||||
lsx_fail("Can't run on mono data."); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Process up to *isamp samples from ibuf and produce up to *osamp samples |
||||
* in obuf. Write back the actual numbers of samples to *isamp and *osamp. |
||||
* Return SOX_SUCCESS or, if error occurs, SOX_EOF. |
||||
*/ |
||||
static int flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, |
||||
size_t *isamp, size_t *osamp) |
||||
{ |
||||
priv_t * UNUSED p = (priv_t *)effp->priv; |
||||
size_t len, done; |
||||
|
||||
switch (effp->out_signal.channels) { |
||||
case 2: |
||||
/* Length to process will be buffer length / 2 since we
|
||||
* work with two samples at a time. |
||||
*/ |
||||
len = min(*isamp, *osamp) / 2; |
||||
for (done = 0; done < len; done++) |
||||
{ |
||||
obuf[0] = ibuf[0]; |
||||
obuf[1] = ibuf[1]; |
||||
/* Advance buffer by 2 samples */ |
||||
ibuf += 2; |
||||
obuf += 2; |
||||
} |
||||
|
||||
*isamp = len * 2; |
||||
*osamp = len * 2; |
||||
|
||||
break; |
||||
} |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Drain out remaining samples if the effect generates any. |
||||
*/ |
||||
static int drain(sox_effect_t UNUSED * effp, sox_sample_t UNUSED *obuf, size_t *osamp) |
||||
{ |
||||
*osamp = 0; |
||||
/* Return SOX_EOF when drain
|
||||
* will not output any more samples. |
||||
* *osamp == 0 also indicates that. |
||||
*/ |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
/*
|
||||
* Do anything required when you stop reading samples. |
||||
*/ |
||||
static int stop(sox_effect_t UNUSED * effp) |
||||
{ |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Do anything required when you kill an effect. |
||||
* (free allocated memory, etc.) |
||||
*/ |
||||
static int lsx_kill(sox_effect_t UNUSED * effp) |
||||
{ |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Function returning effect descriptor. This should be the only |
||||
* externally visible object. |
||||
*/ |
||||
const sox_effect_handler_t *lsx_skel_effect_fn(void); |
||||
const sox_effect_handler_t *lsx_skel_effect_fn(void) |
||||
{ |
||||
/*
|
||||
* Effect descriptor. |
||||
* If no specific processing is needed for any of |
||||
* the 6 functions, then the function above can be deleted |
||||
* and NULL used in place of the its name below. |
||||
*/ |
||||
static sox_effect_handler_t sox_skel_effect = { |
||||
"skel", "[OPTION]", SOX_EFF_MCHAN, |
||||
getopts, start, flow, drain, stop, lsx_kill, sizeof(priv_t) |
||||
}; |
||||
return &sox_skel_effect; |
||||
} |
@ -1,532 +0,0 @@ |
||||
/* libSoX libsndfile formats.
|
||||
* |
||||
* Copyright 2007 Reuben Thomas <rrt@sc3d.org> |
||||
* Copyright 1999-2005 Erik de Castro Lopo <eridk@mega-nerd.com> |
||||
* |
||||
* 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 <assert.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <ctype.h> |
||||
#include <sndfile.h> |
||||
|
||||
#define LOG_MAX 2048 /* As per the SFC_GET_LOG_INFO example */ |
||||
|
||||
static const char* const sndfile_library_names[] = |
||||
{ |
||||
#ifdef DL_LIBSNDFILE |
||||
"libsndfile", |
||||
"libsndfile-1", |
||||
"cygsndfile-1", |
||||
#endif |
||||
NULL |
||||
}; |
||||
|
||||
#ifdef DL_LIBSNDFILE |
||||
#define SNDFILE_FUNC LSX_DLENTRY_DYNAMIC |
||||
#define SNDFILE_FUNC_STOP LSX_DLENTRY_STUB |
||||
#else |
||||
#define SNDFILE_FUNC LSX_DLENTRY_STATIC |
||||
#ifdef HACKED_LSF |
||||
#define SNDFILE_FUNC_STOP LSX_DLENTRY_STATIC |
||||
#else |
||||
#define SNDFILE_FUNC_STOP LSX_DLENTRY_STUB |
||||
#endif |
||||
#endif /* DL_LIBSNDFILE */ |
||||
|
||||
#define SNDFILE_FUNC_OPEN(f,x) \ |
||||
SNDFILE_FUNC(f,x, SNDFILE*, sf_open_virtual, (SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user_data)) |
||||
|
||||
#define SNDFILE_FUNC_ENTRIES(f,x) \ |
||||
SNDFILE_FUNC_OPEN(f,x) \
|
||||
SNDFILE_FUNC_STOP(f,x, int, sf_stop, (SNDFILE *sndfile)) \
|
||||
SNDFILE_FUNC(f,x, int, sf_close, (SNDFILE *sndfile)) \
|
||||
SNDFILE_FUNC(f,x, int, sf_format_check, (const SF_INFO *info)) \
|
||||
SNDFILE_FUNC(f,x, int, sf_command, (SNDFILE *sndfile, int command, void *data, int datasize)) \
|
||||
SNDFILE_FUNC(f,x, sf_count_t, sf_read_int, (SNDFILE *sndfile, int *ptr, sf_count_t items)) \
|
||||
SNDFILE_FUNC(f,x, sf_count_t, sf_write_int, (SNDFILE *sndfile, const int *ptr, sf_count_t items)) \
|
||||
SNDFILE_FUNC(f,x, sf_count_t, sf_seek, (SNDFILE *sndfile, sf_count_t frames, int whence)) \
|
||||
SNDFILE_FUNC(f,x, const char*, sf_strerror, (SNDFILE *sndfile)) |
||||
|
||||
/* Private data for sndfile files */ |
||||
typedef struct { |
||||
SNDFILE *sf_file; |
||||
SF_INFO *sf_info; |
||||
char * log_buffer; |
||||
char const * log_buffer_ptr; |
||||
LSX_DLENTRIES_TO_PTRS(SNDFILE_FUNC_ENTRIES, sndfile_dl); |
||||
} priv_t; |
||||
|
||||
/*
|
||||
* Drain LSF's wonderful log buffer |
||||
*/ |
||||
static void drain_log_buffer(sox_format_t * ft) |
||||
{ |
||||
priv_t * sf = (priv_t *)ft->priv; |
||||
sf->sf_command(sf->sf_file, SFC_GET_LOG_INFO, sf->log_buffer, LOG_MAX); |
||||
while (*sf->log_buffer_ptr) { |
||||
static char const warning_prefix[] = "*** Warning : "; |
||||
char const * end = strchr(sf->log_buffer_ptr, '\n'); |
||||
if (!end) |
||||
end = strchr(sf->log_buffer_ptr, '\0'); |
||||
if (!strncmp(sf->log_buffer_ptr, warning_prefix, strlen(warning_prefix))) { |
||||
sf->log_buffer_ptr += strlen(warning_prefix); |
||||
lsx_warn("`%s': %.*s", |
||||
ft->filename, (int)(end - sf->log_buffer_ptr), sf->log_buffer_ptr); |
||||
} else |
||||
lsx_debug("`%s': %.*s", |
||||
ft->filename, (int)(end - sf->log_buffer_ptr), sf->log_buffer_ptr); |
||||
sf->log_buffer_ptr = end; |
||||
if (*sf->log_buffer_ptr == '\n') |
||||
++sf->log_buffer_ptr; |
||||
} |
||||
} |
||||
|
||||
/* Make libsndfile subtype from sample encoding and size */ |
||||
static int ft_enc(unsigned size, sox_encoding_t e) |
||||
{ |
||||
if (e == SOX_ENCODING_ULAW && size == 8) return SF_FORMAT_ULAW; |
||||
if (e == SOX_ENCODING_ALAW && size == 8) return SF_FORMAT_ALAW; |
||||
if (e == SOX_ENCODING_SIGN2 && size == 8) return SF_FORMAT_PCM_S8; |
||||
if (e == SOX_ENCODING_SIGN2 && size == 16) return SF_FORMAT_PCM_16; |
||||
if (e == SOX_ENCODING_SIGN2 && size == 24) return SF_FORMAT_PCM_24; |
||||
if (e == SOX_ENCODING_SIGN2 && size == 32) return SF_FORMAT_PCM_32; |
||||
if (e == SOX_ENCODING_UNSIGNED && size == 8) return SF_FORMAT_PCM_U8; |
||||
if (e == SOX_ENCODING_FLOAT && size == 32) return SF_FORMAT_FLOAT; |
||||
if (e == SOX_ENCODING_FLOAT && size == 64) return SF_FORMAT_DOUBLE; |
||||
if (e == SOX_ENCODING_G721 && size == 4) return SF_FORMAT_G721_32; |
||||
if (e == SOX_ENCODING_G723 && size == 3) return SF_FORMAT_G723_24; |
||||
if (e == SOX_ENCODING_G723 && size == 5) return SF_FORMAT_G723_40; |
||||
if (e == SOX_ENCODING_MS_ADPCM && size == 4) return SF_FORMAT_MS_ADPCM; |
||||
if (e == SOX_ENCODING_IMA_ADPCM && size == 4) return SF_FORMAT_IMA_ADPCM; |
||||
if (e == SOX_ENCODING_OKI_ADPCM && size == 4) return SF_FORMAT_VOX_ADPCM; |
||||
if (e == SOX_ENCODING_DPCM && size == 8) return SF_FORMAT_DPCM_8; |
||||
if (e == SOX_ENCODING_DPCM && size == 16) return SF_FORMAT_DPCM_16; |
||||
if (e == SOX_ENCODING_DWVW && size == 12) return SF_FORMAT_DWVW_12; |
||||
if (e == SOX_ENCODING_DWVW && size == 16) return SF_FORMAT_DWVW_16; |
||||
if (e == SOX_ENCODING_DWVW && size == 24) return SF_FORMAT_DWVW_24; |
||||
if (e == SOX_ENCODING_DWVWN && size == 0) return SF_FORMAT_DWVW_N; |
||||
if (e == SOX_ENCODING_GSM && size == 0) return SF_FORMAT_GSM610; |
||||
if (e == SOX_ENCODING_FLAC && size == 8) return SF_FORMAT_PCM_S8; |
||||
if (e == SOX_ENCODING_FLAC && size == 16) return SF_FORMAT_PCM_16; |
||||
if (e == SOX_ENCODING_FLAC && size == 24) return SF_FORMAT_PCM_24; |
||||
if (e == SOX_ENCODING_FLAC && size == 32) return SF_FORMAT_PCM_32; |
||||
return 0; /* Bad encoding */ |
||||
} |
||||
|
||||
/* Convert format's encoding type to libSoX encoding type & size. */ |
||||
static sox_encoding_t sox_enc(int ft_encoding, unsigned * size) |
||||
{ |
||||
int sub = ft_encoding & SF_FORMAT_SUBMASK; |
||||
int type = ft_encoding & SF_FORMAT_TYPEMASK; |
||||
|
||||
if (type == SF_FORMAT_FLAC) switch (sub) { |
||||
case SF_FORMAT_PCM_S8 : *size = 8; return SOX_ENCODING_FLAC; |
||||
case SF_FORMAT_PCM_16 : *size = 16; return SOX_ENCODING_FLAC; |
||||
case SF_FORMAT_PCM_24 : *size = 24; return SOX_ENCODING_FLAC; |
||||
} |
||||
switch (sub) { |
||||
case SF_FORMAT_ULAW : *size = 8; return SOX_ENCODING_ULAW; |
||||
case SF_FORMAT_ALAW : *size = 8; return SOX_ENCODING_ALAW; |
||||
case SF_FORMAT_PCM_S8 : *size = 8; return SOX_ENCODING_SIGN2; |
||||
case SF_FORMAT_PCM_16 : *size = 16; return SOX_ENCODING_SIGN2; |
||||
case SF_FORMAT_PCM_24 : *size = 24; return SOX_ENCODING_SIGN2; |
||||
case SF_FORMAT_PCM_32 : *size = 32; return SOX_ENCODING_SIGN2; |
||||
case SF_FORMAT_PCM_U8 : *size = 8; return SOX_ENCODING_UNSIGNED; |
||||
case SF_FORMAT_FLOAT : *size = 32; return SOX_ENCODING_FLOAT; |
||||
case SF_FORMAT_DOUBLE : *size = 64; return SOX_ENCODING_FLOAT; |
||||
case SF_FORMAT_G721_32 : *size = 4; return SOX_ENCODING_G721; |
||||
case SF_FORMAT_G723_24 : *size = 3; return SOX_ENCODING_G723; |
||||
case SF_FORMAT_G723_40 : *size = 5; return SOX_ENCODING_G723; |
||||
case SF_FORMAT_MS_ADPCM : *size = 4; return SOX_ENCODING_MS_ADPCM; |
||||
case SF_FORMAT_IMA_ADPCM: *size = 4; return SOX_ENCODING_IMA_ADPCM; |
||||
case SF_FORMAT_VOX_ADPCM: *size = 4; return SOX_ENCODING_OKI_ADPCM; |
||||
case SF_FORMAT_DPCM_8 : *size = 8; return SOX_ENCODING_DPCM; |
||||
case SF_FORMAT_DPCM_16 : *size = 16; return SOX_ENCODING_DPCM; |
||||
case SF_FORMAT_DWVW_12 : *size = 12; return SOX_ENCODING_DWVW; |
||||
case SF_FORMAT_DWVW_16 : *size = 16; return SOX_ENCODING_DWVW; |
||||
case SF_FORMAT_DWVW_24 : *size = 24; return SOX_ENCODING_DWVW; |
||||
case SF_FORMAT_DWVW_N : *size = 0; return SOX_ENCODING_DWVWN; |
||||
case SF_FORMAT_GSM610 : *size = 0; return SOX_ENCODING_GSM; |
||||
default : *size = 0; return SOX_ENCODING_UNKNOWN; |
||||
} |
||||
} |
||||
|
||||
static struct { |
||||
const char *ext; |
||||
int format; |
||||
} format_map[] = |
||||
{ |
||||
{ "aif", SF_FORMAT_AIFF }, |
||||
{ "aiff", SF_FORMAT_AIFF }, |
||||
{ "wav", SF_FORMAT_WAV }, |
||||
{ "au", SF_FORMAT_AU }, |
||||
{ "snd", SF_FORMAT_AU }, |
||||
{ "caf", SF_FORMAT_CAF }, |
||||
{ "flac", SF_FORMAT_FLAC }, |
||||
{ "wve", SF_FORMAT_WVE }, |
||||
{ "ogg", SF_FORMAT_OGG }, |
||||
{ "svx", SF_FORMAT_SVX }, |
||||
{ "8svx", SF_FORMAT_SVX }, |
||||
{ "paf", SF_ENDIAN_BIG | SF_FORMAT_PAF }, |
||||
{ "fap", SF_ENDIAN_LITTLE | SF_FORMAT_PAF }, |
||||
{ "gsm", SF_FORMAT_RAW | SF_FORMAT_GSM610 }, |
||||
{ "nist", SF_FORMAT_NIST }, |
||||
{ "sph", SF_FORMAT_NIST }, |
||||
{ "ircam", SF_FORMAT_IRCAM }, |
||||
{ "sf", SF_FORMAT_IRCAM }, |
||||
{ "voc", SF_FORMAT_VOC }, |
||||
{ "w64", SF_FORMAT_W64 }, |
||||
{ "raw", SF_FORMAT_RAW }, |
||||
{ "mat4", SF_FORMAT_MAT4 }, |
||||
{ "mat5", SF_FORMAT_MAT5 }, |
||||
{ "mat", SF_FORMAT_MAT4 }, |
||||
{ "pvf", SF_FORMAT_PVF }, |
||||
{ "sds", SF_FORMAT_SDS }, |
||||
{ "sd2", SF_FORMAT_SD2 }, |
||||
{ "vox", SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM }, |
||||
{ "xi", SF_FORMAT_XI } |
||||
}; |
||||
|
||||
static int sf_stop_stub(SNDFILE *sndfile UNUSED) |
||||
{ |
||||
return 1; |
||||
} |
||||
|
||||
static sf_count_t vio_get_filelen(void *user_data) |
||||
{ |
||||
sox_format_t *ft = (sox_format_t *)user_data; |
||||
|
||||
/* lsf excepts unbuffered I/O behavior for get_filelen() so force that */ |
||||
lsx_flush(ft); |
||||
|
||||
return (sf_count_t)lsx_filelength((sox_format_t *)user_data); |
||||
} |
||||
|
||||
static sf_count_t vio_seek(sf_count_t offset, int whence, void *user_data) |
||||
{ |
||||
return lsx_seeki((sox_format_t *)user_data, (off_t)offset, whence); |
||||
} |
||||
|
||||
static sf_count_t vio_read(void *ptr, sf_count_t count, void *user_data) |
||||
{ |
||||
return lsx_readbuf((sox_format_t *)user_data, ptr, (size_t)count); |
||||
} |
||||
|
||||
static sf_count_t vio_write(const void *ptr, sf_count_t count, void *user_data) |
||||
{ |
||||
return lsx_writebuf((sox_format_t *)user_data, ptr, (size_t)count); |
||||
} |
||||
|
||||
static sf_count_t vio_tell(void *user_data) |
||||
{ |
||||
return lsx_tell((sox_format_t *)user_data); |
||||
} |
||||
|
||||
static SF_VIRTUAL_IO vio = |
||||
{ |
||||
vio_get_filelen, |
||||
vio_seek, |
||||
vio_read, |
||||
vio_write, |
||||
vio_tell |
||||
}; |
||||
|
||||
/* Convert file name or type to libsndfile format */ |
||||
static int name_to_format(const char *name) |
||||
{ |
||||
int k; |
||||
#define FILE_TYPE_BUFLEN (size_t)15 |
||||
char buffer[FILE_TYPE_BUFLEN + 1], *cptr; |
||||
|
||||
if ((cptr = strrchr(name, '.')) != NULL) { |
||||
strncpy(buffer, cptr + 1, FILE_TYPE_BUFLEN); |
||||
buffer[FILE_TYPE_BUFLEN] = '\0'; |
||||
|
||||
for (k = 0; buffer[k]; k++) |
||||
buffer[k] = tolower((buffer[k])); |
||||
} else { |
||||
strncpy(buffer, name, FILE_TYPE_BUFLEN); |
||||
buffer[FILE_TYPE_BUFLEN] = '\0'; |
||||
} |
||||
|
||||
for (k = 0; k < (int)(sizeof(format_map) / sizeof(format_map [0])); k++) { |
||||
if (strcmp(buffer, format_map[k].ext) == 0) |
||||
return format_map[k].format; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int start(sox_format_t * ft) |
||||
{ |
||||
priv_t * sf = (priv_t *)ft->priv; |
||||
int subtype = ft_enc(ft->encoding.bits_per_sample? ft->encoding.bits_per_sample : ft->signal.precision, ft->encoding.encoding); |
||||
int open_library_result; |
||||
|
||||
LSX_DLLIBRARY_OPEN( |
||||
sf, |
||||
sndfile_dl, |
||||
SNDFILE_FUNC_ENTRIES, |
||||
"libsndfile library", |
||||
sndfile_library_names, |
||||
open_library_result); |
||||
if (open_library_result) |
||||
return SOX_EOF; |
||||
|
||||
sf->log_buffer_ptr = sf->log_buffer = lsx_malloc((size_t)LOG_MAX); |
||||
sf->sf_info = lsx_calloc(1, sizeof(SF_INFO)); |
||||
|
||||
/* Copy format info */ |
||||
if (subtype) { |
||||
if (strcmp(ft->filetype, "sndfile") == 0) |
||||
sf->sf_info->format = name_to_format(ft->filename) | subtype; |
||||
else |
||||
sf->sf_info->format = name_to_format(ft->filetype) | subtype; |
||||
} |
||||
sf->sf_info->samplerate = (int)ft->signal.rate; |
||||
sf->sf_info->channels = ft->signal.channels; |
||||
if (ft->signal.channels) |
||||
sf->sf_info->frames = ft->signal.length / ft->signal.channels; |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int check_read_params(sox_format_t * ft, unsigned channels, |
||||
sox_rate_t rate, sox_encoding_t encoding, unsigned bits_per_sample, uint64_t length) |
||||
{ |
||||
ft->signal.length = length; |
||||
|
||||
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 (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; |
||||
} |
||||
|
||||
/*
|
||||
* Open file in sndfile. |
||||
*/ |
||||
static int startread(sox_format_t * ft) |
||||
{ |
||||
priv_t * sf = (priv_t *)ft->priv; |
||||
unsigned bits_per_sample; |
||||
sox_encoding_t encoding; |
||||
sox_rate_t rate; |
||||
|
||||
if (start(ft) == SOX_EOF) |
||||
return SOX_EOF; |
||||
|
||||
sf->sf_file = sf->sf_open_virtual(&vio, SFM_READ, sf->sf_info, ft); |
||||
drain_log_buffer(ft); |
||||
|
||||
if (sf->sf_file == NULL) { |
||||
memset(ft->sox_errstr, 0, sizeof(ft->sox_errstr)); |
||||
strncpy(ft->sox_errstr, sf->sf_strerror(sf->sf_file), sizeof(ft->sox_errstr)-1); |
||||
free(sf->sf_file); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
if (!(encoding = sox_enc(sf->sf_info->format, &bits_per_sample))) { |
||||
lsx_fail_errno(ft, SOX_EFMT, "unsupported sndfile encoding %#x", sf->sf_info->format); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
/* Don't believe LSF's rate for raw files */ |
||||
if ((sf->sf_info->format & SF_FORMAT_TYPEMASK) == SF_FORMAT_RAW && !ft->signal.rate) { |
||||
lsx_warn("`%s': sample rate not specified; trying 8kHz", ft->filename); |
||||
rate = 8000; |
||||
} |
||||
else rate = sf->sf_info->samplerate; |
||||
|
||||
if ((sf->sf_info->format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT) { |
||||
sf->sf_command(sf->sf_file, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE); |
||||
sf->sf_command(sf->sf_file, SFC_SET_CLIPPING, NULL, SF_TRUE); |
||||
} |
||||
|
||||
#if 0 /* FIXME */
|
||||
sox_append_comments(&ft->oob.comments, buf); |
||||
#endif |
||||
|
||||
return check_read_params(ft, (unsigned)sf->sf_info->channels, rate, |
||||
encoding, bits_per_sample, (uint64_t)(sf->sf_info->frames * sf->sf_info->channels)); |
||||
} |
||||
|
||||
/*
|
||||
* Read up to len samples of type sox_sample_t from file into buf[]. |
||||
* Return number of samples read. |
||||
*/ |
||||
static size_t read_samples(sox_format_t * ft, sox_sample_t *buf, size_t len) |
||||
{ |
||||
priv_t * sf = (priv_t *)ft->priv; |
||||
/* FIXME: We assume int == sox_sample_t here */ |
||||
return (size_t)sf->sf_read_int(sf->sf_file, (int *)buf, (sf_count_t)len); |
||||
} |
||||
|
||||
/*
|
||||
* Close file for libsndfile (this doesn't close the file handle) |
||||
*/ |
||||
static int stopread(sox_format_t * ft) |
||||
{ |
||||
priv_t * sf = (priv_t *)ft->priv; |
||||
sf->sf_stop(sf->sf_file); |
||||
drain_log_buffer(ft); |
||||
sf->sf_close(sf->sf_file); |
||||
LSX_DLLIBRARY_CLOSE(sf, sndfile_dl); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int startwrite(sox_format_t * ft) |
||||
{ |
||||
priv_t * sf = (priv_t *)ft->priv; |
||||
|
||||
if (start(ft) == SOX_EOF) |
||||
return SOX_EOF; |
||||
|
||||
/* If output format is invalid, try to find a sensible default */ |
||||
if (!sf->sf_format_check(sf->sf_info)) { |
||||
SF_FORMAT_INFO format_info; |
||||
int i, count; |
||||
|
||||
sf->sf_command(sf->sf_file, SFC_GET_SIMPLE_FORMAT_COUNT, &count, (int) sizeof(int)); |
||||
for (i = 0; i < count; i++) { |
||||
format_info.format = i; |
||||
sf->sf_command(sf->sf_file, SFC_GET_SIMPLE_FORMAT, &format_info, (int) sizeof(format_info)); |
||||
if ((format_info.format & SF_FORMAT_TYPEMASK) == (sf->sf_info->format & SF_FORMAT_TYPEMASK)) { |
||||
sf->sf_info->format = format_info.format; |
||||
/* FIXME: Print out exactly what we chose, needs sndfile ->
|
||||
sox encoding conversion functions */ |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!sf->sf_format_check(sf->sf_info)) { |
||||
lsx_fail("cannot find a usable output encoding"); |
||||
return SOX_EOF; |
||||
} |
||||
if ((sf->sf_info->format & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) |
||||
lsx_warn("cannot use desired output encoding, choosing default"); |
||||
} |
||||
|
||||
sf->sf_file = sf->sf_open_virtual(&vio, SFM_WRITE, sf->sf_info, ft); |
||||
drain_log_buffer(ft); |
||||
|
||||
if (sf->sf_file == NULL) { |
||||
memset(ft->sox_errstr, 0, sizeof(ft->sox_errstr)); |
||||
strncpy(ft->sox_errstr, sf->sf_strerror(sf->sf_file), sizeof(ft->sox_errstr)-1); |
||||
free(sf->sf_file); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
if ((sf->sf_info->format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT) |
||||
sf->sf_command(sf->sf_file, SFC_SET_SCALE_INT_FLOAT_WRITE, NULL, SF_TRUE); |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Write len samples of type sox_sample_t from buf[] to file. |
||||
* Return number of samples written. |
||||
*/ |
||||
static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t len) |
||||
{ |
||||
priv_t * sf = (priv_t *)ft->priv; |
||||
/* FIXME: We assume int == sox_sample_t here */ |
||||
return (size_t)sf->sf_write_int(sf->sf_file, (int *)buf, (sf_count_t)len); |
||||
} |
||||
|
||||
/*
|
||||
* Close file for libsndfile (this doesn't close the file handle) |
||||
*/ |
||||
static int stopwrite(sox_format_t * ft) |
||||
{ |
||||
priv_t * sf = (priv_t *)ft->priv; |
||||
sf->sf_stop(sf->sf_file); |
||||
drain_log_buffer(ft); |
||||
sf->sf_close(sf->sf_file); |
||||
LSX_DLLIBRARY_CLOSE(sf, sndfile_dl); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int seek(sox_format_t * ft, uint64_t offset) |
||||
{ |
||||
priv_t * sf = (priv_t *)ft->priv; |
||||
sf->sf_seek(sf->sf_file, (sf_count_t)(offset / ft->signal.channels), SEEK_CUR); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
LSX_FORMAT_HANDLER(sndfile) |
||||
{ |
||||
static char const * const names[] = { |
||||
"sndfile", /* Special type to force use of sndfile for the following: */ |
||||
/* LSF implementation of formats built in to SoX: */ |
||||
/* "aif", */ |
||||
/* "au", */ |
||||
/* "gsm", */ |
||||
/* "nist", */ |
||||
/* "raw", */ |
||||
/* "sf", "ircam", */ |
||||
/* "snd", */ |
||||
/* "svx", */ |
||||
/* "voc", */ |
||||
/* "vox", */ |
||||
/* "wav", */ |
||||
/* LSF wrappers of formats already wrapped in SoX: */ |
||||
/* "flac", */ |
||||
|
||||
"sds", /* ?? */ |
||||
NULL |
||||
}; |
||||
|
||||
static unsigned const write_encodings[] = { |
||||
SOX_ENCODING_SIGN2, 16, 24, 32, 8, 0, |
||||
SOX_ENCODING_UNSIGNED, 8, 0, |
||||
SOX_ENCODING_FLOAT, 32, 64, 0, |
||||
SOX_ENCODING_ALAW, 8, 0, |
||||
SOX_ENCODING_ULAW, 8, 0, |
||||
SOX_ENCODING_IMA_ADPCM, 4, 0, |
||||
SOX_ENCODING_MS_ADPCM, 4, 0, |
||||
SOX_ENCODING_OKI_ADPCM, 4, 0, |
||||
SOX_ENCODING_GSM, 0, |
||||
0}; |
||||
|
||||
static sox_format_handler_t const format = {SOX_LIB_VERSION_CODE, |
||||
"Pseudo format to use libsndfile", names, 0, |
||||
startread, read_samples, stopread, |
||||
startwrite, write_samples, stopwrite, |
||||
seek, write_encodings, NULL, sizeof(priv_t) |
||||
}; |
||||
|
||||
return &format; |
||||
} |
@ -1,246 +0,0 @@ |
||||
/*
|
||||
* libsndio sound handler |
||||
* |
||||
* Copyright (c) 2009 Alexandre Ratchov <alex@caoua.org> |
||||
* |
||||
* Permission to use, copy, modify, and distribute this software for any |
||||
* purpose with or without fee is hereby granted, provided that the above |
||||
* copyright notice and this permission notice appear in all copies. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
*/ |
||||
#include "sox_i.h" |
||||
#include <string.h> |
||||
#include <sndio.h> |
||||
|
||||
struct sndio_priv { |
||||
struct sio_hdl *hdl; /* handle to speak to libsndio */ |
||||
struct sio_par par; /* current device parameters */ |
||||
#define SNDIO_BUFSZ 0x1000 |
||||
unsigned char buf[SNDIO_BUFSZ]; /* temp buffer for converions */ |
||||
}; |
||||
|
||||
/*
|
||||
* convert ``count'' samples from sox encoding to sndio encoding |
||||
*/ |
||||
static void encode(struct sio_par *par, |
||||
sox_sample_t const *idata, unsigned char *odata, unsigned count) |
||||
{ |
||||
int obnext, osnext, s, osigbit; |
||||
unsigned oshift, obps, i; |
||||
|
||||
obps = par->bps; |
||||
osigbit = par->sig ? 0 : 1 << (par->bits - 1); |
||||
oshift = 32 - (par->msb ? par->bps * 8 : par->bits); |
||||
if (par->le) { |
||||
obnext = 1; |
||||
osnext = 0; |
||||
} else { |
||||
odata += par->bps - 1; |
||||
obnext = -1; |
||||
osnext = 2 * par->bps; |
||||
} |
||||
for (; count > 0; count--) { |
||||
s = (*idata++ >> oshift) ^ osigbit; |
||||
for (i = obps; i > 0; i--) { |
||||
*odata = (unsigned char)s; |
||||
s >>= 8; |
||||
odata += obnext; |
||||
} |
||||
odata += osnext; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* convert ``count'' samples from sndio encoding to sox encoding |
||||
*/ |
||||
static void decode(struct sio_par *par, |
||||
unsigned char *idata, sox_sample_t *odata, unsigned count) |
||||
{ |
||||
unsigned ishift, ibps, i; |
||||
int s = 0xdeadbeef, ibnext, isnext, isigbit; |
||||
|
||||
ibps = par->bps; |
||||
isigbit = par->sig ? 0 : 1 << (par->bits - 1); |
||||
ishift = 32 - (par->msb ? par->bps * 8 : par->bits); |
||||
if (par->le) { |
||||
idata += par->bps - 1; |
||||
ibnext = -1; |
||||
isnext = 2 * par->bps; |
||||
} else { |
||||
ibnext = 1; |
||||
isnext = 0; |
||||
} |
||||
for (; count > 0; count--) { |
||||
for (i = ibps; i > 0; i--) { |
||||
s <<= 8; |
||||
s |= *idata; |
||||
idata += ibnext; |
||||
} |
||||
idata += isnext; |
||||
*odata++ = (s ^ isigbit) << ishift; |
||||
} |
||||
} |
||||
|
||||
static int startany(sox_format_t *ft, unsigned mode) |
||||
{ |
||||
struct sndio_priv *p = (struct sndio_priv *)ft->priv; |
||||
struct sio_par reqpar; |
||||
char *device; |
||||
|
||||
device = ft->filename; |
||||
if (strcmp("default", device) == 0) |
||||
device = NULL; |
||||
|
||||
p->hdl = sio_open(device, mode, 0); |
||||
if (p->hdl == NULL) |
||||
return SOX_EOF; |
||||
/*
|
||||
* set specified parameters, leaving others to the defaults |
||||
*/ |
||||
sio_initpar(&reqpar); |
||||
if (ft->signal.rate > 0) |
||||
reqpar.rate = ft->signal.rate; |
||||
if (ft->signal.channels > 0) { |
||||
if (mode == SIO_PLAY) |
||||
reqpar.pchan = ft->signal.channels; |
||||
else |
||||
reqpar.rchan = ft->signal.channels; |
||||
} |
||||
switch (ft->encoding.encoding) { |
||||
case SOX_ENCODING_SIGN2: |
||||
reqpar.sig = 1; |
||||
break; |
||||
case SOX_ENCODING_UNSIGNED: |
||||
reqpar.sig = 0; |
||||
break; |
||||
default: |
||||
break; /* use device default */ |
||||
} |
||||
if (ft->encoding.bits_per_sample > 0) |
||||
reqpar.bits = ft->encoding.bits_per_sample; |
||||
else if (ft->signal.precision > 0) |
||||
reqpar.bits = ft->signal.precision; |
||||
else |
||||
reqpar.bits = SOX_DEFAULT_PRECISION; |
||||
reqpar.bps = (reqpar.bits + 7) / 8; |
||||
reqpar.msb = 1; |
||||
if (ft->encoding.reverse_bytes != sox_option_default) { |
||||
reqpar.le = SIO_LE_NATIVE; |
||||
if (ft->encoding.reverse_bytes) |
||||
reqpar.le = !reqpar.le; |
||||
} |
||||
if (!sio_setpar(p->hdl, &reqpar) || |
||||
!sio_getpar(p->hdl, &p->par)) |
||||
goto failed; |
||||
ft->signal.channels = (mode == SIO_PLAY) ? p->par.pchan : p->par.rchan; |
||||
ft->signal.precision = p->par.bits; |
||||
ft->signal.rate = p->par.rate; |
||||
ft->encoding.encoding = p->par.sig ? SOX_ENCODING_SIGN2 : SOX_ENCODING_UNSIGNED; |
||||
ft->encoding.bits_per_sample = p->par.bps * 8; |
||||
ft->encoding.reverse_bytes = SIO_LE_NATIVE ? !p->par.le : p->par.le; |
||||
ft->encoding.reverse_nibbles = sox_option_no; |
||||
ft->encoding.reverse_bits = sox_option_no; |
||||
|
||||
if (!sio_start(p->hdl)) |
||||
goto failed; |
||||
return SOX_SUCCESS; |
||||
failed: |
||||
sio_close(p->hdl); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
static int stopany(sox_format_t *ft) |
||||
{ |
||||
sio_close(((struct sndio_priv *)ft->priv)->hdl); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int startread(sox_format_t *ft) |
||||
{ |
||||
return startany(ft, SIO_REC); |
||||
} |
||||
|
||||
static int startwrite(sox_format_t *ft) |
||||
{ |
||||
return startany(ft, SIO_PLAY); |
||||
} |
||||
|
||||
static size_t readsamples(sox_format_t *ft, sox_sample_t *buf, size_t len) |
||||
{ |
||||
struct sndio_priv *p = (struct sndio_priv *)ft->priv; |
||||
unsigned char partial[4]; |
||||
unsigned cpb, cc, pc; |
||||
size_t todo, n; |
||||
|
||||
pc = 0; |
||||
todo = len * p->par.bps; |
||||
cpb = SNDIO_BUFSZ - (SNDIO_BUFSZ % p->par.bps); |
||||
while (todo > 0) { |
||||
memcpy(p->buf, partial, (size_t)pc); |
||||
cc = cpb - pc; |
||||
if (cc > todo) |
||||
cc = todo; |
||||
n = sio_read(p->hdl, p->buf + pc, (size_t)cc); |
||||
if (n == 0 && sio_eof(p->hdl)) |
||||
break; |
||||
n += pc; |
||||
pc = n % p->par.bps; |
||||
n -= pc; |
||||
memcpy(partial, p->buf + n, (size_t)pc); |
||||
decode(&p->par, p->buf, buf, (unsigned)(n / p->par.bps)); |
||||
buf += n / p->par.bps; |
||||
todo -= n; |
||||
} |
||||
return len - todo / p->par.bps; |
||||
} |
||||
|
||||
static size_t writesamples(sox_format_t *ft, const sox_sample_t *buf, size_t len) |
||||
{ |
||||
struct sndio_priv *p = (struct sndio_priv *)ft->priv; |
||||
unsigned sc, spb; |
||||
size_t n, todo; |
||||
|
||||
todo = len; |
||||
spb = SNDIO_BUFSZ / p->par.bps; |
||||
while (todo > 0) { |
||||
sc = spb; |
||||
if (sc > todo) |
||||
sc = todo; |
||||
encode(&p->par, buf, p->buf, sc); |
||||
n = sio_write(p->hdl, p->buf, (size_t)(sc * p->par.bps)); |
||||
if (n == 0 && sio_eof(p->hdl)) |
||||
break; |
||||
n /= p->par.bps; |
||||
todo -= n; |
||||
buf += n; |
||||
} |
||||
return len - todo; |
||||
} |
||||
|
||||
LSX_FORMAT_HANDLER(sndio) |
||||
{ |
||||
static char const * const names[] = {"sndio", NULL}; |
||||
static unsigned const write_encodings[] = { |
||||
SOX_ENCODING_SIGN2, 32, 24, 16, 8, 0, |
||||
SOX_ENCODING_UNSIGNED, 32, 24, 16, 8, 0, |
||||
0 |
||||
}; |
||||
static sox_format_handler_t const handler = { |
||||
SOX_LIB_VERSION_CODE, |
||||
"libsndio device driver", |
||||
names, |
||||
SOX_FILE_DEVICE | SOX_FILE_NOSTDIO, |
||||
startread, readsamples, stopany, |
||||
startwrite, writesamples, stopany, |
||||
NULL, write_encodings, NULL, |
||||
sizeof(struct sndio_priv) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,108 +0,0 @@ |
||||
/* libSoX file format: SoX native (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> |
||||
|
||||
static char const magic[2][4] = {".SoX", "XoS."}; |
||||
#define FIXED_HDR (4 + 8 + 8 + 4 + 4) /* Without magic */ |
||||
|
||||
static int startread(sox_format_t * ft) |
||||
{ |
||||
char magic_[sizeof(magic[0])]; |
||||
uint32_t headers_bytes, num_channels, comments_bytes; |
||||
uint64_t num_samples; |
||||
double rate; |
||||
|
||||
if (lsx_readdw(ft, (uint32_t *)&magic_)) |
||||
return SOX_EOF; |
||||
|
||||
if (memcmp(magic[MACHINE_IS_BIGENDIAN], magic_, sizeof(magic_))) { |
||||
if (memcmp(magic[MACHINE_IS_LITTLEENDIAN], magic_, sizeof(magic_))) { |
||||
lsx_fail_errno(ft, SOX_EHDR, "can't find sox file format identifier"); |
||||
return SOX_EOF; |
||||
} |
||||
ft->encoding.reverse_bytes = !ft->encoding.reverse_bytes; |
||||
lsx_report("file is opposite endian"); |
||||
} |
||||
if (lsx_readdw(ft, &headers_bytes) || |
||||
lsx_readqw(ft, &num_samples) || |
||||
lsx_readdf(ft, &rate) || |
||||
lsx_readdw(ft, &num_channels) || |
||||
lsx_readdw(ft, &comments_bytes)) |
||||
return SOX_EOF; |
||||
|
||||
if (((headers_bytes + 4) & 7) || |
||||
comments_bytes > 0x40000000 || /* max 1 GB */ |
||||
headers_bytes < FIXED_HDR + comments_bytes || |
||||
(num_channels > 65535)) /* Reserve top 16 bits */ { |
||||
lsx_fail_errno(ft, SOX_EHDR, "invalid sox file format header"); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
if (comments_bytes) { |
||||
char * buf = lsx_calloc(1, (size_t)comments_bytes + 1); /* ensure nul-terminated */ |
||||
if (lsx_readchars(ft, buf, (size_t)comments_bytes) != SOX_SUCCESS) { |
||||
free(buf); |
||||
return SOX_EOF; |
||||
} |
||||
sox_append_comments(&ft->oob.comments, buf); |
||||
free(buf); |
||||
} |
||||
|
||||
/* Consume any bytes after the comments and before the start of the audio
|
||||
* block. These may include comment padding up to a multiple of 8 bytes, |
||||
* and further header information that might be defined in future. */ |
||||
lsx_seeki(ft, (off_t)(headers_bytes - FIXED_HDR - comments_bytes), SEEK_CUR); |
||||
|
||||
return lsx_check_read_params( |
||||
ft, num_channels, rate, SOX_ENCODING_SIGN2, 32, num_samples, sox_true); |
||||
} |
||||
|
||||
static int write_header(sox_format_t * ft) |
||||
{ |
||||
char * comments = lsx_cat_comments(ft->oob.comments); |
||||
size_t comments_len = strlen(comments); |
||||
size_t comments_bytes = (comments_len + 7) & ~7u; /* Multiple of 8 bytes */ |
||||
uint64_t size = ft->olength? ft->olength : ft->signal.length; |
||||
int error; |
||||
uint32_t header; |
||||
memcpy(&header, magic[MACHINE_IS_BIGENDIAN], sizeof(header)); |
||||
error = 0 |
||||
||lsx_writedw(ft, header) |
||||
||lsx_writedw(ft, FIXED_HDR + (unsigned)comments_bytes) |
||||
||lsx_writeqw(ft, size) |
||||
||lsx_writedf(ft, ft->signal.rate) |
||||
||lsx_writedw(ft, ft->signal.channels) |
||||
||lsx_writedw(ft, (unsigned)comments_len) |
||||
||lsx_writechars(ft, comments, comments_len) |
||||
||lsx_padbytes(ft, comments_bytes - comments_len); |
||||
free(comments); |
||||
return error? SOX_EOF: SOX_SUCCESS; |
||||
} |
||||
|
||||
LSX_FORMAT_HANDLER(sox) |
||||
{ |
||||
static char const * const names[] = {"sox", NULL}; |
||||
static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 32, 0, 0}; |
||||
static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, |
||||
"SoX native intermediate format", names, SOX_FILE_REWIND,
|
||||
startread, lsx_rawread, NULL, write_header, lsx_rawwrite, NULL, |
||||
lsx_rawseek, write_encodings, NULL, 0 |
||||
}; |
||||
return &handler; |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -1,349 +0,0 @@ |
||||
/* libSoX effect: SpeexDsp effect to apply processing from libspeexdsp.
|
||||
* |
||||
* Copyright 1999-2009 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" |
||||
|
||||
#ifdef HAVE_SPEEXDSP |
||||
|
||||
#include <speex/speex_types.h> |
||||
#include <speex/speex_preprocess.h> |
||||
|
||||
/* Private data for effect */ |
||||
typedef struct speexdsp_priv_t { |
||||
size_t buffer_end; /* Index of the end of the buffer. */ |
||||
size_t buffer_ipos; /* Index for the next input sample. */ |
||||
size_t buffer_opos; /* Index of the next sample that has not been drained. */ |
||||
int16_t* buffer; /* Work buffer. */ |
||||
SpeexPreprocessState* sps;/* DSP state. */ |
||||
size_t agc; /* Param: Automatic Gain Control target volume level: 0 to disable, or 1-100 (target volume). */ |
||||
size_t denoise; /* Param: Denoise: 0 to disable, or maximum noise attenuation in dB. */ |
||||
size_t dereverb; /* Param: Dereverb: 0 to disable, 1 to enable. */ |
||||
size_t frames_per_second; /* Param: Used to compute buffer size from sample rate. */ |
||||
size_t samples_per_frame; /* Param: Used to compute buffer size directly. Default is to use frames_per_second instead. */ |
||||
} priv_t; |
||||
|
||||
static int get_param( |
||||
int* pArgc, |
||||
char*** pArgv, |
||||
size_t* pParam, |
||||
size_t default_val, |
||||
size_t min_valid, |
||||
size_t max_valid) |
||||
{ |
||||
*pParam = default_val; |
||||
if (*pArgc > 1 && (*pArgv)[1][0] != '-') |
||||
{ |
||||
char* arg_end; |
||||
*pParam = strtoul((*pArgv)[1], &arg_end, 0); |
||||
if (!arg_end || arg_end[0] || *pParam < min_valid || max_valid <= *pParam) |
||||
return 0; |
||||
|
||||
--*pArgc; |
||||
++*pArgv; |
||||
} |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
/*
|
||||
* Process command-line options but don't do other |
||||
* initialization now: effp->in_signal & effp->out_signal are not |
||||
* yet filled in. |
||||
*/ |
||||
static int getopts(sox_effect_t* effp, int argc, char** argv) |
||||
{ |
||||
priv_t* p = (priv_t*)effp->priv; |
||||
const size_t agcDefault = 100; |
||||
const size_t denoiseDefault = 15; |
||||
const size_t fpsDefault = 50; |
||||
|
||||
for (argc--, argv++; argc; argc--, argv++) |
||||
{ |
||||
if (!strcasecmp("-agc", argv[0])) |
||||
{ |
||||
/* AGC level argument is optional. If not specified, it defaults to agcDefault.
|
||||
If specified, it must be from 0 to 100. */ |
||||
if (!get_param(&argc, &argv, &p->agc, agcDefault, 0, 100)) |
||||
{ |
||||
lsx_fail("Invalid argument \"%s\" to -agc parameter - expected number from 0 to 100.", argv[1]); |
||||
return lsx_usage(effp); |
||||
} |
||||
} |
||||
else if (!strcasecmp("-denoise", argv[0])) |
||||
{ |
||||
/* Denoise level argument is optional. If not specified, it defaults to denoiseDefault.
|
||||
If specified, it must be from 0 to 100. */ |
||||
if (!get_param(&argc, &argv, &p->denoise, denoiseDefault, 0, 100)) |
||||
{ |
||||
lsx_fail("Invalid argument \"%s\" to -denoise parameter - expected number from 0 to 100.", argv[1]); |
||||
return lsx_usage(effp); |
||||
} |
||||
} |
||||
else if (!strcasecmp("-dereverb", argv[0])) |
||||
{ |
||||
p->dereverb = 1; |
||||
} |
||||
else if (!strcasecmp("-spf", argv[0])) |
||||
{ |
||||
/* If samples_per_frame option is given, argument is required and must be
|
||||
greater than 0. */ |
||||
if (!get_param(&argc, &argv, &p->samples_per_frame, 0, 1, 1000000000) || !p->samples_per_frame) |
||||
{ |
||||
lsx_fail("Invalid argument \"%s\" to -spf parameter - expected positive number.", argv[1]); |
||||
return lsx_usage(effp); |
||||
} |
||||
} |
||||
else if (!strcasecmp("-fps", argv[0])) |
||||
{ |
||||
/* If frames_per_second option is given, argument is required and must be
|
||||
from 1 to 100. This will be used later to compute samples_per_frame once |
||||
we know the sample rate). */ |
||||
if (!get_param(&argc, &argv, &p->frames_per_second, 0, 1, 100) || !p->frames_per_second) |
||||
{ |
||||
lsx_fail("Invalid argument \"%s\" to -fps parameter - expected number from 1 to 100.", argv[1]); |
||||
return lsx_usage(effp); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
lsx_fail("Invalid parameter \"%s\".", argv[0]); |
||||
return lsx_usage(effp); |
||||
} |
||||
} |
||||
|
||||
if (!p->frames_per_second) |
||||
p->frames_per_second = fpsDefault; |
||||
|
||||
if (!p->agc && !p->denoise && !p->dereverb) |
||||
{ |
||||
lsx_report("No features specified. Enabling default settings \"-agc %u -denoise %u\".", agcDefault, denoiseDefault); |
||||
p->agc = agcDefault; |
||||
p->denoise = denoiseDefault; |
||||
} |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Do anything required when you stop reading samples. |
||||
*/ |
||||
static int stop(sox_effect_t* effp) |
||||
{ |
||||
priv_t* p = (priv_t*)effp->priv; |
||||
|
||||
if (p->sps) |
||||
{ |
||||
speex_preprocess_state_destroy(p->sps); |
||||
p->sps = NULL; |
||||
} |
||||
|
||||
if (p->buffer) |
||||
{ |
||||
free(p->buffer); |
||||
p->buffer = NULL; |
||||
} |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Prepare processing. |
||||
* Do all initializations. |
||||
*/ |
||||
static int start(sox_effect_t* effp) |
||||
{ |
||||
priv_t* p = (priv_t*)effp->priv; |
||||
int result = SOX_SUCCESS; |
||||
spx_int32_t int_val; |
||||
float float_val; |
||||
|
||||
if (p->samples_per_frame) |
||||
{ |
||||
p->buffer_end = p->samples_per_frame; |
||||
} |
||||
else |
||||
{ |
||||
p->buffer_end = effp->in_signal.rate / p->frames_per_second; |
||||
if (!p->buffer_end) |
||||
{ |
||||
lsx_fail("frames_per_second too large for the current sample rate."); |
||||
return SOX_EOF; |
||||
} |
||||
} |
||||
|
||||
p->buffer_opos = p->buffer_end; |
||||
effp->out_signal.precision = 16; |
||||
|
||||
p->buffer = lsx_malloc(p->buffer_end * sizeof(p->buffer[0])); |
||||
if (!p->buffer) |
||||
{ |
||||
result = SOX_ENOMEM; |
||||
goto Done; |
||||
} |
||||
|
||||
p->sps = speex_preprocess_state_init((int)p->buffer_end, (int)(effp->in_signal.rate + .5)); |
||||
if (!p->sps) |
||||
{ |
||||
lsx_fail("Failed to initialize preprocessor DSP."); |
||||
result = SOX_EOF; |
||||
goto Done; |
||||
} |
||||
|
||||
int_val = p->agc ? 1 : 2; |
||||
speex_preprocess_ctl(p->sps, SPEEX_PREPROCESS_SET_AGC, &int_val); |
||||
if (p->agc) |
||||
{ |
||||
float_val = p->agc * 327.68f; |
||||
speex_preprocess_ctl(p->sps, SPEEX_PREPROCESS_SET_AGC_LEVEL, &float_val); |
||||
} |
||||
|
||||
int_val = p->denoise ? 1 : 2; |
||||
speex_preprocess_ctl(p->sps, SPEEX_PREPROCESS_SET_DENOISE, &int_val); |
||||
if (p->denoise) |
||||
{ |
||||
int_val = -(spx_int32_t)p->denoise; |
||||
speex_preprocess_ctl(p->sps, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, &int_val); |
||||
} |
||||
|
||||
int_val = p->dereverb ? 1 : 2; |
||||
speex_preprocess_ctl(p->sps, SPEEX_PREPROCESS_SET_DEREVERB, &int_val); |
||||
|
||||
Done: |
||||
if (result != SOX_SUCCESS) |
||||
stop(effp); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/*
|
||||
* Process up to *isamp samples from ibuf and produce up to *osamp samples |
||||
* in obuf. Write back the actual numbers of samples to *isamp and *osamp. |
||||
* Return SOX_SUCCESS or, if error occurs, SOX_EOF. |
||||
*/ |
||||
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 ibuf_pos = 0; |
||||
size_t ibuf_end = *isamp; |
||||
size_t obuf_pos = 0; |
||||
size_t obuf_end = *osamp; |
||||
size_t end_pos; |
||||
SOX_SAMPLE_LOCALS; |
||||
|
||||
for (;;) |
||||
{ |
||||
/* Write any processed data in working buffer to the output buffer. */ |
||||
end_pos = obuf_pos + min(p->buffer_end - p->buffer_opos, obuf_end - obuf_pos); |
||||
for (; obuf_pos < end_pos; obuf_pos++, p->buffer_opos++) |
||||
obuf[obuf_pos] = SOX_SIGNED_16BIT_TO_SAMPLE(p->buffer[p->buffer_opos], dummy); |
||||
if (p->buffer_opos != p->buffer_end) |
||||
break; /* Output buffer is full and we still have more processed data. */ |
||||
|
||||
/* Fill working buffer from input buffer. */ |
||||
end_pos = ibuf_pos + min(p->buffer_end - p->buffer_ipos, ibuf_end - ibuf_pos); |
||||
for (; ibuf_pos < end_pos; ibuf_pos++, p->buffer_ipos++) |
||||
p->buffer[p->buffer_ipos] = SOX_SAMPLE_TO_SIGNED_16BIT(ibuf[ibuf_pos], effp->clips); |
||||
if (p->buffer_ipos != p->buffer_end) |
||||
break; /* Working buffer is not full and there is no more input data. */ |
||||
|
||||
speex_preprocess_run(p->sps, p->buffer); |
||||
p->buffer_ipos = 0; |
||||
p->buffer_opos = 0; |
||||
} |
||||
|
||||
*isamp = ibuf_pos; |
||||
*osamp = obuf_pos; |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Drain out remaining samples if the effect generates any. |
||||
*/ |
||||
static int drain(sox_effect_t* effp, sox_sample_t* obuf, size_t* osamp) |
||||
{ |
||||
priv_t* p = (priv_t*)effp->priv; |
||||
size_t obuf_pos = 0; |
||||
size_t obuf_end = *osamp; |
||||
size_t i; |
||||
size_t end_pos; |
||||
|
||||
/* Input that hasn't been processed yet? */ |
||||
if (p->buffer_ipos != 0) |
||||
{ |
||||
/* DSP only works on full frames, so fill the remaining space with 0s. */ |
||||
for (i = p->buffer_ipos; i < p->buffer_end; i++) |
||||
p->buffer[i] = 0; |
||||
speex_preprocess_run(p->sps, p->buffer); |
||||
p->buffer_end = p->buffer_ipos; |
||||
p->buffer_ipos = 0; |
||||
p->buffer_opos = 0; |
||||
} |
||||
|
||||
end_pos = obuf_pos + min(p->buffer_end - p->buffer_opos, obuf_end - obuf_pos); |
||||
for (; obuf_pos < end_pos; obuf_pos++, p->buffer_opos++) |
||||
obuf[obuf_pos] = SOX_SIGNED_16BIT_TO_SAMPLE(p->buffer[p->buffer_opos], dummy); |
||||
|
||||
*osamp = obuf_pos; |
||||
return |
||||
p->buffer_opos != p->buffer_end |
||||
? SOX_SUCCESS |
||||
: SOX_EOF; |
||||
} |
||||
|
||||
/*
|
||||
* Function returning effect descriptor. This should be the only |
||||
* externally visible object. |
||||
*/ |
||||
const sox_effect_handler_t* lsx_speexdsp_effect_fn(void) |
||||
{ |
||||
/*
|
||||
* Effect descriptor. |
||||
* If no specific processing is needed for any of |
||||
* the 6 functions, then the function above can be deleted |
||||
* and NULL used in place of the its name below. |
||||
*/ |
||||
static sox_effect_handler_t descriptor = { |
||||
"speexdsp", 0, SOX_EFF_PREC | SOX_EFF_GAIN | SOX_EFF_ALPHA, |
||||
getopts, start, flow, drain, stop, NULL, sizeof(priv_t) |
||||
}; |
||||
static char const * lines[] = { |
||||
"Uses the Speex DSP library to improve perceived sound quality.", |
||||
"If no options are specified, the -agc and -denoise features are enabled.", |
||||
"Options:", |
||||
"-agc [target_level] Enable automatic gain control, and optionally specify a", |
||||
" target volume level from 1-100 (default is 100).", |
||||
"-denoise [max_dB] Enable noise reduction, and optionally specify the max", |
||||
" attenuation (default is 15).", |
||||
"-dereverb Enable reverb reduction.", |
||||
"-fps frames_per_second Specify the number of frames per second from 1-100", |
||||
" (default is 20).", |
||||
"-spf samples_per_frame Specify the number of samples per frame. Default is to", |
||||
" use the -fps setting.", |
||||
}; |
||||
static char * usage; |
||||
descriptor.usage = lsx_usage_lines(&usage, lines, array_length(lines)); |
||||
return &descriptor; |
||||
} |
||||
|
||||
#endif /* HAVE_SPEEXDSP */ |
@ -1,302 +0,0 @@ |
||||
/* libSoX effect: splice audio Copyright (c) 2008-9 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
static double difference( |
||||
const sox_sample_t * a, const sox_sample_t * b, size_t length) |
||||
{ |
||||
double diff = 0; |
||||
size_t i = 0; |
||||
|
||||
#define _ diff += sqr((double)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 best_overlap_position(sox_sample_t const * f1, |
||||
sox_sample_t const * f2, uint64_t overlap, uint64_t search, size_t channels) |
||||
{ |
||||
size_t i, best_pos = 0; |
||||
double diff, least_diff = difference(f2, f1, (size_t) (channels * overlap)); |
||||
|
||||
for (i = 1; i < search; ++i) { /* linear search */ |
||||
diff = difference(f2 + channels * i, f1, (size_t) (channels * overlap)); |
||||
if (diff < least_diff) |
||||
least_diff = diff, best_pos = i; |
||||
} |
||||
return best_pos; |
||||
} |
||||
|
||||
|
||||
typedef struct { |
||||
enum {Cosine_2, Cosine_4, Triangular} fade_type; |
||||
unsigned nsplices; /* Number of splices requested */ |
||||
struct { |
||||
char * str; /* Command-line argument to parse for this splice */ |
||||
uint64_t overlap; /* Number of samples to overlap */ |
||||
uint64_t search; /* Number of samples to search */ |
||||
uint64_t start; /* Start splicing when in_pos equals this */ |
||||
} * splices; |
||||
|
||||
uint64_t in_pos; /* Number of samples read from the input stream */ |
||||
unsigned splices_pos; /* Number of splices completed so far */ |
||||
size_t buffer_pos; /* Number of samples through the current splice */ |
||||
size_t max_buffer_size; |
||||
sox_sample_t * buffer; |
||||
unsigned state; |
||||
} priv_t; |
||||
|
||||
static void splice(sox_effect_t * effp, const sox_sample_t * in1, const |
||||
sox_sample_t * in2, sox_sample_t * output, uint64_t overlap, size_t channels) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
size_t i, j, k = 0; |
||||
|
||||
if (p->fade_type == Cosine_4) { |
||||
double fade_step = M_PI_2 / overlap; |
||||
for (i = 0; i < overlap; ++i) { |
||||
double fade_in = sin(i * fade_step); |
||||
double fade_out = cos(i * fade_step); /* constant RMS level (`power') */ |
||||
for (j = 0; j < channels; ++j, ++k) { |
||||
double d = in1[k] * fade_out + in2[k] * fade_in; |
||||
output[k] = SOX_ROUND_CLIP_COUNT(d, effp->clips); /* Might clip */ |
||||
} |
||||
} |
||||
} |
||||
else if (p->fade_type == Cosine_2) { |
||||
double fade_step = M_PI / overlap; |
||||
for (i = 0; i < overlap; ++i) { |
||||
double fade_in = .5 - .5 * cos(i * fade_step); |
||||
double fade_out = 1 - fade_in; /* constant peak level (`gain') */ |
||||
for (j = 0; j < channels; ++j, ++k) { |
||||
double d = in1[k] * fade_out + in2[k] * fade_in; |
||||
output[k] = SOX_ROUND_CLIP_COUNT(d, effp->clips); /* Should not clip */ |
||||
} |
||||
} |
||||
} |
||||
else /* Triangular */ { |
||||
double fade_step = 1. / overlap; |
||||
for (i = 0; i < overlap; ++i) { |
||||
double fade_in = fade_step * i; |
||||
double fade_out = 1 - fade_in; /* constant peak level (`gain') */ |
||||
for (j = 0; j < channels; ++j, ++k) { |
||||
double d = in1[k] * fade_out + in2[k] * fade_in; |
||||
output[k] = SOX_ROUND_CLIP_COUNT(d, effp->clips); /* Should not clip */ |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
static uint64_t do_splice(sox_effect_t * effp, |
||||
sox_sample_t * f, uint64_t overlap, uint64_t search, size_t channels) |
||||
{ |
||||
uint64_t offset = search? best_overlap_position( |
||||
f, f + overlap * channels, overlap, search, channels) : 0; |
||||
splice(effp, f, f + (overlap + offset) * channels, |
||||
f + (overlap + offset) * channels, overlap, channels); |
||||
return overlap + offset; |
||||
} |
||||
|
||||
static int parse(sox_effect_t * effp, char * * argv, sox_rate_t rate) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
char const * next; |
||||
size_t i, buffer_size; |
||||
uint64_t last_seen = 0; |
||||
const uint64_t in_length = argv ? 0 : |
||||
(effp->in_signal.length != SOX_UNKNOWN_LEN ? |
||||
effp->in_signal.length / effp->in_signal.channels : SOX_UNKNOWN_LEN); |
||||
|
||||
p->max_buffer_size = 0; |
||||
for (i = 0; i < p->nsplices; ++i) { |
||||
if (argv) /* 1st parse only */ |
||||
p->splices[i].str = lsx_strdup(argv[i]); |
||||
|
||||
p->splices[i].overlap = rate * 0.01 + .5; |
||||
p->splices[i].search = p->fade_type == Cosine_4? 0 : p->splices[i].overlap; |
||||
|
||||
next = lsx_parseposition(rate, p->splices[i].str, |
||||
argv ? NULL : &p->splices[i].start, last_seen, in_length, '='); |
||||
if (next == NULL) break; |
||||
last_seen = p->splices[i].start; |
||||
|
||||
if (*next == ',') { |
||||
next = lsx_parsesamples(rate, next + 1, &p->splices[i].overlap, 't'); |
||||
if (next == NULL) break; |
||||
p->splices[i].overlap *= 2; |
||||
if (*next == ',') { |
||||
next = lsx_parsesamples(rate, next + 1, &p->splices[i].search, 't'); |
||||
if (next == NULL) break; |
||||
p->splices[i].search *= 2; |
||||
} |
||||
} |
||||
if (*next != '\0') break; |
||||
p->splices[i].overlap = max(p->splices[i].overlap + 4, 16); |
||||
p->splices[i].overlap &= ~7; /* Make divisible by 8 for loop optimisation */ |
||||
|
||||
if (!argv) { |
||||
if (i > 0 && p->splices[i].start <= p->splices[i-1].start) break; |
||||
if (p->splices[i].start < p->splices[i].overlap) break; |
||||
p->splices[i].start -= p->splices[i].overlap; |
||||
buffer_size = 2 * p->splices[i].overlap + p->splices[i].search; |
||||
p->max_buffer_size = max(p->max_buffer_size, buffer_size); |
||||
} |
||||
} |
||||
if (i < p->nsplices) |
||||
return lsx_usage(effp); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int create(sox_effect_t * effp, int argc, char * * argv) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
--argc, ++argv; |
||||
if (argc) { |
||||
if (!strcmp(*argv, "-t")) p->fade_type = Triangular, --argc, ++argv; |
||||
else if (!strcmp(*argv, "-q")) p->fade_type = Cosine_4 , --argc, ++argv; |
||||
else if (!strcmp(*argv, "-h")) p->fade_type = Cosine_2 , --argc, ++argv; |
||||
} |
||||
p->nsplices = argc; |
||||
p->splices = lsx_calloc(p->nsplices, sizeof(*p->splices)); |
||||
return parse(effp, argv, 1e5); /* No rate yet; parse with dummy */ |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
unsigned i; |
||||
|
||||
parse(effp, 0, effp->in_signal.rate); /* Re-parse now rate is known */ |
||||
p->buffer = lsx_calloc(p->max_buffer_size * effp->in_signal.channels, sizeof(*p->buffer)); |
||||
p->in_pos = p->buffer_pos = p->splices_pos = 0; |
||||
p->state = p->splices_pos != p->nsplices && p->in_pos == p->splices[p->splices_pos].start; |
||||
effp->out_signal.length = SOX_UNKNOWN_LEN; /* depends on input data */ |
||||
for (i = 0; i < p->nsplices; ++i) |
||||
if (p->splices[i].overlap) { |
||||
if (p->fade_type == Cosine_4 && effp->in_signal.mult) |
||||
*effp->in_signal.mult *= pow(.5, .5); |
||||
return SOX_SUCCESS; |
||||
} |
||||
return SOX_EFF_NULL; |
||||
} |
||||
|
||||
static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, |
||||
sox_sample_t * obuf, size_t * isamp, size_t * osamp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
size_t c, idone = 0, odone = 0; |
||||
*isamp /= effp->in_signal.channels; |
||||
*osamp /= effp->in_signal.channels; |
||||
|
||||
while (sox_true) { |
||||
copying: |
||||
if (p->state == 0) { |
||||
for (; idone < *isamp && odone < *osamp; ++idone, ++odone, ++p->in_pos) { |
||||
if (p->splices_pos != p->nsplices && p->in_pos == p->splices[p->splices_pos].start) { |
||||
p->state = 1; |
||||
goto buffering; |
||||
} |
||||
for (c = 0; c < effp->in_signal.channels; ++c) |
||||
*obuf++ = *ibuf++; |
||||
} |
||||
break; |
||||
} |
||||
|
||||
buffering: |
||||
if (p->state == 1) { |
||||
size_t buffer_size = (2 * p->splices[p->splices_pos].overlap + p->splices[p->splices_pos].search) * effp->in_signal.channels; |
||||
for (; idone < *isamp; ++idone, ++p->in_pos) { |
||||
if (p->buffer_pos == buffer_size) { |
||||
p->buffer_pos = do_splice(effp, p->buffer, |
||||
p->splices[p->splices_pos].overlap, |
||||
p->splices[p->splices_pos].search, |
||||
(size_t)effp->in_signal.channels) * effp->in_signal.channels; |
||||
p->state = 2; |
||||
goto flushing; |
||||
break; |
||||
} |
||||
for (c = 0; c < effp->in_signal.channels; ++c) |
||||
p->buffer[p->buffer_pos++] = *ibuf++; |
||||
} |
||||
break; |
||||
} |
||||
|
||||
flushing: |
||||
if (p->state == 2) { |
||||
size_t buffer_size = (2 * p->splices[p->splices_pos].overlap + p->splices[p->splices_pos].search) * effp->in_signal.channels; |
||||
for (; odone < *osamp; ++odone) { |
||||
if (p->buffer_pos == buffer_size) { |
||||
p->buffer_pos = 0; |
||||
++p->splices_pos; |
||||
p->state = p->splices_pos != p->nsplices && p->in_pos == p->splices[p->splices_pos].start; |
||||
goto copying; |
||||
} |
||||
for (c = 0; c < effp->in_signal.channels; ++c) |
||||
*obuf++ = p->buffer[p->buffer_pos++]; |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
|
||||
*isamp = idone * effp->in_signal.channels; |
||||
*osamp = odone * effp->in_signal.channels; |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp) |
||||
{ |
||||
size_t isamp = 0; |
||||
return flow(effp, 0, obuf, &isamp, osamp); |
||||
} |
||||
|
||||
static int stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
if (p->splices_pos != p->nsplices) |
||||
lsx_warn("Input audio too short; splices not made: %u", p->nsplices - p->splices_pos); |
||||
free(p->buffer); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int lsx_kill(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
unsigned i; |
||||
for (i = 0; i < p->nsplices; ++i) |
||||
free(p->splices[i].str); |
||||
free(p->splices); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_splice_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"splice", "[-h|-t|-q] {position[,excess[,leeway]]}" |
||||
"\n -h Half sine fade (default); constant gain (for correlated audio)" |
||||
"\n -t Triangular (linear) fade; constant gain (for correlated audio)" |
||||
"\n -q Quarter sine fade; constant power (for correlated audio e.g. x-fade)" |
||||
"\n position The length of part 1 (including the excess)" |
||||
"\n excess At the end of part 1 & the start of part2 (default 0.005)" |
||||
"\n leeway Before part2 (default 0.005; set to 0 for cross-fade)", |
||||
SOX_EFF_MCHAN | SOX_EFF_LENGTH, |
||||
create, start, flow, drain, stop, lsx_kill, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,336 +0,0 @@ |
||||
/* libSoX statistics "effect" file.
|
||||
* |
||||
* Compute various statistics on file and print them. |
||||
* |
||||
* Output is unmodified from input. |
||||
* |
||||
* July 5, 1991 |
||||
* Copyright 1991 Lance Norskog And Sundry Contributors |
||||
* This source code is freely redistributable and may be used for |
||||
* any purpose. This copyright notice must be maintained. |
||||
* Lance Norskog And Sundry Contributors are not responsible for |
||||
* the consequences of using this software. |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
/* Private data for stat effect */ |
||||
typedef struct { |
||||
double min, max, mid; |
||||
double asum; |
||||
double sum1, sum2; /* amplitudes */ |
||||
double dmin, dmax; |
||||
double dsum1, dsum2; /* deltas */ |
||||
double scale; /* scale-factor */ |
||||
double last; /* previous sample */ |
||||
uint64_t read; /* samples processed */ |
||||
int volume; |
||||
int srms; |
||||
int fft; |
||||
unsigned long bin[4]; |
||||
float *re_in; |
||||
float *re_out; |
||||
unsigned long fft_size; |
||||
unsigned long fft_offset; |
||||
} priv_t; |
||||
|
||||
|
||||
/*
|
||||
* Process options |
||||
*/ |
||||
static int sox_stat_getopts(sox_effect_t * effp, int argc, char **argv) |
||||
{ |
||||
priv_t * stat = (priv_t *) effp->priv; |
||||
|
||||
stat->scale = SOX_SAMPLE_MAX; |
||||
stat->volume = 0; |
||||
stat->srms = 0; |
||||
stat->fft = 0; |
||||
|
||||
--argc, ++argv; |
||||
for (; argc > 0; argc--, argv++) { |
||||
if (!(strcmp(*argv, "-v"))) |
||||
stat->volume = 1; |
||||
else if (!(strcmp(*argv, "-s"))) { |
||||
if (argc <= 1) { |
||||
lsx_fail("-s option: invalid argument"); |
||||
return SOX_EOF; |
||||
} |
||||
argc--, argv++; /* Move to next argument. */ |
||||
if (!sscanf(*argv, "%lf", &stat->scale)) { |
||||
lsx_fail("-s option: invalid argument"); |
||||
return SOX_EOF; |
||||
} |
||||
} else if (!(strcmp(*argv, "-rms"))) |
||||
stat->srms = 1; |
||||
else if (!(strcmp(*argv, "-freq"))) |
||||
stat->fft = 1; |
||||
else if (!(strcmp(*argv, "-d"))) |
||||
stat->volume = 2; |
||||
else { |
||||
lsx_fail("Summary effect: unknown option"); |
||||
return SOX_EOF; |
||||
} |
||||
} |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Prepare processing. |
||||
*/ |
||||
static int sox_stat_start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * stat = (priv_t *) effp->priv; |
||||
int i; |
||||
|
||||
stat->min = stat->max = stat->mid = 0; |
||||
stat->asum = 0; |
||||
stat->sum1 = stat->sum2 = 0; |
||||
|
||||
stat->dmin = stat->dmax = 0; |
||||
stat->dsum1 = stat->dsum2 = 0; |
||||
|
||||
stat->last = 0; |
||||
stat->read = 0; |
||||
|
||||
for (i = 0; i < 4; i++) |
||||
stat->bin[i] = 0; |
||||
|
||||
stat->fft_size = 4096; |
||||
stat->re_in = stat->re_out = NULL; |
||||
|
||||
if (stat->fft) { |
||||
stat->fft_offset = 0; |
||||
stat->re_in = lsx_malloc(sizeof(float) * stat->fft_size); |
||||
stat->re_out = lsx_malloc(sizeof(float) * (stat->fft_size / 2 + 1)); |
||||
} |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Print power spectrum to given stream |
||||
*/ |
||||
static void print_power_spectrum(unsigned samples, double rate, float *re_in, float *re_out) |
||||
{ |
||||
float ffa = rate / samples; |
||||
unsigned i; |
||||
|
||||
lsx_power_spectrum_f((int)samples, re_in, re_out); |
||||
for (i = 0; i < samples / 2; i++) /* FIXME: should be <= samples / 2 */ |
||||
fprintf(stderr, "%f %f\n", ffa * i, re_out[i]); |
||||
} |
||||
|
||||
/*
|
||||
* Processed signed long samples from ibuf to obuf. |
||||
* Return number of samples processed. |
||||
*/ |
||||
static int sox_stat_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, |
||||
size_t *isamp, size_t *osamp) |
||||
{ |
||||
priv_t * stat = (priv_t *) effp->priv; |
||||
int done, x, len = min(*isamp, *osamp); |
||||
short count = 0; |
||||
|
||||
if (len) { |
||||
if (stat->read == 0) /* 1st sample */ |
||||
stat->min = stat->max = stat->mid = stat->last = (*ibuf)/stat->scale; |
||||
|
||||
if (stat->fft) { |
||||
for (x = 0; x < len; x++) { |
||||
SOX_SAMPLE_LOCALS; |
||||
stat->re_in[stat->fft_offset++] = SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[x], effp->clips); |
||||
|
||||
if (stat->fft_offset >= stat->fft_size) { |
||||
stat->fft_offset = 0; |
||||
print_power_spectrum((unsigned) stat->fft_size, effp->in_signal.rate, stat->re_in, stat->re_out); |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
for (done = 0; done < len; done++) { |
||||
long lsamp = *ibuf++; |
||||
double delta, samp = (double)lsamp / stat->scale; |
||||
/* work in scaled levels for both sample and delta */ |
||||
stat->bin[(lsamp >> 30) + 2]++; |
||||
*obuf++ = lsamp; |
||||
|
||||
if (stat->volume == 2) { |
||||
fprintf(stderr,"%08lx ",lsamp); |
||||
if (count++ == 5) { |
||||
fprintf(stderr,"\n"); |
||||
count = 0; |
||||
} |
||||
} |
||||
|
||||
/* update min/max */ |
||||
if (stat->min > samp) |
||||
stat->min = samp; |
||||
else if (stat->max < samp) |
||||
stat->max = samp; |
||||
stat->mid = stat->min / 2 + stat->max / 2; |
||||
|
||||
stat->sum1 += samp; |
||||
stat->sum2 += samp*samp; |
||||
stat->asum += fabs(samp); |
||||
|
||||
delta = fabs(samp - stat->last); |
||||
if (delta < stat->dmin) |
||||
stat->dmin = delta; |
||||
else if (delta > stat->dmax) |
||||
stat->dmax = delta; |
||||
|
||||
stat->dsum1 += delta; |
||||
stat->dsum2 += delta*delta; |
||||
|
||||
stat->last = samp; |
||||
} |
||||
stat->read += len; |
||||
} |
||||
|
||||
*isamp = *osamp = len; |
||||
/* Process all samples */ |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Process tail of input samples. |
||||
*/ |
||||
static int sox_stat_drain(sox_effect_t * effp, sox_sample_t *obuf UNUSED, size_t *osamp) |
||||
{ |
||||
priv_t * stat = (priv_t *) effp->priv; |
||||
|
||||
/* When we run out of samples, then we need to pad buffer with
|
||||
* zeros and then run FFT one last time to process any unprocessed |
||||
* samples. |
||||
*/ |
||||
if (stat->fft && stat->fft_offset) { |
||||
unsigned int x; |
||||
|
||||
for (x = stat->fft_offset; x < stat->fft_size; x++) |
||||
stat->re_in[x] = 0; |
||||
|
||||
print_power_spectrum((unsigned) stat->fft_size, effp->in_signal.rate, stat->re_in, stat->re_out); |
||||
} |
||||
|
||||
*osamp = 0; |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
/*
|
||||
* Do anything required when you stop reading samples. |
||||
* Don't close input file! |
||||
*/ |
||||
static int sox_stat_stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * stat = (priv_t *) effp->priv; |
||||
double amp, scale, rms = 0, freq; |
||||
double x, ct; |
||||
|
||||
ct = stat->read; |
||||
|
||||
if (stat->srms) { /* adjust results to units of rms */ |
||||
double f; |
||||
rms = sqrt(stat->sum2/ct); |
||||
f = 1.0/rms; |
||||
stat->max *= f; |
||||
stat->min *= f; |
||||
stat->mid *= f; |
||||
stat->asum *= f; |
||||
stat->sum1 *= f; |
||||
stat->sum2 *= f*f; |
||||
stat->dmax *= f; |
||||
stat->dmin *= f; |
||||
stat->dsum1 *= f; |
||||
stat->dsum2 *= f*f; |
||||
stat->scale *= rms; |
||||
} |
||||
|
||||
scale = stat->scale; |
||||
|
||||
amp = -stat->min; |
||||
if (amp < stat->max) |
||||
amp = stat->max; |
||||
|
||||
/* Just print the volume adjustment */ |
||||
if (stat->volume == 1 && amp > 0) { |
||||
fprintf(stderr, "%.3f\n", SOX_SAMPLE_MAX/(amp*scale)); |
||||
return SOX_SUCCESS; |
||||
} |
||||
if (stat->volume == 2) |
||||
fprintf(stderr, "\n\n"); |
||||
/* print out the info */ |
||||
fprintf(stderr, "Samples read: %12" PRIu64 "\n", stat->read); |
||||
fprintf(stderr, "Length (seconds): %12.6f\n", (double)stat->read/effp->in_signal.rate/effp->in_signal.channels); |
||||
if (stat->srms) |
||||
fprintf(stderr, "Scaled by rms: %12.6f\n", rms); |
||||
else |
||||
fprintf(stderr, "Scaled by: %12.1f\n", scale); |
||||
fprintf(stderr, "Maximum amplitude: %12.6f\n", stat->max); |
||||
fprintf(stderr, "Minimum amplitude: %12.6f\n", stat->min); |
||||
fprintf(stderr, "Midline amplitude: %12.6f\n", stat->mid); |
||||
fprintf(stderr, "Mean norm: %12.6f\n", stat->asum/ct); |
||||
fprintf(stderr, "Mean amplitude: %12.6f\n", stat->sum1/ct); |
||||
fprintf(stderr, "RMS amplitude: %12.6f\n", sqrt(stat->sum2/ct)); |
||||
|
||||
fprintf(stderr, "Maximum delta: %12.6f\n", stat->dmax); |
||||
fprintf(stderr, "Minimum delta: %12.6f\n", stat->dmin); |
||||
fprintf(stderr, "Mean delta: %12.6f\n", stat->dsum1/(ct-1)); |
||||
fprintf(stderr, "RMS delta: %12.6f\n", sqrt(stat->dsum2/(ct-1))); |
||||
freq = sqrt(stat->dsum2/stat->sum2)*effp->in_signal.rate/(M_PI*2); |
||||
fprintf(stderr, "Rough frequency: %12d\n", (int)freq); |
||||
|
||||
if (amp>0) |
||||
fprintf(stderr, "Volume adjustment: %12.3f\n", SOX_SAMPLE_MAX/(amp*scale)); |
||||
|
||||
if (stat->bin[2] == 0 && stat->bin[3] == 0) |
||||
fprintf(stderr, "\nProbably text, not sound\n"); |
||||
else { |
||||
|
||||
x = (float)(stat->bin[0] + stat->bin[3]) / (float)(stat->bin[1] + stat->bin[2]); |
||||
|
||||
if (x >= 3.0) { /* use opposite encoding */ |
||||
if (effp->in_encoding->encoding == SOX_ENCODING_UNSIGNED) |
||||
fprintf(stderr,"\nTry: -t raw -e signed-integer -b 8 \n"); |
||||
else |
||||
fprintf(stderr,"\nTry: -t raw -e unsigned-integer -b 8 \n"); |
||||
} else if (x <= 1.0 / 3.0) |
||||
; /* correctly decoded */ |
||||
else if (x >= 0.5 && x <= 2.0) { /* use ULAW */ |
||||
if (effp->in_encoding->encoding == SOX_ENCODING_ULAW) |
||||
fprintf(stderr,"\nTry: -t raw -e unsigned-integer -b 8 \n"); |
||||
else |
||||
fprintf(stderr,"\nTry: -t raw -e mu-law -b 8 \n"); |
||||
} else |
||||
fprintf(stderr, "\nCan't guess the type\n"); |
||||
} |
||||
|
||||
/* Release FFT memory */ |
||||
free(stat->re_in); |
||||
free(stat->re_out); |
||||
|
||||
return SOX_SUCCESS; |
||||
|
||||
} |
||||
|
||||
static sox_effect_handler_t sox_stat_effect = { |
||||
"stat", |
||||
"[ -s N ] [ -rms ] [-freq] [ -v ] [ -d ]", |
||||
SOX_EFF_MCHAN | SOX_EFF_MODIFY, |
||||
sox_stat_getopts, |
||||
sox_stat_start, |
||||
sox_stat_flow, |
||||
sox_stat_drain, |
||||
sox_stat_stop, |
||||
NULL, sizeof(priv_t) |
||||
}; |
||||
|
||||
const sox_effect_handler_t *lsx_stat_effect_fn(void) |
||||
{ |
||||
return &sox_stat_effect; |
||||
} |
@ -1,298 +0,0 @@ |
||||
/* libSoX effect: stats (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 <ctype.h> |
||||
#include <string.h> |
||||
|
||||
typedef struct { |
||||
int scale_bits, hex_bits; |
||||
double time_constant, scale; |
||||
|
||||
double last, sigma_x, sigma_x2, avg_sigma_x2, min_sigma_x2, max_sigma_x2; |
||||
double min, max, mult, min_run, min_runs, max_run, max_runs; |
||||
off_t num_samples, tc_samples, min_count, max_count; |
||||
uint32_t mask; |
||||
} priv_t; |
||||
|
||||
static int getopts(sox_effect_t * effp, int argc, char **argv) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
int c; |
||||
lsx_getopt_t optstate; |
||||
lsx_getopt_init(argc, argv, "+x:b:w:s:", NULL, lsx_getopt_flag_none, 1, &optstate); |
||||
|
||||
p->time_constant = .05; |
||||
p->scale = 1; |
||||
while ((c = lsx_getopt(&optstate)) != -1) switch (c) { |
||||
GETOPT_NUMERIC(optstate, 'x', hex_bits , 2 , 32) |
||||
GETOPT_NUMERIC(optstate, 'b', scale_bits , 2 , 32) |
||||
GETOPT_NUMERIC(optstate, 'w', time_constant , .01 , 10) |
||||
GETOPT_NUMERIC(optstate, 's', scale , -99, 99) |
||||
default: lsx_fail("invalid option `-%c'", optstate.opt); return lsx_usage(effp); |
||||
} |
||||
if (p->hex_bits) |
||||
p->scale_bits = p->hex_bits; |
||||
return optstate.ind != argc? lsx_usage(effp) : SOX_SUCCESS; |
||||
} |
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
|
||||
p->last = 0; |
||||
p->mult = exp((-1 / p->time_constant / effp->in_signal.rate)); |
||||
p->tc_samples = 5 * p->time_constant * effp->in_signal.rate + .5; |
||||
p->sigma_x = p->sigma_x2 = p->avg_sigma_x2 = p->max_sigma_x2 = 0; |
||||
p->min = p->min_sigma_x2 = 2; |
||||
p->max = -p->min; |
||||
p->num_samples = 0; |
||||
p->mask = 0; |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, |
||||
sox_sample_t * obuf, size_t * ilen, size_t * olen) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
size_t len = *ilen = *olen = min(*ilen, *olen); |
||||
memcpy(obuf, ibuf, len * sizeof(*obuf)); |
||||
|
||||
for (; len--; ++ibuf, ++p->num_samples) { |
||||
double d = SOX_SAMPLE_TO_FLOAT_64BIT(*ibuf,); |
||||
|
||||
if (d < p->min) |
||||
p->min = d, p->min_count = 1, p->min_run = 1, p->min_runs = 0; |
||||
else if (d == p->min) { |
||||
++p->min_count; |
||||
p->min_run = d == p->last? p->min_run + 1 : 1; |
||||
} |
||||
else if (p->last == p->min) |
||||
p->min_runs += sqr(p->min_run); |
||||
|
||||
if (d > p->max) |
||||
p->max = d, p->max_count = 1, p->max_run = 1, p->max_runs = 0; |
||||
else if (d == p->max) { |
||||
++p->max_count; |
||||
p->max_run = d == p->last? p->max_run + 1 : 1; |
||||
} |
||||
else if (p->last == p->max) |
||||
p->max_runs += sqr(p->max_run); |
||||
|
||||
p->sigma_x += d; |
||||
p->sigma_x2 += sqr(d); |
||||
p->avg_sigma_x2 = p->avg_sigma_x2 * p->mult + (1 - p->mult) * sqr(d); |
||||
|
||||
if (p->num_samples >= p->tc_samples) { |
||||
if (p->avg_sigma_x2 > p->max_sigma_x2) |
||||
p->max_sigma_x2 = p->avg_sigma_x2; |
||||
if (p->avg_sigma_x2 < p->min_sigma_x2) |
||||
p->min_sigma_x2 = p->avg_sigma_x2; |
||||
} |
||||
p->last = d; |
||||
p->mask |= *ibuf; |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * olen) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
|
||||
if (p->last == p->min) |
||||
p->min_runs += sqr(p->min_run); |
||||
if (p->last == p->max) |
||||
p->max_runs += sqr(p->max_run); |
||||
|
||||
(void)obuf, *olen = 0; |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static unsigned bit_depth(uint32_t mask, double min, double max, unsigned * x) |
||||
{ |
||||
SOX_SAMPLE_LOCALS; |
||||
unsigned result = 32, dummy = 0; |
||||
|
||||
for (; result && !(mask & 1); --result, mask >>= 1); |
||||
if (x) |
||||
*x = result; |
||||
min = -fmax(fabs(min), fabs(max)); |
||||
mask = SOX_FLOAT_64BIT_TO_SAMPLE(min, dummy) << 1; |
||||
for (; result && (mask & SOX_SAMPLE_MIN); --result, mask <<= 1); |
||||
return result; |
||||
} |
||||
|
||||
static void output(priv_t const * p, double x) |
||||
{ |
||||
if (p->scale_bits) { |
||||
unsigned mult = 1 << (p->scale_bits - 1); |
||||
int i; |
||||
x = floor(x * mult + .5); |
||||
i = min(x, mult - 1.); |
||||
if (p->hex_bits) |
||||
if (x < 0) { |
||||
char buf[30]; |
||||
sprintf(buf, "%x", -i); |
||||
fprintf(stderr, " %*c%s", 9 - (int)strlen(buf), '-', buf); |
||||
} |
||||
else fprintf(stderr, " %9x", i); |
||||
else fprintf(stderr, " %9i", i); |
||||
} |
||||
else fprintf(stderr, " %9.*f", fabs(p->scale) < 10 ? 6 : 5, p->scale * x); |
||||
} |
||||
|
||||
static int stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
|
||||
if (!effp->flow) { |
||||
double min_runs = 0, max_count = 0, min = 2, max = -2, max_sigma_x = 0, sigma_x = 0, sigma_x2 = 0, min_sigma_x2 = 2, max_sigma_x2 = 0, avg_peak = 0; |
||||
off_t num_samples = 0, min_count = 0, max_runs = 0; |
||||
uint32_t mask = 0; |
||||
unsigned b1, b2, i, n = effp->flows > 1 ? effp->flows : 0; |
||||
|
||||
for (i = 0; i < effp->flows; ++i) { |
||||
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; |
||||
min = min(min, q->min); |
||||
max = max(max, q->max); |
||||
if (q->num_samples < q->tc_samples) |
||||
q->min_sigma_x2 = q->max_sigma_x2 = q->sigma_x2 / q->num_samples; |
||||
min_sigma_x2 = min(min_sigma_x2, q->min_sigma_x2); |
||||
max_sigma_x2 = max(max_sigma_x2, q->max_sigma_x2); |
||||
sigma_x += q->sigma_x; |
||||
sigma_x2 += q->sigma_x2; |
||||
num_samples += q->num_samples; |
||||
mask |= q->mask; |
||||
if (fabs(q->sigma_x) > fabs(max_sigma_x)) |
||||
max_sigma_x = q->sigma_x; |
||||
min_count += q->min_count; |
||||
min_runs += q->min_runs; |
||||
max_count += q->max_count; |
||||
max_runs += q->max_runs; |
||||
avg_peak += max(-q->min, q->max); |
||||
} |
||||
avg_peak /= effp->flows; |
||||
|
||||
if (!num_samples) { |
||||
lsx_warn("no audio"); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
if (n == 2) |
||||
fprintf(stderr, " Overall Left Right\n"); |
||||
else if (n) { |
||||
fprintf(stderr, " Overall"); |
||||
for (i = 0; i < n; ++i) |
||||
fprintf(stderr, " Ch%-3i", i + 1); |
||||
fprintf(stderr, "\n"); |
||||
} |
||||
|
||||
fprintf(stderr, "DC offset "); |
||||
output(p, max_sigma_x / p->num_samples); |
||||
for (i = 0; i < n; ++i) { |
||||
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; |
||||
output(p, q->sigma_x / q->num_samples); |
||||
} |
||||
|
||||
fprintf(stderr, "\nMin level "); |
||||
output(p, min); |
||||
for (i = 0; i < n; ++i) { |
||||
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; |
||||
output(p, q->min); |
||||
} |
||||
|
||||
fprintf(stderr, "\nMax level "); |
||||
output(p, max); |
||||
for (i = 0; i < n; ++i) { |
||||
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; |
||||
output(p, q->max); |
||||
} |
||||
|
||||
fprintf(stderr, "\nPk lev dB %10.2f", linear_to_dB(max(-min, max))); |
||||
for (i = 0; i < n; ++i) { |
||||
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; |
||||
fprintf(stderr, "%10.2f", linear_to_dB(max(-q->min, q->max))); |
||||
} |
||||
|
||||
fprintf(stderr, "\nRMS lev dB%10.2f", linear_to_dB(sqrt(sigma_x2 / num_samples))); |
||||
for (i = 0; i < n; ++i) { |
||||
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; |
||||
fprintf(stderr, "%10.2f", linear_to_dB(sqrt(q->sigma_x2 / q->num_samples))); |
||||
} |
||||
|
||||
fprintf(stderr, "\nRMS Pk dB %10.2f", linear_to_dB(sqrt(max_sigma_x2))); |
||||
for (i = 0; i < n; ++i) { |
||||
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; |
||||
fprintf(stderr, "%10.2f", linear_to_dB(sqrt(q->max_sigma_x2))); |
||||
} |
||||
|
||||
fprintf(stderr, "\nRMS Tr dB "); |
||||
if (min_sigma_x2 != 1) |
||||
fprintf(stderr, "%10.2f", linear_to_dB(sqrt(min_sigma_x2))); |
||||
else fprintf(stderr, " -"); |
||||
for (i = 0; i < n; ++i) { |
||||
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; |
||||
if (q->min_sigma_x2 != 1) |
||||
fprintf(stderr, "%10.2f", linear_to_dB(sqrt(q->min_sigma_x2))); |
||||
else fprintf(stderr, " -"); |
||||
} |
||||
|
||||
if (effp->flows > 1) |
||||
fprintf(stderr, "\nCrest factor -"); |
||||
else fprintf(stderr, "\nCrest factor %7.2f", sigma_x2 ? avg_peak / sqrt(sigma_x2 / num_samples) : 1); |
||||
for (i = 0; i < n; ++i) { |
||||
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; |
||||
fprintf(stderr, "%10.2f", q->sigma_x2? max(-q->min, q->max) / sqrt(q->sigma_x2 / q->num_samples) : 1); |
||||
} |
||||
|
||||
fprintf(stderr, "\nFlat factor%9.2f", linear_to_dB((min_runs + max_runs) / (min_count + max_count))); |
||||
for (i = 0; i < n; ++i) { |
||||
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; |
||||
fprintf(stderr, " %9.2f", linear_to_dB((q->min_runs + q->max_runs) / (q->min_count + q->max_count))); |
||||
} |
||||
|
||||
fprintf(stderr, "\nPk count %9s", lsx_sigfigs3((min_count + max_count) / effp->flows)); |
||||
for (i = 0; i < n; ++i) { |
||||
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; |
||||
fprintf(stderr, " %9s", lsx_sigfigs3((double)(q->min_count + q->max_count))); |
||||
} |
||||
|
||||
b1 = bit_depth(mask, min, max, &b2); |
||||
fprintf(stderr, "\nBit-depth %2u/%-2u", b1, b2); |
||||
for (i = 0; i < n; ++i) { |
||||
priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; |
||||
b1 = bit_depth(q->mask, q->min, q->max, &b2); |
||||
fprintf(stderr, " %2u/%-2u", b1, b2); |
||||
} |
||||
|
||||
fprintf(stderr, "\nNum samples%9s", lsx_sigfigs3((double)p->num_samples)); |
||||
fprintf(stderr, "\nLength s %9.3f", p->num_samples / effp->in_signal.rate); |
||||
fprintf(stderr, "\nScale max "); |
||||
output(p, 1.); |
||||
fprintf(stderr, "\nWindow s %9.3f", p->time_constant); |
||||
fprintf(stderr, "\n"); |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_stats_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"stats", "[-b bits|-x bits|-s scale] [-w window-time]", SOX_EFF_MODIFY, |
||||
getopts, start, flow, drain, stop, NULL, sizeof(priv_t)}; |
||||
return &handler; |
||||
} |
@ -1,326 +0,0 @@ |
||||
/* libSoX Basic time stretcher.
|
||||
* (c) march/april 2000 Fabien COELHO <fabien@coelho.net> for sox. |
||||
* |
||||
* cross fade samples so as to go slower or faster. |
||||
* |
||||
* The filter is based on 6 parameters: |
||||
* - stretch factor f |
||||
* - window size w |
||||
* - input step i |
||||
* output step o=f*i |
||||
* - steady state of window s, ss = s*w |
||||
* |
||||
* I decided of the default values of these parameters based |
||||
* on some small non extensive tests. maybe better defaults |
||||
* can be suggested. |
||||
*/ |
||||
#include "sox_i.h" |
||||
|
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <assert.h> |
||||
|
||||
#define DEFAULT_SLOW_SHIFT_RATIO 0.8 |
||||
#define DEFAULT_FAST_SHIFT_RATIO 1.0 |
||||
|
||||
#define DEFAULT_STRETCH_WINDOW 20.0 /* ms */ |
||||
|
||||
typedef enum { input_state, output_state } stretch_status_t; |
||||
|
||||
typedef struct { |
||||
/* options
|
||||
* FIXME: maybe shift could be allowed > 1.0 with factor < 1.0 ??? |
||||
*/ |
||||
double factor; /* strech factor. 1.0 means copy. */ |
||||
double window; /* window in ms */ |
||||
double shift; /* shift ratio wrt window. <1.0 */ |
||||
double fading; /* fading ratio wrt window. <0.5 */ |
||||
|
||||
/* internal stuff */ |
||||
stretch_status_t state; /* automaton status */ |
||||
|
||||
size_t segment; /* buffer size */ |
||||
size_t index; /* next available element */ |
||||
sox_sample_t *ibuf; /* input buffer */ |
||||
size_t ishift; /* input shift */ |
||||
|
||||
size_t oindex; /* next evailable element */ |
||||
double * obuf; /* output buffer */ |
||||
size_t oshift; /* output shift */ |
||||
|
||||
size_t overlap; /* fading size */ |
||||
double * fade_coefs; /* fading, 1.0 -> 0.0 */ |
||||
|
||||
} priv_t; |
||||
|
||||
/*
|
||||
* Process options |
||||
*/ |
||||
static int getopts(sox_effect_t * effp, int argc, char **argv) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
--argc, ++argv; |
||||
|
||||
/* default options */ |
||||
p->factor = 1.0; /* default is no change */ |
||||
p->window = DEFAULT_STRETCH_WINDOW; |
||||
|
||||
if (argc > 0 && !sscanf(argv[0], "%lf", &p->factor)) { |
||||
lsx_fail("error while parsing factor"); |
||||
return lsx_usage(effp); |
||||
} |
||||
|
||||
if (argc > 1 && !sscanf(argv[1], "%lf", &p->window)) { |
||||
lsx_fail("error while parsing window size"); |
||||
return lsx_usage(effp); |
||||
} |
||||
|
||||
if (argc > 2) { |
||||
switch (argv[2][0]) { |
||||
case 'l': |
||||
case 'L': |
||||
break; |
||||
default: |
||||
lsx_fail("error while parsing fade type"); |
||||
return lsx_usage(effp); |
||||
} |
||||
} |
||||
|
||||
/* default shift depends whether we go slower or faster */ |
||||
p->shift = (p->factor <= 1.0) ? |
||||
DEFAULT_FAST_SHIFT_RATIO: DEFAULT_SLOW_SHIFT_RATIO; |
||||
|
||||
if (argc > 3 && !sscanf(argv[3], "%lf", &p->shift)) { |
||||
lsx_fail("error while parsing shift ratio"); |
||||
return lsx_usage(effp); |
||||
} |
||||
|
||||
if (p->shift > 1.0 || p->shift <= 0.0) { |
||||
lsx_fail("error with shift ratio value"); |
||||
return lsx_usage(effp); |
||||
} |
||||
|
||||
/* default fading stuff...
|
||||
it makes sense for factor >= 0.5 */ |
||||
if (p->factor < 1.0) |
||||
p->fading = 1.0 - (p->factor * p->shift); |
||||
else |
||||
p->fading = 1.0 - p->shift; |
||||
if (p->fading > 0.5) |
||||
p->fading = 0.5; |
||||
|
||||
if (argc > 4 && !sscanf(argv[4], "%lf", &p->fading)) { |
||||
lsx_fail("error while parsing fading ratio"); |
||||
return lsx_usage(effp); |
||||
} |
||||
|
||||
if (p->fading > 0.5 || p->fading < 0.0) { |
||||
lsx_fail("error with fading ratio value"); |
||||
return lsx_usage(effp); |
||||
} |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/*
|
||||
* Start processing |
||||
*/ |
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
size_t i; |
||||
|
||||
if (p->factor == 1) |
||||
return SOX_EFF_NULL; |
||||
|
||||
p->state = input_state; |
||||
|
||||
p->segment = (int)(effp->out_signal.rate * 0.001 * p->window); |
||||
/* start in the middle of an input to avoid initial fading... */ |
||||
p->index = p->segment / 2; |
||||
p->ibuf = lsx_malloc(p->segment * sizeof(sox_sample_t)); |
||||
|
||||
/* the shift ratio deal with the longest of ishift/oshift
|
||||
hence ishift<=segment and oshift<=segment. */ |
||||
if (p->factor < 1.0) { |
||||
p->ishift = p->shift * p->segment; |
||||
p->oshift = p->factor * p->ishift; |
||||
} else { |
||||
p->oshift = p->shift * p->segment; |
||||
p->ishift = p->oshift / p->factor; |
||||
} |
||||
assert(p->ishift <= p->segment); |
||||
assert(p->oshift <= p->segment); |
||||
|
||||
p->oindex = p->index; /* start as synchronized */ |
||||
p->obuf = lsx_malloc(p->segment * sizeof(double)); |
||||
p->overlap = (int)(p->fading * p->segment); |
||||
p->fade_coefs = lsx_malloc(p->overlap * sizeof(double)); |
||||
|
||||
/* initialize buffers */ |
||||
for (i = 0; i<p->segment; i++) |
||||
p->ibuf[i] = 0; |
||||
|
||||
for (i = 0; i<p->segment; i++) |
||||
p->obuf[i] = 0.0; |
||||
|
||||
if (p->overlap>1) { |
||||
double slope = 1.0 / (p->overlap - 1); |
||||
p->fade_coefs[0] = 1.0; |
||||
for (i = 1; i < p->overlap - 1; i++) |
||||
p->fade_coefs[i] = slope * (p->overlap - i - 1); |
||||
p->fade_coefs[p->overlap - 1] = 0.0; |
||||
} else if (p->overlap == 1) |
||||
p->fade_coefs[0] = 1.0; |
||||
|
||||
lsx_debug("start: (factor=%g segment=%g shift=%g overlap=%g)\nstate=%d\n" |
||||
"segment=%" PRIuPTR "\nindex=%" PRIuPTR "\n" |
||||
"ishift=%" PRIuPTR "\noindex=%" PRIuPTR "\n" |
||||
"oshift=%" PRIuPTR "\noverlap=%" PRIuPTR, |
||||
p->factor, p->window, p->shift, p->fading, p->state, |
||||
p->segment, p->index, p->ishift, p->oindex, p->oshift, p->overlap); |
||||
|
||||
effp->out_signal.length = SOX_UNKNOWN_LEN; /* TODO: calculate actual length */ |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
/* accumulates input ibuf to output obuf with fading fade_coefs */ |
||||
static void combine(priv_t * p) |
||||
{ |
||||
size_t i; |
||||
|
||||
/* fade in */ |
||||
for (i = 0; i < p->overlap; i++) |
||||
p->obuf[i] += p->fade_coefs[p->overlap - 1 - i] * p->ibuf[i]; |
||||
|
||||
/* steady state */ |
||||
for (; i < p->segment - p->overlap; i++) |
||||
p->obuf[i] += p->ibuf[i]; |
||||
|
||||
/* fade out */ |
||||
for (; i<p->segment; i++) |
||||
p->obuf[i] += p->fade_coefs[i - p->segment + p->overlap] * p->ibuf[i]; |
||||
} |
||||
|
||||
/*
|
||||
* Processes flow. |
||||
*/ |
||||
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 iindex = 0, oindex = 0; |
||||
size_t i; |
||||
|
||||
while (iindex<*isamp && oindex<*osamp) { |
||||
if (p->state == input_state) { |
||||
size_t tocopy = min(*isamp-iindex, |
||||
p->segment-p->index); |
||||
|
||||
memcpy(p->ibuf + p->index, ibuf + iindex, tocopy * sizeof(sox_sample_t)); |
||||
|
||||
iindex += tocopy; |
||||
p->index += tocopy; |
||||
|
||||
if (p->index == p->segment) { |
||||
/* compute */ |
||||
combine(p); |
||||
|
||||
/* shift input */ |
||||
for (i = 0; i + p->ishift < p->segment; i++) |
||||
p->ibuf[i] = p->ibuf[i+p->ishift]; |
||||
|
||||
p->index -= p->ishift; |
||||
|
||||
/* switch to output state */ |
||||
p->state = output_state; |
||||
} |
||||
} |
||||
|
||||
if (p->state == output_state) { |
||||
while (p->oindex < p->oshift && oindex < *osamp) { |
||||
float f; |
||||
f = p->obuf[p->oindex++]; |
||||
SOX_SAMPLE_CLIP_COUNT(f, effp->clips); |
||||
obuf[oindex++] = f; |
||||
} |
||||
|
||||
if (p->oindex >= p->oshift && oindex<*osamp) { |
||||
p->oindex -= p->oshift; |
||||
|
||||
/* shift internal output buffer */ |
||||
for (i = 0; i + p->oshift < p->segment; i++) |
||||
p->obuf[i] = p->obuf[i + p->oshift]; |
||||
|
||||
/* pad with 0 */ |
||||
for (; i < p->segment; i++) |
||||
p->obuf[i] = 0.0; |
||||
|
||||
p->state = input_state; |
||||
} |
||||
} |
||||
} |
||||
|
||||
*isamp = iindex; |
||||
*osamp = oindex; |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* Drain buffer at the end |
||||
* maybe not correct ? end might be artificially faded? |
||||
*/ |
||||
static int drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
size_t i; |
||||
size_t oindex = 0; |
||||
|
||||
if (p->state == input_state) { |
||||
for (i=p->index; i<p->segment; i++) |
||||
p->ibuf[i] = 0; |
||||
|
||||
combine(p); |
||||
|
||||
p->state = output_state; |
||||
} |
||||
|
||||
while (oindex<*osamp && p->oindex<p->index) { |
||||
float f = p->obuf[p->oindex++]; |
||||
SOX_SAMPLE_CLIP_COUNT(f, effp->clips); |
||||
obuf[oindex++] = f; |
||||
} |
||||
|
||||
*osamp = oindex; |
||||
|
||||
if (p->oindex == p->index) |
||||
return SOX_EOF; |
||||
else |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
|
||||
static int stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
|
||||
free(p->ibuf); |
||||
free(p->obuf); |
||||
free(p->fade_coefs); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
const sox_effect_handler_t *lsx_stretch_effect_fn(void) |
||||
{ |
||||
static const sox_effect_handler_t handler = { |
||||
"stretch", |
||||
"factor [window fade shift fading]\n" |
||||
" (expansion, frame in ms, lin/..., unit<1.0, unit<0.5)\n" |
||||
" (defaults: 1.0 20 lin ...)", |
||||
SOX_EFF_LENGTH, |
||||
getopts, start, flow, drain, stop, NULL, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,520 +0,0 @@ |
||||
/* libSoX direct to Sun Audio Driver
|
||||
* |
||||
* Added by Chris Bagwell (cbagwell@sprynet.com) on 2/26/96 |
||||
* Based on oss handler. |
||||
* |
||||
* Cleaned up changes of format somewhat in sunstartwrite on 03/31/98 |
||||
* |
||||
*/ |
||||
|
||||
/*
|
||||
* Copyright 1997 Chris Bagwell And Sundry Contributors |
||||
* This source code is freely redistributable and may be used for |
||||
* any purpose. This copyright notice must be maintained. |
||||
* Rick Richardson, Lance Norskog And Sundry Contributors are not |
||||
* responsible for the consequences of using this software. |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
#include "g711.h" |
||||
|
||||
#include <sys/ioctl.h> |
||||
#include <sys/types.h> |
||||
#ifdef HAVE_SUN_AUDIOIO_H |
||||
#include <sun/audioio.h> |
||||
#else |
||||
#include <sys/audioio.h> |
||||
#endif |
||||
#include <errno.h> |
||||
#if !defined(__NetBSD__) && !defined(__OpenBSD__) |
||||
#include <stropts.h> |
||||
#endif |
||||
#include <stdlib.h> |
||||
#include <fcntl.h> |
||||
#include <string.h> |
||||
#ifdef HAVE_UNISTD_H |
||||
#include <unistd.h> |
||||
#endif |
||||
|
||||
typedef struct |
||||
{ |
||||
char* pOutput; |
||||
unsigned cOutput; |
||||
int device; |
||||
unsigned sample_shift; |
||||
} priv_t; |
||||
|
||||
/*
|
||||
* Do anything required before you start reading samples. |
||||
* Read file header. |
||||
* Find out sampling rate, |
||||
* size and encoding of samples, |
||||
* mono/stereo/quad. |
||||
*/ |
||||
static int sunstartread(sox_format_t * ft) |
||||
{ |
||||
char const* szDevname; |
||||
priv_t* pPriv = (priv_t*)ft->priv; |
||||
|
||||
size_t samplesize, encoding; |
||||
audio_info_t audio_if; |
||||
#ifdef __SVR4 |
||||
audio_device_t audio_dev; |
||||
#endif |
||||
char simple_hw=0; |
||||
|
||||
lsx_set_signal_defaults(ft); |
||||
|
||||
if (ft->filename == 0 || ft->filename[0] == 0 || !strcasecmp("default", ft->filename)) { |
||||
szDevname = "/dev/audio"; |
||||
} else { |
||||
szDevname = ft->filename; |
||||
} |
||||
|
||||
pPriv->device = open(szDevname, O_RDONLY); |
||||
if (pPriv->device < 0) { |
||||
lsx_fail_errno(ft, errno, "open failed for device %s", szDevname); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) ft->encoding.encoding = SOX_ENCODING_ULAW; |
||||
|
||||
#ifdef __SVR4 |
||||
/* Read in old values, change to what we need and then send back */ |
||||
if (ioctl(pPriv->device, AUDIO_GETDEV, &audio_dev) < 0) { |
||||
lsx_fail_errno(ft,errno,"Unable to get information for device %s", szDevname); |
||||
return(SOX_EOF); |
||||
} |
||||
lsx_report("Hardware detected: %s",audio_dev.name); |
||||
if (strcmp("SUNW,am79c30",audio_dev.name) == 0) |
||||
{ |
||||
simple_hw = 1; |
||||
} |
||||
#endif |
||||
|
||||
/* If simple hardware detected in force data to ulaw. */ |
||||
if (simple_hw) |
||||
{ |
||||
if (ft->encoding.bits_per_sample == 8) |
||||
{ |
||||
if (ft->encoding.encoding != SOX_ENCODING_ULAW && |
||||
ft->encoding.encoding != SOX_ENCODING_ALAW) |
||||
{ |
||||
lsx_report("Warning: Detected simple hardware. Forcing output to ULAW"); |
||||
ft->encoding.encoding = SOX_ENCODING_ULAW; |
||||
} |
||||
} |
||||
else if (ft->encoding.bits_per_sample == 16) |
||||
{ |
||||
lsx_report("Warning: Detected simple hardware. Forcing output to ULAW"); |
||||
ft->encoding.bits_per_sample = 8; |
||||
ft->encoding.encoding = SOX_ENCODING_ULAW; |
||||
} |
||||
} |
||||
|
||||
if (ft->encoding.bits_per_sample == 8) { |
||||
samplesize = 8; |
||||
pPriv->sample_shift = 0; |
||||
if (ft->encoding.encoding != SOX_ENCODING_ULAW && |
||||
ft->encoding.encoding != SOX_ENCODING_ALAW && |
||||
ft->encoding.encoding != SOX_ENCODING_SIGN2) { |
||||
lsx_fail_errno(ft,SOX_EFMT,"Sun audio driver only supports ULAW, ALAW, and signed linear for bytes."); |
||||
return (SOX_EOF); |
||||
} |
||||
if ((ft->encoding.encoding == SOX_ENCODING_ULAW || |
||||
ft->encoding.encoding == SOX_ENCODING_ALAW) && |
||||
ft->signal.channels == 2) |
||||
{ |
||||
lsx_report("Warning: only support mono for ULAW and ALAW data. Forcing to mono."); |
||||
ft->signal.channels = 1; |
||||
} |
||||
} |
||||
else if (ft->encoding.bits_per_sample == 16) { |
||||
samplesize = 16; |
||||
pPriv->sample_shift = 1; |
||||
if (ft->encoding.encoding != SOX_ENCODING_SIGN2) { |
||||
lsx_fail_errno(ft,SOX_EFMT,"Sun audio driver only supports signed linear for words."); |
||||
return(SOX_EOF); |
||||
} |
||||
} |
||||
else { |
||||
lsx_fail_errno(ft,SOX_EFMT,"Sun audio driver only supports bytes and words"); |
||||
return(SOX_EOF); |
||||
} |
||||
|
||||
if (ft->signal.channels == 0) |
||||
ft->signal.channels = 1; |
||||
else if (ft->signal.channels > 1) { |
||||
lsx_report("Warning: some Sun audio devices can not play stereo"); |
||||
lsx_report("at all or sometimes only with signed words. If the"); |
||||
lsx_report("sound seems sluggish then this is probably the case."); |
||||
lsx_report("Try forcing output to signed words or use the avg"); |
||||
lsx_report("filter to reduce the number of channels."); |
||||
ft->signal.channels = 2; |
||||
} |
||||
|
||||
/* Read in old values, change to what we need and then send back */ |
||||
if (ioctl(pPriv->device, AUDIO_GETINFO, &audio_if) < 0) { |
||||
lsx_fail_errno(ft,errno,"Unable to initialize %s", szDevname); |
||||
return(SOX_EOF); |
||||
} |
||||
audio_if.record.precision = samplesize; |
||||
audio_if.record.channels = ft->signal.channels; |
||||
audio_if.record.sample_rate = ft->signal.rate; |
||||
if (ft->encoding.encoding == SOX_ENCODING_ULAW) |
||||
encoding = AUDIO_ENCODING_ULAW; |
||||
else if (ft->encoding.encoding == SOX_ENCODING_ALAW) |
||||
encoding = AUDIO_ENCODING_ALAW; |
||||
else |
||||
encoding = AUDIO_ENCODING_LINEAR; |
||||
audio_if.record.encoding = encoding; |
||||
|
||||
ioctl(pPriv->device, AUDIO_SETINFO, &audio_if); |
||||
if (audio_if.record.precision != samplesize) { |
||||
lsx_fail_errno(ft,errno,"Unable to initialize sample size for %s", szDevname); |
||||
return(SOX_EOF); |
||||
} |
||||
if (audio_if.record.channels != ft->signal.channels) { |
||||
lsx_fail_errno(ft,errno,"Unable to initialize number of channels for %s", szDevname); |
||||
return(SOX_EOF); |
||||
} |
||||
if (audio_if.record.sample_rate != ft->signal.rate) { |
||||
lsx_fail_errno(ft,errno,"Unable to initialize rate for %s", szDevname); |
||||
return(SOX_EOF); |
||||
} |
||||
if (audio_if.record.encoding != encoding) { |
||||
lsx_fail_errno(ft,errno,"Unable to initialize encoding for %s", szDevname); |
||||
return(SOX_EOF); |
||||
} |
||||
/* Flush any data in the buffers - its probably in the wrong format */ |
||||
#if defined(__NetBSD__) || defined(__OpenBSD__) |
||||
ioctl(pPriv->device, AUDIO_FLUSH); |
||||
#elif defined __GLIBC__ |
||||
ioctl(pPriv->device, (unsigned long int)I_FLUSH, FLUSHR); |
||||
#else |
||||
ioctl(pPriv->device, I_FLUSH, FLUSHR); |
||||
#endif |
||||
|
||||
pPriv->cOutput = 0; |
||||
pPriv->pOutput = NULL; |
||||
|
||||
return (SOX_SUCCESS); |
||||
} |
||||
|
||||
static int sunstartwrite(sox_format_t * ft) |
||||
{ |
||||
size_t samplesize, encoding; |
||||
audio_info_t audio_if; |
||||
#ifdef __SVR4 |
||||
audio_device_t audio_dev; |
||||
#endif |
||||
char simple_hw=0; |
||||
char const* szDevname; |
||||
priv_t* pPriv = (priv_t*)ft->priv; |
||||
|
||||
if (ft->filename == 0 || ft->filename[0] == 0 || !strcasecmp("default", ft->filename)) { |
||||
szDevname = "/dev/audio"; |
||||
} else { |
||||
szDevname = ft->filename; |
||||
} |
||||
|
||||
pPriv->device = open(szDevname, O_WRONLY); |
||||
if (pPriv->device < 0) { |
||||
lsx_fail_errno(ft, errno, "open failed for device: %s", szDevname); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
#ifdef __SVR4 |
||||
/* Read in old values, change to what we need and then send back */ |
||||
if (ioctl(pPriv->device, AUDIO_GETDEV, &audio_dev) < 0) { |
||||
lsx_fail_errno(ft,errno,"Unable to get device information."); |
||||
return(SOX_EOF); |
||||
} |
||||
lsx_report("Hardware detected: %s",audio_dev.name); |
||||
if (strcmp("SUNW,am79c30",audio_dev.name) == 0) |
||||
{ |
||||
simple_hw = 1; |
||||
} |
||||
#endif |
||||
|
||||
if (simple_hw) |
||||
{ |
||||
if (ft->encoding.bits_per_sample == 8) |
||||
{ |
||||
if (ft->encoding.encoding != SOX_ENCODING_ULAW && |
||||
ft->encoding.encoding != SOX_ENCODING_ALAW) |
||||
{ |
||||
lsx_report("Warning: Detected simple hardware. Forcing output to ULAW"); |
||||
ft->encoding.encoding = SOX_ENCODING_ULAW; |
||||
} |
||||
} |
||||
else if (ft->encoding.bits_per_sample == 16) |
||||
{ |
||||
lsx_report("Warning: Detected simple hardware. Forcing output to ULAW"); |
||||
ft->encoding.bits_per_sample = 8; |
||||
ft->encoding.encoding = SOX_ENCODING_ULAW; |
||||
} |
||||
} |
||||
|
||||
if (ft->encoding.bits_per_sample == 8) |
||||
{ |
||||
samplesize = 8; |
||||
pPriv->sample_shift = 0; |
||||
if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) |
||||
ft->encoding.encoding = SOX_ENCODING_ULAW; |
||||
else if (ft->encoding.encoding != SOX_ENCODING_ULAW && |
||||
ft->encoding.encoding != SOX_ENCODING_ALAW && |
||||
ft->encoding.encoding != SOX_ENCODING_SIGN2) { |
||||
lsx_report("Sun Audio driver only supports ULAW, ALAW, and Signed Linear for bytes."); |
||||
lsx_report("Forcing to ULAW"); |
||||
ft->encoding.encoding = SOX_ENCODING_ULAW; |
||||
} |
||||
if ((ft->encoding.encoding == SOX_ENCODING_ULAW || |
||||
ft->encoding.encoding == SOX_ENCODING_ALAW) && |
||||
ft->signal.channels == 2) |
||||
{ |
||||
lsx_report("Warning: only support mono for ULAW and ALAW data. Forcing to mono."); |
||||
ft->signal.channels = 1; |
||||
} |
||||
|
||||
} |
||||
else if (ft->encoding.bits_per_sample == 16) { |
||||
samplesize = 16; |
||||
pPriv->sample_shift = 1; |
||||
if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) |
||||
ft->encoding.encoding = SOX_ENCODING_SIGN2; |
||||
else if (ft->encoding.encoding != SOX_ENCODING_SIGN2) { |
||||
lsx_report("Sun Audio driver only supports Signed Linear for words."); |
||||
lsx_report("Forcing to Signed Linear"); |
||||
ft->encoding.encoding = SOX_ENCODING_SIGN2; |
||||
} |
||||
} |
||||
else { |
||||
lsx_report("Sun Audio driver only supports bytes and words"); |
||||
ft->encoding.bits_per_sample = 16; |
||||
ft->encoding.encoding = SOX_ENCODING_SIGN2; |
||||
samplesize = 16; |
||||
pPriv->sample_shift = 1; |
||||
} |
||||
|
||||
if (ft->signal.channels > 1) ft->signal.channels = 2; |
||||
|
||||
/* Read in old values, change to what we need and then send back */ |
||||
if (ioctl(pPriv->device, AUDIO_GETINFO, &audio_if) < 0) { |
||||
lsx_fail_errno(ft,errno,"Unable to initialize /dev/audio"); |
||||
return(SOX_EOF); |
||||
} |
||||
audio_if.play.precision = samplesize; |
||||
audio_if.play.channels = ft->signal.channels; |
||||
audio_if.play.sample_rate = ft->signal.rate; |
||||
if (ft->encoding.encoding == SOX_ENCODING_ULAW) |
||||
encoding = AUDIO_ENCODING_ULAW; |
||||
else if (ft->encoding.encoding == SOX_ENCODING_ALAW) |
||||
encoding = AUDIO_ENCODING_ALAW; |
||||
else |
||||
encoding = AUDIO_ENCODING_LINEAR; |
||||
audio_if.play.encoding = encoding; |
||||
|
||||
ioctl(pPriv->device, AUDIO_SETINFO, &audio_if); |
||||
if (audio_if.play.precision != samplesize) { |
||||
lsx_fail_errno(ft,errno,"Unable to initialize sample size for /dev/audio"); |
||||
return(SOX_EOF); |
||||
} |
||||
if (audio_if.play.channels != ft->signal.channels) { |
||||
lsx_fail_errno(ft,errno,"Unable to initialize number of channels for /dev/audio"); |
||||
return(SOX_EOF); |
||||
} |
||||
if (audio_if.play.sample_rate != ft->signal.rate) { |
||||
lsx_fail_errno(ft,errno,"Unable to initialize rate for /dev/audio"); |
||||
return(SOX_EOF); |
||||
} |
||||
if (audio_if.play.encoding != encoding) { |
||||
lsx_fail_errno(ft,errno,"Unable to initialize encoding for /dev/audio"); |
||||
return(SOX_EOF); |
||||
} |
||||
|
||||
pPriv->cOutput = sox_globals.bufsiz >> pPriv->sample_shift; |
||||
pPriv->pOutput = lsx_malloc((size_t)pPriv->cOutput << pPriv->sample_shift); |
||||
|
||||
return (SOX_SUCCESS); |
||||
} |
||||
|
||||
static int sunstop(sox_format_t* ft) |
||||
{ |
||||
priv_t* pPriv = (priv_t*)ft->priv; |
||||
if (pPriv->device >= 0) { |
||||
close(pPriv->device); |
||||
} |
||||
if (pPriv->pOutput) { |
||||
free(pPriv->pOutput); |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
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) |
||||
|
||||
static size_t sunread(sox_format_t* ft, sox_sample_t* pOutput, size_t cOutput) |
||||
{ |
||||
priv_t* pPriv = (priv_t*)ft->priv; |
||||
char* pbOutput = (char*)pOutput; |
||||
size_t cbOutputLeft = cOutput << pPriv->sample_shift; |
||||
size_t i, cRead; |
||||
int cbRead; |
||||
SOX_SAMPLE_LOCALS; |
||||
LSX_USE_VAR(sox_macro_temp_double); |
||||
|
||||
while (cbOutputLeft) { |
||||
cbRead = read(pPriv->device, pbOutput, cbOutputLeft); |
||||
if (cbRead <= 0) { |
||||
if (cbRead < 0) { |
||||
lsx_fail_errno(ft, errno, "Error reading from device"); |
||||
return 0; |
||||
} |
||||
break; |
||||
} |
||||
cbOutputLeft -= cbRead; |
||||
pbOutput += cbRead; |
||||
} |
||||
|
||||
/* Convert in-place (backwards) */ |
||||
cRead = cOutput - (cbOutputLeft >> pPriv->sample_shift); |
||||
switch (pPriv->sample_shift) |
||||
{ |
||||
case 0: |
||||
switch (ft->encoding.encoding) |
||||
{ |
||||
case SOX_ENCODING_SIGN2: |
||||
for (i = cRead; i != 0; i--) { |
||||
pOutput[i - 1] = SOX_UNSIGNED_8BIT_TO_SAMPLE( |
||||
((sox_uint8_t*)pOutput)[i - 1], |
||||
dummy); |
||||
} |
||||
break; |
||||
case SOX_ENCODING_ULAW: |
||||
for (i = cRead; i != 0; i--) { |
||||
pOutput[i - 1] = SOX_ULAW_BYTE_TO_SAMPLE( |
||||
((sox_uint8_t*)pOutput)[i - 1], |
||||
dummy); |
||||
} |
||||
break; |
||||
case SOX_ENCODING_ALAW: |
||||
for (i = cRead; i != 0; i--) { |
||||
pOutput[i - 1] = SOX_ALAW_BYTE_TO_SAMPLE( |
||||
((sox_uint8_t*)pOutput)[i - 1], |
||||
dummy); |
||||
} |
||||
break; |
||||
default: |
||||
return 0; |
||||
} |
||||
break; |
||||
case 1: |
||||
for (i = cRead; i != 0; i--) { |
||||
pOutput[i - 1] = SOX_SIGNED_16BIT_TO_SAMPLE( |
||||
((sox_int16_t*)pOutput)[i - 1], |
||||
dummy); |
||||
} |
||||
break; |
||||
} |
||||
|
||||
return cRead; |
||||
} |
||||
|
||||
static size_t sunwrite( |
||||
sox_format_t* ft, |
||||
const sox_sample_t* pInput, |
||||
size_t cInput) |
||||
{ |
||||
priv_t* pPriv = (priv_t*)ft->priv; |
||||
size_t cInputRemaining = cInput; |
||||
unsigned cClips = 0; |
||||
SOX_SAMPLE_LOCALS; |
||||
|
||||
while (cInputRemaining) { |
||||
size_t cStride; |
||||
size_t i; |
||||
size_t cbStride; |
||||
int cbWritten; |
||||
|
||||
cStride = cInputRemaining; |
||||
if (cStride > pPriv->cOutput) { |
||||
cStride = pPriv->cOutput; |
||||
} |
||||
|
||||
switch (pPriv->sample_shift) |
||||
{ |
||||
case 0: |
||||
switch (ft->encoding.encoding) |
||||
{ |
||||
case SOX_ENCODING_SIGN2: |
||||
for (i = 0; i != cStride; i++) { |
||||
((sox_uint8_t*)pPriv->pOutput)[i] = |
||||
SOX_SAMPLE_TO_UNSIGNED_8BIT(pInput[i], cClips); |
||||
} |
||||
break; |
||||
case SOX_ENCODING_ULAW: |
||||
for (i = 0; i != cStride; i++) { |
||||
((sox_uint8_t*)pPriv->pOutput)[i] = |
||||
SOX_SAMPLE_TO_ULAW_BYTE(pInput[i], cClips); |
||||
} |
||||
break; |
||||
case SOX_ENCODING_ALAW: |
||||
for (i = 0; i != cStride; i++) { |
||||
((sox_uint8_t*)pPriv->pOutput)[i] = |
||||
SOX_SAMPLE_TO_ALAW_BYTE(pInput[i], cClips); |
||||
} |
||||
break; |
||||
default: |
||||
return 0; |
||||
} |
||||
break; |
||||
case 1: |
||||
for (i = 0; i != cStride; i++) { |
||||
((sox_int16_t*)pPriv->pOutput)[i] = |
||||
SOX_SAMPLE_TO_SIGNED_16BIT(pInput[i], cClips); |
||||
} |
||||
break; |
||||
} |
||||
|
||||
cbStride = cStride << pPriv->sample_shift; |
||||
i = 0; |
||||
do { |
||||
cbWritten = write(pPriv->device, &pPriv->pOutput[i], cbStride - i); |
||||
i += cbWritten; |
||||
if (cbWritten <= 0) { |
||||
lsx_fail_errno(ft, errno, "Error writing to device"); |
||||
return 0; |
||||
} |
||||
} while (i != cbStride); |
||||
|
||||
cInputRemaining -= cStride; |
||||
pInput += cStride; |
||||
} |
||||
|
||||
return cInput; |
||||
} |
||||
|
||||
LSX_FORMAT_HANDLER(sunau) |
||||
{ |
||||
static char const * const names[] = {"sunau", NULL}; |
||||
static unsigned const write_encodings[] = { |
||||
SOX_ENCODING_ULAW, 8, 0, |
||||
SOX_ENCODING_ALAW, 8, 0, |
||||
SOX_ENCODING_SIGN2, 8, 16, 0, |
||||
0}; |
||||
static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, |
||||
"Sun audio device driver", |
||||
names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO, |
||||
sunstartread, sunread, sunstop, |
||||
sunstartwrite, sunwrite, sunstop, |
||||
NULL, write_encodings, NULL, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,62 +0,0 @@ |
||||
/* libSoX effect: swap pairs of audio channels
|
||||
* |
||||
* First version written 01/2012 by Ulrich Klauer. |
||||
* Replaces an older swap effect originally written by Chris Bagwell |
||||
* on March 16, 1999. |
||||
* |
||||
* Copyright 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 |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
static int start(sox_effect_t *effp) |
||||
{ |
||||
return effp->in_signal.channels >= 2 ? SOX_SUCCESS : SOX_EFF_NULL; |
||||
} |
||||
|
||||
static int flow(sox_effect_t *effp, const sox_sample_t *ibuf, |
||||
sox_sample_t *obuf, size_t *isamp, size_t *osamp) |
||||
{ |
||||
size_t len = min(*isamp, *osamp); |
||||
size_t channels = effp->in_signal.channels; |
||||
len /= channels; |
||||
*isamp = *osamp = len * channels; |
||||
|
||||
while (len--) { |
||||
size_t i; |
||||
for (i = 0; i + 1 < channels; i += 2) { |
||||
*obuf++ = ibuf[1]; |
||||
*obuf++ = ibuf[0]; |
||||
ibuf += 2; |
||||
} |
||||
if (channels % 2) |
||||
*obuf++ = *ibuf++; |
||||
} |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const *lsx_swap_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"swap", NULL, |
||||
SOX_EFF_MCHAN | SOX_EFF_MODIFY, |
||||
NULL, start, flow, NULL, NULL, NULL, |
||||
0 |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,677 +0,0 @@ |
||||
/* libSoX synth - Synthesizer Effect.
|
||||
* |
||||
* Copyright (c) 2001-2009 SoX contributors |
||||
* Copyright (c) Jan 2001 Carsten Borchardt |
||||
* |
||||
* This source code is freely redistributable and may be used for any purpose. |
||||
* This copyright notice must be maintained. The authors are not responsible |
||||
* for the consequences of using this software. |
||||
* |
||||
* Except for synth types: pluck, tpdf, pinknoise, & brownnoise, and |
||||
* sweep types: linear, square & exp, which are: |
||||
* |
||||
* Copyright (c) 2006-2013 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> |
||||
#include <ctype.h> |
||||
|
||||
typedef enum { |
||||
synth_sine, |
||||
synth_square, |
||||
synth_sawtooth, |
||||
synth_triangle, |
||||
synth_trapezium, |
||||
synth_trapetz = synth_trapezium, /* Deprecated name for trapezium */ |
||||
synth_exp, |
||||
/* Tones above, noises below */ |
||||
synth_whitenoise, |
||||
synth_noise = synth_whitenoise, /* Just a handy alias */ |
||||
synth_tpdfnoise, |
||||
synth_pinknoise, |
||||
synth_brownnoise, |
||||
synth_pluck |
||||
} type_t; |
||||
|
||||
static lsx_enum_item const synth_type[] = { |
||||
LSX_ENUM_ITEM(synth_, sine) |
||||
LSX_ENUM_ITEM(synth_, square) |
||||
LSX_ENUM_ITEM(synth_, sawtooth) |
||||
LSX_ENUM_ITEM(synth_, triangle) |
||||
LSX_ENUM_ITEM(synth_, trapezium) |
||||
LSX_ENUM_ITEM(synth_, trapetz) |
||||
LSX_ENUM_ITEM(synth_, exp) |
||||
LSX_ENUM_ITEM(synth_, whitenoise) |
||||
LSX_ENUM_ITEM(synth_, noise) |
||||
LSX_ENUM_ITEM(synth_, tpdfnoise) |
||||
LSX_ENUM_ITEM(synth_, pinknoise) |
||||
LSX_ENUM_ITEM(synth_, brownnoise) |
||||
LSX_ENUM_ITEM(synth_, pluck) |
||||
{0, 0} |
||||
}; |
||||
|
||||
typedef enum {synth_create, synth_mix, synth_amod, synth_fmod} combine_t; |
||||
|
||||
static lsx_enum_item const combine_type[] = { |
||||
LSX_ENUM_ITEM(synth_, create) |
||||
LSX_ENUM_ITEM(synth_, mix) |
||||
LSX_ENUM_ITEM(synth_, amod) |
||||
LSX_ENUM_ITEM(synth_, fmod) |
||||
{0, 0} |
||||
}; |
||||
|
||||
|
||||
|
||||
typedef enum {Linear, Square, Exp, Exp_cycle} sweep_t; |
||||
|
||||
typedef struct { |
||||
/* options */ |
||||
type_t type; |
||||
combine_t combine; |
||||
double freq, freq2, mult; |
||||
sweep_t sweep; |
||||
double offset, phase; |
||||
double p1, p2, p3; /* Use depends on synth type */ |
||||
|
||||
/* internal stuff */ |
||||
double lp_last_out, hp_last_out, hp_last_in, ap_last_out, ap_last_in; |
||||
double cycle_start_time_s, c0, c1, c2, c3, c4, c5, c6; |
||||
|
||||
double * buffer; |
||||
size_t buffer_len, pos; |
||||
} channel_t; |
||||
|
||||
|
||||
|
||||
/* Private data for the synthesizer */ |
||||
typedef struct { |
||||
char * length_str; |
||||
channel_t * getopts_channels; |
||||
size_t getopts_nchannels; |
||||
uint64_t samples_done; |
||||
uint64_t samples_to_do; |
||||
channel_t * channels; |
||||
size_t number_of_channels; |
||||
sox_bool no_headroom; |
||||
double gain; |
||||
} priv_t; |
||||
|
||||
|
||||
|
||||
static void create_channel(channel_t * chan) |
||||
{ |
||||
memset(chan, 0, sizeof(*chan)); |
||||
chan->freq2 = chan->freq = 440; |
||||
chan->p3 = chan->p2 = chan->p1 = -1; |
||||
} |
||||
|
||||
|
||||
|
||||
static void set_default_parameters(channel_t * chan) |
||||
{ |
||||
switch (chan->type) { |
||||
case synth_square: /* p1 is pulse width */ |
||||
if (chan->p1 < 0) |
||||
chan->p1 = 0.5; /* default to 50% duty cycle */ |
||||
break; |
||||
|
||||
case synth_triangle: /* p1 is position of maximum */ |
||||
if (chan->p1 < 0) |
||||
chan->p1 = 0.5; |
||||
break; |
||||
|
||||
case synth_trapezium: |
||||
/* p1 is length of rising slope,
|
||||
* p2 position where falling slope begins |
||||
* p3 position of end of falling slope |
||||
*/ |
||||
if (chan->p1 < 0) { |
||||
chan->p1 = 0.1; |
||||
chan->p2 = 0.5; |
||||
chan->p3 = 0.6; |
||||
} else if (chan->p2 < 0) { /* try a symmetric waveform */ |
||||
if (chan->p1 <= 0.5) { |
||||
chan->p2 = (1 - 2 * chan->p1) / 2; |
||||
chan->p3 = chan->p2 + chan->p1; |
||||
} else { |
||||
/* symetric is not possible, fall back to asymmetrical triangle */ |
||||
chan->p2 = chan->p1; |
||||
chan->p3 = 1; |
||||
} |
||||
} else if (chan->p3 < 0) |
||||
chan->p3 = 1; /* simple falling slope to the end */ |
||||
break; |
||||
|
||||
case synth_exp: |
||||
if (chan->p1 < 0) /* p1 is position of maximum */ |
||||
chan->p1 = 0.5; |
||||
if (chan->p2 < 0) /* p2 is amplitude */ |
||||
chan->p2 = .5; |
||||
break; |
||||
|
||||
case synth_pluck: |
||||
if (chan->p1 < 0) |
||||
chan->p1 = .4; |
||||
if (chan->p2 < 0) |
||||
chan->p2 = .2, chan->p3 = .9; |
||||
|
||||
default: break; |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
#undef NUMERIC_PARAMETER |
||||
#define NUMERIC_PARAMETER(p, min, max) { \ |
||||
char * end_ptr_np; \
|
||||
double d_np = strtod(argv[argn], &end_ptr_np); \
|
||||
if (end_ptr_np == argv[argn]) \
|
||||
break; \
|
||||
if (d_np < min || d_np > max || *end_ptr_np != '\0') { \
|
||||
lsx_fail("parameter error"); \
|
||||
return SOX_EOF; \
|
||||
} \
|
||||
chan->p = d_np / 100; /* adjust so abs(parameter) <= 1 */\
|
||||
if (++argn == argc) \
|
||||
break; \
|
||||
} |
||||
|
||||
|
||||
|
||||
static int getopts(sox_effect_t * effp, int argc, char **argv) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
channel_t master, * chan = &master; |
||||
int key = INT_MAX, argn = 0; |
||||
char dummy, * end_ptr; |
||||
const char *n; |
||||
--argc, ++argv; |
||||
|
||||
if (argc && !strcmp(*argv, "-n")) p->no_headroom = sox_true, ++argv, --argc; |
||||
|
||||
if (argc > 1 && !strcmp(*argv, "-j") && ( |
||||
sscanf(argv[1], "%i %c", &key, &dummy) == 1 || ( |
||||
(key = lsx_parse_note(argv[1], &end_ptr)) != INT_MAX && |
||||
!*end_ptr))) { |
||||
argc -= 2; |
||||
argv += 2; |
||||
} |
||||
|
||||
/* Get duration if given (if first arg starts with digit) */ |
||||
if (argc && (isdigit((int)argv[argn][0]) || argv[argn][0] == '.')) { |
||||
p->length_str = lsx_strdup(argv[argn]); |
||||
/* Do a dummy parse of to see if it will fail */ |
||||
n = lsx_parsesamples(0., p->length_str, &p->samples_to_do, 't'); |
||||
if (!n || *n) |
||||
return lsx_usage(effp); |
||||
argn++; |
||||
} |
||||
|
||||
create_channel(chan); |
||||
if (argn < argc) { /* [off [ph [p1 [p2 [p3]]]]]] */ |
||||
do { /* break-able block */ |
||||
NUMERIC_PARAMETER(offset,-100, 100) |
||||
NUMERIC_PARAMETER(phase , 0, 100) |
||||
NUMERIC_PARAMETER(p1, 0, 100) |
||||
NUMERIC_PARAMETER(p2, 0, 100) |
||||
NUMERIC_PARAMETER(p3, 0, 100) |
||||
} while (0); |
||||
} |
||||
|
||||
while (argn < argc) { /* type [combine] [f1[-f2] [off [ph [p1 [p2 [p3]]]]]] */ |
||||
lsx_enum_item const * enum_p = lsx_find_enum_text(argv[argn], synth_type, lsx_find_enum_item_case_sensitive); |
||||
|
||||
if (enum_p == NULL) { |
||||
lsx_fail("no type given"); |
||||
return SOX_EOF; |
||||
} |
||||
p->getopts_channels = lsx_realloc(p->getopts_channels, sizeof(*p->getopts_channels) * (p->getopts_nchannels + 1)); |
||||
chan = &p->getopts_channels[p->getopts_nchannels++]; |
||||
memcpy(chan, &master, sizeof(*chan)); |
||||
chan->type = enum_p->value; |
||||
if (++argn == argc) |
||||
break; |
||||
|
||||
/* maybe there is a combine-type in next arg */ |
||||
enum_p = lsx_find_enum_text(argv[argn], combine_type, lsx_find_enum_item_case_sensitive); |
||||
if (enum_p != NULL) { |
||||
chan->combine = enum_p->value; |
||||
if (++argn == argc) |
||||
break; |
||||
} |
||||
|
||||
/* read frequencies if given */ |
||||
if (!lsx_find_enum_text(argv[argn], synth_type, lsx_find_enum_item_case_sensitive) && |
||||
argv[argn][0] != '-') { |
||||
static const char sweeps[] = ":+/-"; |
||||
|
||||
chan->freq2 = chan->freq = lsx_parse_frequency_k(argv[argn], &end_ptr, key); |
||||
if (chan->freq < (chan->type == synth_pluck? 27.5 : 0) || |
||||
(chan->type == synth_pluck && chan->freq > 4220)) { |
||||
lsx_fail("invalid freq"); |
||||
return SOX_EOF; |
||||
} |
||||
if (*end_ptr && strchr(sweeps, *end_ptr)) { /* freq2 given? */ |
||||
if (chan->type >= synth_noise) { |
||||
lsx_fail("can't sweep this type"); |
||||
return SOX_EOF; |
||||
} |
||||
chan->sweep = strchr(sweeps, *end_ptr) - sweeps; |
||||
chan->freq2 = lsx_parse_frequency_k(end_ptr + 1, &end_ptr, key); |
||||
if (chan->freq2 < 0) { |
||||
lsx_fail("invalid freq2"); |
||||
return SOX_EOF; |
||||
} |
||||
if (p->length_str == NULL) { |
||||
lsx_fail("duration must be given when using freq2"); |
||||
return SOX_EOF; |
||||
} |
||||
} |
||||
if (*end_ptr) { |
||||
lsx_fail("frequency: invalid trailing character"); |
||||
return SOX_EOF; |
||||
} |
||||
if (chan->sweep >= Exp && chan->freq * chan->freq2 == 0) { |
||||
lsx_fail("invalid frequency for exponential sweep"); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
if (++argn == argc) |
||||
break; |
||||
} |
||||
|
||||
/* read rest of parameters */ |
||||
do { /* break-able block */ |
||||
NUMERIC_PARAMETER(offset,-100, 100) |
||||
NUMERIC_PARAMETER(phase , 0, 100) |
||||
NUMERIC_PARAMETER(p1, 0, 100) |
||||
NUMERIC_PARAMETER(p2, 0, 100) |
||||
NUMERIC_PARAMETER(p3, 0, 100) |
||||
} while (0); |
||||
} |
||||
|
||||
/* If no channel parameters were given, create one default channel: */ |
||||
if (!p->getopts_nchannels) { |
||||
p->getopts_channels = lsx_malloc(sizeof(*p->getopts_channels)); |
||||
memcpy(&p->getopts_channels[0], &master, sizeof(channel_t)); |
||||
++p->getopts_nchannels; |
||||
} |
||||
|
||||
if (!effp->in_signal.channels) |
||||
effp->in_signal.channels = p->getopts_nchannels; |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
|
||||
|
||||
static int start(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *)effp->priv; |
||||
size_t i, j, k; |
||||
|
||||
p->samples_done = 0; |
||||
|
||||
if (p->length_str) { |
||||
if (lsx_parsesamples(effp->in_signal.rate, p->length_str, &p->samples_to_do, 't') == NULL) |
||||
return lsx_usage(effp); |
||||
} else |
||||
p->samples_to_do = effp->in_signal.length != SOX_UNKNOWN_LEN ? |
||||
effp->in_signal.length / effp->in_signal.channels : 0; |
||||
|
||||
p->number_of_channels = effp->in_signal.channels; |
||||
p->channels = lsx_calloc(p->number_of_channels, sizeof(*p->channels)); |
||||
for (i = 0; i < p->number_of_channels; ++i) { |
||||
channel_t * chan = &p->channels[i]; |
||||
*chan = p->getopts_channels[i % p->getopts_nchannels]; |
||||
set_default_parameters(chan); |
||||
if (chan->type == synth_pluck) { |
||||
double min, max, frac, p2; |
||||
|
||||
/* Low pass: */ |
||||
double const decay_rate = -2; /* dB / s */ |
||||
double const decay_f = min(912, 266 + 106 * log(chan->freq)); |
||||
double d = sqr(dB_to_linear(decay_rate / chan->freq)); |
||||
d = (d * cos(2 * M_PI * decay_f / effp->in_signal.rate) - 1) / (d - 1); |
||||
chan->c0 = d - sqrt(d * d - 1); |
||||
chan->c1 = 1 - chan->c0; |
||||
|
||||
/* Single-pole low pass is very rate-dependent: */ |
||||
if (effp->in_signal.rate < 44100 || effp->in_signal.rate > 48000) { |
||||
lsx_fail( |
||||
"sample rate for pluck must be 44100-48000; use `rate' to resample"); |
||||
return SOX_EOF; |
||||
} |
||||
/* Decay: */ |
||||
chan->c1 *= exp(-2e4/ (.05+chan->p1)/ chan->freq/ effp->in_signal.rate); |
||||
|
||||
/* High pass (DC-block): */ |
||||
chan->c2 = exp(-2 * M_PI * 10 / effp->in_signal.rate); |
||||
chan->c3 = (1 + chan->c2) * .5; |
||||
|
||||
/* All pass (for fractional delay): */ |
||||
d = chan->c0 / (chan->c0 + chan->c1); |
||||
chan->buffer_len = effp->in_signal.rate / chan->freq - d; |
||||
frac = effp->in_signal.rate / chan->freq - d - chan->buffer_len; |
||||
chan->c4 = (1 - frac) / (1 + frac); |
||||
chan->pos = 0; |
||||
|
||||
/* Exitation: */ |
||||
chan->buffer = lsx_calloc(chan->buffer_len, sizeof(*chan->buffer)); |
||||
for (k = 0, p2 = chan->p2; k < 2 && p2 >= 0; ++k, p2 = chan->p3) { |
||||
double d1 = 0, d2, colour = pow(2., 4 * (p2 - 1)); |
||||
int32_t r = p2 * 100 + .5; |
||||
for (j = 0; j < chan->buffer_len; ++j) { |
||||
do d2 = d1 + (chan->phase? DRANQD1:dranqd1(r)) * colour; |
||||
while (fabs(d2) > 1); |
||||
chan->buffer[j] += d2 * (1 - .3 * k); |
||||
d1 = d2 * (colour != 1); |
||||
#ifdef TEST_PLUCK |
||||
chan->buffer[j] = sin(2 * M_PI * j / chan->buffer_len); |
||||
#endif |
||||
} |
||||
} |
||||
|
||||
/* In-delay filter graduation: */ |
||||
for (j = 0, min = max = 0; j < chan->buffer_len; ++j) { |
||||
double d2, t = (double)j / chan->buffer_len; |
||||
chan->lp_last_out = d2 = |
||||
chan->buffer[j] * chan->c1 + chan->lp_last_out * chan->c0; |
||||
|
||||
chan->ap_last_out = |
||||
d2 * chan->c4 + chan->ap_last_in - chan->ap_last_out * chan->c4; |
||||
chan->ap_last_in = d2; |
||||
|
||||
chan->buffer[j] = chan->buffer[j] * (1 - t) + chan->ap_last_out * t; |
||||
min = min(min, chan->buffer[j]); |
||||
max = max(max, chan->buffer[j]); |
||||
} |
||||
|
||||
/* Normalise: */ |
||||
for (j = 0, d = 0; j < chan->buffer_len; ++j) { |
||||
chan->buffer[j] = (2 * chan->buffer[j] - max - min) / (max - min); |
||||
d += sqr(chan->buffer[j]); |
||||
} |
||||
lsx_debug("rms=%f c0=%f c1=%f df=%f d3f=%f c2=%f c3=%f c4=%f frac=%f", |
||||
10 * log(d / chan->buffer_len), chan->c0, chan->c1, decay_f, |
||||
log(chan->c0)/ -2 / M_PI * effp->in_signal.rate, |
||||
chan->c2, chan->c3, chan->c4, frac); |
||||
} |
||||
switch (chan->sweep) { |
||||
case Linear: chan->mult = p->samples_to_do? |
||||
(chan->freq2 - chan->freq) / p->samples_to_do / 2 : 0; |
||||
break; |
||||
case Square: chan->mult = p->samples_to_do? |
||||
sqrt(fabs(chan->freq2 - chan->freq)) / p->samples_to_do / sqrt(3.) : 0; |
||||
if (chan->freq > chan->freq2) |
||||
chan->mult = -chan->mult; |
||||
break; |
||||
case Exp: chan->mult = p->samples_to_do? |
||||
log(chan->freq2 / chan->freq) / p->samples_to_do * effp->in_signal.rate : 1; |
||||
chan->freq /= chan->mult; |
||||
break; |
||||
case Exp_cycle: chan->mult = p->samples_to_do? |
||||
(log(chan->freq2) - log(chan->freq)) / p->samples_to_do : 1; |
||||
break; |
||||
} |
||||
lsx_debug("type=%s, combine=%s, samples_to_do=%" PRIu64 ", f1=%g, f2=%g, " |
||||
"offset=%g, phase=%g, p1=%g, p2=%g, p3=%g mult=%g", |
||||
lsx_find_enum_value(chan->type, synth_type)->text, |
||||
lsx_find_enum_value(chan->combine, combine_type)->text, |
||||
p->samples_to_do, chan->freq, chan->freq2, |
||||
chan->offset, chan->phase, chan->p1, chan->p2, chan->p3, chan->mult); |
||||
} |
||||
p->gain = 1; |
||||
effp->out_signal.mult = p->no_headroom? NULL : &p->gain; |
||||
effp->out_signal.length = p->samples_to_do ? |
||||
p->samples_to_do * effp->out_signal.channels : SOX_UNKNOWN_LEN; |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
#define elapsed_time_s p->samples_done / effp->in_signal.rate |
||||
|
||||
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; |
||||
unsigned len = min(*isamp, *osamp) / effp->in_signal.channels; |
||||
unsigned c, done; |
||||
int result = SOX_SUCCESS; |
||||
|
||||
for (done = 0; done < len && result == SOX_SUCCESS; ++done) { |
||||
for (c = 0; c < effp->in_signal.channels; c++) { |
||||
sox_sample_t synth_input = *ibuf++; |
||||
channel_t * chan = &p->channels[c]; |
||||
double synth_out; /* [-1, 1] */ |
||||
|
||||
if (chan->type < synth_noise) { /* Need to calculate phase: */ |
||||
double phase; /* [0, 1) */ |
||||
switch (chan->sweep) { |
||||
case Linear: |
||||
phase = (chan->freq + p->samples_done * chan->mult) * |
||||
elapsed_time_s; |
||||
break; |
||||
case Square: |
||||
phase = (chan->freq + sign(chan->mult) *
|
||||
sqr(p->samples_done * chan->mult)) * elapsed_time_s; |
||||
break; |
||||
case Exp: |
||||
phase = chan->freq * exp(chan->mult * elapsed_time_s); |
||||
break; |
||||
case Exp_cycle: default: { |
||||
double f = chan->freq * exp(p->samples_done * chan->mult); |
||||
double cycle_elapsed_time_s = elapsed_time_s - chan->cycle_start_time_s; |
||||
if (f * cycle_elapsed_time_s >= 1) { /* move to next cycle */ |
||||
chan->cycle_start_time_s += 1 / f; |
||||
cycle_elapsed_time_s = elapsed_time_s - chan->cycle_start_time_s; |
||||
} |
||||
phase = f * cycle_elapsed_time_s; |
||||
break; |
||||
} |
||||
} |
||||
phase = fmod(phase + chan->phase, 1.0); |
||||
|
||||
switch (chan->type) { |
||||
case synth_sine: |
||||
synth_out = sin(2 * M_PI * phase); |
||||
break; |
||||
|
||||
case synth_square: |
||||
/* |_______ | +1
|
||||
* | | | |
||||
* |_______|__________| 0 |
||||
* | | | |
||||
* | |__________| -1 |
||||
* | | |
||||
* 0 p1 1 |
||||
*/ |
||||
synth_out = -1 + 2 * (phase < chan->p1); |
||||
break; |
||||
|
||||
case synth_sawtooth: |
||||
/* | __| +1
|
||||
* | __/ | |
||||
* |_______/_____| 0 |
||||
* | __/ | |
||||
* |_/ | -1 |
||||
* | | |
||||
* 0 1 |
||||
*/ |
||||
synth_out = -1 + 2 * phase; |
||||
break; |
||||
|
||||
case synth_triangle: |
||||
/* | . | +1
|
||||
* | / \ | |
||||
* |__/___\__| 0 |
||||
* | / \ | |
||||
* |/ \| -1 |
||||
* | | |
||||
* 0 p1 1 |
||||
*/ |
||||
|
||||
if (phase < chan->p1) |
||||
synth_out = -1 + 2 * phase / chan->p1; /* In rising part of period */ |
||||
else |
||||
synth_out = 1 - 2 * (phase - chan->p1) / (1 - chan->p1); /* In falling part */ |
||||
break; |
||||
|
||||
case synth_trapezium: |
||||
/* | ______ |+1
|
||||
* | / \ | |
||||
* |__/________\___________| 0 |
||||
* | / \ | |
||||
* |/ \_________|-1 |
||||
* | | |
||||
* 0 p1 p2 p3 1 |
||||
*/ |
||||
if (phase < chan->p1) /* In rising part of period */ |
||||
synth_out = -1 + 2 * phase / chan->p1; |
||||
else if (phase < chan->p2) /* In high part of period */ |
||||
synth_out = 1; |
||||
else if (phase < chan->p3) /* In falling part */ |
||||
synth_out = 1 - 2 * (phase - chan->p2) / (chan->p3 - chan->p2); |
||||
else /* In low part of period */ |
||||
synth_out = -1; |
||||
break; |
||||
|
||||
case synth_exp: |
||||
/* | | | +1
|
||||
* | | | | |
||||
* | _| |_ | 0 |
||||
* | __- -__ | |
||||
* |____--- ---____ | f(p2) |
||||
* | | |
||||
* 0 p1 1 |
||||
*/ |
||||
synth_out = dB_to_linear(chan->p2 * -200); /* 0 .. 1 */ |
||||
if (phase < chan->p1) |
||||
synth_out = synth_out * exp(phase * log(1 / synth_out) / chan->p1); |
||||
else |
||||
synth_out = synth_out * exp((1 - phase) * log(1 / synth_out) / (1 - chan->p1)); |
||||
synth_out = synth_out * 2 - 1; /* map 0 .. 1 to -1 .. +1 */ |
||||
break; |
||||
|
||||
default: synth_out = 0; |
||||
} |
||||
} else switch (chan->type) { |
||||
case synth_whitenoise: |
||||
synth_out = DRANQD1; |
||||
break; |
||||
|
||||
case synth_tpdfnoise: |
||||
synth_out = .5 * (DRANQD1 + DRANQD1); |
||||
break; |
||||
|
||||
case synth_pinknoise: { /* "Paul Kellet's refined method" */ |
||||
#define _ .125 / (65536. * 32768.) |
||||
double d = RANQD1; |
||||
chan->c0 = .99886 * chan->c0 + d * (.0555179*_);
|
||||
chan->c1 = .99332 * chan->c1 + d * (.0750759*_);
|
||||
chan->c2 = .96900 * chan->c2 + d * (.1538520*_);
|
||||
chan->c3 = .86650 * chan->c3 + d * (.3104856*_);
|
||||
chan->c4 = .55000 * chan->c4 + d * (.5329522*_);
|
||||
chan->c5 = -.7616 * chan->c5 - d * (.0168980*_);
|
||||
synth_out = chan->c0 + chan->c1 + chan->c2 + chan->c3 |
||||
+ chan->c4 + chan->c5 + chan->c6 + d * (.5362*_);
|
||||
chan->c6 = d * (.115926*_);
|
||||
break; |
||||
#undef _ |
||||
} |
||||
|
||||
case synth_brownnoise: |
||||
do synth_out = chan->lp_last_out + DRANQD1 * (1. / 16); |
||||
while (fabs(synth_out) > 1); |
||||
chan->lp_last_out = synth_out; |
||||
break; |
||||
|
||||
case synth_pluck: { |
||||
double d = chan->buffer[chan->pos]; |
||||
|
||||
chan->hp_last_out =
|
||||
(d - chan->hp_last_in) * chan->c3 + chan->hp_last_out * chan->c2; |
||||
chan->hp_last_in = d; |
||||
|
||||
synth_out = range_limit(chan->hp_last_out, -1, 1); |
||||
|
||||
chan->lp_last_out = d = d * chan->c1 + chan->lp_last_out * chan->c0; |
||||
|
||||
chan->ap_last_out = chan->buffer[chan->pos] = |
||||
(d - chan->ap_last_out) * chan->c4 + chan->ap_last_in; |
||||
chan->ap_last_in = d; |
||||
|
||||
chan->pos = chan->pos + 1 == chan->buffer_len? 0 : chan->pos + 1; |
||||
break; |
||||
} |
||||
|
||||
default: synth_out = 0; |
||||
} |
||||
|
||||
/* Add offset, but prevent clipping: */ |
||||
synth_out = synth_out * (1 - fabs(chan->offset)) + chan->offset; |
||||
|
||||
switch (chan->combine) { |
||||
case synth_create: synth_out *= SOX_SAMPLE_MAX; break; |
||||
case synth_mix : synth_out = (synth_out * SOX_SAMPLE_MAX + synth_input) * .5; break; |
||||
case synth_amod : synth_out = (synth_out + 1) * synth_input * .5; break; |
||||
case synth_fmod : synth_out *= synth_input; break; |
||||
} |
||||
*obuf++ = synth_out < 0? synth_out * p->gain - .5 : synth_out * p->gain + .5; |
||||
} |
||||
if (++p->samples_done == p->samples_to_do) |
||||
result = SOX_EOF; |
||||
} |
||||
*isamp = *osamp = done * effp->in_signal.channels; |
||||
return result; |
||||
} |
||||
|
||||
|
||||
|
||||
static int stop(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
size_t i; |
||||
|
||||
for (i = 0; i < p->number_of_channels; ++i) |
||||
free(p->channels[i].buffer); |
||||
free(p->channels); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
|
||||
|
||||
static int lsx_kill(sox_effect_t * effp) |
||||
{ |
||||
priv_t * p = (priv_t *) effp->priv; |
||||
free(p->getopts_channels); |
||||
free(p->length_str); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
|
||||
|
||||
const sox_effect_handler_t *lsx_synth_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"synth", "[-j KEY] [-n] [length [offset [phase [p1 [p2 [p3]]]]]]] {type [combine] [[%]freq[k][:|+|/|-[%]freq2[k]] [offset [phase [p1 [p2 [p3]]]]]]}", |
||||
SOX_EFF_MCHAN | SOX_EFF_LENGTH | SOX_EFF_GAIN, |
||||
getopts, start, flow, 0, stop, lsx_kill, sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
@ -1,47 +0,0 @@ |
||||
/* libSoX effect: tremolo (c) 2007 robs@users.sourceforge.net
|
||||
* |
||||
* This library is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU Lesser General Public License as published by |
||||
* the Free Software Foundation; either version 2.1 of the License, or (at |
||||
* your option) any later version. |
||||
* |
||||
* This library is distributed in the hope that it will be useful, but |
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
||||
* General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with this library; if not, write to the Free Software Foundation, |
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
static int getopts(sox_effect_t * effp, int argc, char * * argv) |
||||
{ |
||||
double speed, depth = 40; |
||||
char dummy; /* To check for extraneous chars. */ |
||||
char offset[100]; |
||||
char * args[] = {0, "sine", "fmod", 0, 0, "25"}; |
||||
|
||||
if (argc < 2 || argc > 3 || |
||||
sscanf(argv[1], "%lf %c", &speed, &dummy) != 1 || speed < 0 || |
||||
(argc > 2 && sscanf(argv[2], "%lf %c", &depth, &dummy) != 1) || |
||||
depth <= 0 || depth > 100) |
||||
return lsx_usage(effp); |
||||
args[0] = argv[0]; |
||||
args[3] = argv[1]; |
||||
sprintf(offset, "%g", 100 - depth / 2); |
||||
args[4] = offset; |
||||
return lsx_synth_effect_fn()->getopts(effp, (int)array_length(args), args); |
||||
} |
||||
|
||||
sox_effect_handler_t const * lsx_tremolo_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler; |
||||
handler = *lsx_synth_effect_fn(); |
||||
handler.name = "tremolo"; |
||||
handler.usage = "speed_Hz [depth_percent]"; |
||||
handler.getopts = getopts; |
||||
return &handler; |
||||
} |
@ -1,216 +0,0 @@ |
||||
/* libSoX effect: trim - cut portions out of the audio
|
||||
* |
||||
* First version written 01/2012 by Ulrich Klauer. |
||||
* Replaces an older trim effect originally written by Curt Zirzow in 2000. |
||||
* |
||||
* Copyright 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 |
||||
*/ |
||||
|
||||
#include "sox_i.h" |
||||
|
||||
typedef struct { |
||||
/* parameters */ |
||||
unsigned int num_pos; |
||||
struct { |
||||
uint64_t sample; /* NB: wide samples */ |
||||
char *argstr; |
||||
} *pos; |
||||
/* state */ |
||||
unsigned int current_pos; |
||||
uint64_t samples_read; /* NB: wide samples */ |
||||
sox_bool copying; |
||||
} priv_t; |
||||
|
||||
static int parse(sox_effect_t *effp, int argc, char **argv) |
||||
{ |
||||
priv_t *p = (priv_t*) effp->priv; |
||||
unsigned int i; |
||||
--argc, ++argv; |
||||
p->num_pos = argc; |
||||
lsx_Calloc(p->pos, p->num_pos); |
||||
for (i = 0; i < p->num_pos; i++) { |
||||
const char *arg = argv[i]; |
||||
p->pos[i].argstr = lsx_strdup(arg); |
||||
/* dummy parse to check for syntax errors */ |
||||
arg = lsx_parseposition(0., arg, NULL, (uint64_t)0, (uint64_t)0, '+'); |
||||
if (!arg || *arg) { |
||||
lsx_fail("Error parsing position %u", i+1); |
||||
return lsx_usage(effp); |
||||
} |
||||
} |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int start(sox_effect_t *effp) |
||||
{ |
||||
priv_t *p = (priv_t*) effp->priv; |
||||
uint64_t in_length = effp->in_signal.length != SOX_UNKNOWN_LEN ? |
||||
effp->in_signal.length / effp->in_signal.channels : SOX_UNKNOWN_LEN; |
||||
uint64_t last_seen = 0; |
||||
sox_bool open_end; |
||||
unsigned int i; |
||||
|
||||
p->copying = sox_false; |
||||
|
||||
/* calculate absolute positions */ |
||||
for (i = 0; i < p->num_pos; i++) { |
||||
if (!lsx_parseposition(effp->in_signal.rate, p->pos[i].argstr, &p->pos[i].sample, last_seen, in_length, '+')) { |
||||
lsx_fail("Position %u is relative to end of audio, but audio length is unknown", i+1); |
||||
return SOX_EOF; |
||||
} |
||||
last_seen = p->pos[i].sample; |
||||
lsx_debug_more("position %u at %" PRIu64, i+1, last_seen); |
||||
} |
||||
|
||||
/* sanity checks */ |
||||
last_seen = 0; |
||||
for (i = 0; i < p->num_pos; i++) { |
||||
if (p->pos[i].sample < last_seen) { |
||||
lsx_fail("Position %u is behind the following position.", i); |
||||
return SOX_EOF; |
||||
} |
||||
last_seen = p->pos[i].sample; |
||||
} |
||||
if (p->num_pos && in_length != SOX_UNKNOWN_LEN) |
||||
if (p->pos[0].sample > in_length || |
||||
p->pos[p->num_pos-1].sample > in_length) |
||||
lsx_warn("%s position is after expected end of audio.", |
||||
p->pos[0].sample > in_length ? "Start" : "End"); |
||||
|
||||
/* avoid unnecessary work */ |
||||
if (in_length == SOX_UNKNOWN_LEN) |
||||
while (p->num_pos && p->pos[p->num_pos-1].sample == SOX_UNKNOWN_LEN) { |
||||
lsx_debug_more("removing `-0' position"); |
||||
p->num_pos--; |
||||
free(p->pos[p->num_pos].argstr); |
||||
} |
||||
if (p->num_pos == 1 && !p->pos[0].sample) |
||||
return SOX_EFF_NULL; |
||||
|
||||
/* calculate output length */ |
||||
open_end = p->num_pos % 2; |
||||
if (open_end && in_length == SOX_UNKNOWN_LEN) |
||||
effp->out_signal.length = SOX_UNKNOWN_LEN; |
||||
else { |
||||
effp->out_signal.length = 0; |
||||
for (i = 0; i+1 < p->num_pos ; i += 2) |
||||
effp->out_signal.length += |
||||
min(p->pos[i+1].sample, in_length) - min(p->pos[i].sample, in_length); |
||||
if (open_end) |
||||
effp->out_signal.length += |
||||
in_length - min(p->pos[p->num_pos-1].sample, in_length); |
||||
effp->out_signal.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 len = min(*isamp, *osamp); |
||||
size_t channels = effp->in_signal.channels; |
||||
len /= channels; |
||||
*isamp = *osamp = 0; |
||||
|
||||
while (len) { |
||||
size_t chunk; |
||||
|
||||
if (p->current_pos < p->num_pos && |
||||
p->samples_read == p->pos[p->current_pos].sample) { |
||||
p->copying = !p->copying; |
||||
p->current_pos++; |
||||
} |
||||
|
||||
if (p->current_pos >= p->num_pos && !p->copying) |
||||
return SOX_EOF; |
||||
|
||||
chunk = p->current_pos < p->num_pos ? |
||||
min(len, p->pos[p->current_pos].sample - p->samples_read) : len; |
||||
if (p->copying) { |
||||
memcpy(obuf, ibuf, chunk * channels * sizeof(*obuf)); |
||||
obuf += chunk * channels, *osamp += chunk * channels; |
||||
} |
||||
ibuf += chunk * channels; *isamp += chunk * channels; |
||||
p->samples_read += chunk, len -= chunk; |
||||
} |
||||
|
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
static int drain(sox_effect_t *effp, sox_sample_t *obuf UNUSED, size_t *osamp) |
||||
{ |
||||
priv_t *p = (priv_t*) effp->priv; |
||||
*osamp = 0; /* only checking for errors */ |
||||
|
||||
if (p->current_pos + 1 == p->num_pos && |
||||
p->pos[p->current_pos].sample == p->samples_read && |
||||
p->copying) /* would stop here anyway */ |
||||
p->current_pos++; |
||||
if (p->current_pos < p->num_pos) |
||||
lsx_warn("Last %u position(s) not reached%s.", |
||||
p->num_pos - p->current_pos, |
||||
(effp->in_signal.length == SOX_UNKNOWN_LEN || |
||||
effp->in_signal.length/effp->in_signal.channels == p->samples_read) ? |
||||
"" /* unknown length, or did already warn during start() */ : |
||||
" (audio shorter than expected)" |
||||
); |
||||
return SOX_EOF; |
||||
} |
||||
|
||||
static int lsx_kill(sox_effect_t *effp) |
||||
{ |
||||
unsigned int i; |
||||
priv_t *p = (priv_t*) effp->priv; |
||||
for (i = 0; i < p->num_pos; i++) |
||||
free(p->pos[i].argstr); |
||||
free(p->pos); |
||||
return SOX_SUCCESS; |
||||
} |
||||
|
||||
sox_effect_handler_t const *lsx_trim_effect_fn(void) |
||||
{ |
||||
static sox_effect_handler_t handler = { |
||||
"trim", "{position}", |
||||
SOX_EFF_MCHAN | SOX_EFF_LENGTH | SOX_EFF_MODIFY, |
||||
parse, start, flow, drain, NULL, lsx_kill, |
||||
sizeof(priv_t) |
||||
}; |
||||
return &handler; |
||||
} |
||||
|
||||
/* The following functions allow a libSoX client to do a speed
|
||||
* optimization, by asking for the number of samples to be skipped |
||||
* at the beginning of the audio with sox_trim_get_start(), skipping |
||||
* that many samples in an efficient way such as seeking within the |
||||
* input file, then telling us it has been done by calling |
||||
* sox_trim_clear_start() (the name is historical). |
||||
* Note that sox_trim_get_start() returns the number of non-wide |
||||
* samples. */ |
||||
|
||||
sox_uint64_t sox_trim_get_start(sox_effect_t *effp) |
||||
{ |
||||
priv_t *p = (priv_t*) effp->priv; |
||||
return p->num_pos ? p->pos[0].sample * effp->in_signal.channels : 0; |
||||
} |
||||
|
||||
void sox_trim_clear_start(sox_effect_t *effp) |
||||
{ |
||||
priv_t *p = (priv_t*) effp->priv; |
||||
p->samples_read = p->num_pos ? p->pos[0].sample : 0; |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue