1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4     Piper C++
5 
6     Centre for Digital Music, Queen Mary, University of London.
7     Copyright 2015-2017 QMUL.
8 
9     Permission is hereby granted, free of charge, to any person
10     obtaining a copy of this software and associated documentation
11     files (the "Software"), to deal in the Software without
12     restriction, including without limitation the rights to use, copy,
13     modify, merge, publish, distribute, sublicense, and/or sell copies
14     of the Software, and to permit persons to whom the Software is
15     furnished to do so, subject to the following conditions:
16 
17     The above copyright notice and this permission notice shall be
18     included in all copies or substantial portions of the Software.
19 
20     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
24     ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
25     CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26     WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 
28     Except as contained in this notice, the names of the Centre for
29     Digital Music; Queen Mary, University of London; and Chris Cannam
30     shall not be used in advertising or otherwise to promote the sale,
31     use or other dealings in this Software without prior written
32     authorization.
33 */
34 
35 #include "piper.capnp.h"
36 
37 #include <capnp/message.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 #include "vamp-support/RequestResponse.h"
45 
46 #include "vamp-support/PluginHandleMapper.h"
47 #include "vamp-support/PluginOutputIdMapper.h"
48 #include "vamp-support/RequestResponseType.h"
49 
50 namespace piper_vamp
51 {
52 
53 /**
54  * Convert the structures laid out in the Vamp SDK classes into Cap'n
55  * Proto structures (and back again).
56  *
57  * At least some of this will be necessary for any implementation
58  * using Cap'n Proto that uses the C++ Vamp SDK to provide its
59  * reference structures. An implementation could alternatively use the
60  * Cap'n Proto structures directly, and interact with Vamp plugins
61  * using the Vamp C API, without using the C++ Vamp SDK classes at
62  * all. That would avoid a lot of copying (in Cap'n Proto style).
63  */
64 class VampnProto
65 {
66 public:
67     typedef ::capnp::MallocMessageBuilder MsgBuilder;
68 
69     template <typename T, typename B>
buildBasicDescriptor(B & basic,const T & t)70     static void buildBasicDescriptor(B &basic, const T &t) {
71         basic.setIdentifier(t.identifier);
72         basic.setName(t.name);
73         basic.setDescription(t.description);
74     }
75 
76     template <typename T, typename B>
readBasicDescriptor(T & t,const B & basic)77     static void readBasicDescriptor(T &t, const B &basic) {
78         t.identifier = basic.getIdentifier();
79         t.name = basic.getName();
80         t.description = basic.getDescription();
81     }
82 
83     template <typename T, typename M>
buildValueExtents(M & m,const T & t)84     static void buildValueExtents(M &m, const T &t) {
85         m.setMinValue(t.minValue);
86         m.setMaxValue(t.maxValue);
87     }
88 
89     template <typename T, typename M>
readValueExtents(T & t,const M & m)90     static void readValueExtents(T &t, const M &m) {
91         t.minValue = m.getMinValue();
92         t.maxValue = m.getMaxValue();
93     }
94 
buildRealTime(piper::RealTime::Builder & b,const Vamp::RealTime & t)95     static void buildRealTime(piper::RealTime::Builder &b,
96                               const Vamp::RealTime &t) {
97         b.setSec(t.sec);
98         b.setNsec(t.nsec);
99     }
100 
readRealTime(Vamp::RealTime & t,const piper::RealTime::Reader & r)101     static void readRealTime(Vamp::RealTime &t,
102                              const piper::RealTime::Reader &r) {
103         t.sec = r.getSec();
104         t.nsec = r.getNsec();
105     }
106 
107     static piper::SampleType
fromSampleType(Vamp::Plugin::OutputDescriptor::SampleType t)108     fromSampleType(Vamp::Plugin::OutputDescriptor::SampleType t) {
109         switch (t) {
110         case Vamp::Plugin::OutputDescriptor::OneSamplePerStep:
111             return piper::SampleType::ONE_SAMPLE_PER_STEP;
112         case Vamp::Plugin::OutputDescriptor::FixedSampleRate:
113             return piper::SampleType::FIXED_SAMPLE_RATE;
114         case Vamp::Plugin::OutputDescriptor::VariableSampleRate:
115             return piper::SampleType::VARIABLE_SAMPLE_RATE;
116         }
117         throw std::logic_error("unexpected Vamp SampleType enum value");
118     }
119 
120     static Vamp::Plugin::OutputDescriptor::SampleType
toSampleType(piper::SampleType t)121     toSampleType(piper::SampleType t) {
122         switch (t) {
123         case piper::SampleType::ONE_SAMPLE_PER_STEP:
124             return Vamp::Plugin::OutputDescriptor::OneSamplePerStep;
125         case piper::SampleType::FIXED_SAMPLE_RATE:
126             return Vamp::Plugin::OutputDescriptor::FixedSampleRate;
127         case piper::SampleType::VARIABLE_SAMPLE_RATE:
128             return Vamp::Plugin::OutputDescriptor::VariableSampleRate;
129         }
130         throw std::logic_error("unexpected Capnp SampleType enum value");
131     }
132 
133     static void
buildStaticOutputDescriptor(piper::StaticOutputDescriptor::Builder & b,const StaticOutputDescriptor & sd)134     buildStaticOutputDescriptor(piper::StaticOutputDescriptor::Builder &b,
135                                 const StaticOutputDescriptor &sd) {
136         b.setTypeURI(sd.typeURI);
137     }
138 
139     static void
buildConfiguredOutputDescriptor(piper::ConfiguredOutputDescriptor::Builder & b,const Vamp::Plugin::OutputDescriptor & od)140     buildConfiguredOutputDescriptor(piper::ConfiguredOutputDescriptor::Builder &b,
141                                     const Vamp::Plugin::OutputDescriptor &od) {
142 
143         b.setUnit(od.unit);
144         b.setSampleType(fromSampleType(od.sampleType));
145         b.setSampleRate(od.sampleRate);
146         b.setHasDuration(od.hasDuration);
147 
148         b.setHasFixedBinCount(od.hasFixedBinCount);
149         if (od.hasFixedBinCount) {
150             b.setBinCount(int(od.binCount));
151             if (od.binNames.size() > 0) {
152                 auto binNames = b.initBinNames(unsigned(od.binNames.size()));
153                 for (int i = 0; i < int(od.binNames.size()); ++i) {
154                     binNames.set(i, od.binNames[i]);
155                 }
156             }
157         }
158 
159         b.setHasKnownExtents(od.hasKnownExtents);
160         if (od.hasKnownExtents) {
161             buildValueExtents(b, od);
162         }
163 
164         b.setIsQuantized(od.isQuantized);
165         if (od.isQuantized) {
166             b.setQuantizeStep(od.quantizeStep);
167         }
168     }
169 
170     static void
buildOutputDescriptor(piper::OutputDescriptor::Builder & b,const Vamp::Plugin::OutputDescriptor & od,const StaticOutputDescriptor & sd)171     buildOutputDescriptor(piper::OutputDescriptor::Builder &b,
172                           const Vamp::Plugin::OutputDescriptor &od,
173                           const StaticOutputDescriptor &sd) {
174 
175         auto basic = b.initBasic();
176         buildBasicDescriptor(basic, od);
177 
178         auto configured = b.initConfigured();
179         buildConfiguredOutputDescriptor(configured, od);
180 
181         auto statc = b.initStatic();
182         buildStaticOutputDescriptor(statc, sd);
183     }
184 
185     static void
readStaticOutputDescriptor(StaticOutputDescriptor & sd,const piper::StaticOutputDescriptor::Reader & r)186     readStaticOutputDescriptor(StaticOutputDescriptor &sd,
187                                const piper::StaticOutputDescriptor::Reader &r) {
188         sd.typeURI = r.getTypeURI();
189     }
190 
191     static void
readConfiguredOutputDescriptor(Vamp::Plugin::OutputDescriptor & od,const piper::ConfiguredOutputDescriptor::Reader & r)192     readConfiguredOutputDescriptor(Vamp::Plugin::OutputDescriptor &od,
193                                    const piper::ConfiguredOutputDescriptor::Reader &r) {
194 
195         od.unit = r.getUnit();
196 
197         od.sampleType = toSampleType(r.getSampleType());
198         od.sampleRate = r.getSampleRate();
199         od.hasDuration = r.getHasDuration();
200 
201         od.hasFixedBinCount = r.getHasFixedBinCount();
202         if (od.hasFixedBinCount) {
203             od.binCount = r.getBinCount();
204             od.binNames.clear();
205             auto nn = r.getBinNames();
206             for (const auto &n: nn) {
207                 od.binNames.push_back(n);
208             }
209         }
210 
211         od.hasKnownExtents = r.getHasKnownExtents();
212         if (od.hasKnownExtents) {
213             readValueExtents(od, r);
214         }
215 
216         od.isQuantized = r.getIsQuantized();
217         if (od.isQuantized) {
218             od.quantizeStep = r.getQuantizeStep();
219         }
220     }
221 
222     static void
readOutputDescriptor(Vamp::Plugin::OutputDescriptor & od,StaticOutputDescriptor & sd,const piper::OutputDescriptor::Reader & r)223     readOutputDescriptor(Vamp::Plugin::OutputDescriptor &od,
224                          StaticOutputDescriptor &sd,
225                          const piper::OutputDescriptor::Reader &r) {
226 
227         readBasicDescriptor(od, r.getBasic());
228         readStaticOutputDescriptor(sd, r.getStatic());
229         readConfiguredOutputDescriptor(od, r.getConfigured());
230     }
231 
232     static void
buildParameterDescriptor(piper::ParameterDescriptor::Builder & b,const Vamp::Plugin::ParameterDescriptor & pd)233     buildParameterDescriptor(piper::ParameterDescriptor::Builder &b,
234                              const Vamp::Plugin::ParameterDescriptor &pd) {
235 
236         auto basic = b.initBasic();
237         buildBasicDescriptor(basic, pd);
238 
239         b.setUnit(pd.unit);
240 
241         buildValueExtents(b, pd);
242 
243         b.setDefaultValue(pd.defaultValue);
244 
245         b.setIsQuantized(pd.isQuantized);
246         if (pd.isQuantized) {
247             b.setQuantizeStep(pd.quantizeStep);
248         }
249 
250         if (pd.valueNames.size() > 0) {
251             auto valueNames = b.initValueNames(unsigned(pd.valueNames.size()));
252             for (int i = 0; i < int(pd.valueNames.size()); ++i) {
253                 valueNames.set(i, pd.valueNames[i]);
254             }
255         }
256     }
257 
258     static void
readParameterDescriptor(Vamp::Plugin::ParameterDescriptor & pd,const piper::ParameterDescriptor::Reader & r)259     readParameterDescriptor(Vamp::Plugin::ParameterDescriptor &pd,
260                             const piper::ParameterDescriptor::Reader &r) {
261 
262         readBasicDescriptor(pd, r.getBasic());
263 
264         pd.unit = r.getUnit();
265 
266         readValueExtents(pd, r);
267 
268         pd.defaultValue = r.getDefaultValue();
269 
270         pd.isQuantized = r.getIsQuantized();
271         if (pd.isQuantized) {
272             pd.quantizeStep = r.getQuantizeStep();
273         }
274 
275         pd.valueNames.clear();
276         auto nn = r.getValueNames();
277         for (const auto &n: nn) {
278             pd.valueNames.push_back(n);
279         }
280     }
281 
282     static void
buildFeature(piper::Feature::Builder & b,const Vamp::Plugin::Feature & f)283     buildFeature(piper::Feature::Builder &b,
284                  const Vamp::Plugin::Feature &f) {
285 
286         b.setHasTimestamp(f.hasTimestamp);
287         if (f.hasTimestamp) {
288             auto timestamp = b.initTimestamp();
289             buildRealTime(timestamp, f.timestamp);
290         }
291 
292         b.setHasDuration(f.hasDuration);
293         if (f.hasDuration) {
294             auto duration = b.initDuration();
295             buildRealTime(duration, f.duration);
296         }
297 
298         b.setLabel(f.label);
299 
300         if (f.values.size() > 0) {
301             auto values = b.initFeatureValues(unsigned(f.values.size()));
302             for (int i = 0; i < int(f.values.size()); ++i) {
303                 values.set(i, f.values[i]);
304             }
305         }
306     }
307 
308     static void
readFeature(Vamp::Plugin::Feature & f,const piper::Feature::Reader & r)309     readFeature(Vamp::Plugin::Feature &f,
310                 const piper::Feature::Reader &r) {
311 
312         f.hasTimestamp = r.getHasTimestamp();
313         if (f.hasTimestamp) {
314             readRealTime(f.timestamp, r.getTimestamp());
315         }
316 
317         f.hasDuration = r.getHasDuration();
318         if (f.hasDuration) {
319             readRealTime(f.duration, r.getDuration());
320         }
321 
322         f.label = r.getLabel();
323 
324         f.values.clear();
325         auto vv = r.getFeatureValues();
326         for (auto v: vv) {
327             f.values.push_back(v);
328         }
329     }
330 
331     static void
buildFeatureSet(piper::FeatureSet::Builder & b,const Vamp::Plugin::FeatureSet & fs,const PluginOutputIdMapper & omapper)332     buildFeatureSet(piper::FeatureSet::Builder &b,
333                     const Vamp::Plugin::FeatureSet &fs,
334                     const PluginOutputIdMapper &omapper) {
335 
336         auto featureset = b.initFeaturePairs(unsigned(fs.size()));
337         int ix = 0;
338         for (const auto &fsi : fs) {
339             auto fspair = featureset[ix];
340             fspair.setOutput(omapper.indexToId(fsi.first));
341             auto featurelist = fspair.initFeatures(unsigned(fsi.second.size()));
342             for (int j = 0; j < int(fsi.second.size()); ++j) {
343                 auto feature = featurelist[j];
344                 buildFeature(feature, fsi.second[j]);
345             }
346             ++ix;
347         }
348     }
349 
350     static void
readFeatureSet(Vamp::Plugin::FeatureSet & fs,const piper::FeatureSet::Reader & r,const PluginOutputIdMapper & omapper)351     readFeatureSet(Vamp::Plugin::FeatureSet &fs,
352                    const piper::FeatureSet::Reader &r,
353                    const PluginOutputIdMapper &omapper) {
354 
355         fs.clear();
356         auto pp = r.getFeaturePairs();
357         for (const auto &p: pp) {
358             Vamp::Plugin::FeatureList vfl;
359             auto ff = p.getFeatures();
360             for (const auto &f: ff) {
361                 Vamp::Plugin::Feature vf;
362                 readFeature(vf, f);
363                 vfl.push_back(vf);
364             }
365             fs[omapper.idToIndex(p.getOutput())] = vfl;
366         }
367     }
368 
369     static piper::InputDomain
fromInputDomain(Vamp::Plugin::InputDomain d)370     fromInputDomain(Vamp::Plugin::InputDomain d) {
371         switch(d) {
372         case Vamp::Plugin::TimeDomain:
373             return piper::InputDomain::TIME_DOMAIN;
374         case Vamp::Plugin::FrequencyDomain:
375             return piper::InputDomain::FREQUENCY_DOMAIN;
376         default:
377             throw std::logic_error("unexpected Vamp InputDomain enum value");
378         }
379     }
380 
381     static Vamp::Plugin::InputDomain
toInputDomain(piper::InputDomain d)382     toInputDomain(piper::InputDomain d) {
383         switch(d) {
384         case piper::InputDomain::TIME_DOMAIN:
385             return Vamp::Plugin::TimeDomain;
386         case piper::InputDomain::FREQUENCY_DOMAIN:
387             return Vamp::Plugin::FrequencyDomain;
388         default:
389             throw std::logic_error("unexpected Capnp InputDomain enum value");
390         }
391     }
392 
393     static void
buildExtractorStaticData(piper::ExtractorStaticData::Builder & b,const PluginStaticData & d)394     buildExtractorStaticData(piper::ExtractorStaticData::Builder &b,
395                              const PluginStaticData &d) {
396 
397         b.setKey(d.pluginKey);
398 
399         auto basic = b.initBasic();
400         buildBasicDescriptor(basic, d.basic);
401 
402         b.setMaker(d.maker);
403         b.setRights(d.copyright);
404         b.setVersion(d.pluginVersion);
405 
406         auto clist = b.initCategory(unsigned(d.category.size()));
407         for (int i = 0; i < int(d.category.size()); ++i) {
408             clist.set(i, d.category[i]);
409         }
410 
411         b.setMinChannelCount(int(d.minChannelCount));
412         b.setMaxChannelCount(int(d.maxChannelCount));
413 
414         const auto &vparams = d.parameters;
415         auto plist = b.initParameters(unsigned(vparams.size()));
416         for (int i = 0; i < int(vparams.size()); ++i) {
417             auto pd = plist[i];
418             buildParameterDescriptor(pd, vparams[i]);
419         }
420 
421         const auto &vprogs = d.programs;
422         auto pglist = b.initPrograms(unsigned(vprogs.size()));
423         for (int i = 0; i < int(vprogs.size()); ++i) {
424             pglist.set(i, vprogs[i]);
425         }
426 
427         b.setInputDomain(fromInputDomain(d.inputDomain));
428 
429         const auto &vouts = d.basicOutputInfo;
430         auto olist = b.initBasicOutputInfo(unsigned(vouts.size()));
431         for (int i = 0; i < int(vouts.size()); ++i) {
432             auto od = olist[i];
433             buildBasicDescriptor(od, vouts[i]);
434         }
435 
436         const auto &vstatic = d.staticOutputInfo;
437         auto slist = b.initStaticOutputInfo(unsigned(vstatic.size()));
438         int i = 0;
439         for (const auto &vi: vstatic) {
440             auto spair = slist[i];
441             spair.setOutput(vi.first);
442             auto sdata = spair.initStatic();
443             sdata.setTypeURI(vi.second.typeURI);
444             ++i;
445         }
446     }
447 
448     static void
readExtractorStaticData(PluginStaticData & d,const piper::ExtractorStaticData::Reader & r)449     readExtractorStaticData(PluginStaticData &d,
450                             const piper::ExtractorStaticData::Reader &r) {
451 
452         d.pluginKey = r.getKey();
453 
454         readBasicDescriptor(d.basic, r.getBasic());
455 
456         d.maker = r.getMaker();
457         d.copyright = r.getRights();
458         d.pluginVersion = r.getVersion();
459 
460         d.category.clear();
461         auto cc = r.getCategory();
462         for (auto c: cc) {
463             d.category.push_back(c);
464         }
465 
466         d.minChannelCount = r.getMinChannelCount();
467         d.maxChannelCount = r.getMaxChannelCount();
468 
469         d.parameters.clear();
470         auto pp = r.getParameters();
471         for (auto p: pp) {
472             Vamp::Plugin::ParameterDescriptor pd;
473             readParameterDescriptor(pd, p);
474             d.parameters.push_back(pd);
475         }
476 
477         d.programs.clear();
478         auto prp = r.getPrograms();
479         for (auto p: prp) {
480             d.programs.push_back(p);
481         }
482 
483         d.inputDomain = toInputDomain(r.getInputDomain());
484 
485         d.basicOutputInfo.clear();
486         auto oo = r.getBasicOutputInfo();
487         for (auto o: oo) {
488             PluginStaticData::Basic b;
489             readBasicDescriptor(b, o);
490             d.basicOutputInfo.push_back(b);
491         }
492 
493         d.staticOutputInfo.clear();
494         auto sp = r.getStaticOutputInfo();
495         for (auto s: sp) {
496             std::string id = s.getOutput();
497             std::string typeURI = s.getStatic().getTypeURI();
498             d.staticOutputInfo[id] = { typeURI };
499         }
500     }
501 
502     static void
buildConfiguration(piper::Configuration::Builder & b,const PluginConfiguration & c)503     buildConfiguration(piper::Configuration::Builder &b,
504                        const PluginConfiguration &c) {
505 
506         const auto &vparams = c.parameterValues;
507         auto params = b.initParameterValues(unsigned(vparams.size()));
508         int i = 0;
509         for (const auto &pp : vparams) {
510             auto param = params[i++];
511             param.setParameter(pp.first);
512             param.setValue(pp.second);
513         }
514 
515         b.setCurrentProgram(c.currentProgram);
516         b.setChannelCount(c.channelCount);
517 
518         auto framing = b.initFraming();
519         framing.setStepSize(c.framing.stepSize);
520         framing.setBlockSize(c.framing.blockSize);
521     }
522 
523     static void
readConfiguration(PluginConfiguration & c,const piper::Configuration::Reader & r)524     readConfiguration(PluginConfiguration &c,
525                       const piper::Configuration::Reader &r) {
526 
527         auto pp = r.getParameterValues();
528         for (const auto &p: pp) {
529             c.parameterValues[p.getParameter()] = p.getValue();
530         }
531 
532         c.currentProgram = r.getCurrentProgram();
533         c.channelCount = r.getChannelCount();
534         c.framing.stepSize = r.getFraming().getStepSize();
535         c.framing.blockSize = r.getFraming().getBlockSize();
536     }
537 
538     static void
buildListRequest(piper::ListRequest::Builder & r,const ListRequest & resp)539     buildListRequest(piper::ListRequest::Builder &r,
540                      const ListRequest &resp) {
541 
542         auto p = r.initFrom(unsigned(resp.from.size()));
543         for (int i = 0; i < int(resp.from.size()); ++i) {
544             p.set(i, resp.from[i]);
545         }
546     }
547 
548     static void
readListRequest(ListRequest & lr,const piper::ListRequest::Reader & r)549     readListRequest(ListRequest &lr,
550                     const piper::ListRequest::Reader &r) {
551 
552         lr.from.clear();
553         for (auto f: r.getFrom()) {
554             lr.from.push_back(f);
555         }
556     }
557 
558     static void
buildListResponse(piper::ListResponse::Builder & r,const ListResponse & resp)559     buildListResponse(piper::ListResponse::Builder &r,
560                       const ListResponse &resp) {
561 
562         auto p = r.initAvailable(unsigned(resp.available.size()));
563         for (int i = 0; i < int(resp.available.size()); ++i) {
564             auto pd = p[i];
565             buildExtractorStaticData(pd, resp.available[i]);
566         }
567     }
568 
569     static void
readListResponse(ListResponse & lr,const piper::ListResponse::Reader & r)570     readListResponse(ListResponse &lr,
571                      const piper::ListResponse::Reader &r) {
572 
573         lr.available.clear();
574         auto pp = r.getAvailable();
575         for (const auto &p: pp) {
576             PluginStaticData psd;
577             readExtractorStaticData(psd, p);
578             lr.available.push_back(psd);
579         }
580     }
581 
582     static void
buildLoadRequest(piper::LoadRequest::Builder & r,const LoadRequest & req)583     buildLoadRequest(piper::LoadRequest::Builder &r,
584                      const LoadRequest &req) {
585 
586         r.setKey(req.pluginKey);
587         r.setInputSampleRate(req.inputSampleRate);
588 
589         std::vector<piper::AdapterFlag> flags;
590         if (req.adapterFlags & Vamp::HostExt::PluginLoader::ADAPT_INPUT_DOMAIN) {
591             flags.push_back(piper::AdapterFlag::ADAPT_INPUT_DOMAIN);
592         }
593         if (req.adapterFlags & Vamp::HostExt::PluginLoader::ADAPT_CHANNEL_COUNT) {
594             flags.push_back(piper::AdapterFlag::ADAPT_CHANNEL_COUNT);
595         }
596         if (req.adapterFlags & Vamp::HostExt::PluginLoader::ADAPT_BUFFER_SIZE) {
597             flags.push_back(piper::AdapterFlag::ADAPT_BUFFER_SIZE);
598         }
599 
600         auto f = r.initAdapterFlags(unsigned(flags.size()));
601         for (int i = 0; i < int(flags.size()); ++i) {
602             f.set(i, flags[i]);
603         }
604     }
605 
606     static void
readLoadRequest(LoadRequest & req,const piper::LoadRequest::Reader & r)607     readLoadRequest(LoadRequest &req,
608                     const piper::LoadRequest::Reader &r) {
609 
610         req.pluginKey = r.getKey();
611         req.inputSampleRate = r.getInputSampleRate();
612 
613         int flags = 0;
614         auto aa = r.getAdapterFlags();
615         for (auto a: aa) {
616             if (a == piper::AdapterFlag::ADAPT_INPUT_DOMAIN) {
617                 flags |= Vamp::HostExt::PluginLoader::ADAPT_INPUT_DOMAIN;
618             }
619             if (a == piper::AdapterFlag::ADAPT_CHANNEL_COUNT) {
620                 flags |= Vamp::HostExt::PluginLoader::ADAPT_CHANNEL_COUNT;
621             }
622             if (a == piper::AdapterFlag::ADAPT_BUFFER_SIZE) {
623                 flags |= Vamp::HostExt::PluginLoader::ADAPT_BUFFER_SIZE;
624             }
625         }
626         req.adapterFlags = flags;
627     }
628 
629     static void
buildLoadResponse(piper::LoadResponse::Builder & b,const LoadResponse & resp,const PluginHandleMapper & pmapper)630     buildLoadResponse(piper::LoadResponse::Builder &b,
631                       const LoadResponse &resp,
632                       const PluginHandleMapper &pmapper) {
633 
634         b.setHandle(pmapper.pluginToHandle(resp.plugin));
635         auto sd = b.initStaticData();
636         buildExtractorStaticData(sd, resp.staticData);
637         auto conf = b.initDefaultConfiguration();
638         buildConfiguration(conf, resp.defaultConfiguration);
639     }
640 
641     static void
readLoadResponse(LoadResponse & resp,const piper::LoadResponse::Reader & r,const PluginHandleMapper & pmapper)642     readLoadResponse(LoadResponse &resp,
643                      const piper::LoadResponse::Reader &r,
644                      const PluginHandleMapper &pmapper) {
645 
646         auto h = r.getHandle();
647         resp.plugin = pmapper.handleToPlugin(h);
648         readExtractorStaticData(resp.staticData, r.getStaticData());
649         readConfiguration(resp.defaultConfiguration,
650                           r.getDefaultConfiguration());
651     }
652 
653     static void
buildConfigurationRequest(piper::ConfigurationRequest::Builder & b,const ConfigurationRequest & cr,const PluginHandleMapper & pmapper)654     buildConfigurationRequest(piper::ConfigurationRequest::Builder &b,
655                               const ConfigurationRequest &cr,
656                               const PluginHandleMapper &pmapper) {
657 
658         b.setHandle(pmapper.pluginToHandle(cr.plugin));
659         auto c = b.initConfiguration();
660         buildConfiguration(c, cr.configuration);
661     }
662 
663     static void
readConfigurationRequest(ConfigurationRequest & cr,const piper::ConfigurationRequest::Reader & r,const PluginHandleMapper & pmapper)664     readConfigurationRequest(ConfigurationRequest &cr,
665                              const piper::ConfigurationRequest::Reader &r,
666                              const PluginHandleMapper &pmapper) {
667 
668         auto h = r.getHandle();
669         cr.plugin = pmapper.handleToPlugin(h);
670         auto c = r.getConfiguration();
671         readConfiguration(cr.configuration, c);
672     }
673 
674     static void
buildConfigurationResponse(piper::ConfigurationResponse::Builder & b,const ConfigurationResponse & cr,const PluginHandleMapper & pmapper)675     buildConfigurationResponse(piper::ConfigurationResponse::Builder &b,
676                                const ConfigurationResponse &cr,
677                                const PluginHandleMapper &pmapper) {
678 
679         b.setHandle(pmapper.pluginToHandle(cr.plugin));
680         auto olist = b.initOutputs(unsigned(cr.outputs.size()));
681 
682         for (int i = 0; i < int(cr.outputs.size()); ++i) {
683 
684             auto id = cr.outputs[i].identifier;
685             StaticOutputDescriptor sd;
686             if (cr.staticOutputInfo.find(id) != cr.staticOutputInfo.end()) {
687                 sd = cr.staticOutputInfo.at(id);
688             }
689 
690             auto od = olist[i];
691             buildOutputDescriptor(od, cr.outputs[i], sd);
692         }
693 
694         auto framing = b.initFraming();
695         framing.setStepSize(cr.framing.stepSize);
696         framing.setBlockSize(cr.framing.blockSize);
697     }
698 
699     static void
readConfigurationResponse(ConfigurationResponse & cr,const piper::ConfigurationResponse::Reader & r,const PluginHandleMapper & pmapper)700     readConfigurationResponse(ConfigurationResponse &cr,
701                               const piper::ConfigurationResponse::Reader &r,
702                               const PluginHandleMapper &pmapper) {
703 
704         auto h = r.getHandle();
705         cr.plugin = pmapper.handleToPlugin(h);
706         cr.outputs.clear();
707         cr.staticOutputInfo.clear();
708         auto oo = r.getOutputs();
709         for (const auto &o: oo) {
710             Vamp::Plugin::OutputDescriptor desc;
711             StaticOutputDescriptor sd;
712             readOutputDescriptor(desc, sd, o);
713             cr.outputs.push_back(desc);
714             if (sd.typeURI != "") {
715                 cr.staticOutputInfo[desc.identifier] = { sd.typeURI };
716             }
717         }
718         cr.framing.stepSize = r.getFraming().getStepSize();
719         cr.framing.blockSize = r.getFraming().getBlockSize();
720     }
721 
722     static void
buildProcessInput(piper::ProcessInput::Builder & b,Vamp::RealTime timestamp,const std::vector<std::vector<float>> & buffers)723     buildProcessInput(piper::ProcessInput::Builder &b,
724                       Vamp::RealTime timestamp,
725                       const std::vector<std::vector<float> > &buffers) {
726 
727         auto t = b.initTimestamp();
728         buildRealTime(t, timestamp);
729         auto vv = b.initInputBuffers(unsigned(buffers.size()));
730         for (int ch = 0; ch < int(buffers.size()); ++ch) {
731             const int n = int(buffers[ch].size());
732             vv.init(ch, n);
733             auto v = vv[ch];
734             for (int i = 0; i < n; ++i) {
735                 v.set(i, buffers[ch][i]);
736             }
737         }
738     }
739 
740     static void
readProcessInput(Vamp::RealTime & timestamp,std::vector<std::vector<float>> & buffers,const piper::ProcessInput::Reader & b)741     readProcessInput(Vamp::RealTime &timestamp,
742                      std::vector<std::vector<float> > &buffers,
743                      const piper::ProcessInput::Reader &b) {
744 
745         readRealTime(timestamp, b.getTimestamp());
746         buffers.clear();
747         auto vv = b.getInputBuffers();
748         for (const auto &v: vv) {
749             std::vector<float> buf;
750             for (auto x: v) {
751                 buf.push_back(x);
752             }
753             buffers.push_back(buf);
754         }
755     }
756 
757     static void
buildProcessRequest(piper::ProcessRequest::Builder & b,const ProcessRequest & pr,const PluginHandleMapper & pmapper)758     buildProcessRequest(piper::ProcessRequest::Builder &b,
759                         const ProcessRequest &pr,
760                         const PluginHandleMapper &pmapper) {
761 
762         b.setHandle(pmapper.pluginToHandle(pr.plugin));
763         auto input = b.initProcessInput();
764         buildProcessInput(input, pr.timestamp, pr.inputBuffers);
765     }
766 
767     static void
readProcessRequest(ProcessRequest & pr,const piper::ProcessRequest::Reader & r,const PluginHandleMapper & pmapper)768     readProcessRequest(ProcessRequest &pr,
769                        const piper::ProcessRequest::Reader &r,
770                        const PluginHandleMapper &pmapper) {
771 
772         auto h = r.getHandle();
773         pr.plugin = pmapper.handleToPlugin(h);
774         readProcessInput(pr.timestamp, pr.inputBuffers, r.getProcessInput());
775     }
776 
777     static void
buildProcessResponse(piper::ProcessResponse::Builder & b,const ProcessResponse & pr,const PluginHandleMapper & pmapper)778     buildProcessResponse(piper::ProcessResponse::Builder &b,
779                          const ProcessResponse &pr,
780                          const PluginHandleMapper &pmapper) {
781 
782         b.setHandle(pmapper.pluginToHandle(pr.plugin));
783         auto f = b.initFeatures();
784         buildFeatureSet(f, pr.features,
785                         *pmapper.pluginToOutputIdMapper(pr.plugin));
786     }
787 
788     static void
readProcessResponse(ProcessResponse & pr,const piper::ProcessResponse::Reader & r,const PluginHandleMapper & pmapper)789     readProcessResponse(ProcessResponse &pr,
790                         const piper::ProcessResponse::Reader &r,
791                         const PluginHandleMapper &pmapper) {
792 
793         auto h = r.getHandle();
794         pr.plugin = pmapper.handleToPlugin(h);
795         readFeatureSet(pr.features, r.getFeatures(),
796                        *pmapper.handleToOutputIdMapper(r.getHandle()));
797     }
798 
799     static void
buildFinishResponse(piper::FinishResponse::Builder & b,const FinishResponse & pr,const PluginHandleMapper & pmapper)800     buildFinishResponse(piper::FinishResponse::Builder &b,
801                         const FinishResponse &pr,
802                         const PluginHandleMapper &pmapper) {
803 
804         b.setHandle(pmapper.pluginToHandle(pr.plugin));
805         auto f = b.initFeatures();
806         buildFeatureSet(f, pr.features,
807                         *pmapper.pluginToOutputIdMapper(pr.plugin));
808     }
809 
810     static void
readFinishResponse(FinishResponse & pr,const piper::FinishResponse::Reader & r,const PluginHandleMapper & pmapper)811     readFinishResponse(FinishResponse &pr,
812                        const piper::FinishResponse::Reader &r,
813                        const PluginHandleMapper &pmapper) {
814 
815         auto h = r.getHandle();
816         pr.plugin = pmapper.handleToPlugin(h);
817         readFeatureSet(pr.features, r.getFeatures(),
818                        *pmapper.handleToOutputIdMapper(r.getHandle()));
819     }
820 
821     static void
buildRpcRequest_List(piper::RpcRequest::Builder & b,const ListRequest & req)822     buildRpcRequest_List(piper::RpcRequest::Builder &b,
823                          const ListRequest &req) {
824         auto r = b.getRequest().initList();
825         buildListRequest(r, req);
826     }
827 
828     static void
buildRpcResponse_List(piper::RpcResponse::Builder & b,const ListResponse & resp)829     buildRpcResponse_List(piper::RpcResponse::Builder &b,
830                           const ListResponse &resp) {
831 
832         auto r = b.getResponse().initList();
833         buildListResponse(r, resp);
834     }
835 
836     static void
buildRpcRequest_Load(piper::RpcRequest::Builder & b,const LoadRequest & req)837     buildRpcRequest_Load(piper::RpcRequest::Builder &b,
838                          const LoadRequest &req) {
839         auto u = b.getRequest().initLoad();
840         buildLoadRequest(u, req);
841     }
842 
843     static void
buildRpcResponse_Load(piper::RpcResponse::Builder & b,const LoadResponse & resp,const PluginHandleMapper & pmapper)844     buildRpcResponse_Load(piper::RpcResponse::Builder &b,
845                           const LoadResponse &resp,
846                           const PluginHandleMapper &pmapper) {
847 
848         if (resp.plugin) {
849             auto u = b.getResponse().initLoad();
850             buildLoadResponse(u, resp, pmapper);
851         } else {
852             buildRpcResponse_Error(b, "Failed to load plugin", RRType::Load);
853         }
854     }
855 
856     static void
buildRpcRequest_Configure(piper::RpcRequest::Builder & b,const ConfigurationRequest & cr,const PluginHandleMapper & pmapper)857     buildRpcRequest_Configure(piper::RpcRequest::Builder &b,
858                               const ConfigurationRequest &cr,
859                               const PluginHandleMapper &pmapper) {
860         auto u = b.getRequest().initConfigure();
861         buildConfigurationRequest(u, cr, pmapper);
862     }
863 
864     static void
buildRpcResponse_Configure(piper::RpcResponse::Builder & b,const ConfigurationResponse & cr,const PluginHandleMapper & pmapper)865     buildRpcResponse_Configure(piper::RpcResponse::Builder &b,
866                                const ConfigurationResponse &cr,
867                                const PluginHandleMapper &pmapper) {
868 
869         if (!cr.outputs.empty()) {
870             auto u = b.getResponse().initConfigure();
871             buildConfigurationResponse(u, cr, pmapper);
872         } else {
873             buildRpcResponse_Error(b, "Failed to configure plugin",
874                                    RRType::Configure);
875         }
876     }
877 
878     static void
buildRpcRequest_Process(piper::RpcRequest::Builder & b,const ProcessRequest & pr,const PluginHandleMapper & pmapper)879     buildRpcRequest_Process(piper::RpcRequest::Builder &b,
880                             const ProcessRequest &pr,
881                             const PluginHandleMapper &pmapper) {
882         auto u = b.getRequest().initProcess();
883         buildProcessRequest(u, pr, pmapper);
884     }
885 
886     static void
buildRpcResponse_Process(piper::RpcResponse::Builder & b,const ProcessResponse & pr,const PluginHandleMapper & pmapper)887     buildRpcResponse_Process(piper::RpcResponse::Builder &b,
888                              const ProcessResponse &pr,
889                              const PluginHandleMapper &pmapper) {
890 
891         auto u = b.getResponse().initProcess();
892         buildProcessResponse(u, pr, pmapper);
893     }
894 
895     static void
buildRpcRequest_Finish(piper::RpcRequest::Builder & b,const FinishRequest & req,const PluginHandleMapper & pmapper)896     buildRpcRequest_Finish(piper::RpcRequest::Builder &b,
897                            const FinishRequest &req,
898                            const PluginHandleMapper &pmapper) {
899 
900         auto u = b.getRequest().initFinish();
901         u.setHandle(pmapper.pluginToHandle(req.plugin));
902     }
903 
904     static void
buildRpcResponse_Finish(piper::RpcResponse::Builder & b,const FinishResponse & pr,const PluginHandleMapper & pmapper)905     buildRpcResponse_Finish(piper::RpcResponse::Builder &b,
906                             const FinishResponse &pr,
907                             const PluginHandleMapper &pmapper) {
908 
909         auto u = b.getResponse().initFinish();
910         buildFinishResponse(u, pr, pmapper);
911     }
912 
913     static void
buildRpcResponse_Error(piper::RpcResponse::Builder & b,const std::string & errorText,RRType responseType)914     buildRpcResponse_Error(piper::RpcResponse::Builder &b,
915                            const std::string &errorText,
916                            RRType responseType)
917     {
918         std::string type;
919 
920         auto e = b.getResponse().initError();
921 
922         if (responseType == RRType::List) {
923             type = "list";
924         } else if (responseType == RRType::Load) {
925             type = "load";
926         } else if (responseType == RRType::Configure) {
927             type = "configure";
928         } else if (responseType == RRType::Process) {
929             type = "process";
930         } else if (responseType == RRType::Finish) {
931             type = "finish";
932         } else {
933             type = "invalid";
934         }
935 
936         e.setCode(0);
937 
938         if (responseType == RRType::NotValid) {
939             e.setMessage(errorText);
940         } else {
941             e.setMessage
942                 (std::string("error in ") + type + " request: " + errorText);
943         }
944     }
945 
946     static void
buildRpcResponse_Exception(piper::RpcResponse::Builder & b,const std::exception & e,RRType responseType)947     buildRpcResponse_Exception(piper::RpcResponse::Builder &b,
948                                const std::exception &e,
949                                RRType responseType)
950     {
951         return buildRpcResponse_Error(b, e.what(), responseType);
952     }
953 
954     static RRType
getRequestResponseType(const piper::RpcRequest::Reader & r)955     getRequestResponseType(const piper::RpcRequest::Reader &r) {
956         switch (r.getRequest().which()) {
957         case piper::RpcRequest::Request::Which::LIST:
958             return RRType::List;
959         case piper::RpcRequest::Request::Which::LOAD:
960             return RRType::Load;
961         case piper::RpcRequest::Request::Which::CONFIGURE:
962             return RRType::Configure;
963         case piper::RpcRequest::Request::Which::PROCESS:
964             return RRType::Process;
965         case piper::RpcRequest::Request::Which::FINISH:
966             return RRType::Finish;
967         }
968         return RRType::NotValid;
969     }
970 
971     static RRType
getRequestResponseType(const piper::RpcResponse::Reader & r)972     getRequestResponseType(const piper::RpcResponse::Reader &r) {
973         switch (r.getResponse().which()) {
974         case piper::RpcResponse::Response::Which::ERROR:
975             return RRType::NotValid;
976         case piper::RpcResponse::Response::Which::LIST:
977             return RRType::List;
978         case piper::RpcResponse::Response::Which::LOAD:
979             return RRType::Load;
980         case piper::RpcResponse::Response::Which::CONFIGURE:
981             return RRType::Configure;
982         case piper::RpcResponse::Response::Which::PROCESS:
983             return RRType::Process;
984         case piper::RpcResponse::Response::Which::FINISH:
985             return RRType::Finish;
986         }
987         return RRType::NotValid;
988     }
989 
990     static void
readRpcResponse_Error(int & code,std::string & message,const piper::RpcResponse::Reader & r)991     readRpcResponse_Error(int &code,
992                           std::string &message,
993                           const piper::RpcResponse::Reader &r) {
994         if (getRequestResponseType(r) != RRType::NotValid) {
995             throw std::logic_error("not an error response");
996         }
997         code = r.getResponse().getError().getCode();
998         message = r.getResponse().getError().getMessage();
999     }
1000 
1001     static void
readRpcRequest_List(ListRequest & req,const piper::RpcRequest::Reader & r)1002     readRpcRequest_List(ListRequest &req,
1003                         const piper::RpcRequest::Reader &r) {
1004         if (getRequestResponseType(r) != RRType::List) {
1005             throw std::logic_error("not a list request");
1006         }
1007         readListRequest(req, r.getRequest().getList());
1008     }
1009 
1010     static void
readRpcResponse_List(ListResponse & resp,const piper::RpcResponse::Reader & r)1011     readRpcResponse_List(ListResponse &resp,
1012                          const piper::RpcResponse::Reader &r) {
1013         if (getRequestResponseType(r) != RRType::List) {
1014             throw std::logic_error("not a list response");
1015         }
1016         readListResponse(resp, r.getResponse().getList());
1017     }
1018 
1019     static void
readRpcRequest_Load(LoadRequest & req,const piper::RpcRequest::Reader & r)1020     readRpcRequest_Load(LoadRequest &req,
1021                         const piper::RpcRequest::Reader &r) {
1022         if (getRequestResponseType(r) != RRType::Load) {
1023             throw std::logic_error("not a load request");
1024         }
1025         readLoadRequest(req, r.getRequest().getLoad());
1026     }
1027 
1028     static void
readRpcResponse_Load(LoadResponse & resp,const piper::RpcResponse::Reader & r,const PluginHandleMapper & pmapper)1029     readRpcResponse_Load(LoadResponse &resp,
1030                          const piper::RpcResponse::Reader &r,
1031                          const PluginHandleMapper &pmapper) {
1032         if (getRequestResponseType(r) != RRType::Load) {
1033             throw std::logic_error("not a load response");
1034         }
1035         resp = {};
1036         readLoadResponse(resp, r.getResponse().getLoad(), pmapper);
1037     }
1038 
1039     static void
readRpcRequest_Configure(ConfigurationRequest & req,const piper::RpcRequest::Reader & r,const PluginHandleMapper & pmapper)1040     readRpcRequest_Configure(ConfigurationRequest &req,
1041                              const piper::RpcRequest::Reader &r,
1042                              const PluginHandleMapper &pmapper) {
1043         if (getRequestResponseType(r) != RRType::Configure) {
1044             throw std::logic_error("not a configuration request");
1045         }
1046         readConfigurationRequest(req, r.getRequest().getConfigure(), pmapper);
1047     }
1048 
1049     static void
readRpcResponse_Configure(ConfigurationResponse & resp,const piper::RpcResponse::Reader & r,const PluginHandleMapper & pmapper)1050     readRpcResponse_Configure(ConfigurationResponse &resp,
1051                               const piper::RpcResponse::Reader &r,
1052                               const PluginHandleMapper &pmapper) {
1053         if (getRequestResponseType(r) != RRType::Configure) {
1054             throw std::logic_error("not a configuration response");
1055         }
1056         resp = {};
1057         readConfigurationResponse(resp,
1058                                   r.getResponse().getConfigure(),
1059                                   pmapper);
1060     }
1061 
1062     static void
readRpcRequest_Process(ProcessRequest & req,const piper::RpcRequest::Reader & r,const PluginHandleMapper & pmapper)1063     readRpcRequest_Process(ProcessRequest &req,
1064                            const piper::RpcRequest::Reader &r,
1065                            const PluginHandleMapper &pmapper) {
1066         if (getRequestResponseType(r) != RRType::Process) {
1067             throw std::logic_error("not a process request");
1068         }
1069         readProcessRequest(req, r.getRequest().getProcess(), pmapper);
1070     }
1071 
1072     static void
readRpcResponse_Process(ProcessResponse & resp,const piper::RpcResponse::Reader & r,const PluginHandleMapper & pmapper)1073     readRpcResponse_Process(ProcessResponse &resp,
1074                             const piper::RpcResponse::Reader &r,
1075                             const PluginHandleMapper &pmapper) {
1076         if (getRequestResponseType(r) != RRType::Process) {
1077             throw std::logic_error("not a process response");
1078         }
1079         resp = {};
1080         readProcessResponse(resp, r.getResponse().getProcess(), pmapper);
1081     }
1082 
1083     static void
readRpcRequest_Finish(FinishRequest & req,const piper::RpcRequest::Reader & r,const PluginHandleMapper & pmapper)1084     readRpcRequest_Finish(FinishRequest &req,
1085                           const piper::RpcRequest::Reader &r,
1086                           const PluginHandleMapper &pmapper) {
1087         if (getRequestResponseType(r) != RRType::Finish) {
1088             throw std::logic_error("not a finish request");
1089         }
1090         auto h = r.getRequest().getFinish().getHandle();
1091         req.plugin = pmapper.handleToPlugin(h);
1092     }
1093 
1094     static void
readRpcResponse_Finish(FinishResponse & resp,const piper::RpcResponse::Reader & r,const PluginHandleMapper & pmapper)1095     readRpcResponse_Finish(FinishResponse &resp,
1096                            const piper::RpcResponse::Reader &r,
1097                            const PluginHandleMapper &pmapper) {
1098         if (getRequestResponseType(r) != RRType::Finish) {
1099             throw std::logic_error("not a finish response");
1100         }
1101         resp = {};
1102         readFinishResponse(resp, r.getResponse().getFinish(), pmapper);
1103     }
1104 };
1105 
1106 }
1107 
1108 
1109