# HG changeset patch # User Chris Cannam # Date 1620662286 -3600 # Mon May 10 16:58:06 2021 +0100 # Branch resampler # Node ID 0aed4287880162d190dbc7a31e9efb99665a983f # Parent 46431083ba380813cef8e396c7f3f9c845863117 Refactor e2e tests, add another one diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -7,4 +7,5 @@ test/e2e/halve test/e2e/random test/e2e/undulating +test/e2e/oversample test/e2e/out diff --git a/build/Makefile.inc b/build/Makefile.inc --- a/build/Makefile.inc +++ b/build/Makefile.inc @@ -11,7 +11,7 @@ OBJECTS := $(SOURCES:.cpp=.o) OBJECTS := $(OBJECTS:.c=.o) -TEST_SOURCES := $(wildcard $(TEST_DIR)/*.cpp) +TEST_SOURCES := $(wildcard $(TEST_DIR)/*.cpp) $(wildcard $(TEST_DIR)/e2e/*.cpp) TEST_OBJECTS := $(TEST_SOURCES:.cpp=.o) EXAMPLE_SOURCES := $(wildcard $(EXAMPLE_DIR)/*.cpp) @@ -27,10 +27,11 @@ all: $(LIBRARY) -test: $(LIBRARY) test-resampler test/e2e/halve test/e2e/random test/e2e/undulating +test: $(LIBRARY) test-resampler test/e2e/halve test/e2e/oversample test/e2e/random test/e2e/undulating ./test-resampler mkdir -p ./test/e2e/out ./test/e2e/halve ./test/e2e/sweep-log.wav ./test/e2e/out/halve.wav + ./test/e2e/oversample ./test/e2e/sweep-log.wav ./test/e2e/out/oversample.wav ./test/e2e/random ./test/e2e/sweep-log.wav ./test/e2e/out/random.wav ./test/e2e/undulating ./test/e2e/sweep-log.wav ./test/e2e/out/undulating.wav @@ -55,15 +56,19 @@ rm -f $(OBJECTS) $(TEST_OBJECTS) $(EXAMPLE_OBJECTS) distclean: clean - rm -f $(LIBRARY) test-resampler test/e2e/halve test/e2e/random test/e2e/undulating + rm -f $(LIBRARY) test-resampler test/e2e/halve test/e2e/oversample test/e2e/oversample test/e2e/random test/e2e/undulating depend: makedepend $(RESAMPLE_DEFINES) -Y -fbuild/Makefile.inc $(SOURCES) $(HEADERS) $(TEST_SOURCES) $(EXAMPLE_SOURCES) # DO NOT DELETE - + src/BQResampler.o: src/BQResampler.h src/Resampler.o: bqresample/Resampler.h src/BQResampler.h test/TestResampler.o: bqresample/Resampler.h +test/e2e/halve.o: bqresample/Resampler.h test/e2e/e2e.cpp +test/e2e/oversample.o: bqresample/Resampler.h test/e2e/e2e.cpp +test/e2e/random.o: bqresample/Resampler.h test/e2e/e2e.cpp +test/e2e/undulating.o: bqresample/Resampler.h test/e2e/e2e.cpp example/resample.o: bqresample/Resampler.h diff --git a/example/resample.cpp b/example/resample.cpp --- a/example/resample.cpp +++ b/example/resample.cpp @@ -15,6 +15,7 @@ { cerr << "Usage: resample [-v] [-c ] -to " << endl; cerr << "where may be 0, 1, or 2, for best, medium, or fastest respectively." << endl; + cerr << "The default converter is 0, best." << endl; cerr << "Supply -v for verbose output." << endl; exit(2); } @@ -71,25 +72,35 @@ int output_rate = round(target); int channels = info_in.channels; - cerr << "input rate = " << info_in.samplerate << endl; - cerr << "output rate = " << output_rate << endl; + if (verbose) { + cerr << "input rate = " << info_in.samplerate << endl; + cerr << "output rate = " << output_rate << endl; + } double ratio = target / info_in.samplerate; - cerr << "ratio = " << ratio << endl; + if (verbose) { + cerr << "ratio = " << ratio << endl; + } breakfastquay::Resampler::Parameters parameters; switch (quality) { case 0: parameters.quality = breakfastquay::Resampler::Best; - cerr << "quality = best" << endl; + if (verbose) { + cerr << "quality = best" << endl; + } break; case 1: parameters.quality = breakfastquay::Resampler::FastestTolerable; - cerr << "quality = middling" << endl; + if (verbose) { + cerr << "quality = middling" << endl; + } break; case 2: parameters.quality = breakfastquay::Resampler::Fastest; - cerr << "quality = worst" << endl; + if (verbose) { + cerr << "quality = worst" << endl; + } break; } diff --git a/test/e2e/e2e.cpp b/test/e2e/e2e.cpp new file mode 100644 --- /dev/null +++ b/test/e2e/e2e.cpp @@ -0,0 +1,149 @@ + +// Not a standalone source file + +void usage() +{ + cerr << "This is a test program for bqresample. Please do not try to use it in earnest." << endl; + cerr << "Usage: " << programName << " [-v] [-c ] " << endl; + cerr << "where may be 0, 1, or 2, for best, medium, or fastest respectively." << endl; + cerr << "The default converter is 0, best." << endl; + cerr << "Supply -v for verbose output." << endl; + exit(2); +} + +int main(int argc, char **argv) +{ + int quality = 0; + int arg; + bool verbose = false; + + for (arg = 1; arg + 2 < argc; ++arg) { + if (!strcmp(argv[arg], "-c")) { + char *e = argv[arg+1]; + quality = strtol(argv[arg+1], &e, 10); + if (*e || (quality < 0) || (quality > 2)) { + cerr << "error: invalid converter \"" + << argv[arg+1] << "\" (must be 0, 1, 2)" << endl; + usage(); + } + ++arg; + continue; + } else if (!strcmp(argv[arg], "-v")) { + verbose = true; + } else { + cerr << "error: unexpected option \"" << argv[arg] << "\"" << endl; + usage(); + } + } + + if (arg + 2 != argc) { + usage(); + } + + string infilename = argv[arg]; + string outfilename = argv[arg+1]; + + SF_INFO info_in; + SNDFILE *file_in = sf_open(infilename.c_str(), SFM_READ, &info_in); + if (!file_in) { + cerr << "failed to open " << infilename << endl; + return 1; + } + + int channels = info_in.channels; + + if (verbose) { + cerr << "input rate = " << info_in.samplerate << endl; + } + + double ratio = initialRatio; + + SF_INFO info_out; + memset(&info_out, 0, sizeof(SF_INFO)); + info_out.channels = channels; + info_out.format = info_in.format; + info_out.samplerate = info_in.samplerate; + SNDFILE *file_out = sf_open(outfilename.c_str(), SFM_WRITE, &info_out); + if (!file_out) { + cerr << "failed to open " << outfilename << endl; + return 1; + } + + int ibs = 1024; + int obs = ceil(ibs * ratio * 10); + float *ibuf = new float[ibs * channels]; + float *obuf = new float[obs * channels]; + + breakfastquay::Resampler::Parameters parameters; + switch (quality) { + case 0: + parameters.quality = breakfastquay::Resampler::Best; + if (verbose) { + cerr << "quality = best" << endl; + } + break; + case 1: + parameters.quality = breakfastquay::Resampler::FastestTolerable; + if (verbose) { + cerr << "quality = middling" << endl; + } + break; + case 2: + parameters.quality = breakfastquay::Resampler::Fastest; + if (verbose) { + cerr << "quality = worst" << endl; + } + break; + } + + if (isRatioChanging()) { + parameters.dynamism = breakfastquay::Resampler::RatioOftenChanging; + parameters.ratioChange = breakfastquay::Resampler::SmoothRatioChange; + } else { + parameters.dynamism = breakfastquay::Resampler::RatioMostlyFixed; + parameters.ratioChange = breakfastquay::Resampler::SuddenRatioChange; + } + + parameters.initialSampleRate = info_in.samplerate; + parameters.debugLevel = (verbose ? 1 : 0); + breakfastquay::Resampler resampler(parameters, channels); + + int n = 0; + while (true) { + int count = sf_readf_float(file_in, ibuf, ibs); + if (verbose) { + cerr << "."; + } + if (count < 0) { + cerr << "error: count = " << count << endl; + break; + } + + bool final = (count < ibs); + int got = resampler.resampleInterleaved + (obuf, obs, ibuf, count, ratio, final); + + if (got == 0 && final) { + break; + } else { + for (int i = 0; i < got; ++i) { + if (obuf[i] < -1.0) obuf[i] = -1.0; + if (obuf[i] > 1.0) obuf[i] = 1.0; + } + sf_writef_float(file_out, obuf, got); + } + + ratio = nextRatio(ratio); + ++n; + } + + if (verbose) { + cerr << endl; + } + + sf_close(file_in); + sf_close(file_out); + + delete[] ibuf; + delete[] obuf; +} diff --git a/test/e2e/halve.cpp b/test/e2e/halve.cpp --- a/test/e2e/halve.cpp +++ b/test/e2e/halve.cpp @@ -9,91 +9,13 @@ using namespace std; -void usage() -{ - cerr << "This is a test program for bqresample. Please do not try to use it in earnest." << endl; - cerr << "Usage: halve " << endl; - exit(2); +static const string programName = "halve"; +static const double initialRatio = 0.5; +static double nextRatio(double ratio) { + return ratio; +} +static bool isRatioChanging() { + return false; } -int main(int argc, char **argv) -{ - if (argc != 3) { - usage(); - } - - string infilename = argv[1]; - string outfilename = argv[2]; - - SF_INFO info_in; - SNDFILE *file_in = sf_open(infilename.c_str(), SFM_READ, &info_in); - if (!file_in) { - cerr << "failed to open " << infilename << endl; - return 1; - } - - int output_rate = info_in.samplerate / 2; - int channels = info_in.channels; - double ratio = double(output_rate) / info_in.samplerate; - -// cerr << "input rate = " << info_in.samplerate << endl; -// cerr << "output rate = " << output_rate << endl; -// cerr << "ratio = " << ratio << endl; - - SF_INFO info_out; - memset(&info_out, 0, sizeof(SF_INFO)); - info_out.channels = channels; - info_out.format = info_in.format; - info_out.samplerate = output_rate; - SNDFILE *file_out = sf_open(outfilename.c_str(), SFM_WRITE, &info_out); - if (!file_out) { - cerr << "failed to open " << outfilename << endl; - return 1; - } - - int ibs = 1024; - int obs = ceil(ibs * ratio); - float *ibuf = new float[ibs * channels]; - float *obuf = new float[obs * channels]; - - breakfastquay::Resampler::Parameters parameters; - parameters.quality = breakfastquay::Resampler::Best; - parameters.dynamism = breakfastquay::Resampler::RatioMostlyFixed; - parameters.ratioChange = breakfastquay::Resampler::SuddenRatioChange; - parameters.initialSampleRate = info_in.samplerate; -// parameters.debugLevel = 1; - breakfastquay::Resampler resampler(parameters, channels); - - int n = 0; - while (true) { - int count = sf_readf_float(file_in, ibuf, ibs); - cerr << "."; - if (count < 0) { - cerr << "error: count = " << count << endl; - break; - } - - bool final = (count < ibs); - int got = resampler.resampleInterleaved - (obuf, obs, ibuf, count, ratio, final); - - if (got == 0 && final) { - break; - } else { - for (int i = 0; i < got; ++i) { - if (obuf[i] < -1.0) obuf[i] = -1.0; - if (obuf[i] > 1.0) obuf[i] = 1.0; - } - sf_writef_float(file_out, obuf, got); - } - ++n; - } - - cerr << endl; - - sf_close(file_in); - sf_close(file_out); - - delete[] ibuf; - delete[] obuf; -} +#include "e2e.cpp" diff --git a/test/e2e/oversample.cpp b/test/e2e/oversample.cpp new file mode 100644 --- /dev/null +++ b/test/e2e/oversample.cpp @@ -0,0 +1,21 @@ + +#include "bqresample/Resampler.h" + +#include +#include +#include +#include +#include + +using namespace std; + +static const string programName = "oversample"; +static const double initialRatio = 16.0; +static double nextRatio(double ratio) { + return ratio; +} +static bool isRatioChanging() { + return false; +} + +#include "e2e.cpp" diff --git a/test/e2e/random.cpp b/test/e2e/random.cpp --- a/test/e2e/random.cpp +++ b/test/e2e/random.cpp @@ -9,91 +9,13 @@ using namespace std; -void usage() -{ - cerr << "This is a test program for bqresample. Please do not try to use it in earnest." << endl; - cerr << "Usage: random " << endl; - exit(2); +static const string programName = "random"; +static const double initialRatio = 0.5; +static double nextRatio(double) { + return drand48() * 2.5 + 0.1; +} +static bool isRatioChanging() { + return true; } -int main(int argc, char **argv) -{ - if (argc != 3) { - usage(); - } - - string infilename = argv[1]; - string outfilename = argv[2]; - - SF_INFO info_in; - SNDFILE *file_in = sf_open(infilename.c_str(), SFM_READ, &info_in); - if (!file_in) { - cerr << "failed to open " << infilename << endl; - return 1; - } - - int channels = info_in.channels; - -// cerr << "input rate = " << info_in.samplerate << endl; - - double ratio = 0.5; // initially - - SF_INFO info_out; - memset(&info_out, 0, sizeof(SF_INFO)); - info_out.channels = channels; - info_out.format = info_in.format; - info_out.samplerate = info_in.samplerate; - SNDFILE *file_out = sf_open(outfilename.c_str(), SFM_WRITE, &info_out); - if (!file_out) { - cerr << "failed to open " << outfilename << endl; - return 1; - } - - int ibs = 1024; - int obs = ceil(ibs * ratio * 10); - float *ibuf = new float[ibs]; - float *obuf = new float[obs]; - - breakfastquay::Resampler::Parameters parameters; - parameters.quality = breakfastquay::Resampler::Best; - parameters.dynamism = breakfastquay::Resampler::RatioOftenChanging; - parameters.ratioChange = breakfastquay::Resampler::SmoothRatioChange; - parameters.initialSampleRate = info_in.samplerate; -// parameters.debugLevel = 1; - breakfastquay::Resampler resampler(parameters, channels); - - int n = 0; - while (true) { - int count = sf_readf_float(file_in, ibuf, ibs); - cerr << "."; - if (count < 0) { - cerr << "error: count = " << count << endl; - break; - } - - bool final = (count < ibs); - int got = resampler.resampleInterleaved - (obuf, obs, ibuf, count, ratio, final); - - if (got == 0 && final) { - break; - } else { - for (int i = 0; i < got; ++i) { - if (obuf[i] < -1.0) obuf[i] = -1.0; - if (obuf[i] > 1.0) obuf[i] = 1.0; - } - sf_writef_float(file_out, obuf, got); - } - - ratio = drand48() * 2.5 + 0.1; - ++n; - } - - cerr << endl; - - sf_close(file_in); - sf_close(file_out); - - delete[] ibuf; - delete[] obuf; -} +#include "e2e.cpp" diff --git a/test/e2e/undulating.cpp b/test/e2e/undulating.cpp --- a/test/e2e/undulating.cpp +++ b/test/e2e/undulating.cpp @@ -9,95 +9,17 @@ using namespace std; -void usage() -{ - cerr << "This is a test program for bqresample. Please do not try to use it in earnest." << endl; - cerr << "Usage: undulating " << endl; - exit(2); +static const string programName = "undulating"; +static const double initialRatio = 0.5; +static double nextRatio(double ratio) { + static double factor = 1.01; + ratio *= factor; + if (ratio > 3.0) factor = 0.99; + else if (ratio < 0.3) factor = 1.01; + return ratio; +} +static bool isRatioChanging() { + return true; } -int main(int argc, char **argv) -{ - if (argc != 3) { - usage(); - } - - string infilename = argv[1]; - string outfilename = argv[2]; - - SF_INFO info_in; - SNDFILE *file_in = sf_open(infilename.c_str(), SFM_READ, &info_in); - if (!file_in) { - cerr << "failed to open " << infilename << endl; - return 1; - } - - int channels = info_in.channels; - -// cerr << "input rate = " << info_in.samplerate << endl; - - SF_INFO info_out; - memset(&info_out, 0, sizeof(SF_INFO)); - info_out.channels = channels; - info_out.format = info_in.format; - info_out.samplerate = info_in.samplerate; - SNDFILE *file_out = sf_open(outfilename.c_str(), SFM_WRITE, &info_out); - if (!file_out) { - cerr << "failed to open " << outfilename << endl; - return 1; - } - - int ibs = 1024; - int obs = ceil(ibs * 3); - float *ibuf = new float[ibs]; - float *obuf = new float[obs]; - - breakfastquay::Resampler::Parameters parameters; - parameters.quality = breakfastquay::Resampler::Best; - parameters.dynamism = breakfastquay::Resampler::RatioOftenChanging; - parameters.ratioChange = breakfastquay::Resampler::SmoothRatioChange; - parameters.initialSampleRate = info_in.samplerate; -// parameters.debugLevel = 1; - breakfastquay::Resampler resampler(parameters, channels); - - double ratio = 0.5; // initially - double factor = 1.01; - - int n = 0; - while (true) { - int count = sf_readf_float(file_in, ibuf, ibs); - cerr << "."; - if (count < 0) { - cerr << "error: count = " << count << endl; - break; - } - - bool final = (count < ibs); - int got = resampler.resampleInterleaved - (obuf, obs, ibuf, count, ratio, final); - - if (got == 0 && final) { - break; - } else { - for (int i = 0; i < got; ++i) { - if (obuf[i] < -1.0) obuf[i] = -1.0; - if (obuf[i] > 1.0) obuf[i] = 1.0; - } - sf_writef_float(file_out, obuf, got); - } - - ratio *= factor; - if (ratio > 3.0) factor = 0.99; - else if (ratio < 0.3) factor = 1.01; - - ++n; - } - - cerr << endl; - - sf_close(file_in); - sf_close(file_out); - - delete[] ibuf; - delete[] obuf; -} +#include "e2e.cpp"