M .hgignore +4 -0
@@ 4,3 4,7 @@ syntax: glob
*.a
test-*
example/resample
+test/e2e/halve
+test/e2e/random
+test/e2e/undulating
+test/e2e/out
M Makefile +4 -2
@@ 15,6 15,7 @@
# are supplied, the code will refuse to compile.
RESAMPLE_DEFINES := -DUSE_BQRESAMPLER
+#RESAMPLE_DEFINES := -DHAVE_LIBSAMPLERATE
# Add to VECTOR_DEFINES and ALLOCATOR_DEFINES any options desired for
@@ 25,10 26,11 @@ VECTOR_DEFINES :=
ALLOCATOR_DEFINES :=
-# Add any related includes and libraries here
+# Add any related includes and libraries here (e.g. -lsamplerate in
+# THIRD_PARTY_LIBS if using libsamplerate)
#
THIRD_PARTY_INCLUDES :=
-THIRD_PARTY_LIBS :=
+THIRD_PARTY_LIBS := -lsamplerate
# If you are including a set of bq libraries into a project, you can
M build/Makefile.inc +9 -2
@@ 27,8 27,12 @@ LIBRARY := libbqresample.a
all: $(LIBRARY)
-test: $(LIBRARY) test-resampler
+test: $(LIBRARY) test-resampler test/e2e/halve 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/random ./test/e2e/sweep-log.wav ./test/e2e/out/random.wav
+ ./test/e2e/undulating ./test/e2e/sweep-log.wav ./test/e2e/out/undulating.wav
example: $(LIBRARY) example/resample
@@ 44,11 48,14 @@ test-resampler: test/TestResampler.o $(L
example/resample: example/resample.o $(LIBRARY)
$(CXX) $(CXXFLAGS) -o $@ $^ $(LIBRARY) -lsndfile -L../bqvec -lbqvec $(THIRD_PARTY_LIBS)
+test/e2e/%: test/e2e/%.o $(LIBRARY)
+ $(CXX) $(CXXFLAGS) -o $@ $^ $(LIBRARY) -lsndfile -L../bqvec -lbqvec $(THIRD_PARTY_LIBS)
+
clean:
rm -f $(OBJECTS) $(TEST_OBJECTS) $(EXAMPLE_OBJECTS)
distclean: clean
- rm -f $(LIBRARY) test-resampler
+ rm -f $(LIBRARY) test-resampler test/e2e/halve test/e2e/random test/e2e/undulating
depend:
makedepend $(RESAMPLE_DEFINES) -Y -fbuild/Makefile.inc $(SOURCES) $(HEADERS) $(TEST_SOURCES) $(EXAMPLE_SOURCES)
M example/resample.cpp +4 -1
@@ 105,7 105,7 @@ int main(int argc, char **argv)
}
int ibs = 1024;
- int obs = ceil(ibs * ratio * 10.0);
+ int obs = ceil(ibs * ratio);
float *ibuf = new float[ibs * channels];
float *obuf = new float[obs * channels];
@@ 146,4 146,7 @@ int main(int argc, char **argv)
sf_close(file_in);
sf_close(file_out);
+
+ delete[] ibuf;
+ delete[] obuf;
}
M src/BQResampler.cpp +23 -3
@@ 42,9 42,6 @@
#include <bqvec/Allocators.h>
#include <bqvec/VectorOps.h>
-//!!! copy/assign etc
-//!!! channels
-
using std::vector;
using std::cerr;
using std::endl;
@@ 95,6 92,29 @@ BQResampler::BQResampler(Parameters para
m_fade = &m_state_b;
}
+BQResampler::BQResampler(const BQResampler &other) :
+ m_qparams(other.m_qparams),
+ m_dynamism(other.m_dynamism),
+ m_ratio_change(other.m_ratio_change),
+ m_debug_level(other.m_debug_level),
+ m_initial_rate(other.m_initial_rate),
+ m_channels(other.m_channels),
+ m_state_a(other.m_state_a),
+ m_state_b(other.m_state_b),
+ m_fade_count(other.m_fade_count),
+ m_prototype(other.m_prototype),
+ m_proto_length(other.m_proto_length),
+ m_initialised(other.m_initialised)
+{
+ if (other.m_s == &(other.m_state_a)) {
+ m_s = &m_state_a;
+ m_fade = &m_state_b;
+ } else {
+ m_s = &m_state_b;
+ m_fade = &m_state_a;
+ }
+}
+
BQResampler::QualityParams::QualityParams(Quality q)
{
switch (q) {
M src/BQResampler.h +3 -0
@@ 66,6 66,7 @@ public:
};
BQResampler(Parameters parameters, int channels);
+ BQResampler(const BQResampler &);
int resampleInterleaved(float *const out, int outspace,
const float *const in, int incount,
@@ 165,6 166,8 @@ private:
const state &BQ_R__ prev_state) const;
double reconstruct_one(state *s) const;
+
+ BQResampler &operator=(const BQResampler &); // not provided
};
}
A => test/e2e/halve.cpp +99 -0
@@ 0,0 1,99 @@
+
+#include "bqresample/Resampler.h"
+
+#include <sndfile.h>
+#include <cstring>
+#include <cstdlib>
+#include <cmath>
+#include <iostream>
+
+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);
+}
+
+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;
+}
A => test/e2e/random.cpp +99 -0
@@ 0,0 1,99 @@
+
+#include "bqresample/Resampler.h"
+
+#include <sndfile.h>
+#include <cstring>
+#include <cstdlib>
+#include <cmath>
+#include <iostream>
+
+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);
+}
+
+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;
+}
A => test/e2e/sweep-log.wav +0 -0
A => test/e2e/undulating.cpp +103 -0
@@ 0,0 1,103 @@
+
+#include "bqresample/Resampler.h"
+
+#include <sndfile.h>
+#include <cstring>
+#include <cstdlib>
+#include <cmath>
+#include <iostream>
+
+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);
+}
+
+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;
+}