M .hgignore +1 -0
@@ 7,4 7,5 @@ example/resample
test/e2e/halve
test/e2e/random
test/e2e/undulating
+test/e2e/oversample
test/e2e/out
M build/Makefile.inc +9 -4
@@ 11,7 11,7 @@ HEADERS := $(wildcard $(HEADER_DIR)/*.h)
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 @@ LIBRARY := libbqresample.a
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 @@ clean:
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
M example/resample.cpp +17 -6
@@ 15,6 15,7 @@ void usage()
{
cerr << "Usage: resample [-v] [-c <converter>] -to <rate> <infile> <outfile>" << endl;
cerr << "where <converter> 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 main(int argc, char **argv)
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;
}
A => test/e2e/e2e.cpp +149 -0
@@ 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 <converter>] <infile> <outfile>" << endl;
+ cerr << "where <converter> 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;
+}
M test/e2e/halve.cpp +8 -86
@@ 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 <infile> <outfile>" << 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"
A => test/e2e/oversample.cpp +21 -0
@@ 0,0 1,21 @@
+
+#include "bqresample/Resampler.h"
+
+#include <sndfile.h>
+#include <cstring>
+#include <cstdlib>
+#include <cmath>
+#include <iostream>
+
+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"
M test/e2e/random.cpp +8 -86
@@ 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 <infile> <outfile>" << 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"
M test/e2e/undulating.cpp +12 -90
@@ 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 <infile> <outfile>" << 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"