c@5: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ c@5: c@5: #include "vamp.capnp.h" c@5: c@5: #include c@5: #include c@5: c@5: #include c@5: #include c@5: #include c@5: c@10: #include "bits/PluginHandleMapper.h" c@10: c@5: namespace vampipe c@5: { c@5: c@5: /** c@5: * Convert the structures laid out in the Vamp SDK classes into Cap'n c@6: * Proto structures (and back again). c@5: * c@6: * At least some of this will be necessary for any implementation c@6: * using Cap'n Proto that uses the C++ Vamp SDK to provide its c@6: * reference structures. An implementation could alternatively use the c@6: * Cap'n Proto structures directly, and interact with Vamp plugins c@6: * using the Vamp C API, without using the C++ Vamp SDK classes at c@6: * all. c@5: */ c@6: class VampnProto c@5: { c@5: public: c@5: typedef ::capnp::MallocMessageBuilder MsgBuilder; c@5: c@5: template c@5: static void buildBasicDescriptor(B &basic, const T &t) { c@5: basic.setIdentifier(t.identifier); c@5: basic.setName(t.name); c@5: basic.setDescription(t.description); c@5: } c@5: c@5: template c@5: static void readBasicDescriptor(T &t, const B &basic) { c@5: t.identifier = basic.getIdentifier(); c@5: t.name = basic.getName(); c@5: t.description = basic.getDescription(); c@5: } c@5: c@5: template c@5: static void buildValueExtents(M &m, const T &t) { c@5: m.setMinValue(t.minValue); c@5: m.setMaxValue(t.maxValue); c@5: } c@5: c@5: template c@5: static void readValueExtents(T &t, const M &m) { c@5: t.minValue = m.getMinValue(); c@5: t.maxValue = m.getMaxValue(); c@5: } c@5: c@5: static void buildRealTime(RealTime::Builder &b, const Vamp::RealTime &t) { c@5: b.setSec(t.sec); c@5: b.setNsec(t.nsec); c@5: } c@5: c@5: static void readRealTime(Vamp::RealTime &t, const RealTime::Reader &r) { c@5: t.sec = r.getSec(); c@5: t.nsec = r.getNsec(); c@5: } c@5: c@5: static SampleType c@5: fromSampleType(Vamp::Plugin::OutputDescriptor::SampleType t) { c@5: switch (t) { c@5: case Vamp::Plugin::OutputDescriptor::OneSamplePerStep: c@5: return SampleType::ONE_SAMPLE_PER_STEP; c@5: case Vamp::Plugin::OutputDescriptor::FixedSampleRate: c@5: return SampleType::FIXED_SAMPLE_RATE; c@5: case Vamp::Plugin::OutputDescriptor::VariableSampleRate: c@5: return SampleType::VARIABLE_SAMPLE_RATE; c@5: } c@5: throw std::logic_error("unexpected Vamp SampleType enum value"); c@5: } c@5: c@5: static Vamp::Plugin::OutputDescriptor::SampleType c@5: toSampleType(SampleType t) { c@5: switch (t) { c@5: case SampleType::ONE_SAMPLE_PER_STEP: c@5: return Vamp::Plugin::OutputDescriptor::OneSamplePerStep; c@5: case SampleType::FIXED_SAMPLE_RATE: c@5: return Vamp::Plugin::OutputDescriptor::FixedSampleRate; c@5: case SampleType::VARIABLE_SAMPLE_RATE: c@5: return Vamp::Plugin::OutputDescriptor::VariableSampleRate; c@5: } c@5: throw std::logic_error("unexpected Capnp SampleType enum value"); c@5: } c@5: c@5: static void c@5: buildOutputDescriptor(OutputDescriptor::Builder &b, c@5: const Vamp::Plugin::OutputDescriptor &od) { c@5: c@5: auto basic = b.initBasic(); c@5: buildBasicDescriptor(basic, od); c@5: c@5: b.setUnit(od.unit); c@5: c@5: b.setSampleType(fromSampleType(od.sampleType)); c@5: b.setSampleRate(od.sampleRate); c@5: b.setHasDuration(od.hasDuration); c@5: c@5: b.setHasFixedBinCount(od.hasFixedBinCount); c@5: if (od.hasFixedBinCount) { c@5: b.setBinCount(od.binCount); c@5: if (od.binNames.size() > 0) { c@5: auto binNames = b.initBinNames(od.binNames.size()); c@5: for (size_t i = 0; i < od.binNames.size(); ++i) { c@5: binNames.set(i, od.binNames[i]); c@5: } c@5: } c@5: } c@5: c@5: b.setHasKnownExtents(od.hasKnownExtents); c@5: if (od.hasKnownExtents) { c@5: buildValueExtents(b, od); c@5: } c@5: c@5: b.setIsQuantized(od.isQuantized); c@5: if (od.isQuantized) { c@5: b.setQuantizeStep(od.quantizeStep); c@5: } c@5: } c@5: c@5: static void c@5: readOutputDescriptor(Vamp::Plugin::OutputDescriptor &od, c@5: const OutputDescriptor::Reader &r) { c@5: c@5: readBasicDescriptor(od, r.getBasic()); c@5: c@5: od.unit = r.getUnit(); c@5: c@5: od.sampleType = toSampleType(r.getSampleType()); c@5: od.sampleRate = r.getSampleRate(); c@5: od.hasDuration = r.getHasDuration(); c@5: c@5: od.hasFixedBinCount = r.getHasFixedBinCount(); c@5: if (od.hasFixedBinCount) { c@5: od.binCount = r.getBinCount(); c@13: od.binNames.clear(); c@5: for (const auto &n: r.getBinNames()) { c@5: od.binNames.push_back(n); c@5: } c@5: } c@5: c@5: od.hasKnownExtents = r.getHasKnownExtents(); c@5: if (od.hasKnownExtents) { c@5: readValueExtents(od, r); c@5: } c@5: c@5: od.isQuantized = r.getIsQuantized(); c@5: if (od.isQuantized) { c@5: od.quantizeStep = r.getQuantizeStep(); c@5: } c@5: } c@5: c@5: static void c@5: buildParameterDescriptor(ParameterDescriptor::Builder &b, c@5: const Vamp::Plugin::ParameterDescriptor &pd) { c@5: c@5: auto basic = b.initBasic(); c@5: buildBasicDescriptor(basic, pd); c@5: c@5: b.setUnit(pd.unit); c@5: c@5: buildValueExtents(b, pd); c@5: c@5: b.setDefaultValue(pd.defaultValue); c@5: c@5: b.setIsQuantized(pd.isQuantized); c@5: if (pd.isQuantized) { c@5: b.setQuantizeStep(pd.quantizeStep); c@5: } c@5: c@5: if (pd.valueNames.size() > 0) { c@5: auto valueNames = b.initValueNames(pd.valueNames.size()); c@5: for (size_t i = 0; i < pd.valueNames.size(); ++i) { c@5: valueNames.set(i, pd.valueNames[i]); c@5: } c@5: } c@5: } c@5: c@5: static void c@5: readParameterDescriptor(Vamp::Plugin::ParameterDescriptor &pd, c@5: const ParameterDescriptor::Reader &r) { c@5: c@5: readBasicDescriptor(pd, r.getBasic()); c@5: c@5: pd.unit = r.getUnit(); c@5: c@5: readValueExtents(pd, r); c@5: c@5: pd.defaultValue = r.getDefaultValue(); c@5: c@5: pd.isQuantized = r.getIsQuantized(); c@5: if (pd.isQuantized) { c@5: pd.quantizeStep = r.getQuantizeStep(); c@5: } c@5: c@13: pd.valueNames.clear(); c@5: for (const auto &n: r.getValueNames()) { c@5: pd.valueNames.push_back(n); c@5: } c@5: } c@5: c@5: static void c@5: buildFeature(Feature::Builder &b, c@5: const Vamp::Plugin::Feature &f) { c@5: c@5: b.setHasTimestamp(f.hasTimestamp); c@5: if (f.hasTimestamp) { c@5: auto timestamp = b.initTimestamp(); c@5: buildRealTime(timestamp, f.timestamp); c@5: } c@5: c@5: b.setHasDuration(f.hasDuration); c@5: if (f.hasDuration) { c@5: auto duration = b.initDuration(); c@5: buildRealTime(duration, f.duration); c@5: } c@5: c@5: b.setLabel(f.label); c@5: c@5: if (f.values.size() > 0) { c@5: auto values = b.initValues(f.values.size()); c@5: for (size_t i = 0; i < f.values.size(); ++i) { c@5: values.set(i, f.values[i]); c@5: } c@5: } c@5: } c@5: c@5: static void c@5: readFeature(Vamp::Plugin::Feature &f, c@5: const Feature::Reader &r) { c@5: c@5: f.hasTimestamp = r.getHasTimestamp(); c@5: if (f.hasTimestamp) { c@5: readRealTime(f.timestamp, r.getTimestamp()); c@5: } c@5: c@5: f.hasDuration = r.getHasDuration(); c@5: if (f.hasDuration) { c@5: readRealTime(f.duration, r.getDuration()); c@5: } c@5: c@5: f.label = r.getLabel(); c@5: c@13: f.values.clear(); c@5: for (auto v: r.getValues()) { c@5: f.values.push_back(v); c@5: } c@5: } c@5: c@5: static void c@5: buildFeatureSet(FeatureSet::Builder &b, c@5: const Vamp::Plugin::FeatureSet &fs) { c@5: c@5: auto featureset = b.initFeaturePairs(fs.size()); c@5: int ix = 0; c@5: for (const auto &fsi : fs) { c@5: auto fspair = featureset[ix]; c@5: fspair.setOutput(fsi.first); c@5: auto featurelist = fspair.initFeatures(fsi.second.size()); c@5: for (size_t j = 0; j < fsi.second.size(); ++j) { c@5: auto feature = featurelist[j]; c@5: buildFeature(feature, fsi.second[j]); c@5: } c@5: ++ix; c@5: } c@5: } c@5: c@5: static void c@5: readFeatureSet(Vamp::Plugin::FeatureSet &fs, c@5: const FeatureSet::Reader &r) { c@5: c@13: fs.clear(); c@5: for (const auto &p: r.getFeaturePairs()) { c@5: Vamp::Plugin::FeatureList vfl; c@5: for (const auto &f: p.getFeatures()) { c@5: Vamp::Plugin::Feature vf; c@5: readFeature(vf, f); c@5: vfl.push_back(vf); c@5: } c@5: fs[p.getOutput()] = vfl; c@5: } c@5: } c@5: c@5: static InputDomain c@5: fromInputDomain(Vamp::Plugin::InputDomain d) { c@5: switch(d) { c@5: case Vamp::Plugin::TimeDomain: c@5: return InputDomain::TIME_DOMAIN; c@5: case Vamp::Plugin::FrequencyDomain: c@5: return InputDomain::FREQUENCY_DOMAIN; c@5: default: c@5: throw std::logic_error("unexpected Vamp InputDomain enum value"); c@5: } c@5: } c@5: c@5: static Vamp::Plugin::InputDomain c@5: toInputDomain(InputDomain d) { c@5: switch(d) { c@5: case InputDomain::TIME_DOMAIN: c@5: return Vamp::Plugin::TimeDomain; c@5: case InputDomain::FREQUENCY_DOMAIN: c@5: return Vamp::Plugin::FrequencyDomain; c@5: default: c@5: throw std::logic_error("unexpected Capnp InputDomain enum value"); c@5: } c@5: } c@5: c@5: static void c@5: buildPluginStaticData(PluginStaticData::Builder &b, c@5: const Vamp::HostExt::PluginStaticData &d) { c@5: c@5: b.setPluginKey(d.pluginKey); c@5: c@5: auto basic = b.initBasic(); c@5: buildBasicDescriptor(basic, d.basic); c@5: c@5: b.setMaker(d.maker); c@5: b.setCopyright(d.copyright); c@5: b.setPluginVersion(d.pluginVersion); c@5: c@5: auto clist = b.initCategory(d.category.size()); c@5: for (size_t i = 0; i < d.category.size(); ++i) { c@5: clist.set(i, d.category[i]); c@5: } c@5: c@5: b.setMinChannelCount(d.minChannelCount); c@5: b.setMaxChannelCount(d.maxChannelCount); c@5: c@5: const auto &vparams = d.parameters; c@5: auto plist = b.initParameters(vparams.size()); c@5: for (size_t i = 0; i < vparams.size(); ++i) { c@5: auto pd = plist[i]; c@5: buildParameterDescriptor(pd, vparams[i]); c@5: } c@5: c@5: const auto &vprogs = d.programs; c@5: auto pglist = b.initPrograms(vprogs.size()); c@5: for (size_t i = 0; i < vprogs.size(); ++i) { c@5: pglist.set(i, vprogs[i]); c@5: } c@5: c@5: b.setInputDomain(fromInputDomain(d.inputDomain)); c@5: c@5: const auto &vouts = d.basicOutputInfo; c@5: auto olist = b.initBasicOutputInfo(vouts.size()); c@5: for (size_t i = 0; i < vouts.size(); ++i) { c@5: auto od = olist[i]; c@5: buildBasicDescriptor(od, vouts[i]); c@5: } c@5: } c@5: c@5: static void c@5: readPluginStaticData(Vamp::HostExt::PluginStaticData &d, c@5: const PluginStaticData::Reader &r) { c@5: c@5: d.pluginKey = r.getPluginKey(); c@5: c@5: readBasicDescriptor(d.basic, r.getBasic()); c@5: c@5: d.maker = r.getMaker(); c@5: d.copyright = r.getCopyright(); c@5: d.pluginVersion = r.getPluginVersion(); c@5: c@13: d.category.clear(); c@5: for (auto c: r.getCategory()) { c@5: d.category.push_back(c); c@5: } c@5: c@5: d.minChannelCount = r.getMinChannelCount(); c@5: d.maxChannelCount = r.getMaxChannelCount(); c@5: c@13: d.parameters.clear(); c@5: for (auto p: r.getParameters()) { c@5: Vamp::Plugin::ParameterDescriptor pd; c@5: readParameterDescriptor(pd, p); c@5: d.parameters.push_back(pd); c@5: } c@5: c@13: d.programs.clear(); c@5: for (auto p: r.getPrograms()) { c@5: d.programs.push_back(p); c@5: } c@5: c@5: d.inputDomain = toInputDomain(r.getInputDomain()); c@5: c@13: d.basicOutputInfo.clear(); c@5: for (auto o: r.getBasicOutputInfo()) { c@5: Vamp::HostExt::PluginStaticData::Basic b; c@5: readBasicDescriptor(b, o); c@5: d.basicOutputInfo.push_back(b); c@5: } c@5: } c@5: c@5: static void c@5: buildPluginConfiguration(PluginConfiguration::Builder &b, c@5: const Vamp::HostExt::PluginConfiguration &c) { c@5: c@5: const auto &vparams = c.parameterValues; c@5: auto params = b.initParameterValues(vparams.size()); c@5: int i = 0; c@5: for (const auto &pp : vparams) { c@5: auto param = params[i++]; c@5: param.setParameter(pp.first); c@5: param.setValue(pp.second); c@5: } c@5: c@5: b.setCurrentProgram(c.currentProgram); c@5: b.setChannelCount(c.channelCount); c@5: b.setStepSize(c.stepSize); c@5: b.setBlockSize(c.blockSize); c@5: } c@5: c@5: static void c@5: readPluginConfiguration(Vamp::HostExt::PluginConfiguration &c, c@5: const PluginConfiguration::Reader &r) { c@5: c@5: for (const auto &pp: r.getParameterValues()) { c@5: c.parameterValues[pp.getParameter()] = pp.getValue(); c@5: } c@5: c@5: c.currentProgram = r.getCurrentProgram(); c@5: c.channelCount = r.getChannelCount(); c@5: c.stepSize = r.getStepSize(); c@5: c.blockSize = r.getBlockSize(); c@5: } c@5: c@5: static void c@5: buildLoadRequest(LoadRequest::Builder &r, c@5: const Vamp::HostExt::LoadRequest &req) { c@5: c@5: r.setPluginKey(req.pluginKey); c@5: r.setInputSampleRate(req.inputSampleRate); c@5: c@5: std::vector flags; c@5: if (req.adapterFlags & Vamp::HostExt::PluginLoader::ADAPT_INPUT_DOMAIN) { c@5: flags.push_back(AdapterFlag::ADAPT_INPUT_DOMAIN); c@5: } c@5: if (req.adapterFlags & Vamp::HostExt::PluginLoader::ADAPT_CHANNEL_COUNT) { c@5: flags.push_back(AdapterFlag::ADAPT_CHANNEL_COUNT); c@5: } c@5: if (req.adapterFlags & Vamp::HostExt::PluginLoader::ADAPT_BUFFER_SIZE) { c@5: flags.push_back(AdapterFlag::ADAPT_BUFFER_SIZE); c@5: } c@5: c@5: auto f = r.initAdapterFlags(flags.size()); c@5: for (size_t i = 0; i < flags.size(); ++i) { c@5: f.set(i, flags[i]); c@5: } c@5: } c@5: c@5: static void c@5: readLoadRequest(Vamp::HostExt::LoadRequest &req, c@5: const LoadRequest::Reader &r) { c@5: c@5: req.pluginKey = r.getPluginKey(); c@5: req.inputSampleRate = r.getInputSampleRate(); c@5: c@5: int flags = 0; c@5: for (const auto &a: r.getAdapterFlags()) { c@5: if (a == AdapterFlag::ADAPT_INPUT_DOMAIN) { c@5: flags |= Vamp::HostExt::PluginLoader::ADAPT_INPUT_DOMAIN; c@5: } c@5: if (a == AdapterFlag::ADAPT_CHANNEL_COUNT) { c@5: flags |= Vamp::HostExt::PluginLoader::ADAPT_CHANNEL_COUNT; c@5: } c@5: if (a == AdapterFlag::ADAPT_BUFFER_SIZE) { c@5: flags |= Vamp::HostExt::PluginLoader::ADAPT_BUFFER_SIZE; c@5: } c@5: } c@5: req.adapterFlags = flags; c@5: } c@10: c@10: static void c@10: buildLoadResponse(LoadResponse::Builder &b, c@10: const Vamp::HostExt::LoadResponse &resp, c@10: PluginHandleMapper &mapper) { c@10: c@10: b.setPluginHandle(mapper.pluginToHandle(resp.plugin)); c@10: auto sd = b.initStaticData(); c@10: buildPluginStaticData(sd, resp.staticData); c@10: auto conf = b.initDefaultConfiguration(); c@10: buildPluginConfiguration(conf, resp.defaultConfiguration); c@10: } c@10: c@10: static void c@10: readLoadResponse(Vamp::HostExt::LoadResponse &resp, c@10: const LoadResponse::Reader &r, c@10: PluginHandleMapper &mapper) { c@10: c@10: resp.plugin = mapper.handleToPlugin(r.getPluginHandle()); c@10: readPluginStaticData(resp.staticData, r.getStaticData()); c@10: readPluginConfiguration(resp.defaultConfiguration, c@10: r.getDefaultConfiguration()); c@10: } c@13: c@13: static void c@13: buildConfigurationRequest(ConfigurationRequest::Builder &b, c@13: const Vamp::HostExt::ConfigurationRequest &cr, c@13: PluginHandleMapper &mapper) { c@13: c@13: b.setPluginHandle(mapper.pluginToHandle(cr.plugin)); c@13: auto c = b.initConfiguration(); c@13: buildPluginConfiguration(c, cr.configuration); c@13: } c@13: c@13: static void c@13: readConfigurationRequest(Vamp::HostExt::ConfigurationRequest &cr, c@13: const ConfigurationRequest::Reader &r, c@13: PluginHandleMapper &mapper) { c@13: c@13: auto h = r.getPluginHandle(); c@13: cr.plugin = mapper.handleToPlugin(h); c@13: auto c = r.getConfiguration(); c@13: readPluginConfiguration(cr.configuration, c); c@13: } c@13: c@13: static void c@13: buildConfigurationResponse(ConfigurationResponse::Builder &b, c@13: const Vamp::HostExt::ConfigurationResponse &cr) { c@13: c@13: auto olist = b.initOutputs(cr.outputs.size()); c@13: for (size_t i = 0; i < cr.outputs.size(); ++i) { c@13: auto od = olist[i]; c@13: buildOutputDescriptor(od, cr.outputs[i]); c@13: } c@13: } c@13: c@13: static void c@13: readConfigurationResponse(Vamp::HostExt::ConfigurationResponse &cr, c@13: const ConfigurationResponse::Reader &r) { c@13: c@13: cr.outputs.clear(); c@13: for (const auto &o: r.getOutputs()) { c@13: Vamp::Plugin::OutputDescriptor desc; c@13: readOutputDescriptor(desc, o); c@13: cr.outputs.push_back(desc); c@13: } c@13: } c@14: c@14: static void c@14: buildProcessInput(ProcessInput::Builder &b, c@14: Vamp::RealTime timestamp, c@14: const std::vector > &buffers) { c@14: c@14: auto t = b.initTimestamp(); c@14: buildRealTime(t, timestamp); c@14: auto vv = b.initInputBuffers(buffers.size()); c@14: for (size_t ch = 0; ch < buffers.size(); ++ch) { c@14: const int n = int(buffers[ch].size()); c@14: vv.init(ch, n); c@14: auto v = vv[ch]; c@14: for (int i = 0; i < n; ++i) { c@14: v.set(i, buffers[ch][i]); c@14: } c@14: } c@14: } c@14: c@14: static void c@14: readProcessInput(Vamp::RealTime ×tamp, c@14: std::vector > &buffers, c@14: const ProcessInput::Reader &b) { c@14: c@14: readRealTime(timestamp, b.getTimestamp()); c@14: buffers.clear(); c@14: for (const auto &v: b.getInputBuffers()) { c@14: std::vector buf; c@14: for (auto x: v) { c@14: buf.push_back(x); c@14: } c@14: buffers.push_back(buf); c@14: } c@14: } c@14: c@14: static void c@14: buildProcessRequest(ProcessRequest::Builder &b, c@14: const Vamp::HostExt::ProcessRequest &pr, c@14: PluginHandleMapper &mapper) { c@14: c@14: b.setPluginHandle(mapper.pluginToHandle(pr.plugin)); c@14: auto input = b.initInput(); c@14: buildProcessInput(input, pr.timestamp, pr.inputBuffers); c@14: } c@14: c@14: static void c@14: readProcessRequest(Vamp::HostExt::ProcessRequest &pr, c@14: const ProcessRequest::Reader &r, c@14: PluginHandleMapper &mapper) { c@14: c@14: auto h = r.getPluginHandle(); c@14: pr.plugin = mapper.handleToPlugin(h); c@14: readProcessInput(pr.timestamp, pr.inputBuffers, r.getInput()); c@14: } c@14: c@14: static void c@14: buildVampListRequest(VampRequest::Builder &b) { c@14: b.getRequest().setList(); c@14: } c@14: c@14: static void c@14: buildVampLoadRequest(VampRequest::Builder &b, c@14: const Vamp::HostExt::LoadRequest &req) { c@14: auto u = b.getRequest().initLoad(); c@14: buildLoadRequest(u, req); c@14: } c@14: c@14: static void c@14: buildVampConfigureRequest(VampRequest::Builder &b, c@14: const Vamp::HostExt::ConfigurationRequest &cr, c@14: PluginHandleMapper &mapper) { c@14: auto u = b.getRequest().initConfigure(); c@14: buildConfigurationRequest(u, cr, mapper); c@14: } c@14: c@14: static void c@14: buildVampProcessRequest(VampRequest::Builder &b, c@14: const Vamp::HostExt::ProcessRequest &pr, c@14: PluginHandleMapper &mapper) { c@14: auto u = b.getRequest().initProcess(); c@14: buildProcessRequest(u, pr, mapper); c@14: } c@14: c@14: c@14: //...!!! and responses c@5: }; c@5: c@5: } c@5: c@5: