From: Richard Kettlewell Date: Thu, 19 Nov 2009 20:07:40 +0000 (+0000) Subject: Trivial resampler fixes X-Git-Tag: 5.0~56^2~8 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/commitdiff_plain/0024bde0fcca14f018c647f41d8192b4564df96e Trivial resampler fixes Scanty resampler testing --- diff --git a/.bzrignore b/.bzrignore index 3b13be6..7695a2b 100644 --- a/.bzrignore +++ b/.bzrignore @@ -203,3 +203,4 @@ doc/disorder-choose.8.html config.aux/compile server/endian clients/rtpmon +libtests/t-resample diff --git a/lib/resample.c b/lib/resample.c index 9617db9..de2358c 100644 --- a/lib/resample.c +++ b/lib/resample.c @@ -105,17 +105,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 +156,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); @@ -210,7 +210,7 @@ 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, float *floats) { @@ -233,6 +233,7 @@ static void resample_prepare_input(struct resampler *rs, ++floats; } } + --nframes; } } @@ -242,14 +243,17 @@ 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)); @@ -290,7 +294,7 @@ 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); diff --git a/lib/resample.h b/lib/resample.h index e8bfb10..477efd9 100644 --- a/lib/resample.h +++ b/lib/resample.h @@ -47,12 +47,14 @@ void resample_init(struct resampler *rs, int output_bits, int output_channels, int output_rate, int output_signed, int output_endian); -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); void resample_close(struct resampler *rs); #endif /* RESAMPLE_H */ diff --git a/libtests/Makefile.am b/libtests/Makefile.am index 2f81f20..7be6c51 100644 --- a/libtests/Makefile.am +++ b/libtests/Makefile.am @@ -1,6 +1,6 @@ # # This file is part of DisOrder. -# Copyright (C) 2008 Richard Kettlewell +# Copyright (C) 2009 Richard Kettlewell # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -20,7 +20,7 @@ TESTS=t-addr t-arcfour t-basen t-bits t-cache t-casefold t-charset \ t-cookies t-dateparse t-event t-filepart t-hash t-heap t-hex \ t-kvp t-mime t-printf t-regsub t-selection t-signame t-sink \ t-split t-syscalls t-trackname t-unicode t-url t-utf8 t-vector \ - t-words t-wstat t-macros t-cgi t-eventdist + t-words t-wstat t-macros t-cgi t-eventdist t-resample noinst_PROGRAMS=$(TESTS) @@ -61,6 +61,8 @@ t_vector_SOURCES=t-vector.c test.c test.h t_words_SOURCES=t-words.c test.c test.h t_wstat_SOURCES=t-wstat.c test.c test.h t_eventdist_SOURCES=t-eventdist.c test.c test.h +t_resample_SOURCES=t-resample.c test.c test.h +t_resample_LDFLAGS=$(LIBSAMPLERATE) check-report: before-check check make-coverage-reports before-check: diff --git a/libtests/t-resample.c b/libtests/t-resample.c new file mode 100644 index 0000000..1dbdf8b --- /dev/null +++ b/libtests/t-resample.c @@ -0,0 +1,149 @@ +/* + * This file is part of DisOrder. + * Copyright (C) 2009 Richard Kettlewell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "test.h" +#include "resample.h" +#include "vector.h" + +/* Accumulate converted bytes in a dynamic string */ +static void converted(uint8_t *bytes, + size_t nbytes, + void *cd) { + struct dynstr *d = cd; + dynstr_append_bytes(d, (void *)bytes, nbytes); +} + +/* Converter wrapper */ +static uint8_t *convert(const struct resampler *rs, + const uint8_t *input, size_t input_bytes, + size_t *output_bytes) { + struct dynstr d[1]; + + dynstr_init(d); + while(input_bytes > 0) { + size_t chunk = input_bytes > 1024 ? 1024 : input_bytes; + size_t consumed = resample_convert(rs, + input, input_bytes, + input_bytes == chunk, + converted, + d); + input += consumed; + input_bytes -= consumed; + } + *output_bytes = d->nvec; + return (uint8_t *)d->vec; +} + +static const uint8_t simple_bytes_u[] = { + 0, 127, 128, 255, +}; + +static const uint8_t simple_bytes_s[] = { + -128, -1, 0, 127, +}; + +static const struct { + const char *description; + int input_bits; + int input_channels; + int input_rate; + int input_signed; + int input_endian; + const uint8_t *input; + size_t input_bytes; + int output_bits; + int output_channels; + int output_rate; + int output_signed; + int output_endian; + const uint8_t *output; + size_t output_bytes; +} conversions[] = { + /* Conversions that don't change the sample rate */ + { + "empty input", + 8, 1, 8000, 0, ENDIAN_LITTLE, (const uint8_t *)"", 0, + 8, 1, 8000, 0, ENDIAN_LITTLE, (const uint8_t *)"", 0 + }, + { + "sign flip", + 8, 1, 8000, 0, ENDIAN_LITTLE, simple_bytes_u, 4, + 8, 1, 8000, 1, ENDIAN_LITTLE, simple_bytes_s, 4 + }, +#if HAVE_SAMPLERATE_H + /* Conversions that do change the sample rate */ + +#endif +}; +#define NCONVERSIONS (sizeof conversions / sizeof *conversions) + +static void test_resample(void) { + for(size_t n = 0; n < NCONVERSIONS; ++n) { + struct resampler rs[1]; + + resample_init(rs, + conversions[n].input_bits, + conversions[n].input_channels, + conversions[n].input_rate, + conversions[n].input_signed, + conversions[n].input_endian, + conversions[n].output_bits, + conversions[n].output_channels, + conversions[n].output_rate, + conversions[n].output_signed, + conversions[n].output_endian); + size_t output_bytes; + const uint8_t *output = convert(rs, + conversions[n].input, + conversions[n].input_bytes, + &output_bytes); + if(output_bytes != conversions[n].output_bytes + || memcmp(output, conversions[n].output, output_bytes)) { + fprintf(stderr, "index %zu description %s mismatch\n", + n, conversions[n].description); + size_t k = 0; + while(k < conversions[n].output_bytes || k < output_bytes) { + size_t j = 0; + fprintf(stderr, "%8zu E:", k); + for(j = 0; j < 16; ++j) { + if(j + k < conversions[n].output_bytes) + fprintf(stderr, " %02x", conversions[n].output[j + k]); + } + fprintf(stderr, "\n G:"); + for(j = 0; j < 16; ++j) { + if(j + k < output_bytes) + fprintf(stderr, " %02x", output[j + k]); + } + fprintf(stderr, "\n"); + k += 16; + } + ++errors; + } + ++tests; + } +} + +TEST(resample); + +/* +Local Variables: +c-basic-offset:2 +comment-column:40 +fill-column:79 +indent-tabs-mode:nil +End: +*/