cannam@150
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
cannam@150
|
2 /*
|
cannam@150
|
3 Piper C++
|
cannam@150
|
4
|
cannam@150
|
5 An API for audio analysis and feature extraction plugins.
|
cannam@150
|
6
|
cannam@150
|
7 Centre for Digital Music, Queen Mary, University of London.
|
cannam@150
|
8 Copyright 2006-2016 Chris Cannam and QMUL.
|
cannam@150
|
9
|
cannam@150
|
10 Permission is hereby granted, free of charge, to any person
|
cannam@150
|
11 obtaining a copy of this software and associated documentation
|
cannam@150
|
12 files (the "Software"), to deal in the Software without
|
cannam@150
|
13 restriction, including without limitation the rights to use, copy,
|
cannam@150
|
14 modify, merge, publish, distribute, sublicense, and/or sell copies
|
cannam@150
|
15 of the Software, and to permit persons to whom the Software is
|
cannam@150
|
16 furnished to do so, subject to the following conditions:
|
cannam@150
|
17
|
cannam@150
|
18 The above copyright notice and this permission notice shall be
|
cannam@150
|
19 included in all copies or substantial portions of the Software.
|
cannam@150
|
20
|
cannam@150
|
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
cannam@150
|
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
cannam@150
|
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
cannam@150
|
24 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
cannam@150
|
25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
cannam@150
|
26 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
cannam@150
|
27 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
cannam@150
|
28
|
cannam@150
|
29 Except as contained in this notice, the names of the Centre for
|
cannam@150
|
30 Digital Music; Queen Mary, University of London; and Chris Cannam
|
cannam@150
|
31 shall not be used in advertising or otherwise to promote the sale,
|
cannam@150
|
32 use or other dealings in this Software without prior written
|
cannam@150
|
33 authorization.
|
cannam@150
|
34 */
|
cannam@150
|
35
|
cannam@150
|
36 #include "ProcessQtTransport.h"
|
cannam@150
|
37 #include "CapnpRRClient.h"
|
cannam@208
|
38 #include "PiperAutoPlugin.h"
|
cannam@150
|
39
|
cannam@270
|
40 #include <vamp-hostsdk/PluginInputDomainAdapter.h>
|
cannam@270
|
41
|
cannam@150
|
42 #include <stdexcept>
|
cannam@150
|
43
|
cannam@150
|
44 using std::cerr;
|
cannam@150
|
45 using std::endl;
|
cannam@150
|
46 using std::exception;
|
cannam@150
|
47 using std::vector;
|
cannam@270
|
48 using std::string;
|
cannam@150
|
49
|
cannam@150
|
50 int main(int argc, char **argv)
|
cannam@150
|
51 {
|
cannam@150
|
52 if (argc != 2) {
|
cannam@150
|
53 cerr << "Usage: " << argv[0] << " <server-executable-path>" << endl;
|
cannam@150
|
54 return 2;
|
cannam@150
|
55 }
|
cannam@150
|
56
|
cannam@270
|
57 string server = argv[1];
|
cannam@270
|
58 string format = "capnp";
|
cannam@270
|
59 string zeroCrossing = "vamp-example-plugins:zerocrossing";
|
cannam@270
|
60 string powerSpectrum = "vamp-example-plugins:powerspectrum";
|
cannam@270
|
61 piper_vamp::client::LogCallback *logger = nullptr;
|
cannam@270
|
62
|
cannam@150
|
63 try {
|
cannam@270
|
64 cerr << endl << "*** Test: starting transport" << endl;
|
cannam@270
|
65 piper_vamp::client::ProcessQtTransport transport(server, format, logger);
|
cannam@150
|
66 if (!transport.isOK()) {
|
cannam@150
|
67 cerr << "ERROR: Transport failed to start" << endl;
|
cannam@150
|
68 return 1;
|
cannam@150
|
69 }
|
cannam@270
|
70 cerr << "OK" << endl;
|
cannam@150
|
71
|
cannam@270
|
72 cerr << endl << "*** Test: constructing client" << endl;
|
cannam@270
|
73 piper_vamp::client::CapnpRRClient client(&transport, logger);
|
cannam@270
|
74 cerr << "OK" << endl;
|
cannam@270
|
75
|
cannam@270
|
76 cerr << endl << "*** Test: listing plugins" << endl;
|
cannam@207
|
77 piper_vamp::ListResponse lr = client.list({});
|
cannam@270
|
78 cerr << "OK; plugins are:" << endl;
|
cannam@150
|
79 int i = 1;
|
cannam@150
|
80 for (const auto &p: lr.available) {
|
cannam@150
|
81 cerr << i++ << ". [" << p.pluginKey << "] " << p.basic.name << endl;
|
cannam@150
|
82 }
|
cannam@270
|
83
|
cannam@270
|
84 enum {
|
cannam@270
|
85 explicitServer = 1,
|
cannam@270
|
86 autoServer = 2
|
cannam@270
|
87 };
|
cannam@270
|
88 enum {
|
cannam@270
|
89 timeDomain = 1,
|
cannam@270
|
90 frequencyDomainServerSide = 2,
|
cannam@270
|
91 frequencyDomainClientSide = 3
|
cannam@270
|
92 };
|
cannam@270
|
93
|
cannam@270
|
94 for (int domain = timeDomain;
|
cannam@270
|
95 domain <= frequencyDomainClientSide;
|
cannam@270
|
96 ++domain) {
|
cannam@270
|
97
|
cannam@270
|
98 for (int serverSort = explicitServer;
|
cannam@270
|
99 serverSort <= autoServer;
|
cannam@270
|
100 ++serverSort) {
|
cannam@270
|
101
|
cannam@270
|
102 string id = zeroCrossing;
|
cannam@270
|
103 if (domain == frequencyDomainServerSide ||
|
cannam@270
|
104 domain == frequencyDomainClientSide) {
|
cannam@270
|
105 id = powerSpectrum;
|
cannam@270
|
106 }
|
cannam@270
|
107
|
cannam@270
|
108 Vamp::Plugin *plugin = nullptr;
|
cannam@270
|
109
|
cannam@270
|
110 int adapterFlags = 0;
|
cannam@270
|
111 if (domain == frequencyDomainServerSide) {
|
cannam@270
|
112 adapterFlags = (int)
|
cannam@270
|
113 Vamp::HostExt::PluginLoader::ADAPT_INPUT_DOMAIN;
|
cannam@270
|
114 }
|
cannam@270
|
115
|
cannam@270
|
116 if (serverSort == explicitServer) {
|
cannam@270
|
117
|
cannam@270
|
118 cerr << endl << "*** Test: loading \"" << id
|
cannam@270
|
119 << "\" with explicit server" << endl;
|
cannam@270
|
120
|
cannam@270
|
121 piper_vamp::LoadRequest req;
|
cannam@270
|
122 req.pluginKey = id;
|
cannam@270
|
123 req.inputSampleRate = 16;
|
cannam@270
|
124 req.adapterFlags = adapterFlags;
|
cannam@270
|
125 piper_vamp::LoadResponse resp = client.load(req);
|
cannam@270
|
126 plugin = resp.plugin;
|
cannam@270
|
127 if (!plugin) {
|
cannam@270
|
128 cerr << "ERROR: plugin is null" << endl;
|
cannam@270
|
129 return 1;
|
cannam@270
|
130 }
|
cannam@270
|
131 cerr << "OK" << endl;
|
cannam@270
|
132
|
cannam@270
|
133 } else {
|
cannam@270
|
134
|
cannam@270
|
135 cerr << endl << "*** Test: loading \"" << id
|
cannam@270
|
136 << "\" with auto-plugin" << endl;
|
cannam@270
|
137
|
cannam@270
|
138 piper_vamp::client::PiperAutoPlugin *ap =
|
cannam@270
|
139 new piper_vamp::client::PiperAutoPlugin
|
cannam@270
|
140 (server, id, 16, adapterFlags, logger);
|
cannam@270
|
141 if (!ap->isOK()) {
|
cannam@270
|
142 cerr << "ERROR: PiperAutoPlugin creation failed" << endl;
|
cannam@270
|
143 return 1;
|
cannam@270
|
144 }
|
cannam@270
|
145 cerr << "OK" << endl;
|
cannam@270
|
146
|
cannam@270
|
147 plugin = ap;
|
cannam@270
|
148 }
|
cannam@270
|
149
|
cannam@270
|
150 if (domain == frequencyDomainClientSide) {
|
cannam@270
|
151 cerr << "*** Test: creating input-domain adapter" << endl;
|
cannam@270
|
152 plugin = new Vamp::HostExt::PluginInputDomainAdapter(plugin);
|
cannam@270
|
153 cerr << "OK" << endl;
|
cannam@270
|
154 }
|
cannam@270
|
155
|
cannam@270
|
156 cerr << endl << "*** Test: initialising plugin" << endl;
|
cannam@270
|
157 if (!plugin->initialise(1, 4, 4)) {
|
cannam@270
|
158 cerr << "ERROR: initialisation failed" << endl;
|
cannam@270
|
159 return 1;
|
cannam@270
|
160 }
|
cannam@270
|
161 cerr << "OK" << endl;
|
cannam@270
|
162
|
cannam@270
|
163 for (int round = 1; round <= 2; ++round) {
|
cannam@270
|
164 cerr << endl << "*** Test: processing"
|
cannam@270
|
165 << " (domain " << domain
|
cannam@270
|
166 << ", sort " << serverSort
|
cannam@270
|
167 << ", round " << round << ")" << endl;
|
cannam@270
|
168
|
cannam@270
|
169 vector<float> buf = { 1.0, -1.0, 1.0, -1.0 };
|
cannam@270
|
170 float *bd = buf.data();
|
cannam@270
|
171 Vamp::Plugin::FeatureSet features = plugin->process
|
cannam@270
|
172 (&bd, Vamp::RealTime::zeroTime);
|
cannam@270
|
173 cerr << "OK, process succeeded" << endl;
|
cannam@270
|
174 if (features[0].size() != 1) {
|
cannam@270
|
175 cerr << "ERROR: wrong number of features on output 0"
|
cannam@270
|
176 << " (expected 1, obtained " << features[0].size() << ")"
|
cannam@270
|
177 << endl;
|
cannam@270
|
178 return 1;
|
cannam@270
|
179 }
|
cannam@270
|
180 vector<float> expected;
|
cannam@270
|
181 if (domain == timeDomain) {
|
cannam@270
|
182 expected.push_back(4);
|
cannam@270
|
183 } else {
|
cannam@270
|
184 // these would be 0, 0, 16 if we were
|
cannam@270
|
185 // calculating the power spectrum without
|
cannam@270
|
186 // windowing - but the input domain adapter
|
cannam@270
|
187 // does window, and an asymmetrical Hann
|
cannam@270
|
188 // window gives these results
|
cannam@270
|
189 expected.push_back(0);
|
cannam@270
|
190 expected.push_back(1);
|
cannam@270
|
191 expected.push_back(4);
|
cannam@270
|
192 }
|
cannam@270
|
193
|
cannam@270
|
194 if (features[0][0].values.size() != expected.size()) {
|
cannam@270
|
195 cerr << "ERROR: wrong size for feature on output 0"
|
cannam@270
|
196 << " (expected " << expected.size()
|
cannam@270
|
197 << ", obtained "
|
cannam@270
|
198 << features[0][0].values.size() << ")" << endl;
|
cannam@270
|
199 return 1;
|
cannam@270
|
200 }
|
cannam@270
|
201 for (size_t i = 0; i < expected.size(); ++i) {
|
cannam@270
|
202 if (features[0][0].values[i] != expected[i]) {
|
cannam@270
|
203 cerr << "ERROR: wrong value for index " << i
|
cannam@270
|
204 << " of feature on output 0"
|
cannam@270
|
205 << " (expected " << expected[i]
|
cannam@270
|
206 << ", obtained "
|
cannam@270
|
207 << features[0][0].values[i] << ")" << endl;
|
cannam@270
|
208 cerr << "(All obtained values are:";
|
cannam@270
|
209 for (size_t j = 0; j < expected.size(); ++j) {
|
cannam@270
|
210 cerr << " " << features[0][0].values[j];
|
cannam@270
|
211 }
|
cannam@270
|
212 cerr << ")" << endl;
|
cannam@270
|
213 return 1;
|
cannam@270
|
214 }
|
cannam@270
|
215 }
|
cannam@270
|
216 cerr << "OK, results are correct" << endl;
|
cannam@270
|
217
|
cannam@270
|
218 (void)plugin->getRemainingFeatures();
|
cannam@270
|
219
|
cannam@270
|
220 if (round == 1) {
|
cannam@270
|
221 cerr << endl << "*** Test: resetting plugin for round 2" << endl;
|
cannam@270
|
222 plugin->reset();
|
cannam@270
|
223 cerr << "OK" << endl;
|
cannam@270
|
224 }
|
cannam@270
|
225 }
|
cannam@270
|
226
|
cannam@270
|
227 cerr << endl << "*** Test: deleting plugin" << endl;
|
cannam@270
|
228 delete plugin;
|
cannam@270
|
229 cerr << "OK" << endl;
|
cannam@150
|
230 }
|
cannam@150
|
231 }
|
cannam@150
|
232
|
cannam@150
|
233 } catch (const exception &e) {
|
cannam@150
|
234 cerr << "ERROR: Exception caught: " << e.what() << endl;
|
cannam@150
|
235 return 1;
|
cannam@150
|
236 }
|
cannam@150
|
237
|
cannam@270
|
238 cerr << endl << "*** All tests succeeded" << endl;
|
cannam@270
|
239
|
cannam@150
|
240 return 0;
|
cannam@150
|
241 }
|
cannam@150
|
242
|