46431083ba38 — Chris Cannam 3 years ago
Copy ctor; some test material
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;
+}