ref: 94c87a5b3fb7e94e4a8fdf6151b909f54da031ad
dir: /src/rabbit.c/
/* libsamplerate (aka Secret Rabbit Code) support for sox
* (c) Reuben Thomas <rrt@sc3d.org> 2006
*
* 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_SAMPLERATE_H
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <samplerate.h>
/* Private data for resampling */
typedef struct {
int converter_type; /* SRC converter type */
double out_rate;
SRC_STATE *state; /* SRC state struct */
SRC_DATA *data; /* SRC_DATA control struct */
sox_size_t i_alloc, o_alloc; /* Samples allocated in data->data_{in,out} */
} priv_t;
/*
* Process options
*/
static int getopts(sox_effect_t * effp, int argc, char **argv)
{
priv_t * r = (priv_t *) effp->priv;
char dummy; /* To check for extraneous chars. */
r->converter_type = SRC_SINC_BEST_QUALITY;
if (argc) {
if (!strcmp(argv[0], "-c0")) {
r->converter_type = SRC_SINC_BEST_QUALITY;
argc--; argv++;
} else if (!strcmp(argv[0], "-c1")) {
r->converter_type = SRC_SINC_MEDIUM_QUALITY;
argc--; argv++;
} else if (!strcmp(argv[0], "-c2")) {
r->converter_type = SRC_SINC_FASTEST;
argc--; argv++;
} else if (!strcmp(argv[0], "-c3")) {
r->converter_type = SRC_ZERO_ORDER_HOLD;
argc--; argv++;
} else if (!strcmp(argv[0], "-c4")) {
r->converter_type = SRC_LINEAR;
argc--; argv++;
}
}
r->out_rate = HUGE_VAL;
if (argc) {
if (sscanf(*argv, "%lf %c", &r->out_rate, &dummy) != 1 || r->out_rate <= 0)
return lsx_usage(effp);
argc--; argv++;
}
return argc? lsx_usage(effp) : SOX_SUCCESS;
}
/*
* Prepare processing.
*/
static int start(sox_effect_t * effp)
{
priv_t * r = (priv_t *) effp->priv;
int err = 0;
double out_rate = r->out_rate != HUGE_VAL? r->out_rate : effp->out_signal.rate;
if (effp->in_signal.rate == out_rate)
return SOX_EFF_NULL;
effp->out_signal.channels = effp->in_signal.channels;
effp->out_signal.rate = out_rate;
r->data = lsx_calloc(1, sizeof(SRC_DATA));
r->data->src_ratio = out_rate / effp->in_signal.rate;
r->i_alloc = r->o_alloc = 0;
r->state = src_new(r->converter_type, (int)effp->in_signal.channels, &err);
if (err) {
free(r->data);
sox_fail("cannot initialise rabbit: %s", src_strerror(err));
return SOX_EOF;
}
return SOX_SUCCESS;
}
/*
* Read, convert, return data.
*/
static int flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf UNUSED,
sox_size_t *isamp, sox_size_t *osamp)
{
priv_t * r = (priv_t *) effp->priv;
SRC_DATA *d = r->data;
unsigned int channels = effp->in_signal.channels;
sox_size_t i;
sox_size_t isamples0 = d->input_frames * channels;
sox_size_t isamples = isamples0 + *isamp;
sox_size_t osamples = isamples * (d->src_ratio + 0.01) + 8;
if (osamples > *osamp) {
osamples = *osamp;
isamples = (osamples - 8) / (d->src_ratio + 0.01);
}
if (r->i_alloc < isamples) {
d->data_in = lsx_realloc(d->data_in, isamples * sizeof(float));
r->i_alloc = isamples;
}
if (r->o_alloc < osamples) {
d->data_out = lsx_realloc(d->data_out, osamples * sizeof(float));
r->o_alloc = osamples;
d->output_frames = osamples / channels;
}
for (i = 0; i < isamples - isamples0; i++)
d->data_in[isamples0 + i] = SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[i], effp->clips);
*isamp = i;
d->input_frames = isamples / channels;
*osamp = 0;
while (d->input_frames > 0 || d->end_of_input != 0) {
if (src_process(r->state, r->data) != 0) {
sox_fail("%s", src_strerror(src_error(r->state)));
return SOX_EOF;
}
d->input_frames -= d->input_frames_used;
if (d->input_frames)
memmove(d->data_in, d->data_in + d->input_frames_used * sizeof(float),
d->input_frames * sizeof(float));
for (i = 0; i < (sox_size_t)d->output_frames_gen * channels; i++)
obuf[i] = SOX_FLOAT_32BIT_TO_SAMPLE(d->data_out[i], effp->clips);
*osamp += i;
if (!d->output_frames_gen || d->end_of_input)
break;
}
return SOX_SUCCESS;
}
/*
* Process samples and write output.
*/
static int drain(sox_effect_t * effp, sox_sample_t *obuf, sox_size_t *osamp)
{
priv_t * r = (priv_t *) effp->priv;
static sox_size_t isamp = 0;
r->data->end_of_input = 1;
return flow(effp, NULL, obuf, &isamp, osamp);
}
/*
* Do anything required when you stop reading samples.
*/
static int stop(sox_effect_t * effp)
{
priv_t * r = (priv_t *) effp->priv;
free(r->data);
src_delete(r->state);
return SOX_SUCCESS;
}
const sox_effect_handler_t *sox_rabbit_effect_fn(void)
{
static sox_effect_handler_t handler = {
"rabbit", "[-c0|-c1|-c2|-c3|-c4] [rate]",
SOX_EFF_RATE | SOX_EFF_MCHAN,
getopts, start, flow, drain, stop, NULL, sizeof(priv_t)
};
return &handler;
}
#endif /* HAVE_SAMPLERATE */