ref: 19032af10bf5b22ec31b327cbd3a590c6788e64c
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 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, Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, * USA. */ #include "st_i.h" #ifdef HAVE_SAMPLERATE #include <limits.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <samplerate.h> static st_effect_t st_rabbit_effect; #ifdef min #undef min #endif #define min(a, b) ((a) <= (b) ? (a) : (b)) #ifdef max #undef max #endif #define max(a, b) ((a) >= (b) ? (a) : (b)) /* Private data for resampling */ typedef struct { int converter_type; /* SRC converter type */ SRC_STATE *state; /* SRC state struct */ SRC_DATA *data; /* SRC_DATA control struct */ st_size_t samples; /* Number of samples read so far */ st_size_t outsamp; /* Next output sample */ } *rabbit_t; /* * Process options */ int st_rabbit_getopts(eff_t effp, int n, char **argv) { rabbit_t r = (rabbit_t) effp->priv; r->converter_type = SRC_SINC_BEST_QUALITY; if (n >= 1) { if (!strcmp(argv[0], "-c0")) { r->converter_type = SRC_SINC_BEST_QUALITY; n--; argv++; } else if (!strcmp(argv[0], "-c1")) { r->converter_type = SRC_SINC_MEDIUM_QUALITY; n--; argv++; } else if (!strcmp(argv[0], "-c2")) { r->converter_type = SRC_SINC_FASTEST; n--; argv++; } else if (!strcmp(argv[0], "-c3")) { r->converter_type = SRC_ZERO_ORDER_HOLD; n--; argv++; } else if (!strcmp(argv[0], "-c4")) { r->converter_type = SRC_LINEAR; n--; argv++; } } if (n >= 1) { st_fail(st_rabbit_effect.usage); return (ST_EOF); } return (ST_SUCCESS); } /* * Prepare processing. */ int st_rabbit_start(eff_t effp) { rabbit_t r = (rabbit_t) effp->priv; if (effp->ininfo.rate == effp->outinfo.rate) { st_fail("Input and Output rates must be different to use rabbit effect"); return (ST_EOF); } if (effp->ininfo.channels != effp->outinfo.channels) { st_fail("number of Input and Output channels must be equal to use rabbit effect"); return (ST_EOF); } if ((r->data = (SRC_DATA *)calloc(1, sizeof(SRC_DATA))) == NULL) { st_fail("could not allocate SRC_DATA buffer"); return (ST_EOF); } r->data->src_ratio = (double)effp->outinfo.rate / effp->ininfo.rate; r->data->input_frames_used = 0; r->data->output_frames_gen = 0; return (ST_SUCCESS); } /* * Read all the data. */ int st_rabbit_flow(eff_t effp, st_sample_t *ibuf, st_sample_t *obuf, st_size_t *isamp, st_size_t *osamp) { rabbit_t r = (rabbit_t) effp->priv; int channels = effp->ininfo.channels; st_size_t i, newsamples; newsamples = r->samples + *isamp; if (newsamples / channels > INT_MAX) { st_fail("input data size %d too large for libsamplerate", newsamples); return (ST_EOF); } if ((r->data->data_in = (float *)realloc(r->data->data_in, newsamples * sizeof(float))) == NULL) { st_fail("unable to allocate input buffer of size %d", newsamples); return (ST_EOF); } for (i = 0 ; i < *isamp; i++) r->data->data_in[r->samples + i] = ST_SAMPLE_TO_FLOAT_DWORD(ibuf[i]); r->samples = newsamples; r->data->input_frames = r->samples / channels; r->outsamp = 0; *osamp = 0; /* Signal that we didn't produce any output */ return (ST_SUCCESS); } /* * Process samples and write output. */ int st_rabbit_drain(eff_t effp, st_sample_t *obuf, st_size_t *osamp) { rabbit_t r = (rabbit_t) effp->priv; int channels = effp->ininfo.channels; st_size_t i, outsamps; /* On first call, process the data */ if (r->data->data_out == NULL) { /* Guess maximum number of possible output frames */ st_size_t outframes = r->data->input_frames * (r->data->src_ratio + 0.01) + 8; int error, i; double max_amp = 0.0; if (outframes > INT_MAX) { st_fail("too many output frames (%d) for libsamplerate", outframes); return (ST_EOF); } r->data->output_frames = outframes; r->data->data_out = (float *)malloc(r->data->output_frames * channels * sizeof(float)); if (r->data->data_out == NULL) { st_fail("unable to allocate output frames buffer of size %d", r->data->output_frames); return (ST_EOF); } /* Process the data */ if ((error = src_simple(r->data, r->converter_type, channels))) { st_fail("libsamplerate processing failed: %s", src_strerror(error)); return (ST_EOF); } /* Find the scaling coefficient needed to avoid any values with amplitude > 1.0 */ for (i = 0; i < r->data->output_frames_gen * channels; i++) max_amp = max(max_amp, fabs(r->data->data_out[i])); /* Rescale */ if (max_amp > 1.0) for (i = 0; i < r->data->output_frames_gen * channels; i++) r->data->data_out[i] /= max_amp; } /* Return the data one bufferful at a time */ if (*osamp > INT_MAX) { st_fail("output buffer size %d too large for libsamplerate", *osamp); return (ST_EOF); } outsamps = min(r->data->output_frames_gen * channels - r->outsamp, *osamp); for (i = 0; i < outsamps; i++) obuf[i] = ST_FLOAT_DWORD_TO_SAMPLE(r->data->data_out[r->outsamp + i]); *osamp = (st_size_t)outsamps; r->outsamp += outsamps; return (ST_SUCCESS); } /* * Do anything required when you stop reading samples. * Don't close input file! */ int st_rabbit_stop(eff_t effp) { rabbit_t r = (rabbit_t) effp->priv; free(r->data); src_delete(r->state); return (ST_SUCCESS); } static st_effect_t st_rabbit_effect = { "rabbit", "Usage: rabbit [ -c0 | -c1 | -c2 | -c3 | -c4 ]", ST_EFF_RATE | ST_EFF_MCHAN, st_rabbit_getopts, st_rabbit_start, st_rabbit_flow, st_rabbit_drain, st_rabbit_stop }; const st_effect_t *st_rabbit_effect_fn(void) { return &st_rabbit_effect; } #endif /* HAVE_SAMPLERATE */