File: TestResampler.cpp

package info (click to toggle)
sonic-visualiser 5.2.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 24,744 kB
  • sloc: cpp: 158,888; ansic: 11,920; sh: 1,785; makefile: 517; xml: 64; perl: 31
file content (199 lines) | stat: -rw-r--r-- 7,367 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */

#include "bqresample/Resampler.h"

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN

#include <boost/test/unit_test.hpp>

#include <stdexcept>
#include <vector>
#include <cmath>
#include <iostream>

using namespace std;
using namespace breakfastquay;

BOOST_AUTO_TEST_SUITE(TestResampler)

#define LEN(a) (int(sizeof(a)/sizeof(a[0])))

static vector<float>
sine(double samplerate, double frequency, int nsamples)
{
    vector<float> v(nsamples, 0.f);
    for (int i = 0; i < nsamples; ++i) {
        v[i] = sin ((i * 2.0 * M_PI * frequency) / samplerate);
    }
    return v;
}

#define COMPARE_N(a, b, n)                    \
    for (int cmp_i = 0; cmp_i < n; ++cmp_i) { \
        BOOST_CHECK_SMALL((a)[cmp_i] - (b)[cmp_i], 1e-4f);      \
    }

static const float guard_value = -999.f;

BOOST_AUTO_TEST_CASE(interpolated_sine_1ch_interleaved)
{
    // Interpolating a sinusoid should give us a sinusoid, once we've
    // dropped the first few samples
    vector<float> in = sine(8, 2, 1000); // 2Hz wave at 8Hz: [ 0, 1, 0, -1 ] etc
    vector<float> expected = sine(16, 2, 2000);
    vector<float> out(in.size() * 2 + 1, guard_value);
    Resampler r(Resampler::Parameters(), 1);
    int returned = r.resampleInterleaved
        (out.data(), out.size(), in.data(), in.size(), 2, true);

    // because final was true, we expect to have exactly the right
    // number of samples back
    BOOST_CHECK_EQUAL(returned, int(in.size() * 2));
    BOOST_CHECK_NE(out[returned-1], guard_value);
    BOOST_CHECK_EQUAL(out[returned], guard_value);

    // and they should match the expected data, at least in the middle
    const float *outf = out.data() + 200, *expectedf = expected.data() + 200;
    COMPARE_N(outf, expectedf, 600);
}

BOOST_AUTO_TEST_CASE(interpolated_sine_1ch_noninterleaved)
{
    // Interpolating a sinusoid should give us a sinusoid, once we've
    // dropped the first few samples
    vector<float> in = sine(8, 2, 1000); // 2Hz wave at 8Hz: [ 0, 1, 0, -1 ] etc
    vector<float> expected = sine(16, 2, 2000);
    vector<float> out(in.size() * 2 + 1, guard_value);
    const float *in_data = in.data();
    float *out_data = out.data();
    Resampler r(Resampler::Parameters(), 1);
    int returned = r.resample
        (&out_data, out.size(), &in_data, in.size(), 2, true);

    // because final was true, we expect to have exactly the right
    // number of samples back
    BOOST_CHECK_EQUAL(returned, int(in.size() * 2));
    BOOST_CHECK_NE(out[returned-1], guard_value);
    BOOST_CHECK_EQUAL(out[returned], guard_value);

    // and they should match the expected data, at least in the middle
    const float *outf = out.data() + 200, *expectedf = expected.data() + 200;
    COMPARE_N(outf, expectedf, 600);
}

BOOST_AUTO_TEST_CASE(overrun_interleaved)
{
    // Check that the outcount argument is correctly used: any samples
    // already in the out buffer beyond outcount*channels must be left
    // untouched. We test this with short buffers (likely to be
    // shorter than the resampler filter length) and longer ones, with
    // resampler ratios that reduce, leave unchanged, and raise the
    // sample rate, and with all quality settings.

    // Options are ordered from most normal/likely to least.
    
    int channels = 2;

    int lengths[] = { 6000, 6 };
    int constructionBufferSizes[] = { 0, 1000 };
    double ratios[] = { 1.0, 10.0, 0.1 };
    Resampler::Quality qualities[] = {
        Resampler::FastestTolerable, Resampler::Best, Resampler::Fastest
    };

    bool failed = false;
    
    for (int li = 0; li < LEN(lengths); ++li) {
        for (int cbi = 0; cbi < LEN(constructionBufferSizes); ++cbi) {
            for (int ri = 0; ri < LEN(ratios); ++ri) {
                for (int qi = 0; qi < LEN(qualities); ++qi) {
                    
                    int length = lengths[li];
                    double ratio = ratios[ri];
                    Resampler::Parameters parameters;
                    parameters.quality = qualities[qi];
                    parameters.maxBufferSize = constructionBufferSizes[cbi];
                    Resampler r(parameters, channels);

                    float *inbuf = new float[length * channels];
                    for (int i = 0; i < length; ++i) {
                        for (int c = 0; c < channels; ++c) {
                            inbuf[i*channels+c] =
                                sinf((i * 2.0 * M_PI * 440.0) / 44100.0);
                        }
                    }

                    int outcount = int(round(length * ratio));
                    outcount -= 10;
                    if (outcount < 1) outcount = 1;
                    int outbuflen = outcount + 10;
                    float *outbuf = new float[outbuflen * channels];
                    for (int i = 0; i < outbuflen; ++i) {
                        for (int c = 0; c < channels; ++c) {
                            outbuf[i*channels+c] = guard_value;
                        }
                    }
/*
                    cerr << "\nTesting with length = " << length << ", ratio = "
                         << ratio << ", outcount = " << outcount << ", final = false"
                         << endl;
*/                    
                    int returned = r.resampleInterleaved
                        (outbuf, outcount, inbuf, length, ratio, false);

                    BOOST_CHECK_LE(returned, outcount);
                    
                    for (int i = returned; i < outbuflen; ++i) {
                        for (int c = 0; c < channels; ++c) {
                            BOOST_CHECK_EQUAL(outbuf[i*channels+c], guard_value);
                            if (outbuf[i*channels+c] != guard_value) {
                                failed = true;
                            }
                        }
                    }

                    if (failed) {
                        cerr << "Test failed, abandoning remaining loop cycles"
                             << endl;
                        break;
                    }
/*
                    cerr << "\nContinuing with length = " << length << ", ratio = "
                         << ratio << ", outcount = " << outcount << ", final = true"
                         << endl;
*/
                    returned = r.resampleInterleaved
                        (outbuf, outcount, inbuf, length, ratio, true);

                    BOOST_CHECK_LE(returned, outcount);

                    for (int i = returned; i < outbuflen; ++i) {
                        for (int c = 0; c < channels; ++c) {
                            BOOST_CHECK_EQUAL(outbuf[i*channels+c], guard_value);
                            if (outbuf[i*channels+c] != guard_value) {
                                failed = true;
                            }
                        }
                    }

                    delete[] outbuf;
                    delete[] inbuf;

                    if (failed) {
                        cerr << "Test failed, abandoning remaining loop cycles"
                             << endl;
                        break;
                    }
                }

                if (failed) break;
            }
            if (failed) break;
        }
        if (failed) break;
    }
}

BOOST_AUTO_TEST_SUITE_END()