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 ×tamp, 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