comparison vamp-client/PiperVampPlugin.h @ 208:c67a0a945b6b

Rename PluginStub to PiperVampPlugin and AutoPlugin to PiperAutoPlugin
author Chris Cannam <cannam@all-day-breakfast.com>
date Thu, 09 Feb 2017 13:31:46 +0000
parents
children df65480a08de
comparison
equal deleted inserted replaced
207:61034472c304 208:c67a0a945b6b
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 /*
3 Piper C++
4
5 An API for audio analysis and feature extraction plugins.
6
7 Centre for Digital Music, Queen Mary, University of London.
8 Copyright 2006-2017 Chris Cannam and QMUL.
9
10 Permission is hereby granted, free of charge, to any person
11 obtaining a copy of this software and associated documentation
12 files (the "Software"), to deal in the Software without
13 restriction, including without limitation the rights to use, copy,
14 modify, merge, publish, distribute, sublicense, and/or sell copies
15 of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
17
18 The above copyright notice and this permission notice shall be
19 included in all copies or substantial portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
26 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29 Except as contained in this notice, the names of the Centre for
30 Digital Music; Queen Mary, University of London; and Chris Cannam
31 shall not be used in advertising or otherwise to promote the sale,
32 use or other dealings in this Software without prior written
33 authorization.
34 */
35
36 #ifndef PIPER_VAMP_PLUGIN_H
37 #define PIPER_VAMP_PLUGIN_H
38
39 #include <vamp-hostsdk/Plugin.h>
40 #include <vamp-hostsdk/PluginLoader.h>
41
42 #include "vamp-support/PluginStaticData.h"
43 #include "vamp-support/PluginConfiguration.h"
44
45 #include "PluginClient.h"
46
47 #include <cstdint>
48 #include <iostream>
49
50 namespace piper_vamp {
51 namespace client {
52
53 class PiperVampPlugin : public Vamp::Plugin
54 {
55 enum State {
56 /**
57 * The plugin's corresponding Piper feature extractor has been
58 * loaded but no subsequent state change has happened. This is
59 * the initial state of PiperVampPlugin on construction, since
60 * it is associated with a pre-loaded handle.
61 */
62 Loaded,
63
64 /**
65 * The plugin has been configured, and the step and block size
66 * received from the host in its last call to initialise()
67 * match those that were returned in the configuration
68 * response (i.e. the server's desired step and block
69 * size). Our m_config record reflects these correct
70 * values. The plugin is ready to process.
71 */
72 Configured,
73
74 /**
75 * The plugin has been configured, but the step and block size
76 * received from the host in its last call to initialise()
77 * differ from those returned by the server in the
78 * configuration response. Our initialise() call therefore
79 * returned false, and the plugin cannot be used until the
80 * host calls initialise() again with the "correct" step and
81 * block size. Our m_config record reflects these correct
82 * values, so the host can retrieve them through
83 * getPreferredStepSize and getPreferredBlockSize.
84 */
85 Misconfigured,
86
87 /**
88 * The finish() function has been called and the plugin
89 * unloaded. No further plugin activity is possible.
90 */
91 Finished,
92
93 /**
94 * A call has failed unrecoverably. No further plugin activity
95 * is possible.
96 */
97 Failed
98 };
99
100 public:
101 PiperVampPlugin(PluginClient *client,
102 std::string pluginKey,
103 float inputSampleRate,
104 int adapterFlags,
105 PluginStaticData psd,
106 PluginConfiguration defaultConfig) :
107 Plugin(inputSampleRate),
108 m_client(client),
109 m_key(pluginKey),
110 m_adapterFlags(adapterFlags),
111 m_state(Loaded),
112 m_psd(psd),
113 m_defaultConfig(defaultConfig),
114 m_config(defaultConfig)
115 { }
116
117 virtual ~PiperVampPlugin() {
118 if (m_state != Finished && m_state != Failed) {
119 try {
120 (void)m_client->finish(this);
121 } catch (const std::exception &e) {
122 // Finish can throw, but our destructor must not
123 std::cerr << "WARNING: PiperVampPlugin::~PiperVampPlugin: caught exception from finish(): " << e.what() << std::endl;
124 }
125 }
126 }
127
128 virtual std::string getIdentifier() const {
129 return m_psd.basic.identifier;
130 }
131
132 virtual std::string getName() const {
133 return m_psd.basic.name;
134 }
135
136 virtual std::string getDescription() const {
137 return m_psd.basic.description;
138 }
139
140 virtual std::string getMaker() const {
141 return m_psd.maker;
142 }
143
144 virtual std::string getCopyright() const {
145 return m_psd.copyright;
146 }
147
148 virtual int getPluginVersion() const {
149 return m_psd.pluginVersion;
150 }
151
152 virtual ParameterList getParameterDescriptors() const {
153 return m_psd.parameters;
154 }
155
156 virtual float getParameter(std::string name) const {
157 if (m_config.parameterValues.find(name) != m_config.parameterValues.end()) {
158 return m_config.parameterValues.at(name);
159 } else {
160 return 0.f;
161 }
162 }
163
164 virtual void setParameter(std::string name, float value) {
165 if (m_state == Failed) {
166 throw std::logic_error("Plugin is in failed state");
167 }
168 if (m_state != Loaded) {
169 m_state = Failed;
170 throw std::logic_error("Can't set parameter after plugin initialised");
171 }
172 m_config.parameterValues[name] = value;
173 }
174
175 virtual ProgramList getPrograms() const {
176 return m_psd.programs;
177 }
178
179 virtual std::string getCurrentProgram() const {
180 return m_config.currentProgram;
181 }
182
183 virtual void selectProgram(std::string program) {
184 if (m_state == Failed) {
185 throw std::logic_error("Plugin is in failed state");
186 }
187 if (m_state != Loaded) {
188 m_state = Failed;
189 throw std::logic_error("Can't select program after plugin initialised");
190 }
191 m_config.currentProgram = program;
192 }
193
194 virtual bool initialise(size_t inputChannels,
195 size_t stepSize,
196 size_t blockSize) {
197
198 if (m_state == Failed) {
199 throw std::logic_error("Plugin is in failed state");
200 }
201
202 if (m_state == Misconfigured) {
203 if (int(stepSize) == m_config.framing.stepSize &&
204 int(blockSize) == m_config.framing.blockSize) {
205 m_state = Configured;
206 return true;
207 } else {
208 return false;
209 }
210 }
211
212 if (m_state != Loaded) {
213 m_state = Failed;
214 throw std::logic_error("Plugin has already been initialised");
215 }
216
217 m_config.channelCount = int(inputChannels);
218 m_config.framing.stepSize = int(stepSize);
219 m_config.framing.blockSize = int(blockSize);
220
221 try {
222 auto response = m_client->configure(this, m_config);
223 m_outputs = response.outputs;
224
225 // Update with the new preferred step and block size now
226 // that the plugin has taken into account its parameter
227 // settings. If the values passed in to initialise()
228 // weren't suitable, then this ensures that a subsequent
229 // call to getPreferredStepSize/BlockSize on this plugin
230 // object will at least get acceptable values from now on
231 m_config.framing = response.framing;
232
233 // And if they didn't match up with the passed-in ones,
234 // lodge ourselves in Misconfigured state and report
235 // failure so as to provoke the host to call initialise()
236 // again before any processing.
237 if (m_config.framing.stepSize != int(stepSize) ||
238 m_config.framing.blockSize != int(blockSize)) {
239 m_state = Misconfigured;
240 return false;
241 }
242
243 } catch (const std::exception &e) {
244 m_state = Failed;
245 throw;
246 }
247
248 if (!m_outputs.empty()) {
249 m_state = Configured;
250 return true;
251 } else {
252 return false;
253 }
254 }
255
256 virtual void reset() {
257
258 if (m_state == Failed) {
259 throw std::logic_error("Plugin is in failed state");
260 }
261 if (m_state == Loaded || m_state == Misconfigured) {
262 // reset is a no-op if the plugin hasn't been initialised yet
263 return;
264 }
265
266 try {
267 m_client->reset(this, m_config);
268 } catch (const std::exception &e) {
269 m_state = Failed;
270 throw;
271 }
272
273 m_state = Configured;
274 }
275
276 virtual InputDomain getInputDomain() const {
277 return m_psd.inputDomain;
278 }
279
280 virtual size_t getPreferredBlockSize() const {
281 // Return this from m_config instead of m_defaultConfig, so
282 // that it gets updated in the event of an initialise() call
283 // that fails for the wrong value
284 return m_config.framing.blockSize;
285 }
286
287 virtual size_t getPreferredStepSize() const {
288 // Return this from m_config instead of m_defaultConfig, so
289 // that it gets updated in the event of an initialise() call
290 // that fails for the wrong value
291 return m_config.framing.stepSize;
292 }
293
294 virtual size_t getMinChannelCount() const {
295 return m_psd.minChannelCount;
296 }
297
298 virtual size_t getMaxChannelCount() const {
299 return m_psd.maxChannelCount;
300 }
301
302 virtual OutputList getOutputDescriptors() const {
303
304 if (m_state == Failed) {
305 throw std::logic_error("Plugin is in failed state");
306 }
307 if (m_state == Configured) {
308 return m_outputs;
309 }
310
311 //!!! todo: figure out for which hosts (and adapters?) it may
312 //!!! be a problem that the output descriptors are incomplete
313 //!!! here. Any such hosts/adapters are broken, but I bet they
314 //!!! exist
315
316 OutputList staticOutputs;
317 for (const auto &o: m_psd.basicOutputInfo) {
318 OutputDescriptor od;
319 od.identifier = o.identifier;
320 od.name = o.name;
321 od.description = o.description;
322 staticOutputs.push_back(od);
323 }
324 return staticOutputs;
325 }
326
327 virtual FeatureSet process(const float *const *inputBuffers,
328 Vamp::RealTime timestamp) {
329
330 if (m_state == Failed) {
331 throw std::logic_error("Plugin is in failed state");
332 }
333 if (m_state == Loaded || m_state == Misconfigured) {
334 m_state = Failed;
335 throw std::logic_error("Plugin has not been initialised");
336 }
337 if (m_state == Finished) {
338 m_state = Failed;
339 throw std::logic_error("Plugin has already been disposed of");
340 }
341
342 std::vector<std::vector<float> > vecbuf;
343 for (int c = 0; c < m_config.channelCount; ++c) {
344 vecbuf.push_back(std::vector<float>
345 (inputBuffers[c],
346 inputBuffers[c] + m_config.framing.blockSize));
347 }
348
349 try {
350 return m_client->process(this, vecbuf, timestamp);
351 } catch (const std::exception &e) {
352 m_state = Failed;
353 throw;
354 }
355 }
356
357 virtual FeatureSet getRemainingFeatures() {
358
359 if (m_state == Failed) {
360 throw std::logic_error("Plugin is in failed state");
361 }
362 if (m_state == Loaded || m_state == Misconfigured) {
363 m_state = Failed;
364 throw std::logic_error("Plugin has not been configured");
365 }
366 if (m_state == Finished) {
367 m_state = Failed;
368 throw std::logic_error("Plugin has already been disposed of");
369 }
370
371 m_state = Finished;
372
373 try {
374 return m_client->finish(this);
375 } catch (const std::exception &e) {
376 m_state = Failed;
377 throw;
378 }
379 }
380
381 // Not Plugin methods, but needed by the PluginClient to support reloads:
382
383 virtual float getInputSampleRate() const {
384 return m_inputSampleRate;
385 }
386
387 virtual std::string getPluginKey() const {
388 return m_key;
389 }
390
391 virtual int getAdapterFlags() const {
392 return m_adapterFlags;
393 }
394
395 private:
396 PluginClient *m_client;
397 std::string m_key;
398 int m_adapterFlags;
399 State m_state;
400 PluginStaticData m_psd;
401 OutputList m_outputs;
402 PluginConfiguration m_defaultConfig;
403 PluginConfiguration m_config;
404 };
405
406 }
407 }
408
409 #endif