1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 #include "bqresample/Resampler.h"
4
5 #define BOOST_TEST_DYN_LINK
6 #define BOOST_TEST_MAIN
7
8 #include <boost/test/unit_test.hpp>
9
10 #include <stdexcept>
11 #include <vector>
12 #include <cmath>
13 #include <iostream>
14
15 using namespace std;
16 using namespace breakfastquay;
17
BOOST_AUTO_TEST_SUITE(TestResampler)18 BOOST_AUTO_TEST_SUITE(TestResampler)
19
20 #define LEN(a) (int(sizeof(a)/sizeof(a[0])))
21
22 static vector<float>
23 sine(double samplerate, double frequency, int nsamples)
24 {
25 vector<float> v(nsamples, 0.f);
26 for (int i = 0; i < nsamples; ++i) {
27 v[i] = sin ((i * 2.0 * M_PI * frequency) / samplerate);
28 }
29 return v;
30 }
31
32 #define COMPARE_N(a, b, n) \
33 for (int cmp_i = 0; cmp_i < n; ++cmp_i) { \
34 BOOST_CHECK_SMALL((a)[cmp_i] - (b)[cmp_i], 1e-4f); \
35 }
36
37 static const float guard_value = -999.f;
38
BOOST_AUTO_TEST_CASE(interpolated_sine_1ch_interleaved)39 BOOST_AUTO_TEST_CASE(interpolated_sine_1ch_interleaved)
40 {
41 // Interpolating a sinusoid should give us a sinusoid, once we've
42 // dropped the first few samples
43 vector<float> in = sine(8, 2, 1000); // 2Hz wave at 8Hz: [ 0, 1, 0, -1 ] etc
44 vector<float> expected = sine(16, 2, 2000);
45 vector<float> out(in.size() * 2 + 1, guard_value);
46 Resampler r(Resampler::Parameters(), 1);
47 int returned = r.resampleInterleaved
48 (out.data(), out.size(), in.data(), in.size(), 2, true);
49
50 // because final was true, we expect to have exactly the right
51 // number of samples back
52 BOOST_CHECK_EQUAL(returned, int(in.size() * 2));
53 BOOST_CHECK_NE(out[returned-1], guard_value);
54 BOOST_CHECK_EQUAL(out[returned], guard_value);
55
56 // and they should match the expected data, at least in the middle
57 const float *outf = out.data() + 200, *expectedf = expected.data() + 200;
58 COMPARE_N(outf, expectedf, 600);
59 }
60
BOOST_AUTO_TEST_CASE(interpolated_sine_1ch_noninterleaved)61 BOOST_AUTO_TEST_CASE(interpolated_sine_1ch_noninterleaved)
62 {
63 // Interpolating a sinusoid should give us a sinusoid, once we've
64 // dropped the first few samples
65 vector<float> in = sine(8, 2, 1000); // 2Hz wave at 8Hz: [ 0, 1, 0, -1 ] etc
66 vector<float> expected = sine(16, 2, 2000);
67 vector<float> out(in.size() * 2 + 1, guard_value);
68 const float *in_data = in.data();
69 float *out_data = out.data();
70 Resampler r(Resampler::Parameters(), 1);
71 int returned = r.resample
72 (&out_data, out.size(), &in_data, in.size(), 2, true);
73
74 // because final was true, we expect to have exactly the right
75 // number of samples back
76 BOOST_CHECK_EQUAL(returned, int(in.size() * 2));
77 BOOST_CHECK_NE(out[returned-1], guard_value);
78 BOOST_CHECK_EQUAL(out[returned], guard_value);
79
80 // and they should match the expected data, at least in the middle
81 const float *outf = out.data() + 200, *expectedf = expected.data() + 200;
82 COMPARE_N(outf, expectedf, 600);
83 }
84
BOOST_AUTO_TEST_CASE(overrun_interleaved)85 BOOST_AUTO_TEST_CASE(overrun_interleaved)
86 {
87 // Check that the outcount argument is correctly used: any samples
88 // already in the out buffer beyond outcount*channels must be left
89 // untouched. We test this with short buffers (likely to be
90 // shorter than the resampler filter length) and longer ones, with
91 // resampler ratios that reduce, leave unchanged, and raise the
92 // sample rate, and with all quality settings.
93
94 // Options are ordered from most normal/likely to least.
95
96 int channels = 2;
97
98 int lengths[] = { 6000, 6 };
99 int constructionBufferSizes[] = { 0, 1000 };
100 double ratios[] = { 1.0, 10.0, 0.1 };
101 Resampler::Quality qualities[] = {
102 Resampler::FastestTolerable, Resampler::Best, Resampler::Fastest
103 };
104
105 bool failed = false;
106
107 for (int li = 0; li < LEN(lengths); ++li) {
108 for (int cbi = 0; cbi < LEN(constructionBufferSizes); ++cbi) {
109 for (int ri = 0; ri < LEN(ratios); ++ri) {
110 for (int qi = 0; qi < LEN(qualities); ++qi) {
111
112 int length = lengths[li];
113 double ratio = ratios[ri];
114 Resampler::Parameters parameters;
115 parameters.quality = qualities[qi];
116 parameters.maxBufferSize = constructionBufferSizes[cbi];
117 Resampler r(parameters, channels);
118
119 float *inbuf = new float[length * channels];
120 for (int i = 0; i < length; ++i) {
121 for (int c = 0; c < channels; ++c) {
122 inbuf[i*channels+c] =
123 sinf((i * 2.0 * M_PI * 440.0) / 44100.0);
124 }
125 }
126
127 int outcount = int(round(length * ratio));
128 outcount -= 10;
129 if (outcount < 1) outcount = 1;
130 int outbuflen = outcount + 10;
131 float *outbuf = new float[outbuflen * channels];
132 for (int i = 0; i < outbuflen; ++i) {
133 for (int c = 0; c < channels; ++c) {
134 outbuf[i*channels+c] = guard_value;
135 }
136 }
137 /*
138 cerr << "\nTesting with length = " << length << ", ratio = "
139 << ratio << ", outcount = " << outcount << ", final = false"
140 << endl;
141 */
142 int returned = r.resampleInterleaved
143 (outbuf, outcount, inbuf, length, ratio, false);
144
145 BOOST_CHECK_LE(returned, outcount);
146
147 for (int i = returned; i < outbuflen; ++i) {
148 for (int c = 0; c < channels; ++c) {
149 BOOST_CHECK_EQUAL(outbuf[i*channels+c], guard_value);
150 if (outbuf[i*channels+c] != guard_value) {
151 failed = true;
152 }
153 }
154 }
155
156 if (failed) {
157 cerr << "Test failed, abandoning remaining loop cycles"
158 << endl;
159 break;
160 }
161 /*
162 cerr << "\nContinuing with length = " << length << ", ratio = "
163 << ratio << ", outcount = " << outcount << ", final = true"
164 << endl;
165 */
166 returned = r.resampleInterleaved
167 (outbuf, outcount, inbuf, length, ratio, true);
168
169 BOOST_CHECK_LE(returned, outcount);
170
171 for (int i = returned; i < outbuflen; ++i) {
172 for (int c = 0; c < channels; ++c) {
173 BOOST_CHECK_EQUAL(outbuf[i*channels+c], guard_value);
174 if (outbuf[i*channels+c] != guard_value) {
175 failed = true;
176 }
177 }
178 }
179
180 delete[] outbuf;
181 delete[] inbuf;
182
183 if (failed) {
184 cerr << "Test failed, abandoning remaining loop cycles"
185 << endl;
186 break;
187 }
188 }
189
190 if (failed) break;
191 }
192 if (failed) break;
193 }
194 if (failed) break;
195 }
196 }
197
198 BOOST_AUTO_TEST_SUITE_END()
199
200