X-Git-Url: https://git.distorted.org.uk/~mdw/disorder/blobdiff_plain/0e8c21de2a464fc913e0dbb6f7f148a84db95d55..9e42afcd09973d589b58be8f503f05b9f292c3b4:/lib/resample.c diff --git a/lib/resample.c b/lib/resample.c index 9617db9..0363d99 100644 --- a/lib/resample.c +++ b/lib/resample.c @@ -41,10 +41,12 @@ * @param input_channels Number of input channels * @param input_signed Whether input samples are signed or unsigned * @param input_rate Frames/second in input + * @param input_endian Input endianness (@c ENDIAN_BIG or @c ENDIAN_LITTLE) * @param output_bits Bits/sample in output * @param output_channels Number of output channels * @param output_rate Frames/second in output * @param output_signed Whether output samples are signed or unsigned + * @param output_endian Output endianness (@c ENDIAN_BIG or @c ENDIAN_LITTLE) * * For formats with more than two channels it's assume that the first * two channels are left and right. No particular meaning is attached @@ -58,7 +60,6 @@ void resample_init(struct resampler *rs, int output_bits, int output_channels, int output_rate, int output_signed, int output_endian) { - int error_; memset(rs, 0, sizeof *rs); assert(input_bits == 8 || input_bits == 16); assert(output_bits == 8 || output_bits == 16); @@ -80,11 +81,12 @@ void resample_init(struct resampler *rs, rs->input_bytes_per_frame = rs->input_channels * rs->input_bytes_per_sample; if(rs->input_rate != rs->output_rate) { #if HAVE_SAMPLERATE_H + int error_; rs->state = src_new(SRC_SINC_BEST_QUALITY, rs->output_channels, &error_); if(!rs->state) - fatal(0, "calling src_new: %s", src_strerror(error_)); + disorder_fatal(0, "calling src_new: %s", src_strerror(error_)); #else - fatal(0, "need to resample audio data but libsamplerate not available"); + disorder_fatal(0, "need to resample audio data but libsamplerate not available"); #endif } } @@ -96,6 +98,8 @@ void resample_close(struct resampler *rs) { #if HAVE_SAMPLERATE_H if(rs->state) src_delete(rs->state); +#else + if(rs){} /* quieten compiler */ #endif } @@ -105,17 +109,17 @@ void resample_close(struct resampler *rs) { * @param where Where to store result * @return Number of bytes consumed */ -static size_t resample_get_sample(struct resampler *rs, +static size_t resample_get_sample(const struct resampler *rs, const uint8_t *bytes, float *where) { switch(rs->input_bits + rs->input_signed + rs->input_endian) { case 8+ENDIAN_BIG: case 8+ENDIAN_LITTLE: - *where = (bytes[0] - 128)/ 128; + *where = (bytes[0] - 128)/ 128.0; return 1; case 8+SIGNED+ENDIAN_BIG: case 8+SIGNED+ENDIAN_LITTLE: - *where = (int8_t)bytes[0] / 128; + *where = (int8_t)bytes[0] / 128.0; return 1; case 16+ENDIAN_BIG: *where = (bytes[0] * 256 + bytes[1] - 32768)/ 32768.0; @@ -156,11 +160,11 @@ static inline int clip(int n, int min, int max) { * * The value is clipped naively if it will not fit. */ -static size_t resample_put_sample(struct resampler *rs, +static size_t resample_put_sample(const struct resampler *rs, float sample, uint8_t *bytes) { unsigned value; - switch(rs->input_bits + rs->input_signed + rs->input_endian) { + switch(rs->output_bits + rs->output_signed + rs->output_endian) { case 8+ENDIAN_BIG: case 8+ENDIAN_LITTLE: *bytes = clip(sample * 128.0 + 128, 0, 255); @@ -197,7 +201,7 @@ static size_t resample_put_sample(struct resampler *rs, /** @brief Convert input samples to floats * @param rs Resampler state * @param bytes Input bytes - * @param nbytes Number of input bytes + * @param nframes Number of input frames * @param floats Where to store converted data * * @p floats must be big enough. As well as converting to floats this @@ -210,12 +214,10 @@ static size_t resample_put_sample(struct resampler *rs, * the input either mono or stereo, so the result isn't actually going to be * too bad. */ -static void resample_prepare_input(struct resampler *rs, +static void resample_prepare_input(const struct resampler *rs, const uint8_t *bytes, - size_t nbytes, + size_t nframes, float *floats) { - size_t nframes = nbytes / (rs->input_bytes_per_frame); - while(nframes > 0) { int n; @@ -233,6 +235,7 @@ static void resample_prepare_input(struct resampler *rs, ++floats; } } + --nframes; } } @@ -242,24 +245,28 @@ static void resample_prepare_input(struct resampler *rs, * @param nbytes Number of bytes to convert * @param eof Set an end of input stream * @param converted Called with converted data (possibly more than once) + * @param cd Passed to @p cd * @return Number of bytes consumed */ -size_t resample_convert(struct resampler *rs, +size_t resample_convert(const struct resampler *rs, const uint8_t *bytes, size_t nbytes, int eof, void (*converted)(uint8_t *bytes, - size_t nbytes)) { + size_t nbytes, + void *cd), + void *cd) { size_t nframesin = nbytes / (rs->input_bytes_per_frame); size_t nsamplesout; float *input = xcalloc(nframesin * rs->output_channels, sizeof (float)); float *output = 0; - resample_prepare_input(rs, bytes, nbytes, input); + resample_prepare_input(rs, bytes, nframesin, input); #if HAVE_SAMPLERATE_H if(rs->state) { /* A sample-rate conversion must be performed */ SRC_DATA data; + memset(&data, 0, sizeof data); /* Compute how many frames are expected to come out. */ size_t maxframesout = nframesin * rs->output_rate / rs->input_rate + 1; output = xcalloc(maxframesout * rs->output_channels, sizeof(float)); @@ -268,12 +275,17 @@ size_t resample_convert(struct resampler *rs, data.input_frames = nframesin; data.output_frames = maxframesout; data.end_of_input = eof; - data.src_ratio = rs->output_rate / rs->input_rate; + data.src_ratio = (double)rs->output_rate / rs->input_rate; + D(("nframesin=%zu maxframesout=%zu eof=%d ratio=%d.%06d", + nframesin, maxframesout, eof, + (int)data.src_ratio, + ((int)(data.src_ratio * 1000000) % 1000000))); int error_ = src_process(rs->state, &data); if(error_) - fatal(0, "calling src_process: %s", src_strerror(error_)); + disorder_fatal(0, "calling src_process: %s", src_strerror(error_)); nframesin = data.input_frames_used; nsamplesout = data.output_frames_gen * rs->output_channels; + D(("new nframesin=%zu nsamplesout=%zu", nframesin, nsamplesout)); } #endif if(!output) { @@ -290,12 +302,14 @@ size_t resample_convert(struct resampler *rs, bufused += resample_put_sample(rs, *op++, buffer + bufused); --nsamplesout; } - converted(buffer, bufused); + converted(buffer, bufused, cd); } if(output != input) xfree(output); xfree(input); + if(eof){} /* quieten compiler */ /* Report how many input bytes were actually consumed */ + //fprintf(stderr, "converted %zu frames\n", nframesin); return nframesin * rs->input_bytes_per_frame; }