To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / TestDefaults.cpp @ 67:fa66ee7dcf08

History | View | Annotate | Download (9.91 KB)

1 5:6a279da6fdd7 cannam
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
2
3
/*
4
    Vamp Plugin Tester
5
    Chris Cannam, cannam@all-day-breakfast.com
6
    Centre for Digital Music, Queen Mary, University of London.
7 42:f1e8e14e9c96 Chris
    Copyright 2009-2014 QMUL.
8 5:6a279da6fdd7 cannam

9
    This program loads a Vamp plugin and tests its susceptibility to a
10
    number of common pitfalls, including handling of extremes of input
11
    data.  If you can think of any additional useful tests that are
12
    easily added, please send them to me.
13

14
    Permission is hereby granted, free of charge, to any person
15
    obtaining a copy of this software and associated documentation
16
    files (the "Software"), to deal in the Software without
17
    restriction, including without limitation the rights to use, copy,
18
    modify, merge, publish, distribute, sublicense, and/or sell copies
19
    of the Software, and to permit persons to whom the Software is
20
    furnished to do so, subject to the following conditions:
21

22
    The above copyright notice and this permission notice shall be
23
    included in all copies or substantial portions of the Software.
24

25
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
29
    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
30
    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31
    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32

33
    Except as contained in this notice, the names of the Centre for
34
    Digital Music; Queen Mary, University of London; and Chris Cannam
35
    shall not be used in advertising or otherwise to promote the sale,
36
    use or other dealings in this Software without prior written
37
    authorization.
38
*/
39
40
#include "TestDefaults.h"
41
42
#include <vamp-hostsdk/Plugin.h>
43
using namespace Vamp;
44
45
#include <memory>
46
using namespace std;
47
48
#include <cmath>
49 6:ba3c8cc649d3 cannam
#include <time.h>
50 5:6a279da6fdd7 cannam
51
Tester::TestRegistrar<TestDefaultProgram>
52 39:07144cdcbedf Chris
TestDefaultProgram::m_registrar("E1", "Inconsistent default program");
53 5:6a279da6fdd7 cannam
54
Tester::TestRegistrar<TestDefaultParameters>
55 39:07144cdcbedf Chris
TestDefaultParameters::m_registrar("E2", "Inconsistent default parameters");
56 5:6a279da6fdd7 cannam
57 34:a2d9aed55a2a Chris
Tester::TestRegistrar<TestParametersOnReset>
58 39:07144cdcbedf Chris
TestParametersOnReset::m_registrar("E3", "Parameter retention through reset");
59 34:a2d9aed55a2a Chris
60 5:6a279da6fdd7 cannam
static const size_t _step = 1000;
61
62
Test::Results
63 8:3019cb6b538d cannam
TestDefaultProgram::test(string key, Options options)
64 5:6a279da6fdd7 cannam
{
65
    Plugin::FeatureSet f[2];
66
    int rate = 44100;
67
    Results r;
68
    float **data = 0;
69
    size_t channels = 0;
70
    size_t count = 100;
71
72
    for (int run = 0; run < 2; ++run) {
73
        auto_ptr<Plugin> p(load(key, rate));
74
        if (p->getPrograms().empty()) return r;
75
        if (run == 1) {
76
            p->selectProgram(p->getCurrentProgram());
77
        }
78
        if (!initAdapted(p.get(), channels, _step, _step, r)) return r;
79
        if (!data) data = createTestAudio(channels, _step, count);
80
        for (size_t i = 0; i < count; ++i) {
81 67:fa66ee7dcf08 Chris
            float **ptr = new float *[channels];
82 5:6a279da6fdd7 cannam
            size_t idx = i * _step;
83
            for (size_t c = 0; c < channels; ++c) ptr[c] = data[c] + idx;
84
            RealTime timestamp = RealTime::frame2RealTime(idx, rate);
85
            Plugin::FeatureSet fs = p->process(ptr, timestamp);
86 67:fa66ee7dcf08 Chris
            delete[] ptr;
87 5:6a279da6fdd7 cannam
            appendFeatures(f[run], fs);
88
        }
89
        Plugin::FeatureSet fs = p->getRemainingFeatures();
90
        appendFeatures(f[run], fs);
91
    }
92
    if (data) destroyTestAudio(data, channels);
93
94
    if (!(f[0] == f[1])) {
95 8:3019cb6b538d cannam
        string message = "Explicitly setting current program to its supposed current value changes the results";
96
        Result res;
97
        if (options & NonDeterministic) res = note(message);
98
        else res = error(message);
99 52:4bd0cd3c60f3 Chris
        if (options & Verbose) dumpDiff(res, f[0], f[1]);
100 7:43eb3a4b95c8 cannam
        r.push_back(res);
101 5:6a279da6fdd7 cannam
    } else {
102
        r.push_back(success());
103
    }
104
105
    return r;
106
}
107
108
Test::Results
109 8:3019cb6b538d cannam
TestDefaultParameters::test(string key, Options options)
110 5:6a279da6fdd7 cannam
{
111
    Plugin::FeatureSet f[2];
112
    int rate = 44100;
113
    Results r;
114
    float **data = 0;
115
    size_t channels = 0;
116
    size_t count = 100;
117
118
    for (int run = 0; run < 2; ++run) {
119
        auto_ptr<Plugin> p(load(key, rate));
120
        if (p->getParameterDescriptors().empty()) return r;
121
        if (run == 1) {
122
            Plugin::ParameterList pl = p->getParameterDescriptors();
123
            for (int i = 0; i < (int)pl.size(); ++i) {
124
                if (p->getParameter(pl[i].identifier) != pl[i].defaultValue) {
125 23:28097c1b3de4 cannam
                    if (options & Verbose) {
126
                        cout << "Parameter: " << pl[i].identifier << endl;
127
                        cout << "Expected: " << pl[i].defaultValue << endl;
128
                        cout << "Actual: " << p->getParameter(pl[i].identifier) << endl;
129
                    }
130 5:6a279da6fdd7 cannam
                    r.push_back(error("Not all parameters have their default values when queried directly after construction"));
131
                }
132
                p->setParameter(pl[i].identifier, pl[i].defaultValue);
133
            }
134
        }
135
        if (!initAdapted(p.get(), channels, _step, _step, r)) return r;
136
        if (!data) data = createTestAudio(channels, _step, count);
137
        for (size_t i = 0; i < count; ++i) {
138 67:fa66ee7dcf08 Chris
            float **ptr = new float *[channels];
139 5:6a279da6fdd7 cannam
            size_t idx = i * _step;
140
            for (size_t c = 0; c < channels; ++c) ptr[c] = data[c] + idx;
141
            RealTime timestamp = RealTime::frame2RealTime(idx, rate);
142
            Plugin::FeatureSet fs = p->process(ptr, timestamp);
143 67:fa66ee7dcf08 Chris
            delete[] ptr;
144 5:6a279da6fdd7 cannam
            appendFeatures(f[run], fs);
145
        }
146
        Plugin::FeatureSet fs = p->getRemainingFeatures();
147
        appendFeatures(f[run], fs);
148
    }
149
    if (data) destroyTestAudio(data, channels);
150
151
    if (!(f[0] == f[1])) {
152 8:3019cb6b538d cannam
        string message = "Explicitly setting parameters to their supposed default values changes the results";
153
        Result res;
154
        if (options & NonDeterministic) res = note(message);
155
        else res = error(message);
156 52:4bd0cd3c60f3 Chris
        if (options & Verbose) dumpDiff(res, f[0], f[1]);
157 7:43eb3a4b95c8 cannam
        r.push_back(res);
158 5:6a279da6fdd7 cannam
    } else {
159
        r.push_back(success());
160
    }
161
162
    return r;
163
}
164 34:a2d9aed55a2a Chris
165
Test::Results
166
TestParametersOnReset::test(string key, Options options)
167
{
168
    Plugin::FeatureSet f[2];
169
    int rate = 44100;
170
    Results r;
171
    float **data = 0;
172
    size_t channels = 0;
173
    size_t count = 100;
174
175
    for (int run = 0; run < 2; ++run) {
176
        auto_ptr<Plugin> p(load(key, rate));
177
        if (p->getParameterDescriptors().empty()) return r;
178
179
        // Set all parameters to non-default values
180 36:7d4c98c696a5 Chris
181 34:a2d9aed55a2a Chris
        Plugin::ParameterList pl = p->getParameterDescriptors();
182 36:7d4c98c696a5 Chris
183 34:a2d9aed55a2a Chris
        for (int i = 0; i < (int)pl.size(); ++i) {
184 36:7d4c98c696a5 Chris
185
            // Half-way between default and max value, seems a
186
            // reasonable guess for something to set it to. We want to
187
            // avoid the real extremes because they can sometimes be
188
            // very slow, and we want to avoid setting everything to
189
            // the same values (e.g. min) because plugins will
190
            // sometimes legitimately reject that.
191
192
            // Remember to take into account quantization
193
194
            float value = (pl[i].defaultValue + pl[i].maxValue) / 2;
195
196
            if (pl[i].isQuantized) {
197
                value = round(value / pl[i].quantizeStep) * pl[i].quantizeStep;
198 34:a2d9aed55a2a Chris
            }
199 36:7d4c98c696a5 Chris
200
            if (value > pl[i].maxValue) {
201
                value = pl[i].maxValue;
202
            }
203
            if (value < pl[i].minValue) {
204
                value = pl[i].minValue;
205
            }
206
            if (value == pl[i].defaultValue) {
207
                if (pl[i].defaultValue == pl[i].minValue) {
208
                    value = pl[i].maxValue;
209
                } else {
210
                    value = pl[i].minValue;
211
                }
212
            }
213
214
            p->setParameter(pl[i].identifier, value);
215 34:a2d9aed55a2a Chris
        }
216
217 52:4bd0cd3c60f3 Chris
        if (!initAdapted(p.get(), channels, _step, _step, r)) {
218
219
            // OK, plugin didn't like that. Let's try a different tack
220
            // -- set everything to min except those parameters whose
221
            // default is min, and set those to half way instead
222
223
            for (int i = 0; i < (int)pl.size(); ++i) {
224
                float value = pl[i].minValue;
225
                if (value == pl[i].defaultValue) {
226
                    value = (pl[i].maxValue + pl[i].minValue) / 2;
227
                    value = ceil(value / pl[i].quantizeStep) * pl[i].quantizeStep;
228
                    if (value > pl[i].maxValue) {
229
                        value = pl[i].maxValue;
230
                    }
231
                }
232
                p->setParameter(pl[i].identifier, value);
233
            }
234
235
            r = Results();
236
            if (!initAdapted(p.get(), channels, _step, _step, r)) {
237
                // Still didn't work, give up
238
                return r;
239
            }
240
        }
241 34:a2d9aed55a2a Chris
242
        //  First run: construct, set params, init, process
243
        // Second run: construct, set params, init, reset, process
244
        // We expect these to produce the same results
245
        if (run == 1) p->reset();
246
247
        if (!data) data = createTestAudio(channels, _step, count);
248
        for (size_t i = 0; i < count; ++i) {
249 67:fa66ee7dcf08 Chris
            float **ptr = new float *[channels];
250 34:a2d9aed55a2a Chris
            size_t idx = i * _step;
251
            for (size_t c = 0; c < channels; ++c) ptr[c] = data[c] + idx;
252
            RealTime timestamp = RealTime::frame2RealTime(idx, rate);
253
            Plugin::FeatureSet fs = p->process(ptr, timestamp);
254 67:fa66ee7dcf08 Chris
            delete[] ptr;
255 34:a2d9aed55a2a Chris
            appendFeatures(f[run], fs);
256
        }
257
        Plugin::FeatureSet fs = p->getRemainingFeatures();
258
        appendFeatures(f[run], fs);
259
    }
260
    if (data) destroyTestAudio(data, channels);
261
262
    if (!(f[0] == f[1])) {
263
        string message = "Call to reset after setting parameters, but before processing, changes the results (parameter values not retained through reset?)";
264
        Result res;
265
        if (options & NonDeterministic) res = note(message);
266
        else res = error(message);
267 52:4bd0cd3c60f3 Chris
        if (options & Verbose) dumpDiff(res, f[0], f[1]);
268 34:a2d9aed55a2a Chris
        r.push_back(res);
269
    } else {
270
        r.push_back(success());
271
    }
272
273
    return r;
274
}